@mrciphersmith/keryx 0.2.65 → 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 +605 -34
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -28105,6 +28105,332 @@ function looksLikeUnifiedDiff(text) {
|
|
|
28105
28105
|
}
|
|
28106
28106
|
return false;
|
|
28107
28107
|
}
|
|
28108
|
+
var CODE_LANG_ALIASES = {
|
|
28109
|
+
js: "javascript",
|
|
28110
|
+
mjs: "javascript",
|
|
28111
|
+
cjs: "javascript",
|
|
28112
|
+
jsx: "javascript",
|
|
28113
|
+
ts: "typescript",
|
|
28114
|
+
tsx: "typescript",
|
|
28115
|
+
py: "python",
|
|
28116
|
+
py3: "python",
|
|
28117
|
+
sh: "bash",
|
|
28118
|
+
shell: "bash",
|
|
28119
|
+
zsh: "bash",
|
|
28120
|
+
console: "bash",
|
|
28121
|
+
yml: "yaml",
|
|
28122
|
+
rb: "ruby",
|
|
28123
|
+
rs: "rust",
|
|
28124
|
+
kt: "kotlin",
|
|
28125
|
+
cs: "csharp",
|
|
28126
|
+
"c++": "cpp",
|
|
28127
|
+
cc: "cpp",
|
|
28128
|
+
cxx: "cpp",
|
|
28129
|
+
hpp: "cpp"
|
|
28130
|
+
};
|
|
28131
|
+
var GENERIC_KEYWORDS = new Set([
|
|
28132
|
+
"if",
|
|
28133
|
+
"else",
|
|
28134
|
+
"for",
|
|
28135
|
+
"while",
|
|
28136
|
+
"return",
|
|
28137
|
+
"function",
|
|
28138
|
+
"class",
|
|
28139
|
+
"const",
|
|
28140
|
+
"let",
|
|
28141
|
+
"var",
|
|
28142
|
+
"import",
|
|
28143
|
+
"export",
|
|
28144
|
+
"from",
|
|
28145
|
+
"true",
|
|
28146
|
+
"false",
|
|
28147
|
+
"null",
|
|
28148
|
+
"new",
|
|
28149
|
+
"this",
|
|
28150
|
+
"try",
|
|
28151
|
+
"catch",
|
|
28152
|
+
"throw",
|
|
28153
|
+
"switch",
|
|
28154
|
+
"case",
|
|
28155
|
+
"break",
|
|
28156
|
+
"continue",
|
|
28157
|
+
"default",
|
|
28158
|
+
"static",
|
|
28159
|
+
"public",
|
|
28160
|
+
"private"
|
|
28161
|
+
]);
|
|
28162
|
+
var CODE_LANG_KEYWORDS = {
|
|
28163
|
+
javascript: new Set([
|
|
28164
|
+
...GENERIC_KEYWORDS,
|
|
28165
|
+
"async",
|
|
28166
|
+
"await",
|
|
28167
|
+
"yield",
|
|
28168
|
+
"typeof",
|
|
28169
|
+
"instanceof",
|
|
28170
|
+
"in",
|
|
28171
|
+
"of",
|
|
28172
|
+
"void",
|
|
28173
|
+
"undefined",
|
|
28174
|
+
"super",
|
|
28175
|
+
"extends",
|
|
28176
|
+
"finally",
|
|
28177
|
+
"do",
|
|
28178
|
+
"delete"
|
|
28179
|
+
]),
|
|
28180
|
+
typescript: new Set([
|
|
28181
|
+
...GENERIC_KEYWORDS,
|
|
28182
|
+
"async",
|
|
28183
|
+
"await",
|
|
28184
|
+
"yield",
|
|
28185
|
+
"typeof",
|
|
28186
|
+
"instanceof",
|
|
28187
|
+
"in",
|
|
28188
|
+
"of",
|
|
28189
|
+
"void",
|
|
28190
|
+
"undefined",
|
|
28191
|
+
"super",
|
|
28192
|
+
"extends",
|
|
28193
|
+
"implements",
|
|
28194
|
+
"interface",
|
|
28195
|
+
"type",
|
|
28196
|
+
"enum",
|
|
28197
|
+
"namespace",
|
|
28198
|
+
"declare",
|
|
28199
|
+
"readonly",
|
|
28200
|
+
"abstract",
|
|
28201
|
+
"as",
|
|
28202
|
+
"satisfies",
|
|
28203
|
+
"finally",
|
|
28204
|
+
"do",
|
|
28205
|
+
"delete"
|
|
28206
|
+
]),
|
|
28207
|
+
python: new Set([
|
|
28208
|
+
"def",
|
|
28209
|
+
"return",
|
|
28210
|
+
"if",
|
|
28211
|
+
"elif",
|
|
28212
|
+
"else",
|
|
28213
|
+
"for",
|
|
28214
|
+
"while",
|
|
28215
|
+
"break",
|
|
28216
|
+
"continue",
|
|
28217
|
+
"class",
|
|
28218
|
+
"import",
|
|
28219
|
+
"from",
|
|
28220
|
+
"as",
|
|
28221
|
+
"try",
|
|
28222
|
+
"except",
|
|
28223
|
+
"finally",
|
|
28224
|
+
"raise",
|
|
28225
|
+
"with",
|
|
28226
|
+
"lambda",
|
|
28227
|
+
"yield",
|
|
28228
|
+
"pass",
|
|
28229
|
+
"None",
|
|
28230
|
+
"True",
|
|
28231
|
+
"False",
|
|
28232
|
+
"and",
|
|
28233
|
+
"or",
|
|
28234
|
+
"not",
|
|
28235
|
+
"in",
|
|
28236
|
+
"is",
|
|
28237
|
+
"global",
|
|
28238
|
+
"nonlocal",
|
|
28239
|
+
"assert",
|
|
28240
|
+
"async",
|
|
28241
|
+
"await",
|
|
28242
|
+
"del",
|
|
28243
|
+
"self"
|
|
28244
|
+
]),
|
|
28245
|
+
bash: new Set([
|
|
28246
|
+
"if",
|
|
28247
|
+
"then",
|
|
28248
|
+
"else",
|
|
28249
|
+
"elif",
|
|
28250
|
+
"fi",
|
|
28251
|
+
"for",
|
|
28252
|
+
"while",
|
|
28253
|
+
"do",
|
|
28254
|
+
"done",
|
|
28255
|
+
"case",
|
|
28256
|
+
"esac",
|
|
28257
|
+
"function",
|
|
28258
|
+
"return",
|
|
28259
|
+
"local",
|
|
28260
|
+
"export",
|
|
28261
|
+
"exit",
|
|
28262
|
+
"break",
|
|
28263
|
+
"continue",
|
|
28264
|
+
"in",
|
|
28265
|
+
"select",
|
|
28266
|
+
"until"
|
|
28267
|
+
]),
|
|
28268
|
+
go: new Set([
|
|
28269
|
+
"func",
|
|
28270
|
+
"return",
|
|
28271
|
+
"if",
|
|
28272
|
+
"else",
|
|
28273
|
+
"for",
|
|
28274
|
+
"range",
|
|
28275
|
+
"switch",
|
|
28276
|
+
"case",
|
|
28277
|
+
"default",
|
|
28278
|
+
"break",
|
|
28279
|
+
"continue",
|
|
28280
|
+
"package",
|
|
28281
|
+
"import",
|
|
28282
|
+
"var",
|
|
28283
|
+
"const",
|
|
28284
|
+
"type",
|
|
28285
|
+
"struct",
|
|
28286
|
+
"interface",
|
|
28287
|
+
"map",
|
|
28288
|
+
"chan",
|
|
28289
|
+
"go",
|
|
28290
|
+
"defer",
|
|
28291
|
+
"select",
|
|
28292
|
+
"fallthrough",
|
|
28293
|
+
"nil",
|
|
28294
|
+
"true",
|
|
28295
|
+
"false"
|
|
28296
|
+
]),
|
|
28297
|
+
rust: new Set([
|
|
28298
|
+
"fn",
|
|
28299
|
+
"let",
|
|
28300
|
+
"mut",
|
|
28301
|
+
"return",
|
|
28302
|
+
"if",
|
|
28303
|
+
"else",
|
|
28304
|
+
"for",
|
|
28305
|
+
"while",
|
|
28306
|
+
"loop",
|
|
28307
|
+
"match",
|
|
28308
|
+
"struct",
|
|
28309
|
+
"enum",
|
|
28310
|
+
"impl",
|
|
28311
|
+
"trait",
|
|
28312
|
+
"pub",
|
|
28313
|
+
"use",
|
|
28314
|
+
"mod",
|
|
28315
|
+
"crate",
|
|
28316
|
+
"self",
|
|
28317
|
+
"Self",
|
|
28318
|
+
"super",
|
|
28319
|
+
"const",
|
|
28320
|
+
"static",
|
|
28321
|
+
"async",
|
|
28322
|
+
"await",
|
|
28323
|
+
"move",
|
|
28324
|
+
"ref",
|
|
28325
|
+
"dyn",
|
|
28326
|
+
"where",
|
|
28327
|
+
"unsafe",
|
|
28328
|
+
"true",
|
|
28329
|
+
"false",
|
|
28330
|
+
"None",
|
|
28331
|
+
"Some",
|
|
28332
|
+
"Ok",
|
|
28333
|
+
"Err"
|
|
28334
|
+
]),
|
|
28335
|
+
json: new Set(["true", "false", "null"])
|
|
28336
|
+
};
|
|
28337
|
+
function codeCommentPrefix(normalizedLang) {
|
|
28338
|
+
switch (normalizedLang) {
|
|
28339
|
+
case "javascript":
|
|
28340
|
+
case "typescript":
|
|
28341
|
+
case "go":
|
|
28342
|
+
case "rust":
|
|
28343
|
+
case "java":
|
|
28344
|
+
case "c":
|
|
28345
|
+
case "cpp":
|
|
28346
|
+
case "csharp":
|
|
28347
|
+
case "swift":
|
|
28348
|
+
case "kotlin":
|
|
28349
|
+
case "scala":
|
|
28350
|
+
case "php":
|
|
28351
|
+
return "//";
|
|
28352
|
+
case "python":
|
|
28353
|
+
case "bash":
|
|
28354
|
+
case "ruby":
|
|
28355
|
+
case "yaml":
|
|
28356
|
+
case "toml":
|
|
28357
|
+
case "r":
|
|
28358
|
+
case "perl":
|
|
28359
|
+
return "#";
|
|
28360
|
+
case "sql":
|
|
28361
|
+
case "lua":
|
|
28362
|
+
case "haskell":
|
|
28363
|
+
return "--";
|
|
28364
|
+
default:
|
|
28365
|
+
return "";
|
|
28366
|
+
}
|
|
28367
|
+
}
|
|
28368
|
+
function normalizeCodeLang(lang) {
|
|
28369
|
+
const key = lang.trim().toLowerCase();
|
|
28370
|
+
return CODE_LANG_ALIASES[key] ?? key;
|
|
28371
|
+
}
|
|
28372
|
+
var CODE_WORD_OR_NUMBER = /[A-Za-z_$][A-Za-z0-9_$]*|\d+(?:\.\d+)?/g;
|
|
28373
|
+
function tokenizeCodeWords(text, keywords) {
|
|
28374
|
+
const tokens = [];
|
|
28375
|
+
let last = 0;
|
|
28376
|
+
CODE_WORD_OR_NUMBER.lastIndex = 0;
|
|
28377
|
+
let m;
|
|
28378
|
+
while ((m = CODE_WORD_OR_NUMBER.exec(text)) !== null) {
|
|
28379
|
+
if (m.index > last) {
|
|
28380
|
+
tokens.push({ kind: "plain", text: text.slice(last, m.index) });
|
|
28381
|
+
}
|
|
28382
|
+
const word = m[0];
|
|
28383
|
+
if (/^[0-9]/.test(word)) {
|
|
28384
|
+
tokens.push({ kind: "number", text: word });
|
|
28385
|
+
} else if (keywords.has(word)) {
|
|
28386
|
+
tokens.push({ kind: "keyword", text: word });
|
|
28387
|
+
} else {
|
|
28388
|
+
tokens.push({ kind: "plain", text: word });
|
|
28389
|
+
}
|
|
28390
|
+
last = m.index + word.length;
|
|
28391
|
+
}
|
|
28392
|
+
if (last < text.length) {
|
|
28393
|
+
tokens.push({ kind: "plain", text: text.slice(last) });
|
|
28394
|
+
}
|
|
28395
|
+
return tokens;
|
|
28396
|
+
}
|
|
28397
|
+
function tokenizeCodeLine(line, lang) {
|
|
28398
|
+
const normalized = normalizeCodeLang(lang);
|
|
28399
|
+
const keywords = CODE_LANG_KEYWORDS[normalized] ?? GENERIC_KEYWORDS;
|
|
28400
|
+
const commentPrefix = codeCommentPrefix(normalized);
|
|
28401
|
+
const tokens = [];
|
|
28402
|
+
let plainBuf = "";
|
|
28403
|
+
const flushPlain = () => {
|
|
28404
|
+
if (plainBuf.length > 0) {
|
|
28405
|
+
tokens.push(...tokenizeCodeWords(plainBuf, keywords));
|
|
28406
|
+
plainBuf = "";
|
|
28407
|
+
}
|
|
28408
|
+
};
|
|
28409
|
+
let i = 0;
|
|
28410
|
+
while (i < line.length) {
|
|
28411
|
+
if (commentPrefix.length > 0 && line.startsWith(commentPrefix, i)) {
|
|
28412
|
+
flushPlain();
|
|
28413
|
+
tokens.push({ kind: "comment", text: line.slice(i) });
|
|
28414
|
+
break;
|
|
28415
|
+
}
|
|
28416
|
+
const ch = line[i];
|
|
28417
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
28418
|
+
flushPlain();
|
|
28419
|
+
let j = i + 1;
|
|
28420
|
+
while (j < line.length && line[j] !== ch) {
|
|
28421
|
+
j += line[j] === "\\" ? 2 : 1;
|
|
28422
|
+
}
|
|
28423
|
+
j = Math.min(j + 1, line.length);
|
|
28424
|
+
tokens.push({ kind: "string", text: line.slice(i, j) });
|
|
28425
|
+
i = j;
|
|
28426
|
+
continue;
|
|
28427
|
+
}
|
|
28428
|
+
plainBuf += ch;
|
|
28429
|
+
i += 1;
|
|
28430
|
+
}
|
|
28431
|
+
flushPlain();
|
|
28432
|
+
return tokens;
|
|
28433
|
+
}
|
|
28108
28434
|
function payloadKind(lang, _lineCount) {
|
|
28109
28435
|
const normalized = lang.toLowerCase();
|
|
28110
28436
|
if (MARKDOWN_LANGS.has(normalized)) {
|
|
@@ -28121,6 +28447,18 @@ function blockLabel({ kind, lineCount, collapsed, hint }) {
|
|
|
28121
28447
|
const suffix = hint !== undefined && hint.length > 0 ? ` \xB7 ${hint}` : "";
|
|
28122
28448
|
return `${marker} ${kind} (${lineCount} ${unit})${suffix}`;
|
|
28123
28449
|
}
|
|
28450
|
+
function summarizeSubmittedLine(line) {
|
|
28451
|
+
const normalized = line.replace(/\r\n/g, `
|
|
28452
|
+
`).replace(/\r/g, `
|
|
28453
|
+
`);
|
|
28454
|
+
const nonEmpty = normalized.split(`
|
|
28455
|
+
`).filter((linePart) => linePart.length > 0);
|
|
28456
|
+
if (nonEmpty.length <= 1) {
|
|
28457
|
+
return line;
|
|
28458
|
+
}
|
|
28459
|
+
const [first, ...rest] = nonEmpty;
|
|
28460
|
+
return `${first} [+ ${rest.length} pasted line${rest.length === 1 ? "" : "s"}]`;
|
|
28461
|
+
}
|
|
28124
28462
|
var ZERO_WIDTH = /^[\u0300-\u036F\u200B-\u200F\uFE00-\uFE0F\u2060-\u2064]$/u;
|
|
28125
28463
|
var WIDE_RANGES = [
|
|
28126
28464
|
[4352, 4447],
|
|
@@ -53148,6 +53486,7 @@ ${lines.join(`
|
|
|
53148
53486
|
|
|
53149
53487
|
// src/tui/tui-shell.ts
|
|
53150
53488
|
init_agent();
|
|
53489
|
+
init_single_turn();
|
|
53151
53490
|
init_slate_lifecycle();
|
|
53152
53491
|
init_slate();
|
|
53153
53492
|
|
|
@@ -53556,7 +53895,7 @@ import { spawnSync as spawnSync2 } from "child_process";
|
|
|
53556
53895
|
// package.json
|
|
53557
53896
|
var package_default = {
|
|
53558
53897
|
name: "@mrciphersmith/keryx",
|
|
53559
|
-
version: "0.2.
|
|
53898
|
+
version: "0.2.67",
|
|
53560
53899
|
description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
53561
53900
|
private: false,
|
|
53562
53901
|
publishConfig: {
|
|
@@ -53919,7 +54258,7 @@ function diffChunks(otui, text) {
|
|
|
53919
54258
|
}
|
|
53920
54259
|
return out;
|
|
53921
54260
|
}
|
|
53922
|
-
function
|
|
54261
|
+
function flatDimChunks(otui, text) {
|
|
53923
54262
|
const out = [];
|
|
53924
54263
|
for (const [index, line] of splitLines(text).entries()) {
|
|
53925
54264
|
if (index > 0) {
|
|
@@ -53930,6 +54269,34 @@ function codeChunks(otui, text) {
|
|
|
53930
54269
|
}
|
|
53931
54270
|
return out;
|
|
53932
54271
|
}
|
|
54272
|
+
function codeChunks(otui, text, lang) {
|
|
54273
|
+
const out = [];
|
|
54274
|
+
for (const [index, line] of splitLines(text).entries()) {
|
|
54275
|
+
if (index > 0) {
|
|
54276
|
+
out.push(...otui.stringToStyledText(`
|
|
54277
|
+
`).chunks);
|
|
54278
|
+
}
|
|
54279
|
+
for (const token of tokenizeCodeLine(line, lang)) {
|
|
54280
|
+
switch (token.kind) {
|
|
54281
|
+
case "comment":
|
|
54282
|
+
out.push(otui.dim(token.text));
|
|
54283
|
+
break;
|
|
54284
|
+
case "string":
|
|
54285
|
+
out.push(otui.green(token.text));
|
|
54286
|
+
break;
|
|
54287
|
+
case "number":
|
|
54288
|
+
out.push(otui.yellow(token.text));
|
|
54289
|
+
break;
|
|
54290
|
+
case "keyword":
|
|
54291
|
+
out.push(otui.cyan(token.text));
|
|
54292
|
+
break;
|
|
54293
|
+
default:
|
|
54294
|
+
out.push(...otui.stringToStyledText(token.text).chunks);
|
|
54295
|
+
}
|
|
54296
|
+
}
|
|
54297
|
+
}
|
|
54298
|
+
return out;
|
|
54299
|
+
}
|
|
53933
54300
|
function payloadChunks(otui, text, lang = "") {
|
|
53934
54301
|
const kind2 = payloadKind(lang, lineCountOf(text));
|
|
53935
54302
|
if (kind2 === "diff" || looksLikeUnifiedDiff(text)) {
|
|
@@ -53938,7 +54305,7 @@ function payloadChunks(otui, text, lang = "") {
|
|
|
53938
54305
|
if (kind2 === "markdown" || lang.length === 0) {
|
|
53939
54306
|
return markdownToChunks(otui, text);
|
|
53940
54307
|
}
|
|
53941
|
-
return codeChunks(otui, text);
|
|
54308
|
+
return codeChunks(otui, text, lang);
|
|
53942
54309
|
}
|
|
53943
54310
|
function createSegmentView(otui, renderer, parent, segment) {
|
|
53944
54311
|
viewSeq += 1;
|
|
@@ -53966,7 +54333,7 @@ function createSegmentView(otui, renderer, parent, segment) {
|
|
|
53966
54333
|
}
|
|
53967
54334
|
const tag = (lang, body2) => {
|
|
53968
54335
|
const n = lineCountOf(body2);
|
|
53969
|
-
return `${lang.length > 0 ? lang : "text"} \xB7 ${n} ${n === 1 ? "line" : "lines"}`;
|
|
54336
|
+
return `${lang.length > 0 ? lang : "text"} \xB7 ${n} ${n === 1 ? "line" : "lines"} \xB7 y copy`;
|
|
53970
54337
|
};
|
|
53971
54338
|
const frameWidth = (lang, body2) => Math.max(hugWidth(body2, FRAME_CHROME), hugWidth(tag(lang, body2), FRAME_CHROME));
|
|
53972
54339
|
const frame = new otui.BoxRenderable(renderer, {
|
|
@@ -54012,6 +54379,7 @@ function createSegmentView(otui, renderer, parent, segment) {
|
|
|
54012
54379
|
var messageSeq = 0;
|
|
54013
54380
|
function createAssistantMessageStream(otui, renderer, parent) {
|
|
54014
54381
|
let message2;
|
|
54382
|
+
let lastCode;
|
|
54015
54383
|
const start = () => {
|
|
54016
54384
|
messageSeq += 1;
|
|
54017
54385
|
const container = new otui.BoxRenderable(renderer, {
|
|
@@ -54040,6 +54408,11 @@ function createAssistantMessageStream(otui, renderer, parent) {
|
|
|
54040
54408
|
stale.destroy();
|
|
54041
54409
|
}
|
|
54042
54410
|
m.frozen = frozen;
|
|
54411
|
+
for (const segment of segments2) {
|
|
54412
|
+
if (segment.kind === "code") {
|
|
54413
|
+
lastCode = { lang: segment.lang, body: segment.body };
|
|
54414
|
+
}
|
|
54415
|
+
}
|
|
54043
54416
|
};
|
|
54044
54417
|
return {
|
|
54045
54418
|
push: (chunk) => {
|
|
@@ -54077,7 +54450,8 @@ function createAssistantMessageStream(otui, renderer, parent) {
|
|
|
54077
54450
|
parent.remove(message2.container);
|
|
54078
54451
|
} catch {}
|
|
54079
54452
|
message2 = undefined;
|
|
54080
|
-
}
|
|
54453
|
+
},
|
|
54454
|
+
lastCodeSegment: () => lastCode
|
|
54081
54455
|
};
|
|
54082
54456
|
}
|
|
54083
54457
|
function createBlockView(otui, renderer, parent, block, options = {}) {
|
|
@@ -54134,7 +54508,7 @@ function createBlockView(otui, renderer, parent, block, options = {}) {
|
|
|
54134
54508
|
return;
|
|
54135
54509
|
}
|
|
54136
54510
|
const shown = clipBody(text, options.maxLines ?? MAX_BODY_LINES);
|
|
54137
|
-
const content = new otui.StyledText(options.dim === true ?
|
|
54511
|
+
const content = new otui.StyledText(options.dim === true ? flatDimChunks(otui, shown) : payloadChunks(otui, shown));
|
|
54138
54512
|
painted = text;
|
|
54139
54513
|
if (bodyText !== undefined) {
|
|
54140
54514
|
bodyText.content = content;
|
|
@@ -54987,10 +55361,13 @@ async function readExternalUnboundCandidates(cwd) {
|
|
|
54987
55361
|
}
|
|
54988
55362
|
return groups;
|
|
54989
55363
|
}, []));
|
|
55364
|
+
const metaPath2 = path150.join(extDir, `${id}.json`);
|
|
55365
|
+
if (await pathExists(unboundDismissedReceiptPath(metaPath2)))
|
|
55366
|
+
continue;
|
|
54990
55367
|
candidates.push({
|
|
54991
55368
|
type: "unbound-candidate",
|
|
54992
55369
|
externalSessionId: id,
|
|
54993
|
-
evidencePath:
|
|
55370
|
+
evidencePath: metaPath2,
|
|
54994
55371
|
summary
|
|
54995
55372
|
});
|
|
54996
55373
|
}
|
|
@@ -55008,6 +55385,8 @@ async function readNewestUnboundCandidateForExternal(cwd, externalSessionId) {
|
|
|
55008
55385
|
entries.sort();
|
|
55009
55386
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
55010
55387
|
const evidencePath = path150.join(evidenceDir, entries[i]);
|
|
55388
|
+
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
55389
|
+
continue;
|
|
55011
55390
|
const result = readConfigFile(evidencePath);
|
|
55012
55391
|
if (!result.ok) {
|
|
55013
55392
|
continue;
|
|
@@ -55216,6 +55595,55 @@ async function readTerminalState(dir) {
|
|
|
55216
55595
|
return;
|
|
55217
55596
|
}
|
|
55218
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
|
+
}
|
|
55219
55647
|
async function readNewestUnboundCandidate(dir) {
|
|
55220
55648
|
const archiveDir = path150.join(dir, "slate-archive");
|
|
55221
55649
|
let entries;
|
|
@@ -55227,6 +55655,8 @@ async function readNewestUnboundCandidate(dir) {
|
|
|
55227
55655
|
entries.sort();
|
|
55228
55656
|
for (let i = entries.length - 1;i >= 0; i--) {
|
|
55229
55657
|
const evidencePath = path150.join(archiveDir, entries[i]);
|
|
55658
|
+
if (await pathExists(unboundDismissedReceiptPath(evidencePath)))
|
|
55659
|
+
continue;
|
|
55230
55660
|
const result = readConfigFile(evidencePath);
|
|
55231
55661
|
if (!result.ok) {
|
|
55232
55662
|
continue;
|
|
@@ -58998,6 +59428,53 @@ function composerMaxRowsForViewport(viewportRows) {
|
|
|
58998
59428
|
}
|
|
58999
59429
|
return Math.max(COMPOSER_MIN_ROWS, Math.floor(viewportRows / 3));
|
|
59000
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
|
+
}
|
|
59001
59478
|
function wrappedLineCount(text, width) {
|
|
59002
59479
|
const inner = Number.isFinite(width) ? Math.floor(width) : 0;
|
|
59003
59480
|
const paragraphs = text.length === 0 ? [""] : text.split(`
|
|
@@ -59035,6 +59512,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59035
59512
|
const filter = opts.filterCommands ?? ((query) => prefixFilter(opts.commands, query));
|
|
59036
59513
|
let uid = 0;
|
|
59037
59514
|
let alive = true;
|
|
59515
|
+
let appliedTheme = getTheme();
|
|
59038
59516
|
const rootRow = new otui.BoxRenderable(r, { id: "root-row", flexGrow: 1, flexDirection: "row" });
|
|
59039
59517
|
r.root.add(rootRow);
|
|
59040
59518
|
const main = new otui.BoxRenderable(r, { id: "main", flexGrow: 1, minWidth: 0, flexDirection: "column" });
|
|
@@ -59432,6 +59910,12 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59432
59910
|
input2.value = "";
|
|
59433
59911
|
hideMenu();
|
|
59434
59912
|
syncComposerHeight();
|
|
59913
|
+
if (line.length === 0 && suggestion !== null) {
|
|
59914
|
+
const next = suggestion;
|
|
59915
|
+
clearSuggestion();
|
|
59916
|
+
emitSubmit(next);
|
|
59917
|
+
return;
|
|
59918
|
+
}
|
|
59435
59919
|
emitSubmit(line);
|
|
59436
59920
|
};
|
|
59437
59921
|
const unsubscribeMenuKeys = onKeypress3(r, (key) => {
|
|
@@ -59470,7 +59954,51 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59470
59954
|
key.stopPropagation();
|
|
59471
59955
|
}
|
|
59472
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
|
+
});
|
|
59473
60000
|
const applyTheme = (theme = getTheme()) => {
|
|
60001
|
+
const remap = themeColorRemap(appliedTheme, theme);
|
|
59474
60002
|
try {
|
|
59475
60003
|
r.setBackgroundColor(theme.bg);
|
|
59476
60004
|
} catch {}
|
|
@@ -59488,6 +60016,15 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59488
60016
|
menu.selectedTextColor = theme.focus;
|
|
59489
60017
|
menu.descriptionColor = theme.muted;
|
|
59490
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;
|
|
59491
60028
|
};
|
|
59492
60029
|
const unsubTheme = onThemeChange((theme) => applyTheme(theme));
|
|
59493
60030
|
return {
|
|
@@ -59534,6 +60071,9 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59534
60071
|
setTitle: (text) => paintDim(headerLeft, text),
|
|
59535
60072
|
setStatus: (text) => paintDim(footerRight, text),
|
|
59536
60073
|
setHeaderMeta: (text) => paintDim(headerRight, text),
|
|
60074
|
+
showSuggestion,
|
|
60075
|
+
clearSuggestion,
|
|
60076
|
+
suggestionActive: () => suggestion !== null,
|
|
59537
60077
|
onSubmit: (handler) => {
|
|
59538
60078
|
submitHandlers.add(handler);
|
|
59539
60079
|
return () => {
|
|
@@ -59547,6 +60087,7 @@ async function createShellChrome(otui, renderer, opts) {
|
|
|
59547
60087
|
clearBusyTimer();
|
|
59548
60088
|
clearToastTimer();
|
|
59549
60089
|
unsubscribeMenuKeys();
|
|
60090
|
+
unsubscribeSuggestionKeys();
|
|
59550
60091
|
try {
|
|
59551
60092
|
textarea.off(otui.LayoutEvents.RESIZED, onComposerResized);
|
|
59552
60093
|
} catch {}
|
|
@@ -61740,7 +62281,8 @@ function createTuiAgentIo(otui, renderer, transcript) {
|
|
|
61740
62281
|
onSystem: (text) => append(text.includes("[error]") ? otui.t`${otui.red(text)}` : otui.t`${otui.dim(text)}`),
|
|
61741
62282
|
resetStream: () => {
|
|
61742
62283
|
messages.reset();
|
|
61743
|
-
}
|
|
62284
|
+
},
|
|
62285
|
+
lastCodeSegment: () => messages.lastCodeSegment()
|
|
61744
62286
|
};
|
|
61745
62287
|
}
|
|
61746
62288
|
function attachBlockIo(io, addBlock, chrome = {}) {
|
|
@@ -62926,6 +63468,23 @@ async function launchTuiAgentShell(opts) {
|
|
|
62926
63468
|
const newestBlock = (kind2) => nav.newest(kind2);
|
|
62927
63469
|
const toggleNewestBlock = (kind2) => nav.toggleNewest(kind2);
|
|
62928
63470
|
const copyBlock = (id) => nav.copy(id);
|
|
63471
|
+
const copyNewestOrLastCode = () => {
|
|
63472
|
+
const target = newestBlock();
|
|
63473
|
+
if (target !== undefined) {
|
|
63474
|
+
return copyBlock(target.id);
|
|
63475
|
+
}
|
|
63476
|
+
const code = io.lastCodeSegment();
|
|
63477
|
+
if (code === undefined) {
|
|
63478
|
+
return false;
|
|
63479
|
+
}
|
|
63480
|
+
try {
|
|
63481
|
+
r.copyToClipboardOSC52(code.body);
|
|
63482
|
+
chrome.showToast("Copied to clipboard");
|
|
63483
|
+
return true;
|
|
63484
|
+
} catch {
|
|
63485
|
+
return false;
|
|
63486
|
+
}
|
|
63487
|
+
};
|
|
62929
63488
|
const addBlock = (input3, options = {}) => {
|
|
62930
63489
|
const id = blockMount.add(input3, options);
|
|
62931
63490
|
nav.paint(id);
|
|
@@ -63917,17 +64476,6 @@ Staying in the current session.
|
|
|
63917
64476
|
} catch {}
|
|
63918
64477
|
}, 12000);
|
|
63919
64478
|
};
|
|
63920
|
-
const summarizeSubmittedLine = (line) => {
|
|
63921
|
-
const normalized = line.replace(/\r\n/g, `
|
|
63922
|
-
`).replace(/\r/g, `
|
|
63923
|
-
`);
|
|
63924
|
-
const count = normalized.split(`
|
|
63925
|
-
`).filter((linePart) => linePart.length > 0).length;
|
|
63926
|
-
if (count <= 1) {
|
|
63927
|
-
return line;
|
|
63928
|
-
}
|
|
63929
|
-
return `[pasted ${count} lines]`;
|
|
63930
|
-
};
|
|
63931
64479
|
const spawnSideWorker = (question, displayQuestion = question) => {
|
|
63932
64480
|
sideQueue.push({ question, displayQuestion });
|
|
63933
64481
|
if (sideQueue.length > 1 || sideWorkerRunning) {
|
|
@@ -64140,8 +64688,7 @@ Staying in the current session.
|
|
|
64140
64688
|
return;
|
|
64141
64689
|
}
|
|
64142
64690
|
case "copy": {
|
|
64143
|
-
|
|
64144
|
-
if (target === undefined || !copyBlock(target.id)) {
|
|
64691
|
+
if (!copyNewestOrLastCode()) {
|
|
64145
64692
|
io.onSystem?.(`Nothing to copy yet.
|
|
64146
64693
|
`);
|
|
64147
64694
|
}
|
|
@@ -64400,8 +64947,7 @@ Staying in the current session.
|
|
|
64400
64947
|
return;
|
|
64401
64948
|
}
|
|
64402
64949
|
if (command.name === "/copy") {
|
|
64403
|
-
|
|
64404
|
-
if (target === undefined || !copyBlock(target.id)) {
|
|
64950
|
+
if (!copyNewestOrLastCode()) {
|
|
64405
64951
|
io.onSystem?.(`Nothing to copy yet.
|
|
64406
64952
|
`);
|
|
64407
64953
|
}
|
|
@@ -64658,6 +65204,28 @@ ${formatThemeList(getThemeId())}`);
|
|
|
64658
65204
|
};
|
|
64659
65205
|
const controller = new AbortController;
|
|
64660
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
|
+
};
|
|
64661
65229
|
runAgentTurn(io, deps, history, line, {
|
|
64662
65230
|
signal: controller.signal,
|
|
64663
65231
|
...slateSession !== undefined ? { slateSession } : {}
|
|
@@ -64678,6 +65246,9 @@ ${formatThemeList(getThemeId())}`);
|
|
|
64678
65246
|
sbContext.content = otui.t`${otui.dim(`~${est.toLocaleString()} tokens (est)`)}`;
|
|
64679
65247
|
}
|
|
64680
65248
|
focusComposer();
|
|
65249
|
+
if (priorityMainQuestion === undefined && mainQueue.length === 0 && !turnFailed) {
|
|
65250
|
+
suggestNextStep();
|
|
65251
|
+
}
|
|
64681
65252
|
if (priorityMainQuestion !== undefined) {
|
|
64682
65253
|
const next = priorityMainQuestion;
|
|
64683
65254
|
priorityMainQuestion = undefined;
|
|
@@ -64884,17 +65455,6 @@ async function mountChatShell(otui, renderer, opts) {
|
|
|
64884
65455
|
chrome.setStatus(label());
|
|
64885
65456
|
sbModel.content = otui.t`${otui.dim(label())}`;
|
|
64886
65457
|
};
|
|
64887
|
-
const summarizeSubmittedLine = (line) => {
|
|
64888
|
-
const normalized = line.replace(/\r\n/g, `
|
|
64889
|
-
`).replace(/\r/g, `
|
|
64890
|
-
`);
|
|
64891
|
-
const count = normalized.split(`
|
|
64892
|
-
`).filter((linePart) => linePart.length > 0).length;
|
|
64893
|
-
if (count <= 1) {
|
|
64894
|
-
return line;
|
|
64895
|
-
}
|
|
64896
|
-
return `[pasted ${count} lines]`;
|
|
64897
|
-
};
|
|
64898
65458
|
const bridge = createChatBridge({
|
|
64899
65459
|
onAccepted: (line) => {
|
|
64900
65460
|
const displayLine = line.startsWith("/") ? line : summarizeSubmittedLine(line);
|
|
@@ -73004,6 +73564,17 @@ async function workspaceCommand(args2) {
|
|
|
73004
73564
|
console.log(JSON.stringify(normalizeProposalLifecycleResult(result), null, 2));
|
|
73005
73565
|
return;
|
|
73006
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
|
+
}
|
|
73007
73578
|
if (subcommand === "collaboration") {
|
|
73008
73579
|
rejectUnknownOptions(args2.slice(2), new Set);
|
|
73009
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
|
+
}
|