Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
"debug:supertokens": "export DEBUG=com.supertokens &&bun run dev:backend",
"debug:web": "http-server build/web/",
"dev:backend -verbose": "export DEBUG=* &&bun run dev:backend",
"dev:backend": "bun run dev:ports && cd packages/backend && bun --watch src/app.ts",
"dev:backend": "bun run dev:ports backend && cd packages/backend && bun --watch src/app.ts",
"dev:ports": "bun packages/scripts/src/commands/dev-ports.ts",
"dev:update": "git checkout main && git pull &&bun install",
"dev:web": "bun run dev:ports && cd packages/web &&bun run dev.ts",
"dev:web": "bun run dev:ports web && cd packages/web &&bun run dev.ts",
"lint": "bun packages/scripts/src/testing/check-semantic-colors.ts && biome check .",
"lint:fix": "biome check --write .",
"format": "biome format --write .",
Expand Down Expand Up @@ -58,7 +58,7 @@
"@types/node": "^22.13.10",
"@types/node-fetch": "^2.6.13",
"axe-core": "^4.12.1",
"typescript": "^7.0.2"
"typescript": "7.0.2"
},
"resolutions": {
"glob": "^13.0.6",
Expand Down
53 changes: 51 additions & 2 deletions packages/scripts/src/commands/dev-ports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export interface DevPorts {
backend: number;
}

// Which dev server is launching, so the port-in-use warning only covers the
// service that's actually about to bind. Port reassignment stays pair-based.
export type Scope = "web" | "backend";

export function readPorts(yamlText: string): DevPorts | null {
try {
const config = parse(yamlText) as {
Expand Down Expand Up @@ -154,7 +158,47 @@ async function findNextPorts(claimed: DevPorts[]): Promise<DevPorts | null> {
return null;
}

async function main(): Promise<void> {
// Best-effort: PIDs listening on the given TCP port, or [] if none (or if
// lsof isn't available). Sibling-config detection can't see a stale process
// still bound to this worktree's own port, so we probe the live socket only
// to print a friendlier warning than the raw EADDRINUSE stack trace the dev
// server would otherwise throw.
function portHolders(port: number): string[] {
try {
const out = execSync(`lsof -nP -iTCP:${port} -sTCP:LISTEN -t`, {
encoding: "utf8",
stdio: ["ignore", "pipe", "ignore"],
});
return out
.split("\n")
.map((line) => line.trim())
.filter(Boolean);
} catch {
return []; // no holder (lsof exits non-zero) or lsof unavailable
}
}

// `scope` limits the check to the service actually being launched, so
// `dev:backend` doesn't warn about a web server legitimately running on 9080
// (and vice versa). Omitted → check both.
function warnIfPortsHeld(ports: DevPorts, scope?: Scope): void {
for (const [label, port] of [
["web", ports.web],
["backend", ports.backend],
] as const) {
if (scope && label !== scope) continue;
const pids = portHolders(port);
if (pids.length > 0) {
console.log(
`[dev-ports] warning: ${label} port ${port} is already in use by ` +
`PID ${pids.join(", ")}. The dev server will fail to bind. ` +
`Free it with: kill ${pids.join(" ")}`,
);
}
}
}

async function main(scope?: Scope): Promise<void> {
const root = process.cwd();
const configPath = path.join(root, "compass.yaml");

Expand All @@ -170,6 +214,7 @@ async function main(): Promise<void> {

const claimed = readSiblingPorts(root);
if (!isPortsClaimed(current, claimed)) {
warnIfPortsHeld(current, scope);
return;
}

Expand All @@ -183,6 +228,7 @@ async function main(): Promise<void> {
console.log(
"[dev-ports] compass.yaml uses custom URLs — manage ports manually",
);
warnIfPortsHeld(current, scope);
return;
}

Expand All @@ -194,7 +240,10 @@ async function main(): Promise<void> {
}

if (require.main === module) {
main().catch((err) => {
const arg = process.argv[2];
const scope: Scope | undefined =
arg === "web" || arg === "backend" ? arg : undefined;
main(scope).catch((err) => {
console.log(err);
process.exit(1);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ export const CompassOptionalProviders = ({ children }: PropsWithChildren) => {
apiKey={ENV_WEB.POSTHOG_KEY as string}
options={{
api_host: ENV_WEB.POSTHOG_HOST!,
// Assumes the US cloud; self-hosters on another instance would differ.
ui_host: "https://us.posthog.com",
capture_exceptions: {
capture_unhandled_errors: true,
capture_unhandled_rejections: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ export function ReleaseNotesPrompt() {
Want the latest Compass news?
</h2>
<p className="text-text-muted">
Get monthly release notes with new features, improvements, and
helpful tips. Unsubscribe anytime.
Get monthly product email. Unsubscribe anytime.
</p>
</div>
<div className="flex flex-wrap justify-end gap-3">
Expand All @@ -97,14 +96,14 @@ export function ReleaseNotesPrompt() {
onClick={decline}
className="c-button c-button-secondary rounded-full px-5"
>
Nah, I don&apos;t want updates
Nah, I don&apos;t want more emails
</button>
<button
type="button"
onClick={() => void subscribe()}
className="c-button c-button-primary c-button-elevated rounded-full px-5"
>
Yes, Keep Me Updated
Yes, keep me updated
</button>
</div>
</>
Expand All @@ -115,7 +114,7 @@ export function ReleaseNotesPrompt() {
</h2>
<p className="text-text-muted">
{state === "confirmed"
? "Monthly notes headed your way."
? "You'll get the next release notes in your inbox"
: "No problem, you can signup using the cmd palette if you change your mind."}
</p>
</div>
Expand Down