dsh-antfubot 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +87 -3
- package/assets/skills/antfu-create-pr.md +96 -0
- package/assets/skills/antfu-issue-triage.md +169 -0
- package/assets/skills/antfu-query.md +42 -0
- package/assets/skills/antfu-simplify.md +91 -0
- package/cordis.patch.yml +5 -0
- package/dist/client.cjs +4 -0
- package/dist/client.cjs.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +916 -0
- package/package.json +128 -6
- package/src/main.css +1 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-PRESENT Hairy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,87 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
# dsh-antfubot
|
|
2
|
+
|
|
3
|
+
Anthony Fu's agent workflow for DeepSeek Harness: issue triage, a persistent digest, task execution, pull requests, simplification, and design interviews.
|
|
4
|
+
|
|
5
|
+
`dsh-antfubot` does two things:
|
|
6
|
+
|
|
7
|
+
1. **Injects four skills** into every session catalog, so the agent has the procedure before you ask for it.
|
|
8
|
+
2. **Registers thirteen slash commands** that compose the request and hand it to the agent.
|
|
9
|
+
|
|
10
|
+
Both halves are plain data: the skills are markdown shipped in this package, the commands are prompts that name them.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
dsh plugin install <path-or-package>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The plugin needs the gh CLI on `PATH`, authenticated with at least one account:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
gh auth status
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Commands
|
|
25
|
+
|
|
26
|
+
| Command | Input | What it does |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| `/triage` | — | Scan the repo's open issues and PRs, present three action tables, then stop for confirmation. |
|
|
29
|
+
| `/triage update` | — | Resume from the newest digest: skip checked items, scan only what is new, keep every `TASKxx` code. |
|
|
30
|
+
| `/triage focus <topic>` | a focus phrase | Build a scoped digest for one work line (`router rewrite`, `SSR hydration`). |
|
|
31
|
+
| `/triage apply <1,2,4-6>` | row numbers | Execute only the approved rows, one issue per command, then report a done/failed table. |
|
|
32
|
+
| `/task` | — | List the digest's unfinished items. |
|
|
33
|
+
| `/task <TASKxx>` | `TASK03` | Do that item, open the PR, and write the result back into the digest. |
|
|
34
|
+
| `/digest` | — | Show the current digest verbatim. Read-only. |
|
|
35
|
+
| `/status` | — | Repo, acting account, digest freshness, and pending review activity. |
|
|
36
|
+
| `/pr` | — | Open a pull request from the current branch. |
|
|
37
|
+
| `/pr respond` | — | Address review comments: fix, add commits, reply with evidence, resolve. |
|
|
38
|
+
| `/pr review` | — | Review the current PR without changing it. |
|
|
39
|
+
| `/simplify` | `staged` or `HEAD~3` | Ablation study on the current diff. |
|
|
40
|
+
| `/grill` | the plan | Interview you through the design tree until nothing is assumed. |
|
|
41
|
+
|
|
42
|
+
Every command queues its prompt as its own turn, so a slash command's work never mixes into whatever you were already doing.
|
|
43
|
+
|
|
44
|
+
## Skills
|
|
45
|
+
|
|
46
|
+
Four skills are injected from this package:
|
|
47
|
+
|
|
48
|
+
| Skill | Purpose |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `antfu-issue-triage` | Read-only triage, action tables, confirmation gate, digest issue. |
|
|
51
|
+
| `antfu-create-pr` | Ten-step PR: merge base, full diff, checks, atomic commits, evidence body. |
|
|
52
|
+
| `antfu-simplify` | Ablation study that keeps only what is proven needed. |
|
|
53
|
+
| `antfu-query` | Relentless design-tree interview through the question tool. |
|
|
54
|
+
|
|
55
|
+
They are bundled at rank 600, so a workspace copy under `.agents/skills` or `.dsh/skills` overrides them. Bodies live in `assets/skills/<name>.md` and are read on every load: editing one takes effect without a rebuild.
|
|
56
|
+
|
|
57
|
+
## Settings
|
|
58
|
+
|
|
59
|
+
**Settings → General → GitHub Account** picks the gh account this plugin acts as.
|
|
60
|
+
|
|
61
|
+
The dropdown lists the accounts `gh auth status` reports and marks the active one. Selection is **plugin-scoped**: each gh call runs with `GH_TOKEN` for the chosen account, so nothing is written to gh's config and your global `gh auth` login stays exactly as it was. "Use the active gh account" clears the override.
|
|
62
|
+
|
|
63
|
+
The setting is stored per profile at `$DSH_PROFILE_DIR/antfubot/settings.json`.
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
Nothing else to configure. The plugin reads no secrets and writes only its own settings file.
|
|
68
|
+
|
|
69
|
+
## Development
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pnpm install --frozen-lockfile
|
|
73
|
+
pnpm run lint --fix
|
|
74
|
+
pnpm run typecheck
|
|
75
|
+
pnpm run test -- --run
|
|
76
|
+
pnpm run build
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
E2E tests need Playwright browsers (`pnpm exec playwright install`) and the `@deepseek-ai/dsh` CLI; they skip when DSH is absent.
|
|
80
|
+
|
|
81
|
+
## Attribution
|
|
82
|
+
|
|
83
|
+
The four skills are vendored from [antfu/skills](https://github.com/antfu/skills) by Anthony Fu (MIT). This plugin packages them for DeepSeek Harness and adds the command surface; the workflow design is his.
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: antfu-create-pr
|
|
3
|
+
description: Create a reviewable GitHub pull request from the current branch with a Conventional Commits title, a concise evidence-based body, and before/after screenshots for UI changes. Use when asked to open, create, publish, or prepare a PR.
|
|
4
|
+
metadata:
|
|
5
|
+
author: Anthony Fu
|
|
6
|
+
version: "2026.11.05"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Create Pull Request
|
|
10
|
+
|
|
11
|
+
Open a PR that a reviewer can understand from the body alone. Explain the changed behavior and why, not the list of changed files. Keep the body proportional to the change: a one-line fix gets a few sentences, a cross-module feature gets tables and diagrams.
|
|
12
|
+
|
|
13
|
+
## Workflow
|
|
14
|
+
|
|
15
|
+
1. Inspect the repo: `git status`, current branch, remotes, default branch, `.github/PULL_REQUEST_TEMPLATE*`, and `AGENTS.md` / `CONTRIBUTING.md` for PR rules.
|
|
16
|
+
2. Compute the merge base against the target branch and record the exact `base...head` range the PR publishes. If the branch is stacked on another unmerged branch, target that branch and describe only this PR's own changes.
|
|
17
|
+
3. Read the full diff. Separate runtime code from generated files, lockfiles, and snapshots. Trace changed code to its entry points, callers, and external boundaries so architecture claims are backed by file paths or symbols.
|
|
18
|
+
4. Classify the PR (feature, fix, refactor, chore, docs) and decide which optional body sections earn their place. See [pr-body](references/pr-body.md).
|
|
19
|
+
5. Run the checks that match the changed surfaces (focused tests, typecheck, lint). Record the exact commands and results.
|
|
20
|
+
6. If the diff changes user-visible UI, capture before/after evidence. See [visual-evidence](references/visual-evidence.md).
|
|
21
|
+
7. Review the commit history and reshape it into atomic Conventional Commits. See [Commits](#commits).
|
|
22
|
+
8. Write the body to a temporary file. Push the branch. Create the PR with `gh pr create --title ... --body-file ...` (add `--attach` for each screenshot; newer `gh` can upload local images and videos from the CLI, see [Attaching files with GitHub CLI](https://docs.github.com/en/github-cli/github-cli/attaching-files-with-github-cli)). Use `--draft` when checks are still running or the work is not review-ready.
|
|
23
|
+
9. Open the created PR and verify title, base, head, rendered tables, diagrams, and images.
|
|
24
|
+
10. Address review comments: fix each confirmed issue, run focused checks, push, reply with evidence, and resolve the thread.
|
|
25
|
+
|
|
26
|
+
## Title
|
|
27
|
+
|
|
28
|
+
Use Conventional Commits, matching how the repo already writes commit messages:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
feat(scope): add retry to upload client
|
|
32
|
+
fix(scope): avoid double submit on enter
|
|
33
|
+
refactor: extract diff parsing from cli
|
|
34
|
+
chore(deps): update vite to v8
|
|
35
|
+
docs: clarify worktree setup
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Lowercase, imperative, no trailing period, under ~70 characters.
|
|
39
|
+
- Scope is the package, module, or feature name the repo already uses. Omit it when the change is repo-wide.
|
|
40
|
+
- Squash-merge repos turn the title into the commit message; write it as the commit you want in history.
|
|
41
|
+
|
|
42
|
+
## Commits
|
|
43
|
+
|
|
44
|
+
Each commit does one logical thing and uses a Conventional Commits message. A reviewer should be able to read `git log --oneline` as the story of the change and review commit by commit.
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
# Good: each commit is self-contained
|
|
48
|
+
feat(api): add task creation endpoint with validation
|
|
49
|
+
feat(ui): add task creation form component
|
|
50
|
+
feat(ui): connect form to api and add loading state
|
|
51
|
+
test(tasks): cover task creation (unit + integration)
|
|
52
|
+
|
|
53
|
+
# Bad: everything mixed together
|
|
54
|
+
feat: add task feature, fix sidebar, update deps, refactor utils
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- Keep unrelated fixes, dependency bumps, and drive-by refactors out of the branch; open separate PRs for them.
|
|
58
|
+
- Before pushing, review the history and split or squash local commits (`git rebase -i <base>`) until each one stands alone and builds.
|
|
59
|
+
- Do not rewrite commits that are already pushed and under review; add new commits instead.
|
|
60
|
+
|
|
61
|
+
## Body
|
|
62
|
+
|
|
63
|
+
Required in every PR:
|
|
64
|
+
|
|
65
|
+
- `## Summary`: the problem or capability first, then what changed and why this approach. Mention if the PR is stacked and on what.
|
|
66
|
+
- Linked issues: `closes #123` / `fixes #123` / `refs #123` so GitHub links and auto-closes.
|
|
67
|
+
- `## Verification`: exact commands run and their results, plus anything left unverified. Show proof matched to the change type (bug: same input before and after; perf: same workload measured both sides; CLI: real output). See [Evidence by change type](references/pr-body.md#evidence-by-change-type).
|
|
68
|
+
|
|
69
|
+
Optional, only when it helps the reviewer:
|
|
70
|
+
|
|
71
|
+
- `## Change map`: table of module, before, after, reason. Use for changes across several modules or ownership boundaries. Never a raw file list.
|
|
72
|
+
- `## Architecture and behavior`: a Mermaid flow, sequence, or state diagram when ordering, async work, or state transitions changed. For a fix, pair a `Before` and `After` diagram at the same abstraction level.
|
|
73
|
+
- `## Boundaries and risks`: table of invariant, failure mode, protection, evidence. Use when there are real failure modes, migrations, or external effects.
|
|
74
|
+
- `## Visual changes`: before/after image table for UI changes.
|
|
75
|
+
- `## Rollout and follow-up`: migrations, feature flags, known gaps. State whether a gap blocks merge.
|
|
76
|
+
|
|
77
|
+
If the repo has a PR template, keep its headings and fill them; add sections above only where the template leaves room.
|
|
78
|
+
|
|
79
|
+
## Rules
|
|
80
|
+
|
|
81
|
+
- Say what is verified, what is assumed, and what is not verified. Do not write "safe", "fixed", or "backward compatible" without pointing at the evidence.
|
|
82
|
+
- Green CI proves only the checks CI runs. Focused tests prove only the behavior they cover.
|
|
83
|
+
- Do not describe inherited changes from a parent branch as this PR's changes.
|
|
84
|
+
- Use plain hyphens; never em dashes (U+2014) or en dashes (U+2013).
|
|
85
|
+
- No filler ("This PR aims to...", "comprehensive", "robust"). Start sentences with the fact.
|
|
86
|
+
- Do not paste tokens, secrets, user records, or full payloads into the body.
|
|
87
|
+
- Do not commit screenshots or other PR-only artifacts to the repo; attach them with `gh --attach` (supported by newer `gh`, no manual upload needed).
|
|
88
|
+
- A description conveys belief, not proof. Show the change working instead of only saying it works.
|
|
89
|
+
- "Before" is what is live (base branch or production), never a faked revert. Check every capture; agents can screenshot the wrong page. Use demo or sanitized data only.
|
|
90
|
+
- Security fixes: keep the description short and delay exploit details until release.
|
|
91
|
+
- If the PR was written with the help of an agent, say so in one line at the end of the body: what the human contributed (gave the task, wrote the spec, shaped the solution) and whether they have reviewed the diff yet. If not, the reviewer is the first human to look.
|
|
92
|
+
|
|
93
|
+
## Credits
|
|
94
|
+
|
|
95
|
+
Evidence-by-type, honesty rules, and review-status disclosure are adapted from Hugo Richard's [What my pull requests look like now](https://hugorcd.com/writing/what-my-pull-requests-look-like-now).
|
|
96
|
+
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: antfu-issue-triage
|
|
3
|
+
description: Triage open issues and PRs of the current GitHub repo - find already-fixed, duplicate, and spam items, suggest labels, gauge demand from reactions and comments, then present a table of proposed actions and comments for confirmation before touching anything. Use when asked to triage, organize, clean up, or groom issues and PRs.
|
|
4
|
+
metadata:
|
|
5
|
+
author: Anthony Fu
|
|
6
|
+
version: "2026.11.05"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Issue Triage
|
|
10
|
+
|
|
11
|
+
Go through the open issues and PRs of the **current repo** (`gh repo view --json nameWithOwner`) and propose clean-up actions. Maintainers decide; the agent investigates.
|
|
12
|
+
|
|
13
|
+
## Hard Rules
|
|
14
|
+
|
|
15
|
+
- **Read-only until confirmed.** Never comment, label, close, or edit before the user approves the action tables. Reads (`gh issue view`, `gh api` GET, `gh search`) are fine.
|
|
16
|
+
- **Every comment says it is automated by an agent.** End with a separate last line (blank line before it): `🤖 *Automated by an agent.*`
|
|
17
|
+
- **Comments are short and plain.** Write them in simple English (use the `simple-english` skill if available): 1-3 short sentences, active voice, no jargon, no filler. Write each comment fresh for the item. Do not reuse a fixed template. Always include the link (PR, commit, release, or canonical issue) that justifies the action.
|
|
18
|
+
- Only apply approved rows. If the user edits or drops rows, follow their edits exactly.
|
|
19
|
+
- Be conservative: when unsure, propose `keep open` (with labels if useful) instead of closing. Do not close items with active maintainer discussion, an open linked PR, or a milestone unless the user asks.
|
|
20
|
+
- Use plain hyphens; no em or en dashes.
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
0. **Resume.** Look for earlier digests (`gh issue list --state all --search "Triage digest in:title"`). Read the one that matches this run (the unscoped digest for a full-repo run, the digest with the same focus for a focused run). If it exists: skip items already checked, re-check the unchecked ones, and scan only items newer than its recorded range plus items with new activity since its recorded date. Keep each item's `TASKxx` code. If none matches, scan everything in scope. Also skim the other digests for codes already used and for items already tracked there (see Scoped digests).
|
|
25
|
+
1. **Scope.** Confirm the repo and range (default: all open items, narrowed by the digest if there is one; for large repos ask for a limit, label, or age filter). Fetch in bulk:
|
|
26
|
+
```bash
|
|
27
|
+
gh issue list --state open --limit 200 --json number,title,body,author,labels,createdAt,updatedAt,comments,reactionGroups,url,milestone
|
|
28
|
+
gh pr list --state open --limit 200 --json number,title,body,author,labels,isDraft,reviewDecision,closingIssuesReferences,url,reactionGroups
|
|
29
|
+
gh label list --limit 200 --json name,description
|
|
30
|
+
```
|
|
31
|
+
2. **Learn the labels.** Read every label name and description. Only apply labels that exist. New labels (including `spam` if missing) go in the Labels table and are created only after approval. Check how maintainers labeled similar items (`gh issue list --state all --label <l>`). Compare the repo's labels with the Recommended Labels section below and note useful ones that are missing.
|
|
32
|
+
3. **Map references.** Collect cross-references from bodies, comments, and the timeline (`gh api repos/{owner}/{repo}/issues/{n}/timeline --paginate`): `#123`, URLs, `closes/fixes`, linked PRs, cross-repo links. Treat linked items as one cluster. Do not close an issue whose fix PR is still open. Do not mark linked items as duplicates of each other.
|
|
33
|
+
4. **Check each item:**
|
|
34
|
+
- **Already fixed/implemented.** Search merged PRs and commits (`gh pr list --state merged --search "<keywords>"`, `git log -i --grep`), changelog, docs, and current code. Find the first release with the fix (`git tag --contains <sha> --sort=version:refname | head -1`). Verify in the code, not just the title. A partial fix is not fixed: keep it open.
|
|
35
|
+
- **Duplicate.** Group by symptom or request, not wording. Search open and closed issues with distinctive text (`gh issue list --state all --search "<text>"`). Pick one canonical item: linked PR > maintainer response > best repro > most reactions > oldest. Close the others into it.
|
|
36
|
+
- **Spam.** Needs two or more strong signals: promo/SEO/crypto links, off-topic text, repeated identical posts, empty body with a link, bulk activity from a new account. Typos, terse text, wrong template, or non-English are not spam.
|
|
37
|
+
- **Labels.** Suggest existing labels for unlabeled or mislabeled items.
|
|
38
|
+
- **Low hanging fruit.** Items a maintainer can finish fast: PRs that are approved or ready with passing CI, small PRs with a clear change, typo or docs fixes, bugs with a clear repro and an obvious small fix, and requests that are small and well defined. Say why each is quick, and propose the `low hanging fruit` label for it. Skip items that are blocked, unclear, or large.
|
|
39
|
+
- **Status.** For every item that is not closed in this run, record its digest marker now, while the evidence is fresh: 🚧 a PR is open for it, ❓ you could not decide, 🚨 security, ⚠️ extra notice (see Digest Issue for the full meaning), or none. Assign it a `TASKxx` code (reuse the code from the digest if it has one, otherwise the next unused number).
|
|
40
|
+
- **Demand.** Count positive reactions (👍 ❤️ 🎉 🚀), negative ones, distinct commenters, "+1" comments, and folded-in duplicates. Rate `High / Medium / Low` for the repo's size and show the raw numbers. Recent activity on an old item means it is still wanted.
|
|
41
|
+
5. **Present the plan** as the tables below, **Stop to ask for confirmation**. Run no write command in this turn.
|
|
42
|
+
6. **Execute** approved rows only, one at a time: comment, then label, then close. Stop on the first API error and report it. End with a done/failed table with links.
|
|
43
|
+
- Run one issue per command (comment, label, and close for that issue chained with `&&`). Do not batch many issues in one script or loop: bulk write commands can be blocked by the permission classifier. If a command is blocked, do not work around it. Split it into smaller per-issue commands, and tell the user.
|
|
44
|
+
- Create approved new labels first, in their own command.
|
|
45
|
+
- For rows the user adds after the tables (for example "also close #4"), write a short fresh comment in the same style and show it in the final report.
|
|
46
|
+
7. **Offer a digest issue.** Ask whether to create or update the digest issue (see Digest Issue). It is built from the Needs attention rows, plus the items closed in this run. Do not write it without approval.
|
|
47
|
+
|
|
48
|
+
## Recommended Labels
|
|
49
|
+
|
|
50
|
+
General labels. Map them to the repo's existing labels first (same meaning, different name). Never rename or delete existing labels.
|
|
51
|
+
|
|
52
|
+
| Group | Labels | Meaning |
|
|
53
|
+
|-------|--------|---------|
|
|
54
|
+
| Type | `bug`, `enhancement`, `documentation`, `regression` | What kind of item it is. `regression`: only appears after a new release. |
|
|
55
|
+
| Triage state | `pending triage`, `needs reproduction` | Where the item is stuck. |
|
|
56
|
+
| Resolution | `duplicate`, `invalid`, `wontfix`, `spam` | Why it was closed. |
|
|
57
|
+
| Priority | `p1-chore`, `p2-nice-to-have`, `p2-edge-case`, `p3-minor-bug`, `p3-significant`, `p4-important`, `p5-urgent` | How much it matters. Descriptions: p5 breaks most users and needs a release now; p4 breaks documented behavior; p3 is an edge case or a high-priority enhancement; p2 is nice to have or has a workaround; p1 changes no behavior. |
|
|
58
|
+
| Contribution | `low hanging fruit` | Quick for a maintainer to finish. |
|
|
59
|
+
| Context | `has workaround`, `bug: upstream`, `<platform> only` (e.g. `windows only`) | Extra facts that help the next reader. |
|
|
60
|
+
| Area | `feat: <area>` (one per major module of the repo) | Which part of the code it touches. Derive areas from the repo's directories, docs, and past issues. |
|
|
61
|
+
| Bot | `bot: maybe`, `bot: likely` | Suspected bot or LLM content, short of spam. |
|
|
62
|
+
|
|
63
|
+
Rules:
|
|
64
|
+
|
|
65
|
+
- Keep every label's description filled. If an existing label has none and its meaning is clear, suggest a description.
|
|
66
|
+
- Suggest only labels that would help *this* repo's triage: needed by items you saw, or filling an obvious gap (for example no way to mark "needs reproduction" while many issues lack a repro). Do not suggest the whole list.
|
|
67
|
+
- Prefer a few `feat: <area>` labels backed by real clusters of issues over many speculative ones.
|
|
68
|
+
- Creating labels is a write action. List them in the Labels table (as `(new label)` rows) with name, color (match the repo's palette), description, and the items that would use them. Create only after approval (`gh label create <name> --description "..." --color <hex>`), and before applying them to items.
|
|
69
|
+
|
|
70
|
+
## Comments
|
|
71
|
+
|
|
72
|
+
Short, friendly, and specific. Examples of the tone (do not copy verbatim). Each ends with the notice on its own line:
|
|
73
|
+
|
|
74
|
+
- Fixed:
|
|
75
|
+
```md
|
|
76
|
+
This was fixed in #456, released in v1.2.0. Please upgrade to get it. If it still happens, comment with a repro and we will reopen.
|
|
77
|
+
|
|
78
|
+
🤖 *Automated by an agent.*
|
|
79
|
+
```
|
|
80
|
+
- Duplicate:
|
|
81
|
+
```md
|
|
82
|
+
This is a duplicate of #123. Please follow that issue. Tell us if it is different and we will reopen.
|
|
83
|
+
|
|
84
|
+
🤖 *Automated by an agent.*
|
|
85
|
+
```
|
|
86
|
+
- Spam:
|
|
87
|
+
```md
|
|
88
|
+
Detected as a spam. Sorry if this was a mistake. Let us know and a maintainer can bring it back.
|
|
89
|
+
|
|
90
|
+
🤖 *Automated by an agent.*
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Rules per type:
|
|
94
|
+
|
|
95
|
+
- **Fixed:** link the PR or commit and release, and say what to do (upgrade, enable an option, use an API). Close as completed.
|
|
96
|
+
- **Duplicate:** name the canonical issue and invite the author to reopen if it differs. Close as `not planned`.
|
|
97
|
+
- **Spam:** add the `spam` label. Say it was detected as spam, with no reasoning. Say sorry if wrong, and say we can bring it back. Put the reasoning in the table, not in the comment. Close as `not planned`.
|
|
98
|
+
|
|
99
|
+
## Action Tables
|
|
100
|
+
|
|
101
|
+
Three tables. Close and Labels rows are numbered so the user can reply "apply 1-5, skip 3". Needs attention rows carry their `TASKxx` code instead, so the user can say "do TASK03" now and in later runs. Show the full comment text in the table.
|
|
102
|
+
|
|
103
|
+
**1. Close**
|
|
104
|
+
|
|
105
|
+
| # | Item | Reason | Link (fix / canonical) | Comment |
|
|
106
|
+
|---|------|--------|------------------------|---------|
|
|
107
|
+
|
|
108
|
+
`Reason` is `fixed`, `duplicate`, or `spam`. Spam rows also add the `spam` label, and their reasoning stays in this table, not in the comment.
|
|
109
|
+
|
|
110
|
+
**2. Labels**
|
|
111
|
+
|
|
112
|
+
| # | Item | Add | Reason |
|
|
113
|
+
|---|------|-----|--------|
|
|
114
|
+
|
|
115
|
+
Include `low hanging fruit` rows here. For a label the repo does not have, add a row with item `(new label)`, the name, description, color, and which items will use it. Approved new labels are created first (`gh label create`), then applied.
|
|
116
|
+
|
|
117
|
+
**3. Needs attention** (no write action)
|
|
118
|
+
|
|
119
|
+
| Code | Status | Item | Demand | Reactions / comments | Note |
|
|
120
|
+
|------|--------|------|--------|----------------------|------|
|
|
121
|
+
|
|
122
|
+
`Code` is the `TASKxx` code and `Status` is the emoji marker (empty if none), both exactly as they will appear in the digest, so the digest is a copy of this table.
|
|
123
|
+
|
|
124
|
+
Put the most recommended check-them-first items at the top, ranked by importance: high demand, regressions or build-breaking bugs, security reports, security-sensitive or long-waiting PRs, and items with active unanswered discussion. Say why in `Note`. Low hanging fruits go here too, after those, with the reason it is quick.
|
|
125
|
+
|
|
126
|
+
Do not close PRs for being stale unless asked; label or flag them instead.
|
|
127
|
+
|
|
128
|
+
## Digest Issue (optional)
|
|
129
|
+
|
|
130
|
+
After the actions are applied (or when the user only wants a report), **offer** to create a digest issue that records the Needs attention results, so later triage runs can pick up from it (Resume step). The digest is a copy of the Needs attention table; do not re-derive it. Creating an issue is a write action: ask first, show the full title and body, and create it only after approval. Skip the offer if the user declined or the list is empty.
|
|
131
|
+
|
|
132
|
+
- **Title:** `Triage digest (YYYY-MM-DD)`, or `Triage digest [<focus>] (YYYY-MM-DD)` for a scoped digest (see Scoped digests). If an earlier digest with the same focus exists (`gh issue list --state all --search "Triage digest in:title"`), offer to update it (`gh issue edit`) instead of opening a new one, and keep checked items checked.
|
|
133
|
+
- **Overview:** start the body with a short `Status` paragraph (2-4 sentences): the overall state of open issues and PRs (rough counts, main themes or clusters, how healthy the backlog is, what is stale or blocked), then a `Recommended start` line naming the 1-3 items to do first and why.
|
|
134
|
+
- **Items:** one task-list line per item: ``- [ ] `TASK00` 🚧 #134 - <concise recommendation>``. Mark items already handled as `- [x]`. Keep each line to one short sentence: what to do and why (for example `review and merge, CI green, small change`).
|
|
135
|
+
- **Code:** every item gets a unique `TASKxx` code (`TASK01`, `TASK02`, ... zero-padded, numbered in order of appearance) so the maintainer can say "do TASK03 and TASK07". Codes are stable: when updating an existing digest, keep each item's code, give new items the next unused number, and never reuse or renumber. Codes are unique across all digests of the repo, not per digest (see Scoped digests).
|
|
136
|
+
- **Link:** the issue or PR reference (`#134`, or the full URL for another repo) right after the code and emoji.
|
|
137
|
+
- **Emoji:** one status marker between the code and the link, or none if no marker applies:
|
|
138
|
+
- ✅ done: already handled or fixed
|
|
139
|
+
- 🚧 wip: a PR is open for it
|
|
140
|
+
- ❓ unsure: the agent could not decide, needs a maintainer call
|
|
141
|
+
- 🚨 security: security report or security-sensitive
|
|
142
|
+
- ⚠️ extra notice: regression, breaking change, or anything else the maintainer should read first
|
|
143
|
+
- Pick the most important one; omit the emoji otherwise (`` - [ ] `TASK04` #151 - ... ``).
|
|
144
|
+
- **Groups:** use these headings, in order, omitting empty ones:
|
|
145
|
+
1. `Prioritized` - high demand, regressions, security, long-waiting items. Most important first.
|
|
146
|
+
2. `Low hanging fruit` - quick wins, with the reason it is quick.
|
|
147
|
+
3. `Other` - worth a look but neither urgent nor quick.
|
|
148
|
+
4. `Done in this run` - items closed or fixed in this run, as `- [x]` lines with ✅ and their own code. A later run drops them once the digest has been updated again.
|
|
149
|
+
- **Metadata:** end the body with a block that lets a future run continue without redoing the scan:
|
|
150
|
+
```md
|
|
151
|
+
---
|
|
152
|
+
- Focus: <"all", or the domain or feature, for example `router rewrite`>
|
|
153
|
+
- Selection: <for a focus: how items were chosen, for example "label feat: router, keywords navigation/guard, cluster of #120">
|
|
154
|
+
- Scanned: <repo>, open issues and PRs (<fetch filters used, or "all">)
|
|
155
|
+
- Date: <YYYY-MM-DD>
|
|
156
|
+
- Model: <model name or id>
|
|
157
|
+
- Newest item scanned: #<n> (<createdAt>)
|
|
158
|
+
- Counts: <n> issues, <n> PRs scanned; <n> closed, <n> labeled in this run
|
|
159
|
+
```
|
|
160
|
+
- **Scoped digests:** a scoped digest is a work list for one **focus**: a domain, feature, theme, or goal the maintainer is working on (`router rewrite`, `SSR hydration`, `v2 release`, `Windows support`). It is not a fetch filter. Fetch filters (limit, label, age for a large repo) only narrow what is scanned and go in the `Scanned` line; they do not make a scoped digest. Users can keep several scoped digests next to the full one.
|
|
161
|
+
- The user names the focus. Pick the items by relevance across the whole backlog, not by one label: matching labels, keywords, the code area an item touches, and its reference cluster (linked issues and PRs). Include open PRs that implement the focus, and recently merged ones only when they explain an open item. Record how you chose in the `Selection` line, and list borderline items as ❓ rather than leaving them out silently.
|
|
162
|
+
- Name the focus in the title and the `Focus` metadata line, using a short stable phrase. The same phrase is how the next run finds its digest, so reuse it exactly.
|
|
163
|
+
- Order the groups for the focus, not the repo: what unblocks the focus first. `Recommended start` says what to do first for this focus. The `Status` paragraph describes the focus (its open work, blockers, how close it is), not the whole backlog.
|
|
164
|
+
- A scoped digest only covers items in its focus. Never mark an item outside the focus as done or missing; the full digest, if any, stays untouched.
|
|
165
|
+
- Codes are shared across the repo: before assigning a new code, read all digests (open and closed) and take the next number after the highest one used. If an item is already tracked in another digest, reuse its code instead of creating a second one, and add `(also in #<digest>)` to the line.
|
|
166
|
+
- When the same item is checked off in one digest, mention it in the report so the user can tick it in the others; do not edit digests outside this run's scope.
|
|
167
|
+
- Add the same `🤖 *Automated by an agent.*` last line. Do not add labels or assignees unless asked.
|
|
168
|
+
- On the next run, follow the Resume step: the digest is read first, before scoping.
|
|
169
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: antfu-query
|
|
3
|
+
description: Interview the user relentlessly about a plan, decision, or idea until reaching a shared understanding, using the agent's interactive question tool (not plain text). Use when the user wants to stress-test their thinking, clarify requirements, or says "grill me" or "query me".
|
|
4
|
+
metadata:
|
|
5
|
+
author: Anthony Fu
|
|
6
|
+
version: "2026.10.31"
|
|
7
|
+
source: Adapted from https://github.com/mattpocock/skills/blob/main/skills/productivity/grilling/SKILL.md
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Query
|
|
11
|
+
|
|
12
|
+
Interview the user relentlessly until you reach a shared understanding. Map this as a **design tree**: every decision branches into the decisions that hang off it.
|
|
13
|
+
|
|
14
|
+
## Ask With the Question Tool
|
|
15
|
+
|
|
16
|
+
Put every question to the user through the agent's **interactive question tool** (for example `AskUserQuestion` in Claude Code, or the equivalent in other agents; load it first if it is deferred). Do not write questions as plain text in the reply.
|
|
17
|
+
|
|
18
|
+
- Give each question 2-4 distinct, concrete options with a short description of the trade-off.
|
|
19
|
+
- Put your recommended answer first and mark it `(Recommended)`, so picking it accepts your recommendation. The tool adds an "Other" option for free-form answers; do not add one.
|
|
20
|
+
- Keep headers short. Use multi-select only when the options are not mutually exclusive.
|
|
21
|
+
- Batch the whole frontier into one call, up to the tool's limit per call (4 in Claude Code). If the frontier is larger, ask the most blocking questions first and the rest next round.
|
|
22
|
+
- If the agent has no question tool, fall back to plain text: number the questions, list the options, and state your recommended answer for each.
|
|
23
|
+
|
|
24
|
+
## Rounds
|
|
25
|
+
|
|
26
|
+
Work the tree in **rounds**. The **frontier** is every decision whose prerequisites are already settled: the questions you can ask _now_ without guessing at answers you have not heard yet. Ask the whole frontier in one round, then wait for the answers before the next round.
|
|
27
|
+
|
|
28
|
+
- Each answered round reshapes the tree: settled decisions push the frontier outward and unblock questions that depended on them. Recompute the frontier and ask the next round.
|
|
29
|
+
- A question whose answer depends on another question still open in this round belongs to a _later_ round.
|
|
30
|
+
- Word each question so the recommended option is the natural "yes".
|
|
31
|
+
- Use the user's free-form "Other" answers and notes as new input: they may add or remove branches.
|
|
32
|
+
|
|
33
|
+
## Facts vs Decisions
|
|
34
|
+
|
|
35
|
+
Finding _facts_ is your job, never the user's. When a question needs a fact from the environment (files, code, tools, docs), look it up yourself or dispatch a sub-agent with a fresh context window. Do not ask the user for anything you could look up.
|
|
36
|
+
|
|
37
|
+
Do not block on it: a running exploration is an unsettled prerequisite, so only the questions downstream of it wait. Ask the rest of the frontier now. The _decisions_ are the user's: put each to them and wait.
|
|
38
|
+
|
|
39
|
+
## Done
|
|
40
|
+
|
|
41
|
+
The session is done when the frontier is empty: every branch of the design tree visited, nothing left silently assumed. Summarize the settled decisions in a short list and **do not act on them** until the user confirms you have reached a shared understanding.
|
|
42
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: antfu-simplify
|
|
3
|
+
description: Simplify the changes of the current PR or working tree with an ablation study - remove each piece of the diff and keep only what is proven needed - so the result has just-right abstraction, minimal clean code, and stays robust and universal. Use when asked to simplify, slim down, clean up, or reduce the current changes or PR.
|
|
4
|
+
metadata:
|
|
5
|
+
author: Anthony Fu
|
|
6
|
+
version: "2026.10.31"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Simplify Changes
|
|
10
|
+
|
|
11
|
+
Review the **current changes** (PR branch or working tree) and cut them down to the smallest correct diff, the way a skilled developer would. The method is an **ablation study**: remove each piece, check whether anything that matters breaks, and keep only what earns its place.
|
|
12
|
+
|
|
13
|
+
Goal: clean, minimal code with the **just-right abstraction**, that is also **robust** (handles real edge cases) and **universal** (solves the general case, not only the one that triggered the change).
|
|
14
|
+
|
|
15
|
+
## Hard Rules
|
|
16
|
+
|
|
17
|
+
- **Behavior stays the same.** Simplify only. Do not add features, change public APIs, or fix unrelated issues. Report unrelated findings instead.
|
|
18
|
+
- **Scope is the diff.** Only touch code the change introduced or modified, plus code that must change to remove it. Do not refactor the surrounding codebase.
|
|
19
|
+
- **Every removal is verified.** Run the repo's tests, typecheck, and lint after each batch. If a check has no coverage for the removed piece, reason about it explicitly or keep it.
|
|
20
|
+
- Match the surrounding code's style, naming, and comment density.
|
|
21
|
+
|
|
22
|
+
## Workflow
|
|
23
|
+
|
|
24
|
+
1. **Get the diff.** Pick the base: PR target branch merge base (`git merge-base HEAD origin/<default>`), else `git diff HEAD` for uncommitted work. Read the full diff and the files around it. Note the goal of the change in one sentence; it is the yardstick for everything below.
|
|
25
|
+
2. **Inventory the pieces.** List each unit the diff adds: function, parameter, option, branch, type, file, dependency, abstraction layer, comment, test. See [Ablation Study](#ablation-study).
|
|
26
|
+
3. **Ablate.** For each piece, try removing, inlining, or merging it. Decide keep or cut using [Keep vs Cut](#keep-vs-cut).
|
|
27
|
+
4. **Apply** the cuts in small steps. After each batch run focused checks (tests, typecheck, lint). Revert a cut that breaks behavior; that piece is now proven needed.
|
|
28
|
+
5. **Check the result.** Re-read the final diff as a reviewer. Is each remaining line explained by the one-sentence goal? Is it still robust and general?
|
|
29
|
+
6. **Report.** Show a short table of what was cut or kept and why, plus the diff size before and after (`git diff --stat`). Do not commit unless asked.
|
|
30
|
+
|
|
31
|
+
## Ablation Study
|
|
32
|
+
|
|
33
|
+
For every piece in the diff, ask: *if I delete this, what concretely breaks?*
|
|
34
|
+
|
|
35
|
+
| Piece | Ablation | Keep if |
|
|
36
|
+
|-------|----------|---------|
|
|
37
|
+
| New function / helper | Inline it at the call site | Called from 2+ places, or the name explains a non-obvious step |
|
|
38
|
+
| Wrapper / abstraction layer | Call the underlying thing directly | It hides real complexity or a likely-to-change boundary |
|
|
39
|
+
| Parameter / option / config | Hardcode the only used value | A real caller needs a different value now |
|
|
40
|
+
| Type / interface / generic | Use the inferred or existing type | It is exported, or inference gives a worse or wrong type |
|
|
41
|
+
| Branch / guard / try-catch | Delete it and run tests | It guards a reachable case (real input, real failure), not an impossible one |
|
|
42
|
+
| New file / module | Merge it into its only consumer | It has multiple consumers or a distinct responsibility |
|
|
43
|
+
| Dependency | Replace with a few lines or an existing dep | It handles hard edge cases you would otherwise get wrong |
|
|
44
|
+
| Duplicate logic | Reuse an existing util in the repo | No equivalent exists (search first) |
|
|
45
|
+
| Comment | Delete it | It explains *why* (constraint, workaround, surprising choice), not *what* |
|
|
46
|
+
| Test | Remove it and see what is unprotected | It covers behavior or a regression nothing else covers |
|
|
47
|
+
| Changed lines unrelated to the goal | Revert them | Never keep drive-by edits |
|
|
48
|
+
|
|
49
|
+
## Keep vs Cut
|
|
50
|
+
|
|
51
|
+
Cut when the piece is:
|
|
52
|
+
|
|
53
|
+
- Speculative: built for a future need nobody has (extra options, hooks, plugin points, "just in case" generics).
|
|
54
|
+
- Redundant: repeats what the language, framework, types, or an existing util already provides.
|
|
55
|
+
- Defensive against the impossible: null checks on values the types or callers guarantee, fallbacks that never run, catch blocks that swallow errors.
|
|
56
|
+
- Indirection without payoff: one-use helpers, pass-through wrappers, classes where a function works, factories that build one thing.
|
|
57
|
+
- Noise: commented-out code, narrating comments, unused imports and exports, formatting-only churn.
|
|
58
|
+
|
|
59
|
+
Keep (or even add) when the piece is:
|
|
60
|
+
|
|
61
|
+
- **Robustness:** handles real edge cases (empty input, concurrency, cleanup, cross-platform paths, error propagation with context).
|
|
62
|
+
- **Universality:** solves the general problem instead of special-casing the reported one. If the fix hardcodes a name, path, or value from the bug report, generalize it.
|
|
63
|
+
- **Right-sized abstraction:** the third repetition of something gets extracted; the first and second usually do not. A good abstraction removes more code than it adds.
|
|
64
|
+
|
|
65
|
+
If an abstraction is too small, merge; if a function does several unrelated things, split. The target is neither fewest lines nor most layers, it is the fewest concepts a reader must hold.
|
|
66
|
+
|
|
67
|
+
## Smells to Look For
|
|
68
|
+
|
|
69
|
+
- A fix that patches the symptom at the call site instead of the cause.
|
|
70
|
+
- Special cases (`if (name === 'foo')`) where a general rule would cover them.
|
|
71
|
+
- Two code paths that do the same thing with small differences; unify them.
|
|
72
|
+
- State, flags, or caches that can be derived from existing data.
|
|
73
|
+
- Long parameter lists or option bags where most values are never varied.
|
|
74
|
+
- Types duplicated by hand when they can be derived (`typeof`, `ReturnType`, `Parameters`, utility types).
|
|
75
|
+
- Hand-rolled utilities that the repo, runtime, or an existing dependency already has.
|
|
76
|
+
- Tests that assert implementation details or mirror the code line by line.
|
|
77
|
+
|
|
78
|
+
## Report Format
|
|
79
|
+
|
|
80
|
+
```md
|
|
81
|
+
| # | Piece | Action | Why |
|
|
82
|
+
|---|-------|--------|-----|
|
|
83
|
+
| 1 | `parseOptions()` in src/cli.ts | inlined | one caller, 3 lines |
|
|
84
|
+
| 2 | `retry` option | removed | no caller passes it; default is enough |
|
|
85
|
+
| 3 | `try/catch` in fetchData | kept | network errors reach users; test covers it |
|
|
86
|
+
|
|
87
|
+
Diff: +142 -8 -> +61 -8. Tests, typecheck, lint pass.
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
List anything noticed but out of scope (unrelated bugs, wider refactors) separately, and leave it alone.
|
|
91
|
+
|
package/cordis.patch.yml
ADDED
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({id:"dsh-antfubot",factory:(require)=>{var module={exports:{}};var exports=module.exports;
|
|
2
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("react"),t=require("react/jsx-runtime");const n=`settings.general.item`;async function r(e,t){let n=await fetch(`/api/antfubot${e}`,{credentials:`same-origin`,...t,headers:{"content-type":`application/json`,...t?.headers}});if(!n.ok)throw Error(`${e} failed with ${n.status}`);return await n.json()}function i(){return r(`/accounts`)}function a(e){return r(`/settings`,{method:`PUT`,body:JSON.stringify({githubAccount:e})})}function o({t:n}){let[r,o]=(0,e.useState)([]),[s,c]=(0,e.useState)(``),[l,u]=(0,e.useState)(`loading`),[d,f]=(0,e.useState)(!1);(0,e.useEffect)(()=>{let e=!0;return i().then(t=>{e&&(o(t.accounts),c(t.settings.githubAccount),u(`ready`))}).catch(()=>{e&&u(`error`)}),()=>{e=!1}},[]);let p=async e=>{let t=s;c(e),f(!0);try{await a(e)}catch{c(t),u(`error`)}finally{f(!1)}};return l===`loading`?(0,t.jsx)(`div`,{className:`text-sm text-text-secondary`,children:n(`loading`)}):l===`error`?(0,t.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,t.jsx)(`span`,{className:`text-sm font-medium`,children:n(`title`)}),(0,t.jsx)(`span`,{className:`text-sm text-text-secondary`,children:n(`unavailable`)})]}):(0,t.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,t.jsxs)(`label`,{className:`flex items-center justify-between gap-4`,children:[(0,t.jsx)(`span`,{className:`text-sm font-medium`,children:n(`title`)}),(0,t.jsxs)(`select`,{className:`min-w-40 rounded-md border border-border bg-background px-2 py-1 text-sm disabled:opacity-60`,value:s,disabled:d,onChange:e=>{p(e.target.value)},children:[(0,t.jsx)(`option`,{value:``,children:n(`default`)}),r.map(e=>(0,t.jsx)(`option`,{value:e.login,children:e.active?`${e.login} ${n(`activeSuffix`)}`:e.login},e.login))]})]}),(0,t.jsx)(`span`,{className:`text-xs text-text-secondary`,children:n(`hint`)})]})}const s={title:`GitHub Account`,hint:`Used by /triage, /task, /pr and /status. Only this plugin is affected; your global gh login stays as it is.`,default:`Use the active gh account`,activeSuffix:`(active)`,loading:`Reading gh accounts…`,unavailable:`Unable to read gh accounts. Check that the gh CLI is installed and logged in.`},c={title:`GitHub 账号`,hint:`供 /triage、/task、/pr、/status 使用。仅影响本插件,全局 gh 登录状态保持不变。`,default:`使用 gh 当前账号`,activeSuffix:`(当前)`,loading:`正在读取 gh 账号…`,unavailable:`无法读取 gh 账号,请确认已安装并登录 gh CLI。`};function l(e){e.slots.inject(n,()=>e.slots.register({name:n,id:`antfubot-account`,order:10,inject:()=>({t:t=>(e.locale.getSnapshot().active===`zh`?c:s)[t]??s[t]??t})},o))}exports.apply=l;
|
|
3
|
+
return module.exports;}});
|
|
4
|
+
//# sourceMappingURL=client.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.cjs","names":[],"sources":["../src/client/constants.ts","../src/client/settings-client.ts","../src/client/components/account-row.tsx","../src/client/locale.ts","../src/client/index.ts"],"sourcesContent":["/** Slot this plugin contributes to: one row in Settings → General. */\r\nexport const SETTINGS_SLOT = 'settings.general.item'\r\n\r\n/** Stable registration id inside that slot. */\r\nexport const SETTINGS_ROW_ID = 'antfubot-account'\r\n\r\n/** Row ordering: right after the built-in language row (order 0). */\r\nexport const SETTINGS_ROW_ORDER = 10\r\n\r\n/** Route prefix owned by the host half. */\r\nexport const API_BASE = '/api/antfubot'\r\n\r\n/** Locale namespace for this plugin's strings. */\r\nexport const LOCALE_NS = 'antfubot'\r\n","import type { AntfuFlowSettings } from '../types'\r\nimport { API_BASE } from './constants'\r\n\r\n/** One gh account option for the dropdown. */\r\nexport interface AccountOption {\r\n readonly login: string\r\n readonly active: boolean\r\n}\r\n\r\n/** Reply shape of the accounts route. */\r\ninterface AccountsReply {\r\n readonly accounts: readonly AccountOption[]\r\n readonly settings: AntfuFlowSettings\r\n}\r\n\r\nasync function request<T>(path: string, init?: RequestInit): Promise<T> {\r\n const response = await fetch(`${API_BASE}${path}`, {\r\n credentials: 'same-origin',\r\n ...init,\r\n headers: { 'content-type': 'application/json', ...init?.headers },\r\n })\r\n if (!response.ok)\r\n throw new Error(`${path} failed with ${response.status}`)\r\n return await response.json() as T\r\n}\r\n\r\n/** Read the logged-in gh accounts and the stored selection. */\r\nexport function fetchAccounts(): Promise<AccountsReply> {\r\n return request<AccountsReply>('/accounts')\r\n}\r\n\r\n/** Persist the selected account. An empty login clears the override. */\r\nexport function saveAccount(login: string): Promise<{ settings: AntfuFlowSettings }> {\r\n return request('/settings', { method: 'PUT', body: JSON.stringify({ githubAccount: login }) })\r\n}\r\n","import type { AccountOption } from '../settings-client'\r\nimport { useEffect, useState } from 'react'\r\nimport { fetchAccounts, saveAccount } from '../settings-client'\r\n\r\n/** Row exposed in Settings → General: choose which gh account the plugin acts as. */\r\nexport interface AccountRowProps {\r\n /** Translate a locale key. */\r\n readonly t: (key: string, params?: Record<string, unknown>) => string\r\n}\r\n\r\n/**\r\n * Account selector backed by the host routes.\r\n *\r\n * Selection is plugin-scoped: the plugin exports GH_TOKEN for its own gh calls\r\n * and never runs `gh auth switch`, so the global CLI login is untouched. That\r\n * promise is stated in the row's help text, not only in the README.\r\n */\r\nexport function AccountRow({ t }: AccountRowProps): React.ReactElement {\r\n const [accounts, setAccounts] = useState<readonly AccountOption[]>([])\r\n const [selected, setSelected] = useState('')\r\n const [state, setState] = useState<'loading' | 'ready' | 'error'>('loading')\r\n const [saving, setSaving] = useState(false)\r\n\r\n useEffect(() => {\r\n let live = true\r\n fetchAccounts()\r\n .then((reply) => {\r\n if (!live)\r\n return\r\n setAccounts(reply.accounts)\r\n setSelected(reply.settings.githubAccount)\r\n setState('ready')\r\n })\r\n .catch(() => {\r\n if (live)\r\n setState('error')\r\n })\r\n return () => {\r\n live = false\r\n }\r\n }, [])\r\n\r\n const onChange = async (login: string): Promise<void> => {\r\n const previous = selected\r\n setSelected(login)\r\n setSaving(true)\r\n try {\r\n await saveAccount(login)\r\n }\r\n catch {\r\n setSelected(previous)\r\n setState('error')\r\n }\r\n finally {\r\n setSaving(false)\r\n }\r\n }\r\n\r\n if (state === 'loading')\r\n return <div className=\"text-sm text-text-secondary\">{t('loading')}</div>\r\n\r\n if (state === 'error') {\r\n return (\r\n <div className=\"flex flex-col gap-1\">\r\n <span className=\"text-sm font-medium\">{t('title')}</span>\r\n <span className=\"text-sm text-text-secondary\">{t('unavailable')}</span>\r\n </div>\r\n )\r\n }\r\n\r\n return (\r\n <div className=\"flex flex-col gap-1\">\r\n <label className=\"flex items-center justify-between gap-4\">\r\n <span className=\"text-sm font-medium\">{t('title')}</span>\r\n <select\r\n className=\"min-w-40 rounded-md border border-border bg-background px-2 py-1 text-sm disabled:opacity-60\"\r\n value={selected}\r\n disabled={saving}\r\n onChange={(event) => { void onChange(event.target.value) }}\r\n >\r\n <option value=\"\">{t('default')}</option>\r\n {accounts.map(account => (\r\n <option key={account.login} value={account.login}>\r\n {account.active ? `${account.login} ${t('activeSuffix')}` : account.login}\r\n </option>\r\n ))}\r\n </select>\r\n </label>\r\n <span className=\"text-xs text-text-secondary\">{t('hint')}</span>\r\n </div>\r\n )\r\n}\r\n","import { LOCALE_NS } from './constants'\r\n\r\nexport { LOCALE_NS }\r\n\r\n/** English strings for the settings row. */\r\nexport const en = {\r\n title: 'GitHub Account',\r\n hint: 'Used by /triage, /task, /pr and /status. Only this plugin is affected; your global gh login stays as it is.',\r\n default: 'Use the active gh account',\r\n activeSuffix: '(active)',\r\n loading: 'Reading gh accounts…',\r\n unavailable: 'Unable to read gh accounts. Check that the gh CLI is installed and logged in.',\r\n}\r\n\r\n/** Chinese strings for the settings row. */\r\nexport const zh = {\r\n title: 'GitHub 账号',\r\n hint: '供 /triage、/task、/pr、/status 使用。仅影响本插件,全局 gh 登录状态保持不变。',\r\n default: '使用 gh 当前账号',\r\n activeSuffix: '(当前)',\r\n loading: '正在读取 gh 账号…',\r\n unavailable: '无法读取 gh 账号,请确认已安装并登录 gh CLI。',\r\n}\r\n","import type { Context } from '@deepseek-ai/cordis'\r\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\r\n// Type-only: bring the `slots` service and the settings/General slot contract\r\n// into scope without importing either package at runtime.\r\nimport type {} from '@deepseek-ai/dsh-client-ui-renderer/client'\r\nimport type {} from '@deepseek-ai/dsh-client-ui-settings/client'\r\nimport { AccountRow } from './components/account-row'\r\nimport { SETTINGS_ROW_ID, SETTINGS_ROW_ORDER, SETTINGS_SLOT } from './constants'\r\nimport { en, zh } from './locale'\r\n\r\n/**\r\n * Contribute one row to Settings → General.\r\n *\r\n * The General item slot hands the registrar no props, so this row owns its own\r\n * copy: `inject` supplies a translate function resolved from the active locale\r\n * at call time. `slots.inject` waits for the settings surface, so a client\r\n * without it skips the row instead of throwing.\r\n */\r\nexport function apply(ctx: Context): void {\r\n ctx.slots.inject(SETTINGS_SLOT, () => ctx.slots.register({\r\n name: SETTINGS_SLOT,\r\n id: SETTINGS_ROW_ID,\r\n order: SETTINGS_ROW_ORDER,\r\n inject: () => ({\r\n t: (key: string): string => {\r\n const dict = ctx.locale.getSnapshot().active === 'zh' ? zh : en\r\n return (dict as Record<string, string>)[key] ?? (en as Record<string, string>)[key] ?? key\r\n },\r\n }),\r\n }, AccountRow))\r\n}\r\n"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
2
|
+
//#region src/index.d.ts
|
|
3
|
+
declare const name = "antfubot";
|
|
4
|
+
declare const inject: string[];
|
|
5
|
+
/**
|
|
6
|
+
* Mount the antfubot workflow plugin.
|
|
7
|
+
*
|
|
8
|
+
* Three independent contributions: the four antfu skills reach every session
|
|
9
|
+
* catalog, the slash commands compose prompts that name those skills, and the
|
|
10
|
+
* HTTP routes back the settings panel. Each fails loudly on its own instead of
|
|
11
|
+
* leaving a half-working surface.
|
|
12
|
+
*/
|
|
13
|
+
declare function apply(ctx: Context): void;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { apply, inject, name };
|