@ordewell/cli 0.4.15 → 0.4.17
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/main.js +78 -30
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -3035,12 +3035,39 @@ function findCommand(name) {
|
|
|
3035
3035
|
const key = name.replace(/^\//, "").toLowerCase();
|
|
3036
3036
|
return BY_NAME.get(key) ?? skillByName.get(key);
|
|
3037
3037
|
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
const
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3038
|
+
var TRAILING_PUNCT = /[,.!?;:]+$/;
|
|
3039
|
+
function slashTokens(text) {
|
|
3040
|
+
const tokens = [];
|
|
3041
|
+
const re = /(^|\s)\/(\S*)/g;
|
|
3042
|
+
let match;
|
|
3043
|
+
while (match = re.exec(text)) {
|
|
3044
|
+
const start = match.index + match[1].length;
|
|
3045
|
+
const raw = match[2];
|
|
3046
|
+
const punct = raw.match(TRAILING_PUNCT)?.[0] ?? "";
|
|
3047
|
+
const nameLen = raw.length - punct.length;
|
|
3048
|
+
tokens.push({
|
|
3049
|
+
start,
|
|
3050
|
+
end: start + 1 + raw.length,
|
|
3051
|
+
name: raw.slice(0, nameLen).toLowerCase(),
|
|
3052
|
+
nameEnd: start + 1 + nameLen
|
|
3053
|
+
});
|
|
3054
|
+
}
|
|
3055
|
+
return tokens;
|
|
3056
|
+
}
|
|
3057
|
+
function activeToken(text, cursor) {
|
|
3058
|
+
return slashTokens(text).find((t) => t.end === cursor) ?? null;
|
|
3059
|
+
}
|
|
3060
|
+
function skillMatchKind(name) {
|
|
3061
|
+
if (name.length === 0) return null;
|
|
3062
|
+
if (skillByName.has(name)) return "exact";
|
|
3063
|
+
for (const key of skillByName.keys()) {
|
|
3064
|
+
if (key.startsWith(name)) return "prefix";
|
|
3065
|
+
}
|
|
3066
|
+
return null;
|
|
3067
|
+
}
|
|
3068
|
+
function tokenCompletions(token) {
|
|
3069
|
+
const pool = token.start === 0 ? [...SLASH_COMMANDS, ...skillCommands] : skillCommands;
|
|
3070
|
+
return pool.filter((c) => c.name.startsWith(token.name));
|
|
3044
3071
|
}
|
|
3045
3072
|
|
|
3046
3073
|
// src/tui/markdown.ts
|
|
@@ -3768,17 +3795,32 @@ function renderStatus(state, cols) {
|
|
|
3768
3795
|
const tail = thinking.length > room ? `\u2026${thinking.slice(-(room - 1)).trimStart()}` : thinking;
|
|
3769
3796
|
return truncate(`${head}${style.grey(` \xB7 ${tail}`)}`, cols);
|
|
3770
3797
|
}
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
const
|
|
3774
|
-
|
|
3775
|
-
|
|
3798
|
+
function highlightSpans(text) {
|
|
3799
|
+
const spans = [];
|
|
3800
|
+
const expandedExact = /* @__PURE__ */ new Set();
|
|
3801
|
+
for (const token of slashTokens(text)) {
|
|
3802
|
+
const kind = skillMatchKind(token.name);
|
|
3803
|
+
if (kind === null) continue;
|
|
3804
|
+
if (kind === "exact") {
|
|
3805
|
+
if (expandedExact.has(token.name)) continue;
|
|
3806
|
+
expandedExact.add(token.name);
|
|
3807
|
+
}
|
|
3808
|
+
spans.push({ start: token.start, end: token.nameEnd });
|
|
3809
|
+
}
|
|
3810
|
+
return spans;
|
|
3776
3811
|
}
|
|
3777
|
-
function
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3812
|
+
function paintSpans(text, base, spans) {
|
|
3813
|
+
if (spans.length === 0) return text;
|
|
3814
|
+
let out = "";
|
|
3815
|
+
let cursor = 0;
|
|
3816
|
+
for (const span of spans) {
|
|
3817
|
+
const localStart = Math.max(cursor, Math.min(text.length, span.start - base));
|
|
3818
|
+
const localEnd = Math.max(0, Math.min(text.length, span.end - base));
|
|
3819
|
+
if (localEnd <= localStart) continue;
|
|
3820
|
+
out += text.slice(cursor, localStart) + style.cyan(text.slice(localStart, localEnd));
|
|
3821
|
+
cursor = localEnd;
|
|
3822
|
+
}
|
|
3823
|
+
return out + text.slice(cursor);
|
|
3782
3824
|
}
|
|
3783
3825
|
function renderInput(state, cols) {
|
|
3784
3826
|
const prompt = state.focus === "plan" ? style.grey("\u276F ") : style.cyan("\u276F ");
|
|
@@ -3786,28 +3828,31 @@ function renderInput(state, cols) {
|
|
|
3786
3828
|
const room = chatEditorRoom(cols, lines !== null);
|
|
3787
3829
|
const { text, cursor } = state.editor;
|
|
3788
3830
|
const continuation = " ".repeat(width(prompt));
|
|
3789
|
-
const
|
|
3831
|
+
const spans = highlightSpans(text);
|
|
3790
3832
|
if (!lines) {
|
|
3791
3833
|
const visible = text.replace(/\n/g, "\xB6").replace(/\t/g, " ");
|
|
3792
|
-
const painted =
|
|
3834
|
+
const painted = paintSpans(visible, 0, spans);
|
|
3793
3835
|
return [prompt + painted + suggest(state, room - width(visible))];
|
|
3794
3836
|
}
|
|
3795
3837
|
const { line: lineIndex, col } = cursorInLines(lines, cursor, text.length);
|
|
3796
|
-
|
|
3797
|
-
return rawLines.map((raw, i) => {
|
|
3838
|
+
return lines.map(({ line: raw, start: base }, i) => {
|
|
3798
3839
|
const prefix = i === 0 ? prompt : continuation;
|
|
3799
3840
|
const line = raw.replace(/\t/g, " ");
|
|
3800
3841
|
const isCursorLine = i === lineIndex;
|
|
3801
|
-
|
|
3802
|
-
const
|
|
3803
|
-
const
|
|
3804
|
-
const
|
|
3805
|
-
|
|
3842
|
+
if (!isCursorLine) return prefix + paintSpans(line, base, spans);
|
|
3843
|
+
const before = paintSpans(line.slice(0, col), base, spans);
|
|
3844
|
+
const caretChar = line.slice(col, col + 1) || " ";
|
|
3845
|
+
const after = paintSpans(line.slice(col + 1), base + col + 1, spans);
|
|
3846
|
+
const used = width(line.slice(0, col)) + width(caretChar);
|
|
3847
|
+
const hint = suggest(state, room - used);
|
|
3848
|
+
return prefix + before + style.inverse(caretChar) + hint + after;
|
|
3806
3849
|
});
|
|
3807
3850
|
}
|
|
3808
3851
|
function suggest(state, room) {
|
|
3809
3852
|
if (state.focus === "plan" || room <= 2) return "";
|
|
3810
|
-
const
|
|
3853
|
+
const token = activeToken(state.editor.text, state.editor.cursor);
|
|
3854
|
+
if (!token) return "";
|
|
3855
|
+
const matches = tokenCompletions(token);
|
|
3811
3856
|
if (matches.length === 0) return "";
|
|
3812
3857
|
const names = matches.map((c) => c.name).join(" ");
|
|
3813
3858
|
return style.grey(` ${truncate(names, Math.max(0, room - 2))}`);
|
|
@@ -4434,10 +4479,13 @@ function handleKey2(state, key) {
|
|
|
4434
4479
|
if (isMouseSelect(key)) return handleMouseSelect(state, key);
|
|
4435
4480
|
if (key.name === "wheelignored") return step(state);
|
|
4436
4481
|
if (key.name === "tab" && state.focus === "chat") {
|
|
4437
|
-
const
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4482
|
+
const token = activeToken(state.editor.text, state.editor.cursor);
|
|
4483
|
+
const matches = token ? tokenCompletions(token) : [];
|
|
4484
|
+
if (token && matches.length > 0) {
|
|
4485
|
+
const { text: full } = state.editor;
|
|
4486
|
+
const completed = `/${matches[0].name} `;
|
|
4487
|
+
const text = full.slice(0, token.start) + completed + full.slice(token.end);
|
|
4488
|
+
return step({ ...state, editor: { ...state.editor, text, cursor: token.start + completed.length } });
|
|
4441
4489
|
}
|
|
4442
4490
|
}
|
|
4443
4491
|
if (key.name === "tab") return step({ ...state, focus: state.focus === "chat" ? "plan" : "chat" });
|
package/package.json
CHANGED