From 3cae2b6ec0447b0d848177705491e510628c764b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Wed, 1 Jul 2026 08:39:22 +0200 Subject: [PATCH] =?UTF-8?q?refactor:=20split=20daemon=20server=20runtime?= =?UTF-8?q?=20into=20daemon/server/=20=E2=80=94=20Phase=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase-5 ยง5.5 folder move (server side; the daemon/client/ split shipped in #962). Extracts the process-bootstrap / server-runtime cluster into src/daemon/server/ as a pure, behaviorless path codemod โ€” no logic changes. Moved (server bootstrap/runtime โ€” the layer that spins up the daemon and owns the platform graph; each imported only by the bootstrap layer + each other): src/daemon-runtime.ts -> src/daemon/server/daemon-runtime.ts src/daemon/http-server.ts -> src/daemon/server/http-server.ts src/daemon/transport.ts -> src/daemon/server/transport.ts src/daemon/server-lifecycle.ts -> src/daemon/server/server-lifecycle.ts src/daemon/server-shutdown.ts -> src/daemon/server/server-shutdown.ts Left in src/daemon/ root (request core / shared wire helpers, out of scope): request-router.ts, handlers/, session-store.ts, lease-registry.ts, context.ts (the daemon's request layer) and http-contract.ts / http-health.ts / http-errors.ts / config.ts (HTTP wire contract + daemon config shared across client, remote, and cli โ€” not server-only). Left: src/daemon.ts (the thin process entry) stays at src/ with the other package entrypoints; it is coupled to its physical path by four non-import string references (rslib entry, config dev-mode sentinel, process-identity detection regex, daemon-client launch srcPath), so moving it is beyond a pure import codemod. Rewrote every from/import/import()/type-only specifier per importer (resolve-based path.relative recompute) across src and test, and renamed the fallow health-baseline key for http-server.ts. daemon-runtime's static platforms/ import is now inside the daemon-server seam the layering lint (#984 R3) allows. Verification: tsc --noEmit 0; layering check (branch script) unchanged (3 pre-existing R3 violations, 0 new); oxfmt clean; oxlint --deny-warnings 0; fallow audit --base origin/main clean (14 files); rslib build 0 (internal/daemon entry still emits); vitest 17 passed (daemon-entrypoint, http-server-rpc-validation, server-shutdown + 3 provider-integration). --- fallow-baselines/health.json | 2 +- src/__tests__/daemon-entrypoint.test.ts | 2 +- src/daemon.ts | 2 +- .../http-server-rpc-validation.test.ts | 2 +- src/daemon/__tests__/server-shutdown.test.ts | 4 +-- src/{ => daemon/server}/daemon-runtime.ts | 36 +++++++++---------- src/daemon/{ => server}/http-server.ts | 32 ++++++++--------- src/daemon/{ => server}/server-lifecycle.ts | 8 ++--- src/daemon/{ => server}/server-shutdown.ts | 0 src/daemon/{ => server}/transport.ts | 18 +++++----- .../daemon-http-server.test.ts | 2 +- .../daemon-lifecycle.test.ts | 2 +- .../daemon-transport.test.ts | 2 +- 13 files changed, 56 insertions(+), 56 deletions(-) rename src/{ => daemon/server}/daemon-runtime.ts (87%) rename src/daemon/{ => server}/http-server.ts (97%) rename src/daemon/{ => server}/server-lifecycle.ts (91%) rename src/daemon/{ => server}/server-shutdown.ts (100%) rename src/daemon/{ => server}/transport.ts (91%) diff --git a/fallow-baselines/health.json b/fallow-baselines/health.json index 11400a648..b4a93e297 100644 --- a/fallow-baselines/health.json +++ b/fallow-baselines/health.json @@ -330,7 +330,7 @@ "count": 1 } }, - "src/daemon/http-server.ts": { + "src/daemon/server/http-server.ts": { "complexity_critical": { "count": 1 }, diff --git a/src/__tests__/daemon-entrypoint.test.ts b/src/__tests__/daemon-entrypoint.test.ts index 9c5f0a316..25c043037 100644 --- a/src/__tests__/daemon-entrypoint.test.ts +++ b/src/__tests__/daemon-entrypoint.test.ts @@ -4,7 +4,7 @@ import os from 'node:os'; import path from 'node:path'; import { test } from 'vitest'; import { resolveDaemonPaths } from '../daemon/config.ts'; -import { startDaemonRuntime } from '../daemon-runtime.ts'; +import { startDaemonRuntime } from '../daemon/server/daemon-runtime.ts'; import { runCmdBackground } from '../utils/exec.ts'; import { isProcessAlive, waitForProcessExit } from '../utils/process-identity.ts'; import { waitForHttpOk } from './test-utils/index.ts'; diff --git a/src/daemon.ts b/src/daemon.ts index 1e1a70038..bb995e5c9 100644 --- a/src/daemon.ts +++ b/src/daemon.ts @@ -1,4 +1,4 @@ -import { startDaemonRuntime } from './daemon-runtime.ts'; +import { startDaemonRuntime } from './daemon/server/daemon-runtime.ts'; import { asAppError } from './kernel/errors.ts'; void startDaemonRuntime().catch((error) => { diff --git a/src/daemon/__tests__/http-server-rpc-validation.test.ts b/src/daemon/__tests__/http-server-rpc-validation.test.ts index afb75de29..ea063365c 100644 --- a/src/daemon/__tests__/http-server-rpc-validation.test.ts +++ b/src/daemon/__tests__/http-server-rpc-validation.test.ts @@ -1,6 +1,6 @@ import { test } from 'vitest'; import assert from 'node:assert/strict'; -import { createDaemonHttpServer } from '../http-server.ts'; +import { createDaemonHttpServer } from '../server/http-server.ts'; import type { DaemonRequest, DaemonResponse } from '../types.ts'; import { closeLoopbackServer, diff --git a/src/daemon/__tests__/server-shutdown.test.ts b/src/daemon/__tests__/server-shutdown.test.ts index ab8a71ba1..d6123e029 100644 --- a/src/daemon/__tests__/server-shutdown.test.ts +++ b/src/daemon/__tests__/server-shutdown.test.ts @@ -1,7 +1,7 @@ import { test } from 'vitest'; import assert from 'node:assert/strict'; -import type { DaemonServer } from '../transport.ts'; -import { closeDaemonServers } from '../server-shutdown.ts'; +import type { DaemonServer } from '../server/transport.ts'; +import { closeDaemonServers } from '../server/server-shutdown.ts'; test('closeDaemonServers forces stuck servers after timeout', async () => { let destroyed = false; diff --git a/src/daemon-runtime.ts b/src/daemon/server/daemon-runtime.ts similarity index 87% rename from src/daemon-runtime.ts rename to src/daemon/server/daemon-runtime.ts index be1f7cfd0..7ac02d24c 100644 --- a/src/daemon-runtime.ts +++ b/src/daemon/server/daemon-runtime.ts @@ -1,20 +1,20 @@ import crypto from 'node:crypto'; -import { asAppError, AppError } from './kernel/errors.ts'; -import { SessionStore } from './daemon/session-store.ts'; -import { cleanupStaleAppLogProcesses } from './daemon/app-log-process.ts'; -import { resolveDaemonPaths, resolveDaemonServerMode } from './daemon/config.ts'; -import { createDaemonHttpServer } from './daemon/http-server.ts'; -import { trackDownloadableArtifact } from './daemon/artifact-tracking.ts'; -import { LeaseRegistry } from './daemon/lease-registry.ts'; -import { createRequestHandler } from './daemon/request-router.ts'; -import { teardownSessionResources } from './daemon/session-teardown.ts'; -import { closeDaemonServers } from './daemon/server-shutdown.ts'; -import type { SessionState } from './daemon/types.ts'; +import { asAppError, AppError } from '../../kernel/errors.ts'; +import { SessionStore } from '../session-store.ts'; +import { cleanupStaleAppLogProcesses } from '../app-log-process.ts'; +import { resolveDaemonPaths, resolveDaemonServerMode } from '../config.ts'; +import { createDaemonHttpServer } from './http-server.ts'; +import { trackDownloadableArtifact } from '../artifact-tracking.ts'; +import { LeaseRegistry } from '../lease-registry.ts'; +import { createRequestHandler } from '../request-router.ts'; +import { teardownSessionResources } from '../session-teardown.ts'; +import { closeDaemonServers } from './server-shutdown.ts'; +import type { SessionState } from '../types.ts'; import { emitDiagnostic, flushDiagnosticsToSessionFile, withDiagnosticsScope, -} from './utils/diagnostics.ts'; +} from '../../utils/diagnostics.ts'; import { acquireDaemonLock, parseIntegerEnv, @@ -24,16 +24,16 @@ import { removeInfo, resolveDaemonCodeSignature, writeInfo, -} from './daemon/server-lifecycle.ts'; +} from './server-lifecycle.ts'; import { createSocketServer, listenHttpServer, listenNetServer, type DaemonServer, -} from './daemon/transport.ts'; -import { prewarmPngWorker, terminatePngWorker } from './utils/png-worker-client.ts'; -import { sleep } from './utils/timeouts.ts'; -import { setRunnerLeaseOwnerStateDir } from './platforms/apple/core/runner/runner-lease.ts'; +} from './transport.ts'; +import { prewarmPngWorker, terminatePngWorker } from '../../utils/png-worker-client.ts'; +import { sleep } from '../../utils/timeouts.ts'; +import { setRunnerLeaseOwnerStateDir } from '../../platforms/apple/core/runner/runner-lease.ts'; const DAEMON_SESSION_TEARDOWN_TIMEOUT_MS = 5_000; const DAEMON_PNG_WORKER_TERMINATE_TIMEOUT_MS = 1_000; @@ -224,7 +224,7 @@ export async function startDaemonRuntime( await closeDaemonServers(servers); await teardownDaemonSessions(); const { stopAllIosRunnerSessions } = - await import('./platforms/apple/core/runner/runner-client.ts'); + await import('../../platforms/apple/core/runner/runner-client.ts'); await stopAllIosRunnerSessions(); // Best effort: stop the PNG worker so an in-flight job cannot delay exit. await Promise.race([ diff --git a/src/daemon/http-server.ts b/src/daemon/server/http-server.ts similarity index 97% rename from src/daemon/http-server.ts rename to src/daemon/server/http-server.ts index f4c8184b3..f134d22de 100644 --- a/src/daemon/http-server.ts +++ b/src/daemon/server/http-server.ts @@ -1,37 +1,37 @@ import http, { type IncomingHttpHeaders } from 'node:http'; import fs from 'node:fs'; -import { AppError, normalizeError, toAppErrorCode } from '../kernel/errors.ts'; -import { emitDiagnostic } from '../utils/diagnostics.ts'; -import { timingSafeStringEqual } from '../utils/timing-safe-equal.ts'; +import { AppError, normalizeError, toAppErrorCode } from '../../kernel/errors.ts'; +import { emitDiagnostic } from '../../utils/diagnostics.ts'; +import { timingSafeStringEqual } from '../../utils/timing-safe-equal.ts'; import type { CommandRpcParams, JsonRpcId, JsonRpcRequestEnvelope, LeaseBackend, -} from '../kernel/contracts.ts'; -import { commandRpcParamsSchema } from '../kernel/contracts.ts'; -import type { DaemonInstallSource, DaemonInvokeFn, DaemonRequest } from './types.ts'; -import { normalizeTenantId } from './config.ts'; +} from '../../kernel/contracts.ts'; +import { commandRpcParamsSchema } from '../../kernel/contracts.ts'; +import type { DaemonInstallSource, DaemonInvokeFn, DaemonRequest } from '../types.ts'; +import { normalizeTenantId } from '../config.ts'; import { clearRequestCanceled, isRequestCanceled, markRequestCanceled, registerRequestAbort, resolveRequestTrackingId, -} from './request-cancel.ts'; +} from '../request-cancel.ts'; import path from 'node:path'; import { pathToFileURL } from 'node:url'; -import { sleep } from '../utils/timeouts.ts'; -import { cleanupDownloadableArtifact, prepareDownloadableArtifact } from './artifact-tracking.ts'; -import { type RequestProgressEvent, withRequestProgressSink } from './request-progress.ts'; +import { sleep } from '../../utils/timeouts.ts'; +import { cleanupDownloadableArtifact, prepareDownloadableArtifact } from '../artifact-tracking.ts'; +import { type RequestProgressEvent, withRequestProgressSink } from '../request-progress.ts'; import { serializeDaemonProgressEnvelope, serializeDaemonRpcResponseEnvelope, shouldStreamRequestProgress, -} from './request-progress-protocol.ts'; -import { buildDaemonHealthPayload } from './http-health.ts'; -import { sendRestJsonError, statusCodeForNormalizedError } from './http-errors.ts'; -import { tryHandleUploadHttpRoute } from './upload-http.ts'; +} from '../request-progress-protocol.ts'; +import { buildDaemonHealthPayload } from '../http-health.ts'; +import { sendRestJsonError, statusCodeForNormalizedError } from '../http-errors.ts'; +import { tryHandleUploadHttpRoute } from '../upload-http.ts'; type JsonRpcRequest = JsonRpcRequestEnvelope; @@ -795,7 +795,7 @@ async function abortInFlightIosRunnerSessionsWhileDisconnected( const deadline = Date.now() + CLIENT_DISCONNECT_ABORT_MAX_WINDOW_MS; while (isRequestCanceled(requestId) && Date.now() < deadline) { const { abortAllIosRunnerSessions } = - await import('../platforms/apple/core/runner/runner-client.ts'); + await import('../../platforms/apple/core/runner/runner-client.ts'); await abortAllIosRunnerSessions(); if (!isRequestCanceled(requestId)) break; await sleep(CLIENT_DISCONNECT_ABORT_POLL_INTERVAL_MS); diff --git a/src/daemon/server-lifecycle.ts b/src/daemon/server/server-lifecycle.ts similarity index 91% rename from src/daemon/server-lifecycle.ts rename to src/daemon/server/server-lifecycle.ts index 7950c61f7..bdfe52d2f 100644 --- a/src/daemon/server-lifecycle.ts +++ b/src/daemon/server/server-lifecycle.ts @@ -1,9 +1,9 @@ import fs from 'node:fs'; -import { isAgentDeviceDaemonProcess } from '../utils/process-identity.ts'; +import { isAgentDeviceDaemonProcess } from '../../utils/process-identity.ts'; -export { readVersion } from '../utils/version.ts'; -export { readProcessStartTime } from '../utils/process-identity.ts'; -export { resolveDaemonCodeSignature } from './code-signature.ts'; +export { readVersion } from '../../utils/version.ts'; +export { readProcessStartTime } from '../../utils/process-identity.ts'; +export { resolveDaemonCodeSignature } from '../code-signature.ts'; export type DaemonLockInfo = { pid: number; diff --git a/src/daemon/server-shutdown.ts b/src/daemon/server/server-shutdown.ts similarity index 100% rename from src/daemon/server-shutdown.ts rename to src/daemon/server/server-shutdown.ts diff --git a/src/daemon/transport.ts b/src/daemon/server/transport.ts similarity index 91% rename from src/daemon/transport.ts rename to src/daemon/server/transport.ts index be62491bb..8febe9742 100644 --- a/src/daemon/transport.ts +++ b/src/daemon/server/transport.ts @@ -1,7 +1,7 @@ import net from 'node:net'; import type { Server as HttpServer } from 'node:http'; -import { AppError, normalizeError } from '../kernel/errors.ts'; -import type { DaemonInvokeFn, DaemonRequest, DaemonResponse } from './types.ts'; +import { AppError, normalizeError } from '../../kernel/errors.ts'; +import type { DaemonInvokeFn, DaemonRequest, DaemonResponse } from '../types.ts'; import { clearRequestCanceled, createRequestCanceledError, @@ -9,16 +9,16 @@ import { markRequestCanceled, registerRequestAbort, resolveRequestTrackingId, -} from './request-cancel.ts'; -import { emitDiagnostic } from '../utils/diagnostics.ts'; -import { consumeTextLines } from '../utils/line-stream.ts'; -import { sleep } from '../utils/timeouts.ts'; -import { withRequestProgressSink } from './request-progress.ts'; +} from '../request-cancel.ts'; +import { emitDiagnostic } from '../../utils/diagnostics.ts'; +import { consumeTextLines } from '../../utils/line-stream.ts'; +import { sleep } from '../../utils/timeouts.ts'; +import { withRequestProgressSink } from '../request-progress.ts'; import { serializeDaemonProgressEnvelope, serializeDaemonResponseEnvelope, shouldStreamRequestProgress, -} from './request-progress-protocol.ts'; +} from '../request-progress-protocol.ts'; const disconnectAbortPollIntervalMs = 200; const disconnectAbortMaxWindowMs = 15_000; @@ -54,7 +54,7 @@ export function createSocketServer(handleRequest: DaemonInvokeFn): DaemonServer const deadline = Date.now() + disconnectAbortMaxWindowMs; while (inFlightRequests > 0 && Date.now() < deadline) { const { abortAllIosRunnerSessions } = - await import('../platforms/apple/core/runner/runner-client.ts'); + await import('../../platforms/apple/core/runner/runner-client.ts'); await abortAllIosRunnerSessions(); if (inFlightRequests <= 0) break; await sleep(disconnectAbortPollIntervalMs); diff --git a/test/integration/provider-scenarios/daemon-http-server.test.ts b/test/integration/provider-scenarios/daemon-http-server.test.ts index 9ee27c386..8b40daf98 100644 --- a/test/integration/provider-scenarios/daemon-http-server.test.ts +++ b/test/integration/provider-scenarios/daemon-http-server.test.ts @@ -12,7 +12,7 @@ import { trackDownloadableArtifact, } from '../../../src/daemon/artifact-tracking.ts'; import { DAEMON_RPC_PROTOCOL_VERSION } from '../../../src/daemon/http-health.ts'; -import { createDaemonHttpServer } from '../../../src/daemon/http-server.ts'; +import { createDaemonHttpServer } from '../../../src/daemon/server/http-server.ts'; import { emitRequestProgress } from '../../../src/daemon/request-progress.ts'; import { getRequestSignal, isRequestCanceled } from '../../../src/daemon/request-cancel.ts'; import type { DaemonRequest, DaemonResponse } from '../../../src/daemon/types.ts'; diff --git a/test/integration/provider-scenarios/daemon-lifecycle.test.ts b/test/integration/provider-scenarios/daemon-lifecycle.test.ts index b2d02326a..9de67809f 100644 --- a/test/integration/provider-scenarios/daemon-lifecycle.test.ts +++ b/test/integration/provider-scenarios/daemon-lifecycle.test.ts @@ -9,7 +9,7 @@ import { releaseDaemonLock, removeInfo, writeInfo, -} from '../../../src/daemon/server-lifecycle.ts'; +} from '../../../src/daemon/server/server-lifecycle.ts'; test('Provider-backed integration daemon lifecycle writes metadata and protects process-owned locks', () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-device-daemon-lifecycle-')); diff --git a/test/integration/provider-scenarios/daemon-transport.test.ts b/test/integration/provider-scenarios/daemon-transport.test.ts index c25c94bd8..783b0ced6 100644 --- a/test/integration/provider-scenarios/daemon-transport.test.ts +++ b/test/integration/provider-scenarios/daemon-transport.test.ts @@ -7,7 +7,7 @@ import { createSocketServer, listenHttpServer, listenNetServer, -} from '../../../src/daemon/transport.ts'; +} from '../../../src/daemon/server/transport.ts'; import { closeLoopbackServer, skipWhenLoopbackUnavailable,