agdi 3.3.4 → 3.3.6
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 +348 -332
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
agentEventBus,
|
|
4
3
|
emitAgentEvent
|
|
5
4
|
} from "./chunk-A5UTYKKM.js";
|
|
6
5
|
import {
|
|
@@ -10,7 +9,7 @@ import {
|
|
|
10
9
|
|
|
11
10
|
// src/index.ts
|
|
12
11
|
import { Command } from "commander";
|
|
13
|
-
import
|
|
12
|
+
import chalk15 from "chalk";
|
|
14
13
|
import ora6 from "ora";
|
|
15
14
|
|
|
16
15
|
// src/core/llm/index.ts
|
|
@@ -453,8 +452,8 @@ async function smartConfirm(message, defaultValue = false) {
|
|
|
453
452
|
console.warn(chalk.yellow("\u26A0\uFE0F Non-interactive session detected. Use --yes to approve actions."));
|
|
454
453
|
return false;
|
|
455
454
|
}
|
|
456
|
-
const { confirm } = await import("@inquirer/prompts");
|
|
457
|
-
return
|
|
455
|
+
const { confirm: confirm2 } = await import("@inquirer/prompts");
|
|
456
|
+
return confirm2({ message, default: defaultValue });
|
|
458
457
|
}
|
|
459
458
|
async function smartSelect(message, choices, defaultValue) {
|
|
460
459
|
if (!process.stdout.isTTY || flags.headless) {
|
|
@@ -464,8 +463,8 @@ async function smartSelect(message, choices, defaultValue) {
|
|
|
464
463
|
}
|
|
465
464
|
return result || null;
|
|
466
465
|
}
|
|
467
|
-
const { select:
|
|
468
|
-
return
|
|
466
|
+
const { select: select4 } = await import("@inquirer/prompts");
|
|
467
|
+
return select4({ message, choices });
|
|
469
468
|
}
|
|
470
469
|
var ui = {
|
|
471
470
|
renderBanner,
|
|
@@ -499,7 +498,10 @@ Return a JSON object with:
|
|
|
499
498
|
{
|
|
500
499
|
"name": "app-name",
|
|
501
500
|
"description": "Brief description",
|
|
502
|
-
"files": [
|
|
501
|
+
"files": [
|
|
502
|
+
{"path": "src/App.tsx", "description": "Main component"},
|
|
503
|
+
{"path": "README.md", "description": "Project documentation"}
|
|
504
|
+
],
|
|
503
505
|
"dependencies": ["react", "tailwindcss"],
|
|
504
506
|
"architecture": "Component architecture description"
|
|
505
507
|
}
|
|
@@ -1786,8 +1788,8 @@ async function runOnboarding() {
|
|
|
1786
1788
|
console.log(chalk7.gray("We collect anonymous error logs (like a ") + chalk7.yellow("'Check Engine'") + chalk7.gray(" light)"));
|
|
1787
1789
|
console.log(chalk7.gray("to fix bugs faster. We ") + chalk7.green.bold("never") + chalk7.gray(" see your code or keys.\n"));
|
|
1788
1790
|
console.log(chalk7.dim("Verify anytime: agdi config telemetry --dry-run\n"));
|
|
1789
|
-
const { confirm } = await import("@inquirer/prompts");
|
|
1790
|
-
const enableTelemetry = await
|
|
1791
|
+
const { confirm: confirm2 } = await import("@inquirer/prompts");
|
|
1792
|
+
const enableTelemetry = await confirm2({
|
|
1791
1793
|
message: "Enable crash reporting? (helps us fix bugs)",
|
|
1792
1794
|
default: false
|
|
1793
1795
|
});
|
|
@@ -4182,19 +4184,243 @@ ${msg}
|
|
|
4182
4184
|
}
|
|
4183
4185
|
}
|
|
4184
4186
|
|
|
4185
|
-
// src/commands/
|
|
4187
|
+
// src/commands/wizard.ts
|
|
4188
|
+
import { input as input5, select as select3, confirm, password as password3 } from "@inquirer/prompts";
|
|
4186
4189
|
import chalk13 from "chalk";
|
|
4187
|
-
import
|
|
4188
|
-
import
|
|
4190
|
+
import path6 from "path";
|
|
4191
|
+
import os from "os";
|
|
4192
|
+
import fs6 from "fs";
|
|
4193
|
+
async function runWizard() {
|
|
4194
|
+
await checkSafety();
|
|
4195
|
+
if (needsOnboarding()) {
|
|
4196
|
+
await runOnboarding();
|
|
4197
|
+
}
|
|
4198
|
+
await setupOptionalTools();
|
|
4199
|
+
const wantsSaas = await confirm({
|
|
4200
|
+
message: "Enable SaaS Blueprint mode? (Next.js + Prisma + Postgres + Stripe)",
|
|
4201
|
+
default: true
|
|
4202
|
+
});
|
|
4203
|
+
if (wantsSaas) {
|
|
4204
|
+
ui.setFlags({ saas: true });
|
|
4205
|
+
}
|
|
4206
|
+
console.log(chalk13.cyan.bold("\n\u{1F3AF} Mission Control (ClawBot Setup)"));
|
|
4207
|
+
console.log(chalk13.gray("I need to calibrate the squad. Answer these 4 questions to define your build.\n"));
|
|
4208
|
+
const vision = await input5({
|
|
4209
|
+
message: '1. What are we building today? (e.g. "A Kanban board", "Portfolio site")',
|
|
4210
|
+
validate: (value) => value.length > 3 ? true : "Please provide a bit more detail"
|
|
4211
|
+
});
|
|
4212
|
+
const target = await input5({
|
|
4213
|
+
message: "2. Who is this for? (Target Audience)",
|
|
4214
|
+
default: "General users"
|
|
4215
|
+
});
|
|
4216
|
+
const problem = await input5({
|
|
4217
|
+
message: "3. What core problem does this solve?",
|
|
4218
|
+
default: "Simplifying a workflow"
|
|
4219
|
+
});
|
|
4220
|
+
const needsImages = await confirm({
|
|
4221
|
+
message: "4. Do you need generated images or placeholder assets?",
|
|
4222
|
+
default: true
|
|
4223
|
+
});
|
|
4224
|
+
let prompt = `Build an application with the following specification:
|
|
4225
|
+
- **Concept:** ${vision}
|
|
4226
|
+
- **Target Audience:** ${target}
|
|
4227
|
+
- **Problem Solved:** ${problem}
|
|
4228
|
+
- **Asset Requirement:** ${needsImages ? "Include placeholder images and assets" : "Minimalist, code-only layout"}
|
|
4229
|
+
`;
|
|
4230
|
+
if (wantsSaas) {
|
|
4231
|
+
prompt = `${prompt}
|
|
4232
|
+
|
|
4233
|
+
Constraints: Build a production SaaS using Next.js App Router, Prisma, Postgres, and Stripe. Include auth, billing, multi-tenant orgs, and a dashboard.`;
|
|
4234
|
+
}
|
|
4235
|
+
const activeConfig = getActiveProvider();
|
|
4236
|
+
if (!activeConfig) {
|
|
4237
|
+
console.log(chalk13.red("\u274C No API key configured. Run: agdi auth"));
|
|
4238
|
+
return;
|
|
4239
|
+
}
|
|
4240
|
+
const llm = createLLMProvider(activeConfig.provider, {
|
|
4241
|
+
apiKey: activeConfig.apiKey,
|
|
4242
|
+
model: activeConfig.model
|
|
4243
|
+
});
|
|
4244
|
+
console.log(chalk13.cyan("\n\u{1F914} Analyzing requirements..."));
|
|
4245
|
+
try {
|
|
4246
|
+
const analysis = await llm.generate(prompt, `
|
|
4247
|
+
You are a Senior Product Manager. Analyze this app idea.
|
|
4248
|
+
If it is vague (e.g., "make a CRM"), generate 3 specific questions to clarify scope, tech stack, and features.
|
|
4249
|
+
If it is detailed enough, return "DETAILED".
|
|
4250
|
+
|
|
4251
|
+
Format:
|
|
4252
|
+
Questions:
|
|
4253
|
+
1. [Question 1]
|
|
4254
|
+
2. [Question 2]
|
|
4255
|
+
3. [Question 3]
|
|
4256
|
+
`);
|
|
4257
|
+
if (!analysis.text.includes("DETAILED")) {
|
|
4258
|
+
console.log(chalk13.yellow("\n\u{1F4A1} I need a few more details to build exactly what you want:"));
|
|
4259
|
+
const questions = analysis.text.split("\n").filter((line) => line.match(/^\d+\./));
|
|
4260
|
+
const answers = [];
|
|
4261
|
+
for (const q of questions.slice(0, 3)) {
|
|
4262
|
+
const answer = await input5({ message: q.replace(/^\d+\.\s*/, "") });
|
|
4263
|
+
answers.push({ q, a: answer });
|
|
4264
|
+
}
|
|
4265
|
+
console.log(chalk13.cyan("\n\u{1F504} Synthesizing Master Plan..."));
|
|
4266
|
+
const synthesis = await llm.generate(
|
|
4267
|
+
`Original Request: ${prompt}
|
|
4268
|
+
|
|
4269
|
+
Clarifications:
|
|
4270
|
+
${answers.map((x) => `Q: ${x.q}
|
|
4271
|
+
A: ${x.a}`).join("\n")}
|
|
4272
|
+
|
|
4273
|
+
Rewrite the original request into a comprehensive technical specification for a developer squad.`,
|
|
4274
|
+
"You are a Technical Architect."
|
|
4275
|
+
);
|
|
4276
|
+
prompt = synthesis.text;
|
|
4277
|
+
console.log(chalk13.gray("\nUpdated Spec: " + prompt.substring(0, 100) + "...\n"));
|
|
4278
|
+
}
|
|
4279
|
+
} catch (err) {
|
|
4280
|
+
console.log(chalk13.gray("Skipping analysis (API unreachable), proceeding with raw prompt."));
|
|
4281
|
+
}
|
|
4282
|
+
console.log(chalk13.cyan("\n\u{1F680} Assembling the Squad..."));
|
|
4283
|
+
console.log(chalk13.gray("Frontend, Backend, QA, and DevOps agents are coming online.\n"));
|
|
4284
|
+
const config = loadConfig();
|
|
4285
|
+
const canDeploy = !!(config.vercelToken || config.netlifyToken || config.railwayToken);
|
|
4286
|
+
await runSquadCommand(prompt, llm, {
|
|
4287
|
+
deploy: canDeploy,
|
|
4288
|
+
// Auto-deploy if configured
|
|
4289
|
+
output: "./",
|
|
4290
|
+
// Current directory (safe because we checked safety earlier)
|
|
4291
|
+
verbose: true
|
|
4292
|
+
});
|
|
4293
|
+
if (ui.flags.saas) {
|
|
4294
|
+
console.log(chalk13.cyan("\nSaaS Quick Start:"));
|
|
4295
|
+
console.log(chalk13.gray(" 1) npm install"));
|
|
4296
|
+
console.log(chalk13.gray(" 2) cp .env.example .env"));
|
|
4297
|
+
console.log(chalk13.gray(" 3) npx prisma generate"));
|
|
4298
|
+
console.log(chalk13.gray(" 4) npx prisma db push"));
|
|
4299
|
+
console.log(chalk13.gray(" 5) npm run dev\n"));
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
async function checkSafety() {
|
|
4303
|
+
const cwd = process.cwd();
|
|
4304
|
+
const home = os.homedir();
|
|
4305
|
+
const root = path6.parse(cwd).root;
|
|
4306
|
+
const isUnsafe = cwd === home || cwd === root;
|
|
4307
|
+
if (isUnsafe) {
|
|
4308
|
+
console.log(chalk13.yellow.bold("\n\u26A0\uFE0F Safety Warning"));
|
|
4309
|
+
console.log(chalk13.gray(`You are running Agdi in ${chalk13.cyan(cwd)}.`));
|
|
4310
|
+
console.log(chalk13.gray("Agdi writes files and runs commands. It needs its own space.\n"));
|
|
4311
|
+
const action = await select3({
|
|
4312
|
+
message: "What would you like to do?",
|
|
4313
|
+
choices: [
|
|
4314
|
+
{ name: "\u{1F4C2} Create a new project folder (Recommended)", value: "create" },
|
|
4315
|
+
{ name: "\u{1F525} Run here anyway (Dangerous)", value: "unsafe" },
|
|
4316
|
+
{ name: "\u274C Cancel", value: "cancel" }
|
|
4317
|
+
]
|
|
4318
|
+
});
|
|
4319
|
+
if (action === "cancel") {
|
|
4320
|
+
ui.safeExit(0);
|
|
4321
|
+
}
|
|
4322
|
+
if (action === "create") {
|
|
4323
|
+
const folderName = await input5({
|
|
4324
|
+
message: "Project name:",
|
|
4325
|
+
default: "my-agdi-app",
|
|
4326
|
+
validate: (v) => /^[a-z0-9-_]+$/i.test(v) ? true : "Invalid folder name"
|
|
4327
|
+
});
|
|
4328
|
+
const newPath = path6.join(cwd, folderName);
|
|
4329
|
+
if (!fs6.existsSync(newPath)) {
|
|
4330
|
+
fs6.mkdirSync(newPath);
|
|
4331
|
+
}
|
|
4332
|
+
process.chdir(newPath);
|
|
4333
|
+
console.log(chalk13.green(`
|
|
4334
|
+
\u{1F4C2} Switched to: ${chalk13.cyan(newPath)}
|
|
4335
|
+
`));
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
async function setupOptionalTools() {
|
|
4340
|
+
const config = loadConfig();
|
|
4341
|
+
let configChanged = false;
|
|
4342
|
+
if (!config.searchApiKey) {
|
|
4343
|
+
console.log(chalk13.white.bold("\n\u{1F310} Web Access (Optional)\n"));
|
|
4344
|
+
console.log(chalk13.gray("Giving Agdi web access allows it to find up-to-date docs and fix tricky bugs."));
|
|
4345
|
+
const wantsSearch = await confirm({
|
|
4346
|
+
message: "Enable web search capabilities?",
|
|
4347
|
+
default: true
|
|
4348
|
+
});
|
|
4349
|
+
if (wantsSearch) {
|
|
4350
|
+
const provider = await select3({
|
|
4351
|
+
message: "Select Search Provider:",
|
|
4352
|
+
choices: [
|
|
4353
|
+
{ name: "Brave Search (Recommended)", value: "brave" },
|
|
4354
|
+
{ name: "Tavily", value: "tavily" }
|
|
4355
|
+
]
|
|
4356
|
+
});
|
|
4357
|
+
const keyUrl = provider === "brave" ? "https://brave.com/search/api/" : "https://tavily.com/";
|
|
4358
|
+
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4359
|
+
`));
|
|
4360
|
+
const apiKey = await password3({
|
|
4361
|
+
message: `Enter your ${provider} API key:`,
|
|
4362
|
+
mask: "*"
|
|
4363
|
+
});
|
|
4364
|
+
if (apiKey) {
|
|
4365
|
+
config.searchApiKey = apiKey;
|
|
4366
|
+
config.searchProvider = provider;
|
|
4367
|
+
config.searchEnabled = true;
|
|
4368
|
+
configChanged = true;
|
|
4369
|
+
console.log(chalk13.green("\u2705 Web search enabled!"));
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
if (!config.vercelToken && !config.netlifyToken && !config.railwayToken) {
|
|
4374
|
+
console.log(chalk13.white.bold("\n\u{1F680} Deployment (Optional)\n"));
|
|
4375
|
+
console.log(chalk13.gray("Agdi can automatically deploy your app to the cloud when finished."));
|
|
4376
|
+
const wantsDeploy = await confirm({
|
|
4377
|
+
message: "Enable auto-deployment?",
|
|
4378
|
+
default: true
|
|
4379
|
+
});
|
|
4380
|
+
if (wantsDeploy) {
|
|
4381
|
+
const provider = await select3({
|
|
4382
|
+
message: "Select Deployment Target:",
|
|
4383
|
+
choices: [
|
|
4384
|
+
{ name: "Vercel", value: "vercel" },
|
|
4385
|
+
{ name: "Railway", value: "railway" },
|
|
4386
|
+
{ name: "Netlify", value: "netlify" }
|
|
4387
|
+
]
|
|
4388
|
+
});
|
|
4389
|
+
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";
|
|
4390
|
+
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4391
|
+
`));
|
|
4392
|
+
const apiKey = await password3({
|
|
4393
|
+
message: `Enter your ${provider} API token:`,
|
|
4394
|
+
mask: "*"
|
|
4395
|
+
});
|
|
4396
|
+
if (apiKey) {
|
|
4397
|
+
if (provider === "vercel") config.vercelToken = apiKey;
|
|
4398
|
+
if (provider === "netlify") config.netlifyToken = apiKey;
|
|
4399
|
+
if (provider === "railway") config.railwayToken = apiKey;
|
|
4400
|
+
config.deploymentProvider = provider;
|
|
4401
|
+
configChanged = true;
|
|
4402
|
+
console.log(chalk13.green("\u2705 Auto-deployment enabled!"));
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
if (configChanged) {
|
|
4407
|
+
saveConfig(config);
|
|
4408
|
+
}
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
// src/commands/replay.ts
|
|
4412
|
+
import chalk14 from "chalk";
|
|
4413
|
+
import * as fs7 from "fs/promises";
|
|
4414
|
+
import * as path7 from "path";
|
|
4189
4415
|
async function runReplayCommand(runId, llm, options = {}) {
|
|
4190
4416
|
const workspaceRoot = options.workspace || process.cwd();
|
|
4191
|
-
const runConfigPath =
|
|
4192
|
-
const outputsDir =
|
|
4417
|
+
const runConfigPath = path7.join(workspaceRoot, "runs", runId, "run.json");
|
|
4418
|
+
const outputsDir = path7.join(workspaceRoot, "runs", runId, "outputs");
|
|
4193
4419
|
try {
|
|
4194
|
-
const raw = await
|
|
4420
|
+
const raw = await fs7.readFile(runConfigPath, "utf-8");
|
|
4195
4421
|
const runConfig = JSON.parse(raw);
|
|
4196
4422
|
if (!runConfig.prompt) {
|
|
4197
|
-
console.log(
|
|
4423
|
+
console.log(chalk14.red("\u274C Invalid run.json (missing prompt)"));
|
|
4198
4424
|
return null;
|
|
4199
4425
|
}
|
|
4200
4426
|
const config = {
|
|
@@ -4203,31 +4429,31 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4203
4429
|
verbose: options.verbose ?? runConfig.config?.verbose ?? true,
|
|
4204
4430
|
autoDeploy: options.deploy ?? runConfig.config?.autoDeploy ?? false
|
|
4205
4431
|
};
|
|
4206
|
-
console.log(
|
|
4432
|
+
console.log(chalk14.cyan(`
|
|
4207
4433
|
\u{1F501} Replaying run ${runId}`));
|
|
4208
4434
|
if (options.exact !== false) {
|
|
4209
4435
|
try {
|
|
4210
|
-
const entries = await
|
|
4436
|
+
const entries = await fs7.readdir(outputsDir, { withFileTypes: true });
|
|
4211
4437
|
if (entries.length === 0) {
|
|
4212
4438
|
throw new Error("No outputs found");
|
|
4213
4439
|
}
|
|
4214
4440
|
const copyOutputs = async (dir, rel = "") => {
|
|
4215
|
-
const files = await
|
|
4441
|
+
const files = await fs7.readdir(dir, { withFileTypes: true });
|
|
4216
4442
|
for (const file of files) {
|
|
4217
|
-
const sourcePath =
|
|
4218
|
-
const targetRel =
|
|
4219
|
-
const targetPath =
|
|
4443
|
+
const sourcePath = path7.join(dir, file.name);
|
|
4444
|
+
const targetRel = path7.join(rel, file.name);
|
|
4445
|
+
const targetPath = path7.join(workspaceRoot, targetRel);
|
|
4220
4446
|
if (file.isDirectory()) {
|
|
4221
4447
|
await copyOutputs(sourcePath, targetRel);
|
|
4222
4448
|
} else if (file.isFile()) {
|
|
4223
|
-
await
|
|
4224
|
-
const content = await
|
|
4225
|
-
await
|
|
4449
|
+
await fs7.mkdir(path7.dirname(targetPath), { recursive: true });
|
|
4450
|
+
const content = await fs7.readFile(sourcePath, "utf-8");
|
|
4451
|
+
await fs7.writeFile(targetPath, content, "utf-8");
|
|
4226
4452
|
}
|
|
4227
4453
|
}
|
|
4228
4454
|
};
|
|
4229
4455
|
await copyOutputs(outputsDir);
|
|
4230
|
-
console.log(
|
|
4456
|
+
console.log(chalk14.green("\u2705 Exact replay applied from stored outputs."));
|
|
4231
4457
|
return {
|
|
4232
4458
|
success: true,
|
|
4233
4459
|
projectSpec: { name: "replay", description: "Exact replay", type: "web-app", stack: {}, features: [] },
|
|
@@ -4238,255 +4464,34 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4238
4464
|
errors: []
|
|
4239
4465
|
};
|
|
4240
4466
|
} catch (error) {
|
|
4241
|
-
console.log(
|
|
4242
|
-
console.log(
|
|
4467
|
+
console.log(chalk14.yellow("\u26A0\uFE0F Exact replay failed, falling back to rerun."));
|
|
4468
|
+
console.log(chalk14.gray(String(error)));
|
|
4243
4469
|
}
|
|
4244
4470
|
}
|
|
4245
4471
|
if (!llm) {
|
|
4246
|
-
console.log(
|
|
4472
|
+
console.log(chalk14.red("\u274C No LLM provider available for replay."));
|
|
4247
4473
|
return null;
|
|
4248
4474
|
}
|
|
4249
4475
|
const orchestrator = new SquadOrchestrator(llm, config);
|
|
4250
4476
|
return await orchestrator.run(runConfig.prompt);
|
|
4251
4477
|
} catch (error) {
|
|
4252
|
-
console.log(
|
|
4253
|
-
console.log(
|
|
4478
|
+
console.log(chalk14.red("\u274C Failed to load run config for replay"));
|
|
4479
|
+
console.log(chalk14.gray(String(error)));
|
|
4254
4480
|
return null;
|
|
4255
4481
|
}
|
|
4256
4482
|
}
|
|
4257
4483
|
|
|
4258
|
-
// src/commands/tui-entry.tsx
|
|
4259
|
-
import { render } from "ink";
|
|
4260
|
-
|
|
4261
|
-
// src/ui/tui.tsx
|
|
4262
|
-
import { useState, useEffect } from "react";
|
|
4263
|
-
import { Box, Text, useApp } from "ink";
|
|
4264
|
-
import TextInput from "ink-text-input";
|
|
4265
|
-
import fs7 from "fs";
|
|
4266
|
-
import path7 from "path";
|
|
4267
|
-
import os from "os";
|
|
4268
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4269
|
-
var THEME2 = {
|
|
4270
|
-
bg: "black",
|
|
4271
|
-
border: "gray",
|
|
4272
|
-
accent: "blue",
|
|
4273
|
-
text: "white",
|
|
4274
|
-
dim: "gray",
|
|
4275
|
-
success: "green"
|
|
4276
|
-
};
|
|
4277
|
-
var BootScreen = ({ onComplete }) => {
|
|
4278
|
-
const [progress, setProgress] = useState(0);
|
|
4279
|
-
useEffect(() => {
|
|
4280
|
-
const timer = setInterval(() => {
|
|
4281
|
-
setProgress((prev) => {
|
|
4282
|
-
const next = prev + 10;
|
|
4283
|
-
if (next >= 100) {
|
|
4284
|
-
clearInterval(timer);
|
|
4285
|
-
setTimeout(onComplete, 100);
|
|
4286
|
-
return 100;
|
|
4287
|
-
}
|
|
4288
|
-
return next;
|
|
4289
|
-
});
|
|
4290
|
-
}, 20);
|
|
4291
|
-
return () => clearInterval(timer);
|
|
4292
|
-
}, []);
|
|
4293
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 15, children: [
|
|
4294
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.accent, bold: true, children: "Initializing Agdi Workspace..." }),
|
|
4295
|
-
/* @__PURE__ */ jsxs(Text, { color: THEME2.dim, children: [
|
|
4296
|
-
"\u2588",
|
|
4297
|
-
"\u2588".repeat(progress / 5)
|
|
4298
|
-
] })
|
|
4299
|
-
] });
|
|
4300
|
-
};
|
|
4301
|
-
var Sidebar = ({ history }) => {
|
|
4302
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 25, borderStyle: "single", borderColor: THEME2.border, paddingX: 1, children: [
|
|
4303
|
-
/* @__PURE__ */ jsx(Box, { marginBottom: 1, borderStyle: "single", borderColor: THEME2.accent, justifyContent: "center", children: /* @__PURE__ */ jsx(Text, { bold: true, children: "+ New task" }) }),
|
|
4304
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.dim, bold: true, children: "RECENTS" }),
|
|
4305
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", marginTop: 0, children: history.length === 0 ? /* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: "No recent sessions" }) : history.map((h, i) => /* @__PURE__ */ jsx(Text, { color: THEME2.text, children: h }, i)) })
|
|
4306
|
-
] });
|
|
4307
|
-
};
|
|
4308
|
-
var ContextPanel = ({ files, agentStatus }) => {
|
|
4309
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", width: 30, borderStyle: "single", borderColor: THEME2.border, paddingX: 1, children: [
|
|
4310
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
4311
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Context" }),
|
|
4312
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: "WORKING FILES" }),
|
|
4313
|
-
files.length === 0 ? /* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: "None yet." }) : files.slice(0, 5).map((f, i) => /* @__PURE__ */ jsxs(Text, { color: THEME2.accent, children: [
|
|
4314
|
-
"\u{1F4C4} ",
|
|
4315
|
-
f
|
|
4316
|
-
] }, i))
|
|
4317
|
-
] }),
|
|
4318
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, borderStyle: "single", borderColor: THEME2.dim, padding: 0, children: [
|
|
4319
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: " Plugins" }),
|
|
4320
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.success, children: "\u2022 Scheduler" }),
|
|
4321
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: " Run scheduled jobs" })
|
|
4322
|
-
] }),
|
|
4323
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
|
|
4324
|
-
/* @__PURE__ */ jsx(Text, { bold: true, children: "Status" }),
|
|
4325
|
-
/* @__PURE__ */ jsxs(Text, { color: agentStatus === "IDLE" ? THEME2.dim : THEME2.success, children: [
|
|
4326
|
-
"\u2022 ",
|
|
4327
|
-
agentStatus
|
|
4328
|
-
] })
|
|
4329
|
-
] })
|
|
4330
|
-
] });
|
|
4331
|
-
};
|
|
4332
|
-
var ChatArea = ({ history, onSend, placeholder }) => {
|
|
4333
|
-
const [query, setQuery] = useState("");
|
|
4334
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", flexGrow: 1, borderStyle: "single", borderColor: THEME2.border, marginLeft: 0, marginRight: 0, children: [
|
|
4335
|
-
/* @__PURE__ */ jsx(Box, { justifyContent: "center", borderStyle: "single", borderBottomColor: THEME2.border, borderTop: false, borderLeft: false, borderRight: false, paddingBottom: 0, children: /* @__PURE__ */ jsx(Text, { bold: true, children: "Start a conversation" }) }),
|
|
4336
|
-
/* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, padding: 1, justifyContent: "flex-end", children: history.length === 0 ? /* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 10, children: [
|
|
4337
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: "Describe what you want to do," }),
|
|
4338
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.dim, children: "and Agdi will take it from there." })
|
|
4339
|
-
] }) : history.slice(-8).map((msg, i) => /* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [
|
|
4340
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: msg.role === "user" ? THEME2.text : THEME2.accent, children: msg.role === "user" ? "You" : "Agdi" }),
|
|
4341
|
-
/* @__PURE__ */ jsx(Text, { color: THEME2.text, children: msg.text })
|
|
4342
|
-
] }, i)) }),
|
|
4343
|
-
/* @__PURE__ */ jsx(Box, { borderStyle: "round", borderColor: THEME2.dim, paddingX: 1, marginX: 1, marginBottom: 1, children: /* @__PURE__ */ jsx(
|
|
4344
|
-
TextInput,
|
|
4345
|
-
{
|
|
4346
|
-
value: query,
|
|
4347
|
-
onChange: setQuery,
|
|
4348
|
-
onSubmit: (val) => {
|
|
4349
|
-
onSend(val);
|
|
4350
|
-
setQuery("");
|
|
4351
|
-
},
|
|
4352
|
-
placeholder
|
|
4353
|
-
}
|
|
4354
|
-
) })
|
|
4355
|
-
] });
|
|
4356
|
-
};
|
|
4357
|
-
var Dashboard = () => {
|
|
4358
|
-
const { exit } = useApp();
|
|
4359
|
-
const [cwd, setCwd] = useState(process.cwd());
|
|
4360
|
-
const [chatHistory, setChatHistory] = useState([]);
|
|
4361
|
-
const [step, setStep] = useState("safety");
|
|
4362
|
-
const [pendingAction, setPendingAction] = useState(null);
|
|
4363
|
-
const [activeFiles, setActiveFiles] = useState([]);
|
|
4364
|
-
const [agentStatus, setAgentStatus] = useState("IDLE");
|
|
4365
|
-
useEffect(() => {
|
|
4366
|
-
const handleEvent = (event) => {
|
|
4367
|
-
if (event.type === "handoff") {
|
|
4368
|
-
setAgentStatus(event.role.toUpperCase());
|
|
4369
|
-
}
|
|
4370
|
-
if (event.type === "thought") {
|
|
4371
|
-
if (!event.message.startsWith("Analyzing")) {
|
|
4372
|
-
setChatHistory((prev) => [...prev, { role: "system", text: `[${event.agentName}] ${event.message}` }]);
|
|
4373
|
-
}
|
|
4374
|
-
}
|
|
4375
|
-
if (event.message.includes("Created:")) {
|
|
4376
|
-
const filename = event.message.split("Created:")[1].trim();
|
|
4377
|
-
setActiveFiles((prev) => [filename, ...prev].slice(0, 5));
|
|
4378
|
-
}
|
|
4379
|
-
};
|
|
4380
|
-
agentEventBus.on("agent_event", handleEvent);
|
|
4381
|
-
return () => {
|
|
4382
|
-
agentEventBus.off("agent_event", handleEvent);
|
|
4383
|
-
};
|
|
4384
|
-
}, []);
|
|
4385
|
-
useEffect(() => {
|
|
4386
|
-
if (step === "safety") {
|
|
4387
|
-
const home = os.homedir();
|
|
4388
|
-
const root = path7.parse(cwd).root;
|
|
4389
|
-
const isUnsafe = cwd === home || cwd === root;
|
|
4390
|
-
if (isUnsafe) {
|
|
4391
|
-
setChatHistory([
|
|
4392
|
-
{ role: "system", text: `\u26A0\uFE0F Safety Check: Running in ${cwd}` },
|
|
4393
|
-
{ role: "ai", text: "This directory is too broad. Should I create a new project folder? (yes/no)" }
|
|
4394
|
-
]);
|
|
4395
|
-
setPendingAction("safety_confirm");
|
|
4396
|
-
} else {
|
|
4397
|
-
setStep("prompt");
|
|
4398
|
-
}
|
|
4399
|
-
}
|
|
4400
|
-
}, []);
|
|
4401
|
-
const handleCommand = async (cmd) => {
|
|
4402
|
-
if (cmd === "/exit") exit();
|
|
4403
|
-
setChatHistory((prev) => [...prev, { role: "user", text: cmd }]);
|
|
4404
|
-
if (step === "safety" && pendingAction === "safety_confirm") {
|
|
4405
|
-
if (cmd.toLowerCase().startsWith("y")) {
|
|
4406
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "Name your project:" }]);
|
|
4407
|
-
setPendingAction("create_folder");
|
|
4408
|
-
} else {
|
|
4409
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "Proceeding in current directory." }]);
|
|
4410
|
-
setStep("prompt");
|
|
4411
|
-
setPendingAction(null);
|
|
4412
|
-
}
|
|
4413
|
-
return;
|
|
4414
|
-
}
|
|
4415
|
-
if (step === "safety" && pendingAction === "create_folder") {
|
|
4416
|
-
const newPath = path7.join(cwd, cmd.replace(/[^a-z0-9-_]/gi, "-"));
|
|
4417
|
-
try {
|
|
4418
|
-
if (!fs7.existsSync(newPath)) fs7.mkdirSync(newPath);
|
|
4419
|
-
process.chdir(newPath);
|
|
4420
|
-
setCwd(newPath);
|
|
4421
|
-
setChatHistory((prev) => [...prev, { role: "system", text: `\u{1F4C2} Switched to ${newPath}` }]);
|
|
4422
|
-
setStep("prompt");
|
|
4423
|
-
setPendingAction(null);
|
|
4424
|
-
} catch (e) {
|
|
4425
|
-
setChatHistory((prev) => [...prev, { role: "system", text: `Error: ${e}` }]);
|
|
4426
|
-
}
|
|
4427
|
-
return;
|
|
4428
|
-
}
|
|
4429
|
-
if (step === "prompt") {
|
|
4430
|
-
setStep("active");
|
|
4431
|
-
setAgentStatus("MANAGER");
|
|
4432
|
-
const activeConfig = getActiveProvider();
|
|
4433
|
-
if (!activeConfig) {
|
|
4434
|
-
setChatHistory((prev) => [...prev, { role: "system", text: '\u274C No API key found. Run "agdi auth" first.' }]);
|
|
4435
|
-
return;
|
|
4436
|
-
}
|
|
4437
|
-
const llm = createLLMProvider(activeConfig.provider, {
|
|
4438
|
-
apiKey: activeConfig.apiKey,
|
|
4439
|
-
model: activeConfig.model
|
|
4440
|
-
});
|
|
4441
|
-
runSquadCommand(cmd, llm, {
|
|
4442
|
-
output: cwd,
|
|
4443
|
-
verbose: false,
|
|
4444
|
-
deploy: false
|
|
4445
|
-
}).then(() => {
|
|
4446
|
-
setAgentStatus("IDLE");
|
|
4447
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "Task completed." }]);
|
|
4448
|
-
}).catch((err) => {
|
|
4449
|
-
setAgentStatus("ERROR");
|
|
4450
|
-
setChatHistory((prev) => [...prev, { role: "system", text: `Error: ${err.message}` }]);
|
|
4451
|
-
});
|
|
4452
|
-
}
|
|
4453
|
-
};
|
|
4454
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "row", height: 30, padding: 1, children: [
|
|
4455
|
-
/* @__PURE__ */ jsx(Sidebar, { history: ["New session - " + (/* @__PURE__ */ new Date()).toLocaleDateString()] }),
|
|
4456
|
-
/* @__PURE__ */ jsx(
|
|
4457
|
-
ChatArea,
|
|
4458
|
-
{
|
|
4459
|
-
history: chatHistory,
|
|
4460
|
-
onSend: handleCommand,
|
|
4461
|
-
placeholder: step === "prompt" ? "Ask Agdi..." : "Reply..."
|
|
4462
|
-
}
|
|
4463
|
-
),
|
|
4464
|
-
/* @__PURE__ */ jsx(ContextPanel, { files: activeFiles, agentStatus })
|
|
4465
|
-
] });
|
|
4466
|
-
};
|
|
4467
|
-
var App = () => {
|
|
4468
|
-
const [screen, setScreen] = useState("boot");
|
|
4469
|
-
return screen === "boot" ? /* @__PURE__ */ jsx(BootScreen, { onComplete: () => setScreen("dashboard") }) : /* @__PURE__ */ jsx(Dashboard, {});
|
|
4470
|
-
};
|
|
4471
|
-
|
|
4472
|
-
// src/commands/tui-entry.tsx
|
|
4473
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4474
|
-
function runTUI() {
|
|
4475
|
-
console.clear();
|
|
4476
|
-
render(/* @__PURE__ */ jsx2(App, {}));
|
|
4477
|
-
}
|
|
4478
|
-
|
|
4479
4484
|
// src/index.ts
|
|
4480
4485
|
var BANNER = `
|
|
4481
|
-
${
|
|
4482
|
-
${
|
|
4483
|
-
${
|
|
4484
|
-
${
|
|
4485
|
-
${
|
|
4486
|
-
${
|
|
4486
|
+
${chalk15.cyan(` ___ __ _ `)}
|
|
4487
|
+
${chalk15.cyan(` / | ____ _____/ /(_) `)}
|
|
4488
|
+
${chalk15.cyan(` / /| | / __ \`/ __ // / `)}
|
|
4489
|
+
${chalk15.cyan(` / ___ |/ /_/ / /_/ // / `)}
|
|
4490
|
+
${chalk15.cyan(`/_/ |_|\\_, /\\__,_//_/ `)}
|
|
4491
|
+
${chalk15.cyan(` /____/ `)}
|
|
4487
4492
|
`;
|
|
4488
4493
|
var program = new Command();
|
|
4489
|
-
program.name("agdi").description(
|
|
4494
|
+
program.name("agdi").description(chalk15.cyan("\u{1F9B8} The Autonomous AI Employee")).version("3.3.5").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)");
|
|
4490
4495
|
program.hook("preAction", (thisCommand) => {
|
|
4491
4496
|
const opts = thisCommand.opts();
|
|
4492
4497
|
if (opts.yes) {
|
|
@@ -4503,14 +4508,14 @@ program.hook("preAction", (thisCommand) => {
|
|
|
4503
4508
|
}
|
|
4504
4509
|
});
|
|
4505
4510
|
program.addHelpText("beforeAll", () => {
|
|
4506
|
-
return BANNER + "\n" +
|
|
4511
|
+
return BANNER + "\n" + chalk15.gray(" The Autonomous AI Employee") + "\n" + chalk15.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");
|
|
4507
4512
|
});
|
|
4508
4513
|
program.action(async () => {
|
|
4509
4514
|
try {
|
|
4510
|
-
|
|
4515
|
+
await runWizard();
|
|
4511
4516
|
} catch (error) {
|
|
4512
4517
|
if (error.name === "ExitPromptError") {
|
|
4513
|
-
console.log(
|
|
4518
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4514
4519
|
try {
|
|
4515
4520
|
ui.safeExit(0);
|
|
4516
4521
|
} catch {
|
|
@@ -4532,7 +4537,7 @@ program.command("auth").description("Configure API keys").option("--status", "Sh
|
|
|
4532
4537
|
}
|
|
4533
4538
|
} catch (error) {
|
|
4534
4539
|
if (error.name === "ExitPromptError") {
|
|
4535
|
-
console.log(
|
|
4540
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4536
4541
|
try {
|
|
4537
4542
|
ui.safeExit(0);
|
|
4538
4543
|
} catch {
|
|
@@ -4550,7 +4555,7 @@ program.command("model").alias("models").description("Change AI model").action(a
|
|
|
4550
4555
|
await selectModel();
|
|
4551
4556
|
} catch (error) {
|
|
4552
4557
|
if (error.name === "ExitPromptError") {
|
|
4553
|
-
console.log(
|
|
4558
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4554
4559
|
try {
|
|
4555
4560
|
ui.safeExit(0);
|
|
4556
4561
|
} catch {
|
|
@@ -4571,7 +4576,7 @@ program.command("chat").description("Start a chat session").action(async () => {
|
|
|
4571
4576
|
await startChat();
|
|
4572
4577
|
} catch (error) {
|
|
4573
4578
|
if (error.name === "ExitPromptError") {
|
|
4574
|
-
console.log(
|
|
4579
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4575
4580
|
try {
|
|
4576
4581
|
ui.safeExit(0);
|
|
4577
4582
|
} catch {
|
|
@@ -4589,7 +4594,7 @@ program.command("run [directory]").description("Run a generated project").action
|
|
|
4589
4594
|
await runProject(directory);
|
|
4590
4595
|
} catch (error) {
|
|
4591
4596
|
if (error.name === "ExitPromptError") {
|
|
4592
|
-
console.log(
|
|
4597
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4593
4598
|
try {
|
|
4594
4599
|
ui.safeExit(0);
|
|
4595
4600
|
} catch {
|
|
@@ -4612,7 +4617,7 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4612
4617
|
}
|
|
4613
4618
|
const activeConfig = getActiveProvider();
|
|
4614
4619
|
if (!activeConfig) {
|
|
4615
|
-
console.log(
|
|
4620
|
+
console.log(chalk15.red("\u274C No API key configured. Run: agdi auth"));
|
|
4616
4621
|
return;
|
|
4617
4622
|
}
|
|
4618
4623
|
const spinner = ora6("Generating application...").start();
|
|
@@ -4624,52 +4629,52 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4624
4629
|
const pm = new ProjectManager();
|
|
4625
4630
|
pm.create(options.output.replace("./", ""), prompt);
|
|
4626
4631
|
const { plan, files } = await generateApp(prompt, llm, (step, file) => {
|
|
4627
|
-
spinner.text = file ? `${step} ${
|
|
4632
|
+
spinner.text = file ? `${step} ${chalk15.gray(file)}` : step;
|
|
4628
4633
|
});
|
|
4629
4634
|
pm.updateFiles(files);
|
|
4630
4635
|
pm.updateDependencies(plan.dependencies);
|
|
4631
4636
|
if (options.dryRun || ui.flags.dryRun) {
|
|
4632
4637
|
spinner.stop();
|
|
4633
|
-
console.log(
|
|
4634
|
-
console.log(
|
|
4638
|
+
console.log(chalk15.cyan.bold("\n\u{1F6A7} DRY RUN SUMMARY\n"));
|
|
4639
|
+
console.log(chalk15.gray(`Project: ${plan.name}
|
|
4635
4640
|
`));
|
|
4636
|
-
console.log(
|
|
4637
|
-
files.forEach((f) => console.log(
|
|
4638
|
-
console.log(
|
|
4639
|
-
console.log(
|
|
4640
|
-
console.log(
|
|
4641
|
+
console.log(chalk15.cyan("Files to be created:"));
|
|
4642
|
+
files.forEach((f) => console.log(chalk15.gray(` \u{1F4C4} ${f.path}`)));
|
|
4643
|
+
console.log(chalk15.cyan("\nDependencies:"));
|
|
4644
|
+
console.log(chalk15.gray(` \u{1F4E6} ${plan.dependencies.join(", ")}`));
|
|
4645
|
+
console.log(chalk15.green("\n\u2713 Dry run complete. No files written.\n"));
|
|
4641
4646
|
return;
|
|
4642
4647
|
}
|
|
4643
4648
|
await writeProject(pm.get(), options.output);
|
|
4644
|
-
spinner.succeed(
|
|
4645
|
-
console.log(
|
|
4646
|
-
\u{1F4C1} Created ${files.length} files in ${
|
|
4649
|
+
spinner.succeed(chalk15.green("App generated!"));
|
|
4650
|
+
console.log(chalk15.gray(`
|
|
4651
|
+
\u{1F4C1} Created ${files.length} files in ${chalk15.cyan(options.output)}`));
|
|
4647
4652
|
if (ui.flags.saas || options.saas) {
|
|
4648
|
-
console.log(
|
|
4649
|
-
console.log(
|
|
4650
|
-
console.log(
|
|
4651
|
-
console.log(
|
|
4652
|
-
console.log(
|
|
4653
|
-
console.log(
|
|
4654
|
-
console.log(
|
|
4653
|
+
console.log(chalk15.cyan("\nSaaS Quick Start:"));
|
|
4654
|
+
console.log(chalk15.gray(` 1) cd ${options.output}`));
|
|
4655
|
+
console.log(chalk15.gray(" 2) npm install"));
|
|
4656
|
+
console.log(chalk15.gray(" 3) cp .env.example .env"));
|
|
4657
|
+
console.log(chalk15.gray(" 4) npx prisma generate"));
|
|
4658
|
+
console.log(chalk15.gray(" 5) npx prisma db push"));
|
|
4659
|
+
console.log(chalk15.gray(" 6) npm run dev\n"));
|
|
4655
4660
|
} else {
|
|
4656
|
-
console.log(
|
|
4661
|
+
console.log(chalk15.gray("\nNext: cd " + options.output + " && npm install && npm run dev\n"));
|
|
4657
4662
|
}
|
|
4658
4663
|
} catch (error) {
|
|
4659
4664
|
spinner.fail("Generation failed");
|
|
4660
4665
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4661
4666
|
if (msg.includes("429") || msg.includes("quota")) {
|
|
4662
|
-
console.log(
|
|
4667
|
+
console.log(chalk15.yellow("\n\u26A0\uFE0F Quota exceeded. Run: agdi model\n"));
|
|
4663
4668
|
} else if (msg.includes("401") || msg.includes("403")) {
|
|
4664
|
-
console.log(
|
|
4669
|
+
console.log(chalk15.red("\n\u{1F511} Invalid API key. Run: agdi auth\n"));
|
|
4665
4670
|
} else {
|
|
4666
|
-
console.error(
|
|
4671
|
+
console.error(chalk15.red("\n" + msg + "\n"));
|
|
4667
4672
|
}
|
|
4668
4673
|
ui.safeExit(1);
|
|
4669
4674
|
}
|
|
4670
4675
|
} catch (error) {
|
|
4671
4676
|
if (error.name === "ExitPromptError") {
|
|
4672
|
-
console.log(
|
|
4677
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4673
4678
|
try {
|
|
4674
4679
|
ui.safeExit(0);
|
|
4675
4680
|
} catch {
|
|
@@ -4685,11 +4690,11 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4685
4690
|
program.command("config").description("Show configuration").action(async () => {
|
|
4686
4691
|
const config = loadConfig();
|
|
4687
4692
|
const active = getActiveProvider();
|
|
4688
|
-
console.log(
|
|
4689
|
-
console.log(
|
|
4690
|
-
console.log(
|
|
4691
|
-
console.log(
|
|
4692
|
-
console.log(
|
|
4693
|
+
console.log(chalk15.cyan.bold("\n\u2699\uFE0F Configuration\n"));
|
|
4694
|
+
console.log(chalk15.gray(" Provider: ") + chalk15.cyan(config.defaultProvider || "not set"));
|
|
4695
|
+
console.log(chalk15.gray(" Model: ") + chalk15.cyan(config.defaultModel || "not set"));
|
|
4696
|
+
console.log(chalk15.gray(" Config: ") + chalk15.gray("~/.agdi/config.json"));
|
|
4697
|
+
console.log(chalk15.cyan.bold("\n\u{1F510} API Keys\n"));
|
|
4693
4698
|
const keys = [
|
|
4694
4699
|
["Gemini", config.geminiApiKey],
|
|
4695
4700
|
["OpenRouter", config.openrouterApiKey],
|
|
@@ -4698,13 +4703,13 @@ program.command("config").description("Show configuration").action(async () => {
|
|
|
4698
4703
|
["DeepSeek", config.deepseekApiKey]
|
|
4699
4704
|
];
|
|
4700
4705
|
for (const [name, key] of keys) {
|
|
4701
|
-
const status = key ?
|
|
4706
|
+
const status = key ? chalk15.green("\u2713") : chalk15.gray("\u2717");
|
|
4702
4707
|
console.log(` ${status} ${name}`);
|
|
4703
4708
|
}
|
|
4704
|
-
console.log(
|
|
4709
|
+
console.log(chalk15.cyan.bold("\n\u{1F4CA} Telemetry\n"));
|
|
4705
4710
|
const telemetryEnabled = config.telemetry?.enabled ?? false;
|
|
4706
|
-
console.log(` ${telemetryEnabled ?
|
|
4707
|
-
console.log(
|
|
4711
|
+
console.log(` ${telemetryEnabled ? chalk15.green("\u2713 Enabled") : chalk15.gray("\u2717 Disabled")}`);
|
|
4712
|
+
console.log(chalk15.gray(" Change with: agdi config telemetry --enable | --disable"));
|
|
4708
4713
|
console.log("");
|
|
4709
4714
|
console.log("");
|
|
4710
4715
|
});
|
|
@@ -4712,59 +4717,59 @@ program.command("config:telemetry").alias("telemetry").description("Manage telem
|
|
|
4712
4717
|
const { isTelemetryEnabled, setTelemetryConsent, getTelemetryConfig } = await import("./config-ZFU7TSU2.js");
|
|
4713
4718
|
const { generateSampleEvent, generateSanitizationDemo } = await import("./telemetry-service-OHU5NKON.js");
|
|
4714
4719
|
if (options.dryRun || options.test) {
|
|
4715
|
-
console.log(
|
|
4716
|
-
console.log(
|
|
4717
|
-
console.log(
|
|
4718
|
-
console.log(
|
|
4720
|
+
console.log(chalk15.cyan.bold("\n\u{1F50D} TELEMETRY TRANSPARENCY MODE\n"));
|
|
4721
|
+
console.log(chalk15.gray("This is exactly what Agdi sends. Notice there is"));
|
|
4722
|
+
console.log(chalk15.green.bold("NO source code, file paths, or API keys.\n"));
|
|
4723
|
+
console.log(chalk15.white.bold('\u{1F4CA} Sample "Build Failed" Event:\n'));
|
|
4719
4724
|
const sample = generateSampleEvent();
|
|
4720
|
-
console.log(
|
|
4721
|
-
console.log(
|
|
4722
|
-
console.log(
|
|
4723
|
-
console.log(
|
|
4725
|
+
console.log(chalk15.gray(JSON.stringify(sample, null, 2)));
|
|
4726
|
+
console.log(chalk15.white.bold("\n\u{1F6E1}\uFE0F Sanitization Demo:\n"));
|
|
4727
|
+
console.log(chalk15.gray("Even if sensitive data accidentally enters an error message,"));
|
|
4728
|
+
console.log(chalk15.gray("our sanitization layer strips it before transmission:\n"));
|
|
4724
4729
|
const demo = generateSanitizationDemo();
|
|
4725
|
-
console.log(
|
|
4726
|
-
console.log(
|
|
4730
|
+
console.log(chalk15.red.bold("BEFORE sanitization (never sent):"));
|
|
4731
|
+
console.log(chalk15.gray(JSON.stringify({
|
|
4727
4732
|
errorCode: demo.before.errorCode,
|
|
4728
4733
|
feedback: demo.before.feedback
|
|
4729
4734
|
}, null, 2)));
|
|
4730
|
-
console.log(
|
|
4731
|
-
console.log(
|
|
4735
|
+
console.log(chalk15.green.bold("\nAFTER sanitization (what we actually send):"));
|
|
4736
|
+
console.log(chalk15.gray(JSON.stringify({
|
|
4732
4737
|
errorCode: demo.after.errorCode,
|
|
4733
4738
|
feedback: demo.after.feedback
|
|
4734
4739
|
}, null, 2)));
|
|
4735
|
-
console.log(
|
|
4736
|
-
console.log(
|
|
4740
|
+
console.log(chalk15.cyan("\n\u2705 Your code and secrets are NEVER transmitted."));
|
|
4741
|
+
console.log(chalk15.gray(" Learn more: https://agdi.dev/privacy\n"));
|
|
4737
4742
|
return;
|
|
4738
4743
|
}
|
|
4739
4744
|
if (options.enable) {
|
|
4740
4745
|
setTelemetryConsent(true);
|
|
4741
|
-
console.log(
|
|
4742
|
-
console.log(
|
|
4743
|
-
console.log(
|
|
4744
|
-
console.log(
|
|
4746
|
+
console.log(chalk15.green("\n\u2705 Telemetry enabled"));
|
|
4747
|
+
console.log(chalk15.gray(" We collect: success/fail, error types, model used"));
|
|
4748
|
+
console.log(chalk15.gray(" We NEVER collect: source code, API keys, file paths"));
|
|
4749
|
+
console.log(chalk15.gray(" Verify anytime: agdi config telemetry --dry-run\n"));
|
|
4745
4750
|
} else if (options.disable) {
|
|
4746
4751
|
setTelemetryConsent(false);
|
|
4747
|
-
console.log(
|
|
4748
|
-
console.log(
|
|
4752
|
+
console.log(chalk15.yellow("\n\u{1F4CA} Telemetry disabled"));
|
|
4753
|
+
console.log(chalk15.gray(" You can re-enable anytime with: agdi config telemetry --enable\n"));
|
|
4749
4754
|
} else {
|
|
4750
4755
|
const config = getTelemetryConfig();
|
|
4751
|
-
console.log(
|
|
4752
|
-
console.log(
|
|
4753
|
-
console.log(
|
|
4756
|
+
console.log(chalk15.cyan.bold("\n\u{1F4CA} Telemetry Status\n"));
|
|
4757
|
+
console.log(chalk15.gray(" Enabled: ") + (config.enabled ? chalk15.green("Yes") : chalk15.gray("No")));
|
|
4758
|
+
console.log(chalk15.gray(" Consent: ") + (config.consentAsked ? chalk15.green("Asked") : chalk15.gray("Not asked")));
|
|
4754
4759
|
if (config.anonymousId) {
|
|
4755
|
-
console.log(
|
|
4760
|
+
console.log(chalk15.gray(" ID: ") + chalk15.gray(config.anonymousId.slice(0, 8) + "..."));
|
|
4756
4761
|
}
|
|
4757
4762
|
console.log("");
|
|
4758
|
-
console.log(
|
|
4759
|
-
console.log(
|
|
4760
|
-
console.log(
|
|
4763
|
+
console.log(chalk15.gray(" Enable: agdi config telemetry --enable"));
|
|
4764
|
+
console.log(chalk15.gray(" Disable: agdi config telemetry --disable"));
|
|
4765
|
+
console.log(chalk15.gray(" Verify: agdi config telemetry --dry-run\n"));
|
|
4761
4766
|
}
|
|
4762
4767
|
});
|
|
4763
4768
|
program.command("doctor").alias("doc").description("Run self-diagnosis checks").action(async () => {
|
|
4764
4769
|
try {
|
|
4765
4770
|
await runDoctor();
|
|
4766
4771
|
} catch (error) {
|
|
4767
|
-
console.error(
|
|
4772
|
+
console.error(chalk15.red("Diagnostic failed: " + error));
|
|
4768
4773
|
ui.safeExit(1);
|
|
4769
4774
|
}
|
|
4770
4775
|
});
|
|
@@ -4775,7 +4780,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4775
4780
|
}
|
|
4776
4781
|
const activeConfig = getActiveProvider();
|
|
4777
4782
|
if (!activeConfig) {
|
|
4778
|
-
console.log(
|
|
4783
|
+
console.log(chalk15.red("\u274C No API key configured. Run: agdi auth"));
|
|
4779
4784
|
return;
|
|
4780
4785
|
}
|
|
4781
4786
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4789,7 +4794,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4789
4794
|
});
|
|
4790
4795
|
} catch (error) {
|
|
4791
4796
|
if (error.name === "ExitPromptError") {
|
|
4792
|
-
console.log(
|
|
4797
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4793
4798
|
try {
|
|
4794
4799
|
ui.safeExit(0);
|
|
4795
4800
|
} catch {
|
|
@@ -4817,7 +4822,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4817
4822
|
}
|
|
4818
4823
|
const activeConfig = getActiveProvider();
|
|
4819
4824
|
if (!activeConfig) {
|
|
4820
|
-
console.log(
|
|
4825
|
+
console.log(chalk15.red("\u274C No API key configured. Run: agdi auth"));
|
|
4821
4826
|
return;
|
|
4822
4827
|
}
|
|
4823
4828
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4831,7 +4836,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4831
4836
|
});
|
|
4832
4837
|
} catch (error) {
|
|
4833
4838
|
if (error.name === "ExitPromptError") {
|
|
4834
|
-
console.log(
|
|
4839
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4835
4840
|
try {
|
|
4836
4841
|
ui.safeExit(0);
|
|
4837
4842
|
} catch {
|
|
@@ -4849,7 +4854,7 @@ program.command("import <url>").alias("i").description("\u{1F4E6} Import a GitHu
|
|
|
4849
4854
|
await runImportCommand(url, options.output);
|
|
4850
4855
|
} catch (error) {
|
|
4851
4856
|
if (error.name === "ExitPromptError") {
|
|
4852
|
-
console.log(
|
|
4857
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4853
4858
|
try {
|
|
4854
4859
|
ui.safeExit(0);
|
|
4855
4860
|
} catch {
|
|
@@ -4859,4 +4864,15 @@ program.command("import <url>").alias("i").description("\u{1F4E6} Import a GitHu
|
|
|
4859
4864
|
throw error;
|
|
4860
4865
|
}
|
|
4861
4866
|
});
|
|
4867
|
+
program.command("wizard").alias("w").description("\u{1F9D9} Start the ClawBot Setup Wizard").action(async () => {
|
|
4868
|
+
try {
|
|
4869
|
+
await runWizard();
|
|
4870
|
+
} catch (error) {
|
|
4871
|
+
console.log(chalk15.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4872
|
+
try {
|
|
4873
|
+
ui.safeExit(0);
|
|
4874
|
+
} catch {
|
|
4875
|
+
}
|
|
4876
|
+
}
|
|
4877
|
+
});
|
|
4862
4878
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agdi",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.6",
|
|
4
4
|
"description": "AI-powered app generator - build full-stack apps from natural language in your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"README.md"
|
|
19
19
|
],
|
|
20
20
|
"scripts": {
|
|
21
|
-
"build": "tsup src/index.ts --format esm --clean",
|
|
21
|
+
"build": "npx tsup src/index.ts --format esm --clean",
|
|
22
22
|
"dev": "tsx src/index.ts",
|
|
23
23
|
"start": "tsx src/dev.ts",
|
|
24
24
|
"test": "vitest run",
|