@agjs/tsforge 0.2.0 → 0.2.2

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/src/eval/score.ts CHANGED
@@ -20,6 +20,15 @@ export function summarize(records: IRunRecord[]): IVariantSummary[] {
20
20
  const sum = (select: (r: IRunRecord) => number): number =>
21
21
  list.reduce((acc, r) => acc + select(r), 0);
22
22
  const scored = list.filter((r) => r.quality !== undefined);
23
+ const failureClasses: Record<string, number> = {};
24
+
25
+ for (const r of list) {
26
+ const fc = r.failureClass;
27
+
28
+ if (!r.passed && fc !== undefined && fc !== "none") {
29
+ failureClasses[fc] = (failureClasses[fc] ?? 0) + 1;
30
+ }
31
+ }
23
32
 
24
33
  summaries.push({
25
34
  label,
@@ -32,6 +41,7 @@ export function summarize(records: IRunRecord[]): IVariantSummary[] {
32
41
  scored.length > 0
33
42
  ? scored.reduce((acc, r) => acc + (r.quality ?? 0), 0) / scored.length
34
43
  : 0,
44
+ failureClasses,
35
45
  });
36
46
  }
37
47
 
@@ -32,6 +32,10 @@ export interface ILoopEvent {
32
32
  /** For `timing` events: how long the turn took, in milliseconds. */
33
33
  ms?: number;
34
34
  errors?: number;
35
+ /** For `validated` events: the failing gate rules/codes (e.g. "TS18048",
36
+ * "no-restricted-syntax") — the structured substrate the failure classifier
37
+ * reads to tell a type error from a lint rule, not just a count. */
38
+ rules?: readonly string[];
35
39
  passed?: boolean;
36
40
  file?: string;
37
41
  /** For `create` events: the new file's content (rendered as a code block). */
package/src/loop/turn.ts CHANGED
@@ -784,6 +784,9 @@ export async function settleGate(
784
784
  cycle: turn,
785
785
  passed: gatePassed,
786
786
  errors: gateErrors.length,
787
+ // Structured rule/code list (not just a count) so the failure classifier can
788
+ // tell a type error from a lint rule without re-parsing the gate output.
789
+ rules: gateErrors.flatMap((e) => (e.rule === undefined ? [] : [e.rule])),
787
790
  message: gatePassed
788
791
  ? `task ${task.id} · turn ${turn}: GREEN`
789
792
  : `task ${task.id} · turn ${turn}: red (${String(gateErrors.length)} error(s))${gateDetail}`,
@@ -12,6 +12,7 @@
12
12
  // Rule overrides are loaded via TSFORGE_RULE_OVERRIDES env var (JSON-encoded
13
13
  // map of bare rule names to "error" | "warn" | "off").
14
14
  import tseslint from "typescript-eslint";
15
+ import stylistic from "@stylistic/eslint-plugin";
15
16
 
16
17
  // Load stack-aware packs if TSFORGE_PACKS env var is set
17
18
  let packConfig = [];
@@ -52,7 +53,10 @@ export default tseslint.config(
52
53
  {
53
54
  files: ["**/*.ts", "**/*.tsx"],
54
55
  languageOptions: { parser: tseslint.parser },
55
- plugins: { "@typescript-eslint": tseslint.plugin },
56
+ plugins: {
57
+ "@typescript-eslint": tseslint.plugin,
58
+ "@stylistic": stylistic,
59
+ },
56
60
  rules: {
57
61
  // The idioms the model habitually violates — all caught WITHOUT type info.
58
62
  "@typescript-eslint/consistent-type-assertions": [
@@ -69,6 +73,25 @@ export default tseslint.config(
69
73
  "prefer-const": "error",
70
74
  "prefer-template": "error",
71
75
  "no-var": "error",
76
+ // Blank-line discipline — the model rarely gets spacing right, so
77
+ // eslint --fix + prettier make it free. Uses @stylistic (the rule's
78
+ // maintained home; the core rule is deprecated and spams usedDeprecatedRules
79
+ // into eslint's --format json gate output).
80
+ "@stylistic/padding-line-between-statements": [
81
+ "error",
82
+ { blankLine: "always", prev: "import", next: "*" },
83
+ { blankLine: "any", prev: "import", next: "import" },
84
+ { blankLine: "always", prev: "*", next: "return" },
85
+ { blankLine: "always", prev: "*", next: "throw" },
86
+ { blankLine: "always", prev: ["const", "let", "var"], next: "*" },
87
+ {
88
+ blankLine: "any",
89
+ prev: ["const", "let", "var"],
90
+ next: ["const", "let", "var"],
91
+ },
92
+ { blankLine: "always", prev: "block-like", next: "*" },
93
+ { blankLine: "always", prev: "*", next: "block-like" },
94
+ ],
72
95
  eqeqeq: ["error", "always"],
73
96
  curly: ["error", "all"],
74
97
  "no-restricted-syntax": [
@@ -0,0 +1,33 @@
1
+ // Optional type-aware ESLint overlay — enabled only when the target has a
2
+ // compiling tsconfig (see detect-gate.ts). Adds async correctness rules that
3
+ // require parserOptions.project; kept separate from strict.eslint.config.mjs
4
+ // so the syntactic gate still runs on any .ts file without type info.
5
+ import tseslint from "typescript-eslint";
6
+
7
+ export default tseslint.config(
8
+ { ignores: ["**/node_modules/**", "**/dist/**", "**/build/**"] },
9
+ {
10
+ files: ["**/*.ts", "**/*.tsx"],
11
+ languageOptions: {
12
+ parser: tseslint.parser,
13
+ parserOptions: {
14
+ projectService: true,
15
+ tsconfigRootDir: process.cwd(),
16
+ },
17
+ },
18
+ plugins: {
19
+ "@typescript-eslint": tseslint.plugin,
20
+ },
21
+ rules: {
22
+ "@typescript-eslint/no-floating-promises": "error",
23
+ "@typescript-eslint/no-misused-promises": [
24
+ "error",
25
+ {
26
+ checksVoidReturn: {
27
+ attributes: false,
28
+ },
29
+ },
30
+ ],
31
+ },
32
+ }
33
+ );