@corbat-tech/coco 1.2.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/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, existsSync, constants } from 'fs';
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(path37) {
283
- await mkdir(dirname(path37), { recursive: true });
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(path37) {
362
- return join(path37);
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 (path37, options) => {
613
- await runInit(path37, options);
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(path37) {
693
- const name = path37 === "." ? "my-project" : path37.split("/").pop() || "my-project";
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(path37) {
701
+ async function checkExistingProject(path36) {
701
702
  try {
702
703
  const fs39 = await import('fs/promises');
703
- await fs39.access(`${path37}/.coco`);
704
+ await fs39.access(`${path36}/.coco`);
704
705
  return true;
705
706
  } catch {
706
707
  return false;
@@ -7648,20 +7649,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
7648
7649
  },
7649
7650
  tools: {
7650
7651
  file: {
7651
- async read(path37) {
7652
+ async read(path36) {
7652
7653
  const fs39 = await import('fs/promises');
7653
- return fs39.readFile(path37, "utf-8");
7654
+ return fs39.readFile(path36, "utf-8");
7654
7655
  },
7655
- async write(path37, content) {
7656
+ async write(path36, content) {
7656
7657
  const fs39 = await import('fs/promises');
7657
7658
  const nodePath = await import('path');
7658
- await fs39.mkdir(nodePath.dirname(path37), { recursive: true });
7659
- await fs39.writeFile(path37, content, "utf-8");
7659
+ await fs39.mkdir(nodePath.dirname(path36), { recursive: true });
7660
+ await fs39.writeFile(path36, content, "utf-8");
7660
7661
  },
7661
- async exists(path37) {
7662
+ async exists(path36) {
7662
7663
  const fs39 = await import('fs/promises');
7663
7664
  try {
7664
- await fs39.access(path37);
7665
+ await fs39.access(path36);
7665
7666
  return true;
7666
7667
  } catch {
7667
7668
  return false;
@@ -8014,10 +8015,10 @@ function getPhaseStatusForPhase(phase) {
8014
8015
  }
8015
8016
  async function loadProjectState(cwd, config) {
8016
8017
  const fs39 = await import('fs/promises');
8017
- const path37 = await import('path');
8018
- const statePath = path37.join(cwd, ".coco", "state.json");
8019
- const backlogPath = path37.join(cwd, ".coco", "planning", "backlog.json");
8020
- const checkpointDir = path37.join(cwd, ".coco", "checkpoints");
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");
8021
8022
  let currentPhase = "idle";
8022
8023
  let metrics;
8023
8024
  let sprint;
@@ -8732,8 +8733,8 @@ async function saveConfig(config) {
8732
8733
  await fs39.mkdir(".coco", { recursive: true });
8733
8734
  await fs39.writeFile(".coco/config.json", JSON.stringify(config, null, 2));
8734
8735
  }
8735
- function getNestedValue(obj, path37) {
8736
- const keys = path37.split(".");
8736
+ function getNestedValue(obj, path36) {
8737
+ const keys = path36.split(".");
8737
8738
  let current = obj;
8738
8739
  for (const key of keys) {
8739
8740
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -8743,8 +8744,8 @@ function getNestedValue(obj, path37) {
8743
8744
  }
8744
8745
  return current;
8745
8746
  }
8746
- function setNestedValue(obj, path37, value) {
8747
- const keys = path37.split(".");
8747
+ function setNestedValue(obj, path36, value) {
8748
+ const keys = path36.split(".");
8748
8749
  let current = obj;
8749
8750
  for (let i = 0; i < keys.length - 1; i++) {
8750
8751
  const key = keys[i];
@@ -8965,8 +8966,8 @@ var MCPRegistryImpl = class {
8965
8966
  /**
8966
8967
  * Ensure directory exists
8967
8968
  */
8968
- async ensureDir(path37) {
8969
- await mkdir(dirname(path37), { recursive: true });
8969
+ async ensureDir(path36) {
8970
+ await mkdir(dirname(path36), { recursive: true });
8970
8971
  }
8971
8972
  };
8972
8973
  function createMCPRegistry(registryPath) {
@@ -9485,9 +9486,9 @@ function createEmptyMemoryContext() {
9485
9486
  errors: []
9486
9487
  };
9487
9488
  }
9488
- function createMissingMemoryFile(path37, level) {
9489
+ function createMissingMemoryFile(path36, level) {
9489
9490
  return {
9490
- path: path37,
9491
+ path: path36,
9491
9492
  level,
9492
9493
  content: "",
9493
9494
  sections: [],
@@ -12178,8 +12179,8 @@ async function listTrustedProjects2(trustStore) {
12178
12179
  p9.log.message("");
12179
12180
  for (const project of projects) {
12180
12181
  const level = project.approvalLevel.toUpperCase().padEnd(5);
12181
- const path37 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
12182
- p9.log.message(` [${level}] ${path37}`);
12182
+ const path36 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
12183
+ p9.log.message(` [${level}] ${path36}`);
12183
12184
  p9.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
12184
12185
  }
12185
12186
  p9.log.message("");
@@ -13439,8 +13440,8 @@ function displayRewindResult(result) {
13439
13440
  const fileName = filePath.split("/").pop() ?? filePath;
13440
13441
  console.log(`${chalk12.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
13441
13442
  }
13442
- for (const { path: path37, error } of result.filesFailed) {
13443
- const fileName = path37.split("/").pop() ?? path37;
13443
+ for (const { path: path36, error } of result.filesFailed) {
13444
+ const fileName = path36.split("/").pop() ?? path36;
13444
13445
  console.log(`${chalk12.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
13445
13446
  }
13446
13447
  if (result.conversationRestored) {
@@ -14873,8 +14874,8 @@ function formatToolSummary(toolName, input) {
14873
14874
  return String(input.path || ".");
14874
14875
  case "search_files": {
14875
14876
  const pattern = String(input.pattern || "");
14876
- const path37 = input.path ? ` in ${input.path}` : "";
14877
- return `"${pattern}"${path37}`;
14877
+ const path36 = input.path ? ` in ${input.path}` : "";
14878
+ return `"${pattern}"${path36}`;
14878
14879
  }
14879
14880
  case "bash_exec": {
14880
14881
  const cmd = String(input.command || "");
@@ -16253,6 +16254,7 @@ function createInputHandler(_session) {
16253
16254
  let tempLine = "";
16254
16255
  let lastMenuLines = 0;
16255
16256
  let lastCursorRow = 0;
16257
+ let lastContentRows = 1;
16256
16258
  let isFirstRender = true;
16257
16259
  let isPasting = false;
16258
16260
  let pasteBuffer = "";
@@ -16304,7 +16306,12 @@ function createInputHandler(_session) {
16304
16306
  output += chalk12.dim.gray(ghost);
16305
16307
  }
16306
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;
16307
16313
  const showMenu = completions.length > 0 && currentLine.startsWith("/") && currentLine.length >= 1;
16314
+ let extraLinesBelow = 0;
16308
16315
  if (showMenu) {
16309
16316
  const cols = getColumnCount();
16310
16317
  const maxVisibleItems = MAX_ROWS * cols;
@@ -16323,9 +16330,11 @@ function createInputHandler(_session) {
16323
16330
  output += "\n";
16324
16331
  output += chalk12.dim(` \u2191 ${startIndex} more above`);
16325
16332
  lastMenuLines++;
16333
+ extraLinesBelow++;
16326
16334
  }
16327
16335
  for (let row = 0; row < rowCount; row++) {
16328
16336
  output += "\n";
16337
+ extraLinesBelow++;
16329
16338
  for (let col = 0; col < cols; col++) {
16330
16339
  const itemIndex = row * cols + col;
16331
16340
  if (itemIndex >= visibleItems.length) break;
@@ -16344,22 +16353,22 @@ function createInputHandler(_session) {
16344
16353
  output += "\n";
16345
16354
  output += chalk12.dim(` \u2193 ${completions.length - endIndex} more below`);
16346
16355
  lastMenuLines++;
16356
+ extraLinesBelow++;
16347
16357
  }
16348
- for (let i = 0; i < BOTTOM_MARGIN; i++) {
16349
- output += "\n";
16350
- }
16351
- output += ansiEscapes3.cursorUp(lastMenuLines + BOTTOM_MARGIN + 1);
16352
16358
  } else {
16353
16359
  lastMenuLines = 0;
16354
- for (let i = 0; i < BOTTOM_MARGIN; i++) {
16355
- output += "\n";
16356
- }
16357
- output += ansiEscapes3.cursorUp(BOTTOM_MARGIN + 1);
16358
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);
16359
16367
  output += ansiEscapes3.cursorDown(1);
16360
16368
  const cursorAbsolutePos = prompt.visualLen + cursorPos;
16361
- const finalLine = Math.floor(cursorAbsolutePos / termCols);
16362
- const finalCol = cursorAbsolutePos % termCols;
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;
16363
16372
  output += "\r";
16364
16373
  if (finalLine > 0) {
16365
16374
  output += ansiEscapes3.cursorDown(finalLine);
@@ -16368,10 +16377,15 @@ function createInputHandler(_session) {
16368
16377
  output += ansiEscapes3.cursorForward(finalCol);
16369
16378
  }
16370
16379
  lastCursorRow = finalLine;
16380
+ lastContentRows = contentRows;
16371
16381
  process.stdout.write(output);
16372
16382
  }
16373
16383
  function clearMenu() {
16374
- process.stdout.write(ansiEscapes3.eraseDown);
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);
16375
16389
  lastMenuLines = 0;
16376
16390
  }
16377
16391
  function insertTextAtCursor(text9) {
@@ -16395,6 +16409,7 @@ function createInputHandler(_session) {
16395
16409
  tempLine = "";
16396
16410
  lastMenuLines = 0;
16397
16411
  lastCursorRow = 0;
16412
+ lastContentRows = 1;
16398
16413
  isFirstRender = true;
16399
16414
  render();
16400
16415
  if (process.stdin.isTTY) {
@@ -16537,9 +16552,7 @@ function createInputHandler(_session) {
16537
16552
  currentLine = completions[selectedCompletion].cmd;
16538
16553
  }
16539
16554
  cleanup();
16540
- const termWidth = process.stdout.columns || 80;
16541
16555
  console.log();
16542
- console.log(chalk12.dim("\u2500".repeat(termWidth)));
16543
16556
  const result = currentLine.trim();
16544
16557
  if (result) {
16545
16558
  sessionHistory.push(result);
@@ -20306,10 +20319,10 @@ var CoverageAnalyzer = class {
20306
20319
  join(this.projectPath, ".coverage", "coverage-summary.json"),
20307
20320
  join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
20308
20321
  ];
20309
- for (const path37 of possiblePaths) {
20322
+ for (const path36 of possiblePaths) {
20310
20323
  try {
20311
- await access(path37, constants.R_OK);
20312
- const content = await readFile(path37, "utf-8");
20324
+ await access(path36, constants.R_OK);
20325
+ const content = await readFile(path36, "utf-8");
20313
20326
  const report = JSON.parse(content);
20314
20327
  return parseCoverageSummary(report);
20315
20328
  } catch {
@@ -24491,9 +24504,9 @@ Examples:
24491
24504
  }
24492
24505
  });
24493
24506
  var diffTools = [showDiffTool];
24494
- async function fileExists(path37) {
24507
+ async function fileExists(path36) {
24495
24508
  try {
24496
- await access(path37);
24509
+ await access(path36);
24497
24510
  return true;
24498
24511
  } catch {
24499
24512
  return false;
@@ -28624,24 +28637,6 @@ var pc = chalk12;
28624
28637
  });
28625
28638
 
28626
28639
  // src/cli/repl/index.ts
28627
- function visualWidth(str) {
28628
- const stripped = str.replace(/\x1b\[[0-9;]*m/g, "");
28629
- let width = 0;
28630
- for (const char of stripped) {
28631
- const cp = char.codePointAt(0) || 0;
28632
- 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) {
28633
- width += 2;
28634
- } else if (
28635
- // CJK Unified Ideographs and other wide characters
28636
- 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
28637
- ) {
28638
- width += 2;
28639
- } else {
28640
- width += 1;
28641
- }
28642
- }
28643
- return width;
28644
- }
28645
28640
  async function startRepl(options = {}) {
28646
28641
  const projectPath = options.projectPath ?? process.cwd();
28647
28642
  const session = createSession(projectPath, options.config);
@@ -28920,40 +28915,30 @@ async function startRepl(options = {}) {
28920
28915
  inputHandler.close();
28921
28916
  }
28922
28917
  async function printWelcome(session) {
28923
- const providerType = session.config.provider.type;
28924
- const model = session.config.provider.model || "default";
28925
- const isReturningUser = existsSync(path20__default.join(session.projectPath, ".coco"));
28926
- if (isReturningUser) {
28927
- const versionStr = chalk12.dim(`v${VERSION}`);
28928
- const providerStr = chalk12.dim(`${providerType}/${model}`);
28929
- console.log(
28930
- `
28931
- \u{1F965} Coco ${versionStr} ${chalk12.dim("\u2502")} ${providerStr} ${chalk12.dim("\u2502")} ${chalk12.yellow("/help")}
28932
- `
28933
- );
28934
- return;
28935
- }
28936
28918
  const trustStore = createTrustStore();
28937
28919
  await trustStore.init();
28938
28920
  const trustLevel = trustStore.getLevel(session.projectPath);
28939
28921
  const boxWidth = 41;
28940
- const innerWidth = boxWidth - 4;
28941
- const titleContent = "\u{1F965} CORBAT-COCO";
28922
+ const innerWidth = boxWidth - 2;
28942
28923
  const versionText = `v${VERSION}`;
28943
- const titleContentVisualWidth = visualWidth(titleContent);
28944
- const versionVisualWidth = visualWidth(versionText);
28945
- const titlePadding = innerWidth - titleContentVisualWidth - versionVisualWidth;
28946
28924
  const subtitleText = "open source \u2022 corbat.tech";
28947
- const subtitleVisualWidth = visualWidth(subtitleText);
28948
- const subtitlePadding = innerWidth - subtitleVisualWidth;
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) + " ";
28949
28937
  console.log();
28950
28938
  console.log(chalk12.magenta(" \u256D" + "\u2500".repeat(boxWidth - 2) + "\u256E"));
28951
- console.log(
28952
- chalk12.magenta(" \u2502 ") + "\u{1F965} " + chalk12.bold.white("CORBAT-COCO") + " ".repeat(Math.max(0, titlePadding)) + chalk12.dim(versionText) + chalk12.magenta(" \u2502")
28953
- );
28954
- console.log(
28955
- chalk12.magenta(" \u2502 ") + chalk12.dim(subtitleText) + " ".repeat(Math.max(0, subtitlePadding)) + chalk12.magenta(" \u2502")
28956
- );
28939
+ console.log(" " + boxLine(titleContent));
28940
+ console.log(" " + boxLine(taglineContent));
28941
+ console.log(" " + boxLine(subtitleContent));
28957
28942
  console.log(chalk12.magenta(" \u2570" + "\u2500".repeat(boxWidth - 2) + "\u256F"));
28958
28943
  const updateInfo = await checkForUpdates();
28959
28944
  if (updateInfo) {
@@ -28994,7 +28979,7 @@ async function checkProjectTrust(projectPath) {
28994
28979
  return true;
28995
28980
  }
28996
28981
  console.log();
28997
- console.log(chalk12.cyan.bold(" \u{1F965} Corbat-Coco") + chalk12.dim(` v${VERSION}`));
28982
+ console.log(chalk12.cyan.bold(" \u{1F965} Coco") + chalk12.dim(` v${VERSION}`));
28998
28983
  console.log(chalk12.dim(` \u{1F4C1} ${projectPath}`));
28999
28984
  console.log();
29000
28985
  console.log(chalk12.yellow(" \u26A0 First time accessing this directory"));