@vextlabs/theron-cli 0.1.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 +15 -0
- package/LICENSE.txt +190 -0
- package/README.md +98 -0
- package/bin/theron +22 -0
- package/bin/theron.js +25 -0
- package/dist/api.d.ts +111 -0
- package/dist/api.js +328 -0
- package/dist/api.js.map +1 -0
- package/dist/auth.d.ts +15 -0
- package/dist/auth.js +92 -0
- package/dist/auth.js.map +1 -0
- package/dist/banner.d.ts +29 -0
- package/dist/banner.js +191 -0
- package/dist/banner.js.map +1 -0
- package/dist/cap_config.d.ts +28 -0
- package/dist/cap_config.js +83 -0
- package/dist/cap_config.js.map +1 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/connections.d.ts +3 -0
- package/dist/connections.js +105 -0
- package/dist/connections.js.map +1 -0
- package/dist/import_claude.d.ts +3 -0
- package/dist/import_claude.js +268 -0
- package/dist/import_claude.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +237 -0
- package/dist/index.js.map +1 -0
- package/dist/onboard.d.ts +3 -0
- package/dist/onboard.js +234 -0
- package/dist/onboard.js.map +1 -0
- package/dist/profile_match.d.ts +15 -0
- package/dist/profile_match.js +107 -0
- package/dist/profile_match.js.map +1 -0
- package/dist/profiles/index.d.ts +20 -0
- package/dist/profiles/index.js +56 -0
- package/dist/profiles/index.js.map +1 -0
- package/dist/profiles/seeds.d.ts +4 -0
- package/dist/profiles/seeds.js +500 -0
- package/dist/profiles/seeds.js.map +1 -0
- package/dist/profiles/types.d.ts +35 -0
- package/dist/profiles/types.js +18 -0
- package/dist/profiles/types.js.map +1 -0
- package/dist/render.d.ts +18 -0
- package/dist/render.js +82 -0
- package/dist/render.js.map +1 -0
- package/dist/repl.d.ts +13 -0
- package/dist/repl.js +821 -0
- package/dist/repl.js.map +1 -0
- package/dist/streaming.d.ts +28 -0
- package/dist/streaming.js +118 -0
- package/dist/streaming.js.map +1 -0
- package/dist/tools/bash.d.ts +8 -0
- package/dist/tools/bash.js +57 -0
- package/dist/tools/bash.js.map +1 -0
- package/dist/tools/edit.d.ts +9 -0
- package/dist/tools/edit.js +42 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +7 -0
- package/dist/tools/glob.js +40 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +9 -0
- package/dist/tools/grep.js +73 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.d.ts +31 -0
- package/dist/tools/index.js +180 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/ls.d.ts +6 -0
- package/dist/tools/ls.js +25 -0
- package/dist/tools/ls.js.map +1 -0
- package/dist/tools/read.d.ts +8 -0
- package/dist/tools/read.js +43 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/stoa.d.ts +34 -0
- package/dist/tools/stoa.js +103 -0
- package/dist/tools/stoa.js.map +1 -0
- package/dist/tools/write.d.ts +7 -0
- package/dist/tools/write.js +15 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/verifiers/ai_ism_check.d.ts +2 -0
- package/dist/verifiers/ai_ism_check.js +48 -0
- package/dist/verifiers/ai_ism_check.js.map +1 -0
- package/dist/verifiers/arithmetic_recheck.d.ts +2 -0
- package/dist/verifiers/arithmetic_recheck.js +74 -0
- package/dist/verifiers/arithmetic_recheck.js.map +1 -0
- package/dist/verifiers/citation_presence.d.ts +2 -0
- package/dist/verifiers/citation_presence.js +42 -0
- package/dist/verifiers/citation_presence.js.map +1 -0
- package/dist/verifiers/em_dash_check.d.ts +2 -0
- package/dist/verifiers/em_dash_check.js +23 -0
- package/dist/verifiers/em_dash_check.js.map +1 -0
- package/dist/verifiers/index.d.ts +16 -0
- package/dist/verifiers/index.js +123 -0
- package/dist/verifiers/index.js.map +1 -0
- package/dist/verifiers/lint.d.ts +2 -0
- package/dist/verifiers/lint.js +90 -0
- package/dist/verifiers/lint.js.map +1 -0
- package/dist/verifiers/style_lint.d.ts +2 -0
- package/dist/verifiers/style_lint.js +115 -0
- package/dist/verifiers/style_lint.js.map +1 -0
- package/dist/verifiers/test_smoke.d.ts +2 -0
- package/dist/verifiers/test_smoke.js +94 -0
- package/dist/verifiers/test_smoke.js.map +1 -0
- package/dist/verifiers/typecheck.d.ts +2 -0
- package/dist/verifiers/typecheck.js +98 -0
- package/dist/verifiers/typecheck.js.map +1 -0
- package/dist/verifiers/types.d.ts +33 -0
- package/dist/verifiers/types.js +23 -0
- package/dist/verifiers/types.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Citation-presence verifier — used by the legal, research, academic,
|
|
2
|
+
// medical, and policy profiles. Checks that the output contains AT
|
|
3
|
+
// LEAST ONE citation in a recognized form for outputs over a threshold
|
|
4
|
+
// length.
|
|
5
|
+
//
|
|
6
|
+
// We don't try to validate citations against an external corpus (that
|
|
7
|
+
// requires WebFetch + tool budget); we just enforce that the model
|
|
8
|
+
// committed itself to citing rather than hand-waving.
|
|
9
|
+
// Acceptable citation forms:
|
|
10
|
+
// - Legal: [Source §1.2(b)] / [State v. Foo, 123 U.S. 456 (1900)] / [USC §123]
|
|
11
|
+
// - Academic: [Smith 2022] / [Smith et al. 2022] / (Smith, 2022)
|
|
12
|
+
// - Markdown link: [text](url)
|
|
13
|
+
// - URL: https://...
|
|
14
|
+
const CITATION_PATTERNS = [
|
|
15
|
+
/\[[^\]]*§[^\]]*\]/, // [...§...]
|
|
16
|
+
/\[[A-Z][a-z]+(?:\s+et\s+al\.?)?\s+\d{4}\]/, // [Smith 2022] / [Smith et al. 2022]
|
|
17
|
+
/\([A-Z][a-z]+(?:\s+et\s+al\.?)?,?\s+\d{4}\)/, // (Smith, 2022)
|
|
18
|
+
/\[\s*[^\]]+v\.\s+[^\]]+,\s*\d{4}\]/, // [Foo v. Bar, 1985]
|
|
19
|
+
/\bhttps?:\/\/\S+/, // URL
|
|
20
|
+
/\[[^\]]+\]\(\S+\)/, // Markdown link
|
|
21
|
+
];
|
|
22
|
+
const MIN_LENGTH_TO_REQUIRE_CITATION = 280;
|
|
23
|
+
const APPLIES_TO_PROFILES = new Set(["legal", "research", "academic", "medical", "policy", "architect"]);
|
|
24
|
+
export const citationPresenceKernel = {
|
|
25
|
+
slug: "citation_presence",
|
|
26
|
+
describe: "Output above threshold length must contain ≥1 recognized citation",
|
|
27
|
+
async run(ctx) {
|
|
28
|
+
if (!APPLIES_TO_PROFILES.has(ctx.profile))
|
|
29
|
+
return [];
|
|
30
|
+
if (ctx.assistantText.length < MIN_LENGTH_TO_REQUIRE_CITATION)
|
|
31
|
+
return [];
|
|
32
|
+
const hasOne = CITATION_PATTERNS.some((re) => re.test(ctx.assistantText));
|
|
33
|
+
if (hasOne)
|
|
34
|
+
return [];
|
|
35
|
+
return [{
|
|
36
|
+
severity: "warn",
|
|
37
|
+
kernel: "citation_presence",
|
|
38
|
+
message: "Substantive output with no citations — cite a source, statute, paper, or URL",
|
|
39
|
+
}];
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=citation_presence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"citation_presence.js","sourceRoot":"","sources":["../../src/verifiers/citation_presence.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,mEAAmE;AACnE,uEAAuE;AACvE,UAAU;AACV,EAAE;AACF,sEAAsE;AACtE,mEAAmE;AACnE,sDAAsD;AAItD,6BAA6B;AAC7B,iFAAiF;AACjF,mEAAmE;AACnE,iCAAiC;AACjC,uBAAuB;AACvB,MAAM,iBAAiB,GAAG;IACxB,mBAAmB,EAAmB,YAAY;IAClD,2CAA2C,EAAG,qCAAqC;IACnF,6CAA6C,EAAE,gBAAgB;IAC/D,oCAAoC,EAAS,qBAAqB;IAClE,kBAAkB,EAA6B,MAAM;IACrD,mBAAmB,EAA4B,gBAAgB;CAChE,CAAC;AAEF,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAE3C,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;AAEzG,MAAM,CAAC,MAAM,sBAAsB,GAAa;IAC9C,IAAI,EAAE,mBAAmB;IACzB,QAAQ,EAAE,mEAAmE;IAC7E,KAAK,CAAC,GAAG,CAAC,GAAoB;QAC5B,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;YAAE,OAAO,EAAE,CAAC;QACrD,IAAI,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,8BAA8B;YAAE,OAAO,EAAE,CAAC;QACzE,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1E,IAAI,MAAM;YAAE,OAAO,EAAE,CAAC;QACtB,OAAO,CAAC;gBACN,QAAQ,EAAE,MAAM;gBAChB,MAAM,EAAE,mBAAmB;gBAC3B,OAAO,EAAE,8EAA8E;aACxF,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Em-dash checker — the single highest-signal "this was AI-generated"
|
|
2
|
+
// tell. The writing profile system prompt forbids em-dashes; this
|
|
3
|
+
// kernel surfaces any that slip through.
|
|
4
|
+
//
|
|
5
|
+
// Why this matters: writing mode is one of the profiles where Theron
|
|
6
|
+
// has the most surface area to differentiate. Every AI assistant on
|
|
7
|
+
// the planet outputs em-dashes. Theron does not. Period.
|
|
8
|
+
const EM_DASH_RE = /—/g;
|
|
9
|
+
export const emDashCheckKernel = {
|
|
10
|
+
slug: "em_dash_check",
|
|
11
|
+
describe: "Scan output for em-dashes (—) — the #1 AI-text tell",
|
|
12
|
+
async run(ctx) {
|
|
13
|
+
const matches = [...ctx.assistantText.matchAll(EM_DASH_RE)];
|
|
14
|
+
if (matches.length === 0)
|
|
15
|
+
return [];
|
|
16
|
+
return [{
|
|
17
|
+
severity: "block",
|
|
18
|
+
kernel: "em_dash_check",
|
|
19
|
+
message: `Found ${matches.length} em-dash${matches.length === 1 ? "" : "es"} (—). Replace with a period, comma, parenthesis, or "but".`,
|
|
20
|
+
}];
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=em_dash_check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"em_dash_check.js","sourceRoot":"","sources":["../../src/verifiers/em_dash_check.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,kEAAkE;AAClE,yCAAyC;AACzC,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,yDAAyD;AAIzD,MAAM,UAAU,GAAG,IAAI,CAAC;AAExB,MAAM,CAAC,MAAM,iBAAiB,GAAa;IACzC,IAAI,EAAE,eAAe;IACrB,QAAQ,EAAE,qDAAqD;IAC/D,KAAK,CAAC,GAAG,CAAC,GAAoB;QAC5B,MAAM,OAAO,GAAG,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;QAC5D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACpC,OAAO,CAAC;gBACN,QAAQ,EAAE,OAAO;gBACjB,MAAM,EAAE,eAAe;gBACvB,OAAO,EAAE,SAAS,OAAO,CAAC,MAAM,WAAW,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,4DAA4D;aACxI,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { VerifierContext, VerifierIssue } from "./types.js";
|
|
2
|
+
export type { Verifier, VerifierContext, VerifierIssue } from "./types.js";
|
|
3
|
+
/** Run the kernels for the active profile in parallel. Each kernel
|
|
4
|
+
* has its own 5s timeout — slow kernels return [] rather than block
|
|
5
|
+
* the loop. Total wall time bounded by max(per-kernel time, 5s). */
|
|
6
|
+
export declare function runVerifiers(slugs: string[] | undefined, ctx: VerifierContext): Promise<VerifierIssue[]>;
|
|
7
|
+
/** Format issues into a short summary chip for the terminal. */
|
|
8
|
+
export declare function summarizeIssues(issues: VerifierIssue[]): {
|
|
9
|
+
ok: boolean;
|
|
10
|
+
summary: string;
|
|
11
|
+
details: string[];
|
|
12
|
+
};
|
|
13
|
+
/** Encode verifier results as a system block to prepend to the next
|
|
14
|
+
* user turn. The model picks this up and self-corrects without the
|
|
15
|
+
* user typing "fix it." Empty string when there's nothing to surface. */
|
|
16
|
+
export declare function formatForNextTurn(issues: VerifierIssue[]): string;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Verifier kernel registry + dispatch.
|
|
2
|
+
//
|
|
3
|
+
// Profile.verifiers[] is a list of kernel slugs ("typecheck", "lint",
|
|
4
|
+
// "em_dash_check", etc.). After every assistant turn that produced
|
|
5
|
+
// output, we run the active profile's kernels in parallel and
|
|
6
|
+
// collect their issues. The summary surfaces as a small inline chip:
|
|
7
|
+
//
|
|
8
|
+
// ✓ verifiers: typecheck, lint, test_smoke (all green, 312ms)
|
|
9
|
+
// ✗ verifiers: 2 issues — tsc: 1 error · style_lint: 1 warning
|
|
10
|
+
//
|
|
11
|
+
// The full issue list gets fed back into the next turn's user message
|
|
12
|
+
// as a SYSTEM block so the model can self-correct without the user
|
|
13
|
+
// needing to copy-paste error messages.
|
|
14
|
+
import { typecheckKernel } from "./typecheck.js";
|
|
15
|
+
import { lintKernel } from "./lint.js";
|
|
16
|
+
import { testSmokeKernel } from "./test_smoke.js";
|
|
17
|
+
import { styleLintKernel } from "./style_lint.js";
|
|
18
|
+
import { emDashCheckKernel } from "./em_dash_check.js";
|
|
19
|
+
import { aiIsmCheckKernel } from "./ai_ism_check.js";
|
|
20
|
+
import { citationPresenceKernel } from "./citation_presence.js";
|
|
21
|
+
import { arithmeticRecheckKernel } from "./arithmetic_recheck.js";
|
|
22
|
+
// Map slug → kernel. Profiles reference these via Profile.verifiers[].
|
|
23
|
+
const REGISTRY = new Map();
|
|
24
|
+
function register(v) { REGISTRY.set(v.slug, v); }
|
|
25
|
+
register(typecheckKernel);
|
|
26
|
+
register(lintKernel);
|
|
27
|
+
register(testSmokeKernel);
|
|
28
|
+
register(styleLintKernel);
|
|
29
|
+
register(emDashCheckKernel);
|
|
30
|
+
register(aiIsmCheckKernel);
|
|
31
|
+
register(citationPresenceKernel);
|
|
32
|
+
register(arithmeticRecheckKernel);
|
|
33
|
+
// Aliases for verifier slugs referenced in seeds.ts that share a kernel
|
|
34
|
+
// (e.g. assumption_marked / advice_disclaimer / confidence_marked all
|
|
35
|
+
// run via style_lint with a different config — the verifier reads the
|
|
36
|
+
// active profile slug to know what to look for).
|
|
37
|
+
for (const alias of [
|
|
38
|
+
"claim_grounding",
|
|
39
|
+
"assumption_marked",
|
|
40
|
+
"advice_disclaimer",
|
|
41
|
+
"confidence_marked",
|
|
42
|
+
"sentence_variance",
|
|
43
|
+
"unit_consistency",
|
|
44
|
+
"component_states_complete",
|
|
45
|
+
"token_lint",
|
|
46
|
+
]) {
|
|
47
|
+
// Default these aliases to the style_lint kernel for now — they're
|
|
48
|
+
// surfaced as the kernel name in issue.kernel so the user still sees
|
|
49
|
+
// which rule fired. Each gets its own kernel as we promote them out
|
|
50
|
+
// of "auto-baseline" into "hand-crafted."
|
|
51
|
+
REGISTRY.set(alias, { ...styleLintKernel, slug: alias });
|
|
52
|
+
}
|
|
53
|
+
/** Run the kernels for the active profile in parallel. Each kernel
|
|
54
|
+
* has its own 5s timeout — slow kernels return [] rather than block
|
|
55
|
+
* the loop. Total wall time bounded by max(per-kernel time, 5s). */
|
|
56
|
+
export async function runVerifiers(slugs, ctx) {
|
|
57
|
+
if (!slugs || slugs.length === 0)
|
|
58
|
+
return [];
|
|
59
|
+
const kernels = slugs
|
|
60
|
+
.map((s) => REGISTRY.get(s))
|
|
61
|
+
.filter((k) => k !== undefined);
|
|
62
|
+
if (kernels.length === 0)
|
|
63
|
+
return [];
|
|
64
|
+
const results = await Promise.all(kernels.map(async (k) => {
|
|
65
|
+
try {
|
|
66
|
+
const issues = await Promise.race([
|
|
67
|
+
k.run(ctx),
|
|
68
|
+
new Promise((resolve) => setTimeout(() => resolve([]), 5000)),
|
|
69
|
+
]);
|
|
70
|
+
return issues;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
// Verifier crashes don't kill the turn — surface as info.
|
|
74
|
+
return [{
|
|
75
|
+
severity: "info",
|
|
76
|
+
kernel: k.slug,
|
|
77
|
+
message: `verifier crashed: ${err instanceof Error ? err.message : String(err)}`,
|
|
78
|
+
}];
|
|
79
|
+
}
|
|
80
|
+
}));
|
|
81
|
+
return results.flat();
|
|
82
|
+
}
|
|
83
|
+
/** Format issues into a short summary chip for the terminal. */
|
|
84
|
+
export function summarizeIssues(issues) {
|
|
85
|
+
if (issues.length === 0)
|
|
86
|
+
return { ok: true, summary: "verifiers ✓", details: [] };
|
|
87
|
+
const blocks = issues.filter((i) => i.severity === "block");
|
|
88
|
+
const warns = issues.filter((i) => i.severity === "warn");
|
|
89
|
+
const ok = blocks.length === 0;
|
|
90
|
+
const parts = [];
|
|
91
|
+
if (blocks.length > 0)
|
|
92
|
+
parts.push(`${blocks.length} block`);
|
|
93
|
+
if (warns.length > 0)
|
|
94
|
+
parts.push(`${warns.length} warn`);
|
|
95
|
+
return {
|
|
96
|
+
ok,
|
|
97
|
+
summary: parts.join(" · "),
|
|
98
|
+
details: issues.map((i) => {
|
|
99
|
+
const sev = i.severity === "block" ? "✗" : i.severity === "warn" ? "·" : "i";
|
|
100
|
+
const loc = i.location ? ` ${i.location}` : "";
|
|
101
|
+
return ` ${sev} ${i.kernel}:${loc} ${i.message}`;
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Encode verifier results as a system block to prepend to the next
|
|
106
|
+
* user turn. The model picks this up and self-corrects without the
|
|
107
|
+
* user typing "fix it." Empty string when there's nothing to surface. */
|
|
108
|
+
export function formatForNextTurn(issues) {
|
|
109
|
+
const blocks = issues.filter((i) => i.severity === "block");
|
|
110
|
+
if (blocks.length === 0)
|
|
111
|
+
return "";
|
|
112
|
+
const lines = blocks.map((i) => {
|
|
113
|
+
const loc = i.location ? ` (${i.location})` : "";
|
|
114
|
+
return `- [${i.kernel}]${loc} ${i.message}`;
|
|
115
|
+
});
|
|
116
|
+
return [
|
|
117
|
+
"[VERIFIER SUMMARY — auto-injected by CLI after your last turn]",
|
|
118
|
+
"These issues blocked your previous output. Address them in the next response, then continue:",
|
|
119
|
+
...lines,
|
|
120
|
+
"",
|
|
121
|
+
].join("\n");
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/verifiers/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Lint verifier — looks for the easy mechanical problems that a real
|
|
2
|
+
// production codebase would catch in CI: console.log left in, debugger
|
|
3
|
+
// statements, TODO without a date, .only() in tests, eslint-disable
|
|
4
|
+
// without a reason. These are LIGHTWEIGHT checks the kernel does
|
|
5
|
+
// without invoking eslint (a real eslint run would take 30+ seconds
|
|
6
|
+
// on a large repo; we have a 5s budget).
|
|
7
|
+
//
|
|
8
|
+
// For projects that have an `npm run lint:fast` script, we'd hand off
|
|
9
|
+
// to that — but most don't. This kernel is the "Theron found this in
|
|
10
|
+
// 200ms instead of waiting for CI" win.
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
const RULES = [
|
|
14
|
+
// Code rules.
|
|
15
|
+
{
|
|
16
|
+
kernel: "lint",
|
|
17
|
+
applies: (p) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p),
|
|
18
|
+
pattern: /\bconsole\.log\s*\(/g,
|
|
19
|
+
message: () => "console.log left in (use a real logger or remove before commit)",
|
|
20
|
+
severity: "warn",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
kernel: "lint",
|
|
24
|
+
applies: (p) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p),
|
|
25
|
+
pattern: /\bdebugger\b/g,
|
|
26
|
+
message: () => "`debugger` statement left in",
|
|
27
|
+
severity: "block",
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
kernel: "lint",
|
|
31
|
+
applies: (p) => /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(p),
|
|
32
|
+
pattern: /\.(only|skip)\(/g,
|
|
33
|
+
message: (m) => `.${m[1]}() left in test — would block / hide other tests in CI`,
|
|
34
|
+
severity: "block",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
kernel: "lint",
|
|
38
|
+
applies: (p) => /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(p),
|
|
39
|
+
pattern: /\/\/\s*eslint-disable(?:-next-line|-line)?(?!.+--\s*[\S])/g,
|
|
40
|
+
message: () => "eslint-disable without an inline reason after `--`",
|
|
41
|
+
severity: "warn",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
kernel: "lint",
|
|
45
|
+
applies: (p) => /\.(ts|tsx|js|jsx|mjs|cjs|md)$/.test(p),
|
|
46
|
+
pattern: /\bTODO\b(?!\s*\(\d{4}-\d{2}-\d{2}\))/g,
|
|
47
|
+
message: () => "TODO without a date in the form TODO(YYYY-MM-DD)",
|
|
48
|
+
severity: "warn",
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
export const lintKernel = {
|
|
52
|
+
slug: "lint",
|
|
53
|
+
describe: "Mechanical lint pass on touched files (no-debugger, .only, dated TODOs, etc.)",
|
|
54
|
+
async run(ctx) {
|
|
55
|
+
if (ctx.touchedFiles.length === 0)
|
|
56
|
+
return [];
|
|
57
|
+
const issues = [];
|
|
58
|
+
for (const rel of ctx.touchedFiles) {
|
|
59
|
+
const abs = path.isAbsolute(rel) ? rel : path.join(ctx.cwd, rel);
|
|
60
|
+
let content;
|
|
61
|
+
try {
|
|
62
|
+
content = fs.readFileSync(abs, "utf8");
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
for (const rule of RULES) {
|
|
68
|
+
if (!rule.applies(abs))
|
|
69
|
+
continue;
|
|
70
|
+
let m;
|
|
71
|
+
rule.pattern.lastIndex = 0;
|
|
72
|
+
while ((m = rule.pattern.exec(content))) {
|
|
73
|
+
const lineNo = content.slice(0, m.index).split("\n").length;
|
|
74
|
+
issues.push({
|
|
75
|
+
severity: rule.severity,
|
|
76
|
+
kernel: rule.kernel,
|
|
77
|
+
message: rule.message(m),
|
|
78
|
+
location: `${path.relative(ctx.cwd, abs)}:${lineNo}`,
|
|
79
|
+
});
|
|
80
|
+
// Cap repetitions of the same rule per file at 5 — saves us
|
|
81
|
+
// from spamming 200 "console.log" warnings.
|
|
82
|
+
if ((issues.filter((i) => i.kernel === rule.kernel).length) > 5)
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return issues;
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/verifiers/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Generic style-lint kernel — used as the fallback for profile.verifier
|
|
2
|
+
// slugs that don't have their own dedicated kernel yet (claim_grounding,
|
|
3
|
+
// assumption_marked, advice_disclaimer, confidence_marked,
|
|
4
|
+
// sentence_variance, etc.).
|
|
5
|
+
//
|
|
6
|
+
// Each "rule" inside this kernel is scoped to the profile slug — when
|
|
7
|
+
// running for the `legal` profile, we check for "Assumption:" markers
|
|
8
|
+
// and the licensed-attorney disclaimer; when running for `research`,
|
|
9
|
+
// we check for confidence markers and citations; etc.
|
|
10
|
+
//
|
|
11
|
+
// This is the catch-all that lets us ship 27 baseline specs without
|
|
12
|
+
// hand-crafting 27 separate kernels. Each rule that proves load-bearing
|
|
13
|
+
// gets promoted into its own dedicated kernel file over time.
|
|
14
|
+
const RULES_BY_PROFILE = {
|
|
15
|
+
legal: [
|
|
16
|
+
{
|
|
17
|
+
must: [/\bAssumption\b\s*[:\-]/i, /\bAssumes\b/i],
|
|
18
|
+
mustMessage: "Legal output missing 'Assumption:' marker — flag the facts you're treating as given",
|
|
19
|
+
appliesIfOutputLongerThan: 240,
|
|
20
|
+
severity: "warn",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
must: [/licen[sc]ed attorney|consult.*attorney/i],
|
|
24
|
+
mustMessage: "Legal output missing the 'have a licensed attorney review' disclaimer",
|
|
25
|
+
appliesIfOutputLongerThan: 240,
|
|
26
|
+
severity: "block",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
research: [
|
|
30
|
+
{
|
|
31
|
+
must: [/\bConfidence\b\s*[:\-]/i, /\bconfidence:?\s*(high|medium|low)/i],
|
|
32
|
+
mustMessage: "Research output missing a confidence marker — qualify the claims",
|
|
33
|
+
appliesIfOutputLongerThan: 360,
|
|
34
|
+
severity: "warn",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
must: [/\[\s*(?:[A-Z][a-z]+\s+){0,3}\d{4}.{0,40}\]|https?:\/\/\S+/],
|
|
38
|
+
mustMessage: "Research output missing source citations [Author Year] or URLs",
|
|
39
|
+
appliesIfOutputLongerThan: 360,
|
|
40
|
+
severity: "warn",
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
medical: [
|
|
44
|
+
{
|
|
45
|
+
must: [/(licen[sc]ed physician|medical advice|consult.*(physician|doctor))/i],
|
|
46
|
+
mustMessage: "Medical output missing the 'not medical advice / consult a physician' disclaimer",
|
|
47
|
+
severity: "block",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
therapy: [
|
|
51
|
+
{
|
|
52
|
+
must: [/(licen[sc]ed therapist|isn'?t therapy|crisis line|988)/i],
|
|
53
|
+
mustMessage: "Therapy output missing the 'not clinical therapy / crisis line' line",
|
|
54
|
+
severity: "block",
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
trader: [
|
|
58
|
+
{
|
|
59
|
+
must: [/(not investment advice|educational|past performance)/i],
|
|
60
|
+
mustMessage: "Trader output missing the 'educational, not investment advice' disclaimer",
|
|
61
|
+
severity: "block",
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
trainer: [
|
|
65
|
+
{
|
|
66
|
+
must: [/(sports medicine|see a (physician|doctor|trainer)|if anything hurts)/i],
|
|
67
|
+
mustMessage: "Trainer output missing the 'see a sports medicine physician if it hurts' disclaimer",
|
|
68
|
+
severity: "block",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
design: [
|
|
72
|
+
{
|
|
73
|
+
must: [/(default|hover|focus|active|disabled|error|loading)/i],
|
|
74
|
+
mustMessage: "Design spec missing state coverage — include default/hover/focus/active/disabled/error/loading",
|
|
75
|
+
appliesIfOutputLongerThan: 300,
|
|
76
|
+
severity: "warn",
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
};
|
|
80
|
+
export const styleLintKernel = {
|
|
81
|
+
slug: "style_lint",
|
|
82
|
+
describe: "Profile-specific style + completeness checks (assumptions, disclaimers, state coverage)",
|
|
83
|
+
async run(ctx) {
|
|
84
|
+
const rules = RULES_BY_PROFILE[ctx.profile] || [];
|
|
85
|
+
if (rules.length === 0)
|
|
86
|
+
return [];
|
|
87
|
+
const issues = [];
|
|
88
|
+
for (const rule of rules) {
|
|
89
|
+
if (rule.appliesIfOutputLongerThan != null && ctx.assistantText.length < rule.appliesIfOutputLongerThan)
|
|
90
|
+
continue;
|
|
91
|
+
const hasMust = rule.must.some((re) => re.test(ctx.assistantText));
|
|
92
|
+
if (!hasMust) {
|
|
93
|
+
issues.push({
|
|
94
|
+
severity: rule.severity ?? "warn",
|
|
95
|
+
kernel: "style_lint",
|
|
96
|
+
message: rule.mustMessage,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (rule.forbid) {
|
|
100
|
+
for (const fre of rule.forbid) {
|
|
101
|
+
if (fre.test(ctx.assistantText)) {
|
|
102
|
+
issues.push({
|
|
103
|
+
severity: rule.severity ?? "warn",
|
|
104
|
+
kernel: "style_lint",
|
|
105
|
+
message: rule.forbidMessage ?? `Forbidden pattern matched: ${fre.source}`,
|
|
106
|
+
});
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return issues;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=style_lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"style_lint.js","sourceRoot":"","sources":["../../src/verifiers/style_lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Smoke-test verifier — runs the project's test command in "fast" mode
|
|
2
|
+
// against the touched files only. Doesn't run the full suite (that
|
|
3
|
+
// could take minutes); just checks that nothing the model touched
|
|
4
|
+
// breaks the existing tests for those files.
|
|
5
|
+
//
|
|
6
|
+
// Detection order:
|
|
7
|
+
// 1. `package.json` scripts.test:smoke / scripts.test:fast → run it
|
|
8
|
+
// 2. vitest config in repo → `vitest run --bail=1 <touched test files>`
|
|
9
|
+
// 3. jest config in repo → `jest --bail <touched test files>`
|
|
10
|
+
// 4. pytest available + tests/ dir → `pytest -q --maxfail=1 <touched .py test paths>`
|
|
11
|
+
//
|
|
12
|
+
// In all cases: 5s wall-clock budget. If the kernel can't finish in
|
|
13
|
+
// time it returns [] rather than blocking.
|
|
14
|
+
import { spawn } from "node:child_process";
|
|
15
|
+
import fs from "node:fs";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
function findUpward(startDir, names) {
|
|
18
|
+
let dir = startDir;
|
|
19
|
+
for (let i = 0; i < 10; i++) {
|
|
20
|
+
for (const name of names) {
|
|
21
|
+
const cand = path.join(dir, name);
|
|
22
|
+
if (fs.existsSync(cand))
|
|
23
|
+
return cand;
|
|
24
|
+
}
|
|
25
|
+
const parent = path.dirname(dir);
|
|
26
|
+
if (parent === dir)
|
|
27
|
+
break;
|
|
28
|
+
dir = parent;
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
async function runCmd(cmd, args, cwd, timeoutMs) {
|
|
33
|
+
return await new Promise((resolve) => {
|
|
34
|
+
let out = "";
|
|
35
|
+
const child = spawn(cmd, args, { cwd, env: { ...process.env, FORCE_COLOR: "0" }, shell: false });
|
|
36
|
+
const timer = setTimeout(() => { try {
|
|
37
|
+
child.kill("SIGKILL");
|
|
38
|
+
}
|
|
39
|
+
catch { /* ignore */ } }, timeoutMs);
|
|
40
|
+
child.stdout?.on("data", (b) => { out += b.toString("utf8"); });
|
|
41
|
+
child.stderr?.on("data", (b) => { out += b.toString("utf8"); });
|
|
42
|
+
child.on("close", (code) => { clearTimeout(timer); resolve({ code: code ?? -1, out }); });
|
|
43
|
+
child.on("error", () => { clearTimeout(timer); resolve({ code: -1, out }); });
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
export const testSmokeKernel = {
|
|
47
|
+
slug: "test_smoke",
|
|
48
|
+
describe: "Run the project's smoke / fast test command against touched files",
|
|
49
|
+
async run(ctx) {
|
|
50
|
+
if (ctx.touchedFiles.length === 0)
|
|
51
|
+
return [];
|
|
52
|
+
const pkgJsonPath = findUpward(ctx.cwd, ["package.json"]);
|
|
53
|
+
if (pkgJsonPath) {
|
|
54
|
+
try {
|
|
55
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
56
|
+
const scripts = pkg.scripts || {};
|
|
57
|
+
const scriptName = scripts["test:smoke"] ? "test:smoke"
|
|
58
|
+
: scripts["test:fast"] ? "test:fast"
|
|
59
|
+
: null;
|
|
60
|
+
if (scriptName) {
|
|
61
|
+
const res = await runCmd("npm", ["run", "--silent", scriptName], path.dirname(pkgJsonPath), 5000);
|
|
62
|
+
if (res.code !== 0) {
|
|
63
|
+
return [{
|
|
64
|
+
severity: "block",
|
|
65
|
+
kernel: "test_smoke",
|
|
66
|
+
message: `\`npm run ${scriptName}\` failed (exit ${res.code})`,
|
|
67
|
+
location: path.relative(ctx.cwd, pkgJsonPath),
|
|
68
|
+
}];
|
|
69
|
+
}
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch { /* fall through */ }
|
|
74
|
+
}
|
|
75
|
+
// Python: look for pytest + tests/ dir + touched .py files.
|
|
76
|
+
const pyTouched = ctx.touchedFiles.filter((p) => p.endsWith(".py"));
|
|
77
|
+
if (pyTouched.length > 0) {
|
|
78
|
+
const testsDir = findUpward(ctx.cwd, ["tests"]);
|
|
79
|
+
if (testsDir) {
|
|
80
|
+
const res = await runCmd("pytest", ["-q", "--maxfail=1", testsDir], ctx.cwd, 5000);
|
|
81
|
+
if (res.code !== 0 && res.code !== -1) {
|
|
82
|
+
return [{
|
|
83
|
+
severity: "block",
|
|
84
|
+
kernel: "test_smoke",
|
|
85
|
+
message: `pytest failed (exit ${res.code})`,
|
|
86
|
+
location: path.relative(ctx.cwd, testsDir),
|
|
87
|
+
}];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return [];
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=test_smoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test_smoke.js","sourceRoot":"","sources":["../../src/verifiers/test_smoke.ts"],"names":[],"mappings":"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"}
|