Skip to content

Commit 3b7ebd7

Browse files
authored
fix: keep Windows cold starts responsive (#54)
Signed-off-by: Joseph Yaksich <gitcommit90@users.noreply.github.com> Co-authored-by: Joseph Yaksich <gitcommit90@users.noreply.github.com>
1 parent 1a228b6 commit 3b7ebd7

12 files changed

Lines changed: 46 additions & 13 deletions

‎CHANGELOG.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [0.0.36] - 2026-08-02
11+
12+
### Fixed
13+
14+
- Kept the Windows desktop control plane available across a genuine cold WSL
15+
reboot by deferring retained OCI directory maintenance until runtime access
16+
or fleet reconciliation actually needs it, instead of synchronously waking
17+
WSL before the HTTP server can listen.
18+
- Gave the Windows desktop a bounded three-minute cold-runtime readiness window
19+
while preserving the existing 30-second startup budget on other platforms.
20+
1021
## [0.0.35] - 2026-08-01
1122

1223
### Fixed
@@ -989,7 +1000,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9891000
notarization, stapled tickets, Gatekeeper verification, persistent
9901001
Application Support, and isolated Apple container machines.
9911002

992-
[Unreleased]: https://github.com/gitcommit90/1Helm/compare/v0.0.35...HEAD
1003+
[Unreleased]: https://github.com/gitcommit90/1Helm/compare/v0.0.36...HEAD
1004+
[0.0.36]: https://github.com/gitcommit90/1Helm/compare/v0.0.35...v0.0.36
9931005
[0.0.35]: https://github.com/gitcommit90/1Helm/compare/v0.0.34...v0.0.35
9941006
[0.0.34]: https://github.com/gitcommit90/1Helm/compare/v0.0.33...v0.0.34
9951007
[0.0.33]: https://github.com/gitcommit90/1Helm/compare/v0.0.32...v0.0.33

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ A fresh data directory opens first-run setup. The source runtime defaults to
313313
| `PORT` | `8123` | HTTP/WebSocket control-plane port. |
314314
| `CTRL_DATA_DIR` | `./data` | Databases, routing state, uploads, and non-OCI development/Apple workspace mirrors. |
315315
| `HELM_CHANNEL_COMPUTER_BACKEND` | `apple` on macOS, `oci` on Linux and Windows | Host isolation backend; `native` and `mock` are explicit development/test overrides. |
316-
| `HELM_CHANNEL_MACHINE_IMAGE` | `local/1helm-channel-machine:0.0.35` | Versioned channel-machine image contract. |
316+
| `HELM_CHANNEL_MACHINE_IMAGE` | `local/1helm-channel-machine:0.0.36` | Versioned channel-machine image contract. |
317317

318318
### Agent-first JSON CLI
319319

‎desktop/main.cjs‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const LOOPBACK = "127.0.0.1";
1515
// installation's Application Support/AppData tree untouched and never import
1616
// it implicitly into this runtime generation.
1717
const DATA_NAMESPACE = "1Helm-OCI-v1";
18+
const SERVER_READY_TIMEOUT_MS = process.platform === "win32" ? 3 * 60_000 : 30_000;
1819
app.setPath("userData", path.join(app.getPath("appData"), DATA_NAMESPACE));
1920
let mainWindow = null;
2021
let authWindow = null;
@@ -95,7 +96,7 @@ function freePort() {
9596
});
9697
}
9798

