import { tap, expect } from '@git.zone/tstest/tapbundle'; import * as childProcess from 'node:child_process'; import * as fs from 'node:fs/promises'; import * as os from 'node:os'; import * as path from 'node:path'; import { createRemoteEphemeralBootstrapCommand, createRemoteEphemeralReadinessCommand, createRemoteEphemeralPortAllocationCommand, createRemoteEphemeralRuntimeCacheCheckCommand, createRemoteEphemeralRuntimeMarkCommand, createRemoteOpenCodeToolCommand, createRemoteProjectListCommand, createRemoteProjectUpsertCommand, remoteOpenCodeToolScript, createRemoteBootstrapCommand, createRemoteInstallCommand, createRemoteServerInstallPlan, joinRemotePath, quoteRemotePath, quoteShellArg, } from '../packages/server-installer/ts/index.js'; tap.test('should create stable remote install paths', async () => { const plan = createRemoteServerInstallPlan({ serverVersion: '0.1.0', artifactName: 'remote-theia-linux-x64.tgz', platform: 'linux', arch: 'x64', }); expect(plan.paths.versionRoot).toEqual('~/.git.zone/ide/server/0.1.0'); expect(plan.paths.currentLink).toEqual('~/.git.zone/ide/server/current'); expect(plan.manifest.protocolVersion).toEqual(1); expect(plan.manifest.artifactName).toEqual('remote-theia-linux-x64.tgz'); }); tap.test('should quote shell arguments safely', async () => { expect(quoteShellArg("that's it")).toEqual("'that'\"'\"'s it'"); expect(quoteRemotePath('~/.git.zone/ide/server')).toEqual('"$HOME"/\'.git.zone/ide/server\''); expect(quoteRemotePath('$HOME/work/project')).toEqual('"$HOME"/\'work/project\''); expect(joinRemotePath('~/.git.zone/', '/ide/', '/0.1.0')).toEqual('~/.git.zone/ide/0.1.0'); }); tap.test('should render install and bootstrap commands', async () => { const plan = createRemoteServerInstallPlan({ serverVersion: '0.1.0', artifactName: 'remote-theia.tgz', }); const installCommand = createRemoteInstallCommand(plan); const bootstrapCommand = createRemoteBootstrapCommand({ serverVersion: '0.1.0', workspacePath: '/srv/work/project', theiaPort: 33990, opencodePort: 4096, opencodeUsername: 'opencode', opencodePassword: 'secret', }); expect(installCommand).toInclude('GITZONE_IDE_MANIFEST'); expect(installCommand).toInclude('"$HOME"/\'.git.zone/ide/server/0.1.0\''); expect(bootstrapCommand).toInclude('GITZONE_IDE_OPENCODE_PORT'); expect(bootstrapCommand).toInclude('GITZONE_IDE_DISABLE_OPENCODE_AUTOSTART'); expect(bootstrapCommand).toInclude('pnpm --dir'); }); tap.test('should render remote home paths as expandable shell paths', async () => { const bootstrapCommand = createRemoteBootstrapCommand({ serverVersion: '0.1.0', workspacePath: '$HOME', theiaPort: 33990, opencodePort: 4096, opencodeUsername: 'opencode', opencodePassword: 'secret', }); expect(bootstrapCommand).toInclude('test -d "$HOME"'); expect(bootstrapCommand).toInclude('export GITZONE_IDE_WORKSPACE="$HOME"'); expect(bootstrapCommand).toInclude('"$HOME"/\'.git.zone/ide/server/0.1.0/applications/remote-theia\''); }); tap.test('should render ephemeral runtime bootstrap without remote pnpm', async () => { const bootstrapCommand = createRemoteEphemeralBootstrapCommand({ serverVersion: '0.1.0', runtimeRoot: '/tmp/gitzone-ide-runtime-test', workspacePath: '$HOME', theiaPort: 33990, opencodePort: 4096, opencodeUsername: 'opencode', opencodePassword: 'secret', }); expect(bootstrapCommand).toInclude('/tmp/gitzone-ide-runtime-test/node/bin/node'); expect(bootstrapCommand).toInclude('lib/backend/main.js'); expect(bootstrapCommand).not.toInclude('pnpm'); expect(bootstrapCommand).toInclude('LD_LIBRARY_PATH'); expect(bootstrapCommand).toInclude('THEIA_CONFIG_DIR="$HOME"/\'.git.zone/ide/theia\''); expect(bootstrapCommand).toInclude('GITZONE_IDE_DISABLE_OPENCODE_AUTOSTART=\'1\''); expect(bootstrapCommand).toInclude('GITZONE_IDE_THEIA_COLOR_THEME=\'dark\''); expect(bootstrapCommand).toInclude("settings['workbench.colorTheme'] = colorTheme"); expect(bootstrapCommand).toInclude('"$HOME"/\'.git.zone/ide/logs\''); expect(bootstrapCommand).toInclude('runtimeRoot='); }); tap.test('should render ephemeral readiness check with remote logs', async () => { const readinessCommand = createRemoteEphemeralReadinessCommand({ runtimeRoot: '/tmp/gitzone-ide-runtime-test', theiaPort: 33990, waitSeconds: 2, }); expect(readinessCommand).toInclude('fetch'); expect(readinessCommand).toInclude('theia-33990.log'); expect(readinessCommand).toInclude('"$HOME"/\'.git.zone/ide/logs/theia-33990.log\''); expect(readinessCommand).toInclude('LD_LIBRARY_PATH'); }); tap.test('should render ephemeral runtime cache check command', async () => { const cacheCheckCommand = createRemoteEphemeralRuntimeCacheCheckCommand({ runtimeRoot: '/tmp/gitzone-ide-0.1.0-deadbeef', runtimeSha256: 'deadbeef', }); expect(cacheCheckCommand).toInclude('.gitzone-runtime-sha256'); expect(cacheCheckCommand).toInclude('test "$(cat'); expect(cacheCheckCommand).toInclude("'deadbeef'"); expect(cacheCheckCommand).toInclude('runtimeCache=hit'); }); tap.test('should render ephemeral runtime mark command', async () => { const markCommand = createRemoteEphemeralRuntimeMarkCommand({ runtimeRoot: '/tmp/gitzone-ide-0.1.0-deadbeef', runtimeSha256: 'deadbeef', }); expect(markCommand).toInclude('.gitzone-runtime-sha256.tmp'); expect(markCommand).toInclude("printf '%s"); expect(markCommand).toInclude("'deadbeef'"); expect(markCommand).toInclude('runtimeCache=stored'); }); tap.test('should render remote port allocation command', async () => { const portCommand = createRemoteEphemeralPortAllocationCommand({ runtimeRoot: '/tmp/gitzone-ide-runtime-test', count: 2, }); expect(portCommand).toInclude('/tmp/gitzone-ide-runtime-test/node/bin/node'); expect(portCommand).toInclude('ports='); expect(portCommand).toInclude('LD_LIBRARY_PATH'); }); tap.test('should render remote OpenCode tool bridge command', async () => { const command = createRemoteOpenCodeToolCommand({ runtimeRoot: '/tmp/gitzone-ide-runtime-test', workspacePath: '$HOME/project', toolName: 'read', }); expect(command).toInclude('/tmp/gitzone-ide-runtime-test/node/bin/node'); expect(command).toInclude('GITZONE_IDE_TOOL_NAME=\'read\''); expect(command).toInclude('GITZONE_IDE_WORKSPACE="$HOME"/\'project\''); expect(command).toInclude('GITZONE_IDE_RG_PATH'); expect(command).toInclude('fs.readFileSync(0'); }); tap.test('should execute remote OpenCode tool script with stdin payloads', async () => { const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'gitzone-opencode-tool-')); const filePath = path.join(tempDir, 'sample.txt'); await fs.writeFile(filePath, 'hello\nworld\n'); const readResult = runRemoteOpenCodeToolScript('read', tempDir, { filePath: 'sample.txt' }); expect(readResult.output).toInclude('1: hello'); const editResult = runRemoteOpenCodeToolScript('edit', tempDir, { filePath: 'sample.txt', oldString: 'world', newString: 'remote', }); expect(editResult.output).toInclude('Edit applied successfully'); expect(await fs.readFile(filePath, 'utf8')).toEqual('hello\nremote\n'); const patchResult = runRemoteOpenCodeToolScript('apply_patch', tempDir, { patchText: '*** Begin Patch\n*** Add File: nested/new.txt\n+created remotely\n*** End Patch', }); expect(patchResult.output).toInclude('A nested/new.txt'); expect(await fs.readFile(path.join(tempDir, 'nested', 'new.txt'), 'utf8')).toEqual('created remotely\n'); }); tap.test('should render remote project registry commands', async () => { const listCommand = createRemoteProjectListCommand({ runtimeRoot: '/tmp/gitzone-ide-runtime-test', }); const upsertCommand = createRemoteProjectUpsertCommand({ runtimeRoot: '/tmp/gitzone-ide-runtime-test', projectPath: '$HOME/project', title: 'Project', }); expect(listCommand).toInclude('projects.json'); expect(listCommand).toInclude('{"projects":[]}'); expect(upsertCommand).toInclude('GITZONE_IDE_PROJECT_PATH="$HOME"/\'project\''); expect(upsertCommand).toInclude('test -d "$GITZONE_IDE_PROJECT_PATH"'); expect(upsertCommand).toInclude('crypto.createHash'); }); const runRemoteOpenCodeToolScript = (toolName: string, workspacePath: string, args: Record) => { const result = childProcess.spawnSync(process.execPath, ['-e', remoteOpenCodeToolScript], { input: JSON.stringify({ args }), encoding: 'utf8', env: { ...process.env, GITZONE_IDE_TOOL_NAME: toolName, GITZONE_IDE_WORKSPACE: workspacePath, GITZONE_IDE_RG_PATH: '/not-found/rg', }, }); if (result.status !== 0) { throw new Error(result.stderr || `tool script failed with ${result.status}`); } return JSON.parse(result.stdout) as { output: string; metadata?: Record }; }; export default tap.start();