@vyuhlabs/dxkit 2.22.0 → 2.24.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 (93) hide show
  1. package/CHANGELOG.md +97 -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/cli.d.ts.map +1 -1
  15. package/dist/cli.js +144 -4
  16. package/dist/cli.js.map +1 -1
  17. package/dist/generator.d.ts.map +1 -1
  18. package/dist/generator.js +5 -0
  19. package/dist/generator.js.map +1 -1
  20. package/dist/issue-cli.d.ts +2 -1
  21. package/dist/issue-cli.d.ts.map +1 -1
  22. package/dist/issue-cli.js +4 -0
  23. package/dist/issue-cli.js.map +1 -1
  24. package/dist/languages/capabilities/correctness.d.ts +54 -0
  25. package/dist/languages/capabilities/correctness.d.ts.map +1 -0
  26. package/dist/languages/capabilities/correctness.js +20 -0
  27. package/dist/languages/capabilities/correctness.js.map +1 -0
  28. package/dist/languages/csharp.d.ts.map +1 -1
  29. package/dist/languages/csharp.js +84 -0
  30. package/dist/languages/csharp.js.map +1 -1
  31. package/dist/languages/go.d.ts.map +1 -1
  32. package/dist/languages/go.js +51 -0
  33. package/dist/languages/go.js.map +1 -1
  34. package/dist/languages/index.d.ts +11 -0
  35. package/dist/languages/index.d.ts.map +1 -1
  36. package/dist/languages/index.js +12 -0
  37. package/dist/languages/index.js.map +1 -1
  38. package/dist/languages/java.d.ts.map +1 -1
  39. package/dist/languages/java.js +12 -0
  40. package/dist/languages/java.js.map +1 -1
  41. package/dist/languages/jvm-build.d.ts +54 -0
  42. package/dist/languages/jvm-build.d.ts.map +1 -0
  43. package/dist/languages/jvm-build.js +245 -0
  44. package/dist/languages/jvm-build.js.map +1 -0
  45. package/dist/languages/kotlin.d.ts.map +1 -1
  46. package/dist/languages/kotlin.js +13 -0
  47. package/dist/languages/kotlin.js.map +1 -1
  48. package/dist/languages/python.d.ts.map +1 -1
  49. package/dist/languages/python.js +78 -0
  50. package/dist/languages/python.js.map +1 -1
  51. package/dist/languages/ruby.d.ts.map +1 -1
  52. package/dist/languages/ruby.js +64 -0
  53. package/dist/languages/ruby.js.map +1 -1
  54. package/dist/languages/rust.d.ts.map +1 -1
  55. package/dist/languages/rust.js +110 -0
  56. package/dist/languages/rust.js.map +1 -1
  57. package/dist/languages/types.d.ts +20 -0
  58. package/dist/languages/types.d.ts.map +1 -1
  59. package/dist/languages/typescript.d.ts.map +1 -1
  60. package/dist/languages/typescript.js +109 -0
  61. package/dist/languages/typescript.js.map +1 -1
  62. package/dist/loop/floor-gate.d.ts +54 -0
  63. package/dist/loop/floor-gate.d.ts.map +1 -0
  64. package/dist/loop/floor-gate.js +157 -0
  65. package/dist/loop/floor-gate.js.map +1 -0
  66. package/dist/loop/floor-state.d.ts +66 -0
  67. package/dist/loop/floor-state.d.ts.map +1 -0
  68. package/dist/loop/floor-state.js +138 -0
  69. package/dist/loop/floor-state.js.map +1 -0
  70. package/dist/loop/scaffold.d.ts +4 -0
  71. package/dist/loop/scaffold.d.ts.map +1 -1
  72. package/dist/loop/scaffold.js +7 -7
  73. package/dist/loop/scaffold.js.map +1 -1
  74. package/dist/loop/stop-gate.d.ts +2 -1
  75. package/dist/loop/stop-gate.d.ts.map +1 -1
  76. package/dist/loop/stop-gate.js +44 -6
  77. package/dist/loop/stop-gate.js.map +1 -1
  78. package/dist/ship-installers.d.ts +20 -0
  79. package/dist/ship-installers.d.ts.map +1 -1
  80. package/dist/ship-installers.js +17 -16
  81. package/dist/ship-installers.js.map +1 -1
  82. package/dist/uninstall/index.d.ts +47 -0
  83. package/dist/uninstall/index.d.ts.map +1 -0
  84. package/dist/uninstall/index.js +418 -0
  85. package/dist/uninstall/index.js.map +1 -0
  86. package/dist/uninstall/reversals.d.ts +70 -0
  87. package/dist/uninstall/reversals.d.ts.map +1 -0
  88. package/dist/uninstall/reversals.js +202 -0
  89. package/dist/uninstall/reversals.js.map +1 -0
  90. package/package.json +1 -1
  91. package/templates/.claude/skills/dxkit-uninstall/SKILL.md +55 -0
  92. package/templates/.githooks/pre-push +10 -0
  93. package/templates/.github/workflows/dxkit-guardrails.yml +17 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,103 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [2.24.0] - 2026-07-04
