@corbat-tech/coco 2.35.0 → 2.36.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/README.md +7 -0
- package/dist/cli/index.js +485 -109
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +1268 -1
- package/dist/index.js +2213 -241
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execFileSync,
|
|
2
|
+
import { execFileSync, spawn, execSync, execFile, exec } from 'child_process';
|
|
3
3
|
import { setGlobalDispatcher, EnvHttpProxyAgent } from 'undici';
|
|
4
4
|
import * as fs5 from 'fs';
|
|
5
|
-
import fs5__default, { accessSync, readFileSync, constants as constants$1 } from 'fs';
|
|
5
|
+
import fs5__default, { accessSync, mkdirSync, appendFileSync, readFileSync, writeFileSync, constants as constants$1 } from 'fs';
|
|
6
6
|
import * as path39 from 'path';
|
|
7
7
|
import path39__default, { join, dirname, resolve, basename } from 'path';
|
|
8
8
|
import { URL as URL$1, fileURLToPath } from 'url';
|
|
@@ -10,7 +10,7 @@ import { z } from 'zod';
|
|
|
10
10
|
import * as os4 from 'os';
|
|
11
11
|
import os4__default, { homedir } from 'os';
|
|
12
12
|
import * as fs35 from 'fs/promises';
|
|
13
|
-
import fs35__default, { mkdir, writeFile, readFile, access,
|
|
13
|
+
import fs35__default, { mkdir, writeFile, readFile, access, readdir, rm, constants } from 'fs/promises';
|
|
14
14
|
import JSON5 from 'json5';
|
|
15
15
|
import * as crypto from 'crypto';
|
|
16
16
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
@@ -23,7 +23,7 @@ import Anthropic from '@anthropic-ai/sdk';
|
|
|
23
23
|
import { jsonrepair } from 'jsonrepair';
|
|
24
24
|
import OpenAI from 'openai';
|
|
25
25
|
import { GoogleGenAI, FunctionCallingConfigMode } from '@google/genai';
|
|
26
|
-
import { parse
|
|
26
|
+
import { parse } from 'yaml';
|
|
27
27
|
import { minimatch } from 'minimatch';
|
|
28
28
|
import hljs from 'highlight.js/lib/core';
|
|
29
29
|
import bash from 'highlight.js/lib/languages/bash';
|
|
@@ -42,7 +42,7 @@ import yaml from 'highlight.js/lib/languages/yaml';
|
|
|
42
42
|
import { diffLines, diffWords } from 'diff';
|
|
43
43
|
import { glob } from 'glob';
|
|
44
44
|
import { execa } from 'execa';
|
|
45
|
-
import { parse } from '@typescript-eslint/typescript-estree';
|
|
45
|
+
import { parse as parse$1 } from '@typescript-eslint/typescript-estree';
|
|
46
46
|
import { simpleGit } from 'simple-git';
|
|
47
47
|
import { Marked } from 'marked';
|
|
48
48
|
import { markedTerminal } from 'marked-terminal';
|
|
@@ -893,8 +893,8 @@ async function configExists(configPath, scope = "any") {
|
|
|
893
893
|
}
|
|
894
894
|
return false;
|
|
895
895
|
}
|
|
896
|
-
function getConfigValue(config,
|
|
897
|
-
const keys =
|
|
896
|
+
function getConfigValue(config, path65) {
|
|
897
|
+
const keys = path65.split(".");
|
|
898
898
|
let current = config;
|
|
899
899
|
for (const key of keys) {
|
|
900
900
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -956,6 +956,10 @@ function getCatalogDefaultModel(provider) {
|
|
|
956
956
|
function getCatalogModel(provider, modelId) {
|
|
957
957
|
return getProviderCatalogEntry(provider).models.find((modelEntry) => modelEntry.id === modelId);
|
|
958
958
|
}
|
|
959
|
+
function getCatalogRecommendedModel(provider) {
|
|
960
|
+
const entry = getProviderCatalogEntry(provider);
|
|
961
|
+
return entry.models.find((modelEntry) => modelEntry.recommended) ?? entry.models[0];
|
|
962
|
+
}
|
|
959
963
|
function getCatalogContextWindow(provider, modelId, fallback) {
|
|
960
964
|
if (!modelId) return fallback;
|
|
961
965
|
const exact = getCatalogModel(provider, modelId);
|
|
@@ -9496,9 +9500,9 @@ async function migrateGlobalConfig(oldDir, newConfigPath) {
|
|
|
9496
9500
|
);
|
|
9497
9501
|
}
|
|
9498
9502
|
}
|
|
9499
|
-
async function fileExists(
|
|
9503
|
+
async function fileExists(path65) {
|
|
9500
9504
|
try {
|
|
9501
|
-
await access(
|
|
9505
|
+
await access(path65);
|
|
9502
9506
|
return true;
|
|
9503
9507
|
} catch {
|
|
9504
9508
|
return false;
|
|
@@ -9881,8 +9885,8 @@ var init_registry = __esm({
|
|
|
9881
9885
|
/**
|
|
9882
9886
|
* Ensure directory exists
|
|
9883
9887
|
*/
|
|
9884
|
-
async ensureDir(
|
|
9885
|
-
await mkdir(dirname(
|
|
9888
|
+
async ensureDir(path65) {
|
|
9889
|
+
await mkdir(dirname(path65), { recursive: true });
|
|
9886
9890
|
}
|
|
9887
9891
|
};
|
|
9888
9892
|
}
|
|
@@ -10057,7 +10061,7 @@ function parseSkillMarkdown(raw) {
|
|
|
10057
10061
|
const frontmatter = normalized.slice(3, closeIndex).trim();
|
|
10058
10062
|
const afterMarkerStart = closeIndex + closeMarker.length;
|
|
10059
10063
|
const contentStart = normalized[afterMarkerStart] === "\n" ? afterMarkerStart + 1 : afterMarkerStart;
|
|
10060
|
-
const parsed = frontmatter.length > 0 ? parse
|
|
10064
|
+
const parsed = frontmatter.length > 0 ? parse(frontmatter) : {};
|
|
10061
10065
|
return {
|
|
10062
10066
|
data: parsed && typeof parsed === "object" ? parsed : {},
|
|
10063
10067
|
content: normalized.slice(contentStart)
|
|
@@ -11563,9 +11567,9 @@ function createEmptyMemoryContext() {
|
|
|
11563
11567
|
errors: []
|
|
11564
11568
|
};
|
|
11565
11569
|
}
|
|
11566
|
-
function createMissingMemoryFile(
|
|
11570
|
+
function createMissingMemoryFile(path65, level) {
|
|
11567
11571
|
return {
|
|
11568
|
-
path:
|
|
11572
|
+
path: path65,
|
|
11569
11573
|
level,
|
|
11570
11574
|
content: "",
|
|
11571
11575
|
sections: [],
|
|
@@ -13126,8 +13130,8 @@ __export(trust_store_exports, {
|
|
|
13126
13130
|
saveTrustStore: () => saveTrustStore,
|
|
13127
13131
|
updateLastAccessed: () => updateLastAccessed
|
|
13128
13132
|
});
|
|
13129
|
-
async function ensureDir(
|
|
13130
|
-
await mkdir(dirname(
|
|
13133
|
+
async function ensureDir(path65) {
|
|
13134
|
+
await mkdir(dirname(path65), { recursive: true });
|
|
13131
13135
|
}
|
|
13132
13136
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
13133
13137
|
try {
|
|
@@ -13212,8 +13216,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
13212
13216
|
};
|
|
13213
13217
|
return permissions[level]?.includes(operation) ?? false;
|
|
13214
13218
|
}
|
|
13215
|
-
function normalizePath(
|
|
13216
|
-
return join(
|
|
13219
|
+
function normalizePath(path65) {
|
|
13220
|
+
return join(path65);
|
|
13217
13221
|
}
|
|
13218
13222
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
13219
13223
|
let store = null;
|
|
@@ -13569,12 +13573,12 @@ function humanizeError(message, toolName) {
|
|
|
13569
13573
|
return msg;
|
|
13570
13574
|
}
|
|
13571
13575
|
if (/ENOENT/i.test(msg)) {
|
|
13572
|
-
const
|
|
13573
|
-
return
|
|
13576
|
+
const path65 = extractQuotedPath(msg);
|
|
13577
|
+
return path65 ? `File or directory not found: ${path65}` : "File or directory not found";
|
|
13574
13578
|
}
|
|
13575
13579
|
if (/EACCES/i.test(msg)) {
|
|
13576
|
-
const
|
|
13577
|
-
return
|
|
13580
|
+
const path65 = extractQuotedPath(msg);
|
|
13581
|
+
return path65 ? `Permission denied: ${path65}` : "Permission denied \u2014 check file permissions";
|
|
13578
13582
|
}
|
|
13579
13583
|
if (/EISDIR/i.test(msg)) {
|
|
13580
13584
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -14516,9 +14520,9 @@ var init_diff_renderer = __esm({
|
|
|
14516
14520
|
getTerminalWidth = () => process.stdout.columns || 80;
|
|
14517
14521
|
}
|
|
14518
14522
|
});
|
|
14519
|
-
async function fileExists4(
|
|
14523
|
+
async function fileExists4(path65) {
|
|
14520
14524
|
try {
|
|
14521
|
-
await access(
|
|
14525
|
+
await access(path65);
|
|
14522
14526
|
return true;
|
|
14523
14527
|
} catch {
|
|
14524
14528
|
return false;
|
|
@@ -15461,7 +15465,7 @@ var init_complexity = __esm({
|
|
|
15461
15465
|
* Analyze single file
|
|
15462
15466
|
*/
|
|
15463
15467
|
async analyzeFile(file, content) {
|
|
15464
|
-
const ast = parse(content, {
|
|
15468
|
+
const ast = parse$1(content, {
|
|
15465
15469
|
loc: true,
|
|
15466
15470
|
range: true,
|
|
15467
15471
|
comment: false,
|
|
@@ -16058,7 +16062,7 @@ var init_completeness = __esm({
|
|
|
16058
16062
|
for (const file of files) {
|
|
16059
16063
|
try {
|
|
16060
16064
|
const content = await readFile(file, "utf-8");
|
|
16061
|
-
const ast = parse(content, {
|
|
16065
|
+
const ast = parse$1(content, {
|
|
16062
16066
|
loc: true,
|
|
16063
16067
|
range: true,
|
|
16064
16068
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -16271,7 +16275,7 @@ var init_robustness = __esm({
|
|
|
16271
16275
|
for (const file of targetFiles) {
|
|
16272
16276
|
try {
|
|
16273
16277
|
const content = await readFile(file, "utf-8");
|
|
16274
|
-
const ast = parse(content, {
|
|
16278
|
+
const ast = parse$1(content, {
|
|
16275
16279
|
loc: true,
|
|
16276
16280
|
range: true,
|
|
16277
16281
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -16564,7 +16568,7 @@ var init_documentation = __esm({
|
|
|
16564
16568
|
for (const file of targetFiles) {
|
|
16565
16569
|
try {
|
|
16566
16570
|
const content = await readFile(file, "utf-8");
|
|
16567
|
-
const ast = parse(content, {
|
|
16571
|
+
const ast = parse$1(content, {
|
|
16568
16572
|
loc: true,
|
|
16569
16573
|
range: true,
|
|
16570
16574
|
comment: true,
|
|
@@ -16942,7 +16946,7 @@ var init_readability = __esm({
|
|
|
16942
16946
|
for (const file of targetFiles) {
|
|
16943
16947
|
try {
|
|
16944
16948
|
const content = await readFile(file, "utf-8");
|
|
16945
|
-
const ast = parse(content, {
|
|
16949
|
+
const ast = parse$1(content, {
|
|
16946
16950
|
loc: true,
|
|
16947
16951
|
range: true,
|
|
16948
16952
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -17100,7 +17104,7 @@ var init_maintainability = __esm({
|
|
|
17100
17104
|
try {
|
|
17101
17105
|
const content = await readFile(file, "utf-8");
|
|
17102
17106
|
const lineCount = countLines(content);
|
|
17103
|
-
const ast = parse(content, {
|
|
17107
|
+
const ast = parse$1(content, {
|
|
17104
17108
|
loc: true,
|
|
17105
17109
|
range: true,
|
|
17106
17110
|
jsx: file.endsWith(".tsx") || file.endsWith(".jsx")
|
|
@@ -26985,8 +26989,8 @@ Generated by Corbat-Coco v0.1.0
|
|
|
26985
26989
|
|
|
26986
26990
|
// src/cli/commands/init.ts
|
|
26987
26991
|
function registerInitCommand(program2) {
|
|
26988
|
-
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (
|
|
26989
|
-
await runInit(
|
|
26992
|
+
program2.command("init").description("Initialize a new Corbat-Coco project").argument("[path]", "Project directory path", ".").option("-t, --template <template>", "Project template to use").option("-y, --yes", "Skip prompts and use defaults").option("--skip-discovery", "Skip the discovery phase (use existing spec)").action(async (path65, options) => {
|
|
26993
|
+
await runInit(path65, options);
|
|
26990
26994
|
});
|
|
26991
26995
|
}
|
|
26992
26996
|
async function runInit(projectPath, options) {
|
|
@@ -27065,18 +27069,18 @@ async function gatherProjectInfo() {
|
|
|
27065
27069
|
language
|
|
27066
27070
|
};
|
|
27067
27071
|
}
|
|
27068
|
-
function getDefaultProjectInfo(
|
|
27069
|
-
const name =
|
|
27072
|
+
function getDefaultProjectInfo(path65) {
|
|
27073
|
+
const name = path65 === "." ? "my-project" : path65.split("/").pop() || "my-project";
|
|
27070
27074
|
return {
|
|
27071
27075
|
name,
|
|
27072
27076
|
description: "",
|
|
27073
27077
|
language: "typescript"
|
|
27074
27078
|
};
|
|
27075
27079
|
}
|
|
27076
|
-
async function checkExistingProject(
|
|
27080
|
+
async function checkExistingProject(path65) {
|
|
27077
27081
|
try {
|
|
27078
27082
|
const fs57 = await import('fs/promises');
|
|
27079
|
-
await fs57.access(`${
|
|
27083
|
+
await fs57.access(`${path65}/.coco`);
|
|
27080
27084
|
return true;
|
|
27081
27085
|
} catch {
|
|
27082
27086
|
return false;
|
|
@@ -30577,20 +30581,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
30577
30581
|
},
|
|
30578
30582
|
tools: {
|
|
30579
30583
|
file: {
|
|
30580
|
-
async read(
|
|
30584
|
+
async read(path65) {
|
|
30581
30585
|
const fs57 = await import('fs/promises');
|
|
30582
|
-
return fs57.readFile(
|
|
30586
|
+
return fs57.readFile(path65, "utf-8");
|
|
30583
30587
|
},
|
|
30584
|
-
async write(
|
|
30588
|
+
async write(path65, content) {
|
|
30585
30589
|
const fs57 = await import('fs/promises');
|
|
30586
30590
|
const nodePath = await import('path');
|
|
30587
|
-
await fs57.mkdir(nodePath.dirname(
|
|
30588
|
-
await fs57.writeFile(
|
|
30591
|
+
await fs57.mkdir(nodePath.dirname(path65), { recursive: true });
|
|
30592
|
+
await fs57.writeFile(path65, content, "utf-8");
|
|
30589
30593
|
},
|
|
30590
|
-
async exists(
|
|
30594
|
+
async exists(path65) {
|
|
30591
30595
|
const fs57 = await import('fs/promises');
|
|
30592
30596
|
try {
|
|
30593
|
-
await fs57.access(
|
|
30597
|
+
await fs57.access(path65);
|
|
30594
30598
|
return true;
|
|
30595
30599
|
} catch {
|
|
30596
30600
|
return false;
|
|
@@ -30946,10 +30950,10 @@ function getPhaseStatusForPhase(phase) {
|
|
|
30946
30950
|
}
|
|
30947
30951
|
async function loadProjectState(cwd, config) {
|
|
30948
30952
|
const fs57 = await import('fs/promises');
|
|
30949
|
-
const
|
|
30950
|
-
const statePath =
|
|
30951
|
-
const backlogPath =
|
|
30952
|
-
const checkpointDir =
|
|
30953
|
+
const path65 = await import('path');
|
|
30954
|
+
const statePath = path65.join(cwd, ".coco", "state.json");
|
|
30955
|
+
const backlogPath = path65.join(cwd, ".coco", "planning", "backlog.json");
|
|
30956
|
+
const checkpointDir = path65.join(cwd, ".coco", "checkpoints");
|
|
30953
30957
|
let currentPhase = "idle";
|
|
30954
30958
|
let metrics;
|
|
30955
30959
|
let sprint;
|
|
@@ -32521,8 +32525,8 @@ async function saveConfig2(config) {
|
|
|
32521
32525
|
await fs57.mkdir(dir, { recursive: true });
|
|
32522
32526
|
await fs57.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
32523
32527
|
}
|
|
32524
|
-
function getNestedValue(obj,
|
|
32525
|
-
const keys =
|
|
32528
|
+
function getNestedValue(obj, path65) {
|
|
32529
|
+
const keys = path65.split(".");
|
|
32526
32530
|
let current = obj;
|
|
32527
32531
|
for (const key of keys) {
|
|
32528
32532
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -32532,8 +32536,8 @@ function getNestedValue(obj, path63) {
|
|
|
32532
32536
|
}
|
|
32533
32537
|
return current;
|
|
32534
32538
|
}
|
|
32535
|
-
function setNestedValue(obj,
|
|
32536
|
-
const keys =
|
|
32539
|
+
function setNestedValue(obj, path65, value) {
|
|
32540
|
+
const keys = path65.split(".");
|
|
32537
32541
|
let current = obj;
|
|
32538
32542
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
32539
32543
|
const key = keys[i];
|
|
@@ -33565,9 +33569,9 @@ function registerCheckCommand(program2) {
|
|
|
33565
33569
|
// src/swarm/spec-parser.ts
|
|
33566
33570
|
async function parseSwarmSpec(filePath) {
|
|
33567
33571
|
const fs57 = await import('fs/promises');
|
|
33568
|
-
const
|
|
33572
|
+
const path65 = await import('path');
|
|
33569
33573
|
const rawContent = await fs57.readFile(filePath, "utf-8");
|
|
33570
|
-
const ext =
|
|
33574
|
+
const ext = path65.extname(filePath).toLowerCase();
|
|
33571
33575
|
if (ext === ".yaml" || ext === ".yml") {
|
|
33572
33576
|
return parseYamlSpec(rawContent);
|
|
33573
33577
|
}
|
|
@@ -33897,8 +33901,8 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
33897
33901
|
};
|
|
33898
33902
|
async function loadAgentConfig(projectPath) {
|
|
33899
33903
|
const fs57 = await import('fs/promises');
|
|
33900
|
-
const
|
|
33901
|
-
const configPath =
|
|
33904
|
+
const path65 = await import('path');
|
|
33905
|
+
const configPath = path65.join(projectPath, ".coco", "swarm", "agents.json");
|
|
33902
33906
|
try {
|
|
33903
33907
|
const raw = await fs57.readFile(configPath, "utf-8");
|
|
33904
33908
|
const parsed = JSON.parse(raw);
|
|
@@ -34089,16 +34093,16 @@ async function createBoard(projectPath, spec) {
|
|
|
34089
34093
|
}
|
|
34090
34094
|
async function loadBoard(projectPath) {
|
|
34091
34095
|
const fs57 = await import('fs/promises');
|
|
34092
|
-
const
|
|
34093
|
-
const boardPath =
|
|
34096
|
+
const path65 = await import('path');
|
|
34097
|
+
const boardPath = path65.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
34094
34098
|
const raw = await fs57.readFile(boardPath, "utf-8");
|
|
34095
34099
|
return JSON.parse(raw);
|
|
34096
34100
|
}
|
|
34097
34101
|
async function saveBoard(projectPath, board) {
|
|
34098
34102
|
const fs57 = await import('fs/promises');
|
|
34099
|
-
const
|
|
34100
|
-
const boardDir =
|
|
34101
|
-
const boardPath =
|
|
34103
|
+
const path65 = await import('path');
|
|
34104
|
+
const boardDir = path65.join(projectPath, ".coco", "swarm");
|
|
34105
|
+
const boardPath = path65.join(boardDir, "task-board.json");
|
|
34102
34106
|
await fs57.mkdir(boardDir, { recursive: true });
|
|
34103
34107
|
await fs57.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
34104
34108
|
}
|
|
@@ -34266,9 +34270,9 @@ async function defaultPromptHandler(q) {
|
|
|
34266
34270
|
}
|
|
34267
34271
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
34268
34272
|
const fs57 = await import('fs/promises');
|
|
34269
|
-
const
|
|
34270
|
-
const swarmDir =
|
|
34271
|
-
const assumptionsPath =
|
|
34273
|
+
const path65 = await import('path');
|
|
34274
|
+
const swarmDir = path65.join(projectPath, ".coco", "swarm");
|
|
34275
|
+
const assumptionsPath = path65.join(swarmDir, "assumptions.md");
|
|
34272
34276
|
await fs57.mkdir(swarmDir, { recursive: true });
|
|
34273
34277
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
34274
34278
|
const content = [
|
|
@@ -34292,9 +34296,9 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
34292
34296
|
// src/swarm/events.ts
|
|
34293
34297
|
async function appendSwarmEvent(projectPath, event) {
|
|
34294
34298
|
const fs57 = await import('fs/promises');
|
|
34295
|
-
const
|
|
34296
|
-
const eventsDir =
|
|
34297
|
-
const eventsFile =
|
|
34299
|
+
const path65 = await import('path');
|
|
34300
|
+
const eventsDir = path65.join(projectPath, ".coco", "swarm");
|
|
34301
|
+
const eventsFile = path65.join(eventsDir, "events.jsonl");
|
|
34298
34302
|
await fs57.mkdir(eventsDir, { recursive: true });
|
|
34299
34303
|
await fs57.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
34300
34304
|
}
|
|
@@ -34305,9 +34309,9 @@ function createEventId() {
|
|
|
34305
34309
|
// src/swarm/knowledge.ts
|
|
34306
34310
|
async function appendKnowledge(projectPath, entry) {
|
|
34307
34311
|
const fs57 = await import('fs/promises');
|
|
34308
|
-
const
|
|
34309
|
-
const knowledgeDir =
|
|
34310
|
-
const knowledgeFile =
|
|
34312
|
+
const path65 = await import('path');
|
|
34313
|
+
const knowledgeDir = path65.join(projectPath, ".coco", "swarm");
|
|
34314
|
+
const knowledgeFile = path65.join(knowledgeDir, "knowledge.jsonl");
|
|
34311
34315
|
await fs57.mkdir(knowledgeDir, { recursive: true });
|
|
34312
34316
|
await fs57.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
34313
34317
|
}
|
|
@@ -34614,10 +34618,10 @@ async function runSwarmLifecycle(options) {
|
|
|
34614
34618
|
async function stageInit(ctx) {
|
|
34615
34619
|
const { projectPath, spec } = ctx.options;
|
|
34616
34620
|
const fs57 = await import('fs/promises');
|
|
34617
|
-
const
|
|
34618
|
-
await fs57.mkdir(
|
|
34621
|
+
const path65 = await import('path');
|
|
34622
|
+
await fs57.mkdir(path65.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
34619
34623
|
await fs57.mkdir(ctx.options.outputPath, { recursive: true });
|
|
34620
|
-
const specSummaryPath =
|
|
34624
|
+
const specSummaryPath = path65.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
34621
34625
|
const specSummary = {
|
|
34622
34626
|
projectName: spec.projectName,
|
|
34623
34627
|
description: spec.description,
|
|
@@ -34689,8 +34693,8 @@ async function stagePlan(ctx) {
|
|
|
34689
34693
|
]);
|
|
34690
34694
|
await createBoard(projectPath, spec);
|
|
34691
34695
|
const fs57 = await import('fs/promises');
|
|
34692
|
-
const
|
|
34693
|
-
const planPath =
|
|
34696
|
+
const path65 = await import('path');
|
|
34697
|
+
const planPath = path65.join(projectPath, ".coco", "swarm", "plan.json");
|
|
34694
34698
|
await fs57.writeFile(
|
|
34695
34699
|
planPath,
|
|
34696
34700
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
@@ -34907,7 +34911,7 @@ async function stageIntegrate(ctx) {
|
|
|
34907
34911
|
async function stageOutput(ctx) {
|
|
34908
34912
|
const { projectPath, outputPath } = ctx.options;
|
|
34909
34913
|
const fs57 = await import('fs/promises');
|
|
34910
|
-
const
|
|
34914
|
+
const path65 = await import('path');
|
|
34911
34915
|
const board = await loadBoard(projectPath);
|
|
34912
34916
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
34913
34917
|
const summary = {
|
|
@@ -34922,7 +34926,7 @@ async function stageOutput(ctx) {
|
|
|
34922
34926
|
globalScore: computeGlobalScore(featureResults)
|
|
34923
34927
|
};
|
|
34924
34928
|
await fs57.mkdir(outputPath, { recursive: true });
|
|
34925
|
-
const summaryPath =
|
|
34929
|
+
const summaryPath = path65.join(outputPath, "swarm-summary.json");
|
|
34926
34930
|
await fs57.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
34927
34931
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
34928
34932
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
@@ -35269,8 +35273,8 @@ var SwarmOrchestrator = class {
|
|
|
35269
35273
|
noQuestions = false,
|
|
35270
35274
|
onProgress
|
|
35271
35275
|
} = options;
|
|
35272
|
-
const
|
|
35273
|
-
const projectPath =
|
|
35276
|
+
const path65 = await import('path');
|
|
35277
|
+
const projectPath = path65.dirname(path65.resolve(specFile));
|
|
35274
35278
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
35275
35279
|
const spec = await parseSwarmSpec(specFile);
|
|
35276
35280
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -35281,7 +35285,7 @@ var SwarmOrchestrator = class {
|
|
|
35281
35285
|
await runSwarmLifecycle({
|
|
35282
35286
|
spec,
|
|
35283
35287
|
projectPath,
|
|
35284
|
-
outputPath:
|
|
35288
|
+
outputPath: path65.resolve(outputPath),
|
|
35285
35289
|
provider,
|
|
35286
35290
|
agentConfig,
|
|
35287
35291
|
minScore,
|
|
@@ -39219,8 +39223,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
39219
39223
|
p26.log.message("");
|
|
39220
39224
|
for (const project of projects) {
|
|
39221
39225
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
39222
|
-
const
|
|
39223
|
-
p26.log.message(` [${level}] ${
|
|
39226
|
+
const path65 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
39227
|
+
p26.log.message(` [${level}] ${path65}`);
|
|
39224
39228
|
p26.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
39225
39229
|
}
|
|
39226
39230
|
p26.log.message("");
|
|
@@ -40451,8 +40455,8 @@ function displayRewindResult(result) {
|
|
|
40451
40455
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
40452
40456
|
console.log(`${chalk.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
40453
40457
|
}
|
|
40454
|
-
for (const { path:
|
|
40455
|
-
const fileName =
|
|
40458
|
+
for (const { path: path65, error } of result.filesFailed) {
|
|
40459
|
+
const fileName = path65.split("/").pop() ?? path65;
|
|
40456
40460
|
console.log(`${chalk.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
40457
40461
|
}
|
|
40458
40462
|
if (result.conversationRestored) {
|
|
@@ -40853,6 +40857,9 @@ function getSessionStore() {
|
|
|
40853
40857
|
}
|
|
40854
40858
|
return defaultStore;
|
|
40855
40859
|
}
|
|
40860
|
+
function createSessionStore(config) {
|
|
40861
|
+
return new SessionStore(config);
|
|
40862
|
+
}
|
|
40856
40863
|
|
|
40857
40864
|
// src/cli/repl/commands/resume.ts
|
|
40858
40865
|
function formatRelativeTime2(date) {
|
|
@@ -49993,7 +50000,7 @@ async function validateCode(code, filePath, _language) {
|
|
|
49993
50000
|
const errors = [];
|
|
49994
50001
|
const warnings = [];
|
|
49995
50002
|
try {
|
|
49996
|
-
const ast = parse(code, {
|
|
50003
|
+
const ast = parse$1(code, {
|
|
49997
50004
|
loc: true,
|
|
49998
50005
|
range: true,
|
|
49999
50006
|
comment: true,
|
|
@@ -50120,7 +50127,7 @@ async function analyzeFile(filePath, includeAst = false) {
|
|
|
50120
50127
|
const exports$1 = [];
|
|
50121
50128
|
let ast;
|
|
50122
50129
|
try {
|
|
50123
|
-
ast = parse(content, {
|
|
50130
|
+
ast = parse$1(content, {
|
|
50124
50131
|
loc: true,
|
|
50125
50132
|
range: true,
|
|
50126
50133
|
comment: true,
|
|
@@ -54880,8 +54887,8 @@ function formatToolSummary(toolName, input) {
|
|
|
54880
54887
|
case "grep":
|
|
54881
54888
|
case "search_files": {
|
|
54882
54889
|
const pattern = String(input.pattern || "");
|
|
54883
|
-
const
|
|
54884
|
-
return `"${pattern}"${
|
|
54890
|
+
const path65 = input.path ? ` in ${input.path}` : "";
|
|
54891
|
+
return `"${pattern}"${path65}`;
|
|
54885
54892
|
}
|
|
54886
54893
|
case "bash_exec": {
|
|
54887
54894
|
const cmd = String(input.command || "");
|
|
@@ -54902,8 +54909,8 @@ function formatToolSummary(toolName, input) {
|
|
|
54902
54909
|
function formatUrl(url) {
|
|
54903
54910
|
try {
|
|
54904
54911
|
const u = new URL(url);
|
|
54905
|
-
const
|
|
54906
|
-
const display =
|
|
54912
|
+
const path65 = u.pathname.replace(/\/$/, "");
|
|
54913
|
+
const display = path65 ? `${u.hostname} \u203A ${path65.slice(1)}` : u.hostname;
|
|
54907
54914
|
const max = Math.max(getTerminalWidth2() - 20, 50);
|
|
54908
54915
|
return display.length > max ? display.slice(0, max - 1) + "\u2026" : display;
|
|
54909
54916
|
} catch {
|
|
@@ -55083,6 +55090,12 @@ var RepeatedOutputSuppressor = class {
|
|
|
55083
55090
|
// src/cli/repl/agent-loop.ts
|
|
55084
55091
|
async function executeAgentTurn(session, userMessage, provider, toolRegistry, options = {}) {
|
|
55085
55092
|
resetLineBuffer();
|
|
55093
|
+
session.runtime?.eventLog.record("turn.started", {
|
|
55094
|
+
sessionId: session.id,
|
|
55095
|
+
provider: session.config.provider.type,
|
|
55096
|
+
model: session.config.provider.model,
|
|
55097
|
+
mode: session.agentMode ?? (session.planMode ? "plan" : "build")
|
|
55098
|
+
});
|
|
55086
55099
|
const messageSnapshot = session.messages.length;
|
|
55087
55100
|
addMessage(session, { role: "user", content: userMessage });
|
|
55088
55101
|
const executedTools = [];
|
|
@@ -55099,6 +55112,15 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
55099
55112
|
const readOnlyModeEnabled = session.planMode === true || activeMode?.readOnly === true;
|
|
55100
55113
|
const strictPlanModeEnabled = readOnlyModeEnabled && session.config.agent.planModeStrict === true;
|
|
55101
55114
|
const outputOffloadObservationEnabled = session.config.agent.outputOffload === true;
|
|
55115
|
+
const recordToolSkipped = (toolCall, reason) => {
|
|
55116
|
+
session.runtime?.eventLog.record("tool.skipped", {
|
|
55117
|
+
sessionId: session.id,
|
|
55118
|
+
tool: toolCall.name,
|
|
55119
|
+
toolCallId: toolCall.id,
|
|
55120
|
+
reason
|
|
55121
|
+
});
|
|
55122
|
+
options.onToolSkipped?.(toolCall, reason);
|
|
55123
|
+
};
|
|
55102
55124
|
const buildQualityMetrics = () => computeTurnQualityMetrics({
|
|
55103
55125
|
iterationsUsed: iteration,
|
|
55104
55126
|
maxIterations,
|
|
@@ -55110,7 +55132,7 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
55110
55132
|
});
|
|
55111
55133
|
const abortReturn = () => {
|
|
55112
55134
|
session.messages.length = messageSnapshot;
|
|
55113
|
-
|
|
55135
|
+
const result2 = {
|
|
55114
55136
|
content: finalContent,
|
|
55115
55137
|
toolCalls: executedTools,
|
|
55116
55138
|
usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
|
|
@@ -55119,6 +55141,14 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
55119
55141
|
partialContent: finalContent || void 0,
|
|
55120
55142
|
abortReason: "user_cancel"
|
|
55121
55143
|
};
|
|
55144
|
+
session.runtime?.eventLog.record("turn.completed", {
|
|
55145
|
+
sessionId: session.id,
|
|
55146
|
+
aborted: true,
|
|
55147
|
+
toolsExecuted: executedTools.length,
|
|
55148
|
+
inputTokens: totalInputTokens,
|
|
55149
|
+
outputTokens: totalOutputTokens
|
|
55150
|
+
});
|
|
55151
|
+
return result2;
|
|
55122
55152
|
};
|
|
55123
55153
|
const allTools = toolRegistry.getToolDefinitionsForLLM();
|
|
55124
55154
|
const tools = readOnlyModeEnabled ? strictPlanModeEnabled ? filterStrictPlanModeTools(allTools) : filterReadOnlyTools(allTools) : allTools;
|
|
@@ -55441,10 +55471,20 @@ ${tail}`;
|
|
|
55441
55471
|
return abortReturn();
|
|
55442
55472
|
}
|
|
55443
55473
|
if (classification.kind === "provider_non_retryable") {
|
|
55474
|
+
session.runtime?.eventLog.record("turn.failed", {
|
|
55475
|
+
sessionId: session.id,
|
|
55476
|
+
error: classification.original instanceof Error ? classification.original.message : String(classification.original),
|
|
55477
|
+
toolsExecuted: executedTools.length
|
|
55478
|
+
});
|
|
55444
55479
|
throw classification.original;
|
|
55445
55480
|
}
|
|
55446
55481
|
hadTurnError = true;
|
|
55447
55482
|
const errorMsg = classification.message;
|
|
55483
|
+
session.runtime?.eventLog.record("turn.failed", {
|
|
55484
|
+
sessionId: session.id,
|
|
55485
|
+
error: errorMsg,
|
|
55486
|
+
toolsExecuted: executedTools.length
|
|
55487
|
+
});
|
|
55448
55488
|
addMessage(session, {
|
|
55449
55489
|
role: "assistant",
|
|
55450
55490
|
content: `[Error during streaming: ${errorMsg}]`
|
|
@@ -55550,7 +55590,7 @@ ${tail}`;
|
|
|
55550
55590
|
toolCall.id,
|
|
55551
55591
|
`User explicitly requested MCP, but the model selected '${toolCall.name}' instead. Use an MCP tool (${availableMcpToolNames.join(", ")}) for this service access.`
|
|
55552
55592
|
);
|
|
55553
|
-
|
|
55593
|
+
recordToolSkipped(toolCall, "Use MCP tool instead of generic fetch");
|
|
55554
55594
|
continue;
|
|
55555
55595
|
}
|
|
55556
55596
|
if (shouldBlockShellMcpInspection(toolCall)) {
|
|
@@ -55558,7 +55598,7 @@ ${tail}`;
|
|
|
55558
55598
|
toolCall.id,
|
|
55559
55599
|
"Use the native mcp_list_servers tool to inspect configured and connected MCP services in this session. Do not shell out to `coco mcp ...` for runtime MCP diagnosis unless the user explicitly asked for the CLI command."
|
|
55560
55600
|
);
|
|
55561
|
-
|
|
55601
|
+
recordToolSkipped(toolCall, "Use mcp_list_servers instead of coco mcp CLI");
|
|
55562
55602
|
continue;
|
|
55563
55603
|
}
|
|
55564
55604
|
if (strictPlanModeEnabled && !STRICT_PLAN_MODE_ALLOWED_TOOLS.has(toolCall.name)) {
|
|
@@ -55566,7 +55606,7 @@ ${tail}`;
|
|
|
55566
55606
|
toolCall.id,
|
|
55567
55607
|
`Blocked by strict plan mode: tool '${toolCall.name}' is not read-only`
|
|
55568
55608
|
);
|
|
55569
|
-
|
|
55609
|
+
recordToolSkipped(toolCall, "Blocked by strict plan mode");
|
|
55570
55610
|
continue;
|
|
55571
55611
|
}
|
|
55572
55612
|
const trustPattern = getTrustPattern(toolCall.name, toolCall.input);
|
|
@@ -55579,7 +55619,7 @@ ${tail}`;
|
|
|
55579
55619
|
} catch (confirmError) {
|
|
55580
55620
|
options.onAfterConfirmation?.();
|
|
55581
55621
|
declinedTools.set(toolCall.id, "Confirmation failed");
|
|
55582
|
-
|
|
55622
|
+
recordToolSkipped(
|
|
55583
55623
|
toolCall,
|
|
55584
55624
|
`Confirmation failed: ${confirmError instanceof Error ? confirmError.message : String(confirmError)}`
|
|
55585
55625
|
);
|
|
@@ -55598,7 +55638,7 @@ ${tail}`;
|
|
|
55598
55638
|
switch (confirmResult) {
|
|
55599
55639
|
case "no":
|
|
55600
55640
|
declinedTools.set(toolCall.id, "User declined");
|
|
55601
|
-
|
|
55641
|
+
recordToolSkipped(toolCall, "User declined");
|
|
55602
55642
|
continue;
|
|
55603
55643
|
case "abort":
|
|
55604
55644
|
turnAborted = true;
|
|
@@ -55628,15 +55668,33 @@ ${tail}`;
|
|
|
55628
55668
|
onToolStart: (toolCall, _index, _total) => {
|
|
55629
55669
|
const originalIndex = response.toolCalls.findIndex((tc) => tc.id === toolCall.id) + 1;
|
|
55630
55670
|
options.onToolStart?.(toolCall, originalIndex, totalTools);
|
|
55671
|
+
session.runtime?.eventLog.record("tool.started", {
|
|
55672
|
+
sessionId: session.id,
|
|
55673
|
+
tool: toolCall.name,
|
|
55674
|
+
toolCallId: toolCall.id,
|
|
55675
|
+
index: originalIndex,
|
|
55676
|
+
total: totalTools
|
|
55677
|
+
});
|
|
55678
|
+
},
|
|
55679
|
+
onToolEnd: (result2) => {
|
|
55680
|
+
session.runtime?.eventLog.record("tool.completed", {
|
|
55681
|
+
sessionId: session.id,
|
|
55682
|
+
tool: result2.name,
|
|
55683
|
+
toolCallId: result2.id,
|
|
55684
|
+
success: result2.result.success,
|
|
55685
|
+
duration: result2.duration
|
|
55686
|
+
});
|
|
55687
|
+
options.onToolEnd?.(result2);
|
|
55688
|
+
},
|
|
55689
|
+
onToolSkipped: (toolCall, reason) => {
|
|
55690
|
+
recordToolSkipped(toolCall, reason);
|
|
55631
55691
|
},
|
|
55632
|
-
onToolEnd: options.onToolEnd,
|
|
55633
|
-
onToolSkipped: options.onToolSkipped,
|
|
55634
55692
|
signal: options.signal,
|
|
55635
55693
|
onPathAccessDenied: async (dirPath) => {
|
|
55636
55694
|
options.onBeforeConfirmation?.();
|
|
55637
|
-
const
|
|
55695
|
+
const result2 = await promptAllowPath(dirPath);
|
|
55638
55696
|
options.onAfterConfirmation?.();
|
|
55639
|
-
return
|
|
55697
|
+
return result2;
|
|
55640
55698
|
},
|
|
55641
55699
|
// Pass hooks through so PreToolUse/PostToolUse hooks fire during execution
|
|
55642
55700
|
hookRegistry: options.hookRegistry,
|
|
@@ -55910,13 +55968,21 @@ I have reached the maximum iteration limit (${maxIterations}). The task may be i
|
|
|
55910
55968
|
}
|
|
55911
55969
|
}
|
|
55912
55970
|
options.onStream?.({ type: "done" });
|
|
55913
|
-
|
|
55971
|
+
const result = {
|
|
55914
55972
|
content: finalContent,
|
|
55915
55973
|
toolCalls: executedTools,
|
|
55916
55974
|
usage: { inputTokens: totalInputTokens, outputTokens: totalOutputTokens },
|
|
55917
55975
|
quality: buildQualityMetrics(),
|
|
55918
55976
|
aborted: false
|
|
55919
55977
|
};
|
|
55978
|
+
session.runtime?.eventLog.record("turn.completed", {
|
|
55979
|
+
sessionId: session.id,
|
|
55980
|
+
aborted: false,
|
|
55981
|
+
toolsExecuted: executedTools.length,
|
|
55982
|
+
inputTokens: totalInputTokens,
|
|
55983
|
+
outputTokens: totalOutputTokens
|
|
55984
|
+
});
|
|
55985
|
+
return result;
|
|
55920
55986
|
}
|
|
55921
55987
|
function formatAbortSummary(executedTools) {
|
|
55922
55988
|
if (executedTools.length === 0) return null;
|
|
@@ -56307,6 +56373,9 @@ var statsCommand = {
|
|
|
56307
56373
|
console.log(` Model: ${chalk.cyan(session.config.provider.model)}`);
|
|
56308
56374
|
console.log(` Endpoint: ${chalk.yellow(runtime.endpoint)}`);
|
|
56309
56375
|
console.log(` Mode: ${session.agentMode ?? (session.planMode ? "plan" : "build")}`);
|
|
56376
|
+
if (session.runtime) {
|
|
56377
|
+
console.log(` Runtime events: ${chalk.yellow(String(session.runtime.eventLog.count()))}`);
|
|
56378
|
+
}
|
|
56310
56379
|
console.log();
|
|
56311
56380
|
console.log(chalk.dim(" Messages:"));
|
|
56312
56381
|
console.log(chalk.dim(` user: ${userMessages}`));
|
|
@@ -57302,6 +57371,295 @@ function createSpinner(message) {
|
|
|
57302
57371
|
// src/cli/repl/index.ts
|
|
57303
57372
|
init_error_resilience();
|
|
57304
57373
|
init_providers();
|
|
57374
|
+
|
|
57375
|
+
// src/runtime/agent-runtime.ts
|
|
57376
|
+
init_env();
|
|
57377
|
+
var InMemoryEventLog = class {
|
|
57378
|
+
events = [];
|
|
57379
|
+
record(type, data = {}) {
|
|
57380
|
+
const event = {
|
|
57381
|
+
id: randomUUID(),
|
|
57382
|
+
type,
|
|
57383
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
57384
|
+
data
|
|
57385
|
+
};
|
|
57386
|
+
this.events.push(event);
|
|
57387
|
+
return event;
|
|
57388
|
+
}
|
|
57389
|
+
list() {
|
|
57390
|
+
return [...this.events];
|
|
57391
|
+
}
|
|
57392
|
+
count() {
|
|
57393
|
+
return this.events.length;
|
|
57394
|
+
}
|
|
57395
|
+
clear() {
|
|
57396
|
+
this.events = [];
|
|
57397
|
+
}
|
|
57398
|
+
};
|
|
57399
|
+
var FileEventLog = class {
|
|
57400
|
+
constructor(filePath) {
|
|
57401
|
+
this.filePath = filePath;
|
|
57402
|
+
try {
|
|
57403
|
+
mkdirSync(dirname(filePath), { recursive: true });
|
|
57404
|
+
} catch {
|
|
57405
|
+
this.writable = false;
|
|
57406
|
+
}
|
|
57407
|
+
}
|
|
57408
|
+
filePath;
|
|
57409
|
+
memory = new InMemoryEventLog();
|
|
57410
|
+
writable = true;
|
|
57411
|
+
record(type, data = {}) {
|
|
57412
|
+
const event = this.memory.record(type, data);
|
|
57413
|
+
if (this.writable) {
|
|
57414
|
+
try {
|
|
57415
|
+
appendFileSync(this.filePath, JSON.stringify(event) + "\n", "utf-8");
|
|
57416
|
+
} catch {
|
|
57417
|
+
this.writable = false;
|
|
57418
|
+
}
|
|
57419
|
+
}
|
|
57420
|
+
return event;
|
|
57421
|
+
}
|
|
57422
|
+
list() {
|
|
57423
|
+
if (!this.writable) return this.memory.list();
|
|
57424
|
+
try {
|
|
57425
|
+
const raw = readFileSync(this.filePath, "utf-8");
|
|
57426
|
+
return raw.split("\n").filter(Boolean).flatMap((line) => {
|
|
57427
|
+
try {
|
|
57428
|
+
return [JSON.parse(line)];
|
|
57429
|
+
} catch {
|
|
57430
|
+
return [];
|
|
57431
|
+
}
|
|
57432
|
+
});
|
|
57433
|
+
} catch {
|
|
57434
|
+
return this.memory.list();
|
|
57435
|
+
}
|
|
57436
|
+
}
|
|
57437
|
+
count() {
|
|
57438
|
+
return this.list().length;
|
|
57439
|
+
}
|
|
57440
|
+
clear() {
|
|
57441
|
+
this.memory.clear();
|
|
57442
|
+
if (this.writable) {
|
|
57443
|
+
try {
|
|
57444
|
+
writeFileSync(this.filePath, "", "utf-8");
|
|
57445
|
+
} catch {
|
|
57446
|
+
this.writable = false;
|
|
57447
|
+
}
|
|
57448
|
+
}
|
|
57449
|
+
}
|
|
57450
|
+
};
|
|
57451
|
+
function createEventLog() {
|
|
57452
|
+
return new InMemoryEventLog();
|
|
57453
|
+
}
|
|
57454
|
+
function createFileEventLog(filePath) {
|
|
57455
|
+
return new FileEventLog(filePath);
|
|
57456
|
+
}
|
|
57457
|
+
|
|
57458
|
+
// src/runtime/permission-policy.ts
|
|
57459
|
+
var READ_ONLY_CATEGORIES = /* @__PURE__ */ new Set(["search", "web", "document"]);
|
|
57460
|
+
var WRITE_CATEGORIES = /* @__PURE__ */ new Set(["file", "git", "test", "build", "memory"]);
|
|
57461
|
+
var READ_ONLY_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
57462
|
+
"glob",
|
|
57463
|
+
"read_file",
|
|
57464
|
+
"list_dir",
|
|
57465
|
+
"tree",
|
|
57466
|
+
"grep",
|
|
57467
|
+
"find_in_file",
|
|
57468
|
+
"semantic_search",
|
|
57469
|
+
"codebase_map",
|
|
57470
|
+
"repo_context",
|
|
57471
|
+
"lsp_status",
|
|
57472
|
+
"lsp_document_symbols",
|
|
57473
|
+
"lsp_workspace_symbols",
|
|
57474
|
+
"lsp_definition",
|
|
57475
|
+
"lsp_references",
|
|
57476
|
+
"git_status",
|
|
57477
|
+
"git_log",
|
|
57478
|
+
"git_diff",
|
|
57479
|
+
"git_show",
|
|
57480
|
+
"git_branch",
|
|
57481
|
+
"recall_memory",
|
|
57482
|
+
"list_memories",
|
|
57483
|
+
"list_checkpoints",
|
|
57484
|
+
"spawnSimpleAgent",
|
|
57485
|
+
"checkAgentCapability"
|
|
57486
|
+
]);
|
|
57487
|
+
var WRITE_CAPABLE_TOOL_NAMES = /* @__PURE__ */ new Set(["run_linter"]);
|
|
57488
|
+
var DESTRUCTIVE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
57489
|
+
"bash_exec",
|
|
57490
|
+
"write_file",
|
|
57491
|
+
"edit_file",
|
|
57492
|
+
"delete_file",
|
|
57493
|
+
"restore_checkpoint",
|
|
57494
|
+
"git_commit",
|
|
57495
|
+
"git_push"
|
|
57496
|
+
]);
|
|
57497
|
+
function riskForTool(tool) {
|
|
57498
|
+
if (READ_ONLY_TOOL_NAMES.has(tool.name)) return "read-only";
|
|
57499
|
+
if (DESTRUCTIVE_TOOL_NAMES.has(tool.name)) return "destructive";
|
|
57500
|
+
if (WRITE_CAPABLE_TOOL_NAMES.has(tool.name)) return "write";
|
|
57501
|
+
if (tool.category === "web") return "network";
|
|
57502
|
+
if (WRITE_CATEGORIES.has(tool.category)) return "write";
|
|
57503
|
+
if (tool.category === "quality") return "write";
|
|
57504
|
+
return "read-only";
|
|
57505
|
+
}
|
|
57506
|
+
var DefaultPermissionPolicy = class {
|
|
57507
|
+
canExecuteTool(mode, tool) {
|
|
57508
|
+
const definition = getAgentMode(mode);
|
|
57509
|
+
const risk = riskForTool(tool);
|
|
57510
|
+
const readOnlyTool = READ_ONLY_TOOL_NAMES.has(tool.name) || READ_ONLY_CATEGORIES.has(tool.category);
|
|
57511
|
+
if (definition.readOnly && !readOnlyTool) {
|
|
57512
|
+
return {
|
|
57513
|
+
allowed: false,
|
|
57514
|
+
reason: `${definition.label} mode is read-only; ${tool.name} is a ${tool.category} tool.`,
|
|
57515
|
+
risk
|
|
57516
|
+
};
|
|
57517
|
+
}
|
|
57518
|
+
if (risk === "destructive") {
|
|
57519
|
+
return {
|
|
57520
|
+
allowed: true,
|
|
57521
|
+
requiresConfirmation: true,
|
|
57522
|
+
reason: `${tool.name} can change repository state and should be confirmed.`,
|
|
57523
|
+
risk
|
|
57524
|
+
};
|
|
57525
|
+
}
|
|
57526
|
+
return { allowed: true, risk };
|
|
57527
|
+
}
|
|
57528
|
+
};
|
|
57529
|
+
function createPermissionPolicy() {
|
|
57530
|
+
return new DefaultPermissionPolicy();
|
|
57531
|
+
}
|
|
57532
|
+
|
|
57533
|
+
// src/runtime/provider-registry.ts
|
|
57534
|
+
init_providers();
|
|
57535
|
+
init_catalog();
|
|
57536
|
+
init_runtime_capabilities();
|
|
57537
|
+
var ProviderRegistry = class {
|
|
57538
|
+
listProviders() {
|
|
57539
|
+
return Object.values(PROVIDER_CATALOG);
|
|
57540
|
+
}
|
|
57541
|
+
getProvider(provider) {
|
|
57542
|
+
return getProviderCatalogEntry(provider);
|
|
57543
|
+
}
|
|
57544
|
+
listModels(provider) {
|
|
57545
|
+
return this.getProvider(provider).models;
|
|
57546
|
+
}
|
|
57547
|
+
getModel(provider, model2) {
|
|
57548
|
+
return getCatalogModel(provider, model2);
|
|
57549
|
+
}
|
|
57550
|
+
getDefaultModel(provider) {
|
|
57551
|
+
return getCatalogDefaultModel(provider);
|
|
57552
|
+
}
|
|
57553
|
+
getRecommendedModel(provider) {
|
|
57554
|
+
return getCatalogRecommendedModel(provider);
|
|
57555
|
+
}
|
|
57556
|
+
getCapability(provider, model2) {
|
|
57557
|
+
return getProviderRuntimeCapability(provider, model2);
|
|
57558
|
+
}
|
|
57559
|
+
async createProvider(provider, config = {}) {
|
|
57560
|
+
return createProvider(provider, config);
|
|
57561
|
+
}
|
|
57562
|
+
async probe(provider, model2, checkAvailability) {
|
|
57563
|
+
return probeProviderRuntimeCapability(provider, model2, checkAvailability);
|
|
57564
|
+
}
|
|
57565
|
+
};
|
|
57566
|
+
function createProviderRegistry() {
|
|
57567
|
+
return new ProviderRegistry();
|
|
57568
|
+
}
|
|
57569
|
+
|
|
57570
|
+
// src/runtime/agent-runtime.ts
|
|
57571
|
+
var AgentRuntime = class {
|
|
57572
|
+
constructor(options) {
|
|
57573
|
+
this.options = options;
|
|
57574
|
+
this.providerRegistry = createProviderRegistry();
|
|
57575
|
+
this.toolRegistry = options.toolRegistry ?? createFullToolRegistry();
|
|
57576
|
+
this.sessionStore = options.sessionStore ?? createSessionStore({});
|
|
57577
|
+
this.permissionPolicy = options.permissionPolicy ?? createPermissionPolicy();
|
|
57578
|
+
this.eventLog = options.eventLog ?? (options.eventLogPath ? createFileEventLog(options.eventLogPath) : createEventLog());
|
|
57579
|
+
this.providerType = options.providerType;
|
|
57580
|
+
this.model = options.model ?? options.providerConfig?.model ?? getDefaultModel(options.providerType);
|
|
57581
|
+
}
|
|
57582
|
+
options;
|
|
57583
|
+
providerRegistry;
|
|
57584
|
+
toolRegistry;
|
|
57585
|
+
sessionStore;
|
|
57586
|
+
permissionPolicy;
|
|
57587
|
+
eventLog;
|
|
57588
|
+
providerType;
|
|
57589
|
+
model;
|
|
57590
|
+
async initialize() {
|
|
57591
|
+
const providerInjected = Boolean(this.options.provider);
|
|
57592
|
+
const provider = this.options.provider ?? await this.providerRegistry.createProvider(this.providerType, {
|
|
57593
|
+
...this.options.providerConfig,
|
|
57594
|
+
model: this.getModel()
|
|
57595
|
+
});
|
|
57596
|
+
this.publishToGlobalBridge(provider);
|
|
57597
|
+
this.eventLog.record(providerInjected ? "provider.attached" : "provider.created", {
|
|
57598
|
+
provider: this.providerType,
|
|
57599
|
+
model: this.getModel(),
|
|
57600
|
+
createdByRuntime: !providerInjected
|
|
57601
|
+
});
|
|
57602
|
+
this.eventLog.record("runtime.initialized", { snapshot: this.snapshot() });
|
|
57603
|
+
}
|
|
57604
|
+
getModel() {
|
|
57605
|
+
return this.model;
|
|
57606
|
+
}
|
|
57607
|
+
updateProvider(providerType, model2, provider) {
|
|
57608
|
+
this.providerType = providerType;
|
|
57609
|
+
this.model = model2 ?? getDefaultModel(providerType);
|
|
57610
|
+
this.publishToGlobalBridge(provider);
|
|
57611
|
+
this.eventLog.record("provider.updated", {
|
|
57612
|
+
provider: this.providerType,
|
|
57613
|
+
model: this.model
|
|
57614
|
+
});
|
|
57615
|
+
}
|
|
57616
|
+
publishToGlobalBridge(provider) {
|
|
57617
|
+
if (this.options.publishToGlobalBridge !== true) return;
|
|
57618
|
+
setAgentProvider(provider);
|
|
57619
|
+
setAgentToolRegistry(this.toolRegistry);
|
|
57620
|
+
}
|
|
57621
|
+
snapshot() {
|
|
57622
|
+
const capability = this.providerRegistry.getCapability(this.providerType, this.getModel());
|
|
57623
|
+
const toolNames = this.toolRegistry.getAll().map((tool) => tool.name).sort();
|
|
57624
|
+
return {
|
|
57625
|
+
provider: {
|
|
57626
|
+
type: this.providerType,
|
|
57627
|
+
model: this.getModel(),
|
|
57628
|
+
capability
|
|
57629
|
+
},
|
|
57630
|
+
tools: {
|
|
57631
|
+
count: toolNames.length,
|
|
57632
|
+
names: toolNames
|
|
57633
|
+
},
|
|
57634
|
+
modes: listAgentModes()
|
|
57635
|
+
};
|
|
57636
|
+
}
|
|
57637
|
+
assertToolAllowed(mode, toolName) {
|
|
57638
|
+
const tool = this.toolRegistry.get(toolName);
|
|
57639
|
+
if (!tool) {
|
|
57640
|
+
this.eventLog.record("tool.blocked", {
|
|
57641
|
+
mode,
|
|
57642
|
+
tool: toolName,
|
|
57643
|
+
reason: "Tool not registered."
|
|
57644
|
+
});
|
|
57645
|
+
return false;
|
|
57646
|
+
}
|
|
57647
|
+
const decision = this.permissionPolicy.canExecuteTool(mode, tool);
|
|
57648
|
+
this.eventLog.record(decision.allowed ? "tool.allowed" : "tool.blocked", {
|
|
57649
|
+
mode,
|
|
57650
|
+
tool: toolName,
|
|
57651
|
+
...decision
|
|
57652
|
+
});
|
|
57653
|
+
return decision.allowed;
|
|
57654
|
+
}
|
|
57655
|
+
};
|
|
57656
|
+
async function createAgentRuntime(options) {
|
|
57657
|
+
const runtime = new AgentRuntime(options);
|
|
57658
|
+
await runtime.initialize();
|
|
57659
|
+
return runtime;
|
|
57660
|
+
}
|
|
57661
|
+
|
|
57662
|
+
// src/cli/repl/index.ts
|
|
57305
57663
|
init_version();
|
|
57306
57664
|
init_trust_store();
|
|
57307
57665
|
|
|
@@ -57854,9 +58212,15 @@ async function startRepl(options = {}) {
|
|
|
57854
58212
|
loadFullAccessPreference2(),
|
|
57855
58213
|
loadFullPowerRiskPreference2()
|
|
57856
58214
|
]);
|
|
57857
|
-
const
|
|
57858
|
-
|
|
57859
|
-
|
|
58215
|
+
const runtime = await createAgentRuntime({
|
|
58216
|
+
providerType: internalProviderId,
|
|
58217
|
+
model: session.config.provider.model || void 0,
|
|
58218
|
+
provider,
|
|
58219
|
+
eventLogPath: path39__default.join(projectPath, ".coco", "events", `${session.id}.jsonl`),
|
|
58220
|
+
publishToGlobalBridge: true
|
|
58221
|
+
});
|
|
58222
|
+
session.runtime = runtime;
|
|
58223
|
+
const toolRegistry = runtime.toolRegistry;
|
|
57860
58224
|
try {
|
|
57861
58225
|
const { createUnifiedSkillRegistry: createUnifiedSkillRegistry2 } = await Promise.resolve().then(() => (init_skills(), skills_exports));
|
|
57862
58226
|
const { getBuiltinSkillsForDiscovery: getBuiltinSkillsForDiscovery2 } = await Promise.resolve().then(() => (init_skills2(), skills_exports2));
|
|
@@ -58040,7 +58404,7 @@ async function startRepl(options = {}) {
|
|
|
58040
58404
|
let consecutiveErrors = 0;
|
|
58041
58405
|
const AUTO_SWITCH_THRESHOLD = 2;
|
|
58042
58406
|
const autoSwitchHistory = /* @__PURE__ */ new Set();
|
|
58043
|
-
const enableAutoSwitchProvider = session.config.agent
|
|
58407
|
+
const enableAutoSwitchProvider = session.config.agent?.enableAutoSwitchProvider === true;
|
|
58044
58408
|
const buildReplayMessage = (message) => {
|
|
58045
58409
|
if (typeof message === "string") {
|
|
58046
58410
|
const trimmed = message.trim();
|
|
@@ -58143,7 +58507,8 @@ async function startRepl(options = {}) {
|
|
|
58143
58507
|
provider = nextProvider;
|
|
58144
58508
|
session.config.provider.type = candidate;
|
|
58145
58509
|
session.config.provider.model = getDefaultModel(candidate);
|
|
58146
|
-
|
|
58510
|
+
runtime.updateProvider(nextInternalId, session.config.provider.model, provider);
|
|
58511
|
+
session.runtime = runtime;
|
|
58147
58512
|
initializeContextManager(session, provider);
|
|
58148
58513
|
llmClassifier = createLLMClassifier2(provider);
|
|
58149
58514
|
autoSwitchHistory.add(edge);
|
|
@@ -58205,7 +58570,12 @@ async function startRepl(options = {}) {
|
|
|
58205
58570
|
project: session.config.provider.project ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"],
|
|
58206
58571
|
location: session.config.provider.location ?? process.env["VERTEX_LOCATION"] ?? process.env["GOOGLE_CLOUD_LOCATION"]
|
|
58207
58572
|
});
|
|
58208
|
-
|
|
58573
|
+
runtime.updateProvider(
|
|
58574
|
+
newInternalId,
|
|
58575
|
+
session.config.provider.model || void 0,
|
|
58576
|
+
provider
|
|
58577
|
+
);
|
|
58578
|
+
session.runtime = runtime;
|
|
58209
58579
|
initializeContextManager(session, provider);
|
|
58210
58580
|
} catch (err) {
|
|
58211
58581
|
session.config.provider.type = prevProviderType;
|
|
@@ -59118,9 +59488,15 @@ ${stdinContent}
|
|
|
59118
59488
|
const provider = await createProvider(providerType, {
|
|
59119
59489
|
model: session.config.provider.model || void 0
|
|
59120
59490
|
});
|
|
59121
|
-
const
|
|
59122
|
-
|
|
59123
|
-
|
|
59491
|
+
const runtime = await createAgentRuntime({
|
|
59492
|
+
providerType,
|
|
59493
|
+
model: session.config.provider.model || void 0,
|
|
59494
|
+
provider,
|
|
59495
|
+
eventLogPath: path39__default.join(options.projectPath, ".coco", "events", `${session.id}.jsonl`),
|
|
59496
|
+
publishToGlobalBridge: true
|
|
59497
|
+
});
|
|
59498
|
+
session.runtime = runtime;
|
|
59499
|
+
const toolRegistry = runtime.toolRegistry;
|
|
59124
59500
|
await loadAllowedPaths(options.projectPath);
|
|
59125
59501
|
await initializeContextManager(session, provider);
|
|
59126
59502
|
const result = await executeAgentTurn(session, task, provider, toolRegistry, {
|