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
9 changes: 9 additions & 0 deletions setup
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,9 @@ create_codex_runtime_root() {
if [ -d "$gstack_dir/bin" ]; then
_link_or_copy "$gstack_dir/bin" "$codex_gstack/bin"
fi
if [ -d "$gstack_dir/lib" ]; then
_link_or_copy "$gstack_dir/lib" "$codex_gstack/lib"
fi
if [ -d "$gstack_dir/browse/dist" ]; then
_link_or_copy "$gstack_dir/browse/dist" "$codex_gstack/browse/dist"
fi
Expand Down Expand Up @@ -836,6 +839,9 @@ create_factory_runtime_root() {
if [ -d "$gstack_dir/bin" ]; then
_link_or_copy "$gstack_dir/bin" "$factory_gstack/bin"
fi
if [ -d "$gstack_dir/lib" ]; then
_link_or_copy "$gstack_dir/lib" "$factory_gstack/lib"
fi
if [ -d "$gstack_dir/browse/dist" ]; then
_link_or_copy "$gstack_dir/browse/dist" "$factory_gstack/browse/dist"
fi
Expand Down Expand Up @@ -874,6 +880,9 @@ create_opencode_runtime_root() {
if [ -d "$gstack_dir/bin" ]; then
_link_or_copy "$gstack_dir/bin" "$opencode_gstack/bin"
fi
if [ -d "$gstack_dir/lib" ]; then
_link_or_copy "$gstack_dir/lib" "$opencode_gstack/lib"
fi
if [ -d "$gstack_dir/browse/dist" ]; then
_link_or_copy "$gstack_dir/browse/dist" "$opencode_gstack/browse/dist"
fi
Expand Down
51 changes: 51 additions & 0 deletions test/setup-lib-sidecar.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Static invariant: runtime sidecar roots (codex, factory, opencode) that link
* bin/ MUST also link lib/, because bin/ scripts import from ../lib/ via
* relative paths (e.g. gstack-learnings-log imports lib/jsonl-store.ts).
*
* Without lib/ beside bin/ in the sidecar, those imports resolve to nothing and
* the script crashes at runtime.
*
* Issue: #2305
*/

import { describe, test, expect } from 'bun:test';
import * as fs from 'fs';
import * as path from 'path';

const SETUP = fs.readFileSync(path.join(import.meta.dir, '..', 'setup'), 'utf-8');

describe('setup links lib/ beside bin/ in runtime sidecars', () => {
const SIDECAR_VARS = ['codex_gstack', 'factory_gstack', 'opencode_gstack'];

for (const sidecar of SIDECAR_VARS) {
test(`${sidecar} links lib/ when bin/ is linked`, () => {
const binPattern = new RegExp(
`_link_or_copy "\\$gstack_dir/bin" "\\$${sidecar}/bin"`,
);
const libPattern = new RegExp(
`_link_or_copy "\\$gstack_dir/lib" "\\$${sidecar}/lib"`,
);

const hasBin = binPattern.test(SETUP);
const hasLib = libPattern.test(SETUP);

expect(hasBin).toBe(true);
expect(hasLib).toBe(true);
});
}

test('lib/ link uses _link_or_copy (not raw ln)', () => {
const libLines = SETUP.split('\n').filter(
(l) => l.includes('/lib"') && /\bln\s+-/.test(l),
);
expect(libLines).toEqual([]);
});

test('lib/ link is guarded by -d check', () => {
const libGuards = SETUP.split('\n').filter((l) =>
l.includes('if [ -d "$gstack_dir/lib" ]'),
);
expect(libGuards.length).toBeGreaterThanOrEqual(3);
});
});
Loading