zelari-code 1.29.0 → 1.30.1
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.js +14 -0
- package/dist/cli/headless.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +11 -0
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/kraken/executor.js +63 -1
- package/dist/cli/kraken/executor.js.map +1 -1
- package/dist/cli/kraken/planner.js +87 -2
- package/dist/cli/kraken/planner.js.map +1 -1
- package/dist/cli/kraken/planner.test.js +43 -0
- package/dist/cli/kraken/planner.test.js.map +1 -0
- package/dist/cli/kraken/runtime/compile.js +73 -0
- package/dist/cli/kraken/runtime/compile.js.map +1 -0
- package/dist/cli/kraken/runtime/runScriptPlan.js +195 -0
- package/dist/cli/kraken/runtime/runScriptPlan.js.map +1 -0
- package/dist/cli/kraken/scriptPlanner.js +286 -0
- package/dist/cli/kraken/scriptPlanner.js.map +1 -0
- package/dist/cli/kraken/scriptPlanner.test.js +152 -0
- package/dist/cli/kraken/scriptPlanner.test.js.map +1 -0
- package/dist/cli/kraken/skillSuggest.js +97 -0
- package/dist/cli/kraken/skillSuggest.js.map +1 -0
- package/dist/cli/kraken/skillSuggest.test.js +157 -0
- package/dist/cli/kraken/skillSuggest.test.js.map +1 -0
- package/dist/cli/kraken/weaknessMeter.js +183 -0
- package/dist/cli/kraken/weaknessMeter.js.map +1 -0
- package/dist/cli/kraken/weaknessMeter.test.js +212 -0
- package/dist/cli/kraken/weaknessMeter.test.js.map +1 -0
- package/dist/cli/kraken/workbench.js +296 -0
- package/dist/cli/kraken/workbench.js.map +1 -0
- package/dist/cli/kraken/workbench.test.js +253 -0
- package/dist/cli/kraken/workbench.test.js.map +1 -0
- package/dist/cli/kraken/workbenchView.js +155 -0
- package/dist/cli/kraken/workbenchView.js.map +1 -0
- package/dist/cli/kraken/workbenchView.test.js +130 -0
- package/dist/cli/kraken/workbenchView.test.js.map +1 -0
- package/dist/cli/main.bundled.js +2214 -299
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/runHeadless.js +58 -7
- package/dist/cli/runHeadless.js.map +1 -1
- package/dist/cli/slashCommands.js +16 -0
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/krakenFanout.js +200 -0
- package/dist/cli/slashHandlers/krakenFanout.js.map +1 -0
- package/dist/cli/slashHandlers/krakenWorkbench.js +49 -0
- package/dist/cli/slashHandlers/krakenWorkbench.js.map +1 -0
- package/dist/cli/tools/krakenCsvFanout.js +260 -0
- package/dist/cli/tools/krakenCsvFanout.js.map +1 -0
- package/dist/cli/tools/krakenCsvFanout.test.js +200 -0
- package/dist/cli/tools/krakenCsvFanout.test.js.map +1 -0
- package/dist/cli/tools/krakenModel.js +32 -0
- package/dist/cli/tools/krakenModel.js.map +1 -1
- package/dist/cli/tools/krakenRadio.js.map +1 -1
- package/dist/cli/tools/taskTool.js +1 -1
- package/dist/cli/tools/taskTool.js.map +1 -1
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -886,8 +886,8 @@ function loadModelsRegistry(file2 = getModelsFilePath()) {
|
|
|
886
886
|
}
|
|
887
887
|
}
|
|
888
888
|
function getCachedModels(provider, file2 = getModelsFilePath()) {
|
|
889
|
-
const
|
|
890
|
-
return
|
|
889
|
+
const registry4 = loadModelsRegistry(file2);
|
|
890
|
+
return registry4[provider];
|
|
891
891
|
}
|
|
892
892
|
function isModelsCacheStale(provider, maxAgeMs = 6 * 60 * 60 * 1e3, file2 = getModelsFilePath(), now = Date.now()) {
|
|
893
893
|
const entry = getCachedModels(provider, file2);
|
|
@@ -1829,10 +1829,10 @@ function mergeDefs(...defs) {
|
|
|
1829
1829
|
function cloneDef(schema) {
|
|
1830
1830
|
return mergeDefs(schema._zod.def);
|
|
1831
1831
|
}
|
|
1832
|
-
function getElementAtPath(obj,
|
|
1833
|
-
if (!
|
|
1832
|
+
function getElementAtPath(obj, path47) {
|
|
1833
|
+
if (!path47)
|
|
1834
1834
|
return obj;
|
|
1835
|
-
return
|
|
1835
|
+
return path47.reduce((acc, key) => acc?.[key], obj);
|
|
1836
1836
|
}
|
|
1837
1837
|
function promiseAllObject(promisesObj) {
|
|
1838
1838
|
const keys = Object.keys(promisesObj);
|
|
@@ -2160,11 +2160,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
2160
2160
|
}
|
|
2161
2161
|
return false;
|
|
2162
2162
|
}
|
|
2163
|
-
function prefixIssues(
|
|
2163
|
+
function prefixIssues(path47, issues) {
|
|
2164
2164
|
return issues.map((iss) => {
|
|
2165
2165
|
var _a3;
|
|
2166
2166
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
2167
|
-
iss.path.unshift(
|
|
2167
|
+
iss.path.unshift(path47);
|
|
2168
2168
|
return iss;
|
|
2169
2169
|
});
|
|
2170
2170
|
}
|
|
@@ -2382,16 +2382,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2382
2382
|
}
|
|
2383
2383
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
2384
2384
|
const fieldErrors = { _errors: [] };
|
|
2385
|
-
const processError = (error52,
|
|
2385
|
+
const processError = (error52, path47 = []) => {
|
|
2386
2386
|
for (const issue2 of error52.issues) {
|
|
2387
2387
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2388
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2388
|
+
issue2.errors.map((issues) => processError({ issues }, [...path47, ...issue2.path]));
|
|
2389
2389
|
} else if (issue2.code === "invalid_key") {
|
|
2390
|
-
processError({ issues: issue2.issues }, [...
|
|
2390
|
+
processError({ issues: issue2.issues }, [...path47, ...issue2.path]);
|
|
2391
2391
|
} else if (issue2.code === "invalid_element") {
|
|
2392
|
-
processError({ issues: issue2.issues }, [...
|
|
2392
|
+
processError({ issues: issue2.issues }, [...path47, ...issue2.path]);
|
|
2393
2393
|
} else {
|
|
2394
|
-
const fullpath = [...
|
|
2394
|
+
const fullpath = [...path47, ...issue2.path];
|
|
2395
2395
|
if (fullpath.length === 0) {
|
|
2396
2396
|
fieldErrors._errors.push(mapper(issue2));
|
|
2397
2397
|
} else {
|
|
@@ -2418,17 +2418,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2418
2418
|
}
|
|
2419
2419
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
2420
2420
|
const result = { errors: [] };
|
|
2421
|
-
const processError = (error52,
|
|
2421
|
+
const processError = (error52, path47 = []) => {
|
|
2422
2422
|
var _a3, _b;
|
|
2423
2423
|
for (const issue2 of error52.issues) {
|
|
2424
2424
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
2425
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
2425
|
+
issue2.errors.map((issues) => processError({ issues }, [...path47, ...issue2.path]));
|
|
2426
2426
|
} else if (issue2.code === "invalid_key") {
|
|
2427
|
-
processError({ issues: issue2.issues }, [...
|
|
2427
|
+
processError({ issues: issue2.issues }, [...path47, ...issue2.path]);
|
|
2428
2428
|
} else if (issue2.code === "invalid_element") {
|
|
2429
|
-
processError({ issues: issue2.issues }, [...
|
|
2429
|
+
processError({ issues: issue2.issues }, [...path47, ...issue2.path]);
|
|
2430
2430
|
} else {
|
|
2431
|
-
const fullpath = [...
|
|
2431
|
+
const fullpath = [...path47, ...issue2.path];
|
|
2432
2432
|
if (fullpath.length === 0) {
|
|
2433
2433
|
result.errors.push(mapper(issue2));
|
|
2434
2434
|
continue;
|
|
@@ -2460,8 +2460,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
2460
2460
|
}
|
|
2461
2461
|
function toDotPath(_path) {
|
|
2462
2462
|
const segs = [];
|
|
2463
|
-
const
|
|
2464
|
-
for (const seg of
|
|
2463
|
+
const path47 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
2464
|
+
for (const seg of path47) {
|
|
2465
2465
|
if (typeof seg === "number")
|
|
2466
2466
|
segs.push(`[${seg}]`);
|
|
2467
2467
|
else if (typeof seg === "symbol")
|
|
@@ -13342,21 +13342,21 @@ var init_to_json_schema = __esm({
|
|
|
13342
13342
|
// node_modules/zod/v4/core/json-schema-processors.js
|
|
13343
13343
|
function toJSONSchema(input, params) {
|
|
13344
13344
|
if ("_idmap" in input) {
|
|
13345
|
-
const
|
|
13345
|
+
const registry4 = input;
|
|
13346
13346
|
const ctx2 = initializeContext({ ...params, processors: allProcessors });
|
|
13347
13347
|
const defs = {};
|
|
13348
|
-
for (const entry of
|
|
13348
|
+
for (const entry of registry4._idmap.entries()) {
|
|
13349
13349
|
const [_, schema] = entry;
|
|
13350
13350
|
process2(schema, ctx2);
|
|
13351
13351
|
}
|
|
13352
13352
|
const schemas = {};
|
|
13353
13353
|
const external = {
|
|
13354
|
-
registry:
|
|
13354
|
+
registry: registry4,
|
|
13355
13355
|
uri: params?.uri,
|
|
13356
13356
|
defs
|
|
13357
13357
|
};
|
|
13358
13358
|
ctx2.external = external;
|
|
13359
|
-
for (const entry of
|
|
13359
|
+
for (const entry of registry4._idmap.entries()) {
|
|
13360
13360
|
const [key, schema] = entry;
|
|
13361
13361
|
extractDefs(ctx2, schema);
|
|
13362
13362
|
schemas[key] = finalize(ctx2, schema);
|
|
@@ -15964,13 +15964,13 @@ function resolveRef(ref, ctx) {
|
|
|
15964
15964
|
if (!ref.startsWith("#")) {
|
|
15965
15965
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
15966
15966
|
}
|
|
15967
|
-
const
|
|
15968
|
-
if (
|
|
15967
|
+
const path47 = ref.slice(1).split("/").filter(Boolean);
|
|
15968
|
+
if (path47.length === 0) {
|
|
15969
15969
|
return ctx.rootSchema;
|
|
15970
15970
|
}
|
|
15971
15971
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
15972
|
-
if (
|
|
15973
|
-
const key =
|
|
15972
|
+
if (path47[0] === defsKey) {
|
|
15973
|
+
const key = path47[1];
|
|
15974
15974
|
if (!key || !ctx.defs[key]) {
|
|
15975
15975
|
throw new Error(`Reference not found: ${ref}`);
|
|
15976
15976
|
}
|
|
@@ -18134,11 +18134,11 @@ var init_tools = __esm({
|
|
|
18134
18134
|
if (!ctx.addDocument)
|
|
18135
18135
|
return "Knowledge vault tool not available.";
|
|
18136
18136
|
const title = args["title"] || "New Document";
|
|
18137
|
-
const
|
|
18137
|
+
const path47 = args["path"] || `notes/${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
18138
18138
|
const content = args["content"] || "";
|
|
18139
18139
|
const tags = args["tags"] || [];
|
|
18140
18140
|
ctx.addDocument({
|
|
18141
|
-
path:
|
|
18141
|
+
path: path47,
|
|
18142
18142
|
title,
|
|
18143
18143
|
content,
|
|
18144
18144
|
format: "markdown",
|
|
@@ -18147,7 +18147,7 @@ var init_tools = __esm({
|
|
|
18147
18147
|
workspaceId: ctx.workspaceId
|
|
18148
18148
|
});
|
|
18149
18149
|
ctx.addActivity("vault", "created document", title);
|
|
18150
|
-
return `Document "${title}" created at "${
|
|
18150
|
+
return `Document "${title}" created at "${path47}".`;
|
|
18151
18151
|
}
|
|
18152
18152
|
}
|
|
18153
18153
|
];
|
|
@@ -18922,10 +18922,10 @@ function computeAgentTools(agent, aiConfig) {
|
|
|
18922
18922
|
}
|
|
18923
18923
|
return merged;
|
|
18924
18924
|
}
|
|
18925
|
-
function getToolDescriptions(toolNames,
|
|
18925
|
+
function getToolDescriptions(toolNames, registry4) {
|
|
18926
18926
|
const lines = ["AVAILABLE TOOLS (use ONLY these exact names):"];
|
|
18927
18927
|
for (const name of toolNames) {
|
|
18928
|
-
const tool =
|
|
18928
|
+
const tool = registry4.get(name);
|
|
18929
18929
|
if (!tool)
|
|
18930
18930
|
continue;
|
|
18931
18931
|
let paramList;
|
|
@@ -18952,7 +18952,7 @@ function buildSystemPromptSplit(agent, options) {
|
|
|
18952
18952
|
includeWorkspaceInPrompt = true,
|
|
18953
18953
|
durableStateContext
|
|
18954
18954
|
} = options;
|
|
18955
|
-
const
|
|
18955
|
+
const registry4 = new Map(tools.map((t) => [t.name, t]));
|
|
18956
18956
|
const skills = computeAgentSkills(agent, aiConfig);
|
|
18957
18957
|
const baseModules = getBasePromptModules(mode).filter((m) => !m.conditional || m.conditional(skills));
|
|
18958
18958
|
const customModulesRaw = aiConfig?.customPromptModules ?? [];
|
|
@@ -18987,7 +18987,7 @@ ${projectInstructions.trim()}`);
|
|
|
18987
18987
|
` + skills.map((s) => `## ${s.name}
|
|
18988
18988
|
${s.systemPromptFragment}`).join("\n\n"));
|
|
18989
18989
|
}
|
|
18990
|
-
const toolBlock = getToolDescriptions(toolNames,
|
|
18990
|
+
const toolBlock = getToolDescriptions(toolNames, registry4);
|
|
18991
18991
|
if (toolNames.length > 0) {
|
|
18992
18992
|
stableParts.push(`# Tools
|
|
18993
18993
|
|
|
@@ -19619,6 +19619,48 @@ var init_krakenLive = __esm({
|
|
|
19619
19619
|
});
|
|
19620
19620
|
|
|
19621
19621
|
// packages/core/dist/shared/events.js
|
|
19622
|
+
function isBrainAgentStartEvent(e) {
|
|
19623
|
+
return e.type === "agent_start";
|
|
19624
|
+
}
|
|
19625
|
+
function isBrainAgentEndEvent(e) {
|
|
19626
|
+
return e.type === "agent_end";
|
|
19627
|
+
}
|
|
19628
|
+
function isBrainMessageStartEvent(e) {
|
|
19629
|
+
return e.type === "message_start";
|
|
19630
|
+
}
|
|
19631
|
+
function isBrainMessageDeltaEvent(e) {
|
|
19632
|
+
return e.type === "message_delta";
|
|
19633
|
+
}
|
|
19634
|
+
function isBrainMessageEndEvent(e) {
|
|
19635
|
+
return e.type === "message_end";
|
|
19636
|
+
}
|
|
19637
|
+
function isBrainThinkingDeltaEvent(e) {
|
|
19638
|
+
return e.type === "thinking_delta";
|
|
19639
|
+
}
|
|
19640
|
+
function isBrainToolExecutionStartEvent(e) {
|
|
19641
|
+
return e.type === "tool_execution_start";
|
|
19642
|
+
}
|
|
19643
|
+
function isBrainToolExecutionUpdateEvent(e) {
|
|
19644
|
+
return e.type === "tool_execution_update";
|
|
19645
|
+
}
|
|
19646
|
+
function isBrainToolExecutionEndEvent(e) {
|
|
19647
|
+
return e.type === "tool_execution_end";
|
|
19648
|
+
}
|
|
19649
|
+
function isBrainQueueUpdateEvent(e) {
|
|
19650
|
+
return e.type === "queue_update";
|
|
19651
|
+
}
|
|
19652
|
+
function isBrainSessionCompactedEvent(e) {
|
|
19653
|
+
return e.type === "session_compacted";
|
|
19654
|
+
}
|
|
19655
|
+
function isBrainErrorEvent(e) {
|
|
19656
|
+
return e.type === "error";
|
|
19657
|
+
}
|
|
19658
|
+
function isBrainMemberCostEvent(e) {
|
|
19659
|
+
return e.type === "member_cost";
|
|
19660
|
+
}
|
|
19661
|
+
function isBrainCouncilModeEvent(e) {
|
|
19662
|
+
return e.type === "council_mode";
|
|
19663
|
+
}
|
|
19622
19664
|
function createBrainEvent(type, sessionId, data) {
|
|
19623
19665
|
return {
|
|
19624
19666
|
type,
|
|
@@ -19635,9 +19677,90 @@ var init_events = __esm({
|
|
|
19635
19677
|
});
|
|
19636
19678
|
|
|
19637
19679
|
// packages/core/dist/shared/eventBus.js
|
|
19680
|
+
var EventBus;
|
|
19638
19681
|
var init_eventBus = __esm({
|
|
19639
19682
|
"packages/core/dist/shared/eventBus.js"() {
|
|
19640
19683
|
"use strict";
|
|
19684
|
+
EventBus = class {
|
|
19685
|
+
/** Per-type subscriber registry. */
|
|
19686
|
+
subscribers;
|
|
19687
|
+
/** Wildcard subscribers (receive every event). */
|
|
19688
|
+
wildcardSubscribers;
|
|
19689
|
+
constructor() {
|
|
19690
|
+
this.subscribers = /* @__PURE__ */ new Map();
|
|
19691
|
+
this.wildcardSubscribers = /* @__PURE__ */ new Set();
|
|
19692
|
+
}
|
|
19693
|
+
/** Subscribe to a specific event type. Returns an unsubscribe function. */
|
|
19694
|
+
subscribe(type, handler) {
|
|
19695
|
+
let set2 = this.subscribers.get(type);
|
|
19696
|
+
if (!set2) {
|
|
19697
|
+
set2 = /* @__PURE__ */ new Set();
|
|
19698
|
+
this.subscribers.set(type, set2);
|
|
19699
|
+
}
|
|
19700
|
+
const stored = handler;
|
|
19701
|
+
set2.add(stored);
|
|
19702
|
+
return () => {
|
|
19703
|
+
const current = this.subscribers.get(type);
|
|
19704
|
+
if (!current)
|
|
19705
|
+
return;
|
|
19706
|
+
current.delete(stored);
|
|
19707
|
+
if (current.size === 0)
|
|
19708
|
+
this.subscribers.delete(type);
|
|
19709
|
+
};
|
|
19710
|
+
}
|
|
19711
|
+
/** Subscribe to all events. Returns an unsubscribe function. */
|
|
19712
|
+
subscribeAll(handler) {
|
|
19713
|
+
this.wildcardSubscribers.add(handler);
|
|
19714
|
+
return () => {
|
|
19715
|
+
this.wildcardSubscribers.delete(handler);
|
|
19716
|
+
};
|
|
19717
|
+
}
|
|
19718
|
+
/**
|
|
19719
|
+
* Emit an event to all matching subscribers (typed first, then wildcard).
|
|
19720
|
+
* Errors in individual subscribers are logged but do not prevent other
|
|
19721
|
+
* subscribers from receiving the event.
|
|
19722
|
+
*/
|
|
19723
|
+
emit(event) {
|
|
19724
|
+
const set2 = this.subscribers.get(event.type);
|
|
19725
|
+
if (set2) {
|
|
19726
|
+
for (const handler of set2)
|
|
19727
|
+
this.dispatch(handler, event);
|
|
19728
|
+
}
|
|
19729
|
+
for (const handler of this.wildcardSubscribers)
|
|
19730
|
+
this.dispatch(handler, event);
|
|
19731
|
+
}
|
|
19732
|
+
/** Remove all subscribers (typed + wildcard). */
|
|
19733
|
+
clear() {
|
|
19734
|
+
this.subscribers.clear();
|
|
19735
|
+
this.wildcardSubscribers.clear();
|
|
19736
|
+
}
|
|
19737
|
+
/**
|
|
19738
|
+
* Number of subscribers. With a `type`, returns typed subscribers for that
|
|
19739
|
+
* type; without, returns the total across all types plus wildcard handlers.
|
|
19740
|
+
*/
|
|
19741
|
+
listenerCount(type) {
|
|
19742
|
+
if (type !== void 0) {
|
|
19743
|
+
return this.subscribers.get(type)?.size ?? 0;
|
|
19744
|
+
}
|
|
19745
|
+
let total = this.wildcardSubscribers.size;
|
|
19746
|
+
for (const set2 of this.subscribers.values())
|
|
19747
|
+
total += set2.size;
|
|
19748
|
+
return total;
|
|
19749
|
+
}
|
|
19750
|
+
/** Invoke a single subscriber, isolating sync throws and async rejections. */
|
|
19751
|
+
dispatch(handler, event) {
|
|
19752
|
+
try {
|
|
19753
|
+
const result = handler(event);
|
|
19754
|
+
if (result instanceof Promise) {
|
|
19755
|
+
result.catch((err) => {
|
|
19756
|
+
console.error("[eventBus] subscriber error:", err);
|
|
19757
|
+
});
|
|
19758
|
+
}
|
|
19759
|
+
} catch (err) {
|
|
19760
|
+
console.error("[eventBus] subscriber error:", err);
|
|
19761
|
+
}
|
|
19762
|
+
}
|
|
19763
|
+
};
|
|
19641
19764
|
}
|
|
19642
19765
|
});
|
|
19643
19766
|
|
|
@@ -19658,6 +19781,14 @@ var init_context = __esm({
|
|
|
19658
19781
|
});
|
|
19659
19782
|
|
|
19660
19783
|
// packages/core/dist/types/systemTypes.js
|
|
19784
|
+
function createDefaultSystemPromptConfig() {
|
|
19785
|
+
return {
|
|
19786
|
+
enabledSkills: [],
|
|
19787
|
+
enabledTools: [],
|
|
19788
|
+
customPromptModules: [],
|
|
19789
|
+
agentSkillConfigs: []
|
|
19790
|
+
};
|
|
19791
|
+
}
|
|
19661
19792
|
var init_systemTypes = __esm({
|
|
19662
19793
|
"packages/core/dist/types/systemTypes.js"() {
|
|
19663
19794
|
"use strict";
|
|
@@ -21839,11 +21970,11 @@ var init_synthesisAudit = __esm({
|
|
|
21839
21970
|
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
|
|
21840
21971
|
import { join as join2 } from "node:path";
|
|
21841
21972
|
function loadNfrSpec(zelariRoot) {
|
|
21842
|
-
const
|
|
21843
|
-
if (!existsSync6(
|
|
21973
|
+
const path47 = join2(zelariRoot, "nfr-spec.json");
|
|
21974
|
+
if (!existsSync6(path47))
|
|
21844
21975
|
return null;
|
|
21845
21976
|
try {
|
|
21846
|
-
const raw = JSON.parse(readFileSync5(
|
|
21977
|
+
const raw = JSON.parse(readFileSync5(path47, "utf8"));
|
|
21847
21978
|
if (raw.version !== 1 || !Array.isArray(raw.targets))
|
|
21848
21979
|
return null;
|
|
21849
21980
|
return raw;
|
|
@@ -24149,9 +24280,9 @@ var init_types3 = __esm({
|
|
|
24149
24280
|
import { readFileSync as readFileSync10 } from "node:fs";
|
|
24150
24281
|
import { join as join8 } from "node:path";
|
|
24151
24282
|
function readLessonsDeduped(zelariRoot) {
|
|
24152
|
-
const
|
|
24283
|
+
const path47 = join8(zelariRoot, LESSONS_FILE);
|
|
24153
24284
|
try {
|
|
24154
|
-
const raw = readFileSync10(
|
|
24285
|
+
const raw = readFileSync10(path47, "utf8");
|
|
24155
24286
|
const byId = /* @__PURE__ */ new Map();
|
|
24156
24287
|
for (const line of raw.split(/\r?\n/)) {
|
|
24157
24288
|
if (!line.trim())
|
|
@@ -24252,8 +24383,8 @@ function keywordsFrom(check2, signature) {
|
|
|
24252
24383
|
return [.../* @__PURE__ */ new Set([...fromId, ...words])].slice(0, 12);
|
|
24253
24384
|
}
|
|
24254
24385
|
function writeLesson(zelariRoot, lesson) {
|
|
24255
|
-
const
|
|
24256
|
-
appendFileSync(
|
|
24386
|
+
const path47 = join9(zelariRoot, LESSONS_FILE);
|
|
24387
|
+
appendFileSync(path47, `${JSON.stringify(lesson)}
|
|
24257
24388
|
`, "utf8");
|
|
24258
24389
|
}
|
|
24259
24390
|
function findSimilar(lessons, signature) {
|
|
@@ -24866,9 +24997,9 @@ function findCycle(nodes) {
|
|
|
24866
24997
|
if (color.get(start) !== WHITE)
|
|
24867
24998
|
continue;
|
|
24868
24999
|
const stack = [[start, 0]];
|
|
24869
|
-
const
|
|
25000
|
+
const path47 = [];
|
|
24870
25001
|
color.set(start, GRAY);
|
|
24871
|
-
|
|
25002
|
+
path47.push(start);
|
|
24872
25003
|
while (stack.length > 0) {
|
|
24873
25004
|
const top = stack[stack.length - 1];
|
|
24874
25005
|
const [id, idx] = top;
|
|
@@ -24881,17 +25012,17 @@ function findCycle(nodes) {
|
|
|
24881
25012
|
continue;
|
|
24882
25013
|
const c = color.get(dep);
|
|
24883
25014
|
if (c === GRAY) {
|
|
24884
|
-
const at =
|
|
24885
|
-
return [...
|
|
25015
|
+
const at = path47.indexOf(dep);
|
|
25016
|
+
return [...path47.slice(at), dep];
|
|
24886
25017
|
}
|
|
24887
25018
|
if (c === WHITE) {
|
|
24888
25019
|
color.set(dep, GRAY);
|
|
24889
|
-
|
|
25020
|
+
path47.push(dep);
|
|
24890
25021
|
stack.push([dep, 0]);
|
|
24891
25022
|
}
|
|
24892
25023
|
} else {
|
|
24893
25024
|
color.set(id, BLACK);
|
|
24894
|
-
|
|
25025
|
+
path47.pop();
|
|
24895
25026
|
stack.pop();
|
|
24896
25027
|
}
|
|
24897
25028
|
}
|
|
@@ -24978,10 +25109,15 @@ function countByStatus(graph) {
|
|
|
24978
25109
|
counts[node.status] += 1;
|
|
24979
25110
|
return counts;
|
|
24980
25111
|
}
|
|
24981
|
-
var DEFAULT_MAX_NODES;
|
|
25112
|
+
var TERMINAL_STATUSES, DEFAULT_MAX_NODES;
|
|
24982
25113
|
var init_graph = __esm({
|
|
24983
25114
|
"packages/core/dist/kraken/graph.js"() {
|
|
24984
25115
|
"use strict";
|
|
25116
|
+
TERMINAL_STATUSES = [
|
|
25117
|
+
"done",
|
|
25118
|
+
"error",
|
|
25119
|
+
"skipped"
|
|
25120
|
+
];
|
|
24985
25121
|
DEFAULT_MAX_NODES = 24;
|
|
24986
25122
|
}
|
|
24987
25123
|
});
|
|
@@ -25074,6 +25210,14 @@ function canRunParallel(a, b) {
|
|
|
25074
25210
|
}
|
|
25075
25211
|
return false;
|
|
25076
25212
|
}
|
|
25213
|
+
function selectParallelWave(candidates) {
|
|
25214
|
+
const wave = [];
|
|
25215
|
+
for (const node of candidates) {
|
|
25216
|
+
if (wave.every((w) => canRunParallel(w, node)))
|
|
25217
|
+
wave.push(node);
|
|
25218
|
+
}
|
|
25219
|
+
return wave;
|
|
25220
|
+
}
|
|
25077
25221
|
var READ_ONLY_KINDS, WRITER_KINDS;
|
|
25078
25222
|
var init_conflict = __esm({
|
|
25079
25223
|
"packages/core/dist/kraken/conflict.js"() {
|
|
@@ -25083,6 +25227,168 @@ var init_conflict = __esm({
|
|
|
25083
25227
|
}
|
|
25084
25228
|
});
|
|
25085
25229
|
|
|
25230
|
+
// packages/core/dist/kraken/weakness.js
|
|
25231
|
+
function weaknessFromVerdict(text) {
|
|
25232
|
+
if (typeof text !== "string")
|
|
25233
|
+
return 0;
|
|
25234
|
+
const trimmed = text.trim();
|
|
25235
|
+
if (trimmed === "")
|
|
25236
|
+
return 0;
|
|
25237
|
+
let score = 0;
|
|
25238
|
+
for (const re of SPECIFICITY_MARKERS) {
|
|
25239
|
+
if (re.test(trimmed))
|
|
25240
|
+
score += SPECIFICITY_MARKER_WEIGHT;
|
|
25241
|
+
}
|
|
25242
|
+
const clauses = trimmed.split(/[.!?;]+|\n+/).map((c) => c.trim()).filter((c) => c.length > 0 && /\b\w+ing\b|\b\w+ed\b|\bwill\b|\bcan\b|\bmust\b|\bshould\b|\bmay\b/i.test(c));
|
|
25243
|
+
const clausePenalty = Math.min(clauses.length, SPECIFICITY_CLAUSE_MAX) * SPECIFICITY_CLAUSE_WEIGHT;
|
|
25244
|
+
score += clausePenalty;
|
|
25245
|
+
return clamp01(score);
|
|
25246
|
+
}
|
|
25247
|
+
function weaknessScoreFromText(text) {
|
|
25248
|
+
return 1 - weaknessFromVerdict(text);
|
|
25249
|
+
}
|
|
25250
|
+
function weaknessFromMeter(meter) {
|
|
25251
|
+
return clamp01(1 - clamp01(meter.specificity));
|
|
25252
|
+
}
|
|
25253
|
+
function specificityFromAssumptions(assumptions) {
|
|
25254
|
+
if (!Array.isArray(assumptions) || assumptions.length === 0)
|
|
25255
|
+
return 0;
|
|
25256
|
+
const raw = Math.min(assumptions.length, 6) / 6;
|
|
25257
|
+
return clamp01(raw);
|
|
25258
|
+
}
|
|
25259
|
+
function rankByWeakness(candidates) {
|
|
25260
|
+
if (candidates.length === 0)
|
|
25261
|
+
return [];
|
|
25262
|
+
const raws = candidates.map((c) => computeRaw(c));
|
|
25263
|
+
const extScores = raws.filter((r) => r.source === "extensionSize").map((r) => r.raw);
|
|
25264
|
+
const extMax = extScores.length > 0 ? Math.max(...extScores) : 1;
|
|
25265
|
+
const extMin = extScores.length > 0 ? Math.min(...extScores) : 0;
|
|
25266
|
+
const extRange = extMax - extMin;
|
|
25267
|
+
const scored = raws.map((r) => {
|
|
25268
|
+
let score;
|
|
25269
|
+
switch (r.source) {
|
|
25270
|
+
case "extensionSize":
|
|
25271
|
+
score = extRange > 0 ? (r.raw - extMin) / extRange : 1;
|
|
25272
|
+
break;
|
|
25273
|
+
case "meter":
|
|
25274
|
+
score = clamp01(1 - clamp01(r.raw));
|
|
25275
|
+
break;
|
|
25276
|
+
case "heuristic":
|
|
25277
|
+
score = clamp01(r.raw);
|
|
25278
|
+
break;
|
|
25279
|
+
}
|
|
25280
|
+
return { candidate: r.candidate, score, source: r.source };
|
|
25281
|
+
});
|
|
25282
|
+
const indexed = scored.map((s, i) => ({ ...s, originalIndex: i }));
|
|
25283
|
+
indexed.sort((a, b) => {
|
|
25284
|
+
if (b.score !== a.score)
|
|
25285
|
+
return b.score - a.score;
|
|
25286
|
+
return a.originalIndex - b.originalIndex;
|
|
25287
|
+
});
|
|
25288
|
+
let lastScore;
|
|
25289
|
+
let lastRank = 0;
|
|
25290
|
+
let seen = 0;
|
|
25291
|
+
return indexed.map((s) => {
|
|
25292
|
+
seen += 1;
|
|
25293
|
+
if (lastScore === void 0 || s.score !== lastScore) {
|
|
25294
|
+
lastRank = seen;
|
|
25295
|
+
lastScore = s.score;
|
|
25296
|
+
}
|
|
25297
|
+
return {
|
|
25298
|
+
candidate: s.candidate,
|
|
25299
|
+
weaknessScore: s.score,
|
|
25300
|
+
rank: lastRank,
|
|
25301
|
+
source: s.source
|
|
25302
|
+
};
|
|
25303
|
+
});
|
|
25304
|
+
}
|
|
25305
|
+
function computeRaw(c) {
|
|
25306
|
+
if (typeof c.extensionSize === "number" && Number.isFinite(c.extensionSize) && c.extensionSize >= 0) {
|
|
25307
|
+
return { candidate: c, raw: c.extensionSize, source: "extensionSize" };
|
|
25308
|
+
}
|
|
25309
|
+
if (c.meter && typeof c.meter.specificity === "number" && Number.isFinite(c.meter.specificity)) {
|
|
25310
|
+
return { candidate: c, raw: clamp01(c.meter.specificity), source: "meter" };
|
|
25311
|
+
}
|
|
25312
|
+
return { candidate: c, raw: weaknessScoreFromText(c.text), source: "heuristic" };
|
|
25313
|
+
}
|
|
25314
|
+
function clamp01(n) {
|
|
25315
|
+
if (!Number.isFinite(n))
|
|
25316
|
+
return 0;
|
|
25317
|
+
if (n < 0)
|
|
25318
|
+
return 0;
|
|
25319
|
+
if (n > 1)
|
|
25320
|
+
return 1;
|
|
25321
|
+
return n;
|
|
25322
|
+
}
|
|
25323
|
+
function pickWeakest(candidates) {
|
|
25324
|
+
const ranked = rankByWeakness(candidates);
|
|
25325
|
+
return ranked.length > 0 ? ranked[0].candidate : void 0;
|
|
25326
|
+
}
|
|
25327
|
+
function filterByWeakness(candidates, threshold) {
|
|
25328
|
+
const ranked = rankByWeakness(candidates);
|
|
25329
|
+
return ranked.filter((r) => r.weaknessScore >= threshold).map((r) => r.candidate);
|
|
25330
|
+
}
|
|
25331
|
+
var BENNETTS_RAZOR, BENNETTS_RAZOR_SHORT, SPECIFICITY_MARKERS, SPECIFICITY_MARKER_WEIGHT, SPECIFICITY_CLAUSE_WEIGHT, SPECIFICITY_CLAUSE_MAX, WEAKNESS_METER_PROMPT, WeaknessMeterResponseSchema;
|
|
25332
|
+
var init_weakness = __esm({
|
|
25333
|
+
"packages/core/dist/kraken/weakness.js"() {
|
|
25334
|
+
"use strict";
|
|
25335
|
+
init_zod();
|
|
25336
|
+
BENNETTS_RAZOR = [
|
|
25337
|
+
"Bennett's Razor (arXiv:2301.12987): explanations should be no more specific than necessary.",
|
|
25338
|
+
"When two solutions both satisfy the task, prefer the one that assumes the least.",
|
|
25339
|
+
'A claim is "more specific" when it pins down an exact value, path, version, or invariant that a more general plan would not have to commit to.',
|
|
25340
|
+
"Specificity is a tie-breaker, not a goal: a plan that is too vague to act on is still useless.",
|
|
25341
|
+
"Weakness ranking only applies among solutions that already meet the bar; do not weaken a passing plan below the bar in the name of weakness."
|
|
25342
|
+
].join(" ");
|
|
25343
|
+
BENNETTS_RAZOR_SHORT = "Prefer the solution that is no more specific than necessary.";
|
|
25344
|
+
SPECIFICITY_MARKERS = [
|
|
25345
|
+
/\bguarantee[ds]?\b/i,
|
|
25346
|
+
/\bexact(?:ly)?\b/i,
|
|
25347
|
+
/\bmust\b/i,
|
|
25348
|
+
/\bshall\b/i,
|
|
25349
|
+
/\balways\b/i,
|
|
25350
|
+
/\bnever\b/i,
|
|
25351
|
+
/\brequire[ds]?\b/i,
|
|
25352
|
+
/\bmandatory\b/i,
|
|
25353
|
+
/\bline\s+\d+/i,
|
|
25354
|
+
// "line 42"
|
|
25355
|
+
/\bversion\s+[\d.]+/i,
|
|
25356
|
+
// "version 1.2.3"
|
|
25357
|
+
/\bv?\d+\.\d+\.\d+\b/,
|
|
25358
|
+
// bare semver
|
|
25359
|
+
/\b[0-9a-f]{7,40}\b/i,
|
|
25360
|
+
// git short SHA / commit hash
|
|
25361
|
+
/\bthe\s+(?:file|path)\s+(?:is|at)\b/i,
|
|
25362
|
+
/\bprecise(?:ly)?\b/i,
|
|
25363
|
+
/\bassert(?:s|ed|ion)?\b/i,
|
|
25364
|
+
/\bconfirm(?:s|ed)?\b/i,
|
|
25365
|
+
/\bwill\s+(?:definitely|certainly|always)\b/i
|
|
25366
|
+
];
|
|
25367
|
+
SPECIFICITY_MARKER_WEIGHT = 0.25;
|
|
25368
|
+
SPECIFICITY_CLAUSE_WEIGHT = 0.05;
|
|
25369
|
+
SPECIFICITY_CLAUSE_MAX = 6;
|
|
25370
|
+
WEAKNESS_METER_PROMPT = `You are measuring the SPECIFICITY of a candidate solution to a software task.
|
|
25371
|
+
|
|
25372
|
+
Specificity means: how many specific commitments does this solution make that a more general plan would not have to make? Examples of specific commitments: exact file paths, exact line numbers, exact semver versions, exact function signatures, guarantees about runtime behaviour, assertions about what other agents/users will do.
|
|
25373
|
+
|
|
25374
|
+
A maximally general solution is one that asserts nothing beyond the task itself ("just do the task"). A maximally specific solution is one that pins every possible value, path, and invariant.
|
|
25375
|
+
|
|
25376
|
+
Output ONLY a JSON object of the form:
|
|
25377
|
+
{"specificity": <float in [0,1]>, "assumptions": [<short string>, ...]}
|
|
25378
|
+
|
|
25379
|
+
where
|
|
25380
|
+
- specificity = 0.0 \u2192 solution asserts nothing beyond the task
|
|
25381
|
+
- specificity = 1.0 \u2192 solution pins every value, path, version, and invariant
|
|
25382
|
+
- assumptions = the list of specific commitments you identified, each \u2264 12 words, deduped, sorted by strength (most specific first). Cap the list at 12.
|
|
25383
|
+
|
|
25384
|
+
Do not add prose, do not add a code fence, do not explain your reasoning. JSON only.`;
|
|
25385
|
+
WeaknessMeterResponseSchema = external_exports.object({
|
|
25386
|
+
specificity: external_exports.number().min(0).max(1),
|
|
25387
|
+
assumptions: external_exports.array(external_exports.string().min(1).max(200)).max(12)
|
|
25388
|
+
});
|
|
25389
|
+
}
|
|
25390
|
+
});
|
|
25391
|
+
|
|
25086
25392
|
// packages/core/dist/kraken/verdict.js
|
|
25087
25393
|
function parseVerifyVerdict(text) {
|
|
25088
25394
|
const source = typeof text === "string" ? text : "";
|
|
@@ -25103,6 +25409,55 @@ function parseVerifyVerdict(text) {
|
|
|
25103
25409
|
const findings = capFindings(source.slice(0, last.index));
|
|
25104
25410
|
return { verdict, findings };
|
|
25105
25411
|
}
|
|
25412
|
+
function extractRequirementsBlock(text) {
|
|
25413
|
+
if (typeof text !== "string" || text.trim() === "")
|
|
25414
|
+
return [];
|
|
25415
|
+
const re = /```json\s*([\s\S]*?)```/gi;
|
|
25416
|
+
let m;
|
|
25417
|
+
let last = null;
|
|
25418
|
+
while ((m = re.exec(text)) !== null) {
|
|
25419
|
+
last = m[1];
|
|
25420
|
+
if (m.index === re.lastIndex)
|
|
25421
|
+
re.lastIndex += 1;
|
|
25422
|
+
}
|
|
25423
|
+
if (!last)
|
|
25424
|
+
return [];
|
|
25425
|
+
try {
|
|
25426
|
+
const obj = JSON.parse(last);
|
|
25427
|
+
if (!obj || !Array.isArray(obj.requirements))
|
|
25428
|
+
return [];
|
|
25429
|
+
const out = [];
|
|
25430
|
+
for (const r of obj.requirements) {
|
|
25431
|
+
if (!r || typeof r !== "object")
|
|
25432
|
+
continue;
|
|
25433
|
+
const row = r;
|
|
25434
|
+
const req = typeof row.requirement === "string" ? row.requirement : "";
|
|
25435
|
+
const metRaw = typeof row.met === "string" ? row.met.toLowerCase() : "";
|
|
25436
|
+
const met = metRaw === "pass" || metRaw === "true" ? "pass" : metRaw === "fail" || metRaw === "false" ? "fail" : "unknown";
|
|
25437
|
+
const evidence = typeof row.evidence === "string" ? row.evidence : void 0;
|
|
25438
|
+
if (req)
|
|
25439
|
+
out.push({ requirement: req, met, ...evidence ? { evidence } : {} });
|
|
25440
|
+
}
|
|
25441
|
+
return out;
|
|
25442
|
+
} catch {
|
|
25443
|
+
return [];
|
|
25444
|
+
}
|
|
25445
|
+
}
|
|
25446
|
+
function parsePersonaVerdict(text) {
|
|
25447
|
+
const base = parseVerifyVerdict(text);
|
|
25448
|
+
return {
|
|
25449
|
+
verdict: base.verdict,
|
|
25450
|
+
findings: base.findings,
|
|
25451
|
+
requirements: extractRequirementsBlock(text),
|
|
25452
|
+
// Bennett's weakness = "how little the reviewer's free text asserts"
|
|
25453
|
+
// (arXiv:2301.12987). `weaknessScoreFromText` is the weakness form
|
|
25454
|
+
// (1.0 = maximally general / no claims; 0.0 = maximally specific).
|
|
25455
|
+
// The verdict gate is the trailer; weakness is metadata surfaced in
|
|
25456
|
+
// the workbench so a user can see whether a PASS was earned by a
|
|
25457
|
+
// tightly-asserted or loosely-claimed reviewer.
|
|
25458
|
+
weaknessScore: weaknessScoreFromText(text)
|
|
25459
|
+
};
|
|
25460
|
+
}
|
|
25106
25461
|
function capFindings(raw) {
|
|
25107
25462
|
const trimmed = raw.trim();
|
|
25108
25463
|
if (trimmed.length <= MAX_FINDINGS_CHARS)
|
|
@@ -25114,11 +25469,537 @@ var MAX_FINDINGS_CHARS, VERDICT_LINE;
|
|
|
25114
25469
|
var init_verdict = __esm({
|
|
25115
25470
|
"packages/core/dist/kraken/verdict.js"() {
|
|
25116
25471
|
"use strict";
|
|
25472
|
+
init_weakness();
|
|
25117
25473
|
MAX_FINDINGS_CHARS = 2800;
|
|
25118
25474
|
VERDICT_LINE = /^[\s>*_-]*VERDICT[\s*_]*:[\s*_]*(PASS|FAIL)\b/gim;
|
|
25119
25475
|
}
|
|
25120
25476
|
});
|
|
25121
25477
|
|
|
25478
|
+
// packages/core/dist/kraken/personas/registry.js
|
|
25479
|
+
function registerPersona(p3) {
|
|
25480
|
+
registry3.set(p3.kind, p3);
|
|
25481
|
+
}
|
|
25482
|
+
function getPersona(kind) {
|
|
25483
|
+
return registry3.get(kind);
|
|
25484
|
+
}
|
|
25485
|
+
function listPersonas() {
|
|
25486
|
+
return [...registry3.values()];
|
|
25487
|
+
}
|
|
25488
|
+
function isReviewerKind(kind) {
|
|
25489
|
+
return kind === "verify" || kind === "spec" || kind === "conformance";
|
|
25490
|
+
}
|
|
25491
|
+
function defaultPersonaParse(text) {
|
|
25492
|
+
return parsePersonaVerdict(text);
|
|
25493
|
+
}
|
|
25494
|
+
var registry3;
|
|
25495
|
+
var init_registry = __esm({
|
|
25496
|
+
"packages/core/dist/kraken/personas/registry.js"() {
|
|
25497
|
+
"use strict";
|
|
25498
|
+
init_verdict();
|
|
25499
|
+
registry3 = /* @__PURE__ */ new Map();
|
|
25500
|
+
}
|
|
25501
|
+
});
|
|
25502
|
+
|
|
25503
|
+
// packages/core/dist/kraken/personas/specReviewer.js
|
|
25504
|
+
var SYSTEM_PROMPT, specPersona;
|
|
25505
|
+
var init_specReviewer = __esm({
|
|
25506
|
+
"packages/core/dist/kraken/personas/specReviewer.js"() {
|
|
25507
|
+
"use strict";
|
|
25508
|
+
init_registry();
|
|
25509
|
+
SYSTEM_PROMPT = [
|
|
25510
|
+
"You are the spec-reviewer for Kraken. You compare a writer's delivered",
|
|
25511
|
+
"work against a written spec or plan and judge each requirement.",
|
|
25512
|
+
"",
|
|
25513
|
+
'Your bias is CONSERVATIVE. When the spec said "must do X" and the writer',
|
|
25514
|
+
"did a reasonable but slightly different thing, that is a FAIL. Specs",
|
|
25515
|
+
"are meant to catch exactly this kind of drift.",
|
|
25516
|
+
"",
|
|
25517
|
+
"## Output format",
|
|
25518
|
+
"",
|
|
25519
|
+
"You MUST end with a verdict trailer on its own line:",
|
|
25520
|
+
"",
|
|
25521
|
+
" VERDICT: PASS",
|
|
25522
|
+
"or",
|
|
25523
|
+
" VERDICT: FAIL",
|
|
25524
|
+
"",
|
|
25525
|
+
"When the verdict is FAIL, you MUST also emit a per-requirement table in",
|
|
25526
|
+
"a JSON code block, BEFORE the trailer:",
|
|
25527
|
+
"",
|
|
25528
|
+
"```json",
|
|
25529
|
+
"{",
|
|
25530
|
+
' "requirements": [',
|
|
25531
|
+
' { "requirement": "<verbatim from the spec>", "met": "pass|fail|unknown", "evidence": "<path, line, command output>" },',
|
|
25532
|
+
" ...",
|
|
25533
|
+
" ]",
|
|
25534
|
+
"}",
|
|
25535
|
+
"```",
|
|
25536
|
+
"",
|
|
25537
|
+
"Rules:",
|
|
25538
|
+
" - Cite concrete evidence (file path, function name, command output).",
|
|
25539
|
+
' "Looks fine" is not evidence.',
|
|
25540
|
+
" - When a requirement is partially met, mark it `fail` with evidence",
|
|
25541
|
+
" describing the gap. The downstream `fix` tentacle will read this.",
|
|
25542
|
+
" - When a requirement is genuinely impossible to assess without running",
|
|
25543
|
+
" code, mark it `unknown` and explain why in evidence.",
|
|
25544
|
+
" - The verdict trailer is the GATE: the executor will not read the",
|
|
25545
|
+
" table if the trailer says PASS. The table is for diagnostics.",
|
|
25546
|
+
" - Keep the table terse. One line per row.",
|
|
25547
|
+
"",
|
|
25548
|
+
"## What you do NOT do",
|
|
25549
|
+
"",
|
|
25550
|
+
" - You do not modify any files. You are a judge, not a fixer.",
|
|
25551
|
+
" - You do not invent requirements that are not in the spec.",
|
|
25552
|
+
" - You do not say PASS when the spec listed requirements you did not",
|
|
25553
|
+
" actually assess. Either assess them or mark them `unknown`."
|
|
25554
|
+
].join("\n");
|
|
25555
|
+
specPersona = {
|
|
25556
|
+
kind: "spec",
|
|
25557
|
+
label: "spec-reviewer",
|
|
25558
|
+
description: "Compares a writer's output against a written spec, per-requirement.",
|
|
25559
|
+
systemPrompt: SYSTEM_PROMPT
|
|
25560
|
+
// Default parser handles both the trailer and the requirements block.
|
|
25561
|
+
};
|
|
25562
|
+
registerPersona(specPersona);
|
|
25563
|
+
}
|
|
25564
|
+
});
|
|
25565
|
+
|
|
25566
|
+
// packages/core/dist/kraken/personas/conformance.js
|
|
25567
|
+
var SYSTEM_PROMPT2, conformancePersona;
|
|
25568
|
+
var init_conformance = __esm({
|
|
25569
|
+
"packages/core/dist/kraken/personas/conformance.js"() {
|
|
25570
|
+
"use strict";
|
|
25571
|
+
init_registry();
|
|
25572
|
+
SYSTEM_PROMPT2 = [
|
|
25573
|
+
"You are the conformance-reviewer for Kraken. You compare a writer's",
|
|
25574
|
+
"delivered work against the USER'S ORIGINAL VERBATIM PROMPT \u2014 not a",
|
|
25575
|
+
"spec, not a plan, not what the writer decided to do.",
|
|
25576
|
+
"",
|
|
25577
|
+
'Your bias is LITERAL. When the user said "use JWT", "use session',
|
|
25578
|
+
'cookies" is a FAIL even if it works. When the user said "ship a CLI",',
|
|
25579
|
+
'"ship a library" is a FAIL even if the library is excellent.',
|
|
25580
|
+
"",
|
|
25581
|
+
"## Decomposition",
|
|
25582
|
+
"",
|
|
25583
|
+
"Before judging, decompose the prompt into the discrete asks the user",
|
|
25584
|
+
"made. A good decomposition:",
|
|
25585
|
+
" - Each user-stated requirement gets one row.",
|
|
25586
|
+
' - Each user-stated preference ("preferably X", "ideally Y") gets one row.',
|
|
25587
|
+
' - Each user-stated constraint ("no dependencies", "stay under 100 LOC") gets one row.',
|
|
25588
|
+
" - If the prompt is ambiguous, decompose into the LITERAL reading AND",
|
|
25589
|
+
" note in the evidence that a more permissive reading would have passed.",
|
|
25590
|
+
"",
|
|
25591
|
+
"## Output format",
|
|
25592
|
+
"",
|
|
25593
|
+
"You MUST end with a verdict trailer on its own line:",
|
|
25594
|
+
"",
|
|
25595
|
+
" VERDICT: PASS",
|
|
25596
|
+
"or",
|
|
25597
|
+
" VERDICT: FAIL",
|
|
25598
|
+
"",
|
|
25599
|
+
"When the verdict is FAIL, you MUST also emit a per-requirement table in",
|
|
25600
|
+
"a JSON code block, BEFORE the trailer:",
|
|
25601
|
+
"",
|
|
25602
|
+
"```json",
|
|
25603
|
+
"{",
|
|
25604
|
+
' "requirements": [',
|
|
25605
|
+
' { "requirement": "<verbatim from the user prompt>", "met": "pass|fail|unknown", "evidence": "<path, line, output>" },',
|
|
25606
|
+
" ...",
|
|
25607
|
+
" ]",
|
|
25608
|
+
"}",
|
|
25609
|
+
"```",
|
|
25610
|
+
"",
|
|
25611
|
+
"Rules:",
|
|
25612
|
+
" - Cite concrete evidence (file path, line, function name, command",
|
|
25613
|
+
' output) for every row. "Looks right" is not evidence.',
|
|
25614
|
+
" - When a literal reading would have failed but a more permissive",
|
|
25615
|
+
" reading would have passed, mark it `fail` with evidence explaining",
|
|
25616
|
+
" the gap. The user is the authority on what they meant.",
|
|
25617
|
+
' - When the prompt is genuinely too vague to decompose (e.g. "make it',
|
|
25618
|
+
' better"), say so explicitly in your findings and mark all rows',
|
|
25619
|
+
" `unknown`. The downstream fix node will then ask the user.",
|
|
25620
|
+
" - Keep the table terse. One line per row.",
|
|
25621
|
+
"",
|
|
25622
|
+
"## What you do NOT do",
|
|
25623
|
+
"",
|
|
25624
|
+
" - You do not consult any spec, plan, or intermediate artifact. Only the",
|
|
25625
|
+
" original user prompt.",
|
|
25626
|
+
" - You do not modify any files. You are a judge, not a fixer.",
|
|
25627
|
+
" - You do not say PASS to be polite. The user has only one chance to",
|
|
25628
|
+
" see your verdict before shipping; be honest."
|
|
25629
|
+
].join("\n");
|
|
25630
|
+
conformancePersona = {
|
|
25631
|
+
kind: "conformance",
|
|
25632
|
+
label: "conformance-reviewer",
|
|
25633
|
+
description: "Compares a writer's output against the user's original verbatim prompt.",
|
|
25634
|
+
systemPrompt: SYSTEM_PROMPT2
|
|
25635
|
+
};
|
|
25636
|
+
registerPersona(conformancePersona);
|
|
25637
|
+
}
|
|
25638
|
+
});
|
|
25639
|
+
|
|
25640
|
+
// packages/core/dist/kraken/personas/index.js
|
|
25641
|
+
var init_personas = __esm({
|
|
25642
|
+
"packages/core/dist/kraken/personas/index.js"() {
|
|
25643
|
+
"use strict";
|
|
25644
|
+
init_specReviewer();
|
|
25645
|
+
init_conformance();
|
|
25646
|
+
init_registry();
|
|
25647
|
+
}
|
|
25648
|
+
});
|
|
25649
|
+
|
|
25650
|
+
// packages/core/dist/kraken/runtime/types.js
|
|
25651
|
+
var PlanError;
|
|
25652
|
+
var init_types6 = __esm({
|
|
25653
|
+
"packages/core/dist/kraken/runtime/types.js"() {
|
|
25654
|
+
"use strict";
|
|
25655
|
+
PlanError = class extends Error {
|
|
25656
|
+
name = "PlanError";
|
|
25657
|
+
kind;
|
|
25658
|
+
cause;
|
|
25659
|
+
constructor(kind, message, cause) {
|
|
25660
|
+
super(message);
|
|
25661
|
+
this.kind = kind;
|
|
25662
|
+
if (cause !== void 0)
|
|
25663
|
+
this.cause = cause;
|
|
25664
|
+
}
|
|
25665
|
+
};
|
|
25666
|
+
}
|
|
25667
|
+
});
|
|
25668
|
+
|
|
25669
|
+
// packages/core/dist/kraken/runtime/sandbox.js
|
|
25670
|
+
import vm from "node:vm";
|
|
25671
|
+
function scanForFootguns(bundleCode) {
|
|
25672
|
+
if (bundleCode.length > MAX_BUNDLE_BYTES) {
|
|
25673
|
+
return [
|
|
25674
|
+
`bundle is ${bundleCode.length} bytes; max is ${MAX_BUNDLE_BYTES} (LLM is almost certainly looping)`
|
|
25675
|
+
];
|
|
25676
|
+
}
|
|
25677
|
+
const hits = [];
|
|
25678
|
+
for (const re of FORBIDDEN_TOKENS) {
|
|
25679
|
+
const m = re.exec(bundleCode);
|
|
25680
|
+
if (m)
|
|
25681
|
+
hits.push(`forbidden token "${m[0]}"`);
|
|
25682
|
+
}
|
|
25683
|
+
return hits;
|
|
25684
|
+
}
|
|
25685
|
+
function deepFreeze(value) {
|
|
25686
|
+
if (value === null || typeof value !== "object")
|
|
25687
|
+
return value;
|
|
25688
|
+
if (Object.isFrozen(value))
|
|
25689
|
+
return value;
|
|
25690
|
+
const obj = value;
|
|
25691
|
+
for (const k of Object.keys(obj))
|
|
25692
|
+
deepFreeze(obj[k]);
|
|
25693
|
+
return Object.freeze(value);
|
|
25694
|
+
}
|
|
25695
|
+
async function runInSandbox(opts) {
|
|
25696
|
+
const { bundleCode, sdk, timeoutMs } = opts;
|
|
25697
|
+
if (!opts.skipFootgunScan) {
|
|
25698
|
+
const footguns = scanForFootguns(bundleCode);
|
|
25699
|
+
if (footguns.length > 0) {
|
|
25700
|
+
throw new PlanError("sandbox_breach", `script bundle failed footgun scan: ${footguns.join("; ")}`);
|
|
25701
|
+
}
|
|
25702
|
+
}
|
|
25703
|
+
const frozen = deepFreeze({ ...sdk });
|
|
25704
|
+
const sandbox = {
|
|
25705
|
+
__zelari_sdk__: frozen,
|
|
25706
|
+
// A console that prefixes lines with the graph id; useful for the
|
|
25707
|
+
// workbench view and harmless to expose (it just logs to stdout).
|
|
25708
|
+
console: makeSandboxConsole()
|
|
25709
|
+
};
|
|
25710
|
+
const context = vm.createContext(sandbox, {
|
|
25711
|
+
name: "kraken-script",
|
|
25712
|
+
codeGeneration: { strings: false, wasm: false }
|
|
25713
|
+
});
|
|
25714
|
+
const start = Date.now();
|
|
25715
|
+
const vmOpts = {
|
|
25716
|
+
timeout: Math.max(1, timeoutMs),
|
|
25717
|
+
displayErrors: true,
|
|
25718
|
+
breakOnSigint: true
|
|
25719
|
+
};
|
|
25720
|
+
try {
|
|
25721
|
+
const value = await vm.runInContext(bundleCode, context, vmOpts);
|
|
25722
|
+
return { value, durationMs: Date.now() - start };
|
|
25723
|
+
} catch (err) {
|
|
25724
|
+
const msg = err && typeof err === "object" && "message" in err ? String(err.message ?? "") : String(err);
|
|
25725
|
+
if (/timed out/i.test(msg)) {
|
|
25726
|
+
throw new PlanError("budget_exceeded", `script exceeded ${timeoutMs}ms budget`);
|
|
25727
|
+
}
|
|
25728
|
+
if (opts.signal?.aborted) {
|
|
25729
|
+
throw new PlanError("cancelled", "script aborted by host");
|
|
25730
|
+
}
|
|
25731
|
+
if (err instanceof PlanError)
|
|
25732
|
+
throw err;
|
|
25733
|
+
throw new PlanError("runtime_error", msg, err);
|
|
25734
|
+
}
|
|
25735
|
+
}
|
|
25736
|
+
function makeSandboxConsole() {
|
|
25737
|
+
const prefix = "[kraken-script]";
|
|
25738
|
+
return {
|
|
25739
|
+
...console,
|
|
25740
|
+
log: (...args) => console.log(prefix, ...args),
|
|
25741
|
+
info: (...args) => console.info(prefix, ...args),
|
|
25742
|
+
warn: (...args) => console.warn(prefix, ...args),
|
|
25743
|
+
error: (...args) => console.error(prefix, ...args)
|
|
25744
|
+
};
|
|
25745
|
+
}
|
|
25746
|
+
var MAX_BUNDLE_BYTES, FORBIDDEN_TOKENS;
|
|
25747
|
+
var init_sandbox = __esm({
|
|
25748
|
+
"packages/core/dist/kraken/runtime/sandbox.js"() {
|
|
25749
|
+
"use strict";
|
|
25750
|
+
init_types6();
|
|
25751
|
+
MAX_BUNDLE_BYTES = 256 * 1024;
|
|
25752
|
+
FORBIDDEN_TOKENS = [
|
|
25753
|
+
/\bprocess\b/,
|
|
25754
|
+
/\brequire\b/,
|
|
25755
|
+
/\bmodule\b/,
|
|
25756
|
+
/\bexports\b/,
|
|
25757
|
+
/\b__dirname\b/,
|
|
25758
|
+
/\b__filename\b/,
|
|
25759
|
+
/\bglobalThis\b/,
|
|
25760
|
+
/\bglobal\b(?!\s*=)/,
|
|
25761
|
+
/\bBuffer\b/,
|
|
25762
|
+
/\beval\b/,
|
|
25763
|
+
/\bFunction\s*\(/,
|
|
25764
|
+
/\bnew\s+Function\b/
|
|
25765
|
+
];
|
|
25766
|
+
}
|
|
25767
|
+
});
|
|
25768
|
+
|
|
25769
|
+
// packages/core/dist/kraken/runtime/runner.js
|
|
25770
|
+
function resolveMaxTentacles(env = process.env) {
|
|
25771
|
+
const raw = env.ZELARI_KRAKEN_MAX_TENTACLES;
|
|
25772
|
+
if (raw === void 0 || raw === "")
|
|
25773
|
+
return DEFAULT_MAX_TENTACLES;
|
|
25774
|
+
const n = Number.parseInt(raw, 10);
|
|
25775
|
+
return Number.isFinite(n) && n > 0 ? n : DEFAULT_MAX_TENTACLES;
|
|
25776
|
+
}
|
|
25777
|
+
function resolvePlanTimeoutMs(env = process.env) {
|
|
25778
|
+
const raw = env.ZELARI_KRAKEN_PLAN_TIMEOUT_MS;
|
|
25779
|
+
if (raw === void 0 || raw === "")
|
|
25780
|
+
return DEFAULT_PLAN_TIMEOUT_MS;
|
|
25781
|
+
const n = Number.parseInt(raw, 10);
|
|
25782
|
+
return Number.isFinite(n) && n >= 0 ? n : DEFAULT_PLAN_TIMEOUT_MS;
|
|
25783
|
+
}
|
|
25784
|
+
function cap(text, max) {
|
|
25785
|
+
if (text.length <= max)
|
|
25786
|
+
return text;
|
|
25787
|
+
return `${text.slice(0, max)}
|
|
25788
|
+
\u2026 [truncated]`;
|
|
25789
|
+
}
|
|
25790
|
+
function buildRef(id, opts, result) {
|
|
25791
|
+
const findings = cap(result.ok ? (result.result ?? "").trim() : result.error ?? "unknown error", MAX_FINDINGS_CHARS);
|
|
25792
|
+
const ref = {
|
|
25793
|
+
id,
|
|
25794
|
+
kind: opts.kind,
|
|
25795
|
+
label: opts.label,
|
|
25796
|
+
status: result.ok ? "done" : "error",
|
|
25797
|
+
findings,
|
|
25798
|
+
scope: opts.scope,
|
|
25799
|
+
...result.durationMs !== void 0 ? { durationMs: result.durationMs } : {},
|
|
25800
|
+
...result.worktree !== void 0 ? { worktree: result.worktree } : {}
|
|
25801
|
+
};
|
|
25802
|
+
if (isReviewerKind(opts.kind)) {
|
|
25803
|
+
ref.verdict = defaultPersonaParse(findings).verdict;
|
|
25804
|
+
}
|
|
25805
|
+
return ref;
|
|
25806
|
+
}
|
|
25807
|
+
var DEFAULT_MAX_TENTACLES, DEFAULT_PLAN_TIMEOUT_MS, ScriptRunner;
|
|
25808
|
+
var init_runner = __esm({
|
|
25809
|
+
"packages/core/dist/kraken/runtime/runner.js"() {
|
|
25810
|
+
"use strict";
|
|
25811
|
+
init_verdict();
|
|
25812
|
+
init_personas();
|
|
25813
|
+
init_types6();
|
|
25814
|
+
DEFAULT_MAX_TENTACLES = 200;
|
|
25815
|
+
DEFAULT_PLAN_TIMEOUT_MS = 30 * 6e4;
|
|
25816
|
+
ScriptRunner = class {
|
|
25817
|
+
host;
|
|
25818
|
+
goal;
|
|
25819
|
+
graphId;
|
|
25820
|
+
parentCwd;
|
|
25821
|
+
sessionId;
|
|
25822
|
+
maxTentacles;
|
|
25823
|
+
planTimeoutMs;
|
|
25824
|
+
startTime;
|
|
25825
|
+
tentaclesById = /* @__PURE__ */ new Map();
|
|
25826
|
+
tentacleCount = 0;
|
|
25827
|
+
mergeCount = 0;
|
|
25828
|
+
cancelled = false;
|
|
25829
|
+
constructor(opts) {
|
|
25830
|
+
this.host = opts.host;
|
|
25831
|
+
this.goal = opts.goal;
|
|
25832
|
+
this.graphId = opts.graphId;
|
|
25833
|
+
this.parentCwd = opts.parentCwd;
|
|
25834
|
+
this.sessionId = opts.sessionId;
|
|
25835
|
+
this.maxTentacles = opts.maxTentacles ?? resolveMaxTentacles();
|
|
25836
|
+
this.planTimeoutMs = opts.planTimeoutMs ?? resolvePlanTimeoutMs();
|
|
25837
|
+
this.startTime = Date.now();
|
|
25838
|
+
}
|
|
25839
|
+
/** Build the `PlanCapabilities` object the sandbox will see. */
|
|
25840
|
+
buildSdk() {
|
|
25841
|
+
return {
|
|
25842
|
+
tentacle: (opts) => this.callTentacle(opts),
|
|
25843
|
+
barrier: (refs) => this.callBarrier(refs),
|
|
25844
|
+
race: (refs) => this.callRace(refs),
|
|
25845
|
+
while_: (cond, body, maxIter) => this.callWhile(cond, body, maxIter),
|
|
25846
|
+
until: (cond, body, maxIter) => this.callUntil(cond, body, maxIter),
|
|
25847
|
+
merge: (refs, opts) => this.callMerge(refs, opts),
|
|
25848
|
+
checkpoint: (label) => this.callCheckpoint(label),
|
|
25849
|
+
log: (msg, data) => this.callLog(msg, data),
|
|
25850
|
+
emit: (payload) => this.callEmit(payload),
|
|
25851
|
+
getContext: () => this.callGetContext(),
|
|
25852
|
+
sendTo: (peerId, payload) => this.callSendTo(peerId, payload)
|
|
25853
|
+
};
|
|
25854
|
+
}
|
|
25855
|
+
/** One tentacle = one `runTentacle` call. The host returns a raw result;
|
|
25856
|
+
* we turn it into a `TentacleRef` and stash it. */
|
|
25857
|
+
async callTentacle(opts) {
|
|
25858
|
+
if (this.cancelled)
|
|
25859
|
+
throw new PlanError("cancelled", "runner is cancelled");
|
|
25860
|
+
if (this.tentacleCount >= this.maxTentacles) {
|
|
25861
|
+
throw new PlanError("budget_exceeded", `tentacle cap (${this.maxTentacles}) reached; raise ZELARI_KRAKEN_MAX_TENTACLES`);
|
|
25862
|
+
}
|
|
25863
|
+
if (this.tentacleCount > 0 && Date.now() - this.startTime > this.planTimeoutMs) {
|
|
25864
|
+
throw new PlanError("budget_exceeded", `plan wall-clock budget (${this.planTimeoutMs}ms) exceeded`);
|
|
25865
|
+
}
|
|
25866
|
+
this.tentacleCount += 1;
|
|
25867
|
+
const id = `t${String(this.tentacleCount).padStart(4, "0")}`;
|
|
25868
|
+
const res = await this.host.runTentacle({
|
|
25869
|
+
node: opts,
|
|
25870
|
+
parentCwd: this.parentCwd,
|
|
25871
|
+
sessionId: this.sessionId
|
|
25872
|
+
});
|
|
25873
|
+
const ref = buildRef(id, opts, res);
|
|
25874
|
+
this.tentaclesById.set(id, ref);
|
|
25875
|
+
return ref;
|
|
25876
|
+
}
|
|
25877
|
+
async callBarrier(refs) {
|
|
25878
|
+
if (refs.some((r) => !this.tentaclesById.has(r.id))) {
|
|
25879
|
+
throw new PlanError("runtime_error", "barrier() received a ref not in this runner");
|
|
25880
|
+
}
|
|
25881
|
+
return refs;
|
|
25882
|
+
}
|
|
25883
|
+
async callRace(refs) {
|
|
25884
|
+
if (refs.length === 0) {
|
|
25885
|
+
throw new PlanError("runtime_error", "race() requires at least one ref");
|
|
25886
|
+
}
|
|
25887
|
+
let winner = refs[0];
|
|
25888
|
+
for (const r of refs) {
|
|
25889
|
+
const a = winner.durationMs ?? Number.POSITIVE_INFINITY;
|
|
25890
|
+
const b = r.durationMs ?? Number.POSITIVE_INFINITY;
|
|
25891
|
+
if (b < a || b === a && r.id < winner.id)
|
|
25892
|
+
winner = r;
|
|
25893
|
+
}
|
|
25894
|
+
return winner;
|
|
25895
|
+
}
|
|
25896
|
+
async callWhile(cond, body, maxIter) {
|
|
25897
|
+
if (maxIter < 1)
|
|
25898
|
+
throw new PlanError("runtime_error", "while_() maxIter must be \u2265 1");
|
|
25899
|
+
const out = [];
|
|
25900
|
+
let iter = 0;
|
|
25901
|
+
while (await cond()) {
|
|
25902
|
+
if (iter >= maxIter) {
|
|
25903
|
+
throw new PlanError("budget_exceeded", `while_() exceeded maxIter=${maxIter} without cond turning false`);
|
|
25904
|
+
}
|
|
25905
|
+
out.push(await body());
|
|
25906
|
+
iter += 1;
|
|
25907
|
+
}
|
|
25908
|
+
return out;
|
|
25909
|
+
}
|
|
25910
|
+
async callUntil(cond, body, maxIter) {
|
|
25911
|
+
return this.callWhile(async () => !await cond(), body, maxIter);
|
|
25912
|
+
}
|
|
25913
|
+
/** One merge per plan. A second call is a structured error. */
|
|
25914
|
+
async callMerge(refs, opts = {}) {
|
|
25915
|
+
if (this.mergeCount > 0) {
|
|
25916
|
+
throw new PlanError("merge_already_done", "merge() called more than once; a plan can merge at most one batch");
|
|
25917
|
+
}
|
|
25918
|
+
if (refs.length === 0) {
|
|
25919
|
+
throw new PlanError("runtime_error", "merge() requires at least one ref");
|
|
25920
|
+
}
|
|
25921
|
+
for (const r of refs) {
|
|
25922
|
+
if (!this.tentaclesById.has(r.id)) {
|
|
25923
|
+
throw new PlanError("runtime_error", `merge() received unknown ref "${r.id}"`);
|
|
25924
|
+
}
|
|
25925
|
+
}
|
|
25926
|
+
this.mergeCount += 1;
|
|
25927
|
+
return this.host.mergeWorktrees({
|
|
25928
|
+
refs,
|
|
25929
|
+
parentCwd: this.parentCwd,
|
|
25930
|
+
strategy: opts.strategy ?? "squash-sequential",
|
|
25931
|
+
...opts.message ? { message: opts.message } : {},
|
|
25932
|
+
...opts.cleanup !== void 0 ? { cleanup: opts.cleanup } : {}
|
|
25933
|
+
});
|
|
25934
|
+
}
|
|
25935
|
+
async callCheckpoint(label) {
|
|
25936
|
+
const snapshot = {
|
|
25937
|
+
graphId: this.graphId,
|
|
25938
|
+
goal: this.goal,
|
|
25939
|
+
takenAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
25940
|
+
completed: [...this.tentaclesById.values()].filter((r) => r.status === "done"),
|
|
25941
|
+
inFlight: [...this.tentaclesById.values()].filter((r) => r.status === "running"),
|
|
25942
|
+
failed: [...this.tentaclesById.values()].filter((r) => r.status === "error"),
|
|
25943
|
+
pending: []
|
|
25944
|
+
};
|
|
25945
|
+
const path47 = await this.host.saveSnapshot(snapshot, ".zelari/kraken/snapshots");
|
|
25946
|
+
this.host.log(`checkpoint: ${label ?? "auto"} \u2192 ${path47}`);
|
|
25947
|
+
return snapshot;
|
|
25948
|
+
}
|
|
25949
|
+
callLog(msg, data) {
|
|
25950
|
+
const line = data ? `${msg} ${JSON.stringify(data)}` : msg;
|
|
25951
|
+
this.host.log(line);
|
|
25952
|
+
}
|
|
25953
|
+
callEmit(payload) {
|
|
25954
|
+
this.host.log(`emit: ${payload.kind}${payload.detail ? ` \u2014 ${payload.detail}` : ""}`);
|
|
25955
|
+
}
|
|
25956
|
+
callGetContext() {
|
|
25957
|
+
return {
|
|
25958
|
+
graphId: this.graphId,
|
|
25959
|
+
goal: this.goal,
|
|
25960
|
+
parentCwd: this.parentCwd,
|
|
25961
|
+
sessionId: this.sessionId,
|
|
25962
|
+
tentacles: this.tentaclesById,
|
|
25963
|
+
maxTentacles: this.maxTentacles,
|
|
25964
|
+
planTimeoutMs: this.planTimeoutMs
|
|
25965
|
+
};
|
|
25966
|
+
}
|
|
25967
|
+
callSendTo(peerId, payload) {
|
|
25968
|
+
this.host.log(`sendTo(${peerId}): ${payload.kind}${payload.detail ? ` \u2014 ${payload.detail}` : ""}`);
|
|
25969
|
+
}
|
|
25970
|
+
/** Called by the host after the sandbox returns, to mark the run. */
|
|
25971
|
+
finalize(opts) {
|
|
25972
|
+
if (opts.cancelled)
|
|
25973
|
+
this.cancelled = true;
|
|
25974
|
+
const failed = [...this.tentaclesById.values()].filter((r) => r.status === "error");
|
|
25975
|
+
return {
|
|
25976
|
+
tentacles: this.tentaclesById,
|
|
25977
|
+
mergeCount: this.mergeCount,
|
|
25978
|
+
converged: opts.converged,
|
|
25979
|
+
cancelled: this.cancelled,
|
|
25980
|
+
durationMs: Date.now() - this.startTime,
|
|
25981
|
+
unresolvedFindings: failed.map((r) => ({
|
|
25982
|
+
nodeId: r.id,
|
|
25983
|
+
label: r.label,
|
|
25984
|
+
reason: r.status === "error" ? "fail" : "unknown",
|
|
25985
|
+
findings: r.findings
|
|
25986
|
+
}))
|
|
25987
|
+
};
|
|
25988
|
+
}
|
|
25989
|
+
};
|
|
25990
|
+
}
|
|
25991
|
+
});
|
|
25992
|
+
|
|
25993
|
+
// packages/core/dist/kraken/runtime/index.js
|
|
25994
|
+
var init_runtime = __esm({
|
|
25995
|
+
"packages/core/dist/kraken/runtime/index.js"() {
|
|
25996
|
+
"use strict";
|
|
25997
|
+
init_types6();
|
|
25998
|
+
init_sandbox();
|
|
25999
|
+
init_runner();
|
|
26000
|
+
}
|
|
26001
|
+
});
|
|
26002
|
+
|
|
25122
26003
|
// packages/core/dist/kraken/index.js
|
|
25123
26004
|
var init_kraken = __esm({
|
|
25124
26005
|
"packages/core/dist/kraken/index.js"() {
|
|
@@ -25126,10 +26007,254 @@ var init_kraken = __esm({
|
|
|
25126
26007
|
init_graph();
|
|
25127
26008
|
init_conflict();
|
|
25128
26009
|
init_verdict();
|
|
26010
|
+
init_personas();
|
|
26011
|
+
init_runtime();
|
|
26012
|
+
init_weakness();
|
|
25129
26013
|
}
|
|
25130
26014
|
});
|
|
25131
26015
|
|
|
25132
26016
|
// packages/core/dist/index.js
|
|
26017
|
+
var dist_exports = {};
|
|
26018
|
+
__export(dist_exports, {
|
|
26019
|
+
ADVANCED_TOOL_DEFINITIONS: () => ADVANCED_TOOL_DEFINITIONS,
|
|
26020
|
+
AGENT_ROLES: () => AGENT_ROLES,
|
|
26021
|
+
ALL_TOOLS: () => ALL_TOOLS,
|
|
26022
|
+
AgentHarness: () => AgentHarness,
|
|
26023
|
+
BENNETTS_RAZOR: () => BENNETTS_RAZOR,
|
|
26024
|
+
BENNETTS_RAZOR_SHORT: () => BENNETTS_RAZOR_SHORT,
|
|
26025
|
+
CLARIFICATION_PROTOCOL_MODULE: () => CLARIFICATION_PROTOCOL_MODULE,
|
|
26026
|
+
CODING_CATEGORY: () => CODING_CATEGORY,
|
|
26027
|
+
CODING_PRACTICES_MODULE: () => CODING_PRACTICES_MODULE,
|
|
26028
|
+
CODING_SKILL_CATALOG: () => CODING_SKILL_CATALOG,
|
|
26029
|
+
COLLABORATION_DIRECTIVE: () => COLLABORATION_DIRECTIVE,
|
|
26030
|
+
COMPOSITOR_ONLY_PROPS: () => COMPOSITOR_ONLY_PROPS,
|
|
26031
|
+
DEFAULT_MAX_NODES: () => DEFAULT_MAX_NODES,
|
|
26032
|
+
DEFAULT_MAX_TENTACLES: () => DEFAULT_MAX_TENTACLES,
|
|
26033
|
+
DEFAULT_NFR_SPEC: () => DEFAULT_NFR_SPEC,
|
|
26034
|
+
DEFAULT_PLAN_TIMEOUT_MS: () => DEFAULT_PLAN_TIMEOUT_MS,
|
|
26035
|
+
DEGRADED_RUN_BANNER: () => DEGRADED_RUN_BANNER,
|
|
26036
|
+
DESIGN_PHASE_MODE_BANNER: () => DESIGN_PHASE_MODE_BANNER,
|
|
26037
|
+
DESIGN_PHASE_REQUIREMENTS: () => DESIGN_PHASE_REQUIREMENTS,
|
|
26038
|
+
DESIGN_PHASE_REQUIREMENT_SETS: () => DESIGN_PHASE_REQUIREMENT_SETS,
|
|
26039
|
+
DOOM_LOOP_THRESHOLD: () => DOOM_LOOP_THRESHOLD,
|
|
26040
|
+
EventBus: () => EventBus,
|
|
26041
|
+
IMPLEMENTATION_ADVISOR_BANNER: () => IMPLEMENTATION_ADVISOR_BANNER,
|
|
26042
|
+
IMPLEMENTATION_IMPLEMENTER_BANNER: () => IMPLEMENTATION_IMPLEMENTER_BANNER,
|
|
26043
|
+
IMPLEMENTATION_MODE_BANNER: () => IMPLEMENTATION_MODE_BANNER,
|
|
26044
|
+
IMPLEMENTATION_WRITE_REQUIREMENTS: () => IMPLEMENTATION_WRITE_REQUIREMENTS,
|
|
26045
|
+
KRAKEN_IDENTITY_MODULE: () => KRAKEN_IDENTITY_MODULE,
|
|
26046
|
+
KRAKEN_LEAD_PLAYBOOK_MODULE: () => KRAKEN_LEAD_PLAYBOOK_MODULE,
|
|
26047
|
+
LANGUAGE_POLICY_MODULE_TYPE: () => LANGUAGE_POLICY_MODULE_TYPE,
|
|
26048
|
+
LAYOUT_MOTION_PROPS: () => LAYOUT_MOTION_PROPS,
|
|
26049
|
+
LESSONS_FILE: () => LESSONS_FILE,
|
|
26050
|
+
MAX_DELIVERY_ATTEMPTS: () => MAX_DELIVERY_ATTEMPTS,
|
|
26051
|
+
MAX_FINDINGS_CHARS: () => MAX_FINDINGS_CHARS,
|
|
26052
|
+
MAX_RETRY_PER_MEMBER: () => MAX_RETRY_PER_MEMBER,
|
|
26053
|
+
MUTATING_PROJECT_TOOLS: () => MUTATING_PROJECT_TOOLS,
|
|
26054
|
+
NATIVE_TOOL_PROTOCOL_MODULE: () => NATIVE_TOOL_PROTOCOL_MODULE,
|
|
26055
|
+
NFR_KEYWORDS: () => NFR_KEYWORDS,
|
|
26056
|
+
NON_RETRY_AGENTS: () => NON_RETRY_AGENTS,
|
|
26057
|
+
OUTPUT_QUALITY_DIRECTIVE: () => OUTPUT_QUALITY_DIRECTIVE,
|
|
26058
|
+
PROMPT_MODULES: () => PROMPT_MODULES,
|
|
26059
|
+
PROPRIETARY_REFUSAL_TEXT: () => PROPRIETARY_REFUSAL_TEXT,
|
|
26060
|
+
PROPRIETARY_SECRECY_MARKER: () => PROPRIETARY_SECRECY_MARKER,
|
|
26061
|
+
PROPRIETARY_SECRECY_MODULE: () => PROPRIETARY_SECRECY_MODULE,
|
|
26062
|
+
PlanError: () => PlanError,
|
|
26063
|
+
SINGLE_AGENT_IDENTITY_MODULE: () => SINGLE_AGENT_IDENTITY_MODULE,
|
|
26064
|
+
SKILL_CATALOG: () => SKILL_CATALOG,
|
|
26065
|
+
STRUCTURED_REASONING_DIRECTIVE: () => STRUCTURED_REASONING_DIRECTIVE,
|
|
26066
|
+
ScriptRunner: () => ScriptRunner,
|
|
26067
|
+
SessionJsonlWriter: () => SessionJsonlWriter,
|
|
26068
|
+
TERMINAL_STATUSES: () => TERMINAL_STATUSES,
|
|
26069
|
+
TEXT_LOOP_RECOVERY_SYSTEM: () => TEXT_LOOP_RECOVERY_SYSTEM,
|
|
26070
|
+
TEXT_LOOP_RECOVERY_USER_PROMPT: () => TEXT_LOOP_RECOVERY_USER_PROMPT,
|
|
26071
|
+
TIER_RANK: () => TIER_RANK,
|
|
26072
|
+
TOOL_DEFINITIONS: () => TOOL_DEFINITIONS,
|
|
26073
|
+
TOOL_USE_PROTOCOL_DIRECTIVE: () => TOOL_USE_PROTOCOL_DIRECTIVE,
|
|
26074
|
+
TURN_COMPLETION_MODULE: () => TURN_COMPLETION_MODULE,
|
|
26075
|
+
UnknownMemberError: () => UnknownMemberError,
|
|
26076
|
+
VAULT_TOOL_DEFINITIONS: () => VAULT_TOOL_DEFINITIONS,
|
|
26077
|
+
WEAKNESS_METER_PROMPT: () => WEAKNESS_METER_PROMPT,
|
|
26078
|
+
WeaknessMeterResponseSchema: () => WeaknessMeterResponseSchema,
|
|
26079
|
+
applyCompletionRetry: () => applyCompletionRetry,
|
|
26080
|
+
applyDeterministicAutofix: () => applyDeterministicAutofix,
|
|
26081
|
+
applyImplementationWriteRetry: () => applyImplementationWriteRetry,
|
|
26082
|
+
applyInlineJsAutofix: () => applyInlineJsAutofix,
|
|
26083
|
+
applyMotionAutofix: () => applyMotionAutofix,
|
|
26084
|
+
applyRetryIfMissing: () => applyRetryIfMissing,
|
|
26085
|
+
auditDegradedBanner: () => auditDegradedBanner,
|
|
26086
|
+
auditSynthesisTiers: () => auditSynthesisTiers,
|
|
26087
|
+
buildCouncilCompletion: () => buildCouncilCompletion,
|
|
26088
|
+
buildCustomParameters: () => buildCustomParameters,
|
|
26089
|
+
buildDeliveryFixPrompt: () => buildDeliveryFixPrompt,
|
|
26090
|
+
buildImplementationVerifyRetryPrompt: () => buildImplementationVerifyRetryPrompt,
|
|
26091
|
+
buildImplementationWriteRetryPrompt: () => buildImplementationWriteRetryPrompt,
|
|
26092
|
+
buildLanguageDirective: () => buildLanguageDirective,
|
|
26093
|
+
buildLanguagePolicyModule: () => buildLanguagePolicyModule,
|
|
26094
|
+
buildLanguagePolicyModuleFor: () => buildLanguagePolicyModuleFor,
|
|
26095
|
+
buildMissionBrief: () => buildMissionBrief,
|
|
26096
|
+
buildMotionFixPrompt: () => buildMotionFixPrompt,
|
|
26097
|
+
buildRetryPrompt: () => buildRetryPrompt,
|
|
26098
|
+
buildSkillDefinition: () => buildSkillDefinition,
|
|
26099
|
+
buildSystemPrompt: () => buildSystemPrompt,
|
|
26100
|
+
buildSystemPromptSplit: () => buildSystemPromptSplit,
|
|
26101
|
+
canRunParallel: () => canRunParallel,
|
|
26102
|
+
captureFailure: () => captureFailure,
|
|
26103
|
+
checkImplementationCompletion: () => checkImplementationCompletion,
|
|
26104
|
+
checkImplementationDelivery: () => checkImplementationDelivery,
|
|
26105
|
+
checkMemberToolEmissionSets: () => checkMemberToolEmissionSets,
|
|
26106
|
+
checkMemberToolEmissions: () => checkMemberToolEmissions,
|
|
26107
|
+
classifyMission: () => classifyMission,
|
|
26108
|
+
classifyTaskScope: () => classifyTaskScope,
|
|
26109
|
+
cleanAgentContent: () => cleanAgentContent,
|
|
26110
|
+
clearCustomTools: () => clearCustomTools,
|
|
26111
|
+
cliToolToEnhanced: () => cliToolToEnhanced,
|
|
26112
|
+
collapseLoopedAssistantText: () => collapseLoopedAssistantText,
|
|
26113
|
+
computeAgentSkills: () => computeAgentSkills,
|
|
26114
|
+
computeAgentTools: () => computeAgentTools,
|
|
26115
|
+
councilModeBanner: () => councilModeBanner,
|
|
26116
|
+
councilTierFromSize: () => councilTierFromSize,
|
|
26117
|
+
countByStatus: () => countByStatus,
|
|
26118
|
+
countEmittedWriteTools: () => countEmittedWriteTools,
|
|
26119
|
+
createBrainEvent: () => createBrainEvent,
|
|
26120
|
+
createDefaultSystemPromptConfig: () => createDefaultSystemPromptConfig,
|
|
26121
|
+
createGraph: () => createGraph,
|
|
26122
|
+
defaultPersonaParse: () => defaultPersonaParse,
|
|
26123
|
+
detectAssistantTextLoop: () => detectAssistantTextLoop,
|
|
26124
|
+
detectDegradedRun: () => detectDegradedRun,
|
|
26125
|
+
detectResponseLanguage: () => detectResponseLanguage,
|
|
26126
|
+
disjointScopeSets: () => disjointScopeSets,
|
|
26127
|
+
enforceDesignPhaseToolEmissions: () => enforceDesignPhaseToolEmissions,
|
|
26128
|
+
executeTool: () => executeTool,
|
|
26129
|
+
extractCitations: () => extractCitations,
|
|
26130
|
+
extractRequirementsBlock: () => extractRequirementsBlock,
|
|
26131
|
+
extractTaskScope: () => extractTaskScope,
|
|
26132
|
+
failedNodeIds: () => failedNodeIds,
|
|
26133
|
+
filterByWeakness: () => filterByWeakness,
|
|
26134
|
+
filterDeliveryBlockingFails: () => filterDeliveryBlockingFails,
|
|
26135
|
+
findCodingSkillsByCategory: () => findCodingSkillsByCategory,
|
|
26136
|
+
findCodingSkillsByTag: () => findCodingSkillsByTag,
|
|
26137
|
+
findSkillsByIds: () => findSkillsByIds,
|
|
26138
|
+
findSkillsByTag: () => findSkillsByTag,
|
|
26139
|
+
formatLessonsForContext: () => formatLessonsForContext,
|
|
26140
|
+
getAgent: () => getAgent,
|
|
26141
|
+
getAllTools: () => getAllTools,
|
|
26142
|
+
getAvailableTools: () => getAvailableTools,
|
|
26143
|
+
getBasePromptModules: () => getBasePromptModules,
|
|
26144
|
+
getBuiltinSkillIds: () => getBuiltinSkillIds,
|
|
26145
|
+
getCodingSkillById: () => getCodingSkillById,
|
|
26146
|
+
getCouncilAgents: () => getCouncilAgents,
|
|
26147
|
+
getCouncilDirectiveModules: () => getCouncilDirectiveModules,
|
|
26148
|
+
getPersona: () => getPersona,
|
|
26149
|
+
getPromptModule: () => getPromptModule,
|
|
26150
|
+
getProviderTools: () => getProviderTools,
|
|
26151
|
+
getReadyNodes: () => getReadyNodes,
|
|
26152
|
+
getSkillById: () => getSkillById,
|
|
26153
|
+
getSkillMetadata: () => getSkillMetadata,
|
|
26154
|
+
getSkillsByCategory: () => getSkillsByCategory,
|
|
26155
|
+
getToolDescriptions: () => getToolDescriptions,
|
|
26156
|
+
hasInteractiveClarification: () => hasInteractiveClarification,
|
|
26157
|
+
hashToolCall: () => hashToolCall,
|
|
26158
|
+
isAnswerLeak: () => isAnswerLeak,
|
|
26159
|
+
isBrainAgentEndEvent: () => isBrainAgentEndEvent,
|
|
26160
|
+
isBrainAgentStartEvent: () => isBrainAgentStartEvent,
|
|
26161
|
+
isBrainCouncilModeEvent: () => isBrainCouncilModeEvent,
|
|
26162
|
+
isBrainErrorEvent: () => isBrainErrorEvent,
|
|
26163
|
+
isBrainMemberCostEvent: () => isBrainMemberCostEvent,
|
|
26164
|
+
isBrainMessageDeltaEvent: () => isBrainMessageDeltaEvent,
|
|
26165
|
+
isBrainMessageEndEvent: () => isBrainMessageEndEvent,
|
|
26166
|
+
isBrainMessageStartEvent: () => isBrainMessageStartEvent,
|
|
26167
|
+
isBrainQueueUpdateEvent: () => isBrainQueueUpdateEvent,
|
|
26168
|
+
isBrainSessionCompactedEvent: () => isBrainSessionCompactedEvent,
|
|
26169
|
+
isBrainThinkingDeltaEvent: () => isBrainThinkingDeltaEvent,
|
|
26170
|
+
isBrainToolExecutionEndEvent: () => isBrainToolExecutionEndEvent,
|
|
26171
|
+
isBrainToolExecutionStartEvent: () => isBrainToolExecutionStartEvent,
|
|
26172
|
+
isBrainToolExecutionUpdateEvent: () => isBrainToolExecutionUpdateEvent,
|
|
26173
|
+
isConverged: () => isConverged,
|
|
26174
|
+
isReviewerKind: () => isReviewerKind,
|
|
26175
|
+
isSettled: () => isSettled,
|
|
26176
|
+
isStatusTheaterUnit: () => isStatusTheaterUnit,
|
|
26177
|
+
isValidTool: () => isValidTool,
|
|
26178
|
+
isVerifyToolCheckSkipped: () => isVerifyToolCheckSkipped,
|
|
26179
|
+
jaccardSimilarity: () => jaccardSimilarity,
|
|
26180
|
+
lintSynthesisHonesty: () => lintSynthesisHonesty,
|
|
26181
|
+
listCodingSkills: () => listCodingSkills,
|
|
26182
|
+
listPersonas: () => listPersonas,
|
|
26183
|
+
listSkills: () => listSkills,
|
|
26184
|
+
loadNfrSpec: () => loadNfrSpec,
|
|
26185
|
+
matchCheckPrefix: () => matchCheckPrefix,
|
|
26186
|
+
normalizeForSignature: () => normalizeForSignature,
|
|
26187
|
+
normalizeLoopUnit: () => normalizeLoopUnit,
|
|
26188
|
+
normalizeScopePath: () => normalizeScopePath,
|
|
26189
|
+
normalizeTextToolArgs: () => normalizeTextToolArgs,
|
|
26190
|
+
parseClarificationRequest: () => parseClarificationRequest,
|
|
26191
|
+
parseEvidenceTier: () => parseEvidenceTier,
|
|
26192
|
+
parseMinimaxStyleToolCalls: () => parseMinimaxStyleToolCalls,
|
|
26193
|
+
parsePersonaVerdict: () => parsePersonaVerdict,
|
|
26194
|
+
parseProjectRootFromWorkspaceContext: () => parseProjectRootFromWorkspaceContext,
|
|
26195
|
+
parseTextToolCalls: () => parseTextToolCalls,
|
|
26196
|
+
parseThinking: () => parseThinking,
|
|
26197
|
+
parseVerificationTable: () => parseVerificationTable,
|
|
26198
|
+
parseVerifyVerdict: () => parseVerifyVerdict,
|
|
26199
|
+
pathsOverlap: () => pathsOverlap,
|
|
26200
|
+
pickWeakest: () => pickWeakest,
|
|
26201
|
+
promoteMember: () => promoteMember,
|
|
26202
|
+
rankByWeakness: () => rankByWeakness,
|
|
26203
|
+
readLessonsDeduped: () => readLessonsDeduped,
|
|
26204
|
+
readSession: () => readSession,
|
|
26205
|
+
recallLessons: () => recallLessons,
|
|
26206
|
+
registerCodingSkill: () => registerCodingSkill,
|
|
26207
|
+
registerCustomTool: () => registerCustomTool,
|
|
26208
|
+
registerPersona: () => registerPersona,
|
|
26209
|
+
registerSkill: () => registerSkill,
|
|
26210
|
+
renderSkillMarkdown: () => renderSkillMarkdown,
|
|
26211
|
+
replayChairmanTextTools: () => replayChairmanTextTools,
|
|
26212
|
+
resolveAgentSkills: () => resolveAgentSkills,
|
|
26213
|
+
resolveCouncilRunMode: () => resolveCouncilRunMode,
|
|
26214
|
+
resolveMaxTentacles: () => resolveMaxTentacles,
|
|
26215
|
+
resolvePlanTimeoutMs: () => resolvePlanTimeoutMs,
|
|
26216
|
+
resolveResponseLanguage: () => resolveResponseLanguage,
|
|
26217
|
+
resolveRoleSystemPrompt: () => resolveRoleSystemPrompt,
|
|
26218
|
+
resolveSkillDependencies: () => resolveSkillDependencies,
|
|
26219
|
+
resolveVerifyRetryTool: () => resolveVerifyRetryTool,
|
|
26220
|
+
restrictImplementationWrites: () => restrictImplementationWrites,
|
|
26221
|
+
runChairmanDeliveryLoop: () => runChairmanDeliveryLoop,
|
|
26222
|
+
runChairmanFixLoop: () => runChairmanFixLoop,
|
|
26223
|
+
runChairmanMicroGate: () => runChairmanMicroGate,
|
|
26224
|
+
runCouncilPure: () => runCouncilPure,
|
|
26225
|
+
runImplementationVerification: () => runImplementationVerification,
|
|
26226
|
+
runInSandbox: () => runInSandbox,
|
|
26227
|
+
runMicroVerificationOnFile: () => runMicroVerificationOnFile,
|
|
26228
|
+
runRetryTurnForMember: () => runRetryTurnForMember,
|
|
26229
|
+
scanForFootguns: () => scanForFootguns,
|
|
26230
|
+
scanKeyframesViolations: () => scanKeyframesViolations,
|
|
26231
|
+
scanTransitionViolations: () => scanTransitionViolations,
|
|
26232
|
+
scrubProprietaryLeak: () => scrubProprietaryLeak,
|
|
26233
|
+
selectParallelWave: () => selectParallelWave,
|
|
26234
|
+
setWorkspaceStubs: () => setWorkspaceStubs,
|
|
26235
|
+
shouldRetryMember: () => shouldRetryMember,
|
|
26236
|
+
slugify: () => slugify2,
|
|
26237
|
+
specificityFromAssumptions: () => specificityFromAssumptions,
|
|
26238
|
+
stripClarificationProtocol: () => stripClarificationProtocol,
|
|
26239
|
+
swapMembers: () => swapMembers,
|
|
26240
|
+
systemMessagesFromSplit: () => systemMessagesFromSplit,
|
|
26241
|
+
taskMatchesNfrKeywords: () => taskMatchesNfrKeywords,
|
|
26242
|
+
tierAtLeast: () => tierAtLeast,
|
|
26243
|
+
tokenizeForSignature: () => tokenizeForSignature,
|
|
26244
|
+
topoLevels: () => topoLevels,
|
|
26245
|
+
unregisterCustomTool: () => unregisterCustomTool,
|
|
26246
|
+
unregisterSkill: () => unregisterSkill,
|
|
26247
|
+
validateCodingSkillRequires: () => validateCodingSkillRequires,
|
|
26248
|
+
validateGraph: () => validateGraph,
|
|
26249
|
+
verifyCitations: () => verifyCitations,
|
|
26250
|
+
warnIfNfrSpecMissing: () => warnIfNfrSpecMissing,
|
|
26251
|
+
weaknessFromMeter: () => weaknessFromMeter,
|
|
26252
|
+
weaknessFromVerdict: () => weaknessFromVerdict,
|
|
26253
|
+
weaknessScoreFromText: () => weaknessScoreFromText,
|
|
26254
|
+
wrapLegacyStream: () => wrapLegacyStream,
|
|
26255
|
+
writeCouncilCompletion: () => writeCouncilCompletion,
|
|
26256
|
+
writeVerificationReport: () => writeVerificationReport
|
|
26257
|
+
});
|
|
25133
26258
|
var init_dist = __esm({
|
|
25134
26259
|
"packages/core/dist/index.js"() {
|
|
25135
26260
|
"use strict";
|
|
@@ -25773,9 +26898,9 @@ function spillToolOutput(fullText, meta3) {
|
|
|
25773
26898
|
const rnd = randomBytes(3).toString("hex");
|
|
25774
26899
|
const safeTool = (meta3?.toolName ?? "tool").replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 32);
|
|
25775
26900
|
const file2 = `${stamp}-${safeTool}-${hash3}-${rnd}.txt`;
|
|
25776
|
-
const
|
|
25777
|
-
writeFileSync10(
|
|
25778
|
-
return
|
|
26901
|
+
const path47 = join11(dir, file2);
|
|
26902
|
+
writeFileSync10(path47, fullText, "utf8");
|
|
26903
|
+
return path47;
|
|
25779
26904
|
} catch {
|
|
25780
26905
|
return null;
|
|
25781
26906
|
}
|
|
@@ -25791,21 +26916,21 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
25791
26916
|
if (text.length === 0)
|
|
25792
26917
|
return text;
|
|
25793
26918
|
const opts = typeof capOrOpts === "number" ? { cap: capOrOpts } : capOrOpts ?? {};
|
|
25794
|
-
const
|
|
26919
|
+
const cap3 = typeof opts.cap === "number" && Number.isFinite(opts.cap) && opts.cap >= 10 ? opts.cap : TOOL_RESULT_LINE_CAP;
|
|
25795
26920
|
const doSpill = opts.spill !== false;
|
|
25796
26921
|
const lines = text.split("\n");
|
|
25797
|
-
const charBudget =
|
|
25798
|
-
const overLines = lines.length >
|
|
25799
|
-
const overChars = text.length > charBudget && lines.length <=
|
|
26922
|
+
const charBudget = cap3 * 80;
|
|
26923
|
+
const overLines = lines.length > cap3;
|
|
26924
|
+
const overChars = text.length > charBudget && lines.length <= cap3;
|
|
25800
26925
|
if (!overLines && !overChars)
|
|
25801
26926
|
return text;
|
|
25802
26927
|
let preview;
|
|
25803
26928
|
let marker;
|
|
25804
26929
|
if (overLines) {
|
|
25805
|
-
const half = Math.floor(
|
|
26930
|
+
const half = Math.floor(cap3 / 2);
|
|
25806
26931
|
const head = lines.slice(0, half);
|
|
25807
26932
|
const tail = lines.slice(lines.length - half);
|
|
25808
|
-
const omitted = lines.length -
|
|
26933
|
+
const omitted = lines.length - cap3;
|
|
25809
26934
|
marker = `+${omitted} lines omitted \u2014 showing head:${half}, tail:${half} of ${lines.length} total`;
|
|
25810
26935
|
preview = head.join("\n") + `
|
|
25811
26936
|
\u2026 [${marker}] \u2026
|
|
@@ -25821,10 +26946,10 @@ function truncateToolResult(text, capOrOpts = TOOL_RESULT_LINE_CAP) {
|
|
|
25821
26946
|
${tail}`;
|
|
25822
26947
|
}
|
|
25823
26948
|
if (doSpill) {
|
|
25824
|
-
const
|
|
25825
|
-
if (
|
|
26949
|
+
const path47 = spillToolOutput(text, { toolName: opts.toolName });
|
|
26950
|
+
if (path47) {
|
|
25826
26951
|
const spillNote = `
|
|
25827
|
-
\u2026 [full output spilled to: ${
|
|
26952
|
+
\u2026 [full output spilled to: ${path47} \u2014 re-read with read_file if you need the complete text] \u2026`;
|
|
25828
26953
|
if (preview.includes("] \u2026\n")) {
|
|
25829
26954
|
preview = preview.replace("] \u2026\n", `] \u2026${spillNote}
|
|
25830
26955
|
`);
|
|
@@ -25836,7 +26961,7 @@ ${tail}`;
|
|
|
25836
26961
|
return preview;
|
|
25837
26962
|
}
|
|
25838
26963
|
var TOOL_NAME_ALIASES, TOOL_RESULT_LINE_CAP, ToolRegistry;
|
|
25839
|
-
var
|
|
26964
|
+
var init_registry2 = __esm({
|
|
25840
26965
|
"packages/core/dist/core/tools/registry.js"() {
|
|
25841
26966
|
"use strict";
|
|
25842
26967
|
init_zodBridge();
|
|
@@ -26770,7 +27895,7 @@ async function runTentacle(opts) {
|
|
|
26770
27895
|
model: sub.model,
|
|
26771
27896
|
provider: sub.provider,
|
|
26772
27897
|
messages: [
|
|
26773
|
-
{ role: "system", content: systemPromptForAgent(agent) },
|
|
27898
|
+
{ role: "system", content: opts.systemPromptOverride ?? systemPromptForAgent(agent) },
|
|
26774
27899
|
{ role: "user", content: userContent }
|
|
26775
27900
|
],
|
|
26776
27901
|
tools: sub.tools,
|
|
@@ -28765,21 +29890,21 @@ function normalizeAuth(auth) {
|
|
|
28765
29890
|
return "agent";
|
|
28766
29891
|
}
|
|
28767
29892
|
function readSecrets() {
|
|
28768
|
-
const
|
|
28769
|
-
if (!existsSync17(
|
|
29893
|
+
const path47 = getSshSecretsPath();
|
|
29894
|
+
if (!existsSync17(path47)) return {};
|
|
28770
29895
|
try {
|
|
28771
|
-
return JSON.parse(readFileSync16(
|
|
29896
|
+
return JSON.parse(readFileSync16(path47, "utf8"));
|
|
28772
29897
|
} catch {
|
|
28773
29898
|
return {};
|
|
28774
29899
|
}
|
|
28775
29900
|
}
|
|
28776
29901
|
function writeSecrets(data) {
|
|
28777
|
-
const
|
|
28778
|
-
mkdirSync9(dirname2(
|
|
28779
|
-
writeFileSync11(
|
|
29902
|
+
const path47 = getSshSecretsPath();
|
|
29903
|
+
mkdirSync9(dirname2(path47), { recursive: true });
|
|
29904
|
+
writeFileSync11(path47, `${JSON.stringify(data, null, 2)}
|
|
28780
29905
|
`, "utf8");
|
|
28781
29906
|
try {
|
|
28782
|
-
chmodSync(
|
|
29907
|
+
chmodSync(path47, 384);
|
|
28783
29908
|
} catch {
|
|
28784
29909
|
}
|
|
28785
29910
|
}
|
|
@@ -28808,10 +29933,10 @@ function deleteSshPassword(id) {
|
|
|
28808
29933
|
writeSecrets({ passwords });
|
|
28809
29934
|
}
|
|
28810
29935
|
function readStore2() {
|
|
28811
|
-
const
|
|
28812
|
-
if (!existsSync17(
|
|
29936
|
+
const path47 = getSshTargetsPath();
|
|
29937
|
+
if (!existsSync17(path47)) return [];
|
|
28813
29938
|
try {
|
|
28814
|
-
const parsed = JSON.parse(readFileSync16(
|
|
29939
|
+
const parsed = JSON.parse(readFileSync16(path47, "utf8"));
|
|
28815
29940
|
const list = Array.isArray(parsed.targets) ? parsed.targets : [];
|
|
28816
29941
|
return list.filter(
|
|
28817
29942
|
(t) => t && typeof t.id === "string" && typeof t.host === "string" && typeof t.user === "string"
|
|
@@ -28826,11 +29951,11 @@ function readStore2() {
|
|
|
28826
29951
|
}
|
|
28827
29952
|
}
|
|
28828
29953
|
function writeStore2(targets) {
|
|
28829
|
-
const
|
|
28830
|
-
mkdirSync9(dirname2(
|
|
29954
|
+
const path47 = getSshTargetsPath();
|
|
29955
|
+
mkdirSync9(dirname2(path47), { recursive: true });
|
|
28831
29956
|
const clean = targets.map(({ hasPassword: _hp, ...t }) => t);
|
|
28832
29957
|
writeFileSync11(
|
|
28833
|
-
|
|
29958
|
+
path47,
|
|
28834
29959
|
`${JSON.stringify({ targets: clean }, null, 2)}
|
|
28835
29960
|
`,
|
|
28836
29961
|
"utf8"
|
|
@@ -28989,12 +30114,12 @@ function runSsh(target, remoteCommand, timeoutMs = 6e4) {
|
|
|
28989
30114
|
});
|
|
28990
30115
|
let stdout = "";
|
|
28991
30116
|
let stderr = "";
|
|
28992
|
-
const
|
|
30117
|
+
const cap3 = 4e4;
|
|
28993
30118
|
child.stdout?.on("data", (d) => {
|
|
28994
|
-
if (stdout.length <
|
|
30119
|
+
if (stdout.length < cap3) stdout += d.toString("utf8");
|
|
28995
30120
|
});
|
|
28996
30121
|
child.stderr?.on("data", (d) => {
|
|
28997
|
-
if (stderr.length <
|
|
30122
|
+
if (stderr.length < cap3) stderr += d.toString("utf8");
|
|
28998
30123
|
});
|
|
28999
30124
|
const timer = setTimeout(() => {
|
|
29000
30125
|
child.kill("SIGTERM");
|
|
@@ -29076,11 +30201,11 @@ function formatSshTargetsForPrompt() {
|
|
|
29076
30201
|
];
|
|
29077
30202
|
for (const t of targets) {
|
|
29078
30203
|
const tags = t.tags?.length ? ` tags=[${t.tags.join(",")}]` : "";
|
|
29079
|
-
const
|
|
30204
|
+
const path47 = t.defaultRemotePath ? ` remotePath=${t.defaultRemotePath}` : "";
|
|
29080
30205
|
const allow = t.allowedCommands?.length ? ` allowed=${t.allowedCommands.join("|")}` : " allowed=status-only";
|
|
29081
30206
|
const auth = t.auth === "password" ? " auth=password" : t.auth === "keyPath" ? " auth=key" : " auth=agent";
|
|
29082
30207
|
lines.push(
|
|
29083
|
-
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${
|
|
30208
|
+
`- id=${t.id} name=${t.name} ${t.user}@${t.host}:${t.port ?? 22}${auth}${path47}${tags}${allow}`
|
|
29084
30209
|
);
|
|
29085
30210
|
}
|
|
29086
30211
|
return lines.join("\n");
|
|
@@ -29591,7 +30716,8 @@ __export(krakenModel_exports, {
|
|
|
29591
30716
|
isKrakenAutoModelEnabled: () => isKrakenAutoModelEnabled,
|
|
29592
30717
|
pickCheapModel: () => pickCheapModel,
|
|
29593
30718
|
resolveKrakenSubModel: () => resolveKrakenSubModel,
|
|
29594
|
-
resolveKrakenSubModelAsync: () => resolveKrakenSubModelAsync
|
|
30719
|
+
resolveKrakenSubModelAsync: () => resolveKrakenSubModelAsync,
|
|
30720
|
+
resolvePersonaModel: () => resolvePersonaModel
|
|
29595
30721
|
});
|
|
29596
30722
|
function isCheapModelId(id) {
|
|
29597
30723
|
if (!id) return false;
|
|
@@ -29641,6 +30767,12 @@ function resolveKrakenSubModel(agent, parentModel, env = process.env, opts = {})
|
|
|
29641
30767
|
}
|
|
29642
30768
|
return parentModel;
|
|
29643
30769
|
}
|
|
30770
|
+
function resolvePersonaModel(kind, parentModel, env = process.env, opts = {}) {
|
|
30771
|
+
const personaKey = kind === "spec" ? "ZELARI_KRAKEN_SPEC_MODEL" : kind === "conformance" ? "ZELARI_KRAKEN_CONFORMANCE_MODEL" : kind === "oracle" ? "ZELARI_KRAKEN_ORACLE_MODEL" : "";
|
|
30772
|
+
const specific = personaKey ? env[personaKey]?.trim() : void 0;
|
|
30773
|
+
if (specific) return specific;
|
|
30774
|
+
return resolveKrakenSubModel("verify", parentModel, env, opts);
|
|
30775
|
+
}
|
|
29644
30776
|
async function resolveKrakenSubModelAsync(agent, parentModel, env = process.env, opts = {}) {
|
|
29645
30777
|
let candidates = [];
|
|
29646
30778
|
if (opts.provider) {
|
|
@@ -29690,7 +30822,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29690
30822
|
const safeBash = wrapWithShellSafety(bashTool, audit, sessionId);
|
|
29691
30823
|
const safeFetchUrl = wrapWithAudit(fetchUrlTool, audit, sessionId);
|
|
29692
30824
|
const safeWebSearch = wrapWithAudit(webSearchTool, audit, sessionId);
|
|
29693
|
-
const
|
|
30825
|
+
const registry4 = new ToolRegistry();
|
|
29694
30826
|
const profile = options.profile ?? "full";
|
|
29695
30827
|
const readOnly = options.readOnly === true || options.planMode === true || profile === "explore";
|
|
29696
30828
|
const verifyMode = profile === "verify";
|
|
@@ -29698,34 +30830,34 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29698
30830
|
const allowBash = allowMutators || verifyMode;
|
|
29699
30831
|
const permPolicy = options.permissionPolicy ?? defaultPermissionPolicy();
|
|
29700
30832
|
const withPerm = (t) => wrapWithPermissions(t, permPolicy, options.onPermissionAsk);
|
|
29701
|
-
|
|
29702
|
-
|
|
29703
|
-
|
|
29704
|
-
|
|
29705
|
-
|
|
29706
|
-
|
|
30833
|
+
registry4.register(withPerm(safeReadFile));
|
|
30834
|
+
registry4.register(withPerm(safeGrepContent));
|
|
30835
|
+
registry4.register(withPerm(safeListFiles));
|
|
30836
|
+
registry4.register(withPerm(safeShowDiff));
|
|
30837
|
+
registry4.register(withPerm(safeFetchUrl));
|
|
30838
|
+
registry4.register(withPerm(safeWebSearch));
|
|
29707
30839
|
if (allowMutators) {
|
|
29708
|
-
|
|
29709
|
-
|
|
29710
|
-
|
|
30840
|
+
registry4.register(withPerm(safeWriteFile));
|
|
30841
|
+
registry4.register(withPerm(safeEditFile));
|
|
30842
|
+
registry4.register(withPerm(safeApplyDiff));
|
|
29711
30843
|
}
|
|
29712
30844
|
if (allowBash) {
|
|
29713
|
-
|
|
30845
|
+
registry4.register(withPerm(safeBash));
|
|
29714
30846
|
}
|
|
29715
30847
|
const askUserTool = options.readOnly === true || profile === "explore" || profile === "verify" ? null : createAskUserTool(options.onAskUser);
|
|
29716
30848
|
if (askUserTool) {
|
|
29717
|
-
|
|
30849
|
+
registry4.register(withPerm(askUserTool));
|
|
29718
30850
|
}
|
|
29719
30851
|
const enableSkill = options.enableSkill !== false && options.readOnly !== true && profile !== "explore" && profile !== "verify";
|
|
29720
30852
|
const skillTool = enableSkill ? withPerm(createSkillTool({ cwd: root })) : null;
|
|
29721
30853
|
if (skillTool) {
|
|
29722
|
-
|
|
30854
|
+
registry4.register(skillTool);
|
|
29723
30855
|
}
|
|
29724
30856
|
const enableTodos = options.enableTodos !== false && options.readOnly !== true && profile === "full";
|
|
29725
30857
|
const todoWrite = enableTodos ? withPerm(createTodoWriteTool()) : null;
|
|
29726
30858
|
const todoRead = enableTodos ? withPerm(createTodoReadTool()) : null;
|
|
29727
|
-
if (todoWrite)
|
|
29728
|
-
if (todoRead)
|
|
30859
|
+
if (todoWrite) registry4.register(todoWrite);
|
|
30860
|
+
if (todoRead) registry4.register(todoRead);
|
|
29729
30861
|
const summary = [
|
|
29730
30862
|
safeReadFile,
|
|
29731
30863
|
safeGrepContent,
|
|
@@ -29747,13 +30879,13 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29747
30879
|
}));
|
|
29748
30880
|
if (process.env.ZELARI_AST !== "0") {
|
|
29749
30881
|
for (const t of createAstTools()) {
|
|
29750
|
-
|
|
30882
|
+
registry4.register(t);
|
|
29751
30883
|
tools.push({ name: t.name, description: t.description, permissions: t.permissions ?? [] });
|
|
29752
30884
|
}
|
|
29753
30885
|
}
|
|
29754
30886
|
if (process.env.ZELARI_SEMANTIC !== "0") {
|
|
29755
30887
|
const semanticTool = createSemanticTool({ root });
|
|
29756
|
-
|
|
30888
|
+
registry4.register(semanticTool);
|
|
29757
30889
|
tools.push({
|
|
29758
30890
|
name: semanticTool.name,
|
|
29759
30891
|
description: semanticTool.description,
|
|
@@ -29762,7 +30894,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29762
30894
|
}
|
|
29763
30895
|
if (!readOnly && process.env.ZELARI_BROWSER !== "0") {
|
|
29764
30896
|
const browserTool = createBrowserTool();
|
|
29765
|
-
|
|
30897
|
+
registry4.register(browserTool);
|
|
29766
30898
|
tools.push({
|
|
29767
30899
|
name: browserTool.name,
|
|
29768
30900
|
description: browserTool.description,
|
|
@@ -29771,7 +30903,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29771
30903
|
}
|
|
29772
30904
|
if (!readOnly && process.env.ZELARI_SSH !== "0") {
|
|
29773
30905
|
for (const t of createSshTools()) {
|
|
29774
|
-
|
|
30906
|
+
registry4.register(t);
|
|
29775
30907
|
tools.push({
|
|
29776
30908
|
name: t.name,
|
|
29777
30909
|
description: t.description,
|
|
@@ -29782,7 +30914,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29782
30914
|
if (!readOnly) {
|
|
29783
30915
|
for (const t of createWorldModelTools()) {
|
|
29784
30916
|
const safe = wrapWithAudit(t, audit, sessionId);
|
|
29785
|
-
|
|
30917
|
+
registry4.register(safe);
|
|
29786
30918
|
tools.push({
|
|
29787
30919
|
name: t.name,
|
|
29788
30920
|
description: t.description,
|
|
@@ -29795,7 +30927,7 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29795
30927
|
const taskTool = createTaskTool({
|
|
29796
30928
|
createSubAgentContext: createKrakenSubAgentContextFactory({ root, audit, sessionId })
|
|
29797
30929
|
});
|
|
29798
|
-
|
|
30930
|
+
registry4.register(withPerm(taskTool));
|
|
29799
30931
|
tools.push({
|
|
29800
30932
|
name: taskTool.name,
|
|
29801
30933
|
description: taskTool.description,
|
|
@@ -29805,17 +30937,17 @@ function createBuiltinToolRegistry(options = {}) {
|
|
|
29805
30937
|
if (!readOnly && process.env.ZELARI_LSP !== "0" && options.lspProvider !== null) {
|
|
29806
30938
|
const lspTools = options.lspProvider ? createLspTools(options.lspProvider, root) : createLspTools(getSharedLspManager(root), root);
|
|
29807
30939
|
for (const t of lspTools) {
|
|
29808
|
-
|
|
30940
|
+
registry4.register(t);
|
|
29809
30941
|
tools.push({ name: t.name, description: t.description, permissions: t.permissions ?? [] });
|
|
29810
30942
|
}
|
|
29811
30943
|
}
|
|
29812
|
-
return { registry:
|
|
30944
|
+
return { registry: registry4, tools };
|
|
29813
30945
|
}
|
|
29814
|
-
function getCliToolCatalogEntries(
|
|
30946
|
+
function getCliToolCatalogEntries(registry4) {
|
|
29815
30947
|
const entries = [];
|
|
29816
|
-
for (const name of
|
|
30948
|
+
for (const name of registry4.list()) {
|
|
29817
30949
|
if (HARNESS_BUILTIN_NAMES.has(name)) continue;
|
|
29818
|
-
const def =
|
|
30950
|
+
const def = registry4.get(name);
|
|
29819
30951
|
if (!def) continue;
|
|
29820
30952
|
try {
|
|
29821
30953
|
entries.push(cliToolToEnhanced(def));
|
|
@@ -29824,8 +30956,8 @@ function getCliToolCatalogEntries(registry3) {
|
|
|
29824
30956
|
}
|
|
29825
30957
|
return entries;
|
|
29826
30958
|
}
|
|
29827
|
-
function registerCliToolsIntoCouncilCatalog(
|
|
29828
|
-
for (const entry of getCliToolCatalogEntries(
|
|
30959
|
+
function registerCliToolsIntoCouncilCatalog(registry4) {
|
|
30960
|
+
for (const entry of getCliToolCatalogEntries(registry4)) {
|
|
29829
30961
|
try {
|
|
29830
30962
|
registerCustomTool(entry);
|
|
29831
30963
|
} catch {
|
|
@@ -30072,7 +31204,7 @@ var HARNESS_BUILTIN_NAMES;
|
|
|
30072
31204
|
var init_toolRegistry = __esm({
|
|
30073
31205
|
"src/cli/toolRegistry.ts"() {
|
|
30074
31206
|
"use strict";
|
|
30075
|
-
|
|
31207
|
+
init_registry2();
|
|
30076
31208
|
init_filesystem();
|
|
30077
31209
|
init_shell();
|
|
30078
31210
|
init_search();
|
|
@@ -31425,7 +32557,7 @@ __export(composeContext_exports, {
|
|
|
31425
32557
|
});
|
|
31426
32558
|
import { existsSync as existsSync23, readdirSync as readdirSync4, readFileSync as readFileSync19 } from "node:fs";
|
|
31427
32559
|
import { join as join20 } from "node:path";
|
|
31428
|
-
function
|
|
32560
|
+
function cap2(text, max, label) {
|
|
31429
32561
|
if (!text || text.length <= max) return { text: text || "", truncated: false };
|
|
31430
32562
|
return {
|
|
31431
32563
|
text: text.slice(0, max) + `
|
|
@@ -31469,7 +32601,7 @@ function buildDesignIndex(projectRoot, maxChars) {
|
|
|
31469
32601
|
}
|
|
31470
32602
|
}
|
|
31471
32603
|
const raw = lines.join("\n");
|
|
31472
|
-
return
|
|
32604
|
+
return cap2(raw, maxChars, "design-index").text;
|
|
31473
32605
|
}
|
|
31474
32606
|
function composeProjectContext(input) {
|
|
31475
32607
|
const cwd = input.cwd ?? process.cwd();
|
|
@@ -31523,7 +32655,7 @@ function composeProjectContext(input) {
|
|
|
31523
32655
|
default: 12e3,
|
|
31524
32656
|
min: 2e3
|
|
31525
32657
|
});
|
|
31526
|
-
const totalCapped =
|
|
32658
|
+
const totalCapped = cap2(workspaceContext, totalCap, "workspaceContext");
|
|
31527
32659
|
workspaceContext = totalCapped.text;
|
|
31528
32660
|
if (totalCapped.truncated) {
|
|
31529
32661
|
warnings.push(
|
|
@@ -31541,14 +32673,14 @@ function composeProjectContext(input) {
|
|
|
31541
32673
|
}
|
|
31542
32674
|
const ragParts = [];
|
|
31543
32675
|
if (durableRaw) {
|
|
31544
|
-
const d =
|
|
32676
|
+
const d = cap2(durableRaw, durableMax, "durable-state");
|
|
31545
32677
|
ragParts.push(d.text);
|
|
31546
32678
|
if (d.truncated) {
|
|
31547
32679
|
warnings.push(`[context] durable state truncated to ${durableMax} chars.`);
|
|
31548
32680
|
}
|
|
31549
32681
|
}
|
|
31550
32682
|
if (input.memoryHits?.trim()) {
|
|
31551
|
-
const m =
|
|
32683
|
+
const m = cap2(input.memoryHits.trim(), memoryMax, "memory");
|
|
31552
32684
|
ragParts.push(m.text);
|
|
31553
32685
|
if (m.truncated) warnings.push(`[context] memory RAG truncated to ${memoryMax} chars.`);
|
|
31554
32686
|
}
|
|
@@ -31932,28 +33064,28 @@ var init_storage = __esm({
|
|
|
31932
33064
|
VALID_SCALARS = /^(true|false|null|~)$/i;
|
|
31933
33065
|
Storage = class {
|
|
31934
33066
|
/** Read a Markdown file with frontmatter. Throws if not found. */
|
|
31935
|
-
read(
|
|
31936
|
-
if (!existsSync25(
|
|
31937
|
-
throw new Error(`File not found: ${
|
|
33067
|
+
read(path47) {
|
|
33068
|
+
if (!existsSync25(path47)) {
|
|
33069
|
+
throw new Error(`File not found: ${path47}`);
|
|
31938
33070
|
}
|
|
31939
|
-
const md = readFileSync21(
|
|
33071
|
+
const md = readFileSync21(path47, "utf8");
|
|
31940
33072
|
return parseFrontmatter(md);
|
|
31941
33073
|
}
|
|
31942
33074
|
/** Read a Markdown file; returns null if not found. */
|
|
31943
|
-
readIfExists(
|
|
31944
|
-
if (!existsSync25(
|
|
31945
|
-
return this.read(
|
|
33075
|
+
readIfExists(path47) {
|
|
33076
|
+
if (!existsSync25(path47)) return null;
|
|
33077
|
+
return this.read(path47);
|
|
31946
33078
|
}
|
|
31947
33079
|
/**
|
|
31948
33080
|
* Write a Markdown file atomically (tmp + rename). Creates parent dirs.
|
|
31949
33081
|
* The meta object is serialized as YAML frontmatter; body as Markdown.
|
|
31950
33082
|
*/
|
|
31951
|
-
write(
|
|
31952
|
-
mkdirSync11(dirname4(
|
|
31953
|
-
const tmp =
|
|
33083
|
+
write(path47, meta3, body) {
|
|
33084
|
+
mkdirSync11(dirname4(path47), { recursive: true });
|
|
33085
|
+
const tmp = path47 + ".tmp-" + process.pid;
|
|
31954
33086
|
const md = serializeFrontmatter(meta3, body);
|
|
31955
33087
|
writeFileSync13(tmp, md, "utf8");
|
|
31956
|
-
renameSync2(tmp,
|
|
33088
|
+
renameSync2(tmp, path47);
|
|
31957
33089
|
}
|
|
31958
33090
|
/** List all .md files in a directory (non-recursive). */
|
|
31959
33091
|
listMarkdown(dir) {
|
|
@@ -32031,8 +33163,8 @@ function readPlan(ctx) {
|
|
|
32031
33163
|
} catch {
|
|
32032
33164
|
}
|
|
32033
33165
|
}
|
|
32034
|
-
const
|
|
32035
|
-
const doc = ctx.storage.readIfExists(
|
|
33166
|
+
const path47 = workspaceFile(ctx.rootDir, "plan");
|
|
33167
|
+
const doc = ctx.storage.readIfExists(path47);
|
|
32036
33168
|
if (!doc) return { phases: [], tasks: [], milestones: [] };
|
|
32037
33169
|
const meta3 = doc.meta;
|
|
32038
33170
|
return {
|
|
@@ -32197,7 +33329,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
32197
33329
|
dueDate: input.dueDate,
|
|
32198
33330
|
targetVersion: version2
|
|
32199
33331
|
});
|
|
32200
|
-
const
|
|
33332
|
+
const path47 = join23(ctx.rootDir, "milestones", `${id}.md`);
|
|
32201
33333
|
const meta3 = {
|
|
32202
33334
|
kind: "milestone",
|
|
32203
33335
|
id,
|
|
@@ -32214,7 +33346,7 @@ function addMilestoneRecord(ctx, summary, input) {
|
|
|
32214
33346
|
`Target version: ${version2}`,
|
|
32215
33347
|
""
|
|
32216
33348
|
].join("\n");
|
|
32217
|
-
ctx.storage.write(
|
|
33349
|
+
ctx.storage.write(path47, meta3, body);
|
|
32218
33350
|
return { id, created: true };
|
|
32219
33351
|
}
|
|
32220
33352
|
function readPlanSummary(ctx) {
|
|
@@ -32418,7 +33550,7 @@ function addIdeaStub(ctx) {
|
|
|
32418
33550
|
const tags = args["tags"] ?? [];
|
|
32419
33551
|
const category = args["category"] ?? "General";
|
|
32420
33552
|
const id = `${nextAdrId(ctx)}-${slugify3(title)}`;
|
|
32421
|
-
const
|
|
33553
|
+
const path47 = workspaceArtifact(ctx.rootDir, "decisions", id);
|
|
32422
33554
|
const meta3 = {
|
|
32423
33555
|
kind: "adr",
|
|
32424
33556
|
status: "proposed",
|
|
@@ -32444,7 +33576,7 @@ function addIdeaStub(ctx) {
|
|
|
32444
33576
|
...consequences.map((c) => `- ${c}`),
|
|
32445
33577
|
""
|
|
32446
33578
|
].join("\n");
|
|
32447
|
-
ctx.storage.write(
|
|
33579
|
+
ctx.storage.write(path47, meta3, body);
|
|
32448
33580
|
return `ADR ${id} created: "${title}". Status: proposed. Promote to accepted via /update ADR or manual edit.`;
|
|
32449
33581
|
});
|
|
32450
33582
|
}
|
|
@@ -32526,14 +33658,14 @@ function createDocumentStub(ctx) {
|
|
|
32526
33658
|
ctx.storage.write(risksPath, riskMeta, content);
|
|
32527
33659
|
return `Document "${title}" created at risks.md (workspace root).`;
|
|
32528
33660
|
}
|
|
32529
|
-
const
|
|
33661
|
+
const path47 = workspaceArtifact(ctx.rootDir, "docs", slug);
|
|
32530
33662
|
const meta3 = {
|
|
32531
33663
|
kind: "doc",
|
|
32532
33664
|
id: slug,
|
|
32533
33665
|
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
32534
33666
|
tags
|
|
32535
33667
|
};
|
|
32536
|
-
ctx.storage.write(
|
|
33668
|
+
ctx.storage.write(path47, meta3, content);
|
|
32537
33669
|
return `Document "${title}" created at docs/${slug}.md.`;
|
|
32538
33670
|
});
|
|
32539
33671
|
}
|
|
@@ -32694,12 +33826,12 @@ __export(toolRegistry_exports2, {
|
|
|
32694
33826
|
});
|
|
32695
33827
|
function createWorkspaceToolRegistry(ctx) {
|
|
32696
33828
|
const stubs = createWorkspaceStubs(ctx);
|
|
32697
|
-
const
|
|
33829
|
+
const registry4 = new ToolRegistry();
|
|
32698
33830
|
for (const stub of stubs) {
|
|
32699
33831
|
const td = adaptStubToToolDefinition(stub, ctx);
|
|
32700
|
-
|
|
33832
|
+
registry4.register(td);
|
|
32701
33833
|
}
|
|
32702
|
-
return
|
|
33834
|
+
return registry4;
|
|
32703
33835
|
}
|
|
32704
33836
|
function adaptStubToToolDefinition(stub, workspaceCtx) {
|
|
32705
33837
|
return {
|
|
@@ -32731,7 +33863,7 @@ var init_toolRegistry2 = __esm({
|
|
|
32731
33863
|
"src/cli/workspace/toolRegistry.ts"() {
|
|
32732
33864
|
"use strict";
|
|
32733
33865
|
init_zod();
|
|
32734
|
-
|
|
33866
|
+
init_registry2();
|
|
32735
33867
|
init_toolTypes();
|
|
32736
33868
|
init_stubs();
|
|
32737
33869
|
}
|
|
@@ -33077,10 +34209,10 @@ function getUserMcpPath() {
|
|
|
33077
34209
|
function getProjectMcpPath(projectRoot) {
|
|
33078
34210
|
return join24(projectRoot, ".zelari", "mcp.json");
|
|
33079
34211
|
}
|
|
33080
|
-
function readFile2(
|
|
33081
|
-
if (!existsSync28(
|
|
34212
|
+
function readFile2(path47) {
|
|
34213
|
+
if (!existsSync28(path47)) return {};
|
|
33082
34214
|
try {
|
|
33083
|
-
const parsed = JSON.parse(readFileSync23(
|
|
34215
|
+
const parsed = JSON.parse(readFileSync23(path47, "utf8"));
|
|
33084
34216
|
const out = {};
|
|
33085
34217
|
for (const [name, cfg] of Object.entries(parsed.mcpServers ?? {})) {
|
|
33086
34218
|
if (!cfg || typeof cfg.command !== "string" || !cfg.command.trim()) continue;
|
|
@@ -33096,10 +34228,10 @@ function readFile2(path44) {
|
|
|
33096
34228
|
return {};
|
|
33097
34229
|
}
|
|
33098
34230
|
}
|
|
33099
|
-
function writeFile(
|
|
33100
|
-
mkdirSync13(dirname6(
|
|
34231
|
+
function writeFile(path47, servers) {
|
|
34232
|
+
mkdirSync13(dirname6(path47), { recursive: true });
|
|
33101
34233
|
const body = { mcpServers: servers };
|
|
33102
|
-
writeFileSync15(
|
|
34234
|
+
writeFileSync15(path47, `${JSON.stringify(body, null, 2)}
|
|
33103
34235
|
`, "utf8");
|
|
33104
34236
|
}
|
|
33105
34237
|
function listMcpServers(projectRoot) {
|
|
@@ -33132,9 +34264,9 @@ function upsertMcpServer(opts) {
|
|
|
33132
34264
|
if (!opts.config.command?.trim()) {
|
|
33133
34265
|
return { ok: false, error: "command is required" };
|
|
33134
34266
|
}
|
|
33135
|
-
let
|
|
34267
|
+
let path47;
|
|
33136
34268
|
if (opts.scope === "user") {
|
|
33137
|
-
|
|
34269
|
+
path47 = getUserMcpPath();
|
|
33138
34270
|
} else {
|
|
33139
34271
|
const root = opts.projectRoot?.trim();
|
|
33140
34272
|
if (!root) {
|
|
@@ -33143,30 +34275,30 @@ function upsertMcpServer(opts) {
|
|
|
33143
34275
|
error: "projectRoot required for project scope (Open Folder first)"
|
|
33144
34276
|
};
|
|
33145
34277
|
}
|
|
33146
|
-
|
|
34278
|
+
path47 = getProjectMcpPath(root);
|
|
33147
34279
|
}
|
|
33148
|
-
const current = readFile2(
|
|
34280
|
+
const current = readFile2(path47);
|
|
33149
34281
|
current[name] = {
|
|
33150
34282
|
command: opts.config.command.trim(),
|
|
33151
34283
|
args: opts.config.args,
|
|
33152
34284
|
env: opts.config.env,
|
|
33153
34285
|
enabled: opts.config.enabled !== false
|
|
33154
34286
|
};
|
|
33155
|
-
writeFile(
|
|
33156
|
-
return { ok: true, path:
|
|
34287
|
+
writeFile(path47, current);
|
|
34288
|
+
return { ok: true, path: path47 };
|
|
33157
34289
|
}
|
|
33158
34290
|
function removeMcpServer(opts) {
|
|
33159
|
-
const
|
|
33160
|
-
if (!
|
|
34291
|
+
const path47 = opts.scope === "user" ? getUserMcpPath() : opts.projectRoot ? getProjectMcpPath(opts.projectRoot) : null;
|
|
34292
|
+
if (!path47) {
|
|
33161
34293
|
return { ok: false, error: "projectRoot required for project scope" };
|
|
33162
34294
|
}
|
|
33163
|
-
const current = readFile2(
|
|
34295
|
+
const current = readFile2(path47);
|
|
33164
34296
|
if (!(opts.name in current)) {
|
|
33165
|
-
return { ok: false, error: `Server "${opts.name}" not found in ${
|
|
34297
|
+
return { ok: false, error: `Server "${opts.name}" not found in ${path47}` };
|
|
33166
34298
|
}
|
|
33167
34299
|
delete current[opts.name];
|
|
33168
|
-
writeFile(
|
|
33169
|
-
return { ok: true, path:
|
|
34300
|
+
writeFile(path47, current);
|
|
34301
|
+
return { ok: true, path: path47 };
|
|
33170
34302
|
}
|
|
33171
34303
|
var init_mcpConfigIo = __esm({
|
|
33172
34304
|
"src/cli/mcp/mcpConfigIo.ts"() {
|
|
@@ -33310,7 +34442,7 @@ async function ensureLoaded(projectRoot) {
|
|
|
33310
34442
|
function sanitizeToolName(raw) {
|
|
33311
34443
|
return raw.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
33312
34444
|
}
|
|
33313
|
-
async function registerMcpTools(
|
|
34445
|
+
async function registerMcpTools(registry4, projectRoot = process.cwd(), opts) {
|
|
33314
34446
|
if (process.env["ZELARI_MCP"] === "0") return { registered: [], warnings: [] };
|
|
33315
34447
|
await ensureLoaded(projectRoot);
|
|
33316
34448
|
const skipCuaForCouncil = opts?.councilMode === true && !isCuaAllowedForCouncil();
|
|
@@ -33319,7 +34451,7 @@ async function registerMcpTools(registry3, projectRoot = process.cwd(), opts) {
|
|
|
33319
34451
|
if (skipCuaForCouncil && isCuaMcpServerName(t.serverName)) {
|
|
33320
34452
|
continue;
|
|
33321
34453
|
}
|
|
33322
|
-
|
|
34454
|
+
registry4.register({
|
|
33323
34455
|
name: t.registryName,
|
|
33324
34456
|
description: `[MCP:${t.serverName}] ${t.info.description}`.slice(0, 1024),
|
|
33325
34457
|
// The MCP server owns validation; its JSON Schema is forwarded to the
|
|
@@ -33503,10 +34635,10 @@ import { createHash as createHash5 } from "node:crypto";
|
|
|
33503
34635
|
import { join as join26 } from "node:path";
|
|
33504
34636
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
33505
34637
|
async function readPackageJson2(projectRoot) {
|
|
33506
|
-
const
|
|
33507
|
-
if (!existsSync30(
|
|
34638
|
+
const path47 = join26(projectRoot, "package.json");
|
|
34639
|
+
if (!existsSync30(path47)) return null;
|
|
33508
34640
|
try {
|
|
33509
|
-
return JSON.parse(await readFile3(
|
|
34641
|
+
return JSON.parse(await readFile3(path47, "utf8"));
|
|
33510
34642
|
} catch {
|
|
33511
34643
|
return null;
|
|
33512
34644
|
}
|
|
@@ -33588,9 +34720,9 @@ async function genBuild(ctx) {
|
|
|
33588
34720
|
].join("\n");
|
|
33589
34721
|
}
|
|
33590
34722
|
async function genOpenQuestions(ctx) {
|
|
33591
|
-
const
|
|
33592
|
-
if (!existsSync30(
|
|
33593
|
-
const content = readFileSync25(
|
|
34723
|
+
const path47 = join26(ctx.rootDir, "risks.md");
|
|
34724
|
+
if (!existsSync30(path47)) return "_No open questions._";
|
|
34725
|
+
const content = readFileSync25(path47, "utf8");
|
|
33594
34726
|
const lines = content.split("\n");
|
|
33595
34727
|
const questions = [];
|
|
33596
34728
|
let currentTitle = "";
|
|
@@ -34121,9 +35253,9 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
34121
35253
|
lessons = { ran: true, captured: 0, rejected: 0 };
|
|
34122
35254
|
for (const r of verification.report.results) {
|
|
34123
35255
|
if (r.ok) continue;
|
|
34124
|
-
const
|
|
34125
|
-
if (
|
|
34126
|
-
else if (
|
|
35256
|
+
const cap3 = captureFailure(ctx.rootDir, r);
|
|
35257
|
+
if (cap3.rejected) lessons.rejected++;
|
|
35258
|
+
else if (cap3.captured) lessons.captured++;
|
|
34127
35259
|
}
|
|
34128
35260
|
} else if (process.env["ZELARI_LESSONS"] === "0") {
|
|
34129
35261
|
lessons = {
|
|
@@ -34157,8 +35289,8 @@ async function runPostCouncilHook(ctx, options) {
|
|
|
34157
35289
|
sources: scope.sources
|
|
34158
35290
|
} : void 0
|
|
34159
35291
|
});
|
|
34160
|
-
const
|
|
34161
|
-
completionHook = { ran: true, path:
|
|
35292
|
+
const path47 = writeCouncilCompletion(ctx.rootDir, completion);
|
|
35293
|
+
completionHook = { ran: true, path: path47, completion };
|
|
34162
35294
|
} catch (err) {
|
|
34163
35295
|
completionHook = {
|
|
34164
35296
|
ran: true,
|
|
@@ -35376,6 +36508,7 @@ __export(planner_exports, {
|
|
|
35376
36508
|
KRAKEN_PLANNER_SYSTEM_PROMPT: () => KRAKEN_PLANNER_SYSTEM_PROMPT,
|
|
35377
36509
|
PlannerTransportError: () => PlannerTransportError,
|
|
35378
36510
|
buildGraphFromPlan: () => buildGraphFromPlan,
|
|
36511
|
+
buildPlannerSystemPrompt: () => buildPlannerSystemPrompt,
|
|
35379
36512
|
buildPlannerUserPrompt: () => buildPlannerUserPrompt,
|
|
35380
36513
|
extractJsonObject: () => extractJsonObject,
|
|
35381
36514
|
planTaskGraph: () => planTaskGraph,
|
|
@@ -35399,6 +36532,15 @@ function resolvePlannerMaxTokens(env = process.env) {
|
|
|
35399
36532
|
const n = Number.parseInt(raw, 10);
|
|
35400
36533
|
return Number.isFinite(n) && n > 0 ? n : DEFAULT_LLM_MAX_TOKENS;
|
|
35401
36534
|
}
|
|
36535
|
+
function resolveBennettsRazorEnabled(env = process.env) {
|
|
36536
|
+
const raw = env.ZELARI_KRAKEN_PLANNER_BENNETTS_RAZOR;
|
|
36537
|
+
if (raw === void 0 || raw === "") return false;
|
|
36538
|
+
return raw === "1" || raw.toLowerCase() === "true";
|
|
36539
|
+
}
|
|
36540
|
+
function buildPlannerSystemPrompt(env = process.env) {
|
|
36541
|
+
if (!resolveBennettsRazorEnabled(env)) return KRAKEN_PLANNER_SYSTEM_PROMPT;
|
|
36542
|
+
return KRAKEN_PLANNER_SYSTEM_PROMPT + "\n" + KRAKEN_PLANNER_BENNETTS_RAZOR_SECTION;
|
|
36543
|
+
}
|
|
35402
36544
|
function extractJsonObject(text, opts = {}) {
|
|
35403
36545
|
const stripped = stripReasoningBlocks(text);
|
|
35404
36546
|
const usable = findJsonIn(stripped, opts);
|
|
@@ -35824,7 +36966,7 @@ async function planTaskGraph(opts) {
|
|
|
35824
36966
|
let userMessage = userBase;
|
|
35825
36967
|
for (let attempt = 1; attempt <= MAX_PLAN_ATTEMPTS; attempt++) {
|
|
35826
36968
|
try {
|
|
35827
|
-
const text = await client.complete({ system:
|
|
36969
|
+
const text = await client.complete({ system: buildPlannerSystemPrompt(), user: userMessage });
|
|
35828
36970
|
const parsedJson = extractJsonObject(text, { requireKey: "nodes" });
|
|
35829
36971
|
const validated = PlannedGraphSchema.parse(parsedJson);
|
|
35830
36972
|
if (!validated.nodes.some((n) => n.kind === "general")) {
|
|
@@ -35850,7 +36992,7 @@ Your previous response was invalid (${lastError}). Return ONLY corrected JSON ma
|
|
|
35850
36992
|
`kraken planner: failed to produce a valid task graph after ${MAX_PLAN_ATTEMPTS} attempts \u2014 ${lastError}`
|
|
35851
36993
|
);
|
|
35852
36994
|
}
|
|
35853
|
-
var MAX_PLAN_ATTEMPTS, DEFAULT_PLANNER_WORKSPACE_CHARS, DEFAULT_LLM_TIMEOUT_MS, PlannerTransportError, DEFAULT_LLM_MAX_TOKENS, DEFAULT_MAX_RETRIES, KRAKEN_PLANNER_SYSTEM_PROMPT, PlannedNodeSchema, PlannedGraphSchema, MAX_VERIFY_TASK_PROMPT_CHARS;
|
|
36995
|
+
var MAX_PLAN_ATTEMPTS, DEFAULT_PLANNER_WORKSPACE_CHARS, DEFAULT_LLM_TIMEOUT_MS, PlannerTransportError, DEFAULT_LLM_MAX_TOKENS, DEFAULT_MAX_RETRIES, KRAKEN_PLANNER_SYSTEM_PROMPT, KRAKEN_PLANNER_BENNETTS_RAZOR_SECTION, PlannedNodeSchema, PlannedGraphSchema, MAX_VERIFY_TASK_PROMPT_CHARS;
|
|
35854
36996
|
var init_planner = __esm({
|
|
35855
36997
|
"src/cli/kraken/planner.ts"() {
|
|
35856
36998
|
"use strict";
|
|
@@ -35875,7 +37017,11 @@ var init_planner = __esm({
|
|
|
35875
37017
|
general: 1,
|
|
35876
37018
|
verify: 1,
|
|
35877
37019
|
fix: 0,
|
|
35878
|
-
merge: 0
|
|
37020
|
+
merge: 0,
|
|
37021
|
+
// Pillar 2 persona kinds: same retry budget as `verify` (the gate is
|
|
37022
|
+
// the same — trailer-based).
|
|
37023
|
+
spec: 1,
|
|
37024
|
+
conformance: 1
|
|
35879
37025
|
};
|
|
35880
37026
|
KRAKEN_PLANNER_SYSTEM_PROMPT = [
|
|
35881
37027
|
"You are the PLANNER for Kraken, a multi-agent graph executor.",
|
|
@@ -35887,7 +37033,7 @@ var init_planner = __esm({
|
|
|
35887
37033
|
"Rules:",
|
|
35888
37034
|
'- kind "explore": read-only research (no edits). Use to gather context before edits.',
|
|
35889
37035
|
'- kind "general": can edit files for one bounded, self-contained unit of work.',
|
|
35890
|
-
'- Do NOT emit "verify", "fix", or "merge" nodes \u2014 the executor adds those automatically.',
|
|
37036
|
+
'- Do NOT emit "verify", "spec", "conformance", "fix", or "merge" nodes \u2014 the executor adds those automatically based on the writer kind and the goal shape.',
|
|
35891
37037
|
'- "id" must be short, unique, kebab-case (e.g. "e1", "g-auth", "g-ui").',
|
|
35892
37038
|
'- "prompt" must be self-contained: the sub-agent sees ONLY this prompt, not this conversation.',
|
|
35893
37039
|
'- "deps" lists ids of nodes that must finish first (topological order); [] if none.',
|
|
@@ -35896,7 +37042,36 @@ var init_planner = __esm({
|
|
|
35896
37042
|
'- The user message includes a listing of the real project on disk. Build every "scope" from paths that appear there (or new paths that clearly belong beside them) \u2014 an invented path makes the parallelism decision meaningless, since scopes are exactly what the executor uses to decide which writers may run at the same time.',
|
|
35897
37043
|
'- Prefer one "explore" node feeding several parallel "general" nodes over one giant node.',
|
|
35898
37044
|
"- Keep the graph small: most goals need 3-8 nodes total.",
|
|
35899
|
-
'- "acceptance" (optional) lists concrete, checkable criteria for a "general" node. These are ENFORCED: the executor adds a verify tentacle that checks them on disk and can send the work back for a rework round when they are not met. Write criteria a reader can settle by opening a file or running a command ("exports slugify(input: string): string", "npm test passes"), never subjective ones ("the code is elegant") \u2014 a criterion nobody can check just burns a rework round.'
|
|
37045
|
+
'- "acceptance" (optional) lists concrete, checkable criteria for a "general" node. These are ENFORCED: the executor adds a verify tentacle that checks them on disk and can send the work back for a rework round when they are not met. Write criteria a reader can settle by opening a file or running a command ("exports slugify(input: string): string", "npm test passes"), never subjective ones ("the code is elegant") \u2014 a criterion nobody can check just burns a rework round.',
|
|
37046
|
+
"",
|
|
37047
|
+
"# Reviewer personas (Pillar 2 spec council)",
|
|
37048
|
+
"",
|
|
37049
|
+
"After every `general` node, the executor auto-injects a `verify` tentacle that checks the `acceptance[]` criteria. For goals that have a written spec or that must literally match the user prompt, the executor also auto-injects two more personas:",
|
|
37050
|
+
' - `spec` (spec-reviewer) \u2014 compares the writer\'s output against a written spec/plan, per requirement. Conservative: "reasonable but different" is a FAIL.',
|
|
37051
|
+
' - `conformance` (conformance-reviewer) \u2014 compares the writer\'s output against the USER\'S ORIGINAL VERBATIM PROMPT. Literal: "use session cookies" is a FAIL when the prompt said "use JWT".',
|
|
37052
|
+
"",
|
|
37053
|
+
"You (the JSON planner) do NOT emit these directly; the executor decides when to inject them. To hint that a node needs a `conformance` reviewer, include the user's original ask verbatim in the `prompt`."
|
|
37054
|
+
].join("\n");
|
|
37055
|
+
KRAKEN_PLANNER_BENNETTS_RAZOR_SECTION = [
|
|
37056
|
+
"",
|
|
37057
|
+
"# Bennett's Razor (tie-breaker)",
|
|
37058
|
+
"",
|
|
37059
|
+
'When two valid plans cover the goal, prefer the one that "assumes the least".',
|
|
37060
|
+
"A plan is *more specific* when it pins exact paths, exact semver, exact function",
|
|
37061
|
+
"signatures, or hard invariants about external state. A more general plan that",
|
|
37062
|
+
"still satisfies the goal generalises better (Bennett, AGI 2023: 1.1\xD7\u20135\xD7 the rate",
|
|
37063
|
+
"of MDL in his experiments).",
|
|
37064
|
+
"",
|
|
37065
|
+
"Examples of the bias you should apply:",
|
|
37066
|
+
'- "edit the user model" > "edit /src/models/user.ts and add a nullable email field"',
|
|
37067
|
+
" when the goal can be met either way.",
|
|
37068
|
+
'- "use a stable sort" > "use Array.prototype.sort with a custom comparator" unless',
|
|
37069
|
+
" the user pinned the API.",
|
|
37070
|
+
"- Prefer plans that touch fewer files and assume less about runtime versions.",
|
|
37071
|
+
"",
|
|
37072
|
+
"Hard constraint: do NOT weaken a plan below the bar in the name of weakness. The",
|
|
37073
|
+
"goal must be reachable by following the plan as written; weakness is only a",
|
|
37074
|
+
"tie-breaker among plans that do reach the goal."
|
|
35900
37075
|
].join("\n");
|
|
35901
37076
|
PlannedNodeSchema = external_exports.object({
|
|
35902
37077
|
id: external_exports.string().min(1).max(64).regex(/^[a-zA-Z0-9_-]+$/, "id must be alphanumeric/dash/underscore"),
|
|
@@ -36033,6 +37208,126 @@ var init_tentacle = __esm({
|
|
|
36033
37208
|
}
|
|
36034
37209
|
});
|
|
36035
37210
|
|
|
37211
|
+
// src/cli/kraken/weaknessMeter.ts
|
|
37212
|
+
var weaknessMeter_exports = {};
|
|
37213
|
+
__export(weaknessMeter_exports, {
|
|
37214
|
+
_resetWeaknessMeterCacheForTests: () => _resetWeaknessMeterCacheForTests,
|
|
37215
|
+
isWeaknessMeterEnabled: () => isWeaknessMeterEnabled,
|
|
37216
|
+
measureWeaknessViaLLM: () => measureWeaknessViaLLM,
|
|
37217
|
+
parseMeterContent: () => parseMeterContent
|
|
37218
|
+
});
|
|
37219
|
+
function isWeaknessMeterEnabled(env = process.env) {
|
|
37220
|
+
if (meterEnabledCache !== null) return meterEnabledCache;
|
|
37221
|
+
const raw = env.ZELARI_KRAKEN_WEAKNESS_METER;
|
|
37222
|
+
const enabled = raw === "1" || raw === "true" || raw === "yes";
|
|
37223
|
+
meterEnabledCache = enabled;
|
|
37224
|
+
return enabled;
|
|
37225
|
+
}
|
|
37226
|
+
function _resetWeaknessMeterCacheForTests() {
|
|
37227
|
+
meterEnabledCache = null;
|
|
37228
|
+
}
|
|
37229
|
+
function resolveMeterModel(env = process.env, fallback) {
|
|
37230
|
+
const raw = env.ZELARI_KRAKEN_WEAKNESS_METER_MODEL;
|
|
37231
|
+
if (raw && raw.trim() !== "") return raw.trim();
|
|
37232
|
+
return fallback;
|
|
37233
|
+
}
|
|
37234
|
+
async function measureWeaknessViaLLM(text, options = {}) {
|
|
37235
|
+
const env = options.env ?? process.env;
|
|
37236
|
+
if (!isWeaknessMeterEnabled(env)) return null;
|
|
37237
|
+
if (typeof text !== "string" || text.trim() === "") return null;
|
|
37238
|
+
const provider = options.providerOverride ?? await resolveActiveProvider2(env);
|
|
37239
|
+
if (!provider) return null;
|
|
37240
|
+
const model = options.modelOverride ?? resolveMeterModel(env, provider.model);
|
|
37241
|
+
const userPayload = JSON.stringify({
|
|
37242
|
+
task: "measure weakness of the following reviewer reply",
|
|
37243
|
+
reply: text
|
|
37244
|
+
});
|
|
37245
|
+
const start = Date.now();
|
|
37246
|
+
try {
|
|
37247
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
37248
|
+
const ac = new AbortController();
|
|
37249
|
+
const timer = setTimeout(() => ac.abort(), METER_TIMEOUT_MS);
|
|
37250
|
+
let response;
|
|
37251
|
+
try {
|
|
37252
|
+
response = await fetchImpl(provider.endpoint, {
|
|
37253
|
+
method: "POST",
|
|
37254
|
+
headers: {
|
|
37255
|
+
"Content-Type": "application/json",
|
|
37256
|
+
Authorization: `Bearer ${provider.apiKey}`
|
|
37257
|
+
},
|
|
37258
|
+
body: JSON.stringify({
|
|
37259
|
+
model,
|
|
37260
|
+
messages: [
|
|
37261
|
+
{ role: "system", content: WEAKNESS_METER_PROMPT },
|
|
37262
|
+
{ role: "user", content: userPayload }
|
|
37263
|
+
],
|
|
37264
|
+
// The meter is a classification call; no need for a hot
|
|
37265
|
+
// sampling distribution. Most providers accept this pair
|
|
37266
|
+
// without complaint; the few that require it get a stable
|
|
37267
|
+
// answer.
|
|
37268
|
+
temperature: 0,
|
|
37269
|
+
stream: false
|
|
37270
|
+
}),
|
|
37271
|
+
signal: ac.signal
|
|
37272
|
+
});
|
|
37273
|
+
} finally {
|
|
37274
|
+
clearTimeout(timer);
|
|
37275
|
+
}
|
|
37276
|
+
if (!response.ok) return null;
|
|
37277
|
+
const json2 = await response.json();
|
|
37278
|
+
const raw = json2.choices?.[0]?.message?.content;
|
|
37279
|
+
if (typeof raw !== "string") return null;
|
|
37280
|
+
return parseMeterContent(raw, model, Date.now() - start);
|
|
37281
|
+
} catch {
|
|
37282
|
+
return null;
|
|
37283
|
+
}
|
|
37284
|
+
}
|
|
37285
|
+
function parseMeterContent(raw, model, durationMs) {
|
|
37286
|
+
const trimmed = raw.trim();
|
|
37287
|
+
const fenced = /^```(?:json)?\s*([\s\S]+?)\s*```$/i.exec(trimmed);
|
|
37288
|
+
const body = fenced ? fenced[1] : trimmed;
|
|
37289
|
+
let parsed;
|
|
37290
|
+
try {
|
|
37291
|
+
parsed = JSON.parse(body);
|
|
37292
|
+
} catch {
|
|
37293
|
+
return null;
|
|
37294
|
+
}
|
|
37295
|
+
const validated = WeaknessMeterResponseSchema.safeParse(parsed);
|
|
37296
|
+
if (!validated.success) return null;
|
|
37297
|
+
return {
|
|
37298
|
+
meter: validated.data,
|
|
37299
|
+
weakness: weaknessFromMeter(validated.data),
|
|
37300
|
+
durationMs,
|
|
37301
|
+
model
|
|
37302
|
+
};
|
|
37303
|
+
}
|
|
37304
|
+
async function resolveActiveProvider2(env) {
|
|
37305
|
+
const cfg = await getProviderConfig();
|
|
37306
|
+
if (!cfg) return null;
|
|
37307
|
+
const providerId = cfg.activeProviderId;
|
|
37308
|
+
const key = await resolveApiKeyWithMeta(providerId, env);
|
|
37309
|
+
if (!key?.apiKey) return null;
|
|
37310
|
+
const model = getModelForProvider(providerId) ?? cfg.modelByProvider[providerId] ?? "";
|
|
37311
|
+
const endpoint = getCustomEndpoint(providerId) ?? `https://api.openai.com/v1/chat/completions`;
|
|
37312
|
+
return { providerId, model, endpoint, apiKey: key.apiKey };
|
|
37313
|
+
}
|
|
37314
|
+
var meterEnabledCache, METER_TIMEOUT_MS;
|
|
37315
|
+
var init_weaknessMeter = __esm({
|
|
37316
|
+
"src/cli/kraken/weaknessMeter.ts"() {
|
|
37317
|
+
"use strict";
|
|
37318
|
+
init_dist();
|
|
37319
|
+
init_providerConfig();
|
|
37320
|
+
init_keyStore();
|
|
37321
|
+
meterEnabledCache = null;
|
|
37322
|
+
METER_TIMEOUT_MS = (() => {
|
|
37323
|
+
const raw = process.env.ZELARI_KRAKEN_WEAKNESS_METER_TIMEOUT_MS;
|
|
37324
|
+
if (!raw) return 12e3;
|
|
37325
|
+
const n = Number.parseInt(raw, 10);
|
|
37326
|
+
return Number.isFinite(n) && n > 0 ? n : 12e3;
|
|
37327
|
+
})();
|
|
37328
|
+
}
|
|
37329
|
+
});
|
|
37330
|
+
|
|
36036
37331
|
// src/cli/kraken/executor.ts
|
|
36037
37332
|
var executor_exports = {};
|
|
36038
37333
|
__export(executor_exports, {
|
|
@@ -36130,14 +37425,14 @@ function buildUpstreamContext(graph, node) {
|
|
|
36130
37425
|
if (!dep || dep.status !== "done") continue;
|
|
36131
37426
|
const raw = (dep.result ?? "").trim();
|
|
36132
37427
|
if (!raw) continue;
|
|
36133
|
-
const
|
|
36134
|
-
if (
|
|
37428
|
+
const cap3 = Math.min(MAX_UPSTREAM_CHARS_PER_DEP, budget);
|
|
37429
|
+
if (cap3 <= 0) {
|
|
36135
37430
|
omitted.push(dep.label);
|
|
36136
37431
|
continue;
|
|
36137
37432
|
}
|
|
36138
|
-
const body = raw.length >
|
|
36139
|
-
\u2026 [truncated ${raw.length}\u2192${
|
|
36140
|
-
budget -= Math.min(raw.length,
|
|
37433
|
+
const body = raw.length > cap3 ? `${raw.slice(0, cap3)}
|
|
37434
|
+
\u2026 [truncated ${raw.length}\u2192${cap3} chars]` : raw;
|
|
37435
|
+
budget -= Math.min(raw.length, cap3);
|
|
36141
37436
|
const scope = dep.scope && dep.scope.length > 0 ? `, scope: ${dep.scope.join(", ")}` : "";
|
|
36142
37437
|
parts.push(`### ${dep.label} (${dep.kind}${scope})
|
|
36143
37438
|
${body}`);
|
|
@@ -36443,7 +37738,7 @@ var init_executor = __esm({
|
|
|
36443
37738
|
}
|
|
36444
37739
|
const isRework = this.reworks.has(node.id);
|
|
36445
37740
|
const usesWorktree = (node.kind === "general" || node.kind === "fix") && !isRework;
|
|
36446
|
-
const agent = node.kind === "fix" ? "general" : node.kind;
|
|
37741
|
+
const agent = node.kind === "fix" ? "general" : node.kind === "spec" || node.kind === "conformance" ? "verify" : node.kind;
|
|
36447
37742
|
const controller = new AbortController();
|
|
36448
37743
|
this.nodeControllers.set(node.id, controller);
|
|
36449
37744
|
if (this.aborted) controller.abort();
|
|
@@ -36745,6 +38040,7 @@ ${upstream}` : node.prompt,
|
|
|
36745
38040
|
if (verdict === "pass") return;
|
|
36746
38041
|
const writer = this.writerBehind(verify, graph);
|
|
36747
38042
|
if (!writer) return;
|
|
38043
|
+
void this.maybeRunWeaknessMeter(verify, verdict);
|
|
36748
38044
|
if (verdict === "unknown") {
|
|
36749
38045
|
this.unresolved.push({
|
|
36750
38046
|
nodeId: writer.id,
|
|
@@ -36939,6 +38235,41 @@ ${failed.error ?? "unknown error"}`,
|
|
|
36939
38235
|
...fields.ok !== void 0 ? { ok: fields.ok } : {}
|
|
36940
38236
|
});
|
|
36941
38237
|
}
|
|
38238
|
+
/**
|
|
38239
|
+
* Bennett's Razor meter (Slice L/N+3 wiring): when the env flag is
|
|
38240
|
+
* set, fire a non-blocking LLM call to refine the persona verdict's
|
|
38241
|
+
* weakness score. The local heuristic already produced a score in
|
|
38242
|
+
* `parsePersonaVerdict`; the meter just refines it. Results land in
|
|
38243
|
+
* the radio stream as a `node_meter` event so the desktop / tail
|
|
38244
|
+
* can surface the distinction between a "tightly asserted" PASS
|
|
38245
|
+
* (specificity > 0.6) and a "loosely claimed" one (specificity < 0.3).
|
|
38246
|
+
*
|
|
38247
|
+
* No-op when:
|
|
38248
|
+
* - the meter is disabled (default)
|
|
38249
|
+
* - the result text is empty
|
|
38250
|
+
* - the meter call fails (silent: the local score is good enough)
|
|
38251
|
+
*
|
|
38252
|
+
* @since v1.31.x
|
|
38253
|
+
*/
|
|
38254
|
+
async maybeRunWeaknessMeter(verify, verdict) {
|
|
38255
|
+
const text = typeof verify.result === "string" ? verify.result : "";
|
|
38256
|
+
if (text.length === 0) return;
|
|
38257
|
+
let meter;
|
|
38258
|
+
try {
|
|
38259
|
+
({ measureWeaknessViaLLM: meter } = await Promise.resolve().then(() => (init_weaknessMeter(), weaknessMeter_exports)));
|
|
38260
|
+
} catch {
|
|
38261
|
+
return;
|
|
38262
|
+
}
|
|
38263
|
+
if (!meter) return;
|
|
38264
|
+
const outcome = await meter(text);
|
|
38265
|
+
if (!outcome) return;
|
|
38266
|
+
this.radio("node_meter", {
|
|
38267
|
+
description: `meter: ${verify.id}`,
|
|
38268
|
+
agent: "weakness-meter",
|
|
38269
|
+
detail: `v=${verdict} specificity=${outcome.meter.specificity.toFixed(2)} weakness=${outcome.weakness.toFixed(2)} model=${outcome.model} dur=${outcome.durationMs}ms assumptions=${outcome.meter.assumptions.length}`,
|
|
38270
|
+
ok: true
|
|
38271
|
+
});
|
|
38272
|
+
}
|
|
36942
38273
|
};
|
|
36943
38274
|
}
|
|
36944
38275
|
});
|
|
@@ -37327,10 +38658,10 @@ var init_prereqChecks = __esm({
|
|
|
37327
38658
|
|
|
37328
38659
|
// src/cli/plugins/prefs.ts
|
|
37329
38660
|
import { existsSync as existsSync36, readFileSync as readFileSync29, writeFileSync as writeFileSync18, mkdirSync as mkdirSync15 } from "node:fs";
|
|
37330
|
-
import
|
|
38661
|
+
import path38 from "node:path";
|
|
37331
38662
|
import os9 from "node:os";
|
|
37332
38663
|
function getPluginPrefsPath() {
|
|
37333
|
-
return process.env.ZELARI_PLUGINS_PREFS_FILE ??
|
|
38664
|
+
return process.env.ZELARI_PLUGINS_PREFS_FILE ?? path38.join(os9.homedir(), ".tmp", "zelari-code", "plugins.json");
|
|
37334
38665
|
}
|
|
37335
38666
|
function getPluginPrefs() {
|
|
37336
38667
|
const file2 = getPluginPrefsPath();
|
|
@@ -37351,7 +38682,7 @@ function getPluginPrefs() {
|
|
|
37351
38682
|
}
|
|
37352
38683
|
function writePluginPrefs(prefs) {
|
|
37353
38684
|
const file2 = getPluginPrefsPath();
|
|
37354
|
-
mkdirSync15(
|
|
38685
|
+
mkdirSync15(path38.dirname(file2), { recursive: true });
|
|
37355
38686
|
writeFileSync18(file2, JSON.stringify(prefs, null, 2), {
|
|
37356
38687
|
encoding: "utf-8",
|
|
37357
38688
|
mode: 384
|
|
@@ -37388,7 +38719,7 @@ __export(registry_exports, {
|
|
|
37388
38719
|
isBinaryOnPath: () => isBinaryOnPath
|
|
37389
38720
|
});
|
|
37390
38721
|
import { existsSync as existsSync37 } from "node:fs";
|
|
37391
|
-
import
|
|
38722
|
+
import path39 from "node:path";
|
|
37392
38723
|
function detectLocalBin(bin) {
|
|
37393
38724
|
return (cwd) => {
|
|
37394
38725
|
try {
|
|
@@ -37406,7 +38737,7 @@ function isBinaryOnPath(bin, opts = {}) {
|
|
|
37406
38737
|
const platform = opts.platform ?? process.platform;
|
|
37407
38738
|
const exists = opts.exists ?? existsSync37;
|
|
37408
38739
|
const pathEnv = opts.pathEnv ?? process.env.PATH ?? "";
|
|
37409
|
-
const pathMod = platform === "win32" ?
|
|
38740
|
+
const pathMod = platform === "win32" ? path39.win32 : path39.posix;
|
|
37410
38741
|
const sep2 = platform === "win32" ? ";" : ":";
|
|
37411
38742
|
const dirs = pathEnv.split(sep2).filter((d) => d.length > 0);
|
|
37412
38743
|
const candidates = [bin];
|
|
@@ -37475,7 +38806,7 @@ function findPlugin(id) {
|
|
|
37475
38806
|
return PLUGINS.find((p3) => p3.id === id);
|
|
37476
38807
|
}
|
|
37477
38808
|
var PLUGINS;
|
|
37478
|
-
var
|
|
38809
|
+
var init_registry3 = __esm({
|
|
37479
38810
|
"src/cli/plugins/registry.ts"() {
|
|
37480
38811
|
"use strict";
|
|
37481
38812
|
init_engine();
|
|
@@ -37544,7 +38875,7 @@ __export(atMentions_exports, {
|
|
|
37544
38875
|
hasAtMentions: () => hasAtMentions
|
|
37545
38876
|
});
|
|
37546
38877
|
import { existsSync as existsSync40, readFileSync as readFileSync31, statSync as statSync6 } from "node:fs";
|
|
37547
|
-
import { isAbsolute, relative as relative3, resolve, sep } from "node:path";
|
|
38878
|
+
import { isAbsolute as isAbsolute2, relative as relative3, resolve, sep } from "node:path";
|
|
37548
38879
|
function isProbablyText(name, head) {
|
|
37549
38880
|
if (/\.(txt|md|markdown|json|jsonc|ts|tsx|js|jsx|mjs|cjs|css|scss|html|htm|xml|yml|yaml|toml|ini|cfg|conf|rs|go|py|java|kt|swift|c|cc|cpp|h|hpp|cs|rb|php|sh|bash|zsh|ps1|sql|graphql|env|gitignore|dockerfile|makefile|cmake|lock|svg)$/i.test(
|
|
37550
38881
|
name
|
|
@@ -37575,8 +38906,8 @@ function extractAtMentions(text) {
|
|
|
37575
38906
|
return out;
|
|
37576
38907
|
}
|
|
37577
38908
|
function resolveMention(token, cwd) {
|
|
37578
|
-
const abs =
|
|
37579
|
-
if (!underRoot(abs, cwd) && !
|
|
38909
|
+
const abs = isAbsolute2(token) ? resolve(token) : resolve(cwd, token);
|
|
38910
|
+
if (!underRoot(abs, cwd) && !isAbsolute2(token)) {
|
|
37580
38911
|
if (!underRoot(abs, cwd)) {
|
|
37581
38912
|
return {
|
|
37582
38913
|
raw: token,
|
|
@@ -37587,7 +38918,7 @@ function resolveMention(token, cwd) {
|
|
|
37587
38918
|
};
|
|
37588
38919
|
}
|
|
37589
38920
|
}
|
|
37590
|
-
if (
|
|
38921
|
+
if (isAbsolute2(token) && !underRoot(abs, cwd)) {
|
|
37591
38922
|
return {
|
|
37592
38923
|
raw: token,
|
|
37593
38924
|
path: token,
|
|
@@ -37715,10 +39046,10 @@ __export(triggerLock_exports, {
|
|
|
37715
39046
|
lockPath: () => lockPath,
|
|
37716
39047
|
releaseLock: () => releaseLock
|
|
37717
39048
|
});
|
|
37718
|
-
import { promises as
|
|
37719
|
-
import * as
|
|
39049
|
+
import { promises as fs27 } from "node:fs";
|
|
39050
|
+
import * as path44 from "node:path";
|
|
37720
39051
|
function lockPath(projectRoot) {
|
|
37721
|
-
return
|
|
39052
|
+
return path44.join(projectRoot, ".zelari", "trigger.lock");
|
|
37722
39053
|
}
|
|
37723
39054
|
function isPidAlive(pid) {
|
|
37724
39055
|
try {
|
|
@@ -37731,10 +39062,10 @@ function isPidAlive(pid) {
|
|
|
37731
39062
|
}
|
|
37732
39063
|
async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date()) {
|
|
37733
39064
|
const lp = lockPath(projectRoot);
|
|
37734
|
-
const dir =
|
|
37735
|
-
await
|
|
39065
|
+
const dir = path44.dirname(lp);
|
|
39066
|
+
await fs27.mkdir(dir, { recursive: true });
|
|
37736
39067
|
try {
|
|
37737
|
-
const raw = await
|
|
39068
|
+
const raw = await fs27.readFile(lp, "utf8");
|
|
37738
39069
|
const existing = JSON.parse(raw);
|
|
37739
39070
|
if (existing.pid && isPidAlive(existing.pid)) {
|
|
37740
39071
|
return { acquired: false, heldBy: existing.pid, lockPath: lp };
|
|
@@ -37745,13 +39076,13 @@ async function acquireLock(projectRoot, now = () => /* @__PURE__ */ new Date())
|
|
|
37745
39076
|
pid: process.pid,
|
|
37746
39077
|
acquiredAt: now().toISOString()
|
|
37747
39078
|
};
|
|
37748
|
-
await
|
|
39079
|
+
await fs27.writeFile(lp, JSON.stringify(payload, null, 2) + "\n", "utf8");
|
|
37749
39080
|
return { acquired: true, lockPath: lp };
|
|
37750
39081
|
}
|
|
37751
39082
|
async function releaseLock(projectRoot) {
|
|
37752
39083
|
const lp = lockPath(projectRoot);
|
|
37753
39084
|
try {
|
|
37754
|
-
await
|
|
39085
|
+
await fs27.unlink(lp);
|
|
37755
39086
|
} catch {
|
|
37756
39087
|
}
|
|
37757
39088
|
}
|
|
@@ -38022,7 +39353,7 @@ import {
|
|
|
38022
39353
|
} from "node:fs";
|
|
38023
39354
|
import { join as join35 } from "node:path";
|
|
38024
39355
|
import { homedir as homedir11 } from "node:os";
|
|
38025
|
-
import { createHash as createHash6, randomBytes as
|
|
39356
|
+
import { createHash as createHash6, randomBytes as randomBytes4, timingSafeEqual } from "node:crypto";
|
|
38026
39357
|
function getZelariHome() {
|
|
38027
39358
|
return join35(homedir11(), ".zelari-code");
|
|
38028
39359
|
}
|
|
@@ -38039,12 +39370,12 @@ function ensureHome() {
|
|
|
38039
39370
|
}
|
|
38040
39371
|
}
|
|
38041
39372
|
function loadCompanionConfig() {
|
|
38042
|
-
const
|
|
38043
|
-
if (!existsSync43(
|
|
39373
|
+
const path47 = getCompanionConfigPath();
|
|
39374
|
+
if (!existsSync43(path47)) {
|
|
38044
39375
|
return { projects: [] };
|
|
38045
39376
|
}
|
|
38046
39377
|
try {
|
|
38047
|
-
const raw = JSON.parse(readFileSync34(
|
|
39378
|
+
const raw = JSON.parse(readFileSync34(path47, "utf8"));
|
|
38048
39379
|
const projects = Array.isArray(raw.projects) ? raw.projects.filter(
|
|
38049
39380
|
(p3) => p3 && typeof p3.path === "string" && p3.path.trim() && typeof (p3.id ?? p3.name) === "string"
|
|
38050
39381
|
).map((p3) => ({
|
|
@@ -38082,16 +39413,16 @@ function loadOrCreateToken(explicit) {
|
|
|
38082
39413
|
return { token: explicit.trim(), created: false };
|
|
38083
39414
|
}
|
|
38084
39415
|
ensureHome();
|
|
38085
|
-
const
|
|
38086
|
-
if (existsSync43(
|
|
38087
|
-
const t = readFileSync34(
|
|
39416
|
+
const path47 = getCompanionTokenPath();
|
|
39417
|
+
if (existsSync43(path47)) {
|
|
39418
|
+
const t = readFileSync34(path47, "utf8").trim();
|
|
38088
39419
|
if (t) return { token: t, created: false };
|
|
38089
39420
|
}
|
|
38090
|
-
const token =
|
|
38091
|
-
writeFileSync21(
|
|
39421
|
+
const token = randomBytes4(24).toString("base64url");
|
|
39422
|
+
writeFileSync21(path47, token + "\n", "utf8");
|
|
38092
39423
|
try {
|
|
38093
|
-
const
|
|
38094
|
-
|
|
39424
|
+
const fs29 = __require("node:fs");
|
|
39425
|
+
fs29.chmodSync?.(path47, 384);
|
|
38095
39426
|
} catch {
|
|
38096
39427
|
}
|
|
38097
39428
|
return { token, created: true };
|
|
@@ -38116,17 +39447,17 @@ function mergeProjects(cfg, extraPaths) {
|
|
|
38116
39447
|
byId.set(p3.id, p3);
|
|
38117
39448
|
}
|
|
38118
39449
|
for (const raw of extraPaths) {
|
|
38119
|
-
const
|
|
38120
|
-
if (!
|
|
38121
|
-
let id = slugFromPath(
|
|
39450
|
+
const path47 = raw.trim();
|
|
39451
|
+
if (!path47) continue;
|
|
39452
|
+
let id = slugFromPath(path47);
|
|
38122
39453
|
let n = 2;
|
|
38123
|
-
while (byId.has(id) && byId.get(id).path !==
|
|
38124
|
-
id = `${slugFromPath(
|
|
39454
|
+
while (byId.has(id) && byId.get(id).path !== path47) {
|
|
39455
|
+
id = `${slugFromPath(path47)}-${n++}`;
|
|
38125
39456
|
}
|
|
38126
39457
|
byId.set(id, {
|
|
38127
39458
|
id,
|
|
38128
|
-
name: slugFromPath(
|
|
38129
|
-
path:
|
|
39459
|
+
name: slugFromPath(path47),
|
|
39460
|
+
path: path47
|
|
38130
39461
|
});
|
|
38131
39462
|
}
|
|
38132
39463
|
return [...byId.values()];
|
|
@@ -38176,7 +39507,7 @@ var init_config = __esm({
|
|
|
38176
39507
|
// src/cli/companion/runManager.ts
|
|
38177
39508
|
import { spawn as spawn11 } from "node:child_process";
|
|
38178
39509
|
import { createInterface } from "node:readline";
|
|
38179
|
-
import { randomUUID as
|
|
39510
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
38180
39511
|
import { writeFileSync as writeFileSync22, unlinkSync as unlinkSync2 } from "node:fs";
|
|
38181
39512
|
import { join as join36 } from "node:path";
|
|
38182
39513
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
@@ -38245,7 +39576,7 @@ var init_runManager = __esm({
|
|
|
38245
39576
|
}
|
|
38246
39577
|
const prompt = args.prompt?.trim();
|
|
38247
39578
|
if (!prompt) return { ok: false, error: "prompt is required" };
|
|
38248
|
-
const id =
|
|
39579
|
+
const id = randomUUID7();
|
|
38249
39580
|
const mode = (args.mode || "kraken").toLowerCase();
|
|
38250
39581
|
const phase2 = (args.phase || "build").toLowerCase();
|
|
38251
39582
|
const run = {
|
|
@@ -38503,9 +39834,9 @@ async function runCompanionServe(opts = {}) {
|
|
|
38503
39834
|
return;
|
|
38504
39835
|
}
|
|
38505
39836
|
const url2 = parseUrl(req);
|
|
38506
|
-
const
|
|
39837
|
+
const path47 = url2.pathname.replace(/\/+$/, "") || "/";
|
|
38507
39838
|
try {
|
|
38508
|
-
if (req.method === "GET" && (
|
|
39839
|
+
if (req.method === "GET" && (path47 === "/health" || path47 === "/v1/health")) {
|
|
38509
39840
|
sendJson(res, 200, {
|
|
38510
39841
|
ok: true,
|
|
38511
39842
|
service: "zelari-companion",
|
|
@@ -38517,18 +39848,18 @@ async function runCompanionServe(opts = {}) {
|
|
|
38517
39848
|
});
|
|
38518
39849
|
return;
|
|
38519
39850
|
}
|
|
38520
|
-
if (
|
|
39851
|
+
if (path47.startsWith("/v1")) {
|
|
38521
39852
|
if (!tokenMatches(token, getBearer(req))) {
|
|
38522
39853
|
sendJson(res, 401, { ok: false, error: "unauthorized" });
|
|
38523
39854
|
return;
|
|
38524
39855
|
}
|
|
38525
39856
|
}
|
|
38526
|
-
if (req.method === "GET" &&
|
|
39857
|
+
if (req.method === "GET" && path47 === "/v1/config") {
|
|
38527
39858
|
const snap = buildDesktopConfigSnapshot();
|
|
38528
39859
|
sendJson(res, 200, { ok: true, ...snap });
|
|
38529
39860
|
return;
|
|
38530
39861
|
}
|
|
38531
|
-
if (req.method === "GET" &&
|
|
39862
|
+
if (req.method === "GET" && path47 === "/v1/projects") {
|
|
38532
39863
|
sendJson(res, 200, {
|
|
38533
39864
|
ok: true,
|
|
38534
39865
|
projects: projects.map((p3) => ({
|
|
@@ -38539,7 +39870,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
38539
39870
|
});
|
|
38540
39871
|
return;
|
|
38541
39872
|
}
|
|
38542
|
-
if (req.method === "GET" &&
|
|
39873
|
+
if (req.method === "GET" && path47 === "/v1/runs") {
|
|
38543
39874
|
sendJson(res, 200, {
|
|
38544
39875
|
ok: true,
|
|
38545
39876
|
active: runs.getActive(),
|
|
@@ -38557,7 +39888,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
38557
39888
|
});
|
|
38558
39889
|
return;
|
|
38559
39890
|
}
|
|
38560
|
-
if (req.method === "POST" &&
|
|
39891
|
+
if (req.method === "POST" && path47 === "/v1/runs") {
|
|
38561
39892
|
const raw = await readBody(req);
|
|
38562
39893
|
let body = {};
|
|
38563
39894
|
try {
|
|
@@ -38604,7 +39935,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
38604
39935
|
});
|
|
38605
39936
|
return;
|
|
38606
39937
|
}
|
|
38607
|
-
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(
|
|
39938
|
+
const eventsMatch = /^\/v1\/runs\/([^/]+)\/events$/.exec(path47);
|
|
38608
39939
|
if (req.method === "GET" && eventsMatch) {
|
|
38609
39940
|
const runId = eventsMatch[1];
|
|
38610
39941
|
const run = runs.getRun(runId);
|
|
@@ -38669,7 +40000,7 @@ async function runCompanionServe(opts = {}) {
|
|
|
38669
40000
|
}, 500);
|
|
38670
40001
|
return;
|
|
38671
40002
|
}
|
|
38672
|
-
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(
|
|
40003
|
+
const cancelMatch = /^\/v1\/runs\/([^/]+)\/cancel$/.exec(path47);
|
|
38673
40004
|
if (req.method === "POST" && cancelMatch) {
|
|
38674
40005
|
const runId = cancelMatch[1];
|
|
38675
40006
|
const result = runs.cancel(runId);
|
|
@@ -38781,11 +40112,11 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
38781
40112
|
import { existsSync as existsSync45, readFileSync as readFileSync35, readlinkSync, statSync as statSync7 } from "node:fs";
|
|
38782
40113
|
import { createRequire as createRequire3 } from "node:module";
|
|
38783
40114
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
38784
|
-
import
|
|
40115
|
+
import path46 from "node:path";
|
|
38785
40116
|
function findPackageRoot(start) {
|
|
38786
40117
|
let dir = start;
|
|
38787
40118
|
for (let i = 0; i < 6; i += 1) {
|
|
38788
|
-
const candidate =
|
|
40119
|
+
const candidate = path46.join(dir, "package.json");
|
|
38789
40120
|
if (existsSync45(candidate)) {
|
|
38790
40121
|
try {
|
|
38791
40122
|
const pkg = JSON.parse(readFileSync35(candidate, "utf8"));
|
|
@@ -38793,11 +40124,11 @@ function findPackageRoot(start) {
|
|
|
38793
40124
|
} catch {
|
|
38794
40125
|
}
|
|
38795
40126
|
}
|
|
38796
|
-
const parent =
|
|
40127
|
+
const parent = path46.dirname(dir);
|
|
38797
40128
|
if (parent === dir) break;
|
|
38798
40129
|
dir = parent;
|
|
38799
40130
|
}
|
|
38800
|
-
return
|
|
40131
|
+
return path46.resolve(__dirname3, "..", "..", "..");
|
|
38801
40132
|
}
|
|
38802
40133
|
function tryExec(cmd) {
|
|
38803
40134
|
try {
|
|
@@ -38811,7 +40142,7 @@ function tryExec(cmd) {
|
|
|
38811
40142
|
}
|
|
38812
40143
|
function readPackageJson3() {
|
|
38813
40144
|
try {
|
|
38814
|
-
const pkgPath =
|
|
40145
|
+
const pkgPath = path46.join(packageRoot, "package.json");
|
|
38815
40146
|
return JSON.parse(readFileSync35(pkgPath, "utf8"));
|
|
38816
40147
|
} catch {
|
|
38817
40148
|
return null;
|
|
@@ -38827,7 +40158,7 @@ function checkShim(pkgName) {
|
|
|
38827
40158
|
}
|
|
38828
40159
|
const isWin = process.platform === "win32";
|
|
38829
40160
|
const shimName = isWin ? "zelari-code.cmd" : "zelari-code";
|
|
38830
|
-
const shimPath =
|
|
40161
|
+
const shimPath = path46.join(prefix, shimName);
|
|
38831
40162
|
if (!existsSync45(shimPath)) {
|
|
38832
40163
|
return FAIL(
|
|
38833
40164
|
`shim not found at ${shimPath}
|
|
@@ -38855,8 +40186,8 @@ function checkShim(pkgName) {
|
|
|
38855
40186
|
fix: npm install -g ${pkgName}@latest --force`
|
|
38856
40187
|
);
|
|
38857
40188
|
}
|
|
38858
|
-
const resolved =
|
|
38859
|
-
const expected =
|
|
40189
|
+
const resolved = path46.resolve(path46.dirname(shimPath), target);
|
|
40190
|
+
const expected = path46.join(
|
|
38860
40191
|
prefix,
|
|
38861
40192
|
"node_modules",
|
|
38862
40193
|
pkgName,
|
|
@@ -38895,7 +40226,7 @@ function checkNode(pkg) {
|
|
|
38895
40226
|
return OK(`node ${raw}`);
|
|
38896
40227
|
}
|
|
38897
40228
|
function checkBundle() {
|
|
38898
|
-
const bundle =
|
|
40229
|
+
const bundle = path46.join(packageRoot, "dist", "cli", "main.bundled.js");
|
|
38899
40230
|
if (!existsSync45(bundle)) {
|
|
38900
40231
|
return FAIL(
|
|
38901
40232
|
`dist/cli/main.bundled.js missing at ${bundle}
|
|
@@ -38916,7 +40247,7 @@ function checkRuntimeDeps() {
|
|
|
38916
40247
|
const missing = [];
|
|
38917
40248
|
for (const dep of required2) {
|
|
38918
40249
|
try {
|
|
38919
|
-
const localReq = createRequire3(
|
|
40250
|
+
const localReq = createRequire3(path46.join(packageRoot, "package.json"));
|
|
38920
40251
|
localReq.resolve(dep);
|
|
38921
40252
|
} catch {
|
|
38922
40253
|
missing.push(dep);
|
|
@@ -38993,7 +40324,7 @@ function prereqToCheckResult(r) {
|
|
|
38993
40324
|
return r.severity === "critical" ? FAIL(r.message, "critical") : WARN(r.message);
|
|
38994
40325
|
}
|
|
38995
40326
|
async function checkOptionalPlugins() {
|
|
38996
|
-
const { detectMissingPlugins: detectMissingPlugins2 } = await Promise.resolve().then(() => (
|
|
40327
|
+
const { detectMissingPlugins: detectMissingPlugins2 } = await Promise.resolve().then(() => (init_registry3(), registry_exports));
|
|
38997
40328
|
let missing;
|
|
38998
40329
|
try {
|
|
38999
40330
|
missing = await detectMissingPlugins2(packageRoot, { includeMuted: true });
|
|
@@ -39092,7 +40423,7 @@ var init_doctor = __esm({
|
|
|
39092
40423
|
"use strict";
|
|
39093
40424
|
init_prereqChecks();
|
|
39094
40425
|
require3 = createRequire3(import.meta.url);
|
|
39095
|
-
__dirname3 =
|
|
40426
|
+
__dirname3 = path46.dirname(fileURLToPath2(import.meta.url));
|
|
39096
40427
|
packageRoot = findPackageRoot(__dirname3);
|
|
39097
40428
|
OK = (message) => ({
|
|
39098
40429
|
ok: true,
|
|
@@ -39332,9 +40663,9 @@ function tryParseJson(s) {
|
|
|
39332
40663
|
}
|
|
39333
40664
|
}
|
|
39334
40665
|
function truncateLines(lines) {
|
|
39335
|
-
const
|
|
39336
|
-
if (lines.length <=
|
|
39337
|
-
return [...lines.slice(0,
|
|
40666
|
+
const cap3 = toolOutputLineCap();
|
|
40667
|
+
if (lines.length <= cap3) return lines;
|
|
40668
|
+
return [...lines.slice(0, cap3), `\u2026 (+${lines.length - cap3} lines)`];
|
|
39338
40669
|
}
|
|
39339
40670
|
function formatBytes(n) {
|
|
39340
40671
|
if (n >= 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;
|
|
@@ -39522,7 +40853,7 @@ function rel(p3) {
|
|
|
39522
40853
|
}
|
|
39523
40854
|
}
|
|
39524
40855
|
function formatToolSummary(toolName, args, maxWidth) {
|
|
39525
|
-
const
|
|
40856
|
+
const cap3 = maxWidth && maxWidth > 10 ? maxWidth : 100;
|
|
39526
40857
|
const lower = toolName.toLowerCase();
|
|
39527
40858
|
const a = args && typeof args === "object" ? args : {};
|
|
39528
40859
|
let summary;
|
|
@@ -39545,7 +40876,7 @@ function formatToolSummary(toolName, args, maxWidth) {
|
|
|
39545
40876
|
const json2 = JSON.stringify(args) ?? "";
|
|
39546
40877
|
summary = json2;
|
|
39547
40878
|
}
|
|
39548
|
-
return summary.length >
|
|
40879
|
+
return summary.length > cap3 ? `${summary.slice(0, cap3 - 1)}\u2026` : summary;
|
|
39549
40880
|
}
|
|
39550
40881
|
|
|
39551
40882
|
// src/cli/components/ToolOutput.tsx
|
|
@@ -44957,6 +46288,20 @@ ${formatSkillList(availableSkills)}`
|
|
|
44957
46288
|
graphPrompt: args.slice(1).join(" ").trim()
|
|
44958
46289
|
};
|
|
44959
46290
|
}
|
|
46291
|
+
if (args[0] === "fanout") {
|
|
46292
|
+
return {
|
|
46293
|
+
handled: true,
|
|
46294
|
+
kind: "kraken_fanout",
|
|
46295
|
+
fanoutArgs: args.slice(1).join(" ").trim()
|
|
46296
|
+
};
|
|
46297
|
+
}
|
|
46298
|
+
if (args[0] === "workbench") {
|
|
46299
|
+
return {
|
|
46300
|
+
handled: true,
|
|
46301
|
+
kind: "kraken_workbench",
|
|
46302
|
+
workbenchArgs: args.slice(1).join(" ").trim()
|
|
46303
|
+
};
|
|
46304
|
+
}
|
|
44960
46305
|
const sessionArg = args.join(" ").trim();
|
|
44961
46306
|
return {
|
|
44962
46307
|
handled: true,
|
|
@@ -45571,6 +46916,508 @@ ${digest}
|
|
|
45571
46916
|
}
|
|
45572
46917
|
}
|
|
45573
46918
|
|
|
46919
|
+
// src/cli/slashHandlers/krakenFanout.ts
|
|
46920
|
+
init_auditLogger();
|
|
46921
|
+
init_toolRegistry();
|
|
46922
|
+
import { promises as fs21 } from "node:fs";
|
|
46923
|
+
|
|
46924
|
+
// src/cli/tools/krakenCsvFanout.ts
|
|
46925
|
+
init_zod();
|
|
46926
|
+
init_taskTool();
|
|
46927
|
+
import { promises as fs20 } from "node:fs";
|
|
46928
|
+
import path36 from "node:path";
|
|
46929
|
+
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
46930
|
+
var CsvFanoutArgsSchema = external_exports.object({
|
|
46931
|
+
csv_path: external_exports.string().min(1),
|
|
46932
|
+
id_column: external_exports.string().min(1),
|
|
46933
|
+
output_csv_path: external_exports.string().min(1),
|
|
46934
|
+
/** Template with `{column_name}` placeholders. The tentacle's prompt is
|
|
46935
|
+
* the template with each row's values substituted. */
|
|
46936
|
+
instruction_template: external_exports.string().min(1),
|
|
46937
|
+
/** Default 'verify' — read-mostly workloads are the common case. */
|
|
46938
|
+
agent_kind: external_exports.enum(["explore", "general", "verify"]).default("verify"),
|
|
46939
|
+
thoroughness: external_exports.enum(["quick", "medium", "deep"]).default("medium"),
|
|
46940
|
+
/** Optional: per-row scope template with `{column}` placeholders. The
|
|
46941
|
+
* resulting path/glob list is fed to the scope-overlap check. */
|
|
46942
|
+
scope_template: external_exports.array(external_exports.string()).optional(),
|
|
46943
|
+
/** Default: ZELARI_KRAKEN_MAX_PARALLEL. */
|
|
46944
|
+
max_concurrency: external_exports.number().int().positive().optional(),
|
|
46945
|
+
/** Per-row timeout (ms). Default: 5 min for verify, 15 min for general. */
|
|
46946
|
+
max_runtime_seconds: external_exports.number().int().positive().optional()
|
|
46947
|
+
});
|
|
46948
|
+
async function readCsv(filePath) {
|
|
46949
|
+
const text = await fs20.readFile(filePath, "utf8");
|
|
46950
|
+
return parseCsv(text);
|
|
46951
|
+
}
|
|
46952
|
+
function parseCsv(text) {
|
|
46953
|
+
const records = [];
|
|
46954
|
+
let row = [];
|
|
46955
|
+
let field = "";
|
|
46956
|
+
let inQuotes = false;
|
|
46957
|
+
for (let i = 0; i < text.length; i++) {
|
|
46958
|
+
const ch = text[i];
|
|
46959
|
+
if (inQuotes) {
|
|
46960
|
+
if (ch === '"') {
|
|
46961
|
+
if (text[i + 1] === '"') {
|
|
46962
|
+
field += '"';
|
|
46963
|
+
i += 1;
|
|
46964
|
+
} else inQuotes = false;
|
|
46965
|
+
} else {
|
|
46966
|
+
field += ch;
|
|
46967
|
+
}
|
|
46968
|
+
} else {
|
|
46969
|
+
if (ch === '"') inQuotes = true;
|
|
46970
|
+
else if (ch === ",") {
|
|
46971
|
+
row.push(field);
|
|
46972
|
+
field = "";
|
|
46973
|
+
} else if (ch === "\n") {
|
|
46974
|
+
row.push(field);
|
|
46975
|
+
records.push(row);
|
|
46976
|
+
row = [];
|
|
46977
|
+
field = "";
|
|
46978
|
+
} else if (ch === "\r") {
|
|
46979
|
+
} else field += ch;
|
|
46980
|
+
}
|
|
46981
|
+
}
|
|
46982
|
+
if (field !== "" || row.length > 0) {
|
|
46983
|
+
row.push(field);
|
|
46984
|
+
records.push(row);
|
|
46985
|
+
}
|
|
46986
|
+
while (records.length > 0 && records[records.length - 1].length === 1 && records[records.length - 1][0] === "") {
|
|
46987
|
+
records.pop();
|
|
46988
|
+
}
|
|
46989
|
+
if (records.length === 0) return { headers: [], rows: [] };
|
|
46990
|
+
const headers = records[0];
|
|
46991
|
+
const rows = records.slice(1).map((r) => {
|
|
46992
|
+
const obj = {};
|
|
46993
|
+
for (let i = 0; i < headers.length; i++) obj[headers[i]] = r[i] ?? "";
|
|
46994
|
+
return obj;
|
|
46995
|
+
});
|
|
46996
|
+
return { headers, rows };
|
|
46997
|
+
}
|
|
46998
|
+
function applyTemplate(template, row) {
|
|
46999
|
+
return template.replace(/\{([a-zA-Z_][\w-]*)\}/g, (_, k) => row[k] ?? "");
|
|
47000
|
+
}
|
|
47001
|
+
function serializeCsv(headers, rows) {
|
|
47002
|
+
const escape = (v) => {
|
|
47003
|
+
if (v.includes(",") || v.includes("\n") || v.includes('"')) {
|
|
47004
|
+
return `"${v.replace(/"/g, '""')}"`;
|
|
47005
|
+
}
|
|
47006
|
+
return v;
|
|
47007
|
+
};
|
|
47008
|
+
const out = [headers.map(escape).join(",")];
|
|
47009
|
+
for (const row of rows) {
|
|
47010
|
+
out.push(headers.map((h) => escape(row[h] ?? "")).join(","));
|
|
47011
|
+
}
|
|
47012
|
+
return out.join("\n") + "\n";
|
|
47013
|
+
}
|
|
47014
|
+
function resolveMaxConcurrency(env = process.env) {
|
|
47015
|
+
const raw = env.ZELARI_KRAKEN_MAX_PARALLEL;
|
|
47016
|
+
if (raw === void 0 || raw === "") return 12;
|
|
47017
|
+
const n = Number.parseInt(raw, 10);
|
|
47018
|
+
return Number.isFinite(n) && n > 0 ? n : 12;
|
|
47019
|
+
}
|
|
47020
|
+
async function runCsvFanout(args, deps, opts) {
|
|
47021
|
+
const start = Date.now();
|
|
47022
|
+
const absCsv = path36.isAbsolute(args.csv_path) ? args.csv_path : path36.join(opts.parentCwd, args.csv_path);
|
|
47023
|
+
const absOut = path36.isAbsolute(args.output_csv_path) ? args.output_csv_path : path36.join(opts.parentCwd, args.output_csv_path);
|
|
47024
|
+
const { headers, rows } = await readCsv(absCsv);
|
|
47025
|
+
if (headers.length === 0) {
|
|
47026
|
+
throw new Error(`kraken_csv_fanout: ${absCsv} is empty`);
|
|
47027
|
+
}
|
|
47028
|
+
if (!args.id_column) {
|
|
47029
|
+
throw new Error("kraken_csv_fanout: id_column is required");
|
|
47030
|
+
}
|
|
47031
|
+
if (!headers.includes(args.id_column)) {
|
|
47032
|
+
throw new Error(`kraken_csv_fanout: id_column "${args.id_column}" not in CSV header [${headers.join(", ")}]`);
|
|
47033
|
+
}
|
|
47034
|
+
const concurrency = args.max_concurrency ?? resolveMaxConcurrency();
|
|
47035
|
+
opts.onLog?.(`csv fanout: ${rows.length} rows \xD7 ${args.agent_kind} @ concurrency=${concurrency}`);
|
|
47036
|
+
const perRowMs = args.max_runtime_seconds !== void 0 ? args.max_runtime_seconds * 1e3 : args.agent_kind === "general" ? 9e5 : 3e5;
|
|
47037
|
+
const outputRecords = rows.map((r) => ({ ...r, status: "pending", result: "", error: "" }));
|
|
47038
|
+
const outHeaders = [...headers, "status", "result", "error"];
|
|
47039
|
+
let writeChain2 = Promise.resolve();
|
|
47040
|
+
function queueWrite(contents) {
|
|
47041
|
+
const next = writeChain2.then(() => atomicWrite(absOut, contents));
|
|
47042
|
+
writeChain2 = next.catch(() => {
|
|
47043
|
+
});
|
|
47044
|
+
return next;
|
|
47045
|
+
}
|
|
47046
|
+
let nextIndex = 0;
|
|
47047
|
+
let completed = 0;
|
|
47048
|
+
let errored = 0;
|
|
47049
|
+
const errors = [];
|
|
47050
|
+
async function worker() {
|
|
47051
|
+
while (true) {
|
|
47052
|
+
const i = nextIndex;
|
|
47053
|
+
nextIndex += 1;
|
|
47054
|
+
if (i >= rows.length) return;
|
|
47055
|
+
const row = rows[i];
|
|
47056
|
+
const prompt = applyTemplate(args.instruction_template, row);
|
|
47057
|
+
const scope = args.scope_template?.map((t) => applyTemplate(t, row));
|
|
47058
|
+
const res = await runTentacle({
|
|
47059
|
+
deps,
|
|
47060
|
+
args: {
|
|
47061
|
+
description: `csv-row ${row[args.id_column] ?? i}`,
|
|
47062
|
+
prompt,
|
|
47063
|
+
...scope ? { scope } : {}
|
|
47064
|
+
},
|
|
47065
|
+
agent: args.agent_kind,
|
|
47066
|
+
thoroughness: args.thoroughness,
|
|
47067
|
+
parentCwd: opts.parentCwd,
|
|
47068
|
+
sessionId: opts.sessionId
|
|
47069
|
+
});
|
|
47070
|
+
outputRecords[i].status = res.ok ? "ok" : "error";
|
|
47071
|
+
if (res.ok) {
|
|
47072
|
+
outputRecords[i].result = res.result;
|
|
47073
|
+
completed += 1;
|
|
47074
|
+
} else {
|
|
47075
|
+
outputRecords[i].error = res.error;
|
|
47076
|
+
errored += 1;
|
|
47077
|
+
errors.push(`${row[args.id_column] ?? i}: ${res.error}`);
|
|
47078
|
+
}
|
|
47079
|
+
await fs20.mkdir(path36.dirname(absOut), { recursive: true });
|
|
47080
|
+
await queueWrite(serializeCsv(outHeaders, outputRecords));
|
|
47081
|
+
}
|
|
47082
|
+
}
|
|
47083
|
+
const pool = Array.from({ length: Math.min(concurrency, rows.length) }, () => worker());
|
|
47084
|
+
await Promise.all(pool);
|
|
47085
|
+
const durationMs = Date.now() - start;
|
|
47086
|
+
opts.onLog?.(`csv fanout: ${completed} ok, ${errored} error, ${durationMs}ms`);
|
|
47087
|
+
if (errored > 0) {
|
|
47088
|
+
opts.onLog?.(`csv fanout: first 3 errors:
|
|
47089
|
+
- ${errors.slice(0, 3).join("\n - ")}`);
|
|
47090
|
+
}
|
|
47091
|
+
return {
|
|
47092
|
+
rows: rows.length,
|
|
47093
|
+
completed,
|
|
47094
|
+
errored,
|
|
47095
|
+
output_csv_path: absOut,
|
|
47096
|
+
durationMs
|
|
47097
|
+
};
|
|
47098
|
+
}
|
|
47099
|
+
async function atomicWrite(file2, contents) {
|
|
47100
|
+
const tmp = `${file2}.${process.pid}.${Date.now()}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
47101
|
+
await fs20.writeFile(tmp, contents, "utf8");
|
|
47102
|
+
await fs20.rename(tmp, file2);
|
|
47103
|
+
}
|
|
47104
|
+
|
|
47105
|
+
// src/cli/slashHandlers/krakenFanout.ts
|
|
47106
|
+
function parseFanoutArgs(argv) {
|
|
47107
|
+
if (argv.length === 0) {
|
|
47108
|
+
return { ok: false, usage: USAGE };
|
|
47109
|
+
}
|
|
47110
|
+
const positional = [];
|
|
47111
|
+
const flags = {};
|
|
47112
|
+
const listFlags = {};
|
|
47113
|
+
for (let i = 0; i < argv.length; i++) {
|
|
47114
|
+
const a = argv[i];
|
|
47115
|
+
if (a.startsWith("--")) {
|
|
47116
|
+
const eq = a.indexOf("=");
|
|
47117
|
+
if (eq >= 0) {
|
|
47118
|
+
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
47119
|
+
} else if (i + 1 < argv.length && !argv[i + 1].startsWith("--")) {
|
|
47120
|
+
flags[a.slice(2)] = argv[i + 1];
|
|
47121
|
+
i += 1;
|
|
47122
|
+
} else {
|
|
47123
|
+
flags[a.slice(2)] = true;
|
|
47124
|
+
}
|
|
47125
|
+
} else {
|
|
47126
|
+
positional.push(a);
|
|
47127
|
+
}
|
|
47128
|
+
}
|
|
47129
|
+
const csv = positional[0] ?? (typeof flags.csv === "string" ? flags.csv : void 0);
|
|
47130
|
+
const col = typeof flags.col === "string" ? flags.col : void 0;
|
|
47131
|
+
const out = typeof flags.out === "string" ? flags.out : void 0;
|
|
47132
|
+
const instruction = typeof flags.instruction === "string" ? flags.instruction : void 0;
|
|
47133
|
+
if (!csv) return { ok: false, error: "csv_path is required (positional or --csv)" };
|
|
47134
|
+
if (!col) return { ok: false, error: "--col <id_column> is required" };
|
|
47135
|
+
if (!out) return { ok: false, error: "--out <output_csv_path> is required" };
|
|
47136
|
+
if (!instruction) return { ok: false, error: "--instruction <template> is required" };
|
|
47137
|
+
const agentKindRaw = typeof flags.agent === "string" ? flags.agent : "verify";
|
|
47138
|
+
if (agentKindRaw !== "explore" && agentKindRaw !== "verify" && agentKindRaw !== "general") {
|
|
47139
|
+
return { ok: false, error: `--agent must be one of explore, verify, general (got "${agentKindRaw}")` };
|
|
47140
|
+
}
|
|
47141
|
+
const thoroughnessRaw = typeof flags.thoroughness === "string" ? flags.thoroughness : "medium";
|
|
47142
|
+
if (thoroughnessRaw !== "quick" && thoroughnessRaw !== "medium" && thoroughnessRaw !== "deep") {
|
|
47143
|
+
return { ok: false, error: `--thoroughness must be one of quick, medium, deep (got "${thoroughnessRaw}")` };
|
|
47144
|
+
}
|
|
47145
|
+
let concurrency;
|
|
47146
|
+
if (typeof flags.concurrency === "string") {
|
|
47147
|
+
concurrency = Number.parseInt(flags.concurrency, 10);
|
|
47148
|
+
if (!Number.isFinite(concurrency) || concurrency <= 0) {
|
|
47149
|
+
return { ok: false, error: `--concurrency must be a positive integer (got "${flags.concurrency}")` };
|
|
47150
|
+
}
|
|
47151
|
+
}
|
|
47152
|
+
let maxRuntimeSeconds;
|
|
47153
|
+
if (typeof flags["max-runtime"] === "string") {
|
|
47154
|
+
maxRuntimeSeconds = Number.parseInt(flags["max-runtime"], 10);
|
|
47155
|
+
if (!Number.isFinite(maxRuntimeSeconds) || maxRuntimeSeconds <= 0) {
|
|
47156
|
+
return { ok: false, error: `--max-runtime must be a positive integer (got "${flags["max-runtime"]}")` };
|
|
47157
|
+
}
|
|
47158
|
+
}
|
|
47159
|
+
const scopeList = listFlags.scope ?? (typeof flags.scope === "string" ? [flags.scope] : void 0);
|
|
47160
|
+
return {
|
|
47161
|
+
ok: true,
|
|
47162
|
+
args: {
|
|
47163
|
+
csv_path: csv,
|
|
47164
|
+
id_column: col,
|
|
47165
|
+
output_csv_path: out,
|
|
47166
|
+
instruction_template: instruction,
|
|
47167
|
+
agent_kind: agentKindRaw,
|
|
47168
|
+
thoroughness: thoroughnessRaw,
|
|
47169
|
+
...scopeList ? { scope_template: scopeList } : {},
|
|
47170
|
+
...concurrency !== void 0 ? { max_concurrency: concurrency } : {},
|
|
47171
|
+
...maxRuntimeSeconds !== void 0 ? { max_runtime_seconds: maxRuntimeSeconds } : {}
|
|
47172
|
+
}
|
|
47173
|
+
};
|
|
47174
|
+
}
|
|
47175
|
+
var USAGE = `Usage:
|
|
47176
|
+
/kraken fanout <csv_path>
|
|
47177
|
+
--col <id_column>
|
|
47178
|
+
--out <output_csv_path>
|
|
47179
|
+
--instruction "<template with {column} placeholders>"
|
|
47180
|
+
[--agent explore|verify|general] (default: verify)
|
|
47181
|
+
[--thoroughness quick|medium|deep] (default: medium)
|
|
47182
|
+
[--scope "<glob template>"] (repeatable)
|
|
47183
|
+
[--concurrency <n>] (default: ZELARI_KRAKEN_MAX_PARALLEL)
|
|
47184
|
+
[--max-runtime <seconds>]
|
|
47185
|
+
|
|
47186
|
+
Each row in <csv_path> becomes one sub-agent tentacle. The result CSV
|
|
47187
|
+
gets one row per input row, with extra columns \`status\`, \`result\`, \`error\`.`;
|
|
47188
|
+
async function handleKrakenFanout(ctx, raw) {
|
|
47189
|
+
const argv = splitArgs(stripPrefix(raw, "fanout"));
|
|
47190
|
+
const parsed = parseFanoutArgs(argv);
|
|
47191
|
+
if (!parsed.ok || !parsed.args) {
|
|
47192
|
+
appendSystem(ctx.setMessages, parsed.usage ?? `Usage: ${USAGE}`);
|
|
47193
|
+
if (parsed.error) {
|
|
47194
|
+
appendSystem(ctx.setMessages, `[kraken fanout] ${parsed.error}`);
|
|
47195
|
+
}
|
|
47196
|
+
return;
|
|
47197
|
+
}
|
|
47198
|
+
const absCsv = isAbsolute(parsed.args.csv_path) ? parsed.args.csv_path : joinPath(ctx.cwd, parsed.args.csv_path);
|
|
47199
|
+
try {
|
|
47200
|
+
await fs21.access(absCsv);
|
|
47201
|
+
} catch {
|
|
47202
|
+
appendSystem(ctx.setMessages, `[kraken fanout] source CSV not found: ${absCsv}`);
|
|
47203
|
+
return;
|
|
47204
|
+
}
|
|
47205
|
+
appendSystem(
|
|
47206
|
+
ctx.setMessages,
|
|
47207
|
+
`[kraken fanout] starting: ${parsed.args.csv_path} \u2192 ${parsed.args.output_csv_path} (agent=${parsed.args.agent_kind})`
|
|
47208
|
+
);
|
|
47209
|
+
const audit = new AuditLogger();
|
|
47210
|
+
const taskToolDeps = {
|
|
47211
|
+
createSubAgentContext: createKrakenSubAgentContextFactory({
|
|
47212
|
+
root: ctx.cwd,
|
|
47213
|
+
audit,
|
|
47214
|
+
sessionId: ctx.sessionId
|
|
47215
|
+
})
|
|
47216
|
+
};
|
|
47217
|
+
try {
|
|
47218
|
+
const summary = await runCsvFanout(parsed.args, taskToolDeps, {
|
|
47219
|
+
parentCwd: ctx.cwd,
|
|
47220
|
+
sessionId: ctx.sessionId,
|
|
47221
|
+
onLog: (line) => appendSystem(ctx.setMessages, `[kraken fanout] ${line}`)
|
|
47222
|
+
});
|
|
47223
|
+
appendSystem(
|
|
47224
|
+
ctx.setMessages,
|
|
47225
|
+
`[kraken fanout] done: ${summary.completed}/${summary.rows} ok, ${summary.errored} error, ${summary.durationMs}ms \u2192 ${summary.output_csv_path}`
|
|
47226
|
+
);
|
|
47227
|
+
} catch (err) {
|
|
47228
|
+
appendSystem(
|
|
47229
|
+
ctx.setMessages,
|
|
47230
|
+
`[kraken fanout] failed: ${err instanceof Error ? err.message : String(err)}`
|
|
47231
|
+
);
|
|
47232
|
+
}
|
|
47233
|
+
}
|
|
47234
|
+
function isAbsolute(p3) {
|
|
47235
|
+
return /^([A-Za-z]:[\\/]|[\\/])/.test(p3);
|
|
47236
|
+
}
|
|
47237
|
+
function joinPath(a, b) {
|
|
47238
|
+
if (a.endsWith("\\") || a.endsWith("/")) return a + b;
|
|
47239
|
+
return `${a}\\${b}`;
|
|
47240
|
+
}
|
|
47241
|
+
function stripPrefix(s, prefix) {
|
|
47242
|
+
const trimmed = s.trim();
|
|
47243
|
+
if (trimmed.toLowerCase().startsWith(prefix.toLowerCase())) {
|
|
47244
|
+
return trimmed.slice(prefix.length).trim();
|
|
47245
|
+
}
|
|
47246
|
+
return trimmed;
|
|
47247
|
+
}
|
|
47248
|
+
function splitArgs(s) {
|
|
47249
|
+
const out = [];
|
|
47250
|
+
let cur = "";
|
|
47251
|
+
let inQuotes = false;
|
|
47252
|
+
for (let i = 0; i < s.length; i++) {
|
|
47253
|
+
const ch = s[i];
|
|
47254
|
+
if (ch === '"') {
|
|
47255
|
+
inQuotes = !inQuotes;
|
|
47256
|
+
continue;
|
|
47257
|
+
}
|
|
47258
|
+
if (!inQuotes && /\s/.test(ch)) {
|
|
47259
|
+
if (cur !== "") {
|
|
47260
|
+
out.push(cur);
|
|
47261
|
+
cur = "";
|
|
47262
|
+
}
|
|
47263
|
+
continue;
|
|
47264
|
+
}
|
|
47265
|
+
cur += ch;
|
|
47266
|
+
}
|
|
47267
|
+
if (cur !== "") out.push(cur);
|
|
47268
|
+
return out;
|
|
47269
|
+
}
|
|
47270
|
+
|
|
47271
|
+
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
47272
|
+
import { promises as fs22 } from "node:fs";
|
|
47273
|
+
import path37 from "node:path";
|
|
47274
|
+
|
|
47275
|
+
// src/cli/kraken/workbenchView.ts
|
|
47276
|
+
var EMPTY = {
|
|
47277
|
+
goal: "",
|
|
47278
|
+
graphId: "",
|
|
47279
|
+
started: "",
|
|
47280
|
+
elapsed: "",
|
|
47281
|
+
progress: "",
|
|
47282
|
+
nodes: [],
|
|
47283
|
+
events: []
|
|
47284
|
+
};
|
|
47285
|
+
function parseWorkbench(content) {
|
|
47286
|
+
if (!content) return { ...EMPTY, nodes: [], events: [] };
|
|
47287
|
+
const lines = content.split(/\r?\n/);
|
|
47288
|
+
const out = { ...EMPTY, nodes: [], events: [] };
|
|
47289
|
+
let i = 0;
|
|
47290
|
+
while (i < lines.length) {
|
|
47291
|
+
const line = lines[i];
|
|
47292
|
+
const goalM = /^\*\*Goal:\*\*\s*(.*)$/.exec(line);
|
|
47293
|
+
if (goalM) {
|
|
47294
|
+
out.goal = goalM[1];
|
|
47295
|
+
i += 1;
|
|
47296
|
+
continue;
|
|
47297
|
+
}
|
|
47298
|
+
const gidM = /^\*\*Graph id:\*\*\s*`?([^`\s]*)`?/.exec(line);
|
|
47299
|
+
if (gidM) {
|
|
47300
|
+
out.graphId = gidM[1];
|
|
47301
|
+
i += 1;
|
|
47302
|
+
continue;
|
|
47303
|
+
}
|
|
47304
|
+
const startedM = /^\*\*Started:\*\*\s*(.+?)\s*·\s*\*\*Elapsed:\*\*\s*(\S+)/.exec(line);
|
|
47305
|
+
if (startedM) {
|
|
47306
|
+
out.started = startedM[1];
|
|
47307
|
+
out.elapsed = startedM[2];
|
|
47308
|
+
i += 1;
|
|
47309
|
+
continue;
|
|
47310
|
+
}
|
|
47311
|
+
const justStarted = /^\*\*Started:\*\*\s*(.*)$/.exec(line);
|
|
47312
|
+
if (justStarted) {
|
|
47313
|
+
out.started = justStarted[1];
|
|
47314
|
+
i += 1;
|
|
47315
|
+
continue;
|
|
47316
|
+
}
|
|
47317
|
+
const sectionM = /^##\s+([^:\s]+)(?::\s*(.*))?/.exec(line);
|
|
47318
|
+
if (!sectionM) {
|
|
47319
|
+
i += 1;
|
|
47320
|
+
continue;
|
|
47321
|
+
}
|
|
47322
|
+
const section = sectionM[1];
|
|
47323
|
+
const inline = sectionM[2] ?? "";
|
|
47324
|
+
if (section === "Progress") {
|
|
47325
|
+
if (inline) out.progress = inline;
|
|
47326
|
+
i += 1;
|
|
47327
|
+
continue;
|
|
47328
|
+
}
|
|
47329
|
+
if (section === "Wave") {
|
|
47330
|
+
while (i < lines.length && !lines[i].startsWith("| t")) i += 1;
|
|
47331
|
+
while (i < lines.length && lines[i].startsWith("| t")) {
|
|
47332
|
+
const cells = splitRow(lines[i]);
|
|
47333
|
+
if (cells.length >= 7) {
|
|
47334
|
+
out.nodes.push({
|
|
47335
|
+
id: cells[0],
|
|
47336
|
+
label: cells[1],
|
|
47337
|
+
kind: cells[2],
|
|
47338
|
+
scope: cells[3],
|
|
47339
|
+
status: cells[4],
|
|
47340
|
+
model: cells[5],
|
|
47341
|
+
duration: cells[6]
|
|
47342
|
+
});
|
|
47343
|
+
}
|
|
47344
|
+
i += 1;
|
|
47345
|
+
}
|
|
47346
|
+
continue;
|
|
47347
|
+
}
|
|
47348
|
+
if (section === "Events" || section.startsWith("Events")) {
|
|
47349
|
+
while (i < lines.length && !lines[i].startsWith("- ")) i += 1;
|
|
47350
|
+
while (i < lines.length && lines[i].startsWith("- ")) {
|
|
47351
|
+
const m = /^-\s+(\d{2}:\d{2}:\d{2})\s+(.*)$/.exec(lines[i]);
|
|
47352
|
+
if (m) out.events.push({ ts: m[1], text: m[2] });
|
|
47353
|
+
i += 1;
|
|
47354
|
+
}
|
|
47355
|
+
continue;
|
|
47356
|
+
}
|
|
47357
|
+
i += 1;
|
|
47358
|
+
}
|
|
47359
|
+
return out;
|
|
47360
|
+
}
|
|
47361
|
+
function splitRow(line) {
|
|
47362
|
+
return line.replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
47363
|
+
}
|
|
47364
|
+
function formatWorkbenchForTerminal(p3) {
|
|
47365
|
+
const lines = [];
|
|
47366
|
+
if (p3.goal) lines.push(`[kraken] ${p3.goal}`);
|
|
47367
|
+
if (p3.progress) lines.push(`[kraken] progress: ${p3.progress}`);
|
|
47368
|
+
if (p3.elapsed) lines.push(`[kraken] elapsed: ${p3.elapsed}`);
|
|
47369
|
+
lines.push("");
|
|
47370
|
+
if (p3.nodes.length > 0) {
|
|
47371
|
+
lines.push("[kraken] wave:");
|
|
47372
|
+
for (const n of p3.nodes) {
|
|
47373
|
+
const scope = n.scope ? ` (${n.scope})` : "";
|
|
47374
|
+
const dur = n.duration ? ` ${n.duration}` : "";
|
|
47375
|
+
lines.push(` ${n.status} ${n.id} ${n.label}${scope}${dur ? " " + dur : ""}`);
|
|
47376
|
+
}
|
|
47377
|
+
lines.push("");
|
|
47378
|
+
}
|
|
47379
|
+
if (p3.events.length > 0) {
|
|
47380
|
+
lines.push("[kraken] events (latest):");
|
|
47381
|
+
for (const e of p3.events.slice(-10)) {
|
|
47382
|
+
lines.push(` ${e.ts} ${e.text}`);
|
|
47383
|
+
}
|
|
47384
|
+
}
|
|
47385
|
+
return lines.join("\n");
|
|
47386
|
+
}
|
|
47387
|
+
|
|
47388
|
+
// src/cli/slashHandlers/krakenWorkbench.ts
|
|
47389
|
+
async function handleKrakenWorkbench(ctx) {
|
|
47390
|
+
const dir = path37.join(ctx.cwd, ".zelari", "radio");
|
|
47391
|
+
let latest = null;
|
|
47392
|
+
let latestMtime = 0;
|
|
47393
|
+
try {
|
|
47394
|
+
const files = await fs22.readdir(dir);
|
|
47395
|
+
for (const f of files) {
|
|
47396
|
+
if (!f.startsWith("workbench-") || !f.endsWith(".md")) continue;
|
|
47397
|
+
const full = path37.join(dir, f);
|
|
47398
|
+
const stat = await fs22.stat(full);
|
|
47399
|
+
if (stat.mtimeMs > latestMtime) {
|
|
47400
|
+
latestMtime = stat.mtimeMs;
|
|
47401
|
+
latest = full;
|
|
47402
|
+
}
|
|
47403
|
+
}
|
|
47404
|
+
} catch {
|
|
47405
|
+
}
|
|
47406
|
+
if (!latest) {
|
|
47407
|
+
appendSystem(ctx.setMessages, "[kraken workbench] no workbench file found (.zelari/radio/workbench-*.md)");
|
|
47408
|
+
return;
|
|
47409
|
+
}
|
|
47410
|
+
const content = await fs22.readFile(latest, "utf8");
|
|
47411
|
+
const parsed = parseWorkbench(content);
|
|
47412
|
+
const rendered = formatWorkbenchForTerminal(parsed);
|
|
47413
|
+
if (!rendered.trim()) {
|
|
47414
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path37.basename(latest)}: (no nodes / no events yet)`);
|
|
47415
|
+
return;
|
|
47416
|
+
}
|
|
47417
|
+
appendSystem(ctx.setMessages, `[kraken workbench] ${path37.basename(latest)}:
|
|
47418
|
+
${rendered}`);
|
|
47419
|
+
}
|
|
47420
|
+
|
|
45574
47421
|
// src/cli/compaction.ts
|
|
45575
47422
|
function compactTranscript(messages, options = {}) {
|
|
45576
47423
|
const threshold = options.threshold ?? 50;
|
|
@@ -45714,7 +47561,7 @@ ${output}`.toLowerCase();
|
|
|
45714
47561
|
}
|
|
45715
47562
|
|
|
45716
47563
|
// src/cli/slashHandlers/plugins.ts
|
|
45717
|
-
|
|
47564
|
+
init_registry3();
|
|
45718
47565
|
|
|
45719
47566
|
// src/cli/plugins/installer.ts
|
|
45720
47567
|
init_cmdline();
|
|
@@ -45868,17 +47715,17 @@ ${result.output.split("\n").slice(-8).join("\n")}` : "";
|
|
|
45868
47715
|
}
|
|
45869
47716
|
|
|
45870
47717
|
// src/cli/slashHandlers/promoteMember.ts
|
|
45871
|
-
import { promises as
|
|
45872
|
-
import
|
|
47718
|
+
import { promises as fs23 } from "node:fs";
|
|
47719
|
+
import path40 from "node:path";
|
|
45873
47720
|
import os10 from "node:os";
|
|
45874
47721
|
async function handlePromoteMember(ctx, memberId) {
|
|
45875
47722
|
try {
|
|
45876
47723
|
const { promoteMember: promoteMember2 } = await Promise.resolve().then(() => (init_council(), council_exports));
|
|
45877
47724
|
const { skill, markdown } = promoteMember2(memberId);
|
|
45878
|
-
const skillDir = process.env.ANATHEMA_SKILL_DIR ??
|
|
45879
|
-
await
|
|
45880
|
-
const filePath =
|
|
45881
|
-
await
|
|
47725
|
+
const skillDir = process.env.ANATHEMA_SKILL_DIR ?? path40.join(os10.homedir(), ".tmp", "zelari-code", "skills");
|
|
47726
|
+
await fs23.mkdir(skillDir, { recursive: true });
|
|
47727
|
+
const filePath = path40.join(skillDir, `${skill.id}.md`);
|
|
47728
|
+
await fs23.writeFile(filePath, markdown, "utf8");
|
|
45882
47729
|
appendSystem(
|
|
45883
47730
|
ctx.setMessages,
|
|
45884
47731
|
`[promote-member] ${skill.name} (${memberId}) \u2192 ${filePath}
|
|
@@ -45894,25 +47741,25 @@ async function handlePromoteMember(ctx, memberId) {
|
|
|
45894
47741
|
}
|
|
45895
47742
|
|
|
45896
47743
|
// src/cli/branchManager.ts
|
|
45897
|
-
import { promises as
|
|
45898
|
-
import
|
|
47744
|
+
import { promises as fs24, existsSync as existsSync38, readFileSync as readFileSync30, writeFileSync as writeFileSync19, mkdirSync as mkdirSync16, statSync as statSync4, rmSync as rmSync3 } from "node:fs";
|
|
47745
|
+
import path41 from "node:path";
|
|
45899
47746
|
import os11 from "node:os";
|
|
45900
47747
|
var META_FILENAME = "meta.json";
|
|
45901
47748
|
var SESSIONS_SUBDIR = "sessions";
|
|
45902
47749
|
function getBranchesBaseDir() {
|
|
45903
|
-
return process.env.ANATHEMA_BRANCHES_DIR ??
|
|
47750
|
+
return process.env.ANATHEMA_BRANCHES_DIR ?? path41.join(os11.homedir(), ".tmp", "zelari-code", "branches");
|
|
45904
47751
|
}
|
|
45905
47752
|
function getSessionsBaseDir() {
|
|
45906
|
-
return process.env.ANATHEMA_SESSIONS_DIR ??
|
|
47753
|
+
return process.env.ANATHEMA_SESSIONS_DIR ?? path41.join(os11.homedir(), ".tmp", "zelari-code", "sessions");
|
|
45907
47754
|
}
|
|
45908
47755
|
function branchPathFor(name, baseDir) {
|
|
45909
|
-
return
|
|
47756
|
+
return path41.join(baseDir, name);
|
|
45910
47757
|
}
|
|
45911
47758
|
function metaPathFor(name, baseDir) {
|
|
45912
|
-
return
|
|
47759
|
+
return path41.join(baseDir, name, META_FILENAME);
|
|
45913
47760
|
}
|
|
45914
47761
|
function sessionsPathFor(name, baseDir) {
|
|
45915
|
-
return
|
|
47762
|
+
return path41.join(baseDir, name, SESSIONS_SUBDIR);
|
|
45916
47763
|
}
|
|
45917
47764
|
function readBranchMeta(name, baseDir) {
|
|
45918
47765
|
const metaPath = metaPathFor(name, baseDir);
|
|
@@ -45937,13 +47784,13 @@ function readBranchMeta(name, baseDir) {
|
|
|
45937
47784
|
}
|
|
45938
47785
|
function writeBranchMeta(name, baseDir, meta3) {
|
|
45939
47786
|
const metaPath = metaPathFor(name, baseDir);
|
|
45940
|
-
mkdirSync16(
|
|
47787
|
+
mkdirSync16(path41.dirname(metaPath), { recursive: true });
|
|
45941
47788
|
writeFileSync19(metaPath, JSON.stringify(meta3, null, 2), "utf-8");
|
|
45942
47789
|
}
|
|
45943
47790
|
async function countSessions(name, baseDir) {
|
|
45944
47791
|
const sessionsPath = sessionsPathFor(name, baseDir);
|
|
45945
47792
|
try {
|
|
45946
|
-
const entries = await
|
|
47793
|
+
const entries = await fs24.readdir(sessionsPath);
|
|
45947
47794
|
return entries.filter((e) => e.endsWith(".jsonl")).length;
|
|
45948
47795
|
} catch (err) {
|
|
45949
47796
|
if (err.code === "ENOENT") return 0;
|
|
@@ -45988,15 +47835,15 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
45988
47835
|
if (branchExists(name, baseDir)) {
|
|
45989
47836
|
throw new BranchAlreadyExistsError(name);
|
|
45990
47837
|
}
|
|
45991
|
-
const sourcePath =
|
|
47838
|
+
const sourcePath = path41.join(sessionsBaseDir, `${fromSessionId}.jsonl`);
|
|
45992
47839
|
if (!existsSync38(sourcePath)) {
|
|
45993
47840
|
throw new SessionNotFoundError(`Source session "${fromSessionId}" not found at ${sourcePath}`);
|
|
45994
47841
|
}
|
|
45995
47842
|
const branchPath = branchPathFor(name, baseDir);
|
|
45996
47843
|
const branchSessionsPath = sessionsPathFor(name, baseDir);
|
|
45997
47844
|
mkdirSync16(branchSessionsPath, { recursive: true });
|
|
45998
|
-
const destPath =
|
|
45999
|
-
await
|
|
47845
|
+
const destPath = path41.join(branchSessionsPath, `${fromSessionId}.jsonl`);
|
|
47846
|
+
await fs24.copyFile(sourcePath, destPath);
|
|
46000
47847
|
const meta3 = {
|
|
46001
47848
|
name,
|
|
46002
47849
|
createdAt: Date.now(),
|
|
@@ -46014,7 +47861,7 @@ async function createBranch(name, fromSessionId, baseDir = getBranchesBaseDir(),
|
|
|
46014
47861
|
async function listBranches(baseDir = getBranchesBaseDir()) {
|
|
46015
47862
|
let entries;
|
|
46016
47863
|
try {
|
|
46017
|
-
entries = await
|
|
47864
|
+
entries = await fs24.readdir(baseDir);
|
|
46018
47865
|
} catch (err) {
|
|
46019
47866
|
if (err.code === "ENOENT") return [];
|
|
46020
47867
|
throw err;
|
|
@@ -46095,26 +47942,26 @@ async function handleBranchCheckout(ctx, branchName) {
|
|
|
46095
47942
|
}
|
|
46096
47943
|
|
|
46097
47944
|
// src/cli/slashHandlers/workspace.ts
|
|
46098
|
-
import { promises as
|
|
46099
|
-
import
|
|
47945
|
+
import { promises as fs25 } from "node:fs";
|
|
47946
|
+
import path42 from "node:path";
|
|
46100
47947
|
async function handleWorkspaceShow(ctx, what) {
|
|
46101
47948
|
try {
|
|
46102
|
-
const zelari =
|
|
47949
|
+
const zelari = path42.join(process.cwd(), ".zelari");
|
|
46103
47950
|
let content;
|
|
46104
47951
|
switch (what) {
|
|
46105
47952
|
case "plan": {
|
|
46106
|
-
const planPath =
|
|
47953
|
+
const planPath = path42.join(zelari, "plan.md");
|
|
46107
47954
|
try {
|
|
46108
|
-
content = await
|
|
47955
|
+
content = await fs25.readFile(planPath, "utf-8");
|
|
46109
47956
|
} catch {
|
|
46110
47957
|
content = "(no plan.md yet \u2014 run a council session first)";
|
|
46111
47958
|
}
|
|
46112
47959
|
break;
|
|
46113
47960
|
}
|
|
46114
47961
|
case "decisions": {
|
|
46115
|
-
const decisionsDir =
|
|
47962
|
+
const decisionsDir = path42.join(zelari, "decisions");
|
|
46116
47963
|
try {
|
|
46117
|
-
const files = (await
|
|
47964
|
+
const files = (await fs25.readdir(decisionsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
46118
47965
|
if (files.length === 0) {
|
|
46119
47966
|
content = "(no ADRs yet \u2014 invoke /council to generate some)";
|
|
46120
47967
|
} else {
|
|
@@ -46122,7 +47969,7 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
46122
47969
|
`];
|
|
46123
47970
|
const { parseFrontmatter: parseFrontmatter2 } = await Promise.resolve().then(() => (init_storage(), storage_exports));
|
|
46124
47971
|
for (const f of files) {
|
|
46125
|
-
const raw = await
|
|
47972
|
+
const raw = await fs25.readFile(path42.join(decisionsDir, f), "utf-8");
|
|
46126
47973
|
const { meta: meta3, body } = parseFrontmatter2(raw);
|
|
46127
47974
|
const title = meta3.title ?? body.split("\n")[0]?.replace(/^#\s*/, "").trim() ?? f;
|
|
46128
47975
|
lines.push(`- **${f.replace(/\.md$/, "")}** [${meta3.status ?? "unknown"}] ${title}`);
|
|
@@ -46135,27 +47982,27 @@ async function handleWorkspaceShow(ctx, what) {
|
|
|
46135
47982
|
break;
|
|
46136
47983
|
}
|
|
46137
47984
|
case "risks": {
|
|
46138
|
-
const risksPath =
|
|
47985
|
+
const risksPath = path42.join(zelari, "risks.md");
|
|
46139
47986
|
try {
|
|
46140
|
-
content = await
|
|
47987
|
+
content = await fs25.readFile(risksPath, "utf-8");
|
|
46141
47988
|
} catch {
|
|
46142
47989
|
content = "(no risks.md yet)";
|
|
46143
47990
|
}
|
|
46144
47991
|
break;
|
|
46145
47992
|
}
|
|
46146
47993
|
case "agents": {
|
|
46147
|
-
const agentsPath =
|
|
47994
|
+
const agentsPath = path42.join(process.cwd(), "AGENTS.MD");
|
|
46148
47995
|
try {
|
|
46149
|
-
content = await
|
|
47996
|
+
content = await fs25.readFile(agentsPath, "utf-8");
|
|
46150
47997
|
} catch {
|
|
46151
47998
|
content = "(no AGENTS.MD yet at project root \u2014 run `/workspace sync` after a council session)";
|
|
46152
47999
|
}
|
|
46153
48000
|
break;
|
|
46154
48001
|
}
|
|
46155
48002
|
case "docs": {
|
|
46156
|
-
const docsDir =
|
|
48003
|
+
const docsDir = path42.join(zelari, "docs");
|
|
46157
48004
|
try {
|
|
46158
|
-
const files = (await
|
|
48005
|
+
const files = (await fs25.readdir(docsDir)).filter((f) => f.endsWith(".md")).sort();
|
|
46159
48006
|
content = files.length ? `# Docs (${files.length})
|
|
46160
48007
|
|
|
46161
48008
|
` + files.map((f) => `- ${f}`).join("\n") : "(no docs drafts yet)";
|
|
@@ -46195,8 +48042,8 @@ async function handleWorkspaceReset(ctx, force) {
|
|
|
46195
48042
|
return;
|
|
46196
48043
|
}
|
|
46197
48044
|
try {
|
|
46198
|
-
const target =
|
|
46199
|
-
await
|
|
48045
|
+
const target = path42.join(process.cwd(), ".zelari");
|
|
48046
|
+
await fs25.rm(target, { recursive: true, force: true });
|
|
46200
48047
|
appendSystem(ctx.setMessages, "[workspace] .zelari/ removed");
|
|
46201
48048
|
} catch (err) {
|
|
46202
48049
|
appendSystem(ctx.setMessages, `[workspace reset error] ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -46555,16 +48402,16 @@ function handleModelsRefresh(ctx) {
|
|
|
46555
48402
|
}
|
|
46556
48403
|
|
|
46557
48404
|
// src/cli/slashHandlers/skills.ts
|
|
46558
|
-
import
|
|
48405
|
+
import path43 from "node:path";
|
|
46559
48406
|
import os12 from "node:os";
|
|
46560
48407
|
|
|
46561
48408
|
// src/cli/skillHistory.ts
|
|
46562
|
-
import { promises as
|
|
48409
|
+
import { promises as fs26, existsSync as existsSync39, statSync as statSync5, renameSync as renameSync4, appendFileSync as appendFileSync4, mkdirSync as mkdirSync17 } from "node:fs";
|
|
46563
48410
|
var SKILL_HISTORY_ROTATE_BYTES = 10 * 1024 * 1024;
|
|
46564
48411
|
async function readSkillHistory(file2) {
|
|
46565
48412
|
let raw = "";
|
|
46566
48413
|
try {
|
|
46567
|
-
raw = await
|
|
48414
|
+
raw = await fs26.readFile(file2, "utf-8");
|
|
46568
48415
|
} catch {
|
|
46569
48416
|
return [];
|
|
46570
48417
|
}
|
|
@@ -46681,7 +48528,7 @@ function handleSkillPicker(ctx, skills, openPicker, fallbackMessage) {
|
|
|
46681
48528
|
});
|
|
46682
48529
|
}
|
|
46683
48530
|
async function handleSkillStats(ctx, skillId) {
|
|
46684
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
48531
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path43.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
46685
48532
|
try {
|
|
46686
48533
|
const records = await readSkillHistory(historyFile);
|
|
46687
48534
|
const stats = getSkillStats(records, skillId);
|
|
@@ -46697,7 +48544,7 @@ async function handleSkillCompare(ctx, ids, fallbackMessage) {
|
|
|
46697
48544
|
appendSystem(ctx.setMessages, fallbackMessage ?? "[skill-compare] missing args");
|
|
46698
48545
|
return;
|
|
46699
48546
|
}
|
|
46700
|
-
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ??
|
|
48547
|
+
const historyFile = process.env.ANATHEMA_SKILL_HISTORY_FILE ?? path43.join(os12.homedir(), ".tmp", "zelari-code", "skill-history.jsonl");
|
|
46701
48548
|
try {
|
|
46702
48549
|
const formatted = await compareSkillsFromFile(ids[0], ids[1], historyFile);
|
|
46703
48550
|
appendSystem(ctx.setMessages, formatted);
|
|
@@ -47121,6 +48968,18 @@ function useSlashDispatch(params) {
|
|
|
47121
48968
|
await handleKrakenGraph({ setMessages, cwd: process.cwd(), sessionId: sid }, result.graphPrompt ?? "");
|
|
47122
48969
|
return;
|
|
47123
48970
|
}
|
|
48971
|
+
if (result.kind === "kraken_fanout") {
|
|
48972
|
+
const sid = (sessionId || "default").trim();
|
|
48973
|
+
await handleKrakenFanout(
|
|
48974
|
+
{ setMessages, cwd: process.cwd(), sessionId: sid },
|
|
48975
|
+
result.fanoutArgs ?? ""
|
|
48976
|
+
);
|
|
48977
|
+
return;
|
|
48978
|
+
}
|
|
48979
|
+
if (result.kind === "kraken_workbench") {
|
|
48980
|
+
await handleKrakenWorkbench({ setMessages, cwd: process.cwd() });
|
|
48981
|
+
return;
|
|
48982
|
+
}
|
|
47124
48983
|
if (result.kind === "phase_set" && result.phaseTarget) {
|
|
47125
48984
|
const { setPhase: setPhase2 } = await Promise.resolve().then(() => (init_phaseState(), phaseState_exports));
|
|
47126
48985
|
const { describePhase: describePhase2 } = await Promise.resolve().then(() => (init_phase(), phase_exports));
|
|
@@ -47704,7 +49563,7 @@ function SplashGate({
|
|
|
47704
49563
|
// src/cli/components/PluginGate.tsx
|
|
47705
49564
|
import React12, { useEffect as useEffect9, useState as useState10, useCallback as useCallback6 } from "react";
|
|
47706
49565
|
import { Box as Box11, Text as Text12, useStdin as useStdin4 } from "ink";
|
|
47707
|
-
|
|
49566
|
+
init_registry3();
|
|
47708
49567
|
init_prefs();
|
|
47709
49568
|
var CHOICE_INSTALL = "__install__";
|
|
47710
49569
|
var CHOICE_LATER = "__later__";
|
|
@@ -48144,6 +50003,8 @@ function parseHeadlessFlags(argv) {
|
|
|
48144
50003
|
let history2;
|
|
48145
50004
|
let once = false;
|
|
48146
50005
|
let krakenGraph;
|
|
50006
|
+
let planOnly = process.env.ZELARI_KRAKEN_PLAN_ONLY === "1" || process.env.ZELARI_KRAKEN_PLAN_ONLY === "true";
|
|
50007
|
+
let runPlan = process.env.ZELARI_KRAKEN_RUN_PLAN;
|
|
48147
50008
|
for (let i = 0; i < argv.length; i++) {
|
|
48148
50009
|
const arg = argv[i];
|
|
48149
50010
|
if (arg === "--headless") continue;
|
|
@@ -48237,6 +50098,11 @@ function parseHeadlessFlags(argv) {
|
|
|
48237
50098
|
} else if (arg === "--kraken-graph") {
|
|
48238
50099
|
krakenGraph = argv[i + 1];
|
|
48239
50100
|
i++;
|
|
50101
|
+
} else if (arg === "--plan-only") {
|
|
50102
|
+
planOnly = true;
|
|
50103
|
+
} else if (arg === "--run-plan") {
|
|
50104
|
+
runPlan = argv[i + 1];
|
|
50105
|
+
i++;
|
|
48240
50106
|
}
|
|
48241
50107
|
}
|
|
48242
50108
|
if (councilFlag && !modeExplicit) {
|
|
@@ -48264,7 +50130,9 @@ function parseHeadlessFlags(argv) {
|
|
|
48264
50130
|
model,
|
|
48265
50131
|
...history2 && history2.length > 0 ? { history: history2 } : {},
|
|
48266
50132
|
...once ? { once: true } : {},
|
|
48267
|
-
...krakenGraph ? { krakenGraph } : {}
|
|
50133
|
+
...krakenGraph ? { krakenGraph } : {},
|
|
50134
|
+
...planOnly ? { planOnly: true } : {},
|
|
50135
|
+
...runPlan ? { runPlan } : {}
|
|
48268
50136
|
}
|
|
48269
50137
|
};
|
|
48270
50138
|
}
|
|
@@ -48335,6 +50203,9 @@ function createStreamScrubber() {
|
|
|
48335
50203
|
|
|
48336
50204
|
// src/cli/runHeadless.ts
|
|
48337
50205
|
init_taskTool();
|
|
50206
|
+
import { promises as fs28 } from "node:fs";
|
|
50207
|
+
import path45 from "node:path";
|
|
50208
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
48338
50209
|
async function runHeadless(opts) {
|
|
48339
50210
|
resetTaskSpawnCount();
|
|
48340
50211
|
try {
|
|
@@ -48443,11 +50314,39 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
48443
50314
|
};
|
|
48444
50315
|
process.once("SIGINT", onSigint);
|
|
48445
50316
|
try {
|
|
50317
|
+
let preflightGraph;
|
|
50318
|
+
if (opts.runPlan && opts.runPlan.trim() !== "") {
|
|
50319
|
+
const planPath = path45.join(cwd, ".zelari", "radio", `plan-${opts.runPlan}.json`);
|
|
50320
|
+
log(`loading pre-flight plan: ${planPath}`);
|
|
50321
|
+
let raw;
|
|
50322
|
+
try {
|
|
50323
|
+
raw = await fs28.readFile(planPath, "utf8");
|
|
50324
|
+
} catch (e) {
|
|
50325
|
+
log(`plan file not found: ${planPath} (${e.message})`);
|
|
50326
|
+
return 1;
|
|
50327
|
+
}
|
|
50328
|
+
let planJson;
|
|
50329
|
+
try {
|
|
50330
|
+
planJson = JSON.parse(raw);
|
|
50331
|
+
} catch (e) {
|
|
50332
|
+
log(`plan file is malformed JSON: ${e.message}`);
|
|
50333
|
+
return 1;
|
|
50334
|
+
}
|
|
50335
|
+
if (!planJson || !Array.isArray(planJson.nodes)) {
|
|
50336
|
+
log(`plan file is malformed: missing "nodes" array`);
|
|
50337
|
+
return 1;
|
|
50338
|
+
}
|
|
50339
|
+
const { createGraph: createGraph2, validateGraph: validateGraph2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
50340
|
+
const validated = createGraph2(planJson.graphId ?? opts.runPlan, planJson.nodes);
|
|
50341
|
+
validateGraph2(validated);
|
|
50342
|
+
preflightGraph = validated;
|
|
50343
|
+
log(`pre-flight plan loaded (${validated.nodes.size} nodes); executing`);
|
|
50344
|
+
}
|
|
48446
50345
|
log(`planning kraken graph: ${prompt}`);
|
|
48447
50346
|
const previous = await loadGraphSnapshot2(cwd);
|
|
48448
50347
|
const previousAttempt = formatSnapshotForPlanner2(previous);
|
|
48449
50348
|
if (previousAttempt) log("resuming from the previous unfinished graph");
|
|
48450
|
-
const graph = await planTaskGraph2({
|
|
50349
|
+
const graph = preflightGraph ?? await planTaskGraph2({
|
|
48451
50350
|
prompt,
|
|
48452
50351
|
provider,
|
|
48453
50352
|
model,
|
|
@@ -48455,6 +50354,22 @@ async function runHeadlessKrakenGraph(opts, provider, model) {
|
|
|
48455
50354
|
...previousAttempt ? { previousAttempt } : {}
|
|
48456
50355
|
});
|
|
48457
50356
|
log(formatKrakenGraphAscii2(graph));
|
|
50357
|
+
if (opts.planOnly) {
|
|
50358
|
+
const planId = randomUUID6();
|
|
50359
|
+
const planDir = path45.join(cwd, ".zelari", "radio");
|
|
50360
|
+
const planPath = path45.join(planDir, `plan-${planId}.json`);
|
|
50361
|
+
await fs28.mkdir(planDir, { recursive: true });
|
|
50362
|
+
await fs28.writeFile(planPath, JSON.stringify(graph, null, 2), "utf8");
|
|
50363
|
+
log(`plan-only: wrote ${planPath} (${graph.nodes.size} nodes)`);
|
|
50364
|
+
log(
|
|
50365
|
+
`re-run with ZELARI_KRAKEN_RUN_PLAN=${planId} to execute (or --run-plan <id> when the desktop wiring is in place)`
|
|
50366
|
+
);
|
|
50367
|
+
if (opts.output === "json") {
|
|
50368
|
+
emitEvent({ type: "log", message: `plan_only_id=${planId}` });
|
|
50369
|
+
emitEvent({ type: "log", message: `plan_only_path=${planPath}` });
|
|
50370
|
+
}
|
|
50371
|
+
return 0;
|
|
50372
|
+
}
|
|
48458
50373
|
const audit = new AuditLogger2();
|
|
48459
50374
|
const executor = new KrakenGraphExecutor2({
|
|
48460
50375
|
taskToolDeps: {
|
|
@@ -49330,7 +51245,7 @@ ${ragContext}` : slicePrompt;
|
|
|
49330
51245
|
init_desktopConfig();
|
|
49331
51246
|
|
|
49332
51247
|
// src/cli/plugins/cliFlags.ts
|
|
49333
|
-
|
|
51248
|
+
init_registry3();
|
|
49334
51249
|
function getArg(argv, flag) {
|
|
49335
51250
|
const i = argv.indexOf(flag);
|
|
49336
51251
|
if (i < 0) return void 0;
|
|
@@ -49630,7 +51545,7 @@ function upsertSkill(opts) {
|
|
|
49630
51545
|
}
|
|
49631
51546
|
dir = getProjectSkillsDir(root);
|
|
49632
51547
|
}
|
|
49633
|
-
const
|
|
51548
|
+
const path47 = skillFilePath(dir, name);
|
|
49634
51549
|
const content = serializeSkillMd({
|
|
49635
51550
|
name,
|
|
49636
51551
|
description,
|
|
@@ -49639,13 +51554,13 @@ function upsertSkill(opts) {
|
|
|
49639
51554
|
tools: opts.tools,
|
|
49640
51555
|
cost: opts.cost
|
|
49641
51556
|
});
|
|
49642
|
-
const parsed = parseSkillMd(content,
|
|
51557
|
+
const parsed = parseSkillMd(content, path47);
|
|
49643
51558
|
if (!parsed) {
|
|
49644
51559
|
return { ok: false, error: "Generated SKILL.md failed validation" };
|
|
49645
51560
|
}
|
|
49646
|
-
mkdirSync18(dirname9(
|
|
49647
|
-
writeFileSync20(
|
|
49648
|
-
return { ok: true, path:
|
|
51561
|
+
mkdirSync18(dirname9(path47), { recursive: true });
|
|
51562
|
+
writeFileSync20(path47, content, "utf8");
|
|
51563
|
+
return { ok: true, path: path47 };
|
|
49649
51564
|
}
|
|
49650
51565
|
function removeSkill(opts) {
|
|
49651
51566
|
const name = opts.name.trim().toLowerCase();
|
|
@@ -49663,8 +51578,8 @@ function removeSkill(opts) {
|
|
|
49663
51578
|
dir = getProjectSkillsDir(root);
|
|
49664
51579
|
}
|
|
49665
51580
|
const skillDir = join34(dir, name);
|
|
49666
|
-
const
|
|
49667
|
-
if (!existsSync42(
|
|
51581
|
+
const path47 = skillFilePath(dir, name);
|
|
51582
|
+
if (!existsSync42(path47) && !existsSync42(skillDir)) {
|
|
49668
51583
|
return { ok: false, error: `Skill "${name}" not found in ${dir}` };
|
|
49669
51584
|
}
|
|
49670
51585
|
try {
|
|
@@ -49675,7 +51590,7 @@ function removeSkill(opts) {
|
|
|
49675
51590
|
error: err instanceof Error ? err.message : String(err)
|
|
49676
51591
|
};
|
|
49677
51592
|
}
|
|
49678
|
-
return { ok: true, path:
|
|
51593
|
+
return { ok: true, path: path47 };
|
|
49679
51594
|
}
|
|
49680
51595
|
|
|
49681
51596
|
// src/cli/generateSkillFromUrl.ts
|
|
@@ -49765,8 +51680,8 @@ function normalizeDraft(raw, sourceUrl, provider, model) {
|
|
|
49765
51680
|
let name = String(o.name ?? "").trim().toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64);
|
|
49766
51681
|
if (!name || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name)) {
|
|
49767
51682
|
try {
|
|
49768
|
-
const
|
|
49769
|
-
name =
|
|
51683
|
+
const path47 = new URL(sourceUrl).pathname.split("/").filter(Boolean).pop()?.replace(/\.[a-z0-9]+$/i, "").toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
|
|
51684
|
+
name = path47 && /^[a-z0-9]/.test(path47) ? path47 : "imported-skill";
|
|
49770
51685
|
} catch {
|
|
49771
51686
|
name = "imported-skill";
|
|
49772
51687
|
}
|