agdi 3.3.2 → 3.3.4
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.
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// src/core/event-bus.ts
|
|
2
|
+
import { EventEmitter } from "events";
|
|
3
|
+
var agentEventBus = new EventEmitter();
|
|
4
|
+
agentEventBus.setMaxListeners(50);
|
|
5
|
+
var thoughtFlushTimeout = null;
|
|
6
|
+
var pendingThought = null;
|
|
7
|
+
function emitAgentEvent(event) {
|
|
8
|
+
const fullEvent = {
|
|
9
|
+
...event,
|
|
10
|
+
timestamp: Date.now()
|
|
11
|
+
};
|
|
12
|
+
if (event.type === "thought") {
|
|
13
|
+
pendingThought = fullEvent;
|
|
14
|
+
if (!thoughtFlushTimeout) {
|
|
15
|
+
thoughtFlushTimeout = setTimeout(() => {
|
|
16
|
+
if (pendingThought) {
|
|
17
|
+
agentEventBus.emit("agent_event", pendingThought);
|
|
18
|
+
pendingThought = null;
|
|
19
|
+
}
|
|
20
|
+
thoughtFlushTimeout = null;
|
|
21
|
+
}, 100);
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
agentEventBus.emit("agent_event", fullEvent);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function cleanupEventBus() {
|
|
28
|
+
agentEventBus.removeAllListeners();
|
|
29
|
+
if (thoughtFlushTimeout) {
|
|
30
|
+
clearTimeout(thoughtFlushTimeout);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
process.on("exit", cleanupEventBus);
|
|
34
|
+
process.on("SIGINT", cleanupEventBus);
|
|
35
|
+
process.on("uncaughtException", (err) => {
|
|
36
|
+
console.error("Uncaught exception:", err);
|
|
37
|
+
cleanupEventBus();
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
agentEventBus,
|
|
43
|
+
emitAgentEvent,
|
|
44
|
+
cleanupEventBus
|
|
45
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
agentEventBus,
|
|
4
4
|
emitAgentEvent
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-A5UTYKKM.js";
|
|
6
6
|
import {
|
|
7
7
|
loadConfig,
|
|
8
8
|
saveConfig
|
|
@@ -343,9 +343,9 @@ var errorGradient = gradient([THEME.red, "#b91c1c"]);
|
|
|
343
343
|
var goldGradient = gradient([THEME.yellow, "#fbbf24"]);
|
|
344
344
|
async function renderBanner(version = "v2.6.0") {
|
|
345
345
|
console.clear();
|
|
346
|
-
const text = await new Promise((
|
|
346
|
+
const text = await new Promise((resolve2) => {
|
|
347
347
|
figlet("AGDI", { font: "Slant" }, (err, data) => {
|
|
348
|
-
|
|
348
|
+
resolve2(data || "AGDI");
|
|
349
349
|
});
|
|
350
350
|
});
|
|
351
351
|
console.log(brandGradient.multiline(text));
|
|
@@ -1576,7 +1576,7 @@ async function runProject(targetDir) {
|
|
|
1576
1576
|
console.log(chalk6.yellow("\u{1F4E6} Installing dependencies...\n"));
|
|
1577
1577
|
const installSpinner = ora3("Running npm install...").start();
|
|
1578
1578
|
try {
|
|
1579
|
-
await new Promise((
|
|
1579
|
+
await new Promise((resolve2, reject) => {
|
|
1580
1580
|
const install = spawn("npm", ["install"], {
|
|
1581
1581
|
cwd: absoluteDir,
|
|
1582
1582
|
stdio: "inherit",
|
|
@@ -1585,7 +1585,7 @@ async function runProject(targetDir) {
|
|
|
1585
1585
|
install.on("close", (code) => {
|
|
1586
1586
|
if (code === 0) {
|
|
1587
1587
|
installSpinner.succeed("Dependencies installed!");
|
|
1588
|
-
|
|
1588
|
+
resolve2();
|
|
1589
1589
|
} else {
|
|
1590
1590
|
installSpinner.fail("npm install failed");
|
|
1591
1591
|
reject(new Error(`npm install exited with code ${code}`));
|
|
@@ -2101,8 +2101,9 @@ var BaseAgent = class {
|
|
|
2101
2101
|
}
|
|
2102
2102
|
/**
|
|
2103
2103
|
* Generate a response from the LLM
|
|
2104
|
+
* Includes timeout protection to prevent indefinite hanging
|
|
2104
2105
|
*/
|
|
2105
|
-
async think(prompt) {
|
|
2106
|
+
async think(prompt, timeoutMs = 12e4) {
|
|
2106
2107
|
this.log("Thinking...", "info");
|
|
2107
2108
|
emitAgentEvent({
|
|
2108
2109
|
type: "thought",
|
|
@@ -2110,7 +2111,12 @@ var BaseAgent = class {
|
|
|
2110
2111
|
role: this.role,
|
|
2111
2112
|
message: `Analyzing task...`
|
|
2112
2113
|
});
|
|
2113
|
-
const response = await
|
|
2114
|
+
const response = await Promise.race([
|
|
2115
|
+
this.llm.generate(prompt, this.getSystemPrompt()),
|
|
2116
|
+
new Promise(
|
|
2117
|
+
(_, reject) => setTimeout(() => reject(new Error(`LLM request timed out after ${timeoutMs / 1e3}s`)), timeoutMs)
|
|
2118
|
+
)
|
|
2119
|
+
]);
|
|
2114
2120
|
const summary = response.text.split("\n")[0].substring(0, 80) + "...";
|
|
2115
2121
|
emitAgentEvent({
|
|
2116
2122
|
type: "thought",
|
|
@@ -3148,12 +3154,17 @@ Requirements:
|
|
|
3148
3154
|
}
|
|
3149
3155
|
try {
|
|
3150
3156
|
const prodFlag = production ? "--prod" : "";
|
|
3151
|
-
const command = `npx vercel ${prodFlag} --yes
|
|
3152
|
-
this.log(`Running: npx vercel ${prodFlag} --yes
|
|
3157
|
+
const command = `npx vercel ${prodFlag} --yes`;
|
|
3158
|
+
this.log(`Running: npx vercel ${prodFlag} --yes`, "info");
|
|
3153
3159
|
const { stdout, stderr } = await execAsync2(command, {
|
|
3154
3160
|
cwd,
|
|
3155
|
-
timeout: 3e5
|
|
3161
|
+
timeout: 3e5,
|
|
3156
3162
|
// 5 minutes
|
|
3163
|
+
env: {
|
|
3164
|
+
...process.env,
|
|
3165
|
+
VERCEL_TOKEN: this.vercelToken
|
|
3166
|
+
// Pass via env, not CLI (security)
|
|
3167
|
+
}
|
|
3157
3168
|
});
|
|
3158
3169
|
const output = stdout + stderr;
|
|
3159
3170
|
const urlMatch = output.match(/https:\/\/[^\s]+\.vercel\.app/);
|
|
@@ -3203,10 +3214,15 @@ Requirements:
|
|
|
3203
3214
|
try {
|
|
3204
3215
|
const prodFlag = production ? "--prod" : "";
|
|
3205
3216
|
const outputDir = await detectBuildOutputDir(cwd);
|
|
3206
|
-
const command = `npx netlify deploy ${prodFlag} --
|
|
3217
|
+
const command = `npx netlify deploy ${prodFlag} --dir=${outputDir}`;
|
|
3207
3218
|
const { stdout, stderr } = await execAsync2(command, {
|
|
3208
3219
|
cwd,
|
|
3209
|
-
timeout: 3e5
|
|
3220
|
+
timeout: 3e5,
|
|
3221
|
+
env: {
|
|
3222
|
+
...process.env,
|
|
3223
|
+
NETLIFY_AUTH_TOKEN: this.netlifyToken
|
|
3224
|
+
// Pass via env, not CLI (security)
|
|
3225
|
+
}
|
|
3210
3226
|
});
|
|
3211
3227
|
const output = stdout + (stderr || "");
|
|
3212
3228
|
const urlMatch = output.match(/https:\/\/[^\s]+\.netlify\.app/);
|
|
@@ -3592,7 +3608,7 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3592
3608
|
*/
|
|
3593
3609
|
async executeTask(task) {
|
|
3594
3610
|
this.log(`[${task.assignee}] ${task.title}`, "task");
|
|
3595
|
-
const { emitAgentEvent: emitAgentEvent2 } = await import("./event-bus-
|
|
3611
|
+
const { emitAgentEvent: emitAgentEvent2 } = await import("./event-bus-Q3WCETQQ.js");
|
|
3596
3612
|
emitAgentEvent2({
|
|
3597
3613
|
type: "handoff",
|
|
3598
3614
|
agentName: task.assignee,
|
|
@@ -3647,10 +3663,21 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3647
3663
|
}
|
|
3648
3664
|
/**
|
|
3649
3665
|
* Write generated files to disk
|
|
3666
|
+
* SECURITY: All paths are validated to prevent directory traversal attacks
|
|
3650
3667
|
*/
|
|
3651
3668
|
async writeFiles(files, filesCreated, filesModified) {
|
|
3669
|
+
const workspaceRoot = path5.resolve(this.config.workspaceRoot);
|
|
3652
3670
|
for (const file of files) {
|
|
3653
|
-
const
|
|
3671
|
+
const validationResult = this.validateFilePath(file.path, workspaceRoot);
|
|
3672
|
+
if (!validationResult.valid) {
|
|
3673
|
+
this.log(`\u{1F6E1}\uFE0F Blocked unsafe path: ${file.path} - ${validationResult.error}`, "error");
|
|
3674
|
+
await this.appendTrace("file_blocked", {
|
|
3675
|
+
path: file.path,
|
|
3676
|
+
reason: validationResult.error
|
|
3677
|
+
});
|
|
3678
|
+
continue;
|
|
3679
|
+
}
|
|
3680
|
+
const fullPath = validationResult.resolvedPath;
|
|
3654
3681
|
const dir = path5.dirname(fullPath);
|
|
3655
3682
|
try {
|
|
3656
3683
|
await fs5.mkdir(dir, { recursive: true });
|
|
@@ -3665,7 +3692,7 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3665
3692
|
}
|
|
3666
3693
|
await fs5.writeFile(fullPath, file.content, "utf-8");
|
|
3667
3694
|
const afterContent = file.content;
|
|
3668
|
-
const outputPath = path5.join(this.runDir, "outputs",
|
|
3695
|
+
const outputPath = path5.join(this.runDir, "outputs", validationResult.normalizedPath);
|
|
3669
3696
|
await fs5.mkdir(path5.dirname(outputPath), { recursive: true });
|
|
3670
3697
|
await fs5.writeFile(outputPath, file.content, "utf-8");
|
|
3671
3698
|
const beforeHash = beforeContent ? this.hashContent(beforeContent) : null;
|
|
@@ -3692,6 +3719,54 @@ ${qaResult.errors?.join("\n")}`,
|
|
|
3692
3719
|
}
|
|
3693
3720
|
}
|
|
3694
3721
|
}
|
|
3722
|
+
/**
|
|
3723
|
+
* Validate a file path to prevent directory traversal attacks
|
|
3724
|
+
* SECURITY: Critical function - blocks paths that escape workspace root
|
|
3725
|
+
*/
|
|
3726
|
+
validateFilePath(filePath, workspaceRoot) {
|
|
3727
|
+
if (path5.isAbsolute(filePath)) {
|
|
3728
|
+
return {
|
|
3729
|
+
valid: false,
|
|
3730
|
+
error: "Absolute paths not allowed"
|
|
3731
|
+
};
|
|
3732
|
+
}
|
|
3733
|
+
const normalizedPath = path5.normalize(filePath).replace(/^(\.\.[\\/])+/, "");
|
|
3734
|
+
const resolvedPath = path5.resolve(workspaceRoot, filePath);
|
|
3735
|
+
if (filePath.includes("..")) {
|
|
3736
|
+
if (!resolvedPath.startsWith(workspaceRoot + path5.sep) && resolvedPath !== workspaceRoot) {
|
|
3737
|
+
return {
|
|
3738
|
+
valid: false,
|
|
3739
|
+
error: "Path traversal blocked: cannot escape workspace root"
|
|
3740
|
+
};
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
if (!resolvedPath.startsWith(workspaceRoot)) {
|
|
3744
|
+
return {
|
|
3745
|
+
valid: false,
|
|
3746
|
+
error: "Path traversal blocked: resolved path outside workspace"
|
|
3747
|
+
};
|
|
3748
|
+
}
|
|
3749
|
+
const sensitivePatterns = [
|
|
3750
|
+
/^\.git\//,
|
|
3751
|
+
/^node_modules\//,
|
|
3752
|
+
/^\.env$/,
|
|
3753
|
+
/^\.env\./,
|
|
3754
|
+
/\/\.git\//
|
|
3755
|
+
];
|
|
3756
|
+
for (const pattern of sensitivePatterns) {
|
|
3757
|
+
if (pattern.test(normalizedPath)) {
|
|
3758
|
+
return {
|
|
3759
|
+
valid: false,
|
|
3760
|
+
error: `Blocked write to sensitive path: ${normalizedPath}`
|
|
3761
|
+
};
|
|
3762
|
+
}
|
|
3763
|
+
}
|
|
3764
|
+
return {
|
|
3765
|
+
valid: true,
|
|
3766
|
+
resolvedPath,
|
|
3767
|
+
normalizedPath
|
|
3768
|
+
};
|
|
3769
|
+
}
|
|
3695
3770
|
async initializeRun(userPrompt) {
|
|
3696
3771
|
this.runId = uuidv42();
|
|
3697
3772
|
this.runDir = path5.join(this.config.workspaceRoot, "runs", this.runId);
|
|
@@ -4186,145 +4261,120 @@ import { render } from "ink";
|
|
|
4186
4261
|
// src/ui/tui.tsx
|
|
4187
4262
|
import { useState, useEffect } from "react";
|
|
4188
4263
|
import { Box, Text, useApp } from "ink";
|
|
4189
|
-
import BigText from "ink-big-text";
|
|
4190
|
-
import Spinner from "ink-spinner";
|
|
4191
4264
|
import TextInput from "ink-text-input";
|
|
4192
4265
|
import fs7 from "fs";
|
|
4193
4266
|
import path7 from "path";
|
|
4194
4267
|
import os from "os";
|
|
4195
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
|
+
};
|
|
4196
4277
|
var BootScreen = ({ onComplete }) => {
|
|
4197
4278
|
const [progress, setProgress] = useState(0);
|
|
4198
|
-
const [log, setLog] = useState("");
|
|
4199
|
-
const logs = [
|
|
4200
|
-
"Initializing core systems...",
|
|
4201
|
-
"Loading neural modules...",
|
|
4202
|
-
"Connecting to Agdi Cloud...",
|
|
4203
|
-
"Verifying agent credentials...",
|
|
4204
|
-
"Mounting virtual filesystem...",
|
|
4205
|
-
"Establishing secure uplink...",
|
|
4206
|
-
"Syncing global state...",
|
|
4207
|
-
"Boot sequence complete."
|
|
4208
|
-
];
|
|
4209
4279
|
useEffect(() => {
|
|
4210
4280
|
const timer = setInterval(() => {
|
|
4211
4281
|
setProgress((prev) => {
|
|
4212
|
-
const next = prev +
|
|
4282
|
+
const next = prev + 10;
|
|
4213
4283
|
if (next >= 100) {
|
|
4214
4284
|
clearInterval(timer);
|
|
4215
|
-
setTimeout(onComplete,
|
|
4285
|
+
setTimeout(onComplete, 100);
|
|
4216
4286
|
return 100;
|
|
4217
4287
|
}
|
|
4218
4288
|
return next;
|
|
4219
4289
|
});
|
|
4220
|
-
|
|
4221
|
-
setLog(logs[index] || logs[logs.length - 1]);
|
|
4222
|
-
}, 30);
|
|
4290
|
+
}, 20);
|
|
4223
4291
|
return () => clearInterval(timer);
|
|
4224
|
-
}, [
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
/* @__PURE__ */ jsx(Box, { marginY: 1, children: /* @__PURE__ */ jsxs(Text, { color: "cyan", children: [
|
|
4231
|
-
bar,
|
|
4232
|
-
" ",
|
|
4233
|
-
progress,
|
|
4234
|
-
"%"
|
|
4235
|
-
] }) }),
|
|
4236
|
-
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
4237
|
-
"\u279C ",
|
|
4238
|
-
log
|
|
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)
|
|
4239
4298
|
] })
|
|
4240
4299
|
] });
|
|
4241
4300
|
};
|
|
4242
|
-
var
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
const list = fs7.readdirSync(cwd).filter((f) => !f.startsWith(".")).slice(0, 15);
|
|
4248
|
-
setFiles(list);
|
|
4249
|
-
} catch {
|
|
4250
|
-
setFiles(["<Error reading dir>"]);
|
|
4251
|
-
}
|
|
4252
|
-
};
|
|
4253
|
-
refresh();
|
|
4254
|
-
const timer = setInterval(refresh, 2e3);
|
|
4255
|
-
return () => clearInterval(timer);
|
|
4256
|
-
}, [cwd, lastChange]);
|
|
4257
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", title: " FILESYSTEM ", width: "30%", children: [
|
|
4258
|
-
/* @__PURE__ */ jsxs(Text, { color: "cyan", bold: true, children: [
|
|
4259
|
-
" ",
|
|
4260
|
-
cwd.length > 30 ? "..." + cwd.slice(-30) : cwd
|
|
4261
|
-
] }),
|
|
4262
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
4263
|
-
files.map((f, i) => /* @__PURE__ */ jsxs(Text, { color: "white", children: [
|
|
4264
|
-
fs7.statSync(path7.join(cwd, f)).isDirectory() ? "\u{1F4C1} " : "\u{1F4C4} ",
|
|
4265
|
-
f
|
|
4266
|
-
] }, i)),
|
|
4267
|
-
files.length === 0 && /* @__PURE__ */ jsx(Text, { color: "gray", children: " (empty)" })
|
|
4268
|
-
] })
|
|
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)) })
|
|
4269
4306
|
] });
|
|
4270
4307
|
};
|
|
4271
|
-
var
|
|
4272
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column",
|
|
4273
|
-
|
|
4274
|
-
/* @__PURE__ */
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
"
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
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
|
+
] })
|
|
4283
4330
|
] });
|
|
4284
4331
|
};
|
|
4285
|
-
var
|
|
4332
|
+
var ChatArea = ({ history, onSend, placeholder }) => {
|
|
4286
4333
|
const [query, setQuery] = useState("");
|
|
4287
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", borderStyle: "
|
|
4288
|
-
/* @__PURE__ */ jsx(Box, {
|
|
4289
|
-
|
|
4290
|
-
/* @__PURE__ */ jsx(Text, {
|
|
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 })
|
|
4291
4342
|
] }, i)) }),
|
|
4292
|
-
/* @__PURE__ */
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
}
|
|
4305
|
-
)
|
|
4306
|
-
] })
|
|
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
|
+
) })
|
|
4307
4355
|
] });
|
|
4308
4356
|
};
|
|
4309
4357
|
var Dashboard = () => {
|
|
4310
4358
|
const { exit } = useApp();
|
|
4311
4359
|
const [cwd, setCwd] = useState(process.cwd());
|
|
4312
|
-
const [logs, setLogs] = useState(["System ready.", "Initializing Neural Link..."]);
|
|
4313
4360
|
const [chatHistory, setChatHistory] = useState([]);
|
|
4314
4361
|
const [step, setStep] = useState("safety");
|
|
4315
4362
|
const [pendingAction, setPendingAction] = useState(null);
|
|
4316
|
-
const [
|
|
4317
|
-
const [
|
|
4363
|
+
const [activeFiles, setActiveFiles] = useState([]);
|
|
4364
|
+
const [agentStatus, setAgentStatus] = useState("IDLE");
|
|
4318
4365
|
useEffect(() => {
|
|
4319
4366
|
const handleEvent = (event) => {
|
|
4320
4367
|
if (event.type === "handoff") {
|
|
4321
|
-
|
|
4368
|
+
setAgentStatus(event.role.toUpperCase());
|
|
4322
4369
|
}
|
|
4323
|
-
if (event.type === "
|
|
4324
|
-
|
|
4370
|
+
if (event.type === "thought") {
|
|
4371
|
+
if (!event.message.startsWith("Analyzing")) {
|
|
4372
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `[${event.agentName}] ${event.message}` }]);
|
|
4373
|
+
}
|
|
4325
4374
|
}
|
|
4326
|
-
if (event.message.includes("Created:")
|
|
4327
|
-
|
|
4375
|
+
if (event.message.includes("Created:")) {
|
|
4376
|
+
const filename = event.message.split("Created:")[1].trim();
|
|
4377
|
+
setActiveFiles((prev) => [filename, ...prev].slice(0, 5));
|
|
4328
4378
|
}
|
|
4329
4379
|
};
|
|
4330
4380
|
agentEventBus.on("agent_event", handleEvent);
|
|
@@ -4339,13 +4389,12 @@ var Dashboard = () => {
|
|
|
4339
4389
|
const isUnsafe = cwd === home || cwd === root;
|
|
4340
4390
|
if (isUnsafe) {
|
|
4341
4391
|
setChatHistory([
|
|
4342
|
-
{ role: "system", text: `\u26A0\uFE0F
|
|
4343
|
-
{ role: "ai", text: "
|
|
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)" }
|
|
4344
4394
|
]);
|
|
4345
4395
|
setPendingAction("safety_confirm");
|
|
4346
4396
|
} else {
|
|
4347
4397
|
setStep("prompt");
|
|
4348
|
-
setChatHistory([{ role: "ai", text: "Safety check passed. What are we building today?" }]);
|
|
4349
4398
|
}
|
|
4350
4399
|
}
|
|
4351
4400
|
}, []);
|
|
@@ -4354,13 +4403,12 @@ var Dashboard = () => {
|
|
|
4354
4403
|
setChatHistory((prev) => [...prev, { role: "user", text: cmd }]);
|
|
4355
4404
|
if (step === "safety" && pendingAction === "safety_confirm") {
|
|
4356
4405
|
if (cmd.toLowerCase().startsWith("y")) {
|
|
4357
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "
|
|
4406
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Name your project:" }]);
|
|
4358
4407
|
setPendingAction("create_folder");
|
|
4359
4408
|
} else {
|
|
4360
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "
|
|
4409
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Proceeding in current directory." }]);
|
|
4361
4410
|
setStep("prompt");
|
|
4362
4411
|
setPendingAction(null);
|
|
4363
|
-
setTimeout(() => setChatHistory((prev) => [...prev, { role: "ai", text: "What are we building today?" }]), 500);
|
|
4364
4412
|
}
|
|
4365
4413
|
return;
|
|
4366
4414
|
}
|
|
@@ -4370,20 +4418,17 @@ var Dashboard = () => {
|
|
|
4370
4418
|
if (!fs7.existsSync(newPath)) fs7.mkdirSync(newPath);
|
|
4371
4419
|
process.chdir(newPath);
|
|
4372
4420
|
setCwd(newPath);
|
|
4373
|
-
setLogs((prev) => [...prev, `Switched directory to ${newPath}`]);
|
|
4374
4421
|
setChatHistory((prev) => [...prev, { role: "system", text: `\u{1F4C2} Switched to ${newPath}` }]);
|
|
4375
4422
|
setStep("prompt");
|
|
4376
4423
|
setPendingAction(null);
|
|
4377
|
-
setTimeout(() => setChatHistory((prev) => [...prev, { role: "ai", text: "What are we building today?" }]), 500);
|
|
4378
4424
|
} catch (e) {
|
|
4379
|
-
setChatHistory((prev) => [...prev, { role: "system", text: `Error
|
|
4425
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `Error: ${e}` }]);
|
|
4380
4426
|
}
|
|
4381
4427
|
return;
|
|
4382
4428
|
}
|
|
4383
4429
|
if (step === "prompt") {
|
|
4384
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "Analyzing requirements..." }]);
|
|
4385
4430
|
setStep("active");
|
|
4386
|
-
|
|
4431
|
+
setAgentStatus("MANAGER");
|
|
4387
4432
|
const activeConfig = getActiveProvider();
|
|
4388
4433
|
if (!activeConfig) {
|
|
4389
4434
|
setChatHistory((prev) => [...prev, { role: "system", text: '\u274C No API key found. Run "agdi auth" first.' }]);
|
|
@@ -4396,51 +4441,27 @@ var Dashboard = () => {
|
|
|
4396
4441
|
runSquadCommand(cmd, llm, {
|
|
4397
4442
|
output: cwd,
|
|
4398
4443
|
verbose: false,
|
|
4399
|
-
// We handle logs via event bus now
|
|
4400
4444
|
deploy: false
|
|
4401
4445
|
}).then(() => {
|
|
4402
|
-
|
|
4403
|
-
setChatHistory((prev) => [...prev, { role: "ai", text: "
|
|
4446
|
+
setAgentStatus("IDLE");
|
|
4447
|
+
setChatHistory((prev) => [...prev, { role: "ai", text: "Task completed." }]);
|
|
4404
4448
|
}).catch((err) => {
|
|
4405
|
-
|
|
4406
|
-
setChatHistory((prev) => [...prev, { role: "system", text:
|
|
4449
|
+
setAgentStatus("ERROR");
|
|
4450
|
+
setChatHistory((prev) => [...prev, { role: "system", text: `Error: ${err.message}` }]);
|
|
4407
4451
|
});
|
|
4408
4452
|
}
|
|
4409
4453
|
};
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
return "green";
|
|
4422
|
-
case "ERROR":
|
|
4423
|
-
return "red";
|
|
4424
|
-
default:
|
|
4425
|
-
return "gray";
|
|
4426
|
-
}
|
|
4427
|
-
};
|
|
4428
|
-
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [
|
|
4429
|
-
/* @__PURE__ */ jsxs(Box, { justifyContent: "space-between", marginBottom: 1, children: [
|
|
4430
|
-
/* @__PURE__ */ jsx(Text, { bold: true, color: "cyan", children: "AGDI v3.3.2 [ONLINE]" }),
|
|
4431
|
-
/* @__PURE__ */ jsxs(Text, { color: getStatusColor(), children: [
|
|
4432
|
-
"AGENT: ",
|
|
4433
|
-
activeAgent,
|
|
4434
|
-
" ",
|
|
4435
|
-
activeAgent !== "IDLE" && /* @__PURE__ */ jsx(Spinner, { type: "dots" })
|
|
4436
|
-
] }),
|
|
4437
|
-
/* @__PURE__ */ jsx(Text, { color: "gray", children: "NET: CONNECTED" })
|
|
4438
|
-
] }),
|
|
4439
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [
|
|
4440
|
-
/* @__PURE__ */ jsx(FileExplorer, { cwd, lastChange: lastFileChange }),
|
|
4441
|
-
/* @__PURE__ */ jsx(LogPanel, { logs })
|
|
4442
|
-
] }),
|
|
4443
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 0, children: /* @__PURE__ */ jsx(ChatPanel, { history: chatHistory, onSend: handleCommand, placeholder: step === "prompt" ? "Describe your app..." : "" }) })
|
|
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 })
|
|
4444
4465
|
] });
|
|
4445
4466
|
};
|
|
4446
4467
|
var App = () => {
|
|
@@ -4465,7 +4486,7 @@ ${chalk14.cyan(`/_/ |_|\\_, /\\__,_//_/ `)}
|
|
|
4465
4486
|
${chalk14.cyan(` /____/ `)}
|
|
4466
4487
|
`;
|
|
4467
4488
|
var program = new Command();
|
|
4468
|
-
program.name("agdi").description(chalk14.cyan("\u{1F9B8} The Autonomous AI Employee")).version("3.3.
|
|
4489
|
+
program.name("agdi").description(chalk14.cyan("\u{1F9B8} The Autonomous AI Employee")).version("3.3.4").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)");
|
|
4469
4490
|
program.hook("preAction", (thisCommand) => {
|
|
4470
4491
|
const opts = thisCommand.opts();
|
|
4471
4492
|
if (opts.yes) {
|
package/package.json
CHANGED
package/dist/chunk-AEWEBMJY.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// src/core/event-bus.ts
|
|
2
|
-
import { EventEmitter } from "events";
|
|
3
|
-
var agentEventBus = new EventEmitter();
|
|
4
|
-
function emitAgentEvent(event) {
|
|
5
|
-
agentEventBus.emit("agent_event", {
|
|
6
|
-
...event,
|
|
7
|
-
timestamp: Date.now()
|
|
8
|
-
});
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export {
|
|
12
|
-
agentEventBus,
|
|
13
|
-
emitAgentEvent
|
|
14
|
-
};
|