zelari-code 1.8.0 → 1.8.2
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/app.js +37 -22
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/components/LiveRegion.js +9 -1
- package/dist/cli/components/LiveRegion.js.map +1 -1
- package/dist/cli/components/Sidebar.js +38 -7
- package/dist/cli/components/Sidebar.js.map +1 -1
- package/dist/cli/components/brandArt.js +62 -0
- package/dist/cli/components/brandArt.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +44 -25
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useTerminalSize.js +17 -10
- package/dist/cli/hooks/useTerminalSize.js.map +1 -1
- package/dist/cli/main.bundled.js +358 -115
- package/dist/cli/main.bundled.js.map +4 -4
- package/package.json +2 -2
package/dist/cli/main.bundled.js
CHANGED
|
@@ -16880,6 +16880,25 @@ var init_walk = __esm({
|
|
|
16880
16880
|
// packages/core/dist/core/tools/builtin/search.js
|
|
16881
16881
|
import { promises as fs6 } from "node:fs";
|
|
16882
16882
|
import path7 from "node:path";
|
|
16883
|
+
function coerceStringList(value, fallback) {
|
|
16884
|
+
if (value === void 0 || value === null)
|
|
16885
|
+
return fallback;
|
|
16886
|
+
if (Array.isArray(value)) {
|
|
16887
|
+
const cleaned = value.filter((x) => typeof x === "string" && x.trim().length > 0);
|
|
16888
|
+
return cleaned.length > 0 ? cleaned : fallback;
|
|
16889
|
+
}
|
|
16890
|
+
if (typeof value === "string") {
|
|
16891
|
+
const s = value.trim();
|
|
16892
|
+
if (!s)
|
|
16893
|
+
return fallback;
|
|
16894
|
+
if (s.includes(",") && !s.includes("{")) {
|
|
16895
|
+
const parts = s.split(",").map((x) => x.trim()).filter(Boolean);
|
|
16896
|
+
return parts.length > 0 ? parts : fallback;
|
|
16897
|
+
}
|
|
16898
|
+
return [s];
|
|
16899
|
+
}
|
|
16900
|
+
return fallback;
|
|
16901
|
+
}
|
|
16883
16902
|
async function searchFile(absPath, relPath, regex, contextLines, remainingSlots) {
|
|
16884
16903
|
let buf;
|
|
16885
16904
|
try {
|
|
@@ -16923,13 +16942,14 @@ async function isDirectory(p3) {
|
|
|
16923
16942
|
return false;
|
|
16924
16943
|
}
|
|
16925
16944
|
}
|
|
16926
|
-
var GrepContentArgsSchema, grepContentTool;
|
|
16945
|
+
var stringOrStringArray, GrepContentArgsSchema, grepContentTool;
|
|
16927
16946
|
var init_search = __esm({
|
|
16928
16947
|
"packages/core/dist/core/tools/builtin/search.js"() {
|
|
16929
16948
|
"use strict";
|
|
16930
16949
|
init_zod();
|
|
16931
16950
|
init_toolTypes();
|
|
16932
16951
|
init_walk();
|
|
16952
|
+
stringOrStringArray = external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]);
|
|
16933
16953
|
GrepContentArgsSchema = external_exports.object({
|
|
16934
16954
|
/** File OR directory to search (relative to cwd or absolute). */
|
|
16935
16955
|
path: external_exports.string().min(1),
|
|
@@ -16940,21 +16960,22 @@ var init_search = __esm({
|
|
|
16940
16960
|
/** Max matches returned (total matches still counted). */
|
|
16941
16961
|
maxMatches: external_exports.number().int().positive().max(1e3).default(50),
|
|
16942
16962
|
/**
|
|
16943
|
-
* Glob
|
|
16963
|
+
* Glob pattern(s) to INCLUDE when path is a directory.
|
|
16964
|
+
* Accepts a string OR string[] (models often emit a bare string).
|
|
16944
16965
|
* Default ['*'] = all files. Ignored when path is a file.
|
|
16945
16966
|
*/
|
|
16946
|
-
include:
|
|
16967
|
+
include: stringOrStringArray.optional().default(["*"]),
|
|
16947
16968
|
/**
|
|
16948
|
-
* Glob
|
|
16949
|
-
*
|
|
16969
|
+
* Glob pattern(s) to EXCLUDE when path is a directory.
|
|
16970
|
+
* Accepts a string OR string[]. Defaults to common noise dirs.
|
|
16950
16971
|
*/
|
|
16951
|
-
exclude:
|
|
16972
|
+
exclude: stringOrStringArray.optional().default(DEFAULT_EXCLUDES),
|
|
16952
16973
|
/** Max recursion depth when path is a directory (default 8). */
|
|
16953
16974
|
maxDepth: external_exports.number().int().positive().max(15).default(8)
|
|
16954
16975
|
});
|
|
16955
16976
|
grepContentTool = {
|
|
16956
16977
|
name: "grep_content",
|
|
16957
|
-
description:
|
|
16978
|
+
description: 'Regex search for content in a file OR recursively in a directory. When path is a directory, include/exclude globs filter which files are searched (default: all files, excluding node_modules/dist/.git/etc.). include/exclude accept a single glob string (e.g. "*.ts") OR an array of globs. Returns matches with line numbers and surrounding context.',
|
|
16958
16979
|
permissions: ["read"],
|
|
16959
16980
|
timeoutMs: 3e4,
|
|
16960
16981
|
inputSchema: GrepContentArgsSchema,
|
|
@@ -16962,6 +16983,8 @@ var init_search = __esm({
|
|
|
16962
16983
|
try {
|
|
16963
16984
|
const absRoot = path7.isAbsolute(args.path) ? args.path : path7.join(ctx.cwd, args.path);
|
|
16964
16985
|
const regex = new RegExp(args.pattern, "gm");
|
|
16986
|
+
const include = coerceStringList(args.include, ["*"]);
|
|
16987
|
+
const exclude = coerceStringList(args.exclude, DEFAULT_EXCLUDES);
|
|
16965
16988
|
if (!await isDirectory(absRoot)) {
|
|
16966
16989
|
const single = await searchFile(absRoot, args.path, regex, args.contextLines, args.maxMatches);
|
|
16967
16990
|
return typedOk({
|
|
@@ -16973,8 +16996,8 @@ var init_search = __esm({
|
|
|
16973
16996
|
});
|
|
16974
16997
|
}
|
|
16975
16998
|
const allEntries = [];
|
|
16976
|
-
await walk(absRoot, "", 0, args.maxDepth,
|
|
16977
|
-
const matchedFiles = filterByInclude(allEntries,
|
|
16999
|
+
await walk(absRoot, "", 0, args.maxDepth, exclude, allEntries, ctx.signal);
|
|
17000
|
+
const matchedFiles = filterByInclude(allEntries, include);
|
|
16978
17001
|
const allMatches = [];
|
|
16979
17002
|
let totalMatches = 0;
|
|
16980
17003
|
let truncated = false;
|
|
@@ -18271,20 +18294,24 @@ The council shares a context window across turns. Follow these rules:
|
|
|
18271
18294
|
type: "tool-usage-guidelines",
|
|
18272
18295
|
title: "Tool Usage",
|
|
18273
18296
|
priority: 60,
|
|
18274
|
-
content:
|
|
18275
|
-
|
|
18276
|
-
|
|
18277
|
-
-
|
|
18278
|
-
-
|
|
18279
|
-
-
|
|
18280
|
-
-
|
|
18281
|
-
|
|
18282
|
-
|
|
18283
|
-
|
|
18284
|
-
|
|
18285
|
-
|
|
18286
|
-
|
|
18287
|
-
|
|
18297
|
+
content: [
|
|
18298
|
+
"# Tool Usage Guidelines",
|
|
18299
|
+
"",
|
|
18300
|
+
"- Use tools to create or modify durable state (tasks, ideas, documents, mind maps, milestones).",
|
|
18301
|
+
"- Tool calls go in a dedicated block at the end of your response using the exact format documented below.",
|
|
18302
|
+
"- Only use tools listed in the AVAILABLE TOOLS section. Never invent tool names.",
|
|
18303
|
+
"- Pass arguments as JSON. Required parameters must be present.",
|
|
18304
|
+
"- One tool call per entry. Multiple entries are allowed in a single block.",
|
|
18305
|
+
"",
|
|
18306
|
+
"Format (ONE JSON array only - never multiple arrays stacked):",
|
|
18307
|
+
"```",
|
|
18308
|
+
"---TOOLS---",
|
|
18309
|
+
'[{"name":"<toolName>","args":{"key":"value"}},{"name":"<toolName2>","args":{"key":"value"}}]',
|
|
18310
|
+
"---END---",
|
|
18311
|
+
"```",
|
|
18312
|
+
"Rules: valid JSON; escape newlines inside strings as \\n; do NOT stack separate",
|
|
18313
|
+
"JSON arrays (one tool per array) - put every call in the SAME outer array."
|
|
18314
|
+
].join("\n")
|
|
18288
18315
|
},
|
|
18289
18316
|
{
|
|
18290
18317
|
type: "custom",
|
|
@@ -18946,16 +18973,53 @@ function parseTextToolCalls(text) {
|
|
|
18946
18973
|
const m = /---TOOLS---\s*([\s\S]*?)---END---/.exec(text);
|
|
18947
18974
|
if (!m || !m[1])
|
|
18948
18975
|
return [];
|
|
18976
|
+
let body = m[1].trim();
|
|
18977
|
+
body = body.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
|
|
18978
|
+
const candidates = [body];
|
|
18979
|
+
if (/\]\s*\[/.test(body)) {
|
|
18980
|
+
candidates.push(body.replace(/\]\s*\[/g, ","));
|
|
18981
|
+
}
|
|
18982
|
+
if (body.includes('\\"')) {
|
|
18983
|
+
candidates.push(body.replace(/\\"/g, '"'));
|
|
18984
|
+
if (/\]\s*\[/.test(body)) {
|
|
18985
|
+
candidates.push(body.replace(/\\"/g, '"').replace(/\]\s*\[/g, ","));
|
|
18986
|
+
}
|
|
18987
|
+
}
|
|
18988
|
+
for (const cand of candidates) {
|
|
18989
|
+
const items = tryParseToolArray(cand);
|
|
18990
|
+
if (items.length > 0)
|
|
18991
|
+
return items;
|
|
18992
|
+
}
|
|
18993
|
+
const arrays = extractJsonArrays(body);
|
|
18994
|
+
if (arrays.length > 1) {
|
|
18995
|
+
const merged = [];
|
|
18996
|
+
for (const a of arrays) {
|
|
18997
|
+
merged.push(...tryParseToolArray(a));
|
|
18998
|
+
}
|
|
18999
|
+
if (merged.length > 0)
|
|
19000
|
+
return merged;
|
|
19001
|
+
}
|
|
19002
|
+
return extractToolObjects(body);
|
|
19003
|
+
}
|
|
19004
|
+
function tryParseToolArray(raw) {
|
|
18949
19005
|
let parsed;
|
|
18950
19006
|
try {
|
|
18951
|
-
parsed = JSON.parse(
|
|
19007
|
+
parsed = JSON.parse(raw.trim());
|
|
18952
19008
|
} catch {
|
|
18953
19009
|
return [];
|
|
18954
19010
|
}
|
|
18955
|
-
if (!Array.isArray(parsed))
|
|
18956
|
-
|
|
19011
|
+
if (!Array.isArray(parsed)) {
|
|
19012
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19013
|
+
parsed = [parsed];
|
|
19014
|
+
} else {
|
|
19015
|
+
return [];
|
|
19016
|
+
}
|
|
19017
|
+
}
|
|
19018
|
+
return normalizeToolItems(parsed);
|
|
19019
|
+
}
|
|
19020
|
+
function normalizeToolItems(items) {
|
|
18957
19021
|
const out = [];
|
|
18958
|
-
for (const item of
|
|
19022
|
+
for (const item of items) {
|
|
18959
19023
|
if (item && typeof item === "object" && typeof item.name === "string") {
|
|
18960
19024
|
const rawArgs = item.args;
|
|
18961
19025
|
out.push({
|
|
@@ -18966,6 +19030,70 @@ function parseTextToolCalls(text) {
|
|
|
18966
19030
|
}
|
|
18967
19031
|
return out;
|
|
18968
19032
|
}
|
|
19033
|
+
function extractJsonArrays(text) {
|
|
19034
|
+
const out = [];
|
|
19035
|
+
let i = 0;
|
|
19036
|
+
while (i < text.length) {
|
|
19037
|
+
if (text[i] !== "[") {
|
|
19038
|
+
i++;
|
|
19039
|
+
continue;
|
|
19040
|
+
}
|
|
19041
|
+
let depth = 0;
|
|
19042
|
+
let inStr = false;
|
|
19043
|
+
let esc2 = false;
|
|
19044
|
+
let end = -1;
|
|
19045
|
+
for (let j = i; j < text.length; j++) {
|
|
19046
|
+
const c = text[j];
|
|
19047
|
+
if (inStr) {
|
|
19048
|
+
if (esc2)
|
|
19049
|
+
esc2 = false;
|
|
19050
|
+
else if (c === "\\")
|
|
19051
|
+
esc2 = true;
|
|
19052
|
+
else if (c === '"')
|
|
19053
|
+
inStr = false;
|
|
19054
|
+
continue;
|
|
19055
|
+
}
|
|
19056
|
+
if (c === '"') {
|
|
19057
|
+
inStr = true;
|
|
19058
|
+
continue;
|
|
19059
|
+
}
|
|
19060
|
+
if (c === "[")
|
|
19061
|
+
depth++;
|
|
19062
|
+
else if (c === "]") {
|
|
19063
|
+
depth--;
|
|
19064
|
+
if (depth === 0) {
|
|
19065
|
+
end = j;
|
|
19066
|
+
break;
|
|
19067
|
+
}
|
|
19068
|
+
}
|
|
19069
|
+
}
|
|
19070
|
+
if (end > i) {
|
|
19071
|
+
out.push(text.slice(i, end + 1));
|
|
19072
|
+
i = end + 1;
|
|
19073
|
+
} else {
|
|
19074
|
+
i++;
|
|
19075
|
+
}
|
|
19076
|
+
}
|
|
19077
|
+
return out;
|
|
19078
|
+
}
|
|
19079
|
+
function extractToolObjects(text) {
|
|
19080
|
+
const out = [];
|
|
19081
|
+
const re = /\{\s*"name"\s*:\s*"([^"]+)"\s*,\s*"args"\s*:\s*(\{[\s\S]*?\})\s*\}/g;
|
|
19082
|
+
let match;
|
|
19083
|
+
while ((match = re.exec(text)) !== null) {
|
|
19084
|
+
const name = match[1];
|
|
19085
|
+
let args = {};
|
|
19086
|
+
try {
|
|
19087
|
+
const parsed = JSON.parse(match[2]);
|
|
19088
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
19089
|
+
args = parsed;
|
|
19090
|
+
}
|
|
19091
|
+
} catch {
|
|
19092
|
+
}
|
|
19093
|
+
out.push({ name, args });
|
|
19094
|
+
}
|
|
19095
|
+
return out;
|
|
19096
|
+
}
|
|
18969
19097
|
var AgentHarness;
|
|
18970
19098
|
var init_AgentHarness = __esm({
|
|
18971
19099
|
"packages/core/dist/core/AgentHarness.js"() {
|
|
@@ -23934,11 +24062,19 @@ function parseClarificationRequest(text) {
|
|
|
23934
24062
|
}
|
|
23935
24063
|
}
|
|
23936
24064
|
function parseThinking(text) {
|
|
23937
|
-
const
|
|
23938
|
-
|
|
24065
|
+
const complete = text.match(/<think(?:ing)?>([\s\S]*?)<\/think(?:ing)?>/i);
|
|
24066
|
+
if (complete)
|
|
24067
|
+
return complete[1].trim();
|
|
24068
|
+
const open = text.match(/<think(?:ing)?>([\s\S]*)$/i);
|
|
24069
|
+
return open ? open[1].trim() : "";
|
|
23939
24070
|
}
|
|
23940
|
-
function cleanAgentContent(text) {
|
|
23941
|
-
|
|
24071
|
+
function cleanAgentContent(text, opts = {}) {
|
|
24072
|
+
const stripQuestion = opts.stripQuestion !== false;
|
|
24073
|
+
let out = text.replace(/<think(?:ing)?>[\s\S]*?<\/think(?:ing)?>/gi, "").replace(/<think(?:ing)?>[\s\S]*$/gi, "").replace(/<\/think(?:ing)?>/gi, "").replace(/<minimax:tool_call>[\s\S]*?<\/minimax:tool_call>/g, "");
|
|
24074
|
+
if (stripQuestion) {
|
|
24075
|
+
out = out.replace(/---QUESTION---[\s\S]*?---END---/g, "");
|
|
24076
|
+
}
|
|
24077
|
+
return out.replace(/\n{3,}/g, "\n\n").trim();
|
|
23942
24078
|
}
|
|
23943
24079
|
function restrictImplementationWrites(toolNames, opts) {
|
|
23944
24080
|
if (opts.runMode !== "implementation" || opts.isImplementer)
|
|
@@ -30520,7 +30656,7 @@ import React14 from "react";
|
|
|
30520
30656
|
import { render } from "ink";
|
|
30521
30657
|
|
|
30522
30658
|
// src/cli/app.tsx
|
|
30523
|
-
import React9, { useState as useState8, useMemo, useCallback as useCallback5, useEffect as useEffect7 } from "react";
|
|
30659
|
+
import React9, { useState as useState8, useMemo, useCallback as useCallback5, useEffect as useEffect7, useRef as useRef6 } from "react";
|
|
30524
30660
|
import { Box as Box8, Static, useInput as useInput2, useStdin as useStdin2 } from "ink";
|
|
30525
30661
|
|
|
30526
30662
|
// src/cli/components/InputBar.tsx
|
|
@@ -30918,9 +31054,12 @@ function WorkingIndicator({
|
|
|
30918
31054
|
|
|
30919
31055
|
// src/cli/components/LiveRegion.tsx
|
|
30920
31056
|
var LIVE_STREAM_TAIL_LINES = 10;
|
|
31057
|
+
var MAX_LIVE_TOOLS = 4;
|
|
30921
31058
|
function LiveRegion({ live, busy, elapsedMs = null }) {
|
|
30922
31059
|
const { streaming, runningTools } = live;
|
|
30923
31060
|
if (!streaming && runningTools.length === 0 && !busy) return null;
|
|
31061
|
+
const visibleTools = runningTools.slice(0, MAX_LIVE_TOOLS);
|
|
31062
|
+
const hiddenTools = runningTools.length - visibleTools.length;
|
|
30924
31063
|
return /* @__PURE__ */ React5.createElement(Box4, { flexDirection: "column", paddingX: 1 }, streaming && streaming.role === "assistant" && /* @__PURE__ */ React5.createElement(
|
|
30925
31064
|
StreamingTail,
|
|
30926
31065
|
{
|
|
@@ -30930,7 +31069,7 @@ function LiveRegion({ live, busy, elapsedMs = null }) {
|
|
|
30930
31069
|
memberName: streaming.memberName,
|
|
30931
31070
|
memberId: streaming.memberId
|
|
30932
31071
|
}
|
|
30933
|
-
),
|
|
31072
|
+
), visibleTools.map((t) => /* @__PURE__ */ React5.createElement(Box4, { key: t.id, flexDirection: "column" }, renderMessage(t, true))), hiddenTools > 0 ? /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2026 +", hiddenTools, " more tools") : null, busy && runningTools.length === 0 && !streaming && /* @__PURE__ */ React5.createElement(WorkingIndicator, { elapsedMs }));
|
|
30934
31073
|
}
|
|
30935
31074
|
function StreamingTail(m) {
|
|
30936
31075
|
const lines = m.content.split("\n");
|
|
@@ -31093,11 +31232,25 @@ import React8 from "react";
|
|
|
31093
31232
|
import { Box as Box7, Text as Text8 } from "ink";
|
|
31094
31233
|
var SIDEBAR_WIDTH = 28;
|
|
31095
31234
|
var SIDEBAR_MIN_COLUMNS = 96;
|
|
31096
|
-
var
|
|
31097
|
-
var
|
|
31098
|
-
var
|
|
31235
|
+
var SIDEBAR_HIDE_COLUMNS = 88;
|
|
31236
|
+
var SIDEBAR_MIN_ROWS = 16;
|
|
31237
|
+
var SIDEBAR_HIDE_ROWS = 14;
|
|
31238
|
+
var MAX_FILES_SHORT = 4;
|
|
31239
|
+
var MAX_FILES_TALL = 8;
|
|
31240
|
+
var SIDEBAR_CHROME_LINES = 4;
|
|
31099
31241
|
function shouldShowSidebar(columns, rows) {
|
|
31100
|
-
return columns >= SIDEBAR_MIN_COLUMNS && rows >=
|
|
31242
|
+
return columns >= SIDEBAR_MIN_COLUMNS && rows >= SIDEBAR_MIN_ROWS;
|
|
31243
|
+
}
|
|
31244
|
+
function sidebarVisibility(columns, rows, currentlyVisible) {
|
|
31245
|
+
if (currentlyVisible) {
|
|
31246
|
+
return columns >= SIDEBAR_HIDE_COLUMNS && rows >= SIDEBAR_HIDE_ROWS;
|
|
31247
|
+
}
|
|
31248
|
+
return shouldShowSidebar(columns, rows);
|
|
31249
|
+
}
|
|
31250
|
+
function maxSidebarFiles(rows) {
|
|
31251
|
+
const budget = Math.max(2, rows - 14 - SIDEBAR_CHROME_LINES);
|
|
31252
|
+
const cap = rows >= 28 ? MAX_FILES_TALL : MAX_FILES_SHORT;
|
|
31253
|
+
return Math.min(cap, budget);
|
|
31101
31254
|
}
|
|
31102
31255
|
function truncatePath(p3, max) {
|
|
31103
31256
|
if (p3.length <= max) return p3;
|
|
@@ -31105,7 +31258,7 @@ function truncatePath(p3, max) {
|
|
|
31105
31258
|
}
|
|
31106
31259
|
function Sidebar({ version: version2, changes, rows }) {
|
|
31107
31260
|
void version2;
|
|
31108
|
-
const maxFiles = rows
|
|
31261
|
+
const maxFiles = maxSidebarFiles(rows);
|
|
31109
31262
|
const visible = changes.files.slice(0, maxFiles);
|
|
31110
31263
|
const hidden = changes.files.length - visible.length;
|
|
31111
31264
|
const innerWidth = SIDEBAR_WIDTH - 4;
|
|
@@ -31117,7 +31270,9 @@ function Sidebar({ version: version2, changes, rows }) {
|
|
|
31117
31270
|
borderStyle: "single",
|
|
31118
31271
|
borderColor: "gray",
|
|
31119
31272
|
paddingX: 1,
|
|
31120
|
-
flexShrink: 0
|
|
31273
|
+
flexShrink: 0,
|
|
31274
|
+
height: Math.min(rows - 8, SIDEBAR_CHROME_LINES + maxFiles + 2),
|
|
31275
|
+
overflow: "hidden"
|
|
31121
31276
|
},
|
|
31122
31277
|
/* @__PURE__ */ React8.createElement(Box7, { justifyContent: "center" }, /* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, changes.branch ? truncatePath(changes.branch, 18) : "git")),
|
|
31123
31278
|
/* @__PURE__ */ React8.createElement(Text8, { dimColor: true }, "\u2500".repeat(innerWidth)),
|
|
@@ -31129,6 +31284,53 @@ function FileRow({ file: file2, pathWidth }) {
|
|
|
31129
31284
|
return /* @__PURE__ */ React8.createElement(Box7, null, /* @__PURE__ */ React8.createElement(Text8, { wrap: "truncate" }, /* @__PURE__ */ React8.createElement(Text8, { color: file2.untracked ? "yellow" : "white" }, name), file2.untracked ? /* @__PURE__ */ React8.createElement(Text8, { color: "yellow" }, " new") : /* @__PURE__ */ React8.createElement(React8.Fragment, null, /* @__PURE__ */ React8.createElement(Text8, { color: "green" }, " +", file2.added ?? "\xB7"), /* @__PURE__ */ React8.createElement(Text8, { color: "red" }, " -", file2.removed ?? "\xB7"))));
|
|
31130
31285
|
}
|
|
31131
31286
|
|
|
31287
|
+
// src/cli/components/brandArt.ts
|
|
31288
|
+
var BRAND_LOGO_ASCII = [
|
|
31289
|
+
" -#%=",
|
|
31290
|
+
" +%%%%#.",
|
|
31291
|
+
" :#%%%%%%%-",
|
|
31292
|
+
":%%@@@@@@@@=",
|
|
31293
|
+
"-%@@@@@@@@@@@+",
|
|
31294
|
+
":%@@@@@@%@@@@@@=",
|
|
31295
|
+
"-%%@@@@@.+%@@%@+",
|
|
31296
|
+
" -@@@@@@:%++%@=",
|
|
31297
|
+
"=*%@@@@@@:@@%=*@#+.",
|
|
31298
|
+
"%%%%%@@@@:+++-*%@@*",
|
|
31299
|
+
".%%%%%@@@@@+%+=:%@@@@:",
|
|
31300
|
+
"*@@@@@@@@@@@@@%@@@@@@*"
|
|
31301
|
+
].join("\n");
|
|
31302
|
+
var BRAND_LOGO_COMPACT = [
|
|
31303
|
+
" -#%=",
|
|
31304
|
+
" +%%%%#.",
|
|
31305
|
+
":%%@@@@=",
|
|
31306
|
+
"*@@@@@@*"
|
|
31307
|
+
].join("\n");
|
|
31308
|
+
function formatBannerWithLogoRight(opts) {
|
|
31309
|
+
const logoSrc = opts.compact ? BRAND_LOGO_COMPACT : BRAND_LOGO_ASCII;
|
|
31310
|
+
const logoLines = logoSrc.split("\n");
|
|
31311
|
+
const logoWidth = Math.max(...logoLines.map((l) => l.length));
|
|
31312
|
+
const cols = Math.max(logoWidth + 20, Math.min(opts.columns, 120));
|
|
31313
|
+
const left = [...opts.leftLines];
|
|
31314
|
+
const wordmark = `ZELARI CODE v${opts.version}`;
|
|
31315
|
+
const rightExtra = [wordmark];
|
|
31316
|
+
const rightBlock = [...logoLines, ...rightExtra];
|
|
31317
|
+
const rows = Math.max(left.length, rightBlock.length);
|
|
31318
|
+
const out = [];
|
|
31319
|
+
for (let i = 0; i < rows; i++) {
|
|
31320
|
+
const L = left[i] ?? "";
|
|
31321
|
+
const R = rightBlock[i] ?? "";
|
|
31322
|
+
if (!R) {
|
|
31323
|
+
out.push(L);
|
|
31324
|
+
continue;
|
|
31325
|
+
}
|
|
31326
|
+
const maxLeft = Math.max(0, cols - R.length - 2);
|
|
31327
|
+
const leftClipped = L.length > maxLeft ? L.slice(0, Math.max(0, maxLeft - 1)) + "\u2026" : L;
|
|
31328
|
+
const pad = Math.max(2, cols - leftClipped.length - R.length);
|
|
31329
|
+
out.push(leftClipped + " ".repeat(pad) + R);
|
|
31330
|
+
}
|
|
31331
|
+
return out.join("\n");
|
|
31332
|
+
}
|
|
31333
|
+
|
|
31132
31334
|
// src/cli/modelDiscovery.ts
|
|
31133
31335
|
import { promises as fs3, existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
31134
31336
|
import { homedir } from "node:os";
|
|
@@ -34478,15 +34680,16 @@ function useChatTurn(params) {
|
|
|
34478
34680
|
if (event.type === "message_delta") {
|
|
34479
34681
|
assistantContent += event.delta;
|
|
34480
34682
|
streamContent += event.delta;
|
|
34683
|
+
const displayContent = cleanAgentContent(streamContent);
|
|
34481
34684
|
if (useLiveModel) {
|
|
34482
|
-
setStreaming(commitStreaming,
|
|
34685
|
+
setStreaming(commitStreaming, displayContent, Date.now(), {
|
|
34483
34686
|
...event.memberId ? { memberId: event.memberId } : {},
|
|
34484
34687
|
...event.memberName ? { memberName: event.memberName } : {}
|
|
34485
34688
|
});
|
|
34486
34689
|
} else {
|
|
34487
34690
|
appendOrExtendStreamingAssistant(
|
|
34488
34691
|
commitStreaming,
|
|
34489
|
-
|
|
34692
|
+
displayContent,
|
|
34490
34693
|
Date.now(),
|
|
34491
34694
|
{
|
|
34492
34695
|
...event.memberId ? { memberId: event.memberId } : {},
|
|
@@ -34552,32 +34755,41 @@ function useChatTurn(params) {
|
|
|
34552
34755
|
const all = h.getMessages();
|
|
34553
34756
|
const seedLen = 1 + historySeedLen + 1;
|
|
34554
34757
|
if (all.length > seedLen) {
|
|
34555
|
-
appendMessages(
|
|
34758
|
+
appendMessages(
|
|
34759
|
+
all.slice(seedLen).map(
|
|
34760
|
+
(m) => m.role === "assistant" && m.content ? {
|
|
34761
|
+
...m,
|
|
34762
|
+
content: cleanAgentContent(m.content, {
|
|
34763
|
+
stripQuestion: false
|
|
34764
|
+
})
|
|
34765
|
+
} : m
|
|
34766
|
+
)
|
|
34767
|
+
);
|
|
34556
34768
|
}
|
|
34557
34769
|
}
|
|
34558
34770
|
} catch {
|
|
34559
34771
|
}
|
|
34560
34772
|
if (turnSucceeded && assistantContent) {
|
|
34561
34773
|
try {
|
|
34774
|
+
const needsScrub = assistantContent.includes("<think") || assistantContent.includes("<thinking") || assistantContent.includes("---QUESTION---");
|
|
34775
|
+
if (needsScrub) {
|
|
34776
|
+
setMessages(
|
|
34777
|
+
(prev2) => prev2.map((m) => {
|
|
34778
|
+
if (m.role !== "assistant") return m;
|
|
34779
|
+
if (!m.content.includes("<think") && !m.content.includes("<thinking") && !m.content.includes("---QUESTION---")) {
|
|
34780
|
+
return m;
|
|
34781
|
+
}
|
|
34782
|
+
const cleaned = cleanAgentContent(m.content);
|
|
34783
|
+
return cleaned === m.content ? m : { ...m, content: cleaned };
|
|
34784
|
+
})
|
|
34785
|
+
);
|
|
34786
|
+
}
|
|
34562
34787
|
const clar = parseClarificationRequest(assistantContent);
|
|
34563
34788
|
if (clar && clar.choices && clar.choices.length >= 2) {
|
|
34564
34789
|
setLastClarification({
|
|
34565
34790
|
question: clar.question,
|
|
34566
34791
|
choices: clar.choices
|
|
34567
34792
|
});
|
|
34568
|
-
const cleaned = cleanAgentContent(assistantContent);
|
|
34569
|
-
if (cleaned !== assistantContent) {
|
|
34570
|
-
setMessages((prev2) => {
|
|
34571
|
-
const next = [...prev2];
|
|
34572
|
-
for (let i = next.length - 1; i >= 0; i--) {
|
|
34573
|
-
if (next[i].role === "assistant") {
|
|
34574
|
-
next[i] = { ...next[i], content: cleaned };
|
|
34575
|
-
break;
|
|
34576
|
-
}
|
|
34577
|
-
}
|
|
34578
|
-
return next;
|
|
34579
|
-
});
|
|
34580
|
-
}
|
|
34581
34793
|
if (setPicker) {
|
|
34582
34794
|
setPicker({
|
|
34583
34795
|
kind: "clarification",
|
|
@@ -34866,17 +35078,23 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
34866
35078
|
streamMemberId = memberId;
|
|
34867
35079
|
}
|
|
34868
35080
|
streamContent += event.delta;
|
|
34869
|
-
setStreaming(
|
|
34870
|
-
|
|
34871
|
-
|
|
34872
|
-
|
|
35081
|
+
setStreaming(
|
|
35082
|
+
commitStreaming,
|
|
35083
|
+
cleanAgentContent(streamContent),
|
|
35084
|
+
event.ts,
|
|
35085
|
+
{
|
|
35086
|
+
...event.memberId ? { memberId: event.memberId } : {},
|
|
35087
|
+
...event.memberName ? { memberName: event.memberName } : {}
|
|
35088
|
+
}
|
|
35089
|
+
);
|
|
34873
35090
|
} else {
|
|
34874
35091
|
commitStreaming((prev2) => {
|
|
34875
35092
|
const last = prev2[prev2.length - 1];
|
|
34876
35093
|
if (last && last.role === "assistant" && last.id.startsWith("streaming-") && (last.memberId ?? null) === (event.memberId ?? null)) {
|
|
35094
|
+
const nextContent = cleanAgentContent(last.content + event.delta);
|
|
34877
35095
|
return [
|
|
34878
35096
|
...prev2.slice(0, -1),
|
|
34879
|
-
{ ...last, content:
|
|
35097
|
+
{ ...last, content: nextContent }
|
|
34880
35098
|
];
|
|
34881
35099
|
}
|
|
34882
35100
|
return [
|
|
@@ -34884,7 +35102,7 @@ async function dispatchCouncilPromptImpl(text, deps, overrides = {}) {
|
|
|
34884
35102
|
{
|
|
34885
35103
|
id: `streaming-${crypto.randomUUID()}`,
|
|
34886
35104
|
role: "assistant",
|
|
34887
|
-
content: event.delta,
|
|
35105
|
+
content: cleanAgentContent(event.delta),
|
|
34888
35106
|
ts: event.ts,
|
|
34889
35107
|
...event.memberId ? { memberId: event.memberId } : {},
|
|
34890
35108
|
...event.memberName ? { memberName: event.memberName } : {}
|
|
@@ -37569,8 +37787,9 @@ function useBatchedMessages(state2, setState, cadenceMs = 16) {
|
|
|
37569
37787
|
// src/cli/hooks/useTerminalSize.ts
|
|
37570
37788
|
import { useEffect as useEffect6, useState as useState7 } from "react";
|
|
37571
37789
|
import { useStdout as useStdout2 } from "ink";
|
|
37790
|
+
var DEFAULT_COALESCE_MS = 120;
|
|
37572
37791
|
function useTerminalSize(options = {}) {
|
|
37573
|
-
const { defaults = { columns: 80, rows: 24 }, coalesceMs =
|
|
37792
|
+
const { defaults = { columns: 80, rows: 24 }, coalesceMs = DEFAULT_COALESCE_MS } = options;
|
|
37574
37793
|
const { stdout } = useStdout2();
|
|
37575
37794
|
const [size, setSize] = useState7({
|
|
37576
37795
|
columns: stdout?.columns ?? defaults.columns,
|
|
@@ -37578,25 +37797,25 @@ function useTerminalSize(options = {}) {
|
|
|
37578
37797
|
});
|
|
37579
37798
|
useEffect6(() => {
|
|
37580
37799
|
if (!stdout) return;
|
|
37581
|
-
|
|
37800
|
+
const read = () => ({
|
|
37582
37801
|
columns: stdout.columns ?? defaults.columns,
|
|
37583
37802
|
rows: stdout.rows ?? defaults.rows
|
|
37584
37803
|
});
|
|
37804
|
+
const commit = (next) => {
|
|
37805
|
+
setSize(
|
|
37806
|
+
(prev2) => prev2.columns === next.columns && prev2.rows === next.rows ? prev2 : next
|
|
37807
|
+
);
|
|
37808
|
+
};
|
|
37809
|
+
commit(read());
|
|
37585
37810
|
let rafId = null;
|
|
37586
37811
|
const handleResize = () => {
|
|
37587
37812
|
if (coalesceMs <= 0) {
|
|
37588
|
-
|
|
37589
|
-
columns: stdout.columns ?? defaults.columns,
|
|
37590
|
-
rows: stdout.rows ?? defaults.rows
|
|
37591
|
-
});
|
|
37813
|
+
commit(read());
|
|
37592
37814
|
return;
|
|
37593
37815
|
}
|
|
37594
37816
|
if (rafId !== null) clearTimeout(rafId);
|
|
37595
37817
|
rafId = setTimeout(() => {
|
|
37596
|
-
|
|
37597
|
-
columns: stdout.columns ?? defaults.columns,
|
|
37598
|
-
rows: stdout.rows ?? defaults.rows
|
|
37599
|
-
});
|
|
37818
|
+
commit(read());
|
|
37600
37819
|
rafId = null;
|
|
37601
37820
|
}, coalesceMs);
|
|
37602
37821
|
};
|
|
@@ -37723,60 +37942,84 @@ function App() {
|
|
|
37723
37942
|
}
|
|
37724
37943
|
setPicker(null);
|
|
37725
37944
|
}, [picker]);
|
|
37945
|
+
const bannerColsRef = useRef6(null);
|
|
37946
|
+
if (bannerColsRef.current === null) {
|
|
37947
|
+
bannerColsRef.current = size.columns > 0 ? size.columns : 80;
|
|
37948
|
+
}
|
|
37726
37949
|
const banner = useMemo(() => {
|
|
37727
|
-
const
|
|
37728
|
-
const
|
|
37729
|
-
|
|
37950
|
+
const cols = bannerColsRef.current ?? 80;
|
|
37951
|
+
const content = formatBannerWithLogoRight({
|
|
37952
|
+
leftLines: [
|
|
37953
|
+
`zelari-code \xB7 ${activeProviderSpec.id}/${activeModel}`,
|
|
37954
|
+
`cwd: ${cwd}`,
|
|
37955
|
+
`/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode`
|
|
37956
|
+
],
|
|
37957
|
+
version: VERSION,
|
|
37958
|
+
columns: cols,
|
|
37959
|
+
compact: cols < 72
|
|
37960
|
+
});
|
|
37730
37961
|
return {
|
|
37731
37962
|
id: "banner-once",
|
|
37732
37963
|
role: "system",
|
|
37733
37964
|
ts: 0,
|
|
37734
|
-
content
|
|
37735
|
-
cwd: ${cwd}
|
|
37736
|
-
/help \xB7 /plan \xB7 /build \xB7 /view-plan \xB7 shift+tab mode (agent/council/zelari)`
|
|
37965
|
+
content
|
|
37737
37966
|
};
|
|
37738
37967
|
}, [activeProviderSpec.id, activeModel, cwd]);
|
|
37968
|
+
const [sidebarOpen, setSidebarOpen] = useState8(false);
|
|
37969
|
+
useEffect7(() => {
|
|
37970
|
+
setSidebarOpen((prev2) => sidebarVisibility(size.columns, size.rows, prev2));
|
|
37971
|
+
}, [size.columns, size.rows]);
|
|
37739
37972
|
const staticKey = `${session.sessionId || "pre-bootstrap"}-${clearEpoch}`;
|
|
37740
37973
|
const staticItems = session.sessionId ? [banner, ...session.messages] : [];
|
|
37741
|
-
const
|
|
37742
|
-
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Static, { key: staticKey, items: staticItems }, (item) => renderMessage(item)), /* @__PURE__ */ React9.createElement(
|
|
37743
|
-
|
|
37744
|
-
{
|
|
37745
|
-
title: picker.title,
|
|
37746
|
-
items: picker.items,
|
|
37747
|
-
onSelect: onPickerSelect,
|
|
37748
|
-
onCancel: onPickerCancel,
|
|
37749
|
-
maxVisible: Math.max(4, Math.min(10, size.rows - 10))
|
|
37750
|
-
}
|
|
37751
|
-
) : /* @__PURE__ */ React9.createElement(
|
|
37752
|
-
InputBar,
|
|
37974
|
+
const dynamicMaxRows = Math.max(8, Math.min(18, size.rows - 2));
|
|
37975
|
+
return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(Static, { key: staticKey, items: staticItems }, (item) => renderMessage(item)), /* @__PURE__ */ React9.createElement(
|
|
37976
|
+
Box8,
|
|
37753
37977
|
{
|
|
37754
|
-
|
|
37755
|
-
|
|
37756
|
-
|
|
37757
|
-
|
|
37758
|
-
}
|
|
37759
|
-
|
|
37760
|
-
|
|
37761
|
-
|
|
37762
|
-
|
|
37763
|
-
|
|
37764
|
-
|
|
37765
|
-
|
|
37766
|
-
|
|
37767
|
-
|
|
37768
|
-
|
|
37769
|
-
|
|
37770
|
-
|
|
37771
|
-
|
|
37772
|
-
|
|
37773
|
-
|
|
37774
|
-
|
|
37775
|
-
|
|
37776
|
-
|
|
37777
|
-
|
|
37778
|
-
|
|
37779
|
-
|
|
37978
|
+
flexDirection: "row",
|
|
37979
|
+
width: size.columns > 0 ? size.columns : void 0,
|
|
37980
|
+
height: dynamicMaxRows,
|
|
37981
|
+
overflow: "hidden"
|
|
37982
|
+
},
|
|
37983
|
+
/* @__PURE__ */ React9.createElement(Box8, { flexDirection: "column", flexGrow: 1, paddingX: 1, overflow: "hidden" }, /* @__PURE__ */ React9.createElement(LiveRegion, { live: session.live, busy, elapsedMs: timer.elapsedMs }), picker ? /* @__PURE__ */ React9.createElement(
|
|
37984
|
+
SelectList,
|
|
37985
|
+
{
|
|
37986
|
+
title: picker.title,
|
|
37987
|
+
items: picker.items,
|
|
37988
|
+
onSelect: onPickerSelect,
|
|
37989
|
+
onCancel: onPickerCancel,
|
|
37990
|
+
maxVisible: Math.max(3, Math.min(8, size.rows - 12))
|
|
37991
|
+
}
|
|
37992
|
+
) : /* @__PURE__ */ React9.createElement(
|
|
37993
|
+
InputBar,
|
|
37994
|
+
{
|
|
37995
|
+
value: input,
|
|
37996
|
+
onChange: setInput,
|
|
37997
|
+
onSubmit: handleSubmit,
|
|
37998
|
+
disabled: busy
|
|
37999
|
+
}
|
|
38000
|
+
), /* @__PURE__ */ React9.createElement(
|
|
38001
|
+
StatusBar,
|
|
38002
|
+
{
|
|
38003
|
+
model: activeModel,
|
|
38004
|
+
provider: activeProviderSpec.id,
|
|
38005
|
+
sessionId: session.sessionId ? session.sessionId.slice(0, 8) : "...",
|
|
38006
|
+
sessionActive: session.sessionActive,
|
|
38007
|
+
queueCount: chatTurn.queueCount,
|
|
38008
|
+
busy,
|
|
38009
|
+
mode,
|
|
38010
|
+
phase: phase2,
|
|
38011
|
+
cwd,
|
|
38012
|
+
elapsedMs: timer.elapsedMs,
|
|
38013
|
+
lastMs: timer.lastMs,
|
|
38014
|
+
costUsd: sessionStats.totalCostUsd,
|
|
38015
|
+
cachedTokens: sessionStats.cachedTokens,
|
|
38016
|
+
contextUsed: sessionStats.totalTokens,
|
|
38017
|
+
contextLimit: Number(process.env.ZELARI_CONTEXT_LIMIT) || 2e5,
|
|
38018
|
+
brandVersion: VERSION
|
|
38019
|
+
}
|
|
38020
|
+
)),
|
|
38021
|
+
sidebarOpen && /* @__PURE__ */ React9.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })
|
|
38022
|
+
));
|
|
37780
38023
|
}
|
|
37781
38024
|
|
|
37782
38025
|
// src/cli/components/SplashScreen.tsx
|