agdi 3.1.2 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -64
- package/dist/index.js +385 -379
- package/package.json +13 -5
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
8
|
import { Command } from "commander";
|
|
9
|
-
import
|
|
9
|
+
import chalk14 from "chalk";
|
|
10
10
|
import ora6 from "ora";
|
|
11
11
|
|
|
12
12
|
// src/core/llm/index.ts
|
|
@@ -449,8 +449,8 @@ async function smartConfirm(message, defaultValue = false) {
|
|
|
449
449
|
console.warn(chalk.yellow("\u26A0\uFE0F Non-interactive session detected. Use --yes to approve actions."));
|
|
450
450
|
return false;
|
|
451
451
|
}
|
|
452
|
-
const { confirm
|
|
453
|
-
return
|
|
452
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
453
|
+
return confirm({ message, default: defaultValue });
|
|
454
454
|
}
|
|
455
455
|
async function smartSelect(message, choices, defaultValue) {
|
|
456
456
|
if (!process.stdout.isTTY || flags.headless) {
|
|
@@ -460,8 +460,8 @@ async function smartSelect(message, choices, defaultValue) {
|
|
|
460
460
|
}
|
|
461
461
|
return result || null;
|
|
462
462
|
}
|
|
463
|
-
const { select:
|
|
464
|
-
return
|
|
463
|
+
const { select: select3 } = await import("@inquirer/prompts");
|
|
464
|
+
return select3({ message, choices });
|
|
465
465
|
}
|
|
466
466
|
var ui = {
|
|
467
467
|
renderBanner,
|
|
@@ -1782,8 +1782,8 @@ async function runOnboarding() {
|
|
|
1782
1782
|
console.log(chalk7.gray("We collect anonymous error logs (like a ") + chalk7.yellow("'Check Engine'") + chalk7.gray(" light)"));
|
|
1783
1783
|
console.log(chalk7.gray("to fix bugs faster. We ") + chalk7.green.bold("never") + chalk7.gray(" see your code or keys.\n"));
|
|
1784
1784
|
console.log(chalk7.dim("Verify anytime: agdi config telemetry --dry-run\n"));
|
|
1785
|
-
const { confirm
|
|
1786
|
-
const enableTelemetry = await
|
|
1785
|
+
const { confirm } = await import("@inquirer/prompts");
|
|
1786
|
+
const enableTelemetry = await confirm({
|
|
1787
1787
|
message: "Enable crash reporting? (helps us fix bugs)",
|
|
1788
1788
|
default: false
|
|
1789
1789
|
});
|
|
@@ -2749,6 +2749,8 @@ Requirements:
|
|
|
2749
2749
|
// src/agents/core/qa-agent.ts
|
|
2750
2750
|
import { exec } from "child_process";
|
|
2751
2751
|
import { promisify } from "util";
|
|
2752
|
+
import * as fs3 from "fs/promises";
|
|
2753
|
+
import * as path3 from "path";
|
|
2752
2754
|
var execAsync = promisify(exec);
|
|
2753
2755
|
var QA_SYSTEM_PROMPT = `You are a SENIOR QA ENGINEER and DEBUGGER with expertise in:
|
|
2754
2756
|
- TypeScript/JavaScript debugging
|
|
@@ -2758,10 +2760,10 @@ var QA_SYSTEM_PROMPT = `You are a SENIOR QA ENGINEER and DEBUGGER with expertise
|
|
|
2758
2760
|
- ESLint / TypeScript errors
|
|
2759
2761
|
|
|
2760
2762
|
Your responsibilities:
|
|
2761
|
-
1.
|
|
2762
|
-
2.
|
|
2763
|
-
3.
|
|
2764
|
-
4.
|
|
2763
|
+
1. Analyze build/test errors
|
|
2764
|
+
2. Read the provided source code context
|
|
2765
|
+
3. Diagnose the root cause (e.g., missing prop, type mismatch, bad import)
|
|
2766
|
+
4. Generate SURGICAL fixes
|
|
2765
2767
|
|
|
2766
2768
|
When fixing errors, you MUST:
|
|
2767
2769
|
1. Quote the exact error message
|
|
@@ -2776,10 +2778,13 @@ import React from 'react';
|
|
|
2776
2778
|
// ... fixed code
|
|
2777
2779
|
\`\`\`
|
|
2778
2780
|
|
|
2779
|
-
|
|
2780
|
-
-
|
|
2781
|
+
IMPORTANT:
|
|
2782
|
+
- Do NOT generate "placeholder" fixes.
|
|
2783
|
+
- If an import is missing, make sure the file actually exists or fix the path.
|
|
2784
|
+
- If a type is missing, check where it is defined.
|
|
2781
2785
|
|
|
2782
|
-
|
|
2786
|
+
Sources:
|
|
2787
|
+
- If you reference any external fixes or docs, list their URLs in a "Sources:" section at the end.`;
|
|
2783
2788
|
var QAAgent = class extends BaseAgent {
|
|
2784
2789
|
maxFixAttempts = 3;
|
|
2785
2790
|
constructor(llm, options = {}) {
|
|
@@ -2796,8 +2801,8 @@ var QAAgent = class extends BaseAgent {
|
|
|
2796
2801
|
try {
|
|
2797
2802
|
const { stdout, stderr } = await execAsync("npm run build", {
|
|
2798
2803
|
cwd,
|
|
2799
|
-
timeout:
|
|
2800
|
-
//
|
|
2804
|
+
timeout: 3e5
|
|
2805
|
+
// 5 minutes
|
|
2801
2806
|
});
|
|
2802
2807
|
return {
|
|
2803
2808
|
success: true,
|
|
@@ -2819,7 +2824,7 @@ var QAAgent = class extends BaseAgent {
|
|
|
2819
2824
|
try {
|
|
2820
2825
|
const { stdout, stderr } = await execAsync("npm test -- --run", {
|
|
2821
2826
|
cwd,
|
|
2822
|
-
timeout:
|
|
2827
|
+
timeout: 3e5
|
|
2823
2828
|
});
|
|
2824
2829
|
return { success: true, output: stdout + stderr };
|
|
2825
2830
|
} catch (error) {
|
|
@@ -2830,27 +2835,61 @@ var QAAgent = class extends BaseAgent {
|
|
|
2830
2835
|
};
|
|
2831
2836
|
}
|
|
2832
2837
|
}
|
|
2838
|
+
/**
|
|
2839
|
+
* Extract file paths from error log
|
|
2840
|
+
*/
|
|
2841
|
+
extractFilePaths(errorLog) {
|
|
2842
|
+
const paths = /* @__PURE__ */ new Set();
|
|
2843
|
+
const regex = /((?:src|app|pages|lib|components)\/[a-zA-Z0-9_\-\/\.]+\.(?:ts|tsx|js|jsx|json))/g;
|
|
2844
|
+
const matches = errorLog.matchAll(regex);
|
|
2845
|
+
for (const match of matches) {
|
|
2846
|
+
paths.add(match[1]);
|
|
2847
|
+
}
|
|
2848
|
+
return paths;
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Read file content for context
|
|
2852
|
+
*/
|
|
2853
|
+
async getFileContext(cwd, paths) {
|
|
2854
|
+
if (paths.size === 0) return "";
|
|
2855
|
+
const contextParts = [];
|
|
2856
|
+
for (const filePath of paths) {
|
|
2857
|
+
try {
|
|
2858
|
+
const fullPath = path3.join(cwd, filePath);
|
|
2859
|
+
const content = await fs3.readFile(fullPath, "utf-8");
|
|
2860
|
+
contextParts.push(`// File: ${filePath}
|
|
2861
|
+
${content}`);
|
|
2862
|
+
} catch (e) {
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
return contextParts.join("\n\n");
|
|
2866
|
+
}
|
|
2833
2867
|
/**
|
|
2834
2868
|
* Diagnose build errors and generate fixes
|
|
2835
2869
|
*/
|
|
2836
|
-
async diagnoseAndFix(errorOutput) {
|
|
2837
|
-
this.log("Analyzing errors...");
|
|
2870
|
+
async diagnoseAndFix(cwd, errorOutput) {
|
|
2871
|
+
this.log("Analyzing errors and reading source files...");
|
|
2872
|
+
const problematicFiles = this.extractFilePaths(errorOutput);
|
|
2873
|
+
this.log(`Identified ${problematicFiles.size} problematic files: ${Array.from(problematicFiles).join(", ")}`);
|
|
2874
|
+
const fileContext = await this.getFileContext(cwd, problematicFiles);
|
|
2838
2875
|
const response = await this.think(`
|
|
2839
2876
|
The following build/test errors occurred:
|
|
2840
2877
|
|
|
2841
2878
|
\`\`\`
|
|
2842
|
-
${errorOutput.slice(0,
|
|
2879
|
+
${errorOutput.slice(0, 5e3)}
|
|
2843
2880
|
\`\`\`
|
|
2844
2881
|
|
|
2845
|
-
|
|
2846
|
-
For each error:
|
|
2847
|
-
1. Quote the exact error
|
|
2848
|
-
2. Identify the file and line
|
|
2849
|
-
3. Explain the fix
|
|
2850
|
-
4. Provide the corrected code
|
|
2882
|
+
Here is the content of the files mentioned in the errors:
|
|
2851
2883
|
|
|
2852
|
-
|
|
2853
|
-
|
|
2884
|
+
\`\`\`typescript
|
|
2885
|
+
${fileContext.slice(0, 2e4)}
|
|
2886
|
+
\`\`\`
|
|
2887
|
+
|
|
2888
|
+
Analyze these errors and the provided code.
|
|
2889
|
+
Diagnose the root cause and provide SURGICAL fixes.
|
|
2890
|
+
For example, if a property is missing in a component prop type, fix the interface.
|
|
2891
|
+
If an import is wrong, correct it.
|
|
2892
|
+
`);
|
|
2854
2893
|
const fixes = this.extractCodeBlocks(response);
|
|
2855
2894
|
this.log(`Generated ${fixes.length} fixes`, fixes.length > 0 ? "success" : "warn");
|
|
2856
2895
|
return fixes;
|
|
@@ -2882,7 +2921,7 @@ Only fix what's broken. Keep the rest intact.
|
|
|
2882
2921
|
commandOutputs
|
|
2883
2922
|
};
|
|
2884
2923
|
} else {
|
|
2885
|
-
const testFixes = await this.diagnoseAndFix(testResult.output);
|
|
2924
|
+
const testFixes = await this.diagnoseAndFix(cwd, testResult.output);
|
|
2886
2925
|
allFixes.push(...testFixes);
|
|
2887
2926
|
if (testFixes.length === 0) {
|
|
2888
2927
|
errors.push(`Tests failed but couldn't generate fixes: ${testResult.output.slice(0, 500)}`);
|
|
@@ -2892,12 +2931,22 @@ Only fix what's broken. Keep the rest intact.
|
|
|
2892
2931
|
}
|
|
2893
2932
|
}
|
|
2894
2933
|
this.log("Build failed, diagnosing...", "warn");
|
|
2895
|
-
const fixes = await this.diagnoseAndFix(buildResult.output);
|
|
2934
|
+
const fixes = await this.diagnoseAndFix(cwd, buildResult.output);
|
|
2896
2935
|
if (fixes.length === 0) {
|
|
2897
2936
|
errors.push(`Build failed but couldn't generate fixes: ${buildResult.output.slice(0, 500)}`);
|
|
2898
2937
|
break;
|
|
2899
2938
|
}
|
|
2900
2939
|
allFixes.push(...fixes);
|
|
2940
|
+
for (const fix of fixes) {
|
|
2941
|
+
try {
|
|
2942
|
+
const fullPath = path3.join(cwd, fix.path);
|
|
2943
|
+
await fs3.mkdir(path3.dirname(fullPath), { recursive: true });
|
|
2944
|
+
await fs3.writeFile(fullPath, fix.content, "utf-8");
|
|
2945
|
+
this.log(` Applied fix to: ${fix.path}`, "info");
|
|
2946
|
+
} catch (e) {
|
|
2947
|
+
this.log(`Failed to apply fix to ${fix.path}: ${e}`, "error");
|
|
2948
|
+
}
|
|
2949
|
+
}
|
|
2901
2950
|
}
|
|
2902
2951
|
return {
|
|
2903
2952
|
success: false,
|
|
@@ -2933,13 +2982,13 @@ Only fix what's broken. Keep the rest intact.
|
|
|
2933
2982
|
// src/agents/core/devops-agent.ts
|
|
2934
2983
|
import { exec as exec2 } from "child_process";
|
|
2935
2984
|
import { promisify as promisify2 } from "util";
|
|
2936
|
-
import
|
|
2937
|
-
import
|
|
2985
|
+
import fs4 from "fs/promises";
|
|
2986
|
+
import path4 from "path";
|
|
2938
2987
|
var execAsync2 = promisify2(exec2);
|
|
2939
2988
|
async function detectBuildOutputDir(cwd) {
|
|
2940
2989
|
try {
|
|
2941
|
-
const pkgPath =
|
|
2942
|
-
const raw = await
|
|
2990
|
+
const pkgPath = path4.join(cwd, "package.json");
|
|
2991
|
+
const raw = await fs4.readFile(pkgPath, "utf-8");
|
|
2943
2992
|
const pkg = JSON.parse(raw);
|
|
2944
2993
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
2945
2994
|
if (deps["next"]) return ".next";
|
|
@@ -3270,8 +3319,8 @@ URL: ${deployResult.url || "See dashboard"}`,
|
|
|
3270
3319
|
};
|
|
3271
3320
|
|
|
3272
3321
|
// src/agents/core/squad-orchestrator.ts
|
|
3273
|
-
import * as
|
|
3274
|
-
import * as
|
|
3322
|
+
import * as fs5 from "fs/promises";
|
|
3323
|
+
import * as path5 from "path";
|
|
3275
3324
|
import crypto2 from "crypto";
|
|
3276
3325
|
var SquadOrchestrator = class {
|
|
3277
3326
|
manager;
|
|
@@ -3409,7 +3458,7 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3409
3458
|
this.log("\u2705 Codebase is stable.", "success");
|
|
3410
3459
|
}
|
|
3411
3460
|
let deploymentUrl;
|
|
3412
|
-
if (this.config.autoDeploy) {
|
|
3461
|
+
if (healthy && this.config.autoDeploy) {
|
|
3413
3462
|
this.log("\u{1F680} Phase 4: Deployment", "phase");
|
|
3414
3463
|
const devopsTask = this.tasks.find((t) => t.assignee === "devops");
|
|
3415
3464
|
if (devopsTask) {
|
|
@@ -3471,7 +3520,15 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3471
3520
|
(t) => t.assignee !== "qa" && t.assignee !== "devops"
|
|
3472
3521
|
);
|
|
3473
3522
|
const pending = /* @__PURE__ */ new Map();
|
|
3474
|
-
coreTasks.forEach((task) =>
|
|
3523
|
+
coreTasks.forEach((task) => {
|
|
3524
|
+
if (!this.completedTasks.has(task.id)) {
|
|
3525
|
+
pending.set(task.id, task);
|
|
3526
|
+
}
|
|
3527
|
+
});
|
|
3528
|
+
if (pending.size === 0) {
|
|
3529
|
+
this.log("No new tasks to execute.", "info");
|
|
3530
|
+
return;
|
|
3531
|
+
}
|
|
3475
3532
|
const runTask = async (task) => {
|
|
3476
3533
|
const taskStart = Date.now();
|
|
3477
3534
|
const result = await this.executeTask(task);
|
|
@@ -3561,24 +3618,24 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3561
3618
|
*/
|
|
3562
3619
|
async writeFiles(files, filesCreated, filesModified) {
|
|
3563
3620
|
for (const file of files) {
|
|
3564
|
-
const fullPath =
|
|
3565
|
-
const dir =
|
|
3621
|
+
const fullPath = path5.join(this.config.workspaceRoot, file.path);
|
|
3622
|
+
const dir = path5.dirname(fullPath);
|
|
3566
3623
|
try {
|
|
3567
|
-
await
|
|
3624
|
+
await fs5.mkdir(dir, { recursive: true });
|
|
3568
3625
|
let existed = false;
|
|
3569
3626
|
let beforeContent = null;
|
|
3570
3627
|
try {
|
|
3571
|
-
await
|
|
3628
|
+
await fs5.access(fullPath);
|
|
3572
3629
|
existed = true;
|
|
3573
|
-
beforeContent = await
|
|
3630
|
+
beforeContent = await fs5.readFile(fullPath, "utf-8");
|
|
3574
3631
|
} catch {
|
|
3575
3632
|
existed = false;
|
|
3576
3633
|
}
|
|
3577
|
-
await
|
|
3634
|
+
await fs5.writeFile(fullPath, file.content, "utf-8");
|
|
3578
3635
|
const afterContent = file.content;
|
|
3579
|
-
const outputPath =
|
|
3580
|
-
await
|
|
3581
|
-
await
|
|
3636
|
+
const outputPath = path5.join(this.runDir, "outputs", file.path);
|
|
3637
|
+
await fs5.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
3638
|
+
await fs5.writeFile(outputPath, file.content, "utf-8");
|
|
3582
3639
|
const beforeHash = beforeContent ? this.hashContent(beforeContent) : null;
|
|
3583
3640
|
const afterHash = this.hashContent(afterContent);
|
|
3584
3641
|
await this.appendTrace("file_write", {
|
|
@@ -3605,17 +3662,17 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3605
3662
|
}
|
|
3606
3663
|
async initializeRun(userPrompt) {
|
|
3607
3664
|
this.runId = uuidv42();
|
|
3608
|
-
this.runDir =
|
|
3609
|
-
this.tracePath =
|
|
3610
|
-
this.reportPath =
|
|
3611
|
-
this.sourcesPath =
|
|
3612
|
-
this.snapshotManifestPath =
|
|
3613
|
-
this.runConfigPath =
|
|
3614
|
-
const outputsDir =
|
|
3615
|
-
await
|
|
3616
|
-
await
|
|
3617
|
-
await
|
|
3618
|
-
await
|
|
3665
|
+
this.runDir = path5.join(this.config.workspaceRoot, "runs", this.runId);
|
|
3666
|
+
this.tracePath = path5.join(this.runDir, "trace.jsonl");
|
|
3667
|
+
this.reportPath = path5.join(this.runDir, "report.md");
|
|
3668
|
+
this.sourcesPath = path5.join(this.runDir, "sources.json");
|
|
3669
|
+
this.snapshotManifestPath = path5.join(this.runDir, "snapshot", "manifest.json");
|
|
3670
|
+
this.runConfigPath = path5.join(this.runDir, "run.json");
|
|
3671
|
+
const outputsDir = path5.join(this.runDir, "outputs");
|
|
3672
|
+
await fs5.mkdir(this.runDir, { recursive: true });
|
|
3673
|
+
await fs5.mkdir(path5.join(this.runDir, "snapshot"), { recursive: true });
|
|
3674
|
+
await fs5.mkdir(outputsDir, { recursive: true });
|
|
3675
|
+
await fs5.writeFile(this.runConfigPath, JSON.stringify({
|
|
3619
3676
|
runId: this.runId,
|
|
3620
3677
|
prompt: userPrompt,
|
|
3621
3678
|
config: {
|
|
@@ -3650,7 +3707,7 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3650
3707
|
errors: result.errors,
|
|
3651
3708
|
deploymentUrl: result.deploymentUrl
|
|
3652
3709
|
});
|
|
3653
|
-
await
|
|
3710
|
+
await fs5.writeFile(this.sourcesPath, JSON.stringify(Array.from(this.sources).sort(), null, 2), "utf-8");
|
|
3654
3711
|
const diffSummary = await this.generateDiffReport();
|
|
3655
3712
|
const reportLines = [
|
|
3656
3713
|
`# Agdi Squad Run Report`,
|
|
@@ -3676,13 +3733,13 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3676
3733
|
result.errors.length ? `## Errors` : void 0,
|
|
3677
3734
|
...result.errors.length ? result.errors.map((e) => `- ${e}`) : []
|
|
3678
3735
|
].filter(Boolean).join("\n");
|
|
3679
|
-
await
|
|
3736
|
+
await fs5.writeFile(this.reportPath, reportLines, "utf-8");
|
|
3680
3737
|
}
|
|
3681
3738
|
async appendTrace(event, data) {
|
|
3682
3739
|
const entry = { timestamp: (/* @__PURE__ */ new Date()).toISOString(), event, data };
|
|
3683
3740
|
this.traceBuffer.push(entry);
|
|
3684
3741
|
if (!this.tracePath) return;
|
|
3685
|
-
await
|
|
3742
|
+
await fs5.appendFile(this.tracePath, JSON.stringify(entry) + "\n", "utf-8");
|
|
3686
3743
|
}
|
|
3687
3744
|
hashContent(content) {
|
|
3688
3745
|
return crypto2.createHash("sha256").update(content).digest("hex");
|
|
@@ -3697,15 +3754,15 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3697
3754
|
const ignore = /* @__PURE__ */ new Set(["node_modules", ".git", "runs", "dist", "build", ".next"]);
|
|
3698
3755
|
const manifest = [];
|
|
3699
3756
|
const walk = async (dir) => {
|
|
3700
|
-
const entries = await
|
|
3757
|
+
const entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
3701
3758
|
for (const entry of entries) {
|
|
3702
3759
|
if (ignore.has(entry.name)) continue;
|
|
3703
|
-
const fullPath =
|
|
3704
|
-
const relPath =
|
|
3760
|
+
const fullPath = path5.join(dir, entry.name);
|
|
3761
|
+
const relPath = path5.relative(snapshotRoot, fullPath);
|
|
3705
3762
|
if (entry.isDirectory()) {
|
|
3706
3763
|
await walk(fullPath);
|
|
3707
3764
|
} else if (entry.isFile()) {
|
|
3708
|
-
const buffer = await
|
|
3765
|
+
const buffer = await fs5.readFile(fullPath);
|
|
3709
3766
|
const content = buffer.toString("utf-8");
|
|
3710
3767
|
manifest.push({
|
|
3711
3768
|
path: relPath,
|
|
@@ -3716,23 +3773,23 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3716
3773
|
}
|
|
3717
3774
|
};
|
|
3718
3775
|
await walk(snapshotRoot);
|
|
3719
|
-
await
|
|
3776
|
+
await fs5.writeFile(this.snapshotManifestPath, JSON.stringify({
|
|
3720
3777
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3721
3778
|
root: snapshotRoot,
|
|
3722
3779
|
files: manifest
|
|
3723
3780
|
}, null, 2), "utf-8");
|
|
3724
3781
|
await this.appendTrace("snapshot", {
|
|
3725
3782
|
files: manifest.length,
|
|
3726
|
-
manifestPath:
|
|
3783
|
+
manifestPath: path5.relative(this.config.workspaceRoot, this.snapshotManifestPath)
|
|
3727
3784
|
});
|
|
3728
3785
|
}
|
|
3729
3786
|
async generateDiffReport() {
|
|
3730
3787
|
const snapshotRoot = this.config.workspaceRoot;
|
|
3731
3788
|
const ignore = /* @__PURE__ */ new Set(["node_modules", ".git", "runs", "dist", "build", ".next"]);
|
|
3732
|
-
const diffPath =
|
|
3789
|
+
const diffPath = path5.join(this.runDir, "diff.json");
|
|
3733
3790
|
let snapshotData = null;
|
|
3734
3791
|
try {
|
|
3735
|
-
const raw = await
|
|
3792
|
+
const raw = await fs5.readFile(this.snapshotManifestPath, "utf-8");
|
|
3736
3793
|
snapshotData = JSON.parse(raw);
|
|
3737
3794
|
} catch {
|
|
3738
3795
|
snapshotData = { files: [] };
|
|
@@ -3740,15 +3797,15 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3740
3797
|
const snapshotMap = new Map(snapshotData.files.map((file) => [file.path, file.hash]));
|
|
3741
3798
|
const currentMap = /* @__PURE__ */ new Map();
|
|
3742
3799
|
const walk = async (dir) => {
|
|
3743
|
-
const entries = await
|
|
3800
|
+
const entries = await fs5.readdir(dir, { withFileTypes: true });
|
|
3744
3801
|
for (const entry of entries) {
|
|
3745
3802
|
if (ignore.has(entry.name)) continue;
|
|
3746
|
-
const fullPath =
|
|
3747
|
-
const relPath =
|
|
3803
|
+
const fullPath = path5.join(dir, entry.name);
|
|
3804
|
+
const relPath = path5.relative(snapshotRoot, fullPath);
|
|
3748
3805
|
if (entry.isDirectory()) {
|
|
3749
3806
|
await walk(fullPath);
|
|
3750
3807
|
} else if (entry.isFile()) {
|
|
3751
|
-
const buffer = await
|
|
3808
|
+
const buffer = await fs5.readFile(fullPath);
|
|
3752
3809
|
const content = buffer.toString("utf-8");
|
|
3753
3810
|
currentMap.set(relPath, this.hashContent(content));
|
|
3754
3811
|
}
|
|
@@ -3775,12 +3832,12 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3775
3832
|
modified,
|
|
3776
3833
|
deleted
|
|
3777
3834
|
};
|
|
3778
|
-
await
|
|
3835
|
+
await fs5.writeFile(diffPath, JSON.stringify(diffPayload, null, 2), "utf-8");
|
|
3779
3836
|
await this.appendTrace("diff", {
|
|
3780
3837
|
created: created.length,
|
|
3781
3838
|
modified: modified.length,
|
|
3782
3839
|
deleted: deleted.length,
|
|
3783
|
-
diffPath:
|
|
3840
|
+
diffPath: path5.relative(this.config.workspaceRoot, diffPath)
|
|
3784
3841
|
});
|
|
3785
3842
|
return diffPayload;
|
|
3786
3843
|
}
|
|
@@ -3892,8 +3949,8 @@ Constraints: Build a production SaaS using Next.js App Router, Prisma, Postgres,
|
|
|
3892
3949
|
// src/commands/import.ts
|
|
3893
3950
|
import chalk12 from "chalk";
|
|
3894
3951
|
import ora5 from "ora";
|
|
3895
|
-
import { mkdir as
|
|
3896
|
-
import { join as
|
|
3952
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
3953
|
+
import { join as join4, dirname as dirname3 } from "path";
|
|
3897
3954
|
function sanitizeRelativePath(p) {
|
|
3898
3955
|
if (!p || p.startsWith("/") || p.match(/^[A-Za-z]:/)) return null;
|
|
3899
3956
|
const normalized = p.replace(/\\/g, "/");
|
|
@@ -3910,8 +3967,8 @@ function parseGitHubUrl(url) {
|
|
|
3910
3967
|
if (!cleanUrl.startsWith("github.com/")) {
|
|
3911
3968
|
throw new Error("Invalid GitHub URL. Please use format: https://github.com/owner/repo");
|
|
3912
3969
|
}
|
|
3913
|
-
const
|
|
3914
|
-
const parts =
|
|
3970
|
+
const path8 = cleanUrl.replace("github.com/", "");
|
|
3971
|
+
const parts = path8.split("/");
|
|
3915
3972
|
if (parts.length < 2) {
|
|
3916
3973
|
throw new Error("Invalid GitHub URL. Could not extract owner/repo.");
|
|
3917
3974
|
}
|
|
@@ -3979,10 +4036,10 @@ async function extractZipToFiles(buffer) {
|
|
|
3979
4036
|
}
|
|
3980
4037
|
async function writeFiles(files, outputDir) {
|
|
3981
4038
|
for (const file of files) {
|
|
3982
|
-
const fullPath =
|
|
3983
|
-
const dir =
|
|
3984
|
-
await
|
|
3985
|
-
await
|
|
4039
|
+
const fullPath = join4(outputDir, file.path);
|
|
4040
|
+
const dir = dirname3(fullPath);
|
|
4041
|
+
await mkdir3(dir, { recursive: true });
|
|
4042
|
+
await writeFile3(fullPath, file.content, "utf-8");
|
|
3986
4043
|
}
|
|
3987
4044
|
}
|
|
3988
4045
|
async function runImportCommand(url, outputDir) {
|
|
@@ -4018,214 +4075,8 @@ ${msg}
|
|
|
4018
4075
|
}
|
|
4019
4076
|
}
|
|
4020
4077
|
|
|
4021
|
-
// src/commands/wizard.ts
|
|
4022
|
-
import { input as input5, select as select3, confirm, password as password3 } from "@inquirer/prompts";
|
|
4023
|
-
import chalk13 from "chalk";
|
|
4024
|
-
import path5 from "path";
|
|
4025
|
-
import os from "os";
|
|
4026
|
-
import fs5 from "fs";
|
|
4027
|
-
async function runWizard() {
|
|
4028
|
-
await checkSafety();
|
|
4029
|
-
if (needsOnboarding()) {
|
|
4030
|
-
await runOnboarding();
|
|
4031
|
-
}
|
|
4032
|
-
await setupOptionalTools();
|
|
4033
|
-
const wantsSaas = await confirm({
|
|
4034
|
-
message: "Enable SaaS Blueprint mode? (Next.js + Prisma + Postgres + Stripe)",
|
|
4035
|
-
default: true
|
|
4036
|
-
});
|
|
4037
|
-
if (wantsSaas) {
|
|
4038
|
-
ui.setFlags({ saas: true });
|
|
4039
|
-
}
|
|
4040
|
-
console.log(chalk13.cyan.bold("\n\u{1F3AF} Mission Control"));
|
|
4041
|
-
console.log(chalk13.gray("Describe your app in detail. The Agdi Squad will handle the rest."));
|
|
4042
|
-
let prompt = await input5({
|
|
4043
|
-
message: "What are we building today?",
|
|
4044
|
-
validate: (value) => value.length > 5 ? true : "Please provide more detail (min 5 chars)"
|
|
4045
|
-
});
|
|
4046
|
-
if (wantsSaas) {
|
|
4047
|
-
prompt = `${prompt}
|
|
4048
|
-
|
|
4049
|
-
Constraints: Build a production SaaS using Next.js App Router, Prisma, Postgres, and Stripe. Include auth, billing, multi-tenant orgs, and a dashboard.`;
|
|
4050
|
-
}
|
|
4051
|
-
const activeConfig = getActiveProvider();
|
|
4052
|
-
if (!activeConfig) {
|
|
4053
|
-
console.log(chalk13.red("\u274C No API key configured. Run: agdi auth"));
|
|
4054
|
-
return;
|
|
4055
|
-
}
|
|
4056
|
-
const llm = createLLMProvider(activeConfig.provider, {
|
|
4057
|
-
apiKey: activeConfig.apiKey,
|
|
4058
|
-
model: activeConfig.model
|
|
4059
|
-
});
|
|
4060
|
-
console.log(chalk13.cyan("\n\u{1F914} Analyzing requirements..."));
|
|
4061
|
-
try {
|
|
4062
|
-
const analysis = await llm.generate(prompt, `
|
|
4063
|
-
You are a Senior Product Manager. Analyze this app idea.
|
|
4064
|
-
If it is vague (e.g., "make a CRM"), generate 3 specific questions to clarify scope, tech stack, and features.
|
|
4065
|
-
If it is detailed enough, return "DETAILED".
|
|
4066
|
-
|
|
4067
|
-
Format:
|
|
4068
|
-
Questions:
|
|
4069
|
-
1. [Question 1]
|
|
4070
|
-
2. [Question 2]
|
|
4071
|
-
3. [Question 3]
|
|
4072
|
-
`);
|
|
4073
|
-
if (!analysis.text.includes("DETAILED")) {
|
|
4074
|
-
console.log(chalk13.yellow("\n\u{1F4A1} I need a few more details to build exactly what you want:"));
|
|
4075
|
-
const questions = analysis.text.split("\n").filter((line) => line.match(/^\d+\./));
|
|
4076
|
-
const answers = [];
|
|
4077
|
-
for (const q of questions.slice(0, 3)) {
|
|
4078
|
-
const answer = await input5({ message: q.replace(/^\d+\.\s*/, "") });
|
|
4079
|
-
answers.push({ q, a: answer });
|
|
4080
|
-
}
|
|
4081
|
-
console.log(chalk13.cyan("\n\u{1F504} Synthesizing Master Plan..."));
|
|
4082
|
-
const synthesis = await llm.generate(
|
|
4083
|
-
`Original Request: ${prompt}
|
|
4084
|
-
|
|
4085
|
-
Clarifications:
|
|
4086
|
-
${answers.map((x) => `Q: ${x.q}
|
|
4087
|
-
A: ${x.a}`).join("\n")}
|
|
4088
|
-
|
|
4089
|
-
Rewrite the original request into a comprehensive technical specification for a developer squad.`,
|
|
4090
|
-
"You are a Technical Architect."
|
|
4091
|
-
);
|
|
4092
|
-
prompt = synthesis.text;
|
|
4093
|
-
console.log(chalk13.gray("\nUpdated Spec: " + prompt.substring(0, 100) + "...\n"));
|
|
4094
|
-
}
|
|
4095
|
-
} catch (err) {
|
|
4096
|
-
console.log(chalk13.gray("Skipping analysis (API unreachable), proceeding with raw prompt."));
|
|
4097
|
-
}
|
|
4098
|
-
console.log(chalk13.cyan("\n\u{1F680} Assembling the Squad..."));
|
|
4099
|
-
console.log(chalk13.gray("Frontend, Backend, QA, and DevOps agents are coming online.\n"));
|
|
4100
|
-
const config = loadConfig();
|
|
4101
|
-
const canDeploy = !!(config.vercelToken || config.netlifyToken || config.railwayToken);
|
|
4102
|
-
await runSquadCommand(prompt, llm, {
|
|
4103
|
-
deploy: canDeploy,
|
|
4104
|
-
// Auto-deploy if configured
|
|
4105
|
-
output: "./",
|
|
4106
|
-
// Current directory (safe because we checked safety earlier)
|
|
4107
|
-
verbose: true
|
|
4108
|
-
});
|
|
4109
|
-
if (ui.flags.saas) {
|
|
4110
|
-
console.log(chalk13.cyan("\nSaaS Quick Start:"));
|
|
4111
|
-
console.log(chalk13.gray(" 1) npm install"));
|
|
4112
|
-
console.log(chalk13.gray(" 2) cp .env.example .env"));
|
|
4113
|
-
console.log(chalk13.gray(" 3) npx prisma generate"));
|
|
4114
|
-
console.log(chalk13.gray(" 4) npx prisma db push"));
|
|
4115
|
-
console.log(chalk13.gray(" 5) npm run dev\n"));
|
|
4116
|
-
}
|
|
4117
|
-
}
|
|
4118
|
-
async function checkSafety() {
|
|
4119
|
-
const cwd = process.cwd();
|
|
4120
|
-
const home = os.homedir();
|
|
4121
|
-
const root = path5.parse(cwd).root;
|
|
4122
|
-
const isUnsafe = cwd === home || cwd === root;
|
|
4123
|
-
if (isUnsafe) {
|
|
4124
|
-
console.log(chalk13.yellow.bold("\n\u26A0\uFE0F Safety Warning"));
|
|
4125
|
-
console.log(chalk13.gray(`You are running Agdi in ${chalk13.cyan(cwd)}.`));
|
|
4126
|
-
console.log(chalk13.gray("Agdi writes files and runs commands. It needs its own space.\n"));
|
|
4127
|
-
const action = await select3({
|
|
4128
|
-
message: "What would you like to do?",
|
|
4129
|
-
choices: [
|
|
4130
|
-
{ name: "\u{1F4C2} Create a new project folder (Recommended)", value: "create" },
|
|
4131
|
-
{ name: "\u{1F525} Run here anyway (Dangerous)", value: "unsafe" },
|
|
4132
|
-
{ name: "\u274C Cancel", value: "cancel" }
|
|
4133
|
-
]
|
|
4134
|
-
});
|
|
4135
|
-
if (action === "cancel") {
|
|
4136
|
-
ui.safeExit(0);
|
|
4137
|
-
}
|
|
4138
|
-
if (action === "create") {
|
|
4139
|
-
const folderName = await input5({
|
|
4140
|
-
message: "Project name:",
|
|
4141
|
-
default: "my-agdi-app",
|
|
4142
|
-
validate: (v) => /^[a-z0-9-_]+$/i.test(v) ? true : "Invalid folder name"
|
|
4143
|
-
});
|
|
4144
|
-
const newPath = path5.join(cwd, folderName);
|
|
4145
|
-
if (!fs5.existsSync(newPath)) {
|
|
4146
|
-
fs5.mkdirSync(newPath);
|
|
4147
|
-
}
|
|
4148
|
-
process.chdir(newPath);
|
|
4149
|
-
console.log(chalk13.green(`
|
|
4150
|
-
\u{1F4C2} Switched to: ${chalk13.cyan(newPath)}
|
|
4151
|
-
`));
|
|
4152
|
-
}
|
|
4153
|
-
}
|
|
4154
|
-
}
|
|
4155
|
-
async function setupOptionalTools() {
|
|
4156
|
-
const config = loadConfig();
|
|
4157
|
-
let configChanged = false;
|
|
4158
|
-
if (!config.searchApiKey) {
|
|
4159
|
-
console.log(chalk13.white.bold("\n\u{1F310} Web Access (Optional)\n"));
|
|
4160
|
-
console.log(chalk13.gray("Giving Agdi web access allows it to find up-to-date docs and fix tricky bugs."));
|
|
4161
|
-
const wantsSearch = await confirm({
|
|
4162
|
-
message: "Enable web search capabilities?",
|
|
4163
|
-
default: true
|
|
4164
|
-
});
|
|
4165
|
-
if (wantsSearch) {
|
|
4166
|
-
const provider = await select3({
|
|
4167
|
-
message: "Select Search Provider:",
|
|
4168
|
-
choices: [
|
|
4169
|
-
{ name: "Brave Search (Recommended)", value: "brave" },
|
|
4170
|
-
{ name: "Tavily", value: "tavily" }
|
|
4171
|
-
]
|
|
4172
|
-
});
|
|
4173
|
-
const keyUrl = provider === "brave" ? "https://brave.com/search/api/" : "https://tavily.com/";
|
|
4174
|
-
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4175
|
-
`));
|
|
4176
|
-
const apiKey = await password3({
|
|
4177
|
-
message: `Enter your ${provider} API key:`,
|
|
4178
|
-
mask: "*"
|
|
4179
|
-
});
|
|
4180
|
-
if (apiKey) {
|
|
4181
|
-
config.searchApiKey = apiKey;
|
|
4182
|
-
config.searchProvider = provider;
|
|
4183
|
-
config.searchEnabled = true;
|
|
4184
|
-
configChanged = true;
|
|
4185
|
-
console.log(chalk13.green("\u2705 Web search enabled!"));
|
|
4186
|
-
}
|
|
4187
|
-
}
|
|
4188
|
-
}
|
|
4189
|
-
if (!config.vercelToken && !config.netlifyToken && !config.railwayToken) {
|
|
4190
|
-
console.log(chalk13.white.bold("\n\u{1F680} Deployment (Optional)\n"));
|
|
4191
|
-
console.log(chalk13.gray("Agdi can automatically deploy your app to the cloud when finished."));
|
|
4192
|
-
const wantsDeploy = await confirm({
|
|
4193
|
-
message: "Enable auto-deployment?",
|
|
4194
|
-
default: true
|
|
4195
|
-
});
|
|
4196
|
-
if (wantsDeploy) {
|
|
4197
|
-
const provider = await select3({
|
|
4198
|
-
message: "Select Deployment Target:",
|
|
4199
|
-
choices: [
|
|
4200
|
-
{ name: "Vercel", value: "vercel" },
|
|
4201
|
-
{ name: "Railway", value: "railway" },
|
|
4202
|
-
{ name: "Netlify", value: "netlify" }
|
|
4203
|
-
]
|
|
4204
|
-
});
|
|
4205
|
-
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";
|
|
4206
|
-
console.log(chalk13.gray(`Get your key at: ${chalk13.cyan(keyUrl)}
|
|
4207
|
-
`));
|
|
4208
|
-
const apiKey = await password3({
|
|
4209
|
-
message: `Enter your ${provider} API token:`,
|
|
4210
|
-
mask: "*"
|
|
4211
|
-
});
|
|
4212
|
-
if (apiKey) {
|
|
4213
|
-
if (provider === "vercel") config.vercelToken = apiKey;
|
|
4214
|
-
if (provider === "netlify") config.netlifyToken = apiKey;
|
|
4215
|
-
if (provider === "railway") config.railwayToken = apiKey;
|
|
4216
|
-
config.deploymentProvider = provider;
|
|
4217
|
-
configChanged = true;
|
|
4218
|
-
console.log(chalk13.green("\u2705 Auto-deployment enabled!"));
|
|
4219
|
-
}
|
|
4220
|
-
}
|
|
4221
|
-
}
|
|
4222
|
-
if (configChanged) {
|
|
4223
|
-
saveConfig(config);
|
|
4224
|
-
}
|
|
4225
|
-
}
|
|
4226
|
-
|
|
4227
4078
|
// src/commands/replay.ts
|
|
4228
|
-
import
|
|
4079
|
+
import chalk13 from "chalk";
|
|
4229
4080
|
import * as fs6 from "fs/promises";
|
|
4230
4081
|
import * as path6 from "path";
|
|
4231
4082
|
async function runReplayCommand(runId, llm, options = {}) {
|
|
@@ -4236,7 +4087,7 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4236
4087
|
const raw = await fs6.readFile(runConfigPath, "utf-8");
|
|
4237
4088
|
const runConfig = JSON.parse(raw);
|
|
4238
4089
|
if (!runConfig.prompt) {
|
|
4239
|
-
console.log(
|
|
4090
|
+
console.log(chalk13.red("\u274C Invalid run.json (missing prompt)"));
|
|
4240
4091
|
return null;
|
|
4241
4092
|
}
|
|
4242
4093
|
const config = {
|
|
@@ -4245,7 +4096,7 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4245
4096
|
verbose: options.verbose ?? runConfig.config?.verbose ?? true,
|
|
4246
4097
|
autoDeploy: options.deploy ?? runConfig.config?.autoDeploy ?? false
|
|
4247
4098
|
};
|
|
4248
|
-
console.log(
|
|
4099
|
+
console.log(chalk13.cyan(`
|
|
4249
4100
|
\u{1F501} Replaying run ${runId}`));
|
|
4250
4101
|
if (options.exact !== false) {
|
|
4251
4102
|
try {
|
|
@@ -4269,7 +4120,7 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4269
4120
|
}
|
|
4270
4121
|
};
|
|
4271
4122
|
await copyOutputs(outputsDir);
|
|
4272
|
-
console.log(
|
|
4123
|
+
console.log(chalk13.green("\u2705 Exact replay applied from stored outputs."));
|
|
4273
4124
|
return {
|
|
4274
4125
|
success: true,
|
|
4275
4126
|
projectSpec: { name: "replay", description: "Exact replay", type: "web-app", stack: {}, features: [] },
|
|
@@ -4280,34 +4131,190 @@ async function runReplayCommand(runId, llm, options = {}) {
|
|
|
4280
4131
|
errors: []
|
|
4281
4132
|
};
|
|
4282
4133
|
} catch (error) {
|
|
4283
|
-
console.log(
|
|
4284
|
-
console.log(
|
|
4134
|
+
console.log(chalk13.yellow("\u26A0\uFE0F Exact replay failed, falling back to rerun."));
|
|
4135
|
+
console.log(chalk13.gray(String(error)));
|
|
4285
4136
|
}
|
|
4286
4137
|
}
|
|
4287
4138
|
if (!llm) {
|
|
4288
|
-
console.log(
|
|
4139
|
+
console.log(chalk13.red("\u274C No LLM provider available for replay."));
|
|
4289
4140
|
return null;
|
|
4290
4141
|
}
|
|
4291
4142
|
const orchestrator = new SquadOrchestrator(llm, config);
|
|
4292
4143
|
return await orchestrator.run(runConfig.prompt);
|
|
4293
4144
|
} catch (error) {
|
|
4294
|
-
console.log(
|
|
4295
|
-
console.log(
|
|
4145
|
+
console.log(chalk13.red("\u274C Failed to load run config for replay"));
|
|
4146
|
+
console.log(chalk13.gray(String(error)));
|
|
4296
4147
|
return null;
|
|
4297
4148
|
}
|
|
4298
4149
|
}
|
|
4299
4150
|
|
|
4151
|
+
// src/commands/tui-entry.tsx
|
|
4152
|
+
import { render } from "ink";
|
|
4153
|
+
|
|
4154
|
+
// src/ui/tui.tsx
|
|
4155
|
+
import { useState, useEffect } from "react";
|
|
4156
|
+
import { Box, Text, useApp } from "ink";
|
|
4157
|
+
import BigText from "ink-big-text";
|
|
4158
|
+
import TextInput from "ink-text-input";
|
|
4159
|
+
import fs7 from "fs";
|
|
4160
|
+
import path7 from "path";
|
|
4161
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4162
|
+
var BootScreen = ({ onComplete }) => {
|
|
4163
|
+
const [progress, setProgress] = useState(0);
|
|
4164
|
+
const [log, setLog] = useState("");
|
|
4165
|
+
const logs = [
|
|
4166
|
+
"Initializing core systems...",
|
|
4167
|
+
"Loading neural modules...",
|
|
4168
|
+
"Connecting to Agdi Cloud...",
|
|
4169
|
+
"Verifying agent credentials...",
|
|
4170
|
+
"Mounting virtual filesystem...",
|
|
4171
|
+
"Establishing secure uplink...",
|
|
4172
|
+
"Syncing global state...",
|
|
4173
|
+
"Boot sequence complete."
|
|
4174
|
+
];
|
|
4175
|
+
useEffect(() => {
|
|
4176
|
+
const timer = setInterval(() => {
|
|
4177
|
+
setProgress((prev) => {
|
|
4178
|
+
const next = prev + 2;
|
|
4179
|
+
if (next >= 100) {
|
|
4180
|
+
clearInterval(timer);
|
|
4181
|
+
setTimeout(onComplete, 500);
|
|
4182
|
+
return 100;
|
|
4183
|
+
}
|
|
4184
|
+
return next;
|
|
4185
|
+
});
|
|
4186
|
+
const index = Math.floor(progress / 100 * logs.length);
|
|
4187
|
+
setLog(logs[index] || logs[logs.length - 1]);
|
|
4188
|
+
}, 30);
|
|
4189
|
+
return () => clearInterval(timer);
|
|
4190
|
+
}, [progress]);
|
|
4191
|
+
const width = 60;
|
|
4192
|
+
const filled = Math.floor(width * progress / 100);
|
|
4193
|
+
const bar = "\u2588".repeat(filled) + "\u2591".repeat(width - filled);
|
|
4194
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 20, children: [
|
|
4195
|
+
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(BigText, { text: "AGDI OS", font: "block", align: "center", colors: ["cyan", "blue"] }) }),
|
|
4196
|
+
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
4197
|
+
bar,
|
|
4198
|
+
" ",
|
|
4199
|
+
progress,
|
|
4200
|
+
"%"
|
|
4201
|
+
] }) }),
|
|
4202
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
4203
|
+
"\u279C ",
|
|
4204
|
+
log
|
|
4205
|
+
] })
|
|
4206
|
+
] });
|
|
4207
|
+
};
|
|
4208
|
+
var FileExplorer = ({ cwd }) => {
|
|
4209
|
+
const [files, setFiles] = useState([]);
|
|
4210
|
+
useEffect(() => {
|
|
4211
|
+
try {
|
|
4212
|
+
const list = fs7.readdirSync(cwd).filter((f) => !f.startsWith(".")).slice(0, 15);
|
|
4213
|
+
setFiles(list);
|
|
4214
|
+
} catch {
|
|
4215
|
+
setFiles(["<Error reading dir>"]);
|
|
4216
|
+
}
|
|
4217
|
+
}, [cwd]);
|
|
4218
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", title: " FILESYSTEM ", width: "30%", children: [
|
|
4219
|
+
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
4220
|
+
" ",
|
|
4221
|
+
cwd
|
|
4222
|
+
] }),
|
|
4223
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
4224
|
+
files.map((f, i) => /* @__PURE__ */ jsxs(Text, { color: "white", children: [
|
|
4225
|
+
fs7.statSync(path7.join(cwd, f)).isDirectory() ? "\u{1F4C1} " : "\u{1F4C4} ",
|
|
4226
|
+
f
|
|
4227
|
+
] }, i)),
|
|
4228
|
+
files.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: " (empty)" })
|
|
4229
|
+
] })
|
|
4230
|
+
] });
|
|
4231
|
+
};
|
|
4232
|
+
var LogPanel = ({ logs }) => {
|
|
4233
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", title: " AGENT LOGS ", width: "70%", marginLeft: 1, children: [
|
|
4234
|
+
logs.slice(-10).map((log, i) => /* @__PURE__ */ jsxs(Text, { color: "green", children: [
|
|
4235
|
+
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
4236
|
+
"[",
|
|
4237
|
+
(/* @__PURE__ */ new Date()).toLocaleTimeString(),
|
|
4238
|
+
"]"
|
|
4239
|
+
] }),
|
|
4240
|
+
" ",
|
|
4241
|
+
log
|
|
4242
|
+
] }, i)),
|
|
4243
|
+
logs.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: "Waiting for agent activity..." })
|
|
4244
|
+
] });
|
|
4245
|
+
};
|
|
4246
|
+
var ChatPanel = ({ history, onSend }) => {
|
|
4247
|
+
const [query, setQuery] = useState("");
|
|
4248
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", title: " MISSION CONTROL ", height: 12, children: [
|
|
4249
|
+
/* @__PURE__ */ jsx(Box, { flexDirection: "column", flexGrow: 1, justifyContent: "flex-end", children: history.slice(-5).map((msg, i) => /* @__PURE__ */ jsxs(Box, { marginY: 0, children: [
|
|
4250
|
+
/* @__PURE__ */ jsx(Text, { color: msg.role === "user" ? "cyan" : "magenta", bold: true, children: msg.role === "user" ? "YOU \u203A " : "AGDI \u203A " }),
|
|
4251
|
+
/* @__PURE__ */ jsx(Text, { children: msg.text })
|
|
4252
|
+
] }, i)) }),
|
|
4253
|
+
/* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "gray", marginTop: 1, children: [
|
|
4254
|
+
/* @__PURE__ */ jsx(Text, { color: "cyan", children: "\u279C " }),
|
|
4255
|
+
/* @__PURE__ */ jsx(
|
|
4256
|
+
TextInput,
|
|
4257
|
+
{
|
|
4258
|
+
value: query,
|
|
4259
|
+
onChange: setQuery,
|
|
4260
|
+
onSubmit: (val) => {
|
|
4261
|
+
onSend(val);
|
|
4262
|
+
setQuery("");
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
)
|
|
4266
|
+
] })
|
|
4267
|
+
] });
|
|
4268
|
+
};
|
|
4269
|
+
var Dashboard = () => {
|
|
4270
|
+
const { exit } = useApp();
|
|
4271
|
+
const [logs, setLogs] = useState(["System ready.", "Waiting for instructions."]);
|
|
4272
|
+
const [chatHistory, setChatHistory] = useState([]);
|
|
4273
|
+
const addLog = (msg) => setLogs((prev) => [...prev, msg]);
|
|
4274
|
+
const handleCommand = (cmd) => {
|
|
4275
|
+
if (cmd === "/exit") exit();
|
|
4276
|
+
setChatHistory((prev) => [...prev, { role: "user", text: cmd }]);
|
|
4277
|
+
addLog(`Processing command: ${cmd}`);
|
|
4278
|
+
setTimeout(() => {
|
|
4279
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: `I'm analyzing your request to "${cmd}"...` }]);
|
|
4280
|
+
addLog("Agent [Manager] started planning phase.");
|
|
4281
|
+
}, 800);
|
|
4282
|
+
};
|
|
4283
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [
|
|
4284
|
+
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
4285
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "AGDI v3.3.0 [ONLINE]" }),
|
|
4286
|
+
/* @__PURE__ */ jsx(Text, { color: "gray", children: "CPU: 12% | MEM: 450MB | NET: CONNECTED" })
|
|
4287
|
+
] }),
|
|
4288
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [
|
|
4289
|
+
/* @__PURE__ */ jsx(FileExplorer, { cwd: process.cwd() }),
|
|
4290
|
+
/* @__PURE__ */ jsx(LogPanel, { logs })
|
|
4291
|
+
] }),
|
|
4292
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(ChatPanel, { history: chatHistory, onSend: handleCommand }) })
|
|
4293
|
+
] });
|
|
4294
|
+
};
|
|
4295
|
+
var App = () => {
|
|
4296
|
+
const [screen, setScreen] = useState("boot");
|
|
4297
|
+
return screen === "boot" ? /* @__PURE__ */ jsx(BootScreen, { onComplete: () => setScreen("dashboard") }) : /* @__PURE__ */ jsx(Dashboard, {});
|
|
4298
|
+
};
|
|
4299
|
+
|
|
4300
|
+
// src/commands/tui-entry.tsx
|
|
4301
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
4302
|
+
function runTUI() {
|
|
4303
|
+
console.clear();
|
|
4304
|
+
render(/* @__PURE__ */ jsx2(App, {}));
|
|
4305
|
+
}
|
|
4306
|
+
|
|
4300
4307
|
// src/index.ts
|
|
4301
4308
|
var BANNER = `
|
|
4302
|
-
${
|
|
4303
|
-
${
|
|
4304
|
-
${
|
|
4305
|
-
${
|
|
4306
|
-
${
|
|
4307
|
-
${
|
|
4309
|
+
${chalk14.cyan(` ___ __ _ `)}
|
|
4310
|
+
${chalk14.cyan(` / | ____ _____/ /(_) `)}
|
|
4311
|
+
${chalk14.cyan(` / /| | / __ \`/ __ // / `)}
|
|
4312
|
+
${chalk14.cyan(` / ___ |/ /_/ / /_/ // / `)}
|
|
4313
|
+
${chalk14.cyan(`/_/ |_|\\_, /\\__,_//_/ `)}
|
|
4314
|
+
${chalk14.cyan(` /____/ `)}
|
|
4308
4315
|
`;
|
|
4309
4316
|
var program = new Command();
|
|
4310
|
-
program.name("agdi").description(
|
|
4317
|
+
program.name("agdi").description(chalk14.cyan("\u{1F9B8} The Autonomous AI Employee")).version("3.3.0").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)");
|
|
4311
4318
|
program.hook("preAction", (thisCommand) => {
|
|
4312
4319
|
const opts = thisCommand.opts();
|
|
4313
4320
|
if (opts.yes) {
|
|
@@ -4324,15 +4331,14 @@ program.hook("preAction", (thisCommand) => {
|
|
|
4324
4331
|
}
|
|
4325
4332
|
});
|
|
4326
4333
|
program.addHelpText("beforeAll", () => {
|
|
4327
|
-
return BANNER + "\n" +
|
|
4334
|
+
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");
|
|
4328
4335
|
});
|
|
4329
4336
|
program.action(async () => {
|
|
4330
4337
|
try {
|
|
4331
|
-
|
|
4332
|
-
await runWizard();
|
|
4338
|
+
runTUI();
|
|
4333
4339
|
} catch (error) {
|
|
4334
4340
|
if (error.name === "ExitPromptError") {
|
|
4335
|
-
console.log(
|
|
4341
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4336
4342
|
try {
|
|
4337
4343
|
ui.safeExit(0);
|
|
4338
4344
|
} catch {
|
|
@@ -4354,7 +4360,7 @@ program.command("auth").description("Configure API keys").option("--status", "Sh
|
|
|
4354
4360
|
}
|
|
4355
4361
|
} catch (error) {
|
|
4356
4362
|
if (error.name === "ExitPromptError") {
|
|
4357
|
-
console.log(
|
|
4363
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4358
4364
|
try {
|
|
4359
4365
|
ui.safeExit(0);
|
|
4360
4366
|
} catch {
|
|
@@ -4372,7 +4378,7 @@ program.command("model").alias("models").description("Change AI model").action(a
|
|
|
4372
4378
|
await selectModel();
|
|
4373
4379
|
} catch (error) {
|
|
4374
4380
|
if (error.name === "ExitPromptError") {
|
|
4375
|
-
console.log(
|
|
4381
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4376
4382
|
try {
|
|
4377
4383
|
ui.safeExit(0);
|
|
4378
4384
|
} catch {
|
|
@@ -4393,7 +4399,7 @@ program.command("chat").description("Start a chat session").action(async () => {
|
|
|
4393
4399
|
await startChat();
|
|
4394
4400
|
} catch (error) {
|
|
4395
4401
|
if (error.name === "ExitPromptError") {
|
|
4396
|
-
console.log(
|
|
4402
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Goodbye!\n"));
|
|
4397
4403
|
try {
|
|
4398
4404
|
ui.safeExit(0);
|
|
4399
4405
|
} catch {
|
|
@@ -4411,7 +4417,7 @@ program.command("run [directory]").description("Run a generated project").action
|
|
|
4411
4417
|
await runProject(directory);
|
|
4412
4418
|
} catch (error) {
|
|
4413
4419
|
if (error.name === "ExitPromptError") {
|
|
4414
|
-
console.log(
|
|
4420
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4415
4421
|
try {
|
|
4416
4422
|
ui.safeExit(0);
|
|
4417
4423
|
} catch {
|
|
@@ -4434,7 +4440,7 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4434
4440
|
}
|
|
4435
4441
|
const activeConfig = getActiveProvider();
|
|
4436
4442
|
if (!activeConfig) {
|
|
4437
|
-
console.log(
|
|
4443
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4438
4444
|
return;
|
|
4439
4445
|
}
|
|
4440
4446
|
const spinner = ora6("Generating application...").start();
|
|
@@ -4446,52 +4452,52 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4446
4452
|
const pm = new ProjectManager();
|
|
4447
4453
|
pm.create(options.output.replace("./", ""), prompt);
|
|
4448
4454
|
const { plan, files } = await generateApp(prompt, llm, (step, file) => {
|
|
4449
|
-
spinner.text = file ? `${step} ${
|
|
4455
|
+
spinner.text = file ? `${step} ${chalk14.gray(file)}` : step;
|
|
4450
4456
|
});
|
|
4451
4457
|
pm.updateFiles(files);
|
|
4452
4458
|
pm.updateDependencies(plan.dependencies);
|
|
4453
4459
|
if (options.dryRun || ui.flags.dryRun) {
|
|
4454
4460
|
spinner.stop();
|
|
4455
|
-
console.log(
|
|
4456
|
-
console.log(
|
|
4461
|
+
console.log(chalk14.cyan.bold("\n\u{1F6A7} DRY RUN SUMMARY\n"));
|
|
4462
|
+
console.log(chalk14.gray(`Project: ${plan.name}
|
|
4457
4463
|
`));
|
|
4458
|
-
console.log(
|
|
4459
|
-
files.forEach((f) => console.log(
|
|
4460
|
-
console.log(
|
|
4461
|
-
console.log(
|
|
4462
|
-
console.log(
|
|
4464
|
+
console.log(chalk14.cyan("Files to be created:"));
|
|
4465
|
+
files.forEach((f) => console.log(chalk14.gray(` \u{1F4C4} ${f.path}`)));
|
|
4466
|
+
console.log(chalk14.cyan("\nDependencies:"));
|
|
4467
|
+
console.log(chalk14.gray(` \u{1F4E6} ${plan.dependencies.join(", ")}`));
|
|
4468
|
+
console.log(chalk14.green("\n\u2713 Dry run complete. No files written.\n"));
|
|
4463
4469
|
return;
|
|
4464
4470
|
}
|
|
4465
4471
|
await writeProject(pm.get(), options.output);
|
|
4466
|
-
spinner.succeed(
|
|
4467
|
-
console.log(
|
|
4468
|
-
\u{1F4C1} Created ${files.length} files in ${
|
|
4472
|
+
spinner.succeed(chalk14.green("App generated!"));
|
|
4473
|
+
console.log(chalk14.gray(`
|
|
4474
|
+
\u{1F4C1} Created ${files.length} files in ${chalk14.cyan(options.output)}`));
|
|
4469
4475
|
if (ui.flags.saas || options.saas) {
|
|
4470
|
-
console.log(
|
|
4471
|
-
console.log(
|
|
4472
|
-
console.log(
|
|
4473
|
-
console.log(
|
|
4474
|
-
console.log(
|
|
4475
|
-
console.log(
|
|
4476
|
-
console.log(
|
|
4476
|
+
console.log(chalk14.cyan("\nSaaS Quick Start:"));
|
|
4477
|
+
console.log(chalk14.gray(` 1) cd ${options.output}`));
|
|
4478
|
+
console.log(chalk14.gray(" 2) npm install"));
|
|
4479
|
+
console.log(chalk14.gray(" 3) cp .env.example .env"));
|
|
4480
|
+
console.log(chalk14.gray(" 4) npx prisma generate"));
|
|
4481
|
+
console.log(chalk14.gray(" 5) npx prisma db push"));
|
|
4482
|
+
console.log(chalk14.gray(" 6) npm run dev\n"));
|
|
4477
4483
|
} else {
|
|
4478
|
-
console.log(
|
|
4484
|
+
console.log(chalk14.gray("\nNext: cd " + options.output + " && npm install && npm run dev\n"));
|
|
4479
4485
|
}
|
|
4480
4486
|
} catch (error) {
|
|
4481
4487
|
spinner.fail("Generation failed");
|
|
4482
4488
|
const msg = error instanceof Error ? error.message : String(error);
|
|
4483
4489
|
if (msg.includes("429") || msg.includes("quota")) {
|
|
4484
|
-
console.log(
|
|
4490
|
+
console.log(chalk14.yellow("\n\u26A0\uFE0F Quota exceeded. Run: agdi model\n"));
|
|
4485
4491
|
} else if (msg.includes("401") || msg.includes("403")) {
|
|
4486
|
-
console.log(
|
|
4492
|
+
console.log(chalk14.red("\n\u{1F511} Invalid API key. Run: agdi auth\n"));
|
|
4487
4493
|
} else {
|
|
4488
|
-
console.error(
|
|
4494
|
+
console.error(chalk14.red("\n" + msg + "\n"));
|
|
4489
4495
|
}
|
|
4490
4496
|
ui.safeExit(1);
|
|
4491
4497
|
}
|
|
4492
4498
|
} catch (error) {
|
|
4493
4499
|
if (error.name === "ExitPromptError") {
|
|
4494
|
-
console.log(
|
|
4500
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4495
4501
|
try {
|
|
4496
4502
|
ui.safeExit(0);
|
|
4497
4503
|
} catch {
|
|
@@ -4507,11 +4513,11 @@ program.command("build <prompt>").alias("b").description("Generate an app from a
|
|
|
4507
4513
|
program.command("config").description("Show configuration").action(async () => {
|
|
4508
4514
|
const config = loadConfig();
|
|
4509
4515
|
const active = getActiveProvider();
|
|
4510
|
-
console.log(
|
|
4511
|
-
console.log(
|
|
4512
|
-
console.log(
|
|
4513
|
-
console.log(
|
|
4514
|
-
console.log(
|
|
4516
|
+
console.log(chalk14.cyan.bold("\n\u2699\uFE0F Configuration\n"));
|
|
4517
|
+
console.log(chalk14.gray(" Provider: ") + chalk14.cyan(config.defaultProvider || "not set"));
|
|
4518
|
+
console.log(chalk14.gray(" Model: ") + chalk14.cyan(config.defaultModel || "not set"));
|
|
4519
|
+
console.log(chalk14.gray(" Config: ") + chalk14.gray("~/.agdi/config.json"));
|
|
4520
|
+
console.log(chalk14.cyan.bold("\n\u{1F510} API Keys\n"));
|
|
4515
4521
|
const keys = [
|
|
4516
4522
|
["Gemini", config.geminiApiKey],
|
|
4517
4523
|
["OpenRouter", config.openrouterApiKey],
|
|
@@ -4520,13 +4526,13 @@ program.command("config").description("Show configuration").action(async () => {
|
|
|
4520
4526
|
["DeepSeek", config.deepseekApiKey]
|
|
4521
4527
|
];
|
|
4522
4528
|
for (const [name, key] of keys) {
|
|
4523
|
-
const status = key ?
|
|
4529
|
+
const status = key ? chalk14.green("\u2713") : chalk14.gray("\u2717");
|
|
4524
4530
|
console.log(` ${status} ${name}`);
|
|
4525
4531
|
}
|
|
4526
|
-
console.log(
|
|
4532
|
+
console.log(chalk14.cyan.bold("\n\u{1F4CA} Telemetry\n"));
|
|
4527
4533
|
const telemetryEnabled = config.telemetry?.enabled ?? false;
|
|
4528
|
-
console.log(` ${telemetryEnabled ?
|
|
4529
|
-
console.log(
|
|
4534
|
+
console.log(` ${telemetryEnabled ? chalk14.green("\u2713 Enabled") : chalk14.gray("\u2717 Disabled")}`);
|
|
4535
|
+
console.log(chalk14.gray(" Change with: agdi config telemetry --enable | --disable"));
|
|
4530
4536
|
console.log("");
|
|
4531
4537
|
console.log("");
|
|
4532
4538
|
});
|
|
@@ -4534,59 +4540,59 @@ program.command("config:telemetry").alias("telemetry").description("Manage telem
|
|
|
4534
4540
|
const { isTelemetryEnabled, setTelemetryConsent, getTelemetryConfig } = await import("./config-ZFU7TSU2.js");
|
|
4535
4541
|
const { generateSampleEvent, generateSanitizationDemo } = await import("./telemetry-service-OHU5NKON.js");
|
|
4536
4542
|
if (options.dryRun || options.test) {
|
|
4537
|
-
console.log(
|
|
4538
|
-
console.log(
|
|
4539
|
-
console.log(
|
|
4540
|
-
console.log(
|
|
4543
|
+
console.log(chalk14.cyan.bold("\n\u{1F50D} TELEMETRY TRANSPARENCY MODE\n"));
|
|
4544
|
+
console.log(chalk14.gray("This is exactly what Agdi sends. Notice there is"));
|
|
4545
|
+
console.log(chalk14.green.bold("NO source code, file paths, or API keys.\n"));
|
|
4546
|
+
console.log(chalk14.white.bold('\u{1F4CA} Sample "Build Failed" Event:\n'));
|
|
4541
4547
|
const sample = generateSampleEvent();
|
|
4542
|
-
console.log(
|
|
4543
|
-
console.log(
|
|
4544
|
-
console.log(
|
|
4545
|
-
console.log(
|
|
4548
|
+
console.log(chalk14.gray(JSON.stringify(sample, null, 2)));
|
|
4549
|
+
console.log(chalk14.white.bold("\n\u{1F6E1}\uFE0F Sanitization Demo:\n"));
|
|
4550
|
+
console.log(chalk14.gray("Even if sensitive data accidentally enters an error message,"));
|
|
4551
|
+
console.log(chalk14.gray("our sanitization layer strips it before transmission:\n"));
|
|
4546
4552
|
const demo = generateSanitizationDemo();
|
|
4547
|
-
console.log(
|
|
4548
|
-
console.log(
|
|
4553
|
+
console.log(chalk14.red.bold("BEFORE sanitization (never sent):"));
|
|
4554
|
+
console.log(chalk14.gray(JSON.stringify({
|
|
4549
4555
|
errorCode: demo.before.errorCode,
|
|
4550
4556
|
feedback: demo.before.feedback
|
|
4551
4557
|
}, null, 2)));
|
|
4552
|
-
console.log(
|
|
4553
|
-
console.log(
|
|
4558
|
+
console.log(chalk14.green.bold("\nAFTER sanitization (what we actually send):"));
|
|
4559
|
+
console.log(chalk14.gray(JSON.stringify({
|
|
4554
4560
|
errorCode: demo.after.errorCode,
|
|
4555
4561
|
feedback: demo.after.feedback
|
|
4556
4562
|
}, null, 2)));
|
|
4557
|
-
console.log(
|
|
4558
|
-
console.log(
|
|
4563
|
+
console.log(chalk14.cyan("\n\u2705 Your code and secrets are NEVER transmitted."));
|
|
4564
|
+
console.log(chalk14.gray(" Learn more: https://agdi.dev/privacy\n"));
|
|
4559
4565
|
return;
|
|
4560
4566
|
}
|
|
4561
4567
|
if (options.enable) {
|
|
4562
4568
|
setTelemetryConsent(true);
|
|
4563
|
-
console.log(
|
|
4564
|
-
console.log(
|
|
4565
|
-
console.log(
|
|
4566
|
-
console.log(
|
|
4569
|
+
console.log(chalk14.green("\n\u2705 Telemetry enabled"));
|
|
4570
|
+
console.log(chalk14.gray(" We collect: success/fail, error types, model used"));
|
|
4571
|
+
console.log(chalk14.gray(" We NEVER collect: source code, API keys, file paths"));
|
|
4572
|
+
console.log(chalk14.gray(" Verify anytime: agdi config telemetry --dry-run\n"));
|
|
4567
4573
|
} else if (options.disable) {
|
|
4568
4574
|
setTelemetryConsent(false);
|
|
4569
|
-
console.log(
|
|
4570
|
-
console.log(
|
|
4575
|
+
console.log(chalk14.yellow("\n\u{1F4CA} Telemetry disabled"));
|
|
4576
|
+
console.log(chalk14.gray(" You can re-enable anytime with: agdi config telemetry --enable\n"));
|
|
4571
4577
|
} else {
|
|
4572
4578
|
const config = getTelemetryConfig();
|
|
4573
|
-
console.log(
|
|
4574
|
-
console.log(
|
|
4575
|
-
console.log(
|
|
4579
|
+
console.log(chalk14.cyan.bold("\n\u{1F4CA} Telemetry Status\n"));
|
|
4580
|
+
console.log(chalk14.gray(" Enabled: ") + (config.enabled ? chalk14.green("Yes") : chalk14.gray("No")));
|
|
4581
|
+
console.log(chalk14.gray(" Consent: ") + (config.consentAsked ? chalk14.green("Asked") : chalk14.gray("Not asked")));
|
|
4576
4582
|
if (config.anonymousId) {
|
|
4577
|
-
console.log(
|
|
4583
|
+
console.log(chalk14.gray(" ID: ") + chalk14.gray(config.anonymousId.slice(0, 8) + "..."));
|
|
4578
4584
|
}
|
|
4579
4585
|
console.log("");
|
|
4580
|
-
console.log(
|
|
4581
|
-
console.log(
|
|
4582
|
-
console.log(
|
|
4586
|
+
console.log(chalk14.gray(" Enable: agdi config telemetry --enable"));
|
|
4587
|
+
console.log(chalk14.gray(" Disable: agdi config telemetry --disable"));
|
|
4588
|
+
console.log(chalk14.gray(" Verify: agdi config telemetry --dry-run\n"));
|
|
4583
4589
|
}
|
|
4584
4590
|
});
|
|
4585
4591
|
program.command("doctor").alias("doc").description("Run self-diagnosis checks").action(async () => {
|
|
4586
4592
|
try {
|
|
4587
4593
|
await runDoctor();
|
|
4588
4594
|
} catch (error) {
|
|
4589
|
-
console.error(
|
|
4595
|
+
console.error(chalk14.red("Diagnostic failed: " + error));
|
|
4590
4596
|
ui.safeExit(1);
|
|
4591
4597
|
}
|
|
4592
4598
|
});
|
|
@@ -4597,7 +4603,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4597
4603
|
}
|
|
4598
4604
|
const activeConfig = getActiveProvider();
|
|
4599
4605
|
if (!activeConfig) {
|
|
4600
|
-
console.log(
|
|
4606
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4601
4607
|
return;
|
|
4602
4608
|
}
|
|
4603
4609
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4611,7 +4617,7 @@ program.command("squad [prompt]").alias("s").description("\u{1F9B8} Autonomous m
|
|
|
4611
4617
|
});
|
|
4612
4618
|
} catch (error) {
|
|
4613
4619
|
if (error.name === "ExitPromptError") {
|
|
4614
|
-
console.log(
|
|
4620
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4615
4621
|
try {
|
|
4616
4622
|
ui.safeExit(0);
|
|
4617
4623
|
} catch {
|
|
@@ -4639,7 +4645,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4639
4645
|
}
|
|
4640
4646
|
const activeConfig = getActiveProvider();
|
|
4641
4647
|
if (!activeConfig) {
|
|
4642
|
-
console.log(
|
|
4648
|
+
console.log(chalk14.red("\u274C No API key configured. Run: agdi auth"));
|
|
4643
4649
|
return;
|
|
4644
4650
|
}
|
|
4645
4651
|
const llm = createLLMProvider(activeConfig.provider, {
|
|
@@ -4653,7 +4659,7 @@ program.command("replay <runId>").description("\u{1F501} Replay a previous squad
|
|
|
4653
4659
|
});
|
|
4654
4660
|
} catch (error) {
|
|
4655
4661
|
if (error.name === "ExitPromptError") {
|
|
4656
|
-
console.log(
|
|
4662
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4657
4663
|
try {
|
|
4658
4664
|
ui.safeExit(0);
|
|
4659
4665
|
} catch {
|
|
@@ -4671,7 +4677,7 @@ program.command("import <url>").alias("i").description("\u{1F4E6} Import a GitHu
|
|
|
4671
4677
|
await runImportCommand(url, options.output);
|
|
4672
4678
|
} catch (error) {
|
|
4673
4679
|
if (error.name === "ExitPromptError") {
|
|
4674
|
-
console.log(
|
|
4680
|
+
console.log(chalk14.gray("\n\n\u{1F44B} Cancelled.\n"));
|
|
4675
4681
|
try {
|
|
4676
4682
|
ui.safeExit(0);
|
|
4677
4683
|
} catch {
|