From d10aa39408472d5ae951c0cc339ac5bad088d8b8 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 14 Aug 2026 19:19:46 -0700 Subject: [PATCH] fix(setup): ship supabase/config.sh with every host runtime root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Distinct from the lib/-beside-bin/ defect: gstack-telemetry-sync, gstack-update-check, gstack-security-dashboard and gstack-community-dashboard all source $GSTACK_DIR/supabase/config.sh to resolve GSTACK_SUPABASE_URL, where GSTACK_DIR is the installed root (parent of bin/). The [ -f ... ] guard means a root without the file degrades SILENTLY — telemetry and update checks just stop resolving the project URL on non-Claude installs. Closes #2215. setup now links supabase/config.sh (file-level on purpose — migrations/ and functions/ are dev-only) via _link_or_copy at all five host-install sites: the PR's four (Codex, Factory, OpenCode runtime roots + the Kiro block) plus the .agents sidecar, whose bin/ resolves the same relative path and which the PR predates covering. The runtime-root test now asserts supabase/config.sh is present in every built root, on both the symlink and Windows-copy branches. Contributed by @jizusun (PR #2216). Co-Authored-By: Claude Fable 5 --- setup | 27 ++++++++++++++++++++++++++ test/setup-runtime-lib-command.test.ts | 10 +++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/setup b/setup index 34aa72758..c28b44a71 100755 --- a/setup +++ b/setup @@ -780,6 +780,13 @@ create_agents_sidecar() { fi fi done + + # supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL + # (file-level on purpose: migrations/ and functions/ are dev-only) + if [ -f "$SOURCE_GSTACK_DIR/supabase/config.sh" ]; then + mkdir -p "$agents_gstack/supabase" + _link_or_copy "$SOURCE_GSTACK_DIR/supabase/config.sh" "$agents_gstack/supabase/config.sh" + fi } # ─── Helper: create a minimal ~/.codex/skills/gstack runtime root ─────────── @@ -829,6 +836,11 @@ create_codex_runtime_root() { if [ -f "$gstack_dir/ETHOS.md" ]; then _link_or_copy "$gstack_dir/ETHOS.md" "$codex_gstack/ETHOS.md" fi + # supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL + if [ -f "$gstack_dir/supabase/config.sh" ]; then + mkdir -p "$codex_gstack/supabase" + _link_or_copy "$gstack_dir/supabase/config.sh" "$codex_gstack/supabase/config.sh" + fi } create_factory_runtime_root() { @@ -870,6 +882,11 @@ create_factory_runtime_root() { if [ -f "$gstack_dir/ETHOS.md" ]; then _link_or_copy "$gstack_dir/ETHOS.md" "$factory_gstack/ETHOS.md" fi + # supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL + if [ -f "$gstack_dir/supabase/config.sh" ]; then + mkdir -p "$factory_gstack/supabase" + _link_or_copy "$gstack_dir/supabase/config.sh" "$factory_gstack/supabase/config.sh" + fi } create_opencode_runtime_root() { @@ -926,6 +943,11 @@ create_opencode_runtime_root() { if [ -f "$gstack_dir/ETHOS.md" ]; then _link_or_copy "$gstack_dir/ETHOS.md" "$opencode_gstack/ETHOS.md" fi + # supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL + if [ -f "$gstack_dir/supabase/config.sh" ]; then + mkdir -p "$opencode_gstack/supabase" + _link_or_copy "$gstack_dir/supabase/config.sh" "$opencode_gstack/supabase/config.sh" + fi } link_factory_skill_dirs() { @@ -1142,6 +1164,11 @@ if [ "$INSTALL_KIRO" -eq 1 ]; then if [ -f "$SOURCE_GSTACK_DIR/ETHOS.md" ]; then _link_or_copy "$SOURCE_GSTACK_DIR/ETHOS.md" "$KIRO_GSTACK/ETHOS.md" fi + # supabase/config.sh — required by gstack-telemetry-sync to resolve GSTACK_SUPABASE_URL + if [ -f "$SOURCE_GSTACK_DIR/supabase/config.sh" ]; then + mkdir -p "$KIRO_GSTACK/supabase" + _link_or_copy "$SOURCE_GSTACK_DIR/supabase/config.sh" "$KIRO_GSTACK/supabase/config.sh" + fi # gstack-upgrade skill if [ -f "$AGENTS_DIR/gstack-upgrade/SKILL.md" ]; then _link_or_copy "$AGENTS_DIR/gstack-upgrade/SKILL.md" "$KIRO_GSTACK/gstack-upgrade/SKILL.md" diff --git a/test/setup-runtime-lib-command.test.ts b/test/setup-runtime-lib-command.test.ts index d116bdfb3..1105f9152 100644 --- a/test/setup-runtime-lib-command.test.ts +++ b/test/setup-runtime-lib-command.test.ts @@ -34,7 +34,7 @@ function extractFunction(name: string): string { // a complete statement list. function extractKiroBlock(): string { const startAnchor = 'KIRO_GSTACK="$KIRO_SKILLS/gstack"'; - const endAnchor = '_link_or_copy "$SOURCE_GSTACK_DIR/browse/bin" "$KIRO_GSTACK/browse/bin"'; + const endAnchor = '_link_or_copy "$SOURCE_GSTACK_DIR/supabase/config.sh" "$KIRO_GSTACK/supabase/config.sh"\n fi'; const start = SETUP_SRC.indexOf(startAnchor); const end = SETUP_SRC.indexOf(endAnchor, start); if (start < 0 || end < 0) throw new Error('Could not locate the Kiro install block in setup'); @@ -48,6 +48,7 @@ interface CommandResult { runStderr: string; learningsWritten: boolean; libIsSymlink: boolean | null; + supabaseConfigPresent: boolean; } // Build one host runtime root inside a sandbox using the real setup shell code @@ -93,6 +94,11 @@ function buildRootAndRunCommand( runStderr: run.stderr, learningsWritten, libIsSymlink: libLst ? libLst.isSymbolicLink() : null, + // Distinct defect (#2215): telemetry-class bin scripts source + // $GSTACK_DIR/supabase/config.sh to resolve GSTACK_SUPABASE_URL. The + // [ -f ... ] guard means a missing file degrades SILENTLY, so only a + // presence check on the installed root catches it. + supabaseConfigPresent: fs.existsSync(path.join(rootDir, 'supabase', 'config.sh')), }; } finally { fs.rmSync(sandbox, { recursive: true, force: true }); @@ -158,6 +164,7 @@ describe.skipIf(process.platform === 'win32')('setup: bin commands resolve sibli expect(r.runStderr).not.toContain('lib/jsonl-store.ts'); expect(r.runStatus).toBe(0); expect(r.learningsWritten).toBe(true); + expect(r.supabaseConfigPresent).toBe(true); }); test(`${host} root (Windows copy install): gstack-learnings-log imports ../lib and writes the learning`, () => { @@ -168,6 +175,7 @@ describe.skipIf(process.platform === 'win32')('setup: bin commands resolve sibli expect(r.runStderr).not.toContain('lib/jsonl-store.ts'); expect(r.runStatus).toBe(0); expect(r.learningsWritten).toBe(true); + expect(r.supabaseConfigPresent).toBe(true); }); }