98-
async function waitForServer(origin, timeoutMs = 30_000) {
99+
async function waitForServer(origin, timeoutMs = SERVER_READY_TIMEOUT_MS) {
99100
const deadline = Date.now() + timeoutMs;
100101
let lastError = null;
101102
while (Date.now() < deadline) {

‎package-lock.json‎

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "1helm",
33
"productName": "1Helm",
4-
"version": "0.0.35",
4+
"version": "0.0.36",
55
"private": true,
66
"type": "module",
77
"license": "AGPL-3.0-only",

‎src/server/agents.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export const channelRoot = hostChannelRoot;
6262
export const channelWorkspace = channelWorkspacePath;
6363
export const channelFiles = channelFilesPath;
6464

65-
export function ensureChannelWorkspace(channelId: number): string {
65+
export function ensureChannelWorkspace(channelId: number, options: { initializeRuntimeStorage?: boolean } = {}): string {
6666
const channel = q1("SELECT id,name,personal_main_owner_id FROM channels WHERE id=? AND status<>'deleted'", channelId);
6767
if (!channel) throw new Error("Channel workspace not found.");
6868
const root = channelRoot(channelId);
@@ -71,8 +71,10 @@ export function ensureChannelWorkspace(channelId: number): string {
7171
if (channelUsesRuntimeStorage(channelId)) {
7272
// OCI workspace/files live in runtime storage. On Windows that path is
7373
// \\wsl.localhost\\... and host mkdir there fails; create via the WSL runtime.
74-
try { ensureOciChannelWorkspaceDirs(channelId); }
75-
catch { /* provision path creates these once the computer exists */ }
74+
if (options.initializeRuntimeStorage !== false) {
75+
try { ensureOciChannelWorkspaceDirs(channelId); }
76+
catch { /* provision path creates these once the computer exists */ }
77+
}
7678
} else {
7779
mkdirSync(channelWorkspace(channelId), { recursive: true });
7880
mkdirSync(channelFiles(channelId), { recursive: true });

‎src/server/channel-computers.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ const APPLE_RUNTIME_VERSION = "1.1.0";
6868
export const APPLE_RUNTIME_PACKAGE = `container-${APPLE_RUNTIME_VERSION}-installer-signed.pkg`;
6969
export const APPLE_RUNTIME_URL = `https://github.com/apple/container/releases/download/${APPLE_RUNTIME_VERSION}/${APPLE_RUNTIME_PACKAGE}`;
7070
export const APPLE_RUNTIME_SHA256 = "0ca1c42a2269c2557efb1d82b1b38ac553e6a3a3da1b1179c439bcee1e7d6714";
71-
export const DEFAULT_CHANNEL_IMAGE = process.env.HELM_CHANNEL_MACHINE_IMAGE || "local/1helm-channel-machine:0.0.35";
71+
export const DEFAULT_CHANNEL_IMAGE = process.env.HELM_CHANNEL_MACHINE_IMAGE || "local/1helm-channel-machine:0.0.36";
7272
const CONTAINER_CANDIDATES = [process.env.HELM_CONTAINER_CLI, "/usr/local/bin/container", "/opt/homebrew/bin/container", "container"].filter(Boolean) as string[];
7373
const OCI_RUNTIME_VERSION = "1helm-oci-runtime-v1";
7474
const OCI_HELPER_CANDIDATES = [

‎src/server/db.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -939,7 +939,7 @@ export function migrate(): void {
939939
const platformBackend = process.platform === "darwin" ? "apple" : "oci";
940940
const configuredBackend = String(process.env.HELM_CHANNEL_COMPUTER_BACKEND || platformBackend);
941941
const backend = ["apple", "oci", "native", "mock"].includes(configuredBackend) ? configuredBackend : platformBackend;
942-
const image = String(process.env.HELM_CHANNEL_MACHINE_IMAGE || "local/1helm-channel-machine:0.0.35");
942+
const image = String(process.env.HELM_CHANNEL_MACHINE_IMAGE || "local/1helm-channel-machine:0.0.36");
943943
for (const channel of q(`SELECT c.id FROM channels c JOIN agent_channels ac ON ac.channel_id=c.id
944944
WHERE c.kind='channel' AND c.status<>'deleted'`)) {
945945
const channelId = Number(channel.id);

‎src/server/index.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2287,7 +2287,12 @@ async function bootstrap(): Promise<void> {
22872287
// Resident agents own their Linux machine, never the Captain's native Mac.
22882288
run("DELETE FROM bot_computers WHERE computer_id=? AND bot_id IN (SELECT bot_id FROM agents WHERE kind='channel')", computerId);
22892289
for (const channel of q("SELECT id FROM channels WHERE kind='channel' AND status<>'deleted'")) {
2290-
ensureChannelWorkspace(Number(channel.id));
2290+
// Retained OCI storage is already authoritative. In particular, a cold
2291+
// Windows login can take minutes to wake WSL, and that maintenance must
2292+
// never hold the HTTP control plane behind a synchronous startup probe.
2293+
// Provisioning, Files/Cowork access, Terminal, and the fleet reconciler
2294+
// initialize or verify runtime directories when they actually need them.
2295+
ensureChannelWorkspace(Number(channel.id), { initializeRuntimeStorage: false });
22912296
}
22922297
startImprovementLoop();
22932298
startThreadAuditLoop();

‎test/autonomy-platform.mjs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,17 @@ test("Cowork contracts survive follow-ups and reject only newly-created incompat
200200
assert.equal(cowork.enforceCoworkCommandOutput(channelId, null, whiteboards, boardBefore), null);
201201
});
202202

203+
test("retained OCI channel metadata can initialize without synchronously touching runtime storage", () => {
204+
seed();
205+
const channelId = run("INSERT INTO channels (name,slug,kind,topic,purpose,status,created) VALUES ('retained-cold-start','retained-cold-start','channel','','','active',?)", now()).lastInsertRowid;
206+
const botId = run("INSERT INTO bots (name,model,prompt,created) VALUES ('retained-cold-agent','mock','Resident.',?)", now()).lastInsertRowid;
207+
const agentId = run("INSERT INTO agents (bot_id,kind,name,status,created) VALUES (?,'channel','retained-cold-agent','ready',?)", botId, now()).lastInsertRowid;
208+
run("INSERT INTO agent_channels (agent_id,channel_id,bound_at) VALUES (?,?,?)", agentId, channelId, now());
209+
run("INSERT INTO agent_profiles (agent_id,purpose,instructions,updated) VALUES (?,'Cold start','Resident.',?)", agentId, now());
210+
assert.doesNotThrow(() => agents.ensureChannelWorkspace(channelId, { initializeRuntimeStorage: false }));
211+
assert.equal(q1("SELECT root_ref FROM channel_workspaces WHERE channel_id=?", channelId).root_ref, `channels/${channelId}`);
212+
});
213+
203214
test("resident raw transcript search is semantic, exact, readable, and channel-isolated", () => {
204215
const ownerId = run("INSERT INTO users (username,pass,display,is_admin,created) VALUES ('history-owner','x','History Owner',1,?)", now()).lastInsertRowid;
205216
const channelId = run("INSERT INTO channels (name,slug,kind,topic,purpose,status,created_by,created) VALUES ('history-home','history-home','channel','','Recall prior sessions','active',?,?)", ownerId, now()).lastInsertRowid;

0 commit comments

Comments
 (0)