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: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

> Campfire began as a fork of [the-companion](https://github.com/The-Vibe-Company/companion) and diverged into a separate product. Pre-fork history (versions up to 0.42.0) lives in the upstream repository; Campfire's own releases start at 0.1.0.

## 0.4.1 (2026-07-07)

### Fixes

* **desktop:** first-launch resilience — the server boot deadline is now 90 s (Gatekeeper verifies the whole ~400 MB bundle on first launch, which can exceed the old 30 s limit on slower machines), the splash explains the wait after 15 s instead of looking hung, the startup-failure dialog includes the recent server log tail, and launching a second instance logs that it is focusing the existing one

## 0.4.0 (2026-07-07)

### Features
Expand Down
13 changes: 13 additions & 0 deletions desktop/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ let quitting = false;

// ── Single instance ──────────────────────────────────────────────────────────
if (!app.requestSingleInstanceLock()) {
console.log("[desktop] Another Campfire instance is already running — focusing it instead.");
app.exit(0);
}
app.on("second-instance", () => {
Expand Down Expand Up @@ -109,10 +110,21 @@ async function bootAndLoad(win) {
win.once("ready-to-show", () => win.show());
}

// First launches can sit in Gatekeeper verification for a while — tell the
// user the wait is expected instead of looking hung.
const slowBootNote = setTimeout(() => {
win.webContents
.executeJavaScript(
`document.getElementById("s").textContent = "Still starting — the first launch can take a minute while macOS verifies the app…"`,
)
.catch(() => { /* window may have navigated */ });
}, 15000);

let result;
try {
result = await serverManager.ensure();
} catch (err) {
clearTimeout(slowBootNote);
if (SMOKE) {
console.error(`SMOKE_FAIL: ${err.message}`);
app.exit(1);
Expand All @@ -128,6 +140,7 @@ async function bootAndLoad(win) {
return;
}

clearTimeout(slowBootNote);
const origin = serverManager.origin();
console.log(
result.external
Expand Down
20 changes: 18 additions & 2 deletions desktop/main/server-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,32 @@ class ServerManager {
if (!wasStopping && this.onUnexpectedExit) this.onUnexpectedExit(code);
});

const ready = await waitForCampfire(this.port, 30000, () => this.child !== null);
// Generous deadline: on the very first launch Gatekeeper verifies the
// whole bundle (~400 MB) before and while the sidecar starts, which can
// take well over 30s on slower machines.
const ready = await waitForCampfire(this.port, 90000, () => this.child !== null);
if (!ready) {
this.stop();
throw new Error(
"The Campfire server did not start.\nSee ~/.campfire/logs/desktop-server.log for details.",
"The Campfire server did not start.\n\n" +
`Recent server log (~/.campfire/logs/desktop-server.log):\n${this.logTail()}`,
);
}
return { port: this.port, external: false };
}

/** Last few lines of the sidecar log, for error dialogs. */
logTail(lines = 12) {
try {
const { readFileSync } = require("node:fs");
const logPath = join(os.homedir(), ".campfire", "logs", "desktop-server.log");
const content = readFileSync(logPath, "utf8");
return content.split("\n").filter(Boolean).slice(-lines).join("\n");
} catch {
return "(log unavailable)";
}
}

/** Stop the sidecar (no-op when attached to an external server). */
stop() {
if (!this.child) return;
Expand Down
2 changes: 1 addition & 1 deletion desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "campfire-desktop",
"version": "0.4.0",
"version": "0.4.1",
"private": true,
"description": "Campfire desktop app — native macOS shell around the Campfire server",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "the-campfire",
"version": "0.4.0",
"version": "0.4.1",
"type": "module",
"description": "Campfire \u2014 collaborative web platform for AI coding agents. Run Claude Code, Codex, Goose, Aider, and more from one browser UI with real-time collaboration, permission voting, and automation.",
"license": "MIT",
Expand Down
Loading