agdi 3.2.0 → 3.3.2
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 +1 -0
- package/dist/chunk-AEWEBMJY.js +14 -0
- package/dist/event-bus-EDC4P3T5.js +8 -0
- package/dist/index.js +416 -316
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
# 🦸 AGDI
|
|
7
7
|
### The Autonomous AI Software Squad in Your Terminal
|
|
8
|
+
#### v3.3.0: New Mission Control TUI
|
|
8
9
|
|
|
9
10
|
[](https://www.npmjs.com/package/agdi)
|
|
10
11
|
[](https://github.com/anassagd432/Agdi-dev)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// src/core/event-bus.ts
|
|
2
|
+
import { EventEmitter } from "events";
|
|
3
|
+
var agentEventBus = new EventEmitter();
|
|
4
|
+
function emitAgentEvent(event) {
|
|
5
|
+
agentEventBus.emit("agent_event", {
|
|
6
|
+
...event,
|
|
7
|
+
timestamp: Date.now()
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
agentEventBus,
|
|
13
|
+
emitAgentEvent
|
|
14
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
agentEventBus,
|
|
4
|
+
emitAgentEvent
|
|
5
|
+
} from "./chunk-AEWEBMJY.js";
|
|
2
6
|
import {
|
|
3
7
|
loadConfig,
|
|
4
8
|
saveConfig
|
|
@@ -6,7 +10,7 @@ import {
|
|
|
6
10
|
|
|
7
11
|
// src/index.ts
|
|
8
12
|
import { Command } from "commander";
|
|
9
|
-
import
|
|
13
|
+
import chalk14 from "chalk";
|
|
10
14
|
import ora6 from "ora";
|
|
11
15
|
|
|
12
16
|
// src/core/llm/index.ts
|
|
@@ -449,8 +453,8 @@ async function smartConfirm(message, defaultValue = false) {
|
|
|
449
453
|
console.warn(chalk.yellow("\u26A0\uFE0F Non-interactive session detected. Use --yes to approve actions."));
|
|
450
454
|
return false;
|
|
451
455
|
}
|
|
452
|
-
const { confirm
|
|
453
|
-
return
|
|
456
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
457
|
+
return confirm({ message, default: defaultValue });
|
|
454
458
|
}
|
|
455
459
|
async function smartSelect(message, choices, defaultValue) {
|
|
456
460
|
if (!process.stdout.isTTY || flags.headless) {
|
|
@@ -460,8 +464,8 @@ async function smartSelect(message, choices, defaultValue) {
|
|
|
460
464
|
}
|
|
461
465
|
return result || null;
|
|
462
466
|
}
|
|
463
|
-
const { select:
|
|
464
|
-
return
|
|
467
|
+
const { select: select3 } = await import("@inquirer/prompts");
|
|
468
|
+
return select3({ message, choices });
|
|
465
469
|
}
|
|
466
470
|
var ui = {
|
|
467
471
|
renderBanner,
|
|
@@ -1782,8 +1786,8 @@ async function runOnboarding() {
|
|
|
1782
1786
|
console.log(chalk7.gray("We collect anonymous error logs (like a ") + chalk7.yellow("'Check Engine'") + chalk7.gray(" light)"));
|
|
1783
1787
|
console.log(chalk7.gray("to fix bugs faster. We ") + chalk7.green.bold("never") + chalk7.gray(" see your code or keys.\n"));
|
|
1784
1788
|
console.log(chalk7.dim("Verify anytime: agdi config telemetry --dry-run\n"));
|
|
1785
|
-
const { confirm
|
|
1786
|
-
const enableTelemetry = await
|
|
1789
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
1790
|
+
const enableTelemetry = await confirm({
|
|
1787
1791
|
message: "Enable crash reporting? (helps us fix bugs)",
|
|
1788
1792
|
default: false
|
|
1789
1793
|
});
|
|
@@ -2072,6 +2076,13 @@ var BaseAgent = class {
|
|
|
2072
2076
|
* Log a message (if verbose)
|
|
2073
2077
|
*/
|
|
2074
2078
|
log(message, type = "info") {
|
|
2079
|
+
emitAgentEvent({
|
|
2080
|
+
type: "log",
|
|
2081
|
+
agentName: this.name,
|
|
2082
|
+
role: this.role,
|
|
2083
|
+
message,
|
|
2084
|
+
metadata: { type }
|
|
2085
|
+
});
|
|
2075
2086
|
if (!this.verbose) return;
|
|
2076
2087
|
const prefix = `[${this.name}]`;
|
|
2077
2088
|
switch (type) {
|
|
@@ -2093,7 +2104,20 @@ var BaseAgent = class {
|
|
|
2093
2104
|
*/
|
|
2094
2105
|
async think(prompt) {
|
|
2095
2106
|
this.log("Thinking...", "info");
|
|
2107
|
+
emitAgentEvent({
|
|
2108
|
+
type: "thought",
|
|
2109
|
+
agentName: this.name,
|
|
2110
|
+
role: this.role,
|
|
2111
|
+
message: `Analyzing task...`
|
|
2112
|
+
});
|
|
2096
2113
|
const response = await this.llm.generate(prompt, this.getSystemPrompt());
|
|
2114
|
+
const summary = response.text.split("\n")[0].substring(0, 80) + "...";
|
|
2115
|
+
emitAgentEvent({
|
|
2116
|
+
type: "thought",
|
|
2117
|
+
agentName: this.name,
|
|
2118
|
+
role: this.role,
|
|
2119
|
+
message: `Generated response: ${summary}`
|
|
2120
|
+
});
|
|
2097
2121
|
this.collectSourcesFromText(response.text);
|
|
2098
2122
|
return response.text;
|
|
2099
2123
|
}
|
|
@@ -3568,6 +3592,14 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3568
3592
|
*/
|
|
3569
3593
|
async executeTask(task) {
|
|
3570
3594
|
this.log(`[${task.assignee}] ${task.title}`, "task");
|
|
3595
|
+
const { emitAgentEvent: emitAgentEvent2 } = await import("./event-bus-EDC4P3T5.js");
|
|
3596
|
+
emitAgentEvent2({
|
|
3597
|
+
type: "handoff",
|
|
3598
|
+
agentName: task.assignee,
|
|
3599
|
+
// e.g. "frontend"
|
|
3600
|
+
role: task.assignee,
|
|
3601
|
+
message: `Taking control for task: ${task.title}`
|
|
3602
|
+
});
|
|
3571
3603
|
await this.appendTrace("task_start", {
|
|
3572
3604
|
id: task.id,
|
|
3573
3605
|
title: task.title,
|
|
@@ -4075,225 +4107,19 @@ ${msg}
|
|
|
4075
4107
|
}
|
|
4076
4108
|
}
|
|
4077
4109
|
|
|
4078
|
-
// src/commands/wizard.ts
|
|
4079
|
-
import { input as input5, select as select3, confirm, password as password3 } from "@inquirer/prompts";
|
|
4080
|
-
import chalk13 from "chalk";
|
|
4081
|
-
import path6 from "path";
|
|
4082
|
-
import os from "os";
|
|
4083
|
-
import fs6 from "fs";
|
|
4084
|
-
async function runWizard() {
|
|
4085
|
-
await checkSafety();
|
|
4086
|
-
if (needsOnboarding()) {
|
|
4087
|
-
await runOnboarding();
|
|
4088
|
-
}
|
|
4089
|
-
await setupOptionalTools();
|
|
4090
|
-
const wantsSaas = await confirm({
|
|
4091
|
-
message: "Enable SaaS Blueprint mode? (Next.js + Prisma + Postgres + Stripe)",
|
|
4092
|
-
default: true
|
|
4093
|
-
});
|
|
4094
|
-
if (wantsSaas) {
|
|
4095
|
-
ui.setFlags({ saas: true });
|
|
4096
|
-
}
|
|
4097
|
-
console.log(chalk13.cyan.bold("\n\u{1F3AF} Mission Control"));
|
|
4098
|
-
console.log(chalk13.gray("Describe your app in detail. The Agdi Squad will handle the rest."));
|
|
4099
|
-
let prompt = await input5({
|
|
4100
|
-
message: "What are we building today?",
|
|
4101
|
-
validate: (value) => value.length > 5 ? true : "Please provide more detail (min 5 chars)"
|
|
4102
|
-
});
|
|
4103
|
-
if (wantsSaas) {
|
|
4104
|
-
prompt = `${prompt}
|
|
4105
|
-
|
|
4106
|
-
Constraints: Build a production SaaS using Next.js App Router, Prisma, Postgres, and Stripe. Include auth, billing, multi-tenant orgs, and a dashboard.`;
|
|
4107
|
-
}
|
|
4108
|
-
const activeConfig = getActiveProvider();
|
|
4109
|
-
if (!activeConfig) {
|
|
4110
|
-
console.log(chalk13.red("\u274C No API key configured. Run: agdi auth"));
|
|
4111
|
-
return;
|
|
4112
|
-
}
|
|
4113
|
-
const llm = createLLMProvider(activeConfig.provider, {
|
|
4114
|
-
apiKey: activeConfig.apiKey,
|
|
4115
|
-
model: activeConfig.model
|
|
4116
|
-
});
|
|
4117
|
-
console.log(chalk13.cyan("\n\u{1F914} Analyzing requirements..."));
|
|
4118
|
-
try {
|
|
4119
|
-
const analysis = await llm.generate(prompt, `
|
|
4120
|
-
You are a Senior Product Manager. Analyze this app idea.
|
|
4121
|
-
If it is vague (e.g., "make a CRM"), generate 3 specific questions to clarify scope, tech stack, and features.
|
|
4122
|
-
If it is detailed enough, return "DETAILED".
|
|
4123
|
-
|
|
4124
|
-
Format:
|
|
4125
|
-
Questions:
|
|
4126
|
-
1. [Question 1]
|
|
4127
|
-
2. [Question 2]
|
|
4128
|
-
3. [Question 3]
|
|
4129
|
-
`);
|
|
4130
|
-
if (!analysis.text.includes("DETAILED")) {
|
|
4131
|
-
console.log(chalk13.yellow("\n\u{1F4A1} I need a few more details to build exactly what you want:"));
|
|
4132
|
-
const questions = analysis.text.split("\n").filter((line) => line.match(/^\d+\./));
|
|
4133
|
-
const answers = [];
|
|
4134
|
-
for (const q of questions.slice(0, 3)) {
|
|
4135
|
-
const answer = await input5({ message: q.replace(/^\d+\.\s*/, "") });
|
|
4136
|
-
answers.push({ q, a: answer });
|
|
4137
|
-
}
|
|
4138
|
-
console.log(chalk13.cyan("\n\u{1F504} Synthesizing Master Plan..."));
|
|
4139
|
-
const synthesis = await llm.generate(
|
|
4140
|
-
`Original Request: ${prompt}
|
|
4141
|
-
|
|
4142
|
-
Clarifications:
|
|
4143
|
-
${answers.map((x) => `Q: ${x.q}
|
|
4144
|
-
A: ${x.a}`).join("\n")}
|
|
4145
|
-
|
|
4146
|
-
Rewrite the original request into a comprehensive technical specification for a developer squad.`,
|
|
4147
|
-
"You are a Technical Architect."
|
|
4148
|
-
);
|
|
4149
|
-
prompt = synthesis.text;
|
|
4150
|
-
console.log(chalk13.gray("\nUpdated Spec: " + prompt.substring(0, 100) + "...\n"));
|
|
4151
|
-
}
|
|
4152
|
-
} catch (err) {
|
|
4153
|
-
console.log(chalk13.gray("Skipping analysis (API unreachable), proceeding with raw prompt."));
|
|
4154
|
-
}
|
|
4155
|
-
console.log(chalk13.cyan("\n\u{1F680} Assembling the Squad..."));
|
|
4156
|
-
console.log(chalk13.gray("Frontend, Backend, QA, and DevOps agents are coming online.\n"));
|
|
4157
|
-
const config = loadConfig();
|
|
4158
|
-
const canDeploy = !!(config.vercelToken || config.netlifyToken || config.railwayToken);
|
|
4159
|
-
await runSquadCommand(prompt, llm, {
|
|
4160
|
-
deploy: canDeploy,
|
|
4161
|
-
// Auto-deploy if configured
|
|
4162
|
-
output: "./",
|
|
4163
|
-
// Current directory (safe because we checked safety earlier)
|
|
4164
|
-
verbose: true
|
|
4165
|
-
});
|
|
4166
|
-
if (ui.flags.saas) {
|
|
4167
|
-
console.log(chalk13.cyan("\nSaaS Quick Start:"));
|
|
4168
|
-
console.log(chalk13.gray(" 1) npm install"));
|
|
4169
|
-
console.log(chalk13.gray(" 2) cp .env.example .env"));
|
|
4170
|
-
console.log(chalk13.gray(" 3) npx prisma generate"));
|
|
4171
|
-
console.log(chalk13.gray(" 4) npx prisma db push"));
|
|
4172
|
-
console.log(chalk13.gray(" 5) npm run dev\n"));
|
|
4173
|
-
}
|
|
4174
|
-
}
|
|
4175
|
-
async function checkSafety() {
|
|
4176
|
-
const cwd = process.cwd();
|
|
4177
|
-
const home = os.homedir();
|
|
4178
|
-
const root = path6.parse(cwd).root;
|
|
4179
|
-
const isUnsafe = cwd === home || cwd === root;
|
|
4180
|
-
if (isUnsafe) {
|
|
4181
|
-
console.log(chalk13.yellow.bold("\n\u26A0\uFE0F Safety Warning"));
|
|
4182
|
-
console.log(chalk13.gray(`You are running Agdi in ${chalk13.cyan(cwd)}.`));
|
|
4183
|
-
console.log(chalk13.gray("Agdi writes files and runs commands. It needs its own space.\n"));
|
|
4184
|
-
const action = await select3({
|
|
4185
|
-
message: "What would you like to do?",
|
|
4186
|
-
choices: [
|
|
4187
|
-
{ name: "\u{1F4C2} Create a new project folder (Recommended)", value: "create" },
|
|
4188
|
-
{ name: "\u{1F525} Run here anyway (Dangerous)", value: "unsafe" },
|
|
4189
|
-
{ name: "\u274C Cancel", value: "cancel" }
|
|
4190
|
-
]
|
|
4191
|
-
});
|
|
4192
|
-
if (action === "cancel") {
|
|
4193
|
-
ui.safeExit(0);
|
|
4194
|
-
}
|
|
4195
|
-
if (action === "create") {
|
|
4196
|
-
const folderName = await input5({
|
|
4197
|
-
message: "Project name:",
|
|
4198
|
-
default: "my-agdi-app",
|
|
4199
|
-
validate: (v) => /^[a-z0-9-_]+$/i.test(v) ? true : "Invalid folder name"
|
|
4200
|
-
});
|
|
4201
|
-
const newPath = path6.join(cwd, folderName);
|
|
4202
|
-
if (!fs6.existsSync(newPath)) {
|
|
4203
|
-
fs6.mkdirSync(newPath);
|
|
4204
|
-
}
|
|
4205
|
-
process.chdir(newPath);
|
|
4206
|
-
console.log(chalk13.green(`
|
|
4207
|
-
\u{1F4C2} Switched to: ${chalk13.cyan(newPath)}
|
|
4208
|
-
`));
|
|
4209
|
-
}
|
|
4210
|
-
}
|
|
4211
|
-
}
|
|
4212
|
-
async function setupOptionalTools() {
|
|
4213
|
-
const config = loadConfig();
|
|
4214
|
-
let configChanged = false;
|
|
4215
|
-
if (!config.searchApiKey) {
|
|
4216
|
-
console.log(chalk13.white.bold("\n\u{1F310} Web Access (Optional)\n"));
|
|
4217
|
-
console.log(chalk13.gray("Giving Agdi web access allows it to find up-to-date docs and fix tricky bugs."));
|
|
4218
|
-
const wantsSearch = await confirm({
|
|
4219
|
-
message: "Enable web search capabilities?",
|
|
4220
|
-
default: true
|
|
4221
|
-
});
|
|
4222
|
-
if (wantsSearch) {
|
|
4223
|
-
const provider = await select3({
|
|
4224
|
-
message: "Select Search Provider:",
|
|
4225
|
-
choices: [
|
|
4226
|
-
{ name: "Brave Search (Recommended)", value: "brave" },
|
|
4227
|
-
{ name: "Tavily", value: "tavily" }
|
|
4228
|
-
]
|
|
4229
|
-
});
|
|
4230
|
-
const keyUrl = provider === "brave" ? "https://brave.com/search/api/" : "https://tavily.com/";
|
|
4231
|
-
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4232
|
-
`));
|
|
4233
|
-
const apiKey = await password3({
|
|
4234
|
-
message: `Enter your ${provider} API key:`,
|
|
4235
|
-
mask: "*"
|
|
4236
|
-
});
|
|
4237
|
-
if (apiKey) {
|
|
4238
|
-
config.searchApiKey = apiKey;
|
|
4239
|
-
config.searchProvider = provider;
|
|
4240
|
-
config.searchEnabled = true;
|
|
4241
|
-
configChanged = true;
|
|
4242
|
-
console.log(chalk13.green("\u2705 Web search enabled!"));
|
|
4243
|
-
}
|
|
4244
|
-
}
|
|
4245
|
-
}
|
|
4246
|
-
if (!config.vercelToken && !config.netlifyToken && !config.railwayToken) {
|
|
4247
|
-
console.log(chalk13.white.bold("\n\u{1F680} Deployment (Optional)\n"));
|
|
4248
|
-
console.log(chalk13.gray("Agdi can automatically deploy your app to the cloud when finished."));
|
|
4249
|
-
const wantsDeploy = await confirm({
|
|
4250
|
-
message: "Enable auto-deployment?",
|
|
4251
|
-
default: true
|
|
4252
|
-
});
|
|
4253
|
-
if (wantsDeploy) {
|
|
4254
|
-
const provider = await select3({
|
|
4255
|
-
message: "Select Deployment Target:",
|
|
4256
|
-
choices: [
|
|
4257
|
-
{ name: "Vercel", value: "vercel" },
|
|
4258
|
-
{ name: "Railway", value: "railway" },
|
|
4259
|
-
{ name: "Netlify", value: "netlify" }
|
|
4260
|
-
]
|
|
4261
|
-
});
|
|
4262
|
-
const keyUrl = provider === "vercel" ? "https://vercel.com/account/tokens" : provider === "railway" ? "https://railway.app/account/tokens" : "https://app.netlify.com/user/applications#personal-access-tokens";
|
|
4263
|
-
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4264
|
-
`));
|
|
4265
|
-
const apiKey = await password3({
|
|
4266
|
-
message: `Enter your ${provider} API token:`,
|
|
4267
|
-
mask: "*"
|
|
4268
|
-
});
|
|
4269
|
-
if (apiKey) {
|
|
4270
|
-
if (provider === "vercel") config.vercelToken = apiKey;
|
|
4271
|
-
if (provider === "netlify") config.netlifyToken = apiKey;
|
|
4272
|
-
if (provider === "railway") config.railwayToken = apiKey;
|
|
4273
|
-
config.deploymentProvider = provider;
|
|
4274
|
-
configChanged = true;
|
|
4275
|
-
console.log(chalk13.green("\u2705 Auto-deployment enabled!"));
|
|
4276
|
-
}
|
|
4277
|
-
}
|
|
4278
|
-
}
|
|
4279
|
-
if (configChanged) {
|
|
4280
|
-
saveConfig(config);
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
|
|
4284
4110
|
// src/commands/replay.ts
|
|
4285
|
-
import
|
|
4286
|
-
import * as
|
|
4287
|
-
import * as
|
|
4111
|
+
import chalk13 from "chalk";
|
|
4112
|
+
import * as fs6 from "fs/promises";
|
|
4113
|
+
import * as path6 from "path";
|
|
4288
4114
|
async function runReplayCommand(runId, llm, options = {}) {
|
|
4289
4115
|
const workspaceRoot = options.workspace || process.cwd();
|
|
4290
|
-
const runConfigPath =
|
|
4291
|
-
const outputsDir =
|
|
4116
|
+
const runConfigPath = path6.join(workspaceRoot, "runs", runId, "run.json");
|
|
4117
|
+
const outputsDir = path6.join(workspaceRoot, "runs", runId, "outputs");
|
|
4292
4118
|
try {
|
|
4293
|
-
const raw = await
|
|
4119
|
+
const raw = await fs6.readFile(runConfigPath, "utf-8");
|
|
4294
4120
|
const runConfig = JSON.parse(raw);
|
|
4295
4121
|
if (!runConfig.prompt) {
|
|
4296
|
-
console.log(
|
|
4122
|
+
console.log(chalk13.red("\u274C Invalid run.json (missing prompt)"));
|
|
4297
4123
|
return null;
|
|
4298
4124
|
}
|
|
4299
4125
|
const config = {
|
|
@@ -4302,31 +4128,31 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4302
4128
|
verbose: options.verbose ?? runConfig.config?.verbose ?? true,
|
|
4303
4129
|
autoDeploy: options.deploy ?? runConfig.config?.autoDeploy ?? false
|
|
4304
4130
|
};
|
|
4305
|
-
console.log(
|
|
4131
|
+
console.log(chalk13.cyan(`
|
|
4306
4132
|
\u{1F501} Replaying run ${runId}`));
|
|
4307
4133
|
if (options.exact !== false) {
|
|
4308
4134
|
try {
|
|
4309
|
-
const entries = await
|
|
4135
|
+
const entries = await fs6.readdir(outputsDir, { withFileTypes: true });
|
|
4310
4136
|
if (entries.length === 0) {
|
|
4311
4137
|
throw new Error("No outputs found");
|
|
4312
4138
|
}
|
|
4313
4139
|
const copyOutputs = async (dir, rel = "") => {
|
|
4314
|
-
const files = await
|
|
4140
|
+
const files = await fs6.readdir(dir, { withFileTypes: true });
|
|
4315
4141
|
for (const file of files) {
|
|
4316
|
-
const sourcePath =
|
|
4317
|
-
const targetRel =
|
|
4318
|
-
const targetPath =
|
|
4142
|
+
const sourcePath = path6.join(dir, file.name);
|
|
4143
|
+
const targetRel = path6.join(rel, file.name);
|
|
4144
|
+
const targetPath = path6.join(workspaceRoot, targetRel);
|
|
4319
4145
|
if (file.isDirectory()) {
|
|
4320
4146
|
await copyOutputs(sourcePath, targetRel);
|
|
4321
4147
|
} else if (file.isFile()) {
|
|
4322
|
-
await
|
|
4323
|
-
const content = await
|
|
4324
|
-
await
|
|
4148
|
+
await fs6.mkdir(path6.dirname(targetPath), { recursive: true });
|
|
4149
|
+
const content = await fs6.readFile(sourcePath, "utf-8");
|
|
4150
|
+
await fs6.writeFile(targetPath, content, "utf-8");
|
|
4325
4151
|
}
|
|
4326
4152
|
}
|
|
4327
4153
|
};
|
|
4328
4154
|
await copyOutputs(outputsDir);
|
|
4329
|
-
console.log(
|
|
4155
|
+
console.log(chalk13.green("\u2705 Exact replay applied from stored outputs."));
|
|
4330
4156
|
return {
|
|
4331
4157
|
success: true,
|
|
4332
4158
|
projectSpec: { name: "replay", description: "Exact replay", type: "web-app", stack: {}, features: [] },
|
|
@@ -4337,34 +4163,309 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4337
4163
|
errors: []
|
|
4338
4164
|
};
|
|
4339
4165
|
} catch (error) {
|
|
4340
|
-
console.log(
|
|
4341
|
-
console.log(
|
|
4166
|
+
console.log(chalk13.yellow("\u26A0\uFE0F Exact replay failed, falling back to rerun."));
|
|
4167
|
+
console.log(chalk13.gray(String(error)));
|
|
4342
4168
|
}
|
|
4343
4169
|
}
|
|
4344
4170
|
if (!llm) {
|
|
4345
|
-
console.log(
|
|
4171
|
+
console.log(chalk13.red("\u274C No LLM provider available for replay."));
|
|
4346
4172
|
return null;
|
|
4347
4173
|
}
|
|
4348
4174
|
const orchestrator = new SquadOrchestrator(llm, config);
|
|
4349
4175
|
return await orchestrator.run(runConfig.prompt);
|
|
4350
4176
|
} catch (error) {
|
|
4351
|
-
console.log(
|
|
4352
|
-
console.log(
|
|
4177
|
+
console.log(chalk13.red("\u274C Failed to load run config for replay"));
|
|
4178
|
+
console.log(chalk13.gray(String(error)));
|
|
4353
4179
|
return null;
|
|
4354
4180
|
}
|
|
4355
4181
|
}
|
|
4356
4182
|
|
|
4183
|
+
// src/commands/tui-entry.tsx
|
|
4184
|
+
import { render } from "ink";
|
|
4185
|
+
|
|
4186
|
+
// src/ui/tui.tsx
|
|
4187
|
+
import { useState, useEffect } from "react";
|
|
4188
|
+
import { Box, Text, useApp } from "ink";
|
|
4189
|
+
import BigText from "ink-big-text";
|
|
4190
|
+
import Spinner from "ink-spinner";
|
|
4191
|
+
import TextInput from "ink-text-input";
|
|
4192
|
+
import fs7 from "fs";
|
|
4193
|
+
import path7 from "path";
|
|
4194
|
+
import os from "os";
|
|
4195
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4196
|
+
var BootScreen = ({ onComplete }) => {
|
|
4197
|
+
const [progress, setProgress] = useState(0);
|
|
4198
|
+
const [log, setLog] = useState("");
|
|
4199
|
+
const logs = [
|
|
4200
|
+
"Initializing core systems...",
|
|
4201
|
+
"Loading neural modules...",
|
|
4202
|
+
"Connecting to Agdi Cloud...",
|
|
4203
|
+
"Verifying agent credentials...",
|
|
4204
|
+
"Mounting virtual filesystem...",
|
|
4205
|
+
"Establishing secure uplink...",
|
|
4206
|
+
"Syncing global state...",
|
|
4207
|
+
"Boot sequence complete."
|
|
4208
|
+
];
|
|
4209
|
+
useEffect(() => {
|
|
4210
|
+
const timer = setInterval(() => {
|
|
4211
|
+
setProgress((prev) => {
|
|
4212
|
+
const next = prev + 5;
|
|
4213
|
+
if (next >= 100) {
|
|
4214
|
+
clearInterval(timer);
|
|
4215
|
+
setTimeout(onComplete, 200);
|
|
4216
|
+
return 100;
|
|
4217
|
+
}
|
|
4218
|
+
return next;
|
|
4219
|
+
});
|
|
4220
|
+
const index = Math.floor(progress / 100 * logs.length);
|
|
4221
|
+
setLog(logs[index] || logs[logs.length - 1]);
|
|
4222
|
+
}, 30);
|
|
4223
|
+
return () => clearInterval(timer);
|
|
4224
|
+
}, [progress]);
|
|
4225
|
+
const width = 60;
|
|
4226
|
+
const filled = Math.floor(width * progress / 100);
|
|
4227
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
4228
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 20, children: [
|
|
4229
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(BigText, { text: "AGDI OS", font: "block", align: "center", colors: ["cyan", "blue"] }) }),
|
|
4230
|
+
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
4231
|
+
bar,
|
|
4232
|
+
" ",
|
|
4233
|
+
progress,
|
|
4234
|
+
"%"
|
|
4235
|
+
] }) }),
|
|
4236
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
4237
|
+
"\u279C ",
|
|
4238
|
+
log
|
|
4239
|
+
] })
|
|
4240
|
+
] });
|
|
4241
|
+
};
|
|
4242
|
+
var FileExplorer = ({ cwd, lastChange }) => {
|
|
4243
|
+
const [files, setFiles] = useState([]);
|
|
4244
|
+
useEffect(() => {
|
|
4245
|
+
const refresh = () => {
|
|
4246
|
+
try {
|
|
4247
|
+
const list = fs7.readdirSync(cwd).filter((f) => !f.startsWith(".")).slice(0, 15);
|
|
4248
|
+
setFiles(list);
|
|
4249
|
+
} catch {
|
|
4250
|
+
setFiles(["<Error reading dir>"]);
|
|
4251
|
+
}
|
|
4252
|
+
};
|
|
4253
|
+
refresh();
|
|
4254
|
+
const timer = setInterval(refresh, 2e3);
|
|
4255
|
+
return () => clearInterval(timer);
|
|
4256
|
+
}, [cwd, lastChange]);
|
|
4257
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", title: " FILESYSTEM ", width: "30%", children: [
|
|
4258
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
4259
|
+
" ",
|
|
4260
|
+
cwd.length > 30 ? "..." + cwd.slice(-30) : cwd
|
|
4261
|
+
] }),
|
|
4262
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
4263
|
+
files.map((f, i) => /* @__PURE__ */ jsxs(Text, { color: "white", children: [
|
|
4264
|
+
fs7.statSync(path7.join(cwd, f)).isDirectory() ? "\u{1F4C1} " : "\u{1F4C4} ",
|
|
4265
|
+
f
|
|
4266
|
+
] }, i)),
|
|
4267
|
+
files.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: " (empty)" })
|
|
4268
|
+
] })
|
|
4269
|
+
] });
|
|
4270
|
+
};
|
|
4271
|
+
var LogPanel = ({ logs }) => {
|
|
4272
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", title: " AGENT LOGS ", width: "70%", marginLeft: 1, children: [
|
|
4273
|
+
logs.slice(-12).map((log, i) => /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
4274
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
4275
|
+
"[",
|
|
4276
|
+
(/* @__PURE__ */ new Date()).toLocaleTimeString(),
|
|
4277
|
+
"]"
|
|
4278
|
+
] }),
|
|
4279
|
+
" ",
|
|
4280
|
+
log
|
|
4281
|
+
] }, i)),
|
|
4282
|
+
logs.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: "Waiting for agent activity..." })
|
|
4283
|
+
] });
|
|
4284
|
+
};
|
|
4285
|
+
var ChatPanel = ({ history, onSend, placeholder = "" }) => {
|
|
4286
|
+
const [query, setQuery] = useState("");
|
|
4287
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", title: " MISSION CONTROL ", height: 12, children: [
|
|
4288
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, justifyContent: "flex-end", children: history.slice(-5).map((msg, i) => /* @__PURE__ */ jsxs(Box, { marginY: 0, children: [
|
|
4289
|
+
/* @__PURE__ */ jsx(Text, { color: msg.role === "user" ? "cyan" : msg.role === "system" ? "yellow" : "magenta", bold: true, children: msg.role === "user" ? "YOU \u203A " : msg.role === "system" ? "SYS \u203A " : "AGDI \u203A " }),
|
|
4290
|
+
/* @__PURE__ */ jsx(Text, { children: msg.text })
|
|
4291
|
+
] }, i)) }),
|
|
4292
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "gray", marginTop: 1, children: [
|
|
4293
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u279C " }),
|
|
4294
|
+
/* @__PURE__ */ jsx(
|
|
4295
|
+
TextInput,
|
|
4296
|
+
{
|
|
4297
|
+
value: query,
|
|
4298
|
+
onChange: setQuery,
|
|
4299
|
+
onSubmit: (val) => {
|
|
4300
|
+
onSend(val);
|
|
4301
|
+
setQuery("");
|
|
4302
|
+
},
|
|
4303
|
+
placeholder
|
|
4304
|
+
}
|
|
4305
|
+
)
|
|
4306
|
+
] })
|
|
4307
|
+
] });
|
|
4308
|
+
};
|
|
4309
|
+
var Dashboard = () => {
|
|
4310
|
+
const { exit } = useApp();
|
|
4311
|
+
const [cwd, setCwd] = useState(process.cwd());
|
|
4312
|
+
const [logs, setLogs] = useState(["System ready.", "Initializing Neural Link..."]);
|
|
4313
|
+
const [chatHistory, setChatHistory] = useState([]);
|
|
4314
|
+
const [step, setStep] = useState("safety");
|
|
4315
|
+
const [pendingAction, setPendingAction] = useState(null);
|
|
4316
|
+
const [lastFileChange, setLastFileChange] = useState(0);
|
|
4317
|
+
const [activeAgent, setActiveAgent] = useState("IDLE");
|
|
4318
|
+
useEffect(() => {
|
|
4319
|
+
const handleEvent = (event) => {
|
|
4320
|
+
if (event.type === "handoff") {
|
|
4321
|
+
setActiveAgent(event.role.toUpperCase());
|
|
4322
|
+
}
|
|
4323
|
+
if (event.type === "log" || event.type === "thought") {
|
|
4324
|
+
setLogs((prev) => [...prev, `[${event.agentName}] ${event.message}`]);
|
|
4325
|
+
}
|
|
4326
|
+
if (event.message.includes("Created:") || event.message.includes("Modified:")) {
|
|
4327
|
+
setLastFileChange(Date.now());
|
|
4328
|
+
}
|
|
4329
|
+
};
|
|
4330
|
+
agentEventBus.on("agent_event", handleEvent);
|
|
4331
|
+
return () => {
|
|
4332
|
+
agentEventBus.off("agent_event", handleEvent);
|
|
4333
|
+
};
|
|
4334
|
+
}, []);
|
|
4335
|
+
useEffect(() => {
|
|
4336
|
+
if (step === "safety") {
|
|
4337
|
+
const home = os.homedir();
|
|
4338
|
+
const root = path7.parse(cwd).root;
|
|
4339
|
+
const isUnsafe = cwd === home || cwd === root;
|
|
4340
|
+
if (isUnsafe) {
|
|
4341
|
+
setChatHistory([
|
|
4342
|
+
{ role: "system", text: `\u26A0\uFE0F SAFETY WARNING: You are running in ${cwd}` },
|
|
4343
|
+
{ role: "ai", text: "It is unsafe to run here. Should I create a new project folder for you? (yes/no)" }
|
|
4344
|
+
]);
|
|
4345
|
+
setPendingAction("safety_confirm");
|
|
4346
|
+
} else {
|
|
4347
|
+
setStep("prompt");
|
|
4348
|
+
setChatHistory([{ role: "ai", text: "Safety check passed. What are we building today?" }]);
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
}, []);
|
|
4352
|
+
const handleCommand = async (cmd) => {
|
|
4353
|
+
if (cmd === "/exit") exit();
|
|
4354
|
+
setChatHistory((prev) => [...prev, { role: "user", text: cmd }]);
|
|
4355
|
+
if (step === "safety" && pendingAction === "safety_confirm") {
|
|
4356
|
+
if (cmd.toLowerCase().startsWith("y")) {
|
|
4357
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Great. Enter a name for your project folder:" }]);
|
|
4358
|
+
setPendingAction("create_folder");
|
|
4359
|
+
} else {
|
|
4360
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Okay, proceeding in current directory (AT YOUR OWN RISK)." }]);
|
|
4361
|
+
setStep("prompt");
|
|
4362
|
+
setPendingAction(null);
|
|
4363
|
+
setTimeout(() => setChatHistory((prev) => [...prev, { role: "ai", text: "What are we building today?" }]), 500);
|
|
4364
|
+
}
|
|
4365
|
+
return;
|
|
4366
|
+
}
|
|
4367
|
+
if (step === "safety" && pendingAction === "create_folder") {
|
|
4368
|
+
const newPath = path7.join(cwd, cmd.replace(/[^a-z0-9-_]/gi, "-"));
|
|
4369
|
+
try {
|
|
4370
|
+
if (!fs7.existsSync(newPath)) fs7.mkdirSync(newPath);
|
|
4371
|
+
process.chdir(newPath);
|
|
4372
|
+
setCwd(newPath);
|
|
4373
|
+
setLogs((prev) => [...prev, `Switched directory to ${newPath}`]);
|
|
4374
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `\u{1F4C2} Switched to ${newPath}` }]);
|
|
4375
|
+
setStep("prompt");
|
|
4376
|
+
setPendingAction(null);
|
|
4377
|
+
setTimeout(() => setChatHistory((prev) => [...prev, { role: "ai", text: "What are we building today?" }]), 500);
|
|
4378
|
+
} catch (e) {
|
|
4379
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `Error creating folder: ${e}` }]);
|
|
4380
|
+
}
|
|
4381
|
+
return;
|
|
4382
|
+
}
|
|
4383
|
+
if (step === "prompt") {
|
|
4384
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Analyzing requirements..." }]);
|
|
4385
|
+
setStep("active");
|
|
4386
|
+
setActiveAgent("MANAGER");
|
|
4387
|
+
const activeConfig = getActiveProvider();
|
|
4388
|
+
if (!activeConfig) {
|
|
4389
|
+
setChatHistory((prev) => [...prev, { role: "system", text: '\u274C No API key found. Run "agdi auth" first.' }]);
|
|
4390
|
+
return;
|
|
4391
|
+
}
|
|
4392
|
+
const llm = createLLMProvider(activeConfig.provider, {
|
|
4393
|
+
apiKey: activeConfig.apiKey,
|
|
4394
|
+
model: activeConfig.model
|
|
4395
|
+
});
|
|
4396
|
+
runSquadCommand(cmd, llm, {
|
|
4397
|
+
output: cwd,
|
|
4398
|
+
verbose: false,
|
|
4399
|
+
// We handle logs via event bus now
|
|
4400
|
+
deploy: false
|
|
4401
|
+
}).then(() => {
|
|
4402
|
+
setActiveAgent("IDLE");
|
|
4403
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "\u{1F680} Mission Complete! Check the files." }]);
|
|
4404
|
+
}).catch((err) => {
|
|
4405
|
+
setActiveAgent("ERROR");
|
|
4406
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `\u274C Error: ${err.message}` }]);
|
|
4407
|
+
});
|
|
4408
|
+
}
|
|
4409
|
+
};
|
|
4410
|
+
const getStatusColor = () => {
|
|
4411
|
+
switch (activeAgent) {
|
|
4412
|
+
case "MANAGER":
|
|
4413
|
+
return "magenta";
|
|
4414
|
+
case "FRONTEND":
|
|
4415
|
+
return "cyan";
|
|
4416
|
+
case "BACKEND":
|
|
4417
|
+
return "blue";
|
|
4418
|
+
case "QA":
|
|
4419
|
+
return "yellow";
|
|
4420
|
+
case "DEVOPS":
|
|
4421
|
+
return "green";
|
|
4422
|
+
case "ERROR":
|
|
4423
|
+
return "red";
|
|
4424
|
+
default:
|
|
4425
|
+
return "gray";
|
|
4426
|
+
}
|
|
4427
|
+
};
|
|
4428
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [
|
|
4429
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
4430
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "AGDI v3.3.2 [ONLINE]" }),
|
|
4431
|
+
/* @__PURE__ */ jsxs(Text, { color: getStatusColor(), children: [
|
|
4432
|
+
"AGENT: ",
|
|
4433
|
+
activeAgent,
|
|
4434
|
+
" ",
|
|
4435
|
+
activeAgent !== "IDLE" && /* @__PURE__ */ jsx(Spinner, { type: "dots" })
|
|
4436
|
+
] }),
|
|
4437
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "NET: CONNECTED" })
|
|
4438
|
+
] }),
|
|
4439
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [
|
|
4440
|
+
/* @__PURE__ */ jsx(FileExplorer, { cwd, lastChange: lastFileChange }),
|
|
4441
|
+
/* @__PURE__ */ jsx(LogPanel, { logs })
|
|
4442
|
+
] }),
|
|
4443
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(ChatPanel, { history: chatHistory, onSend: handleCommand, placeholder: step === "prompt" ? "Describe your app..." : "" }) })
|
|
4444
|
+
] });
|
|
4445
|
+
};
|
|
4446
|
+
var App = () => {
|
|
4447
|
+
const [screen, setScreen] = useState("boot");
|
|
4448
|
+
return screen === "boot" ? /* @__PURE__ */ jsx(BootScreen, { onComplete: () => setScreen("dashboard") }) : /* @__PURE__ */ jsx(Dashboard, {});
|
|
4449
|
+
};
|
|
4450
|
+
|
|
4451
|
+
// src/commands/tui-entry.tsx
|
|
4452
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4453
|
+
function runTUI() {
|
|
4454
|
+
console.clear();
|
|
4455
|
+
render(/* @__PURE__ */ jsx2(App, {}));
|
|
4456
|
+
}
|
|
4457
|
+
|
|
4357
4458
|
// src/index.ts
|
|
4358
4459
|
var BANNER = `
|
|
4359
|
-
${
|
|
4360
|
-
${
|
|
4361
|
-
${
|
|
4362
|
-
${
|
|
4363
|
-
${
|
|
4364
|
-
${
|
|
4460
|
+
${chalk14.cyan(` ___ __ _ `)}
|
|
4461
|
+
${chalk14.cyan(` / | ____ _____/ /(_) `)}
|
|
4462
|
+
${chalk14.cyan(` / /| | / __ \`/ __ // / `)}
|
|
4463
|
+
${chalk14.cyan(` / ___ |/ /_/ / /_/ // / `)}
|
|
4464
|
+
${chalk14.cyan(`/_/ |_|\\_, /\\__,_//_/ `)}
|
|
4465
|
+
${chalk14.cyan(` /____/ `)}
|
|
4365
4466
|
`;
|
|
4366
4467
|
var program = new Command();
|
|
4367
|
-
program.name("agdi").description(
|
|
4468
|
+
program.name("agdi").description(chalk14.cyan("\u{1F9B8} The Autonomous AI Employee")).version("3.3.2").option("-y, --yes", "Auto-approve all prompts (headless/CI mode)").option("-m, --minimal", "Generate only the requested file(s), not a full app").option("-d, --dry-run", "Show what would be created without writing files").option("--saas", "Generate a production SaaS blueprint (Next.js + Prisma + Postgres + Stripe)");
|
|
4368
4469
|
program.hook("preAction", (thisCommand) => {
|
|
4369
4470
|
const opts = thisCommand.opts();
|
|
4370
4471
|
if (opts.yes) {
|
|
@@ -4381,15 +4482,14 @@ program.hook("preAction", (thisCommand) => {
|
|
|
4381
4482
|
}
|
|
4382
4483
|
});
|
|
4383
4484
|
program.addHelpText("beforeAll", () => {
|
|
4384
|
-
return BANNER + "\n" +
|
|
4485
|
+
return BANNER + "\n" + chalk14.gray(" The Autonomous AI Employee") + "\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");
|
|
4385
4486
|
});
|
|
4386
4487
|
program.action(async () => {
|
|
4387
4488
|
try {
|
|
4388
|
-
|
|
4389
|
-
await runWizard();
|
|
4489
|
+
runTUI();
|
|
4390
4490
|
} catch (error) {
|
|
4391
4491
|
if (error.name === "ExitPromptError") {
|
|
4392
|
-
console.log(
|
|
4492
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4393
4493
|
try {
|
|
4394
4494
|
ui.safeExit(0);
|
|
4395
4495
|
} catch {
|
|
@@ -4411,7 +4511,7 @@ program.command("auth").description("Configure API keys").option("--status", "Sh
|
|
|
4411
4511
|
}
|
|
4412
4512
|
} catch (error) {
|
|
4413
4513
|
if (error.name === "ExitPromptError") {
|
|
4414
|
-
console.log(
|
|
4514
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4415
4515
|
try {
|
|
4416
4516
|
ui.safeExit(0);
|
|
4417
4517
|
} catch {
|
|
@@ -4429,7 +4529,7 @@ program.command("model").alias("models").description("Change AI model").action(a
|
|
|
4429
4529
|
await selectModel();
|
|
4430
4530
|
} catch (error) {
|
|
4431
4531
|
if (error.name === "ExitPromptError") {
|
|
4432
|
-
console.log(
|
|
4532
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4433
4533
|
try {
|
|
4434
4534
|
ui.safeExit(0);
|
|
4435
4535
|
} catch {
|
|
@@ -4450,7 +4550,7 @@ program.command("chat").description("Start a chat session").action(async () => {
|
|
|
4450
4550
|
await startChat();
|
|
4451
4551
|
} catch (error) {
|
|
4452
4552
|
if (error.name === "ExitPromptError") {
|
|
4453
|
-
console.log(
|
|
4553
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4454
4554
|
try {
|
|
4455
4555
|
ui.safeExit(0);
|
|
4456
4556
|
} catch {
|
|
@@ -4468,7 +4568,7 @@ program.command("run [directory]").description("Run a generated project").action
|
|
|
4468
4568
|
await runProject(directory);
|
|
4469
4569
|
} catch (error) {
|
|
4470
4570
|
if (error.name === "ExitPromptError") {
|
|
4471
|
-
console.log(
|
|
4571
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4472
4572
|
try {
|
|
4473
4573
|
ui.safeExit(0);
|
|
4474
4574
|
} catch {
|
|
@@ -4491,7 +4591,7 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4491
4591
|
}
|
|
4492
4592
|
const activeConfig = getActiveProvider();
|
|
4493
4593
|
if (!activeConfig) {
|
|
4494
|
-
console.log(
|
|
4594
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4495
4595
|
return;
|
|
4496
4596
|
}
|
|
4497
4597
|
const spinner = ora6("Generating application...").start();
|
|
@@ -4503,52 +4603,52 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4503
4603
|
const pm = new ProjectManager();
|
|
4504
4604
|
pm.create(options.output.replace("./", ""), prompt);
|
|
4505
4605
|
const { plan, files } = await generateApp(prompt, llm, (step, file) => {
|
|
4506
|
-
spinner.text = file ? `${step} ${
|
|
4606
|
+
spinner.text = file ? `${step} ${chalk14.gray(file)}` : step;
|
|
4507
4607
|
});
|
|
4508
4608
|
pm.updateFiles(files);
|
|
4509
4609
|
pm.updateDependencies(plan.dependencies);
|
|
4510
4610
|
if (options.dryRun || ui.flags.dryRun) {
|
|
4511
4611
|
spinner.stop();
|
|
4512
|
-
console.log(
|
|
4513
|
-
console.log(
|
|
4612
|
+
console.log(chalk14.cyan.bold("\n\u{1F6A7} DRY RUN SUMMARY\n"));
|
|
4613
|
+
console.log(chalk14.gray(`Project: ${plan.name}
|
|
4514
4614
|
`));
|
|
4515
|
-
console.log(
|
|
4516
|
-
files.forEach((f) => console.log(
|
|
4517
|
-
console.log(
|
|
4518
|
-
console.log(
|
|
4519
|
-
console.log(
|
|
4615
|
+
console.log(chalk14.cyan("Files to be created:"));
|
|
4616
|
+
files.forEach((f) => console.log(chalk14.gray(` \u{1F4C4} ${f.path}`)));
|
|
4617
|
+
console.log(chalk14.cyan("\nDependencies:"));
|
|
4618
|
+
console.log(chalk14.gray(` \u{1F4E6} ${plan.dependencies.join(", ")}`));
|
|
4619
|
+
console.log(chalk14.green("\n\u2713 Dry run complete. No files written.\n"));
|
|
4520
4620
|
return;
|
|
4521
4621
|
}
|
|
4522
4622
|
await writeProject(pm.get(), options.output);
|
|
4523
|
-
spinner.succeed(
|
|
4524
|
-
console.log(
|
|
4525
|
-
\u{1F4C1} Created ${files.length} files in ${
|
|
4623
|
+
spinner.succeed(chalk14.green("App generated!"));
|
|
4624
|
+
console.log(chalk14.gray(`
|
|
4625
|
+
\u{1F4C1} Created ${files.length} files in ${chalk14.cyan(options.output)}`));
|
|
4526
4626
|
if (ui.flags.saas || options.saas) {
|
|
4527
|
-
console.log(
|
|
4528
|
-
console.log(
|
|
4529
|
-
console.log(
|
|
4530
|
-
console.log(
|
|
4531
|
-
console.log(
|
|
4532
|
-
console.log(
|
|
4533
|
-
console.log(
|
|
4627
|
+
console.log(chalk14.cyan("\nSaaS Quick Start:"));
|
|
4628
|
+
console.log(chalk14.gray(` 1) cd ${options.output}`));
|
|
4629
|
+
console.log(chalk14.gray(" 2) npm install"));
|
|
4630
|
+
console.log(chalk14.gray(" 3) cp .env.example .env"));
|
|
4631
|
+
console.log(chalk14.gray(" 4) npx prisma generate"));
|
|
4632
|
+
console.log(chalk14.gray(" 5) npx prisma db push"));
|
|
4633
|
+
console.log(chalk14.gray(" 6) npm run dev\n"));
|
|
4534
4634
|
} else {
|
|
4535
|
-
console.log(
|
|
4635
|
+
console.log(chalk14.gray("\nNext: cd " + options.output + " && npm install && npm run dev\n"));
|
|
4536
4636
|
}
|
|
4537
4637
|
} catch (error) {
|
|
4538
4638
|
spinner.fail("Generation failed");
|
|
4539
4639
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4540
4640
|
if (msg.includes("429") || msg.includes("quota")) {
|
|
4541
|
-
console.log(
|
|
4641
|
+
console.log(chalk14.yellow("\n\u26A0\uFE0F Quota exceeded. Run: agdi model\n"));
|
|
4542
4642
|
} else if (msg.includes("401") || msg.includes("403")) {
|
|
4543
|
-
console.log(
|
|
4643
|
+
console.log(chalk14.red("\n\u{1F511} Invalid API key. Run: agdi auth\n"));
|
|
4544
4644
|
} else {
|
|
4545
|
-
console.error(
|
|
4645
|
+
console.error(chalk14.red("\n" + msg + "\n"));
|
|
4546
4646
|
}
|
|
4547
4647
|
ui.safeExit(1);
|
|
4548
4648
|
}
|
|
4549
4649
|
} catch (error) {
|
|
4550
4650
|
if (error.name === "ExitPromptError") {
|
|
4551
|
-
console.log(
|
|
4651
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4552
4652
|
try {
|
|
4553
4653
|
ui.safeExit(0);
|
|
4554
4654
|
} catch {
|
|
@@ -4564,11 +4664,11 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4564
4664
|
program.command("config").description("Show configuration").action(async () => {
|
|
4565
4665
|
const config = loadConfig();
|
|
4566
4666
|
const active = getActiveProvider();
|
|
4567
|
-
console.log(
|
|
4568
|
-
console.log(
|
|
4569
|
-
console.log(
|
|
4570
|
-
console.log(
|
|
4571
|
-
console.log(
|
|
4667
|
+
console.log(chalk14.cyan.bold("\n\u2699\uFE0F Configuration\n"));
|
|
4668
|
+
console.log(chalk14.gray(" Provider: ") + chalk14.cyan(config.defaultProvider || "not set"));
|
|
4669
|
+
console.log(chalk14.gray(" Model: ") + chalk14.cyan(config.defaultModel || "not set"));
|
|
4670
|
+
console.log(chalk14.gray(" Config: ") + chalk14.gray("~/.agdi/config.json"));
|
|
4671
|
+
console.log(chalk14.cyan.bold("\n\u{1F510} API Keys\n"));
|
|
4572
4672
|
const keys = [
|
|
4573
4673
|
["Gemini", config.geminiApiKey],
|
|
4574
4674
|
["OpenRouter", config.openrouterApiKey],
|
|
@@ -4577,13 +4677,13 @@ program.command("config").description("Show configuration").action(async () => {
|
|
|
4577
4677
|
["DeepSeek", config.deepseekApiKey]
|
|
4578
4678
|
];
|
|
4579
4679
|
for (const [name, key] of keys) {
|
|
4580
|
-
const status = key ?
|
|
4680
|
+
const status = key ? chalk14.green("\u2713") : chalk14.gray("\u2717");
|
|
4581
4681
|
console.log(` ${status} ${name}`);
|
|
4582
4682
|
}
|
|
4583
|
-
console.log(
|
|
4683
|
+
console.log(chalk14.cyan.bold("\n\u{1F4CA} Telemetry\n"));
|
|
4584
4684
|
const telemetryEnabled = config.telemetry?.enabled ?? false;
|
|
4585
|
-
console.log(` ${telemetryEnabled ?
|
|
4586
|
-
console.log(
|
|
4685
|
+
console.log(` ${telemetryEnabled ? chalk14.green("\u2713 Enabled") : chalk14.gray("\u2717 Disabled")}`);
|
|
4686
|
+
console.log(chalk14.gray(" Change with: agdi config telemetry --enable | --disable"));
|
|
4587
4687
|
console.log("");
|
|
4588
4688
|
console.log("");
|
|
4589
4689
|
});
|
|
@@ -4591,59 +4691,59 @@ program.command("config:telemetry").alias("telemetry").description("Manage telem
|
|
|
4591
4691
|
const { isTelemetryEnabled, setTelemetryConsent, getTelemetryConfig } = await import("./config-ZFU7TSU2.js");
|
|
4592
4692
|
const { generateSampleEvent, generateSanitizationDemo } = await import("./telemetry-service-OHU5NKON.js");
|
|
4593
4693
|
if (options.dryRun || options.test) {
|
|
4594
|
-
console.log(
|
|
4595
|
-
console.log(
|
|
4596
|
-
console.log(
|
|
4597
|
-
console.log(
|
|
4694
|
+
console.log(chalk14.cyan.bold("\n\u{1F50D} TELEMETRY TRANSPARENCY MODE\n"));
|
|
4695
|
+
console.log(chalk14.gray("This is exactly what Agdi sends. Notice there is"));
|
|
4696
|
+
console.log(chalk14.green.bold("NO source code, file paths, or API keys.\n"));
|
|
4697
|
+
console.log(chalk14.white.bold('\u{1F4CA} Sample "Build Failed" Event:\n'));
|
|
4598
4698
|
const sample = generateSampleEvent();
|
|
4599
|
-
console.log(
|
|
4600
|
-
console.log(
|
|
4601
|
-
console.log(
|
|
4602
|
-
console.log(
|
|
4699
|
+
console.log(chalk14.gray(JSON.stringify(sample, null, 2)));
|
|
4700
|
+
console.log(chalk14.white.bold("\n\u{1F6E1}\uFE0F Sanitization Demo:\n"));
|
|
4701
|
+
console.log(chalk14.gray("Even if sensitive data accidentally enters an error message,"));
|
|
4702
|
+
console.log(chalk14.gray("our sanitization layer strips it before transmission:\n"));
|
|
4603
4703
|
const demo = generateSanitizationDemo();
|
|
4604
|
-
console.log(
|
|
4605
|
-
console.log(
|
|
4704
|
+
console.log(chalk14.red.bold("BEFORE sanitization (never sent):"));
|
|
4705
|
+
console.log(chalk14.gray(JSON.stringify({
|
|
4606
4706
|
errorCode: demo.before.errorCode,
|
|
4607
4707
|
feedback: demo.before.feedback
|
|
4608
4708
|
}, null, 2)));
|
|
4609
|
-
console.log(
|
|
4610
|
-
console.log(
|
|
4709
|
+
console.log(chalk14.green.bold("\nAFTER sanitization (what we actually send):"));
|
|
4710
|
+
console.log(chalk14.gray(JSON.stringify({
|
|
4611
4711
|
errorCode: demo.after.errorCode,
|
|
4612
4712
|
feedback: demo.after.feedback
|
|
4613
4713
|
}, null, 2)));
|
|
4614
|
-
console.log(
|
|
4615
|
-
console.log(
|
|
4714
|
+
console.log(chalk14.cyan("\n\u2705 Your code and secrets are NEVER transmitted."));
|
|
4715
|
+
console.log(chalk14.gray(" Learn more: https://agdi.dev/privacy\n"));
|
|
4616
4716
|
return;
|
|
4617
4717
|
}
|
|
4618
4718
|
if (options.enable) {
|
|
4619
4719
|
setTelemetryConsent(true);
|
|
4620
|
-
console.log(
|
|
4621
|
-
console.log(
|
|
4622
|
-
console.log(
|
|
4623
|
-
console.log(
|
|
4720
|
+
console.log(chalk14.green("\n\u2705 Telemetry enabled"));
|
|
4721
|
+
console.log(chalk14.gray(" We collect: success/fail, error types, model used"));
|
|
4722
|
+
console.log(chalk14.gray(" We NEVER collect: source code, API keys, file paths"));
|
|
4723
|
+
console.log(chalk14.gray(" Verify anytime: agdi config telemetry --dry-run\n"));
|
|
4624
4724
|
} else if (options.disable) {
|
|
4625
4725
|
setTelemetryConsent(false);
|
|
4626
|
-
console.log(
|
|
4627
|
-
console.log(
|
|
4726
|
+
console.log(chalk14.yellow("\n\u{1F4CA} Telemetry disabled"));
|
|
4727
|
+
console.log(chalk14.gray(" You can re-enable anytime with: agdi config telemetry --enable\n"));
|
|
4628
4728
|
} else {
|
|
4629
4729
|
const config = getTelemetryConfig();
|
|
4630
|
-
console.log(
|
|
4631
|
-
console.log(
|
|
4632
|
-
console.log(
|
|
4730
|
+
console.log(chalk14.cyan.bold("\n\u{1F4CA} Telemetry Status\n"));
|
|
4731
|
+
console.log(chalk14.gray(" Enabled: ") + (config.enabled ? chalk14.green("Yes") : chalk14.gray("No")));
|
|
4732
|
+
console.log(chalk14.gray(" Consent: ") + (config.consentAsked ? chalk14.green("Asked") : chalk14.gray("Not asked")));
|
|
4633
4733
|
if (config.anonymousId) {
|
|
4634
|
-
console.log(
|
|
4734
|
+
console.log(chalk14.gray(" ID: ") + chalk14.gray(config.anonymousId.slice(0, 8) + "..."));
|
|
4635
4735
|
}
|
|
4636
4736
|
console.log("");
|
|
4637
|
-
console.log(
|
|
4638
|
-
console.log(
|
|
4639
|
-
console.log(
|
|
4737
|
+
console.log(chalk14.gray(" Enable: agdi config telemetry --enable"));
|
|
4738
|
+
console.log(chalk14.gray(" Disable: agdi config telemetry --disable"));
|
|
4739
|
+
console.log(chalk14.gray(" Verify: agdi config telemetry --dry-run\n"));
|
|
4640
4740
|
}
|
|
4641
4741
|
});
|
|
4642
4742
|
program.command("doctor").alias("doc").description("Run self-diagnosis checks").action(async () => {
|
|
4643
4743
|
try {
|
|
4644
4744
|
await runDoctor();
|
|
4645
4745
|
} catch (error) {
|
|
4646
|
-
console.error(
|
|
4746
|
+
console.error(chalk14.red("Diagnostic failed: " + error));
|
|
4647
4747
|
ui.safeExit(1);
|
|
4648
4748
|
}
|
|
4649
4749
|
});
|
|
@@ -4654,7 +4754,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4654
4754
|
}
|
|
4655
4755
|
const activeConfig = getActiveProvider();
|
|
4656
4756
|
if (!activeConfig) {
|
|
4657
|
-
console.log(
|
|
4757
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4658
4758
|
return;
|
|
4659
4759
|
}
|
|
4660
4760
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4668,7 +4768,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4668
4768
|
});
|
|
4669
4769
|
} catch (error) {
|
|
4670
4770
|
if (error.name === "ExitPromptError") {
|
|
4671
|
-
console.log(
|
|
4771
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4672
4772
|
try {
|
|
4673
4773
|
ui.safeExit(0);
|
|
4674
4774
|
} catch {
|
|
@@ -4696,7 +4796,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4696
4796
|
}
|
|
4697
4797
|
const activeConfig = getActiveProvider();
|
|
4698
4798
|
if (!activeConfig) {
|
|
4699
|
-
console.log(
|
|
4799
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4700
4800
|
return;
|
|
4701
4801
|
}
|
|
4702
4802
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4710,7 +4810,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4710
4810
|
});
|
|
4711
4811
|
} catch (error) {
|
|
4712
4812
|
if (error.name === "ExitPromptError") {
|
|
4713
|
-
console.log(
|
|
4813
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4714
4814
|
try {
|
|
4715
4815
|
ui.safeExit(0);
|
|
4716
4816
|
} catch {
|
|
@@ -4728,7 +4828,7 @@ program.command("import <url>").alias("i").description("\u{1F4E6} Import a GitHu
|
|
|
4728
4828
|
await runImportCommand(url, options.output);
|
|
4729
4829
|
} catch (error) {
|
|
4730
4830
|
if (error.name === "ExitPromptError") {
|
|
4731
|
-
console.log(
|
|
4831
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4732
4832
|
try {
|
|
4733
4833
|
ui.safeExit(0);
|
|
4734
4834
|
} catch {
|