agent-hub-sdd 0.1.4 → 0.1.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/README.md +16 -3
- package/electron/main.mjs +49 -17
- package/electron/stage-hub.test.ts +1 -1
- package/next.config.ts +1 -0
- package/package.json +1 -1
- package/scripts/cli.cjs +2 -0
- package/scripts/kill-hub.ps1 +11 -0
- package/src/app/globals.css +2 -2
- package/src/app/layout.tsx +1 -15
package/README.md
CHANGED
|
@@ -15,13 +15,26 @@ npm run app
|
|
|
15
15
|
Pelo npm (precisa do Node 20+ no PATH):
|
|
16
16
|
|
|
17
17
|
```powershell
|
|
18
|
-
npx --yes agent-hub-sdd@
|
|
18
|
+
npx --yes agent-hub-sdd@0.1.6
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
Na primeira abertura a janela diz que está compilando. O **N** no canto é o Next.js em modo dev, não o app. Sem `@0.1.6`, o Windows pode reusar cache antigo.
|
|
22
|
+
|
|
23
|
+
Se ainda abrir a 0.1.2, ou se o npm disser `EBUSY` / `resource busy or locked`, o Next da tentativa antiga ainda está com o cache aberto. O `Stop-Process electron` não mata esse `node`:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
Get-CimInstance Win32_Process | Where-Object {
|
|
27
|
+
$_.CommandLine -and ($_.CommandLine -match 'agent-hub|_npx|next dev|43147')
|
|
28
|
+
} | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }
|
|
29
|
+
Remove-Item -Recurse -Force "$env:LOCALAPPDATA\npm-cache\_npx" -ErrorAction SilentlyContinue
|
|
30
|
+
npx --yes agent-hub-sdd@0.1.6
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Instalar global evita o rename do `npx` nessa pasta:
|
|
22
34
|
|
|
23
35
|
```powershell
|
|
24
|
-
|
|
36
|
+
npm install -g agent-hub-sdd@0.1.6
|
|
37
|
+
agent-hub-sdd
|
|
25
38
|
```
|
|
26
39
|
|
|
27
40
|
## App no Windows (a partir do código)
|
package/electron/main.mjs
CHANGED
|
@@ -11,6 +11,7 @@ const PORT = Number(process.env.AGENT_HUB_PORT || 43147);
|
|
|
11
11
|
const HUB = `http://127.0.0.1:${PORT}`;
|
|
12
12
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
const repoRoot = path.join(here, "..");
|
|
14
|
+
const VERSION = JSON.parse(fs.readFileSync(path.join(repoRoot, "package.json"), "utf8")).version;
|
|
14
15
|
|
|
15
16
|
let win;
|
|
16
17
|
let child;
|
|
@@ -18,8 +19,10 @@ let startedServer = false;
|
|
|
18
19
|
let logs = "";
|
|
19
20
|
|
|
20
21
|
function hubDir() {
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
if (app.isPackaged) return path.join(process.resourcesPath, "hub");
|
|
23
|
+
const dist = path.join(repoRoot, "dist-hub");
|
|
24
|
+
if (fs.existsSync(path.join(dist, "server.js"))) return dist;
|
|
25
|
+
return stageHub(repoRoot);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
function nodeName() {
|
|
@@ -77,20 +80,32 @@ function withNodeOnPath(env, node) {
|
|
|
77
80
|
return next;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
function
|
|
83
|
+
function hubHtml() {
|
|
81
84
|
return new Promise((resolve) => {
|
|
82
85
|
const req = http.get(HUB, (res) => {
|
|
83
|
-
|
|
84
|
-
|
|
86
|
+
const chunks = [];
|
|
87
|
+
res.on("data", (chunk) => {
|
|
88
|
+
chunks.push(chunk);
|
|
89
|
+
if (Buffer.concat(chunks).length > 40000) res.destroy();
|
|
90
|
+
});
|
|
91
|
+
res.on("end", () => {
|
|
92
|
+
resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks).toString("utf8") });
|
|
93
|
+
});
|
|
85
94
|
});
|
|
86
|
-
req.on("error", () => resolve(
|
|
87
|
-
req.setTimeout(
|
|
95
|
+
req.on("error", () => resolve(null));
|
|
96
|
+
req.setTimeout(20000, () => {
|
|
88
97
|
req.destroy();
|
|
89
|
-
resolve(
|
|
98
|
+
resolve(null);
|
|
90
99
|
});
|
|
91
100
|
});
|
|
92
101
|
}
|
|
93
102
|
|
|
103
|
+
function pageReady(html) {
|
|
104
|
+
if (!html) return false;
|
|
105
|
+
if (/Can't resolve|Module not found|Module parse failed/.test(html.body)) return false;
|
|
106
|
+
return html.status === 200 && /Agent Hub|Carregando o hub/.test(html.body);
|
|
107
|
+
}
|
|
108
|
+
|
|
94
109
|
function note(chunk) {
|
|
95
110
|
logs = (logs + chunk.toString()).slice(-8000);
|
|
96
111
|
}
|
|
@@ -98,8 +113,9 @@ function note(chunk) {
|
|
|
98
113
|
function startServer() {
|
|
99
114
|
const cwd = hubDir();
|
|
100
115
|
const node = nodeBin();
|
|
101
|
-
const
|
|
102
|
-
|
|
116
|
+
const serverJs = path.join(cwd, "server.js");
|
|
117
|
+
const args = fs.existsSync(serverJs)
|
|
118
|
+
? [serverJs]
|
|
103
119
|
: [nextBin(cwd), "dev", "--webpack", "-H", "127.0.0.1", "-p", String(PORT)];
|
|
104
120
|
const env = withNodeOnPath(
|
|
105
121
|
{ ...process.env, HOSTNAME: "127.0.0.1", PORT: String(PORT) },
|
|
@@ -137,8 +153,12 @@ async function waitForHub(proc) {
|
|
|
137
153
|
proc?.once("exit", (code) => {
|
|
138
154
|
exited = code ?? 1;
|
|
139
155
|
});
|
|
140
|
-
for (let i = 0; i <
|
|
141
|
-
|
|
156
|
+
for (let i = 0; i < 24; i++) {
|
|
157
|
+
const html = await hubHtml();
|
|
158
|
+
if (pageReady(html)) return;
|
|
159
|
+
if (html?.body && /Can't resolve|Module not found|Module parse failed/.test(html.body)) {
|
|
160
|
+
throw new Error(`Falha ao compilar o hub.\n${html.body.slice(0, 1500)}`);
|
|
161
|
+
}
|
|
142
162
|
if (exited !== undefined) {
|
|
143
163
|
throw new Error(`O servidor saiu com código ${exited}.\n${logs.trim() || "Sem log."}`);
|
|
144
164
|
}
|
|
@@ -172,7 +192,17 @@ function createWindow() {
|
|
|
172
192
|
},
|
|
173
193
|
});
|
|
174
194
|
win.once("ready-to-show", () => win.show());
|
|
175
|
-
win.loadURL(
|
|
195
|
+
void win.loadURL(
|
|
196
|
+
`data:text/html;charset=utf-8,${encodeURIComponent(`<!doctype html>
|
|
197
|
+
<html lang="pt-BR">
|
|
198
|
+
<body style="margin:0;background:#000;color:#e4e4e7;font-family:'Segoe UI',sans-serif;display:flex;min-height:100vh;align-items:center;justify-content:center">
|
|
199
|
+
<div style="text-align:center;max-width:28rem;padding:1.5rem">
|
|
200
|
+
<p style="font-size:1.15rem;margin:0 0 .75rem">Agent Hub ${VERSION}</p>
|
|
201
|
+
<p style="color:#a1a1aa;line-height:1.6;margin:0">Primeira abertura compila o hub. Pode levar alguns minutos. Não feche a janela.</p>
|
|
202
|
+
</div>
|
|
203
|
+
</body>
|
|
204
|
+
</html>`)}`,
|
|
205
|
+
);
|
|
176
206
|
win.webContents.setWindowOpenHandler(({ url }) => {
|
|
177
207
|
void shell.openExternal(url);
|
|
178
208
|
return { action: "deny" };
|
|
@@ -191,18 +221,20 @@ ipcMain.handle("pick-folder", async () => {
|
|
|
191
221
|
|
|
192
222
|
app.whenReady().then(async () => {
|
|
193
223
|
try {
|
|
194
|
-
|
|
224
|
+
createWindow();
|
|
225
|
+
const html = await hubHtml();
|
|
226
|
+
if (!pageReady(html)) {
|
|
195
227
|
child = startServer();
|
|
196
228
|
startedServer = true;
|
|
229
|
+
await waitForHub(child);
|
|
197
230
|
}
|
|
198
|
-
await
|
|
199
|
-
createWindow();
|
|
231
|
+
await win.loadURL(HUB);
|
|
200
232
|
} catch (error) {
|
|
201
233
|
stopServer();
|
|
202
234
|
const message = error instanceof Error ? error.message : String(error);
|
|
203
235
|
await dialog.showErrorBox(
|
|
204
236
|
"Agent Hub",
|
|
205
|
-
`${message}\n\
|
|
237
|
+
`${message}\n\nAgent Hub ${VERSION}. O app precisa do Node.js 20+ (o mesmo node do npx).\nRode: npx --yes agent-hub-sdd@${VERSION}`,
|
|
206
238
|
);
|
|
207
239
|
app.quit();
|
|
208
240
|
}
|
|
@@ -21,7 +21,7 @@ describe("stageHub", () => {
|
|
|
21
21
|
temps.push(root);
|
|
22
22
|
const pkg = path.join(root, "node_modules", "agent-hub-sdd");
|
|
23
23
|
fs.mkdirSync(path.join(pkg, "src", "components"), { recursive: true });
|
|
24
|
-
fs.writeFileSync(path.join(pkg, "package.json"), JSON.stringify({ name: "agent-hub-sdd", version: "0.1.
|
|
24
|
+
fs.writeFileSync(path.join(pkg, "package.json"), JSON.stringify({ name: "agent-hub-sdd", version: "0.1.6" }));
|
|
25
25
|
fs.writeFileSync(path.join(pkg, "src", "components", "desktop-chrome.tsx"), "export const DesktopChrome = () => null;\n");
|
|
26
26
|
fs.writeFileSync(path.join(root, "node_modules", "sentinel"), "ok");
|
|
27
27
|
const dest = path.join(root, "runtime");
|
package/next.config.ts
CHANGED
|
@@ -12,6 +12,7 @@ const nextConfig: NextConfig = {
|
|
|
12
12
|
cacheComponents: false,
|
|
13
13
|
partialPrefetching: false,
|
|
14
14
|
agentRules: false,
|
|
15
|
+
devIndicators: false,
|
|
15
16
|
// npx installs this app under node_modules. Next's tsconfig-paths plugin
|
|
16
17
|
// skips any importer in node_modules, so @/ would 404 without a webpack alias.
|
|
17
18
|
webpack: (config) => {
|
package/package.json
CHANGED
package/scripts/cli.cjs
CHANGED
|
@@ -3,6 +3,8 @@ const { spawn } = require("node:child_process");
|
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
|
|
5
5
|
const root = path.join(__dirname, "..");
|
|
6
|
+
const pkg = require(path.join(root, "package.json"));
|
|
7
|
+
console.log(`Agent Hub ${pkg.version}`);
|
|
6
8
|
let electron;
|
|
7
9
|
try {
|
|
8
10
|
electron = require("electron");
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
$ErrorActionPreference = "SilentlyContinue"
|
|
2
|
+
Get-CimInstance Win32_Process |
|
|
3
|
+
Where-Object {
|
|
4
|
+
$_.CommandLine -and
|
|
5
|
+
($_.CommandLine -match "agent-hub|_npx|next dev|43147")
|
|
6
|
+
} |
|
|
7
|
+
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
|
|
8
|
+
Stop-Process -Name electron -Force
|
|
9
|
+
$npx = Join-Path $env:LOCALAPPDATA "npm-cache\_npx"
|
|
10
|
+
if (Test-Path $npx) { Remove-Item -Recurse -Force $npx }
|
|
11
|
+
Write-Host "Cache do npx limpo. Rode: npx --yes agent-hub-sdd@0.1.6"
|
package/src/app/globals.css
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
@theme inline {
|
|
8
8
|
--color-background: var(--background);
|
|
9
9
|
--color-foreground: var(--foreground);
|
|
10
|
-
--font-sans:
|
|
11
|
-
--font-mono:
|
|
10
|
+
--font-sans: "Segoe UI", ui-sans-serif, system-ui, sans-serif;
|
|
11
|
+
--font-mono: "Cascadia Mono", Consolas, ui-monospace, monospace;
|
|
12
12
|
--font-heading: var(--font-sans);
|
|
13
13
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
14
14
|
--color-sidebar-border: var(--sidebar-border);
|
package/src/app/layout.tsx
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
1
|
import type { Metadata } from "next";
|
|
2
|
-
import { Geist, Geist_Mono } from "next/font/google";
|
|
3
2
|
import { DesktopChrome } from "@/components/desktop-chrome";
|
|
4
3
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
5
4
|
import "./globals.css";
|
|
6
5
|
|
|
7
|
-
const geistSans = Geist({
|
|
8
|
-
variable: "--font-geist-sans",
|
|
9
|
-
subsets: ["latin"],
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const geistMono = Geist_Mono({
|
|
13
|
-
variable: "--font-geist-mono",
|
|
14
|
-
subsets: ["latin"],
|
|
15
|
-
});
|
|
16
|
-
|
|
17
6
|
export const metadata: Metadata = {
|
|
18
7
|
title: "Agent Hub",
|
|
19
8
|
description: "Harness visual local para agentes do SDLC",
|
|
@@ -21,10 +10,7 @@ export const metadata: Metadata = {
|
|
|
21
10
|
|
|
22
11
|
export default function RootLayout({ children }: LayoutProps<"/">) {
|
|
23
12
|
return (
|
|
24
|
-
<html
|
|
25
|
-
lang="pt-BR"
|
|
26
|
-
className={`${geistSans.variable} ${geistMono.variable} dark h-full antialiased`}
|
|
27
|
-
>
|
|
13
|
+
<html lang="pt-BR" className="dark h-full antialiased">
|
|
28
14
|
<body className="flex min-h-dvh flex-col bg-black text-zinc-100">
|
|
29
15
|
<TooltipProvider>
|
|
30
16
|
<DesktopChrome />
|