@corbat-tech/coco 2.28.3 → 2.28.5
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 +5 -0
- package/dist/cli/index.js +1009 -672
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as fs5 from 'fs';
|
|
3
|
-
import fs5__default, { accessSync, readFileSync, constants } from 'fs';
|
|
3
|
+
import fs5__default, { accessSync, readFileSync, constants as constants$1 } from 'fs';
|
|
4
4
|
import * as path39 from 'path';
|
|
5
5
|
import path39__default, { join, dirname, resolve, basename } from 'path';
|
|
6
6
|
import { URL as URL$1, fileURLToPath } from 'url';
|
|
@@ -8,7 +8,7 @@ import { z } from 'zod';
|
|
|
8
8
|
import * as os4 from 'os';
|
|
9
9
|
import os4__default, { homedir } from 'os';
|
|
10
10
|
import * as fs35 from 'fs/promises';
|
|
11
|
-
import fs35__default, { mkdir, writeFile, readFile, access, readdir, rm } from 'fs/promises';
|
|
11
|
+
import fs35__default, { mkdir, writeFile, readFile, access, constants, readdir, rm } from 'fs/promises';
|
|
12
12
|
import JSON5 from 'json5';
|
|
13
13
|
import * as crypto from 'crypto';
|
|
14
14
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
@@ -707,8 +707,8 @@ async function configExists(configPath, scope = "any") {
|
|
|
707
707
|
}
|
|
708
708
|
return false;
|
|
709
709
|
}
|
|
710
|
-
function getConfigValue(config,
|
|
711
|
-
const keys =
|
|
710
|
+
function getConfigValue(config, path62) {
|
|
711
|
+
const keys = path62.split(".");
|
|
712
712
|
let current = config;
|
|
713
713
|
for (const key of keys) {
|
|
714
714
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -6980,7 +6980,7 @@ var init_fallback = __esm({
|
|
|
6980
6980
|
*/
|
|
6981
6981
|
async initialize(config) {
|
|
6982
6982
|
const results = await Promise.allSettled(
|
|
6983
|
-
this.providers.map((
|
|
6983
|
+
this.providers.map((p47) => p47.provider.initialize(config))
|
|
6984
6984
|
);
|
|
6985
6985
|
const anySuccess = results.some((r) => r.status === "fulfilled");
|
|
6986
6986
|
if (!anySuccess) {
|
|
@@ -7102,11 +7102,11 @@ var init_fallback = __esm({
|
|
|
7102
7102
|
*/
|
|
7103
7103
|
async isAvailable() {
|
|
7104
7104
|
const results = await Promise.all(
|
|
7105
|
-
this.providers.map(async (
|
|
7106
|
-
if (
|
|
7105
|
+
this.providers.map(async (p47) => {
|
|
7106
|
+
if (p47.breaker.isOpen()) {
|
|
7107
7107
|
return false;
|
|
7108
7108
|
}
|
|
7109
|
-
return
|
|
7109
|
+
return p47.provider.isAvailable();
|
|
7110
7110
|
})
|
|
7111
7111
|
);
|
|
7112
7112
|
return results.some((available) => available);
|
|
@@ -7137,10 +7137,10 @@ var init_fallback = __esm({
|
|
|
7137
7137
|
* @returns Array of provider status objects
|
|
7138
7138
|
*/
|
|
7139
7139
|
getCircuitStatus() {
|
|
7140
|
-
return this.providers.map((
|
|
7141
|
-
providerId:
|
|
7142
|
-
state:
|
|
7143
|
-
failureCount:
|
|
7140
|
+
return this.providers.map((p47) => ({
|
|
7141
|
+
providerId: p47.provider.id,
|
|
7142
|
+
state: p47.breaker.getState(),
|
|
7143
|
+
failureCount: p47.breaker.getFailureCount()
|
|
7144
7144
|
}));
|
|
7145
7145
|
}
|
|
7146
7146
|
/**
|
|
@@ -7150,8 +7150,8 @@ var init_fallback = __esm({
|
|
|
7150
7150
|
* previously failing providers to be tried again.
|
|
7151
7151
|
*/
|
|
7152
7152
|
resetCircuits() {
|
|
7153
|
-
for (const
|
|
7154
|
-
|
|
7153
|
+
for (const p47 of this.providers) {
|
|
7154
|
+
p47.breaker.reset();
|
|
7155
7155
|
}
|
|
7156
7156
|
}
|
|
7157
7157
|
/**
|
|
@@ -7726,9 +7726,9 @@ async function migrateGlobalConfig(oldDir, newConfigPath) {
|
|
|
7726
7726
|
);
|
|
7727
7727
|
}
|
|
7728
7728
|
}
|
|
7729
|
-
async function fileExists(
|
|
7729
|
+
async function fileExists(path62) {
|
|
7730
7730
|
try {
|
|
7731
|
-
await access(
|
|
7731
|
+
await access(path62);
|
|
7732
7732
|
return true;
|
|
7733
7733
|
} catch {
|
|
7734
7734
|
return false;
|
|
@@ -8111,8 +8111,8 @@ var init_registry = __esm({
|
|
|
8111
8111
|
/**
|
|
8112
8112
|
* Ensure directory exists
|
|
8113
8113
|
*/
|
|
8114
|
-
async ensureDir(
|
|
8115
|
-
await mkdir(dirname(
|
|
8114
|
+
async ensureDir(path62) {
|
|
8115
|
+
await mkdir(dirname(path62), { recursive: true });
|
|
8116
8116
|
}
|
|
8117
8117
|
};
|
|
8118
8118
|
}
|
|
@@ -9749,9 +9749,9 @@ function createEmptyMemoryContext() {
|
|
|
9749
9749
|
errors: []
|
|
9750
9750
|
};
|
|
9751
9751
|
}
|
|
9752
|
-
function createMissingMemoryFile(
|
|
9752
|
+
function createMissingMemoryFile(path62, level) {
|
|
9753
9753
|
return {
|
|
9754
|
-
path:
|
|
9754
|
+
path: path62,
|
|
9755
9755
|
level,
|
|
9756
9756
|
content: "",
|
|
9757
9757
|
sections: [],
|
|
@@ -10217,6 +10217,9 @@ After outputting the plan, the user will decide to approve, edit, or reject it.
|
|
|
10217
10217
|
if (subcommand === "status") {
|
|
10218
10218
|
if (session.planMode) {
|
|
10219
10219
|
p26.log.info(chalk.cyan("Plan mode is ACTIVE (read-only tools only)"));
|
|
10220
|
+
if (session.config.agent.planModeStrict) {
|
|
10221
|
+
p26.log.info("Strict plan mode is ON. Only the strict read-only allowlist is available.");
|
|
10222
|
+
}
|
|
10220
10223
|
if (session.pendingPlan) {
|
|
10221
10224
|
p26.log.info("A plan is pending approval. Use /plan approve or /plan reject.");
|
|
10222
10225
|
}
|
|
@@ -10271,6 +10274,9 @@ ${plan}`
|
|
|
10271
10274
|
const instruction = args.join(" ");
|
|
10272
10275
|
p26.log.success(chalk.cyan("Plan mode ACTIVATED"));
|
|
10273
10276
|
p26.log.info("Agent will explore the codebase and create a plan.");
|
|
10277
|
+
if (session.config.agent.planModeStrict) {
|
|
10278
|
+
p26.log.info("Strict plan mode is ON. Execution tools remain blocked until approval.");
|
|
10279
|
+
}
|
|
10274
10280
|
p26.log.info(chalk.dim(`Task: ${instruction}`));
|
|
10275
10281
|
p26.log.info("After the plan is generated, use /plan approve or /plan reject.");
|
|
10276
10282
|
session.messages.push({
|
|
@@ -10357,10 +10363,27 @@ async function createDefaultReplConfig() {
|
|
|
10357
10363
|
systemPrompt: COCO_SYSTEM_PROMPT,
|
|
10358
10364
|
maxToolIterations: 25,
|
|
10359
10365
|
confirmDestructive: true,
|
|
10360
|
-
enableAutoSwitchProvider: false
|
|
10366
|
+
enableAutoSwitchProvider: false,
|
|
10367
|
+
recoveryV2: readBooleanFlag("COCO_AGENT_RECOVERY_V2", true),
|
|
10368
|
+
planModeStrict: readBooleanFlag("COCO_AGENT_PLAN_MODE_STRICT", true),
|
|
10369
|
+
doctorV2: readBooleanFlag("COCO_AGENT_DOCTOR_V2", true),
|
|
10370
|
+
outputOffload: readBooleanFlag("COCO_AGENT_OUTPUT_OFFLOAD", false)
|
|
10361
10371
|
}
|
|
10362
10372
|
};
|
|
10363
10373
|
}
|
|
10374
|
+
function readBooleanFlag(envName, defaultValue) {
|
|
10375
|
+
const value = process.env[envName]?.trim().toLowerCase();
|
|
10376
|
+
if (value === void 0) {
|
|
10377
|
+
return defaultValue;
|
|
10378
|
+
}
|
|
10379
|
+
if (value === "1" || value === "true" || value === "yes" || value === "on") {
|
|
10380
|
+
return true;
|
|
10381
|
+
}
|
|
10382
|
+
if (value === "0" || value === "false" || value === "no" || value === "off") {
|
|
10383
|
+
return false;
|
|
10384
|
+
}
|
|
10385
|
+
return defaultValue;
|
|
10386
|
+
}
|
|
10364
10387
|
async function createSession(projectPath, config) {
|
|
10365
10388
|
const defaultConfig = await createDefaultReplConfig();
|
|
10366
10389
|
return {
|
|
@@ -11234,8 +11257,8 @@ __export(trust_store_exports, {
|
|
|
11234
11257
|
saveTrustStore: () => saveTrustStore,
|
|
11235
11258
|
updateLastAccessed: () => updateLastAccessed
|
|
11236
11259
|
});
|
|
11237
|
-
async function ensureDir(
|
|
11238
|
-
await mkdir(dirname(
|
|
11260
|
+
async function ensureDir(path62) {
|
|
11261
|
+
await mkdir(dirname(path62), { recursive: true });
|
|
11239
11262
|
}
|
|
11240
11263
|
async function loadTrustStore(storePath = TRUST_STORE_PATH) {
|
|
11241
11264
|
try {
|
|
@@ -11320,8 +11343,8 @@ function canPerformOperation(store, projectPath, operation) {
|
|
|
11320
11343
|
};
|
|
11321
11344
|
return permissions[level]?.includes(operation) ?? false;
|
|
11322
11345
|
}
|
|
11323
|
-
function normalizePath(
|
|
11324
|
-
return join(
|
|
11346
|
+
function normalizePath(path62) {
|
|
11347
|
+
return join(path62);
|
|
11325
11348
|
}
|
|
11326
11349
|
function createTrustStore(storePath = TRUST_STORE_PATH) {
|
|
11327
11350
|
let store = null;
|
|
@@ -11677,12 +11700,12 @@ function humanizeError(message, toolName) {
|
|
|
11677
11700
|
return msg;
|
|
11678
11701
|
}
|
|
11679
11702
|
if (/ENOENT/i.test(msg)) {
|
|
11680
|
-
const
|
|
11681
|
-
return
|
|
11703
|
+
const path62 = extractQuotedPath(msg);
|
|
11704
|
+
return path62 ? `File or directory not found: ${path62}` : "File or directory not found";
|
|
11682
11705
|
}
|
|
11683
11706
|
if (/EACCES/i.test(msg)) {
|
|
11684
|
-
const
|
|
11685
|
-
return
|
|
11707
|
+
const path62 = extractQuotedPath(msg);
|
|
11708
|
+
return path62 ? `Permission denied: ${path62}` : "Permission denied \u2014 check file permissions";
|
|
11686
11709
|
}
|
|
11687
11710
|
if (/EISDIR/i.test(msg)) {
|
|
11688
11711
|
return "Expected a file but found a directory at the specified path";
|
|
@@ -11774,7 +11797,7 @@ function humanizeError(message, toolName) {
|
|
|
11774
11797
|
return msg;
|
|
11775
11798
|
}
|
|
11776
11799
|
function looksLikeTechnicalJargon(message) {
|
|
11777
|
-
return JARGON_PATTERNS.some((
|
|
11800
|
+
return JARGON_PATTERNS.some((p47) => p47.test(message));
|
|
11778
11801
|
}
|
|
11779
11802
|
async function humanizeWithLLM(errorMessage, toolName, provider) {
|
|
11780
11803
|
const prompt = [
|
|
@@ -12535,9 +12558,9 @@ function renderFileBlock(file, opts) {
|
|
|
12535
12558
|
);
|
|
12536
12559
|
}
|
|
12537
12560
|
const pairs = pairAdjacentLines(hunk.lines);
|
|
12538
|
-
const pairedDeleteIndices = new Set(pairs.map((
|
|
12539
|
-
const pairedAddIndices = new Set(pairs.map((
|
|
12540
|
-
const pairByAdd = new Map(pairs.map((
|
|
12561
|
+
const pairedDeleteIndices = new Set(pairs.map((p47) => p47.deleteIdx));
|
|
12562
|
+
const pairedAddIndices = new Set(pairs.map((p47) => p47.addIdx));
|
|
12563
|
+
const pairByAdd = new Map(pairs.map((p47) => [p47.addIdx, p47.deleteIdx]));
|
|
12541
12564
|
const wordHighlights = /* @__PURE__ */ new Map();
|
|
12542
12565
|
for (const pair of pairs) {
|
|
12543
12566
|
const delLine = hunk.lines[pair.deleteIdx];
|
|
@@ -12616,9 +12639,9 @@ var init_diff_renderer = __esm({
|
|
|
12616
12639
|
getTerminalWidth = () => process.stdout.columns || 80;
|
|
12617
12640
|
}
|
|
12618
12641
|
});
|
|
12619
|
-
async function fileExists4(
|
|
12642
|
+
async function fileExists4(path62) {
|
|
12620
12643
|
try {
|
|
12621
|
-
await access(
|
|
12644
|
+
await access(path62);
|
|
12622
12645
|
return true;
|
|
12623
12646
|
} catch {
|
|
12624
12647
|
return false;
|
|
@@ -12816,13 +12839,13 @@ var init_subprocess_registry = __esm({
|
|
|
12816
12839
|
});
|
|
12817
12840
|
async function detectTestFramework(projectPath) {
|
|
12818
12841
|
try {
|
|
12819
|
-
await access(join(projectPath, "pom.xml"), constants.R_OK);
|
|
12842
|
+
await access(join(projectPath, "pom.xml"), constants$1.R_OK);
|
|
12820
12843
|
return "maven";
|
|
12821
12844
|
} catch {
|
|
12822
12845
|
}
|
|
12823
12846
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
12824
12847
|
try {
|
|
12825
|
-
await access(join(projectPath, f), constants.R_OK);
|
|
12848
|
+
await access(join(projectPath, f), constants$1.R_OK);
|
|
12826
12849
|
return "gradle";
|
|
12827
12850
|
} catch {
|
|
12828
12851
|
}
|
|
@@ -12980,7 +13003,7 @@ var init_coverage = __esm({
|
|
|
12980
13003
|
] : [join(this.projectPath, "build", "reports", "jacoco", "test", "jacocoTestReport.csv")];
|
|
12981
13004
|
for (const csvPath of jacocoPaths) {
|
|
12982
13005
|
try {
|
|
12983
|
-
await access(csvPath, constants.R_OK);
|
|
13006
|
+
await access(csvPath, constants$1.R_OK);
|
|
12984
13007
|
const csv = await readFile(csvPath, "utf-8");
|
|
12985
13008
|
return parseJacocoCsv(csv);
|
|
12986
13009
|
} catch {
|
|
@@ -12993,10 +13016,10 @@ var init_coverage = __esm({
|
|
|
12993
13016
|
join(this.projectPath, ".coverage", "coverage-summary.json"),
|
|
12994
13017
|
join(this.projectPath, "coverage", "lcov-report", "coverage-summary.json")
|
|
12995
13018
|
];
|
|
12996
|
-
for (const
|
|
13019
|
+
for (const p47 of possiblePaths) {
|
|
12997
13020
|
try {
|
|
12998
|
-
await access(
|
|
12999
|
-
const content = await readFile(
|
|
13021
|
+
await access(p47, constants$1.R_OK);
|
|
13022
|
+
const content = await readFile(p47, "utf-8");
|
|
13000
13023
|
const report = JSON.parse(content);
|
|
13001
13024
|
return parseCoverageSummary(report);
|
|
13002
13025
|
} catch {
|
|
@@ -14198,7 +14221,7 @@ var init_completeness = __esm({
|
|
|
14198
14221
|
];
|
|
14199
14222
|
for (const entry of entryPoints) {
|
|
14200
14223
|
try {
|
|
14201
|
-
await access(join(this.projectPath, entry), constants.R_OK);
|
|
14224
|
+
await access(join(this.projectPath, entry), constants$1.R_OK);
|
|
14202
14225
|
return true;
|
|
14203
14226
|
} catch {
|
|
14204
14227
|
}
|
|
@@ -14691,7 +14714,7 @@ var init_documentation = __esm({
|
|
|
14691
14714
|
}
|
|
14692
14715
|
async fileExists(relativePath) {
|
|
14693
14716
|
try {
|
|
14694
|
-
await access(join(this.projectPath, relativePath), constants.R_OK);
|
|
14717
|
+
await access(join(this.projectPath, relativePath), constants$1.R_OK);
|
|
14695
14718
|
return true;
|
|
14696
14719
|
} catch {
|
|
14697
14720
|
return false;
|
|
@@ -16998,16 +17021,16 @@ var init_evaluator = __esm({
|
|
|
16998
17021
|
* Find source files in project, adapting to the detected language stack.
|
|
16999
17022
|
*/
|
|
17000
17023
|
async findSourceFiles() {
|
|
17001
|
-
const { access:
|
|
17024
|
+
const { access: access18 } = await import('fs/promises');
|
|
17002
17025
|
const { join: join26 } = await import('path');
|
|
17003
17026
|
let isJava = false;
|
|
17004
17027
|
try {
|
|
17005
|
-
await
|
|
17028
|
+
await access18(join26(this.projectPath, "pom.xml"));
|
|
17006
17029
|
isJava = true;
|
|
17007
17030
|
} catch {
|
|
17008
17031
|
for (const f of ["build.gradle", "build.gradle.kts"]) {
|
|
17009
17032
|
try {
|
|
17010
|
-
await
|
|
17033
|
+
await access18(join26(this.projectPath, f));
|
|
17011
17034
|
isJava = true;
|
|
17012
17035
|
break;
|
|
17013
17036
|
} catch {
|
|
@@ -17934,13 +17957,13 @@ function buildReviewMarkdown(result) {
|
|
|
17934
17957
|
const { summary, required, suggestions, maturity } = result;
|
|
17935
17958
|
const lines = [];
|
|
17936
17959
|
lines.push("## Code Review\n");
|
|
17937
|
-
const
|
|
17960
|
+
const statusIcon2 = summary.status === "approved" ? "Approved" : "Needs Work";
|
|
17938
17961
|
lines.push(`**Branch:** \`${summary.branch}\` \u2192 \`${summary.baseBranch}\``);
|
|
17939
17962
|
lines.push(
|
|
17940
17963
|
`**Files:** ${summary.filesChanged} changed | +${summary.additions} -${summary.deletions}`
|
|
17941
17964
|
);
|
|
17942
17965
|
lines.push(`**Maturity:** ${maturity}`);
|
|
17943
|
-
lines.push(`**Status:** ${
|
|
17966
|
+
lines.push(`**Status:** ${statusIcon2}`);
|
|
17944
17967
|
lines.push("");
|
|
17945
17968
|
if (required.length > 0) {
|
|
17946
17969
|
lines.push(`### Required (${required.length})
|
|
@@ -18366,9 +18389,9 @@ Examples:
|
|
|
18366
18389
|
if (file) {
|
|
18367
18390
|
options.file = file;
|
|
18368
18391
|
}
|
|
18369
|
-
const
|
|
18392
|
+
const log39 = await git.log(options);
|
|
18370
18393
|
return {
|
|
18371
|
-
commits:
|
|
18394
|
+
commits: log39.all.map((commit) => ({
|
|
18372
18395
|
hash: commit.hash,
|
|
18373
18396
|
message: commit.message,
|
|
18374
18397
|
author: commit.author_name,
|
|
@@ -19257,6 +19280,24 @@ async function writeVersion(cwd, versionFile, newVersion) {
|
|
|
19257
19280
|
return;
|
|
19258
19281
|
}
|
|
19259
19282
|
await writeFile(fullPath, updated, "utf-8");
|
|
19283
|
+
if (versionFile.stack === "node" && versionFile.path === "package.json") {
|
|
19284
|
+
await syncCompanionNodeVersions(cwd, newVersion);
|
|
19285
|
+
}
|
|
19286
|
+
}
|
|
19287
|
+
async function syncCompanionNodeVersions(cwd, newVersion) {
|
|
19288
|
+
for (const relativePath of NODE_VERSION_SYNC_TARGETS) {
|
|
19289
|
+
const fullPath = path39__default.join(cwd, relativePath);
|
|
19290
|
+
if (!await fileExists3(fullPath)) {
|
|
19291
|
+
continue;
|
|
19292
|
+
}
|
|
19293
|
+
const content = await readFile(fullPath, "utf-8");
|
|
19294
|
+
const pkg = JSON.parse(content);
|
|
19295
|
+
if (typeof pkg["version"] !== "string") {
|
|
19296
|
+
continue;
|
|
19297
|
+
}
|
|
19298
|
+
pkg["version"] = newVersion;
|
|
19299
|
+
await writeFile(fullPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
|
|
19300
|
+
}
|
|
19260
19301
|
}
|
|
19261
19302
|
function detectBumpFromCommits(commitMessages) {
|
|
19262
19303
|
let bump = "patch";
|
|
@@ -19271,7 +19312,7 @@ function detectBumpFromCommits(commitMessages) {
|
|
|
19271
19312
|
}
|
|
19272
19313
|
return bump;
|
|
19273
19314
|
}
|
|
19274
|
-
var VERSION_FILES;
|
|
19315
|
+
var VERSION_FILES, NODE_VERSION_SYNC_TARGETS;
|
|
19275
19316
|
var init_version_detector = __esm({
|
|
19276
19317
|
"src/cli/repl/skills/builtin/ship/version-detector.ts"() {
|
|
19277
19318
|
init_files();
|
|
@@ -19281,6 +19322,7 @@ var init_version_detector = __esm({
|
|
|
19281
19322
|
{ file: "pyproject.toml", stack: "python", field: "version" },
|
|
19282
19323
|
{ file: "pom.xml", stack: "java", field: "version" }
|
|
19283
19324
|
];
|
|
19325
|
+
NODE_VERSION_SYNC_TARGETS = ["vscode-extension/package.json"];
|
|
19284
19326
|
}
|
|
19285
19327
|
});
|
|
19286
19328
|
async function detectChangelog(cwd) {
|
|
@@ -20031,18 +20073,18 @@ async function runVersion(ctx) {
|
|
|
20031
20073
|
});
|
|
20032
20074
|
const tag = lastTag.stdout.trim();
|
|
20033
20075
|
if (tag) {
|
|
20034
|
-
const
|
|
20076
|
+
const log39 = await bashExecTool.execute({
|
|
20035
20077
|
command: `git log ${tag}..HEAD --oneline`,
|
|
20036
20078
|
cwd: ctx.cwd
|
|
20037
20079
|
});
|
|
20038
|
-
commitMessages =
|
|
20080
|
+
commitMessages = log39.stdout.trim().split("\n").filter(Boolean);
|
|
20039
20081
|
} else {
|
|
20040
|
-
const
|
|
20041
|
-
commitMessages =
|
|
20082
|
+
const log39 = await gitLogTool.execute({ cwd: ctx.cwd, maxCount: 20 });
|
|
20083
|
+
commitMessages = log39.commits.map((c) => c.message);
|
|
20042
20084
|
}
|
|
20043
20085
|
} catch {
|
|
20044
|
-
const
|
|
20045
|
-
commitMessages =
|
|
20086
|
+
const log39 = await gitLogTool.execute({ cwd: ctx.cwd, maxCount: 10 });
|
|
20087
|
+
commitMessages = log39.commits.map((c) => c.message);
|
|
20046
20088
|
}
|
|
20047
20089
|
detectedBump = detectBumpFromCommits(commitMessages);
|
|
20048
20090
|
}
|
|
@@ -20080,8 +20122,8 @@ async function runVersion(ctx) {
|
|
|
20080
20122
|
p26.log.success(`Updated ${versionFile.path}: ${currentVersion} \u2192 ${finalVersion}`);
|
|
20081
20123
|
if (ctx.profile.changelog && !ctx.options.noChangelog) {
|
|
20082
20124
|
try {
|
|
20083
|
-
const
|
|
20084
|
-
const entries = generateChangelogEntries(
|
|
20125
|
+
const log39 = await gitLogTool.execute({ cwd: ctx.cwd, maxCount: 30 });
|
|
20126
|
+
const entries = generateChangelogEntries(log39.commits.map((c) => c.message));
|
|
20085
20127
|
if (entries.length > 0) {
|
|
20086
20128
|
await insertChangelogEntry(ctx.cwd, ctx.profile.changelog, finalVersion, entries);
|
|
20087
20129
|
p26.log.success(`Updated ${ctx.profile.changelog.path} with ${entries.length} entries`);
|
|
@@ -20799,11 +20841,11 @@ function isBlockedPath(absolute) {
|
|
|
20799
20841
|
return void 0;
|
|
20800
20842
|
}
|
|
20801
20843
|
function isBlockedExecFile(filePath) {
|
|
20802
|
-
return BLOCKED_EXEC_PATTERNS.some((
|
|
20844
|
+
return BLOCKED_EXEC_PATTERNS.some((p47) => p47.test(filePath));
|
|
20803
20845
|
}
|
|
20804
20846
|
function hasDangerousArgs(args) {
|
|
20805
20847
|
const joined = args.join(" ");
|
|
20806
|
-
return DANGEROUS_ARG_PATTERNS.some((
|
|
20848
|
+
return DANGEROUS_ARG_PATTERNS.some((p47) => p47.test(joined));
|
|
20807
20849
|
}
|
|
20808
20850
|
function getInterpreter(ext) {
|
|
20809
20851
|
return INTERPRETER_MAP[ext.toLowerCase()];
|
|
@@ -23311,413 +23353,6 @@ var init_allow_path_prompt = __esm({
|
|
|
23311
23353
|
}
|
|
23312
23354
|
});
|
|
23313
23355
|
|
|
23314
|
-
// src/cli/repl/interruptions/types.ts
|
|
23315
|
-
var init_types7 = __esm({
|
|
23316
|
-
"src/cli/repl/interruptions/types.ts"() {
|
|
23317
|
-
}
|
|
23318
|
-
});
|
|
23319
|
-
|
|
23320
|
-
// src/cli/repl/interruptions/classifier.ts
|
|
23321
|
-
function matchPatterns(text15, patterns) {
|
|
23322
|
-
for (let i = 0; i < patterns.length; i++) {
|
|
23323
|
-
if (patterns[i].test(text15)) {
|
|
23324
|
-
return 1 - i * 0.1;
|
|
23325
|
-
}
|
|
23326
|
-
}
|
|
23327
|
-
return 0;
|
|
23328
|
-
}
|
|
23329
|
-
function classifyInterruption(message) {
|
|
23330
|
-
const text15 = message.text;
|
|
23331
|
-
const abortConf = matchPatterns(text15, ABORT_PATTERNS);
|
|
23332
|
-
const modifyConf = matchPatterns(text15, MODIFY_PATTERNS);
|
|
23333
|
-
const correctConf = matchPatterns(text15, CORRECT_PATTERNS);
|
|
23334
|
-
if (abortConf > 0 && abortConf >= modifyConf && abortConf >= correctConf) {
|
|
23335
|
-
return {
|
|
23336
|
-
text: text15,
|
|
23337
|
-
type: "abort" /* Abort */,
|
|
23338
|
-
confidence: Math.min(1, abortConf),
|
|
23339
|
-
timestamp: message.timestamp
|
|
23340
|
-
};
|
|
23341
|
-
}
|
|
23342
|
-
if (modifyConf > 0 && modifyConf >= correctConf) {
|
|
23343
|
-
return {
|
|
23344
|
-
text: text15,
|
|
23345
|
-
type: "modify" /* Modify */,
|
|
23346
|
-
confidence: Math.min(1, modifyConf),
|
|
23347
|
-
timestamp: message.timestamp
|
|
23348
|
-
};
|
|
23349
|
-
}
|
|
23350
|
-
if (correctConf > 0) {
|
|
23351
|
-
return {
|
|
23352
|
-
text: text15,
|
|
23353
|
-
type: "correct" /* Correct */,
|
|
23354
|
-
confidence: Math.min(1, correctConf),
|
|
23355
|
-
timestamp: message.timestamp
|
|
23356
|
-
};
|
|
23357
|
-
}
|
|
23358
|
-
return {
|
|
23359
|
-
text: text15,
|
|
23360
|
-
type: "info" /* Info */,
|
|
23361
|
-
confidence: 0.5,
|
|
23362
|
-
timestamp: message.timestamp
|
|
23363
|
-
};
|
|
23364
|
-
}
|
|
23365
|
-
var ABORT_PATTERNS, MODIFY_PATTERNS, CORRECT_PATTERNS;
|
|
23366
|
-
var init_classifier = __esm({
|
|
23367
|
-
"src/cli/repl/interruptions/classifier.ts"() {
|
|
23368
|
-
init_types7();
|
|
23369
|
-
ABORT_PATTERNS = [
|
|
23370
|
-
/^(para|stop|cancel|abort|quit|exit|detente|basta)$/i,
|
|
23371
|
-
/^(para\s+ya|stop\s+it|cancel\s+that)$/i,
|
|
23372
|
-
/\b(para|stop|cancel|abort)\b/i
|
|
23373
|
-
];
|
|
23374
|
-
MODIFY_PATTERNS = [
|
|
23375
|
-
/^(a[ñn]ade|add|incluye|include|pon|put|agrega)\b/i,
|
|
23376
|
-
/^(cambia|change|modifica|modify|usa|use|haz|make)\b/i,
|
|
23377
|
-
/^no[,.]?\s+/i,
|
|
23378
|
-
// "no, mejor de la griega" — negation signals redirection
|
|
23379
|
-
/^(prefiero|prefer|quiero|i\s+want)\b/i,
|
|
23380
|
-
// "prefiero en gijon" — preference signals redirection
|
|
23381
|
-
/\b(a[ñn]ade|add|incluye|include)\s+/i,
|
|
23382
|
-
/\b(cambia|change|modifica|modify)\s+/i,
|
|
23383
|
-
/\b(en\s+vez\s+de|instead\s+of|rather\s+than)\b/i,
|
|
23384
|
-
/\b(prefiero|prefer|mejor|better|más|more|less|menos|bigger|smaller|larger)\b/i,
|
|
23385
|
-
/\b(también|also|además|additionally)\b/i
|
|
23386
|
-
];
|
|
23387
|
-
CORRECT_PATTERNS = [
|
|
23388
|
-
/^(error|bug|fallo|wrong|mal|incorrect)\b/i,
|
|
23389
|
-
/^(arregla|fix|corrige|correct|repara|repair)\b/i,
|
|
23390
|
-
/\b(error\s+en|bug\s+in|fallo\s+en)\b/i,
|
|
23391
|
-
/\b(está\s+mal|is\s+wrong|no\s+funciona|doesn'?t\s+work)\b/i,
|
|
23392
|
-
/\b(arregla|fix|corrige|correct)\s+/i
|
|
23393
|
-
];
|
|
23394
|
-
}
|
|
23395
|
-
});
|
|
23396
|
-
function mapClassificationToAction(type) {
|
|
23397
|
-
switch (type) {
|
|
23398
|
-
case "abort" /* Abort */:
|
|
23399
|
-
return "abort" /* Abort */;
|
|
23400
|
-
// Explicit modification/correction keywords → pre-select Modify
|
|
23401
|
-
case "modify" /* Modify */:
|
|
23402
|
-
case "correct" /* Correct */:
|
|
23403
|
-
return "modify" /* Modify */;
|
|
23404
|
-
// Info or unclassified → pre-select Queue (likely a new topic/task)
|
|
23405
|
-
// The user can always switch to Modify via the menu if needed
|
|
23406
|
-
case "info" /* Info */:
|
|
23407
|
-
default:
|
|
23408
|
-
return "queue" /* Queue */;
|
|
23409
|
-
}
|
|
23410
|
-
}
|
|
23411
|
-
var init_action_selector = __esm({
|
|
23412
|
-
"src/cli/repl/input/action-selector.ts"() {
|
|
23413
|
-
init_types7();
|
|
23414
|
-
}
|
|
23415
|
-
});
|
|
23416
|
-
|
|
23417
|
-
// src/cli/repl/interruptions/llm-classifier.ts
|
|
23418
|
-
var llm_classifier_exports = {};
|
|
23419
|
-
__export(llm_classifier_exports, {
|
|
23420
|
-
createLLMClassifier: () => createLLMClassifier
|
|
23421
|
-
});
|
|
23422
|
-
function buildClassificationPrompt(userMessage, currentTask) {
|
|
23423
|
-
if (currentTask) {
|
|
23424
|
-
return `Current task: "${currentTask}"
|
|
23425
|
-
User's new message: "${userMessage}"`;
|
|
23426
|
-
}
|
|
23427
|
-
return `User's new message: "${userMessage}"`;
|
|
23428
|
-
}
|
|
23429
|
-
function parseResponse(response) {
|
|
23430
|
-
const normalized = response.trim().toUpperCase();
|
|
23431
|
-
if (normalized.includes("STEER")) return "steer" /* Steer */;
|
|
23432
|
-
if (normalized.includes("MODIFY")) return "modify" /* Modify */;
|
|
23433
|
-
if (normalized.includes("QUEUE")) return "queue" /* Queue */;
|
|
23434
|
-
if (normalized.includes("ABORT")) return "abort" /* Abort */;
|
|
23435
|
-
return null;
|
|
23436
|
-
}
|
|
23437
|
-
function classifyWithKeywords(message) {
|
|
23438
|
-
const classified = classifyInterruption(message);
|
|
23439
|
-
return mapClassificationToAction(classified.type);
|
|
23440
|
-
}
|
|
23441
|
-
function createLLMClassifier(provider, config) {
|
|
23442
|
-
const cfg = { ...DEFAULT_CONFIG6, ...config };
|
|
23443
|
-
return {
|
|
23444
|
-
/**
|
|
23445
|
-
* Classify a user message captured during agent execution.
|
|
23446
|
-
*
|
|
23447
|
-
* Makes a fast parallel LLM call. If the LLM doesn't respond within
|
|
23448
|
-
* the timeout, falls back to keyword-based classification.
|
|
23449
|
-
*
|
|
23450
|
-
* @param message - The captured message
|
|
23451
|
-
* @param currentTask - The original task the agent is working on (for context)
|
|
23452
|
-
* @returns Classification result with action and source
|
|
23453
|
-
*/
|
|
23454
|
-
async classify(message, currentTask) {
|
|
23455
|
-
const llmPromise = classifyWithLLM(provider, message, currentTask, cfg);
|
|
23456
|
-
let timeoutId;
|
|
23457
|
-
const timeoutPromise = new Promise((resolve4) => {
|
|
23458
|
-
timeoutId = setTimeout(() => resolve4(null), cfg.timeoutMs);
|
|
23459
|
-
});
|
|
23460
|
-
try {
|
|
23461
|
-
const llmResult = await Promise.race([llmPromise, timeoutPromise]);
|
|
23462
|
-
if (llmResult !== null) {
|
|
23463
|
-
return { action: llmResult, source: "llm" };
|
|
23464
|
-
}
|
|
23465
|
-
return {
|
|
23466
|
-
action: classifyWithKeywords(message),
|
|
23467
|
-
source: "keywords"
|
|
23468
|
-
};
|
|
23469
|
-
} finally {
|
|
23470
|
-
clearTimeout(timeoutId);
|
|
23471
|
-
}
|
|
23472
|
-
}
|
|
23473
|
-
};
|
|
23474
|
-
}
|
|
23475
|
-
async function classifyWithLLM(provider, message, currentTask, cfg) {
|
|
23476
|
-
try {
|
|
23477
|
-
const userPrompt = buildClassificationPrompt(message.text, currentTask);
|
|
23478
|
-
const options = {
|
|
23479
|
-
maxTokens: cfg.maxTokens,
|
|
23480
|
-
temperature: cfg.temperature,
|
|
23481
|
-
system: CLASSIFICATION_SYSTEM_PROMPT2,
|
|
23482
|
-
timeout: cfg.timeoutMs
|
|
23483
|
-
};
|
|
23484
|
-
const response = await provider.chat([{ role: "user", content: userPrompt }], options);
|
|
23485
|
-
return parseResponse(response.content);
|
|
23486
|
-
} catch {
|
|
23487
|
-
return null;
|
|
23488
|
-
}
|
|
23489
|
-
}
|
|
23490
|
-
var DEFAULT_CONFIG6, CLASSIFICATION_SYSTEM_PROMPT2;
|
|
23491
|
-
var init_llm_classifier = __esm({
|
|
23492
|
-
"src/cli/repl/interruptions/llm-classifier.ts"() {
|
|
23493
|
-
init_types7();
|
|
23494
|
-
init_classifier();
|
|
23495
|
-
init_action_selector();
|
|
23496
|
-
DEFAULT_CONFIG6 = {
|
|
23497
|
-
timeoutMs: 8e3,
|
|
23498
|
-
maxTokens: 10,
|
|
23499
|
-
temperature: 0
|
|
23500
|
-
};
|
|
23501
|
-
CLASSIFICATION_SYSTEM_PROMPT2 = `You are a message classifier for a coding assistant. The user sent a message while the assistant was working on a task.
|
|
23502
|
-
|
|
23503
|
-
Classify the message into exactly ONE category. Reply with ONLY the category word, nothing else.
|
|
23504
|
-
|
|
23505
|
-
Categories:
|
|
23506
|
-
- STEER: The message provides a hint, preference, or minor adjustment to the CURRENT task without requiring a restart (e.g. "also add a test", "use camelCase", "make sure to handle errors", "btw the file is in src/", "prefer async/await")
|
|
23507
|
-
- MODIFY: The message fundamentally changes the CURRENT task requiring a fresh start (e.g. "actually use Python instead of JS", "no, do it completely differently", "start over with a new approach")
|
|
23508
|
-
- QUEUE: The message is a NEW, DIFFERENT task unrelated to what's being done (e.g. "what's 2+2", "tell me the weather", "create another file for X")
|
|
23509
|
-
- ABORT: The message asks to stop/cancel the current work (e.g. "stop", "cancel", "para", "never mind")
|
|
23510
|
-
|
|
23511
|
-
Reply with exactly one word: STEER, MODIFY, QUEUE, or ABORT`;
|
|
23512
|
-
}
|
|
23513
|
-
});
|
|
23514
|
-
|
|
23515
|
-
// src/cli/repl/context/stack-detector.ts
|
|
23516
|
-
var stack_detector_exports = {};
|
|
23517
|
-
__export(stack_detector_exports, {
|
|
23518
|
-
detectProjectStack: () => detectProjectStack
|
|
23519
|
-
});
|
|
23520
|
-
async function detectStack2(cwd) {
|
|
23521
|
-
if (await fileExists3(path39__default.join(cwd, "package.json"))) return "node";
|
|
23522
|
-
if (await fileExists3(path39__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
23523
|
-
if (await fileExists3(path39__default.join(cwd, "pyproject.toml"))) return "python";
|
|
23524
|
-
if (await fileExists3(path39__default.join(cwd, "go.mod"))) return "go";
|
|
23525
|
-
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) return "java";
|
|
23526
|
-
if (await fileExists3(path39__default.join(cwd, "build.gradle"))) return "java";
|
|
23527
|
-
if (await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
23528
|
-
return "unknown";
|
|
23529
|
-
}
|
|
23530
|
-
async function detectPackageManager3(cwd, stack) {
|
|
23531
|
-
if (stack === "rust") return "cargo";
|
|
23532
|
-
if (stack === "python") return "pip";
|
|
23533
|
-
if (stack === "go") return "go";
|
|
23534
|
-
if (stack === "java") {
|
|
23535
|
-
if (await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) {
|
|
23536
|
-
return "gradle";
|
|
23537
|
-
}
|
|
23538
|
-
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) {
|
|
23539
|
-
return "maven";
|
|
23540
|
-
}
|
|
23541
|
-
}
|
|
23542
|
-
if (stack === "node") {
|
|
23543
|
-
if (await fileExists3(path39__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
23544
|
-
if (await fileExists3(path39__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
23545
|
-
if (await fileExists3(path39__default.join(cwd, "bun.lockb"))) return "bun";
|
|
23546
|
-
return "npm";
|
|
23547
|
-
}
|
|
23548
|
-
return null;
|
|
23549
|
-
}
|
|
23550
|
-
async function parsePackageJson(cwd) {
|
|
23551
|
-
const packageJsonPath = path39__default.join(cwd, "package.json");
|
|
23552
|
-
try {
|
|
23553
|
-
const content = await fs35__default.readFile(packageJsonPath, "utf-8");
|
|
23554
|
-
const pkg = JSON.parse(content);
|
|
23555
|
-
const allDeps = {
|
|
23556
|
-
...pkg.dependencies,
|
|
23557
|
-
...pkg.devDependencies
|
|
23558
|
-
};
|
|
23559
|
-
const frameworks = [];
|
|
23560
|
-
if (allDeps.react) frameworks.push("React");
|
|
23561
|
-
if (allDeps.vue) frameworks.push("Vue");
|
|
23562
|
-
if (allDeps["@angular/core"]) frameworks.push("Angular");
|
|
23563
|
-
if (allDeps.next) frameworks.push("Next.js");
|
|
23564
|
-
if (allDeps.nuxt) frameworks.push("Nuxt");
|
|
23565
|
-
if (allDeps.express) frameworks.push("Express");
|
|
23566
|
-
if (allDeps.fastify) frameworks.push("Fastify");
|
|
23567
|
-
if (allDeps.nestjs || allDeps["@nestjs/core"]) frameworks.push("NestJS");
|
|
23568
|
-
const buildTools2 = [];
|
|
23569
|
-
if (allDeps.webpack) buildTools2.push("webpack");
|
|
23570
|
-
if (allDeps.vite) buildTools2.push("vite");
|
|
23571
|
-
if (allDeps.rollup) buildTools2.push("rollup");
|
|
23572
|
-
if (allDeps.tsup) buildTools2.push("tsup");
|
|
23573
|
-
if (allDeps.esbuild) buildTools2.push("esbuild");
|
|
23574
|
-
if (pkg.scripts?.build) buildTools2.push("build");
|
|
23575
|
-
const testingFrameworks = [];
|
|
23576
|
-
if (allDeps.vitest) testingFrameworks.push("vitest");
|
|
23577
|
-
if (allDeps.jest) testingFrameworks.push("jest");
|
|
23578
|
-
if (allDeps.mocha) testingFrameworks.push("mocha");
|
|
23579
|
-
if (allDeps.chai) testingFrameworks.push("chai");
|
|
23580
|
-
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
23581
|
-
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
23582
|
-
const languages = ["JavaScript"];
|
|
23583
|
-
if (allDeps.typescript || await fileExists3(path39__default.join(cwd, "tsconfig.json"))) {
|
|
23584
|
-
languages.push("TypeScript");
|
|
23585
|
-
}
|
|
23586
|
-
return {
|
|
23587
|
-
dependencies: allDeps,
|
|
23588
|
-
frameworks,
|
|
23589
|
-
buildTools: buildTools2,
|
|
23590
|
-
testingFrameworks,
|
|
23591
|
-
languages
|
|
23592
|
-
};
|
|
23593
|
-
} catch {
|
|
23594
|
-
return {
|
|
23595
|
-
dependencies: {},
|
|
23596
|
-
frameworks: [],
|
|
23597
|
-
buildTools: [],
|
|
23598
|
-
testingFrameworks: [],
|
|
23599
|
-
languages: []
|
|
23600
|
-
};
|
|
23601
|
-
}
|
|
23602
|
-
}
|
|
23603
|
-
async function parsePomXml(cwd) {
|
|
23604
|
-
const pomPath = path39__default.join(cwd, "pom.xml");
|
|
23605
|
-
try {
|
|
23606
|
-
const content = await fs35__default.readFile(pomPath, "utf-8");
|
|
23607
|
-
const dependencies = {};
|
|
23608
|
-
const frameworks = [];
|
|
23609
|
-
const buildTools2 = ["maven"];
|
|
23610
|
-
const testingFrameworks = [];
|
|
23611
|
-
const depRegex = /<groupId>([^<]+)<\/groupId>\s*<artifactId>([^<]+)<\/artifactId>/g;
|
|
23612
|
-
let match;
|
|
23613
|
-
while ((match = depRegex.exec(content)) !== null) {
|
|
23614
|
-
const groupId = match[1];
|
|
23615
|
-
const artifactId = match[2];
|
|
23616
|
-
if (!groupId || !artifactId) continue;
|
|
23617
|
-
const fullName = `${groupId}:${artifactId}`;
|
|
23618
|
-
dependencies[fullName] = "unknown";
|
|
23619
|
-
if (artifactId.includes("spring-boot")) {
|
|
23620
|
-
if (!frameworks.includes("Spring Boot")) frameworks.push("Spring Boot");
|
|
23621
|
-
}
|
|
23622
|
-
if (artifactId.includes("spring-webmvc") || artifactId.includes("spring-web")) {
|
|
23623
|
-
if (!frameworks.includes("Spring MVC")) frameworks.push("Spring MVC");
|
|
23624
|
-
}
|
|
23625
|
-
if (artifactId.includes("hibernate")) {
|
|
23626
|
-
if (!frameworks.includes("Hibernate")) frameworks.push("Hibernate");
|
|
23627
|
-
}
|
|
23628
|
-
if (artifactId === "junit-jupiter" || artifactId === "junit") {
|
|
23629
|
-
if (!testingFrameworks.includes("JUnit")) testingFrameworks.push("JUnit");
|
|
23630
|
-
}
|
|
23631
|
-
if (artifactId === "mockito-core") {
|
|
23632
|
-
if (!testingFrameworks.includes("Mockito")) testingFrameworks.push("Mockito");
|
|
23633
|
-
}
|
|
23634
|
-
}
|
|
23635
|
-
return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
|
|
23636
|
-
} catch {
|
|
23637
|
-
return { dependencies: {}, frameworks: [], buildTools: ["maven"], testingFrameworks: [] };
|
|
23638
|
-
}
|
|
23639
|
-
}
|
|
23640
|
-
async function parsePyprojectToml(cwd) {
|
|
23641
|
-
const pyprojectPath = path39__default.join(cwd, "pyproject.toml");
|
|
23642
|
-
try {
|
|
23643
|
-
const content = await fs35__default.readFile(pyprojectPath, "utf-8");
|
|
23644
|
-
const dependencies = {};
|
|
23645
|
-
const frameworks = [];
|
|
23646
|
-
const buildTools2 = ["pip"];
|
|
23647
|
-
const testingFrameworks = [];
|
|
23648
|
-
const lines = content.split("\n");
|
|
23649
|
-
for (const line of lines) {
|
|
23650
|
-
const trimmed = line.trim();
|
|
23651
|
-
if (trimmed.match(/^["']?[\w-]+["']?\s*=\s*["'][\^~>=<]+[\d.]+["']/)) {
|
|
23652
|
-
const depMatch = trimmed.match(/^["']?([\w-]+)["']?\s*=\s*["']([\^~>=<]+[\d.]+)["']/);
|
|
23653
|
-
if (depMatch && depMatch[1] && depMatch[2]) {
|
|
23654
|
-
dependencies[depMatch[1]] = depMatch[2];
|
|
23655
|
-
}
|
|
23656
|
-
}
|
|
23657
|
-
if (trimmed.includes("fastapi")) frameworks.push("FastAPI");
|
|
23658
|
-
if (trimmed.includes("django")) frameworks.push("Django");
|
|
23659
|
-
if (trimmed.includes("flask")) frameworks.push("Flask");
|
|
23660
|
-
if (trimmed.includes("pytest")) testingFrameworks.push("pytest");
|
|
23661
|
-
if (trimmed.includes("unittest")) testingFrameworks.push("unittest");
|
|
23662
|
-
}
|
|
23663
|
-
return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
|
|
23664
|
-
} catch {
|
|
23665
|
-
return { dependencies: {}, frameworks: [], buildTools: ["pip"], testingFrameworks: [] };
|
|
23666
|
-
}
|
|
23667
|
-
}
|
|
23668
|
-
async function detectProjectStack(cwd) {
|
|
23669
|
-
const stack = await detectStack2(cwd);
|
|
23670
|
-
const packageManager = await detectPackageManager3(cwd, stack);
|
|
23671
|
-
let dependencies = {};
|
|
23672
|
-
let frameworks = [];
|
|
23673
|
-
let buildTools2 = [];
|
|
23674
|
-
let testingFrameworks = [];
|
|
23675
|
-
let languages = [];
|
|
23676
|
-
if (stack === "node") {
|
|
23677
|
-
const parsed = await parsePackageJson(cwd);
|
|
23678
|
-
dependencies = parsed.dependencies;
|
|
23679
|
-
frameworks = parsed.frameworks;
|
|
23680
|
-
buildTools2 = parsed.buildTools;
|
|
23681
|
-
testingFrameworks = parsed.testingFrameworks;
|
|
23682
|
-
languages = parsed.languages;
|
|
23683
|
-
} else if (stack === "java") {
|
|
23684
|
-
const isGradle = await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"));
|
|
23685
|
-
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
23686
|
-
dependencies = parsed.dependencies;
|
|
23687
|
-
frameworks = parsed.frameworks;
|
|
23688
|
-
buildTools2 = parsed.buildTools;
|
|
23689
|
-
testingFrameworks = parsed.testingFrameworks;
|
|
23690
|
-
languages = ["Java"];
|
|
23691
|
-
} else if (stack === "python") {
|
|
23692
|
-
const parsed = await parsePyprojectToml(cwd);
|
|
23693
|
-
dependencies = parsed.dependencies;
|
|
23694
|
-
frameworks = parsed.frameworks;
|
|
23695
|
-
buildTools2 = parsed.buildTools;
|
|
23696
|
-
testingFrameworks = parsed.testingFrameworks;
|
|
23697
|
-
languages = ["Python"];
|
|
23698
|
-
} else if (stack === "go") {
|
|
23699
|
-
languages = ["Go"];
|
|
23700
|
-
buildTools2 = ["go"];
|
|
23701
|
-
} else if (stack === "rust") {
|
|
23702
|
-
languages = ["Rust"];
|
|
23703
|
-
buildTools2 = ["cargo"];
|
|
23704
|
-
}
|
|
23705
|
-
return {
|
|
23706
|
-
stack,
|
|
23707
|
-
packageManager,
|
|
23708
|
-
dependencies,
|
|
23709
|
-
frameworks,
|
|
23710
|
-
buildTools: buildTools2,
|
|
23711
|
-
testingFrameworks,
|
|
23712
|
-
languages
|
|
23713
|
-
};
|
|
23714
|
-
}
|
|
23715
|
-
var init_stack_detector = __esm({
|
|
23716
|
-
"src/cli/repl/context/stack-detector.ts"() {
|
|
23717
|
-
init_files();
|
|
23718
|
-
}
|
|
23719
|
-
});
|
|
23720
|
-
|
|
23721
23356
|
// src/cli/repl/hooks/types.ts
|
|
23722
23357
|
function isHookEvent(value) {
|
|
23723
23358
|
return typeof value === "string" && HOOK_EVENTS.includes(value);
|
|
@@ -23729,7 +23364,7 @@ function isHookAction(value) {
|
|
|
23729
23364
|
return value === "allow" || value === "deny" || value === "modify";
|
|
23730
23365
|
}
|
|
23731
23366
|
var HOOK_EVENTS;
|
|
23732
|
-
var
|
|
23367
|
+
var init_types7 = __esm({
|
|
23733
23368
|
"src/cli/repl/hooks/types.ts"() {
|
|
23734
23369
|
HOOK_EVENTS = [
|
|
23735
23370
|
"PreToolUse",
|
|
@@ -23748,7 +23383,7 @@ function createHookRegistry() {
|
|
|
23748
23383
|
var HookRegistry;
|
|
23749
23384
|
var init_registry5 = __esm({
|
|
23750
23385
|
"src/cli/repl/hooks/registry.ts"() {
|
|
23751
|
-
|
|
23386
|
+
init_types7();
|
|
23752
23387
|
HookRegistry = class {
|
|
23753
23388
|
/** Hooks indexed by event type for O(1) lookup */
|
|
23754
23389
|
hooksByEvent;
|
|
@@ -24386,12 +24021,419 @@ __export(hooks_exports, {
|
|
|
24386
24021
|
});
|
|
24387
24022
|
var init_hooks = __esm({
|
|
24388
24023
|
"src/cli/repl/hooks/index.ts"() {
|
|
24389
|
-
|
|
24024
|
+
init_types7();
|
|
24390
24025
|
init_registry5();
|
|
24391
24026
|
init_executor();
|
|
24392
24027
|
}
|
|
24393
24028
|
});
|
|
24394
24029
|
|
|
24030
|
+
// src/cli/repl/interruptions/types.ts
|
|
24031
|
+
var init_types8 = __esm({
|
|
24032
|
+
"src/cli/repl/interruptions/types.ts"() {
|
|
24033
|
+
}
|
|
24034
|
+
});
|
|
24035
|
+
|
|
24036
|
+
// src/cli/repl/interruptions/classifier.ts
|
|
24037
|
+
function matchPatterns(text15, patterns) {
|
|
24038
|
+
for (let i = 0; i < patterns.length; i++) {
|
|
24039
|
+
if (patterns[i].test(text15)) {
|
|
24040
|
+
return 1 - i * 0.1;
|
|
24041
|
+
}
|
|
24042
|
+
}
|
|
24043
|
+
return 0;
|
|
24044
|
+
}
|
|
24045
|
+
function classifyInterruption(message) {
|
|
24046
|
+
const text15 = message.text;
|
|
24047
|
+
const abortConf = matchPatterns(text15, ABORT_PATTERNS);
|
|
24048
|
+
const modifyConf = matchPatterns(text15, MODIFY_PATTERNS);
|
|
24049
|
+
const correctConf = matchPatterns(text15, CORRECT_PATTERNS);
|
|
24050
|
+
if (abortConf > 0 && abortConf >= modifyConf && abortConf >= correctConf) {
|
|
24051
|
+
return {
|
|
24052
|
+
text: text15,
|
|
24053
|
+
type: "abort" /* Abort */,
|
|
24054
|
+
confidence: Math.min(1, abortConf),
|
|
24055
|
+
timestamp: message.timestamp
|
|
24056
|
+
};
|
|
24057
|
+
}
|
|
24058
|
+
if (modifyConf > 0 && modifyConf >= correctConf) {
|
|
24059
|
+
return {
|
|
24060
|
+
text: text15,
|
|
24061
|
+
type: "modify" /* Modify */,
|
|
24062
|
+
confidence: Math.min(1, modifyConf),
|
|
24063
|
+
timestamp: message.timestamp
|
|
24064
|
+
};
|
|
24065
|
+
}
|
|
24066
|
+
if (correctConf > 0) {
|
|
24067
|
+
return {
|
|
24068
|
+
text: text15,
|
|
24069
|
+
type: "correct" /* Correct */,
|
|
24070
|
+
confidence: Math.min(1, correctConf),
|
|
24071
|
+
timestamp: message.timestamp
|
|
24072
|
+
};
|
|
24073
|
+
}
|
|
24074
|
+
return {
|
|
24075
|
+
text: text15,
|
|
24076
|
+
type: "info" /* Info */,
|
|
24077
|
+
confidence: 0.5,
|
|
24078
|
+
timestamp: message.timestamp
|
|
24079
|
+
};
|
|
24080
|
+
}
|
|
24081
|
+
var ABORT_PATTERNS, MODIFY_PATTERNS, CORRECT_PATTERNS;
|
|
24082
|
+
var init_classifier = __esm({
|
|
24083
|
+
"src/cli/repl/interruptions/classifier.ts"() {
|
|
24084
|
+
init_types8();
|
|
24085
|
+
ABORT_PATTERNS = [
|
|
24086
|
+
/^(para|stop|cancel|abort|quit|exit|detente|basta)$/i,
|
|
24087
|
+
/^(para\s+ya|stop\s+it|cancel\s+that)$/i,
|
|
24088
|
+
/\b(para|stop|cancel|abort)\b/i
|
|
24089
|
+
];
|
|
24090
|
+
MODIFY_PATTERNS = [
|
|
24091
|
+
/^(a[ñn]ade|add|incluye|include|pon|put|agrega)\b/i,
|
|
24092
|
+
/^(cambia|change|modifica|modify|usa|use|haz|make)\b/i,
|
|
24093
|
+
/^no[,.]?\s+/i,
|
|
24094
|
+
// "no, mejor de la griega" — negation signals redirection
|
|
24095
|
+
/^(prefiero|prefer|quiero|i\s+want)\b/i,
|
|
24096
|
+
// "prefiero en gijon" — preference signals redirection
|
|
24097
|
+
/\b(a[ñn]ade|add|incluye|include)\s+/i,
|
|
24098
|
+
/\b(cambia|change|modifica|modify)\s+/i,
|
|
24099
|
+
/\b(en\s+vez\s+de|instead\s+of|rather\s+than)\b/i,
|
|
24100
|
+
/\b(prefiero|prefer|mejor|better|más|more|less|menos|bigger|smaller|larger)\b/i,
|
|
24101
|
+
/\b(también|also|además|additionally)\b/i
|
|
24102
|
+
];
|
|
24103
|
+
CORRECT_PATTERNS = [
|
|
24104
|
+
/^(error|bug|fallo|wrong|mal|incorrect)\b/i,
|
|
24105
|
+
/^(arregla|fix|corrige|correct|repara|repair)\b/i,
|
|
24106
|
+
/\b(error\s+en|bug\s+in|fallo\s+en)\b/i,
|
|
24107
|
+
/\b(está\s+mal|is\s+wrong|no\s+funciona|doesn'?t\s+work)\b/i,
|
|
24108
|
+
/\b(arregla|fix|corrige|correct)\s+/i
|
|
24109
|
+
];
|
|
24110
|
+
}
|
|
24111
|
+
});
|
|
24112
|
+
function mapClassificationToAction(type) {
|
|
24113
|
+
switch (type) {
|
|
24114
|
+
case "abort" /* Abort */:
|
|
24115
|
+
return "abort" /* Abort */;
|
|
24116
|
+
// Explicit modification/correction keywords → pre-select Modify
|
|
24117
|
+
case "modify" /* Modify */:
|
|
24118
|
+
case "correct" /* Correct */:
|
|
24119
|
+
return "modify" /* Modify */;
|
|
24120
|
+
// Info or unclassified → pre-select Queue (likely a new topic/task)
|
|
24121
|
+
// The user can always switch to Modify via the menu if needed
|
|
24122
|
+
case "info" /* Info */:
|
|
24123
|
+
default:
|
|
24124
|
+
return "queue" /* Queue */;
|
|
24125
|
+
}
|
|
24126
|
+
}
|
|
24127
|
+
var init_action_selector = __esm({
|
|
24128
|
+
"src/cli/repl/input/action-selector.ts"() {
|
|
24129
|
+
init_types8();
|
|
24130
|
+
}
|
|
24131
|
+
});
|
|
24132
|
+
|
|
24133
|
+
// src/cli/repl/interruptions/llm-classifier.ts
|
|
24134
|
+
var llm_classifier_exports = {};
|
|
24135
|
+
__export(llm_classifier_exports, {
|
|
24136
|
+
createLLMClassifier: () => createLLMClassifier
|
|
24137
|
+
});
|
|
24138
|
+
function buildClassificationPrompt(userMessage, currentTask) {
|
|
24139
|
+
if (currentTask) {
|
|
24140
|
+
return `Current task: "${currentTask}"
|
|
24141
|
+
User's new message: "${userMessage}"`;
|
|
24142
|
+
}
|
|
24143
|
+
return `User's new message: "${userMessage}"`;
|
|
24144
|
+
}
|
|
24145
|
+
function parseResponse(response) {
|
|
24146
|
+
const normalized = response.trim().toUpperCase();
|
|
24147
|
+
if (normalized.includes("STEER")) return "steer" /* Steer */;
|
|
24148
|
+
if (normalized.includes("MODIFY")) return "modify" /* Modify */;
|
|
24149
|
+
if (normalized.includes("QUEUE")) return "queue" /* Queue */;
|
|
24150
|
+
if (normalized.includes("ABORT")) return "abort" /* Abort */;
|
|
24151
|
+
return null;
|
|
24152
|
+
}
|
|
24153
|
+
function classifyWithKeywords(message) {
|
|
24154
|
+
const classified = classifyInterruption(message);
|
|
24155
|
+
return mapClassificationToAction(classified.type);
|
|
24156
|
+
}
|
|
24157
|
+
function createLLMClassifier(provider, config) {
|
|
24158
|
+
const cfg = { ...DEFAULT_CONFIG6, ...config };
|
|
24159
|
+
return {
|
|
24160
|
+
/**
|
|
24161
|
+
* Classify a user message captured during agent execution.
|
|
24162
|
+
*
|
|
24163
|
+
* Makes a fast parallel LLM call. If the LLM doesn't respond within
|
|
24164
|
+
* the timeout, falls back to keyword-based classification.
|
|
24165
|
+
*
|
|
24166
|
+
* @param message - The captured message
|
|
24167
|
+
* @param currentTask - The original task the agent is working on (for context)
|
|
24168
|
+
* @returns Classification result with action and source
|
|
24169
|
+
*/
|
|
24170
|
+
async classify(message, currentTask) {
|
|
24171
|
+
const llmPromise = classifyWithLLM(provider, message, currentTask, cfg);
|
|
24172
|
+
let timeoutId;
|
|
24173
|
+
const timeoutPromise = new Promise((resolve4) => {
|
|
24174
|
+
timeoutId = setTimeout(() => resolve4(null), cfg.timeoutMs);
|
|
24175
|
+
});
|
|
24176
|
+
try {
|
|
24177
|
+
const llmResult = await Promise.race([llmPromise, timeoutPromise]);
|
|
24178
|
+
if (llmResult !== null) {
|
|
24179
|
+
return { action: llmResult, source: "llm" };
|
|
24180
|
+
}
|
|
24181
|
+
return {
|
|
24182
|
+
action: classifyWithKeywords(message),
|
|
24183
|
+
source: "keywords"
|
|
24184
|
+
};
|
|
24185
|
+
} finally {
|
|
24186
|
+
clearTimeout(timeoutId);
|
|
24187
|
+
}
|
|
24188
|
+
}
|
|
24189
|
+
};
|
|
24190
|
+
}
|
|
24191
|
+
async function classifyWithLLM(provider, message, currentTask, cfg) {
|
|
24192
|
+
try {
|
|
24193
|
+
const userPrompt = buildClassificationPrompt(message.text, currentTask);
|
|
24194
|
+
const options = {
|
|
24195
|
+
maxTokens: cfg.maxTokens,
|
|
24196
|
+
temperature: cfg.temperature,
|
|
24197
|
+
system: CLASSIFICATION_SYSTEM_PROMPT2,
|
|
24198
|
+
timeout: cfg.timeoutMs
|
|
24199
|
+
};
|
|
24200
|
+
const response = await provider.chat([{ role: "user", content: userPrompt }], options);
|
|
24201
|
+
return parseResponse(response.content);
|
|
24202
|
+
} catch {
|
|
24203
|
+
return null;
|
|
24204
|
+
}
|
|
24205
|
+
}
|
|
24206
|
+
var DEFAULT_CONFIG6, CLASSIFICATION_SYSTEM_PROMPT2;
|
|
24207
|
+
var init_llm_classifier = __esm({
|
|
24208
|
+
"src/cli/repl/interruptions/llm-classifier.ts"() {
|
|
24209
|
+
init_types8();
|
|
24210
|
+
init_classifier();
|
|
24211
|
+
init_action_selector();
|
|
24212
|
+
DEFAULT_CONFIG6 = {
|
|
24213
|
+
timeoutMs: 8e3,
|
|
24214
|
+
maxTokens: 10,
|
|
24215
|
+
temperature: 0
|
|
24216
|
+
};
|
|
24217
|
+
CLASSIFICATION_SYSTEM_PROMPT2 = `You are a message classifier for a coding assistant. The user sent a message while the assistant was working on a task.
|
|
24218
|
+
|
|
24219
|
+
Classify the message into exactly ONE category. Reply with ONLY the category word, nothing else.
|
|
24220
|
+
|
|
24221
|
+
Categories:
|
|
24222
|
+
- STEER: The message provides a hint, preference, or minor adjustment to the CURRENT task without requiring a restart (e.g. "also add a test", "use camelCase", "make sure to handle errors", "btw the file is in src/", "prefer async/await")
|
|
24223
|
+
- MODIFY: The message fundamentally changes the CURRENT task requiring a fresh start (e.g. "actually use Python instead of JS", "no, do it completely differently", "start over with a new approach")
|
|
24224
|
+
- QUEUE: The message is a NEW, DIFFERENT task unrelated to what's being done (e.g. "what's 2+2", "tell me the weather", "create another file for X")
|
|
24225
|
+
- ABORT: The message asks to stop/cancel the current work (e.g. "stop", "cancel", "para", "never mind")
|
|
24226
|
+
|
|
24227
|
+
Reply with exactly one word: STEER, MODIFY, QUEUE, or ABORT`;
|
|
24228
|
+
}
|
|
24229
|
+
});
|
|
24230
|
+
|
|
24231
|
+
// src/cli/repl/context/stack-detector.ts
|
|
24232
|
+
var stack_detector_exports = {};
|
|
24233
|
+
__export(stack_detector_exports, {
|
|
24234
|
+
detectProjectStack: () => detectProjectStack
|
|
24235
|
+
});
|
|
24236
|
+
async function detectStack2(cwd) {
|
|
24237
|
+
if (await fileExists3(path39__default.join(cwd, "package.json"))) return "node";
|
|
24238
|
+
if (await fileExists3(path39__default.join(cwd, "Cargo.toml"))) return "rust";
|
|
24239
|
+
if (await fileExists3(path39__default.join(cwd, "pyproject.toml"))) return "python";
|
|
24240
|
+
if (await fileExists3(path39__default.join(cwd, "go.mod"))) return "go";
|
|
24241
|
+
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) return "java";
|
|
24242
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle"))) return "java";
|
|
24243
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) return "java";
|
|
24244
|
+
return "unknown";
|
|
24245
|
+
}
|
|
24246
|
+
async function detectPackageManager3(cwd, stack) {
|
|
24247
|
+
if (stack === "rust") return "cargo";
|
|
24248
|
+
if (stack === "python") return "pip";
|
|
24249
|
+
if (stack === "go") return "go";
|
|
24250
|
+
if (stack === "java") {
|
|
24251
|
+
if (await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"))) {
|
|
24252
|
+
return "gradle";
|
|
24253
|
+
}
|
|
24254
|
+
if (await fileExists3(path39__default.join(cwd, "pom.xml"))) {
|
|
24255
|
+
return "maven";
|
|
24256
|
+
}
|
|
24257
|
+
}
|
|
24258
|
+
if (stack === "node") {
|
|
24259
|
+
if (await fileExists3(path39__default.join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
24260
|
+
if (await fileExists3(path39__default.join(cwd, "yarn.lock"))) return "yarn";
|
|
24261
|
+
if (await fileExists3(path39__default.join(cwd, "bun.lockb"))) return "bun";
|
|
24262
|
+
return "npm";
|
|
24263
|
+
}
|
|
24264
|
+
return null;
|
|
24265
|
+
}
|
|
24266
|
+
async function parsePackageJson(cwd) {
|
|
24267
|
+
const packageJsonPath = path39__default.join(cwd, "package.json");
|
|
24268
|
+
try {
|
|
24269
|
+
const content = await fs35__default.readFile(packageJsonPath, "utf-8");
|
|
24270
|
+
const pkg = JSON.parse(content);
|
|
24271
|
+
const allDeps = {
|
|
24272
|
+
...pkg.dependencies,
|
|
24273
|
+
...pkg.devDependencies
|
|
24274
|
+
};
|
|
24275
|
+
const frameworks = [];
|
|
24276
|
+
if (allDeps.react) frameworks.push("React");
|
|
24277
|
+
if (allDeps.vue) frameworks.push("Vue");
|
|
24278
|
+
if (allDeps["@angular/core"]) frameworks.push("Angular");
|
|
24279
|
+
if (allDeps.next) frameworks.push("Next.js");
|
|
24280
|
+
if (allDeps.nuxt) frameworks.push("Nuxt");
|
|
24281
|
+
if (allDeps.express) frameworks.push("Express");
|
|
24282
|
+
if (allDeps.fastify) frameworks.push("Fastify");
|
|
24283
|
+
if (allDeps.nestjs || allDeps["@nestjs/core"]) frameworks.push("NestJS");
|
|
24284
|
+
const buildTools2 = [];
|
|
24285
|
+
if (allDeps.webpack) buildTools2.push("webpack");
|
|
24286
|
+
if (allDeps.vite) buildTools2.push("vite");
|
|
24287
|
+
if (allDeps.rollup) buildTools2.push("rollup");
|
|
24288
|
+
if (allDeps.tsup) buildTools2.push("tsup");
|
|
24289
|
+
if (allDeps.esbuild) buildTools2.push("esbuild");
|
|
24290
|
+
if (pkg.scripts?.build) buildTools2.push("build");
|
|
24291
|
+
const testingFrameworks = [];
|
|
24292
|
+
if (allDeps.vitest) testingFrameworks.push("vitest");
|
|
24293
|
+
if (allDeps.jest) testingFrameworks.push("jest");
|
|
24294
|
+
if (allDeps.mocha) testingFrameworks.push("mocha");
|
|
24295
|
+
if (allDeps.chai) testingFrameworks.push("chai");
|
|
24296
|
+
if (allDeps["@playwright/test"]) testingFrameworks.push("playwright");
|
|
24297
|
+
if (allDeps.cypress) testingFrameworks.push("cypress");
|
|
24298
|
+
const languages = ["JavaScript"];
|
|
24299
|
+
if (allDeps.typescript || await fileExists3(path39__default.join(cwd, "tsconfig.json"))) {
|
|
24300
|
+
languages.push("TypeScript");
|
|
24301
|
+
}
|
|
24302
|
+
return {
|
|
24303
|
+
dependencies: allDeps,
|
|
24304
|
+
frameworks,
|
|
24305
|
+
buildTools: buildTools2,
|
|
24306
|
+
testingFrameworks,
|
|
24307
|
+
languages
|
|
24308
|
+
};
|
|
24309
|
+
} catch {
|
|
24310
|
+
return {
|
|
24311
|
+
dependencies: {},
|
|
24312
|
+
frameworks: [],
|
|
24313
|
+
buildTools: [],
|
|
24314
|
+
testingFrameworks: [],
|
|
24315
|
+
languages: []
|
|
24316
|
+
};
|
|
24317
|
+
}
|
|
24318
|
+
}
|
|
24319
|
+
async function parsePomXml(cwd) {
|
|
24320
|
+
const pomPath = path39__default.join(cwd, "pom.xml");
|
|
24321
|
+
try {
|
|
24322
|
+
const content = await fs35__default.readFile(pomPath, "utf-8");
|
|
24323
|
+
const dependencies = {};
|
|
24324
|
+
const frameworks = [];
|
|
24325
|
+
const buildTools2 = ["maven"];
|
|
24326
|
+
const testingFrameworks = [];
|
|
24327
|
+
const depRegex = /<groupId>([^<]+)<\/groupId>\s*<artifactId>([^<]+)<\/artifactId>/g;
|
|
24328
|
+
let match;
|
|
24329
|
+
while ((match = depRegex.exec(content)) !== null) {
|
|
24330
|
+
const groupId = match[1];
|
|
24331
|
+
const artifactId = match[2];
|
|
24332
|
+
if (!groupId || !artifactId) continue;
|
|
24333
|
+
const fullName = `${groupId}:${artifactId}`;
|
|
24334
|
+
dependencies[fullName] = "unknown";
|
|
24335
|
+
if (artifactId.includes("spring-boot")) {
|
|
24336
|
+
if (!frameworks.includes("Spring Boot")) frameworks.push("Spring Boot");
|
|
24337
|
+
}
|
|
24338
|
+
if (artifactId.includes("spring-webmvc") || artifactId.includes("spring-web")) {
|
|
24339
|
+
if (!frameworks.includes("Spring MVC")) frameworks.push("Spring MVC");
|
|
24340
|
+
}
|
|
24341
|
+
if (artifactId.includes("hibernate")) {
|
|
24342
|
+
if (!frameworks.includes("Hibernate")) frameworks.push("Hibernate");
|
|
24343
|
+
}
|
|
24344
|
+
if (artifactId === "junit-jupiter" || artifactId === "junit") {
|
|
24345
|
+
if (!testingFrameworks.includes("JUnit")) testingFrameworks.push("JUnit");
|
|
24346
|
+
}
|
|
24347
|
+
if (artifactId === "mockito-core") {
|
|
24348
|
+
if (!testingFrameworks.includes("Mockito")) testingFrameworks.push("Mockito");
|
|
24349
|
+
}
|
|
24350
|
+
}
|
|
24351
|
+
return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
|
|
24352
|
+
} catch {
|
|
24353
|
+
return { dependencies: {}, frameworks: [], buildTools: ["maven"], testingFrameworks: [] };
|
|
24354
|
+
}
|
|
24355
|
+
}
|
|
24356
|
+
async function parsePyprojectToml(cwd) {
|
|
24357
|
+
const pyprojectPath = path39__default.join(cwd, "pyproject.toml");
|
|
24358
|
+
try {
|
|
24359
|
+
const content = await fs35__default.readFile(pyprojectPath, "utf-8");
|
|
24360
|
+
const dependencies = {};
|
|
24361
|
+
const frameworks = [];
|
|
24362
|
+
const buildTools2 = ["pip"];
|
|
24363
|
+
const testingFrameworks = [];
|
|
24364
|
+
const lines = content.split("\n");
|
|
24365
|
+
for (const line of lines) {
|
|
24366
|
+
const trimmed = line.trim();
|
|
24367
|
+
if (trimmed.match(/^["']?[\w-]+["']?\s*=\s*["'][\^~>=<]+[\d.]+["']/)) {
|
|
24368
|
+
const depMatch = trimmed.match(/^["']?([\w-]+)["']?\s*=\s*["']([\^~>=<]+[\d.]+)["']/);
|
|
24369
|
+
if (depMatch && depMatch[1] && depMatch[2]) {
|
|
24370
|
+
dependencies[depMatch[1]] = depMatch[2];
|
|
24371
|
+
}
|
|
24372
|
+
}
|
|
24373
|
+
if (trimmed.includes("fastapi")) frameworks.push("FastAPI");
|
|
24374
|
+
if (trimmed.includes("django")) frameworks.push("Django");
|
|
24375
|
+
if (trimmed.includes("flask")) frameworks.push("Flask");
|
|
24376
|
+
if (trimmed.includes("pytest")) testingFrameworks.push("pytest");
|
|
24377
|
+
if (trimmed.includes("unittest")) testingFrameworks.push("unittest");
|
|
24378
|
+
}
|
|
24379
|
+
return { dependencies, frameworks, buildTools: buildTools2, testingFrameworks };
|
|
24380
|
+
} catch {
|
|
24381
|
+
return { dependencies: {}, frameworks: [], buildTools: ["pip"], testingFrameworks: [] };
|
|
24382
|
+
}
|
|
24383
|
+
}
|
|
24384
|
+
async function detectProjectStack(cwd) {
|
|
24385
|
+
const stack = await detectStack2(cwd);
|
|
24386
|
+
const packageManager = await detectPackageManager3(cwd, stack);
|
|
24387
|
+
let dependencies = {};
|
|
24388
|
+
let frameworks = [];
|
|
24389
|
+
let buildTools2 = [];
|
|
24390
|
+
let testingFrameworks = [];
|
|
24391
|
+
let languages = [];
|
|
24392
|
+
if (stack === "node") {
|
|
24393
|
+
const parsed = await parsePackageJson(cwd);
|
|
24394
|
+
dependencies = parsed.dependencies;
|
|
24395
|
+
frameworks = parsed.frameworks;
|
|
24396
|
+
buildTools2 = parsed.buildTools;
|
|
24397
|
+
testingFrameworks = parsed.testingFrameworks;
|
|
24398
|
+
languages = parsed.languages;
|
|
24399
|
+
} else if (stack === "java") {
|
|
24400
|
+
const isGradle = await fileExists3(path39__default.join(cwd, "build.gradle")) || await fileExists3(path39__default.join(cwd, "build.gradle.kts"));
|
|
24401
|
+
const parsed = isGradle ? { dependencies: {}, frameworks: [], buildTools: ["gradle"], testingFrameworks: ["JUnit"] } : await parsePomXml(cwd);
|
|
24402
|
+
dependencies = parsed.dependencies;
|
|
24403
|
+
frameworks = parsed.frameworks;
|
|
24404
|
+
buildTools2 = parsed.buildTools;
|
|
24405
|
+
testingFrameworks = parsed.testingFrameworks;
|
|
24406
|
+
languages = ["Java"];
|
|
24407
|
+
} else if (stack === "python") {
|
|
24408
|
+
const parsed = await parsePyprojectToml(cwd);
|
|
24409
|
+
dependencies = parsed.dependencies;
|
|
24410
|
+
frameworks = parsed.frameworks;
|
|
24411
|
+
buildTools2 = parsed.buildTools;
|
|
24412
|
+
testingFrameworks = parsed.testingFrameworks;
|
|
24413
|
+
languages = ["Python"];
|
|
24414
|
+
} else if (stack === "go") {
|
|
24415
|
+
languages = ["Go"];
|
|
24416
|
+
buildTools2 = ["go"];
|
|
24417
|
+
} else if (stack === "rust") {
|
|
24418
|
+
languages = ["Rust"];
|
|
24419
|
+
buildTools2 = ["cargo"];
|
|
24420
|
+
}
|
|
24421
|
+
return {
|
|
24422
|
+
stack,
|
|
24423
|
+
packageManager,
|
|
24424
|
+
dependencies,
|
|
24425
|
+
frameworks,
|
|
24426
|
+
buildTools: buildTools2,
|
|
24427
|
+
testingFrameworks,
|
|
24428
|
+
languages
|
|
24429
|
+
};
|
|
24430
|
+
}
|
|
24431
|
+
var init_stack_detector = __esm({
|
|
24432
|
+
"src/cli/repl/context/stack-detector.ts"() {
|
|
24433
|
+
init_files();
|
|
24434
|
+
}
|
|
24435
|
+
});
|
|
24436
|
+
|
|
24395
24437
|
// src/cli/repl/input/message-queue.ts
|
|
24396
24438
|
function createMessageQueue(maxSize = 50) {
|
|
24397
24439
|
let messages = [];
|
|
@@ -24769,7 +24811,7 @@ function createFeedbackSystem(getSpinner, config) {
|
|
|
24769
24811
|
var DEFAULT_FEEDBACK_CONFIG;
|
|
24770
24812
|
var init_feedback_system = __esm({
|
|
24771
24813
|
"src/cli/repl/feedback/feedback-system.ts"() {
|
|
24772
|
-
|
|
24814
|
+
init_types8();
|
|
24773
24815
|
DEFAULT_FEEDBACK_CONFIG = {
|
|
24774
24816
|
method: "spinner",
|
|
24775
24817
|
displayDurationMs: 2e3,
|
|
@@ -25045,8 +25087,8 @@ Generated by Corbat-Coco v0.1.0
|
|
|
25045
25087
|
|
|
25046
25088
|
// src/cli/commands/init.ts
|
|
25047
25089
|
function registerInitCommand(program2) {
|
|
25048
|
-
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 (
|
|
25049
|
-
await runInit(
|
|
25090
|
+
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 (path62, options) => {
|
|
25091
|
+
await runInit(path62, options);
|
|
25050
25092
|
});
|
|
25051
25093
|
}
|
|
25052
25094
|
async function runInit(projectPath, options) {
|
|
@@ -25125,18 +25167,18 @@ async function gatherProjectInfo() {
|
|
|
25125
25167
|
language
|
|
25126
25168
|
};
|
|
25127
25169
|
}
|
|
25128
|
-
function getDefaultProjectInfo(
|
|
25129
|
-
const name =
|
|
25170
|
+
function getDefaultProjectInfo(path62) {
|
|
25171
|
+
const name = path62 === "." ? "my-project" : path62.split("/").pop() || "my-project";
|
|
25130
25172
|
return {
|
|
25131
25173
|
name,
|
|
25132
25174
|
description: "",
|
|
25133
25175
|
language: "typescript"
|
|
25134
25176
|
};
|
|
25135
25177
|
}
|
|
25136
|
-
async function checkExistingProject(
|
|
25178
|
+
async function checkExistingProject(path62) {
|
|
25137
25179
|
try {
|
|
25138
25180
|
const fs56 = await import('fs/promises');
|
|
25139
|
-
await fs56.access(`${
|
|
25181
|
+
await fs56.access(`${path62}/.coco`);
|
|
25140
25182
|
return true;
|
|
25141
25183
|
} catch {
|
|
25142
25184
|
return false;
|
|
@@ -28637,20 +28679,20 @@ async function createCliPhaseContext(projectPath, _onUserInput) {
|
|
|
28637
28679
|
},
|
|
28638
28680
|
tools: {
|
|
28639
28681
|
file: {
|
|
28640
|
-
async read(
|
|
28682
|
+
async read(path62) {
|
|
28641
28683
|
const fs56 = await import('fs/promises');
|
|
28642
|
-
return fs56.readFile(
|
|
28684
|
+
return fs56.readFile(path62, "utf-8");
|
|
28643
28685
|
},
|
|
28644
|
-
async write(
|
|
28686
|
+
async write(path62, content) {
|
|
28645
28687
|
const fs56 = await import('fs/promises');
|
|
28646
28688
|
const nodePath = await import('path');
|
|
28647
|
-
await fs56.mkdir(nodePath.dirname(
|
|
28648
|
-
await fs56.writeFile(
|
|
28689
|
+
await fs56.mkdir(nodePath.dirname(path62), { recursive: true });
|
|
28690
|
+
await fs56.writeFile(path62, content, "utf-8");
|
|
28649
28691
|
},
|
|
28650
|
-
async exists(
|
|
28692
|
+
async exists(path62) {
|
|
28651
28693
|
const fs56 = await import('fs/promises');
|
|
28652
28694
|
try {
|
|
28653
|
-
await fs56.access(
|
|
28695
|
+
await fs56.access(path62);
|
|
28654
28696
|
return true;
|
|
28655
28697
|
} catch {
|
|
28656
28698
|
return false;
|
|
@@ -29006,10 +29048,10 @@ function getPhaseStatusForPhase(phase) {
|
|
|
29006
29048
|
}
|
|
29007
29049
|
async function loadProjectState(cwd, config) {
|
|
29008
29050
|
const fs56 = await import('fs/promises');
|
|
29009
|
-
const
|
|
29010
|
-
const statePath =
|
|
29011
|
-
const backlogPath =
|
|
29012
|
-
const checkpointDir =
|
|
29051
|
+
const path62 = await import('path');
|
|
29052
|
+
const statePath = path62.join(cwd, ".coco", "state.json");
|
|
29053
|
+
const backlogPath = path62.join(cwd, ".coco", "planning", "backlog.json");
|
|
29054
|
+
const checkpointDir = path62.join(cwd, ".coco", "checkpoints");
|
|
29013
29055
|
let currentPhase = "idle";
|
|
29014
29056
|
let metrics;
|
|
29015
29057
|
let sprint;
|
|
@@ -30352,7 +30394,7 @@ function getProviderDefinition(type) {
|
|
|
30352
30394
|
return PROVIDER_DEFINITIONS[type];
|
|
30353
30395
|
}
|
|
30354
30396
|
function getAllProviders() {
|
|
30355
|
-
return Object.values(PROVIDER_DEFINITIONS).filter((
|
|
30397
|
+
return Object.values(PROVIDER_DEFINITIONS).filter((p47) => !p47.internal);
|
|
30356
30398
|
}
|
|
30357
30399
|
function getRecommendedModel(type) {
|
|
30358
30400
|
const provider = PROVIDER_DEFINITIONS[type];
|
|
@@ -30373,20 +30415,20 @@ function hasLocalProviderConfig(type) {
|
|
|
30373
30415
|
return process.env["COCO_PROVIDER"] === "ollama" || !!process.env["OLLAMA_MODEL"] || !!process.env["OLLAMA_BASE_URL"];
|
|
30374
30416
|
}
|
|
30375
30417
|
function getConfiguredProviders() {
|
|
30376
|
-
return getAllProviders().filter((
|
|
30377
|
-
if (
|
|
30418
|
+
return getAllProviders().filter((p47) => {
|
|
30419
|
+
if (p47.id === "copilot") {
|
|
30378
30420
|
return !!process.env["GITHUB_TOKEN"] || !!process.env["GH_TOKEN"] || hasCopilotCredentials();
|
|
30379
30421
|
}
|
|
30380
|
-
if (
|
|
30381
|
-
return !!process.env[
|
|
30422
|
+
if (p47.id === "openai") {
|
|
30423
|
+
return !!process.env[p47.envVar] || !!process.env["OPENAI_CODEX_TOKEN"] || !!process.env["OPENAI_ACCESS_TOKEN"];
|
|
30382
30424
|
}
|
|
30383
|
-
if (
|
|
30384
|
-
return hasLocalProviderConfig(
|
|
30425
|
+
if (p47.id === "lmstudio" || p47.id === "ollama") {
|
|
30426
|
+
return hasLocalProviderConfig(p47.id);
|
|
30385
30427
|
}
|
|
30386
|
-
if (
|
|
30428
|
+
if (p47.id === "vertex") {
|
|
30387
30429
|
return !!(process.env["VERTEX_API_KEY"] ?? process.env["GOOGLE_API_KEY"] ?? process.env["VERTEX_PROJECT"] ?? process.env["GOOGLE_CLOUD_PROJECT"] ?? process.env["GCLOUD_PROJECT"]);
|
|
30388
30430
|
}
|
|
30389
|
-
return !!process.env[
|
|
30431
|
+
return !!process.env[p47.envVar];
|
|
30390
30432
|
});
|
|
30391
30433
|
}
|
|
30392
30434
|
function isProviderConfigured(type) {
|
|
@@ -30554,8 +30596,8 @@ async function saveConfig2(config) {
|
|
|
30554
30596
|
await fs56.mkdir(dir, { recursive: true });
|
|
30555
30597
|
await fs56.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
30556
30598
|
}
|
|
30557
|
-
function getNestedValue(obj,
|
|
30558
|
-
const keys =
|
|
30599
|
+
function getNestedValue(obj, path62) {
|
|
30600
|
+
const keys = path62.split(".");
|
|
30559
30601
|
let current = obj;
|
|
30560
30602
|
for (const key of keys) {
|
|
30561
30603
|
if (current === null || current === void 0 || typeof current !== "object") {
|
|
@@ -30565,8 +30607,8 @@ function getNestedValue(obj, path60) {
|
|
|
30565
30607
|
}
|
|
30566
30608
|
return current;
|
|
30567
30609
|
}
|
|
30568
|
-
function setNestedValue(obj,
|
|
30569
|
-
const keys =
|
|
30610
|
+
function setNestedValue(obj, path62, value) {
|
|
30611
|
+
const keys = path62.split(".");
|
|
30570
30612
|
let current = obj;
|
|
30571
30613
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
30572
30614
|
const key = keys[i];
|
|
@@ -31598,9 +31640,9 @@ function registerCheckCommand(program2) {
|
|
|
31598
31640
|
// src/swarm/spec-parser.ts
|
|
31599
31641
|
async function parseSwarmSpec(filePath) {
|
|
31600
31642
|
const fs56 = await import('fs/promises');
|
|
31601
|
-
const
|
|
31643
|
+
const path62 = await import('path');
|
|
31602
31644
|
const rawContent = await fs56.readFile(filePath, "utf-8");
|
|
31603
|
-
const ext =
|
|
31645
|
+
const ext = path62.extname(filePath).toLowerCase();
|
|
31604
31646
|
if (ext === ".yaml" || ext === ".yml") {
|
|
31605
31647
|
return parseYamlSpec(rawContent);
|
|
31606
31648
|
}
|
|
@@ -31930,8 +31972,8 @@ var DEFAULT_AGENT_CONFIG = {
|
|
|
31930
31972
|
};
|
|
31931
31973
|
async function loadAgentConfig(projectPath) {
|
|
31932
31974
|
const fs56 = await import('fs/promises');
|
|
31933
|
-
const
|
|
31934
|
-
const configPath =
|
|
31975
|
+
const path62 = await import('path');
|
|
31976
|
+
const configPath = path62.join(projectPath, ".coco", "swarm", "agents.json");
|
|
31935
31977
|
try {
|
|
31936
31978
|
const raw = await fs56.readFile(configPath, "utf-8");
|
|
31937
31979
|
const parsed = JSON.parse(raw);
|
|
@@ -32122,16 +32164,16 @@ async function createBoard(projectPath, spec) {
|
|
|
32122
32164
|
}
|
|
32123
32165
|
async function loadBoard(projectPath) {
|
|
32124
32166
|
const fs56 = await import('fs/promises');
|
|
32125
|
-
const
|
|
32126
|
-
const boardPath =
|
|
32167
|
+
const path62 = await import('path');
|
|
32168
|
+
const boardPath = path62.join(projectPath, ".coco", "swarm", "task-board.json");
|
|
32127
32169
|
const raw = await fs56.readFile(boardPath, "utf-8");
|
|
32128
32170
|
return JSON.parse(raw);
|
|
32129
32171
|
}
|
|
32130
32172
|
async function saveBoard(projectPath, board) {
|
|
32131
32173
|
const fs56 = await import('fs/promises');
|
|
32132
|
-
const
|
|
32133
|
-
const boardDir =
|
|
32134
|
-
const boardPath =
|
|
32174
|
+
const path62 = await import('path');
|
|
32175
|
+
const boardDir = path62.join(projectPath, ".coco", "swarm");
|
|
32176
|
+
const boardPath = path62.join(boardDir, "task-board.json");
|
|
32135
32177
|
await fs56.mkdir(boardDir, { recursive: true });
|
|
32136
32178
|
await fs56.writeFile(boardPath, JSON.stringify(board, null, 2), "utf-8");
|
|
32137
32179
|
}
|
|
@@ -32273,25 +32315,25 @@ Rules:
|
|
|
32273
32315
|
}
|
|
32274
32316
|
}
|
|
32275
32317
|
async function defaultPromptHandler(q) {
|
|
32276
|
-
const
|
|
32318
|
+
const p47 = await import('@clack/prompts');
|
|
32277
32319
|
if (q.options && q.options.length > 0) {
|
|
32278
|
-
const result = await
|
|
32320
|
+
const result = await p47.select({
|
|
32279
32321
|
message: q.question,
|
|
32280
32322
|
options: [
|
|
32281
32323
|
...q.options.map((o) => ({ value: o, label: o })),
|
|
32282
32324
|
{ value: q.assumedAnswer, label: `${q.assumedAnswer} (default)` }
|
|
32283
32325
|
]
|
|
32284
32326
|
});
|
|
32285
|
-
if (
|
|
32327
|
+
if (p47.isCancel(result)) {
|
|
32286
32328
|
return q.assumedAnswer;
|
|
32287
32329
|
}
|
|
32288
32330
|
return result;
|
|
32289
32331
|
} else {
|
|
32290
|
-
const result = await
|
|
32332
|
+
const result = await p47.text({
|
|
32291
32333
|
message: q.question,
|
|
32292
32334
|
placeholder: q.assumedAnswer
|
|
32293
32335
|
});
|
|
32294
|
-
if (
|
|
32336
|
+
if (p47.isCancel(result) || !result) {
|
|
32295
32337
|
return q.assumedAnswer;
|
|
32296
32338
|
}
|
|
32297
32339
|
return result;
|
|
@@ -32299,9 +32341,9 @@ async function defaultPromptHandler(q) {
|
|
|
32299
32341
|
}
|
|
32300
32342
|
async function writeAssumptionsFile(projectPath, projectName, questions, assumptions) {
|
|
32301
32343
|
const fs56 = await import('fs/promises');
|
|
32302
|
-
const
|
|
32303
|
-
const swarmDir =
|
|
32304
|
-
const assumptionsPath =
|
|
32344
|
+
const path62 = await import('path');
|
|
32345
|
+
const swarmDir = path62.join(projectPath, ".coco", "swarm");
|
|
32346
|
+
const assumptionsPath = path62.join(swarmDir, "assumptions.md");
|
|
32305
32347
|
await fs56.mkdir(swarmDir, { recursive: true });
|
|
32306
32348
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
32307
32349
|
const content = [
|
|
@@ -32325,9 +32367,9 @@ async function writeAssumptionsFile(projectPath, projectName, questions, assumpt
|
|
|
32325
32367
|
// src/swarm/events.ts
|
|
32326
32368
|
async function appendSwarmEvent(projectPath, event) {
|
|
32327
32369
|
const fs56 = await import('fs/promises');
|
|
32328
|
-
const
|
|
32329
|
-
const eventsDir =
|
|
32330
|
-
const eventsFile =
|
|
32370
|
+
const path62 = await import('path');
|
|
32371
|
+
const eventsDir = path62.join(projectPath, ".coco", "swarm");
|
|
32372
|
+
const eventsFile = path62.join(eventsDir, "events.jsonl");
|
|
32331
32373
|
await fs56.mkdir(eventsDir, { recursive: true });
|
|
32332
32374
|
await fs56.appendFile(eventsFile, JSON.stringify(event) + "\n", "utf-8");
|
|
32333
32375
|
}
|
|
@@ -32338,9 +32380,9 @@ function createEventId() {
|
|
|
32338
32380
|
// src/swarm/knowledge.ts
|
|
32339
32381
|
async function appendKnowledge(projectPath, entry) {
|
|
32340
32382
|
const fs56 = await import('fs/promises');
|
|
32341
|
-
const
|
|
32342
|
-
const knowledgeDir =
|
|
32343
|
-
const knowledgeFile =
|
|
32383
|
+
const path62 = await import('path');
|
|
32384
|
+
const knowledgeDir = path62.join(projectPath, ".coco", "swarm");
|
|
32385
|
+
const knowledgeFile = path62.join(knowledgeDir, "knowledge.jsonl");
|
|
32344
32386
|
await fs56.mkdir(knowledgeDir, { recursive: true });
|
|
32345
32387
|
await fs56.appendFile(knowledgeFile, JSON.stringify(entry) + "\n", "utf-8");
|
|
32346
32388
|
}
|
|
@@ -32647,10 +32689,10 @@ async function runSwarmLifecycle(options) {
|
|
|
32647
32689
|
async function stageInit(ctx) {
|
|
32648
32690
|
const { projectPath, spec } = ctx.options;
|
|
32649
32691
|
const fs56 = await import('fs/promises');
|
|
32650
|
-
const
|
|
32651
|
-
await fs56.mkdir(
|
|
32692
|
+
const path62 = await import('path');
|
|
32693
|
+
await fs56.mkdir(path62.join(projectPath, ".coco", "swarm"), { recursive: true });
|
|
32652
32694
|
await fs56.mkdir(ctx.options.outputPath, { recursive: true });
|
|
32653
|
-
const specSummaryPath =
|
|
32695
|
+
const specSummaryPath = path62.join(projectPath, ".coco", "swarm", "spec-summary.json");
|
|
32654
32696
|
const specSummary = {
|
|
32655
32697
|
projectName: spec.projectName,
|
|
32656
32698
|
description: spec.description,
|
|
@@ -32722,8 +32764,8 @@ async function stagePlan(ctx) {
|
|
|
32722
32764
|
]);
|
|
32723
32765
|
await createBoard(projectPath, spec);
|
|
32724
32766
|
const fs56 = await import('fs/promises');
|
|
32725
|
-
const
|
|
32726
|
-
const planPath =
|
|
32767
|
+
const path62 = await import('path');
|
|
32768
|
+
const planPath = path62.join(projectPath, ".coco", "swarm", "plan.json");
|
|
32727
32769
|
await fs56.writeFile(
|
|
32728
32770
|
planPath,
|
|
32729
32771
|
JSON.stringify({ pm: pmResult, architect: archResult, bestPractices: bpResult }, null, 2),
|
|
@@ -32940,7 +32982,7 @@ async function stageIntegrate(ctx) {
|
|
|
32940
32982
|
async function stageOutput(ctx) {
|
|
32941
32983
|
const { projectPath, outputPath } = ctx.options;
|
|
32942
32984
|
const fs56 = await import('fs/promises');
|
|
32943
|
-
const
|
|
32985
|
+
const path62 = await import('path');
|
|
32944
32986
|
const board = await loadBoard(projectPath);
|
|
32945
32987
|
const featureResults = Array.from(ctx.featureResults.values());
|
|
32946
32988
|
const summary = {
|
|
@@ -32955,7 +32997,7 @@ async function stageOutput(ctx) {
|
|
|
32955
32997
|
globalScore: computeGlobalScore(featureResults)
|
|
32956
32998
|
};
|
|
32957
32999
|
await fs56.mkdir(outputPath, { recursive: true });
|
|
32958
|
-
const summaryPath =
|
|
33000
|
+
const summaryPath = path62.join(outputPath, "swarm-summary.json");
|
|
32959
33001
|
await fs56.writeFile(summaryPath, JSON.stringify(summary, null, 2), "utf-8");
|
|
32960
33002
|
const passed = summary.globalScore >= ctx.options.minScore;
|
|
32961
33003
|
await emitGate(projectPath, "global-score", passed, `Global score: ${summary.globalScore}`);
|
|
@@ -33302,8 +33344,8 @@ var SwarmOrchestrator = class {
|
|
|
33302
33344
|
noQuestions = false,
|
|
33303
33345
|
onProgress
|
|
33304
33346
|
} = options;
|
|
33305
|
-
const
|
|
33306
|
-
const projectPath =
|
|
33347
|
+
const path62 = await import('path');
|
|
33348
|
+
const projectPath = path62.dirname(path62.resolve(specFile));
|
|
33307
33349
|
onProgress?.("init", `Parsing spec file: ${specFile}`);
|
|
33308
33350
|
const spec = await parseSwarmSpec(specFile);
|
|
33309
33351
|
onProgress?.("init", `Initializing provider: ${providerType}`);
|
|
@@ -33314,7 +33356,7 @@ var SwarmOrchestrator = class {
|
|
|
33314
33356
|
await runSwarmLifecycle({
|
|
33315
33357
|
spec,
|
|
33316
33358
|
projectPath,
|
|
33317
|
-
outputPath:
|
|
33359
|
+
outputPath: path62.resolve(outputPath),
|
|
33318
33360
|
provider,
|
|
33319
33361
|
agentConfig,
|
|
33320
33362
|
minScore,
|
|
@@ -33446,6 +33488,7 @@ var helpCommand = {
|
|
|
33446
33488
|
commands: [
|
|
33447
33489
|
{ cmd: "/model, /m", desc: "View or change the current model" },
|
|
33448
33490
|
{ cmd: "/provider", desc: "View or change the LLM provider" },
|
|
33491
|
+
{ cmd: "/doctor, /dr", desc: "Run local diagnostics for config, auth, hooks, and tools" },
|
|
33449
33492
|
{ cmd: "/compact", desc: "Toggle compact mode (less verbose)" },
|
|
33450
33493
|
{ cmd: "/cost, /tokens", desc: "Show token usage and cost" },
|
|
33451
33494
|
{ cmd: "/trust", desc: "Manage project trust permissions" },
|
|
@@ -34256,7 +34299,7 @@ async function runOnboardingV2() {
|
|
|
34256
34299
|
console.log(chalk.magenta(" \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
34257
34300
|
console.log();
|
|
34258
34301
|
p26.log.info(
|
|
34259
|
-
`Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((
|
|
34302
|
+
`Found ${configuredProviders.length} configured provider(s): ${configuredProviders.map((p47) => p47.emoji + " " + p47.name).join(", ")}`
|
|
34260
34303
|
);
|
|
34261
34304
|
const useExisting = await p26.confirm({
|
|
34262
34305
|
message: "Use an existing provider?",
|
|
@@ -35008,9 +35051,9 @@ async function setupOllamaProvider(port) {
|
|
|
35008
35051
|
return setupLocalProvider("ollama", port);
|
|
35009
35052
|
}
|
|
35010
35053
|
async function selectExistingProvider(providers) {
|
|
35011
|
-
const options = providers.map((
|
|
35012
|
-
value:
|
|
35013
|
-
label: `${
|
|
35054
|
+
const options = providers.map((p47) => ({
|
|
35055
|
+
value: p47.id,
|
|
35056
|
+
label: `${p47.emoji} ${p47.name}`,
|
|
35014
35057
|
hint: "Configured"
|
|
35015
35058
|
}));
|
|
35016
35059
|
options.push({ value: "__new__", label: "\u2795 Setup new provider", hint: "" });
|
|
@@ -35402,7 +35445,7 @@ async function ensureConfiguredV2(config) {
|
|
|
35402
35445
|
} catch {
|
|
35403
35446
|
}
|
|
35404
35447
|
}
|
|
35405
|
-
const preferredProviderDef = providers.find((
|
|
35448
|
+
const preferredProviderDef = providers.find((p47) => p47.id === config.provider.type);
|
|
35406
35449
|
const preferredIsLocal = preferredProviderDef?.requiresApiKey === false && preferredProviderDef?.id !== "copilot";
|
|
35407
35450
|
const preferredHasApiKey = preferredProviderDef ? !!process.env[preferredProviderDef.envVar] : false;
|
|
35408
35451
|
const preferredHasOpenAIOAuth = preferredProviderDef?.id === "openai" && hasOpenAIOAuthTokens;
|
|
@@ -35432,12 +35475,12 @@ async function ensureConfiguredV2(config) {
|
|
|
35432
35475
|
preferredUnavailableWasLocal = preferredIsLocal;
|
|
35433
35476
|
}
|
|
35434
35477
|
if (!preferredWasConfiguredButUnavailable || !preferredUnavailableWasLocal) {
|
|
35435
|
-
const configuredProviders = providers.filter((
|
|
35436
|
-
if (
|
|
35437
|
-
if (
|
|
35438
|
-
return hasOpenAIOAuthTokens || !!process.env[
|
|
35478
|
+
const configuredProviders = providers.filter((p47) => {
|
|
35479
|
+
if (p47.id === "copilot") return isProviderConfigured();
|
|
35480
|
+
if (p47.id === "openai") {
|
|
35481
|
+
return hasOpenAIOAuthTokens || !!process.env[p47.envVar];
|
|
35439
35482
|
}
|
|
35440
|
-
return
|
|
35483
|
+
return p47.requiresApiKey === false || !!process.env[p47.envVar];
|
|
35441
35484
|
});
|
|
35442
35485
|
for (const prov of configuredProviders) {
|
|
35443
35486
|
try {
|
|
@@ -35510,7 +35553,7 @@ init_auth();
|
|
|
35510
35553
|
init_env();
|
|
35511
35554
|
async function selectProviderInteractively(providers, currentProviderId) {
|
|
35512
35555
|
return new Promise((resolve4) => {
|
|
35513
|
-
let selectedIndex = providers.findIndex((
|
|
35556
|
+
let selectedIndex = providers.findIndex((p47) => p47.id === currentProviderId);
|
|
35514
35557
|
if (selectedIndex === -1) selectedIndex = 0;
|
|
35515
35558
|
let lastTotalLines = 0;
|
|
35516
35559
|
const clearPrevious = () => {
|
|
@@ -35608,12 +35651,12 @@ var providerCommand = {
|
|
|
35608
35651
|
`));
|
|
35609
35652
|
const allProviders2 = getAllProviders();
|
|
35610
35653
|
const configuredProviders = getConfiguredProviders();
|
|
35611
|
-
const providerOptions = allProviders2.map((
|
|
35612
|
-
id:
|
|
35613
|
-
name:
|
|
35614
|
-
emoji:
|
|
35615
|
-
description:
|
|
35616
|
-
isConfigured: configuredProviders.some((cp) => cp.id ===
|
|
35654
|
+
const providerOptions = allProviders2.map((p47) => ({
|
|
35655
|
+
id: p47.id,
|
|
35656
|
+
name: p47.name,
|
|
35657
|
+
emoji: p47.emoji,
|
|
35658
|
+
description: p47.description,
|
|
35659
|
+
isConfigured: configuredProviders.some((cp) => cp.id === p47.id)
|
|
35617
35660
|
}));
|
|
35618
35661
|
const selectedProviderId = await selectProviderInteractively(
|
|
35619
35662
|
providerOptions,
|
|
@@ -35628,15 +35671,15 @@ var providerCommand = {
|
|
|
35628
35671
|
`));
|
|
35629
35672
|
return false;
|
|
35630
35673
|
}
|
|
35631
|
-
const newProvider2 = allProviders2.find((
|
|
35674
|
+
const newProvider2 = allProviders2.find((p47) => p47.id === selectedProviderId);
|
|
35632
35675
|
return await switchProvider(newProvider2, session);
|
|
35633
35676
|
}
|
|
35634
35677
|
const newProviderId = args[0]?.toLowerCase();
|
|
35635
35678
|
const allProviders = getAllProviders();
|
|
35636
|
-
const newProvider = allProviders.find((
|
|
35679
|
+
const newProvider = allProviders.find((p47) => p47.id === newProviderId);
|
|
35637
35680
|
if (!newProvider) {
|
|
35638
35681
|
console.log(chalk.red(`Unknown provider: ${newProviderId}`));
|
|
35639
|
-
console.log(chalk.dim(`Available: ${allProviders.map((
|
|
35682
|
+
console.log(chalk.dim(`Available: ${allProviders.map((p47) => p47.id).join(", ")}
|
|
35640
35683
|
`));
|
|
35641
35684
|
return false;
|
|
35642
35685
|
}
|
|
@@ -36368,9 +36411,9 @@ function formatChangeSummary(files, options = {}) {
|
|
|
36368
36411
|
const filesToShow = opts.maxFiles && opts.maxFiles > 0 ? files.slice(0, opts.maxFiles) : files;
|
|
36369
36412
|
const remaining = files.length - filesToShow.length;
|
|
36370
36413
|
for (const file of filesToShow) {
|
|
36371
|
-
const
|
|
36414
|
+
const statusIcon2 = file.status === "added" ? chalk.green("A") : file.status === "deleted" ? chalk.red("D") : chalk.yellow("M");
|
|
36372
36415
|
const stats = `${chalk.green("+" + file.additions)} ${chalk.red("-" + file.deletions)}`;
|
|
36373
|
-
output += ` ${
|
|
36416
|
+
output += ` ${statusIcon2} ${chalk.white(file.path)} ${chalk.gray(stats)}
|
|
36374
36417
|
`;
|
|
36375
36418
|
}
|
|
36376
36419
|
if (remaining > 0) {
|
|
@@ -36795,7 +36838,7 @@ async function showTrustStatus(session, trustStore) {
|
|
|
36795
36838
|
}
|
|
36796
36839
|
const level = trustStore.getLevel(projectPath);
|
|
36797
36840
|
const list = trustStore.list();
|
|
36798
|
-
const project = list.find((
|
|
36841
|
+
const project = list.find((p47) => p47.path === projectPath);
|
|
36799
36842
|
p26.log.message("");
|
|
36800
36843
|
p26.log.message(`\u{1F510} Project Trust Status`);
|
|
36801
36844
|
p26.log.message(` Path: ${projectPath}`);
|
|
@@ -36888,8 +36931,8 @@ async function listTrustedProjects2(trustStore) {
|
|
|
36888
36931
|
p26.log.message("");
|
|
36889
36932
|
for (const project of projects) {
|
|
36890
36933
|
const level = project.approvalLevel.toUpperCase().padEnd(5);
|
|
36891
|
-
const
|
|
36892
|
-
p26.log.message(` [${level}] ${
|
|
36934
|
+
const path62 = project.path.length > 50 ? "..." + project.path.slice(-47) : project.path;
|
|
36935
|
+
p26.log.message(` [${level}] ${path62}`);
|
|
36893
36936
|
p26.log.message(` Last accessed: ${new Date(project.lastAccessed).toLocaleString()}`);
|
|
36894
36937
|
}
|
|
36895
36938
|
p26.log.message("");
|
|
@@ -38120,8 +38163,8 @@ function displayRewindResult(result) {
|
|
|
38120
38163
|
const fileName = filePath.split("/").pop() ?? filePath;
|
|
38121
38164
|
console.log(`${chalk.green(String.fromCodePoint(10003))} Restored: ${fileName}`);
|
|
38122
38165
|
}
|
|
38123
|
-
for (const { path:
|
|
38124
|
-
const fileName =
|
|
38166
|
+
for (const { path: path62, error } of result.filesFailed) {
|
|
38167
|
+
const fileName = path62.split("/").pop() ?? path62;
|
|
38125
38168
|
console.log(`${chalk.red(String.fromCodePoint(10007))} Failed: ${fileName} (${error})`);
|
|
38126
38169
|
}
|
|
38127
38170
|
if (result.conversationRestored) {
|
|
@@ -38580,10 +38623,10 @@ function getStatusIcon(status) {
|
|
|
38580
38623
|
function displaySessionEntry(index, session, isCurrentProject) {
|
|
38581
38624
|
const timeAgo = formatRelativeTime2(new Date(session.lastSavedAt));
|
|
38582
38625
|
const tokenStr = formatTokenCount(session.totalTokens);
|
|
38583
|
-
const
|
|
38626
|
+
const statusIcon2 = getStatusIcon(session.status);
|
|
38584
38627
|
console.log();
|
|
38585
38628
|
console.log(
|
|
38586
|
-
`${chalk.yellow(`${index}.`)} ${
|
|
38629
|
+
`${chalk.yellow(`${index}.`)} ${statusIcon2} ${chalk.dim(`[${timeAgo}]`)} ${session.messageCount} messages, ${tokenStr}`
|
|
38587
38630
|
);
|
|
38588
38631
|
if (session.title) {
|
|
38589
38632
|
console.log(` ${chalk.cyan(`"${session.title}"`)}`);
|
|
@@ -38762,8 +38805,8 @@ var STARTUP_TIMEOUT_MS = 5500;
|
|
|
38762
38805
|
var CACHE_DIR = path39__default.join(os4__default.homedir(), ".coco");
|
|
38763
38806
|
var CACHE_FILE = path39__default.join(CACHE_DIR, "version-check-cache.json");
|
|
38764
38807
|
function compareVersions(a, b) {
|
|
38765
|
-
const partsA = a.replace(/^v/, "").split(".").map((
|
|
38766
|
-
const partsB = b.replace(/^v/, "").split(".").map((
|
|
38808
|
+
const partsA = a.replace(/^v/, "").split(".").map((p47) => Number(p47.replace(/-.*$/, "")));
|
|
38809
|
+
const partsB = b.replace(/^v/, "").split(".").map((p47) => Number(p47.replace(/-.*$/, "")));
|
|
38767
38810
|
for (let i = 0; i < 3; i++) {
|
|
38768
38811
|
const numA = partsA[i] ?? 0;
|
|
38769
38812
|
const numB = partsB[i] ?? 0;
|
|
@@ -38887,13 +38930,13 @@ async function checkForUpdatesInteractive() {
|
|
|
38887
38930
|
]);
|
|
38888
38931
|
clearTimeout(startupTimerId);
|
|
38889
38932
|
if (!updateInfo) return;
|
|
38890
|
-
const
|
|
38933
|
+
const p47 = await import('@clack/prompts');
|
|
38891
38934
|
printUpdateBanner(updateInfo);
|
|
38892
|
-
const answer = await
|
|
38935
|
+
const answer = await p47.confirm({
|
|
38893
38936
|
message: "Exit now to update?",
|
|
38894
38937
|
initialValue: true
|
|
38895
38938
|
});
|
|
38896
|
-
if (!
|
|
38939
|
+
if (!p47.isCancel(answer) && answer) {
|
|
38897
38940
|
console.log();
|
|
38898
38941
|
console.log(chalk.dim(` Running: ${updateInfo.updateCommand}`));
|
|
38899
38942
|
console.log();
|
|
@@ -48530,11 +48573,11 @@ var getLearnedPatternsTool = defineTool({
|
|
|
48530
48573
|
const patterns = store.getFrequentPatterns(typedInput.limit);
|
|
48531
48574
|
return {
|
|
48532
48575
|
totalPatterns: patterns.length,
|
|
48533
|
-
patterns: patterns.map((
|
|
48534
|
-
pattern:
|
|
48535
|
-
preference:
|
|
48536
|
-
frequency:
|
|
48537
|
-
lastUsed: new Date(
|
|
48576
|
+
patterns: patterns.map((p47) => ({
|
|
48577
|
+
pattern: p47.pattern,
|
|
48578
|
+
preference: p47.userPreference,
|
|
48579
|
+
frequency: p47.frequency,
|
|
48580
|
+
lastUsed: new Date(p47.lastUsed).toISOString()
|
|
48538
48581
|
}))
|
|
48539
48582
|
};
|
|
48540
48583
|
}
|
|
@@ -50047,6 +50090,188 @@ var bestOfNCommand = {
|
|
|
50047
50090
|
}
|
|
50048
50091
|
};
|
|
50049
50092
|
|
|
50093
|
+
// src/cli/repl/commands/doctor.ts
|
|
50094
|
+
init_paths();
|
|
50095
|
+
init_loader();
|
|
50096
|
+
init_hooks();
|
|
50097
|
+
init_auth();
|
|
50098
|
+
function statusIcon(status) {
|
|
50099
|
+
if (status === "pass") return "PASS";
|
|
50100
|
+
if (status === "warn") return "WARN";
|
|
50101
|
+
return "FAIL";
|
|
50102
|
+
}
|
|
50103
|
+
async function checkProjectAccess(projectPath) {
|
|
50104
|
+
try {
|
|
50105
|
+
await access(projectPath, constants.R_OK | constants.W_OK);
|
|
50106
|
+
return {
|
|
50107
|
+
name: "Project access",
|
|
50108
|
+
status: "pass",
|
|
50109
|
+
detail: `Readable and writable: ${projectPath}`
|
|
50110
|
+
};
|
|
50111
|
+
} catch (error) {
|
|
50112
|
+
return {
|
|
50113
|
+
name: "Project access",
|
|
50114
|
+
status: "fail",
|
|
50115
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
50116
|
+
};
|
|
50117
|
+
}
|
|
50118
|
+
}
|
|
50119
|
+
async function checkConfig(projectPath) {
|
|
50120
|
+
try {
|
|
50121
|
+
const paths = await findAllConfigPaths(projectPath);
|
|
50122
|
+
await loadConfig(path39__default.join(projectPath, ".coco", "config.json"));
|
|
50123
|
+
const found = [paths.project, paths.global].filter(Boolean).length;
|
|
50124
|
+
return {
|
|
50125
|
+
name: "Configuration",
|
|
50126
|
+
status: "pass",
|
|
50127
|
+
detail: found > 0 ? `${found} config file(s) parsed successfully` : "Using built-in defaults"
|
|
50128
|
+
};
|
|
50129
|
+
} catch (error) {
|
|
50130
|
+
return {
|
|
50131
|
+
name: "Configuration",
|
|
50132
|
+
status: "fail",
|
|
50133
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
50134
|
+
};
|
|
50135
|
+
}
|
|
50136
|
+
}
|
|
50137
|
+
async function checkAuth(session) {
|
|
50138
|
+
const provider = session.config.provider.type;
|
|
50139
|
+
if (provider === "anthropic") {
|
|
50140
|
+
return process.env["ANTHROPIC_API_KEY"] ? {
|
|
50141
|
+
name: "Provider auth",
|
|
50142
|
+
status: "pass",
|
|
50143
|
+
detail: "ANTHROPIC_API_KEY detected"
|
|
50144
|
+
} : {
|
|
50145
|
+
name: "Provider auth",
|
|
50146
|
+
status: "warn",
|
|
50147
|
+
detail: "Missing ANTHROPIC_API_KEY for current provider"
|
|
50148
|
+
};
|
|
50149
|
+
}
|
|
50150
|
+
if (provider === "openai" || provider === "codex") {
|
|
50151
|
+
const hasApiKey = !!process.env["OPENAI_API_KEY"];
|
|
50152
|
+
const hasOauth = await isOAuthConfigured("openai").catch(() => false);
|
|
50153
|
+
return hasApiKey || hasOauth ? {
|
|
50154
|
+
name: "Provider auth",
|
|
50155
|
+
status: "pass",
|
|
50156
|
+
detail: hasApiKey ? "OPENAI_API_KEY detected" : "OpenAI OAuth is configured"
|
|
50157
|
+
} : {
|
|
50158
|
+
name: "Provider auth",
|
|
50159
|
+
status: "warn",
|
|
50160
|
+
detail: "Missing OPENAI_API_KEY and no OpenAI OAuth configuration found"
|
|
50161
|
+
};
|
|
50162
|
+
}
|
|
50163
|
+
if (provider === "gemini") {
|
|
50164
|
+
const hasApiKey = !!process.env["GEMINI_API_KEY"] || !!process.env["GOOGLE_API_KEY"];
|
|
50165
|
+
const hasOauth = await isOAuthConfigured("gemini").catch(() => false);
|
|
50166
|
+
const hasAdc = await isADCConfigured().catch(() => false);
|
|
50167
|
+
return hasApiKey || hasOauth || hasAdc ? {
|
|
50168
|
+
name: "Provider auth",
|
|
50169
|
+
status: "pass",
|
|
50170
|
+
detail: hasApiKey ? "Gemini API key detected" : hasAdc ? "Google ADC is configured" : "Gemini OAuth is configured"
|
|
50171
|
+
} : {
|
|
50172
|
+
name: "Provider auth",
|
|
50173
|
+
status: "warn",
|
|
50174
|
+
detail: "Missing Gemini auth (API key, OAuth, or ADC)"
|
|
50175
|
+
};
|
|
50176
|
+
}
|
|
50177
|
+
if (provider === "copilot") {
|
|
50178
|
+
const hasOauth = await isOAuthConfigured("copilot").catch(() => false);
|
|
50179
|
+
return hasOauth ? {
|
|
50180
|
+
name: "Provider auth",
|
|
50181
|
+
status: "pass",
|
|
50182
|
+
detail: "Copilot auth is configured"
|
|
50183
|
+
} : {
|
|
50184
|
+
name: "Provider auth",
|
|
50185
|
+
status: "warn",
|
|
50186
|
+
detail: "Copilot auth not configured"
|
|
50187
|
+
};
|
|
50188
|
+
}
|
|
50189
|
+
return {
|
|
50190
|
+
name: "Provider auth",
|
|
50191
|
+
status: "warn",
|
|
50192
|
+
detail: `No doctor auth rule for provider '${provider}'`
|
|
50193
|
+
};
|
|
50194
|
+
}
|
|
50195
|
+
async function checkHooks(projectPath) {
|
|
50196
|
+
const hooksPath = path39__default.join(projectPath, ".coco", "hooks.json");
|
|
50197
|
+
try {
|
|
50198
|
+
await access(hooksPath, constants.R_OK);
|
|
50199
|
+
} catch {
|
|
50200
|
+
return {
|
|
50201
|
+
name: "Hooks",
|
|
50202
|
+
status: "pass",
|
|
50203
|
+
detail: "No project hooks configured"
|
|
50204
|
+
};
|
|
50205
|
+
}
|
|
50206
|
+
try {
|
|
50207
|
+
const registry = createHookRegistry();
|
|
50208
|
+
await registry.loadFromFile(hooksPath);
|
|
50209
|
+
return {
|
|
50210
|
+
name: "Hooks",
|
|
50211
|
+
status: "pass",
|
|
50212
|
+
detail: `${registry.size} hook(s) loaded from .coco/hooks.json`
|
|
50213
|
+
};
|
|
50214
|
+
} catch (error) {
|
|
50215
|
+
return {
|
|
50216
|
+
name: "Hooks",
|
|
50217
|
+
status: "fail",
|
|
50218
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
50219
|
+
};
|
|
50220
|
+
}
|
|
50221
|
+
}
|
|
50222
|
+
async function checkTooling() {
|
|
50223
|
+
try {
|
|
50224
|
+
const registry = createFullToolRegistry();
|
|
50225
|
+
const defs = registry.getToolDefinitionsForLLM();
|
|
50226
|
+
return {
|
|
50227
|
+
name: "Tool registry",
|
|
50228
|
+
status: defs.length > 0 ? "pass" : "fail",
|
|
50229
|
+
detail: `${defs.length} tool(s) available to the agent`
|
|
50230
|
+
};
|
|
50231
|
+
} catch (error) {
|
|
50232
|
+
return {
|
|
50233
|
+
name: "Tool registry",
|
|
50234
|
+
status: "fail",
|
|
50235
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
50236
|
+
};
|
|
50237
|
+
}
|
|
50238
|
+
}
|
|
50239
|
+
async function runDoctorChecks(session) {
|
|
50240
|
+
return Promise.all([
|
|
50241
|
+
checkProjectAccess(session.projectPath),
|
|
50242
|
+
checkConfig(session.projectPath),
|
|
50243
|
+
checkAuth(session),
|
|
50244
|
+
checkHooks(session.projectPath),
|
|
50245
|
+
checkTooling()
|
|
50246
|
+
]);
|
|
50247
|
+
}
|
|
50248
|
+
var doctorCommand = {
|
|
50249
|
+
name: "doctor",
|
|
50250
|
+
aliases: ["dr"],
|
|
50251
|
+
description: "Run read-only diagnostics for config, auth, hooks, and tools",
|
|
50252
|
+
usage: "/doctor",
|
|
50253
|
+
async execute(_args, session) {
|
|
50254
|
+
if (!session.config.agent.doctorV2) {
|
|
50255
|
+
p26.log.warn("Doctor v2 is disabled. Set agent.doctorV2=true to enable it.");
|
|
50256
|
+
return false;
|
|
50257
|
+
}
|
|
50258
|
+
p26.intro(chalk.cyan("Coco Doctor"));
|
|
50259
|
+
const checks = await runDoctorChecks(session);
|
|
50260
|
+
const failures = checks.filter((check) => check.status === "fail").length;
|
|
50261
|
+
const warnings = checks.filter((check) => check.status === "warn").length;
|
|
50262
|
+
for (const check of checks) {
|
|
50263
|
+
p26.log.message(`${statusIcon(check.status)} ${check.name}: ${check.detail}`);
|
|
50264
|
+
}
|
|
50265
|
+
p26.log.message("");
|
|
50266
|
+
p26.log.info(
|
|
50267
|
+
`Summary: ${checks.length - failures - warnings} pass, ${warnings} warn, ${failures} fail`
|
|
50268
|
+
);
|
|
50269
|
+
p26.log.message(`Config home: ${CONFIG_PATHS.home}`);
|
|
50270
|
+
p26.outro(failures > 0 ? "Doctor finished with failures" : "Doctor finished");
|
|
50271
|
+
return false;
|
|
50272
|
+
}
|
|
50273
|
+
};
|
|
50274
|
+
|
|
50050
50275
|
// src/cli/repl/output/renderer.ts
|
|
50051
50276
|
init_syntax();
|
|
50052
50277
|
var lineBuffer = "";
|
|
@@ -50815,9 +51040,9 @@ function printEditDiff(oldStr, newStr) {
|
|
|
50815
51040
|
}
|
|
50816
51041
|
if (diffLineList.length === 0) return;
|
|
50817
51042
|
const pairs = pairAdjacentDiffLines(diffLineList);
|
|
50818
|
-
const pairedDeletes = new Set(pairs.map((
|
|
50819
|
-
const pairedAdds = new Set(pairs.map((
|
|
50820
|
-
const pairByAdd = new Map(pairs.map((
|
|
51043
|
+
const pairedDeletes = new Set(pairs.map((p47) => p47.deleteIdx));
|
|
51044
|
+
const pairedAdds = new Set(pairs.map((p47) => p47.addIdx));
|
|
51045
|
+
const pairByAdd = new Map(pairs.map((p47) => [p47.addIdx, p47.deleteIdx]));
|
|
50821
51046
|
const wordHighlights = /* @__PURE__ */ new Map();
|
|
50822
51047
|
for (const pair of pairs) {
|
|
50823
51048
|
const del = diffLineList[pair.deleteIdx];
|
|
@@ -50897,8 +51122,8 @@ function formatToolSummary(toolName, input) {
|
|
|
50897
51122
|
case "grep":
|
|
50898
51123
|
case "search_files": {
|
|
50899
51124
|
const pattern = String(input.pattern || "");
|
|
50900
|
-
const
|
|
50901
|
-
return `"${pattern}"${
|
|
51125
|
+
const path62 = input.path ? ` in ${input.path}` : "";
|
|
51126
|
+
return `"${pattern}"${path62}`;
|
|
50902
51127
|
}
|
|
50903
51128
|
case "bash_exec": {
|
|
50904
51129
|
const cmd = String(input.command || "");
|
|
@@ -50919,8 +51144,8 @@ function formatToolSummary(toolName, input) {
|
|
|
50919
51144
|
function formatUrl(url) {
|
|
50920
51145
|
try {
|
|
50921
51146
|
const u = new URL(url);
|
|
50922
|
-
const
|
|
50923
|
-
const display =
|
|
51147
|
+
const path62 = u.pathname.replace(/\/$/, "");
|
|
51148
|
+
const display = path62 ? `${u.hostname} \u203A ${path62.slice(1)}` : u.hostname;
|
|
50924
51149
|
const max = Math.max(getTerminalWidth2() - 20, 50);
|
|
50925
51150
|
return display.length > max ? display.slice(0, max - 1) + "\u2026" : display;
|
|
50926
51151
|
} catch {
|
|
@@ -51077,7 +51302,8 @@ var commands = [
|
|
|
51077
51302
|
fullPowerRiskCommand,
|
|
51078
51303
|
buildAppCommand,
|
|
51079
51304
|
contextCommand,
|
|
51080
|
-
bestOfNCommand
|
|
51305
|
+
bestOfNCommand,
|
|
51306
|
+
doctorCommand
|
|
51081
51307
|
];
|
|
51082
51308
|
function isSlashCommand(input) {
|
|
51083
51309
|
return input.startsWith("/");
|
|
@@ -51280,8 +51506,8 @@ function getCursorVisualPos(text15, cursorPos, promptLen, termCols) {
|
|
|
51280
51506
|
function computeWordWrap(text15, startCol, termCols) {
|
|
51281
51507
|
const passthrough = {
|
|
51282
51508
|
display: text15,
|
|
51283
|
-
toDisplayPos: (
|
|
51284
|
-
toOrigPos: (
|
|
51509
|
+
toDisplayPos: (p47) => p47,
|
|
51510
|
+
toOrigPos: (p47) => p47
|
|
51285
51511
|
};
|
|
51286
51512
|
if (!text15 || termCols <= 1) return passthrough;
|
|
51287
51513
|
const origToDisp = new Int32Array(text15.length + 1);
|
|
@@ -51908,7 +52134,7 @@ function createInputHandler(_session) {
|
|
|
51908
52134
|
}
|
|
51909
52135
|
|
|
51910
52136
|
// src/cli/repl/index.ts
|
|
51911
|
-
|
|
52137
|
+
init_types8();
|
|
51912
52138
|
var COCO_SPINNER = {
|
|
51913
52139
|
interval: 120,
|
|
51914
52140
|
frames: ["\u{1F965} ", " \u{1F965} ", " \u{1F965} ", " \u{1F965} ", " \u{1F965}", " \u{1F965} ", " \u{1F965} ", " \u{1F965} "]
|
|
@@ -52540,16 +52766,16 @@ function formatToolCallForConfirmation(toolCall, metadata) {
|
|
|
52540
52766
|
const reason = input.reason ? String(input.reason) : void 0;
|
|
52541
52767
|
const actionLabel = action === "allow" ? chalk.green.bold("ALLOW") : chalk.red.bold(action.toUpperCase());
|
|
52542
52768
|
const scopeLabel = scope === "global" ? chalk.blue("Global (all projects)") : chalk.magenta("Project (current only)");
|
|
52543
|
-
const patternList = patterns.map((
|
|
52769
|
+
const patternList = patterns.map((p47) => chalk.cyan(p47)).join(", ");
|
|
52544
52770
|
const lines = [`${actionLabel}: ${patternList}`];
|
|
52545
52771
|
lines.push(`${chalk.dim(" Scope:")} ${scopeLabel}`);
|
|
52546
52772
|
if (reason) {
|
|
52547
52773
|
lines.push(`${chalk.dim(" Reason:")} ${reason}`);
|
|
52548
52774
|
}
|
|
52549
|
-
for (const
|
|
52550
|
-
lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(
|
|
52775
|
+
for (const p47 of patterns) {
|
|
52776
|
+
lines.push(`${chalk.dim(" Risk:")} ${getRiskDescription(p47)}`);
|
|
52551
52777
|
lines.push(
|
|
52552
|
-
`${chalk.dim(" Effect:")} ${getEffectDescription(action,
|
|
52778
|
+
`${chalk.dim(" Effect:")} ${getEffectDescription(action, p47, scope)}`
|
|
52553
52779
|
);
|
|
52554
52780
|
}
|
|
52555
52781
|
description = lines.join("\n ");
|
|
@@ -53219,7 +53445,9 @@ function computeTurnQualityMetrics(input) {
|
|
|
53219
53445
|
successfulToolCalls,
|
|
53220
53446
|
failedToolCalls,
|
|
53221
53447
|
hadError: input.hadError,
|
|
53222
|
-
repeatedOutputsSuppressed: input.repeatedOutputsSuppressed
|
|
53448
|
+
repeatedOutputsSuppressed: input.repeatedOutputsSuppressed,
|
|
53449
|
+
observedLargeOutputs: input.observedLargeOutputs ?? 0,
|
|
53450
|
+
observedLargeOutputChars: input.observedLargeOutputChars ?? 0
|
|
53223
53451
|
};
|
|
53224
53452
|
}
|
|
53225
53453
|
var RepeatedOutputSuppressor = class {
|
|
@@ -53254,13 +53482,20 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
53254
53482
|
let finalContent = "";
|
|
53255
53483
|
let hadTurnError = false;
|
|
53256
53484
|
let repeatedOutputsSuppressed = 0;
|
|
53485
|
+
let observedLargeOutputs = 0;
|
|
53486
|
+
let observedLargeOutputChars = 0;
|
|
53257
53487
|
const repeatedOutputSuppressor = new RepeatedOutputSuppressor();
|
|
53488
|
+
const recoveryV2Enabled = session.config.agent.recoveryV2 === true;
|
|
53489
|
+
const strictPlanModeEnabled = session.planMode && session.config.agent.planModeStrict === true;
|
|
53490
|
+
const outputOffloadObservationEnabled = session.config.agent.outputOffload === true;
|
|
53258
53491
|
const buildQualityMetrics = () => computeTurnQualityMetrics({
|
|
53259
53492
|
iterationsUsed: iteration,
|
|
53260
53493
|
maxIterations,
|
|
53261
53494
|
executedTools,
|
|
53262
53495
|
hadError: hadTurnError,
|
|
53263
|
-
repeatedOutputsSuppressed
|
|
53496
|
+
repeatedOutputsSuppressed,
|
|
53497
|
+
observedLargeOutputs,
|
|
53498
|
+
observedLargeOutputChars
|
|
53264
53499
|
});
|
|
53265
53500
|
const abortReturn = () => {
|
|
53266
53501
|
session.messages.length = messageSnapshot;
|
|
@@ -53275,7 +53510,7 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
53275
53510
|
};
|
|
53276
53511
|
};
|
|
53277
53512
|
const allTools = toolRegistry.getToolDefinitionsForLLM();
|
|
53278
|
-
const tools = session.planMode ? filterReadOnlyTools(allTools) : allTools;
|
|
53513
|
+
const tools = session.planMode ? strictPlanModeEnabled ? filterStrictPlanModeTools(allTools) : filterReadOnlyTools(allTools) : allTools;
|
|
53279
53514
|
const availableMcpToolNames = allTools.map((t) => t.name).filter((name) => name.startsWith("mcp_"));
|
|
53280
53515
|
function extractPlainText(content) {
|
|
53281
53516
|
if (typeof content === "string") return content;
|
|
@@ -53318,6 +53553,38 @@ async function executeAgentTurn(session, userMessage, provider, toolRegistry, op
|
|
|
53318
53553
|
const INLINE_RESULT_MAX_CHARS = 8e3;
|
|
53319
53554
|
const INLINE_RESULT_HEAD_CHARS = 6500;
|
|
53320
53555
|
const INLINE_RESULT_TAIL_CHARS = 1e3;
|
|
53556
|
+
const OUTPUT_OFFLOAD_OBSERVATION_THRESHOLD = 12e3;
|
|
53557
|
+
const OUTPUT_OFFLOAD_PERSIST_THRESHOLD = 2e4;
|
|
53558
|
+
function shouldRetryStreamError(classification, responseSoFar, toolCallsSoFar, attempt, maxAttempts) {
|
|
53559
|
+
if (!recoveryV2Enabled) return false;
|
|
53560
|
+
if (attempt >= maxAttempts) return false;
|
|
53561
|
+
if (toolCallsSoFar.length > 0) return false;
|
|
53562
|
+
if (responseSoFar.trim().length > 0) return false;
|
|
53563
|
+
return classification.kind === "provider_retryable" || classification.kind === "unexpected";
|
|
53564
|
+
}
|
|
53565
|
+
async function pauseBeforeRetry(attempt) {
|
|
53566
|
+
const delayMs = Math.min(1200, 250 * attempt);
|
|
53567
|
+
await new Promise((resolve4) => setTimeout(resolve4, delayMs));
|
|
53568
|
+
}
|
|
53569
|
+
async function offloadLargeOutput(toolCall, content) {
|
|
53570
|
+
const artifactDir = path39__default.join(session.projectPath, ".coco", "session-artifacts", session.id);
|
|
53571
|
+
const safeToolName = toolCall.name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
53572
|
+
const artifactPath = path39__default.join(artifactDir, `${safeToolName}-${toolCall.id}.txt`);
|
|
53573
|
+
const relativeArtifactPath = path39__default.relative(session.projectPath, artifactPath);
|
|
53574
|
+
await mkdir(artifactDir, { recursive: true });
|
|
53575
|
+
await writeFile(artifactPath, content, "utf-8");
|
|
53576
|
+
return {
|
|
53577
|
+
artifactPath,
|
|
53578
|
+
toolResultContent: [
|
|
53579
|
+
`Large tool output stored in local artifact: ${relativeArtifactPath}`,
|
|
53580
|
+
`Original size: ${content.length.toLocaleString()} characters.`,
|
|
53581
|
+
"Use read_file on the artifact path if you need the full output.",
|
|
53582
|
+
"",
|
|
53583
|
+
"Preview:",
|
|
53584
|
+
truncateInlineResult(content, toolCall.name)
|
|
53585
|
+
].join("\n")
|
|
53586
|
+
};
|
|
53587
|
+
}
|
|
53321
53588
|
function truncateInlineResult(content, toolName) {
|
|
53322
53589
|
if (content.length <= INLINE_RESULT_MAX_CHARS) return content;
|
|
53323
53590
|
const head = content.slice(0, INLINE_RESULT_HEAD_CHARS);
|
|
@@ -53445,80 +53712,110 @@ ${tail}`;
|
|
|
53445
53712
|
const messages = getConversationContext(session, toolRegistry);
|
|
53446
53713
|
options.onThinkingStart?.();
|
|
53447
53714
|
let responseContent = "";
|
|
53448
|
-
|
|
53715
|
+
let collectedToolCalls = [];
|
|
53449
53716
|
let thinkingEnded = false;
|
|
53450
53717
|
let lastStopReason;
|
|
53451
|
-
const
|
|
53718
|
+
const maxStreamAttempts = recoveryV2Enabled ? 2 : 1;
|
|
53452
53719
|
try {
|
|
53453
|
-
|
|
53454
|
-
|
|
53455
|
-
|
|
53456
|
-
|
|
53457
|
-
|
|
53458
|
-
|
|
53459
|
-
break;
|
|
53460
|
-
}
|
|
53720
|
+
let streamAttempt = 0;
|
|
53721
|
+
while (streamAttempt < maxStreamAttempts) {
|
|
53722
|
+
responseContent = "";
|
|
53723
|
+
collectedToolCalls = [];
|
|
53724
|
+
lastStopReason = void 0;
|
|
53725
|
+
const toolCallBuilders = /* @__PURE__ */ new Map();
|
|
53461
53726
|
try {
|
|
53462
|
-
|
|
53463
|
-
|
|
53464
|
-
|
|
53465
|
-
|
|
53466
|
-
|
|
53467
|
-
|
|
53468
|
-
|
|
53469
|
-
iterationTextChunks.push(chunk);
|
|
53470
|
-
}
|
|
53471
|
-
if (chunk.type === "tool_use_start" && chunk.toolCall) {
|
|
53472
|
-
flushLineBuffer();
|
|
53473
|
-
if (!thinkingEnded) {
|
|
53474
|
-
options.onThinkingEnd?.();
|
|
53475
|
-
thinkingEnded = true;
|
|
53476
|
-
}
|
|
53477
|
-
const id = chunk.toolCall.id ?? `tool_${toolCallBuilders.size}`;
|
|
53478
|
-
const toolName = chunk.toolCall.name ?? "";
|
|
53479
|
-
toolCallBuilders.set(id, {
|
|
53480
|
-
id,
|
|
53481
|
-
name: toolName,
|
|
53482
|
-
input: {},
|
|
53483
|
-
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
|
|
53484
|
-
});
|
|
53485
|
-
if (toolName) {
|
|
53486
|
-
options.onToolPreparing?.(toolName);
|
|
53727
|
+
for await (const chunk of provider.streamWithTools(messages, {
|
|
53728
|
+
tools,
|
|
53729
|
+
maxTokens: session.config.provider.maxTokens,
|
|
53730
|
+
signal: options.signal
|
|
53731
|
+
})) {
|
|
53732
|
+
if (options.signal?.aborted) {
|
|
53733
|
+
break;
|
|
53487
53734
|
}
|
|
53488
|
-
|
|
53489
|
-
|
|
53490
|
-
|
|
53491
|
-
|
|
53492
|
-
|
|
53493
|
-
|
|
53494
|
-
|
|
53495
|
-
|
|
53496
|
-
|
|
53497
|
-
|
|
53498
|
-
|
|
53499
|
-
|
|
53500
|
-
|
|
53501
|
-
|
|
53502
|
-
|
|
53503
|
-
|
|
53504
|
-
|
|
53505
|
-
|
|
53506
|
-
|
|
53735
|
+
try {
|
|
53736
|
+
if (chunk.type === "text" && chunk.text) {
|
|
53737
|
+
if (!thinkingEnded) {
|
|
53738
|
+
options.onThinkingEnd?.();
|
|
53739
|
+
thinkingEnded = true;
|
|
53740
|
+
}
|
|
53741
|
+
responseContent += chunk.text;
|
|
53742
|
+
finalContent += chunk.text;
|
|
53743
|
+
iterationTextChunks.push(chunk);
|
|
53744
|
+
}
|
|
53745
|
+
if (chunk.type === "tool_use_start" && chunk.toolCall) {
|
|
53746
|
+
flushLineBuffer();
|
|
53747
|
+
if (!thinkingEnded) {
|
|
53748
|
+
options.onThinkingEnd?.();
|
|
53749
|
+
thinkingEnded = true;
|
|
53750
|
+
}
|
|
53751
|
+
const id = chunk.toolCall.id ?? `tool_${toolCallBuilders.size}`;
|
|
53752
|
+
const toolName = chunk.toolCall.name ?? "";
|
|
53753
|
+
toolCallBuilders.set(id, {
|
|
53754
|
+
id,
|
|
53755
|
+
name: toolName,
|
|
53756
|
+
input: {},
|
|
53757
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
|
|
53758
|
+
});
|
|
53759
|
+
if (toolName) {
|
|
53760
|
+
options.onToolPreparing?.(toolName);
|
|
53761
|
+
}
|
|
53762
|
+
}
|
|
53763
|
+
if (chunk.type === "tool_use_end" && chunk.toolCall) {
|
|
53764
|
+
const id = chunk.toolCall.id ?? "";
|
|
53765
|
+
const builder = toolCallBuilders.get(id);
|
|
53766
|
+
if (builder) {
|
|
53767
|
+
const finalToolCall = {
|
|
53768
|
+
id: builder.id,
|
|
53769
|
+
name: chunk.toolCall.name ?? builder.name,
|
|
53770
|
+
input: chunk.toolCall.input ?? builder.input,
|
|
53771
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature ?? builder.geminiThoughtSignature
|
|
53772
|
+
};
|
|
53773
|
+
collectedToolCalls.push(finalToolCall);
|
|
53774
|
+
} else if (chunk.toolCall.id && chunk.toolCall.name) {
|
|
53775
|
+
collectedToolCalls.push({
|
|
53776
|
+
id: chunk.toolCall.id,
|
|
53777
|
+
name: chunk.toolCall.name,
|
|
53778
|
+
input: chunk.toolCall.input ?? {},
|
|
53779
|
+
geminiThoughtSignature: chunk.toolCall.geminiThoughtSignature
|
|
53780
|
+
});
|
|
53781
|
+
}
|
|
53782
|
+
}
|
|
53783
|
+
if (chunk.type === "done") {
|
|
53784
|
+
if (chunk.stopReason) {
|
|
53785
|
+
lastStopReason = chunk.stopReason;
|
|
53786
|
+
}
|
|
53787
|
+
if (!thinkingEnded) {
|
|
53788
|
+
options.onThinkingEnd?.();
|
|
53789
|
+
thinkingEnded = true;
|
|
53790
|
+
}
|
|
53791
|
+
break;
|
|
53792
|
+
}
|
|
53793
|
+
} catch (chunkError) {
|
|
53794
|
+
const errorMsg = chunkError instanceof Error ? chunkError.message : String(chunkError);
|
|
53795
|
+
console.error(`[agent-loop] Error processing chunk: ${errorMsg}`);
|
|
53507
53796
|
}
|
|
53508
53797
|
}
|
|
53509
|
-
|
|
53510
|
-
|
|
53511
|
-
|
|
53512
|
-
|
|
53513
|
-
|
|
53514
|
-
|
|
53515
|
-
|
|
53516
|
-
|
|
53517
|
-
|
|
53798
|
+
break;
|
|
53799
|
+
} catch (streamError) {
|
|
53800
|
+
const classification = classifyAgentLoopError(streamError, options.signal);
|
|
53801
|
+
if (classification.kind === "abort") {
|
|
53802
|
+
throw classification.original;
|
|
53803
|
+
}
|
|
53804
|
+
if (classification.kind === "provider_non_retryable") {
|
|
53805
|
+
throw classification.original;
|
|
53806
|
+
}
|
|
53807
|
+
streamAttempt++;
|
|
53808
|
+
if (shouldRetryStreamError(
|
|
53809
|
+
classification,
|
|
53810
|
+
responseContent,
|
|
53811
|
+
collectedToolCalls,
|
|
53812
|
+
streamAttempt,
|
|
53813
|
+
maxStreamAttempts
|
|
53814
|
+
)) {
|
|
53815
|
+
await pauseBeforeRetry(streamAttempt);
|
|
53816
|
+
continue;
|
|
53518
53817
|
}
|
|
53519
|
-
|
|
53520
|
-
const errorMsg = chunkError instanceof Error ? chunkError.message : String(chunkError);
|
|
53521
|
-
console.error(`[agent-loop] Error processing chunk: ${errorMsg}`);
|
|
53818
|
+
throw classification.original;
|
|
53522
53819
|
}
|
|
53523
53820
|
}
|
|
53524
53821
|
} catch (streamError) {
|
|
@@ -53651,6 +53948,14 @@ ${tail}`;
|
|
|
53651
53948
|
options.onToolSkipped?.(toolCall, "Use mcp_list_servers instead of coco mcp CLI");
|
|
53652
53949
|
continue;
|
|
53653
53950
|
}
|
|
53951
|
+
if (strictPlanModeEnabled && !STRICT_PLAN_MODE_ALLOWED_TOOLS.has(toolCall.name)) {
|
|
53952
|
+
declinedTools.set(
|
|
53953
|
+
toolCall.id,
|
|
53954
|
+
`Blocked by strict plan mode: tool '${toolCall.name}' is not read-only`
|
|
53955
|
+
);
|
|
53956
|
+
options.onToolSkipped?.(toolCall, "Blocked by strict plan mode");
|
|
53957
|
+
continue;
|
|
53958
|
+
}
|
|
53654
53959
|
const trustPattern = getTrustPattern(toolCall.name, toolCall.input);
|
|
53655
53960
|
const needsConfirmation = !options.skipConfirmation && !session.trustedTools.has(trustPattern) && requiresConfirmation(toolCall.name, toolCall.input);
|
|
53656
53961
|
if (needsConfirmation) {
|
|
@@ -53735,29 +54040,29 @@ ${tail}`;
|
|
|
53735
54040
|
const patterns = executed.input.patterns;
|
|
53736
54041
|
const scope = executed.input.scope || "project";
|
|
53737
54042
|
if (Array.isArray(patterns)) {
|
|
53738
|
-
for (const
|
|
54043
|
+
for (const p47 of patterns) {
|
|
53739
54044
|
if (action === "allow") {
|
|
53740
|
-
session.trustedTools.add(
|
|
54045
|
+
session.trustedTools.add(p47);
|
|
53741
54046
|
if (scope === "global") {
|
|
53742
|
-
saveTrustedTool(
|
|
54047
|
+
saveTrustedTool(p47, null, true).catch(() => {
|
|
53743
54048
|
});
|
|
53744
54049
|
} else {
|
|
53745
|
-
saveTrustedTool(
|
|
54050
|
+
saveTrustedTool(p47, session.projectPath, false).catch(() => {
|
|
53746
54051
|
});
|
|
53747
54052
|
}
|
|
53748
|
-
removeDeniedTool(
|
|
54053
|
+
removeDeniedTool(p47, session.projectPath).catch(() => {
|
|
53749
54054
|
});
|
|
53750
54055
|
} else if (action === "deny") {
|
|
53751
|
-
session.trustedTools.delete(
|
|
54056
|
+
session.trustedTools.delete(p47);
|
|
53752
54057
|
if (scope === "global") {
|
|
53753
|
-
removeTrustedTool(
|
|
54058
|
+
removeTrustedTool(p47, session.projectPath, true).catch(() => {
|
|
53754
54059
|
});
|
|
53755
54060
|
} else {
|
|
53756
|
-
saveDeniedTool(
|
|
54061
|
+
saveDeniedTool(p47, session.projectPath).catch(() => {
|
|
53757
54062
|
});
|
|
53758
54063
|
}
|
|
53759
54064
|
} else {
|
|
53760
|
-
session.trustedTools.delete(
|
|
54065
|
+
session.trustedTools.delete(p47);
|
|
53761
54066
|
}
|
|
53762
54067
|
}
|
|
53763
54068
|
}
|
|
@@ -53803,10 +54108,21 @@ ${tail}`;
|
|
|
53803
54108
|
}
|
|
53804
54109
|
const executedCall = executedTools.find((e) => e.id === toolCall.id);
|
|
53805
54110
|
if (executedCall) {
|
|
53806
|
-
|
|
54111
|
+
if (outputOffloadObservationEnabled && executedCall.result.output.length > OUTPUT_OFFLOAD_OBSERVATION_THRESHOLD) {
|
|
54112
|
+
observedLargeOutputs++;
|
|
54113
|
+
observedLargeOutputChars += executedCall.result.output.length;
|
|
54114
|
+
}
|
|
54115
|
+
let toolResultContent = truncateInlineResult(executedCall.result.output, toolCall.name);
|
|
54116
|
+
if (outputOffloadObservationEnabled && executedCall.result.success && executedCall.result.output.length > OUTPUT_OFFLOAD_PERSIST_THRESHOLD) {
|
|
54117
|
+
try {
|
|
54118
|
+
const offloaded = await offloadLargeOutput(toolCall, executedCall.result.output);
|
|
54119
|
+
toolResultContent = offloaded.toolResultContent;
|
|
54120
|
+
} catch {
|
|
54121
|
+
}
|
|
54122
|
+
}
|
|
53807
54123
|
const transformedOutput = repeatedOutputSuppressor.transform(
|
|
53808
54124
|
toolCall.name,
|
|
53809
|
-
|
|
54125
|
+
toolResultContent
|
|
53810
54126
|
);
|
|
53811
54127
|
if (transformedOutput.suppressed) {
|
|
53812
54128
|
repeatedOutputsSuppressed++;
|
|
@@ -54054,9 +54370,30 @@ var PLAN_MODE_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
|
54054
54370
|
"spawnSimpleAgent",
|
|
54055
54371
|
"checkAgentCapability"
|
|
54056
54372
|
]);
|
|
54373
|
+
var STRICT_PLAN_MODE_ALLOWED_TOOLS = /* @__PURE__ */ new Set([
|
|
54374
|
+
"glob",
|
|
54375
|
+
"read_file",
|
|
54376
|
+
"list_dir",
|
|
54377
|
+
"tree",
|
|
54378
|
+
"grep",
|
|
54379
|
+
"find_in_file",
|
|
54380
|
+
"semantic_search",
|
|
54381
|
+
"codebase_map",
|
|
54382
|
+
"git_status",
|
|
54383
|
+
"git_log",
|
|
54384
|
+
"git_diff",
|
|
54385
|
+
"git_show",
|
|
54386
|
+
"git_branch",
|
|
54387
|
+
"recall_memory",
|
|
54388
|
+
"list_memories",
|
|
54389
|
+
"list_checkpoints"
|
|
54390
|
+
]);
|
|
54057
54391
|
function filterReadOnlyTools(tools) {
|
|
54058
54392
|
return tools.filter((tool) => PLAN_MODE_ALLOWED_TOOLS.has(tool.name));
|
|
54059
54393
|
}
|
|
54394
|
+
function filterStrictPlanModeTools(tools) {
|
|
54395
|
+
return tools.filter((tool) => STRICT_PLAN_MODE_ALLOWED_TOOLS.has(tool.name));
|
|
54396
|
+
}
|
|
54060
54397
|
|
|
54061
54398
|
// src/cli/repl/index.ts
|
|
54062
54399
|
init_error_resilience();
|
|
@@ -54836,8 +55173,8 @@ async function startRepl(options = {}) {
|
|
|
54836
55173
|
};
|
|
54837
55174
|
const getAutoSwitchCandidates = (current) => {
|
|
54838
55175
|
const ordered = [];
|
|
54839
|
-
const push = (
|
|
54840
|
-
if (
|
|
55176
|
+
const push = (p47) => {
|
|
55177
|
+
if (p47 !== current && !ordered.includes(p47)) ordered.push(p47);
|
|
54841
55178
|
};
|
|
54842
55179
|
if (current === "openai") {
|
|
54843
55180
|
push("codex");
|
|
@@ -54875,7 +55212,7 @@ async function startRepl(options = {}) {
|
|
|
54875
55212
|
"lmstudio",
|
|
54876
55213
|
"ollama"
|
|
54877
55214
|
];
|
|
54878
|
-
for (const
|
|
55215
|
+
for (const p47 of genericOrder) push(p47);
|
|
54879
55216
|
return ordered;
|
|
54880
55217
|
};
|
|
54881
55218
|
const attemptAutoProviderSwitch = async (reason, originalMessage) => {
|