diff --git a/.github/workflows/opencode2-activation.yml b/.github/workflows/opencode2-activation.yml new file mode 100644 index 0000000..264ec86 --- /dev/null +++ b/.github/workflows/opencode2-activation.yml @@ -0,0 +1,138 @@ +name: OpenCode 2 Activation + +on: + pull_request: + paths: + - "src/source/opencode2/**" + - ".github/workflows/opencode2-activation.yml" + push: + branches: + - main + paths: + - "src/source/opencode2/**" + - ".github/workflows/opencode2-activation.yml" + workflow_dispatch: + +permissions: + contents: read + +jobs: + activation: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v6 + with: + persist-credentials: false + + - uses: actions/setup-node@v6 + with: + node-version: "24" + cache: npm + + - name: Initialize isolated OpenCode 2 paths + shell: bash + run: | + echo "HOME=$RUNNER_TEMP/opencode2-home" >> "$GITHUB_ENV" + echo "XDG_CONFIG_HOME=$RUNNER_TEMP/opencode2-home/.config" >> "$GITHUB_ENV" + echo "XDG_DATA_HOME=$RUNNER_TEMP/opencode2-home/.local/share" >> "$GITHUB_ENV" + echo "XDG_STATE_HOME=$RUNNER_TEMP/opencode2-home/.local/state" >> "$GITHUB_ENV" + + - run: npm ci + + - name: Install OpenCode 2 CLI with postinstall enabled + run: npm install -g --allow-scripts=@opencode-ai/cli @opencode-ai/cli@next + + - name: Install matching OpenCode 2 plugin API + run: npm install --no-save --package-lock=false @opencode-ai/plugin@next + + - name: Show tested V2 versions and host API declarations + shell: bash + run: | + node -p "require('./node_modules/@opencode-ai/plugin/package.json').version" + command -v opencode2 + opencode2 --version + node -p "JSON.stringify(require('./node_modules/@opencode-ai/plugin/package.json').exports, null, 2)" + for file in context session event command tool; do + echo "--- dist/promise/$file.d.ts ---" + sed -n '1,260p' "$GITHUB_WORKSPACE/node_modules/@opencode-ai/plugin/dist/promise/$file.d.ts" || true + echo "--- dist/promise/$file.js ---" + sed -n '1,260p' "$GITHUB_WORKSPACE/node_modules/@opencode-ai/plugin/dist/promise/$file.js" || true + done + + - name: Prepare dependency-free V2 activation probe + shell: bash + run: | + mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_STATE_HOME" + project="$RUNNER_TEMP/opencode-loop-v2-activation" + plugin_dir="$project/.opencode/plugins" + mkdir -p "$plugin_dir" + git init --quiet "$project" + git -C "$project" config user.email "opencode-loop-ci@example.invalid" + git -C "$project" config user.name "OpenCode Loop CI" + cat > "$plugin_dir/opencode-loop-v2-probe.js" <<'EOF' + import { writeFile } from "node:fs/promises" + + const id = "bybrawe.opencode-loop.v2.activation-probe" + const marker = new URL("../../v2-activation-marker.json", import.meta.url) + const keys = (value) => value && typeof value === "object" ? Object.keys(value).sort() : [] + + export default { + id, + async setup(ctx) { + await writeFile(marker, JSON.stringify({ + id, + activated: true, + keys: { + context: keys(ctx), + command: keys(ctx?.command), + event: keys(ctx?.event), + session: keys(ctx?.session), + tool: keys(ctx?.tool), + }, + capabilities: { + commandTransform: typeof ctx?.command?.transform === "function", + eventSubscribe: typeof ctx?.event?.subscribe === "function", + sessionHook: typeof ctx?.session?.hook === "function", + sessionPrompt: typeof ctx?.session?.prompt === "function", + toolTransform: typeof ctx?.tool?.transform === "function", + toolHook: typeof ctx?.tool?.hook === "function", + }, + }, null, 2), "utf8") + }, + } + EOF + git -C "$project" add .opencode/plugins/opencode-loop-v2-probe.js + git -C "$project" commit --quiet -m "init" + + - name: Verify dependency-free setup runs in real OpenCode 2 host + shell: bash + run: | + project="$RUNNER_TEMP/opencode-loop-v2-activation" + marker="$project/v2-activation-marker.json" + rm -f "$marker" + + opencode2 api get /api/command -H "x-opencode-directory: $project" > "$RUNNER_TEMP/opencode2-command.json" 2>&1 || true + if [ ! -f "$marker" ]; then + opencode2 api get /api/plugin -H "x-opencode-directory: $project" > "$RUNNER_TEMP/opencode2-plugin.json" 2>&1 || true + fi + + for attempt in $(seq 1 50); do + if [ -f "$marker" ]; then + cat "$marker" + node -e 'const fs=require("node:fs"); const value=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); if(value.id!=="bybrawe.opencode-loop.v2.activation-probe" || value.activated!==true) process.exit(1)' "$marker" + exit 0 + fi + sleep 0.2 + done + + echo "OpenCode 2 did not execute the local plugin setup hook." >&2 + cat "$RUNNER_TEMP/opencode2-command.json" >&2 || true + cat "$RUNNER_TEMP/opencode2-plugin.json" >&2 || true + exit 1 + + - name: Dump OpenCode 2 logs on failure + if: failure() + shell: bash + run: | + find "$XDG_DATA_HOME" -maxdepth 6 -type f -print -exec sh -c 'echo "--- $1"; tail -n 200 "$1"' _ {} \;