diff --git a/test-setup.ts b/test-setup.ts index 1cd3470f9..31234cc63 100644 --- a/test-setup.ts +++ b/test-setup.ts @@ -18,6 +18,7 @@ import { afterEach, beforeAll } from 'bun:test'; import * as os from 'node:os'; import * as path from 'node:path'; +import { CAPY_LAUNCH_MARKERS } from './scripts/lib/shard-engine'; // State-root hermeticity (docs/state-root.md). Tests isolate state with // GSTACK_HOME, but GSTACK_STATE_ROOT and GSTACK_STATE_DIR outrank or join it @@ -37,7 +38,7 @@ for (const name of ['GSTACK_STATE_ROOT', 'GSTACK_STATE_DIR']) { // run from a shell that sourced the launch file would hand every product child // an unattended Capy session it never set up. The shard engine strips the same // list for the lanes; this reaches direct runs too. -for (const name of ['GSTACK_SESSION_KIND', 'GSTACK_CAPY', 'GSTACK_EPHEMERAL', 'GSTACK_INSTALL_VERDICT']) delete process.env[name]; +for (const name of CAPY_LAUNCH_MARKERS) delete process.env[name]; process.env.GSTACK_TEST_LEGACY_ROOT = path.join(os.tmpdir(), `gstack-test-legacy-root-${process.pid}-${Date.now()}-unused`); // Workflow leases (bin/gstack-lease) default to the installation's git dir; // for the dev checkout under test that is this repo's .git, and a live test diff --git a/test/launch-env-echo-ratchet.test.ts b/test/launch-env-echo-ratchet.test.ts index be0bb4577..f6bc6dcf8 100644 --- a/test/launch-env-echo-ratchet.test.ts +++ b/test/launch-env-echo-ratchet.test.ts @@ -26,6 +26,7 @@ import { describe, expect, test } from 'bun:test'; import * as fs from 'fs'; import * as path from 'path'; +import { CAPY_LAUNCH_MARKERS } from '../scripts/lib/shard-engine'; const ROOT = path.resolve(import.meta.dir, '..'); @@ -110,10 +111,13 @@ function markdownTargets(): string[] { /^capy\/skill\/gstack\/[^/]+\.md$/.test(rel)); } +/** Every shell helper under bin/, the setup script and the install scripts callers run first. */ function shellTargets(): string[] { - return fs.readdirSync(path.join(ROOT, 'bin')).map(name => path.join('bin', name)).filter(rel => { + const candidates = [...fs.readdirSync(path.join(ROOT, 'bin')).map(name => path.join('bin', name)), 'setup', + ...fs.readdirSync(path.join(ROOT, 'scripts')).filter(name => name.endsWith('.sh')).map(name => path.join('scripts', name))]; + return candidates.filter(rel => { const full = path.join(ROOT, rel); - return fs.statSync(full).isFile() && isShell(rel, fs.readFileSync(full, 'utf8')); + return fs.existsSync(full) && fs.statSync(full).isFile() && isShell(rel, fs.readFileSync(full, 'utf8')); }); } @@ -177,6 +181,7 @@ describe('launch-env echo ratchet', () => { const installer = fs.readFileSync(path.join(ROOT, 'bin/gstack-capy-install'), 'utf8'); expect(installer).toContain('LAUNCH_FILE="${VERDICT%.json}.env"'); expect(installer).toContain('chmod 0600 "$tmp"'); + for (const name of CAPY_LAUNCH_MARKERS) expect(installer, name).toMatch(new RegExp(`^\\s*echo "export ${name}=`, 'm')); expect(installer).toContain('echo "GSTACK_LAUNCH_FILE: $LAUNCH_FILE"'); for (const file of ['ship/sections/documentation.md', 'document-release/SKILL.md', 'autoplan/DRIVER.md', 'capy/skill/gstack/SKILL.md']) { const text = fs.readFileSync(path.join(ROOT, file), 'utf8');