Skip to content
Merged
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
48 changes: 48 additions & 0 deletions .github/releases/v1.0.39.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
## opencode {VERSION}

{Prerelease/Stable} release from `{branch}` branch. A follow-up hardening train closing the v1.0.38 review leftovers: a credential-leak dependency fix, the platform group-kill primitive converged to a single source, and two test-robustness deliveries (a load-tolerant stall bound, real-component cleanup coverage), synced from dev back to main.

---

### 🏗️ Architecture / Refactor

- **Platform group-kill converged into one primitive, #515**: the win32 `taskkill /T /F` versus negative-pid `process.kill` branching existed as diverging copies in `util/process.stop` and the hook `execShell` kill group, with different error handling. `killGroupPid` is now the single source (POSIX signals the group; win32 awaits the taskkill exit code and throws, leaving fallback and logging to callers), reused by both call sites with zero behavior change: same signals, ordering, and grace constants, and the #500 process-group regression suite with real grandchildren passes. The published SDK keeps its documented synchronous copy (#503).

---

### ⚙️ CI / Engineering

- **Memory stall assertion made load-tolerant, #512**: the dead-connection test bounded a 40ms connectTimeout with a 200ms wall-clock assertion and flaked at 288ms on a loaded linux runner (raw setTimeout; TestClock cannot apply). The bound is now 2000ms, still separating fail-fast from hang, with the Stalled error-class assertion as the semantic check.
- **TUI route cleanup pinned against the real components, #514**: the #502 seam test mirrored the production subscription shape, so removing an onCleanup wrapper from the real routes left it green. The real Session and Prompt components now mount inside the production provider stack, and the SDK event bus must return to its baseline listener count after unmount; both wrappers were negative-verified (removal turns the test red).

---

### 📦 Dependencies / Tooling

- **mysql2 3.14.4 to 3.22.0, #513**: closes the open high-severity dependabot advisory (alert 110) where an auth-plugin downgrade to mysql_clear_password leaks plaintext credentials.

---

### 🧪 Test Summary

```
unit tests (linux): 4447 tests, 4423 pass, 0 fail (364 files)
tui suites: 48 pass, 0 fail in test/cli/tui (incl. 4 real-component cleanup tests)
targeted suites: memory + process + hook 215 pass, 0 fail (linux and macos)
typecheck: 29/29 packages green
lint: 4839 warnings, 0 errors (ratchet budget 4850)
```

---

### 🔍 Verification

- Negative verification for #514: removing either production onCleanup wrapper turns the new real-component test red (Expected 0, Received 1); restoring turns it green, with an empty diff against production files afterwards.
- Zero-behavior-change argument for #515 walked per branch in the delivery commit: stop's win32 fallback path (taskkill failure to single-process kill) is preserved through the throw/catch reshape.
- The companion review finding on the workflow worker_type catalog's native-primary filter was adjudicated intentional (catalog lists spawn-resolvable worker shapes; native build/plan appear only because block defaults compile to them) and recorded on #507 without code change.
- Issues #512-#515 were closed manually with merge evidence: GitHub fires closing references only on PRs targeting the default branch, and this delivery merged through dev (PR #516) first.
- specgit finish exited 0 (accepted) for the dev delivery; this sync PR carries the same content to main under its own verdict.

---

