@corbat-tech/coco 1.4.0 → 1.5.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 CHANGED
@@ -12,11 +12,11 @@ import { z } from 'zod';
12
12
  import chalk42 from 'chalk';
13
13
  import * as p9 from '@clack/prompts';
14
14
  import { execa } from 'execa';
15
+ import * as crypto from 'crypto';
16
+ import { randomUUID } from 'crypto';
15
17
  import { Command } from 'commander';
16
18
  import { fileURLToPath, URL as URL$1 } from 'url';
17
19
  import JSON5 from 'json5';
18
- import * as crypto from 'crypto';
19
- import { randomUUID } from 'crypto';
20
20
  import Anthropic from '@anthropic-ai/sdk';
21
21
  import OpenAI from 'openai';
22
22
  import * as http from 'http';
@@ -448,8 +448,8 @@ __export(trust_store_exports, {
448
448
  saveTrustStore: () => saveTrustStore,
449
449
  updateLastAccessed: () => updateLastAccessed
450
450
  });
451
- async function ensureDir(path43) {
452
- await mkdir(dirname(path43), { recursive: true });
451
+ async function ensureDir(path44) {
452
+ await mkdir(dirname(path44), { recursive: true });
453
453
  }
454
454
  async function loadTrustStore(storePath = TRUST_STORE_PATH) {
455
455
  try {
@@ -527,8 +527,8 @@ function canPerformOperation(store, projectPath, operation) {
527
527
  };
528
528
  return permissions[level]?.includes(operation) ?? false;
529
529
  }
530
- function normalizePath(path43) {
531
- return join(path43);
530
+ function normalizePath(path44) {
531
+ return join(path44);
532
532
  }
533
533
  function createTrustStore(storePath = TRUST_STORE_PATH) {
534
534
  let store = null;
@@ -1260,6 +1260,224 @@ Examples:
1260
1260
  bashTools = [bashExecTool, bashBackgroundTool, commandExistsTool, getEnvTool];
1261
1261
  }
1262
1262
  });
1263
+ async function fileExists(filePath) {
1264
+ try {
1265
+ await fs23__default.access(filePath);
1266
+ return true;
1267
+ } catch {
1268
+ return false;
1269
+ }
1270
+ }
1271
+ var init_files = __esm({
1272
+ "src/utils/files.ts"() {
1273
+ init_errors();
1274
+ }
1275
+ });
1276
+
1277
+ // src/cli/repl/context/stack-detector.ts
1278
+ var stack_detector_exports = {};
1279
+ __export(stack_detector_exports, {
1280
+ detectProjectStack: () => detectProjectStack
1281
+ });
1282
+ async function detectStack(cwd) {
1283
+ if (await fileExists(path20__default.join(cwd, "package.json"))) return "node";
1284
+ if (await fileExists(path20__default.join(cwd, "Cargo.toml"))) return "rust";
1285
+ if (await fileExists(path20__default.join(cwd, "pyproject.toml"))) return "python";
1286
+ if (await fileExists(path20__default.join(cwd, "go.mod"))) return "go";
1287
+ if (await fileExists(path20__default.join(cwd, "pom.xml"))) return "java";
1288
+ if (await fileExists(path20__default.join(cwd, "build.gradle"))) return "java";
1289
+ if (await fileExists(path20__default.join(cwd, "build.gradle.kts"))) return "java";
1290
+ return "unknown";
1291
+ }
1292
+ async function detectPackageManager2(cwd, stack) {
1293
+ if (stack === "rust") return "cargo";
1294
+ if (stack === "python") return "pip";
1295
+ if (stack === "go") return "go";
1296
+ if (stack === "java") {
1297
+ if (await fileExists(path20__default.join(cwd, "build.gradle")) || await fileExists(path20__default.join(cwd, "build.gradle.kts"))) {
1298
+ return "gradle";
1299
+ }
1300
+ if (await fileExists(path20__default.join(cwd, "pom.xml"))) {
1301
+ return "maven";
1302
+ }
1303
+ }
1304
+ if (stack === "node") {
1305
+ if (await fileExists(path20__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
1306
+ if (await fileExists(path20__default.join(cwd, "yarn.lock"))) return "yarn";
1307
+ if (await fileExists(path20__default.join(cwd, "bun.lockb"))) return "bun";
1308
+ return "npm";
1309
+ }
1310
+ return null;
1311
+ }
1312
+ async function parsePackageJson(cwd) {
1313
+ const packageJsonPath = path20__default.join(cwd, "package.json");
1314
+ try {
1315
+ const content = await fs23__default.readFile(packageJsonPath, "utf-8");
1316
+ const pkg = JSON.parse(content);
1317
+ const allDeps = {
1318
+ ...pkg.dependencies,
1319
+ ...pkg.devDependencies
1320
+ };
1321
+ const frameworks = [];
1322
+ if (allDeps.react) frameworks.push("React");
1323
+ if (allDeps.vue) frameworks.push("Vue");
1324
+ if (allDeps["@angular/core"]) frameworks.push("Angular");
1325
+ if (allDeps.next) frameworks.push("Next.js");
1326
+ if (allDeps.nuxt) frameworks.push("Nuxt");
1327
+ if (allDeps.express) frameworks.push("Express");
1328
+ if (allDeps.fastify) frameworks.push("Fastify");
1329
+ if (allDeps.nestjs || allDeps["@nestjs/core"]) frameworks.push("NestJS");
1330
+ const buildTools2 = [];
1331
+ if (allDeps.webpack) buildTools2.push("webpack");
1332
+ if (allDeps.vite) buildTools2.push("vite");
1333
+ if (allDeps.rollup) buildTools2.push("rollup");
1334
+ if (allDeps.tsup) buildTools2.push("tsup");
1335
+ if (allDeps.esbuild) buildTools2.push("esbuild");
1336
+ if (pkg.scripts?.build) buildTools2.push("build");
1337
+ const testingFrameworks = [];
1338
+ if (allDeps.vitest) testingFrameworks.push("vitest");
1339
+ if (allDeps.jest) testingFrameworks.push("jest");
1340
+ if (allDeps.mocha) testingFrameworks.push("mocha");
1341
+ if (allDeps.chai) testingFrameworks.push("chai");
1342
+ if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
1343
+ if (allDeps.cypress) testingFrameworks.push("cypress");
1344
+ const languages = ["JavaScript"];
1345
+ if (allDeps.typescript || await fileExists(path20__default.join(cwd, "tsconfig.json"))) {
1346
+ languages.push("TypeScript");
1347
+ }
1348
+ return {
1349
+ dependencies: allDeps,
1350
+ frameworks,
1351
+ buildTools: buildTools2,
1352
+ testingFrameworks,
1353
+ languages
1354
+ };
1355
+ } catch {
1356
+ return {
1357
+ dependencies: {},
1358
+ frameworks: [],
1359
+ buildTools: [],
1360
+ testingFrameworks: [],
1361
+ languages: []
1362
+ };
1363
+ }
1364
+ }
1365
+ async function parsePomXml(cwd) {
1366
+ const pomPath = path20__default.join(cwd, "pom.xml");
1367
+ try {
1368
+ const content = await fs23__default.readFile(pomPath, "utf-8");
1369
+ const dependencies = {};
1370
+ const frameworks = [];
1371
+ const buildTools2 = ["maven"];
1372
+ const testingFrameworks = [];
1373
+ const depRegex = /<groupId>([^<]+)<\/groupId>\s*<artifactId>([^<]+)<\/artifactId>/g;
1374
+ let match;
1375
+ while ((match = depRegex.exec(content)) !== null) {
1376
+ const groupId = match[1];
1377
+ const artifactId = match[2];
1378
+ if (!groupId || !artifactId) continue;
1379
+ const fullName = `${groupId}:${artifactId}`;
1380
+ dependencies[fullName] = "unknown";
1381
+ if (artifactId.includes("spring-boot")) {
1382
+ if (!frameworks.includes("Spring Boot")) frameworks.push("Spring Boot");
1383
+ }
1384
+ if (artifactId.includes("spring-webmvc") || artifactId.includes("spring-web")) {
1385
+ if (!frameworks.includes("Spring MVC")) frameworks.push("Spring MVC");
1386
+ }
1387
+ if (artifactId.includes("hibernate")) {
1388
+ if (!frameworks.includes("Hibernate")) frameworks.push("Hibernate");
1389
+ }
1390
+ if (artifactId === "junit-jupiter" || artifactId === "junit") {
1391
+ if (!testingFrameworks.includes("JUnit")) testingFrameworks.push("JUnit");
1392
+ }
1393
+ if (artifactId === "mockito-core") {
1394
+ if (!testingFrameworks.includes("Mockito")) testingFrameworks.push("Mockito");
1395
+ }
1396
+ }
1397
+ return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
1398
+ } catch {
1399
+ return { dependencies: {}, frameworks: [], buildTools: ["maven"], testingFrameworks: [] };
1400
+ }
1401
+ }
1402
+ async function parsePyprojectToml(cwd) {
1403
+ const pyprojectPath = path20__default.join(cwd, "pyproject.toml");
1404
+ try {
1405
+ const content = await fs23__default.readFile(pyprojectPath, "utf-8");
1406
+ const dependencies = {};
1407
+ const frameworks = [];
1408
+ const buildTools2 = ["pip"];
1409
+ const testingFrameworks = [];
1410
+ const lines = content.split("\n");
1411
+ for (const line of lines) {
1412
+ const trimmed = line.trim();
1413
+ if (trimmed.match(/^["']?[\w-]+["']?\s*=\s*["'][\^~>=<]+[\d.]+["']/)) {
1414
+ const depMatch = trimmed.match(/^["']?([\w-]+)["']?\s*=\s*["']([\^~>=<]+[\d.]+)["']/);
1415
+ if (depMatch && depMatch[1] && depMatch[2]) {
1416
+ dependencies[depMatch[1]] = depMatch[2];
1417
+ }
1418
+ }
1419
+ if (trimmed.includes("fastapi")) frameworks.push("FastAPI");
1420
+ if (trimmed.includes("django")) frameworks.push("Django");
1421
+ if (trimmed.includes("flask")) frameworks.push("Flask");
1422
+ if (trimmed.includes("pytest")) testingFrameworks.push("pytest");
1423
+ if (trimmed.includes("unittest")) testingFrameworks.push("unittest");
1424
+ }
1425
+ return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
1426
+ } catch {
1427
+ return { dependencies: {}, frameworks: [], buildTools: ["pip"], testingFrameworks: [] };
1428
+ }
1429
+ }
1430
+ async function detectProjectStack(cwd) {
1431
+ const stack = await detectStack(cwd);
1432
+ const packageManager = await detectPackageManager2(cwd, stack);
1433
+ let dependencies = {};
1434
+ let frameworks = [];
1435
+ let buildTools2 = [];
1436
+ let testingFrameworks = [];
1437
+ let languages = [];
1438
+ if (stack === "node") {
1439
+ const parsed = await parsePackageJson(cwd);
1440
+ dependencies = parsed.dependencies;
1441
+ frameworks = parsed.frameworks;
1442
+ buildTools2 = parsed.buildTools;
1443
+ testingFrameworks = parsed.testingFrameworks;
1444
+ languages = parsed.languages;
1445
+ } else if (stack === "java") {
1446
+ const parsed = await parsePomXml(cwd);
1447
+ dependencies = parsed.dependencies;
1448
+ frameworks = parsed.frameworks;
1449
+ buildTools2 = parsed.buildTools;
1450
+ testingFrameworks = parsed.testingFrameworks;
1451
+ languages = ["Java"];
1452
+ } else if (stack === "python") {
1453
+ const parsed = await parsePyprojectToml(cwd);
1454
+ dependencies = parsed.dependencies;
1455
+ frameworks = parsed.frameworks;
1456
+ buildTools2 = parsed.buildTools;
1457
+ testingFrameworks = parsed.testingFrameworks;
1458
+ languages = ["Python"];
1459
+ } else if (stack === "go") {
1460
+ languages = ["Go"];
1461
+ buildTools2 = ["go"];
1462
+ } else if (stack === "rust") {
1463
+ languages = ["Rust"];
1464
+ buildTools2 = ["cargo"];
1465
+ }
1466
+ return {
1467
+ stack,
1468
+ packageManager,
1469
+ dependencies,
1470
+ frameworks,
1471
+ buildTools: buildTools2,
1472
+ testingFrameworks,
1473
+ languages
1474
+ };
1475
+ }
1476
+ var init_stack_detector = __esm({
1477
+ "src/cli/repl/context/stack-detector.ts"() {
1478
+ init_files();
1479
+ }
1480
+ });
1263
1481
  function findPackageJson() {
1264
1482
  let dir = dirname(fileURLToPath(import.meta.url));
1265
1483
  for (let i = 0; i < 10; i++) {
@@ -1418,8 +1636,8 @@ Generated by Corbat-Coco v0.1.0
1418
1636
 
1419
1637
  // src/cli/commands/init.ts
1420
1638
  function registerInitCommand(program2) {
1421
- 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 (path43, options) => {
1422
- await runInit(path43, options);
1639
+ 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 (path44, options) => {
1640
+ await runInit(path44, options);
1423
1641
  });
1424
1642
  }
1425
1643
  async function runInit(projectPath, options) {
@@ -1498,18 +1716,18 @@ async function gatherProjectInfo() {
1498
1716
  language
1499
1717
  };
1500
1718
  }
1501
- function getDefaultProjectInfo(path43) {
1502
- const name = path43 === "." ? "my-project" : path43.split("/").pop() || "my-project";
1719
+ function getDefaultProjectInfo(path44) {
1720
+ const name = path44 === "." ? "my-project" : path44.split("/").pop() || "my-project";
1503
1721
  return {
1504
1722
  name,
1505
1723
  description: "",
1506
1724
  language: "typescript"
1507
1725
  };
1508
1726
  }
1509
- async function checkExistingProject(path43) {
1727
+ async function checkExistingProject(path44) {
1510
1728
  try {
1511
- const fs43 = await import('fs/promises');
1512
- await fs43.access(`${path43}/.coco`);
1729
+ const fs44 = await import('fs/promises');
1730
+ await fs44.access(`${path44}/.coco`);
1513
1731
  return true;
1514
1732
  } catch {
1515
1733
  return false;
@@ -8368,20 +8586,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
8368
8586
  },
8369
8587
  tools: {
8370
8588
  file: {
8371
- async read(path43) {
8372
- const fs43 = await import('fs/promises');
8373
- return fs43.readFile(path43, "utf-8");
8589
+ async read(path44) {
8590
+ const fs44 = await import('fs/promises');
8591
+ return fs44.readFile(path44, "utf-8");
8374
8592
  },
8375
- async write(path43, content) {
8376
- const fs43 = await import('fs/promises');
8593
+ async write(path44, content) {
8594
+ const fs44 = await import('fs/promises');
8377
8595
  const nodePath = await import('path');
8378
- await fs43.mkdir(nodePath.dirname(path43), { recursive: true });
8379
- await fs43.writeFile(path43, content, "utf-8");
8596
+ await fs44.mkdir(nodePath.dirname(path44), { recursive: true });
8597
+ await fs44.writeFile(path44, content, "utf-8");
8380
8598
  },
8381
- async exists(path43) {
8382
- const fs43 = await import('fs/promises');
8599
+ async exists(path44) {
8600
+ const fs44 = await import('fs/promises');
8383
8601
  try {
8384
- await fs43.access(path43);
8602
+ await fs44.access(path44);
8385
8603
  return true;
8386
8604
  } catch {
8387
8605
  return false;
@@ -8620,16 +8838,16 @@ async function loadTasks(_options) {
8620
8838
  ];
8621
8839
  }
8622
8840
  async function checkProjectState() {
8623
- const fs43 = await import('fs/promises');
8841
+ const fs44 = await import('fs/promises');
8624
8842
  let hasProject = false;
8625
8843
  let hasPlan = false;
8626
8844
  try {
8627
- await fs43.access(".coco");
8845
+ await fs44.access(".coco");
8628
8846
  hasProject = true;
8629
8847
  } catch {
8630
8848
  }
8631
8849
  try {
8632
- await fs43.access(".coco/planning/backlog.json");
8850
+ await fs44.access(".coco/planning/backlog.json");
8633
8851
  hasPlan = true;
8634
8852
  } catch {
8635
8853
  }
@@ -8733,24 +8951,24 @@ function getPhaseStatusForPhase(phase) {
8733
8951
  return "in_progress";
8734
8952
  }
8735
8953
  async function loadProjectState(cwd, config) {
8736
- const fs43 = await import('fs/promises');
8737
- const path43 = await import('path');
8738
- const statePath = path43.join(cwd, ".coco", "state.json");
8739
- const backlogPath = path43.join(cwd, ".coco", "planning", "backlog.json");
8740
- const checkpointDir = path43.join(cwd, ".coco", "checkpoints");
8954
+ const fs44 = await import('fs/promises');
8955
+ const path44 = await import('path');
8956
+ const statePath = path44.join(cwd, ".coco", "state.json");
8957
+ const backlogPath = path44.join(cwd, ".coco", "planning", "backlog.json");
8958
+ const checkpointDir = path44.join(cwd, ".coco", "checkpoints");
8741
8959
  let currentPhase = "idle";
8742
8960
  let metrics;
8743
8961
  let sprint;
8744
8962
  let checkpoints = [];
8745
8963
  try {
8746
- const stateContent = await fs43.readFile(statePath, "utf-8");
8964
+ const stateContent = await fs44.readFile(statePath, "utf-8");
8747
8965
  const stateData = JSON.parse(stateContent);
8748
8966
  currentPhase = stateData.currentPhase || "idle";
8749
8967
  metrics = stateData.metrics;
8750
8968
  } catch {
8751
8969
  }
8752
8970
  try {
8753
- const backlogContent = await fs43.readFile(backlogPath, "utf-8");
8971
+ const backlogContent = await fs44.readFile(backlogPath, "utf-8");
8754
8972
  const backlogData = JSON.parse(backlogContent);
8755
8973
  if (backlogData.currentSprint) {
8756
8974
  const tasks = backlogData.tasks || [];
@@ -8772,7 +8990,7 @@ async function loadProjectState(cwd, config) {
8772
8990
  } catch {
8773
8991
  }
8774
8992
  try {
8775
- const files = await fs43.readdir(checkpointDir);
8993
+ const files = await fs44.readdir(checkpointDir);
8776
8994
  checkpoints = files.filter((f) => f.endsWith(".json")).sort().reverse();
8777
8995
  } catch {
8778
8996
  }
@@ -8908,8 +9126,8 @@ async function restoreFromCheckpoint(_checkpoint) {
8908
9126
  }
8909
9127
  async function checkProjectExists() {
8910
9128
  try {
8911
- const fs43 = await import('fs/promises');
8912
- await fs43.access(".coco");
9129
+ const fs44 = await import('fs/promises');
9130
+ await fs44.access(".coco");
8913
9131
  return true;
8914
9132
  } catch {
8915
9133
  return false;
@@ -9570,12 +9788,12 @@ async function loadConfig2() {
9570
9788
  };
9571
9789
  }
9572
9790
  async function saveConfig(config) {
9573
- const fs43 = await import('fs/promises');
9574
- await fs43.mkdir(".coco", { recursive: true });
9575
- await fs43.writeFile(".coco/config.json", JSON.stringify(config, null, 2));
9791
+ const fs44 = await import('fs/promises');
9792
+ await fs44.mkdir(".coco", { recursive: true });
9793
+ await fs44.writeFile(".coco/config.json", JSON.stringify(config, null, 2));
9576
9794
  }
9577
- function getNestedValue(obj, path43) {
9578
- const keys = path43.split(".");
9795
+ function getNestedValue(obj, path44) {
9796
+ const keys = path44.split(".");
9579
9797
  let current = obj;
9580
9798
  for (const key of keys) {
9581
9799
  if (current === null || current === void 0 || typeof current !== "object") {
@@ -9585,8 +9803,8 @@ function getNestedValue(obj, path43) {
9585
9803
  }
9586
9804
  return current;
9587
9805
  }
9588
- function setNestedValue(obj, path43, value) {
9589
- const keys = path43.split(".");
9806
+ function setNestedValue(obj, path44, value) {
9807
+ const keys = path44.split(".");
9590
9808
  let current = obj;
9591
9809
  for (let i = 0; i < keys.length - 1; i++) {
9592
9810
  const key = keys[i];
@@ -9807,8 +10025,8 @@ var MCPRegistryImpl = class {
9807
10025
  /**
9808
10026
  * Ensure directory exists
9809
10027
  */
9810
- async ensureDir(path43) {
9811
- await mkdir(dirname(path43), { recursive: true });
10028
+ async ensureDir(path44) {
10029
+ await mkdir(dirname(path44), { recursive: true });
9812
10030
  }
9813
10031
  };
9814
10032
  function createMCPRegistry(registryPath) {
@@ -10327,9 +10545,9 @@ function createEmptyMemoryContext() {
10327
10545
  errors: []
10328
10546
  };
10329
10547
  }
10330
- function createMissingMemoryFile(path43, level) {
10548
+ function createMissingMemoryFile(path44, level) {
10331
10549
  return {
10332
- path: path43,
10550
+ path: path44,
10333
10551
  level,
10334
10552
  content: "",
10335
10553
  sections: [],
@@ -10506,9 +10724,45 @@ function getConversationContext(session, toolRegistry) {
10506
10724
  # Project Instructions (from COCO.md/CLAUDE.md)
10507
10725
 
10508
10726
  ${session.memoryContext.combinedContent}`;
10727
+ }
10728
+ if (session.projectContext) {
10729
+ const stackInfo = formatStackContext(session.projectContext);
10730
+ systemPrompt = `${systemPrompt}
10731
+
10732
+ ${stackInfo}`;
10509
10733
  }
10510
10734
  return [{ role: "system", content: systemPrompt }, ...session.messages];
10511
10735
  }
10736
+ function formatStackContext(ctx) {
10737
+ const parts = [];
10738
+ parts.push("# Project Technology Stack");
10739
+ parts.push("");
10740
+ parts.push(`**Language/Runtime:** ${ctx.stack}`);
10741
+ if (ctx.packageManager) {
10742
+ parts.push(`**Package Manager:** ${ctx.packageManager}`);
10743
+ }
10744
+ if (ctx.frameworks.length > 0) {
10745
+ parts.push(`**Frameworks:** ${ctx.frameworks.join(", ")}`);
10746
+ }
10747
+ if (ctx.languages.length > 0) {
10748
+ parts.push(`**Languages:** ${ctx.languages.join(", ")}`);
10749
+ }
10750
+ if (ctx.testingFrameworks.length > 0) {
10751
+ parts.push(`**Testing Frameworks:** ${ctx.testingFrameworks.join(", ")}`);
10752
+ }
10753
+ if (ctx.buildTools.length > 0) {
10754
+ parts.push(`**Build Tools:** ${ctx.buildTools.join(", ")}`);
10755
+ }
10756
+ const keyDeps = Object.entries(ctx.dependencies).slice(0, 10).map(([name, version]) => `${name}@${version}`).join(", ");
10757
+ if (keyDeps) {
10758
+ parts.push(`**Key Dependencies:** ${keyDeps}`);
10759
+ }
10760
+ parts.push("");
10761
+ parts.push(
10762
+ "**IMPORTANT:** When suggesting libraries, frameworks, or dependencies, ONLY recommend technologies compatible with the stack above. Do not suggest installing Node.js packages in a Java project, or Java libraries in a Python project."
10763
+ );
10764
+ return parts.join("\n");
10765
+ }
10512
10766
  function clearSession(session) {
10513
10767
  session.messages = [];
10514
10768
  }
@@ -13259,8 +13513,8 @@ async function listTrustedProjects2(trustStore) {
13259
13513
  p9.log.message("");
13260
13514
  for (const project of projects) {
13261
13515
  const level = project.approvalLevel.toUpperCase().padEnd(5);
13262
- const path43 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
13263
- p9.log.message(` [${level}] ${path43}`);
13516
+ const path44 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
13517
+ p9.log.message(` [${level}] ${path44}`);
13264
13518
  p9.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
13265
13519
  }
13266
13520
  p9.log.message("");
@@ -14430,7 +14684,7 @@ async function getCheckpoint(session, checkpointId) {
14430
14684
  return store.checkpoints.find((cp) => cp.id === checkpointId) ?? null;
14431
14685
  }
14432
14686
  async function restoreFiles(checkpoint, excludeFiles) {
14433
- const fs43 = await import('fs/promises');
14687
+ const fs44 = await import('fs/promises');
14434
14688
  const restored = [];
14435
14689
  const failed = [];
14436
14690
  for (const fileCheckpoint of checkpoint.files) {
@@ -14438,7 +14692,7 @@ async function restoreFiles(checkpoint, excludeFiles) {
14438
14692
  continue;
14439
14693
  }
14440
14694
  try {
14441
- await fs43.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
14695
+ await fs44.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
14442
14696
  restored.push(fileCheckpoint.filePath);
14443
14697
  } catch (error) {
14444
14698
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -14520,8 +14774,8 @@ function displayRewindResult(result) {
14520
14774
  const fileName = filePath.split("/").pop() ?? filePath;
14521
14775
  console.log(`${chalk42.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
14522
14776
  }
14523
- for (const { path: path43, error } of result.filesFailed) {
14524
- const fileName = path43.split("/").pop() ?? path43;
14777
+ for (const { path: path44, error } of result.filesFailed) {
14778
+ const fileName = path44.split("/").pop() ?? path44;
14525
14779
  console.log(`${chalk42.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
14526
14780
  }
14527
14781
  if (result.conversationRestored) {
@@ -15954,8 +16208,8 @@ function formatToolSummary(toolName, input) {
15954
16208
  return String(input.path || ".");
15955
16209
  case "search_files": {
15956
16210
  const pattern = String(input.pattern || "");
15957
- const path43 = input.path ? ` in ${input.path}` : "";
15958
- return `"${pattern}"${path43}`;
16211
+ const path44 = input.path ? ` in ${input.path}` : "";
16212
+ return `"${pattern}"${path44}`;
15959
16213
  }
15960
16214
  case "bash_exec": {
15961
16215
  const cmd = String(input.command || "");
@@ -20989,10 +21243,10 @@ var CoverageAnalyzer = class {
20989
21243
  join(this.projectPath, ".coverage", "coverage-summary.json"),
20990
21244
  join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
20991
21245
  ];
20992
- for (const path43 of possiblePaths) {
21246
+ for (const path44 of possiblePaths) {
20993
21247
  try {
20994
- await access(path43, constants.R_OK);
20995
- const content = await readFile(path43, "utf-8");
21248
+ await access(path44, constants.R_OK);
21249
+ const content = await readFile(path44, "utf-8");
20996
21250
  const report = JSON.parse(content);
20997
21251
  return parseCoverageSummary(report);
20998
21252
  } catch {
@@ -25202,20 +25456,10 @@ var diffTools = [showDiffTool];
25202
25456
  // src/tools/review.ts
25203
25457
  init_registry();
25204
25458
  init_errors();
25205
-
25206
- // src/utils/files.ts
25207
- init_errors();
25208
- async function fileExists(filePath) {
25209
- try {
25210
- await fs23__default.access(filePath);
25211
- return true;
25212
- } catch {
25213
- return false;
25214
- }
25215
- }
25216
- async function fileExists2(path43) {
25459
+ init_files();
25460
+ async function fileExists2(path44) {
25217
25461
  try {
25218
- await access(path43);
25462
+ await access(path44);
25219
25463
  return true;
25220
25464
  } catch {
25221
25465
  return false;
@@ -25305,7 +25549,7 @@ async function detectMaturity(cwd) {
25305
25549
  if (!hasLintConfig && hasPackageJson) {
25306
25550
  try {
25307
25551
  const pkgRaw = await import('fs/promises').then(
25308
- (fs43) => fs43.readFile(join(cwd, "package.json"), "utf-8")
25552
+ (fs44) => fs44.readFile(join(cwd, "package.json"), "utf-8")
25309
25553
  );
25310
25554
  const pkg = JSON.parse(pkgRaw);
25311
25555
  if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
@@ -29964,6 +30208,13 @@ var terminalOptions = {
29964
30208
  var marked = new Marked();
29965
30209
  marked.use(markedTerminal(terminalOptions));
29966
30210
  init_bash();
30211
+ init_files();
30212
+
30213
+ // src/cli/repl/skills/builtin/ship/version-detector.ts
30214
+ init_files();
30215
+
30216
+ // src/cli/repl/skills/builtin/ship/changelog.ts
30217
+ init_files();
29967
30218
 
29968
30219
  // src/cli/repl/skills/builtin/ship/steps/test-coverage.ts
29969
30220
  init_bash();
@@ -30038,6 +30289,8 @@ async function startRepl(options = {}) {
30038
30289
  process.exit(1);
30039
30290
  }
30040
30291
  initializeContextManager(session, provider);
30292
+ const { detectProjectStack: detectProjectStack2 } = await Promise.resolve().then(() => (init_stack_detector(), stack_detector_exports));
30293
+ session.projectContext = await detectProjectStack2(projectPath);
30041
30294
  await loadAllowedPaths(projectPath);
30042
30295
  if (await shouldShowPermissionSuggestion()) {
30043
30296
  await showPermissionSuggestion();