11
+
12
+ ### Added — `vyuh-dxkit uninstall` (restore the pre-dxkit state)
13
+
14
+ A clean, non-intrusive way to remove dxkit. Its one guarantee: after uninstall,
15
+ the repo is back to its **exact pre-dxkit state** — every file dxkit created is
16
+ gone, and every additive change dxkit made to a file you already had is reversed,
17
+ leaving your own content byte-for-byte intact.
18
+
19
+ - **Two kinds of footprint, handled differently.** Files dxkit created (`.dxkit/`,
20
+ the `dxkit-*` skills, `AGENTS.md`, the git hooks, the `dxkit-*` workflows,
21
+ `.dxkit-ignore`, `.vyuh-dxkit.json`) are removed. Additive merges into files you
22
+ already had — the `.gitignore` block, the `CLAUDE.md` loop block, the
23
+ `settings.json` hooks (`context-hook` / `stop-gate`), and the `package.json`
24
+ `@vyuhlabs/dxkit` devDependency + postinstall — are surgically reverted, keeping
25
+ your keys, prose, and formatting. JSON reverts preserve the file's original
26
+ indent + trailing-newline so there is no spurious diff.
27
+ - **Manifest-driven + hash-guarded.** It reads the install manifest
28
+ (`.vyuh-dxkit.json`) for the authoritative created-file list, flags, and hashes.
29
+ A dxkit-created file you have since edited is surfaced and **skipped** (never
30
+ clobbered) unless you pass `--force`; the manifest is kept in that case so a
31
+ later `--force` run can still find it.
32
+ - **`vyuh-dxkit uninstall [path] [--yes] [--keep-baselines] [--remove-devdep]
33
+ [--force] [--no-feedback] [--json]`** — dry-run by default (prints exactly what
34
+ it will remove/revert); `--yes` applies. `--keep-baselines` keeps the curated,
35
+ git-tracked artifacts (baselines, allowlist, `external/`). On completion it
36
+ offers a prefilled GitHub issue for optional feedback — nothing is sent
37
+ automatically, and `--no-feedback` skips it.
38
+ - **`dxkit-uninstall` skill** — the graceful-exit surface for an agent.
39
+
40
+ The reversal markers are imported from the installer modules, so a marker change
41
+ breaks install and uninstall together (recipe symmetry); a test asserts every
42
+ install surface and all four self-invocation surfaces have a removal path.
43
+
44
+ ## [2.23.0] - 2026-07-04
45
+
46
+ ### Added — the correctness floor (a loop-safety liveness gate)
47
+
48
+ The guardrail proves "no net-new findings" (secrets, CVEs, SAST, coverage). It
49
+ does not prove the code still **compiles and its affected tests still pass** — so
50
+ an autonomous agent loop can satisfy the finding gate while shipping code that
51
+ does not build, and even a broken test that lifts coverage gets rewarded. The
52
+ correctness floor closes that gap: a liveness check that asks "does this still
53
+ build, and do the tests it affects still pass?" before an agent may declare
54
+ "done". A failing floor is a pass/fail signal, not a fingerprinted, grandfathered
55
+ finding (there is no "grandfather a syntax error"), so it sits outside the
56
+ baseline and allowlist.
57
+
58
+ - **Pack-declared, runner-executed** (CLAUDE.md Rule 15). Each language pack
59
+ declares two pure command builders — `syntaxCheck` (the cheap "does it
60
+ compile/parse" check) and `affectedTests` (run the tests the change reaches).
61
+ One runner owns the load-bearing policy in a single place: fail-CLOSED on a
62
+ real failure (a non-zero exit blocks), fail-OPEN on infrastructure (a missing
63
+ toolchain or a timeout is a skip, never a block — a slow or un-installed
64
+ toolchain is not broken code; CI is the backstop). A pack never shells out
65
+ itself.
66
+ - **All 8 packs, verified against real toolchains**, at the affected granularity
67
+ each ecosystem natively supports:
68
+
69
+ | Pack | Compile | Affected-test granularity |
70
+ | --- | --- | --- |
71
+ | TypeScript / JavaScript | `tsc --noEmit` (or the project's typecheck script) | per-file (`vitest related` / `jest --findRelatedTests`) |
72
+ | Python | `py_compile` | per changed test file (pytest) |
73
+ | Go | `go build ./...` | changed package(s) |
74
+ | Rust | `cargo check` | changed crate(s) (`-p`) |
75
+ | C# / .NET | `dotnet build` | changed test project (`dotnet test <proj>`) |
76
+ | Java | Maven `test-compile` / Gradle `testClasses` | changed build module (Maven `-pl -am`, Gradle `:mod:test`) |
77
+ | Kotlin | Maven `test-compile` / Gradle `testClasses` | changed build module |
78
+ | Ruby | `ruby -c` per changed file | changed spec/test file (RSpec / minitest) |
79
+
80
+ A change whose dependents live in another package/module/crate is caught at
81
+ full/CI scope, not the fast affected surface. The two JVM packs share one
82
+ `jvm-build.ts` provider (Rule 2).
83
+ - **Three surfaces, one adaptive resolver.** The loop Stop-gate runs the floor
84
+ by default (an agent must not stop on broken code), scoped to what the loop
85
+ introduced via a testmon-style entry snapshot, so a pre-existing failure never
86
+ blocks. The pre-push and CI surfaces are adaptive: when the repo already runs
87
+ its tests in its own CI, the floor defaults to opt-in there; when no test-CI is
88
+ detected it runs by default; when a CI exists but its test step is opaque it
89
+ fails toward on. Precedence: an explicit flag, then a `DXKIT_FLOOR_<SURFACE>`
90
+ env, then `.dxkit/policy.json` `correctness.surfaces.<surface>`, then the
91
+ adaptive default.
92
+ - **`vyuh-dxkit floor check [--surface pre-push|ci] [--base <ref>]
93
+ [--correctness | --no-correctness]`** — the entry point the pre-push hook and
94
+ CI workflow call. It is baseline-independent, so a brand-new repo with no
95
+ baseline still gets push-time liveness. The installed pre-push hook runs it
96
+ before the baseline check; the CI guardrail workflow runs it (full scope) after
97
+ the finding gate.
98
+
99
+ ### Changed
100
+
101
+ - `LanguageSupport.correctness` is now a required field: the capability shipped
102
+ optional and tightened once all eight packs declared it, so a new pack that
103
+ omits it fails to compile (not just at test time). The `new-lang` scaffold
104
+ wires a dormant provider so a fresh pack still compiles, with TODOs for the
105
+ real commands.
106
+
10
107
  ## [2.22.0] - 2026-07-02
11
108
 
12
109
  ### Added — the flow feature becomes agent-operable (setup, diagnose, publish, repair)
@@ -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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"}