mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-11 22:50:06 +00:00
fix: Tweaks on codespace opencode setup (no-changelog) (#39488)
This commit is contained in:
@@ -46,7 +46,8 @@ create an 8-core Codespace by default.
|
||||
terminal's own text selection, hold **Shift** and drag.
|
||||
- **Reattach** by running the same session command from any machine.
|
||||
- Each named session gets its own worktree (`/workspaces/wt-<name>`, branch
|
||||
`session/<name>`), so parallel agents never touch each other's tree. Builds
|
||||
`session/<name>`), so parallel agents never touch each other's tree. A new
|
||||
branch starts from the latest `origin/master`. Builds
|
||||
in fresh worktrees are cache-hits via a shared turbo cache.
|
||||
- First codespace creation takes ~20 min uncached (image + full build). After
|
||||
that, sessions attach instantly; new worktrees cost a `pnpm install` (~10 s: the
|
||||
@@ -84,9 +85,12 @@ For the TUI, install the same OpenCode version as the remote server. The
|
||||
for new images:
|
||||
|
||||
```bash
|
||||
pnpm add --global opencode-ai@<version>
|
||||
npm install -g opencode-ai@<version>
|
||||
```
|
||||
|
||||
Use npm, not pnpm. The package gets its binary from a `postinstall` script.
|
||||
pnpm does not run that script by default.
|
||||
|
||||
The launcher checks both versions. It reports a mismatch with both version
|
||||
numbers before it opens the TUI. An existing Codespace can have a different
|
||||
version. Install that version locally, or use `--web`. Browser mode does not
|
||||
@@ -423,7 +427,7 @@ partial mapping breaks it.
|
||||
| Event | Running processes | Disk (checkout, worktrees, chat history) |
|
||||
|---|---|---|
|
||||
| Detach / close laptop / network drop | ✅ keep running | ✅ |
|
||||
| Stop, or idle timeout (default 30 min, max 4 h) | ❌ killed | ✅ |
|
||||
| Stop, or idle timeout (2 h for a codespace that `pnpm session` creates, max 4 h) | ❌ killed | ✅ |
|
||||
| Delete (`pnpm session rm`) | ❌ | ❌ (push your branches first) |
|
||||
|
||||
After a stop, `pnpm session <name>` restarts the codespace (~30–60 s); run
|
||||
|
||||
@@ -101,7 +101,10 @@ test('starts a named OpenCode session in a worktree', () => {
|
||||
assert.match(command, /unset AGENT_WORKER_TOKEN N8N_DEQUEUE_URL SLACK_BOT_TOKEN/);
|
||||
assert.match(command, /OPENCODE_CONFIG_CONTENT/);
|
||||
assert.match(command, /export N8N_AGENT_RUNTIME=sandbox; unset N8N_AGENT_PROFILE/);
|
||||
assert.match(command, /git -C \/workspaces\/n8n worktree add "\/workspaces\/wt-fix-flaky"/);
|
||||
assert.match(
|
||||
command,
|
||||
/git -C \/workspaces\/n8n fetch origin master; git -C \/workspaces\/n8n worktree add --no-track -b "session\/fix-flaky" "\/workspaces\/wt-fix-flaky" origin\/master/,
|
||||
);
|
||||
assert.match(command, /cd "\/workspaces\/wt-fix-flaky" && opencode --auto --model test/);
|
||||
assert.doesNotMatch(command, /unset OPENROUTER_API_KEY/);
|
||||
assert.doesNotMatch(command, /claude plugin/);
|
||||
|
||||
@@ -201,7 +201,11 @@ for (const signal of ['SIGINT', 'SIGHUP']) {
|
||||
}
|
||||
|
||||
for (const [label, env, message] of [
|
||||
['a version mismatch', { TEST_SERVER_VERSION: '1.14.22' }, /versions differ/],
|
||||
[
|
||||
'a version mismatch',
|
||||
{ TEST_SERVER_VERSION: '1.14.22' },
|
||||
/versions differ.*npm install -g opencode-ai@1\.14\.22/,
|
||||
],
|
||||
['an authentication failure', { TEST_UNAUTHORIZED: '1' }, /health check failed \(401\)/],
|
||||
['a tunnel startup failure', { TEST_TUNNEL_FAIL: '1' }, /SSH tunnel closed/],
|
||||
['a remote preparation failure', { TEST_BOOTSTRAP_FAIL: '1' }, /Could not prepare/],
|
||||
|
||||
@@ -132,6 +132,10 @@ function prepareWorkspace({ name, directory, mainDirectory, stateDir }) {
|
||||
'--quiet',
|
||||
`refs/heads/${branch}`,
|
||||
]).status === 0;
|
||||
if (!exists)
|
||||
spawnSync('git', ['-C', mainDirectory, 'fetch', 'origin', 'master'], {
|
||||
stdio: ['ignore', 2, 2],
|
||||
});
|
||||
run(
|
||||
'git',
|
||||
[
|
||||
@@ -139,9 +143,9 @@ function prepareWorkspace({ name, directory, mainDirectory, stateDir }) {
|
||||
mainDirectory,
|
||||
'worktree',
|
||||
'add',
|
||||
...(exists ? [] : ['-b', branch]),
|
||||
...(exists ? [] : ['--no-track', '-b', branch]),
|
||||
directory,
|
||||
...(exists ? [branch] : []),
|
||||
exists ? branch : 'origin/master',
|
||||
],
|
||||
{ stdio: ['ignore', 2, 2] },
|
||||
);
|
||||
|
||||
@@ -40,7 +40,8 @@ function fixture(t) {
|
||||
'git',
|
||||
`
|
||||
if (args.includes('show-ref')) process.exit(fs.existsSync(file('branch-exists')) ? 0 : 1);
|
||||
fs.mkdirSync(args.includes('-b') ? args.at(-1) : args.at(-2), { recursive: true });
|
||||
if (args.includes('fetch')) process.exit(0);
|
||||
fs.mkdirSync(args.at(-2), { recursive: true });
|
||||
`,
|
||||
);
|
||||
bin(
|
||||
@@ -151,6 +152,23 @@ test(
|
||||
const f = fixture(t);
|
||||
const first = await f.prepare({ name: 'fix-flaky' });
|
||||
assert.equal(first.directory, join(f.dir, 'wt-fix-flaky'));
|
||||
const git = f.commands().filter((entry) => entry.command === 'git');
|
||||
assert.deepEqual(
|
||||
git.map((entry) => entry.args.slice(2)),
|
||||
[
|
||||
['show-ref', '--verify', '--quiet', 'refs/heads/session/fix-flaky'],
|
||||
['fetch', 'origin', 'master'],
|
||||
[
|
||||
'worktree',
|
||||
'add',
|
||||
'--no-track',
|
||||
'-b',
|
||||
'session/fix-flaky',
|
||||
first.directory,
|
||||
'origin/master',
|
||||
],
|
||||
],
|
||||
);
|
||||
assert.equal(first.sessionID, 'ses_1');
|
||||
assert.deepEqual(await f.prepare({ name: 'fix-flaky' }), first);
|
||||
const second = await f.prepare({ name: 'another-task' });
|
||||
|
||||
@@ -220,7 +220,7 @@ export async function connectOpenCode(options, ensureCodespace) {
|
||||
const health = await waitForTunnel(url, state.password, tunnel, controller.signal);
|
||||
if (version && health.version !== version) {
|
||||
throw new Error(
|
||||
`OpenCode versions differ: local ${version}, server ${health.version}. Install the matching local version, or use --web or --legacy. The remote server is still running.`,
|
||||
`OpenCode versions differ: local ${version}, server ${health.version}. Install the matching version with \`npm install -g opencode-ai@${health.version}\`, or use --web or --legacy. The remote server is still running.`,
|
||||
);
|
||||
}
|
||||
const stopped = new Promise((resolve) =>
|
||||
|
||||
@@ -63,6 +63,8 @@ function ensureCodespace() {
|
||||
DEVCONTAINER,
|
||||
'-m',
|
||||
MACHINE,
|
||||
'--idle-timeout',
|
||||
'2h',
|
||||
);
|
||||
if (status !== 0) {
|
||||
console.error('Codespace create failed. Authorize the permissions prompt above, then retry.');
|
||||
@@ -118,7 +120,8 @@ function remoteCommand(session, launcher, extraArgs) {
|
||||
return [
|
||||
prelude,
|
||||
`if [ ! -d "${wt}" ]; then echo "Setting up worktree ${wt}…"`,
|
||||
`git -C /workspaces/n8n worktree add "${wt}" -b "${branch}" 2>/dev/null || git -C /workspaces/n8n worktree add "${wt}" "${branch}"`,
|
||||
`git -C /workspaces/n8n fetch origin master`,
|
||||
`git -C /workspaces/n8n worktree add --no-track -b "${branch}" "${wt}" origin/master 2>/dev/null || git -C /workspaces/n8n worktree add "${wt}" "${branch}"`,
|
||||
`(cd "${wt}" && pnpm install); fi`,
|
||||
`cd "${wt}" && ${command}`,
|
||||
].join('; ');
|
||||
|
||||
Reference in New Issue
Block a user