@corbat-tech/coco 2.25.0 → 2.25.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +1150 -729
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs5 from 'fs';
|
|
3
3
|
import fs5__default, { accessSync, readFileSync, constants } from 'fs';
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
4
|
+
import * as path38 from 'path';
|
|
5
|
+
import path38__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 fs35 from 'fs/promises';
|
|
11
|
+
import fs35__default, { mkdir, writeFile, readFile, access, readdir, rm } from 'fs/promises';
|
|
12
12
|
import JSON5 from 'json5';
|
|
13
13
|
import * as crypto from 'crypto';
|
|
14
|
-
import { randomUUID } from 'crypto';
|
|
14
|
+
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
15
15
|
import * as http from 'http';
|
|
16
16
|
import * as p26 from '@clack/prompts';
|
|
17
17
|
import chalk from 'chalk';
|
|
@@ -556,7 +556,7 @@ async function loadConfig(configPath) {
|
|
|
556
556
|
async function loadConfigFile(configPath, options = {}) {
|
|
557
557
|
const { strict = true } = options;
|
|
558
558
|
try {
|
|
559
|
-
const content = await
|
|
559
|
+
const content = await fs35__default.readFile(configPath, "utf-8");
|
|
560
560
|
const parsed = JSON5.parse(content);
|
|
561
561
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
562
562
|
if (!strict) {
|
|
@@ -612,7 +612,7 @@ function deepMergeConfig(base, override) {
|
|
|
612
612
|
};
|
|
613
613
|
}
|
|
614
614
|
function getProjectConfigPath() {
|
|
615
|
-
return
|
|
615
|
+
return path38__default.join(process.cwd(), ".coco", "config.json");
|
|
616
616
|
}
|
|
617
617
|
async function saveConfig(config, configPath, global = false) {
|
|
618
618
|
const result = CocoConfigSchema.safeParse(config);
|
|
@@ -627,10 +627,10 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
627
627
|
});
|
|
628
628
|
}
|
|
629
629
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath());
|
|
630
|
-
const dir =
|
|
631
|
-
await
|
|
630
|
+
const dir = path38__default.dirname(resolvedPath);
|
|
631
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
632
632
|
const content = JSON.stringify(result.data, null, 2);
|
|
633
|
-
await
|
|
633
|
+
await fs35__default.writeFile(resolvedPath, content, "utf-8");
|
|
634
634
|
}
|
|
635
635
|
function createDefaultConfig(projectName, language = "typescript") {
|
|
636
636
|
return createDefaultConfigObject(projectName, language);
|
|
@@ -639,20 +639,20 @@ async function findConfigPath(cwd) {
|
|
|
639
639
|
const envPath = process.env["COCO_CONFIG_PATH"];
|
|
640
640
|
if (envPath) {
|
|
641
641
|
try {
|
|
642
|
-
await
|
|
642
|
+
await fs35__default.access(envPath);
|
|
643
643
|
return envPath;
|
|
644
644
|
} catch {
|
|
645
645
|
}
|
|
646
646
|
}
|
|
647
647
|
const basePath = cwd || process.cwd();
|
|
648
|
-
const projectConfigPath =
|
|
648
|
+
const projectConfigPath = path38__default.join(basePath, ".coco", "config.json");
|
|
649
649
|
try {
|
|
650
|
-
await
|
|
650
|
+
await fs35__default.access(projectConfigPath);
|
|
651
651
|
return projectConfigPath;
|
|
652
652
|
} catch {
|
|
653
653
|
}
|
|
654
654
|
try {
|
|
655
|
-
await
|
|
655
|
+
await fs35__default.access(CONFIG_PATHS.config);
|
|
656
656
|
return CONFIG_PATHS.config;
|
|
657
657
|
} catch {
|
|
658
658
|
return void 0;
|
|
@@ -661,14 +661,14 @@ async function findConfigPath(cwd) {
|
|
|
661
661
|
async function findAllConfigPaths(cwd) {
|
|
662
662
|
const result = {};
|
|
663
663
|
try {
|
|
664
|
-
await
|
|
664
|
+
await fs35__default.access(CONFIG_PATHS.config);
|
|
665
665
|
result.global = CONFIG_PATHS.config;
|
|
666
666
|
} catch {
|
|
667
667
|
}
|
|
668
668
|
const basePath = cwd || process.cwd();
|
|
669
|
-
const projectConfigPath =
|
|
669
|
+
const projectConfigPath = path38__default.join(basePath, ".coco", "config.json");
|
|
670
670
|
try {
|
|
671
|
-
await
|
|
671
|
+
await fs35__default.access(projectConfigPath);
|
|
672
672
|
result.project = projectConfigPath;
|
|
673
673
|
} catch {
|
|
674
674
|
}
|
|
@@ -677,7 +677,7 @@ async function findAllConfigPaths(cwd) {
|
|
|
677
677
|
async function configExists(configPath, scope = "any") {
|
|
678
678
|
if (configPath) {
|
|
679
679
|
try {
|
|
680
|
-
await
|
|
680
|
+
await fs35__default.access(configPath);
|
|
681
681
|
return true;
|
|
682
682
|
} catch {
|
|
683
683
|
return false;
|
|
@@ -685,7 +685,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
685
685
|
}
|
|
686
686
|
if (scope === "project" || scope === "any") {
|
|
687
687
|
try {
|
|
688
|
-
await
|
|
688
|
+
await fs35__default.access(getProjectConfigPath());
|
|
689
689
|
return true;
|
|
690
690
|
} catch {
|
|
691
691
|
if (scope === "project") return false;
|
|
@@ -693,7 +693,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
693
693
|
}
|
|
694
694
|
if (scope === "global" || scope === "any") {
|
|
695
695
|
try {
|
|
696
|
-
await
|
|
696
|
+
await fs35__default.access(CONFIG_PATHS.config);
|
|
697
697
|
return true;
|
|
698
698
|
} catch {
|
|
699
699
|
return false;
|
|
@@ -701,8 +701,8 @@ async function configExists(configPath, scope = "any") {
|
|
|
701
701
|
}
|
|
702
702
|
return false;
|
|
703
703
|
}
|
|
704
|
-
function getConfigValue(config,
|
|
705
|
-
const keys =
|
|
704
|
+
function getConfigValue(config, path60) {
|
|
705
|
+
const keys = path60.split(".");
|
|
706
706
|
let current = config;
|
|
707
707
|
for (const key of keys) {
|
|
708
708
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -879,18 +879,18 @@ async function refreshAccessToken(provider, refreshToken) {
|
|
|
879
879
|
}
|
|
880
880
|
function getTokenStoragePath(provider) {
|
|
881
881
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
882
|
-
return
|
|
882
|
+
return path38.join(home, ".coco", "tokens", `${provider}.json`);
|
|
883
883
|
}
|
|
884
884
|
async function saveTokens(provider, tokens) {
|
|
885
885
|
const filePath = getTokenStoragePath(provider);
|
|
886
|
-
const dir =
|
|
887
|
-
await
|
|
888
|
-
await
|
|
886
|
+
const dir = path38.dirname(filePath);
|
|
887
|
+
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
888
|
+
await fs35.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
889
889
|
}
|
|
890
890
|
async function loadTokens(provider) {
|
|
891
891
|
const filePath = getTokenStoragePath(provider);
|
|
892
892
|
try {
|
|
893
|
-
const content = await
|
|
893
|
+
const content = await fs35.readFile(filePath, "utf-8");
|
|
894
894
|
return JSON.parse(content);
|
|
895
895
|
} catch {
|
|
896
896
|
return null;
|
|
@@ -899,7 +899,7 @@ async function loadTokens(provider) {
|
|
|
899
899
|
async function deleteTokens(provider) {
|
|
900
900
|
const filePath = getTokenStoragePath(provider);
|
|
901
901
|
try {
|
|
902
|
-
await
|
|
902
|
+
await fs35.unlink(filePath);
|
|
903
903
|
} catch {
|
|
904
904
|
}
|
|
905
905
|
}
|
|
@@ -1009,16 +1009,16 @@ var init_oauth = __esm({
|
|
|
1009
1009
|
}
|
|
1010
1010
|
});
|
|
1011
1011
|
function generateCodeVerifier(length = 64) {
|
|
1012
|
-
const
|
|
1013
|
-
return base64UrlEncode(
|
|
1012
|
+
const randomBytes3 = crypto.randomBytes(length);
|
|
1013
|
+
return base64UrlEncode(randomBytes3);
|
|
1014
1014
|
}
|
|
1015
1015
|
function generateCodeChallenge(codeVerifier) {
|
|
1016
1016
|
const hash = crypto.createHash("sha256").update(codeVerifier).digest();
|
|
1017
1017
|
return base64UrlEncode(hash);
|
|
1018
1018
|
}
|
|
1019
1019
|
function generateState(length = 32) {
|
|
1020
|
-
const
|
|
1021
|
-
return base64UrlEncode(
|
|
1020
|
+
const randomBytes3 = crypto.randomBytes(length);
|
|
1021
|
+
return base64UrlEncode(randomBytes3);
|
|
1022
1022
|
}
|
|
1023
1023
|
function base64UrlEncode(buffer) {
|
|
1024
1024
|
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
@@ -1479,17 +1479,17 @@ function getCopilotBaseUrl(accountType) {
|
|
|
1479
1479
|
}
|
|
1480
1480
|
function getCopilotCredentialsPath() {
|
|
1481
1481
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
1482
|
-
return
|
|
1482
|
+
return path38.join(home, ".coco", "tokens", "copilot.json");
|
|
1483
1483
|
}
|
|
1484
1484
|
async function saveCopilotCredentials(creds) {
|
|
1485
1485
|
const filePath = getCopilotCredentialsPath();
|
|
1486
|
-
const dir =
|
|
1487
|
-
await
|
|
1488
|
-
await
|
|
1486
|
+
const dir = path38.dirname(filePath);
|
|
1487
|
+
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
1488
|
+
await fs35.writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
1489
1489
|
}
|
|
1490
1490
|
async function loadCopilotCredentials() {
|
|
1491
1491
|
try {
|
|
1492
|
-
const content = await
|
|
1492
|
+
const content = await fs35.readFile(getCopilotCredentialsPath(), "utf-8");
|
|
1493
1493
|
const parsed = CopilotCredentialsSchema.safeParse(JSON.parse(content));
|
|
1494
1494
|
return parsed.success ? parsed.data : null;
|
|
1495
1495
|
} catch {
|
|
@@ -1498,7 +1498,7 @@ async function loadCopilotCredentials() {
|
|
|
1498
1498
|
}
|
|
1499
1499
|
async function deleteCopilotCredentials() {
|
|
1500
1500
|
try {
|
|
1501
|
-
await
|
|
1501
|
+
await fs35.unlink(getCopilotCredentialsPath());
|
|
1502
1502
|
} catch {
|
|
1503
1503
|
}
|
|
1504
1504
|
}
|
|
@@ -2239,7 +2239,7 @@ function getADCPath() {
|
|
|
2239
2239
|
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
2240
2240
|
return process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
2241
2241
|
}
|
|
2242
|
-
return
|
|
2242
|
+
return path38.join(home, ".config", "gcloud", "application_default_credentials.json");
|
|
2243
2243
|
}
|
|
2244
2244
|
async function isGcloudInstalled() {
|
|
2245
2245
|
try {
|
|
@@ -2252,7 +2252,7 @@ async function isGcloudInstalled() {
|
|
|
2252
2252
|
async function hasADCCredentials() {
|
|
2253
2253
|
const adcPath = getADCPath();
|
|
2254
2254
|
try {
|
|
2255
|
-
await
|
|
2255
|
+
await fs35.access(adcPath);
|
|
2256
2256
|
return true;
|
|
2257
2257
|
} catch {
|
|
2258
2258
|
return false;
|
|
@@ -2395,7 +2395,7 @@ function loadGlobalCocoEnv() {
|
|
|
2395
2395
|
try {
|
|
2396
2396
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2397
2397
|
if (!home) return;
|
|
2398
|
-
const globalEnvPath =
|
|
2398
|
+
const globalEnvPath = path38.join(home, ".coco", ".env");
|
|
2399
2399
|
const content = fs5.readFileSync(globalEnvPath, "utf-8");
|
|
2400
2400
|
for (const line of content.split("\n")) {
|
|
2401
2401
|
const trimmed = line.trim();
|
|
@@ -2633,7 +2633,7 @@ async function updateEnvProvider(provider) {
|
|
|
2633
2633
|
try {
|
|
2634
2634
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2635
2635
|
if (!home) return;
|
|
2636
|
-
const envPath =
|
|
2636
|
+
const envPath = path38.join(home, ".coco", ".env");
|
|
2637
2637
|
let content;
|
|
2638
2638
|
try {
|
|
2639
2639
|
content = await fs5.promises.readFile(envPath, "utf-8");
|
|
@@ -2660,7 +2660,7 @@ async function removeEnvProvider() {
|
|
|
2660
2660
|
try {
|
|
2661
2661
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2662
2662
|
if (!home) return;
|
|
2663
|
-
const envPath =
|
|
2663
|
+
const envPath = path38.join(home, ".coco", ".env");
|
|
2664
2664
|
let content;
|
|
2665
2665
|
try {
|
|
2666
2666
|
content = await fs5.promises.readFile(envPath, "utf-8");
|
|
@@ -2679,7 +2679,7 @@ async function migrateOldPreferences() {
|
|
|
2679
2679
|
try {
|
|
2680
2680
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2681
2681
|
if (!home) return;
|
|
2682
|
-
const oldPrefsPath =
|
|
2682
|
+
const oldPrefsPath = path38.join(home, ".coco", "preferences.json");
|
|
2683
2683
|
let oldPrefs = null;
|
|
2684
2684
|
try {
|
|
2685
2685
|
const content = await fs5.promises.readFile(oldPrefsPath, "utf-8");
|
|
@@ -2855,7 +2855,7 @@ function levelToNumber(level) {
|
|
|
2855
2855
|
}
|
|
2856
2856
|
function createLogger(config = {}) {
|
|
2857
2857
|
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
2858
|
-
const
|
|
2858
|
+
const logger2 = new Logger({
|
|
2859
2859
|
name: finalConfig.name,
|
|
2860
2860
|
minLevel: levelToNumber(finalConfig.level),
|
|
2861
2861
|
prettyLogTemplate: finalConfig.prettyPrint ? "{{yyyy}}-{{mm}}-{{dd}} {{hh}}:{{MM}}:{{ss}} {{logLevelName}} [{{name}}] " : void 0,
|
|
@@ -2863,16 +2863,16 @@ function createLogger(config = {}) {
|
|
|
2863
2863
|
stylePrettyLogs: finalConfig.prettyPrint
|
|
2864
2864
|
});
|
|
2865
2865
|
if (finalConfig.logToFile && finalConfig.logDir) {
|
|
2866
|
-
setupFileLogging(
|
|
2866
|
+
setupFileLogging(logger2, finalConfig.logDir, finalConfig.name);
|
|
2867
2867
|
}
|
|
2868
|
-
return
|
|
2868
|
+
return logger2;
|
|
2869
2869
|
}
|
|
2870
|
-
function setupFileLogging(
|
|
2870
|
+
function setupFileLogging(logger2, logDir, name) {
|
|
2871
2871
|
if (!fs5__default.existsSync(logDir)) {
|
|
2872
2872
|
fs5__default.mkdirSync(logDir, { recursive: true });
|
|
2873
2873
|
}
|
|
2874
|
-
const logFile =
|
|
2875
|
-
|
|
2874
|
+
const logFile = path38__default.join(logDir, `${name}.log`);
|
|
2875
|
+
logger2.attachTransport((logObj) => {
|
|
2876
2876
|
const line = JSON.stringify(logObj) + "\n";
|
|
2877
2877
|
fs5__default.appendFileSync(logFile, line);
|
|
2878
2878
|
});
|
|
@@ -2886,34 +2886,34 @@ function getLogger() {
|
|
|
2886
2886
|
}
|
|
2887
2887
|
return globalLogger;
|
|
2888
2888
|
}
|
|
2889
|
-
function setLogger(
|
|
2890
|
-
globalLogger =
|
|
2889
|
+
function setLogger(logger2) {
|
|
2890
|
+
globalLogger = logger2;
|
|
2891
2891
|
}
|
|
2892
2892
|
function initializeLogging(projectPath, level = "info") {
|
|
2893
|
-
const logDir =
|
|
2894
|
-
const
|
|
2893
|
+
const logDir = path38__default.join(projectPath, ".coco", "logs");
|
|
2894
|
+
const logger2 = createLogger({
|
|
2895
2895
|
name: "coco",
|
|
2896
2896
|
level,
|
|
2897
2897
|
prettyPrint: process.stdout.isTTY ?? true,
|
|
2898
2898
|
logToFile: true,
|
|
2899
2899
|
logDir
|
|
2900
2900
|
});
|
|
2901
|
-
setLogger(
|
|
2902
|
-
return
|
|
2901
|
+
setLogger(logger2);
|
|
2902
|
+
return logger2;
|
|
2903
2903
|
}
|
|
2904
|
-
function logEvent(
|
|
2905
|
-
|
|
2904
|
+
function logEvent(logger2, event, data = {}) {
|
|
2905
|
+
logger2.info({ event, ...data });
|
|
2906
2906
|
}
|
|
2907
|
-
async function logTiming(
|
|
2907
|
+
async function logTiming(logger2, operation, fn) {
|
|
2908
2908
|
const start = performance.now();
|
|
2909
2909
|
try {
|
|
2910
2910
|
const result = await fn();
|
|
2911
2911
|
const duration = performance.now() - start;
|
|
2912
|
-
|
|
2912
|
+
logger2.debug({ operation, durationMs: duration.toFixed(2), status: "success" });
|
|
2913
2913
|
return result;
|
|
2914
2914
|
} catch (error) {
|
|
2915
2915
|
const duration = performance.now() - start;
|
|
2916
|
-
|
|
2916
|
+
logger2.error({ operation, durationMs: duration.toFixed(2), status: "error", error });
|
|
2917
2917
|
throw error;
|
|
2918
2918
|
}
|
|
2919
2919
|
}
|
|
@@ -7164,9 +7164,9 @@ async function migrateGlobalConfig(oldDir, newConfigPath) {
|
|
|
7164
7164
|
);
|
|
7165
7165
|
}
|
|
7166
7166
|
}
|
|
7167
|
-
async function fileExists(
|
|
7167
|
+
async function fileExists(path60) {
|
|
7168
7168
|
try {
|
|
7169
|
-
await access(
|
|
7169
|
+
await access(path60);
|
|
7170
7170
|
return true;
|
|
7171
7171
|
} catch {
|
|
7172
7172
|
return false;
|
|
@@ -7297,8 +7297,8 @@ var init_registry = __esm({
|
|
|
7297
7297
|
/**
|
|
7298
7298
|
* Ensure directory exists
|
|
7299
7299
|
*/
|
|
7300
|
-
async ensureDir(
|
|
7301
|
-
await mkdir(dirname(
|
|
7300
|
+
async ensureDir(path60) {
|
|
7301
|
+
await mkdir(dirname(path60), { recursive: true });
|
|
7302
7302
|
}
|
|
7303
7303
|
};
|
|
7304
7304
|
}
|
|
@@ -7373,7 +7373,7 @@ __export(markdown_loader_exports, {
|
|
|
7373
7373
|
});
|
|
7374
7374
|
async function isMarkdownSkill(skillDir) {
|
|
7375
7375
|
try {
|
|
7376
|
-
await
|
|
7376
|
+
await fs35__default.access(path38__default.join(skillDir, SKILL_FILENAME));
|
|
7377
7377
|
return true;
|
|
7378
7378
|
} catch {
|
|
7379
7379
|
return false;
|
|
@@ -7381,16 +7381,16 @@ async function isMarkdownSkill(skillDir) {
|
|
|
7381
7381
|
}
|
|
7382
7382
|
async function loadMarkdownMetadata(skillDir, scope) {
|
|
7383
7383
|
try {
|
|
7384
|
-
const skillPath =
|
|
7385
|
-
const raw = await
|
|
7384
|
+
const skillPath = path38__default.join(skillDir, SKILL_FILENAME);
|
|
7385
|
+
const raw = await fs35__default.readFile(skillPath, "utf-8");
|
|
7386
7386
|
const { data } = matter(raw);
|
|
7387
7387
|
const parsed = SkillFrontmatterSchema.safeParse(data);
|
|
7388
7388
|
if (!parsed.success) {
|
|
7389
7389
|
return null;
|
|
7390
7390
|
}
|
|
7391
7391
|
const fm = parsed.data;
|
|
7392
|
-
const dirName =
|
|
7393
|
-
const parentDir =
|
|
7392
|
+
const dirName = path38__default.basename(skillDir);
|
|
7393
|
+
const parentDir = path38__default.basename(path38__default.dirname(skillDir));
|
|
7394
7394
|
const namespace = isNamespaceDirectory(parentDir) ? parentDir : void 0;
|
|
7395
7395
|
const baseId = toKebabCase(fm.name || dirName);
|
|
7396
7396
|
const fullId = namespace ? `${namespace}/${baseId}` : baseId;
|
|
@@ -7420,8 +7420,8 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
7420
7420
|
context: fm.context
|
|
7421
7421
|
};
|
|
7422
7422
|
} catch (error) {
|
|
7423
|
-
const
|
|
7424
|
-
|
|
7423
|
+
const logger2 = getLogger();
|
|
7424
|
+
logger2.warn(
|
|
7425
7425
|
`[Skills] Failed to load metadata from ${skillDir}:`,
|
|
7426
7426
|
error instanceof Error ? error.message : error
|
|
7427
7427
|
);
|
|
@@ -7430,8 +7430,8 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
7430
7430
|
}
|
|
7431
7431
|
async function loadMarkdownContent(skillDir) {
|
|
7432
7432
|
try {
|
|
7433
|
-
const skillPath =
|
|
7434
|
-
const raw = await
|
|
7433
|
+
const skillPath = path38__default.join(skillDir, SKILL_FILENAME);
|
|
7434
|
+
const raw = await fs35__default.readFile(skillPath, "utf-8");
|
|
7435
7435
|
const { content } = matter(raw);
|
|
7436
7436
|
const references = await listSubdirectory(skillDir, "references");
|
|
7437
7437
|
const scripts = await listSubdirectory(skillDir, "scripts");
|
|
@@ -7443,8 +7443,8 @@ async function loadMarkdownContent(skillDir) {
|
|
|
7443
7443
|
templates
|
|
7444
7444
|
};
|
|
7445
7445
|
} catch (error) {
|
|
7446
|
-
const
|
|
7447
|
-
|
|
7446
|
+
const logger2 = getLogger();
|
|
7447
|
+
logger2.warn(
|
|
7448
7448
|
`[Skills] Failed to load content from ${skillDir}:`,
|
|
7449
7449
|
error instanceof Error ? error.message : error
|
|
7450
7450
|
);
|
|
@@ -7453,9 +7453,9 @@ async function loadMarkdownContent(skillDir) {
|
|
|
7453
7453
|
}
|
|
7454
7454
|
async function listSubdirectory(skillDir, subdir) {
|
|
7455
7455
|
try {
|
|
7456
|
-
const dir =
|
|
7457
|
-
const entries = await
|
|
7458
|
-
return entries.filter((e) => e.isFile()).map((e) =>
|
|
7456
|
+
const dir = path38__default.join(skillDir, subdir);
|
|
7457
|
+
const entries = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
7458
|
+
return entries.filter((e) => e.isFile()).map((e) => path38__default.join(dir, e.name));
|
|
7459
7459
|
} catch {
|
|
7460
7460
|
return [];
|
|
7461
7461
|
}
|
|
@@ -7532,8 +7532,8 @@ async function loadSkillFromDirectory(skillDir, scope) {
|
|
|
7532
7532
|
if (await isMarkdownSkill(skillDir)) {
|
|
7533
7533
|
return loadMarkdownMetadata(skillDir, scope);
|
|
7534
7534
|
}
|
|
7535
|
-
const hasTs = await fileExists2(
|
|
7536
|
-
const hasJs = await fileExists2(
|
|
7535
|
+
const hasTs = await fileExists2(path38__default.join(skillDir, "index.ts"));
|
|
7536
|
+
const hasJs = await fileExists2(path38__default.join(skillDir, "index.js"));
|
|
7537
7537
|
if (hasTs || hasJs) {
|
|
7538
7538
|
return null;
|
|
7539
7539
|
}
|
|
@@ -7553,7 +7553,7 @@ async function loadFullSkill(metadata) {
|
|
|
7553
7553
|
}
|
|
7554
7554
|
async function fileExists2(filePath) {
|
|
7555
7555
|
try {
|
|
7556
|
-
await
|
|
7556
|
+
await fs35__default.access(filePath);
|
|
7557
7557
|
return true;
|
|
7558
7558
|
} catch {
|
|
7559
7559
|
return false;
|
|
@@ -7576,8 +7576,8 @@ function normalizeDirectories(dirs, relativeBaseDir) {
|
|
|
7576
7576
|
for (const dir of dirs) {
|
|
7577
7577
|
const trimmed = dir.trim();
|
|
7578
7578
|
if (!trimmed) continue;
|
|
7579
|
-
const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") ?
|
|
7580
|
-
const resolved =
|
|
7579
|
+
const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") ? path38__default.join(home, trimmed.slice(2)) : trimmed;
|
|
7580
|
+
const resolved = path38__default.isAbsolute(expanded) ? path38__default.resolve(expanded) : path38__default.resolve(relativeBaseDir ?? process.cwd(), expanded);
|
|
7581
7581
|
if (seen.has(resolved)) continue;
|
|
7582
7582
|
seen.add(resolved);
|
|
7583
7583
|
normalized.push(resolved);
|
|
@@ -7590,7 +7590,7 @@ function resolveDiscoveryDirs(projectPath, options) {
|
|
|
7590
7590
|
opts.globalDirs && opts.globalDirs.length > 0 ? opts.globalDirs : opts.globalDir ? [opts.globalDir] : GLOBAL_SKILLS_DIRS
|
|
7591
7591
|
);
|
|
7592
7592
|
const projectDirs = normalizeDirectories(
|
|
7593
|
-
opts.projectDirs && opts.projectDirs.length > 0 ? opts.projectDirs : opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) =>
|
|
7593
|
+
opts.projectDirs && opts.projectDirs.length > 0 ? opts.projectDirs : opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) => path38__default.join(projectPath, d)),
|
|
7594
7594
|
projectPath
|
|
7595
7595
|
);
|
|
7596
7596
|
return { globalDirs, projectDirs };
|
|
@@ -7618,13 +7618,13 @@ async function discoverAllSkills(projectPath, builtinSkills = [], options) {
|
|
|
7618
7618
|
}
|
|
7619
7619
|
async function scanSkillsDirectory(dir, scope) {
|
|
7620
7620
|
try {
|
|
7621
|
-
const entries = await
|
|
7621
|
+
const entries = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
7622
7622
|
const skillDirs = entries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
7623
7623
|
const results = [];
|
|
7624
7624
|
for (const entry of skillDirs) {
|
|
7625
|
-
const entryPath =
|
|
7625
|
+
const entryPath = path38__default.join(dir, entry.name);
|
|
7626
7626
|
try {
|
|
7627
|
-
const stat2 = await
|
|
7627
|
+
const stat2 = await fs35__default.lstat(entryPath);
|
|
7628
7628
|
if (stat2.isSymbolicLink()) continue;
|
|
7629
7629
|
} catch {
|
|
7630
7630
|
continue;
|
|
@@ -7640,8 +7640,8 @@ async function scanSkillsDirectory(dir, scope) {
|
|
|
7640
7640
|
return results.filter((meta) => meta !== null);
|
|
7641
7641
|
} catch (error) {
|
|
7642
7642
|
if (error.code !== "ENOENT") {
|
|
7643
|
-
const
|
|
7644
|
-
|
|
7643
|
+
const logger2 = getLogger();
|
|
7644
|
+
logger2.warn(
|
|
7645
7645
|
`[Skills] Failed to scan directory ${dir}:`,
|
|
7646
7646
|
error instanceof Error ? error.message : error
|
|
7647
7647
|
);
|
|
@@ -7652,13 +7652,13 @@ async function scanSkillsDirectory(dir, scope) {
|
|
|
7652
7652
|
async function scanNestedSkills(dir, scope, depth) {
|
|
7653
7653
|
if (depth >= MAX_NESTING_DEPTH) return [];
|
|
7654
7654
|
try {
|
|
7655
|
-
const subEntries = await
|
|
7655
|
+
const subEntries = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
7656
7656
|
const subDirs = subEntries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
7657
7657
|
const results = await Promise.all(
|
|
7658
7658
|
subDirs.map(async (sub) => {
|
|
7659
|
-
const subPath =
|
|
7659
|
+
const subPath = path38__default.join(dir, sub.name);
|
|
7660
7660
|
try {
|
|
7661
|
-
const stat2 = await
|
|
7661
|
+
const stat2 = await fs35__default.lstat(subPath);
|
|
7662
7662
|
if (stat2.isSymbolicLink()) return null;
|
|
7663
7663
|
} catch {
|
|
7664
7664
|
return null;
|
|
@@ -7686,17 +7686,17 @@ var init_discovery = __esm({
|
|
|
7686
7686
|
init_paths();
|
|
7687
7687
|
init_logger();
|
|
7688
7688
|
GLOBAL_SKILLS_DIRS = [
|
|
7689
|
-
|
|
7689
|
+
path38__default.join(homedir(), ".codex", "skills"),
|
|
7690
7690
|
// Codex CLI legacy compat
|
|
7691
|
-
|
|
7691
|
+
path38__default.join(homedir(), ".gemini", "skills"),
|
|
7692
7692
|
// Gemini CLI compat
|
|
7693
|
-
|
|
7693
|
+
path38__default.join(homedir(), ".opencode", "skills"),
|
|
7694
7694
|
// OpenCode compat
|
|
7695
|
-
|
|
7695
|
+
path38__default.join(homedir(), ".claude", "skills"),
|
|
7696
7696
|
// Claude Code compat
|
|
7697
|
-
|
|
7697
|
+
path38__default.join(homedir(), ".agents", "skills"),
|
|
7698
7698
|
// shared cross-agent standard
|
|
7699
|
-
|
|
7699
|
+
path38__default.join(COCO_HOME, "skills")
|
|
7700
7700
|
// Coco native global directory (authoritative for Coco)
|
|
7701
7701
|
];
|
|
7702
7702
|
PROJECT_SKILLS_DIRNAMES = [
|
|
@@ -8935,9 +8935,9 @@ function createEmptyMemoryContext() {
|
|
|
8935
8935
|
errors: []
|
|
8936
8936
|
};
|
|
8937
8937
|
}
|
|
8938
|
-
function createMissingMemoryFile(
|
|
8938
|
+
function createMissingMemoryFile(path60, level) {
|
|
8939
8939
|
return {
|
|
8940
|
-
path:
|
|
8940
|
+
path: path60,
|
|
8941
8941
|
level,
|
|
8942
8942
|
content: "",
|
|
8943
8943
|
sections: [],
|
|
@@ -9080,11 +9080,11 @@ var init_loader3 = __esm({
|
|
|
9080
9080
|
async loadFile(filePath, level) {
|
|
9081
9081
|
const resolvedPath = this.resolvePath(filePath);
|
|
9082
9082
|
try {
|
|
9083
|
-
const stat2 = await
|
|
9084
|
-
const rawContent = await
|
|
9083
|
+
const stat2 = await fs35.stat(resolvedPath);
|
|
9084
|
+
const rawContent = await fs35.readFile(resolvedPath, "utf-8");
|
|
9085
9085
|
const { content, imports } = await this.resolveImports(
|
|
9086
9086
|
rawContent,
|
|
9087
|
-
|
|
9087
|
+
path38.dirname(resolvedPath),
|
|
9088
9088
|
0
|
|
9089
9089
|
);
|
|
9090
9090
|
const sections = this.parseSections(content);
|
|
@@ -9111,16 +9111,16 @@ var init_loader3 = __esm({
|
|
|
9111
9111
|
if (this.config.includeUserLevel) {
|
|
9112
9112
|
const userDir = this.resolvePath(USER_CONFIG_DIR);
|
|
9113
9113
|
for (const pattern of this.config.filePatterns) {
|
|
9114
|
-
const userPath =
|
|
9114
|
+
const userPath = path38.join(userDir, pattern);
|
|
9115
9115
|
if (await this.fileExists(userPath)) {
|
|
9116
9116
|
result.user = userPath;
|
|
9117
9117
|
break;
|
|
9118
9118
|
}
|
|
9119
9119
|
}
|
|
9120
9120
|
}
|
|
9121
|
-
const absoluteProjectPath =
|
|
9121
|
+
const absoluteProjectPath = path38.resolve(projectPath);
|
|
9122
9122
|
for (const pattern of this.config.filePatterns) {
|
|
9123
|
-
const projectFilePath =
|
|
9123
|
+
const projectFilePath = path38.join(absoluteProjectPath, pattern);
|
|
9124
9124
|
if (await this.fileExists(projectFilePath)) {
|
|
9125
9125
|
result.project = projectFilePath;
|
|
9126
9126
|
break;
|
|
@@ -9128,14 +9128,14 @@ var init_loader3 = __esm({
|
|
|
9128
9128
|
}
|
|
9129
9129
|
const cwd = currentDir ?? process.cwd();
|
|
9130
9130
|
if (cwd.startsWith(absoluteProjectPath) && cwd !== absoluteProjectPath) {
|
|
9131
|
-
const relativePath =
|
|
9132
|
-
const parts = relativePath.split(
|
|
9131
|
+
const relativePath = path38.relative(absoluteProjectPath, cwd);
|
|
9132
|
+
const parts = relativePath.split(path38.sep);
|
|
9133
9133
|
const dirFiles = [];
|
|
9134
9134
|
let currentDir2 = absoluteProjectPath;
|
|
9135
9135
|
for (const part of parts) {
|
|
9136
|
-
currentDir2 =
|
|
9136
|
+
currentDir2 = path38.join(currentDir2, part);
|
|
9137
9137
|
for (const pattern of this.config.filePatterns) {
|
|
9138
|
-
const dirFilePath =
|
|
9138
|
+
const dirFilePath = path38.join(currentDir2, pattern);
|
|
9139
9139
|
if (await this.fileExists(dirFilePath)) {
|
|
9140
9140
|
dirFiles.push(dirFilePath);
|
|
9141
9141
|
break;
|
|
@@ -9149,7 +9149,7 @@ var init_loader3 = __esm({
|
|
|
9149
9149
|
for (const pattern of this.config.filePatterns) {
|
|
9150
9150
|
const baseName = pattern.replace(/\.md$/, "");
|
|
9151
9151
|
const localFileName = `${baseName}${LOCAL_SUFFIX}`;
|
|
9152
|
-
const localPath =
|
|
9152
|
+
const localPath = path38.join(absoluteProjectPath, localFileName);
|
|
9153
9153
|
if (await this.fileExists(localPath)) {
|
|
9154
9154
|
result.local = localPath;
|
|
9155
9155
|
break;
|
|
@@ -9200,10 +9200,10 @@ var init_loader3 = __esm({
|
|
|
9200
9200
|
};
|
|
9201
9201
|
try {
|
|
9202
9202
|
if (await this.fileExists(resolvedPath)) {
|
|
9203
|
-
const importedContent = await
|
|
9203
|
+
const importedContent = await fs35.readFile(resolvedPath, "utf-8");
|
|
9204
9204
|
const nestedResult = await this.resolveImports(
|
|
9205
9205
|
importedContent,
|
|
9206
|
-
|
|
9206
|
+
path38.dirname(resolvedPath),
|
|
9207
9207
|
depth + 1
|
|
9208
9208
|
);
|
|
9209
9209
|
processedLines.push(`<!-- Imported from: ${importPath} -->`);
|
|
@@ -9244,7 +9244,7 @@ var init_loader3 = __esm({
|
|
|
9244
9244
|
const parts = [];
|
|
9245
9245
|
for (const file of files) {
|
|
9246
9246
|
if (file.exists && file.content.trim()) {
|
|
9247
|
-
const label = file.level === "directory" ? `directory level (${
|
|
9247
|
+
const label = file.level === "directory" ? `directory level (${path38.dirname(file.path)}/${path38.basename(file.path)})` : `${file.level} level (${path38.basename(file.path)})`;
|
|
9248
9248
|
parts.push(`<!-- Memory: ${label} -->`);
|
|
9249
9249
|
parts.push(file.content);
|
|
9250
9250
|
parts.push("");
|
|
@@ -9307,9 +9307,9 @@ var init_loader3 = __esm({
|
|
|
9307
9307
|
*/
|
|
9308
9308
|
resolvePath(filePath) {
|
|
9309
9309
|
if (filePath.startsWith("~")) {
|
|
9310
|
-
return
|
|
9310
|
+
return path38.join(os4.homedir(), filePath.slice(1));
|
|
9311
9311
|
}
|
|
9312
|
-
return
|
|
9312
|
+
return path38.resolve(filePath);
|
|
9313
9313
|
}
|
|
9314
9314
|
/**
|
|
9315
9315
|
* Resolve an import path relative to a base directory.
|
|
@@ -9324,22 +9324,22 @@ var init_loader3 = __esm({
|
|
|
9324
9324
|
resolveImportPath(importPath, basePath) {
|
|
9325
9325
|
let resolved;
|
|
9326
9326
|
if (importPath.startsWith("~")) {
|
|
9327
|
-
resolved =
|
|
9327
|
+
resolved = path38.join(os4.homedir(), importPath.slice(1));
|
|
9328
9328
|
const userConfigDir = this.resolvePath(USER_CONFIG_DIR);
|
|
9329
|
-
if (!resolved.startsWith(userConfigDir +
|
|
9329
|
+
if (!resolved.startsWith(userConfigDir + path38.sep) && resolved !== userConfigDir) {
|
|
9330
9330
|
throw new Error(`Import path escapes user config directory: @${importPath}`);
|
|
9331
9331
|
}
|
|
9332
9332
|
return resolved;
|
|
9333
9333
|
}
|
|
9334
|
-
if (
|
|
9335
|
-
resolved =
|
|
9336
|
-
if (!resolved.startsWith(basePath +
|
|
9334
|
+
if (path38.isAbsolute(importPath)) {
|
|
9335
|
+
resolved = path38.resolve(importPath);
|
|
9336
|
+
if (!resolved.startsWith(basePath + path38.sep) && resolved !== basePath) {
|
|
9337
9337
|
throw new Error(`Import path escapes project directory: @${importPath}`);
|
|
9338
9338
|
}
|
|
9339
9339
|
return resolved;
|
|
9340
9340
|
}
|
|
9341
|
-
resolved =
|
|
9342
|
-
if (!resolved.startsWith(basePath +
|
|
9341
|
+
resolved = path38.resolve(basePath, importPath);
|
|
9342
|
+
if (!resolved.startsWith(basePath + path38.sep) && resolved !== basePath) {
|
|
9343
9343
|
throw new Error(`Import path escapes project directory: @${importPath}`);
|
|
9344
9344
|
}
|
|
9345
9345
|
return resolved;
|
|
@@ -9351,7 +9351,7 @@ var init_loader3 = __esm({
|
|
|
9351
9351
|
*/
|
|
9352
9352
|
async fileExists(filePath) {
|
|
9353
9353
|
try {
|
|
9354
|
-
await
|
|
9354
|
+
await fs35.access(filePath);
|
|
9355
9355
|
return true;
|
|
9356
9356
|
} catch {
|
|
9357
9357
|
return false;
|
|
@@ -9719,7 +9719,7 @@ function clearSession(session) {
|
|
|
9719
9719
|
}
|
|
9720
9720
|
async function loadTrustSettings() {
|
|
9721
9721
|
try {
|
|
9722
|
-
const content = await
|
|
9722
|
+
const content = await fs35__default.readFile(TRUST_SETTINGS_FILE, "utf-8");
|
|
9723
9723
|
const raw = JSON.parse(content);
|
|
9724
9724
|
return {
|
|
9725
9725
|
globalTrusted: raw.globalTrusted ?? [],
|
|
@@ -9738,9 +9738,9 @@ async function loadTrustSettings() {
|
|
|
9738
9738
|
}
|
|
9739
9739
|
async function saveTrustSettings(settings) {
|
|
9740
9740
|
try {
|
|
9741
|
-
await
|
|
9741
|
+
await fs35__default.mkdir(TRUST_SETTINGS_DIR, { recursive: true });
|
|
9742
9742
|
settings.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
9743
|
-
await
|
|
9743
|
+
await fs35__default.writeFile(TRUST_SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
|
|
9744
9744
|
} catch (error) {
|
|
9745
9745
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9746
9746
|
console.warn(`[Trust] Failed to save trust settings: ${msg}`);
|
|
@@ -9927,7 +9927,7 @@ var init_session = __esm({
|
|
|
9927
9927
|
init_manager();
|
|
9928
9928
|
init_compactor();
|
|
9929
9929
|
MAX_SKILL_INSTRUCTIONS_CHARS = 16e3;
|
|
9930
|
-
TRUST_SETTINGS_DIR =
|
|
9930
|
+
TRUST_SETTINGS_DIR = path38__default.dirname(CONFIG_PATHS.trustedTools);
|
|
9931
9931
|
TRUST_SETTINGS_FILE = CONFIG_PATHS.trustedTools;
|
|
9932
9932
|
CATEGORY_LABELS = {
|
|
9933
9933
|
file: "File Operations",
|
|
@@ -10210,13 +10210,13 @@ var init_types4 = __esm({
|
|
|
10210
10210
|
}
|
|
10211
10211
|
});
|
|
10212
10212
|
function getStatePath(projectPath) {
|
|
10213
|
-
return
|
|
10213
|
+
return path38.join(projectPath, ".coco", "state.json");
|
|
10214
10214
|
}
|
|
10215
10215
|
function createStateManager() {
|
|
10216
10216
|
async function load(projectPath) {
|
|
10217
10217
|
const statePath = getStatePath(projectPath);
|
|
10218
10218
|
try {
|
|
10219
|
-
const content = await
|
|
10219
|
+
const content = await fs35.readFile(statePath, "utf-8");
|
|
10220
10220
|
const file = JSON.parse(content);
|
|
10221
10221
|
if (file.version !== STATE_VERSION) {
|
|
10222
10222
|
console.warn(`State version mismatch: ${file.version} vs ${STATE_VERSION}`);
|
|
@@ -10235,7 +10235,7 @@ function createStateManager() {
|
|
|
10235
10235
|
}
|
|
10236
10236
|
async function save(state) {
|
|
10237
10237
|
const statePath = getStatePath(state.path);
|
|
10238
|
-
await
|
|
10238
|
+
await fs35.mkdir(path38.dirname(statePath), { recursive: true });
|
|
10239
10239
|
const file = {
|
|
10240
10240
|
version: STATE_VERSION,
|
|
10241
10241
|
state: {
|
|
@@ -10243,19 +10243,19 @@ function createStateManager() {
|
|
|
10243
10243
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10244
10244
|
}
|
|
10245
10245
|
};
|
|
10246
|
-
await
|
|
10246
|
+
await fs35.writeFile(statePath, JSON.stringify(file, null, 2), "utf-8");
|
|
10247
10247
|
}
|
|
10248
10248
|
async function clear(projectPath) {
|
|
10249
10249
|
const statePath = getStatePath(projectPath);
|
|
10250
10250
|
try {
|
|
10251
|
-
await
|
|
10251
|
+
await fs35.unlink(statePath);
|
|
10252
10252
|
} catch {
|
|
10253
10253
|
}
|
|
10254
10254
|
}
|
|
10255
10255
|
async function exists(projectPath) {
|
|
10256
10256
|
const statePath = getStatePath(projectPath);
|
|
10257
10257
|
try {
|
|
10258
|
-
await
|
|
10258
|
+
await fs35.access(statePath);
|
|
10259
10259
|
return true;
|
|
10260
10260
|
} catch {
|
|
10261
10261
|
return false;
|
|
@@ -10383,8 +10383,8 @@ __export(trust_store_exports, {
|
|
|
10383
10383
|
saveTrustStore: () => saveTrustStore,
|
|
10384
10384
|
updateLastAccessed: () => updateLastAccessed
|
|
10385
10385
|
});
|
|
10386
|
-
async function ensureDir(
|
|
10387
|
-
await mkdir(dirname(
|
|
10386
|
+
async function ensureDir(path60) {
|
|
10387
|
+
await mkdir(dirname(path60), { recursive: true });
|
|
10388
10388
|
}
|
|
10389
10389
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
10390
10390
|
try {
|
|
@@ -10408,8 +10408,8 @@ async function saveTrustStore(store, storePath = TRUST_STORE_PATH) {
|
|
|
10408
10408
|
await ensureDir(storePath);
|
|
10409
10409
|
await writeFile(storePath, JSON.stringify(store, null, 2), "utf-8");
|
|
10410
10410
|
} catch (error) {
|
|
10411
|
-
const
|
|
10412
|
-
|
|
10411
|
+
const logger2 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
10412
|
+
logger2.warn(
|
|
10413
10413
|
`[TrustStore] Failed to save: ${error instanceof Error ? error.message : String(error)}`
|
|
10414
10414
|
);
|
|
10415
10415
|
}
|
|
@@ -10469,8 +10469,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
10469
10469
|
};
|
|
10470
10470
|
return permissions[level]?.includes(operation) ?? false;
|
|
10471
10471
|
}
|
|
10472
|
-
function normalizePath(
|
|
10473
|
-
return join(
|
|
10472
|
+
function normalizePath(path60) {
|
|
10473
|
+
return join(path60);
|
|
10474
10474
|
}
|
|
10475
10475
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
10476
10476
|
let store = null;
|
|
@@ -10826,12 +10826,12 @@ function humanizeError(message, toolName) {
|
|
|
10826
10826
|
return msg;
|
|
10827
10827
|
}
|
|
10828
10828
|
if (/ENOENT/i.test(msg)) {
|
|
10829
|
-
const
|
|
10830
|
-
return
|
|
10829
|
+
const path60 = extractQuotedPath(msg);
|
|
10830
|
+
return path60 ? `File or directory not found: ${path60}` : "File or directory not found";
|
|
10831
10831
|
}
|
|
10832
10832
|
if (/EACCES/i.test(msg)) {
|
|
10833
|
-
const
|
|
10834
|
-
return
|
|
10833
|
+
const path60 = extractQuotedPath(msg);
|
|
10834
|
+
return path60 ? `Permission denied: ${path60}` : "Permission denied \u2014 check file permissions";
|
|
10835
10835
|
}
|
|
10836
10836
|
if (/EISDIR/i.test(msg)) {
|
|
10837
10837
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -11306,7 +11306,7 @@ Suggestion: ${error.suggestion}`;
|
|
|
11306
11306
|
});
|
|
11307
11307
|
async function fileExists3(filePath) {
|
|
11308
11308
|
try {
|
|
11309
|
-
await
|
|
11309
|
+
await fs35__default.access(filePath);
|
|
11310
11310
|
return true;
|
|
11311
11311
|
} catch {
|
|
11312
11312
|
return false;
|
|
@@ -11765,9 +11765,9 @@ var init_diff_renderer = __esm({
|
|
|
11765
11765
|
getTerminalWidth = () => process.stdout.columns || 80;
|
|
11766
11766
|
}
|
|
11767
11767
|
});
|
|
11768
|
-
async function fileExists4(
|
|
11768
|
+
async function fileExists4(path60) {
|
|
11769
11769
|
try {
|
|
11770
|
-
await access(
|
|
11770
|
+
await access(path60);
|
|
11771
11771
|
return true;
|
|
11772
11772
|
} catch {
|
|
11773
11773
|
return false;
|
|
@@ -11857,7 +11857,7 @@ async function detectMaturity(cwd) {
|
|
|
11857
11857
|
if (!hasLintConfig && hasPackageJson) {
|
|
11858
11858
|
try {
|
|
11859
11859
|
const pkgRaw = await import('fs/promises').then(
|
|
11860
|
-
(
|
|
11860
|
+
(fs56) => fs56.readFile(join(cwd, "package.json"), "utf-8")
|
|
11861
11861
|
);
|
|
11862
11862
|
const pkg = JSON.parse(pkgRaw);
|
|
11863
11863
|
if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
|
|
@@ -12879,7 +12879,7 @@ var init_build_verifier = __esm({
|
|
|
12879
12879
|
async verifyTypes() {
|
|
12880
12880
|
const startTime = Date.now();
|
|
12881
12881
|
try {
|
|
12882
|
-
const hasTsConfig = await this.fileExists(
|
|
12882
|
+
const hasTsConfig = await this.fileExists(path38.join(this.projectPath, "tsconfig.json"));
|
|
12883
12883
|
if (!hasTsConfig) {
|
|
12884
12884
|
return {
|
|
12885
12885
|
success: true,
|
|
@@ -12929,19 +12929,19 @@ var init_build_verifier = __esm({
|
|
|
12929
12929
|
* Checks Maven, Gradle, and Node.js in that order.
|
|
12930
12930
|
*/
|
|
12931
12931
|
async detectBuildCommand() {
|
|
12932
|
-
if (await this.fileExists(
|
|
12933
|
-
const wrapper =
|
|
12932
|
+
if (await this.fileExists(path38.join(this.projectPath, "pom.xml"))) {
|
|
12933
|
+
const wrapper = path38.join(this.projectPath, "mvnw");
|
|
12934
12934
|
return await this.fileExists(wrapper) ? "./mvnw compile -B -q" : "mvn compile -B -q";
|
|
12935
12935
|
}
|
|
12936
12936
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
12937
|
-
if (await this.fileExists(
|
|
12938
|
-
const wrapper =
|
|
12937
|
+
if (await this.fileExists(path38.join(this.projectPath, f))) {
|
|
12938
|
+
const wrapper = path38.join(this.projectPath, "gradlew");
|
|
12939
12939
|
return await this.fileExists(wrapper) ? "./gradlew classes -q" : "gradle classes -q";
|
|
12940
12940
|
}
|
|
12941
12941
|
}
|
|
12942
12942
|
try {
|
|
12943
|
-
const packageJsonPath =
|
|
12944
|
-
const content = await
|
|
12943
|
+
const packageJsonPath = path38.join(this.projectPath, "package.json");
|
|
12944
|
+
const content = await fs35.readFile(packageJsonPath, "utf-8");
|
|
12945
12945
|
const packageJson = JSON.parse(content);
|
|
12946
12946
|
if (packageJson.scripts?.build) {
|
|
12947
12947
|
return "npm run build";
|
|
@@ -13016,7 +13016,7 @@ var init_build_verifier = __esm({
|
|
|
13016
13016
|
*/
|
|
13017
13017
|
async fileExists(filePath) {
|
|
13018
13018
|
try {
|
|
13019
|
-
await
|
|
13019
|
+
await fs35.access(filePath);
|
|
13020
13020
|
return true;
|
|
13021
13021
|
} catch {
|
|
13022
13022
|
return false;
|
|
@@ -14675,9 +14675,9 @@ function detectProjectLanguage(files) {
|
|
|
14675
14675
|
return { language: dominant, confidence, evidence };
|
|
14676
14676
|
}
|
|
14677
14677
|
function getFileExtension(filePath) {
|
|
14678
|
-
const base =
|
|
14678
|
+
const base = path38.basename(filePath);
|
|
14679
14679
|
if (base.endsWith(".d.ts")) return ".d.ts";
|
|
14680
|
-
return
|
|
14680
|
+
return path38.extname(filePath).toLowerCase();
|
|
14681
14681
|
}
|
|
14682
14682
|
function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
14683
14683
|
const evidence = [];
|
|
@@ -14685,7 +14685,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
|
14685
14685
|
evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
|
|
14686
14686
|
const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
|
|
14687
14687
|
for (const cfg of configFiles) {
|
|
14688
|
-
if (files.some((f) =>
|
|
14688
|
+
if (files.some((f) => path38.basename(f) === cfg)) {
|
|
14689
14689
|
evidence.push(`Found ${cfg}`);
|
|
14690
14690
|
}
|
|
14691
14691
|
}
|
|
@@ -16180,20 +16180,20 @@ var init_evaluator = __esm({
|
|
|
16180
16180
|
});
|
|
16181
16181
|
async function detectLinter2(cwd) {
|
|
16182
16182
|
try {
|
|
16183
|
-
await
|
|
16183
|
+
await fs35__default.access(path38__default.join(cwd, "pom.xml"));
|
|
16184
16184
|
return "maven-checkstyle";
|
|
16185
16185
|
} catch {
|
|
16186
16186
|
}
|
|
16187
16187
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
16188
16188
|
try {
|
|
16189
|
-
await
|
|
16189
|
+
await fs35__default.access(path38__default.join(cwd, f));
|
|
16190
16190
|
return "gradle-checkstyle";
|
|
16191
16191
|
} catch {
|
|
16192
16192
|
}
|
|
16193
16193
|
}
|
|
16194
16194
|
try {
|
|
16195
|
-
const pkgPath =
|
|
16196
|
-
const pkgContent = await
|
|
16195
|
+
const pkgPath = path38__default.join(cwd, "package.json");
|
|
16196
|
+
const pkgContent = await fs35__default.readFile(pkgPath, "utf-8");
|
|
16197
16197
|
const pkg = JSON.parse(pkgContent);
|
|
16198
16198
|
const deps = {
|
|
16199
16199
|
...pkg.dependencies,
|
|
@@ -16209,7 +16209,7 @@ async function detectLinter2(cwd) {
|
|
|
16209
16209
|
}
|
|
16210
16210
|
async function mavenExec(cwd) {
|
|
16211
16211
|
try {
|
|
16212
|
-
await
|
|
16212
|
+
await fs35__default.access(path38__default.join(cwd, "mvnw"));
|
|
16213
16213
|
return "./mvnw";
|
|
16214
16214
|
} catch {
|
|
16215
16215
|
return "mvn";
|
|
@@ -16217,7 +16217,7 @@ async function mavenExec(cwd) {
|
|
|
16217
16217
|
}
|
|
16218
16218
|
async function gradleExec(cwd) {
|
|
16219
16219
|
try {
|
|
16220
|
-
await
|
|
16220
|
+
await fs35__default.access(path38__default.join(cwd, "gradlew"));
|
|
16221
16221
|
return "./gradlew";
|
|
16222
16222
|
} catch {
|
|
16223
16223
|
return "gradle";
|
|
@@ -16286,14 +16286,14 @@ async function findSourceFiles(cwd) {
|
|
|
16286
16286
|
const { glob: glob17 } = await import('glob');
|
|
16287
16287
|
let isJava = false;
|
|
16288
16288
|
try {
|
|
16289
|
-
await
|
|
16289
|
+
await fs35__default.access(path38__default.join(cwd, "pom.xml"));
|
|
16290
16290
|
isJava = true;
|
|
16291
16291
|
} catch {
|
|
16292
16292
|
}
|
|
16293
16293
|
if (!isJava) {
|
|
16294
16294
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
16295
16295
|
try {
|
|
16296
|
-
await
|
|
16296
|
+
await fs35__default.access(path38__default.join(cwd, f));
|
|
16297
16297
|
isJava = true;
|
|
16298
16298
|
break;
|
|
16299
16299
|
} catch {
|
|
@@ -16501,7 +16501,7 @@ Examples:
|
|
|
16501
16501
|
let totalFunctions = 0;
|
|
16502
16502
|
let complexFunctions = 0;
|
|
16503
16503
|
for (const file of targetFiles) {
|
|
16504
|
-
const content = await
|
|
16504
|
+
const content = await fs35__default.readFile(file, "utf-8");
|
|
16505
16505
|
const fileComplexity = analyzeFileComplexity(content, file);
|
|
16506
16506
|
fileResults.push(fileComplexity);
|
|
16507
16507
|
totalComplexity += fileComplexity.complexity;
|
|
@@ -16648,7 +16648,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
16648
16648
|
);
|
|
16649
16649
|
if (!hasTestChange) {
|
|
16650
16650
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
16651
|
-
const testExists = await fileExists3(
|
|
16651
|
+
const testExists = await fileExists3(path38__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists3(path38__default.join(cwd, `${baseName}.spec${ext}`));
|
|
16652
16652
|
if (testExists) {
|
|
16653
16653
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
16654
16654
|
findings.push({
|
|
@@ -18329,7 +18329,7 @@ var init_github = __esm({
|
|
|
18329
18329
|
});
|
|
18330
18330
|
async function detectVersionFile(cwd) {
|
|
18331
18331
|
for (const { file, stack, field } of VERSION_FILES) {
|
|
18332
|
-
const fullPath =
|
|
18332
|
+
const fullPath = path38__default.join(cwd, file);
|
|
18333
18333
|
if (await fileExists3(fullPath)) {
|
|
18334
18334
|
const version = await readVersionFromFile(fullPath, stack, field);
|
|
18335
18335
|
if (version) {
|
|
@@ -18375,7 +18375,7 @@ function bumpVersion(current, bump) {
|
|
|
18375
18375
|
}
|
|
18376
18376
|
}
|
|
18377
18377
|
async function writeVersion(cwd, versionFile, newVersion) {
|
|
18378
|
-
const fullPath =
|
|
18378
|
+
const fullPath = path38__default.join(cwd, versionFile.path);
|
|
18379
18379
|
const content = await readFile(fullPath, "utf-8");
|
|
18380
18380
|
let updated;
|
|
18381
18381
|
switch (versionFile.stack) {
|
|
@@ -18434,7 +18434,7 @@ var init_version_detector = __esm({
|
|
|
18434
18434
|
});
|
|
18435
18435
|
async function detectChangelog(cwd) {
|
|
18436
18436
|
for (const name of CHANGELOG_NAMES) {
|
|
18437
|
-
const fullPath =
|
|
18437
|
+
const fullPath = path38__default.join(cwd, name);
|
|
18438
18438
|
if (await fileExists3(fullPath)) {
|
|
18439
18439
|
const content = await readFile(fullPath, "utf-8");
|
|
18440
18440
|
const format = detectFormat(content);
|
|
@@ -18456,7 +18456,7 @@ function detectFormat(content) {
|
|
|
18456
18456
|
return "custom";
|
|
18457
18457
|
}
|
|
18458
18458
|
async function insertChangelogEntry(cwd, changelog, version, entries, date) {
|
|
18459
|
-
const fullPath =
|
|
18459
|
+
const fullPath = path38__default.join(cwd, changelog.path);
|
|
18460
18460
|
const content = await readFile(fullPath, "utf-8");
|
|
18461
18461
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18462
18462
|
const entry = buildEntry(changelog.format, version, entries, dateStr);
|
|
@@ -18517,11 +18517,11 @@ var init_changelog = __esm({
|
|
|
18517
18517
|
}
|
|
18518
18518
|
});
|
|
18519
18519
|
async function detectStack(cwd) {
|
|
18520
|
-
if (await fileExists3(
|
|
18521
|
-
if (await fileExists3(
|
|
18522
|
-
if (await fileExists3(
|
|
18523
|
-
if (await fileExists3(
|
|
18524
|
-
if (await fileExists3(
|
|
18520
|
+
if (await fileExists3(path38__default.join(cwd, "package.json"))) return "node";
|
|
18521
|
+
if (await fileExists3(path38__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
18522
|
+
if (await fileExists3(path38__default.join(cwd, "pyproject.toml"))) return "python";
|
|
18523
|
+
if (await fileExists3(path38__default.join(cwd, "go.mod"))) return "go";
|
|
18524
|
+
if (await fileExists3(path38__default.join(cwd, "pom.xml"))) return "java";
|
|
18525
18525
|
return "unknown";
|
|
18526
18526
|
}
|
|
18527
18527
|
async function detectPackageManager(cwd, stack) {
|
|
@@ -18529,15 +18529,15 @@ async function detectPackageManager(cwd, stack) {
|
|
|
18529
18529
|
if (stack === "python") return "pip";
|
|
18530
18530
|
if (stack === "go") return "go";
|
|
18531
18531
|
if (stack === "node") {
|
|
18532
|
-
if (await fileExists3(
|
|
18533
|
-
if (await fileExists3(
|
|
18534
|
-
if (await fileExists3(
|
|
18532
|
+
if (await fileExists3(path38__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
18533
|
+
if (await fileExists3(path38__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
18534
|
+
if (await fileExists3(path38__default.join(cwd, "bun.lockb"))) return "bun";
|
|
18535
18535
|
return "npm";
|
|
18536
18536
|
}
|
|
18537
18537
|
return null;
|
|
18538
18538
|
}
|
|
18539
18539
|
async function detectCI(cwd) {
|
|
18540
|
-
const ghDir =
|
|
18540
|
+
const ghDir = path38__default.join(cwd, ".github", "workflows");
|
|
18541
18541
|
if (await fileExists3(ghDir)) {
|
|
18542
18542
|
let workflowFiles = [];
|
|
18543
18543
|
let hasCodeQL = false;
|
|
@@ -18561,7 +18561,7 @@ async function detectCI(cwd) {
|
|
|
18561
18561
|
}
|
|
18562
18562
|
return { type: "github-actions", workflowFiles, hasCodeQL, hasLinting };
|
|
18563
18563
|
}
|
|
18564
|
-
if (await fileExists3(
|
|
18564
|
+
if (await fileExists3(path38__default.join(cwd, ".gitlab-ci.yml"))) {
|
|
18565
18565
|
return {
|
|
18566
18566
|
type: "gitlab-ci",
|
|
18567
18567
|
workflowFiles: [".gitlab-ci.yml"],
|
|
@@ -18569,7 +18569,7 @@ async function detectCI(cwd) {
|
|
|
18569
18569
|
hasLinting: false
|
|
18570
18570
|
};
|
|
18571
18571
|
}
|
|
18572
|
-
if (await fileExists3(
|
|
18572
|
+
if (await fileExists3(path38__default.join(cwd, ".circleci"))) {
|
|
18573
18573
|
return { type: "circle-ci", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
18574
18574
|
}
|
|
18575
18575
|
return { type: "none", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
@@ -19940,8 +19940,8 @@ function hasNullByte(str) {
|
|
|
19940
19940
|
}
|
|
19941
19941
|
function isBlockedPath(absolute) {
|
|
19942
19942
|
for (const blocked of BLOCKED_PATHS) {
|
|
19943
|
-
const normalizedBlocked =
|
|
19944
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
19943
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
19944
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
19945
19945
|
return blocked;
|
|
19946
19946
|
}
|
|
19947
19947
|
}
|
|
@@ -19959,7 +19959,7 @@ function getInterpreter(ext) {
|
|
|
19959
19959
|
}
|
|
19960
19960
|
async function isExecutable(filePath) {
|
|
19961
19961
|
try {
|
|
19962
|
-
await
|
|
19962
|
+
await fs35__default.access(filePath, fs35__default.constants.X_OK);
|
|
19963
19963
|
return true;
|
|
19964
19964
|
} catch {
|
|
19965
19965
|
return false;
|
|
@@ -20035,7 +20035,7 @@ Examples:
|
|
|
20035
20035
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
20036
20036
|
}
|
|
20037
20037
|
const workDir = cwd ?? process.cwd();
|
|
20038
|
-
const absolute =
|
|
20038
|
+
const absolute = path38__default.isAbsolute(filePath) ? path38__default.normalize(filePath) : path38__default.resolve(workDir, filePath);
|
|
20039
20039
|
const blockedBy = isBlockedPath(absolute);
|
|
20040
20040
|
if (blockedBy) {
|
|
20041
20041
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -20043,7 +20043,7 @@ Examples:
|
|
|
20043
20043
|
});
|
|
20044
20044
|
}
|
|
20045
20045
|
try {
|
|
20046
|
-
await
|
|
20046
|
+
await fs35__default.access(absolute);
|
|
20047
20047
|
} catch {
|
|
20048
20048
|
throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
|
|
20049
20049
|
}
|
|
@@ -20058,14 +20058,14 @@ Examples:
|
|
|
20058
20058
|
};
|
|
20059
20059
|
}
|
|
20060
20060
|
if (isBlockedExecFile(absolute)) {
|
|
20061
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
20061
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path38__default.basename(absolute)}`, {
|
|
20062
20062
|
tool: "open_file"
|
|
20063
20063
|
});
|
|
20064
20064
|
}
|
|
20065
20065
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
20066
20066
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
20067
20067
|
}
|
|
20068
|
-
const ext =
|
|
20068
|
+
const ext = path38__default.extname(absolute);
|
|
20069
20069
|
const interpreter = getInterpreter(ext);
|
|
20070
20070
|
const executable = await isExecutable(absolute);
|
|
20071
20071
|
let command;
|
|
@@ -20078,7 +20078,7 @@ Examples:
|
|
|
20078
20078
|
cmdArgs = [...args];
|
|
20079
20079
|
} else {
|
|
20080
20080
|
throw new ToolError(
|
|
20081
|
-
`Cannot execute '${
|
|
20081
|
+
`Cannot execute '${path38__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
20082
20082
|
{ tool: "open_file" }
|
|
20083
20083
|
);
|
|
20084
20084
|
}
|
|
@@ -20250,10 +20250,10 @@ function getAllowedPaths() {
|
|
|
20250
20250
|
return [...sessionAllowedPaths];
|
|
20251
20251
|
}
|
|
20252
20252
|
function isWithinAllowedPath(absolutePath, operation) {
|
|
20253
|
-
const normalizedTarget =
|
|
20253
|
+
const normalizedTarget = path38__default.normalize(absolutePath);
|
|
20254
20254
|
for (const entry of sessionAllowedPaths) {
|
|
20255
|
-
const normalizedAllowed =
|
|
20256
|
-
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed +
|
|
20255
|
+
const normalizedAllowed = path38__default.normalize(entry.path);
|
|
20256
|
+
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path38__default.sep)) {
|
|
20257
20257
|
if (operation === "read") return true;
|
|
20258
20258
|
if (entry.level === "write") return true;
|
|
20259
20259
|
}
|
|
@@ -20261,8 +20261,8 @@ function isWithinAllowedPath(absolutePath, operation) {
|
|
|
20261
20261
|
return false;
|
|
20262
20262
|
}
|
|
20263
20263
|
function addAllowedPathToSession(dirPath, level) {
|
|
20264
|
-
const absolute =
|
|
20265
|
-
if (sessionAllowedPaths.some((e) =>
|
|
20264
|
+
const absolute = path38__default.resolve(dirPath);
|
|
20265
|
+
if (sessionAllowedPaths.some((e) => path38__default.normalize(e.path) === path38__default.normalize(absolute))) {
|
|
20266
20266
|
return;
|
|
20267
20267
|
}
|
|
20268
20268
|
sessionAllowedPaths.push({
|
|
@@ -20272,14 +20272,14 @@ function addAllowedPathToSession(dirPath, level) {
|
|
|
20272
20272
|
});
|
|
20273
20273
|
}
|
|
20274
20274
|
function removeAllowedPathFromSession(dirPath) {
|
|
20275
|
-
const absolute =
|
|
20276
|
-
const normalized =
|
|
20275
|
+
const absolute = path38__default.resolve(dirPath);
|
|
20276
|
+
const normalized = path38__default.normalize(absolute);
|
|
20277
20277
|
const before = sessionAllowedPaths.length;
|
|
20278
|
-
sessionAllowedPaths = sessionAllowedPaths.filter((e) =>
|
|
20278
|
+
sessionAllowedPaths = sessionAllowedPaths.filter((e) => path38__default.normalize(e.path) !== normalized);
|
|
20279
20279
|
return sessionAllowedPaths.length < before;
|
|
20280
20280
|
}
|
|
20281
20281
|
async function loadAllowedPaths(projectPath) {
|
|
20282
|
-
currentProjectPath =
|
|
20282
|
+
currentProjectPath = path38__default.resolve(projectPath);
|
|
20283
20283
|
const store = await loadStore();
|
|
20284
20284
|
const entries = store.projects[currentProjectPath] ?? [];
|
|
20285
20285
|
for (const entry of entries) {
|
|
@@ -20288,14 +20288,14 @@ async function loadAllowedPaths(projectPath) {
|
|
|
20288
20288
|
}
|
|
20289
20289
|
async function persistAllowedPath(dirPath, level) {
|
|
20290
20290
|
if (!currentProjectPath) return;
|
|
20291
|
-
const absolute =
|
|
20291
|
+
const absolute = path38__default.resolve(dirPath);
|
|
20292
20292
|
const store = await loadStore();
|
|
20293
20293
|
if (!store.projects[currentProjectPath]) {
|
|
20294
20294
|
store.projects[currentProjectPath] = [];
|
|
20295
20295
|
}
|
|
20296
20296
|
const entries = store.projects[currentProjectPath];
|
|
20297
|
-
const normalized =
|
|
20298
|
-
if (entries.some((e) =>
|
|
20297
|
+
const normalized = path38__default.normalize(absolute);
|
|
20298
|
+
if (entries.some((e) => path38__default.normalize(e.path) === normalized)) {
|
|
20299
20299
|
return;
|
|
20300
20300
|
}
|
|
20301
20301
|
entries.push({
|
|
@@ -20307,13 +20307,13 @@ async function persistAllowedPath(dirPath, level) {
|
|
|
20307
20307
|
}
|
|
20308
20308
|
async function removePersistedAllowedPath(dirPath) {
|
|
20309
20309
|
if (!currentProjectPath) return false;
|
|
20310
|
-
const absolute =
|
|
20311
|
-
const normalized =
|
|
20310
|
+
const absolute = path38__default.resolve(dirPath);
|
|
20311
|
+
const normalized = path38__default.normalize(absolute);
|
|
20312
20312
|
const store = await loadStore();
|
|
20313
20313
|
const entries = store.projects[currentProjectPath];
|
|
20314
20314
|
if (!entries) return false;
|
|
20315
20315
|
const before = entries.length;
|
|
20316
|
-
store.projects[currentProjectPath] = entries.filter((e) =>
|
|
20316
|
+
store.projects[currentProjectPath] = entries.filter((e) => path38__default.normalize(e.path) !== normalized);
|
|
20317
20317
|
if (store.projects[currentProjectPath].length < before) {
|
|
20318
20318
|
await saveStore(store);
|
|
20319
20319
|
return true;
|
|
@@ -20322,7 +20322,7 @@ async function removePersistedAllowedPath(dirPath) {
|
|
|
20322
20322
|
}
|
|
20323
20323
|
async function loadStore() {
|
|
20324
20324
|
try {
|
|
20325
|
-
const content = await
|
|
20325
|
+
const content = await fs35__default.readFile(STORE_FILE, "utf-8");
|
|
20326
20326
|
return { ...DEFAULT_STORE, ...JSON.parse(content) };
|
|
20327
20327
|
} catch {
|
|
20328
20328
|
return { ...DEFAULT_STORE };
|
|
@@ -20330,8 +20330,8 @@ async function loadStore() {
|
|
|
20330
20330
|
}
|
|
20331
20331
|
async function saveStore(store) {
|
|
20332
20332
|
try {
|
|
20333
|
-
await
|
|
20334
|
-
await
|
|
20333
|
+
await fs35__default.mkdir(path38__default.dirname(STORE_FILE), { recursive: true });
|
|
20334
|
+
await fs35__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
20335
20335
|
} catch {
|
|
20336
20336
|
}
|
|
20337
20337
|
}
|
|
@@ -20339,7 +20339,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
|
|
|
20339
20339
|
var init_allowed_paths = __esm({
|
|
20340
20340
|
"src/tools/allowed-paths.ts"() {
|
|
20341
20341
|
init_paths();
|
|
20342
|
-
STORE_FILE =
|
|
20342
|
+
STORE_FILE = path38__default.join(CONFIG_PATHS.home, "allowed-paths.json");
|
|
20343
20343
|
DEFAULT_STORE = {
|
|
20344
20344
|
version: 1,
|
|
20345
20345
|
projects: {}
|
|
@@ -20395,7 +20395,7 @@ function shouldAutoApprove(command, cwd) {
|
|
|
20395
20395
|
}
|
|
20396
20396
|
async function loadFullAccessPreference() {
|
|
20397
20397
|
try {
|
|
20398
|
-
const content = await
|
|
20398
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
20399
20399
|
const config = JSON.parse(content);
|
|
20400
20400
|
if (typeof config.fullAccessMode === "boolean") {
|
|
20401
20401
|
fullAccessEnabled = config.fullAccessMode;
|
|
@@ -20409,12 +20409,12 @@ async function saveFullAccessPreference(enabled) {
|
|
|
20409
20409
|
try {
|
|
20410
20410
|
let config = {};
|
|
20411
20411
|
try {
|
|
20412
|
-
const content = await
|
|
20412
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
20413
20413
|
config = JSON.parse(content);
|
|
20414
20414
|
} catch {
|
|
20415
20415
|
}
|
|
20416
20416
|
config.fullAccessMode = enabled;
|
|
20417
|
-
await
|
|
20417
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
20418
20418
|
} catch {
|
|
20419
20419
|
}
|
|
20420
20420
|
}
|
|
@@ -20822,12 +20822,384 @@ var init_stdio = __esm({
|
|
|
20822
20822
|
};
|
|
20823
20823
|
}
|
|
20824
20824
|
});
|
|
20825
|
+
function getResourceKey(resourceUrl) {
|
|
20826
|
+
const resource = canonicalizeResourceUrl(resourceUrl);
|
|
20827
|
+
return resource.toLowerCase();
|
|
20828
|
+
}
|
|
20829
|
+
function canonicalizeResourceUrl(resourceUrl) {
|
|
20830
|
+
const parsed = new URL(resourceUrl);
|
|
20831
|
+
parsed.search = "";
|
|
20832
|
+
parsed.hash = "";
|
|
20833
|
+
if (parsed.pathname === "/") {
|
|
20834
|
+
return `${parsed.protocol}//${parsed.host}`;
|
|
20835
|
+
}
|
|
20836
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "");
|
|
20837
|
+
return parsed.toString();
|
|
20838
|
+
}
|
|
20839
|
+
async function loadStore2() {
|
|
20840
|
+
try {
|
|
20841
|
+
const content = await fs35__default.readFile(TOKEN_STORE_PATH, "utf-8");
|
|
20842
|
+
const parsed = JSON.parse(content);
|
|
20843
|
+
return {
|
|
20844
|
+
tokens: parsed.tokens ?? {},
|
|
20845
|
+
clients: parsed.clients ?? {}
|
|
20846
|
+
};
|
|
20847
|
+
} catch {
|
|
20848
|
+
return { tokens: {}, clients: {} };
|
|
20849
|
+
}
|
|
20850
|
+
}
|
|
20851
|
+
async function saveStore2(store) {
|
|
20852
|
+
await fs35__default.mkdir(path38__default.dirname(TOKEN_STORE_PATH), { recursive: true });
|
|
20853
|
+
await fs35__default.writeFile(TOKEN_STORE_PATH, JSON.stringify(store, null, 2), {
|
|
20854
|
+
encoding: "utf-8",
|
|
20855
|
+
mode: 384
|
|
20856
|
+
});
|
|
20857
|
+
}
|
|
20858
|
+
function isTokenExpired2(token) {
|
|
20859
|
+
if (!token.expiresAt) return false;
|
|
20860
|
+
return Date.now() >= token.expiresAt - 3e4;
|
|
20861
|
+
}
|
|
20862
|
+
async function getStoredMcpOAuthToken(resourceUrl) {
|
|
20863
|
+
const store = await loadStore2();
|
|
20864
|
+
const token = store.tokens[getResourceKey(resourceUrl)];
|
|
20865
|
+
if (!token) return void 0;
|
|
20866
|
+
if (isTokenExpired2(token)) return void 0;
|
|
20867
|
+
return token.accessToken;
|
|
20868
|
+
}
|
|
20869
|
+
function createCodeVerifier() {
|
|
20870
|
+
return randomBytes(32).toString("base64url");
|
|
20871
|
+
}
|
|
20872
|
+
function createCodeChallenge(verifier) {
|
|
20873
|
+
return createHash("sha256").update(verifier).digest("base64url");
|
|
20874
|
+
}
|
|
20875
|
+
function createState() {
|
|
20876
|
+
return randomBytes(16).toString("hex");
|
|
20877
|
+
}
|
|
20878
|
+
async function openBrowser2(url) {
|
|
20879
|
+
let safeUrl;
|
|
20880
|
+
try {
|
|
20881
|
+
const parsed = new URL(url);
|
|
20882
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
|
|
20883
|
+
return false;
|
|
20884
|
+
}
|
|
20885
|
+
safeUrl = parsed.toString();
|
|
20886
|
+
} catch {
|
|
20887
|
+
return false;
|
|
20888
|
+
}
|
|
20889
|
+
const isWSL2 = process.platform === "linux" && (process.env["WSL_DISTRO_NAME"] !== void 0 || process.env["WSL_INTEROP"] !== void 0 || process.env["TERM_PROGRAM"]?.toLowerCase().includes("wsl") === true);
|
|
20890
|
+
const commands2 = [];
|
|
20891
|
+
if (process.platform === "darwin") {
|
|
20892
|
+
commands2.push(
|
|
20893
|
+
{ cmd: "open", args: [safeUrl] },
|
|
20894
|
+
{ cmd: "open", args: ["-a", "Safari", safeUrl] },
|
|
20895
|
+
{ cmd: "open", args: ["-a", "Google Chrome", safeUrl] }
|
|
20896
|
+
);
|
|
20897
|
+
} else if (process.platform === "win32") {
|
|
20898
|
+
commands2.push({ cmd: "rundll32", args: ["url.dll,FileProtocolHandler", safeUrl] });
|
|
20899
|
+
} else if (isWSL2) {
|
|
20900
|
+
commands2.push(
|
|
20901
|
+
{ cmd: "cmd.exe", args: ["/c", "start", "", safeUrl] },
|
|
20902
|
+
{ cmd: "powershell.exe", args: ["-Command", `Start-Process '${safeUrl}'`] },
|
|
20903
|
+
{ cmd: "wslview", args: [safeUrl] }
|
|
20904
|
+
);
|
|
20905
|
+
} else {
|
|
20906
|
+
commands2.push(
|
|
20907
|
+
{ cmd: "xdg-open", args: [safeUrl] },
|
|
20908
|
+
{ cmd: "sensible-browser", args: [safeUrl] },
|
|
20909
|
+
{ cmd: "x-www-browser", args: [safeUrl] },
|
|
20910
|
+
{ cmd: "gnome-open", args: [safeUrl] },
|
|
20911
|
+
{ cmd: "firefox", args: [safeUrl] },
|
|
20912
|
+
{ cmd: "chromium-browser", args: [safeUrl] },
|
|
20913
|
+
{ cmd: "google-chrome", args: [safeUrl] }
|
|
20914
|
+
);
|
|
20915
|
+
}
|
|
20916
|
+
for (const { cmd, args } of commands2) {
|
|
20917
|
+
try {
|
|
20918
|
+
await execFileAsync2(cmd, args);
|
|
20919
|
+
return true;
|
|
20920
|
+
} catch {
|
|
20921
|
+
continue;
|
|
20922
|
+
}
|
|
20923
|
+
}
|
|
20924
|
+
return false;
|
|
20925
|
+
}
|
|
20926
|
+
function maskUrlForLogs(rawUrl) {
|
|
20927
|
+
try {
|
|
20928
|
+
const url = new URL(rawUrl);
|
|
20929
|
+
url.search = "";
|
|
20930
|
+
url.hash = "";
|
|
20931
|
+
return url.toString();
|
|
20932
|
+
} catch {
|
|
20933
|
+
return "[invalid-url]";
|
|
20934
|
+
}
|
|
20935
|
+
}
|
|
20936
|
+
function parseResourceMetadataUrl(wwwAuthenticateHeader) {
|
|
20937
|
+
if (!wwwAuthenticateHeader) return void 0;
|
|
20938
|
+
const match = wwwAuthenticateHeader.match(/resource_metadata="([^"]+)"/i);
|
|
20939
|
+
return match?.[1];
|
|
20940
|
+
}
|
|
20941
|
+
function createProtectedMetadataCandidates(resourceUrl, headerUrl) {
|
|
20942
|
+
const candidates = [];
|
|
20943
|
+
if (headerUrl) {
|
|
20944
|
+
candidates.push(headerUrl);
|
|
20945
|
+
}
|
|
20946
|
+
const resource = new URL(resourceUrl);
|
|
20947
|
+
const origin = `${resource.protocol}//${resource.host}`;
|
|
20948
|
+
const pathPart = resource.pathname.replace(/\/+$/, "");
|
|
20949
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource`);
|
|
20950
|
+
if (pathPart && pathPart !== "/") {
|
|
20951
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource${pathPart}`);
|
|
20952
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource/${pathPart.replace(/^\//, "")}`);
|
|
20953
|
+
}
|
|
20954
|
+
return Array.from(new Set(candidates));
|
|
20955
|
+
}
|
|
20956
|
+
async function fetchJson(url) {
|
|
20957
|
+
const res = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
|
|
20958
|
+
if (!res.ok) {
|
|
20959
|
+
throw new Error(`HTTP ${res.status} while fetching ${url}`);
|
|
20960
|
+
}
|
|
20961
|
+
return await res.json();
|
|
20962
|
+
}
|
|
20963
|
+
function buildAuthorizationMetadataCandidates(issuer) {
|
|
20964
|
+
const parsed = new URL(issuer);
|
|
20965
|
+
const base = `${parsed.protocol}//${parsed.host}`;
|
|
20966
|
+
const issuerPath = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
|
|
20967
|
+
const candidates = [
|
|
20968
|
+
`${base}/.well-known/oauth-authorization-server${issuerPath}`,
|
|
20969
|
+
`${base}/.well-known/oauth-authorization-server`,
|
|
20970
|
+
`${base}/.well-known/openid-configuration${issuerPath}`,
|
|
20971
|
+
`${base}/.well-known/openid-configuration`
|
|
20972
|
+
];
|
|
20973
|
+
return Array.from(new Set(candidates));
|
|
20974
|
+
}
|
|
20975
|
+
async function discoverProtectedResourceMetadata(resourceUrl, wwwAuthenticateHeader) {
|
|
20976
|
+
const headerUrl = parseResourceMetadataUrl(wwwAuthenticateHeader);
|
|
20977
|
+
const candidates = createProtectedMetadataCandidates(resourceUrl, headerUrl);
|
|
20978
|
+
for (const candidate of candidates) {
|
|
20979
|
+
try {
|
|
20980
|
+
const metadata = await fetchJson(candidate);
|
|
20981
|
+
if (Array.isArray(metadata.authorization_servers) && metadata.authorization_servers.length > 0) {
|
|
20982
|
+
return metadata;
|
|
20983
|
+
}
|
|
20984
|
+
} catch {
|
|
20985
|
+
}
|
|
20986
|
+
}
|
|
20987
|
+
throw new Error("Could not discover OAuth protected resource metadata for MCP server");
|
|
20988
|
+
}
|
|
20989
|
+
async function discoverAuthorizationServerMetadata(authorizationServer) {
|
|
20990
|
+
const candidates = buildAuthorizationMetadataCandidates(authorizationServer);
|
|
20991
|
+
for (const candidate of candidates) {
|
|
20992
|
+
try {
|
|
20993
|
+
const metadata = await fetchJson(candidate);
|
|
20994
|
+
if (metadata.authorization_endpoint && metadata.token_endpoint) {
|
|
20995
|
+
return metadata;
|
|
20996
|
+
}
|
|
20997
|
+
} catch {
|
|
20998
|
+
}
|
|
20999
|
+
}
|
|
21000
|
+
throw new Error("Could not discover OAuth authorization server metadata");
|
|
21001
|
+
}
|
|
21002
|
+
async function ensureClientId(authorizationMetadata, authorizationServer, redirectUri) {
|
|
21003
|
+
const store = await loadStore2();
|
|
21004
|
+
const clientKey = `${authorizationServer}|${redirectUri}`;
|
|
21005
|
+
const existing = store.clients[clientKey]?.clientId;
|
|
21006
|
+
if (existing) return existing;
|
|
21007
|
+
const registrationEndpoint = authorizationMetadata.registration_endpoint;
|
|
21008
|
+
if (!registrationEndpoint) {
|
|
21009
|
+
throw new Error(
|
|
21010
|
+
"Authorization server does not expose dynamic client registration; configure a static OAuth client ID for this MCP server."
|
|
21011
|
+
);
|
|
21012
|
+
}
|
|
21013
|
+
const registrationPayload = {
|
|
21014
|
+
client_name: "corbat-coco-mcp",
|
|
21015
|
+
redirect_uris: [redirectUri],
|
|
21016
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
21017
|
+
response_types: ["code"],
|
|
21018
|
+
token_endpoint_auth_method: "none"
|
|
21019
|
+
};
|
|
21020
|
+
const response = await fetch(registrationEndpoint, {
|
|
21021
|
+
method: "POST",
|
|
21022
|
+
headers: {
|
|
21023
|
+
"Content-Type": "application/json",
|
|
21024
|
+
Accept: "application/json"
|
|
21025
|
+
},
|
|
21026
|
+
body: JSON.stringify(registrationPayload)
|
|
21027
|
+
});
|
|
21028
|
+
if (!response.ok) {
|
|
21029
|
+
throw new Error(`Dynamic client registration failed: HTTP ${response.status}`);
|
|
21030
|
+
}
|
|
21031
|
+
const data = await response.json();
|
|
21032
|
+
const clientId = data.client_id;
|
|
21033
|
+
if (!clientId) {
|
|
21034
|
+
throw new Error("Dynamic client registration did not return client_id");
|
|
21035
|
+
}
|
|
21036
|
+
store.clients[clientKey] = { clientId };
|
|
21037
|
+
await saveStore2(store);
|
|
21038
|
+
return clientId;
|
|
21039
|
+
}
|
|
21040
|
+
async function refreshAccessToken2(params) {
|
|
21041
|
+
const body = new URLSearchParams({
|
|
21042
|
+
grant_type: "refresh_token",
|
|
21043
|
+
client_id: params.clientId,
|
|
21044
|
+
refresh_token: params.refreshToken,
|
|
21045
|
+
resource: params.resource
|
|
21046
|
+
});
|
|
21047
|
+
const response = await fetch(params.tokenEndpoint, {
|
|
21048
|
+
method: "POST",
|
|
21049
|
+
headers: {
|
|
21050
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
21051
|
+
Accept: "application/json"
|
|
21052
|
+
},
|
|
21053
|
+
body: body.toString()
|
|
21054
|
+
});
|
|
21055
|
+
if (!response.ok) {
|
|
21056
|
+
throw new Error(`Refresh token exchange failed: HTTP ${response.status}`);
|
|
21057
|
+
}
|
|
21058
|
+
const tokenResponse = await response.json();
|
|
21059
|
+
if (!tokenResponse.access_token) {
|
|
21060
|
+
throw new Error("Refresh token response missing access_token");
|
|
21061
|
+
}
|
|
21062
|
+
return tokenResponse;
|
|
21063
|
+
}
|
|
21064
|
+
async function exchangeCodeForToken(tokenEndpoint, clientId, code, codeVerifier, redirectUri, resource) {
|
|
21065
|
+
const body = new URLSearchParams({
|
|
21066
|
+
grant_type: "authorization_code",
|
|
21067
|
+
code,
|
|
21068
|
+
client_id: clientId,
|
|
21069
|
+
redirect_uri: redirectUri,
|
|
21070
|
+
code_verifier: codeVerifier,
|
|
21071
|
+
resource
|
|
21072
|
+
});
|
|
21073
|
+
const response = await fetch(tokenEndpoint, {
|
|
21074
|
+
method: "POST",
|
|
21075
|
+
headers: {
|
|
21076
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
21077
|
+
Accept: "application/json"
|
|
21078
|
+
},
|
|
21079
|
+
body: body.toString()
|
|
21080
|
+
});
|
|
21081
|
+
if (!response.ok) {
|
|
21082
|
+
throw new Error(`Token exchange failed: HTTP ${response.status}`);
|
|
21083
|
+
}
|
|
21084
|
+
const tokenResponse = await response.json();
|
|
21085
|
+
if (!tokenResponse.access_token) {
|
|
21086
|
+
throw new Error("Token exchange response missing access_token");
|
|
21087
|
+
}
|
|
21088
|
+
return tokenResponse;
|
|
21089
|
+
}
|
|
21090
|
+
async function persistToken(resourceUrl, token, metadata) {
|
|
21091
|
+
const store = await loadStore2();
|
|
21092
|
+
const expiresAt = typeof token.expires_in === "number" ? Date.now() + Math.max(0, token.expires_in) * 1e3 : void 0;
|
|
21093
|
+
store.tokens[getResourceKey(resourceUrl)] = {
|
|
21094
|
+
accessToken: token.access_token,
|
|
21095
|
+
tokenType: token.token_type,
|
|
21096
|
+
refreshToken: token.refresh_token,
|
|
21097
|
+
authorizationServer: metadata?.authorizationServer,
|
|
21098
|
+
clientId: metadata?.clientId,
|
|
21099
|
+
resource: canonicalizeResourceUrl(resourceUrl),
|
|
21100
|
+
...expiresAt ? { expiresAt } : {}
|
|
21101
|
+
};
|
|
21102
|
+
await saveStore2(store);
|
|
21103
|
+
}
|
|
21104
|
+
async function authenticateMcpOAuth(params) {
|
|
21105
|
+
const resource = canonicalizeResourceUrl(params.resourceUrl);
|
|
21106
|
+
const store = await loadStore2();
|
|
21107
|
+
const stored = store.tokens[getResourceKey(resource)];
|
|
21108
|
+
if (stored && !isTokenExpired2(stored)) {
|
|
21109
|
+
return stored.accessToken;
|
|
21110
|
+
}
|
|
21111
|
+
if (!process.stdout.isTTY) {
|
|
21112
|
+
throw new Error(
|
|
21113
|
+
`MCP server '${params.serverName}' requires interactive OAuth in a TTY session. Run Coco in a terminal, or use mcp-remote (e.g. npx -y mcp-remote@latest ${resource}) for IDE bridge workflows.`
|
|
21114
|
+
);
|
|
21115
|
+
}
|
|
21116
|
+
const protectedMetadata = await discoverProtectedResourceMetadata(
|
|
21117
|
+
resource,
|
|
21118
|
+
params.wwwAuthenticateHeader
|
|
21119
|
+
);
|
|
21120
|
+
const authorizationServer = protectedMetadata.authorization_servers?.[0];
|
|
21121
|
+
if (!authorizationServer) {
|
|
21122
|
+
throw new Error("Protected resource metadata does not include authorization_servers");
|
|
21123
|
+
}
|
|
21124
|
+
const authorizationMetadata = await discoverAuthorizationServerMetadata(authorizationServer);
|
|
21125
|
+
if (stored && isTokenExpired2(stored) && stored.refreshToken && stored.clientId) {
|
|
21126
|
+
try {
|
|
21127
|
+
const refreshed = await refreshAccessToken2({
|
|
21128
|
+
tokenEndpoint: authorizationMetadata.token_endpoint,
|
|
21129
|
+
clientId: stored.clientId,
|
|
21130
|
+
refreshToken: stored.refreshToken,
|
|
21131
|
+
resource
|
|
21132
|
+
});
|
|
21133
|
+
await persistToken(resource, refreshed, {
|
|
21134
|
+
authorizationServer,
|
|
21135
|
+
clientId: stored.clientId
|
|
21136
|
+
});
|
|
21137
|
+
return refreshed.access_token;
|
|
21138
|
+
} catch {
|
|
21139
|
+
}
|
|
21140
|
+
}
|
|
21141
|
+
const codeVerifier = createCodeVerifier();
|
|
21142
|
+
const codeChallenge = createCodeChallenge(codeVerifier);
|
|
21143
|
+
const state = createState();
|
|
21144
|
+
const { port, resultPromise } = await createCallbackServer(
|
|
21145
|
+
state,
|
|
21146
|
+
OAUTH_TIMEOUT_MS,
|
|
21147
|
+
OAUTH_CALLBACK_PORT
|
|
21148
|
+
);
|
|
21149
|
+
const redirectUri = `http://localhost:${port}/auth/callback`;
|
|
21150
|
+
const clientId = await ensureClientId(authorizationMetadata, authorizationServer, redirectUri);
|
|
21151
|
+
const authUrl = new URL(authorizationMetadata.authorization_endpoint);
|
|
21152
|
+
authUrl.searchParams.set("response_type", "code");
|
|
21153
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
21154
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
21155
|
+
authUrl.searchParams.set("state", state);
|
|
21156
|
+
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
21157
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
21158
|
+
authUrl.searchParams.set("resource", resource);
|
|
21159
|
+
if (authorizationMetadata.scopes_supported?.includes("offline_access")) {
|
|
21160
|
+
authUrl.searchParams.set("scope", "offline_access");
|
|
21161
|
+
}
|
|
21162
|
+
const opened = await openBrowser2(authUrl.toString());
|
|
21163
|
+
if (!opened) {
|
|
21164
|
+
logger.warn(`[MCP OAuth] Could not open browser automatically for '${params.serverName}'`);
|
|
21165
|
+
logger.warn(`[MCP OAuth] Manual auth URL base: ${maskUrlForLogs(authUrl.toString())}`);
|
|
21166
|
+
console.log(`[MCP OAuth] Open this URL manually: ${authUrl.toString()}`);
|
|
21167
|
+
} else {
|
|
21168
|
+
logger.info(
|
|
21169
|
+
`[MCP OAuth] Opened browser for '${params.serverName}'. Complete login to continue.`
|
|
21170
|
+
);
|
|
21171
|
+
}
|
|
21172
|
+
const callback = await resultPromise;
|
|
21173
|
+
const token = await exchangeCodeForToken(
|
|
21174
|
+
authorizationMetadata.token_endpoint,
|
|
21175
|
+
clientId,
|
|
21176
|
+
callback.code,
|
|
21177
|
+
codeVerifier,
|
|
21178
|
+
redirectUri,
|
|
21179
|
+
resource
|
|
21180
|
+
);
|
|
21181
|
+
await persistToken(resource, token, { authorizationServer, clientId });
|
|
21182
|
+
return token.access_token;
|
|
21183
|
+
}
|
|
21184
|
+
var execFileAsync2, TOKEN_STORE_PATH, OAUTH_TIMEOUT_MS, logger;
|
|
21185
|
+
var init_oauth2 = __esm({
|
|
21186
|
+
"src/mcp/oauth.ts"() {
|
|
21187
|
+
init_callback_server();
|
|
21188
|
+
init_paths();
|
|
21189
|
+
init_logger();
|
|
21190
|
+
execFileAsync2 = promisify(execFile);
|
|
21191
|
+
TOKEN_STORE_PATH = path38__default.join(CONFIG_PATHS.tokens, "mcp-oauth.json");
|
|
21192
|
+
OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
21193
|
+
logger = getLogger();
|
|
21194
|
+
}
|
|
21195
|
+
});
|
|
20825
21196
|
|
|
20826
21197
|
// src/mcp/transport/http.ts
|
|
20827
21198
|
var HTTPTransport;
|
|
20828
21199
|
var init_http = __esm({
|
|
20829
21200
|
"src/mcp/transport/http.ts"() {
|
|
20830
21201
|
init_errors2();
|
|
21202
|
+
init_oauth2();
|
|
20831
21203
|
init_errors2();
|
|
20832
21204
|
HTTPTransport = class {
|
|
20833
21205
|
constructor(config) {
|
|
@@ -20845,10 +21217,15 @@ var init_http = __esm({
|
|
|
20845
21217
|
connected = false;
|
|
20846
21218
|
abortController = null;
|
|
20847
21219
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
21220
|
+
oauthToken;
|
|
21221
|
+
oauthInFlight = null;
|
|
20848
21222
|
/**
|
|
20849
21223
|
* Get authentication token
|
|
20850
21224
|
*/
|
|
20851
21225
|
getAuthToken() {
|
|
21226
|
+
if (this.oauthToken) {
|
|
21227
|
+
return this.oauthToken;
|
|
21228
|
+
}
|
|
20852
21229
|
if (!this.config.auth) return void 0;
|
|
20853
21230
|
if (this.config.auth.token) {
|
|
20854
21231
|
return this.config.auth.token;
|
|
@@ -20867,22 +21244,64 @@ var init_http = __esm({
|
|
|
20867
21244
|
Accept: "application/json",
|
|
20868
21245
|
...this.config.headers
|
|
20869
21246
|
};
|
|
21247
|
+
if (this.oauthToken) {
|
|
21248
|
+
headers["Authorization"] = `Bearer ${this.oauthToken}`;
|
|
21249
|
+
return headers;
|
|
21250
|
+
}
|
|
20870
21251
|
const token = this.getAuthToken();
|
|
20871
21252
|
if (token && this.config.auth) {
|
|
20872
|
-
|
|
20873
|
-
|
|
20874
|
-
|
|
20875
|
-
|
|
20876
|
-
case "apikey":
|
|
20877
|
-
headers[this.config.auth.headerName || "X-API-Key"] = token;
|
|
20878
|
-
break;
|
|
20879
|
-
case "oauth":
|
|
20880
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
20881
|
-
break;
|
|
21253
|
+
if (this.config.auth.type === "apikey") {
|
|
21254
|
+
headers[this.config.auth.headerName || "X-API-Key"] = token;
|
|
21255
|
+
} else {
|
|
21256
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
20882
21257
|
}
|
|
20883
21258
|
}
|
|
20884
21259
|
return headers;
|
|
20885
21260
|
}
|
|
21261
|
+
shouldAttemptOAuth() {
|
|
21262
|
+
if (this.config.auth?.type === "apikey") {
|
|
21263
|
+
return false;
|
|
21264
|
+
}
|
|
21265
|
+
if (this.config.auth?.type === "bearer") {
|
|
21266
|
+
return !this.getAuthToken();
|
|
21267
|
+
}
|
|
21268
|
+
return true;
|
|
21269
|
+
}
|
|
21270
|
+
async ensureOAuthToken(wwwAuthenticateHeader) {
|
|
21271
|
+
if (this.oauthToken) {
|
|
21272
|
+
return this.oauthToken;
|
|
21273
|
+
}
|
|
21274
|
+
if (this.oauthInFlight) {
|
|
21275
|
+
return this.oauthInFlight;
|
|
21276
|
+
}
|
|
21277
|
+
const serverName = this.config.name ?? this.config.url;
|
|
21278
|
+
this.oauthInFlight = authenticateMcpOAuth({
|
|
21279
|
+
serverName,
|
|
21280
|
+
resourceUrl: this.config.url,
|
|
21281
|
+
wwwAuthenticateHeader
|
|
21282
|
+
}).then((token) => {
|
|
21283
|
+
this.oauthToken = token;
|
|
21284
|
+
return token;
|
|
21285
|
+
}).finally(() => {
|
|
21286
|
+
this.oauthInFlight = null;
|
|
21287
|
+
});
|
|
21288
|
+
return this.oauthInFlight;
|
|
21289
|
+
}
|
|
21290
|
+
async sendRequestWithOAuthRetry(method, body, signal) {
|
|
21291
|
+
const doFetch = async () => fetch(this.config.url, {
|
|
21292
|
+
method,
|
|
21293
|
+
headers: this.buildHeaders(),
|
|
21294
|
+
...body ? { body } : {},
|
|
21295
|
+
signal
|
|
21296
|
+
});
|
|
21297
|
+
let response = await doFetch();
|
|
21298
|
+
if (response.status !== 401 || !this.shouldAttemptOAuth()) {
|
|
21299
|
+
return response;
|
|
21300
|
+
}
|
|
21301
|
+
await this.ensureOAuthToken(response.headers.get("www-authenticate"));
|
|
21302
|
+
response = await doFetch();
|
|
21303
|
+
return response;
|
|
21304
|
+
}
|
|
20886
21305
|
/**
|
|
20887
21306
|
* Connect to the HTTP transport
|
|
20888
21307
|
*/
|
|
@@ -20897,11 +21316,14 @@ var init_http = __esm({
|
|
|
20897
21316
|
}
|
|
20898
21317
|
try {
|
|
20899
21318
|
this.abortController = new AbortController();
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
21319
|
+
if (this.shouldAttemptOAuth()) {
|
|
21320
|
+
this.oauthToken = await getStoredMcpOAuthToken(this.config.url);
|
|
21321
|
+
}
|
|
21322
|
+
const response = await this.sendRequestWithOAuthRetry(
|
|
21323
|
+
"GET",
|
|
21324
|
+
void 0,
|
|
21325
|
+
this.abortController.signal
|
|
21326
|
+
);
|
|
20905
21327
|
if (!response.ok && response.status !== 404) {
|
|
20906
21328
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
20907
21329
|
}
|
|
@@ -20933,12 +21355,11 @@ var init_http = __esm({
|
|
|
20933
21355
|
const timeoutId = setTimeout(() => {
|
|
20934
21356
|
abortController.abort();
|
|
20935
21357
|
}, this.config.timeout);
|
|
20936
|
-
const response = await
|
|
20937
|
-
|
|
20938
|
-
|
|
20939
|
-
|
|
20940
|
-
|
|
20941
|
-
});
|
|
21358
|
+
const response = await this.sendRequestWithOAuthRetry(
|
|
21359
|
+
"POST",
|
|
21360
|
+
JSON.stringify(message),
|
|
21361
|
+
abortController.signal
|
|
21362
|
+
);
|
|
20942
21363
|
clearTimeout(timeoutId);
|
|
20943
21364
|
if (!response.ok) {
|
|
20944
21365
|
throw new MCPTransportError(`HTTP error ${response.status}: ${response.statusText}`);
|
|
@@ -21314,6 +21735,7 @@ var init_lifecycle = __esm({
|
|
|
21314
21735
|
throw new MCPConnectionError(`Server '${config.name}' requires http.url`);
|
|
21315
21736
|
}
|
|
21316
21737
|
return new HTTPTransport({
|
|
21738
|
+
name: config.name,
|
|
21317
21739
|
url: config.http.url,
|
|
21318
21740
|
headers: config.http.headers,
|
|
21319
21741
|
auth: config.http.auth
|
|
@@ -21530,7 +21952,7 @@ function shouldFullPowerApprove(command) {
|
|
|
21530
21952
|
}
|
|
21531
21953
|
async function loadFullPowerRiskPreference() {
|
|
21532
21954
|
try {
|
|
21533
|
-
const content = await
|
|
21955
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
21534
21956
|
const config = JSON.parse(content);
|
|
21535
21957
|
if (typeof config.fullPowerRiskMode === "boolean") {
|
|
21536
21958
|
fullPowerRiskEnabled = config.fullPowerRiskMode;
|
|
@@ -21544,12 +21966,12 @@ async function saveFullPowerRiskPreference(enabled) {
|
|
|
21544
21966
|
try {
|
|
21545
21967
|
let config = {};
|
|
21546
21968
|
try {
|
|
21547
|
-
const content = await
|
|
21969
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
21548
21970
|
config = JSON.parse(content);
|
|
21549
21971
|
} catch {
|
|
21550
21972
|
}
|
|
21551
21973
|
config.fullPowerRiskMode = enabled;
|
|
21552
|
-
await
|
|
21974
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
21553
21975
|
} catch {
|
|
21554
21976
|
}
|
|
21555
21977
|
}
|
|
@@ -21601,7 +22023,7 @@ __export(allow_path_prompt_exports, {
|
|
|
21601
22023
|
promptAllowPath: () => promptAllowPath
|
|
21602
22024
|
});
|
|
21603
22025
|
async function promptAllowPath(dirPath) {
|
|
21604
|
-
const absolute =
|
|
22026
|
+
const absolute = path38__default.resolve(dirPath);
|
|
21605
22027
|
console.log();
|
|
21606
22028
|
console.log(chalk.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
21607
22029
|
console.log(chalk.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -21843,13 +22265,13 @@ __export(stack_detector_exports, {
|
|
|
21843
22265
|
detectProjectStack: () => detectProjectStack
|
|
21844
22266
|
});
|
|
21845
22267
|
async function detectStack2(cwd) {
|
|
21846
|
-
if (await fileExists3(
|
|
21847
|
-
if (await fileExists3(
|
|
21848
|
-
if (await fileExists3(
|
|
21849
|
-
if (await fileExists3(
|
|
21850
|
-
if (await fileExists3(
|
|
21851
|
-
if (await fileExists3(
|
|
21852
|
-
if (await fileExists3(
|
|
22268
|
+
if (await fileExists3(path38__default.join(cwd, "package.json"))) return "node";
|
|
22269
|
+
if (await fileExists3(path38__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
22270
|
+
if (await fileExists3(path38__default.join(cwd, "pyproject.toml"))) return "python";
|
|
22271
|
+
if (await fileExists3(path38__default.join(cwd, "go.mod"))) return "go";
|
|
22272
|
+
if (await fileExists3(path38__default.join(cwd, "pom.xml"))) return "java";
|
|
22273
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle"))) return "java";
|
|
22274
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
21853
22275
|
return "unknown";
|
|
21854
22276
|
}
|
|
21855
22277
|
async function detectPackageManager3(cwd, stack) {
|
|
@@ -21857,25 +22279,25 @@ async function detectPackageManager3(cwd, stack) {
|
|
|
21857
22279
|
if (stack === "python") return "pip";
|
|
21858
22280
|
if (stack === "go") return "go";
|
|
21859
22281
|
if (stack === "java") {
|
|
21860
|
-
if (await fileExists3(
|
|
22282
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle")) || await fileExists3(path38__default.join(cwd, "build.gradle.kts"))) {
|
|
21861
22283
|
return "gradle";
|
|
21862
22284
|
}
|
|
21863
|
-
if (await fileExists3(
|
|
22285
|
+
if (await fileExists3(path38__default.join(cwd, "pom.xml"))) {
|
|
21864
22286
|
return "maven";
|
|
21865
22287
|
}
|
|
21866
22288
|
}
|
|
21867
22289
|
if (stack === "node") {
|
|
21868
|
-
if (await fileExists3(
|
|
21869
|
-
if (await fileExists3(
|
|
21870
|
-
if (await fileExists3(
|
|
22290
|
+
if (await fileExists3(path38__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
22291
|
+
if (await fileExists3(path38__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
22292
|
+
if (await fileExists3(path38__default.join(cwd, "bun.lockb"))) return "bun";
|
|
21871
22293
|
return "npm";
|
|
21872
22294
|
}
|
|
21873
22295
|
return null;
|
|
21874
22296
|
}
|
|
21875
22297
|
async function parsePackageJson(cwd) {
|
|
21876
|
-
const packageJsonPath =
|
|
22298
|
+
const packageJsonPath = path38__default.join(cwd, "package.json");
|
|
21877
22299
|
try {
|
|
21878
|
-
const content = await
|
|
22300
|
+
const content = await fs35__default.readFile(packageJsonPath, "utf-8");
|
|
21879
22301
|
const pkg = JSON.parse(content);
|
|
21880
22302
|
const allDeps = {
|
|
21881
22303
|
...pkg.dependencies,
|
|
@@ -21905,7 +22327,7 @@ async function parsePackageJson(cwd) {
|
|
|
21905
22327
|
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
21906
22328
|
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
21907
22329
|
const languages = ["JavaScript"];
|
|
21908
|
-
if (allDeps.typescript || await fileExists3(
|
|
22330
|
+
if (allDeps.typescript || await fileExists3(path38__default.join(cwd, "tsconfig.json"))) {
|
|
21909
22331
|
languages.push("TypeScript");
|
|
21910
22332
|
}
|
|
21911
22333
|
return {
|
|
@@ -21926,9 +22348,9 @@ async function parsePackageJson(cwd) {
|
|
|
21926
22348
|
}
|
|
21927
22349
|
}
|
|
21928
22350
|
async function parsePomXml(cwd) {
|
|
21929
|
-
const pomPath =
|
|
22351
|
+
const pomPath = path38__default.join(cwd, "pom.xml");
|
|
21930
22352
|
try {
|
|
21931
|
-
const content = await
|
|
22353
|
+
const content = await fs35__default.readFile(pomPath, "utf-8");
|
|
21932
22354
|
const dependencies = {};
|
|
21933
22355
|
const frameworks = [];
|
|
21934
22356
|
const buildTools2 = ["maven"];
|
|
@@ -21963,9 +22385,9 @@ async function parsePomXml(cwd) {
|
|
|
21963
22385
|
}
|
|
21964
22386
|
}
|
|
21965
22387
|
async function parsePyprojectToml(cwd) {
|
|
21966
|
-
const pyprojectPath =
|
|
22388
|
+
const pyprojectPath = path38__default.join(cwd, "pyproject.toml");
|
|
21967
22389
|
try {
|
|
21968
|
-
const content = await
|
|
22390
|
+
const content = await fs35__default.readFile(pyprojectPath, "utf-8");
|
|
21969
22391
|
const dependencies = {};
|
|
21970
22392
|
const frameworks = [];
|
|
21971
22393
|
const buildTools2 = ["pip"];
|
|
@@ -22006,7 +22428,7 @@ async function detectProjectStack(cwd) {
|
|
|
22006
22428
|
testingFrameworks = parsed.testingFrameworks;
|
|
22007
22429
|
languages = parsed.languages;
|
|
22008
22430
|
} else if (stack === "java") {
|
|
22009
|
-
const isGradle = await fileExists3(
|
|
22431
|
+
const isGradle = await fileExists3(path38__default.join(cwd, "build.gradle")) || await fileExists3(path38__default.join(cwd, "build.gradle.kts"));
|
|
22010
22432
|
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
22011
22433
|
dependencies = parsed.dependencies;
|
|
22012
22434
|
frameworks = parsed.frameworks;
|
|
@@ -22407,7 +22829,7 @@ function loadStandardFormat(config, configPath) {
|
|
|
22407
22829
|
return validServers;
|
|
22408
22830
|
}
|
|
22409
22831
|
async function loadProjectMCPFile(projectPath) {
|
|
22410
|
-
const mcpJsonPath =
|
|
22832
|
+
const mcpJsonPath = path38__default.join(projectPath, ".mcp.json");
|
|
22411
22833
|
try {
|
|
22412
22834
|
await access(mcpJsonPath);
|
|
22413
22835
|
} catch {
|
|
@@ -23719,26 +24141,26 @@ init_version();
|
|
|
23719
24141
|
// src/orchestrator/project.ts
|
|
23720
24142
|
init_env();
|
|
23721
24143
|
async function createProjectStructure(projectPath, info) {
|
|
23722
|
-
const cocoPath =
|
|
24144
|
+
const cocoPath = path38__default.join(projectPath, ".coco");
|
|
23723
24145
|
const directories = [
|
|
23724
24146
|
cocoPath,
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
|
|
23730
|
-
|
|
23731
|
-
|
|
23732
|
-
|
|
23733
|
-
|
|
23734
|
-
|
|
23735
|
-
|
|
23736
|
-
|
|
23737
|
-
|
|
23738
|
-
|
|
24147
|
+
path38__default.join(cocoPath, "state"),
|
|
24148
|
+
path38__default.join(cocoPath, "checkpoints"),
|
|
24149
|
+
path38__default.join(cocoPath, "logs"),
|
|
24150
|
+
path38__default.join(cocoPath, "discovery"),
|
|
24151
|
+
path38__default.join(cocoPath, "spec"),
|
|
24152
|
+
path38__default.join(cocoPath, "architecture"),
|
|
24153
|
+
path38__default.join(cocoPath, "architecture", "adrs"),
|
|
24154
|
+
path38__default.join(cocoPath, "architecture", "diagrams"),
|
|
24155
|
+
path38__default.join(cocoPath, "planning"),
|
|
24156
|
+
path38__default.join(cocoPath, "planning", "epics"),
|
|
24157
|
+
path38__default.join(cocoPath, "execution"),
|
|
24158
|
+
path38__default.join(cocoPath, "versions"),
|
|
24159
|
+
path38__default.join(cocoPath, "reviews"),
|
|
24160
|
+
path38__default.join(cocoPath, "delivery")
|
|
23739
24161
|
];
|
|
23740
24162
|
for (const dir of directories) {
|
|
23741
|
-
await
|
|
24163
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
23742
24164
|
}
|
|
23743
24165
|
await createInitialConfig(cocoPath, info);
|
|
23744
24166
|
await createProjectState(cocoPath, info);
|
|
@@ -23773,7 +24195,7 @@ async function createInitialConfig(cocoPath, info) {
|
|
|
23773
24195
|
maxCheckpoints: 50
|
|
23774
24196
|
}
|
|
23775
24197
|
};
|
|
23776
|
-
await
|
|
24198
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
23777
24199
|
}
|
|
23778
24200
|
async function createProjectState(cocoPath, info) {
|
|
23779
24201
|
const state = {
|
|
@@ -23790,8 +24212,8 @@ async function createProjectState(cocoPath, info) {
|
|
|
23790
24212
|
qualityHistory: [],
|
|
23791
24213
|
lastCheckpoint: null
|
|
23792
24214
|
};
|
|
23793
|
-
await
|
|
23794
|
-
|
|
24215
|
+
await fs35__default.writeFile(
|
|
24216
|
+
path38__default.join(cocoPath, "state", "project.json"),
|
|
23795
24217
|
JSON.stringify(state, null, 2),
|
|
23796
24218
|
"utf-8"
|
|
23797
24219
|
);
|
|
@@ -23812,7 +24234,7 @@ checkpoints/
|
|
|
23812
24234
|
state/session.json
|
|
23813
24235
|
state/lock.json
|
|
23814
24236
|
`;
|
|
23815
|
-
await
|
|
24237
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, ".gitignore"), content, "utf-8");
|
|
23816
24238
|
}
|
|
23817
24239
|
async function createReadme(cocoPath, info) {
|
|
23818
24240
|
const content = `# Corbat-Coco Project: ${info.name}
|
|
@@ -23859,13 +24281,13 @@ Edit \`config.json\` to customize:
|
|
|
23859
24281
|
---
|
|
23860
24282
|
Generated by Corbat-Coco v0.1.0
|
|
23861
24283
|
`;
|
|
23862
|
-
await
|
|
24284
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, "README.md"), content, "utf-8");
|
|
23863
24285
|
}
|
|
23864
24286
|
|
|
23865
24287
|
// src/cli/commands/init.ts
|
|
23866
24288
|
function registerInitCommand(program2) {
|
|
23867
|
-
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 (
|
|
23868
|
-
await runInit(
|
|
24289
|
+
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 (path60, options) => {
|
|
24290
|
+
await runInit(path60, options);
|
|
23869
24291
|
});
|
|
23870
24292
|
}
|
|
23871
24293
|
async function runInit(projectPath, options) {
|
|
@@ -23944,18 +24366,18 @@ async function gatherProjectInfo() {
|
|
|
23944
24366
|
language
|
|
23945
24367
|
};
|
|
23946
24368
|
}
|
|
23947
|
-
function getDefaultProjectInfo(
|
|
23948
|
-
const name =
|
|
24369
|
+
function getDefaultProjectInfo(path60) {
|
|
24370
|
+
const name = path60 === "." ? "my-project" : path60.split("/").pop() || "my-project";
|
|
23949
24371
|
return {
|
|
23950
24372
|
name,
|
|
23951
24373
|
description: "",
|
|
23952
24374
|
language: "typescript"
|
|
23953
24375
|
};
|
|
23954
24376
|
}
|
|
23955
|
-
async function checkExistingProject(
|
|
24377
|
+
async function checkExistingProject(path60) {
|
|
23956
24378
|
try {
|
|
23957
|
-
const
|
|
23958
|
-
await
|
|
24379
|
+
const fs56 = await import('fs/promises');
|
|
24380
|
+
await fs56.access(`${path60}/.coco`);
|
|
23959
24381
|
return true;
|
|
23960
24382
|
} catch {
|
|
23961
24383
|
return false;
|
|
@@ -25163,13 +25585,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
25163
25585
|
// src/phases/converge/persistence.ts
|
|
25164
25586
|
init_errors();
|
|
25165
25587
|
function getPersistencePaths(projectPath) {
|
|
25166
|
-
const baseDir =
|
|
25588
|
+
const baseDir = path38__default.join(projectPath, ".coco", "spec");
|
|
25167
25589
|
return {
|
|
25168
25590
|
baseDir,
|
|
25169
|
-
sessionFile:
|
|
25170
|
-
specFile:
|
|
25171
|
-
conversationLog:
|
|
25172
|
-
checkpointFile:
|
|
25591
|
+
sessionFile: path38__default.join(baseDir, "discovery-session.json"),
|
|
25592
|
+
specFile: path38__default.join(baseDir, "spec.md"),
|
|
25593
|
+
conversationLog: path38__default.join(baseDir, "conversation.jsonl"),
|
|
25594
|
+
checkpointFile: path38__default.join(baseDir, "checkpoint.json")
|
|
25173
25595
|
};
|
|
25174
25596
|
}
|
|
25175
25597
|
var SessionPersistence = class {
|
|
@@ -25182,7 +25604,7 @@ var SessionPersistence = class {
|
|
|
25182
25604
|
*/
|
|
25183
25605
|
async ensureDir() {
|
|
25184
25606
|
try {
|
|
25185
|
-
await
|
|
25607
|
+
await fs35__default.mkdir(this.paths.baseDir, { recursive: true });
|
|
25186
25608
|
} catch {
|
|
25187
25609
|
throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
|
|
25188
25610
|
path: this.paths.baseDir,
|
|
@@ -25197,7 +25619,7 @@ var SessionPersistence = class {
|
|
|
25197
25619
|
await this.ensureDir();
|
|
25198
25620
|
try {
|
|
25199
25621
|
const data = JSON.stringify(session, null, 2);
|
|
25200
|
-
await
|
|
25622
|
+
await fs35__default.writeFile(this.paths.sessionFile, data, "utf-8");
|
|
25201
25623
|
} catch {
|
|
25202
25624
|
throw new FileSystemError("Failed to save discovery session", {
|
|
25203
25625
|
path: this.paths.sessionFile,
|
|
@@ -25210,7 +25632,7 @@ var SessionPersistence = class {
|
|
|
25210
25632
|
*/
|
|
25211
25633
|
async loadSession() {
|
|
25212
25634
|
try {
|
|
25213
|
-
const data = await
|
|
25635
|
+
const data = await fs35__default.readFile(this.paths.sessionFile, "utf-8");
|
|
25214
25636
|
const parsed = JSON.parse(data);
|
|
25215
25637
|
parsed.startedAt = new Date(parsed.startedAt);
|
|
25216
25638
|
parsed.updatedAt = new Date(parsed.updatedAt);
|
|
@@ -25236,7 +25658,7 @@ var SessionPersistence = class {
|
|
|
25236
25658
|
*/
|
|
25237
25659
|
async hasSession() {
|
|
25238
25660
|
try {
|
|
25239
|
-
await
|
|
25661
|
+
await fs35__default.access(this.paths.sessionFile);
|
|
25240
25662
|
return true;
|
|
25241
25663
|
} catch {
|
|
25242
25664
|
return false;
|
|
@@ -25247,7 +25669,7 @@ var SessionPersistence = class {
|
|
|
25247
25669
|
*/
|
|
25248
25670
|
async deleteSession() {
|
|
25249
25671
|
try {
|
|
25250
|
-
await
|
|
25672
|
+
await fs35__default.unlink(this.paths.sessionFile);
|
|
25251
25673
|
} catch (error) {
|
|
25252
25674
|
if (error.code !== "ENOENT") {
|
|
25253
25675
|
throw new FileSystemError("Failed to delete discovery session", {
|
|
@@ -25263,7 +25685,7 @@ var SessionPersistence = class {
|
|
|
25263
25685
|
async saveSpecification(content) {
|
|
25264
25686
|
await this.ensureDir();
|
|
25265
25687
|
try {
|
|
25266
|
-
await
|
|
25688
|
+
await fs35__default.writeFile(this.paths.specFile, content, "utf-8");
|
|
25267
25689
|
} catch {
|
|
25268
25690
|
throw new FileSystemError("Failed to save specification", {
|
|
25269
25691
|
path: this.paths.specFile,
|
|
@@ -25276,7 +25698,7 @@ var SessionPersistence = class {
|
|
|
25276
25698
|
*/
|
|
25277
25699
|
async loadSpecification() {
|
|
25278
25700
|
try {
|
|
25279
|
-
return await
|
|
25701
|
+
return await fs35__default.readFile(this.paths.specFile, "utf-8");
|
|
25280
25702
|
} catch {
|
|
25281
25703
|
return null;
|
|
25282
25704
|
}
|
|
@@ -25292,7 +25714,7 @@ var SessionPersistence = class {
|
|
|
25292
25714
|
content
|
|
25293
25715
|
};
|
|
25294
25716
|
try {
|
|
25295
|
-
await
|
|
25717
|
+
await fs35__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
|
|
25296
25718
|
} catch {
|
|
25297
25719
|
throw new FileSystemError("Failed to append to conversation log", {
|
|
25298
25720
|
path: this.paths.conversationLog,
|
|
@@ -25305,7 +25727,7 @@ var SessionPersistence = class {
|
|
|
25305
25727
|
*/
|
|
25306
25728
|
async loadConversationLog() {
|
|
25307
25729
|
try {
|
|
25308
|
-
const data = await
|
|
25730
|
+
const data = await fs35__default.readFile(this.paths.conversationLog, "utf-8");
|
|
25309
25731
|
const lines = data.trim().split("\n");
|
|
25310
25732
|
return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
25311
25733
|
} catch {
|
|
@@ -25319,7 +25741,7 @@ var SessionPersistence = class {
|
|
|
25319
25741
|
await this.ensureDir();
|
|
25320
25742
|
try {
|
|
25321
25743
|
const data = JSON.stringify(checkpoint, null, 2);
|
|
25322
|
-
await
|
|
25744
|
+
await fs35__default.writeFile(this.paths.checkpointFile, data, "utf-8");
|
|
25323
25745
|
} catch {
|
|
25324
25746
|
throw new FileSystemError("Failed to save checkpoint", {
|
|
25325
25747
|
path: this.paths.checkpointFile,
|
|
@@ -25332,7 +25754,7 @@ var SessionPersistence = class {
|
|
|
25332
25754
|
*/
|
|
25333
25755
|
async loadCheckpoint() {
|
|
25334
25756
|
try {
|
|
25335
|
-
const data = await
|
|
25757
|
+
const data = await fs35__default.readFile(this.paths.checkpointFile, "utf-8");
|
|
25336
25758
|
const parsed = JSON.parse(data);
|
|
25337
25759
|
parsed.timestamp = new Date(parsed.timestamp);
|
|
25338
25760
|
return parsed;
|
|
@@ -25345,7 +25767,7 @@ var SessionPersistence = class {
|
|
|
25345
25767
|
*/
|
|
25346
25768
|
async clearAll() {
|
|
25347
25769
|
try {
|
|
25348
|
-
await
|
|
25770
|
+
await fs35__default.rm(this.paths.baseDir, { recursive: true, force: true });
|
|
25349
25771
|
} catch (error) {
|
|
25350
25772
|
if (error.code !== "ENOENT") {
|
|
25351
25773
|
throw new FileSystemError("Failed to clear persistence data", {
|
|
@@ -27273,8 +27695,8 @@ var OrchestrateExecutor = class {
|
|
|
27273
27695
|
}
|
|
27274
27696
|
async loadSpecification(projectPath) {
|
|
27275
27697
|
try {
|
|
27276
|
-
const jsonPath =
|
|
27277
|
-
const jsonContent = await
|
|
27698
|
+
const jsonPath = path38__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
27699
|
+
const jsonContent = await fs35__default.readFile(jsonPath, "utf-8");
|
|
27278
27700
|
return JSON.parse(jsonContent);
|
|
27279
27701
|
} catch {
|
|
27280
27702
|
return this.createMinimalSpec(projectPath);
|
|
@@ -27285,7 +27707,7 @@ var OrchestrateExecutor = class {
|
|
|
27285
27707
|
version: "1.0.0",
|
|
27286
27708
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
27287
27709
|
overview: {
|
|
27288
|
-
name:
|
|
27710
|
+
name: path38__default.basename(projectPath),
|
|
27289
27711
|
description: "Project specification",
|
|
27290
27712
|
goals: [],
|
|
27291
27713
|
targetUsers: ["developers"],
|
|
@@ -27312,53 +27734,53 @@ var OrchestrateExecutor = class {
|
|
|
27312
27734
|
};
|
|
27313
27735
|
}
|
|
27314
27736
|
async saveArchitecture(projectPath, architecture) {
|
|
27315
|
-
const dir =
|
|
27316
|
-
await
|
|
27317
|
-
const mdPath =
|
|
27318
|
-
await
|
|
27319
|
-
const jsonPath =
|
|
27320
|
-
await
|
|
27737
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture");
|
|
27738
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27739
|
+
const mdPath = path38__default.join(dir, "ARCHITECTURE.md");
|
|
27740
|
+
await fs35__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
27741
|
+
const jsonPath = path38__default.join(dir, "architecture.json");
|
|
27742
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
27321
27743
|
return mdPath;
|
|
27322
27744
|
}
|
|
27323
27745
|
async saveADRs(projectPath, adrs) {
|
|
27324
|
-
const dir =
|
|
27325
|
-
await
|
|
27746
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
27747
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27326
27748
|
const paths = [];
|
|
27327
|
-
const indexPath =
|
|
27328
|
-
await
|
|
27749
|
+
const indexPath = path38__default.join(dir, "README.md");
|
|
27750
|
+
await fs35__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
27329
27751
|
paths.push(indexPath);
|
|
27330
27752
|
for (const adr of adrs) {
|
|
27331
27753
|
const filename = getADRFilename(adr);
|
|
27332
|
-
const adrPath =
|
|
27333
|
-
await
|
|
27754
|
+
const adrPath = path38__default.join(dir, filename);
|
|
27755
|
+
await fs35__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
27334
27756
|
paths.push(adrPath);
|
|
27335
27757
|
}
|
|
27336
27758
|
return paths;
|
|
27337
27759
|
}
|
|
27338
27760
|
async saveBacklog(projectPath, backlogResult) {
|
|
27339
|
-
const dir =
|
|
27340
|
-
await
|
|
27341
|
-
const mdPath =
|
|
27342
|
-
await
|
|
27343
|
-
const jsonPath =
|
|
27344
|
-
await
|
|
27761
|
+
const dir = path38__default.join(projectPath, ".coco", "planning");
|
|
27762
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27763
|
+
const mdPath = path38__default.join(dir, "BACKLOG.md");
|
|
27764
|
+
await fs35__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
27765
|
+
const jsonPath = path38__default.join(dir, "backlog.json");
|
|
27766
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
27345
27767
|
return mdPath;
|
|
27346
27768
|
}
|
|
27347
27769
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
27348
|
-
const dir =
|
|
27349
|
-
await
|
|
27770
|
+
const dir = path38__default.join(projectPath, ".coco", "planning", "sprints");
|
|
27771
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27350
27772
|
const filename = `${sprint.id}.md`;
|
|
27351
|
-
const sprintPath =
|
|
27352
|
-
await
|
|
27353
|
-
const jsonPath =
|
|
27354
|
-
await
|
|
27773
|
+
const sprintPath = path38__default.join(dir, filename);
|
|
27774
|
+
await fs35__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
27775
|
+
const jsonPath = path38__default.join(dir, `${sprint.id}.json`);
|
|
27776
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
27355
27777
|
return sprintPath;
|
|
27356
27778
|
}
|
|
27357
27779
|
async saveDiagram(projectPath, id, mermaid) {
|
|
27358
|
-
const dir =
|
|
27359
|
-
await
|
|
27360
|
-
const diagramPath =
|
|
27361
|
-
await
|
|
27780
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
27781
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27782
|
+
const diagramPath = path38__default.join(dir, `${id}.mmd`);
|
|
27783
|
+
await fs35__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
27362
27784
|
return diagramPath;
|
|
27363
27785
|
}
|
|
27364
27786
|
};
|
|
@@ -27456,20 +27878,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
27456
27878
|
},
|
|
27457
27879
|
tools: {
|
|
27458
27880
|
file: {
|
|
27459
|
-
async read(
|
|
27460
|
-
const
|
|
27461
|
-
return
|
|
27881
|
+
async read(path60) {
|
|
27882
|
+
const fs56 = await import('fs/promises');
|
|
27883
|
+
return fs56.readFile(path60, "utf-8");
|
|
27462
27884
|
},
|
|
27463
|
-
async write(
|
|
27464
|
-
const
|
|
27885
|
+
async write(path60, content) {
|
|
27886
|
+
const fs56 = await import('fs/promises');
|
|
27465
27887
|
const nodePath = await import('path');
|
|
27466
|
-
await
|
|
27467
|
-
await
|
|
27888
|
+
await fs56.mkdir(nodePath.dirname(path60), { recursive: true });
|
|
27889
|
+
await fs56.writeFile(path60, content, "utf-8");
|
|
27468
27890
|
},
|
|
27469
|
-
async exists(
|
|
27470
|
-
const
|
|
27891
|
+
async exists(path60) {
|
|
27892
|
+
const fs56 = await import('fs/promises');
|
|
27471
27893
|
try {
|
|
27472
|
-
await
|
|
27894
|
+
await fs56.access(path60);
|
|
27473
27895
|
return true;
|
|
27474
27896
|
} catch {
|
|
27475
27897
|
return false;
|
|
@@ -27708,16 +28130,16 @@ async function loadTasks(_options) {
|
|
|
27708
28130
|
];
|
|
27709
28131
|
}
|
|
27710
28132
|
async function checkProjectState() {
|
|
27711
|
-
const
|
|
28133
|
+
const fs56 = await import('fs/promises');
|
|
27712
28134
|
let hasProject = false;
|
|
27713
28135
|
let hasPlan = false;
|
|
27714
28136
|
try {
|
|
27715
|
-
await
|
|
28137
|
+
await fs56.access(".coco");
|
|
27716
28138
|
hasProject = true;
|
|
27717
28139
|
} catch {
|
|
27718
28140
|
}
|
|
27719
28141
|
try {
|
|
27720
|
-
await
|
|
28142
|
+
await fs56.access(".coco/planning/backlog.json");
|
|
27721
28143
|
hasPlan = true;
|
|
27722
28144
|
} catch {
|
|
27723
28145
|
}
|
|
@@ -27824,24 +28246,24 @@ function getPhaseStatusForPhase(phase) {
|
|
|
27824
28246
|
return "in_progress";
|
|
27825
28247
|
}
|
|
27826
28248
|
async function loadProjectState(cwd, config) {
|
|
27827
|
-
const
|
|
27828
|
-
const
|
|
27829
|
-
const statePath =
|
|
27830
|
-
const backlogPath =
|
|
27831
|
-
const checkpointDir =
|
|
28249
|
+
const fs56 = await import('fs/promises');
|
|
28250
|
+
const path60 = await import('path');
|
|
28251
|
+
const statePath = path60.join(cwd, ".coco", "state.json");
|
|
28252
|
+
const backlogPath = path60.join(cwd, ".coco", "planning", "backlog.json");
|
|
28253
|
+
const checkpointDir = path60.join(cwd, ".coco", "checkpoints");
|
|
27832
28254
|
let currentPhase = "idle";
|
|
27833
28255
|
let metrics;
|
|
27834
28256
|
let sprint;
|
|
27835
28257
|
let checkpoints = [];
|
|
27836
28258
|
try {
|
|
27837
|
-
const stateContent = await
|
|
28259
|
+
const stateContent = await fs56.readFile(statePath, "utf-8");
|
|
27838
28260
|
const stateData = JSON.parse(stateContent);
|
|
27839
28261
|
currentPhase = stateData.currentPhase || "idle";
|
|
27840
28262
|
metrics = stateData.metrics;
|
|
27841
28263
|
} catch {
|
|
27842
28264
|
}
|
|
27843
28265
|
try {
|
|
27844
|
-
const backlogContent = await
|
|
28266
|
+
const backlogContent = await fs56.readFile(backlogPath, "utf-8");
|
|
27845
28267
|
const backlogData = JSON.parse(backlogContent);
|
|
27846
28268
|
if (backlogData.currentSprint) {
|
|
27847
28269
|
const tasks = backlogData.tasks || [];
|
|
@@ -27863,7 +28285,7 @@ async function loadProjectState(cwd, config) {
|
|
|
27863
28285
|
} catch {
|
|
27864
28286
|
}
|
|
27865
28287
|
try {
|
|
27866
|
-
const files = await
|
|
28288
|
+
const files = await fs56.readdir(checkpointDir);
|
|
27867
28289
|
checkpoints = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
27868
28290
|
} catch {
|
|
27869
28291
|
}
|
|
@@ -27999,8 +28421,8 @@ async function restoreFromCheckpoint(_checkpoint) {
|
|
|
27999
28421
|
}
|
|
28000
28422
|
async function checkProjectExists() {
|
|
28001
28423
|
try {
|
|
28002
|
-
const
|
|
28003
|
-
await
|
|
28424
|
+
const fs56 = await import('fs/promises');
|
|
28425
|
+
await fs56.access(".coco");
|
|
28004
28426
|
return true;
|
|
28005
28427
|
} catch {
|
|
28006
28428
|
return false;
|
|
@@ -29215,9 +29637,9 @@ var DEFAULT_CONFIG2 = {
|
|
|
29215
29637
|
}
|
|
29216
29638
|
};
|
|
29217
29639
|
async function loadConfig2() {
|
|
29218
|
-
const
|
|
29640
|
+
const fs56 = await import('fs/promises');
|
|
29219
29641
|
try {
|
|
29220
|
-
const raw = await
|
|
29642
|
+
const raw = await fs56.readFile(CONFIG_PATH, "utf-8");
|
|
29221
29643
|
const parsed = JSON.parse(raw);
|
|
29222
29644
|
return { ...DEFAULT_CONFIG2, ...parsed };
|
|
29223
29645
|
} catch {
|
|
@@ -29225,13 +29647,13 @@ async function loadConfig2() {
|
|
|
29225
29647
|
}
|
|
29226
29648
|
}
|
|
29227
29649
|
async function saveConfig2(config) {
|
|
29228
|
-
const
|
|
29650
|
+
const fs56 = await import('fs/promises');
|
|
29229
29651
|
const dir = join(CONFIG_PATH, "..");
|
|
29230
|
-
await
|
|
29231
|
-
await
|
|
29652
|
+
await fs56.mkdir(dir, { recursive: true });
|
|
29653
|
+
await fs56.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
29232
29654
|
}
|
|
29233
|
-
function getNestedValue(obj,
|
|
29234
|
-
const keys =
|
|
29655
|
+
function getNestedValue(obj, path60) {
|
|
29656
|
+
const keys = path60.split(".");
|
|
29235
29657
|
let current = obj;
|
|
29236
29658
|
for (const key of keys) {
|
|
29237
29659
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -29241,8 +29663,8 @@ function getNestedValue(obj, path59) {
|
|
|
29241
29663
|
}
|
|
29242
29664
|
return current;
|
|
29243
29665
|
}
|
|
29244
|
-
function setNestedValue(obj,
|
|
29245
|
-
const keys =
|
|
29666
|
+
function setNestedValue(obj, path60, value) {
|
|
29667
|
+
const keys = path60.split(".");
|
|
29246
29668
|
let current = obj;
|
|
29247
29669
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
29248
29670
|
const key = keys[i];
|
|
@@ -29608,13 +30030,13 @@ async function runAdd(source, options) {
|
|
|
29608
30030
|
const isGithubShorthand = source.includes("/") && !isGitUrl;
|
|
29609
30031
|
const isLocalPath = source.startsWith(".") || source.startsWith("/");
|
|
29610
30032
|
if (isLocalPath) {
|
|
29611
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29612
|
-
const sourcePath =
|
|
29613
|
-
const skillName =
|
|
29614
|
-
const destPath =
|
|
30033
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30034
|
+
const sourcePath = path38__default.resolve(source);
|
|
30035
|
+
const skillName = path38__default.basename(sourcePath);
|
|
30036
|
+
const destPath = path38__default.join(targetDir, skillName);
|
|
29615
30037
|
try {
|
|
29616
|
-
await
|
|
29617
|
-
await
|
|
30038
|
+
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
30039
|
+
await fs35__default.cp(sourcePath, destPath, { recursive: true });
|
|
29618
30040
|
p26.log.success(`Installed "${skillName}" to ${destPath}`);
|
|
29619
30041
|
} catch (error) {
|
|
29620
30042
|
p26.log.error(
|
|
@@ -29645,10 +30067,10 @@ async function runAdd(source, options) {
|
|
|
29645
30067
|
p26.log.info("Try installing manually: git clone the repo into .agents/skills/");
|
|
29646
30068
|
}
|
|
29647
30069
|
} else if (isGitUrl) {
|
|
29648
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29649
|
-
await
|
|
30070
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30071
|
+
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
29650
30072
|
const skillName = source.split("/").pop()?.replace(".git", "") ?? "skill";
|
|
29651
|
-
const skillDir =
|
|
30073
|
+
const skillDir = path38__default.join(targetDir, skillName);
|
|
29652
30074
|
const spinner18 = p26.spinner();
|
|
29653
30075
|
spinner18.start(`Cloning ${source}...`);
|
|
29654
30076
|
try {
|
|
@@ -29674,15 +30096,15 @@ async function runAdd(source, options) {
|
|
|
29674
30096
|
}
|
|
29675
30097
|
async function runRemove(name, options) {
|
|
29676
30098
|
p26.intro(chalk.magenta("Remove Skill"));
|
|
29677
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29678
|
-
const skillPath =
|
|
29679
|
-
if (!skillPath.startsWith(
|
|
30099
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30100
|
+
const skillPath = path38__default.resolve(targetDir, name);
|
|
30101
|
+
if (!skillPath.startsWith(path38__default.resolve(targetDir) + path38__default.sep)) {
|
|
29680
30102
|
p26.log.error(`Invalid skill name: "${name}"`);
|
|
29681
30103
|
p26.outro("");
|
|
29682
30104
|
return;
|
|
29683
30105
|
}
|
|
29684
30106
|
try {
|
|
29685
|
-
await
|
|
30107
|
+
await fs35__default.access(skillPath);
|
|
29686
30108
|
} catch {
|
|
29687
30109
|
p26.log.error(`Skill "${name}" not found at ${skillPath}`);
|
|
29688
30110
|
p26.outro("");
|
|
@@ -29698,7 +30120,7 @@ async function runRemove(name, options) {
|
|
|
29698
30120
|
return;
|
|
29699
30121
|
}
|
|
29700
30122
|
}
|
|
29701
|
-
await
|
|
30123
|
+
await fs35__default.rm(skillPath, { recursive: true });
|
|
29702
30124
|
p26.log.success(`Removed "${name}"`);
|
|
29703
30125
|
p26.outro("");
|
|
29704
30126
|
}
|
|
@@ -29760,10 +30182,10 @@ async function runInfo(name) {
|
|
|
29760
30182
|
}
|
|
29761
30183
|
async function runCreate(name, options) {
|
|
29762
30184
|
p26.intro(chalk.magenta("Create Skill"));
|
|
29763
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29764
|
-
const skillDir =
|
|
30185
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30186
|
+
const skillDir = path38__default.join(targetDir, name);
|
|
29765
30187
|
try {
|
|
29766
|
-
await
|
|
30188
|
+
await fs35__default.access(skillDir);
|
|
29767
30189
|
p26.log.error(`Skill "${name}" already exists at ${skillDir}`);
|
|
29768
30190
|
p26.outro("");
|
|
29769
30191
|
return;
|
|
@@ -29792,7 +30214,7 @@ async function runCreate(name, options) {
|
|
|
29792
30214
|
p26.outro("Cancelled.");
|
|
29793
30215
|
return;
|
|
29794
30216
|
}
|
|
29795
|
-
await
|
|
30217
|
+
await fs35__default.mkdir(skillDir, { recursive: true });
|
|
29796
30218
|
const skillMd = `---
|
|
29797
30219
|
name: "${name}"
|
|
29798
30220
|
description: "${description}"
|
|
@@ -29814,10 +30236,10 @@ when this skill is activated (automatically via matching or manually via /${name
|
|
|
29814
30236
|
2. Include examples when helpful
|
|
29815
30237
|
3. Keep instructions under 500 lines
|
|
29816
30238
|
`;
|
|
29817
|
-
await
|
|
29818
|
-
await
|
|
30239
|
+
await fs35__default.writeFile(path38__default.join(skillDir, "SKILL.md"), skillMd, "utf-8");
|
|
30240
|
+
await fs35__default.mkdir(path38__default.join(skillDir, "references"), { recursive: true });
|
|
29819
30241
|
p26.log.success(`Created skill at ${skillDir}`);
|
|
29820
|
-
p26.log.info(`Edit ${
|
|
30242
|
+
p26.log.info(`Edit ${path38__default.join(skillDir, "SKILL.md")} to add instructions.`);
|
|
29821
30243
|
p26.outro("");
|
|
29822
30244
|
}
|
|
29823
30245
|
function registerWinner(winners, candidate, candidateScanOrder, scanOrderById) {
|
|
@@ -30273,10 +30695,10 @@ function registerCheckCommand(program2) {
|
|
|
30273
30695
|
|
|
30274
30696
|
// src/swarm/spec-parser.ts
|
|
30275
30697
|
async function parseSwarmSpec(filePath) {
|
|
30276
|
-
const
|
|
30277
|
-
const
|
|
30278
|
-
const rawContent = await
|
|
30279
|
-
const ext =
|
|
30698
|
+
const fs56 = await import('fs/promises');
|
|
30699
|
+
const path60 = await import('path');
|
|
30700
|
+
const rawContent = await fs56.readFile(filePath, "utf-8");
|
|
30701
|
+
const ext = path60.extname(filePath).toLowerCase();
|
|
30280
30702
|
if (ext === ".yaml" || ext === ".yml") {
|
|
30281
30703
|
return parseYamlSpec(rawContent);
|
|
30282
30704
|
}
|
|
@@ -30605,11 +31027,11 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
30605
31027
|
integrator: { maxTurns: 20, temperature: 0.2 }
|
|
30606
31028
|
};
|
|
30607
31029
|
async function loadAgentConfig(projectPath) {
|
|
30608
|
-
const
|
|
30609
|
-
const
|
|
30610
|
-
const configPath =
|
|
31030
|
+
const fs56 = await import('fs/promises');
|
|
31031
|
+
const path60 = await import('path');
|
|
31032
|
+
const configPath = path60.join(projectPath, ".coco", "swarm", "agents.json");
|
|
30611
31033
|
try {
|
|
30612
|
-
const raw = await
|
|
31034
|
+
const raw = await fs56.readFile(configPath, "utf-8");
|
|
30613
31035
|
const parsed = JSON.parse(raw);
|
|
30614
31036
|
const merged = { ...DEFAULT_AGENT_CONFIG };
|
|
30615
31037
|
for (const role of Object.keys(DEFAULT_AGENT_CONFIG)) {
|
|
@@ -30797,19 +31219,19 @@ async function createBoard(projectPath, spec) {
|
|
|
30797
31219
|
return board;
|
|
30798
31220
|
}
|
|
30799
31221
|
async function loadBoard(projectPath) {
|
|
30800
|
-
const
|
|
30801
|
-
const
|
|
30802
|
-
const boardPath =
|
|
30803
|
-
const raw = await
|
|
31222
|
+
const fs56 = await import('fs/promises');
|
|
31223
|
+
const path60 = await import('path');
|
|
31224
|
+
const boardPath = path60.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
31225
|
+
const raw = await fs56.readFile(boardPath, "utf-8");
|
|
30804
31226
|
return JSON.parse(raw);
|
|
30805
31227
|
}
|
|
30806
31228
|
async function saveBoard(projectPath, board) {
|
|
30807
|
-
const
|
|
30808
|
-
const
|
|
30809
|
-
const boardDir =
|
|
30810
|
-
const boardPath =
|
|
30811
|
-
await
|
|
30812
|
-
await
|
|
31229
|
+
const fs56 = await import('fs/promises');
|
|
31230
|
+
const path60 = await import('path');
|
|
31231
|
+
const boardDir = path60.join(projectPath, ".coco", "swarm");
|
|
31232
|
+
const boardPath = path60.join(boardDir, "task-board.json");
|
|
31233
|
+
await fs56.mkdir(boardDir, { recursive: true });
|
|
31234
|
+
await fs56.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
30813
31235
|
}
|
|
30814
31236
|
function markTaskInProgress(board, taskId, role) {
|
|
30815
31237
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -30974,11 +31396,11 @@ async function defaultPromptHandler(q) {
|
|
|
30974
31396
|
}
|
|
30975
31397
|
}
|
|
30976
31398
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
30977
|
-
const
|
|
30978
|
-
const
|
|
30979
|
-
const swarmDir =
|
|
30980
|
-
const assumptionsPath =
|
|
30981
|
-
await
|
|
31399
|
+
const fs56 = await import('fs/promises');
|
|
31400
|
+
const path60 = await import('path');
|
|
31401
|
+
const swarmDir = path60.join(projectPath, ".coco", "swarm");
|
|
31402
|
+
const assumptionsPath = path60.join(swarmDir, "assumptions.md");
|
|
31403
|
+
await fs56.mkdir(swarmDir, { recursive: true });
|
|
30982
31404
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
30983
31405
|
const content = [
|
|
30984
31406
|
`# Swarm Assumptions \u2014 ${projectName}`,
|
|
@@ -30994,18 +31416,18 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
30994
31416
|
assumptions.length > 0 ? assumptions.join("\n\n") : `_(none)_`,
|
|
30995
31417
|
``
|
|
30996
31418
|
].join("\n");
|
|
30997
|
-
await
|
|
31419
|
+
await fs56.writeFile(assumptionsPath, content, "utf-8");
|
|
30998
31420
|
return assumptionsPath;
|
|
30999
31421
|
}
|
|
31000
31422
|
|
|
31001
31423
|
// src/swarm/events.ts
|
|
31002
31424
|
async function appendSwarmEvent(projectPath, event) {
|
|
31003
|
-
const
|
|
31004
|
-
const
|
|
31005
|
-
const eventsDir =
|
|
31006
|
-
const eventsFile =
|
|
31007
|
-
await
|
|
31008
|
-
await
|
|
31425
|
+
const fs56 = await import('fs/promises');
|
|
31426
|
+
const path60 = await import('path');
|
|
31427
|
+
const eventsDir = path60.join(projectPath, ".coco", "swarm");
|
|
31428
|
+
const eventsFile = path60.join(eventsDir, "events.jsonl");
|
|
31429
|
+
await fs56.mkdir(eventsDir, { recursive: true });
|
|
31430
|
+
await fs56.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
31009
31431
|
}
|
|
31010
31432
|
function createEventId() {
|
|
31011
31433
|
return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -31013,12 +31435,12 @@ function createEventId() {
|
|
|
31013
31435
|
|
|
31014
31436
|
// src/swarm/knowledge.ts
|
|
31015
31437
|
async function appendKnowledge(projectPath, entry) {
|
|
31016
|
-
const
|
|
31017
|
-
const
|
|
31018
|
-
const knowledgeDir =
|
|
31019
|
-
const knowledgeFile =
|
|
31020
|
-
await
|
|
31021
|
-
await
|
|
31438
|
+
const fs56 = await import('fs/promises');
|
|
31439
|
+
const path60 = await import('path');
|
|
31440
|
+
const knowledgeDir = path60.join(projectPath, ".coco", "swarm");
|
|
31441
|
+
const knowledgeFile = path60.join(knowledgeDir, "knowledge.jsonl");
|
|
31442
|
+
await fs56.mkdir(knowledgeDir, { recursive: true });
|
|
31443
|
+
await fs56.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
31022
31444
|
}
|
|
31023
31445
|
|
|
31024
31446
|
// src/swarm/agents/prompts.ts
|
|
@@ -31322,11 +31744,11 @@ async function runSwarmLifecycle(options) {
|
|
|
31322
31744
|
}
|
|
31323
31745
|
async function stageInit(ctx) {
|
|
31324
31746
|
const { projectPath, spec } = ctx.options;
|
|
31325
|
-
const
|
|
31326
|
-
const
|
|
31327
|
-
await
|
|
31328
|
-
await
|
|
31329
|
-
const specSummaryPath =
|
|
31747
|
+
const fs56 = await import('fs/promises');
|
|
31748
|
+
const path60 = await import('path');
|
|
31749
|
+
await fs56.mkdir(path60.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
31750
|
+
await fs56.mkdir(ctx.options.outputPath, { recursive: true });
|
|
31751
|
+
const specSummaryPath = path60.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
31330
31752
|
const specSummary = {
|
|
31331
31753
|
projectName: spec.projectName,
|
|
31332
31754
|
description: spec.description,
|
|
@@ -31340,7 +31762,7 @@ async function stageInit(ctx) {
|
|
|
31340
31762
|
})),
|
|
31341
31763
|
qualityConfig: spec.qualityConfig
|
|
31342
31764
|
};
|
|
31343
|
-
await
|
|
31765
|
+
await fs56.writeFile(specSummaryPath, JSON.stringify(specSummary, null, 2), "utf-8");
|
|
31344
31766
|
await emitEvent(projectPath, {
|
|
31345
31767
|
agentRole: "pm",
|
|
31346
31768
|
agentTurn: 0,
|
|
@@ -31397,10 +31819,10 @@ async function stagePlan(ctx) {
|
|
|
31397
31819
|
})
|
|
31398
31820
|
]);
|
|
31399
31821
|
await createBoard(projectPath, spec);
|
|
31400
|
-
const
|
|
31401
|
-
const
|
|
31402
|
-
const planPath =
|
|
31403
|
-
await
|
|
31822
|
+
const fs56 = await import('fs/promises');
|
|
31823
|
+
const path60 = await import('path');
|
|
31824
|
+
const planPath = path60.join(projectPath, ".coco", "swarm", "plan.json");
|
|
31825
|
+
await fs56.writeFile(
|
|
31404
31826
|
planPath,
|
|
31405
31827
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
31406
31828
|
"utf-8"
|
|
@@ -31615,8 +32037,8 @@ async function stageIntegrate(ctx) {
|
|
|
31615
32037
|
}
|
|
31616
32038
|
async function stageOutput(ctx) {
|
|
31617
32039
|
const { projectPath, outputPath } = ctx.options;
|
|
31618
|
-
const
|
|
31619
|
-
const
|
|
32040
|
+
const fs56 = await import('fs/promises');
|
|
32041
|
+
const path60 = await import('path');
|
|
31620
32042
|
const board = await loadBoard(projectPath);
|
|
31621
32043
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
31622
32044
|
const summary = {
|
|
@@ -31630,9 +32052,9 @@ async function stageOutput(ctx) {
|
|
|
31630
32052
|
},
|
|
31631
32053
|
globalScore: computeGlobalScore(featureResults)
|
|
31632
32054
|
};
|
|
31633
|
-
await
|
|
31634
|
-
const summaryPath =
|
|
31635
|
-
await
|
|
32055
|
+
await fs56.mkdir(outputPath, { recursive: true });
|
|
32056
|
+
const summaryPath = path60.join(outputPath, "swarm-summary.json");
|
|
32057
|
+
await fs56.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
31636
32058
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
31637
32059
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
31638
32060
|
await emitEvent(projectPath, {
|
|
@@ -31978,8 +32400,8 @@ var SwarmOrchestrator = class {
|
|
|
31978
32400
|
noQuestions = false,
|
|
31979
32401
|
onProgress
|
|
31980
32402
|
} = options;
|
|
31981
|
-
const
|
|
31982
|
-
const projectPath =
|
|
32403
|
+
const path60 = await import('path');
|
|
32404
|
+
const projectPath = path60.dirname(path60.resolve(specFile));
|
|
31983
32405
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
31984
32406
|
const spec = await parseSwarmSpec(specFile);
|
|
31985
32407
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -31990,7 +32412,7 @@ var SwarmOrchestrator = class {
|
|
|
31990
32412
|
await runSwarmLifecycle({
|
|
31991
32413
|
spec,
|
|
31992
32414
|
projectPath,
|
|
31993
|
-
outputPath:
|
|
32415
|
+
outputPath: path60.resolve(outputPath),
|
|
31994
32416
|
provider,
|
|
31995
32417
|
agentConfig,
|
|
31996
32418
|
minScore,
|
|
@@ -32828,8 +33250,8 @@ async function setupGcloudADC(provider) {
|
|
|
32828
33250
|
console.log(chalk.dim(" (Complete the sign-in in your browser, then return here)"));
|
|
32829
33251
|
console.log();
|
|
32830
33252
|
const { exec: exec3 } = await import('child_process');
|
|
32831
|
-
const { promisify:
|
|
32832
|
-
const execAsync3 =
|
|
33253
|
+
const { promisify: promisify6 } = await import('util');
|
|
33254
|
+
const execAsync3 = promisify6(exec3);
|
|
32833
33255
|
try {
|
|
32834
33256
|
await execAsync3("gcloud auth application-default login", {
|
|
32835
33257
|
timeout: 12e4
|
|
@@ -33514,15 +33936,15 @@ async function saveConfiguration(result) {
|
|
|
33514
33936
|
}
|
|
33515
33937
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
33516
33938
|
if (createDir) {
|
|
33517
|
-
const dir =
|
|
33939
|
+
const dir = path38.dirname(filePath);
|
|
33518
33940
|
try {
|
|
33519
|
-
await
|
|
33941
|
+
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
33520
33942
|
} catch {
|
|
33521
33943
|
}
|
|
33522
33944
|
}
|
|
33523
33945
|
let existingVars = {};
|
|
33524
33946
|
try {
|
|
33525
|
-
const content = await
|
|
33947
|
+
const content = await fs35.readFile(filePath, "utf-8");
|
|
33526
33948
|
for (const line of content.split("\n")) {
|
|
33527
33949
|
const trimmed = line.trim();
|
|
33528
33950
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -33545,7 +33967,7 @@ async function saveEnvVars(filePath, vars, createDir = false) {
|
|
|
33545
33967
|
for (const [key, value] of Object.entries(allVars)) {
|
|
33546
33968
|
lines.push(`${key}=${value}`);
|
|
33547
33969
|
}
|
|
33548
|
-
await
|
|
33970
|
+
await fs35.writeFile(filePath, lines.join("\n") + "\n", { mode: 384 });
|
|
33549
33971
|
}
|
|
33550
33972
|
async function handleLocalProviderUnavailable(providerType, config) {
|
|
33551
33973
|
const cfg = LOCAL_PROVIDER_CONFIG[providerType];
|
|
@@ -33635,6 +34057,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33635
34057
|
const preferredHasCopilotCreds = preferredProviderDef?.id === "copilot" && isProviderConfigured();
|
|
33636
34058
|
const preferredIsConfigured = preferredIsLocal || preferredHasApiKey || preferredHasOpenAIOAuth || preferredHasCopilotCreds;
|
|
33637
34059
|
let preferredWasConfiguredButUnavailable = false;
|
|
34060
|
+
let preferredUnavailableWasLocal = false;
|
|
33638
34061
|
if (preferredProviderDef && preferredIsConfigured) {
|
|
33639
34062
|
try {
|
|
33640
34063
|
const preferredInternalProviderId = preferredProviderDef.id === "openai" && preferredHasOpenAIOAuth ? "codex" : preferredProviderDef.id;
|
|
@@ -33654,8 +34077,9 @@ async function ensureConfiguredV2(config) {
|
|
|
33654
34077
|
if (retryResult !== null) return retryResult;
|
|
33655
34078
|
}
|
|
33656
34079
|
preferredWasConfiguredButUnavailable = true;
|
|
34080
|
+
preferredUnavailableWasLocal = preferredIsLocal;
|
|
33657
34081
|
}
|
|
33658
|
-
if (!preferredWasConfiguredButUnavailable) {
|
|
34082
|
+
if (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal) {
|
|
33659
34083
|
const configuredProviders = providers.filter((p45) => {
|
|
33660
34084
|
if (p45.id === "copilot") return isProviderConfigured();
|
|
33661
34085
|
if (p45.id === "openai") {
|
|
@@ -33676,6 +34100,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33676
34100
|
}
|
|
33677
34101
|
const provider = await createProvider(providerId, { model });
|
|
33678
34102
|
if (await provider.isAvailable()) {
|
|
34103
|
+
await saveProviderPreference(prov.id, model);
|
|
33679
34104
|
return {
|
|
33680
34105
|
...config,
|
|
33681
34106
|
provider: {
|
|
@@ -33690,7 +34115,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33690
34115
|
}
|
|
33691
34116
|
}
|
|
33692
34117
|
}
|
|
33693
|
-
if (config.provider.type !== "openai" && config.provider.type !== "codex" && hasOpenAIOAuthTokens && !preferredWasConfiguredButUnavailable) {
|
|
34118
|
+
if (config.provider.type !== "openai" && config.provider.type !== "codex" && hasOpenAIOAuthTokens && (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal)) {
|
|
33694
34119
|
try {
|
|
33695
34120
|
const tokenResult = await getOrRefreshOAuthToken("openai");
|
|
33696
34121
|
if (tokenResult) {
|
|
@@ -34174,8 +34599,8 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
34174
34599
|
return false;
|
|
34175
34600
|
}
|
|
34176
34601
|
const { exec: exec3 } = await import('child_process');
|
|
34177
|
-
const { promisify:
|
|
34178
|
-
const execAsync3 =
|
|
34602
|
+
const { promisify: promisify6 } = await import('util');
|
|
34603
|
+
const execAsync3 = promisify6(exec3);
|
|
34179
34604
|
try {
|
|
34180
34605
|
await execAsync3("gcloud auth application-default login", { timeout: 12e4 });
|
|
34181
34606
|
const token = await getADCAccessToken();
|
|
@@ -34911,8 +35336,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
34911
35336
|
p26.log.message("");
|
|
34912
35337
|
for (const project of projects) {
|
|
34913
35338
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
34914
|
-
const
|
|
34915
|
-
p26.log.message(` [${level}] ${
|
|
35339
|
+
const path60 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
35340
|
+
p26.log.message(` [${level}] ${path60}`);
|
|
34916
35341
|
p26.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
34917
35342
|
}
|
|
34918
35343
|
p26.log.message("");
|
|
@@ -35082,8 +35507,8 @@ var buildCommand = {
|
|
|
35082
35507
|
};
|
|
35083
35508
|
async function loadBacklog(projectPath) {
|
|
35084
35509
|
try {
|
|
35085
|
-
const backlogPath =
|
|
35086
|
-
const content = await
|
|
35510
|
+
const backlogPath = path38.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35511
|
+
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35087
35512
|
const data = JSON.parse(content);
|
|
35088
35513
|
return data.backlog;
|
|
35089
35514
|
} catch {
|
|
@@ -35092,25 +35517,25 @@ async function loadBacklog(projectPath) {
|
|
|
35092
35517
|
}
|
|
35093
35518
|
async function loadSprint(projectPath, sprintId) {
|
|
35094
35519
|
try {
|
|
35095
|
-
const sprintsDir =
|
|
35096
|
-
const files = await
|
|
35520
|
+
const sprintsDir = path38.join(projectPath, ".coco", "planning", "sprints");
|
|
35521
|
+
const files = await fs35.readdir(sprintsDir);
|
|
35097
35522
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
35098
35523
|
if (jsonFiles.length === 0) return null;
|
|
35099
35524
|
const targetFile = sprintId ? jsonFiles.find((f) => f.includes(sprintId)) : jsonFiles[0];
|
|
35100
35525
|
if (!targetFile) return null;
|
|
35101
|
-
const sprintPath =
|
|
35102
|
-
const content = await
|
|
35526
|
+
const sprintPath = path38.join(sprintsDir, targetFile);
|
|
35527
|
+
const content = await fs35.readFile(sprintPath, "utf-8");
|
|
35103
35528
|
return JSON.parse(content);
|
|
35104
35529
|
} catch {
|
|
35105
35530
|
return null;
|
|
35106
35531
|
}
|
|
35107
35532
|
}
|
|
35108
35533
|
async function saveBacklog(projectPath, backlog) {
|
|
35109
|
-
const backlogPath =
|
|
35110
|
-
const content = await
|
|
35534
|
+
const backlogPath = path38.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35535
|
+
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35111
35536
|
const data = JSON.parse(content);
|
|
35112
35537
|
data.backlog = backlog;
|
|
35113
|
-
await
|
|
35538
|
+
await fs35.writeFile(backlogPath, JSON.stringify(data, null, 2), "utf-8");
|
|
35114
35539
|
}
|
|
35115
35540
|
function getStatusEmoji(status) {
|
|
35116
35541
|
const emojis = {
|
|
@@ -35816,7 +36241,7 @@ function getLevelName(level) {
|
|
|
35816
36241
|
function displayMemoryFile(file) {
|
|
35817
36242
|
const { emoji, color } = getLevelStyle(file.level);
|
|
35818
36243
|
const levelName = getLevelName(file.level);
|
|
35819
|
-
const fileName =
|
|
36244
|
+
const fileName = path38__default.basename(file.path);
|
|
35820
36245
|
console.log();
|
|
35821
36246
|
console.log(
|
|
35822
36247
|
`${emoji} ${color.bold(levelName)} ${chalk.dim(`(${fileName})`)} ${chalk.dim(file.path)}`
|
|
@@ -35911,7 +36336,7 @@ var memoryCommand = {
|
|
|
35911
36336
|
)
|
|
35912
36337
|
);
|
|
35913
36338
|
for (const f of reloaded) {
|
|
35914
|
-
const fileName =
|
|
36339
|
+
const fileName = path38__default.basename(f.path);
|
|
35915
36340
|
console.log(chalk.dim(` ${fileName} (${formatSize(f.content?.length ?? 0)})`));
|
|
35916
36341
|
}
|
|
35917
36342
|
} else {
|
|
@@ -36053,7 +36478,7 @@ async function getCheckpoint(session, checkpointId) {
|
|
|
36053
36478
|
return store.checkpoints.find((cp) => cp.id === checkpointId) ?? null;
|
|
36054
36479
|
}
|
|
36055
36480
|
async function restoreFiles(checkpoint, excludeFiles) {
|
|
36056
|
-
const
|
|
36481
|
+
const fs56 = await import('fs/promises');
|
|
36057
36482
|
const restored = [];
|
|
36058
36483
|
const failed = [];
|
|
36059
36484
|
for (const fileCheckpoint of checkpoint.files) {
|
|
@@ -36061,7 +36486,7 @@ async function restoreFiles(checkpoint, excludeFiles) {
|
|
|
36061
36486
|
continue;
|
|
36062
36487
|
}
|
|
36063
36488
|
try {
|
|
36064
|
-
await
|
|
36489
|
+
await fs56.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
|
|
36065
36490
|
restored.push(fileCheckpoint.filePath);
|
|
36066
36491
|
} catch (error) {
|
|
36067
36492
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -36143,8 +36568,8 @@ function displayRewindResult(result) {
|
|
|
36143
36568
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
36144
36569
|
console.log(`${chalk.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
36145
36570
|
}
|
|
36146
|
-
for (const { path:
|
|
36147
|
-
const fileName =
|
|
36571
|
+
for (const { path: path60, error } of result.filesFailed) {
|
|
36572
|
+
const fileName = path60.split("/").pop() ?? path60;
|
|
36148
36573
|
console.log(`${chalk.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
36149
36574
|
}
|
|
36150
36575
|
if (result.conversationRestored) {
|
|
@@ -36782,8 +37207,8 @@ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@corbat-tech/coco/latest";
|
|
|
36782
37207
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
36783
37208
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
36784
37209
|
var STARTUP_TIMEOUT_MS = 5500;
|
|
36785
|
-
var CACHE_DIR =
|
|
36786
|
-
var CACHE_FILE =
|
|
37210
|
+
var CACHE_DIR = path38__default.join(os4__default.homedir(), ".coco");
|
|
37211
|
+
var CACHE_FILE = path38__default.join(CACHE_DIR, "version-check-cache.json");
|
|
36787
37212
|
function compareVersions(a, b) {
|
|
36788
37213
|
const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
36789
37214
|
const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
@@ -37125,7 +37550,7 @@ async function readClipboardImage() {
|
|
|
37125
37550
|
return null;
|
|
37126
37551
|
}
|
|
37127
37552
|
async function readClipboardImageMacOS() {
|
|
37128
|
-
const tmpFile =
|
|
37553
|
+
const tmpFile = path38.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37129
37554
|
try {
|
|
37130
37555
|
const script = `
|
|
37131
37556
|
set theFile to POSIX file "${tmpFile}"
|
|
@@ -37148,7 +37573,7 @@ end try
|
|
|
37148
37573
|
if (!result.startsWith("ok")) {
|
|
37149
37574
|
return null;
|
|
37150
37575
|
}
|
|
37151
|
-
const buffer = await
|
|
37576
|
+
const buffer = await fs35.readFile(tmpFile);
|
|
37152
37577
|
return {
|
|
37153
37578
|
data: buffer.toString("base64"),
|
|
37154
37579
|
media_type: "image/png"
|
|
@@ -37157,7 +37582,7 @@ end try
|
|
|
37157
37582
|
return null;
|
|
37158
37583
|
} finally {
|
|
37159
37584
|
try {
|
|
37160
|
-
await
|
|
37585
|
+
await fs35.unlink(tmpFile);
|
|
37161
37586
|
} catch {
|
|
37162
37587
|
}
|
|
37163
37588
|
}
|
|
@@ -37187,7 +37612,7 @@ async function readClipboardImageLinux() {
|
|
|
37187
37612
|
}
|
|
37188
37613
|
}
|
|
37189
37614
|
async function readClipboardImageWindows() {
|
|
37190
|
-
const tmpFile =
|
|
37615
|
+
const tmpFile = path38.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37191
37616
|
try {
|
|
37192
37617
|
const escapedPath = tmpFile.replace(/'/g, "''");
|
|
37193
37618
|
const script = `
|
|
@@ -37205,7 +37630,7 @@ if ($img -ne $null) {
|
|
|
37205
37630
|
timeout: 1e4
|
|
37206
37631
|
}).trim();
|
|
37207
37632
|
if (result !== "ok") return null;
|
|
37208
|
-
const buffer = await
|
|
37633
|
+
const buffer = await fs35.readFile(tmpFile);
|
|
37209
37634
|
return {
|
|
37210
37635
|
data: buffer.toString("base64"),
|
|
37211
37636
|
media_type: "image/png"
|
|
@@ -37214,7 +37639,7 @@ if ($img -ne $null) {
|
|
|
37214
37639
|
return null;
|
|
37215
37640
|
} finally {
|
|
37216
37641
|
try {
|
|
37217
|
-
await
|
|
37642
|
+
await fs35.unlink(tmpFile);
|
|
37218
37643
|
} catch {
|
|
37219
37644
|
}
|
|
37220
37645
|
}
|
|
@@ -37312,9 +37737,9 @@ var allowPathCommand = {
|
|
|
37312
37737
|
}
|
|
37313
37738
|
};
|
|
37314
37739
|
async function addPath(dirPath, session) {
|
|
37315
|
-
const absolute =
|
|
37740
|
+
const absolute = path38__default.resolve(dirPath);
|
|
37316
37741
|
try {
|
|
37317
|
-
const stat2 = await
|
|
37742
|
+
const stat2 = await fs35__default.stat(absolute);
|
|
37318
37743
|
if (!stat2.isDirectory()) {
|
|
37319
37744
|
p26.log.error(`Not a directory: ${absolute}`);
|
|
37320
37745
|
return;
|
|
@@ -37324,19 +37749,19 @@ async function addPath(dirPath, session) {
|
|
|
37324
37749
|
return;
|
|
37325
37750
|
}
|
|
37326
37751
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
37327
|
-
const normalizedBlocked =
|
|
37328
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
37752
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
37753
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
37329
37754
|
p26.log.error(`System path '${blocked}' cannot be allowed`);
|
|
37330
37755
|
return;
|
|
37331
37756
|
}
|
|
37332
37757
|
}
|
|
37333
|
-
const normalizedCwd =
|
|
37334
|
-
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd +
|
|
37758
|
+
const normalizedCwd = path38__default.normalize(session.projectPath);
|
|
37759
|
+
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd + path38__default.sep)) {
|
|
37335
37760
|
p26.log.info("That path is already within the project directory");
|
|
37336
37761
|
return;
|
|
37337
37762
|
}
|
|
37338
37763
|
const existing = getAllowedPaths();
|
|
37339
|
-
if (existing.some((e) =>
|
|
37764
|
+
if (existing.some((e) => path38__default.normalize(e.path) === path38__default.normalize(absolute))) {
|
|
37340
37765
|
p26.log.info(`Already allowed: ${absolute}`);
|
|
37341
37766
|
return;
|
|
37342
37767
|
}
|
|
@@ -37407,7 +37832,7 @@ async function revokePath(dirPath, _session) {
|
|
|
37407
37832
|
}
|
|
37408
37833
|
dirPath = selected;
|
|
37409
37834
|
}
|
|
37410
|
-
const absolute =
|
|
37835
|
+
const absolute = path38__default.resolve(dirPath);
|
|
37411
37836
|
const removed = removeAllowedPathFromSession(absolute);
|
|
37412
37837
|
await removePersistedAllowedPath(absolute);
|
|
37413
37838
|
if (removed) {
|
|
@@ -37760,11 +38185,12 @@ var RECOMMENDED_DENY = [
|
|
|
37760
38185
|
];
|
|
37761
38186
|
async function loadPermissionPreferences() {
|
|
37762
38187
|
try {
|
|
37763
|
-
const content = await
|
|
38188
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
37764
38189
|
const config = JSON.parse(content);
|
|
37765
38190
|
return {
|
|
37766
38191
|
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
37767
|
-
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed
|
|
38192
|
+
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed,
|
|
38193
|
+
recommendedAllowlistPrompted: config.recommendedAllowlistPrompted
|
|
37768
38194
|
};
|
|
37769
38195
|
} catch {
|
|
37770
38196
|
return {};
|
|
@@ -37774,34 +38200,28 @@ async function savePermissionPreference(key, value) {
|
|
|
37774
38200
|
try {
|
|
37775
38201
|
let config = {};
|
|
37776
38202
|
try {
|
|
37777
|
-
const content = await
|
|
38203
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
37778
38204
|
config = JSON.parse(content);
|
|
37779
38205
|
} catch {
|
|
37780
38206
|
}
|
|
37781
38207
|
config[key] = value;
|
|
37782
|
-
await
|
|
37783
|
-
await
|
|
38208
|
+
await fs35__default.mkdir(path38__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
38209
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
37784
38210
|
} catch {
|
|
37785
38211
|
}
|
|
37786
38212
|
}
|
|
37787
38213
|
async function shouldShowPermissionSuggestion() {
|
|
37788
38214
|
const prefs = await loadPermissionPreferences();
|
|
37789
|
-
if (prefs.
|
|
38215
|
+
if (prefs.recommendedAllowlistPrompted) {
|
|
37790
38216
|
return false;
|
|
37791
38217
|
}
|
|
37792
|
-
if (
|
|
37793
|
-
return
|
|
38218
|
+
if (prefs.recommendedAllowlistDismissed) {
|
|
38219
|
+
return false;
|
|
37794
38220
|
}
|
|
37795
|
-
|
|
37796
|
-
|
|
37797
|
-
const settings = JSON.parse(content);
|
|
37798
|
-
if (!settings.globalTrusted || settings.globalTrusted.length === 0) {
|
|
37799
|
-
return true;
|
|
37800
|
-
}
|
|
37801
|
-
} catch {
|
|
37802
|
-
return true;
|
|
38221
|
+
if (prefs.recommendedAllowlistApplied) {
|
|
38222
|
+
return false;
|
|
37803
38223
|
}
|
|
37804
|
-
return
|
|
38224
|
+
return true;
|
|
37805
38225
|
}
|
|
37806
38226
|
async function applyRecommendedPermissions() {
|
|
37807
38227
|
for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
|
|
@@ -37810,6 +38230,7 @@ async function applyRecommendedPermissions() {
|
|
|
37810
38230
|
await savePermissionPreference("recommendedAllowlistApplied", true);
|
|
37811
38231
|
}
|
|
37812
38232
|
async function showPermissionSuggestion() {
|
|
38233
|
+
await savePermissionPreference("recommendedAllowlistPrompted", true);
|
|
37813
38234
|
console.log();
|
|
37814
38235
|
console.log(chalk.magenta.bold(" \u{1F4CB} Recommended Permissions"));
|
|
37815
38236
|
console.log();
|
|
@@ -38029,7 +38450,7 @@ async function resetPermissions(session) {
|
|
|
38029
38450
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
38030
38451
|
};
|
|
38031
38452
|
try {
|
|
38032
|
-
await
|
|
38453
|
+
await fs35__default.writeFile(CONFIG_PATHS.trustedTools, JSON.stringify(emptySettings, null, 2), "utf-8");
|
|
38033
38454
|
} catch {
|
|
38034
38455
|
}
|
|
38035
38456
|
await savePermissionPreference("recommendedAllowlistApplied", false);
|
|
@@ -38111,7 +38532,7 @@ function formatQualityResult(result) {
|
|
|
38111
38532
|
}
|
|
38112
38533
|
async function loadQualityLoopPreference() {
|
|
38113
38534
|
try {
|
|
38114
|
-
const content = await
|
|
38535
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
38115
38536
|
const config = JSON.parse(content);
|
|
38116
38537
|
const value = config.qualityLoop ?? config.cocoMode;
|
|
38117
38538
|
if (typeof value === "boolean") {
|
|
@@ -38126,12 +38547,12 @@ async function saveQualityLoopPreference(enabled) {
|
|
|
38126
38547
|
try {
|
|
38127
38548
|
let config = {};
|
|
38128
38549
|
try {
|
|
38129
|
-
const content = await
|
|
38550
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
38130
38551
|
config = JSON.parse(content);
|
|
38131
38552
|
} catch {
|
|
38132
38553
|
}
|
|
38133
38554
|
config.qualityLoop = enabled;
|
|
38134
|
-
await
|
|
38555
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
38135
38556
|
} catch {
|
|
38136
38557
|
}
|
|
38137
38558
|
}
|
|
@@ -38977,9 +39398,9 @@ Response format (JSON only, no prose):
|
|
|
38977
39398
|
cancel5("Build cancelled.");
|
|
38978
39399
|
}
|
|
38979
39400
|
}
|
|
38980
|
-
const cocoDir =
|
|
38981
|
-
await
|
|
38982
|
-
await
|
|
39401
|
+
const cocoDir = path38__default.join(outputPath, ".coco");
|
|
39402
|
+
await fs35__default.mkdir(cocoDir, { recursive: true });
|
|
39403
|
+
await fs35__default.writeFile(path38__default.join(cocoDir, "backlog.json"), JSON.stringify(spec, null, 2), "utf-8");
|
|
38983
39404
|
p26.outro(" Spec saved \u2014 starting sprints");
|
|
38984
39405
|
return spec;
|
|
38985
39406
|
}
|
|
@@ -39529,20 +39950,20 @@ init_errors();
|
|
|
39529
39950
|
init_subprocess_registry();
|
|
39530
39951
|
async function detectTestFramework2(cwd) {
|
|
39531
39952
|
try {
|
|
39532
|
-
await
|
|
39953
|
+
await fs35__default.access(path38__default.join(cwd, "pom.xml"));
|
|
39533
39954
|
return "maven";
|
|
39534
39955
|
} catch {
|
|
39535
39956
|
}
|
|
39536
39957
|
for (const gradleFile of ["build.gradle", "build.gradle.kts"]) {
|
|
39537
39958
|
try {
|
|
39538
|
-
await
|
|
39959
|
+
await fs35__default.access(path38__default.join(cwd, gradleFile));
|
|
39539
39960
|
return "gradle";
|
|
39540
39961
|
} catch {
|
|
39541
39962
|
}
|
|
39542
39963
|
}
|
|
39543
39964
|
try {
|
|
39544
|
-
const pkgPath =
|
|
39545
|
-
const pkgContent = await
|
|
39965
|
+
const pkgPath = path38__default.join(cwd, "package.json");
|
|
39966
|
+
const pkgContent = await fs35__default.readFile(pkgPath, "utf-8");
|
|
39546
39967
|
const pkg = JSON.parse(pkgContent);
|
|
39547
39968
|
const deps = {
|
|
39548
39969
|
...pkg.dependencies,
|
|
@@ -39558,16 +39979,16 @@ async function detectTestFramework2(cwd) {
|
|
|
39558
39979
|
}
|
|
39559
39980
|
}
|
|
39560
39981
|
function toMavenTestFilter(pattern) {
|
|
39561
|
-
const base =
|
|
39982
|
+
const base = path38__default.basename(pattern).replace(/\.java$/, "");
|
|
39562
39983
|
return base;
|
|
39563
39984
|
}
|
|
39564
39985
|
function toGradleTestFilter(pattern) {
|
|
39565
|
-
const base =
|
|
39986
|
+
const base = path38__default.basename(pattern).replace(/\.java$/, "");
|
|
39566
39987
|
return `*${base}`;
|
|
39567
39988
|
}
|
|
39568
39989
|
async function mavenExecutable(cwd) {
|
|
39569
39990
|
try {
|
|
39570
|
-
await
|
|
39991
|
+
await fs35__default.access(path38__default.join(cwd, "mvnw"));
|
|
39571
39992
|
return "./mvnw";
|
|
39572
39993
|
} catch {
|
|
39573
39994
|
return "mvn";
|
|
@@ -39575,7 +39996,7 @@ async function mavenExecutable(cwd) {
|
|
|
39575
39996
|
}
|
|
39576
39997
|
async function gradleExecutable(cwd) {
|
|
39577
39998
|
try {
|
|
39578
|
-
await
|
|
39999
|
+
await fs35__default.access(path38__default.join(cwd, "gradlew"));
|
|
39579
40000
|
return "./gradlew";
|
|
39580
40001
|
} catch {
|
|
39581
40002
|
return "gradle";
|
|
@@ -39816,18 +40237,18 @@ Examples:
|
|
|
39816
40237
|
const projectDir = cwd ?? process.cwd();
|
|
39817
40238
|
try {
|
|
39818
40239
|
const coverageLocations = [
|
|
39819
|
-
|
|
39820
|
-
|
|
39821
|
-
|
|
40240
|
+
path38__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
40241
|
+
path38__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
40242
|
+
path38__default.join(projectDir, ".nyc_output", "coverage-summary.json"),
|
|
39822
40243
|
// Maven JaCoCo
|
|
39823
|
-
|
|
39824
|
-
|
|
40244
|
+
path38__default.join(projectDir, "target", "site", "jacoco", "jacoco.csv"),
|
|
40245
|
+
path38__default.join(projectDir, "target", "site", "jacoco-ut", "jacoco.csv"),
|
|
39825
40246
|
// Gradle JaCoCo
|
|
39826
|
-
|
|
40247
|
+
path38__default.join(projectDir, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")
|
|
39827
40248
|
];
|
|
39828
40249
|
for (const location of coverageLocations) {
|
|
39829
40250
|
try {
|
|
39830
|
-
const content = await
|
|
40251
|
+
const content = await fs35__default.readFile(location, "utf-8");
|
|
39831
40252
|
if (location.endsWith(".csv")) {
|
|
39832
40253
|
const result = parseJacocoCsvCoverage(content);
|
|
39833
40254
|
if (result) {
|
|
@@ -39936,7 +40357,7 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
39936
40357
|
const results = [];
|
|
39937
40358
|
const startTime = Date.now();
|
|
39938
40359
|
const isTimedOut = () => Date.now() - startTime > opts.timeoutMs;
|
|
39939
|
-
const queue = [[
|
|
40360
|
+
const queue = [[path38__default.resolve(rootDir), 0]];
|
|
39940
40361
|
const visited = /* @__PURE__ */ new Set();
|
|
39941
40362
|
while (queue.length > 0 && results.length < opts.maxResults) {
|
|
39942
40363
|
if (isTimedOut()) break;
|
|
@@ -39945,11 +40366,11 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
39945
40366
|
visited.add(currentDir);
|
|
39946
40367
|
if (depth > opts.maxDepth) continue;
|
|
39947
40368
|
try {
|
|
39948
|
-
const entries = await
|
|
40369
|
+
const entries = await fs35__default.readdir(currentDir, { withFileTypes: true });
|
|
39949
40370
|
for (const entry of entries) {
|
|
39950
40371
|
if (isTimedOut()) break;
|
|
39951
40372
|
const entryName = entry.name;
|
|
39952
|
-
const entryPath =
|
|
40373
|
+
const entryPath = path38__default.join(currentDir, entryName);
|
|
39953
40374
|
if (!opts.includeHidden && entryName.startsWith(".")) continue;
|
|
39954
40375
|
if (entry.isDirectory() && opts.excludeDirs.has(entryName)) continue;
|
|
39955
40376
|
const isMatch = opts.type === "file" && entry.isFile() || opts.type === "directory" && entry.isDirectory() || opts.type === "both";
|
|
@@ -39983,19 +40404,19 @@ async function suggestSimilarFilesDeep(missingPath, rootDir = process.cwd(), opt
|
|
|
39983
40404
|
if (fastResults.length > 0) {
|
|
39984
40405
|
return fastResults;
|
|
39985
40406
|
}
|
|
39986
|
-
const absPath =
|
|
39987
|
-
const target =
|
|
40407
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40408
|
+
const target = path38__default.basename(absPath);
|
|
39988
40409
|
return findFileRecursive(rootDir, target, options);
|
|
39989
40410
|
}
|
|
39990
40411
|
async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), options) {
|
|
39991
|
-
const absPath =
|
|
39992
|
-
const target =
|
|
39993
|
-
const parentDir =
|
|
40412
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40413
|
+
const target = path38__default.basename(absPath);
|
|
40414
|
+
const parentDir = path38__default.dirname(absPath);
|
|
39994
40415
|
try {
|
|
39995
|
-
const entries = await
|
|
40416
|
+
const entries = await fs35__default.readdir(parentDir, { withFileTypes: true });
|
|
39996
40417
|
const dirs = entries.filter((e) => e.isDirectory());
|
|
39997
40418
|
const scored = dirs.map((d) => ({
|
|
39998
|
-
path:
|
|
40419
|
+
path: path38__default.join(parentDir, d.name),
|
|
39999
40420
|
distance: levenshtein(target.toLowerCase(), d.name.toLowerCase())
|
|
40000
40421
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance).slice(0, options?.maxResults ?? MAX_SUGGESTIONS);
|
|
40001
40422
|
if (scored.length > 0) {
|
|
@@ -40006,15 +40427,15 @@ async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), opti
|
|
|
40006
40427
|
return findFileRecursive(rootDir, target, { ...options, type: "directory" });
|
|
40007
40428
|
}
|
|
40008
40429
|
async function suggestSimilarFiles(missingPath, options) {
|
|
40009
|
-
const absPath =
|
|
40010
|
-
const dir =
|
|
40011
|
-
const target =
|
|
40430
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40431
|
+
const dir = path38__default.dirname(absPath);
|
|
40432
|
+
const target = path38__default.basename(absPath);
|
|
40012
40433
|
const maxResults = options?.maxResults;
|
|
40013
40434
|
try {
|
|
40014
|
-
const entries = await
|
|
40435
|
+
const entries = await fs35__default.readdir(dir);
|
|
40015
40436
|
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
40016
40437
|
const scored = limited.map((name) => ({
|
|
40017
|
-
path:
|
|
40438
|
+
path: path38__default.join(dir, name),
|
|
40018
40439
|
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
40019
40440
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
40020
40441
|
return scored.slice(0, maxResults);
|
|
@@ -40026,7 +40447,7 @@ function formatSuggestions(suggestions, baseDir) {
|
|
|
40026
40447
|
if (suggestions.length === 0) return "";
|
|
40027
40448
|
const base = baseDir ?? process.cwd();
|
|
40028
40449
|
const lines = suggestions.map((s) => {
|
|
40029
|
-
const rel =
|
|
40450
|
+
const rel = path38__default.relative(base, s.path);
|
|
40030
40451
|
return ` - ${rel}`;
|
|
40031
40452
|
});
|
|
40032
40453
|
return `
|
|
@@ -40060,7 +40481,7 @@ function hasNullByte2(str) {
|
|
|
40060
40481
|
}
|
|
40061
40482
|
function normalizePath2(filePath) {
|
|
40062
40483
|
let normalized = filePath.replace(/\0/g, "");
|
|
40063
|
-
normalized =
|
|
40484
|
+
normalized = path38__default.normalize(normalized);
|
|
40064
40485
|
return normalized;
|
|
40065
40486
|
}
|
|
40066
40487
|
function isPathAllowed(filePath, operation) {
|
|
@@ -40068,31 +40489,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
40068
40489
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
40069
40490
|
}
|
|
40070
40491
|
const normalized = normalizePath2(filePath);
|
|
40071
|
-
const absolute =
|
|
40492
|
+
const absolute = path38__default.resolve(normalized);
|
|
40072
40493
|
const cwd = process.cwd();
|
|
40073
40494
|
for (const blocked of BLOCKED_PATHS2) {
|
|
40074
|
-
const normalizedBlocked =
|
|
40075
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
40495
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
40496
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
40076
40497
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
40077
40498
|
}
|
|
40078
40499
|
}
|
|
40079
40500
|
const home = process.env.HOME;
|
|
40080
40501
|
if (home) {
|
|
40081
|
-
const normalizedHome =
|
|
40082
|
-
const normalizedCwd =
|
|
40502
|
+
const normalizedHome = path38__default.normalize(home);
|
|
40503
|
+
const normalizedCwd = path38__default.normalize(cwd);
|
|
40083
40504
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
40084
40505
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
40085
40506
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
40086
|
-
const basename4 =
|
|
40507
|
+
const basename4 = path38__default.basename(absolute);
|
|
40087
40508
|
if (!allowedHomeReads.includes(basename4)) {
|
|
40088
|
-
const targetDir =
|
|
40509
|
+
const targetDir = path38__default.dirname(absolute);
|
|
40089
40510
|
return {
|
|
40090
40511
|
allowed: false,
|
|
40091
40512
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
40092
40513
|
};
|
|
40093
40514
|
}
|
|
40094
40515
|
} else {
|
|
40095
|
-
const targetDir =
|
|
40516
|
+
const targetDir = path38__default.dirname(absolute);
|
|
40096
40517
|
return {
|
|
40097
40518
|
allowed: false,
|
|
40098
40519
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -40101,7 +40522,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
40101
40522
|
}
|
|
40102
40523
|
}
|
|
40103
40524
|
if (operation === "write" || operation === "delete") {
|
|
40104
|
-
const basename4 =
|
|
40525
|
+
const basename4 = path38__default.basename(absolute);
|
|
40105
40526
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
40106
40527
|
if (pattern.test(basename4)) {
|
|
40107
40528
|
return {
|
|
@@ -40124,17 +40545,17 @@ function isENOENT(error) {
|
|
|
40124
40545
|
return error.code === "ENOENT";
|
|
40125
40546
|
}
|
|
40126
40547
|
async function enrichENOENT(filePath, operation) {
|
|
40127
|
-
const absPath =
|
|
40548
|
+
const absPath = path38__default.resolve(filePath);
|
|
40128
40549
|
const suggestions = await suggestSimilarFilesDeep(absPath, process.cwd());
|
|
40129
|
-
const hint = formatSuggestions(suggestions,
|
|
40550
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(absPath));
|
|
40130
40551
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
40131
40552
|
return `File not found: ${filePath}${hint}
|
|
40132
40553
|
${action}`;
|
|
40133
40554
|
}
|
|
40134
40555
|
async function enrichDirENOENT(dirPath) {
|
|
40135
|
-
const absPath =
|
|
40556
|
+
const absPath = path38__default.resolve(dirPath);
|
|
40136
40557
|
const suggestions = await suggestSimilarDirsDeep(absPath, process.cwd());
|
|
40137
|
-
const hint = formatSuggestions(suggestions,
|
|
40558
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(absPath));
|
|
40138
40559
|
return `Directory not found: ${dirPath}${hint}
|
|
40139
40560
|
Use list_dir or glob to find the correct path.`;
|
|
40140
40561
|
}
|
|
@@ -40155,13 +40576,13 @@ Examples:
|
|
|
40155
40576
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
40156
40577
|
validatePath(filePath, "read");
|
|
40157
40578
|
try {
|
|
40158
|
-
const absolutePath =
|
|
40159
|
-
const stats = await
|
|
40579
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40580
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40160
40581
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
40161
40582
|
let truncated = false;
|
|
40162
40583
|
let content;
|
|
40163
40584
|
if (stats.size > maxBytes) {
|
|
40164
|
-
const handle = await
|
|
40585
|
+
const handle = await fs35__default.open(absolutePath, "r");
|
|
40165
40586
|
try {
|
|
40166
40587
|
const buffer = Buffer.alloc(maxBytes);
|
|
40167
40588
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -40171,7 +40592,7 @@ Examples:
|
|
|
40171
40592
|
await handle.close();
|
|
40172
40593
|
}
|
|
40173
40594
|
} else {
|
|
40174
|
-
content = await
|
|
40595
|
+
content = await fs35__default.readFile(absolutePath, encoding);
|
|
40175
40596
|
}
|
|
40176
40597
|
return {
|
|
40177
40598
|
content,
|
|
@@ -40214,10 +40635,10 @@ Examples:
|
|
|
40214
40635
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
40215
40636
|
validatePath(filePath, "write");
|
|
40216
40637
|
try {
|
|
40217
|
-
const absolutePath =
|
|
40638
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40218
40639
|
let wouldCreate = false;
|
|
40219
40640
|
try {
|
|
40220
|
-
await
|
|
40641
|
+
await fs35__default.access(absolutePath);
|
|
40221
40642
|
} catch {
|
|
40222
40643
|
wouldCreate = true;
|
|
40223
40644
|
}
|
|
@@ -40230,10 +40651,10 @@ Examples:
|
|
|
40230
40651
|
};
|
|
40231
40652
|
}
|
|
40232
40653
|
if (createDirs) {
|
|
40233
|
-
await
|
|
40654
|
+
await fs35__default.mkdir(path38__default.dirname(absolutePath), { recursive: true });
|
|
40234
40655
|
}
|
|
40235
|
-
await
|
|
40236
|
-
const stats = await
|
|
40656
|
+
await fs35__default.writeFile(absolutePath, content, "utf-8");
|
|
40657
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40237
40658
|
return {
|
|
40238
40659
|
path: absolutePath,
|
|
40239
40660
|
size: stats.size,
|
|
@@ -40276,8 +40697,8 @@ Examples:
|
|
|
40276
40697
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
40277
40698
|
validatePath(filePath, "write");
|
|
40278
40699
|
try {
|
|
40279
|
-
const absolutePath =
|
|
40280
|
-
let content = await
|
|
40700
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40701
|
+
let content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
40281
40702
|
let replacements = 0;
|
|
40282
40703
|
if (all) {
|
|
40283
40704
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -40326,7 +40747,7 @@ Hint: Use read_file first to verify the exact content.`
|
|
|
40326
40747
|
preview
|
|
40327
40748
|
};
|
|
40328
40749
|
}
|
|
40329
|
-
await
|
|
40750
|
+
await fs35__default.writeFile(absolutePath, content, "utf-8");
|
|
40330
40751
|
return {
|
|
40331
40752
|
path: absolutePath,
|
|
40332
40753
|
replacements,
|
|
@@ -40397,8 +40818,8 @@ Examples:
|
|
|
40397
40818
|
}),
|
|
40398
40819
|
async execute({ path: filePath }) {
|
|
40399
40820
|
try {
|
|
40400
|
-
const absolutePath =
|
|
40401
|
-
const stats = await
|
|
40821
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40822
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40402
40823
|
return {
|
|
40403
40824
|
exists: true,
|
|
40404
40825
|
isFile: stats.isFile(),
|
|
@@ -40428,12 +40849,12 @@ Examples:
|
|
|
40428
40849
|
}),
|
|
40429
40850
|
async execute({ path: dirPath, recursive }) {
|
|
40430
40851
|
try {
|
|
40431
|
-
const absolutePath =
|
|
40852
|
+
const absolutePath = path38__default.resolve(dirPath);
|
|
40432
40853
|
const entries = [];
|
|
40433
40854
|
async function listDir(dir, prefix = "") {
|
|
40434
|
-
const items = await
|
|
40855
|
+
const items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
40435
40856
|
for (const item of items) {
|
|
40436
|
-
const fullPath =
|
|
40857
|
+
const fullPath = path38__default.join(dir, item.name);
|
|
40437
40858
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
40438
40859
|
if (item.isDirectory()) {
|
|
40439
40860
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -40441,7 +40862,7 @@ Examples:
|
|
|
40441
40862
|
await listDir(fullPath, relativePath);
|
|
40442
40863
|
}
|
|
40443
40864
|
} else if (item.isFile()) {
|
|
40444
|
-
const stats = await
|
|
40865
|
+
const stats = await fs35__default.stat(fullPath);
|
|
40445
40866
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
40446
40867
|
}
|
|
40447
40868
|
}
|
|
@@ -40488,23 +40909,23 @@ Examples:
|
|
|
40488
40909
|
}
|
|
40489
40910
|
validatePath(filePath, "delete");
|
|
40490
40911
|
try {
|
|
40491
|
-
const absolutePath =
|
|
40492
|
-
const stats = await
|
|
40912
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40913
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40493
40914
|
if (stats.isDirectory()) {
|
|
40494
40915
|
if (!recursive) {
|
|
40495
40916
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
40496
40917
|
tool: "delete_file"
|
|
40497
40918
|
});
|
|
40498
40919
|
}
|
|
40499
|
-
await
|
|
40920
|
+
await fs35__default.rm(absolutePath, { recursive: true });
|
|
40500
40921
|
} else {
|
|
40501
|
-
await
|
|
40922
|
+
await fs35__default.unlink(absolutePath);
|
|
40502
40923
|
}
|
|
40503
40924
|
return { deleted: true, path: absolutePath };
|
|
40504
40925
|
} catch (error) {
|
|
40505
40926
|
if (error instanceof ToolError) throw error;
|
|
40506
40927
|
if (error.code === "ENOENT") {
|
|
40507
|
-
return { deleted: false, path:
|
|
40928
|
+
return { deleted: false, path: path38__default.resolve(filePath) };
|
|
40508
40929
|
}
|
|
40509
40930
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
40510
40931
|
path: filePath,
|
|
@@ -40532,11 +40953,11 @@ Examples:
|
|
|
40532
40953
|
validatePath(source, "read");
|
|
40533
40954
|
validatePath(destination, "write");
|
|
40534
40955
|
try {
|
|
40535
|
-
const srcPath =
|
|
40536
|
-
const destPath =
|
|
40956
|
+
const srcPath = path38__default.resolve(source);
|
|
40957
|
+
const destPath = path38__default.resolve(destination);
|
|
40537
40958
|
if (!overwrite) {
|
|
40538
40959
|
try {
|
|
40539
|
-
await
|
|
40960
|
+
await fs35__default.access(destPath);
|
|
40540
40961
|
throw new ToolError(
|
|
40541
40962
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
40542
40963
|
{
|
|
@@ -40549,9 +40970,9 @@ Examples:
|
|
|
40549
40970
|
}
|
|
40550
40971
|
}
|
|
40551
40972
|
}
|
|
40552
|
-
await
|
|
40553
|
-
await
|
|
40554
|
-
const stats = await
|
|
40973
|
+
await fs35__default.mkdir(path38__default.dirname(destPath), { recursive: true });
|
|
40974
|
+
await fs35__default.copyFile(srcPath, destPath);
|
|
40975
|
+
const stats = await fs35__default.stat(destPath);
|
|
40555
40976
|
return {
|
|
40556
40977
|
source: srcPath,
|
|
40557
40978
|
destination: destPath,
|
|
@@ -40593,11 +41014,11 @@ Examples:
|
|
|
40593
41014
|
validatePath(source, "delete");
|
|
40594
41015
|
validatePath(destination, "write");
|
|
40595
41016
|
try {
|
|
40596
|
-
const srcPath =
|
|
40597
|
-
const destPath =
|
|
41017
|
+
const srcPath = path38__default.resolve(source);
|
|
41018
|
+
const destPath = path38__default.resolve(destination);
|
|
40598
41019
|
if (!overwrite) {
|
|
40599
41020
|
try {
|
|
40600
|
-
await
|
|
41021
|
+
await fs35__default.access(destPath);
|
|
40601
41022
|
throw new ToolError(
|
|
40602
41023
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
40603
41024
|
{
|
|
@@ -40610,8 +41031,8 @@ Examples:
|
|
|
40610
41031
|
}
|
|
40611
41032
|
}
|
|
40612
41033
|
}
|
|
40613
|
-
await
|
|
40614
|
-
await
|
|
41034
|
+
await fs35__default.mkdir(path38__default.dirname(destPath), { recursive: true });
|
|
41035
|
+
await fs35__default.rename(srcPath, destPath);
|
|
40615
41036
|
return {
|
|
40616
41037
|
source: srcPath,
|
|
40617
41038
|
destination: destPath
|
|
@@ -40680,15 +41101,15 @@ Examples:
|
|
|
40680
41101
|
}),
|
|
40681
41102
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
40682
41103
|
try {
|
|
40683
|
-
const absolutePath =
|
|
41104
|
+
const absolutePath = path38__default.resolve(dirPath ?? ".");
|
|
40684
41105
|
let totalFiles = 0;
|
|
40685
41106
|
let totalDirs = 0;
|
|
40686
|
-
const lines = [
|
|
41107
|
+
const lines = [path38__default.basename(absolutePath) + "/"];
|
|
40687
41108
|
let truncated = false;
|
|
40688
41109
|
async function buildTree(dir, prefix, currentDepth) {
|
|
40689
41110
|
if (currentDepth > (depth ?? 4)) return;
|
|
40690
41111
|
if (lines.length >= MAX_TREE_LINES) return;
|
|
40691
|
-
let items = await
|
|
41112
|
+
let items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
40692
41113
|
items = items.filter((item) => !TREE_IGNORED_DIRS.has(item.name));
|
|
40693
41114
|
if (!showHidden) {
|
|
40694
41115
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
@@ -40713,7 +41134,7 @@ Examples:
|
|
|
40713
41134
|
if (item.isDirectory()) {
|
|
40714
41135
|
totalDirs++;
|
|
40715
41136
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
40716
|
-
await buildTree(
|
|
41137
|
+
await buildTree(path38__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
40717
41138
|
} else {
|
|
40718
41139
|
totalFiles++;
|
|
40719
41140
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -41981,7 +42402,7 @@ Examples:
|
|
|
41981
42402
|
caseSensitive,
|
|
41982
42403
|
wholeWord
|
|
41983
42404
|
}) {
|
|
41984
|
-
const targetPath = searchPath ?
|
|
42405
|
+
const targetPath = searchPath ? path38__default.resolve(searchPath) : process.cwd();
|
|
41985
42406
|
const matches = [];
|
|
41986
42407
|
let filesSearched = 0;
|
|
41987
42408
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -42003,7 +42424,7 @@ Examples:
|
|
|
42003
42424
|
tool: "grep"
|
|
42004
42425
|
});
|
|
42005
42426
|
}
|
|
42006
|
-
const stats = await
|
|
42427
|
+
const stats = await fs35__default.stat(targetPath);
|
|
42007
42428
|
let filesToSearch;
|
|
42008
42429
|
if (stats.isFile()) {
|
|
42009
42430
|
filesToSearch = [targetPath];
|
|
@@ -42025,7 +42446,7 @@ Examples:
|
|
|
42025
42446
|
}
|
|
42026
42447
|
filesSearched++;
|
|
42027
42448
|
try {
|
|
42028
|
-
const content = await
|
|
42449
|
+
const content = await fs35__default.readFile(file, "utf-8");
|
|
42029
42450
|
const lines = content.split("\n");
|
|
42030
42451
|
let fileHasMatch = false;
|
|
42031
42452
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -42048,7 +42469,7 @@ Examples:
|
|
|
42048
42469
|
contextAfter.push(lines[j] ?? "");
|
|
42049
42470
|
}
|
|
42050
42471
|
matches.push({
|
|
42051
|
-
file:
|
|
42472
|
+
file: path38__default.relative(process.cwd(), file),
|
|
42052
42473
|
line: i + 1,
|
|
42053
42474
|
column: match.index + 1,
|
|
42054
42475
|
content: line,
|
|
@@ -42099,8 +42520,8 @@ Examples:
|
|
|
42099
42520
|
}),
|
|
42100
42521
|
async execute({ file, pattern, caseSensitive }) {
|
|
42101
42522
|
try {
|
|
42102
|
-
const absolutePath =
|
|
42103
|
-
const content = await
|
|
42523
|
+
const absolutePath = path38__default.resolve(file);
|
|
42524
|
+
const content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
42104
42525
|
const lines = content.split("\n");
|
|
42105
42526
|
const matches = [];
|
|
42106
42527
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -42118,7 +42539,7 @@ Examples:
|
|
|
42118
42539
|
} catch (error) {
|
|
42119
42540
|
if (error.code === "ENOENT") {
|
|
42120
42541
|
const suggestions = await suggestSimilarFilesDeep(file, process.cwd());
|
|
42121
|
-
const hint = formatSuggestions(suggestions,
|
|
42542
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(file));
|
|
42122
42543
|
throw new ToolError(`File not found: ${file}${hint}
|
|
42123
42544
|
Use glob to find the correct path.`, {
|
|
42124
42545
|
tool: "find_in_file"
|
|
@@ -42309,7 +42730,7 @@ async function detectPackageManager2(cwd) {
|
|
|
42309
42730
|
];
|
|
42310
42731
|
for (const { file, pm } of lockfiles) {
|
|
42311
42732
|
try {
|
|
42312
|
-
await
|
|
42733
|
+
await fs35__default.access(path38__default.join(cwd, file));
|
|
42313
42734
|
return pm;
|
|
42314
42735
|
} catch {
|
|
42315
42736
|
}
|
|
@@ -42582,7 +43003,7 @@ ${message}
|
|
|
42582
43003
|
});
|
|
42583
43004
|
try {
|
|
42584
43005
|
try {
|
|
42585
|
-
await
|
|
43006
|
+
await fs35__default.access(path38__default.join(projectDir, "Makefile"));
|
|
42586
43007
|
} catch {
|
|
42587
43008
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
42588
43009
|
}
|
|
@@ -42752,7 +43173,7 @@ ${message}
|
|
|
42752
43173
|
});
|
|
42753
43174
|
async function resolveMaven(cwd) {
|
|
42754
43175
|
try {
|
|
42755
|
-
await
|
|
43176
|
+
await fs35__default.access(path38__default.join(cwd, "mvnw"));
|
|
42756
43177
|
return "./mvnw";
|
|
42757
43178
|
} catch {
|
|
42758
43179
|
return "mvn";
|
|
@@ -42760,7 +43181,7 @@ async function resolveMaven(cwd) {
|
|
|
42760
43181
|
}
|
|
42761
43182
|
async function resolveGradle(cwd) {
|
|
42762
43183
|
try {
|
|
42763
|
-
await
|
|
43184
|
+
await fs35__default.access(path38__default.join(cwd, "gradlew"));
|
|
42764
43185
|
return "./gradlew";
|
|
42765
43186
|
} catch {
|
|
42766
43187
|
return "gradle";
|
|
@@ -43627,8 +44048,8 @@ init_review();
|
|
|
43627
44048
|
// src/tools/codebase-map.ts
|
|
43628
44049
|
init_registry4();
|
|
43629
44050
|
init_errors();
|
|
43630
|
-
var
|
|
43631
|
-
var
|
|
44051
|
+
var fs38 = await import('fs/promises');
|
|
44052
|
+
var path41 = await import('path');
|
|
43632
44053
|
var { glob: glob14 } = await import('glob');
|
|
43633
44054
|
var DEFAULT_MAX_FILES = 200;
|
|
43634
44055
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -43654,7 +44075,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
43654
44075
|
"**/*.d.ts"
|
|
43655
44076
|
];
|
|
43656
44077
|
function detectLanguage3(filePath) {
|
|
43657
|
-
const ext =
|
|
44078
|
+
const ext = path41.extname(filePath).toLowerCase();
|
|
43658
44079
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
43659
44080
|
if (extensions.includes(ext)) return lang;
|
|
43660
44081
|
}
|
|
@@ -44063,9 +44484,9 @@ Examples:
|
|
|
44063
44484
|
}),
|
|
44064
44485
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
44065
44486
|
const startTime = performance.now();
|
|
44066
|
-
const absPath =
|
|
44487
|
+
const absPath = path41.resolve(rootPath);
|
|
44067
44488
|
try {
|
|
44068
|
-
const stat2 = await
|
|
44489
|
+
const stat2 = await fs38.stat(absPath);
|
|
44069
44490
|
if (!stat2.isDirectory()) {
|
|
44070
44491
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
44071
44492
|
tool: "codebase_map"
|
|
@@ -44102,14 +44523,14 @@ Examples:
|
|
|
44102
44523
|
let totalDefinitions = 0;
|
|
44103
44524
|
let exportedSymbols = 0;
|
|
44104
44525
|
for (const file of limitedFiles) {
|
|
44105
|
-
const fullPath =
|
|
44526
|
+
const fullPath = path41.join(absPath, file);
|
|
44106
44527
|
const language = detectLanguage3(file);
|
|
44107
44528
|
if (!language) continue;
|
|
44108
44529
|
if (languages && !languages.includes(language)) {
|
|
44109
44530
|
continue;
|
|
44110
44531
|
}
|
|
44111
44532
|
try {
|
|
44112
|
-
const content = await
|
|
44533
|
+
const content = await fs38.readFile(fullPath, "utf-8");
|
|
44113
44534
|
const lineCount = content.split("\n").length;
|
|
44114
44535
|
const parsed = parseFile(content, language);
|
|
44115
44536
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -44146,23 +44567,23 @@ var codebaseMapTools = [codebaseMapTool];
|
|
|
44146
44567
|
init_registry4();
|
|
44147
44568
|
init_errors();
|
|
44148
44569
|
init_paths();
|
|
44149
|
-
var
|
|
44150
|
-
var
|
|
44570
|
+
var fs39 = await import('fs/promises');
|
|
44571
|
+
var path42 = await import('path');
|
|
44151
44572
|
var crypto2 = await import('crypto');
|
|
44152
|
-
var GLOBAL_MEMORIES_DIR =
|
|
44573
|
+
var GLOBAL_MEMORIES_DIR = path42.join(COCO_HOME, "memories");
|
|
44153
44574
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
44154
44575
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
44155
44576
|
async function ensureDir2(dirPath) {
|
|
44156
|
-
await
|
|
44577
|
+
await fs39.mkdir(dirPath, { recursive: true });
|
|
44157
44578
|
}
|
|
44158
44579
|
function getMemoriesDir(scope) {
|
|
44159
44580
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
44160
44581
|
}
|
|
44161
44582
|
async function loadIndex(scope) {
|
|
44162
44583
|
const dir = getMemoriesDir(scope);
|
|
44163
|
-
const indexPath =
|
|
44584
|
+
const indexPath = path42.join(dir, "index.json");
|
|
44164
44585
|
try {
|
|
44165
|
-
const content = await
|
|
44586
|
+
const content = await fs39.readFile(indexPath, "utf-8");
|
|
44166
44587
|
return JSON.parse(content);
|
|
44167
44588
|
} catch {
|
|
44168
44589
|
return [];
|
|
@@ -44171,14 +44592,14 @@ async function loadIndex(scope) {
|
|
|
44171
44592
|
async function saveIndex(scope, index) {
|
|
44172
44593
|
const dir = getMemoriesDir(scope);
|
|
44173
44594
|
await ensureDir2(dir);
|
|
44174
|
-
const indexPath =
|
|
44175
|
-
await
|
|
44595
|
+
const indexPath = path42.join(dir, "index.json");
|
|
44596
|
+
await fs39.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
44176
44597
|
}
|
|
44177
44598
|
async function loadMemory(scope, id) {
|
|
44178
44599
|
const dir = getMemoriesDir(scope);
|
|
44179
|
-
const memPath =
|
|
44600
|
+
const memPath = path42.join(dir, `${id}.json`);
|
|
44180
44601
|
try {
|
|
44181
|
-
const content = await
|
|
44602
|
+
const content = await fs39.readFile(memPath, "utf-8");
|
|
44182
44603
|
return JSON.parse(content);
|
|
44183
44604
|
} catch {
|
|
44184
44605
|
return null;
|
|
@@ -44187,8 +44608,8 @@ async function loadMemory(scope, id) {
|
|
|
44187
44608
|
async function saveMemory(scope, memory) {
|
|
44188
44609
|
const dir = getMemoriesDir(scope);
|
|
44189
44610
|
await ensureDir2(dir);
|
|
44190
|
-
const memPath =
|
|
44191
|
-
await
|
|
44611
|
+
const memPath = path42.join(dir, `${memory.id}.json`);
|
|
44612
|
+
await fs39.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
44192
44613
|
}
|
|
44193
44614
|
var createMemoryTool = defineTool({
|
|
44194
44615
|
name: "create_memory",
|
|
@@ -44344,17 +44765,17 @@ var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
|
44344
44765
|
// src/tools/checkpoint.ts
|
|
44345
44766
|
init_registry4();
|
|
44346
44767
|
init_errors();
|
|
44347
|
-
var
|
|
44768
|
+
var fs40 = await import('fs/promises');
|
|
44348
44769
|
var crypto3 = await import('crypto');
|
|
44349
44770
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
44350
44771
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
44351
44772
|
var STASH_PREFIX = "coco-cp";
|
|
44352
44773
|
async function ensureCocoDir() {
|
|
44353
|
-
await
|
|
44774
|
+
await fs40.mkdir(".coco", { recursive: true });
|
|
44354
44775
|
}
|
|
44355
44776
|
async function loadCheckpoints() {
|
|
44356
44777
|
try {
|
|
44357
|
-
const content = await
|
|
44778
|
+
const content = await fs40.readFile(CHECKPOINT_FILE, "utf-8");
|
|
44358
44779
|
return JSON.parse(content);
|
|
44359
44780
|
} catch {
|
|
44360
44781
|
return [];
|
|
@@ -44362,7 +44783,7 @@ async function loadCheckpoints() {
|
|
|
44362
44783
|
}
|
|
44363
44784
|
async function saveCheckpoints(checkpoints) {
|
|
44364
44785
|
await ensureCocoDir();
|
|
44365
|
-
await
|
|
44786
|
+
await fs40.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
44366
44787
|
}
|
|
44367
44788
|
async function execGit(args) {
|
|
44368
44789
|
const { execaCommand } = await import('execa');
|
|
@@ -44527,8 +44948,8 @@ var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpoi
|
|
|
44527
44948
|
|
|
44528
44949
|
// src/tools/semantic-search.ts
|
|
44529
44950
|
init_registry4();
|
|
44530
|
-
var
|
|
44531
|
-
var
|
|
44951
|
+
var fs41 = await import('fs/promises');
|
|
44952
|
+
var path43 = await import('path');
|
|
44532
44953
|
var { glob: glob15 } = await import('glob');
|
|
44533
44954
|
var INDEX_DIR = ".coco/search-index";
|
|
44534
44955
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -44656,20 +45077,20 @@ async function getEmbedding(text13) {
|
|
|
44656
45077
|
}
|
|
44657
45078
|
async function loadIndex2(indexDir) {
|
|
44658
45079
|
try {
|
|
44659
|
-
const indexPath =
|
|
44660
|
-
const content = await
|
|
45080
|
+
const indexPath = path43.join(indexDir, "index.json");
|
|
45081
|
+
const content = await fs41.readFile(indexPath, "utf-8");
|
|
44661
45082
|
return JSON.parse(content);
|
|
44662
45083
|
} catch {
|
|
44663
45084
|
return null;
|
|
44664
45085
|
}
|
|
44665
45086
|
}
|
|
44666
45087
|
async function saveIndex2(indexDir, index) {
|
|
44667
|
-
await
|
|
44668
|
-
const indexPath =
|
|
44669
|
-
await
|
|
45088
|
+
await fs41.mkdir(indexDir, { recursive: true });
|
|
45089
|
+
const indexPath = path43.join(indexDir, "index.json");
|
|
45090
|
+
await fs41.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
44670
45091
|
}
|
|
44671
45092
|
function isBinary(filePath) {
|
|
44672
|
-
return BINARY_EXTENSIONS.has(
|
|
45093
|
+
return BINARY_EXTENSIONS.has(path43.extname(filePath).toLowerCase());
|
|
44673
45094
|
}
|
|
44674
45095
|
var semanticSearchTool = defineTool({
|
|
44675
45096
|
name: "semantic_search",
|
|
@@ -44694,8 +45115,8 @@ Examples:
|
|
|
44694
45115
|
const effectivePath = rootPath ?? ".";
|
|
44695
45116
|
const effectiveMaxResults = maxResults ?? 10;
|
|
44696
45117
|
const effectiveThreshold = threshold ?? 0.3;
|
|
44697
|
-
const absPath =
|
|
44698
|
-
const indexDir =
|
|
45118
|
+
const absPath = path43.resolve(effectivePath);
|
|
45119
|
+
const indexDir = path43.join(absPath, INDEX_DIR);
|
|
44699
45120
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
44700
45121
|
let warnings = [];
|
|
44701
45122
|
if (!index) {
|
|
@@ -44711,10 +45132,10 @@ Examples:
|
|
|
44711
45132
|
let indexSaveWarning = "";
|
|
44712
45133
|
for (const file of files) {
|
|
44713
45134
|
if (isBinary(file)) continue;
|
|
44714
|
-
const fullPath =
|
|
45135
|
+
const fullPath = path43.join(absPath, file);
|
|
44715
45136
|
try {
|
|
44716
|
-
const stat2 = await
|
|
44717
|
-
const content = await
|
|
45137
|
+
const stat2 = await fs41.stat(fullPath);
|
|
45138
|
+
const content = await fs41.readFile(fullPath, "utf-8");
|
|
44718
45139
|
if (content.length > 1e5) continue;
|
|
44719
45140
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
44720
45141
|
for (const chunk of fileChunks) {
|
|
@@ -44794,8 +45215,8 @@ var semanticSearchTools = [semanticSearchTool];
|
|
|
44794
45215
|
// src/tools/diagram.ts
|
|
44795
45216
|
init_registry4();
|
|
44796
45217
|
init_errors();
|
|
44797
|
-
var
|
|
44798
|
-
var
|
|
45218
|
+
var fs42 = await import('fs/promises');
|
|
45219
|
+
var path44 = await import('path');
|
|
44799
45220
|
var { glob: glob16 } = await import('glob');
|
|
44800
45221
|
async function parseClassRelationships(rootPath, include) {
|
|
44801
45222
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -44808,7 +45229,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
44808
45229
|
const interfaces = [];
|
|
44809
45230
|
for (const file of files.slice(0, 100)) {
|
|
44810
45231
|
try {
|
|
44811
|
-
const content = await
|
|
45232
|
+
const content = await fs42.readFile(path44.join(rootPath, file), "utf-8");
|
|
44812
45233
|
const lines = content.split("\n");
|
|
44813
45234
|
for (let i = 0; i < lines.length; i++) {
|
|
44814
45235
|
const line = lines[i];
|
|
@@ -44927,14 +45348,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
44927
45348
|
};
|
|
44928
45349
|
}
|
|
44929
45350
|
async function generateArchitectureDiagram(rootPath) {
|
|
44930
|
-
const entries = await
|
|
45351
|
+
const entries = await fs42.readdir(rootPath, { withFileTypes: true });
|
|
44931
45352
|
const dirs = entries.filter(
|
|
44932
45353
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
44933
45354
|
);
|
|
44934
45355
|
const lines = ["graph TD"];
|
|
44935
45356
|
let nodeCount = 0;
|
|
44936
45357
|
let edgeCount = 0;
|
|
44937
|
-
const rootName =
|
|
45358
|
+
const rootName = path44.basename(rootPath);
|
|
44938
45359
|
lines.push(` ROOT["${rootName}"]`);
|
|
44939
45360
|
nodeCount++;
|
|
44940
45361
|
for (const dir of dirs) {
|
|
@@ -44944,7 +45365,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
44944
45365
|
nodeCount++;
|
|
44945
45366
|
edgeCount++;
|
|
44946
45367
|
try {
|
|
44947
|
-
const subEntries = await
|
|
45368
|
+
const subEntries = await fs42.readdir(path44.join(rootPath, dir.name), {
|
|
44948
45369
|
withFileTypes: true
|
|
44949
45370
|
});
|
|
44950
45371
|
const subDirs = subEntries.filter(
|
|
@@ -45067,7 +45488,7 @@ Examples:
|
|
|
45067
45488
|
tool: "generate_diagram"
|
|
45068
45489
|
});
|
|
45069
45490
|
}
|
|
45070
|
-
const absPath = rootPath ?
|
|
45491
|
+
const absPath = rootPath ? path44.resolve(rootPath) : process.cwd();
|
|
45071
45492
|
switch (type) {
|
|
45072
45493
|
case "class":
|
|
45073
45494
|
return generateClassDiagram(absPath, include);
|
|
@@ -45132,8 +45553,8 @@ var diagramTools = [generateDiagramTool];
|
|
|
45132
45553
|
// src/tools/pdf.ts
|
|
45133
45554
|
init_registry4();
|
|
45134
45555
|
init_errors();
|
|
45135
|
-
var
|
|
45136
|
-
var
|
|
45556
|
+
var fs43 = await import('fs/promises');
|
|
45557
|
+
var path45 = await import('path');
|
|
45137
45558
|
var DEFAULT_MAX_PAGES = 20;
|
|
45138
45559
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
45139
45560
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -45168,9 +45589,9 @@ Examples:
|
|
|
45168
45589
|
}),
|
|
45169
45590
|
async execute({ path: filePath, pages, maxPages }) {
|
|
45170
45591
|
const startTime = performance.now();
|
|
45171
|
-
const absPath =
|
|
45592
|
+
const absPath = path45.resolve(filePath);
|
|
45172
45593
|
try {
|
|
45173
|
-
const stat2 = await
|
|
45594
|
+
const stat2 = await fs43.stat(absPath);
|
|
45174
45595
|
if (!stat2.isFile()) {
|
|
45175
45596
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
45176
45597
|
tool: "read_pdf"
|
|
@@ -45201,7 +45622,7 @@ Examples:
|
|
|
45201
45622
|
}
|
|
45202
45623
|
try {
|
|
45203
45624
|
const pdfParse = await import('pdf-parse');
|
|
45204
|
-
const dataBuffer = await
|
|
45625
|
+
const dataBuffer = await fs43.readFile(absPath);
|
|
45205
45626
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
45206
45627
|
max: maxPages
|
|
45207
45628
|
});
|
|
@@ -45252,8 +45673,8 @@ var pdfTools = [readPdfTool];
|
|
|
45252
45673
|
// src/tools/image.ts
|
|
45253
45674
|
init_registry4();
|
|
45254
45675
|
init_errors();
|
|
45255
|
-
var
|
|
45256
|
-
var
|
|
45676
|
+
var fs44 = await import('fs/promises');
|
|
45677
|
+
var path46 = await import('path');
|
|
45257
45678
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
45258
45679
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
45259
45680
|
var MIME_TYPES = {
|
|
@@ -45281,15 +45702,15 @@ Examples:
|
|
|
45281
45702
|
async execute({ path: filePath, prompt, provider }) {
|
|
45282
45703
|
const startTime = performance.now();
|
|
45283
45704
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
45284
|
-
const absPath =
|
|
45705
|
+
const absPath = path46.resolve(filePath);
|
|
45285
45706
|
const cwd = process.cwd();
|
|
45286
|
-
if (!absPath.startsWith(cwd +
|
|
45707
|
+
if (!absPath.startsWith(cwd + path46.sep) && absPath !== cwd) {
|
|
45287
45708
|
throw new ToolError(
|
|
45288
45709
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
45289
45710
|
{ tool: "read_image" }
|
|
45290
45711
|
);
|
|
45291
45712
|
}
|
|
45292
|
-
const ext =
|
|
45713
|
+
const ext = path46.extname(absPath).toLowerCase();
|
|
45293
45714
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
45294
45715
|
throw new ToolError(
|
|
45295
45716
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -45297,7 +45718,7 @@ Examples:
|
|
|
45297
45718
|
);
|
|
45298
45719
|
}
|
|
45299
45720
|
try {
|
|
45300
|
-
const stat2 = await
|
|
45721
|
+
const stat2 = await fs44.stat(absPath);
|
|
45301
45722
|
if (!stat2.isFile()) {
|
|
45302
45723
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
45303
45724
|
tool: "read_image"
|
|
@@ -45318,7 +45739,7 @@ Examples:
|
|
|
45318
45739
|
if (error instanceof ToolError) throw error;
|
|
45319
45740
|
throw error;
|
|
45320
45741
|
}
|
|
45321
|
-
const imageBuffer = await
|
|
45742
|
+
const imageBuffer = await fs44.readFile(absPath);
|
|
45322
45743
|
const base64 = imageBuffer.toString("base64");
|
|
45323
45744
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
45324
45745
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -45440,7 +45861,7 @@ var imageTools = [readImageTool];
|
|
|
45440
45861
|
// src/tools/database.ts
|
|
45441
45862
|
init_registry4();
|
|
45442
45863
|
init_errors();
|
|
45443
|
-
var
|
|
45864
|
+
var path47 = await import('path');
|
|
45444
45865
|
var DANGEROUS_PATTERNS = [
|
|
45445
45866
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
45446
45867
|
/\bTRUNCATE\b/i,
|
|
@@ -45471,7 +45892,7 @@ Examples:
|
|
|
45471
45892
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
45472
45893
|
const isReadonly = isReadonlyParam ?? true;
|
|
45473
45894
|
const startTime = performance.now();
|
|
45474
|
-
const absPath =
|
|
45895
|
+
const absPath = path47.resolve(database);
|
|
45475
45896
|
if (isReadonly && isDangerousSql(query)) {
|
|
45476
45897
|
throw new ToolError(
|
|
45477
45898
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -45554,7 +45975,7 @@ Examples:
|
|
|
45554
45975
|
}),
|
|
45555
45976
|
async execute({ database, table }) {
|
|
45556
45977
|
const startTime = performance.now();
|
|
45557
|
-
const absPath =
|
|
45978
|
+
const absPath = path47.resolve(database);
|
|
45558
45979
|
try {
|
|
45559
45980
|
const { default: Database } = await import('better-sqlite3');
|
|
45560
45981
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -45737,14 +46158,14 @@ var astValidatorTools = [validateCodeTool, findMissingImportsTool];
|
|
|
45737
46158
|
|
|
45738
46159
|
// src/tools/code-analyzer.ts
|
|
45739
46160
|
init_registry4();
|
|
45740
|
-
var
|
|
45741
|
-
var
|
|
46161
|
+
var fs45 = await import('fs/promises');
|
|
46162
|
+
var path48 = await import('path');
|
|
45742
46163
|
var AnalyzeFileSchema = z.object({
|
|
45743
46164
|
filePath: z.string().describe("Path to file to analyze"),
|
|
45744
46165
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
45745
46166
|
});
|
|
45746
46167
|
async function analyzeFile(filePath, includeAst = false) {
|
|
45747
|
-
const content = await
|
|
46168
|
+
const content = await fs45.readFile(filePath, "utf-8");
|
|
45748
46169
|
const lines = content.split("\n").length;
|
|
45749
46170
|
const functions = [];
|
|
45750
46171
|
const classes = [];
|
|
@@ -45848,10 +46269,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
45848
46269
|
try {
|
|
45849
46270
|
const analysis = await analyzeFile(file, false);
|
|
45850
46271
|
totalLines += analysis.lines;
|
|
45851
|
-
const ext =
|
|
46272
|
+
const ext = path48.extname(file);
|
|
45852
46273
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
45853
46274
|
fileStats.push({
|
|
45854
|
-
file:
|
|
46275
|
+
file: path48.relative(dirPath, file),
|
|
45855
46276
|
lines: analysis.lines,
|
|
45856
46277
|
complexity: analysis.complexity.cyclomatic
|
|
45857
46278
|
});
|
|
@@ -46222,13 +46643,13 @@ var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateRes
|
|
|
46222
46643
|
|
|
46223
46644
|
// src/tools/smart-suggestions.ts
|
|
46224
46645
|
init_registry4();
|
|
46225
|
-
var
|
|
46646
|
+
var fs46 = await import('fs/promises');
|
|
46226
46647
|
var SuggestImprovementsSchema = z.object({
|
|
46227
46648
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
46228
46649
|
context: z.string().optional().describe("Additional context about the code")
|
|
46229
46650
|
});
|
|
46230
46651
|
async function analyzeAndSuggest(filePath, _context) {
|
|
46231
|
-
const content = await
|
|
46652
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
46232
46653
|
const lines = content.split("\n");
|
|
46233
46654
|
const suggestions = [];
|
|
46234
46655
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -46320,7 +46741,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
46320
46741
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
46321
46742
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
46322
46743
|
try {
|
|
46323
|
-
await
|
|
46744
|
+
await fs46.access(testPath);
|
|
46324
46745
|
} catch {
|
|
46325
46746
|
suggestions.push({
|
|
46326
46747
|
type: "testing",
|
|
@@ -46377,7 +46798,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
46377
46798
|
async execute(input) {
|
|
46378
46799
|
const { filePath } = input;
|
|
46379
46800
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
46380
|
-
const content = await
|
|
46801
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
46381
46802
|
const lines = content.split("\n");
|
|
46382
46803
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
46383
46804
|
let score = 100;
|
|
@@ -46414,8 +46835,8 @@ var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
|
46414
46835
|
|
|
46415
46836
|
// src/tools/context-enhancer.ts
|
|
46416
46837
|
init_registry4();
|
|
46417
|
-
var
|
|
46418
|
-
var
|
|
46838
|
+
var fs47 = await import('fs/promises');
|
|
46839
|
+
var path49 = await import('path');
|
|
46419
46840
|
var ContextMemoryStore = class {
|
|
46420
46841
|
items = /* @__PURE__ */ new Map();
|
|
46421
46842
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -46427,7 +46848,7 @@ var ContextMemoryStore = class {
|
|
|
46427
46848
|
}
|
|
46428
46849
|
async load() {
|
|
46429
46850
|
try {
|
|
46430
|
-
const content = await
|
|
46851
|
+
const content = await fs47.readFile(this.storePath, "utf-8");
|
|
46431
46852
|
const data = JSON.parse(content);
|
|
46432
46853
|
this.items = new Map(Object.entries(data.items || {}));
|
|
46433
46854
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -46435,15 +46856,15 @@ var ContextMemoryStore = class {
|
|
|
46435
46856
|
}
|
|
46436
46857
|
}
|
|
46437
46858
|
async save() {
|
|
46438
|
-
const dir =
|
|
46439
|
-
await
|
|
46859
|
+
const dir = path49.dirname(this.storePath);
|
|
46860
|
+
await fs47.mkdir(dir, { recursive: true });
|
|
46440
46861
|
const data = {
|
|
46441
46862
|
sessionId: this.sessionId,
|
|
46442
46863
|
items: Object.fromEntries(this.items),
|
|
46443
46864
|
learnings: Object.fromEntries(this.learnings),
|
|
46444
46865
|
savedAt: Date.now()
|
|
46445
46866
|
};
|
|
46446
|
-
await
|
|
46867
|
+
await fs47.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
46447
46868
|
}
|
|
46448
46869
|
addContext(id, item) {
|
|
46449
46870
|
this.items.set(id, item);
|
|
@@ -46611,11 +47032,11 @@ var contextEnhancerTools = [
|
|
|
46611
47032
|
|
|
46612
47033
|
// src/tools/skill-enhancer.ts
|
|
46613
47034
|
init_registry4();
|
|
46614
|
-
var
|
|
46615
|
-
var
|
|
47035
|
+
var fs48 = await import('fs/promises');
|
|
47036
|
+
var path50 = await import('path');
|
|
46616
47037
|
async function discoverSkills(skillsDir) {
|
|
46617
47038
|
try {
|
|
46618
|
-
const files = await
|
|
47039
|
+
const files = await fs48.readdir(skillsDir);
|
|
46619
47040
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
46620
47041
|
} catch {
|
|
46621
47042
|
return [];
|
|
@@ -46623,12 +47044,12 @@ async function discoverSkills(skillsDir) {
|
|
|
46623
47044
|
}
|
|
46624
47045
|
async function loadSkillMetadata(skillPath) {
|
|
46625
47046
|
try {
|
|
46626
|
-
const content = await
|
|
47047
|
+
const content = await fs48.readFile(skillPath, "utf-8");
|
|
46627
47048
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
46628
47049
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
46629
47050
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
46630
47051
|
return {
|
|
46631
|
-
name: nameMatch?.[1] ||
|
|
47052
|
+
name: nameMatch?.[1] || path50.basename(skillPath, path50.extname(skillPath)),
|
|
46632
47053
|
description: descMatch?.[1] || "No description",
|
|
46633
47054
|
version: versionMatch?.[1] || "1.0.0",
|
|
46634
47055
|
dependencies: []
|
|
@@ -46672,7 +47093,7 @@ var discoverSkillsTool = defineTool({
|
|
|
46672
47093
|
const { skillsDir } = input;
|
|
46673
47094
|
const skills = await discoverSkills(skillsDir);
|
|
46674
47095
|
const metadata = await Promise.all(
|
|
46675
|
-
skills.map((s) => loadSkillMetadata(
|
|
47096
|
+
skills.map((s) => loadSkillMetadata(path50.join(skillsDir, s)))
|
|
46676
47097
|
);
|
|
46677
47098
|
return {
|
|
46678
47099
|
skillsDir,
|
|
@@ -46843,7 +47264,7 @@ Examples:
|
|
|
46843
47264
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
46844
47265
|
}),
|
|
46845
47266
|
async execute({ path: dirPath, reason }) {
|
|
46846
|
-
const absolute =
|
|
47267
|
+
const absolute = path38__default.resolve(dirPath);
|
|
46847
47268
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
46848
47269
|
return {
|
|
46849
47270
|
authorized: true,
|
|
@@ -46852,8 +47273,8 @@ Examples:
|
|
|
46852
47273
|
};
|
|
46853
47274
|
}
|
|
46854
47275
|
for (const blocked of BLOCKED_SYSTEM_PATHS2) {
|
|
46855
|
-
const normalizedBlocked =
|
|
46856
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
47276
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
47277
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
46857
47278
|
return {
|
|
46858
47279
|
authorized: false,
|
|
46859
47280
|
path: absolute,
|
|
@@ -46862,7 +47283,7 @@ Examples:
|
|
|
46862
47283
|
}
|
|
46863
47284
|
}
|
|
46864
47285
|
const cwd = process.cwd();
|
|
46865
|
-
if (absolute ===
|
|
47286
|
+
if (absolute === path38__default.normalize(cwd) || absolute.startsWith(path38__default.normalize(cwd) + path38__default.sep)) {
|
|
46866
47287
|
return {
|
|
46867
47288
|
authorized: true,
|
|
46868
47289
|
path: absolute,
|
|
@@ -46870,7 +47291,7 @@ Examples:
|
|
|
46870
47291
|
};
|
|
46871
47292
|
}
|
|
46872
47293
|
try {
|
|
46873
|
-
const stat2 = await
|
|
47294
|
+
const stat2 = await fs35__default.stat(absolute);
|
|
46874
47295
|
if (!stat2.isDirectory()) {
|
|
46875
47296
|
return {
|
|
46876
47297
|
authorized: false,
|
|
@@ -46886,7 +47307,7 @@ Examples:
|
|
|
46886
47307
|
};
|
|
46887
47308
|
}
|
|
46888
47309
|
const existing = getAllowedPaths();
|
|
46889
|
-
if (existing.some((e) =>
|
|
47310
|
+
if (existing.some((e) => path38__default.normalize(e.path) === path38__default.normalize(absolute))) {
|
|
46890
47311
|
return {
|
|
46891
47312
|
authorized: true,
|
|
46892
47313
|
path: absolute,
|
|
@@ -46971,9 +47392,9 @@ async function runSprints(options) {
|
|
|
46971
47392
|
Object.entries(AGENT_ROLES).map(([role, def]) => [role, { ...def, maxTurns: 20 }])
|
|
46972
47393
|
);
|
|
46973
47394
|
const coordinator = createAgentCoordinator(executor, agentDefsMap);
|
|
46974
|
-
await
|
|
46975
|
-
const sprintsDir =
|
|
46976
|
-
await
|
|
47395
|
+
await fs35__default.mkdir(spec.outputPath, { recursive: true });
|
|
47396
|
+
const sprintsDir = path38__default.join(spec.outputPath, ".coco", "sprints");
|
|
47397
|
+
await fs35__default.mkdir(sprintsDir, { recursive: true });
|
|
46977
47398
|
for (const sprint of spec.sprints) {
|
|
46978
47399
|
onProgress(`Starting ${sprint.id}: ${sprint.name}`);
|
|
46979
47400
|
const sprintStart = Date.now();
|
|
@@ -47226,8 +47647,8 @@ Assess: overall architecture, consistency, error handling, and production readin
|
|
|
47226
47647
|
};
|
|
47227
47648
|
}
|
|
47228
47649
|
async function saveSprintResult(sprintsDir, result) {
|
|
47229
|
-
const filePath =
|
|
47230
|
-
await
|
|
47650
|
+
const filePath = path38__default.join(sprintsDir, `${result.sprintId}.json`);
|
|
47651
|
+
await fs35__default.writeFile(filePath, JSON.stringify(result, null, 2), "utf-8");
|
|
47231
47652
|
}
|
|
47232
47653
|
|
|
47233
47654
|
// src/cli/repl/commands/build-app.ts
|
|
@@ -47252,9 +47673,9 @@ function parseArgs6(args) {
|
|
|
47252
47673
|
return { description, specFile, outputDir, skipConfirmation };
|
|
47253
47674
|
}
|
|
47254
47675
|
function isWithinRoot(resolvedPath, rootDir) {
|
|
47255
|
-
const normalRoot =
|
|
47256
|
-
const normalPath =
|
|
47257
|
-
return normalPath ===
|
|
47676
|
+
const normalRoot = path38__default.normalize(rootDir) + path38__default.sep;
|
|
47677
|
+
const normalPath = path38__default.normalize(resolvedPath);
|
|
47678
|
+
return normalPath === path38__default.normalize(rootDir) || normalPath.startsWith(normalRoot);
|
|
47258
47679
|
}
|
|
47259
47680
|
var buildAppCommand = {
|
|
47260
47681
|
name: "build-app",
|
|
@@ -47277,20 +47698,20 @@ var buildAppCommand = {
|
|
|
47277
47698
|
}
|
|
47278
47699
|
let initialDescription = parsed.description;
|
|
47279
47700
|
if (parsed.specFile) {
|
|
47280
|
-
const specPath =
|
|
47701
|
+
const specPath = path38__default.resolve(session.projectPath, parsed.specFile);
|
|
47281
47702
|
if (!isWithinRoot(specPath, session.projectPath)) {
|
|
47282
47703
|
p26.log.error(`--spec path must be within the project directory: ${specPath}`);
|
|
47283
47704
|
return false;
|
|
47284
47705
|
}
|
|
47285
47706
|
try {
|
|
47286
|
-
initialDescription = await
|
|
47707
|
+
initialDescription = await fs35__default.readFile(specPath, "utf-8");
|
|
47287
47708
|
} catch (err) {
|
|
47288
47709
|
const msg = err instanceof Error ? err.message : String(err);
|
|
47289
47710
|
p26.log.error(`Error reading spec file: ${msg}`);
|
|
47290
47711
|
return false;
|
|
47291
47712
|
}
|
|
47292
47713
|
}
|
|
47293
|
-
const outputPath = parsed.outputDir ?
|
|
47714
|
+
const outputPath = parsed.outputDir ? path38__default.resolve(session.projectPath, parsed.outputDir) : path38__default.join(session.projectPath, "build-app-output");
|
|
47294
47715
|
if (parsed.outputDir && !isWithinRoot(outputPath, session.projectPath)) {
|
|
47295
47716
|
p26.log.error(`--output path must be within the project directory: ${outputPath}`);
|
|
47296
47717
|
return false;
|
|
@@ -47454,7 +47875,7 @@ function buildProgressBar(pct) {
|
|
|
47454
47875
|
|
|
47455
47876
|
// src/cli/repl/worktree/manager.ts
|
|
47456
47877
|
init_logger();
|
|
47457
|
-
var
|
|
47878
|
+
var execFileAsync3 = promisify(execFile);
|
|
47458
47879
|
var WORKTREES_DIR = ".worktrees";
|
|
47459
47880
|
var WorktreeManager = class {
|
|
47460
47881
|
worktrees = /* @__PURE__ */ new Map();
|
|
@@ -47474,7 +47895,7 @@ var WorktreeManager = class {
|
|
|
47474
47895
|
const id = randomUUID();
|
|
47475
47896
|
const branchPrefix = options.branchPrefix ?? "coco-agent";
|
|
47476
47897
|
const branchName = `${branchPrefix}/${name}-${id.slice(0, 8)}`;
|
|
47477
|
-
const worktreePath =
|
|
47898
|
+
const worktreePath = path38__default.join(this.projectRoot, WORKTREES_DIR, `${name}-${id.slice(0, 8)}`);
|
|
47478
47899
|
const worktree = {
|
|
47479
47900
|
id,
|
|
47480
47901
|
name,
|
|
@@ -47485,7 +47906,7 @@ var WorktreeManager = class {
|
|
|
47485
47906
|
};
|
|
47486
47907
|
this.worktrees.set(id, worktree);
|
|
47487
47908
|
try {
|
|
47488
|
-
await
|
|
47909
|
+
await fs35__default.mkdir(path38__default.join(this.projectRoot, WORKTREES_DIR), { recursive: true });
|
|
47489
47910
|
const baseBranch = options.baseBranch ?? "HEAD";
|
|
47490
47911
|
await this.git(["worktree", "add", "-b", branchName, worktreePath, baseBranch]);
|
|
47491
47912
|
worktree.status = "active";
|
|
@@ -47678,7 +48099,7 @@ var WorktreeManager = class {
|
|
|
47678
48099
|
try {
|
|
47679
48100
|
await this.git(["push", "-u", "origin", worktree.branch]);
|
|
47680
48101
|
const title = options.message ?? `Agent: ${worktree.name}`;
|
|
47681
|
-
const { stdout } = await
|
|
48102
|
+
const { stdout } = await execFileAsync3(
|
|
47682
48103
|
"gh",
|
|
47683
48104
|
[
|
|
47684
48105
|
"pr",
|
|
@@ -47704,10 +48125,10 @@ var WorktreeManager = class {
|
|
|
47704
48125
|
}
|
|
47705
48126
|
// ── Helpers ──────────────────────────────────────────────────────
|
|
47706
48127
|
async git(args) {
|
|
47707
|
-
return
|
|
48128
|
+
return execFileAsync3("git", args, { cwd: this.projectRoot });
|
|
47708
48129
|
}
|
|
47709
48130
|
async gitIn(cwd, args) {
|
|
47710
|
-
return
|
|
48131
|
+
return execFileAsync3("git", args, { cwd });
|
|
47711
48132
|
}
|
|
47712
48133
|
async countChangedFiles(branch) {
|
|
47713
48134
|
try {
|
|
@@ -47732,7 +48153,7 @@ var DEFAULT_CONFIG5 = {
|
|
|
47732
48153
|
};
|
|
47733
48154
|
async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
47734
48155
|
const cfg = { ...DEFAULT_CONFIG5, ...config };
|
|
47735
|
-
const
|
|
48156
|
+
const logger2 = getLogger();
|
|
47736
48157
|
const startTime = Date.now();
|
|
47737
48158
|
if (cfg.attempts < 2) {
|
|
47738
48159
|
return {
|
|
@@ -47755,7 +48176,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47755
48176
|
const worktreeManager = new WorktreeManager(projectRoot);
|
|
47756
48177
|
const attempts = [];
|
|
47757
48178
|
try {
|
|
47758
|
-
|
|
48179
|
+
logger2.info(`Best-of-N: Creating ${cfg.attempts} worktrees...`);
|
|
47759
48180
|
const worktrees = await Promise.all(
|
|
47760
48181
|
Array.from(
|
|
47761
48182
|
{ length: cfg.attempts },
|
|
@@ -47779,7 +48200,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47779
48200
|
durationMs: 0
|
|
47780
48201
|
});
|
|
47781
48202
|
}
|
|
47782
|
-
|
|
48203
|
+
logger2.info(`Best-of-N: Running ${cfg.attempts} parallel attempts...`);
|
|
47783
48204
|
await Promise.all(
|
|
47784
48205
|
attempts.map(async (attempt) => {
|
|
47785
48206
|
const attemptStart = Date.now();
|
|
@@ -47833,7 +48254,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47833
48254
|
attempt.status = "discarded";
|
|
47834
48255
|
}
|
|
47835
48256
|
}
|
|
47836
|
-
|
|
48257
|
+
logger2.info(`Best-of-N: Winner is attempt #${winner.index} with score ${winner.score}`);
|
|
47837
48258
|
for (const attempt of attempts) {
|
|
47838
48259
|
if (attempt.id !== winner.id) {
|
|
47839
48260
|
try {
|
|
@@ -47848,7 +48269,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47848
48269
|
message: `Best-of-N winner (attempt #${winner.index}, score: ${winner.score})`
|
|
47849
48270
|
});
|
|
47850
48271
|
if (!mergeResult.success) {
|
|
47851
|
-
|
|
48272
|
+
logger2.warn(`Best-of-N: Auto-merge failed: ${mergeResult.error}`);
|
|
47852
48273
|
}
|
|
47853
48274
|
}
|
|
47854
48275
|
return {
|
|
@@ -48831,8 +49252,8 @@ function formatToolSummary(toolName, input) {
|
|
|
48831
49252
|
case "grep":
|
|
48832
49253
|
case "search_files": {
|
|
48833
49254
|
const pattern = String(input.pattern || "");
|
|
48834
|
-
const
|
|
48835
|
-
return `"${pattern}"${
|
|
49255
|
+
const path60 = input.path ? ` in ${input.path}` : "";
|
|
49256
|
+
return `"${pattern}"${path60}`;
|
|
48836
49257
|
}
|
|
48837
49258
|
case "bash_exec": {
|
|
48838
49259
|
const cmd = String(input.command || "");
|
|
@@ -48853,8 +49274,8 @@ function formatToolSummary(toolName, input) {
|
|
|
48853
49274
|
function formatUrl(url) {
|
|
48854
49275
|
try {
|
|
48855
49276
|
const u = new URL(url);
|
|
48856
|
-
const
|
|
48857
|
-
const display =
|
|
49277
|
+
const path60 = u.pathname.replace(/\/$/, "");
|
|
49278
|
+
const display = path60 ? `${u.hostname} \u203A ${path60.slice(1)}` : u.hostname;
|
|
48858
49279
|
const max = Math.max(getTerminalWidth2() - 20, 50);
|
|
48859
49280
|
return display.length > max ? display.slice(0, max - 1) + "\u2026" : display;
|
|
48860
49281
|
} catch {
|
|
@@ -49084,7 +49505,7 @@ function getAllCommands() {
|
|
|
49084
49505
|
}
|
|
49085
49506
|
|
|
49086
49507
|
// src/cli/repl/input/handler.ts
|
|
49087
|
-
var HISTORY_FILE =
|
|
49508
|
+
var HISTORY_FILE = path38.join(os4.homedir(), ".coco", "history");
|
|
49088
49509
|
async function handleOptionC(copyFn = copyToClipboard, getLastBlockFn = getLastBlock) {
|
|
49089
49510
|
const block = getLastBlockFn();
|
|
49090
49511
|
if (!block) return null;
|
|
@@ -49105,7 +49526,7 @@ function loadHistory() {
|
|
|
49105
49526
|
}
|
|
49106
49527
|
function saveHistory(history) {
|
|
49107
49528
|
try {
|
|
49108
|
-
const dir =
|
|
49529
|
+
const dir = path38.dirname(HISTORY_FILE);
|
|
49109
49530
|
if (!fs5.existsSync(dir)) {
|
|
49110
49531
|
fs5.mkdirSync(dir, { recursive: true });
|
|
49111
49532
|
}
|
|
@@ -50459,7 +50880,7 @@ function formatDiffPreview(toolCall) {
|
|
|
50459
50880
|
}
|
|
50460
50881
|
async function checkFileExists(filePath) {
|
|
50461
50882
|
try {
|
|
50462
|
-
await
|
|
50883
|
+
await fs35__default.access(filePath);
|
|
50463
50884
|
return true;
|
|
50464
50885
|
} catch {
|
|
50465
50886
|
return false;
|
|
@@ -52256,7 +52677,7 @@ function formatContextUsage(percent) {
|
|
|
52256
52677
|
}
|
|
52257
52678
|
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
52258
52679
|
const parts = [];
|
|
52259
|
-
const projectName =
|
|
52680
|
+
const projectName = path38__default.basename(projectPath);
|
|
52260
52681
|
parts.push(chalk.dim("\u{1F4C1} ") + chalk.magenta(projectName));
|
|
52261
52682
|
const providerName = config.provider.type;
|
|
52262
52683
|
const modelName = config.provider.model || "default";
|
|
@@ -52361,13 +52782,13 @@ async function startRepl(options = {}) {
|
|
|
52361
52782
|
}
|
|
52362
52783
|
await session.skillRegistry.discoverAndRegister(projectPath, getBuiltinSkillsForDiscovery2());
|
|
52363
52784
|
} catch (skillError) {
|
|
52364
|
-
const
|
|
52365
|
-
|
|
52785
|
+
const logger3 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
52786
|
+
logger3.warn(
|
|
52366
52787
|
`[Skills] Failed to initialize skills: ${skillError instanceof Error ? skillError.message : String(skillError)}`
|
|
52367
52788
|
);
|
|
52368
52789
|
}
|
|
52369
52790
|
let mcpManager = null;
|
|
52370
|
-
const
|
|
52791
|
+
const logger2 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
52371
52792
|
try {
|
|
52372
52793
|
const { getMCPServerManager: getMCPServerManager2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
|
|
52373
52794
|
const { MCPRegistryImpl: MCPRegistryImpl2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
@@ -52387,7 +52808,7 @@ async function startRepl(options = {}) {
|
|
|
52387
52808
|
try {
|
|
52388
52809
|
connections = await mcpManager.startAll(enabledServers);
|
|
52389
52810
|
} catch (startError) {
|
|
52390
|
-
|
|
52811
|
+
logger2.warn(
|
|
52391
52812
|
`[MCP] Failed to start servers: ${startError instanceof Error ? startError.message : String(startError)}`
|
|
52392
52813
|
);
|
|
52393
52814
|
try {
|
|
@@ -52401,18 +52822,18 @@ async function startRepl(options = {}) {
|
|
|
52401
52822
|
try {
|
|
52402
52823
|
await registerMCPTools2(toolRegistry, connection.name, connection.client);
|
|
52403
52824
|
} catch (toolError) {
|
|
52404
|
-
|
|
52825
|
+
logger2.warn(
|
|
52405
52826
|
`[MCP] Failed to register tools for server '${connection.name}': ${toolError instanceof Error ? toolError.message : String(toolError)}`
|
|
52406
52827
|
);
|
|
52407
52828
|
}
|
|
52408
52829
|
}
|
|
52409
52830
|
const activeCount = connections.size;
|
|
52410
52831
|
if (activeCount > 0) {
|
|
52411
|
-
|
|
52832
|
+
logger2.info(`[MCP] ${activeCount} MCP server(s) active`);
|
|
52412
52833
|
}
|
|
52413
52834
|
}
|
|
52414
52835
|
} catch (mcpError) {
|
|
52415
|
-
|
|
52836
|
+
logger2.warn(
|
|
52416
52837
|
`[MCP] Initialization failed: ${mcpError instanceof Error ? mcpError.message : String(mcpError)}`
|
|
52417
52838
|
);
|
|
52418
52839
|
}
|
|
@@ -52426,12 +52847,12 @@ async function startRepl(options = {}) {
|
|
|
52426
52847
|
if (registry.size > 0) {
|
|
52427
52848
|
hookRegistry = registry;
|
|
52428
52849
|
hookExecutor = createHookExecutor2();
|
|
52429
|
-
|
|
52850
|
+
logger2.info(`[Hooks] Loaded ${registry.size} hook(s) from ${hooksConfigPath}`);
|
|
52430
52851
|
}
|
|
52431
52852
|
} catch (hookError) {
|
|
52432
52853
|
const msg = hookError instanceof Error ? hookError.message : String(hookError);
|
|
52433
52854
|
if (!msg.includes("ENOENT")) {
|
|
52434
|
-
|
|
52855
|
+
logger2.warn(`[Hooks] Failed to load hooks: ${msg}`);
|
|
52435
52856
|
}
|
|
52436
52857
|
}
|
|
52437
52858
|
const inputHandler = createInputHandler();
|