zelari-code 2.13.0 → 2.14.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 (84) hide show
  1. package/dist/cli/headless/policyGate.js +101 -0
  2. package/dist/cli/headless/policyGate.js.map +1 -0
  3. package/dist/cli/headless.js.map +1 -1
  4. package/dist/cli/kraken/completionProof.js +89 -41
  5. package/dist/cli/kraken/completionProof.js.map +1 -1
  6. package/dist/cli/kraken/completionProofAttestation.js +157 -0
  7. package/dist/cli/kraken/completionProofAttestation.js.map +1 -0
  8. package/dist/cli/kraken/completionProofPersist.js +219 -0
  9. package/dist/cli/kraken/completionProofPersist.js.map +1 -0
  10. package/dist/cli/kraken/completionProofProbe.js +135 -0
  11. package/dist/cli/kraken/completionProofProbe.js.map +1 -0
  12. package/dist/cli/kraken/contractCompiler.js +142 -0
  13. package/dist/cli/kraken/contractCompiler.js.map +1 -0
  14. package/dist/cli/kraken/delegationPolicy.js +40 -3
  15. package/dist/cli/kraken/delegationPolicy.js.map +1 -1
  16. package/dist/cli/kraken/executor.js +462 -9
  17. package/dist/cli/kraken/executor.js.map +1 -1
  18. package/dist/cli/kraken/fileOwnership.js +190 -0
  19. package/dist/cli/kraken/fileOwnership.js.map +1 -0
  20. package/dist/cli/kraken/modelReputation.js +208 -0
  21. package/dist/cli/kraken/modelReputation.js.map +1 -0
  22. package/dist/cli/kraken/nativeVerification.js +53 -11
  23. package/dist/cli/kraken/nativeVerification.js.map +1 -1
  24. package/dist/cli/kraken/planner.js +2 -0
  25. package/dist/cli/kraken/planner.js.map +1 -1
  26. package/dist/cli/kraken/reputationStore.js +139 -0
  27. package/dist/cli/kraken/reputationStore.js.map +1 -0
  28. package/dist/cli/kraken/semanticOwnership.js +184 -0
  29. package/dist/cli/kraken/semanticOwnership.js.map +1 -0
  30. package/dist/cli/kraken/spawnRoi.js +209 -0
  31. package/dist/cli/kraken/spawnRoi.js.map +1 -0
  32. package/dist/cli/kraken/transactional.js +104 -0
  33. package/dist/cli/kraken/transactional.js.map +1 -0
  34. package/dist/cli/kraken/verificationAdapters/dotnet.js +49 -0
  35. package/dist/cli/kraken/verificationAdapters/dotnet.js.map +1 -0
  36. package/dist/cli/kraken/verificationAdapters/go.js +36 -0
  37. package/dist/cli/kraken/verificationAdapters/go.js.map +1 -0
  38. package/dist/cli/kraken/verificationAdapters/index.js +47 -0
  39. package/dist/cli/kraken/verificationAdapters/index.js.map +1 -0
  40. package/dist/cli/kraken/verificationAdapters/java.js +102 -0
  41. package/dist/cli/kraken/verificationAdapters/java.js.map +1 -0
  42. package/dist/cli/kraken/verificationAdapters/node.js +90 -0
  43. package/dist/cli/kraken/verificationAdapters/node.js.map +1 -0
  44. package/dist/cli/kraken/verificationAdapters/python.js +86 -0
  45. package/dist/cli/kraken/verificationAdapters/python.js.map +1 -0
  46. package/dist/cli/kraken/verificationAdapters/rust.js +39 -0
  47. package/dist/cli/kraken/verificationAdapters/rust.js.map +1 -0
  48. package/dist/cli/kraken/verificationAdapters/types.js +2 -0
  49. package/dist/cli/kraken/verificationAdapters/types.js.map +1 -0
  50. package/dist/cli/kraken/verificationBridge.js +40 -3
  51. package/dist/cli/kraken/verificationBridge.js.map +1 -1
  52. package/dist/cli/kraken/verifierLifecycle.js +51 -36
  53. package/dist/cli/kraken/verifierLifecycle.js.map +1 -1
  54. package/dist/cli/kraken/verifierRouting.js +264 -0
  55. package/dist/cli/kraken/verifierRouting.js.map +1 -0
  56. package/dist/cli/kraken/worktreeScheduling.js +201 -0
  57. package/dist/cli/kraken/worktreeScheduling.js.map +1 -0
  58. package/dist/cli/main.bundled.js +3880 -889
  59. package/dist/cli/main.bundled.js.map +4 -4
  60. package/dist/cli/orchestration/facts.js +127 -0
  61. package/dist/cli/orchestration/facts.js.map +1 -0
  62. package/dist/cli/orchestration/policy.js +128 -75
  63. package/dist/cli/orchestration/policy.js.map +1 -1
  64. package/dist/cli/orchestration/signals.js +96 -0
  65. package/dist/cli/orchestration/signals.js.map +1 -0
  66. package/dist/cli/runHeadless.js +92 -19
  67. package/dist/cli/runHeadless.js.map +1 -1
  68. package/dist/cli/safety/policyEngine.js +159 -20
  69. package/dist/cli/safety/policyEngine.js.map +1 -1
  70. package/dist/cli/safety/policyLoadMode.js +59 -0
  71. package/dist/cli/safety/policyLoadMode.js.map +1 -0
  72. package/dist/cli/safety/resourceClaims.js +373 -0
  73. package/dist/cli/safety/resourceClaims.js.map +1 -0
  74. package/dist/cli/safety/sandboxPath.js +160 -17
  75. package/dist/cli/safety/sandboxPath.js.map +1 -1
  76. package/dist/cli/toolRegistry.js +98 -8
  77. package/dist/cli/toolRegistry.js.map +1 -1
  78. package/dist/cli/tools/execProcess.js +121 -0
  79. package/dist/cli/tools/execProcess.js.map +1 -0
  80. package/dist/cli/tools/krakenRadio.js +9 -0
  81. package/dist/cli/tools/krakenRadio.js.map +1 -1
  82. package/dist/cli/tools/taskTool.js +8 -3
  83. package/dist/cli/tools/taskTool.js.map +1 -1
  84. package/package.json +2 -2
