@corbat-tech/coco 2.9.0 → 2.11.0
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 +5577 -2781
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1230 -551
- package/dist/index.js.map +1 -1
- package/package.json +17 -18
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
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
|
|
8
|
-
import
|
|
9
|
-
import * as
|
|
6
|
+
import * as fs16 from 'fs/promises';
|
|
7
|
+
import fs16__default, { readFile, access, readdir } from 'fs/promises';
|
|
8
|
+
import chalk4 from 'chalk';
|
|
9
|
+
import * as p4 from '@clack/prompts';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { randomUUID } from 'crypto';
|
|
12
12
|
import { execa } from 'execa';
|
|
@@ -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,12 +404,12 @@ __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
|
-
console.log(
|
|
403
|
-
console.log(
|
|
409
|
+
console.log(chalk4.yellow(" \u26A0 Access denied \u2014 path is outside the project directory"));
|
|
410
|
+
console.log(chalk4.dim(` \u{1F4C1} ${absolute}`));
|
|
404
411
|
console.log();
|
|
405
|
-
const action = await
|
|
412
|
+
const action = await p4.select({
|
|
406
413
|
message: "Grant access to this directory?",
|
|
407
414
|
options: [
|
|
408
415
|
{ value: "session-write", label: "\u2713 Allow write (this session)" },
|
|
@@ -412,7 +419,7 @@ async function promptAllowPath(dirPath) {
|
|
|
412
419
|
{ value: "no", label: "\u2717 Deny" }
|
|
413
420
|
]
|
|
414
421
|
});
|
|
415
|
-
if (
|
|
422
|
+
if (p4.isCancel(action) || action === "no") {
|
|
416
423
|
return false;
|
|
417
424
|
}
|
|
418
425
|
const level = action.includes("read") ? "read" : "write";
|
|
@@ -423,7 +430,7 @@ async function promptAllowPath(dirPath) {
|
|
|
423
430
|
}
|
|
424
431
|
const levelLabel = level === "write" ? "write" : "read-only";
|
|
425
432
|
const persistLabel = persist ? " (remembered)" : "";
|
|
426
|
-
console.log(
|
|
433
|
+
console.log(chalk4.green(` \u2713 Access granted: ${levelLabel}${persistLabel}`));
|
|
427
434
|
return true;
|
|
428
435
|
}
|
|
429
436
|
var init_allow_path_prompt = __esm({
|
|
@@ -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,
|
|
@@ -12985,18 +12993,18 @@ async function refreshAccessToken(provider, refreshToken) {
|
|
|
12985
12993
|
}
|
|
12986
12994
|
function getTokenStoragePath(provider) {
|
|
12987
12995
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
12988
|
-
return
|
|
12996
|
+
return path17.join(home, ".coco", "tokens", `${provider}.json`);
|
|
12989
12997
|
}
|
|
12990
12998
|
async function saveTokens(provider, tokens) {
|
|
12991
12999
|
const filePath = getTokenStoragePath(provider);
|
|
12992
|
-
const dir =
|
|
12993
|
-
await
|
|
12994
|
-
await
|
|
13000
|
+
const dir = path17.dirname(filePath);
|
|
13001
|
+
await fs16.mkdir(dir, { recursive: true, mode: 448 });
|
|
13002
|
+
await fs16.writeFile(filePath, JSON.stringify(tokens, null, 2), { mode: 384 });
|
|
12995
13003
|
}
|
|
12996
13004
|
async function loadTokens(provider) {
|
|
12997
13005
|
const filePath = getTokenStoragePath(provider);
|
|
12998
13006
|
try {
|
|
12999
|
-
const content = await
|
|
13007
|
+
const content = await fs16.readFile(filePath, "utf-8");
|
|
13000
13008
|
return JSON.parse(content);
|
|
13001
13009
|
} catch {
|
|
13002
13010
|
return null;
|
|
@@ -13005,7 +13013,7 @@ async function loadTokens(provider) {
|
|
|
13005
13013
|
async function deleteTokens(provider) {
|
|
13006
13014
|
const filePath = getTokenStoragePath(provider);
|
|
13007
13015
|
try {
|
|
13008
|
-
await
|
|
13016
|
+
await fs16.unlink(filePath);
|
|
13009
13017
|
} catch {
|
|
13010
13018
|
}
|
|
13011
13019
|
}
|
|
@@ -13043,6 +13051,124 @@ function detectWSL() {
|
|
|
13043
13051
|
}
|
|
13044
13052
|
}
|
|
13045
13053
|
var isWSL = detectWSL();
|
|
13054
|
+
var COPILOT_TOKEN_URL = "https://api.github.com/copilot_internal/v2/token";
|
|
13055
|
+
var COPILOT_BASE_URLS = {
|
|
13056
|
+
individual: "https://api.githubcopilot.com",
|
|
13057
|
+
business: "https://api.business.githubcopilot.com",
|
|
13058
|
+
enterprise: "https://api.enterprise.githubcopilot.com"
|
|
13059
|
+
};
|
|
13060
|
+
var DEFAULT_COPILOT_BASE_URL = "https://api.githubcopilot.com";
|
|
13061
|
+
var REFRESH_BUFFER_MS = 6e4;
|
|
13062
|
+
var CopilotAuthError = class extends Error {
|
|
13063
|
+
constructor(message, permanent) {
|
|
13064
|
+
super(message);
|
|
13065
|
+
this.permanent = permanent;
|
|
13066
|
+
this.name = "CopilotAuthError";
|
|
13067
|
+
}
|
|
13068
|
+
};
|
|
13069
|
+
async function exchangeForCopilotToken(githubToken) {
|
|
13070
|
+
const response = await fetch(COPILOT_TOKEN_URL, {
|
|
13071
|
+
method: "GET",
|
|
13072
|
+
headers: {
|
|
13073
|
+
Authorization: `token ${githubToken}`,
|
|
13074
|
+
Accept: "application/json",
|
|
13075
|
+
"User-Agent": "Corbat-Coco/1.0"
|
|
13076
|
+
}
|
|
13077
|
+
});
|
|
13078
|
+
if (!response.ok) {
|
|
13079
|
+
const error = await response.text();
|
|
13080
|
+
if (response.status === 401) {
|
|
13081
|
+
throw new CopilotAuthError(
|
|
13082
|
+
"GitHub token is invalid or expired. Please re-authenticate with /provider copilot.",
|
|
13083
|
+
true
|
|
13084
|
+
);
|
|
13085
|
+
}
|
|
13086
|
+
if (response.status === 403) {
|
|
13087
|
+
throw new CopilotAuthError(
|
|
13088
|
+
"GitHub Copilot is not enabled for this account.\n Please ensure you have an active Copilot subscription:\n https://github.com/settings/copilot",
|
|
13089
|
+
true
|
|
13090
|
+
);
|
|
13091
|
+
}
|
|
13092
|
+
throw new Error(`Copilot token exchange failed: ${response.status} - ${error}`);
|
|
13093
|
+
}
|
|
13094
|
+
return await response.json();
|
|
13095
|
+
}
|
|
13096
|
+
function getCopilotBaseUrl(accountType) {
|
|
13097
|
+
if (accountType && accountType in COPILOT_BASE_URLS) {
|
|
13098
|
+
return COPILOT_BASE_URLS[accountType];
|
|
13099
|
+
}
|
|
13100
|
+
return DEFAULT_COPILOT_BASE_URL;
|
|
13101
|
+
}
|
|
13102
|
+
function getCopilotCredentialsPath() {
|
|
13103
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
13104
|
+
return path17.join(home, ".coco", "tokens", "copilot.json");
|
|
13105
|
+
}
|
|
13106
|
+
async function saveCopilotCredentials(creds) {
|
|
13107
|
+
const filePath = getCopilotCredentialsPath();
|
|
13108
|
+
const dir = path17.dirname(filePath);
|
|
13109
|
+
await fs16.mkdir(dir, { recursive: true, mode: 448 });
|
|
13110
|
+
await fs16.writeFile(filePath, JSON.stringify(creds, null, 2), { mode: 384 });
|
|
13111
|
+
}
|
|
13112
|
+
var CopilotCredentialsSchema = z.object({
|
|
13113
|
+
githubToken: z.string().min(1),
|
|
13114
|
+
copilotToken: z.string().optional(),
|
|
13115
|
+
copilotTokenExpiresAt: z.number().optional(),
|
|
13116
|
+
accountType: z.string().optional()
|
|
13117
|
+
});
|
|
13118
|
+
async function loadCopilotCredentials() {
|
|
13119
|
+
try {
|
|
13120
|
+
const content = await fs16.readFile(getCopilotCredentialsPath(), "utf-8");
|
|
13121
|
+
const parsed = CopilotCredentialsSchema.safeParse(JSON.parse(content));
|
|
13122
|
+
return parsed.success ? parsed.data : null;
|
|
13123
|
+
} catch {
|
|
13124
|
+
return null;
|
|
13125
|
+
}
|
|
13126
|
+
}
|
|
13127
|
+
async function deleteCopilotCredentials() {
|
|
13128
|
+
try {
|
|
13129
|
+
await fs16.unlink(getCopilotCredentialsPath());
|
|
13130
|
+
} catch {
|
|
13131
|
+
}
|
|
13132
|
+
}
|
|
13133
|
+
function isCopilotTokenExpired(creds) {
|
|
13134
|
+
if (!creds.copilotToken || !creds.copilotTokenExpiresAt) return true;
|
|
13135
|
+
return Date.now() >= creds.copilotTokenExpiresAt - REFRESH_BUFFER_MS;
|
|
13136
|
+
}
|
|
13137
|
+
async function getValidCopilotToken() {
|
|
13138
|
+
const creds = await loadCopilotCredentials();
|
|
13139
|
+
if (!creds) return null;
|
|
13140
|
+
const envToken = process.env["GITHUB_TOKEN"] || process.env["GH_TOKEN"];
|
|
13141
|
+
const githubToken = envToken || creds.githubToken;
|
|
13142
|
+
if (!isCopilotTokenExpired(creds) && creds.copilotToken) {
|
|
13143
|
+
return {
|
|
13144
|
+
token: creds.copilotToken,
|
|
13145
|
+
baseUrl: getCopilotBaseUrl(creds.accountType),
|
|
13146
|
+
isNew: false
|
|
13147
|
+
};
|
|
13148
|
+
}
|
|
13149
|
+
try {
|
|
13150
|
+
const copilotToken = await exchangeForCopilotToken(githubToken);
|
|
13151
|
+
const updatedCreds = {
|
|
13152
|
+
...creds,
|
|
13153
|
+
githubToken: creds.githubToken,
|
|
13154
|
+
copilotToken: copilotToken.token,
|
|
13155
|
+
copilotTokenExpiresAt: copilotToken.expires_at * 1e3,
|
|
13156
|
+
accountType: copilotToken.annotations?.copilot_plan ?? creds.accountType
|
|
13157
|
+
};
|
|
13158
|
+
await saveCopilotCredentials(updatedCreds);
|
|
13159
|
+
return {
|
|
13160
|
+
token: copilotToken.token,
|
|
13161
|
+
baseUrl: getCopilotBaseUrl(updatedCreds.accountType),
|
|
13162
|
+
isNew: true
|
|
13163
|
+
};
|
|
13164
|
+
} catch (error) {
|
|
13165
|
+
if (error instanceof CopilotAuthError && error.permanent) {
|
|
13166
|
+
await deleteCopilotCredentials();
|
|
13167
|
+
return null;
|
|
13168
|
+
}
|
|
13169
|
+
throw error;
|
|
13170
|
+
}
|
|
13171
|
+
}
|
|
13046
13172
|
|
|
13047
13173
|
// src/auth/flow.ts
|
|
13048
13174
|
promisify(execFile);
|
|
@@ -13355,22 +13481,496 @@ var CodexProvider = class {
|
|
|
13355
13481
|
yield* this.stream(messages, options);
|
|
13356
13482
|
}
|
|
13357
13483
|
};
|
|
13358
|
-
var DEFAULT_MODEL4 = "gemini-3-flash-preview";
|
|
13359
13484
|
var CONTEXT_WINDOWS4 = {
|
|
13360
|
-
//
|
|
13485
|
+
// Claude models
|
|
13486
|
+
"claude-sonnet-4.6": 2e5,
|
|
13487
|
+
"claude-opus-4.6": 2e5,
|
|
13488
|
+
"claude-sonnet-4.5": 2e5,
|
|
13489
|
+
"claude-opus-4.5": 2e5,
|
|
13490
|
+
"claude-haiku-4.5": 2e5,
|
|
13491
|
+
// OpenAI models — chat/completions
|
|
13492
|
+
"gpt-4.1": 1048576,
|
|
13493
|
+
// OpenAI models — /responses API (Codex/GPT-5+)
|
|
13494
|
+
"gpt-5.3-codex": 4e5,
|
|
13495
|
+
"gpt-5.2-codex": 4e5,
|
|
13496
|
+
"gpt-5.1-codex-max": 4e5,
|
|
13497
|
+
"gpt-5.2": 4e5,
|
|
13498
|
+
"gpt-5.1": 4e5,
|
|
13499
|
+
// Google models
|
|
13500
|
+
"gemini-3.1-pro-preview": 1e6,
|
|
13501
|
+
"gemini-3-flash-preview": 1e6,
|
|
13502
|
+
"gemini-2.5-pro": 1048576
|
|
13503
|
+
};
|
|
13504
|
+
var DEFAULT_MODEL4 = "claude-sonnet-4.6";
|
|
13505
|
+
var COPILOT_HEADERS = {
|
|
13506
|
+
"Copilot-Integration-Id": "vscode-chat",
|
|
13507
|
+
"Editor-Version": "vscode/1.99.0",
|
|
13508
|
+
"Editor-Plugin-Version": "copilot-chat/0.26.7",
|
|
13509
|
+
"X-GitHub-Api-Version": "2025-04-01"
|
|
13510
|
+
};
|
|
13511
|
+
function needsResponsesApi(model) {
|
|
13512
|
+
return model.includes("codex") || model.startsWith("gpt-5") || model.startsWith("o4-") || model.startsWith("o3-");
|
|
13513
|
+
}
|
|
13514
|
+
var CopilotProvider = class extends OpenAIProvider {
|
|
13515
|
+
baseUrl = "https://api.githubcopilot.com";
|
|
13516
|
+
currentToken = null;
|
|
13517
|
+
/** In-flight refresh promise to prevent concurrent token exchanges */
|
|
13518
|
+
refreshPromise = null;
|
|
13519
|
+
constructor() {
|
|
13520
|
+
super("copilot", "GitHub Copilot");
|
|
13521
|
+
}
|
|
13522
|
+
/**
|
|
13523
|
+
* Initialize the provider with Copilot credentials.
|
|
13524
|
+
*
|
|
13525
|
+
* Gets a valid Copilot API token (from cache or by refreshing),
|
|
13526
|
+
* then creates an OpenAI client configured for the Copilot endpoint.
|
|
13527
|
+
*/
|
|
13528
|
+
async initialize(config) {
|
|
13529
|
+
this.config = {
|
|
13530
|
+
...config,
|
|
13531
|
+
model: config.model ?? DEFAULT_MODEL4
|
|
13532
|
+
};
|
|
13533
|
+
const tokenResult = await getValidCopilotToken();
|
|
13534
|
+
if (tokenResult) {
|
|
13535
|
+
this.currentToken = tokenResult.token;
|
|
13536
|
+
this.baseUrl = tokenResult.baseUrl;
|
|
13537
|
+
} else if (config.apiKey) {
|
|
13538
|
+
this.currentToken = config.apiKey;
|
|
13539
|
+
}
|
|
13540
|
+
if (!this.currentToken) {
|
|
13541
|
+
throw new ProviderError(
|
|
13542
|
+
"No Copilot token found. Please authenticate with: coco --provider copilot",
|
|
13543
|
+
{ provider: this.id }
|
|
13544
|
+
);
|
|
13545
|
+
}
|
|
13546
|
+
this.createCopilotClient();
|
|
13547
|
+
}
|
|
13548
|
+
/**
|
|
13549
|
+
* Create the OpenAI client configured for Copilot API
|
|
13550
|
+
*/
|
|
13551
|
+
createCopilotClient() {
|
|
13552
|
+
this.client = new OpenAI({
|
|
13553
|
+
apiKey: this.currentToken,
|
|
13554
|
+
baseURL: this.config.baseUrl ?? this.baseUrl,
|
|
13555
|
+
timeout: this.config.timeout ?? 12e4,
|
|
13556
|
+
defaultHeaders: COPILOT_HEADERS
|
|
13557
|
+
});
|
|
13558
|
+
}
|
|
13559
|
+
/**
|
|
13560
|
+
* Refresh the Copilot token if expired.
|
|
13561
|
+
*
|
|
13562
|
+
* Uses a mutex so concurrent callers share a single in-flight token
|
|
13563
|
+
* exchange. The slot is cleared inside the IIFE's finally block,
|
|
13564
|
+
* which runs after all awaiting callers have resumed.
|
|
13565
|
+
*/
|
|
13566
|
+
async refreshTokenIfNeeded() {
|
|
13567
|
+
if (!this.refreshPromise) {
|
|
13568
|
+
this.refreshPromise = (async () => {
|
|
13569
|
+
try {
|
|
13570
|
+
const tokenResult = await getValidCopilotToken();
|
|
13571
|
+
if (tokenResult && tokenResult.isNew) {
|
|
13572
|
+
this.currentToken = tokenResult.token;
|
|
13573
|
+
this.baseUrl = tokenResult.baseUrl;
|
|
13574
|
+
this.createCopilotClient();
|
|
13575
|
+
}
|
|
13576
|
+
} finally {
|
|
13577
|
+
this.refreshPromise = null;
|
|
13578
|
+
}
|
|
13579
|
+
})();
|
|
13580
|
+
}
|
|
13581
|
+
await this.refreshPromise;
|
|
13582
|
+
}
|
|
13583
|
+
// --- Override public methods to add token refresh + Responses API routing ---
|
|
13584
|
+
async chat(messages, options) {
|
|
13585
|
+
await this.refreshTokenIfNeeded();
|
|
13586
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13587
|
+
if (needsResponsesApi(model)) {
|
|
13588
|
+
return this.chatViaResponses(messages, options);
|
|
13589
|
+
}
|
|
13590
|
+
return super.chat(messages, options);
|
|
13591
|
+
}
|
|
13592
|
+
async chatWithTools(messages, options) {
|
|
13593
|
+
await this.refreshTokenIfNeeded();
|
|
13594
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13595
|
+
if (needsResponsesApi(model)) {
|
|
13596
|
+
return this.chatWithToolsViaResponses(messages, options);
|
|
13597
|
+
}
|
|
13598
|
+
return super.chatWithTools(messages, options);
|
|
13599
|
+
}
|
|
13600
|
+
// Note: Token is refreshed before the stream starts but NOT mid-stream.
|
|
13601
|
+
// Copilot tokens last ~25 min. Very long streams may get a 401 mid-stream
|
|
13602
|
+
// which surfaces as a ProviderError. The retry layer handles re-attempts.
|
|
13603
|
+
async *stream(messages, options) {
|
|
13604
|
+
await this.refreshTokenIfNeeded();
|
|
13605
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13606
|
+
if (needsResponsesApi(model)) {
|
|
13607
|
+
yield* this.streamViaResponses(messages, options);
|
|
13608
|
+
return;
|
|
13609
|
+
}
|
|
13610
|
+
yield* super.stream(messages, options);
|
|
13611
|
+
}
|
|
13612
|
+
async *streamWithTools(messages, options) {
|
|
13613
|
+
await this.refreshTokenIfNeeded();
|
|
13614
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13615
|
+
if (needsResponsesApi(model)) {
|
|
13616
|
+
yield* this.streamWithToolsViaResponses(messages, options);
|
|
13617
|
+
return;
|
|
13618
|
+
}
|
|
13619
|
+
yield* super.streamWithTools(messages, options);
|
|
13620
|
+
}
|
|
13621
|
+
// --- Responses API implementations ---
|
|
13622
|
+
/**
|
|
13623
|
+
* Simple chat via Responses API (no tools)
|
|
13624
|
+
*/
|
|
13625
|
+
async chatViaResponses(messages, options) {
|
|
13626
|
+
this.ensureInitialized();
|
|
13627
|
+
return withRetry(async () => {
|
|
13628
|
+
try {
|
|
13629
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13630
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13631
|
+
const response = await this.client.responses.create({
|
|
13632
|
+
model,
|
|
13633
|
+
input,
|
|
13634
|
+
instructions: instructions ?? void 0,
|
|
13635
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13636
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13637
|
+
store: false
|
|
13638
|
+
});
|
|
13639
|
+
return {
|
|
13640
|
+
id: response.id,
|
|
13641
|
+
content: response.output_text ?? "",
|
|
13642
|
+
stopReason: response.status === "completed" ? "end_turn" : "max_tokens",
|
|
13643
|
+
usage: {
|
|
13644
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
13645
|
+
outputTokens: response.usage?.output_tokens ?? 0
|
|
13646
|
+
},
|
|
13647
|
+
model: String(response.model)
|
|
13648
|
+
};
|
|
13649
|
+
} catch (error) {
|
|
13650
|
+
throw this.handleError(error);
|
|
13651
|
+
}
|
|
13652
|
+
}, DEFAULT_RETRY_CONFIG);
|
|
13653
|
+
}
|
|
13654
|
+
/**
|
|
13655
|
+
* Chat with tools via Responses API
|
|
13656
|
+
*/
|
|
13657
|
+
async chatWithToolsViaResponses(messages, options) {
|
|
13658
|
+
this.ensureInitialized();
|
|
13659
|
+
return withRetry(async () => {
|
|
13660
|
+
try {
|
|
13661
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13662
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13663
|
+
const tools = this.convertToolsForResponses(options.tools);
|
|
13664
|
+
const response = await this.client.responses.create({
|
|
13665
|
+
model,
|
|
13666
|
+
input,
|
|
13667
|
+
instructions: instructions ?? void 0,
|
|
13668
|
+
tools,
|
|
13669
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13670
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13671
|
+
store: false
|
|
13672
|
+
});
|
|
13673
|
+
let content = "";
|
|
13674
|
+
const toolCalls = [];
|
|
13675
|
+
for (const item of response.output) {
|
|
13676
|
+
if (item.type === "message") {
|
|
13677
|
+
for (const part of item.content) {
|
|
13678
|
+
if (part.type === "output_text") {
|
|
13679
|
+
content += part.text;
|
|
13680
|
+
}
|
|
13681
|
+
}
|
|
13682
|
+
} else if (item.type === "function_call") {
|
|
13683
|
+
toolCalls.push({
|
|
13684
|
+
id: item.call_id,
|
|
13685
|
+
name: item.name,
|
|
13686
|
+
input: this.parseToolArguments(item.arguments)
|
|
13687
|
+
});
|
|
13688
|
+
}
|
|
13689
|
+
}
|
|
13690
|
+
return {
|
|
13691
|
+
id: response.id,
|
|
13692
|
+
content,
|
|
13693
|
+
stopReason: response.status === "completed" ? "end_turn" : "tool_use",
|
|
13694
|
+
usage: {
|
|
13695
|
+
inputTokens: response.usage?.input_tokens ?? 0,
|
|
13696
|
+
outputTokens: response.usage?.output_tokens ?? 0
|
|
13697
|
+
},
|
|
13698
|
+
model: String(response.model),
|
|
13699
|
+
toolCalls
|
|
13700
|
+
};
|
|
13701
|
+
} catch (error) {
|
|
13702
|
+
throw this.handleError(error);
|
|
13703
|
+
}
|
|
13704
|
+
}, DEFAULT_RETRY_CONFIG);
|
|
13705
|
+
}
|
|
13706
|
+
/**
|
|
13707
|
+
* Stream via Responses API (no tools)
|
|
13708
|
+
*/
|
|
13709
|
+
async *streamViaResponses(messages, options) {
|
|
13710
|
+
this.ensureInitialized();
|
|
13711
|
+
try {
|
|
13712
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13713
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13714
|
+
const stream = await this.client.responses.create({
|
|
13715
|
+
model,
|
|
13716
|
+
input,
|
|
13717
|
+
instructions: instructions ?? void 0,
|
|
13718
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13719
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13720
|
+
store: false,
|
|
13721
|
+
stream: true
|
|
13722
|
+
});
|
|
13723
|
+
for await (const event of stream) {
|
|
13724
|
+
if (event.type === "response.output_text.delta") {
|
|
13725
|
+
yield { type: "text", text: event.delta };
|
|
13726
|
+
} else if (event.type === "response.completed") {
|
|
13727
|
+
yield { type: "done", stopReason: "end_turn" };
|
|
13728
|
+
}
|
|
13729
|
+
}
|
|
13730
|
+
} catch (error) {
|
|
13731
|
+
throw this.handleError(error);
|
|
13732
|
+
}
|
|
13733
|
+
}
|
|
13734
|
+
/**
|
|
13735
|
+
* Stream with tools via Responses API
|
|
13736
|
+
*/
|
|
13737
|
+
async *streamWithToolsViaResponses(messages, options) {
|
|
13738
|
+
this.ensureInitialized();
|
|
13739
|
+
try {
|
|
13740
|
+
const model = options?.model ?? this.config.model ?? DEFAULT_MODEL4;
|
|
13741
|
+
const { input, instructions } = this.convertToResponsesInput(messages, options?.system);
|
|
13742
|
+
const tools = this.convertToolsForResponses(options.tools);
|
|
13743
|
+
const stream = await this.client.responses.create({
|
|
13744
|
+
model,
|
|
13745
|
+
input,
|
|
13746
|
+
instructions: instructions ?? void 0,
|
|
13747
|
+
tools,
|
|
13748
|
+
max_output_tokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13749
|
+
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
13750
|
+
store: false,
|
|
13751
|
+
stream: true
|
|
13752
|
+
});
|
|
13753
|
+
const fnCallBuilders = /* @__PURE__ */ new Map();
|
|
13754
|
+
for await (const event of stream) {
|
|
13755
|
+
switch (event.type) {
|
|
13756
|
+
case "response.output_text.delta":
|
|
13757
|
+
yield { type: "text", text: event.delta };
|
|
13758
|
+
break;
|
|
13759
|
+
case "response.output_item.added":
|
|
13760
|
+
if (event.item.type === "function_call") {
|
|
13761
|
+
const fc = event.item;
|
|
13762
|
+
fnCallBuilders.set(fc.call_id, {
|
|
13763
|
+
callId: fc.call_id,
|
|
13764
|
+
name: fc.name,
|
|
13765
|
+
arguments: ""
|
|
13766
|
+
});
|
|
13767
|
+
yield {
|
|
13768
|
+
type: "tool_use_start",
|
|
13769
|
+
toolCall: { id: fc.call_id, name: fc.name }
|
|
13770
|
+
};
|
|
13771
|
+
}
|
|
13772
|
+
break;
|
|
13773
|
+
case "response.function_call_arguments.delta":
|
|
13774
|
+
{
|
|
13775
|
+
const builder = fnCallBuilders.get(event.item_id);
|
|
13776
|
+
if (builder) {
|
|
13777
|
+
builder.arguments += event.delta;
|
|
13778
|
+
}
|
|
13779
|
+
}
|
|
13780
|
+
break;
|
|
13781
|
+
case "response.function_call_arguments.done":
|
|
13782
|
+
{
|
|
13783
|
+
const builder = fnCallBuilders.get(event.item_id);
|
|
13784
|
+
if (builder) {
|
|
13785
|
+
yield {
|
|
13786
|
+
type: "tool_use_end",
|
|
13787
|
+
toolCall: {
|
|
13788
|
+
id: builder.callId,
|
|
13789
|
+
name: builder.name,
|
|
13790
|
+
input: this.parseToolArguments(event.arguments)
|
|
13791
|
+
}
|
|
13792
|
+
};
|
|
13793
|
+
fnCallBuilders.delete(event.item_id);
|
|
13794
|
+
}
|
|
13795
|
+
}
|
|
13796
|
+
break;
|
|
13797
|
+
case "response.completed":
|
|
13798
|
+
{
|
|
13799
|
+
for (const [, builder] of fnCallBuilders) {
|
|
13800
|
+
yield {
|
|
13801
|
+
type: "tool_use_end",
|
|
13802
|
+
toolCall: {
|
|
13803
|
+
id: builder.callId,
|
|
13804
|
+
name: builder.name,
|
|
13805
|
+
input: this.parseToolArguments(builder.arguments)
|
|
13806
|
+
}
|
|
13807
|
+
};
|
|
13808
|
+
}
|
|
13809
|
+
fnCallBuilders.clear();
|
|
13810
|
+
const hasToolCalls = event.response.output.some((i) => i.type === "function_call");
|
|
13811
|
+
yield {
|
|
13812
|
+
type: "done",
|
|
13813
|
+
stopReason: hasToolCalls ? "tool_use" : "end_turn"
|
|
13814
|
+
};
|
|
13815
|
+
}
|
|
13816
|
+
break;
|
|
13817
|
+
}
|
|
13818
|
+
}
|
|
13819
|
+
} catch (error) {
|
|
13820
|
+
throw this.handleError(error);
|
|
13821
|
+
}
|
|
13822
|
+
}
|
|
13823
|
+
// --- Responses API helpers ---
|
|
13824
|
+
/**
|
|
13825
|
+
* Convert our internal messages to Responses API input format.
|
|
13826
|
+
*
|
|
13827
|
+
* The Responses API uses a flat array of input items (EasyInputMessage,
|
|
13828
|
+
* function_call, function_call_output) instead of the chat completions
|
|
13829
|
+
* messages array.
|
|
13830
|
+
*/
|
|
13831
|
+
convertToResponsesInput(messages, systemPrompt) {
|
|
13832
|
+
const input = [];
|
|
13833
|
+
let instructions = null;
|
|
13834
|
+
if (systemPrompt) {
|
|
13835
|
+
instructions = systemPrompt;
|
|
13836
|
+
}
|
|
13837
|
+
for (const msg of messages) {
|
|
13838
|
+
if (msg.role === "system") {
|
|
13839
|
+
instructions = (instructions ? instructions + "\n\n" : "") + this.contentToStr(msg.content);
|
|
13840
|
+
} else if (msg.role === "user") {
|
|
13841
|
+
if (Array.isArray(msg.content) && msg.content.some((b) => b.type === "tool_result")) {
|
|
13842
|
+
for (const block of msg.content) {
|
|
13843
|
+
if (block.type === "tool_result") {
|
|
13844
|
+
const tr = block;
|
|
13845
|
+
input.push({
|
|
13846
|
+
type: "function_call_output",
|
|
13847
|
+
call_id: tr.tool_use_id,
|
|
13848
|
+
output: tr.content
|
|
13849
|
+
});
|
|
13850
|
+
}
|
|
13851
|
+
}
|
|
13852
|
+
} else {
|
|
13853
|
+
input.push({
|
|
13854
|
+
role: "user",
|
|
13855
|
+
content: this.contentToStr(msg.content)
|
|
13856
|
+
});
|
|
13857
|
+
}
|
|
13858
|
+
} else if (msg.role === "assistant") {
|
|
13859
|
+
if (typeof msg.content === "string") {
|
|
13860
|
+
input.push({
|
|
13861
|
+
role: "assistant",
|
|
13862
|
+
content: msg.content
|
|
13863
|
+
});
|
|
13864
|
+
} else if (Array.isArray(msg.content)) {
|
|
13865
|
+
const textParts = [];
|
|
13866
|
+
for (const block of msg.content) {
|
|
13867
|
+
if (block.type === "text") {
|
|
13868
|
+
textParts.push(block.text);
|
|
13869
|
+
} else if (block.type === "tool_use") {
|
|
13870
|
+
if (textParts.length > 0) {
|
|
13871
|
+
input.push({
|
|
13872
|
+
role: "assistant",
|
|
13873
|
+
content: textParts.join("")
|
|
13874
|
+
});
|
|
13875
|
+
textParts.length = 0;
|
|
13876
|
+
}
|
|
13877
|
+
input.push({
|
|
13878
|
+
type: "function_call",
|
|
13879
|
+
call_id: block.id,
|
|
13880
|
+
name: block.name,
|
|
13881
|
+
arguments: JSON.stringify(block.input)
|
|
13882
|
+
});
|
|
13883
|
+
}
|
|
13884
|
+
}
|
|
13885
|
+
if (textParts.length > 0) {
|
|
13886
|
+
input.push({
|
|
13887
|
+
role: "assistant",
|
|
13888
|
+
content: textParts.join("")
|
|
13889
|
+
});
|
|
13890
|
+
}
|
|
13891
|
+
}
|
|
13892
|
+
}
|
|
13893
|
+
}
|
|
13894
|
+
return { input, instructions };
|
|
13895
|
+
}
|
|
13896
|
+
/**
|
|
13897
|
+
* Convert our tool definitions to Responses API FunctionTool format
|
|
13898
|
+
*/
|
|
13899
|
+
convertToolsForResponses(tools) {
|
|
13900
|
+
return tools.map((tool) => ({
|
|
13901
|
+
type: "function",
|
|
13902
|
+
name: tool.name,
|
|
13903
|
+
description: tool.description ?? void 0,
|
|
13904
|
+
parameters: tool.input_schema ?? null,
|
|
13905
|
+
strict: false
|
|
13906
|
+
}));
|
|
13907
|
+
}
|
|
13908
|
+
/**
|
|
13909
|
+
* Parse tool call arguments with jsonrepair fallback
|
|
13910
|
+
*/
|
|
13911
|
+
parseToolArguments(args) {
|
|
13912
|
+
try {
|
|
13913
|
+
return args ? JSON.parse(args) : {};
|
|
13914
|
+
} catch {
|
|
13915
|
+
try {
|
|
13916
|
+
if (args) {
|
|
13917
|
+
const repaired = jsonrepair(args);
|
|
13918
|
+
return JSON.parse(repaired);
|
|
13919
|
+
}
|
|
13920
|
+
} catch {
|
|
13921
|
+
console.error(`[${this.name}] Cannot parse tool arguments: ${args.slice(0, 200)}`);
|
|
13922
|
+
}
|
|
13923
|
+
return {};
|
|
13924
|
+
}
|
|
13925
|
+
}
|
|
13926
|
+
/**
|
|
13927
|
+
* Convert message content to string
|
|
13928
|
+
*/
|
|
13929
|
+
contentToStr(content) {
|
|
13930
|
+
if (typeof content === "string") return content;
|
|
13931
|
+
return content.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
13932
|
+
}
|
|
13933
|
+
// --- Override metadata methods ---
|
|
13934
|
+
/**
|
|
13935
|
+
* Count tokens (approximate — Copilot models vary in tokenizer)
|
|
13936
|
+
*/
|
|
13937
|
+
countTokens(text) {
|
|
13938
|
+
if (!text) return 0;
|
|
13939
|
+
return Math.ceil(text.length / 3.5);
|
|
13940
|
+
}
|
|
13941
|
+
/**
|
|
13942
|
+
* Get context window for the current model
|
|
13943
|
+
*/
|
|
13944
|
+
getContextWindow() {
|
|
13945
|
+
const model = this.config.model ?? DEFAULT_MODEL4;
|
|
13946
|
+
return CONTEXT_WINDOWS4[model] ?? 128e3;
|
|
13947
|
+
}
|
|
13948
|
+
/**
|
|
13949
|
+
* Check if Copilot credentials are available
|
|
13950
|
+
*/
|
|
13951
|
+
async isAvailable() {
|
|
13952
|
+
try {
|
|
13953
|
+
const tokenResult = await getValidCopilotToken();
|
|
13954
|
+
return tokenResult !== null;
|
|
13955
|
+
} catch {
|
|
13956
|
+
return false;
|
|
13957
|
+
}
|
|
13958
|
+
}
|
|
13959
|
+
};
|
|
13960
|
+
var DEFAULT_MODEL5 = "gemini-3.1-pro-preview";
|
|
13961
|
+
var CONTEXT_WINDOWS5 = {
|
|
13962
|
+
// Gemini 3.1 series (latest)
|
|
13963
|
+
"gemini-3.1-pro-preview": 1e6,
|
|
13964
|
+
"gemini-3.1-flash-lite-preview": 1e6,
|
|
13965
|
+
// Gemini 3 series
|
|
13361
13966
|
"gemini-3-flash-preview": 1e6,
|
|
13362
|
-
"gemini-3-pro-preview": 1e6,
|
|
13363
13967
|
// 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
13968
|
"gemini-2.5-pro": 1048576,
|
|
13367
13969
|
"gemini-2.5-flash": 1048576,
|
|
13368
|
-
|
|
13369
|
-
"gemini-2.0-flash": 1048576,
|
|
13970
|
+
"gemini-2.5-flash-lite": 1048576,
|
|
13370
13971
|
// Legacy
|
|
13371
13972
|
"gemini-1.5-flash": 1e6,
|
|
13372
|
-
"gemini-1.5-pro": 2e6
|
|
13373
|
-
"gemini-1.0-pro": 32e3
|
|
13973
|
+
"gemini-1.5-pro": 2e6
|
|
13374
13974
|
};
|
|
13375
13975
|
var GeminiProvider = class {
|
|
13376
13976
|
id = "gemini";
|
|
@@ -13429,7 +14029,7 @@ var GeminiProvider = class {
|
|
|
13429
14029
|
await this.refreshADCIfNeeded();
|
|
13430
14030
|
try {
|
|
13431
14031
|
const model = this.client.getGenerativeModel({
|
|
13432
|
-
model: options?.model ?? this.config.model ??
|
|
14032
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13433
14033
|
generationConfig: {
|
|
13434
14034
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13435
14035
|
temperature: options?.temperature ?? this.config.temperature ?? 0,
|
|
@@ -13458,7 +14058,7 @@ var GeminiProvider = class {
|
|
|
13458
14058
|
}
|
|
13459
14059
|
];
|
|
13460
14060
|
const model = this.client.getGenerativeModel({
|
|
13461
|
-
model: options?.model ?? this.config.model ??
|
|
14061
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13462
14062
|
generationConfig: {
|
|
13463
14063
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13464
14064
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13487,7 +14087,7 @@ var GeminiProvider = class {
|
|
|
13487
14087
|
await this.refreshADCIfNeeded();
|
|
13488
14088
|
try {
|
|
13489
14089
|
const model = this.client.getGenerativeModel({
|
|
13490
|
-
model: options?.model ?? this.config.model ??
|
|
14090
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13491
14091
|
generationConfig: {
|
|
13492
14092
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13493
14093
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13526,7 +14126,7 @@ var GeminiProvider = class {
|
|
|
13526
14126
|
}
|
|
13527
14127
|
];
|
|
13528
14128
|
const model = this.client.getGenerativeModel({
|
|
13529
|
-
model: options?.model ?? this.config.model ??
|
|
14129
|
+
model: options?.model ?? this.config.model ?? DEFAULT_MODEL5,
|
|
13530
14130
|
generationConfig: {
|
|
13531
14131
|
maxOutputTokens: options?.maxTokens ?? this.config.maxTokens ?? 8192,
|
|
13532
14132
|
temperature: options?.temperature ?? this.config.temperature ?? 0
|
|
@@ -13610,8 +14210,8 @@ var GeminiProvider = class {
|
|
|
13610
14210
|
* Get context window size
|
|
13611
14211
|
*/
|
|
13612
14212
|
getContextWindow() {
|
|
13613
|
-
const model = this.config.model ??
|
|
13614
|
-
return
|
|
14213
|
+
const model = this.config.model ?? DEFAULT_MODEL5;
|
|
14214
|
+
return CONTEXT_WINDOWS5[model] ?? 1e6;
|
|
13615
14215
|
}
|
|
13616
14216
|
/**
|
|
13617
14217
|
* Check if provider is available
|
|
@@ -13619,7 +14219,7 @@ var GeminiProvider = class {
|
|
|
13619
14219
|
async isAvailable() {
|
|
13620
14220
|
if (!this.client) return false;
|
|
13621
14221
|
try {
|
|
13622
|
-
const modelName = this.config.model ??
|
|
14222
|
+
const modelName = this.config.model ?? DEFAULT_MODEL5;
|
|
13623
14223
|
const model = this.client.getGenerativeModel({ model: modelName });
|
|
13624
14224
|
await model.generateContent("hi");
|
|
13625
14225
|
return true;
|
|
@@ -13751,7 +14351,7 @@ var GeminiProvider = class {
|
|
|
13751
14351
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
13752
14352
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
13753
14353
|
},
|
|
13754
|
-
model: this.config.model ??
|
|
14354
|
+
model: this.config.model ?? DEFAULT_MODEL5
|
|
13755
14355
|
};
|
|
13756
14356
|
}
|
|
13757
14357
|
/**
|
|
@@ -13786,7 +14386,7 @@ var GeminiProvider = class {
|
|
|
13786
14386
|
inputTokens: usage?.promptTokenCount ?? 0,
|
|
13787
14387
|
outputTokens: usage?.candidatesTokenCount ?? 0
|
|
13788
14388
|
},
|
|
13789
|
-
model: this.config.model ??
|
|
14389
|
+
model: this.config.model ?? DEFAULT_MODEL5,
|
|
13790
14390
|
toolCalls
|
|
13791
14391
|
};
|
|
13792
14392
|
}
|
|
@@ -13820,8 +14420,6 @@ var GeminiProvider = class {
|
|
|
13820
14420
|
});
|
|
13821
14421
|
}
|
|
13822
14422
|
};
|
|
13823
|
-
|
|
13824
|
-
// src/providers/index.ts
|
|
13825
14423
|
init_env();
|
|
13826
14424
|
async function createProvider(type, config = {}) {
|
|
13827
14425
|
let provider;
|
|
@@ -13843,6 +14441,9 @@ async function createProvider(type, config = {}) {
|
|
|
13843
14441
|
case "codex":
|
|
13844
14442
|
provider = new CodexProvider();
|
|
13845
14443
|
break;
|
|
14444
|
+
case "copilot":
|
|
14445
|
+
provider = new CopilotProvider();
|
|
14446
|
+
break;
|
|
13846
14447
|
case "gemini":
|
|
13847
14448
|
provider = new GeminiProvider();
|
|
13848
14449
|
break;
|
|
@@ -14013,9 +14614,9 @@ function createInitialState(config) {
|
|
|
14013
14614
|
}
|
|
14014
14615
|
async function loadExistingState(projectPath) {
|
|
14015
14616
|
try {
|
|
14016
|
-
const
|
|
14617
|
+
const fs38 = await import('fs/promises');
|
|
14017
14618
|
const statePath = `${projectPath}/.coco/state/project.json`;
|
|
14018
|
-
const content = await
|
|
14619
|
+
const content = await fs38.readFile(statePath, "utf-8");
|
|
14019
14620
|
const data = JSON.parse(content);
|
|
14020
14621
|
data.createdAt = new Date(data.createdAt);
|
|
14021
14622
|
data.updatedAt = new Date(data.updatedAt);
|
|
@@ -14025,13 +14626,13 @@ async function loadExistingState(projectPath) {
|
|
|
14025
14626
|
}
|
|
14026
14627
|
}
|
|
14027
14628
|
async function saveState(state) {
|
|
14028
|
-
const
|
|
14629
|
+
const fs38 = await import('fs/promises');
|
|
14029
14630
|
const statePath = `${state.path}/.coco/state`;
|
|
14030
|
-
await
|
|
14631
|
+
await fs38.mkdir(statePath, { recursive: true });
|
|
14031
14632
|
const filePath = `${statePath}/project.json`;
|
|
14032
14633
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
14033
|
-
await
|
|
14034
|
-
await
|
|
14634
|
+
await fs38.writeFile(tmpPath, JSON.stringify(state, null, 2), "utf-8");
|
|
14635
|
+
await fs38.rename(tmpPath, filePath);
|
|
14035
14636
|
}
|
|
14036
14637
|
function getPhaseExecutor(phase) {
|
|
14037
14638
|
switch (phase) {
|
|
@@ -14090,20 +14691,20 @@ async function createPhaseContext(config, state) {
|
|
|
14090
14691
|
};
|
|
14091
14692
|
const tools = {
|
|
14092
14693
|
file: {
|
|
14093
|
-
async read(
|
|
14094
|
-
const
|
|
14095
|
-
return
|
|
14694
|
+
async read(path40) {
|
|
14695
|
+
const fs38 = await import('fs/promises');
|
|
14696
|
+
return fs38.readFile(path40, "utf-8");
|
|
14096
14697
|
},
|
|
14097
|
-
async write(
|
|
14098
|
-
const
|
|
14698
|
+
async write(path40, content) {
|
|
14699
|
+
const fs38 = await import('fs/promises');
|
|
14099
14700
|
const nodePath = await import('path');
|
|
14100
|
-
await
|
|
14101
|
-
await
|
|
14701
|
+
await fs38.mkdir(nodePath.dirname(path40), { recursive: true });
|
|
14702
|
+
await fs38.writeFile(path40, content, "utf-8");
|
|
14102
14703
|
},
|
|
14103
|
-
async exists(
|
|
14104
|
-
const
|
|
14704
|
+
async exists(path40) {
|
|
14705
|
+
const fs38 = await import('fs/promises');
|
|
14105
14706
|
try {
|
|
14106
|
-
await
|
|
14707
|
+
await fs38.access(path40);
|
|
14107
14708
|
return true;
|
|
14108
14709
|
} catch {
|
|
14109
14710
|
return false;
|
|
@@ -14252,9 +14853,9 @@ async function createSnapshot(state) {
|
|
|
14252
14853
|
var MAX_CHECKPOINT_VERSIONS = 5;
|
|
14253
14854
|
async function getCheckpointFiles(state, phase) {
|
|
14254
14855
|
try {
|
|
14255
|
-
const
|
|
14856
|
+
const fs38 = await import('fs/promises');
|
|
14256
14857
|
const checkpointDir = `${state.path}/.coco/checkpoints`;
|
|
14257
|
-
const files = await
|
|
14858
|
+
const files = await fs38.readdir(checkpointDir);
|
|
14258
14859
|
const phaseFiles = files.filter((f) => f.startsWith(`snapshot-pre-${phase}-`) && f.endsWith(".json")).sort((a, b) => {
|
|
14259
14860
|
const tsA = parseInt(a.split("-").pop()?.replace(".json", "") ?? "0", 10);
|
|
14260
14861
|
const tsB = parseInt(b.split("-").pop()?.replace(".json", "") ?? "0", 10);
|
|
@@ -14267,11 +14868,11 @@ async function getCheckpointFiles(state, phase) {
|
|
|
14267
14868
|
}
|
|
14268
14869
|
async function cleanupOldCheckpoints(state, phase) {
|
|
14269
14870
|
try {
|
|
14270
|
-
const
|
|
14871
|
+
const fs38 = await import('fs/promises');
|
|
14271
14872
|
const files = await getCheckpointFiles(state, phase);
|
|
14272
14873
|
if (files.length > MAX_CHECKPOINT_VERSIONS) {
|
|
14273
14874
|
const filesToDelete = files.slice(MAX_CHECKPOINT_VERSIONS);
|
|
14274
|
-
await Promise.all(filesToDelete.map((f) =>
|
|
14875
|
+
await Promise.all(filesToDelete.map((f) => fs38.unlink(f).catch(() => {
|
|
14275
14876
|
})));
|
|
14276
14877
|
}
|
|
14277
14878
|
} catch {
|
|
@@ -14279,13 +14880,13 @@ async function cleanupOldCheckpoints(state, phase) {
|
|
|
14279
14880
|
}
|
|
14280
14881
|
async function saveSnapshot(state, snapshotId) {
|
|
14281
14882
|
try {
|
|
14282
|
-
const
|
|
14883
|
+
const fs38 = await import('fs/promises');
|
|
14283
14884
|
const snapshotPath = `${state.path}/.coco/checkpoints/snapshot-${snapshotId}.json`;
|
|
14284
14885
|
const snapshotDir = `${state.path}/.coco/checkpoints`;
|
|
14285
|
-
await
|
|
14886
|
+
await fs38.mkdir(snapshotDir, { recursive: true });
|
|
14286
14887
|
const createdAt = state.createdAt instanceof Date ? state.createdAt.toISOString() : String(state.createdAt);
|
|
14287
14888
|
const updatedAt = state.updatedAt instanceof Date ? state.updatedAt.toISOString() : String(state.updatedAt);
|
|
14288
|
-
await
|
|
14889
|
+
await fs38.writeFile(
|
|
14289
14890
|
snapshotPath,
|
|
14290
14891
|
JSON.stringify(
|
|
14291
14892
|
{
|
|
@@ -14597,7 +15198,7 @@ async function loadConfig(configPath) {
|
|
|
14597
15198
|
async function loadConfigFile(configPath, options = {}) {
|
|
14598
15199
|
const { strict = true } = options;
|
|
14599
15200
|
try {
|
|
14600
|
-
const content = await
|
|
15201
|
+
const content = await fs16__default.readFile(configPath, "utf-8");
|
|
14601
15202
|
const parsed = JSON5.parse(content);
|
|
14602
15203
|
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
14603
15204
|
if (!strict) {
|
|
@@ -14653,7 +15254,7 @@ function deepMergeConfig(base, override) {
|
|
|
14653
15254
|
};
|
|
14654
15255
|
}
|
|
14655
15256
|
function getProjectConfigPath2() {
|
|
14656
|
-
return
|
|
15257
|
+
return path17__default.join(process.cwd(), ".coco", "config.json");
|
|
14657
15258
|
}
|
|
14658
15259
|
async function saveConfig(config, configPath, global = false) {
|
|
14659
15260
|
const result = CocoConfigSchema.safeParse(config);
|
|
@@ -14668,10 +15269,10 @@ async function saveConfig(config, configPath, global = false) {
|
|
|
14668
15269
|
});
|
|
14669
15270
|
}
|
|
14670
15271
|
const resolvedPath = configPath || (global ? CONFIG_PATHS.config : getProjectConfigPath2());
|
|
14671
|
-
const dir =
|
|
14672
|
-
await
|
|
15272
|
+
const dir = path17__default.dirname(resolvedPath);
|
|
15273
|
+
await fs16__default.mkdir(dir, { recursive: true });
|
|
14673
15274
|
const content = JSON.stringify(result.data, null, 2);
|
|
14674
|
-
await
|
|
15275
|
+
await fs16__default.writeFile(resolvedPath, content, "utf-8");
|
|
14675
15276
|
}
|
|
14676
15277
|
function createDefaultConfig(projectName, language = "typescript") {
|
|
14677
15278
|
return createDefaultConfigObject(projectName, language);
|
|
@@ -14679,7 +15280,7 @@ function createDefaultConfig(projectName, language = "typescript") {
|
|
|
14679
15280
|
async function configExists(configPath, scope = "any") {
|
|
14680
15281
|
if (configPath) {
|
|
14681
15282
|
try {
|
|
14682
|
-
await
|
|
15283
|
+
await fs16__default.access(configPath);
|
|
14683
15284
|
return true;
|
|
14684
15285
|
} catch {
|
|
14685
15286
|
return false;
|
|
@@ -14687,7 +15288,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
14687
15288
|
}
|
|
14688
15289
|
if (scope === "project" || scope === "any") {
|
|
14689
15290
|
try {
|
|
14690
|
-
await
|
|
15291
|
+
await fs16__default.access(getProjectConfigPath2());
|
|
14691
15292
|
return true;
|
|
14692
15293
|
} catch {
|
|
14693
15294
|
if (scope === "project") return false;
|
|
@@ -14695,7 +15296,7 @@ async function configExists(configPath, scope = "any") {
|
|
|
14695
15296
|
}
|
|
14696
15297
|
if (scope === "global" || scope === "any") {
|
|
14697
15298
|
try {
|
|
14698
|
-
await
|
|
15299
|
+
await fs16__default.access(CONFIG_PATHS.config);
|
|
14699
15300
|
return true;
|
|
14700
15301
|
} catch {
|
|
14701
15302
|
return false;
|
|
@@ -14737,15 +15338,15 @@ function levenshtein(a, b) {
|
|
|
14737
15338
|
var MAX_DIR_ENTRIES = 200;
|
|
14738
15339
|
var MAX_SUGGESTIONS = 5;
|
|
14739
15340
|
async function suggestSimilarFiles(missingPath, options) {
|
|
14740
|
-
const absPath =
|
|
14741
|
-
const dir =
|
|
14742
|
-
const target =
|
|
15341
|
+
const absPath = path17__default.resolve(missingPath);
|
|
15342
|
+
const dir = path17__default.dirname(absPath);
|
|
15343
|
+
const target = path17__default.basename(absPath);
|
|
14743
15344
|
const maxResults = MAX_SUGGESTIONS;
|
|
14744
15345
|
try {
|
|
14745
|
-
const entries = await
|
|
15346
|
+
const entries = await fs16__default.readdir(dir);
|
|
14746
15347
|
const limited = entries.slice(0, MAX_DIR_ENTRIES);
|
|
14747
15348
|
const scored = limited.map((name) => ({
|
|
14748
|
-
path:
|
|
15349
|
+
path: path17__default.join(dir, name),
|
|
14749
15350
|
distance: levenshtein(target.toLowerCase(), name.toLowerCase())
|
|
14750
15351
|
})).filter((s) => s.distance <= Math.max(target.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
14751
15352
|
return scored.slice(0, maxResults);
|
|
@@ -14756,15 +15357,15 @@ async function suggestSimilarFiles(missingPath, options) {
|
|
|
14756
15357
|
async function suggestSimilarPaths(missingPath, options) {
|
|
14757
15358
|
const fileSuggestions = await suggestSimilarFiles(missingPath);
|
|
14758
15359
|
if (fileSuggestions.length > 0) return fileSuggestions;
|
|
14759
|
-
const absPath =
|
|
14760
|
-
const grandparent =
|
|
14761
|
-
const parentBasename =
|
|
15360
|
+
const absPath = path17__default.resolve(missingPath);
|
|
15361
|
+
const grandparent = path17__default.dirname(path17__default.dirname(absPath));
|
|
15362
|
+
const parentBasename = path17__default.basename(path17__default.dirname(absPath));
|
|
14762
15363
|
const maxResults = MAX_SUGGESTIONS;
|
|
14763
15364
|
try {
|
|
14764
|
-
const entries = await
|
|
15365
|
+
const entries = await fs16__default.readdir(grandparent, { withFileTypes: true });
|
|
14765
15366
|
const dirs = entries.filter((e) => e.isDirectory()).slice(0, MAX_DIR_ENTRIES);
|
|
14766
15367
|
const scored = dirs.map((d) => ({
|
|
14767
|
-
path:
|
|
15368
|
+
path: path17__default.join(grandparent, d.name),
|
|
14768
15369
|
distance: levenshtein(parentBasename.toLowerCase(), d.name.toLowerCase())
|
|
14769
15370
|
})).filter((s) => s.distance <= Math.max(parentBasename.length * 0.6, 3)).sort((a, b) => a.distance - b.distance);
|
|
14770
15371
|
return scored.slice(0, maxResults);
|
|
@@ -14776,7 +15377,7 @@ function formatSuggestions(suggestions, baseDir) {
|
|
|
14776
15377
|
if (suggestions.length === 0) return "";
|
|
14777
15378
|
const base = baseDir ?? process.cwd();
|
|
14778
15379
|
const lines = suggestions.map((s) => {
|
|
14779
|
-
const rel =
|
|
15380
|
+
const rel = path17__default.relative(base, s.path);
|
|
14780
15381
|
return ` - ${rel}`;
|
|
14781
15382
|
});
|
|
14782
15383
|
return `
|
|
@@ -14809,7 +15410,7 @@ function hasNullByte(str) {
|
|
|
14809
15410
|
}
|
|
14810
15411
|
function normalizePath(filePath) {
|
|
14811
15412
|
let normalized = filePath.replace(/\0/g, "");
|
|
14812
|
-
normalized =
|
|
15413
|
+
normalized = path17__default.normalize(normalized);
|
|
14813
15414
|
return normalized;
|
|
14814
15415
|
}
|
|
14815
15416
|
function isPathAllowed(filePath, operation) {
|
|
@@ -14817,31 +15418,31 @@ function isPathAllowed(filePath, operation) {
|
|
|
14817
15418
|
return { allowed: false, reason: "Path contains invalid characters" };
|
|
14818
15419
|
}
|
|
14819
15420
|
const normalized = normalizePath(filePath);
|
|
14820
|
-
const absolute =
|
|
15421
|
+
const absolute = path17__default.resolve(normalized);
|
|
14821
15422
|
const cwd = process.cwd();
|
|
14822
15423
|
for (const blocked of BLOCKED_PATHS) {
|
|
14823
|
-
const normalizedBlocked =
|
|
14824
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
15424
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
15425
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
14825
15426
|
return { allowed: false, reason: `Access to system path '${blocked}' is not allowed` };
|
|
14826
15427
|
}
|
|
14827
15428
|
}
|
|
14828
15429
|
const home = process.env.HOME;
|
|
14829
15430
|
if (home) {
|
|
14830
|
-
const normalizedHome =
|
|
14831
|
-
const normalizedCwd =
|
|
15431
|
+
const normalizedHome = path17__default.normalize(home);
|
|
15432
|
+
const normalizedCwd = path17__default.normalize(cwd);
|
|
14832
15433
|
if (absolute.startsWith(normalizedHome) && !absolute.startsWith(normalizedCwd)) {
|
|
14833
15434
|
if (isWithinAllowedPath(absolute, operation)) ; else if (operation === "read") {
|
|
14834
15435
|
const allowedHomeReads = [".gitconfig", ".zshrc", ".bashrc"];
|
|
14835
|
-
const basename5 =
|
|
15436
|
+
const basename5 = path17__default.basename(absolute);
|
|
14836
15437
|
if (!allowedHomeReads.includes(basename5)) {
|
|
14837
|
-
const targetDir =
|
|
15438
|
+
const targetDir = path17__default.dirname(absolute);
|
|
14838
15439
|
return {
|
|
14839
15440
|
allowed: false,
|
|
14840
15441
|
reason: `Reading files outside project directory is not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
14841
15442
|
};
|
|
14842
15443
|
}
|
|
14843
15444
|
} else {
|
|
14844
|
-
const targetDir =
|
|
15445
|
+
const targetDir = path17__default.dirname(absolute);
|
|
14845
15446
|
return {
|
|
14846
15447
|
allowed: false,
|
|
14847
15448
|
reason: `${operation} operations outside project directory are not allowed. Use /allow-path ${targetDir} to grant access.`
|
|
@@ -14850,7 +15451,7 @@ function isPathAllowed(filePath, operation) {
|
|
|
14850
15451
|
}
|
|
14851
15452
|
}
|
|
14852
15453
|
if (operation === "write" || operation === "delete") {
|
|
14853
|
-
const basename5 =
|
|
15454
|
+
const basename5 = path17__default.basename(absolute);
|
|
14854
15455
|
for (const pattern of SENSITIVE_PATTERNS) {
|
|
14855
15456
|
if (pattern.test(basename5)) {
|
|
14856
15457
|
return {
|
|
@@ -14873,17 +15474,17 @@ function isENOENT(error) {
|
|
|
14873
15474
|
return error.code === "ENOENT";
|
|
14874
15475
|
}
|
|
14875
15476
|
async function enrichENOENT(filePath, operation) {
|
|
14876
|
-
const absPath =
|
|
15477
|
+
const absPath = path17__default.resolve(filePath);
|
|
14877
15478
|
const suggestions = await suggestSimilarFiles(absPath);
|
|
14878
|
-
const hint = formatSuggestions(suggestions,
|
|
15479
|
+
const hint = formatSuggestions(suggestions, path17__default.dirname(absPath));
|
|
14879
15480
|
const action = operation === "read" ? "Use glob or list_dir to find the correct path." : "Check that the parent directory exists.";
|
|
14880
15481
|
return `File not found: ${filePath}${hint}
|
|
14881
15482
|
${action}`;
|
|
14882
15483
|
}
|
|
14883
15484
|
async function enrichDirENOENT(dirPath) {
|
|
14884
|
-
const absPath =
|
|
15485
|
+
const absPath = path17__default.resolve(dirPath);
|
|
14885
15486
|
const suggestions = await suggestSimilarPaths(absPath);
|
|
14886
|
-
const hint = formatSuggestions(suggestions,
|
|
15487
|
+
const hint = formatSuggestions(suggestions, path17__default.dirname(absPath));
|
|
14887
15488
|
return `Directory not found: ${dirPath}${hint}
|
|
14888
15489
|
Use list_dir or glob to find the correct path.`;
|
|
14889
15490
|
}
|
|
@@ -14904,13 +15505,13 @@ Examples:
|
|
|
14904
15505
|
async execute({ path: filePath, encoding, maxSize }) {
|
|
14905
15506
|
validatePath(filePath, "read");
|
|
14906
15507
|
try {
|
|
14907
|
-
const absolutePath =
|
|
14908
|
-
const stats = await
|
|
15508
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15509
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
14909
15510
|
const maxBytes = maxSize ?? DEFAULT_MAX_FILE_SIZE;
|
|
14910
15511
|
let truncated = false;
|
|
14911
15512
|
let content;
|
|
14912
15513
|
if (stats.size > maxBytes) {
|
|
14913
|
-
const handle = await
|
|
15514
|
+
const handle = await fs16__default.open(absolutePath, "r");
|
|
14914
15515
|
try {
|
|
14915
15516
|
const buffer = Buffer.alloc(maxBytes);
|
|
14916
15517
|
await handle.read(buffer, 0, maxBytes, 0);
|
|
@@ -14920,7 +15521,7 @@ Examples:
|
|
|
14920
15521
|
await handle.close();
|
|
14921
15522
|
}
|
|
14922
15523
|
} else {
|
|
14923
|
-
content = await
|
|
15524
|
+
content = await fs16__default.readFile(absolutePath, encoding);
|
|
14924
15525
|
}
|
|
14925
15526
|
return {
|
|
14926
15527
|
content,
|
|
@@ -14963,10 +15564,10 @@ Examples:
|
|
|
14963
15564
|
async execute({ path: filePath, content, createDirs, dryRun }) {
|
|
14964
15565
|
validatePath(filePath, "write");
|
|
14965
15566
|
try {
|
|
14966
|
-
const absolutePath =
|
|
15567
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
14967
15568
|
let wouldCreate = false;
|
|
14968
15569
|
try {
|
|
14969
|
-
await
|
|
15570
|
+
await fs16__default.access(absolutePath);
|
|
14970
15571
|
} catch {
|
|
14971
15572
|
wouldCreate = true;
|
|
14972
15573
|
}
|
|
@@ -14979,10 +15580,10 @@ Examples:
|
|
|
14979
15580
|
};
|
|
14980
15581
|
}
|
|
14981
15582
|
if (createDirs) {
|
|
14982
|
-
await
|
|
15583
|
+
await fs16__default.mkdir(path17__default.dirname(absolutePath), { recursive: true });
|
|
14983
15584
|
}
|
|
14984
|
-
await
|
|
14985
|
-
const stats = await
|
|
15585
|
+
await fs16__default.writeFile(absolutePath, content, "utf-8");
|
|
15586
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
14986
15587
|
return {
|
|
14987
15588
|
path: absolutePath,
|
|
14988
15589
|
size: stats.size,
|
|
@@ -15025,8 +15626,8 @@ Examples:
|
|
|
15025
15626
|
async execute({ path: filePath, oldText, newText, all, dryRun }) {
|
|
15026
15627
|
validatePath(filePath, "write");
|
|
15027
15628
|
try {
|
|
15028
|
-
const absolutePath =
|
|
15029
|
-
let content = await
|
|
15629
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15630
|
+
let content = await fs16__default.readFile(absolutePath, "utf-8");
|
|
15030
15631
|
let replacements = 0;
|
|
15031
15632
|
if (all) {
|
|
15032
15633
|
const regex = new RegExp(escapeRegex(oldText), "g");
|
|
@@ -15075,7 +15676,7 @@ Hint: Use read_file first to verify the exact content.`
|
|
|
15075
15676
|
preview
|
|
15076
15677
|
};
|
|
15077
15678
|
}
|
|
15078
|
-
await
|
|
15679
|
+
await fs16__default.writeFile(absolutePath, content, "utf-8");
|
|
15079
15680
|
return {
|
|
15080
15681
|
path: absolutePath,
|
|
15081
15682
|
replacements,
|
|
@@ -15146,8 +15747,8 @@ Examples:
|
|
|
15146
15747
|
}),
|
|
15147
15748
|
async execute({ path: filePath }) {
|
|
15148
15749
|
try {
|
|
15149
|
-
const absolutePath =
|
|
15150
|
-
const stats = await
|
|
15750
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15751
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
15151
15752
|
return {
|
|
15152
15753
|
exists: true,
|
|
15153
15754
|
isFile: stats.isFile(),
|
|
@@ -15177,12 +15778,12 @@ Examples:
|
|
|
15177
15778
|
}),
|
|
15178
15779
|
async execute({ path: dirPath, recursive }) {
|
|
15179
15780
|
try {
|
|
15180
|
-
const absolutePath =
|
|
15781
|
+
const absolutePath = path17__default.resolve(dirPath);
|
|
15181
15782
|
const entries = [];
|
|
15182
15783
|
async function listDir(dir, prefix = "") {
|
|
15183
|
-
const items = await
|
|
15784
|
+
const items = await fs16__default.readdir(dir, { withFileTypes: true });
|
|
15184
15785
|
for (const item of items) {
|
|
15185
|
-
const fullPath =
|
|
15786
|
+
const fullPath = path17__default.join(dir, item.name);
|
|
15186
15787
|
const relativePath = prefix ? `${prefix}/${item.name}` : item.name;
|
|
15187
15788
|
if (item.isDirectory()) {
|
|
15188
15789
|
entries.push({ name: relativePath, type: "directory" });
|
|
@@ -15190,7 +15791,7 @@ Examples:
|
|
|
15190
15791
|
await listDir(fullPath, relativePath);
|
|
15191
15792
|
}
|
|
15192
15793
|
} else if (item.isFile()) {
|
|
15193
|
-
const stats = await
|
|
15794
|
+
const stats = await fs16__default.stat(fullPath);
|
|
15194
15795
|
entries.push({ name: relativePath, type: "file", size: stats.size });
|
|
15195
15796
|
}
|
|
15196
15797
|
}
|
|
@@ -15237,23 +15838,23 @@ Examples:
|
|
|
15237
15838
|
}
|
|
15238
15839
|
validatePath(filePath, "delete");
|
|
15239
15840
|
try {
|
|
15240
|
-
const absolutePath =
|
|
15241
|
-
const stats = await
|
|
15841
|
+
const absolutePath = path17__default.resolve(filePath);
|
|
15842
|
+
const stats = await fs16__default.stat(absolutePath);
|
|
15242
15843
|
if (stats.isDirectory()) {
|
|
15243
15844
|
if (!recursive) {
|
|
15244
15845
|
throw new ToolError("Cannot delete directory without recursive: true", {
|
|
15245
15846
|
tool: "delete_file"
|
|
15246
15847
|
});
|
|
15247
15848
|
}
|
|
15248
|
-
await
|
|
15849
|
+
await fs16__default.rm(absolutePath, { recursive: true });
|
|
15249
15850
|
} else {
|
|
15250
|
-
await
|
|
15851
|
+
await fs16__default.unlink(absolutePath);
|
|
15251
15852
|
}
|
|
15252
15853
|
return { deleted: true, path: absolutePath };
|
|
15253
15854
|
} catch (error) {
|
|
15254
15855
|
if (error instanceof ToolError) throw error;
|
|
15255
15856
|
if (error.code === "ENOENT") {
|
|
15256
|
-
return { deleted: false, path:
|
|
15857
|
+
return { deleted: false, path: path17__default.resolve(filePath) };
|
|
15257
15858
|
}
|
|
15258
15859
|
throw new FileSystemError(`Failed to delete: ${filePath}`, {
|
|
15259
15860
|
path: filePath,
|
|
@@ -15281,11 +15882,11 @@ Examples:
|
|
|
15281
15882
|
validatePath(source, "read");
|
|
15282
15883
|
validatePath(destination, "write");
|
|
15283
15884
|
try {
|
|
15284
|
-
const srcPath =
|
|
15285
|
-
const destPath =
|
|
15885
|
+
const srcPath = path17__default.resolve(source);
|
|
15886
|
+
const destPath = path17__default.resolve(destination);
|
|
15286
15887
|
if (!overwrite) {
|
|
15287
15888
|
try {
|
|
15288
|
-
await
|
|
15889
|
+
await fs16__default.access(destPath);
|
|
15289
15890
|
throw new ToolError(
|
|
15290
15891
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
15291
15892
|
{
|
|
@@ -15298,9 +15899,9 @@ Examples:
|
|
|
15298
15899
|
}
|
|
15299
15900
|
}
|
|
15300
15901
|
}
|
|
15301
|
-
await
|
|
15302
|
-
await
|
|
15303
|
-
const stats = await
|
|
15902
|
+
await fs16__default.mkdir(path17__default.dirname(destPath), { recursive: true });
|
|
15903
|
+
await fs16__default.copyFile(srcPath, destPath);
|
|
15904
|
+
const stats = await fs16__default.stat(destPath);
|
|
15304
15905
|
return {
|
|
15305
15906
|
source: srcPath,
|
|
15306
15907
|
destination: destPath,
|
|
@@ -15342,11 +15943,11 @@ Examples:
|
|
|
15342
15943
|
validatePath(source, "delete");
|
|
15343
15944
|
validatePath(destination, "write");
|
|
15344
15945
|
try {
|
|
15345
|
-
const srcPath =
|
|
15346
|
-
const destPath =
|
|
15946
|
+
const srcPath = path17__default.resolve(source);
|
|
15947
|
+
const destPath = path17__default.resolve(destination);
|
|
15347
15948
|
if (!overwrite) {
|
|
15348
15949
|
try {
|
|
15349
|
-
await
|
|
15950
|
+
await fs16__default.access(destPath);
|
|
15350
15951
|
throw new ToolError(
|
|
15351
15952
|
`Destination already exists: ${destination}. Use overwrite: true to replace.`,
|
|
15352
15953
|
{
|
|
@@ -15359,8 +15960,8 @@ Examples:
|
|
|
15359
15960
|
}
|
|
15360
15961
|
}
|
|
15361
15962
|
}
|
|
15362
|
-
await
|
|
15363
|
-
await
|
|
15963
|
+
await fs16__default.mkdir(path17__default.dirname(destPath), { recursive: true });
|
|
15964
|
+
await fs16__default.rename(srcPath, destPath);
|
|
15364
15965
|
return {
|
|
15365
15966
|
source: srcPath,
|
|
15366
15967
|
destination: destPath
|
|
@@ -15402,13 +16003,13 @@ Examples:
|
|
|
15402
16003
|
}),
|
|
15403
16004
|
async execute({ path: dirPath, depth, showHidden, dirsOnly }) {
|
|
15404
16005
|
try {
|
|
15405
|
-
const absolutePath =
|
|
16006
|
+
const absolutePath = path17__default.resolve(dirPath ?? ".");
|
|
15406
16007
|
let totalFiles = 0;
|
|
15407
16008
|
let totalDirs = 0;
|
|
15408
|
-
const lines = [
|
|
16009
|
+
const lines = [path17__default.basename(absolutePath) + "/"];
|
|
15409
16010
|
async function buildTree(dir, prefix, currentDepth) {
|
|
15410
16011
|
if (currentDepth > (depth ?? 4)) return;
|
|
15411
|
-
let items = await
|
|
16012
|
+
let items = await fs16__default.readdir(dir, { withFileTypes: true });
|
|
15412
16013
|
if (!showHidden) {
|
|
15413
16014
|
items = items.filter((item) => !item.name.startsWith("."));
|
|
15414
16015
|
}
|
|
@@ -15428,7 +16029,7 @@ Examples:
|
|
|
15428
16029
|
if (item.isDirectory()) {
|
|
15429
16030
|
totalDirs++;
|
|
15430
16031
|
lines.push(`${prefix}${connector}${item.name}/`);
|
|
15431
|
-
await buildTree(
|
|
16032
|
+
await buildTree(path17__default.join(dir, item.name), prefix + childPrefix, currentDepth + 1);
|
|
15432
16033
|
} else {
|
|
15433
16034
|
totalFiles++;
|
|
15434
16035
|
lines.push(`${prefix}${connector}${item.name}`);
|
|
@@ -15968,9 +16569,9 @@ Examples:
|
|
|
15968
16569
|
if (file) {
|
|
15969
16570
|
options.file = file;
|
|
15970
16571
|
}
|
|
15971
|
-
const
|
|
16572
|
+
const log3 = await git.log(options);
|
|
15972
16573
|
return {
|
|
15973
|
-
commits:
|
|
16574
|
+
commits: log3.all.map((commit) => ({
|
|
15974
16575
|
hash: commit.hash,
|
|
15975
16576
|
message: commit.message,
|
|
15976
16577
|
author: commit.author_name,
|
|
@@ -16282,6 +16883,34 @@ var simpleAutoCommitTool = defineTool({
|
|
|
16282
16883
|
}
|
|
16283
16884
|
});
|
|
16284
16885
|
var gitSimpleTools = [checkProtectedBranchTool, simpleAutoCommitTool];
|
|
16886
|
+
var AGENT_NAMES = {
|
|
16887
|
+
explore: "Explorer",
|
|
16888
|
+
plan: "Planner",
|
|
16889
|
+
test: "Tester",
|
|
16890
|
+
debug: "Debugger",
|
|
16891
|
+
review: "Reviewer",
|
|
16892
|
+
architect: "Architect",
|
|
16893
|
+
security: "Security Auditor",
|
|
16894
|
+
tdd: "TDD Guide",
|
|
16895
|
+
refactor: "Refactorer",
|
|
16896
|
+
e2e: "E2E Tester",
|
|
16897
|
+
docs: "Docs Writer",
|
|
16898
|
+
database: "Database Engineer"
|
|
16899
|
+
};
|
|
16900
|
+
var AGENT_DESCRIPTIONS = {
|
|
16901
|
+
explore: "Search the codebase to answer questions and gather information",
|
|
16902
|
+
plan: "Design implementation approaches and create detailed plans",
|
|
16903
|
+
test: "Write and run tests to ensure code quality",
|
|
16904
|
+
debug: "Analyze errors and fix issues",
|
|
16905
|
+
review: "Review code for quality and best practices",
|
|
16906
|
+
architect: "Design system architecture and create architectural decision records",
|
|
16907
|
+
security: "Audit code for security vulnerabilities using OWASP Top 10",
|
|
16908
|
+
tdd: "Drive development with test-first methodology and RED-GREEN-REFACTOR cycle",
|
|
16909
|
+
refactor: "Improve code structure and quality without changing behavior",
|
|
16910
|
+
e2e: "Write and run end-to-end tests covering full user workflows",
|
|
16911
|
+
docs: "Generate and maintain documentation for code, APIs, and architecture",
|
|
16912
|
+
database: "Design database schemas, write migrations, and optimize queries"
|
|
16913
|
+
};
|
|
16285
16914
|
|
|
16286
16915
|
// src/agents/provider-bridge.ts
|
|
16287
16916
|
var agentProvider = null;
|
|
@@ -16292,103 +16921,80 @@ function getAgentProvider() {
|
|
|
16292
16921
|
function getAgentToolRegistry() {
|
|
16293
16922
|
return agentToolRegistry;
|
|
16294
16923
|
}
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
systemPrompt: `You are a code researcher agent. Your role is to:
|
|
16299
|
-
- Explore and understand existing codebases
|
|
16300
|
-
- Find relevant code patterns and examples
|
|
16301
|
-
- Identify dependencies and relationships
|
|
16302
|
-
- Document your findings clearly
|
|
16303
|
-
|
|
16304
|
-
Use tools to search, read files, and analyze code structure.`,
|
|
16305
|
-
allowedTools: ["read_file", "grep", "find_in_file", "glob", "codebase_map"]
|
|
16306
|
-
},
|
|
16307
|
-
coder: {
|
|
16308
|
-
role: "coder",
|
|
16309
|
-
systemPrompt: `You are a code generation agent. Your role is to:
|
|
16310
|
-
- Write high-quality, production-ready code
|
|
16311
|
-
- Follow best practices and coding standards
|
|
16312
|
-
- Ensure code is syntactically valid
|
|
16313
|
-
- Write clean, maintainable code
|
|
16314
|
-
|
|
16315
|
-
Use tools to read existing code, write new files, and validate syntax.`,
|
|
16316
|
-
allowedTools: ["read_file", "write_file", "edit_file", "bash_exec", "validateCode"]
|
|
16317
|
-
},
|
|
16318
|
-
tester: {
|
|
16319
|
-
role: "tester",
|
|
16320
|
-
systemPrompt: `You are a test generation agent. Your role is to:
|
|
16321
|
-
- Write comprehensive test suites
|
|
16322
|
-
- Achieve high code coverage
|
|
16323
|
-
- Test edge cases and error conditions
|
|
16324
|
-
- Ensure tests are reliable and maintainable
|
|
16325
|
-
|
|
16326
|
-
Use tools to read code, write tests, and run them.`,
|
|
16327
|
-
allowedTools: ["read_file", "write_file", "run_tests", "get_coverage", "run_test_file"]
|
|
16328
|
-
},
|
|
16329
|
-
reviewer: {
|
|
16330
|
-
role: "reviewer",
|
|
16331
|
-
systemPrompt: `You are a code review agent. Your role is to:
|
|
16332
|
-
- Identify code quality issues
|
|
16333
|
-
- Check for security vulnerabilities
|
|
16334
|
-
- Ensure best practices are followed
|
|
16335
|
-
- Provide actionable feedback
|
|
16336
|
-
|
|
16337
|
-
Use tools to read and analyze code quality.`,
|
|
16338
|
-
allowedTools: ["read_file", "calculate_quality", "analyze_complexity", "grep"]
|
|
16339
|
-
},
|
|
16340
|
-
optimizer: {
|
|
16341
|
-
role: "optimizer",
|
|
16342
|
-
systemPrompt: `You are a code optimization agent. Your role is to:
|
|
16343
|
-
- Reduce code complexity
|
|
16344
|
-
- Eliminate duplication
|
|
16345
|
-
- Improve performance
|
|
16346
|
-
- Refactor for maintainability
|
|
16347
|
-
|
|
16348
|
-
Use tools to analyze and improve code.`,
|
|
16349
|
-
allowedTools: ["read_file", "write_file", "edit_file", "analyze_complexity", "grep"]
|
|
16350
|
-
},
|
|
16351
|
-
planner: {
|
|
16352
|
-
role: "planner",
|
|
16353
|
-
systemPrompt: `You are a task planning agent. Your role is to:
|
|
16354
|
-
- Break down complex tasks into subtasks
|
|
16355
|
-
- Identify dependencies between tasks
|
|
16356
|
-
- Estimate complexity and effort
|
|
16357
|
-
- Create actionable plans
|
|
16358
|
-
|
|
16359
|
-
Use tools to analyze requirements and explore the codebase.`,
|
|
16360
|
-
allowedTools: ["read_file", "grep", "glob", "codebase_map"]
|
|
16924
|
+
function getAgentManager() {
|
|
16925
|
+
{
|
|
16926
|
+
return null;
|
|
16361
16927
|
}
|
|
16362
|
-
}
|
|
16928
|
+
}
|
|
16363
16929
|
|
|
16364
16930
|
// src/tools/simple-agent.ts
|
|
16931
|
+
var AGENT_TYPES = [
|
|
16932
|
+
"explore",
|
|
16933
|
+
"plan",
|
|
16934
|
+
"test",
|
|
16935
|
+
"debug",
|
|
16936
|
+
"review",
|
|
16937
|
+
"architect",
|
|
16938
|
+
"security",
|
|
16939
|
+
"tdd",
|
|
16940
|
+
"refactor",
|
|
16941
|
+
"e2e",
|
|
16942
|
+
"docs",
|
|
16943
|
+
"database"
|
|
16944
|
+
];
|
|
16945
|
+
var LEGACY_ROLE_MAP = {
|
|
16946
|
+
researcher: "explore",
|
|
16947
|
+
coder: "debug",
|
|
16948
|
+
// "debug" has write + bash + read — closest to general coding
|
|
16949
|
+
tester: "test",
|
|
16950
|
+
reviewer: "review",
|
|
16951
|
+
optimizer: "refactor",
|
|
16952
|
+
planner: "plan"
|
|
16953
|
+
};
|
|
16365
16954
|
var SpawnSimpleAgentSchema = z.object({
|
|
16366
16955
|
task: z.string().describe("Task description for the sub-agent"),
|
|
16367
16956
|
context: z.string().optional().describe("Additional context or instructions for the agent"),
|
|
16368
|
-
|
|
16957
|
+
type: z.enum(AGENT_TYPES).optional().describe(
|
|
16958
|
+
"Specialized agent type. Use 'explore' for codebase search, 'plan' for design, 'test' for testing, 'review' for code review, 'architect' for system design, 'security' for security audit, 'tdd' for test-driven development, 'debug' for debugging, 'refactor' for code improvement, 'e2e' for integration tests, 'docs' for documentation, 'database' for DB operations."
|
|
16959
|
+
),
|
|
16960
|
+
role: z.enum(["researcher", "coder", "tester", "reviewer", "optimizer", "planner"]).optional().describe("DEPRECATED: Use 'type' instead. Legacy role name, mapped to new agent types."),
|
|
16369
16961
|
maxTurns: z.number().default(10).describe("Maximum tool-use turns for the agent")
|
|
16370
16962
|
});
|
|
16963
|
+
function resolveAgentType(input) {
|
|
16964
|
+
if (input.type) return input.type;
|
|
16965
|
+
if (input.role && input.role in LEGACY_ROLE_MAP) return LEGACY_ROLE_MAP[input.role];
|
|
16966
|
+
return "explore";
|
|
16967
|
+
}
|
|
16371
16968
|
var spawnSimpleAgentTool = defineTool({
|
|
16372
16969
|
name: "spawnSimpleAgent",
|
|
16373
|
-
description: `Spawn a sub-agent to handle a specific task
|
|
16374
|
-
|
|
16375
|
-
|
|
16376
|
-
-
|
|
16377
|
-
-
|
|
16378
|
-
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16970
|
+
description: `Spawn a specialized sub-agent to handle a specific task autonomously.
|
|
16971
|
+
|
|
16972
|
+
Available agent types:
|
|
16973
|
+
- explore: Search and understand codebases (read-only, fast)
|
|
16974
|
+
- plan: Design implementation approaches (read-only)
|
|
16975
|
+
- test: Write and run tests
|
|
16976
|
+
- debug: Analyze errors and fix issues
|
|
16977
|
+
- review: Review code for quality and best practices (read-only)
|
|
16978
|
+
- architect: Design system architecture (read-only)
|
|
16979
|
+
- security: Audit code for security vulnerabilities (read-only)
|
|
16980
|
+
- tdd: Test-driven development with RED-GREEN-REFACTOR
|
|
16981
|
+
- refactor: Improve code structure without changing behavior
|
|
16982
|
+
- e2e: End-to-end integration testing
|
|
16983
|
+
- docs: Generate and maintain documentation
|
|
16984
|
+
- database: Design schemas, migrations, and optimize queries
|
|
16985
|
+
|
|
16986
|
+
Each type has a filtered set of tools appropriate for its role.
|
|
16987
|
+
Use 'explore' for quick codebase searches, 'plan' for design before execution.`,
|
|
16383
16988
|
category: "build",
|
|
16384
16989
|
parameters: SpawnSimpleAgentSchema,
|
|
16385
16990
|
async execute(input) {
|
|
16386
16991
|
const typedInput = input;
|
|
16387
|
-
|
|
16388
|
-
|
|
16992
|
+
const manager = getAgentManager();
|
|
16993
|
+
if (!manager) {
|
|
16994
|
+
const agentId = `agent-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
16389
16995
|
return {
|
|
16390
16996
|
stdout: JSON.stringify({
|
|
16391
|
-
agentId
|
|
16997
|
+
agentId,
|
|
16392
16998
|
status: "unavailable",
|
|
16393
16999
|
task: typedInput.task,
|
|
16394
17000
|
message: "Agent provider not initialized. Call setAgentProvider() during orchestrator startup.",
|
|
@@ -16399,6 +17005,31 @@ Example: "Write unit tests for the authentication module"`,
|
|
|
16399
17005
|
duration: 0
|
|
16400
17006
|
};
|
|
16401
17007
|
}
|
|
17008
|
+
const agentType = resolveAgentType(typedInput);
|
|
17009
|
+
const taskDescription = typedInput.context ? `${typedInput.task}
|
|
17010
|
+
|
|
17011
|
+
Additional context: ${typedInput.context}` : typedInput.task;
|
|
17012
|
+
const startTime = Date.now();
|
|
17013
|
+
const result = await manager.spawn(agentType, taskDescription, {
|
|
17014
|
+
timeout: typedInput.maxTurns * 6e4
|
|
17015
|
+
// rough estimate: 1 min per turn
|
|
17016
|
+
});
|
|
17017
|
+
const duration = Date.now() - startTime;
|
|
17018
|
+
return {
|
|
17019
|
+
stdout: JSON.stringify({
|
|
17020
|
+
agentId: result.agent.id,
|
|
17021
|
+
agentType,
|
|
17022
|
+
status: result.success ? "completed" : "failed",
|
|
17023
|
+
task: typedInput.task,
|
|
17024
|
+
output: result.output,
|
|
17025
|
+
success: result.success,
|
|
17026
|
+
usage: result.usage,
|
|
17027
|
+
duration
|
|
17028
|
+
}),
|
|
17029
|
+
stderr: "",
|
|
17030
|
+
exitCode: result.success ? 0 : 1,
|
|
17031
|
+
duration
|
|
17032
|
+
};
|
|
16402
17033
|
}
|
|
16403
17034
|
});
|
|
16404
17035
|
var checkAgentCapabilityTool = defineTool({
|
|
@@ -16410,17 +17041,23 @@ var checkAgentCapabilityTool = defineTool({
|
|
|
16410
17041
|
const provider = getAgentProvider();
|
|
16411
17042
|
const toolRegistry = getAgentToolRegistry();
|
|
16412
17043
|
const isReady = provider !== null;
|
|
17044
|
+
const agentTypes = Object.entries(AGENT_DESCRIPTIONS).map(([type, description]) => ({
|
|
17045
|
+
type,
|
|
17046
|
+
name: AGENT_NAMES[type],
|
|
17047
|
+
description
|
|
17048
|
+
}));
|
|
16413
17049
|
return {
|
|
16414
17050
|
stdout: JSON.stringify({
|
|
16415
17051
|
multiAgentSupported: true,
|
|
16416
17052
|
providerConfigured: provider !== null,
|
|
16417
17053
|
toolRegistryConfigured: toolRegistry !== null,
|
|
16418
17054
|
ready: isReady,
|
|
16419
|
-
|
|
17055
|
+
availableTypes: agentTypes,
|
|
16420
17056
|
features: {
|
|
16421
17057
|
taskDelegation: "requires provider initialization",
|
|
16422
17058
|
parallelSpawn: "requires provider initialization",
|
|
16423
|
-
multiTurnToolUse: "requires provider initialization"
|
|
17059
|
+
multiTurnToolUse: "requires provider initialization",
|
|
17060
|
+
specializedAgents: "requires provider initialization"
|
|
16424
17061
|
},
|
|
16425
17062
|
status: "Provider not initialized. Call setAgentProvider() during startup."
|
|
16426
17063
|
}),
|
|
@@ -16433,8 +17070,8 @@ var checkAgentCapabilityTool = defineTool({
|
|
|
16433
17070
|
var simpleAgentTools = [spawnSimpleAgentTool, checkAgentCapabilityTool];
|
|
16434
17071
|
async function detectTestFramework2(cwd) {
|
|
16435
17072
|
try {
|
|
16436
|
-
const pkgPath =
|
|
16437
|
-
const pkgContent = await
|
|
17073
|
+
const pkgPath = path17__default.join(cwd, "package.json");
|
|
17074
|
+
const pkgContent = await fs16__default.readFile(pkgPath, "utf-8");
|
|
16438
17075
|
const pkg = JSON.parse(pkgContent);
|
|
16439
17076
|
const deps = {
|
|
16440
17077
|
...pkg.dependencies,
|
|
@@ -16615,13 +17252,13 @@ Examples:
|
|
|
16615
17252
|
const projectDir = cwd ?? process.cwd();
|
|
16616
17253
|
try {
|
|
16617
17254
|
const coverageLocations = [
|
|
16618
|
-
|
|
16619
|
-
|
|
16620
|
-
|
|
17255
|
+
path17__default.join(projectDir, "coverage", "coverage-summary.json"),
|
|
17256
|
+
path17__default.join(projectDir, "coverage", "coverage-final.json"),
|
|
17257
|
+
path17__default.join(projectDir, ".nyc_output", "coverage-summary.json")
|
|
16621
17258
|
];
|
|
16622
17259
|
for (const location of coverageLocations) {
|
|
16623
17260
|
try {
|
|
16624
|
-
const content = await
|
|
17261
|
+
const content = await fs16__default.readFile(location, "utf-8");
|
|
16625
17262
|
const coverage = JSON.parse(content);
|
|
16626
17263
|
if (coverage.total) {
|
|
16627
17264
|
return {
|
|
@@ -16674,8 +17311,8 @@ Examples:
|
|
|
16674
17311
|
var testTools = [runTestsTool, getCoverageTool, runTestFileTool];
|
|
16675
17312
|
async function detectLinter2(cwd) {
|
|
16676
17313
|
try {
|
|
16677
|
-
const pkgPath =
|
|
16678
|
-
const pkgContent = await
|
|
17314
|
+
const pkgPath = path17__default.join(cwd, "package.json");
|
|
17315
|
+
const pkgContent = await fs16__default.readFile(pkgPath, "utf-8");
|
|
16679
17316
|
const pkg = JSON.parse(pkgContent);
|
|
16680
17317
|
const deps = {
|
|
16681
17318
|
...pkg.dependencies,
|
|
@@ -16833,7 +17470,7 @@ Examples:
|
|
|
16833
17470
|
let totalFunctions = 0;
|
|
16834
17471
|
let complexFunctions = 0;
|
|
16835
17472
|
for (const file of targetFiles) {
|
|
16836
|
-
const content = await
|
|
17473
|
+
const content = await fs16__default.readFile(file, "utf-8");
|
|
16837
17474
|
const fileComplexity = analyzeFileComplexity(content, file);
|
|
16838
17475
|
fileResults.push(fileComplexity);
|
|
16839
17476
|
totalComplexity += fileComplexity.complexity;
|
|
@@ -16984,7 +17621,7 @@ Examples:
|
|
|
16984
17621
|
caseSensitive,
|
|
16985
17622
|
wholeWord
|
|
16986
17623
|
}) {
|
|
16987
|
-
const targetPath = searchPath ?
|
|
17624
|
+
const targetPath = searchPath ? path17__default.resolve(searchPath) : process.cwd();
|
|
16988
17625
|
const matches = [];
|
|
16989
17626
|
let filesSearched = 0;
|
|
16990
17627
|
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
@@ -17006,7 +17643,7 @@ Examples:
|
|
|
17006
17643
|
tool: "grep"
|
|
17007
17644
|
});
|
|
17008
17645
|
}
|
|
17009
|
-
const stats = await
|
|
17646
|
+
const stats = await fs16__default.stat(targetPath);
|
|
17010
17647
|
let filesToSearch;
|
|
17011
17648
|
if (stats.isFile()) {
|
|
17012
17649
|
filesToSearch = [targetPath];
|
|
@@ -17028,7 +17665,7 @@ Examples:
|
|
|
17028
17665
|
}
|
|
17029
17666
|
filesSearched++;
|
|
17030
17667
|
try {
|
|
17031
|
-
const content = await
|
|
17668
|
+
const content = await fs16__default.readFile(file, "utf-8");
|
|
17032
17669
|
const lines = content.split("\n");
|
|
17033
17670
|
let fileHasMatch = false;
|
|
17034
17671
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -17051,7 +17688,7 @@ Examples:
|
|
|
17051
17688
|
contextAfter.push(lines[j] ?? "");
|
|
17052
17689
|
}
|
|
17053
17690
|
matches.push({
|
|
17054
|
-
file:
|
|
17691
|
+
file: path17__default.relative(process.cwd(), file),
|
|
17055
17692
|
line: i + 1,
|
|
17056
17693
|
column: match.index + 1,
|
|
17057
17694
|
content: line,
|
|
@@ -17102,8 +17739,8 @@ Examples:
|
|
|
17102
17739
|
}),
|
|
17103
17740
|
async execute({ file, pattern, caseSensitive }) {
|
|
17104
17741
|
try {
|
|
17105
|
-
const absolutePath =
|
|
17106
|
-
const content = await
|
|
17742
|
+
const absolutePath = path17__default.resolve(file);
|
|
17743
|
+
const content = await fs16__default.readFile(absolutePath, "utf-8");
|
|
17107
17744
|
const lines = content.split("\n");
|
|
17108
17745
|
const matches = [];
|
|
17109
17746
|
const flags = caseSensitive ? "" : "i";
|
|
@@ -17132,7 +17769,7 @@ Examples:
|
|
|
17132
17769
|
}
|
|
17133
17770
|
});
|
|
17134
17771
|
var searchTools = [grepTool, findInFileTool];
|
|
17135
|
-
var
|
|
17772
|
+
var DEFAULT_TIMEOUT_MS3 = 3e4;
|
|
17136
17773
|
var MAX_RESPONSE_SIZE = 5 * 1024 * 1024;
|
|
17137
17774
|
var httpFetchTool = defineTool({
|
|
17138
17775
|
name: "http_fetch",
|
|
@@ -17155,7 +17792,7 @@ Examples:
|
|
|
17155
17792
|
}),
|
|
17156
17793
|
async execute({ url, method, headers, body, timeout, maxSize }) {
|
|
17157
17794
|
const startTime = performance.now();
|
|
17158
|
-
const timeoutMs = timeout ??
|
|
17795
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS3;
|
|
17159
17796
|
const maxBytes = maxSize ?? MAX_RESPONSE_SIZE;
|
|
17160
17797
|
try {
|
|
17161
17798
|
const controller = new AbortController();
|
|
@@ -17273,7 +17910,7 @@ Examples:
|
|
|
17273
17910
|
}
|
|
17274
17911
|
});
|
|
17275
17912
|
var httpTools = [httpFetchTool, httpJsonTool];
|
|
17276
|
-
var
|
|
17913
|
+
var DEFAULT_TIMEOUT_MS4 = 6e5;
|
|
17277
17914
|
var MAX_OUTPUT_SIZE2 = 2 * 1024 * 1024;
|
|
17278
17915
|
function getBuildHint(stderr, tool) {
|
|
17279
17916
|
if (/MODULE_NOT_FOUND|Cannot find module/i.test(stderr))
|
|
@@ -17300,7 +17937,7 @@ async function detectPackageManager(cwd) {
|
|
|
17300
17937
|
];
|
|
17301
17938
|
for (const { file, pm } of lockfiles) {
|
|
17302
17939
|
try {
|
|
17303
|
-
await
|
|
17940
|
+
await fs16__default.access(path17__default.join(cwd, file));
|
|
17304
17941
|
return pm;
|
|
17305
17942
|
} catch {
|
|
17306
17943
|
}
|
|
@@ -17337,7 +17974,7 @@ Examples:
|
|
|
17337
17974
|
async execute({ script, cwd, packageManager, args, env: env2, timeout }) {
|
|
17338
17975
|
const projectDir = cwd ?? process.cwd();
|
|
17339
17976
|
const startTime = performance.now();
|
|
17340
|
-
const timeoutMs = timeout ??
|
|
17977
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
17341
17978
|
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
17342
17979
|
const heartbeat = new CommandHeartbeat2({
|
|
17343
17980
|
onUpdate: (stats) => {
|
|
@@ -17433,7 +18070,7 @@ Examples:
|
|
|
17433
18070
|
async execute({ cwd, packageManager, packages, dev, frozen, timeout }) {
|
|
17434
18071
|
const projectDir = cwd ?? process.cwd();
|
|
17435
18072
|
const startTime = performance.now();
|
|
17436
|
-
const timeoutMs = timeout ??
|
|
18073
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
17437
18074
|
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
17438
18075
|
const heartbeat = new CommandHeartbeat2({
|
|
17439
18076
|
onUpdate: (stats) => {
|
|
@@ -17557,7 +18194,7 @@ Examples:
|
|
|
17557
18194
|
async execute({ target, cwd, args, env: env2, timeout }) {
|
|
17558
18195
|
const projectDir = cwd ?? process.cwd();
|
|
17559
18196
|
const startTime = performance.now();
|
|
17560
|
-
const timeoutMs = timeout ??
|
|
18197
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
17561
18198
|
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
17562
18199
|
const heartbeat = new CommandHeartbeat2({
|
|
17563
18200
|
onUpdate: (stats) => {
|
|
@@ -17573,7 +18210,7 @@ ${message}
|
|
|
17573
18210
|
});
|
|
17574
18211
|
try {
|
|
17575
18212
|
try {
|
|
17576
|
-
await
|
|
18213
|
+
await fs16__default.access(path17__default.join(projectDir, "Makefile"));
|
|
17577
18214
|
} catch {
|
|
17578
18215
|
throw new ToolError("No Makefile found in directory", { tool: "make" });
|
|
17579
18216
|
}
|
|
@@ -17660,7 +18297,7 @@ Examples:
|
|
|
17660
18297
|
async execute({ cwd, project, noEmit, watch: watch2, args, timeout }) {
|
|
17661
18298
|
const projectDir = cwd ?? process.cwd();
|
|
17662
18299
|
const startTime = performance.now();
|
|
17663
|
-
const timeoutMs = timeout ??
|
|
18300
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS4;
|
|
17664
18301
|
const { CommandHeartbeat: CommandHeartbeat2 } = await Promise.resolve().then(() => (init_heartbeat(), heartbeat_exports));
|
|
17665
18302
|
const heartbeat = new CommandHeartbeat2({
|
|
17666
18303
|
onUpdate: (stats) => {
|
|
@@ -17778,7 +18415,7 @@ z.object({
|
|
|
17778
18415
|
});
|
|
17779
18416
|
|
|
17780
18417
|
// src/cli/repl/session.ts
|
|
17781
|
-
|
|
18418
|
+
path17__default.dirname(CONFIG_PATHS.trustedTools);
|
|
17782
18419
|
CONFIG_PATHS.trustedTools;
|
|
17783
18420
|
|
|
17784
18421
|
// src/cli/repl/recommended-permissions.ts
|
|
@@ -18440,7 +19077,7 @@ Examples:
|
|
|
18440
19077
|
}
|
|
18441
19078
|
}
|
|
18442
19079
|
});
|
|
18443
|
-
var
|
|
19080
|
+
var DEFAULT_TIMEOUT_MS5 = 3e4;
|
|
18444
19081
|
var DEFAULT_MAX_LENGTH = 5e4;
|
|
18445
19082
|
var MAX_DOWNLOAD_SIZE = 10 * 1024 * 1024;
|
|
18446
19083
|
var BLOCKED_SCHEMES = ["file:", "ftp:", "data:", "javascript:"];
|
|
@@ -18671,12 +19308,12 @@ Examples:
|
|
|
18671
19308
|
url: z.string().url().describe("URL to fetch"),
|
|
18672
19309
|
extractContent: z.boolean().optional().default(true).describe("Extract and clean main content (true) or return raw (false)"),
|
|
18673
19310
|
maxLength: z.number().min(1e3).max(2e5).optional().default(DEFAULT_MAX_LENGTH).describe("Maximum content length in characters"),
|
|
18674
|
-
timeout: z.number().min(1e3).max(12e4).optional().default(
|
|
19311
|
+
timeout: z.number().min(1e3).max(12e4).optional().default(DEFAULT_TIMEOUT_MS5).describe("Timeout in milliseconds")
|
|
18675
19312
|
}),
|
|
18676
19313
|
async execute({ url, extractContent, maxLength, timeout }) {
|
|
18677
19314
|
const startTime = performance.now();
|
|
18678
19315
|
const effectiveMaxLength = maxLength ?? DEFAULT_MAX_LENGTH;
|
|
18679
|
-
const effectiveTimeout = timeout ??
|
|
19316
|
+
const effectiveTimeout = timeout ?? DEFAULT_TIMEOUT_MS5;
|
|
18680
19317
|
validateUrl(url);
|
|
18681
19318
|
const controller = new AbortController();
|
|
18682
19319
|
const timeoutId = setTimeout(() => controller.abort(), effectiveTimeout);
|
|
@@ -18805,63 +19442,63 @@ var LANG_ALIASES = {
|
|
|
18805
19442
|
};
|
|
18806
19443
|
var TOKEN_COLORS = {
|
|
18807
19444
|
// Keywords & control flow
|
|
18808
|
-
keyword: (t) =>
|
|
18809
|
-
"keyword.control": (t) =>
|
|
19445
|
+
keyword: (t) => chalk4.blue(t),
|
|
19446
|
+
"keyword.control": (t) => chalk4.blue(t),
|
|
18810
19447
|
// Built-in types and literals
|
|
18811
|
-
built_in: (t) =>
|
|
18812
|
-
type: (t) =>
|
|
18813
|
-
class: (t) =>
|
|
18814
|
-
"title.class": (t) =>
|
|
18815
|
-
"title.class.inherited": (t) =>
|
|
19448
|
+
built_in: (t) => chalk4.cyan(t),
|
|
19449
|
+
type: (t) => chalk4.cyan(t),
|
|
19450
|
+
class: (t) => chalk4.cyan(t),
|
|
19451
|
+
"title.class": (t) => chalk4.cyan(t),
|
|
19452
|
+
"title.class.inherited": (t) => chalk4.cyan(t),
|
|
18816
19453
|
// Functions
|
|
18817
|
-
"title.function": (t) =>
|
|
18818
|
-
"title.function.invoke": (t) =>
|
|
18819
|
-
title: (t) =>
|
|
19454
|
+
"title.function": (t) => chalk4.green(t),
|
|
19455
|
+
"title.function.invoke": (t) => chalk4.green(t),
|
|
19456
|
+
title: (t) => chalk4.green(t),
|
|
18820
19457
|
// Strings
|
|
18821
|
-
string: (t) =>
|
|
18822
|
-
"template-tag": (t) =>
|
|
18823
|
-
"template-variable": (t) =>
|
|
19458
|
+
string: (t) => chalk4.yellow(t),
|
|
19459
|
+
"template-tag": (t) => chalk4.yellow(t),
|
|
19460
|
+
"template-variable": (t) => chalk4.green(t),
|
|
18824
19461
|
// Numbers
|
|
18825
|
-
number: (t) =>
|
|
19462
|
+
number: (t) => chalk4.magenta(t),
|
|
18826
19463
|
// Literals (true, false, null)
|
|
18827
|
-
literal: (t) =>
|
|
19464
|
+
literal: (t) => chalk4.magenta(t),
|
|
18828
19465
|
// Comments
|
|
18829
|
-
comment: (t) =>
|
|
18830
|
-
doctag: (t) =>
|
|
19466
|
+
comment: (t) => chalk4.dim(t),
|
|
19467
|
+
doctag: (t) => chalk4.dim.bold(t),
|
|
18831
19468
|
// Regular expressions
|
|
18832
|
-
regexp: (t) =>
|
|
19469
|
+
regexp: (t) => chalk4.red(t),
|
|
18833
19470
|
// Attributes & properties
|
|
18834
|
-
attr: (t) =>
|
|
18835
|
-
attribute: (t) =>
|
|
18836
|
-
property: (t) =>
|
|
19471
|
+
attr: (t) => chalk4.cyan(t),
|
|
19472
|
+
attribute: (t) => chalk4.cyan(t),
|
|
19473
|
+
property: (t) => chalk4.white(t),
|
|
18837
19474
|
// Operators & punctuation
|
|
18838
|
-
operator: (t) =>
|
|
18839
|
-
punctuation: (t) =>
|
|
19475
|
+
operator: (t) => chalk4.dim.white(t),
|
|
19476
|
+
punctuation: (t) => chalk4.dim.white(t),
|
|
18840
19477
|
// Meta / preprocessor
|
|
18841
|
-
meta: (t) =>
|
|
18842
|
-
"meta keyword": (t) =>
|
|
18843
|
-
"meta string": (t) =>
|
|
19478
|
+
meta: (t) => chalk4.dim(t),
|
|
19479
|
+
"meta keyword": (t) => chalk4.blue(t),
|
|
19480
|
+
"meta string": (t) => chalk4.yellow(t),
|
|
18844
19481
|
// Variables & params
|
|
18845
|
-
variable: (t) =>
|
|
18846
|
-
"variable.language": (t) =>
|
|
18847
|
-
params: (t) =>
|
|
19482
|
+
variable: (t) => chalk4.white(t),
|
|
19483
|
+
"variable.language": (t) => chalk4.blue(t),
|
|
19484
|
+
params: (t) => chalk4.white(t),
|
|
18848
19485
|
// Tags (HTML/XML)
|
|
18849
|
-
tag: (t) =>
|
|
18850
|
-
name: (t) =>
|
|
19486
|
+
tag: (t) => chalk4.blue(t),
|
|
19487
|
+
name: (t) => chalk4.blue(t),
|
|
18851
19488
|
// Symbols & selectors (CSS, Ruby)
|
|
18852
|
-
symbol: (t) =>
|
|
18853
|
-
selector: (t) =>
|
|
18854
|
-
"selector-tag": (t) =>
|
|
18855
|
-
"selector-class": (t) =>
|
|
18856
|
-
"selector-id": (t) =>
|
|
19489
|
+
symbol: (t) => chalk4.magenta(t),
|
|
19490
|
+
selector: (t) => chalk4.green(t),
|
|
19491
|
+
"selector-tag": (t) => chalk4.blue(t),
|
|
19492
|
+
"selector-class": (t) => chalk4.green(t),
|
|
19493
|
+
"selector-id": (t) => chalk4.cyan(t),
|
|
18857
19494
|
// Additions/deletions (diffs)
|
|
18858
|
-
addition: (t) =>
|
|
18859
|
-
deletion: (t) =>
|
|
19495
|
+
addition: (t) => chalk4.green(t),
|
|
19496
|
+
deletion: (t) => chalk4.red(t),
|
|
18860
19497
|
// Section headers
|
|
18861
|
-
section: (t) =>
|
|
19498
|
+
section: (t) => chalk4.bold(t),
|
|
18862
19499
|
// Emphasis
|
|
18863
|
-
emphasis: (t) =>
|
|
18864
|
-
strong: (t) =>
|
|
19500
|
+
emphasis: (t) => chalk4.italic(t),
|
|
19501
|
+
strong: (t) => chalk4.bold(t)
|
|
18865
19502
|
};
|
|
18866
19503
|
function hljsToChalk(html) {
|
|
18867
19504
|
const safeSpans = [];
|
|
@@ -18916,10 +19553,10 @@ function highlightLine(line, lang) {
|
|
|
18916
19553
|
}
|
|
18917
19554
|
|
|
18918
19555
|
// src/cli/repl/output/diff-renderer.ts
|
|
18919
|
-
var bgDeleteLine =
|
|
18920
|
-
var bgAddLine =
|
|
18921
|
-
var bgDeleteWord =
|
|
18922
|
-
var bgAddWord =
|
|
19556
|
+
var bgDeleteLine = chalk4.bgRgb(80, 20, 20);
|
|
19557
|
+
var bgAddLine = chalk4.bgRgb(20, 60, 20);
|
|
19558
|
+
var bgDeleteWord = chalk4.bgRgb(160, 40, 40);
|
|
19559
|
+
var bgAddWord = chalk4.bgRgb(40, 120, 40);
|
|
18923
19560
|
function parseDiff(raw) {
|
|
18924
19561
|
const files = [];
|
|
18925
19562
|
const lines = raw.split("\n");
|
|
@@ -19116,7 +19753,7 @@ function renderDiff(diff, options) {
|
|
|
19116
19753
|
const maxWidth = options?.maxWidth ?? Math.min(getTerminalWidth() - 2, 120);
|
|
19117
19754
|
const compact = options?.compact ?? false;
|
|
19118
19755
|
if (diff.files.length === 0) {
|
|
19119
|
-
console.log(
|
|
19756
|
+
console.log(chalk4.dim("\n No changes\n"));
|
|
19120
19757
|
return;
|
|
19121
19758
|
}
|
|
19122
19759
|
for (const file of diff.files) {
|
|
@@ -19125,9 +19762,9 @@ function renderDiff(diff, options) {
|
|
|
19125
19762
|
const { stats } = diff;
|
|
19126
19763
|
const parts = [];
|
|
19127
19764
|
parts.push(`${stats.filesChanged} file${stats.filesChanged !== 1 ? "s" : ""}`);
|
|
19128
|
-
if (stats.additions > 0) parts.push(
|
|
19129
|
-
if (stats.deletions > 0) parts.push(
|
|
19130
|
-
console.log(
|
|
19765
|
+
if (stats.additions > 0) parts.push(chalk4.green(`+${stats.additions}`));
|
|
19766
|
+
if (stats.deletions > 0) parts.push(chalk4.red(`-${stats.deletions}`));
|
|
19767
|
+
console.log(chalk4.dim(`
|
|
19131
19768
|
${parts.join(", ")}
|
|
19132
19769
|
`));
|
|
19133
19770
|
}
|
|
@@ -19140,22 +19777,22 @@ function renderFileBlock(file, opts) {
|
|
|
19140
19777
|
const title = ` ${file.path} (${typeLabel}${statsLabel}) `;
|
|
19141
19778
|
const topFill = Math.max(0, maxWidth - 2 - stripAnsi(title).length);
|
|
19142
19779
|
console.log(
|
|
19143
|
-
|
|
19780
|
+
chalk4.magenta("\u256D\u2500\u2500") + chalk4.cyan.bold(title) + chalk4.magenta("\u2500".repeat(topFill) + "\u256E")
|
|
19144
19781
|
);
|
|
19145
19782
|
for (let h = 0; h < file.hunks.length; h++) {
|
|
19146
19783
|
const hunk = file.hunks[h];
|
|
19147
19784
|
if (!compact || h > 0) {
|
|
19148
|
-
const hunkLabel = hunk.heading ? ` ${
|
|
19785
|
+
const hunkLabel = hunk.heading ? ` ${chalk4.dim(hunk.heading)}` : "";
|
|
19149
19786
|
console.log(
|
|
19150
|
-
|
|
19787
|
+
chalk4.magenta("\u2502") + " " + chalk4.cyan(
|
|
19151
19788
|
`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`
|
|
19152
19789
|
) + hunkLabel
|
|
19153
19790
|
);
|
|
19154
19791
|
}
|
|
19155
19792
|
const pairs = pairAdjacentLines(hunk.lines);
|
|
19156
|
-
const pairedDeleteIndices = new Set(pairs.map((
|
|
19157
|
-
const pairedAddIndices = new Set(pairs.map((
|
|
19158
|
-
const pairByAdd = new Map(pairs.map((
|
|
19793
|
+
const pairedDeleteIndices = new Set(pairs.map((p5) => p5.deleteIdx));
|
|
19794
|
+
const pairedAddIndices = new Set(pairs.map((p5) => p5.addIdx));
|
|
19795
|
+
const pairByAdd = new Map(pairs.map((p5) => [p5.addIdx, p5.deleteIdx]));
|
|
19159
19796
|
const wordHighlights = /* @__PURE__ */ new Map();
|
|
19160
19797
|
for (const pair of pairs) {
|
|
19161
19798
|
const delLine = hunk.lines[pair.deleteIdx];
|
|
@@ -19179,7 +19816,7 @@ function renderFileBlock(file, opts) {
|
|
|
19179
19816
|
const plainLen = stripAnsi(innerText).length + 1;
|
|
19180
19817
|
const pad = Math.max(0, contentWidth - plainLen);
|
|
19181
19818
|
console.log(
|
|
19182
|
-
|
|
19819
|
+
chalk4.magenta("\u2502") + bgAddLine(` ${innerText}` + " ".repeat(pad + 2)) + chalk4.magenta("\u2502")
|
|
19183
19820
|
);
|
|
19184
19821
|
} else if (line.type === "delete") {
|
|
19185
19822
|
const isPaired = pairedDeleteIndices.has(li);
|
|
@@ -19193,7 +19830,7 @@ function renderFileBlock(file, opts) {
|
|
|
19193
19830
|
const plainLen = stripAnsi(innerText).length + 1;
|
|
19194
19831
|
const pad = Math.max(0, contentWidth - plainLen);
|
|
19195
19832
|
console.log(
|
|
19196
|
-
|
|
19833
|
+
chalk4.magenta("\u2502") + bgDeleteLine(` ${innerText}` + " ".repeat(pad + 2)) + chalk4.magenta("\u2502")
|
|
19197
19834
|
);
|
|
19198
19835
|
} else {
|
|
19199
19836
|
let content = line.content;
|
|
@@ -19204,17 +19841,17 @@ function renderFileBlock(file, opts) {
|
|
|
19204
19841
|
const plainLen = stripAnsi(lineStr).length;
|
|
19205
19842
|
const pad = Math.max(0, contentWidth - plainLen);
|
|
19206
19843
|
console.log(
|
|
19207
|
-
|
|
19844
|
+
chalk4.magenta("\u2502") + chalk4.dim(` ${lineStr}`) + " ".repeat(pad) + " " + chalk4.magenta("\u2502")
|
|
19208
19845
|
);
|
|
19209
19846
|
}
|
|
19210
19847
|
}
|
|
19211
19848
|
}
|
|
19212
|
-
console.log(
|
|
19849
|
+
console.log(chalk4.magenta("\u2570" + "\u2500".repeat(Math.max(0, maxWidth - 2)) + "\u256F"));
|
|
19213
19850
|
}
|
|
19214
19851
|
function formatLineNo(line, show) {
|
|
19215
19852
|
if (!show) return "";
|
|
19216
19853
|
const lineNo = line.type === "delete" ? line.oldLineNo : line.newLineNo;
|
|
19217
|
-
return
|
|
19854
|
+
return chalk4.dim(`${String(lineNo ?? "").padStart(5)} `);
|
|
19218
19855
|
}
|
|
19219
19856
|
function getChangedLines(diff) {
|
|
19220
19857
|
const result = /* @__PURE__ */ new Map();
|
|
@@ -19313,15 +19950,15 @@ Examples:
|
|
|
19313
19950
|
var diffTools = [showDiffTool];
|
|
19314
19951
|
async function fileExists(filePath) {
|
|
19315
19952
|
try {
|
|
19316
|
-
await
|
|
19953
|
+
await fs16__default.access(filePath);
|
|
19317
19954
|
return true;
|
|
19318
19955
|
} catch {
|
|
19319
19956
|
return false;
|
|
19320
19957
|
}
|
|
19321
19958
|
}
|
|
19322
|
-
async function fileExists2(
|
|
19959
|
+
async function fileExists2(path40) {
|
|
19323
19960
|
try {
|
|
19324
|
-
await access(
|
|
19961
|
+
await access(path40);
|
|
19325
19962
|
return true;
|
|
19326
19963
|
} catch {
|
|
19327
19964
|
return false;
|
|
@@ -19411,7 +20048,7 @@ async function detectMaturity(cwd) {
|
|
|
19411
20048
|
if (!hasLintConfig && hasPackageJson) {
|
|
19412
20049
|
try {
|
|
19413
20050
|
const pkgRaw = await import('fs/promises').then(
|
|
19414
|
-
(
|
|
20051
|
+
(fs38) => fs38.readFile(join(cwd, "package.json"), "utf-8")
|
|
19415
20052
|
);
|
|
19416
20053
|
const pkg = JSON.parse(pkgRaw);
|
|
19417
20054
|
if (pkg.scripts?.lint || pkg.scripts?.["lint:fix"]) {
|
|
@@ -19580,7 +20217,7 @@ async function checkTestCoverage(diff, cwd) {
|
|
|
19580
20217
|
);
|
|
19581
20218
|
if (!hasTestChange) {
|
|
19582
20219
|
const ext = src.path.match(/\.(ts|tsx|js|jsx)$/)?.[0] ?? ".ts";
|
|
19583
|
-
const testExists = await fileExists(
|
|
20220
|
+
const testExists = await fileExists(path17__default.join(cwd, `${baseName}.test${ext}`)) || await fileExists(path17__default.join(cwd, `${baseName}.spec${ext}`));
|
|
19584
20221
|
if (testExists) {
|
|
19585
20222
|
if (src.additions >= TEST_COVERAGE_LARGE_CHANGE_THRESHOLD) {
|
|
19586
20223
|
findings.push({
|
|
@@ -19811,8 +20448,8 @@ Examples:
|
|
|
19811
20448
|
}
|
|
19812
20449
|
});
|
|
19813
20450
|
var reviewTools = [reviewCodeTool];
|
|
19814
|
-
var
|
|
19815
|
-
var
|
|
20451
|
+
var fs25 = await import('fs/promises');
|
|
20452
|
+
var path27 = await import('path');
|
|
19816
20453
|
var { glob: glob14 } = await import('glob');
|
|
19817
20454
|
var DEFAULT_MAX_FILES = 200;
|
|
19818
20455
|
var LANGUAGE_EXTENSIONS = {
|
|
@@ -19838,7 +20475,7 @@ var DEFAULT_EXCLUDES = [
|
|
|
19838
20475
|
"**/*.d.ts"
|
|
19839
20476
|
];
|
|
19840
20477
|
function detectLanguage3(filePath) {
|
|
19841
|
-
const ext =
|
|
20478
|
+
const ext = path27.extname(filePath).toLowerCase();
|
|
19842
20479
|
for (const [lang, extensions] of Object.entries(LANGUAGE_EXTENSIONS)) {
|
|
19843
20480
|
if (extensions.includes(ext)) return lang;
|
|
19844
20481
|
}
|
|
@@ -20247,9 +20884,9 @@ Examples:
|
|
|
20247
20884
|
}),
|
|
20248
20885
|
async execute({ path: rootPath, include, exclude, languages, maxFiles, depth }) {
|
|
20249
20886
|
const startTime = performance.now();
|
|
20250
|
-
const absPath =
|
|
20887
|
+
const absPath = path27.resolve(rootPath);
|
|
20251
20888
|
try {
|
|
20252
|
-
const stat2 = await
|
|
20889
|
+
const stat2 = await fs25.stat(absPath);
|
|
20253
20890
|
if (!stat2.isDirectory()) {
|
|
20254
20891
|
throw new ToolError(`Path is not a directory: ${absPath}`, {
|
|
20255
20892
|
tool: "codebase_map"
|
|
@@ -20286,14 +20923,14 @@ Examples:
|
|
|
20286
20923
|
let totalDefinitions = 0;
|
|
20287
20924
|
let exportedSymbols = 0;
|
|
20288
20925
|
for (const file of limitedFiles) {
|
|
20289
|
-
const fullPath =
|
|
20926
|
+
const fullPath = path27.join(absPath, file);
|
|
20290
20927
|
const language = detectLanguage3(file);
|
|
20291
20928
|
if (!language) continue;
|
|
20292
20929
|
if (languages && !languages.includes(language)) {
|
|
20293
20930
|
continue;
|
|
20294
20931
|
}
|
|
20295
20932
|
try {
|
|
20296
|
-
const content = await
|
|
20933
|
+
const content = await fs25.readFile(fullPath, "utf-8");
|
|
20297
20934
|
const lineCount = content.split("\n").length;
|
|
20298
20935
|
const parsed = parseFile(content, language);
|
|
20299
20936
|
const definitions = depth === "overview" ? parsed.definitions.filter((d) => d.exported) : parsed.definitions;
|
|
@@ -20326,23 +20963,23 @@ Examples:
|
|
|
20326
20963
|
});
|
|
20327
20964
|
var codebaseMapTools = [codebaseMapTool];
|
|
20328
20965
|
init_paths();
|
|
20329
|
-
var
|
|
20330
|
-
var
|
|
20966
|
+
var fs26 = await import('fs/promises');
|
|
20967
|
+
var path28 = await import('path');
|
|
20331
20968
|
var crypto2 = await import('crypto');
|
|
20332
|
-
var GLOBAL_MEMORIES_DIR =
|
|
20969
|
+
var GLOBAL_MEMORIES_DIR = path28.join(COCO_HOME, "memories");
|
|
20333
20970
|
var PROJECT_MEMORIES_DIR = ".coco/memories";
|
|
20334
20971
|
var DEFAULT_MAX_MEMORIES = 1e3;
|
|
20335
20972
|
async function ensureDir(dirPath) {
|
|
20336
|
-
await
|
|
20973
|
+
await fs26.mkdir(dirPath, { recursive: true });
|
|
20337
20974
|
}
|
|
20338
20975
|
function getMemoriesDir(scope) {
|
|
20339
20976
|
return scope === "global" ? GLOBAL_MEMORIES_DIR : PROJECT_MEMORIES_DIR;
|
|
20340
20977
|
}
|
|
20341
20978
|
async function loadIndex(scope) {
|
|
20342
20979
|
const dir = getMemoriesDir(scope);
|
|
20343
|
-
const indexPath =
|
|
20980
|
+
const indexPath = path28.join(dir, "index.json");
|
|
20344
20981
|
try {
|
|
20345
|
-
const content = await
|
|
20982
|
+
const content = await fs26.readFile(indexPath, "utf-8");
|
|
20346
20983
|
return JSON.parse(content);
|
|
20347
20984
|
} catch {
|
|
20348
20985
|
return [];
|
|
@@ -20351,14 +20988,14 @@ async function loadIndex(scope) {
|
|
|
20351
20988
|
async function saveIndex(scope, index) {
|
|
20352
20989
|
const dir = getMemoriesDir(scope);
|
|
20353
20990
|
await ensureDir(dir);
|
|
20354
|
-
const indexPath =
|
|
20355
|
-
await
|
|
20991
|
+
const indexPath = path28.join(dir, "index.json");
|
|
20992
|
+
await fs26.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
20356
20993
|
}
|
|
20357
20994
|
async function loadMemory(scope, id) {
|
|
20358
20995
|
const dir = getMemoriesDir(scope);
|
|
20359
|
-
const memPath =
|
|
20996
|
+
const memPath = path28.join(dir, `${id}.json`);
|
|
20360
20997
|
try {
|
|
20361
|
-
const content = await
|
|
20998
|
+
const content = await fs26.readFile(memPath, "utf-8");
|
|
20362
20999
|
return JSON.parse(content);
|
|
20363
21000
|
} catch {
|
|
20364
21001
|
return null;
|
|
@@ -20367,8 +21004,8 @@ async function loadMemory(scope, id) {
|
|
|
20367
21004
|
async function saveMemory(scope, memory) {
|
|
20368
21005
|
const dir = getMemoriesDir(scope);
|
|
20369
21006
|
await ensureDir(dir);
|
|
20370
|
-
const memPath =
|
|
20371
|
-
await
|
|
21007
|
+
const memPath = path28.join(dir, `${memory.id}.json`);
|
|
21008
|
+
await fs26.writeFile(memPath, JSON.stringify(memory, null, 2), "utf-8");
|
|
20372
21009
|
}
|
|
20373
21010
|
var createMemoryTool = defineTool({
|
|
20374
21011
|
name: "create_memory",
|
|
@@ -20520,17 +21157,17 @@ Examples:
|
|
|
20520
21157
|
}
|
|
20521
21158
|
});
|
|
20522
21159
|
var memoryTools = [createMemoryTool, recallMemoryTool, listMemoriesTool];
|
|
20523
|
-
var
|
|
21160
|
+
var fs27 = await import('fs/promises');
|
|
20524
21161
|
var crypto3 = await import('crypto');
|
|
20525
21162
|
var CHECKPOINT_FILE = ".coco/checkpoints.json";
|
|
20526
21163
|
var DEFAULT_MAX_CHECKPOINTS = 50;
|
|
20527
21164
|
var STASH_PREFIX = "coco-cp";
|
|
20528
21165
|
async function ensureCocoDir() {
|
|
20529
|
-
await
|
|
21166
|
+
await fs27.mkdir(".coco", { recursive: true });
|
|
20530
21167
|
}
|
|
20531
21168
|
async function loadCheckpoints() {
|
|
20532
21169
|
try {
|
|
20533
|
-
const content = await
|
|
21170
|
+
const content = await fs27.readFile(CHECKPOINT_FILE, "utf-8");
|
|
20534
21171
|
return JSON.parse(content);
|
|
20535
21172
|
} catch {
|
|
20536
21173
|
return [];
|
|
@@ -20538,7 +21175,7 @@ async function loadCheckpoints() {
|
|
|
20538
21175
|
}
|
|
20539
21176
|
async function saveCheckpoints(checkpoints) {
|
|
20540
21177
|
await ensureCocoDir();
|
|
20541
|
-
await
|
|
21178
|
+
await fs27.writeFile(CHECKPOINT_FILE, JSON.stringify(checkpoints, null, 2), "utf-8");
|
|
20542
21179
|
}
|
|
20543
21180
|
async function execGit(args) {
|
|
20544
21181
|
const { execaCommand } = await import('execa');
|
|
@@ -20700,8 +21337,8 @@ Examples:
|
|
|
20700
21337
|
}
|
|
20701
21338
|
});
|
|
20702
21339
|
var checkpointTools = [createCheckpointTool, restoreCheckpointTool, listCheckpointsTool];
|
|
20703
|
-
var
|
|
20704
|
-
var
|
|
21340
|
+
var fs28 = await import('fs/promises');
|
|
21341
|
+
var path29 = await import('path');
|
|
20705
21342
|
var { glob: glob15 } = await import('glob');
|
|
20706
21343
|
var INDEX_DIR = ".coco/search-index";
|
|
20707
21344
|
var DEFAULT_CHUNK_SIZE = 20;
|
|
@@ -20829,20 +21466,20 @@ async function getEmbedding(text) {
|
|
|
20829
21466
|
}
|
|
20830
21467
|
async function loadIndex2(indexDir) {
|
|
20831
21468
|
try {
|
|
20832
|
-
const indexPath =
|
|
20833
|
-
const content = await
|
|
21469
|
+
const indexPath = path29.join(indexDir, "index.json");
|
|
21470
|
+
const content = await fs28.readFile(indexPath, "utf-8");
|
|
20834
21471
|
return JSON.parse(content);
|
|
20835
21472
|
} catch {
|
|
20836
21473
|
return null;
|
|
20837
21474
|
}
|
|
20838
21475
|
}
|
|
20839
21476
|
async function saveIndex2(indexDir, index) {
|
|
20840
|
-
await
|
|
20841
|
-
const indexPath =
|
|
20842
|
-
await
|
|
21477
|
+
await fs28.mkdir(indexDir, { recursive: true });
|
|
21478
|
+
const indexPath = path29.join(indexDir, "index.json");
|
|
21479
|
+
await fs28.writeFile(indexPath, JSON.stringify(index), "utf-8");
|
|
20843
21480
|
}
|
|
20844
21481
|
function isBinary(filePath) {
|
|
20845
|
-
return BINARY_EXTENSIONS.has(
|
|
21482
|
+
return BINARY_EXTENSIONS.has(path29.extname(filePath).toLowerCase());
|
|
20846
21483
|
}
|
|
20847
21484
|
var semanticSearchTool = defineTool({
|
|
20848
21485
|
name: "semantic_search",
|
|
@@ -20867,8 +21504,8 @@ Examples:
|
|
|
20867
21504
|
const effectivePath = rootPath ?? ".";
|
|
20868
21505
|
const effectiveMaxResults = maxResults ?? 10;
|
|
20869
21506
|
const effectiveThreshold = threshold ?? 0.3;
|
|
20870
|
-
const absPath =
|
|
20871
|
-
const indexDir =
|
|
21507
|
+
const absPath = path29.resolve(effectivePath);
|
|
21508
|
+
const indexDir = path29.join(absPath, INDEX_DIR);
|
|
20872
21509
|
let index = reindex ? null : await loadIndex2(indexDir);
|
|
20873
21510
|
let warnings = [];
|
|
20874
21511
|
if (!index) {
|
|
@@ -20884,10 +21521,10 @@ Examples:
|
|
|
20884
21521
|
let indexSaveWarning = "";
|
|
20885
21522
|
for (const file of files) {
|
|
20886
21523
|
if (isBinary(file)) continue;
|
|
20887
|
-
const fullPath =
|
|
21524
|
+
const fullPath = path29.join(absPath, file);
|
|
20888
21525
|
try {
|
|
20889
|
-
const stat2 = await
|
|
20890
|
-
const content = await
|
|
21526
|
+
const stat2 = await fs28.stat(fullPath);
|
|
21527
|
+
const content = await fs28.readFile(fullPath, "utf-8");
|
|
20891
21528
|
if (content.length > 1e5) continue;
|
|
20892
21529
|
const fileChunks = chunkContent(content, DEFAULT_CHUNK_SIZE);
|
|
20893
21530
|
for (const chunk of fileChunks) {
|
|
@@ -20963,8 +21600,8 @@ Examples:
|
|
|
20963
21600
|
}
|
|
20964
21601
|
});
|
|
20965
21602
|
var semanticSearchTools = [semanticSearchTool];
|
|
20966
|
-
var
|
|
20967
|
-
var
|
|
21603
|
+
var fs29 = await import('fs/promises');
|
|
21604
|
+
var path30 = await import('path');
|
|
20968
21605
|
var { glob: glob16 } = await import('glob');
|
|
20969
21606
|
async function parseClassRelationships(rootPath, include) {
|
|
20970
21607
|
const pattern = include ?? "**/*.{ts,tsx,js,jsx}";
|
|
@@ -20977,7 +21614,7 @@ async function parseClassRelationships(rootPath, include) {
|
|
|
20977
21614
|
const interfaces = [];
|
|
20978
21615
|
for (const file of files.slice(0, 100)) {
|
|
20979
21616
|
try {
|
|
20980
|
-
const content = await
|
|
21617
|
+
const content = await fs29.readFile(path30.join(rootPath, file), "utf-8");
|
|
20981
21618
|
const lines = content.split("\n");
|
|
20982
21619
|
for (let i = 0; i < lines.length; i++) {
|
|
20983
21620
|
const line = lines[i];
|
|
@@ -21096,14 +21733,14 @@ async function generateClassDiagram(rootPath, include) {
|
|
|
21096
21733
|
};
|
|
21097
21734
|
}
|
|
21098
21735
|
async function generateArchitectureDiagram(rootPath) {
|
|
21099
|
-
const entries = await
|
|
21736
|
+
const entries = await fs29.readdir(rootPath, { withFileTypes: true });
|
|
21100
21737
|
const dirs = entries.filter(
|
|
21101
21738
|
(e) => e.isDirectory() && !e.name.startsWith(".") && !["node_modules", "dist", "build", "coverage", "__pycache__", "target"].includes(e.name)
|
|
21102
21739
|
);
|
|
21103
21740
|
const lines = ["graph TD"];
|
|
21104
21741
|
let nodeCount = 0;
|
|
21105
21742
|
let edgeCount = 0;
|
|
21106
|
-
const rootName =
|
|
21743
|
+
const rootName = path30.basename(rootPath);
|
|
21107
21744
|
lines.push(` ROOT["${rootName}"]`);
|
|
21108
21745
|
nodeCount++;
|
|
21109
21746
|
for (const dir of dirs) {
|
|
@@ -21113,7 +21750,7 @@ async function generateArchitectureDiagram(rootPath) {
|
|
|
21113
21750
|
nodeCount++;
|
|
21114
21751
|
edgeCount++;
|
|
21115
21752
|
try {
|
|
21116
|
-
const subEntries = await
|
|
21753
|
+
const subEntries = await fs29.readdir(path30.join(rootPath, dir.name), {
|
|
21117
21754
|
withFileTypes: true
|
|
21118
21755
|
});
|
|
21119
21756
|
const subDirs = subEntries.filter(
|
|
@@ -21236,7 +21873,7 @@ Examples:
|
|
|
21236
21873
|
tool: "generate_diagram"
|
|
21237
21874
|
});
|
|
21238
21875
|
}
|
|
21239
|
-
const absPath = rootPath ?
|
|
21876
|
+
const absPath = rootPath ? path30.resolve(rootPath) : process.cwd();
|
|
21240
21877
|
switch (type) {
|
|
21241
21878
|
case "class":
|
|
21242
21879
|
return generateClassDiagram(absPath, include);
|
|
@@ -21297,8 +21934,8 @@ Examples:
|
|
|
21297
21934
|
}
|
|
21298
21935
|
});
|
|
21299
21936
|
var diagramTools = [generateDiagramTool];
|
|
21300
|
-
var
|
|
21301
|
-
var
|
|
21937
|
+
var fs30 = await import('fs/promises');
|
|
21938
|
+
var path31 = await import('path');
|
|
21302
21939
|
var DEFAULT_MAX_PAGES = 20;
|
|
21303
21940
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
21304
21941
|
function parsePageRange(rangeStr, totalPages) {
|
|
@@ -21333,9 +21970,9 @@ Examples:
|
|
|
21333
21970
|
}),
|
|
21334
21971
|
async execute({ path: filePath, pages, maxPages }) {
|
|
21335
21972
|
const startTime = performance.now();
|
|
21336
|
-
const absPath =
|
|
21973
|
+
const absPath = path31.resolve(filePath);
|
|
21337
21974
|
try {
|
|
21338
|
-
const stat2 = await
|
|
21975
|
+
const stat2 = await fs30.stat(absPath);
|
|
21339
21976
|
if (!stat2.isFile()) {
|
|
21340
21977
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
21341
21978
|
tool: "read_pdf"
|
|
@@ -21366,7 +22003,7 @@ Examples:
|
|
|
21366
22003
|
}
|
|
21367
22004
|
try {
|
|
21368
22005
|
const pdfParse = await import('pdf-parse');
|
|
21369
|
-
const dataBuffer = await
|
|
22006
|
+
const dataBuffer = await fs30.readFile(absPath);
|
|
21370
22007
|
const pdfData = await pdfParse.default(dataBuffer, {
|
|
21371
22008
|
max: maxPages
|
|
21372
22009
|
});
|
|
@@ -21413,8 +22050,8 @@ Examples:
|
|
|
21413
22050
|
}
|
|
21414
22051
|
});
|
|
21415
22052
|
var pdfTools = [readPdfTool];
|
|
21416
|
-
var
|
|
21417
|
-
var
|
|
22053
|
+
var fs31 = await import('fs/promises');
|
|
22054
|
+
var path32 = await import('path');
|
|
21418
22055
|
var SUPPORTED_FORMATS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp"]);
|
|
21419
22056
|
var MAX_IMAGE_SIZE = 20 * 1024 * 1024;
|
|
21420
22057
|
var MIME_TYPES = {
|
|
@@ -21442,15 +22079,15 @@ Examples:
|
|
|
21442
22079
|
async execute({ path: filePath, prompt, provider }) {
|
|
21443
22080
|
const startTime = performance.now();
|
|
21444
22081
|
const effectivePrompt = prompt ?? "Describe this image in detail. If it's code or a UI, identify the key elements.";
|
|
21445
|
-
const absPath =
|
|
22082
|
+
const absPath = path32.resolve(filePath);
|
|
21446
22083
|
const cwd = process.cwd();
|
|
21447
|
-
if (!absPath.startsWith(cwd +
|
|
22084
|
+
if (!absPath.startsWith(cwd + path32.sep) && absPath !== cwd) {
|
|
21448
22085
|
throw new ToolError(
|
|
21449
22086
|
`Path traversal denied: '${filePath}' resolves outside the project directory`,
|
|
21450
22087
|
{ tool: "read_image" }
|
|
21451
22088
|
);
|
|
21452
22089
|
}
|
|
21453
|
-
const ext =
|
|
22090
|
+
const ext = path32.extname(absPath).toLowerCase();
|
|
21454
22091
|
if (!SUPPORTED_FORMATS.has(ext)) {
|
|
21455
22092
|
throw new ToolError(
|
|
21456
22093
|
`Unsupported image format '${ext}'. Supported: ${Array.from(SUPPORTED_FORMATS).join(", ")}`,
|
|
@@ -21458,7 +22095,7 @@ Examples:
|
|
|
21458
22095
|
);
|
|
21459
22096
|
}
|
|
21460
22097
|
try {
|
|
21461
|
-
const stat2 = await
|
|
22098
|
+
const stat2 = await fs31.stat(absPath);
|
|
21462
22099
|
if (!stat2.isFile()) {
|
|
21463
22100
|
throw new ToolError(`Path is not a file: ${absPath}`, {
|
|
21464
22101
|
tool: "read_image"
|
|
@@ -21479,7 +22116,7 @@ Examples:
|
|
|
21479
22116
|
if (error instanceof ToolError) throw error;
|
|
21480
22117
|
throw error;
|
|
21481
22118
|
}
|
|
21482
|
-
const imageBuffer = await
|
|
22119
|
+
const imageBuffer = await fs31.readFile(absPath);
|
|
21483
22120
|
const base64 = imageBuffer.toString("base64");
|
|
21484
22121
|
const mimeType = MIME_TYPES[ext] ?? "image/png";
|
|
21485
22122
|
const selectedProvider = provider ?? "anthropic";
|
|
@@ -21516,8 +22153,8 @@ Examples:
|
|
|
21516
22153
|
description = response.content.filter((block) => block.type === "text").map((block) => block.text).join("\n") || "No description generated";
|
|
21517
22154
|
} else if (selectedProvider === "openai") {
|
|
21518
22155
|
model = "gpt-4o";
|
|
21519
|
-
const { default:
|
|
21520
|
-
const client = new
|
|
22156
|
+
const { default: OpenAI3 } = await import('openai');
|
|
22157
|
+
const client = new OpenAI3();
|
|
21521
22158
|
const openaiMessages = [
|
|
21522
22159
|
{
|
|
21523
22160
|
role: "user",
|
|
@@ -21597,7 +22234,7 @@ Examples:
|
|
|
21597
22234
|
}
|
|
21598
22235
|
});
|
|
21599
22236
|
var imageTools = [readImageTool];
|
|
21600
|
-
var
|
|
22237
|
+
var path33 = await import('path');
|
|
21601
22238
|
var DANGEROUS_PATTERNS = [
|
|
21602
22239
|
/\bDROP\s+(?:TABLE|DATABASE|INDEX|VIEW)\b/i,
|
|
21603
22240
|
/\bTRUNCATE\b/i,
|
|
@@ -21628,7 +22265,7 @@ Examples:
|
|
|
21628
22265
|
async execute({ database, query, params, readonly: isReadonlyParam }) {
|
|
21629
22266
|
const isReadonly = isReadonlyParam ?? true;
|
|
21630
22267
|
const startTime = performance.now();
|
|
21631
|
-
const absPath =
|
|
22268
|
+
const absPath = path33.resolve(database);
|
|
21632
22269
|
if (isReadonly && isDangerousSql(query)) {
|
|
21633
22270
|
throw new ToolError(
|
|
21634
22271
|
"Write operations (INSERT, UPDATE, DELETE, DROP, ALTER, TRUNCATE, CREATE) are blocked in readonly mode. Set readonly: false to allow writes.",
|
|
@@ -21711,7 +22348,7 @@ Examples:
|
|
|
21711
22348
|
}),
|
|
21712
22349
|
async execute({ database, table }) {
|
|
21713
22350
|
const startTime = performance.now();
|
|
21714
|
-
const absPath =
|
|
22351
|
+
const absPath = path33.resolve(database);
|
|
21715
22352
|
try {
|
|
21716
22353
|
const { default: Database } = await import('better-sqlite3');
|
|
21717
22354
|
const db = new Database(absPath, { readonly: true, fileMustExist: true });
|
|
@@ -21770,14 +22407,14 @@ Examples:
|
|
|
21770
22407
|
}
|
|
21771
22408
|
});
|
|
21772
22409
|
var databaseTools = [sqlQueryTool, inspectSchemaTool];
|
|
21773
|
-
var
|
|
21774
|
-
var
|
|
22410
|
+
var fs32 = await import('fs/promises');
|
|
22411
|
+
var path34 = await import('path');
|
|
21775
22412
|
var AnalyzeFileSchema = z.object({
|
|
21776
22413
|
filePath: z.string().describe("Path to file to analyze"),
|
|
21777
22414
|
includeAst: z.boolean().default(false).describe("Include AST in result")
|
|
21778
22415
|
});
|
|
21779
22416
|
async function analyzeFile(filePath, includeAst = false) {
|
|
21780
|
-
const content = await
|
|
22417
|
+
const content = await fs32.readFile(filePath, "utf-8");
|
|
21781
22418
|
const lines = content.split("\n").length;
|
|
21782
22419
|
const functions = [];
|
|
21783
22420
|
const classes = [];
|
|
@@ -21881,10 +22518,10 @@ async function analyzeDirectory(dirPath) {
|
|
|
21881
22518
|
try {
|
|
21882
22519
|
const analysis = await analyzeFile(file, false);
|
|
21883
22520
|
totalLines += analysis.lines;
|
|
21884
|
-
const ext =
|
|
22521
|
+
const ext = path34.extname(file);
|
|
21885
22522
|
filesByType[ext] = (filesByType[ext] || 0) + 1;
|
|
21886
22523
|
fileStats.push({
|
|
21887
|
-
file:
|
|
22524
|
+
file: path34.relative(dirPath, file),
|
|
21888
22525
|
lines: analysis.lines,
|
|
21889
22526
|
complexity: analysis.complexity.cyclomatic
|
|
21890
22527
|
});
|
|
@@ -22121,6 +22758,13 @@ var createAgentPlanTool = defineTool({
|
|
|
22121
22758
|
};
|
|
22122
22759
|
}
|
|
22123
22760
|
});
|
|
22761
|
+
var LEGACY_ROLE_TO_TYPE = {
|
|
22762
|
+
researcher: "explore",
|
|
22763
|
+
coder: "debug",
|
|
22764
|
+
reviewer: "review",
|
|
22765
|
+
tester: "test",
|
|
22766
|
+
optimizer: "refactor"
|
|
22767
|
+
};
|
|
22124
22768
|
var delegateTaskTool = defineTool({
|
|
22125
22769
|
name: "delegateTask",
|
|
22126
22770
|
description: "Delegate a task to a specialized sub-agent with real LLM tool-use execution.",
|
|
@@ -22128,22 +22772,57 @@ var delegateTaskTool = defineTool({
|
|
|
22128
22772
|
parameters: z.object({
|
|
22129
22773
|
taskId: z.string(),
|
|
22130
22774
|
task: z.string().describe("Description of the task for the agent to execute"),
|
|
22131
|
-
|
|
22775
|
+
agentType: z.enum([
|
|
22776
|
+
"explore",
|
|
22777
|
+
"plan",
|
|
22778
|
+
"test",
|
|
22779
|
+
"debug",
|
|
22780
|
+
"review",
|
|
22781
|
+
"architect",
|
|
22782
|
+
"security",
|
|
22783
|
+
"tdd",
|
|
22784
|
+
"refactor",
|
|
22785
|
+
"e2e",
|
|
22786
|
+
"docs",
|
|
22787
|
+
"database"
|
|
22788
|
+
]).optional().describe("Specialized agent type to use"),
|
|
22789
|
+
agentRole: z.enum(["researcher", "coder", "reviewer", "tester", "optimizer"]).optional().describe("DEPRECATED: Use agentType instead"),
|
|
22132
22790
|
context: z.string().optional(),
|
|
22133
22791
|
maxTurns: z.number().default(10)
|
|
22134
22792
|
}),
|
|
22135
22793
|
async execute(input) {
|
|
22136
22794
|
const typedInput = input;
|
|
22137
|
-
|
|
22795
|
+
const manager = getAgentManager();
|
|
22796
|
+
if (!manager) {
|
|
22797
|
+
const resolvedType = typedInput.agentType ?? "explore";
|
|
22138
22798
|
return {
|
|
22139
|
-
agentId: `agent-${Date.now()}-${
|
|
22799
|
+
agentId: `agent-${Date.now()}-${resolvedType}`,
|
|
22140
22800
|
taskId: typedInput.taskId,
|
|
22141
|
-
|
|
22801
|
+
agentType: resolvedType,
|
|
22142
22802
|
status: "unavailable",
|
|
22143
22803
|
message: "Agent provider not initialized. Call setAgentProvider() during orchestrator startup.",
|
|
22144
22804
|
success: false
|
|
22145
22805
|
};
|
|
22146
22806
|
}
|
|
22807
|
+
const agentType = typedInput.agentType ?? (typedInput.agentRole ? LEGACY_ROLE_TO_TYPE[typedInput.agentRole] ?? "explore" : "explore");
|
|
22808
|
+
const taskDescription = typedInput.context ? `${typedInput.task}
|
|
22809
|
+
|
|
22810
|
+
Additional context: ${typedInput.context}` : typedInput.task;
|
|
22811
|
+
const startTime = Date.now();
|
|
22812
|
+
const result = await manager.spawn(agentType, taskDescription, {
|
|
22813
|
+
timeout: typedInput.maxTurns * 6e4
|
|
22814
|
+
});
|
|
22815
|
+
const duration = Date.now() - startTime;
|
|
22816
|
+
return {
|
|
22817
|
+
agentId: result.agent.id,
|
|
22818
|
+
taskId: typedInput.taskId,
|
|
22819
|
+
agentType,
|
|
22820
|
+
status: result.success ? "completed" : "failed",
|
|
22821
|
+
output: result.output,
|
|
22822
|
+
success: result.success,
|
|
22823
|
+
usage: result.usage,
|
|
22824
|
+
duration
|
|
22825
|
+
};
|
|
22147
22826
|
}
|
|
22148
22827
|
});
|
|
22149
22828
|
var aggregateResultsTool = defineTool({
|
|
@@ -22207,13 +22886,13 @@ ${completed.map((r) => `- ${r.agentId}: Success`).join("\n")}`;
|
|
|
22207
22886
|
}
|
|
22208
22887
|
});
|
|
22209
22888
|
var agentCoordinatorTools = [createAgentPlanTool, delegateTaskTool, aggregateResultsTool];
|
|
22210
|
-
var
|
|
22889
|
+
var fs33 = await import('fs/promises');
|
|
22211
22890
|
var SuggestImprovementsSchema = z.object({
|
|
22212
22891
|
filePath: z.string().describe("File to analyze for improvement suggestions"),
|
|
22213
22892
|
context: z.string().optional().describe("Additional context about the code")
|
|
22214
22893
|
});
|
|
22215
22894
|
async function analyzeAndSuggest(filePath, _context) {
|
|
22216
|
-
const content = await
|
|
22895
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
22217
22896
|
const lines = content.split("\n");
|
|
22218
22897
|
const suggestions = [];
|
|
22219
22898
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -22305,7 +22984,7 @@ async function analyzeAndSuggest(filePath, _context) {
|
|
|
22305
22984
|
if (filePath.endsWith(".ts") && !filePath.includes("test") && !filePath.includes(".d.ts") && line.includes("export ")) {
|
|
22306
22985
|
const testPath = filePath.replace(".ts", ".test.ts");
|
|
22307
22986
|
try {
|
|
22308
|
-
await
|
|
22987
|
+
await fs33.access(testPath);
|
|
22309
22988
|
} catch {
|
|
22310
22989
|
suggestions.push({
|
|
22311
22990
|
type: "testing",
|
|
@@ -22362,7 +23041,7 @@ var calculateCodeScoreTool = defineTool({
|
|
|
22362
23041
|
async execute(input) {
|
|
22363
23042
|
const { filePath } = input;
|
|
22364
23043
|
const suggestions = await analyzeAndSuggest(filePath);
|
|
22365
|
-
const content = await
|
|
23044
|
+
const content = await fs33.readFile(filePath, "utf-8");
|
|
22366
23045
|
const lines = content.split("\n");
|
|
22367
23046
|
const nonEmptyLines = lines.filter((l) => l.trim()).length;
|
|
22368
23047
|
let score = 100;
|
|
@@ -22396,8 +23075,8 @@ var calculateCodeScoreTool = defineTool({
|
|
|
22396
23075
|
}
|
|
22397
23076
|
});
|
|
22398
23077
|
var smartSuggestionsTools = [suggestImprovementsTool, calculateCodeScoreTool];
|
|
22399
|
-
var
|
|
22400
|
-
var
|
|
23078
|
+
var fs34 = await import('fs/promises');
|
|
23079
|
+
var path35 = await import('path');
|
|
22401
23080
|
var ContextMemoryStore = class {
|
|
22402
23081
|
items = /* @__PURE__ */ new Map();
|
|
22403
23082
|
learnings = /* @__PURE__ */ new Map();
|
|
@@ -22409,7 +23088,7 @@ var ContextMemoryStore = class {
|
|
|
22409
23088
|
}
|
|
22410
23089
|
async load() {
|
|
22411
23090
|
try {
|
|
22412
|
-
const content = await
|
|
23091
|
+
const content = await fs34.readFile(this.storePath, "utf-8");
|
|
22413
23092
|
const data = JSON.parse(content);
|
|
22414
23093
|
this.items = new Map(Object.entries(data.items || {}));
|
|
22415
23094
|
this.learnings = new Map(Object.entries(data.learnings || {}));
|
|
@@ -22417,15 +23096,15 @@ var ContextMemoryStore = class {
|
|
|
22417
23096
|
}
|
|
22418
23097
|
}
|
|
22419
23098
|
async save() {
|
|
22420
|
-
const dir =
|
|
22421
|
-
await
|
|
23099
|
+
const dir = path35.dirname(this.storePath);
|
|
23100
|
+
await fs34.mkdir(dir, { recursive: true });
|
|
22422
23101
|
const data = {
|
|
22423
23102
|
sessionId: this.sessionId,
|
|
22424
23103
|
items: Object.fromEntries(this.items),
|
|
22425
23104
|
learnings: Object.fromEntries(this.learnings),
|
|
22426
23105
|
savedAt: Date.now()
|
|
22427
23106
|
};
|
|
22428
|
-
await
|
|
23107
|
+
await fs34.writeFile(this.storePath, JSON.stringify(data, null, 2));
|
|
22429
23108
|
}
|
|
22430
23109
|
addContext(id, item) {
|
|
22431
23110
|
this.items.set(id, item);
|
|
@@ -22575,11 +23254,11 @@ var getLearnedPatternsTool = defineTool({
|
|
|
22575
23254
|
const patterns = store.getFrequentPatterns(typedInput.limit);
|
|
22576
23255
|
return {
|
|
22577
23256
|
totalPatterns: patterns.length,
|
|
22578
|
-
patterns: patterns.map((
|
|
22579
|
-
pattern:
|
|
22580
|
-
preference:
|
|
22581
|
-
frequency:
|
|
22582
|
-
lastUsed: new Date(
|
|
23257
|
+
patterns: patterns.map((p5) => ({
|
|
23258
|
+
pattern: p5.pattern,
|
|
23259
|
+
preference: p5.userPreference,
|
|
23260
|
+
frequency: p5.frequency,
|
|
23261
|
+
lastUsed: new Date(p5.lastUsed).toISOString()
|
|
22583
23262
|
}))
|
|
22584
23263
|
};
|
|
22585
23264
|
}
|
|
@@ -22590,11 +23269,11 @@ var contextEnhancerTools = [
|
|
|
22590
23269
|
recordLearningTool,
|
|
22591
23270
|
getLearnedPatternsTool
|
|
22592
23271
|
];
|
|
22593
|
-
var
|
|
22594
|
-
var
|
|
23272
|
+
var fs35 = await import('fs/promises');
|
|
23273
|
+
var path36 = await import('path');
|
|
22595
23274
|
async function discoverSkills(skillsDir) {
|
|
22596
23275
|
try {
|
|
22597
|
-
const files = await
|
|
23276
|
+
const files = await fs35.readdir(skillsDir);
|
|
22598
23277
|
return files.filter((f) => f.endsWith(".ts") || f.endsWith(".js"));
|
|
22599
23278
|
} catch {
|
|
22600
23279
|
return [];
|
|
@@ -22602,12 +23281,12 @@ async function discoverSkills(skillsDir) {
|
|
|
22602
23281
|
}
|
|
22603
23282
|
async function loadSkillMetadata(skillPath) {
|
|
22604
23283
|
try {
|
|
22605
|
-
const content = await
|
|
23284
|
+
const content = await fs35.readFile(skillPath, "utf-8");
|
|
22606
23285
|
const nameMatch = content.match(/@name\s+(\S+)/);
|
|
22607
23286
|
const descMatch = content.match(/@description\s+(.+)/);
|
|
22608
23287
|
const versionMatch = content.match(/@version\s+(\S+)/);
|
|
22609
23288
|
return {
|
|
22610
|
-
name: nameMatch?.[1] ||
|
|
23289
|
+
name: nameMatch?.[1] || path36.basename(skillPath, path36.extname(skillPath)),
|
|
22611
23290
|
description: descMatch?.[1] || "No description",
|
|
22612
23291
|
version: versionMatch?.[1] || "1.0.0",
|
|
22613
23292
|
dependencies: []
|
|
@@ -22651,7 +23330,7 @@ var discoverSkillsTool = defineTool({
|
|
|
22651
23330
|
const { skillsDir } = input;
|
|
22652
23331
|
const skills = await discoverSkills(skillsDir);
|
|
22653
23332
|
const metadata = await Promise.all(
|
|
22654
|
-
skills.map((s) => loadSkillMetadata(
|
|
23333
|
+
skills.map((s) => loadSkillMetadata(path36.join(skillsDir, s)))
|
|
22655
23334
|
);
|
|
22656
23335
|
return {
|
|
22657
23336
|
skillsDir,
|
|
@@ -23152,26 +23831,26 @@ function hasNullByte2(str) {
|
|
|
23152
23831
|
}
|
|
23153
23832
|
function isBlockedPath(absolute) {
|
|
23154
23833
|
for (const blocked of BLOCKED_PATHS2) {
|
|
23155
|
-
const normalizedBlocked =
|
|
23156
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
23834
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
23835
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
23157
23836
|
return blocked;
|
|
23158
23837
|
}
|
|
23159
23838
|
}
|
|
23160
23839
|
return void 0;
|
|
23161
23840
|
}
|
|
23162
23841
|
function isBlockedExecFile(filePath) {
|
|
23163
|
-
return BLOCKED_EXEC_PATTERNS.some((
|
|
23842
|
+
return BLOCKED_EXEC_PATTERNS.some((p5) => p5.test(filePath));
|
|
23164
23843
|
}
|
|
23165
23844
|
function hasDangerousArgs(args) {
|
|
23166
23845
|
const joined = args.join(" ");
|
|
23167
|
-
return DANGEROUS_ARG_PATTERNS.some((
|
|
23846
|
+
return DANGEROUS_ARG_PATTERNS.some((p5) => p5.test(joined));
|
|
23168
23847
|
}
|
|
23169
23848
|
function getInterpreter(ext) {
|
|
23170
23849
|
return INTERPRETER_MAP[ext.toLowerCase()];
|
|
23171
23850
|
}
|
|
23172
23851
|
async function isExecutable(filePath) {
|
|
23173
23852
|
try {
|
|
23174
|
-
await
|
|
23853
|
+
await fs16__default.access(filePath, fs16__default.constants.X_OK);
|
|
23175
23854
|
return true;
|
|
23176
23855
|
} catch {
|
|
23177
23856
|
return false;
|
|
@@ -23211,7 +23890,7 @@ Examples:
|
|
|
23211
23890
|
throw new ToolError("Invalid file path", { tool: "open_file" });
|
|
23212
23891
|
}
|
|
23213
23892
|
const workDir = cwd ?? process.cwd();
|
|
23214
|
-
const absolute =
|
|
23893
|
+
const absolute = path17__default.isAbsolute(filePath) ? path17__default.normalize(filePath) : path17__default.resolve(workDir, filePath);
|
|
23215
23894
|
const blockedBy = isBlockedPath(absolute);
|
|
23216
23895
|
if (blockedBy) {
|
|
23217
23896
|
throw new ToolError(`Access to system path '${blockedBy}' is not allowed`, {
|
|
@@ -23219,7 +23898,7 @@ Examples:
|
|
|
23219
23898
|
});
|
|
23220
23899
|
}
|
|
23221
23900
|
try {
|
|
23222
|
-
await
|
|
23901
|
+
await fs16__default.access(absolute);
|
|
23223
23902
|
} catch {
|
|
23224
23903
|
throw new ToolError(`File not found: ${absolute}`, { tool: "open_file" });
|
|
23225
23904
|
}
|
|
@@ -23234,14 +23913,14 @@ Examples:
|
|
|
23234
23913
|
};
|
|
23235
23914
|
}
|
|
23236
23915
|
if (isBlockedExecFile(absolute)) {
|
|
23237
|
-
throw new ToolError(`Execution of sensitive file is blocked: ${
|
|
23916
|
+
throw new ToolError(`Execution of sensitive file is blocked: ${path17__default.basename(absolute)}`, {
|
|
23238
23917
|
tool: "open_file"
|
|
23239
23918
|
});
|
|
23240
23919
|
}
|
|
23241
23920
|
if (args.length > 0 && hasDangerousArgs(args)) {
|
|
23242
23921
|
throw new ToolError("Arguments contain dangerous patterns", { tool: "open_file" });
|
|
23243
23922
|
}
|
|
23244
|
-
const ext =
|
|
23923
|
+
const ext = path17__default.extname(absolute);
|
|
23245
23924
|
const interpreter = getInterpreter(ext);
|
|
23246
23925
|
const executable = await isExecutable(absolute);
|
|
23247
23926
|
let command;
|
|
@@ -23254,7 +23933,7 @@ Examples:
|
|
|
23254
23933
|
cmdArgs = [...args];
|
|
23255
23934
|
} else {
|
|
23256
23935
|
throw new ToolError(
|
|
23257
|
-
`Cannot execute '${
|
|
23936
|
+
`Cannot execute '${path17__default.basename(absolute)}': no known interpreter for '${ext || "(no extension)"}' and file is not executable`,
|
|
23258
23937
|
{ tool: "open_file" }
|
|
23259
23938
|
);
|
|
23260
23939
|
}
|
|
@@ -23306,7 +23985,7 @@ Examples:
|
|
|
23306
23985
|
reason: z.string().optional().describe("Why access is needed (shown to user for context)")
|
|
23307
23986
|
}),
|
|
23308
23987
|
async execute({ path: dirPath, reason }) {
|
|
23309
|
-
const absolute =
|
|
23988
|
+
const absolute = path17__default.resolve(dirPath);
|
|
23310
23989
|
if (isWithinAllowedPath(absolute, "read")) {
|
|
23311
23990
|
return {
|
|
23312
23991
|
authorized: true,
|
|
@@ -23315,8 +23994,8 @@ Examples:
|
|
|
23315
23994
|
};
|
|
23316
23995
|
}
|
|
23317
23996
|
for (const blocked of BLOCKED_SYSTEM_PATHS) {
|
|
23318
|
-
const normalizedBlocked =
|
|
23319
|
-
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked +
|
|
23997
|
+
const normalizedBlocked = path17__default.normalize(blocked);
|
|
23998
|
+
if (absolute === normalizedBlocked || absolute.startsWith(normalizedBlocked + path17__default.sep)) {
|
|
23320
23999
|
return {
|
|
23321
24000
|
authorized: false,
|
|
23322
24001
|
path: absolute,
|
|
@@ -23325,7 +24004,7 @@ Examples:
|
|
|
23325
24004
|
}
|
|
23326
24005
|
}
|
|
23327
24006
|
const cwd = process.cwd();
|
|
23328
|
-
if (absolute ===
|
|
24007
|
+
if (absolute === path17__default.normalize(cwd) || absolute.startsWith(path17__default.normalize(cwd) + path17__default.sep)) {
|
|
23329
24008
|
return {
|
|
23330
24009
|
authorized: true,
|
|
23331
24010
|
path: absolute,
|
|
@@ -23333,7 +24012,7 @@ Examples:
|
|
|
23333
24012
|
};
|
|
23334
24013
|
}
|
|
23335
24014
|
try {
|
|
23336
|
-
const stat2 = await
|
|
24015
|
+
const stat2 = await fs16__default.stat(absolute);
|
|
23337
24016
|
if (!stat2.isDirectory()) {
|
|
23338
24017
|
return {
|
|
23339
24018
|
authorized: false,
|
|
@@ -23349,7 +24028,7 @@ Examples:
|
|
|
23349
24028
|
};
|
|
23350
24029
|
}
|
|
23351
24030
|
const existing = getAllowedPaths();
|
|
23352
|
-
if (existing.some((e) =>
|
|
24031
|
+
if (existing.some((e) => path17__default.normalize(e.path) === path17__default.normalize(absolute))) {
|
|
23353
24032
|
return {
|
|
23354
24033
|
authorized: true,
|
|
23355
24034
|
path: absolute,
|