@vyuhlabs/dxkit 2.21.2 → 2.23.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.
Files changed (114) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/dist/analyzers/correctness/run.d.ts +79 -0
  3. package/dist/analyzers/correctness/run.d.ts.map +1 -0
  4. package/dist/analyzers/correctness/run.js +173 -0
  5. package/dist/analyzers/correctness/run.js.map +1 -0
  6. package/dist/analyzers/correctness/surface-run.d.ts +73 -0
  7. package/dist/analyzers/correctness/surface-run.d.ts.map +1 -0
  8. package/dist/analyzers/correctness/surface-run.js +142 -0
  9. package/dist/analyzers/correctness/surface-run.js.map +1 -0
  10. package/dist/analyzers/correctness/surface.d.ts +69 -0
  11. package/dist/analyzers/correctness/surface.d.ts.map +1 -0
  12. package/dist/analyzers/correctness/surface.js +281 -0
  13. package/dist/analyzers/correctness/surface.js.map +1 -0
  14. package/dist/analyzers/flow/config.d.ts +10 -0
  15. package/dist/analyzers/flow/config.d.ts.map +1 -1
  16. package/dist/analyzers/flow/config.js +29 -0
  17. package/dist/analyzers/flow/config.js.map +1 -1
  18. package/dist/analyzers/flow/contract.d.ts +12 -0
  19. package/dist/analyzers/flow/contract.d.ts.map +1 -1
  20. package/dist/analyzers/flow/contract.js +20 -0
  21. package/dist/analyzers/flow/contract.js.map +1 -1
  22. package/dist/analyzers/flow/diagnose.d.ts +62 -0
  23. package/dist/analyzers/flow/diagnose.d.ts.map +1 -0
  24. package/dist/analyzers/flow/diagnose.js +120 -0
  25. package/dist/analyzers/flow/diagnose.js.map +1 -0
  26. package/dist/analyzers/flow/publish.d.ts +47 -0
  27. package/dist/analyzers/flow/publish.d.ts.map +1 -0
  28. package/dist/analyzers/flow/publish.js +146 -0
  29. package/dist/analyzers/flow/publish.js.map +1 -0
  30. package/dist/analyzers/flow/setup.d.ts +71 -0
  31. package/dist/analyzers/flow/setup.d.ts.map +1 -0
  32. package/dist/analyzers/flow/setup.js +136 -0
  33. package/dist/analyzers/flow/setup.js.map +1 -0
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +129 -6
  36. package/dist/cli.js.map +1 -1
  37. package/dist/doctor.d.ts +7 -0
  38. package/dist/doctor.d.ts.map +1 -1
  39. package/dist/doctor.js +38 -1
  40. package/dist/doctor.js.map +1 -1
  41. package/dist/flow-cli.d.ts +10 -0
  42. package/dist/flow-cli.d.ts.map +1 -1
  43. package/dist/flow-cli.js +46 -0
  44. package/dist/flow-cli.js.map +1 -1
  45. package/dist/generator.d.ts.map +1 -1
  46. package/dist/generator.js +6 -0
  47. package/dist/generator.js.map +1 -1
  48. package/dist/languages/capabilities/correctness.d.ts +54 -0
  49. package/dist/languages/capabilities/correctness.d.ts.map +1 -0
  50. package/dist/languages/capabilities/correctness.js +20 -0
  51. package/dist/languages/capabilities/correctness.js.map +1 -0
  52. package/dist/languages/csharp.d.ts.map +1 -1
  53. package/dist/languages/csharp.js +84 -0
  54. package/dist/languages/csharp.js.map +1 -1
  55. package/dist/languages/go.d.ts.map +1 -1
  56. package/dist/languages/go.js +51 -0
  57. package/dist/languages/go.js.map +1 -1
  58. package/dist/languages/index.d.ts +11 -0
  59. package/dist/languages/index.d.ts.map +1 -1
  60. package/dist/languages/index.js +12 -0
  61. package/dist/languages/index.js.map +1 -1
  62. package/dist/languages/java.d.ts.map +1 -1
  63. package/dist/languages/java.js +12 -0
  64. package/dist/languages/java.js.map +1 -1
  65. package/dist/languages/jvm-build.d.ts +54 -0
  66. package/dist/languages/jvm-build.d.ts.map +1 -0
  67. package/dist/languages/jvm-build.js +245 -0
  68. package/dist/languages/jvm-build.js.map +1 -0
  69. package/dist/languages/kotlin.d.ts.map +1 -1
  70. package/dist/languages/kotlin.js +13 -0
  71. package/dist/languages/kotlin.js.map +1 -1
  72. package/dist/languages/python.d.ts.map +1 -1
  73. package/dist/languages/python.js +78 -0
  74. package/dist/languages/python.js.map +1 -1
  75. package/dist/languages/ruby.d.ts.map +1 -1
  76. package/dist/languages/ruby.js +64 -0
  77. package/dist/languages/ruby.js.map +1 -1
  78. package/dist/languages/rust.d.ts.map +1 -1
  79. package/dist/languages/rust.js +110 -0
  80. package/dist/languages/rust.js.map +1 -1
  81. package/dist/languages/types.d.ts +20 -0
  82. package/dist/languages/types.d.ts.map +1 -1
  83. package/dist/languages/typescript.d.ts.map +1 -1
  84. package/dist/languages/typescript.js +109 -0
  85. package/dist/languages/typescript.js.map +1 -1
  86. package/dist/loop/floor-gate.d.ts +54 -0
  87. package/dist/loop/floor-gate.d.ts.map +1 -0
  88. package/dist/loop/floor-gate.js +157 -0
  89. package/dist/loop/floor-gate.js.map +1 -0
  90. package/dist/loop/floor-state.d.ts +66 -0
  91. package/dist/loop/floor-state.d.ts.map +1 -0
  92. package/dist/loop/floor-state.js +138 -0
  93. package/dist/loop/floor-state.js.map +1 -0
  94. package/dist/loop/stop-gate.d.ts +2 -1
  95. package/dist/loop/stop-gate.d.ts.map +1 -1
  96. package/dist/loop/stop-gate.js +44 -6
  97. package/dist/loop/stop-gate.js.map +1 -1
  98. package/dist/prompts.d.ts +15 -0
  99. package/dist/prompts.d.ts.map +1 -1
  100. package/dist/prompts.js +66 -0
  101. package/dist/prompts.js.map +1 -1
  102. package/dist/workspace.d.ts +52 -0
  103. package/dist/workspace.d.ts.map +1 -0
  104. package/dist/workspace.js +130 -0
  105. package/dist/workspace.js.map +1 -0
  106. package/package.json +1 -1
  107. package/templates/.claude/skills/dxkit-config/SKILL.md +14 -0
  108. package/templates/.claude/skills/dxkit-fix/SKILL.md +2 -0
  109. package/templates/.claude/skills/dxkit-flow/SKILL.md +83 -0
  110. package/templates/.claude/skills/dxkit-hooks/SKILL.md +1 -1
  111. package/templates/.claude/skills/dxkit-init/SKILL.md +5 -0
  112. package/templates/.claude/skills/dxkit-onboard/SKILL.md +2 -0
  113. package/templates/.githooks/pre-push +10 -0
  114. package/templates/.github/workflows/dxkit-guardrails.yml +17 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,100 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.23.0] - 2026-07-04
