@corbat-tech/coco 1.1.0 → 1.2.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/README.md +159 -173
- package/dist/cli/index.js +231 -141
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +94 -26
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/dist/cli/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from 'os';
|
|
|
4
4
|
import * as path20 from 'path';
|
|
5
5
|
import path20__default, { join, dirname, basename } from 'path';
|
|
6
6
|
import * as fs19 from 'fs';
|
|
7
|
-
import fs19__default, { readFileSync,
|
|
7
|
+
import fs19__default, { readFileSync, constants } from 'fs';
|
|
8
8
|
import * as fs22 from 'fs/promises';
|
|
9
9
|
import fs22__default, { writeFile, access, readFile, mkdir, readdir, rm } from 'fs/promises';
|
|
10
10
|
import { Command } from 'commander';
|
|
@@ -21,6 +21,7 @@ import * as http from 'http';
|
|
|
21
21
|
import { execFile, exec, execSync, execFileSync, spawn } from 'child_process';
|
|
22
22
|
import { promisify } from 'util';
|
|
23
23
|
import { GoogleGenerativeAI, FunctionCallingMode } from '@google/generative-ai';
|
|
24
|
+
import stringWidth from 'string-width';
|
|
24
25
|
import ansiEscapes3 from 'ansi-escapes';
|
|
25
26
|
import * as readline from 'readline';
|
|
26
27
|
import { execa } from 'execa';
|
|
@@ -279,8 +280,8 @@ __export(trust_store_exports, {
|
|
|
279
280
|
saveTrustStore: () => saveTrustStore,
|
|
280
281
|
updateLastAccessed: () => updateLastAccessed
|
|
281
282
|
});
|
|
282
|
-
async function ensureDir(
|
|
283
|
-
await mkdir(dirname(
|
|
283
|
+
async function ensureDir(path36) {
|
|
284
|
+
await mkdir(dirname(path36), { recursive: true });
|
|
284
285
|
}
|
|
285
286
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
286
287
|
try {
|
|
@@ -358,8 +359,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
358
359
|
};
|
|
359
360
|
return permissions[level]?.includes(operation) ?? false;
|
|
360
361
|
}
|
|
361
|
-
function normalizePath(
|
|
362
|
-
return join(
|
|
362
|
+
function normalizePath(path36) {
|
|
363
|
+
return join(path36);
|
|
363
364
|
}
|
|
364
365
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
365
366
|
let store = null;
|
|
@@ -609,8 +610,8 @@ Generated by Corbat-Coco v0.1.0
|
|
|
609
610
|
|
|
610
611
|
// src/cli/commands/init.ts
|
|
611
612
|
function registerInitCommand(program2) {
|
|
612
|
-
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (
|
|
613
|
-
await runInit(
|
|
613
|
+
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (path36, options) => {
|
|
614
|
+
await runInit(path36, options);
|
|
614
615
|
});
|
|
615
616
|
}
|
|
616
617
|
async function runInit(projectPath, options) {
|
|
@@ -689,18 +690,18 @@ async function gatherProjectInfo() {
|
|
|
689
690
|
language
|
|
690
691
|
};
|
|
691
692
|
}
|
|
692
|
-
function getDefaultProjectInfo(
|
|
693
|
-
const name =
|
|
693
|
+
function getDefaultProjectInfo(path36) {
|
|
694
|
+
const name = path36 === "." ? "my-project" : path36.split("/").pop() || "my-project";
|
|
694
695
|
return {
|
|
695
696
|
name,
|
|
696
697
|
description: "",
|
|
697
698
|
language: "typescript"
|
|
698
699
|
};
|
|
699
700
|
}
|
|
700
|
-
async function checkExistingProject(
|
|
701
|
+
async function checkExistingProject(path36) {
|
|
701
702
|
try {
|
|
702
703
|
const fs39 = await import('fs/promises');
|
|
703
|
-
await fs39.access(`${
|
|
704
|
+
await fs39.access(`${path36}/.coco`);
|
|
704
705
|
return true;
|
|
705
706
|
} catch {
|
|
706
707
|
return false;
|
|
@@ -724,9 +725,6 @@ var QualityConfigSchema = z.object({
|
|
|
724
725
|
}).refine((data) => data.minIterations <= data.maxIterations, {
|
|
725
726
|
message: "minIterations must be <= maxIterations",
|
|
726
727
|
path: ["minIterations"]
|
|
727
|
-
}).refine((data) => data.convergenceThreshold < data.minScore, {
|
|
728
|
-
message: "convergenceThreshold must be < minScore",
|
|
729
|
-
path: ["convergenceThreshold"]
|
|
730
728
|
});
|
|
731
729
|
var PersistenceConfigSchema = z.object({
|
|
732
730
|
checkpointInterval: z.number().min(6e4).default(3e5),
|
|
@@ -1072,7 +1070,17 @@ function deepMergeConfig(base, override) {
|
|
|
1072
1070
|
project: { ...base.project, ...override.project },
|
|
1073
1071
|
provider: { ...base.provider, ...override.provider },
|
|
1074
1072
|
quality: { ...base.quality, ...override.quality },
|
|
1075
|
-
persistence: { ...base.persistence, ...override.persistence }
|
|
1073
|
+
persistence: { ...base.persistence, ...override.persistence },
|
|
1074
|
+
// Merge optional sections only if present in either base or override
|
|
1075
|
+
...base.stack || override.stack ? { stack: { ...base.stack, ...override.stack } } : {},
|
|
1076
|
+
...base.integrations || override.integrations ? {
|
|
1077
|
+
integrations: {
|
|
1078
|
+
...base.integrations,
|
|
1079
|
+
...override.integrations
|
|
1080
|
+
}
|
|
1081
|
+
} : {},
|
|
1082
|
+
...base.mcp || override.mcp ? { mcp: { ...base.mcp, ...override.mcp } } : {},
|
|
1083
|
+
...base.tools || override.tools ? { tools: { ...base.tools, ...override.tools } } : {}
|
|
1076
1084
|
};
|
|
1077
1085
|
}
|
|
1078
1086
|
function getProjectConfigPath() {
|
|
@@ -4778,6 +4786,9 @@ var AnthropicProvider = class {
|
|
|
4778
4786
|
try {
|
|
4779
4787
|
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
4780
4788
|
} catch {
|
|
4789
|
+
console.warn(
|
|
4790
|
+
`[Anthropic] Failed to parse tool call arguments: ${currentToolInputJson?.slice(0, 100)}`
|
|
4791
|
+
);
|
|
4781
4792
|
currentToolCall.input = {};
|
|
4782
4793
|
}
|
|
4783
4794
|
yield {
|
|
@@ -5310,6 +5321,9 @@ var OpenAIProvider = class {
|
|
|
5310
5321
|
try {
|
|
5311
5322
|
input = builder.arguments ? JSON.parse(builder.arguments) : {};
|
|
5312
5323
|
} catch {
|
|
5324
|
+
console.warn(
|
|
5325
|
+
`[OpenAI] Failed to parse tool call arguments: ${builder.arguments?.slice(0, 100)}`
|
|
5326
|
+
);
|
|
5313
5327
|
}
|
|
5314
5328
|
yield {
|
|
5315
5329
|
type: "tool_use_end",
|
|
@@ -5598,7 +5612,16 @@ var OpenAIProvider = class {
|
|
|
5598
5612
|
).map((tc) => ({
|
|
5599
5613
|
id: tc.id,
|
|
5600
5614
|
name: tc.function.name,
|
|
5601
|
-
input:
|
|
5615
|
+
input: (() => {
|
|
5616
|
+
try {
|
|
5617
|
+
return JSON.parse(tc.function.arguments || "{}");
|
|
5618
|
+
} catch {
|
|
5619
|
+
console.warn(
|
|
5620
|
+
`[OpenAI] Failed to parse tool call arguments: ${tc.function.arguments?.slice(0, 100)}`
|
|
5621
|
+
);
|
|
5622
|
+
return {};
|
|
5623
|
+
}
|
|
5624
|
+
})()
|
|
5602
5625
|
}));
|
|
5603
5626
|
}
|
|
5604
5627
|
/**
|
|
@@ -7246,7 +7269,10 @@ var GeminiProvider = class {
|
|
|
7246
7269
|
for (const part of candidate.content.parts) {
|
|
7247
7270
|
if ("functionCall" in part && part.functionCall) {
|
|
7248
7271
|
const funcCall = part.functionCall;
|
|
7249
|
-
const
|
|
7272
|
+
const sortedArgs = funcCall.args ? Object.keys(funcCall.args).sort().map(
|
|
7273
|
+
(k) => `${k}:${JSON.stringify(funcCall.args[k])}`
|
|
7274
|
+
).join(",") : "";
|
|
7275
|
+
const callKey = `${funcCall.name}-${sortedArgs}`;
|
|
7250
7276
|
if (!emittedToolCalls.has(callKey)) {
|
|
7251
7277
|
emittedToolCalls.add(callKey);
|
|
7252
7278
|
const toolCall = {
|
|
@@ -7278,9 +7304,18 @@ var GeminiProvider = class {
|
|
|
7278
7304
|
}
|
|
7279
7305
|
/**
|
|
7280
7306
|
* Count tokens (approximate)
|
|
7307
|
+
*
|
|
7308
|
+
* Gemini uses a SentencePiece tokenizer. The average ratio varies:
|
|
7309
|
+
* - English text: ~4 characters per token
|
|
7310
|
+
* - Code: ~3.2 characters per token
|
|
7311
|
+
* - Mixed content: ~3.5 characters per token
|
|
7312
|
+
*
|
|
7313
|
+
* Using 3.5 as the default provides a better estimate for typical
|
|
7314
|
+
* coding agent workloads which mix code and natural language.
|
|
7281
7315
|
*/
|
|
7282
7316
|
countTokens(text9) {
|
|
7283
|
-
|
|
7317
|
+
if (!text9) return 0;
|
|
7318
|
+
return Math.ceil(text9.length / 3.5);
|
|
7284
7319
|
}
|
|
7285
7320
|
/**
|
|
7286
7321
|
* Get context window size
|
|
@@ -7614,20 +7649,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
7614
7649
|
},
|
|
7615
7650
|
tools: {
|
|
7616
7651
|
file: {
|
|
7617
|
-
async read(
|
|
7652
|
+
async read(path36) {
|
|
7618
7653
|
const fs39 = await import('fs/promises');
|
|
7619
|
-
return fs39.readFile(
|
|
7654
|
+
return fs39.readFile(path36, "utf-8");
|
|
7620
7655
|
},
|
|
7621
|
-
async write(
|
|
7656
|
+
async write(path36, content) {
|
|
7622
7657
|
const fs39 = await import('fs/promises');
|
|
7623
7658
|
const nodePath = await import('path');
|
|
7624
|
-
await fs39.mkdir(nodePath.dirname(
|
|
7625
|
-
await fs39.writeFile(
|
|
7659
|
+
await fs39.mkdir(nodePath.dirname(path36), { recursive: true });
|
|
7660
|
+
await fs39.writeFile(path36, content, "utf-8");
|
|
7626
7661
|
},
|
|
7627
|
-
async exists(
|
|
7662
|
+
async exists(path36) {
|
|
7628
7663
|
const fs39 = await import('fs/promises');
|
|
7629
7664
|
try {
|
|
7630
|
-
await fs39.access(
|
|
7665
|
+
await fs39.access(path36);
|
|
7631
7666
|
return true;
|
|
7632
7667
|
} catch {
|
|
7633
7668
|
return false;
|
|
@@ -7980,10 +8015,10 @@ function getPhaseStatusForPhase(phase) {
|
|
|
7980
8015
|
}
|
|
7981
8016
|
async function loadProjectState(cwd, config) {
|
|
7982
8017
|
const fs39 = await import('fs/promises');
|
|
7983
|
-
const
|
|
7984
|
-
const statePath =
|
|
7985
|
-
const backlogPath =
|
|
7986
|
-
const checkpointDir =
|
|
8018
|
+
const path36 = await import('path');
|
|
8019
|
+
const statePath = path36.join(cwd, ".coco", "state.json");
|
|
8020
|
+
const backlogPath = path36.join(cwd, ".coco", "planning", "backlog.json");
|
|
8021
|
+
const checkpointDir = path36.join(cwd, ".coco", "checkpoints");
|
|
7987
8022
|
let currentPhase = "idle";
|
|
7988
8023
|
let metrics;
|
|
7989
8024
|
let sprint;
|
|
@@ -8698,8 +8733,8 @@ async function saveConfig(config) {
|
|
|
8698
8733
|
await fs39.mkdir(".coco", { recursive: true });
|
|
8699
8734
|
await fs39.writeFile(".coco/config.json", JSON.stringify(config, null, 2));
|
|
8700
8735
|
}
|
|
8701
|
-
function getNestedValue(obj,
|
|
8702
|
-
const keys =
|
|
8736
|
+
function getNestedValue(obj, path36) {
|
|
8737
|
+
const keys = path36.split(".");
|
|
8703
8738
|
let current = obj;
|
|
8704
8739
|
for (const key of keys) {
|
|
8705
8740
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -8709,8 +8744,8 @@ function getNestedValue(obj, path37) {
|
|
|
8709
8744
|
}
|
|
8710
8745
|
return current;
|
|
8711
8746
|
}
|
|
8712
|
-
function setNestedValue(obj,
|
|
8713
|
-
const keys =
|
|
8747
|
+
function setNestedValue(obj, path36, value) {
|
|
8748
|
+
const keys = path36.split(".");
|
|
8714
8749
|
let current = obj;
|
|
8715
8750
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
8716
8751
|
const key = keys[i];
|
|
@@ -8931,8 +8966,8 @@ var MCPRegistryImpl = class {
|
|
|
8931
8966
|
/**
|
|
8932
8967
|
* Ensure directory exists
|
|
8933
8968
|
*/
|
|
8934
|
-
async ensureDir(
|
|
8935
|
-
await mkdir(dirname(
|
|
8969
|
+
async ensureDir(path36) {
|
|
8970
|
+
await mkdir(dirname(path36), { recursive: true });
|
|
8936
8971
|
}
|
|
8937
8972
|
};
|
|
8938
8973
|
function createMCPRegistry(registryPath) {
|
|
@@ -9451,9 +9486,9 @@ function createEmptyMemoryContext() {
|
|
|
9451
9486
|
errors: []
|
|
9452
9487
|
};
|
|
9453
9488
|
}
|
|
9454
|
-
function createMissingMemoryFile(
|
|
9489
|
+
function createMissingMemoryFile(path36, level) {
|
|
9455
9490
|
return {
|
|
9456
|
-
path:
|
|
9491
|
+
path: path36,
|
|
9457
9492
|
level,
|
|
9458
9493
|
content: "",
|
|
9459
9494
|
sections: [],
|
|
@@ -9658,7 +9693,9 @@ async function saveTrustSettings(settings) {
|
|
|
9658
9693
|
await fs22__default.mkdir(TRUST_SETTINGS_DIR, { recursive: true });
|
|
9659
9694
|
settings.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9660
9695
|
await fs22__default.writeFile(TRUST_SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
|
|
9661
|
-
} catch {
|
|
9696
|
+
} catch (error) {
|
|
9697
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
9698
|
+
console.warn(`[Trust] Failed to save trust settings: ${msg}`);
|
|
9662
9699
|
}
|
|
9663
9700
|
}
|
|
9664
9701
|
async function loadTrustedTools(projectPath) {
|
|
@@ -12142,8 +12179,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
12142
12179
|
p9.log.message("");
|
|
12143
12180
|
for (const project of projects) {
|
|
12144
12181
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
12145
|
-
const
|
|
12146
|
-
p9.log.message(` [${level}] ${
|
|
12182
|
+
const path36 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
12183
|
+
p9.log.message(` [${level}] ${path36}`);
|
|
12147
12184
|
p9.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
12148
12185
|
}
|
|
12149
12186
|
p9.log.message("");
|
|
@@ -13403,8 +13440,8 @@ function displayRewindResult(result) {
|
|
|
13403
13440
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
13404
13441
|
console.log(`${chalk12.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
13405
13442
|
}
|
|
13406
|
-
for (const { path:
|
|
13407
|
-
const fileName =
|
|
13443
|
+
for (const { path: path36, error } of result.filesFailed) {
|
|
13444
|
+
const fileName = path36.split("/").pop() ?? path36;
|
|
13408
13445
|
console.log(`${chalk12.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
13409
13446
|
}
|
|
13410
13447
|
if (result.conversationRestored) {
|
|
@@ -14369,7 +14406,11 @@ function flushLineBuffer() {
|
|
|
14369
14406
|
}
|
|
14370
14407
|
if (inCodeBlock && codeBlockLines.length > 0) {
|
|
14371
14408
|
stopStreamingIndicator();
|
|
14372
|
-
|
|
14409
|
+
try {
|
|
14410
|
+
renderCodeBlock(codeBlockLang, codeBlockLines);
|
|
14411
|
+
} finally {
|
|
14412
|
+
stopStreamingIndicator();
|
|
14413
|
+
}
|
|
14373
14414
|
inCodeBlock = false;
|
|
14374
14415
|
codeBlockLang = "";
|
|
14375
14416
|
codeBlockLines = [];
|
|
@@ -14725,6 +14766,7 @@ function formatInlineMarkdown(text9) {
|
|
|
14725
14766
|
return text9;
|
|
14726
14767
|
}
|
|
14727
14768
|
function wrapText(text9, maxWidth) {
|
|
14769
|
+
if (maxWidth <= 0) return [text9];
|
|
14728
14770
|
const plainText = stripAnsi(text9);
|
|
14729
14771
|
if (plainText.length <= maxWidth) {
|
|
14730
14772
|
return [text9];
|
|
@@ -14732,14 +14774,37 @@ function wrapText(text9, maxWidth) {
|
|
|
14732
14774
|
const lines = [];
|
|
14733
14775
|
let remaining = text9;
|
|
14734
14776
|
while (stripAnsi(remaining).length > maxWidth) {
|
|
14735
|
-
let breakPoint = maxWidth;
|
|
14736
14777
|
const plain = stripAnsi(remaining);
|
|
14778
|
+
let breakPoint = maxWidth;
|
|
14737
14779
|
const lastSpace = plain.lastIndexOf(" ", maxWidth);
|
|
14738
14780
|
if (lastSpace > maxWidth * 0.5) {
|
|
14739
14781
|
breakPoint = lastSpace;
|
|
14740
14782
|
}
|
|
14741
|
-
|
|
14742
|
-
|
|
14783
|
+
const ansiRegex = /\x1b\[[0-9;]*m/g;
|
|
14784
|
+
let match;
|
|
14785
|
+
const ansiPositions = [];
|
|
14786
|
+
ansiRegex.lastIndex = 0;
|
|
14787
|
+
while ((match = ansiRegex.exec(remaining)) !== null) {
|
|
14788
|
+
ansiPositions.push({ start: match.index, end: match.index + match[0].length });
|
|
14789
|
+
}
|
|
14790
|
+
let rawPos = 0;
|
|
14791
|
+
let visualPos = 0;
|
|
14792
|
+
let ansiIdx = 0;
|
|
14793
|
+
while (visualPos < breakPoint && rawPos < remaining.length) {
|
|
14794
|
+
while (ansiIdx < ansiPositions.length && ansiPositions[ansiIdx].start === rawPos) {
|
|
14795
|
+
rawPos = ansiPositions[ansiIdx].end;
|
|
14796
|
+
ansiIdx++;
|
|
14797
|
+
}
|
|
14798
|
+
if (rawPos >= remaining.length) break;
|
|
14799
|
+
rawPos++;
|
|
14800
|
+
visualPos++;
|
|
14801
|
+
}
|
|
14802
|
+
while (ansiIdx < ansiPositions.length && ansiPositions[ansiIdx].start === rawPos) {
|
|
14803
|
+
rawPos = ansiPositions[ansiIdx].end;
|
|
14804
|
+
ansiIdx++;
|
|
14805
|
+
}
|
|
14806
|
+
lines.push(remaining.slice(0, rawPos));
|
|
14807
|
+
remaining = remaining.slice(rawPos).trimStart();
|
|
14743
14808
|
}
|
|
14744
14809
|
if (remaining) {
|
|
14745
14810
|
lines.push(remaining);
|
|
@@ -14809,8 +14874,8 @@ function formatToolSummary(toolName, input) {
|
|
|
14809
14874
|
return String(input.path || ".");
|
|
14810
14875
|
case "search_files": {
|
|
14811
14876
|
const pattern = String(input.pattern || "");
|
|
14812
|
-
const
|
|
14813
|
-
return `"${pattern}"${
|
|
14877
|
+
const path36 = input.path ? ` in ${input.path}` : "";
|
|
14878
|
+
return `"${pattern}"${path36}`;
|
|
14814
14879
|
}
|
|
14815
14880
|
case "bash_exec": {
|
|
14816
14881
|
const cmd = String(input.command || "");
|
|
@@ -16188,6 +16253,9 @@ function createInputHandler(_session) {
|
|
|
16188
16253
|
let historyIndex = -1;
|
|
16189
16254
|
let tempLine = "";
|
|
16190
16255
|
let lastMenuLines = 0;
|
|
16256
|
+
let lastCursorRow = 0;
|
|
16257
|
+
let lastContentRows = 1;
|
|
16258
|
+
let isFirstRender = true;
|
|
16191
16259
|
let isPasting = false;
|
|
16192
16260
|
let pasteBuffer = "";
|
|
16193
16261
|
let isReadingClipboard = false;
|
|
@@ -16219,11 +16287,13 @@ function createInputHandler(_session) {
|
|
|
16219
16287
|
function render() {
|
|
16220
16288
|
const termCols = process.stdout.columns || 80;
|
|
16221
16289
|
const prompt = getPrompt();
|
|
16222
|
-
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16290
|
+
if (!isFirstRender) {
|
|
16291
|
+
const linesToGoUp = lastCursorRow + 1;
|
|
16292
|
+
if (linesToGoUp > 0) {
|
|
16293
|
+
process.stdout.write(ansiEscapes3.cursorUp(linesToGoUp));
|
|
16294
|
+
}
|
|
16226
16295
|
}
|
|
16296
|
+
isFirstRender = false;
|
|
16227
16297
|
process.stdout.write("\r" + ansiEscapes3.eraseDown);
|
|
16228
16298
|
const separator = chalk12.dim("\u2500".repeat(termCols));
|
|
16229
16299
|
let output = separator + "\n";
|
|
@@ -16236,7 +16306,12 @@ function createInputHandler(_session) {
|
|
|
16236
16306
|
output += chalk12.dim.gray(ghost);
|
|
16237
16307
|
}
|
|
16238
16308
|
}
|
|
16309
|
+
const totalContentLen = prompt.visualLen + currentLine.length;
|
|
16310
|
+
const contentRows = totalContentLen === 0 ? 1 : Math.ceil(totalContentLen / termCols);
|
|
16311
|
+
const contentExactFill = totalContentLen > 0 && totalContentLen % termCols === 0;
|
|
16312
|
+
output += (contentExactFill ? "" : "\n") + separator;
|
|
16239
16313
|
const showMenu = completions.length > 0 && currentLine.startsWith("/") && currentLine.length >= 1;
|
|
16314
|
+
let extraLinesBelow = 0;
|
|
16240
16315
|
if (showMenu) {
|
|
16241
16316
|
const cols = getColumnCount();
|
|
16242
16317
|
const maxVisibleItems = MAX_ROWS * cols;
|
|
@@ -16255,9 +16330,11 @@ function createInputHandler(_session) {
|
|
|
16255
16330
|
output += "\n";
|
|
16256
16331
|
output += chalk12.dim(` \u2191 ${startIndex} more above`);
|
|
16257
16332
|
lastMenuLines++;
|
|
16333
|
+
extraLinesBelow++;
|
|
16258
16334
|
}
|
|
16259
16335
|
for (let row = 0; row < rowCount; row++) {
|
|
16260
16336
|
output += "\n";
|
|
16337
|
+
extraLinesBelow++;
|
|
16261
16338
|
for (let col = 0; col < cols; col++) {
|
|
16262
16339
|
const itemIndex = row * cols + col;
|
|
16263
16340
|
if (itemIndex >= visibleItems.length) break;
|
|
@@ -16276,22 +16353,22 @@ function createInputHandler(_session) {
|
|
|
16276
16353
|
output += "\n";
|
|
16277
16354
|
output += chalk12.dim(` \u2193 ${completions.length - endIndex} more below`);
|
|
16278
16355
|
lastMenuLines++;
|
|
16356
|
+
extraLinesBelow++;
|
|
16279
16357
|
}
|
|
16280
|
-
for (let i = 0; i < BOTTOM_MARGIN; i++) {
|
|
16281
|
-
output += "\n";
|
|
16282
|
-
}
|
|
16283
|
-
output += ansiEscapes3.cursorUp(lastMenuLines + BOTTOM_MARGIN + 1);
|
|
16284
16358
|
} else {
|
|
16285
16359
|
lastMenuLines = 0;
|
|
16286
|
-
for (let i = 0; i < BOTTOM_MARGIN; i++) {
|
|
16287
|
-
output += "\n";
|
|
16288
|
-
}
|
|
16289
|
-
output += ansiEscapes3.cursorUp(BOTTOM_MARGIN + 1);
|
|
16290
16360
|
}
|
|
16361
|
+
for (let i = 0; i < BOTTOM_MARGIN; i++) {
|
|
16362
|
+
output += "\n";
|
|
16363
|
+
extraLinesBelow++;
|
|
16364
|
+
}
|
|
16365
|
+
const totalUp = extraLinesBelow + 1 + contentRows;
|
|
16366
|
+
output += ansiEscapes3.cursorUp(totalUp);
|
|
16291
16367
|
output += ansiEscapes3.cursorDown(1);
|
|
16292
16368
|
const cursorAbsolutePos = prompt.visualLen + cursorPos;
|
|
16293
|
-
const
|
|
16294
|
-
const
|
|
16369
|
+
const onExactBoundary = cursorAbsolutePos > 0 && cursorAbsolutePos % termCols === 0;
|
|
16370
|
+
const finalLine = onExactBoundary ? cursorAbsolutePos / termCols - 1 : Math.floor(cursorAbsolutePos / termCols);
|
|
16371
|
+
const finalCol = onExactBoundary ? 0 : cursorAbsolutePos % termCols;
|
|
16295
16372
|
output += "\r";
|
|
16296
16373
|
if (finalLine > 0) {
|
|
16297
16374
|
output += ansiEscapes3.cursorDown(finalLine);
|
|
@@ -16299,10 +16376,16 @@ function createInputHandler(_session) {
|
|
|
16299
16376
|
if (finalCol > 0) {
|
|
16300
16377
|
output += ansiEscapes3.cursorForward(finalCol);
|
|
16301
16378
|
}
|
|
16379
|
+
lastCursorRow = finalLine;
|
|
16380
|
+
lastContentRows = contentRows;
|
|
16302
16381
|
process.stdout.write(output);
|
|
16303
16382
|
}
|
|
16304
16383
|
function clearMenu() {
|
|
16305
|
-
|
|
16384
|
+
const rowsDown = lastContentRows - lastCursorRow + 1;
|
|
16385
|
+
if (rowsDown > 0) {
|
|
16386
|
+
process.stdout.write(ansiEscapes3.cursorDown(rowsDown));
|
|
16387
|
+
}
|
|
16388
|
+
process.stdout.write("\r" + ansiEscapes3.eraseDown);
|
|
16306
16389
|
lastMenuLines = 0;
|
|
16307
16390
|
}
|
|
16308
16391
|
function insertTextAtCursor(text9) {
|
|
@@ -16325,15 +16408,21 @@ function createInputHandler(_session) {
|
|
|
16325
16408
|
historyIndex = -1;
|
|
16326
16409
|
tempLine = "";
|
|
16327
16410
|
lastMenuLines = 0;
|
|
16411
|
+
lastCursorRow = 0;
|
|
16412
|
+
lastContentRows = 1;
|
|
16413
|
+
isFirstRender = true;
|
|
16328
16414
|
render();
|
|
16329
16415
|
if (process.stdin.isTTY) {
|
|
16330
16416
|
process.stdin.setRawMode(true);
|
|
16331
16417
|
}
|
|
16332
16418
|
process.stdin.resume();
|
|
16333
16419
|
process.stdout.write("\x1B[?2004h");
|
|
16420
|
+
const onResize = () => render();
|
|
16421
|
+
process.stdout.on("resize", onResize);
|
|
16334
16422
|
const cleanup = () => {
|
|
16335
16423
|
process.stdout.write("\x1B[?2004l");
|
|
16336
16424
|
process.stdin.removeListener("data", onData);
|
|
16425
|
+
process.stdout.removeListener("resize", onResize);
|
|
16337
16426
|
if (process.stdin.isTTY) {
|
|
16338
16427
|
process.stdin.setRawMode(false);
|
|
16339
16428
|
}
|
|
@@ -16463,9 +16552,7 @@ function createInputHandler(_session) {
|
|
|
16463
16552
|
currentLine = completions[selectedCompletion].cmd;
|
|
16464
16553
|
}
|
|
16465
16554
|
cleanup();
|
|
16466
|
-
const termWidth = process.stdout.columns || 80;
|
|
16467
16555
|
console.log();
|
|
16468
|
-
console.log(chalk12.dim("\u2500".repeat(termWidth)));
|
|
16469
16556
|
const result = currentLine.trim();
|
|
16470
16557
|
if (result) {
|
|
16471
16558
|
sessionHistory.push(result);
|
|
@@ -17504,7 +17591,8 @@ async function promptEditCommand(originalCommand) {
|
|
|
17504
17591
|
console.log();
|
|
17505
17592
|
console.log(chalk12.dim(" Edit command (or press Enter to cancel):"));
|
|
17506
17593
|
console.log(chalk12.cyan(` Current: ${originalCommand}`));
|
|
17507
|
-
|
|
17594
|
+
const wasRaw = process.stdin.isTTY ? process.stdin.isRaw : false;
|
|
17595
|
+
if (process.stdin.isTTY && wasRaw) {
|
|
17508
17596
|
process.stdin.setRawMode(false);
|
|
17509
17597
|
}
|
|
17510
17598
|
const rl = readline2.createInterface({
|
|
@@ -17517,6 +17605,9 @@ async function promptEditCommand(originalCommand) {
|
|
|
17517
17605
|
return trimmed || null;
|
|
17518
17606
|
} finally {
|
|
17519
17607
|
rl.close();
|
|
17608
|
+
if (process.stdin.isTTY && wasRaw) {
|
|
17609
|
+
process.stdin.setRawMode(true);
|
|
17610
|
+
}
|
|
17520
17611
|
}
|
|
17521
17612
|
}
|
|
17522
17613
|
async function confirmToolExecution(toolCall) {
|
|
@@ -20228,10 +20319,10 @@ var CoverageAnalyzer = class {
|
|
|
20228
20319
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
20229
20320
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
20230
20321
|
];
|
|
20231
|
-
for (const
|
|
20322
|
+
for (const path36 of possiblePaths) {
|
|
20232
20323
|
try {
|
|
20233
|
-
await access(
|
|
20234
|
-
const content = await readFile(
|
|
20324
|
+
await access(path36, constants.R_OK);
|
|
20325
|
+
const content = await readFile(path36, "utf-8");
|
|
20235
20326
|
const report = JSON.parse(content);
|
|
20236
20327
|
return parseCoverageSummary(report);
|
|
20237
20328
|
} catch {
|
|
@@ -22452,17 +22543,17 @@ var QualityEvaluator = class {
|
|
|
22452
22543
|
maintainabilityResult
|
|
22453
22544
|
] = await Promise.all([
|
|
22454
22545
|
this.coverageAnalyzer.analyze().catch(() => null),
|
|
22455
|
-
this.securityScanner.scan(fileContents),
|
|
22456
|
-
this.complexityAnalyzer.analyze(targetFiles),
|
|
22457
|
-
this.duplicationAnalyzer.analyze(targetFiles),
|
|
22546
|
+
this.securityScanner.scan(fileContents).catch(() => ({ score: 0, vulnerabilities: [] })),
|
|
22547
|
+
this.complexityAnalyzer.analyze(targetFiles).catch(() => ({ score: 0, files: [] })),
|
|
22548
|
+
this.duplicationAnalyzer.analyze(targetFiles).catch(() => ({ score: 0, percentage: 0 })),
|
|
22458
22549
|
this.correctnessAnalyzer.analyze().catch(() => ({ score: 0 })),
|
|
22459
22550
|
this.completenessAnalyzer.analyze(targetFiles).catch(() => ({ score: 0 })),
|
|
22460
22551
|
this.robustnessAnalyzer.analyze(targetFiles).catch(() => ({ score: 0 })),
|
|
22461
22552
|
this.testQualityAnalyzer.analyze().catch(() => ({ score: 0 })),
|
|
22462
22553
|
this.documentationAnalyzer.analyze(targetFiles).catch(() => ({ score: 0 })),
|
|
22463
|
-
this.styleAnalyzer.analyze().catch(() => ({ score:
|
|
22464
|
-
this.readabilityAnalyzer.analyze(targetFiles).catch(() => ({ score:
|
|
22465
|
-
this.maintainabilityAnalyzer.analyze(targetFiles).catch(() => ({ score:
|
|
22554
|
+
this.styleAnalyzer.analyze().catch(() => ({ score: 0 })),
|
|
22555
|
+
this.readabilityAnalyzer.analyze(targetFiles).catch(() => ({ score: 0 })),
|
|
22556
|
+
this.maintainabilityAnalyzer.analyze(targetFiles).catch(() => ({ score: 0 }))
|
|
22466
22557
|
]);
|
|
22467
22558
|
const dimensions = {
|
|
22468
22559
|
testCoverage: coverageResult?.lines.percentage ?? 0,
|
|
@@ -22976,7 +23067,17 @@ Examples:
|
|
|
22976
23067
|
regexPattern = `\\b${pattern}\\b`;
|
|
22977
23068
|
}
|
|
22978
23069
|
const flags = caseSensitive ? "g" : "gi";
|
|
22979
|
-
|
|
23070
|
+
let regex;
|
|
23071
|
+
try {
|
|
23072
|
+
regex = new RegExp(regexPattern, flags);
|
|
23073
|
+
} catch {
|
|
23074
|
+
throw new ToolError(`Invalid regex pattern: ${pattern}`, { tool: "grep" });
|
|
23075
|
+
}
|
|
23076
|
+
if (/(\.\*|\.\+|\[.*\][*+])\s*(\.\*|\.\+|\[.*\][*+])/.test(regexPattern)) {
|
|
23077
|
+
throw new ToolError(`Regex pattern rejected: nested quantifiers may cause slow matching`, {
|
|
23078
|
+
tool: "grep"
|
|
23079
|
+
});
|
|
23080
|
+
}
|
|
22980
23081
|
const stats = await fs22__default.stat(targetPath);
|
|
22981
23082
|
let filesToSearch;
|
|
22982
23083
|
if (stats.isFile()) {
|
|
@@ -24114,9 +24215,11 @@ function parseDiff(raw) {
|
|
|
24114
24215
|
function parseFileBlock(lines, start) {
|
|
24115
24216
|
const diffLine = lines[start];
|
|
24116
24217
|
let i = start + 1;
|
|
24117
|
-
const
|
|
24118
|
-
const
|
|
24119
|
-
const
|
|
24218
|
+
const gitPrefix = "diff --git a/";
|
|
24219
|
+
const pathPart = diffLine.slice(gitPrefix.length);
|
|
24220
|
+
const lastBSlash = pathPart.lastIndexOf(" b/");
|
|
24221
|
+
const oldPath = lastBSlash >= 0 ? pathPart.slice(0, lastBSlash) : pathPart;
|
|
24222
|
+
const newPath = lastBSlash >= 0 ? pathPart.slice(lastBSlash + 3) : oldPath;
|
|
24120
24223
|
let fileType = "modified";
|
|
24121
24224
|
while (i < lines.length && !lines[i].startsWith("diff --git ")) {
|
|
24122
24225
|
const current = lines[i];
|
|
@@ -24262,7 +24365,7 @@ function renderDiff(diff, options) {
|
|
|
24262
24365
|
function renderFileBlock(file, opts) {
|
|
24263
24366
|
const { maxWidth, showLineNumbers, compact } = opts;
|
|
24264
24367
|
const lang = detectLanguage(file.path);
|
|
24265
|
-
const contentWidth = maxWidth - 4;
|
|
24368
|
+
const contentWidth = Math.max(1, maxWidth - 4);
|
|
24266
24369
|
const typeLabel = file.type === "modified" ? "modified" : file.type === "added" ? "new file" : file.type === "deleted" ? "deleted" : `renamed from ${file.oldPath}`;
|
|
24267
24370
|
const statsLabel = ` +${file.additions} -${file.deletions}`;
|
|
24268
24371
|
const title = ` ${file.path} (${typeLabel}${statsLabel}) `;
|
|
@@ -24309,12 +24412,8 @@ function renderFileBlock(file, opts) {
|
|
|
24309
24412
|
}
|
|
24310
24413
|
function formatLineNo(line, show) {
|
|
24311
24414
|
if (!show) return "";
|
|
24312
|
-
|
|
24313
|
-
|
|
24314
|
-
} else if (line.type === "delete") {
|
|
24315
|
-
return chalk12.dim(`${String(line.oldLineNo ?? "").padStart(4)} `);
|
|
24316
|
-
}
|
|
24317
|
-
return chalk12.dim(`${String(line.newLineNo ?? "").padStart(4)} `);
|
|
24415
|
+
const lineNo = line.type === "delete" ? line.oldLineNo : line.newLineNo;
|
|
24416
|
+
return chalk12.dim(`${String(lineNo ?? "").padStart(5)} `);
|
|
24318
24417
|
}
|
|
24319
24418
|
function getChangedLines(diff) {
|
|
24320
24419
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -24405,9 +24504,9 @@ Examples:
|
|
|
24405
24504
|
}
|
|
24406
24505
|
});
|
|
24407
24506
|
var diffTools = [showDiffTool];
|
|
24408
|
-
async function fileExists(
|
|
24507
|
+
async function fileExists(path36) {
|
|
24409
24508
|
try {
|
|
24410
|
-
await access(
|
|
24509
|
+
await access(path36);
|
|
24411
24510
|
return true;
|
|
24412
24511
|
} catch {
|
|
24413
24512
|
return false;
|
|
@@ -26471,6 +26570,13 @@ Examples:
|
|
|
26471
26570
|
const startTime = performance.now();
|
|
26472
26571
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
26473
26572
|
const absPath = path31.resolve(filePath);
|
|
26573
|
+
const cwd = process.cwd();
|
|
26574
|
+
if (!absPath.startsWith(cwd + path31.sep) && absPath !== cwd) {
|
|
26575
|
+
throw new ToolError(
|
|
26576
|
+
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
26577
|
+
{ tool: "read_image" }
|
|
26578
|
+
);
|
|
26579
|
+
}
|
|
26474
26580
|
const ext = path31.extname(absPath).toLowerCase();
|
|
26475
26581
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
26476
26582
|
throw new ToolError(
|
|
@@ -28531,24 +28637,6 @@ var pc = chalk12;
|
|
|
28531
28637
|
});
|
|
28532
28638
|
|
|
28533
28639
|
// src/cli/repl/index.ts
|
|
28534
|
-
function visualWidth(str) {
|
|
28535
|
-
const stripped = str.replace(/\x1b\[[0-9;]*m/g, "");
|
|
28536
|
-
let width = 0;
|
|
28537
|
-
for (const char of stripped) {
|
|
28538
|
-
const cp = char.codePointAt(0) || 0;
|
|
28539
|
-
if (cp > 128512 || cp >= 9728 && cp <= 10175 || cp >= 127744 && cp <= 129750 || cp >= 129280 && cp <= 129535 || cp >= 9986 && cp <= 10160 || cp >= 65024 && cp <= 65039 || cp === 8205) {
|
|
28540
|
-
width += 2;
|
|
28541
|
-
} else if (
|
|
28542
|
-
// CJK Unified Ideographs and other wide characters
|
|
28543
|
-
cp >= 4352 && cp <= 4447 || cp >= 11904 && cp <= 12350 || cp >= 12352 && cp <= 13247 || cp >= 19968 && cp <= 40959 || cp >= 63744 && cp <= 64255 || cp >= 65072 && cp <= 65135 || cp >= 65281 && cp <= 65376 || cp >= 65504 && cp <= 65510
|
|
28544
|
-
) {
|
|
28545
|
-
width += 2;
|
|
28546
|
-
} else {
|
|
28547
|
-
width += 1;
|
|
28548
|
-
}
|
|
28549
|
-
}
|
|
28550
|
-
return width;
|
|
28551
|
-
}
|
|
28552
28640
|
async function startRepl(options = {}) {
|
|
28553
28641
|
const projectPath = options.projectPath ?? process.cwd();
|
|
28554
28642
|
const session = createSession(projectPath, options.config);
|
|
@@ -28598,6 +28686,17 @@ async function startRepl(options = {}) {
|
|
|
28598
28686
|
const inputHandler = createInputHandler();
|
|
28599
28687
|
const intentRecognizer = createIntentRecognizer();
|
|
28600
28688
|
await printWelcome(session);
|
|
28689
|
+
const cleanupTerminal = () => {
|
|
28690
|
+
process.stdout.write("\x1B[?2004l");
|
|
28691
|
+
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
28692
|
+
process.stdin.setRawMode(false);
|
|
28693
|
+
}
|
|
28694
|
+
};
|
|
28695
|
+
process.on("exit", cleanupTerminal);
|
|
28696
|
+
process.on("SIGTERM", () => {
|
|
28697
|
+
cleanupTerminal();
|
|
28698
|
+
process.exit(0);
|
|
28699
|
+
});
|
|
28601
28700
|
while (true) {
|
|
28602
28701
|
const input = await inputHandler.prompt();
|
|
28603
28702
|
if (input === null && !hasPendingImage()) {
|
|
@@ -28677,6 +28776,14 @@ async function startRepl(options = {}) {
|
|
|
28677
28776
|
activeSpinner.start();
|
|
28678
28777
|
}
|
|
28679
28778
|
};
|
|
28779
|
+
const abortController = new AbortController();
|
|
28780
|
+
let wasAborted = false;
|
|
28781
|
+
const sigintHandler = () => {
|
|
28782
|
+
wasAborted = true;
|
|
28783
|
+
abortController.abort();
|
|
28784
|
+
clearSpinner();
|
|
28785
|
+
renderInfo("\nOperation cancelled");
|
|
28786
|
+
};
|
|
28680
28787
|
try {
|
|
28681
28788
|
if (typeof agentMessage === "string" && !isCocoMode() && !wasHintShown() && looksLikeFeatureRequest(agentMessage)) {
|
|
28682
28789
|
markHintShown();
|
|
@@ -28689,14 +28796,6 @@ async function startRepl(options = {}) {
|
|
|
28689
28796
|
session.config.agent.systemPrompt = originalSystemPrompt + "\n" + getCocoModeSystemPrompt();
|
|
28690
28797
|
}
|
|
28691
28798
|
inputHandler.pause();
|
|
28692
|
-
const abortController = new AbortController();
|
|
28693
|
-
let wasAborted = false;
|
|
28694
|
-
const sigintHandler = () => {
|
|
28695
|
-
wasAborted = true;
|
|
28696
|
-
abortController.abort();
|
|
28697
|
-
clearSpinner();
|
|
28698
|
-
renderInfo("\nOperation cancelled");
|
|
28699
|
-
};
|
|
28700
28799
|
process.once("SIGINT", sigintHandler);
|
|
28701
28800
|
const result = await executeAgentTurn(session, agentMessage, provider, toolRegistry, {
|
|
28702
28801
|
onStream: renderStreamChunk,
|
|
@@ -28785,6 +28884,7 @@ async function startRepl(options = {}) {
|
|
|
28785
28884
|
console.log();
|
|
28786
28885
|
} catch (error) {
|
|
28787
28886
|
clearSpinner();
|
|
28887
|
+
process.off("SIGINT", sigintHandler);
|
|
28788
28888
|
if (error instanceof Error && error.name === "AbortError") {
|
|
28789
28889
|
continue;
|
|
28790
28890
|
}
|
|
@@ -28815,40 +28915,30 @@ async function startRepl(options = {}) {
|
|
|
28815
28915
|
inputHandler.close();
|
|
28816
28916
|
}
|
|
28817
28917
|
async function printWelcome(session) {
|
|
28818
|
-
const providerType = session.config.provider.type;
|
|
28819
|
-
const model = session.config.provider.model || "default";
|
|
28820
|
-
const isReturningUser = existsSync(path20__default.join(session.projectPath, ".coco"));
|
|
28821
|
-
if (isReturningUser) {
|
|
28822
|
-
const versionStr = chalk12.dim(`v${VERSION}`);
|
|
28823
|
-
const providerStr = chalk12.dim(`${providerType}/${model}`);
|
|
28824
|
-
console.log(
|
|
28825
|
-
`
|
|
28826
|
-
\u{1F965} Coco ${versionStr} ${chalk12.dim("\u2502")} ${providerStr} ${chalk12.dim("\u2502")} ${chalk12.yellow("/help")}
|
|
28827
|
-
`
|
|
28828
|
-
);
|
|
28829
|
-
return;
|
|
28830
|
-
}
|
|
28831
28918
|
const trustStore = createTrustStore();
|
|
28832
28919
|
await trustStore.init();
|
|
28833
28920
|
const trustLevel = trustStore.getLevel(session.projectPath);
|
|
28834
28921
|
const boxWidth = 41;
|
|
28835
|
-
const innerWidth = boxWidth -
|
|
28836
|
-
const titleContent = "\u{1F965} CORBAT-COCO";
|
|
28922
|
+
const innerWidth = boxWidth - 2;
|
|
28837
28923
|
const versionText = `v${VERSION}`;
|
|
28838
|
-
const titleContentVisualWidth = visualWidth(titleContent);
|
|
28839
|
-
const versionVisualWidth = visualWidth(versionText);
|
|
28840
|
-
const titlePadding = innerWidth - titleContentVisualWidth - versionVisualWidth;
|
|
28841
28924
|
const subtitleText = "open source \u2022 corbat.tech";
|
|
28842
|
-
const
|
|
28843
|
-
|
|
28925
|
+
const boxLine = (content) => {
|
|
28926
|
+
const pad = Math.max(0, innerWidth - stringWidth(content));
|
|
28927
|
+
return chalk12.magenta("\u2502") + content + " ".repeat(pad) + chalk12.magenta("\u2502");
|
|
28928
|
+
};
|
|
28929
|
+
const titleLeftRaw = " COCO";
|
|
28930
|
+
const titleRightRaw = versionText + " ";
|
|
28931
|
+
const titleLeftStyled = " " + chalk12.bold.white("COCO");
|
|
28932
|
+
const titleGap = Math.max(1, innerWidth - stringWidth(titleLeftRaw) - stringWidth(titleRightRaw));
|
|
28933
|
+
const titleContent = titleLeftStyled + " ".repeat(titleGap) + chalk12.dim(titleRightRaw);
|
|
28934
|
+
const taglineText = "code that converges to quality";
|
|
28935
|
+
const taglineContent = " " + chalk12.magenta(taglineText) + " ";
|
|
28936
|
+
const subtitleContent = " " + chalk12.dim(subtitleText) + " ";
|
|
28844
28937
|
console.log();
|
|
28845
28938
|
console.log(chalk12.magenta(" \u256D" + "\u2500".repeat(boxWidth - 2) + "\u256E"));
|
|
28846
|
-
console.log(
|
|
28847
|
-
|
|
28848
|
-
);
|
|
28849
|
-
console.log(
|
|
28850
|
-
chalk12.magenta(" \u2502 ") + chalk12.dim(subtitleText) + " ".repeat(Math.max(0, subtitlePadding)) + chalk12.magenta(" \u2502")
|
|
28851
|
-
);
|
|
28939
|
+
console.log(" " + boxLine(titleContent));
|
|
28940
|
+
console.log(" " + boxLine(taglineContent));
|
|
28941
|
+
console.log(" " + boxLine(subtitleContent));
|
|
28852
28942
|
console.log(chalk12.magenta(" \u2570" + "\u2500".repeat(boxWidth - 2) + "\u256F"));
|
|
28853
28943
|
const updateInfo = await checkForUpdates();
|
|
28854
28944
|
if (updateInfo) {
|
|
@@ -28889,7 +28979,7 @@ async function checkProjectTrust(projectPath) {
|
|
|
28889
28979
|
return true;
|
|
28890
28980
|
}
|
|
28891
28981
|
console.log();
|
|
28892
|
-
console.log(chalk12.cyan.bold(" \u{1F965}
|
|
28982
|
+
console.log(chalk12.cyan.bold(" \u{1F965} Coco") + chalk12.dim(` v${VERSION}`));
|
|
28893
28983
|
console.log(chalk12.dim(` \u{1F4C1} ${projectPath}`));
|
|
28894
28984
|
console.log();
|
|
28895
28985
|
console.log(chalk12.yellow(" \u26A0 First time accessing this directory"));
|