@@ -0,0 +1,209 @@
1
+ /**
2
+ * spawnRoi — t30 (hardening plan §17): orchestration ROI gate.
3
+ *
4
+ * Every tentacle spawn must have positive expected value. A node is worth
5
+ * starting only when its expected success gain outweighs what the spawn costs:
6
+ *
7
+ * spawnScore = expectedSuccessGain / (cost + latency + duplicationRisk)
8
+ *
9
+ * PURE module — zero fs, zero env, zero clock reads: same input ⇒ same score.
10
+ * Wall-clock time never enters here; recency decay is already baked into the
11
+ * t29 reputation aggregate the executor feeds in (`now` is injected there).
12
+ * The executor owns the policy side: it scores each admitted node before the
13
+ * tentacle starts, vetoes (advisory-first v1) anything below the threshold by
14
+ * sending it back the deferred path — stays READY, never failed — and emits
15
+ * the `node_roi_vetoed` radio trail.
16
+ *
17
+ * Score formula (v1, deterministic):
18
+ * gain = verifiedRate * repairFactor * kindWeight
19
+ * verifiedRate = clamp01(verifiedRate ?? DEFAULT_VERIFIED_RATE)
20
+ * — unknown history is neither trusted nor punished: 0.7 says "a spawn
21
+ * with no evidence is presumed useful".
22
+ * repairFactor = max(REPAIR_FACTOR_FLOOR,
23
+ * 1 + REPAIR_PENALTY * (avgRepairs ?? DEFAULT_AVG_REPAIRS))
24
+ * — every historical repair round discounts the gain (rework is the
25
+ * visible part of a low-quality spawn), floored so even a catastrophic
26
+ * record keeps a positive gain.
27
+ * kindWeight = KIND_WEIGHTS[taskKind]
28
+ * cost = money + latency + duplicationRisk * COST_SCALE
29
+ * money = (estimatedTokens / 1000 * costUsdPer1k) / COST_NORM_USD when
30
+ * both estimates exist, else DEFAULT_COST_NORM (unknown prices
31
+ * like a ~$0.10 run — absence of data ≠ free).
32
+ * latency = latencyMsEstimate / LATENCY_NORM_MS when known, else
33
+ * DEFAULT_LATENCY_NORM (unknown ≈ a 5-minute run).
34
+ * score = gain / max(cost, COST_FLOOR)
35
+ *
36
+ * Calibration (SPAWN_SCORE_THRESHOLD = 0.15): an all-null input scores
37
+ * 0.6475 / 2 ≈ 0.324 — comfortably above the threshold, so the gate SPAWNS on
38
+ * missing data. An advisor that vetoes everything on unknowns is worse than
39
+ * no advisor. The executor passes nulls whenever the reputation bucket has
40
+ * fewer than REPUTATION_MIN_SAMPLE records, so under the default threshold a
41
+ * veto can only happen on reputation-backed evidence (a bad verified-rate
42
+ * bucket) or extreme duplication — never on mere absence of data.
43
+ *
44
+ * Threshold override: the EXECUTOR reads ZELARI_KRAKEN_ROI_THRESHOLD and hands
45
+ * the raw string to {@link parseRoiThreshold}; this module stays env-free.
46
+ *
47
+ * @since v0.10.x — Kraken hardening §17 (P2.F / t30)
48
+ */
49
+ import { globsOverlap, normalizeGlob } from './fileOwnership.js';
50
+ import { REPUTATION_MIN_SAMPLE } from './modelReputation.js';
51
+ /** Verified rate presumed when history is unknown/too thin to trust. */
52
+ export const DEFAULT_VERIFIED_RATE = 0.7;
53
+ /** Gain discount per historical repair round (negative: rework discounts). */
54
+ export const REPAIR_PENALTY = -0.15;
55
+ /** Floor for the repair factor — a terrible record still has nonzero gain. */
56
+ export const REPAIR_FACTOR_FLOOR = 0.3;
57
+ /** Average repair rounds presumed when unknown. */
58
+ export const DEFAULT_AVG_REPAIRS = 0.5;
59
+ /** Marginal value of one spawn by task kind (advisory v1 calibration). */
60
+ export const KIND_WEIGHTS = {
61
+ explore: 1.0, // unique information, cheap — never presumptively vetoed
62
+ implement: 1.0, // the task's actual output
63
+ verify: 0.9, // guards quality; a skipped verify can be re-run later
64
+ review: 0.85, // advisory review, least unique output
65
+ };
66
+ /** An estimated $0.10 run contributes 1.0 cost unit. */
67
+ export const COST_NORM_USD = 0.1;
68
+ /** Cost-unit contribution of UNKNOWN money (≈ a $0.10 run: unknown ≠ free). */
69
+ export const DEFAULT_COST_NORM = 1.0;
70
+ /** An estimated 5-minute run contributes 1.0 cost unit. */
71
+ export const LATENCY_NORM_MS = 300_000;
72
+ /** Cost-unit contribution of UNKNOWN latency (≈ a 5-minute run). */
73
+ export const DEFAULT_LATENCY_NORM = 1.0;
74
+ /** A fully duplicated spawn (risk 1) adds one full cost unit. */
75
+ export const COST_SCALE = 1.0;
76
+ /** Denominator floor — a zero-cost spawn cannot divide by zero. */
77
+ export const COST_FLOOR = 1e-6;
78
+ /**
79
+ * Default spawn threshold: score ≥ threshold spawns. 0.15 keeps the default
80
+ * verdict "spawn" for every unknown-input shape (see the header calibration
81
+ * note). Lower it to gate harder; raise it only once reputation coverage
82
+ * exists, or the gate will veto on missing data.
83
+ */
84
+ export const SPAWN_SCORE_THRESHOLD = 0.15;
85
+ /** Treat non-finite garbage as "unknown" — NaN must never reach the score. */
86
+ function finiteOrNull(v) {
87
+ return typeof v === 'number' && Number.isFinite(v) ? v : null;
88
+ }
89
+ function clamp01(v) {
90
+ return Math.min(1, Math.max(0, v));
91
+ }
92
+ /** Snap an arbitrary number onto the {@link DuplicationRisk} lattice (nearest point). */
93
+ function toDuplicationRisk(v) {
94
+ if (v === null || v <= 0.125)
95
+ return 0;
96
+ if (v < 0.375)
97
+ return 0.25;
98
+ if (v < 0.75)
99
+ return 0.5;
100
+ return 1;
101
+ }
102
+ /**
103
+ * Deterministic ROI score for one would-be spawn. All-null inputs produce the
104
+ * sane default score (≈ 0.324, see header) — never NaN: every numeric field
105
+ * is sanitized to "unknown" and unknowns have documented defaults.
106
+ */
107
+ export function computeSpawnScore(input) {
108
+ const verified = clamp01(finiteOrNull(input.verifiedRate) ?? DEFAULT_VERIFIED_RATE);
109
+ const repairs = Math.max(0, finiteOrNull(input.historicalAvgRepairs) ?? DEFAULT_AVG_REPAIRS);
110
+ const repairFactor = Math.max(REPAIR_FACTOR_FLOOR, 1 + REPAIR_PENALTY * repairs);
111
+ const kindWeight = KIND_WEIGHTS[input.taskKind] ?? 1;
112
+ const gain = verified * repairFactor * kindWeight;
113
+ const tokens = finiteOrNull(input.estimatedTokens);
114
+ const price = finiteOrNull(input.costUsdPer1k);
115
+ const money = tokens !== null && price !== null
116
+ ? Math.max(0, (tokens / 1000) * price) / COST_NORM_USD
117
+ : DEFAULT_COST_NORM;
118
+ const latency = finiteOrNull(input.latencyMsEstimate);
119
+ const latencyNorm = latency !== null ? Math.max(0, latency) / LATENCY_NORM_MS : DEFAULT_LATENCY_NORM;
120
+ const dup = toDuplicationRisk(finiteOrNull(input.duplicationRisk));
121
+ const cost = money + latencyNorm + dup * COST_SCALE;
122
+ return {
123
+ score: gain / Math.max(cost, COST_FLOOR),
124
+ components: { gain, cost },
125
+ rationaleCode: (finiteOrNull(input.reputationSample) ?? 0) >= REPUTATION_MIN_SAMPLE
126
+ ? 'roi-reputation-backed'
127
+ : 'roi-defaults',
128
+ };
129
+ }
130
+ /**
131
+ * The gate verdict: spawn at-or-above the threshold (ties spawn — the
132
+ * fail-open direction). A non-finite threshold spawns too: garbage input
133
+ * must never veto work.
134
+ */
135
+ export function shouldSpawn(scoreResult, threshold = SPAWN_SCORE_THRESHOLD) {
136
+ if (!Number.isFinite(threshold))
137
+ return true;
138
+ return scoreResult.score >= threshold;
139
+ }
140
+ /**
141
+ * Parse the ZELARI_KRAKEN_ROI_THRESHOLD override. Empty/undefined/invalid or
142
+ * negative values fall back to SPAWN_SCORE_THRESHOLD; anything parseFloat
143
+ * accepts and is finite and ≥ 0 is honored ('0' disables the veto outright).
144
+ */
145
+ export function parseRoiThreshold(raw) {
146
+ if (raw === undefined || raw === null)
147
+ return SPAWN_SCORE_THRESHOLD;
148
+ const s = raw.trim();
149
+ if (s.length === 0)
150
+ return SPAWN_SCORE_THRESHOLD;
151
+ const n = Number.parseFloat(s);
152
+ if (!Number.isFinite(n) || n < 0)
153
+ return SPAWN_SCORE_THRESHOLD;
154
+ return n;
155
+ }
156
+ /** Kinds that never mutate the workspace (fileOwnership READ_ONLY_KINDS parity). */
157
+ const READ_ONLY_KINDS = ['explore', 'verify', 'spec', 'conformance'];
158
+ /**
159
+ * The scope globs a node works on — for duplication (unlike write ownership)
160
+ * this applies to readers too: a missing/empty scope claims the whole tree.
161
+ */
162
+ function workScopeOf(node) {
163
+ const scope = node.scope;
164
+ if (!scope || scope.length === 0)
165
+ return ['**'];
166
+ return scope;
167
+ }
168
+ function isWriterKind(kind) {
169
+ return !READ_ONLY_KINDS.includes(kind);
170
+ }
171
+ /**
172
+ * Duplication-risk heuristic: the chance this spawn repeats work a
173
+ * concurrently-racing node is already doing, from task class + scope overlap.
174
+ * Reuses fileOwnership's globsOverlap/normalizeGlob so both layers agree on
175
+ * what a scope claims (case-folded first, mirroring globsOverlap's default):
176
+ * 0 — no racing node touches this scope;
177
+ * 0.25 — read-only overlap (two readers may duplicate conclusions, but
178
+ * nothing conflicts);
179
+ * 0.5 — at least one writer is involved on an overlapping (non-identical)
180
+ * claim;
181
+ * 1 — an identical normalized glob claim (same tree, same kind of work:
182
+ * near-certain duplicate).
183
+ * Deterministic; the node itself (same id) is excluded from the race set.
184
+ */
185
+ export function duplicationRiskFor(node, racing) {
186
+ let risk = 0;
187
+ // Fold case before normalizing — globsOverlap folds internally, so the
188
+ // identical-claim check must see the same folded form to agree with it.
189
+ const scopeA = workScopeOf(node).map((g) => normalizeGlob(g.toLowerCase()));
190
+ const nodeWrites = isWriterKind(node.kind);
191
+ for (const other of racing) {
192
+ if (!other || other.id === node.id)
193
+ continue;
194
+ const scopeB = workScopeOf(other).map((g) => normalizeGlob(g.toLowerCase()));
195
+ const overlaps = scopeA.some((a) => scopeB.some((b) => globsOverlap(a, b)));
196
+ if (!overlaps)
197
+ continue;
198
+ const identical = scopeA.some((a) => scopeB.some((b) => a === b));
199
+ const candidate = identical
200
+ ? 1
201
+ : nodeWrites || isWriterKind(other.kind)
202
+ ? 0.5
203
+ : 0.25;
204
+ if (candidate > risk)
205
+ risk = candidate;
206
+ }
207
+ return risk;
208
+ }
209
+ //# sourceMappingURL=spawnRoi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawnRoi.js","sourceRoot":"","sources":["../../../src/cli/kraken/spawnRoi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * transactional — checkpoint → run → keep-or-rollback wrapper (P2.D).
3
+ *
4
+ * Wraps one unit of work (a writer tentacle run) in a workspace transaction:
5
+ * 1. checkpoint the working tree via `checkpointManager` (git plumbing only
6
+ * — HEAD, branch, index and stash are never touched);
7
+ * 2. run the work;
8
+ * 3. PASS → keep the checkpoint as a recovery point, correlated to the
9
+ * task/node through the checkpoint label;
10
+ * FAIL → restore the tree to the checkpoint and drop the ref, so a
11
+ * failed subagent never leaves a dirty workspace (a retry then
12
+ * starts from clean state);
13
+ * restore failure → surfaced honestly: the outcome is still `rolledback`
14
+ * but the error says the workspace may be dirty. Never swallowed.
15
+ *
16
+ * When no transaction is possible — not a git repo, or the checkpoint itself
17
+ * fails to create — the work still runs (`passthrough`) with an honest `note`.
18
+ * A passthrough run does NOT swallow errors: there is nothing to roll back,
19
+ * so a throwing work rejects all the way out to the caller's ordinary error
20
+ * handling.
21
+ *
22
+ * Concurrency note: the checkpoint/restore covers the WHOLE working tree, not
23
+ * one node's write scope. Concurrent in-place writers sharing a tree (i.e.
24
+ * worktree isolation off) can have a sibling's post-checkpoint writes reverted
25
+ * by a rollback. Part of why this stays opt-in (default OFF) for v1.
26
+ *
27
+ * @since P2.D — transactional agent execution
28
+ */
29
+ import { isGitRepo, createCheckpoint, restoreCheckpoint, dropCheckpoint, } from '../checkpoint/checkpointManager.js';
30
+ /**
31
+ * Correlated checkpoint label: `task=<id> node=<id> · <label>`.
32
+ *
33
+ * `Checkpoint` has no metadata slot — the git commit subject is the only
34
+ * persisted annotation — so the correlation rides in the label: it survives
35
+ * in the ref's commit message and comes back verbatim from
36
+ * `listCheckpoints(...)[i].label`.
37
+ */
38
+ export function correlatedLabel(opts) {
39
+ const parts = [];
40
+ if (opts.taskId)
41
+ parts.push(`task=${opts.taskId}`);
42
+ if (opts.nodeId)
43
+ parts.push(`node=${opts.nodeId}`);
44
+ return parts.length > 0 ? `${parts.join(' ')} · ${opts.label}` : opts.label;
45
+ }
46
+ /**
47
+ * Run `fn` inside a workspace transaction: checkpoint → run → PASS keep /
48
+ * FAIL rollback. Failure means `fn` threw (or rejected) — a resolved result
49
+ * is a success by definition here; callers that get a failure *value* from
50
+ * their work should map it to a throw before handing it over.
51
+ */
52
+ export async function runTransactional(opts, fn) {
53
+ // No git, no transaction — but the work must still happen. Errors propagate.
54
+ if (!(await isGitRepo(opts.cwd))) {
55
+ const value = await fn();
56
+ return {
57
+ outcome: 'passthrough',
58
+ value,
59
+ note: 'not a git repository — ran without a transaction (no checkpoint, no rollback)',
60
+ };
61
+ }
62
+ const created = await createCheckpoint(opts.cwd, correlatedLabel(opts));
63
+ if (!created.ok) {
64
+ const value = await fn();
65
+ return {
66
+ outcome: 'passthrough',
67
+ value,
68
+ note: `checkpoint failed (${created.error}) — ran without a transaction`,
69
+ };
70
+ }
71
+ const checkpointId = created.value.id;
72
+ let value;
73
+ try {
74
+ value = await fn();
75
+ }
76
+ catch (err) {
77
+ const cause = err instanceof Error ? err.message : String(err);
78
+ const restored = await restoreCheckpoint(opts.cwd, checkpointId);
79
+ if (!restored.ok) {
80
+ // Never swallow a failed restore: the caller must know the workspace
81
+ // may be dirty. The checkpoint ref stays — it is the only way back.
82
+ return {
83
+ outcome: 'rolledback',
84
+ error: `${cause} — RESTORE FAILED (${restored.error}); workspace may be dirty`,
85
+ checkpointId,
86
+ };
87
+ }
88
+ // Rollback done; drop the spent recovery point (best-effort — a stale ref
89
+ // is clutter, not corruption).
90
+ await dropCheckpoint(opts.cwd, checkpointId);
91
+ const removed = restored.value.deleted.length;
92
+ return {
93
+ outcome: 'rolledback',
94
+ error: `${cause} — rolled back to checkpoint ${checkpointId}` +
95
+ (removed > 0
96
+ ? ` (${removed} file${removed === 1 ? '' : 's'} created after the snapshot removed)`
97
+ : ''),
98
+ checkpointId,
99
+ };
100
+ }
101
+ // PASS: keep the checkpoint as the recovery point for this task/node.
102
+ return { outcome: 'success', value, checkpointId };
103
+ }
104
+ //# sourceMappingURL=transactional.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transactional.js","sourceRoot":"","sources":["../../../src/cli/kraken/transactional.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * verificationAdapters/dotnet — .NET solutions and projects (P1.A2 / t24).
3
+ *
4
+ * Ecosystem ownership: a root containing any `*.sln` / `*.slnx` (score 4) or
5
+ * `*.csproj` / `*.fsproj` (score 3). The scan is depth-1 ONLY — the honest,
6
+ * cheap, deterministic boundary for v1. Nested-only layouts (a project file
7
+ * under src/ with nothing at the root) are deliberately NOT claimed:
8
+ * `dotnet` verbs would run against a directory with no buildable input and
9
+ * misreport as `fail` instead of an honest not-applicable.
10
+ *
11
+ * Honest-unknown rule: .NET has no typecheck verb separate from compilation
12
+ * (`dotnet build` compiles AND validates), so typecheck stays null. test and
13
+ * build bind unconditionally: `dotnet test` / `dotnet build` natively target
14
+ * the solution or the project in the working directory.
15
+ */
16
+ import { readdir } from 'node:fs/promises';
17
+ const SOLUTION_EXTENSIONS = ['.sln', '.slnx'];
18
+ const PROJECT_EXTENSIONS = ['.csproj', '.fsproj'];
19
+ /**
20
+ * Whether any root-level FILE ends with one of `extensions`
21
+ * (case-insensitive — Windows-authored trees commonly uppercase them).
22
+ * An unreadable root → false (honest absence, never a guess).
23
+ */
24
+ async function hasRootFileWithExtension(root, extensions) {
25
+ let entries;
26
+ try {
27
+ entries = await readdir(root, { withFileTypes: true });
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ return entries.some((entry) => entry.isFile() && extensions.some((ext) => entry.name.toLowerCase().endsWith(ext)));
33
+ }
34
+ export const dotnetAdapter = {
35
+ async detect(root) {
36
+ if (await hasRootFileWithExtension(root, SOLUTION_EXTENSIONS))
37
+ return 4;
38
+ return (await hasRootFileWithExtension(root, PROJECT_EXTENSIONS)) ? 3 : 0;
39
+ },
40
+ async buildPlan(_root) {
41
+ void _root; // dotnet verbs resolve the sln/project in the working dir themselves
42
+ return {
43
+ typecheckCommand: null, // compilation IS the check — see header
44
+ testCommand: 'dotnet test',
45
+ buildCommand: 'dotnet build',
46
+ };
47
+ },
48
+ };
49
+ //# sourceMappingURL=dotnet.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotnet.js","sourceRoot":"","sources":["../../../../src/cli/kraken/verificationAdapters/dotnet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,mBAAmB,GAAsB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AACjE,MAAM,kBAAkB,GAAsB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAErE;;;;GAIG;AACH,KAAK,UAAU,wBAAwB,CAAC,IAAY,EAAE,UAA6B;IACjF,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CACjB,CAAC,KAAK,EAAE,EAAE,CACR,KAAK,CAAC,MAAM,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CACrF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAwB;IAChD,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,IAAI,MAAM,wBAAwB,CAAC,IAAI,EAAE,mBAAmB,CAAC;YAAE,OAAO,CAAC,CAAC;QACxE,OAAO,CAAC,MAAM,wBAAwB,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,KAAK,KAAK,CAAC,CAAC,qEAAqE;QACjF,OAAO;YACL,gBAAgB,EAAE,IAAI,EAAE,wCAAwC;YAChE,WAAW,EAAE,aAAa;YAC1B,YAAY,EAAE,cAAc;SAC7B,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * verificationAdapters/go — Go modules (t19 §P1.A).
3
+ *
4
+ * Slot-mapping decision (documented per task brief): Go has NO separate
5
+ * typecheck verb — compilation IS the typecheck — and the canonical static
6
+ * gate is `go vet ./...`. Vet is therefore mapped onto the TYPECHECK slot:
7
+ * it is the semantic equivalent of what `tsc --noEmit` enforces on Node
8
+ * repos (compile errors + suspicious constructs, no artifacts emitted),
9
+ * keeping strict-mode meaning aligned across ecosystems.
10
+ *
11
+ * `./...` patterns cover every package in the module and its subpackages —
12
+ * matching how Go teams gate CI.
13
+ */
14
+ import { stat } from 'node:fs/promises';
15
+ import path from 'node:path';
16
+ async function fileExists(candidate) {
17
+ try {
18
+ return (await stat(candidate)).isFile();
19
+ }
20
+ catch {
21
+ return false;
22
+ }
23
+ }
24
+ export const goAdapter = {
25
+ async detect(root) {
26
+ return (await fileExists(path.join(root, 'go.mod'))) ? 10 : 0;
27
+ },
28
+ async buildPlan(_root) {
29
+ return {
30
+ typecheckCommand: 'go vet ./...', // mapped slot — see rationale above
31
+ testCommand: 'go test ./...',
32
+ buildCommand: 'go build ./...',
33
+ };
34
+ },
35
+ };
36
+ //# sourceMappingURL=go.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"go.js","sourceRoot":"","sources":["../../../../src/cli/kraken/verificationAdapters/go.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,KAAK,UAAU,UAAU,CAAC,SAAiB;IACzC,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAwB;IAC5C,KAAK,CAAC,MAAM,CAAC,IAAY;QACvB,OAAO,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,OAAO;YACL,gBAAgB,EAAE,cAAc,EAAE,oCAAoC;YACtE,WAAW,EAAE,eAAe;YAC5B,YAAY,EAAE,gBAAgB;SAC/B,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { nodeAdapter } from './node.js';
2
+ import { pythonAdapter } from './python.js';
3
+ import { rustAdapter } from './rust.js';
4
+ import { goAdapter } from './go.js';
5
+ import { javaAdapter } from './java.js';
6
+ import { dotnetAdapter } from './dotnet.js';
7
+ export { nodeAdapter } from './node.js';
8
+ export { pythonAdapter } from './python.js';
9
+ export { rustAdapter } from './rust.js';
10
+ export { goAdapter } from './go.js';
11
+ export { javaAdapter } from './java.js';
12
+ export { dotnetAdapter } from './dotnet.js';
13
+ /** Ordered ecosystem adapters; see header for the tie-break contract. */
14
+ export const VERIFICATION_ADAPTERS = [
15
+ nodeAdapter,
16
+ pythonAdapter,
17
+ rustAdapter,
18
+ goAdapter,
19
+ javaAdapter,
20
+ dotnetAdapter,
21
+ ];
22
+ /**
23
+ * Highest-scoring adapter for `root` (ties → earlier registration), or null
24
+ * when no adapter applies (score ≤ 0 everywhere — e.g. an empty directory;
25
+ * env overrides alone still work then, see
26
+ * nativeVerification.resolvePackCommandsForRoot). A throwing `detect`
27
+ * (filesystem race) counts as not-applicable rather than aborting resolution.
28
+ */
29
+ export async function resolveAdapterForRoot(root) {
30
+ let best = null;
31
+ let bestScore = 0;
32
+ for (const adapter of VERIFICATION_ADAPTERS) {
33
+ let score;
34
+ try {
35
+ score = await adapter.detect(root);
36
+ }
37
+ catch {
38
+ continue;
39
+ }
40
+ if (score > bestScore) {
41
+ best = adapter;
42
+ bestScore = score;
43
+ }
44
+ }
45
+ return best;
46
+ }
47
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/kraken/verificationAdapters/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAI5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,yEAAyE;AACzE,MAAM,CAAC,MAAM,qBAAqB,GAAmC;IACnE,WAAW;IACX,aAAa;IACb,WAAW;IACX,SAAS;IACT,WAAW;IACX,aAAa;CACd,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,IAAY;IACtD,IAAI,IAAI,GAA+B,IAAI,CAAC;IAC5C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,OAAO,IAAI,qBAAqB,EAAE,CAAC;QAC5C,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,IAAI,GAAG,OAAO,CAAC;YACf,SAAS,GAAG,KAAK,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * verificationAdapters/java — JVM builds: Gradle and Maven (P1.A2 / t24).
3
+ *
4
+ * Ecosystem ownership: Gradle roots (wrapper script, build.gradle[.kts],
5
+ * settings.gradle[.kts]) and Maven roots (pom.xml). Gradle WINS over Maven
6
+ * when markers coexist: the wrapper scores above pom.xml, and the remaining
7
+ * tie (build.gradle 3 vs pom.xml 3) is resolved gradle-first inside
8
+ * buildPlan — detect's single score cannot express within-root precedence.
9
+ *
10
+ * Detect scores (highest present marker wins): gradlew / gradlew.bat = 4
11
+ * (a project-local toolchain is the strongest evidence), build.gradle /
12
+ * build.gradle.kts = 3, pom.xml = 3, settings.gradle[.kts] = 2. No markers
13
+ * → 0.
14
+ *
15
+ * Honest-unknown rule: Java has NO standalone typecheck verb — compilation
16
+ * is inlined into `gradle build` / the Maven lifecycle — so the typecheck
17
+ * slot binds null (dropped downstream) instead of a fabricated command that
18
+ * would misreport a missing tool as `fail`.
19
+ *
20
+ * Wrapper resolution: `./gradlew <verb>` on non-win32 when the `gradlew`
21
+ * file exists, `gradlew.bat <verb>` on win32 when the wrapper batch file
22
+ * exists, else bare `gradle <verb>` (PATH invocation). `platform` is
23
+ * injectable in gradleCommand (default process.platform) so both namings
24
+ * stay deterministically testable on any host.
25
+ */
26
+ import { stat } from 'node:fs/promises';
27
+ import path from 'node:path';
28
+ /** Tiny fs helpers stay LOCAL per adapter (shared utils would couple sibling adapters). */
29
+ async function fileExists(candidate) {
30
+ try {
31
+ return (await stat(candidate)).isFile();
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /** Gradle markers, strongest first (see header). */
38
+ const GRADLE_MARKERS = [
39
+ ['gradlew', 4],
40
+ ['gradlew.bat', 4],
41
+ ['build.gradle', 3],
42
+ ['build.gradle.kts', 3],
43
+ ['settings.gradle', 2],
44
+ ['settings.gradle.kts', 2],
45
+ ];
46
+ /** Full detection set: every gradle marker plus Maven's pom.xml (3). */
47
+ const DETECT_MARKERS = [
48
+ ...GRADLE_MARKERS,
49
+ ['pom.xml', 3],
50
+ ];
51
+ async function hasGradleMarker(root) {
52
+ for (const [marker] of GRADLE_MARKERS) {
53
+ if (await fileExists(path.join(root, marker)))
54
+ return true;
55
+ }
56
+ return false;
57
+ }
58
+ /**
59
+ * Gradle invocation for `verb` at `root`: the platform-appropriate wrapper
60
+ * when its file exists, else bare `gradle` (PATH). Exported (unlike sibling
61
+ * helpers) so tests can drive BOTH platform branches deterministically;
62
+ * buildPlan passes process.platform.
63
+ */
64
+ export async function gradleCommand(root, verb, platform = process.platform) {
65
+ const wrapper = platform === 'win32' ? 'gradlew.bat' : 'gradlew';
66
+ if (await fileExists(path.join(root, wrapper))) {
67
+ return platform === 'win32' ? `gradlew.bat ${verb}` : `./gradlew ${verb}`;
68
+ }
69
+ return `gradle ${verb}`;
70
+ }
71
+ export const javaAdapter = {
72
+ async detect(root) {
73
+ let best = 0;
74
+ for (const [marker, score] of DETECT_MARKERS) {
75
+ if (score > best && (await fileExists(path.join(root, marker))))
76
+ best = score;
77
+ }
78
+ return best;
79
+ },
80
+ async buildPlan(root) {
81
+ // Gradle-first precedence — see header. detect cannot encode the
82
+ // build.gradle(3) vs pom.xml(3) tie, so buildPlan decides.
83
+ if (await hasGradleMarker(root)) {
84
+ return {
85
+ typecheckCommand: null, // no standalone verb — honest absence
86
+ testCommand: await gradleCommand(root, 'test'),
87
+ buildCommand: await gradleCommand(root, 'build'),
88
+ };
89
+ }
90
+ if (await fileExists(path.join(root, 'pom.xml'))) {
91
+ return {
92
+ typecheckCommand: null, // compilation rides the test/package lifecycle
93
+ testCommand: 'mvn test',
94
+ buildCommand: 'mvn package',
95
+ };
96
+ }
97
+ // Defensive (the registry never calls buildPlan on a 0-score root):
98
+ // all-null, never fabricated.
99
+ return { typecheckCommand: null, testCommand: null, buildCommand: null };
100
+ },
101
+ };
102
+ //# sourceMappingURL=java.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"java.js","sourceRoot":"","sources":["../../../../src/cli/kraken/verificationAdapters/java.ts"],"names":[],"mappings":"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"}