@corbat-tech/coco 2.25.0 → 2.25.1
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 +1123 -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,360 @@ 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
|
+
try {
|
|
20890
|
+
if (process.platform === "darwin") {
|
|
20891
|
+
await execFileAsync2("open", [safeUrl]);
|
|
20892
|
+
} else if (process.platform === "win32") {
|
|
20893
|
+
await execFileAsync2("rundll32", ["url.dll,FileProtocolHandler", safeUrl]);
|
|
20894
|
+
} else {
|
|
20895
|
+
await execFileAsync2("xdg-open", [safeUrl]);
|
|
20896
|
+
}
|
|
20897
|
+
return true;
|
|
20898
|
+
} catch {
|
|
20899
|
+
return false;
|
|
20900
|
+
}
|
|
20901
|
+
}
|
|
20902
|
+
function maskUrlForLogs(rawUrl) {
|
|
20903
|
+
try {
|
|
20904
|
+
const url = new URL(rawUrl);
|
|
20905
|
+
url.search = "";
|
|
20906
|
+
url.hash = "";
|
|
20907
|
+
return url.toString();
|
|
20908
|
+
} catch {
|
|
20909
|
+
return "[invalid-url]";
|
|
20910
|
+
}
|
|
20911
|
+
}
|
|
20912
|
+
function parseResourceMetadataUrl(wwwAuthenticateHeader) {
|
|
20913
|
+
if (!wwwAuthenticateHeader) return void 0;
|
|
20914
|
+
const match = wwwAuthenticateHeader.match(/resource_metadata="([^"]+)"/i);
|
|
20915
|
+
return match?.[1];
|
|
20916
|
+
}
|
|
20917
|
+
function createProtectedMetadataCandidates(resourceUrl, headerUrl) {
|
|
20918
|
+
const candidates = [];
|
|
20919
|
+
if (headerUrl) {
|
|
20920
|
+
candidates.push(headerUrl);
|
|
20921
|
+
}
|
|
20922
|
+
const resource = new URL(resourceUrl);
|
|
20923
|
+
const origin = `${resource.protocol}//${resource.host}`;
|
|
20924
|
+
const pathPart = resource.pathname.replace(/\/+$/, "");
|
|
20925
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource`);
|
|
20926
|
+
if (pathPart && pathPart !== "/") {
|
|
20927
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource${pathPart}`);
|
|
20928
|
+
candidates.push(`${origin}/.well-known/oauth-protected-resource/${pathPart.replace(/^\//, "")}`);
|
|
20929
|
+
}
|
|
20930
|
+
return Array.from(new Set(candidates));
|
|
20931
|
+
}
|
|
20932
|
+
async function fetchJson(url) {
|
|
20933
|
+
const res = await fetch(url, { method: "GET", headers: { Accept: "application/json" } });
|
|
20934
|
+
if (!res.ok) {
|
|
20935
|
+
throw new Error(`HTTP ${res.status} while fetching ${url}`);
|
|
20936
|
+
}
|
|
20937
|
+
return await res.json();
|
|
20938
|
+
}
|
|
20939
|
+
function buildAuthorizationMetadataCandidates(issuer) {
|
|
20940
|
+
const parsed = new URL(issuer);
|
|
20941
|
+
const base = `${parsed.protocol}//${parsed.host}`;
|
|
20942
|
+
const issuerPath = parsed.pathname === "/" ? "" : parsed.pathname.replace(/\/+$/, "");
|
|
20943
|
+
const candidates = [
|
|
20944
|
+
`${base}/.well-known/oauth-authorization-server${issuerPath}`,
|
|
20945
|
+
`${base}/.well-known/oauth-authorization-server`,
|
|
20946
|
+
`${base}/.well-known/openid-configuration${issuerPath}`,
|
|
20947
|
+
`${base}/.well-known/openid-configuration`
|
|
20948
|
+
];
|
|
20949
|
+
return Array.from(new Set(candidates));
|
|
20950
|
+
}
|
|
20951
|
+
async function discoverProtectedResourceMetadata(resourceUrl, wwwAuthenticateHeader) {
|
|
20952
|
+
const headerUrl = parseResourceMetadataUrl(wwwAuthenticateHeader);
|
|
20953
|
+
const candidates = createProtectedMetadataCandidates(resourceUrl, headerUrl);
|
|
20954
|
+
for (const candidate of candidates) {
|
|
20955
|
+
try {
|
|
20956
|
+
const metadata = await fetchJson(candidate);
|
|
20957
|
+
if (Array.isArray(metadata.authorization_servers) && metadata.authorization_servers.length > 0) {
|
|
20958
|
+
return metadata;
|
|
20959
|
+
}
|
|
20960
|
+
} catch {
|
|
20961
|
+
}
|
|
20962
|
+
}
|
|
20963
|
+
throw new Error("Could not discover OAuth protected resource metadata for MCP server");
|
|
20964
|
+
}
|
|
20965
|
+
async function discoverAuthorizationServerMetadata(authorizationServer) {
|
|
20966
|
+
const candidates = buildAuthorizationMetadataCandidates(authorizationServer);
|
|
20967
|
+
for (const candidate of candidates) {
|
|
20968
|
+
try {
|
|
20969
|
+
const metadata = await fetchJson(candidate);
|
|
20970
|
+
if (metadata.authorization_endpoint && metadata.token_endpoint) {
|
|
20971
|
+
return metadata;
|
|
20972
|
+
}
|
|
20973
|
+
} catch {
|
|
20974
|
+
}
|
|
20975
|
+
}
|
|
20976
|
+
throw new Error("Could not discover OAuth authorization server metadata");
|
|
20977
|
+
}
|
|
20978
|
+
async function ensureClientId(authorizationMetadata, authorizationServer, redirectUri) {
|
|
20979
|
+
const store = await loadStore2();
|
|
20980
|
+
const clientKey = `${authorizationServer}|${redirectUri}`;
|
|
20981
|
+
const existing = store.clients[clientKey]?.clientId;
|
|
20982
|
+
if (existing) return existing;
|
|
20983
|
+
const registrationEndpoint = authorizationMetadata.registration_endpoint;
|
|
20984
|
+
if (!registrationEndpoint) {
|
|
20985
|
+
throw new Error(
|
|
20986
|
+
"Authorization server does not expose dynamic client registration; configure a static OAuth client ID for this MCP server."
|
|
20987
|
+
);
|
|
20988
|
+
}
|
|
20989
|
+
const registrationPayload = {
|
|
20990
|
+
client_name: "corbat-coco-mcp",
|
|
20991
|
+
redirect_uris: [redirectUri],
|
|
20992
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
20993
|
+
response_types: ["code"],
|
|
20994
|
+
token_endpoint_auth_method: "none"
|
|
20995
|
+
};
|
|
20996
|
+
const response = await fetch(registrationEndpoint, {
|
|
20997
|
+
method: "POST",
|
|
20998
|
+
headers: {
|
|
20999
|
+
"Content-Type": "application/json",
|
|
21000
|
+
Accept: "application/json"
|
|
21001
|
+
},
|
|
21002
|
+
body: JSON.stringify(registrationPayload)
|
|
21003
|
+
});
|
|
21004
|
+
if (!response.ok) {
|
|
21005
|
+
throw new Error(`Dynamic client registration failed: HTTP ${response.status}`);
|
|
21006
|
+
}
|
|
21007
|
+
const data = await response.json();
|
|
21008
|
+
const clientId = data.client_id;
|
|
21009
|
+
if (!clientId) {
|
|
21010
|
+
throw new Error("Dynamic client registration did not return client_id");
|
|
21011
|
+
}
|
|
21012
|
+
store.clients[clientKey] = { clientId };
|
|
21013
|
+
await saveStore2(store);
|
|
21014
|
+
return clientId;
|
|
21015
|
+
}
|
|
21016
|
+
async function refreshAccessToken2(params) {
|
|
21017
|
+
const body = new URLSearchParams({
|
|
21018
|
+
grant_type: "refresh_token",
|
|
21019
|
+
client_id: params.clientId,
|
|
21020
|
+
refresh_token: params.refreshToken,
|
|
21021
|
+
resource: params.resource
|
|
21022
|
+
});
|
|
21023
|
+
const response = await fetch(params.tokenEndpoint, {
|
|
21024
|
+
method: "POST",
|
|
21025
|
+
headers: {
|
|
21026
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
21027
|
+
Accept: "application/json"
|
|
21028
|
+
},
|
|
21029
|
+
body: body.toString()
|
|
21030
|
+
});
|
|
21031
|
+
if (!response.ok) {
|
|
21032
|
+
throw new Error(`Refresh token exchange failed: HTTP ${response.status}`);
|
|
21033
|
+
}
|
|
21034
|
+
const tokenResponse = await response.json();
|
|
21035
|
+
if (!tokenResponse.access_token) {
|
|
21036
|
+
throw new Error("Refresh token response missing access_token");
|
|
21037
|
+
}
|
|
21038
|
+
return tokenResponse;
|
|
21039
|
+
}
|
|
21040
|
+
async function exchangeCodeForToken(tokenEndpoint, clientId, code, codeVerifier, redirectUri, resource) {
|
|
21041
|
+
const body = new URLSearchParams({
|
|
21042
|
+
grant_type: "authorization_code",
|
|
21043
|
+
code,
|
|
21044
|
+
client_id: clientId,
|
|
21045
|
+
redirect_uri: redirectUri,
|
|
21046
|
+
code_verifier: codeVerifier,
|
|
21047
|
+
resource
|
|
21048
|
+
});
|
|
21049
|
+
const response = await fetch(tokenEndpoint, {
|
|
21050
|
+
method: "POST",
|
|
21051
|
+
headers: {
|
|
21052
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
21053
|
+
Accept: "application/json"
|
|
21054
|
+
},
|
|
21055
|
+
body: body.toString()
|
|
21056
|
+
});
|
|
21057
|
+
if (!response.ok) {
|
|
21058
|
+
throw new Error(`Token exchange failed: HTTP ${response.status}`);
|
|
21059
|
+
}
|
|
21060
|
+
const tokenResponse = await response.json();
|
|
21061
|
+
if (!tokenResponse.access_token) {
|
|
21062
|
+
throw new Error("Token exchange response missing access_token");
|
|
21063
|
+
}
|
|
21064
|
+
return tokenResponse;
|
|
21065
|
+
}
|
|
21066
|
+
async function persistToken(resourceUrl, token, metadata) {
|
|
21067
|
+
const store = await loadStore2();
|
|
21068
|
+
const expiresAt = typeof token.expires_in === "number" ? Date.now() + Math.max(0, token.expires_in) * 1e3 : void 0;
|
|
21069
|
+
store.tokens[getResourceKey(resourceUrl)] = {
|
|
21070
|
+
accessToken: token.access_token,
|
|
21071
|
+
tokenType: token.token_type,
|
|
21072
|
+
refreshToken: token.refresh_token,
|
|
21073
|
+
authorizationServer: metadata?.authorizationServer,
|
|
21074
|
+
clientId: metadata?.clientId,
|
|
21075
|
+
resource: canonicalizeResourceUrl(resourceUrl),
|
|
21076
|
+
...expiresAt ? { expiresAt } : {}
|
|
21077
|
+
};
|
|
21078
|
+
await saveStore2(store);
|
|
21079
|
+
}
|
|
21080
|
+
async function authenticateMcpOAuth(params) {
|
|
21081
|
+
const resource = canonicalizeResourceUrl(params.resourceUrl);
|
|
21082
|
+
const store = await loadStore2();
|
|
21083
|
+
const stored = store.tokens[getResourceKey(resource)];
|
|
21084
|
+
if (stored && !isTokenExpired2(stored)) {
|
|
21085
|
+
return stored.accessToken;
|
|
21086
|
+
}
|
|
21087
|
+
if (!process.stdout.isTTY) {
|
|
21088
|
+
throw new Error(
|
|
21089
|
+
`MCP server '${params.serverName}' requires interactive OAuth in a TTY session. Run Coco in a terminal to authenticate.`
|
|
21090
|
+
);
|
|
21091
|
+
}
|
|
21092
|
+
const protectedMetadata = await discoverProtectedResourceMetadata(
|
|
21093
|
+
resource,
|
|
21094
|
+
params.wwwAuthenticateHeader
|
|
21095
|
+
);
|
|
21096
|
+
const authorizationServer = protectedMetadata.authorization_servers?.[0];
|
|
21097
|
+
if (!authorizationServer) {
|
|
21098
|
+
throw new Error("Protected resource metadata does not include authorization_servers");
|
|
21099
|
+
}
|
|
21100
|
+
const authorizationMetadata = await discoverAuthorizationServerMetadata(authorizationServer);
|
|
21101
|
+
if (stored && isTokenExpired2(stored) && stored.refreshToken && stored.clientId) {
|
|
21102
|
+
try {
|
|
21103
|
+
const refreshed = await refreshAccessToken2({
|
|
21104
|
+
tokenEndpoint: authorizationMetadata.token_endpoint,
|
|
21105
|
+
clientId: stored.clientId,
|
|
21106
|
+
refreshToken: stored.refreshToken,
|
|
21107
|
+
resource
|
|
21108
|
+
});
|
|
21109
|
+
await persistToken(resource, refreshed, {
|
|
21110
|
+
authorizationServer,
|
|
21111
|
+
clientId: stored.clientId
|
|
21112
|
+
});
|
|
21113
|
+
return refreshed.access_token;
|
|
21114
|
+
} catch {
|
|
21115
|
+
}
|
|
21116
|
+
}
|
|
21117
|
+
const codeVerifier = createCodeVerifier();
|
|
21118
|
+
const codeChallenge = createCodeChallenge(codeVerifier);
|
|
21119
|
+
const state = createState();
|
|
21120
|
+
const { port, resultPromise } = await createCallbackServer(
|
|
21121
|
+
state,
|
|
21122
|
+
OAUTH_TIMEOUT_MS,
|
|
21123
|
+
OAUTH_CALLBACK_PORT
|
|
21124
|
+
);
|
|
21125
|
+
const redirectUri = `http://localhost:${port}/auth/callback`;
|
|
21126
|
+
const clientId = await ensureClientId(authorizationMetadata, authorizationServer, redirectUri);
|
|
21127
|
+
const authUrl = new URL(authorizationMetadata.authorization_endpoint);
|
|
21128
|
+
authUrl.searchParams.set("response_type", "code");
|
|
21129
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
21130
|
+
authUrl.searchParams.set("redirect_uri", redirectUri);
|
|
21131
|
+
authUrl.searchParams.set("state", state);
|
|
21132
|
+
authUrl.searchParams.set("code_challenge", codeChallenge);
|
|
21133
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
21134
|
+
authUrl.searchParams.set("resource", resource);
|
|
21135
|
+
if (authorizationMetadata.scopes_supported?.includes("offline_access")) {
|
|
21136
|
+
authUrl.searchParams.set("scope", "offline_access");
|
|
21137
|
+
}
|
|
21138
|
+
const opened = await openBrowser2(authUrl.toString());
|
|
21139
|
+
if (!opened) {
|
|
21140
|
+
logger.warn(`[MCP OAuth] Could not open browser automatically for '${params.serverName}'`);
|
|
21141
|
+
logger.warn(`[MCP OAuth] Manual auth URL base: ${maskUrlForLogs(authUrl.toString())}`);
|
|
21142
|
+
console.log(`[MCP OAuth] Open this URL manually: ${authUrl.toString()}`);
|
|
21143
|
+
} else {
|
|
21144
|
+
logger.info(
|
|
21145
|
+
`[MCP OAuth] Opened browser for '${params.serverName}'. Complete login to continue.`
|
|
21146
|
+
);
|
|
21147
|
+
}
|
|
21148
|
+
const callback = await resultPromise;
|
|
21149
|
+
const token = await exchangeCodeForToken(
|
|
21150
|
+
authorizationMetadata.token_endpoint,
|
|
21151
|
+
clientId,
|
|
21152
|
+
callback.code,
|
|
21153
|
+
codeVerifier,
|
|
21154
|
+
redirectUri,
|
|
21155
|
+
resource
|
|
21156
|
+
);
|
|
21157
|
+
await persistToken(resource, token, { authorizationServer, clientId });
|
|
21158
|
+
return token.access_token;
|
|
21159
|
+
}
|
|
21160
|
+
var execFileAsync2, TOKEN_STORE_PATH, OAUTH_TIMEOUT_MS, logger;
|
|
21161
|
+
var init_oauth2 = __esm({
|
|
21162
|
+
"src/mcp/oauth.ts"() {
|
|
21163
|
+
init_callback_server();
|
|
21164
|
+
init_paths();
|
|
21165
|
+
init_logger();
|
|
21166
|
+
execFileAsync2 = promisify(execFile);
|
|
21167
|
+
TOKEN_STORE_PATH = path38__default.join(CONFIG_PATHS.tokens, "mcp-oauth.json");
|
|
21168
|
+
OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
21169
|
+
logger = getLogger();
|
|
21170
|
+
}
|
|
21171
|
+
});
|
|
20825
21172
|
|
|
20826
21173
|
// src/mcp/transport/http.ts
|
|
20827
21174
|
var HTTPTransport;
|
|
20828
21175
|
var init_http = __esm({
|
|
20829
21176
|
"src/mcp/transport/http.ts"() {
|
|
20830
21177
|
init_errors2();
|
|
21178
|
+
init_oauth2();
|
|
20831
21179
|
init_errors2();
|
|
20832
21180
|
HTTPTransport = class {
|
|
20833
21181
|
constructor(config) {
|
|
@@ -20845,10 +21193,15 @@ var init_http = __esm({
|
|
|
20845
21193
|
connected = false;
|
|
20846
21194
|
abortController = null;
|
|
20847
21195
|
pendingRequests = /* @__PURE__ */ new Map();
|
|
21196
|
+
oauthToken;
|
|
21197
|
+
oauthInFlight = null;
|
|
20848
21198
|
/**
|
|
20849
21199
|
* Get authentication token
|
|
20850
21200
|
*/
|
|
20851
21201
|
getAuthToken() {
|
|
21202
|
+
if (this.oauthToken) {
|
|
21203
|
+
return this.oauthToken;
|
|
21204
|
+
}
|
|
20852
21205
|
if (!this.config.auth) return void 0;
|
|
20853
21206
|
if (this.config.auth.token) {
|
|
20854
21207
|
return this.config.auth.token;
|
|
@@ -20867,22 +21220,61 @@ var init_http = __esm({
|
|
|
20867
21220
|
Accept: "application/json",
|
|
20868
21221
|
...this.config.headers
|
|
20869
21222
|
};
|
|
21223
|
+
if (this.oauthToken) {
|
|
21224
|
+
headers["Authorization"] = `Bearer ${this.oauthToken}`;
|
|
21225
|
+
return headers;
|
|
21226
|
+
}
|
|
20870
21227
|
const token = this.getAuthToken();
|
|
20871
21228
|
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;
|
|
21229
|
+
if (this.config.auth.type === "apikey") {
|
|
21230
|
+
headers[this.config.auth.headerName || "X-API-Key"] = token;
|
|
21231
|
+
} else {
|
|
21232
|
+
headers["Authorization"] = `Bearer ${token}`;
|
|
20882
21233
|
}
|
|
20883
21234
|
}
|
|
20884
21235
|
return headers;
|
|
20885
21236
|
}
|
|
21237
|
+
shouldAttemptOAuth() {
|
|
21238
|
+
if (this.config.auth?.type === "apikey" || this.config.auth?.type === "bearer") {
|
|
21239
|
+
return false;
|
|
21240
|
+
}
|
|
21241
|
+
return true;
|
|
21242
|
+
}
|
|
21243
|
+
async ensureOAuthToken(wwwAuthenticateHeader) {
|
|
21244
|
+
if (this.oauthToken) {
|
|
21245
|
+
return this.oauthToken;
|
|
21246
|
+
}
|
|
21247
|
+
if (this.oauthInFlight) {
|
|
21248
|
+
return this.oauthInFlight;
|
|
21249
|
+
}
|
|
21250
|
+
const serverName = this.config.name ?? this.config.url;
|
|
21251
|
+
this.oauthInFlight = authenticateMcpOAuth({
|
|
21252
|
+
serverName,
|
|
21253
|
+
resourceUrl: this.config.url,
|
|
21254
|
+
wwwAuthenticateHeader
|
|
21255
|
+
}).then((token) => {
|
|
21256
|
+
this.oauthToken = token;
|
|
21257
|
+
return token;
|
|
21258
|
+
}).finally(() => {
|
|
21259
|
+
this.oauthInFlight = null;
|
|
21260
|
+
});
|
|
21261
|
+
return this.oauthInFlight;
|
|
21262
|
+
}
|
|
21263
|
+
async sendRequestWithOAuthRetry(method, body, signal) {
|
|
21264
|
+
const doFetch = async () => fetch(this.config.url, {
|
|
21265
|
+
method,
|
|
21266
|
+
headers: this.buildHeaders(),
|
|
21267
|
+
...body ? { body } : {},
|
|
21268
|
+
signal
|
|
21269
|
+
});
|
|
21270
|
+
let response = await doFetch();
|
|
21271
|
+
if (response.status !== 401 || !this.shouldAttemptOAuth()) {
|
|
21272
|
+
return response;
|
|
21273
|
+
}
|
|
21274
|
+
await this.ensureOAuthToken(response.headers.get("www-authenticate"));
|
|
21275
|
+
response = await doFetch();
|
|
21276
|
+
return response;
|
|
21277
|
+
}
|
|
20886
21278
|
/**
|
|
20887
21279
|
* Connect to the HTTP transport
|
|
20888
21280
|
*/
|
|
@@ -20897,11 +21289,14 @@ var init_http = __esm({
|
|
|
20897
21289
|
}
|
|
20898
21290
|
try {
|
|
20899
21291
|
this.abortController = new AbortController();
|
|
20900
|
-
|
|
20901
|
-
|
|
20902
|
-
|
|
20903
|
-
|
|
20904
|
-
|
|
21292
|
+
if (this.shouldAttemptOAuth()) {
|
|
21293
|
+
this.oauthToken = await getStoredMcpOAuthToken(this.config.url);
|
|
21294
|
+
}
|
|
21295
|
+
const response = await this.sendRequestWithOAuthRetry(
|
|
21296
|
+
"GET",
|
|
21297
|
+
void 0,
|
|
21298
|
+
this.abortController.signal
|
|
21299
|
+
);
|
|
20905
21300
|
if (!response.ok && response.status !== 404) {
|
|
20906
21301
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
20907
21302
|
}
|
|
@@ -20933,12 +21328,11 @@ var init_http = __esm({
|
|
|
20933
21328
|
const timeoutId = setTimeout(() => {
|
|
20934
21329
|
abortController.abort();
|
|
20935
21330
|
}, this.config.timeout);
|
|
20936
|
-
const response = await
|
|
20937
|
-
|
|
20938
|
-
|
|
20939
|
-
|
|
20940
|
-
|
|
20941
|
-
});
|
|
21331
|
+
const response = await this.sendRequestWithOAuthRetry(
|
|
21332
|
+
"POST",
|
|
21333
|
+
JSON.stringify(message),
|
|
21334
|
+
abortController.signal
|
|
21335
|
+
);
|
|
20942
21336
|
clearTimeout(timeoutId);
|
|
20943
21337
|
if (!response.ok) {
|
|
20944
21338
|
throw new MCPTransportError(`HTTP error ${response.status}: ${response.statusText}`);
|
|
@@ -21314,6 +21708,7 @@ var init_lifecycle = __esm({
|
|
|
21314
21708
|
throw new MCPConnectionError(`Server '${config.name}' requires http.url`);
|
|
21315
21709
|
}
|
|
21316
21710
|
return new HTTPTransport({
|
|
21711
|
+
name: config.name,
|
|
21317
21712
|
url: config.http.url,
|
|
21318
21713
|
headers: config.http.headers,
|
|
21319
21714
|
auth: config.http.auth
|
|
@@ -21530,7 +21925,7 @@ function shouldFullPowerApprove(command) {
|
|
|
21530
21925
|
}
|
|
21531
21926
|
async function loadFullPowerRiskPreference() {
|
|
21532
21927
|
try {
|
|
21533
|
-
const content = await
|
|
21928
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
21534
21929
|
const config = JSON.parse(content);
|
|
21535
21930
|
if (typeof config.fullPowerRiskMode === "boolean") {
|
|
21536
21931
|
fullPowerRiskEnabled = config.fullPowerRiskMode;
|
|
@@ -21544,12 +21939,12 @@ async function saveFullPowerRiskPreference(enabled) {
|
|
|
21544
21939
|
try {
|
|
21545
21940
|
let config = {};
|
|
21546
21941
|
try {
|
|
21547
|
-
const content = await
|
|
21942
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
21548
21943
|
config = JSON.parse(content);
|
|
21549
21944
|
} catch {
|
|
21550
21945
|
}
|
|
21551
21946
|
config.fullPowerRiskMode = enabled;
|
|
21552
|
-
await
|
|
21947
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
21553
21948
|
} catch {
|
|
21554
21949
|
}
|
|
21555
21950
|
}
|
|
@@ -21601,7 +21996,7 @@ __export(allow_path_prompt_exports, {
|
|
|
21601
21996
|
promptAllowPath: () => promptAllowPath
|
|
21602
21997
|
});
|
|
21603
21998
|
async function promptAllowPath(dirPath) {
|
|
21604
|
-
const absolute =
|
|
21999
|
+
const absolute = path38__default.resolve(dirPath);
|
|
21605
22000
|
console.log();
|
|
21606
22001
|
console.log(chalk.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
21607
22002
|
console.log(chalk.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -21843,13 +22238,13 @@ __export(stack_detector_exports, {
|
|
|
21843
22238
|
detectProjectStack: () => detectProjectStack
|
|
21844
22239
|
});
|
|
21845
22240
|
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(
|
|
22241
|
+
if (await fileExists3(path38__default.join(cwd, "package.json"))) return "node";
|
|
22242
|
+
if (await fileExists3(path38__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
22243
|
+
if (await fileExists3(path38__default.join(cwd, "pyproject.toml"))) return "python";
|
|
22244
|
+
if (await fileExists3(path38__default.join(cwd, "go.mod"))) return "go";
|
|
22245
|
+
if (await fileExists3(path38__default.join(cwd, "pom.xml"))) return "java";
|
|
22246
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle"))) return "java";
|
|
22247
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
21853
22248
|
return "unknown";
|
|
21854
22249
|
}
|
|
21855
22250
|
async function detectPackageManager3(cwd, stack) {
|
|
@@ -21857,25 +22252,25 @@ async function detectPackageManager3(cwd, stack) {
|
|
|
21857
22252
|
if (stack === "python") return "pip";
|
|
21858
22253
|
if (stack === "go") return "go";
|
|
21859
22254
|
if (stack === "java") {
|
|
21860
|
-
if (await fileExists3(
|
|
22255
|
+
if (await fileExists3(path38__default.join(cwd, "build.gradle")) || await fileExists3(path38__default.join(cwd, "build.gradle.kts"))) {
|
|
21861
22256
|
return "gradle";
|
|
21862
22257
|
}
|
|
21863
|
-
if (await fileExists3(
|
|
22258
|
+
if (await fileExists3(path38__default.join(cwd, "pom.xml"))) {
|
|
21864
22259
|
return "maven";
|
|
21865
22260
|
}
|
|
21866
22261
|
}
|
|
21867
22262
|
if (stack === "node") {
|
|
21868
|
-
if (await fileExists3(
|
|
21869
|
-
if (await fileExists3(
|
|
21870
|
-
if (await fileExists3(
|
|
22263
|
+
if (await fileExists3(path38__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
22264
|
+
if (await fileExists3(path38__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
22265
|
+
if (await fileExists3(path38__default.join(cwd, "bun.lockb"))) return "bun";
|
|
21871
22266
|
return "npm";
|
|
21872
22267
|
}
|
|
21873
22268
|
return null;
|
|
21874
22269
|
}
|
|
21875
22270
|
async function parsePackageJson(cwd) {
|
|
21876
|
-
const packageJsonPath =
|
|
22271
|
+
const packageJsonPath = path38__default.join(cwd, "package.json");
|
|
21877
22272
|
try {
|
|
21878
|
-
const content = await
|
|
22273
|
+
const content = await fs35__default.readFile(packageJsonPath, "utf-8");
|
|
21879
22274
|
const pkg = JSON.parse(content);
|
|
21880
22275
|
const allDeps = {
|
|
21881
22276
|
...pkg.dependencies,
|
|
@@ -21905,7 +22300,7 @@ async function parsePackageJson(cwd) {
|
|
|
21905
22300
|
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
21906
22301
|
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
21907
22302
|
const languages = ["JavaScript"];
|
|
21908
|
-
if (allDeps.typescript || await fileExists3(
|
|
22303
|
+
if (allDeps.typescript || await fileExists3(path38__default.join(cwd, "tsconfig.json"))) {
|
|
21909
22304
|
languages.push("TypeScript");
|
|
21910
22305
|
}
|
|
21911
22306
|
return {
|
|
@@ -21926,9 +22321,9 @@ async function parsePackageJson(cwd) {
|
|
|
21926
22321
|
}
|
|
21927
22322
|
}
|
|
21928
22323
|
async function parsePomXml(cwd) {
|
|
21929
|
-
const pomPath =
|
|
22324
|
+
const pomPath = path38__default.join(cwd, "pom.xml");
|
|
21930
22325
|
try {
|
|
21931
|
-
const content = await
|
|
22326
|
+
const content = await fs35__default.readFile(pomPath, "utf-8");
|
|
21932
22327
|
const dependencies = {};
|
|
21933
22328
|
const frameworks = [];
|
|
21934
22329
|
const buildTools2 = ["maven"];
|
|
@@ -21963,9 +22358,9 @@ async function parsePomXml(cwd) {
|
|
|
21963
22358
|
}
|
|
21964
22359
|
}
|
|
21965
22360
|
async function parsePyprojectToml(cwd) {
|
|
21966
|
-
const pyprojectPath =
|
|
22361
|
+
const pyprojectPath = path38__default.join(cwd, "pyproject.toml");
|
|
21967
22362
|
try {
|
|
21968
|
-
const content = await
|
|
22363
|
+
const content = await fs35__default.readFile(pyprojectPath, "utf-8");
|
|
21969
22364
|
const dependencies = {};
|
|
21970
22365
|
const frameworks = [];
|
|
21971
22366
|
const buildTools2 = ["pip"];
|
|
@@ -22006,7 +22401,7 @@ async function detectProjectStack(cwd) {
|
|
|
22006
22401
|
testingFrameworks = parsed.testingFrameworks;
|
|
22007
22402
|
languages = parsed.languages;
|
|
22008
22403
|
} else if (stack === "java") {
|
|
22009
|
-
const isGradle = await fileExists3(
|
|
22404
|
+
const isGradle = await fileExists3(path38__default.join(cwd, "build.gradle")) || await fileExists3(path38__default.join(cwd, "build.gradle.kts"));
|
|
22010
22405
|
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
22011
22406
|
dependencies = parsed.dependencies;
|
|
22012
22407
|
frameworks = parsed.frameworks;
|
|
@@ -22407,7 +22802,7 @@ function loadStandardFormat(config, configPath) {
|
|
|
22407
22802
|
return validServers;
|
|
22408
22803
|
}
|
|
22409
22804
|
async function loadProjectMCPFile(projectPath) {
|
|
22410
|
-
const mcpJsonPath =
|
|
22805
|
+
const mcpJsonPath = path38__default.join(projectPath, ".mcp.json");
|
|
22411
22806
|
try {
|
|
22412
22807
|
await access(mcpJsonPath);
|
|
22413
22808
|
} catch {
|
|
@@ -23719,26 +24114,26 @@ init_version();
|
|
|
23719
24114
|
// src/orchestrator/project.ts
|
|
23720
24115
|
init_env();
|
|
23721
24116
|
async function createProjectStructure(projectPath, info) {
|
|
23722
|
-
const cocoPath =
|
|
24117
|
+
const cocoPath = path38__default.join(projectPath, ".coco");
|
|
23723
24118
|
const directories = [
|
|
23724
24119
|
cocoPath,
|
|
23725
|
-
|
|
23726
|
-
|
|
23727
|
-
|
|
23728
|
-
|
|
23729
|
-
|
|
23730
|
-
|
|
23731
|
-
|
|
23732
|
-
|
|
23733
|
-
|
|
23734
|
-
|
|
23735
|
-
|
|
23736
|
-
|
|
23737
|
-
|
|
23738
|
-
|
|
24120
|
+
path38__default.join(cocoPath, "state"),
|
|
24121
|
+
path38__default.join(cocoPath, "checkpoints"),
|
|
24122
|
+
path38__default.join(cocoPath, "logs"),
|
|
24123
|
+
path38__default.join(cocoPath, "discovery"),
|
|
24124
|
+
path38__default.join(cocoPath, "spec"),
|
|
24125
|
+
path38__default.join(cocoPath, "architecture"),
|
|
24126
|
+
path38__default.join(cocoPath, "architecture", "adrs"),
|
|
24127
|
+
path38__default.join(cocoPath, "architecture", "diagrams"),
|
|
24128
|
+
path38__default.join(cocoPath, "planning"),
|
|
24129
|
+
path38__default.join(cocoPath, "planning", "epics"),
|
|
24130
|
+
path38__default.join(cocoPath, "execution"),
|
|
24131
|
+
path38__default.join(cocoPath, "versions"),
|
|
24132
|
+
path38__default.join(cocoPath, "reviews"),
|
|
24133
|
+
path38__default.join(cocoPath, "delivery")
|
|
23739
24134
|
];
|
|
23740
24135
|
for (const dir of directories) {
|
|
23741
|
-
await
|
|
24136
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
23742
24137
|
}
|
|
23743
24138
|
await createInitialConfig(cocoPath, info);
|
|
23744
24139
|
await createProjectState(cocoPath, info);
|
|
@@ -23773,7 +24168,7 @@ async function createInitialConfig(cocoPath, info) {
|
|
|
23773
24168
|
maxCheckpoints: 50
|
|
23774
24169
|
}
|
|
23775
24170
|
};
|
|
23776
|
-
await
|
|
24171
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
23777
24172
|
}
|
|
23778
24173
|
async function createProjectState(cocoPath, info) {
|
|
23779
24174
|
const state = {
|
|
@@ -23790,8 +24185,8 @@ async function createProjectState(cocoPath, info) {
|
|
|
23790
24185
|
qualityHistory: [],
|
|
23791
24186
|
lastCheckpoint: null
|
|
23792
24187
|
};
|
|
23793
|
-
await
|
|
23794
|
-
|
|
24188
|
+
await fs35__default.writeFile(
|
|
24189
|
+
path38__default.join(cocoPath, "state", "project.json"),
|
|
23795
24190
|
JSON.stringify(state, null, 2),
|
|
23796
24191
|
"utf-8"
|
|
23797
24192
|
);
|
|
@@ -23812,7 +24207,7 @@ checkpoints/
|
|
|
23812
24207
|
state/session.json
|
|
23813
24208
|
state/lock.json
|
|
23814
24209
|
`;
|
|
23815
|
-
await
|
|
24210
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, ".gitignore"), content, "utf-8");
|
|
23816
24211
|
}
|
|
23817
24212
|
async function createReadme(cocoPath, info) {
|
|
23818
24213
|
const content = `# Corbat-Coco Project: ${info.name}
|
|
@@ -23859,13 +24254,13 @@ Edit \`config.json\` to customize:
|
|
|
23859
24254
|
---
|
|
23860
24255
|
Generated by Corbat-Coco v0.1.0
|
|
23861
24256
|
`;
|
|
23862
|
-
await
|
|
24257
|
+
await fs35__default.writeFile(path38__default.join(cocoPath, "README.md"), content, "utf-8");
|
|
23863
24258
|
}
|
|
23864
24259
|
|
|
23865
24260
|
// src/cli/commands/init.ts
|
|
23866
24261
|
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(
|
|
24262
|
+
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) => {
|
|
24263
|
+
await runInit(path60, options);
|
|
23869
24264
|
});
|
|
23870
24265
|
}
|
|
23871
24266
|
async function runInit(projectPath, options) {
|
|
@@ -23944,18 +24339,18 @@ async function gatherProjectInfo() {
|
|
|
23944
24339
|
language
|
|
23945
24340
|
};
|
|
23946
24341
|
}
|
|
23947
|
-
function getDefaultProjectInfo(
|
|
23948
|
-
const name =
|
|
24342
|
+
function getDefaultProjectInfo(path60) {
|
|
24343
|
+
const name = path60 === "." ? "my-project" : path60.split("/").pop() || "my-project";
|
|
23949
24344
|
return {
|
|
23950
24345
|
name,
|
|
23951
24346
|
description: "",
|
|
23952
24347
|
language: "typescript"
|
|
23953
24348
|
};
|
|
23954
24349
|
}
|
|
23955
|
-
async function checkExistingProject(
|
|
24350
|
+
async function checkExistingProject(path60) {
|
|
23956
24351
|
try {
|
|
23957
|
-
const
|
|
23958
|
-
await
|
|
24352
|
+
const fs56 = await import('fs/promises');
|
|
24353
|
+
await fs56.access(`${path60}/.coco`);
|
|
23959
24354
|
return true;
|
|
23960
24355
|
} catch {
|
|
23961
24356
|
return false;
|
|
@@ -25163,13 +25558,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
25163
25558
|
// src/phases/converge/persistence.ts
|
|
25164
25559
|
init_errors();
|
|
25165
25560
|
function getPersistencePaths(projectPath) {
|
|
25166
|
-
const baseDir =
|
|
25561
|
+
const baseDir = path38__default.join(projectPath, ".coco", "spec");
|
|
25167
25562
|
return {
|
|
25168
25563
|
baseDir,
|
|
25169
|
-
sessionFile:
|
|
25170
|
-
specFile:
|
|
25171
|
-
conversationLog:
|
|
25172
|
-
checkpointFile:
|
|
25564
|
+
sessionFile: path38__default.join(baseDir, "discovery-session.json"),
|
|
25565
|
+
specFile: path38__default.join(baseDir, "spec.md"),
|
|
25566
|
+
conversationLog: path38__default.join(baseDir, "conversation.jsonl"),
|
|
25567
|
+
checkpointFile: path38__default.join(baseDir, "checkpoint.json")
|
|
25173
25568
|
};
|
|
25174
25569
|
}
|
|
25175
25570
|
var SessionPersistence = class {
|
|
@@ -25182,7 +25577,7 @@ var SessionPersistence = class {
|
|
|
25182
25577
|
*/
|
|
25183
25578
|
async ensureDir() {
|
|
25184
25579
|
try {
|
|
25185
|
-
await
|
|
25580
|
+
await fs35__default.mkdir(this.paths.baseDir, { recursive: true });
|
|
25186
25581
|
} catch {
|
|
25187
25582
|
throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
|
|
25188
25583
|
path: this.paths.baseDir,
|
|
@@ -25197,7 +25592,7 @@ var SessionPersistence = class {
|
|
|
25197
25592
|
await this.ensureDir();
|
|
25198
25593
|
try {
|
|
25199
25594
|
const data = JSON.stringify(session, null, 2);
|
|
25200
|
-
await
|
|
25595
|
+
await fs35__default.writeFile(this.paths.sessionFile, data, "utf-8");
|
|
25201
25596
|
} catch {
|
|
25202
25597
|
throw new FileSystemError("Failed to save discovery session", {
|
|
25203
25598
|
path: this.paths.sessionFile,
|
|
@@ -25210,7 +25605,7 @@ var SessionPersistence = class {
|
|
|
25210
25605
|
*/
|
|
25211
25606
|
async loadSession() {
|
|
25212
25607
|
try {
|
|
25213
|
-
const data = await
|
|
25608
|
+
const data = await fs35__default.readFile(this.paths.sessionFile, "utf-8");
|
|
25214
25609
|
const parsed = JSON.parse(data);
|
|
25215
25610
|
parsed.startedAt = new Date(parsed.startedAt);
|
|
25216
25611
|
parsed.updatedAt = new Date(parsed.updatedAt);
|
|
@@ -25236,7 +25631,7 @@ var SessionPersistence = class {
|
|
|
25236
25631
|
*/
|
|
25237
25632
|
async hasSession() {
|
|
25238
25633
|
try {
|
|
25239
|
-
await
|
|
25634
|
+
await fs35__default.access(this.paths.sessionFile);
|
|
25240
25635
|
return true;
|
|
25241
25636
|
} catch {
|
|
25242
25637
|
return false;
|
|
@@ -25247,7 +25642,7 @@ var SessionPersistence = class {
|
|
|
25247
25642
|
*/
|
|
25248
25643
|
async deleteSession() {
|
|
25249
25644
|
try {
|
|
25250
|
-
await
|
|
25645
|
+
await fs35__default.unlink(this.paths.sessionFile);
|
|
25251
25646
|
} catch (error) {
|
|
25252
25647
|
if (error.code !== "ENOENT") {
|
|
25253
25648
|
throw new FileSystemError("Failed to delete discovery session", {
|
|
@@ -25263,7 +25658,7 @@ var SessionPersistence = class {
|
|
|
25263
25658
|
async saveSpecification(content) {
|
|
25264
25659
|
await this.ensureDir();
|
|
25265
25660
|
try {
|
|
25266
|
-
await
|
|
25661
|
+
await fs35__default.writeFile(this.paths.specFile, content, "utf-8");
|
|
25267
25662
|
} catch {
|
|
25268
25663
|
throw new FileSystemError("Failed to save specification", {
|
|
25269
25664
|
path: this.paths.specFile,
|
|
@@ -25276,7 +25671,7 @@ var SessionPersistence = class {
|
|
|
25276
25671
|
*/
|
|
25277
25672
|
async loadSpecification() {
|
|
25278
25673
|
try {
|
|
25279
|
-
return await
|
|
25674
|
+
return await fs35__default.readFile(this.paths.specFile, "utf-8");
|
|
25280
25675
|
} catch {
|
|
25281
25676
|
return null;
|
|
25282
25677
|
}
|
|
@@ -25292,7 +25687,7 @@ var SessionPersistence = class {
|
|
|
25292
25687
|
content
|
|
25293
25688
|
};
|
|
25294
25689
|
try {
|
|
25295
|
-
await
|
|
25690
|
+
await fs35__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
|
|
25296
25691
|
} catch {
|
|
25297
25692
|
throw new FileSystemError("Failed to append to conversation log", {
|
|
25298
25693
|
path: this.paths.conversationLog,
|
|
@@ -25305,7 +25700,7 @@ var SessionPersistence = class {
|
|
|
25305
25700
|
*/
|
|
25306
25701
|
async loadConversationLog() {
|
|
25307
25702
|
try {
|
|
25308
|
-
const data = await
|
|
25703
|
+
const data = await fs35__default.readFile(this.paths.conversationLog, "utf-8");
|
|
25309
25704
|
const lines = data.trim().split("\n");
|
|
25310
25705
|
return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
25311
25706
|
} catch {
|
|
@@ -25319,7 +25714,7 @@ var SessionPersistence = class {
|
|
|
25319
25714
|
await this.ensureDir();
|
|
25320
25715
|
try {
|
|
25321
25716
|
const data = JSON.stringify(checkpoint, null, 2);
|
|
25322
|
-
await
|
|
25717
|
+
await fs35__default.writeFile(this.paths.checkpointFile, data, "utf-8");
|
|
25323
25718
|
} catch {
|
|
25324
25719
|
throw new FileSystemError("Failed to save checkpoint", {
|
|
25325
25720
|
path: this.paths.checkpointFile,
|
|
@@ -25332,7 +25727,7 @@ var SessionPersistence = class {
|
|
|
25332
25727
|
*/
|
|
25333
25728
|
async loadCheckpoint() {
|
|
25334
25729
|
try {
|
|
25335
|
-
const data = await
|
|
25730
|
+
const data = await fs35__default.readFile(this.paths.checkpointFile, "utf-8");
|
|
25336
25731
|
const parsed = JSON.parse(data);
|
|
25337
25732
|
parsed.timestamp = new Date(parsed.timestamp);
|
|
25338
25733
|
return parsed;
|
|
@@ -25345,7 +25740,7 @@ var SessionPersistence = class {
|
|
|
25345
25740
|
*/
|
|
25346
25741
|
async clearAll() {
|
|
25347
25742
|
try {
|
|
25348
|
-
await
|
|
25743
|
+
await fs35__default.rm(this.paths.baseDir, { recursive: true, force: true });
|
|
25349
25744
|
} catch (error) {
|
|
25350
25745
|
if (error.code !== "ENOENT") {
|
|
25351
25746
|
throw new FileSystemError("Failed to clear persistence data", {
|
|
@@ -27273,8 +27668,8 @@ var OrchestrateExecutor = class {
|
|
|
27273
27668
|
}
|
|
27274
27669
|
async loadSpecification(projectPath) {
|
|
27275
27670
|
try {
|
|
27276
|
-
const jsonPath =
|
|
27277
|
-
const jsonContent = await
|
|
27671
|
+
const jsonPath = path38__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
27672
|
+
const jsonContent = await fs35__default.readFile(jsonPath, "utf-8");
|
|
27278
27673
|
return JSON.parse(jsonContent);
|
|
27279
27674
|
} catch {
|
|
27280
27675
|
return this.createMinimalSpec(projectPath);
|
|
@@ -27285,7 +27680,7 @@ var OrchestrateExecutor = class {
|
|
|
27285
27680
|
version: "1.0.0",
|
|
27286
27681
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
27287
27682
|
overview: {
|
|
27288
|
-
name:
|
|
27683
|
+
name: path38__default.basename(projectPath),
|
|
27289
27684
|
description: "Project specification",
|
|
27290
27685
|
goals: [],
|
|
27291
27686
|
targetUsers: ["developers"],
|
|
@@ -27312,53 +27707,53 @@ var OrchestrateExecutor = class {
|
|
|
27312
27707
|
};
|
|
27313
27708
|
}
|
|
27314
27709
|
async saveArchitecture(projectPath, architecture) {
|
|
27315
|
-
const dir =
|
|
27316
|
-
await
|
|
27317
|
-
const mdPath =
|
|
27318
|
-
await
|
|
27319
|
-
const jsonPath =
|
|
27320
|
-
await
|
|
27710
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture");
|
|
27711
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27712
|
+
const mdPath = path38__default.join(dir, "ARCHITECTURE.md");
|
|
27713
|
+
await fs35__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
27714
|
+
const jsonPath = path38__default.join(dir, "architecture.json");
|
|
27715
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
27321
27716
|
return mdPath;
|
|
27322
27717
|
}
|
|
27323
27718
|
async saveADRs(projectPath, adrs) {
|
|
27324
|
-
const dir =
|
|
27325
|
-
await
|
|
27719
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
27720
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27326
27721
|
const paths = [];
|
|
27327
|
-
const indexPath =
|
|
27328
|
-
await
|
|
27722
|
+
const indexPath = path38__default.join(dir, "README.md");
|
|
27723
|
+
await fs35__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
27329
27724
|
paths.push(indexPath);
|
|
27330
27725
|
for (const adr of adrs) {
|
|
27331
27726
|
const filename = getADRFilename(adr);
|
|
27332
|
-
const adrPath =
|
|
27333
|
-
await
|
|
27727
|
+
const adrPath = path38__default.join(dir, filename);
|
|
27728
|
+
await fs35__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
27334
27729
|
paths.push(adrPath);
|
|
27335
27730
|
}
|
|
27336
27731
|
return paths;
|
|
27337
27732
|
}
|
|
27338
27733
|
async saveBacklog(projectPath, backlogResult) {
|
|
27339
|
-
const dir =
|
|
27340
|
-
await
|
|
27341
|
-
const mdPath =
|
|
27342
|
-
await
|
|
27343
|
-
const jsonPath =
|
|
27344
|
-
await
|
|
27734
|
+
const dir = path38__default.join(projectPath, ".coco", "planning");
|
|
27735
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27736
|
+
const mdPath = path38__default.join(dir, "BACKLOG.md");
|
|
27737
|
+
await fs35__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
27738
|
+
const jsonPath = path38__default.join(dir, "backlog.json");
|
|
27739
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
27345
27740
|
return mdPath;
|
|
27346
27741
|
}
|
|
27347
27742
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
27348
|
-
const dir =
|
|
27349
|
-
await
|
|
27743
|
+
const dir = path38__default.join(projectPath, ".coco", "planning", "sprints");
|
|
27744
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27350
27745
|
const filename = `${sprint.id}.md`;
|
|
27351
|
-
const sprintPath =
|
|
27352
|
-
await
|
|
27353
|
-
const jsonPath =
|
|
27354
|
-
await
|
|
27746
|
+
const sprintPath = path38__default.join(dir, filename);
|
|
27747
|
+
await fs35__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
27748
|
+
const jsonPath = path38__default.join(dir, `${sprint.id}.json`);
|
|
27749
|
+
await fs35__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
27355
27750
|
return sprintPath;
|
|
27356
27751
|
}
|
|
27357
27752
|
async saveDiagram(projectPath, id, mermaid) {
|
|
27358
|
-
const dir =
|
|
27359
|
-
await
|
|
27360
|
-
const diagramPath =
|
|
27361
|
-
await
|
|
27753
|
+
const dir = path38__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
27754
|
+
await fs35__default.mkdir(dir, { recursive: true });
|
|
27755
|
+
const diagramPath = path38__default.join(dir, `${id}.mmd`);
|
|
27756
|
+
await fs35__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
27362
27757
|
return diagramPath;
|
|
27363
27758
|
}
|
|
27364
27759
|
};
|
|
@@ -27456,20 +27851,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
27456
27851
|
},
|
|
27457
27852
|
tools: {
|
|
27458
27853
|
file: {
|
|
27459
|
-
async read(
|
|
27460
|
-
const
|
|
27461
|
-
return
|
|
27854
|
+
async read(path60) {
|
|
27855
|
+
const fs56 = await import('fs/promises');
|
|
27856
|
+
return fs56.readFile(path60, "utf-8");
|
|
27462
27857
|
},
|
|
27463
|
-
async write(
|
|
27464
|
-
const
|
|
27858
|
+
async write(path60, content) {
|
|
27859
|
+
const fs56 = await import('fs/promises');
|
|
27465
27860
|
const nodePath = await import('path');
|
|
27466
|
-
await
|
|
27467
|
-
await
|
|
27861
|
+
await fs56.mkdir(nodePath.dirname(path60), { recursive: true });
|
|
27862
|
+
await fs56.writeFile(path60, content, "utf-8");
|
|
27468
27863
|
},
|
|
27469
|
-
async exists(
|
|
27470
|
-
const
|
|
27864
|
+
async exists(path60) {
|
|
27865
|
+
const fs56 = await import('fs/promises');
|
|
27471
27866
|
try {
|
|
27472
|
-
await
|
|
27867
|
+
await fs56.access(path60);
|
|
27473
27868
|
return true;
|
|
27474
27869
|
} catch {
|
|
27475
27870
|
return false;
|
|
@@ -27708,16 +28103,16 @@ async function loadTasks(_options) {
|
|
|
27708
28103
|
];
|
|
27709
28104
|
}
|
|
27710
28105
|
async function checkProjectState() {
|
|
27711
|
-
const
|
|
28106
|
+
const fs56 = await import('fs/promises');
|
|
27712
28107
|
let hasProject = false;
|
|
27713
28108
|
let hasPlan = false;
|
|
27714
28109
|
try {
|
|
27715
|
-
await
|
|
28110
|
+
await fs56.access(".coco");
|
|
27716
28111
|
hasProject = true;
|
|
27717
28112
|
} catch {
|
|
27718
28113
|
}
|
|
27719
28114
|
try {
|
|
27720
|
-
await
|
|
28115
|
+
await fs56.access(".coco/planning/backlog.json");
|
|
27721
28116
|
hasPlan = true;
|
|
27722
28117
|
} catch {
|
|
27723
28118
|
}
|
|
@@ -27824,24 +28219,24 @@ function getPhaseStatusForPhase(phase) {
|
|
|
27824
28219
|
return "in_progress";
|
|
27825
28220
|
}
|
|
27826
28221
|
async function loadProjectState(cwd, config) {
|
|
27827
|
-
const
|
|
27828
|
-
const
|
|
27829
|
-
const statePath =
|
|
27830
|
-
const backlogPath =
|
|
27831
|
-
const checkpointDir =
|
|
28222
|
+
const fs56 = await import('fs/promises');
|
|
28223
|
+
const path60 = await import('path');
|
|
28224
|
+
const statePath = path60.join(cwd, ".coco", "state.json");
|
|
28225
|
+
const backlogPath = path60.join(cwd, ".coco", "planning", "backlog.json");
|
|
28226
|
+
const checkpointDir = path60.join(cwd, ".coco", "checkpoints");
|
|
27832
28227
|
let currentPhase = "idle";
|
|
27833
28228
|
let metrics;
|
|
27834
28229
|
let sprint;
|
|
27835
28230
|
let checkpoints = [];
|
|
27836
28231
|
try {
|
|
27837
|
-
const stateContent = await
|
|
28232
|
+
const stateContent = await fs56.readFile(statePath, "utf-8");
|
|
27838
28233
|
const stateData = JSON.parse(stateContent);
|
|
27839
28234
|
currentPhase = stateData.currentPhase || "idle";
|
|
27840
28235
|
metrics = stateData.metrics;
|
|
27841
28236
|
} catch {
|
|
27842
28237
|
}
|
|
27843
28238
|
try {
|
|
27844
|
-
const backlogContent = await
|
|
28239
|
+
const backlogContent = await fs56.readFile(backlogPath, "utf-8");
|
|
27845
28240
|
const backlogData = JSON.parse(backlogContent);
|
|
27846
28241
|
if (backlogData.currentSprint) {
|
|
27847
28242
|
const tasks = backlogData.tasks || [];
|
|
@@ -27863,7 +28258,7 @@ async function loadProjectState(cwd, config) {
|
|
|
27863
28258
|
} catch {
|
|
27864
28259
|
}
|
|
27865
28260
|
try {
|
|
27866
|
-
const files = await
|
|
28261
|
+
const files = await fs56.readdir(checkpointDir);
|
|
27867
28262
|
checkpoints = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
27868
28263
|
} catch {
|
|
27869
28264
|
}
|
|
@@ -27999,8 +28394,8 @@ async function restoreFromCheckpoint(_checkpoint) {
|
|
|
27999
28394
|
}
|
|
28000
28395
|
async function checkProjectExists() {
|
|
28001
28396
|
try {
|
|
28002
|
-
const
|
|
28003
|
-
await
|
|
28397
|
+
const fs56 = await import('fs/promises');
|
|
28398
|
+
await fs56.access(".coco");
|
|
28004
28399
|
return true;
|
|
28005
28400
|
} catch {
|
|
28006
28401
|
return false;
|
|
@@ -29215,9 +29610,9 @@ var DEFAULT_CONFIG2 = {
|
|
|
29215
29610
|
}
|
|
29216
29611
|
};
|
|
29217
29612
|
async function loadConfig2() {
|
|
29218
|
-
const
|
|
29613
|
+
const fs56 = await import('fs/promises');
|
|
29219
29614
|
try {
|
|
29220
|
-
const raw = await
|
|
29615
|
+
const raw = await fs56.readFile(CONFIG_PATH, "utf-8");
|
|
29221
29616
|
const parsed = JSON.parse(raw);
|
|
29222
29617
|
return { ...DEFAULT_CONFIG2, ...parsed };
|
|
29223
29618
|
} catch {
|
|
@@ -29225,13 +29620,13 @@ async function loadConfig2() {
|
|
|
29225
29620
|
}
|
|
29226
29621
|
}
|
|
29227
29622
|
async function saveConfig2(config) {
|
|
29228
|
-
const
|
|
29623
|
+
const fs56 = await import('fs/promises');
|
|
29229
29624
|
const dir = join(CONFIG_PATH, "..");
|
|
29230
|
-
await
|
|
29231
|
-
await
|
|
29625
|
+
await fs56.mkdir(dir, { recursive: true });
|
|
29626
|
+
await fs56.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
29232
29627
|
}
|
|
29233
|
-
function getNestedValue(obj,
|
|
29234
|
-
const keys =
|
|
29628
|
+
function getNestedValue(obj, path60) {
|
|
29629
|
+
const keys = path60.split(".");
|
|
29235
29630
|
let current = obj;
|
|
29236
29631
|
for (const key of keys) {
|
|
29237
29632
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -29241,8 +29636,8 @@ function getNestedValue(obj, path59) {
|
|
|
29241
29636
|
}
|
|
29242
29637
|
return current;
|
|
29243
29638
|
}
|
|
29244
|
-
function setNestedValue(obj,
|
|
29245
|
-
const keys =
|
|
29639
|
+
function setNestedValue(obj, path60, value) {
|
|
29640
|
+
const keys = path60.split(".");
|
|
29246
29641
|
let current = obj;
|
|
29247
29642
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
29248
29643
|
const key = keys[i];
|
|
@@ -29608,13 +30003,13 @@ async function runAdd(source, options) {
|
|
|
29608
30003
|
const isGithubShorthand = source.includes("/") && !isGitUrl;
|
|
29609
30004
|
const isLocalPath = source.startsWith(".") || source.startsWith("/");
|
|
29610
30005
|
if (isLocalPath) {
|
|
29611
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29612
|
-
const sourcePath =
|
|
29613
|
-
const skillName =
|
|
29614
|
-
const destPath =
|
|
30006
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30007
|
+
const sourcePath = path38__default.resolve(source);
|
|
30008
|
+
const skillName = path38__default.basename(sourcePath);
|
|
30009
|
+
const destPath = path38__default.join(targetDir, skillName);
|
|
29615
30010
|
try {
|
|
29616
|
-
await
|
|
29617
|
-
await
|
|
30011
|
+
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
30012
|
+
await fs35__default.cp(sourcePath, destPath, { recursive: true });
|
|
29618
30013
|
p26.log.success(`Installed "${skillName}" to ${destPath}`);
|
|
29619
30014
|
} catch (error) {
|
|
29620
30015
|
p26.log.error(
|
|
@@ -29645,10 +30040,10 @@ async function runAdd(source, options) {
|
|
|
29645
30040
|
p26.log.info("Try installing manually: git clone the repo into .agents/skills/");
|
|
29646
30041
|
}
|
|
29647
30042
|
} else if (isGitUrl) {
|
|
29648
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29649
|
-
await
|
|
30043
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30044
|
+
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
29650
30045
|
const skillName = source.split("/").pop()?.replace(".git", "") ?? "skill";
|
|
29651
|
-
const skillDir =
|
|
30046
|
+
const skillDir = path38__default.join(targetDir, skillName);
|
|
29652
30047
|
const spinner18 = p26.spinner();
|
|
29653
30048
|
spinner18.start(`Cloning ${source}...`);
|
|
29654
30049
|
try {
|
|
@@ -29674,15 +30069,15 @@ async function runAdd(source, options) {
|
|
|
29674
30069
|
}
|
|
29675
30070
|
async function runRemove(name, options) {
|
|
29676
30071
|
p26.intro(chalk.magenta("Remove Skill"));
|
|
29677
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29678
|
-
const skillPath =
|
|
29679
|
-
if (!skillPath.startsWith(
|
|
30072
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30073
|
+
const skillPath = path38__default.resolve(targetDir, name);
|
|
30074
|
+
if (!skillPath.startsWith(path38__default.resolve(targetDir) + path38__default.sep)) {
|
|
29680
30075
|
p26.log.error(`Invalid skill name: "${name}"`);
|
|
29681
30076
|
p26.outro("");
|
|
29682
30077
|
return;
|
|
29683
30078
|
}
|
|
29684
30079
|
try {
|
|
29685
|
-
await
|
|
30080
|
+
await fs35__default.access(skillPath);
|
|
29686
30081
|
} catch {
|
|
29687
30082
|
p26.log.error(`Skill "${name}" not found at ${skillPath}`);
|
|
29688
30083
|
p26.outro("");
|
|
@@ -29698,7 +30093,7 @@ async function runRemove(name, options) {
|
|
|
29698
30093
|
return;
|
|
29699
30094
|
}
|
|
29700
30095
|
}
|
|
29701
|
-
await
|
|
30096
|
+
await fs35__default.rm(skillPath, { recursive: true });
|
|
29702
30097
|
p26.log.success(`Removed "${name}"`);
|
|
29703
30098
|
p26.outro("");
|
|
29704
30099
|
}
|
|
@@ -29760,10 +30155,10 @@ async function runInfo(name) {
|
|
|
29760
30155
|
}
|
|
29761
30156
|
async function runCreate(name, options) {
|
|
29762
30157
|
p26.intro(chalk.magenta("Create Skill"));
|
|
29763
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
29764
|
-
const skillDir =
|
|
30158
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path38__default.join(process.cwd(), ".agents", "skills");
|
|
30159
|
+
const skillDir = path38__default.join(targetDir, name);
|
|
29765
30160
|
try {
|
|
29766
|
-
await
|
|
30161
|
+
await fs35__default.access(skillDir);
|
|
29767
30162
|
p26.log.error(`Skill "${name}" already exists at ${skillDir}`);
|
|
29768
30163
|
p26.outro("");
|
|
29769
30164
|
return;
|
|
@@ -29792,7 +30187,7 @@ async function runCreate(name, options) {
|
|
|
29792
30187
|
p26.outro("Cancelled.");
|
|
29793
30188
|
return;
|
|
29794
30189
|
}
|
|
29795
|
-
await
|
|
30190
|
+
await fs35__default.mkdir(skillDir, { recursive: true });
|
|
29796
30191
|
const skillMd = `---
|
|
29797
30192
|
name: "${name}"
|
|
29798
30193
|
description: "${description}"
|
|
@@ -29814,10 +30209,10 @@ when this skill is activated (automatically via matching or manually via /${name
|
|
|
29814
30209
|
2. Include examples when helpful
|
|
29815
30210
|
3. Keep instructions under 500 lines
|
|
29816
30211
|
`;
|
|
29817
|
-
await
|
|
29818
|
-
await
|
|
30212
|
+
await fs35__default.writeFile(path38__default.join(skillDir, "SKILL.md"), skillMd, "utf-8");
|
|
30213
|
+
await fs35__default.mkdir(path38__default.join(skillDir, "references"), { recursive: true });
|
|
29819
30214
|
p26.log.success(`Created skill at ${skillDir}`);
|
|
29820
|
-
p26.log.info(`Edit ${
|
|
30215
|
+
p26.log.info(`Edit ${path38__default.join(skillDir, "SKILL.md")} to add instructions.`);
|
|
29821
30216
|
p26.outro("");
|
|
29822
30217
|
}
|
|
29823
30218
|
function registerWinner(winners, candidate, candidateScanOrder, scanOrderById) {
|
|
@@ -30273,10 +30668,10 @@ function registerCheckCommand(program2) {
|
|
|
30273
30668
|
|
|
30274
30669
|
// src/swarm/spec-parser.ts
|
|
30275
30670
|
async function parseSwarmSpec(filePath) {
|
|
30276
|
-
const
|
|
30277
|
-
const
|
|
30278
|
-
const rawContent = await
|
|
30279
|
-
const ext =
|
|
30671
|
+
const fs56 = await import('fs/promises');
|
|
30672
|
+
const path60 = await import('path');
|
|
30673
|
+
const rawContent = await fs56.readFile(filePath, "utf-8");
|
|
30674
|
+
const ext = path60.extname(filePath).toLowerCase();
|
|
30280
30675
|
if (ext === ".yaml" || ext === ".yml") {
|
|
30281
30676
|
return parseYamlSpec(rawContent);
|
|
30282
30677
|
}
|
|
@@ -30605,11 +31000,11 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
30605
31000
|
integrator: { maxTurns: 20, temperature: 0.2 }
|
|
30606
31001
|
};
|
|
30607
31002
|
async function loadAgentConfig(projectPath) {
|
|
30608
|
-
const
|
|
30609
|
-
const
|
|
30610
|
-
const configPath =
|
|
31003
|
+
const fs56 = await import('fs/promises');
|
|
31004
|
+
const path60 = await import('path');
|
|
31005
|
+
const configPath = path60.join(projectPath, ".coco", "swarm", "agents.json");
|
|
30611
31006
|
try {
|
|
30612
|
-
const raw = await
|
|
31007
|
+
const raw = await fs56.readFile(configPath, "utf-8");
|
|
30613
31008
|
const parsed = JSON.parse(raw);
|
|
30614
31009
|
const merged = { ...DEFAULT_AGENT_CONFIG };
|
|
30615
31010
|
for (const role of Object.keys(DEFAULT_AGENT_CONFIG)) {
|
|
@@ -30797,19 +31192,19 @@ async function createBoard(projectPath, spec) {
|
|
|
30797
31192
|
return board;
|
|
30798
31193
|
}
|
|
30799
31194
|
async function loadBoard(projectPath) {
|
|
30800
|
-
const
|
|
30801
|
-
const
|
|
30802
|
-
const boardPath =
|
|
30803
|
-
const raw = await
|
|
31195
|
+
const fs56 = await import('fs/promises');
|
|
31196
|
+
const path60 = await import('path');
|
|
31197
|
+
const boardPath = path60.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
31198
|
+
const raw = await fs56.readFile(boardPath, "utf-8");
|
|
30804
31199
|
return JSON.parse(raw);
|
|
30805
31200
|
}
|
|
30806
31201
|
async function saveBoard(projectPath, board) {
|
|
30807
|
-
const
|
|
30808
|
-
const
|
|
30809
|
-
const boardDir =
|
|
30810
|
-
const boardPath =
|
|
30811
|
-
await
|
|
30812
|
-
await
|
|
31202
|
+
const fs56 = await import('fs/promises');
|
|
31203
|
+
const path60 = await import('path');
|
|
31204
|
+
const boardDir = path60.join(projectPath, ".coco", "swarm");
|
|
31205
|
+
const boardPath = path60.join(boardDir, "task-board.json");
|
|
31206
|
+
await fs56.mkdir(boardDir, { recursive: true });
|
|
31207
|
+
await fs56.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
30813
31208
|
}
|
|
30814
31209
|
function markTaskInProgress(board, taskId, role) {
|
|
30815
31210
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -30974,11 +31369,11 @@ async function defaultPromptHandler(q) {
|
|
|
30974
31369
|
}
|
|
30975
31370
|
}
|
|
30976
31371
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
30977
|
-
const
|
|
30978
|
-
const
|
|
30979
|
-
const swarmDir =
|
|
30980
|
-
const assumptionsPath =
|
|
30981
|
-
await
|
|
31372
|
+
const fs56 = await import('fs/promises');
|
|
31373
|
+
const path60 = await import('path');
|
|
31374
|
+
const swarmDir = path60.join(projectPath, ".coco", "swarm");
|
|
31375
|
+
const assumptionsPath = path60.join(swarmDir, "assumptions.md");
|
|
31376
|
+
await fs56.mkdir(swarmDir, { recursive: true });
|
|
30982
31377
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
30983
31378
|
const content = [
|
|
30984
31379
|
`# Swarm Assumptions \u2014 ${projectName}`,
|
|
@@ -30994,18 +31389,18 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
30994
31389
|
assumptions.length > 0 ? assumptions.join("\n\n") : `_(none)_`,
|
|
30995
31390
|
``
|
|
30996
31391
|
].join("\n");
|
|
30997
|
-
await
|
|
31392
|
+
await fs56.writeFile(assumptionsPath, content, "utf-8");
|
|
30998
31393
|
return assumptionsPath;
|
|
30999
31394
|
}
|
|
31000
31395
|
|
|
31001
31396
|
// src/swarm/events.ts
|
|
31002
31397
|
async function appendSwarmEvent(projectPath, event) {
|
|
31003
|
-
const
|
|
31004
|
-
const
|
|
31005
|
-
const eventsDir =
|
|
31006
|
-
const eventsFile =
|
|
31007
|
-
await
|
|
31008
|
-
await
|
|
31398
|
+
const fs56 = await import('fs/promises');
|
|
31399
|
+
const path60 = await import('path');
|
|
31400
|
+
const eventsDir = path60.join(projectPath, ".coco", "swarm");
|
|
31401
|
+
const eventsFile = path60.join(eventsDir, "events.jsonl");
|
|
31402
|
+
await fs56.mkdir(eventsDir, { recursive: true });
|
|
31403
|
+
await fs56.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
31009
31404
|
}
|
|
31010
31405
|
function createEventId() {
|
|
31011
31406
|
return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -31013,12 +31408,12 @@ function createEventId() {
|
|
|
31013
31408
|
|
|
31014
31409
|
// src/swarm/knowledge.ts
|
|
31015
31410
|
async function appendKnowledge(projectPath, entry) {
|
|
31016
|
-
const
|
|
31017
|
-
const
|
|
31018
|
-
const knowledgeDir =
|
|
31019
|
-
const knowledgeFile =
|
|
31020
|
-
await
|
|
31021
|
-
await
|
|
31411
|
+
const fs56 = await import('fs/promises');
|
|
31412
|
+
const path60 = await import('path');
|
|
31413
|
+
const knowledgeDir = path60.join(projectPath, ".coco", "swarm");
|
|
31414
|
+
const knowledgeFile = path60.join(knowledgeDir, "knowledge.jsonl");
|
|
31415
|
+
await fs56.mkdir(knowledgeDir, { recursive: true });
|
|
31416
|
+
await fs56.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
31022
31417
|
}
|
|
31023
31418
|
|
|
31024
31419
|
// src/swarm/agents/prompts.ts
|
|
@@ -31322,11 +31717,11 @@ async function runSwarmLifecycle(options) {
|
|
|
31322
31717
|
}
|
|
31323
31718
|
async function stageInit(ctx) {
|
|
31324
31719
|
const { projectPath, spec } = ctx.options;
|
|
31325
|
-
const
|
|
31326
|
-
const
|
|
31327
|
-
await
|
|
31328
|
-
await
|
|
31329
|
-
const specSummaryPath =
|
|
31720
|
+
const fs56 = await import('fs/promises');
|
|
31721
|
+
const path60 = await import('path');
|
|
31722
|
+
await fs56.mkdir(path60.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
31723
|
+
await fs56.mkdir(ctx.options.outputPath, { recursive: true });
|
|
31724
|
+
const specSummaryPath = path60.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
31330
31725
|
const specSummary = {
|
|
31331
31726
|
projectName: spec.projectName,
|
|
31332
31727
|
description: spec.description,
|
|
@@ -31340,7 +31735,7 @@ async function stageInit(ctx) {
|
|
|
31340
31735
|
})),
|
|
31341
31736
|
qualityConfig: spec.qualityConfig
|
|
31342
31737
|
};
|
|
31343
|
-
await
|
|
31738
|
+
await fs56.writeFile(specSummaryPath, JSON.stringify(specSummary, null, 2), "utf-8");
|
|
31344
31739
|
await emitEvent(projectPath, {
|
|
31345
31740
|
agentRole: "pm",
|
|
31346
31741
|
agentTurn: 0,
|
|
@@ -31397,10 +31792,10 @@ async function stagePlan(ctx) {
|
|
|
31397
31792
|
})
|
|
31398
31793
|
]);
|
|
31399
31794
|
await createBoard(projectPath, spec);
|
|
31400
|
-
const
|
|
31401
|
-
const
|
|
31402
|
-
const planPath =
|
|
31403
|
-
await
|
|
31795
|
+
const fs56 = await import('fs/promises');
|
|
31796
|
+
const path60 = await import('path');
|
|
31797
|
+
const planPath = path60.join(projectPath, ".coco", "swarm", "plan.json");
|
|
31798
|
+
await fs56.writeFile(
|
|
31404
31799
|
planPath,
|
|
31405
31800
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
31406
31801
|
"utf-8"
|
|
@@ -31615,8 +32010,8 @@ async function stageIntegrate(ctx) {
|
|
|
31615
32010
|
}
|
|
31616
32011
|
async function stageOutput(ctx) {
|
|
31617
32012
|
const { projectPath, outputPath } = ctx.options;
|
|
31618
|
-
const
|
|
31619
|
-
const
|
|
32013
|
+
const fs56 = await import('fs/promises');
|
|
32014
|
+
const path60 = await import('path');
|
|
31620
32015
|
const board = await loadBoard(projectPath);
|
|
31621
32016
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
31622
32017
|
const summary = {
|
|
@@ -31630,9 +32025,9 @@ async function stageOutput(ctx) {
|
|
|
31630
32025
|
},
|
|
31631
32026
|
globalScore: computeGlobalScore(featureResults)
|
|
31632
32027
|
};
|
|
31633
|
-
await
|
|
31634
|
-
const summaryPath =
|
|
31635
|
-
await
|
|
32028
|
+
await fs56.mkdir(outputPath, { recursive: true });
|
|
32029
|
+
const summaryPath = path60.join(outputPath, "swarm-summary.json");
|
|
32030
|
+
await fs56.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
31636
32031
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
31637
32032
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
31638
32033
|
await emitEvent(projectPath, {
|
|
@@ -31978,8 +32373,8 @@ var SwarmOrchestrator = class {
|
|
|
31978
32373
|
noQuestions = false,
|
|
31979
32374
|
onProgress
|
|
31980
32375
|
} = options;
|
|
31981
|
-
const
|
|
31982
|
-
const projectPath =
|
|
32376
|
+
const path60 = await import('path');
|
|
32377
|
+
const projectPath = path60.dirname(path60.resolve(specFile));
|
|
31983
32378
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
31984
32379
|
const spec = await parseSwarmSpec(specFile);
|
|
31985
32380
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -31990,7 +32385,7 @@ var SwarmOrchestrator = class {
|
|
|
31990
32385
|
await runSwarmLifecycle({
|
|
31991
32386
|
spec,
|
|
31992
32387
|
projectPath,
|
|
31993
|
-
outputPath:
|
|
32388
|
+
outputPath: path60.resolve(outputPath),
|
|
31994
32389
|
provider,
|
|
31995
32390
|
agentConfig,
|
|
31996
32391
|
minScore,
|
|
@@ -32828,8 +33223,8 @@ async function setupGcloudADC(provider) {
|
|
|
32828
33223
|
console.log(chalk.dim(" (Complete the sign-in in your browser, then return here)"));
|
|
32829
33224
|
console.log();
|
|
32830
33225
|
const { exec: exec3 } = await import('child_process');
|
|
32831
|
-
const { promisify:
|
|
32832
|
-
const execAsync3 =
|
|
33226
|
+
const { promisify: promisify6 } = await import('util');
|
|
33227
|
+
const execAsync3 = promisify6(exec3);
|
|
32833
33228
|
try {
|
|
32834
33229
|
await execAsync3("gcloud auth application-default login", {
|
|
32835
33230
|
timeout: 12e4
|
|
@@ -33514,15 +33909,15 @@ async function saveConfiguration(result) {
|
|
|
33514
33909
|
}
|
|
33515
33910
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
33516
33911
|
if (createDir) {
|
|
33517
|
-
const dir =
|
|
33912
|
+
const dir = path38.dirname(filePath);
|
|
33518
33913
|
try {
|
|
33519
|
-
await
|
|
33914
|
+
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
33520
33915
|
} catch {
|
|
33521
33916
|
}
|
|
33522
33917
|
}
|
|
33523
33918
|
let existingVars = {};
|
|
33524
33919
|
try {
|
|
33525
|
-
const content = await
|
|
33920
|
+
const content = await fs35.readFile(filePath, "utf-8");
|
|
33526
33921
|
for (const line of content.split("\n")) {
|
|
33527
33922
|
const trimmed = line.trim();
|
|
33528
33923
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -33545,7 +33940,7 @@ async function saveEnvVars(filePath, vars, createDir = false) {
|
|
|
33545
33940
|
for (const [key, value] of Object.entries(allVars)) {
|
|
33546
33941
|
lines.push(`${key}=${value}`);
|
|
33547
33942
|
}
|
|
33548
|
-
await
|
|
33943
|
+
await fs35.writeFile(filePath, lines.join("\n") + "\n", { mode: 384 });
|
|
33549
33944
|
}
|
|
33550
33945
|
async function handleLocalProviderUnavailable(providerType, config) {
|
|
33551
33946
|
const cfg = LOCAL_PROVIDER_CONFIG[providerType];
|
|
@@ -33635,6 +34030,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33635
34030
|
const preferredHasCopilotCreds = preferredProviderDef?.id === "copilot" && isProviderConfigured();
|
|
33636
34031
|
const preferredIsConfigured = preferredIsLocal || preferredHasApiKey || preferredHasOpenAIOAuth || preferredHasCopilotCreds;
|
|
33637
34032
|
let preferredWasConfiguredButUnavailable = false;
|
|
34033
|
+
let preferredUnavailableWasLocal = false;
|
|
33638
34034
|
if (preferredProviderDef && preferredIsConfigured) {
|
|
33639
34035
|
try {
|
|
33640
34036
|
const preferredInternalProviderId = preferredProviderDef.id === "openai" && preferredHasOpenAIOAuth ? "codex" : preferredProviderDef.id;
|
|
@@ -33654,8 +34050,9 @@ async function ensureConfiguredV2(config) {
|
|
|
33654
34050
|
if (retryResult !== null) return retryResult;
|
|
33655
34051
|
}
|
|
33656
34052
|
preferredWasConfiguredButUnavailable = true;
|
|
34053
|
+
preferredUnavailableWasLocal = preferredIsLocal;
|
|
33657
34054
|
}
|
|
33658
|
-
if (!preferredWasConfiguredButUnavailable) {
|
|
34055
|
+
if (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal) {
|
|
33659
34056
|
const configuredProviders = providers.filter((p45) => {
|
|
33660
34057
|
if (p45.id === "copilot") return isProviderConfigured();
|
|
33661
34058
|
if (p45.id === "openai") {
|
|
@@ -33676,6 +34073,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33676
34073
|
}
|
|
33677
34074
|
const provider = await createProvider(providerId, { model });
|
|
33678
34075
|
if (await provider.isAvailable()) {
|
|
34076
|
+
await saveProviderPreference(prov.id, model);
|
|
33679
34077
|
return {
|
|
33680
34078
|
...config,
|
|
33681
34079
|
provider: {
|
|
@@ -33690,7 +34088,7 @@ async function ensureConfiguredV2(config) {
|
|
|
33690
34088
|
}
|
|
33691
34089
|
}
|
|
33692
34090
|
}
|
|
33693
|
-
if (config.provider.type !== "openai" && config.provider.type !== "codex" && hasOpenAIOAuthTokens && !preferredWasConfiguredButUnavailable) {
|
|
34091
|
+
if (config.provider.type !== "openai" && config.provider.type !== "codex" && hasOpenAIOAuthTokens && (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal)) {
|
|
33694
34092
|
try {
|
|
33695
34093
|
const tokenResult = await getOrRefreshOAuthToken("openai");
|
|
33696
34094
|
if (tokenResult) {
|
|
@@ -34174,8 +34572,8 @@ async function setupGcloudADCForProvider(_provider) {
|
|
|
34174
34572
|
return false;
|
|
34175
34573
|
}
|
|
34176
34574
|
const { exec: exec3 } = await import('child_process');
|
|
34177
|
-
const { promisify:
|
|
34178
|
-
const execAsync3 =
|
|
34575
|
+
const { promisify: promisify6 } = await import('util');
|
|
34576
|
+
const execAsync3 = promisify6(exec3);
|
|
34179
34577
|
try {
|
|
34180
34578
|
await execAsync3("gcloud auth application-default login", { timeout: 12e4 });
|
|
34181
34579
|
const token = await getADCAccessToken();
|
|
@@ -34911,8 +35309,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
34911
35309
|
p26.log.message("");
|
|
34912
35310
|
for (const project of projects) {
|
|
34913
35311
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
34914
|
-
const
|
|
34915
|
-
p26.log.message(` [${level}] ${
|
|
35312
|
+
const path60 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
35313
|
+
p26.log.message(` [${level}] ${path60}`);
|
|
34916
35314
|
p26.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
34917
35315
|
}
|
|
34918
35316
|
p26.log.message("");
|
|
@@ -35082,8 +35480,8 @@ var buildCommand = {
|
|
|
35082
35480
|
};
|
|
35083
35481
|
async function loadBacklog(projectPath) {
|
|
35084
35482
|
try {
|
|
35085
|
-
const backlogPath =
|
|
35086
|
-
const content = await
|
|
35483
|
+
const backlogPath = path38.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35484
|
+
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35087
35485
|
const data = JSON.parse(content);
|
|
35088
35486
|
return data.backlog;
|
|
35089
35487
|
} catch {
|
|
@@ -35092,25 +35490,25 @@ async function loadBacklog(projectPath) {
|
|
|
35092
35490
|
}
|
|
35093
35491
|
async function loadSprint(projectPath, sprintId) {
|
|
35094
35492
|
try {
|
|
35095
|
-
const sprintsDir =
|
|
35096
|
-
const files = await
|
|
35493
|
+
const sprintsDir = path38.join(projectPath, ".coco", "planning", "sprints");
|
|
35494
|
+
const files = await fs35.readdir(sprintsDir);
|
|
35097
35495
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
35098
35496
|
if (jsonFiles.length === 0) return null;
|
|
35099
35497
|
const targetFile = sprintId ? jsonFiles.find((f) => f.includes(sprintId)) : jsonFiles[0];
|
|
35100
35498
|
if (!targetFile) return null;
|
|
35101
|
-
const sprintPath =
|
|
35102
|
-
const content = await
|
|
35499
|
+
const sprintPath = path38.join(sprintsDir, targetFile);
|
|
35500
|
+
const content = await fs35.readFile(sprintPath, "utf-8");
|
|
35103
35501
|
return JSON.parse(content);
|
|
35104
35502
|
} catch {
|
|
35105
35503
|
return null;
|
|
35106
35504
|
}
|
|
35107
35505
|
}
|
|
35108
35506
|
async function saveBacklog(projectPath, backlog) {
|
|
35109
|
-
const backlogPath =
|
|
35110
|
-
const content = await
|
|
35507
|
+
const backlogPath = path38.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35508
|
+
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35111
35509
|
const data = JSON.parse(content);
|
|
35112
35510
|
data.backlog = backlog;
|
|
35113
|
-
await
|
|
35511
|
+
await fs35.writeFile(backlogPath, JSON.stringify(data, null, 2), "utf-8");
|
|
35114
35512
|
}
|
|
35115
35513
|
function getStatusEmoji(status) {
|
|
35116
35514
|
const emojis = {
|
|
@@ -35816,7 +36214,7 @@ function getLevelName(level) {
|
|
|
35816
36214
|
function displayMemoryFile(file) {
|
|
35817
36215
|
const { emoji, color } = getLevelStyle(file.level);
|
|
35818
36216
|
const levelName = getLevelName(file.level);
|
|
35819
|
-
const fileName =
|
|
36217
|
+
const fileName = path38__default.basename(file.path);
|
|
35820
36218
|
console.log();
|
|
35821
36219
|
console.log(
|
|
35822
36220
|
`${emoji} ${color.bold(levelName)} ${chalk.dim(`(${fileName})`)} ${chalk.dim(file.path)}`
|
|
@@ -35911,7 +36309,7 @@ var memoryCommand = {
|
|
|
35911
36309
|
)
|
|
35912
36310
|
);
|
|
35913
36311
|
for (const f of reloaded) {
|
|
35914
|
-
const fileName =
|
|
36312
|
+
const fileName = path38__default.basename(f.path);
|
|
35915
36313
|
console.log(chalk.dim(` ${fileName} (${formatSize(f.content?.length ?? 0)})`));
|
|
35916
36314
|
}
|
|
35917
36315
|
} else {
|
|
@@ -36053,7 +36451,7 @@ async function getCheckpoint(session, checkpointId) {
|
|
|
36053
36451
|
return store.checkpoints.find((cp) => cp.id === checkpointId) ?? null;
|
|
36054
36452
|
}
|
|
36055
36453
|
async function restoreFiles(checkpoint, excludeFiles) {
|
|
36056
|
-
const
|
|
36454
|
+
const fs56 = await import('fs/promises');
|
|
36057
36455
|
const restored = [];
|
|
36058
36456
|
const failed = [];
|
|
36059
36457
|
for (const fileCheckpoint of checkpoint.files) {
|
|
@@ -36061,7 +36459,7 @@ async function restoreFiles(checkpoint, excludeFiles) {
|
|
|
36061
36459
|
continue;
|
|
36062
36460
|
}
|
|
36063
36461
|
try {
|
|
36064
|
-
await
|
|
36462
|
+
await fs56.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
|
|
36065
36463
|
restored.push(fileCheckpoint.filePath);
|
|
36066
36464
|
} catch (error) {
|
|
36067
36465
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -36143,8 +36541,8 @@ function displayRewindResult(result) {
|
|
|
36143
36541
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
36144
36542
|
console.log(`${chalk.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
36145
36543
|
}
|
|
36146
|
-
for (const { path:
|
|
36147
|
-
const fileName =
|
|
36544
|
+
for (const { path: path60, error } of result.filesFailed) {
|
|
36545
|
+
const fileName = path60.split("/").pop() ?? path60;
|
|
36148
36546
|
console.log(`${chalk.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
36149
36547
|
}
|
|
36150
36548
|
if (result.conversationRestored) {
|
|
@@ -36782,8 +37180,8 @@ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@corbat-tech/coco/latest";
|
|
|
36782
37180
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
36783
37181
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
36784
37182
|
var STARTUP_TIMEOUT_MS = 5500;
|
|
36785
|
-
var CACHE_DIR =
|
|
36786
|
-
var CACHE_FILE =
|
|
37183
|
+
var CACHE_DIR = path38__default.join(os4__default.homedir(), ".coco");
|
|
37184
|
+
var CACHE_FILE = path38__default.join(CACHE_DIR, "version-check-cache.json");
|
|
36787
37185
|
function compareVersions(a, b) {
|
|
36788
37186
|
const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
36789
37187
|
const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
@@ -37125,7 +37523,7 @@ async function readClipboardImage() {
|
|
|
37125
37523
|
return null;
|
|
37126
37524
|
}
|
|
37127
37525
|
async function readClipboardImageMacOS() {
|
|
37128
|
-
const tmpFile =
|
|
37526
|
+
const tmpFile = path38.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37129
37527
|
try {
|
|
37130
37528
|
const script = `
|
|
37131
37529
|
set theFile to POSIX file "${tmpFile}"
|
|
@@ -37148,7 +37546,7 @@ end try
|
|
|
37148
37546
|
if (!result.startsWith("ok")) {
|
|
37149
37547
|
return null;
|
|
37150
37548
|
}
|
|
37151
|
-
const buffer = await
|
|
37549
|
+
const buffer = await fs35.readFile(tmpFile);
|
|
37152
37550
|
return {
|
|
37153
37551
|
data: buffer.toString("base64"),
|
|
37154
37552
|
media_type: "image/png"
|
|
@@ -37157,7 +37555,7 @@ end try
|
|
|
37157
37555
|
return null;
|
|
37158
37556
|
} finally {
|
|
37159
37557
|
try {
|
|
37160
|
-
await
|
|
37558
|
+
await fs35.unlink(tmpFile);
|
|
37161
37559
|
} catch {
|
|
37162
37560
|
}
|
|
37163
37561
|
}
|
|
@@ -37187,7 +37585,7 @@ async function readClipboardImageLinux() {
|
|
|
37187
37585
|
}
|
|
37188
37586
|
}
|
|
37189
37587
|
async function readClipboardImageWindows() {
|
|
37190
|
-
const tmpFile =
|
|
37588
|
+
const tmpFile = path38.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37191
37589
|
try {
|
|
37192
37590
|
const escapedPath = tmpFile.replace(/'/g, "''");
|
|
37193
37591
|
const script = `
|
|
@@ -37205,7 +37603,7 @@ if ($img -ne $null) {
|
|
|
37205
37603
|
timeout: 1e4
|
|
37206
37604
|
}).trim();
|
|
37207
37605
|
if (result !== "ok") return null;
|
|
37208
|
-
const buffer = await
|
|
37606
|
+
const buffer = await fs35.readFile(tmpFile);
|
|
37209
37607
|
return {
|
|
37210
37608
|
data: buffer.toString("base64"),
|
|
37211
37609
|
media_type: "image/png"
|
|
@@ -37214,7 +37612,7 @@ if ($img -ne $null) {
|
|
|
37214
37612
|
return null;
|
|
37215
37613
|
} finally {
|
|
37216
37614
|
try {
|
|
37217
|
-
await
|
|
37615
|
+
await fs35.unlink(tmpFile);
|
|
37218
37616
|
} catch {
|
|
37219
37617
|
}
|
|
37220
37618
|
}
|
|
@@ -37312,9 +37710,9 @@ var allowPathCommand = {
|
|
|
37312
37710
|
}
|
|
37313
37711
|
};
|
|
37314
37712
|
async function addPath(dirPath, session) {
|
|
37315
|
-
const absolute =
|
|
37713
|
+
const absolute = path38__default.resolve(dirPath);
|
|
37316
37714
|
try {
|
|
37317
|
-
const stat2 = await
|
|
37715
|
+
const stat2 = await fs35__default.stat(absolute);
|
|
37318
37716
|
if (!stat2.isDirectory()) {
|
|
37319
37717
|
p26.log.error(`Not a directory: ${absolute}`);
|
|
37320
37718
|
return;
|
|
@@ -37324,19 +37722,19 @@ async function addPath(dirPath, session) {
|
|
|
37324
37722
|
return;
|
|
37325
37723
|
}
|
|
37326
37724
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
37327
|
-
const normalizedBlocked =
|
|
37328
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
37725
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
37726
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
37329
37727
|
p26.log.error(`System path '${blocked}' cannot be allowed`);
|
|
37330
37728
|
return;
|
|
37331
37729
|
}
|
|
37332
37730
|
}
|
|
37333
|
-
const normalizedCwd =
|
|
37334
|
-
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd +
|
|
37731
|
+
const normalizedCwd = path38__default.normalize(session.projectPath);
|
|
37732
|
+
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd + path38__default.sep)) {
|
|
37335
37733
|
p26.log.info("That path is already within the project directory");
|
|
37336
37734
|
return;
|
|
37337
37735
|
}
|
|
37338
37736
|
const existing = getAllowedPaths();
|
|
37339
|
-
if (existing.some((e) =>
|
|
37737
|
+
if (existing.some((e) => path38__default.normalize(e.path) === path38__default.normalize(absolute))) {
|
|
37340
37738
|
p26.log.info(`Already allowed: ${absolute}`);
|
|
37341
37739
|
return;
|
|
37342
37740
|
}
|
|
@@ -37407,7 +37805,7 @@ async function revokePath(dirPath, _session) {
|
|
|
37407
37805
|
}
|
|
37408
37806
|
dirPath = selected;
|
|
37409
37807
|
}
|
|
37410
|
-
const absolute =
|
|
37808
|
+
const absolute = path38__default.resolve(dirPath);
|
|
37411
37809
|
const removed = removeAllowedPathFromSession(absolute);
|
|
37412
37810
|
await removePersistedAllowedPath(absolute);
|
|
37413
37811
|
if (removed) {
|
|
@@ -37760,11 +38158,12 @@ var RECOMMENDED_DENY = [
|
|
|
37760
38158
|
];
|
|
37761
38159
|
async function loadPermissionPreferences() {
|
|
37762
38160
|
try {
|
|
37763
|
-
const content = await
|
|
38161
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
37764
38162
|
const config = JSON.parse(content);
|
|
37765
38163
|
return {
|
|
37766
38164
|
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
37767
|
-
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed
|
|
38165
|
+
recommendedAllowlistDismissed: config.recommendedAllowlistDismissed,
|
|
38166
|
+
recommendedAllowlistPrompted: config.recommendedAllowlistPrompted
|
|
37768
38167
|
};
|
|
37769
38168
|
} catch {
|
|
37770
38169
|
return {};
|
|
@@ -37774,34 +38173,28 @@ async function savePermissionPreference(key, value) {
|
|
|
37774
38173
|
try {
|
|
37775
38174
|
let config = {};
|
|
37776
38175
|
try {
|
|
37777
|
-
const content = await
|
|
38176
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
37778
38177
|
config = JSON.parse(content);
|
|
37779
38178
|
} catch {
|
|
37780
38179
|
}
|
|
37781
38180
|
config[key] = value;
|
|
37782
|
-
await
|
|
37783
|
-
await
|
|
38181
|
+
await fs35__default.mkdir(path38__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
38182
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
37784
38183
|
} catch {
|
|
37785
38184
|
}
|
|
37786
38185
|
}
|
|
37787
38186
|
async function shouldShowPermissionSuggestion() {
|
|
37788
38187
|
const prefs = await loadPermissionPreferences();
|
|
37789
|
-
if (prefs.
|
|
38188
|
+
if (prefs.recommendedAllowlistPrompted) {
|
|
37790
38189
|
return false;
|
|
37791
38190
|
}
|
|
37792
|
-
if (
|
|
37793
|
-
return
|
|
38191
|
+
if (prefs.recommendedAllowlistDismissed) {
|
|
38192
|
+
return false;
|
|
37794
38193
|
}
|
|
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;
|
|
38194
|
+
if (prefs.recommendedAllowlistApplied) {
|
|
38195
|
+
return false;
|
|
37803
38196
|
}
|
|
37804
|
-
return
|
|
38197
|
+
return true;
|
|
37805
38198
|
}
|
|
37806
38199
|
async function applyRecommendedPermissions() {
|
|
37807
38200
|
for (const tool of [...RECOMMENDED_GLOBAL, ...RECOMMENDED_PROJECT]) {
|
|
@@ -37810,6 +38203,7 @@ async function applyRecommendedPermissions() {
|
|
|
37810
38203
|
await savePermissionPreference("recommendedAllowlistApplied", true);
|
|
37811
38204
|
}
|
|
37812
38205
|
async function showPermissionSuggestion() {
|
|
38206
|
+
await savePermissionPreference("recommendedAllowlistPrompted", true);
|
|
37813
38207
|
console.log();
|
|
37814
38208
|
console.log(chalk.magenta.bold(" \u{1F4CB} Recommended Permissions"));
|
|
37815
38209
|
console.log();
|
|
@@ -38029,7 +38423,7 @@ async function resetPermissions(session) {
|
|
|
38029
38423
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
38030
38424
|
};
|
|
38031
38425
|
try {
|
|
38032
|
-
await
|
|
38426
|
+
await fs35__default.writeFile(CONFIG_PATHS.trustedTools, JSON.stringify(emptySettings, null, 2), "utf-8");
|
|
38033
38427
|
} catch {
|
|
38034
38428
|
}
|
|
38035
38429
|
await savePermissionPreference("recommendedAllowlistApplied", false);
|
|
@@ -38111,7 +38505,7 @@ function formatQualityResult(result) {
|
|
|
38111
38505
|
}
|
|
38112
38506
|
async function loadQualityLoopPreference() {
|
|
38113
38507
|
try {
|
|
38114
|
-
const content = await
|
|
38508
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
38115
38509
|
const config = JSON.parse(content);
|
|
38116
38510
|
const value = config.qualityLoop ?? config.cocoMode;
|
|
38117
38511
|
if (typeof value === "boolean") {
|
|
@@ -38126,12 +38520,12 @@ async function saveQualityLoopPreference(enabled) {
|
|
|
38126
38520
|
try {
|
|
38127
38521
|
let config = {};
|
|
38128
38522
|
try {
|
|
38129
|
-
const content = await
|
|
38523
|
+
const content = await fs35__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
38130
38524
|
config = JSON.parse(content);
|
|
38131
38525
|
} catch {
|
|
38132
38526
|
}
|
|
38133
38527
|
config.qualityLoop = enabled;
|
|
38134
|
-
await
|
|
38528
|
+
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
38135
38529
|
} catch {
|
|
38136
38530
|
}
|
|
38137
38531
|
}
|
|
@@ -38977,9 +39371,9 @@ Response format (JSON only, no prose):
|
|
|
38977
39371
|
cancel5("Build cancelled.");
|
|
38978
39372
|
}
|
|
38979
39373
|
}
|
|
38980
|
-
const cocoDir =
|
|
38981
|
-
await
|
|
38982
|
-
await
|
|
39374
|
+
const cocoDir = path38__default.join(outputPath, ".coco");
|
|
39375
|
+
await fs35__default.mkdir(cocoDir, { recursive: true });
|
|
39376
|
+
await fs35__default.writeFile(path38__default.join(cocoDir, "backlog.json"), JSON.stringify(spec, null, 2), "utf-8");
|
|
38983
39377
|
p26.outro(" Spec saved \u2014 starting sprints");
|
|
38984
39378
|
return spec;
|
|
38985
39379
|
}
|
|
@@ -39529,20 +39923,20 @@ init_errors();
|
|
|
39529
39923
|
init_subprocess_registry();
|
|
39530
39924
|
async function detectTestFramework2(cwd) {
|
|
39531
39925
|
try {
|
|
39532
|
-
await
|
|
39926
|
+
await fs35__default.access(path38__default.join(cwd, "pom.xml"));
|
|
39533
39927
|
return "maven";
|
|
39534
39928
|
} catch {
|
|
39535
39929
|
}
|
|
39536
39930
|
for (const gradleFile of ["build.gradle", "build.gradle.kts"]) {
|
|
39537
39931
|
try {
|
|
39538
|
-
await
|
|
39932
|
+
await fs35__default.access(path38__default.join(cwd, gradleFile));
|
|
39539
39933
|
return "gradle";
|
|
39540
39934
|
} catch {
|
|
39541
39935
|
}
|
|
39542
39936
|
}
|
|
39543
39937
|
try {
|
|
39544
|
-
const pkgPath =
|
|
39545
|
-
const pkgContent = await
|
|
39938
|
+
const pkgPath = path38__default.join(cwd, "package.json");
|
|
39939
|
+
const pkgContent = await fs35__default.readFile(pkgPath, "utf-8");
|
|
39546
39940
|
const pkg = JSON.parse(pkgContent);
|
|
39547
39941
|
const deps = {
|
|
39548
39942
|
...pkg.dependencies,
|
|
@@ -39558,16 +39952,16 @@ async function detectTestFramework2(cwd) {
|
|
|
39558
39952
|
}
|
|
39559
39953
|
}
|
|
39560
39954
|
function toMavenTestFilter(pattern) {
|
|
39561
|
-
const base =
|
|
39955
|
+
const base = path38__default.basename(pattern).replace(/\.java$/, "");
|
|
39562
39956
|
return base;
|
|
39563
39957
|
}
|
|
39564
39958
|
function toGradleTestFilter(pattern) {
|
|
39565
|
-
const base =
|
|
39959
|
+
const base = path38__default.basename(pattern).replace(/\.java$/, "");
|
|
39566
39960
|
return `*${base}`;
|
|
39567
39961
|
}
|
|
39568
39962
|
async function mavenExecutable(cwd) {
|
|
39569
39963
|
try {
|
|
39570
|
-
await
|
|
39964
|
+
await fs35__default.access(path38__default.join(cwd, "mvnw"));
|
|
39571
39965
|
return "./mvnw";
|
|
39572
39966
|
} catch {
|
|
39573
39967
|
return "mvn";
|
|
@@ -39575,7 +39969,7 @@ async function mavenExecutable(cwd) {
|
|
|
39575
39969
|
}
|
|
39576
39970
|
async function gradleExecutable(cwd) {
|
|
39577
39971
|
try {
|
|
39578
|
-
await
|
|
39972
|
+
await fs35__default.access(path38__default.join(cwd, "gradlew"));
|
|
39579
39973
|
return "./gradlew";
|
|
39580
39974
|
} catch {
|
|
39581
39975
|
return "gradle";
|
|
@@ -39816,18 +40210,18 @@ Examples:
|
|
|
39816
40210
|
const projectDir = cwd ?? process.cwd();
|
|
39817
40211
|
try {
|
|
39818
40212
|
const coverageLocations = [
|
|
39819
|
-
|
|
39820
|
-
|
|
39821
|
-
|
|
40213
|
+
path38__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
40214
|
+
path38__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
40215
|
+
path38__default.join(projectDir, ".nyc_output", "coverage-summary.json"),
|
|
39822
40216
|
// Maven JaCoCo
|
|
39823
|
-
|
|
39824
|
-
|
|
40217
|
+
path38__default.join(projectDir, "target", "site", "jacoco", "jacoco.csv"),
|
|
40218
|
+
path38__default.join(projectDir, "target", "site", "jacoco-ut", "jacoco.csv"),
|
|
39825
40219
|
// Gradle JaCoCo
|
|
39826
|
-
|
|
40220
|
+
path38__default.join(projectDir, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")
|
|
39827
40221
|
];
|
|
39828
40222
|
for (const location of coverageLocations) {
|
|
39829
40223
|
try {
|
|
39830
|
-
const content = await
|
|
40224
|
+
const content = await fs35__default.readFile(location, "utf-8");
|
|
39831
40225
|
if (location.endsWith(".csv")) {
|
|
39832
40226
|
const result = parseJacocoCsvCoverage(content);
|
|
39833
40227
|
if (result) {
|
|
@@ -39936,7 +40330,7 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
39936
40330
|
const results = [];
|
|
39937
40331
|
const startTime = Date.now();
|
|
39938
40332
|
const isTimedOut = () => Date.now() - startTime > opts.timeoutMs;
|
|
39939
|
-
const queue = [[
|
|
40333
|
+
const queue = [[path38__default.resolve(rootDir), 0]];
|
|
39940
40334
|
const visited = /* @__PURE__ */ new Set();
|
|
39941
40335
|
while (queue.length > 0 && results.length < opts.maxResults) {
|
|
39942
40336
|
if (isTimedOut()) break;
|
|
@@ -39945,11 +40339,11 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
39945
40339
|
visited.add(currentDir);
|
|
39946
40340
|
if (depth > opts.maxDepth) continue;
|
|
39947
40341
|
try {
|
|
39948
|
-
const entries = await
|
|
40342
|
+
const entries = await fs35__default.readdir(currentDir, { withFileTypes: true });
|
|
39949
40343
|
for (const entry of entries) {
|
|
39950
40344
|
if (isTimedOut()) break;
|
|
39951
40345
|
const entryName = entry.name;
|
|
39952
|
-
const entryPath =
|
|
40346
|
+
const entryPath = path38__default.join(currentDir, entryName);
|
|
39953
40347
|
if (!opts.includeHidden && entryName.startsWith(".")) continue;
|
|
39954
40348
|
if (entry.isDirectory() && opts.excludeDirs.has(entryName)) continue;
|
|
39955
40349
|
const isMatch = opts.type === "file" && entry.isFile() || opts.type === "directory" && entry.isDirectory() || opts.type === "both";
|
|
@@ -39983,19 +40377,19 @@ async function suggestSimilarFilesDeep(missingPath, rootDir = process.cwd(), opt
|
|
|
39983
40377
|
if (fastResults.length > 0) {
|
|
39984
40378
|
return fastResults;
|
|
39985
40379
|
}
|
|
39986
|
-
const absPath =
|
|
39987
|
-
const target =
|
|
40380
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40381
|
+
const target = path38__default.basename(absPath);
|
|
39988
40382
|
return findFileRecursive(rootDir, target, options);
|
|
39989
40383
|
}
|
|
39990
40384
|
async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), options) {
|
|
39991
|
-
const absPath =
|
|
39992
|
-
const target =
|
|
39993
|
-
const parentDir =
|
|
40385
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40386
|
+
const target = path38__default.basename(absPath);
|
|
40387
|
+
const parentDir = path38__default.dirname(absPath);
|
|
39994
40388
|
try {
|
|
39995
|
-
const entries = await
|
|
40389
|
+
const entries = await fs35__default.readdir(parentDir, { withFileTypes: true });
|
|
39996
40390
|
const dirs = entries.filter((e) => e.isDirectory());
|
|
39997
40391
|
const scored = dirs.map((d) => ({
|
|
39998
|
-
path:
|
|
40392
|
+
path: path38__default.join(parentDir, d.name),
|
|
39999
40393
|
distance: levenshtein(target.toLowerCase(), d.name.toLowerCase())
|
|
40000
40394
|
})).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
40395
|
if (scored.length > 0) {
|
|
@@ -40006,15 +40400,15 @@ async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), opti
|
|
|
40006
40400
|
return findFileRecursive(rootDir, target, { ...options, type: "directory" });
|
|
40007
40401
|
}
|
|
40008
40402
|
async function suggestSimilarFiles(missingPath, options) {
|
|
40009
|
-
const absPath =
|
|
40010
|
-
const dir =
|
|
40011
|
-
const target =
|
|
40403
|
+
const absPath = path38__default.resolve(missingPath);
|
|
40404
|
+
const dir = path38__default.dirname(absPath);
|
|
40405
|
+
const target = path38__default.basename(absPath);
|
|
40012
40406
|
const maxResults = options?.maxResults;
|
|
40013
40407
|
try {
|
|
40014
|
-
const entries = await
|
|
40408
|
+
const entries = await fs35__default.readdir(dir);
|
|
40015
40409
|
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
40016
40410
|
const scored = limited.map((name) => ({
|
|
40017
|
-
path:
|
|
40411
|
+
path: path38__default.join(dir, name),
|
|
40018
40412
|
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
40019
40413
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
40020
40414
|
return scored.slice(0, maxResults);
|
|
@@ -40026,7 +40420,7 @@ function formatSuggestions(suggestions, baseDir) {
|
|
|
40026
40420
|
if (suggestions.length === 0) return "";
|
|
40027
40421
|
const base = baseDir ?? process.cwd();
|
|
40028
40422
|
const lines = suggestions.map((s) => {
|
|
40029
|
-
const rel =
|
|
40423
|
+
const rel = path38__default.relative(base, s.path);
|
|
40030
40424
|
return ` - ${rel}`;
|
|
40031
40425
|
});
|
|
40032
40426
|
return `
|
|
@@ -40060,7 +40454,7 @@ function hasNullByte2(str) {
|
|
|
40060
40454
|
}
|
|
40061
40455
|
function normalizePath2(filePath) {
|
|
40062
40456
|
let normalized = filePath.replace(/\0/g, "");
|
|
40063
|
-
normalized =
|
|
40457
|
+
normalized = path38__default.normalize(normalized);
|
|
40064
40458
|
return normalized;
|
|
40065
40459
|
}
|
|
40066
40460
|
function isPathAllowed(filePath, operation) {
|
|
@@ -40068,31 +40462,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
40068
40462
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
40069
40463
|
}
|
|
40070
40464
|
const normalized = normalizePath2(filePath);
|
|
40071
|
-
const absolute =
|
|
40465
|
+
const absolute = path38__default.resolve(normalized);
|
|
40072
40466
|
const cwd = process.cwd();
|
|
40073
40467
|
for (const blocked of BLOCKED_PATHS2) {
|
|
40074
|
-
const normalizedBlocked =
|
|
40075
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
40468
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
40469
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
40076
40470
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
40077
40471
|
}
|
|
40078
40472
|
}
|
|
40079
40473
|
const home = process.env.HOME;
|
|
40080
40474
|
if (home) {
|
|
40081
|
-
const normalizedHome =
|
|
40082
|
-
const normalizedCwd =
|
|
40475
|
+
const normalizedHome = path38__default.normalize(home);
|
|
40476
|
+
const normalizedCwd = path38__default.normalize(cwd);
|
|
40083
40477
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
40084
40478
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
40085
40479
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
40086
|
-
const basename4 =
|
|
40480
|
+
const basename4 = path38__default.basename(absolute);
|
|
40087
40481
|
if (!allowedHomeReads.includes(basename4)) {
|
|
40088
|
-
const targetDir =
|
|
40482
|
+
const targetDir = path38__default.dirname(absolute);
|
|
40089
40483
|
return {
|
|
40090
40484
|
allowed: false,
|
|
40091
40485
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
40092
40486
|
};
|
|
40093
40487
|
}
|
|
40094
40488
|
} else {
|
|
40095
|
-
const targetDir =
|
|
40489
|
+
const targetDir = path38__default.dirname(absolute);
|
|
40096
40490
|
return {
|
|
40097
40491
|
allowed: false,
|
|
40098
40492
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -40101,7 +40495,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
40101
40495
|
}
|
|
40102
40496
|
}
|
|
40103
40497
|
if (operation === "write" || operation === "delete") {
|
|
40104
|
-
const basename4 =
|
|
40498
|
+
const basename4 = path38__default.basename(absolute);
|
|
40105
40499
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
40106
40500
|
if (pattern.test(basename4)) {
|
|
40107
40501
|
return {
|
|
@@ -40124,17 +40518,17 @@ function isENOENT(error) {
|
|
|
40124
40518
|
return error.code === "ENOENT";
|
|
40125
40519
|
}
|
|
40126
40520
|
async function enrichENOENT(filePath, operation) {
|
|
40127
|
-
const absPath =
|
|
40521
|
+
const absPath = path38__default.resolve(filePath);
|
|
40128
40522
|
const suggestions = await suggestSimilarFilesDeep(absPath, process.cwd());
|
|
40129
|
-
const hint = formatSuggestions(suggestions,
|
|
40523
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(absPath));
|
|
40130
40524
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
40131
40525
|
return `File not found: ${filePath}${hint}
|
|
40132
40526
|
${action}`;
|
|
40133
40527
|
}
|
|
40134
40528
|
async function enrichDirENOENT(dirPath) {
|
|
40135
|
-
const absPath =
|
|
40529
|
+
const absPath = path38__default.resolve(dirPath);
|
|
40136
40530
|
const suggestions = await suggestSimilarDirsDeep(absPath, process.cwd());
|
|
40137
|
-
const hint = formatSuggestions(suggestions,
|
|
40531
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(absPath));
|
|
40138
40532
|
return `Directory not found: ${dirPath}${hint}
|
|
40139
40533
|
Use list_dir or glob to find the correct path.`;
|
|
40140
40534
|
}
|
|
@@ -40155,13 +40549,13 @@ Examples:
|
|
|
40155
40549
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
40156
40550
|
validatePath(filePath, "read");
|
|
40157
40551
|
try {
|
|
40158
|
-
const absolutePath =
|
|
40159
|
-
const stats = await
|
|
40552
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40553
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40160
40554
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
40161
40555
|
let truncated = false;
|
|
40162
40556
|
let content;
|
|
40163
40557
|
if (stats.size > maxBytes) {
|
|
40164
|
-
const handle = await
|
|
40558
|
+
const handle = await fs35__default.open(absolutePath, "r");
|
|
40165
40559
|
try {
|
|
40166
40560
|
const buffer = Buffer.alloc(maxBytes);
|
|
40167
40561
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -40171,7 +40565,7 @@ Examples:
|
|
|
40171
40565
|
await handle.close();
|
|
40172
40566
|
}
|
|
40173
40567
|
} else {
|
|
40174
|
-
content = await
|
|
40568
|
+
content = await fs35__default.readFile(absolutePath, encoding);
|
|
40175
40569
|
}
|
|
40176
40570
|
return {
|
|
40177
40571
|
content,
|
|
@@ -40214,10 +40608,10 @@ Examples:
|
|
|
40214
40608
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
40215
40609
|
validatePath(filePath, "write");
|
|
40216
40610
|
try {
|
|
40217
|
-
const absolutePath =
|
|
40611
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40218
40612
|
let wouldCreate = false;
|
|
40219
40613
|
try {
|
|
40220
|
-
await
|
|
40614
|
+
await fs35__default.access(absolutePath);
|
|
40221
40615
|
} catch {
|
|
40222
40616
|
wouldCreate = true;
|
|
40223
40617
|
}
|
|
@@ -40230,10 +40624,10 @@ Examples:
|
|
|
40230
40624
|
};
|
|
40231
40625
|
}
|
|
40232
40626
|
if (createDirs) {
|
|
40233
|
-
await
|
|
40627
|
+
await fs35__default.mkdir(path38__default.dirname(absolutePath), { recursive: true });
|
|
40234
40628
|
}
|
|
40235
|
-
await
|
|
40236
|
-
const stats = await
|
|
40629
|
+
await fs35__default.writeFile(absolutePath, content, "utf-8");
|
|
40630
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40237
40631
|
return {
|
|
40238
40632
|
path: absolutePath,
|
|
40239
40633
|
size: stats.size,
|
|
@@ -40276,8 +40670,8 @@ Examples:
|
|
|
40276
40670
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
40277
40671
|
validatePath(filePath, "write");
|
|
40278
40672
|
try {
|
|
40279
|
-
const absolutePath =
|
|
40280
|
-
let content = await
|
|
40673
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40674
|
+
let content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
40281
40675
|
let replacements = 0;
|
|
40282
40676
|
if (all) {
|
|
40283
40677
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -40326,7 +40720,7 @@ Hint: Use read_file first to verify the exact content.`
|
|
|
40326
40720
|
preview
|
|
40327
40721
|
};
|
|
40328
40722
|
}
|
|
40329
|
-
await
|
|
40723
|
+
await fs35__default.writeFile(absolutePath, content, "utf-8");
|
|
40330
40724
|
return {
|
|
40331
40725
|
path: absolutePath,
|
|
40332
40726
|
replacements,
|
|
@@ -40397,8 +40791,8 @@ Examples:
|
|
|
40397
40791
|
}),
|
|
40398
40792
|
async execute({ path: filePath }) {
|
|
40399
40793
|
try {
|
|
40400
|
-
const absolutePath =
|
|
40401
|
-
const stats = await
|
|
40794
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40795
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40402
40796
|
return {
|
|
40403
40797
|
exists: true,
|
|
40404
40798
|
isFile: stats.isFile(),
|
|
@@ -40428,12 +40822,12 @@ Examples:
|
|
|
40428
40822
|
}),
|
|
40429
40823
|
async execute({ path: dirPath, recursive }) {
|
|
40430
40824
|
try {
|
|
40431
|
-
const absolutePath =
|
|
40825
|
+
const absolutePath = path38__default.resolve(dirPath);
|
|
40432
40826
|
const entries = [];
|
|
40433
40827
|
async function listDir(dir, prefix = "") {
|
|
40434
|
-
const items = await
|
|
40828
|
+
const items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
40435
40829
|
for (const item of items) {
|
|
40436
|
-
const fullPath =
|
|
40830
|
+
const fullPath = path38__default.join(dir, item.name);
|
|
40437
40831
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
40438
40832
|
if (item.isDirectory()) {
|
|
40439
40833
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -40441,7 +40835,7 @@ Examples:
|
|
|
40441
40835
|
await listDir(fullPath, relativePath);
|
|
40442
40836
|
}
|
|
40443
40837
|
} else if (item.isFile()) {
|
|
40444
|
-
const stats = await
|
|
40838
|
+
const stats = await fs35__default.stat(fullPath);
|
|
40445
40839
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
40446
40840
|
}
|
|
40447
40841
|
}
|
|
@@ -40488,23 +40882,23 @@ Examples:
|
|
|
40488
40882
|
}
|
|
40489
40883
|
validatePath(filePath, "delete");
|
|
40490
40884
|
try {
|
|
40491
|
-
const absolutePath =
|
|
40492
|
-
const stats = await
|
|
40885
|
+
const absolutePath = path38__default.resolve(filePath);
|
|
40886
|
+
const stats = await fs35__default.stat(absolutePath);
|
|
40493
40887
|
if (stats.isDirectory()) {
|
|
40494
40888
|
if (!recursive) {
|
|
40495
40889
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
40496
40890
|
tool: "delete_file"
|
|
40497
40891
|
});
|
|
40498
40892
|
}
|
|
40499
|
-
await
|
|
40893
|
+
await fs35__default.rm(absolutePath, { recursive: true });
|
|
40500
40894
|
} else {
|
|
40501
|
-
await
|
|
40895
|
+
await fs35__default.unlink(absolutePath);
|
|
40502
40896
|
}
|
|
40503
40897
|
return { deleted: true, path: absolutePath };
|
|
40504
40898
|
} catch (error) {
|
|
40505
40899
|
if (error instanceof ToolError) throw error;
|
|
40506
40900
|
if (error.code === "ENOENT") {
|
|
40507
|
-
return { deleted: false, path:
|
|
40901
|
+
return { deleted: false, path: path38__default.resolve(filePath) };
|
|
40508
40902
|
}
|
|
40509
40903
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
40510
40904
|
path: filePath,
|
|
@@ -40532,11 +40926,11 @@ Examples:
|
|
|
40532
40926
|
validatePath(source, "read");
|
|
40533
40927
|
validatePath(destination, "write");
|
|
40534
40928
|
try {
|
|
40535
|
-
const srcPath =
|
|
40536
|
-
const destPath =
|
|
40929
|
+
const srcPath = path38__default.resolve(source);
|
|
40930
|
+
const destPath = path38__default.resolve(destination);
|
|
40537
40931
|
if (!overwrite) {
|
|
40538
40932
|
try {
|
|
40539
|
-
await
|
|
40933
|
+
await fs35__default.access(destPath);
|
|
40540
40934
|
throw new ToolError(
|
|
40541
40935
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
40542
40936
|
{
|
|
@@ -40549,9 +40943,9 @@ Examples:
|
|
|
40549
40943
|
}
|
|
40550
40944
|
}
|
|
40551
40945
|
}
|
|
40552
|
-
await
|
|
40553
|
-
await
|
|
40554
|
-
const stats = await
|
|
40946
|
+
await fs35__default.mkdir(path38__default.dirname(destPath), { recursive: true });
|
|
40947
|
+
await fs35__default.copyFile(srcPath, destPath);
|
|
40948
|
+
const stats = await fs35__default.stat(destPath);
|
|
40555
40949
|
return {
|
|
40556
40950
|
source: srcPath,
|
|
40557
40951
|
destination: destPath,
|
|
@@ -40593,11 +40987,11 @@ Examples:
|
|
|
40593
40987
|
validatePath(source, "delete");
|
|
40594
40988
|
validatePath(destination, "write");
|
|
40595
40989
|
try {
|
|
40596
|
-
const srcPath =
|
|
40597
|
-
const destPath =
|
|
40990
|
+
const srcPath = path38__default.resolve(source);
|
|
40991
|
+
const destPath = path38__default.resolve(destination);
|
|
40598
40992
|
if (!overwrite) {
|
|
40599
40993
|
try {
|
|
40600
|
-
await
|
|
40994
|
+
await fs35__default.access(destPath);
|
|
40601
40995
|
throw new ToolError(
|
|
40602
40996
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
40603
40997
|
{
|
|
@@ -40610,8 +41004,8 @@ Examples:
|
|
|
40610
41004
|
}
|
|
40611
41005
|
}
|
|
40612
41006
|
}
|
|
40613
|
-
await
|
|
40614
|
-
await
|
|
41007
|
+
await fs35__default.mkdir(path38__default.dirname(destPath), { recursive: true });
|
|
41008
|
+
await fs35__default.rename(srcPath, destPath);
|
|
40615
41009
|
return {
|
|
40616
41010
|
source: srcPath,
|
|
40617
41011
|
destination: destPath
|
|
@@ -40680,15 +41074,15 @@ Examples:
|
|
|
40680
41074
|
}),
|
|
40681
41075
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
40682
41076
|
try {
|
|
40683
|
-
const absolutePath =
|
|
41077
|
+
const absolutePath = path38__default.resolve(dirPath ?? ".");
|
|
40684
41078
|
let totalFiles = 0;
|
|
40685
41079
|
let totalDirs = 0;
|
|
40686
|
-
const lines = [
|
|
41080
|
+
const lines = [path38__default.basename(absolutePath) + "/"];
|
|
40687
41081
|
let truncated = false;
|
|
40688
41082
|
async function buildTree(dir, prefix, currentDepth) {
|
|
40689
41083
|
if (currentDepth > (depth ?? 4)) return;
|
|
40690
41084
|
if (lines.length >= MAX_TREE_LINES) return;
|
|
40691
|
-
let items = await
|
|
41085
|
+
let items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
40692
41086
|
items = items.filter((item) => !TREE_IGNORED_DIRS.has(item.name));
|
|
40693
41087
|
if (!showHidden) {
|
|
40694
41088
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
@@ -40713,7 +41107,7 @@ Examples:
|
|
|
40713
41107
|
if (item.isDirectory()) {
|
|
40714
41108
|
totalDirs++;
|
|
40715
41109
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
40716
|
-
await buildTree(
|
|
41110
|
+
await buildTree(path38__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
40717
41111
|
} else {
|
|
40718
41112
|
totalFiles++;
|
|
40719
41113
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -41981,7 +42375,7 @@ Examples:
|
|
|
41981
42375
|
caseSensitive,
|
|
41982
42376
|
wholeWord
|
|
41983
42377
|
}) {
|
|
41984
|
-
const targetPath = searchPath ?
|
|
42378
|
+
const targetPath = searchPath ? path38__default.resolve(searchPath) : process.cwd();
|
|
41985
42379
|
const matches = [];
|
|
41986
42380
|
let filesSearched = 0;
|
|
41987
42381
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -42003,7 +42397,7 @@ Examples:
|
|
|
42003
42397
|
tool: "grep"
|
|
42004
42398
|
});
|
|
42005
42399
|
}
|
|
42006
|
-
const stats = await
|
|
42400
|
+
const stats = await fs35__default.stat(targetPath);
|
|
42007
42401
|
let filesToSearch;
|
|
42008
42402
|
if (stats.isFile()) {
|
|
42009
42403
|
filesToSearch = [targetPath];
|
|
@@ -42025,7 +42419,7 @@ Examples:
|
|
|
42025
42419
|
}
|
|
42026
42420
|
filesSearched++;
|
|
42027
42421
|
try {
|
|
42028
|
-
const content = await
|
|
42422
|
+
const content = await fs35__default.readFile(file, "utf-8");
|
|
42029
42423
|
const lines = content.split("\n");
|
|
42030
42424
|
let fileHasMatch = false;
|
|
42031
42425
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -42048,7 +42442,7 @@ Examples:
|
|
|
42048
42442
|
contextAfter.push(lines[j] ?? "");
|
|
42049
42443
|
}
|
|
42050
42444
|
matches.push({
|
|
42051
|
-
file:
|
|
42445
|
+
file: path38__default.relative(process.cwd(), file),
|
|
42052
42446
|
line: i + 1,
|
|
42053
42447
|
column: match.index + 1,
|
|
42054
42448
|
content: line,
|
|
@@ -42099,8 +42493,8 @@ Examples:
|
|
|
42099
42493
|
}),
|
|
42100
42494
|
async execute({ file, pattern, caseSensitive }) {
|
|
42101
42495
|
try {
|
|
42102
|
-
const absolutePath =
|
|
42103
|
-
const content = await
|
|
42496
|
+
const absolutePath = path38__default.resolve(file);
|
|
42497
|
+
const content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
42104
42498
|
const lines = content.split("\n");
|
|
42105
42499
|
const matches = [];
|
|
42106
42500
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -42118,7 +42512,7 @@ Examples:
|
|
|
42118
42512
|
} catch (error) {
|
|
42119
42513
|
if (error.code === "ENOENT") {
|
|
42120
42514
|
const suggestions = await suggestSimilarFilesDeep(file, process.cwd());
|
|
42121
|
-
const hint = formatSuggestions(suggestions,
|
|
42515
|
+
const hint = formatSuggestions(suggestions, path38__default.dirname(file));
|
|
42122
42516
|
throw new ToolError(`File not found: ${file}${hint}
|
|
42123
42517
|
Use glob to find the correct path.`, {
|
|
42124
42518
|
tool: "find_in_file"
|
|
@@ -42309,7 +42703,7 @@ async function detectPackageManager2(cwd) {
|
|
|
42309
42703
|
];
|
|
42310
42704
|
for (const { file, pm } of lockfiles) {
|
|
42311
42705
|
try {
|
|
42312
|
-
await
|
|
42706
|
+
await fs35__default.access(path38__default.join(cwd, file));
|
|
42313
42707
|
return pm;
|
|
42314
42708
|
} catch {
|
|
42315
42709
|
}
|
|
@@ -42582,7 +42976,7 @@ ${message}
|
|
|
42582
42976
|
});
|
|
42583
42977
|
try {
|
|
42584
42978
|
try {
|
|
42585
|
-
await
|
|
42979
|
+
await fs35__default.access(path38__default.join(projectDir, "Makefile"));
|
|
42586
42980
|
} catch {
|
|
42587
42981
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
42588
42982
|
}
|
|
@@ -42752,7 +43146,7 @@ ${message}
|
|
|
42752
43146
|
});
|
|
42753
43147
|
async function resolveMaven(cwd) {
|
|
42754
43148
|
try {
|
|
42755
|
-
await
|
|
43149
|
+
await fs35__default.access(path38__default.join(cwd, "mvnw"));
|
|
42756
43150
|
return "./mvnw";
|
|
42757
43151
|
} catch {
|
|
42758
43152
|
return "mvn";
|
|
@@ -42760,7 +43154,7 @@ async function resolveMaven(cwd) {
|
|
|
42760
43154
|
}
|
|
42761
43155
|
async function resolveGradle(cwd) {
|
|
42762
43156
|
try {
|
|
42763
|
-
await
|
|
43157
|
+
await fs35__default.access(path38__default.join(cwd, "gradlew"));
|
|
42764
43158
|
return "./gradlew";
|
|
42765
43159
|
} catch {
|
|
42766
43160
|
return "gradle";
|
|
@@ -43627,8 +44021,8 @@ init_review();
|
|
|
43627
44021
|
// src/tools/codebase-map.ts
|
|
43628
44022
|
init_registry4();
|
|
43629
44023
|
init_errors();
|
|
43630
|
-
var
|
|
43631
|
-
var
|
|
44024
|
+
var fs38 = await import('fs/promises');
|
|
44025
|
+
var path41 = await import('path');
|
|
43632
44026
|
var { glob: glob14 } = await import('glob');
|
|
43633
44027
|
var DEFAULT_MAX_FILES = 200;
|
|
43634
44028
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -43654,7 +44048,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
43654
44048
|
"**/*.d.ts"
|
|
43655
44049
|
];
|
|
43656
44050
|
function detectLanguage3(filePath) {
|
|
43657
|
-
const ext =
|
|
44051
|
+
const ext = path41.extname(filePath).toLowerCase();
|
|
43658
44052
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
43659
44053
|
if (extensions.includes(ext)) return lang;
|
|
43660
44054
|
}
|
|
@@ -44063,9 +44457,9 @@ Examples:
|
|
|
44063
44457
|
}),
|
|
44064
44458
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
44065
44459
|
const startTime = performance.now();
|
|
44066
|
-
const absPath =
|
|
44460
|
+
const absPath = path41.resolve(rootPath);
|
|
44067
44461
|
try {
|
|
44068
|
-
const stat2 = await
|
|
44462
|
+
const stat2 = await fs38.stat(absPath);
|
|
44069
44463
|
if (!stat2.isDirectory()) {
|
|
44070
44464
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
44071
44465
|
tool: "codebase_map"
|
|
@@ -44102,14 +44496,14 @@ Examples:
|
|
|
44102
44496
|
let totalDefinitions = 0;
|
|
44103
44497
|
let exportedSymbols = 0;
|
|
44104
44498
|
for (const file of limitedFiles) {
|
|
44105
|
-
const fullPath =
|
|
44499
|
+
const fullPath = path41.join(absPath, file);
|
|
44106
44500
|
const language = detectLanguage3(file);
|
|
44107
44501
|
if (!language) continue;
|
|
44108
44502
|
if (languages && !languages.includes(language)) {
|
|
44109
44503
|
continue;
|
|
44110
44504
|
}
|
|
44111
44505
|
try {
|
|
44112
|
-
const content = await
|
|
44506
|
+
const content = await fs38.readFile(fullPath, "utf-8");
|
|
44113
44507
|
const lineCount = content.split("\n").length;
|
|
44114
44508
|
const parsed = parseFile(content, language);
|
|
44115
44509
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -44146,23 +44540,23 @@ var codebaseMapTools = [codebaseMapTool];
|
|
|
44146
44540
|
init_registry4();
|
|
44147
44541
|
init_errors();
|
|
44148
44542
|
init_paths();
|
|
44149
|
-
var
|
|
44150
|
-
var
|
|
44543
|
+
var fs39 = await import('fs/promises');
|
|
44544
|
+
var path42 = await import('path');
|
|
44151
44545
|
var crypto2 = await import('crypto');
|
|
44152
|
-
var GLOBAL_MEMORIES_DIR =
|
|
44546
|
+
var GLOBAL_MEMORIES_DIR = path42.join(COCO_HOME, "memories");
|
|
44153
44547
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
44154
44548
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
44155
44549
|
async function ensureDir2(dirPath) {
|
|
44156
|
-
await
|
|
44550
|
+
await fs39.mkdir(dirPath, { recursive: true });
|
|
44157
44551
|
}
|
|
44158
44552
|
function getMemoriesDir(scope) {
|
|
44159
44553
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
44160
44554
|
}
|
|
44161
44555
|
async function loadIndex(scope) {
|
|
44162
44556
|
const dir = getMemoriesDir(scope);
|
|
44163
|
-
const indexPath =
|
|
44557
|
+
const indexPath = path42.join(dir, "index.json");
|
|
44164
44558
|
try {
|
|
44165
|
-
const content = await
|
|
44559
|
+
const content = await fs39.readFile(indexPath, "utf-8");
|
|
44166
44560
|
return JSON.parse(content);
|
|
44167
44561
|
} catch {
|
|
44168
44562
|
return [];
|
|
@@ -44171,14 +44565,14 @@ async function loadIndex(scope) {
|
|
|
44171
44565
|
async function saveIndex(scope, index) {
|
|
44172
44566
|
const dir = getMemoriesDir(scope);
|
|
44173
44567
|
await ensureDir2(dir);
|
|
44174
|
-
const indexPath =
|
|
44175
|
-
await
|
|
44568
|
+
const indexPath = path42.join(dir, "index.json");
|
|
44569
|
+
await fs39.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
44176
44570
|
}
|
|
44177
44571
|
async function loadMemory(scope, id) {
|
|
44178
44572
|
const dir = getMemoriesDir(scope);
|
|
44179
|
-
const memPath =
|
|
44573
|
+
const memPath = path42.join(dir, `${id}.json`);
|
|
44180
44574
|
try {
|
|
44181
|
-
const content = await
|
|
44575
|
+
const content = await fs39.readFile(memPath, "utf-8");
|
|
44182
44576
|
return JSON.parse(content);
|
|
44183
44577
|
} catch {
|
|
44184
44578
|
return null;
|
|
@@ -44187,8 +44581,8 @@ async function loadMemory(scope, id) {
|
|
|
44187
44581
|
async function saveMemory(scope, memory) {
|
|
44188
44582
|
const dir = getMemoriesDir(scope);
|
|
44189
44583
|
await ensureDir2(dir);
|
|
44190
|
-
const memPath =
|
|
44191
|
-
await
|
|
44584
|
+
const memPath = path42.join(dir, `${memory.id}.json`);
|
|
44585
|
+
await fs39.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
44192
44586
|
}
|
|
44193
44587
|
var createMemoryTool = defineTool({
|
|
44194
44588
|
name: "create_memory",
|
|
@@ -44344,17 +44738,17 @@ var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
|
44344
44738
|
// src/tools/checkpoint.ts
|
|
44345
44739
|
init_registry4();
|
|
44346
44740
|
init_errors();
|
|
44347
|
-
var
|
|
44741
|
+
var fs40 = await import('fs/promises');
|
|
44348
44742
|
var crypto3 = await import('crypto');
|
|
44349
44743
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
44350
44744
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
44351
44745
|
var STASH_PREFIX = "coco-cp";
|
|
44352
44746
|
async function ensureCocoDir() {
|
|
44353
|
-
await
|
|
44747
|
+
await fs40.mkdir(".coco", { recursive: true });
|
|
44354
44748
|
}
|
|
44355
44749
|
async function loadCheckpoints() {
|
|
44356
44750
|
try {
|
|
44357
|
-
const content = await
|
|
44751
|
+
const content = await fs40.readFile(CHECKPOINT_FILE, "utf-8");
|
|
44358
44752
|
return JSON.parse(content);
|
|
44359
44753
|
} catch {
|
|
44360
44754
|
return [];
|
|
@@ -44362,7 +44756,7 @@ async function loadCheckpoints() {
|
|
|
44362
44756
|
}
|
|
44363
44757
|
async function saveCheckpoints(checkpoints) {
|
|
44364
44758
|
await ensureCocoDir();
|
|
44365
|
-
await
|
|
44759
|
+
await fs40.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
44366
44760
|
}
|
|
44367
44761
|
async function execGit(args) {
|
|
44368
44762
|
const { execaCommand } = await import('execa');
|
|
@@ -44527,8 +44921,8 @@ var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpoi
|
|
|
44527
44921
|
|
|
44528
44922
|
// src/tools/semantic-search.ts
|
|
44529
44923
|
init_registry4();
|
|
44530
|
-
var
|
|
44531
|
-
var
|
|
44924
|
+
var fs41 = await import('fs/promises');
|
|
44925
|
+
var path43 = await import('path');
|
|
44532
44926
|
var { glob: glob15 } = await import('glob');
|
|
44533
44927
|
var INDEX_DIR = ".coco/search-index";
|
|
44534
44928
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -44656,20 +45050,20 @@ async function getEmbedding(text13) {
|
|
|
44656
45050
|
}
|
|
44657
45051
|
async function loadIndex2(indexDir) {
|
|
44658
45052
|
try {
|
|
44659
|
-
const indexPath =
|
|
44660
|
-
const content = await
|
|
45053
|
+
const indexPath = path43.join(indexDir, "index.json");
|
|
45054
|
+
const content = await fs41.readFile(indexPath, "utf-8");
|
|
44661
45055
|
return JSON.parse(content);
|
|
44662
45056
|
} catch {
|
|
44663
45057
|
return null;
|
|
44664
45058
|
}
|
|
44665
45059
|
}
|
|
44666
45060
|
async function saveIndex2(indexDir, index) {
|
|
44667
|
-
await
|
|
44668
|
-
const indexPath =
|
|
44669
|
-
await
|
|
45061
|
+
await fs41.mkdir(indexDir, { recursive: true });
|
|
45062
|
+
const indexPath = path43.join(indexDir, "index.json");
|
|
45063
|
+
await fs41.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
44670
45064
|
}
|
|
44671
45065
|
function isBinary(filePath) {
|
|
44672
|
-
return BINARY_EXTENSIONS.has(
|
|
45066
|
+
return BINARY_EXTENSIONS.has(path43.extname(filePath).toLowerCase());
|
|
44673
45067
|
}
|
|
44674
45068
|
var semanticSearchTool = defineTool({
|
|
44675
45069
|
name: "semantic_search",
|
|
@@ -44694,8 +45088,8 @@ Examples:
|
|
|
44694
45088
|
const effectivePath = rootPath ?? ".";
|
|
44695
45089
|
const effectiveMaxResults = maxResults ?? 10;
|
|
44696
45090
|
const effectiveThreshold = threshold ?? 0.3;
|
|
44697
|
-
const absPath =
|
|
44698
|
-
const indexDir =
|
|
45091
|
+
const absPath = path43.resolve(effectivePath);
|
|
45092
|
+
const indexDir = path43.join(absPath, INDEX_DIR);
|
|
44699
45093
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
44700
45094
|
let warnings = [];
|
|
44701
45095
|
if (!index) {
|
|
@@ -44711,10 +45105,10 @@ Examples:
|
|
|
44711
45105
|
let indexSaveWarning = "";
|
|
44712
45106
|
for (const file of files) {
|
|
44713
45107
|
if (isBinary(file)) continue;
|
|
44714
|
-
const fullPath =
|
|
45108
|
+
const fullPath = path43.join(absPath, file);
|
|
44715
45109
|
try {
|
|
44716
|
-
const stat2 = await
|
|
44717
|
-
const content = await
|
|
45110
|
+
const stat2 = await fs41.stat(fullPath);
|
|
45111
|
+
const content = await fs41.readFile(fullPath, "utf-8");
|
|
44718
45112
|
if (content.length > 1e5) continue;
|
|
44719
45113
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
44720
45114
|
for (const chunk of fileChunks) {
|
|
@@ -44794,8 +45188,8 @@ var semanticSearchTools = [semanticSearchTool];
|
|
|
44794
45188
|
// src/tools/diagram.ts
|
|
44795
45189
|
init_registry4();
|
|
44796
45190
|
init_errors();
|
|
44797
|
-
var
|
|
44798
|
-
var
|
|
45191
|
+
var fs42 = await import('fs/promises');
|
|
45192
|
+
var path44 = await import('path');
|
|
44799
45193
|
var { glob: glob16 } = await import('glob');
|
|
44800
45194
|
async function parseClassRelationships(rootPath, include) {
|
|
44801
45195
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -44808,7 +45202,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
44808
45202
|
const interfaces = [];
|
|
44809
45203
|
for (const file of files.slice(0, 100)) {
|
|
44810
45204
|
try {
|
|
44811
|
-
const content = await
|
|
45205
|
+
const content = await fs42.readFile(path44.join(rootPath, file), "utf-8");
|
|
44812
45206
|
const lines = content.split("\n");
|
|
44813
45207
|
for (let i = 0; i < lines.length; i++) {
|
|
44814
45208
|
const line = lines[i];
|
|
@@ -44927,14 +45321,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
44927
45321
|
};
|
|
44928
45322
|
}
|
|
44929
45323
|
async function generateArchitectureDiagram(rootPath) {
|
|
44930
|
-
const entries = await
|
|
45324
|
+
const entries = await fs42.readdir(rootPath, { withFileTypes: true });
|
|
44931
45325
|
const dirs = entries.filter(
|
|
44932
45326
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
44933
45327
|
);
|
|
44934
45328
|
const lines = ["graph TD"];
|
|
44935
45329
|
let nodeCount = 0;
|
|
44936
45330
|
let edgeCount = 0;
|
|
44937
|
-
const rootName =
|
|
45331
|
+
const rootName = path44.basename(rootPath);
|
|
44938
45332
|
lines.push(` ROOT["${rootName}"]`);
|
|
44939
45333
|
nodeCount++;
|
|
44940
45334
|
for (const dir of dirs) {
|
|
@@ -44944,7 +45338,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
44944
45338
|
nodeCount++;
|
|
44945
45339
|
edgeCount++;
|
|
44946
45340
|
try {
|
|
44947
|
-
const subEntries = await
|
|
45341
|
+
const subEntries = await fs42.readdir(path44.join(rootPath, dir.name), {
|
|
44948
45342
|
withFileTypes: true
|
|
44949
45343
|
});
|
|
44950
45344
|
const subDirs = subEntries.filter(
|
|
@@ -45067,7 +45461,7 @@ Examples:
|
|
|
45067
45461
|
tool: "generate_diagram"
|
|
45068
45462
|
});
|
|
45069
45463
|
}
|
|
45070
|
-
const absPath = rootPath ?
|
|
45464
|
+
const absPath = rootPath ? path44.resolve(rootPath) : process.cwd();
|
|
45071
45465
|
switch (type) {
|
|
45072
45466
|
case "class":
|
|
45073
45467
|
return generateClassDiagram(absPath, include);
|
|
@@ -45132,8 +45526,8 @@ var diagramTools = [generateDiagramTool];
|
|
|
45132
45526
|
// src/tools/pdf.ts
|
|
45133
45527
|
init_registry4();
|
|
45134
45528
|
init_errors();
|
|
45135
|
-
var
|
|
45136
|
-
var
|
|
45529
|
+
var fs43 = await import('fs/promises');
|
|
45530
|
+
var path45 = await import('path');
|
|
45137
45531
|
var DEFAULT_MAX_PAGES = 20;
|
|
45138
45532
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
45139
45533
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -45168,9 +45562,9 @@ Examples:
|
|
|
45168
45562
|
}),
|
|
45169
45563
|
async execute({ path: filePath, pages, maxPages }) {
|
|
45170
45564
|
const startTime = performance.now();
|
|
45171
|
-
const absPath =
|
|
45565
|
+
const absPath = path45.resolve(filePath);
|
|
45172
45566
|
try {
|
|
45173
|
-
const stat2 = await
|
|
45567
|
+
const stat2 = await fs43.stat(absPath);
|
|
45174
45568
|
if (!stat2.isFile()) {
|
|
45175
45569
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
45176
45570
|
tool: "read_pdf"
|
|
@@ -45201,7 +45595,7 @@ Examples:
|
|
|
45201
45595
|
}
|
|
45202
45596
|
try {
|
|
45203
45597
|
const pdfParse = await import('pdf-parse');
|
|
45204
|
-
const dataBuffer = await
|
|
45598
|
+
const dataBuffer = await fs43.readFile(absPath);
|
|
45205
45599
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
45206
45600
|
max: maxPages
|
|
45207
45601
|
});
|
|
@@ -45252,8 +45646,8 @@ var pdfTools = [readPdfTool];
|
|
|
45252
45646
|
// src/tools/image.ts
|
|
45253
45647
|
init_registry4();
|
|
45254
45648
|
init_errors();
|
|
45255
|
-
var
|
|
45256
|
-
var
|
|
45649
|
+
var fs44 = await import('fs/promises');
|
|
45650
|
+
var path46 = await import('path');
|
|
45257
45651
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
45258
45652
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
45259
45653
|
var MIME_TYPES = {
|
|
@@ -45281,15 +45675,15 @@ Examples:
|
|
|
45281
45675
|
async execute({ path: filePath, prompt, provider }) {
|
|
45282
45676
|
const startTime = performance.now();
|
|
45283
45677
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
45284
|
-
const absPath =
|
|
45678
|
+
const absPath = path46.resolve(filePath);
|
|
45285
45679
|
const cwd = process.cwd();
|
|
45286
|
-
if (!absPath.startsWith(cwd +
|
|
45680
|
+
if (!absPath.startsWith(cwd + path46.sep) && absPath !== cwd) {
|
|
45287
45681
|
throw new ToolError(
|
|
45288
45682
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
45289
45683
|
{ tool: "read_image" }
|
|
45290
45684
|
);
|
|
45291
45685
|
}
|
|
45292
|
-
const ext =
|
|
45686
|
+
const ext = path46.extname(absPath).toLowerCase();
|
|
45293
45687
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
45294
45688
|
throw new ToolError(
|
|
45295
45689
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -45297,7 +45691,7 @@ Examples:
|
|
|
45297
45691
|
);
|
|
45298
45692
|
}
|
|
45299
45693
|
try {
|
|
45300
|
-
const stat2 = await
|
|
45694
|
+
const stat2 = await fs44.stat(absPath);
|
|
45301
45695
|
if (!stat2.isFile()) {
|
|
45302
45696
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
45303
45697
|
tool: "read_image"
|
|
@@ -45318,7 +45712,7 @@ Examples:
|
|
|
45318
45712
|
if (error instanceof ToolError) throw error;
|
|
45319
45713
|
throw error;
|
|
45320
45714
|
}
|
|
45321
|
-
const imageBuffer = await
|
|
45715
|
+
const imageBuffer = await fs44.readFile(absPath);
|
|
45322
45716
|
const base64 = imageBuffer.toString("base64");
|
|
45323
45717
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
45324
45718
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -45440,7 +45834,7 @@ var imageTools = [readImageTool];
|
|
|
45440
45834
|
// src/tools/database.ts
|
|
45441
45835
|
init_registry4();
|
|
45442
45836
|
init_errors();
|
|
45443
|
-
var
|
|
45837
|
+
var path47 = await import('path');
|
|
45444
45838
|
var DANGEROUS_PATTERNS = [
|
|
45445
45839
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
45446
45840
|
/\bTRUNCATE\b/i,
|
|
@@ -45471,7 +45865,7 @@ Examples:
|
|
|
45471
45865
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
45472
45866
|
const isReadonly = isReadonlyParam ?? true;
|
|
45473
45867
|
const startTime = performance.now();
|
|
45474
|
-
const absPath =
|
|
45868
|
+
const absPath = path47.resolve(database);
|
|
45475
45869
|
if (isReadonly && isDangerousSql(query)) {
|
|
45476
45870
|
throw new ToolError(
|
|
45477
45871
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -45554,7 +45948,7 @@ Examples:
|
|
|
45554
45948
|
}),
|
|
45555
45949
|
async execute({ database, table }) {
|
|
45556
45950
|
const startTime = performance.now();
|
|
45557
|
-
const absPath =
|
|
45951
|
+
const absPath = path47.resolve(database);
|
|
45558
45952
|
try {
|
|
45559
45953
|
const { default: Database } = await import('better-sqlite3');
|
|
45560
45954
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -45737,14 +46131,14 @@ var astValidatorTools = [validateCodeTool, findMissingImportsTool];
|
|
|
45737
46131
|
|
|
45738
46132
|
// src/tools/code-analyzer.ts
|
|
45739
46133
|
init_registry4();
|
|
45740
|
-
var
|
|
45741
|
-
var
|
|
46134
|
+
var fs45 = await import('fs/promises');
|
|
46135
|
+
var path48 = await import('path');
|
|
45742
46136
|
var AnalyzeFileSchema = z.object({
|
|
45743
46137
|
filePath: z.string().describe("Path to file to analyze"),
|
|
45744
46138
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
45745
46139
|
});
|
|
45746
46140
|
async function analyzeFile(filePath, includeAst = false) {
|
|
45747
|
-
const content = await
|
|
46141
|
+
const content = await fs45.readFile(filePath, "utf-8");
|
|
45748
46142
|
const lines = content.split("\n").length;
|
|
45749
46143
|
const functions = [];
|
|
45750
46144
|
const classes = [];
|
|
@@ -45848,10 +46242,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
45848
46242
|
try {
|
|
45849
46243
|
const analysis = await analyzeFile(file, false);
|
|
45850
46244
|
totalLines += analysis.lines;
|
|
45851
|
-
const ext =
|
|
46245
|
+
const ext = path48.extname(file);
|
|
45852
46246
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
45853
46247
|
fileStats.push({
|
|
45854
|
-
file:
|
|
46248
|
+
file: path48.relative(dirPath, file),
|
|
45855
46249
|
lines: analysis.lines,
|
|
45856
46250
|
complexity: analysis.complexity.cyclomatic
|
|
45857
46251
|
});
|
|
@@ -46222,13 +46616,13 @@ var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateRes
|
|
|
46222
46616
|
|
|
46223
46617
|
// src/tools/smart-suggestions.ts
|
|
46224
46618
|
init_registry4();
|
|
46225
|
-
var
|
|
46619
|
+
var fs46 = await import('fs/promises');
|
|
46226
46620
|
var SuggestImprovementsSchema = z.object({
|
|
46227
46621
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
46228
46622
|
context: z.string().optional().describe("Additional context about the code")
|
|
46229
46623
|
});
|
|
46230
46624
|
async function analyzeAndSuggest(filePath, _context) {
|
|
46231
|
-
const content = await
|
|
46625
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
46232
46626
|
const lines = content.split("\n");
|
|
46233
46627
|
const suggestions = [];
|
|
46234
46628
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -46320,7 +46714,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
46320
46714
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
46321
46715
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
46322
46716
|
try {
|
|
46323
|
-
await
|
|
46717
|
+
await fs46.access(testPath);
|
|
46324
46718
|
} catch {
|
|
46325
46719
|
suggestions.push({
|
|
46326
46720
|
type: "testing",
|
|
@@ -46377,7 +46771,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
46377
46771
|
async execute(input) {
|
|
46378
46772
|
const { filePath } = input;
|
|
46379
46773
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
46380
|
-
const content = await
|
|
46774
|
+
const content = await fs46.readFile(filePath, "utf-8");
|
|
46381
46775
|
const lines = content.split("\n");
|
|
46382
46776
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
46383
46777
|
let score = 100;
|
|
@@ -46414,8 +46808,8 @@ var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
|
46414
46808
|
|
|
46415
46809
|
// src/tools/context-enhancer.ts
|
|
46416
46810
|
init_registry4();
|
|
46417
|
-
var
|
|
46418
|
-
var
|
|
46811
|
+
var fs47 = await import('fs/promises');
|
|
46812
|
+
var path49 = await import('path');
|
|
46419
46813
|
var ContextMemoryStore = class {
|
|
46420
46814
|
items = /* @__PURE__ */ new Map();
|
|
46421
46815
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -46427,7 +46821,7 @@ var ContextMemoryStore = class {
|
|
|
46427
46821
|
}
|
|
46428
46822
|
async load() {
|
|
46429
46823
|
try {
|
|
46430
|
-
const content = await
|
|
46824
|
+
const content = await fs47.readFile(this.storePath, "utf-8");
|
|
46431
46825
|
const data = JSON.parse(content);
|
|
46432
46826
|
this.items = new Map(Object.entries(data.items || {}));
|
|
46433
46827
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -46435,15 +46829,15 @@ var ContextMemoryStore = class {
|
|
|
46435
46829
|
}
|
|
46436
46830
|
}
|
|
46437
46831
|
async save() {
|
|
46438
|
-
const dir =
|
|
46439
|
-
await
|
|
46832
|
+
const dir = path49.dirname(this.storePath);
|
|
46833
|
+
await fs47.mkdir(dir, { recursive: true });
|
|
46440
46834
|
const data = {
|
|
46441
46835
|
sessionId: this.sessionId,
|
|
46442
46836
|
items: Object.fromEntries(this.items),
|
|
46443
46837
|
learnings: Object.fromEntries(this.learnings),
|
|
46444
46838
|
savedAt: Date.now()
|
|
46445
46839
|
};
|
|
46446
|
-
await
|
|
46840
|
+
await fs47.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
46447
46841
|
}
|
|
46448
46842
|
addContext(id, item) {
|
|
46449
46843
|
this.items.set(id, item);
|
|
@@ -46611,11 +47005,11 @@ var contextEnhancerTools = [
|
|
|
46611
47005
|
|
|
46612
47006
|
// src/tools/skill-enhancer.ts
|
|
46613
47007
|
init_registry4();
|
|
46614
|
-
var
|
|
46615
|
-
var
|
|
47008
|
+
var fs48 = await import('fs/promises');
|
|
47009
|
+
var path50 = await import('path');
|
|
46616
47010
|
async function discoverSkills(skillsDir) {
|
|
46617
47011
|
try {
|
|
46618
|
-
const files = await
|
|
47012
|
+
const files = await fs48.readdir(skillsDir);
|
|
46619
47013
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
46620
47014
|
} catch {
|
|
46621
47015
|
return [];
|
|
@@ -46623,12 +47017,12 @@ async function discoverSkills(skillsDir) {
|
|
|
46623
47017
|
}
|
|
46624
47018
|
async function loadSkillMetadata(skillPath) {
|
|
46625
47019
|
try {
|
|
46626
|
-
const content = await
|
|
47020
|
+
const content = await fs48.readFile(skillPath, "utf-8");
|
|
46627
47021
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
46628
47022
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
46629
47023
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
46630
47024
|
return {
|
|
46631
|
-
name: nameMatch?.[1] ||
|
|
47025
|
+
name: nameMatch?.[1] || path50.basename(skillPath, path50.extname(skillPath)),
|
|
46632
47026
|
description: descMatch?.[1] || "No description",
|
|
46633
47027
|
version: versionMatch?.[1] || "1.0.0",
|
|
46634
47028
|
dependencies: []
|
|
@@ -46672,7 +47066,7 @@ var discoverSkillsTool = defineTool({
|
|
|
46672
47066
|
const { skillsDir } = input;
|
|
46673
47067
|
const skills = await discoverSkills(skillsDir);
|
|
46674
47068
|
const metadata = await Promise.all(
|
|
46675
|
-
skills.map((s) => loadSkillMetadata(
|
|
47069
|
+
skills.map((s) => loadSkillMetadata(path50.join(skillsDir, s)))
|
|
46676
47070
|
);
|
|
46677
47071
|
return {
|
|
46678
47072
|
skillsDir,
|
|
@@ -46843,7 +47237,7 @@ Examples:
|
|
|
46843
47237
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
46844
47238
|
}),
|
|
46845
47239
|
async execute({ path: dirPath, reason }) {
|
|
46846
|
-
const absolute =
|
|
47240
|
+
const absolute = path38__default.resolve(dirPath);
|
|
46847
47241
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
46848
47242
|
return {
|
|
46849
47243
|
authorized: true,
|
|
@@ -46852,8 +47246,8 @@ Examples:
|
|
|
46852
47246
|
};
|
|
46853
47247
|
}
|
|
46854
47248
|
for (const blocked of BLOCKED_SYSTEM_PATHS2) {
|
|
46855
|
-
const normalizedBlocked =
|
|
46856
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
47249
|
+
const normalizedBlocked = path38__default.normalize(blocked);
|
|
47250
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path38__default.sep)) {
|
|
46857
47251
|
return {
|
|
46858
47252
|
authorized: false,
|
|
46859
47253
|
path: absolute,
|
|
@@ -46862,7 +47256,7 @@ Examples:
|
|
|
46862
47256
|
}
|
|
46863
47257
|
}
|
|
46864
47258
|
const cwd = process.cwd();
|
|
46865
|
-
if (absolute ===
|
|
47259
|
+
if (absolute === path38__default.normalize(cwd) || absolute.startsWith(path38__default.normalize(cwd) + path38__default.sep)) {
|
|
46866
47260
|
return {
|
|
46867
47261
|
authorized: true,
|
|
46868
47262
|
path: absolute,
|
|
@@ -46870,7 +47264,7 @@ Examples:
|
|
|
46870
47264
|
};
|
|
46871
47265
|
}
|
|
46872
47266
|
try {
|
|
46873
|
-
const stat2 = await
|
|
47267
|
+
const stat2 = await fs35__default.stat(absolute);
|
|
46874
47268
|
if (!stat2.isDirectory()) {
|
|
46875
47269
|
return {
|
|
46876
47270
|
authorized: false,
|
|
@@ -46886,7 +47280,7 @@ Examples:
|
|
|
46886
47280
|
};
|
|
46887
47281
|
}
|
|
46888
47282
|
const existing = getAllowedPaths();
|
|
46889
|
-
if (existing.some((e) =>
|
|
47283
|
+
if (existing.some((e) => path38__default.normalize(e.path) === path38__default.normalize(absolute))) {
|
|
46890
47284
|
return {
|
|
46891
47285
|
authorized: true,
|
|
46892
47286
|
path: absolute,
|
|
@@ -46971,9 +47365,9 @@ async function runSprints(options) {
|
|
|
46971
47365
|
Object.entries(AGENT_ROLES).map(([role, def]) => [role, { ...def, maxTurns: 20 }])
|
|
46972
47366
|
);
|
|
46973
47367
|
const coordinator = createAgentCoordinator(executor, agentDefsMap);
|
|
46974
|
-
await
|
|
46975
|
-
const sprintsDir =
|
|
46976
|
-
await
|
|
47368
|
+
await fs35__default.mkdir(spec.outputPath, { recursive: true });
|
|
47369
|
+
const sprintsDir = path38__default.join(spec.outputPath, ".coco", "sprints");
|
|
47370
|
+
await fs35__default.mkdir(sprintsDir, { recursive: true });
|
|
46977
47371
|
for (const sprint of spec.sprints) {
|
|
46978
47372
|
onProgress(`Starting ${sprint.id}: ${sprint.name}`);
|
|
46979
47373
|
const sprintStart = Date.now();
|
|
@@ -47226,8 +47620,8 @@ Assess: overall architecture, consistency, error handling, and production readin
|
|
|
47226
47620
|
};
|
|
47227
47621
|
}
|
|
47228
47622
|
async function saveSprintResult(sprintsDir, result) {
|
|
47229
|
-
const filePath =
|
|
47230
|
-
await
|
|
47623
|
+
const filePath = path38__default.join(sprintsDir, `${result.sprintId}.json`);
|
|
47624
|
+
await fs35__default.writeFile(filePath, JSON.stringify(result, null, 2), "utf-8");
|
|
47231
47625
|
}
|
|
47232
47626
|
|
|
47233
47627
|
// src/cli/repl/commands/build-app.ts
|
|
@@ -47252,9 +47646,9 @@ function parseArgs6(args) {
|
|
|
47252
47646
|
return { description, specFile, outputDir, skipConfirmation };
|
|
47253
47647
|
}
|
|
47254
47648
|
function isWithinRoot(resolvedPath, rootDir) {
|
|
47255
|
-
const normalRoot =
|
|
47256
|
-
const normalPath =
|
|
47257
|
-
return normalPath ===
|
|
47649
|
+
const normalRoot = path38__default.normalize(rootDir) + path38__default.sep;
|
|
47650
|
+
const normalPath = path38__default.normalize(resolvedPath);
|
|
47651
|
+
return normalPath === path38__default.normalize(rootDir) || normalPath.startsWith(normalRoot);
|
|
47258
47652
|
}
|
|
47259
47653
|
var buildAppCommand = {
|
|
47260
47654
|
name: "build-app",
|
|
@@ -47277,20 +47671,20 @@ var buildAppCommand = {
|
|
|
47277
47671
|
}
|
|
47278
47672
|
let initialDescription = parsed.description;
|
|
47279
47673
|
if (parsed.specFile) {
|
|
47280
|
-
const specPath =
|
|
47674
|
+
const specPath = path38__default.resolve(session.projectPath, parsed.specFile);
|
|
47281
47675
|
if (!isWithinRoot(specPath, session.projectPath)) {
|
|
47282
47676
|
p26.log.error(`--spec path must be within the project directory: ${specPath}`);
|
|
47283
47677
|
return false;
|
|
47284
47678
|
}
|
|
47285
47679
|
try {
|
|
47286
|
-
initialDescription = await
|
|
47680
|
+
initialDescription = await fs35__default.readFile(specPath, "utf-8");
|
|
47287
47681
|
} catch (err) {
|
|
47288
47682
|
const msg = err instanceof Error ? err.message : String(err);
|
|
47289
47683
|
p26.log.error(`Error reading spec file: ${msg}`);
|
|
47290
47684
|
return false;
|
|
47291
47685
|
}
|
|
47292
47686
|
}
|
|
47293
|
-
const outputPath = parsed.outputDir ?
|
|
47687
|
+
const outputPath = parsed.outputDir ? path38__default.resolve(session.projectPath, parsed.outputDir) : path38__default.join(session.projectPath, "build-app-output");
|
|
47294
47688
|
if (parsed.outputDir && !isWithinRoot(outputPath, session.projectPath)) {
|
|
47295
47689
|
p26.log.error(`--output path must be within the project directory: ${outputPath}`);
|
|
47296
47690
|
return false;
|
|
@@ -47454,7 +47848,7 @@ function buildProgressBar(pct) {
|
|
|
47454
47848
|
|
|
47455
47849
|
// src/cli/repl/worktree/manager.ts
|
|
47456
47850
|
init_logger();
|
|
47457
|
-
var
|
|
47851
|
+
var execFileAsync3 = promisify(execFile);
|
|
47458
47852
|
var WORKTREES_DIR = ".worktrees";
|
|
47459
47853
|
var WorktreeManager = class {
|
|
47460
47854
|
worktrees = /* @__PURE__ */ new Map();
|
|
@@ -47474,7 +47868,7 @@ var WorktreeManager = class {
|
|
|
47474
47868
|
const id = randomUUID();
|
|
47475
47869
|
const branchPrefix = options.branchPrefix ?? "coco-agent";
|
|
47476
47870
|
const branchName = `${branchPrefix}/${name}-${id.slice(0, 8)}`;
|
|
47477
|
-
const worktreePath =
|
|
47871
|
+
const worktreePath = path38__default.join(this.projectRoot, WORKTREES_DIR, `${name}-${id.slice(0, 8)}`);
|
|
47478
47872
|
const worktree = {
|
|
47479
47873
|
id,
|
|
47480
47874
|
name,
|
|
@@ -47485,7 +47879,7 @@ var WorktreeManager = class {
|
|
|
47485
47879
|
};
|
|
47486
47880
|
this.worktrees.set(id, worktree);
|
|
47487
47881
|
try {
|
|
47488
|
-
await
|
|
47882
|
+
await fs35__default.mkdir(path38__default.join(this.projectRoot, WORKTREES_DIR), { recursive: true });
|
|
47489
47883
|
const baseBranch = options.baseBranch ?? "HEAD";
|
|
47490
47884
|
await this.git(["worktree", "add", "-b", branchName, worktreePath, baseBranch]);
|
|
47491
47885
|
worktree.status = "active";
|
|
@@ -47678,7 +48072,7 @@ var WorktreeManager = class {
|
|
|
47678
48072
|
try {
|
|
47679
48073
|
await this.git(["push", "-u", "origin", worktree.branch]);
|
|
47680
48074
|
const title = options.message ?? `Agent: ${worktree.name}`;
|
|
47681
|
-
const { stdout } = await
|
|
48075
|
+
const { stdout } = await execFileAsync3(
|
|
47682
48076
|
"gh",
|
|
47683
48077
|
[
|
|
47684
48078
|
"pr",
|
|
@@ -47704,10 +48098,10 @@ var WorktreeManager = class {
|
|
|
47704
48098
|
}
|
|
47705
48099
|
// ── Helpers ──────────────────────────────────────────────────────
|
|
47706
48100
|
async git(args) {
|
|
47707
|
-
return
|
|
48101
|
+
return execFileAsync3("git", args, { cwd: this.projectRoot });
|
|
47708
48102
|
}
|
|
47709
48103
|
async gitIn(cwd, args) {
|
|
47710
|
-
return
|
|
48104
|
+
return execFileAsync3("git", args, { cwd });
|
|
47711
48105
|
}
|
|
47712
48106
|
async countChangedFiles(branch) {
|
|
47713
48107
|
try {
|
|
@@ -47732,7 +48126,7 @@ var DEFAULT_CONFIG5 = {
|
|
|
47732
48126
|
};
|
|
47733
48127
|
async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
47734
48128
|
const cfg = { ...DEFAULT_CONFIG5, ...config };
|
|
47735
|
-
const
|
|
48129
|
+
const logger2 = getLogger();
|
|
47736
48130
|
const startTime = Date.now();
|
|
47737
48131
|
if (cfg.attempts < 2) {
|
|
47738
48132
|
return {
|
|
@@ -47755,7 +48149,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47755
48149
|
const worktreeManager = new WorktreeManager(projectRoot);
|
|
47756
48150
|
const attempts = [];
|
|
47757
48151
|
try {
|
|
47758
|
-
|
|
48152
|
+
logger2.info(`Best-of-N: Creating ${cfg.attempts} worktrees...`);
|
|
47759
48153
|
const worktrees = await Promise.all(
|
|
47760
48154
|
Array.from(
|
|
47761
48155
|
{ length: cfg.attempts },
|
|
@@ -47779,7 +48173,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47779
48173
|
durationMs: 0
|
|
47780
48174
|
});
|
|
47781
48175
|
}
|
|
47782
|
-
|
|
48176
|
+
logger2.info(`Best-of-N: Running ${cfg.attempts} parallel attempts...`);
|
|
47783
48177
|
await Promise.all(
|
|
47784
48178
|
attempts.map(async (attempt) => {
|
|
47785
48179
|
const attemptStart = Date.now();
|
|
@@ -47833,7 +48227,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47833
48227
|
attempt.status = "discarded";
|
|
47834
48228
|
}
|
|
47835
48229
|
}
|
|
47836
|
-
|
|
48230
|
+
logger2.info(`Best-of-N: Winner is attempt #${winner.index} with score ${winner.score}`);
|
|
47837
48231
|
for (const attempt of attempts) {
|
|
47838
48232
|
if (attempt.id !== winner.id) {
|
|
47839
48233
|
try {
|
|
@@ -47848,7 +48242,7 @@ async function runBestOfN(projectRoot, executor, config, callbacks = {}) {
|
|
|
47848
48242
|
message: `Best-of-N winner (attempt #${winner.index}, score: ${winner.score})`
|
|
47849
48243
|
});
|
|
47850
48244
|
if (!mergeResult.success) {
|
|
47851
|
-
|
|
48245
|
+
logger2.warn(`Best-of-N: Auto-merge failed: ${mergeResult.error}`);
|
|
47852
48246
|
}
|
|
47853
48247
|
}
|
|
47854
48248
|
return {
|
|
@@ -48831,8 +49225,8 @@ function formatToolSummary(toolName, input) {
|
|
|
48831
49225
|
case "grep":
|
|
48832
49226
|
case "search_files": {
|
|
48833
49227
|
const pattern = String(input.pattern || "");
|
|
48834
|
-
const
|
|
48835
|
-
return `"${pattern}"${
|
|
49228
|
+
const path60 = input.path ? ` in ${input.path}` : "";
|
|
49229
|
+
return `"${pattern}"${path60}`;
|
|
48836
49230
|
}
|
|
48837
49231
|
case "bash_exec": {
|
|
48838
49232
|
const cmd = String(input.command || "");
|
|
@@ -48853,8 +49247,8 @@ function formatToolSummary(toolName, input) {
|
|
|
48853
49247
|
function formatUrl(url) {
|
|
48854
49248
|
try {
|
|
48855
49249
|
const u = new URL(url);
|
|
48856
|
-
const
|
|
48857
|
-
const display =
|
|
49250
|
+
const path60 = u.pathname.replace(/\/$/, "");
|
|
49251
|
+
const display = path60 ? `${u.hostname} \u203A ${path60.slice(1)}` : u.hostname;
|
|
48858
49252
|
const max = Math.max(getTerminalWidth2() - 20, 50);
|
|
48859
49253
|
return display.length > max ? display.slice(0, max - 1) + "\u2026" : display;
|
|
48860
49254
|
} catch {
|
|
@@ -49084,7 +49478,7 @@ function getAllCommands() {
|
|
|
49084
49478
|
}
|
|
49085
49479
|
|
|
49086
49480
|
// src/cli/repl/input/handler.ts
|
|
49087
|
-
var HISTORY_FILE =
|
|
49481
|
+
var HISTORY_FILE = path38.join(os4.homedir(), ".coco", "history");
|
|
49088
49482
|
async function handleOptionC(copyFn = copyToClipboard, getLastBlockFn = getLastBlock) {
|
|
49089
49483
|
const block = getLastBlockFn();
|
|
49090
49484
|
if (!block) return null;
|
|
@@ -49105,7 +49499,7 @@ function loadHistory() {
|
|
|
49105
49499
|
}
|
|
49106
49500
|
function saveHistory(history) {
|
|
49107
49501
|
try {
|
|
49108
|
-
const dir =
|
|
49502
|
+
const dir = path38.dirname(HISTORY_FILE);
|
|
49109
49503
|
if (!fs5.existsSync(dir)) {
|
|
49110
49504
|
fs5.mkdirSync(dir, { recursive: true });
|
|
49111
49505
|
}
|
|
@@ -50459,7 +50853,7 @@ function formatDiffPreview(toolCall) {
|
|
|
50459
50853
|
}
|
|
50460
50854
|
async function checkFileExists(filePath) {
|
|
50461
50855
|
try {
|
|
50462
|
-
await
|
|
50856
|
+
await fs35__default.access(filePath);
|
|
50463
50857
|
return true;
|
|
50464
50858
|
} catch {
|
|
50465
50859
|
return false;
|
|
@@ -52256,7 +52650,7 @@ function formatContextUsage(percent) {
|
|
|
52256
52650
|
}
|
|
52257
52651
|
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
52258
52652
|
const parts = [];
|
|
52259
|
-
const projectName =
|
|
52653
|
+
const projectName = path38__default.basename(projectPath);
|
|
52260
52654
|
parts.push(chalk.dim("\u{1F4C1} ") + chalk.magenta(projectName));
|
|
52261
52655
|
const providerName = config.provider.type;
|
|
52262
52656
|
const modelName = config.provider.model || "default";
|
|
@@ -52361,13 +52755,13 @@ async function startRepl(options = {}) {
|
|
|
52361
52755
|
}
|
|
52362
52756
|
await session.skillRegistry.discoverAndRegister(projectPath, getBuiltinSkillsForDiscovery2());
|
|
52363
52757
|
} catch (skillError) {
|
|
52364
|
-
const
|
|
52365
|
-
|
|
52758
|
+
const logger3 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
52759
|
+
logger3.warn(
|
|
52366
52760
|
`[Skills] Failed to initialize skills: ${skillError instanceof Error ? skillError.message : String(skillError)}`
|
|
52367
52761
|
);
|
|
52368
52762
|
}
|
|
52369
52763
|
let mcpManager = null;
|
|
52370
|
-
const
|
|
52764
|
+
const logger2 = (await Promise.resolve().then(() => (init_logger(), logger_exports))).getLogger();
|
|
52371
52765
|
try {
|
|
52372
52766
|
const { getMCPServerManager: getMCPServerManager2 } = await Promise.resolve().then(() => (init_lifecycle(), lifecycle_exports));
|
|
52373
52767
|
const { MCPRegistryImpl: MCPRegistryImpl2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
|
|
@@ -52387,7 +52781,7 @@ async function startRepl(options = {}) {
|
|
|
52387
52781
|
try {
|
|
52388
52782
|
connections = await mcpManager.startAll(enabledServers);
|
|
52389
52783
|
} catch (startError) {
|
|
52390
|
-
|
|
52784
|
+
logger2.warn(
|
|
52391
52785
|
`[MCP] Failed to start servers: ${startError instanceof Error ? startError.message : String(startError)}`
|
|
52392
52786
|
);
|
|
52393
52787
|
try {
|
|
@@ -52401,18 +52795,18 @@ async function startRepl(options = {}) {
|
|
|
52401
52795
|
try {
|
|
52402
52796
|
await registerMCPTools2(toolRegistry, connection.name, connection.client);
|
|
52403
52797
|
} catch (toolError) {
|
|
52404
|
-
|
|
52798
|
+
logger2.warn(
|
|
52405
52799
|
`[MCP] Failed to register tools for server '${connection.name}': ${toolError instanceof Error ? toolError.message : String(toolError)}`
|
|
52406
52800
|
);
|
|
52407
52801
|
}
|
|
52408
52802
|
}
|
|
52409
52803
|
const activeCount = connections.size;
|
|
52410
52804
|
if (activeCount > 0) {
|
|
52411
|
-
|
|
52805
|
+
logger2.info(`[MCP] ${activeCount} MCP server(s) active`);
|
|
52412
52806
|
}
|
|
52413
52807
|
}
|
|
52414
52808
|
} catch (mcpError) {
|
|
52415
|
-
|
|
52809
|
+
logger2.warn(
|
|
52416
52810
|
`[MCP] Initialization failed: ${mcpError instanceof Error ? mcpError.message : String(mcpError)}`
|
|
52417
52811
|
);
|
|
52418
52812
|
}
|
|
@@ -52426,12 +52820,12 @@ async function startRepl(options = {}) {
|
|
|
52426
52820
|
if (registry.size > 0) {
|
|
52427
52821
|
hookRegistry = registry;
|
|
52428
52822
|
hookExecutor = createHookExecutor2();
|
|
52429
|
-
|
|
52823
|
+
logger2.info(`[Hooks] Loaded ${registry.size} hook(s) from ${hooksConfigPath}`);
|
|
52430
52824
|
}
|
|
52431
52825
|
} catch (hookError) {
|
|
52432
52826
|
const msg = hookError instanceof Error ? hookError.message : String(hookError);
|
|
52433
52827
|
if (!msg.includes("ENOENT")) {
|
|
52434
|
-
|
|
52828
|
+
logger2.warn(`[Hooks] Failed to load hooks: ${msg}`);
|
|
52435
52829
|
}
|
|
52436
52830
|
}
|
|
52437
52831
|
const inputHandler = createInputHandler();
|