@corbat-tech/coco 2.25.7 → 2.25.8
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 +748 -584
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +2692 -202
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
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 path39 from 'path';
|
|
5
|
+
import path39__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';
|
|
@@ -612,7 +612,7 @@ function deepMergeConfig(base, override) {
|
|
|
612
612
|
};
|
|
613
613
|
}
|
|
614
614
|
function getProjectConfigPath() {
|
|
615
|
-
return
|
|
615
|
+
return path39__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,7 +627,7 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
627
627
|
});
|
|
628
628
|
}
|
|
629
629
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath());
|
|
630
|
-
const dir =
|
|
630
|
+
const dir = path39__default.dirname(resolvedPath);
|
|
631
631
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
632
632
|
const content = JSON.stringify(result.data, null, 2);
|
|
633
633
|
await fs35__default.writeFile(resolvedPath, content, "utf-8");
|
|
@@ -645,7 +645,7 @@ async function findConfigPath(cwd) {
|
|
|
645
645
|
}
|
|
646
646
|
}
|
|
647
647
|
const basePath = cwd || process.cwd();
|
|
648
|
-
const projectConfigPath =
|
|
648
|
+
const projectConfigPath = path39__default.join(basePath, ".coco", "config.json");
|
|
649
649
|
try {
|
|
650
650
|
await fs35__default.access(projectConfigPath);
|
|
651
651
|
return projectConfigPath;
|
|
@@ -666,7 +666,7 @@ async function findAllConfigPaths(cwd) {
|
|
|
666
666
|
} catch {
|
|
667
667
|
}
|
|
668
668
|
const basePath = cwd || process.cwd();
|
|
669
|
-
const projectConfigPath =
|
|
669
|
+
const projectConfigPath = path39__default.join(basePath, ".coco", "config.json");
|
|
670
670
|
try {
|
|
671
671
|
await fs35__default.access(projectConfigPath);
|
|
672
672
|
result.project = projectConfigPath;
|
|
@@ -879,11 +879,11 @@ 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 path39.join(home, ".coco", "tokens", `${provider}.json`);
|
|
883
883
|
}
|
|
884
884
|
async function saveTokens(provider, tokens) {
|
|
885
885
|
const filePath = getTokenStoragePath(provider);
|
|
886
|
-
const dir =
|
|
886
|
+
const dir = path39.dirname(filePath);
|
|
887
887
|
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
888
888
|
await fs35.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
889
889
|
}
|
|
@@ -1479,11 +1479,11 @@ function getCopilotBaseUrl(accountType) {
|
|
|
1479
1479
|
}
|
|
1480
1480
|
function getCopilotCredentialsPath() {
|
|
1481
1481
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
1482
|
-
return
|
|
1482
|
+
return path39.join(home, ".coco", "tokens", "copilot.json");
|
|
1483
1483
|
}
|
|
1484
1484
|
async function saveCopilotCredentials(creds) {
|
|
1485
1485
|
const filePath = getCopilotCredentialsPath();
|
|
1486
|
-
const dir =
|
|
1486
|
+
const dir = path39.dirname(filePath);
|
|
1487
1487
|
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
1488
1488
|
await fs35.writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
1489
1489
|
}
|
|
@@ -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 path39.join(home, ".config", "gcloud", "application_default_credentials.json");
|
|
2243
2243
|
}
|
|
2244
2244
|
async function isGcloudInstalled() {
|
|
2245
2245
|
try {
|
|
@@ -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 = path39.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 = path39.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 = path39.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 = path39.join(home, ".coco", "preferences.json");
|
|
2683
2683
|
let oldPrefs = null;
|
|
2684
2684
|
try {
|
|
2685
2685
|
const content = await fs5.promises.readFile(oldPrefsPath, "utf-8");
|
|
@@ -2871,7 +2871,7 @@ 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 =
|
|
2874
|
+
const logFile = path39__default.join(logDir, `${name}.log`);
|
|
2875
2875
|
logger2.attachTransport((logObj) => {
|
|
2876
2876
|
const line = JSON.stringify(logObj) + "\n";
|
|
2877
2877
|
fs5__default.appendFileSync(logFile, line);
|
|
@@ -2890,7 +2890,7 @@ function setLogger(logger2) {
|
|
|
2890
2890
|
globalLogger = logger2;
|
|
2891
2891
|
}
|
|
2892
2892
|
function initializeLogging(projectPath, level = "info") {
|
|
2893
|
-
const logDir =
|
|
2893
|
+
const logDir = path39__default.join(projectPath, ".coco", "logs");
|
|
2894
2894
|
const logger2 = createLogger({
|
|
2895
2895
|
name: "coco",
|
|
2896
2896
|
level,
|
|
@@ -7186,6 +7186,251 @@ var init_config = __esm({
|
|
|
7186
7186
|
}
|
|
7187
7187
|
});
|
|
7188
7188
|
|
|
7189
|
+
// src/mcp/config-loader.ts
|
|
7190
|
+
var config_loader_exports = {};
|
|
7191
|
+
__export(config_loader_exports, {
|
|
7192
|
+
loadMCPConfigFile: () => loadMCPConfigFile,
|
|
7193
|
+
loadMCPServersFromCOCOConfig: () => loadMCPServersFromCOCOConfig,
|
|
7194
|
+
loadProjectMCPFile: () => loadProjectMCPFile,
|
|
7195
|
+
mergeMCPConfigs: () => mergeMCPConfigs
|
|
7196
|
+
});
|
|
7197
|
+
function expandEnvVar(value) {
|
|
7198
|
+
return value.replace(/\$\{([^}]+)\}/g, (match, name) => process.env[name] ?? match);
|
|
7199
|
+
}
|
|
7200
|
+
function expandEnvObject(env2) {
|
|
7201
|
+
const result = {};
|
|
7202
|
+
for (const [k, v] of Object.entries(env2)) {
|
|
7203
|
+
result[k] = expandEnvVar(v);
|
|
7204
|
+
}
|
|
7205
|
+
return result;
|
|
7206
|
+
}
|
|
7207
|
+
function expandHeaders(headers) {
|
|
7208
|
+
const result = {};
|
|
7209
|
+
for (const [k, v] of Object.entries(headers)) {
|
|
7210
|
+
result[k] = expandEnvVar(v);
|
|
7211
|
+
}
|
|
7212
|
+
return result;
|
|
7213
|
+
}
|
|
7214
|
+
function convertStandardEntry(name, entry) {
|
|
7215
|
+
if (entry.command) {
|
|
7216
|
+
return {
|
|
7217
|
+
name,
|
|
7218
|
+
transport: "stdio",
|
|
7219
|
+
enabled: entry.enabled ?? true,
|
|
7220
|
+
stdio: {
|
|
7221
|
+
command: entry.command,
|
|
7222
|
+
args: entry.args,
|
|
7223
|
+
env: entry.env ? expandEnvObject(entry.env) : void 0
|
|
7224
|
+
}
|
|
7225
|
+
};
|
|
7226
|
+
}
|
|
7227
|
+
if (entry.url) {
|
|
7228
|
+
const headers = entry.headers ? expandHeaders(entry.headers) : void 0;
|
|
7229
|
+
const authHeader = headers?.["Authorization"] ?? headers?.["authorization"];
|
|
7230
|
+
let auth;
|
|
7231
|
+
if (authHeader) {
|
|
7232
|
+
if (authHeader.startsWith("Bearer ")) {
|
|
7233
|
+
auth = { type: "bearer", token: authHeader.slice(7) };
|
|
7234
|
+
} else {
|
|
7235
|
+
auth = { type: "apikey", token: authHeader };
|
|
7236
|
+
}
|
|
7237
|
+
}
|
|
7238
|
+
return {
|
|
7239
|
+
name,
|
|
7240
|
+
transport: "http",
|
|
7241
|
+
enabled: entry.enabled ?? true,
|
|
7242
|
+
http: {
|
|
7243
|
+
url: entry.url,
|
|
7244
|
+
...headers && Object.keys(headers).length > 0 ? { headers } : {},
|
|
7245
|
+
...auth ? { auth } : {}
|
|
7246
|
+
}
|
|
7247
|
+
};
|
|
7248
|
+
}
|
|
7249
|
+
throw new Error(`Server "${name}" must have either "command" (stdio) or "url" (http) defined`);
|
|
7250
|
+
}
|
|
7251
|
+
async function loadMCPConfigFile(configPath) {
|
|
7252
|
+
try {
|
|
7253
|
+
await access(configPath);
|
|
7254
|
+
} catch {
|
|
7255
|
+
throw new MCPError(-32003 /* CONNECTION_ERROR */, `Config file not found: ${configPath}`);
|
|
7256
|
+
}
|
|
7257
|
+
let content;
|
|
7258
|
+
try {
|
|
7259
|
+
content = await readFile(configPath, "utf-8");
|
|
7260
|
+
} catch (error) {
|
|
7261
|
+
throw new MCPError(
|
|
7262
|
+
-32003 /* CONNECTION_ERROR */,
|
|
7263
|
+
`Failed to read config file: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
7264
|
+
);
|
|
7265
|
+
}
|
|
7266
|
+
let parsed;
|
|
7267
|
+
try {
|
|
7268
|
+
parsed = JSON.parse(content);
|
|
7269
|
+
} catch {
|
|
7270
|
+
throw new MCPError(-32700 /* PARSE_ERROR */, "Invalid JSON in config file");
|
|
7271
|
+
}
|
|
7272
|
+
const obj = parsed;
|
|
7273
|
+
if (obj.mcpServers && typeof obj.mcpServers === "object" && !Array.isArray(obj.mcpServers)) {
|
|
7274
|
+
return loadStandardFormat(obj, configPath);
|
|
7275
|
+
}
|
|
7276
|
+
if (obj.servers && Array.isArray(obj.servers)) {
|
|
7277
|
+
return loadCocoFormat(obj, configPath);
|
|
7278
|
+
}
|
|
7279
|
+
throw new MCPError(
|
|
7280
|
+
-32602 /* INVALID_PARAMS */,
|
|
7281
|
+
'Config file must have either a "mcpServers" object (standard) or a "servers" array (Coco format)'
|
|
7282
|
+
);
|
|
7283
|
+
}
|
|
7284
|
+
function loadStandardFormat(config, configPath) {
|
|
7285
|
+
const validServers = [];
|
|
7286
|
+
const errors = [];
|
|
7287
|
+
for (const [name, entry] of Object.entries(config.mcpServers)) {
|
|
7288
|
+
if (name.startsWith("_")) continue;
|
|
7289
|
+
try {
|
|
7290
|
+
const converted = convertStandardEntry(name, entry);
|
|
7291
|
+
validateServerConfig(converted);
|
|
7292
|
+
validServers.push(converted);
|
|
7293
|
+
} catch (error) {
|
|
7294
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7295
|
+
errors.push(`Server '${name}': ${message}`);
|
|
7296
|
+
}
|
|
7297
|
+
}
|
|
7298
|
+
if (errors.length > 0) {
|
|
7299
|
+
getLogger().warn(`[MCP] Some servers in ${configPath} failed to load: ${errors.join("; ")}`);
|
|
7300
|
+
}
|
|
7301
|
+
return validServers;
|
|
7302
|
+
}
|
|
7303
|
+
async function loadProjectMCPFile(projectPath) {
|
|
7304
|
+
const mcpJsonPath = path39__default.join(projectPath, ".mcp.json");
|
|
7305
|
+
try {
|
|
7306
|
+
await access(mcpJsonPath);
|
|
7307
|
+
} catch {
|
|
7308
|
+
return [];
|
|
7309
|
+
}
|
|
7310
|
+
try {
|
|
7311
|
+
return await loadMCPConfigFile(mcpJsonPath);
|
|
7312
|
+
} catch (error) {
|
|
7313
|
+
getLogger().warn(
|
|
7314
|
+
`[MCP] Failed to load .mcp.json: ${error instanceof Error ? error.message : String(error)}`
|
|
7315
|
+
);
|
|
7316
|
+
return [];
|
|
7317
|
+
}
|
|
7318
|
+
}
|
|
7319
|
+
function loadCocoFormat(config, configPath) {
|
|
7320
|
+
const validServers = [];
|
|
7321
|
+
const errors = [];
|
|
7322
|
+
for (const server of config.servers) {
|
|
7323
|
+
try {
|
|
7324
|
+
const converted = convertCocoServerEntry(server);
|
|
7325
|
+
validateServerConfig(converted);
|
|
7326
|
+
validServers.push(converted);
|
|
7327
|
+
} catch (error) {
|
|
7328
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7329
|
+
errors.push(`Server '${server.name || "unknown"}': ${message}`);
|
|
7330
|
+
}
|
|
7331
|
+
}
|
|
7332
|
+
if (errors.length > 0) {
|
|
7333
|
+
getLogger().warn(`[MCP] Some servers in ${configPath} failed to load: ${errors.join("; ")}`);
|
|
7334
|
+
}
|
|
7335
|
+
return validServers;
|
|
7336
|
+
}
|
|
7337
|
+
function convertCocoServerEntry(server) {
|
|
7338
|
+
const base = {
|
|
7339
|
+
name: server.name,
|
|
7340
|
+
description: server.description,
|
|
7341
|
+
transport: server.transport,
|
|
7342
|
+
enabled: server.enabled ?? true,
|
|
7343
|
+
metadata: server.metadata
|
|
7344
|
+
};
|
|
7345
|
+
if (server.transport === "stdio" && server.stdio) {
|
|
7346
|
+
return {
|
|
7347
|
+
...base,
|
|
7348
|
+
stdio: {
|
|
7349
|
+
command: server.stdio.command,
|
|
7350
|
+
args: server.stdio.args,
|
|
7351
|
+
env: server.stdio.env ? expandEnvObject(server.stdio.env) : void 0,
|
|
7352
|
+
cwd: server.stdio.cwd
|
|
7353
|
+
}
|
|
7354
|
+
};
|
|
7355
|
+
}
|
|
7356
|
+
if (server.transport === "http" && server.http) {
|
|
7357
|
+
return {
|
|
7358
|
+
...base,
|
|
7359
|
+
http: {
|
|
7360
|
+
url: server.http.url,
|
|
7361
|
+
...server.http.headers ? { headers: expandHeaders(server.http.headers) } : {},
|
|
7362
|
+
...server.http.auth ? { auth: server.http.auth } : {},
|
|
7363
|
+
...server.http.timeout !== void 0 ? { timeout: server.http.timeout } : {}
|
|
7364
|
+
}
|
|
7365
|
+
};
|
|
7366
|
+
}
|
|
7367
|
+
throw new Error(`Missing configuration for transport: ${server.transport}`);
|
|
7368
|
+
}
|
|
7369
|
+
function mergeMCPConfigs(base, ...overrides) {
|
|
7370
|
+
const merged = /* @__PURE__ */ new Map();
|
|
7371
|
+
for (const server of base) {
|
|
7372
|
+
merged.set(server.name, server);
|
|
7373
|
+
}
|
|
7374
|
+
for (const override of overrides) {
|
|
7375
|
+
for (const server of override) {
|
|
7376
|
+
const existing = merged.get(server.name);
|
|
7377
|
+
if (existing) {
|
|
7378
|
+
merged.set(server.name, { ...existing, ...server });
|
|
7379
|
+
} else {
|
|
7380
|
+
merged.set(server.name, server);
|
|
7381
|
+
}
|
|
7382
|
+
}
|
|
7383
|
+
}
|
|
7384
|
+
return Array.from(merged.values());
|
|
7385
|
+
}
|
|
7386
|
+
async function loadMCPServersFromCOCOConfig(configPath) {
|
|
7387
|
+
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
7388
|
+
const { MCPServerConfigEntrySchema: MCPServerConfigEntrySchema2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
7389
|
+
const config = await loadConfig3(configPath);
|
|
7390
|
+
if (!config.mcp?.servers || config.mcp.servers.length === 0) {
|
|
7391
|
+
return [];
|
|
7392
|
+
}
|
|
7393
|
+
const servers = [];
|
|
7394
|
+
for (const entry of config.mcp.servers) {
|
|
7395
|
+
try {
|
|
7396
|
+
const parsed = MCPServerConfigEntrySchema2.parse(entry);
|
|
7397
|
+
const serverConfig = {
|
|
7398
|
+
name: parsed.name,
|
|
7399
|
+
description: parsed.description,
|
|
7400
|
+
transport: parsed.transport,
|
|
7401
|
+
enabled: parsed.enabled,
|
|
7402
|
+
...parsed.transport === "stdio" && parsed.command && {
|
|
7403
|
+
stdio: {
|
|
7404
|
+
command: parsed.command,
|
|
7405
|
+
args: parsed.args,
|
|
7406
|
+
env: parsed.env ? expandEnvObject(parsed.env) : void 0
|
|
7407
|
+
}
|
|
7408
|
+
},
|
|
7409
|
+
...parsed.transport === "http" && parsed.url && {
|
|
7410
|
+
http: {
|
|
7411
|
+
url: parsed.url,
|
|
7412
|
+
auth: parsed.auth
|
|
7413
|
+
}
|
|
7414
|
+
}
|
|
7415
|
+
};
|
|
7416
|
+
validateServerConfig(serverConfig);
|
|
7417
|
+
servers.push(serverConfig);
|
|
7418
|
+
} catch (error) {
|
|
7419
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
7420
|
+
getLogger().warn(`[MCP] Failed to load server '${entry.name}': ${message}`);
|
|
7421
|
+
}
|
|
7422
|
+
}
|
|
7423
|
+
return servers;
|
|
7424
|
+
}
|
|
7425
|
+
var init_config_loader = __esm({
|
|
7426
|
+
"src/mcp/config-loader.ts"() {
|
|
7427
|
+
init_config();
|
|
7428
|
+
init_types();
|
|
7429
|
+
init_errors2();
|
|
7430
|
+
init_logger();
|
|
7431
|
+
}
|
|
7432
|
+
});
|
|
7433
|
+
|
|
7189
7434
|
// src/mcp/registry.ts
|
|
7190
7435
|
var registry_exports = {};
|
|
7191
7436
|
__export(registry_exports, {
|
|
@@ -7286,7 +7531,14 @@ var init_registry = __esm({
|
|
|
7286
7531
|
try {
|
|
7287
7532
|
await access(this.registryPath);
|
|
7288
7533
|
const content = await readFile(this.registryPath, "utf-8");
|
|
7289
|
-
|
|
7534
|
+
let servers = parseRegistry(content);
|
|
7535
|
+
if (servers.length === 0) {
|
|
7536
|
+
try {
|
|
7537
|
+
const { loadMCPConfigFile: loadMCPConfigFile2 } = await Promise.resolve().then(() => (init_config_loader(), config_loader_exports));
|
|
7538
|
+
servers = await loadMCPConfigFile2(this.registryPath);
|
|
7539
|
+
} catch {
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7290
7542
|
this.servers.clear();
|
|
7291
7543
|
for (const server of servers) {
|
|
7292
7544
|
try {
|
|
@@ -7378,7 +7630,7 @@ __export(markdown_loader_exports, {
|
|
|
7378
7630
|
});
|
|
7379
7631
|
async function isMarkdownSkill(skillDir) {
|
|
7380
7632
|
try {
|
|
7381
|
-
await fs35__default.access(
|
|
7633
|
+
await fs35__default.access(path39__default.join(skillDir, SKILL_FILENAME));
|
|
7382
7634
|
return true;
|
|
7383
7635
|
} catch {
|
|
7384
7636
|
return false;
|
|
@@ -7386,7 +7638,7 @@ async function isMarkdownSkill(skillDir) {
|
|
|
7386
7638
|
}
|
|
7387
7639
|
async function loadMarkdownMetadata(skillDir, scope) {
|
|
7388
7640
|
try {
|
|
7389
|
-
const skillPath =
|
|
7641
|
+
const skillPath = path39__default.join(skillDir, SKILL_FILENAME);
|
|
7390
7642
|
const raw = await fs35__default.readFile(skillPath, "utf-8");
|
|
7391
7643
|
const { data } = matter(raw);
|
|
7392
7644
|
const parsed = SkillFrontmatterSchema.safeParse(data);
|
|
@@ -7394,8 +7646,8 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
7394
7646
|
return null;
|
|
7395
7647
|
}
|
|
7396
7648
|
const fm = parsed.data;
|
|
7397
|
-
const dirName =
|
|
7398
|
-
const parentDir =
|
|
7649
|
+
const dirName = path39__default.basename(skillDir);
|
|
7650
|
+
const parentDir = path39__default.basename(path39__default.dirname(skillDir));
|
|
7399
7651
|
const namespace = isNamespaceDirectory(parentDir) ? parentDir : void 0;
|
|
7400
7652
|
const baseId = toKebabCase(fm.name || dirName);
|
|
7401
7653
|
const fullId = namespace ? `${namespace}/${baseId}` : baseId;
|
|
@@ -7435,7 +7687,7 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
7435
7687
|
}
|
|
7436
7688
|
async function loadMarkdownContent(skillDir) {
|
|
7437
7689
|
try {
|
|
7438
|
-
const skillPath =
|
|
7690
|
+
const skillPath = path39__default.join(skillDir, SKILL_FILENAME);
|
|
7439
7691
|
const raw = await fs35__default.readFile(skillPath, "utf-8");
|
|
7440
7692
|
const { content } = matter(raw);
|
|
7441
7693
|
const references = await listSubdirectory(skillDir, "references");
|
|
@@ -7458,9 +7710,9 @@ async function loadMarkdownContent(skillDir) {
|
|
|
7458
7710
|
}
|
|
7459
7711
|
async function listSubdirectory(skillDir, subdir) {
|
|
7460
7712
|
try {
|
|
7461
|
-
const dir =
|
|
7713
|
+
const dir = path39__default.join(skillDir, subdir);
|
|
7462
7714
|
const entries = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
7463
|
-
return entries.filter((e) => e.isFile()).map((e) =>
|
|
7715
|
+
return entries.filter((e) => e.isFile()).map((e) => path39__default.join(dir, e.name));
|
|
7464
7716
|
} catch {
|
|
7465
7717
|
return [];
|
|
7466
7718
|
}
|
|
@@ -7537,8 +7789,8 @@ async function loadSkillFromDirectory(skillDir, scope) {
|
|
|
7537
7789
|
if (await isMarkdownSkill(skillDir)) {
|
|
7538
7790
|
return loadMarkdownMetadata(skillDir, scope);
|
|
7539
7791
|
}
|
|
7540
|
-
const hasTs = await fileExists2(
|
|
7541
|
-
const hasJs = await fileExists2(
|
|
7792
|
+
const hasTs = await fileExists2(path39__default.join(skillDir, "index.ts"));
|
|
7793
|
+
const hasJs = await fileExists2(path39__default.join(skillDir, "index.js"));
|
|
7542
7794
|
if (hasTs || hasJs) {
|
|
7543
7795
|
return null;
|
|
7544
7796
|
}
|
|
@@ -7581,8 +7833,8 @@ function normalizeDirectories(dirs, relativeBaseDir) {
|
|
|
7581
7833
|
for (const dir of dirs) {
|
|
7582
7834
|
const trimmed = dir.trim();
|
|
7583
7835
|
if (!trimmed) continue;
|
|
7584
|
-
const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") ?
|
|
7585
|
-
const resolved =
|
|
7836
|
+
const expanded = trimmed === "~" ? home : trimmed.startsWith("~/") ? path39__default.join(home, trimmed.slice(2)) : trimmed;
|
|
7837
|
+
const resolved = path39__default.isAbsolute(expanded) ? path39__default.resolve(expanded) : path39__default.resolve(relativeBaseDir ?? process.cwd(), expanded);
|
|
7586
7838
|
if (seen.has(resolved)) continue;
|
|
7587
7839
|
seen.add(resolved);
|
|
7588
7840
|
normalized.push(resolved);
|
|
@@ -7595,7 +7847,7 @@ function resolveDiscoveryDirs(projectPath, options) {
|
|
|
7595
7847
|
opts.globalDirs && opts.globalDirs.length > 0 ? opts.globalDirs : opts.globalDir ? [opts.globalDir] : GLOBAL_SKILLS_DIRS
|
|
7596
7848
|
);
|
|
7597
7849
|
const projectDirs = normalizeDirectories(
|
|
7598
|
-
opts.projectDirs && opts.projectDirs.length > 0 ? opts.projectDirs : opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) =>
|
|
7850
|
+
opts.projectDirs && opts.projectDirs.length > 0 ? opts.projectDirs : opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) => path39__default.join(projectPath, d)),
|
|
7599
7851
|
projectPath
|
|
7600
7852
|
);
|
|
7601
7853
|
return { globalDirs, projectDirs };
|
|
@@ -7627,7 +7879,7 @@ async function scanSkillsDirectory(dir, scope) {
|
|
|
7627
7879
|
const skillDirs = entries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
7628
7880
|
const results = [];
|
|
7629
7881
|
for (const entry of skillDirs) {
|
|
7630
|
-
const entryPath =
|
|
7882
|
+
const entryPath = path39__default.join(dir, entry.name);
|
|
7631
7883
|
try {
|
|
7632
7884
|
const stat2 = await fs35__default.lstat(entryPath);
|
|
7633
7885
|
if (stat2.isSymbolicLink()) continue;
|
|
@@ -7661,7 +7913,7 @@ async function scanNestedSkills(dir, scope, depth) {
|
|
|
7661
7913
|
const subDirs = subEntries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
7662
7914
|
const results = await Promise.all(
|
|
7663
7915
|
subDirs.map(async (sub) => {
|
|
7664
|
-
const subPath =
|
|
7916
|
+
const subPath = path39__default.join(dir, sub.name);
|
|
7665
7917
|
try {
|
|
7666
7918
|
const stat2 = await fs35__default.lstat(subPath);
|
|
7667
7919
|
if (stat2.isSymbolicLink()) return null;
|
|
@@ -7691,17 +7943,17 @@ var init_discovery = __esm({
|
|
|
7691
7943
|
init_paths();
|
|
7692
7944
|
init_logger();
|
|
7693
7945
|
GLOBAL_SKILLS_DIRS = [
|
|
7694
|
-
|
|
7946
|
+
path39__default.join(homedir(), ".codex", "skills"),
|
|
7695
7947
|
// Codex CLI legacy compat
|
|
7696
|
-
|
|
7948
|
+
path39__default.join(homedir(), ".gemini", "skills"),
|
|
7697
7949
|
// Gemini CLI compat
|
|
7698
|
-
|
|
7950
|
+
path39__default.join(homedir(), ".opencode", "skills"),
|
|
7699
7951
|
// OpenCode compat
|
|
7700
|
-
|
|
7952
|
+
path39__default.join(homedir(), ".claude", "skills"),
|
|
7701
7953
|
// Claude Code compat
|
|
7702
|
-
|
|
7954
|
+
path39__default.join(homedir(), ".agents", "skills"),
|
|
7703
7955
|
// shared cross-agent standard
|
|
7704
|
-
|
|
7956
|
+
path39__default.join(COCO_HOME, "skills")
|
|
7705
7957
|
// Coco native global directory (authoritative for Coco)
|
|
7706
7958
|
];
|
|
7707
7959
|
PROJECT_SKILLS_DIRNAMES = [
|
|
@@ -9089,7 +9341,7 @@ var init_loader3 = __esm({
|
|
|
9089
9341
|
const rawContent = await fs35.readFile(resolvedPath, "utf-8");
|
|
9090
9342
|
const { content, imports } = await this.resolveImports(
|
|
9091
9343
|
rawContent,
|
|
9092
|
-
|
|
9344
|
+
path39.dirname(resolvedPath),
|
|
9093
9345
|
0
|
|
9094
9346
|
);
|
|
9095
9347
|
const sections = this.parseSections(content);
|
|
@@ -9116,16 +9368,16 @@ var init_loader3 = __esm({
|
|
|
9116
9368
|
if (this.config.includeUserLevel) {
|
|
9117
9369
|
const userDir = this.resolvePath(USER_CONFIG_DIR);
|
|
9118
9370
|
for (const pattern of this.config.filePatterns) {
|
|
9119
|
-
const userPath =
|
|
9371
|
+
const userPath = path39.join(userDir, pattern);
|
|
9120
9372
|
if (await this.fileExists(userPath)) {
|
|
9121
9373
|
result.user = userPath;
|
|
9122
9374
|
break;
|
|
9123
9375
|
}
|
|
9124
9376
|
}
|
|
9125
9377
|
}
|
|
9126
|
-
const absoluteProjectPath =
|
|
9378
|
+
const absoluteProjectPath = path39.resolve(projectPath);
|
|
9127
9379
|
for (const pattern of this.config.filePatterns) {
|
|
9128
|
-
const projectFilePath =
|
|
9380
|
+
const projectFilePath = path39.join(absoluteProjectPath, pattern);
|
|
9129
9381
|
if (await this.fileExists(projectFilePath)) {
|
|
9130
9382
|
result.project = projectFilePath;
|
|
9131
9383
|
break;
|
|
@@ -9133,14 +9385,14 @@ var init_loader3 = __esm({
|
|
|
9133
9385
|
}
|
|
9134
9386
|
const cwd = currentDir ?? process.cwd();
|
|
9135
9387
|
if (cwd.startsWith(absoluteProjectPath) && cwd !== absoluteProjectPath) {
|
|
9136
|
-
const relativePath =
|
|
9137
|
-
const parts = relativePath.split(
|
|
9388
|
+
const relativePath = path39.relative(absoluteProjectPath, cwd);
|
|
9389
|
+
const parts = relativePath.split(path39.sep);
|
|
9138
9390
|
const dirFiles = [];
|
|
9139
9391
|
let currentDir2 = absoluteProjectPath;
|
|
9140
9392
|
for (const part of parts) {
|
|
9141
|
-
currentDir2 =
|
|
9393
|
+
currentDir2 = path39.join(currentDir2, part);
|
|
9142
9394
|
for (const pattern of this.config.filePatterns) {
|
|
9143
|
-
const dirFilePath =
|
|
9395
|
+
const dirFilePath = path39.join(currentDir2, pattern);
|
|
9144
9396
|
if (await this.fileExists(dirFilePath)) {
|
|
9145
9397
|
dirFiles.push(dirFilePath);
|
|
9146
9398
|
break;
|
|
@@ -9154,7 +9406,7 @@ var init_loader3 = __esm({
|
|
|
9154
9406
|
for (const pattern of this.config.filePatterns) {
|
|
9155
9407
|
const baseName = pattern.replace(/\.md$/, "");
|
|
9156
9408
|
const localFileName = `${baseName}${LOCAL_SUFFIX}`;
|
|
9157
|
-
const localPath =
|
|
9409
|
+
const localPath = path39.join(absoluteProjectPath, localFileName);
|
|
9158
9410
|
if (await this.fileExists(localPath)) {
|
|
9159
9411
|
result.local = localPath;
|
|
9160
9412
|
break;
|
|
@@ -9208,7 +9460,7 @@ var init_loader3 = __esm({
|
|
|
9208
9460
|
const importedContent = await fs35.readFile(resolvedPath, "utf-8");
|
|
9209
9461
|
const nestedResult = await this.resolveImports(
|
|
9210
9462
|
importedContent,
|
|
9211
|
-
|
|
9463
|
+
path39.dirname(resolvedPath),
|
|
9212
9464
|
depth + 1
|
|
9213
9465
|
);
|
|
9214
9466
|
processedLines.push(`<!-- Imported from: ${importPath} -->`);
|
|
@@ -9249,7 +9501,7 @@ var init_loader3 = __esm({
|
|
|
9249
9501
|
const parts = [];
|
|
9250
9502
|
for (const file of files) {
|
|
9251
9503
|
if (file.exists && file.content.trim()) {
|
|
9252
|
-
const label = file.level === "directory" ? `directory level (${
|
|
9504
|
+
const label = file.level === "directory" ? `directory level (${path39.dirname(file.path)}/${path39.basename(file.path)})` : `${file.level} level (${path39.basename(file.path)})`;
|
|
9253
9505
|
parts.push(`<!-- Memory: ${label} -->`);
|
|
9254
9506
|
parts.push(file.content);
|
|
9255
9507
|
parts.push("");
|
|
@@ -9312,9 +9564,9 @@ var init_loader3 = __esm({
|
|
|
9312
9564
|
*/
|
|
9313
9565
|
resolvePath(filePath) {
|
|
9314
9566
|
if (filePath.startsWith("~")) {
|
|
9315
|
-
return
|
|
9567
|
+
return path39.join(os4.homedir(), filePath.slice(1));
|
|
9316
9568
|
}
|
|
9317
|
-
return
|
|
9569
|
+
return path39.resolve(filePath);
|
|
9318
9570
|
}
|
|
9319
9571
|
/**
|
|
9320
9572
|
* Resolve an import path relative to a base directory.
|
|
@@ -9329,22 +9581,22 @@ var init_loader3 = __esm({
|
|
|
9329
9581
|
resolveImportPath(importPath, basePath) {
|
|
9330
9582
|
let resolved;
|
|
9331
9583
|
if (importPath.startsWith("~")) {
|
|
9332
|
-
resolved =
|
|
9584
|
+
resolved = path39.join(os4.homedir(), importPath.slice(1));
|
|
9333
9585
|
const userConfigDir = this.resolvePath(USER_CONFIG_DIR);
|
|
9334
|
-
if (!resolved.startsWith(userConfigDir +
|
|
9586
|
+
if (!resolved.startsWith(userConfigDir + path39.sep) && resolved !== userConfigDir) {
|
|
9335
9587
|
throw new Error(`Import path escapes user config directory: @${importPath}`);
|
|
9336
9588
|
}
|
|
9337
9589
|
return resolved;
|
|
9338
9590
|
}
|
|
9339
|
-
if (
|
|
9340
|
-
resolved =
|
|
9341
|
-
if (!resolved.startsWith(basePath +
|
|
9591
|
+
if (path39.isAbsolute(importPath)) {
|
|
9592
|
+
resolved = path39.resolve(importPath);
|
|
9593
|
+
if (!resolved.startsWith(basePath + path39.sep) && resolved !== basePath) {
|
|
9342
9594
|
throw new Error(`Import path escapes project directory: @${importPath}`);
|
|
9343
9595
|
}
|
|
9344
9596
|
return resolved;
|
|
9345
9597
|
}
|
|
9346
|
-
resolved =
|
|
9347
|
-
if (!resolved.startsWith(basePath +
|
|
9598
|
+
resolved = path39.resolve(basePath, importPath);
|
|
9599
|
+
if (!resolved.startsWith(basePath + path39.sep) && resolved !== basePath) {
|
|
9348
9600
|
throw new Error(`Import path escapes project directory: @${importPath}`);
|
|
9349
9601
|
}
|
|
9350
9602
|
return resolved;
|
|
@@ -9511,7 +9763,7 @@ function generateToolCatalog(registry) {
|
|
|
9511
9763
|
const tools = registry.getAll();
|
|
9512
9764
|
const byCategory = /* @__PURE__ */ new Map();
|
|
9513
9765
|
for (const tool of tools) {
|
|
9514
|
-
const cat = tool.category;
|
|
9766
|
+
const cat = tool.name.startsWith("mcp_") ? "mcp" : tool.category;
|
|
9515
9767
|
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
9516
9768
|
byCategory.get(cat).push({ name: tool.name, description: tool.description });
|
|
9517
9769
|
}
|
|
@@ -9932,9 +10184,10 @@ var init_session = __esm({
|
|
|
9932
10184
|
init_manager();
|
|
9933
10185
|
init_compactor();
|
|
9934
10186
|
MAX_SKILL_INSTRUCTIONS_CHARS = 16e3;
|
|
9935
|
-
TRUST_SETTINGS_DIR =
|
|
10187
|
+
TRUST_SETTINGS_DIR = path39__default.dirname(CONFIG_PATHS.trustedTools);
|
|
9936
10188
|
TRUST_SETTINGS_FILE = CONFIG_PATHS.trustedTools;
|
|
9937
10189
|
CATEGORY_LABELS = {
|
|
10190
|
+
mcp: "MCP Connected Services",
|
|
9938
10191
|
file: "File Operations",
|
|
9939
10192
|
bash: "Shell Commands",
|
|
9940
10193
|
git: "Git & Version Control",
|
|
@@ -9964,6 +10217,8 @@ Rules:
|
|
|
9964
10217
|
- NEVER show code blocks instead of writing files. NEVER describe actions instead of performing them.
|
|
9965
10218
|
- NEVER ask "should I?" or "do you want me to?" \u2014 the user already told you. JUST DO IT.
|
|
9966
10219
|
- If you need real-time data, CALL web_search. NEVER say "I don't have access to real-time data."
|
|
10220
|
+
- If an MCP tool exists for a service (tool names like \`mcp_<service>_...\`), prefer that MCP tool over generic \`web_fetch\` or \`http_fetch\`.
|
|
10221
|
+
- Use \`mcp_list_servers\` to inspect configured or connected MCP services. Do NOT use \`bash_exec\` to run \`coco mcp ...\` unless the user explicitly asked for that CLI command.
|
|
9967
10222
|
- Before answering "I can't do that", check your full tool catalog below \u2014 you likely have a tool for it.
|
|
9968
10223
|
- NEVER claim you cannot run a command because you lack credentials, access, or connectivity. bash_exec runs in the user's own shell environment and inherits their full PATH, kubeconfig, gcloud auth, AWS profiles, SSH keys, and every other tool installed on their machine. kubectl, gcloud, aws, docker, and any other CLI available to the user are available to you. ALWAYS attempt the command with bash_exec; report failure only if it actually returns a non-zero exit code.
|
|
9969
10224
|
|
|
@@ -10072,6 +10327,7 @@ Suggest 1-2 brief, actionable next steps:
|
|
|
10072
10327
|
## File Access
|
|
10073
10328
|
File operations are restricted to the project directory by default.
|
|
10074
10329
|
Use **authorize_path** to access paths outside the project \u2014 it prompts the user interactively.
|
|
10330
|
+
Exception: Coco's own config area under \`~/.coco/\` is first-party product state. You may read safe config files there, especially \`~/.coco/mcp.json\` and \`~/.coco/config.json\`, without using \`authorize_path\`.
|
|
10075
10331
|
|
|
10076
10332
|
## Tone and Brevity
|
|
10077
10333
|
|
|
@@ -10215,7 +10471,7 @@ var init_types4 = __esm({
|
|
|
10215
10471
|
}
|
|
10216
10472
|
});
|
|
10217
10473
|
function getStatePath(projectPath) {
|
|
10218
|
-
return
|
|
10474
|
+
return path39.join(projectPath, ".coco", "state.json");
|
|
10219
10475
|
}
|
|
10220
10476
|
function createStateManager() {
|
|
10221
10477
|
async function load(projectPath) {
|
|
@@ -10240,7 +10496,7 @@ function createStateManager() {
|
|
|
10240
10496
|
}
|
|
10241
10497
|
async function save(state) {
|
|
10242
10498
|
const statePath = getStatePath(state.path);
|
|
10243
|
-
await fs35.mkdir(
|
|
10499
|
+
await fs35.mkdir(path39.dirname(statePath), { recursive: true });
|
|
10244
10500
|
const file = {
|
|
10245
10501
|
version: STATE_VERSION,
|
|
10246
10502
|
state: {
|
|
@@ -12884,7 +13140,7 @@ var init_build_verifier = __esm({
|
|
|
12884
13140
|
async verifyTypes() {
|
|
12885
13141
|
const startTime = Date.now();
|
|
12886
13142
|
try {
|
|
12887
|
-
const hasTsConfig = await this.fileExists(
|
|
13143
|
+
const hasTsConfig = await this.fileExists(path39.join(this.projectPath, "tsconfig.json"));
|
|
12888
13144
|
if (!hasTsConfig) {
|
|
12889
13145
|
return {
|
|
12890
13146
|
success: true,
|
|
@@ -12934,18 +13190,18 @@ var init_build_verifier = __esm({
|
|
|
12934
13190
|
* Checks Maven, Gradle, and Node.js in that order.
|
|
12935
13191
|
*/
|
|
12936
13192
|
async detectBuildCommand() {
|
|
12937
|
-
if (await this.fileExists(
|
|
12938
|
-
const wrapper =
|
|
13193
|
+
if (await this.fileExists(path39.join(this.projectPath, "pom.xml"))) {
|
|
13194
|
+
const wrapper = path39.join(this.projectPath, "mvnw");
|
|
12939
13195
|
return await this.fileExists(wrapper) ? "./mvnw compile -B -q" : "mvn compile -B -q";
|
|
12940
13196
|
}
|
|
12941
13197
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
12942
|
-
if (await this.fileExists(
|
|
12943
|
-
const wrapper =
|
|
13198
|
+
if (await this.fileExists(path39.join(this.projectPath, f))) {
|
|
13199
|
+
const wrapper = path39.join(this.projectPath, "gradlew");
|
|
12944
13200
|
return await this.fileExists(wrapper) ? "./gradlew classes -q" : "gradle classes -q";
|
|
12945
13201
|
}
|
|
12946
13202
|
}
|
|
12947
13203
|
try {
|
|
12948
|
-
const packageJsonPath =
|
|
13204
|
+
const packageJsonPath = path39.join(this.projectPath, "package.json");
|
|
12949
13205
|
const content = await fs35.readFile(packageJsonPath, "utf-8");
|
|
12950
13206
|
const packageJson = JSON.parse(content);
|
|
12951
13207
|
if (packageJson.scripts?.build) {
|
|
@@ -14680,9 +14936,9 @@ function detectProjectLanguage(files) {
|
|
|
14680
14936
|
return { language: dominant, confidence, evidence };
|
|
14681
14937
|
}
|
|
14682
14938
|
function getFileExtension(filePath) {
|
|
14683
|
-
const base =
|
|
14939
|
+
const base = path39.basename(filePath);
|
|
14684
14940
|
if (base.endsWith(".d.ts")) return ".d.ts";
|
|
14685
|
-
return
|
|
14941
|
+
return path39.extname(filePath).toLowerCase();
|
|
14686
14942
|
}
|
|
14687
14943
|
function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
14688
14944
|
const evidence = [];
|
|
@@ -14690,7 +14946,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
|
14690
14946
|
evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
|
|
14691
14947
|
const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
|
|
14692
14948
|
for (const cfg of configFiles) {
|
|
14693
|
-
if (files.some((f) =>
|
|
14949
|
+
if (files.some((f) => path39.basename(f) === cfg)) {
|
|
14694
14950
|
evidence.push(`Found ${cfg}`);
|
|
14695
14951
|
}
|
|
14696
14952
|
}
|
|
@@ -16185,19 +16441,19 @@ var init_evaluator = __esm({
|
|
|
16185
16441
|
});
|
|
16186
16442
|
async function detectLinter2(cwd) {
|
|
16187
16443
|
try {
|
|
16188
|
-
await fs35__default.access(
|
|
16444
|
+
await fs35__default.access(path39__default.join(cwd, "pom.xml"));
|
|
16189
16445
|
return "maven-checkstyle";
|
|
16190
16446
|
} catch {
|
|
16191
16447
|
}
|
|
16192
16448
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
16193
16449
|
try {
|
|
16194
|
-
await fs35__default.access(
|
|
16450
|
+
await fs35__default.access(path39__default.join(cwd, f));
|
|
16195
16451
|
return "gradle-checkstyle";
|
|
16196
16452
|
} catch {
|
|
16197
16453
|
}
|
|
16198
16454
|
}
|
|
16199
16455
|
try {
|
|
16200
|
-
const pkgPath =
|
|
16456
|
+
const pkgPath = path39__default.join(cwd, "package.json");
|
|
16201
16457
|
const pkgContent = await fs35__default.readFile(pkgPath, "utf-8");
|
|
16202
16458
|
const pkg = JSON.parse(pkgContent);
|
|
16203
16459
|
const deps = {
|
|
@@ -16214,7 +16470,7 @@ async function detectLinter2(cwd) {
|
|
|
16214
16470
|
}
|
|
16215
16471
|
async function mavenExec(cwd) {
|
|
16216
16472
|
try {
|
|
16217
|
-
await fs35__default.access(
|
|
16473
|
+
await fs35__default.access(path39__default.join(cwd, "mvnw"));
|
|
16218
16474
|
return "./mvnw";
|
|
16219
16475
|
} catch {
|
|
16220
16476
|
return "mvn";
|
|
@@ -16222,7 +16478,7 @@ async function mavenExec(cwd) {
|
|
|
16222
16478
|
}
|
|
16223
16479
|
async function gradleExec(cwd) {
|
|
16224
16480
|
try {
|
|
16225
|
-
await fs35__default.access(
|
|
16481
|
+
await fs35__default.access(path39__default.join(cwd, "gradlew"));
|
|
16226
16482
|
return "./gradlew";
|
|
16227
16483
|
} catch {
|
|
16228
16484
|
return "gradle";
|
|
@@ -16291,14 +16547,14 @@ async function findSourceFiles(cwd) {
|
|
|
16291
16547
|
const { glob: glob17 } = await import('glob');
|
|
16292
16548
|
let isJava = false;
|
|
16293
16549
|
try {
|
|
16294
|
-
await fs35__default.access(
|
|
16550
|
+
await fs35__default.access(path39__default.join(cwd, "pom.xml"));
|
|
16295
16551
|
isJava = true;
|
|
16296
16552
|
} catch {
|
|
16297
16553
|
}
|
|
16298
16554
|
if (!isJava) {
|
|
16299
16555
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
16300
16556
|
try {
|
|
16301
|
-
await fs35__default.access(
|
|
16557
|
+
await fs35__default.access(path39__default.join(cwd, f));
|
|
16302
16558
|
isJava = true;
|
|
16303
16559
|
break;
|
|
16304
16560
|
} catch {
|
|
@@ -16653,7 +16909,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
16653
16909
|
);
|
|
16654
16910
|
if (!hasTestChange) {
|
|
16655
16911
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
16656
|
-
const testExists = await fileExists3(
|
|
16912
|
+
const testExists = await fileExists3(path39__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists3(path39__default.join(cwd, `${baseName}.spec${ext}`));
|
|
16657
16913
|
if (testExists) {
|
|
16658
16914
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
16659
16915
|
findings.push({
|
|
@@ -18334,7 +18590,7 @@ var init_github = __esm({
|
|
|
18334
18590
|
});
|
|
18335
18591
|
async function detectVersionFile(cwd) {
|
|
18336
18592
|
for (const { file, stack, field } of VERSION_FILES) {
|
|
18337
|
-
const fullPath =
|
|
18593
|
+
const fullPath = path39__default.join(cwd, file);
|
|
18338
18594
|
if (await fileExists3(fullPath)) {
|
|
18339
18595
|
const version = await readVersionFromFile(fullPath, stack, field);
|
|
18340
18596
|
if (version) {
|
|
@@ -18380,7 +18636,7 @@ function bumpVersion(current, bump) {
|
|
|
18380
18636
|
}
|
|
18381
18637
|
}
|
|
18382
18638
|
async function writeVersion(cwd, versionFile, newVersion) {
|
|
18383
|
-
const fullPath =
|
|
18639
|
+
const fullPath = path39__default.join(cwd, versionFile.path);
|
|
18384
18640
|
const content = await readFile(fullPath, "utf-8");
|
|
18385
18641
|
let updated;
|
|
18386
18642
|
switch (versionFile.stack) {
|
|
@@ -18439,7 +18695,7 @@ var init_version_detector = __esm({
|
|
|
18439
18695
|
});
|
|
18440
18696
|
async function detectChangelog(cwd) {
|
|
18441
18697
|
for (const name of CHANGELOG_NAMES) {
|
|
18442
|
-
const fullPath =
|
|
18698
|
+
const fullPath = path39__default.join(cwd, name);
|
|
18443
18699
|
if (await fileExists3(fullPath)) {
|
|
18444
18700
|
const content = await readFile(fullPath, "utf-8");
|
|
18445
18701
|
const format = detectFormat(content);
|
|
@@ -18461,7 +18717,7 @@ function detectFormat(content) {
|
|
|
18461
18717
|
return "custom";
|
|
18462
18718
|
}
|
|
18463
18719
|
async function insertChangelogEntry(cwd, changelog, version, entries, date) {
|
|
18464
|
-
const fullPath =
|
|
18720
|
+
const fullPath = path39__default.join(cwd, changelog.path);
|
|
18465
18721
|
const content = await readFile(fullPath, "utf-8");
|
|
18466
18722
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18467
18723
|
const entry = buildEntry(changelog.format, version, entries, dateStr);
|
|
@@ -18522,11 +18778,11 @@ var init_changelog = __esm({
|
|
|
18522
18778
|
}
|
|
18523
18779
|
});
|
|
18524
18780
|
async function detectStack(cwd) {
|
|
18525
|
-
if (await fileExists3(
|
|
18526
|
-
if (await fileExists3(
|
|
18527
|
-
if (await fileExists3(
|
|
18528
|
-
if (await fileExists3(
|
|
18529
|
-
if (await fileExists3(
|
|
18781
|
+
if (await fileExists3(path39__default.join(cwd, "package.json"))) return "node";
|
|
18782
|
+
if (await fileExists3(path39__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
18783
|
+
if (await fileExists3(path39__default.join(cwd, "pyproject.toml"))) return "python";
|
|
18784
|
+
if (await fileExists3(path39__default.join(cwd, "go.mod"))) return "go";
|
|
18785
|
+
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) return "java";
|
|
18530
18786
|
return "unknown";
|
|
18531
18787
|
}
|
|
18532
18788
|
async function detectPackageManager(cwd, stack) {
|
|
@@ -18534,15 +18790,15 @@ async function detectPackageManager(cwd, stack) {
|
|
|
18534
18790
|
if (stack === "python") return "pip";
|
|
18535
18791
|
if (stack === "go") return "go";
|
|
18536
18792
|
if (stack === "node") {
|
|
18537
|
-
if (await fileExists3(
|
|
18538
|
-
if (await fileExists3(
|
|
18539
|
-
if (await fileExists3(
|
|
18793
|
+
if (await fileExists3(path39__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
18794
|
+
if (await fileExists3(path39__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
18795
|
+
if (await fileExists3(path39__default.join(cwd, "bun.lockb"))) return "bun";
|
|
18540
18796
|
return "npm";
|
|
18541
18797
|
}
|
|
18542
18798
|
return null;
|
|
18543
18799
|
}
|
|
18544
18800
|
async function detectCI(cwd) {
|
|
18545
|
-
const ghDir =
|
|
18801
|
+
const ghDir = path39__default.join(cwd, ".github", "workflows");
|
|
18546
18802
|
if (await fileExists3(ghDir)) {
|
|
18547
18803
|
let workflowFiles = [];
|
|
18548
18804
|
let hasCodeQL = false;
|
|
@@ -18566,7 +18822,7 @@ async function detectCI(cwd) {
|
|
|
18566
18822
|
}
|
|
18567
18823
|
return { type: "github-actions", workflowFiles, hasCodeQL, hasLinting };
|
|
18568
18824
|
}
|
|
18569
|
-
if (await fileExists3(
|
|
18825
|
+
if (await fileExists3(path39__default.join(cwd, ".gitlab-ci.yml"))) {
|
|
18570
18826
|
return {
|
|
18571
18827
|
type: "gitlab-ci",
|
|
18572
18828
|
workflowFiles: [".gitlab-ci.yml"],
|
|
@@ -18574,7 +18830,7 @@ async function detectCI(cwd) {
|
|
|
18574
18830
|
hasLinting: false
|
|
18575
18831
|
};
|
|
18576
18832
|
}
|
|
18577
|
-
if (await fileExists3(
|
|
18833
|
+
if (await fileExists3(path39__default.join(cwd, ".circleci"))) {
|
|
18578
18834
|
return { type: "circle-ci", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
18579
18835
|
}
|
|
18580
18836
|
return { type: "none", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
@@ -19945,8 +20201,8 @@ function hasNullByte(str) {
|
|
|
19945
20201
|
}
|
|
19946
20202
|
function isBlockedPath(absolute) {
|
|
19947
20203
|
for (const blocked of BLOCKED_PATHS) {
|
|
19948
|
-
const normalizedBlocked =
|
|
19949
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
20204
|
+
const normalizedBlocked = path39__default.normalize(blocked);
|
|
20205
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path39__default.sep)) {
|
|
19950
20206
|
return blocked;
|
|
19951
20207
|
}
|
|
19952
20208
|
}
|
|
@@ -20040,7 +20296,7 @@ Examples:
|
|
|
20040
20296
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
20041
20297
|
}
|
|
20042
20298
|
const workDir = cwd ?? process.cwd();
|
|
20043
|
-
const absolute =
|
|
20299
|
+
const absolute = path39__default.isAbsolute(filePath) ? path39__default.normalize(filePath) : path39__default.resolve(workDir, filePath);
|
|
20044
20300
|
const blockedBy = isBlockedPath(absolute);
|
|
20045
20301
|
if (blockedBy) {
|
|
20046
20302
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -20063,14 +20319,14 @@ Examples:
|
|
|
20063
20319
|
};
|
|
20064
20320
|
}
|
|
20065
20321
|
if (isBlockedExecFile(absolute)) {
|
|
20066
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
20322
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path39__default.basename(absolute)}`, {
|
|
20067
20323
|
tool: "open_file"
|
|
20068
20324
|
});
|
|
20069
20325
|
}
|
|
20070
20326
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
20071
20327
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
20072
20328
|
}
|
|
20073
|
-
const ext =
|
|
20329
|
+
const ext = path39__default.extname(absolute);
|
|
20074
20330
|
const interpreter = getInterpreter(ext);
|
|
20075
20331
|
const executable = await isExecutable(absolute);
|
|
20076
20332
|
let command;
|
|
@@ -20083,7 +20339,7 @@ Examples:
|
|
|
20083
20339
|
cmdArgs = [...args];
|
|
20084
20340
|
} else {
|
|
20085
20341
|
throw new ToolError(
|
|
20086
|
-
`Cannot execute '${
|
|
20342
|
+
`Cannot execute '${path39__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
20087
20343
|
{ tool: "open_file" }
|
|
20088
20344
|
);
|
|
20089
20345
|
}
|
|
@@ -20255,10 +20511,10 @@ function getAllowedPaths() {
|
|
|
20255
20511
|
return [...sessionAllowedPaths];
|
|
20256
20512
|
}
|
|
20257
20513
|
function isWithinAllowedPath(absolutePath, operation) {
|
|
20258
|
-
const normalizedTarget =
|
|
20514
|
+
const normalizedTarget = path39__default.normalize(absolutePath);
|
|
20259
20515
|
for (const entry of sessionAllowedPaths) {
|
|
20260
|
-
const normalizedAllowed =
|
|
20261
|
-
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed +
|
|
20516
|
+
const normalizedAllowed = path39__default.normalize(entry.path);
|
|
20517
|
+
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path39__default.sep)) {
|
|
20262
20518
|
if (operation === "read") return true;
|
|
20263
20519
|
if (entry.level === "write") return true;
|
|
20264
20520
|
}
|
|
@@ -20266,8 +20522,8 @@ function isWithinAllowedPath(absolutePath, operation) {
|
|
|
20266
20522
|
return false;
|
|
20267
20523
|
}
|
|
20268
20524
|
function addAllowedPathToSession(dirPath, level) {
|
|
20269
|
-
const absolute =
|
|
20270
|
-
if (sessionAllowedPaths.some((e) =>
|
|
20525
|
+
const absolute = path39__default.resolve(dirPath);
|
|
20526
|
+
if (sessionAllowedPaths.some((e) => path39__default.normalize(e.path) === path39__default.normalize(absolute))) {
|
|
20271
20527
|
return;
|
|
20272
20528
|
}
|
|
20273
20529
|
sessionAllowedPaths.push({
|
|
@@ -20277,14 +20533,14 @@ function addAllowedPathToSession(dirPath, level) {
|
|
|
20277
20533
|
});
|
|
20278
20534
|
}
|
|
20279
20535
|
function removeAllowedPathFromSession(dirPath) {
|
|
20280
|
-
const absolute =
|
|
20281
|
-
const normalized =
|
|
20536
|
+
const absolute = path39__default.resolve(dirPath);
|
|
20537
|
+
const normalized = path39__default.normalize(absolute);
|
|
20282
20538
|
const before = sessionAllowedPaths.length;
|
|
20283
|
-
sessionAllowedPaths = sessionAllowedPaths.filter((e) =>
|
|
20539
|
+
sessionAllowedPaths = sessionAllowedPaths.filter((e) => path39__default.normalize(e.path) !== normalized);
|
|
20284
20540
|
return sessionAllowedPaths.length < before;
|
|
20285
20541
|
}
|
|
20286
20542
|
async function loadAllowedPaths(projectPath) {
|
|
20287
|
-
currentProjectPath =
|
|
20543
|
+
currentProjectPath = path39__default.resolve(projectPath);
|
|
20288
20544
|
const store = await loadStore();
|
|
20289
20545
|
const entries = store.projects[currentProjectPath] ?? [];
|
|
20290
20546
|
for (const entry of entries) {
|
|
@@ -20293,14 +20549,14 @@ async function loadAllowedPaths(projectPath) {
|
|
|
20293
20549
|
}
|
|
20294
20550
|
async function persistAllowedPath(dirPath, level) {
|
|
20295
20551
|
if (!currentProjectPath) return;
|
|
20296
|
-
const absolute =
|
|
20552
|
+
const absolute = path39__default.resolve(dirPath);
|
|
20297
20553
|
const store = await loadStore();
|
|
20298
20554
|
if (!store.projects[currentProjectPath]) {
|
|
20299
20555
|
store.projects[currentProjectPath] = [];
|
|
20300
20556
|
}
|
|
20301
20557
|
const entries = store.projects[currentProjectPath];
|
|
20302
|
-
const normalized =
|
|
20303
|
-
if (entries.some((e) =>
|
|
20558
|
+
const normalized = path39__default.normalize(absolute);
|
|
20559
|
+
if (entries.some((e) => path39__default.normalize(e.path) === normalized)) {
|
|
20304
20560
|
return;
|
|
20305
20561
|
}
|
|
20306
20562
|
entries.push({
|
|
@@ -20312,13 +20568,13 @@ async function persistAllowedPath(dirPath, level) {
|
|
|
20312
20568
|
}
|
|
20313
20569
|
async function removePersistedAllowedPath(dirPath) {
|
|
20314
20570
|
if (!currentProjectPath) return false;
|
|
20315
|
-
const absolute =
|
|
20316
|
-
const normalized =
|
|
20571
|
+
const absolute = path39__default.resolve(dirPath);
|
|
20572
|
+
const normalized = path39__default.normalize(absolute);
|
|
20317
20573
|
const store = await loadStore();
|
|
20318
20574
|
const entries = store.projects[currentProjectPath];
|
|
20319
20575
|
if (!entries) return false;
|
|
20320
20576
|
const before = entries.length;
|
|
20321
|
-
store.projects[currentProjectPath] = entries.filter((e) =>
|
|
20577
|
+
store.projects[currentProjectPath] = entries.filter((e) => path39__default.normalize(e.path) !== normalized);
|
|
20322
20578
|
if (store.projects[currentProjectPath].length < before) {
|
|
20323
20579
|
await saveStore(store);
|
|
20324
20580
|
return true;
|
|
@@ -20335,7 +20591,7 @@ async function loadStore() {
|
|
|
20335
20591
|
}
|
|
20336
20592
|
async function saveStore(store) {
|
|
20337
20593
|
try {
|
|
20338
|
-
await fs35__default.mkdir(
|
|
20594
|
+
await fs35__default.mkdir(path39__default.dirname(STORE_FILE), { recursive: true });
|
|
20339
20595
|
await fs35__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
20340
20596
|
} catch {
|
|
20341
20597
|
}
|
|
@@ -20344,7 +20600,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
|
|
|
20344
20600
|
var init_allowed_paths = __esm({
|
|
20345
20601
|
"src/tools/allowed-paths.ts"() {
|
|
20346
20602
|
init_paths();
|
|
20347
|
-
STORE_FILE =
|
|
20603
|
+
STORE_FILE = path39__default.join(CONFIG_PATHS.home, "allowed-paths.json");
|
|
20348
20604
|
DEFAULT_STORE = {
|
|
20349
20605
|
version: 1,
|
|
20350
20606
|
projects: {}
|
|
@@ -20854,7 +21110,7 @@ async function loadStore2() {
|
|
|
20854
21110
|
}
|
|
20855
21111
|
}
|
|
20856
21112
|
async function saveStore2(store) {
|
|
20857
|
-
await fs35__default.mkdir(
|
|
21113
|
+
await fs35__default.mkdir(path39__default.dirname(TOKEN_STORE_PATH), { recursive: true });
|
|
20858
21114
|
await fs35__default.writeFile(TOKEN_STORE_PATH, JSON.stringify(store, null, 2), {
|
|
20859
21115
|
encoding: "utf-8",
|
|
20860
21116
|
mode: 384
|
|
@@ -21201,7 +21457,7 @@ var init_oauth2 = __esm({
|
|
|
21201
21457
|
init_paths();
|
|
21202
21458
|
init_logger();
|
|
21203
21459
|
execFileAsync2 = promisify(execFile);
|
|
21204
|
-
TOKEN_STORE_PATH =
|
|
21460
|
+
TOKEN_STORE_PATH = path39__default.join(CONFIG_PATHS.tokens, "mcp-oauth.json");
|
|
21205
21461
|
OAUTH_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
21206
21462
|
logger = getLogger();
|
|
21207
21463
|
}
|
|
@@ -22075,7 +22331,7 @@ __export(allow_path_prompt_exports, {
|
|
|
22075
22331
|
promptAllowPath: () => promptAllowPath
|
|
22076
22332
|
});
|
|
22077
22333
|
async function promptAllowPath(dirPath) {
|
|
22078
|
-
const absolute =
|
|
22334
|
+
const absolute = path39__default.resolve(dirPath);
|
|
22079
22335
|
console.log();
|
|
22080
22336
|
console.log(chalk.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
22081
22337
|
console.log(chalk.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -22317,13 +22573,13 @@ __export(stack_detector_exports, {
|
|
|
22317
22573
|
detectProjectStack: () => detectProjectStack
|
|
22318
22574
|
});
|
|
22319
22575
|
async function detectStack2(cwd) {
|
|
22320
|
-
if (await fileExists3(
|
|
22321
|
-
if (await fileExists3(
|
|
22322
|
-
if (await fileExists3(
|
|
22323
|
-
if (await fileExists3(
|
|
22324
|
-
if (await fileExists3(
|
|
22325
|
-
if (await fileExists3(
|
|
22326
|
-
if (await fileExists3(
|
|
22576
|
+
if (await fileExists3(path39__default.join(cwd, "package.json"))) return "node";
|
|
22577
|
+
if (await fileExists3(path39__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
22578
|
+
if (await fileExists3(path39__default.join(cwd, "pyproject.toml"))) return "python";
|
|
22579
|
+
if (await fileExists3(path39__default.join(cwd, "go.mod"))) return "go";
|
|
22580
|
+
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) return "java";
|
|
22581
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle"))) return "java";
|
|
22582
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
22327
22583
|
return "unknown";
|
|
22328
22584
|
}
|
|
22329
22585
|
async function detectPackageManager3(cwd, stack) {
|
|
@@ -22331,23 +22587,23 @@ async function detectPackageManager3(cwd, stack) {
|
|
|
22331
22587
|
if (stack === "python") return "pip";
|
|
22332
22588
|
if (stack === "go") return "go";
|
|
22333
22589
|
if (stack === "java") {
|
|
22334
|
-
if (await fileExists3(
|
|
22590
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) {
|
|
22335
22591
|
return "gradle";
|
|
22336
22592
|
}
|
|
22337
|
-
if (await fileExists3(
|
|
22593
|
+
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) {
|
|
22338
22594
|
return "maven";
|
|
22339
22595
|
}
|
|
22340
22596
|
}
|
|
22341
22597
|
if (stack === "node") {
|
|
22342
|
-
if (await fileExists3(
|
|
22343
|
-
if (await fileExists3(
|
|
22344
|
-
if (await fileExists3(
|
|
22598
|
+
if (await fileExists3(path39__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
22599
|
+
if (await fileExists3(path39__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
22600
|
+
if (await fileExists3(path39__default.join(cwd, "bun.lockb"))) return "bun";
|
|
22345
22601
|
return "npm";
|
|
22346
22602
|
}
|
|
22347
22603
|
return null;
|
|
22348
22604
|
}
|
|
22349
22605
|
async function parsePackageJson(cwd) {
|
|
22350
|
-
const packageJsonPath =
|
|
22606
|
+
const packageJsonPath = path39__default.join(cwd, "package.json");
|
|
22351
22607
|
try {
|
|
22352
22608
|
const content = await fs35__default.readFile(packageJsonPath, "utf-8");
|
|
22353
22609
|
const pkg = JSON.parse(content);
|
|
@@ -22379,7 +22635,7 @@ async function parsePackageJson(cwd) {
|
|
|
22379
22635
|
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
22380
22636
|
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
22381
22637
|
const languages = ["JavaScript"];
|
|
22382
|
-
if (allDeps.typescript || await fileExists3(
|
|
22638
|
+
if (allDeps.typescript || await fileExists3(path39__default.join(cwd, "tsconfig.json"))) {
|
|
22383
22639
|
languages.push("TypeScript");
|
|
22384
22640
|
}
|
|
22385
22641
|
return {
|
|
@@ -22400,7 +22656,7 @@ async function parsePackageJson(cwd) {
|
|
|
22400
22656
|
}
|
|
22401
22657
|
}
|
|
22402
22658
|
async function parsePomXml(cwd) {
|
|
22403
|
-
const pomPath =
|
|
22659
|
+
const pomPath = path39__default.join(cwd, "pom.xml");
|
|
22404
22660
|
try {
|
|
22405
22661
|
const content = await fs35__default.readFile(pomPath, "utf-8");
|
|
22406
22662
|
const dependencies = {};
|
|
@@ -22437,7 +22693,7 @@ async function parsePomXml(cwd) {
|
|
|
22437
22693
|
}
|
|
22438
22694
|
}
|
|
22439
22695
|
async function parsePyprojectToml(cwd) {
|
|
22440
|
-
const pyprojectPath =
|
|
22696
|
+
const pyprojectPath = path39__default.join(cwd, "pyproject.toml");
|
|
22441
22697
|
try {
|
|
22442
22698
|
const content = await fs35__default.readFile(pyprojectPath, "utf-8");
|
|
22443
22699
|
const dependencies = {};
|
|
@@ -22480,7 +22736,7 @@ async function detectProjectStack(cwd) {
|
|
|
22480
22736
|
testingFrameworks = parsed.testingFrameworks;
|
|
22481
22737
|
languages = parsed.languages;
|
|
22482
22738
|
} else if (stack === "java") {
|
|
22483
|
-
const isGradle = await fileExists3(
|
|
22739
|
+
const isGradle = await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"));
|
|
22484
22740
|
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
22485
22741
|
dependencies = parsed.dependencies;
|
|
22486
22742
|
frameworks = parsed.frameworks;
|
|
@@ -22528,6 +22784,14 @@ __export(tools_exports, {
|
|
|
22528
22784
|
wrapMCPTool: () => wrapMCPTool,
|
|
22529
22785
|
wrapMCPTools: () => wrapMCPTools
|
|
22530
22786
|
});
|
|
22787
|
+
function buildMcpToolDescription(serverName, tool) {
|
|
22788
|
+
const base = tool.description || `Tool '${tool.name}' exposed by MCP server '${serverName}'`;
|
|
22789
|
+
const lowerServer = serverName.toLowerCase();
|
|
22790
|
+
if (lowerServer.includes("atlassian") || lowerServer.includes("jira") || lowerServer.includes("confluence")) {
|
|
22791
|
+
return `${base}. Use this MCP tool for Atlassian/Jira/Confluence data. Prefer it over direct web_fetch or http_fetch for Atlassian content.`;
|
|
22792
|
+
}
|
|
22793
|
+
return `${base}. Exposed by MCP server '${serverName}'. Prefer this MCP tool over generic web/http fetch when accessing data from that connected service.`;
|
|
22794
|
+
}
|
|
22531
22795
|
function jsonSchemaToZod(schema) {
|
|
22532
22796
|
if (schema.enum && Array.isArray(schema.enum)) {
|
|
22533
22797
|
const values = schema.enum;
|
|
@@ -22680,7 +22944,7 @@ function wrapMCPTool(tool, serverName, client, options = {}) {
|
|
|
22680
22944
|
const parametersSchema = createToolParametersSchema(tool);
|
|
22681
22945
|
const cocoTool = {
|
|
22682
22946
|
name: wrappedName,
|
|
22683
|
-
description:
|
|
22947
|
+
description: buildMcpToolDescription(serverName, tool),
|
|
22684
22948
|
category: opts.category,
|
|
22685
22949
|
parameters: parametersSchema,
|
|
22686
22950
|
execute: async (params) => {
|
|
@@ -22766,251 +23030,6 @@ var init_tools = __esm({
|
|
|
22766
23030
|
}
|
|
22767
23031
|
});
|
|
22768
23032
|
|
|
22769
|
-
// src/mcp/config-loader.ts
|
|
22770
|
-
var config_loader_exports = {};
|
|
22771
|
-
__export(config_loader_exports, {
|
|
22772
|
-
loadMCPConfigFile: () => loadMCPConfigFile,
|
|
22773
|
-
loadMCPServersFromCOCOConfig: () => loadMCPServersFromCOCOConfig,
|
|
22774
|
-
loadProjectMCPFile: () => loadProjectMCPFile,
|
|
22775
|
-
mergeMCPConfigs: () => mergeMCPConfigs
|
|
22776
|
-
});
|
|
22777
|
-
function expandEnvVar(value) {
|
|
22778
|
-
return value.replace(/\$\{([^}]+)\}/g, (match, name) => process.env[name] ?? match);
|
|
22779
|
-
}
|
|
22780
|
-
function expandEnvObject(env2) {
|
|
22781
|
-
const result = {};
|
|
22782
|
-
for (const [k, v] of Object.entries(env2)) {
|
|
22783
|
-
result[k] = expandEnvVar(v);
|
|
22784
|
-
}
|
|
22785
|
-
return result;
|
|
22786
|
-
}
|
|
22787
|
-
function expandHeaders(headers) {
|
|
22788
|
-
const result = {};
|
|
22789
|
-
for (const [k, v] of Object.entries(headers)) {
|
|
22790
|
-
result[k] = expandEnvVar(v);
|
|
22791
|
-
}
|
|
22792
|
-
return result;
|
|
22793
|
-
}
|
|
22794
|
-
function convertStandardEntry(name, entry) {
|
|
22795
|
-
if (entry.command) {
|
|
22796
|
-
return {
|
|
22797
|
-
name,
|
|
22798
|
-
transport: "stdio",
|
|
22799
|
-
enabled: entry.enabled ?? true,
|
|
22800
|
-
stdio: {
|
|
22801
|
-
command: entry.command,
|
|
22802
|
-
args: entry.args,
|
|
22803
|
-
env: entry.env ? expandEnvObject(entry.env) : void 0
|
|
22804
|
-
}
|
|
22805
|
-
};
|
|
22806
|
-
}
|
|
22807
|
-
if (entry.url) {
|
|
22808
|
-
const headers = entry.headers ? expandHeaders(entry.headers) : void 0;
|
|
22809
|
-
const authHeader = headers?.["Authorization"] ?? headers?.["authorization"];
|
|
22810
|
-
let auth;
|
|
22811
|
-
if (authHeader) {
|
|
22812
|
-
if (authHeader.startsWith("Bearer ")) {
|
|
22813
|
-
auth = { type: "bearer", token: authHeader.slice(7) };
|
|
22814
|
-
} else {
|
|
22815
|
-
auth = { type: "apikey", token: authHeader };
|
|
22816
|
-
}
|
|
22817
|
-
}
|
|
22818
|
-
return {
|
|
22819
|
-
name,
|
|
22820
|
-
transport: "http",
|
|
22821
|
-
enabled: entry.enabled ?? true,
|
|
22822
|
-
http: {
|
|
22823
|
-
url: entry.url,
|
|
22824
|
-
...headers && Object.keys(headers).length > 0 ? { headers } : {},
|
|
22825
|
-
...auth ? { auth } : {}
|
|
22826
|
-
}
|
|
22827
|
-
};
|
|
22828
|
-
}
|
|
22829
|
-
throw new Error(`Server "${name}" must have either "command" (stdio) or "url" (http) defined`);
|
|
22830
|
-
}
|
|
22831
|
-
async function loadMCPConfigFile(configPath) {
|
|
22832
|
-
try {
|
|
22833
|
-
await access(configPath);
|
|
22834
|
-
} catch {
|
|
22835
|
-
throw new MCPError(-32003 /* CONNECTION_ERROR */, `Config file not found: ${configPath}`);
|
|
22836
|
-
}
|
|
22837
|
-
let content;
|
|
22838
|
-
try {
|
|
22839
|
-
content = await readFile(configPath, "utf-8");
|
|
22840
|
-
} catch (error) {
|
|
22841
|
-
throw new MCPError(
|
|
22842
|
-
-32003 /* CONNECTION_ERROR */,
|
|
22843
|
-
`Failed to read config file: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
22844
|
-
);
|
|
22845
|
-
}
|
|
22846
|
-
let parsed;
|
|
22847
|
-
try {
|
|
22848
|
-
parsed = JSON.parse(content);
|
|
22849
|
-
} catch {
|
|
22850
|
-
throw new MCPError(-32700 /* PARSE_ERROR */, "Invalid JSON in config file");
|
|
22851
|
-
}
|
|
22852
|
-
const obj = parsed;
|
|
22853
|
-
if (obj.mcpServers && typeof obj.mcpServers === "object" && !Array.isArray(obj.mcpServers)) {
|
|
22854
|
-
return loadStandardFormat(obj, configPath);
|
|
22855
|
-
}
|
|
22856
|
-
if (obj.servers && Array.isArray(obj.servers)) {
|
|
22857
|
-
return loadCocoFormat(obj, configPath);
|
|
22858
|
-
}
|
|
22859
|
-
throw new MCPError(
|
|
22860
|
-
-32602 /* INVALID_PARAMS */,
|
|
22861
|
-
'Config file must have either a "mcpServers" object (standard) or a "servers" array (Coco format)'
|
|
22862
|
-
);
|
|
22863
|
-
}
|
|
22864
|
-
function loadStandardFormat(config, configPath) {
|
|
22865
|
-
const validServers = [];
|
|
22866
|
-
const errors = [];
|
|
22867
|
-
for (const [name, entry] of Object.entries(config.mcpServers)) {
|
|
22868
|
-
if (name.startsWith("_")) continue;
|
|
22869
|
-
try {
|
|
22870
|
-
const converted = convertStandardEntry(name, entry);
|
|
22871
|
-
validateServerConfig(converted);
|
|
22872
|
-
validServers.push(converted);
|
|
22873
|
-
} catch (error) {
|
|
22874
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
22875
|
-
errors.push(`Server '${name}': ${message}`);
|
|
22876
|
-
}
|
|
22877
|
-
}
|
|
22878
|
-
if (errors.length > 0) {
|
|
22879
|
-
getLogger().warn(`[MCP] Some servers in ${configPath} failed to load: ${errors.join("; ")}`);
|
|
22880
|
-
}
|
|
22881
|
-
return validServers;
|
|
22882
|
-
}
|
|
22883
|
-
async function loadProjectMCPFile(projectPath) {
|
|
22884
|
-
const mcpJsonPath = path38__default.join(projectPath, ".mcp.json");
|
|
22885
|
-
try {
|
|
22886
|
-
await access(mcpJsonPath);
|
|
22887
|
-
} catch {
|
|
22888
|
-
return [];
|
|
22889
|
-
}
|
|
22890
|
-
try {
|
|
22891
|
-
return await loadMCPConfigFile(mcpJsonPath);
|
|
22892
|
-
} catch (error) {
|
|
22893
|
-
getLogger().warn(
|
|
22894
|
-
`[MCP] Failed to load .mcp.json: ${error instanceof Error ? error.message : String(error)}`
|
|
22895
|
-
);
|
|
22896
|
-
return [];
|
|
22897
|
-
}
|
|
22898
|
-
}
|
|
22899
|
-
function loadCocoFormat(config, configPath) {
|
|
22900
|
-
const validServers = [];
|
|
22901
|
-
const errors = [];
|
|
22902
|
-
for (const server of config.servers) {
|
|
22903
|
-
try {
|
|
22904
|
-
const converted = convertCocoServerEntry(server);
|
|
22905
|
-
validateServerConfig(converted);
|
|
22906
|
-
validServers.push(converted);
|
|
22907
|
-
} catch (error) {
|
|
22908
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
22909
|
-
errors.push(`Server '${server.name || "unknown"}': ${message}`);
|
|
22910
|
-
}
|
|
22911
|
-
}
|
|
22912
|
-
if (errors.length > 0) {
|
|
22913
|
-
getLogger().warn(`[MCP] Some servers in ${configPath} failed to load: ${errors.join("; ")}`);
|
|
22914
|
-
}
|
|
22915
|
-
return validServers;
|
|
22916
|
-
}
|
|
22917
|
-
function convertCocoServerEntry(server) {
|
|
22918
|
-
const base = {
|
|
22919
|
-
name: server.name,
|
|
22920
|
-
description: server.description,
|
|
22921
|
-
transport: server.transport,
|
|
22922
|
-
enabled: server.enabled ?? true,
|
|
22923
|
-
metadata: server.metadata
|
|
22924
|
-
};
|
|
22925
|
-
if (server.transport === "stdio" && server.stdio) {
|
|
22926
|
-
return {
|
|
22927
|
-
...base,
|
|
22928
|
-
stdio: {
|
|
22929
|
-
command: server.stdio.command,
|
|
22930
|
-
args: server.stdio.args,
|
|
22931
|
-
env: server.stdio.env ? expandEnvObject(server.stdio.env) : void 0,
|
|
22932
|
-
cwd: server.stdio.cwd
|
|
22933
|
-
}
|
|
22934
|
-
};
|
|
22935
|
-
}
|
|
22936
|
-
if (server.transport === "http" && server.http) {
|
|
22937
|
-
return {
|
|
22938
|
-
...base,
|
|
22939
|
-
http: {
|
|
22940
|
-
url: server.http.url,
|
|
22941
|
-
...server.http.headers ? { headers: expandHeaders(server.http.headers) } : {},
|
|
22942
|
-
...server.http.auth ? { auth: server.http.auth } : {},
|
|
22943
|
-
...server.http.timeout !== void 0 ? { timeout: server.http.timeout } : {}
|
|
22944
|
-
}
|
|
22945
|
-
};
|
|
22946
|
-
}
|
|
22947
|
-
throw new Error(`Missing configuration for transport: ${server.transport}`);
|
|
22948
|
-
}
|
|
22949
|
-
function mergeMCPConfigs(base, ...overrides) {
|
|
22950
|
-
const merged = /* @__PURE__ */ new Map();
|
|
22951
|
-
for (const server of base) {
|
|
22952
|
-
merged.set(server.name, server);
|
|
22953
|
-
}
|
|
22954
|
-
for (const override of overrides) {
|
|
22955
|
-
for (const server of override) {
|
|
22956
|
-
const existing = merged.get(server.name);
|
|
22957
|
-
if (existing) {
|
|
22958
|
-
merged.set(server.name, { ...existing, ...server });
|
|
22959
|
-
} else {
|
|
22960
|
-
merged.set(server.name, server);
|
|
22961
|
-
}
|
|
22962
|
-
}
|
|
22963
|
-
}
|
|
22964
|
-
return Array.from(merged.values());
|
|
22965
|
-
}
|
|
22966
|
-
async function loadMCPServersFromCOCOConfig(configPath) {
|
|
22967
|
-
const { loadConfig: loadConfig3 } = await Promise.resolve().then(() => (init_loader(), loader_exports));
|
|
22968
|
-
const { MCPServerConfigEntrySchema: MCPServerConfigEntrySchema2 } = await Promise.resolve().then(() => (init_schema(), schema_exports));
|
|
22969
|
-
const config = await loadConfig3(configPath);
|
|
22970
|
-
if (!config.mcp?.servers || config.mcp.servers.length === 0) {
|
|
22971
|
-
return [];
|
|
22972
|
-
}
|
|
22973
|
-
const servers = [];
|
|
22974
|
-
for (const entry of config.mcp.servers) {
|
|
22975
|
-
try {
|
|
22976
|
-
const parsed = MCPServerConfigEntrySchema2.parse(entry);
|
|
22977
|
-
const serverConfig = {
|
|
22978
|
-
name: parsed.name,
|
|
22979
|
-
description: parsed.description,
|
|
22980
|
-
transport: parsed.transport,
|
|
22981
|
-
enabled: parsed.enabled,
|
|
22982
|
-
...parsed.transport === "stdio" && parsed.command && {
|
|
22983
|
-
stdio: {
|
|
22984
|
-
command: parsed.command,
|
|
22985
|
-
args: parsed.args,
|
|
22986
|
-
env: parsed.env ? expandEnvObject(parsed.env) : void 0
|
|
22987
|
-
}
|
|
22988
|
-
},
|
|
22989
|
-
...parsed.transport === "http" && parsed.url && {
|
|
22990
|
-
http: {
|
|
22991
|
-
url: parsed.url,
|
|
22992
|
-
auth: parsed.auth
|
|
22993
|
-
}
|
|
22994
|
-
}
|
|
22995
|
-
};
|
|
22996
|
-
validateServerConfig(serverConfig);
|
|
22997
|
-
servers.push(serverConfig);
|
|
22998
|
-
} catch (error) {
|
|
22999
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
23000
|
-
getLogger().warn(`[MCP] Failed to load server '${entry.name}': ${message}`);
|
|
23001
|
-
}
|
|
23002
|
-
}
|
|
23003
|
-
return servers;
|
|
23004
|
-
}
|
|
23005
|
-
var init_config_loader = __esm({
|
|
23006
|
-
"src/mcp/config-loader.ts"() {
|
|
23007
|
-
init_config();
|
|
23008
|
-
init_types();
|
|
23009
|
-
init_errors2();
|
|
23010
|
-
init_logger();
|
|
23011
|
-
}
|
|
23012
|
-
});
|
|
23013
|
-
|
|
23014
23033
|
// src/cli/repl/hooks/types.ts
|
|
23015
23034
|
function isHookEvent(value) {
|
|
23016
23035
|
return typeof value === "string" && HOOK_EVENTS.includes(value);
|
|
@@ -24193,23 +24212,23 @@ init_version();
|
|
|
24193
24212
|
// src/orchestrator/project.ts
|
|
24194
24213
|
init_env();
|
|
24195
24214
|
async function createProjectStructure(projectPath, info) {
|
|
24196
|
-
const cocoPath =
|
|
24215
|
+
const cocoPath = path39__default.join(projectPath, ".coco");
|
|
24197
24216
|
const directories = [
|
|
24198
24217
|
cocoPath,
|
|
24199
|
-
|
|
24200
|
-
|
|
24201
|
-
|
|
24202
|
-
|
|
24203
|
-
|
|
24204
|
-
|
|
24205
|
-
|
|
24206
|
-
|
|
24207
|
-
|
|
24208
|
-
|
|
24209
|
-
|
|
24210
|
-
|
|
24211
|
-
|
|
24212
|
-
|
|
24218
|
+
path39__default.join(cocoPath, "state"),
|
|
24219
|
+
path39__default.join(cocoPath, "checkpoints"),
|
|
24220
|
+
path39__default.join(cocoPath, "logs"),
|
|
24221
|
+
path39__default.join(cocoPath, "discovery"),
|
|
24222
|
+
path39__default.join(cocoPath, "spec"),
|
|
24223
|
+
path39__default.join(cocoPath, "architecture"),
|
|
24224
|
+
path39__default.join(cocoPath, "architecture", "adrs"),
|
|
24225
|
+
path39__default.join(cocoPath, "architecture", "diagrams"),
|
|
24226
|
+
path39__default.join(cocoPath, "planning"),
|
|
24227
|
+
path39__default.join(cocoPath, "planning", "epics"),
|
|
24228
|
+
path39__default.join(cocoPath, "execution"),
|
|
24229
|
+
path39__default.join(cocoPath, "versions"),
|
|
24230
|
+
path39__default.join(cocoPath, "reviews"),
|
|
24231
|
+
path39__default.join(cocoPath, "delivery")
|
|
24213
24232
|
];
|
|
24214
24233
|
for (const dir of directories) {
|
|
24215
24234
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
@@ -24247,7 +24266,7 @@ async function createInitialConfig(cocoPath, info) {
|
|
|
24247
24266
|
maxCheckpoints: 50
|
|
24248
24267
|
}
|
|
24249
24268
|
};
|
|
24250
|
-
await fs35__default.writeFile(
|
|
24269
|
+
await fs35__default.writeFile(path39__default.join(cocoPath, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
24251
24270
|
}
|
|
24252
24271
|
async function createProjectState(cocoPath, info) {
|
|
24253
24272
|
const state = {
|
|
@@ -24265,7 +24284,7 @@ async function createProjectState(cocoPath, info) {
|
|
|
24265
24284
|
lastCheckpoint: null
|
|
24266
24285
|
};
|
|
24267
24286
|
await fs35__default.writeFile(
|
|
24268
|
-
|
|
24287
|
+
path39__default.join(cocoPath, "state", "project.json"),
|
|
24269
24288
|
JSON.stringify(state, null, 2),
|
|
24270
24289
|
"utf-8"
|
|
24271
24290
|
);
|
|
@@ -24286,7 +24305,7 @@ checkpoints/
|
|
|
24286
24305
|
state/session.json
|
|
24287
24306
|
state/lock.json
|
|
24288
24307
|
`;
|
|
24289
|
-
await fs35__default.writeFile(
|
|
24308
|
+
await fs35__default.writeFile(path39__default.join(cocoPath, ".gitignore"), content, "utf-8");
|
|
24290
24309
|
}
|
|
24291
24310
|
async function createReadme(cocoPath, info) {
|
|
24292
24311
|
const content = `# Corbat-Coco Project: ${info.name}
|
|
@@ -24333,7 +24352,7 @@ Edit \`config.json\` to customize:
|
|
|
24333
24352
|
---
|
|
24334
24353
|
Generated by Corbat-Coco v0.1.0
|
|
24335
24354
|
`;
|
|
24336
|
-
await fs35__default.writeFile(
|
|
24355
|
+
await fs35__default.writeFile(path39__default.join(cocoPath, "README.md"), content, "utf-8");
|
|
24337
24356
|
}
|
|
24338
24357
|
|
|
24339
24358
|
// src/cli/commands/init.ts
|
|
@@ -25637,13 +25656,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
25637
25656
|
// src/phases/converge/persistence.ts
|
|
25638
25657
|
init_errors();
|
|
25639
25658
|
function getPersistencePaths(projectPath) {
|
|
25640
|
-
const baseDir =
|
|
25659
|
+
const baseDir = path39__default.join(projectPath, ".coco", "spec");
|
|
25641
25660
|
return {
|
|
25642
25661
|
baseDir,
|
|
25643
|
-
sessionFile:
|
|
25644
|
-
specFile:
|
|
25645
|
-
conversationLog:
|
|
25646
|
-
checkpointFile:
|
|
25662
|
+
sessionFile: path39__default.join(baseDir, "discovery-session.json"),
|
|
25663
|
+
specFile: path39__default.join(baseDir, "spec.md"),
|
|
25664
|
+
conversationLog: path39__default.join(baseDir, "conversation.jsonl"),
|
|
25665
|
+
checkpointFile: path39__default.join(baseDir, "checkpoint.json")
|
|
25647
25666
|
};
|
|
25648
25667
|
}
|
|
25649
25668
|
var SessionPersistence = class {
|
|
@@ -27747,7 +27766,7 @@ var OrchestrateExecutor = class {
|
|
|
27747
27766
|
}
|
|
27748
27767
|
async loadSpecification(projectPath) {
|
|
27749
27768
|
try {
|
|
27750
|
-
const jsonPath =
|
|
27769
|
+
const jsonPath = path39__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
27751
27770
|
const jsonContent = await fs35__default.readFile(jsonPath, "utf-8");
|
|
27752
27771
|
return JSON.parse(jsonContent);
|
|
27753
27772
|
} catch {
|
|
@@ -27759,7 +27778,7 @@ var OrchestrateExecutor = class {
|
|
|
27759
27778
|
version: "1.0.0",
|
|
27760
27779
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
27761
27780
|
overview: {
|
|
27762
|
-
name:
|
|
27781
|
+
name: path39__default.basename(projectPath),
|
|
27763
27782
|
description: "Project specification",
|
|
27764
27783
|
goals: [],
|
|
27765
27784
|
targetUsers: ["developers"],
|
|
@@ -27786,52 +27805,52 @@ var OrchestrateExecutor = class {
|
|
|
27786
27805
|
};
|
|
27787
27806
|
}
|
|
27788
27807
|
async saveArchitecture(projectPath, architecture) {
|
|
27789
|
-
const dir =
|
|
27808
|
+
const dir = path39__default.join(projectPath, ".coco", "architecture");
|
|
27790
27809
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
27791
|
-
const mdPath =
|
|
27810
|
+
const mdPath = path39__default.join(dir, "ARCHITECTURE.md");
|
|
27792
27811
|
await fs35__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
27793
|
-
const jsonPath =
|
|
27812
|
+
const jsonPath = path39__default.join(dir, "architecture.json");
|
|
27794
27813
|
await fs35__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
27795
27814
|
return mdPath;
|
|
27796
27815
|
}
|
|
27797
27816
|
async saveADRs(projectPath, adrs) {
|
|
27798
|
-
const dir =
|
|
27817
|
+
const dir = path39__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
27799
27818
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
27800
27819
|
const paths = [];
|
|
27801
|
-
const indexPath =
|
|
27820
|
+
const indexPath = path39__default.join(dir, "README.md");
|
|
27802
27821
|
await fs35__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
27803
27822
|
paths.push(indexPath);
|
|
27804
27823
|
for (const adr of adrs) {
|
|
27805
27824
|
const filename = getADRFilename(adr);
|
|
27806
|
-
const adrPath =
|
|
27825
|
+
const adrPath = path39__default.join(dir, filename);
|
|
27807
27826
|
await fs35__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
27808
27827
|
paths.push(adrPath);
|
|
27809
27828
|
}
|
|
27810
27829
|
return paths;
|
|
27811
27830
|
}
|
|
27812
27831
|
async saveBacklog(projectPath, backlogResult) {
|
|
27813
|
-
const dir =
|
|
27832
|
+
const dir = path39__default.join(projectPath, ".coco", "planning");
|
|
27814
27833
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
27815
|
-
const mdPath =
|
|
27834
|
+
const mdPath = path39__default.join(dir, "BACKLOG.md");
|
|
27816
27835
|
await fs35__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
27817
|
-
const jsonPath =
|
|
27836
|
+
const jsonPath = path39__default.join(dir, "backlog.json");
|
|
27818
27837
|
await fs35__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
27819
27838
|
return mdPath;
|
|
27820
27839
|
}
|
|
27821
27840
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
27822
|
-
const dir =
|
|
27841
|
+
const dir = path39__default.join(projectPath, ".coco", "planning", "sprints");
|
|
27823
27842
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
27824
27843
|
const filename = `${sprint.id}.md`;
|
|
27825
|
-
const sprintPath =
|
|
27844
|
+
const sprintPath = path39__default.join(dir, filename);
|
|
27826
27845
|
await fs35__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
27827
|
-
const jsonPath =
|
|
27846
|
+
const jsonPath = path39__default.join(dir, `${sprint.id}.json`);
|
|
27828
27847
|
await fs35__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
27829
27848
|
return sprintPath;
|
|
27830
27849
|
}
|
|
27831
27850
|
async saveDiagram(projectPath, id, mermaid) {
|
|
27832
|
-
const dir =
|
|
27851
|
+
const dir = path39__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
27833
27852
|
await fs35__default.mkdir(dir, { recursive: true });
|
|
27834
|
-
const diagramPath =
|
|
27853
|
+
const diagramPath = path39__default.join(dir, `${id}.mmd`);
|
|
27835
27854
|
await fs35__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
27836
27855
|
return diagramPath;
|
|
27837
27856
|
}
|
|
@@ -30082,10 +30101,10 @@ async function runAdd(source, options) {
|
|
|
30082
30101
|
const isGithubShorthand = source.includes("/") && !isGitUrl;
|
|
30083
30102
|
const isLocalPath = source.startsWith(".") || source.startsWith("/");
|
|
30084
30103
|
if (isLocalPath) {
|
|
30085
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
30086
|
-
const sourcePath =
|
|
30087
|
-
const skillName =
|
|
30088
|
-
const destPath =
|
|
30104
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path39__default.join(process.cwd(), ".agents", "skills");
|
|
30105
|
+
const sourcePath = path39__default.resolve(source);
|
|
30106
|
+
const skillName = path39__default.basename(sourcePath);
|
|
30107
|
+
const destPath = path39__default.join(targetDir, skillName);
|
|
30089
30108
|
try {
|
|
30090
30109
|
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
30091
30110
|
await fs35__default.cp(sourcePath, destPath, { recursive: true });
|
|
@@ -30119,10 +30138,10 @@ async function runAdd(source, options) {
|
|
|
30119
30138
|
p26.log.info("Try installing manually: git clone the repo into .agents/skills/");
|
|
30120
30139
|
}
|
|
30121
30140
|
} else if (isGitUrl) {
|
|
30122
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
30141
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path39__default.join(process.cwd(), ".agents", "skills");
|
|
30123
30142
|
await fs35__default.mkdir(targetDir, { recursive: true });
|
|
30124
30143
|
const skillName = source.split("/").pop()?.replace(".git", "") ?? "skill";
|
|
30125
|
-
const skillDir =
|
|
30144
|
+
const skillDir = path39__default.join(targetDir, skillName);
|
|
30126
30145
|
const spinner18 = p26.spinner();
|
|
30127
30146
|
spinner18.start(`Cloning ${source}...`);
|
|
30128
30147
|
try {
|
|
@@ -30148,9 +30167,9 @@ async function runAdd(source, options) {
|
|
|
30148
30167
|
}
|
|
30149
30168
|
async function runRemove(name, options) {
|
|
30150
30169
|
p26.intro(chalk.magenta("Remove Skill"));
|
|
30151
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
30152
|
-
const skillPath =
|
|
30153
|
-
if (!skillPath.startsWith(
|
|
30170
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path39__default.join(process.cwd(), ".agents", "skills");
|
|
30171
|
+
const skillPath = path39__default.resolve(targetDir, name);
|
|
30172
|
+
if (!skillPath.startsWith(path39__default.resolve(targetDir) + path39__default.sep)) {
|
|
30154
30173
|
p26.log.error(`Invalid skill name: "${name}"`);
|
|
30155
30174
|
p26.outro("");
|
|
30156
30175
|
return;
|
|
@@ -30234,8 +30253,8 @@ async function runInfo(name) {
|
|
|
30234
30253
|
}
|
|
30235
30254
|
async function runCreate(name, options) {
|
|
30236
30255
|
p26.intro(chalk.magenta("Create Skill"));
|
|
30237
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
30238
|
-
const skillDir =
|
|
30256
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path39__default.join(process.cwd(), ".agents", "skills");
|
|
30257
|
+
const skillDir = path39__default.join(targetDir, name);
|
|
30239
30258
|
try {
|
|
30240
30259
|
await fs35__default.access(skillDir);
|
|
30241
30260
|
p26.log.error(`Skill "${name}" already exists at ${skillDir}`);
|
|
@@ -30288,10 +30307,10 @@ when this skill is activated (automatically via matching or manually via /${name
|
|
|
30288
30307
|
2. Include examples when helpful
|
|
30289
30308
|
3. Keep instructions under 500 lines
|
|
30290
30309
|
`;
|
|
30291
|
-
await fs35__default.writeFile(
|
|
30292
|
-
await fs35__default.mkdir(
|
|
30310
|
+
await fs35__default.writeFile(path39__default.join(skillDir, "SKILL.md"), skillMd, "utf-8");
|
|
30311
|
+
await fs35__default.mkdir(path39__default.join(skillDir, "references"), { recursive: true });
|
|
30293
30312
|
p26.log.success(`Created skill at ${skillDir}`);
|
|
30294
|
-
p26.log.info(`Edit ${
|
|
30313
|
+
p26.log.info(`Edit ${path39__default.join(skillDir, "SKILL.md")} to add instructions.`);
|
|
30295
30314
|
p26.outro("");
|
|
30296
30315
|
}
|
|
30297
30316
|
function registerWinner(winners, candidate, candidateScanOrder, scanOrderById) {
|
|
@@ -33988,7 +34007,7 @@ async function saveConfiguration(result) {
|
|
|
33988
34007
|
}
|
|
33989
34008
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
33990
34009
|
if (createDir) {
|
|
33991
|
-
const dir =
|
|
34010
|
+
const dir = path39.dirname(filePath);
|
|
33992
34011
|
try {
|
|
33993
34012
|
await fs35.mkdir(dir, { recursive: true, mode: 448 });
|
|
33994
34013
|
} catch {
|
|
@@ -35559,7 +35578,7 @@ var buildCommand = {
|
|
|
35559
35578
|
};
|
|
35560
35579
|
async function loadBacklog(projectPath) {
|
|
35561
35580
|
try {
|
|
35562
|
-
const backlogPath =
|
|
35581
|
+
const backlogPath = path39.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35563
35582
|
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35564
35583
|
const data = JSON.parse(content);
|
|
35565
35584
|
return data.backlog;
|
|
@@ -35569,13 +35588,13 @@ async function loadBacklog(projectPath) {
|
|
|
35569
35588
|
}
|
|
35570
35589
|
async function loadSprint(projectPath, sprintId) {
|
|
35571
35590
|
try {
|
|
35572
|
-
const sprintsDir =
|
|
35591
|
+
const sprintsDir = path39.join(projectPath, ".coco", "planning", "sprints");
|
|
35573
35592
|
const files = await fs35.readdir(sprintsDir);
|
|
35574
35593
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
35575
35594
|
if (jsonFiles.length === 0) return null;
|
|
35576
35595
|
const targetFile = sprintId ? jsonFiles.find((f) => f.includes(sprintId)) : jsonFiles[0];
|
|
35577
35596
|
if (!targetFile) return null;
|
|
35578
|
-
const sprintPath =
|
|
35597
|
+
const sprintPath = path39.join(sprintsDir, targetFile);
|
|
35579
35598
|
const content = await fs35.readFile(sprintPath, "utf-8");
|
|
35580
35599
|
return JSON.parse(content);
|
|
35581
35600
|
} catch {
|
|
@@ -35583,7 +35602,7 @@ async function loadSprint(projectPath, sprintId) {
|
|
|
35583
35602
|
}
|
|
35584
35603
|
}
|
|
35585
35604
|
async function saveBacklog(projectPath, backlog) {
|
|
35586
|
-
const backlogPath =
|
|
35605
|
+
const backlogPath = path39.join(projectPath, ".coco", "planning", "backlog.json");
|
|
35587
35606
|
const content = await fs35.readFile(backlogPath, "utf-8");
|
|
35588
35607
|
const data = JSON.parse(content);
|
|
35589
35608
|
data.backlog = backlog;
|
|
@@ -36293,7 +36312,7 @@ function getLevelName(level) {
|
|
|
36293
36312
|
function displayMemoryFile(file) {
|
|
36294
36313
|
const { emoji, color } = getLevelStyle(file.level);
|
|
36295
36314
|
const levelName = getLevelName(file.level);
|
|
36296
|
-
const fileName =
|
|
36315
|
+
const fileName = path39__default.basename(file.path);
|
|
36297
36316
|
console.log();
|
|
36298
36317
|
console.log(
|
|
36299
36318
|
`${emoji} ${color.bold(levelName)} ${chalk.dim(`(${fileName})`)} ${chalk.dim(file.path)}`
|
|
@@ -36388,7 +36407,7 @@ var memoryCommand = {
|
|
|
36388
36407
|
)
|
|
36389
36408
|
);
|
|
36390
36409
|
for (const f of reloaded) {
|
|
36391
|
-
const fileName =
|
|
36410
|
+
const fileName = path39__default.basename(f.path);
|
|
36392
36411
|
console.log(chalk.dim(` ${fileName} (${formatSize(f.content?.length ?? 0)})`));
|
|
36393
36412
|
}
|
|
36394
36413
|
} else {
|
|
@@ -37259,8 +37278,8 @@ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@corbat-tech/coco/latest";
|
|
|
37259
37278
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
37260
37279
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
37261
37280
|
var STARTUP_TIMEOUT_MS = 5500;
|
|
37262
|
-
var CACHE_DIR =
|
|
37263
|
-
var CACHE_FILE =
|
|
37281
|
+
var CACHE_DIR = path39__default.join(os4__default.homedir(), ".coco");
|
|
37282
|
+
var CACHE_FILE = path39__default.join(CACHE_DIR, "version-check-cache.json");
|
|
37264
37283
|
function compareVersions(a, b) {
|
|
37265
37284
|
const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
37266
37285
|
const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
@@ -37602,7 +37621,7 @@ async function readClipboardImage() {
|
|
|
37602
37621
|
return null;
|
|
37603
37622
|
}
|
|
37604
37623
|
async function readClipboardImageMacOS() {
|
|
37605
|
-
const tmpFile =
|
|
37624
|
+
const tmpFile = path39.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37606
37625
|
try {
|
|
37607
37626
|
const script = `
|
|
37608
37627
|
set theFile to POSIX file "${tmpFile}"
|
|
@@ -37664,7 +37683,7 @@ async function readClipboardImageLinux() {
|
|
|
37664
37683
|
}
|
|
37665
37684
|
}
|
|
37666
37685
|
async function readClipboardImageWindows() {
|
|
37667
|
-
const tmpFile =
|
|
37686
|
+
const tmpFile = path39.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
37668
37687
|
try {
|
|
37669
37688
|
const escapedPath = tmpFile.replace(/'/g, "''");
|
|
37670
37689
|
const script = `
|
|
@@ -37789,7 +37808,7 @@ var allowPathCommand = {
|
|
|
37789
37808
|
}
|
|
37790
37809
|
};
|
|
37791
37810
|
async function addPath(dirPath, session) {
|
|
37792
|
-
const absolute =
|
|
37811
|
+
const absolute = path39__default.resolve(dirPath);
|
|
37793
37812
|
try {
|
|
37794
37813
|
const stat2 = await fs35__default.stat(absolute);
|
|
37795
37814
|
if (!stat2.isDirectory()) {
|
|
@@ -37801,19 +37820,19 @@ async function addPath(dirPath, session) {
|
|
|
37801
37820
|
return;
|
|
37802
37821
|
}
|
|
37803
37822
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
37804
|
-
const normalizedBlocked =
|
|
37805
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
37823
|
+
const normalizedBlocked = path39__default.normalize(blocked);
|
|
37824
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path39__default.sep)) {
|
|
37806
37825
|
p26.log.error(`System path '${blocked}' cannot be allowed`);
|
|
37807
37826
|
return;
|
|
37808
37827
|
}
|
|
37809
37828
|
}
|
|
37810
|
-
const normalizedCwd =
|
|
37811
|
-
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd +
|
|
37829
|
+
const normalizedCwd = path39__default.normalize(session.projectPath);
|
|
37830
|
+
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd + path39__default.sep)) {
|
|
37812
37831
|
p26.log.info("That path is already within the project directory");
|
|
37813
37832
|
return;
|
|
37814
37833
|
}
|
|
37815
37834
|
const existing = getAllowedPaths();
|
|
37816
|
-
if (existing.some((e) =>
|
|
37835
|
+
if (existing.some((e) => path39__default.normalize(e.path) === path39__default.normalize(absolute))) {
|
|
37817
37836
|
p26.log.info(`Already allowed: ${absolute}`);
|
|
37818
37837
|
return;
|
|
37819
37838
|
}
|
|
@@ -37884,7 +37903,7 @@ async function revokePath(dirPath, _session) {
|
|
|
37884
37903
|
}
|
|
37885
37904
|
dirPath = selected;
|
|
37886
37905
|
}
|
|
37887
|
-
const absolute =
|
|
37906
|
+
const absolute = path39__default.resolve(dirPath);
|
|
37888
37907
|
const removed = removeAllowedPathFromSession(absolute);
|
|
37889
37908
|
await removePersistedAllowedPath(absolute);
|
|
37890
37909
|
if (removed) {
|
|
@@ -38257,7 +38276,7 @@ async function savePermissionPreference(key, value) {
|
|
|
38257
38276
|
} catch {
|
|
38258
38277
|
}
|
|
38259
38278
|
config[key] = value;
|
|
38260
|
-
await fs35__default.mkdir(
|
|
38279
|
+
await fs35__default.mkdir(path39__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
38261
38280
|
await fs35__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
38262
38281
|
} catch {
|
|
38263
38282
|
}
|
|
@@ -38974,15 +38993,20 @@ var tutorialCommand = {
|
|
|
38974
38993
|
// src/cli/repl/commands/mcp.ts
|
|
38975
38994
|
init_lifecycle();
|
|
38976
38995
|
init_registry();
|
|
38996
|
+
init_config_loader();
|
|
38977
38997
|
function formatLatency(ms) {
|
|
38978
38998
|
if (ms < 1) return "<1ms";
|
|
38979
38999
|
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
38980
39000
|
return `${(ms / 1e3).toFixed(1)}s`;
|
|
38981
39001
|
}
|
|
38982
|
-
async function listServers() {
|
|
39002
|
+
async function listServers(session) {
|
|
38983
39003
|
const registry = new MCPRegistryImpl();
|
|
38984
39004
|
await registry.load();
|
|
38985
|
-
const servers =
|
|
39005
|
+
const servers = mergeMCPConfigs(
|
|
39006
|
+
registry.listServers(),
|
|
39007
|
+
await loadMCPServersFromCOCOConfig(),
|
|
39008
|
+
await loadProjectMCPFile(session.projectPath)
|
|
39009
|
+
);
|
|
38986
39010
|
const manager = getMCPServerManager();
|
|
38987
39011
|
p26.intro("MCP Servers");
|
|
38988
39012
|
if (servers.length === 0) {
|
|
@@ -39084,12 +39108,12 @@ var mcpCommand = {
|
|
|
39084
39108
|
aliases: [],
|
|
39085
39109
|
description: "Manage MCP servers (list, status, health, restart)",
|
|
39086
39110
|
usage: "/mcp [list|status|health [name]|restart <name>]",
|
|
39087
|
-
execute: async (args,
|
|
39111
|
+
execute: async (args, session) => {
|
|
39088
39112
|
const subcommand = args[0]?.toLowerCase() ?? "list";
|
|
39089
39113
|
try {
|
|
39090
39114
|
switch (subcommand) {
|
|
39091
39115
|
case "list":
|
|
39092
|
-
await listServers();
|
|
39116
|
+
await listServers(session);
|
|
39093
39117
|
break;
|
|
39094
39118
|
case "status":
|
|
39095
39119
|
showStatus2();
|
|
@@ -39448,9 +39472,9 @@ Response format (JSON only, no prose):
|
|
|
39448
39472
|
cancel5("Build cancelled.");
|
|
39449
39473
|
}
|
|
39450
39474
|
}
|
|
39451
|
-
const cocoDir =
|
|
39475
|
+
const cocoDir = path39__default.join(outputPath, ".coco");
|
|
39452
39476
|
await fs35__default.mkdir(cocoDir, { recursive: true });
|
|
39453
|
-
await fs35__default.writeFile(
|
|
39477
|
+
await fs35__default.writeFile(path39__default.join(cocoDir, "backlog.json"), JSON.stringify(spec, null, 2), "utf-8");
|
|
39454
39478
|
p26.outro(" Spec saved \u2014 starting sprints");
|
|
39455
39479
|
return spec;
|
|
39456
39480
|
}
|
|
@@ -40000,19 +40024,19 @@ init_errors();
|
|
|
40000
40024
|
init_subprocess_registry();
|
|
40001
40025
|
async function detectTestFramework2(cwd) {
|
|
40002
40026
|
try {
|
|
40003
|
-
await fs35__default.access(
|
|
40027
|
+
await fs35__default.access(path39__default.join(cwd, "pom.xml"));
|
|
40004
40028
|
return "maven";
|
|
40005
40029
|
} catch {
|
|
40006
40030
|
}
|
|
40007
40031
|
for (const gradleFile of ["build.gradle", "build.gradle.kts"]) {
|
|
40008
40032
|
try {
|
|
40009
|
-
await fs35__default.access(
|
|
40033
|
+
await fs35__default.access(path39__default.join(cwd, gradleFile));
|
|
40010
40034
|
return "gradle";
|
|
40011
40035
|
} catch {
|
|
40012
40036
|
}
|
|
40013
40037
|
}
|
|
40014
40038
|
try {
|
|
40015
|
-
const pkgPath =
|
|
40039
|
+
const pkgPath = path39__default.join(cwd, "package.json");
|
|
40016
40040
|
const pkgContent = await fs35__default.readFile(pkgPath, "utf-8");
|
|
40017
40041
|
const pkg = JSON.parse(pkgContent);
|
|
40018
40042
|
const deps = {
|
|
@@ -40029,16 +40053,16 @@ async function detectTestFramework2(cwd) {
|
|
|
40029
40053
|
}
|
|
40030
40054
|
}
|
|
40031
40055
|
function toMavenTestFilter(pattern) {
|
|
40032
|
-
const base =
|
|
40056
|
+
const base = path39__default.basename(pattern).replace(/\.java$/, "");
|
|
40033
40057
|
return base;
|
|
40034
40058
|
}
|
|
40035
40059
|
function toGradleTestFilter(pattern) {
|
|
40036
|
-
const base =
|
|
40060
|
+
const base = path39__default.basename(pattern).replace(/\.java$/, "");
|
|
40037
40061
|
return `*${base}`;
|
|
40038
40062
|
}
|
|
40039
40063
|
async function mavenExecutable(cwd) {
|
|
40040
40064
|
try {
|
|
40041
|
-
await fs35__default.access(
|
|
40065
|
+
await fs35__default.access(path39__default.join(cwd, "mvnw"));
|
|
40042
40066
|
return "./mvnw";
|
|
40043
40067
|
} catch {
|
|
40044
40068
|
return "mvn";
|
|
@@ -40046,7 +40070,7 @@ async function mavenExecutable(cwd) {
|
|
|
40046
40070
|
}
|
|
40047
40071
|
async function gradleExecutable(cwd) {
|
|
40048
40072
|
try {
|
|
40049
|
-
await fs35__default.access(
|
|
40073
|
+
await fs35__default.access(path39__default.join(cwd, "gradlew"));
|
|
40050
40074
|
return "./gradlew";
|
|
40051
40075
|
} catch {
|
|
40052
40076
|
return "gradle";
|
|
@@ -40287,14 +40311,14 @@ Examples:
|
|
|
40287
40311
|
const projectDir = cwd ?? process.cwd();
|
|
40288
40312
|
try {
|
|
40289
40313
|
const coverageLocations = [
|
|
40290
|
-
|
|
40291
|
-
|
|
40292
|
-
|
|
40314
|
+
path39__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
40315
|
+
path39__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
40316
|
+
path39__default.join(projectDir, ".nyc_output", "coverage-summary.json"),
|
|
40293
40317
|
// Maven JaCoCo
|
|
40294
|
-
|
|
40295
|
-
|
|
40318
|
+
path39__default.join(projectDir, "target", "site", "jacoco", "jacoco.csv"),
|
|
40319
|
+
path39__default.join(projectDir, "target", "site", "jacoco-ut", "jacoco.csv"),
|
|
40296
40320
|
// Gradle JaCoCo
|
|
40297
|
-
|
|
40321
|
+
path39__default.join(projectDir, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")
|
|
40298
40322
|
];
|
|
40299
40323
|
for (const location of coverageLocations) {
|
|
40300
40324
|
try {
|
|
@@ -40407,7 +40431,7 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
40407
40431
|
const results = [];
|
|
40408
40432
|
const startTime = Date.now();
|
|
40409
40433
|
const isTimedOut = () => Date.now() - startTime > opts.timeoutMs;
|
|
40410
|
-
const queue = [[
|
|
40434
|
+
const queue = [[path39__default.resolve(rootDir), 0]];
|
|
40411
40435
|
const visited = /* @__PURE__ */ new Set();
|
|
40412
40436
|
while (queue.length > 0 && results.length < opts.maxResults) {
|
|
40413
40437
|
if (isTimedOut()) break;
|
|
@@ -40420,7 +40444,7 @@ async function findFileRecursive(rootDir, target, options = {}) {
|
|
|
40420
40444
|
for (const entry of entries) {
|
|
40421
40445
|
if (isTimedOut()) break;
|
|
40422
40446
|
const entryName = entry.name;
|
|
40423
|
-
const entryPath =
|
|
40447
|
+
const entryPath = path39__default.join(currentDir, entryName);
|
|
40424
40448
|
if (!opts.includeHidden && entryName.startsWith(".")) continue;
|
|
40425
40449
|
if (entry.isDirectory() && opts.excludeDirs.has(entryName)) continue;
|
|
40426
40450
|
const isMatch = opts.type === "file" && entry.isFile() || opts.type === "directory" && entry.isDirectory() || opts.type === "both";
|
|
@@ -40454,19 +40478,19 @@ async function suggestSimilarFilesDeep(missingPath, rootDir = process.cwd(), opt
|
|
|
40454
40478
|
if (fastResults.length > 0) {
|
|
40455
40479
|
return fastResults;
|
|
40456
40480
|
}
|
|
40457
|
-
const absPath =
|
|
40458
|
-
const target =
|
|
40481
|
+
const absPath = path39__default.resolve(missingPath);
|
|
40482
|
+
const target = path39__default.basename(absPath);
|
|
40459
40483
|
return findFileRecursive(rootDir, target, options);
|
|
40460
40484
|
}
|
|
40461
40485
|
async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), options) {
|
|
40462
|
-
const absPath =
|
|
40463
|
-
const target =
|
|
40464
|
-
const parentDir =
|
|
40486
|
+
const absPath = path39__default.resolve(missingPath);
|
|
40487
|
+
const target = path39__default.basename(absPath);
|
|
40488
|
+
const parentDir = path39__default.dirname(absPath);
|
|
40465
40489
|
try {
|
|
40466
40490
|
const entries = await fs35__default.readdir(parentDir, { withFileTypes: true });
|
|
40467
40491
|
const dirs = entries.filter((e) => e.isDirectory());
|
|
40468
40492
|
const scored = dirs.map((d) => ({
|
|
40469
|
-
path:
|
|
40493
|
+
path: path39__default.join(parentDir, d.name),
|
|
40470
40494
|
distance: levenshtein(target.toLowerCase(), d.name.toLowerCase())
|
|
40471
40495
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance).slice(0, options?.maxResults ?? MAX_SUGGESTIONS);
|
|
40472
40496
|
if (scored.length > 0) {
|
|
@@ -40477,15 +40501,15 @@ async function suggestSimilarDirsDeep(missingPath, rootDir = process.cwd(), opti
|
|
|
40477
40501
|
return findFileRecursive(rootDir, target, { ...options, type: "directory" });
|
|
40478
40502
|
}
|
|
40479
40503
|
async function suggestSimilarFiles(missingPath, options) {
|
|
40480
|
-
const absPath =
|
|
40481
|
-
const dir =
|
|
40482
|
-
const target =
|
|
40504
|
+
const absPath = path39__default.resolve(missingPath);
|
|
40505
|
+
const dir = path39__default.dirname(absPath);
|
|
40506
|
+
const target = path39__default.basename(absPath);
|
|
40483
40507
|
const maxResults = options?.maxResults;
|
|
40484
40508
|
try {
|
|
40485
40509
|
const entries = await fs35__default.readdir(dir);
|
|
40486
40510
|
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
40487
40511
|
const scored = limited.map((name) => ({
|
|
40488
|
-
path:
|
|
40512
|
+
path: path39__default.join(dir, name),
|
|
40489
40513
|
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
40490
40514
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
40491
40515
|
return scored.slice(0, maxResults);
|
|
@@ -40497,7 +40521,7 @@ function formatSuggestions(suggestions, baseDir) {
|
|
|
40497
40521
|
if (suggestions.length === 0) return "";
|
|
40498
40522
|
const base = baseDir ?? process.cwd();
|
|
40499
40523
|
const lines = suggestions.map((s) => {
|
|
40500
|
-
const rel =
|
|
40524
|
+
const rel = path39__default.relative(base, s.path);
|
|
40501
40525
|
return ` - ${rel}`;
|
|
40502
40526
|
});
|
|
40503
40527
|
return `
|
|
@@ -40526,44 +40550,85 @@ var SENSITIVE_PATTERNS = [
|
|
|
40526
40550
|
// PyPI auth
|
|
40527
40551
|
];
|
|
40528
40552
|
var BLOCKED_PATHS2 = ["/etc", "/var", "/usr", "/root", "/sys", "/proc", "/boot"];
|
|
40553
|
+
var SAFE_COCO_HOME_READ_FILES = /* @__PURE__ */ new Set([
|
|
40554
|
+
"mcp.json",
|
|
40555
|
+
"config.json",
|
|
40556
|
+
"COCO.md",
|
|
40557
|
+
"AGENTS.md",
|
|
40558
|
+
"CLAUDE.md",
|
|
40559
|
+
"projects.json",
|
|
40560
|
+
"trusted-tools.json",
|
|
40561
|
+
"allowed-paths.json"
|
|
40562
|
+
]);
|
|
40563
|
+
var SAFE_COCO_HOME_READ_DIR_PREFIXES = ["skills", "memories", "logs", "checkpoints", "sessions"];
|
|
40529
40564
|
function hasNullByte2(str) {
|
|
40530
40565
|
return str.includes("\0");
|
|
40531
40566
|
}
|
|
40532
40567
|
function normalizePath2(filePath) {
|
|
40533
40568
|
let normalized = filePath.replace(/\0/g, "");
|
|
40534
|
-
normalized =
|
|
40569
|
+
normalized = path39__default.normalize(normalized);
|
|
40535
40570
|
return normalized;
|
|
40536
40571
|
}
|
|
40572
|
+
function isWithinDirectory(targetPath, baseDir) {
|
|
40573
|
+
const normalizedTarget = path39__default.normalize(targetPath);
|
|
40574
|
+
const normalizedBase = path39__default.normalize(baseDir);
|
|
40575
|
+
return normalizedTarget === normalizedBase || normalizedTarget.startsWith(normalizedBase + path39__default.sep);
|
|
40576
|
+
}
|
|
40577
|
+
function isSafeCocoHomeReadPath(absolutePath, homeDir) {
|
|
40578
|
+
const cocoHome = path39__default.join(homeDir, ".coco");
|
|
40579
|
+
if (!isWithinDirectory(absolutePath, cocoHome)) {
|
|
40580
|
+
return false;
|
|
40581
|
+
}
|
|
40582
|
+
const relativePath = path39__default.relative(cocoHome, absolutePath);
|
|
40583
|
+
if (!relativePath || relativePath.startsWith("..")) {
|
|
40584
|
+
return false;
|
|
40585
|
+
}
|
|
40586
|
+
const segments = relativePath.split(path39__default.sep).filter(Boolean);
|
|
40587
|
+
const firstSegment = segments[0];
|
|
40588
|
+
if (!firstSegment) {
|
|
40589
|
+
return false;
|
|
40590
|
+
}
|
|
40591
|
+
if (firstSegment === "tokens" || firstSegment === ".env") {
|
|
40592
|
+
return false;
|
|
40593
|
+
}
|
|
40594
|
+
if (segments.length === 1 && SAFE_COCO_HOME_READ_FILES.has(firstSegment)) {
|
|
40595
|
+
return true;
|
|
40596
|
+
}
|
|
40597
|
+
return SAFE_COCO_HOME_READ_DIR_PREFIXES.includes(firstSegment);
|
|
40598
|
+
}
|
|
40537
40599
|
function isPathAllowed(filePath, operation) {
|
|
40538
40600
|
if (hasNullByte2(filePath)) {
|
|
40539
40601
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
40540
40602
|
}
|
|
40541
40603
|
const normalized = normalizePath2(filePath);
|
|
40542
|
-
const absolute =
|
|
40604
|
+
const absolute = path39__default.resolve(normalized);
|
|
40543
40605
|
const cwd = process.cwd();
|
|
40544
40606
|
for (const blocked of BLOCKED_PATHS2) {
|
|
40545
|
-
const normalizedBlocked =
|
|
40546
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
40607
|
+
const normalizedBlocked = path39__default.normalize(blocked);
|
|
40608
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path39__default.sep)) {
|
|
40547
40609
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
40548
40610
|
}
|
|
40549
40611
|
}
|
|
40550
40612
|
const home = process.env.HOME;
|
|
40551
40613
|
if (home) {
|
|
40552
|
-
const normalizedHome =
|
|
40553
|
-
const normalizedCwd =
|
|
40614
|
+
const normalizedHome = path39__default.normalize(home);
|
|
40615
|
+
const normalizedCwd = path39__default.normalize(cwd);
|
|
40554
40616
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
40555
40617
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
40618
|
+
if (isSafeCocoHomeReadPath(absolute, normalizedHome)) {
|
|
40619
|
+
return { allowed: true };
|
|
40620
|
+
}
|
|
40556
40621
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
40557
|
-
const basename4 =
|
|
40622
|
+
const basename4 = path39__default.basename(absolute);
|
|
40558
40623
|
if (!allowedHomeReads.includes(basename4)) {
|
|
40559
|
-
const targetDir =
|
|
40624
|
+
const targetDir = path39__default.dirname(absolute);
|
|
40560
40625
|
return {
|
|
40561
40626
|
allowed: false,
|
|
40562
40627
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
40563
40628
|
};
|
|
40564
40629
|
}
|
|
40565
40630
|
} else {
|
|
40566
|
-
const targetDir =
|
|
40631
|
+
const targetDir = path39__default.dirname(absolute);
|
|
40567
40632
|
return {
|
|
40568
40633
|
allowed: false,
|
|
40569
40634
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -40572,7 +40637,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
40572
40637
|
}
|
|
40573
40638
|
}
|
|
40574
40639
|
if (operation === "write" || operation === "delete") {
|
|
40575
|
-
const basename4 =
|
|
40640
|
+
const basename4 = path39__default.basename(absolute);
|
|
40576
40641
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
40577
40642
|
if (pattern.test(basename4)) {
|
|
40578
40643
|
return {
|
|
@@ -40595,17 +40660,17 @@ function isENOENT(error) {
|
|
|
40595
40660
|
return error.code === "ENOENT";
|
|
40596
40661
|
}
|
|
40597
40662
|
async function enrichENOENT(filePath, operation) {
|
|
40598
|
-
const absPath =
|
|
40663
|
+
const absPath = path39__default.resolve(filePath);
|
|
40599
40664
|
const suggestions = await suggestSimilarFilesDeep(absPath, process.cwd());
|
|
40600
|
-
const hint = formatSuggestions(suggestions,
|
|
40665
|
+
const hint = formatSuggestions(suggestions, path39__default.dirname(absPath));
|
|
40601
40666
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
40602
40667
|
return `File not found: ${filePath}${hint}
|
|
40603
40668
|
${action}`;
|
|
40604
40669
|
}
|
|
40605
40670
|
async function enrichDirENOENT(dirPath) {
|
|
40606
|
-
const absPath =
|
|
40671
|
+
const absPath = path39__default.resolve(dirPath);
|
|
40607
40672
|
const suggestions = await suggestSimilarDirsDeep(absPath, process.cwd());
|
|
40608
|
-
const hint = formatSuggestions(suggestions,
|
|
40673
|
+
const hint = formatSuggestions(suggestions, path39__default.dirname(absPath));
|
|
40609
40674
|
return `Directory not found: ${dirPath}${hint}
|
|
40610
40675
|
Use list_dir or glob to find the correct path.`;
|
|
40611
40676
|
}
|
|
@@ -40626,7 +40691,7 @@ Examples:
|
|
|
40626
40691
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
40627
40692
|
validatePath(filePath, "read");
|
|
40628
40693
|
try {
|
|
40629
|
-
const absolutePath =
|
|
40694
|
+
const absolutePath = path39__default.resolve(filePath);
|
|
40630
40695
|
const stats = await fs35__default.stat(absolutePath);
|
|
40631
40696
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
40632
40697
|
let truncated = false;
|
|
@@ -40685,7 +40750,7 @@ Examples:
|
|
|
40685
40750
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
40686
40751
|
validatePath(filePath, "write");
|
|
40687
40752
|
try {
|
|
40688
|
-
const absolutePath =
|
|
40753
|
+
const absolutePath = path39__default.resolve(filePath);
|
|
40689
40754
|
let wouldCreate = false;
|
|
40690
40755
|
try {
|
|
40691
40756
|
await fs35__default.access(absolutePath);
|
|
@@ -40701,7 +40766,7 @@ Examples:
|
|
|
40701
40766
|
};
|
|
40702
40767
|
}
|
|
40703
40768
|
if (createDirs) {
|
|
40704
|
-
await fs35__default.mkdir(
|
|
40769
|
+
await fs35__default.mkdir(path39__default.dirname(absolutePath), { recursive: true });
|
|
40705
40770
|
}
|
|
40706
40771
|
await fs35__default.writeFile(absolutePath, content, "utf-8");
|
|
40707
40772
|
const stats = await fs35__default.stat(absolutePath);
|
|
@@ -40747,7 +40812,7 @@ Examples:
|
|
|
40747
40812
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
40748
40813
|
validatePath(filePath, "write");
|
|
40749
40814
|
try {
|
|
40750
|
-
const absolutePath =
|
|
40815
|
+
const absolutePath = path39__default.resolve(filePath);
|
|
40751
40816
|
let content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
40752
40817
|
let replacements = 0;
|
|
40753
40818
|
if (all) {
|
|
@@ -40868,7 +40933,7 @@ Examples:
|
|
|
40868
40933
|
}),
|
|
40869
40934
|
async execute({ path: filePath }) {
|
|
40870
40935
|
try {
|
|
40871
|
-
const absolutePath =
|
|
40936
|
+
const absolutePath = path39__default.resolve(filePath);
|
|
40872
40937
|
const stats = await fs35__default.stat(absolutePath);
|
|
40873
40938
|
return {
|
|
40874
40939
|
exists: true,
|
|
@@ -40899,12 +40964,12 @@ Examples:
|
|
|
40899
40964
|
}),
|
|
40900
40965
|
async execute({ path: dirPath, recursive }) {
|
|
40901
40966
|
try {
|
|
40902
|
-
const absolutePath =
|
|
40967
|
+
const absolutePath = path39__default.resolve(dirPath);
|
|
40903
40968
|
const entries = [];
|
|
40904
40969
|
async function listDir(dir, prefix = "") {
|
|
40905
40970
|
const items = await fs35__default.readdir(dir, { withFileTypes: true });
|
|
40906
40971
|
for (const item of items) {
|
|
40907
|
-
const fullPath =
|
|
40972
|
+
const fullPath = path39__default.join(dir, item.name);
|
|
40908
40973
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
40909
40974
|
if (item.isDirectory()) {
|
|
40910
40975
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -40959,7 +41024,7 @@ Examples:
|
|
|
40959
41024
|
}
|
|
40960
41025
|
validatePath(filePath, "delete");
|
|
40961
41026
|
try {
|
|
40962
|
-
const absolutePath =
|
|
41027
|
+
const absolutePath = path39__default.resolve(filePath);
|
|
40963
41028
|
const stats = await fs35__default.stat(absolutePath);
|
|
40964
41029
|
if (stats.isDirectory()) {
|
|
40965
41030
|
if (!recursive) {
|
|
@@ -40975,7 +41040,7 @@ Examples:
|
|
|
40975
41040
|
} catch (error) {
|
|
40976
41041
|
if (error instanceof ToolError) throw error;
|
|
40977
41042
|
if (error.code === "ENOENT") {
|
|
40978
|
-
return { deleted: false, path:
|
|
41043
|
+
return { deleted: false, path: path39__default.resolve(filePath) };
|
|
40979
41044
|
}
|
|
40980
41045
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
40981
41046
|
path: filePath,
|
|
@@ -41003,8 +41068,8 @@ Examples:
|
|
|
41003
41068
|
validatePath(source, "read");
|
|
41004
41069
|
validatePath(destination, "write");
|
|
41005
41070
|
try {
|
|
41006
|
-
const srcPath =
|
|
41007
|
-
const destPath =
|
|
41071
|
+
const srcPath = path39__default.resolve(source);
|
|
41072
|
+
const destPath = path39__default.resolve(destination);
|
|
41008
41073
|
if (!overwrite) {
|
|
41009
41074
|
try {
|
|
41010
41075
|
await fs35__default.access(destPath);
|
|
@@ -41020,7 +41085,7 @@ Examples:
|
|
|
41020
41085
|
}
|
|
41021
41086
|
}
|
|
41022
41087
|
}
|
|
41023
|
-
await fs35__default.mkdir(
|
|
41088
|
+
await fs35__default.mkdir(path39__default.dirname(destPath), { recursive: true });
|
|
41024
41089
|
await fs35__default.copyFile(srcPath, destPath);
|
|
41025
41090
|
const stats = await fs35__default.stat(destPath);
|
|
41026
41091
|
return {
|
|
@@ -41064,8 +41129,8 @@ Examples:
|
|
|
41064
41129
|
validatePath(source, "delete");
|
|
41065
41130
|
validatePath(destination, "write");
|
|
41066
41131
|
try {
|
|
41067
|
-
const srcPath =
|
|
41068
|
-
const destPath =
|
|
41132
|
+
const srcPath = path39__default.resolve(source);
|
|
41133
|
+
const destPath = path39__default.resolve(destination);
|
|
41069
41134
|
if (!overwrite) {
|
|
41070
41135
|
try {
|
|
41071
41136
|
await fs35__default.access(destPath);
|
|
@@ -41081,7 +41146,7 @@ Examples:
|
|
|
41081
41146
|
}
|
|
41082
41147
|
}
|
|
41083
41148
|
}
|
|
41084
|
-
await fs35__default.mkdir(
|
|
41149
|
+
await fs35__default.mkdir(path39__default.dirname(destPath), { recursive: true });
|
|
41085
41150
|
await fs35__default.rename(srcPath, destPath);
|
|
41086
41151
|
return {
|
|
41087
41152
|
source: srcPath,
|
|
@@ -41151,10 +41216,10 @@ Examples:
|
|
|
41151
41216
|
}),
|
|
41152
41217
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
41153
41218
|
try {
|
|
41154
|
-
const absolutePath =
|
|
41219
|
+
const absolutePath = path39__default.resolve(dirPath ?? ".");
|
|
41155
41220
|
let totalFiles = 0;
|
|
41156
41221
|
let totalDirs = 0;
|
|
41157
|
-
const lines = [
|
|
41222
|
+
const lines = [path39__default.basename(absolutePath) + "/"];
|
|
41158
41223
|
let truncated = false;
|
|
41159
41224
|
async function buildTree(dir, prefix, currentDepth) {
|
|
41160
41225
|
if (currentDepth > (depth ?? 4)) return;
|
|
@@ -41184,7 +41249,7 @@ Examples:
|
|
|
41184
41249
|
if (item.isDirectory()) {
|
|
41185
41250
|
totalDirs++;
|
|
41186
41251
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
41187
|
-
await buildTree(
|
|
41252
|
+
await buildTree(path39__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
41188
41253
|
} else {
|
|
41189
41254
|
totalFiles++;
|
|
41190
41255
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -42452,7 +42517,7 @@ Examples:
|
|
|
42452
42517
|
caseSensitive,
|
|
42453
42518
|
wholeWord
|
|
42454
42519
|
}) {
|
|
42455
|
-
const targetPath = searchPath ?
|
|
42520
|
+
const targetPath = searchPath ? path39__default.resolve(searchPath) : process.cwd();
|
|
42456
42521
|
const matches = [];
|
|
42457
42522
|
let filesSearched = 0;
|
|
42458
42523
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -42519,7 +42584,7 @@ Examples:
|
|
|
42519
42584
|
contextAfter.push(lines[j] ?? "");
|
|
42520
42585
|
}
|
|
42521
42586
|
matches.push({
|
|
42522
|
-
file:
|
|
42587
|
+
file: path39__default.relative(process.cwd(), file),
|
|
42523
42588
|
line: i + 1,
|
|
42524
42589
|
column: match.index + 1,
|
|
42525
42590
|
content: line,
|
|
@@ -42570,7 +42635,7 @@ Examples:
|
|
|
42570
42635
|
}),
|
|
42571
42636
|
async execute({ file, pattern, caseSensitive }) {
|
|
42572
42637
|
try {
|
|
42573
|
-
const absolutePath =
|
|
42638
|
+
const absolutePath = path39__default.resolve(file);
|
|
42574
42639
|
const content = await fs35__default.readFile(absolutePath, "utf-8");
|
|
42575
42640
|
const lines = content.split("\n");
|
|
42576
42641
|
const matches = [];
|
|
@@ -42589,7 +42654,7 @@ Examples:
|
|
|
42589
42654
|
} catch (error) {
|
|
42590
42655
|
if (error.code === "ENOENT") {
|
|
42591
42656
|
const suggestions = await suggestSimilarFilesDeep(file, process.cwd());
|
|
42592
|
-
const hint = formatSuggestions(suggestions,
|
|
42657
|
+
const hint = formatSuggestions(suggestions, path39__default.dirname(file));
|
|
42593
42658
|
throw new ToolError(`File not found: ${file}${hint}
|
|
42594
42659
|
Use glob to find the correct path.`, {
|
|
42595
42660
|
tool: "find_in_file"
|
|
@@ -42780,7 +42845,7 @@ async function detectPackageManager2(cwd) {
|
|
|
42780
42845
|
];
|
|
42781
42846
|
for (const { file, pm } of lockfiles) {
|
|
42782
42847
|
try {
|
|
42783
|
-
await fs35__default.access(
|
|
42848
|
+
await fs35__default.access(path39__default.join(cwd, file));
|
|
42784
42849
|
return pm;
|
|
42785
42850
|
} catch {
|
|
42786
42851
|
}
|
|
@@ -43053,7 +43118,7 @@ ${message}
|
|
|
43053
43118
|
});
|
|
43054
43119
|
try {
|
|
43055
43120
|
try {
|
|
43056
|
-
await fs35__default.access(
|
|
43121
|
+
await fs35__default.access(path39__default.join(projectDir, "Makefile"));
|
|
43057
43122
|
} catch {
|
|
43058
43123
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
43059
43124
|
}
|
|
@@ -43223,7 +43288,7 @@ ${message}
|
|
|
43223
43288
|
});
|
|
43224
43289
|
async function resolveMaven(cwd) {
|
|
43225
43290
|
try {
|
|
43226
|
-
await fs35__default.access(
|
|
43291
|
+
await fs35__default.access(path39__default.join(cwd, "mvnw"));
|
|
43227
43292
|
return "./mvnw";
|
|
43228
43293
|
} catch {
|
|
43229
43294
|
return "mvn";
|
|
@@ -43231,7 +43296,7 @@ async function resolveMaven(cwd) {
|
|
|
43231
43296
|
}
|
|
43232
43297
|
async function resolveGradle(cwd) {
|
|
43233
43298
|
try {
|
|
43234
|
-
await fs35__default.access(
|
|
43299
|
+
await fs35__default.access(path39__default.join(cwd, "gradlew"));
|
|
43235
43300
|
return "./gradlew";
|
|
43236
43301
|
} catch {
|
|
43237
43302
|
return "gradle";
|
|
@@ -44099,7 +44164,7 @@ init_review();
|
|
|
44099
44164
|
init_registry4();
|
|
44100
44165
|
init_errors();
|
|
44101
44166
|
var fs38 = await import('fs/promises');
|
|
44102
|
-
var
|
|
44167
|
+
var path42 = await import('path');
|
|
44103
44168
|
var { glob: glob14 } = await import('glob');
|
|
44104
44169
|
var DEFAULT_MAX_FILES = 200;
|
|
44105
44170
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -44125,7 +44190,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
44125
44190
|
"**/*.d.ts"
|
|
44126
44191
|
];
|
|
44127
44192
|
function detectLanguage3(filePath) {
|
|
44128
|
-
const ext =
|
|
44193
|
+
const ext = path42.extname(filePath).toLowerCase();
|
|
44129
44194
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
44130
44195
|
if (extensions.includes(ext)) return lang;
|
|
44131
44196
|
}
|
|
@@ -44534,7 +44599,7 @@ Examples:
|
|
|
44534
44599
|
}),
|
|
44535
44600
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
44536
44601
|
const startTime = performance.now();
|
|
44537
|
-
const absPath =
|
|
44602
|
+
const absPath = path42.resolve(rootPath);
|
|
44538
44603
|
try {
|
|
44539
44604
|
const stat2 = await fs38.stat(absPath);
|
|
44540
44605
|
if (!stat2.isDirectory()) {
|
|
@@ -44573,7 +44638,7 @@ Examples:
|
|
|
44573
44638
|
let totalDefinitions = 0;
|
|
44574
44639
|
let exportedSymbols = 0;
|
|
44575
44640
|
for (const file of limitedFiles) {
|
|
44576
|
-
const fullPath =
|
|
44641
|
+
const fullPath = path42.join(absPath, file);
|
|
44577
44642
|
const language = detectLanguage3(file);
|
|
44578
44643
|
if (!language) continue;
|
|
44579
44644
|
if (languages && !languages.includes(language)) {
|
|
@@ -44618,9 +44683,9 @@ init_registry4();
|
|
|
44618
44683
|
init_errors();
|
|
44619
44684
|
init_paths();
|
|
44620
44685
|
var fs39 = await import('fs/promises');
|
|
44621
|
-
var
|
|
44686
|
+
var path43 = await import('path');
|
|
44622
44687
|
var crypto2 = await import('crypto');
|
|
44623
|
-
var GLOBAL_MEMORIES_DIR =
|
|
44688
|
+
var GLOBAL_MEMORIES_DIR = path43.join(COCO_HOME, "memories");
|
|
44624
44689
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
44625
44690
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
44626
44691
|
async function ensureDir2(dirPath) {
|
|
@@ -44631,7 +44696,7 @@ function getMemoriesDir(scope) {
|
|
|
44631
44696
|
}
|
|
44632
44697
|
async function loadIndex(scope) {
|
|
44633
44698
|
const dir = getMemoriesDir(scope);
|
|
44634
|
-
const indexPath =
|
|
44699
|
+
const indexPath = path43.join(dir, "index.json");
|
|
44635
44700
|
try {
|
|
44636
44701
|
const content = await fs39.readFile(indexPath, "utf-8");
|
|
44637
44702
|
return JSON.parse(content);
|
|
@@ -44642,12 +44707,12 @@ async function loadIndex(scope) {
|
|
|
44642
44707
|
async function saveIndex(scope, index) {
|
|
44643
44708
|
const dir = getMemoriesDir(scope);
|
|
44644
44709
|
await ensureDir2(dir);
|
|
44645
|
-
const indexPath =
|
|
44710
|
+
const indexPath = path43.join(dir, "index.json");
|
|
44646
44711
|
await fs39.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
44647
44712
|
}
|
|
44648
44713
|
async function loadMemory(scope, id) {
|
|
44649
44714
|
const dir = getMemoriesDir(scope);
|
|
44650
|
-
const memPath =
|
|
44715
|
+
const memPath = path43.join(dir, `${id}.json`);
|
|
44651
44716
|
try {
|
|
44652
44717
|
const content = await fs39.readFile(memPath, "utf-8");
|
|
44653
44718
|
return JSON.parse(content);
|
|
@@ -44658,7 +44723,7 @@ async function loadMemory(scope, id) {
|
|
|
44658
44723
|
async function saveMemory(scope, memory) {
|
|
44659
44724
|
const dir = getMemoriesDir(scope);
|
|
44660
44725
|
await ensureDir2(dir);
|
|
44661
|
-
const memPath =
|
|
44726
|
+
const memPath = path43.join(dir, `${memory.id}.json`);
|
|
44662
44727
|
await fs39.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
44663
44728
|
}
|
|
44664
44729
|
var createMemoryTool = defineTool({
|
|
@@ -44999,7 +45064,7 @@ var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpoi
|
|
|
44999
45064
|
// src/tools/semantic-search.ts
|
|
45000
45065
|
init_registry4();
|
|
45001
45066
|
var fs41 = await import('fs/promises');
|
|
45002
|
-
var
|
|
45067
|
+
var path44 = await import('path');
|
|
45003
45068
|
var { glob: glob15 } = await import('glob');
|
|
45004
45069
|
var INDEX_DIR = ".coco/search-index";
|
|
45005
45070
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -45127,7 +45192,7 @@ async function getEmbedding(text13) {
|
|
|
45127
45192
|
}
|
|
45128
45193
|
async function loadIndex2(indexDir) {
|
|
45129
45194
|
try {
|
|
45130
|
-
const indexPath =
|
|
45195
|
+
const indexPath = path44.join(indexDir, "index.json");
|
|
45131
45196
|
const content = await fs41.readFile(indexPath, "utf-8");
|
|
45132
45197
|
return JSON.parse(content);
|
|
45133
45198
|
} catch {
|
|
@@ -45136,11 +45201,11 @@ async function loadIndex2(indexDir) {
|
|
|
45136
45201
|
}
|
|
45137
45202
|
async function saveIndex2(indexDir, index) {
|
|
45138
45203
|
await fs41.mkdir(indexDir, { recursive: true });
|
|
45139
|
-
const indexPath =
|
|
45204
|
+
const indexPath = path44.join(indexDir, "index.json");
|
|
45140
45205
|
await fs41.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
45141
45206
|
}
|
|
45142
45207
|
function isBinary(filePath) {
|
|
45143
|
-
return BINARY_EXTENSIONS.has(
|
|
45208
|
+
return BINARY_EXTENSIONS.has(path44.extname(filePath).toLowerCase());
|
|
45144
45209
|
}
|
|
45145
45210
|
var semanticSearchTool = defineTool({
|
|
45146
45211
|
name: "semantic_search",
|
|
@@ -45165,8 +45230,8 @@ Examples:
|
|
|
45165
45230
|
const effectivePath = rootPath ?? ".";
|
|
45166
45231
|
const effectiveMaxResults = maxResults ?? 10;
|
|
45167
45232
|
const effectiveThreshold = threshold ?? 0.3;
|
|
45168
|
-
const absPath =
|
|
45169
|
-
const indexDir =
|
|
45233
|
+
const absPath = path44.resolve(effectivePath);
|
|
45234
|
+
const indexDir = path44.join(absPath, INDEX_DIR);
|
|
45170
45235
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
45171
45236
|
let warnings = [];
|
|
45172
45237
|
if (!index) {
|
|
@@ -45182,7 +45247,7 @@ Examples:
|
|
|
45182
45247
|
let indexSaveWarning = "";
|
|
45183
45248
|
for (const file of files) {
|
|
45184
45249
|
if (isBinary(file)) continue;
|
|
45185
|
-
const fullPath =
|
|
45250
|
+
const fullPath = path44.join(absPath, file);
|
|
45186
45251
|
try {
|
|
45187
45252
|
const stat2 = await fs41.stat(fullPath);
|
|
45188
45253
|
const content = await fs41.readFile(fullPath, "utf-8");
|
|
@@ -45266,7 +45331,7 @@ var semanticSearchTools = [semanticSearchTool];
|
|
|
45266
45331
|
init_registry4();
|
|
45267
45332
|
init_errors();
|
|
45268
45333
|
var fs42 = await import('fs/promises');
|
|
45269
|
-
var
|
|
45334
|
+
var path45 = await import('path');
|
|
45270
45335
|
var { glob: glob16 } = await import('glob');
|
|
45271
45336
|
async function parseClassRelationships(rootPath, include) {
|
|
45272
45337
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -45279,7 +45344,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
45279
45344
|
const interfaces = [];
|
|
45280
45345
|
for (const file of files.slice(0, 100)) {
|
|
45281
45346
|
try {
|
|
45282
|
-
const content = await fs42.readFile(
|
|
45347
|
+
const content = await fs42.readFile(path45.join(rootPath, file), "utf-8");
|
|
45283
45348
|
const lines = content.split("\n");
|
|
45284
45349
|
for (let i = 0; i < lines.length; i++) {
|
|
45285
45350
|
const line = lines[i];
|
|
@@ -45405,7 +45470,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
45405
45470
|
const lines = ["graph TD"];
|
|
45406
45471
|
let nodeCount = 0;
|
|
45407
45472
|
let edgeCount = 0;
|
|
45408
|
-
const rootName =
|
|
45473
|
+
const rootName = path45.basename(rootPath);
|
|
45409
45474
|
lines.push(` ROOT["${rootName}"]`);
|
|
45410
45475
|
nodeCount++;
|
|
45411
45476
|
for (const dir of dirs) {
|
|
@@ -45415,7 +45480,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
45415
45480
|
nodeCount++;
|
|
45416
45481
|
edgeCount++;
|
|
45417
45482
|
try {
|
|
45418
|
-
const subEntries = await fs42.readdir(
|
|
45483
|
+
const subEntries = await fs42.readdir(path45.join(rootPath, dir.name), {
|
|
45419
45484
|
withFileTypes: true
|
|
45420
45485
|
});
|
|
45421
45486
|
const subDirs = subEntries.filter(
|
|
@@ -45538,7 +45603,7 @@ Examples:
|
|
|
45538
45603
|
tool: "generate_diagram"
|
|
45539
45604
|
});
|
|
45540
45605
|
}
|
|
45541
|
-
const absPath = rootPath ?
|
|
45606
|
+
const absPath = rootPath ? path45.resolve(rootPath) : process.cwd();
|
|
45542
45607
|
switch (type) {
|
|
45543
45608
|
case "class":
|
|
45544
45609
|
return generateClassDiagram(absPath, include);
|
|
@@ -45604,7 +45669,7 @@ var diagramTools = [generateDiagramTool];
|
|
|
45604
45669
|
init_registry4();
|
|
45605
45670
|
init_errors();
|
|
45606
45671
|
var fs43 = await import('fs/promises');
|
|
45607
|
-
var
|
|
45672
|
+
var path46 = await import('path');
|
|
45608
45673
|
var DEFAULT_MAX_PAGES = 20;
|
|
45609
45674
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
45610
45675
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -45639,7 +45704,7 @@ Examples:
|
|
|
45639
45704
|
}),
|
|
45640
45705
|
async execute({ path: filePath, pages, maxPages }) {
|
|
45641
45706
|
const startTime = performance.now();
|
|
45642
|
-
const absPath =
|
|
45707
|
+
const absPath = path46.resolve(filePath);
|
|
45643
45708
|
try {
|
|
45644
45709
|
const stat2 = await fs43.stat(absPath);
|
|
45645
45710
|
if (!stat2.isFile()) {
|
|
@@ -45724,7 +45789,7 @@ var pdfTools = [readPdfTool];
|
|
|
45724
45789
|
init_registry4();
|
|
45725
45790
|
init_errors();
|
|
45726
45791
|
var fs44 = await import('fs/promises');
|
|
45727
|
-
var
|
|
45792
|
+
var path47 = await import('path');
|
|
45728
45793
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
45729
45794
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
45730
45795
|
var MIME_TYPES = {
|
|
@@ -45752,15 +45817,15 @@ Examples:
|
|
|
45752
45817
|
async execute({ path: filePath, prompt, provider }) {
|
|
45753
45818
|
const startTime = performance.now();
|
|
45754
45819
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
45755
|
-
const absPath =
|
|
45820
|
+
const absPath = path47.resolve(filePath);
|
|
45756
45821
|
const cwd = process.cwd();
|
|
45757
|
-
if (!absPath.startsWith(cwd +
|
|
45822
|
+
if (!absPath.startsWith(cwd + path47.sep) && absPath !== cwd) {
|
|
45758
45823
|
throw new ToolError(
|
|
45759
45824
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
45760
45825
|
{ tool: "read_image" }
|
|
45761
45826
|
);
|
|
45762
45827
|
}
|
|
45763
|
-
const ext =
|
|
45828
|
+
const ext = path47.extname(absPath).toLowerCase();
|
|
45764
45829
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
45765
45830
|
throw new ToolError(
|
|
45766
45831
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -45911,7 +45976,7 @@ var imageTools = [readImageTool];
|
|
|
45911
45976
|
// src/tools/database.ts
|
|
45912
45977
|
init_registry4();
|
|
45913
45978
|
init_errors();
|
|
45914
|
-
var
|
|
45979
|
+
var path48 = await import('path');
|
|
45915
45980
|
var DANGEROUS_PATTERNS = [
|
|
45916
45981
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
45917
45982
|
/\bTRUNCATE\b/i,
|
|
@@ -45942,7 +46007,7 @@ Examples:
|
|
|
45942
46007
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
45943
46008
|
const isReadonly = isReadonlyParam ?? true;
|
|
45944
46009
|
const startTime = performance.now();
|
|
45945
|
-
const absPath =
|
|
46010
|
+
const absPath = path48.resolve(database);
|
|
45946
46011
|
if (isReadonly && isDangerousSql(query)) {
|
|
45947
46012
|
throw new ToolError(
|
|
45948
46013
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -46025,7 +46090,7 @@ Examples:
|
|
|
46025
46090
|
}),
|
|
46026
46091
|
async execute({ database, table }) {
|
|
46027
46092
|
const startTime = performance.now();
|
|
46028
|
-
const absPath =
|
|
46093
|
+
const absPath = path48.resolve(database);
|
|
46029
46094
|
try {
|
|
46030
46095
|
const { default: Database } = await import('better-sqlite3');
|
|
46031
46096
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -46209,7 +46274,7 @@ var astValidatorTools = [validateCodeTool, findMissingImportsTool];
|
|
|
46209
46274
|
// src/tools/code-analyzer.ts
|
|
46210
46275
|
init_registry4();
|
|
46211
46276
|
var fs45 = await import('fs/promises');
|
|
46212
|
-
var
|
|
46277
|
+
var path49 = await import('path');
|
|
46213
46278
|
var AnalyzeFileSchema = z.object({
|
|
46214
46279
|
filePath: z.string().describe("Path to file to analyze"),
|
|
46215
46280
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
@@ -46319,10 +46384,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
46319
46384
|
try {
|
|
46320
46385
|
const analysis = await analyzeFile(file, false);
|
|
46321
46386
|
totalLines += analysis.lines;
|
|
46322
|
-
const ext =
|
|
46387
|
+
const ext = path49.extname(file);
|
|
46323
46388
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
46324
46389
|
fileStats.push({
|
|
46325
|
-
file:
|
|
46390
|
+
file: path49.relative(dirPath, file),
|
|
46326
46391
|
lines: analysis.lines,
|
|
46327
46392
|
complexity: analysis.complexity.cyclomatic
|
|
46328
46393
|
});
|
|
@@ -46886,7 +46951,7 @@ var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
|
46886
46951
|
// src/tools/context-enhancer.ts
|
|
46887
46952
|
init_registry4();
|
|
46888
46953
|
var fs47 = await import('fs/promises');
|
|
46889
|
-
var
|
|
46954
|
+
var path50 = await import('path');
|
|
46890
46955
|
var ContextMemoryStore = class {
|
|
46891
46956
|
items = /* @__PURE__ */ new Map();
|
|
46892
46957
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -46906,7 +46971,7 @@ var ContextMemoryStore = class {
|
|
|
46906
46971
|
}
|
|
46907
46972
|
}
|
|
46908
46973
|
async save() {
|
|
46909
|
-
const dir =
|
|
46974
|
+
const dir = path50.dirname(this.storePath);
|
|
46910
46975
|
await fs47.mkdir(dir, { recursive: true });
|
|
46911
46976
|
const data = {
|
|
46912
46977
|
sessionId: this.sessionId,
|
|
@@ -47083,7 +47148,7 @@ var contextEnhancerTools = [
|
|
|
47083
47148
|
// src/tools/skill-enhancer.ts
|
|
47084
47149
|
init_registry4();
|
|
47085
47150
|
var fs48 = await import('fs/promises');
|
|
47086
|
-
var
|
|
47151
|
+
var path51 = await import('path');
|
|
47087
47152
|
async function discoverSkills(skillsDir) {
|
|
47088
47153
|
try {
|
|
47089
47154
|
const files = await fs48.readdir(skillsDir);
|
|
@@ -47099,7 +47164,7 @@ async function loadSkillMetadata(skillPath) {
|
|
|
47099
47164
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
47100
47165
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
47101
47166
|
return {
|
|
47102
|
-
name: nameMatch?.[1] ||
|
|
47167
|
+
name: nameMatch?.[1] || path51.basename(skillPath, path51.extname(skillPath)),
|
|
47103
47168
|
description: descMatch?.[1] || "No description",
|
|
47104
47169
|
version: versionMatch?.[1] || "1.0.0",
|
|
47105
47170
|
dependencies: []
|
|
@@ -47143,7 +47208,7 @@ var discoverSkillsTool = defineTool({
|
|
|
47143
47208
|
const { skillsDir } = input;
|
|
47144
47209
|
const skills = await discoverSkills(skillsDir);
|
|
47145
47210
|
const metadata = await Promise.all(
|
|
47146
|
-
skills.map((s) => loadSkillMetadata(
|
|
47211
|
+
skills.map((s) => loadSkillMetadata(path51.join(skillsDir, s)))
|
|
47147
47212
|
);
|
|
47148
47213
|
return {
|
|
47149
47214
|
skillsDir,
|
|
@@ -47271,6 +47336,66 @@ var skillEnhancerTools = [discoverSkillsTool, validateSkillTool, createCustomToo
|
|
|
47271
47336
|
init_git_enhanced();
|
|
47272
47337
|
init_github();
|
|
47273
47338
|
init_open();
|
|
47339
|
+
|
|
47340
|
+
// src/tools/mcp.ts
|
|
47341
|
+
init_registry4();
|
|
47342
|
+
init_registry();
|
|
47343
|
+
init_config_loader();
|
|
47344
|
+
init_lifecycle();
|
|
47345
|
+
var mcpListServersTool = defineTool({
|
|
47346
|
+
name: "mcp_list_servers",
|
|
47347
|
+
description: `Inspect Coco's MCP configuration and current runtime connections.
|
|
47348
|
+
|
|
47349
|
+
Use this instead of bash_exec with "coco mcp ..." and instead of manually reading ~/.coco/mcp.json
|
|
47350
|
+
when you need to know which MCP servers are configured, connected, healthy, or which tools they expose.`,
|
|
47351
|
+
category: "config",
|
|
47352
|
+
parameters: z.object({
|
|
47353
|
+
includeDisabled: z.boolean().optional().default(false).describe("Include disabled MCP servers in the result"),
|
|
47354
|
+
includeTools: z.boolean().optional().default(false).describe("Include the list of exposed tool names for connected servers"),
|
|
47355
|
+
projectPath: z.string().optional().describe("Project path whose .mcp.json should be merged. Defaults to process.cwd()")
|
|
47356
|
+
}),
|
|
47357
|
+
async execute({ includeDisabled, includeTools, projectPath }) {
|
|
47358
|
+
const registry = new MCPRegistryImpl();
|
|
47359
|
+
await registry.load();
|
|
47360
|
+
const resolvedProjectPath = projectPath || process.cwd();
|
|
47361
|
+
const configuredServers = mergeMCPConfigs(
|
|
47362
|
+
registry.listServers(),
|
|
47363
|
+
await loadMCPServersFromCOCOConfig(),
|
|
47364
|
+
await loadProjectMCPFile(resolvedProjectPath)
|
|
47365
|
+
).filter((server) => includeDisabled || server.enabled !== false);
|
|
47366
|
+
const manager = getMCPServerManager();
|
|
47367
|
+
const servers = [];
|
|
47368
|
+
for (const server of configuredServers) {
|
|
47369
|
+
const connection = manager.getConnection(server.name);
|
|
47370
|
+
let tools;
|
|
47371
|
+
if (includeTools && connection) {
|
|
47372
|
+
try {
|
|
47373
|
+
const listed = await connection.client.listTools();
|
|
47374
|
+
tools = listed.tools.map((tool) => tool.name);
|
|
47375
|
+
} catch {
|
|
47376
|
+
tools = [];
|
|
47377
|
+
}
|
|
47378
|
+
}
|
|
47379
|
+
servers.push({
|
|
47380
|
+
name: server.name,
|
|
47381
|
+
transport: server.transport,
|
|
47382
|
+
enabled: server.enabled !== false,
|
|
47383
|
+
connected: connection !== void 0,
|
|
47384
|
+
healthy: connection?.healthy ?? false,
|
|
47385
|
+
toolCount: connection?.toolCount ?? 0,
|
|
47386
|
+
...includeTools ? { tools: tools ?? [] } : {}
|
|
47387
|
+
});
|
|
47388
|
+
}
|
|
47389
|
+
return {
|
|
47390
|
+
configuredCount: servers.length,
|
|
47391
|
+
connectedCount: servers.filter((server) => server.connected).length,
|
|
47392
|
+
servers
|
|
47393
|
+
};
|
|
47394
|
+
}
|
|
47395
|
+
});
|
|
47396
|
+
var mcpTools = [mcpListServersTool];
|
|
47397
|
+
|
|
47398
|
+
// src/tools/index.ts
|
|
47274
47399
|
init_registry4();
|
|
47275
47400
|
init_bash();
|
|
47276
47401
|
init_git();
|
|
@@ -47314,7 +47439,7 @@ Examples:
|
|
|
47314
47439
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
47315
47440
|
}),
|
|
47316
47441
|
async execute({ path: dirPath, reason }) {
|
|
47317
|
-
const absolute =
|
|
47442
|
+
const absolute = path39__default.resolve(dirPath);
|
|
47318
47443
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
47319
47444
|
return {
|
|
47320
47445
|
authorized: true,
|
|
@@ -47323,8 +47448,8 @@ Examples:
|
|
|
47323
47448
|
};
|
|
47324
47449
|
}
|
|
47325
47450
|
for (const blocked of BLOCKED_SYSTEM_PATHS2) {
|
|
47326
|
-
const normalizedBlocked =
|
|
47327
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
47451
|
+
const normalizedBlocked = path39__default.normalize(blocked);
|
|
47452
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path39__default.sep)) {
|
|
47328
47453
|
return {
|
|
47329
47454
|
authorized: false,
|
|
47330
47455
|
path: absolute,
|
|
@@ -47333,7 +47458,7 @@ Examples:
|
|
|
47333
47458
|
}
|
|
47334
47459
|
}
|
|
47335
47460
|
const cwd = process.cwd();
|
|
47336
|
-
if (absolute ===
|
|
47461
|
+
if (absolute === path39__default.normalize(cwd) || absolute.startsWith(path39__default.normalize(cwd) + path39__default.sep)) {
|
|
47337
47462
|
return {
|
|
47338
47463
|
authorized: true,
|
|
47339
47464
|
path: absolute,
|
|
@@ -47357,7 +47482,7 @@ Examples:
|
|
|
47357
47482
|
};
|
|
47358
47483
|
}
|
|
47359
47484
|
const existing = getAllowedPaths();
|
|
47360
|
-
if (existing.some((e) =>
|
|
47485
|
+
if (existing.some((e) => path39__default.normalize(e.path) === path39__default.normalize(absolute))) {
|
|
47361
47486
|
return {
|
|
47362
47487
|
authorized: true,
|
|
47363
47488
|
path: absolute,
|
|
@@ -47416,6 +47541,7 @@ function registerAllTools(registry) {
|
|
|
47416
47541
|
...gitEnhancedTools,
|
|
47417
47542
|
...githubTools,
|
|
47418
47543
|
...openTools,
|
|
47544
|
+
...mcpTools,
|
|
47419
47545
|
...authorizePathTools
|
|
47420
47546
|
];
|
|
47421
47547
|
for (const tool of allTools) {
|
|
@@ -47443,7 +47569,7 @@ async function runSprints(options) {
|
|
|
47443
47569
|
);
|
|
47444
47570
|
const coordinator = createAgentCoordinator(executor, agentDefsMap);
|
|
47445
47571
|
await fs35__default.mkdir(spec.outputPath, { recursive: true });
|
|
47446
|
-
const sprintsDir =
|
|
47572
|
+
const sprintsDir = path39__default.join(spec.outputPath, ".coco", "sprints");
|
|
47447
47573
|
await fs35__default.mkdir(sprintsDir, { recursive: true });
|
|
47448
47574
|
for (const sprint of spec.sprints) {
|
|
47449
47575
|
onProgress(`Starting ${sprint.id}: ${sprint.name}`);
|
|
@@ -47697,7 +47823,7 @@ Assess: overall architecture, consistency, error handling, and production readin
|
|
|
47697
47823
|
};
|
|
47698
47824
|
}
|
|
47699
47825
|
async function saveSprintResult(sprintsDir, result) {
|
|
47700
|
-
const filePath =
|
|
47826
|
+
const filePath = path39__default.join(sprintsDir, `${result.sprintId}.json`);
|
|
47701
47827
|
await fs35__default.writeFile(filePath, JSON.stringify(result, null, 2), "utf-8");
|
|
47702
47828
|
}
|
|
47703
47829
|
|
|
@@ -47723,9 +47849,9 @@ function parseArgs6(args) {
|
|
|
47723
47849
|
return { description, specFile, outputDir, skipConfirmation };
|
|
47724
47850
|
}
|
|
47725
47851
|
function isWithinRoot(resolvedPath, rootDir) {
|
|
47726
|
-
const normalRoot =
|
|
47727
|
-
const normalPath =
|
|
47728
|
-
return normalPath ===
|
|
47852
|
+
const normalRoot = path39__default.normalize(rootDir) + path39__default.sep;
|
|
47853
|
+
const normalPath = path39__default.normalize(resolvedPath);
|
|
47854
|
+
return normalPath === path39__default.normalize(rootDir) || normalPath.startsWith(normalRoot);
|
|
47729
47855
|
}
|
|
47730
47856
|
var buildAppCommand = {
|
|
47731
47857
|
name: "build-app",
|
|
@@ -47748,7 +47874,7 @@ var buildAppCommand = {
|
|
|
47748
47874
|
}
|
|
47749
47875
|
let initialDescription = parsed.description;
|
|
47750
47876
|
if (parsed.specFile) {
|
|
47751
|
-
const specPath =
|
|
47877
|
+
const specPath = path39__default.resolve(session.projectPath, parsed.specFile);
|
|
47752
47878
|
if (!isWithinRoot(specPath, session.projectPath)) {
|
|
47753
47879
|
p26.log.error(`--spec path must be within the project directory: ${specPath}`);
|
|
47754
47880
|
return false;
|
|
@@ -47761,7 +47887,7 @@ var buildAppCommand = {
|
|
|
47761
47887
|
return false;
|
|
47762
47888
|
}
|
|
47763
47889
|
}
|
|
47764
|
-
const outputPath = parsed.outputDir ?
|
|
47890
|
+
const outputPath = parsed.outputDir ? path39__default.resolve(session.projectPath, parsed.outputDir) : path39__default.join(session.projectPath, "build-app-output");
|
|
47765
47891
|
if (parsed.outputDir && !isWithinRoot(outputPath, session.projectPath)) {
|
|
47766
47892
|
p26.log.error(`--output path must be within the project directory: ${outputPath}`);
|
|
47767
47893
|
return false;
|
|
@@ -47945,7 +48071,7 @@ var WorktreeManager = class {
|
|
|
47945
48071
|
const id = randomUUID();
|
|
47946
48072
|
const branchPrefix = options.branchPrefix ?? "coco-agent";
|
|
47947
48073
|
const branchName = `${branchPrefix}/${name}-${id.slice(0, 8)}`;
|
|
47948
|
-
const worktreePath =
|
|
48074
|
+
const worktreePath = path39__default.join(this.projectRoot, WORKTREES_DIR, `${name}-${id.slice(0, 8)}`);
|
|
47949
48075
|
const worktree = {
|
|
47950
48076
|
id,
|
|
47951
48077
|
name,
|
|
@@ -47956,7 +48082,7 @@ var WorktreeManager = class {
|
|
|
47956
48082
|
};
|
|
47957
48083
|
this.worktrees.set(id, worktree);
|
|
47958
48084
|
try {
|
|
47959
|
-
await fs35__default.mkdir(
|
|
48085
|
+
await fs35__default.mkdir(path39__default.join(this.projectRoot, WORKTREES_DIR), { recursive: true });
|
|
47960
48086
|
const baseBranch = options.baseBranch ?? "HEAD";
|
|
47961
48087
|
await this.git(["worktree", "add", "-b", branchName, worktreePath, baseBranch]);
|
|
47962
48088
|
worktree.status = "active";
|
|
@@ -49555,7 +49681,7 @@ function getAllCommands() {
|
|
|
49555
49681
|
}
|
|
49556
49682
|
|
|
49557
49683
|
// src/cli/repl/input/handler.ts
|
|
49558
|
-
var HISTORY_FILE =
|
|
49684
|
+
var HISTORY_FILE = path39.join(os4.homedir(), ".coco", "history");
|
|
49559
49685
|
async function handleOptionC(copyFn = copyToClipboard, getLastBlockFn = getLastBlock) {
|
|
49560
49686
|
const block = getLastBlockFn();
|
|
49561
49687
|
if (!block) return null;
|
|
@@ -49576,7 +49702,7 @@ function loadHistory() {
|
|
|
49576
49702
|
}
|
|
49577
49703
|
function saveHistory(history) {
|
|
49578
49704
|
try {
|
|
49579
|
-
const dir =
|
|
49705
|
+
const dir = path39.dirname(HISTORY_FILE);
|
|
49580
49706
|
if (!fs5.existsSync(dir)) {
|
|
49581
49707
|
fs5.mkdirSync(dir, { recursive: true });
|
|
49582
49708
|
}
|
|
@@ -51596,6 +51722,28 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
51596
51722
|
};
|
|
51597
51723
|
const allTools = toolRegistry.getToolDefinitionsForLLM();
|
|
51598
51724
|
const tools = session.planMode ? filterReadOnlyTools(allTools) : allTools;
|
|
51725
|
+
const availableMcpToolNames = allTools.map((t) => t.name).filter((name) => name.startsWith("mcp_"));
|
|
51726
|
+
function extractPlainText(content) {
|
|
51727
|
+
if (typeof content === "string") return content;
|
|
51728
|
+
return content.filter((block) => block.type === "text").map((block) => block.text).join(" ");
|
|
51729
|
+
}
|
|
51730
|
+
const normalizedUserRequest = extractPlainText(userMessage).toLowerCase();
|
|
51731
|
+
const userExplicitlyRequestedMcp = /\bmcp\b/.test(normalizedUserRequest) || /\b(use|using|usa|usar|utiliza|utilizar)\b.{0,24}\bmcp\b/.test(normalizedUserRequest);
|
|
51732
|
+
const userExplicitlyRequestedCocoMcpCli = /\bcoco\s+mcp\b/.test(normalizedUserRequest) || /\b(run|ejecuta|ejecutar|lanza|lanzar)\b.{0,24}\bcoco\s+mcp\b/.test(normalizedUserRequest);
|
|
51733
|
+
const genericNetworkToolNames = /* @__PURE__ */ new Set(["http_fetch", "http_json", "web_fetch", "web_search"]);
|
|
51734
|
+
function shouldForceMcpForTool(toolCall) {
|
|
51735
|
+
if (!userExplicitlyRequestedMcp) return false;
|
|
51736
|
+
if (availableMcpToolNames.length === 0) return false;
|
|
51737
|
+
if (!genericNetworkToolNames.has(toolCall.name)) return false;
|
|
51738
|
+
return true;
|
|
51739
|
+
}
|
|
51740
|
+
function shouldBlockShellMcpInspection(toolCall) {
|
|
51741
|
+
if (toolCall.name !== "bash_exec") return false;
|
|
51742
|
+
if (!userExplicitlyRequestedMcp) return false;
|
|
51743
|
+
if (userExplicitlyRequestedCocoMcpCli) return false;
|
|
51744
|
+
const command = String(toolCall.input.command ?? "").trim().toLowerCase();
|
|
51745
|
+
return /^coco\s+mcp(?:\s|$)/.test(command);
|
|
51746
|
+
}
|
|
51599
51747
|
let iteration = 0;
|
|
51600
51748
|
let maxIterations = session.config.agent.maxToolIterations;
|
|
51601
51749
|
const HARD_MAX_ITERATIONS = 100;
|
|
@@ -51835,6 +51983,22 @@ ${tail}`;
|
|
|
51835
51983
|
if (options.signal?.aborted || turnAborted) {
|
|
51836
51984
|
break;
|
|
51837
51985
|
}
|
|
51986
|
+
if (shouldForceMcpForTool(toolCall)) {
|
|
51987
|
+
declinedTools.set(
|
|
51988
|
+
toolCall.id,
|
|
51989
|
+
`User explicitly requested MCP, but the model selected '${toolCall.name}' instead. Use an MCP tool (${availableMcpToolNames.join(", ")}) for this service access.`
|
|
51990
|
+
);
|
|
51991
|
+
options.onToolSkipped?.(toolCall, "Use MCP tool instead of generic fetch");
|
|
51992
|
+
continue;
|
|
51993
|
+
}
|
|
51994
|
+
if (shouldBlockShellMcpInspection(toolCall)) {
|
|
51995
|
+
declinedTools.set(
|
|
51996
|
+
toolCall.id,
|
|
51997
|
+
"Use the native mcp_list_servers tool to inspect configured and connected MCP services in this session. Do not shell out to `coco mcp ...` for runtime MCP diagnosis unless the user explicitly asked for the CLI command."
|
|
51998
|
+
);
|
|
51999
|
+
options.onToolSkipped?.(toolCall, "Use mcp_list_servers instead of coco mcp CLI");
|
|
52000
|
+
continue;
|
|
52001
|
+
}
|
|
51838
52002
|
const trustPattern = getTrustPattern(toolCall.name, toolCall.input);
|
|
51839
52003
|
const needsConfirmation = !options.skipConfirmation && !session.trustedTools.has(trustPattern) && requiresConfirmation(toolCall.name, toolCall.input);
|
|
51840
52004
|
if (needsConfirmation) {
|
|
@@ -52727,7 +52891,7 @@ function formatContextUsage(percent) {
|
|
|
52727
52891
|
}
|
|
52728
52892
|
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
52729
52893
|
const parts = [];
|
|
52730
|
-
const projectName =
|
|
52894
|
+
const projectName = path39__default.basename(projectPath);
|
|
52731
52895
|
parts.push(chalk.dim("\u{1F4C1} ") + chalk.magenta(projectName));
|
|
52732
52896
|
const providerName = config.provider.type;
|
|
52733
52897
|
const modelName = config.provider.model || "default";
|