@corbat-tech/coco 2.5.3 → 2.6.0
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/index.js +435 -52
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -7141,9 +7141,12 @@ YOU ARE AN EXECUTION AGENT, NOT A CONVERSATIONAL ASSISTANT.
|
|
|
7141
7141
|
- EVERY action requires a TOOL CALL. Text responses are ONLY for brief confirmations AFTER tools execute.
|
|
7142
7142
|
|
|
7143
7143
|
**Execution Process:**
|
|
7144
|
-
1. **
|
|
7144
|
+
1. **Orient**: Output ONE line stating the *goal* of the next step \u2014 not the tool, the intent.
|
|
7145
|
+
- Good: "Confirming the typo is gone\u2026" / "Checking tests still pass\u2026" / "Reading the config to understand current structure\u2026"
|
|
7146
|
+
- Bad: "I'll use grep to search." (restates the tool, not the goal)
|
|
7147
|
+
- Skip this for obvious single-step tasks ("create hello.js" \u2192 just create it).
|
|
7145
7148
|
2. **Execute**: IMMEDIATELY CALL THE APPROPRIATE TOOLS (this is mandatory, not optional)
|
|
7146
|
-
3. **Respond**: Brief confirmation of what was done (AFTER tools executed)
|
|
7149
|
+
3. **Respond**: Brief confirmation of what was done (AFTER all tools executed)
|
|
7147
7150
|
|
|
7148
7151
|
**Critical Rules:**
|
|
7149
7152
|
- User says "create X with Y" \u2192 Immediately call write_file/edit_file tool, no discussion
|
|
@@ -7228,19 +7231,43 @@ If a file tool fails with "outside project directory", the system will automatic
|
|
|
7228
7231
|
|
|
7229
7232
|
**For structured content** (documentation, tutorials, summaries, explanations with multiple sections, or when the user asks for "markdown"):
|
|
7230
7233
|
|
|
7231
|
-
1. Wrap your entire response in a single markdown
|
|
7232
|
-
|
|
7234
|
+
1. Wrap your entire response in a single tilde markdown block:
|
|
7235
|
+
~~~markdown
|
|
7233
7236
|
Your content here...
|
|
7237
|
+
~~~
|
|
7238
|
+
|
|
7239
|
+
2. **CRITICAL: Bare ~~~ closes the outer block** \u2014 Only use bare ~~~ (without a lang tag) as the VERY LAST line to close the outer block. Writing ~~~ anywhere else inside the block will break rendering.
|
|
7240
|
+
|
|
7241
|
+
3. **ALL inner fenced blocks use standard backtick syntax:**
|
|
7242
|
+
- Code: \`\`\`javascript / \`\`\`typescript / \`\`\`python / \`\`\`bash / etc.
|
|
7243
|
+
- Shell commands: \`\`\`bash
|
|
7244
|
+
- ASCII diagrams: \`\`\`ascii
|
|
7245
|
+
- Tree structures / file paths: \`\`\`text
|
|
7246
|
+
- Any other fenced content: \`\`\`<lang>
|
|
7247
|
+
|
|
7248
|
+
Example:
|
|
7249
|
+
~~~markdown
|
|
7250
|
+
## Section
|
|
7251
|
+
|
|
7252
|
+
Some text here.
|
|
7253
|
+
|
|
7254
|
+
\`\`\`bash
|
|
7255
|
+
echo "hello"
|
|
7256
|
+
ls -la
|
|
7234
7257
|
\`\`\`
|
|
7235
7258
|
|
|
7236
|
-
|
|
7259
|
+
\`\`\`ascii
|
|
7260
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
7261
|
+
\u2502 Service \u2502
|
|
7262
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
7263
|
+
\`\`\`
|
|
7237
7264
|
|
|
7238
|
-
|
|
7239
|
-
~~~javascript
|
|
7240
|
-
function example() { return "hello"; }
|
|
7265
|
+
More text after blocks.
|
|
7241
7266
|
~~~
|
|
7242
7267
|
|
|
7243
|
-
|
|
7268
|
+
**Inner blocks open with \`\`\`lang and close with \`\`\`. The only ~~~ inside the markdown block is the final bare ~~~ at the very end.**
|
|
7269
|
+
|
|
7270
|
+
4. **Include all content in ONE block**: headers, lists, tables, quotes, code, commands, diagrams.
|
|
7244
7271
|
|
|
7245
7272
|
**When to use markdown block:**
|
|
7246
7273
|
- User asks for documentation, summary, tutorial, guide
|
|
@@ -32837,6 +32864,8 @@ var rawMarkdownBuffer = "";
|
|
|
32837
32864
|
var inCodeBlock = false;
|
|
32838
32865
|
var codeBlockLang = "";
|
|
32839
32866
|
var codeBlockLines = [];
|
|
32867
|
+
var inNestedCodeBlock = false;
|
|
32868
|
+
var codeBlockFenceChar = "";
|
|
32840
32869
|
var streamingIndicatorActive = false;
|
|
32841
32870
|
var streamingIndicatorInterval = null;
|
|
32842
32871
|
var streamingIndicatorFrame = 0;
|
|
@@ -32880,6 +32909,7 @@ function flushLineBuffer() {
|
|
|
32880
32909
|
stopStreamingIndicator();
|
|
32881
32910
|
}
|
|
32882
32911
|
inCodeBlock = false;
|
|
32912
|
+
codeBlockFenceChar = "";
|
|
32883
32913
|
codeBlockLang = "";
|
|
32884
32914
|
codeBlockLines = [];
|
|
32885
32915
|
}
|
|
@@ -32887,6 +32917,8 @@ function flushLineBuffer() {
|
|
|
32887
32917
|
function resetLineBuffer() {
|
|
32888
32918
|
lineBuffer = "";
|
|
32889
32919
|
inCodeBlock = false;
|
|
32920
|
+
inNestedCodeBlock = false;
|
|
32921
|
+
codeBlockFenceChar = "";
|
|
32890
32922
|
codeBlockLang = "";
|
|
32891
32923
|
codeBlockLines = [];
|
|
32892
32924
|
stopStreamingIndicator();
|
|
@@ -32909,28 +32941,100 @@ function renderStreamChunk(chunk) {
|
|
|
32909
32941
|
}
|
|
32910
32942
|
}
|
|
32911
32943
|
function processAndOutputLine(line) {
|
|
32912
|
-
|
|
32944
|
+
line = line.replace(/^[\u200B\uFEFF\u200C\u200D\u2060\u00AD]+/, "");
|
|
32945
|
+
const tildeFenceMatch = line.match(/^~~~(\w*)$/);
|
|
32946
|
+
if (tildeFenceMatch) {
|
|
32947
|
+
const lang = tildeFenceMatch[1] || "";
|
|
32948
|
+
if (!inCodeBlock) {
|
|
32949
|
+
if (lang) {
|
|
32950
|
+
inCodeBlock = true;
|
|
32951
|
+
inNestedCodeBlock = false;
|
|
32952
|
+
codeBlockFenceChar = "~~~";
|
|
32953
|
+
codeBlockLang = lang;
|
|
32954
|
+
codeBlockLines = [];
|
|
32955
|
+
if (codeBlockLang === "markdown" || codeBlockLang === "md") {
|
|
32956
|
+
startStreamingIndicator();
|
|
32957
|
+
}
|
|
32958
|
+
} else {
|
|
32959
|
+
const formatted = formatMarkdownLine(line);
|
|
32960
|
+
const termWidth = getTerminalWidth2();
|
|
32961
|
+
const wrapped = wrapText(formatted, termWidth);
|
|
32962
|
+
for (const wl of wrapped) {
|
|
32963
|
+
console.log(wl);
|
|
32964
|
+
}
|
|
32965
|
+
}
|
|
32966
|
+
} else if (codeBlockFenceChar === "~~~") {
|
|
32967
|
+
if (lang && !inNestedCodeBlock) {
|
|
32968
|
+
inNestedCodeBlock = true;
|
|
32969
|
+
codeBlockLines.push(line);
|
|
32970
|
+
} else if (!lang && inNestedCodeBlock) {
|
|
32971
|
+
inNestedCodeBlock = false;
|
|
32972
|
+
codeBlockLines.push(line);
|
|
32973
|
+
} else if (!lang && !inNestedCodeBlock) {
|
|
32974
|
+
stopStreamingIndicator();
|
|
32975
|
+
renderCodeBlock(codeBlockLang, codeBlockLines);
|
|
32976
|
+
inCodeBlock = false;
|
|
32977
|
+
inNestedCodeBlock = false;
|
|
32978
|
+
codeBlockFenceChar = "";
|
|
32979
|
+
codeBlockLang = "";
|
|
32980
|
+
codeBlockLines = [];
|
|
32981
|
+
} else {
|
|
32982
|
+
codeBlockLines.push(line);
|
|
32983
|
+
}
|
|
32984
|
+
} else {
|
|
32985
|
+
if (lang && !inNestedCodeBlock) {
|
|
32986
|
+
inNestedCodeBlock = true;
|
|
32987
|
+
codeBlockLines.push(line);
|
|
32988
|
+
} else if (!lang && inNestedCodeBlock) {
|
|
32989
|
+
inNestedCodeBlock = false;
|
|
32990
|
+
codeBlockLines.push(line);
|
|
32991
|
+
} else {
|
|
32992
|
+
codeBlockLines.push(line);
|
|
32993
|
+
}
|
|
32994
|
+
}
|
|
32995
|
+
return;
|
|
32996
|
+
}
|
|
32997
|
+
const codeBlockMatch = line.match(/^(`{3,4})(\w*)$/);
|
|
32913
32998
|
if (codeBlockMatch) {
|
|
32999
|
+
const fenceChars = codeBlockMatch[1];
|
|
33000
|
+
const lang = codeBlockMatch[2] || "";
|
|
32914
33001
|
if (!inCodeBlock) {
|
|
32915
33002
|
inCodeBlock = true;
|
|
32916
|
-
|
|
33003
|
+
inNestedCodeBlock = false;
|
|
33004
|
+
codeBlockFenceChar = fenceChars;
|
|
33005
|
+
codeBlockLang = lang;
|
|
32917
33006
|
codeBlockLines = [];
|
|
32918
33007
|
if (codeBlockLang === "markdown" || codeBlockLang === "md") {
|
|
32919
33008
|
startStreamingIndicator();
|
|
32920
33009
|
}
|
|
32921
|
-
} else {
|
|
33010
|
+
} else if (!lang && inNestedCodeBlock && fenceChars === "```") {
|
|
33011
|
+
inNestedCodeBlock = false;
|
|
33012
|
+
codeBlockLines.push(line);
|
|
33013
|
+
} else if (!inNestedCodeBlock && lang && fenceChars === "```") {
|
|
33014
|
+
inNestedCodeBlock = true;
|
|
33015
|
+
codeBlockLines.push(line);
|
|
33016
|
+
} else if (!lang && !inNestedCodeBlock && codeBlockFenceChar === fenceChars) {
|
|
32922
33017
|
stopStreamingIndicator();
|
|
32923
33018
|
renderCodeBlock(codeBlockLang, codeBlockLines);
|
|
32924
33019
|
inCodeBlock = false;
|
|
33020
|
+
inNestedCodeBlock = false;
|
|
33021
|
+
codeBlockFenceChar = "";
|
|
32925
33022
|
codeBlockLang = "";
|
|
32926
33023
|
codeBlockLines = [];
|
|
33024
|
+
} else {
|
|
33025
|
+
codeBlockLines.push(line);
|
|
32927
33026
|
}
|
|
32928
33027
|
return;
|
|
32929
33028
|
}
|
|
32930
33029
|
if (inCodeBlock) {
|
|
32931
33030
|
codeBlockLines.push(line);
|
|
32932
33031
|
} else {
|
|
32933
|
-
|
|
33032
|
+
const formatted = formatMarkdownLine(line);
|
|
33033
|
+
const termWidth = getTerminalWidth2();
|
|
33034
|
+
const wrapped = wrapText(formatted, termWidth);
|
|
33035
|
+
for (const wl of wrapped) {
|
|
33036
|
+
console.log(wl);
|
|
33037
|
+
}
|
|
32934
33038
|
}
|
|
32935
33039
|
}
|
|
32936
33040
|
function renderCodeBlock(lang, lines) {
|
|
@@ -33241,8 +33345,9 @@ function wrapText(text13, maxWidth) {
|
|
|
33241
33345
|
}
|
|
33242
33346
|
const lines = [];
|
|
33243
33347
|
let remaining = text13;
|
|
33244
|
-
while (
|
|
33348
|
+
while (true) {
|
|
33245
33349
|
const plain = stripAnsi2(remaining);
|
|
33350
|
+
if (plain.length <= maxWidth) break;
|
|
33246
33351
|
let breakPoint = maxWidth;
|
|
33247
33352
|
const lastSpace = plain.lastIndexOf(" ", maxWidth);
|
|
33248
33353
|
if (lastSpace > maxWidth * 0.5) {
|
|
@@ -33271,8 +33376,8 @@ function wrapText(text13, maxWidth) {
|
|
|
33271
33376
|
rawPos = ansiPositions[ansiIdx].end;
|
|
33272
33377
|
ansiIdx++;
|
|
33273
33378
|
}
|
|
33274
|
-
lines.push(remaining.slice(0, rawPos));
|
|
33275
|
-
remaining = remaining.slice(rawPos).trimStart();
|
|
33379
|
+
lines.push(remaining.slice(0, rawPos) + "\x1B[0m");
|
|
33380
|
+
remaining = "\x1B[0m" + remaining.slice(rawPos).trimStart();
|
|
33276
33381
|
}
|
|
33277
33382
|
if (remaining) {
|
|
33278
33383
|
lines.push(remaining);
|
|
@@ -33312,16 +33417,54 @@ function getToolIcon(toolName, input) {
|
|
|
33312
33417
|
function renderToolStart(toolName, input, metadata) {
|
|
33313
33418
|
const icon = getToolIcon(toolName, { ...input, wouldCreate: metadata?.isCreate });
|
|
33314
33419
|
const summary = formatToolSummary(toolName, input);
|
|
33315
|
-
let label = toolName;
|
|
33316
33420
|
if (toolName === "write_file") {
|
|
33317
|
-
label = chalk25.yellow.bold("MODIFY") + " " + chalk25.cyan(String(input.path || ""));
|
|
33421
|
+
const label = chalk25.yellow.bold("MODIFY") + " " + chalk25.cyan(String(input.path || ""));
|
|
33318
33422
|
console.log(`
|
|
33319
33423
|
${icon} ${label}`);
|
|
33424
|
+
const preview = renderContentPreview(String(input.content || ""), 3);
|
|
33425
|
+
if (preview) console.log(preview);
|
|
33426
|
+
return;
|
|
33427
|
+
}
|
|
33428
|
+
if (toolName === "edit_file") {
|
|
33429
|
+
console.log(`
|
|
33430
|
+
${icon} ${chalk25.yellow.bold("EDIT")} ${chalk25.cyan(String(input.path || ""))}`);
|
|
33431
|
+
const editPreview = renderEditPreview(
|
|
33432
|
+
String(input.old_string || ""),
|
|
33433
|
+
String(input.new_string || "")
|
|
33434
|
+
);
|
|
33435
|
+
if (editPreview) console.log(editPreview);
|
|
33320
33436
|
return;
|
|
33321
33437
|
}
|
|
33322
33438
|
console.log(`
|
|
33323
33439
|
${icon} ${chalk25.cyan.bold(toolName)} ${chalk25.dim(summary)}`);
|
|
33324
33440
|
}
|
|
33441
|
+
function renderContentPreview(content, maxLines) {
|
|
33442
|
+
const maxWidth = Math.max(getTerminalWidth2() - 6, 40);
|
|
33443
|
+
const lines = content.split("\n");
|
|
33444
|
+
const preview = [];
|
|
33445
|
+
for (const line of lines) {
|
|
33446
|
+
if (preview.length >= maxLines) break;
|
|
33447
|
+
const trimmed = line.trimEnd();
|
|
33448
|
+
if (trimmed.length === 0 && preview.length === 0) continue;
|
|
33449
|
+
const truncated = trimmed.length > maxWidth ? trimmed.slice(0, maxWidth - 1) + "\u2026" : trimmed;
|
|
33450
|
+
preview.push(` ${truncated}`);
|
|
33451
|
+
}
|
|
33452
|
+
if (preview.length === 0) return "";
|
|
33453
|
+
const totalNonEmpty = lines.filter((l) => l.trim().length > 0).length;
|
|
33454
|
+
const more = totalNonEmpty > maxLines ? chalk25.dim(` \u2026 +${totalNonEmpty - maxLines} lines`) : "";
|
|
33455
|
+
return chalk25.dim(preview.join("\n")) + more;
|
|
33456
|
+
}
|
|
33457
|
+
function renderEditPreview(oldStr, newStr) {
|
|
33458
|
+
const maxWidth = Math.max(getTerminalWidth2() - 8, 30);
|
|
33459
|
+
const firstOld = oldStr.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
33460
|
+
const firstNew = newStr.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
33461
|
+
if (!firstOld && !firstNew) return "";
|
|
33462
|
+
const truncate2 = (s) => s.length > maxWidth ? s.slice(0, maxWidth - 1) + "\u2026" : s;
|
|
33463
|
+
const lines = [];
|
|
33464
|
+
if (firstOld) lines.push(chalk25.dim(" ") + chalk25.red(`- ${truncate2(firstOld.trim())}`));
|
|
33465
|
+
if (firstNew) lines.push(chalk25.dim(" ") + chalk25.green(`+ ${truncate2(firstNew.trim())}`));
|
|
33466
|
+
return lines.join("\n");
|
|
33467
|
+
}
|
|
33325
33468
|
function renderToolEnd(result) {
|
|
33326
33469
|
const status = result.result.success ? chalk25.green("\u2713") : chalk25.red("\u2717");
|
|
33327
33470
|
const duration = chalk25.dim(`${result.duration.toFixed(0)}ms`);
|
|
@@ -33330,6 +33473,8 @@ function renderToolEnd(result) {
|
|
|
33330
33473
|
if (!result.result.success && result.result.error) {
|
|
33331
33474
|
console.log(chalk25.red(` \u2514\u2500 ${result.result.error}`));
|
|
33332
33475
|
}
|
|
33476
|
+
const details = formatResultDetails(result);
|
|
33477
|
+
if (details) console.log(details);
|
|
33333
33478
|
}
|
|
33334
33479
|
function formatToolSummary(toolName, input) {
|
|
33335
33480
|
switch (toolName) {
|
|
@@ -33340,6 +33485,7 @@ function formatToolSummary(toolName, input) {
|
|
|
33340
33485
|
return String(input.path || "");
|
|
33341
33486
|
case "list_directory":
|
|
33342
33487
|
return String(input.path || ".");
|
|
33488
|
+
case "grep":
|
|
33343
33489
|
case "search_files": {
|
|
33344
33490
|
const pattern = String(input.pattern || "");
|
|
33345
33491
|
const path54 = input.path ? ` in ${input.path}` : "";
|
|
@@ -33347,7 +33493,8 @@ function formatToolSummary(toolName, input) {
|
|
|
33347
33493
|
}
|
|
33348
33494
|
case "bash_exec": {
|
|
33349
33495
|
const cmd = String(input.command || "");
|
|
33350
|
-
|
|
33496
|
+
const max = Math.max(getTerminalWidth2() - 20, 50);
|
|
33497
|
+
return cmd.length > max ? cmd.slice(0, max - 1) + "\u2026" : cmd;
|
|
33351
33498
|
}
|
|
33352
33499
|
default:
|
|
33353
33500
|
return formatToolInput(input);
|
|
@@ -33371,15 +33518,16 @@ function formatResultPreview(result) {
|
|
|
33371
33518
|
return chalk25.dim(`(${files} files, ${dirs} dirs)`);
|
|
33372
33519
|
}
|
|
33373
33520
|
break;
|
|
33521
|
+
case "grep":
|
|
33374
33522
|
case "search_files":
|
|
33375
33523
|
if (Array.isArray(data.matches)) {
|
|
33376
|
-
|
|
33524
|
+
const n = data.matches.length;
|
|
33525
|
+
return n === 0 ? chalk25.yellow("\xB7 no matches") : chalk25.dim(`\xB7 ${n} match${n === 1 ? "" : "es"}`);
|
|
33377
33526
|
}
|
|
33378
33527
|
break;
|
|
33379
33528
|
case "bash_exec":
|
|
33380
|
-
if (data.exitCode
|
|
33381
|
-
|
|
33382
|
-
return chalk25.dim(`(${lines} lines)`);
|
|
33529
|
+
if (data.exitCode !== void 0 && data.exitCode !== 0) {
|
|
33530
|
+
return chalk25.red(`(exit ${data.exitCode})`);
|
|
33383
33531
|
}
|
|
33384
33532
|
break;
|
|
33385
33533
|
case "write_file":
|
|
@@ -33390,6 +33538,47 @@ function formatResultPreview(result) {
|
|
|
33390
33538
|
}
|
|
33391
33539
|
return "";
|
|
33392
33540
|
}
|
|
33541
|
+
function formatResultDetails(result) {
|
|
33542
|
+
if (!result.result.success) return "";
|
|
33543
|
+
const { name, result: toolResult } = result;
|
|
33544
|
+
const maxWidth = Math.max(getTerminalWidth2() - 8, 40);
|
|
33545
|
+
try {
|
|
33546
|
+
const data = JSON.parse(toolResult.output);
|
|
33547
|
+
if ((name === "grep" || name === "search_files") && Array.isArray(data.matches)) {
|
|
33548
|
+
const matches = data.matches;
|
|
33549
|
+
if (matches.length === 0) return "";
|
|
33550
|
+
const MAX_SHOWN = 3;
|
|
33551
|
+
const shown = matches.slice(0, MAX_SHOWN);
|
|
33552
|
+
const lines = shown.map(({ file, line, content }) => {
|
|
33553
|
+
const location = chalk25.cyan(`${file}:${line}`);
|
|
33554
|
+
const snippet = content.trim();
|
|
33555
|
+
const truncated = snippet.length > maxWidth ? snippet.slice(0, maxWidth - 1) + "\u2026" : snippet;
|
|
33556
|
+
return ` ${chalk25.dim("\u2502")} ${location} ${chalk25.dim(truncated)}`;
|
|
33557
|
+
});
|
|
33558
|
+
if (matches.length > MAX_SHOWN) {
|
|
33559
|
+
lines.push(` ${chalk25.dim(`\u2502 \u2026 +${matches.length - MAX_SHOWN} more`)}`);
|
|
33560
|
+
}
|
|
33561
|
+
return lines.join("\n");
|
|
33562
|
+
}
|
|
33563
|
+
if (name === "bash_exec" && data.exitCode === 0) {
|
|
33564
|
+
const stdout = String(data.stdout || "").trimEnd();
|
|
33565
|
+
if (!stdout) return "";
|
|
33566
|
+
const outputLines = stdout.split("\n").filter((l) => l.trim());
|
|
33567
|
+
if (outputLines.length > 6) return "";
|
|
33568
|
+
const shown = outputLines.slice(0, 4);
|
|
33569
|
+
const lines = shown.map((l) => {
|
|
33570
|
+
const truncated = l.length > maxWidth ? l.slice(0, maxWidth - 1) + "\u2026" : l;
|
|
33571
|
+
return ` ${chalk25.dim("\u2502")} ${chalk25.dim(truncated)}`;
|
|
33572
|
+
});
|
|
33573
|
+
if (outputLines.length > 4) {
|
|
33574
|
+
lines.push(` ${chalk25.dim(`\u2502 \u2026 +${outputLines.length - 4} more`)}`);
|
|
33575
|
+
}
|
|
33576
|
+
return lines.join("\n");
|
|
33577
|
+
}
|
|
33578
|
+
} catch {
|
|
33579
|
+
}
|
|
33580
|
+
return "";
|
|
33581
|
+
}
|
|
33393
33582
|
function formatToolInput(input) {
|
|
33394
33583
|
const entries = Object.entries(input);
|
|
33395
33584
|
if (entries.length === 0) return "";
|
|
@@ -38786,7 +38975,7 @@ init_errors();
|
|
|
38786
38975
|
init_paths();
|
|
38787
38976
|
var fs36 = await import('fs/promises');
|
|
38788
38977
|
var path38 = await import('path');
|
|
38789
|
-
var
|
|
38978
|
+
var crypto2 = await import('crypto');
|
|
38790
38979
|
var GLOBAL_MEMORIES_DIR = path38.join(COCO_HOME, "memories");
|
|
38791
38980
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
38792
38981
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
@@ -38868,7 +39057,7 @@ Examples:
|
|
|
38868
39057
|
{ tool: "create_memory" }
|
|
38869
39058
|
);
|
|
38870
39059
|
}
|
|
38871
|
-
const id =
|
|
39060
|
+
const id = crypto2.randomUUID();
|
|
38872
39061
|
const memory = {
|
|
38873
39062
|
id,
|
|
38874
39063
|
key,
|
|
@@ -38983,7 +39172,7 @@ var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
|
38983
39172
|
init_registry4();
|
|
38984
39173
|
init_errors();
|
|
38985
39174
|
var fs37 = await import('fs/promises');
|
|
38986
|
-
var
|
|
39175
|
+
var crypto3 = await import('crypto');
|
|
38987
39176
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
38988
39177
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
38989
39178
|
var STASH_PREFIX = "coco-cp";
|
|
@@ -39038,7 +39227,7 @@ Examples:
|
|
|
39038
39227
|
description: z.string().min(1).max(200).describe("Description of this checkpoint")
|
|
39039
39228
|
}),
|
|
39040
39229
|
async execute({ description }) {
|
|
39041
|
-
const id =
|
|
39230
|
+
const id = crypto3.randomUUID().slice(0, 8);
|
|
39042
39231
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
39043
39232
|
const stashMessage = `${STASH_PREFIX}-${id}-${description.replace(/\s+/g, "-").slice(0, 50)}`;
|
|
39044
39233
|
const changedFiles = await getChangedFiles();
|
|
@@ -42128,6 +42317,115 @@ function findNextWordBoundary(line, pos) {
|
|
|
42128
42317
|
while (i < line.length && line[i] === " ") i++;
|
|
42129
42318
|
return i;
|
|
42130
42319
|
}
|
|
42320
|
+
function countVisualRows(text13, startCol, termCols) {
|
|
42321
|
+
let rows = 1;
|
|
42322
|
+
let col = startCol;
|
|
42323
|
+
for (const char of text13) {
|
|
42324
|
+
if (char === "\n") {
|
|
42325
|
+
if (col > 0) rows++;
|
|
42326
|
+
col = 0;
|
|
42327
|
+
} else {
|
|
42328
|
+
col++;
|
|
42329
|
+
if (col >= termCols) {
|
|
42330
|
+
rows++;
|
|
42331
|
+
col = 0;
|
|
42332
|
+
}
|
|
42333
|
+
}
|
|
42334
|
+
}
|
|
42335
|
+
return rows;
|
|
42336
|
+
}
|
|
42337
|
+
function getCursorVisualPos(text13, cursorPos, promptLen, termCols) {
|
|
42338
|
+
let row = 0;
|
|
42339
|
+
let col = promptLen;
|
|
42340
|
+
for (let i = 0; i < cursorPos; i++) {
|
|
42341
|
+
if (text13[i] === "\n") {
|
|
42342
|
+
if (col > 0) row++;
|
|
42343
|
+
col = 0;
|
|
42344
|
+
} else {
|
|
42345
|
+
col++;
|
|
42346
|
+
if (col >= termCols) {
|
|
42347
|
+
row++;
|
|
42348
|
+
col = 0;
|
|
42349
|
+
}
|
|
42350
|
+
}
|
|
42351
|
+
}
|
|
42352
|
+
return { row, col };
|
|
42353
|
+
}
|
|
42354
|
+
function computeWordWrap(text13, startCol, termCols) {
|
|
42355
|
+
const passthrough = {
|
|
42356
|
+
display: text13,
|
|
42357
|
+
toDisplayPos: (p45) => p45,
|
|
42358
|
+
toOrigPos: (p45) => p45
|
|
42359
|
+
};
|
|
42360
|
+
if (!text13 || termCols <= 1) return passthrough;
|
|
42361
|
+
const origToDisp = new Int32Array(text13.length + 1);
|
|
42362
|
+
const dispToOrig = [];
|
|
42363
|
+
let display = "";
|
|
42364
|
+
let col = startCol;
|
|
42365
|
+
function emitChar(ch, origIdx) {
|
|
42366
|
+
origToDisp[origIdx] = display.length;
|
|
42367
|
+
dispToOrig.push(origIdx);
|
|
42368
|
+
display += ch;
|
|
42369
|
+
col = ch === "\n" ? 0 : col + 1;
|
|
42370
|
+
}
|
|
42371
|
+
function injectNewline() {
|
|
42372
|
+
dispToOrig.push(-1);
|
|
42373
|
+
display += "\n";
|
|
42374
|
+
col = 0;
|
|
42375
|
+
}
|
|
42376
|
+
let i = 0;
|
|
42377
|
+
while (i < text13.length) {
|
|
42378
|
+
const ch = text13[i];
|
|
42379
|
+
if (ch === "\n") {
|
|
42380
|
+
emitChar("\n", i++);
|
|
42381
|
+
continue;
|
|
42382
|
+
}
|
|
42383
|
+
if (ch !== " ") {
|
|
42384
|
+
let wordEnd = i;
|
|
42385
|
+
while (wordEnd < text13.length && text13[wordEnd] !== " " && text13[wordEnd] !== "\n") {
|
|
42386
|
+
wordEnd++;
|
|
42387
|
+
}
|
|
42388
|
+
const wordLen = wordEnd - i;
|
|
42389
|
+
if (col > 0 && col + wordLen > termCols) {
|
|
42390
|
+
injectNewline();
|
|
42391
|
+
}
|
|
42392
|
+
for (let k = i; k < wordEnd; k++) {
|
|
42393
|
+
emitChar(text13[k], k);
|
|
42394
|
+
if (col >= termCols && k + 1 < wordEnd) {
|
|
42395
|
+
injectNewline();
|
|
42396
|
+
}
|
|
42397
|
+
}
|
|
42398
|
+
i = wordEnd;
|
|
42399
|
+
} else {
|
|
42400
|
+
emitChar(" ", i++);
|
|
42401
|
+
if (col >= termCols) {
|
|
42402
|
+
col = 0;
|
|
42403
|
+
} else {
|
|
42404
|
+
let nextWordEnd = i;
|
|
42405
|
+
while (nextWordEnd < text13.length && text13[nextWordEnd] !== " " && text13[nextWordEnd] !== "\n") {
|
|
42406
|
+
nextWordEnd++;
|
|
42407
|
+
}
|
|
42408
|
+
const nextWordLen = nextWordEnd - i;
|
|
42409
|
+
if (nextWordLen > 0 && col + nextWordLen > termCols) {
|
|
42410
|
+
injectNewline();
|
|
42411
|
+
}
|
|
42412
|
+
}
|
|
42413
|
+
}
|
|
42414
|
+
}
|
|
42415
|
+
origToDisp[text13.length] = display.length;
|
|
42416
|
+
return {
|
|
42417
|
+
display,
|
|
42418
|
+
toDisplayPos: (origPos) => origToDisp[Math.min(origPos, text13.length)] ?? display.length,
|
|
42419
|
+
toOrigPos: (displayPos) => {
|
|
42420
|
+
const dp = Math.max(0, Math.min(displayPos, dispToOrig.length - 1));
|
|
42421
|
+
for (let d = dp; d >= 0; d--) {
|
|
42422
|
+
const orig = dispToOrig[d];
|
|
42423
|
+
if (orig !== void 0 && orig >= 0) return orig;
|
|
42424
|
+
}
|
|
42425
|
+
return 0;
|
|
42426
|
+
}
|
|
42427
|
+
};
|
|
42428
|
+
}
|
|
42131
42429
|
function createInputHandler(_session) {
|
|
42132
42430
|
const savedHistory = loadHistory();
|
|
42133
42431
|
const sessionHistory = [...savedHistory];
|
|
@@ -42142,6 +42440,7 @@ function createInputHandler(_session) {
|
|
|
42142
42440
|
let lastCursorRow = 0;
|
|
42143
42441
|
let lastContentRows = 1;
|
|
42144
42442
|
let isFirstRender = true;
|
|
42443
|
+
let lastCtrlCTime = 0;
|
|
42145
42444
|
let isPasting = false;
|
|
42146
42445
|
let pasteBuffer = "";
|
|
42147
42446
|
let isReadingClipboard = false;
|
|
@@ -42183,7 +42482,9 @@ function createInputHandler(_session) {
|
|
|
42183
42482
|
process.stdout.write("\r" + ansiEscapes.eraseDown);
|
|
42184
42483
|
const separator = chalk25.dim("\u2500".repeat(termCols));
|
|
42185
42484
|
let output = separator + "\n";
|
|
42186
|
-
|
|
42485
|
+
const ww = computeWordWrap(currentLine, prompt.visualLen, termCols);
|
|
42486
|
+
const displayLine = ww.display;
|
|
42487
|
+
output += prompt.str + displayLine;
|
|
42187
42488
|
completions = findCompletions(currentLine);
|
|
42188
42489
|
selectedCompletion = Math.min(selectedCompletion, Math.max(0, completions.length - 1));
|
|
42189
42490
|
if (cursorPos === currentLine.length && completions.length > 0 && completions[selectedCompletion]) {
|
|
@@ -42192,9 +42493,23 @@ function createInputHandler(_session) {
|
|
|
42192
42493
|
output += chalk25.dim.gray(ghost);
|
|
42193
42494
|
}
|
|
42194
42495
|
}
|
|
42195
|
-
const
|
|
42196
|
-
const contentRows =
|
|
42197
|
-
|
|
42496
|
+
const hasWrapped = displayLine.includes("\n");
|
|
42497
|
+
const contentRows = hasWrapped ? countVisualRows(displayLine, prompt.visualLen, termCols) : (() => {
|
|
42498
|
+
const len = prompt.visualLen + displayLine.length;
|
|
42499
|
+
return len === 0 ? 1 : Math.ceil(len / termCols);
|
|
42500
|
+
})();
|
|
42501
|
+
const contentExactFill = hasWrapped ? (() => {
|
|
42502
|
+
const { col } = getCursorVisualPos(
|
|
42503
|
+
displayLine,
|
|
42504
|
+
displayLine.length,
|
|
42505
|
+
prompt.visualLen,
|
|
42506
|
+
termCols
|
|
42507
|
+
);
|
|
42508
|
+
return col === 0 && displayLine.length > 0;
|
|
42509
|
+
})() : (() => {
|
|
42510
|
+
const len = prompt.visualLen + displayLine.length;
|
|
42511
|
+
return len > 0 && len % termCols === 0;
|
|
42512
|
+
})();
|
|
42198
42513
|
output += (contentExactFill ? "" : "\n") + separator;
|
|
42199
42514
|
const showMenu = completions.length > 0 && currentLine.startsWith("/") && currentLine.length >= 1;
|
|
42200
42515
|
let extraLinesBelow = 0;
|
|
@@ -42251,10 +42566,19 @@ function createInputHandler(_session) {
|
|
|
42251
42566
|
const totalUp = extraLinesBelow + 1 + contentRows;
|
|
42252
42567
|
output += ansiEscapes.cursorUp(totalUp);
|
|
42253
42568
|
output += ansiEscapes.cursorDown(1);
|
|
42254
|
-
const
|
|
42255
|
-
|
|
42256
|
-
|
|
42257
|
-
|
|
42569
|
+
const displayCursorPos = cursorPos === 0 ? 0 : ww.toDisplayPos(cursorPos);
|
|
42570
|
+
let finalLine;
|
|
42571
|
+
let finalCol;
|
|
42572
|
+
if (hasWrapped) {
|
|
42573
|
+
const pos = getCursorVisualPos(displayLine, displayCursorPos, prompt.visualLen, termCols);
|
|
42574
|
+
finalLine = pos.row;
|
|
42575
|
+
finalCol = pos.col;
|
|
42576
|
+
} else {
|
|
42577
|
+
const cursorAbsolutePos = prompt.visualLen + cursorPos;
|
|
42578
|
+
const onExactBoundary = cursorAbsolutePos > 0 && cursorAbsolutePos % termCols === 0;
|
|
42579
|
+
finalLine = onExactBoundary ? cursorAbsolutePos / termCols - 1 : Math.floor(cursorAbsolutePos / termCols);
|
|
42580
|
+
finalCol = onExactBoundary ? 0 : cursorAbsolutePos % termCols;
|
|
42581
|
+
}
|
|
42258
42582
|
output += "\r";
|
|
42259
42583
|
if (finalLine > 0) {
|
|
42260
42584
|
output += ansiEscapes.cursorDown(finalLine);
|
|
@@ -42275,8 +42599,8 @@ function createInputHandler(_session) {
|
|
|
42275
42599
|
lastMenuLines = 0;
|
|
42276
42600
|
}
|
|
42277
42601
|
function insertTextAtCursor(text13) {
|
|
42278
|
-
const cleaned = text13.replace(
|
|
42279
|
-
const printable = cleaned.replace(/[^\x20-\x7E\u00A0-\uFFFF]/g, "");
|
|
42602
|
+
const cleaned = text13.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
42603
|
+
const printable = cleaned.replace(/[^\n\x20-\x7E\u00A0-\uFFFF]/g, "");
|
|
42280
42604
|
if (printable.length === 0) return;
|
|
42281
42605
|
currentLine = currentLine.slice(0, cursorPos) + printable + currentLine.slice(cursorPos);
|
|
42282
42606
|
cursorPos += printable.length;
|
|
@@ -42343,10 +42667,27 @@ function createInputHandler(_session) {
|
|
|
42343
42667
|
return;
|
|
42344
42668
|
}
|
|
42345
42669
|
if (key === "") {
|
|
42670
|
+
if (currentLine.length > 0) {
|
|
42671
|
+
currentLine = "";
|
|
42672
|
+
cursorPos = 0;
|
|
42673
|
+
selectedCompletion = 0;
|
|
42674
|
+
historyIndex = -1;
|
|
42675
|
+
lastCtrlCTime = 0;
|
|
42676
|
+
render();
|
|
42677
|
+
return;
|
|
42678
|
+
}
|
|
42679
|
+
const now = Date.now();
|
|
42680
|
+
if (now - lastCtrlCTime < 800) {
|
|
42681
|
+
cleanup();
|
|
42682
|
+
console.log("\n\u{1F44B} Goodbye!");
|
|
42683
|
+
saveHistory(sessionHistory);
|
|
42684
|
+
process.exit(0);
|
|
42685
|
+
}
|
|
42686
|
+
lastCtrlCTime = now;
|
|
42346
42687
|
cleanup();
|
|
42347
|
-
console.log("
|
|
42348
|
-
|
|
42349
|
-
|
|
42688
|
+
console.log(chalk25.dim("(Press Ctrl+C again to exit)"));
|
|
42689
|
+
resolve4("");
|
|
42690
|
+
return;
|
|
42350
42691
|
}
|
|
42351
42692
|
if (key === "") {
|
|
42352
42693
|
if (currentLine.length === 0) {
|
|
@@ -42484,7 +42825,10 @@ function createInputHandler(_session) {
|
|
|
42484
42825
|
selectedCompletion = Math.min(targetIndex, completions.length - 1);
|
|
42485
42826
|
}
|
|
42486
42827
|
render();
|
|
42487
|
-
} else if (
|
|
42828
|
+
} else if (cursorPos > 0) {
|
|
42829
|
+
cursorPos = 0;
|
|
42830
|
+
render();
|
|
42831
|
+
} else if (sessionHistory.length > 0) {
|
|
42488
42832
|
if (historyIndex === -1) {
|
|
42489
42833
|
tempLine = currentLine;
|
|
42490
42834
|
historyIndex = sessionHistory.length - 1;
|
|
@@ -42510,7 +42854,10 @@ function createInputHandler(_session) {
|
|
|
42510
42854
|
selectedCompletion = currentCol;
|
|
42511
42855
|
}
|
|
42512
42856
|
render();
|
|
42513
|
-
} else if (
|
|
42857
|
+
} else if (cursorPos < currentLine.length) {
|
|
42858
|
+
cursorPos = currentLine.length;
|
|
42859
|
+
render();
|
|
42860
|
+
} else if (historyIndex !== -1) {
|
|
42514
42861
|
if (historyIndex < sessionHistory.length - 1) {
|
|
42515
42862
|
historyIndex++;
|
|
42516
42863
|
currentLine = sessionHistory[historyIndex] ?? "";
|
|
@@ -42655,7 +43002,9 @@ function createSpinner(message) {
|
|
|
42655
43002
|
const elapsed = startTime ? Math.floor((Date.now() - startTime) / 1e3) : 0;
|
|
42656
43003
|
const elapsedStr = elapsed > 0 ? chalk25.dim(` (${elapsed}s)`) : "";
|
|
42657
43004
|
const toolCountStr = formatToolCount();
|
|
42658
|
-
|
|
43005
|
+
const rawMsg = finalMessage || currentMessage;
|
|
43006
|
+
const cleanMsg = rawMsg.replace(/\u2026$|\.\.\.$/, "").trimEnd();
|
|
43007
|
+
spinner19.succeed(`${cleanMsg}${toolCountStr}${elapsedStr}`);
|
|
42659
43008
|
spinner19 = null;
|
|
42660
43009
|
}
|
|
42661
43010
|
startTime = null;
|
|
@@ -44521,7 +44870,13 @@ function formatGitShort(ctx) {
|
|
|
44521
44870
|
return chalk25.dim("\u{1F33F} ") + branch + dirty;
|
|
44522
44871
|
}
|
|
44523
44872
|
init_full_access_mode();
|
|
44524
|
-
function
|
|
44873
|
+
function formatContextUsage(percent) {
|
|
44874
|
+
const label = `ctx ${percent.toFixed(0)}%`;
|
|
44875
|
+
if (percent >= 90) return chalk25.red(label);
|
|
44876
|
+
if (percent >= 75) return chalk25.yellow(label);
|
|
44877
|
+
return chalk25.dim(label);
|
|
44878
|
+
}
|
|
44879
|
+
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
44525
44880
|
const parts = [];
|
|
44526
44881
|
const projectName = path34__default.basename(projectPath);
|
|
44527
44882
|
parts.push(chalk25.dim("\u{1F4C1}") + chalk25.magenta(projectName));
|
|
@@ -44537,10 +44892,13 @@ function formatStatusBar(projectPath, config, gitCtx) {
|
|
|
44537
44892
|
if (gitCtx) {
|
|
44538
44893
|
parts.push(formatGitShort(gitCtx));
|
|
44539
44894
|
}
|
|
44895
|
+
if (contextUsagePercent !== void 0 && contextUsagePercent > 0) {
|
|
44896
|
+
parts.push(formatContextUsage(contextUsagePercent));
|
|
44897
|
+
}
|
|
44540
44898
|
return " " + parts.join(chalk25.dim(" \u2022 "));
|
|
44541
44899
|
}
|
|
44542
|
-
function renderStatusBar(projectPath, config, gitCtx) {
|
|
44543
|
-
const statusLine = formatStatusBar(projectPath, config, gitCtx);
|
|
44900
|
+
function renderStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
44901
|
+
const statusLine = formatStatusBar(projectPath, config, gitCtx, contextUsagePercent);
|
|
44544
44902
|
console.log();
|
|
44545
44903
|
console.log(statusLine);
|
|
44546
44904
|
}
|
|
@@ -44723,6 +45081,8 @@ async function startRepl(options = {}) {
|
|
|
44723
45081
|
}).finally(() => process.exit(0));
|
|
44724
45082
|
};
|
|
44725
45083
|
process.once("SIGTERM", sigtermHandler);
|
|
45084
|
+
let warned75 = false;
|
|
45085
|
+
let warned90 = false;
|
|
44726
45086
|
while (true) {
|
|
44727
45087
|
let autoInput = null;
|
|
44728
45088
|
if (pendingQueuedMessages.length > 0) {
|
|
@@ -44998,7 +45358,8 @@ async function startRepl(options = {}) {
|
|
|
44998
45358
|
},
|
|
44999
45359
|
onToolEnd: (result2) => {
|
|
45000
45360
|
const elapsed = activeSpinner && typeof activeSpinner.getElapsed === "function" ? activeSpinner.getElapsed() : 0;
|
|
45001
|
-
if (elapsed >=
|
|
45361
|
+
if (elapsed >= 3) {
|
|
45362
|
+
inputEcho.clear();
|
|
45002
45363
|
activeSpinner?.stop();
|
|
45003
45364
|
activeSpinner = null;
|
|
45004
45365
|
turnActiveSpinner = null;
|
|
@@ -45050,7 +45411,15 @@ async function startRepl(options = {}) {
|
|
|
45050
45411
|
},
|
|
45051
45412
|
onThinkingEnd: () => {
|
|
45052
45413
|
clearThinkingInterval();
|
|
45053
|
-
|
|
45414
|
+
const thinkingElapsed = activeSpinner?.getElapsed() ?? 0;
|
|
45415
|
+
if (thinkingElapsed >= 2) {
|
|
45416
|
+
inputEcho.clear();
|
|
45417
|
+
activeSpinner?.stop();
|
|
45418
|
+
activeSpinner = null;
|
|
45419
|
+
turnActiveSpinner = null;
|
|
45420
|
+
} else {
|
|
45421
|
+
clearSpinner();
|
|
45422
|
+
}
|
|
45054
45423
|
},
|
|
45055
45424
|
onToolPreparing: (toolName) => {
|
|
45056
45425
|
setSpinner(getToolPreparingDescription(toolName));
|
|
@@ -45153,20 +45522,34 @@ async function startRepl(options = {}) {
|
|
|
45153
45522
|
if (ctx) gitContext = ctx;
|
|
45154
45523
|
}).catch(() => {
|
|
45155
45524
|
});
|
|
45156
|
-
|
|
45525
|
+
const usageBefore = getContextUsagePercent(session);
|
|
45526
|
+
let usageForDisplay = usageBefore;
|
|
45157
45527
|
try {
|
|
45158
|
-
const usageBefore = getContextUsagePercent(session);
|
|
45159
45528
|
const compactionResult = await checkAndCompactContext(session, provider);
|
|
45160
45529
|
if (compactionResult?.wasCompacted) {
|
|
45161
|
-
|
|
45530
|
+
usageForDisplay = getContextUsagePercent(session);
|
|
45162
45531
|
console.log(
|
|
45163
45532
|
chalk25.dim(
|
|
45164
|
-
`Context compacted (${usageBefore.toFixed(0)}% -> ${
|
|
45533
|
+
`Context compacted (${usageBefore.toFixed(0)}% -> ${usageForDisplay.toFixed(0)}%)`
|
|
45165
45534
|
)
|
|
45166
45535
|
);
|
|
45536
|
+
warned75 = false;
|
|
45537
|
+
warned90 = false;
|
|
45167
45538
|
}
|
|
45168
45539
|
} catch {
|
|
45169
45540
|
}
|
|
45541
|
+
renderStatusBar(session.projectPath, session.config, gitContext, usageForDisplay);
|
|
45542
|
+
if (usageForDisplay >= 90 && !warned90) {
|
|
45543
|
+
warned90 = true;
|
|
45544
|
+
console.log(
|
|
45545
|
+
chalk25.red(" \u2717 Context critical (" + usageForDisplay.toFixed(0) + "%) \u2014 use /clear to start fresh")
|
|
45546
|
+
);
|
|
45547
|
+
} else if (usageForDisplay >= 75 && !warned75) {
|
|
45548
|
+
warned75 = true;
|
|
45549
|
+
console.log(
|
|
45550
|
+
chalk25.yellow(" \u26A0 Context at " + usageForDisplay.toFixed(0) + "% \u2014 use /clear to start fresh or /compact to summarize")
|
|
45551
|
+
);
|
|
45552
|
+
}
|
|
45170
45553
|
console.log();
|
|
45171
45554
|
} catch (error) {
|
|
45172
45555
|
clearThinkingInterval();
|