@humanbased/crosscheck 1.2.0-beta.80 → 1.2.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/LICENSE +1 -1
- package/README.md +388 -149
- package/README.zh.md +1 -1
- package/crosscheck.config.example.yml +2 -63
- package/dist/__tests__/codex.test.js +27 -14
- package/dist/__tests__/codex.test.js.map +1 -1
- package/dist/__tests__/comment-bodies.test.js +1 -49
- package/dist/__tests__/comment-bodies.test.js.map +1 -1
- package/dist/__tests__/conflict-resolve.test.js +1 -44
- package/dist/__tests__/conflict-resolve.test.js.map +1 -1
- package/dist/__tests__/fix.test.js +0 -33
- package/dist/__tests__/fix.test.js.map +1 -1
- package/dist/__tests__/onboard-preservation.test.js +0 -5
- package/dist/__tests__/onboard-preservation.test.js.map +1 -1
- package/dist/__tests__/optimize.test.js +0 -2
- package/dist/__tests__/optimize.test.js.map +1 -1
- package/dist/__tests__/repo-picker.test.js +1 -7
- package/dist/__tests__/repo-picker.test.js.map +1 -1
- package/dist/__tests__/review-comment-body.test.js +0 -35
- package/dist/__tests__/review-comment-body.test.js.map +1 -1
- package/dist/__tests__/review-models.test.js +3 -19
- package/dist/__tests__/review-models.test.js.map +1 -1
- package/dist/__tests__/runner.test.js +1 -29
- package/dist/__tests__/runner.test.js.map +1 -1
- package/dist/cli.js +0 -29
- package/dist/cli.js.map +1 -1
- package/dist/commands/onboard.d.ts +0 -11
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +2 -88
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/review.d.ts.map +1 -1
- package/dist/commands/review.js +6 -65
- package/dist/commands/review.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +3 -23
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +1 -53
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/watch.d.ts.map +1 -1
- package/dist/commands/watch.js +6 -52
- package/dist/commands/watch.js.map +1 -1
- package/dist/config/loader.d.ts +1 -3
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +0 -13
- package/dist/config/loader.js.map +1 -1
- package/dist/config/review-model-tiers.json +3 -3
- package/dist/config/schema.d.ts +10 -254
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +2 -62
- package/dist/config/schema.js.map +1 -1
- package/dist/github/client.d.ts +1 -6
- package/dist/github/client.d.ts.map +1 -1
- package/dist/github/client.js +7 -15
- package/dist/github/client.js.map +1 -1
- package/dist/issues/ticket-ref.d.ts.map +1 -1
- package/dist/issues/ticket-ref.js +5 -6
- package/dist/issues/ticket-ref.js.map +1 -1
- package/dist/lib/clone.d.ts +0 -1
- package/dist/lib/clone.d.ts.map +1 -1
- package/dist/lib/clone.js +10 -32
- package/dist/lib/clone.js.map +1 -1
- package/dist/lib/comment-bodies.d.ts +0 -35
- package/dist/lib/comment-bodies.d.ts.map +1 -1
- package/dist/lib/comment-bodies.js +9 -43
- package/dist/lib/comment-bodies.js.map +1 -1
- package/dist/lib/repo-picker.d.ts +0 -3
- package/dist/lib/repo-picker.d.ts.map +1 -1
- package/dist/lib/repo-picker.js +9 -45
- package/dist/lib/repo-picker.js.map +1 -1
- package/dist/lib/review-models.d.ts +2 -15
- package/dist/lib/review-models.d.ts.map +1 -1
- package/dist/lib/review-models.js +6 -26
- package/dist/lib/review-models.js.map +1 -1
- package/dist/lib/runner.d.ts +0 -12
- package/dist/lib/runner.d.ts.map +1 -1
- package/dist/lib/runner.js +42 -186
- package/dist/lib/runner.js.map +1 -1
- package/dist/lib/workflow.d.ts +0 -9
- package/dist/lib/workflow.d.ts.map +1 -1
- package/dist/lib/workflow.js +0 -20
- package/dist/lib/workflow.js.map +1 -1
- package/dist/reviewers/claude.d.ts +1 -4
- package/dist/reviewers/claude.d.ts.map +1 -1
- package/dist/reviewers/claude.js +7 -39
- package/dist/reviewers/claude.js.map +1 -1
- package/dist/reviewers/codex.d.ts +1 -3
- package/dist/reviewers/codex.d.ts.map +1 -1
- package/dist/reviewers/codex.js +70 -76
- package/dist/reviewers/codex.js.map +1 -1
- package/dist/reviewers/conflict-resolve.d.ts +1 -3
- package/dist/reviewers/conflict-resolve.d.ts.map +1 -1
- package/dist/reviewers/conflict-resolve.js +6 -21
- package/dist/reviewers/conflict-resolve.js.map +1 -1
- package/dist/reviewers/fix.d.ts +2 -5
- package/dist/reviewers/fix.d.ts.map +1 -1
- package/dist/reviewers/fix.js +10 -26
- package/dist/reviewers/fix.js.map +1 -1
- package/get-started.md +4 -139
- package/package.json +3 -4
- package/assets/icon-256.png +0 -0
- package/assets/linear-comment.svg +0 -18
- package/assets/linear-onboard.svg +0 -30
- package/assets/linear-status.svg +0 -23
- package/assets/linear-test.svg +0 -34
- package/assets/skills/code-review/.crosscheck-skill.json +0 -9
- package/assets/skills/code-review/LICENSE +0 -21
- package/assets/skills/code-review/SKILL.md +0 -89
- package/assets/skills/code-review/agents/openai.yaml +0 -3
- package/assets/skills/code-review-skill/.crosscheck-skill.json +0 -9
- package/assets/skills/code-review-skill/LICENSE +0 -21
- package/assets/skills/code-review-skill/SKILL.md +0 -231
- package/assets/skills/code-review-skill/assets/pr-review-template.md +0 -137
- package/assets/skills/code-review-skill/assets/review-checklist.md +0 -123
- package/assets/skills/code-review-skill/reference/angular.md +0 -768
- package/assets/skills/code-review-skill/reference/architecture-review-guide.md +0 -472
- package/assets/skills/code-review-skill/reference/c.md +0 -890
- package/assets/skills/code-review-skill/reference/code-quality-universal.md +0 -488
- package/assets/skills/code-review-skill/reference/code-review-best-practices.md +0 -136
- package/assets/skills/code-review-skill/reference/common-bugs-checklist.md +0 -286
- package/assets/skills/code-review-skill/reference/cpp.md +0 -893
- package/assets/skills/code-review-skill/reference/cross-cutting/async-concurrency-patterns.md +0 -515
- package/assets/skills/code-review-skill/reference/cross-cutting/error-handling-principles.md +0 -492
- package/assets/skills/code-review-skill/reference/cross-cutting/n-plus-one-queries.md +0 -309
- package/assets/skills/code-review-skill/reference/cross-cutting/sql-injection-prevention.md +0 -308
- package/assets/skills/code-review-skill/reference/cross-cutting/xss-prevention.md +0 -264
- package/assets/skills/code-review-skill/reference/csharp.md +0 -525
- package/assets/skills/code-review-skill/reference/css-less-sass.md +0 -661
- package/assets/skills/code-review-skill/reference/django.md +0 -985
- package/assets/skills/code-review-skill/reference/fastapi.md +0 -580
- package/assets/skills/code-review-skill/reference/go.md +0 -993
- package/assets/skills/code-review-skill/reference/java.md +0 -409
- package/assets/skills/code-review-skill/reference/java8.md +0 -586
- package/assets/skills/code-review-skill/reference/kotlin.md +0 -1018
- package/assets/skills/code-review-skill/reference/nestjs.md +0 -593
- package/assets/skills/code-review-skill/reference/performance-review-guide.md +0 -816
- package/assets/skills/code-review-skill/reference/php.md +0 -684
- package/assets/skills/code-review-skill/reference/python.md +0 -1073
- package/assets/skills/code-review-skill/reference/qt.md +0 -757
- package/assets/skills/code-review-skill/reference/react.md +0 -871
- package/assets/skills/code-review-skill/reference/ruby.md +0 -964
- package/assets/skills/code-review-skill/reference/rust.md +0 -846
- package/assets/skills/code-review-skill/reference/security-review-guide.md +0 -494
- package/assets/skills/code-review-skill/reference/svelte.md +0 -1064
- package/assets/skills/code-review-skill/reference/swift.md +0 -936
- package/assets/skills/code-review-skill/reference/typescript.md +0 -1016
- package/assets/skills/code-review-skill/reference/vue.md +0 -924
- package/assets/skills/code-review-skill/reference/zig.md +0 -440
- package/assets/skills/code-review-skill/scripts/pr-analyzer.py +0 -435
- package/assets/skills/code-review-skill/scripts/test_pr_analyzer.py +0 -380
- package/assets/skills/codebase-design/.crosscheck-skill.json +0 -9
- package/assets/skills/codebase-design/DEEPENING.md +0 -37
- package/assets/skills/codebase-design/DESIGN-IT-TWICE.md +0 -44
- package/assets/skills/codebase-design/LICENSE +0 -21
- package/assets/skills/codebase-design/SKILL.md +0 -114
- package/assets/skills/codebase-design/agents/openai.yaml +0 -3
- package/assets/skills/diagnosing-bugs/.crosscheck-skill.json +0 -9
- package/assets/skills/diagnosing-bugs/LICENSE +0 -21
- package/assets/skills/diagnosing-bugs/SKILL.md +0 -134
- package/assets/skills/diagnosing-bugs/agents/openai.yaml +0 -3
- package/assets/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
- package/dist/__tests__/can-write-verdict.test.d.ts +0 -2
- package/dist/__tests__/can-write-verdict.test.d.ts.map +0 -1
- package/dist/__tests__/can-write-verdict.test.js +0 -31
- package/dist/__tests__/can-write-verdict.test.js.map +0 -1
- package/dist/__tests__/linear-branding.test.d.ts +0 -2
- package/dist/__tests__/linear-branding.test.d.ts.map +0 -1
- package/dist/__tests__/linear-branding.test.js +0 -156
- package/dist/__tests__/linear-branding.test.js.map +0 -1
- package/dist/__tests__/linear-client.test.d.ts +0 -2
- package/dist/__tests__/linear-client.test.d.ts.map +0 -1
- package/dist/__tests__/linear-client.test.js +0 -120
- package/dist/__tests__/linear-client.test.js.map +0 -1
- package/dist/__tests__/linear-comment.test.d.ts +0 -2
- package/dist/__tests__/linear-comment.test.d.ts.map +0 -1
- package/dist/__tests__/linear-comment.test.js +0 -151
- package/dist/__tests__/linear-comment.test.js.map +0 -1
- package/dist/__tests__/linear-identity.test.d.ts +0 -2
- package/dist/__tests__/linear-identity.test.d.ts.map +0 -1
- package/dist/__tests__/linear-identity.test.js +0 -253
- package/dist/__tests__/linear-identity.test.js.map +0 -1
- package/dist/__tests__/linear-notify.test.d.ts +0 -2
- package/dist/__tests__/linear-notify.test.d.ts.map +0 -1
- package/dist/__tests__/linear-notify.test.js +0 -144
- package/dist/__tests__/linear-notify.test.js.map +0 -1
- package/dist/__tests__/linear-ref.test.d.ts +0 -2
- package/dist/__tests__/linear-ref.test.d.ts.map +0 -1
- package/dist/__tests__/linear-ref.test.js +0 -261
- package/dist/__tests__/linear-ref.test.js.map +0 -1
- package/dist/__tests__/linear-test-ref.test.d.ts +0 -2
- package/dist/__tests__/linear-test-ref.test.d.ts.map +0 -1
- package/dist/__tests__/linear-test-ref.test.js +0 -81
- package/dist/__tests__/linear-test-ref.test.js.map +0 -1
- package/dist/__tests__/linear-verify.test.d.ts +0 -2
- package/dist/__tests__/linear-verify.test.d.ts.map +0 -1
- package/dist/__tests__/linear-verify.test.js +0 -132
- package/dist/__tests__/linear-verify.test.js.map +0 -1
- package/dist/__tests__/linear-worker.test.d.ts +0 -2
- package/dist/__tests__/linear-worker.test.d.ts.map +0 -1
- package/dist/__tests__/linear-worker.test.js +0 -83
- package/dist/__tests__/linear-worker.test.js.map +0 -1
- package/dist/__tests__/linear-write-possible.test.d.ts +0 -2
- package/dist/__tests__/linear-write-possible.test.d.ts.map +0 -1
- package/dist/__tests__/linear-write-possible.test.js +0 -30
- package/dist/__tests__/linear-write-possible.test.js.map +0 -1
- package/dist/__tests__/repository-guidance.test.d.ts +0 -2
- package/dist/__tests__/repository-guidance.test.d.ts.map +0 -1
- package/dist/__tests__/repository-guidance.test.js +0 -107
- package/dist/__tests__/repository-guidance.test.js.map +0 -1
- package/dist/__tests__/review-strategy.test.d.ts +0 -2
- package/dist/__tests__/review-strategy.test.d.ts.map +0 -1
- package/dist/__tests__/review-strategy.test.js +0 -195
- package/dist/__tests__/review-strategy.test.js.map +0 -1
- package/dist/__tests__/skill-attribution.test.d.ts +0 -2
- package/dist/__tests__/skill-attribution.test.d.ts.map +0 -1
- package/dist/__tests__/skill-attribution.test.js +0 -53
- package/dist/__tests__/skill-attribution.test.js.map +0 -1
- package/dist/__tests__/skill-broker.test.d.ts +0 -2
- package/dist/__tests__/skill-broker.test.d.ts.map +0 -1
- package/dist/__tests__/skill-broker.test.js +0 -144
- package/dist/__tests__/skill-broker.test.js.map +0 -1
- package/dist/__tests__/skill-catalog.test.d.ts +0 -2
- package/dist/__tests__/skill-catalog.test.d.ts.map +0 -1
- package/dist/__tests__/skill-catalog.test.js +0 -40
- package/dist/__tests__/skill-catalog.test.js.map +0 -1
- package/dist/__tests__/skill-installer.test.d.ts +0 -2
- package/dist/__tests__/skill-installer.test.d.ts.map +0 -1
- package/dist/__tests__/skill-installer.test.js +0 -96
- package/dist/__tests__/skill-installer.test.js.map +0 -1
- package/dist/__tests__/skills-config.test.d.ts +0 -2
- package/dist/__tests__/skills-config.test.d.ts.map +0 -1
- package/dist/__tests__/skills-config.test.js +0 -12
- package/dist/__tests__/skills-config.test.js.map +0 -1
- package/dist/commands/linear-test.d.ts +0 -18
- package/dist/commands/linear-test.d.ts.map +0 -1
- package/dist/commands/linear-test.js +0 -130
- package/dist/commands/linear-test.js.map +0 -1
- package/dist/commands/skill.d.ts +0 -2
- package/dist/commands/skill.d.ts.map +0 -1
- package/dist/commands/skill.js +0 -16
- package/dist/commands/skill.js.map +0 -1
- package/dist/config/review-strategy.json +0 -202
- package/dist/lib/repository-guidance.d.ts +0 -2
- package/dist/lib/repository-guidance.d.ts.map +0 -1
- package/dist/lib/repository-guidance.js +0 -55
- package/dist/lib/repository-guidance.js.map +0 -1
- package/dist/lib/review-strategy.d.ts +0 -62
- package/dist/lib/review-strategy.d.ts.map +0 -1
- package/dist/lib/review-strategy.js +0 -235
- package/dist/lib/review-strategy.js.map +0 -1
- package/dist/linear/client.d.ts +0 -18
- package/dist/linear/client.d.ts.map +0 -1
- package/dist/linear/client.js +0 -67
- package/dist/linear/client.js.map +0 -1
- package/dist/linear/comment.d.ts +0 -20
- package/dist/linear/comment.d.ts.map +0 -1
- package/dist/linear/comment.js +0 -57
- package/dist/linear/comment.js.map +0 -1
- package/dist/linear/identity.d.ts +0 -59
- package/dist/linear/identity.d.ts.map +0 -1
- package/dist/linear/identity.js +0 -187
- package/dist/linear/identity.js.map +0 -1
- package/dist/linear/notify.d.ts +0 -35
- package/dist/linear/notify.d.ts.map +0 -1
- package/dist/linear/notify.js +0 -76
- package/dist/linear/notify.js.map +0 -1
- package/dist/linear/ref.d.ts +0 -13
- package/dist/linear/ref.d.ts.map +0 -1
- package/dist/linear/ref.js +0 -90
- package/dist/linear/ref.js.map +0 -1
- package/dist/linear/verify.d.ts +0 -26
- package/dist/linear/verify.d.ts.map +0 -1
- package/dist/linear/verify.js +0 -67
- package/dist/linear/verify.js.map +0 -1
- package/dist/skills/attribution.d.ts +0 -4
- package/dist/skills/attribution.d.ts.map +0 -1
- package/dist/skills/attribution.js +0 -14
- package/dist/skills/attribution.js.map +0 -1
- package/dist/skills/broker-server.d.ts +0 -2
- package/dist/skills/broker-server.d.ts.map +0 -1
- package/dist/skills/broker-server.js +0 -17
- package/dist/skills/broker-server.js.map +0 -1
- package/dist/skills/broker.d.ts +0 -42
- package/dist/skills/broker.d.ts.map +0 -1
- package/dist/skills/broker.js +0 -285
- package/dist/skills/broker.js.map +0 -1
- package/dist/skills/catalog.d.ts +0 -28
- package/dist/skills/catalog.d.ts.map +0 -1
- package/dist/skills/catalog.js +0 -104
- package/dist/skills/catalog.js.map +0 -1
- package/dist/skills/installer.d.ts +0 -10
- package/dist/skills/installer.d.ts.map +0 -1
- package/dist/skills/installer.js +0 -138
- package/dist/skills/installer.js.map +0 -1
- package/dist/skills/integrity.d.ts +0 -4
- package/dist/skills/integrity.d.ts.map +0 -1
- package/dist/skills/integrity.js +0 -36
- package/dist/skills/integrity.js.map +0 -1
- package/docs/dynamic-thoroughness.md +0 -286
- package/docs/linear-identity-contract.md +0 -139
- package/docs/linear-identity.md +0 -293
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/skills/catalog.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb;AAMD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,eAAO,MAAM,uBAAuB,sEAAuE,CAAA;AAE3G,eAAO,MAAM,6BAA6B,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAK1E,CAAA;AAOD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAE1G;AAGD,eAAO,MAAM,oBAAoB,QAA2C,CAAA;AAE5E,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAMxE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAElE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEnE;AAiDD,wBAAgB,iBAAiB,CAAC,OAAO,SAAqB,GAAG,aAAa,EAAE,CAE/E;AAED,wBAAgB,mBAAmB,CAAC,OAAO,SAAuB,GAAG,aAAa,EAAE,CAEnF;AAED,wBAAgB,gBAAgB,CAAC,aAAa,SAAuB,GAAG,aAAa,EAAE,CAMtF;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC,GAAG,MAAM,CAErG"}
|
package/dist/skills/catalog.js
DELETED
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { fileURLToPath } from 'url';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
|
-
import yaml from 'js-yaml';
|
|
6
|
-
import { computeSkillIntegrity } from './integrity.js';
|
|
7
|
-
export const RECOMMENDED_SKILL_NAMES = ['code-review-skill', 'codebase-design', 'diagnosing-bugs'];
|
|
8
|
-
export const BUNDLED_SKILL_RECOMMENDATIONS = {
|
|
9
|
-
'code-review': 'Best for evidence-rich repositories with documented standards and a clear issue or PRD; checks Standards and Spec separately.',
|
|
10
|
-
'code-review-skill': 'Best general default for broad language, correctness, security, performance, and architecture coverage.',
|
|
11
|
-
'codebase-design': 'Best for architecture-heavy changes: deep modules, small interfaces, clean seams, and testability.',
|
|
12
|
-
'diagnosing-bugs': 'Best for hard bugs and regressions: requires a reproducible signal, ranked hypotheses, and regression evidence.',
|
|
13
|
-
};
|
|
14
|
-
const COMPETING_SKILLS = {
|
|
15
|
-
'code-review': ['code-review-skill'],
|
|
16
|
-
'code-review-skill': ['code-review'],
|
|
17
|
-
};
|
|
18
|
-
export function findCompetingSkill(skillName, selectedNames) {
|
|
19
|
-
return COMPETING_SKILLS[skillName]?.find(name => selectedNames.includes(name));
|
|
20
|
-
}
|
|
21
|
-
const BUNDLED_SKILLS_DIR = fileURLToPath(new URL('../../assets/skills/', import.meta.url));
|
|
22
|
-
export const INSTALLED_SKILLS_DIR = join(homedir(), '.crosscheck', 'skills');
|
|
23
|
-
export function readSkillFrontmatter(skillPath) {
|
|
24
|
-
const content = readFileSync(join(skillPath, 'SKILL.md'), 'utf8');
|
|
25
|
-
const match = /^---\r?\n([\s\S]*?)\r?\n---/.exec(content);
|
|
26
|
-
if (!match)
|
|
27
|
-
return {};
|
|
28
|
-
const parsed = yaml.load(match[1]);
|
|
29
|
-
return typeof parsed === 'object' && parsed !== null ? parsed : {};
|
|
30
|
-
}
|
|
31
|
-
export function isValidSkillAuthor(value) {
|
|
32
|
-
return typeof value === 'string' && /^[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,37}[a-zA-Z0-9])?$/.test(value);
|
|
33
|
-
}
|
|
34
|
-
export function isValidSkillLicense(value) {
|
|
35
|
-
return typeof value === 'string' && /^[a-zA-Z0-9][a-zA-Z0-9.+() -]{0,99}$/.test(value);
|
|
36
|
-
}
|
|
37
|
-
function isSkillReceipt(value) {
|
|
38
|
-
if (typeof value !== 'object' || value === null)
|
|
39
|
-
return false;
|
|
40
|
-
const receipt = value;
|
|
41
|
-
return receipt.schemaVersion === 1
|
|
42
|
-
&& typeof receipt.name === 'string' && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(receipt.name)
|
|
43
|
-
&& isValidSkillAuthor(receipt.author)
|
|
44
|
-
&& isValidSkillLicense(receipt.license)
|
|
45
|
-
&& typeof receipt.source === 'string' && receipt.source.length > 0
|
|
46
|
-
&& typeof receipt.revision === 'string' && receipt.revision.length > 0
|
|
47
|
-
&& typeof receipt.integrity === 'string' && /^sha256:[0-9a-f]{64}$/.test(receipt.integrity);
|
|
48
|
-
}
|
|
49
|
-
function loadSkills(rootDir, skipInvalid) {
|
|
50
|
-
if (!existsSync(rootDir))
|
|
51
|
-
return [];
|
|
52
|
-
return readdirSync(rootDir, { withFileTypes: true })
|
|
53
|
-
.filter(entry => entry.isDirectory() && !entry.name.startsWith('.'))
|
|
54
|
-
.flatMap(entry => {
|
|
55
|
-
const path = join(rootDir, entry.name);
|
|
56
|
-
try {
|
|
57
|
-
const receiptPath = join(path, '.crosscheck-skill.json');
|
|
58
|
-
if (statSync(receiptPath).size > 64 * 1024)
|
|
59
|
-
throw new Error(`Invalid skill receipt: ${entry.name}`);
|
|
60
|
-
const integrity = computeSkillIntegrity(path);
|
|
61
|
-
const receipt = JSON.parse(readFileSync(receiptPath, 'utf8'));
|
|
62
|
-
const frontmatter = readSkillFrontmatter(path);
|
|
63
|
-
if (!isSkillReceipt(receipt) || receipt.name !== entry.name || frontmatter.name !== receipt.name
|
|
64
|
-
|| typeof frontmatter.description !== 'string' || !frontmatter.description.trim()
|
|
65
|
-
|| integrity !== receipt.integrity) {
|
|
66
|
-
throw new Error(`Invalid skill package: ${entry.name}`);
|
|
67
|
-
}
|
|
68
|
-
return [{
|
|
69
|
-
name: receipt.name,
|
|
70
|
-
description: frontmatter.description.trim(),
|
|
71
|
-
author: receipt.author,
|
|
72
|
-
license: receipt.license,
|
|
73
|
-
source: receipt.source,
|
|
74
|
-
revision: receipt.revision,
|
|
75
|
-
integrity: receipt.integrity,
|
|
76
|
-
path,
|
|
77
|
-
}];
|
|
78
|
-
}
|
|
79
|
-
catch (err) {
|
|
80
|
-
if (skipInvalid)
|
|
81
|
-
return [];
|
|
82
|
-
throw err;
|
|
83
|
-
}
|
|
84
|
-
})
|
|
85
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
86
|
-
}
|
|
87
|
-
export function loadBundledSkills(rootDir = BUNDLED_SKILLS_DIR) {
|
|
88
|
-
return loadSkills(rootDir, false);
|
|
89
|
-
}
|
|
90
|
-
export function loadInstalledSkills(rootDir = INSTALLED_SKILLS_DIR) {
|
|
91
|
-
return loadSkills(rootDir, true);
|
|
92
|
-
}
|
|
93
|
-
export function loadSkillCatalog(installedRoot = INSTALLED_SKILLS_DIR) {
|
|
94
|
-
const skills = new Map(loadBundledSkills().map(skill => [skill.name, skill]));
|
|
95
|
-
for (const skill of loadInstalledSkills(installedRoot)) {
|
|
96
|
-
if (!skills.has(skill.name))
|
|
97
|
-
skills.set(skill.name, skill);
|
|
98
|
-
}
|
|
99
|
-
return [...skills.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
100
|
-
}
|
|
101
|
-
export function formatSkillIdentity(skill) {
|
|
102
|
-
return `${skill.name} (by @${skill.author}, ${skill.license})`;
|
|
103
|
-
}
|
|
104
|
-
//# sourceMappingURL=catalog.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/skills/catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type SkillIdentity } from './catalog.js';
|
|
2
|
-
export { computeSkillIntegrity } from './integrity.js';
|
|
3
|
-
export interface InstallSkillOptions {
|
|
4
|
-
installDir?: string;
|
|
5
|
-
}
|
|
6
|
-
export declare class SkillInstallError extends Error {
|
|
7
|
-
}
|
|
8
|
-
export declare function redactSkillSource(source: string): string;
|
|
9
|
-
export declare function installSkill(source: string, opts?: InstallSkillOptions): Promise<SkillIdentity>;
|
|
10
|
-
//# sourceMappingURL=installer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"installer.d.ts","sourceRoot":"","sources":["../../src/skills/installer.ts"],"names":[],"mappings":"AAIA,OAAO,EAA+H,KAAK,aAAa,EAAE,MAAM,cAAc,CAAA;AAG9K,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAA;AAEtD,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAYxD;AAuCD,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAAC,aAAa,CAAC,CAgEzG"}
|
package/dist/skills/installer.js
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'fs';
|
|
2
|
-
import { basename, join, resolve } from 'path';
|
|
3
|
-
import { tmpdir } from 'os';
|
|
4
|
-
import { execa } from 'execa';
|
|
5
|
-
import { INSTALLED_SKILLS_DIR, isValidSkillAuthor, isValidSkillLicense, loadBundledSkills, loadInstalledSkills, readSkillFrontmatter } from './catalog.js';
|
|
6
|
-
import { computeSkillIntegrity } from './integrity.js';
|
|
7
|
-
export { computeSkillIntegrity } from './integrity.js';
|
|
8
|
-
export class SkillInstallError extends Error {
|
|
9
|
-
}
|
|
10
|
-
export function redactSkillSource(source) {
|
|
11
|
-
if (existsSync(source))
|
|
12
|
-
return resolve(source);
|
|
13
|
-
try {
|
|
14
|
-
const url = new URL(source);
|
|
15
|
-
url.username = '';
|
|
16
|
-
url.password = '';
|
|
17
|
-
url.search = '';
|
|
18
|
-
url.hash = '';
|
|
19
|
-
return url.toString();
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return source;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
function detectLicense(rootDir, declared) {
|
|
26
|
-
if (typeof declared === 'string' && declared.trim())
|
|
27
|
-
return declared.trim();
|
|
28
|
-
const licenseName = ['LICENSE', 'LICENSE.md', 'COPYING'].find(name => existsSync(join(rootDir, name)));
|
|
29
|
-
if (!licenseName)
|
|
30
|
-
return 'UNKNOWN';
|
|
31
|
-
const license = readFileSync(join(rootDir, licenseName), 'utf8');
|
|
32
|
-
if (/MIT License/i.test(license))
|
|
33
|
-
return 'MIT';
|
|
34
|
-
if (/Apache License[\s\S]*Version 2\.0/i.test(license))
|
|
35
|
-
return 'Apache-2.0';
|
|
36
|
-
if (/BSD 3-Clause/i.test(license))
|
|
37
|
-
return 'BSD-3-Clause';
|
|
38
|
-
if (/ISC License/i.test(license))
|
|
39
|
-
return 'ISC';
|
|
40
|
-
return 'UNKNOWN';
|
|
41
|
-
}
|
|
42
|
-
function detectAuthor(source, declared) {
|
|
43
|
-
if (typeof declared === 'string' && declared.trim())
|
|
44
|
-
return declared.trim().replace(/^@/, '');
|
|
45
|
-
return /github\.com[/:]([^/]+)/i.exec(source)?.[1] ?? 'local';
|
|
46
|
-
}
|
|
47
|
-
async function checkoutSource(source) {
|
|
48
|
-
if (existsSync(source)) {
|
|
49
|
-
const path = resolve(source);
|
|
50
|
-
if (lstatSync(path).isSymbolicLink())
|
|
51
|
-
throw new SkillInstallError('Skill source cannot be a symbolic link');
|
|
52
|
-
if (!statSync(path).isDirectory())
|
|
53
|
-
throw new SkillInstallError(`Skill source is not a directory: ${source}`);
|
|
54
|
-
return { path, revision: 'local' };
|
|
55
|
-
}
|
|
56
|
-
const cleanup = mkdtempSync(join(tmpdir(), 'crosscheck-skill-clone-'));
|
|
57
|
-
const path = join(cleanup, 'source');
|
|
58
|
-
try {
|
|
59
|
-
await execa('git', ['clone', '--depth', '1', source, path]);
|
|
60
|
-
const revision = (await execa('git', ['-C', path, 'rev-parse', 'HEAD'])).stdout.trim();
|
|
61
|
-
return { path, revision, cleanup };
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
rmSync(cleanup, { recursive: true, force: true });
|
|
65
|
-
throw new SkillInstallError(`Could not clone skill source: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
export async function installSkill(source, opts = {}) {
|
|
69
|
-
const installDir = resolve(opts.installDir ?? INSTALLED_SKILLS_DIR);
|
|
70
|
-
const checkout = await checkoutSource(source);
|
|
71
|
-
try {
|
|
72
|
-
if (!existsSync(join(checkout.path, 'SKILL.md'))) {
|
|
73
|
-
throw new SkillInstallError('Skill package must contain SKILL.md');
|
|
74
|
-
}
|
|
75
|
-
try {
|
|
76
|
-
computeSkillIntegrity(checkout.path);
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
throw new SkillInstallError(err instanceof Error ? err.message : String(err));
|
|
80
|
-
}
|
|
81
|
-
let frontmatter;
|
|
82
|
-
try {
|
|
83
|
-
frontmatter = readSkillFrontmatter(checkout.path);
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
throw new SkillInstallError(`Invalid SKILL.md frontmatter: ${err instanceof Error ? err.message : String(err)}`);
|
|
87
|
-
}
|
|
88
|
-
const name = typeof frontmatter.name === 'string' ? frontmatter.name : '';
|
|
89
|
-
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(name)) {
|
|
90
|
-
throw new SkillInstallError(`Invalid skill name: ${name || '(missing)'}`);
|
|
91
|
-
}
|
|
92
|
-
if (typeof frontmatter.description !== 'string' || !frontmatter.description.trim()) {
|
|
93
|
-
throw new SkillInstallError('Skill frontmatter must include a description');
|
|
94
|
-
}
|
|
95
|
-
if (loadBundledSkills().some(skill => skill.name === name)) {
|
|
96
|
-
throw new SkillInstallError(`Skill ${name} is already bundled with Crosscheck`);
|
|
97
|
-
}
|
|
98
|
-
mkdirSync(installDir, { recursive: true });
|
|
99
|
-
const target = join(installDir, name);
|
|
100
|
-
if (existsSync(target)) {
|
|
101
|
-
throw new SkillInstallError(`Skill ${name} is already installed`);
|
|
102
|
-
}
|
|
103
|
-
const pendingTarget = join(installDir, `.install-${name}-${process.pid}`);
|
|
104
|
-
try {
|
|
105
|
-
cpSync(checkout.path, pendingTarget, {
|
|
106
|
-
recursive: true,
|
|
107
|
-
filter: path => basename(path) !== '.git' && basename(path) !== '.crosscheck-skill.json',
|
|
108
|
-
});
|
|
109
|
-
const author = detectAuthor(source, frontmatter.author);
|
|
110
|
-
const license = detectLicense(checkout.path, frontmatter.license);
|
|
111
|
-
if (!isValidSkillAuthor(author))
|
|
112
|
-
throw new SkillInstallError(`Invalid skill author: ${author}`);
|
|
113
|
-
if (!isValidSkillLicense(license))
|
|
114
|
-
throw new SkillInstallError(`Invalid skill license: ${license}`);
|
|
115
|
-
const receipt = {
|
|
116
|
-
schemaVersion: 1,
|
|
117
|
-
name,
|
|
118
|
-
author,
|
|
119
|
-
license,
|
|
120
|
-
source: redactSkillSource(source),
|
|
121
|
-
revision: checkout.revision,
|
|
122
|
-
integrity: computeSkillIntegrity(pendingTarget),
|
|
123
|
-
};
|
|
124
|
-
writeFileSync(join(pendingTarget, '.crosscheck-skill.json'), `${JSON.stringify(receipt, null, 2)}\n`);
|
|
125
|
-
renameSync(pendingTarget, target);
|
|
126
|
-
return loadInstalledSkills(installDir).find(skill => skill.name === name);
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
rmSync(pendingTarget, { recursive: true, force: true });
|
|
130
|
-
throw err;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
finally {
|
|
134
|
-
if (checkout.cleanup)
|
|
135
|
-
rmSync(checkout.cleanup, { recursive: true, force: true });
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
//# sourceMappingURL=installer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../../src/skills/installer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"integrity.d.ts","sourceRoot":"","sources":["../../src/skills/integrity.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,uBAAuB,OAAQ,CAAA;AAC5C,eAAO,MAAM,uBAAuB,QAAmB,CAAA;AAevD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAc7D"}
|
package/dist/skills/integrity.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { createHash } from 'crypto';
|
|
2
|
-
import { lstatSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
3
|
-
import { join, relative, sep } from 'path';
|
|
4
|
-
export const MAX_SKILL_PACKAGE_FILES = 1_000;
|
|
5
|
-
export const MAX_SKILL_PACKAGE_BYTES = 10 * 1024 * 1024;
|
|
6
|
-
function packageFiles(rootDir, currentDir, files) {
|
|
7
|
-
for (const entry of readdirSync(currentDir, { withFileTypes: true })) {
|
|
8
|
-
if (entry.name === '.git' || entry.name === '.crosscheck-skill.json')
|
|
9
|
-
continue;
|
|
10
|
-
const path = join(currentDir, entry.name);
|
|
11
|
-
if (lstatSync(path).isSymbolicLink())
|
|
12
|
-
throw new Error('Skill packages cannot contain symbolic links');
|
|
13
|
-
if (entry.isDirectory())
|
|
14
|
-
packageFiles(rootDir, path, files);
|
|
15
|
-
else if (entry.isFile()) {
|
|
16
|
-
files.push(path);
|
|
17
|
-
if (files.length > MAX_SKILL_PACKAGE_FILES)
|
|
18
|
-
throw new Error(`Skill packages cannot contain more than ${MAX_SKILL_PACKAGE_FILES} files`);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
export function computeSkillIntegrity(rootDir) {
|
|
23
|
-
const files = [];
|
|
24
|
-
packageFiles(rootDir, rootDir, files);
|
|
25
|
-
files.sort((a, b) => relative(rootDir, a).localeCompare(relative(rootDir, b)));
|
|
26
|
-
const totalBytes = files.reduce((sum, path) => sum + statSync(path).size, 0);
|
|
27
|
-
if (totalBytes > MAX_SKILL_PACKAGE_BYTES)
|
|
28
|
-
throw new Error('Skill packages cannot exceed 10 MiB');
|
|
29
|
-
const hash = createHash('sha256');
|
|
30
|
-
for (const path of files) {
|
|
31
|
-
hash.update(relative(rootDir, path).split(sep).join('/')).update('\0');
|
|
32
|
-
hash.update(readFileSync(path)).update('\0');
|
|
33
|
-
}
|
|
34
|
-
return `sha256:${hash.digest('hex')}`;
|
|
35
|
-
}
|
|
36
|
-
//# sourceMappingURL=integrity.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../src/skills/integrity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;AACnE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAE1C,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAA;AAC5C,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAA;AAEvD,SAAS,YAAY,CAAC,OAAe,EAAE,UAAkB,EAAE,KAAe;IACxE,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACrE,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,wBAAwB;YAAE,SAAQ;QAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACzC,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAA;QACrG,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,YAAY,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;aACtD,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAChB,IAAI,KAAK,CAAC,MAAM,GAAG,uBAAuB;gBAAE,MAAM,IAAI,KAAK,CAAC,2CAA2C,uBAAuB,QAAQ,CAAC,CAAA;QACzI,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAe;IACnD,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAAA;IACrC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAE9E,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC5E,IAAI,UAAU,GAAG,uBAAuB;QAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAA;IAEhG,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAA;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACtE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;IACD,OAAO,UAAU,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;AACvC,CAAC"}
|
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# Dynamic thoroughness
|
|
2
|
-
|
|
3
|
-
**Strategy version 1.0.0 · updated 2026-08-07 · re-verify every 60 days.**
|
|
4
|
-
|
|
5
|
-
This document is the analysis behind [`src/config/review-strategy.json`](../src/config/review-strategy.json).
|
|
6
|
-
The JSON is the policy crosscheck executes; this file is why the policy says what it
|
|
7
|
-
says. They are versioned together: a change to one without the other is drift, and
|
|
8
|
-
`npm run verify:strategy` is the check that makes that drift loud.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## 1. The problem
|
|
13
|
-
|
|
14
|
-
One PR is not like another. A lockfile bump and a rewrite of the session handler
|
|
15
|
-
are both "a PR", and crosscheck used to review them identically — one configured
|
|
16
|
-
`quality.tier`, one model, one effort level, the same review→fix→recheck loop.
|
|
17
|
-
That is wrong in both directions at once: it overpays on the lockfile and
|
|
18
|
-
under-reviews the session handler.
|
|
19
|
-
|
|
20
|
-
The failure that prompted this was quieter than either. `review-model-tiers.json`
|
|
21
|
-
pinned `claude-opus-4-8` for the `thorough` tier and kept pinning it after
|
|
22
|
-
`claude-opus-5` shipped at identical $5/$25 pricing with a higher coding score.
|
|
23
|
-
Nothing broke. Nothing warned. Every `thorough` review just got worse than it had
|
|
24
|
-
to be, for months. A model pin is a perishable asset, and nothing in the repo
|
|
25
|
-
treated it as one.
|
|
26
|
-
|
|
27
|
-
So the policy has two jobs: choose per PR, and tell a human when the inputs it
|
|
28
|
-
chose from have moved.
|
|
29
|
-
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
## 2. Sources, and how to re-verify
|
|
33
|
-
|
|
34
|
-
`sources[]` in the JSON lists the pages the numbers came from, each with the
|
|
35
|
-
strings that must still appear on it. `scripts/verify-review-strategy.mjs`
|
|
36
|
-
fetches them and compares.
|
|
37
|
-
|
|
38
|
-
| Source | What it fixes |
|
|
39
|
-
|---|---|
|
|
40
|
-
| [Anthropic model catalog](https://platform.claude.com/docs/en/about-claude/models/overview) | Claude model IDs and availability |
|
|
41
|
-
| [Anthropic effort parameter](https://platform.claude.com/docs/en/build-with-claude/effort) | The effort ladder, including `xhigh` |
|
|
42
|
-
| [OpenAI model catalog](https://developers.openai.com/api/docs/models) | Codex model IDs |
|
|
43
|
-
|
|
44
|
-
Benchmarks are recorded in `benchmarks` with their own `as_of` dates and caveats,
|
|
45
|
-
because they age faster than prices:
|
|
46
|
-
|
|
47
|
-
- **SWE-bench Verified** — resolving real GitHub issues in Python repos. A
|
|
48
|
-
backend/general proxy only. Comparable within one leaderboard run; cross-run
|
|
49
|
-
positions are indicative.
|
|
50
|
-
- **Frontend Code Arena** — blind pairwise human preference on generated frontend
|
|
51
|
-
output. Measures *generation*, not defect detection. Claude Opus 5 is absent
|
|
52
|
-
from the retrieved leaderboard: a missing measurement, not a low score.
|
|
53
|
-
|
|
54
|
-
Re-verification is not automatic and is not meant to be. Model choice is a
|
|
55
|
-
judgement call backed by benchmarks that need reading. The weekly
|
|
56
|
-
`Review Strategy` workflow fetches the sources and opens an issue when a check
|
|
57
|
-
string disappears; a human then re-reads and edits. The job's job is to say *the
|
|
58
|
-
inputs moved*, never to move the policy itself.
|
|
59
|
-
|
|
60
|
-
Network failures are deliberately not drift. A fetch that never landed says
|
|
61
|
-
nothing about the policy, so the verifier treats unreachable sources as warnings
|
|
62
|
-
on `pull_request` and as errors only on `schedule`, where someone is looking.
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 3. The model catalog
|
|
67
|
-
|
|
68
|
-
Prices are USD per million tokens.
|
|
69
|
-
|
|
70
|
-
| Model | Vendor | In | Out | SWE-bench V | Frontend Elo | Effort levels |
|
|
71
|
-
|---|---|---:|---:|---:|---:|---|
|
|
72
|
-
| `claude-opus-5` | claude | 5 | 25 | 0.960 | — | low…max |
|
|
73
|
-
| `claude-sonnet-5` | claude | 3 | 15 | 0.852 | — | low…max |
|
|
74
|
-
| `claude-haiku-4-5-20251001` | claude | 1 | 5 | 0.733 | — | *(none)* |
|
|
75
|
-
| `gpt-5.6-sol` | codex | 5 | 30 | — | 1618 | none…max |
|
|
76
|
-
| `gpt-5.6-terra` | codex | 2 | 12 | — | — | none…max |
|
|
77
|
-
| `gpt-5.6-luna` | codex | 0.2 | 1.2 | — | — | none…max |
|
|
78
|
-
| `kimi-k3` | opencode *(planned)* | 3 | 15 | — | 1679 | *(none)* |
|
|
79
|
-
| `glm-5.2` | opencode *(planned)* | 1.4 | 4.4 | — | 1587 | *(none)* |
|
|
80
|
-
| `deepseek-v4-pro` | opencode *(planned)* | 0.435 | 0.87 | 0.806 | — | none, high, max |
|
|
81
|
-
| `deepseek-v4-flash` | opencode *(planned)* | 0.14 | 0.28 | 0.790 | — | none, high, max |
|
|
82
|
-
|
|
83
|
-
`banned_models` is a separate list from "not currently routed", because the
|
|
84
|
-
reason matters. `claude-fable-5` is banned on cost: $50/MTok output is 2× Opus 5
|
|
85
|
-
for a *lower* SWE-bench Verified score (95.0 vs 96.0). At the measured ~48k
|
|
86
|
-
output tokens per review that is $2.40 a call with no capability justification.
|
|
87
|
-
The verifier fails if any vendor tier or domain preference ever routes to it.
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## 4. Tiers and domains
|
|
92
|
-
|
|
93
|
-
Tiers are the vendor-facing ladder:
|
|
94
|
-
|
|
95
|
-
| Tier | Claude | Codex | OpenCode *(planned)* |
|
|
96
|
-
|---|---|---|---|
|
|
97
|
-
| `fast` | Haiku 4.5 | GPT-5.6 Luna | deepseek-v4-flash |
|
|
98
|
-
| `balanced` | Sonnet 5 | GPT-5.6 Terra | glm-5.2 |
|
|
99
|
-
| `thorough` | Opus 5 | GPT-5.6 Sol | kimi-k3 |
|
|
100
|
-
|
|
101
|
-
Capability, though, is domain-shaped rather than scalar. Opus 5 leads backend
|
|
102
|
-
defect resolution; kimi-k3 leads the frontend arena. A single ladder cannot
|
|
103
|
-
express that, so `domains` carries a preference list per tier. The domain is
|
|
104
|
-
detected from changed-file extensions; `mixed` and `unknown` both fall back to
|
|
105
|
-
`backend`, the conservative default — the backend list is `measured`, the
|
|
106
|
-
frontend list is still a `hypothesis` pending a local A/B.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
## 5. PR classes
|
|
111
|
-
|
|
112
|
-
**Order is the routing logic — first match wins.** The list is in
|
|
113
|
-
`pr_classes`, and `risky` sits second, immediately after `generated`, so
|
|
114
|
-
consequence-based promotion dominates every cheapening rule below it. A
|
|
115
|
-
deletion-only PR that removes auth code, or a two-file change to a migration,
|
|
116
|
-
must not fall through to `fast`.
|
|
117
|
-
|
|
118
|
-
| # | Class | Tier · effort | Steps |
|
|
119
|
-
|---|---|---|---|
|
|
120
|
-
| 1 | `generated` — every file generated or vendored | *skip* | — |
|
|
121
|
-
| 2 | `risky` — security / data-critical | thorough · high | review, fix, recheck |
|
|
122
|
-
| 3 | `deletion_only` | fast · medium | review |
|
|
123
|
-
| 4 | `docs` | balanced · high | review |
|
|
124
|
-
| 5 | `test_only` | fast · medium | review, fix |
|
|
125
|
-
| 6 | `config_infra` | balanced · high | review, fix, recheck |
|
|
126
|
-
| 7 | `trivial` | fast · medium | review, fix |
|
|
127
|
-
| 8 | `standard` — fallthrough | balanced · medium | review, fix, recheck |
|
|
128
|
-
|
|
129
|
-
Two classes drop the fix loop on purpose. `docs` is open-ended design
|
|
130
|
-
negotiation that no automated fix loop terminates. `deletion_only` carries
|
|
131
|
-
reference-breakage risk rather than defect density — a wrong deletion is
|
|
132
|
-
reverted, not patched — so it gets a review focused on dangling imports, call
|
|
133
|
-
sites, config keys, route registrations and stale doc pointers.
|
|
134
|
-
|
|
135
|
-
The last entry must have an empty `match`: it is the fallthrough, and
|
|
136
|
-
`resolveReviewStrategy` falls back to it when nothing matches. The verifier
|
|
137
|
-
asserts this.
|
|
138
|
-
|
|
139
|
-
### Path patterns are anchored
|
|
140
|
-
|
|
141
|
-
Class patterns match path *segments and extensions*, not substrings. An
|
|
142
|
-
unanchored list is worse than no list:
|
|
143
|
-
|
|
144
|
-
- `auth` matched `author.ts`, `authors.ts` and `oauth.ts`;
|
|
145
|
-
- `migration` matched this repo's own `MIGRATION_AND_GROWTH.md`, promoting a
|
|
146
|
-
pure-docs PR to `thorough` with a full fix/recheck loop;
|
|
147
|
-
- `spec` matched `src/lib/pr-spec.ts` and `test` matched any `latest.ts`,
|
|
148
|
-
routing ordinary source changes to `test_only` with a test-focused prompt.
|
|
149
|
-
|
|
150
|
-
Over-promotion is safe but expensive; under-review is neither. Both are bugs.
|
|
151
|
-
|
|
152
|
-
### Size caps fail closed
|
|
153
|
-
|
|
154
|
-
`src_churn_max` can only be evaluated when churn is attributable — the PR
|
|
155
|
-
context carries whole-PR `additions`/`deletions`, not per-file counts, so the
|
|
156
|
-
total is only meaningful when every changed file is source. When it is not, the
|
|
157
|
-
cap fails **closed** (the churn reads as `Infinity` and the class does not
|
|
158
|
-
match). Failing open cost us a real misroute: `['package.json',
|
|
159
|
-
'src/lib/runner.ts', 'src/lib/board.ts']` at +3000/−2000 satisfied
|
|
160
|
-
`files_max: 3`, the unattributable churn read as `0`, and a 5,000-line change to
|
|
161
|
-
the core runner was routed to `fast` with no recheck.
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## 6. Design decisions
|
|
166
|
-
|
|
167
|
-
### 6.1 Why a versioned policy file, not code
|
|
168
|
-
|
|
169
|
-
Every crosscheck comment cites `strategy=<version>`. A review that ran three
|
|
170
|
-
months ago has to stay explicable by the policy in force when it ran, and that is
|
|
171
|
-
only possible if the policy is a versioned artifact rather than a diff of
|
|
172
|
-
`if` statements. It also puts the routing decision and the sentence explaining it
|
|
173
|
-
in the same record, so the two cannot drift apart: `reason` is quoted verbatim
|
|
174
|
-
into the PR comment, which is why the verifier fails any class missing one.
|
|
175
|
-
|
|
176
|
-
`review-model-tiers.json` is retained for backwards compatibility and is
|
|
177
|
-
superseded by this file.
|
|
178
|
-
|
|
179
|
-
### 6.2 Why capability is not a single number
|
|
180
|
-
|
|
181
|
-
See §4. A tier ladder is a cost ladder that happens to correlate with capability
|
|
182
|
-
inside one vendor. Across vendors and across domains it stops correlating, which
|
|
183
|
-
is why `domains.*.preferred` exists and why each entry carries a `confidence`
|
|
184
|
-
field. `measured` and `hypothesis` are load-bearing words here — the frontend
|
|
185
|
-
list is a hypothesis and is labelled as one.
|
|
186
|
-
|
|
187
|
-
### 6.3 Why `thorough` moved to Opus 5
|
|
188
|
-
|
|
189
|
-
Identical $5/$25 pricing, higher SWE-bench Verified (0.960 vs the 4.8 pin it
|
|
190
|
-
replaced). There is no trade here; the old pin was a silent capability loss, and
|
|
191
|
-
it persisted only because nothing was watching. §2 exists so the next one does
|
|
192
|
-
not persist.
|
|
193
|
-
|
|
194
|
-
### 6.4 Models with no effort ladder — the OpenCode case
|
|
195
|
-
|
|
196
|
-
Most open-weight models expose no effort parameter at all: `kimi-k3`, `glm-5.2`
|
|
197
|
-
and `claude-haiku-4-5-20251001` all have `effort_levels: []`, and the deepseek
|
|
198
|
-
models expose only `none`/`high`/`max`. An escalation step defined purely as
|
|
199
|
-
"raise effort" silently no-ops on every one of them.
|
|
200
|
-
|
|
201
|
-
So the ladder declares `effort_fallback: "promote_tier"`: where effort cannot
|
|
202
|
-
rise, the escalation degrades to a model step instead. `escalate()` implements
|
|
203
|
-
this by clamping the round's target effort to what the model actually accepts and
|
|
204
|
-
promoting a tier only when the clamped value is not an increase over the round
|
|
205
|
-
before — otherwise a model whose ladder tops out below `xhigh` comes out of
|
|
206
|
-
round 3 *weaker* than it left round 2.
|
|
207
|
-
|
|
208
|
-
The verifier enforces the invariant directly: if any model has no effort levels,
|
|
209
|
-
`ladder.effort_fallback` must be set.
|
|
210
|
-
|
|
211
|
-
### 6.5 Escalate on measured non-convergence, never on predicted complexity
|
|
212
|
-
|
|
213
|
-
The ladder is bounded — 3 rounds, 5 blocking findings, 60 wall-clock minutes —
|
|
214
|
-
and each round narrows scope rather than widening it. Round 2 rechecks the delta
|
|
215
|
-
plus the open findings, not the whole PR again. The model never weakens across
|
|
216
|
-
rounds; only its scope shrinks. Round 4 is a handoff to a human with a digest,
|
|
217
|
-
not a fourth attempt.
|
|
218
|
-
|
|
219
|
-
### 6.6 Cross-vendor vs single-vendor
|
|
220
|
-
|
|
221
|
-
Cross-vendor buys an independent second perspective: in the census a vendor
|
|
222
|
-
switch broke a stalled loop twice (PR #2057, #2060) after same-vendor escalation
|
|
223
|
-
had failed for three to six rounds. Its round-3 lever is *switch vendor and raise
|
|
224
|
-
effort*, and it caps at 3 rounds. Single-vendor buys one CLI to authenticate,
|
|
225
|
-
version and monitor, with no routing logic; its round-3 lever is *raise effort,
|
|
226
|
-
then promote one tier*, because no fresh-eyes option exists, and it caps at 2.
|
|
227
|
-
|
|
228
|
-
### 6.7 Conflict resolution is not a review
|
|
229
|
-
|
|
230
|
-
`conflict_resolve` runs at `fast`/`low` regardless of class. Resolving conflict
|
|
231
|
-
markers is mechanical text surgery bounded by the markers themselves — measured
|
|
232
|
-
at 37s against ~643s for a review. Spending review-grade capability on it buys
|
|
233
|
-
nothing.
|
|
234
|
-
|
|
235
|
-
### 6.8 What classification may and may not conclude
|
|
236
|
-
|
|
237
|
-
Two rules constrain the classifier, and they are the reason it stays a small
|
|
238
|
-
static function instead of growing into a difficulty predictor:
|
|
239
|
-
|
|
240
|
-
1. **It may set a floor, or promote on consequence.** A security path is
|
|
241
|
-
reviewed thoroughly because a miss there is expensive. That is a statement
|
|
242
|
-
about cost of failure, which the file list genuinely supports.
|
|
243
|
-
2. **It may not predict that a PR will be hard.** Static features — file count,
|
|
244
|
-
line count, extension mix — do not support that inference. Difficulty is
|
|
245
|
-
discovered by reviewing, not before it. So there is no "this looks tricky,
|
|
246
|
-
use the big model" rule, and there never should be.
|
|
247
|
-
|
|
248
|
-
Escalation is how difficulty gets handled, and it is driven by *measured*
|
|
249
|
-
non-convergence: the review came back BLOCK, the fix did not resolve it, so the
|
|
250
|
-
next round escalates. That is evidence. A file-count heuristic is not.
|
|
251
|
-
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
## 7. Runtime status
|
|
255
|
-
|
|
256
|
-
`runtime_status: "defined_not_wired"`. This file and the JSON are the adopted
|
|
257
|
-
policy, but no runtime code reads `resolveReviewStrategy()` yet —
|
|
258
|
-
`resolveClaudeModel` / `resolveCodexModel` still apply the single configured
|
|
259
|
-
`quality.tier`. Verification, documentation and the citation contract are in
|
|
260
|
-
place ahead of the resolver so the policy is settled before it is enforced.
|
|
261
|
-
|
|
262
|
-
Consequently:
|
|
263
|
-
|
|
264
|
-
- `quality.mode` stays **optional**. Unset means `fixed` — the legacy behaviour —
|
|
265
|
-
and it will stay that way until the resolver lands, so nothing silently changes
|
|
266
|
-
tier on upgrade.
|
|
267
|
-
- `citation.annotation_fields` (`strategy`, `class`, `tier`) is a declared
|
|
268
|
-
contract, not yet emitted by `src/lib/annotation.ts`.
|
|
269
|
-
|
|
270
|
-
Wiring is the next change, and it is a separate one. It needs the PR's changed-file
|
|
271
|
-
list threaded to the reviewers, the `strategy` argument passed at each
|
|
272
|
-
`resolve*Model` call site, and the annotation fields emitted — none of which
|
|
273
|
-
belongs in the PR that settles the policy.
|
|
274
|
-
|
|
275
|
-
---
|
|
276
|
-
|
|
277
|
-
## 8. Cadence
|
|
278
|
-
|
|
279
|
-
`review_interval_days: 60`. The verifier warns past 45 days and fails past 60.
|
|
280
|
-
The `Review Strategy` workflow runs Mondays at 09:15 UTC — fifteen minutes after
|
|
281
|
-
`model-tier-sources`, so the two do not race the same provider docs — and on any
|
|
282
|
-
PR touching the strategy, the verifier or this document.
|
|
283
|
-
|
|
284
|
-
To refresh: re-read the `sources` and `benchmarks` pages, update prices, scores
|
|
285
|
-
and tier assignments in `src/config/review-strategy.json`, refresh the analysis
|
|
286
|
-
here, bump `version` and `updated`, then run `npm run verify:strategy`.
|