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 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@latest
18
+ npx --yes agent-hub-sdd@0.1.6
19
19
  ```
20
20
 
21
- Isso abre a **janela** do app. Na primeira vez o npm baixa o Electron e o Next. Se uma versão antiga ficou em cache e a janela não sobe, use a versão explícita:
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
- npx --yes agent-hub-sdd@0.1.4
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
- const raw = app.isPackaged ? path.join(process.resourcesPath, "hub") : repoRoot;
22
- return stageHub(raw);
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 isUp() {
83
+ function hubHtml() {
81
84
  return new Promise((resolve) => {
82
85
  const req = http.get(HUB, (res) => {
83
- res.resume();
84
- resolve(true);
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(false));
87
- req.setTimeout(800, () => {
95
+ req.on("error", () => resolve(null));
96
+ req.setTimeout(20000, () => {
88
97
  req.destroy();
89
- resolve(false);
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 args = app.isPackaged
102
- ? [path.join(cwd, "server.js")]
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 < 180; i++) {
141
- if (await isUp()) return;
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(HUB);
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
- if (!(await isUp())) {
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 waitForHub(startedServer ? child : null);
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\nO app precisa do Node.js 20+ (o mesmo node do npx). Instale em https://nodejs.org/ e rode: npx --yes agent-hub-sdd@0.1.4`,
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.4" }));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-hub-sdd",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "private": false,
5
5
  "license": "MIT",
6
6
  "author": "Agent Hub",
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"
@@ -7,8 +7,8 @@
7
7
  @theme inline {
8
8
  --color-background: var(--background);
9
9
  --color-foreground: var(--foreground);
10
- --font-sans: var(--font-geist-sans);
11
- --font-mono: var(--font-geist-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);
@@ -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 />