**Full changelog:** [`{previous_tag}`...`{current_tag}`](https://github.com/LeXwDeX/OpenCode-GraphAgent/compare/{previous_tag}...{current_tag})
98 changes: 98 additions & 0 deletions .github/workflows/dev-issue-autoclose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# ============================================================================
# 🧹 Dev · Issue Auto-Close
# ----------------------------------------------------------------------------
# Purpose: Mirror GitHub's native issue auto-close for PRs merged into `dev`.
# Native auto-close (`Closes #n` in the PR body) only fires when a PR
# merges into the DEFAULT branch (`main`). This repo delivers into
# `dev` first (two-tier Git Workflow), so dev-delivered issues would
# otherwise stay open until manual close (#433/#472/#496/#517 et al.).
# Trigger: `pull_request: types: [closed]`. The job-level `if` gates actual
# work to MERGED PRs whose base is `dev`; merges to `main` keep
# GitHub's native auto-close (no overlap).
# Jobs : autoclose — single Linux runner, pure event payload + `gh` CLI.
# No `actions/checkout`, no third-party actions. The PR body reaches
# the script ONLY via `env:` (script-injection safety); refs are
# matched case-insensitively against the official closing keywords
# followed by bare `#n` (plain-text scan of the whole body, matching
# GitHub's own scanner — refs inside fenced code blocks are included,
# best-effort native parity). Shared issue/PR number space guards:
# numbers resolving to a pull request are skipped, nonexistent
# numbers are skipped, already-CLOSED issues are skipped (no
# duplicate comments). Survivors are closed as `completed` with a
# comment naming the delivery PR.
# Notes : The whole matrix (extraction + guards) is exercised by the dry-run
# harness under /tmp/dev-issue-autoclose/ (see issue #519 evidence).
# Runs on every PR close event; non-dev or unmerged closes exit at
# the job-level `if` without consuming a runner step.
# ============================================================================

name: 🧹 Dev · Issue Auto-Close

on:
pull_request:
types: [closed]

permissions:
contents: read
issues: write
pull-requests: read

jobs:
autoclose:
name: Auto-close linked issues
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev'
runs-on: ubuntu-latest
steps:
- name: Close linked issues referenced in the PR body
env:
GH_TOKEN: ${{ github.token }}
PR_BODY: ${{ github.event.pull_request.body }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_URL: ${{ github.event.pull_request.html_url }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail

if [ -z "$PR_BODY" ]; then
echo "dev-issue-autoclose: PR #$PR_NUMBER has no body; nothing to do"
exit 0
fi

# Official closing keywords + bare #n, case-insensitive, deduped.
# Plain-text scan of the whole body (code fences included) mirrors
# GitHub's own scanner; qualified `owner/repo#n` and URL refs do not
# match (whitespace must sit directly before `#`).
refs=$(printf '%s' "$PR_BODY" \
| grep -oiE '\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)[[:space:]]+#[0-9]+\b' \
| grep -oE '#[0-9]+\b' \
| tr -d '#' \
| sort -nu \
|| true)

if [ -z "$refs" ]; then
echo "dev-issue-autoclose: PR #$PR_NUMBER body has no closing-keyword refs; nothing to do"
exit 0
fi

echo "dev-issue-autoclose: PR #$PR_NUMBER -> refs: $(echo "$refs" | tr '\n' ' ')"

for n in $refs; do
# Shared issue/PR number space: skip numbers that resolve to a PR.
if gh pr view "$n" --repo "$REPO" >/dev/null 2>&1; then
echo "dev-issue-autoclose: #$n is a pull request; skipping"
continue
fi
# Skip numbers that do not exist as issues.
if ! state=$(gh issue view "$n" --repo "$REPO" --json state --jq .state 2>/dev/null); then
echo "dev-issue-autoclose: #$n not found; skipping"
continue
fi
# Skip already-closed issues (no duplicate comments).
if [ "$state" = "CLOSED" ]; then
echo "dev-issue-autoclose: #$n is already CLOSED; skipping (no duplicate comment)"
continue
fi
gh issue close "$n" --repo "$REPO" --reason completed \
--comment "Auto-closed: delivery PR #$PR_NUMBER ([view]($PR_URL)) merged into \`dev\` with a closing keyword for #$n in its body. GitHub's native auto-close only fires on the default branch (\`main\`); this mirrors it for the dev integration layer ([#519](https://github.com/$REPO/issues/519))."
echo "dev-issue-autoclose: #$n closed (reason: completed) by delivery PR #$PR_NUMBER"
done
20 changes: 4 additions & 16 deletions .specgit.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
version: 1
delivery: leftover-hardening
delivery: auto-close-linked
context:
kind: branch
branch: test/512-leftover-hardening
branch: feat/519-auto-close-linked
issues:
- 512
- 513
- 514
- 515
issueKinds:
- issue: 512
kind: kind::test
- issue: 513
kind: kind::fix
- issue: 514
kind: kind::test
- issue: 515
kind: kind::refactor
pr: 516
- 519
pr: 520
Loading