@corbat-tech/coco 2.7.0 → 2.8.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/README.md +1 -1
- package/dist/cli/index.js +1068 -704
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +824 -468
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
2
|
+
import * as fs50 from 'fs';
|
|
3
|
+
import fs50__default, { readFileSync, constants } from 'fs';
|
|
4
|
+
import * as path35 from 'path';
|
|
5
|
+
import path35__default, { join, dirname, resolve, basename } from 'path';
|
|
6
6
|
import { URL as URL$1, fileURLToPath } from 'url';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import * as os4 from 'os';
|
|
9
9
|
import os4__default, { homedir } from 'os';
|
|
10
|
-
import * as
|
|
11
|
-
import
|
|
10
|
+
import * as fs33 from 'fs/promises';
|
|
11
|
+
import fs33__default, { mkdir, writeFile, readFile, access, readdir, rm } from 'fs/promises';
|
|
12
12
|
import JSON5 from 'json5';
|
|
13
13
|
import { Logger } from 'tslog';
|
|
14
14
|
import Anthropic from '@anthropic-ai/sdk';
|
|
@@ -282,6 +282,9 @@ var init_schema = __esm({
|
|
|
282
282
|
});
|
|
283
283
|
|
|
284
284
|
// src/utils/errors.ts
|
|
285
|
+
function isCocoError(error) {
|
|
286
|
+
return error instanceof CocoError;
|
|
287
|
+
}
|
|
285
288
|
function formatError(error) {
|
|
286
289
|
if (error instanceof CocoError) {
|
|
287
290
|
let message = `[${error.code}] ${error.message}`;
|
|
@@ -506,7 +509,7 @@ async function loadConfig(configPath) {
|
|
|
506
509
|
async function loadConfigFile(configPath, options = {}) {
|
|
507
510
|
const { strict = true } = options;
|
|
508
511
|
try {
|
|
509
|
-
const content = await
|
|
512
|
+
const content = await fs33__default.readFile(configPath, "utf-8");
|
|
510
513
|
const parsed = JSON5.parse(content);
|
|
511
514
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
512
515
|
if (!strict) {
|
|
@@ -562,7 +565,7 @@ function deepMergeConfig(base, override) {
|
|
|
562
565
|
};
|
|
563
566
|
}
|
|
564
567
|
function getProjectConfigPath() {
|
|
565
|
-
return
|
|
568
|
+
return path35__default.join(process.cwd(), ".coco", "config.json");
|
|
566
569
|
}
|
|
567
570
|
async function saveConfig(config, configPath, global = false) {
|
|
568
571
|
const result = CocoConfigSchema.safeParse(config);
|
|
@@ -577,10 +580,10 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
577
580
|
});
|
|
578
581
|
}
|
|
579
582
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath());
|
|
580
|
-
const dir =
|
|
581
|
-
await
|
|
583
|
+
const dir = path35__default.dirname(resolvedPath);
|
|
584
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
582
585
|
const content = JSON.stringify(result.data, null, 2);
|
|
583
|
-
await
|
|
586
|
+
await fs33__default.writeFile(resolvedPath, content, "utf-8");
|
|
584
587
|
}
|
|
585
588
|
function createDefaultConfig(projectName, language = "typescript") {
|
|
586
589
|
return createDefaultConfigObject(projectName, language);
|
|
@@ -589,20 +592,20 @@ async function findConfigPath(cwd) {
|
|
|
589
592
|
const envPath = process.env["COCO_CONFIG_PATH"];
|
|
590
593
|
if (envPath) {
|
|
591
594
|
try {
|
|
592
|
-
await
|
|
595
|
+
await fs33__default.access(envPath);
|
|
593
596
|
return envPath;
|
|
594
597
|
} catch {
|
|
595
598
|
}
|
|
596
599
|
}
|
|
597
600
|
const basePath = cwd || process.cwd();
|
|
598
|
-
const projectConfigPath =
|
|
601
|
+
const projectConfigPath = path35__default.join(basePath, ".coco", "config.json");
|
|
599
602
|
try {
|
|
600
|
-
await
|
|
603
|
+
await fs33__default.access(projectConfigPath);
|
|
601
604
|
return projectConfigPath;
|
|
602
605
|
} catch {
|
|
603
606
|
}
|
|
604
607
|
try {
|
|
605
|
-
await
|
|
608
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
606
609
|
return CONFIG_PATHS.config;
|
|
607
610
|
} catch {
|
|
608
611
|
return void 0;
|
|
@@ -611,14 +614,14 @@ async function findConfigPath(cwd) {
|
|
|
611
614
|
async function findAllConfigPaths(cwd) {
|
|
612
615
|
const result = {};
|
|
613
616
|
try {
|
|
614
|
-
await
|
|
617
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
615
618
|
result.global = CONFIG_PATHS.config;
|
|
616
619
|
} catch {
|
|
617
620
|
}
|
|
618
621
|
const basePath = cwd || process.cwd();
|
|
619
|
-
const projectConfigPath =
|
|
622
|
+
const projectConfigPath = path35__default.join(basePath, ".coco", "config.json");
|
|
620
623
|
try {
|
|
621
|
-
await
|
|
624
|
+
await fs33__default.access(projectConfigPath);
|
|
622
625
|
result.project = projectConfigPath;
|
|
623
626
|
} catch {
|
|
624
627
|
}
|
|
@@ -627,7 +630,7 @@ async function findAllConfigPaths(cwd) {
|
|
|
627
630
|
async function configExists(configPath, scope = "any") {
|
|
628
631
|
if (configPath) {
|
|
629
632
|
try {
|
|
630
|
-
await
|
|
633
|
+
await fs33__default.access(configPath);
|
|
631
634
|
return true;
|
|
632
635
|
} catch {
|
|
633
636
|
return false;
|
|
@@ -635,7 +638,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
635
638
|
}
|
|
636
639
|
if (scope === "project" || scope === "any") {
|
|
637
640
|
try {
|
|
638
|
-
await
|
|
641
|
+
await fs33__default.access(getProjectConfigPath());
|
|
639
642
|
return true;
|
|
640
643
|
} catch {
|
|
641
644
|
if (scope === "project") return false;
|
|
@@ -643,7 +646,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
643
646
|
}
|
|
644
647
|
if (scope === "global" || scope === "any") {
|
|
645
648
|
try {
|
|
646
|
-
await
|
|
649
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
647
650
|
return true;
|
|
648
651
|
} catch {
|
|
649
652
|
return false;
|
|
@@ -651,8 +654,8 @@ async function configExists(configPath, scope = "any") {
|
|
|
651
654
|
}
|
|
652
655
|
return false;
|
|
653
656
|
}
|
|
654
|
-
function getConfigValue(config,
|
|
655
|
-
const keys =
|
|
657
|
+
function getConfigValue(config, path55) {
|
|
658
|
+
const keys = path55.split(".");
|
|
656
659
|
let current = config;
|
|
657
660
|
for (const key of keys) {
|
|
658
661
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -799,13 +802,13 @@ function createLogger(config = {}) {
|
|
|
799
802
|
return logger;
|
|
800
803
|
}
|
|
801
804
|
function setupFileLogging(logger, logDir, name) {
|
|
802
|
-
if (!
|
|
803
|
-
|
|
805
|
+
if (!fs50__default.existsSync(logDir)) {
|
|
806
|
+
fs50__default.mkdirSync(logDir, { recursive: true });
|
|
804
807
|
}
|
|
805
|
-
const logFile =
|
|
808
|
+
const logFile = path35__default.join(logDir, `${name}.log`);
|
|
806
809
|
logger.attachTransport((logObj) => {
|
|
807
810
|
const line = JSON.stringify(logObj) + "\n";
|
|
808
|
-
|
|
811
|
+
fs50__default.appendFileSync(logFile, line);
|
|
809
812
|
});
|
|
810
813
|
}
|
|
811
814
|
function createChildLogger(parent, name) {
|
|
@@ -821,7 +824,7 @@ function setLogger(logger) {
|
|
|
821
824
|
globalLogger = logger;
|
|
822
825
|
}
|
|
823
826
|
function initializeLogging(projectPath, level = "info") {
|
|
824
|
-
const logDir =
|
|
827
|
+
const logDir = path35__default.join(projectPath, ".coco", "logs");
|
|
825
828
|
const logger = createLogger({
|
|
826
829
|
name: "coco",
|
|
827
830
|
level,
|
|
@@ -2230,18 +2233,18 @@ async function refreshAccessToken(provider, refreshToken) {
|
|
|
2230
2233
|
}
|
|
2231
2234
|
function getTokenStoragePath(provider) {
|
|
2232
2235
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2233
|
-
return
|
|
2236
|
+
return path35.join(home, ".coco", "tokens", `${provider}.json`);
|
|
2234
2237
|
}
|
|
2235
2238
|
async function saveTokens(provider, tokens) {
|
|
2236
2239
|
const filePath = getTokenStoragePath(provider);
|
|
2237
|
-
const dir =
|
|
2238
|
-
await
|
|
2239
|
-
await
|
|
2240
|
+
const dir = path35.dirname(filePath);
|
|
2241
|
+
await fs33.mkdir(dir, { recursive: true, mode: 448 });
|
|
2242
|
+
await fs33.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
2240
2243
|
}
|
|
2241
2244
|
async function loadTokens(provider) {
|
|
2242
2245
|
const filePath = getTokenStoragePath(provider);
|
|
2243
2246
|
try {
|
|
2244
|
-
const content = await
|
|
2247
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
2245
2248
|
return JSON.parse(content);
|
|
2246
2249
|
} catch {
|
|
2247
2250
|
return null;
|
|
@@ -2250,7 +2253,7 @@ async function loadTokens(provider) {
|
|
|
2250
2253
|
async function deleteTokens(provider) {
|
|
2251
2254
|
const filePath = getTokenStoragePath(provider);
|
|
2252
2255
|
try {
|
|
2253
|
-
await
|
|
2256
|
+
await fs33.unlink(filePath);
|
|
2254
2257
|
} catch {
|
|
2255
2258
|
}
|
|
2256
2259
|
}
|
|
@@ -3214,7 +3217,7 @@ function getADCPath() {
|
|
|
3214
3217
|
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
3215
3218
|
return process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
3216
3219
|
}
|
|
3217
|
-
return
|
|
3220
|
+
return path35.join(home, ".config", "gcloud", "application_default_credentials.json");
|
|
3218
3221
|
}
|
|
3219
3222
|
async function isGcloudInstalled() {
|
|
3220
3223
|
try {
|
|
@@ -3227,7 +3230,7 @@ async function isGcloudInstalled() {
|
|
|
3227
3230
|
async function hasADCCredentials() {
|
|
3228
3231
|
const adcPath = getADCPath();
|
|
3229
3232
|
try {
|
|
3230
|
-
await
|
|
3233
|
+
await fs33.access(adcPath);
|
|
3231
3234
|
return true;
|
|
3232
3235
|
} catch {
|
|
3233
3236
|
return false;
|
|
@@ -4607,8 +4610,8 @@ function loadGlobalCocoEnv() {
|
|
|
4607
4610
|
try {
|
|
4608
4611
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
4609
4612
|
if (!home) return;
|
|
4610
|
-
const globalEnvPath =
|
|
4611
|
-
const content =
|
|
4613
|
+
const globalEnvPath = path35.join(home, ".coco", ".env");
|
|
4614
|
+
const content = fs50.readFileSync(globalEnvPath, "utf-8");
|
|
4612
4615
|
for (const line of content.split("\n")) {
|
|
4613
4616
|
const trimmed = line.trim();
|
|
4614
4617
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -4743,7 +4746,7 @@ function loadUserPreferences() {
|
|
|
4743
4746
|
return cachedPreferences;
|
|
4744
4747
|
}
|
|
4745
4748
|
try {
|
|
4746
|
-
const content =
|
|
4749
|
+
const content = fs50.readFileSync(CONFIG_PATHS.config, "utf-8");
|
|
4747
4750
|
cachedPreferences = JSON.parse(content);
|
|
4748
4751
|
return cachedPreferences;
|
|
4749
4752
|
} catch {
|
|
@@ -4761,9 +4764,9 @@ async function saveUserPreferences(prefs) {
|
|
|
4761
4764
|
authMethods: { ...existing.authMethods, ...prefs.authMethods },
|
|
4762
4765
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4763
4766
|
};
|
|
4764
|
-
const dir =
|
|
4765
|
-
await
|
|
4766
|
-
await
|
|
4767
|
+
const dir = path35.dirname(CONFIG_PATHS.config);
|
|
4768
|
+
await fs50.promises.mkdir(dir, { recursive: true });
|
|
4769
|
+
await fs50.promises.writeFile(CONFIG_PATHS.config, JSON.stringify(updated, null, 2), "utf-8");
|
|
4767
4770
|
cachedPreferences = updated;
|
|
4768
4771
|
} catch {
|
|
4769
4772
|
}
|
|
@@ -5235,8 +5238,8 @@ var init_registry = __esm({
|
|
|
5235
5238
|
/**
|
|
5236
5239
|
* Ensure directory exists
|
|
5237
5240
|
*/
|
|
5238
|
-
async ensureDir(
|
|
5239
|
-
await mkdir(dirname(
|
|
5241
|
+
async ensureDir(path55) {
|
|
5242
|
+
await mkdir(dirname(path55), { recursive: true });
|
|
5240
5243
|
}
|
|
5241
5244
|
};
|
|
5242
5245
|
}
|
|
@@ -5311,7 +5314,7 @@ __export(markdown_loader_exports, {
|
|
|
5311
5314
|
});
|
|
5312
5315
|
async function isMarkdownSkill(skillDir) {
|
|
5313
5316
|
try {
|
|
5314
|
-
await
|
|
5317
|
+
await fs33__default.access(path35__default.join(skillDir, SKILL_FILENAME));
|
|
5315
5318
|
return true;
|
|
5316
5319
|
} catch {
|
|
5317
5320
|
return false;
|
|
@@ -5319,16 +5322,16 @@ async function isMarkdownSkill(skillDir) {
|
|
|
5319
5322
|
}
|
|
5320
5323
|
async function loadMarkdownMetadata(skillDir, scope) {
|
|
5321
5324
|
try {
|
|
5322
|
-
const skillPath =
|
|
5323
|
-
const raw = await
|
|
5325
|
+
const skillPath = path35__default.join(skillDir, SKILL_FILENAME);
|
|
5326
|
+
const raw = await fs33__default.readFile(skillPath, "utf-8");
|
|
5324
5327
|
const { data } = matter(raw);
|
|
5325
5328
|
const parsed = SkillFrontmatterSchema.safeParse(data);
|
|
5326
5329
|
if (!parsed.success) {
|
|
5327
5330
|
return null;
|
|
5328
5331
|
}
|
|
5329
5332
|
const fm = parsed.data;
|
|
5330
|
-
const dirName =
|
|
5331
|
-
const parentDir =
|
|
5333
|
+
const dirName = path35__default.basename(skillDir);
|
|
5334
|
+
const parentDir = path35__default.basename(path35__default.dirname(skillDir));
|
|
5332
5335
|
const namespace = isNamespaceDirectory(parentDir) ? parentDir : void 0;
|
|
5333
5336
|
const baseId = toKebabCase(fm.name || dirName);
|
|
5334
5337
|
const fullId = namespace ? `${namespace}/${baseId}` : baseId;
|
|
@@ -5368,8 +5371,8 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
5368
5371
|
}
|
|
5369
5372
|
async function loadMarkdownContent(skillDir) {
|
|
5370
5373
|
try {
|
|
5371
|
-
const skillPath =
|
|
5372
|
-
const raw = await
|
|
5374
|
+
const skillPath = path35__default.join(skillDir, SKILL_FILENAME);
|
|
5375
|
+
const raw = await fs33__default.readFile(skillPath, "utf-8");
|
|
5373
5376
|
const { content } = matter(raw);
|
|
5374
5377
|
const references = await listSubdirectory(skillDir, "references");
|
|
5375
5378
|
const scripts = await listSubdirectory(skillDir, "scripts");
|
|
@@ -5391,9 +5394,9 @@ async function loadMarkdownContent(skillDir) {
|
|
|
5391
5394
|
}
|
|
5392
5395
|
async function listSubdirectory(skillDir, subdir) {
|
|
5393
5396
|
try {
|
|
5394
|
-
const dir =
|
|
5395
|
-
const entries = await
|
|
5396
|
-
return entries.filter((e) => e.isFile()).map((e) =>
|
|
5397
|
+
const dir = path35__default.join(skillDir, subdir);
|
|
5398
|
+
const entries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5399
|
+
return entries.filter((e) => e.isFile()).map((e) => path35__default.join(dir, e.name));
|
|
5397
5400
|
} catch {
|
|
5398
5401
|
return [];
|
|
5399
5402
|
}
|
|
@@ -5470,8 +5473,8 @@ async function loadSkillFromDirectory(skillDir, scope) {
|
|
|
5470
5473
|
if (await isMarkdownSkill(skillDir)) {
|
|
5471
5474
|
return loadMarkdownMetadata(skillDir, scope);
|
|
5472
5475
|
}
|
|
5473
|
-
const hasTs = await fileExists(
|
|
5474
|
-
const hasJs = await fileExists(
|
|
5476
|
+
const hasTs = await fileExists(path35__default.join(skillDir, "index.ts"));
|
|
5477
|
+
const hasJs = await fileExists(path35__default.join(skillDir, "index.js"));
|
|
5475
5478
|
if (hasTs || hasJs) {
|
|
5476
5479
|
return null;
|
|
5477
5480
|
}
|
|
@@ -5491,7 +5494,7 @@ async function loadFullSkill(metadata) {
|
|
|
5491
5494
|
}
|
|
5492
5495
|
async function fileExists(filePath) {
|
|
5493
5496
|
try {
|
|
5494
|
-
await
|
|
5497
|
+
await fs33__default.access(filePath);
|
|
5495
5498
|
return true;
|
|
5496
5499
|
} catch {
|
|
5497
5500
|
return false;
|
|
@@ -5516,7 +5519,7 @@ async function discoverAllSkills(projectPath, builtinSkills = [], options) {
|
|
|
5516
5519
|
for (const meta of globalSkills) {
|
|
5517
5520
|
applyWithPriority(allSkills, meta);
|
|
5518
5521
|
}
|
|
5519
|
-
const projectDirs = opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) =>
|
|
5522
|
+
const projectDirs = opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) => path35__default.join(projectPath, d));
|
|
5520
5523
|
for (const dir of projectDirs) {
|
|
5521
5524
|
const projectSkills = await scanSkillsDirectory(dir, "project");
|
|
5522
5525
|
for (const meta of projectSkills) {
|
|
@@ -5527,13 +5530,13 @@ async function discoverAllSkills(projectPath, builtinSkills = [], options) {
|
|
|
5527
5530
|
}
|
|
5528
5531
|
async function scanSkillsDirectory(dir, scope) {
|
|
5529
5532
|
try {
|
|
5530
|
-
const entries = await
|
|
5533
|
+
const entries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5531
5534
|
const skillDirs = entries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
5532
5535
|
const results = [];
|
|
5533
5536
|
for (const entry of skillDirs) {
|
|
5534
|
-
const entryPath =
|
|
5537
|
+
const entryPath = path35__default.join(dir, entry.name);
|
|
5535
5538
|
try {
|
|
5536
|
-
const stat2 = await
|
|
5539
|
+
const stat2 = await fs33__default.lstat(entryPath);
|
|
5537
5540
|
if (stat2.isSymbolicLink()) continue;
|
|
5538
5541
|
} catch {
|
|
5539
5542
|
continue;
|
|
@@ -5561,13 +5564,13 @@ async function scanSkillsDirectory(dir, scope) {
|
|
|
5561
5564
|
async function scanNestedSkills(dir, scope, depth) {
|
|
5562
5565
|
if (depth >= MAX_NESTING_DEPTH) return [];
|
|
5563
5566
|
try {
|
|
5564
|
-
const subEntries = await
|
|
5567
|
+
const subEntries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5565
5568
|
const subDirs = subEntries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
5566
5569
|
const results = await Promise.all(
|
|
5567
5570
|
subDirs.map(async (sub) => {
|
|
5568
|
-
const subPath =
|
|
5571
|
+
const subPath = path35__default.join(dir, sub.name);
|
|
5569
5572
|
try {
|
|
5570
|
-
const stat2 = await
|
|
5573
|
+
const stat2 = await fs33__default.lstat(subPath);
|
|
5571
5574
|
if (stat2.isSymbolicLink()) return null;
|
|
5572
5575
|
} catch {
|
|
5573
5576
|
return null;
|
|
@@ -5594,7 +5597,7 @@ var init_discovery = __esm({
|
|
|
5594
5597
|
init_typescript_loader();
|
|
5595
5598
|
init_paths();
|
|
5596
5599
|
init_logger();
|
|
5597
|
-
GLOBAL_SKILLS_DIR =
|
|
5600
|
+
GLOBAL_SKILLS_DIR = path35__default.join(COCO_HOME, "skills");
|
|
5598
5601
|
PROJECT_SKILLS_DIRNAMES = [
|
|
5599
5602
|
".claude/skills",
|
|
5600
5603
|
// Claude compat — read for migration/interop (lowest project priority)
|
|
@@ -6700,9 +6703,9 @@ function createEmptyMemoryContext() {
|
|
|
6700
6703
|
errors: []
|
|
6701
6704
|
};
|
|
6702
6705
|
}
|
|
6703
|
-
function createMissingMemoryFile(
|
|
6706
|
+
function createMissingMemoryFile(path55, level) {
|
|
6704
6707
|
return {
|
|
6705
|
-
path:
|
|
6708
|
+
path: path55,
|
|
6706
6709
|
level,
|
|
6707
6710
|
content: "",
|
|
6708
6711
|
sections: [],
|
|
@@ -6933,7 +6936,7 @@ function clearSession(session) {
|
|
|
6933
6936
|
}
|
|
6934
6937
|
async function loadTrustSettings() {
|
|
6935
6938
|
try {
|
|
6936
|
-
const content = await
|
|
6939
|
+
const content = await fs33__default.readFile(TRUST_SETTINGS_FILE, "utf-8");
|
|
6937
6940
|
const raw = JSON.parse(content);
|
|
6938
6941
|
return {
|
|
6939
6942
|
globalTrusted: raw.globalTrusted ?? [],
|
|
@@ -6952,9 +6955,9 @@ async function loadTrustSettings() {
|
|
|
6952
6955
|
}
|
|
6953
6956
|
async function saveTrustSettings(settings) {
|
|
6954
6957
|
try {
|
|
6955
|
-
await
|
|
6958
|
+
await fs33__default.mkdir(TRUST_SETTINGS_DIR, { recursive: true });
|
|
6956
6959
|
settings.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6957
|
-
await
|
|
6960
|
+
await fs33__default.writeFile(TRUST_SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
|
|
6958
6961
|
} catch (error) {
|
|
6959
6962
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6960
6963
|
console.warn(`[Trust] Failed to save trust settings: ${msg}`);
|
|
@@ -7097,7 +7100,7 @@ var init_session = __esm({
|
|
|
7097
7100
|
init_manager();
|
|
7098
7101
|
init_compactor();
|
|
7099
7102
|
MAX_SKILL_INSTRUCTIONS_CHARS = 16e3;
|
|
7100
|
-
TRUST_SETTINGS_DIR =
|
|
7103
|
+
TRUST_SETTINGS_DIR = path35__default.dirname(CONFIG_PATHS.trustedTools);
|
|
7101
7104
|
TRUST_SETTINGS_FILE = CONFIG_PATHS.trustedTools;
|
|
7102
7105
|
CATEGORY_LABELS = {
|
|
7103
7106
|
file: "File Operations",
|
|
@@ -7220,6 +7223,21 @@ After completing a task, ALWAYS suggest logical next steps based on what you did
|
|
|
7220
7223
|
|
|
7221
7224
|
Keep suggestions brief (1-2 bullet points max) and actionable.
|
|
7222
7225
|
|
|
7226
|
+
## Error Recovery
|
|
7227
|
+
|
|
7228
|
+
When a tool fails, do NOT blindly retry with the same arguments. Instead:
|
|
7229
|
+
- **File not found**: Use **glob** with a pattern like \`**/*partial-name*\` or **list_dir** to explore nearby directories. Check the error for "Did you mean?" suggestions.
|
|
7230
|
+
- **Text not found in edit_file**: Use **read_file** to see the actual content. The error shows the closest matching lines \u2014 use those as reference for the correct oldText.
|
|
7231
|
+
- **web_fetch HTTP error (404, 403, etc.)**: Do NOT retry the same URL. Use **web_search** to find the correct or alternative URL. If the page requires authentication, look for a public alternative.
|
|
7232
|
+
- **web_search failure**: Try a different search engine parameter, simplify the query, or rephrase with different keywords.
|
|
7233
|
+
- **Timeout errors**: Do NOT immediately retry. Simplify the request, try a different source, or inform the user.
|
|
7234
|
+
- **After 2 failures with the same tool**: Stop, rethink your approach, try an alternative tool or strategy, or explain the issue to the user.
|
|
7235
|
+
- **Git errors**: If git_commit, git_push, etc. fail, read the error carefully. Use git_status to understand the current state. For "not a git repository", verify the working directory with list_dir.
|
|
7236
|
+
- **Build/test failures**: Read the stderr output and the hint field in the result. Use read_file to inspect the failing file. Never retry the same build without fixing the underlying code first.
|
|
7237
|
+
- **Permission denied**: Do NOT retry. Explain to the user that the operation requires different permissions.
|
|
7238
|
+
- **Command not found**: Use command_exists to verify availability before suggesting alternatives.
|
|
7239
|
+
- **Database errors**: Use inspect_schema to understand table structure before retrying queries.
|
|
7240
|
+
|
|
7223
7241
|
## File Access
|
|
7224
7242
|
File operations are restricted to the project directory by default.
|
|
7225
7243
|
When you need to access a path outside the project, use the **authorize_path** tool first \u2014 it will ask the user for permission interactively. Once authorized, proceed with the file operation.
|
|
@@ -7382,13 +7400,13 @@ var init_types4 = __esm({
|
|
|
7382
7400
|
}
|
|
7383
7401
|
});
|
|
7384
7402
|
function getStatePath(projectPath) {
|
|
7385
|
-
return
|
|
7403
|
+
return path35.join(projectPath, ".coco", "state.json");
|
|
7386
7404
|
}
|
|
7387
7405
|
function createStateManager() {
|
|
7388
7406
|
async function load(projectPath) {
|
|
7389
7407
|
const statePath = getStatePath(projectPath);
|
|
7390
7408
|
try {
|
|
7391
|
-
const content = await
|
|
7409
|
+
const content = await fs33.readFile(statePath, "utf-8");
|
|
7392
7410
|
const file = JSON.parse(content);
|
|
7393
7411
|
if (file.version !== STATE_VERSION) {
|
|
7394
7412
|
console.warn(`State version mismatch: ${file.version} vs ${STATE_VERSION}`);
|
|
@@ -7407,7 +7425,7 @@ function createStateManager() {
|
|
|
7407
7425
|
}
|
|
7408
7426
|
async function save(state) {
|
|
7409
7427
|
const statePath = getStatePath(state.path);
|
|
7410
|
-
await
|
|
7428
|
+
await fs33.mkdir(path35.dirname(statePath), { recursive: true });
|
|
7411
7429
|
const file = {
|
|
7412
7430
|
version: STATE_VERSION,
|
|
7413
7431
|
state: {
|
|
@@ -7415,19 +7433,19 @@ function createStateManager() {
|
|
|
7415
7433
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7416
7434
|
}
|
|
7417
7435
|
};
|
|
7418
|
-
await
|
|
7436
|
+
await fs33.writeFile(statePath, JSON.stringify(file, null, 2), "utf-8");
|
|
7419
7437
|
}
|
|
7420
7438
|
async function clear(projectPath) {
|
|
7421
7439
|
const statePath = getStatePath(projectPath);
|
|
7422
7440
|
try {
|
|
7423
|
-
await
|
|
7441
|
+
await fs33.unlink(statePath);
|
|
7424
7442
|
} catch {
|
|
7425
7443
|
}
|
|
7426
7444
|
}
|
|
7427
7445
|
async function exists(projectPath) {
|
|
7428
7446
|
const statePath = getStatePath(projectPath);
|
|
7429
7447
|
try {
|
|
7430
|
-
await
|
|
7448
|
+
await fs33.access(statePath);
|
|
7431
7449
|
return true;
|
|
7432
7450
|
} catch {
|
|
7433
7451
|
return false;
|
|
@@ -7555,8 +7573,8 @@ __export(trust_store_exports, {
|
|
|
7555
7573
|
saveTrustStore: () => saveTrustStore,
|
|
7556
7574
|
updateLastAccessed: () => updateLastAccessed
|
|
7557
7575
|
});
|
|
7558
|
-
async function ensureDir(
|
|
7559
|
-
await mkdir(dirname(
|
|
7576
|
+
async function ensureDir(path55) {
|
|
7577
|
+
await mkdir(dirname(path55), { recursive: true });
|
|
7560
7578
|
}
|
|
7561
7579
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
7562
7580
|
try {
|
|
@@ -7634,8 +7652,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
7634
7652
|
};
|
|
7635
7653
|
return permissions[level]?.includes(operation) ?? false;
|
|
7636
7654
|
}
|
|
7637
|
-
function normalizePath(
|
|
7638
|
-
return join(
|
|
7655
|
+
function normalizePath(path55) {
|
|
7656
|
+
return join(path55);
|
|
7639
7657
|
}
|
|
7640
7658
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
7641
7659
|
let store = null;
|
|
@@ -7952,6 +7970,14 @@ function extractQuotedPath(msg) {
|
|
|
7952
7970
|
function humanizeError(message, toolName) {
|
|
7953
7971
|
const msg = message.trim();
|
|
7954
7972
|
if (!msg) return msg;
|
|
7973
|
+
if (/Use (glob|list_dir|read_file|git_init|git_status|git_add|git_commit|git_log|git_branch|git_checkout|git_push|git_pull|web_search|inspect_schema|list_checkpoints|command_exists|edit_file|run_linter|run_tests|run_script|bash_exec)\b/.test(
|
|
7974
|
+
msg
|
|
7975
|
+
)) {
|
|
7976
|
+
return msg;
|
|
7977
|
+
}
|
|
7978
|
+
if (/run git_init\b/.test(msg)) {
|
|
7979
|
+
return msg;
|
|
7980
|
+
}
|
|
7955
7981
|
if (/ECONNREFUSED/i.test(msg)) {
|
|
7956
7982
|
return "Connection refused \u2014 the server may not be running";
|
|
7957
7983
|
}
|
|
@@ -7973,13 +7999,22 @@ function humanizeError(message, toolName) {
|
|
|
7973
7999
|
if (/fetch failed|network error|Failed to fetch/i.test(msg)) {
|
|
7974
8000
|
return "Network request failed \u2014 check your internet connection";
|
|
7975
8001
|
}
|
|
8002
|
+
if (/File not found:/.test(msg) && /Did you mean/.test(msg)) {
|
|
8003
|
+
return msg;
|
|
8004
|
+
}
|
|
8005
|
+
if (/Directory not found:/.test(msg) && /Did you mean/.test(msg)) {
|
|
8006
|
+
return msg;
|
|
8007
|
+
}
|
|
8008
|
+
if (/^HTTP \d{3}:/.test(msg) && /Try/.test(msg)) {
|
|
8009
|
+
return msg;
|
|
8010
|
+
}
|
|
7976
8011
|
if (/ENOENT/i.test(msg)) {
|
|
7977
|
-
const
|
|
7978
|
-
return
|
|
8012
|
+
const path55 = extractQuotedPath(msg);
|
|
8013
|
+
return path55 ? `File or directory not found: ${path55}` : "File or directory not found";
|
|
7979
8014
|
}
|
|
7980
8015
|
if (/EACCES/i.test(msg)) {
|
|
7981
|
-
const
|
|
7982
|
-
return
|
|
8016
|
+
const path55 = extractQuotedPath(msg);
|
|
8017
|
+
return path55 ? `Permission denied: ${path55}` : "Permission denied \u2014 check file permissions";
|
|
7983
8018
|
}
|
|
7984
8019
|
if (/EISDIR/i.test(msg)) {
|
|
7985
8020
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -8062,6 +8097,12 @@ function humanizeError(message, toolName) {
|
|
|
8062
8097
|
if (/invalid.*api.?key|api.?key.*invalid|api.?key.*not.*found/i.test(msg)) {
|
|
8063
8098
|
return "Invalid or missing API key \u2014 check your provider credentials";
|
|
8064
8099
|
}
|
|
8100
|
+
if (/TS\d{4}:/.test(msg)) {
|
|
8101
|
+
return `TypeScript error \u2014 check the referenced file and line number. ${msg}`;
|
|
8102
|
+
}
|
|
8103
|
+
if (/SQLITE_ERROR/i.test(msg)) {
|
|
8104
|
+
return `Database error \u2014 use inspect_schema to verify the table structure. ${msg}`;
|
|
8105
|
+
}
|
|
8065
8106
|
return msg;
|
|
8066
8107
|
}
|
|
8067
8108
|
function looksLikeTechnicalJargon(message) {
|
|
@@ -8161,6 +8202,7 @@ var init_registry4 = __esm({
|
|
|
8161
8202
|
"src/tools/registry.ts"() {
|
|
8162
8203
|
init_logger();
|
|
8163
8204
|
init_error_humanizer();
|
|
8205
|
+
init_errors();
|
|
8164
8206
|
ToolRegistry = class {
|
|
8165
8207
|
tools = /* @__PURE__ */ new Map();
|
|
8166
8208
|
logger = getLogger();
|
|
@@ -8264,6 +8306,14 @@ var init_registry4 = __esm({
|
|
|
8264
8306
|
if (allUndefined && error.issues.length > 1) {
|
|
8265
8307
|
errorMessage += ". All parameters are missing \u2014 this is likely a JSON serialization error on our side. Please retry with the same arguments.";
|
|
8266
8308
|
}
|
|
8309
|
+
} else if (isCocoError(error)) {
|
|
8310
|
+
const causeMsg = error.cause instanceof Error ? error.cause.message : "";
|
|
8311
|
+
const combined = causeMsg && !error.message.includes(causeMsg) ? `${error.message} \u2014 ${causeMsg}` : error.message;
|
|
8312
|
+
errorMessage = humanizeError(combined, name);
|
|
8313
|
+
if (error.suggestion && !errorMessage.includes(error.suggestion)) {
|
|
8314
|
+
errorMessage += `
|
|
8315
|
+
Suggestion: ${error.suggestion}`;
|
|
8316
|
+
}
|
|
8267
8317
|
} else {
|
|
8268
8318
|
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
8269
8319
|
errorMessage = humanizeError(rawMessage, name);
|
|
@@ -8297,7 +8347,7 @@ var init_registry4 = __esm({
|
|
|
8297
8347
|
});
|
|
8298
8348
|
async function fileExists2(filePath) {
|
|
8299
8349
|
try {
|
|
8300
|
-
await
|
|
8350
|
+
await fs33__default.access(filePath);
|
|
8301
8351
|
return true;
|
|
8302
8352
|
} catch {
|
|
8303
8353
|
return false;
|
|
@@ -8699,9 +8749,9 @@ var init_diff_renderer = __esm({
|
|
|
8699
8749
|
getTerminalWidth = () => process.stdout.columns || 80;
|
|
8700
8750
|
}
|
|
8701
8751
|
});
|
|
8702
|
-
async function fileExists3(
|
|
8752
|
+
async function fileExists3(path55) {
|
|
8703
8753
|
try {
|
|
8704
|
-
await access(
|
|
8754
|
+
await access(path55);
|
|
8705
8755
|
return true;
|
|
8706
8756
|
} catch {
|
|
8707
8757
|
return false;
|
|
@@ -8791,7 +8841,7 @@ async function detectMaturity(cwd) {
|
|
|
8791
8841
|
if (!hasLintConfig && hasPackageJson) {
|
|
8792
8842
|
try {
|
|
8793
8843
|
const pkgRaw = await import('fs/promises').then(
|
|
8794
|
-
(
|
|
8844
|
+
(fs53) => fs53.readFile(join(cwd, "package.json"), "utf-8")
|
|
8795
8845
|
);
|
|
8796
8846
|
const pkg = JSON.parse(pkgRaw);
|
|
8797
8847
|
if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
|
|
@@ -8991,10 +9041,10 @@ var init_coverage = __esm({
|
|
|
8991
9041
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
8992
9042
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
8993
9043
|
];
|
|
8994
|
-
for (const
|
|
9044
|
+
for (const path55 of possiblePaths) {
|
|
8995
9045
|
try {
|
|
8996
|
-
await access(
|
|
8997
|
-
const content = await readFile(
|
|
9046
|
+
await access(path55, constants.R_OK);
|
|
9047
|
+
const content = await readFile(path55, "utf-8");
|
|
8998
9048
|
const report = JSON.parse(content);
|
|
8999
9049
|
return parseCoverageSummary(report);
|
|
9000
9050
|
} catch {
|
|
@@ -9728,7 +9778,7 @@ var init_build_verifier = __esm({
|
|
|
9728
9778
|
async verifyTypes() {
|
|
9729
9779
|
const startTime = Date.now();
|
|
9730
9780
|
try {
|
|
9731
|
-
const hasTsConfig = await this.fileExists(
|
|
9781
|
+
const hasTsConfig = await this.fileExists(path35.join(this.projectPath, "tsconfig.json"));
|
|
9732
9782
|
if (!hasTsConfig) {
|
|
9733
9783
|
return {
|
|
9734
9784
|
success: true,
|
|
@@ -9778,8 +9828,8 @@ var init_build_verifier = __esm({
|
|
|
9778
9828
|
*/
|
|
9779
9829
|
async detectBuildCommand() {
|
|
9780
9830
|
try {
|
|
9781
|
-
const packageJsonPath =
|
|
9782
|
-
const content = await
|
|
9831
|
+
const packageJsonPath = path35.join(this.projectPath, "package.json");
|
|
9832
|
+
const content = await fs33.readFile(packageJsonPath, "utf-8");
|
|
9783
9833
|
const packageJson = JSON.parse(content);
|
|
9784
9834
|
if (packageJson.scripts?.build) {
|
|
9785
9835
|
return "npm run build";
|
|
@@ -9855,7 +9905,7 @@ var init_build_verifier = __esm({
|
|
|
9855
9905
|
*/
|
|
9856
9906
|
async fileExists(filePath) {
|
|
9857
9907
|
try {
|
|
9858
|
-
await
|
|
9908
|
+
await fs33.access(filePath);
|
|
9859
9909
|
return true;
|
|
9860
9910
|
} catch {
|
|
9861
9911
|
return false;
|
|
@@ -11477,9 +11527,9 @@ function detectProjectLanguage(files) {
|
|
|
11477
11527
|
return { language: dominant, confidence, evidence };
|
|
11478
11528
|
}
|
|
11479
11529
|
function getFileExtension(filePath) {
|
|
11480
|
-
const base =
|
|
11530
|
+
const base = path35.basename(filePath);
|
|
11481
11531
|
if (base.endsWith(".d.ts")) return ".d.ts";
|
|
11482
|
-
return
|
|
11532
|
+
return path35.extname(filePath).toLowerCase();
|
|
11483
11533
|
}
|
|
11484
11534
|
function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
11485
11535
|
const evidence = [];
|
|
@@ -11487,7 +11537,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
|
11487
11537
|
evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
|
|
11488
11538
|
const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
|
|
11489
11539
|
for (const cfg of configFiles) {
|
|
11490
|
-
if (files.some((f) =>
|
|
11540
|
+
if (files.some((f) => path35.basename(f) === cfg)) {
|
|
11491
11541
|
evidence.push(`Found ${cfg}`);
|
|
11492
11542
|
}
|
|
11493
11543
|
}
|
|
@@ -12957,8 +13007,8 @@ var init_evaluator = __esm({
|
|
|
12957
13007
|
});
|
|
12958
13008
|
async function detectLinter2(cwd) {
|
|
12959
13009
|
try {
|
|
12960
|
-
const pkgPath =
|
|
12961
|
-
const pkgContent = await
|
|
13010
|
+
const pkgPath = path35__default.join(cwd, "package.json");
|
|
13011
|
+
const pkgContent = await fs33__default.readFile(pkgPath, "utf-8");
|
|
12962
13012
|
const pkg = JSON.parse(pkgContent);
|
|
12963
13013
|
const deps = {
|
|
12964
13014
|
...pkg.dependencies,
|
|
@@ -13093,7 +13143,9 @@ Examples:
|
|
|
13093
13143
|
warnings: 0,
|
|
13094
13144
|
fixable: 0,
|
|
13095
13145
|
issues: [],
|
|
13096
|
-
score:
|
|
13146
|
+
score: null,
|
|
13147
|
+
linter: "none",
|
|
13148
|
+
message: "No linter detected (looked for: eslint, oxlint, biome). Install one or use bash_exec to run a custom linter."
|
|
13097
13149
|
};
|
|
13098
13150
|
}
|
|
13099
13151
|
try {
|
|
@@ -13173,7 +13225,7 @@ Examples:
|
|
|
13173
13225
|
let totalFunctions = 0;
|
|
13174
13226
|
let complexFunctions = 0;
|
|
13175
13227
|
for (const file of targetFiles) {
|
|
13176
|
-
const content = await
|
|
13228
|
+
const content = await fs33__default.readFile(file, "utf-8");
|
|
13177
13229
|
const fileComplexity = analyzeFileComplexity(content, file);
|
|
13178
13230
|
fileResults.push(fileComplexity);
|
|
13179
13231
|
totalComplexity += fileComplexity.complexity;
|
|
@@ -13196,8 +13248,9 @@ Examples:
|
|
|
13196
13248
|
files: fileResults
|
|
13197
13249
|
};
|
|
13198
13250
|
} catch (error) {
|
|
13251
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13199
13252
|
throw new ToolError(
|
|
13200
|
-
`Complexity analysis failed: ${
|
|
13253
|
+
`Complexity analysis failed: ${msg}. Try read_file to inspect the code manually.`,
|
|
13201
13254
|
{ tool: "analyze_complexity", cause: error instanceof Error ? error : void 0 }
|
|
13202
13255
|
);
|
|
13203
13256
|
}
|
|
@@ -13230,8 +13283,9 @@ Examples:
|
|
|
13230
13283
|
const evaluation = await evaluator.evaluate(files);
|
|
13231
13284
|
return evaluation.scores;
|
|
13232
13285
|
} catch (error) {
|
|
13286
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13233
13287
|
throw new ToolError(
|
|
13234
|
-
`Quality calculation failed: ${
|
|
13288
|
+
`Quality calculation failed: ${msg}. Run run_linter and run_tests separately for partial results.`,
|
|
13235
13289
|
{ tool: "calculate_quality", cause: error instanceof Error ? error : void 0 }
|
|
13236
13290
|
);
|
|
13237
13291
|
}
|
|
@@ -13245,6 +13299,7 @@ function getGit(cwd) {
|
|
|
13245
13299
|
}
|
|
13246
13300
|
async function getDiff(git, baseBranch, includeUncommitted) {
|
|
13247
13301
|
const diffs = [];
|
|
13302
|
+
const warnings = [];
|
|
13248
13303
|
try {
|
|
13249
13304
|
const branchDiff = await git.diff([`${baseBranch}...HEAD`]);
|
|
13250
13305
|
if (branchDiff) diffs.push(branchDiff);
|
|
@@ -13253,6 +13308,7 @@ async function getDiff(git, baseBranch, includeUncommitted) {
|
|
|
13253
13308
|
const directDiff = await git.diff([baseBranch]);
|
|
13254
13309
|
if (directDiff) diffs.push(directDiff);
|
|
13255
13310
|
} catch {
|
|
13311
|
+
warnings.push(`Could not diff against base branch '${baseBranch}' \u2014 it may not exist.`);
|
|
13256
13312
|
}
|
|
13257
13313
|
}
|
|
13258
13314
|
if (includeUncommitted) {
|
|
@@ -13260,14 +13316,16 @@ async function getDiff(git, baseBranch, includeUncommitted) {
|
|
|
13260
13316
|
const uncommitted = await git.diff();
|
|
13261
13317
|
if (uncommitted) diffs.push(uncommitted);
|
|
13262
13318
|
} catch {
|
|
13319
|
+
warnings.push("Could not read unstaged changes.");
|
|
13263
13320
|
}
|
|
13264
13321
|
try {
|
|
13265
13322
|
const staged = await git.diff(["--staged"]);
|
|
13266
13323
|
if (staged) diffs.push(staged);
|
|
13267
13324
|
} catch {
|
|
13325
|
+
warnings.push("Could not read staged changes.");
|
|
13268
13326
|
}
|
|
13269
13327
|
}
|
|
13270
|
-
return diffs.join("\n");
|
|
13328
|
+
return { raw: diffs.join("\n"), warnings };
|
|
13271
13329
|
}
|
|
13272
13330
|
function analyzePatterns(diff) {
|
|
13273
13331
|
const findings = [];
|
|
@@ -13314,7 +13372,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
13314
13372
|
);
|
|
13315
13373
|
if (!hasTestChange) {
|
|
13316
13374
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
13317
|
-
const testExists = await fileExists2(
|
|
13375
|
+
const testExists = await fileExists2(path35__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists2(path35__default.join(cwd, `${baseName}.spec${ext}`));
|
|
13318
13376
|
if (testExists) {
|
|
13319
13377
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
13320
13378
|
findings.push({
|
|
@@ -13537,10 +13595,14 @@ Examples:
|
|
|
13537
13595
|
try {
|
|
13538
13596
|
const status = await git.status();
|
|
13539
13597
|
const currentBranch = status.current ?? "HEAD";
|
|
13540
|
-
const rawDiff = await getDiff(
|
|
13598
|
+
const { raw: rawDiff, warnings: diffWarnings } = await getDiff(
|
|
13599
|
+
git,
|
|
13600
|
+
baseBranch,
|
|
13601
|
+
includeUncommitted
|
|
13602
|
+
);
|
|
13541
13603
|
const diff = parseDiff(rawDiff);
|
|
13542
13604
|
if (diff.files.length === 0) {
|
|
13543
|
-
|
|
13605
|
+
const emptyResult = {
|
|
13544
13606
|
summary: {
|
|
13545
13607
|
branch: currentBranch,
|
|
13546
13608
|
baseBranch,
|
|
@@ -13554,6 +13616,10 @@ Examples:
|
|
|
13554
13616
|
maturity: "new",
|
|
13555
13617
|
diff
|
|
13556
13618
|
};
|
|
13619
|
+
if (diffWarnings.length > 0) {
|
|
13620
|
+
emptyResult.warnings = diffWarnings;
|
|
13621
|
+
}
|
|
13622
|
+
return emptyResult;
|
|
13557
13623
|
}
|
|
13558
13624
|
const maturityInfo = await detectMaturity(projectDir);
|
|
13559
13625
|
const maturity = maturityInfo.level;
|
|
@@ -13575,6 +13641,7 @@ Examples:
|
|
|
13575
13641
|
}
|
|
13576
13642
|
}
|
|
13577
13643
|
} catch {
|
|
13644
|
+
diffWarnings.push("Linter not available \u2014 code style was not checked.");
|
|
13578
13645
|
}
|
|
13579
13646
|
}
|
|
13580
13647
|
allFindings.push(...getMaturityRecommendations(maturity, diff));
|
|
@@ -13587,7 +13654,7 @@ Examples:
|
|
|
13587
13654
|
(f) => f.severity === "minor" || f.severity === "info"
|
|
13588
13655
|
);
|
|
13589
13656
|
const status_result = required.some((f) => f.severity === "critical") ? "needs_work" : required.length > 0 ? "needs_work" : "approved";
|
|
13590
|
-
|
|
13657
|
+
const result = {
|
|
13591
13658
|
summary: {
|
|
13592
13659
|
branch: currentBranch,
|
|
13593
13660
|
baseBranch,
|
|
@@ -13601,6 +13668,10 @@ Examples:
|
|
|
13601
13668
|
maturity,
|
|
13602
13669
|
diff
|
|
13603
13670
|
};
|
|
13671
|
+
if (diffWarnings.length > 0) {
|
|
13672
|
+
result.warnings = diffWarnings;
|
|
13673
|
+
}
|
|
13674
|
+
return result;
|
|
13604
13675
|
} catch (error) {
|
|
13605
13676
|
throw new ToolError(
|
|
13606
13677
|
`Code review failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -13891,10 +13962,16 @@ Examples:
|
|
|
13891
13962
|
rendered: true
|
|
13892
13963
|
};
|
|
13893
13964
|
} catch (error) {
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13965
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13966
|
+
let hint = `Diff failed: ${msg}`;
|
|
13967
|
+
if (/not a git repository/i.test(msg))
|
|
13968
|
+
hint = "Not a git repository. Use list_dir to verify you're in the right directory.";
|
|
13969
|
+
else if (/unknown revision|bad revision/i.test(msg))
|
|
13970
|
+
hint = `Reference not found: ${msg}. Use git_log or git_branch to find valid refs.`;
|
|
13971
|
+
throw new ToolError(hint, {
|
|
13972
|
+
tool: "show_diff",
|
|
13973
|
+
cause: error instanceof Error ? error : void 0
|
|
13974
|
+
});
|
|
13898
13975
|
}
|
|
13899
13976
|
}
|
|
13900
13977
|
});
|
|
@@ -13968,6 +14045,27 @@ var init_diff2 = __esm({
|
|
|
13968
14045
|
};
|
|
13969
14046
|
}
|
|
13970
14047
|
});
|
|
14048
|
+
function enrichGitError(operation, error) {
|
|
14049
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14050
|
+
if (/not a git repository/i.test(msg))
|
|
14051
|
+
return `Not a git repository. Run git_init first or verify you're in the correct directory.`;
|
|
14052
|
+
if (/nothing to commit/i.test(msg))
|
|
14053
|
+
return `Nothing to commit \u2014 working tree is clean. Use git_status to verify your changes were saved.`;
|
|
14054
|
+
if (/CONFLICT|merge conflict/i.test(msg))
|
|
14055
|
+
return `Merge conflict detected. Use read_file to see the conflicting file, resolve manually with edit_file, then git_add and git_commit.`;
|
|
14056
|
+
if (/non-fast-forward|\[rejected\]/i.test(msg))
|
|
14057
|
+
return `Push rejected \u2014 remote has new commits. Run git_pull first, resolve any conflicts, then retry git_push.`;
|
|
14058
|
+
if (/authentication failed/i.test(msg))
|
|
14059
|
+
return `Git authentication failed. Check your credentials, SSH key, or access token.`;
|
|
14060
|
+
if (/branch.*already exists/i.test(msg))
|
|
14061
|
+
return `Branch already exists. Use git_checkout to switch to it, or choose a different name.`;
|
|
14062
|
+
if (/does not exist|unknown revision|bad revision/i.test(msg))
|
|
14063
|
+
return `Git reference not found. Use git_branch to list available branches, or git_log to find the correct commit.`;
|
|
14064
|
+
if (/pathspec.*did not match/i.test(msg))
|
|
14065
|
+
return `File not tracked by git. Use glob to verify the file exists, then git_add it first.`;
|
|
14066
|
+
if (/already up to date/i.test(msg)) return `Already up to date \u2014 no changes to pull.`;
|
|
14067
|
+
return `Git ${operation} failed: ${msg}`;
|
|
14068
|
+
}
|
|
13971
14069
|
function getGit3(cwd) {
|
|
13972
14070
|
const baseDir = cwd ?? process.cwd();
|
|
13973
14071
|
return simpleGit({ baseDir });
|
|
@@ -14004,10 +14102,10 @@ Examples:
|
|
|
14004
14102
|
isClean: status.isClean()
|
|
14005
14103
|
};
|
|
14006
14104
|
} catch (error) {
|
|
14007
|
-
throw new ToolError(
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
);
|
|
14105
|
+
throw new ToolError(enrichGitError("status", error), {
|
|
14106
|
+
tool: "git_status",
|
|
14107
|
+
cause: error instanceof Error ? error : void 0
|
|
14108
|
+
});
|
|
14011
14109
|
}
|
|
14012
14110
|
}
|
|
14013
14111
|
});
|
|
@@ -14041,10 +14139,10 @@ Examples:
|
|
|
14041
14139
|
deletions: diffStat.deletions
|
|
14042
14140
|
};
|
|
14043
14141
|
} catch (error) {
|
|
14044
|
-
throw new ToolError(
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
);
|
|
14142
|
+
throw new ToolError(enrichGitError("diff", error), {
|
|
14143
|
+
tool: "git_diff",
|
|
14144
|
+
cause: error instanceof Error ? error : void 0
|
|
14145
|
+
});
|
|
14048
14146
|
}
|
|
14049
14147
|
}
|
|
14050
14148
|
});
|
|
@@ -14067,10 +14165,10 @@ Examples:
|
|
|
14067
14165
|
await git.add(files);
|
|
14068
14166
|
return { added: files };
|
|
14069
14167
|
} catch (error) {
|
|
14070
|
-
throw new ToolError(
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
);
|
|
14168
|
+
throw new ToolError(enrichGitError("add", error), {
|
|
14169
|
+
tool: "git_add",
|
|
14170
|
+
cause: error instanceof Error ? error : void 0
|
|
14171
|
+
});
|
|
14074
14172
|
}
|
|
14075
14173
|
}
|
|
14076
14174
|
});
|
|
@@ -14100,10 +14198,10 @@ Examples:
|
|
|
14100
14198
|
summary: result.summary.changes ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "No changes"
|
|
14101
14199
|
};
|
|
14102
14200
|
} catch (error) {
|
|
14103
|
-
throw new ToolError(
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
);
|
|
14201
|
+
throw new ToolError(enrichGitError("commit", error), {
|
|
14202
|
+
tool: "git_commit",
|
|
14203
|
+
cause: error instanceof Error ? error : void 0
|
|
14204
|
+
});
|
|
14107
14205
|
}
|
|
14108
14206
|
}
|
|
14109
14207
|
});
|
|
@@ -14140,10 +14238,10 @@ Examples:
|
|
|
14140
14238
|
}))
|
|
14141
14239
|
};
|
|
14142
14240
|
} catch (error) {
|
|
14143
|
-
throw new ToolError(
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
);
|
|
14241
|
+
throw new ToolError(enrichGitError("log", error), {
|
|
14242
|
+
tool: "git_log",
|
|
14243
|
+
cause: error instanceof Error ? error : void 0
|
|
14244
|
+
});
|
|
14147
14245
|
}
|
|
14148
14246
|
}
|
|
14149
14247
|
});
|
|
@@ -14184,10 +14282,10 @@ Examples:
|
|
|
14184
14282
|
current: status.current ?? "HEAD"
|
|
14185
14283
|
};
|
|
14186
14284
|
} catch (error) {
|
|
14187
|
-
throw new ToolError(
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
);
|
|
14285
|
+
throw new ToolError(enrichGitError("branch", error), {
|
|
14286
|
+
tool: "git_branch",
|
|
14287
|
+
cause: error instanceof Error ? error : void 0
|
|
14288
|
+
});
|
|
14191
14289
|
}
|
|
14192
14290
|
}
|
|
14193
14291
|
});
|
|
@@ -14214,10 +14312,10 @@ Examples:
|
|
|
14214
14312
|
}
|
|
14215
14313
|
return { branch };
|
|
14216
14314
|
} catch (error) {
|
|
14217
|
-
throw new ToolError(
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
);
|
|
14315
|
+
throw new ToolError(enrichGitError("checkout", error), {
|
|
14316
|
+
tool: "git_checkout",
|
|
14317
|
+
cause: error instanceof Error ? error : void 0
|
|
14318
|
+
});
|
|
14221
14319
|
}
|
|
14222
14320
|
}
|
|
14223
14321
|
});
|
|
@@ -14252,10 +14350,10 @@ Examples:
|
|
|
14252
14350
|
branch: pushBranch
|
|
14253
14351
|
};
|
|
14254
14352
|
} catch (error) {
|
|
14255
|
-
throw new ToolError(
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
);
|
|
14353
|
+
throw new ToolError(enrichGitError("push", error), {
|
|
14354
|
+
tool: "git_push",
|
|
14355
|
+
cause: error instanceof Error ? error : void 0
|
|
14356
|
+
});
|
|
14259
14357
|
}
|
|
14260
14358
|
}
|
|
14261
14359
|
});
|
|
@@ -14287,10 +14385,10 @@ Examples:
|
|
|
14287
14385
|
summary: result.summary ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "Already up to date"
|
|
14288
14386
|
};
|
|
14289
14387
|
} catch (error) {
|
|
14290
|
-
throw new ToolError(
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
);
|
|
14388
|
+
throw new ToolError(enrichGitError("pull", error), {
|
|
14389
|
+
tool: "git_pull",
|
|
14390
|
+
cause: error instanceof Error ? error : void 0
|
|
14391
|
+
});
|
|
14294
14392
|
}
|
|
14295
14393
|
}
|
|
14296
14394
|
});
|
|
@@ -14316,10 +14414,10 @@ Examples:
|
|
|
14316
14414
|
path: cwd ?? process.cwd()
|
|
14317
14415
|
};
|
|
14318
14416
|
} catch (error) {
|
|
14319
|
-
throw new ToolError(
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
);
|
|
14417
|
+
throw new ToolError(enrichGitError("init", error), {
|
|
14418
|
+
tool: "git_init",
|
|
14419
|
+
cause: error instanceof Error ? error : void 0
|
|
14420
|
+
});
|
|
14323
14421
|
}
|
|
14324
14422
|
}
|
|
14325
14423
|
});
|
|
@@ -14449,40 +14547,24 @@ var init_bash = __esm({
|
|
|
14449
14547
|
DEFAULT_TIMEOUT_MS = 12e4;
|
|
14450
14548
|
MAX_OUTPUT_SIZE = 1024 * 1024;
|
|
14451
14549
|
DANGEROUS_PATTERNS_FULL = [
|
|
14452
|
-
/\brm\s+-rf\s+\/(?!\w)/,
|
|
14453
|
-
|
|
14454
|
-
/\
|
|
14455
|
-
|
|
14456
|
-
/\
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
/\
|
|
14461
|
-
|
|
14462
|
-
/\
|
|
14463
|
-
|
|
14464
|
-
/>\s*\/etc\//,
|
|
14465
|
-
// Write to /etc
|
|
14466
|
-
/>\s*\/root\//,
|
|
14467
|
-
// Write to /root
|
|
14468
|
-
/\bchmod\s+777/,
|
|
14469
|
-
// Overly permissive chmod
|
|
14470
|
-
/\bchown\s+root/,
|
|
14471
|
-
// chown to root
|
|
14472
|
-
/\bcurl\s+.*\|\s*(ba)?sh/,
|
|
14473
|
-
// curl | sh pattern
|
|
14474
|
-
/\bwget\s+.*\|\s*(ba)?sh/
|
|
14475
|
-
// wget | sh pattern
|
|
14550
|
+
{ pattern: /\brm\s+-rf\s+\/(?!\w)/, rule: "rm -rf on root filesystem" },
|
|
14551
|
+
{ pattern: /\bsudo\s+rm\s+-rf/, rule: "sudo rm -rf (destructive with elevated privileges)" },
|
|
14552
|
+
{ pattern: /\b:?\(\)\s*\{.*\}/, rule: "fork bomb pattern" },
|
|
14553
|
+
{ pattern: /\bdd\s+if=.*of=\/dev\//, rule: "dd write to device" },
|
|
14554
|
+
{ pattern: /\bmkfs\./, rule: "filesystem format command" },
|
|
14555
|
+
{ pattern: /\bformat\s+/, rule: "format command" },
|
|
14556
|
+
{ pattern: />\s*\/etc\//, rule: "write redirect to /etc/" },
|
|
14557
|
+
{ pattern: />\s*\/root\//, rule: "write redirect to /root/" },
|
|
14558
|
+
{ pattern: /\bchmod\s+777/, rule: "overly permissive chmod 777" },
|
|
14559
|
+
{ pattern: /\bchown\s+root/, rule: "chown to root" },
|
|
14560
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/, rule: "curl pipe to shell (untrusted code execution)" },
|
|
14561
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/, rule: "wget pipe to shell (untrusted code execution)" }
|
|
14476
14562
|
];
|
|
14477
14563
|
DANGEROUS_PATTERNS_SHELL_ONLY = [
|
|
14478
|
-
/`[^`]+`/,
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
/\beval\s+/,
|
|
14483
|
-
// eval command (shell eval, not JS eval())
|
|
14484
|
-
/\bsource\s+/
|
|
14485
|
-
// source command (can execute arbitrary scripts)
|
|
14564
|
+
{ pattern: /`[^`]+`/, rule: "backtick command substitution" },
|
|
14565
|
+
{ pattern: /\$\([^)]+\)/, rule: "$() command substitution" },
|
|
14566
|
+
{ pattern: /\beval\s+/, rule: "eval command (arbitrary code execution)" },
|
|
14567
|
+
{ pattern: /\bsource\s+/, rule: "source command (can execute arbitrary scripts)" }
|
|
14486
14568
|
];
|
|
14487
14569
|
SAFE_ENV_VARS = /* @__PURE__ */ new Set([
|
|
14488
14570
|
// System info (non-sensitive)
|
|
@@ -14551,18 +14633,20 @@ Examples:
|
|
|
14551
14633
|
}),
|
|
14552
14634
|
async execute({ command, cwd, timeout, env: env2 }) {
|
|
14553
14635
|
const shellPart = getShellCommandPart(command);
|
|
14554
|
-
for (const pattern of DANGEROUS_PATTERNS_FULL) {
|
|
14636
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
|
|
14555
14637
|
if (pattern.test(command)) {
|
|
14556
|
-
throw new ToolError(
|
|
14557
|
-
|
|
14558
|
-
|
|
14638
|
+
throw new ToolError(
|
|
14639
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14640
|
+
{ tool: "bash_exec" }
|
|
14641
|
+
);
|
|
14559
14642
|
}
|
|
14560
14643
|
}
|
|
14561
|
-
for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14644
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14562
14645
|
if (pattern.test(shellPart)) {
|
|
14563
|
-
throw new ToolError(
|
|
14564
|
-
|
|
14565
|
-
|
|
14646
|
+
throw new ToolError(
|
|
14647
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14648
|
+
{ tool: "bash_exec" }
|
|
14649
|
+
);
|
|
14566
14650
|
}
|
|
14567
14651
|
}
|
|
14568
14652
|
const startTime = performance.now();
|
|
@@ -14647,18 +14731,20 @@ Examples:
|
|
|
14647
14731
|
}),
|
|
14648
14732
|
async execute({ command, cwd, env: env2 }) {
|
|
14649
14733
|
const shellPart = getShellCommandPart(command);
|
|
14650
|
-
for (const pattern of DANGEROUS_PATTERNS_FULL) {
|
|
14734
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
|
|
14651
14735
|
if (pattern.test(command)) {
|
|
14652
|
-
throw new ToolError(
|
|
14653
|
-
|
|
14654
|
-
|
|
14736
|
+
throw new ToolError(
|
|
14737
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14738
|
+
{ tool: "bash_background" }
|
|
14739
|
+
);
|
|
14655
14740
|
}
|
|
14656
14741
|
}
|
|
14657
|
-
for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14742
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14658
14743
|
if (pattern.test(shellPart)) {
|
|
14659
|
-
throw new ToolError(
|
|
14660
|
-
|
|
14661
|
-
|
|
14744
|
+
throw new ToolError(
|
|
14745
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14746
|
+
{ tool: "bash_background" }
|
|
14747
|
+
);
|
|
14662
14748
|
}
|
|
14663
14749
|
}
|
|
14664
14750
|
try {
|
|
@@ -14941,7 +15027,7 @@ var init_github = __esm({
|
|
|
14941
15027
|
});
|
|
14942
15028
|
async function detectVersionFile(cwd) {
|
|
14943
15029
|
for (const { file, stack, field } of VERSION_FILES) {
|
|
14944
|
-
const fullPath =
|
|
15030
|
+
const fullPath = path35__default.join(cwd, file);
|
|
14945
15031
|
if (await fileExists2(fullPath)) {
|
|
14946
15032
|
const version = await readVersionFromFile(fullPath, stack, field);
|
|
14947
15033
|
if (version) {
|
|
@@ -14987,7 +15073,7 @@ function bumpVersion(current, bump) {
|
|
|
14987
15073
|
}
|
|
14988
15074
|
}
|
|
14989
15075
|
async function writeVersion(cwd, versionFile, newVersion) {
|
|
14990
|
-
const fullPath =
|
|
15076
|
+
const fullPath = path35__default.join(cwd, versionFile.path);
|
|
14991
15077
|
const content = await readFile(fullPath, "utf-8");
|
|
14992
15078
|
let updated;
|
|
14993
15079
|
switch (versionFile.stack) {
|
|
@@ -15046,7 +15132,7 @@ var init_version_detector = __esm({
|
|
|
15046
15132
|
});
|
|
15047
15133
|
async function detectChangelog(cwd) {
|
|
15048
15134
|
for (const name of CHANGELOG_NAMES) {
|
|
15049
|
-
const fullPath =
|
|
15135
|
+
const fullPath = path35__default.join(cwd, name);
|
|
15050
15136
|
if (await fileExists2(fullPath)) {
|
|
15051
15137
|
const content = await readFile(fullPath, "utf-8");
|
|
15052
15138
|
const format = detectFormat(content);
|
|
@@ -15068,7 +15154,7 @@ function detectFormat(content) {
|
|
|
15068
15154
|
return "custom";
|
|
15069
15155
|
}
|
|
15070
15156
|
async function insertChangelogEntry(cwd, changelog, version, entries, date) {
|
|
15071
|
-
const fullPath =
|
|
15157
|
+
const fullPath = path35__default.join(cwd, changelog.path);
|
|
15072
15158
|
const content = await readFile(fullPath, "utf-8");
|
|
15073
15159
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15074
15160
|
const entry = buildEntry(changelog.format, version, entries, dateStr);
|
|
@@ -15129,11 +15215,11 @@ var init_changelog = __esm({
|
|
|
15129
15215
|
}
|
|
15130
15216
|
});
|
|
15131
15217
|
async function detectStack(cwd) {
|
|
15132
|
-
if (await fileExists2(
|
|
15133
|
-
if (await fileExists2(
|
|
15134
|
-
if (await fileExists2(
|
|
15135
|
-
if (await fileExists2(
|
|
15136
|
-
if (await fileExists2(
|
|
15218
|
+
if (await fileExists2(path35__default.join(cwd, "package.json"))) return "node";
|
|
15219
|
+
if (await fileExists2(path35__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
15220
|
+
if (await fileExists2(path35__default.join(cwd, "pyproject.toml"))) return "python";
|
|
15221
|
+
if (await fileExists2(path35__default.join(cwd, "go.mod"))) return "go";
|
|
15222
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) return "java";
|
|
15137
15223
|
return "unknown";
|
|
15138
15224
|
}
|
|
15139
15225
|
async function detectPackageManager(cwd, stack) {
|
|
@@ -15141,15 +15227,15 @@ async function detectPackageManager(cwd, stack) {
|
|
|
15141
15227
|
if (stack === "python") return "pip";
|
|
15142
15228
|
if (stack === "go") return "go";
|
|
15143
15229
|
if (stack === "node") {
|
|
15144
|
-
if (await fileExists2(
|
|
15145
|
-
if (await fileExists2(
|
|
15146
|
-
if (await fileExists2(
|
|
15230
|
+
if (await fileExists2(path35__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15231
|
+
if (await fileExists2(path35__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
15232
|
+
if (await fileExists2(path35__default.join(cwd, "bun.lockb"))) return "bun";
|
|
15147
15233
|
return "npm";
|
|
15148
15234
|
}
|
|
15149
15235
|
return null;
|
|
15150
15236
|
}
|
|
15151
15237
|
async function detectCI(cwd) {
|
|
15152
|
-
const ghDir =
|
|
15238
|
+
const ghDir = path35__default.join(cwd, ".github", "workflows");
|
|
15153
15239
|
if (await fileExists2(ghDir)) {
|
|
15154
15240
|
let workflowFiles = [];
|
|
15155
15241
|
let hasCodeQL = false;
|
|
@@ -15173,7 +15259,7 @@ async function detectCI(cwd) {
|
|
|
15173
15259
|
}
|
|
15174
15260
|
return { type: "github-actions", workflowFiles, hasCodeQL, hasLinting };
|
|
15175
15261
|
}
|
|
15176
|
-
if (await fileExists2(
|
|
15262
|
+
if (await fileExists2(path35__default.join(cwd, ".gitlab-ci.yml"))) {
|
|
15177
15263
|
return {
|
|
15178
15264
|
type: "gitlab-ci",
|
|
15179
15265
|
workflowFiles: [".gitlab-ci.yml"],
|
|
@@ -15181,7 +15267,7 @@ async function detectCI(cwd) {
|
|
|
15181
15267
|
hasLinting: false
|
|
15182
15268
|
};
|
|
15183
15269
|
}
|
|
15184
|
-
if (await fileExists2(
|
|
15270
|
+
if (await fileExists2(path35__default.join(cwd, ".circleci"))) {
|
|
15185
15271
|
return { type: "circle-ci", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
15186
15272
|
}
|
|
15187
15273
|
return { type: "none", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
@@ -16552,8 +16638,8 @@ function hasNullByte(str) {
|
|
|
16552
16638
|
}
|
|
16553
16639
|
function isBlockedPath(absolute) {
|
|
16554
16640
|
for (const blocked of BLOCKED_PATHS) {
|
|
16555
|
-
const normalizedBlocked =
|
|
16556
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
16641
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
16642
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
16557
16643
|
return blocked;
|
|
16558
16644
|
}
|
|
16559
16645
|
}
|
|
@@ -16571,7 +16657,7 @@ function getInterpreter(ext) {
|
|
|
16571
16657
|
}
|
|
16572
16658
|
async function isExecutable(filePath) {
|
|
16573
16659
|
try {
|
|
16574
|
-
await
|
|
16660
|
+
await fs33__default.access(filePath, fs33__default.constants.X_OK);
|
|
16575
16661
|
return true;
|
|
16576
16662
|
} catch {
|
|
16577
16663
|
return false;
|
|
@@ -16647,7 +16733,7 @@ Examples:
|
|
|
16647
16733
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
16648
16734
|
}
|
|
16649
16735
|
const workDir = cwd ?? process.cwd();
|
|
16650
|
-
const absolute =
|
|
16736
|
+
const absolute = path35__default.isAbsolute(filePath) ? path35__default.normalize(filePath) : path35__default.resolve(workDir, filePath);
|
|
16651
16737
|
const blockedBy = isBlockedPath(absolute);
|
|
16652
16738
|
if (blockedBy) {
|
|
16653
16739
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -16655,7 +16741,7 @@ Examples:
|
|
|
16655
16741
|
});
|
|
16656
16742
|
}
|
|
16657
16743
|
try {
|
|
16658
|
-
await
|
|
16744
|
+
await fs33__default.access(absolute);
|
|
16659
16745
|
} catch {
|
|
16660
16746
|
throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
|
|
16661
16747
|
}
|
|
@@ -16670,14 +16756,14 @@ Examples:
|
|
|
16670
16756
|
};
|
|
16671
16757
|
}
|
|
16672
16758
|
if (isBlockedExecFile(absolute)) {
|
|
16673
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
16759
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path35__default.basename(absolute)}`, {
|
|
16674
16760
|
tool: "open_file"
|
|
16675
16761
|
});
|
|
16676
16762
|
}
|
|
16677
16763
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
16678
16764
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
16679
16765
|
}
|
|
16680
|
-
const ext =
|
|
16766
|
+
const ext = path35__default.extname(absolute);
|
|
16681
16767
|
const interpreter = getInterpreter(ext);
|
|
16682
16768
|
const executable = await isExecutable(absolute);
|
|
16683
16769
|
let command;
|
|
@@ -16690,7 +16776,7 @@ Examples:
|
|
|
16690
16776
|
cmdArgs = [...args];
|
|
16691
16777
|
} else {
|
|
16692
16778
|
throw new ToolError(
|
|
16693
|
-
`Cannot execute '${
|
|
16779
|
+
`Cannot execute '${path35__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
16694
16780
|
{ tool: "open_file" }
|
|
16695
16781
|
);
|
|
16696
16782
|
}
|
|
@@ -16862,10 +16948,10 @@ function getAllowedPaths() {
|
|
|
16862
16948
|
return [...sessionAllowedPaths];
|
|
16863
16949
|
}
|
|
16864
16950
|
function isWithinAllowedPath(absolutePath, operation) {
|
|
16865
|
-
const normalizedTarget =
|
|
16951
|
+
const normalizedTarget = path35__default.normalize(absolutePath);
|
|
16866
16952
|
for (const entry of sessionAllowedPaths) {
|
|
16867
|
-
const normalizedAllowed =
|
|
16868
|
-
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed +
|
|
16953
|
+
const normalizedAllowed = path35__default.normalize(entry.path);
|
|
16954
|
+
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path35__default.sep)) {
|
|
16869
16955
|
if (operation === "read") return true;
|
|
16870
16956
|
if (entry.level === "write") return true;
|
|
16871
16957
|
}
|
|
@@ -16873,8 +16959,8 @@ function isWithinAllowedPath(absolutePath, operation) {
|
|
|
16873
16959
|
return false;
|
|
16874
16960
|
}
|
|
16875
16961
|
function addAllowedPathToSession(dirPath, level) {
|
|
16876
|
-
const absolute =
|
|
16877
|
-
if (sessionAllowedPaths.some((e) =>
|
|
16962
|
+
const absolute = path35__default.resolve(dirPath);
|
|
16963
|
+
if (sessionAllowedPaths.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
16878
16964
|
return;
|
|
16879
16965
|
}
|
|
16880
16966
|
sessionAllowedPaths.push({
|
|
@@ -16884,14 +16970,14 @@ function addAllowedPathToSession(dirPath, level) {
|
|
|
16884
16970
|
});
|
|
16885
16971
|
}
|
|
16886
16972
|
function removeAllowedPathFromSession(dirPath) {
|
|
16887
|
-
const absolute =
|
|
16888
|
-
const normalized =
|
|
16973
|
+
const absolute = path35__default.resolve(dirPath);
|
|
16974
|
+
const normalized = path35__default.normalize(absolute);
|
|
16889
16975
|
const before = sessionAllowedPaths.length;
|
|
16890
|
-
sessionAllowedPaths = sessionAllowedPaths.filter((e) =>
|
|
16976
|
+
sessionAllowedPaths = sessionAllowedPaths.filter((e) => path35__default.normalize(e.path) !== normalized);
|
|
16891
16977
|
return sessionAllowedPaths.length < before;
|
|
16892
16978
|
}
|
|
16893
16979
|
async function loadAllowedPaths(projectPath) {
|
|
16894
|
-
currentProjectPath =
|
|
16980
|
+
currentProjectPath = path35__default.resolve(projectPath);
|
|
16895
16981
|
const store = await loadStore();
|
|
16896
16982
|
const entries = store.projects[currentProjectPath] ?? [];
|
|
16897
16983
|
for (const entry of entries) {
|
|
@@ -16900,14 +16986,14 @@ async function loadAllowedPaths(projectPath) {
|
|
|
16900
16986
|
}
|
|
16901
16987
|
async function persistAllowedPath(dirPath, level) {
|
|
16902
16988
|
if (!currentProjectPath) return;
|
|
16903
|
-
const absolute =
|
|
16989
|
+
const absolute = path35__default.resolve(dirPath);
|
|
16904
16990
|
const store = await loadStore();
|
|
16905
16991
|
if (!store.projects[currentProjectPath]) {
|
|
16906
16992
|
store.projects[currentProjectPath] = [];
|
|
16907
16993
|
}
|
|
16908
16994
|
const entries = store.projects[currentProjectPath];
|
|
16909
|
-
const normalized =
|
|
16910
|
-
if (entries.some((e) =>
|
|
16995
|
+
const normalized = path35__default.normalize(absolute);
|
|
16996
|
+
if (entries.some((e) => path35__default.normalize(e.path) === normalized)) {
|
|
16911
16997
|
return;
|
|
16912
16998
|
}
|
|
16913
16999
|
entries.push({
|
|
@@ -16919,13 +17005,13 @@ async function persistAllowedPath(dirPath, level) {
|
|
|
16919
17005
|
}
|
|
16920
17006
|
async function removePersistedAllowedPath(dirPath) {
|
|
16921
17007
|
if (!currentProjectPath) return false;
|
|
16922
|
-
const absolute =
|
|
16923
|
-
const normalized =
|
|
17008
|
+
const absolute = path35__default.resolve(dirPath);
|
|
17009
|
+
const normalized = path35__default.normalize(absolute);
|
|
16924
17010
|
const store = await loadStore();
|
|
16925
17011
|
const entries = store.projects[currentProjectPath];
|
|
16926
17012
|
if (!entries) return false;
|
|
16927
17013
|
const before = entries.length;
|
|
16928
|
-
store.projects[currentProjectPath] = entries.filter((e) =>
|
|
17014
|
+
store.projects[currentProjectPath] = entries.filter((e) => path35__default.normalize(e.path) !== normalized);
|
|
16929
17015
|
if (store.projects[currentProjectPath].length < before) {
|
|
16930
17016
|
await saveStore(store);
|
|
16931
17017
|
return true;
|
|
@@ -16934,7 +17020,7 @@ async function removePersistedAllowedPath(dirPath) {
|
|
|
16934
17020
|
}
|
|
16935
17021
|
async function loadStore() {
|
|
16936
17022
|
try {
|
|
16937
|
-
const content = await
|
|
17023
|
+
const content = await fs33__default.readFile(STORE_FILE, "utf-8");
|
|
16938
17024
|
return { ...DEFAULT_STORE, ...JSON.parse(content) };
|
|
16939
17025
|
} catch {
|
|
16940
17026
|
return { ...DEFAULT_STORE };
|
|
@@ -16942,8 +17028,8 @@ async function loadStore() {
|
|
|
16942
17028
|
}
|
|
16943
17029
|
async function saveStore(store) {
|
|
16944
17030
|
try {
|
|
16945
|
-
await
|
|
16946
|
-
await
|
|
17031
|
+
await fs33__default.mkdir(path35__default.dirname(STORE_FILE), { recursive: true });
|
|
17032
|
+
await fs33__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
16947
17033
|
} catch {
|
|
16948
17034
|
}
|
|
16949
17035
|
}
|
|
@@ -16951,7 +17037,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
|
|
|
16951
17037
|
var init_allowed_paths = __esm({
|
|
16952
17038
|
"src/tools/allowed-paths.ts"() {
|
|
16953
17039
|
init_paths();
|
|
16954
|
-
STORE_FILE =
|
|
17040
|
+
STORE_FILE = path35__default.join(CONFIG_PATHS.home, "allowed-paths.json");
|
|
16955
17041
|
DEFAULT_STORE = {
|
|
16956
17042
|
version: 1,
|
|
16957
17043
|
projects: {}
|
|
@@ -17007,7 +17093,7 @@ function shouldAutoApprove(command, cwd) {
|
|
|
17007
17093
|
}
|
|
17008
17094
|
async function loadFullAccessPreference() {
|
|
17009
17095
|
try {
|
|
17010
|
-
const content = await
|
|
17096
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
17011
17097
|
const config = JSON.parse(content);
|
|
17012
17098
|
if (typeof config.fullAccessMode === "boolean") {
|
|
17013
17099
|
fullAccessEnabled = config.fullAccessMode;
|
|
@@ -17021,12 +17107,12 @@ async function saveFullAccessPreference(enabled) {
|
|
|
17021
17107
|
try {
|
|
17022
17108
|
let config = {};
|
|
17023
17109
|
try {
|
|
17024
|
-
const content = await
|
|
17110
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
17025
17111
|
config = JSON.parse(content);
|
|
17026
17112
|
} catch {
|
|
17027
17113
|
}
|
|
17028
17114
|
config.fullAccessMode = enabled;
|
|
17029
|
-
await
|
|
17115
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
17030
17116
|
} catch {
|
|
17031
17117
|
}
|
|
17032
17118
|
}
|
|
@@ -18142,7 +18228,7 @@ function shouldFullPowerApprove(command) {
|
|
|
18142
18228
|
}
|
|
18143
18229
|
async function loadFullPowerRiskPreference() {
|
|
18144
18230
|
try {
|
|
18145
|
-
const content = await
|
|
18231
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
18146
18232
|
const config = JSON.parse(content);
|
|
18147
18233
|
if (typeof config.fullPowerRiskMode === "boolean") {
|
|
18148
18234
|
fullPowerRiskEnabled = config.fullPowerRiskMode;
|
|
@@ -18156,12 +18242,12 @@ async function saveFullPowerRiskPreference(enabled) {
|
|
|
18156
18242
|
try {
|
|
18157
18243
|
let config = {};
|
|
18158
18244
|
try {
|
|
18159
|
-
const content = await
|
|
18245
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
18160
18246
|
config = JSON.parse(content);
|
|
18161
18247
|
} catch {
|
|
18162
18248
|
}
|
|
18163
18249
|
config.fullPowerRiskMode = enabled;
|
|
18164
|
-
await
|
|
18250
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
18165
18251
|
} catch {
|
|
18166
18252
|
}
|
|
18167
18253
|
}
|
|
@@ -18213,7 +18299,7 @@ __export(allow_path_prompt_exports, {
|
|
|
18213
18299
|
promptAllowPath: () => promptAllowPath
|
|
18214
18300
|
});
|
|
18215
18301
|
async function promptAllowPath(dirPath) {
|
|
18216
|
-
const absolute =
|
|
18302
|
+
const absolute = path35__default.resolve(dirPath);
|
|
18217
18303
|
console.log();
|
|
18218
18304
|
console.log(chalk25.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
18219
18305
|
console.log(chalk25.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -18448,13 +18534,13 @@ __export(stack_detector_exports, {
|
|
|
18448
18534
|
detectProjectStack: () => detectProjectStack
|
|
18449
18535
|
});
|
|
18450
18536
|
async function detectStack2(cwd) {
|
|
18451
|
-
if (await fileExists2(
|
|
18452
|
-
if (await fileExists2(
|
|
18453
|
-
if (await fileExists2(
|
|
18454
|
-
if (await fileExists2(
|
|
18455
|
-
if (await fileExists2(
|
|
18456
|
-
if (await fileExists2(
|
|
18457
|
-
if (await fileExists2(
|
|
18537
|
+
if (await fileExists2(path35__default.join(cwd, "package.json"))) return "node";
|
|
18538
|
+
if (await fileExists2(path35__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
18539
|
+
if (await fileExists2(path35__default.join(cwd, "pyproject.toml"))) return "python";
|
|
18540
|
+
if (await fileExists2(path35__default.join(cwd, "go.mod"))) return "go";
|
|
18541
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) return "java";
|
|
18542
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle"))) return "java";
|
|
18543
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
18458
18544
|
return "unknown";
|
|
18459
18545
|
}
|
|
18460
18546
|
async function detectPackageManager3(cwd, stack) {
|
|
@@ -18462,25 +18548,25 @@ async function detectPackageManager3(cwd, stack) {
|
|
|
18462
18548
|
if (stack === "python") return "pip";
|
|
18463
18549
|
if (stack === "go") return "go";
|
|
18464
18550
|
if (stack === "java") {
|
|
18465
|
-
if (await fileExists2(
|
|
18551
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle")) || await fileExists2(path35__default.join(cwd, "build.gradle.kts"))) {
|
|
18466
18552
|
return "gradle";
|
|
18467
18553
|
}
|
|
18468
|
-
if (await fileExists2(
|
|
18554
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) {
|
|
18469
18555
|
return "maven";
|
|
18470
18556
|
}
|
|
18471
18557
|
}
|
|
18472
18558
|
if (stack === "node") {
|
|
18473
|
-
if (await fileExists2(
|
|
18474
|
-
if (await fileExists2(
|
|
18475
|
-
if (await fileExists2(
|
|
18559
|
+
if (await fileExists2(path35__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
18560
|
+
if (await fileExists2(path35__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
18561
|
+
if (await fileExists2(path35__default.join(cwd, "bun.lockb"))) return "bun";
|
|
18476
18562
|
return "npm";
|
|
18477
18563
|
}
|
|
18478
18564
|
return null;
|
|
18479
18565
|
}
|
|
18480
18566
|
async function parsePackageJson(cwd) {
|
|
18481
|
-
const packageJsonPath =
|
|
18567
|
+
const packageJsonPath = path35__default.join(cwd, "package.json");
|
|
18482
18568
|
try {
|
|
18483
|
-
const content = await
|
|
18569
|
+
const content = await fs33__default.readFile(packageJsonPath, "utf-8");
|
|
18484
18570
|
const pkg = JSON.parse(content);
|
|
18485
18571
|
const allDeps = {
|
|
18486
18572
|
...pkg.dependencies,
|
|
@@ -18510,7 +18596,7 @@ async function parsePackageJson(cwd) {
|
|
|
18510
18596
|
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
18511
18597
|
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
18512
18598
|
const languages = ["JavaScript"];
|
|
18513
|
-
if (allDeps.typescript || await fileExists2(
|
|
18599
|
+
if (allDeps.typescript || await fileExists2(path35__default.join(cwd, "tsconfig.json"))) {
|
|
18514
18600
|
languages.push("TypeScript");
|
|
18515
18601
|
}
|
|
18516
18602
|
return {
|
|
@@ -18531,9 +18617,9 @@ async function parsePackageJson(cwd) {
|
|
|
18531
18617
|
}
|
|
18532
18618
|
}
|
|
18533
18619
|
async function parsePomXml(cwd) {
|
|
18534
|
-
const pomPath =
|
|
18620
|
+
const pomPath = path35__default.join(cwd, "pom.xml");
|
|
18535
18621
|
try {
|
|
18536
|
-
const content = await
|
|
18622
|
+
const content = await fs33__default.readFile(pomPath, "utf-8");
|
|
18537
18623
|
const dependencies = {};
|
|
18538
18624
|
const frameworks = [];
|
|
18539
18625
|
const buildTools2 = ["maven"];
|
|
@@ -18568,9 +18654,9 @@ async function parsePomXml(cwd) {
|
|
|
18568
18654
|
}
|
|
18569
18655
|
}
|
|
18570
18656
|
async function parsePyprojectToml(cwd) {
|
|
18571
|
-
const pyprojectPath =
|
|
18657
|
+
const pyprojectPath = path35__default.join(cwd, "pyproject.toml");
|
|
18572
18658
|
try {
|
|
18573
|
-
const content = await
|
|
18659
|
+
const content = await fs33__default.readFile(pyprojectPath, "utf-8");
|
|
18574
18660
|
const dependencies = {};
|
|
18575
18661
|
const frameworks = [];
|
|
18576
18662
|
const buildTools2 = ["pip"];
|
|
@@ -20075,26 +20161,26 @@ var init_input_echo = __esm({
|
|
|
20075
20161
|
// src/cli/index.ts
|
|
20076
20162
|
init_version();
|
|
20077
20163
|
async function createProjectStructure(projectPath, info) {
|
|
20078
|
-
const cocoPath =
|
|
20164
|
+
const cocoPath = path35__default.join(projectPath, ".coco");
|
|
20079
20165
|
const directories = [
|
|
20080
20166
|
cocoPath,
|
|
20081
|
-
|
|
20082
|
-
|
|
20083
|
-
|
|
20084
|
-
|
|
20085
|
-
|
|
20086
|
-
|
|
20087
|
-
|
|
20088
|
-
|
|
20089
|
-
|
|
20090
|
-
|
|
20091
|
-
|
|
20092
|
-
|
|
20093
|
-
|
|
20094
|
-
|
|
20167
|
+
path35__default.join(cocoPath, "state"),
|
|
20168
|
+
path35__default.join(cocoPath, "checkpoints"),
|
|
20169
|
+
path35__default.join(cocoPath, "logs"),
|
|
20170
|
+
path35__default.join(cocoPath, "discovery"),
|
|
20171
|
+
path35__default.join(cocoPath, "spec"),
|
|
20172
|
+
path35__default.join(cocoPath, "architecture"),
|
|
20173
|
+
path35__default.join(cocoPath, "architecture", "adrs"),
|
|
20174
|
+
path35__default.join(cocoPath, "architecture", "diagrams"),
|
|
20175
|
+
path35__default.join(cocoPath, "planning"),
|
|
20176
|
+
path35__default.join(cocoPath, "planning", "epics"),
|
|
20177
|
+
path35__default.join(cocoPath, "execution"),
|
|
20178
|
+
path35__default.join(cocoPath, "versions"),
|
|
20179
|
+
path35__default.join(cocoPath, "reviews"),
|
|
20180
|
+
path35__default.join(cocoPath, "delivery")
|
|
20095
20181
|
];
|
|
20096
20182
|
for (const dir of directories) {
|
|
20097
|
-
await
|
|
20183
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
20098
20184
|
}
|
|
20099
20185
|
await createInitialConfig(cocoPath, info);
|
|
20100
20186
|
await createProjectState(cocoPath, info);
|
|
@@ -20127,7 +20213,7 @@ async function createInitialConfig(cocoPath, info) {
|
|
|
20127
20213
|
maxCheckpoints: 50
|
|
20128
20214
|
}
|
|
20129
20215
|
};
|
|
20130
|
-
await
|
|
20216
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
20131
20217
|
}
|
|
20132
20218
|
async function createProjectState(cocoPath, info) {
|
|
20133
20219
|
const state = {
|
|
@@ -20144,8 +20230,8 @@ async function createProjectState(cocoPath, info) {
|
|
|
20144
20230
|
qualityHistory: [],
|
|
20145
20231
|
lastCheckpoint: null
|
|
20146
20232
|
};
|
|
20147
|
-
await
|
|
20148
|
-
|
|
20233
|
+
await fs33__default.writeFile(
|
|
20234
|
+
path35__default.join(cocoPath, "state", "project.json"),
|
|
20149
20235
|
JSON.stringify(state, null, 2),
|
|
20150
20236
|
"utf-8"
|
|
20151
20237
|
);
|
|
@@ -20166,7 +20252,7 @@ checkpoints/
|
|
|
20166
20252
|
state/session.json
|
|
20167
20253
|
state/lock.json
|
|
20168
20254
|
`;
|
|
20169
|
-
await
|
|
20255
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, ".gitignore"), content, "utf-8");
|
|
20170
20256
|
}
|
|
20171
20257
|
async function createReadme(cocoPath, info) {
|
|
20172
20258
|
const content = `# Corbat-Coco Project: ${info.name}
|
|
@@ -20213,13 +20299,13 @@ Edit \`config.json\` to customize:
|
|
|
20213
20299
|
---
|
|
20214
20300
|
Generated by Corbat-Coco v0.1.0
|
|
20215
20301
|
`;
|
|
20216
|
-
await
|
|
20302
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, "README.md"), content, "utf-8");
|
|
20217
20303
|
}
|
|
20218
20304
|
|
|
20219
20305
|
// src/cli/commands/init.ts
|
|
20220
20306
|
function registerInitCommand(program2) {
|
|
20221
|
-
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 (
|
|
20222
|
-
await runInit(
|
|
20307
|
+
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 (path55, options) => {
|
|
20308
|
+
await runInit(path55, options);
|
|
20223
20309
|
});
|
|
20224
20310
|
}
|
|
20225
20311
|
async function runInit(projectPath, options) {
|
|
@@ -20298,18 +20384,18 @@ async function gatherProjectInfo() {
|
|
|
20298
20384
|
language
|
|
20299
20385
|
};
|
|
20300
20386
|
}
|
|
20301
|
-
function getDefaultProjectInfo(
|
|
20302
|
-
const name =
|
|
20387
|
+
function getDefaultProjectInfo(path55) {
|
|
20388
|
+
const name = path55 === "." ? "my-project" : path55.split("/").pop() || "my-project";
|
|
20303
20389
|
return {
|
|
20304
20390
|
name,
|
|
20305
20391
|
description: "",
|
|
20306
20392
|
language: "typescript"
|
|
20307
20393
|
};
|
|
20308
20394
|
}
|
|
20309
|
-
async function checkExistingProject(
|
|
20395
|
+
async function checkExistingProject(path55) {
|
|
20310
20396
|
try {
|
|
20311
|
-
const
|
|
20312
|
-
await
|
|
20397
|
+
const fs53 = await import('fs/promises');
|
|
20398
|
+
await fs53.access(`${path55}/.coco`);
|
|
20313
20399
|
return true;
|
|
20314
20400
|
} catch {
|
|
20315
20401
|
return false;
|
|
@@ -21517,13 +21603,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
21517
21603
|
// src/phases/converge/persistence.ts
|
|
21518
21604
|
init_errors();
|
|
21519
21605
|
function getPersistencePaths(projectPath) {
|
|
21520
|
-
const baseDir =
|
|
21606
|
+
const baseDir = path35__default.join(projectPath, ".coco", "spec");
|
|
21521
21607
|
return {
|
|
21522
21608
|
baseDir,
|
|
21523
|
-
sessionFile:
|
|
21524
|
-
specFile:
|
|
21525
|
-
conversationLog:
|
|
21526
|
-
checkpointFile:
|
|
21609
|
+
sessionFile: path35__default.join(baseDir, "discovery-session.json"),
|
|
21610
|
+
specFile: path35__default.join(baseDir, "spec.md"),
|
|
21611
|
+
conversationLog: path35__default.join(baseDir, "conversation.jsonl"),
|
|
21612
|
+
checkpointFile: path35__default.join(baseDir, "checkpoint.json")
|
|
21527
21613
|
};
|
|
21528
21614
|
}
|
|
21529
21615
|
var SessionPersistence = class {
|
|
@@ -21536,7 +21622,7 @@ var SessionPersistence = class {
|
|
|
21536
21622
|
*/
|
|
21537
21623
|
async ensureDir() {
|
|
21538
21624
|
try {
|
|
21539
|
-
await
|
|
21625
|
+
await fs33__default.mkdir(this.paths.baseDir, { recursive: true });
|
|
21540
21626
|
} catch {
|
|
21541
21627
|
throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
|
|
21542
21628
|
path: this.paths.baseDir,
|
|
@@ -21551,7 +21637,7 @@ var SessionPersistence = class {
|
|
|
21551
21637
|
await this.ensureDir();
|
|
21552
21638
|
try {
|
|
21553
21639
|
const data = JSON.stringify(session, null, 2);
|
|
21554
|
-
await
|
|
21640
|
+
await fs33__default.writeFile(this.paths.sessionFile, data, "utf-8");
|
|
21555
21641
|
} catch {
|
|
21556
21642
|
throw new FileSystemError("Failed to save discovery session", {
|
|
21557
21643
|
path: this.paths.sessionFile,
|
|
@@ -21564,7 +21650,7 @@ var SessionPersistence = class {
|
|
|
21564
21650
|
*/
|
|
21565
21651
|
async loadSession() {
|
|
21566
21652
|
try {
|
|
21567
|
-
const data = await
|
|
21653
|
+
const data = await fs33__default.readFile(this.paths.sessionFile, "utf-8");
|
|
21568
21654
|
const parsed = JSON.parse(data);
|
|
21569
21655
|
parsed.startedAt = new Date(parsed.startedAt);
|
|
21570
21656
|
parsed.updatedAt = new Date(parsed.updatedAt);
|
|
@@ -21590,7 +21676,7 @@ var SessionPersistence = class {
|
|
|
21590
21676
|
*/
|
|
21591
21677
|
async hasSession() {
|
|
21592
21678
|
try {
|
|
21593
|
-
await
|
|
21679
|
+
await fs33__default.access(this.paths.sessionFile);
|
|
21594
21680
|
return true;
|
|
21595
21681
|
} catch {
|
|
21596
21682
|
return false;
|
|
@@ -21601,7 +21687,7 @@ var SessionPersistence = class {
|
|
|
21601
21687
|
*/
|
|
21602
21688
|
async deleteSession() {
|
|
21603
21689
|
try {
|
|
21604
|
-
await
|
|
21690
|
+
await fs33__default.unlink(this.paths.sessionFile);
|
|
21605
21691
|
} catch (error) {
|
|
21606
21692
|
if (error.code !== "ENOENT") {
|
|
21607
21693
|
throw new FileSystemError("Failed to delete discovery session", {
|
|
@@ -21617,7 +21703,7 @@ var SessionPersistence = class {
|
|
|
21617
21703
|
async saveSpecification(content) {
|
|
21618
21704
|
await this.ensureDir();
|
|
21619
21705
|
try {
|
|
21620
|
-
await
|
|
21706
|
+
await fs33__default.writeFile(this.paths.specFile, content, "utf-8");
|
|
21621
21707
|
} catch {
|
|
21622
21708
|
throw new FileSystemError("Failed to save specification", {
|
|
21623
21709
|
path: this.paths.specFile,
|
|
@@ -21630,7 +21716,7 @@ var SessionPersistence = class {
|
|
|
21630
21716
|
*/
|
|
21631
21717
|
async loadSpecification() {
|
|
21632
21718
|
try {
|
|
21633
|
-
return await
|
|
21719
|
+
return await fs33__default.readFile(this.paths.specFile, "utf-8");
|
|
21634
21720
|
} catch {
|
|
21635
21721
|
return null;
|
|
21636
21722
|
}
|
|
@@ -21646,7 +21732,7 @@ var SessionPersistence = class {
|
|
|
21646
21732
|
content
|
|
21647
21733
|
};
|
|
21648
21734
|
try {
|
|
21649
|
-
await
|
|
21735
|
+
await fs33__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
|
|
21650
21736
|
} catch {
|
|
21651
21737
|
throw new FileSystemError("Failed to append to conversation log", {
|
|
21652
21738
|
path: this.paths.conversationLog,
|
|
@@ -21659,7 +21745,7 @@ var SessionPersistence = class {
|
|
|
21659
21745
|
*/
|
|
21660
21746
|
async loadConversationLog() {
|
|
21661
21747
|
try {
|
|
21662
|
-
const data = await
|
|
21748
|
+
const data = await fs33__default.readFile(this.paths.conversationLog, "utf-8");
|
|
21663
21749
|
const lines = data.trim().split("\n");
|
|
21664
21750
|
return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
21665
21751
|
} catch {
|
|
@@ -21673,7 +21759,7 @@ var SessionPersistence = class {
|
|
|
21673
21759
|
await this.ensureDir();
|
|
21674
21760
|
try {
|
|
21675
21761
|
const data = JSON.stringify(checkpoint, null, 2);
|
|
21676
|
-
await
|
|
21762
|
+
await fs33__default.writeFile(this.paths.checkpointFile, data, "utf-8");
|
|
21677
21763
|
} catch {
|
|
21678
21764
|
throw new FileSystemError("Failed to save checkpoint", {
|
|
21679
21765
|
path: this.paths.checkpointFile,
|
|
@@ -21686,7 +21772,7 @@ var SessionPersistence = class {
|
|
|
21686
21772
|
*/
|
|
21687
21773
|
async loadCheckpoint() {
|
|
21688
21774
|
try {
|
|
21689
|
-
const data = await
|
|
21775
|
+
const data = await fs33__default.readFile(this.paths.checkpointFile, "utf-8");
|
|
21690
21776
|
const parsed = JSON.parse(data);
|
|
21691
21777
|
parsed.timestamp = new Date(parsed.timestamp);
|
|
21692
21778
|
return parsed;
|
|
@@ -21699,7 +21785,7 @@ var SessionPersistence = class {
|
|
|
21699
21785
|
*/
|
|
21700
21786
|
async clearAll() {
|
|
21701
21787
|
try {
|
|
21702
|
-
await
|
|
21788
|
+
await fs33__default.rm(this.paths.baseDir, { recursive: true, force: true });
|
|
21703
21789
|
} catch (error) {
|
|
21704
21790
|
if (error.code !== "ENOENT") {
|
|
21705
21791
|
throw new FileSystemError("Failed to clear persistence data", {
|
|
@@ -23627,8 +23713,8 @@ var OrchestrateExecutor = class {
|
|
|
23627
23713
|
}
|
|
23628
23714
|
async loadSpecification(projectPath) {
|
|
23629
23715
|
try {
|
|
23630
|
-
const jsonPath =
|
|
23631
|
-
const jsonContent = await
|
|
23716
|
+
const jsonPath = path35__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
23717
|
+
const jsonContent = await fs33__default.readFile(jsonPath, "utf-8");
|
|
23632
23718
|
return JSON.parse(jsonContent);
|
|
23633
23719
|
} catch {
|
|
23634
23720
|
return this.createMinimalSpec(projectPath);
|
|
@@ -23639,7 +23725,7 @@ var OrchestrateExecutor = class {
|
|
|
23639
23725
|
version: "1.0.0",
|
|
23640
23726
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
23641
23727
|
overview: {
|
|
23642
|
-
name:
|
|
23728
|
+
name: path35__default.basename(projectPath),
|
|
23643
23729
|
description: "Project specification",
|
|
23644
23730
|
goals: [],
|
|
23645
23731
|
targetUsers: ["developers"],
|
|
@@ -23666,53 +23752,53 @@ var OrchestrateExecutor = class {
|
|
|
23666
23752
|
};
|
|
23667
23753
|
}
|
|
23668
23754
|
async saveArchitecture(projectPath, architecture) {
|
|
23669
|
-
const dir =
|
|
23670
|
-
await
|
|
23671
|
-
const mdPath =
|
|
23672
|
-
await
|
|
23673
|
-
const jsonPath =
|
|
23674
|
-
await
|
|
23755
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture");
|
|
23756
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23757
|
+
const mdPath = path35__default.join(dir, "ARCHITECTURE.md");
|
|
23758
|
+
await fs33__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
23759
|
+
const jsonPath = path35__default.join(dir, "architecture.json");
|
|
23760
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
23675
23761
|
return mdPath;
|
|
23676
23762
|
}
|
|
23677
23763
|
async saveADRs(projectPath, adrs) {
|
|
23678
|
-
const dir =
|
|
23679
|
-
await
|
|
23764
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
23765
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23680
23766
|
const paths = [];
|
|
23681
|
-
const indexPath =
|
|
23682
|
-
await
|
|
23767
|
+
const indexPath = path35__default.join(dir, "README.md");
|
|
23768
|
+
await fs33__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
23683
23769
|
paths.push(indexPath);
|
|
23684
23770
|
for (const adr of adrs) {
|
|
23685
23771
|
const filename = getADRFilename(adr);
|
|
23686
|
-
const adrPath =
|
|
23687
|
-
await
|
|
23772
|
+
const adrPath = path35__default.join(dir, filename);
|
|
23773
|
+
await fs33__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
23688
23774
|
paths.push(adrPath);
|
|
23689
23775
|
}
|
|
23690
23776
|
return paths;
|
|
23691
23777
|
}
|
|
23692
23778
|
async saveBacklog(projectPath, backlogResult) {
|
|
23693
|
-
const dir =
|
|
23694
|
-
await
|
|
23695
|
-
const mdPath =
|
|
23696
|
-
await
|
|
23697
|
-
const jsonPath =
|
|
23698
|
-
await
|
|
23779
|
+
const dir = path35__default.join(projectPath, ".coco", "planning");
|
|
23780
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23781
|
+
const mdPath = path35__default.join(dir, "BACKLOG.md");
|
|
23782
|
+
await fs33__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
23783
|
+
const jsonPath = path35__default.join(dir, "backlog.json");
|
|
23784
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
23699
23785
|
return mdPath;
|
|
23700
23786
|
}
|
|
23701
23787
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
23702
|
-
const dir =
|
|
23703
|
-
await
|
|
23788
|
+
const dir = path35__default.join(projectPath, ".coco", "planning", "sprints");
|
|
23789
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23704
23790
|
const filename = `${sprint.id}.md`;
|
|
23705
|
-
const sprintPath =
|
|
23706
|
-
await
|
|
23707
|
-
const jsonPath =
|
|
23708
|
-
await
|
|
23791
|
+
const sprintPath = path35__default.join(dir, filename);
|
|
23792
|
+
await fs33__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
23793
|
+
const jsonPath = path35__default.join(dir, `${sprint.id}.json`);
|
|
23794
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
23709
23795
|
return sprintPath;
|
|
23710
23796
|
}
|
|
23711
23797
|
async saveDiagram(projectPath, id, mermaid) {
|
|
23712
|
-
const dir =
|
|
23713
|
-
await
|
|
23714
|
-
const diagramPath =
|
|
23715
|
-
await
|
|
23798
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
23799
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23800
|
+
const diagramPath = path35__default.join(dir, `${id}.mmd`);
|
|
23801
|
+
await fs33__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
23716
23802
|
return diagramPath;
|
|
23717
23803
|
}
|
|
23718
23804
|
};
|
|
@@ -23857,20 +23943,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
23857
23943
|
},
|
|
23858
23944
|
tools: {
|
|
23859
23945
|
file: {
|
|
23860
|
-
async read(
|
|
23861
|
-
const
|
|
23862
|
-
return
|
|
23946
|
+
async read(path55) {
|
|
23947
|
+
const fs53 = await import('fs/promises');
|
|
23948
|
+
return fs53.readFile(path55, "utf-8");
|
|
23863
23949
|
},
|
|
23864
|
-
async write(
|
|
23865
|
-
const
|
|
23950
|
+
async write(path55, content) {
|
|
23951
|
+
const fs53 = await import('fs/promises');
|
|
23866
23952
|
const nodePath = await import('path');
|
|
23867
|
-
await
|
|
23868
|
-
await
|
|
23953
|
+
await fs53.mkdir(nodePath.dirname(path55), { recursive: true });
|
|
23954
|
+
await fs53.writeFile(path55, content, "utf-8");
|
|
23869
23955
|
},
|
|
23870
|
-
async exists(
|
|
23871
|
-
const
|
|
23956
|
+
async exists(path55) {
|
|
23957
|
+
const fs53 = await import('fs/promises');
|
|
23872
23958
|
try {
|
|
23873
|
-
await
|
|
23959
|
+
await fs53.access(path55);
|
|
23874
23960
|
return true;
|
|
23875
23961
|
} catch {
|
|
23876
23962
|
return false;
|
|
@@ -24109,16 +24195,16 @@ async function loadTasks(_options) {
|
|
|
24109
24195
|
];
|
|
24110
24196
|
}
|
|
24111
24197
|
async function checkProjectState() {
|
|
24112
|
-
const
|
|
24198
|
+
const fs53 = await import('fs/promises');
|
|
24113
24199
|
let hasProject = false;
|
|
24114
24200
|
let hasPlan = false;
|
|
24115
24201
|
try {
|
|
24116
|
-
await
|
|
24202
|
+
await fs53.access(".coco");
|
|
24117
24203
|
hasProject = true;
|
|
24118
24204
|
} catch {
|
|
24119
24205
|
}
|
|
24120
24206
|
try {
|
|
24121
|
-
await
|
|
24207
|
+
await fs53.access(".coco/planning/backlog.json");
|
|
24122
24208
|
hasPlan = true;
|
|
24123
24209
|
} catch {
|
|
24124
24210
|
}
|
|
@@ -24225,24 +24311,24 @@ function getPhaseStatusForPhase(phase) {
|
|
|
24225
24311
|
return "in_progress";
|
|
24226
24312
|
}
|
|
24227
24313
|
async function loadProjectState(cwd, config) {
|
|
24228
|
-
const
|
|
24229
|
-
const
|
|
24230
|
-
const statePath =
|
|
24231
|
-
const backlogPath =
|
|
24232
|
-
const checkpointDir =
|
|
24314
|
+
const fs53 = await import('fs/promises');
|
|
24315
|
+
const path55 = await import('path');
|
|
24316
|
+
const statePath = path55.join(cwd, ".coco", "state.json");
|
|
24317
|
+
const backlogPath = path55.join(cwd, ".coco", "planning", "backlog.json");
|
|
24318
|
+
const checkpointDir = path55.join(cwd, ".coco", "checkpoints");
|
|
24233
24319
|
let currentPhase = "idle";
|
|
24234
24320
|
let metrics;
|
|
24235
24321
|
let sprint;
|
|
24236
24322
|
let checkpoints = [];
|
|
24237
24323
|
try {
|
|
24238
|
-
const stateContent = await
|
|
24324
|
+
const stateContent = await fs53.readFile(statePath, "utf-8");
|
|
24239
24325
|
const stateData = JSON.parse(stateContent);
|
|
24240
24326
|
currentPhase = stateData.currentPhase || "idle";
|
|
24241
24327
|
metrics = stateData.metrics;
|
|
24242
24328
|
} catch {
|
|
24243
24329
|
}
|
|
24244
24330
|
try {
|
|
24245
|
-
const backlogContent = await
|
|
24331
|
+
const backlogContent = await fs53.readFile(backlogPath, "utf-8");
|
|
24246
24332
|
const backlogData = JSON.parse(backlogContent);
|
|
24247
24333
|
if (backlogData.currentSprint) {
|
|
24248
24334
|
const tasks = backlogData.tasks || [];
|
|
@@ -24264,7 +24350,7 @@ async function loadProjectState(cwd, config) {
|
|
|
24264
24350
|
} catch {
|
|
24265
24351
|
}
|
|
24266
24352
|
try {
|
|
24267
|
-
const files = await
|
|
24353
|
+
const files = await fs53.readdir(checkpointDir);
|
|
24268
24354
|
checkpoints = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
24269
24355
|
} catch {
|
|
24270
24356
|
}
|
|
@@ -24400,8 +24486,8 @@ async function restoreFromCheckpoint(_checkpoint) {
|
|
|
24400
24486
|
}
|
|
24401
24487
|
async function checkProjectExists() {
|
|
24402
24488
|
try {
|
|
24403
|
-
const
|
|
24404
|
-
await
|
|
24489
|
+
const fs53 = await import('fs/promises');
|
|
24490
|
+
await fs53.access(".coco");
|
|
24405
24491
|
return true;
|
|
24406
24492
|
} catch {
|
|
24407
24493
|
return false;
|
|
@@ -25440,9 +25526,9 @@ var DEFAULT_CONFIG2 = {
|
|
|
25440
25526
|
}
|
|
25441
25527
|
};
|
|
25442
25528
|
async function loadConfig2() {
|
|
25443
|
-
const
|
|
25529
|
+
const fs53 = await import('fs/promises');
|
|
25444
25530
|
try {
|
|
25445
|
-
const raw = await
|
|
25531
|
+
const raw = await fs53.readFile(CONFIG_PATH, "utf-8");
|
|
25446
25532
|
const parsed = JSON.parse(raw);
|
|
25447
25533
|
return { ...DEFAULT_CONFIG2, ...parsed };
|
|
25448
25534
|
} catch {
|
|
@@ -25450,13 +25536,13 @@ async function loadConfig2() {
|
|
|
25450
25536
|
}
|
|
25451
25537
|
}
|
|
25452
25538
|
async function saveConfig2(config) {
|
|
25453
|
-
const
|
|
25539
|
+
const fs53 = await import('fs/promises');
|
|
25454
25540
|
const dir = join(CONFIG_PATH, "..");
|
|
25455
|
-
await
|
|
25456
|
-
await
|
|
25541
|
+
await fs53.mkdir(dir, { recursive: true });
|
|
25542
|
+
await fs53.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
25457
25543
|
}
|
|
25458
|
-
function getNestedValue(obj,
|
|
25459
|
-
const keys =
|
|
25544
|
+
function getNestedValue(obj, path55) {
|
|
25545
|
+
const keys = path55.split(".");
|
|
25460
25546
|
let current = obj;
|
|
25461
25547
|
for (const key of keys) {
|
|
25462
25548
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -25466,8 +25552,8 @@ function getNestedValue(obj, path54) {
|
|
|
25466
25552
|
}
|
|
25467
25553
|
return current;
|
|
25468
25554
|
}
|
|
25469
|
-
function setNestedValue(obj,
|
|
25470
|
-
const keys =
|
|
25555
|
+
function setNestedValue(obj, path55, value) {
|
|
25556
|
+
const keys = path55.split(".");
|
|
25471
25557
|
let current = obj;
|
|
25472
25558
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
25473
25559
|
const key = keys[i];
|
|
@@ -25807,13 +25893,13 @@ async function runAdd(source, options) {
|
|
|
25807
25893
|
const isGithubShorthand = source.includes("/") && !isGitUrl;
|
|
25808
25894
|
const isLocalPath = source.startsWith(".") || source.startsWith("/");
|
|
25809
25895
|
if (isLocalPath) {
|
|
25810
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25811
|
-
const sourcePath =
|
|
25812
|
-
const skillName =
|
|
25813
|
-
const destPath =
|
|
25896
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
25897
|
+
const sourcePath = path35__default.resolve(source);
|
|
25898
|
+
const skillName = path35__default.basename(sourcePath);
|
|
25899
|
+
const destPath = path35__default.join(targetDir, skillName);
|
|
25814
25900
|
try {
|
|
25815
|
-
await
|
|
25816
|
-
await
|
|
25901
|
+
await fs33__default.mkdir(targetDir, { recursive: true });
|
|
25902
|
+
await fs33__default.cp(sourcePath, destPath, { recursive: true });
|
|
25817
25903
|
p25.log.success(`Installed "${skillName}" to ${destPath}`);
|
|
25818
25904
|
} catch (error) {
|
|
25819
25905
|
p25.log.error(
|
|
@@ -25843,10 +25929,10 @@ async function runAdd(source, options) {
|
|
|
25843
25929
|
p25.log.info("Try installing manually: git clone the repo into .coco/skills/");
|
|
25844
25930
|
}
|
|
25845
25931
|
} else if (isGitUrl) {
|
|
25846
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25847
|
-
await
|
|
25932
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
25933
|
+
await fs33__default.mkdir(targetDir, { recursive: true });
|
|
25848
25934
|
const skillName = source.split("/").pop()?.replace(".git", "") ?? "skill";
|
|
25849
|
-
const skillDir =
|
|
25935
|
+
const skillDir = path35__default.join(targetDir, skillName);
|
|
25850
25936
|
const spinner19 = p25.spinner();
|
|
25851
25937
|
spinner19.start(`Cloning ${source}...`);
|
|
25852
25938
|
try {
|
|
@@ -25871,10 +25957,10 @@ async function runAdd(source, options) {
|
|
|
25871
25957
|
}
|
|
25872
25958
|
async function runRemove(name, options) {
|
|
25873
25959
|
p25.intro(chalk25.magenta("Remove Skill"));
|
|
25874
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25875
|
-
const skillPath =
|
|
25960
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
25961
|
+
const skillPath = path35__default.join(targetDir, name);
|
|
25876
25962
|
try {
|
|
25877
|
-
await
|
|
25963
|
+
await fs33__default.access(skillPath);
|
|
25878
25964
|
} catch {
|
|
25879
25965
|
p25.log.error(`Skill "${name}" not found at ${skillPath}`);
|
|
25880
25966
|
p25.outro("");
|
|
@@ -25890,7 +25976,7 @@ async function runRemove(name, options) {
|
|
|
25890
25976
|
return;
|
|
25891
25977
|
}
|
|
25892
25978
|
}
|
|
25893
|
-
await
|
|
25979
|
+
await fs33__default.rm(skillPath, { recursive: true });
|
|
25894
25980
|
p25.log.success(`Removed "${name}"`);
|
|
25895
25981
|
p25.outro("");
|
|
25896
25982
|
}
|
|
@@ -25951,10 +26037,10 @@ async function runInfo(name) {
|
|
|
25951
26037
|
}
|
|
25952
26038
|
async function runCreate(name, options) {
|
|
25953
26039
|
p25.intro(chalk25.magenta("Create Skill"));
|
|
25954
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25955
|
-
const skillDir =
|
|
26040
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
26041
|
+
const skillDir = path35__default.join(targetDir, name);
|
|
25956
26042
|
try {
|
|
25957
|
-
await
|
|
26043
|
+
await fs33__default.access(skillDir);
|
|
25958
26044
|
p25.log.error(`Skill "${name}" already exists at ${skillDir}`);
|
|
25959
26045
|
p25.outro("");
|
|
25960
26046
|
return;
|
|
@@ -25983,7 +26069,7 @@ async function runCreate(name, options) {
|
|
|
25983
26069
|
p25.outro("Cancelled.");
|
|
25984
26070
|
return;
|
|
25985
26071
|
}
|
|
25986
|
-
await
|
|
26072
|
+
await fs33__default.mkdir(skillDir, { recursive: true });
|
|
25987
26073
|
const skillMd = `---
|
|
25988
26074
|
name: "${name}"
|
|
25989
26075
|
description: "${description}"
|
|
@@ -26005,10 +26091,10 @@ when this skill is activated (automatically via matching or manually via /${name
|
|
|
26005
26091
|
2. Include examples when helpful
|
|
26006
26092
|
3. Keep instructions under 500 lines
|
|
26007
26093
|
`;
|
|
26008
|
-
await
|
|
26009
|
-
await
|
|
26094
|
+
await fs33__default.writeFile(path35__default.join(skillDir, "SKILL.md"), skillMd, "utf-8");
|
|
26095
|
+
await fs33__default.mkdir(path35__default.join(skillDir, "references"), { recursive: true });
|
|
26010
26096
|
p25.log.success(`Created skill at ${skillDir}`);
|
|
26011
|
-
p25.log.info(`Edit ${
|
|
26097
|
+
p25.log.info(`Edit ${path35__default.join(skillDir, "SKILL.md")} to add instructions.`);
|
|
26012
26098
|
p25.outro("");
|
|
26013
26099
|
}
|
|
26014
26100
|
|
|
@@ -26372,10 +26458,10 @@ function registerCheckCommand(program2) {
|
|
|
26372
26458
|
|
|
26373
26459
|
// src/swarm/spec-parser.ts
|
|
26374
26460
|
async function parseSwarmSpec(filePath) {
|
|
26375
|
-
const
|
|
26376
|
-
const
|
|
26377
|
-
const rawContent = await
|
|
26378
|
-
const ext =
|
|
26461
|
+
const fs53 = await import('fs/promises');
|
|
26462
|
+
const path55 = await import('path');
|
|
26463
|
+
const rawContent = await fs53.readFile(filePath, "utf-8");
|
|
26464
|
+
const ext = path55.extname(filePath).toLowerCase();
|
|
26379
26465
|
if (ext === ".yaml" || ext === ".yml") {
|
|
26380
26466
|
return parseYamlSpec(rawContent);
|
|
26381
26467
|
}
|
|
@@ -26704,11 +26790,11 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
26704
26790
|
integrator: { maxTurns: 20, temperature: 0.2 }
|
|
26705
26791
|
};
|
|
26706
26792
|
async function loadAgentConfig(projectPath) {
|
|
26707
|
-
const
|
|
26708
|
-
const
|
|
26709
|
-
const configPath =
|
|
26793
|
+
const fs53 = await import('fs/promises');
|
|
26794
|
+
const path55 = await import('path');
|
|
26795
|
+
const configPath = path55.join(projectPath, ".coco", "swarm", "agents.json");
|
|
26710
26796
|
try {
|
|
26711
|
-
const raw = await
|
|
26797
|
+
const raw = await fs53.readFile(configPath, "utf-8");
|
|
26712
26798
|
const parsed = JSON.parse(raw);
|
|
26713
26799
|
const merged = { ...DEFAULT_AGENT_CONFIG };
|
|
26714
26800
|
for (const role of Object.keys(DEFAULT_AGENT_CONFIG)) {
|
|
@@ -26896,19 +26982,19 @@ async function createBoard(projectPath, spec) {
|
|
|
26896
26982
|
return board;
|
|
26897
26983
|
}
|
|
26898
26984
|
async function loadBoard(projectPath) {
|
|
26899
|
-
const
|
|
26900
|
-
const
|
|
26901
|
-
const boardPath =
|
|
26902
|
-
const raw = await
|
|
26985
|
+
const fs53 = await import('fs/promises');
|
|
26986
|
+
const path55 = await import('path');
|
|
26987
|
+
const boardPath = path55.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
26988
|
+
const raw = await fs53.readFile(boardPath, "utf-8");
|
|
26903
26989
|
return JSON.parse(raw);
|
|
26904
26990
|
}
|
|
26905
26991
|
async function saveBoard(projectPath, board) {
|
|
26906
|
-
const
|
|
26907
|
-
const
|
|
26908
|
-
const boardDir =
|
|
26909
|
-
const boardPath =
|
|
26910
|
-
await
|
|
26911
|
-
await
|
|
26992
|
+
const fs53 = await import('fs/promises');
|
|
26993
|
+
const path55 = await import('path');
|
|
26994
|
+
const boardDir = path55.join(projectPath, ".coco", "swarm");
|
|
26995
|
+
const boardPath = path55.join(boardDir, "task-board.json");
|
|
26996
|
+
await fs53.mkdir(boardDir, { recursive: true });
|
|
26997
|
+
await fs53.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
26912
26998
|
}
|
|
26913
26999
|
function markTaskInProgress(board, taskId, role) {
|
|
26914
27000
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27073,11 +27159,11 @@ async function defaultPromptHandler(q) {
|
|
|
27073
27159
|
}
|
|
27074
27160
|
}
|
|
27075
27161
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
27076
|
-
const
|
|
27077
|
-
const
|
|
27078
|
-
const swarmDir =
|
|
27079
|
-
const assumptionsPath =
|
|
27080
|
-
await
|
|
27162
|
+
const fs53 = await import('fs/promises');
|
|
27163
|
+
const path55 = await import('path');
|
|
27164
|
+
const swarmDir = path55.join(projectPath, ".coco", "swarm");
|
|
27165
|
+
const assumptionsPath = path55.join(swarmDir, "assumptions.md");
|
|
27166
|
+
await fs53.mkdir(swarmDir, { recursive: true });
|
|
27081
27167
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
27082
27168
|
const content = [
|
|
27083
27169
|
`# Swarm Assumptions \u2014 ${projectName}`,
|
|
@@ -27093,18 +27179,18 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
27093
27179
|
assumptions.length > 0 ? assumptions.join("\n\n") : `_(none)_`,
|
|
27094
27180
|
``
|
|
27095
27181
|
].join("\n");
|
|
27096
|
-
await
|
|
27182
|
+
await fs53.writeFile(assumptionsPath, content, "utf-8");
|
|
27097
27183
|
return assumptionsPath;
|
|
27098
27184
|
}
|
|
27099
27185
|
|
|
27100
27186
|
// src/swarm/events.ts
|
|
27101
27187
|
async function appendSwarmEvent(projectPath, event) {
|
|
27102
|
-
const
|
|
27103
|
-
const
|
|
27104
|
-
const eventsDir =
|
|
27105
|
-
const eventsFile =
|
|
27106
|
-
await
|
|
27107
|
-
await
|
|
27188
|
+
const fs53 = await import('fs/promises');
|
|
27189
|
+
const path55 = await import('path');
|
|
27190
|
+
const eventsDir = path55.join(projectPath, ".coco", "swarm");
|
|
27191
|
+
const eventsFile = path55.join(eventsDir, "events.jsonl");
|
|
27192
|
+
await fs53.mkdir(eventsDir, { recursive: true });
|
|
27193
|
+
await fs53.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
27108
27194
|
}
|
|
27109
27195
|
function createEventId() {
|
|
27110
27196
|
return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -27112,12 +27198,12 @@ function createEventId() {
|
|
|
27112
27198
|
|
|
27113
27199
|
// src/swarm/knowledge.ts
|
|
27114
27200
|
async function appendKnowledge(projectPath, entry) {
|
|
27115
|
-
const
|
|
27116
|
-
const
|
|
27117
|
-
const knowledgeDir =
|
|
27118
|
-
const knowledgeFile =
|
|
27119
|
-
await
|
|
27120
|
-
await
|
|
27201
|
+
const fs53 = await import('fs/promises');
|
|
27202
|
+
const path55 = await import('path');
|
|
27203
|
+
const knowledgeDir = path55.join(projectPath, ".coco", "swarm");
|
|
27204
|
+
const knowledgeFile = path55.join(knowledgeDir, "knowledge.jsonl");
|
|
27205
|
+
await fs53.mkdir(knowledgeDir, { recursive: true });
|
|
27206
|
+
await fs53.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
27121
27207
|
}
|
|
27122
27208
|
|
|
27123
27209
|
// src/swarm/agents/prompts.ts
|
|
@@ -27421,11 +27507,11 @@ async function runSwarmLifecycle(options) {
|
|
|
27421
27507
|
}
|
|
27422
27508
|
async function stageInit(ctx) {
|
|
27423
27509
|
const { projectPath, spec } = ctx.options;
|
|
27424
|
-
const
|
|
27425
|
-
const
|
|
27426
|
-
await
|
|
27427
|
-
await
|
|
27428
|
-
const specSummaryPath =
|
|
27510
|
+
const fs53 = await import('fs/promises');
|
|
27511
|
+
const path55 = await import('path');
|
|
27512
|
+
await fs53.mkdir(path55.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
27513
|
+
await fs53.mkdir(ctx.options.outputPath, { recursive: true });
|
|
27514
|
+
const specSummaryPath = path55.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
27429
27515
|
const specSummary = {
|
|
27430
27516
|
projectName: spec.projectName,
|
|
27431
27517
|
description: spec.description,
|
|
@@ -27439,7 +27525,7 @@ async function stageInit(ctx) {
|
|
|
27439
27525
|
})),
|
|
27440
27526
|
qualityConfig: spec.qualityConfig
|
|
27441
27527
|
};
|
|
27442
|
-
await
|
|
27528
|
+
await fs53.writeFile(specSummaryPath, JSON.stringify(specSummary, null, 2), "utf-8");
|
|
27443
27529
|
await emitEvent(projectPath, {
|
|
27444
27530
|
agentRole: "pm",
|
|
27445
27531
|
agentTurn: 0,
|
|
@@ -27496,10 +27582,10 @@ async function stagePlan(ctx) {
|
|
|
27496
27582
|
})
|
|
27497
27583
|
]);
|
|
27498
27584
|
await createBoard(projectPath, spec);
|
|
27499
|
-
const
|
|
27500
|
-
const
|
|
27501
|
-
const planPath =
|
|
27502
|
-
await
|
|
27585
|
+
const fs53 = await import('fs/promises');
|
|
27586
|
+
const path55 = await import('path');
|
|
27587
|
+
const planPath = path55.join(projectPath, ".coco", "swarm", "plan.json");
|
|
27588
|
+
await fs53.writeFile(
|
|
27503
27589
|
planPath,
|
|
27504
27590
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
27505
27591
|
"utf-8"
|
|
@@ -27714,8 +27800,8 @@ async function stageIntegrate(ctx) {
|
|
|
27714
27800
|
}
|
|
27715
27801
|
async function stageOutput(ctx) {
|
|
27716
27802
|
const { projectPath, outputPath } = ctx.options;
|
|
27717
|
-
const
|
|
27718
|
-
const
|
|
27803
|
+
const fs53 = await import('fs/promises');
|
|
27804
|
+
const path55 = await import('path');
|
|
27719
27805
|
const board = await loadBoard(projectPath);
|
|
27720
27806
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
27721
27807
|
const summary = {
|
|
@@ -27729,9 +27815,9 @@ async function stageOutput(ctx) {
|
|
|
27729
27815
|
},
|
|
27730
27816
|
globalScore: computeGlobalScore(featureResults)
|
|
27731
27817
|
};
|
|
27732
|
-
await
|
|
27733
|
-
const summaryPath =
|
|
27734
|
-
await
|
|
27818
|
+
await fs53.mkdir(outputPath, { recursive: true });
|
|
27819
|
+
const summaryPath = path55.join(outputPath, "swarm-summary.json");
|
|
27820
|
+
await fs53.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
27735
27821
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
27736
27822
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
27737
27823
|
await emitEvent(projectPath, {
|
|
@@ -28077,8 +28163,8 @@ var SwarmOrchestrator = class {
|
|
|
28077
28163
|
noQuestions = false,
|
|
28078
28164
|
onProgress
|
|
28079
28165
|
} = options;
|
|
28080
|
-
const
|
|
28081
|
-
const projectPath =
|
|
28166
|
+
const path55 = await import('path');
|
|
28167
|
+
const projectPath = path55.dirname(path55.resolve(specFile));
|
|
28082
28168
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
28083
28169
|
const spec = await parseSwarmSpec(specFile);
|
|
28084
28170
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -28089,7 +28175,7 @@ var SwarmOrchestrator = class {
|
|
|
28089
28175
|
await runSwarmLifecycle({
|
|
28090
28176
|
spec,
|
|
28091
28177
|
projectPath,
|
|
28092
|
-
outputPath:
|
|
28178
|
+
outputPath: path55.resolve(outputPath),
|
|
28093
28179
|
provider,
|
|
28094
28180
|
agentConfig,
|
|
28095
28181
|
minScore,
|
|
@@ -29589,15 +29675,15 @@ async function saveConfiguration(result) {
|
|
|
29589
29675
|
}
|
|
29590
29676
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
29591
29677
|
if (createDir) {
|
|
29592
|
-
const dir =
|
|
29678
|
+
const dir = path35.dirname(filePath);
|
|
29593
29679
|
try {
|
|
29594
|
-
await
|
|
29680
|
+
await fs33.mkdir(dir, { recursive: true, mode: 448 });
|
|
29595
29681
|
} catch {
|
|
29596
29682
|
}
|
|
29597
29683
|
}
|
|
29598
29684
|
let existingVars = {};
|
|
29599
29685
|
try {
|
|
29600
|
-
const content = await
|
|
29686
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
29601
29687
|
for (const line of content.split("\n")) {
|
|
29602
29688
|
const trimmed = line.trim();
|
|
29603
29689
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -29620,7 +29706,7 @@ async function saveEnvVars(filePath, vars, createDir = false) {
|
|
|
29620
29706
|
for (const [key, value] of Object.entries(allVars)) {
|
|
29621
29707
|
lines.push(`${key}=${value}`);
|
|
29622
29708
|
}
|
|
29623
|
-
await
|
|
29709
|
+
await fs33.writeFile(filePath, lines.join("\n") + "\n", { mode: 384 });
|
|
29624
29710
|
}
|
|
29625
29711
|
async function handleLocalProviderUnavailable(providerType, config) {
|
|
29626
29712
|
const cfg = LOCAL_PROVIDER_CONFIG[providerType];
|
|
@@ -30727,8 +30813,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
30727
30813
|
p25.log.message("");
|
|
30728
30814
|
for (const project of projects) {
|
|
30729
30815
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
30730
|
-
const
|
|
30731
|
-
p25.log.message(` [${level}] ${
|
|
30816
|
+
const path55 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
30817
|
+
p25.log.message(` [${level}] ${path55}`);
|
|
30732
30818
|
p25.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
30733
30819
|
}
|
|
30734
30820
|
p25.log.message("");
|
|
@@ -30966,8 +31052,8 @@ var buildCommand = {
|
|
|
30966
31052
|
};
|
|
30967
31053
|
async function loadBacklog(projectPath) {
|
|
30968
31054
|
try {
|
|
30969
|
-
const backlogPath =
|
|
30970
|
-
const content = await
|
|
31055
|
+
const backlogPath = path35.join(projectPath, ".coco", "planning", "backlog.json");
|
|
31056
|
+
const content = await fs33.readFile(backlogPath, "utf-8");
|
|
30971
31057
|
const data = JSON.parse(content);
|
|
30972
31058
|
return data.backlog;
|
|
30973
31059
|
} catch {
|
|
@@ -30976,25 +31062,25 @@ async function loadBacklog(projectPath) {
|
|
|
30976
31062
|
}
|
|
30977
31063
|
async function loadSprint(projectPath, sprintId) {
|
|
30978
31064
|
try {
|
|
30979
|
-
const sprintsDir =
|
|
30980
|
-
const files = await
|
|
31065
|
+
const sprintsDir = path35.join(projectPath, ".coco", "planning", "sprints");
|
|
31066
|
+
const files = await fs33.readdir(sprintsDir);
|
|
30981
31067
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
30982
31068
|
if (jsonFiles.length === 0) return null;
|
|
30983
31069
|
const targetFile = sprintId ? jsonFiles.find((f) => f.includes(sprintId)) : jsonFiles[0];
|
|
30984
31070
|
if (!targetFile) return null;
|
|
30985
|
-
const sprintPath =
|
|
30986
|
-
const content = await
|
|
31071
|
+
const sprintPath = path35.join(sprintsDir, targetFile);
|
|
31072
|
+
const content = await fs33.readFile(sprintPath, "utf-8");
|
|
30987
31073
|
return JSON.parse(content);
|
|
30988
31074
|
} catch {
|
|
30989
31075
|
return null;
|
|
30990
31076
|
}
|
|
30991
31077
|
}
|
|
30992
31078
|
async function saveBacklog(projectPath, backlog) {
|
|
30993
|
-
const backlogPath =
|
|
30994
|
-
const content = await
|
|
31079
|
+
const backlogPath = path35.join(projectPath, ".coco", "planning", "backlog.json");
|
|
31080
|
+
const content = await fs33.readFile(backlogPath, "utf-8");
|
|
30995
31081
|
const data = JSON.parse(content);
|
|
30996
31082
|
data.backlog = backlog;
|
|
30997
|
-
await
|
|
31083
|
+
await fs33.writeFile(backlogPath, JSON.stringify(data, null, 2), "utf-8");
|
|
30998
31084
|
}
|
|
30999
31085
|
function getStatusEmoji(status) {
|
|
31000
31086
|
const emojis = {
|
|
@@ -31905,7 +31991,7 @@ async function getCheckpoint(session, checkpointId) {
|
|
|
31905
31991
|
return store.checkpoints.find((cp) => cp.id === checkpointId) ?? null;
|
|
31906
31992
|
}
|
|
31907
31993
|
async function restoreFiles(checkpoint, excludeFiles) {
|
|
31908
|
-
const
|
|
31994
|
+
const fs53 = await import('fs/promises');
|
|
31909
31995
|
const restored = [];
|
|
31910
31996
|
const failed = [];
|
|
31911
31997
|
for (const fileCheckpoint of checkpoint.files) {
|
|
@@ -31913,7 +31999,7 @@ async function restoreFiles(checkpoint, excludeFiles) {
|
|
|
31913
31999
|
continue;
|
|
31914
32000
|
}
|
|
31915
32001
|
try {
|
|
31916
|
-
await
|
|
32002
|
+
await fs53.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
|
|
31917
32003
|
restored.push(fileCheckpoint.filePath);
|
|
31918
32004
|
} catch (error) {
|
|
31919
32005
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -31995,8 +32081,8 @@ function displayRewindResult(result) {
|
|
|
31995
32081
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
31996
32082
|
console.log(`${chalk25.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
31997
32083
|
}
|
|
31998
|
-
for (const { path:
|
|
31999
|
-
const fileName =
|
|
32084
|
+
for (const { path: path55, error } of result.filesFailed) {
|
|
32085
|
+
const fileName = path55.split("/").pop() ?? path55;
|
|
32000
32086
|
console.log(`${chalk25.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
32001
32087
|
}
|
|
32002
32088
|
if (result.conversationRestored) {
|
|
@@ -32634,8 +32720,8 @@ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@corbat-tech/coco/latest";
|
|
|
32634
32720
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
32635
32721
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
32636
32722
|
var STARTUP_TIMEOUT_MS = 5500;
|
|
32637
|
-
var CACHE_DIR =
|
|
32638
|
-
var CACHE_FILE =
|
|
32723
|
+
var CACHE_DIR = path35__default.join(os4__default.homedir(), ".coco");
|
|
32724
|
+
var CACHE_FILE = path35__default.join(CACHE_DIR, "version-check-cache.json");
|
|
32639
32725
|
function compareVersions(a, b) {
|
|
32640
32726
|
const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
32641
32727
|
const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
@@ -33488,8 +33574,8 @@ function formatToolSummary(toolName, input) {
|
|
|
33488
33574
|
case "grep":
|
|
33489
33575
|
case "search_files": {
|
|
33490
33576
|
const pattern = String(input.pattern || "");
|
|
33491
|
-
const
|
|
33492
|
-
return `"${pattern}"${
|
|
33577
|
+
const path55 = input.path ? ` in ${input.path}` : "";
|
|
33578
|
+
return `"${pattern}"${path55}`;
|
|
33493
33579
|
}
|
|
33494
33580
|
case "bash_exec": {
|
|
33495
33581
|
const cmd = String(input.command || "");
|
|
@@ -33703,7 +33789,7 @@ async function readClipboardImage() {
|
|
|
33703
33789
|
return null;
|
|
33704
33790
|
}
|
|
33705
33791
|
async function readClipboardImageMacOS() {
|
|
33706
|
-
const tmpFile =
|
|
33792
|
+
const tmpFile = path35.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
33707
33793
|
try {
|
|
33708
33794
|
const script = `
|
|
33709
33795
|
set theFile to POSIX file "${tmpFile}"
|
|
@@ -33724,7 +33810,7 @@ end try
|
|
|
33724
33810
|
if (!result.startsWith("ok")) {
|
|
33725
33811
|
return null;
|
|
33726
33812
|
}
|
|
33727
|
-
const buffer = await
|
|
33813
|
+
const buffer = await fs33.readFile(tmpFile);
|
|
33728
33814
|
return {
|
|
33729
33815
|
data: buffer.toString("base64"),
|
|
33730
33816
|
media_type: "image/png"
|
|
@@ -33733,7 +33819,7 @@ end try
|
|
|
33733
33819
|
return null;
|
|
33734
33820
|
} finally {
|
|
33735
33821
|
try {
|
|
33736
|
-
await
|
|
33822
|
+
await fs33.unlink(tmpFile);
|
|
33737
33823
|
} catch {
|
|
33738
33824
|
}
|
|
33739
33825
|
}
|
|
@@ -33759,7 +33845,7 @@ async function readClipboardImageLinux() {
|
|
|
33759
33845
|
}
|
|
33760
33846
|
}
|
|
33761
33847
|
async function readClipboardImageWindows() {
|
|
33762
|
-
const tmpFile =
|
|
33848
|
+
const tmpFile = path35.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
33763
33849
|
try {
|
|
33764
33850
|
const escapedPath = tmpFile.replace(/'/g, "''");
|
|
33765
33851
|
const script = `
|
|
@@ -33777,7 +33863,7 @@ if ($img -ne $null) {
|
|
|
33777
33863
|
timeout: 1e4
|
|
33778
33864
|
}).trim();
|
|
33779
33865
|
if (result !== "ok") return null;
|
|
33780
|
-
const buffer = await
|
|
33866
|
+
const buffer = await fs33.readFile(tmpFile);
|
|
33781
33867
|
return {
|
|
33782
33868
|
data: buffer.toString("base64"),
|
|
33783
33869
|
media_type: "image/png"
|
|
@@ -33786,7 +33872,7 @@ if ($img -ne $null) {
|
|
|
33786
33872
|
return null;
|
|
33787
33873
|
} finally {
|
|
33788
33874
|
try {
|
|
33789
|
-
await
|
|
33875
|
+
await fs33.unlink(tmpFile);
|
|
33790
33876
|
} catch {
|
|
33791
33877
|
}
|
|
33792
33878
|
}
|
|
@@ -33874,9 +33960,9 @@ var allowPathCommand = {
|
|
|
33874
33960
|
}
|
|
33875
33961
|
};
|
|
33876
33962
|
async function addPath(dirPath, session) {
|
|
33877
|
-
const absolute =
|
|
33963
|
+
const absolute = path35__default.resolve(dirPath);
|
|
33878
33964
|
try {
|
|
33879
|
-
const stat2 = await
|
|
33965
|
+
const stat2 = await fs33__default.stat(absolute);
|
|
33880
33966
|
if (!stat2.isDirectory()) {
|
|
33881
33967
|
p25.log.error(`Not a directory: ${absolute}`);
|
|
33882
33968
|
return;
|
|
@@ -33886,19 +33972,19 @@ async function addPath(dirPath, session) {
|
|
|
33886
33972
|
return;
|
|
33887
33973
|
}
|
|
33888
33974
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
33889
|
-
const normalizedBlocked =
|
|
33890
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
33975
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
33976
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
33891
33977
|
p25.log.error(`System path '${blocked}' cannot be allowed`);
|
|
33892
33978
|
return;
|
|
33893
33979
|
}
|
|
33894
33980
|
}
|
|
33895
|
-
const normalizedCwd =
|
|
33896
|
-
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd +
|
|
33981
|
+
const normalizedCwd = path35__default.normalize(session.projectPath);
|
|
33982
|
+
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd + path35__default.sep)) {
|
|
33897
33983
|
p25.log.info("That path is already within the project directory");
|
|
33898
33984
|
return;
|
|
33899
33985
|
}
|
|
33900
33986
|
const existing = getAllowedPaths();
|
|
33901
|
-
if (existing.some((e) =>
|
|
33987
|
+
if (existing.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
33902
33988
|
p25.log.info(`Already allowed: ${absolute}`);
|
|
33903
33989
|
return;
|
|
33904
33990
|
}
|
|
@@ -33969,7 +34055,7 @@ async function revokePath(dirPath, _session) {
|
|
|
33969
34055
|
}
|
|
33970
34056
|
dirPath = selected;
|
|
33971
34057
|
}
|
|
33972
|
-
const absolute =
|
|
34058
|
+
const absolute = path35__default.resolve(dirPath);
|
|
33973
34059
|
const removed = removeAllowedPathFromSession(absolute);
|
|
33974
34060
|
await removePersistedAllowedPath(absolute);
|
|
33975
34061
|
if (removed) {
|
|
@@ -34322,7 +34408,7 @@ var RECOMMENDED_DENY = [
|
|
|
34322
34408
|
];
|
|
34323
34409
|
async function loadPermissionPreferences() {
|
|
34324
34410
|
try {
|
|
34325
|
-
const content = await
|
|
34411
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34326
34412
|
const config = JSON.parse(content);
|
|
34327
34413
|
return {
|
|
34328
34414
|
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
@@ -34336,13 +34422,13 @@ async function savePermissionPreference(key, value) {
|
|
|
34336
34422
|
try {
|
|
34337
34423
|
let config = {};
|
|
34338
34424
|
try {
|
|
34339
|
-
const content = await
|
|
34425
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34340
34426
|
config = JSON.parse(content);
|
|
34341
34427
|
} catch {
|
|
34342
34428
|
}
|
|
34343
34429
|
config[key] = value;
|
|
34344
|
-
await
|
|
34345
|
-
await
|
|
34430
|
+
await fs33__default.mkdir(path35__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
34431
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
34346
34432
|
} catch {
|
|
34347
34433
|
}
|
|
34348
34434
|
}
|
|
@@ -34576,7 +34662,7 @@ async function resetPermissions(session) {
|
|
|
34576
34662
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34577
34663
|
};
|
|
34578
34664
|
try {
|
|
34579
|
-
await
|
|
34665
|
+
await fs33__default.writeFile(CONFIG_PATHS.trustedTools, JSON.stringify(emptySettings, null, 2), "utf-8");
|
|
34580
34666
|
} catch {
|
|
34581
34667
|
}
|
|
34582
34668
|
await savePermissionPreference("recommendedAllowlistApplied", false);
|
|
@@ -34658,7 +34744,7 @@ function formatQualityResult(result) {
|
|
|
34658
34744
|
}
|
|
34659
34745
|
async function loadQualityLoopPreference() {
|
|
34660
34746
|
try {
|
|
34661
|
-
const content = await
|
|
34747
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34662
34748
|
const config = JSON.parse(content);
|
|
34663
34749
|
const value = config.qualityLoop ?? config.cocoMode;
|
|
34664
34750
|
if (typeof value === "boolean") {
|
|
@@ -34673,12 +34759,12 @@ async function saveQualityLoopPreference(enabled) {
|
|
|
34673
34759
|
try {
|
|
34674
34760
|
let config = {};
|
|
34675
34761
|
try {
|
|
34676
|
-
const content = await
|
|
34762
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34677
34763
|
config = JSON.parse(content);
|
|
34678
34764
|
} catch {
|
|
34679
34765
|
}
|
|
34680
34766
|
config.qualityLoop = enabled;
|
|
34681
|
-
await
|
|
34767
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
34682
34768
|
} catch {
|
|
34683
34769
|
}
|
|
34684
34770
|
}
|
|
@@ -35514,9 +35600,9 @@ Response format (JSON only, no prose):
|
|
|
35514
35600
|
cancel5("Build cancelled.");
|
|
35515
35601
|
}
|
|
35516
35602
|
}
|
|
35517
|
-
const cocoDir =
|
|
35518
|
-
await
|
|
35519
|
-
await
|
|
35603
|
+
const cocoDir = path35__default.join(outputPath, ".coco");
|
|
35604
|
+
await fs33__default.mkdir(cocoDir, { recursive: true });
|
|
35605
|
+
await fs33__default.writeFile(path35__default.join(cocoDir, "backlog.json"), JSON.stringify(spec, null, 2), "utf-8");
|
|
35520
35606
|
p25.outro(" Spec saved \u2014 starting sprints");
|
|
35521
35607
|
return spec;
|
|
35522
35608
|
}
|
|
@@ -36066,8 +36152,8 @@ init_errors();
|
|
|
36066
36152
|
init_subprocess_registry();
|
|
36067
36153
|
async function detectTestFramework2(cwd) {
|
|
36068
36154
|
try {
|
|
36069
|
-
const pkgPath =
|
|
36070
|
-
const pkgContent = await
|
|
36155
|
+
const pkgPath = path35__default.join(cwd, "package.json");
|
|
36156
|
+
const pkgContent = await fs33__default.readFile(pkgPath, "utf-8");
|
|
36071
36157
|
const pkg = JSON.parse(pkgContent);
|
|
36072
36158
|
const deps = {
|
|
36073
36159
|
...pkg.dependencies,
|
|
@@ -36155,8 +36241,9 @@ Examples:
|
|
|
36155
36241
|
duration
|
|
36156
36242
|
);
|
|
36157
36243
|
} catch (error) {
|
|
36244
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
36158
36245
|
throw new ToolError(
|
|
36159
|
-
`Test execution failed: ${
|
|
36246
|
+
`Test execution failed: ${msg}. Use command_exists to verify the test framework is installed, or run_script with a custom command.`,
|
|
36160
36247
|
{ tool: "run_tests", cause: error instanceof Error ? error : void 0 }
|
|
36161
36248
|
);
|
|
36162
36249
|
}
|
|
@@ -36247,13 +36334,13 @@ Examples:
|
|
|
36247
36334
|
const projectDir = cwd ?? process.cwd();
|
|
36248
36335
|
try {
|
|
36249
36336
|
const coverageLocations = [
|
|
36250
|
-
|
|
36251
|
-
|
|
36252
|
-
|
|
36337
|
+
path35__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
36338
|
+
path35__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
36339
|
+
path35__default.join(projectDir, ".nyc_output", "coverage-summary.json")
|
|
36253
36340
|
];
|
|
36254
36341
|
for (const location of coverageLocations) {
|
|
36255
36342
|
try {
|
|
36256
|
-
const content = await
|
|
36343
|
+
const content = await fs33__default.readFile(location, "utf-8");
|
|
36257
36344
|
const coverage = JSON.parse(content);
|
|
36258
36345
|
if (coverage.total) {
|
|
36259
36346
|
return {
|
|
@@ -36272,8 +36359,9 @@ Examples:
|
|
|
36272
36359
|
});
|
|
36273
36360
|
} catch (error) {
|
|
36274
36361
|
if (error instanceof ToolError) throw error;
|
|
36362
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
36275
36363
|
throw new ToolError(
|
|
36276
|
-
`Failed to read coverage: ${
|
|
36364
|
+
`Failed to read coverage: ${msg}. Run run_tests with coverage: true first to generate coverage data.`,
|
|
36277
36365
|
{ tool: "get_coverage", cause: error instanceof Error ? error : void 0 }
|
|
36278
36366
|
);
|
|
36279
36367
|
}
|
|
@@ -36311,6 +36399,61 @@ init_registry4();
|
|
|
36311
36399
|
init_registry4();
|
|
36312
36400
|
init_errors();
|
|
36313
36401
|
init_allowed_paths();
|
|
36402
|
+
|
|
36403
|
+
// src/utils/file-suggestions.ts
|
|
36404
|
+
init_matcher();
|
|
36405
|
+
var MAX_DIR_ENTRIES = 200;
|
|
36406
|
+
var MAX_SUGGESTIONS = 5;
|
|
36407
|
+
async function suggestSimilarFiles(missingPath, options) {
|
|
36408
|
+
const absPath = path35__default.resolve(missingPath);
|
|
36409
|
+
const dir = path35__default.dirname(absPath);
|
|
36410
|
+
const target = path35__default.basename(absPath);
|
|
36411
|
+
const maxResults = MAX_SUGGESTIONS;
|
|
36412
|
+
try {
|
|
36413
|
+
const entries = await fs33__default.readdir(dir);
|
|
36414
|
+
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
36415
|
+
const scored = limited.map((name) => ({
|
|
36416
|
+
path: path35__default.join(dir, name),
|
|
36417
|
+
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
36418
|
+
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
36419
|
+
return scored.slice(0, maxResults);
|
|
36420
|
+
} catch {
|
|
36421
|
+
return [];
|
|
36422
|
+
}
|
|
36423
|
+
}
|
|
36424
|
+
async function suggestSimilarPaths(missingPath, options) {
|
|
36425
|
+
const fileSuggestions = await suggestSimilarFiles(missingPath);
|
|
36426
|
+
if (fileSuggestions.length > 0) return fileSuggestions;
|
|
36427
|
+
const absPath = path35__default.resolve(missingPath);
|
|
36428
|
+
const grandparent = path35__default.dirname(path35__default.dirname(absPath));
|
|
36429
|
+
const parentBasename = path35__default.basename(path35__default.dirname(absPath));
|
|
36430
|
+
const maxResults = MAX_SUGGESTIONS;
|
|
36431
|
+
try {
|
|
36432
|
+
const entries = await fs33__default.readdir(grandparent, { withFileTypes: true });
|
|
36433
|
+
const dirs = entries.filter((e) => e.isDirectory()).slice(0, MAX_DIR_ENTRIES);
|
|
36434
|
+
const scored = dirs.map((d) => ({
|
|
36435
|
+
path: path35__default.join(grandparent, d.name),
|
|
36436
|
+
distance: levenshtein(parentBasename.toLowerCase(), d.name.toLowerCase())
|
|
36437
|
+
})).filter((s) => s.distance <= Math.max(parentBasename.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
36438
|
+
return scored.slice(0, maxResults);
|
|
36439
|
+
} catch {
|
|
36440
|
+
return [];
|
|
36441
|
+
}
|
|
36442
|
+
}
|
|
36443
|
+
function formatSuggestions(suggestions, baseDir) {
|
|
36444
|
+
if (suggestions.length === 0) return "";
|
|
36445
|
+
const base = baseDir ?? process.cwd();
|
|
36446
|
+
const lines = suggestions.map((s) => {
|
|
36447
|
+
const rel = path35__default.relative(base, s.path);
|
|
36448
|
+
return ` - ${rel}`;
|
|
36449
|
+
});
|
|
36450
|
+
return `
|
|
36451
|
+
Did you mean?
|
|
36452
|
+
${lines.join("\n")}`;
|
|
36453
|
+
}
|
|
36454
|
+
|
|
36455
|
+
// src/tools/file.ts
|
|
36456
|
+
init_matcher();
|
|
36314
36457
|
var SENSITIVE_PATTERNS = [
|
|
36315
36458
|
/\.env(?:\.\w+)?$/,
|
|
36316
36459
|
// .env, .env.local, etc.
|
|
@@ -36335,7 +36478,7 @@ function hasNullByte2(str) {
|
|
|
36335
36478
|
}
|
|
36336
36479
|
function normalizePath2(filePath) {
|
|
36337
36480
|
let normalized = filePath.replace(/\0/g, "");
|
|
36338
|
-
normalized =
|
|
36481
|
+
normalized = path35__default.normalize(normalized);
|
|
36339
36482
|
return normalized;
|
|
36340
36483
|
}
|
|
36341
36484
|
function isPathAllowed(filePath, operation) {
|
|
@@ -36343,31 +36486,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
36343
36486
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
36344
36487
|
}
|
|
36345
36488
|
const normalized = normalizePath2(filePath);
|
|
36346
|
-
const absolute =
|
|
36489
|
+
const absolute = path35__default.resolve(normalized);
|
|
36347
36490
|
const cwd = process.cwd();
|
|
36348
36491
|
for (const blocked of BLOCKED_PATHS2) {
|
|
36349
|
-
const normalizedBlocked =
|
|
36350
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
36492
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
36493
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
36351
36494
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
36352
36495
|
}
|
|
36353
36496
|
}
|
|
36354
36497
|
const home = process.env.HOME;
|
|
36355
36498
|
if (home) {
|
|
36356
|
-
const normalizedHome =
|
|
36357
|
-
const normalizedCwd =
|
|
36499
|
+
const normalizedHome = path35__default.normalize(home);
|
|
36500
|
+
const normalizedCwd = path35__default.normalize(cwd);
|
|
36358
36501
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
36359
36502
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
36360
36503
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
36361
|
-
const basename4 =
|
|
36504
|
+
const basename4 = path35__default.basename(absolute);
|
|
36362
36505
|
if (!allowedHomeReads.includes(basename4)) {
|
|
36363
|
-
const targetDir =
|
|
36506
|
+
const targetDir = path35__default.dirname(absolute);
|
|
36364
36507
|
return {
|
|
36365
36508
|
allowed: false,
|
|
36366
36509
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
36367
36510
|
};
|
|
36368
36511
|
}
|
|
36369
36512
|
} else {
|
|
36370
|
-
const targetDir =
|
|
36513
|
+
const targetDir = path35__default.dirname(absolute);
|
|
36371
36514
|
return {
|
|
36372
36515
|
allowed: false,
|
|
36373
36516
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -36376,7 +36519,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
36376
36519
|
}
|
|
36377
36520
|
}
|
|
36378
36521
|
if (operation === "write" || operation === "delete") {
|
|
36379
|
-
const basename4 =
|
|
36522
|
+
const basename4 = path35__default.basename(absolute);
|
|
36380
36523
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
36381
36524
|
if (pattern.test(basename4)) {
|
|
36382
36525
|
return {
|
|
@@ -36395,6 +36538,24 @@ function validatePath(filePath, operation) {
|
|
|
36395
36538
|
}
|
|
36396
36539
|
}
|
|
36397
36540
|
var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
36541
|
+
function isENOENT(error) {
|
|
36542
|
+
return error.code === "ENOENT";
|
|
36543
|
+
}
|
|
36544
|
+
async function enrichENOENT(filePath, operation) {
|
|
36545
|
+
const absPath = path35__default.resolve(filePath);
|
|
36546
|
+
const suggestions = await suggestSimilarFiles(absPath);
|
|
36547
|
+
const hint = formatSuggestions(suggestions, path35__default.dirname(absPath));
|
|
36548
|
+
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
36549
|
+
return `File not found: ${filePath}${hint}
|
|
36550
|
+
${action}`;
|
|
36551
|
+
}
|
|
36552
|
+
async function enrichDirENOENT(dirPath) {
|
|
36553
|
+
const absPath = path35__default.resolve(dirPath);
|
|
36554
|
+
const suggestions = await suggestSimilarPaths(absPath);
|
|
36555
|
+
const hint = formatSuggestions(suggestions, path35__default.dirname(absPath));
|
|
36556
|
+
return `Directory not found: ${dirPath}${hint}
|
|
36557
|
+
Use list_dir or glob to find the correct path.`;
|
|
36558
|
+
}
|
|
36398
36559
|
var readFileTool = defineTool({
|
|
36399
36560
|
name: "read_file",
|
|
36400
36561
|
description: `Read the contents of a file.
|
|
@@ -36412,13 +36573,13 @@ Examples:
|
|
|
36412
36573
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
36413
36574
|
validatePath(filePath, "read");
|
|
36414
36575
|
try {
|
|
36415
|
-
const absolutePath =
|
|
36416
|
-
const stats = await
|
|
36576
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36577
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36417
36578
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
36418
36579
|
let truncated = false;
|
|
36419
36580
|
let content;
|
|
36420
36581
|
if (stats.size > maxBytes) {
|
|
36421
|
-
const handle = await
|
|
36582
|
+
const handle = await fs33__default.open(absolutePath, "r");
|
|
36422
36583
|
try {
|
|
36423
36584
|
const buffer = Buffer.alloc(maxBytes);
|
|
36424
36585
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -36428,7 +36589,7 @@ Examples:
|
|
|
36428
36589
|
await handle.close();
|
|
36429
36590
|
}
|
|
36430
36591
|
} else {
|
|
36431
|
-
content = await
|
|
36592
|
+
content = await fs33__default.readFile(absolutePath, encoding);
|
|
36432
36593
|
}
|
|
36433
36594
|
return {
|
|
36434
36595
|
content,
|
|
@@ -36437,6 +36598,14 @@ Examples:
|
|
|
36437
36598
|
truncated
|
|
36438
36599
|
};
|
|
36439
36600
|
} catch (error) {
|
|
36601
|
+
if (isENOENT(error)) {
|
|
36602
|
+
const enriched = await enrichENOENT(filePath, "read");
|
|
36603
|
+
throw new FileSystemError(enriched, {
|
|
36604
|
+
path: filePath,
|
|
36605
|
+
operation: "read",
|
|
36606
|
+
cause: error instanceof Error ? error : void 0
|
|
36607
|
+
});
|
|
36608
|
+
}
|
|
36440
36609
|
throw new FileSystemError(`Failed to read file: ${filePath}`, {
|
|
36441
36610
|
path: filePath,
|
|
36442
36611
|
operation: "read",
|
|
@@ -36463,10 +36632,10 @@ Examples:
|
|
|
36463
36632
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
36464
36633
|
validatePath(filePath, "write");
|
|
36465
36634
|
try {
|
|
36466
|
-
const absolutePath =
|
|
36635
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36467
36636
|
let wouldCreate = false;
|
|
36468
36637
|
try {
|
|
36469
|
-
await
|
|
36638
|
+
await fs33__default.access(absolutePath);
|
|
36470
36639
|
} catch {
|
|
36471
36640
|
wouldCreate = true;
|
|
36472
36641
|
}
|
|
@@ -36479,10 +36648,10 @@ Examples:
|
|
|
36479
36648
|
};
|
|
36480
36649
|
}
|
|
36481
36650
|
if (createDirs) {
|
|
36482
|
-
await
|
|
36651
|
+
await fs33__default.mkdir(path35__default.dirname(absolutePath), { recursive: true });
|
|
36483
36652
|
}
|
|
36484
|
-
await
|
|
36485
|
-
const stats = await
|
|
36653
|
+
await fs33__default.writeFile(absolutePath, content, "utf-8");
|
|
36654
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36486
36655
|
return {
|
|
36487
36656
|
path: absolutePath,
|
|
36488
36657
|
size: stats.size,
|
|
@@ -36490,6 +36659,14 @@ Examples:
|
|
|
36490
36659
|
wouldCreate
|
|
36491
36660
|
};
|
|
36492
36661
|
} catch (error) {
|
|
36662
|
+
if (isENOENT(error)) {
|
|
36663
|
+
const enriched = await enrichENOENT(filePath, "write");
|
|
36664
|
+
throw new FileSystemError(enriched, {
|
|
36665
|
+
path: filePath,
|
|
36666
|
+
operation: "write",
|
|
36667
|
+
cause: error instanceof Error ? error : void 0
|
|
36668
|
+
});
|
|
36669
|
+
}
|
|
36493
36670
|
throw new FileSystemError(`Failed to write file: ${filePath}`, {
|
|
36494
36671
|
path: filePath,
|
|
36495
36672
|
operation: "write",
|
|
@@ -36517,8 +36694,8 @@ Examples:
|
|
|
36517
36694
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
36518
36695
|
validatePath(filePath, "write");
|
|
36519
36696
|
try {
|
|
36520
|
-
const absolutePath =
|
|
36521
|
-
let content = await
|
|
36697
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36698
|
+
let content = await fs33__default.readFile(absolutePath, "utf-8");
|
|
36522
36699
|
let replacements = 0;
|
|
36523
36700
|
if (all) {
|
|
36524
36701
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -36532,7 +36709,31 @@ Examples:
|
|
|
36532
36709
|
}
|
|
36533
36710
|
}
|
|
36534
36711
|
if (replacements === 0) {
|
|
36535
|
-
|
|
36712
|
+
const lines = content.split("\n");
|
|
36713
|
+
const searchLine = (oldText.split("\n")[0] ?? oldText).trim().slice(0, 80);
|
|
36714
|
+
let bestIdx = -1;
|
|
36715
|
+
let bestDist = Infinity;
|
|
36716
|
+
for (let i = 0; i < lines.length; i++) {
|
|
36717
|
+
const dist = levenshtein(lines[i].trim().slice(0, 80), searchLine);
|
|
36718
|
+
if (dist < bestDist) {
|
|
36719
|
+
bestDist = dist;
|
|
36720
|
+
bestIdx = i;
|
|
36721
|
+
}
|
|
36722
|
+
}
|
|
36723
|
+
let context = "";
|
|
36724
|
+
if (bestIdx >= 0 && bestDist < searchLine.length * 0.6) {
|
|
36725
|
+
const start = Math.max(0, bestIdx - 2);
|
|
36726
|
+
const end = Math.min(lines.length, bestIdx + 3);
|
|
36727
|
+
const snippet = lines.slice(start, end).map((l, i) => ` ${start + i + 1}: ${l}`).join("\n");
|
|
36728
|
+
context = `
|
|
36729
|
+
|
|
36730
|
+
Closest match near line ${bestIdx + 1}:
|
|
36731
|
+
${snippet}`;
|
|
36732
|
+
}
|
|
36733
|
+
throw new Error(
|
|
36734
|
+
`Text not found in file: "${oldText.slice(0, 50)}..."${context}
|
|
36735
|
+
Hint: Use read_file first to verify the exact content.`
|
|
36736
|
+
);
|
|
36536
36737
|
}
|
|
36537
36738
|
if (dryRun) {
|
|
36538
36739
|
const preview = content.length > 500 ? content.slice(0, 500) + "..." : content;
|
|
@@ -36543,7 +36744,7 @@ Examples:
|
|
|
36543
36744
|
preview
|
|
36544
36745
|
};
|
|
36545
36746
|
}
|
|
36546
|
-
await
|
|
36747
|
+
await fs33__default.writeFile(absolutePath, content, "utf-8");
|
|
36547
36748
|
return {
|
|
36548
36749
|
path: absolutePath,
|
|
36549
36750
|
replacements,
|
|
@@ -36584,6 +36785,14 @@ Examples:
|
|
|
36584
36785
|
count: files.length
|
|
36585
36786
|
};
|
|
36586
36787
|
} catch (error) {
|
|
36788
|
+
if (isENOENT(error) && cwd) {
|
|
36789
|
+
const enriched = await enrichDirENOENT(cwd);
|
|
36790
|
+
throw new FileSystemError(`Glob search failed \u2014 ${enriched}`, {
|
|
36791
|
+
path: cwd,
|
|
36792
|
+
operation: "glob",
|
|
36793
|
+
cause: error instanceof Error ? error : void 0
|
|
36794
|
+
});
|
|
36795
|
+
}
|
|
36587
36796
|
throw new FileSystemError(`Glob search failed: ${pattern}`, {
|
|
36588
36797
|
path: cwd ?? process.cwd(),
|
|
36589
36798
|
operation: "glob",
|
|
@@ -36606,8 +36815,8 @@ Examples:
|
|
|
36606
36815
|
}),
|
|
36607
36816
|
async execute({ path: filePath }) {
|
|
36608
36817
|
try {
|
|
36609
|
-
const absolutePath =
|
|
36610
|
-
const stats = await
|
|
36818
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36819
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36611
36820
|
return {
|
|
36612
36821
|
exists: true,
|
|
36613
36822
|
isFile: stats.isFile(),
|
|
@@ -36637,12 +36846,12 @@ Examples:
|
|
|
36637
36846
|
}),
|
|
36638
36847
|
async execute({ path: dirPath, recursive }) {
|
|
36639
36848
|
try {
|
|
36640
|
-
const absolutePath =
|
|
36849
|
+
const absolutePath = path35__default.resolve(dirPath);
|
|
36641
36850
|
const entries = [];
|
|
36642
36851
|
async function listDir(dir, prefix = "") {
|
|
36643
|
-
const items = await
|
|
36852
|
+
const items = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
36644
36853
|
for (const item of items) {
|
|
36645
|
-
const fullPath =
|
|
36854
|
+
const fullPath = path35__default.join(dir, item.name);
|
|
36646
36855
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
36647
36856
|
if (item.isDirectory()) {
|
|
36648
36857
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -36650,7 +36859,7 @@ Examples:
|
|
|
36650
36859
|
await listDir(fullPath, relativePath);
|
|
36651
36860
|
}
|
|
36652
36861
|
} else if (item.isFile()) {
|
|
36653
|
-
const stats = await
|
|
36862
|
+
const stats = await fs33__default.stat(fullPath);
|
|
36654
36863
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
36655
36864
|
}
|
|
36656
36865
|
}
|
|
@@ -36658,6 +36867,14 @@ Examples:
|
|
|
36658
36867
|
await listDir(absolutePath);
|
|
36659
36868
|
return { entries };
|
|
36660
36869
|
} catch (error) {
|
|
36870
|
+
if (isENOENT(error)) {
|
|
36871
|
+
const enriched = await enrichDirENOENT(dirPath);
|
|
36872
|
+
throw new FileSystemError(enriched, {
|
|
36873
|
+
path: dirPath,
|
|
36874
|
+
operation: "read",
|
|
36875
|
+
cause: error instanceof Error ? error : void 0
|
|
36876
|
+
});
|
|
36877
|
+
}
|
|
36661
36878
|
throw new FileSystemError(`Failed to list directory: ${dirPath}`, {
|
|
36662
36879
|
path: dirPath,
|
|
36663
36880
|
operation: "read",
|
|
@@ -36689,23 +36906,23 @@ Examples:
|
|
|
36689
36906
|
}
|
|
36690
36907
|
validatePath(filePath, "delete");
|
|
36691
36908
|
try {
|
|
36692
|
-
const absolutePath =
|
|
36693
|
-
const stats = await
|
|
36909
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36910
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36694
36911
|
if (stats.isDirectory()) {
|
|
36695
36912
|
if (!recursive) {
|
|
36696
36913
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
36697
36914
|
tool: "delete_file"
|
|
36698
36915
|
});
|
|
36699
36916
|
}
|
|
36700
|
-
await
|
|
36917
|
+
await fs33__default.rm(absolutePath, { recursive: true });
|
|
36701
36918
|
} else {
|
|
36702
|
-
await
|
|
36919
|
+
await fs33__default.unlink(absolutePath);
|
|
36703
36920
|
}
|
|
36704
36921
|
return { deleted: true, path: absolutePath };
|
|
36705
36922
|
} catch (error) {
|
|
36706
36923
|
if (error instanceof ToolError) throw error;
|
|
36707
36924
|
if (error.code === "ENOENT") {
|
|
36708
|
-
return { deleted: false, path:
|
|
36925
|
+
return { deleted: false, path: path35__default.resolve(filePath) };
|
|
36709
36926
|
}
|
|
36710
36927
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
36711
36928
|
path: filePath,
|
|
@@ -36733,11 +36950,11 @@ Examples:
|
|
|
36733
36950
|
validatePath(source, "read");
|
|
36734
36951
|
validatePath(destination, "write");
|
|
36735
36952
|
try {
|
|
36736
|
-
const srcPath =
|
|
36737
|
-
const destPath =
|
|
36953
|
+
const srcPath = path35__default.resolve(source);
|
|
36954
|
+
const destPath = path35__default.resolve(destination);
|
|
36738
36955
|
if (!overwrite) {
|
|
36739
36956
|
try {
|
|
36740
|
-
await
|
|
36957
|
+
await fs33__default.access(destPath);
|
|
36741
36958
|
throw new ToolError(
|
|
36742
36959
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
36743
36960
|
{
|
|
@@ -36750,9 +36967,9 @@ Examples:
|
|
|
36750
36967
|
}
|
|
36751
36968
|
}
|
|
36752
36969
|
}
|
|
36753
|
-
await
|
|
36754
|
-
await
|
|
36755
|
-
const stats = await
|
|
36970
|
+
await fs33__default.mkdir(path35__default.dirname(destPath), { recursive: true });
|
|
36971
|
+
await fs33__default.copyFile(srcPath, destPath);
|
|
36972
|
+
const stats = await fs33__default.stat(destPath);
|
|
36756
36973
|
return {
|
|
36757
36974
|
source: srcPath,
|
|
36758
36975
|
destination: destPath,
|
|
@@ -36760,6 +36977,14 @@ Examples:
|
|
|
36760
36977
|
};
|
|
36761
36978
|
} catch (error) {
|
|
36762
36979
|
if (error instanceof ToolError) throw error;
|
|
36980
|
+
if (isENOENT(error)) {
|
|
36981
|
+
const enriched = await enrichENOENT(source, "read");
|
|
36982
|
+
throw new FileSystemError(`Failed to copy \u2014 ${enriched}`, {
|
|
36983
|
+
path: source,
|
|
36984
|
+
operation: "read",
|
|
36985
|
+
cause: error instanceof Error ? error : void 0
|
|
36986
|
+
});
|
|
36987
|
+
}
|
|
36763
36988
|
throw new FileSystemError(`Failed to copy file: ${source} -> ${destination}`, {
|
|
36764
36989
|
path: source,
|
|
36765
36990
|
operation: "read",
|
|
@@ -36786,11 +37011,11 @@ Examples:
|
|
|
36786
37011
|
validatePath(source, "delete");
|
|
36787
37012
|
validatePath(destination, "write");
|
|
36788
37013
|
try {
|
|
36789
|
-
const srcPath =
|
|
36790
|
-
const destPath =
|
|
37014
|
+
const srcPath = path35__default.resolve(source);
|
|
37015
|
+
const destPath = path35__default.resolve(destination);
|
|
36791
37016
|
if (!overwrite) {
|
|
36792
37017
|
try {
|
|
36793
|
-
await
|
|
37018
|
+
await fs33__default.access(destPath);
|
|
36794
37019
|
throw new ToolError(
|
|
36795
37020
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
36796
37021
|
{
|
|
@@ -36803,14 +37028,22 @@ Examples:
|
|
|
36803
37028
|
}
|
|
36804
37029
|
}
|
|
36805
37030
|
}
|
|
36806
|
-
await
|
|
36807
|
-
await
|
|
37031
|
+
await fs33__default.mkdir(path35__default.dirname(destPath), { recursive: true });
|
|
37032
|
+
await fs33__default.rename(srcPath, destPath);
|
|
36808
37033
|
return {
|
|
36809
37034
|
source: srcPath,
|
|
36810
37035
|
destination: destPath
|
|
36811
37036
|
};
|
|
36812
37037
|
} catch (error) {
|
|
36813
37038
|
if (error instanceof ToolError) throw error;
|
|
37039
|
+
if (isENOENT(error)) {
|
|
37040
|
+
const enriched = await enrichENOENT(source, "read");
|
|
37041
|
+
throw new FileSystemError(`Failed to move \u2014 ${enriched}`, {
|
|
37042
|
+
path: source,
|
|
37043
|
+
operation: "write",
|
|
37044
|
+
cause: error instanceof Error ? error : void 0
|
|
37045
|
+
});
|
|
37046
|
+
}
|
|
36814
37047
|
throw new FileSystemError(`Failed to move file: ${source} -> ${destination}`, {
|
|
36815
37048
|
path: source,
|
|
36816
37049
|
operation: "write",
|
|
@@ -36838,13 +37071,13 @@ Examples:
|
|
|
36838
37071
|
}),
|
|
36839
37072
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
36840
37073
|
try {
|
|
36841
|
-
const absolutePath =
|
|
37074
|
+
const absolutePath = path35__default.resolve(dirPath ?? ".");
|
|
36842
37075
|
let totalFiles = 0;
|
|
36843
37076
|
let totalDirs = 0;
|
|
36844
|
-
const lines = [
|
|
37077
|
+
const lines = [path35__default.basename(absolutePath) + "/"];
|
|
36845
37078
|
async function buildTree(dir, prefix, currentDepth) {
|
|
36846
37079
|
if (currentDepth > (depth ?? 4)) return;
|
|
36847
|
-
let items = await
|
|
37080
|
+
let items = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
36848
37081
|
if (!showHidden) {
|
|
36849
37082
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
36850
37083
|
}
|
|
@@ -36864,7 +37097,7 @@ Examples:
|
|
|
36864
37097
|
if (item.isDirectory()) {
|
|
36865
37098
|
totalDirs++;
|
|
36866
37099
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
36867
|
-
await buildTree(
|
|
37100
|
+
await buildTree(path35__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
36868
37101
|
} else {
|
|
36869
37102
|
totalFiles++;
|
|
36870
37103
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -36878,6 +37111,14 @@ Examples:
|
|
|
36878
37111
|
totalDirs
|
|
36879
37112
|
};
|
|
36880
37113
|
} catch (error) {
|
|
37114
|
+
if (isENOENT(error)) {
|
|
37115
|
+
const enriched = await enrichDirENOENT(dirPath ?? ".");
|
|
37116
|
+
throw new FileSystemError(enriched, {
|
|
37117
|
+
path: dirPath ?? ".",
|
|
37118
|
+
operation: "read",
|
|
37119
|
+
cause: error instanceof Error ? error : void 0
|
|
37120
|
+
});
|
|
37121
|
+
}
|
|
36881
37122
|
throw new FileSystemError(`Failed to generate tree: ${dirPath}`, {
|
|
36882
37123
|
path: dirPath ?? ".",
|
|
36883
37124
|
operation: "read",
|
|
@@ -37185,7 +37426,7 @@ Examples:
|
|
|
37185
37426
|
caseSensitive,
|
|
37186
37427
|
wholeWord
|
|
37187
37428
|
}) {
|
|
37188
|
-
const targetPath = searchPath ?
|
|
37429
|
+
const targetPath = searchPath ? path35__default.resolve(searchPath) : process.cwd();
|
|
37189
37430
|
const matches = [];
|
|
37190
37431
|
let filesSearched = 0;
|
|
37191
37432
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -37207,7 +37448,7 @@ Examples:
|
|
|
37207
37448
|
tool: "grep"
|
|
37208
37449
|
});
|
|
37209
37450
|
}
|
|
37210
|
-
const stats = await
|
|
37451
|
+
const stats = await fs33__default.stat(targetPath);
|
|
37211
37452
|
let filesToSearch;
|
|
37212
37453
|
if (stats.isFile()) {
|
|
37213
37454
|
filesToSearch = [targetPath];
|
|
@@ -37229,7 +37470,7 @@ Examples:
|
|
|
37229
37470
|
}
|
|
37230
37471
|
filesSearched++;
|
|
37231
37472
|
try {
|
|
37232
|
-
const content = await
|
|
37473
|
+
const content = await fs33__default.readFile(file, "utf-8");
|
|
37233
37474
|
const lines = content.split("\n");
|
|
37234
37475
|
let fileHasMatch = false;
|
|
37235
37476
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -37252,7 +37493,7 @@ Examples:
|
|
|
37252
37493
|
contextAfter.push(lines[j] ?? "");
|
|
37253
37494
|
}
|
|
37254
37495
|
matches.push({
|
|
37255
|
-
file:
|
|
37496
|
+
file: path35__default.relative(process.cwd(), file),
|
|
37256
37497
|
line: i + 1,
|
|
37257
37498
|
column: match.index + 1,
|
|
37258
37499
|
content: line,
|
|
@@ -37303,8 +37544,8 @@ Examples:
|
|
|
37303
37544
|
}),
|
|
37304
37545
|
async execute({ file, pattern, caseSensitive }) {
|
|
37305
37546
|
try {
|
|
37306
|
-
const absolutePath =
|
|
37307
|
-
const content = await
|
|
37547
|
+
const absolutePath = path35__default.resolve(file);
|
|
37548
|
+
const content = await fs33__default.readFile(absolutePath, "utf-8");
|
|
37308
37549
|
const lines = content.split("\n");
|
|
37309
37550
|
const matches = [];
|
|
37310
37551
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -37320,6 +37561,11 @@ Examples:
|
|
|
37320
37561
|
}
|
|
37321
37562
|
return { matches, count: matches.length };
|
|
37322
37563
|
} catch (error) {
|
|
37564
|
+
if (error.code === "ENOENT") {
|
|
37565
|
+
throw new ToolError(`File not found: ${file}. Use glob to find the correct path.`, {
|
|
37566
|
+
tool: "find_in_file"
|
|
37567
|
+
});
|
|
37568
|
+
}
|
|
37323
37569
|
throw new ToolError(
|
|
37324
37570
|
`Find in file failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
37325
37571
|
{ tool: "find_in_file", cause: error instanceof Error ? error : void 0 }
|
|
@@ -37480,6 +37726,22 @@ init_registry4();
|
|
|
37480
37726
|
init_errors();
|
|
37481
37727
|
var DEFAULT_TIMEOUT_MS3 = 6e5;
|
|
37482
37728
|
var MAX_OUTPUT_SIZE2 = 2 * 1024 * 1024;
|
|
37729
|
+
function getBuildHint(stderr, tool) {
|
|
37730
|
+
if (/MODULE_NOT_FOUND|Cannot find module/i.test(stderr))
|
|
37731
|
+
return "A dependency is missing. Run install_deps first.";
|
|
37732
|
+
if (/ENOENT|no such file/i.test(stderr))
|
|
37733
|
+
return "A file or directory was not found. Use glob or list_dir to verify paths.";
|
|
37734
|
+
if (/EACCES|permission denied/i.test(stderr)) return "Permission denied. Check file permissions.";
|
|
37735
|
+
if (/SyntaxError|Unexpected token/i.test(stderr))
|
|
37736
|
+
return "Syntax error in the code. Use read_file to check the problematic file.";
|
|
37737
|
+
if (/TS\d{4}:/i.test(stderr))
|
|
37738
|
+
return "TypeScript compilation error. Read the error details above and use edit_file to fix.";
|
|
37739
|
+
if (/ERR!/i.test(stderr) && tool === "install_deps")
|
|
37740
|
+
return "Package install failed. Check if the package name is correct or if there are network issues.";
|
|
37741
|
+
if (/No Makefile/i.test(stderr) || /No rule to make target/i.test(stderr))
|
|
37742
|
+
return "Makefile target not found. Check available targets with 'make -n' or list_dir.";
|
|
37743
|
+
return `${tool} failed. Check stderr output above for details.`;
|
|
37744
|
+
}
|
|
37483
37745
|
async function detectPackageManager2(cwd) {
|
|
37484
37746
|
const lockfiles = [
|
|
37485
37747
|
{ file: "pnpm-lock.yaml", pm: "pnpm" },
|
|
@@ -37489,7 +37751,7 @@ async function detectPackageManager2(cwd) {
|
|
|
37489
37751
|
];
|
|
37490
37752
|
for (const { file, pm } of lockfiles) {
|
|
37491
37753
|
try {
|
|
37492
|
-
await
|
|
37754
|
+
await fs33__default.access(path35__default.join(cwd, file));
|
|
37493
37755
|
return pm;
|
|
37494
37756
|
} catch {
|
|
37495
37757
|
}
|
|
@@ -37572,7 +37834,7 @@ ${message}
|
|
|
37572
37834
|
heartbeat.activity();
|
|
37573
37835
|
});
|
|
37574
37836
|
const result = await subprocess;
|
|
37575
|
-
|
|
37837
|
+
const buildResult2 = {
|
|
37576
37838
|
success: result.exitCode === 0,
|
|
37577
37839
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37578
37840
|
stderr: truncateOutput2(stderrBuffer),
|
|
@@ -37580,6 +37842,10 @@ ${message}
|
|
|
37580
37842
|
duration: performance.now() - startTime,
|
|
37581
37843
|
packageManager: pm
|
|
37582
37844
|
};
|
|
37845
|
+
if (!buildResult2.success) {
|
|
37846
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "run_script");
|
|
37847
|
+
}
|
|
37848
|
+
return buildResult2;
|
|
37583
37849
|
} catch (error) {
|
|
37584
37850
|
if (error.timedOut) {
|
|
37585
37851
|
throw new TimeoutError(`Script '${script}' timed out after ${timeoutMs}ms`, {
|
|
@@ -37693,7 +37959,7 @@ ${message}
|
|
|
37693
37959
|
heartbeat.activity();
|
|
37694
37960
|
});
|
|
37695
37961
|
const result = await subprocess;
|
|
37696
|
-
|
|
37962
|
+
const buildResult2 = {
|
|
37697
37963
|
success: result.exitCode === 0,
|
|
37698
37964
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37699
37965
|
stderr: truncateOutput2(stderrBuffer),
|
|
@@ -37701,6 +37967,10 @@ ${message}
|
|
|
37701
37967
|
duration: performance.now() - startTime,
|
|
37702
37968
|
packageManager: pm
|
|
37703
37969
|
};
|
|
37970
|
+
if (!buildResult2.success) {
|
|
37971
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "install_deps");
|
|
37972
|
+
}
|
|
37973
|
+
return buildResult2;
|
|
37704
37974
|
} catch (error) {
|
|
37705
37975
|
if (error.timedOut) {
|
|
37706
37976
|
throw new TimeoutError(`Install timed out after ${timeoutMs}ms`, {
|
|
@@ -37754,7 +38024,7 @@ ${message}
|
|
|
37754
38024
|
});
|
|
37755
38025
|
try {
|
|
37756
38026
|
try {
|
|
37757
|
-
await
|
|
38027
|
+
await fs33__default.access(path35__default.join(projectDir, "Makefile"));
|
|
37758
38028
|
} catch {
|
|
37759
38029
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
37760
38030
|
}
|
|
@@ -37791,13 +38061,17 @@ ${message}
|
|
|
37791
38061
|
heartbeat.activity();
|
|
37792
38062
|
});
|
|
37793
38063
|
const result = await subprocess;
|
|
37794
|
-
|
|
38064
|
+
const buildResult2 = {
|
|
37795
38065
|
success: result.exitCode === 0,
|
|
37796
38066
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37797
38067
|
stderr: truncateOutput2(stderrBuffer),
|
|
37798
38068
|
exitCode: result.exitCode ?? 0,
|
|
37799
38069
|
duration: performance.now() - startTime
|
|
37800
38070
|
};
|
|
38071
|
+
if (!buildResult2.success) {
|
|
38072
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "make");
|
|
38073
|
+
}
|
|
38074
|
+
return buildResult2;
|
|
37801
38075
|
} catch (error) {
|
|
37802
38076
|
if (error instanceof ToolError) throw error;
|
|
37803
38077
|
if (error.timedOut) {
|
|
@@ -37890,13 +38164,17 @@ ${message}
|
|
|
37890
38164
|
heartbeat.activity();
|
|
37891
38165
|
});
|
|
37892
38166
|
const result = await subprocess;
|
|
37893
|
-
|
|
38167
|
+
const buildResult2 = {
|
|
37894
38168
|
success: result.exitCode === 0,
|
|
37895
38169
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37896
38170
|
stderr: truncateOutput2(stderrBuffer),
|
|
37897
38171
|
exitCode: result.exitCode ?? 0,
|
|
37898
38172
|
duration: performance.now() - startTime
|
|
37899
38173
|
};
|
|
38174
|
+
if (!buildResult2.success) {
|
|
38175
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "tsc");
|
|
38176
|
+
}
|
|
38177
|
+
return buildResult2;
|
|
37900
38178
|
} catch (error) {
|
|
37901
38179
|
if (error.timedOut) {
|
|
37902
38180
|
throw new TimeoutError(`TypeScript compile timed out after ${timeoutMs}ms`, {
|
|
@@ -38099,9 +38377,10 @@ async function searchDuckDuckGo(query, maxResults, timeout) {
|
|
|
38099
38377
|
});
|
|
38100
38378
|
clearTimeout(timeoutId);
|
|
38101
38379
|
if (!response.ok) {
|
|
38102
|
-
throw new ToolError(
|
|
38103
|
-
|
|
38104
|
-
|
|
38380
|
+
throw new ToolError(
|
|
38381
|
+
`DuckDuckGo search failed with status ${response.status}. Try a different search engine (brave, serpapi) or simplify the query.`,
|
|
38382
|
+
{ tool: "web_search" }
|
|
38383
|
+
);
|
|
38105
38384
|
}
|
|
38106
38385
|
const html = await response.text();
|
|
38107
38386
|
return parseDuckDuckGoResults(html, maxResults);
|
|
@@ -38132,9 +38411,10 @@ async function searchBrave(query, maxResults, timeout) {
|
|
|
38132
38411
|
});
|
|
38133
38412
|
clearTimeout(timeoutId);
|
|
38134
38413
|
if (!response.ok) {
|
|
38135
|
-
throw new ToolError(
|
|
38136
|
-
|
|
38137
|
-
|
|
38414
|
+
throw new ToolError(
|
|
38415
|
+
`Brave search failed with status ${response.status}. Try a different search engine (duckduckgo, serpapi) or check your BRAVE_SEARCH_API_KEY.`,
|
|
38416
|
+
{ tool: "web_search" }
|
|
38417
|
+
);
|
|
38138
38418
|
}
|
|
38139
38419
|
const data = await response.json();
|
|
38140
38420
|
return (data.web?.results ?? []).slice(0, maxResults).map((r) => ({
|
|
@@ -38168,9 +38448,10 @@ async function searchSerpApi(query, maxResults, timeout) {
|
|
|
38168
38448
|
});
|
|
38169
38449
|
clearTimeout(timeoutId);
|
|
38170
38450
|
if (!response.ok) {
|
|
38171
|
-
throw new ToolError(
|
|
38172
|
-
|
|
38173
|
-
|
|
38451
|
+
throw new ToolError(
|
|
38452
|
+
`SerpAPI search failed with status ${response.status}. Try a different search engine (duckduckgo, brave) or check your SERPAPI_KEY.`,
|
|
38453
|
+
{ tool: "web_search" }
|
|
38454
|
+
);
|
|
38174
38455
|
}
|
|
38175
38456
|
const data = await response.json();
|
|
38176
38457
|
return (data.organic_results ?? []).slice(0, maxResults).map((r) => ({
|
|
@@ -38260,6 +38541,27 @@ var PRIVATE_IP_PATTERNS = [
|
|
|
38260
38541
|
/^https?:\/\/0\.0\.0\.0/,
|
|
38261
38542
|
/^https?:\/\/\[::1\]/
|
|
38262
38543
|
];
|
|
38544
|
+
function getHttpErrorHint(status) {
|
|
38545
|
+
switch (status) {
|
|
38546
|
+
case 401:
|
|
38547
|
+
case 403:
|
|
38548
|
+
return "\nThis page requires authentication. Try using web_search to find a publicly accessible alternative.";
|
|
38549
|
+
case 404:
|
|
38550
|
+
return "\nPage not found. The URL may be outdated or misspelled. Try web_search to find the correct URL.";
|
|
38551
|
+
case 429:
|
|
38552
|
+
return "\nRate limited. Wait a moment before retrying, or try an alternative source.";
|
|
38553
|
+
case 500:
|
|
38554
|
+
case 502:
|
|
38555
|
+
case 503:
|
|
38556
|
+
case 504:
|
|
38557
|
+
return "\nServer error (temporary). Try again in a moment, or use web_search to find an alternative source.";
|
|
38558
|
+
default:
|
|
38559
|
+
if (status >= 400 && status < 500) {
|
|
38560
|
+
return "\nClient error. Check the URL is correct or try web_search to find the right page.";
|
|
38561
|
+
}
|
|
38562
|
+
return "";
|
|
38563
|
+
}
|
|
38564
|
+
}
|
|
38263
38565
|
function validateUrl(url) {
|
|
38264
38566
|
for (const scheme of BLOCKED_SCHEMES) {
|
|
38265
38567
|
if (url.toLowerCase().startsWith(scheme)) {
|
|
@@ -38478,7 +38780,8 @@ Examples:
|
|
|
38478
38780
|
});
|
|
38479
38781
|
clearTimeout(timeoutId);
|
|
38480
38782
|
if (!response.ok) {
|
|
38481
|
-
|
|
38783
|
+
const hint = getHttpErrorHint(response.status);
|
|
38784
|
+
throw new ToolError(`HTTP ${response.status}: ${response.statusText} \u2014 ${url}${hint}`, {
|
|
38482
38785
|
tool: "web_fetch"
|
|
38483
38786
|
});
|
|
38484
38787
|
}
|
|
@@ -38568,8 +38871,8 @@ init_review();
|
|
|
38568
38871
|
// src/tools/codebase-map.ts
|
|
38569
38872
|
init_registry4();
|
|
38570
38873
|
init_errors();
|
|
38571
|
-
var
|
|
38572
|
-
var
|
|
38874
|
+
var fs36 = await import('fs/promises');
|
|
38875
|
+
var path38 = await import('path');
|
|
38573
38876
|
var { glob: glob14 } = await import('glob');
|
|
38574
38877
|
var DEFAULT_MAX_FILES = 200;
|
|
38575
38878
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -38595,7 +38898,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
38595
38898
|
"**/*.d.ts"
|
|
38596
38899
|
];
|
|
38597
38900
|
function detectLanguage3(filePath) {
|
|
38598
|
-
const ext =
|
|
38901
|
+
const ext = path38.extname(filePath).toLowerCase();
|
|
38599
38902
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
38600
38903
|
if (extensions.includes(ext)) return lang;
|
|
38601
38904
|
}
|
|
@@ -39004,9 +39307,9 @@ Examples:
|
|
|
39004
39307
|
}),
|
|
39005
39308
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
39006
39309
|
const startTime = performance.now();
|
|
39007
|
-
const absPath =
|
|
39310
|
+
const absPath = path38.resolve(rootPath);
|
|
39008
39311
|
try {
|
|
39009
|
-
const stat2 = await
|
|
39312
|
+
const stat2 = await fs36.stat(absPath);
|
|
39010
39313
|
if (!stat2.isDirectory()) {
|
|
39011
39314
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
39012
39315
|
tool: "codebase_map"
|
|
@@ -39043,14 +39346,14 @@ Examples:
|
|
|
39043
39346
|
let totalDefinitions = 0;
|
|
39044
39347
|
let exportedSymbols = 0;
|
|
39045
39348
|
for (const file of limitedFiles) {
|
|
39046
|
-
const fullPath =
|
|
39349
|
+
const fullPath = path38.join(absPath, file);
|
|
39047
39350
|
const language = detectLanguage3(file);
|
|
39048
39351
|
if (!language) continue;
|
|
39049
39352
|
if (languages && !languages.includes(language)) {
|
|
39050
39353
|
continue;
|
|
39051
39354
|
}
|
|
39052
39355
|
try {
|
|
39053
|
-
const content = await
|
|
39356
|
+
const content = await fs36.readFile(fullPath, "utf-8");
|
|
39054
39357
|
const lineCount = content.split("\n").length;
|
|
39055
39358
|
const parsed = parseFile(content, language);
|
|
39056
39359
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -39087,23 +39390,23 @@ var codebaseMapTools = [codebaseMapTool];
|
|
|
39087
39390
|
init_registry4();
|
|
39088
39391
|
init_errors();
|
|
39089
39392
|
init_paths();
|
|
39090
|
-
var
|
|
39091
|
-
var
|
|
39393
|
+
var fs37 = await import('fs/promises');
|
|
39394
|
+
var path39 = await import('path');
|
|
39092
39395
|
var crypto2 = await import('crypto');
|
|
39093
|
-
var GLOBAL_MEMORIES_DIR =
|
|
39396
|
+
var GLOBAL_MEMORIES_DIR = path39.join(COCO_HOME, "memories");
|
|
39094
39397
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
39095
39398
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
39096
39399
|
async function ensureDir2(dirPath) {
|
|
39097
|
-
await
|
|
39400
|
+
await fs37.mkdir(dirPath, { recursive: true });
|
|
39098
39401
|
}
|
|
39099
39402
|
function getMemoriesDir(scope) {
|
|
39100
39403
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
39101
39404
|
}
|
|
39102
39405
|
async function loadIndex(scope) {
|
|
39103
39406
|
const dir = getMemoriesDir(scope);
|
|
39104
|
-
const indexPath =
|
|
39407
|
+
const indexPath = path39.join(dir, "index.json");
|
|
39105
39408
|
try {
|
|
39106
|
-
const content = await
|
|
39409
|
+
const content = await fs37.readFile(indexPath, "utf-8");
|
|
39107
39410
|
return JSON.parse(content);
|
|
39108
39411
|
} catch {
|
|
39109
39412
|
return [];
|
|
@@ -39112,14 +39415,14 @@ async function loadIndex(scope) {
|
|
|
39112
39415
|
async function saveIndex(scope, index) {
|
|
39113
39416
|
const dir = getMemoriesDir(scope);
|
|
39114
39417
|
await ensureDir2(dir);
|
|
39115
|
-
const indexPath =
|
|
39116
|
-
await
|
|
39418
|
+
const indexPath = path39.join(dir, "index.json");
|
|
39419
|
+
await fs37.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
39117
39420
|
}
|
|
39118
39421
|
async function loadMemory(scope, id) {
|
|
39119
39422
|
const dir = getMemoriesDir(scope);
|
|
39120
|
-
const memPath =
|
|
39423
|
+
const memPath = path39.join(dir, `${id}.json`);
|
|
39121
39424
|
try {
|
|
39122
|
-
const content = await
|
|
39425
|
+
const content = await fs37.readFile(memPath, "utf-8");
|
|
39123
39426
|
return JSON.parse(content);
|
|
39124
39427
|
} catch {
|
|
39125
39428
|
return null;
|
|
@@ -39128,8 +39431,8 @@ async function loadMemory(scope, id) {
|
|
|
39128
39431
|
async function saveMemory(scope, memory) {
|
|
39129
39432
|
const dir = getMemoriesDir(scope);
|
|
39130
39433
|
await ensureDir2(dir);
|
|
39131
|
-
const memPath =
|
|
39132
|
-
await
|
|
39434
|
+
const memPath = path39.join(dir, `${memory.id}.json`);
|
|
39435
|
+
await fs37.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
39133
39436
|
}
|
|
39134
39437
|
var createMemoryTool = defineTool({
|
|
39135
39438
|
name: "create_memory",
|
|
@@ -39285,17 +39588,17 @@ var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
|
39285
39588
|
// src/tools/checkpoint.ts
|
|
39286
39589
|
init_registry4();
|
|
39287
39590
|
init_errors();
|
|
39288
|
-
var
|
|
39591
|
+
var fs38 = await import('fs/promises');
|
|
39289
39592
|
var crypto3 = await import('crypto');
|
|
39290
39593
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
39291
39594
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
39292
39595
|
var STASH_PREFIX = "coco-cp";
|
|
39293
39596
|
async function ensureCocoDir() {
|
|
39294
|
-
await
|
|
39597
|
+
await fs38.mkdir(".coco", { recursive: true });
|
|
39295
39598
|
}
|
|
39296
39599
|
async function loadCheckpoints() {
|
|
39297
39600
|
try {
|
|
39298
|
-
const content = await
|
|
39601
|
+
const content = await fs38.readFile(CHECKPOINT_FILE, "utf-8");
|
|
39299
39602
|
return JSON.parse(content);
|
|
39300
39603
|
} catch {
|
|
39301
39604
|
return [];
|
|
@@ -39303,7 +39606,7 @@ async function loadCheckpoints() {
|
|
|
39303
39606
|
}
|
|
39304
39607
|
async function saveCheckpoints(checkpoints) {
|
|
39305
39608
|
await ensureCocoDir();
|
|
39306
|
-
await
|
|
39609
|
+
await fs38.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
39307
39610
|
}
|
|
39308
39611
|
async function execGit(args) {
|
|
39309
39612
|
const { execaCommand } = await import('execa');
|
|
@@ -39314,10 +39617,11 @@ async function execGit(args) {
|
|
|
39314
39617
|
});
|
|
39315
39618
|
return result.stdout;
|
|
39316
39619
|
} catch (error) {
|
|
39317
|
-
|
|
39318
|
-
|
|
39319
|
-
|
|
39320
|
-
|
|
39620
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
39621
|
+
let hint = `Git command failed (${args[0] ?? "unknown"}): ${msg}`;
|
|
39622
|
+
if (/not a git repository/i.test(msg))
|
|
39623
|
+
hint = "Not a git repository. Checkpoints require a git repo \u2014 run git_init first.";
|
|
39624
|
+
throw new ToolError(hint, { tool: "checkpoint" });
|
|
39321
39625
|
}
|
|
39322
39626
|
}
|
|
39323
39627
|
async function getChangedFiles() {
|
|
@@ -39435,8 +39739,9 @@ Examples:
|
|
|
39435
39739
|
message: `Restored checkpoint '${checkpoint.description}' (${checkpoint.fileCount} files)`
|
|
39436
39740
|
};
|
|
39437
39741
|
} catch (error) {
|
|
39742
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
39438
39743
|
throw new ToolError(
|
|
39439
|
-
`Failed to restore checkpoint: ${
|
|
39744
|
+
`Failed to restore checkpoint: ${msg}. Use list_checkpoints to see available checkpoints.`,
|
|
39440
39745
|
{ tool: "restore_checkpoint" }
|
|
39441
39746
|
);
|
|
39442
39747
|
}
|
|
@@ -39466,8 +39771,8 @@ var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpoi
|
|
|
39466
39771
|
|
|
39467
39772
|
// src/tools/semantic-search.ts
|
|
39468
39773
|
init_registry4();
|
|
39469
|
-
var
|
|
39470
|
-
var
|
|
39774
|
+
var fs39 = await import('fs/promises');
|
|
39775
|
+
var path40 = await import('path');
|
|
39471
39776
|
var { glob: glob15 } = await import('glob');
|
|
39472
39777
|
var INDEX_DIR = ".coco/search-index";
|
|
39473
39778
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -39573,6 +39878,7 @@ function simpleEmbedding(text13) {
|
|
|
39573
39878
|
return vector;
|
|
39574
39879
|
}
|
|
39575
39880
|
var embedFn = null;
|
|
39881
|
+
var usingFallbackEmbedding = false;
|
|
39576
39882
|
async function getEmbedding(text13) {
|
|
39577
39883
|
if (!embedFn) {
|
|
39578
39884
|
try {
|
|
@@ -39587,26 +39893,27 @@ async function getEmbedding(text13) {
|
|
|
39587
39893
|
};
|
|
39588
39894
|
} catch {
|
|
39589
39895
|
embedFn = async (t) => simpleEmbedding(t);
|
|
39896
|
+
usingFallbackEmbedding = true;
|
|
39590
39897
|
}
|
|
39591
39898
|
}
|
|
39592
39899
|
return embedFn(text13);
|
|
39593
39900
|
}
|
|
39594
39901
|
async function loadIndex2(indexDir) {
|
|
39595
39902
|
try {
|
|
39596
|
-
const indexPath =
|
|
39597
|
-
const content = await
|
|
39903
|
+
const indexPath = path40.join(indexDir, "index.json");
|
|
39904
|
+
const content = await fs39.readFile(indexPath, "utf-8");
|
|
39598
39905
|
return JSON.parse(content);
|
|
39599
39906
|
} catch {
|
|
39600
39907
|
return null;
|
|
39601
39908
|
}
|
|
39602
39909
|
}
|
|
39603
39910
|
async function saveIndex2(indexDir, index) {
|
|
39604
|
-
await
|
|
39605
|
-
const indexPath =
|
|
39606
|
-
await
|
|
39911
|
+
await fs39.mkdir(indexDir, { recursive: true });
|
|
39912
|
+
const indexPath = path40.join(indexDir, "index.json");
|
|
39913
|
+
await fs39.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
39607
39914
|
}
|
|
39608
39915
|
function isBinary(filePath) {
|
|
39609
|
-
return BINARY_EXTENSIONS.has(
|
|
39916
|
+
return BINARY_EXTENSIONS.has(path40.extname(filePath).toLowerCase());
|
|
39610
39917
|
}
|
|
39611
39918
|
var semanticSearchTool = defineTool({
|
|
39612
39919
|
name: "semantic_search",
|
|
@@ -39631,9 +39938,10 @@ Examples:
|
|
|
39631
39938
|
const effectivePath = rootPath ?? ".";
|
|
39632
39939
|
const effectiveMaxResults = maxResults ?? 10;
|
|
39633
39940
|
const effectiveThreshold = threshold ?? 0.3;
|
|
39634
|
-
const absPath =
|
|
39635
|
-
const indexDir =
|
|
39941
|
+
const absPath = path40.resolve(effectivePath);
|
|
39942
|
+
const indexDir = path40.join(absPath, INDEX_DIR);
|
|
39636
39943
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
39944
|
+
let warnings = [];
|
|
39637
39945
|
if (!index) {
|
|
39638
39946
|
const pattern = include ?? "**/*";
|
|
39639
39947
|
const files = await glob15(pattern, {
|
|
@@ -39643,12 +39951,14 @@ Examples:
|
|
|
39643
39951
|
absolute: false
|
|
39644
39952
|
});
|
|
39645
39953
|
const chunks = [];
|
|
39954
|
+
let skippedFiles = 0;
|
|
39955
|
+
let indexSaveWarning = "";
|
|
39646
39956
|
for (const file of files) {
|
|
39647
39957
|
if (isBinary(file)) continue;
|
|
39648
|
-
const fullPath =
|
|
39958
|
+
const fullPath = path40.join(absPath, file);
|
|
39649
39959
|
try {
|
|
39650
|
-
const stat2 = await
|
|
39651
|
-
const content = await
|
|
39960
|
+
const stat2 = await fs39.stat(fullPath);
|
|
39961
|
+
const content = await fs39.readFile(fullPath, "utf-8");
|
|
39652
39962
|
if (content.length > 1e5) continue;
|
|
39653
39963
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
39654
39964
|
for (const chunk of fileChunks) {
|
|
@@ -39663,6 +39973,7 @@ Examples:
|
|
|
39663
39973
|
});
|
|
39664
39974
|
}
|
|
39665
39975
|
} catch {
|
|
39976
|
+
skippedFiles++;
|
|
39666
39977
|
continue;
|
|
39667
39978
|
}
|
|
39668
39979
|
}
|
|
@@ -39675,6 +39986,18 @@ Examples:
|
|
|
39675
39986
|
try {
|
|
39676
39987
|
await saveIndex2(indexDir, index);
|
|
39677
39988
|
} catch {
|
|
39989
|
+
indexSaveWarning = "Index could not be saved to disk \u2014 next search will rebuild it.";
|
|
39990
|
+
}
|
|
39991
|
+
if (usingFallbackEmbedding) {
|
|
39992
|
+
warnings.push(
|
|
39993
|
+
"Using basic text matching (transformer model unavailable). Results may be less accurate."
|
|
39994
|
+
);
|
|
39995
|
+
}
|
|
39996
|
+
if (skippedFiles > 0) {
|
|
39997
|
+
warnings.push(`${skippedFiles} file(s) could not be read (binary or permission issues).`);
|
|
39998
|
+
}
|
|
39999
|
+
if (indexSaveWarning) {
|
|
40000
|
+
warnings.push(indexSaveWarning);
|
|
39678
40001
|
}
|
|
39679
40002
|
}
|
|
39680
40003
|
const queryVector = await getEmbedding(query);
|
|
@@ -39698,12 +40021,16 @@ Examples:
|
|
|
39698
40021
|
const ageMs = Date.now() - indexDate.getTime();
|
|
39699
40022
|
const ageMinutes = Math.round(ageMs / 6e4);
|
|
39700
40023
|
const indexAge = ageMinutes < 60 ? `${ageMinutes}m ago` : `${Math.round(ageMinutes / 60)}h ago`;
|
|
39701
|
-
|
|
40024
|
+
const output = {
|
|
39702
40025
|
results,
|
|
39703
40026
|
totalIndexed: index.chunks.length,
|
|
39704
40027
|
indexAge,
|
|
39705
40028
|
duration: performance.now() - startTime
|
|
39706
40029
|
};
|
|
40030
|
+
if (warnings.length > 0) {
|
|
40031
|
+
output.warning = warnings.join(" ");
|
|
40032
|
+
}
|
|
40033
|
+
return output;
|
|
39707
40034
|
}
|
|
39708
40035
|
});
|
|
39709
40036
|
var semanticSearchTools = [semanticSearchTool];
|
|
@@ -39711,8 +40038,8 @@ var semanticSearchTools = [semanticSearchTool];
|
|
|
39711
40038
|
// src/tools/diagram.ts
|
|
39712
40039
|
init_registry4();
|
|
39713
40040
|
init_errors();
|
|
39714
|
-
var
|
|
39715
|
-
var
|
|
40041
|
+
var fs40 = await import('fs/promises');
|
|
40042
|
+
var path41 = await import('path');
|
|
39716
40043
|
var { glob: glob16 } = await import('glob');
|
|
39717
40044
|
async function parseClassRelationships(rootPath, include) {
|
|
39718
40045
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -39725,7 +40052,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
39725
40052
|
const interfaces = [];
|
|
39726
40053
|
for (const file of files.slice(0, 100)) {
|
|
39727
40054
|
try {
|
|
39728
|
-
const content = await
|
|
40055
|
+
const content = await fs40.readFile(path41.join(rootPath, file), "utf-8");
|
|
39729
40056
|
const lines = content.split("\n");
|
|
39730
40057
|
for (let i = 0; i < lines.length; i++) {
|
|
39731
40058
|
const line = lines[i];
|
|
@@ -39844,14 +40171,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
39844
40171
|
};
|
|
39845
40172
|
}
|
|
39846
40173
|
async function generateArchitectureDiagram(rootPath) {
|
|
39847
|
-
const entries = await
|
|
40174
|
+
const entries = await fs40.readdir(rootPath, { withFileTypes: true });
|
|
39848
40175
|
const dirs = entries.filter(
|
|
39849
40176
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
39850
40177
|
);
|
|
39851
40178
|
const lines = ["graph TD"];
|
|
39852
40179
|
let nodeCount = 0;
|
|
39853
40180
|
let edgeCount = 0;
|
|
39854
|
-
const rootName =
|
|
40181
|
+
const rootName = path41.basename(rootPath);
|
|
39855
40182
|
lines.push(` ROOT["${rootName}"]`);
|
|
39856
40183
|
nodeCount++;
|
|
39857
40184
|
for (const dir of dirs) {
|
|
@@ -39861,7 +40188,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
39861
40188
|
nodeCount++;
|
|
39862
40189
|
edgeCount++;
|
|
39863
40190
|
try {
|
|
39864
|
-
const subEntries = await
|
|
40191
|
+
const subEntries = await fs40.readdir(path41.join(rootPath, dir.name), {
|
|
39865
40192
|
withFileTypes: true
|
|
39866
40193
|
});
|
|
39867
40194
|
const subDirs = subEntries.filter(
|
|
@@ -39984,7 +40311,7 @@ Examples:
|
|
|
39984
40311
|
tool: "generate_diagram"
|
|
39985
40312
|
});
|
|
39986
40313
|
}
|
|
39987
|
-
const absPath = rootPath ?
|
|
40314
|
+
const absPath = rootPath ? path41.resolve(rootPath) : process.cwd();
|
|
39988
40315
|
switch (type) {
|
|
39989
40316
|
case "class":
|
|
39990
40317
|
return generateClassDiagram(absPath, include);
|
|
@@ -40049,8 +40376,8 @@ var diagramTools = [generateDiagramTool];
|
|
|
40049
40376
|
// src/tools/pdf.ts
|
|
40050
40377
|
init_registry4();
|
|
40051
40378
|
init_errors();
|
|
40052
|
-
var
|
|
40053
|
-
var
|
|
40379
|
+
var fs41 = await import('fs/promises');
|
|
40380
|
+
var path42 = await import('path');
|
|
40054
40381
|
var DEFAULT_MAX_PAGES = 20;
|
|
40055
40382
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
40056
40383
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -40085,9 +40412,9 @@ Examples:
|
|
|
40085
40412
|
}),
|
|
40086
40413
|
async execute({ path: filePath, pages, maxPages }) {
|
|
40087
40414
|
const startTime = performance.now();
|
|
40088
|
-
const absPath =
|
|
40415
|
+
const absPath = path42.resolve(filePath);
|
|
40089
40416
|
try {
|
|
40090
|
-
const stat2 = await
|
|
40417
|
+
const stat2 = await fs41.stat(absPath);
|
|
40091
40418
|
if (!stat2.isFile()) {
|
|
40092
40419
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
40093
40420
|
tool: "read_pdf"
|
|
@@ -40118,7 +40445,7 @@ Examples:
|
|
|
40118
40445
|
}
|
|
40119
40446
|
try {
|
|
40120
40447
|
const pdfParse = await import('pdf-parse');
|
|
40121
|
-
const dataBuffer = await
|
|
40448
|
+
const dataBuffer = await fs41.readFile(absPath);
|
|
40122
40449
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
40123
40450
|
max: maxPages
|
|
40124
40451
|
});
|
|
@@ -40156,8 +40483,9 @@ Examples:
|
|
|
40156
40483
|
tool: "read_pdf"
|
|
40157
40484
|
});
|
|
40158
40485
|
}
|
|
40486
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40159
40487
|
throw new ToolError(
|
|
40160
|
-
`Failed to parse PDF: ${
|
|
40488
|
+
`Failed to parse PDF: ${msg}. The file may be encrypted, password-protected, or corrupted. Try opening it locally to verify.`,
|
|
40161
40489
|
{ tool: "read_pdf", cause: error instanceof Error ? error : void 0 }
|
|
40162
40490
|
);
|
|
40163
40491
|
}
|
|
@@ -40168,8 +40496,8 @@ var pdfTools = [readPdfTool];
|
|
|
40168
40496
|
// src/tools/image.ts
|
|
40169
40497
|
init_registry4();
|
|
40170
40498
|
init_errors();
|
|
40171
|
-
var
|
|
40172
|
-
var
|
|
40499
|
+
var fs42 = await import('fs/promises');
|
|
40500
|
+
var path43 = await import('path');
|
|
40173
40501
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
40174
40502
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
40175
40503
|
var MIME_TYPES = {
|
|
@@ -40197,15 +40525,15 @@ Examples:
|
|
|
40197
40525
|
async execute({ path: filePath, prompt, provider }) {
|
|
40198
40526
|
const startTime = performance.now();
|
|
40199
40527
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
40200
|
-
const absPath =
|
|
40528
|
+
const absPath = path43.resolve(filePath);
|
|
40201
40529
|
const cwd = process.cwd();
|
|
40202
|
-
if (!absPath.startsWith(cwd +
|
|
40530
|
+
if (!absPath.startsWith(cwd + path43.sep) && absPath !== cwd) {
|
|
40203
40531
|
throw new ToolError(
|
|
40204
40532
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
40205
40533
|
{ tool: "read_image" }
|
|
40206
40534
|
);
|
|
40207
40535
|
}
|
|
40208
|
-
const ext =
|
|
40536
|
+
const ext = path43.extname(absPath).toLowerCase();
|
|
40209
40537
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
40210
40538
|
throw new ToolError(
|
|
40211
40539
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -40213,7 +40541,7 @@ Examples:
|
|
|
40213
40541
|
);
|
|
40214
40542
|
}
|
|
40215
40543
|
try {
|
|
40216
|
-
const stat2 = await
|
|
40544
|
+
const stat2 = await fs42.stat(absPath);
|
|
40217
40545
|
if (!stat2.isFile()) {
|
|
40218
40546
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
40219
40547
|
tool: "read_image"
|
|
@@ -40234,7 +40562,7 @@ Examples:
|
|
|
40234
40562
|
if (error instanceof ToolError) throw error;
|
|
40235
40563
|
throw error;
|
|
40236
40564
|
}
|
|
40237
|
-
const imageBuffer = await
|
|
40565
|
+
const imageBuffer = await fs42.readFile(absPath);
|
|
40238
40566
|
const base64 = imageBuffer.toString("base64");
|
|
40239
40567
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
40240
40568
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -40326,10 +40654,15 @@ Examples:
|
|
|
40326
40654
|
} catch (error) {
|
|
40327
40655
|
if (error instanceof ToolError) throw error;
|
|
40328
40656
|
if (error.message?.includes("Cannot find module") || error.message?.includes("MODULE_NOT_FOUND")) {
|
|
40329
|
-
|
|
40330
|
-
|
|
40331
|
-
|
|
40332
|
-
|
|
40657
|
+
const pkgMap = {
|
|
40658
|
+
anthropic: "@anthropic-ai/sdk",
|
|
40659
|
+
openai: "openai",
|
|
40660
|
+
gemini: "@google/generative-ai"
|
|
40661
|
+
};
|
|
40662
|
+
const pkg = pkgMap[selectedProvider] ?? selectedProvider;
|
|
40663
|
+
throw new ToolError(`Provider SDK not installed. Run: pnpm add ${pkg}`, {
|
|
40664
|
+
tool: "read_image"
|
|
40665
|
+
});
|
|
40333
40666
|
}
|
|
40334
40667
|
throw new ToolError(
|
|
40335
40668
|
`Image analysis failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -40351,7 +40684,7 @@ var imageTools = [readImageTool];
|
|
|
40351
40684
|
// src/tools/database.ts
|
|
40352
40685
|
init_registry4();
|
|
40353
40686
|
init_errors();
|
|
40354
|
-
var
|
|
40687
|
+
var path44 = await import('path');
|
|
40355
40688
|
var DANGEROUS_PATTERNS = [
|
|
40356
40689
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
40357
40690
|
/\bTRUNCATE\b/i,
|
|
@@ -40382,7 +40715,7 @@ Examples:
|
|
|
40382
40715
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
40383
40716
|
const isReadonly = isReadonlyParam ?? true;
|
|
40384
40717
|
const startTime = performance.now();
|
|
40385
|
-
const absPath =
|
|
40718
|
+
const absPath = path44.resolve(database);
|
|
40386
40719
|
if (isReadonly && isDangerousSql(query)) {
|
|
40387
40720
|
throw new ToolError(
|
|
40388
40721
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -40434,10 +40767,20 @@ Examples:
|
|
|
40434
40767
|
{ tool: "sql_query" }
|
|
40435
40768
|
);
|
|
40436
40769
|
}
|
|
40437
|
-
|
|
40438
|
-
|
|
40439
|
-
|
|
40440
|
-
|
|
40770
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40771
|
+
let hint = `SQL query failed: ${msg}`;
|
|
40772
|
+
if (/no such table/i.test(msg))
|
|
40773
|
+
hint = `Table not found: ${msg}. Use inspect_schema to see available tables.`;
|
|
40774
|
+
else if (/syntax error|near "/i.test(msg))
|
|
40775
|
+
hint = `SQL syntax error: ${msg}. Check your query syntax.`;
|
|
40776
|
+
else if (/SQLITE_BUSY|database is locked/i.test(msg))
|
|
40777
|
+
hint = `Database is locked by another process. Wait and retry, or close other connections.`;
|
|
40778
|
+
else if (/unable to open database/i.test(msg))
|
|
40779
|
+
hint = `Cannot open database file. Use glob to verify the file path exists.`;
|
|
40780
|
+
throw new ToolError(hint, {
|
|
40781
|
+
tool: "sql_query",
|
|
40782
|
+
cause: error instanceof Error ? error : void 0
|
|
40783
|
+
});
|
|
40441
40784
|
}
|
|
40442
40785
|
}
|
|
40443
40786
|
});
|
|
@@ -40455,7 +40798,7 @@ Examples:
|
|
|
40455
40798
|
}),
|
|
40456
40799
|
async execute({ database, table }) {
|
|
40457
40800
|
const startTime = performance.now();
|
|
40458
|
-
const absPath =
|
|
40801
|
+
const absPath = path44.resolve(database);
|
|
40459
40802
|
try {
|
|
40460
40803
|
const { default: Database } = await import('better-sqlite3');
|
|
40461
40804
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -40500,10 +40843,16 @@ Examples:
|
|
|
40500
40843
|
{ tool: "inspect_schema" }
|
|
40501
40844
|
);
|
|
40502
40845
|
}
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40846
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40847
|
+
let hint = `Schema inspection failed: ${msg}`;
|
|
40848
|
+
if (/unable to open database/i.test(msg))
|
|
40849
|
+
hint = `Cannot open database file. Use glob to verify the file path exists.`;
|
|
40850
|
+
else if (/no such table/i.test(msg))
|
|
40851
|
+
hint = `Table '${table ?? ""}' not found. Run inspect_schema without a table name to list all tables.`;
|
|
40852
|
+
throw new ToolError(hint, {
|
|
40853
|
+
tool: "inspect_schema",
|
|
40854
|
+
cause: error instanceof Error ? error : void 0
|
|
40855
|
+
});
|
|
40507
40856
|
}
|
|
40508
40857
|
}
|
|
40509
40858
|
});
|
|
@@ -40632,14 +40981,14 @@ var astValidatorTools = [validateCodeTool, findMissingImportsTool];
|
|
|
40632
40981
|
|
|
40633
40982
|
// src/tools/code-analyzer.ts
|
|
40634
40983
|
init_registry4();
|
|
40635
|
-
var
|
|
40636
|
-
var
|
|
40984
|
+
var fs43 = await import('fs/promises');
|
|
40985
|
+
var path45 = await import('path');
|
|
40637
40986
|
var AnalyzeFileSchema = z.object({
|
|
40638
40987
|
filePath: z.string().describe("Path to file to analyze"),
|
|
40639
40988
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
40640
40989
|
});
|
|
40641
40990
|
async function analyzeFile(filePath, includeAst = false) {
|
|
40642
|
-
const content = await
|
|
40991
|
+
const content = await fs43.readFile(filePath, "utf-8");
|
|
40643
40992
|
const lines = content.split("\n").length;
|
|
40644
40993
|
const functions = [];
|
|
40645
40994
|
const classes = [];
|
|
@@ -40743,10 +41092,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
40743
41092
|
try {
|
|
40744
41093
|
const analysis = await analyzeFile(file, false);
|
|
40745
41094
|
totalLines += analysis.lines;
|
|
40746
|
-
const ext =
|
|
41095
|
+
const ext = path45.extname(file);
|
|
40747
41096
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
40748
41097
|
fileStats.push({
|
|
40749
|
-
file:
|
|
41098
|
+
file: path45.relative(dirPath, file),
|
|
40750
41099
|
lines: analysis.lines,
|
|
40751
41100
|
complexity: analysis.complexity.cyclomatic
|
|
40752
41101
|
});
|
|
@@ -41108,13 +41457,13 @@ var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateRes
|
|
|
41108
41457
|
|
|
41109
41458
|
// src/tools/smart-suggestions.ts
|
|
41110
41459
|
init_registry4();
|
|
41111
|
-
var
|
|
41460
|
+
var fs44 = await import('fs/promises');
|
|
41112
41461
|
var SuggestImprovementsSchema = z.object({
|
|
41113
41462
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
41114
41463
|
context: z.string().optional().describe("Additional context about the code")
|
|
41115
41464
|
});
|
|
41116
41465
|
async function analyzeAndSuggest(filePath, _context) {
|
|
41117
|
-
const content = await
|
|
41466
|
+
const content = await fs44.readFile(filePath, "utf-8");
|
|
41118
41467
|
const lines = content.split("\n");
|
|
41119
41468
|
const suggestions = [];
|
|
41120
41469
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -41206,7 +41555,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
41206
41555
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
41207
41556
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
41208
41557
|
try {
|
|
41209
|
-
await
|
|
41558
|
+
await fs44.access(testPath);
|
|
41210
41559
|
} catch {
|
|
41211
41560
|
suggestions.push({
|
|
41212
41561
|
type: "testing",
|
|
@@ -41263,7 +41612,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
41263
41612
|
async execute(input) {
|
|
41264
41613
|
const { filePath } = input;
|
|
41265
41614
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
41266
|
-
const content = await
|
|
41615
|
+
const content = await fs44.readFile(filePath, "utf-8");
|
|
41267
41616
|
const lines = content.split("\n");
|
|
41268
41617
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
41269
41618
|
let score = 100;
|
|
@@ -41300,8 +41649,8 @@ var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
|
41300
41649
|
|
|
41301
41650
|
// src/tools/context-enhancer.ts
|
|
41302
41651
|
init_registry4();
|
|
41303
|
-
var
|
|
41304
|
-
var
|
|
41652
|
+
var fs45 = await import('fs/promises');
|
|
41653
|
+
var path46 = await import('path');
|
|
41305
41654
|
var ContextMemoryStore = class {
|
|
41306
41655
|
items = /* @__PURE__ */ new Map();
|
|
41307
41656
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -41313,7 +41662,7 @@ var ContextMemoryStore = class {
|
|
|
41313
41662
|
}
|
|
41314
41663
|
async load() {
|
|
41315
41664
|
try {
|
|
41316
|
-
const content = await
|
|
41665
|
+
const content = await fs45.readFile(this.storePath, "utf-8");
|
|
41317
41666
|
const data = JSON.parse(content);
|
|
41318
41667
|
this.items = new Map(Object.entries(data.items || {}));
|
|
41319
41668
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -41321,15 +41670,15 @@ var ContextMemoryStore = class {
|
|
|
41321
41670
|
}
|
|
41322
41671
|
}
|
|
41323
41672
|
async save() {
|
|
41324
|
-
const dir =
|
|
41325
|
-
await
|
|
41673
|
+
const dir = path46.dirname(this.storePath);
|
|
41674
|
+
await fs45.mkdir(dir, { recursive: true });
|
|
41326
41675
|
const data = {
|
|
41327
41676
|
sessionId: this.sessionId,
|
|
41328
41677
|
items: Object.fromEntries(this.items),
|
|
41329
41678
|
learnings: Object.fromEntries(this.learnings),
|
|
41330
41679
|
savedAt: Date.now()
|
|
41331
41680
|
};
|
|
41332
|
-
await
|
|
41681
|
+
await fs45.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
41333
41682
|
}
|
|
41334
41683
|
addContext(id, item) {
|
|
41335
41684
|
this.items.set(id, item);
|
|
@@ -41497,11 +41846,11 @@ var contextEnhancerTools = [
|
|
|
41497
41846
|
|
|
41498
41847
|
// src/tools/skill-enhancer.ts
|
|
41499
41848
|
init_registry4();
|
|
41500
|
-
var
|
|
41501
|
-
var
|
|
41849
|
+
var fs46 = await import('fs/promises');
|
|
41850
|
+
var path47 = await import('path');
|
|
41502
41851
|
async function discoverSkills(skillsDir) {
|
|
41503
41852
|
try {
|
|
41504
|
-
const files = await
|
|
41853
|
+
const files = await fs46.readdir(skillsDir);
|
|
41505
41854
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
41506
41855
|
} catch {
|
|
41507
41856
|
return [];
|
|
@@ -41509,12 +41858,12 @@ async function discoverSkills(skillsDir) {
|
|
|
41509
41858
|
}
|
|
41510
41859
|
async function loadSkillMetadata(skillPath) {
|
|
41511
41860
|
try {
|
|
41512
|
-
const content = await
|
|
41861
|
+
const content = await fs46.readFile(skillPath, "utf-8");
|
|
41513
41862
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
41514
41863
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
41515
41864
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
41516
41865
|
return {
|
|
41517
|
-
name: nameMatch?.[1] ||
|
|
41866
|
+
name: nameMatch?.[1] || path47.basename(skillPath, path47.extname(skillPath)),
|
|
41518
41867
|
description: descMatch?.[1] || "No description",
|
|
41519
41868
|
version: versionMatch?.[1] || "1.0.0",
|
|
41520
41869
|
dependencies: []
|
|
@@ -41558,7 +41907,7 @@ var discoverSkillsTool = defineTool({
|
|
|
41558
41907
|
const { skillsDir } = input;
|
|
41559
41908
|
const skills = await discoverSkills(skillsDir);
|
|
41560
41909
|
const metadata = await Promise.all(
|
|
41561
|
-
skills.map((s) => loadSkillMetadata(
|
|
41910
|
+
skills.map((s) => loadSkillMetadata(path47.join(skillsDir, s)))
|
|
41562
41911
|
);
|
|
41563
41912
|
return {
|
|
41564
41913
|
skillsDir,
|
|
@@ -41729,7 +42078,7 @@ Examples:
|
|
|
41729
42078
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
41730
42079
|
}),
|
|
41731
42080
|
async execute({ path: dirPath, reason }) {
|
|
41732
|
-
const absolute =
|
|
42081
|
+
const absolute = path35__default.resolve(dirPath);
|
|
41733
42082
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
41734
42083
|
return {
|
|
41735
42084
|
authorized: true,
|
|
@@ -41738,8 +42087,8 @@ Examples:
|
|
|
41738
42087
|
};
|
|
41739
42088
|
}
|
|
41740
42089
|
for (const blocked of BLOCKED_SYSTEM_PATHS2) {
|
|
41741
|
-
const normalizedBlocked =
|
|
41742
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
42090
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
42091
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
41743
42092
|
return {
|
|
41744
42093
|
authorized: false,
|
|
41745
42094
|
path: absolute,
|
|
@@ -41748,7 +42097,7 @@ Examples:
|
|
|
41748
42097
|
}
|
|
41749
42098
|
}
|
|
41750
42099
|
const cwd = process.cwd();
|
|
41751
|
-
if (absolute ===
|
|
42100
|
+
if (absolute === path35__default.normalize(cwd) || absolute.startsWith(path35__default.normalize(cwd) + path35__default.sep)) {
|
|
41752
42101
|
return {
|
|
41753
42102
|
authorized: true,
|
|
41754
42103
|
path: absolute,
|
|
@@ -41756,7 +42105,7 @@ Examples:
|
|
|
41756
42105
|
};
|
|
41757
42106
|
}
|
|
41758
42107
|
try {
|
|
41759
|
-
const stat2 = await
|
|
42108
|
+
const stat2 = await fs33__default.stat(absolute);
|
|
41760
42109
|
if (!stat2.isDirectory()) {
|
|
41761
42110
|
return {
|
|
41762
42111
|
authorized: false,
|
|
@@ -41772,7 +42121,7 @@ Examples:
|
|
|
41772
42121
|
};
|
|
41773
42122
|
}
|
|
41774
42123
|
const existing = getAllowedPaths();
|
|
41775
|
-
if (existing.some((e) =>
|
|
42124
|
+
if (existing.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
41776
42125
|
return {
|
|
41777
42126
|
authorized: true,
|
|
41778
42127
|
path: absolute,
|
|
@@ -41857,9 +42206,9 @@ async function runSprints(options) {
|
|
|
41857
42206
|
Object.entries(AGENT_ROLES).map(([role, def]) => [role, { ...def, maxTurns: 20 }])
|
|
41858
42207
|
);
|
|
41859
42208
|
const coordinator = createAgentCoordinator(executor, agentDefsMap);
|
|
41860
|
-
await
|
|
41861
|
-
const sprintsDir =
|
|
41862
|
-
await
|
|
42209
|
+
await fs33__default.mkdir(spec.outputPath, { recursive: true });
|
|
42210
|
+
const sprintsDir = path35__default.join(spec.outputPath, ".coco", "sprints");
|
|
42211
|
+
await fs33__default.mkdir(sprintsDir, { recursive: true });
|
|
41863
42212
|
for (const sprint of spec.sprints) {
|
|
41864
42213
|
onProgress(`Starting ${sprint.id}: ${sprint.name}`);
|
|
41865
42214
|
const sprintStart = Date.now();
|
|
@@ -42112,8 +42461,8 @@ Assess: overall architecture, consistency, error handling, and production readin
|
|
|
42112
42461
|
};
|
|
42113
42462
|
}
|
|
42114
42463
|
async function saveSprintResult(sprintsDir, result) {
|
|
42115
|
-
const filePath =
|
|
42116
|
-
await
|
|
42464
|
+
const filePath = path35__default.join(sprintsDir, `${result.sprintId}.json`);
|
|
42465
|
+
await fs33__default.writeFile(filePath, JSON.stringify(result, null, 2), "utf-8");
|
|
42117
42466
|
}
|
|
42118
42467
|
|
|
42119
42468
|
// src/cli/repl/commands/build-app.ts
|
|
@@ -42138,9 +42487,9 @@ function parseArgs5(args) {
|
|
|
42138
42487
|
return { description, specFile, outputDir, skipConfirmation };
|
|
42139
42488
|
}
|
|
42140
42489
|
function isWithinRoot(resolvedPath, rootDir) {
|
|
42141
|
-
const normalRoot =
|
|
42142
|
-
const normalPath =
|
|
42143
|
-
return normalPath ===
|
|
42490
|
+
const normalRoot = path35__default.normalize(rootDir) + path35__default.sep;
|
|
42491
|
+
const normalPath = path35__default.normalize(resolvedPath);
|
|
42492
|
+
return normalPath === path35__default.normalize(rootDir) || normalPath.startsWith(normalRoot);
|
|
42144
42493
|
}
|
|
42145
42494
|
var buildAppCommand = {
|
|
42146
42495
|
name: "build-app",
|
|
@@ -42163,20 +42512,20 @@ var buildAppCommand = {
|
|
|
42163
42512
|
}
|
|
42164
42513
|
let initialDescription = parsed.description;
|
|
42165
42514
|
if (parsed.specFile) {
|
|
42166
|
-
const specPath =
|
|
42515
|
+
const specPath = path35__default.resolve(session.projectPath, parsed.specFile);
|
|
42167
42516
|
if (!isWithinRoot(specPath, session.projectPath)) {
|
|
42168
42517
|
p25.log.error(`--spec path must be within the project directory: ${specPath}`);
|
|
42169
42518
|
return false;
|
|
42170
42519
|
}
|
|
42171
42520
|
try {
|
|
42172
|
-
initialDescription = await
|
|
42521
|
+
initialDescription = await fs33__default.readFile(specPath, "utf-8");
|
|
42173
42522
|
} catch (err) {
|
|
42174
42523
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42175
42524
|
p25.log.error(`Error reading spec file: ${msg}`);
|
|
42176
42525
|
return false;
|
|
42177
42526
|
}
|
|
42178
42527
|
}
|
|
42179
|
-
const outputPath = parsed.outputDir ?
|
|
42528
|
+
const outputPath = parsed.outputDir ? path35__default.resolve(session.projectPath, parsed.outputDir) : path35__default.join(session.projectPath, "build-app-output");
|
|
42180
42529
|
if (parsed.outputDir && !isWithinRoot(outputPath, session.projectPath)) {
|
|
42181
42530
|
p25.log.error(`--output path must be within the project directory: ${outputPath}`);
|
|
42182
42531
|
return false;
|
|
@@ -42383,11 +42732,11 @@ function getAllCommands() {
|
|
|
42383
42732
|
}
|
|
42384
42733
|
|
|
42385
42734
|
// src/cli/repl/input/handler.ts
|
|
42386
|
-
var HISTORY_FILE =
|
|
42735
|
+
var HISTORY_FILE = path35.join(os4.homedir(), ".coco", "history");
|
|
42387
42736
|
function loadHistory() {
|
|
42388
42737
|
try {
|
|
42389
|
-
if (
|
|
42390
|
-
const content =
|
|
42738
|
+
if (fs50.existsSync(HISTORY_FILE)) {
|
|
42739
|
+
const content = fs50.readFileSync(HISTORY_FILE, "utf-8");
|
|
42391
42740
|
return content.split("\n").filter(Boolean).slice(-500);
|
|
42392
42741
|
}
|
|
42393
42742
|
} catch {
|
|
@@ -42396,12 +42745,12 @@ function loadHistory() {
|
|
|
42396
42745
|
}
|
|
42397
42746
|
function saveHistory(history) {
|
|
42398
42747
|
try {
|
|
42399
|
-
const dir =
|
|
42400
|
-
if (!
|
|
42401
|
-
|
|
42748
|
+
const dir = path35.dirname(HISTORY_FILE);
|
|
42749
|
+
if (!fs50.existsSync(dir)) {
|
|
42750
|
+
fs50.mkdirSync(dir, { recursive: true });
|
|
42402
42751
|
}
|
|
42403
42752
|
const toSave = history.slice(-500);
|
|
42404
|
-
|
|
42753
|
+
fs50.writeFileSync(HISTORY_FILE, toSave.join("\n") + "\n");
|
|
42405
42754
|
} catch {
|
|
42406
42755
|
}
|
|
42407
42756
|
}
|
|
@@ -43729,7 +44078,7 @@ function formatDiffPreview(toolCall) {
|
|
|
43729
44078
|
}
|
|
43730
44079
|
async function checkFileExists(filePath) {
|
|
43731
44080
|
try {
|
|
43732
|
-
await
|
|
44081
|
+
await fs33__default.access(filePath);
|
|
43733
44082
|
return true;
|
|
43734
44083
|
} catch {
|
|
43735
44084
|
return false;
|
|
@@ -44511,6 +44860,21 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
44511
44860
|
content: toolResults
|
|
44512
44861
|
});
|
|
44513
44862
|
if (stuckInErrorLoop) {
|
|
44863
|
+
try {
|
|
44864
|
+
const finalMessages = getConversationContext(session, toolRegistry);
|
|
44865
|
+
for await (const chunk of provider.streamWithTools(finalMessages, {
|
|
44866
|
+
tools: [],
|
|
44867
|
+
maxTokens: session.config.provider.maxTokens
|
|
44868
|
+
})) {
|
|
44869
|
+
if (options.signal?.aborted) break;
|
|
44870
|
+
if (chunk.type === "text" && chunk.text) {
|
|
44871
|
+
finalContent += chunk.text;
|
|
44872
|
+
options.onStream?.(chunk);
|
|
44873
|
+
}
|
|
44874
|
+
if (chunk.type === "done") break;
|
|
44875
|
+
}
|
|
44876
|
+
} catch {
|
|
44877
|
+
}
|
|
44514
44878
|
break;
|
|
44515
44879
|
}
|
|
44516
44880
|
}
|
|
@@ -45048,8 +45412,8 @@ function formatContextUsage(percent) {
|
|
|
45048
45412
|
}
|
|
45049
45413
|
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
45050
45414
|
const parts = [];
|
|
45051
|
-
const projectName =
|
|
45052
|
-
parts.push(chalk25.dim("\u{1F4C1}") + chalk25.magenta(projectName));
|
|
45415
|
+
const projectName = path35__default.basename(projectPath);
|
|
45416
|
+
parts.push(chalk25.dim("\u{1F4C1} ") + chalk25.magenta(projectName));
|
|
45053
45417
|
const providerName = config.provider.type;
|
|
45054
45418
|
const modelName = config.provider.model || "default";
|
|
45055
45419
|
parts.push(chalk25.dim(`${providerName}/`) + chalk25.cyan(modelName));
|