11
+
12
+ ### Added — the correctness floor (a loop-safety liveness gate)
13
+
14
+ The guardrail proves "no net-new findings" (secrets, CVEs, SAST, coverage). It
15
+ does not prove the code still **compiles and its affected tests still pass** — so
16
+ an autonomous agent loop can satisfy the finding gate while shipping code that
17
+ does not build, and even a broken test that lifts coverage gets rewarded. The
18
+ correctness floor closes that gap: a liveness check that asks "does this still
19
+ build, and do the tests it affects still pass?" before an agent may declare
20
+ "done". A failing floor is a pass/fail signal, not a fingerprinted, grandfathered
21
+ finding (there is no "grandfather a syntax error"), so it sits outside the
22
+ baseline and allowlist.
23
+
24
+ - **Pack-declared, runner-executed** (CLAUDE.md Rule 15). Each language pack
25
+ declares two pure command builders — `syntaxCheck` (the cheap "does it
26
+ compile/parse" check) and `affectedTests` (run the tests the change reaches).
27
+ One runner owns the load-bearing policy in a single place: fail-CLOSED on a
28
+ real failure (a non-zero exit blocks), fail-OPEN on infrastructure (a missing
29
+ toolchain or a timeout is a skip, never a block — a slow or un-installed
30
+ toolchain is not broken code; CI is the backstop). A pack never shells out
31
+ itself.
32
+ - **All 8 packs, verified against real toolchains**, at the affected granularity
33
+ each ecosystem natively supports:
34
+
35
+ | Pack | Compile | Affected-test granularity |
36
+ | --- | --- | --- |
37
+ | TypeScript / JavaScript | `tsc --noEmit` (or the project's typecheck script) | per-file (`vitest related` / `jest --findRelatedTests`) |
38
+ | Python | `py_compile` | per changed test file (pytest) |
39
+ | Go | `go build ./...` | changed package(s) |
40
+ | Rust | `cargo check` | changed crate(s) (`-p`) |
41
+ | C# / .NET | `dotnet build` | changed test project (`dotnet test <proj>`) |
42
+ | Java | Maven `test-compile` / Gradle `testClasses` | changed build module (Maven `-pl -am`, Gradle `:mod:test`) |
43
+ | Kotlin | Maven `test-compile` / Gradle `testClasses` | changed build module |
44
+ | Ruby | `ruby -c` per changed file | changed spec/test file (RSpec / minitest) |
45
+
46
+ A change whose dependents live in another package/module/crate is caught at
47
+ full/CI scope, not the fast affected surface. The two JVM packs share one
48
+ `jvm-build.ts` provider (Rule 2).
49
+ - **Three surfaces, one adaptive resolver.** The loop Stop-gate runs the floor
50
+ by default (an agent must not stop on broken code), scoped to what the loop
51
+ introduced via a testmon-style entry snapshot, so a pre-existing failure never
52
+ blocks. The pre-push and CI surfaces are adaptive: when the repo already runs
53
+ its tests in its own CI, the floor defaults to opt-in there; when no test-CI is
54
+ detected it runs by default; when a CI exists but its test step is opaque it
55
+ fails toward on. Precedence: an explicit flag, then a `DXKIT_FLOOR_<SURFACE>`
56
+ env, then `.dxkit/policy.json` `correctness.surfaces.<surface>`, then the
57
+ adaptive default.
58
+ - **`vyuh-dxkit floor check [--surface pre-push|ci] [--base <ref>]
59
+ [--correctness | --no-correctness]`** — the entry point the pre-push hook and
60
+ CI workflow call. It is baseline-independent, so a brand-new repo with no
61
+ baseline still gets push-time liveness. The installed pre-push hook runs it
62
+ before the baseline check; the CI guardrail workflow runs it (full scope) after
63
+ the finding gate.
64
+
65
+ ### Changed
66
+
67
+ - `LanguageSupport.correctness` is now a required field: the capability shipped
68
+ optional and tightened once all eight packs declared it, so a new pack that
69
+ omits it fails to compile (not just at test time). The `new-lang` scaffold
70
+ wires a dormant provider so a fresh pack still compiles, with TODOs for the
71
+ real commands.
72
+
73
+ ## [2.22.0] - 2026-07-02
74
+
75
+ ### Added — the flow feature becomes agent-operable (setup, diagnose, publish, repair)
76
+
77
+ The UI→API integration gate now has the surfaces an agent (or a person) needs to
78
+ configure, diagnose, and repair it — folded into the commands you already run so
79
+ the CLI stays small.
80
+
81
+ - **Setup folds into `init`.** There is no standalone `flow init`. When `init`
82
+ detects a UI→API surface (client calls and/or server routes) it offers the
83
+ integration gate and asks for the posture — `warn` (default), `block`, or
84
+ `off` — with a one-line description of each; a repo with no such surface stays
85
+ silent. `--flow` forces it on with `warn`; `--no-flow` skips it. The dominant
86
+ base-URL helper to strip and any multiple backend services are surfaced as
87
+ confirm prompts.
88
+ - **`.dxkit/workspace.json`** — a new top-level participants primitive naming the
89
+ repos/services of a multi-repo system (path, optional git ref, base URLs).
90
+ - **Diagnose folds into `doctor`.** There is no standalone `flow doctor`. When the
91
+ repo has a UI→API surface, `doctor` reports a flow-contract diagnosis — the
92
+ unresolved client calls (each with a reason and a suggested next step), the
93
+ served routes nobody consumes, and how the served side is resolved — and
94
+ `doctor --json` carries the whole `flow` object for an agent to read.
95
+ - **`flow publish`** — the multi-repo handshake. Reads `workspace.json` and unions
96
+ every participant's served routes into this repo's `served.json`, so a consumer
97
+ repo gates its calls against a provider it does not co-locate. Participants are
98
+ gathered from a local path, optionally pinned at a git ref; fail-open per
99
+ participant. A content-hash on the snapshot lets a consumer detect drift.
100
+ - **`dxkit-flow` skill** — the operator surface: setup, diagnose, fix (repair a
101
+ net-new broken integration a guardrail flagged — never suppress it), and the
102
+ cross-repo handshake. Thin orchestration over the CLI; `--flow` installs it.
103
+
10
104
  ## [2.21.2] - 2026-07-02
11
105
 
12
106
  ### Fixed — the flow gate now runs in committed-baseline modes too
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The correctness-floor runner — executes each active pack's syntax + affected-
3
+ * test commands and folds them into one pass/fail signal.
4
+ *
5
+ * Policy, in one place so every surface behaves the same:
6
+ * - fail-CLOSED on a real failure — a non-zero exit from a check that ran is a
7
+ * genuine syntax error / failing test, and it BLOCKS.
8
+ * - fail-OPEN on infrastructure — a missing binary (the toolchain isn't
9
+ * installed here) skips the check rather than failing it. A hook must not
10
+ * block a developer who simply hasn't installed a linter locally; CI, where
11
+ * the toolchain is present, is the backstop.
12
+ *
13
+ * Commands come from `LanguageSupport.correctness` via the registry helper
14
+ * (Rule 6); this module never hardcodes a per-language command. Command
15
+ * execution is injected so tests exercise the policy without a real toolchain.
16
+ */
17
+ import type { LanguageId, LanguageSupport } from '../../languages/types';
18
+ import type { CorrectnessCommand, CorrectnessScope } from '../../languages/capabilities/correctness';
19
+ export type CorrectnessStatus = 'pass' | 'fail' | 'skipped-unavailable' | 'skipped-timeout' | 'skipped-none';
20
+ export interface CorrectnessCheckResult {
21
+ readonly pack: LanguageId;
22
+ readonly label: string;
23
+ readonly bin: string;
24
+ readonly status: CorrectnessStatus;
25
+ /** Captured output tail — present only on `fail`, for the block message. */
26
+ readonly output?: string;
27
+ }
28
+ export interface CorrectnessFloorResult {
29
+ /** True when at least one check actually executed (not all skipped). */
30
+ readonly ran: boolean;
31
+ readonly checks: readonly CorrectnessCheckResult[];
32
+ /** True when any check that ran failed — the floor blocks. */
33
+ readonly blocks: boolean;
34
+ }
35
+ /** Outcome of running one command:
36
+ * - `available:false` → the binary isn't on PATH (fail-open skip);
37
+ * - `timedOut:true` → the command exceeded its wall-clock budget. A SLOW
38
+ * suite is not a BROKEN suite, so this is fail-OPEN (skipped), never a block
39
+ * — the fast surface stays fast and CI (unbounded) is the backstop;
40
+ * - otherwise `code` is the exit status and `output` its tail. */
41
+ export interface CommandOutcome {
42
+ readonly available: boolean;
43
+ readonly timedOut?: boolean;
44
+ readonly code: number;
45
+ readonly output: string;
46
+ }
47
+ export type CommandExec = (cmd: CorrectnessCommand, cwd: string) => CommandOutcome;
48
+ /**
49
+ * Build a command exec bounded by an optional per-command wall-clock timeout.
50
+ * On timeout the child is killed and the outcome is `timedOut` (fail-open),
51
+ * distinct from a non-zero exit (a real failure, fail-closed). `timeoutMs`
52
+ * undefined/0 → no timeout (CI, where the full suite is expected to run).
53
+ */
54
+ export declare function makeCommandExec(timeoutMs?: number): CommandExec;
55
+ /** Default exec: resolve on PATH, run unbounded, capture combined output tail. */
56
+ export declare const defaultCommandExec: CommandExec;
57
+ export interface CorrectnessFloorOptions {
58
+ readonly cwd: string;
59
+ readonly changedFiles: readonly string[];
60
+ readonly scope: CorrectnessScope;
61
+ /** Active language packs (from `activeLanguagesFromStack` / `-Flags`). */
62
+ readonly packs: readonly LanguageSupport[];
63
+ /** Per-command wall-clock budget (ms). A command that exceeds it is a
64
+ * fail-OPEN skip, never a block — the fast surface stays fast, CI is the
65
+ * backstop. Undefined → no timeout. Ignored when `exec` is injected. */
66
+ readonly timeoutMs?: number;
67
+ /** Injected for tests; defaults to real PATH resolution + execFileSync. */
68
+ readonly exec?: CommandExec;
69
+ }
70
+ /**
71
+ * Run the correctness floor across the active packs. Never throws — an exec
72
+ * error surfaces as a `fail` check (fail-closed), a missing binary as
73
+ * `skipped-unavailable` (fail-open). `blocks` is true iff a check that ran
74
+ * failed.
75
+ */
76
+ export declare function runCorrectnessFloor(opts: CorrectnessFloorOptions): CorrectnessFloorResult;
77
+ /** One-line human summary of a floor result (for the Stop-gate / hook block). */
78
+ export declare function describeCorrectnessFloor(result: CorrectnessFloorResult): string;
79
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/analyzers/correctness/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,0CAA0C,CAAC;AAqBlD,MAAM,MAAM,iBAAiB,GACzB,MAAM,GACN,MAAM,GACN,qBAAqB,GACrB,iBAAiB,GACjB,cAAc,CAAC;AAEnB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACnD,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;mEAKmE;AACnE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC;AAInF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,CAoC/D;AAED,kFAAkF;AAClF,eAAO,MAAM,kBAAkB,EAAE,WAA+B,CAAC;AAOjE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;IAC3C;;6EAEyE;IACzE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;CAC7B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,uBAAuB,GAAG,sBAAsB,CAiCzF;AAED,iFAAiF;AACjF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,sBAAsB,GAAG,MAAM,CAK/E"}
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ /**
3
+ * The correctness-floor runner — executes each active pack's syntax + affected-
4
+ * test commands and folds them into one pass/fail signal.
5
+ *
6
+ * Policy, in one place so every surface behaves the same:
7
+ * - fail-CLOSED on a real failure — a non-zero exit from a check that ran is a
8
+ * genuine syntax error / failing test, and it BLOCKS.
9
+ * - fail-OPEN on infrastructure — a missing binary (the toolchain isn't
10
+ * installed here) skips the check rather than failing it. A hook must not
11
+ * block a developer who simply hasn't installed a linter locally; CI, where
12
+ * the toolchain is present, is the backstop.
13
+ *
14
+ * Commands come from `LanguageSupport.correctness` via the registry helper
15
+ * (Rule 6); this module never hardcodes a per-language command. Command
16
+ * execution is injected so tests exercise the policy without a real toolchain.
17
+ */
18
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ var desc = Object.getOwnPropertyDescriptor(m, k);
21
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
22
+ desc = { enumerable: true, get: function() { return m[k]; } };
23
+ }
24
+ Object.defineProperty(o, k2, desc);
25
+ }) : (function(o, m, k, k2) {
26
+ if (k2 === undefined) k2 = k;
27
+ o[k2] = m[k];
28
+ }));
29
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
30
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31
+ }) : function(o, v) {
32
+ o["default"] = v;
33
+ });
34
+ var __importStar = (this && this.__importStar) || (function () {
35
+ var ownKeys = function(o) {
36
+ ownKeys = Object.getOwnPropertyNames || function (o) {
37
+ var ar = [];
38
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
39
+ return ar;
40
+ };
41
+ return ownKeys(o);
42
+ };
43
+ return function (mod) {
44
+ if (mod && mod.__esModule) return mod;
45
+ var result = {};
46
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
47
+ __setModuleDefault(result, mod);
48
+ return result;
49
+ };
50
+ })();
51
+ Object.defineProperty(exports, "__esModule", { value: true });
52
+ exports.defaultCommandExec = void 0;
53
+ exports.makeCommandExec = makeCommandExec;
54
+ exports.runCorrectnessFloor = runCorrectnessFloor;
55
+ exports.describeCorrectnessFloor = describeCorrectnessFloor;
56
+ const child_process_1 = require("child_process");
57
+ const fs = __importStar(require("fs"));
58
+ const path = __importStar(require("path"));
59
+ const runner_1 = require("../tools/runner");
60
+ const languages_1 = require("../../languages");
61
+ /**
62
+ * Is a command's `bin` runnable? A bare name is resolved on PATH (`tsc`,
63
+ * `cargo`, `npx`); a path-like `bin` (a pack that resolved an absolute
64
+ * interpreter — a project venv's `python`, a `findTool` path) is accepted when
65
+ * the file exists. Without the latter, a resolved-path bin would be wrongly
66
+ * treated as missing and the check skipped (fail-open on a tool that IS
67
+ * present) — so this keeps the fail-open gate honest for every pack.
68
+ */
69
+ function binaryAvailable(bin) {
70
+ if (bin.includes('/') || bin.includes(path.sep)) {
71
+ try {
72
+ return fs.statSync(bin).isFile();
73
+ }
74
+ catch {
75
+ return false;
76
+ }
77
+ }
78
+ return (0, runner_1.commandExists)(bin);
79
+ }
80
+ const OUTPUT_TAIL = 4000; // cap captured output so a block message stays readable
81
+ /**
82
+ * Build a command exec bounded by an optional per-command wall-clock timeout.
83
+ * On timeout the child is killed and the outcome is `timedOut` (fail-open),
84
+ * distinct from a non-zero exit (a real failure, fail-closed). `timeoutMs`
85
+ * undefined/0 → no timeout (CI, where the full suite is expected to run).
86
+ */
87
+ function makeCommandExec(timeoutMs) {
88
+ return (cmd, cwd) => {
89
+ if (!binaryAvailable(cmd.bin))
90
+ return { available: false, code: -1, output: '' };
91
+ try {
92
+ const out = (0, child_process_1.execFileSync)(cmd.bin, [...cmd.args], {
93
+ cwd,
94
+ encoding: 'utf-8',
95
+ stdio: ['ignore', 'pipe', 'pipe'],
96
+ ...(timeoutMs && timeoutMs > 0 ? { timeout: timeoutMs, killSignal: 'SIGTERM' } : {}),
97
+ });
98
+ return { available: true, code: 0, output: tail(out) };
99
+ }
100
+ catch (e) {
101
+ const err = e;
102
+ const combined = `${err.stdout ?? ''}${err.stderr ?? ''}`;
103
+ // execFileSync sets `code: 'ETIMEDOUT'` (and signal = killSignal) when it
104
+ // fired the timeout kill. Treat that as a fail-OPEN skip, not a failure —
105
+ // the run didn't finish, so it says nothing about correctness.
106
+ if (err.code === 'ETIMEDOUT') {
107
+ return { available: true, timedOut: true, code: -1, output: tail(combined) };
108
+ }
109
+ // A non-numeric status (spawn error, non-timeout signal) is treated as a
110
+ // failure with code 1 — the binary existed (commandExists passed) but the
111
+ // run broke.
112
+ return {
113
+ available: true,
114
+ code: typeof err.status === 'number' ? err.status : 1,
115
+ output: tail(combined),
116
+ };
117
+ }
118
+ };
119
+ }
120
+ /** Default exec: resolve on PATH, run unbounded, capture combined output tail. */
121
+ exports.defaultCommandExec = makeCommandExec();
122
+ function tail(s) {
123
+ const t = s.trim();
124
+ return t.length > OUTPUT_TAIL ? `…${t.slice(-OUTPUT_TAIL)}` : t;
125
+ }
126
+ /**
127
+ * Run the correctness floor across the active packs. Never throws — an exec
128
+ * error surfaces as a `fail` check (fail-closed), a missing binary as
129
+ * `skipped-unavailable` (fail-open). `blocks` is true iff a check that ran
130
+ * failed.
131
+ */
132
+ function runCorrectnessFloor(opts) {
133
+ const exec = opts.exec ?? makeCommandExec(opts.timeoutMs);
134
+ const ctx = { cwd: opts.cwd, changedFiles: opts.changedFiles, scope: opts.scope };
135
+ const checks = [];
136
+ for (const { id, provider } of (0, languages_1.activeCorrectnessProviders)(opts.packs)) {
137
+ const commands = [provider.syntaxCheck(ctx), provider.affectedTests(ctx)];
138
+ for (const cmd of commands) {
139
+ if (cmd === null)
140
+ continue; // pack declined this check for this change
141
+ const outcome = exec(cmd, opts.cwd);
142
+ if (!outcome.available) {
143
+ checks.push({ pack: id, label: cmd.label, bin: cmd.bin, status: 'skipped-unavailable' });
144
+ continue;
145
+ }
146
+ if (outcome.timedOut) {
147
+ // Exceeded the budget — fail-OPEN. The run didn't finish, so it says
148
+ // nothing about correctness; CI (unbounded) is the backstop.
149
+ checks.push({ pack: id, label: cmd.label, bin: cmd.bin, status: 'skipped-timeout' });
150
+ continue;
151
+ }
152
+ checks.push({
153
+ pack: id,
154
+ label: cmd.label,
155
+ bin: cmd.bin,
156
+ status: outcome.code === 0 ? 'pass' : 'fail',
157
+ ...(outcome.code === 0 ? {} : { output: outcome.output }),
158
+ });
159
+ }
160
+ }
161
+ const ran = checks.some((c) => c.status === 'pass' || c.status === 'fail');
162
+ const blocks = checks.some((c) => c.status === 'fail');
163
+ return { ran, checks, blocks };
164
+ }
165
+ /** One-line human summary of a floor result (for the Stop-gate / hook block). */
166
+ function describeCorrectnessFloor(result) {
167
+ const failed = result.checks.filter((c) => c.status === 'fail');
168
+ if (failed.length === 0)
169
+ return 'correctness floor: all checks passed';
170
+ const which = failed.map((c) => `${c.pack} ${c.label}`).join(', ');
171
+ return `correctness floor: ${failed.length} check(s) failed — ${which}`;
172
+ }
173
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/analyzers/correctness/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Run the correctness floor for a NON-loop surface (`pre-push` / `ci`).
3
+ *
4
+ * The loop Stop-gate has its own runner (`src/loop/stop-gate.ts`) because it
5
+ * diffs against a cheap entry snapshot to block only on NET-NEW failures. The
6
+ * pre-push and CI surfaces are point-in-time LIVENESS gates instead: they run
7
+ * the floor at the current tree and are fail-CLOSED on the surface's scope.
8
+ * There is no net-new diffing here (that would cost a base-ref worktree run on
9
+ * every push / PR); the entry-snapshot trick is the loop's alone.
10
+ *
11
+ * - `pre-push` — AFFECTED scope, changed files computed vs the merge-base with
12
+ * the integration branch. Runs on the developer's machine where the
13
+ * toolchain is present, so the floor is meaningful; a per-command timeout
14
+ * keeps `git push` fast. Blocks the push when the affected tests don't pass.
15
+ * (It does not distinguish a pre-existing red test in a touched module from
16
+ * a newly-broken one — that distinction is the loop Stop-gate's job. Bypass
17
+ * with `--no-verify`.)
18
+ * - `ci` — FULL scope, no timeout (the full suite is expected to run). The
19
+ * backstop.
20
+ *
21
+ * Both surfaces are ADAPTIVE (`resolveCorrectnessSurface`): when the repo
22
+ * already runs its tests in its own CI, the floor defaults to opt-in here, so
23
+ * this runner returns a disabled no-op unless explicitly enabled.
24
+ */
25
+ import type { LanguageSupport } from '../../languages/types';
26
+ import { type CommandExec, type CorrectnessFloorResult } from './run';
27
+ /** The surfaces this runner serves (the loop-stop surface has its own runner). */
28
+ export type RunnableSurface = 'pre-push' | 'ci';
29
+ export interface SurfaceFloorOutcome {
30
+ readonly surface: RunnableSurface;
31
+ /** Was the floor enabled on this surface (via the resolver)? */
32
+ readonly enabled: boolean;
33
+ /** Why it resolved the way it did (or why it was skipped). */
34
+ readonly reason: string;
35
+ /** Did any check actually execute (false when disabled / no pack / all skipped)? */
36
+ readonly ran: boolean;
37
+ /** Does the floor block this surface (a real failure)? Always false when not `ran`. */
38
+ readonly blocks: boolean;
39
+ /** One-line human summary for CLI / hook output. */
40
+ readonly summary: string;
41
+ readonly result?: CorrectnessFloorResult;
42
+ }
43
+ /**
44
+ * The merge-base of HEAD against the most likely integration branch, so the
45
+ * pre-push floor scopes to what this branch actually introduces. Tries, in
46
+ * order: an explicit ref, the tracking upstream, then the common remote/local
47
+ * default-branch names. Returns '' when none resolve (caller then runs full).
48
+ */
49
+ export declare function resolvePrePushBase(cwd: string, explicit?: string): string;
50
+ export interface RunFloorForSurfaceOptions {
51
+ readonly surface: RunnableSurface;
52
+ readonly cwd: string;
53
+ /** Explicit base ref for pre-push affected scoping (else auto-resolved). */
54
+ readonly base?: string;
55
+ /** Explicit `--correctness` / `--no-correctness` override (highest precedence). */
56
+ readonly flag?: boolean;
57
+ /** Injected for tests; defaults to the real PATH-resolving exec. */
58
+ readonly exec?: CommandExec;
59
+ /** Injected for tests; defaults to the active packs detected at `cwd`. */
60
+ readonly packs?: readonly LanguageSupport[];
61
+ /** Injected for tests; defaults to the real adaptive resolver. */
62
+ readonly resolveEnabled?: (surface: RunnableSurface, cwd: string) => {
63
+ enabled: boolean;
64
+ reason: string;
65
+ };
66
+ }
67
+ /**
68
+ * Resolve enablement + scope for a surface and run the floor. Never throws — a
69
+ * disabled surface, an absent pack, or an all-skipped run all return
70
+ * `blocks: false` (the caller exits 0); only a real check failure blocks.
71
+ */
72
+ export declare function runFloorForSurface(opts: RunFloorForSurfaceOptions): SurfaceFloorOutcome;
73
+ //# sourceMappingURL=surface-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-run.d.ts","sourceRoot":"","sources":["../../../src/analyzers/correctness/surface-run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC5B,MAAM,OAAO,CAAC;AAGf,kFAAkF;AAClF,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,IAAI,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,gEAAgE;IAChE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,sBAAsB,CAAC;CAC1C;AAeD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CASzE;AAUD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mFAAmF;IACnF,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,eAAe,EAAE,CAAC;IAC5C,kEAAkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,CACxB,OAAO,EAAE,eAAe,EACxB,GAAG,EAAE,MAAM,KACR;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,yBAAyB,GAAG,mBAAmB,CAoEvF"}
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Run the correctness floor for a NON-loop surface (`pre-push` / `ci`).
4
+ *
5
+ * The loop Stop-gate has its own runner (`src/loop/stop-gate.ts`) because it
6
+ * diffs against a cheap entry snapshot to block only on NET-NEW failures. The
7
+ * pre-push and CI surfaces are point-in-time LIVENESS gates instead: they run
8
+ * the floor at the current tree and are fail-CLOSED on the surface's scope.
9
+ * There is no net-new diffing here (that would cost a base-ref worktree run on
10
+ * every push / PR); the entry-snapshot trick is the loop's alone.
11
+ *
12
+ * - `pre-push` — AFFECTED scope, changed files computed vs the merge-base with
13
+ * the integration branch. Runs on the developer's machine where the
14
+ * toolchain is present, so the floor is meaningful; a per-command timeout
15
+ * keeps `git push` fast. Blocks the push when the affected tests don't pass.
16
+ * (It does not distinguish a pre-existing red test in a touched module from
17
+ * a newly-broken one — that distinction is the loop Stop-gate's job. Bypass
18
+ * with `--no-verify`.)
19
+ * - `ci` — FULL scope, no timeout (the full suite is expected to run). The
20
+ * backstop.
21
+ *
22
+ * Both surfaces are ADAPTIVE (`resolveCorrectnessSurface`): when the repo
23
+ * already runs its tests in its own CI, the floor defaults to opt-in here, so
24
+ * this runner returns a disabled no-op unless explicitly enabled.
25
+ */
26
+ Object.defineProperty(exports, "__esModule", { value: true });
27
+ exports.resolvePrePushBase = resolvePrePushBase;
28
+ exports.runFloorForSurface = runFloorForSurface;
29
+ const child_process_1 = require("child_process");
30
+ const languages_1 = require("../../languages");
31
+ const changed_files_1 = require("../../baseline/changed-files");
32
+ const run_1 = require("./run");
33
+ const surface_1 = require("./surface");
34
+ /** Best-effort git stdout for a fixed arg vector; '' on any failure. */
35
+ function gitOut(cwd, args) {
36
+ try {
37
+ return (0, child_process_1.execFileSync)('git', [...args], {
38
+ cwd,
39
+ encoding: 'utf8',
40
+ stdio: ['ignore', 'pipe', 'ignore'],
41
+ }).trim();
42
+ }
43
+ catch {
44
+ return '';
45
+ }
46
+ }
47
+ /**
48
+ * The merge-base of HEAD against the most likely integration branch, so the
49
+ * pre-push floor scopes to what this branch actually introduces. Tries, in
50
+ * order: an explicit ref, the tracking upstream, then the common remote/local
51
+ * default-branch names. Returns '' when none resolve (caller then runs full).
52
+ */
53
+ function resolvePrePushBase(cwd, explicit) {
54
+ const candidates = explicit
55
+ ? [explicit]
56
+ : ['@{upstream}', 'origin/HEAD', 'origin/main', 'origin/master', 'main', 'master'];
57
+ for (const ref of candidates) {
58
+ const mb = gitOut(cwd, ['merge-base', 'HEAD', ref]);
59
+ if (mb)
60
+ return mb;
61
+ }
62
+ return '';
63
+ }
64
+ /** Per-command wall-clock budget for the fast (pre-push) surface. Env-tunable;
65
+ * CI runs unbounded (the full suite is expected to run to completion). */
66
+ function prePushTimeoutMs() {
67
+ const raw = process.env.DXKIT_FLOOR_TIMEOUT_MS;
68
+ const n = raw ? Number(raw) : NaN;
69
+ return Number.isFinite(n) && n > 0 ? n : 120_000;
70
+ }
71
+ /**
72
+ * Resolve enablement + scope for a surface and run the floor. Never throws — a
73
+ * disabled surface, an absent pack, or an all-skipped run all return
74
+ * `blocks: false` (the caller exits 0); only a real check failure blocks.
75
+ */
76
+ function runFloorForSurface(opts) {
77
+ const { surface, cwd } = opts;
78
+ const res = opts.resolveEnabled
79
+ ? opts.resolveEnabled(surface, cwd)
80
+ : (0, surface_1.resolveCorrectnessSurface)({ surface, cwd, flag: opts.flag });
81
+ if (!res.enabled) {
82
+ return {
83
+ surface,
84
+ enabled: false,
85
+ reason: res.reason,
86
+ ran: false,
87
+ blocks: false,
88
+ summary: `correctness floor (${surface}): disabled — ${res.reason}`,
89
+ };
90
+ }
91
+ const packs = (opts.packs ?? (0, languages_1.detectActiveLanguages)(cwd)).filter((p) => p.correctness);
92
+ if (packs.length === 0) {
93
+ return {
94
+ surface,
95
+ enabled: true,
96
+ reason: res.reason,
97
+ ran: false,
98
+ blocks: false,
99
+ summary: `correctness floor (${surface}): no active language pack provides a floor`,
100
+ };
101
+ }
102
+ let scope = 'full';
103
+ let changedFiles = [];
104
+ let timeoutMs;
105
+ if (surface === 'pre-push') {
106
+ scope = 'affected';
107
+ const base = resolvePrePushBase(cwd, opts.base);
108
+ // Empty changedFiles (base unresolved / diff undeterminable) → the packs
109
+ // treat the scope as full, per the CorrectnessContext contract.
110
+ changedFiles = base ? ((0, changed_files_1.computeChangedFiles)(cwd, base) ?? []) : [];
111
+ timeoutMs = prePushTimeoutMs();
112
+ }
113
+ // ci: full scope, no timeout — the full suite runs to completion.
114
+ const result = (0, run_1.runCorrectnessFloor)({
115
+ cwd,
116
+ changedFiles,
117
+ scope,
118
+ packs,
119
+ timeoutMs,
120
+ exec: opts.exec,
121
+ });
122
+ if (!result.ran) {
123
+ return {
124
+ surface,
125
+ enabled: true,
126
+ reason: res.reason,
127
+ ran: false,
128
+ blocks: false,
129
+ summary: `correctness floor (${surface}): all checks skipped (toolchain not present) — CI is the backstop`,
130
+ };
131
+ }
132
+ return {
133
+ surface,
134
+ enabled: true,
135
+ reason: res.reason,
136
+ ran: true,
137
+ blocks: result.blocks,
138
+ summary: (0, run_1.describeCorrectnessFloor)(result),
139
+ result,
140
+ };
141
+ }
142
+ //# sourceMappingURL=surface-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-run.js","sourceRoot":"","sources":["../../../src/analyzers/correctness/surface-run.ts"],"names":[],"mappings":"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"}