zelari-code 2.37.3 → 2.39.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/asyncLimit.js +53 -0
- package/dist/cli/asyncLimit.js.map +1 -0
- package/dist/cli/budget/restoreRuntime.js +10 -5
- package/dist/cli/budget/restoreRuntime.js.map +1 -1
- package/dist/cli/crossProviderFailover.js +32 -0
- package/dist/cli/crossProviderFailover.js.map +1 -1
- package/dist/cli/harnessState.js +7 -3
- package/dist/cli/harnessState.js.map +1 -1
- package/dist/cli/headlessSpine.js +7 -3
- package/dist/cli/headlessSpine.js.map +1 -1
- package/dist/cli/kraken/cachedShell.js +162 -0
- package/dist/cli/kraken/cachedShell.js.map +1 -0
- package/dist/cli/kraken/contractCompiler.js +6 -1
- package/dist/cli/kraken/contractCompiler.js.map +1 -1
- package/dist/cli/kraken/executor.js +131 -27
- package/dist/cli/kraken/executor.js.map +1 -1
- package/dist/cli/kraken/exploreCoverage.js +201 -0
- package/dist/cli/kraken/exploreCoverage.js.map +1 -0
- package/dist/cli/kraken/exploreFlipGate.js +197 -0
- package/dist/cli/kraken/exploreFlipGate.js.map +1 -0
- package/dist/cli/kraken/nativeVerification.js +9 -1
- package/dist/cli/kraken/nativeVerification.js.map +1 -1
- package/dist/cli/kraken/planner.js.map +1 -1
- package/dist/cli/kraken/verifyReask.js +134 -0
- package/dist/cli/kraken/verifyReask.js.map +1 -0
- package/dist/cli/kraken/worktreeCleanupBatch.js +110 -0
- package/dist/cli/kraken/worktreeCleanupBatch.js.map +1 -0
- package/dist/cli/main.bundled.js +1909 -876
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/memory/legacyImport.js +66 -14
- package/dist/cli/memory/legacyImport.js.map +1 -1
- package/dist/cli/memory/sqliteBackend.js +19 -5
- package/dist/cli/memory/sqliteBackend.js.map +1 -1
- package/dist/cli/providerFailover.js +21 -2
- package/dist/cli/providerFailover.js.map +1 -1
- package/dist/cli/runHeadless.js +32 -1
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/sessionSpine.js +26 -10
- package/dist/cli/sessionSpine.js.map +1 -1
- package/dist/cli/toolRegistry.js +23 -4
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/tools/krakenModel.js +72 -9
- package/dist/cli/tools/krakenModel.js.map +1 -1
- package/dist/cli/tools/krakenRadio.js +60 -3
- package/dist/cli/tools/krakenRadio.js.map +1 -1
- package/dist/cli/tools/krakenWorktree.js +105 -4
- package/dist/cli/tools/krakenWorktree.js.map +1 -1
- package/dist/cli/tools/taskTool.js +22 -0
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/dist/cli/zelariMission.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verifyReask — t56: minimal one-shot re-ask for an `unknown` verify verdict.
|
|
3
|
+
*
|
|
4
|
+
* Problem
|
|
5
|
+
* -------
|
|
6
|
+
* When a reviewer's reply has no parseable verdict trailer, the executor
|
|
7
|
+
* records the node as `unresolved` (reason 'unknown') and moves on — correct
|
|
8
|
+
* per "unknown ≠ pass", but expensive in one specific way: the verdict was
|
|
9
|
+
* almost certainly FORMULATED in the reply and only the trailer line got
|
|
10
|
+
* mangled by prompt drift. Re-running the whole verify sub-agent pays a
|
|
11
|
+
* second full review for one missing line.
|
|
12
|
+
*
|
|
13
|
+
* What this module does instead
|
|
14
|
+
* -----------------------------
|
|
15
|
+
* A single non-streaming chat completion, no tools, against the same
|
|
16
|
+
* provider channel the CLI already uses (same resolution as the weakness
|
|
17
|
+
* meter): hand the model its own prior output (tail-capped) and ask it to
|
|
18
|
+
* emit ONLY the trailer it already supports. The reply is parsed with the
|
|
19
|
+
* SAME single-source parser as the original verdict (`parseVerifyVerdict`
|
|
20
|
+
* from @zelari/core) — no second grammar to drift.
|
|
21
|
+
*
|
|
22
|
+
* Guarantees:
|
|
23
|
+
* - capped at ONE call per unknown verdict (the caller enforces this);
|
|
24
|
+
* - default ON, opt-out via ZELARI_KRAKEN_VERIFY_REASK=0;
|
|
25
|
+
* - any failure (disabled, no key, HTTP error, unparseable reply)
|
|
26
|
+
* returns null and the existing unknown-flow is unchanged;
|
|
27
|
+
* - the verify node's raw `result` is NEVER rewritten by this module —
|
|
28
|
+
* audit sees what the reviewer actually emitted.
|
|
29
|
+
*
|
|
30
|
+
* Pattern follows `./weaknessMeter.ts` (provider resolution, timeout,
|
|
31
|
+
* silent failure). No I/O at import time.
|
|
32
|
+
*
|
|
33
|
+
* @since v2.x — t56 re-ask minimal su verdetto unknown
|
|
34
|
+
*/
|
|
35
|
+
import { parseVerifyVerdict } from '@zelari/core';
|
|
36
|
+
import { getProviderConfig, getModelForProvider, getCustomEndpoint } from '../providerConfig.js';
|
|
37
|
+
import { resolveApiKeyWithMeta } from '../keyStore.js';
|
|
38
|
+
/** Env flag. Default ON ('0' | 'false' | 'no' disables). */
|
|
39
|
+
export const VERIFY_REASK_ENV = 'ZELARI_KRAKEN_VERIFY_REASK';
|
|
40
|
+
/** Wall-clock budget for the single re-ask call. */
|
|
41
|
+
const REASK_TIMEOUT_MS = 12_000;
|
|
42
|
+
/** How much of the prior verify output we forward (trailer lives at the end). */
|
|
43
|
+
const PRIOR_OUTPUT_CAP_CHARS = 8_000;
|
|
44
|
+
const REASK_SYSTEM_PROMPT = [
|
|
45
|
+
'You are a verdict-normalization helper.',
|
|
46
|
+
'The message below is a code-review verify report whose final verdict trailer line is missing or malformed.',
|
|
47
|
+
'Re-read the report and emit, as the LAST line, ONLY the verdict the report already supports:',
|
|
48
|
+
'`VERDICT: PASS` or `VERDICT: FAIL`.',
|
|
49
|
+
'Do not re-review the work, do not add commentary.',
|
|
50
|
+
'If the report genuinely supports neither verdict, emit `VERDICT: UNKNOWN`.',
|
|
51
|
+
].join(' ');
|
|
52
|
+
/**
|
|
53
|
+
* Whether the re-ask is enabled. Cheap; read per call (no memoization —
|
|
54
|
+
* unlike the weakness meter this is not on a hot path).
|
|
55
|
+
*/
|
|
56
|
+
export function isVerifyReaskEnabled(env = process.env) {
|
|
57
|
+
const raw = env[VERIFY_REASK_ENV];
|
|
58
|
+
if (raw === undefined || raw === '')
|
|
59
|
+
return true; // default ON
|
|
60
|
+
return !(raw === '0' || raw === 'false' || raw === 'no');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* One-shot trailer recovery. Returns `'pass' | 'fail'` when the model
|
|
64
|
+
* restated a usable verdict, `null` otherwise (disabled / failed /
|
|
65
|
+
* still unknown). Never throws.
|
|
66
|
+
*/
|
|
67
|
+
export async function reaskVerifyTrailer(priorOutput, options = {}) {
|
|
68
|
+
const env = options.env ?? process.env;
|
|
69
|
+
if (!isVerifyReaskEnabled(env))
|
|
70
|
+
return null;
|
|
71
|
+
if (typeof priorOutput !== 'string' || priorOutput.trim() === '')
|
|
72
|
+
return null;
|
|
73
|
+
const provider = options.providerOverride ?? (await resolveActiveProvider(env));
|
|
74
|
+
if (!provider)
|
|
75
|
+
return null;
|
|
76
|
+
// Tail-cap: the verdict trailer sits at the end of the report.
|
|
77
|
+
const capped = priorOutput.length > PRIOR_OUTPUT_CAP_CHARS
|
|
78
|
+
? priorOutput.slice(priorOutput.length - PRIOR_OUTPUT_CAP_CHARS)
|
|
79
|
+
: priorOutput;
|
|
80
|
+
try {
|
|
81
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
82
|
+
const ac = new AbortController();
|
|
83
|
+
const timer = setTimeout(() => ac.abort(), REASK_TIMEOUT_MS);
|
|
84
|
+
let response;
|
|
85
|
+
try {
|
|
86
|
+
response = await fetchImpl(provider.endpoint, {
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: {
|
|
89
|
+
'Content-Type': 'application/json',
|
|
90
|
+
Authorization: `Bearer ${provider.apiKey}`,
|
|
91
|
+
},
|
|
92
|
+
body: JSON.stringify({
|
|
93
|
+
model: provider.model,
|
|
94
|
+
messages: [
|
|
95
|
+
{ role: 'system', content: REASK_SYSTEM_PROMPT },
|
|
96
|
+
{ role: 'user', content: capped },
|
|
97
|
+
],
|
|
98
|
+
temperature: 0,
|
|
99
|
+
stream: false,
|
|
100
|
+
}),
|
|
101
|
+
signal: ac.signal,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
clearTimeout(timer);
|
|
106
|
+
}
|
|
107
|
+
if (!response.ok)
|
|
108
|
+
return null;
|
|
109
|
+
const json = (await response.json());
|
|
110
|
+
const raw = json.choices?.[0]?.message?.content;
|
|
111
|
+
if (typeof raw !== 'string')
|
|
112
|
+
return null;
|
|
113
|
+
// Same single-source parser as the executor — no second grammar.
|
|
114
|
+
const { verdict } = parseVerifyVerdict(raw);
|
|
115
|
+
return verdict === 'pass' || verdict === 'fail' ? verdict : null;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** Same on-disk provider resolution the weakness meter uses. */
|
|
122
|
+
async function resolveActiveProvider(env) {
|
|
123
|
+
const cfg = await getProviderConfig();
|
|
124
|
+
if (!cfg)
|
|
125
|
+
return null;
|
|
126
|
+
const providerId = cfg.activeProviderId;
|
|
127
|
+
const key = await resolveApiKeyWithMeta(providerId, env);
|
|
128
|
+
if (!key?.apiKey)
|
|
129
|
+
return null;
|
|
130
|
+
const model = getModelForProvider(providerId) ?? cfg.modelByProvider[providerId] ?? '';
|
|
131
|
+
const endpoint = getCustomEndpoint(providerId) ?? `https://api.openai.com/v1/chat/completions`;
|
|
132
|
+
return { providerId, model, endpoint, apiKey: key.apiKey };
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=verifyReask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verifyReask.js","sourceRoot":"","sources":["../../../src/cli/kraken/verifyReask.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* worktreeCleanupBatch — Int3c (plan v2 §7.3) cleanup policy + queue.
|
|
3
|
+
*
|
|
4
|
+
* The per-worktree git calls live in `tools/krakenWorktree.ts`; this module
|
|
5
|
+
* owns only the POLICY (`batch` vs `eager`) and the in-process QUEUE of
|
|
6
|
+
* repo-level cleanup that a run defers. Split out because krakenWorktree.ts is
|
|
7
|
+
* already at its size budget and the state here is unrelated to worktree
|
|
8
|
+
* creation/merging.
|
|
9
|
+
*
|
|
10
|
+
* Why defer anything: removing a worktree used to cost three git processes —
|
|
11
|
+
* `worktree remove --force` (must stay eager: the directory has to be free
|
|
12
|
+
* before the next writer, and a merge node may run right after), then
|
|
13
|
+
* `worktree prune`, then `branch -D <branch>`. Prune and branch deletion are
|
|
14
|
+
* idempotent, order-independent and invisible to the run, so inside a run
|
|
15
|
+
* scope they are coalesced into ONE `prune` + ONE `branch -D <list>` at the
|
|
16
|
+
* end of the run.
|
|
17
|
+
*
|
|
18
|
+
* Scope, not "always": `cleanupKrakenWorktree` only defers while a scope is
|
|
19
|
+
* open (`beginKrakenWorktreeCleanupBatch`). Outside one, nothing would ever
|
|
20
|
+
* drain the queue — a standalone `task` call would silently keep its branches
|
|
21
|
+
* — so cleanup stays eager there. The flag's default is still `batch`: every
|
|
22
|
+
* run that opens a scope defers, `ZELARI_KRAKEN_WORKTREE_CLEANUP=eager` opts
|
|
23
|
+
* out for all callers.
|
|
24
|
+
*
|
|
25
|
+
* Pure state + policy: no fs, no git, no clock. The caller does the spawning.
|
|
26
|
+
*
|
|
27
|
+
* @since v2.38.0 (Int3c)
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* `ZELARI_KRAKEN_WORKTREE_CLEANUP`, default `batch` (plan v2 §13):
|
|
31
|
+
*
|
|
32
|
+
* `batch` — inside a run scope, coalesce `worktree prune` + `branch -D` into
|
|
33
|
+
* ONE pair at the end of the run.
|
|
34
|
+
* `eager` — kill-switch: per-worktree `prune` + `branch -D`, exactly as
|
|
35
|
+
* before Int3c.
|
|
36
|
+
*
|
|
37
|
+
* An unrecognized value falls back to the default rather than to `eager`: a
|
|
38
|
+
* typo must not silently re-enable the extra subprocesses the slice removed.
|
|
39
|
+
*/
|
|
40
|
+
export function resolveWorktreeCleanupMode(env = process.env) {
|
|
41
|
+
const v = (env.ZELARI_KRAKEN_WORKTREE_CLEANUP ?? '').trim().toLowerCase();
|
|
42
|
+
if (v === 'eager')
|
|
43
|
+
return 'eager';
|
|
44
|
+
return 'batch';
|
|
45
|
+
}
|
|
46
|
+
/** repoRoot → the `worktree prune` it still owes (one per removed worktree). */
|
|
47
|
+
const pendingPruneRoots = new Set();
|
|
48
|
+
/** repoRoot → branches whose worktree is gone but whose branch is not. */
|
|
49
|
+
const pendingBranches = new Map();
|
|
50
|
+
/**
|
|
51
|
+
* Open run scopes. A counter (not a boolean) so two concurrent scopes — an
|
|
52
|
+
* executor run and, say, a nested one — cannot close each other's batch: each
|
|
53
|
+
* `begin` is matched by one `take`, and a take already drains the whole queue
|
|
54
|
+
* (deleting a queued branch earlier than "end of run" is only ever *more*
|
|
55
|
+
* eager, never wrong).
|
|
56
|
+
*/
|
|
57
|
+
let batchScopes = 0;
|
|
58
|
+
/** True when `cleanupKrakenWorktree` should defer instead of cleaning eagerly. */
|
|
59
|
+
export function isKrakenWorktreeCleanupBatched(env = process.env) {
|
|
60
|
+
return batchScopes > 0 && resolveWorktreeCleanupMode(env) === 'batch';
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Open the cleanup batch for a run. Returns whether deferral is active: false
|
|
64
|
+
* in `eager` mode (nothing is queued, so the caller has no flush to make).
|
|
65
|
+
*/
|
|
66
|
+
export function beginKrakenWorktreeCleanupBatch(env = process.env) {
|
|
67
|
+
if (resolveWorktreeCleanupMode(env) !== 'batch')
|
|
68
|
+
return false;
|
|
69
|
+
batchScopes += 1;
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Queue the repo-level half of one cleanup. Duplicates collapse: N worktrees
|
|
74
|
+
* of the same repo cost one prune, and a branch name is unique per worktree
|
|
75
|
+
* anyway (it embeds a timestamp + random id).
|
|
76
|
+
*/
|
|
77
|
+
export function queueWorktreeCleanup(repoRoot, branch) {
|
|
78
|
+
pendingPruneRoots.add(repoRoot);
|
|
79
|
+
if (!branch)
|
|
80
|
+
return;
|
|
81
|
+
const queued = pendingBranches.get(repoRoot) ?? new Set();
|
|
82
|
+
queued.add(branch);
|
|
83
|
+
pendingBranches.set(repoRoot, queued);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Close one scope and drain the queue. Draining clears the state, so a second
|
|
87
|
+
* drain in the same process returns empty work — the caller can issue no git
|
|
88
|
+
* command for it (an idle flush costs zero spawns).
|
|
89
|
+
*/
|
|
90
|
+
export function takeQueuedWorktreeCleanup() {
|
|
91
|
+
if (batchScopes > 0)
|
|
92
|
+
batchScopes -= 1;
|
|
93
|
+
const repoRoots = new Set([...pendingPruneRoots, ...pendingBranches.keys()]);
|
|
94
|
+
const branchesByRoot = new Map();
|
|
95
|
+
for (const repoRoot of repoRoots) {
|
|
96
|
+
const queued = pendingBranches.get(repoRoot);
|
|
97
|
+
if (queued && queued.size > 0)
|
|
98
|
+
branchesByRoot.set(repoRoot, [...queued]);
|
|
99
|
+
pendingPruneRoots.delete(repoRoot);
|
|
100
|
+
pendingBranches.delete(repoRoot);
|
|
101
|
+
}
|
|
102
|
+
return { repoRoots: [...repoRoots], branchesByRoot };
|
|
103
|
+
}
|
|
104
|
+
/** Test-only: drop the queue and any open scope. */
|
|
105
|
+
export function __resetKrakenWorktreeCleanupQueueForTests() {
|
|
106
|
+
pendingPruneRoots.clear();
|
|
107
|
+
pendingBranches.clear();
|
|
108
|
+
batchScopes = 0;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=worktreeCleanupBatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worktreeCleanupBatch.js","sourceRoot":"","sources":["../../../src/cli/kraken/worktreeCleanupBatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAKH;;;;;;;;;;GAUG;AACH,MAAM,UAAU,0BAA0B,CACxC,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,8BAA8B,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1E,IAAI,CAAC,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IAClC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gFAAgF;AAChF,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE5C,0EAA0E;AAC1E,MAAM,eAAe,GAAG,IAAI,GAAG,EAAuB,CAAC;AAEvD;;;;;;GAMG;AACH,IAAI,WAAW,GAAG,CAAC,CAAC;AAEpB,kFAAkF;AAClF,MAAM,UAAU,8BAA8B,CAC5C,MAAyB,OAAO,CAAC,GAAG;IAEpC,OAAO,WAAW,GAAG,CAAC,IAAI,0BAA0B,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,+BAA+B,CAC7C,MAAyB,OAAO,CAAC,GAAG;IAEpC,IAAI,0BAA0B,CAAC,GAAG,CAAC,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC9D,WAAW,IAAI,CAAC,CAAC;IACjB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,MAAqB;IAC1E,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;IAClE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACxC,CAAC;AAUD;;;;GAIG;AACH,MAAM,UAAU,yBAAyB;IACvC,IAAI,WAAW,GAAG,CAAC;QAAE,WAAW,IAAI,CAAC,CAAC;IAEtC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAS,CAAC,GAAG,iBAAiB,EAAE,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACrF,MAAM,cAAc,GAAG,IAAI,GAAG,EAAoB,CAAC;IACnD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC;YAAE,cAAc,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;QACzE,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACnC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,cAAc,EAAE,CAAC;AACvD,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,yCAAyC;IACvD,iBAAiB,CAAC,KAAK,EAAE,CAAC;IAC1B,eAAe,CAAC,KAAK,EAAE,CAAC;IACxB,WAAW,GAAG,CAAC,CAAC;AAClB,CAAC"}
|