@corbat-tech/coco 2.10.0 → 2.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +2875 -1806
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1066 -394
- package/dist/index.js.map +1 -1
- package/package.json +17 -18
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { homedir } from 'os';
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
2
|
+
import * as path17 from 'path';
|
|
3
|
+
import path17__default, { dirname, join, basename, resolve } from 'path';
|
|
4
4
|
import * as fs4 from 'fs';
|
|
5
5
|
import fs4__default, { readFileSync, constants } from 'fs';
|
|
6
|
-
import * as
|
|
7
|
-
import
|
|
6
|
+
import * as fs16 from 'fs/promises';
|
|
7
|
+
import fs16__default, { readFile, access, readdir } from 'fs/promises';
|
|
8
8
|
import chalk4 from 'chalk';
|
|
9
9
|
import * as p4 from '@clack/prompts';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
@@ -92,7 +92,7 @@ function loadGlobalCocoEnv() {
|
|
|
92
92
|
try {
|
|
93
93
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
94
94
|
if (!home) return;
|
|
95
|
-
const globalEnvPath =
|
|
95
|
+
const globalEnvPath = path17.join(home, ".coco", ".env");
|
|
96
96
|
const content = fs4.readFileSync(globalEnvPath, "utf-8");
|
|
97
97
|
for (const line of content.split("\n")) {
|
|
98
98
|
const trimmed = line.trim();
|
|
@@ -128,6 +128,8 @@ function getApiKey(provider) {
|
|
|
128
128
|
return process.env["OLLAMA_API_KEY"] ?? "ollama";
|
|
129
129
|
case "codex":
|
|
130
130
|
return void 0;
|
|
131
|
+
case "copilot":
|
|
132
|
+
return process.env["GITHUB_TOKEN"] ?? process.env["GH_TOKEN"];
|
|
131
133
|
case "groq":
|
|
132
134
|
return process.env["GROQ_API_KEY"];
|
|
133
135
|
case "openrouter":
|
|
@@ -162,6 +164,8 @@ function getBaseUrl(provider) {
|
|
|
162
164
|
return process.env["OLLAMA_BASE_URL"] ?? "http://localhost:11434/v1";
|
|
163
165
|
case "codex":
|
|
164
166
|
return "https://chatgpt.com/backend-api/codex/responses";
|
|
167
|
+
case "copilot":
|
|
168
|
+
return process.env["COPILOT_BASE_URL"] ?? "https://api.githubcopilot.com";
|
|
165
169
|
case "groq":
|
|
166
170
|
return process.env["GROQ_BASE_URL"] ?? "https://api.groq.com/openai/v1";
|
|
167
171
|
case "openrouter":
|
|
@@ -183,11 +187,11 @@ function getBaseUrl(provider) {
|
|
|
183
187
|
function getDefaultModel(provider) {
|
|
184
188
|
switch (provider) {
|
|
185
189
|
case "anthropic":
|
|
186
|
-
return process.env["ANTHROPIC_MODEL"] ?? "claude-opus-4-6
|
|
190
|
+
return process.env["ANTHROPIC_MODEL"] ?? "claude-opus-4-6";
|
|
187
191
|
case "openai":
|
|
188
192
|
return process.env["OPENAI_MODEL"] ?? "gpt-5.3-codex";
|
|
189
193
|
case "gemini":
|
|
190
|
-
return process.env["GEMINI_MODEL"] ?? "gemini-3-
|
|
194
|
+
return process.env["GEMINI_MODEL"] ?? "gemini-3.1-pro-preview";
|
|
191
195
|
case "kimi":
|
|
192
196
|
return process.env["KIMI_MODEL"] ?? "kimi-k2.5";
|
|
193
197
|
case "kimi-code":
|
|
@@ -198,6 +202,8 @@ function getDefaultModel(provider) {
|
|
|
198
202
|
return process.env["OLLAMA_MODEL"] ?? "llama3.1";
|
|
199
203
|
case "codex":
|
|
200
204
|
return process.env["CODEX_MODEL"] ?? "gpt-5.3-codex";
|
|
205
|
+
case "copilot":
|
|
206
|
+
return process.env["COPILOT_MODEL"] ?? "claude-sonnet-4.6";
|
|
201
207
|
case "groq":
|
|
202
208
|
return process.env["GROQ_MODEL"] ?? "llama-3.3-70b-versatile";
|
|
203
209
|
case "openrouter":
|
|
@@ -232,6 +238,7 @@ var init_env = __esm({
|
|
|
232
238
|
"anthropic",
|
|
233
239
|
"openai",
|
|
234
240
|
"codex",
|
|
241
|
+
"copilot",
|
|
235
242
|
"gemini",
|
|
236
243
|
"kimi",
|
|
237
244
|
"kimi-code",
|
|
@@ -257,10 +264,10 @@ function getAllowedPaths() {
|
|
|
257
264
|
return [...sessionAllowedPaths];
|
|
258
265
|
}
|
|
259
266
|
function isWithinAllowedPath(absolutePath, operation) {
|
|
260
|
-
const normalizedTarget =
|
|
267
|
+
const normalizedTarget = path17__default.normalize(absolutePath);
|
|
261
268
|
for (const entry of sessionAllowedPaths) {
|
|
262
|
-
const normalizedAllowed =
|
|
263
|
-
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed +
|
|
269
|
+
const normalizedAllowed = path17__default.normalize(entry.path);
|
|
270
|
+
if (normalizedTarget === normalizedAllowed || normalizedTarget.startsWith(normalizedAllowed + path17__default.sep)) {
|
|
264
271
|
if (operation === "read") return true;
|
|
265
272
|
if (entry.level === "write") return true;
|
|
266
273
|
}
|
|
@@ -268,8 +275,8 @@ function isWithinAllowedPath(absolutePath, operation) {
|
|
|
268
275
|
return false;
|
|
269
276
|
}
|
|
270
277
|
function addAllowedPathToSession(dirPath, level) {
|
|
271
|
-
const absolute =
|
|
272
|
-
if (sessionAllowedPaths.some((e) =>
|
|
278
|
+
const absolute = path17__default.resolve(dirPath);
|
|
279
|
+
if (sessionAllowedPaths.some((e) => path17__default.normalize(e.path) === path17__default.normalize(absolute))) {
|
|
273
280
|
return;
|
|
274
281
|
}
|
|
275
282
|
sessionAllowedPaths.push({
|
|
@@ -280,14 +287,14 @@ function addAllowedPathToSession(dirPath, level) {
|
|
|
280
287
|
}
|
|
281
288
|
async function persistAllowedPath(dirPath, level) {
|
|
282
289
|
if (!currentProjectPath) return;
|
|
283
|
-
const absolute =
|
|
290
|
+
const absolute = path17__default.resolve(dirPath);
|
|
284
291
|
const store = await loadStore();
|
|
285
292
|
if (!store.projects[currentProjectPath]) {
|
|
286
293
|
store.projects[currentProjectPath] = [];
|
|
287
294
|
}
|
|
288
295
|
const entries = store.projects[currentProjectPath];
|
|
289
|
-
const normalized =
|
|
290
|
-
if (entries.some((e) =>
|
|
296
|
+
const normalized = path17__default.normalize(absolute);
|
|
297
|
+
if (entries.some((e) => path17__default.normalize(e.path) === normalized)) {
|
|
291
298
|
return;
|
|
292
299
|
}
|
|
293
300
|
entries.push({
|
|
@@ -299,7 +306,7 @@ async function persistAllowedPath(dirPath, level) {
|
|
|
299
306
|
}
|
|
300
307
|
async function loadStore() {
|
|
301
308
|
try {
|
|
302
|
-
const content = await
|
|
309
|
+
const content = await fs16__default.readFile(STORE_FILE, "utf-8");
|
|
303
310
|
return { ...DEFAULT_STORE, ...JSON.parse(content) };
|
|
304
311
|
} catch {
|
|
305
312
|
return { ...DEFAULT_STORE };
|
|
@@ -307,8 +314,8 @@ async function loadStore() {
|
|
|
307
314
|
}
|
|
308
315
|
async function saveStore(store) {
|
|
309
316
|
try {
|
|
310
|
-
await
|
|
311
|
-
await
|
|
317
|
+
await fs16__default.mkdir(path17__default.dirname(STORE_FILE), { recursive: true });
|
|
318
|
+
await fs16__default.writeFile(STORE_FILE, JSON.stringify(store, null, 2), "utf-8");
|
|
312
319
|
} catch {
|
|
313
320
|
}
|
|
314
321
|
}
|
|
@@ -316,7 +323,7 @@ var STORE_FILE, DEFAULT_STORE, sessionAllowedPaths, currentProjectPath;
|
|
|
316
323
|
var init_allowed_paths = __esm({
|
|
317
324
|
"src/tools/allowed-paths.ts"() {
|
|
318
325
|
init_paths();
|
|
319
|
-
STORE_FILE =
|
|
326
|
+
STORE_FILE = path17__default.join(CONFIG_PATHS.home, "allowed-paths.json");
|
|
320
327
|
DEFAULT_STORE = {
|
|
321
328
|
version: 1,
|
|
322
329
|
projects: {}
|
|
@@ -397,7 +404,7 @@ __export(allow_path_prompt_exports, {
|
|
|
397
404
|
promptAllowPath: () => promptAllowPath
|
|
398
405
|
});
|
|
399
406
|
async function promptAllowPath(dirPath) {
|
|
400
|
-
const absolute =
|
|
407
|
+
const absolute = path17__default.resolve(dirPath);
|
|
401
408
|
console.log();
|
|
402
409
|
console.log(chalk4.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
403
410
|
console.log(chalk4.dim(` \u{1F4C1} ${absolute}`));
|
|
@@ -1778,13 +1785,13 @@ function createSpecificationGenerator(llm, config) {
|
|
|
1778
1785
|
return new SpecificationGenerator(llm, config);
|
|
1779
1786
|
}
|
|
1780
1787
|
function getPersistencePaths(projectPath) {
|
|
1781
|
-
const baseDir =
|
|
1788
|
+
const baseDir = path17__default.join(projectPath, ".coco", "spec");
|
|
1782
1789
|
return {
|
|
1783
1790
|
baseDir,
|
|
1784
|
-
sessionFile:
|
|
1785
|
-
specFile:
|
|
1786
|
-
conversationLog:
|
|
1787
|
-
checkpointFile:
|
|
1791
|
+
sessionFile: path17__default.join(baseDir, "discovery-session.json"),
|
|
1792
|
+
specFile: path17__default.join(baseDir, "spec.md"),
|
|
1793
|
+
conversationLog: path17__default.join(baseDir, "conversation.jsonl"),
|
|
1794
|
+
checkpointFile: path17__default.join(baseDir, "checkpoint.json")
|
|
1788
1795
|
};
|
|
1789
1796
|
}
|
|
1790
1797
|
var SessionPersistence = class {
|
|
@@ -1797,7 +1804,7 @@ var SessionPersistence = class {
|
|
|
1797
1804
|
*/
|
|
1798
1805
|
async ensureDir() {
|
|
1799
1806
|
try {
|
|
1800
|
-
await
|
|
1807
|
+
await fs16__default.mkdir(this.paths.baseDir, { recursive: true });
|
|
1801
1808
|
} catch {
|
|
1802
1809
|
throw new FileSystemError(`Failed to create persistence directory: ${this.paths.baseDir}`, {
|
|
1803
1810
|
path: this.paths.baseDir,
|
|
@@ -1812,7 +1819,7 @@ var SessionPersistence = class {
|
|
|
1812
1819
|
await this.ensureDir();
|
|
1813
1820
|
try {
|
|
1814
1821
|
const data = JSON.stringify(session, null, 2);
|
|
1815
|
-
await
|
|
1822
|
+
await fs16__default.writeFile(this.paths.sessionFile, data, "utf-8");
|
|
1816
1823
|
} catch {
|
|
1817
1824
|
throw new FileSystemError("Failed to save discovery session", {
|
|
1818
1825
|
path: this.paths.sessionFile,
|
|
@@ -1825,7 +1832,7 @@ var SessionPersistence = class {
|
|
|
1825
1832
|
*/
|
|
1826
1833
|
async loadSession() {
|
|
1827
1834
|
try {
|
|
1828
|
-
const data = await
|
|
1835
|
+
const data = await fs16__default.readFile(this.paths.sessionFile, "utf-8");
|
|
1829
1836
|
const parsed = JSON.parse(data);
|
|
1830
1837
|
parsed.startedAt = new Date(parsed.startedAt);
|
|
1831
1838
|
parsed.updatedAt = new Date(parsed.updatedAt);
|
|
@@ -1851,7 +1858,7 @@ var SessionPersistence = class {
|
|
|
1851
1858
|
*/
|
|
1852
1859
|
async hasSession() {
|
|
1853
1860
|
try {
|
|
1854
|
-
await
|
|
1861
|
+
await fs16__default.access(this.paths.sessionFile);
|
|
1855
1862
|
return true;
|
|
1856
1863
|
} catch {
|
|
1857
1864
|
return false;
|
|
@@ -1862,7 +1869,7 @@ var SessionPersistence = class {
|
|
|
1862
1869
|
*/
|
|
1863
1870
|
async deleteSession() {
|
|
1864
1871
|
try {
|
|
1865
|
-
await
|
|
1872
|
+
await fs16__default.unlink(this.paths.sessionFile);
|
|
1866
1873
|
} catch (error) {
|
|
1867
1874
|
if (error.code !== "ENOENT") {
|
|
1868
1875
|
throw new FileSystemError("Failed to delete discovery session", {
|
|
@@ -1878,7 +1885,7 @@ var SessionPersistence = class {
|
|
|
1878
1885
|
async saveSpecification(content) {
|
|
1879
1886
|
await this.ensureDir();
|
|
1880
1887
|
try {
|
|
1881
|
-
await
|
|
1888
|
+
await fs16__default.writeFile(this.paths.specFile, content, "utf-8");
|
|
1882
1889
|
} catch {
|
|
1883
1890
|
throw new FileSystemError("Failed to save specification", {
|
|
1884
1891
|
path: this.paths.specFile,
|
|
@@ -1891,7 +1898,7 @@ var SessionPersistence = class {
|
|
|
1891
1898
|
*/
|
|
1892
1899
|
async loadSpecification() {
|
|
1893
1900
|
try {
|
|
1894
|
-
return await
|
|
1901
|
+
return await fs16__default.readFile(this.paths.specFile, "utf-8");
|
|
1895
1902
|
} catch {
|
|
1896
1903
|
return null;
|
|
1897
1904
|
}
|
|
@@ -1907,7 +1914,7 @@ var SessionPersistence = class {
|
|
|
1907
1914
|
content
|
|
1908
1915
|
};
|
|
1909
1916
|
try {
|
|
1910
|
-
await
|
|
1917
|
+
await fs16__default.appendFile(this.paths.conversationLog, JSON.stringify(entry) + "\n", "utf-8");
|
|
1911
1918
|
} catch {
|
|
1912
1919
|
throw new FileSystemError("Failed to append to conversation log", {
|
|
1913
1920
|
path: this.paths.conversationLog,
|
|
@@ -1920,7 +1927,7 @@ var SessionPersistence = class {
|
|
|
1920
1927
|
*/
|
|
1921
1928
|
async loadConversationLog() {
|
|
1922
1929
|
try {
|
|
1923
|
-
const data = await
|
|
1930
|
+
const data = await fs16__default.readFile(this.paths.conversationLog, "utf-8");
|
|
1924
1931
|
const lines = data.trim().split("\n");
|
|
1925
1932
|
return lines.filter((line) => line.trim()).map((line) => JSON.parse(line));
|
|
1926
1933
|
} catch {
|
|
@@ -1934,7 +1941,7 @@ var SessionPersistence = class {
|
|
|
1934
1941
|
await this.ensureDir();
|
|
1935
1942
|
try {
|
|
1936
1943
|
const data = JSON.stringify(checkpoint, null, 2);
|
|
1937
|
-
await
|
|
1944
|
+
await fs16__default.writeFile(this.paths.checkpointFile, data, "utf-8");
|
|
1938
1945
|
} catch {
|
|
1939
1946
|
throw new FileSystemError("Failed to save checkpoint", {
|
|
1940
1947
|
path: this.paths.checkpointFile,
|
|
@@ -1947,7 +1954,7 @@ var SessionPersistence = class {
|
|
|
1947
1954
|
*/
|
|
1948
1955
|
async loadCheckpoint() {
|
|
1949
1956
|
try {
|
|
1950
|
-
const data = await
|
|
1957
|
+
const data = await fs16__default.readFile(this.paths.checkpointFile, "utf-8");
|
|
1951
1958
|
const parsed = JSON.parse(data);
|
|
1952
1959
|
parsed.timestamp = new Date(parsed.timestamp);
|
|
1953
1960
|
return parsed;
|
|
@@ -1960,7 +1967,7 @@ var SessionPersistence = class {
|
|
|
1960
1967
|
*/
|
|
1961
1968
|
async clearAll() {
|
|
1962
1969
|
try {
|
|
1963
|
-
await
|
|
1970
|
+
await fs16__default.rm(this.paths.baseDir, { recursive: true, force: true });
|
|
1964
1971
|
} catch (error) {
|
|
1965
1972
|
if (error.code !== "ENOENT") {
|
|
1966
1973
|
throw new FileSystemError("Failed to clear persistence data", {
|
|
@@ -3814,8 +3821,8 @@ var OrchestrateExecutor = class {
|
|
|
3814
3821
|
}
|
|
3815
3822
|
async loadSpecification(projectPath) {
|
|
3816
3823
|
try {
|
|
3817
|
-
const jsonPath =
|
|
3818
|
-
const jsonContent = await
|
|
3824
|
+
const jsonPath = path17__default.join(projectPath, ".coco", "spec", "spec.json");
|
|
3825
|
+
const jsonContent = await fs16__default.readFile(jsonPath, "utf-8");
|
|
3819
3826
|
return JSON.parse(jsonContent);
|
|
3820
3827
|
} catch {
|
|
3821
3828
|
return this.createMinimalSpec(projectPath);
|
|
@@ -3826,7 +3833,7 @@ var OrchestrateExecutor = class {
|
|
|
3826
3833
|
version: "1.0.0",
|
|
3827
3834
|
generatedAt: /* @__PURE__ */ new Date(),
|
|
3828
3835
|
overview: {
|
|
3829
|
-
name:
|
|
3836
|
+
name: path17__default.basename(projectPath),
|
|
3830
3837
|
description: "Project specification",
|
|
3831
3838
|
goals: [],
|
|
3832
3839
|
targetUsers: ["developers"],
|
|
@@ -3853,53 +3860,53 @@ var OrchestrateExecutor = class {
|
|
|
3853
3860
|
};
|
|
3854
3861
|
}
|
|
3855
3862
|
async saveArchitecture(projectPath, architecture) {
|
|
3856
|
-
const dir =
|
|
3857
|
-
await
|
|
3858
|
-
const mdPath =
|
|
3859
|
-
await
|
|
3860
|
-
const jsonPath =
|
|
3861
|
-
await
|
|
3863
|
+
const dir = path17__default.join(projectPath, ".coco", "architecture");
|
|
3864
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
3865
|
+
const mdPath = path17__default.join(dir, "ARCHITECTURE.md");
|
|
3866
|
+
await fs16__default.writeFile(mdPath, generateArchitectureMarkdown(architecture), "utf-8");
|
|
3867
|
+
const jsonPath = path17__default.join(dir, "architecture.json");
|
|
3868
|
+
await fs16__default.writeFile(jsonPath, JSON.stringify(architecture, null, 2), "utf-8");
|
|
3862
3869
|
return mdPath;
|
|
3863
3870
|
}
|
|
3864
3871
|
async saveADRs(projectPath, adrs) {
|
|
3865
|
-
const dir =
|
|
3866
|
-
await
|
|
3872
|
+
const dir = path17__default.join(projectPath, ".coco", "architecture", "adrs");
|
|
3873
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
3867
3874
|
const paths = [];
|
|
3868
|
-
const indexPath =
|
|
3869
|
-
await
|
|
3875
|
+
const indexPath = path17__default.join(dir, "README.md");
|
|
3876
|
+
await fs16__default.writeFile(indexPath, generateADRIndexMarkdown(adrs), "utf-8");
|
|
3870
3877
|
paths.push(indexPath);
|
|
3871
3878
|
for (const adr of adrs) {
|
|
3872
3879
|
const filename = getADRFilename(adr);
|
|
3873
|
-
const adrPath =
|
|
3874
|
-
await
|
|
3880
|
+
const adrPath = path17__default.join(dir, filename);
|
|
3881
|
+
await fs16__default.writeFile(adrPath, generateADRMarkdown(adr), "utf-8");
|
|
3875
3882
|
paths.push(adrPath);
|
|
3876
3883
|
}
|
|
3877
3884
|
return paths;
|
|
3878
3885
|
}
|
|
3879
3886
|
async saveBacklog(projectPath, backlogResult) {
|
|
3880
|
-
const dir =
|
|
3881
|
-
await
|
|
3882
|
-
const mdPath =
|
|
3883
|
-
await
|
|
3884
|
-
const jsonPath =
|
|
3885
|
-
await
|
|
3887
|
+
const dir = path17__default.join(projectPath, ".coco", "planning");
|
|
3888
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
3889
|
+
const mdPath = path17__default.join(dir, "BACKLOG.md");
|
|
3890
|
+
await fs16__default.writeFile(mdPath, generateBacklogMarkdown(backlogResult.backlog), "utf-8");
|
|
3891
|
+
const jsonPath = path17__default.join(dir, "backlog.json");
|
|
3892
|
+
await fs16__default.writeFile(jsonPath, JSON.stringify(backlogResult, null, 2), "utf-8");
|
|
3886
3893
|
return mdPath;
|
|
3887
3894
|
}
|
|
3888
3895
|
async saveSprint(projectPath, sprint, backlogResult) {
|
|
3889
|
-
const dir =
|
|
3890
|
-
await
|
|
3896
|
+
const dir = path17__default.join(projectPath, ".coco", "planning", "sprints");
|
|
3897
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
3891
3898
|
const filename = `${sprint.id}.md`;
|
|
3892
|
-
const sprintPath =
|
|
3893
|
-
await
|
|
3894
|
-
const jsonPath =
|
|
3895
|
-
await
|
|
3899
|
+
const sprintPath = path17__default.join(dir, filename);
|
|
3900
|
+
await fs16__default.writeFile(sprintPath, generateSprintMarkdown(sprint, backlogResult.backlog), "utf-8");
|
|
3901
|
+
const jsonPath = path17__default.join(dir, `${sprint.id}.json`);
|
|
3902
|
+
await fs16__default.writeFile(jsonPath, JSON.stringify(sprint, null, 2), "utf-8");
|
|
3896
3903
|
return sprintPath;
|
|
3897
3904
|
}
|
|
3898
3905
|
async saveDiagram(projectPath, id, mermaid) {
|
|
3899
|
-
const dir =
|
|
3900
|
-
await
|
|
3901
|
-
const diagramPath =
|
|
3902
|
-
await
|
|
3906
|
+
const dir = path17__default.join(projectPath, ".coco", "architecture", "diagrams");
|
|
3907
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
3908
|
+
const diagramPath = path17__default.join(dir, `${id}.mmd`);
|
|
3909
|
+
await fs16__default.writeFile(diagramPath, mermaid, "utf-8");
|
|
3903
3910
|
return diagramPath;
|
|
3904
3911
|
}
|
|
3905
3912
|
};
|
|
@@ -4054,10 +4061,10 @@ var CoverageAnalyzer = class {
|
|
|
4054
4061
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
4055
4062
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
4056
4063
|
];
|
|
4057
|
-
for (const
|
|
4064
|
+
for (const path40 of possiblePaths) {
|
|
4058
4065
|
try {
|
|
4059
|
-
await access(
|
|
4060
|
-
const content = await readFile(
|
|
4066
|
+
await access(path40, constants.R_OK);
|
|
4067
|
+
const content = await readFile(path40, "utf-8");
|
|
4061
4068
|
const report = JSON.parse(content);
|
|
4062
4069
|
return parseCoverageSummary(report);
|
|
4063
4070
|
} catch {
|
|
@@ -4776,7 +4783,7 @@ var BuildVerifier = class {
|
|
|
4776
4783
|
async verifyTypes() {
|
|
4777
4784
|
const startTime = Date.now();
|
|
4778
4785
|
try {
|
|
4779
|
-
const hasTsConfig = await this.fileExists(
|
|
4786
|
+
const hasTsConfig = await this.fileExists(path17.join(this.projectPath, "tsconfig.json"));
|
|
4780
4787
|
if (!hasTsConfig) {
|
|
4781
4788
|
return {
|
|
4782
4789
|
success: true,
|
|
@@ -4826,8 +4833,8 @@ var BuildVerifier = class {
|
|
|
4826
4833
|
*/
|
|
4827
4834
|
async detectBuildCommand() {
|
|
4828
4835
|
try {
|
|
4829
|
-
const packageJsonPath =
|
|
4830
|
-
const content = await
|
|
4836
|
+
const packageJsonPath = path17.join(this.projectPath, "package.json");
|
|
4837
|
+
const content = await fs16.readFile(packageJsonPath, "utf-8");
|
|
4831
4838
|
const packageJson = JSON.parse(content);
|
|
4832
4839
|
if (packageJson.scripts?.build) {
|
|
4833
4840
|
return "npm run build";
|
|
@@ -4903,7 +4910,7 @@ var BuildVerifier = class {
|
|
|
4903
4910
|
*/
|
|
4904
4911
|
async fileExists(filePath) {
|
|
4905
4912
|
try {
|
|
4906
|
-
await
|
|
4913
|
+
await fs16.access(filePath);
|
|
4907
4914
|
return true;
|
|
4908
4915
|
} catch {
|
|
4909
4916
|
return false;
|
|
@@ -6449,9 +6456,9 @@ function detectProjectLanguage(files) {
|
|
|
6449
6456
|
return { language: dominant, confidence, evidence };
|
|
6450
6457
|
}
|
|
6451
6458
|
function getFileExtension(filePath) {
|
|
6452
|
-
const base =
|
|
6459
|
+
const base = path17.basename(filePath);
|
|
6453
6460
|
if (base.endsWith(".d.ts")) return ".d.ts";
|
|
6454
|
-
return
|
|
6461
|
+
return path17.extname(filePath).toLowerCase();
|
|
6455
6462
|
}
|
|
6456
6463
|
function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
6457
6464
|
const evidence = [];
|
|
@@ -6459,7 +6466,7 @@ function buildEvidence(dominant, counts, totalSourceFiles, files) {
|
|
|
6459
6466
|
evidence.push(`${dominantCount} of ${totalSourceFiles} source files are ${dominant}`);
|
|
6460
6467
|
const configFiles = ["tsconfig.json", "pom.xml", "build.gradle", "Cargo.toml", "go.mod"];
|
|
6461
6468
|
for (const cfg of configFiles) {
|
|
6462
|
-
if (files.some((f) =>
|
|
6469
|
+
if (files.some((f) => path17.basename(f) === cfg)) {
|
|
6463
6470
|
evidence.push(`Found ${cfg}`);
|
|
6464
6471
|
}
|
|
6465
6472
|
}
|
|
@@ -8171,7 +8178,7 @@ function setupFileLogging(logger, logDir, name) {
|
|
|
8171
8178
|
if (!fs4__default.existsSync(logDir)) {
|
|
8172
8179
|
fs4__default.mkdirSync(logDir, { recursive: true });
|
|
8173
8180
|
}
|
|
8174
|
-
const logFile =
|
|
8181
|
+
const logFile = path17__default.join(logDir, `${name}.log`);
|
|
8175
8182
|
logger.attachTransport((logObj) => {
|
|
8176
8183
|
const line = JSON.stringify(logObj) + "\n";
|
|
8177
8184
|
fs4__default.appendFileSync(logFile, line);
|
|
@@ -8234,12 +8241,12 @@ function humanizeError(message, toolName) {
|
|
|
8234
8241
|
return msg;
|
|
8235
8242
|
}
|
|
8236
8243
|
if (/ENOENT/i.test(msg)) {
|
|
8237
|
-
const
|
|
8238
|
-
return
|
|
8244
|
+
const path40 = extractQuotedPath(msg);
|
|
8245
|
+
return path40 ? `File or directory not found: ${path40}` : "File or directory not found";
|
|
8239
8246
|
}
|
|
8240
8247
|
if (/EACCES/i.test(msg)) {
|
|
8241
|
-
const
|
|
8242
|
-
return
|
|
8248
|
+
const path40 = extractQuotedPath(msg);
|
|
8249
|
+
return path40 ? `Permission denied: ${path40}` : "Permission denied \u2014 check file permissions";
|
|
8243
8250
|
}
|
|
8244
8251
|
if (/EISDIR/i.test(msg)) {
|
|
8245
8252
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -9724,14 +9731,14 @@ var CompleteExecutor = class {
|
|
|
9724
9731
|
*/
|
|
9725
9732
|
async checkpoint(context) {
|
|
9726
9733
|
if (this.checkpointState && this.currentSprint) {
|
|
9727
|
-
const checkpointPath =
|
|
9734
|
+
const checkpointPath = path17__default.join(
|
|
9728
9735
|
context.projectPath,
|
|
9729
9736
|
".coco",
|
|
9730
9737
|
"checkpoints",
|
|
9731
9738
|
`complete-${this.currentSprint.id}.json`
|
|
9732
9739
|
);
|
|
9733
|
-
await
|
|
9734
|
-
await
|
|
9740
|
+
await fs16__default.mkdir(path17__default.dirname(checkpointPath), { recursive: true });
|
|
9741
|
+
await fs16__default.writeFile(checkpointPath, JSON.stringify(this.checkpointState, null, 2), "utf-8");
|
|
9735
9742
|
}
|
|
9736
9743
|
return {
|
|
9737
9744
|
phase: "complete",
|
|
@@ -9751,13 +9758,13 @@ var CompleteExecutor = class {
|
|
|
9751
9758
|
const sprintId = checkpoint.resumePoint;
|
|
9752
9759
|
if (sprintId === "start") return;
|
|
9753
9760
|
try {
|
|
9754
|
-
const checkpointPath =
|
|
9761
|
+
const checkpointPath = path17__default.join(
|
|
9755
9762
|
context.projectPath,
|
|
9756
9763
|
".coco",
|
|
9757
9764
|
"checkpoints",
|
|
9758
9765
|
`complete-${sprintId}.json`
|
|
9759
9766
|
);
|
|
9760
|
-
const content = await
|
|
9767
|
+
const content = await fs16__default.readFile(checkpointPath, "utf-8");
|
|
9761
9768
|
this.checkpointState = JSON.parse(content);
|
|
9762
9769
|
this.completedTaskIds = new Set(this.checkpointState.completedTaskIds);
|
|
9763
9770
|
} catch {
|
|
@@ -10004,14 +10011,14 @@ var CompleteExecutor = class {
|
|
|
10004
10011
|
};
|
|
10005
10012
|
const saveFiles = async (files) => {
|
|
10006
10013
|
for (const file of files) {
|
|
10007
|
-
const filePath =
|
|
10008
|
-
const dir =
|
|
10009
|
-
await
|
|
10014
|
+
const filePath = path17__default.join(context.projectPath, file.path);
|
|
10015
|
+
const dir = path17__default.dirname(filePath);
|
|
10016
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
10010
10017
|
if (file.action === "delete") {
|
|
10011
|
-
await
|
|
10018
|
+
await fs16__default.unlink(filePath).catch(() => {
|
|
10012
10019
|
});
|
|
10013
10020
|
} else {
|
|
10014
|
-
await
|
|
10021
|
+
await fs16__default.writeFile(filePath, file.content, "utf-8");
|
|
10015
10022
|
}
|
|
10016
10023
|
}
|
|
10017
10024
|
};
|
|
@@ -10137,8 +10144,8 @@ var CompleteExecutor = class {
|
|
|
10137
10144
|
*/
|
|
10138
10145
|
async loadBacklog(projectPath) {
|
|
10139
10146
|
try {
|
|
10140
|
-
const backlogPath =
|
|
10141
|
-
const content = await
|
|
10147
|
+
const backlogPath = path17__default.join(projectPath, ".coco", "planning", "backlog.json");
|
|
10148
|
+
const content = await fs16__default.readFile(backlogPath, "utf-8");
|
|
10142
10149
|
const data = JSON.parse(content);
|
|
10143
10150
|
return data.backlog;
|
|
10144
10151
|
} catch {
|
|
@@ -10150,12 +10157,12 @@ var CompleteExecutor = class {
|
|
|
10150
10157
|
*/
|
|
10151
10158
|
async loadCurrentSprint(projectPath) {
|
|
10152
10159
|
try {
|
|
10153
|
-
const sprintsDir =
|
|
10154
|
-
const files = await
|
|
10160
|
+
const sprintsDir = path17__default.join(projectPath, ".coco", "planning", "sprints");
|
|
10161
|
+
const files = await fs16__default.readdir(sprintsDir);
|
|
10155
10162
|
const jsonFiles = files.filter((f) => f.endsWith(".json"));
|
|
10156
10163
|
if (jsonFiles.length === 0) return null;
|
|
10157
|
-
const sprintPath =
|
|
10158
|
-
const content = await
|
|
10164
|
+
const sprintPath = path17__default.join(sprintsDir, jsonFiles[0] || "");
|
|
10165
|
+
const content = await fs16__default.readFile(sprintPath, "utf-8");
|
|
10159
10166
|
const sprint = JSON.parse(content);
|
|
10160
10167
|
sprint.startDate = new Date(sprint.startDate);
|
|
10161
10168
|
return sprint;
|
|
@@ -10167,12 +10174,12 @@ var CompleteExecutor = class {
|
|
|
10167
10174
|
* Save sprint results
|
|
10168
10175
|
*/
|
|
10169
10176
|
async saveSprintResults(projectPath, result) {
|
|
10170
|
-
const resultsDir =
|
|
10171
|
-
await
|
|
10172
|
-
const resultsPath =
|
|
10173
|
-
await
|
|
10174
|
-
const mdPath =
|
|
10175
|
-
await
|
|
10177
|
+
const resultsDir = path17__default.join(projectPath, ".coco", "results");
|
|
10178
|
+
await fs16__default.mkdir(resultsDir, { recursive: true });
|
|
10179
|
+
const resultsPath = path17__default.join(resultsDir, `${result.sprintId}-results.json`);
|
|
10180
|
+
await fs16__default.writeFile(resultsPath, JSON.stringify(result, null, 2), "utf-8");
|
|
10181
|
+
const mdPath = path17__default.join(resultsDir, `${result.sprintId}-results.md`);
|
|
10182
|
+
await fs16__default.writeFile(mdPath, this.generateResultsMarkdown(result), "utf-8");
|
|
10176
10183
|
return resultsPath;
|
|
10177
10184
|
}
|
|
10178
10185
|
/**
|
|
@@ -11396,9 +11403,9 @@ var OutputExecutor = class {
|
|
|
11396
11403
|
const cicdGenerator = new CICDGenerator(metadata, cicdConfig);
|
|
11397
11404
|
const cicdFiles = cicdGenerator.generate();
|
|
11398
11405
|
for (const file of cicdFiles) {
|
|
11399
|
-
const filePath =
|
|
11400
|
-
await this.ensureDir(
|
|
11401
|
-
await
|
|
11406
|
+
const filePath = path17__default.join(context.projectPath, file.path);
|
|
11407
|
+
await this.ensureDir(path17__default.dirname(filePath));
|
|
11408
|
+
await fs16__default.writeFile(filePath, file.content, "utf-8");
|
|
11402
11409
|
artifacts.push({
|
|
11403
11410
|
type: "cicd",
|
|
11404
11411
|
path: filePath,
|
|
@@ -11408,16 +11415,16 @@ var OutputExecutor = class {
|
|
|
11408
11415
|
if (this.config.docker.enabled) {
|
|
11409
11416
|
const dockerGenerator = new DockerGenerator(metadata);
|
|
11410
11417
|
const dockerfile2 = dockerGenerator.generateDockerfile();
|
|
11411
|
-
const dockerfilePath =
|
|
11412
|
-
await
|
|
11418
|
+
const dockerfilePath = path17__default.join(context.projectPath, "Dockerfile");
|
|
11419
|
+
await fs16__default.writeFile(dockerfilePath, dockerfile2, "utf-8");
|
|
11413
11420
|
artifacts.push({
|
|
11414
11421
|
type: "deployment",
|
|
11415
11422
|
path: dockerfilePath,
|
|
11416
11423
|
description: "Dockerfile"
|
|
11417
11424
|
});
|
|
11418
11425
|
const dockerignore = dockerGenerator.generateDockerignore();
|
|
11419
|
-
const dockerignorePath =
|
|
11420
|
-
await
|
|
11426
|
+
const dockerignorePath = path17__default.join(context.projectPath, ".dockerignore");
|
|
11427
|
+
await fs16__default.writeFile(dockerignorePath, dockerignore, "utf-8");
|
|
11421
11428
|
artifacts.push({
|
|
11422
11429
|
type: "deployment",
|
|
11423
11430
|
path: dockerignorePath,
|
|
@@ -11425,8 +11432,8 @@ var OutputExecutor = class {
|
|
|
11425
11432
|
});
|
|
11426
11433
|
if (this.config.docker.compose) {
|
|
11427
11434
|
const compose = dockerGenerator.generateDockerCompose();
|
|
11428
|
-
const composePath =
|
|
11429
|
-
await
|
|
11435
|
+
const composePath = path17__default.join(context.projectPath, "docker-compose.yml");
|
|
11436
|
+
await fs16__default.writeFile(composePath, compose, "utf-8");
|
|
11430
11437
|
artifacts.push({
|
|
11431
11438
|
type: "deployment",
|
|
11432
11439
|
path: composePath,
|
|
@@ -11437,8 +11444,8 @@ var OutputExecutor = class {
|
|
|
11437
11444
|
const docsGenerator = new DocsGenerator(metadata);
|
|
11438
11445
|
const docs = docsGenerator.generate();
|
|
11439
11446
|
if (this.config.docs.readme) {
|
|
11440
|
-
const readmePath =
|
|
11441
|
-
await
|
|
11447
|
+
const readmePath = path17__default.join(context.projectPath, "README.md");
|
|
11448
|
+
await fs16__default.writeFile(readmePath, docs.readme, "utf-8");
|
|
11442
11449
|
artifacts.push({
|
|
11443
11450
|
type: "documentation",
|
|
11444
11451
|
path: readmePath,
|
|
@@ -11446,8 +11453,8 @@ var OutputExecutor = class {
|
|
|
11446
11453
|
});
|
|
11447
11454
|
}
|
|
11448
11455
|
if (this.config.docs.contributing) {
|
|
11449
|
-
const contributingPath =
|
|
11450
|
-
await
|
|
11456
|
+
const contributingPath = path17__default.join(context.projectPath, "CONTRIBUTING.md");
|
|
11457
|
+
await fs16__default.writeFile(contributingPath, docs.contributing, "utf-8");
|
|
11451
11458
|
artifacts.push({
|
|
11452
11459
|
type: "documentation",
|
|
11453
11460
|
path: contributingPath,
|
|
@@ -11455,8 +11462,8 @@ var OutputExecutor = class {
|
|
|
11455
11462
|
});
|
|
11456
11463
|
}
|
|
11457
11464
|
if (this.config.docs.changelog) {
|
|
11458
|
-
const changelogPath =
|
|
11459
|
-
await
|
|
11465
|
+
const changelogPath = path17__default.join(context.projectPath, "CHANGELOG.md");
|
|
11466
|
+
await fs16__default.writeFile(changelogPath, docs.changelog, "utf-8");
|
|
11460
11467
|
artifacts.push({
|
|
11461
11468
|
type: "documentation",
|
|
11462
11469
|
path: changelogPath,
|
|
@@ -11464,11 +11471,11 @@ var OutputExecutor = class {
|
|
|
11464
11471
|
});
|
|
11465
11472
|
}
|
|
11466
11473
|
if (this.config.docs.api) {
|
|
11467
|
-
const docsDir =
|
|
11474
|
+
const docsDir = path17__default.join(context.projectPath, "docs");
|
|
11468
11475
|
await this.ensureDir(docsDir);
|
|
11469
11476
|
if (docs.api) {
|
|
11470
|
-
const apiPath =
|
|
11471
|
-
await
|
|
11477
|
+
const apiPath = path17__default.join(docsDir, "api.md");
|
|
11478
|
+
await fs16__default.writeFile(apiPath, docs.api, "utf-8");
|
|
11472
11479
|
artifacts.push({
|
|
11473
11480
|
type: "documentation",
|
|
11474
11481
|
path: apiPath,
|
|
@@ -11476,8 +11483,8 @@ var OutputExecutor = class {
|
|
|
11476
11483
|
});
|
|
11477
11484
|
}
|
|
11478
11485
|
if (docs.deployment) {
|
|
11479
|
-
const deployPath =
|
|
11480
|
-
await
|
|
11486
|
+
const deployPath = path17__default.join(docsDir, "deployment.md");
|
|
11487
|
+
await fs16__default.writeFile(deployPath, docs.deployment, "utf-8");
|
|
11481
11488
|
artifacts.push({
|
|
11482
11489
|
type: "documentation",
|
|
11483
11490
|
path: deployPath,
|
|
@@ -11485,8 +11492,8 @@ var OutputExecutor = class {
|
|
|
11485
11492
|
});
|
|
11486
11493
|
}
|
|
11487
11494
|
if (docs.development) {
|
|
11488
|
-
const devPath =
|
|
11489
|
-
await
|
|
11495
|
+
const devPath = path17__default.join(docsDir, "development.md");
|
|
11496
|
+
await fs16__default.writeFile(devPath, docs.development, "utf-8");
|
|
11490
11497
|
artifacts.push({
|
|
11491
11498
|
type: "documentation",
|
|
11492
11499
|
path: devPath,
|
|
@@ -11551,16 +11558,16 @@ var OutputExecutor = class {
|
|
|
11551
11558
|
*/
|
|
11552
11559
|
async loadMetadata(projectPath) {
|
|
11553
11560
|
try {
|
|
11554
|
-
const packagePath =
|
|
11555
|
-
const content = await
|
|
11561
|
+
const packagePath = path17__default.join(projectPath, "package.json");
|
|
11562
|
+
const content = await fs16__default.readFile(packagePath, "utf-8");
|
|
11556
11563
|
const pkg = JSON.parse(content);
|
|
11557
11564
|
let packageManager = "npm";
|
|
11558
11565
|
try {
|
|
11559
|
-
await
|
|
11566
|
+
await fs16__default.access(path17__default.join(projectPath, "pnpm-lock.yaml"));
|
|
11560
11567
|
packageManager = "pnpm";
|
|
11561
11568
|
} catch {
|
|
11562
11569
|
try {
|
|
11563
|
-
await
|
|
11570
|
+
await fs16__default.access(path17__default.join(projectPath, "yarn.lock"));
|
|
11564
11571
|
packageManager = "yarn";
|
|
11565
11572
|
} catch {
|
|
11566
11573
|
}
|
|
@@ -11572,7 +11579,7 @@ var OutputExecutor = class {
|
|
|
11572
11579
|
repository = pkg.repository.url;
|
|
11573
11580
|
}
|
|
11574
11581
|
return {
|
|
11575
|
-
name: pkg.name ||
|
|
11582
|
+
name: pkg.name || path17__default.basename(projectPath),
|
|
11576
11583
|
description: pkg.description || "",
|
|
11577
11584
|
version: pkg.version || "0.1.0",
|
|
11578
11585
|
language: "typescript",
|
|
@@ -11586,7 +11593,7 @@ var OutputExecutor = class {
|
|
|
11586
11593
|
};
|
|
11587
11594
|
} catch {
|
|
11588
11595
|
return {
|
|
11589
|
-
name:
|
|
11596
|
+
name: path17__default.basename(projectPath),
|
|
11590
11597
|
description: "",
|
|
11591
11598
|
version: "0.1.0",
|
|
11592
11599
|
language: "typescript",
|
|
@@ -11602,7 +11609,7 @@ var OutputExecutor = class {
|
|
|
11602
11609
|
* Ensure directory exists
|
|
11603
11610
|
*/
|
|
11604
11611
|
async ensureDir(dir) {
|
|
11605
|
-
await
|
|
11612
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
11606
11613
|
}
|
|
11607
11614
|
};
|
|
11608
11615
|
function createOutputExecutor(config) {
|
|
@@ -11664,18 +11671,19 @@ async function withRetry(fn, config = {}) {
|
|
|
11664
11671
|
}
|
|
11665
11672
|
|
|
11666
11673
|
// src/providers/anthropic.ts
|
|
11667
|
-
var DEFAULT_MODEL = "claude-opus-4-6
|
|
11674
|
+
var DEFAULT_MODEL = "claude-opus-4-6";
|
|
11668
11675
|
var CONTEXT_WINDOWS = {
|
|
11669
11676
|
// Kimi Code model (Anthropic-compatible endpoint)
|
|
11670
11677
|
"kimi-for-coding": 131072,
|
|
11671
|
-
// Claude 4.6 (latest
|
|
11672
|
-
"claude-opus-4-6
|
|
11673
|
-
|
|
11674
|
-
|
|
11678
|
+
// Claude 4.6 (latest) — 200K standard, 1M beta
|
|
11679
|
+
"claude-opus-4-6": 2e5,
|
|
11680
|
+
"claude-sonnet-4-6": 2e5,
|
|
11681
|
+
// Claude 4.5 models
|
|
11682
|
+
"claude-opus-4-5-20251101": 2e5,
|
|
11675
11683
|
"claude-sonnet-4-5-20250929": 2e5,
|
|
11676
11684
|
"claude-haiku-4-5-20251001": 2e5,
|
|
11677
11685
|
// Claude 4.1 models
|
|
11678
|
-
"claude-opus-4-1-
|
|
11686
|
+
"claude-opus-4-1-20250805": 2e5,
|
|
11679
11687
|
// Claude 4 models
|
|
11680
11688
|
"claude-sonnet-4-20250514": 2e5,
|
|
11681
11689
|
"claude-opus-4-20250514": 2e5,
|
|
@@ -11797,12 +11805,16 @@ var AnthropicProvider = class {
|
|
|
11797
11805
|
);
|
|
11798
11806
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
11799
11807
|
let lastActivityTime = Date.now();
|
|
11800
|
-
const
|
|
11808
|
+
const timeoutController = new AbortController();
|
|
11809
|
+
const timeoutInterval = setInterval(() => {
|
|
11801
11810
|
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
11802
|
-
|
|
11811
|
+
clearInterval(timeoutInterval);
|
|
11812
|
+
timeoutController.abort();
|
|
11803
11813
|
}
|
|
11804
|
-
};
|
|
11805
|
-
|
|
11814
|
+
}, 5e3);
|
|
11815
|
+
timeoutController.signal.addEventListener("abort", () => stream.controller.abort(), {
|
|
11816
|
+
once: true
|
|
11817
|
+
});
|
|
11806
11818
|
try {
|
|
11807
11819
|
let streamStopReason;
|
|
11808
11820
|
for await (const event of stream) {
|
|
@@ -11823,6 +11835,9 @@ var AnthropicProvider = class {
|
|
|
11823
11835
|
} finally {
|
|
11824
11836
|
clearInterval(timeoutInterval);
|
|
11825
11837
|
}
|
|
11838
|
+
if (timeoutController.signal.aborted) {
|
|
11839
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
11840
|
+
}
|
|
11826
11841
|
} catch (error) {
|
|
11827
11842
|
throw this.handleError(error);
|
|
11828
11843
|
}
|
|
@@ -11849,12 +11864,16 @@ var AnthropicProvider = class {
|
|
|
11849
11864
|
let currentToolInputJson = "";
|
|
11850
11865
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
11851
11866
|
let lastActivityTime = Date.now();
|
|
11852
|
-
const
|
|
11867
|
+
const timeoutController = new AbortController();
|
|
11868
|
+
const timeoutInterval = setInterval(() => {
|
|
11853
11869
|
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
11854
|
-
|
|
11870
|
+
clearInterval(timeoutInterval);
|
|
11871
|
+
timeoutController.abort();
|
|
11855
11872
|
}
|
|
11856
|
-
};
|
|
11857
|
-
|
|
11873
|
+
}, 5e3);
|
|
11874
|
+
timeoutController.signal.addEventListener("abort", () => stream.controller.abort(), {
|
|
11875
|
+
once: true
|
|
11876
|
+
});
|
|
11858
11877
|
try {
|
|
11859
11878
|
let streamStopReason;
|
|
11860
11879
|
for await (const event of stream) {
|
|
@@ -11939,6 +11958,9 @@ var AnthropicProvider = class {
|
|
|
11939
11958
|
} finally {
|
|
11940
11959
|
clearInterval(timeoutInterval);
|
|
11941
11960
|
}
|
|
11961
|
+
if (timeoutController.signal.aborted) {
|
|
11962
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
11963
|
+
}
|
|
11942
11964
|
} catch (error) {
|
|
11943
11965
|
throw this.handleError(error);
|
|
11944
11966
|
}
|
|
@@ -12274,6 +12296,9 @@ var LOCAL_MODEL_PATTERNS = [
|
|
|
12274
12296
|
"starcoder"
|
|
12275
12297
|
];
|
|
12276
12298
|
var MODELS_WITH_THINKING_MODE = ["kimi-k2.5", "kimi-k2-0324", "kimi-latest"];
|
|
12299
|
+
function needsResponsesApi(model) {
|
|
12300
|
+
return model.includes("codex") || model.startsWith("gpt-5") || model.startsWith("o4-") || model.startsWith("o3-");
|
|
12301
|
+
}
|
|
12277
12302
|
var OpenAIProvider = class {
|
|
12278
12303
|
id;
|
|
12279
12304
|
name;
|
|
@@ -12343,9 +12368,12 @@ var OpenAIProvider = class {
|
|
|
12343
12368
|
*/
|
|
12344
12369
|
async chat(messages, options) {
|
|
12345
12370
|
this.ensureInitialized();
|
|
12371
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12372
|
+
if (needsResponsesApi(model)) {
|
|
12373
|
+
return this.chatViaResponses(messages, options);
|
|
12374
|
+
}
|
|
12346
12375
|
return withRetry(async () => {
|
|
12347
12376
|
try {
|
|
12348
|
-
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12349
12377
|
const supportsTemp = this.supportsTemperature(model);
|
|
12350
12378
|
const response = await this.client.chat.completions.create({
|
|
12351
12379
|
model,
|
|
@@ -12377,9 +12405,12 @@ var OpenAIProvider = class {
|
|
|
12377
12405
|
*/
|
|
12378
12406
|
async chatWithTools(messages, options) {
|
|
12379
12407
|
this.ensureInitialized();
|
|
12408
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12409
|
+
if (needsResponsesApi(model)) {
|
|
12410
|
+
return this.chatWithToolsViaResponses(messages, options);
|
|
12411
|
+
}
|
|
12380
12412
|
return withRetry(async () => {
|
|
12381
12413
|
try {
|
|
12382
|
-
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12383
12414
|
const supportsTemp = this.supportsTemperature(model);
|
|
12384
12415
|
const extraBody = this.getExtraBody(model);
|
|
12385
12416
|
const requestParams = {
|
|
@@ -12421,8 +12452,12 @@ var OpenAIProvider = class {
|
|
|
12421
12452
|
*/
|
|
12422
12453
|
async *stream(messages, options) {
|
|
12423
12454
|
this.ensureInitialized();
|
|
12455
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12456
|
+
if (needsResponsesApi(model)) {
|
|
12457
|
+
yield* this.streamViaResponses(messages, options);
|
|
12458
|
+
return;
|
|
12459
|
+
}
|
|
12424
12460
|
try {
|
|
12425
|
-
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12426
12461
|
const supportsTemp = this.supportsTemperature(model);
|
|
12427
12462
|
const stream = await this.client.chat.completions.create({
|
|
12428
12463
|
model,
|
|
@@ -12452,8 +12487,12 @@ var OpenAIProvider = class {
|
|
|
12452
12487
|
*/
|
|
12453
12488
|
async *streamWithTools(messages, options) {
|
|
12454
12489
|
this.ensureInitialized();
|
|
12490
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12491
|
+
if (needsResponsesApi(model)) {
|
|
12492
|
+
yield* this.streamWithToolsViaResponses(messages, options);
|
|
12493
|
+
return;
|
|
12494
|
+
}
|
|
12455
12495
|
try {
|
|
12456
|
-
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12457
12496
|
const supportsTemp = this.supportsTemperature(model);
|
|
12458
12497
|
const extraBody = this.getExtraBody(model);
|
|
12459
12498
|
const requestParams = {
|
|
@@ -12476,12 +12515,16 @@ var OpenAIProvider = class {
|
|
|
12476
12515
|
const toolCallBuilders = /* @__PURE__ */ new Map();
|
|
12477
12516
|
const streamTimeout = this.config.timeout ?? 12e4;
|
|
12478
12517
|
let lastActivityTime = Date.now();
|
|
12479
|
-
const
|
|
12518
|
+
const timeoutController = new AbortController();
|
|
12519
|
+
const timeoutInterval = setInterval(() => {
|
|
12480
12520
|
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
12481
|
-
|
|
12521
|
+
clearInterval(timeoutInterval);
|
|
12522
|
+
timeoutController.abort();
|
|
12482
12523
|
}
|
|
12483
|
-
};
|
|
12484
|
-
|
|
12524
|
+
}, 5e3);
|
|
12525
|
+
timeoutController.signal.addEventListener("abort", () => stream.controller.abort(), {
|
|
12526
|
+
once: true
|
|
12527
|
+
});
|
|
12485
12528
|
const providerName = this.name;
|
|
12486
12529
|
const parseArguments = (builder) => {
|
|
12487
12530
|
let input = {};
|
|
@@ -12585,6 +12628,9 @@ var OpenAIProvider = class {
|
|
|
12585
12628
|
} finally {
|
|
12586
12629
|
clearInterval(timeoutInterval);
|
|
12587
12630
|
}
|
|
12631
|
+
if (timeoutController.signal.aborted) {
|
|
12632
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
12633
|
+
}
|
|
12588
12634
|
} catch (error) {
|
|
12589
12635
|
throw this.handleError(error);
|
|
12590
12636
|
}
|
|
@@ -12917,6 +12963,375 @@ var OpenAIProvider = class {
|
|
|
12917
12963
|
cause: error instanceof Error ? error : void 0
|
|
12918
12964
|
});
|
|
12919
12965
|
}
|
|
12966
|
+
// --- Responses API support (GPT-5+, Codex, o3, o4 models) ---
|
|
12967
|
+
/**
|
|
12968
|
+
* Simple chat via Responses API (no tools)
|
|
12969
|
+
*/
|
|
12970
|
+
async chatViaResponses(messages, options) {
|
|
12971
|
+
this.ensureInitialized();
|
|
12972
|
+
return withRetry(async () => {
|
|
12973
|
+
try {
|
|
12974
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
12975
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
12976
|
+
const response = await this.client.responses.create({
|
|
12977
|
+
model,
|
|
12978
|
+
input,
|
|
12979
|
+
instructions: instructions ?? void 0,
|
|
12980
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
12981
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
12982
|
+
store: false
|
|
12983
|
+
});
|
|
12984
|
+
return {
|
|
12985
|
+
id: response.id,
|
|
12986
|
+
content: response.output_text ?? "",
|
|
12987
|
+
stopReason: response.status === "completed" ? "end_turn" : "max_tokens",
|
|
12988
|
+
usage: {
|
|
12989
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
12990
|
+
outputTokens: response.usage?.output_tokens ?? 0
|
|
12991
|
+
},
|
|
12992
|
+
model: String(response.model)
|
|
12993
|
+
};
|
|
12994
|
+
} catch (error) {
|
|
12995
|
+
throw this.handleError(error);
|
|
12996
|
+
}
|
|
12997
|
+
}, this.retryConfig);
|
|
12998
|
+
}
|
|
12999
|
+
/**
|
|
13000
|
+
* Chat with tools via Responses API
|
|
13001
|
+
*/
|
|
13002
|
+
async chatWithToolsViaResponses(messages, options) {
|
|
13003
|
+
this.ensureInitialized();
|
|
13004
|
+
return withRetry(async () => {
|
|
13005
|
+
try {
|
|
13006
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
13007
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13008
|
+
const tools = this.convertToolsForResponses(options.tools);
|
|
13009
|
+
const response = await this.client.responses.create({
|
|
13010
|
+
model,
|
|
13011
|
+
input,
|
|
13012
|
+
instructions: instructions ?? void 0,
|
|
13013
|
+
tools,
|
|
13014
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13015
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13016
|
+
store: false
|
|
13017
|
+
});
|
|
13018
|
+
let content = "";
|
|
13019
|
+
const toolCalls = [];
|
|
13020
|
+
for (const item of response.output) {
|
|
13021
|
+
if (item.type === "message") {
|
|
13022
|
+
for (const part of item.content) {
|
|
13023
|
+
if (part.type === "output_text") {
|
|
13024
|
+
content += part.text;
|
|
13025
|
+
}
|
|
13026
|
+
}
|
|
13027
|
+
} else if (item.type === "function_call") {
|
|
13028
|
+
toolCalls.push({
|
|
13029
|
+
id: item.call_id,
|
|
13030
|
+
name: item.name,
|
|
13031
|
+
input: this.parseResponsesArguments(item.arguments)
|
|
13032
|
+
});
|
|
13033
|
+
}
|
|
13034
|
+
}
|
|
13035
|
+
return {
|
|
13036
|
+
id: response.id,
|
|
13037
|
+
content,
|
|
13038
|
+
stopReason: toolCalls.length > 0 ? "tool_use" : "end_turn",
|
|
13039
|
+
usage: {
|
|
13040
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
13041
|
+
outputTokens: response.usage?.output_tokens ?? 0
|
|
13042
|
+
},
|
|
13043
|
+
model: String(response.model),
|
|
13044
|
+
toolCalls
|
|
13045
|
+
};
|
|
13046
|
+
} catch (error) {
|
|
13047
|
+
throw this.handleError(error);
|
|
13048
|
+
}
|
|
13049
|
+
}, this.retryConfig);
|
|
13050
|
+
}
|
|
13051
|
+
/**
|
|
13052
|
+
* Stream via Responses API (no tools)
|
|
13053
|
+
*/
|
|
13054
|
+
async *streamViaResponses(messages, options) {
|
|
13055
|
+
this.ensureInitialized();
|
|
13056
|
+
try {
|
|
13057
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
13058
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13059
|
+
const stream = await this.client.responses.create({
|
|
13060
|
+
model,
|
|
13061
|
+
input,
|
|
13062
|
+
instructions: instructions ?? void 0,
|
|
13063
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13064
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13065
|
+
store: false,
|
|
13066
|
+
stream: true
|
|
13067
|
+
});
|
|
13068
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
13069
|
+
let lastActivityTime = Date.now();
|
|
13070
|
+
const timeoutController = new AbortController();
|
|
13071
|
+
const timeoutInterval = setInterval(() => {
|
|
13072
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
13073
|
+
clearInterval(timeoutInterval);
|
|
13074
|
+
timeoutController.abort();
|
|
13075
|
+
}
|
|
13076
|
+
}, 5e3);
|
|
13077
|
+
timeoutController.signal.addEventListener(
|
|
13078
|
+
"abort",
|
|
13079
|
+
() => stream.controller?.abort(),
|
|
13080
|
+
{ once: true }
|
|
13081
|
+
);
|
|
13082
|
+
try {
|
|
13083
|
+
for await (const event of stream) {
|
|
13084
|
+
lastActivityTime = Date.now();
|
|
13085
|
+
if (event.type === "response.output_text.delta") {
|
|
13086
|
+
yield { type: "text", text: event.delta };
|
|
13087
|
+
} else if (event.type === "response.completed") {
|
|
13088
|
+
yield { type: "done", stopReason: "end_turn" };
|
|
13089
|
+
}
|
|
13090
|
+
}
|
|
13091
|
+
} finally {
|
|
13092
|
+
clearInterval(timeoutInterval);
|
|
13093
|
+
}
|
|
13094
|
+
if (timeoutController.signal.aborted) {
|
|
13095
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
13096
|
+
}
|
|
13097
|
+
} catch (error) {
|
|
13098
|
+
throw this.handleError(error);
|
|
13099
|
+
}
|
|
13100
|
+
}
|
|
13101
|
+
/**
|
|
13102
|
+
* Stream with tools via Responses API
|
|
13103
|
+
*
|
|
13104
|
+
* IMPORTANT: fnCallBuilders is keyed by output item ID (fc.id), NOT by
|
|
13105
|
+
* call_id. The streaming events (function_call_arguments.delta/done) use
|
|
13106
|
+
* item_id which references the output item's id field, not call_id.
|
|
13107
|
+
*/
|
|
13108
|
+
async *streamWithToolsViaResponses(messages, options) {
|
|
13109
|
+
this.ensureInitialized();
|
|
13110
|
+
try {
|
|
13111
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL2;
|
|
13112
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13113
|
+
const tools = options.tools.length > 0 ? this.convertToolsForResponses(options.tools) : void 0;
|
|
13114
|
+
const requestParams = {
|
|
13115
|
+
model,
|
|
13116
|
+
input,
|
|
13117
|
+
instructions: instructions ?? void 0,
|
|
13118
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13119
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13120
|
+
store: false,
|
|
13121
|
+
stream: true
|
|
13122
|
+
};
|
|
13123
|
+
if (tools) {
|
|
13124
|
+
requestParams.tools = tools;
|
|
13125
|
+
}
|
|
13126
|
+
const stream = await this.client.responses.create(
|
|
13127
|
+
requestParams
|
|
13128
|
+
);
|
|
13129
|
+
const fnCallBuilders = /* @__PURE__ */ new Map();
|
|
13130
|
+
const streamTimeout = this.config.timeout ?? 12e4;
|
|
13131
|
+
let lastActivityTime = Date.now();
|
|
13132
|
+
const timeoutController = new AbortController();
|
|
13133
|
+
const timeoutInterval = setInterval(() => {
|
|
13134
|
+
if (Date.now() - lastActivityTime > streamTimeout) {
|
|
13135
|
+
clearInterval(timeoutInterval);
|
|
13136
|
+
timeoutController.abort();
|
|
13137
|
+
}
|
|
13138
|
+
}, 5e3);
|
|
13139
|
+
timeoutController.signal.addEventListener(
|
|
13140
|
+
"abort",
|
|
13141
|
+
() => stream.controller?.abort(),
|
|
13142
|
+
{ once: true }
|
|
13143
|
+
);
|
|
13144
|
+
try {
|
|
13145
|
+
for await (const event of stream) {
|
|
13146
|
+
lastActivityTime = Date.now();
|
|
13147
|
+
switch (event.type) {
|
|
13148
|
+
case "response.output_text.delta":
|
|
13149
|
+
yield { type: "text", text: event.delta };
|
|
13150
|
+
break;
|
|
13151
|
+
case "response.output_item.added":
|
|
13152
|
+
if (event.item.type === "function_call") {
|
|
13153
|
+
const fc = event.item;
|
|
13154
|
+
const itemKey = fc.id ?? fc.call_id;
|
|
13155
|
+
fnCallBuilders.set(itemKey, {
|
|
13156
|
+
callId: fc.call_id,
|
|
13157
|
+
name: fc.name,
|
|
13158
|
+
arguments: ""
|
|
13159
|
+
});
|
|
13160
|
+
yield {
|
|
13161
|
+
type: "tool_use_start",
|
|
13162
|
+
toolCall: { id: fc.call_id, name: fc.name }
|
|
13163
|
+
};
|
|
13164
|
+
}
|
|
13165
|
+
break;
|
|
13166
|
+
case "response.function_call_arguments.delta":
|
|
13167
|
+
{
|
|
13168
|
+
const builder = fnCallBuilders.get(event.item_id);
|
|
13169
|
+
if (builder) {
|
|
13170
|
+
builder.arguments += event.delta;
|
|
13171
|
+
}
|
|
13172
|
+
}
|
|
13173
|
+
break;
|
|
13174
|
+
case "response.function_call_arguments.done":
|
|
13175
|
+
{
|
|
13176
|
+
const builder = fnCallBuilders.get(event.item_id);
|
|
13177
|
+
if (builder) {
|
|
13178
|
+
yield {
|
|
13179
|
+
type: "tool_use_end",
|
|
13180
|
+
toolCall: {
|
|
13181
|
+
id: builder.callId,
|
|
13182
|
+
name: builder.name,
|
|
13183
|
+
input: this.parseResponsesArguments(event.arguments)
|
|
13184
|
+
}
|
|
13185
|
+
};
|
|
13186
|
+
fnCallBuilders.delete(event.item_id);
|
|
13187
|
+
}
|
|
13188
|
+
}
|
|
13189
|
+
break;
|
|
13190
|
+
case "response.completed":
|
|
13191
|
+
{
|
|
13192
|
+
for (const [, builder] of fnCallBuilders) {
|
|
13193
|
+
yield {
|
|
13194
|
+
type: "tool_use_end",
|
|
13195
|
+
toolCall: {
|
|
13196
|
+
id: builder.callId,
|
|
13197
|
+
name: builder.name,
|
|
13198
|
+
input: this.parseResponsesArguments(builder.arguments)
|
|
13199
|
+
}
|
|
13200
|
+
};
|
|
13201
|
+
}
|
|
13202
|
+
fnCallBuilders.clear();
|
|
13203
|
+
const hasToolCalls = event.response.output.some(
|
|
13204
|
+
(i) => i.type === "function_call"
|
|
13205
|
+
);
|
|
13206
|
+
yield {
|
|
13207
|
+
type: "done",
|
|
13208
|
+
stopReason: hasToolCalls ? "tool_use" : "end_turn"
|
|
13209
|
+
};
|
|
13210
|
+
}
|
|
13211
|
+
break;
|
|
13212
|
+
}
|
|
13213
|
+
}
|
|
13214
|
+
} finally {
|
|
13215
|
+
clearInterval(timeoutInterval);
|
|
13216
|
+
}
|
|
13217
|
+
if (timeoutController.signal.aborted) {
|
|
13218
|
+
throw new Error(`Stream timeout: No response from LLM for ${streamTimeout / 1e3}s`);
|
|
13219
|
+
}
|
|
13220
|
+
} catch (error) {
|
|
13221
|
+
throw this.handleError(error);
|
|
13222
|
+
}
|
|
13223
|
+
}
|
|
13224
|
+
// --- Responses API conversion helpers ---
|
|
13225
|
+
/**
|
|
13226
|
+
* Convert internal messages to Responses API input format.
|
|
13227
|
+
*
|
|
13228
|
+
* The Responses API uses a flat array of input items instead of the
|
|
13229
|
+
* chat completions messages array.
|
|
13230
|
+
*/
|
|
13231
|
+
convertToResponsesInput(messages, systemPrompt) {
|
|
13232
|
+
const input = [];
|
|
13233
|
+
let instructions = null;
|
|
13234
|
+
if (systemPrompt) {
|
|
13235
|
+
instructions = systemPrompt;
|
|
13236
|
+
}
|
|
13237
|
+
for (const msg of messages) {
|
|
13238
|
+
if (msg.role === "system") {
|
|
13239
|
+
instructions = (instructions ? instructions + "\n\n" : "") + this.contentToString(msg.content);
|
|
13240
|
+
} else if (msg.role === "user") {
|
|
13241
|
+
if (Array.isArray(msg.content) && msg.content.some((b) => b.type === "tool_result")) {
|
|
13242
|
+
for (const block of msg.content) {
|
|
13243
|
+
if (block.type === "tool_result") {
|
|
13244
|
+
const tr = block;
|
|
13245
|
+
input.push({
|
|
13246
|
+
type: "function_call_output",
|
|
13247
|
+
call_id: tr.tool_use_id,
|
|
13248
|
+
output: tr.content
|
|
13249
|
+
});
|
|
13250
|
+
}
|
|
13251
|
+
}
|
|
13252
|
+
} else if (Array.isArray(msg.content) && msg.content.some((b) => b.type === "image")) {
|
|
13253
|
+
const parts = [];
|
|
13254
|
+
for (const block of msg.content) {
|
|
13255
|
+
if (block.type === "text") {
|
|
13256
|
+
parts.push({ type: "input_text", text: block.text });
|
|
13257
|
+
} else if (block.type === "image") {
|
|
13258
|
+
const imgBlock = block;
|
|
13259
|
+
parts.push({
|
|
13260
|
+
type: "input_image",
|
|
13261
|
+
image_url: `data:${imgBlock.source.media_type};base64,${imgBlock.source.data}`,
|
|
13262
|
+
detail: "auto"
|
|
13263
|
+
});
|
|
13264
|
+
}
|
|
13265
|
+
}
|
|
13266
|
+
input.push({
|
|
13267
|
+
role: "user",
|
|
13268
|
+
content: parts
|
|
13269
|
+
});
|
|
13270
|
+
} else {
|
|
13271
|
+
input.push({
|
|
13272
|
+
role: "user",
|
|
13273
|
+
content: this.contentToString(msg.content)
|
|
13274
|
+
});
|
|
13275
|
+
}
|
|
13276
|
+
} else if (msg.role === "assistant") {
|
|
13277
|
+
if (typeof msg.content === "string") {
|
|
13278
|
+
input.push({ role: "assistant", content: msg.content });
|
|
13279
|
+
} else if (Array.isArray(msg.content)) {
|
|
13280
|
+
const textParts = [];
|
|
13281
|
+
for (const block of msg.content) {
|
|
13282
|
+
if (block.type === "text") {
|
|
13283
|
+
textParts.push(block.text);
|
|
13284
|
+
} else if (block.type === "tool_use") {
|
|
13285
|
+
if (textParts.length > 0) {
|
|
13286
|
+
input.push({ role: "assistant", content: textParts.join("") });
|
|
13287
|
+
textParts.length = 0;
|
|
13288
|
+
}
|
|
13289
|
+
input.push({
|
|
13290
|
+
type: "function_call",
|
|
13291
|
+
call_id: block.id,
|
|
13292
|
+
name: block.name,
|
|
13293
|
+
arguments: JSON.stringify(block.input)
|
|
13294
|
+
});
|
|
13295
|
+
}
|
|
13296
|
+
}
|
|
13297
|
+
if (textParts.length > 0) {
|
|
13298
|
+
input.push({ role: "assistant", content: textParts.join("") });
|
|
13299
|
+
}
|
|
13300
|
+
}
|
|
13301
|
+
}
|
|
13302
|
+
}
|
|
13303
|
+
return { input, instructions };
|
|
13304
|
+
}
|
|
13305
|
+
/**
|
|
13306
|
+
* Convert tool definitions to Responses API FunctionTool format
|
|
13307
|
+
*/
|
|
13308
|
+
convertToolsForResponses(tools) {
|
|
13309
|
+
return tools.map((tool) => ({
|
|
13310
|
+
type: "function",
|
|
13311
|
+
name: tool.name,
|
|
13312
|
+
description: tool.description ?? void 0,
|
|
13313
|
+
parameters: tool.input_schema ?? null,
|
|
13314
|
+
strict: false
|
|
13315
|
+
}));
|
|
13316
|
+
}
|
|
13317
|
+
/**
|
|
13318
|
+
* Parse tool call arguments with jsonrepair fallback (Responses API)
|
|
13319
|
+
*/
|
|
13320
|
+
parseResponsesArguments(args) {
|
|
13321
|
+
try {
|
|
13322
|
+
return args ? JSON.parse(args) : {};
|
|
13323
|
+
} catch {
|
|
13324
|
+
try {
|
|
13325
|
+
if (args) {
|
|
13326
|
+
const repaired = jsonrepair(args);
|
|
13327
|
+
return JSON.parse(repaired);
|
|
13328
|
+
}
|
|
13329
|
+
} catch {
|
|
13330
|
+
console.error(`[${this.name}] Cannot parse tool arguments: ${args.slice(0, 200)}`);
|
|
13331
|
+
}
|
|
13332
|
+
return {};
|
|
13333
|
+
}
|
|
13334
|
+
}
|
|
12920
13335
|
};
|
|
12921
13336
|
function createKimiProvider(config) {
|
|
12922
13337
|
const provider = new OpenAIProvider("kimi", "Kimi (Moonshot)");
|
|
@@ -12985,18 +13400,18 @@ async function refreshAccessToken(provider, refreshToken) {
|
|
|
12985
13400
|
}
|
|
12986
13401
|
function getTokenStoragePath(provider) {
|
|
12987
13402
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
12988
|
-
return
|
|
13403
|
+
return path17.join(home, ".coco", "tokens", `${provider}.json`);
|
|
12989
13404
|
}
|
|
12990
13405
|
async function saveTokens(provider, tokens) {
|
|
12991
13406
|
const filePath = getTokenStoragePath(provider);
|
|
12992
|
-
const dir =
|
|
12993
|
-
await
|
|
12994
|
-
await
|
|
13407
|
+
const dir = path17.dirname(filePath);
|
|
13408
|
+
await fs16.mkdir(dir, { recursive: true, mode: 448 });
|
|
13409
|
+
await fs16.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
12995
13410
|
}
|
|
12996
13411
|
async function loadTokens(provider) {
|
|
12997
13412
|
const filePath = getTokenStoragePath(provider);
|
|
12998
13413
|
try {
|
|
12999
|
-
const content = await
|
|
13414
|
+
const content = await fs16.readFile(filePath, "utf-8");
|
|
13000
13415
|
return JSON.parse(content);
|
|
13001
13416
|
} catch {
|
|
13002
13417
|
return null;
|
|
@@ -13005,7 +13420,7 @@ async function loadTokens(provider) {
|
|
|
13005
13420
|
async function deleteTokens(provider) {
|
|
13006
13421
|
const filePath = getTokenStoragePath(provider);
|
|
13007
13422
|
try {
|
|
13008
|
-
await
|
|
13423
|
+
await fs16.unlink(filePath);
|
|
13009
13424
|
} catch {
|
|
13010
13425
|
}
|
|
13011
13426
|
}
|
|
@@ -13043,6 +13458,124 @@ function detectWSL() {
|
|
|
13043
13458
|
}
|
|
13044
13459
|
}
|
|
13045
13460
|
var isWSL = detectWSL();
|
|
13461
|
+
var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
13462
|
+
var COPILOT_BASE_URLS = {
|
|
13463
|
+
individual: "https://api.githubcopilot.com",
|
|
13464
|
+
business: "https://api.business.githubcopilot.com",
|
|
13465
|
+
enterprise: "https://api.enterprise.githubcopilot.com"
|
|
13466
|
+
};
|
|
13467
|
+
var DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
13468
|
+
var REFRESH_BUFFER_MS = 6e4;
|
|
13469
|
+
var CopilotAuthError = class extends Error {
|
|
13470
|
+
constructor(message, permanent) {
|
|
13471
|
+
super(message);
|
|
13472
|
+
this.permanent = permanent;
|
|
13473
|
+
this.name = "CopilotAuthError";
|
|
13474
|
+
}
|
|
13475
|
+
};
|
|
13476
|
+
async function exchangeForCopilotToken(githubToken) {
|
|
13477
|
+
const response = await fetch(COPILOT_TOKEN_URL, {
|
|
13478
|
+
method: "GET",
|
|
13479
|
+
headers: {
|
|
13480
|
+
Authorization: `token ${githubToken}`,
|
|
13481
|
+
Accept: "application/json",
|
|
13482
|
+
"User-Agent": "Corbat-Coco/1.0"
|
|
13483
|
+
}
|
|
13484
|
+
});
|
|
13485
|
+
if (!response.ok) {
|
|
13486
|
+
const error = await response.text();
|
|
13487
|
+
if (response.status === 401) {
|
|
13488
|
+
throw new CopilotAuthError(
|
|
13489
|
+
"GitHub token is invalid or expired. Please re-authenticate with /provider copilot.",
|
|
13490
|
+
true
|
|
13491
|
+
);
|
|
13492
|
+
}
|
|
13493
|
+
if (response.status === 403) {
|
|
13494
|
+
throw new CopilotAuthError(
|
|
13495
|
+
"GitHub Copilot is not enabled for this account.\n Please ensure you have an active Copilot subscription:\n https://github.com/settings/copilot",
|
|
13496
|
+
true
|
|
13497
|
+
);
|
|
13498
|
+
}
|
|
13499
|
+
throw new Error(`Copilot token exchange failed: ${response.status} - ${error}`);
|
|
13500
|
+
}
|
|
13501
|
+
return await response.json();
|
|
13502
|
+
}
|
|
13503
|
+
function getCopilotBaseUrl(accountType) {
|
|
13504
|
+
if (accountType && accountType in COPILOT_BASE_URLS) {
|
|
13505
|
+
return COPILOT_BASE_URLS[accountType];
|
|
13506
|
+
}
|
|
13507
|
+
return DEFAULT_COPILOT_BASE_URL;
|
|
13508
|
+
}
|
|
13509
|
+
function getCopilotCredentialsPath() {
|
|
13510
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
13511
|
+
return path17.join(home, ".coco", "tokens", "copilot.json");
|
|
13512
|
+
}
|
|
13513
|
+
async function saveCopilotCredentials(creds) {
|
|
13514
|
+
const filePath = getCopilotCredentialsPath();
|
|
13515
|
+
const dir = path17.dirname(filePath);
|
|
13516
|
+
await fs16.mkdir(dir, { recursive: true, mode: 448 });
|
|
13517
|
+
await fs16.writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
13518
|
+
}
|
|
13519
|
+
var CopilotCredentialsSchema = z.object({
|
|
13520
|
+
githubToken: z.string().min(1),
|
|
13521
|
+
copilotToken: z.string().optional(),
|
|
13522
|
+
copilotTokenExpiresAt: z.number().optional(),
|
|
13523
|
+
accountType: z.string().optional()
|
|
13524
|
+
});
|
|
13525
|
+
async function loadCopilotCredentials() {
|
|
13526
|
+
try {
|
|
13527
|
+
const content = await fs16.readFile(getCopilotCredentialsPath(), "utf-8");
|
|
13528
|
+
const parsed = CopilotCredentialsSchema.safeParse(JSON.parse(content));
|
|
13529
|
+
return parsed.success ? parsed.data : null;
|
|
13530
|
+
} catch {
|
|
13531
|
+
return null;
|
|
13532
|
+
}
|
|
13533
|
+
}
|
|
13534
|
+
async function deleteCopilotCredentials() {
|
|
13535
|
+
try {
|
|
13536
|
+
await fs16.unlink(getCopilotCredentialsPath());
|
|
13537
|
+
} catch {
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
function isCopilotTokenExpired(creds) {
|
|
13541
|
+
if (!creds.copilotToken || !creds.copilotTokenExpiresAt) return true;
|
|
13542
|
+
return Date.now() >= creds.copilotTokenExpiresAt - REFRESH_BUFFER_MS;
|
|
13543
|
+
}
|
|
13544
|
+
async function getValidCopilotToken() {
|
|
13545
|
+
const creds = await loadCopilotCredentials();
|
|
13546
|
+
if (!creds) return null;
|
|
13547
|
+
const envToken = process.env["GITHUB_TOKEN"] || process.env["GH_TOKEN"];
|
|
13548
|
+
const githubToken = envToken || creds.githubToken;
|
|
13549
|
+
if (!isCopilotTokenExpired(creds) && creds.copilotToken) {
|
|
13550
|
+
return {
|
|
13551
|
+
token: creds.copilotToken,
|
|
13552
|
+
baseUrl: getCopilotBaseUrl(creds.accountType),
|
|
13553
|
+
isNew: false
|
|
13554
|
+
};
|
|
13555
|
+
}
|
|
13556
|
+
try {
|
|
13557
|
+
const copilotToken = await exchangeForCopilotToken(githubToken);
|
|
13558
|
+
const updatedCreds = {
|
|
13559
|
+
...creds,
|
|
13560
|
+
githubToken: creds.githubToken,
|
|
13561
|
+
copilotToken: copilotToken.token,
|
|
13562
|
+
copilotTokenExpiresAt: copilotToken.expires_at * 1e3,
|
|
13563
|
+
accountType: copilotToken.annotations?.copilot_plan ?? creds.accountType
|
|
13564
|
+
};
|
|
13565
|
+
await saveCopilotCredentials(updatedCreds);
|
|
13566
|
+
return {
|
|
13567
|
+
token: copilotToken.token,
|
|
13568
|
+
baseUrl: getCopilotBaseUrl(updatedCreds.accountType),
|
|
13569
|
+
isNew: true
|
|
13570
|
+
};
|
|
13571
|
+
} catch (error) {
|
|
13572
|
+
if (error instanceof CopilotAuthError && error.permanent) {
|
|
13573
|
+
await deleteCopilotCredentials();
|
|
13574
|
+
return null;
|
|
13575
|
+
}
|
|
13576
|
+
throw error;
|
|
13577
|
+
}
|
|
13578
|
+
}
|
|
13046
13579
|
|
|
13047
13580
|
// src/auth/flow.ts
|
|
13048
13581
|
promisify(execFile);
|
|
@@ -13355,22 +13888,160 @@ var CodexProvider = class {
|
|
|
13355
13888
|
yield* this.stream(messages, options);
|
|
13356
13889
|
}
|
|
13357
13890
|
};
|
|
13358
|
-
var DEFAULT_MODEL4 = "gemini-3-flash-preview";
|
|
13359
13891
|
var CONTEXT_WINDOWS4 = {
|
|
13360
|
-
//
|
|
13892
|
+
// Claude models
|
|
13893
|
+
"claude-sonnet-4.6": 2e5,
|
|
13894
|
+
"claude-opus-4.6": 2e5,
|
|
13895
|
+
"claude-sonnet-4.5": 2e5,
|
|
13896
|
+
"claude-opus-4.5": 2e5,
|
|
13897
|
+
"claude-haiku-4.5": 2e5,
|
|
13898
|
+
// OpenAI models — chat/completions
|
|
13899
|
+
"gpt-4.1": 1048576,
|
|
13900
|
+
// OpenAI models — /responses API (Codex/GPT-5+)
|
|
13901
|
+
"gpt-5.3-codex": 4e5,
|
|
13902
|
+
"gpt-5.2-codex": 4e5,
|
|
13903
|
+
"gpt-5.1-codex-max": 4e5,
|
|
13904
|
+
"gpt-5.2": 4e5,
|
|
13905
|
+
"gpt-5.1": 4e5,
|
|
13906
|
+
// Google models
|
|
13907
|
+
"gemini-3.1-pro-preview": 1e6,
|
|
13908
|
+
"gemini-3-flash-preview": 1e6,
|
|
13909
|
+
"gemini-2.5-pro": 1048576
|
|
13910
|
+
};
|
|
13911
|
+
var DEFAULT_MODEL4 = "claude-sonnet-4.6";
|
|
13912
|
+
var COPILOT_HEADERS = {
|
|
13913
|
+
"Copilot-Integration-Id": "vscode-chat",
|
|
13914
|
+
"Editor-Version": "vscode/1.99.0",
|
|
13915
|
+
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
|
13916
|
+
"X-GitHub-Api-Version": "2025-04-01"
|
|
13917
|
+
};
|
|
13918
|
+
var CopilotProvider = class extends OpenAIProvider {
|
|
13919
|
+
baseUrl = "https://api.githubcopilot.com";
|
|
13920
|
+
currentToken = null;
|
|
13921
|
+
/** In-flight refresh promise to prevent concurrent token exchanges */
|
|
13922
|
+
refreshPromise = null;
|
|
13923
|
+
constructor() {
|
|
13924
|
+
super("copilot", "GitHub Copilot");
|
|
13925
|
+
}
|
|
13926
|
+
/**
|
|
13927
|
+
* Initialize the provider with Copilot credentials.
|
|
13928
|
+
*
|
|
13929
|
+
* Gets a valid Copilot API token (from cache or by refreshing),
|
|
13930
|
+
* then creates an OpenAI client configured for the Copilot endpoint.
|
|
13931
|
+
*/
|
|
13932
|
+
async initialize(config) {
|
|
13933
|
+
this.config = {
|
|
13934
|
+
...config,
|
|
13935
|
+
model: config.model ?? DEFAULT_MODEL4
|
|
13936
|
+
};
|
|
13937
|
+
const tokenResult = await getValidCopilotToken();
|
|
13938
|
+
if (tokenResult) {
|
|
13939
|
+
this.currentToken = tokenResult.token;
|
|
13940
|
+
this.baseUrl = tokenResult.baseUrl;
|
|
13941
|
+
} else if (config.apiKey) {
|
|
13942
|
+
this.currentToken = config.apiKey;
|
|
13943
|
+
}
|
|
13944
|
+
if (!this.currentToken) {
|
|
13945
|
+
throw new ProviderError(
|
|
13946
|
+
"No Copilot token found. Please authenticate with: coco --provider copilot",
|
|
13947
|
+
{ provider: this.id }
|
|
13948
|
+
);
|
|
13949
|
+
}
|
|
13950
|
+
this.createCopilotClient();
|
|
13951
|
+
}
|
|
13952
|
+
/**
|
|
13953
|
+
* Create the OpenAI client configured for Copilot API
|
|
13954
|
+
*/
|
|
13955
|
+
createCopilotClient() {
|
|
13956
|
+
this.client = new OpenAI({
|
|
13957
|
+
apiKey: this.currentToken,
|
|
13958
|
+
baseURL: this.config.baseUrl ?? this.baseUrl,
|
|
13959
|
+
timeout: this.config.timeout ?? 12e4,
|
|
13960
|
+
defaultHeaders: COPILOT_HEADERS
|
|
13961
|
+
});
|
|
13962
|
+
}
|
|
13963
|
+
/**
|
|
13964
|
+
* Refresh the Copilot token if expired.
|
|
13965
|
+
*
|
|
13966
|
+
* Uses a mutex so concurrent callers share a single in-flight token
|
|
13967
|
+
* exchange. The slot is cleared inside the IIFE's finally block,
|
|
13968
|
+
* which runs after all awaiting callers have resumed.
|
|
13969
|
+
*/
|
|
13970
|
+
async refreshTokenIfNeeded() {
|
|
13971
|
+
if (!this.refreshPromise) {
|
|
13972
|
+
this.refreshPromise = (async () => {
|
|
13973
|
+
try {
|
|
13974
|
+
const tokenResult = await getValidCopilotToken();
|
|
13975
|
+
if (tokenResult && tokenResult.isNew) {
|
|
13976
|
+
this.currentToken = tokenResult.token;
|
|
13977
|
+
this.baseUrl = tokenResult.baseUrl;
|
|
13978
|
+
this.createCopilotClient();
|
|
13979
|
+
}
|
|
13980
|
+
} finally {
|
|
13981
|
+
this.refreshPromise = null;
|
|
13982
|
+
}
|
|
13983
|
+
})();
|
|
13984
|
+
}
|
|
13985
|
+
await this.refreshPromise;
|
|
13986
|
+
}
|
|
13987
|
+
// --- Override public methods to add token refresh ---
|
|
13988
|
+
async chat(messages, options) {
|
|
13989
|
+
await this.refreshTokenIfNeeded();
|
|
13990
|
+
return super.chat(messages, options);
|
|
13991
|
+
}
|
|
13992
|
+
async chatWithTools(messages, options) {
|
|
13993
|
+
await this.refreshTokenIfNeeded();
|
|
13994
|
+
return super.chatWithTools(messages, options);
|
|
13995
|
+
}
|
|
13996
|
+
async *stream(messages, options) {
|
|
13997
|
+
await this.refreshTokenIfNeeded();
|
|
13998
|
+
yield* super.stream(messages, options);
|
|
13999
|
+
}
|
|
14000
|
+
async *streamWithTools(messages, options) {
|
|
14001
|
+
await this.refreshTokenIfNeeded();
|
|
14002
|
+
yield* super.streamWithTools(messages, options);
|
|
14003
|
+
}
|
|
14004
|
+
// --- Override metadata methods ---
|
|
14005
|
+
/**
|
|
14006
|
+
* Count tokens (approximate — Copilot models vary in tokenizer)
|
|
14007
|
+
*/
|
|
14008
|
+
countTokens(text) {
|
|
14009
|
+
if (!text) return 0;
|
|
14010
|
+
return Math.ceil(text.length / 3.5);
|
|
14011
|
+
}
|
|
14012
|
+
/**
|
|
14013
|
+
* Get context window for the current model
|
|
14014
|
+
*/
|
|
14015
|
+
getContextWindow() {
|
|
14016
|
+
const model = this.config.model ?? DEFAULT_MODEL4;
|
|
14017
|
+
return CONTEXT_WINDOWS4[model] ?? 128e3;
|
|
14018
|
+
}
|
|
14019
|
+
/**
|
|
14020
|
+
* Check if Copilot credentials are available
|
|
14021
|
+
*/
|
|
14022
|
+
async isAvailable() {
|
|
14023
|
+
try {
|
|
14024
|
+
const tokenResult = await getValidCopilotToken();
|
|
14025
|
+
return tokenResult !== null;
|
|
14026
|
+
} catch {
|
|
14027
|
+
return false;
|
|
14028
|
+
}
|
|
14029
|
+
}
|
|
14030
|
+
};
|
|
14031
|
+
var DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
|
|
14032
|
+
var CONTEXT_WINDOWS5 = {
|
|
14033
|
+
// Gemini 3.1 series (latest)
|
|
14034
|
+
"gemini-3.1-pro-preview": 1e6,
|
|
14035
|
+
"gemini-3.1-flash-lite-preview": 1e6,
|
|
14036
|
+
// Gemini 3 series
|
|
13361
14037
|
"gemini-3-flash-preview": 1e6,
|
|
13362
|
-
"gemini-3-pro-preview": 1e6,
|
|
13363
14038
|
// Gemini 2.5 series (production stable)
|
|
13364
|
-
"gemini-2.5-pro-preview-05-06": 1048576,
|
|
13365
|
-
"gemini-2.5-flash-preview-05-20": 1048576,
|
|
13366
14039
|
"gemini-2.5-pro": 1048576,
|
|
13367
14040
|
"gemini-2.5-flash": 1048576,
|
|
13368
|
-
|
|
13369
|
-
"gemini-2.0-flash": 1048576,
|
|
14041
|
+
"gemini-2.5-flash-lite": 1048576,
|
|
13370
14042
|
// Legacy
|
|
13371
14043
|
"gemini-1.5-flash": 1e6,
|
|
13372
|
-
"gemini-1.5-pro": 2e6
|
|
13373
|
-
"gemini-1.0-pro": 32e3
|
|
14044
|
+
"gemini-1.5-pro": 2e6
|
|
13374
14045
|
};
|
|
13375
14046
|
var GeminiProvider = class {
|
|
13376
14047
|
id = "gemini";
|
|
@@ -13429,7 +14100,7 @@ var GeminiProvider = class {
|
|
|
13429
14100
|
await this.refreshADCIfNeeded();
|
|
13430
14101
|
try {
|
|
13431
14102
|
const model = this.client.getGenerativeModel({
|
|
13432
|
-
model: options?.model ?? this.config.model ??
|
|
14103
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13433
14104
|
generationConfig: {
|
|
13434
14105
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13435
14106
|
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
@@ -13458,7 +14129,7 @@ var GeminiProvider = class {
|
|
|
13458
14129
|
}
|
|
13459
14130
|
];
|
|
13460
14131
|
const model = this.client.getGenerativeModel({
|
|
13461
|
-
model: options?.model ?? this.config.model ??
|
|
14132
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13462
14133
|
generationConfig: {
|
|
13463
14134
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13464
14135
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13487,7 +14158,7 @@ var GeminiProvider = class {
|
|
|
13487
14158
|
await this.refreshADCIfNeeded();
|
|
13488
14159
|
try {
|
|
13489
14160
|
const model = this.client.getGenerativeModel({
|
|
13490
|
-
model: options?.model ?? this.config.model ??
|
|
14161
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13491
14162
|
generationConfig: {
|
|
13492
14163
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13493
14164
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13526,7 +14197,7 @@ var GeminiProvider = class {
|
|
|
13526
14197
|
}
|
|
13527
14198
|
];
|
|
13528
14199
|
const model = this.client.getGenerativeModel({
|
|
13529
|
-
model: options?.model ?? this.config.model ??
|
|
14200
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13530
14201
|
generationConfig: {
|
|
13531
14202
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13532
14203
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13610,8 +14281,8 @@ var GeminiProvider = class {
|
|
|
13610
14281
|
* Get context window size
|
|
13611
14282
|
*/
|
|
13612
14283
|
getContextWindow() {
|
|
13613
|
-
const model = this.config.model ??
|
|
13614
|
-
return
|
|
14284
|
+
const model = this.config.model ?? DEFAULT_MODEL5;
|
|
14285
|
+
return CONTEXT_WINDOWS5[model] ?? 1e6;
|
|
13615
14286
|
}
|
|
13616
14287
|
/**
|
|
13617
14288
|
* Check if provider is available
|
|
@@ -13619,7 +14290,7 @@ var GeminiProvider = class {
|
|
|
13619
14290
|
async isAvailable() {
|
|
13620
14291
|
if (!this.client) return false;
|
|
13621
14292
|
try {
|
|
13622
|
-
const modelName = this.config.model ??
|
|
14293
|
+
const modelName = this.config.model ?? DEFAULT_MODEL5;
|
|
13623
14294
|
const model = this.client.getGenerativeModel({ model: modelName });
|
|
13624
14295
|
await model.generateContent("hi");
|
|
13625
14296
|
return true;
|
|
@@ -13751,7 +14422,7 @@ var GeminiProvider = class {
|
|
|
13751
14422
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
13752
14423
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
13753
14424
|
},
|
|
13754
|
-
model: this.config.model ??
|
|
14425
|
+
model: this.config.model ?? DEFAULT_MODEL5
|
|
13755
14426
|
};
|
|
13756
14427
|
}
|
|
13757
14428
|
/**
|
|
@@ -13786,7 +14457,7 @@ var GeminiProvider = class {
|
|
|
13786
14457
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
13787
14458
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
13788
14459
|
},
|
|
13789
|
-
model: this.config.model ??
|
|
14460
|
+
model: this.config.model ?? DEFAULT_MODEL5,
|
|
13790
14461
|
toolCalls
|
|
13791
14462
|
};
|
|
13792
14463
|
}
|
|
@@ -13820,8 +14491,6 @@ var GeminiProvider = class {
|
|
|
13820
14491
|
});
|
|
13821
14492
|
}
|
|
13822
14493
|
};
|
|
13823
|
-
|
|
13824
|
-
// src/providers/index.ts
|
|
13825
14494
|
init_env();
|
|
13826
14495
|
async function createProvider(type, config = {}) {
|
|
13827
14496
|
let provider;
|
|
@@ -13843,6 +14512,9 @@ async function createProvider(type, config = {}) {
|
|
|
13843
14512
|
case "codex":
|
|
13844
14513
|
provider = new CodexProvider();
|
|
13845
14514
|
break;
|
|
14515
|
+
case "copilot":
|
|
14516
|
+
provider = new CopilotProvider();
|
|
14517
|
+
break;
|
|
13846
14518
|
case "gemini":
|
|
13847
14519
|
provider = new GeminiProvider();
|
|
13848
14520
|
break;
|
|
@@ -14013,9 +14685,9 @@ function createInitialState(config) {
|
|
|
14013
14685
|
}
|
|
14014
14686
|
async function loadExistingState(projectPath) {
|
|
14015
14687
|
try {
|
|
14016
|
-
const
|
|
14688
|
+
const fs38 = await import('fs/promises');
|
|
14017
14689
|
const statePath = `${projectPath}/.coco/state/project.json`;
|
|
14018
|
-
const content = await
|
|
14690
|
+
const content = await fs38.readFile(statePath, "utf-8");
|
|
14019
14691
|
const data = JSON.parse(content);
|
|
14020
14692
|
data.createdAt = new Date(data.createdAt);
|
|
14021
14693
|
data.updatedAt = new Date(data.updatedAt);
|
|
@@ -14025,13 +14697,13 @@ async function loadExistingState(projectPath) {
|
|
|
14025
14697
|
}
|
|
14026
14698
|
}
|
|
14027
14699
|
async function saveState(state) {
|
|
14028
|
-
const
|
|
14700
|
+
const fs38 = await import('fs/promises');
|
|
14029
14701
|
const statePath = `${state.path}/.coco/state`;
|
|
14030
|
-
await
|
|
14702
|
+
await fs38.mkdir(statePath, { recursive: true });
|
|
14031
14703
|
const filePath = `${statePath}/project.json`;
|
|
14032
14704
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
14033
|
-
await
|
|
14034
|
-
await
|
|
14705
|
+
await fs38.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
|
|
14706
|
+
await fs38.rename(tmpPath, filePath);
|
|
14035
14707
|
}
|
|
14036
14708
|
function getPhaseExecutor(phase) {
|
|
14037
14709
|
switch (phase) {
|
|
@@ -14090,20 +14762,20 @@ async function createPhaseContext(config, state) {
|
|
|
14090
14762
|
};
|
|
14091
14763
|
const tools = {
|
|
14092
14764
|
file: {
|
|
14093
|
-
async read(
|
|
14094
|
-
const
|
|
14095
|
-
return
|
|
14765
|
+
async read(path40) {
|
|
14766
|
+
const fs38 = await import('fs/promises');
|
|
14767
|
+
return fs38.readFile(path40, "utf-8");
|
|
14096
14768
|
},
|
|
14097
|
-
async write(
|
|
14098
|
-
const
|
|
14769
|
+
async write(path40, content) {
|
|
14770
|
+
const fs38 = await import('fs/promises');
|
|
14099
14771
|
const nodePath = await import('path');
|
|
14100
|
-
await
|
|
14101
|
-
await
|
|
14772
|
+
await fs38.mkdir(nodePath.dirname(path40), { recursive: true });
|
|
14773
|
+
await fs38.writeFile(path40, content, "utf-8");
|
|
14102
14774
|
},
|
|
14103
|
-
async exists(
|
|
14104
|
-
const
|
|
14775
|
+
async exists(path40) {
|
|
14776
|
+
const fs38 = await import('fs/promises');
|
|
14105
14777
|
try {
|
|
14106
|
-
await
|
|
14778
|
+
await fs38.access(path40);
|
|
14107
14779
|
return true;
|
|
14108
14780
|
} catch {
|
|
14109
14781
|
return false;
|
|
@@ -14252,9 +14924,9 @@ async function createSnapshot(state) {
|
|
|
14252
14924
|
var MAX_CHECKPOINT_VERSIONS = 5;
|
|
14253
14925
|
async function getCheckpointFiles(state, phase) {
|
|
14254
14926
|
try {
|
|
14255
|
-
const
|
|
14927
|
+
const fs38 = await import('fs/promises');
|
|
14256
14928
|
const checkpointDir = `${state.path}/.coco/checkpoints`;
|
|
14257
|
-
const files = await
|
|
14929
|
+
const files = await fs38.readdir(checkpointDir);
|
|
14258
14930
|
const phaseFiles = files.filter((f) => f.startsWith(`snapshot-pre-${phase}-`) && f.endsWith(".json")).sort((a, b) => {
|
|
14259
14931
|
const tsA = parseInt(a.split("-").pop()?.replace(".json", "") ?? "0", 10);
|
|
14260
14932
|
const tsB = parseInt(b.split("-").pop()?.replace(".json", "") ?? "0", 10);
|
|
@@ -14267,11 +14939,11 @@ async function getCheckpointFiles(state, phase) {
|
|
|
14267
14939
|
}
|
|
14268
14940
|
async function cleanupOldCheckpoints(state, phase) {
|
|
14269
14941
|
try {
|
|
14270
|
-
const
|
|
14942
|
+
const fs38 = await import('fs/promises');
|
|
14271
14943
|
const files = await getCheckpointFiles(state, phase);
|
|
14272
14944
|
if (files.length > MAX_CHECKPOINT_VERSIONS) {
|
|
14273
14945
|
const filesToDelete = files.slice(MAX_CHECKPOINT_VERSIONS);
|
|
14274
|
-
await Promise.all(filesToDelete.map((f) =>
|
|
14946
|
+
await Promise.all(filesToDelete.map((f) => fs38.unlink(f).catch(() => {
|
|
14275
14947
|
})));
|
|
14276
14948
|
}
|
|
14277
14949
|
} catch {
|
|
@@ -14279,13 +14951,13 @@ async function cleanupOldCheckpoints(state, phase) {
|
|
|
14279
14951
|
}
|
|
14280
14952
|
async function saveSnapshot(state, snapshotId) {
|
|
14281
14953
|
try {
|
|
14282
|
-
const
|
|
14954
|
+
const fs38 = await import('fs/promises');
|
|
14283
14955
|
const snapshotPath = `${state.path}/.coco/checkpoints/snapshot-${snapshotId}.json`;
|
|
14284
14956
|
const snapshotDir = `${state.path}/.coco/checkpoints`;
|
|
14285
|
-
await
|
|
14957
|
+
await fs38.mkdir(snapshotDir, { recursive: true });
|
|
14286
14958
|
const createdAt = state.createdAt instanceof Date ? state.createdAt.toISOString() : String(state.createdAt);
|
|
14287
14959
|
const updatedAt = state.updatedAt instanceof Date ? state.updatedAt.toISOString() : String(state.updatedAt);
|
|
14288
|
-
await
|
|
14960
|
+
await fs38.writeFile(
|
|
14289
14961
|
snapshotPath,
|
|
14290
14962
|
JSON.stringify(
|
|
14291
14963
|
{
|
|
@@ -14597,7 +15269,7 @@ async function loadConfig(configPath) {
|
|
|
14597
15269
|
async function loadConfigFile(configPath, options = {}) {
|
|
14598
15270
|
const { strict = true } = options;
|
|
14599
15271
|
try {
|
|
14600
|
-
const content = await
|
|
15272
|
+
const content = await fs16__default.readFile(configPath, "utf-8");
|
|
14601
15273
|
const parsed = JSON5.parse(content);
|
|
14602
15274
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
14603
15275
|
if (!strict) {
|
|
@@ -14653,7 +15325,7 @@ function deepMergeConfig(base, override) {
|
|
|
14653
15325
|
};
|
|
14654
15326
|
}
|
|
14655
15327
|
function getProjectConfigPath2() {
|
|
14656
|
-
return
|
|
15328
|
+
return path17__default.join(process.cwd(), ".coco", "config.json");
|
|
14657
15329
|
}
|
|
14658
15330
|
async function saveConfig(config, configPath, global = false) {
|
|
14659
15331
|
const result = CocoConfigSchema.safeParse(config);
|
|
@@ -14668,10 +15340,10 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
14668
15340
|
});
|
|
14669
15341
|
}
|
|
14670
15342
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath2());
|
|
14671
|
-
const dir =
|
|
14672
|
-
await
|
|
15343
|
+
const dir = path17__default.dirname(resolvedPath);
|
|
15344
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
14673
15345
|
const content = JSON.stringify(result.data, null, 2);
|
|
14674
|
-
await
|
|
15346
|
+
await fs16__default.writeFile(resolvedPath, content, "utf-8");
|
|
14675
15347
|
}
|
|
14676
15348
|
function createDefaultConfig(projectName, language = "typescript") {
|
|
14677
15349
|
return createDefaultConfigObject(projectName, language);
|
|
@@ -14679,7 +15351,7 @@ function createDefaultConfig(projectName, language = "typescript") {
|
|
|
14679
15351
|
async function configExists(configPath, scope = "any") {
|
|
14680
15352
|
if (configPath) {
|
|
14681
15353
|
try {
|
|
14682
|
-
await
|
|
15354
|
+
await fs16__default.access(configPath);
|
|
14683
15355
|
return true;
|
|
14684
15356
|
} catch {
|
|
14685
15357
|
return false;
|
|
@@ -14687,7 +15359,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
14687
15359
|
}
|
|
14688
15360
|
if (scope === "project" || scope === "any") {
|
|
14689
15361
|
try {
|
|
14690
|
-
await
|
|
15362
|
+
await fs16__default.access(getProjectConfigPath2());
|
|
14691
15363
|
return true;
|
|
14692
15364
|
} catch {
|
|
14693
15365
|
if (scope === "project") return false;
|
|
@@ -14695,7 +15367,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
14695
15367
|
}
|
|
14696
15368
|
if (scope === "global" || scope === "any") {
|
|
14697
15369
|
try {
|
|
14698
|
-
await
|
|
15370
|
+
await fs16__default.access(CONFIG_PATHS.config);
|
|
14699
15371
|
return true;
|
|
14700
15372
|
} catch {
|
|
14701
15373
|
return false;
|
|
@@ -14737,15 +15409,15 @@ function levenshtein(a, b) {
|
|
|
14737
15409
|
var MAX_DIR_ENTRIES = 200;
|
|
14738
15410
|
var MAX_SUGGESTIONS = 5;
|
|
14739
15411
|
async function suggestSimilarFiles(missingPath, options) {
|
|
14740
|
-
const absPath =
|
|
14741
|
-
const dir =
|
|
14742
|
-
const target =
|
|
15412
|
+
const absPath = path17__default.resolve(missingPath);
|
|
15413
|
+
const dir = path17__default.dirname(absPath);
|
|
15414
|
+
const target = path17__default.basename(absPath);
|
|
14743
15415
|
const maxResults = MAX_SUGGESTIONS;
|
|
14744
15416
|
try {
|
|
14745
|
-
const entries = await
|
|
15417
|
+
const entries = await fs16__default.readdir(dir);
|
|
14746
15418
|
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
14747
15419
|
const scored = limited.map((name) => ({
|
|
14748
|
-
path:
|
|
15420
|
+
path: path17__default.join(dir, name),
|
|
14749
15421
|
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
14750
15422
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
14751
15423
|
return scored.slice(0, maxResults);
|
|
@@ -14756,15 +15428,15 @@ async function suggestSimilarFiles(missingPath, options) {
|
|
|
14756
15428
|
async function suggestSimilarPaths(missingPath, options) {
|
|
14757
15429
|
const fileSuggestions = await suggestSimilarFiles(missingPath);
|
|
14758
15430
|
if (fileSuggestions.length > 0) return fileSuggestions;
|
|
14759
|
-
const absPath =
|
|
14760
|
-
const grandparent =
|
|
14761
|
-
const parentBasename =
|
|
15431
|
+
const absPath = path17__default.resolve(missingPath);
|
|
15432
|
+
const grandparent = path17__default.dirname(path17__default.dirname(absPath));
|
|
15433
|
+
const parentBasename = path17__default.basename(path17__default.dirname(absPath));
|
|
14762
15434
|
const maxResults = MAX_SUGGESTIONS;
|
|
14763
15435
|
try {
|
|
14764
|
-
const entries = await
|
|
15436
|
+
const entries = await fs16__default.readdir(grandparent, { withFileTypes: true });
|
|
14765
15437
|
const dirs = entries.filter((e) => e.isDirectory()).slice(0, MAX_DIR_ENTRIES);
|
|
14766
15438
|
const scored = dirs.map((d) => ({
|
|
14767
|
-
path:
|
|
15439
|
+
path: path17__default.join(grandparent, d.name),
|
|
14768
15440
|
distance: levenshtein(parentBasename.toLowerCase(), d.name.toLowerCase())
|
|
14769
15441
|
})).filter((s) => s.distance <= Math.max(parentBasename.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
14770
15442
|
return scored.slice(0, maxResults);
|
|
@@ -14776,7 +15448,7 @@ function formatSuggestions(suggestions, baseDir) {
|
|
|
14776
15448
|
if (suggestions.length === 0) return "";
|
|
14777
15449
|
const base = baseDir ?? process.cwd();
|
|
14778
15450
|
const lines = suggestions.map((s) => {
|
|
14779
|
-
const rel =
|
|
15451
|
+
const rel = path17__default.relative(base, s.path);
|
|
14780
15452
|
return ` - ${rel}`;
|
|
14781
15453
|
});
|
|
14782
15454
|
return `
|
|
@@ -14809,7 +15481,7 @@ function hasNullByte(str) {
|
|
|
14809
15481
|
}
|
|
14810
15482
|
function normalizePath(filePath) {
|
|
14811
15483
|
let normalized = filePath.replace(/\0/g, "");
|
|
14812
|
-
normalized =
|
|
15484
|
+
normalized = path17__default.normalize(normalized);
|
|
14813
15485
|
return normalized;
|
|
14814
15486
|
}
|
|
14815
15487
|
function isPathAllowed(filePath, operation) {
|
|
@@ -14817,31 +15489,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
14817
15489
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
14818
15490
|
}
|
|
14819
15491
|
const normalized = normalizePath(filePath);
|
|
14820
|
-
const absolute =
|
|
15492
|
+
const absolute = path17__default.resolve(normalized);
|
|
14821
15493
|
const cwd = process.cwd();
|
|
14822
15494
|
for (const blocked of BLOCKED_PATHS) {
|
|
14823
|
-
const normalizedBlocked =
|
|
14824
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
15495
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
15496
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
14825
15497
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
14826
15498
|
}
|
|
14827
15499
|
}
|
|
14828
15500
|
const home = process.env.HOME;
|
|
14829
15501
|
if (home) {
|
|
14830
|
-
const normalizedHome =
|
|
14831
|
-
const normalizedCwd =
|
|
15502
|
+
const normalizedHome = path17__default.normalize(home);
|
|
15503
|
+
const normalizedCwd = path17__default.normalize(cwd);
|
|
14832
15504
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
14833
15505
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
14834
15506
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
14835
|
-
const basename5 =
|
|
15507
|
+
const basename5 = path17__default.basename(absolute);
|
|
14836
15508
|
if (!allowedHomeReads.includes(basename5)) {
|
|
14837
|
-
const targetDir =
|
|
15509
|
+
const targetDir = path17__default.dirname(absolute);
|
|
14838
15510
|
return {
|
|
14839
15511
|
allowed: false,
|
|
14840
15512
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
14841
15513
|
};
|
|
14842
15514
|
}
|
|
14843
15515
|
} else {
|
|
14844
|
-
const targetDir =
|
|
15516
|
+
const targetDir = path17__default.dirname(absolute);
|
|
14845
15517
|
return {
|
|
14846
15518
|
allowed: false,
|
|
14847
15519
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -14850,7 +15522,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
14850
15522
|
}
|
|
14851
15523
|
}
|
|
14852
15524
|
if (operation === "write" || operation === "delete") {
|
|
14853
|
-
const basename5 =
|
|
15525
|
+
const basename5 = path17__default.basename(absolute);
|
|
14854
15526
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
14855
15527
|
if (pattern.test(basename5)) {
|
|
14856
15528
|
return {
|
|
@@ -14873,17 +15545,17 @@ function isENOENT(error) {
|
|
|
14873
15545
|
return error.code === "ENOENT";
|
|
14874
15546
|
}
|
|
14875
15547
|
async function enrichENOENT(filePath, operation) {
|
|
14876
|
-
const absPath =
|
|
15548
|
+
const absPath = path17__default.resolve(filePath);
|
|
14877
15549
|
const suggestions = await suggestSimilarFiles(absPath);
|
|
14878
|
-
const hint = formatSuggestions(suggestions,
|
|
15550
|
+
const hint = formatSuggestions(suggestions, path17__default.dirname(absPath));
|
|
14879
15551
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
14880
15552
|
return `File not found: ${filePath}${hint}
|
|
14881
15553
|
${action}`;
|
|
14882
15554
|
}
|
|
14883
15555
|
async function enrichDirENOENT(dirPath) {
|
|
14884
|
-
const absPath =
|
|
15556
|
+
const absPath = path17__default.resolve(dirPath);
|
|
14885
15557
|
const suggestions = await suggestSimilarPaths(absPath);
|
|
14886
|
-
const hint = formatSuggestions(suggestions,
|
|
15558
|
+
const hint = formatSuggestions(suggestions, path17__default.dirname(absPath));
|
|
14887
15559
|
return `Directory not found: ${dirPath}${hint}
|
|
14888
15560
|
Use list_dir or glob to find the correct path.`;
|
|
14889
15561
|
}
|
|
@@ -14904,13 +15576,13 @@ Examples:
|
|
|
14904
15576
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
14905
15577
|
validatePath(filePath, "read");
|
|
14906
15578
|
try {
|
|
14907
|
-
const absolutePath =
|
|
14908
|
-
const stats = await
|
|
15579
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15580
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
14909
15581
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
14910
15582
|
let truncated = false;
|
|
14911
15583
|
let content;
|
|
14912
15584
|
if (stats.size > maxBytes) {
|
|
14913
|
-
const handle = await
|
|
15585
|
+
const handle = await fs16__default.open(absolutePath, "r");
|
|
14914
15586
|
try {
|
|
14915
15587
|
const buffer = Buffer.alloc(maxBytes);
|
|
14916
15588
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -14920,7 +15592,7 @@ Examples:
|
|
|
14920
15592
|
await handle.close();
|
|
14921
15593
|
}
|
|
14922
15594
|
} else {
|
|
14923
|
-
content = await
|
|
15595
|
+
content = await fs16__default.readFile(absolutePath, encoding);
|
|
14924
15596
|
}
|
|
14925
15597
|
return {
|
|
14926
15598
|
content,
|
|
@@ -14963,10 +15635,10 @@ Examples:
|
|
|
14963
15635
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
14964
15636
|
validatePath(filePath, "write");
|
|
14965
15637
|
try {
|
|
14966
|
-
const absolutePath =
|
|
15638
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
14967
15639
|
let wouldCreate = false;
|
|
14968
15640
|
try {
|
|
14969
|
-
await
|
|
15641
|
+
await fs16__default.access(absolutePath);
|
|
14970
15642
|
} catch {
|
|
14971
15643
|
wouldCreate = true;
|
|
14972
15644
|
}
|
|
@@ -14979,10 +15651,10 @@ Examples:
|
|
|
14979
15651
|
};
|
|
14980
15652
|
}
|
|
14981
15653
|
if (createDirs) {
|
|
14982
|
-
await
|
|
15654
|
+
await fs16__default.mkdir(path17__default.dirname(absolutePath), { recursive: true });
|
|
14983
15655
|
}
|
|
14984
|
-
await
|
|
14985
|
-
const stats = await
|
|
15656
|
+
await fs16__default.writeFile(absolutePath, content, "utf-8");
|
|
15657
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
14986
15658
|
return {
|
|
14987
15659
|
path: absolutePath,
|
|
14988
15660
|
size: stats.size,
|
|
@@ -15025,8 +15697,8 @@ Examples:
|
|
|
15025
15697
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
15026
15698
|
validatePath(filePath, "write");
|
|
15027
15699
|
try {
|
|
15028
|
-
const absolutePath =
|
|
15029
|
-
let content = await
|
|
15700
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15701
|
+
let content = await fs16__default.readFile(absolutePath, "utf-8");
|
|
15030
15702
|
let replacements = 0;
|
|
15031
15703
|
if (all) {
|
|
15032
15704
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -15075,7 +15747,7 @@ Hint: Use read_file first to verify the exact content.`
|
|
|
15075
15747
|
preview
|
|
15076
15748
|
};
|
|
15077
15749
|
}
|
|
15078
|
-
await
|
|
15750
|
+
await fs16__default.writeFile(absolutePath, content, "utf-8");
|
|
15079
15751
|
return {
|
|
15080
15752
|
path: absolutePath,
|
|
15081
15753
|
replacements,
|
|
@@ -15146,8 +15818,8 @@ Examples:
|
|
|
15146
15818
|
}),
|
|
15147
15819
|
async execute({ path: filePath }) {
|
|
15148
15820
|
try {
|
|
15149
|
-
const absolutePath =
|
|
15150
|
-
const stats = await
|
|
15821
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15822
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
15151
15823
|
return {
|
|
15152
15824
|
exists: true,
|
|
15153
15825
|
isFile: stats.isFile(),
|
|
@@ -15177,12 +15849,12 @@ Examples:
|
|
|
15177
15849
|
}),
|
|
15178
15850
|
async execute({ path: dirPath, recursive }) {
|
|
15179
15851
|
try {
|
|
15180
|
-
const absolutePath =
|
|
15852
|
+
const absolutePath = path17__default.resolve(dirPath);
|
|
15181
15853
|
const entries = [];
|
|
15182
15854
|
async function listDir(dir, prefix = "") {
|
|
15183
|
-
const items = await
|
|
15855
|
+
const items = await fs16__default.readdir(dir, { withFileTypes: true });
|
|
15184
15856
|
for (const item of items) {
|
|
15185
|
-
const fullPath =
|
|
15857
|
+
const fullPath = path17__default.join(dir, item.name);
|
|
15186
15858
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
15187
15859
|
if (item.isDirectory()) {
|
|
15188
15860
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -15190,7 +15862,7 @@ Examples:
|
|
|
15190
15862
|
await listDir(fullPath, relativePath);
|
|
15191
15863
|
}
|
|
15192
15864
|
} else if (item.isFile()) {
|
|
15193
|
-
const stats = await
|
|
15865
|
+
const stats = await fs16__default.stat(fullPath);
|
|
15194
15866
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
15195
15867
|
}
|
|
15196
15868
|
}
|
|
@@ -15237,23 +15909,23 @@ Examples:
|
|
|
15237
15909
|
}
|
|
15238
15910
|
validatePath(filePath, "delete");
|
|
15239
15911
|
try {
|
|
15240
|
-
const absolutePath =
|
|
15241
|
-
const stats = await
|
|
15912
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15913
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
15242
15914
|
if (stats.isDirectory()) {
|
|
15243
15915
|
if (!recursive) {
|
|
15244
15916
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
15245
15917
|
tool: "delete_file"
|
|
15246
15918
|
});
|
|
15247
15919
|
}
|
|
15248
|
-
await
|
|
15920
|
+
await fs16__default.rm(absolutePath, { recursive: true });
|
|
15249
15921
|
} else {
|
|
15250
|
-
await
|
|
15922
|
+
await fs16__default.unlink(absolutePath);
|
|
15251
15923
|
}
|
|
15252
15924
|
return { deleted: true, path: absolutePath };
|
|
15253
15925
|
} catch (error) {
|
|
15254
15926
|
if (error instanceof ToolError) throw error;
|
|
15255
15927
|
if (error.code === "ENOENT") {
|
|
15256
|
-
return { deleted: false, path:
|
|
15928
|
+
return { deleted: false, path: path17__default.resolve(filePath) };
|
|
15257
15929
|
}
|
|
15258
15930
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
15259
15931
|
path: filePath,
|
|
@@ -15281,11 +15953,11 @@ Examples:
|
|
|
15281
15953
|
validatePath(source, "read");
|
|
15282
15954
|
validatePath(destination, "write");
|
|
15283
15955
|
try {
|
|
15284
|
-
const srcPath =
|
|
15285
|
-
const destPath =
|
|
15956
|
+
const srcPath = path17__default.resolve(source);
|
|
15957
|
+
const destPath = path17__default.resolve(destination);
|
|
15286
15958
|
if (!overwrite) {
|
|
15287
15959
|
try {
|
|
15288
|
-
await
|
|
15960
|
+
await fs16__default.access(destPath);
|
|
15289
15961
|
throw new ToolError(
|
|
15290
15962
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
15291
15963
|
{
|
|
@@ -15298,9 +15970,9 @@ Examples:
|
|
|
15298
15970
|
}
|
|
15299
15971
|
}
|
|
15300
15972
|
}
|
|
15301
|
-
await
|
|
15302
|
-
await
|
|
15303
|
-
const stats = await
|
|
15973
|
+
await fs16__default.mkdir(path17__default.dirname(destPath), { recursive: true });
|
|
15974
|
+
await fs16__default.copyFile(srcPath, destPath);
|
|
15975
|
+
const stats = await fs16__default.stat(destPath);
|
|
15304
15976
|
return {
|
|
15305
15977
|
source: srcPath,
|
|
15306
15978
|
destination: destPath,
|
|
@@ -15342,11 +16014,11 @@ Examples:
|
|
|
15342
16014
|
validatePath(source, "delete");
|
|
15343
16015
|
validatePath(destination, "write");
|
|
15344
16016
|
try {
|
|
15345
|
-
const srcPath =
|
|
15346
|
-
const destPath =
|
|
16017
|
+
const srcPath = path17__default.resolve(source);
|
|
16018
|
+
const destPath = path17__default.resolve(destination);
|
|
15347
16019
|
if (!overwrite) {
|
|
15348
16020
|
try {
|
|
15349
|
-
await
|
|
16021
|
+
await fs16__default.access(destPath);
|
|
15350
16022
|
throw new ToolError(
|
|
15351
16023
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
15352
16024
|
{
|
|
@@ -15359,8 +16031,8 @@ Examples:
|
|
|
15359
16031
|
}
|
|
15360
16032
|
}
|
|
15361
16033
|
}
|
|
15362
|
-
await
|
|
15363
|
-
await
|
|
16034
|
+
await fs16__default.mkdir(path17__default.dirname(destPath), { recursive: true });
|
|
16035
|
+
await fs16__default.rename(srcPath, destPath);
|
|
15364
16036
|
return {
|
|
15365
16037
|
source: srcPath,
|
|
15366
16038
|
destination: destPath
|
|
@@ -15402,13 +16074,13 @@ Examples:
|
|
|
15402
16074
|
}),
|
|
15403
16075
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
15404
16076
|
try {
|
|
15405
|
-
const absolutePath =
|
|
16077
|
+
const absolutePath = path17__default.resolve(dirPath ?? ".");
|
|
15406
16078
|
let totalFiles = 0;
|
|
15407
16079
|
let totalDirs = 0;
|
|
15408
|
-
const lines = [
|
|
16080
|
+
const lines = [path17__default.basename(absolutePath) + "/"];
|
|
15409
16081
|
async function buildTree(dir, prefix, currentDepth) {
|
|
15410
16082
|
if (currentDepth > (depth ?? 4)) return;
|
|
15411
|
-
let items = await
|
|
16083
|
+
let items = await fs16__default.readdir(dir, { withFileTypes: true });
|
|
15412
16084
|
if (!showHidden) {
|
|
15413
16085
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
15414
16086
|
}
|
|
@@ -15428,7 +16100,7 @@ Examples:
|
|
|
15428
16100
|
if (item.isDirectory()) {
|
|
15429
16101
|
totalDirs++;
|
|
15430
16102
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
15431
|
-
await buildTree(
|
|
16103
|
+
await buildTree(path17__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
15432
16104
|
} else {
|
|
15433
16105
|
totalFiles++;
|
|
15434
16106
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -16469,8 +17141,8 @@ var checkAgentCapabilityTool = defineTool({
|
|
|
16469
17141
|
var simpleAgentTools = [spawnSimpleAgentTool, checkAgentCapabilityTool];
|
|
16470
17142
|
async function detectTestFramework2(cwd) {
|
|
16471
17143
|
try {
|
|
16472
|
-
const pkgPath =
|
|
16473
|
-
const pkgContent = await
|
|
17144
|
+
const pkgPath = path17__default.join(cwd, "package.json");
|
|
17145
|
+
const pkgContent = await fs16__default.readFile(pkgPath, "utf-8");
|
|
16474
17146
|
const pkg = JSON.parse(pkgContent);
|
|
16475
17147
|
const deps = {
|
|
16476
17148
|
...pkg.dependencies,
|
|
@@ -16651,13 +17323,13 @@ Examples:
|
|
|
16651
17323
|
const projectDir = cwd ?? process.cwd();
|
|
16652
17324
|
try {
|
|
16653
17325
|
const coverageLocations = [
|
|
16654
|
-
|
|
16655
|
-
|
|
16656
|
-
|
|
17326
|
+
path17__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
17327
|
+
path17__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
17328
|
+
path17__default.join(projectDir, ".nyc_output", "coverage-summary.json")
|
|
16657
17329
|
];
|
|
16658
17330
|
for (const location of coverageLocations) {
|
|
16659
17331
|
try {
|
|
16660
|
-
const content = await
|
|
17332
|
+
const content = await fs16__default.readFile(location, "utf-8");
|
|
16661
17333
|
const coverage = JSON.parse(content);
|
|
16662
17334
|
if (coverage.total) {
|
|
16663
17335
|
return {
|
|
@@ -16710,8 +17382,8 @@ Examples:
|
|
|
16710
17382
|
var testTools = [runTestsTool, getCoverageTool, runTestFileTool];
|
|
16711
17383
|
async function detectLinter2(cwd) {
|
|
16712
17384
|
try {
|
|
16713
|
-
const pkgPath =
|
|
16714
|
-
const pkgContent = await
|
|
17385
|
+
const pkgPath = path17__default.join(cwd, "package.json");
|
|
17386
|
+
const pkgContent = await fs16__default.readFile(pkgPath, "utf-8");
|
|
16715
17387
|
const pkg = JSON.parse(pkgContent);
|
|
16716
17388
|
const deps = {
|
|
16717
17389
|
...pkg.dependencies,
|
|
@@ -16869,7 +17541,7 @@ Examples:
|
|
|
16869
17541
|
let totalFunctions = 0;
|
|
16870
17542
|
let complexFunctions = 0;
|
|
16871
17543
|
for (const file of targetFiles) {
|
|
16872
|
-
const content = await
|
|
17544
|
+
const content = await fs16__default.readFile(file, "utf-8");
|
|
16873
17545
|
const fileComplexity = analyzeFileComplexity(content, file);
|
|
16874
17546
|
fileResults.push(fileComplexity);
|
|
16875
17547
|
totalComplexity += fileComplexity.complexity;
|
|
@@ -17020,7 +17692,7 @@ Examples:
|
|
|
17020
17692
|
caseSensitive,
|
|
17021
17693
|
wholeWord
|
|
17022
17694
|
}) {
|
|
17023
|
-
const targetPath = searchPath ?
|
|
17695
|
+
const targetPath = searchPath ? path17__default.resolve(searchPath) : process.cwd();
|
|
17024
17696
|
const matches = [];
|
|
17025
17697
|
let filesSearched = 0;
|
|
17026
17698
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -17042,7 +17714,7 @@ Examples:
|
|
|
17042
17714
|
tool: "grep"
|
|
17043
17715
|
});
|
|
17044
17716
|
}
|
|
17045
|
-
const stats = await
|
|
17717
|
+
const stats = await fs16__default.stat(targetPath);
|
|
17046
17718
|
let filesToSearch;
|
|
17047
17719
|
if (stats.isFile()) {
|
|
17048
17720
|
filesToSearch = [targetPath];
|
|
@@ -17064,7 +17736,7 @@ Examples:
|
|
|
17064
17736
|
}
|
|
17065
17737
|
filesSearched++;
|
|
17066
17738
|
try {
|
|
17067
|
-
const content = await
|
|
17739
|
+
const content = await fs16__default.readFile(file, "utf-8");
|
|
17068
17740
|
const lines = content.split("\n");
|
|
17069
17741
|
let fileHasMatch = false;
|
|
17070
17742
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -17087,7 +17759,7 @@ Examples:
|
|
|
17087
17759
|
contextAfter.push(lines[j] ?? "");
|
|
17088
17760
|
}
|
|
17089
17761
|
matches.push({
|
|
17090
|
-
file:
|
|
17762
|
+
file: path17__default.relative(process.cwd(), file),
|
|
17091
17763
|
line: i + 1,
|
|
17092
17764
|
column: match.index + 1,
|
|
17093
17765
|
content: line,
|
|
@@ -17138,8 +17810,8 @@ Examples:
|
|
|
17138
17810
|
}),
|
|
17139
17811
|
async execute({ file, pattern, caseSensitive }) {
|
|
17140
17812
|
try {
|
|
17141
|
-
const absolutePath =
|
|
17142
|
-
const content = await
|
|
17813
|
+
const absolutePath = path17__default.resolve(file);
|
|
17814
|
+
const content = await fs16__default.readFile(absolutePath, "utf-8");
|
|
17143
17815
|
const lines = content.split("\n");
|
|
17144
17816
|
const matches = [];
|
|
17145
17817
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -17336,7 +18008,7 @@ async function detectPackageManager(cwd) {
|
|
|
17336
18008
|
];
|
|
17337
18009
|
for (const { file, pm } of lockfiles) {
|
|
17338
18010
|
try {
|
|
17339
|
-
await
|
|
18011
|
+
await fs16__default.access(path17__default.join(cwd, file));
|
|
17340
18012
|
return pm;
|
|
17341
18013
|
} catch {
|
|
17342
18014
|
}
|
|
@@ -17609,7 +18281,7 @@ ${message}
|
|
|
17609
18281
|
});
|
|
17610
18282
|
try {
|
|
17611
18283
|
try {
|
|
17612
|
-
await
|
|
18284
|
+
await fs16__default.access(path17__default.join(projectDir, "Makefile"));
|
|
17613
18285
|
} catch {
|
|
17614
18286
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
17615
18287
|
}
|
|
@@ -17814,7 +18486,7 @@ z.object({
|
|
|
17814
18486
|
});
|
|
17815
18487
|
|
|
17816
18488
|
// src/cli/repl/session.ts
|
|
17817
|
-
|
|
18489
|
+
path17__default.dirname(CONFIG_PATHS.trustedTools);
|
|
17818
18490
|
CONFIG_PATHS.trustedTools;
|
|
17819
18491
|
|
|
17820
18492
|
// src/cli/repl/recommended-permissions.ts
|
|
@@ -19349,15 +20021,15 @@ Examples:
|
|
|
19349
20021
|
var diffTools = [showDiffTool];
|
|
19350
20022
|
async function fileExists(filePath) {
|
|
19351
20023
|
try {
|
|
19352
|
-
await
|
|
20024
|
+
await fs16__default.access(filePath);
|
|
19353
20025
|
return true;
|
|
19354
20026
|
} catch {
|
|
19355
20027
|
return false;
|
|
19356
20028
|
}
|
|
19357
20029
|
}
|
|
19358
|
-
async function fileExists2(
|
|
20030
|
+
async function fileExists2(path40) {
|
|
19359
20031
|
try {
|
|
19360
|
-
await access(
|
|
20032
|
+
await access(path40);
|
|
19361
20033
|
return true;
|
|
19362
20034
|
} catch {
|
|
19363
20035
|
return false;
|
|
@@ -19447,7 +20119,7 @@ async function detectMaturity(cwd) {
|
|
|
19447
20119
|
if (!hasLintConfig && hasPackageJson) {
|
|
19448
20120
|
try {
|
|
19449
20121
|
const pkgRaw = await import('fs/promises').then(
|
|
19450
|
-
(
|
|
20122
|
+
(fs38) => fs38.readFile(join(cwd, "package.json"), "utf-8")
|
|
19451
20123
|
);
|
|
19452
20124
|
const pkg = JSON.parse(pkgRaw);
|
|
19453
20125
|
if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
|
|
@@ -19616,7 +20288,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
19616
20288
|
);
|
|
19617
20289
|
if (!hasTestChange) {
|
|
19618
20290
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
19619
|
-
const testExists = await fileExists(
|
|
20291
|
+
const testExists = await fileExists(path17__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists(path17__default.join(cwd, `${baseName}.spec${ext}`));
|
|
19620
20292
|
if (testExists) {
|
|
19621
20293
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
19622
20294
|
findings.push({
|
|
@@ -19847,8 +20519,8 @@ Examples:
|
|
|
19847
20519
|
}
|
|
19848
20520
|
});
|
|
19849
20521
|
var reviewTools = [reviewCodeTool];
|
|
19850
|
-
var
|
|
19851
|
-
var
|
|
20522
|
+
var fs25 = await import('fs/promises');
|
|
20523
|
+
var path27 = await import('path');
|
|
19852
20524
|
var { glob: glob14 } = await import('glob');
|
|
19853
20525
|
var DEFAULT_MAX_FILES = 200;
|
|
19854
20526
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -19874,7 +20546,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
19874
20546
|
"**/*.d.ts"
|
|
19875
20547
|
];
|
|
19876
20548
|
function detectLanguage3(filePath) {
|
|
19877
|
-
const ext =
|
|
20549
|
+
const ext = path27.extname(filePath).toLowerCase();
|
|
19878
20550
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
19879
20551
|
if (extensions.includes(ext)) return lang;
|
|
19880
20552
|
}
|
|
@@ -20283,9 +20955,9 @@ Examples:
|
|
|
20283
20955
|
}),
|
|
20284
20956
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
20285
20957
|
const startTime = performance.now();
|
|
20286
|
-
const absPath =
|
|
20958
|
+
const absPath = path27.resolve(rootPath);
|
|
20287
20959
|
try {
|
|
20288
|
-
const stat2 = await
|
|
20960
|
+
const stat2 = await fs25.stat(absPath);
|
|
20289
20961
|
if (!stat2.isDirectory()) {
|
|
20290
20962
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
20291
20963
|
tool: "codebase_map"
|
|
@@ -20322,14 +20994,14 @@ Examples:
|
|
|
20322
20994
|
let totalDefinitions = 0;
|
|
20323
20995
|
let exportedSymbols = 0;
|
|
20324
20996
|
for (const file of limitedFiles) {
|
|
20325
|
-
const fullPath =
|
|
20997
|
+
const fullPath = path27.join(absPath, file);
|
|
20326
20998
|
const language = detectLanguage3(file);
|
|
20327
20999
|
if (!language) continue;
|
|
20328
21000
|
if (languages && !languages.includes(language)) {
|
|
20329
21001
|
continue;
|
|
20330
21002
|
}
|
|
20331
21003
|
try {
|
|
20332
|
-
const content = await
|
|
21004
|
+
const content = await fs25.readFile(fullPath, "utf-8");
|
|
20333
21005
|
const lineCount = content.split("\n").length;
|
|
20334
21006
|
const parsed = parseFile(content, language);
|
|
20335
21007
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -20362,23 +21034,23 @@ Examples:
|
|
|
20362
21034
|
});
|
|
20363
21035
|
var codebaseMapTools = [codebaseMapTool];
|
|
20364
21036
|
init_paths();
|
|
20365
|
-
var
|
|
20366
|
-
var
|
|
21037
|
+
var fs26 = await import('fs/promises');
|
|
21038
|
+
var path28 = await import('path');
|
|
20367
21039
|
var crypto2 = await import('crypto');
|
|
20368
|
-
var GLOBAL_MEMORIES_DIR =
|
|
21040
|
+
var GLOBAL_MEMORIES_DIR = path28.join(COCO_HOME, "memories");
|
|
20369
21041
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
20370
21042
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
20371
21043
|
async function ensureDir(dirPath) {
|
|
20372
|
-
await
|
|
21044
|
+
await fs26.mkdir(dirPath, { recursive: true });
|
|
20373
21045
|
}
|
|
20374
21046
|
function getMemoriesDir(scope) {
|
|
20375
21047
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
20376
21048
|
}
|
|
20377
21049
|
async function loadIndex(scope) {
|
|
20378
21050
|
const dir = getMemoriesDir(scope);
|
|
20379
|
-
const indexPath =
|
|
21051
|
+
const indexPath = path28.join(dir, "index.json");
|
|
20380
21052
|
try {
|
|
20381
|
-
const content = await
|
|
21053
|
+
const content = await fs26.readFile(indexPath, "utf-8");
|
|
20382
21054
|
return JSON.parse(content);
|
|
20383
21055
|
} catch {
|
|
20384
21056
|
return [];
|
|
@@ -20387,14 +21059,14 @@ async function loadIndex(scope) {
|
|
|
20387
21059
|
async function saveIndex(scope, index) {
|
|
20388
21060
|
const dir = getMemoriesDir(scope);
|
|
20389
21061
|
await ensureDir(dir);
|
|
20390
|
-
const indexPath =
|
|
20391
|
-
await
|
|
21062
|
+
const indexPath = path28.join(dir, "index.json");
|
|
21063
|
+
await fs26.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
20392
21064
|
}
|
|
20393
21065
|
async function loadMemory(scope, id) {
|
|
20394
21066
|
const dir = getMemoriesDir(scope);
|
|
20395
|
-
const memPath =
|
|
21067
|
+
const memPath = path28.join(dir, `${id}.json`);
|
|
20396
21068
|
try {
|
|
20397
|
-
const content = await
|
|
21069
|
+
const content = await fs26.readFile(memPath, "utf-8");
|
|
20398
21070
|
return JSON.parse(content);
|
|
20399
21071
|
} catch {
|
|
20400
21072
|
return null;
|
|
@@ -20403,8 +21075,8 @@ async function loadMemory(scope, id) {
|
|
|
20403
21075
|
async function saveMemory(scope, memory) {
|
|
20404
21076
|
const dir = getMemoriesDir(scope);
|
|
20405
21077
|
await ensureDir(dir);
|
|
20406
|
-
const memPath =
|
|
20407
|
-
await
|
|
21078
|
+
const memPath = path28.join(dir, `${memory.id}.json`);
|
|
21079
|
+
await fs26.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
20408
21080
|
}
|
|
20409
21081
|
var createMemoryTool = defineTool({
|
|
20410
21082
|
name: "create_memory",
|
|
@@ -20556,17 +21228,17 @@ Examples:
|
|
|
20556
21228
|
}
|
|
20557
21229
|
});
|
|
20558
21230
|
var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
20559
|
-
var
|
|
21231
|
+
var fs27 = await import('fs/promises');
|
|
20560
21232
|
var crypto3 = await import('crypto');
|
|
20561
21233
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
20562
21234
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
20563
21235
|
var STASH_PREFIX = "coco-cp";
|
|
20564
21236
|
async function ensureCocoDir() {
|
|
20565
|
-
await
|
|
21237
|
+
await fs27.mkdir(".coco", { recursive: true });
|
|
20566
21238
|
}
|
|
20567
21239
|
async function loadCheckpoints() {
|
|
20568
21240
|
try {
|
|
20569
|
-
const content = await
|
|
21241
|
+
const content = await fs27.readFile(CHECKPOINT_FILE, "utf-8");
|
|
20570
21242
|
return JSON.parse(content);
|
|
20571
21243
|
} catch {
|
|
20572
21244
|
return [];
|
|
@@ -20574,7 +21246,7 @@ async function loadCheckpoints() {
|
|
|
20574
21246
|
}
|
|
20575
21247
|
async function saveCheckpoints(checkpoints) {
|
|
20576
21248
|
await ensureCocoDir();
|
|
20577
|
-
await
|
|
21249
|
+
await fs27.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
20578
21250
|
}
|
|
20579
21251
|
async function execGit(args) {
|
|
20580
21252
|
const { execaCommand } = await import('execa');
|
|
@@ -20736,8 +21408,8 @@ Examples:
|
|
|
20736
21408
|
}
|
|
20737
21409
|
});
|
|
20738
21410
|
var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpointsTool];
|
|
20739
|
-
var
|
|
20740
|
-
var
|
|
21411
|
+
var fs28 = await import('fs/promises');
|
|
21412
|
+
var path29 = await import('path');
|
|
20741
21413
|
var { glob: glob15 } = await import('glob');
|
|
20742
21414
|
var INDEX_DIR = ".coco/search-index";
|
|
20743
21415
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -20865,20 +21537,20 @@ async function getEmbedding(text) {
|
|
|
20865
21537
|
}
|
|
20866
21538
|
async function loadIndex2(indexDir) {
|
|
20867
21539
|
try {
|
|
20868
|
-
const indexPath =
|
|
20869
|
-
const content = await
|
|
21540
|
+
const indexPath = path29.join(indexDir, "index.json");
|
|
21541
|
+
const content = await fs28.readFile(indexPath, "utf-8");
|
|
20870
21542
|
return JSON.parse(content);
|
|
20871
21543
|
} catch {
|
|
20872
21544
|
return null;
|
|
20873
21545
|
}
|
|
20874
21546
|
}
|
|
20875
21547
|
async function saveIndex2(indexDir, index) {
|
|
20876
|
-
await
|
|
20877
|
-
const indexPath =
|
|
20878
|
-
await
|
|
21548
|
+
await fs28.mkdir(indexDir, { recursive: true });
|
|
21549
|
+
const indexPath = path29.join(indexDir, "index.json");
|
|
21550
|
+
await fs28.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
20879
21551
|
}
|
|
20880
21552
|
function isBinary(filePath) {
|
|
20881
|
-
return BINARY_EXTENSIONS.has(
|
|
21553
|
+
return BINARY_EXTENSIONS.has(path29.extname(filePath).toLowerCase());
|
|
20882
21554
|
}
|
|
20883
21555
|
var semanticSearchTool = defineTool({
|
|
20884
21556
|
name: "semantic_search",
|
|
@@ -20903,8 +21575,8 @@ Examples:
|
|
|
20903
21575
|
const effectivePath = rootPath ?? ".";
|
|
20904
21576
|
const effectiveMaxResults = maxResults ?? 10;
|
|
20905
21577
|
const effectiveThreshold = threshold ?? 0.3;
|
|
20906
|
-
const absPath =
|
|
20907
|
-
const indexDir =
|
|
21578
|
+
const absPath = path29.resolve(effectivePath);
|
|
21579
|
+
const indexDir = path29.join(absPath, INDEX_DIR);
|
|
20908
21580
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
20909
21581
|
let warnings = [];
|
|
20910
21582
|
if (!index) {
|
|
@@ -20920,10 +21592,10 @@ Examples:
|
|
|
20920
21592
|
let indexSaveWarning = "";
|
|
20921
21593
|
for (const file of files) {
|
|
20922
21594
|
if (isBinary(file)) continue;
|
|
20923
|
-
const fullPath =
|
|
21595
|
+
const fullPath = path29.join(absPath, file);
|
|
20924
21596
|
try {
|
|
20925
|
-
const stat2 = await
|
|
20926
|
-
const content = await
|
|
21597
|
+
const stat2 = await fs28.stat(fullPath);
|
|
21598
|
+
const content = await fs28.readFile(fullPath, "utf-8");
|
|
20927
21599
|
if (content.length > 1e5) continue;
|
|
20928
21600
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
20929
21601
|
for (const chunk of fileChunks) {
|
|
@@ -20999,8 +21671,8 @@ Examples:
|
|
|
20999
21671
|
}
|
|
21000
21672
|
});
|
|
21001
21673
|
var semanticSearchTools = [semanticSearchTool];
|
|
21002
|
-
var
|
|
21003
|
-
var
|
|
21674
|
+
var fs29 = await import('fs/promises');
|
|
21675
|
+
var path30 = await import('path');
|
|
21004
21676
|
var { glob: glob16 } = await import('glob');
|
|
21005
21677
|
async function parseClassRelationships(rootPath, include) {
|
|
21006
21678
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -21013,7 +21685,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
21013
21685
|
const interfaces = [];
|
|
21014
21686
|
for (const file of files.slice(0, 100)) {
|
|
21015
21687
|
try {
|
|
21016
|
-
const content = await
|
|
21688
|
+
const content = await fs29.readFile(path30.join(rootPath, file), "utf-8");
|
|
21017
21689
|
const lines = content.split("\n");
|
|
21018
21690
|
for (let i = 0; i < lines.length; i++) {
|
|
21019
21691
|
const line = lines[i];
|
|
@@ -21132,14 +21804,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
21132
21804
|
};
|
|
21133
21805
|
}
|
|
21134
21806
|
async function generateArchitectureDiagram(rootPath) {
|
|
21135
|
-
const entries = await
|
|
21807
|
+
const entries = await fs29.readdir(rootPath, { withFileTypes: true });
|
|
21136
21808
|
const dirs = entries.filter(
|
|
21137
21809
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
21138
21810
|
);
|
|
21139
21811
|
const lines = ["graph TD"];
|
|
21140
21812
|
let nodeCount = 0;
|
|
21141
21813
|
let edgeCount = 0;
|
|
21142
|
-
const rootName =
|
|
21814
|
+
const rootName = path30.basename(rootPath);
|
|
21143
21815
|
lines.push(` ROOT["${rootName}"]`);
|
|
21144
21816
|
nodeCount++;
|
|
21145
21817
|
for (const dir of dirs) {
|
|
@@ -21149,7 +21821,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
21149
21821
|
nodeCount++;
|
|
21150
21822
|
edgeCount++;
|
|
21151
21823
|
try {
|
|
21152
|
-
const subEntries = await
|
|
21824
|
+
const subEntries = await fs29.readdir(path30.join(rootPath, dir.name), {
|
|
21153
21825
|
withFileTypes: true
|
|
21154
21826
|
});
|
|
21155
21827
|
const subDirs = subEntries.filter(
|
|
@@ -21272,7 +21944,7 @@ Examples:
|
|
|
21272
21944
|
tool: "generate_diagram"
|
|
21273
21945
|
});
|
|
21274
21946
|
}
|
|
21275
|
-
const absPath = rootPath ?
|
|
21947
|
+
const absPath = rootPath ? path30.resolve(rootPath) : process.cwd();
|
|
21276
21948
|
switch (type) {
|
|
21277
21949
|
case "class":
|
|
21278
21950
|
return generateClassDiagram(absPath, include);
|
|
@@ -21333,8 +22005,8 @@ Examples:
|
|
|
21333
22005
|
}
|
|
21334
22006
|
});
|
|
21335
22007
|
var diagramTools = [generateDiagramTool];
|
|
21336
|
-
var
|
|
21337
|
-
var
|
|
22008
|
+
var fs30 = await import('fs/promises');
|
|
22009
|
+
var path31 = await import('path');
|
|
21338
22010
|
var DEFAULT_MAX_PAGES = 20;
|
|
21339
22011
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
21340
22012
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -21369,9 +22041,9 @@ Examples:
|
|
|
21369
22041
|
}),
|
|
21370
22042
|
async execute({ path: filePath, pages, maxPages }) {
|
|
21371
22043
|
const startTime = performance.now();
|
|
21372
|
-
const absPath =
|
|
22044
|
+
const absPath = path31.resolve(filePath);
|
|
21373
22045
|
try {
|
|
21374
|
-
const stat2 = await
|
|
22046
|
+
const stat2 = await fs30.stat(absPath);
|
|
21375
22047
|
if (!stat2.isFile()) {
|
|
21376
22048
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
21377
22049
|
tool: "read_pdf"
|
|
@@ -21402,7 +22074,7 @@ Examples:
|
|
|
21402
22074
|
}
|
|
21403
22075
|
try {
|
|
21404
22076
|
const pdfParse = await import('pdf-parse');
|
|
21405
|
-
const dataBuffer = await
|
|
22077
|
+
const dataBuffer = await fs30.readFile(absPath);
|
|
21406
22078
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
21407
22079
|
max: maxPages
|
|
21408
22080
|
});
|
|
@@ -21449,8 +22121,8 @@ Examples:
|
|
|
21449
22121
|
}
|
|
21450
22122
|
});
|
|
21451
22123
|
var pdfTools = [readPdfTool];
|
|
21452
|
-
var
|
|
21453
|
-
var
|
|
22124
|
+
var fs31 = await import('fs/promises');
|
|
22125
|
+
var path32 = await import('path');
|
|
21454
22126
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
21455
22127
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
21456
22128
|
var MIME_TYPES = {
|
|
@@ -21478,15 +22150,15 @@ Examples:
|
|
|
21478
22150
|
async execute({ path: filePath, prompt, provider }) {
|
|
21479
22151
|
const startTime = performance.now();
|
|
21480
22152
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
21481
|
-
const absPath =
|
|
22153
|
+
const absPath = path32.resolve(filePath);
|
|
21482
22154
|
const cwd = process.cwd();
|
|
21483
|
-
if (!absPath.startsWith(cwd +
|
|
22155
|
+
if (!absPath.startsWith(cwd + path32.sep) && absPath !== cwd) {
|
|
21484
22156
|
throw new ToolError(
|
|
21485
22157
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
21486
22158
|
{ tool: "read_image" }
|
|
21487
22159
|
);
|
|
21488
22160
|
}
|
|
21489
|
-
const ext =
|
|
22161
|
+
const ext = path32.extname(absPath).toLowerCase();
|
|
21490
22162
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
21491
22163
|
throw new ToolError(
|
|
21492
22164
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -21494,7 +22166,7 @@ Examples:
|
|
|
21494
22166
|
);
|
|
21495
22167
|
}
|
|
21496
22168
|
try {
|
|
21497
|
-
const stat2 = await
|
|
22169
|
+
const stat2 = await fs31.stat(absPath);
|
|
21498
22170
|
if (!stat2.isFile()) {
|
|
21499
22171
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
21500
22172
|
tool: "read_image"
|
|
@@ -21515,7 +22187,7 @@ Examples:
|
|
|
21515
22187
|
if (error instanceof ToolError) throw error;
|
|
21516
22188
|
throw error;
|
|
21517
22189
|
}
|
|
21518
|
-
const imageBuffer = await
|
|
22190
|
+
const imageBuffer = await fs31.readFile(absPath);
|
|
21519
22191
|
const base64 = imageBuffer.toString("base64");
|
|
21520
22192
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
21521
22193
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -21552,8 +22224,8 @@ Examples:
|
|
|
21552
22224
|
description = response.content.filter((block) => block.type === "text").map((block) => block.text).join("\n") || "No description generated";
|
|
21553
22225
|
} else if (selectedProvider === "openai") {
|
|
21554
22226
|
model = "gpt-4o";
|
|
21555
|
-
const { default:
|
|
21556
|
-
const client = new
|
|
22227
|
+
const { default: OpenAI3 } = await import('openai');
|
|
22228
|
+
const client = new OpenAI3();
|
|
21557
22229
|
const openaiMessages = [
|
|
21558
22230
|
{
|
|
21559
22231
|
role: "user",
|
|
@@ -21633,7 +22305,7 @@ Examples:
|
|
|
21633
22305
|
}
|
|
21634
22306
|
});
|
|
21635
22307
|
var imageTools = [readImageTool];
|
|
21636
|
-
var
|
|
22308
|
+
var path33 = await import('path');
|
|
21637
22309
|
var DANGEROUS_PATTERNS = [
|
|
21638
22310
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
21639
22311
|
/\bTRUNCATE\b/i,
|
|
@@ -21664,7 +22336,7 @@ Examples:
|
|
|
21664
22336
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
21665
22337
|
const isReadonly = isReadonlyParam ?? true;
|
|
21666
22338
|
const startTime = performance.now();
|
|
21667
|
-
const absPath =
|
|
22339
|
+
const absPath = path33.resolve(database);
|
|
21668
22340
|
if (isReadonly && isDangerousSql(query)) {
|
|
21669
22341
|
throw new ToolError(
|
|
21670
22342
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -21747,7 +22419,7 @@ Examples:
|
|
|
21747
22419
|
}),
|
|
21748
22420
|
async execute({ database, table }) {
|
|
21749
22421
|
const startTime = performance.now();
|
|
21750
|
-
const absPath =
|
|
22422
|
+
const absPath = path33.resolve(database);
|
|
21751
22423
|
try {
|
|
21752
22424
|
const { default: Database } = await import('better-sqlite3');
|
|
21753
22425
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -21806,14 +22478,14 @@ Examples:
|
|
|
21806
22478
|
}
|
|
21807
22479
|
});
|
|
21808
22480
|
var databaseTools = [sqlQueryTool, inspectSchemaTool];
|
|
21809
|
-
var
|
|
21810
|
-
var
|
|
22481
|
+
var fs32 = await import('fs/promises');
|
|
22482
|
+
var path34 = await import('path');
|
|
21811
22483
|
var AnalyzeFileSchema = z.object({
|
|
21812
22484
|
filePath: z.string().describe("Path to file to analyze"),
|
|
21813
22485
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
21814
22486
|
});
|
|
21815
22487
|
async function analyzeFile(filePath, includeAst = false) {
|
|
21816
|
-
const content = await
|
|
22488
|
+
const content = await fs32.readFile(filePath, "utf-8");
|
|
21817
22489
|
const lines = content.split("\n").length;
|
|
21818
22490
|
const functions = [];
|
|
21819
22491
|
const classes = [];
|
|
@@ -21917,10 +22589,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
21917
22589
|
try {
|
|
21918
22590
|
const analysis = await analyzeFile(file, false);
|
|
21919
22591
|
totalLines += analysis.lines;
|
|
21920
|
-
const ext =
|
|
22592
|
+
const ext = path34.extname(file);
|
|
21921
22593
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
21922
22594
|
fileStats.push({
|
|
21923
|
-
file:
|
|
22595
|
+
file: path34.relative(dirPath, file),
|
|
21924
22596
|
lines: analysis.lines,
|
|
21925
22597
|
complexity: analysis.complexity.cyclomatic
|
|
21926
22598
|
});
|
|
@@ -22285,13 +22957,13 @@ ${completed.map((r) => `- ${r.agentId}: Success`).join("\n")}`;
|
|
|
22285
22957
|
}
|
|
22286
22958
|
});
|
|
22287
22959
|
var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateResultsTool];
|
|
22288
|
-
var
|
|
22960
|
+
var fs33 = await import('fs/promises');
|
|
22289
22961
|
var SuggestImprovementsSchema = z.object({
|
|
22290
22962
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
22291
22963
|
context: z.string().optional().describe("Additional context about the code")
|
|
22292
22964
|
});
|
|
22293
22965
|
async function analyzeAndSuggest(filePath, _context) {
|
|
22294
|
-
const content = await
|
|
22966
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
22295
22967
|
const lines = content.split("\n");
|
|
22296
22968
|
const suggestions = [];
|
|
22297
22969
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -22383,7 +23055,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
22383
23055
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
22384
23056
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
22385
23057
|
try {
|
|
22386
|
-
await
|
|
23058
|
+
await fs33.access(testPath);
|
|
22387
23059
|
} catch {
|
|
22388
23060
|
suggestions.push({
|
|
22389
23061
|
type: "testing",
|
|
@@ -22440,7 +23112,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
22440
23112
|
async execute(input) {
|
|
22441
23113
|
const { filePath } = input;
|
|
22442
23114
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
22443
|
-
const content = await
|
|
23115
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
22444
23116
|
const lines = content.split("\n");
|
|
22445
23117
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
22446
23118
|
let score = 100;
|
|
@@ -22474,8 +23146,8 @@ var calculateCodeScoreTool = defineTool({
|
|
|
22474
23146
|
}
|
|
22475
23147
|
});
|
|
22476
23148
|
var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
22477
|
-
var
|
|
22478
|
-
var
|
|
23149
|
+
var fs34 = await import('fs/promises');
|
|
23150
|
+
var path35 = await import('path');
|
|
22479
23151
|
var ContextMemoryStore = class {
|
|
22480
23152
|
items = /* @__PURE__ */ new Map();
|
|
22481
23153
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -22487,7 +23159,7 @@ var ContextMemoryStore = class {
|
|
|
22487
23159
|
}
|
|
22488
23160
|
async load() {
|
|
22489
23161
|
try {
|
|
22490
|
-
const content = await
|
|
23162
|
+
const content = await fs34.readFile(this.storePath, "utf-8");
|
|
22491
23163
|
const data = JSON.parse(content);
|
|
22492
23164
|
this.items = new Map(Object.entries(data.items || {}));
|
|
22493
23165
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -22495,15 +23167,15 @@ var ContextMemoryStore = class {
|
|
|
22495
23167
|
}
|
|
22496
23168
|
}
|
|
22497
23169
|
async save() {
|
|
22498
|
-
const dir =
|
|
22499
|
-
await
|
|
23170
|
+
const dir = path35.dirname(this.storePath);
|
|
23171
|
+
await fs34.mkdir(dir, { recursive: true });
|
|
22500
23172
|
const data = {
|
|
22501
23173
|
sessionId: this.sessionId,
|
|
22502
23174
|
items: Object.fromEntries(this.items),
|
|
22503
23175
|
learnings: Object.fromEntries(this.learnings),
|
|
22504
23176
|
savedAt: Date.now()
|
|
22505
23177
|
};
|
|
22506
|
-
await
|
|
23178
|
+
await fs34.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
22507
23179
|
}
|
|
22508
23180
|
addContext(id, item) {
|
|
22509
23181
|
this.items.set(id, item);
|
|
@@ -22668,11 +23340,11 @@ var contextEnhancerTools = [
|
|
|
22668
23340
|
recordLearningTool,
|
|
22669
23341
|
getLearnedPatternsTool
|
|
22670
23342
|
];
|
|
22671
|
-
var
|
|
22672
|
-
var
|
|
23343
|
+
var fs35 = await import('fs/promises');
|
|
23344
|
+
var path36 = await import('path');
|
|
22673
23345
|
async function discoverSkills(skillsDir) {
|
|
22674
23346
|
try {
|
|
22675
|
-
const files = await
|
|
23347
|
+
const files = await fs35.readdir(skillsDir);
|
|
22676
23348
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
22677
23349
|
} catch {
|
|
22678
23350
|
return [];
|
|
@@ -22680,12 +23352,12 @@ async function discoverSkills(skillsDir) {
|
|
|
22680
23352
|
}
|
|
22681
23353
|
async function loadSkillMetadata(skillPath) {
|
|
22682
23354
|
try {
|
|
22683
|
-
const content = await
|
|
23355
|
+
const content = await fs35.readFile(skillPath, "utf-8");
|
|
22684
23356
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
22685
23357
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
22686
23358
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
22687
23359
|
return {
|
|
22688
|
-
name: nameMatch?.[1] ||
|
|
23360
|
+
name: nameMatch?.[1] || path36.basename(skillPath, path36.extname(skillPath)),
|
|
22689
23361
|
description: descMatch?.[1] || "No description",
|
|
22690
23362
|
version: versionMatch?.[1] || "1.0.0",
|
|
22691
23363
|
dependencies: []
|
|
@@ -22729,7 +23401,7 @@ var discoverSkillsTool = defineTool({
|
|
|
22729
23401
|
const { skillsDir } = input;
|
|
22730
23402
|
const skills = await discoverSkills(skillsDir);
|
|
22731
23403
|
const metadata = await Promise.all(
|
|
22732
|
-
skills.map((s) => loadSkillMetadata(
|
|
23404
|
+
skills.map((s) => loadSkillMetadata(path36.join(skillsDir, s)))
|
|
22733
23405
|
);
|
|
22734
23406
|
return {
|
|
22735
23407
|
skillsDir,
|
|
@@ -23230,8 +23902,8 @@ function hasNullByte2(str) {
|
|
|
23230
23902
|
}
|
|
23231
23903
|
function isBlockedPath(absolute) {
|
|
23232
23904
|
for (const blocked of BLOCKED_PATHS2) {
|
|
23233
|
-
const normalizedBlocked =
|
|
23234
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
23905
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
23906
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
23235
23907
|
return blocked;
|
|
23236
23908
|
}
|
|
23237
23909
|
}
|
|
@@ -23249,7 +23921,7 @@ function getInterpreter(ext) {
|
|
|
23249
23921
|
}
|
|
23250
23922
|
async function isExecutable(filePath) {
|
|
23251
23923
|
try {
|
|
23252
|
-
await
|
|
23924
|
+
await fs16__default.access(filePath, fs16__default.constants.X_OK);
|
|
23253
23925
|
return true;
|
|
23254
23926
|
} catch {
|
|
23255
23927
|
return false;
|
|
@@ -23289,7 +23961,7 @@ Examples:
|
|
|
23289
23961
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
23290
23962
|
}
|
|
23291
23963
|
const workDir = cwd ?? process.cwd();
|
|
23292
|
-
const absolute =
|
|
23964
|
+
const absolute = path17__default.isAbsolute(filePath) ? path17__default.normalize(filePath) : path17__default.resolve(workDir, filePath);
|
|
23293
23965
|
const blockedBy = isBlockedPath(absolute);
|
|
23294
23966
|
if (blockedBy) {
|
|
23295
23967
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -23297,7 +23969,7 @@ Examples:
|
|
|
23297
23969
|
});
|
|
23298
23970
|
}
|
|
23299
23971
|
try {
|
|
23300
|
-
await
|
|
23972
|
+
await fs16__default.access(absolute);
|
|
23301
23973
|
} catch {
|
|
23302
23974
|
throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
|
|
23303
23975
|
}
|
|
@@ -23312,14 +23984,14 @@ Examples:
|
|
|
23312
23984
|
};
|
|
23313
23985
|
}
|
|
23314
23986
|
if (isBlockedExecFile(absolute)) {
|
|
23315
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
23987
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path17__default.basename(absolute)}`, {
|
|
23316
23988
|
tool: "open_file"
|
|
23317
23989
|
});
|
|
23318
23990
|
}
|
|
23319
23991
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
23320
23992
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
23321
23993
|
}
|
|
23322
|
-
const ext =
|
|
23994
|
+
const ext = path17__default.extname(absolute);
|
|
23323
23995
|
const interpreter = getInterpreter(ext);
|
|
23324
23996
|
const executable = await isExecutable(absolute);
|
|
23325
23997
|
let command;
|
|
@@ -23332,7 +24004,7 @@ Examples:
|
|
|
23332
24004
|
cmdArgs = [...args];
|
|
23333
24005
|
} else {
|
|
23334
24006
|
throw new ToolError(
|
|
23335
|
-
`Cannot execute '${
|
|
24007
|
+
`Cannot execute '${path17__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
23336
24008
|
{ tool: "open_file" }
|
|
23337
24009
|
);
|
|
23338
24010
|
}
|
|
@@ -23384,7 +24056,7 @@ Examples:
|
|
|
23384
24056
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
23385
24057
|
}),
|
|
23386
24058
|
async execute({ path: dirPath, reason }) {
|
|
23387
|
-
const absolute =
|
|
24059
|
+
const absolute = path17__default.resolve(dirPath);
|
|
23388
24060
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
23389
24061
|
return {
|
|
23390
24062
|
authorized: true,
|
|
@@ -23393,8 +24065,8 @@ Examples:
|
|
|
23393
24065
|
};
|
|
23394
24066
|
}
|
|
23395
24067
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
23396
|
-
const normalizedBlocked =
|
|
23397
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
24068
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
24069
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
23398
24070
|
return {
|
|
23399
24071
|
authorized: false,
|
|
23400
24072
|
path: absolute,
|
|
@@ -23403,7 +24075,7 @@ Examples:
|
|
|
23403
24075
|
}
|
|
23404
24076
|
}
|
|
23405
24077
|
const cwd = process.cwd();
|
|
23406
|
-
if (absolute ===
|
|
24078
|
+
if (absolute === path17__default.normalize(cwd) || absolute.startsWith(path17__default.normalize(cwd) + path17__default.sep)) {
|
|
23407
24079
|
return {
|
|
23408
24080
|
authorized: true,
|
|
23409
24081
|
path: absolute,
|
|
@@ -23411,7 +24083,7 @@ Examples:
|
|
|
23411
24083
|
};
|
|
23412
24084
|
}
|
|
23413
24085
|
try {
|
|
23414
|
-
const stat2 = await
|
|
24086
|
+
const stat2 = await fs16__default.stat(absolute);
|
|
23415
24087
|
if (!stat2.isDirectory()) {
|
|
23416
24088
|
return {
|
|
23417
24089
|
authorized: false,
|
|
@@ -23427,7 +24099,7 @@ Examples:
|
|
|
23427
24099
|
};
|
|
23428
24100
|
}
|
|
23429
24101
|
const existing = getAllowedPaths();
|
|
23430
|
-
if (existing.some((e) =>
|
|
24102
|
+
if (existing.some((e) => path17__default.normalize(e.path) === path17__default.normalize(absolute))) {
|
|
23431
24103
|
return {
|
|
23432
24104
|
authorized: true,
|
|
23433
24105
|
path: absolute,
|