@mrciphersmith/keryx 0.2.66 → 0.2.67
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.js +206 -2
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -53486,6 +53486,7 @@ ${lines.join(`
|
|
|
53486
53486
|
|
|
53487
53487
|
// src/tui/tui-shell.ts
|
|
53488
53488
|
init_agent();
|
|
53489
|
+
init_single_turn();
|
|
53489
53490
|
init_slate_lifecycle();
|
|
53490
53491
|
init_slate();
|
|
53491
53492
|
|
|
@@ -53894,7 +53895,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
53894
53895
|
// package.json
|
|
53895
53896
|
var package_default = {
|
|
53896
53897
|
name: "@mrciphersmith/keryx",
|
|
53897
|
-
version: "0.2.
|
|
53898
|
+
version: "0.2.67",
|
|
53898
53899
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
53899
53900
|
private: false,
|
|
53900
53901
|
publishConfig: {
|
|
@@ -55360,10 +55361,13 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
55360
55361
|
}
|
|
55361
55362
|
return groups;
|
|
55362
55363
|
}, []));
|
|
55364
|
+
const metaPath2 = path150.join(extDir, `${id}.json`);
|
|
55365
|
+
if (await pathExists(unboundDismissedReceiptPath(metaPath2)))
|
|
55366
|
+
continue;
|
|
55363
55367
|
candidates.push({
|
|
55364
55368
|
type: "unbound-candidate",
|
|
55365
55369
|
externalSessionId: id,
|
|
55366
|
-
evidencePath:
|
|
55370
|
+
evidencePath: metaPath2,
|
|
55367
55371
|
summary
|
|
55368
55372
|
});
|
|
55369
55373
|
}
|
|
@@ -55381,6 +55385,8 @@ async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
|
55381
55385
|
entries.sort();
|
|
55382
55386
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
55383
55387
|
const evidencePath = path150.join(evidenceDir, entries[i]);
|
|
55388
|
+
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
55389
|
+
continue;
|
|
55384
55390
|
const result = readConfigFile(evidencePath);
|
|
55385
55391
|
if (!result.ok) {
|
|
55386
55392
|
continue;
|
|
@@ -55589,6 +55595,55 @@ async function readTerminalState(dir) {
|
|
|
55589
55595
|
return;
|
|
55590
55596
|
}
|
|
55591
55597
|
}
|
|
55598
|
+
function unboundDismissedReceiptPath(candidatePath) {
|
|
55599
|
+
if (/-unbound-candidate\.json$/.test(candidatePath)) {
|
|
55600
|
+
return candidatePath.replace(/-unbound-candidate\.json$/, "-unbound-dismissed.json");
|
|
55601
|
+
}
|
|
55602
|
+
return candidatePath.replace(/\.json$/, ".dismissed.json");
|
|
55603
|
+
}
|
|
55604
|
+
async function resolveUnboundCandidateTarget(cwd, target) {
|
|
55605
|
+
if (target.endsWith("-unbound-candidate.json") || target.endsWith(".json")) {
|
|
55606
|
+
return target;
|
|
55607
|
+
}
|
|
55608
|
+
const session = findSession(cwd, target);
|
|
55609
|
+
if (session === undefined) {
|
|
55610
|
+
throw new Error(`No session or evidence path matches "${target}"`);
|
|
55611
|
+
}
|
|
55612
|
+
const archiveDir = path150.join(sessionDir(session.projectPath, session.id), "slate-archive");
|
|
55613
|
+
let entries;
|
|
55614
|
+
try {
|
|
55615
|
+
entries = (await readdir26(archiveDir)).filter((name) => name.endsWith("-unbound-candidate.json"));
|
|
55616
|
+
} catch {
|
|
55617
|
+
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
55618
|
+
}
|
|
55619
|
+
if (entries.length === 0)
|
|
55620
|
+
throw new Error(`No unbound-candidate artifacts for session ${session.id}`);
|
|
55621
|
+
entries.sort();
|
|
55622
|
+
return path150.join(archiveDir, entries[entries.length - 1]);
|
|
55623
|
+
}
|
|
55624
|
+
async function dismissUnboundByTarget(cwd, target, reason) {
|
|
55625
|
+
const evidencePath = await resolveUnboundCandidateTarget(cwd, target);
|
|
55626
|
+
return dismissUnboundCandidate(evidencePath, reason);
|
|
55627
|
+
}
|
|
55628
|
+
async function dismissUnboundCandidate(candidatePath, reason) {
|
|
55629
|
+
const { rm: rm10, writeFile: writeFile49 } = await import("fs/promises");
|
|
55630
|
+
const { dirname } = await import("path");
|
|
55631
|
+
await rm10(candidatePath, { force: true });
|
|
55632
|
+
const receiptPath = unboundDismissedReceiptPath(candidatePath);
|
|
55633
|
+
const receipt = {
|
|
55634
|
+
recordType: "unbound-dismissed",
|
|
55635
|
+
dismissedAt: new Date().toISOString(),
|
|
55636
|
+
candidatePath: candidatePath.split("/").pop(),
|
|
55637
|
+
...reason !== undefined ? { reason } : {}
|
|
55638
|
+
};
|
|
55639
|
+
await writeFile49(receiptPath, `${JSON.stringify(receipt, null, 2)}
|
|
55640
|
+
`, "utf8");
|
|
55641
|
+
const parent = dirname(candidatePath);
|
|
55642
|
+
try {
|
|
55643
|
+
await rm10(parent, { force: true, recursive: false });
|
|
55644
|
+
} catch {}
|
|
55645
|
+
return { removed: candidatePath, receipt: receiptPath };
|
|
55646
|
+
}
|
|
55592
55647
|
async function readNewestUnboundCandidate(dir) {
|
|
55593
55648
|
const archiveDir = path150.join(dir, "slate-archive");
|
|
55594
55649
|
let entries;
|
|
@@ -55600,6 +55655,8 @@ async function readNewestUnboundCandidate(dir) {
|
|
|
55600
55655
|
entries.sort();
|
|
55601
55656
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
55602
55657
|
const evidencePath = path150.join(archiveDir, entries[i]);
|
|
55658
|
+
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
55659
|
+
continue;
|
|
55603
55660
|
const result = readConfigFile(evidencePath);
|
|
55604
55661
|
if (!result.ok) {
|
|
55605
55662
|
continue;
|
|
@@ -59371,6 +59428,53 @@ function composerMaxRowsForViewport(viewportRows) {
|
|
|
59371
59428
|
}
|
|
59372
59429
|
return Math.max(COMPOSER_MIN_ROWS, Math.floor(viewportRows / 3));
|
|
59373
59430
|
}
|
|
59431
|
+
function themeColorToHex(value) {
|
|
59432
|
+
if (typeof value === "string") {
|
|
59433
|
+
return /^#[0-9a-fA-F]{6}$/.test(value) ? value.toLowerCase() : undefined;
|
|
59434
|
+
}
|
|
59435
|
+
if (value !== null && typeof value === "object" && typeof value.toInts === "function") {
|
|
59436
|
+
const [r, g, b, a] = value.toInts();
|
|
59437
|
+
if (a !== 255) {
|
|
59438
|
+
return;
|
|
59439
|
+
}
|
|
59440
|
+
return `#${[r, g, b].map((x) => x.toString(16).padStart(2, "0")).join("")}`;
|
|
59441
|
+
}
|
|
59442
|
+
return;
|
|
59443
|
+
}
|
|
59444
|
+
function themeColorRemap(from, to) {
|
|
59445
|
+
const remap = new Map;
|
|
59446
|
+
for (const slot of Object.keys(from)) {
|
|
59447
|
+
if (slot === "name") {
|
|
59448
|
+
continue;
|
|
59449
|
+
}
|
|
59450
|
+
const oldColor = from[slot];
|
|
59451
|
+
const newColor = to[slot];
|
|
59452
|
+
if (typeof oldColor === "string" && typeof newColor === "string" && oldColor !== newColor) {
|
|
59453
|
+
remap.set(oldColor, newColor);
|
|
59454
|
+
}
|
|
59455
|
+
}
|
|
59456
|
+
return remap;
|
|
59457
|
+
}
|
|
59458
|
+
function recolorThemeTree(node, remap) {
|
|
59459
|
+
if (node === null || node === undefined) {
|
|
59460
|
+
return;
|
|
59461
|
+
}
|
|
59462
|
+
const target = node;
|
|
59463
|
+
for (const prop of ["borderColor", "backgroundColor", "fg"]) {
|
|
59464
|
+
const hex = themeColorToHex(target[prop]);
|
|
59465
|
+
if (hex !== undefined) {
|
|
59466
|
+
const next = remap.get(hex);
|
|
59467
|
+
if (next !== undefined) {
|
|
59468
|
+
target[prop] = next;
|
|
59469
|
+
}
|
|
59470
|
+
}
|
|
59471
|
+
}
|
|
59472
|
+
if (typeof target.getChildren === "function") {
|
|
59473
|
+
for (const child of target.getChildren()) {
|
|
59474
|
+
recolorThemeTree(child, remap);
|
|
59475
|
+
}
|
|
59476
|
+
}
|
|
59477
|
+
}
|
|
59374
59478
|
function wrappedLineCount(text, width) {
|
|
59375
59479
|
const inner = Number.isFinite(width) ? Math.floor(width) : 0;
|
|
59376
59480
|
const paragraphs = text.length === 0 ? [""] : text.split(`
|
|
@@ -59408,6 +59512,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59408
59512
|
const filter = opts.filterCommands ?? ((query) => prefixFilter(opts.commands, query));
|
|
59409
59513
|
let uid = 0;
|
|
59410
59514
|
let alive = true;
|
|
59515
|
+
let appliedTheme = getTheme();
|
|
59411
59516
|
const rootRow = new otui.BoxRenderable(r, { id: "root-row", flexGrow: 1, flexDirection: "row" });
|
|
59412
59517
|
r.root.add(rootRow);
|
|
59413
59518
|
const main = new otui.BoxRenderable(r, { id: "main", flexGrow: 1, minWidth: 0, flexDirection: "column" });
|
|
@@ -59805,6 +59910,12 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59805
59910
|
input2.value = "";
|
|
59806
59911
|
hideMenu();
|
|
59807
59912
|
syncComposerHeight();
|
|
59913
|
+
if (line.length === 0 && suggestion !== null) {
|
|
59914
|
+
const next = suggestion;
|
|
59915
|
+
clearSuggestion();
|
|
59916
|
+
emitSubmit(next);
|
|
59917
|
+
return;
|
|
59918
|
+
}
|
|
59808
59919
|
emitSubmit(line);
|
|
59809
59920
|
};
|
|
59810
59921
|
const unsubscribeMenuKeys = onKeypress3(r, (key) => {
|
|
@@ -59843,7 +59954,51 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59843
59954
|
key.stopPropagation();
|
|
59844
59955
|
}
|
|
59845
59956
|
});
|
|
59957
|
+
const defaultPlaceholder = opts.placeholder;
|
|
59958
|
+
let suggestion = null;
|
|
59959
|
+
const syncPlaceholder = () => {
|
|
59960
|
+
textarea.placeholder = suggestion !== null && input2.value.length === 0 ? suggestion : defaultPlaceholder;
|
|
59961
|
+
};
|
|
59962
|
+
const showSuggestion = (text) => {
|
|
59963
|
+
if (text.length === 0)
|
|
59964
|
+
return;
|
|
59965
|
+
suggestion = text;
|
|
59966
|
+
syncPlaceholder();
|
|
59967
|
+
};
|
|
59968
|
+
const clearSuggestion = () => {
|
|
59969
|
+
if (suggestion === null)
|
|
59970
|
+
return;
|
|
59971
|
+
suggestion = null;
|
|
59972
|
+
syncPlaceholder();
|
|
59973
|
+
};
|
|
59974
|
+
const prevContentChange = textarea.onContentChange;
|
|
59975
|
+
textarea.onContentChange = (event) => {
|
|
59976
|
+
if (suggestion !== null)
|
|
59977
|
+
syncPlaceholder();
|
|
59978
|
+
prevContentChange?.(event);
|
|
59979
|
+
};
|
|
59980
|
+
const unsubscribeSuggestionKeys = onKeypress3(r, (key) => {
|
|
59981
|
+
if (suggestion === null || overlayActive())
|
|
59982
|
+
return;
|
|
59983
|
+
if (menu.visible && menuNav)
|
|
59984
|
+
return;
|
|
59985
|
+
if (key.name === "tab" || key.name === "right") {
|
|
59986
|
+
if (input2.value.length === 0) {
|
|
59987
|
+
input2.value = suggestion;
|
|
59988
|
+
clearSuggestion();
|
|
59989
|
+
key.preventDefault();
|
|
59990
|
+
key.stopPropagation();
|
|
59991
|
+
return;
|
|
59992
|
+
}
|
|
59993
|
+
return;
|
|
59994
|
+
}
|
|
59995
|
+
const ch = key.sequence;
|
|
59996
|
+
if (!key.ctrl && !key.meta && typeof ch === "string" && ch.length === 1 && ch >= " ") {
|
|
59997
|
+
clearSuggestion();
|
|
59998
|
+
}
|
|
59999
|
+
});
|
|
59846
60000
|
const applyTheme = (theme = getTheme()) => {
|
|
60001
|
+
const remap = themeColorRemap(appliedTheme, theme);
|
|
59847
60002
|
try {
|
|
59848
60003
|
r.setBackgroundColor(theme.bg);
|
|
59849
60004
|
} catch {}
|
|
@@ -59861,6 +60016,15 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59861
60016
|
menu.selectedTextColor = theme.focus;
|
|
59862
60017
|
menu.descriptionColor = theme.muted;
|
|
59863
60018
|
menu.selectedDescriptionColor = theme.muted;
|
|
60019
|
+
recolorThemeTree(transcript, remap);
|
|
60020
|
+
recolorThemeTree(dock, remap);
|
|
60021
|
+
recolorThemeTree(queueDock, remap);
|
|
60022
|
+
recolorThemeTree(sidebarTop, remap);
|
|
60023
|
+
recolorThemeTree(menu, remap);
|
|
60024
|
+
recolorThemeTree(composer, remap);
|
|
60025
|
+
recolorThemeTree(header3, remap);
|
|
60026
|
+
recolorThemeTree(footer, remap);
|
|
60027
|
+
appliedTheme = theme;
|
|
59864
60028
|
};
|
|
59865
60029
|
const unsubTheme = onThemeChange((theme) => applyTheme(theme));
|
|
59866
60030
|
return {
|
|
@@ -59907,6 +60071,9 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59907
60071
|
setTitle: (text) => paintDim(headerLeft, text),
|
|
59908
60072
|
setStatus: (text) => paintDim(footerRight, text),
|
|
59909
60073
|
setHeaderMeta: (text) => paintDim(headerRight, text),
|
|
60074
|
+
showSuggestion,
|
|
60075
|
+
clearSuggestion,
|
|
60076
|
+
suggestionActive: () => suggestion !== null,
|
|
59910
60077
|
onSubmit: (handler) => {
|
|
59911
60078
|
submitHandlers.add(handler);
|
|
59912
60079
|
return () => {
|
|
@@ -59920,6 +60087,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59920
60087
|
clearBusyTimer();
|
|
59921
60088
|
clearToastTimer();
|
|
59922
60089
|
unsubscribeMenuKeys();
|
|
60090
|
+
unsubscribeSuggestionKeys();
|
|
59923
60091
|
try {
|
|
59924
60092
|
textarea.off(otui.LayoutEvents.RESIZED, onComposerResized);
|
|
59925
60093
|
} catch {}
|
|
@@ -65036,6 +65204,28 @@ ${formatThemeList(getThemeId())}`);
|
|
|
65036
65204
|
};
|
|
65037
65205
|
const controller = new AbortController;
|
|
65038
65206
|
mainTurnAbortController = controller;
|
|
65207
|
+
const suggestNextStep = async () => {
|
|
65208
|
+
try {
|
|
65209
|
+
const lastUser = [...history].reverse().find((m) => m.role === "user")?.content ?? "";
|
|
65210
|
+
const lastAssistant = [...history].reverse().find((m) => m.role === "assistant")?.content ?? "";
|
|
65211
|
+
const tail = lastAssistant.slice(-3000);
|
|
65212
|
+
const result = await runModelTurn({
|
|
65213
|
+
provider: sel.provider,
|
|
65214
|
+
model: sel.model,
|
|
65215
|
+
system: "You are the next-step advisor of a coding assistant terminal. Based on the user's last request and the assistant's final reply, propose ONE short follow-up the user could do next: imperative, no quotes, no markdown, at most 80 characters. If nothing useful exists, reply with exactly one dot: .",
|
|
65216
|
+
user: `User: ${lastUser.slice(-800)}
|
|
65217
|
+
|
|
65218
|
+
Assistant reply (tail):
|
|
65219
|
+
${tail}`,
|
|
65220
|
+
maxOutputTokens: 40,
|
|
65221
|
+
requestId: `suggest-next-step-${Date.now()}`
|
|
65222
|
+
});
|
|
65223
|
+
if (!result.credentialAvailable || result.text.trim().length === 0 || result.text.trim() === ".") {
|
|
65224
|
+
return;
|
|
65225
|
+
}
|
|
65226
|
+
chrome.showSuggestion(result.text.trim().split(/\s+/).slice(0, 20).join(" "));
|
|
65227
|
+
} catch {}
|
|
65228
|
+
};
|
|
65039
65229
|
runAgentTurn(io, deps, history, line, {
|
|
65040
65230
|
signal: controller.signal,
|
|
65041
65231
|
...slateSession !== undefined ? { slateSession } : {}
|
|
@@ -65056,6 +65246,9 @@ ${formatThemeList(getThemeId())}`);
|
|
|
65056
65246
|
sbContext.content = otui.t`${otui.dim(`~${est.toLocaleString()} tokens (est)`)}`;
|
|
65057
65247
|
}
|
|
65058
65248
|
focusComposer();
|
|
65249
|
+
if (priorityMainQuestion === undefined && mainQueue.length === 0 && !turnFailed) {
|
|
65250
|
+
suggestNextStep();
|
|
65251
|
+
}
|
|
65059
65252
|
if (priorityMainQuestion !== undefined) {
|
|
65060
65253
|
const next = priorityMainQuestion;
|
|
65061
65254
|
priorityMainQuestion = undefined;
|
|
@@ -73371,6 +73564,17 @@ async function workspaceCommand(args2) {
|
|
|
73371
73564
|
console.log(JSON.stringify(normalizeProposalLifecycleResult(result), null, 2));
|
|
73372
73565
|
return;
|
|
73373
73566
|
}
|
|
73567
|
+
if (subcommand === "dismiss-candidate") {
|
|
73568
|
+
rejectUnknownOptions(args2.slice(2), new Set(["--reason", "--evidence"]));
|
|
73569
|
+
const target = args2[1];
|
|
73570
|
+
const reason = optionValue(args2, "--reason");
|
|
73571
|
+
const evidence = optionValue(args2, "--evidence");
|
|
73572
|
+
if (!target)
|
|
73573
|
+
throw new Error("Usage: keryx workspace dismiss-candidate <evidence-path|session-id> [--reason <reason>] [--evidence <path>]");
|
|
73574
|
+
const result = await dismissUnboundByTarget(process.cwd(), evidence ?? target, reason);
|
|
73575
|
+
console.log(JSON.stringify(result, null, 2));
|
|
73576
|
+
return;
|
|
73577
|
+
}
|
|
73374
73578
|
if (subcommand === "collaboration") {
|
|
73375
73579
|
rejectUnknownOptions(args2.slice(2), new Set);
|
|
73376
73580
|
const workspaceId = args2[1];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.67",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -72,4 +72,4 @@
|
|
|
72
72
|
"protobufjs",
|
|
73
73
|
"sharp"
|
|
74
74
|
]
|
|
75
|
-
}
|
|
75
|
+
}
|