agdi 2.6.0 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +313 -224
- package/package.json +8 -3
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import { Command } from "commander";
|
|
10
|
-
import
|
|
10
|
+
import chalk14 from "chalk";
|
|
11
11
|
import ora5 from "ora";
|
|
12
12
|
|
|
13
13
|
// src/core/llm/index.ts
|
|
@@ -1425,12 +1425,115 @@ async function selectModel() {
|
|
|
1425
1425
|
|
|
1426
1426
|
// src/commands/agdi-dev.ts
|
|
1427
1427
|
import { input as input5, confirm as confirm3 } from "@inquirer/prompts";
|
|
1428
|
-
import
|
|
1429
|
-
|
|
1428
|
+
import chalk13 from "chalk";
|
|
1429
|
+
|
|
1430
|
+
// src/utils/ui.ts
|
|
1431
|
+
import chalk8 from "chalk";
|
|
1432
|
+
import gradient from "gradient-string";
|
|
1433
|
+
import boxen from "boxen";
|
|
1434
|
+
import figlet from "figlet";
|
|
1435
|
+
import ora3 from "ora";
|
|
1436
|
+
var THEME = {
|
|
1437
|
+
cyan: "#06b6d4",
|
|
1438
|
+
// Cyan-500
|
|
1439
|
+
purple: "#8b5cf6",
|
|
1440
|
+
// Violet-500
|
|
1441
|
+
red: "#ef4444",
|
|
1442
|
+
// Red-500
|
|
1443
|
+
yellow: "#eab308",
|
|
1444
|
+
// Yellow-500
|
|
1445
|
+
gray: "#71717a",
|
|
1446
|
+
// Zinc-500
|
|
1447
|
+
dim: "#52525b"
|
|
1448
|
+
// Zinc-600
|
|
1449
|
+
};
|
|
1450
|
+
var brandGradient = gradient([THEME.cyan, THEME.purple]);
|
|
1451
|
+
var errorGradient = gradient([THEME.red, "#b91c1c"]);
|
|
1452
|
+
var goldGradient = gradient([THEME.yellow, "#fbbf24"]);
|
|
1453
|
+
async function renderBanner(version = "v2.6.0") {
|
|
1454
|
+
console.clear();
|
|
1455
|
+
const text = await new Promise((resolve5) => {
|
|
1456
|
+
figlet("AGDI", { font: "Slant" }, (err, data) => {
|
|
1457
|
+
resolve5(data || "AGDI");
|
|
1458
|
+
});
|
|
1459
|
+
});
|
|
1460
|
+
console.log(brandGradient.multiline(text));
|
|
1461
|
+
console.log(chalk8.hex(THEME.dim)(` ${version} [ARCHITECT ONLINE]
|
|
1462
|
+
`));
|
|
1463
|
+
}
|
|
1464
|
+
function renderBox(title, content, style = "info") {
|
|
1465
|
+
let borderColor = THEME.cyan;
|
|
1466
|
+
let titleColor = chalk8.cyan;
|
|
1467
|
+
if (style === "success") {
|
|
1468
|
+
borderColor = THEME.cyan;
|
|
1469
|
+
} else if (style === "warning") {
|
|
1470
|
+
borderColor = THEME.yellow;
|
|
1471
|
+
titleColor = chalk8.yellow;
|
|
1472
|
+
} else if (style === "error") {
|
|
1473
|
+
borderColor = THEME.red;
|
|
1474
|
+
titleColor = chalk8.red;
|
|
1475
|
+
}
|
|
1476
|
+
const box = boxen(content, {
|
|
1477
|
+
title: titleColor.bold(title),
|
|
1478
|
+
padding: 1,
|
|
1479
|
+
margin: 1,
|
|
1480
|
+
borderStyle: "round",
|
|
1481
|
+
borderColor,
|
|
1482
|
+
dimBorder: false,
|
|
1483
|
+
float: "left"
|
|
1484
|
+
});
|
|
1485
|
+
console.log(box);
|
|
1486
|
+
}
|
|
1487
|
+
function renderAlert(title, message) {
|
|
1488
|
+
console.log("");
|
|
1489
|
+
const box = boxen(chalk8.white(message), {
|
|
1490
|
+
title: chalk8.red.bold(`\u{1F6E1}\uFE0F ${title.toUpperCase()} `),
|
|
1491
|
+
padding: 1,
|
|
1492
|
+
borderStyle: "double",
|
|
1493
|
+
borderColor: "red",
|
|
1494
|
+
textAlignment: "center"
|
|
1495
|
+
});
|
|
1496
|
+
console.log(box);
|
|
1497
|
+
console.log("");
|
|
1498
|
+
}
|
|
1499
|
+
function printUserMessage(message) {
|
|
1500
|
+
console.log("");
|
|
1501
|
+
console.log(chalk8.cyan.bold("\u{1F464} YOU \u203A ") + chalk8.white(message));
|
|
1502
|
+
console.log("");
|
|
1503
|
+
}
|
|
1504
|
+
function printAIMessage(message) {
|
|
1505
|
+
console.log("");
|
|
1506
|
+
console.log(brandGradient.multiline("\u26A1 AGDI \u203A "));
|
|
1507
|
+
console.log(message.trim());
|
|
1508
|
+
console.log("");
|
|
1509
|
+
}
|
|
1510
|
+
function createSpinner(text) {
|
|
1511
|
+
return ora3({
|
|
1512
|
+
text: chalk8.hex(THEME.gray)(text),
|
|
1513
|
+
color: "cyan",
|
|
1514
|
+
spinner: "dots",
|
|
1515
|
+
discardStdin: false
|
|
1516
|
+
// Important for allowing interruption if needed
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
function printIter() {
|
|
1520
|
+
console.log(chalk8.hex(THEME.dim)("\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1521
|
+
}
|
|
1522
|
+
var ui = {
|
|
1523
|
+
renderBanner,
|
|
1524
|
+
renderBox,
|
|
1525
|
+
renderAlert,
|
|
1526
|
+
printUserMessage,
|
|
1527
|
+
printAIMessage,
|
|
1528
|
+
createSpinner,
|
|
1529
|
+
printIter,
|
|
1530
|
+
brandGradient,
|
|
1531
|
+
THEME
|
|
1532
|
+
};
|
|
1430
1533
|
|
|
1431
1534
|
// src/actions/plan-executor.ts
|
|
1432
1535
|
import { select as select4, confirm } from "@inquirer/prompts";
|
|
1433
|
-
import
|
|
1536
|
+
import chalk11 from "chalk";
|
|
1434
1537
|
import { spawn as spawn2 } from "child_process";
|
|
1435
1538
|
import { resolve as resolve4 } from "path";
|
|
1436
1539
|
|
|
@@ -1565,7 +1668,7 @@ import { existsSync as existsSync3 } from "fs";
|
|
|
1565
1668
|
import { resolve, dirname, relative, isAbsolute } from "path";
|
|
1566
1669
|
|
|
1567
1670
|
// src/security/execution-env.ts
|
|
1568
|
-
import
|
|
1671
|
+
import chalk9 from "chalk";
|
|
1569
1672
|
import { platform } from "os";
|
|
1570
1673
|
import { existsSync, readFileSync } from "fs";
|
|
1571
1674
|
function detectWSL() {
|
|
@@ -1674,11 +1777,11 @@ function formatNetwork(policy, domains) {
|
|
|
1674
1777
|
function formatTrust(trust) {
|
|
1675
1778
|
switch (trust) {
|
|
1676
1779
|
case "untrusted":
|
|
1677
|
-
return
|
|
1780
|
+
return chalk9.red("untrusted (read-only mode)");
|
|
1678
1781
|
case "session":
|
|
1679
|
-
return
|
|
1782
|
+
return chalk9.yellow("session trusted");
|
|
1680
1783
|
case "persistent":
|
|
1681
|
-
return
|
|
1784
|
+
return chalk9.green("trusted");
|
|
1682
1785
|
}
|
|
1683
1786
|
}
|
|
1684
1787
|
function displaySessionHeader(env) {
|
|
@@ -1692,12 +1795,12 @@ function displaySessionHeader(env) {
|
|
|
1692
1795
|
`Network: ${formatNetwork(env.networkPolicy, env.allowedDomains)}`,
|
|
1693
1796
|
`Trust: ${formatTrust(env.trustLevel)}`
|
|
1694
1797
|
];
|
|
1695
|
-
console.log(
|
|
1798
|
+
console.log(chalk9.cyan(topBorder));
|
|
1696
1799
|
for (const line of lines) {
|
|
1697
1800
|
const padding = " ".repeat(Math.max(0, boxWidth - stripAnsi(line).length - 2));
|
|
1698
|
-
console.log(
|
|
1801
|
+
console.log(chalk9.cyan("\u2502 ") + line + padding + chalk9.cyan(" \u2502"));
|
|
1699
1802
|
}
|
|
1700
|
-
console.log(
|
|
1803
|
+
console.log(chalk9.cyan(bottomBorder));
|
|
1701
1804
|
console.log("");
|
|
1702
1805
|
}
|
|
1703
1806
|
function truncatePath(path4, maxLen) {
|
|
@@ -2696,7 +2799,7 @@ function getRiskDescription(tier, argv) {
|
|
|
2696
2799
|
|
|
2697
2800
|
// src/security/workspace-trust.ts
|
|
2698
2801
|
import { select as select3 } from "@inquirer/prompts";
|
|
2699
|
-
import
|
|
2802
|
+
import chalk10 from "chalk";
|
|
2700
2803
|
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
2701
2804
|
import { join as join3, resolve as resolve3 } from "path";
|
|
2702
2805
|
import { homedir as homedir4 } from "os";
|
|
@@ -2745,14 +2848,14 @@ function trustWorkspace(workspacePath) {
|
|
|
2745
2848
|
}
|
|
2746
2849
|
async function promptWorkspaceTrust(workspacePath) {
|
|
2747
2850
|
if (isWorkspaceTrusted(workspacePath)) {
|
|
2748
|
-
console.log(
|
|
2851
|
+
console.log(chalk10.green("\u2713 Workspace is trusted\n"));
|
|
2749
2852
|
return "persistent";
|
|
2750
2853
|
}
|
|
2751
|
-
console.log(
|
|
2752
|
-
console.log(
|
|
2854
|
+
console.log(chalk10.yellow("\n\u26A0\uFE0F Untrusted Workspace"));
|
|
2855
|
+
console.log(chalk10.gray(` ${workspacePath}
|
|
2753
2856
|
`));
|
|
2754
|
-
console.log(
|
|
2755
|
-
console.log(
|
|
2857
|
+
console.log(chalk10.gray("Agdi can run commands in this workspace."));
|
|
2858
|
+
console.log(chalk10.gray("Do you trust the contents of this folder?\n"));
|
|
2756
2859
|
const choice = await select3({
|
|
2757
2860
|
message: "Trust this workspace?",
|
|
2758
2861
|
choices: [
|
|
@@ -2780,15 +2883,15 @@ async function handleTrustFlow(workspacePath) {
|
|
|
2780
2883
|
switch (choice) {
|
|
2781
2884
|
case "session":
|
|
2782
2885
|
updateEnvironment({ trustLevel: "session" });
|
|
2783
|
-
console.log(
|
|
2886
|
+
console.log(chalk10.green("\u2713 Trusted for this session\n"));
|
|
2784
2887
|
return "session";
|
|
2785
2888
|
case "persistent":
|
|
2786
2889
|
trustWorkspace(workspacePath);
|
|
2787
2890
|
updateEnvironment({ trustLevel: "persistent" });
|
|
2788
|
-
console.log(
|
|
2891
|
+
console.log(chalk10.green("\u2713 Workspace trusted and remembered\n"));
|
|
2789
2892
|
return "persistent";
|
|
2790
2893
|
case "exit":
|
|
2791
|
-
console.log(
|
|
2894
|
+
console.log(chalk10.yellow("\n\u{1F44B} Exiting. Workspace not trusted.\n"));
|
|
2792
2895
|
return null;
|
|
2793
2896
|
}
|
|
2794
2897
|
}
|
|
@@ -2856,53 +2959,33 @@ async function downloadImageAsBase64(url) {
|
|
|
2856
2959
|
// src/actions/plan-executor.ts
|
|
2857
2960
|
function displayPlanSummary(plan) {
|
|
2858
2961
|
const summary = summarizePlan(plan);
|
|
2859
|
-
const boxWidth = 56;
|
|
2860
|
-
console.log("");
|
|
2861
|
-
console.log(chalk10.cyan("\u256D\u2500 Action Plan \u2500" + "\u2500".repeat(boxWidth - 15) + "\u256E"));
|
|
2862
|
-
console.log(chalk10.cyan("\u2502 ") + chalk10.white(`Project: ${plan.projectName}`.padEnd(boxWidth - 2)) + chalk10.cyan(" \u2502"));
|
|
2863
|
-
console.log(chalk10.cyan("\u2502 ") + "\u2500".repeat(boxWidth - 2) + chalk10.cyan(" \u2502"));
|
|
2864
2962
|
const lines = [];
|
|
2865
|
-
if (summary.dirsCreated > 0) {
|
|
2866
|
-
|
|
2867
|
-
}
|
|
2868
|
-
if (summary.
|
|
2869
|
-
|
|
2870
|
-
}
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
}
|
|
2874
|
-
if (summary.commandsToRun > 0) {
|
|
2875
|
-
lines.push(`\u26A1 Run ${summary.commandsToRun} commands`);
|
|
2876
|
-
}
|
|
2877
|
-
if (summary.domains.length > 0) {
|
|
2878
|
-
lines.push(`\u{1F310} Network: ${summary.domains.join(", ")}`);
|
|
2879
|
-
}
|
|
2880
|
-
if (summary.ports.length > 0) {
|
|
2881
|
-
lines.push(`\u{1F50C} Ports: ${summary.ports.join(", ")}`);
|
|
2882
|
-
}
|
|
2883
|
-
for (const line of lines) {
|
|
2884
|
-
console.log(chalk10.cyan("\u2502 ") + chalk10.gray(line.padEnd(boxWidth - 2)) + chalk10.cyan(" \u2502"));
|
|
2885
|
-
}
|
|
2886
|
-
console.log(chalk10.cyan("\u2570" + "\u2500".repeat(boxWidth) + "\u256F"));
|
|
2887
|
-
console.log("");
|
|
2963
|
+
if (summary.dirsCreated > 0) lines.push(`\u{1F4C1} Create ${summary.dirsCreated} directories`);
|
|
2964
|
+
if (summary.filesCreated > 0) lines.push(`\u{1F4C4} Create ${summary.filesCreated} files`);
|
|
2965
|
+
if (summary.filesDeleted > 0) lines.push(`\u{1F5D1}\uFE0F Delete ${summary.filesDeleted} files`);
|
|
2966
|
+
if (summary.commandsToRun > 0) lines.push(`\u26A1 Run ${summary.commandsToRun} commands`);
|
|
2967
|
+
if (summary.domains.length > 0) lines.push(`\u{1F310} Network: ${summary.domains.join(", ")}`);
|
|
2968
|
+
if (summary.ports.length > 0) lines.push(`\u{1F50C} Ports: ${summary.ports.join(", ")}`);
|
|
2969
|
+
const content = lines.join("\n");
|
|
2970
|
+
ui.renderBox(`PLAN: ${plan.projectName}`, content, "info");
|
|
2888
2971
|
}
|
|
2889
2972
|
function displayActionProgress(action, index, total) {
|
|
2890
2973
|
const num = `[${index + 1}/${total}]`;
|
|
2891
2974
|
switch (action.type) {
|
|
2892
2975
|
case "mkdir":
|
|
2893
|
-
console.log(
|
|
2976
|
+
console.log(chalk11.gray(`${num} Creating directory: ${action.path}`));
|
|
2894
2977
|
break;
|
|
2895
2978
|
case "writeFile":
|
|
2896
|
-
console.log(
|
|
2979
|
+
console.log(chalk11.gray(`${num} Writing file: ${action.path}`));
|
|
2897
2980
|
break;
|
|
2898
2981
|
case "deleteFile":
|
|
2899
|
-
console.log(
|
|
2982
|
+
console.log(chalk11.gray(`${num} Deleting file: ${action.path}`));
|
|
2900
2983
|
break;
|
|
2901
2984
|
case "exec":
|
|
2902
|
-
console.log(
|
|
2985
|
+
console.log(chalk11.blue(`${num} Running: ${action.argv.join(" ")}`));
|
|
2903
2986
|
break;
|
|
2904
2987
|
case "generateImage":
|
|
2905
|
-
console.log(
|
|
2988
|
+
console.log(chalk11.magenta(`${num} \u{1F3A8} Generating image: ${action.savePath}`));
|
|
2906
2989
|
break;
|
|
2907
2990
|
}
|
|
2908
2991
|
}
|
|
@@ -3013,16 +3096,16 @@ async function executeAction(action) {
|
|
|
3013
3096
|
};
|
|
3014
3097
|
}
|
|
3015
3098
|
try {
|
|
3016
|
-
console.log(
|
|
3099
|
+
console.log(chalk11.gray(` Prompt: "${action.prompt.slice(0, 50)}..."`));
|
|
3017
3100
|
const result = await generateImage(action.prompt, apiKey, { style: action.style });
|
|
3018
3101
|
if (result.url) {
|
|
3019
3102
|
const base64Data = await downloadImageAsBase64(result.url);
|
|
3020
3103
|
const imageBuffer = Buffer.from(base64Data, "base64");
|
|
3021
3104
|
await writeFileTool(action.savePath, imageBuffer.toString("base64"));
|
|
3022
|
-
console.log(
|
|
3105
|
+
console.log(chalk11.green(` \u2713 Saved to ${action.savePath}`));
|
|
3023
3106
|
} else if (result.base64) {
|
|
3024
3107
|
await writeFileTool(action.savePath, result.base64);
|
|
3025
|
-
console.log(
|
|
3108
|
+
console.log(chalk11.green(` \u2713 Saved to ${action.savePath}`));
|
|
3026
3109
|
}
|
|
3027
3110
|
return {
|
|
3028
3111
|
action,
|
|
@@ -3048,18 +3131,19 @@ async function executePlan(plan) {
|
|
|
3048
3131
|
displayPlanSummary(plan);
|
|
3049
3132
|
const dryRun = await dryRunActions(plan);
|
|
3050
3133
|
if (!dryRun.canProceed) {
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
console.log(chalk10.red(` - ${result.command}: ${result.reason}`));
|
|
3055
|
-
errors.push(result.reason);
|
|
3056
|
-
}
|
|
3057
|
-
}
|
|
3134
|
+
const errorLines = dryRun.gateResults.filter((r) => r.decision === "deny").map((r) => `\u2022 ${r.command}: ${r.reason}`);
|
|
3135
|
+
ui.renderBox("BLOCKED ACTIONS", errorLines.join("\n"), "error");
|
|
3136
|
+
dryRun.gateResults.filter((r) => r.decision === "deny").forEach((r) => errors.push(r.reason));
|
|
3058
3137
|
return { success: false, results, filesCreated, commandsRun, errors };
|
|
3059
3138
|
}
|
|
3060
3139
|
if (dryRun.requiresTrust) {
|
|
3061
|
-
|
|
3062
|
-
|
|
3140
|
+
ui.renderAlert(
|
|
3141
|
+
"UNTRUSTED WORKSPACE",
|
|
3142
|
+
`The agent wants to execute ${plan.actions.length} actions in this folder.
|
|
3143
|
+
This includes writing files and/or running commands.
|
|
3144
|
+
|
|
3145
|
+
Target: ${env.workspaceRoot}`
|
|
3146
|
+
);
|
|
3063
3147
|
const trustChoice = await select4({
|
|
3064
3148
|
message: "Trust this workspace?",
|
|
3065
3149
|
choices: [
|
|
@@ -3069,16 +3153,16 @@ async function executePlan(plan) {
|
|
|
3069
3153
|
]
|
|
3070
3154
|
});
|
|
3071
3155
|
if (trustChoice === "cancel") {
|
|
3072
|
-
console.log(
|
|
3156
|
+
console.log(chalk11.yellow("\n\u{1F44B} Plan cancelled.\n"));
|
|
3073
3157
|
return { success: false, results, filesCreated, commandsRun, errors: ["User cancelled"] };
|
|
3074
3158
|
}
|
|
3075
3159
|
if (trustChoice === "persistent") {
|
|
3076
3160
|
trustWorkspace(env.workspaceRoot);
|
|
3077
3161
|
updateEnvironment({ trustLevel: "persistent" });
|
|
3078
|
-
console.log(
|
|
3162
|
+
console.log(chalk11.green("\u2713 Workspace trusted and remembered\n"));
|
|
3079
3163
|
} else {
|
|
3080
3164
|
updateEnvironment({ trustLevel: "session" });
|
|
3081
|
-
console.log(
|
|
3165
|
+
console.log(chalk11.green("\u2713 Trusted for this session\n"));
|
|
3082
3166
|
}
|
|
3083
3167
|
}
|
|
3084
3168
|
const approved = await confirm({
|
|
@@ -3086,7 +3170,7 @@ async function executePlan(plan) {
|
|
|
3086
3170
|
default: true
|
|
3087
3171
|
});
|
|
3088
3172
|
if (!approved) {
|
|
3089
|
-
console.log(
|
|
3173
|
+
console.log(chalk11.yellow("\n\u{1F44B} Plan cancelled.\n"));
|
|
3090
3174
|
return { success: false, results, filesCreated, commandsRun, errors: ["User cancelled"] };
|
|
3091
3175
|
}
|
|
3092
3176
|
logEvent({
|
|
@@ -3097,7 +3181,7 @@ async function executePlan(plan) {
|
|
|
3097
3181
|
summary: summarizePlan(plan)
|
|
3098
3182
|
}
|
|
3099
3183
|
});
|
|
3100
|
-
console.log(
|
|
3184
|
+
console.log(chalk11.cyan("\n\u25B6 Executing plan...\n"));
|
|
3101
3185
|
for (let i = 0; i < plan.actions.length; i++) {
|
|
3102
3186
|
const action = plan.actions[i];
|
|
3103
3187
|
displayActionProgress(action, i, plan.actions.length);
|
|
@@ -3112,24 +3196,24 @@ async function executePlan(plan) {
|
|
|
3112
3196
|
}
|
|
3113
3197
|
} else {
|
|
3114
3198
|
errors.push(result.error || "Unknown error");
|
|
3115
|
-
console.log(
|
|
3199
|
+
console.log(chalk11.red(` \u2717 Failed: ${result.error}`));
|
|
3116
3200
|
}
|
|
3117
3201
|
}
|
|
3118
3202
|
const success = errors.length === 0;
|
|
3119
3203
|
if (success) {
|
|
3120
|
-
console.log(
|
|
3204
|
+
console.log(chalk11.green(`
|
|
3121
3205
|
\u2713 Plan executed successfully!`));
|
|
3122
|
-
console.log(
|
|
3123
|
-
console.log(
|
|
3206
|
+
console.log(chalk11.gray(` Created ${filesCreated.length} files`));
|
|
3207
|
+
console.log(chalk11.gray(` Ran ${commandsRun.length} commands
|
|
3124
3208
|
`));
|
|
3125
3209
|
} else {
|
|
3126
|
-
console.log(
|
|
3210
|
+
console.log(chalk11.red(`
|
|
3127
3211
|
\u2717 Plan completed with ${errors.length} errors
|
|
3128
3212
|
`));
|
|
3129
3213
|
}
|
|
3130
3214
|
if (plan.nextSteps) {
|
|
3131
|
-
console.log(
|
|
3132
|
-
console.log(
|
|
3215
|
+
console.log(chalk11.cyan("Next steps:"));
|
|
3216
|
+
console.log(chalk11.gray(` ${plan.nextSteps}
|
|
3133
3217
|
`));
|
|
3134
3218
|
}
|
|
3135
3219
|
logEvent({
|
|
@@ -3149,7 +3233,7 @@ async function executePlan(plan) {
|
|
|
3149
3233
|
async function parseAndExecutePlan(response) {
|
|
3150
3234
|
const plan = parseActionPlan(response);
|
|
3151
3235
|
if (!plan) {
|
|
3152
|
-
console.log(
|
|
3236
|
+
console.log(chalk11.yellow("\n\u26A0\uFE0F Could not parse action plan from response.\n"));
|
|
3153
3237
|
return null;
|
|
3154
3238
|
}
|
|
3155
3239
|
return executePlan(plan);
|
|
@@ -3719,8 +3803,8 @@ function clearConversation() {
|
|
|
3719
3803
|
// src/core/file-editor.ts
|
|
3720
3804
|
import { readFile as readFile2 } from "fs/promises";
|
|
3721
3805
|
import { existsSync as existsSync9 } from "fs";
|
|
3722
|
-
import
|
|
3723
|
-
import
|
|
3806
|
+
import chalk12 from "chalk";
|
|
3807
|
+
import ora4 from "ora";
|
|
3724
3808
|
import { input as input4, confirm as confirm2 } from "@inquirer/prompts";
|
|
3725
3809
|
var EDIT_SYSTEM_PROMPT = `You are a surgical code editor. Given a file's content and an edit instruction, output ONLY a unified diff patch.
|
|
3726
3810
|
|
|
@@ -3787,19 +3871,19 @@ function extractDiff(response) {
|
|
|
3787
3871
|
return null;
|
|
3788
3872
|
}
|
|
3789
3873
|
function previewDiff(diff) {
|
|
3790
|
-
console.log(
|
|
3874
|
+
console.log(chalk12.cyan.bold("\n\u{1F4DD} Proposed Changes:\n"));
|
|
3791
3875
|
const lines = diff.split("\n");
|
|
3792
3876
|
for (const line of lines) {
|
|
3793
3877
|
if (line.startsWith("+++") || line.startsWith("---")) {
|
|
3794
|
-
console.log(
|
|
3878
|
+
console.log(chalk12.gray(line));
|
|
3795
3879
|
} else if (line.startsWith("@@")) {
|
|
3796
|
-
console.log(
|
|
3880
|
+
console.log(chalk12.cyan(line));
|
|
3797
3881
|
} else if (line.startsWith("+")) {
|
|
3798
|
-
console.log(
|
|
3882
|
+
console.log(chalk12.green(line));
|
|
3799
3883
|
} else if (line.startsWith("-")) {
|
|
3800
|
-
console.log(
|
|
3884
|
+
console.log(chalk12.red(line));
|
|
3801
3885
|
} else {
|
|
3802
|
-
console.log(
|
|
3886
|
+
console.log(chalk12.gray(line));
|
|
3803
3887
|
}
|
|
3804
3888
|
}
|
|
3805
3889
|
console.log("");
|
|
@@ -3820,35 +3904,35 @@ function countChanges(diff) {
|
|
|
3820
3904
|
async function handleFileEdit(filePath, llm) {
|
|
3821
3905
|
const env = getEnvironment();
|
|
3822
3906
|
if (!fileExists(filePath)) {
|
|
3823
|
-
console.log(
|
|
3907
|
+
console.log(chalk12.red(`
|
|
3824
3908
|
\u2717 File not found: ${filePath}
|
|
3825
3909
|
`));
|
|
3826
3910
|
return { success: false, error: "File not found" };
|
|
3827
3911
|
}
|
|
3828
3912
|
const fileData = await readFileForEdit(filePath);
|
|
3829
3913
|
if (!fileData) {
|
|
3830
|
-
console.log(
|
|
3914
|
+
console.log(chalk12.red(`
|
|
3831
3915
|
\u2717 Could not read file: ${filePath}
|
|
3832
3916
|
`));
|
|
3833
3917
|
return { success: false, error: "Could not read file" };
|
|
3834
3918
|
}
|
|
3835
3919
|
const previewLines = fileData.numbered.split("\n").slice(0, 20);
|
|
3836
|
-
console.log(
|
|
3920
|
+
console.log(chalk12.cyan.bold(`
|
|
3837
3921
|
\u{1F4C4} ${filePath}
|
|
3838
3922
|
`));
|
|
3839
|
-
console.log(
|
|
3923
|
+
console.log(chalk12.gray(previewLines.join("\n")));
|
|
3840
3924
|
if (fileData.content.split("\n").length > 20) {
|
|
3841
|
-
console.log(
|
|
3925
|
+
console.log(chalk12.gray(` ... (${fileData.content.split("\n").length - 20} more lines)`));
|
|
3842
3926
|
}
|
|
3843
3927
|
console.log("");
|
|
3844
3928
|
const instruction = await input4({
|
|
3845
|
-
message:
|
|
3929
|
+
message: chalk12.yellow("Describe the edit:")
|
|
3846
3930
|
});
|
|
3847
3931
|
if (!instruction.trim()) {
|
|
3848
|
-
console.log(
|
|
3932
|
+
console.log(chalk12.gray("\n(no instruction provided)\n"));
|
|
3849
3933
|
return { success: false, error: "No instruction" };
|
|
3850
3934
|
}
|
|
3851
|
-
const spinner =
|
|
3935
|
+
const spinner = ora4("Generating edit...").start();
|
|
3852
3936
|
try {
|
|
3853
3937
|
const prompt = `File: ${filePath}
|
|
3854
3938
|
|
|
@@ -3864,27 +3948,27 @@ Generate the unified diff to make this change.`;
|
|
|
3864
3948
|
spinner.stop();
|
|
3865
3949
|
const diff = extractDiff(response.text);
|
|
3866
3950
|
if (!diff) {
|
|
3867
|
-
console.log(
|
|
3868
|
-
console.log(
|
|
3951
|
+
console.log(chalk12.yellow("\n\u26A0\uFE0F Could not generate a valid diff.\n"));
|
|
3952
|
+
console.log(chalk12.gray("AI response:\n" + response.text.slice(0, 500)));
|
|
3869
3953
|
return { success: false, error: "Invalid diff generated" };
|
|
3870
3954
|
}
|
|
3871
3955
|
previewDiff(diff);
|
|
3872
3956
|
const changes = countChanges(diff);
|
|
3873
|
-
console.log(
|
|
3957
|
+
console.log(chalk12.gray(` ${chalk12.green(`+${changes.added}`)} additions, ${chalk12.red(`-${changes.removed}`)} deletions
|
|
3874
3958
|
`));
|
|
3875
3959
|
const shouldApply = await confirm2({
|
|
3876
3960
|
message: "Apply these changes?",
|
|
3877
3961
|
default: true
|
|
3878
3962
|
});
|
|
3879
3963
|
if (!shouldApply) {
|
|
3880
|
-
console.log(
|
|
3964
|
+
console.log(chalk12.gray("\n\u{1F44B} Edit cancelled.\n"));
|
|
3881
3965
|
return { success: false, error: "Cancelled by user" };
|
|
3882
3966
|
}
|
|
3883
|
-
const applySpinner =
|
|
3967
|
+
const applySpinner = ora4("Applying changes...").start();
|
|
3884
3968
|
const result = await applyPatchTool(filePath, diff);
|
|
3885
3969
|
applySpinner.stop();
|
|
3886
3970
|
if (result.success) {
|
|
3887
|
-
console.log(
|
|
3971
|
+
console.log(chalk12.green(`
|
|
3888
3972
|
\u2713 Successfully edited ${filePath}
|
|
3889
3973
|
`));
|
|
3890
3974
|
logEvent({
|
|
@@ -3899,7 +3983,7 @@ Generate the unified diff to make this change.`;
|
|
|
3899
3983
|
});
|
|
3900
3984
|
return { success: true, linesChanged: changes.added + changes.removed };
|
|
3901
3985
|
} else {
|
|
3902
|
-
console.log(
|
|
3986
|
+
console.log(chalk12.red(`
|
|
3903
3987
|
\u2717 Failed to apply changes: ${result.error}
|
|
3904
3988
|
`));
|
|
3905
3989
|
return { success: false, error: result.error };
|
|
@@ -3907,7 +3991,7 @@ Generate the unified diff to make this change.`;
|
|
|
3907
3991
|
} catch (error) {
|
|
3908
3992
|
spinner.stop();
|
|
3909
3993
|
const msg = error instanceof Error ? error.message : String(error);
|
|
3910
|
-
console.log(
|
|
3994
|
+
console.log(chalk12.red(`
|
|
3911
3995
|
\u2717 Error: ${msg}
|
|
3912
3996
|
`));
|
|
3913
3997
|
return { success: false, error: msg };
|
|
@@ -4159,7 +4243,7 @@ For landing pages, portfolios, or apps that need visuals, use generateImage acti
|
|
|
4159
4243
|
async function startCodingMode() {
|
|
4160
4244
|
const activeConfig = getActiveProvider();
|
|
4161
4245
|
if (!activeConfig) {
|
|
4162
|
-
console.log(
|
|
4246
|
+
console.log(chalk13.red("\u274C No API key configured. Run: agdi"));
|
|
4163
4247
|
return;
|
|
4164
4248
|
}
|
|
4165
4249
|
const { provider, apiKey, model } = activeConfig;
|
|
@@ -4171,11 +4255,15 @@ async function startCodingMode() {
|
|
|
4171
4255
|
process.exit(0);
|
|
4172
4256
|
}
|
|
4173
4257
|
logSessionStart(env.workspaceRoot, env.trustLevel);
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4258
|
+
ui.renderBox(
|
|
4259
|
+
"SESSION INFO",
|
|
4260
|
+
`Model: ${chalk13.cyan(model)}
|
|
4261
|
+
Workspace: ${chalk13.cyan(env.workspaceRoot)}
|
|
4262
|
+
Context: ${isGitRepo() ? chalk13.green("Git Repository") : chalk13.gray("Local Folder")}`,
|
|
4263
|
+
"info"
|
|
4264
|
+
);
|
|
4265
|
+
console.log(chalk13.gray("Commands: /status, /diff, /commit, /build, /help..."));
|
|
4266
|
+
ui.printIter();
|
|
4179
4267
|
const pm = new ProjectManager();
|
|
4180
4268
|
let llm = createLLMProvider(provider, { apiKey, model });
|
|
4181
4269
|
const conversation = getConversation();
|
|
@@ -4183,12 +4271,12 @@ async function startCodingMode() {
|
|
|
4183
4271
|
while (true) {
|
|
4184
4272
|
try {
|
|
4185
4273
|
const userInput = await input5({
|
|
4186
|
-
message:
|
|
4274
|
+
message: chalk13.cyan.bold("\u{1F464} YOU \u203A")
|
|
4187
4275
|
});
|
|
4188
4276
|
const trimmed = userInput.trim().toLowerCase();
|
|
4189
4277
|
if (trimmed === "/exit" || trimmed === "exit" || trimmed === "quit") {
|
|
4190
4278
|
logSessionEnd();
|
|
4191
|
-
console.log(
|
|
4279
|
+
console.log(chalk13.gray("\n\u{1F44B} Goodbye!\n"));
|
|
4192
4280
|
break;
|
|
4193
4281
|
}
|
|
4194
4282
|
if (trimmed === "/help") {
|
|
@@ -4203,34 +4291,34 @@ async function startCodingMode() {
|
|
|
4203
4291
|
apiKey: newConfig.apiKey,
|
|
4204
4292
|
model: newConfig.model
|
|
4205
4293
|
});
|
|
4206
|
-
console.log(
|
|
4294
|
+
console.log(chalk13.gray(`Now using: ${chalk13.cyan(newConfig.model)}
|
|
4207
4295
|
`));
|
|
4208
4296
|
}
|
|
4209
4297
|
continue;
|
|
4210
4298
|
}
|
|
4211
4299
|
if (trimmed === "/chat") {
|
|
4212
|
-
console.log(
|
|
4300
|
+
console.log(chalk13.gray("\nSwitching to chat mode. Type /code to return.\n"));
|
|
4213
4301
|
await chatMode(llm);
|
|
4214
4302
|
continue;
|
|
4215
4303
|
}
|
|
4216
4304
|
if (trimmed === "/clear") {
|
|
4217
4305
|
clearConversation();
|
|
4218
4306
|
conversation.setSystemPrompt(buildContextAwarePrompt());
|
|
4219
|
-
console.log(
|
|
4307
|
+
console.log(chalk13.green("\n\u2713 Conversation cleared.\n"));
|
|
4220
4308
|
continue;
|
|
4221
4309
|
}
|
|
4222
4310
|
if (trimmed === "/history") {
|
|
4223
4311
|
const messages = conversation.getMessages();
|
|
4224
4312
|
if (messages.length === 0) {
|
|
4225
|
-
console.log(
|
|
4313
|
+
console.log(chalk13.gray("\n(no conversation history)\n"));
|
|
4226
4314
|
} else {
|
|
4227
|
-
console.log(
|
|
4228
|
-
console.log(
|
|
4315
|
+
console.log(chalk13.cyan.bold("\n\u{1F4DC} Conversation History\n"));
|
|
4316
|
+
console.log(chalk13.gray(conversation.getSummary()));
|
|
4229
4317
|
console.log("");
|
|
4230
4318
|
for (const msg of messages.slice(-6)) {
|
|
4231
|
-
const role = msg.role === "user" ?
|
|
4319
|
+
const role = msg.role === "user" ? chalk13.green("You") : chalk13.cyan("AI");
|
|
4232
4320
|
const preview = msg.content.slice(0, 80) + (msg.content.length > 80 ? "..." : "");
|
|
4233
|
-
console.log(` ${role}: ${
|
|
4321
|
+
console.log(` ${role}: ${chalk13.gray(preview)}`);
|
|
4234
4322
|
}
|
|
4235
4323
|
console.log("");
|
|
4236
4324
|
}
|
|
@@ -4253,12 +4341,12 @@ async function startCodingMode() {
|
|
|
4253
4341
|
if (filePath) {
|
|
4254
4342
|
await handleFileEdit(filePath, llm);
|
|
4255
4343
|
} else {
|
|
4256
|
-
console.log(
|
|
4344
|
+
console.log(chalk13.yellow("\nUsage: /edit <file>\n"));
|
|
4257
4345
|
}
|
|
4258
4346
|
continue;
|
|
4259
4347
|
}
|
|
4260
4348
|
if (trimmed === "/index") {
|
|
4261
|
-
const spinner2 =
|
|
4349
|
+
const spinner2 = ui.createSpinner("Indexing project...").start();
|
|
4262
4350
|
try {
|
|
4263
4351
|
const index = indexProject(process.cwd());
|
|
4264
4352
|
spinner2.succeed(`Indexed ${index.fileCount} files, ${index.chunkCount} chunks`);
|
|
@@ -4270,18 +4358,18 @@ async function startCodingMode() {
|
|
|
4270
4358
|
if (trimmed.startsWith("/search ")) {
|
|
4271
4359
|
const query = userInput.slice(8).trim();
|
|
4272
4360
|
if (!query) {
|
|
4273
|
-
console.log(
|
|
4361
|
+
console.log(chalk13.yellow("\nUsage: /search <query>\n"));
|
|
4274
4362
|
continue;
|
|
4275
4363
|
}
|
|
4276
4364
|
const results = searchCodebase(process.cwd(), query, { limit: 8 });
|
|
4277
4365
|
if (results.length === 0) {
|
|
4278
|
-
console.log(
|
|
4366
|
+
console.log(chalk13.gray("\nNo results found. Try /index first.\n"));
|
|
4279
4367
|
} else {
|
|
4280
|
-
console.log(
|
|
4368
|
+
console.log(chalk13.cyan.bold("\n\u{1F50D} Search Results\n"));
|
|
4281
4369
|
for (const r of results) {
|
|
4282
|
-
console.log(
|
|
4370
|
+
console.log(chalk13.green(` ${r.chunk.relativePath}:${r.chunk.startLine}`) + chalk13.gray(` (${r.score.toFixed(2)})`));
|
|
4283
4371
|
if (r.highlights.length > 0) {
|
|
4284
|
-
console.log(
|
|
4372
|
+
console.log(chalk13.gray(` ${r.highlights[0].slice(0, 60)}...`));
|
|
4285
4373
|
}
|
|
4286
4374
|
}
|
|
4287
4375
|
console.log("");
|
|
@@ -4290,32 +4378,32 @@ async function startCodingMode() {
|
|
|
4290
4378
|
}
|
|
4291
4379
|
if (trimmed === "/tools") {
|
|
4292
4380
|
const tools2 = listTools();
|
|
4293
|
-
console.log(
|
|
4381
|
+
console.log(chalk13.cyan.bold("\n\u{1F527} Available Tools\n"));
|
|
4294
4382
|
for (const tool of tools2) {
|
|
4295
|
-
console.log(
|
|
4296
|
-
console.log(
|
|
4383
|
+
console.log(chalk13.green(` ${tool.name}`) + chalk13.gray(` [${tool.category}]`));
|
|
4384
|
+
console.log(chalk13.gray(` ${tool.description}`));
|
|
4297
4385
|
}
|
|
4298
4386
|
console.log("");
|
|
4299
4387
|
continue;
|
|
4300
4388
|
}
|
|
4301
4389
|
if (trimmed === "/agent") {
|
|
4302
4390
|
multiAgentMode = !multiAgentMode;
|
|
4303
|
-
console.log(
|
|
4304
|
-
\u{1F916} Multi-agent mode: ${multiAgentMode ?
|
|
4391
|
+
console.log(chalk13.cyan(`
|
|
4392
|
+
\u{1F916} Multi-agent mode: ${multiAgentMode ? chalk13.green("ON") : chalk13.gray("OFF")}
|
|
4305
4393
|
`));
|
|
4306
4394
|
if (multiAgentMode) {
|
|
4307
|
-
console.log(
|
|
4395
|
+
console.log(chalk13.gray(" Planner \u2192 Coder \u2192 Reviewer pipeline enabled\n"));
|
|
4308
4396
|
}
|
|
4309
4397
|
continue;
|
|
4310
4398
|
}
|
|
4311
4399
|
if (trimmed === "/memory") {
|
|
4312
4400
|
const stats = getMemoryStats();
|
|
4313
|
-
console.log(
|
|
4314
|
-
console.log(
|
|
4315
|
-
console.log(
|
|
4316
|
-
console.log(
|
|
4401
|
+
console.log(chalk13.cyan.bold("\n\u{1F9E0} Memory Stats\n"));
|
|
4402
|
+
console.log(chalk13.gray(` Total entries: ${stats.totalEntries}`));
|
|
4403
|
+
console.log(chalk13.gray(` Projects: ${stats.projectCount}`));
|
|
4404
|
+
console.log(chalk13.gray(` Preferences: ${stats.preferenceCount}`));
|
|
4317
4405
|
for (const [type, count] of Object.entries(stats.byType)) {
|
|
4318
|
-
console.log(
|
|
4406
|
+
console.log(chalk13.gray(` ${type}: ${count}`));
|
|
4319
4407
|
}
|
|
4320
4408
|
console.log("");
|
|
4321
4409
|
continue;
|
|
@@ -4325,7 +4413,7 @@ async function startCodingMode() {
|
|
|
4325
4413
|
if (prompt) {
|
|
4326
4414
|
await buildAppWithPlan(prompt, llm);
|
|
4327
4415
|
} else {
|
|
4328
|
-
console.log(
|
|
4416
|
+
console.log(chalk13.yellow("\nUsage: /build <description>\n"));
|
|
4329
4417
|
}
|
|
4330
4418
|
continue;
|
|
4331
4419
|
}
|
|
@@ -4337,7 +4425,7 @@ async function startCodingMode() {
|
|
|
4337
4425
|
await buildAppWithPlan(userInput, llm);
|
|
4338
4426
|
continue;
|
|
4339
4427
|
}
|
|
4340
|
-
const spinner =
|
|
4428
|
+
const spinner = ui.createSpinner("Thinking...").start();
|
|
4341
4429
|
try {
|
|
4342
4430
|
conversation.addUserMessage(userInput);
|
|
4343
4431
|
let response;
|
|
@@ -4349,7 +4437,7 @@ async function startCodingMode() {
|
|
|
4349
4437
|
}
|
|
4350
4438
|
conversation.addAssistantMessage(response.text);
|
|
4351
4439
|
spinner.stop();
|
|
4352
|
-
|
|
4440
|
+
ui.printAIMessage(formatResponse(response.text));
|
|
4353
4441
|
} catch (error) {
|
|
4354
4442
|
spinner.fail("Error");
|
|
4355
4443
|
handleError(error);
|
|
@@ -4357,7 +4445,7 @@ async function startCodingMode() {
|
|
|
4357
4445
|
} catch (error) {
|
|
4358
4446
|
if (error.name === "ExitPromptError") {
|
|
4359
4447
|
logSessionEnd();
|
|
4360
|
-
console.log(
|
|
4448
|
+
console.log(chalk13.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4361
4449
|
process.exit(0);
|
|
4362
4450
|
}
|
|
4363
4451
|
throw error;
|
|
@@ -4365,13 +4453,13 @@ async function startCodingMode() {
|
|
|
4365
4453
|
}
|
|
4366
4454
|
}
|
|
4367
4455
|
async function buildAppWithPlan(prompt, llm) {
|
|
4368
|
-
const spinner =
|
|
4456
|
+
const spinner = ui.createSpinner("Generating action plan...").start();
|
|
4369
4457
|
try {
|
|
4370
4458
|
const response = await llm.generate(prompt, BUILD_SYSTEM_PROMPT);
|
|
4371
4459
|
spinner.stop();
|
|
4372
4460
|
const result = await parseAndExecutePlan(response.text);
|
|
4373
4461
|
if (!result) {
|
|
4374
|
-
console.log(
|
|
4462
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Model did not return an action plan. Showing response:\n"));
|
|
4375
4463
|
console.log(formatResponse(response.text) + "\n");
|
|
4376
4464
|
}
|
|
4377
4465
|
} catch (error) {
|
|
@@ -4383,17 +4471,17 @@ async function chatMode(llm) {
|
|
|
4383
4471
|
while (true) {
|
|
4384
4472
|
try {
|
|
4385
4473
|
const userInput = await input5({
|
|
4386
|
-
message:
|
|
4474
|
+
message: chalk13.blue("\u{1F4AC}")
|
|
4387
4475
|
});
|
|
4388
4476
|
if (userInput.toLowerCase() === "/code" || userInput.toLowerCase() === "/exit") {
|
|
4389
|
-
console.log(
|
|
4477
|
+
console.log(chalk13.gray("\nBack to Agdi dev mode.\n"));
|
|
4390
4478
|
return;
|
|
4391
4479
|
}
|
|
4392
4480
|
if (!userInput.trim()) continue;
|
|
4393
|
-
const spinner =
|
|
4481
|
+
const spinner = ui.createSpinner("Thinking...").start();
|
|
4394
4482
|
const response = await llm.generate(userInput, "You are a helpful assistant. Be friendly and concise.");
|
|
4395
4483
|
spinner.stop();
|
|
4396
|
-
|
|
4484
|
+
ui.printAIMessage(response.text);
|
|
4397
4485
|
} catch (error) {
|
|
4398
4486
|
if (error.name === "ExitPromptError") {
|
|
4399
4487
|
return;
|
|
@@ -4404,10 +4492,10 @@ async function chatMode(llm) {
|
|
|
4404
4492
|
}
|
|
4405
4493
|
async function handleGitStatus(llm) {
|
|
4406
4494
|
if (!isGitRepo()) {
|
|
4407
|
-
console.log(
|
|
4495
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Not a git repository\n"));
|
|
4408
4496
|
return;
|
|
4409
4497
|
}
|
|
4410
|
-
const spinner =
|
|
4498
|
+
const spinner = ui.createSpinner("Analyzing git status...").start();
|
|
4411
4499
|
try {
|
|
4412
4500
|
const status = getStatus();
|
|
4413
4501
|
const statusText = formatStatusForPrompt(status);
|
|
@@ -4416,10 +4504,10 @@ async function handleGitStatus(llm) {
|
|
|
4416
4504
|
${statusText}`;
|
|
4417
4505
|
const response = await llm.generate(prompt, BASE_CHAT_PROMPT);
|
|
4418
4506
|
spinner.stop();
|
|
4419
|
-
console.log(
|
|
4420
|
-
console.log(
|
|
4421
|
-
console.log(
|
|
4422
|
-
|
|
4507
|
+
console.log(chalk13.cyan.bold("\n\u{1F4CA} Git Status Analysis\n"));
|
|
4508
|
+
console.log(chalk13.gray(statusText));
|
|
4509
|
+
console.log(chalk13.cyan("\n\u2500\u2500\u2500 AI Analysis \u2500\u2500\u2500\n"));
|
|
4510
|
+
ui.printAIMessage(formatResponse(response.text));
|
|
4423
4511
|
} catch (error) {
|
|
4424
4512
|
spinner.fail("Error analyzing status");
|
|
4425
4513
|
handleError(error);
|
|
@@ -4427,16 +4515,16 @@ ${statusText}`;
|
|
|
4427
4515
|
}
|
|
4428
4516
|
async function handleGitDiff(llm) {
|
|
4429
4517
|
if (!isGitRepo()) {
|
|
4430
|
-
console.log(
|
|
4518
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Not a git repository\n"));
|
|
4431
4519
|
return;
|
|
4432
4520
|
}
|
|
4433
|
-
const spinner =
|
|
4521
|
+
const spinner = ui.createSpinner("Analyzing changes...").start();
|
|
4434
4522
|
try {
|
|
4435
4523
|
const stagedDiff = getDiff(true);
|
|
4436
4524
|
const unstagedDiff = getDiff(false);
|
|
4437
4525
|
if (stagedDiff.files.length === 0 && unstagedDiff.files.length === 0) {
|
|
4438
4526
|
spinner.stop();
|
|
4439
|
-
console.log(
|
|
4527
|
+
console.log(chalk13.gray("\n(no changes to analyze)\n"));
|
|
4440
4528
|
return;
|
|
4441
4529
|
}
|
|
4442
4530
|
let diffContext = "";
|
|
@@ -4451,8 +4539,8 @@ async function handleGitDiff(llm) {
|
|
|
4451
4539
|
${diffContext}`;
|
|
4452
4540
|
const response = await llm.generate(prompt, BASE_CHAT_PROMPT);
|
|
4453
4541
|
spinner.stop();
|
|
4454
|
-
console.log(
|
|
4455
|
-
|
|
4542
|
+
console.log(chalk13.cyan.bold("\n\u{1F50D} Diff Analysis\n"));
|
|
4543
|
+
ui.printAIMessage(formatResponse(response.text));
|
|
4456
4544
|
} catch (error) {
|
|
4457
4545
|
spinner.fail("Error analyzing diff");
|
|
4458
4546
|
handleError(error);
|
|
@@ -4460,15 +4548,15 @@ ${diffContext}`;
|
|
|
4460
4548
|
}
|
|
4461
4549
|
async function handleGitCommit(llm) {
|
|
4462
4550
|
if (!isGitRepo()) {
|
|
4463
|
-
console.log(
|
|
4551
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Not a git repository\n"));
|
|
4464
4552
|
return;
|
|
4465
4553
|
}
|
|
4466
4554
|
const status = getStatus();
|
|
4467
4555
|
if (status.staged.length === 0) {
|
|
4468
|
-
console.log(
|
|
4556
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F No staged changes. Stage some changes first with `git add`.\n"));
|
|
4469
4557
|
return;
|
|
4470
4558
|
}
|
|
4471
|
-
const spinner =
|
|
4559
|
+
const spinner = ui.createSpinner("Generating commit message...").start();
|
|
4472
4560
|
try {
|
|
4473
4561
|
const stagedDiff = getDiff(true);
|
|
4474
4562
|
const diffText = formatDiffForPrompt(stagedDiff);
|
|
@@ -4483,8 +4571,8 @@ ${diffText}`;
|
|
|
4483
4571
|
const response = await llm.generate(prompt, "You are a git commit message generator. Output ONLY the commit message, no explanation.");
|
|
4484
4572
|
spinner.stop();
|
|
4485
4573
|
const commitMessage = response.text.trim().split("\n")[0];
|
|
4486
|
-
console.log(
|
|
4487
|
-
console.log(
|
|
4574
|
+
console.log(chalk13.cyan.bold("\n\u{1F4AC} Generated Commit Message\n"));
|
|
4575
|
+
console.log(chalk13.white(` ${commitMessage}
|
|
4488
4576
|
`));
|
|
4489
4577
|
const shouldCommit = await confirm3({
|
|
4490
4578
|
message: "Commit with this message?",
|
|
@@ -4498,12 +4586,12 @@ ${diffText}`;
|
|
|
4498
4586
|
cwd: env.workspaceRoot,
|
|
4499
4587
|
stdio: "inherit"
|
|
4500
4588
|
});
|
|
4501
|
-
console.log(
|
|
4589
|
+
console.log(chalk13.green("\n\u2713 Committed successfully!\n"));
|
|
4502
4590
|
} catch (gitError) {
|
|
4503
|
-
console.log(
|
|
4591
|
+
console.log(chalk13.red("\n\u2717 Commit failed. Check git output above.\n"));
|
|
4504
4592
|
}
|
|
4505
4593
|
} else {
|
|
4506
|
-
console.log(
|
|
4594
|
+
console.log(chalk13.gray("\n\u{1F44B} Commit cancelled.\n"));
|
|
4507
4595
|
}
|
|
4508
4596
|
} catch (error) {
|
|
4509
4597
|
spinner.fail("Error generating commit");
|
|
@@ -4512,81 +4600,82 @@ ${diffText}`;
|
|
|
4512
4600
|
}
|
|
4513
4601
|
function formatResponse(text) {
|
|
4514
4602
|
return text.replace(/```(\w+)?\n([\s\S]*?)```/g, (_, lang, code) => {
|
|
4515
|
-
const header = lang ?
|
|
4603
|
+
const header = lang ? chalk13.gray(`\u2500\u2500 ${lang} \u2500\u2500`) : chalk13.gray("\u2500\u2500 code \u2500\u2500");
|
|
4516
4604
|
return `
|
|
4517
4605
|
${header}
|
|
4518
|
-
${
|
|
4519
|
-
${
|
|
4606
|
+
${chalk13.white(code.trim())}
|
|
4607
|
+
${chalk13.gray("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}
|
|
4520
4608
|
`;
|
|
4521
4609
|
});
|
|
4522
4610
|
}
|
|
4523
4611
|
function showHelp() {
|
|
4524
|
-
console.log(
|
|
4525
|
-
console.log(
|
|
4526
|
-
console.log(
|
|
4527
|
-
console.log(
|
|
4528
|
-
console.log(
|
|
4612
|
+
console.log(chalk13.cyan.bold("\n\u{1F4D6} Commands\n"));
|
|
4613
|
+
console.log(chalk13.cyan(" Git Commands:"));
|
|
4614
|
+
console.log(chalk13.gray(" /status ") + "AI analysis of git status");
|
|
4615
|
+
console.log(chalk13.gray(" /diff ") + "AI explanation of current changes");
|
|
4616
|
+
console.log(chalk13.gray(" /commit ") + "Generate and run git commit");
|
|
4529
4617
|
console.log("");
|
|
4530
|
-
console.log(
|
|
4531
|
-
console.log(
|
|
4532
|
-
console.log(
|
|
4618
|
+
console.log(chalk13.cyan(" Build Commands:"));
|
|
4619
|
+
console.log(chalk13.gray(" /build ") + "Generate and execute an application");
|
|
4620
|
+
console.log(chalk13.gray(" /edit ") + "AI-powered surgical file editing");
|
|
4533
4621
|
console.log("");
|
|
4534
|
-
console.log(
|
|
4535
|
-
console.log(
|
|
4536
|
-
console.log(
|
|
4622
|
+
console.log(chalk13.cyan(" RAG Commands:"));
|
|
4623
|
+
console.log(chalk13.gray(" /index ") + "Index current project for search");
|
|
4624
|
+
console.log(chalk13.gray(" /search ") + "Semantic code search");
|
|
4537
4625
|
console.log("");
|
|
4538
|
-
console.log(
|
|
4539
|
-
console.log(
|
|
4540
|
-
console.log(
|
|
4541
|
-
console.log(
|
|
4626
|
+
console.log(chalk13.cyan(" Advanced:"));
|
|
4627
|
+
console.log(chalk13.gray(" /tools ") + "List available MCP tools");
|
|
4628
|
+
console.log(chalk13.gray(" /agent ") + "Toggle multi-agent mode");
|
|
4629
|
+
console.log(chalk13.gray(" /memory ") + "Show memory stats");
|
|
4542
4630
|
console.log("");
|
|
4543
|
-
console.log(
|
|
4544
|
-
console.log(
|
|
4545
|
-
console.log(
|
|
4631
|
+
console.log(chalk13.cyan(" Conversation:"));
|
|
4632
|
+
console.log(chalk13.gray(" /clear ") + "Clear conversation history");
|
|
4633
|
+
console.log(chalk13.gray(" /history ") + "Show recent conversation");
|
|
4546
4634
|
console.log("");
|
|
4547
|
-
console.log(
|
|
4548
|
-
console.log(
|
|
4549
|
-
console.log(
|
|
4550
|
-
console.log(
|
|
4551
|
-
console.log(
|
|
4552
|
-
console.log(
|
|
4635
|
+
console.log(chalk13.cyan(" General:"));
|
|
4636
|
+
console.log(chalk13.gray(" /model ") + "Change AI model");
|
|
4637
|
+
console.log(chalk13.gray(" /chat ") + "Switch to chat mode");
|
|
4638
|
+
console.log(chalk13.gray(" /help ") + "Show this help");
|
|
4639
|
+
console.log(chalk13.gray(" /exit ") + "Exit Agdi");
|
|
4640
|
+
console.log(chalk13.gray("\n Or just type your coding question!\n"));
|
|
4553
4641
|
}
|
|
4554
4642
|
function handleError(error) {
|
|
4555
4643
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4556
4644
|
if (msg.includes("429") || msg.includes("quota")) {
|
|
4557
|
-
console.log(
|
|
4645
|
+
console.log(chalk13.yellow("\n\u26A0\uFE0F Quota exceeded. Run /model to switch.\n"));
|
|
4558
4646
|
} else if (msg.includes("401") || msg.includes("403")) {
|
|
4559
|
-
console.log(
|
|
4647
|
+
console.log(chalk13.red("\n\u{1F511} Invalid API key. Run: agdi auth\n"));
|
|
4560
4648
|
} else {
|
|
4561
|
-
console.log(
|
|
4649
|
+
console.log(chalk13.red("\n" + msg + "\n"));
|
|
4562
4650
|
}
|
|
4563
4651
|
}
|
|
4564
4652
|
|
|
4565
4653
|
// src/index.ts
|
|
4566
4654
|
var BANNER = `
|
|
4567
|
-
${
|
|
4568
|
-
${
|
|
4569
|
-
${
|
|
4570
|
-
${
|
|
4571
|
-
${
|
|
4572
|
-
${
|
|
4655
|
+
${chalk14.cyan(` ___ __ _ `)}
|
|
4656
|
+
${chalk14.cyan(` / | ____ _____/ /(_) `)}
|
|
4657
|
+
${chalk14.cyan(` / /| | / __ \`/ __ // / `)}
|
|
4658
|
+
${chalk14.cyan(` / ___ |/ /_/ / /_/ // / `)}
|
|
4659
|
+
${chalk14.cyan(`/_/ |_|\\_, /\\__,_//_/ `)}
|
|
4660
|
+
${chalk14.cyan(` /____/ `)}
|
|
4573
4661
|
`;
|
|
4574
4662
|
var program = new Command();
|
|
4575
|
-
program.name("agdi").description(
|
|
4663
|
+
program.name("agdi").description(chalk14.cyan("\u{1F680} AI-powered coding assistant")).version("2.6.0").configureHelp({
|
|
4576
4664
|
// Show banner only when help is requested
|
|
4577
4665
|
formatHelp: (cmd, helper) => {
|
|
4578
|
-
return BANNER + "\n" +
|
|
4666
|
+
return BANNER + "\n" + chalk14.gray(" The Open Source AI Architect") + "\n" + chalk14.gray(" \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\n") + "\n" + helper.formatHelp(cmd, helper);
|
|
4579
4667
|
}
|
|
4580
4668
|
});
|
|
4581
4669
|
program.action(async () => {
|
|
4582
4670
|
try {
|
|
4671
|
+
await ui.renderBanner();
|
|
4583
4672
|
if (needsOnboarding()) {
|
|
4584
4673
|
await runOnboarding();
|
|
4585
4674
|
}
|
|
4586
4675
|
await startCodingMode();
|
|
4587
4676
|
} catch (error) {
|
|
4588
4677
|
if (error.name === "ExitPromptError") {
|
|
4589
|
-
console.log(
|
|
4678
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4590
4679
|
process.exit(0);
|
|
4591
4680
|
}
|
|
4592
4681
|
throw error;
|
|
@@ -4601,7 +4690,7 @@ program.command("auth").description("Configure API keys").option("--status", "Sh
|
|
|
4601
4690
|
}
|
|
4602
4691
|
} catch (error) {
|
|
4603
4692
|
if (error.name === "ExitPromptError") {
|
|
4604
|
-
console.log(
|
|
4693
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4605
4694
|
process.exit(0);
|
|
4606
4695
|
}
|
|
4607
4696
|
throw error;
|
|
@@ -4612,7 +4701,7 @@ program.command("model").alias("models").description("Change AI model").action(a
|
|
|
4612
4701
|
await selectModel();
|
|
4613
4702
|
} catch (error) {
|
|
4614
4703
|
if (error.name === "ExitPromptError") {
|
|
4615
|
-
console.log(
|
|
4704
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4616
4705
|
process.exit(0);
|
|
4617
4706
|
}
|
|
4618
4707
|
throw error;
|
|
@@ -4626,7 +4715,7 @@ program.command("chat").description("Start a chat session").action(async () => {
|
|
|
4626
4715
|
await startChat();
|
|
4627
4716
|
} catch (error) {
|
|
4628
4717
|
if (error.name === "ExitPromptError") {
|
|
4629
|
-
console.log(
|
|
4718
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4630
4719
|
process.exit(0);
|
|
4631
4720
|
}
|
|
4632
4721
|
throw error;
|
|
@@ -4637,7 +4726,7 @@ program.command("run [directory]").description("Run a generated project").action
|
|
|
4637
4726
|
await runProject(directory);
|
|
4638
4727
|
} catch (error) {
|
|
4639
4728
|
if (error.name === "ExitPromptError") {
|
|
4640
|
-
console.log(
|
|
4729
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4641
4730
|
process.exit(0);
|
|
4642
4731
|
}
|
|
4643
4732
|
throw error;
|
|
@@ -4650,7 +4739,7 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4650
4739
|
}
|
|
4651
4740
|
const activeConfig = getActiveProvider();
|
|
4652
4741
|
if (!activeConfig) {
|
|
4653
|
-
console.log(
|
|
4742
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4654
4743
|
return;
|
|
4655
4744
|
}
|
|
4656
4745
|
const spinner = ora5("Generating application...").start();
|
|
@@ -4662,30 +4751,30 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4662
4751
|
const pm = new ProjectManager();
|
|
4663
4752
|
pm.create(options.output.replace("./", ""), prompt);
|
|
4664
4753
|
const { plan, files } = await generateApp(prompt, llm, (step, file) => {
|
|
4665
|
-
spinner.text = file ? `${step} ${
|
|
4754
|
+
spinner.text = file ? `${step} ${chalk14.gray(file)}` : step;
|
|
4666
4755
|
});
|
|
4667
4756
|
pm.updateFiles(files);
|
|
4668
4757
|
pm.updateDependencies(plan.dependencies);
|
|
4669
4758
|
await writeProject(pm.get(), options.output);
|
|
4670
|
-
spinner.succeed(
|
|
4671
|
-
console.log(
|
|
4672
|
-
\u{1F4C1} Created ${files.length} files in ${
|
|
4673
|
-
console.log(
|
|
4759
|
+
spinner.succeed(chalk14.green("App generated!"));
|
|
4760
|
+
console.log(chalk14.gray(`
|
|
4761
|
+
\u{1F4C1} Created ${files.length} files in ${chalk14.cyan(options.output)}`));
|
|
4762
|
+
console.log(chalk14.gray("\nNext: cd " + options.output + " && npm install && npm run dev\n"));
|
|
4674
4763
|
} catch (error) {
|
|
4675
4764
|
spinner.fail("Generation failed");
|
|
4676
4765
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4677
4766
|
if (msg.includes("429") || msg.includes("quota")) {
|
|
4678
|
-
console.log(
|
|
4767
|
+
console.log(chalk14.yellow("\n\u26A0\uFE0F Quota exceeded. Run: agdi model\n"));
|
|
4679
4768
|
} else if (msg.includes("401") || msg.includes("403")) {
|
|
4680
|
-
console.log(
|
|
4769
|
+
console.log(chalk14.red("\n\u{1F511} Invalid API key. Run: agdi auth\n"));
|
|
4681
4770
|
} else {
|
|
4682
|
-
console.error(
|
|
4771
|
+
console.error(chalk14.red("\n" + msg + "\n"));
|
|
4683
4772
|
}
|
|
4684
4773
|
process.exit(1);
|
|
4685
4774
|
}
|
|
4686
4775
|
} catch (error) {
|
|
4687
4776
|
if (error.name === "ExitPromptError") {
|
|
4688
|
-
console.log(
|
|
4777
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4689
4778
|
process.exit(0);
|
|
4690
4779
|
}
|
|
4691
4780
|
throw error;
|
|
@@ -4694,11 +4783,11 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4694
4783
|
program.command("config").description("Show configuration").action(async () => {
|
|
4695
4784
|
const config = loadConfig();
|
|
4696
4785
|
const active = getActiveProvider();
|
|
4697
|
-
console.log(
|
|
4698
|
-
console.log(
|
|
4699
|
-
console.log(
|
|
4700
|
-
console.log(
|
|
4701
|
-
console.log(
|
|
4786
|
+
console.log(chalk14.cyan.bold("\n\u2699\uFE0F Configuration\n"));
|
|
4787
|
+
console.log(chalk14.gray(" Provider: ") + chalk14.cyan(config.defaultProvider || "not set"));
|
|
4788
|
+
console.log(chalk14.gray(" Model: ") + chalk14.cyan(config.defaultModel || "not set"));
|
|
4789
|
+
console.log(chalk14.gray(" Config: ") + chalk14.gray("~/.agdi/config.json"));
|
|
4790
|
+
console.log(chalk14.cyan.bold("\n\u{1F510} API Keys\n"));
|
|
4702
4791
|
const keys = [
|
|
4703
4792
|
["Gemini", config.geminiApiKey],
|
|
4704
4793
|
["OpenRouter", config.openrouterApiKey],
|
|
@@ -4707,7 +4796,7 @@ program.command("config").description("Show configuration").action(async () => {
|
|
|
4707
4796
|
["DeepSeek", config.deepseekApiKey]
|
|
4708
4797
|
];
|
|
4709
4798
|
for (const [name, key] of keys) {
|
|
4710
|
-
const status = key ?
|
|
4799
|
+
const status = key ? chalk14.green("\u2713") : chalk14.gray("\u2717");
|
|
4711
4800
|
console.log(` ${status} ${name}`);
|
|
4712
4801
|
}
|
|
4713
4802
|
console.log("");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agdi",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "AI-powered app generator - build full-stack apps from natural language in your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,19 +46,24 @@
|
|
|
46
46
|
"node": ">=18.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
+
"@types/fs-extra": "^11.0.0",
|
|
50
|
+
"@types/node": "^20.0.0",
|
|
49
51
|
"tsup": "^8.0.0",
|
|
50
52
|
"tsx": "^4.7.0",
|
|
51
53
|
"typescript": "^5.4.0",
|
|
52
|
-
"@types/fs-extra": "^11.0.0",
|
|
53
|
-
"@types/node": "^20.0.0",
|
|
54
54
|
"vitest": "^3.0.0"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"@google/genai": "^1.0.0",
|
|
58
58
|
"@inquirer/prompts": "^5.0.0",
|
|
59
|
+
"@types/figlet": "^1.7.0",
|
|
60
|
+
"@types/gradient-string": "^1.1.6",
|
|
61
|
+
"boxen": "^8.0.1",
|
|
59
62
|
"chalk": "^5.3.0",
|
|
60
63
|
"commander": "^12.0.0",
|
|
64
|
+
"figlet": "^1.9.4",
|
|
61
65
|
"fs-extra": "^11.2.0",
|
|
66
|
+
"gradient-string": "^3.0.0",
|
|
62
67
|
"jszip": "^3.10.0",
|
|
63
68
|
"ora": "^8.0.0"
|
|
64
69
|
}
|