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.
- package/dist/cli/headless/policyGate.js +101 -0
- package/dist/cli/headless/policyGate.js.map +1 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/kraken/completionProof.js +89 -41
- package/dist/cli/kraken/completionProof.js.map +1 -1
- package/dist/cli/kraken/completionProofAttestation.js +157 -0
- package/dist/cli/kraken/completionProofAttestation.js.map +1 -0
- package/dist/cli/kraken/completionProofPersist.js +219 -0
- package/dist/cli/kraken/completionProofPersist.js.map +1 -0
- package/dist/cli/kraken/completionProofProbe.js +135 -0
- package/dist/cli/kraken/completionProofProbe.js.map +1 -0
- package/dist/cli/kraken/contractCompiler.js +142 -0
- package/dist/cli/kraken/contractCompiler.js.map +1 -0
- package/dist/cli/kraken/delegationPolicy.js +40 -3
- package/dist/cli/kraken/delegationPolicy.js.map +1 -1
- package/dist/cli/kraken/executor.js +462 -9
- package/dist/cli/kraken/executor.js.map +1 -1
- package/dist/cli/kraken/fileOwnership.js +190 -0
- package/dist/cli/kraken/fileOwnership.js.map +1 -0
- package/dist/cli/kraken/modelReputation.js +208 -0
- package/dist/cli/kraken/modelReputation.js.map +1 -0
- package/dist/cli/kraken/nativeVerification.js +53 -11
- package/dist/cli/kraken/nativeVerification.js.map +1 -1
- package/dist/cli/kraken/planner.js +2 -0
- package/dist/cli/kraken/planner.js.map +1 -1
- package/dist/cli/kraken/reputationStore.js +139 -0
- package/dist/cli/kraken/reputationStore.js.map +1 -0
- package/dist/cli/kraken/semanticOwnership.js +184 -0
- package/dist/cli/kraken/semanticOwnership.js.map +1 -0
- package/dist/cli/kraken/spawnRoi.js +209 -0
- package/dist/cli/kraken/spawnRoi.js.map +1 -0
- package/dist/cli/kraken/transactional.js +104 -0
- package/dist/cli/kraken/transactional.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/dotnet.js +49 -0
- package/dist/cli/kraken/verificationAdapters/dotnet.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/go.js +36 -0
- package/dist/cli/kraken/verificationAdapters/go.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/index.js +47 -0
- package/dist/cli/kraken/verificationAdapters/index.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/java.js +102 -0
- package/dist/cli/kraken/verificationAdapters/java.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/node.js +90 -0
- package/dist/cli/kraken/verificationAdapters/node.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/python.js +86 -0
- package/dist/cli/kraken/verificationAdapters/python.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/rust.js +39 -0
- package/dist/cli/kraken/verificationAdapters/rust.js.map +1 -0
- package/dist/cli/kraken/verificationAdapters/types.js +2 -0
- package/dist/cli/kraken/verificationAdapters/types.js.map +1 -0
- package/dist/cli/kraken/verificationBridge.js +40 -3
- package/dist/cli/kraken/verificationBridge.js.map +1 -1
- package/dist/cli/kraken/verifierLifecycle.js +51 -36
- package/dist/cli/kraken/verifierLifecycle.js.map +1 -1
- package/dist/cli/kraken/verifierRouting.js +264 -0
- package/dist/cli/kraken/verifierRouting.js.map +1 -0
- package/dist/cli/kraken/worktreeScheduling.js +201 -0
- package/dist/cli/kraken/worktreeScheduling.js.map +1 -0
- package/dist/cli/main.bundled.js +3880 -889
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/orchestration/facts.js +127 -0
- package/dist/cli/orchestration/facts.js.map +1 -0
- package/dist/cli/orchestration/policy.js +128 -75
- package/dist/cli/orchestration/policy.js.map +1 -1
- package/dist/cli/orchestration/signals.js +96 -0
- package/dist/cli/orchestration/signals.js.map +1 -0
- package/dist/cli/runHeadless.js +92 -19
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/safety/policyEngine.js +159 -20
- package/dist/cli/safety/policyEngine.js.map +1 -1
- package/dist/cli/safety/policyLoadMode.js +59 -0
- package/dist/cli/safety/policyLoadMode.js.map +1 -0
- package/dist/cli/safety/resourceClaims.js +373 -0
- package/dist/cli/safety/resourceClaims.js.map +1 -0
- package/dist/cli/safety/sandboxPath.js +160 -17
- package/dist/cli/safety/sandboxPath.js.map +1 -1
- package/dist/cli/toolRegistry.js +98 -8
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/execProcess.js +121 -0
- package/dist/cli/tools/execProcess.js.map +1 -0
- package/dist/cli/tools/krakenRadio.js +9 -0
- package/dist/cli/tools/krakenRadio.js.map +1 -1
- package/dist/cli/tools/taskTool.js +8 -3
- package/dist/cli/tools/taskTool.js.map +1 -1
- 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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"}
|