Skip to content
Closed
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
2 changes: 2 additions & 0 deletions apps/control-plane/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
"@hono/oidc-auth": "^1.8.1",
"@hono/zod-openapi": "1.2.3",
"@paws/credentials": "workspace:*",
"@paws/domain-agent": "workspace:*",
"@paws/domain-audit": "workspace:*",
"@paws/domain-browser": "workspace:*",
"@paws/domain-common": "workspace:*",
"@paws/domain-daemon": "workspace:*",
"@paws/domain-fleet": "workspace:*",
"@paws/domain-mcp": "workspace:*",
"@paws/domain-network": "workspace:*",
"@paws/domain-policy": "workspace:*",
"@paws/domain-session": "workspace:*",
"@paws/domain-snapshot": "workspace:*",
"@paws/integrations": "workspace:*",
Expand Down
6 changes: 3 additions & 3 deletions apps/control-plane/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ import {
listDaemonsRoute,
updateDaemonRoute,
receiveWebhookRoute,
createGovernanceChecker,
createDaemonStore,
type DaemonStore,
} from '@paws/domain-daemon';
import { createGovernanceChecker } from '@paws/domain-policy';
import {
selectWorker,
costSummaryRoute,
Expand Down Expand Up @@ -86,7 +86,7 @@ import { createWorkerClient } from './worker-client.js';
import type { CredentialStore } from '@paws/credentials';
import type { PawsDatabase } from './db/index.js';
import type { WorkerDiscovery } from './discovery/index.js';
import type { GovernanceChecker } from '@paws/domain-daemon';
import type { GovernanceChecker } from '@paws/domain-policy';
import type { WorkerClient } from './worker-client.js';

export interface ControlPlaneDeps {
Expand Down Expand Up @@ -1067,7 +1067,7 @@ export async function createControlPlaneApp(deps: ControlPlaneDeps) {
// Generate workload from agent config or use the explicit workload
let workload;
if (daemon.agent) {
const { generateAgentScript } = await import('@paws/domain-daemon');
const { generateAgentScript } = await import('@paws/domain-agent');
workload = {
type: 'script' as const,
script: generateAgentScript(daemon.agent),
Expand Down
2 changes: 1 addition & 1 deletion apps/control-plane/src/governance.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, test } from 'vitest';

import { createGovernanceChecker } from '@paws/domain-daemon';
import { createGovernanceChecker } from '@paws/domain-policy';

describe('createGovernanceChecker', () => {
test('allows actions when no rate limit configured', () => {
Expand Down
4 changes: 2 additions & 2 deletions apps/control-plane/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { createControlPlaneApp } from './app.js';
export type { ControlPlaneDeps } from './app.js';
export { ControlPlaneError, controlPlaneError } from './errors.js';
export { createGovernanceChecker } from '@paws/domain-daemon';
export type { GovernanceChecker } from '@paws/domain-daemon';
export { createGovernanceChecker } from '@paws/domain-policy';
export type { GovernanceChecker } from '@paws/domain-policy';
export { authMiddleware } from './middleware/auth.js';
export { createDaemonStore } from '@paws/domain-daemon';
export type { DaemonStore, StoredDaemon } from '@paws/domain-daemon';
Expand Down
10 changes: 3 additions & 7 deletions apps/control-plane/src/store/daemons.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { eq } from 'drizzle-orm';

import type {
AgentConfig,
CreateDaemonRequest,
DaemonStatus,
Governance,
Trigger,
} from '@paws/domain-daemon';
import type { AgentConfig } from '@paws/domain-agent';
import type { CreateDaemonRequest, DaemonStatus, Trigger } from '@paws/domain-daemon';
import type { Governance } from '@paws/domain-policy';
import type { NetworkConfig } from '@paws/domain-network';
import type { Resources, Workload } from '@paws/domain-session';

Expand Down
2 changes: 2 additions & 0 deletions apps/worker/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"@paws/firecracker": "workspace:*",
"@paws/logger": "workspace:*",
"@paws/proxy": "workspace:*",
"@paws/runtime": "workspace:*",
"@paws/runtime-firecracker": "workspace:*",
"@paws/snapshot-store": "workspace:*",
"hono": "^4.7.0",
"neverthrow": "^8.2.0",
Expand Down
14 changes: 4 additions & 10 deletions apps/worker/src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function createSessionApp(deps: AppDeps) {
queued: semaphore.queued,
available: semaphore.available,
},
pool: executor.poolStats,
runtime: executor.capabilities.fullLinux ? 'firecracker' : 'lightweight',
snapshot: {
syncEnabled: !!syncLoop,
currentVersion: syncStatus?.currentVersion ?? 0,
Expand Down Expand Up @@ -114,6 +114,7 @@ export function createSessionApp(deps: AppDeps) {
const sessionId = randomUUID();

// Fire-and-forget — execute in background, track results
const sessionStartTime = Date.now();
executor.execute(sessionId, parsed.data).then(
(result) => {
const status = result.exitCode === 0 ? 'completed' : 'failed';
Expand All @@ -135,7 +136,7 @@ export function createSessionApp(deps: AppDeps) {
stdout: '',
stderr: err instanceof Error ? err.message : String(err),
output: undefined,
durationMs: Date.now() - Date.now(),
durationMs: Date.now() - sessionStartTime,
completedAt: new Date().toISOString(),
});
},
Expand All @@ -156,14 +157,7 @@ export function createSessionApp(deps: AppDeps) {
status: 'running',
startedAt: active.startedAt.toISOString(),
worker: workerName,
exposedPorts: active.exposedTunnels?.map((t) => ({
port: t.port,
url: t.publicUrl,
label: t.label,
access: t.access,
pin: t.pin,
shareLink: t.shareLink,
})),
exposedPorts: active.exposedPorts,
});
}

Expand Down
29 changes: 25 additions & 4 deletions apps/worker/src/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createLogger } from '@paws/logger';
import { createPortPool } from '@paws/firecracker';
import { createFirecrackerRuntime } from '@paws/runtime-firecracker';
import { createRuntimeRegistry } from '@paws/runtime';

import { createCallHome } from './call-home.js';
import { createSessionApp } from './routes.js';
Expand All @@ -9,6 +11,7 @@ import { createSyncLoop } from './sync/sync-loop.js';
import type { SyncLoop } from './sync/sync-loop.js';
import { createPangolinResourceManager } from './tunnel/pangolin-resources.js';
import type { PangolinResourceManager } from './tunnel/pangolin-resources.js';
import { createPangolinPortExposure } from './tunnel/port-exposure.js';

// Read version from env (Docker) or VERSION file (bare metal)
const PAWS_VERSION =
Expand Down Expand Up @@ -100,16 +103,31 @@ const llmGateway =
}
: undefined;

const executor = createExecutor({
// --- Runtime setup ---
// Create the Firecracker runtime adapter (owns all VM lifecycle)
const firecrackerRuntime = createFirecrackerRuntime({
snapshotDir: SNAPSHOT_DIR,
snapshotBaseDir: SNAPSHOT_BASE_DIR,
vmBaseDir: VM_BASE_DIR,
sshKeyPath: SSH_KEY_PATH,
semaphore,
workerName: WORKER_NAME,
maxConcurrent: MAX_CONCURRENT,
portPool,
pangolinResources,
workerExternalUrl: WORKER_EXTERNAL_URL || undefined,
});

// Register in the runtime registry (future: support multiple runtimes)
const runtimeRegistry = createRuntimeRegistry();
runtimeRegistry.register(firecrackerRuntime);

// Port exposure provider (Pangolin tunnels)
const portExposure = pangolinResources ? createPangolinPortExposure(pangolinResources) : undefined;

// Create the executor (thin wrapper around runtime)
const executor = createExecutor({
runtime: runtimeRegistry.resolve(),
semaphore,
workerName: WORKER_NAME,
portExposure,
llmGateway,
});

Expand Down Expand Up @@ -187,12 +205,15 @@ const portExposureStatus = pangolinResources
? `direct (${WORKER_EXTERNAL_URL})`
: 'disabled';

const runtimeName = runtimeRegistry.resolve().name;

console.log(`
/\\_/\\
( o.o ) paws worker v${PAWS_VERSION}
> ^ <

Listening on :${PORT}
Runtime: ${runtimeName}
Max concurrent VMs: ${MAX_CONCURRENT}
Max queued: ${MAX_QUEUED}
Snapshot: ${SNAPSHOT_DIR}
Expand Down
Loading
Loading