From 546ef939bd96326545ea4a988bae133d9f153219 Mon Sep 17 00:00:00 2001 From: Hunter Bown Date: Tue, 5 May 2026 02:03:16 -0500 Subject: [PATCH] docs+ci(v0.8.12): Resume by UUID, triage workflows, CHANGELOG refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README Usage block now documents `deepseek resume ` and `deepseek fork `. Both commands have existed since v0.7 but were undiscoverable; #682 reported "no way to resume." - New GitHub Actions for issue triage (#688): * triage.yml — keyword-driven auto-labeller (bug / feat / docs / question, area:* by file-path mention, os:*, lang:zh on CJK titles). Only adds labels that already exist on the repo so it can't create noise unilaterally. * stale.yml — 14 d stale → 7 d close on `needs-info` issues only; PRs untouched; respects pinned/keep-open/ bug/security exemptions. * spam-lockdown.yml — auto-closes promotional issues from accounts <30 days old. Pure github-script (no third-party action) so the matching rules stay readable. - CHANGELOG (v0.8.12) updated: README install rewrite (#672), Scoop (#696), pricing extension (#692), Resume docs surface, and the cargo-install-on-stable fix from the previous commit. Lease "pending" caveat removed since it's now actually fixed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/spam-lockdown.yml | 74 +++++++++++++++++++++++++++++ .github/workflows/stale.yml | 36 ++++++++++++++ .github/workflows/triage.yml | 63 ++++++++++++++++++++++++ CHANGELOG.md | 39 +++++++++++++++ README.md | 4 +- 5 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/spam-lockdown.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .github/workflows/triage.yml diff --git a/.github/workflows/spam-lockdown.yml b/.github/workflows/spam-lockdown.yml new file mode 100644 index 00000000..17f11bf0 --- /dev/null +++ b/.github/workflows/spam-lockdown.yml @@ -0,0 +1,74 @@ +name: Lock down obvious spam issues + +on: + issues: + types: [opened] + +permissions: + issues: write + +jobs: + lockdown: + runs-on: ubuntu-latest + steps: + - name: Auto-close spam patterns from new accounts + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const author = issue.user; + + // Only consider brand-new accounts. If the user has been around + // long enough to file good-faith issues elsewhere, don't touch. + const created = new Date(author.created_at || 0); + const ageDays = (Date.now() - created.getTime()) / 86_400_000; + if (ageDays > 30) return; + + const blob = `${issue.title || ''}\n${issue.body || ''}`; + const patterns = [ + /\bcrypto\b/i, + /\bairdrop\b/i, + /\bnft\b/i, + /\bpresale\b/i, + /\busdt\b/i, + /\btg\s*@/i, + /\btelegram\s+@/i, + /\bt\.me\//i, + /\bwhatsapp\s+\+/i, + /\bseo\s+service/i, + /\bguest\s+post/i, + /\bbacklink/i, + /\bbuy\s+followers/i, + /\bjoin\s+our\s+(community|server|group)/i, + /\bpromot[ei]\s+your\b/i, + ]; + const hit = patterns.find(p => p.test(blob)); + if (!hit) return; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: [ + 'This issue was auto-closed because the title or body matches', + 'a spam pattern (paid promotion / unrelated link) and the author', + 'account is less than 30 days old. If this is a real bug or', + 'feature request, please reopen with a clearer description', + '(in English or 中文) of the project-relevant context.', + ].join(' '), + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'not_planned', + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['spam'], + }).catch(() => {}); // ignore if label doesn't exist yet diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000..75535aa7 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,36 @@ +name: Close stale issues + +on: + schedule: + - cron: '17 5 * * *' # daily, off-peak + workflow_dispatch: {} + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + days-before-stale: 14 + days-before-close: 7 + stale-issue-message: > + This issue has been inactive for 14 days while waiting on + additional information. It will close automatically in 7 days + unless someone responds. If you still need help, drop a + comment with the requested details and a maintainer can + reopen. + close-issue-message: > + Closing for inactivity. Feel free to comment to reopen if + you can share the requested information. + stale-issue-label: 'stale' + only-labels: 'needs-info' + exempt-issue-labels: 'pinned,keep-open,bug,security' + # Don't touch PRs — `actions/stale` defaults can be aggressive + # there. We only want it for `needs-info` issues. + days-before-pr-stale: -1 + days-before-pr-close: -1 + operations-per-run: 60 diff --git a/.github/workflows/triage.yml b/.github/workflows/triage.yml new file mode 100644 index 00000000..4c7ad25b --- /dev/null +++ b/.github/workflows/triage.yml @@ -0,0 +1,63 @@ +name: Issue triage + +on: + issues: + types: [opened, reopened] + +permissions: + issues: write + contents: read + +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Auto-label by title and body + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const title = (issue.title || '').toLowerCase(); + const body = (issue.body || '').toLowerCase(); + const text = `${title}\n${body}`; + const labels = new Set(); + + // Type + if (/\b(bug|crash|panic|broken|stack ?trace|regression|err(?:or)?|fail(?:ed|ure)?)\b/.test(text)) labels.add('bug'); + if (/\b(feat(?:ure)?|request|enhancement|wishlist|proposal|please add|would be nice|support for)\b/.test(text)) labels.add('enhancement'); + if (/\b(docs?|readme|documentation|typo|grammar|wording|spelling)\b/.test(text)) labels.add('documentation'); + if (/\b(question|how (?:do|to)|why does|what does|is it possible)\b/.test(text)) labels.add('question'); + + // Locale — title contains CJK (Chinese, Japanese, Korean) characters + if (/[぀-ヿ㐀-鿿가-힯]/.test(issue.title || '')) labels.add('lang:zh'); + + // Areas (path-driven hints) + if (/crates\/tui|\btui\b|ratatui|composer|sidebar/.test(text)) labels.add('area:tui'); + if (/crates\/core|engine|turn ?loop|agent ?loop/.test(text)) labels.add('area:core'); + if (/crates\/mcp|\bmcp\b/.test(text)) labels.add('area:mcp'); + if (/crates\/state|sqlite|sessions?|persistence/.test(text)) labels.add('area:state'); + if (/crates\/execpolicy|approval|sandbox|seatbelt|landlock/.test(text)) labels.add('area:execpolicy'); + if (/crates\/tools|tool[ _]call|tool[ _]registry/.test(text)) labels.add('area:tools'); + if (/install|cargo install|npm install|scoop|homebrew|prebuilt|binary/.test(text)) labels.add('area:install'); + if (/windows/.test(text)) labels.add('os:windows'); + if (/macos|darwin|apple silicon/.test(text)) labels.add('os:macos'); + if (/\blinux\b|ubuntu|debian|fedora|arch ?linux/.test(text)) labels.add('os:linux'); + + if (labels.size === 0) return; + + // Only add labels that already exist on the repo to avoid creating noise. + const existing = await github.paginate(github.rest.issues.listLabelsForRepo, { + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 100, + }); + const existingNames = new Set(existing.map(l => l.name)); + const toAdd = [...labels].filter(name => existingNames.has(name)); + if (toAdd.length === 0) return; + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: toAdd, + }); diff --git a/CHANGELOG.md b/CHANGELOG.md index 99d7ad75..c2281561 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,6 +127,20 @@ resident sub-agents. No breaking changes. diagnostics via the engine-level LSP hooks path. ### Docs +- **README install section rewritten** (#672) — the previous lede claimed + "no Node.js or Python runtime" but the very next paragraph told readers to + install Node before continuing. Replaced with a three-path Install block + (npm / cargo / direct download) that makes the npm wrapper's role explicit: + it downloads the prebuilt binary, but `deepseek` itself does not depend on + Node at runtime. zh-CN README mirrored. +- **Windows Scoop install instructions** (#696) — README and zh-CN README now + document `scoop install deepseek-tui` for Windows users. *Thanks to + [@woyxiang](https://github.com/woyxiang) for this PR.* +- **DeepSeek Pro discount window extended** (#692) — pricing footnote updated + from 5 May 2026 to 31 May 2026 to match the platform-side promotion. *Thanks + to [@wangfeng](mailto:wangfengcsu@qq.com) for this PR.* +- **`deepseek resume ` surfaced in Usage** — the command exists + since v0.7 but was undocumented. Reported via #682. - **SECURITY.md** (#648) — vulnerability reporting policy and supported versions. - **CODE_OF_CONDUCT.md** (#686) — Contributor Covenant v2.1. *Thanks to @@ -135,6 +149,23 @@ resident sub-agents. No breaking changes. config.example.toml now document `locale = "zh-Hans"`. ### Fixed +- **`cargo install` on stable Rust** — the language-picker match guard at + `crates/tui/src/tui/ui.rs:1603` used `&& let Some(...) = ...` inside an + `if`-guard, which requires the nightly-only `if_let_guard` feature on Rust + before 1.94. Reported by an external user whose `cargo install + deepseek-tui` failed with E0658. Rewrote as a plain match guard with a + nested `if let` inside the arm body. The workspace also now declares + `rust-version = "1.88"` (the actual minimum for `let_chains` in + `if`/`while`) so users on too-old toolchains see a clear cargo error + instead of a confusing rustc one. AGENTS.md gains a "stable Rust only" + section so this doesn't regress. +- **Resident-file lease never released after spawn** (#660) — the lease was + stamped as `"pending"` at spawn time because the agent id is only assigned + by the manager after the spawn call returns. The release-on-terminal-state + path (added in the original #660 commit) matched leases by agent id, so + it could never find these placeholder entries. Now the placeholder is + replaced with the real agent id immediately after spawn so existing + release wiring fires. Resolves the v0.8.12 caveat documented at RC time. - **Color::Reset across all UI widgets** (#651, #671) — replaced hardcoded `Color::Black` and `Color::Rgb(18, 29, 39)` backgrounds with `Color::Reset` so the TUI respects the terminal's actual background color on light-themed @@ -145,6 +176,14 @@ resident sub-agents. No breaking changes. shared `truncate_id` helper across session, picker, and UI call sites. ### Maintenance +- Workspace `cargo fmt` sweep across community PRs that landed unformatted. +- Issue-triage GitHub Actions added (#688): keyword-driven auto-labeller, + stale-bot for `needs-info` issues (14 d → stale → 7 d → close), and a + spam lockdown that auto-closes promotional issues from accounts <30 d + old. All pure GitHub Actions — no third-party services. +- Annotated `TuiPrefs` (#657) and `handoff::THRESHOLDS` (#667) with + `#[allow(dead_code)]` so the deferred APIs don't trip CI's `-D warnings` + flag while their call sites are staged for v0.8.13. - Removed dead `prefer_handoff` field from `CompactionConfig` — config knob existed but zero code paths consulted it (#667). - Removed dead `use_terminal_colors` field from `TuiConfig` — no rendering diff --git a/README.md b/README.md index 9b6fb789..97d2cf6d 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,9 @@ deepseek setup --status # read-only setup status deepseek setup --tools --plugins # scaffold tool/plugin dirs deepseek models # list live API models deepseek sessions # list saved sessions -deepseek resume --last # resume latest session +deepseek resume --last # resume the most recent session +deepseek resume # resume a specific session by UUID +deepseek fork # fork a session at a chosen turn deepseek serve --http # HTTP/SSE API server deepseek pr # fetch PR and pre-seed review prompt deepseek mcp list # list configured MCP servers