-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnext.config.ts
More file actions
124 lines (121 loc) · 5.52 KB
/
Copy pathnext.config.ts
File metadata and controls
124 lines (121 loc) · 5.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import type { NextConfig } from "next";
import { withSentryConfig } from "@sentry/nextjs";
import { execSync } from "node:child_process";
import { readFileSync } from "node:fs";
// Build-time version stamp — baked into the client bundle as NEXT_PUBLIC_* so
// the UI can show "which build is this" under the logo (and a changelog link).
// SHA is the precise build identity; the package version is the marketing
// semver. Computed once at build; on the box the push-deploy hook builds
// locally then rsyncs, so the SHA reflects the deployed commit. The desktop
// (Fleet Runner) version is read separately at runtime from the User-Agent
// (`FleetRunner/<ver>`, set in desktop/src/main/index.ts).
function buildSha(): string {
if (process.env.FLEETCROWN_BUILD_SHA) return process.env.FLEETCROWN_BUILD_SHA;
try {
return execSync("git rev-parse --short HEAD", {
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
}).trim();
} catch {
return "dev";
}
}
const PKG_VERSION = (() => {
try {
return (JSON.parse(readFileSync("./package.json", "utf8")) as { version: string }).version;
} catch {
return "0.0.0";
}
})();
const nextConfig: NextConfig = {
output: "standalone",
// Pin file tracing to the project dir. Without this, a build run inside a
// nested git worktree (.claude/worktrees/*) walks up to the outer checkout's
// lockfile as the inferred workspace root: server.js lands nested inside
// standalone/ and the traced externals (require-in-the-middle, node-pty)
// become symlinks that escape the tree — both shipped a broken standalone
// on 2026-07-28. `npm run build` always runs from the project dir.
outputFileTracingRoot: process.cwd(),
// node-pty is a native addon (compiled .node) — it must stay external, never
// bundled by Turbopack/webpack, and only runs in the Node runtime. It backs
// the LocalPtyExecutor (FleetCrown-owned agent PTYs). See
// docs/architecture/agent-execution-platform.md.
serverExternalPackages: ["node-pty"],
env: {
NEXT_PUBLIC_APP_VERSION: PKG_VERSION,
NEXT_PUBLIC_BUILD_SHA: buildSha(),
},
async redirects() {
return [
{ source: "/agents", destination: "/control", permanent: true },
{ source: "/atlas", destination: "/projects", permanent: true },
];
},
async headers() {
return [
{
source: "/sw.js",
headers: [
{ key: "Cache-Control", value: "no-cache, no-store, must-revalidate" },
{ key: "Service-Worker-Allowed", value: "/" },
],
},
];
},
outputFileTracingExcludes: {
"/api/agent/launch": ["./next.config.ts"],
"/api/system/doctor": ["./next.config.ts"],
// CRITICAL — without this glob the standalone build's per-route bundles
// ballooned (the tracer copies traced deps into each), wasting disk and
// build time. The desktop/ subtree is the Electron app + its
// node_modules + bundled Zellij (~35 MB) + AppImage build artifacts.
// It has NOTHING to do with the web app, but Next.js's output:
// "standalone" tracer was copying the whole tree into every function
// on the off chance any web code happened to import something from
// `desktop/`. Nothing does. The "*" key applies the exclusion to
// every route bundle.
"*": [
"./next.config.ts",
"./desktop/**",
// The v0.6 event bridge is its own Node service that runs on the box
// (alongside Postgres) — not part of the web app bundle. Excluding the
// directory keeps its node_modules out of every route bundle. Same
// lesson as desktop/.
"./bridge/**",
// AppImage extraction artifacts (e.g., from `./Fleet-Runner-*.AppImage
// --appimage-extract`) drop a `squashfs-root/` tree containing the
// full unpacked Electron app (~300 MB). It also has nothing to do
// with the web app; tracing was including it whenever a dev had
// extracted an AppImage in the repo root for inspection.
"./squashfs-root/**",
],
},
outputFileTracingIncludes: {
// Serves the @fleetcrown/agent CLI script to new customers (the package
// isn't published to npm yet and the repo is private). Without explicit
// tracing, the standalone tracer would drop the file from the build.
"/api/agent/install": ["./packages/agent/bin/**"],
// Markdown content read at runtime via process.cwd()/content (e.g. the
// /whitepaper page). Tracing it INTO the standalone build makes it
// deterministically present at .next/standalone/content/, instead of
// relying on the postbuild deploy-local.sh copy — which raced with the
// standalone recreate and intermittently left /whitepaper 500-ing
// (ENOENT content/whitepaper.md), repeatedly failing the pre-push smoke.
"/whitepaper": ["./content/**"],
// /api/agent/daemon's bash + python bundle entries are gone — Session 4 of
// killing-the-bash-daemon (2026-06-11) deleted the source files and the
// route now returns 410 Gone pointing at /download for Fleet Runner.
},
};
// Sentry build options — safe without env: sourcemap upload only runs when
// SENTRY_AUTH_TOKEN is set, so builds never fail on a missing token. The SDK
// itself is env-gated at runtime via NEXT_PUBLIC_SENTRY_DSN (see
// sentry.server.config.ts / sentry.edge.config.ts / src/instrumentation-client.ts).
export default withSentryConfig(nextConfig, {
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
silent: true,
sourcemaps: { disable: !process.env.SENTRY_AUTH_TOKEN },
telemetry: false,
});