build(control-ui): prefer bun for UI build
This commit is contained in:
@@ -133,7 +133,7 @@
|
|||||||
- Env: load global `$CLAWDBOT_STATE_DIR/.env` (`~/.clawdbot/.env`) as a fallback after CWD `.env`.
|
- Env: load global `$CLAWDBOT_STATE_DIR/.env` (`~/.clawdbot/.env`) as a fallback after CWD `.env`.
|
||||||
- Env: optional login-shell env fallback (opt-in; imports expected keys without overriding existing env).
|
- Env: optional login-shell env fallback (opt-in; imports expected keys without overriding existing env).
|
||||||
- Agent tools: OpenAI-compatible tool JSON Schemas (fix `browser`, normalize union schemas).
|
- Agent tools: OpenAI-compatible tool JSON Schemas (fix `browser`, normalize union schemas).
|
||||||
- Onboarding: when running from source, auto-build missing Control UI assets (`pnpm ui:build`).
|
- Onboarding: when running from source, auto-build missing Control UI assets (`bun run ui:build`).
|
||||||
- Discord/Slack: route reaction + system notifications to the correct session (no main-session bleed).
|
- Discord/Slack: route reaction + system notifications to the correct session (no main-session bleed).
|
||||||
- Agent tools: honor `agent.tools` allow/deny policy even when sandbox is off.
|
- Agent tools: honor `agent.tools` allow/deny policy even when sandbox is off.
|
||||||
- Discord: avoid duplicate replies when OpenAI emits repeated `message_end` events.
|
- Discord: avoid duplicate replies when OpenAI emits repeated `message_end` events.
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -40,10 +40,10 @@ Do **not** download prebuilt binaries. Build from source.
|
|||||||
git clone https://github.com/clawdbot/clawdbot.git
|
git clone https://github.com/clawdbot/clawdbot.git
|
||||||
cd clawdbot
|
cd clawdbot
|
||||||
|
|
||||||
pnpm install
|
bun install
|
||||||
pnpm build
|
bun run build
|
||||||
pnpm ui:build
|
bun run ui:build
|
||||||
pnpm clawdbot onboard
|
bun run clawdbot onboard
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick start (from source)
|
## Quick start (from source)
|
||||||
@@ -442,5 +442,5 @@ Thanks to all clawtributors:
|
|||||||
<a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a> <a href="https://github.com/osolmaz"><img src="https://avatars.githubusercontent.com/u/2453968?v=4&s=48" width="48" height="48" alt="osolmaz" title="osolmaz"/></a> <a href="https://github.com/conhecendocontato"><img src="https://avatars.githubusercontent.com/u/82890727?v=4&s=48" width="48" height="48" alt="conhecendocontato" title="conhecendocontato"/></a> <a href="https://github.com/hrdwdmrbl"><img src="https://avatars.githubusercontent.com/u/554881?v=4&s=48" width="48" height="48" alt="hrdwdmrbl" title="hrdwdmrbl"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a> <a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a> <a href="https://github.com/gtsifrikas"><img src="https://avatars.githubusercontent.com/u/8904378?v=4&s=48" width="48" height="48" alt="gtsifrikas" title="gtsifrikas"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="djangonavarro220" title="djangonavarro220"/></a>
|
<a href="https://github.com/scald"><img src="https://avatars.githubusercontent.com/u/1215913?v=4&s=48" width="48" height="48" alt="scald" title="scald"/></a> <a href="https://github.com/sreekaransrinath"><img src="https://avatars.githubusercontent.com/u/50989977?v=4&s=48" width="48" height="48" alt="sreekaransrinath" title="sreekaransrinath"/></a> <a href="https://github.com/ratulsarna"><img src="https://avatars.githubusercontent.com/u/105903728?v=4&s=48" width="48" height="48" alt="ratulsarna" title="ratulsarna"/></a> <a href="https://github.com/osolmaz"><img src="https://avatars.githubusercontent.com/u/2453968?v=4&s=48" width="48" height="48" alt="osolmaz" title="osolmaz"/></a> <a href="https://github.com/conhecendocontato"><img src="https://avatars.githubusercontent.com/u/82890727?v=4&s=48" width="48" height="48" alt="conhecendocontato" title="conhecendocontato"/></a> <a href="https://github.com/hrdwdmrbl"><img src="https://avatars.githubusercontent.com/u/554881?v=4&s=48" width="48" height="48" alt="hrdwdmrbl" title="hrdwdmrbl"/></a> <a href="https://github.com/jayhickey"><img src="https://avatars.githubusercontent.com/u/1676460?v=4&s=48" width="48" height="48" alt="jayhickey" title="jayhickey"/></a> <a href="https://github.com/jamesgroat"><img src="https://avatars.githubusercontent.com/u/2634024?v=4&s=48" width="48" height="48" alt="jamesgroat" title="jamesgroat"/></a> <a href="https://github.com/gtsifrikas"><img src="https://avatars.githubusercontent.com/u/8904378?v=4&s=48" width="48" height="48" alt="gtsifrikas" title="gtsifrikas"/></a> <a href="https://github.com/djangonavarro220"><img src="https://avatars.githubusercontent.com/u/251162586?v=4&s=48" width="48" height="48" alt="djangonavarro220" title="djangonavarro220"/></a>
|
||||||
<a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a>
|
<a href="https://github.com/azade-c"><img src="https://avatars.githubusercontent.com/u/252790079?v=4&s=48" width="48" height="48" alt="azade-c" title="azade-c"/></a> <a href="https://github.com/andranik-sahakyan"><img src="https://avatars.githubusercontent.com/u/8908029?v=4&s=48" width="48" height="48" alt="andranik-sahakyan" title="andranik-sahakyan"/></a>
|
||||||
<a href="https://github.com/adamgall"><img src="https://avatars.githubusercontent.com/u/706929?v=4&s=48" width="48" height="48" alt="adamgall" title="adamgall"/></a> <a href="https://github.com/jalehman"><img src="https://avatars.githubusercontent.com/u/550978?v=4&s=48" width="48" height="48" alt="jalehman" title="jalehman"/></a> <a href="https://github.com/jarvis-medmatic"><img src="https://avatars.githubusercontent.com/u/252428873?v=4&s=48" width="48" height="48" alt="jarvis-medmatic" title="jarvis-medmatic"/></a> <a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a> <a href="https://github.com/regenrek"><img src="https://avatars.githubusercontent.com/u/5182020?v=4&s=48" width="48" height="48" alt="regenrek" title="regenrek"/></a> <a href="https://github.com/tobiasbischoff"><img src="https://avatars.githubusercontent.com/u/711564?v=4&s=48" width="48" height="48" alt="tobiasbischoff" title="tobiasbischoff"/></a> <a href="https://github.com/MSch"><img src="https://avatars.githubusercontent.com/u/7475?v=4&s=48" width="48" height="48" alt="MSch" title="MSch"/></a> <a href="https://github.com/obviyus"><img src="https://avatars.githubusercontent.com/u/22031114?v=4&s=48" width="48" height="48" alt="obviyus" title="obviyus"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a>
|
<a href="https://github.com/adamgall"><img src="https://avatars.githubusercontent.com/u/706929?v=4&s=48" width="48" height="48" alt="adamgall" title="adamgall"/></a> <a href="https://github.com/jalehman"><img src="https://avatars.githubusercontent.com/u/550978?v=4&s=48" width="48" height="48" alt="jalehman" title="jalehman"/></a> <a href="https://github.com/jarvis-medmatic"><img src="https://avatars.githubusercontent.com/u/252428873?v=4&s=48" width="48" height="48" alt="jarvis-medmatic" title="jarvis-medmatic"/></a> <a href="https://github.com/mneves75"><img src="https://avatars.githubusercontent.com/u/2423436?v=4&s=48" width="48" height="48" alt="mneves75" title="mneves75"/></a> <a href="https://github.com/regenrek"><img src="https://avatars.githubusercontent.com/u/5182020?v=4&s=48" width="48" height="48" alt="regenrek" title="regenrek"/></a> <a href="https://github.com/tobiasbischoff"><img src="https://avatars.githubusercontent.com/u/711564?v=4&s=48" width="48" height="48" alt="tobiasbischoff" title="tobiasbischoff"/></a> <a href="https://github.com/MSch"><img src="https://avatars.githubusercontent.com/u/7475?v=4&s=48" width="48" height="48" alt="MSch" title="MSch"/></a> <a href="https://github.com/obviyus"><img src="https://avatars.githubusercontent.com/u/22031114?v=4&s=48" width="48" height="48" alt="obviyus" title="obviyus"/></a> <a href="https://github.com/dbhurley"><img src="https://avatars.githubusercontent.com/u/5251425?v=4&s=48" width="48" height="48" alt="dbhurley" title="dbhurley"/></a>
|
||||||
<a href="https://github.com/Asleep123"><img src="https://avatars.githubusercontent.com/u/122379135?v=4&s=48" width="48" height="48" alt="Asleep123" title="Asleep123"/></a> <a href="https://github.com/Iamadig"><img src="https://avatars.githubusercontent.com/u/102129234?v=4&s=48" width="48" height="48" alt="Iamadig" title="Iamadig"/></a> <a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a>
|
<a href="https://github.com/Asleep123"><img src="https://avatars.githubusercontent.com/u/122379135?v=4&s=48" width="48" height="48" alt="Asleep123" title="Asleep123"/></a> <a href="https://github.com/Iamadig"><img src="https://avatars.githubusercontent.com/u/102129234?v=4&s=48" width="48" height="48" alt="Iamadig" title="Iamadig"/></a> <a href="https://github.com/imfing"><img src="https://avatars.githubusercontent.com/u/5097752?v=4&s=48" width="48" height="48" alt="imfing" title="imfing"/></a> <a href="https://github.com/kitze"><img src="https://avatars.githubusercontent.com/u/1160594?v=4&s=48" width="48" height="48" alt="kitze" title="kitze"/></a> <a href="https://github.com/nachoiacovino"><img src="https://avatars.githubusercontent.com/u/50103937?v=4&s=48" width="48" height="48" alt="nachoiacovino" title="nachoiacovino"/></a> <a href="https://github.com/VACInc"><img src="https://avatars.githubusercontent.com/u/3279061?v=4&s=48" width="48" height="48" alt="VACInc" title="VACInc"/></a> <a href="https://github.com/cash-echo-bot"><img src="https://avatars.githubusercontent.com/u/252747386?v=4&s=48" width="48" height="48" alt="cash-echo-bot" title="cash-echo-bot"/></a> <a href="https://github.com/claude"><img src="https://avatars.githubusercontent.com/u/81847?v=4&s=48" width="48" height="48" alt="claude" title="claude"/></a> <a href="https://github.com/kiranjd"><img src="https://avatars.githubusercontent.com/u/25822851?v=4&s=48" width="48" height="48" alt="kiranjd" title="kiranjd"/></a> <a href="https://github.com/pcty-nextgen-service-account"><img src="https://avatars.githubusercontent.com/u/112553441?v=4&s=48" width="48" height="48" alt="pcty-nextgen-service-account" title="pcty-nextgen-service-account"/></a>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -63,21 +63,21 @@ Paste the token into the UI settings (sent as `connect.params.auth.token`).
|
|||||||
The Gateway serves static files from `dist/control-ui`. Build them with:
|
The Gateway serves static files from `dist/control-ui`. Build them with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm ui:install
|
bun run ui:install
|
||||||
pnpm ui:build
|
bun run ui:build
|
||||||
```
|
```
|
||||||
|
|
||||||
Optional absolute base (when you want fixed asset URLs):
|
Optional absolute base (when you want fixed asset URLs):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
CLAWDBOT_CONTROL_UI_BASE_PATH=/clawdbot/ pnpm ui:build
|
CLAWDBOT_CONTROL_UI_BASE_PATH=/clawdbot/ bun run ui:build
|
||||||
```
|
```
|
||||||
|
|
||||||
For local development (separate dev server):
|
For local development (separate dev server):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm ui:install
|
bun run ui:install
|
||||||
pnpm ui:dev
|
bun run ui:dev
|
||||||
```
|
```
|
||||||
|
|
||||||
Then point the UI at your Gateway WS URL (e.g. `ws://127.0.0.1:18789`).
|
Then point the UI at your Gateway WS URL (e.g. `ws://127.0.0.1:18789`).
|
||||||
|
|||||||
@@ -110,6 +110,6 @@ Open:
|
|||||||
The Gateway serves static files from `dist/control-ui`. Build them with:
|
The Gateway serves static files from `dist/control-ui`. Build them with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm ui:install
|
bun run ui:install
|
||||||
pnpm ui:build
|
bun run ui:build
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -51,9 +51,9 @@
|
|||||||
"docs:build": "cd docs && pnpm dlx mint broken-links",
|
"docs:build": "cd docs && pnpm dlx mint broken-links",
|
||||||
"build": "tsc -p tsconfig.json && bun scripts/canvas-a2ui-copy.ts",
|
"build": "tsc -p tsconfig.json && bun scripts/canvas-a2ui-copy.ts",
|
||||||
"release:check": "bun scripts/release-check.ts",
|
"release:check": "bun scripts/release-check.ts",
|
||||||
"ui:install": "pnpm -C ui install",
|
"ui:install": "node scripts/ui.js install",
|
||||||
"ui:dev": "pnpm -C ui dev",
|
"ui:dev": "node scripts/ui.js dev",
|
||||||
"ui:build": "pnpm -C ui build",
|
"ui:build": "node scripts/ui.js build",
|
||||||
"start": "bun src/entry.ts",
|
"start": "bun src/entry.ts",
|
||||||
"clawdbot": "bun src/entry.ts",
|
"clawdbot": "bun src/entry.ts",
|
||||||
"gateway:watch": "bun --watch src/entry.ts gateway --force",
|
"gateway:watch": "bun --watch src/entry.ts gateway --force",
|
||||||
|
|||||||
@@ -146,8 +146,8 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${SKIP_UI_BUILD:-0}" != "1" ]]; then
|
if [[ "${SKIP_UI_BUILD:-0}" != "1" ]]; then
|
||||||
echo "🖥 Building Control UI (pnpm ui:build)"
|
echo "🖥 Building Control UI (ui:build)"
|
||||||
(cd "$ROOT_DIR" && pnpm ui:build)
|
(cd "$ROOT_DIR" && node scripts/ui.js build)
|
||||||
else
|
else
|
||||||
echo "🖥 Skipping Control UI build (SKIP_UI_BUILD=1)"
|
echo "🖥 Skipping Control UI build (SKIP_UI_BUILD=1)"
|
||||||
fi
|
fi
|
||||||
|
|||||||
102
scripts/ui.js
Normal file
102
scripts/ui.js
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
import { spawn } from "node:child_process";
|
||||||
|
import fs from "node:fs";
|
||||||
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
||||||
|
const repoRoot = path.resolve(here, "..");
|
||||||
|
const uiDir = path.join(repoRoot, "ui");
|
||||||
|
|
||||||
|
function usage() {
|
||||||
|
// keep this tiny; it's invoked from npm scripts too
|
||||||
|
process.stderr.write(
|
||||||
|
"Usage: node scripts/ui.js <install|dev|build|test> [...args]\n",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function which(cmd) {
|
||||||
|
try {
|
||||||
|
const key = process.platform === "win32" ? "Path" : "PATH";
|
||||||
|
const paths = (process.env[key] ?? process.env.PATH ?? "")
|
||||||
|
.split(path.delimiter)
|
||||||
|
.filter(Boolean);
|
||||||
|
const extensions =
|
||||||
|
process.platform === "win32"
|
||||||
|
? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM")
|
||||||
|
.split(";")
|
||||||
|
.filter(Boolean)
|
||||||
|
: [""];
|
||||||
|
for (const entry of paths) {
|
||||||
|
for (const ext of extensions) {
|
||||||
|
const candidate = path.join(entry, process.platform === "win32" ? `${cmd}${ext}` : cmd);
|
||||||
|
try {
|
||||||
|
if (fs.existsSync(candidate)) return candidate;
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveRunner() {
|
||||||
|
const bun = which("bun");
|
||||||
|
if (bun) return { cmd: bun, kind: "bun" };
|
||||||
|
const pnpm = which("pnpm");
|
||||||
|
if (pnpm) return { cmd: pnpm, kind: "pnpm" };
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function run(cmd, args) {
|
||||||
|
const child = spawn(cmd, args, {
|
||||||
|
cwd: uiDir,
|
||||||
|
stdio: "inherit",
|
||||||
|
env: process.env,
|
||||||
|
});
|
||||||
|
child.on("exit", (code, signal) => {
|
||||||
|
if (signal) process.exit(1);
|
||||||
|
process.exit(code ?? 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, , action, ...rest] = process.argv;
|
||||||
|
if (!action) {
|
||||||
|
usage();
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
const runner = resolveRunner();
|
||||||
|
if (!runner) {
|
||||||
|
process.stderr.write(
|
||||||
|
"Missing UI runner: install bun or pnpm, then retry.\n",
|
||||||
|
);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const script =
|
||||||
|
action === "install"
|
||||||
|
? null
|
||||||
|
: action === "dev"
|
||||||
|
? "dev"
|
||||||
|
: action === "build"
|
||||||
|
? "build"
|
||||||
|
: action === "test"
|
||||||
|
? "test"
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if (action !== "install" && !script) {
|
||||||
|
usage();
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (runner.kind === "bun") {
|
||||||
|
if (action === "install") run(runner.cmd, ["install", ...rest]);
|
||||||
|
else run(runner.cmd, ["run", script, ...rest]);
|
||||||
|
} else {
|
||||||
|
if (action === "install") run(runner.cmd, ["install", ...rest]);
|
||||||
|
else run(runner.cmd, ["run", script, ...rest]);
|
||||||
|
}
|
||||||
@@ -157,7 +157,7 @@ export function handleControlUiHttpRequest(
|
|||||||
res.statusCode = 503;
|
res.statusCode = 503;
|
||||||
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
||||||
res.end(
|
res.end(
|
||||||
"Control UI assets not found. Build them with `pnpm ui:build` (or run `pnpm ui:dev` during development).",
|
"Control UI assets not found. Build them with `bun run ui:build` (or run `bun run ui:dev` during development).",
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
|
||||||
import { runCommandWithTimeout, runExec } from "../process/exec.js";
|
import { runCommandWithTimeout } from "../process/exec.js";
|
||||||
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
import { defaultRuntime, type RuntimeEnv } from "../runtime.js";
|
||||||
|
|
||||||
export function resolveControlUiRepoRoot(
|
export function resolveControlUiRepoRoot(
|
||||||
@@ -76,7 +76,7 @@ export async function ensureControlUiAssetsBuilt(
|
|||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
built: false,
|
built: false,
|
||||||
message: `${hint}. Build them with \`pnpm ui:build\`.`,
|
message: `${hint}. Build them with \`bun run ui:build\`.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,35 +85,28 @@ export async function ensureControlUiAssetsBuilt(
|
|||||||
return { ok: true, built: false };
|
return { ok: true, built: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const pnpmWhich = process.platform === "win32" ? "where" : "which";
|
const uiScript = path.join(repoRoot, "scripts", "ui.js");
|
||||||
const pnpm = await runExec(pnpmWhich, ["pnpm"])
|
if (!fs.existsSync(uiScript)) {
|
||||||
.then(
|
|
||||||
(r) =>
|
|
||||||
r.stdout
|
|
||||||
.split(/\r?\n/g)
|
|
||||||
.map((l) => l.trim())
|
|
||||||
.find(Boolean) ?? "",
|
|
||||||
)
|
|
||||||
.catch(() => "");
|
|
||||||
if (!pnpm) {
|
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
built: false,
|
built: false,
|
||||||
message:
|
message: `Control UI assets missing but ${uiScript} is unavailable.`,
|
||||||
"Control UI assets not found and pnpm missing. Install pnpm, then run `pnpm ui:build`.",
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
runtime.log("Control UI assets missing; building (pnpm ui:build)…");
|
runtime.log("Control UI assets missing; building (ui:build)…");
|
||||||
|
|
||||||
const ensureInstalled = !fs.existsSync(
|
const ensureInstalled = !fs.existsSync(
|
||||||
path.join(repoRoot, "ui", "node_modules"),
|
path.join(repoRoot, "ui", "node_modules"),
|
||||||
);
|
);
|
||||||
if (ensureInstalled) {
|
if (ensureInstalled) {
|
||||||
const install = await runCommandWithTimeout([pnpm, "ui:install"], {
|
const install = await runCommandWithTimeout(
|
||||||
cwd: repoRoot,
|
[process.execPath, uiScript, "install"],
|
||||||
timeoutMs: opts?.timeoutMs ?? 10 * 60_000,
|
{
|
||||||
});
|
cwd: repoRoot,
|
||||||
|
timeoutMs: opts?.timeoutMs ?? 10 * 60_000,
|
||||||
|
},
|
||||||
|
);
|
||||||
if (install.code !== 0) {
|
if (install.code !== 0) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
@@ -123,10 +116,13 @@ export async function ensureControlUiAssetsBuilt(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const build = await runCommandWithTimeout([pnpm, "ui:build"], {
|
const build = await runCommandWithTimeout(
|
||||||
cwd: repoRoot,
|
[process.execPath, uiScript, "build"],
|
||||||
timeoutMs: opts?.timeoutMs ?? 10 * 60_000,
|
{
|
||||||
});
|
cwd: repoRoot,
|
||||||
|
timeoutMs: opts?.timeoutMs ?? 10 * 60_000,
|
||||||
|
},
|
||||||
|
);
|
||||||
if (build.code !== 0) {
|
if (build.code !== 0) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user