@@ -2,6 +2,7 @@ import { AddressInfo, createServer } from 'net';
22import fs from 'fs/promises' ;
33import path from 'path' ;
44import os from 'os' ;
5+ import pkg from '../../package.json' ;
56import type { AgentConfig } from '../shared/types' ;
67import type { Workspace , CreateWorkspaceOptions } from './types' ;
78import { StateManager } from './state' ;
@@ -10,7 +11,8 @@ import * as docker from '../docker';
1011import { getContainerName } from '../docker' ;
1112import {
1213 VOLUME_PREFIX ,
13- WORKSPACE_IMAGE ,
14+ WORKSPACE_IMAGE_LOCAL ,
15+ WORKSPACE_IMAGE_REGISTRY ,
1416 SSH_PORT_RANGE_START ,
1517 SSH_PORT_RANGE_END ,
1618} from '../shared/constants' ;
@@ -32,6 +34,27 @@ async function findAvailablePort(start: number, end: number): Promise<number> {
3234 throw new Error ( `No available port in range ${ start } -${ end } ` ) ;
3335}
3436
37+ async function ensureWorkspaceImage ( ) : Promise < string > {
38+ const registryImage = `${ WORKSPACE_IMAGE_REGISTRY } :${ pkg . version } ` ;
39+
40+ const localExists = await docker . imageExists ( WORKSPACE_IMAGE_LOCAL ) ;
41+ if ( localExists ) {
42+ return WORKSPACE_IMAGE_LOCAL ;
43+ }
44+
45+ console . log ( `Pulling workspace image ${ registryImage } ...` ) ;
46+ const pulled = await docker . tryPullImage ( registryImage ) ;
47+ if ( pulled ) {
48+ return registryImage ;
49+ }
50+
51+ throw new Error (
52+ `Workspace image not found. Either:\n` +
53+ ` 1. Run 'perry build' to build locally, or\n` +
54+ ` 2. Check your network connection to pull from registry`
55+ ) ;
56+ }
57+
3558interface CopyCredentialOptions {
3659 source : string ;
3760 dest : string ;
@@ -373,12 +396,7 @@ export class WorkspaceManager {
373396 await this . state . setWorkspace ( workspace ) ;
374397
375398 try {
376- const imageReady = await docker . imageExists ( WORKSPACE_IMAGE ) ;
377- if ( ! imageReady ) {
378- throw new Error (
379- `Workspace image '${ WORKSPACE_IMAGE } ' not found. Run 'workspace build' first.`
380- ) ;
381- }
399+ const workspaceImage = await ensureWorkspaceImage ( ) ;
382400
383401 if ( ! ( await docker . volumeExists ( volumeName ) ) ) {
384402 await docker . createVolume ( volumeName ) ;
@@ -404,7 +422,7 @@ export class WorkspaceManager {
404422
405423 const containerId = await docker . createContainer ( {
406424 name : containerName ,
407- image : WORKSPACE_IMAGE ,
425+ image : workspaceImage ,
408426 hostname : name ,
409427 privileged : true ,
410428 restartPolicy : 'unless-stopped' ,
@@ -461,6 +479,7 @@ export class WorkspaceManager {
461479 ) ;
462480 }
463481
482+ const workspaceImage = await ensureWorkspaceImage ( ) ;
464483 const sshPort = await findAvailablePort ( SSH_PORT_RANGE_START , SSH_PORT_RANGE_END ) ;
465484
466485 const containerEnv : Record < string , string > = {
@@ -480,7 +499,7 @@ export class WorkspaceManager {
480499
481500 const containerId = await docker . createContainer ( {
482501 name : containerName ,
483- image : WORKSPACE_IMAGE ,
502+ image : workspaceImage ,
484503 hostname : name ,
485504 privileged : true ,
486505 restartPolicy : 'unless-stopped' ,
0 commit comments