(opts: CreateWorkspaceServiceOptions)
| 225 | } |
| 226 | |
| 227 | export async function createWorkspaceService(opts: CreateWorkspaceServiceOptions): Promise<WorkspaceService> { |
| 228 | const config = loadConfig({ webPort: opts.webPort }); |
| 229 | const inboxStore = opts.inboxStore; |
| 230 | const processLock = await acquireWorkspaceProcessLock(config.launcherRoot); |
| 231 | |
| 232 | const registry = await WorkspaceRegistry.load( |
| 233 | `${config.launcherRoot}/workspaces.json`, |
| 234 | launcherLogger.child({ scope: 'registry' }), |
| 235 | ); |
| 236 | |
| 237 | const sessionRegistry = await SessionRegistry.load( |
| 238 | join(config.launcherRoot, 'state'), |
| 239 | launcherLogger.child({ scope: 'session-registry' }), |
| 240 | ); |
| 241 | |
| 242 | // The headless-task management plane. load() reconciles leftover `running` |
| 243 | // records (zombies from a previous Alice life) → `interrupted`. Each task's |
| 244 | // full stdout/stderr lands in `headlessLogsDir` (pruned with its record). |
| 245 | const headlessLogsDir = join(config.launcherRoot, 'state', 'headless-logs'); |
| 246 | const headlessTasks = await HeadlessTaskRegistry.load( |
| 247 | join(config.launcherRoot, 'state', 'headless-tasks.json'), |
| 248 | launcherLogger.child({ scope: 'headless-registry' }), |
| 249 | { logsDir: headlessLogsDir }, |
| 250 | ); |
| 251 | |
| 252 | const scrollbackStore = new ScrollbackStore( |
| 253 | join(config.launcherRoot, 'state'), |
| 254 | launcherLogger.child({ scope: 'scrollback' }), |
| 255 | ); |
| 256 | |
| 257 | const templates = await TemplateRegistry.load( |
| 258 | config.templatesDir, |
| 259 | launcherLogger.child({ scope: 'templates' }), |
| 260 | ); |
| 261 | if (config.legacyBootstrapScript) { |
| 262 | launcherLogger.warn('config.legacy_bootstrap_script', { |
| 263 | script: config.legacyBootstrapScript, |
| 264 | }); |
| 265 | templates.registerSynthetic({ |
| 266 | name: 'legacy', |
| 267 | description: 'legacy AQ_BOOTSTRAP_SCRIPT entry — migrate to a real template', |
| 268 | bootstrapScript: config.legacyBootstrapScript, |
| 269 | filesDir: '', |
| 270 | templateDir: '', |
| 271 | version: '0.0.0', |
| 272 | defaultAgents: ['claude'], |
| 273 | injectTools: false, |
| 274 | injectPersona: false, |
| 275 | bundledSkills: [], |
| 276 | }); |
| 277 | } |
| 278 | |
| 279 | const adapters = new AdapterRegistry(); |
| 280 | adapters.register(claudeAdapter, { default: true }); |
| 281 | adapters.register(codexAdapter); |
| 282 | adapters.register(opencodeAdapter); |
| 283 | adapters.register(piAdapter); |
| 284 | adapters.register(shellAdapter); |
no test coverage detected