diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0f46d0..aef4bf9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: test-and-build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 @@ -31,11 +31,11 @@ jobs: runs-on: ubuntu-latest needs: test-and-build steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v6 with: node-version: 22 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f53fa9e..75539db 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,7 @@ jobs: validate-release: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 @@ -55,7 +55,7 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 @@ -96,7 +96,7 @@ jobs: script: build:release:darwin-arm64 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: oven-sh/setup-bun@v2 @@ -108,7 +108,7 @@ jobs: run: bun run ${{ matrix.script }} - name: Upload release artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.artifact }} path: dist/${{ matrix.artifact }} @@ -121,10 +121,10 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Download compiled binaries - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: path: dist merge-multiple: true diff --git a/package.json b/package.json index e0f8418..82c1702 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@acai.sh/cli", - "version": "0.0.3", + "version": "0.0.4", "license": "Apache-2.0", "description": "CLI for syncing and querying acai.sh spec-driven development data.", "module": "index.ts", diff --git a/src/env-file.e2e.test.ts b/src/env-file.e2e.test.ts new file mode 100644 index 0000000..2feaffd --- /dev/null +++ b/src/env-file.e2e.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, test } from "bun:test"; +import { createTempWorkspace } from "../test/support/e2e.ts"; + +const workspaceRoot = import.meta.dir + "/.."; + +function stripEnv(keys: string[]): Record { + const env: Record = {}; + for (const [k, v] of Object.entries(process.env)) { + if (v !== undefined && !keys.includes(k)) { + env[k] = v; + } + } + return env; +} + +async function runCliInDir( + cwd: string, + args: string[], + env: Record, +) { + const proc = Bun.spawn( + ["bun", workspaceRoot + "/src/index.ts", ...args], + { cwd, env, stdin: "ignore", stdout: "pipe", stderr: "pipe" }, + ); + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(proc.stdout).text(), + new Response(proc.stderr).text(), + proc.exited, + ]); + return { exitCode, stdout, stderr }; +} + +describe("env-file loading", () => { + test("cli-core.AUTH.2 loads ACAI_API_TOKEN from .env when not set in the process environment", async () => { + const workspace = await createTempWorkspace({ + ".env": "ACAI_API_TOKEN=secret-from-dotenv\n", + }); + + try { + const cleanEnv = stripEnv(["ACAI_API_TOKEN"]); + const result = await runCliInDir( + workspace.root, + ["features", "--impl", "product/impl"], + cleanEnv, + ); + + expect(result.exitCode).not.toBe(2); + expect(result.stderr).not.toContain( + "Missing API bearer token configuration.", + ); + } finally { + await workspace.cleanup(); + } + }); + + test("cli-core.AUTH.2 explicit env var takes precedence over .env", async () => { + const workspace = await createTempWorkspace({ + ".env": "ACAI_API_TOKEN=from-dotenv\n", + }); + + try { + const cleanEnv = stripEnv(["ACAI_API_TOKEN"]); + cleanEnv["ACAI_API_TOKEN"] = "from-env"; + const result = await runCliInDir( + workspace.root, + ["features", "--impl", "product/impl"], + cleanEnv, + ); + + expect(result.exitCode).not.toBe(2); + expect(result.stderr).not.toContain( + "Missing API bearer token configuration.", + ); + } finally { + await workspace.cleanup(); + } + }); +}); diff --git a/src/index.ts b/src/index.ts index f046c30..a9ce140 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ #!/usr/bin/env node +try { process.loadEnvFile?.(); } catch {} import { runCli } from "./core/cli.ts"; import { defaultRuntime } from "./core/runtime.ts";