@corbat-tech/coco 2.7.0 → 2.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cli/index.js +1239 -803
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +938 -550
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
2
|
+
import * as fs50 from 'fs';
|
|
3
|
+
import fs50__default, { readFileSync, constants } from 'fs';
|
|
4
|
+
import * as path35 from 'path';
|
|
5
|
+
import path35__default, { join, dirname, resolve, basename } from 'path';
|
|
6
6
|
import { URL as URL$1, fileURLToPath } from 'url';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import * as os4 from 'os';
|
|
9
9
|
import os4__default, { homedir } from 'os';
|
|
10
|
-
import * as
|
|
11
|
-
import
|
|
10
|
+
import * as fs33 from 'fs/promises';
|
|
11
|
+
import fs33__default, { mkdir, writeFile, readFile, access, readdir, rm } from 'fs/promises';
|
|
12
12
|
import JSON5 from 'json5';
|
|
13
13
|
import { Logger } from 'tslog';
|
|
14
14
|
import Anthropic from '@anthropic-ai/sdk';
|
|
@@ -282,6 +282,9 @@ var init_schema = __esm({
|
|
|
282
282
|
});
|
|
283
283
|
|
|
284
284
|
// src/utils/errors.ts
|
|
285
|
+
function isCocoError(error) {
|
|
286
|
+
return error instanceof CocoError;
|
|
287
|
+
}
|
|
285
288
|
function formatError(error) {
|
|
286
289
|
if (error instanceof CocoError) {
|
|
287
290
|
let message = `[${error.code}] ${error.message}`;
|
|
@@ -506,7 +509,7 @@ async function loadConfig(configPath) {
|
|
|
506
509
|
async function loadConfigFile(configPath, options = {}) {
|
|
507
510
|
const { strict = true } = options;
|
|
508
511
|
try {
|
|
509
|
-
const content = await
|
|
512
|
+
const content = await fs33__default.readFile(configPath, "utf-8");
|
|
510
513
|
const parsed = JSON5.parse(content);
|
|
511
514
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
512
515
|
if (!strict) {
|
|
@@ -562,7 +565,7 @@ function deepMergeConfig(base, override) {
|
|
|
562
565
|
};
|
|
563
566
|
}
|
|
564
567
|
function getProjectConfigPath() {
|
|
565
|
-
return
|
|
568
|
+
return path35__default.join(process.cwd(), ".coco", "config.json");
|
|
566
569
|
}
|
|
567
570
|
async function saveConfig(config, configPath, global = false) {
|
|
568
571
|
const result = CocoConfigSchema.safeParse(config);
|
|
@@ -577,10 +580,10 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
577
580
|
});
|
|
578
581
|
}
|
|
579
582
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath());
|
|
580
|
-
const dir =
|
|
581
|
-
await
|
|
583
|
+
const dir = path35__default.dirname(resolvedPath);
|
|
584
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
582
585
|
const content = JSON.stringify(result.data, null, 2);
|
|
583
|
-
await
|
|
586
|
+
await fs33__default.writeFile(resolvedPath, content, "utf-8");
|
|
584
587
|
}
|
|
585
588
|
function createDefaultConfig(projectName, language = "typescript") {
|
|
586
589
|
return createDefaultConfigObject(projectName, language);
|
|
@@ -589,20 +592,20 @@ async function findConfigPath(cwd) {
|
|
|
589
592
|
const envPath = process.env["COCO_CONFIG_PATH"];
|
|
590
593
|
if (envPath) {
|
|
591
594
|
try {
|
|
592
|
-
await
|
|
595
|
+
await fs33__default.access(envPath);
|
|
593
596
|
return envPath;
|
|
594
597
|
} catch {
|
|
595
598
|
}
|
|
596
599
|
}
|
|
597
600
|
const basePath = cwd || process.cwd();
|
|
598
|
-
const projectConfigPath =
|
|
601
|
+
const projectConfigPath = path35__default.join(basePath, ".coco", "config.json");
|
|
599
602
|
try {
|
|
600
|
-
await
|
|
603
|
+
await fs33__default.access(projectConfigPath);
|
|
601
604
|
return projectConfigPath;
|
|
602
605
|
} catch {
|
|
603
606
|
}
|
|
604
607
|
try {
|
|
605
|
-
await
|
|
608
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
606
609
|
return CONFIG_PATHS.config;
|
|
607
610
|
} catch {
|
|
608
611
|
return void 0;
|
|
@@ -611,14 +614,14 @@ async function findConfigPath(cwd) {
|
|
|
611
614
|
async function findAllConfigPaths(cwd) {
|
|
612
615
|
const result = {};
|
|
613
616
|
try {
|
|
614
|
-
await
|
|
617
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
615
618
|
result.global = CONFIG_PATHS.config;
|
|
616
619
|
} catch {
|
|
617
620
|
}
|
|
618
621
|
const basePath = cwd || process.cwd();
|
|
619
|
-
const projectConfigPath =
|
|
622
|
+
const projectConfigPath = path35__default.join(basePath, ".coco", "config.json");
|
|
620
623
|
try {
|
|
621
|
-
await
|
|
624
|
+
await fs33__default.access(projectConfigPath);
|
|
622
625
|
result.project = projectConfigPath;
|
|
623
626
|
} catch {
|
|
624
627
|
}
|
|
@@ -627,7 +630,7 @@ async function findAllConfigPaths(cwd) {
|
|
|
627
630
|
async function configExists(configPath, scope = "any") {
|
|
628
631
|
if (configPath) {
|
|
629
632
|
try {
|
|
630
|
-
await
|
|
633
|
+
await fs33__default.access(configPath);
|
|
631
634
|
return true;
|
|
632
635
|
} catch {
|
|
633
636
|
return false;
|
|
@@ -635,7 +638,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
635
638
|
}
|
|
636
639
|
if (scope === "project" || scope === "any") {
|
|
637
640
|
try {
|
|
638
|
-
await
|
|
641
|
+
await fs33__default.access(getProjectConfigPath());
|
|
639
642
|
return true;
|
|
640
643
|
} catch {
|
|
641
644
|
if (scope === "project") return false;
|
|
@@ -643,7 +646,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
643
646
|
}
|
|
644
647
|
if (scope === "global" || scope === "any") {
|
|
645
648
|
try {
|
|
646
|
-
await
|
|
649
|
+
await fs33__default.access(CONFIG_PATHS.config);
|
|
647
650
|
return true;
|
|
648
651
|
} catch {
|
|
649
652
|
return false;
|
|
@@ -651,8 +654,8 @@ async function configExists(configPath, scope = "any") {
|
|
|
651
654
|
}
|
|
652
655
|
return false;
|
|
653
656
|
}
|
|
654
|
-
function getConfigValue(config,
|
|
655
|
-
const keys =
|
|
657
|
+
function getConfigValue(config, path55) {
|
|
658
|
+
const keys = path55.split(".");
|
|
656
659
|
let current = config;
|
|
657
660
|
for (const key of keys) {
|
|
658
661
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -799,13 +802,13 @@ function createLogger(config = {}) {
|
|
|
799
802
|
return logger;
|
|
800
803
|
}
|
|
801
804
|
function setupFileLogging(logger, logDir, name) {
|
|
802
|
-
if (!
|
|
803
|
-
|
|
805
|
+
if (!fs50__default.existsSync(logDir)) {
|
|
806
|
+
fs50__default.mkdirSync(logDir, { recursive: true });
|
|
804
807
|
}
|
|
805
|
-
const logFile =
|
|
808
|
+
const logFile = path35__default.join(logDir, `${name}.log`);
|
|
806
809
|
logger.attachTransport((logObj) => {
|
|
807
810
|
const line = JSON.stringify(logObj) + "\n";
|
|
808
|
-
|
|
811
|
+
fs50__default.appendFileSync(logFile, line);
|
|
809
812
|
});
|
|
810
813
|
}
|
|
811
814
|
function createChildLogger(parent, name) {
|
|
@@ -821,7 +824,7 @@ function setLogger(logger) {
|
|
|
821
824
|
globalLogger = logger;
|
|
822
825
|
}
|
|
823
826
|
function initializeLogging(projectPath, level = "info") {
|
|
824
|
-
const logDir =
|
|
827
|
+
const logDir = path35__default.join(projectPath, ".coco", "logs");
|
|
825
828
|
const logger = createLogger({
|
|
826
829
|
name: "coco",
|
|
827
830
|
level,
|
|
@@ -1009,22 +1012,38 @@ var init_anthropic = __esm({
|
|
|
1009
1012
|
async *stream(messages, options) {
|
|
1010
1013
|
this.ensureInitialized();
|
|
1011
1014
|
try {
|
|
1012
|
-
const stream = await this.client.messages.stream(
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1015
|
+
const stream = await this.client.messages.stream(
|
|
1016
|
+
{
|
|
1017
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
|
|
1018
|
+
max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
1019
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
1020
|
+
system: this.extractSystem(messages, options?.system),
|
|
1021
|
+
messages: this.convertMessages(messages)
|
|
1022
|
+
},
|
|
1023
|
+
{ signal: options?.signal }
|
|
1024
|
+
);
|
|
1025
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1026
|
+
let lastActivityTime = Date.now();
|
|
1027
|
+
const checkTimeout = () => {
|
|
1028
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
1029
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
const timeoutInterval = setInterval(checkTimeout, 5e3);
|
|
1033
|
+
try {
|
|
1034
|
+
for await (const event of stream) {
|
|
1035
|
+
lastActivityTime = Date.now();
|
|
1036
|
+
if (event.type === "content_block_delta") {
|
|
1037
|
+
const delta = event.delta;
|
|
1038
|
+
if (delta.type === "text_delta" && delta.text) {
|
|
1039
|
+
yield { type: "text", text: delta.text };
|
|
1040
|
+
}
|
|
1024
1041
|
}
|
|
1025
1042
|
}
|
|
1043
|
+
yield { type: "done" };
|
|
1044
|
+
} finally {
|
|
1045
|
+
clearInterval(timeoutInterval);
|
|
1026
1046
|
}
|
|
1027
|
-
yield { type: "done" };
|
|
1028
1047
|
} catch (error) {
|
|
1029
1048
|
throw this.handleError(error);
|
|
1030
1049
|
}
|
|
@@ -1035,90 +1054,106 @@ var init_anthropic = __esm({
|
|
|
1035
1054
|
async *streamWithTools(messages, options) {
|
|
1036
1055
|
this.ensureInitialized();
|
|
1037
1056
|
try {
|
|
1038
|
-
const stream = await this.client.messages.stream(
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1057
|
+
const stream = await this.client.messages.stream(
|
|
1058
|
+
{
|
|
1059
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL,
|
|
1060
|
+
max_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
1061
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
1062
|
+
system: this.extractSystem(messages, options?.system),
|
|
1063
|
+
messages: this.convertMessages(messages),
|
|
1064
|
+
tools: this.convertTools(options.tools),
|
|
1065
|
+
tool_choice: options.toolChoice ? this.convertToolChoice(options.toolChoice) : void 0
|
|
1066
|
+
},
|
|
1067
|
+
{ signal: options?.signal }
|
|
1068
|
+
);
|
|
1047
1069
|
let currentToolCall = null;
|
|
1048
1070
|
let currentToolInputJson = "";
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1071
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
1072
|
+
let lastActivityTime = Date.now();
|
|
1073
|
+
const checkTimeout = () => {
|
|
1074
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
1075
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
const timeoutInterval = setInterval(checkTimeout, 5e3);
|
|
1079
|
+
try {
|
|
1080
|
+
for await (const event of stream) {
|
|
1081
|
+
lastActivityTime = Date.now();
|
|
1082
|
+
if (event.type === "content_block_start") {
|
|
1083
|
+
const contentBlock = event.content_block;
|
|
1084
|
+
if (contentBlock.type === "tool_use") {
|
|
1085
|
+
if (currentToolCall) {
|
|
1086
|
+
getLogger().warn(
|
|
1087
|
+
`[Anthropic] content_block_stop missing for tool '${currentToolCall.name}' \u2014 finalizing early to prevent data bleed.`
|
|
1088
|
+
);
|
|
1089
|
+
try {
|
|
1090
|
+
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1091
|
+
} catch {
|
|
1092
|
+
currentToolCall.input = {};
|
|
1093
|
+
}
|
|
1094
|
+
yield {
|
|
1095
|
+
type: "tool_use_end",
|
|
1096
|
+
toolCall: { ...currentToolCall }
|
|
1097
|
+
};
|
|
1098
|
+
}
|
|
1099
|
+
currentToolCall = {
|
|
1100
|
+
id: contentBlock.id,
|
|
1101
|
+
name: contentBlock.name
|
|
1102
|
+
};
|
|
1103
|
+
currentToolInputJson = "";
|
|
1104
|
+
yield {
|
|
1105
|
+
type: "tool_use_start",
|
|
1106
|
+
toolCall: { ...currentToolCall }
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
} else if (event.type === "content_block_delta") {
|
|
1110
|
+
const delta = event.delta;
|
|
1111
|
+
if (delta.type === "text_delta" && delta.text) {
|
|
1112
|
+
yield { type: "text", text: delta.text };
|
|
1113
|
+
} else if (delta.type === "input_json_delta" && delta.partial_json) {
|
|
1114
|
+
currentToolInputJson += delta.partial_json;
|
|
1115
|
+
yield {
|
|
1116
|
+
type: "tool_use_delta",
|
|
1117
|
+
toolCall: {
|
|
1118
|
+
...currentToolCall
|
|
1119
|
+
},
|
|
1120
|
+
text: delta.partial_json
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
} else if (event.type === "content_block_stop") {
|
|
1053
1124
|
if (currentToolCall) {
|
|
1054
|
-
getLogger().warn(
|
|
1055
|
-
`[Anthropic] content_block_stop missing for tool '${currentToolCall.name}' \u2014 finalizing early to prevent data bleed.`
|
|
1056
|
-
);
|
|
1057
1125
|
try {
|
|
1058
1126
|
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1059
1127
|
} catch {
|
|
1060
|
-
|
|
1128
|
+
let repaired = false;
|
|
1129
|
+
if (currentToolInputJson) {
|
|
1130
|
+
try {
|
|
1131
|
+
currentToolCall.input = JSON.parse(jsonrepair(currentToolInputJson));
|
|
1132
|
+
repaired = true;
|
|
1133
|
+
getLogger().debug(`Repaired JSON for tool ${currentToolCall.name}`);
|
|
1134
|
+
} catch {
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
if (!repaired) {
|
|
1138
|
+
getLogger().warn(
|
|
1139
|
+
`Failed to parse tool call arguments for ${currentToolCall.name}: ${currentToolInputJson?.slice(0, 300)}`
|
|
1140
|
+
);
|
|
1141
|
+
currentToolCall.input = {};
|
|
1142
|
+
}
|
|
1061
1143
|
}
|
|
1062
1144
|
yield {
|
|
1063
1145
|
type: "tool_use_end",
|
|
1064
1146
|
toolCall: { ...currentToolCall }
|
|
1065
1147
|
};
|
|
1148
|
+
currentToolCall = null;
|
|
1149
|
+
currentToolInputJson = "";
|
|
1066
1150
|
}
|
|
1067
|
-
currentToolCall = {
|
|
1068
|
-
id: contentBlock.id,
|
|
1069
|
-
name: contentBlock.name
|
|
1070
|
-
};
|
|
1071
|
-
currentToolInputJson = "";
|
|
1072
|
-
yield {
|
|
1073
|
-
type: "tool_use_start",
|
|
1074
|
-
toolCall: { ...currentToolCall }
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
} else if (event.type === "content_block_delta") {
|
|
1078
|
-
const delta = event.delta;
|
|
1079
|
-
if (delta.type === "text_delta" && delta.text) {
|
|
1080
|
-
yield { type: "text", text: delta.text };
|
|
1081
|
-
} else if (delta.type === "input_json_delta" && delta.partial_json) {
|
|
1082
|
-
currentToolInputJson += delta.partial_json;
|
|
1083
|
-
yield {
|
|
1084
|
-
type: "tool_use_delta",
|
|
1085
|
-
toolCall: {
|
|
1086
|
-
...currentToolCall
|
|
1087
|
-
},
|
|
1088
|
-
text: delta.partial_json
|
|
1089
|
-
};
|
|
1090
|
-
}
|
|
1091
|
-
} else if (event.type === "content_block_stop") {
|
|
1092
|
-
if (currentToolCall) {
|
|
1093
|
-
try {
|
|
1094
|
-
currentToolCall.input = currentToolInputJson ? JSON.parse(currentToolInputJson) : {};
|
|
1095
|
-
} catch {
|
|
1096
|
-
let repaired = false;
|
|
1097
|
-
if (currentToolInputJson) {
|
|
1098
|
-
try {
|
|
1099
|
-
currentToolCall.input = JSON.parse(jsonrepair(currentToolInputJson));
|
|
1100
|
-
repaired = true;
|
|
1101
|
-
getLogger().debug(`Repaired JSON for tool ${currentToolCall.name}`);
|
|
1102
|
-
} catch {
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
if (!repaired) {
|
|
1106
|
-
getLogger().warn(
|
|
1107
|
-
`Failed to parse tool call arguments for ${currentToolCall.name}: ${currentToolInputJson?.slice(0, 300)}`
|
|
1108
|
-
);
|
|
1109
|
-
currentToolCall.input = {};
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
yield {
|
|
1113
|
-
type: "tool_use_end",
|
|
1114
|
-
toolCall: { ...currentToolCall }
|
|
1115
|
-
};
|
|
1116
|
-
currentToolCall = null;
|
|
1117
|
-
currentToolInputJson = "";
|
|
1118
1151
|
}
|
|
1119
1152
|
}
|
|
1153
|
+
yield { type: "done" };
|
|
1154
|
+
} finally {
|
|
1155
|
+
clearInterval(timeoutInterval);
|
|
1120
1156
|
}
|
|
1121
|
-
yield { type: "done" };
|
|
1122
1157
|
} catch (error) {
|
|
1123
1158
|
throw this.handleError(error);
|
|
1124
1159
|
}
|
|
@@ -2230,18 +2265,18 @@ async function refreshAccessToken(provider, refreshToken) {
|
|
|
2230
2265
|
}
|
|
2231
2266
|
function getTokenStoragePath(provider) {
|
|
2232
2267
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
2233
|
-
return
|
|
2268
|
+
return path35.join(home, ".coco", "tokens", `${provider}.json`);
|
|
2234
2269
|
}
|
|
2235
2270
|
async function saveTokens(provider, tokens) {
|
|
2236
2271
|
const filePath = getTokenStoragePath(provider);
|
|
2237
|
-
const dir =
|
|
2238
|
-
await
|
|
2239
|
-
await
|
|
2272
|
+
const dir = path35.dirname(filePath);
|
|
2273
|
+
await fs33.mkdir(dir, { recursive: true, mode: 448 });
|
|
2274
|
+
await fs33.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
2240
2275
|
}
|
|
2241
2276
|
async function loadTokens(provider) {
|
|
2242
2277
|
const filePath = getTokenStoragePath(provider);
|
|
2243
2278
|
try {
|
|
2244
|
-
const content = await
|
|
2279
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
2245
2280
|
return JSON.parse(content);
|
|
2246
2281
|
} catch {
|
|
2247
2282
|
return null;
|
|
@@ -2250,7 +2285,7 @@ async function loadTokens(provider) {
|
|
|
2250
2285
|
async function deleteTokens(provider) {
|
|
2251
2286
|
const filePath = getTokenStoragePath(provider);
|
|
2252
2287
|
try {
|
|
2253
|
-
await
|
|
2288
|
+
await fs33.unlink(filePath);
|
|
2254
2289
|
} catch {
|
|
2255
2290
|
}
|
|
2256
2291
|
}
|
|
@@ -3214,7 +3249,7 @@ function getADCPath() {
|
|
|
3214
3249
|
if (process.env.GOOGLE_APPLICATION_CREDENTIALS) {
|
|
3215
3250
|
return process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
3216
3251
|
}
|
|
3217
|
-
return
|
|
3252
|
+
return path35.join(home, ".config", "gcloud", "application_default_credentials.json");
|
|
3218
3253
|
}
|
|
3219
3254
|
async function isGcloudInstalled() {
|
|
3220
3255
|
try {
|
|
@@ -3227,7 +3262,7 @@ async function isGcloudInstalled() {
|
|
|
3227
3262
|
async function hasADCCredentials() {
|
|
3228
3263
|
const adcPath = getADCPath();
|
|
3229
3264
|
try {
|
|
3230
|
-
await
|
|
3265
|
+
await fs33.access(adcPath);
|
|
3231
3266
|
return true;
|
|
3232
3267
|
} catch {
|
|
3233
3268
|
return false;
|
|
@@ -4607,8 +4642,8 @@ function loadGlobalCocoEnv() {
|
|
|
4607
4642
|
try {
|
|
4608
4643
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
4609
4644
|
if (!home) return;
|
|
4610
|
-
const globalEnvPath =
|
|
4611
|
-
const content =
|
|
4645
|
+
const globalEnvPath = path35.join(home, ".coco", ".env");
|
|
4646
|
+
const content = fs50.readFileSync(globalEnvPath, "utf-8");
|
|
4612
4647
|
for (const line of content.split("\n")) {
|
|
4613
4648
|
const trimmed = line.trim();
|
|
4614
4649
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -4743,7 +4778,7 @@ function loadUserPreferences() {
|
|
|
4743
4778
|
return cachedPreferences;
|
|
4744
4779
|
}
|
|
4745
4780
|
try {
|
|
4746
|
-
const content =
|
|
4781
|
+
const content = fs50.readFileSync(CONFIG_PATHS.config, "utf-8");
|
|
4747
4782
|
cachedPreferences = JSON.parse(content);
|
|
4748
4783
|
return cachedPreferences;
|
|
4749
4784
|
} catch {
|
|
@@ -4761,9 +4796,9 @@ async function saveUserPreferences(prefs) {
|
|
|
4761
4796
|
authMethods: { ...existing.authMethods, ...prefs.authMethods },
|
|
4762
4797
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4763
4798
|
};
|
|
4764
|
-
const dir =
|
|
4765
|
-
await
|
|
4766
|
-
await
|
|
4799
|
+
const dir = path35.dirname(CONFIG_PATHS.config);
|
|
4800
|
+
await fs50.promises.mkdir(dir, { recursive: true });
|
|
4801
|
+
await fs50.promises.writeFile(CONFIG_PATHS.config, JSON.stringify(updated, null, 2), "utf-8");
|
|
4767
4802
|
cachedPreferences = updated;
|
|
4768
4803
|
} catch {
|
|
4769
4804
|
}
|
|
@@ -5235,8 +5270,8 @@ var init_registry = __esm({
|
|
|
5235
5270
|
/**
|
|
5236
5271
|
* Ensure directory exists
|
|
5237
5272
|
*/
|
|
5238
|
-
async ensureDir(
|
|
5239
|
-
await mkdir(dirname(
|
|
5273
|
+
async ensureDir(path55) {
|
|
5274
|
+
await mkdir(dirname(path55), { recursive: true });
|
|
5240
5275
|
}
|
|
5241
5276
|
};
|
|
5242
5277
|
}
|
|
@@ -5311,7 +5346,7 @@ __export(markdown_loader_exports, {
|
|
|
5311
5346
|
});
|
|
5312
5347
|
async function isMarkdownSkill(skillDir) {
|
|
5313
5348
|
try {
|
|
5314
|
-
await
|
|
5349
|
+
await fs33__default.access(path35__default.join(skillDir, SKILL_FILENAME));
|
|
5315
5350
|
return true;
|
|
5316
5351
|
} catch {
|
|
5317
5352
|
return false;
|
|
@@ -5319,16 +5354,16 @@ async function isMarkdownSkill(skillDir) {
|
|
|
5319
5354
|
}
|
|
5320
5355
|
async function loadMarkdownMetadata(skillDir, scope) {
|
|
5321
5356
|
try {
|
|
5322
|
-
const skillPath =
|
|
5323
|
-
const raw = await
|
|
5357
|
+
const skillPath = path35__default.join(skillDir, SKILL_FILENAME);
|
|
5358
|
+
const raw = await fs33__default.readFile(skillPath, "utf-8");
|
|
5324
5359
|
const { data } = matter(raw);
|
|
5325
5360
|
const parsed = SkillFrontmatterSchema.safeParse(data);
|
|
5326
5361
|
if (!parsed.success) {
|
|
5327
5362
|
return null;
|
|
5328
5363
|
}
|
|
5329
5364
|
const fm = parsed.data;
|
|
5330
|
-
const dirName =
|
|
5331
|
-
const parentDir =
|
|
5365
|
+
const dirName = path35__default.basename(skillDir);
|
|
5366
|
+
const parentDir = path35__default.basename(path35__default.dirname(skillDir));
|
|
5332
5367
|
const namespace = isNamespaceDirectory(parentDir) ? parentDir : void 0;
|
|
5333
5368
|
const baseId = toKebabCase(fm.name || dirName);
|
|
5334
5369
|
const fullId = namespace ? `${namespace}/${baseId}` : baseId;
|
|
@@ -5368,8 +5403,8 @@ async function loadMarkdownMetadata(skillDir, scope) {
|
|
|
5368
5403
|
}
|
|
5369
5404
|
async function loadMarkdownContent(skillDir) {
|
|
5370
5405
|
try {
|
|
5371
|
-
const skillPath =
|
|
5372
|
-
const raw = await
|
|
5406
|
+
const skillPath = path35__default.join(skillDir, SKILL_FILENAME);
|
|
5407
|
+
const raw = await fs33__default.readFile(skillPath, "utf-8");
|
|
5373
5408
|
const { content } = matter(raw);
|
|
5374
5409
|
const references = await listSubdirectory(skillDir, "references");
|
|
5375
5410
|
const scripts = await listSubdirectory(skillDir, "scripts");
|
|
@@ -5391,9 +5426,9 @@ async function loadMarkdownContent(skillDir) {
|
|
|
5391
5426
|
}
|
|
5392
5427
|
async function listSubdirectory(skillDir, subdir) {
|
|
5393
5428
|
try {
|
|
5394
|
-
const dir =
|
|
5395
|
-
const entries = await
|
|
5396
|
-
return entries.filter((e) => e.isFile()).map((e) =>
|
|
5429
|
+
const dir = path35__default.join(skillDir, subdir);
|
|
5430
|
+
const entries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5431
|
+
return entries.filter((e) => e.isFile()).map((e) => path35__default.join(dir, e.name));
|
|
5397
5432
|
} catch {
|
|
5398
5433
|
return [];
|
|
5399
5434
|
}
|
|
@@ -5470,8 +5505,8 @@ async function loadSkillFromDirectory(skillDir, scope) {
|
|
|
5470
5505
|
if (await isMarkdownSkill(skillDir)) {
|
|
5471
5506
|
return loadMarkdownMetadata(skillDir, scope);
|
|
5472
5507
|
}
|
|
5473
|
-
const hasTs = await fileExists(
|
|
5474
|
-
const hasJs = await fileExists(
|
|
5508
|
+
const hasTs = await fileExists(path35__default.join(skillDir, "index.ts"));
|
|
5509
|
+
const hasJs = await fileExists(path35__default.join(skillDir, "index.js"));
|
|
5475
5510
|
if (hasTs || hasJs) {
|
|
5476
5511
|
return null;
|
|
5477
5512
|
}
|
|
@@ -5491,7 +5526,7 @@ async function loadFullSkill(metadata) {
|
|
|
5491
5526
|
}
|
|
5492
5527
|
async function fileExists(filePath) {
|
|
5493
5528
|
try {
|
|
5494
|
-
await
|
|
5529
|
+
await fs33__default.access(filePath);
|
|
5495
5530
|
return true;
|
|
5496
5531
|
} catch {
|
|
5497
5532
|
return false;
|
|
@@ -5516,7 +5551,7 @@ async function discoverAllSkills(projectPath, builtinSkills = [], options) {
|
|
|
5516
5551
|
for (const meta of globalSkills) {
|
|
5517
5552
|
applyWithPriority(allSkills, meta);
|
|
5518
5553
|
}
|
|
5519
|
-
const projectDirs = opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) =>
|
|
5554
|
+
const projectDirs = opts.projectDir ? [opts.projectDir] : PROJECT_SKILLS_DIRNAMES.map((d) => path35__default.join(projectPath, d));
|
|
5520
5555
|
for (const dir of projectDirs) {
|
|
5521
5556
|
const projectSkills = await scanSkillsDirectory(dir, "project");
|
|
5522
5557
|
for (const meta of projectSkills) {
|
|
@@ -5527,13 +5562,13 @@ async function discoverAllSkills(projectPath, builtinSkills = [], options) {
|
|
|
5527
5562
|
}
|
|
5528
5563
|
async function scanSkillsDirectory(dir, scope) {
|
|
5529
5564
|
try {
|
|
5530
|
-
const entries = await
|
|
5565
|
+
const entries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5531
5566
|
const skillDirs = entries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
5532
5567
|
const results = [];
|
|
5533
5568
|
for (const entry of skillDirs) {
|
|
5534
|
-
const entryPath =
|
|
5569
|
+
const entryPath = path35__default.join(dir, entry.name);
|
|
5535
5570
|
try {
|
|
5536
|
-
const stat2 = await
|
|
5571
|
+
const stat2 = await fs33__default.lstat(entryPath);
|
|
5537
5572
|
if (stat2.isSymbolicLink()) continue;
|
|
5538
5573
|
} catch {
|
|
5539
5574
|
continue;
|
|
@@ -5561,13 +5596,13 @@ async function scanSkillsDirectory(dir, scope) {
|
|
|
5561
5596
|
async function scanNestedSkills(dir, scope, depth) {
|
|
5562
5597
|
if (depth >= MAX_NESTING_DEPTH) return [];
|
|
5563
5598
|
try {
|
|
5564
|
-
const subEntries = await
|
|
5599
|
+
const subEntries = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
5565
5600
|
const subDirs = subEntries.filter((e) => e.isDirectory() && !e.isSymbolicLink());
|
|
5566
5601
|
const results = await Promise.all(
|
|
5567
5602
|
subDirs.map(async (sub) => {
|
|
5568
|
-
const subPath =
|
|
5603
|
+
const subPath = path35__default.join(dir, sub.name);
|
|
5569
5604
|
try {
|
|
5570
|
-
const stat2 = await
|
|
5605
|
+
const stat2 = await fs33__default.lstat(subPath);
|
|
5571
5606
|
if (stat2.isSymbolicLink()) return null;
|
|
5572
5607
|
} catch {
|
|
5573
5608
|
return null;
|
|
@@ -5594,7 +5629,7 @@ var init_discovery = __esm({
|
|
|
5594
5629
|
init_typescript_loader();
|
|
5595
5630
|
init_paths();
|
|
5596
5631
|
init_logger();
|
|
5597
|
-
GLOBAL_SKILLS_DIR =
|
|
5632
|
+
GLOBAL_SKILLS_DIR = path35__default.join(COCO_HOME, "skills");
|
|
5598
5633
|
PROJECT_SKILLS_DIRNAMES = [
|
|
5599
5634
|
".claude/skills",
|
|
5600
5635
|
// Claude compat — read for migration/interop (lowest project priority)
|
|
@@ -6561,7 +6596,7 @@ CONVERSATION:
|
|
|
6561
6596
|
* @param provider - The LLM provider to use for summarization
|
|
6562
6597
|
* @returns Compacted messages with summary replacing older messages
|
|
6563
6598
|
*/
|
|
6564
|
-
async compact(messages, provider) {
|
|
6599
|
+
async compact(messages, provider, signal) {
|
|
6565
6600
|
const conversationMessages = messages.filter((m) => m.role !== "system");
|
|
6566
6601
|
if (conversationMessages.length <= this.config.preserveLastN) {
|
|
6567
6602
|
return {
|
|
@@ -6593,7 +6628,7 @@ CONVERSATION:
|
|
|
6593
6628
|
}
|
|
6594
6629
|
const originalTokens = this.estimateTokens(messages, provider);
|
|
6595
6630
|
const conversationText = this.formatMessagesForSummary(messagesToSummarize);
|
|
6596
|
-
const summary = await this.generateSummary(conversationText, provider);
|
|
6631
|
+
const summary = await this.generateSummary(conversationText, provider, signal);
|
|
6597
6632
|
const systemMessages = messages.filter((m) => m.role === "system");
|
|
6598
6633
|
const summaryMessage = {
|
|
6599
6634
|
role: "user",
|
|
@@ -6647,16 +6682,30 @@ ${summary}
|
|
|
6647
6682
|
/**
|
|
6648
6683
|
* Generate a summary of the conversation using the LLM
|
|
6649
6684
|
*/
|
|
6650
|
-
async generateSummary(conversationText, provider) {
|
|
6685
|
+
async generateSummary(conversationText, provider, signal) {
|
|
6686
|
+
if (signal?.aborted) return "[Compaction cancelled]";
|
|
6651
6687
|
const prompt = COMPACTION_PROMPT + conversationText;
|
|
6652
6688
|
try {
|
|
6653
|
-
const
|
|
6689
|
+
const chatPromise = provider.chat([{ role: "user", content: prompt }], {
|
|
6654
6690
|
maxTokens: this.config.summaryMaxTokens,
|
|
6655
6691
|
temperature: 0.3
|
|
6656
6692
|
// Lower temperature for more consistent summaries
|
|
6657
6693
|
});
|
|
6694
|
+
if (signal) {
|
|
6695
|
+
const abortPromise = new Promise((_, reject) => {
|
|
6696
|
+
signal.addEventListener(
|
|
6697
|
+
"abort",
|
|
6698
|
+
() => reject(new DOMException("Aborted", "AbortError")),
|
|
6699
|
+
{ once: true }
|
|
6700
|
+
);
|
|
6701
|
+
});
|
|
6702
|
+
const response2 = await Promise.race([chatPromise, abortPromise]);
|
|
6703
|
+
return response2.content;
|
|
6704
|
+
}
|
|
6705
|
+
const response = await chatPromise;
|
|
6658
6706
|
return response.content;
|
|
6659
6707
|
} catch (error) {
|
|
6708
|
+
if (error instanceof DOMException && error.name === "AbortError") throw error;
|
|
6660
6709
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6661
6710
|
return `[Summary generation failed: ${errorMessage}. Previous conversation had ${conversationText.length} characters.]`;
|
|
6662
6711
|
}
|
|
@@ -6700,9 +6749,9 @@ function createEmptyMemoryContext() {
|
|
|
6700
6749
|
errors: []
|
|
6701
6750
|
};
|
|
6702
6751
|
}
|
|
6703
|
-
function createMissingMemoryFile(
|
|
6752
|
+
function createMissingMemoryFile(path55, level) {
|
|
6704
6753
|
return {
|
|
6705
|
-
path:
|
|
6754
|
+
path: path55,
|
|
6706
6755
|
level,
|
|
6707
6756
|
content: "",
|
|
6708
6757
|
sections: [],
|
|
@@ -6792,7 +6841,14 @@ function addMessage(session, message) {
|
|
|
6792
6841
|
session.messages.push(message);
|
|
6793
6842
|
const maxMessages = session.config.ui.maxHistorySize * 2;
|
|
6794
6843
|
if (session.messages.length > maxMessages) {
|
|
6795
|
-
|
|
6844
|
+
let sliceStart = session.messages.length - session.config.ui.maxHistorySize;
|
|
6845
|
+
while (sliceStart > 0 && sliceStart < session.messages.length) {
|
|
6846
|
+
const msg = session.messages[sliceStart];
|
|
6847
|
+
const isToolResult = Array.isArray(msg?.content) && msg.content.length > 0 && msg.content[0]?.type === "tool_result";
|
|
6848
|
+
if (!isToolResult) break;
|
|
6849
|
+
sliceStart--;
|
|
6850
|
+
}
|
|
6851
|
+
session.messages = session.messages.slice(sliceStart);
|
|
6796
6852
|
}
|
|
6797
6853
|
}
|
|
6798
6854
|
function substituteDynamicContext(body, cwd) {
|
|
@@ -6933,7 +6989,7 @@ function clearSession(session) {
|
|
|
6933
6989
|
}
|
|
6934
6990
|
async function loadTrustSettings() {
|
|
6935
6991
|
try {
|
|
6936
|
-
const content = await
|
|
6992
|
+
const content = await fs33__default.readFile(TRUST_SETTINGS_FILE, "utf-8");
|
|
6937
6993
|
const raw = JSON.parse(content);
|
|
6938
6994
|
return {
|
|
6939
6995
|
globalTrusted: raw.globalTrusted ?? [],
|
|
@@ -6952,9 +7008,9 @@ async function loadTrustSettings() {
|
|
|
6952
7008
|
}
|
|
6953
7009
|
async function saveTrustSettings(settings) {
|
|
6954
7010
|
try {
|
|
6955
|
-
await
|
|
7011
|
+
await fs33__default.mkdir(TRUST_SETTINGS_DIR, { recursive: true });
|
|
6956
7012
|
settings.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
6957
|
-
await
|
|
7013
|
+
await fs33__default.writeFile(TRUST_SETTINGS_FILE, JSON.stringify(settings, null, 2), "utf-8");
|
|
6958
7014
|
} catch (error) {
|
|
6959
7015
|
const msg = error instanceof Error ? error.message : String(error);
|
|
6960
7016
|
console.warn(`[Trust] Failed to save trust settings: ${msg}`);
|
|
@@ -7059,7 +7115,7 @@ function updateContextTokens(session, provider) {
|
|
|
7059
7115
|
}
|
|
7060
7116
|
session.contextManager.setUsedTokens(totalTokens);
|
|
7061
7117
|
}
|
|
7062
|
-
async function checkAndCompactContext(session, provider) {
|
|
7118
|
+
async function checkAndCompactContext(session, provider, signal) {
|
|
7063
7119
|
if (!session.contextManager) {
|
|
7064
7120
|
initializeContextManager(session, provider);
|
|
7065
7121
|
}
|
|
@@ -7071,7 +7127,7 @@ async function checkAndCompactContext(session, provider) {
|
|
|
7071
7127
|
preserveLastN: 4,
|
|
7072
7128
|
summaryMaxTokens: 1e3
|
|
7073
7129
|
});
|
|
7074
|
-
const result = await compactor.compact(session.messages, provider);
|
|
7130
|
+
const result = await compactor.compact(session.messages, provider, signal);
|
|
7075
7131
|
if (result.wasCompacted) {
|
|
7076
7132
|
const compactedNonSystem = result.messages.filter((m) => m.role !== "system");
|
|
7077
7133
|
session.messages = compactedNonSystem;
|
|
@@ -7097,7 +7153,7 @@ var init_session = __esm({
|
|
|
7097
7153
|
init_manager();
|
|
7098
7154
|
init_compactor();
|
|
7099
7155
|
MAX_SKILL_INSTRUCTIONS_CHARS = 16e3;
|
|
7100
|
-
TRUST_SETTINGS_DIR =
|
|
7156
|
+
TRUST_SETTINGS_DIR = path35__default.dirname(CONFIG_PATHS.trustedTools);
|
|
7101
7157
|
TRUST_SETTINGS_FILE = CONFIG_PATHS.trustedTools;
|
|
7102
7158
|
CATEGORY_LABELS = {
|
|
7103
7159
|
file: "File Operations",
|
|
@@ -7220,6 +7276,21 @@ After completing a task, ALWAYS suggest logical next steps based on what you did
|
|
|
7220
7276
|
|
|
7221
7277
|
Keep suggestions brief (1-2 bullet points max) and actionable.
|
|
7222
7278
|
|
|
7279
|
+
## Error Recovery
|
|
7280
|
+
|
|
7281
|
+
When a tool fails, do NOT blindly retry with the same arguments. Instead:
|
|
7282
|
+
- **File not found**: Use **glob** with a pattern like \`**/*partial-name*\` or **list_dir** to explore nearby directories. Check the error for "Did you mean?" suggestions.
|
|
7283
|
+
- **Text not found in edit_file**: Use **read_file** to see the actual content. The error shows the closest matching lines \u2014 use those as reference for the correct oldText.
|
|
7284
|
+
- **web_fetch HTTP error (404, 403, etc.)**: Do NOT retry the same URL. Use **web_search** to find the correct or alternative URL. If the page requires authentication, look for a public alternative.
|
|
7285
|
+
- **web_search failure**: Try a different search engine parameter, simplify the query, or rephrase with different keywords.
|
|
7286
|
+
- **Timeout errors**: Do NOT immediately retry. Simplify the request, try a different source, or inform the user.
|
|
7287
|
+
- **After 2 failures with the same tool**: Stop, rethink your approach, try an alternative tool or strategy, or explain the issue to the user.
|
|
7288
|
+
- **Git errors**: If git_commit, git_push, etc. fail, read the error carefully. Use git_status to understand the current state. For "not a git repository", verify the working directory with list_dir.
|
|
7289
|
+
- **Build/test failures**: Read the stderr output and the hint field in the result. Use read_file to inspect the failing file. Never retry the same build without fixing the underlying code first.
|
|
7290
|
+
- **Permission denied**: Do NOT retry. Explain to the user that the operation requires different permissions.
|
|
7291
|
+
- **Command not found**: Use command_exists to verify availability before suggesting alternatives.
|
|
7292
|
+
- **Database errors**: Use inspect_schema to understand table structure before retrying queries.
|
|
7293
|
+
|
|
7223
7294
|
## File Access
|
|
7224
7295
|
File operations are restricted to the project directory by default.
|
|
7225
7296
|
When you need to access a path outside the project, use the **authorize_path** tool first \u2014 it will ask the user for permission interactively. Once authorized, proceed with the file operation.
|
|
@@ -7382,13 +7453,13 @@ var init_types4 = __esm({
|
|
|
7382
7453
|
}
|
|
7383
7454
|
});
|
|
7384
7455
|
function getStatePath(projectPath) {
|
|
7385
|
-
return
|
|
7456
|
+
return path35.join(projectPath, ".coco", "state.json");
|
|
7386
7457
|
}
|
|
7387
7458
|
function createStateManager() {
|
|
7388
7459
|
async function load(projectPath) {
|
|
7389
7460
|
const statePath = getStatePath(projectPath);
|
|
7390
7461
|
try {
|
|
7391
|
-
const content = await
|
|
7462
|
+
const content = await fs33.readFile(statePath, "utf-8");
|
|
7392
7463
|
const file = JSON.parse(content);
|
|
7393
7464
|
if (file.version !== STATE_VERSION) {
|
|
7394
7465
|
console.warn(`State version mismatch: ${file.version} vs ${STATE_VERSION}`);
|
|
@@ -7407,7 +7478,7 @@ function createStateManager() {
|
|
|
7407
7478
|
}
|
|
7408
7479
|
async function save(state) {
|
|
7409
7480
|
const statePath = getStatePath(state.path);
|
|
7410
|
-
await
|
|
7481
|
+
await fs33.mkdir(path35.dirname(statePath), { recursive: true });
|
|
7411
7482
|
const file = {
|
|
7412
7483
|
version: STATE_VERSION,
|
|
7413
7484
|
state: {
|
|
@@ -7415,19 +7486,19 @@ function createStateManager() {
|
|
|
7415
7486
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7416
7487
|
}
|
|
7417
7488
|
};
|
|
7418
|
-
await
|
|
7489
|
+
await fs33.writeFile(statePath, JSON.stringify(file, null, 2), "utf-8");
|
|
7419
7490
|
}
|
|
7420
7491
|
async function clear(projectPath) {
|
|
7421
7492
|
const statePath = getStatePath(projectPath);
|
|
7422
7493
|
try {
|
|
7423
|
-
await
|
|
7494
|
+
await fs33.unlink(statePath);
|
|
7424
7495
|
} catch {
|
|
7425
7496
|
}
|
|
7426
7497
|
}
|
|
7427
7498
|
async function exists(projectPath) {
|
|
7428
7499
|
const statePath = getStatePath(projectPath);
|
|
7429
7500
|
try {
|
|
7430
|
-
await
|
|
7501
|
+
await fs33.access(statePath);
|
|
7431
7502
|
return true;
|
|
7432
7503
|
} catch {
|
|
7433
7504
|
return false;
|
|
@@ -7555,8 +7626,8 @@ __export(trust_store_exports, {
|
|
|
7555
7626
|
saveTrustStore: () => saveTrustStore,
|
|
7556
7627
|
updateLastAccessed: () => updateLastAccessed
|
|
7557
7628
|
});
|
|
7558
|
-
async function ensureDir(
|
|
7559
|
-
await mkdir(dirname(
|
|
7629
|
+
async function ensureDir(path55) {
|
|
7630
|
+
await mkdir(dirname(path55), { recursive: true });
|
|
7560
7631
|
}
|
|
7561
7632
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
7562
7633
|
try {
|
|
@@ -7634,8 +7705,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
7634
7705
|
};
|
|
7635
7706
|
return permissions[level]?.includes(operation) ?? false;
|
|
7636
7707
|
}
|
|
7637
|
-
function normalizePath(
|
|
7638
|
-
return join(
|
|
7708
|
+
function normalizePath(path55) {
|
|
7709
|
+
return join(path55);
|
|
7639
7710
|
}
|
|
7640
7711
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
7641
7712
|
let store = null;
|
|
@@ -7952,6 +8023,14 @@ function extractQuotedPath(msg) {
|
|
|
7952
8023
|
function humanizeError(message, toolName) {
|
|
7953
8024
|
const msg = message.trim();
|
|
7954
8025
|
if (!msg) return msg;
|
|
8026
|
+
if (/Use (glob|list_dir|read_file|git_init|git_status|git_add|git_commit|git_log|git_branch|git_checkout|git_push|git_pull|web_search|inspect_schema|list_checkpoints|command_exists|edit_file|run_linter|run_tests|run_script|bash_exec)\b/.test(
|
|
8027
|
+
msg
|
|
8028
|
+
)) {
|
|
8029
|
+
return msg;
|
|
8030
|
+
}
|
|
8031
|
+
if (/run git_init\b/.test(msg)) {
|
|
8032
|
+
return msg;
|
|
8033
|
+
}
|
|
7955
8034
|
if (/ECONNREFUSED/i.test(msg)) {
|
|
7956
8035
|
return "Connection refused \u2014 the server may not be running";
|
|
7957
8036
|
}
|
|
@@ -7973,13 +8052,22 @@ function humanizeError(message, toolName) {
|
|
|
7973
8052
|
if (/fetch failed|network error|Failed to fetch/i.test(msg)) {
|
|
7974
8053
|
return "Network request failed \u2014 check your internet connection";
|
|
7975
8054
|
}
|
|
8055
|
+
if (/File not found:/.test(msg) && /Did you mean/.test(msg)) {
|
|
8056
|
+
return msg;
|
|
8057
|
+
}
|
|
8058
|
+
if (/Directory not found:/.test(msg) && /Did you mean/.test(msg)) {
|
|
8059
|
+
return msg;
|
|
8060
|
+
}
|
|
8061
|
+
if (/^HTTP \d{3}:/.test(msg) && /Try/.test(msg)) {
|
|
8062
|
+
return msg;
|
|
8063
|
+
}
|
|
7976
8064
|
if (/ENOENT/i.test(msg)) {
|
|
7977
|
-
const
|
|
7978
|
-
return
|
|
8065
|
+
const path55 = extractQuotedPath(msg);
|
|
8066
|
+
return path55 ? `File or directory not found: ${path55}` : "File or directory not found";
|
|
7979
8067
|
}
|
|
7980
8068
|
if (/EACCES/i.test(msg)) {
|
|
7981
|
-
const
|
|
7982
|
-
return
|
|
8069
|
+
const path55 = extractQuotedPath(msg);
|
|
8070
|
+
return path55 ? `Permission denied: ${path55}` : "Permission denied \u2014 check file permissions";
|
|
7983
8071
|
}
|
|
7984
8072
|
if (/EISDIR/i.test(msg)) {
|
|
7985
8073
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -8062,6 +8150,12 @@ function humanizeError(message, toolName) {
|
|
|
8062
8150
|
if (/invalid.*api.?key|api.?key.*invalid|api.?key.*not.*found/i.test(msg)) {
|
|
8063
8151
|
return "Invalid or missing API key \u2014 check your provider credentials";
|
|
8064
8152
|
}
|
|
8153
|
+
if (/TS\d{4}:/.test(msg)) {
|
|
8154
|
+
return `TypeScript error \u2014 check the referenced file and line number. ${msg}`;
|
|
8155
|
+
}
|
|
8156
|
+
if (/SQLITE_ERROR/i.test(msg)) {
|
|
8157
|
+
return `Database error \u2014 use inspect_schema to verify the table structure. ${msg}`;
|
|
8158
|
+
}
|
|
8065
8159
|
return msg;
|
|
8066
8160
|
}
|
|
8067
8161
|
function looksLikeTechnicalJargon(message) {
|
|
@@ -8161,6 +8255,7 @@ var init_registry4 = __esm({
|
|
|
8161
8255
|
"src/tools/registry.ts"() {
|
|
8162
8256
|
init_logger();
|
|
8163
8257
|
init_error_humanizer();
|
|
8258
|
+
init_errors();
|
|
8164
8259
|
ToolRegistry = class {
|
|
8165
8260
|
tools = /* @__PURE__ */ new Map();
|
|
8166
8261
|
logger = getLogger();
|
|
@@ -8264,6 +8359,14 @@ var init_registry4 = __esm({
|
|
|
8264
8359
|
if (allUndefined && error.issues.length > 1) {
|
|
8265
8360
|
errorMessage += ". All parameters are missing \u2014 this is likely a JSON serialization error on our side. Please retry with the same arguments.";
|
|
8266
8361
|
}
|
|
8362
|
+
} else if (isCocoError(error)) {
|
|
8363
|
+
const causeMsg = error.cause instanceof Error ? error.cause.message : "";
|
|
8364
|
+
const combined = causeMsg && !error.message.includes(causeMsg) ? `${error.message} \u2014 ${causeMsg}` : error.message;
|
|
8365
|
+
errorMessage = humanizeError(combined, name);
|
|
8366
|
+
if (error.suggestion && !errorMessage.includes(error.suggestion)) {
|
|
8367
|
+
errorMessage += `
|
|
8368
|
+
Suggestion: ${error.suggestion}`;
|
|
8369
|
+
}
|
|
8267
8370
|
} else {
|
|
8268
8371
|
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
8269
8372
|
errorMessage = humanizeError(rawMessage, name);
|
|
@@ -8297,7 +8400,7 @@ var init_registry4 = __esm({
|
|
|
8297
8400
|
});
|
|
8298
8401
|
async function fileExists2(filePath) {
|
|
8299
8402
|
try {
|
|
8300
|
-
await
|
|
8403
|
+
await fs33__default.access(filePath);
|
|
8301
8404
|
return true;
|
|
8302
8405
|
} catch {
|
|
8303
8406
|
return false;
|
|
@@ -8699,9 +8802,9 @@ var init_diff_renderer = __esm({
|
|
|
8699
8802
|
getTerminalWidth = () => process.stdout.columns || 80;
|
|
8700
8803
|
}
|
|
8701
8804
|
});
|
|
8702
|
-
async function fileExists3(
|
|
8805
|
+
async function fileExists3(path55) {
|
|
8703
8806
|
try {
|
|
8704
|
-
await access(
|
|
8807
|
+
await access(path55);
|
|
8705
8808
|
return true;
|
|
8706
8809
|
} catch {
|
|
8707
8810
|
return false;
|
|
@@ -8791,7 +8894,7 @@ async function detectMaturity(cwd) {
|
|
|
8791
8894
|
if (!hasLintConfig && hasPackageJson) {
|
|
8792
8895
|
try {
|
|
8793
8896
|
const pkgRaw = await import('fs/promises').then(
|
|
8794
|
-
(
|
|
8897
|
+
(fs53) => fs53.readFile(join(cwd, "package.json"), "utf-8")
|
|
8795
8898
|
);
|
|
8796
8899
|
const pkg = JSON.parse(pkgRaw);
|
|
8797
8900
|
if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
|
|
@@ -8991,10 +9094,10 @@ var init_coverage = __esm({
|
|
|
8991
9094
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
8992
9095
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
8993
9096
|
];
|
|
8994
|
-
for (const
|
|
9097
|
+
for (const path55 of possiblePaths) {
|
|
8995
9098
|
try {
|
|
8996
|
-
await access(
|
|
8997
|
-
const content = await readFile(
|
|
9099
|
+
await access(path55, constants.R_OK);
|
|
9100
|
+
const content = await readFile(path55, "utf-8");
|
|
8998
9101
|
const report = JSON.parse(content);
|
|
8999
9102
|
return parseCoverageSummary(report);
|
|
9000
9103
|
} catch {
|
|
@@ -9728,7 +9831,7 @@ var init_build_verifier = __esm({
|
|
|
9728
9831
|
async verifyTypes() {
|
|
9729
9832
|
const startTime = Date.now();
|
|
9730
9833
|
try {
|
|
9731
|
-
const hasTsConfig = await this.fileExists(
|
|
9834
|
+
const hasTsConfig = await this.fileExists(path35.join(this.projectPath, "tsconfig.json"));
|
|
9732
9835
|
if (!hasTsConfig) {
|
|
9733
9836
|
return {
|
|
9734
9837
|
success: true,
|
|
@@ -9778,8 +9881,8 @@ var init_build_verifier = __esm({
|
|
|
9778
9881
|
*/
|
|
9779
9882
|
async detectBuildCommand() {
|
|
9780
9883
|
try {
|
|
9781
|
-
const packageJsonPath =
|
|
9782
|
-
const content = await
|
|
9884
|
+
const packageJsonPath = path35.join(this.projectPath, "package.json");
|
|
9885
|
+
const content = await fs33.readFile(packageJsonPath, "utf-8");
|
|
9783
9886
|
const packageJson = JSON.parse(content);
|
|
9784
9887
|
if (packageJson.scripts?.build) {
|
|
9785
9888
|
return "npm run build";
|
|
@@ -9855,7 +9958,7 @@ var init_build_verifier = __esm({
|
|
|
9855
9958
|
*/
|
|
9856
9959
|
async fileExists(filePath) {
|
|
9857
9960
|
try {
|
|
9858
|
-
await
|
|
9961
|
+
await fs33.access(filePath);
|
|
9859
9962
|
return true;
|
|
9860
9963
|
} catch {
|
|
9861
9964
|
return false;
|
|
@@ -11477,9 +11580,9 @@ function detectProjectLanguage(files) {
|
|
|
11477
11580
|
return { language: dominant, confidence, evidence };
|
|
11478
11581
|
}
|
|
11479
11582
|
function getFileExtension(filePath) {
|
|
11480
|
-
const base =
|
|
11583
|
+
const base = path35.basename(filePath);
|
|
11481
11584
|
if (base.endsWith(".d.ts")) return ".d.ts";
|
|
11482
|
-
return
|
|
11585
|
+
return path35.extname(filePath).toLowerCase();
|
|
11483
11586
|
}
|
|
11484
11587
|
function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
11485
11588
|
const evidence = [];
|
|
@@ -11487,7 +11590,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
|
11487
11590
|
evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
|
|
11488
11591
|
const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
|
|
11489
11592
|
for (const cfg of configFiles) {
|
|
11490
|
-
if (files.some((f) =>
|
|
11593
|
+
if (files.some((f) => path35.basename(f) === cfg)) {
|
|
11491
11594
|
evidence.push(`Found ${cfg}`);
|
|
11492
11595
|
}
|
|
11493
11596
|
}
|
|
@@ -12957,8 +13060,8 @@ var init_evaluator = __esm({
|
|
|
12957
13060
|
});
|
|
12958
13061
|
async function detectLinter2(cwd) {
|
|
12959
13062
|
try {
|
|
12960
|
-
const pkgPath =
|
|
12961
|
-
const pkgContent = await
|
|
13063
|
+
const pkgPath = path35__default.join(cwd, "package.json");
|
|
13064
|
+
const pkgContent = await fs33__default.readFile(pkgPath, "utf-8");
|
|
12962
13065
|
const pkg = JSON.parse(pkgContent);
|
|
12963
13066
|
const deps = {
|
|
12964
13067
|
...pkg.dependencies,
|
|
@@ -13093,7 +13196,9 @@ Examples:
|
|
|
13093
13196
|
warnings: 0,
|
|
13094
13197
|
fixable: 0,
|
|
13095
13198
|
issues: [],
|
|
13096
|
-
score:
|
|
13199
|
+
score: null,
|
|
13200
|
+
linter: "none",
|
|
13201
|
+
message: "No linter detected (looked for: eslint, oxlint, biome). Install one or use bash_exec to run a custom linter."
|
|
13097
13202
|
};
|
|
13098
13203
|
}
|
|
13099
13204
|
try {
|
|
@@ -13173,7 +13278,7 @@ Examples:
|
|
|
13173
13278
|
let totalFunctions = 0;
|
|
13174
13279
|
let complexFunctions = 0;
|
|
13175
13280
|
for (const file of targetFiles) {
|
|
13176
|
-
const content = await
|
|
13281
|
+
const content = await fs33__default.readFile(file, "utf-8");
|
|
13177
13282
|
const fileComplexity = analyzeFileComplexity(content, file);
|
|
13178
13283
|
fileResults.push(fileComplexity);
|
|
13179
13284
|
totalComplexity += fileComplexity.complexity;
|
|
@@ -13196,8 +13301,9 @@ Examples:
|
|
|
13196
13301
|
files: fileResults
|
|
13197
13302
|
};
|
|
13198
13303
|
} catch (error) {
|
|
13304
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13199
13305
|
throw new ToolError(
|
|
13200
|
-
`Complexity analysis failed: ${
|
|
13306
|
+
`Complexity analysis failed: ${msg}. Try read_file to inspect the code manually.`,
|
|
13201
13307
|
{ tool: "analyze_complexity", cause: error instanceof Error ? error : void 0 }
|
|
13202
13308
|
);
|
|
13203
13309
|
}
|
|
@@ -13230,8 +13336,9 @@ Examples:
|
|
|
13230
13336
|
const evaluation = await evaluator.evaluate(files);
|
|
13231
13337
|
return evaluation.scores;
|
|
13232
13338
|
} catch (error) {
|
|
13339
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
13233
13340
|
throw new ToolError(
|
|
13234
|
-
`Quality calculation failed: ${
|
|
13341
|
+
`Quality calculation failed: ${msg}. Run run_linter and run_tests separately for partial results.`,
|
|
13235
13342
|
{ tool: "calculate_quality", cause: error instanceof Error ? error : void 0 }
|
|
13236
13343
|
);
|
|
13237
13344
|
}
|
|
@@ -13245,6 +13352,7 @@ function getGit(cwd) {
|
|
|
13245
13352
|
}
|
|
13246
13353
|
async function getDiff(git, baseBranch, includeUncommitted) {
|
|
13247
13354
|
const diffs = [];
|
|
13355
|
+
const warnings = [];
|
|
13248
13356
|
try {
|
|
13249
13357
|
const branchDiff = await git.diff([`${baseBranch}...HEAD`]);
|
|
13250
13358
|
if (branchDiff) diffs.push(branchDiff);
|
|
@@ -13253,6 +13361,7 @@ async function getDiff(git, baseBranch, includeUncommitted) {
|
|
|
13253
13361
|
const directDiff = await git.diff([baseBranch]);
|
|
13254
13362
|
if (directDiff) diffs.push(directDiff);
|
|
13255
13363
|
} catch {
|
|
13364
|
+
warnings.push(`Could not diff against base branch '${baseBranch}' \u2014 it may not exist.`);
|
|
13256
13365
|
}
|
|
13257
13366
|
}
|
|
13258
13367
|
if (includeUncommitted) {
|
|
@@ -13260,14 +13369,16 @@ async function getDiff(git, baseBranch, includeUncommitted) {
|
|
|
13260
13369
|
const uncommitted = await git.diff();
|
|
13261
13370
|
if (uncommitted) diffs.push(uncommitted);
|
|
13262
13371
|
} catch {
|
|
13372
|
+
warnings.push("Could not read unstaged changes.");
|
|
13263
13373
|
}
|
|
13264
13374
|
try {
|
|
13265
13375
|
const staged = await git.diff(["--staged"]);
|
|
13266
13376
|
if (staged) diffs.push(staged);
|
|
13267
13377
|
} catch {
|
|
13378
|
+
warnings.push("Could not read staged changes.");
|
|
13268
13379
|
}
|
|
13269
13380
|
}
|
|
13270
|
-
return diffs.join("\n");
|
|
13381
|
+
return { raw: diffs.join("\n"), warnings };
|
|
13271
13382
|
}
|
|
13272
13383
|
function analyzePatterns(diff) {
|
|
13273
13384
|
const findings = [];
|
|
@@ -13314,7 +13425,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
13314
13425
|
);
|
|
13315
13426
|
if (!hasTestChange) {
|
|
13316
13427
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
13317
|
-
const testExists = await fileExists2(
|
|
13428
|
+
const testExists = await fileExists2(path35__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists2(path35__default.join(cwd, `${baseName}.spec${ext}`));
|
|
13318
13429
|
if (testExists) {
|
|
13319
13430
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
13320
13431
|
findings.push({
|
|
@@ -13537,10 +13648,14 @@ Examples:
|
|
|
13537
13648
|
try {
|
|
13538
13649
|
const status = await git.status();
|
|
13539
13650
|
const currentBranch = status.current ?? "HEAD";
|
|
13540
|
-
const rawDiff = await getDiff(
|
|
13651
|
+
const { raw: rawDiff, warnings: diffWarnings } = await getDiff(
|
|
13652
|
+
git,
|
|
13653
|
+
baseBranch,
|
|
13654
|
+
includeUncommitted
|
|
13655
|
+
);
|
|
13541
13656
|
const diff = parseDiff(rawDiff);
|
|
13542
13657
|
if (diff.files.length === 0) {
|
|
13543
|
-
|
|
13658
|
+
const emptyResult = {
|
|
13544
13659
|
summary: {
|
|
13545
13660
|
branch: currentBranch,
|
|
13546
13661
|
baseBranch,
|
|
@@ -13554,6 +13669,10 @@ Examples:
|
|
|
13554
13669
|
maturity: "new",
|
|
13555
13670
|
diff
|
|
13556
13671
|
};
|
|
13672
|
+
if (diffWarnings.length > 0) {
|
|
13673
|
+
emptyResult.warnings = diffWarnings;
|
|
13674
|
+
}
|
|
13675
|
+
return emptyResult;
|
|
13557
13676
|
}
|
|
13558
13677
|
const maturityInfo = await detectMaturity(projectDir);
|
|
13559
13678
|
const maturity = maturityInfo.level;
|
|
@@ -13575,6 +13694,7 @@ Examples:
|
|
|
13575
13694
|
}
|
|
13576
13695
|
}
|
|
13577
13696
|
} catch {
|
|
13697
|
+
diffWarnings.push("Linter not available \u2014 code style was not checked.");
|
|
13578
13698
|
}
|
|
13579
13699
|
}
|
|
13580
13700
|
allFindings.push(...getMaturityRecommendations(maturity, diff));
|
|
@@ -13587,7 +13707,7 @@ Examples:
|
|
|
13587
13707
|
(f) => f.severity === "minor" || f.severity === "info"
|
|
13588
13708
|
);
|
|
13589
13709
|
const status_result = required.some((f) => f.severity === "critical") ? "needs_work" : required.length > 0 ? "needs_work" : "approved";
|
|
13590
|
-
|
|
13710
|
+
const result = {
|
|
13591
13711
|
summary: {
|
|
13592
13712
|
branch: currentBranch,
|
|
13593
13713
|
baseBranch,
|
|
@@ -13601,6 +13721,10 @@ Examples:
|
|
|
13601
13721
|
maturity,
|
|
13602
13722
|
diff
|
|
13603
13723
|
};
|
|
13724
|
+
if (diffWarnings.length > 0) {
|
|
13725
|
+
result.warnings = diffWarnings;
|
|
13726
|
+
}
|
|
13727
|
+
return result;
|
|
13604
13728
|
} catch (error) {
|
|
13605
13729
|
throw new ToolError(
|
|
13606
13730
|
`Code review failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -13891,10 +14015,16 @@ Examples:
|
|
|
13891
14015
|
rendered: true
|
|
13892
14016
|
};
|
|
13893
14017
|
} catch (error) {
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
14018
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14019
|
+
let hint = `Diff failed: ${msg}`;
|
|
14020
|
+
if (/not a git repository/i.test(msg))
|
|
14021
|
+
hint = "Not a git repository. Use list_dir to verify you're in the right directory.";
|
|
14022
|
+
else if (/unknown revision|bad revision/i.test(msg))
|
|
14023
|
+
hint = `Reference not found: ${msg}. Use git_log or git_branch to find valid refs.`;
|
|
14024
|
+
throw new ToolError(hint, {
|
|
14025
|
+
tool: "show_diff",
|
|
14026
|
+
cause: error instanceof Error ? error : void 0
|
|
14027
|
+
});
|
|
13898
14028
|
}
|
|
13899
14029
|
}
|
|
13900
14030
|
});
|
|
@@ -13968,6 +14098,27 @@ var init_diff2 = __esm({
|
|
|
13968
14098
|
};
|
|
13969
14099
|
}
|
|
13970
14100
|
});
|
|
14101
|
+
function enrichGitError(operation, error) {
|
|
14102
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
14103
|
+
if (/not a git repository/i.test(msg))
|
|
14104
|
+
return `Not a git repository. Run git_init first or verify you're in the correct directory.`;
|
|
14105
|
+
if (/nothing to commit/i.test(msg))
|
|
14106
|
+
return `Nothing to commit \u2014 working tree is clean. Use git_status to verify your changes were saved.`;
|
|
14107
|
+
if (/CONFLICT|merge conflict/i.test(msg))
|
|
14108
|
+
return `Merge conflict detected. Use read_file to see the conflicting file, resolve manually with edit_file, then git_add and git_commit.`;
|
|
14109
|
+
if (/non-fast-forward|\[rejected\]/i.test(msg))
|
|
14110
|
+
return `Push rejected \u2014 remote has new commits. Run git_pull first, resolve any conflicts, then retry git_push.`;
|
|
14111
|
+
if (/authentication failed/i.test(msg))
|
|
14112
|
+
return `Git authentication failed. Check your credentials, SSH key, or access token.`;
|
|
14113
|
+
if (/branch.*already exists/i.test(msg))
|
|
14114
|
+
return `Branch already exists. Use git_checkout to switch to it, or choose a different name.`;
|
|
14115
|
+
if (/does not exist|unknown revision|bad revision/i.test(msg))
|
|
14116
|
+
return `Git reference not found. Use git_branch to list available branches, or git_log to find the correct commit.`;
|
|
14117
|
+
if (/pathspec.*did not match/i.test(msg))
|
|
14118
|
+
return `File not tracked by git. Use glob to verify the file exists, then git_add it first.`;
|
|
14119
|
+
if (/already up to date/i.test(msg)) return `Already up to date \u2014 no changes to pull.`;
|
|
14120
|
+
return `Git ${operation} failed: ${msg}`;
|
|
14121
|
+
}
|
|
13971
14122
|
function getGit3(cwd) {
|
|
13972
14123
|
const baseDir = cwd ?? process.cwd();
|
|
13973
14124
|
return simpleGit({ baseDir });
|
|
@@ -14004,10 +14155,10 @@ Examples:
|
|
|
14004
14155
|
isClean: status.isClean()
|
|
14005
14156
|
};
|
|
14006
14157
|
} catch (error) {
|
|
14007
|
-
throw new ToolError(
|
|
14008
|
-
|
|
14009
|
-
|
|
14010
|
-
);
|
|
14158
|
+
throw new ToolError(enrichGitError("status", error), {
|
|
14159
|
+
tool: "git_status",
|
|
14160
|
+
cause: error instanceof Error ? error : void 0
|
|
14161
|
+
});
|
|
14011
14162
|
}
|
|
14012
14163
|
}
|
|
14013
14164
|
});
|
|
@@ -14041,10 +14192,10 @@ Examples:
|
|
|
14041
14192
|
deletions: diffStat.deletions
|
|
14042
14193
|
};
|
|
14043
14194
|
} catch (error) {
|
|
14044
|
-
throw new ToolError(
|
|
14045
|
-
|
|
14046
|
-
|
|
14047
|
-
);
|
|
14195
|
+
throw new ToolError(enrichGitError("diff", error), {
|
|
14196
|
+
tool: "git_diff",
|
|
14197
|
+
cause: error instanceof Error ? error : void 0
|
|
14198
|
+
});
|
|
14048
14199
|
}
|
|
14049
14200
|
}
|
|
14050
14201
|
});
|
|
@@ -14067,10 +14218,10 @@ Examples:
|
|
|
14067
14218
|
await git.add(files);
|
|
14068
14219
|
return { added: files };
|
|
14069
14220
|
} catch (error) {
|
|
14070
|
-
throw new ToolError(
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
);
|
|
14221
|
+
throw new ToolError(enrichGitError("add", error), {
|
|
14222
|
+
tool: "git_add",
|
|
14223
|
+
cause: error instanceof Error ? error : void 0
|
|
14224
|
+
});
|
|
14074
14225
|
}
|
|
14075
14226
|
}
|
|
14076
14227
|
});
|
|
@@ -14100,10 +14251,10 @@ Examples:
|
|
|
14100
14251
|
summary: result.summary.changes ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "No changes"
|
|
14101
14252
|
};
|
|
14102
14253
|
} catch (error) {
|
|
14103
|
-
throw new ToolError(
|
|
14104
|
-
|
|
14105
|
-
|
|
14106
|
-
);
|
|
14254
|
+
throw new ToolError(enrichGitError("commit", error), {
|
|
14255
|
+
tool: "git_commit",
|
|
14256
|
+
cause: error instanceof Error ? error : void 0
|
|
14257
|
+
});
|
|
14107
14258
|
}
|
|
14108
14259
|
}
|
|
14109
14260
|
});
|
|
@@ -14140,10 +14291,10 @@ Examples:
|
|
|
14140
14291
|
}))
|
|
14141
14292
|
};
|
|
14142
14293
|
} catch (error) {
|
|
14143
|
-
throw new ToolError(
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
);
|
|
14294
|
+
throw new ToolError(enrichGitError("log", error), {
|
|
14295
|
+
tool: "git_log",
|
|
14296
|
+
cause: error instanceof Error ? error : void 0
|
|
14297
|
+
});
|
|
14147
14298
|
}
|
|
14148
14299
|
}
|
|
14149
14300
|
});
|
|
@@ -14184,10 +14335,10 @@ Examples:
|
|
|
14184
14335
|
current: status.current ?? "HEAD"
|
|
14185
14336
|
};
|
|
14186
14337
|
} catch (error) {
|
|
14187
|
-
throw new ToolError(
|
|
14188
|
-
|
|
14189
|
-
|
|
14190
|
-
);
|
|
14338
|
+
throw new ToolError(enrichGitError("branch", error), {
|
|
14339
|
+
tool: "git_branch",
|
|
14340
|
+
cause: error instanceof Error ? error : void 0
|
|
14341
|
+
});
|
|
14191
14342
|
}
|
|
14192
14343
|
}
|
|
14193
14344
|
});
|
|
@@ -14214,10 +14365,10 @@ Examples:
|
|
|
14214
14365
|
}
|
|
14215
14366
|
return { branch };
|
|
14216
14367
|
} catch (error) {
|
|
14217
|
-
throw new ToolError(
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
);
|
|
14368
|
+
throw new ToolError(enrichGitError("checkout", error), {
|
|
14369
|
+
tool: "git_checkout",
|
|
14370
|
+
cause: error instanceof Error ? error : void 0
|
|
14371
|
+
});
|
|
14221
14372
|
}
|
|
14222
14373
|
}
|
|
14223
14374
|
});
|
|
@@ -14252,10 +14403,10 @@ Examples:
|
|
|
14252
14403
|
branch: pushBranch
|
|
14253
14404
|
};
|
|
14254
14405
|
} catch (error) {
|
|
14255
|
-
throw new ToolError(
|
|
14256
|
-
|
|
14257
|
-
|
|
14258
|
-
);
|
|
14406
|
+
throw new ToolError(enrichGitError("push", error), {
|
|
14407
|
+
tool: "git_push",
|
|
14408
|
+
cause: error instanceof Error ? error : void 0
|
|
14409
|
+
});
|
|
14259
14410
|
}
|
|
14260
14411
|
}
|
|
14261
14412
|
});
|
|
@@ -14287,10 +14438,10 @@ Examples:
|
|
|
14287
14438
|
summary: result.summary ? `${result.summary.insertions} insertions, ${result.summary.deletions} deletions` : "Already up to date"
|
|
14288
14439
|
};
|
|
14289
14440
|
} catch (error) {
|
|
14290
|
-
throw new ToolError(
|
|
14291
|
-
|
|
14292
|
-
|
|
14293
|
-
);
|
|
14441
|
+
throw new ToolError(enrichGitError("pull", error), {
|
|
14442
|
+
tool: "git_pull",
|
|
14443
|
+
cause: error instanceof Error ? error : void 0
|
|
14444
|
+
});
|
|
14294
14445
|
}
|
|
14295
14446
|
}
|
|
14296
14447
|
});
|
|
@@ -14316,10 +14467,10 @@ Examples:
|
|
|
14316
14467
|
path: cwd ?? process.cwd()
|
|
14317
14468
|
};
|
|
14318
14469
|
} catch (error) {
|
|
14319
|
-
throw new ToolError(
|
|
14320
|
-
|
|
14321
|
-
|
|
14322
|
-
);
|
|
14470
|
+
throw new ToolError(enrichGitError("init", error), {
|
|
14471
|
+
tool: "git_init",
|
|
14472
|
+
cause: error instanceof Error ? error : void 0
|
|
14473
|
+
});
|
|
14323
14474
|
}
|
|
14324
14475
|
}
|
|
14325
14476
|
});
|
|
@@ -14449,40 +14600,24 @@ var init_bash = __esm({
|
|
|
14449
14600
|
DEFAULT_TIMEOUT_MS = 12e4;
|
|
14450
14601
|
MAX_OUTPUT_SIZE = 1024 * 1024;
|
|
14451
14602
|
DANGEROUS_PATTERNS_FULL = [
|
|
14452
|
-
/\brm\s+-rf\s+\/(?!\w)/,
|
|
14453
|
-
|
|
14454
|
-
/\
|
|
14455
|
-
|
|
14456
|
-
/\
|
|
14457
|
-
|
|
14458
|
-
|
|
14459
|
-
|
|
14460
|
-
/\
|
|
14461
|
-
|
|
14462
|
-
/\
|
|
14463
|
-
|
|
14464
|
-
/>\s*\/etc\//,
|
|
14465
|
-
// Write to /etc
|
|
14466
|
-
/>\s*\/root\//,
|
|
14467
|
-
// Write to /root
|
|
14468
|
-
/\bchmod\s+777/,
|
|
14469
|
-
// Overly permissive chmod
|
|
14470
|
-
/\bchown\s+root/,
|
|
14471
|
-
// chown to root
|
|
14472
|
-
/\bcurl\s+.*\|\s*(ba)?sh/,
|
|
14473
|
-
// curl | sh pattern
|
|
14474
|
-
/\bwget\s+.*\|\s*(ba)?sh/
|
|
14475
|
-
// wget | sh pattern
|
|
14603
|
+
{ pattern: /\brm\s+-rf\s+\/(?!\w)/, rule: "rm -rf on root filesystem" },
|
|
14604
|
+
{ pattern: /\bsudo\s+rm\s+-rf/, rule: "sudo rm -rf (destructive with elevated privileges)" },
|
|
14605
|
+
{ pattern: /\b:?\(\)\s*\{.*\}/, rule: "fork bomb pattern" },
|
|
14606
|
+
{ pattern: /\bdd\s+if=.*of=\/dev\//, rule: "dd write to device" },
|
|
14607
|
+
{ pattern: /\bmkfs\./, rule: "filesystem format command" },
|
|
14608
|
+
{ pattern: /\bformat\s+/, rule: "format command" },
|
|
14609
|
+
{ pattern: />\s*\/etc\//, rule: "write redirect to /etc/" },
|
|
14610
|
+
{ pattern: />\s*\/root\//, rule: "write redirect to /root/" },
|
|
14611
|
+
{ pattern: /\bchmod\s+777/, rule: "overly permissive chmod 777" },
|
|
14612
|
+
{ pattern: /\bchown\s+root/, rule: "chown to root" },
|
|
14613
|
+
{ pattern: /\bcurl\s+.*\|\s*(ba)?sh/, rule: "curl pipe to shell (untrusted code execution)" },
|
|
14614
|
+
{ pattern: /\bwget\s+.*\|\s*(ba)?sh/, rule: "wget pipe to shell (untrusted code execution)" }
|
|
14476
14615
|
];
|
|
14477
14616
|
DANGEROUS_PATTERNS_SHELL_ONLY = [
|
|
14478
|
-
/`[^`]+`/,
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
|
|
14482
|
-
/\beval\s+/,
|
|
14483
|
-
// eval command (shell eval, not JS eval())
|
|
14484
|
-
/\bsource\s+/
|
|
14485
|
-
// source command (can execute arbitrary scripts)
|
|
14617
|
+
{ pattern: /`[^`]+`/, rule: "backtick command substitution" },
|
|
14618
|
+
{ pattern: /\$\([^)]+\)/, rule: "$() command substitution" },
|
|
14619
|
+
{ pattern: /\beval\s+/, rule: "eval command (arbitrary code execution)" },
|
|
14620
|
+
{ pattern: /\bsource\s+/, rule: "source command (can execute arbitrary scripts)" }
|
|
14486
14621
|
];
|
|
14487
14622
|
SAFE_ENV_VARS = /* @__PURE__ */ new Set([
|
|
14488
14623
|
// System info (non-sensitive)
|
|
@@ -14551,18 +14686,20 @@ Examples:
|
|
|
14551
14686
|
}),
|
|
14552
14687
|
async execute({ command, cwd, timeout, env: env2 }) {
|
|
14553
14688
|
const shellPart = getShellCommandPart(command);
|
|
14554
|
-
for (const pattern of DANGEROUS_PATTERNS_FULL) {
|
|
14689
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
|
|
14555
14690
|
if (pattern.test(command)) {
|
|
14556
|
-
throw new ToolError(
|
|
14557
|
-
|
|
14558
|
-
|
|
14691
|
+
throw new ToolError(
|
|
14692
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14693
|
+
{ tool: "bash_exec" }
|
|
14694
|
+
);
|
|
14559
14695
|
}
|
|
14560
14696
|
}
|
|
14561
|
-
for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14697
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14562
14698
|
if (pattern.test(shellPart)) {
|
|
14563
|
-
throw new ToolError(
|
|
14564
|
-
|
|
14565
|
-
|
|
14699
|
+
throw new ToolError(
|
|
14700
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14701
|
+
{ tool: "bash_exec" }
|
|
14702
|
+
);
|
|
14566
14703
|
}
|
|
14567
14704
|
}
|
|
14568
14705
|
const startTime = performance.now();
|
|
@@ -14647,18 +14784,20 @@ Examples:
|
|
|
14647
14784
|
}),
|
|
14648
14785
|
async execute({ command, cwd, env: env2 }) {
|
|
14649
14786
|
const shellPart = getShellCommandPart(command);
|
|
14650
|
-
for (const pattern of DANGEROUS_PATTERNS_FULL) {
|
|
14787
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_FULL) {
|
|
14651
14788
|
if (pattern.test(command)) {
|
|
14652
|
-
throw new ToolError(
|
|
14653
|
-
|
|
14654
|
-
|
|
14789
|
+
throw new ToolError(
|
|
14790
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14791
|
+
{ tool: "bash_background" }
|
|
14792
|
+
);
|
|
14655
14793
|
}
|
|
14656
14794
|
}
|
|
14657
|
-
for (const pattern of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14795
|
+
for (const { pattern, rule } of DANGEROUS_PATTERNS_SHELL_ONLY) {
|
|
14658
14796
|
if (pattern.test(shellPart)) {
|
|
14659
|
-
throw new ToolError(
|
|
14660
|
-
|
|
14661
|
-
|
|
14797
|
+
throw new ToolError(
|
|
14798
|
+
`Command blocked by safety rule: "${rule}". Rewrite the command to avoid this pattern, or use a safer alternative.`,
|
|
14799
|
+
{ tool: "bash_background" }
|
|
14800
|
+
);
|
|
14662
14801
|
}
|
|
14663
14802
|
}
|
|
14664
14803
|
try {
|
|
@@ -14941,7 +15080,7 @@ var init_github = __esm({
|
|
|
14941
15080
|
});
|
|
14942
15081
|
async function detectVersionFile(cwd) {
|
|
14943
15082
|
for (const { file, stack, field } of VERSION_FILES) {
|
|
14944
|
-
const fullPath =
|
|
15083
|
+
const fullPath = path35__default.join(cwd, file);
|
|
14945
15084
|
if (await fileExists2(fullPath)) {
|
|
14946
15085
|
const version = await readVersionFromFile(fullPath, stack, field);
|
|
14947
15086
|
if (version) {
|
|
@@ -14987,7 +15126,7 @@ function bumpVersion(current, bump) {
|
|
|
14987
15126
|
}
|
|
14988
15127
|
}
|
|
14989
15128
|
async function writeVersion(cwd, versionFile, newVersion) {
|
|
14990
|
-
const fullPath =
|
|
15129
|
+
const fullPath = path35__default.join(cwd, versionFile.path);
|
|
14991
15130
|
const content = await readFile(fullPath, "utf-8");
|
|
14992
15131
|
let updated;
|
|
14993
15132
|
switch (versionFile.stack) {
|
|
@@ -15046,7 +15185,7 @@ var init_version_detector = __esm({
|
|
|
15046
15185
|
});
|
|
15047
15186
|
async function detectChangelog(cwd) {
|
|
15048
15187
|
for (const name of CHANGELOG_NAMES) {
|
|
15049
|
-
const fullPath =
|
|
15188
|
+
const fullPath = path35__default.join(cwd, name);
|
|
15050
15189
|
if (await fileExists2(fullPath)) {
|
|
15051
15190
|
const content = await readFile(fullPath, "utf-8");
|
|
15052
15191
|
const format = detectFormat(content);
|
|
@@ -15068,7 +15207,7 @@ function detectFormat(content) {
|
|
|
15068
15207
|
return "custom";
|
|
15069
15208
|
}
|
|
15070
15209
|
async function insertChangelogEntry(cwd, changelog, version, entries, date) {
|
|
15071
|
-
const fullPath =
|
|
15210
|
+
const fullPath = path35__default.join(cwd, changelog.path);
|
|
15072
15211
|
const content = await readFile(fullPath, "utf-8");
|
|
15073
15212
|
const dateStr = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
15074
15213
|
const entry = buildEntry(changelog.format, version, entries, dateStr);
|
|
@@ -15129,11 +15268,11 @@ var init_changelog = __esm({
|
|
|
15129
15268
|
}
|
|
15130
15269
|
});
|
|
15131
15270
|
async function detectStack(cwd) {
|
|
15132
|
-
if (await fileExists2(
|
|
15133
|
-
if (await fileExists2(
|
|
15134
|
-
if (await fileExists2(
|
|
15135
|
-
if (await fileExists2(
|
|
15136
|
-
if (await fileExists2(
|
|
15271
|
+
if (await fileExists2(path35__default.join(cwd, "package.json"))) return "node";
|
|
15272
|
+
if (await fileExists2(path35__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
15273
|
+
if (await fileExists2(path35__default.join(cwd, "pyproject.toml"))) return "python";
|
|
15274
|
+
if (await fileExists2(path35__default.join(cwd, "go.mod"))) return "go";
|
|
15275
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) return "java";
|
|
15137
15276
|
return "unknown";
|
|
15138
15277
|
}
|
|
15139
15278
|
async function detectPackageManager(cwd, stack) {
|
|
@@ -15141,15 +15280,15 @@ async function detectPackageManager(cwd, stack) {
|
|
|
15141
15280
|
if (stack === "python") return "pip";
|
|
15142
15281
|
if (stack === "go") return "go";
|
|
15143
15282
|
if (stack === "node") {
|
|
15144
|
-
if (await fileExists2(
|
|
15145
|
-
if (await fileExists2(
|
|
15146
|
-
if (await fileExists2(
|
|
15283
|
+
if (await fileExists2(path35__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
15284
|
+
if (await fileExists2(path35__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
15285
|
+
if (await fileExists2(path35__default.join(cwd, "bun.lockb"))) return "bun";
|
|
15147
15286
|
return "npm";
|
|
15148
15287
|
}
|
|
15149
15288
|
return null;
|
|
15150
15289
|
}
|
|
15151
15290
|
async function detectCI(cwd) {
|
|
15152
|
-
const ghDir =
|
|
15291
|
+
const ghDir = path35__default.join(cwd, ".github", "workflows");
|
|
15153
15292
|
if (await fileExists2(ghDir)) {
|
|
15154
15293
|
let workflowFiles = [];
|
|
15155
15294
|
let hasCodeQL = false;
|
|
@@ -15173,7 +15312,7 @@ async function detectCI(cwd) {
|
|
|
15173
15312
|
}
|
|
15174
15313
|
return { type: "github-actions", workflowFiles, hasCodeQL, hasLinting };
|
|
15175
15314
|
}
|
|
15176
|
-
if (await fileExists2(
|
|
15315
|
+
if (await fileExists2(path35__default.join(cwd, ".gitlab-ci.yml"))) {
|
|
15177
15316
|
return {
|
|
15178
15317
|
type: "gitlab-ci",
|
|
15179
15318
|
workflowFiles: [".gitlab-ci.yml"],
|
|
@@ -15181,7 +15320,7 @@ async function detectCI(cwd) {
|
|
|
15181
15320
|
hasLinting: false
|
|
15182
15321
|
};
|
|
15183
15322
|
}
|
|
15184
|
-
if (await fileExists2(
|
|
15323
|
+
if (await fileExists2(path35__default.join(cwd, ".circleci"))) {
|
|
15185
15324
|
return { type: "circle-ci", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
15186
15325
|
}
|
|
15187
15326
|
return { type: "none", workflowFiles: [], hasCodeQL: false, hasLinting: false };
|
|
@@ -16552,8 +16691,8 @@ function hasNullByte(str) {
|
|
|
16552
16691
|
}
|
|
16553
16692
|
function isBlockedPath(absolute) {
|
|
16554
16693
|
for (const blocked of BLOCKED_PATHS) {
|
|
16555
|
-
const normalizedBlocked =
|
|
16556
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
16694
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
16695
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
16557
16696
|
return blocked;
|
|
16558
16697
|
}
|
|
16559
16698
|
}
|
|
@@ -16571,7 +16710,7 @@ function getInterpreter(ext) {
|
|
|
16571
16710
|
}
|
|
16572
16711
|
async function isExecutable(filePath) {
|
|
16573
16712
|
try {
|
|
16574
|
-
await
|
|
16713
|
+
await fs33__default.access(filePath, fs33__default.constants.X_OK);
|
|
16575
16714
|
return true;
|
|
16576
16715
|
} catch {
|
|
16577
16716
|
return false;
|
|
@@ -16647,7 +16786,7 @@ Examples:
|
|
|
16647
16786
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
16648
16787
|
}
|
|
16649
16788
|
const workDir = cwd ?? process.cwd();
|
|
16650
|
-
const absolute =
|
|
16789
|
+
const absolute = path35__default.isAbsolute(filePath) ? path35__default.normalize(filePath) : path35__default.resolve(workDir, filePath);
|
|
16651
16790
|
const blockedBy = isBlockedPath(absolute);
|
|
16652
16791
|
if (blockedBy) {
|
|
16653
16792
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -16655,7 +16794,7 @@ Examples:
|
|
|
16655
16794
|
});
|
|
16656
16795
|
}
|
|
16657
16796
|
try {
|
|
16658
|
-
await
|
|
16797
|
+
await fs33__default.access(absolute);
|
|
16659
16798
|
} catch {
|
|
16660
16799
|
throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
|
|
16661
16800
|
}
|
|
@@ -16670,14 +16809,14 @@ Examples:
|
|
|
16670
16809
|
};
|
|
16671
16810
|
}
|
|
16672
16811
|
if (isBlockedExecFile(absolute)) {
|
|
16673
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
16812
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path35__default.basename(absolute)}`, {
|
|
16674
16813
|
tool: "open_file"
|
|
16675
16814
|
});
|
|
16676
16815
|
}
|
|
16677
16816
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
16678
16817
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
16679
16818
|
}
|
|
16680
|
-
const ext =
|
|
16819
|
+
const ext = path35__default.extname(absolute);
|
|
16681
16820
|
const interpreter = getInterpreter(ext);
|
|
16682
16821
|
const executable = await isExecutable(absolute);
|
|
16683
16822
|
let command;
|
|
@@ -16690,7 +16829,7 @@ Examples:
|
|
|
16690
16829
|
cmdArgs = [...args];
|
|
16691
16830
|
} else {
|
|
16692
16831
|
throw new ToolError(
|
|
16693
|
-
`Cannot execute '${
|
|
16832
|
+
`Cannot execute '${path35__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
16694
16833
|
{ tool: "open_file" }
|
|
16695
16834
|
);
|
|
16696
16835
|
}
|
|
@@ -16862,10 +17001,10 @@ function getAllowedPaths() {
|
|
|
16862
17001
|
return [...sessionAllowedPaths];
|
|
16863
17002
|
}
|
|
16864
17003
|
function isWithinAllowedPath(absolutePath, operation) {
|
|
16865
|
-
const normalizedTarget =
|
|
17004
|
+
const normalizedTarget = path35__default.normalize(absolutePath);
|
|
16866
17005
|
for (const entry of sessionAllowedPaths) {
|
|
16867
|
-
const normalizedAllowed =
|
|
16868
|
-
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed +
|
|
17006
|
+
const normalizedAllowed = path35__default.normalize(entry.path);
|
|
17007
|
+
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path35__default.sep)) {
|
|
16869
17008
|
if (operation === "read") return true;
|
|
16870
17009
|
if (entry.level === "write") return true;
|
|
16871
17010
|
}
|
|
@@ -16873,8 +17012,8 @@ function isWithinAllowedPath(absolutePath, operation) {
|
|
|
16873
17012
|
return false;
|
|
16874
17013
|
}
|
|
16875
17014
|
function addAllowedPathToSession(dirPath, level) {
|
|
16876
|
-
const absolute =
|
|
16877
|
-
if (sessionAllowedPaths.some((e) =>
|
|
17015
|
+
const absolute = path35__default.resolve(dirPath);
|
|
17016
|
+
if (sessionAllowedPaths.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
16878
17017
|
return;
|
|
16879
17018
|
}
|
|
16880
17019
|
sessionAllowedPaths.push({
|
|
@@ -16884,14 +17023,14 @@ function addAllowedPathToSession(dirPath, level) {
|
|
|
16884
17023
|
});
|
|
16885
17024
|
}
|
|
16886
17025
|
function removeAllowedPathFromSession(dirPath) {
|
|
16887
|
-
const absolute =
|
|
16888
|
-
const normalized =
|
|
17026
|
+
const absolute = path35__default.resolve(dirPath);
|
|
17027
|
+
const normalized = path35__default.normalize(absolute);
|
|
16889
17028
|
const before = sessionAllowedPaths.length;
|
|
16890
|
-
sessionAllowedPaths = sessionAllowedPaths.filter((e) =>
|
|
17029
|
+
sessionAllowedPaths = sessionAllowedPaths.filter((e) => path35__default.normalize(e.path) !== normalized);
|
|
16891
17030
|
return sessionAllowedPaths.length < before;
|
|
16892
17031
|
}
|
|
16893
17032
|
async function loadAllowedPaths(projectPath) {
|
|
16894
|
-
currentProjectPath =
|
|
17033
|
+
currentProjectPath = path35__default.resolve(projectPath);
|
|
16895
17034
|
const store = await loadStore();
|
|
16896
17035
|
const entries = store.projects[currentProjectPath] ?? [];
|
|
16897
17036
|
for (const entry of entries) {
|
|
@@ -16900,14 +17039,14 @@ async function loadAllowedPaths(projectPath) {
|
|
|
16900
17039
|
}
|
|
16901
17040
|
async function persistAllowedPath(dirPath, level) {
|
|
16902
17041
|
if (!currentProjectPath) return;
|
|
16903
|
-
const absolute =
|
|
17042
|
+
const absolute = path35__default.resolve(dirPath);
|
|
16904
17043
|
const store = await loadStore();
|
|
16905
17044
|
if (!store.projects[currentProjectPath]) {
|
|
16906
17045
|
store.projects[currentProjectPath] = [];
|
|
16907
17046
|
}
|
|
16908
17047
|
const entries = store.projects[currentProjectPath];
|
|
16909
|
-
const normalized =
|
|
16910
|
-
if (entries.some((e) =>
|
|
17048
|
+
const normalized = path35__default.normalize(absolute);
|
|
17049
|
+
if (entries.some((e) => path35__default.normalize(e.path) === normalized)) {
|
|
16911
17050
|
return;
|
|
16912
17051
|
}
|
|
16913
17052
|
entries.push({
|
|
@@ -16919,13 +17058,13 @@ async function persistAllowedPath(dirPath, level) {
|
|
|
16919
17058
|
}
|
|
16920
17059
|
async function removePersistedAllowedPath(dirPath) {
|
|
16921
17060
|
if (!currentProjectPath) return false;
|
|
16922
|
-
const absolute =
|
|
16923
|
-
const normalized =
|
|
17061
|
+
const absolute = path35__default.resolve(dirPath);
|
|
17062
|
+
const normalized = path35__default.normalize(absolute);
|
|
16924
17063
|
const store = await loadStore();
|
|
16925
17064
|
const entries = store.projects[currentProjectPath];
|
|
16926
17065
|
if (!entries) return false;
|
|
16927
17066
|
const before = entries.length;
|
|
16928
|
-
store.projects[currentProjectPath] = entries.filter((e) =>
|
|
17067
|
+
store.projects[currentProjectPath] = entries.filter((e) => path35__default.normalize(e.path) !== normalized);
|
|
16929
17068
|
if (store.projects[currentProjectPath].length < before) {
|
|
16930
17069
|
await saveStore(store);
|
|
16931
17070
|
return true;
|
|
@@ -16934,7 +17073,7 @@ async function removePersistedAllowedPath(dirPath) {
|
|
|
16934
17073
|
}
|
|
16935
17074
|
async function loadStore() {
|
|
16936
17075
|
try {
|
|
16937
|
-
const content = await
|
|
17076
|
+
const content = await fs33__default.readFile(STORE_FILE, "utf-8");
|
|
16938
17077
|
return { ...DEFAULT_STORE, ...JSON.parse(content) };
|
|
16939
17078
|
} catch {
|
|
16940
17079
|
return { ...DEFAULT_STORE };
|
|
@@ -16942,8 +17081,8 @@ async function loadStore() {
|
|
|
16942
17081
|
}
|
|
16943
17082
|
async function saveStore(store) {
|
|
16944
17083
|
try {
|
|
16945
|
-
await
|
|
16946
|
-
await
|
|
17084
|
+
await fs33__default.mkdir(path35__default.dirname(STORE_FILE), { recursive: true });
|
|
17085
|
+
await fs33__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
16947
17086
|
} catch {
|
|
16948
17087
|
}
|
|
16949
17088
|
}
|
|
@@ -16951,7 +17090,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
|
|
|
16951
17090
|
var init_allowed_paths = __esm({
|
|
16952
17091
|
"src/tools/allowed-paths.ts"() {
|
|
16953
17092
|
init_paths();
|
|
16954
|
-
STORE_FILE =
|
|
17093
|
+
STORE_FILE = path35__default.join(CONFIG_PATHS.home, "allowed-paths.json");
|
|
16955
17094
|
DEFAULT_STORE = {
|
|
16956
17095
|
version: 1,
|
|
16957
17096
|
projects: {}
|
|
@@ -17007,7 +17146,7 @@ function shouldAutoApprove(command, cwd) {
|
|
|
17007
17146
|
}
|
|
17008
17147
|
async function loadFullAccessPreference() {
|
|
17009
17148
|
try {
|
|
17010
|
-
const content = await
|
|
17149
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
17011
17150
|
const config = JSON.parse(content);
|
|
17012
17151
|
if (typeof config.fullAccessMode === "boolean") {
|
|
17013
17152
|
fullAccessEnabled = config.fullAccessMode;
|
|
@@ -17021,12 +17160,12 @@ async function saveFullAccessPreference(enabled) {
|
|
|
17021
17160
|
try {
|
|
17022
17161
|
let config = {};
|
|
17023
17162
|
try {
|
|
17024
|
-
const content = await
|
|
17163
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
17025
17164
|
config = JSON.parse(content);
|
|
17026
17165
|
} catch {
|
|
17027
17166
|
}
|
|
17028
17167
|
config.fullAccessMode = enabled;
|
|
17029
|
-
await
|
|
17168
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
17030
17169
|
} catch {
|
|
17031
17170
|
}
|
|
17032
17171
|
}
|
|
@@ -18142,7 +18281,7 @@ function shouldFullPowerApprove(command) {
|
|
|
18142
18281
|
}
|
|
18143
18282
|
async function loadFullPowerRiskPreference() {
|
|
18144
18283
|
try {
|
|
18145
|
-
const content = await
|
|
18284
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
18146
18285
|
const config = JSON.parse(content);
|
|
18147
18286
|
if (typeof config.fullPowerRiskMode === "boolean") {
|
|
18148
18287
|
fullPowerRiskEnabled = config.fullPowerRiskMode;
|
|
@@ -18156,12 +18295,12 @@ async function saveFullPowerRiskPreference(enabled) {
|
|
|
18156
18295
|
try {
|
|
18157
18296
|
let config = {};
|
|
18158
18297
|
try {
|
|
18159
|
-
const content = await
|
|
18298
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
18160
18299
|
config = JSON.parse(content);
|
|
18161
18300
|
} catch {
|
|
18162
18301
|
}
|
|
18163
18302
|
config.fullPowerRiskMode = enabled;
|
|
18164
|
-
await
|
|
18303
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
18165
18304
|
} catch {
|
|
18166
18305
|
}
|
|
18167
18306
|
}
|
|
@@ -18213,7 +18352,7 @@ __export(allow_path_prompt_exports, {
|
|
|
18213
18352
|
promptAllowPath: () => promptAllowPath
|
|
18214
18353
|
});
|
|
18215
18354
|
async function promptAllowPath(dirPath) {
|
|
18216
|
-
const absolute =
|
|
18355
|
+
const absolute = path35__default.resolve(dirPath);
|
|
18217
18356
|
console.log();
|
|
18218
18357
|
console.log(chalk25.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
18219
18358
|
console.log(chalk25.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -18448,13 +18587,13 @@ __export(stack_detector_exports, {
|
|
|
18448
18587
|
detectProjectStack: () => detectProjectStack
|
|
18449
18588
|
});
|
|
18450
18589
|
async function detectStack2(cwd) {
|
|
18451
|
-
if (await fileExists2(
|
|
18452
|
-
if (await fileExists2(
|
|
18453
|
-
if (await fileExists2(
|
|
18454
|
-
if (await fileExists2(
|
|
18455
|
-
if (await fileExists2(
|
|
18456
|
-
if (await fileExists2(
|
|
18457
|
-
if (await fileExists2(
|
|
18590
|
+
if (await fileExists2(path35__default.join(cwd, "package.json"))) return "node";
|
|
18591
|
+
if (await fileExists2(path35__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
18592
|
+
if (await fileExists2(path35__default.join(cwd, "pyproject.toml"))) return "python";
|
|
18593
|
+
if (await fileExists2(path35__default.join(cwd, "go.mod"))) return "go";
|
|
18594
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) return "java";
|
|
18595
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle"))) return "java";
|
|
18596
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
18458
18597
|
return "unknown";
|
|
18459
18598
|
}
|
|
18460
18599
|
async function detectPackageManager3(cwd, stack) {
|
|
@@ -18462,25 +18601,25 @@ async function detectPackageManager3(cwd, stack) {
|
|
|
18462
18601
|
if (stack === "python") return "pip";
|
|
18463
18602
|
if (stack === "go") return "go";
|
|
18464
18603
|
if (stack === "java") {
|
|
18465
|
-
if (await fileExists2(
|
|
18604
|
+
if (await fileExists2(path35__default.join(cwd, "build.gradle")) || await fileExists2(path35__default.join(cwd, "build.gradle.kts"))) {
|
|
18466
18605
|
return "gradle";
|
|
18467
18606
|
}
|
|
18468
|
-
if (await fileExists2(
|
|
18607
|
+
if (await fileExists2(path35__default.join(cwd, "pom.xml"))) {
|
|
18469
18608
|
return "maven";
|
|
18470
18609
|
}
|
|
18471
18610
|
}
|
|
18472
18611
|
if (stack === "node") {
|
|
18473
|
-
if (await fileExists2(
|
|
18474
|
-
if (await fileExists2(
|
|
18475
|
-
if (await fileExists2(
|
|
18612
|
+
if (await fileExists2(path35__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
18613
|
+
if (await fileExists2(path35__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
18614
|
+
if (await fileExists2(path35__default.join(cwd, "bun.lockb"))) return "bun";
|
|
18476
18615
|
return "npm";
|
|
18477
18616
|
}
|
|
18478
18617
|
return null;
|
|
18479
18618
|
}
|
|
18480
18619
|
async function parsePackageJson(cwd) {
|
|
18481
|
-
const packageJsonPath =
|
|
18620
|
+
const packageJsonPath = path35__default.join(cwd, "package.json");
|
|
18482
18621
|
try {
|
|
18483
|
-
const content = await
|
|
18622
|
+
const content = await fs33__default.readFile(packageJsonPath, "utf-8");
|
|
18484
18623
|
const pkg = JSON.parse(content);
|
|
18485
18624
|
const allDeps = {
|
|
18486
18625
|
...pkg.dependencies,
|
|
@@ -18510,7 +18649,7 @@ async function parsePackageJson(cwd) {
|
|
|
18510
18649
|
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
18511
18650
|
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
18512
18651
|
const languages = ["JavaScript"];
|
|
18513
|
-
if (allDeps.typescript || await fileExists2(
|
|
18652
|
+
if (allDeps.typescript || await fileExists2(path35__default.join(cwd, "tsconfig.json"))) {
|
|
18514
18653
|
languages.push("TypeScript");
|
|
18515
18654
|
}
|
|
18516
18655
|
return {
|
|
@@ -18531,9 +18670,9 @@ async function parsePackageJson(cwd) {
|
|
|
18531
18670
|
}
|
|
18532
18671
|
}
|
|
18533
18672
|
async function parsePomXml(cwd) {
|
|
18534
|
-
const pomPath =
|
|
18673
|
+
const pomPath = path35__default.join(cwd, "pom.xml");
|
|
18535
18674
|
try {
|
|
18536
|
-
const content = await
|
|
18675
|
+
const content = await fs33__default.readFile(pomPath, "utf-8");
|
|
18537
18676
|
const dependencies = {};
|
|
18538
18677
|
const frameworks = [];
|
|
18539
18678
|
const buildTools2 = ["maven"];
|
|
@@ -18568,9 +18707,9 @@ async function parsePomXml(cwd) {
|
|
|
18568
18707
|
}
|
|
18569
18708
|
}
|
|
18570
18709
|
async function parsePyprojectToml(cwd) {
|
|
18571
|
-
const pyprojectPath =
|
|
18710
|
+
const pyprojectPath = path35__default.join(cwd, "pyproject.toml");
|
|
18572
18711
|
try {
|
|
18573
|
-
const content = await
|
|
18712
|
+
const content = await fs33__default.readFile(pyprojectPath, "utf-8");
|
|
18574
18713
|
const dependencies = {};
|
|
18575
18714
|
const frameworks = [];
|
|
18576
18715
|
const buildTools2 = ["pip"];
|
|
@@ -20075,26 +20214,26 @@ var init_input_echo = __esm({
|
|
|
20075
20214
|
// src/cli/index.ts
|
|
20076
20215
|
init_version();
|
|
20077
20216
|
async function createProjectStructure(projectPath, info) {
|
|
20078
|
-
const cocoPath =
|
|
20217
|
+
const cocoPath = path35__default.join(projectPath, ".coco");
|
|
20079
20218
|
const directories = [
|
|
20080
20219
|
cocoPath,
|
|
20081
|
-
|
|
20082
|
-
|
|
20083
|
-
|
|
20084
|
-
|
|
20085
|
-
|
|
20086
|
-
|
|
20087
|
-
|
|
20088
|
-
|
|
20089
|
-
|
|
20090
|
-
|
|
20091
|
-
|
|
20092
|
-
|
|
20093
|
-
|
|
20094
|
-
|
|
20220
|
+
path35__default.join(cocoPath, "state"),
|
|
20221
|
+
path35__default.join(cocoPath, "checkpoints"),
|
|
20222
|
+
path35__default.join(cocoPath, "logs"),
|
|
20223
|
+
path35__default.join(cocoPath, "discovery"),
|
|
20224
|
+
path35__default.join(cocoPath, "spec"),
|
|
20225
|
+
path35__default.join(cocoPath, "architecture"),
|
|
20226
|
+
path35__default.join(cocoPath, "architecture", "adrs"),
|
|
20227
|
+
path35__default.join(cocoPath, "architecture", "diagrams"),
|
|
20228
|
+
path35__default.join(cocoPath, "planning"),
|
|
20229
|
+
path35__default.join(cocoPath, "planning", "epics"),
|
|
20230
|
+
path35__default.join(cocoPath, "execution"),
|
|
20231
|
+
path35__default.join(cocoPath, "versions"),
|
|
20232
|
+
path35__default.join(cocoPath, "reviews"),
|
|
20233
|
+
path35__default.join(cocoPath, "delivery")
|
|
20095
20234
|
];
|
|
20096
20235
|
for (const dir of directories) {
|
|
20097
|
-
await
|
|
20236
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
20098
20237
|
}
|
|
20099
20238
|
await createInitialConfig(cocoPath, info);
|
|
20100
20239
|
await createProjectState(cocoPath, info);
|
|
@@ -20127,7 +20266,7 @@ async function createInitialConfig(cocoPath, info) {
|
|
|
20127
20266
|
maxCheckpoints: 50
|
|
20128
20267
|
}
|
|
20129
20268
|
};
|
|
20130
|
-
await
|
|
20269
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, "config.json"), JSON.stringify(config, null, 2), "utf-8");
|
|
20131
20270
|
}
|
|
20132
20271
|
async function createProjectState(cocoPath, info) {
|
|
20133
20272
|
const state = {
|
|
@@ -20144,8 +20283,8 @@ async function createProjectState(cocoPath, info) {
|
|
|
20144
20283
|
qualityHistory: [],
|
|
20145
20284
|
lastCheckpoint: null
|
|
20146
20285
|
};
|
|
20147
|
-
await
|
|
20148
|
-
|
|
20286
|
+
await fs33__default.writeFile(
|
|
20287
|
+
path35__default.join(cocoPath, "state", "project.json"),
|
|
20149
20288
|
JSON.stringify(state, null, 2),
|
|
20150
20289
|
"utf-8"
|
|
20151
20290
|
);
|
|
@@ -20166,7 +20305,7 @@ checkpoints/
|
|
|
20166
20305
|
state/session.json
|
|
20167
20306
|
state/lock.json
|
|
20168
20307
|
`;
|
|
20169
|
-
await
|
|
20308
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, ".gitignore"), content, "utf-8");
|
|
20170
20309
|
}
|
|
20171
20310
|
async function createReadme(cocoPath, info) {
|
|
20172
20311
|
const content = `# Corbat-Coco Project: ${info.name}
|
|
@@ -20213,13 +20352,13 @@ Edit \`config.json\` to customize:
|
|
|
20213
20352
|
---
|
|
20214
20353
|
Generated by Corbat-Coco v0.1.0
|
|
20215
20354
|
`;
|
|
20216
|
-
await
|
|
20355
|
+
await fs33__default.writeFile(path35__default.join(cocoPath, "README.md"), content, "utf-8");
|
|
20217
20356
|
}
|
|
20218
20357
|
|
|
20219
20358
|
// src/cli/commands/init.ts
|
|
20220
20359
|
function registerInitCommand(program2) {
|
|
20221
|
-
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (
|
|
20222
|
-
await runInit(
|
|
20360
|
+
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (path55, options) => {
|
|
20361
|
+
await runInit(path55, options);
|
|
20223
20362
|
});
|
|
20224
20363
|
}
|
|
20225
20364
|
async function runInit(projectPath, options) {
|
|
@@ -20298,18 +20437,18 @@ async function gatherProjectInfo() {
|
|
|
20298
20437
|
language
|
|
20299
20438
|
};
|
|
20300
20439
|
}
|
|
20301
|
-
function getDefaultProjectInfo(
|
|
20302
|
-
const name =
|
|
20440
|
+
function getDefaultProjectInfo(path55) {
|
|
20441
|
+
const name = path55 === "." ? "my-project" : path55.split("/").pop() || "my-project";
|
|
20303
20442
|
return {
|
|
20304
20443
|
name,
|
|
20305
20444
|
description: "",
|
|
20306
20445
|
language: "typescript"
|
|
20307
20446
|
};
|
|
20308
20447
|
}
|
|
20309
|
-
async function checkExistingProject(
|
|
20448
|
+
async function checkExistingProject(path55) {
|
|
20310
20449
|
try {
|
|
20311
|
-
const
|
|
20312
|
-
await
|
|
20450
|
+
const fs53 = await import('fs/promises');
|
|
20451
|
+
await fs53.access(`${path55}/.coco`);
|
|
20313
20452
|
return true;
|
|
20314
20453
|
} catch {
|
|
20315
20454
|
return false;
|
|
@@ -21517,13 +21656,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
21517
21656
|
// src/phases/converge/persistence.ts
|
|
21518
21657
|
init_errors();
|
|
21519
21658
|
function getPersistencePaths(projectPath) {
|
|
21520
|
-
const baseDir =
|
|
21659
|
+
const baseDir = path35__default.join(projectPath, ".coco", "spec");
|
|
21521
21660
|
return {
|
|
21522
21661
|
baseDir,
|
|
21523
|
-
sessionFile:
|
|
21524
|
-
specFile:
|
|
21525
|
-
conversationLog:
|
|
21526
|
-
checkpointFile:
|
|
21662
|
+
sessionFile: path35__default.join(baseDir, "discovery-session.json"),
|
|
21663
|
+
specFile: path35__default.join(baseDir, "spec.md"),
|
|
21664
|
+
conversationLog: path35__default.join(baseDir, "conversation.jsonl"),
|
|
21665
|
+
checkpointFile: path35__default.join(baseDir, "checkpoint.json")
|
|
21527
21666
|
};
|
|
21528
21667
|
}
|
|
21529
21668
|
var SessionPersistence = class {
|
|
@@ -21536,7 +21675,7 @@ var SessionPersistence = class {
|
|
|
21536
21675
|
*/
|
|
21537
21676
|
async ensureDir() {
|
|
21538
21677
|
try {
|
|
21539
|
-
await
|
|
21678
|
+
await fs33__default.mkdir(this.paths.baseDir, { recursive: true });
|
|
21540
21679
|
} catch {
|
|
21541
21680
|
throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
|
|
21542
21681
|
path: this.paths.baseDir,
|
|
@@ -21551,7 +21690,7 @@ var SessionPersistence = class {
|
|
|
21551
21690
|
await this.ensureDir();
|
|
21552
21691
|
try {
|
|
21553
21692
|
const data = JSON.stringify(session, null, 2);
|
|
21554
|
-
await
|
|
21693
|
+
await fs33__default.writeFile(this.paths.sessionFile, data, "utf-8");
|
|
21555
21694
|
} catch {
|
|
21556
21695
|
throw new FileSystemError("Failed to save discovery session", {
|
|
21557
21696
|
path: this.paths.sessionFile,
|
|
@@ -21564,7 +21703,7 @@ var SessionPersistence = class {
|
|
|
21564
21703
|
*/
|
|
21565
21704
|
async loadSession() {
|
|
21566
21705
|
try {
|
|
21567
|
-
const data = await
|
|
21706
|
+
const data = await fs33__default.readFile(this.paths.sessionFile, "utf-8");
|
|
21568
21707
|
const parsed = JSON.parse(data);
|
|
21569
21708
|
parsed.startedAt = new Date(parsed.startedAt);
|
|
21570
21709
|
parsed.updatedAt = new Date(parsed.updatedAt);
|
|
@@ -21590,7 +21729,7 @@ var SessionPersistence = class {
|
|
|
21590
21729
|
*/
|
|
21591
21730
|
async hasSession() {
|
|
21592
21731
|
try {
|
|
21593
|
-
await
|
|
21732
|
+
await fs33__default.access(this.paths.sessionFile);
|
|
21594
21733
|
return true;
|
|
21595
21734
|
} catch {
|
|
21596
21735
|
return false;
|
|
@@ -21601,7 +21740,7 @@ var SessionPersistence = class {
|
|
|
21601
21740
|
*/
|
|
21602
21741
|
async deleteSession() {
|
|
21603
21742
|
try {
|
|
21604
|
-
await
|
|
21743
|
+
await fs33__default.unlink(this.paths.sessionFile);
|
|
21605
21744
|
} catch (error) {
|
|
21606
21745
|
if (error.code !== "ENOENT") {
|
|
21607
21746
|
throw new FileSystemError("Failed to delete discovery session", {
|
|
@@ -21617,7 +21756,7 @@ var SessionPersistence = class {
|
|
|
21617
21756
|
async saveSpecification(content) {
|
|
21618
21757
|
await this.ensureDir();
|
|
21619
21758
|
try {
|
|
21620
|
-
await
|
|
21759
|
+
await fs33__default.writeFile(this.paths.specFile, content, "utf-8");
|
|
21621
21760
|
} catch {
|
|
21622
21761
|
throw new FileSystemError("Failed to save specification", {
|
|
21623
21762
|
path: this.paths.specFile,
|
|
@@ -21630,7 +21769,7 @@ var SessionPersistence = class {
|
|
|
21630
21769
|
*/
|
|
21631
21770
|
async loadSpecification() {
|
|
21632
21771
|
try {
|
|
21633
|
-
return await
|
|
21772
|
+
return await fs33__default.readFile(this.paths.specFile, "utf-8");
|
|
21634
21773
|
} catch {
|
|
21635
21774
|
return null;
|
|
21636
21775
|
}
|
|
@@ -21646,7 +21785,7 @@ var SessionPersistence = class {
|
|
|
21646
21785
|
content
|
|
21647
21786
|
};
|
|
21648
21787
|
try {
|
|
21649
|
-
await
|
|
21788
|
+
await fs33__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
|
|
21650
21789
|
} catch {
|
|
21651
21790
|
throw new FileSystemError("Failed to append to conversation log", {
|
|
21652
21791
|
path: this.paths.conversationLog,
|
|
@@ -21659,7 +21798,7 @@ var SessionPersistence = class {
|
|
|
21659
21798
|
*/
|
|
21660
21799
|
async loadConversationLog() {
|
|
21661
21800
|
try {
|
|
21662
|
-
const data = await
|
|
21801
|
+
const data = await fs33__default.readFile(this.paths.conversationLog, "utf-8");
|
|
21663
21802
|
const lines = data.trim().split("\n");
|
|
21664
21803
|
return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
21665
21804
|
} catch {
|
|
@@ -21673,7 +21812,7 @@ var SessionPersistence = class {
|
|
|
21673
21812
|
await this.ensureDir();
|
|
21674
21813
|
try {
|
|
21675
21814
|
const data = JSON.stringify(checkpoint, null, 2);
|
|
21676
|
-
await
|
|
21815
|
+
await fs33__default.writeFile(this.paths.checkpointFile, data, "utf-8");
|
|
21677
21816
|
} catch {
|
|
21678
21817
|
throw new FileSystemError("Failed to save checkpoint", {
|
|
21679
21818
|
path: this.paths.checkpointFile,
|
|
@@ -21686,7 +21825,7 @@ var SessionPersistence = class {
|
|
|
21686
21825
|
*/
|
|
21687
21826
|
async loadCheckpoint() {
|
|
21688
21827
|
try {
|
|
21689
|
-
const data = await
|
|
21828
|
+
const data = await fs33__default.readFile(this.paths.checkpointFile, "utf-8");
|
|
21690
21829
|
const parsed = JSON.parse(data);
|
|
21691
21830
|
parsed.timestamp = new Date(parsed.timestamp);
|
|
21692
21831
|
return parsed;
|
|
@@ -21699,7 +21838,7 @@ var SessionPersistence = class {
|
|
|
21699
21838
|
*/
|
|
21700
21839
|
async clearAll() {
|
|
21701
21840
|
try {
|
|
21702
|
-
await
|
|
21841
|
+
await fs33__default.rm(this.paths.baseDir, { recursive: true, force: true });
|
|
21703
21842
|
} catch (error) {
|
|
21704
21843
|
if (error.code !== "ENOENT") {
|
|
21705
21844
|
throw new FileSystemError("Failed to clear persistence data", {
|
|
@@ -23627,8 +23766,8 @@ var OrchestrateExecutor = class {
|
|
|
23627
23766
|
}
|
|
23628
23767
|
async loadSpecification(projectPath) {
|
|
23629
23768
|
try {
|
|
23630
|
-
const jsonPath =
|
|
23631
|
-
const jsonContent = await
|
|
23769
|
+
const jsonPath = path35__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
23770
|
+
const jsonContent = await fs33__default.readFile(jsonPath, "utf-8");
|
|
23632
23771
|
return JSON.parse(jsonContent);
|
|
23633
23772
|
} catch {
|
|
23634
23773
|
return this.createMinimalSpec(projectPath);
|
|
@@ -23639,7 +23778,7 @@ var OrchestrateExecutor = class {
|
|
|
23639
23778
|
version: "1.0.0",
|
|
23640
23779
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
23641
23780
|
overview: {
|
|
23642
|
-
name:
|
|
23781
|
+
name: path35__default.basename(projectPath),
|
|
23643
23782
|
description: "Project specification",
|
|
23644
23783
|
goals: [],
|
|
23645
23784
|
targetUsers: ["developers"],
|
|
@@ -23666,53 +23805,53 @@ var OrchestrateExecutor = class {
|
|
|
23666
23805
|
};
|
|
23667
23806
|
}
|
|
23668
23807
|
async saveArchitecture(projectPath, architecture) {
|
|
23669
|
-
const dir =
|
|
23670
|
-
await
|
|
23671
|
-
const mdPath =
|
|
23672
|
-
await
|
|
23673
|
-
const jsonPath =
|
|
23674
|
-
await
|
|
23808
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture");
|
|
23809
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23810
|
+
const mdPath = path35__default.join(dir, "ARCHITECTURE.md");
|
|
23811
|
+
await fs33__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
23812
|
+
const jsonPath = path35__default.join(dir, "architecture.json");
|
|
23813
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
23675
23814
|
return mdPath;
|
|
23676
23815
|
}
|
|
23677
23816
|
async saveADRs(projectPath, adrs) {
|
|
23678
|
-
const dir =
|
|
23679
|
-
await
|
|
23817
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
23818
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23680
23819
|
const paths = [];
|
|
23681
|
-
const indexPath =
|
|
23682
|
-
await
|
|
23820
|
+
const indexPath = path35__default.join(dir, "README.md");
|
|
23821
|
+
await fs33__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
23683
23822
|
paths.push(indexPath);
|
|
23684
23823
|
for (const adr of adrs) {
|
|
23685
23824
|
const filename = getADRFilename(adr);
|
|
23686
|
-
const adrPath =
|
|
23687
|
-
await
|
|
23825
|
+
const adrPath = path35__default.join(dir, filename);
|
|
23826
|
+
await fs33__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
23688
23827
|
paths.push(adrPath);
|
|
23689
23828
|
}
|
|
23690
23829
|
return paths;
|
|
23691
23830
|
}
|
|
23692
23831
|
async saveBacklog(projectPath, backlogResult) {
|
|
23693
|
-
const dir =
|
|
23694
|
-
await
|
|
23695
|
-
const mdPath =
|
|
23696
|
-
await
|
|
23697
|
-
const jsonPath =
|
|
23698
|
-
await
|
|
23832
|
+
const dir = path35__default.join(projectPath, ".coco", "planning");
|
|
23833
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23834
|
+
const mdPath = path35__default.join(dir, "BACKLOG.md");
|
|
23835
|
+
await fs33__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
23836
|
+
const jsonPath = path35__default.join(dir, "backlog.json");
|
|
23837
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
23699
23838
|
return mdPath;
|
|
23700
23839
|
}
|
|
23701
23840
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
23702
|
-
const dir =
|
|
23703
|
-
await
|
|
23841
|
+
const dir = path35__default.join(projectPath, ".coco", "planning", "sprints");
|
|
23842
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23704
23843
|
const filename = `${sprint.id}.md`;
|
|
23705
|
-
const sprintPath =
|
|
23706
|
-
await
|
|
23707
|
-
const jsonPath =
|
|
23708
|
-
await
|
|
23844
|
+
const sprintPath = path35__default.join(dir, filename);
|
|
23845
|
+
await fs33__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
23846
|
+
const jsonPath = path35__default.join(dir, `${sprint.id}.json`);
|
|
23847
|
+
await fs33__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
23709
23848
|
return sprintPath;
|
|
23710
23849
|
}
|
|
23711
23850
|
async saveDiagram(projectPath, id, mermaid) {
|
|
23712
|
-
const dir =
|
|
23713
|
-
await
|
|
23714
|
-
const diagramPath =
|
|
23715
|
-
await
|
|
23851
|
+
const dir = path35__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
23852
|
+
await fs33__default.mkdir(dir, { recursive: true });
|
|
23853
|
+
const diagramPath = path35__default.join(dir, `${id}.mmd`);
|
|
23854
|
+
await fs33__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
23716
23855
|
return diagramPath;
|
|
23717
23856
|
}
|
|
23718
23857
|
};
|
|
@@ -23857,20 +23996,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
23857
23996
|
},
|
|
23858
23997
|
tools: {
|
|
23859
23998
|
file: {
|
|
23860
|
-
async read(
|
|
23861
|
-
const
|
|
23862
|
-
return
|
|
23999
|
+
async read(path55) {
|
|
24000
|
+
const fs53 = await import('fs/promises');
|
|
24001
|
+
return fs53.readFile(path55, "utf-8");
|
|
23863
24002
|
},
|
|
23864
|
-
async write(
|
|
23865
|
-
const
|
|
24003
|
+
async write(path55, content) {
|
|
24004
|
+
const fs53 = await import('fs/promises');
|
|
23866
24005
|
const nodePath = await import('path');
|
|
23867
|
-
await
|
|
23868
|
-
await
|
|
24006
|
+
await fs53.mkdir(nodePath.dirname(path55), { recursive: true });
|
|
24007
|
+
await fs53.writeFile(path55, content, "utf-8");
|
|
23869
24008
|
},
|
|
23870
|
-
async exists(
|
|
23871
|
-
const
|
|
24009
|
+
async exists(path55) {
|
|
24010
|
+
const fs53 = await import('fs/promises');
|
|
23872
24011
|
try {
|
|
23873
|
-
await
|
|
24012
|
+
await fs53.access(path55);
|
|
23874
24013
|
return true;
|
|
23875
24014
|
} catch {
|
|
23876
24015
|
return false;
|
|
@@ -24109,16 +24248,16 @@ async function loadTasks(_options) {
|
|
|
24109
24248
|
];
|
|
24110
24249
|
}
|
|
24111
24250
|
async function checkProjectState() {
|
|
24112
|
-
const
|
|
24251
|
+
const fs53 = await import('fs/promises');
|
|
24113
24252
|
let hasProject = false;
|
|
24114
24253
|
let hasPlan = false;
|
|
24115
24254
|
try {
|
|
24116
|
-
await
|
|
24255
|
+
await fs53.access(".coco");
|
|
24117
24256
|
hasProject = true;
|
|
24118
24257
|
} catch {
|
|
24119
24258
|
}
|
|
24120
24259
|
try {
|
|
24121
|
-
await
|
|
24260
|
+
await fs53.access(".coco/planning/backlog.json");
|
|
24122
24261
|
hasPlan = true;
|
|
24123
24262
|
} catch {
|
|
24124
24263
|
}
|
|
@@ -24225,24 +24364,24 @@ function getPhaseStatusForPhase(phase) {
|
|
|
24225
24364
|
return "in_progress";
|
|
24226
24365
|
}
|
|
24227
24366
|
async function loadProjectState(cwd, config) {
|
|
24228
|
-
const
|
|
24229
|
-
const
|
|
24230
|
-
const statePath =
|
|
24231
|
-
const backlogPath =
|
|
24232
|
-
const checkpointDir =
|
|
24367
|
+
const fs53 = await import('fs/promises');
|
|
24368
|
+
const path55 = await import('path');
|
|
24369
|
+
const statePath = path55.join(cwd, ".coco", "state.json");
|
|
24370
|
+
const backlogPath = path55.join(cwd, ".coco", "planning", "backlog.json");
|
|
24371
|
+
const checkpointDir = path55.join(cwd, ".coco", "checkpoints");
|
|
24233
24372
|
let currentPhase = "idle";
|
|
24234
24373
|
let metrics;
|
|
24235
24374
|
let sprint;
|
|
24236
24375
|
let checkpoints = [];
|
|
24237
24376
|
try {
|
|
24238
|
-
const stateContent = await
|
|
24377
|
+
const stateContent = await fs53.readFile(statePath, "utf-8");
|
|
24239
24378
|
const stateData = JSON.parse(stateContent);
|
|
24240
24379
|
currentPhase = stateData.currentPhase || "idle";
|
|
24241
24380
|
metrics = stateData.metrics;
|
|
24242
24381
|
} catch {
|
|
24243
24382
|
}
|
|
24244
24383
|
try {
|
|
24245
|
-
const backlogContent = await
|
|
24384
|
+
const backlogContent = await fs53.readFile(backlogPath, "utf-8");
|
|
24246
24385
|
const backlogData = JSON.parse(backlogContent);
|
|
24247
24386
|
if (backlogData.currentSprint) {
|
|
24248
24387
|
const tasks = backlogData.tasks || [];
|
|
@@ -24264,7 +24403,7 @@ async function loadProjectState(cwd, config) {
|
|
|
24264
24403
|
} catch {
|
|
24265
24404
|
}
|
|
24266
24405
|
try {
|
|
24267
|
-
const files = await
|
|
24406
|
+
const files = await fs53.readdir(checkpointDir);
|
|
24268
24407
|
checkpoints = files.filter((f) => f.endsWith(".json")).sort().reverse();
|
|
24269
24408
|
} catch {
|
|
24270
24409
|
}
|
|
@@ -24400,8 +24539,8 @@ async function restoreFromCheckpoint(_checkpoint) {
|
|
|
24400
24539
|
}
|
|
24401
24540
|
async function checkProjectExists() {
|
|
24402
24541
|
try {
|
|
24403
|
-
const
|
|
24404
|
-
await
|
|
24542
|
+
const fs53 = await import('fs/promises');
|
|
24543
|
+
await fs53.access(".coco");
|
|
24405
24544
|
return true;
|
|
24406
24545
|
} catch {
|
|
24407
24546
|
return false;
|
|
@@ -25440,9 +25579,9 @@ var DEFAULT_CONFIG2 = {
|
|
|
25440
25579
|
}
|
|
25441
25580
|
};
|
|
25442
25581
|
async function loadConfig2() {
|
|
25443
|
-
const
|
|
25582
|
+
const fs53 = await import('fs/promises');
|
|
25444
25583
|
try {
|
|
25445
|
-
const raw = await
|
|
25584
|
+
const raw = await fs53.readFile(CONFIG_PATH, "utf-8");
|
|
25446
25585
|
const parsed = JSON.parse(raw);
|
|
25447
25586
|
return { ...DEFAULT_CONFIG2, ...parsed };
|
|
25448
25587
|
} catch {
|
|
@@ -25450,13 +25589,13 @@ async function loadConfig2() {
|
|
|
25450
25589
|
}
|
|
25451
25590
|
}
|
|
25452
25591
|
async function saveConfig2(config) {
|
|
25453
|
-
const
|
|
25592
|
+
const fs53 = await import('fs/promises');
|
|
25454
25593
|
const dir = join(CONFIG_PATH, "..");
|
|
25455
|
-
await
|
|
25456
|
-
await
|
|
25594
|
+
await fs53.mkdir(dir, { recursive: true });
|
|
25595
|
+
await fs53.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
25457
25596
|
}
|
|
25458
|
-
function getNestedValue(obj,
|
|
25459
|
-
const keys =
|
|
25597
|
+
function getNestedValue(obj, path55) {
|
|
25598
|
+
const keys = path55.split(".");
|
|
25460
25599
|
let current = obj;
|
|
25461
25600
|
for (const key of keys) {
|
|
25462
25601
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -25466,8 +25605,8 @@ function getNestedValue(obj, path54) {
|
|
|
25466
25605
|
}
|
|
25467
25606
|
return current;
|
|
25468
25607
|
}
|
|
25469
|
-
function setNestedValue(obj,
|
|
25470
|
-
const keys =
|
|
25608
|
+
function setNestedValue(obj, path55, value) {
|
|
25609
|
+
const keys = path55.split(".");
|
|
25471
25610
|
let current = obj;
|
|
25472
25611
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
25473
25612
|
const key = keys[i];
|
|
@@ -25807,13 +25946,13 @@ async function runAdd(source, options) {
|
|
|
25807
25946
|
const isGithubShorthand = source.includes("/") && !isGitUrl;
|
|
25808
25947
|
const isLocalPath = source.startsWith(".") || source.startsWith("/");
|
|
25809
25948
|
if (isLocalPath) {
|
|
25810
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25811
|
-
const sourcePath =
|
|
25812
|
-
const skillName =
|
|
25813
|
-
const destPath =
|
|
25949
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
25950
|
+
const sourcePath = path35__default.resolve(source);
|
|
25951
|
+
const skillName = path35__default.basename(sourcePath);
|
|
25952
|
+
const destPath = path35__default.join(targetDir, skillName);
|
|
25814
25953
|
try {
|
|
25815
|
-
await
|
|
25816
|
-
await
|
|
25954
|
+
await fs33__default.mkdir(targetDir, { recursive: true });
|
|
25955
|
+
await fs33__default.cp(sourcePath, destPath, { recursive: true });
|
|
25817
25956
|
p25.log.success(`Installed "${skillName}" to ${destPath}`);
|
|
25818
25957
|
} catch (error) {
|
|
25819
25958
|
p25.log.error(
|
|
@@ -25843,10 +25982,10 @@ async function runAdd(source, options) {
|
|
|
25843
25982
|
p25.log.info("Try installing manually: git clone the repo into .coco/skills/");
|
|
25844
25983
|
}
|
|
25845
25984
|
} else if (isGitUrl) {
|
|
25846
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25847
|
-
await
|
|
25985
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
25986
|
+
await fs33__default.mkdir(targetDir, { recursive: true });
|
|
25848
25987
|
const skillName = source.split("/").pop()?.replace(".git", "") ?? "skill";
|
|
25849
|
-
const skillDir =
|
|
25988
|
+
const skillDir = path35__default.join(targetDir, skillName);
|
|
25850
25989
|
const spinner19 = p25.spinner();
|
|
25851
25990
|
spinner19.start(`Cloning ${source}...`);
|
|
25852
25991
|
try {
|
|
@@ -25871,10 +26010,10 @@ async function runAdd(source, options) {
|
|
|
25871
26010
|
}
|
|
25872
26011
|
async function runRemove(name, options) {
|
|
25873
26012
|
p25.intro(chalk25.magenta("Remove Skill"));
|
|
25874
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25875
|
-
const skillPath =
|
|
26013
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
26014
|
+
const skillPath = path35__default.join(targetDir, name);
|
|
25876
26015
|
try {
|
|
25877
|
-
await
|
|
26016
|
+
await fs33__default.access(skillPath);
|
|
25878
26017
|
} catch {
|
|
25879
26018
|
p25.log.error(`Skill "${name}" not found at ${skillPath}`);
|
|
25880
26019
|
p25.outro("");
|
|
@@ -25890,7 +26029,7 @@ async function runRemove(name, options) {
|
|
|
25890
26029
|
return;
|
|
25891
26030
|
}
|
|
25892
26031
|
}
|
|
25893
|
-
await
|
|
26032
|
+
await fs33__default.rm(skillPath, { recursive: true });
|
|
25894
26033
|
p25.log.success(`Removed "${name}"`);
|
|
25895
26034
|
p25.outro("");
|
|
25896
26035
|
}
|
|
@@ -25951,10 +26090,10 @@ async function runInfo(name) {
|
|
|
25951
26090
|
}
|
|
25952
26091
|
async function runCreate(name, options) {
|
|
25953
26092
|
p25.intro(chalk25.magenta("Create Skill"));
|
|
25954
|
-
const targetDir = options.global ? CONFIG_PATHS.skills :
|
|
25955
|
-
const skillDir =
|
|
26093
|
+
const targetDir = options.global ? CONFIG_PATHS.skills : path35__default.join(process.cwd(), ".coco", "skills");
|
|
26094
|
+
const skillDir = path35__default.join(targetDir, name);
|
|
25956
26095
|
try {
|
|
25957
|
-
await
|
|
26096
|
+
await fs33__default.access(skillDir);
|
|
25958
26097
|
p25.log.error(`Skill "${name}" already exists at ${skillDir}`);
|
|
25959
26098
|
p25.outro("");
|
|
25960
26099
|
return;
|
|
@@ -25983,7 +26122,7 @@ async function runCreate(name, options) {
|
|
|
25983
26122
|
p25.outro("Cancelled.");
|
|
25984
26123
|
return;
|
|
25985
26124
|
}
|
|
25986
|
-
await
|
|
26125
|
+
await fs33__default.mkdir(skillDir, { recursive: true });
|
|
25987
26126
|
const skillMd = `---
|
|
25988
26127
|
name: "${name}"
|
|
25989
26128
|
description: "${description}"
|
|
@@ -26005,10 +26144,10 @@ when this skill is activated (automatically via matching or manually via /${name
|
|
|
26005
26144
|
2. Include examples when helpful
|
|
26006
26145
|
3. Keep instructions under 500 lines
|
|
26007
26146
|
`;
|
|
26008
|
-
await
|
|
26009
|
-
await
|
|
26147
|
+
await fs33__default.writeFile(path35__default.join(skillDir, "SKILL.md"), skillMd, "utf-8");
|
|
26148
|
+
await fs33__default.mkdir(path35__default.join(skillDir, "references"), { recursive: true });
|
|
26010
26149
|
p25.log.success(`Created skill at ${skillDir}`);
|
|
26011
|
-
p25.log.info(`Edit ${
|
|
26150
|
+
p25.log.info(`Edit ${path35__default.join(skillDir, "SKILL.md")} to add instructions.`);
|
|
26012
26151
|
p25.outro("");
|
|
26013
26152
|
}
|
|
26014
26153
|
|
|
@@ -26372,10 +26511,10 @@ function registerCheckCommand(program2) {
|
|
|
26372
26511
|
|
|
26373
26512
|
// src/swarm/spec-parser.ts
|
|
26374
26513
|
async function parseSwarmSpec(filePath) {
|
|
26375
|
-
const
|
|
26376
|
-
const
|
|
26377
|
-
const rawContent = await
|
|
26378
|
-
const ext =
|
|
26514
|
+
const fs53 = await import('fs/promises');
|
|
26515
|
+
const path55 = await import('path');
|
|
26516
|
+
const rawContent = await fs53.readFile(filePath, "utf-8");
|
|
26517
|
+
const ext = path55.extname(filePath).toLowerCase();
|
|
26379
26518
|
if (ext === ".yaml" || ext === ".yml") {
|
|
26380
26519
|
return parseYamlSpec(rawContent);
|
|
26381
26520
|
}
|
|
@@ -26704,11 +26843,11 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
26704
26843
|
integrator: { maxTurns: 20, temperature: 0.2 }
|
|
26705
26844
|
};
|
|
26706
26845
|
async function loadAgentConfig(projectPath) {
|
|
26707
|
-
const
|
|
26708
|
-
const
|
|
26709
|
-
const configPath =
|
|
26846
|
+
const fs53 = await import('fs/promises');
|
|
26847
|
+
const path55 = await import('path');
|
|
26848
|
+
const configPath = path55.join(projectPath, ".coco", "swarm", "agents.json");
|
|
26710
26849
|
try {
|
|
26711
|
-
const raw = await
|
|
26850
|
+
const raw = await fs53.readFile(configPath, "utf-8");
|
|
26712
26851
|
const parsed = JSON.parse(raw);
|
|
26713
26852
|
const merged = { ...DEFAULT_AGENT_CONFIG };
|
|
26714
26853
|
for (const role of Object.keys(DEFAULT_AGENT_CONFIG)) {
|
|
@@ -26896,19 +27035,19 @@ async function createBoard(projectPath, spec) {
|
|
|
26896
27035
|
return board;
|
|
26897
27036
|
}
|
|
26898
27037
|
async function loadBoard(projectPath) {
|
|
26899
|
-
const
|
|
26900
|
-
const
|
|
26901
|
-
const boardPath =
|
|
26902
|
-
const raw = await
|
|
27038
|
+
const fs53 = await import('fs/promises');
|
|
27039
|
+
const path55 = await import('path');
|
|
27040
|
+
const boardPath = path55.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
27041
|
+
const raw = await fs53.readFile(boardPath, "utf-8");
|
|
26903
27042
|
return JSON.parse(raw);
|
|
26904
27043
|
}
|
|
26905
27044
|
async function saveBoard(projectPath, board) {
|
|
26906
|
-
const
|
|
26907
|
-
const
|
|
26908
|
-
const boardDir =
|
|
26909
|
-
const boardPath =
|
|
26910
|
-
await
|
|
26911
|
-
await
|
|
27045
|
+
const fs53 = await import('fs/promises');
|
|
27046
|
+
const path55 = await import('path');
|
|
27047
|
+
const boardDir = path55.join(projectPath, ".coco", "swarm");
|
|
27048
|
+
const boardPath = path55.join(boardDir, "task-board.json");
|
|
27049
|
+
await fs53.mkdir(boardDir, { recursive: true });
|
|
27050
|
+
await fs53.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
26912
27051
|
}
|
|
26913
27052
|
function markTaskInProgress(board, taskId, role) {
|
|
26914
27053
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -27073,11 +27212,11 @@ async function defaultPromptHandler(q) {
|
|
|
27073
27212
|
}
|
|
27074
27213
|
}
|
|
27075
27214
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
27076
|
-
const
|
|
27077
|
-
const
|
|
27078
|
-
const swarmDir =
|
|
27079
|
-
const assumptionsPath =
|
|
27080
|
-
await
|
|
27215
|
+
const fs53 = await import('fs/promises');
|
|
27216
|
+
const path55 = await import('path');
|
|
27217
|
+
const swarmDir = path55.join(projectPath, ".coco", "swarm");
|
|
27218
|
+
const assumptionsPath = path55.join(swarmDir, "assumptions.md");
|
|
27219
|
+
await fs53.mkdir(swarmDir, { recursive: true });
|
|
27081
27220
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
27082
27221
|
const content = [
|
|
27083
27222
|
`# Swarm Assumptions \u2014 ${projectName}`,
|
|
@@ -27093,18 +27232,18 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
27093
27232
|
assumptions.length > 0 ? assumptions.join("\n\n") : `_(none)_`,
|
|
27094
27233
|
``
|
|
27095
27234
|
].join("\n");
|
|
27096
|
-
await
|
|
27235
|
+
await fs53.writeFile(assumptionsPath, content, "utf-8");
|
|
27097
27236
|
return assumptionsPath;
|
|
27098
27237
|
}
|
|
27099
27238
|
|
|
27100
27239
|
// src/swarm/events.ts
|
|
27101
27240
|
async function appendSwarmEvent(projectPath, event) {
|
|
27102
|
-
const
|
|
27103
|
-
const
|
|
27104
|
-
const eventsDir =
|
|
27105
|
-
const eventsFile =
|
|
27106
|
-
await
|
|
27107
|
-
await
|
|
27241
|
+
const fs53 = await import('fs/promises');
|
|
27242
|
+
const path55 = await import('path');
|
|
27243
|
+
const eventsDir = path55.join(projectPath, ".coco", "swarm");
|
|
27244
|
+
const eventsFile = path55.join(eventsDir, "events.jsonl");
|
|
27245
|
+
await fs53.mkdir(eventsDir, { recursive: true });
|
|
27246
|
+
await fs53.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
27108
27247
|
}
|
|
27109
27248
|
function createEventId() {
|
|
27110
27249
|
return `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -27112,12 +27251,12 @@ function createEventId() {
|
|
|
27112
27251
|
|
|
27113
27252
|
// src/swarm/knowledge.ts
|
|
27114
27253
|
async function appendKnowledge(projectPath, entry) {
|
|
27115
|
-
const
|
|
27116
|
-
const
|
|
27117
|
-
const knowledgeDir =
|
|
27118
|
-
const knowledgeFile =
|
|
27119
|
-
await
|
|
27120
|
-
await
|
|
27254
|
+
const fs53 = await import('fs/promises');
|
|
27255
|
+
const path55 = await import('path');
|
|
27256
|
+
const knowledgeDir = path55.join(projectPath, ".coco", "swarm");
|
|
27257
|
+
const knowledgeFile = path55.join(knowledgeDir, "knowledge.jsonl");
|
|
27258
|
+
await fs53.mkdir(knowledgeDir, { recursive: true });
|
|
27259
|
+
await fs53.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
27121
27260
|
}
|
|
27122
27261
|
|
|
27123
27262
|
// src/swarm/agents/prompts.ts
|
|
@@ -27421,11 +27560,11 @@ async function runSwarmLifecycle(options) {
|
|
|
27421
27560
|
}
|
|
27422
27561
|
async function stageInit(ctx) {
|
|
27423
27562
|
const { projectPath, spec } = ctx.options;
|
|
27424
|
-
const
|
|
27425
|
-
const
|
|
27426
|
-
await
|
|
27427
|
-
await
|
|
27428
|
-
const specSummaryPath =
|
|
27563
|
+
const fs53 = await import('fs/promises');
|
|
27564
|
+
const path55 = await import('path');
|
|
27565
|
+
await fs53.mkdir(path55.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
27566
|
+
await fs53.mkdir(ctx.options.outputPath, { recursive: true });
|
|
27567
|
+
const specSummaryPath = path55.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
27429
27568
|
const specSummary = {
|
|
27430
27569
|
projectName: spec.projectName,
|
|
27431
27570
|
description: spec.description,
|
|
@@ -27439,7 +27578,7 @@ async function stageInit(ctx) {
|
|
|
27439
27578
|
})),
|
|
27440
27579
|
qualityConfig: spec.qualityConfig
|
|
27441
27580
|
};
|
|
27442
|
-
await
|
|
27581
|
+
await fs53.writeFile(specSummaryPath, JSON.stringify(specSummary, null, 2), "utf-8");
|
|
27443
27582
|
await emitEvent(projectPath, {
|
|
27444
27583
|
agentRole: "pm",
|
|
27445
27584
|
agentTurn: 0,
|
|
@@ -27496,10 +27635,10 @@ async function stagePlan(ctx) {
|
|
|
27496
27635
|
})
|
|
27497
27636
|
]);
|
|
27498
27637
|
await createBoard(projectPath, spec);
|
|
27499
|
-
const
|
|
27500
|
-
const
|
|
27501
|
-
const planPath =
|
|
27502
|
-
await
|
|
27638
|
+
const fs53 = await import('fs/promises');
|
|
27639
|
+
const path55 = await import('path');
|
|
27640
|
+
const planPath = path55.join(projectPath, ".coco", "swarm", "plan.json");
|
|
27641
|
+
await fs53.writeFile(
|
|
27503
27642
|
planPath,
|
|
27504
27643
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
27505
27644
|
"utf-8"
|
|
@@ -27714,8 +27853,8 @@ async function stageIntegrate(ctx) {
|
|
|
27714
27853
|
}
|
|
27715
27854
|
async function stageOutput(ctx) {
|
|
27716
27855
|
const { projectPath, outputPath } = ctx.options;
|
|
27717
|
-
const
|
|
27718
|
-
const
|
|
27856
|
+
const fs53 = await import('fs/promises');
|
|
27857
|
+
const path55 = await import('path');
|
|
27719
27858
|
const board = await loadBoard(projectPath);
|
|
27720
27859
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
27721
27860
|
const summary = {
|
|
@@ -27729,9 +27868,9 @@ async function stageOutput(ctx) {
|
|
|
27729
27868
|
},
|
|
27730
27869
|
globalScore: computeGlobalScore(featureResults)
|
|
27731
27870
|
};
|
|
27732
|
-
await
|
|
27733
|
-
const summaryPath =
|
|
27734
|
-
await
|
|
27871
|
+
await fs53.mkdir(outputPath, { recursive: true });
|
|
27872
|
+
const summaryPath = path55.join(outputPath, "swarm-summary.json");
|
|
27873
|
+
await fs53.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
27735
27874
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
27736
27875
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
27737
27876
|
await emitEvent(projectPath, {
|
|
@@ -28077,8 +28216,8 @@ var SwarmOrchestrator = class {
|
|
|
28077
28216
|
noQuestions = false,
|
|
28078
28217
|
onProgress
|
|
28079
28218
|
} = options;
|
|
28080
|
-
const
|
|
28081
|
-
const projectPath =
|
|
28219
|
+
const path55 = await import('path');
|
|
28220
|
+
const projectPath = path55.dirname(path55.resolve(specFile));
|
|
28082
28221
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
28083
28222
|
const spec = await parseSwarmSpec(specFile);
|
|
28084
28223
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -28089,7 +28228,7 @@ var SwarmOrchestrator = class {
|
|
|
28089
28228
|
await runSwarmLifecycle({
|
|
28090
28229
|
spec,
|
|
28091
28230
|
projectPath,
|
|
28092
|
-
outputPath:
|
|
28231
|
+
outputPath: path55.resolve(outputPath),
|
|
28093
28232
|
provider,
|
|
28094
28233
|
agentConfig,
|
|
28095
28234
|
minScore,
|
|
@@ -29589,15 +29728,15 @@ async function saveConfiguration(result) {
|
|
|
29589
29728
|
}
|
|
29590
29729
|
async function saveEnvVars(filePath, vars, createDir = false) {
|
|
29591
29730
|
if (createDir) {
|
|
29592
|
-
const dir =
|
|
29731
|
+
const dir = path35.dirname(filePath);
|
|
29593
29732
|
try {
|
|
29594
|
-
await
|
|
29733
|
+
await fs33.mkdir(dir, { recursive: true, mode: 448 });
|
|
29595
29734
|
} catch {
|
|
29596
29735
|
}
|
|
29597
29736
|
}
|
|
29598
29737
|
let existingVars = {};
|
|
29599
29738
|
try {
|
|
29600
|
-
const content = await
|
|
29739
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
29601
29740
|
for (const line of content.split("\n")) {
|
|
29602
29741
|
const trimmed = line.trim();
|
|
29603
29742
|
if (trimmed && !trimmed.startsWith("#")) {
|
|
@@ -29620,7 +29759,7 @@ async function saveEnvVars(filePath, vars, createDir = false) {
|
|
|
29620
29759
|
for (const [key, value] of Object.entries(allVars)) {
|
|
29621
29760
|
lines.push(`${key}=${value}`);
|
|
29622
29761
|
}
|
|
29623
|
-
await
|
|
29762
|
+
await fs33.writeFile(filePath, lines.join("\n") + "\n", { mode: 384 });
|
|
29624
29763
|
}
|
|
29625
29764
|
async function handleLocalProviderUnavailable(providerType, config) {
|
|
29626
29765
|
const cfg = LOCAL_PROVIDER_CONFIG[providerType];
|
|
@@ -30727,8 +30866,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
30727
30866
|
p25.log.message("");
|
|
30728
30867
|
for (const project of projects) {
|
|
30729
30868
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
30730
|
-
const
|
|
30731
|
-
p25.log.message(` [${level}] ${
|
|
30869
|
+
const path55 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
30870
|
+
p25.log.message(` [${level}] ${path55}`);
|
|
30732
30871
|
p25.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
30733
30872
|
}
|
|
30734
30873
|
p25.log.message("");
|
|
@@ -30966,8 +31105,8 @@ var buildCommand = {
|
|
|
30966
31105
|
};
|
|
30967
31106
|
async function loadBacklog(projectPath) {
|
|
30968
31107
|
try {
|
|
30969
|
-
const backlogPath =
|
|
30970
|
-
const content = await
|
|
31108
|
+
const backlogPath = path35.join(projectPath, ".coco", "planning", "backlog.json");
|
|
31109
|
+
const content = await fs33.readFile(backlogPath, "utf-8");
|
|
30971
31110
|
const data = JSON.parse(content);
|
|
30972
31111
|
return data.backlog;
|
|
30973
31112
|
} catch {
|
|
@@ -30976,25 +31115,25 @@ async function loadBacklog(projectPath) {
|
|
|
30976
31115
|
}
|
|
30977
31116
|
async function loadSprint(projectPath, sprintId) {
|
|
30978
31117
|
try {
|
|
30979
|
-
const sprintsDir =
|
|
30980
|
-
const files = await
|
|
31118
|
+
const sprintsDir = path35.join(projectPath, ".coco", "planning", "sprints");
|
|
31119
|
+
const files = await fs33.readdir(sprintsDir);
|
|
30981
31120
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
30982
31121
|
if (jsonFiles.length === 0) return null;
|
|
30983
31122
|
const targetFile = sprintId ? jsonFiles.find((f) => f.includes(sprintId)) : jsonFiles[0];
|
|
30984
31123
|
if (!targetFile) return null;
|
|
30985
|
-
const sprintPath =
|
|
30986
|
-
const content = await
|
|
31124
|
+
const sprintPath = path35.join(sprintsDir, targetFile);
|
|
31125
|
+
const content = await fs33.readFile(sprintPath, "utf-8");
|
|
30987
31126
|
return JSON.parse(content);
|
|
30988
31127
|
} catch {
|
|
30989
31128
|
return null;
|
|
30990
31129
|
}
|
|
30991
31130
|
}
|
|
30992
31131
|
async function saveBacklog(projectPath, backlog) {
|
|
30993
|
-
const backlogPath =
|
|
30994
|
-
const content = await
|
|
31132
|
+
const backlogPath = path35.join(projectPath, ".coco", "planning", "backlog.json");
|
|
31133
|
+
const content = await fs33.readFile(backlogPath, "utf-8");
|
|
30995
31134
|
const data = JSON.parse(content);
|
|
30996
31135
|
data.backlog = backlog;
|
|
30997
|
-
await
|
|
31136
|
+
await fs33.writeFile(backlogPath, JSON.stringify(data, null, 2), "utf-8");
|
|
30998
31137
|
}
|
|
30999
31138
|
function getStatusEmoji(status) {
|
|
31000
31139
|
const emojis = {
|
|
@@ -31905,7 +32044,7 @@ async function getCheckpoint(session, checkpointId) {
|
|
|
31905
32044
|
return store.checkpoints.find((cp) => cp.id === checkpointId) ?? null;
|
|
31906
32045
|
}
|
|
31907
32046
|
async function restoreFiles(checkpoint, excludeFiles) {
|
|
31908
|
-
const
|
|
32047
|
+
const fs53 = await import('fs/promises');
|
|
31909
32048
|
const restored = [];
|
|
31910
32049
|
const failed = [];
|
|
31911
32050
|
for (const fileCheckpoint of checkpoint.files) {
|
|
@@ -31913,7 +32052,7 @@ async function restoreFiles(checkpoint, excludeFiles) {
|
|
|
31913
32052
|
continue;
|
|
31914
32053
|
}
|
|
31915
32054
|
try {
|
|
31916
|
-
await
|
|
32055
|
+
await fs53.writeFile(fileCheckpoint.filePath, fileCheckpoint.originalContent, "utf-8");
|
|
31917
32056
|
restored.push(fileCheckpoint.filePath);
|
|
31918
32057
|
} catch (error) {
|
|
31919
32058
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -31995,8 +32134,8 @@ function displayRewindResult(result) {
|
|
|
31995
32134
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
31996
32135
|
console.log(`${chalk25.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
31997
32136
|
}
|
|
31998
|
-
for (const { path:
|
|
31999
|
-
const fileName =
|
|
32137
|
+
for (const { path: path55, error } of result.filesFailed) {
|
|
32138
|
+
const fileName = path55.split("/").pop() ?? path55;
|
|
32000
32139
|
console.log(`${chalk25.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
32001
32140
|
}
|
|
32002
32141
|
if (result.conversationRestored) {
|
|
@@ -32634,8 +32773,8 @@ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@corbat-tech/coco/latest";
|
|
|
32634
32773
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
32635
32774
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
32636
32775
|
var STARTUP_TIMEOUT_MS = 5500;
|
|
32637
|
-
var CACHE_DIR =
|
|
32638
|
-
var CACHE_FILE =
|
|
32776
|
+
var CACHE_DIR = path35__default.join(os4__default.homedir(), ".coco");
|
|
32777
|
+
var CACHE_FILE = path35__default.join(CACHE_DIR, "version-check-cache.json");
|
|
32639
32778
|
function compareVersions(a, b) {
|
|
32640
32779
|
const partsA = a.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
32641
32780
|
const partsB = b.replace(/^v/, "").split(".").map((p45) => Number(p45.replace(/-.*$/, "")));
|
|
@@ -33488,8 +33627,8 @@ function formatToolSummary(toolName, input) {
|
|
|
33488
33627
|
case "grep":
|
|
33489
33628
|
case "search_files": {
|
|
33490
33629
|
const pattern = String(input.pattern || "");
|
|
33491
|
-
const
|
|
33492
|
-
return `"${pattern}"${
|
|
33630
|
+
const path55 = input.path ? ` in ${input.path}` : "";
|
|
33631
|
+
return `"${pattern}"${path55}`;
|
|
33493
33632
|
}
|
|
33494
33633
|
case "bash_exec": {
|
|
33495
33634
|
const cmd = String(input.command || "");
|
|
@@ -33703,7 +33842,7 @@ async function readClipboardImage() {
|
|
|
33703
33842
|
return null;
|
|
33704
33843
|
}
|
|
33705
33844
|
async function readClipboardImageMacOS() {
|
|
33706
|
-
const tmpFile =
|
|
33845
|
+
const tmpFile = path35.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
33707
33846
|
try {
|
|
33708
33847
|
const script = `
|
|
33709
33848
|
set theFile to POSIX file "${tmpFile}"
|
|
@@ -33724,7 +33863,7 @@ end try
|
|
|
33724
33863
|
if (!result.startsWith("ok")) {
|
|
33725
33864
|
return null;
|
|
33726
33865
|
}
|
|
33727
|
-
const buffer = await
|
|
33866
|
+
const buffer = await fs33.readFile(tmpFile);
|
|
33728
33867
|
return {
|
|
33729
33868
|
data: buffer.toString("base64"),
|
|
33730
33869
|
media_type: "image/png"
|
|
@@ -33733,7 +33872,7 @@ end try
|
|
|
33733
33872
|
return null;
|
|
33734
33873
|
} finally {
|
|
33735
33874
|
try {
|
|
33736
|
-
await
|
|
33875
|
+
await fs33.unlink(tmpFile);
|
|
33737
33876
|
} catch {
|
|
33738
33877
|
}
|
|
33739
33878
|
}
|
|
@@ -33759,7 +33898,7 @@ async function readClipboardImageLinux() {
|
|
|
33759
33898
|
}
|
|
33760
33899
|
}
|
|
33761
33900
|
async function readClipboardImageWindows() {
|
|
33762
|
-
const tmpFile =
|
|
33901
|
+
const tmpFile = path35.join(os4.tmpdir(), `coco-clipboard-${Date.now()}.png`);
|
|
33763
33902
|
try {
|
|
33764
33903
|
const escapedPath = tmpFile.replace(/'/g, "''");
|
|
33765
33904
|
const script = `
|
|
@@ -33777,7 +33916,7 @@ if ($img -ne $null) {
|
|
|
33777
33916
|
timeout: 1e4
|
|
33778
33917
|
}).trim();
|
|
33779
33918
|
if (result !== "ok") return null;
|
|
33780
|
-
const buffer = await
|
|
33919
|
+
const buffer = await fs33.readFile(tmpFile);
|
|
33781
33920
|
return {
|
|
33782
33921
|
data: buffer.toString("base64"),
|
|
33783
33922
|
media_type: "image/png"
|
|
@@ -33786,7 +33925,7 @@ if ($img -ne $null) {
|
|
|
33786
33925
|
return null;
|
|
33787
33926
|
} finally {
|
|
33788
33927
|
try {
|
|
33789
|
-
await
|
|
33928
|
+
await fs33.unlink(tmpFile);
|
|
33790
33929
|
} catch {
|
|
33791
33930
|
}
|
|
33792
33931
|
}
|
|
@@ -33874,9 +34013,9 @@ var allowPathCommand = {
|
|
|
33874
34013
|
}
|
|
33875
34014
|
};
|
|
33876
34015
|
async function addPath(dirPath, session) {
|
|
33877
|
-
const absolute =
|
|
34016
|
+
const absolute = path35__default.resolve(dirPath);
|
|
33878
34017
|
try {
|
|
33879
|
-
const stat2 = await
|
|
34018
|
+
const stat2 = await fs33__default.stat(absolute);
|
|
33880
34019
|
if (!stat2.isDirectory()) {
|
|
33881
34020
|
p25.log.error(`Not a directory: ${absolute}`);
|
|
33882
34021
|
return;
|
|
@@ -33886,19 +34025,19 @@ async function addPath(dirPath, session) {
|
|
|
33886
34025
|
return;
|
|
33887
34026
|
}
|
|
33888
34027
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
33889
|
-
const normalizedBlocked =
|
|
33890
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
34028
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
34029
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
33891
34030
|
p25.log.error(`System path '${blocked}' cannot be allowed`);
|
|
33892
34031
|
return;
|
|
33893
34032
|
}
|
|
33894
34033
|
}
|
|
33895
|
-
const normalizedCwd =
|
|
33896
|
-
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd +
|
|
34034
|
+
const normalizedCwd = path35__default.normalize(session.projectPath);
|
|
34035
|
+
if (absolute === normalizedCwd || absolute.startsWith(normalizedCwd + path35__default.sep)) {
|
|
33897
34036
|
p25.log.info("That path is already within the project directory");
|
|
33898
34037
|
return;
|
|
33899
34038
|
}
|
|
33900
34039
|
const existing = getAllowedPaths();
|
|
33901
|
-
if (existing.some((e) =>
|
|
34040
|
+
if (existing.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
33902
34041
|
p25.log.info(`Already allowed: ${absolute}`);
|
|
33903
34042
|
return;
|
|
33904
34043
|
}
|
|
@@ -33969,7 +34108,7 @@ async function revokePath(dirPath, _session) {
|
|
|
33969
34108
|
}
|
|
33970
34109
|
dirPath = selected;
|
|
33971
34110
|
}
|
|
33972
|
-
const absolute =
|
|
34111
|
+
const absolute = path35__default.resolve(dirPath);
|
|
33973
34112
|
const removed = removeAllowedPathFromSession(absolute);
|
|
33974
34113
|
await removePersistedAllowedPath(absolute);
|
|
33975
34114
|
if (removed) {
|
|
@@ -34322,7 +34461,7 @@ var RECOMMENDED_DENY = [
|
|
|
34322
34461
|
];
|
|
34323
34462
|
async function loadPermissionPreferences() {
|
|
34324
34463
|
try {
|
|
34325
|
-
const content = await
|
|
34464
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34326
34465
|
const config = JSON.parse(content);
|
|
34327
34466
|
return {
|
|
34328
34467
|
recommendedAllowlistApplied: config.recommendedAllowlistApplied,
|
|
@@ -34336,13 +34475,13 @@ async function savePermissionPreference(key, value) {
|
|
|
34336
34475
|
try {
|
|
34337
34476
|
let config = {};
|
|
34338
34477
|
try {
|
|
34339
|
-
const content = await
|
|
34478
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34340
34479
|
config = JSON.parse(content);
|
|
34341
34480
|
} catch {
|
|
34342
34481
|
}
|
|
34343
34482
|
config[key] = value;
|
|
34344
|
-
await
|
|
34345
|
-
await
|
|
34483
|
+
await fs33__default.mkdir(path35__default.dirname(CONFIG_PATHS.config), { recursive: true });
|
|
34484
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2), "utf-8");
|
|
34346
34485
|
} catch {
|
|
34347
34486
|
}
|
|
34348
34487
|
}
|
|
@@ -34576,7 +34715,7 @@ async function resetPermissions(session) {
|
|
|
34576
34715
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
34577
34716
|
};
|
|
34578
34717
|
try {
|
|
34579
|
-
await
|
|
34718
|
+
await fs33__default.writeFile(CONFIG_PATHS.trustedTools, JSON.stringify(emptySettings, null, 2), "utf-8");
|
|
34580
34719
|
} catch {
|
|
34581
34720
|
}
|
|
34582
34721
|
await savePermissionPreference("recommendedAllowlistApplied", false);
|
|
@@ -34658,7 +34797,7 @@ function formatQualityResult(result) {
|
|
|
34658
34797
|
}
|
|
34659
34798
|
async function loadQualityLoopPreference() {
|
|
34660
34799
|
try {
|
|
34661
|
-
const content = await
|
|
34800
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34662
34801
|
const config = JSON.parse(content);
|
|
34663
34802
|
const value = config.qualityLoop ?? config.cocoMode;
|
|
34664
34803
|
if (typeof value === "boolean") {
|
|
@@ -34673,12 +34812,12 @@ async function saveQualityLoopPreference(enabled) {
|
|
|
34673
34812
|
try {
|
|
34674
34813
|
let config = {};
|
|
34675
34814
|
try {
|
|
34676
|
-
const content = await
|
|
34815
|
+
const content = await fs33__default.readFile(CONFIG_PATHS.config, "utf-8");
|
|
34677
34816
|
config = JSON.parse(content);
|
|
34678
34817
|
} catch {
|
|
34679
34818
|
}
|
|
34680
34819
|
config.qualityLoop = enabled;
|
|
34681
|
-
await
|
|
34820
|
+
await fs33__default.writeFile(CONFIG_PATHS.config, JSON.stringify(config, null, 2) + "\n");
|
|
34682
34821
|
} catch {
|
|
34683
34822
|
}
|
|
34684
34823
|
}
|
|
@@ -35514,9 +35653,9 @@ Response format (JSON only, no prose):
|
|
|
35514
35653
|
cancel5("Build cancelled.");
|
|
35515
35654
|
}
|
|
35516
35655
|
}
|
|
35517
|
-
const cocoDir =
|
|
35518
|
-
await
|
|
35519
|
-
await
|
|
35656
|
+
const cocoDir = path35__default.join(outputPath, ".coco");
|
|
35657
|
+
await fs33__default.mkdir(cocoDir, { recursive: true });
|
|
35658
|
+
await fs33__default.writeFile(path35__default.join(cocoDir, "backlog.json"), JSON.stringify(spec, null, 2), "utf-8");
|
|
35520
35659
|
p25.outro(" Spec saved \u2014 starting sprints");
|
|
35521
35660
|
return spec;
|
|
35522
35661
|
}
|
|
@@ -36066,8 +36205,8 @@ init_errors();
|
|
|
36066
36205
|
init_subprocess_registry();
|
|
36067
36206
|
async function detectTestFramework2(cwd) {
|
|
36068
36207
|
try {
|
|
36069
|
-
const pkgPath =
|
|
36070
|
-
const pkgContent = await
|
|
36208
|
+
const pkgPath = path35__default.join(cwd, "package.json");
|
|
36209
|
+
const pkgContent = await fs33__default.readFile(pkgPath, "utf-8");
|
|
36071
36210
|
const pkg = JSON.parse(pkgContent);
|
|
36072
36211
|
const deps = {
|
|
36073
36212
|
...pkg.dependencies,
|
|
@@ -36155,8 +36294,9 @@ Examples:
|
|
|
36155
36294
|
duration
|
|
36156
36295
|
);
|
|
36157
36296
|
} catch (error) {
|
|
36297
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
36158
36298
|
throw new ToolError(
|
|
36159
|
-
`Test execution failed: ${
|
|
36299
|
+
`Test execution failed: ${msg}. Use command_exists to verify the test framework is installed, or run_script with a custom command.`,
|
|
36160
36300
|
{ tool: "run_tests", cause: error instanceof Error ? error : void 0 }
|
|
36161
36301
|
);
|
|
36162
36302
|
}
|
|
@@ -36247,13 +36387,13 @@ Examples:
|
|
|
36247
36387
|
const projectDir = cwd ?? process.cwd();
|
|
36248
36388
|
try {
|
|
36249
36389
|
const coverageLocations = [
|
|
36250
|
-
|
|
36251
|
-
|
|
36252
|
-
|
|
36390
|
+
path35__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
36391
|
+
path35__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
36392
|
+
path35__default.join(projectDir, ".nyc_output", "coverage-summary.json")
|
|
36253
36393
|
];
|
|
36254
36394
|
for (const location of coverageLocations) {
|
|
36255
36395
|
try {
|
|
36256
|
-
const content = await
|
|
36396
|
+
const content = await fs33__default.readFile(location, "utf-8");
|
|
36257
36397
|
const coverage = JSON.parse(content);
|
|
36258
36398
|
if (coverage.total) {
|
|
36259
36399
|
return {
|
|
@@ -36272,8 +36412,9 @@ Examples:
|
|
|
36272
36412
|
});
|
|
36273
36413
|
} catch (error) {
|
|
36274
36414
|
if (error instanceof ToolError) throw error;
|
|
36415
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
36275
36416
|
throw new ToolError(
|
|
36276
|
-
`Failed to read coverage: ${
|
|
36417
|
+
`Failed to read coverage: ${msg}. Run run_tests with coverage: true first to generate coverage data.`,
|
|
36277
36418
|
{ tool: "get_coverage", cause: error instanceof Error ? error : void 0 }
|
|
36278
36419
|
);
|
|
36279
36420
|
}
|
|
@@ -36311,6 +36452,61 @@ init_registry4();
|
|
|
36311
36452
|
init_registry4();
|
|
36312
36453
|
init_errors();
|
|
36313
36454
|
init_allowed_paths();
|
|
36455
|
+
|
|
36456
|
+
// src/utils/file-suggestions.ts
|
|
36457
|
+
init_matcher();
|
|
36458
|
+
var MAX_DIR_ENTRIES = 200;
|
|
36459
|
+
var MAX_SUGGESTIONS = 5;
|
|
36460
|
+
async function suggestSimilarFiles(missingPath, options) {
|
|
36461
|
+
const absPath = path35__default.resolve(missingPath);
|
|
36462
|
+
const dir = path35__default.dirname(absPath);
|
|
36463
|
+
const target = path35__default.basename(absPath);
|
|
36464
|
+
const maxResults = MAX_SUGGESTIONS;
|
|
36465
|
+
try {
|
|
36466
|
+
const entries = await fs33__default.readdir(dir);
|
|
36467
|
+
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
36468
|
+
const scored = limited.map((name) => ({
|
|
36469
|
+
path: path35__default.join(dir, name),
|
|
36470
|
+
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
36471
|
+
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
36472
|
+
return scored.slice(0, maxResults);
|
|
36473
|
+
} catch {
|
|
36474
|
+
return [];
|
|
36475
|
+
}
|
|
36476
|
+
}
|
|
36477
|
+
async function suggestSimilarPaths(missingPath, options) {
|
|
36478
|
+
const fileSuggestions = await suggestSimilarFiles(missingPath);
|
|
36479
|
+
if (fileSuggestions.length > 0) return fileSuggestions;
|
|
36480
|
+
const absPath = path35__default.resolve(missingPath);
|
|
36481
|
+
const grandparent = path35__default.dirname(path35__default.dirname(absPath));
|
|
36482
|
+
const parentBasename = path35__default.basename(path35__default.dirname(absPath));
|
|
36483
|
+
const maxResults = MAX_SUGGESTIONS;
|
|
36484
|
+
try {
|
|
36485
|
+
const entries = await fs33__default.readdir(grandparent, { withFileTypes: true });
|
|
36486
|
+
const dirs = entries.filter((e) => e.isDirectory()).slice(0, MAX_DIR_ENTRIES);
|
|
36487
|
+
const scored = dirs.map((d) => ({
|
|
36488
|
+
path: path35__default.join(grandparent, d.name),
|
|
36489
|
+
distance: levenshtein(parentBasename.toLowerCase(), d.name.toLowerCase())
|
|
36490
|
+
})).filter((s) => s.distance <= Math.max(parentBasename.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
36491
|
+
return scored.slice(0, maxResults);
|
|
36492
|
+
} catch {
|
|
36493
|
+
return [];
|
|
36494
|
+
}
|
|
36495
|
+
}
|
|
36496
|
+
function formatSuggestions(suggestions, baseDir) {
|
|
36497
|
+
if (suggestions.length === 0) return "";
|
|
36498
|
+
const base = baseDir ?? process.cwd();
|
|
36499
|
+
const lines = suggestions.map((s) => {
|
|
36500
|
+
const rel = path35__default.relative(base, s.path);
|
|
36501
|
+
return ` - ${rel}`;
|
|
36502
|
+
});
|
|
36503
|
+
return `
|
|
36504
|
+
Did you mean?
|
|
36505
|
+
${lines.join("\n")}`;
|
|
36506
|
+
}
|
|
36507
|
+
|
|
36508
|
+
// src/tools/file.ts
|
|
36509
|
+
init_matcher();
|
|
36314
36510
|
var SENSITIVE_PATTERNS = [
|
|
36315
36511
|
/\.env(?:\.\w+)?$/,
|
|
36316
36512
|
// .env, .env.local, etc.
|
|
@@ -36335,7 +36531,7 @@ function hasNullByte2(str) {
|
|
|
36335
36531
|
}
|
|
36336
36532
|
function normalizePath2(filePath) {
|
|
36337
36533
|
let normalized = filePath.replace(/\0/g, "");
|
|
36338
|
-
normalized =
|
|
36534
|
+
normalized = path35__default.normalize(normalized);
|
|
36339
36535
|
return normalized;
|
|
36340
36536
|
}
|
|
36341
36537
|
function isPathAllowed(filePath, operation) {
|
|
@@ -36343,31 +36539,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
36343
36539
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
36344
36540
|
}
|
|
36345
36541
|
const normalized = normalizePath2(filePath);
|
|
36346
|
-
const absolute =
|
|
36542
|
+
const absolute = path35__default.resolve(normalized);
|
|
36347
36543
|
const cwd = process.cwd();
|
|
36348
36544
|
for (const blocked of BLOCKED_PATHS2) {
|
|
36349
|
-
const normalizedBlocked =
|
|
36350
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
36545
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
36546
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
36351
36547
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
36352
36548
|
}
|
|
36353
36549
|
}
|
|
36354
36550
|
const home = process.env.HOME;
|
|
36355
36551
|
if (home) {
|
|
36356
|
-
const normalizedHome =
|
|
36357
|
-
const normalizedCwd =
|
|
36552
|
+
const normalizedHome = path35__default.normalize(home);
|
|
36553
|
+
const normalizedCwd = path35__default.normalize(cwd);
|
|
36358
36554
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
36359
36555
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
36360
36556
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
36361
|
-
const basename4 =
|
|
36557
|
+
const basename4 = path35__default.basename(absolute);
|
|
36362
36558
|
if (!allowedHomeReads.includes(basename4)) {
|
|
36363
|
-
const targetDir =
|
|
36559
|
+
const targetDir = path35__default.dirname(absolute);
|
|
36364
36560
|
return {
|
|
36365
36561
|
allowed: false,
|
|
36366
36562
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
36367
36563
|
};
|
|
36368
36564
|
}
|
|
36369
36565
|
} else {
|
|
36370
|
-
const targetDir =
|
|
36566
|
+
const targetDir = path35__default.dirname(absolute);
|
|
36371
36567
|
return {
|
|
36372
36568
|
allowed: false,
|
|
36373
36569
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -36376,7 +36572,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
36376
36572
|
}
|
|
36377
36573
|
}
|
|
36378
36574
|
if (operation === "write" || operation === "delete") {
|
|
36379
|
-
const basename4 =
|
|
36575
|
+
const basename4 = path35__default.basename(absolute);
|
|
36380
36576
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
36381
36577
|
if (pattern.test(basename4)) {
|
|
36382
36578
|
return {
|
|
@@ -36395,6 +36591,24 @@ function validatePath(filePath, operation) {
|
|
|
36395
36591
|
}
|
|
36396
36592
|
}
|
|
36397
36593
|
var DEFAULT_MAX_FILE_SIZE = 10 * 1024 * 1024;
|
|
36594
|
+
function isENOENT(error) {
|
|
36595
|
+
return error.code === "ENOENT";
|
|
36596
|
+
}
|
|
36597
|
+
async function enrichENOENT(filePath, operation) {
|
|
36598
|
+
const absPath = path35__default.resolve(filePath);
|
|
36599
|
+
const suggestions = await suggestSimilarFiles(absPath);
|
|
36600
|
+
const hint = formatSuggestions(suggestions, path35__default.dirname(absPath));
|
|
36601
|
+
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
36602
|
+
return `File not found: ${filePath}${hint}
|
|
36603
|
+
${action}`;
|
|
36604
|
+
}
|
|
36605
|
+
async function enrichDirENOENT(dirPath) {
|
|
36606
|
+
const absPath = path35__default.resolve(dirPath);
|
|
36607
|
+
const suggestions = await suggestSimilarPaths(absPath);
|
|
36608
|
+
const hint = formatSuggestions(suggestions, path35__default.dirname(absPath));
|
|
36609
|
+
return `Directory not found: ${dirPath}${hint}
|
|
36610
|
+
Use list_dir or glob to find the correct path.`;
|
|
36611
|
+
}
|
|
36398
36612
|
var readFileTool = defineTool({
|
|
36399
36613
|
name: "read_file",
|
|
36400
36614
|
description: `Read the contents of a file.
|
|
@@ -36412,13 +36626,13 @@ Examples:
|
|
|
36412
36626
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
36413
36627
|
validatePath(filePath, "read");
|
|
36414
36628
|
try {
|
|
36415
|
-
const absolutePath =
|
|
36416
|
-
const stats = await
|
|
36629
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36630
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36417
36631
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
36418
36632
|
let truncated = false;
|
|
36419
36633
|
let content;
|
|
36420
36634
|
if (stats.size > maxBytes) {
|
|
36421
|
-
const handle = await
|
|
36635
|
+
const handle = await fs33__default.open(absolutePath, "r");
|
|
36422
36636
|
try {
|
|
36423
36637
|
const buffer = Buffer.alloc(maxBytes);
|
|
36424
36638
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -36428,7 +36642,7 @@ Examples:
|
|
|
36428
36642
|
await handle.close();
|
|
36429
36643
|
}
|
|
36430
36644
|
} else {
|
|
36431
|
-
content = await
|
|
36645
|
+
content = await fs33__default.readFile(absolutePath, encoding);
|
|
36432
36646
|
}
|
|
36433
36647
|
return {
|
|
36434
36648
|
content,
|
|
@@ -36437,6 +36651,14 @@ Examples:
|
|
|
36437
36651
|
truncated
|
|
36438
36652
|
};
|
|
36439
36653
|
} catch (error) {
|
|
36654
|
+
if (isENOENT(error)) {
|
|
36655
|
+
const enriched = await enrichENOENT(filePath, "read");
|
|
36656
|
+
throw new FileSystemError(enriched, {
|
|
36657
|
+
path: filePath,
|
|
36658
|
+
operation: "read",
|
|
36659
|
+
cause: error instanceof Error ? error : void 0
|
|
36660
|
+
});
|
|
36661
|
+
}
|
|
36440
36662
|
throw new FileSystemError(`Failed to read file: ${filePath}`, {
|
|
36441
36663
|
path: filePath,
|
|
36442
36664
|
operation: "read",
|
|
@@ -36463,10 +36685,10 @@ Examples:
|
|
|
36463
36685
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
36464
36686
|
validatePath(filePath, "write");
|
|
36465
36687
|
try {
|
|
36466
|
-
const absolutePath =
|
|
36688
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36467
36689
|
let wouldCreate = false;
|
|
36468
36690
|
try {
|
|
36469
|
-
await
|
|
36691
|
+
await fs33__default.access(absolutePath);
|
|
36470
36692
|
} catch {
|
|
36471
36693
|
wouldCreate = true;
|
|
36472
36694
|
}
|
|
@@ -36479,10 +36701,10 @@ Examples:
|
|
|
36479
36701
|
};
|
|
36480
36702
|
}
|
|
36481
36703
|
if (createDirs) {
|
|
36482
|
-
await
|
|
36704
|
+
await fs33__default.mkdir(path35__default.dirname(absolutePath), { recursive: true });
|
|
36483
36705
|
}
|
|
36484
|
-
await
|
|
36485
|
-
const stats = await
|
|
36706
|
+
await fs33__default.writeFile(absolutePath, content, "utf-8");
|
|
36707
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36486
36708
|
return {
|
|
36487
36709
|
path: absolutePath,
|
|
36488
36710
|
size: stats.size,
|
|
@@ -36490,6 +36712,14 @@ Examples:
|
|
|
36490
36712
|
wouldCreate
|
|
36491
36713
|
};
|
|
36492
36714
|
} catch (error) {
|
|
36715
|
+
if (isENOENT(error)) {
|
|
36716
|
+
const enriched = await enrichENOENT(filePath, "write");
|
|
36717
|
+
throw new FileSystemError(enriched, {
|
|
36718
|
+
path: filePath,
|
|
36719
|
+
operation: "write",
|
|
36720
|
+
cause: error instanceof Error ? error : void 0
|
|
36721
|
+
});
|
|
36722
|
+
}
|
|
36493
36723
|
throw new FileSystemError(`Failed to write file: ${filePath}`, {
|
|
36494
36724
|
path: filePath,
|
|
36495
36725
|
operation: "write",
|
|
@@ -36517,8 +36747,8 @@ Examples:
|
|
|
36517
36747
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
36518
36748
|
validatePath(filePath, "write");
|
|
36519
36749
|
try {
|
|
36520
|
-
const absolutePath =
|
|
36521
|
-
let content = await
|
|
36750
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36751
|
+
let content = await fs33__default.readFile(absolutePath, "utf-8");
|
|
36522
36752
|
let replacements = 0;
|
|
36523
36753
|
if (all) {
|
|
36524
36754
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -36532,7 +36762,31 @@ Examples:
|
|
|
36532
36762
|
}
|
|
36533
36763
|
}
|
|
36534
36764
|
if (replacements === 0) {
|
|
36535
|
-
|
|
36765
|
+
const lines = content.split("\n");
|
|
36766
|
+
const searchLine = (oldText.split("\n")[0] ?? oldText).trim().slice(0, 80);
|
|
36767
|
+
let bestIdx = -1;
|
|
36768
|
+
let bestDist = Infinity;
|
|
36769
|
+
for (let i = 0; i < lines.length; i++) {
|
|
36770
|
+
const dist = levenshtein(lines[i].trim().slice(0, 80), searchLine);
|
|
36771
|
+
if (dist < bestDist) {
|
|
36772
|
+
bestDist = dist;
|
|
36773
|
+
bestIdx = i;
|
|
36774
|
+
}
|
|
36775
|
+
}
|
|
36776
|
+
let context = "";
|
|
36777
|
+
if (bestIdx >= 0 && bestDist < searchLine.length * 0.6) {
|
|
36778
|
+
const start = Math.max(0, bestIdx - 2);
|
|
36779
|
+
const end = Math.min(lines.length, bestIdx + 3);
|
|
36780
|
+
const snippet = lines.slice(start, end).map((l, i) => ` ${start + i + 1}: ${l}`).join("\n");
|
|
36781
|
+
context = `
|
|
36782
|
+
|
|
36783
|
+
Closest match near line ${bestIdx + 1}:
|
|
36784
|
+
${snippet}`;
|
|
36785
|
+
}
|
|
36786
|
+
throw new Error(
|
|
36787
|
+
`Text not found in file: "${oldText.slice(0, 50)}..."${context}
|
|
36788
|
+
Hint: Use read_file first to verify the exact content.`
|
|
36789
|
+
);
|
|
36536
36790
|
}
|
|
36537
36791
|
if (dryRun) {
|
|
36538
36792
|
const preview = content.length > 500 ? content.slice(0, 500) + "..." : content;
|
|
@@ -36543,7 +36797,7 @@ Examples:
|
|
|
36543
36797
|
preview
|
|
36544
36798
|
};
|
|
36545
36799
|
}
|
|
36546
|
-
await
|
|
36800
|
+
await fs33__default.writeFile(absolutePath, content, "utf-8");
|
|
36547
36801
|
return {
|
|
36548
36802
|
path: absolutePath,
|
|
36549
36803
|
replacements,
|
|
@@ -36584,6 +36838,14 @@ Examples:
|
|
|
36584
36838
|
count: files.length
|
|
36585
36839
|
};
|
|
36586
36840
|
} catch (error) {
|
|
36841
|
+
if (isENOENT(error) && cwd) {
|
|
36842
|
+
const enriched = await enrichDirENOENT(cwd);
|
|
36843
|
+
throw new FileSystemError(`Glob search failed \u2014 ${enriched}`, {
|
|
36844
|
+
path: cwd,
|
|
36845
|
+
operation: "glob",
|
|
36846
|
+
cause: error instanceof Error ? error : void 0
|
|
36847
|
+
});
|
|
36848
|
+
}
|
|
36587
36849
|
throw new FileSystemError(`Glob search failed: ${pattern}`, {
|
|
36588
36850
|
path: cwd ?? process.cwd(),
|
|
36589
36851
|
operation: "glob",
|
|
@@ -36606,8 +36868,8 @@ Examples:
|
|
|
36606
36868
|
}),
|
|
36607
36869
|
async execute({ path: filePath }) {
|
|
36608
36870
|
try {
|
|
36609
|
-
const absolutePath =
|
|
36610
|
-
const stats = await
|
|
36871
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36872
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36611
36873
|
return {
|
|
36612
36874
|
exists: true,
|
|
36613
36875
|
isFile: stats.isFile(),
|
|
@@ -36637,12 +36899,12 @@ Examples:
|
|
|
36637
36899
|
}),
|
|
36638
36900
|
async execute({ path: dirPath, recursive }) {
|
|
36639
36901
|
try {
|
|
36640
|
-
const absolutePath =
|
|
36902
|
+
const absolutePath = path35__default.resolve(dirPath);
|
|
36641
36903
|
const entries = [];
|
|
36642
36904
|
async function listDir(dir, prefix = "") {
|
|
36643
|
-
const items = await
|
|
36905
|
+
const items = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
36644
36906
|
for (const item of items) {
|
|
36645
|
-
const fullPath =
|
|
36907
|
+
const fullPath = path35__default.join(dir, item.name);
|
|
36646
36908
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
36647
36909
|
if (item.isDirectory()) {
|
|
36648
36910
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -36650,7 +36912,7 @@ Examples:
|
|
|
36650
36912
|
await listDir(fullPath, relativePath);
|
|
36651
36913
|
}
|
|
36652
36914
|
} else if (item.isFile()) {
|
|
36653
|
-
const stats = await
|
|
36915
|
+
const stats = await fs33__default.stat(fullPath);
|
|
36654
36916
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
36655
36917
|
}
|
|
36656
36918
|
}
|
|
@@ -36658,6 +36920,14 @@ Examples:
|
|
|
36658
36920
|
await listDir(absolutePath);
|
|
36659
36921
|
return { entries };
|
|
36660
36922
|
} catch (error) {
|
|
36923
|
+
if (isENOENT(error)) {
|
|
36924
|
+
const enriched = await enrichDirENOENT(dirPath);
|
|
36925
|
+
throw new FileSystemError(enriched, {
|
|
36926
|
+
path: dirPath,
|
|
36927
|
+
operation: "read",
|
|
36928
|
+
cause: error instanceof Error ? error : void 0
|
|
36929
|
+
});
|
|
36930
|
+
}
|
|
36661
36931
|
throw new FileSystemError(`Failed to list directory: ${dirPath}`, {
|
|
36662
36932
|
path: dirPath,
|
|
36663
36933
|
operation: "read",
|
|
@@ -36689,23 +36959,23 @@ Examples:
|
|
|
36689
36959
|
}
|
|
36690
36960
|
validatePath(filePath, "delete");
|
|
36691
36961
|
try {
|
|
36692
|
-
const absolutePath =
|
|
36693
|
-
const stats = await
|
|
36962
|
+
const absolutePath = path35__default.resolve(filePath);
|
|
36963
|
+
const stats = await fs33__default.stat(absolutePath);
|
|
36694
36964
|
if (stats.isDirectory()) {
|
|
36695
36965
|
if (!recursive) {
|
|
36696
36966
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
36697
36967
|
tool: "delete_file"
|
|
36698
36968
|
});
|
|
36699
36969
|
}
|
|
36700
|
-
await
|
|
36970
|
+
await fs33__default.rm(absolutePath, { recursive: true });
|
|
36701
36971
|
} else {
|
|
36702
|
-
await
|
|
36972
|
+
await fs33__default.unlink(absolutePath);
|
|
36703
36973
|
}
|
|
36704
36974
|
return { deleted: true, path: absolutePath };
|
|
36705
36975
|
} catch (error) {
|
|
36706
36976
|
if (error instanceof ToolError) throw error;
|
|
36707
36977
|
if (error.code === "ENOENT") {
|
|
36708
|
-
return { deleted: false, path:
|
|
36978
|
+
return { deleted: false, path: path35__default.resolve(filePath) };
|
|
36709
36979
|
}
|
|
36710
36980
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
36711
36981
|
path: filePath,
|
|
@@ -36733,11 +37003,11 @@ Examples:
|
|
|
36733
37003
|
validatePath(source, "read");
|
|
36734
37004
|
validatePath(destination, "write");
|
|
36735
37005
|
try {
|
|
36736
|
-
const srcPath =
|
|
36737
|
-
const destPath =
|
|
37006
|
+
const srcPath = path35__default.resolve(source);
|
|
37007
|
+
const destPath = path35__default.resolve(destination);
|
|
36738
37008
|
if (!overwrite) {
|
|
36739
37009
|
try {
|
|
36740
|
-
await
|
|
37010
|
+
await fs33__default.access(destPath);
|
|
36741
37011
|
throw new ToolError(
|
|
36742
37012
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
36743
37013
|
{
|
|
@@ -36750,9 +37020,9 @@ Examples:
|
|
|
36750
37020
|
}
|
|
36751
37021
|
}
|
|
36752
37022
|
}
|
|
36753
|
-
await
|
|
36754
|
-
await
|
|
36755
|
-
const stats = await
|
|
37023
|
+
await fs33__default.mkdir(path35__default.dirname(destPath), { recursive: true });
|
|
37024
|
+
await fs33__default.copyFile(srcPath, destPath);
|
|
37025
|
+
const stats = await fs33__default.stat(destPath);
|
|
36756
37026
|
return {
|
|
36757
37027
|
source: srcPath,
|
|
36758
37028
|
destination: destPath,
|
|
@@ -36760,6 +37030,14 @@ Examples:
|
|
|
36760
37030
|
};
|
|
36761
37031
|
} catch (error) {
|
|
36762
37032
|
if (error instanceof ToolError) throw error;
|
|
37033
|
+
if (isENOENT(error)) {
|
|
37034
|
+
const enriched = await enrichENOENT(source, "read");
|
|
37035
|
+
throw new FileSystemError(`Failed to copy \u2014 ${enriched}`, {
|
|
37036
|
+
path: source,
|
|
37037
|
+
operation: "read",
|
|
37038
|
+
cause: error instanceof Error ? error : void 0
|
|
37039
|
+
});
|
|
37040
|
+
}
|
|
36763
37041
|
throw new FileSystemError(`Failed to copy file: ${source} -> ${destination}`, {
|
|
36764
37042
|
path: source,
|
|
36765
37043
|
operation: "read",
|
|
@@ -36786,11 +37064,11 @@ Examples:
|
|
|
36786
37064
|
validatePath(source, "delete");
|
|
36787
37065
|
validatePath(destination, "write");
|
|
36788
37066
|
try {
|
|
36789
|
-
const srcPath =
|
|
36790
|
-
const destPath =
|
|
37067
|
+
const srcPath = path35__default.resolve(source);
|
|
37068
|
+
const destPath = path35__default.resolve(destination);
|
|
36791
37069
|
if (!overwrite) {
|
|
36792
37070
|
try {
|
|
36793
|
-
await
|
|
37071
|
+
await fs33__default.access(destPath);
|
|
36794
37072
|
throw new ToolError(
|
|
36795
37073
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
36796
37074
|
{
|
|
@@ -36803,14 +37081,22 @@ Examples:
|
|
|
36803
37081
|
}
|
|
36804
37082
|
}
|
|
36805
37083
|
}
|
|
36806
|
-
await
|
|
36807
|
-
await
|
|
37084
|
+
await fs33__default.mkdir(path35__default.dirname(destPath), { recursive: true });
|
|
37085
|
+
await fs33__default.rename(srcPath, destPath);
|
|
36808
37086
|
return {
|
|
36809
37087
|
source: srcPath,
|
|
36810
37088
|
destination: destPath
|
|
36811
37089
|
};
|
|
36812
37090
|
} catch (error) {
|
|
36813
37091
|
if (error instanceof ToolError) throw error;
|
|
37092
|
+
if (isENOENT(error)) {
|
|
37093
|
+
const enriched = await enrichENOENT(source, "read");
|
|
37094
|
+
throw new FileSystemError(`Failed to move \u2014 ${enriched}`, {
|
|
37095
|
+
path: source,
|
|
37096
|
+
operation: "write",
|
|
37097
|
+
cause: error instanceof Error ? error : void 0
|
|
37098
|
+
});
|
|
37099
|
+
}
|
|
36814
37100
|
throw new FileSystemError(`Failed to move file: ${source} -> ${destination}`, {
|
|
36815
37101
|
path: source,
|
|
36816
37102
|
operation: "write",
|
|
@@ -36838,13 +37124,13 @@ Examples:
|
|
|
36838
37124
|
}),
|
|
36839
37125
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
36840
37126
|
try {
|
|
36841
|
-
const absolutePath =
|
|
37127
|
+
const absolutePath = path35__default.resolve(dirPath ?? ".");
|
|
36842
37128
|
let totalFiles = 0;
|
|
36843
37129
|
let totalDirs = 0;
|
|
36844
|
-
const lines = [
|
|
37130
|
+
const lines = [path35__default.basename(absolutePath) + "/"];
|
|
36845
37131
|
async function buildTree(dir, prefix, currentDepth) {
|
|
36846
37132
|
if (currentDepth > (depth ?? 4)) return;
|
|
36847
|
-
let items = await
|
|
37133
|
+
let items = await fs33__default.readdir(dir, { withFileTypes: true });
|
|
36848
37134
|
if (!showHidden) {
|
|
36849
37135
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
36850
37136
|
}
|
|
@@ -36864,7 +37150,7 @@ Examples:
|
|
|
36864
37150
|
if (item.isDirectory()) {
|
|
36865
37151
|
totalDirs++;
|
|
36866
37152
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
36867
|
-
await buildTree(
|
|
37153
|
+
await buildTree(path35__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
36868
37154
|
} else {
|
|
36869
37155
|
totalFiles++;
|
|
36870
37156
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -36878,6 +37164,14 @@ Examples:
|
|
|
36878
37164
|
totalDirs
|
|
36879
37165
|
};
|
|
36880
37166
|
} catch (error) {
|
|
37167
|
+
if (isENOENT(error)) {
|
|
37168
|
+
const enriched = await enrichDirENOENT(dirPath ?? ".");
|
|
37169
|
+
throw new FileSystemError(enriched, {
|
|
37170
|
+
path: dirPath ?? ".",
|
|
37171
|
+
operation: "read",
|
|
37172
|
+
cause: error instanceof Error ? error : void 0
|
|
37173
|
+
});
|
|
37174
|
+
}
|
|
36881
37175
|
throw new FileSystemError(`Failed to generate tree: ${dirPath}`, {
|
|
36882
37176
|
path: dirPath ?? ".",
|
|
36883
37177
|
operation: "read",
|
|
@@ -37185,7 +37479,7 @@ Examples:
|
|
|
37185
37479
|
caseSensitive,
|
|
37186
37480
|
wholeWord
|
|
37187
37481
|
}) {
|
|
37188
|
-
const targetPath = searchPath ?
|
|
37482
|
+
const targetPath = searchPath ? path35__default.resolve(searchPath) : process.cwd();
|
|
37189
37483
|
const matches = [];
|
|
37190
37484
|
let filesSearched = 0;
|
|
37191
37485
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -37207,7 +37501,7 @@ Examples:
|
|
|
37207
37501
|
tool: "grep"
|
|
37208
37502
|
});
|
|
37209
37503
|
}
|
|
37210
|
-
const stats = await
|
|
37504
|
+
const stats = await fs33__default.stat(targetPath);
|
|
37211
37505
|
let filesToSearch;
|
|
37212
37506
|
if (stats.isFile()) {
|
|
37213
37507
|
filesToSearch = [targetPath];
|
|
@@ -37229,7 +37523,7 @@ Examples:
|
|
|
37229
37523
|
}
|
|
37230
37524
|
filesSearched++;
|
|
37231
37525
|
try {
|
|
37232
|
-
const content = await
|
|
37526
|
+
const content = await fs33__default.readFile(file, "utf-8");
|
|
37233
37527
|
const lines = content.split("\n");
|
|
37234
37528
|
let fileHasMatch = false;
|
|
37235
37529
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -37252,7 +37546,7 @@ Examples:
|
|
|
37252
37546
|
contextAfter.push(lines[j] ?? "");
|
|
37253
37547
|
}
|
|
37254
37548
|
matches.push({
|
|
37255
|
-
file:
|
|
37549
|
+
file: path35__default.relative(process.cwd(), file),
|
|
37256
37550
|
line: i + 1,
|
|
37257
37551
|
column: match.index + 1,
|
|
37258
37552
|
content: line,
|
|
@@ -37303,8 +37597,8 @@ Examples:
|
|
|
37303
37597
|
}),
|
|
37304
37598
|
async execute({ file, pattern, caseSensitive }) {
|
|
37305
37599
|
try {
|
|
37306
|
-
const absolutePath =
|
|
37307
|
-
const content = await
|
|
37600
|
+
const absolutePath = path35__default.resolve(file);
|
|
37601
|
+
const content = await fs33__default.readFile(absolutePath, "utf-8");
|
|
37308
37602
|
const lines = content.split("\n");
|
|
37309
37603
|
const matches = [];
|
|
37310
37604
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -37320,6 +37614,11 @@ Examples:
|
|
|
37320
37614
|
}
|
|
37321
37615
|
return { matches, count: matches.length };
|
|
37322
37616
|
} catch (error) {
|
|
37617
|
+
if (error.code === "ENOENT") {
|
|
37618
|
+
throw new ToolError(`File not found: ${file}. Use glob to find the correct path.`, {
|
|
37619
|
+
tool: "find_in_file"
|
|
37620
|
+
});
|
|
37621
|
+
}
|
|
37323
37622
|
throw new ToolError(
|
|
37324
37623
|
`Find in file failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
37325
37624
|
{ tool: "find_in_file", cause: error instanceof Error ? error : void 0 }
|
|
@@ -37480,6 +37779,22 @@ init_registry4();
|
|
|
37480
37779
|
init_errors();
|
|
37481
37780
|
var DEFAULT_TIMEOUT_MS3 = 6e5;
|
|
37482
37781
|
var MAX_OUTPUT_SIZE2 = 2 * 1024 * 1024;
|
|
37782
|
+
function getBuildHint(stderr, tool) {
|
|
37783
|
+
if (/MODULE_NOT_FOUND|Cannot find module/i.test(stderr))
|
|
37784
|
+
return "A dependency is missing. Run install_deps first.";
|
|
37785
|
+
if (/ENOENT|no such file/i.test(stderr))
|
|
37786
|
+
return "A file or directory was not found. Use glob or list_dir to verify paths.";
|
|
37787
|
+
if (/EACCES|permission denied/i.test(stderr)) return "Permission denied. Check file permissions.";
|
|
37788
|
+
if (/SyntaxError|Unexpected token/i.test(stderr))
|
|
37789
|
+
return "Syntax error in the code. Use read_file to check the problematic file.";
|
|
37790
|
+
if (/TS\d{4}:/i.test(stderr))
|
|
37791
|
+
return "TypeScript compilation error. Read the error details above and use edit_file to fix.";
|
|
37792
|
+
if (/ERR!/i.test(stderr) && tool === "install_deps")
|
|
37793
|
+
return "Package install failed. Check if the package name is correct or if there are network issues.";
|
|
37794
|
+
if (/No Makefile/i.test(stderr) || /No rule to make target/i.test(stderr))
|
|
37795
|
+
return "Makefile target not found. Check available targets with 'make -n' or list_dir.";
|
|
37796
|
+
return `${tool} failed. Check stderr output above for details.`;
|
|
37797
|
+
}
|
|
37483
37798
|
async function detectPackageManager2(cwd) {
|
|
37484
37799
|
const lockfiles = [
|
|
37485
37800
|
{ file: "pnpm-lock.yaml", pm: "pnpm" },
|
|
@@ -37489,7 +37804,7 @@ async function detectPackageManager2(cwd) {
|
|
|
37489
37804
|
];
|
|
37490
37805
|
for (const { file, pm } of lockfiles) {
|
|
37491
37806
|
try {
|
|
37492
|
-
await
|
|
37807
|
+
await fs33__default.access(path35__default.join(cwd, file));
|
|
37493
37808
|
return pm;
|
|
37494
37809
|
} catch {
|
|
37495
37810
|
}
|
|
@@ -37572,7 +37887,7 @@ ${message}
|
|
|
37572
37887
|
heartbeat.activity();
|
|
37573
37888
|
});
|
|
37574
37889
|
const result = await subprocess;
|
|
37575
|
-
|
|
37890
|
+
const buildResult2 = {
|
|
37576
37891
|
success: result.exitCode === 0,
|
|
37577
37892
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37578
37893
|
stderr: truncateOutput2(stderrBuffer),
|
|
@@ -37580,6 +37895,10 @@ ${message}
|
|
|
37580
37895
|
duration: performance.now() - startTime,
|
|
37581
37896
|
packageManager: pm
|
|
37582
37897
|
};
|
|
37898
|
+
if (!buildResult2.success) {
|
|
37899
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "run_script");
|
|
37900
|
+
}
|
|
37901
|
+
return buildResult2;
|
|
37583
37902
|
} catch (error) {
|
|
37584
37903
|
if (error.timedOut) {
|
|
37585
37904
|
throw new TimeoutError(`Script '${script}' timed out after ${timeoutMs}ms`, {
|
|
@@ -37693,7 +38012,7 @@ ${message}
|
|
|
37693
38012
|
heartbeat.activity();
|
|
37694
38013
|
});
|
|
37695
38014
|
const result = await subprocess;
|
|
37696
|
-
|
|
38015
|
+
const buildResult2 = {
|
|
37697
38016
|
success: result.exitCode === 0,
|
|
37698
38017
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37699
38018
|
stderr: truncateOutput2(stderrBuffer),
|
|
@@ -37701,6 +38020,10 @@ ${message}
|
|
|
37701
38020
|
duration: performance.now() - startTime,
|
|
37702
38021
|
packageManager: pm
|
|
37703
38022
|
};
|
|
38023
|
+
if (!buildResult2.success) {
|
|
38024
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "install_deps");
|
|
38025
|
+
}
|
|
38026
|
+
return buildResult2;
|
|
37704
38027
|
} catch (error) {
|
|
37705
38028
|
if (error.timedOut) {
|
|
37706
38029
|
throw new TimeoutError(`Install timed out after ${timeoutMs}ms`, {
|
|
@@ -37754,7 +38077,7 @@ ${message}
|
|
|
37754
38077
|
});
|
|
37755
38078
|
try {
|
|
37756
38079
|
try {
|
|
37757
|
-
await
|
|
38080
|
+
await fs33__default.access(path35__default.join(projectDir, "Makefile"));
|
|
37758
38081
|
} catch {
|
|
37759
38082
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
37760
38083
|
}
|
|
@@ -37791,13 +38114,17 @@ ${message}
|
|
|
37791
38114
|
heartbeat.activity();
|
|
37792
38115
|
});
|
|
37793
38116
|
const result = await subprocess;
|
|
37794
|
-
|
|
38117
|
+
const buildResult2 = {
|
|
37795
38118
|
success: result.exitCode === 0,
|
|
37796
38119
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37797
38120
|
stderr: truncateOutput2(stderrBuffer),
|
|
37798
38121
|
exitCode: result.exitCode ?? 0,
|
|
37799
38122
|
duration: performance.now() - startTime
|
|
37800
38123
|
};
|
|
38124
|
+
if (!buildResult2.success) {
|
|
38125
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "make");
|
|
38126
|
+
}
|
|
38127
|
+
return buildResult2;
|
|
37801
38128
|
} catch (error) {
|
|
37802
38129
|
if (error instanceof ToolError) throw error;
|
|
37803
38130
|
if (error.timedOut) {
|
|
@@ -37890,13 +38217,17 @@ ${message}
|
|
|
37890
38217
|
heartbeat.activity();
|
|
37891
38218
|
});
|
|
37892
38219
|
const result = await subprocess;
|
|
37893
|
-
|
|
38220
|
+
const buildResult2 = {
|
|
37894
38221
|
success: result.exitCode === 0,
|
|
37895
38222
|
stdout: truncateOutput2(stdoutBuffer),
|
|
37896
38223
|
stderr: truncateOutput2(stderrBuffer),
|
|
37897
38224
|
exitCode: result.exitCode ?? 0,
|
|
37898
38225
|
duration: performance.now() - startTime
|
|
37899
38226
|
};
|
|
38227
|
+
if (!buildResult2.success) {
|
|
38228
|
+
buildResult2.hint = getBuildHint(stderrBuffer || stdoutBuffer, "tsc");
|
|
38229
|
+
}
|
|
38230
|
+
return buildResult2;
|
|
37900
38231
|
} catch (error) {
|
|
37901
38232
|
if (error.timedOut) {
|
|
37902
38233
|
throw new TimeoutError(`TypeScript compile timed out after ${timeoutMs}ms`, {
|
|
@@ -38099,9 +38430,10 @@ async function searchDuckDuckGo(query, maxResults, timeout) {
|
|
|
38099
38430
|
});
|
|
38100
38431
|
clearTimeout(timeoutId);
|
|
38101
38432
|
if (!response.ok) {
|
|
38102
|
-
throw new ToolError(
|
|
38103
|
-
|
|
38104
|
-
|
|
38433
|
+
throw new ToolError(
|
|
38434
|
+
`DuckDuckGo search failed with status ${response.status}. Try a different search engine (brave, serpapi) or simplify the query.`,
|
|
38435
|
+
{ tool: "web_search" }
|
|
38436
|
+
);
|
|
38105
38437
|
}
|
|
38106
38438
|
const html = await response.text();
|
|
38107
38439
|
return parseDuckDuckGoResults(html, maxResults);
|
|
@@ -38132,9 +38464,10 @@ async function searchBrave(query, maxResults, timeout) {
|
|
|
38132
38464
|
});
|
|
38133
38465
|
clearTimeout(timeoutId);
|
|
38134
38466
|
if (!response.ok) {
|
|
38135
|
-
throw new ToolError(
|
|
38136
|
-
|
|
38137
|
-
|
|
38467
|
+
throw new ToolError(
|
|
38468
|
+
`Brave search failed with status ${response.status}. Try a different search engine (duckduckgo, serpapi) or check your BRAVE_SEARCH_API_KEY.`,
|
|
38469
|
+
{ tool: "web_search" }
|
|
38470
|
+
);
|
|
38138
38471
|
}
|
|
38139
38472
|
const data = await response.json();
|
|
38140
38473
|
return (data.web?.results ?? []).slice(0, maxResults).map((r) => ({
|
|
@@ -38168,9 +38501,10 @@ async function searchSerpApi(query, maxResults, timeout) {
|
|
|
38168
38501
|
});
|
|
38169
38502
|
clearTimeout(timeoutId);
|
|
38170
38503
|
if (!response.ok) {
|
|
38171
|
-
throw new ToolError(
|
|
38172
|
-
|
|
38173
|
-
|
|
38504
|
+
throw new ToolError(
|
|
38505
|
+
`SerpAPI search failed with status ${response.status}. Try a different search engine (duckduckgo, brave) or check your SERPAPI_KEY.`,
|
|
38506
|
+
{ tool: "web_search" }
|
|
38507
|
+
);
|
|
38174
38508
|
}
|
|
38175
38509
|
const data = await response.json();
|
|
38176
38510
|
return (data.organic_results ?? []).slice(0, maxResults).map((r) => ({
|
|
@@ -38260,6 +38594,27 @@ var PRIVATE_IP_PATTERNS = [
|
|
|
38260
38594
|
/^https?:\/\/0\.0\.0\.0/,
|
|
38261
38595
|
/^https?:\/\/\[::1\]/
|
|
38262
38596
|
];
|
|
38597
|
+
function getHttpErrorHint(status) {
|
|
38598
|
+
switch (status) {
|
|
38599
|
+
case 401:
|
|
38600
|
+
case 403:
|
|
38601
|
+
return "\nThis page requires authentication. Try using web_search to find a publicly accessible alternative.";
|
|
38602
|
+
case 404:
|
|
38603
|
+
return "\nPage not found. The URL may be outdated or misspelled. Try web_search to find the correct URL.";
|
|
38604
|
+
case 429:
|
|
38605
|
+
return "\nRate limited. Wait a moment before retrying, or try an alternative source.";
|
|
38606
|
+
case 500:
|
|
38607
|
+
case 502:
|
|
38608
|
+
case 503:
|
|
38609
|
+
case 504:
|
|
38610
|
+
return "\nServer error (temporary). Try again in a moment, or use web_search to find an alternative source.";
|
|
38611
|
+
default:
|
|
38612
|
+
if (status >= 400 && status < 500) {
|
|
38613
|
+
return "\nClient error. Check the URL is correct or try web_search to find the right page.";
|
|
38614
|
+
}
|
|
38615
|
+
return "";
|
|
38616
|
+
}
|
|
38617
|
+
}
|
|
38263
38618
|
function validateUrl(url) {
|
|
38264
38619
|
for (const scheme of BLOCKED_SCHEMES) {
|
|
38265
38620
|
if (url.toLowerCase().startsWith(scheme)) {
|
|
@@ -38478,7 +38833,8 @@ Examples:
|
|
|
38478
38833
|
});
|
|
38479
38834
|
clearTimeout(timeoutId);
|
|
38480
38835
|
if (!response.ok) {
|
|
38481
|
-
|
|
38836
|
+
const hint = getHttpErrorHint(response.status);
|
|
38837
|
+
throw new ToolError(`HTTP ${response.status}: ${response.statusText} \u2014 ${url}${hint}`, {
|
|
38482
38838
|
tool: "web_fetch"
|
|
38483
38839
|
});
|
|
38484
38840
|
}
|
|
@@ -38568,8 +38924,8 @@ init_review();
|
|
|
38568
38924
|
// src/tools/codebase-map.ts
|
|
38569
38925
|
init_registry4();
|
|
38570
38926
|
init_errors();
|
|
38571
|
-
var
|
|
38572
|
-
var
|
|
38927
|
+
var fs36 = await import('fs/promises');
|
|
38928
|
+
var path38 = await import('path');
|
|
38573
38929
|
var { glob: glob14 } = await import('glob');
|
|
38574
38930
|
var DEFAULT_MAX_FILES = 200;
|
|
38575
38931
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -38595,7 +38951,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
38595
38951
|
"**/*.d.ts"
|
|
38596
38952
|
];
|
|
38597
38953
|
function detectLanguage3(filePath) {
|
|
38598
|
-
const ext =
|
|
38954
|
+
const ext = path38.extname(filePath).toLowerCase();
|
|
38599
38955
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
38600
38956
|
if (extensions.includes(ext)) return lang;
|
|
38601
38957
|
}
|
|
@@ -39004,9 +39360,9 @@ Examples:
|
|
|
39004
39360
|
}),
|
|
39005
39361
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
39006
39362
|
const startTime = performance.now();
|
|
39007
|
-
const absPath =
|
|
39363
|
+
const absPath = path38.resolve(rootPath);
|
|
39008
39364
|
try {
|
|
39009
|
-
const stat2 = await
|
|
39365
|
+
const stat2 = await fs36.stat(absPath);
|
|
39010
39366
|
if (!stat2.isDirectory()) {
|
|
39011
39367
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
39012
39368
|
tool: "codebase_map"
|
|
@@ -39043,14 +39399,14 @@ Examples:
|
|
|
39043
39399
|
let totalDefinitions = 0;
|
|
39044
39400
|
let exportedSymbols = 0;
|
|
39045
39401
|
for (const file of limitedFiles) {
|
|
39046
|
-
const fullPath =
|
|
39402
|
+
const fullPath = path38.join(absPath, file);
|
|
39047
39403
|
const language = detectLanguage3(file);
|
|
39048
39404
|
if (!language) continue;
|
|
39049
39405
|
if (languages && !languages.includes(language)) {
|
|
39050
39406
|
continue;
|
|
39051
39407
|
}
|
|
39052
39408
|
try {
|
|
39053
|
-
const content = await
|
|
39409
|
+
const content = await fs36.readFile(fullPath, "utf-8");
|
|
39054
39410
|
const lineCount = content.split("\n").length;
|
|
39055
39411
|
const parsed = parseFile(content, language);
|
|
39056
39412
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -39087,23 +39443,23 @@ var codebaseMapTools = [codebaseMapTool];
|
|
|
39087
39443
|
init_registry4();
|
|
39088
39444
|
init_errors();
|
|
39089
39445
|
init_paths();
|
|
39090
|
-
var
|
|
39091
|
-
var
|
|
39446
|
+
var fs37 = await import('fs/promises');
|
|
39447
|
+
var path39 = await import('path');
|
|
39092
39448
|
var crypto2 = await import('crypto');
|
|
39093
|
-
var GLOBAL_MEMORIES_DIR =
|
|
39449
|
+
var GLOBAL_MEMORIES_DIR = path39.join(COCO_HOME, "memories");
|
|
39094
39450
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
39095
39451
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
39096
39452
|
async function ensureDir2(dirPath) {
|
|
39097
|
-
await
|
|
39453
|
+
await fs37.mkdir(dirPath, { recursive: true });
|
|
39098
39454
|
}
|
|
39099
39455
|
function getMemoriesDir(scope) {
|
|
39100
39456
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
39101
39457
|
}
|
|
39102
39458
|
async function loadIndex(scope) {
|
|
39103
39459
|
const dir = getMemoriesDir(scope);
|
|
39104
|
-
const indexPath =
|
|
39460
|
+
const indexPath = path39.join(dir, "index.json");
|
|
39105
39461
|
try {
|
|
39106
|
-
const content = await
|
|
39462
|
+
const content = await fs37.readFile(indexPath, "utf-8");
|
|
39107
39463
|
return JSON.parse(content);
|
|
39108
39464
|
} catch {
|
|
39109
39465
|
return [];
|
|
@@ -39112,14 +39468,14 @@ async function loadIndex(scope) {
|
|
|
39112
39468
|
async function saveIndex(scope, index) {
|
|
39113
39469
|
const dir = getMemoriesDir(scope);
|
|
39114
39470
|
await ensureDir2(dir);
|
|
39115
|
-
const indexPath =
|
|
39116
|
-
await
|
|
39471
|
+
const indexPath = path39.join(dir, "index.json");
|
|
39472
|
+
await fs37.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
39117
39473
|
}
|
|
39118
39474
|
async function loadMemory(scope, id) {
|
|
39119
39475
|
const dir = getMemoriesDir(scope);
|
|
39120
|
-
const memPath =
|
|
39476
|
+
const memPath = path39.join(dir, `${id}.json`);
|
|
39121
39477
|
try {
|
|
39122
|
-
const content = await
|
|
39478
|
+
const content = await fs37.readFile(memPath, "utf-8");
|
|
39123
39479
|
return JSON.parse(content);
|
|
39124
39480
|
} catch {
|
|
39125
39481
|
return null;
|
|
@@ -39128,8 +39484,8 @@ async function loadMemory(scope, id) {
|
|
|
39128
39484
|
async function saveMemory(scope, memory) {
|
|
39129
39485
|
const dir = getMemoriesDir(scope);
|
|
39130
39486
|
await ensureDir2(dir);
|
|
39131
|
-
const memPath =
|
|
39132
|
-
await
|
|
39487
|
+
const memPath = path39.join(dir, `${memory.id}.json`);
|
|
39488
|
+
await fs37.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
39133
39489
|
}
|
|
39134
39490
|
var createMemoryTool = defineTool({
|
|
39135
39491
|
name: "create_memory",
|
|
@@ -39285,17 +39641,17 @@ var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
|
39285
39641
|
// src/tools/checkpoint.ts
|
|
39286
39642
|
init_registry4();
|
|
39287
39643
|
init_errors();
|
|
39288
|
-
var
|
|
39644
|
+
var fs38 = await import('fs/promises');
|
|
39289
39645
|
var crypto3 = await import('crypto');
|
|
39290
39646
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
39291
39647
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
39292
39648
|
var STASH_PREFIX = "coco-cp";
|
|
39293
39649
|
async function ensureCocoDir() {
|
|
39294
|
-
await
|
|
39650
|
+
await fs38.mkdir(".coco", { recursive: true });
|
|
39295
39651
|
}
|
|
39296
39652
|
async function loadCheckpoints() {
|
|
39297
39653
|
try {
|
|
39298
|
-
const content = await
|
|
39654
|
+
const content = await fs38.readFile(CHECKPOINT_FILE, "utf-8");
|
|
39299
39655
|
return JSON.parse(content);
|
|
39300
39656
|
} catch {
|
|
39301
39657
|
return [];
|
|
@@ -39303,7 +39659,7 @@ async function loadCheckpoints() {
|
|
|
39303
39659
|
}
|
|
39304
39660
|
async function saveCheckpoints(checkpoints) {
|
|
39305
39661
|
await ensureCocoDir();
|
|
39306
|
-
await
|
|
39662
|
+
await fs38.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
39307
39663
|
}
|
|
39308
39664
|
async function execGit(args) {
|
|
39309
39665
|
const { execaCommand } = await import('execa');
|
|
@@ -39314,10 +39670,11 @@ async function execGit(args) {
|
|
|
39314
39670
|
});
|
|
39315
39671
|
return result.stdout;
|
|
39316
39672
|
} catch (error) {
|
|
39317
|
-
|
|
39318
|
-
|
|
39319
|
-
|
|
39320
|
-
|
|
39673
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
39674
|
+
let hint = `Git command failed (${args[0] ?? "unknown"}): ${msg}`;
|
|
39675
|
+
if (/not a git repository/i.test(msg))
|
|
39676
|
+
hint = "Not a git repository. Checkpoints require a git repo \u2014 run git_init first.";
|
|
39677
|
+
throw new ToolError(hint, { tool: "checkpoint" });
|
|
39321
39678
|
}
|
|
39322
39679
|
}
|
|
39323
39680
|
async function getChangedFiles() {
|
|
@@ -39435,8 +39792,9 @@ Examples:
|
|
|
39435
39792
|
message: `Restored checkpoint '${checkpoint.description}' (${checkpoint.fileCount} files)`
|
|
39436
39793
|
};
|
|
39437
39794
|
} catch (error) {
|
|
39795
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
39438
39796
|
throw new ToolError(
|
|
39439
|
-
`Failed to restore checkpoint: ${
|
|
39797
|
+
`Failed to restore checkpoint: ${msg}. Use list_checkpoints to see available checkpoints.`,
|
|
39440
39798
|
{ tool: "restore_checkpoint" }
|
|
39441
39799
|
);
|
|
39442
39800
|
}
|
|
@@ -39466,8 +39824,8 @@ var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpoi
|
|
|
39466
39824
|
|
|
39467
39825
|
// src/tools/semantic-search.ts
|
|
39468
39826
|
init_registry4();
|
|
39469
|
-
var
|
|
39470
|
-
var
|
|
39827
|
+
var fs39 = await import('fs/promises');
|
|
39828
|
+
var path40 = await import('path');
|
|
39471
39829
|
var { glob: glob15 } = await import('glob');
|
|
39472
39830
|
var INDEX_DIR = ".coco/search-index";
|
|
39473
39831
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -39573,6 +39931,7 @@ function simpleEmbedding(text13) {
|
|
|
39573
39931
|
return vector;
|
|
39574
39932
|
}
|
|
39575
39933
|
var embedFn = null;
|
|
39934
|
+
var usingFallbackEmbedding = false;
|
|
39576
39935
|
async function getEmbedding(text13) {
|
|
39577
39936
|
if (!embedFn) {
|
|
39578
39937
|
try {
|
|
@@ -39587,26 +39946,27 @@ async function getEmbedding(text13) {
|
|
|
39587
39946
|
};
|
|
39588
39947
|
} catch {
|
|
39589
39948
|
embedFn = async (t) => simpleEmbedding(t);
|
|
39949
|
+
usingFallbackEmbedding = true;
|
|
39590
39950
|
}
|
|
39591
39951
|
}
|
|
39592
39952
|
return embedFn(text13);
|
|
39593
39953
|
}
|
|
39594
39954
|
async function loadIndex2(indexDir) {
|
|
39595
39955
|
try {
|
|
39596
|
-
const indexPath =
|
|
39597
|
-
const content = await
|
|
39956
|
+
const indexPath = path40.join(indexDir, "index.json");
|
|
39957
|
+
const content = await fs39.readFile(indexPath, "utf-8");
|
|
39598
39958
|
return JSON.parse(content);
|
|
39599
39959
|
} catch {
|
|
39600
39960
|
return null;
|
|
39601
39961
|
}
|
|
39602
39962
|
}
|
|
39603
39963
|
async function saveIndex2(indexDir, index) {
|
|
39604
|
-
await
|
|
39605
|
-
const indexPath =
|
|
39606
|
-
await
|
|
39964
|
+
await fs39.mkdir(indexDir, { recursive: true });
|
|
39965
|
+
const indexPath = path40.join(indexDir, "index.json");
|
|
39966
|
+
await fs39.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
39607
39967
|
}
|
|
39608
39968
|
function isBinary(filePath) {
|
|
39609
|
-
return BINARY_EXTENSIONS.has(
|
|
39969
|
+
return BINARY_EXTENSIONS.has(path40.extname(filePath).toLowerCase());
|
|
39610
39970
|
}
|
|
39611
39971
|
var semanticSearchTool = defineTool({
|
|
39612
39972
|
name: "semantic_search",
|
|
@@ -39631,9 +39991,10 @@ Examples:
|
|
|
39631
39991
|
const effectivePath = rootPath ?? ".";
|
|
39632
39992
|
const effectiveMaxResults = maxResults ?? 10;
|
|
39633
39993
|
const effectiveThreshold = threshold ?? 0.3;
|
|
39634
|
-
const absPath =
|
|
39635
|
-
const indexDir =
|
|
39994
|
+
const absPath = path40.resolve(effectivePath);
|
|
39995
|
+
const indexDir = path40.join(absPath, INDEX_DIR);
|
|
39636
39996
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
39997
|
+
let warnings = [];
|
|
39637
39998
|
if (!index) {
|
|
39638
39999
|
const pattern = include ?? "**/*";
|
|
39639
40000
|
const files = await glob15(pattern, {
|
|
@@ -39643,12 +40004,14 @@ Examples:
|
|
|
39643
40004
|
absolute: false
|
|
39644
40005
|
});
|
|
39645
40006
|
const chunks = [];
|
|
40007
|
+
let skippedFiles = 0;
|
|
40008
|
+
let indexSaveWarning = "";
|
|
39646
40009
|
for (const file of files) {
|
|
39647
40010
|
if (isBinary(file)) continue;
|
|
39648
|
-
const fullPath =
|
|
40011
|
+
const fullPath = path40.join(absPath, file);
|
|
39649
40012
|
try {
|
|
39650
|
-
const stat2 = await
|
|
39651
|
-
const content = await
|
|
40013
|
+
const stat2 = await fs39.stat(fullPath);
|
|
40014
|
+
const content = await fs39.readFile(fullPath, "utf-8");
|
|
39652
40015
|
if (content.length > 1e5) continue;
|
|
39653
40016
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
39654
40017
|
for (const chunk of fileChunks) {
|
|
@@ -39663,6 +40026,7 @@ Examples:
|
|
|
39663
40026
|
});
|
|
39664
40027
|
}
|
|
39665
40028
|
} catch {
|
|
40029
|
+
skippedFiles++;
|
|
39666
40030
|
continue;
|
|
39667
40031
|
}
|
|
39668
40032
|
}
|
|
@@ -39675,6 +40039,18 @@ Examples:
|
|
|
39675
40039
|
try {
|
|
39676
40040
|
await saveIndex2(indexDir, index);
|
|
39677
40041
|
} catch {
|
|
40042
|
+
indexSaveWarning = "Index could not be saved to disk \u2014 next search will rebuild it.";
|
|
40043
|
+
}
|
|
40044
|
+
if (usingFallbackEmbedding) {
|
|
40045
|
+
warnings.push(
|
|
40046
|
+
"Using basic text matching (transformer model unavailable). Results may be less accurate."
|
|
40047
|
+
);
|
|
40048
|
+
}
|
|
40049
|
+
if (skippedFiles > 0) {
|
|
40050
|
+
warnings.push(`${skippedFiles} file(s) could not be read (binary or permission issues).`);
|
|
40051
|
+
}
|
|
40052
|
+
if (indexSaveWarning) {
|
|
40053
|
+
warnings.push(indexSaveWarning);
|
|
39678
40054
|
}
|
|
39679
40055
|
}
|
|
39680
40056
|
const queryVector = await getEmbedding(query);
|
|
@@ -39698,12 +40074,16 @@ Examples:
|
|
|
39698
40074
|
const ageMs = Date.now() - indexDate.getTime();
|
|
39699
40075
|
const ageMinutes = Math.round(ageMs / 6e4);
|
|
39700
40076
|
const indexAge = ageMinutes < 60 ? `${ageMinutes}m ago` : `${Math.round(ageMinutes / 60)}h ago`;
|
|
39701
|
-
|
|
40077
|
+
const output = {
|
|
39702
40078
|
results,
|
|
39703
40079
|
totalIndexed: index.chunks.length,
|
|
39704
40080
|
indexAge,
|
|
39705
40081
|
duration: performance.now() - startTime
|
|
39706
40082
|
};
|
|
40083
|
+
if (warnings.length > 0) {
|
|
40084
|
+
output.warning = warnings.join(" ");
|
|
40085
|
+
}
|
|
40086
|
+
return output;
|
|
39707
40087
|
}
|
|
39708
40088
|
});
|
|
39709
40089
|
var semanticSearchTools = [semanticSearchTool];
|
|
@@ -39711,8 +40091,8 @@ var semanticSearchTools = [semanticSearchTool];
|
|
|
39711
40091
|
// src/tools/diagram.ts
|
|
39712
40092
|
init_registry4();
|
|
39713
40093
|
init_errors();
|
|
39714
|
-
var
|
|
39715
|
-
var
|
|
40094
|
+
var fs40 = await import('fs/promises');
|
|
40095
|
+
var path41 = await import('path');
|
|
39716
40096
|
var { glob: glob16 } = await import('glob');
|
|
39717
40097
|
async function parseClassRelationships(rootPath, include) {
|
|
39718
40098
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -39725,7 +40105,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
39725
40105
|
const interfaces = [];
|
|
39726
40106
|
for (const file of files.slice(0, 100)) {
|
|
39727
40107
|
try {
|
|
39728
|
-
const content = await
|
|
40108
|
+
const content = await fs40.readFile(path41.join(rootPath, file), "utf-8");
|
|
39729
40109
|
const lines = content.split("\n");
|
|
39730
40110
|
for (let i = 0; i < lines.length; i++) {
|
|
39731
40111
|
const line = lines[i];
|
|
@@ -39844,14 +40224,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
39844
40224
|
};
|
|
39845
40225
|
}
|
|
39846
40226
|
async function generateArchitectureDiagram(rootPath) {
|
|
39847
|
-
const entries = await
|
|
40227
|
+
const entries = await fs40.readdir(rootPath, { withFileTypes: true });
|
|
39848
40228
|
const dirs = entries.filter(
|
|
39849
40229
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
39850
40230
|
);
|
|
39851
40231
|
const lines = ["graph TD"];
|
|
39852
40232
|
let nodeCount = 0;
|
|
39853
40233
|
let edgeCount = 0;
|
|
39854
|
-
const rootName =
|
|
40234
|
+
const rootName = path41.basename(rootPath);
|
|
39855
40235
|
lines.push(` ROOT["${rootName}"]`);
|
|
39856
40236
|
nodeCount++;
|
|
39857
40237
|
for (const dir of dirs) {
|
|
@@ -39861,7 +40241,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
39861
40241
|
nodeCount++;
|
|
39862
40242
|
edgeCount++;
|
|
39863
40243
|
try {
|
|
39864
|
-
const subEntries = await
|
|
40244
|
+
const subEntries = await fs40.readdir(path41.join(rootPath, dir.name), {
|
|
39865
40245
|
withFileTypes: true
|
|
39866
40246
|
});
|
|
39867
40247
|
const subDirs = subEntries.filter(
|
|
@@ -39984,7 +40364,7 @@ Examples:
|
|
|
39984
40364
|
tool: "generate_diagram"
|
|
39985
40365
|
});
|
|
39986
40366
|
}
|
|
39987
|
-
const absPath = rootPath ?
|
|
40367
|
+
const absPath = rootPath ? path41.resolve(rootPath) : process.cwd();
|
|
39988
40368
|
switch (type) {
|
|
39989
40369
|
case "class":
|
|
39990
40370
|
return generateClassDiagram(absPath, include);
|
|
@@ -40049,8 +40429,8 @@ var diagramTools = [generateDiagramTool];
|
|
|
40049
40429
|
// src/tools/pdf.ts
|
|
40050
40430
|
init_registry4();
|
|
40051
40431
|
init_errors();
|
|
40052
|
-
var
|
|
40053
|
-
var
|
|
40432
|
+
var fs41 = await import('fs/promises');
|
|
40433
|
+
var path42 = await import('path');
|
|
40054
40434
|
var DEFAULT_MAX_PAGES = 20;
|
|
40055
40435
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
40056
40436
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -40085,9 +40465,9 @@ Examples:
|
|
|
40085
40465
|
}),
|
|
40086
40466
|
async execute({ path: filePath, pages, maxPages }) {
|
|
40087
40467
|
const startTime = performance.now();
|
|
40088
|
-
const absPath =
|
|
40468
|
+
const absPath = path42.resolve(filePath);
|
|
40089
40469
|
try {
|
|
40090
|
-
const stat2 = await
|
|
40470
|
+
const stat2 = await fs41.stat(absPath);
|
|
40091
40471
|
if (!stat2.isFile()) {
|
|
40092
40472
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
40093
40473
|
tool: "read_pdf"
|
|
@@ -40118,7 +40498,7 @@ Examples:
|
|
|
40118
40498
|
}
|
|
40119
40499
|
try {
|
|
40120
40500
|
const pdfParse = await import('pdf-parse');
|
|
40121
|
-
const dataBuffer = await
|
|
40501
|
+
const dataBuffer = await fs41.readFile(absPath);
|
|
40122
40502
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
40123
40503
|
max: maxPages
|
|
40124
40504
|
});
|
|
@@ -40156,8 +40536,9 @@ Examples:
|
|
|
40156
40536
|
tool: "read_pdf"
|
|
40157
40537
|
});
|
|
40158
40538
|
}
|
|
40539
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40159
40540
|
throw new ToolError(
|
|
40160
|
-
`Failed to parse PDF: ${
|
|
40541
|
+
`Failed to parse PDF: ${msg}. The file may be encrypted, password-protected, or corrupted. Try opening it locally to verify.`,
|
|
40161
40542
|
{ tool: "read_pdf", cause: error instanceof Error ? error : void 0 }
|
|
40162
40543
|
);
|
|
40163
40544
|
}
|
|
@@ -40168,8 +40549,8 @@ var pdfTools = [readPdfTool];
|
|
|
40168
40549
|
// src/tools/image.ts
|
|
40169
40550
|
init_registry4();
|
|
40170
40551
|
init_errors();
|
|
40171
|
-
var
|
|
40172
|
-
var
|
|
40552
|
+
var fs42 = await import('fs/promises');
|
|
40553
|
+
var path43 = await import('path');
|
|
40173
40554
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
40174
40555
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
40175
40556
|
var MIME_TYPES = {
|
|
@@ -40197,15 +40578,15 @@ Examples:
|
|
|
40197
40578
|
async execute({ path: filePath, prompt, provider }) {
|
|
40198
40579
|
const startTime = performance.now();
|
|
40199
40580
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
40200
|
-
const absPath =
|
|
40581
|
+
const absPath = path43.resolve(filePath);
|
|
40201
40582
|
const cwd = process.cwd();
|
|
40202
|
-
if (!absPath.startsWith(cwd +
|
|
40583
|
+
if (!absPath.startsWith(cwd + path43.sep) && absPath !== cwd) {
|
|
40203
40584
|
throw new ToolError(
|
|
40204
40585
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
40205
40586
|
{ tool: "read_image" }
|
|
40206
40587
|
);
|
|
40207
40588
|
}
|
|
40208
|
-
const ext =
|
|
40589
|
+
const ext = path43.extname(absPath).toLowerCase();
|
|
40209
40590
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
40210
40591
|
throw new ToolError(
|
|
40211
40592
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -40213,7 +40594,7 @@ Examples:
|
|
|
40213
40594
|
);
|
|
40214
40595
|
}
|
|
40215
40596
|
try {
|
|
40216
|
-
const stat2 = await
|
|
40597
|
+
const stat2 = await fs42.stat(absPath);
|
|
40217
40598
|
if (!stat2.isFile()) {
|
|
40218
40599
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
40219
40600
|
tool: "read_image"
|
|
@@ -40234,7 +40615,7 @@ Examples:
|
|
|
40234
40615
|
if (error instanceof ToolError) throw error;
|
|
40235
40616
|
throw error;
|
|
40236
40617
|
}
|
|
40237
|
-
const imageBuffer = await
|
|
40618
|
+
const imageBuffer = await fs42.readFile(absPath);
|
|
40238
40619
|
const base64 = imageBuffer.toString("base64");
|
|
40239
40620
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
40240
40621
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -40326,10 +40707,15 @@ Examples:
|
|
|
40326
40707
|
} catch (error) {
|
|
40327
40708
|
if (error instanceof ToolError) throw error;
|
|
40328
40709
|
if (error.message?.includes("Cannot find module") || error.message?.includes("MODULE_NOT_FOUND")) {
|
|
40329
|
-
|
|
40330
|
-
|
|
40331
|
-
|
|
40332
|
-
|
|
40710
|
+
const pkgMap = {
|
|
40711
|
+
anthropic: "@anthropic-ai/sdk",
|
|
40712
|
+
openai: "openai",
|
|
40713
|
+
gemini: "@google/generative-ai"
|
|
40714
|
+
};
|
|
40715
|
+
const pkg = pkgMap[selectedProvider] ?? selectedProvider;
|
|
40716
|
+
throw new ToolError(`Provider SDK not installed. Run: pnpm add ${pkg}`, {
|
|
40717
|
+
tool: "read_image"
|
|
40718
|
+
});
|
|
40333
40719
|
}
|
|
40334
40720
|
throw new ToolError(
|
|
40335
40721
|
`Image analysis failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
@@ -40351,7 +40737,7 @@ var imageTools = [readImageTool];
|
|
|
40351
40737
|
// src/tools/database.ts
|
|
40352
40738
|
init_registry4();
|
|
40353
40739
|
init_errors();
|
|
40354
|
-
var
|
|
40740
|
+
var path44 = await import('path');
|
|
40355
40741
|
var DANGEROUS_PATTERNS = [
|
|
40356
40742
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
40357
40743
|
/\bTRUNCATE\b/i,
|
|
@@ -40382,7 +40768,7 @@ Examples:
|
|
|
40382
40768
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
40383
40769
|
const isReadonly = isReadonlyParam ?? true;
|
|
40384
40770
|
const startTime = performance.now();
|
|
40385
|
-
const absPath =
|
|
40771
|
+
const absPath = path44.resolve(database);
|
|
40386
40772
|
if (isReadonly && isDangerousSql(query)) {
|
|
40387
40773
|
throw new ToolError(
|
|
40388
40774
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -40434,10 +40820,20 @@ Examples:
|
|
|
40434
40820
|
{ tool: "sql_query" }
|
|
40435
40821
|
);
|
|
40436
40822
|
}
|
|
40437
|
-
|
|
40438
|
-
|
|
40439
|
-
|
|
40440
|
-
|
|
40823
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40824
|
+
let hint = `SQL query failed: ${msg}`;
|
|
40825
|
+
if (/no such table/i.test(msg))
|
|
40826
|
+
hint = `Table not found: ${msg}. Use inspect_schema to see available tables.`;
|
|
40827
|
+
else if (/syntax error|near "/i.test(msg))
|
|
40828
|
+
hint = `SQL syntax error: ${msg}. Check your query syntax.`;
|
|
40829
|
+
else if (/SQLITE_BUSY|database is locked/i.test(msg))
|
|
40830
|
+
hint = `Database is locked by another process. Wait and retry, or close other connections.`;
|
|
40831
|
+
else if (/unable to open database/i.test(msg))
|
|
40832
|
+
hint = `Cannot open database file. Use glob to verify the file path exists.`;
|
|
40833
|
+
throw new ToolError(hint, {
|
|
40834
|
+
tool: "sql_query",
|
|
40835
|
+
cause: error instanceof Error ? error : void 0
|
|
40836
|
+
});
|
|
40441
40837
|
}
|
|
40442
40838
|
}
|
|
40443
40839
|
});
|
|
@@ -40455,7 +40851,7 @@ Examples:
|
|
|
40455
40851
|
}),
|
|
40456
40852
|
async execute({ database, table }) {
|
|
40457
40853
|
const startTime = performance.now();
|
|
40458
|
-
const absPath =
|
|
40854
|
+
const absPath = path44.resolve(database);
|
|
40459
40855
|
try {
|
|
40460
40856
|
const { default: Database } = await import('better-sqlite3');
|
|
40461
40857
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -40500,10 +40896,16 @@ Examples:
|
|
|
40500
40896
|
{ tool: "inspect_schema" }
|
|
40501
40897
|
);
|
|
40502
40898
|
}
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40899
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
40900
|
+
let hint = `Schema inspection failed: ${msg}`;
|
|
40901
|
+
if (/unable to open database/i.test(msg))
|
|
40902
|
+
hint = `Cannot open database file. Use glob to verify the file path exists.`;
|
|
40903
|
+
else if (/no such table/i.test(msg))
|
|
40904
|
+
hint = `Table '${table ?? ""}' not found. Run inspect_schema without a table name to list all tables.`;
|
|
40905
|
+
throw new ToolError(hint, {
|
|
40906
|
+
tool: "inspect_schema",
|
|
40907
|
+
cause: error instanceof Error ? error : void 0
|
|
40908
|
+
});
|
|
40507
40909
|
}
|
|
40508
40910
|
}
|
|
40509
40911
|
});
|
|
@@ -40632,14 +41034,14 @@ var astValidatorTools = [validateCodeTool, findMissingImportsTool];
|
|
|
40632
41034
|
|
|
40633
41035
|
// src/tools/code-analyzer.ts
|
|
40634
41036
|
init_registry4();
|
|
40635
|
-
var
|
|
40636
|
-
var
|
|
41037
|
+
var fs43 = await import('fs/promises');
|
|
41038
|
+
var path45 = await import('path');
|
|
40637
41039
|
var AnalyzeFileSchema = z.object({
|
|
40638
41040
|
filePath: z.string().describe("Path to file to analyze"),
|
|
40639
41041
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
40640
41042
|
});
|
|
40641
41043
|
async function analyzeFile(filePath, includeAst = false) {
|
|
40642
|
-
const content = await
|
|
41044
|
+
const content = await fs43.readFile(filePath, "utf-8");
|
|
40643
41045
|
const lines = content.split("\n").length;
|
|
40644
41046
|
const functions = [];
|
|
40645
41047
|
const classes = [];
|
|
@@ -40743,10 +41145,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
40743
41145
|
try {
|
|
40744
41146
|
const analysis = await analyzeFile(file, false);
|
|
40745
41147
|
totalLines += analysis.lines;
|
|
40746
|
-
const ext =
|
|
41148
|
+
const ext = path45.extname(file);
|
|
40747
41149
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
40748
41150
|
fileStats.push({
|
|
40749
|
-
file:
|
|
41151
|
+
file: path45.relative(dirPath, file),
|
|
40750
41152
|
lines: analysis.lines,
|
|
40751
41153
|
complexity: analysis.complexity.cyclomatic
|
|
40752
41154
|
});
|
|
@@ -41108,13 +41510,13 @@ var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateRes
|
|
|
41108
41510
|
|
|
41109
41511
|
// src/tools/smart-suggestions.ts
|
|
41110
41512
|
init_registry4();
|
|
41111
|
-
var
|
|
41513
|
+
var fs44 = await import('fs/promises');
|
|
41112
41514
|
var SuggestImprovementsSchema = z.object({
|
|
41113
41515
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
41114
41516
|
context: z.string().optional().describe("Additional context about the code")
|
|
41115
41517
|
});
|
|
41116
41518
|
async function analyzeAndSuggest(filePath, _context) {
|
|
41117
|
-
const content = await
|
|
41519
|
+
const content = await fs44.readFile(filePath, "utf-8");
|
|
41118
41520
|
const lines = content.split("\n");
|
|
41119
41521
|
const suggestions = [];
|
|
41120
41522
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -41206,7 +41608,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
41206
41608
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
41207
41609
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
41208
41610
|
try {
|
|
41209
|
-
await
|
|
41611
|
+
await fs44.access(testPath);
|
|
41210
41612
|
} catch {
|
|
41211
41613
|
suggestions.push({
|
|
41212
41614
|
type: "testing",
|
|
@@ -41263,7 +41665,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
41263
41665
|
async execute(input) {
|
|
41264
41666
|
const { filePath } = input;
|
|
41265
41667
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
41266
|
-
const content = await
|
|
41668
|
+
const content = await fs44.readFile(filePath, "utf-8");
|
|
41267
41669
|
const lines = content.split("\n");
|
|
41268
41670
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
41269
41671
|
let score = 100;
|
|
@@ -41300,8 +41702,8 @@ var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
|
41300
41702
|
|
|
41301
41703
|
// src/tools/context-enhancer.ts
|
|
41302
41704
|
init_registry4();
|
|
41303
|
-
var
|
|
41304
|
-
var
|
|
41705
|
+
var fs45 = await import('fs/promises');
|
|
41706
|
+
var path46 = await import('path');
|
|
41305
41707
|
var ContextMemoryStore = class {
|
|
41306
41708
|
items = /* @__PURE__ */ new Map();
|
|
41307
41709
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -41313,7 +41715,7 @@ var ContextMemoryStore = class {
|
|
|
41313
41715
|
}
|
|
41314
41716
|
async load() {
|
|
41315
41717
|
try {
|
|
41316
|
-
const content = await
|
|
41718
|
+
const content = await fs45.readFile(this.storePath, "utf-8");
|
|
41317
41719
|
const data = JSON.parse(content);
|
|
41318
41720
|
this.items = new Map(Object.entries(data.items || {}));
|
|
41319
41721
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -41321,15 +41723,15 @@ var ContextMemoryStore = class {
|
|
|
41321
41723
|
}
|
|
41322
41724
|
}
|
|
41323
41725
|
async save() {
|
|
41324
|
-
const dir =
|
|
41325
|
-
await
|
|
41726
|
+
const dir = path46.dirname(this.storePath);
|
|
41727
|
+
await fs45.mkdir(dir, { recursive: true });
|
|
41326
41728
|
const data = {
|
|
41327
41729
|
sessionId: this.sessionId,
|
|
41328
41730
|
items: Object.fromEntries(this.items),
|
|
41329
41731
|
learnings: Object.fromEntries(this.learnings),
|
|
41330
41732
|
savedAt: Date.now()
|
|
41331
41733
|
};
|
|
41332
|
-
await
|
|
41734
|
+
await fs45.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
41333
41735
|
}
|
|
41334
41736
|
addContext(id, item) {
|
|
41335
41737
|
this.items.set(id, item);
|
|
@@ -41497,11 +41899,11 @@ var contextEnhancerTools = [
|
|
|
41497
41899
|
|
|
41498
41900
|
// src/tools/skill-enhancer.ts
|
|
41499
41901
|
init_registry4();
|
|
41500
|
-
var
|
|
41501
|
-
var
|
|
41902
|
+
var fs46 = await import('fs/promises');
|
|
41903
|
+
var path47 = await import('path');
|
|
41502
41904
|
async function discoverSkills(skillsDir) {
|
|
41503
41905
|
try {
|
|
41504
|
-
const files = await
|
|
41906
|
+
const files = await fs46.readdir(skillsDir);
|
|
41505
41907
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
41506
41908
|
} catch {
|
|
41507
41909
|
return [];
|
|
@@ -41509,12 +41911,12 @@ async function discoverSkills(skillsDir) {
|
|
|
41509
41911
|
}
|
|
41510
41912
|
async function loadSkillMetadata(skillPath) {
|
|
41511
41913
|
try {
|
|
41512
|
-
const content = await
|
|
41914
|
+
const content = await fs46.readFile(skillPath, "utf-8");
|
|
41513
41915
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
41514
41916
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
41515
41917
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
41516
41918
|
return {
|
|
41517
|
-
name: nameMatch?.[1] ||
|
|
41919
|
+
name: nameMatch?.[1] || path47.basename(skillPath, path47.extname(skillPath)),
|
|
41518
41920
|
description: descMatch?.[1] || "No description",
|
|
41519
41921
|
version: versionMatch?.[1] || "1.0.0",
|
|
41520
41922
|
dependencies: []
|
|
@@ -41558,7 +41960,7 @@ var discoverSkillsTool = defineTool({
|
|
|
41558
41960
|
const { skillsDir } = input;
|
|
41559
41961
|
const skills = await discoverSkills(skillsDir);
|
|
41560
41962
|
const metadata = await Promise.all(
|
|
41561
|
-
skills.map((s) => loadSkillMetadata(
|
|
41963
|
+
skills.map((s) => loadSkillMetadata(path47.join(skillsDir, s)))
|
|
41562
41964
|
);
|
|
41563
41965
|
return {
|
|
41564
41966
|
skillsDir,
|
|
@@ -41729,7 +42131,7 @@ Examples:
|
|
|
41729
42131
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
41730
42132
|
}),
|
|
41731
42133
|
async execute({ path: dirPath, reason }) {
|
|
41732
|
-
const absolute =
|
|
42134
|
+
const absolute = path35__default.resolve(dirPath);
|
|
41733
42135
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
41734
42136
|
return {
|
|
41735
42137
|
authorized: true,
|
|
@@ -41738,8 +42140,8 @@ Examples:
|
|
|
41738
42140
|
};
|
|
41739
42141
|
}
|
|
41740
42142
|
for (const blocked of BLOCKED_SYSTEM_PATHS2) {
|
|
41741
|
-
const normalizedBlocked =
|
|
41742
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
42143
|
+
const normalizedBlocked = path35__default.normalize(blocked);
|
|
42144
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path35__default.sep)) {
|
|
41743
42145
|
return {
|
|
41744
42146
|
authorized: false,
|
|
41745
42147
|
path: absolute,
|
|
@@ -41748,7 +42150,7 @@ Examples:
|
|
|
41748
42150
|
}
|
|
41749
42151
|
}
|
|
41750
42152
|
const cwd = process.cwd();
|
|
41751
|
-
if (absolute ===
|
|
42153
|
+
if (absolute === path35__default.normalize(cwd) || absolute.startsWith(path35__default.normalize(cwd) + path35__default.sep)) {
|
|
41752
42154
|
return {
|
|
41753
42155
|
authorized: true,
|
|
41754
42156
|
path: absolute,
|
|
@@ -41756,7 +42158,7 @@ Examples:
|
|
|
41756
42158
|
};
|
|
41757
42159
|
}
|
|
41758
42160
|
try {
|
|
41759
|
-
const stat2 = await
|
|
42161
|
+
const stat2 = await fs33__default.stat(absolute);
|
|
41760
42162
|
if (!stat2.isDirectory()) {
|
|
41761
42163
|
return {
|
|
41762
42164
|
authorized: false,
|
|
@@ -41772,7 +42174,7 @@ Examples:
|
|
|
41772
42174
|
};
|
|
41773
42175
|
}
|
|
41774
42176
|
const existing = getAllowedPaths();
|
|
41775
|
-
if (existing.some((e) =>
|
|
42177
|
+
if (existing.some((e) => path35__default.normalize(e.path) === path35__default.normalize(absolute))) {
|
|
41776
42178
|
return {
|
|
41777
42179
|
authorized: true,
|
|
41778
42180
|
path: absolute,
|
|
@@ -41857,9 +42259,9 @@ async function runSprints(options) {
|
|
|
41857
42259
|
Object.entries(AGENT_ROLES).map(([role, def]) => [role, { ...def, maxTurns: 20 }])
|
|
41858
42260
|
);
|
|
41859
42261
|
const coordinator = createAgentCoordinator(executor, agentDefsMap);
|
|
41860
|
-
await
|
|
41861
|
-
const sprintsDir =
|
|
41862
|
-
await
|
|
42262
|
+
await fs33__default.mkdir(spec.outputPath, { recursive: true });
|
|
42263
|
+
const sprintsDir = path35__default.join(spec.outputPath, ".coco", "sprints");
|
|
42264
|
+
await fs33__default.mkdir(sprintsDir, { recursive: true });
|
|
41863
42265
|
for (const sprint of spec.sprints) {
|
|
41864
42266
|
onProgress(`Starting ${sprint.id}: ${sprint.name}`);
|
|
41865
42267
|
const sprintStart = Date.now();
|
|
@@ -42112,8 +42514,8 @@ Assess: overall architecture, consistency, error handling, and production readin
|
|
|
42112
42514
|
};
|
|
42113
42515
|
}
|
|
42114
42516
|
async function saveSprintResult(sprintsDir, result) {
|
|
42115
|
-
const filePath =
|
|
42116
|
-
await
|
|
42517
|
+
const filePath = path35__default.join(sprintsDir, `${result.sprintId}.json`);
|
|
42518
|
+
await fs33__default.writeFile(filePath, JSON.stringify(result, null, 2), "utf-8");
|
|
42117
42519
|
}
|
|
42118
42520
|
|
|
42119
42521
|
// src/cli/repl/commands/build-app.ts
|
|
@@ -42138,9 +42540,9 @@ function parseArgs5(args) {
|
|
|
42138
42540
|
return { description, specFile, outputDir, skipConfirmation };
|
|
42139
42541
|
}
|
|
42140
42542
|
function isWithinRoot(resolvedPath, rootDir) {
|
|
42141
|
-
const normalRoot =
|
|
42142
|
-
const normalPath =
|
|
42143
|
-
return normalPath ===
|
|
42543
|
+
const normalRoot = path35__default.normalize(rootDir) + path35__default.sep;
|
|
42544
|
+
const normalPath = path35__default.normalize(resolvedPath);
|
|
42545
|
+
return normalPath === path35__default.normalize(rootDir) || normalPath.startsWith(normalRoot);
|
|
42144
42546
|
}
|
|
42145
42547
|
var buildAppCommand = {
|
|
42146
42548
|
name: "build-app",
|
|
@@ -42163,20 +42565,20 @@ var buildAppCommand = {
|
|
|
42163
42565
|
}
|
|
42164
42566
|
let initialDescription = parsed.description;
|
|
42165
42567
|
if (parsed.specFile) {
|
|
42166
|
-
const specPath =
|
|
42568
|
+
const specPath = path35__default.resolve(session.projectPath, parsed.specFile);
|
|
42167
42569
|
if (!isWithinRoot(specPath, session.projectPath)) {
|
|
42168
42570
|
p25.log.error(`--spec path must be within the project directory: ${specPath}`);
|
|
42169
42571
|
return false;
|
|
42170
42572
|
}
|
|
42171
42573
|
try {
|
|
42172
|
-
initialDescription = await
|
|
42574
|
+
initialDescription = await fs33__default.readFile(specPath, "utf-8");
|
|
42173
42575
|
} catch (err) {
|
|
42174
42576
|
const msg = err instanceof Error ? err.message : String(err);
|
|
42175
42577
|
p25.log.error(`Error reading spec file: ${msg}`);
|
|
42176
42578
|
return false;
|
|
42177
42579
|
}
|
|
42178
42580
|
}
|
|
42179
|
-
const outputPath = parsed.outputDir ?
|
|
42581
|
+
const outputPath = parsed.outputDir ? path35__default.resolve(session.projectPath, parsed.outputDir) : path35__default.join(session.projectPath, "build-app-output");
|
|
42180
42582
|
if (parsed.outputDir && !isWithinRoot(outputPath, session.projectPath)) {
|
|
42181
42583
|
p25.log.error(`--output path must be within the project directory: ${outputPath}`);
|
|
42182
42584
|
return false;
|
|
@@ -42383,11 +42785,11 @@ function getAllCommands() {
|
|
|
42383
42785
|
}
|
|
42384
42786
|
|
|
42385
42787
|
// src/cli/repl/input/handler.ts
|
|
42386
|
-
var HISTORY_FILE =
|
|
42788
|
+
var HISTORY_FILE = path35.join(os4.homedir(), ".coco", "history");
|
|
42387
42789
|
function loadHistory() {
|
|
42388
42790
|
try {
|
|
42389
|
-
if (
|
|
42390
|
-
const content =
|
|
42791
|
+
if (fs50.existsSync(HISTORY_FILE)) {
|
|
42792
|
+
const content = fs50.readFileSync(HISTORY_FILE, "utf-8");
|
|
42391
42793
|
return content.split("\n").filter(Boolean).slice(-500);
|
|
42392
42794
|
}
|
|
42393
42795
|
} catch {
|
|
@@ -42396,12 +42798,12 @@ function loadHistory() {
|
|
|
42396
42798
|
}
|
|
42397
42799
|
function saveHistory(history) {
|
|
42398
42800
|
try {
|
|
42399
|
-
const dir =
|
|
42400
|
-
if (!
|
|
42401
|
-
|
|
42801
|
+
const dir = path35.dirname(HISTORY_FILE);
|
|
42802
|
+
if (!fs50.existsSync(dir)) {
|
|
42803
|
+
fs50.mkdirSync(dir, { recursive: true });
|
|
42402
42804
|
}
|
|
42403
42805
|
const toSave = history.slice(-500);
|
|
42404
|
-
|
|
42806
|
+
fs50.writeFileSync(HISTORY_FILE, toSave.join("\n") + "\n");
|
|
42405
42807
|
} catch {
|
|
42406
42808
|
}
|
|
42407
42809
|
}
|
|
@@ -43729,7 +44131,7 @@ function formatDiffPreview(toolCall) {
|
|
|
43729
44131
|
}
|
|
43730
44132
|
async function checkFileExists(filePath) {
|
|
43731
44133
|
try {
|
|
43732
|
-
await
|
|
44134
|
+
await fs33__default.access(filePath);
|
|
43733
44135
|
return true;
|
|
43734
44136
|
} catch {
|
|
43735
44137
|
return false;
|
|
@@ -44241,7 +44643,8 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
44241
44643
|
const toolCallBuilders = /* @__PURE__ */ new Map();
|
|
44242
44644
|
for await (const chunk of provider.streamWithTools(messages, {
|
|
44243
44645
|
tools,
|
|
44244
|
-
maxTokens: session.config.provider.maxTokens
|
|
44646
|
+
maxTokens: session.config.provider.maxTokens,
|
|
44647
|
+
signal: options.signal
|
|
44245
44648
|
})) {
|
|
44246
44649
|
if (options.signal?.aborted) {
|
|
44247
44650
|
break;
|
|
@@ -44511,6 +44914,22 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
44511
44914
|
content: toolResults
|
|
44512
44915
|
});
|
|
44513
44916
|
if (stuckInErrorLoop) {
|
|
44917
|
+
try {
|
|
44918
|
+
const finalMessages = getConversationContext(session, toolRegistry);
|
|
44919
|
+
for await (const chunk of provider.streamWithTools(finalMessages, {
|
|
44920
|
+
tools: [],
|
|
44921
|
+
maxTokens: session.config.provider.maxTokens,
|
|
44922
|
+
signal: options.signal
|
|
44923
|
+
})) {
|
|
44924
|
+
if (options.signal?.aborted) break;
|
|
44925
|
+
if (chunk.type === "text" && chunk.text) {
|
|
44926
|
+
finalContent += chunk.text;
|
|
44927
|
+
options.onStream?.(chunk);
|
|
44928
|
+
}
|
|
44929
|
+
if (chunk.type === "done") break;
|
|
44930
|
+
}
|
|
44931
|
+
} catch {
|
|
44932
|
+
}
|
|
44514
44933
|
break;
|
|
44515
44934
|
}
|
|
44516
44935
|
}
|
|
@@ -45048,8 +45467,8 @@ function formatContextUsage(percent) {
|
|
|
45048
45467
|
}
|
|
45049
45468
|
function formatStatusBar(projectPath, config, gitCtx, contextUsagePercent) {
|
|
45050
45469
|
const parts = [];
|
|
45051
|
-
const projectName =
|
|
45052
|
-
parts.push(chalk25.dim("\u{1F4C1}") + chalk25.magenta(projectName));
|
|
45470
|
+
const projectName = path35__default.basename(projectPath);
|
|
45471
|
+
parts.push(chalk25.dim("\u{1F4C1} ") + chalk25.magenta(projectName));
|
|
45053
45472
|
const providerName = config.provider.type;
|
|
45054
45473
|
const modelName = config.provider.model || "default";
|
|
45055
45474
|
parts.push(chalk25.dim(`${providerName}/`) + chalk25.cyan(modelName));
|
|
@@ -45695,16 +46114,33 @@ async function startRepl(options = {}) {
|
|
|
45695
46114
|
const usageBefore = getContextUsagePercent(session);
|
|
45696
46115
|
let usageForDisplay = usageBefore;
|
|
45697
46116
|
try {
|
|
45698
|
-
const
|
|
45699
|
-
|
|
45700
|
-
|
|
45701
|
-
|
|
45702
|
-
|
|
45703
|
-
|
|
45704
|
-
|
|
46117
|
+
const compactAbort = new AbortController();
|
|
46118
|
+
const compactTimeout = setTimeout(() => compactAbort.abort(), 3e4);
|
|
46119
|
+
const compactSigint = () => compactAbort.abort();
|
|
46120
|
+
process.once("SIGINT", compactSigint);
|
|
46121
|
+
const compactSpinner = createSpinner("Compacting context");
|
|
46122
|
+
compactSpinner.start();
|
|
46123
|
+
try {
|
|
46124
|
+
const compactionResult = await checkAndCompactContext(
|
|
46125
|
+
session,
|
|
46126
|
+
provider,
|
|
46127
|
+
compactAbort.signal
|
|
45705
46128
|
);
|
|
45706
|
-
|
|
45707
|
-
|
|
46129
|
+
if (compactionResult?.wasCompacted) {
|
|
46130
|
+
usageForDisplay = getContextUsagePercent(session);
|
|
46131
|
+
compactSpinner.stop(
|
|
46132
|
+
`Context compacted (${usageBefore.toFixed(0)}% \u2192 ${usageForDisplay.toFixed(0)}%)`
|
|
46133
|
+
);
|
|
46134
|
+
warned75 = false;
|
|
46135
|
+
warned90 = false;
|
|
46136
|
+
} else {
|
|
46137
|
+
compactSpinner.clear();
|
|
46138
|
+
}
|
|
46139
|
+
} catch {
|
|
46140
|
+
compactSpinner.clear();
|
|
46141
|
+
} finally {
|
|
46142
|
+
clearTimeout(compactTimeout);
|
|
46143
|
+
process.off("SIGINT", compactSigint);
|
|
45708
46144
|
}
|
|
45709
46145
|
} catch {
|
|
45710
46146
|
}
|