@perrylink/dsh-github 0.4.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.
Files changed (60) hide show
  1. package/LICENSE +201 -0
  2. package/README.es.md +256 -0
  3. package/README.hi.md +256 -0
  4. package/README.md +257 -0
  5. package/README.pt.md +256 -0
  6. package/README.zh-CN.md +254 -0
  7. package/cordis.patch.yml +9 -0
  8. package/lib/approval-gate.d.ts +25 -0
  9. package/lib/approval-gate.d.ts.map +1 -0
  10. package/lib/approval-gate.js +75 -0
  11. package/lib/approval-gate.js.map +1 -0
  12. package/lib/commands.d.ts +12 -0
  13. package/lib/commands.d.ts.map +1 -0
  14. package/lib/commands.js +228 -0
  15. package/lib/commands.js.map +1 -0
  16. package/lib/config.d.ts +60 -0
  17. package/lib/config.d.ts.map +1 -0
  18. package/lib/config.js +64 -0
  19. package/lib/config.js.map +1 -0
  20. package/lib/credential.d.ts +42 -0
  21. package/lib/credential.d.ts.map +1 -0
  22. package/lib/credential.js +80 -0
  23. package/lib/credential.js.map +1 -0
  24. package/lib/git.d.ts +52 -0
  25. package/lib/git.d.ts.map +1 -0
  26. package/lib/git.js +113 -0
  27. package/lib/git.js.map +1 -0
  28. package/lib/github.d.ts +66 -0
  29. package/lib/github.d.ts.map +1 -0
  30. package/lib/github.js +153 -0
  31. package/lib/github.js.map +1 -0
  32. package/lib/index.d.ts +55 -0
  33. package/lib/index.d.ts.map +1 -0
  34. package/lib/index.js +44 -0
  35. package/lib/index.js.map +1 -0
  36. package/lib/jobs.d.ts +34 -0
  37. package/lib/jobs.d.ts.map +1 -0
  38. package/lib/jobs.js +255 -0
  39. package/lib/jobs.js.map +1 -0
  40. package/lib/present.d.ts +254 -0
  41. package/lib/present.d.ts.map +1 -0
  42. package/lib/present.js +149 -0
  43. package/lib/present.js.map +1 -0
  44. package/lib/review.d.ts +53 -0
  45. package/lib/review.d.ts.map +1 -0
  46. package/lib/review.js +158 -0
  47. package/lib/review.js.map +1 -0
  48. package/lib/state.d.ts +96 -0
  49. package/lib/state.d.ts.map +1 -0
  50. package/lib/state.js +86 -0
  51. package/lib/state.js.map +1 -0
  52. package/lib/tools.d.ts +21 -0
  53. package/lib/tools.d.ts.map +1 -0
  54. package/lib/tools.js +937 -0
  55. package/lib/tools.js.map +1 -0
  56. package/lib/types.d.ts +147 -0
  57. package/lib/types.d.ts.map +1 -0
  58. package/lib/types.js +2 -0
  59. package/lib/types.js.map +1 -0
  60. package/package.json +78 -0
package/README.hi.md ADDED
@@ -0,0 +1,256 @@
1
+ <h1 align="center">dsh-github</h1>
2
+
3
+ <p align="center">
4
+ <b>GitHub को DeepSeek Harness में लाएँ।</b><br/>
5
+ Pull request बनाएँ · inline या summary comments के साथ PR की समीक्षा करें · issues प्रबंधित करें · खोजें — हर write मानवीय approval से नियंत्रित, token कभी logged नहीं होता।
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="README.md">English</a> ·
10
+ <a href="README.zh-CN.md">中文</a> ·
11
+ <a href="README.es.md">Español</a> ·
12
+ <a href="README.pt.md">Português</a> ·
13
+ हिन्दी
14
+ </p>
15
+
16
+ <p align="center">
17
+ <img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License: Apache 2.0">
18
+ <img src="https://img.shields.io/badge/dsh-0.1.0--rc.6-4D6BFE" alt="dsh: 0.1.0-rc.6">
19
+ <img src="https://img.shields.io/badge/dsh-dsh--plugin-4D6BFE" alt="dsh-plugin">
20
+ <img src="https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen" alt="Node: ^22.19 || >=24">
21
+ <img src="https://github.com/PerryLink/dsh-github/actions/workflows/ci.yml/badge.svg" alt="CI">
22
+ <img src="https://img.shields.io/badge/documents-EN%2FZH%2FES%2FPT%2FHI-8257D0" alt="Documents: EN/ZH/ES/PT/HI">
23
+ </p>
24
+
25
+ ---
26
+
27
+ **dsh-github** [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) के लिए एक bundle plugin है — जो "everything is a plugin" एजेंट harness है। यह dsh और [Claude Code](https://github.com/anthropics/claude-code) (`gh claude` / [claude-code-action](https://github.com/anthropics/claude-code-action)) तथा [Codex](https://github.com/openai/codex) (`@codex review` / Autofix CI) जैसे टूल्स के बीच की GitHub कमी को पूरा करता है: आपका एजेंट **PR पढ़ सकता है, PR की समीक्षा (review) कर सकता है, PR खोल सकता है, issues पर comment कर सकता है और उन्हें close कर सकता है, और खोज सकता है** — जबकि हर write को एक मानव अनुमोदित (approve) करता है और token गुप्त रहता है।
28
+
29
+ - 🛠 **8 टूल्स** — `pr_create` · `gh_review` · `review_post` · `gh_issue` · `issue_open` · `issue_comment` · `issue_close` · `gh_search`, सभी `defineTool` के ज़रिए canonical-JSON
30
+ - ⌨️ **3 कमांड परिवार** — `/pr create` · `/review` (start/stop/post) · `/issue open`
31
+ - 📝 **Inline reviews** — `review_post` एक summary comment या PR head commit के विरुद्ध line-anchored review comments प्रकाशित करता है
32
+ - 🔒 **Approval-नियंत्रित writes** — हर GitHub write `ctx.approval` से होकर गुजरता है (डिफ़ॉल्ट `ask`, fail-closed); approval reasons titles, body sizes, और comment overrides की पूर्व-झलक देते हैं
33
+ - 🗝 **Token गोपनीयता** — credentials seam → environment → `gh` CLI, प्रति operation resolved, कभी logs, events, renders, या errors में नहीं
34
+ - ⏱ **Background review jobs** — `/review` `ctx.jobs` पर host के अपने `job_list` / `job_output` / `job_kill` surface के साथ चलता है, और findings के साथ CI status और comment counts भी रिपोर्ट करता है
35
+ - 🤖 **Model review option** — `reviewMode: "model"` capped diff को host के `subagents` seam के ज़रिए एक one-shot subagent को सौंपता है; डिफ़ॉल्ट `static` mode deterministic और token-free रहता है
36
+ - 🚦 **429 backoff + quota surfacing** — model हर result पर (failures सहित) शेष rate limit देखता है; per-section fetch errors छिपाए जाने के बजाय दिखाए जाते हैं
37
+ - 🌐 **5-भाषा docs** — English · 中文 · Español · Português · हिन्दी
38
+
39
+ ---
40
+
41
+ ## 📚 विषय-सूची
42
+
43
+ - [त्वरित शुरुआत](#🚀-त्वरित-शुरुआत)
44
+ - [विशेषताएँ](#✨-विशेषताएँ)
45
+ - [स्थापना](#📦-स्थापना)
46
+ - [कॉन्फ़िगरेशन](#⚙️-कॉन्फ़िगरेशन)
47
+ - [टूल्स](#🛠-टूल्स)
48
+ - [कमांड](#⌨️-कमांड)
49
+ - [आर्किटेक्चर](#🏗-आर्किटेक्चर)
50
+ - [सुरक्षा सीमाएँ](#🔒-सुरक्षा-सीमाएँ)
51
+ - [ज्ञात सीमाएँ](#⚠️-ज्ञात-सीमाएँ)
52
+ - [विकास](#🧪-विकास)
53
+ - [रिपॉज़िटरी संरचना](#🗂-रिपॉज़िटरी-संरचना)
54
+ - [विषय](#🏷-विषय)
55
+ - [लाइसेंस](#लाइसेंस)
56
+
57
+ ## 🚀 त्वरित शुरुआत
58
+
59
+ ```sh
60
+ # 1. install (npm registry — सबसे सरल; या नीचे दिया गया tarball channel इस्तेमाल करें)
61
+ dsh plugin --profile <name> add @perrylink/dsh-github
62
+ # tarball channel (registry की ज़रूरत नहीं):
63
+ pnpm pack # inside this repo → dsh-github-0.4.0.tgz
64
+ dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz
65
+
66
+ # 2. configure a GitHub token (recommended: the credentials seam)
67
+ # $DSH_HOME/.credentials.yaml
68
+ # GITHUB_TOKEN: <your token>
69
+
70
+ # 3. use it — in the dsh web UI or headless
71
+ # /pr create "add dark mode" → agent drafts & opens the PR (approval required)
72
+ # /review 42 → background review job, read it with job_output
73
+ # /review post github-review-1 → publish the review comment (approval required)
74
+ # /issue open "crash on startup" → agent opens the issue (approval required)
75
+ ```
76
+
77
+ सत्यापन: `dsh --profile <name> --dump-config` में `# == dsh-github` सेक्शन **बिना किसी FAILED लाइन के** दिखना चाहिए।
78
+
79
+ ## ✨ विशेषताएँ
80
+
81
+ | क्षेत्र | आपको क्या मिलता है |
82
+ |---|---|
83
+ | **PR बनाएँ** | `/pr create [title]` git स्थिति (branch, changed files, commits ahead) पढ़ता है और एजेंट को एक draft देता है; `pr_create` PR खोलता है और उसका URL लौटाता है |
84
+ | **PR की समीक्षा करें** | `gh_review` metadata, capped diff (canonical value में पूरा text, render में bounded excerpt), comments, CI status, और static findings का सारांश देता है — per-section fetch failures `diff.error` / `comments.error` / `ci.error` के रूप में रिपोर्ट होते हैं |
85
+ | **समीक्षाएँ पोस्ट करें** | `review_post` एक aggregated issue-level comment (`mode: "summary"`, डिफ़ॉल्ट) या PR head commit पर line-anchored review comments (`mode: "inline"`) प्रकाशित करता है; एक `body` override model को पहले comment को निखारने देता है — मानवीय approval के बाद |
86
+ | **Background reviews** | `/review <pr>` एक `ctx.jobs` job में metadata, capped diff, CI checks, और existing comments fetch करता है; completion output findings summary, CI status, और comment count लेकर आता है; `reviewMode: "model"` static analyzer के बजाय diff को एक one-shot subagent को सौंपता है |
87
+ | **Issues पढ़ें** | `gh_issue` lists / gets / comments करता है; listings में pull requests `kind: "pr"` के रूप में marked होते हैं |
88
+ | **Issues प्रबंधित करें** | `issue_open` बनाता है, `issue_comment` comment करता है (PRs पर भी काम करता है), `issue_close` एक optional state reason के साथ close करता है — सभी approval-नियंत्रित |
89
+ | **खोजें** | `gh_search` GitHub search syntax से issues और pull requests को query करता है, अलग search quota दिखाता है |
90
+ | **Approval** | `tools/pre-execute` हर write के लिए `ctx.approval` पूछता है; `allowedActions` whitelist prompting से पहले ही अस्वीकार कर देता है |
91
+ | **गोपनीयता सुरक्षा** | Token प्रति operation पढ़ा जाता है और केवल Authorization header में भेजा जाता है; एक समर्पित test पुष्टि करता है कि यह किसी भी दृश्य output में कभी नहीं आता |
92
+ | **लचीलापन** | `Retry-After`/`x-ratelimit-reset` backoff के साथ 429 retry; read tools concurrency-safe हैं; सभी calls cancellation का सम्मान करते हैं |
93
+ | **अवलोकन-क्षमता** | Model-visible ⇔ logged: model जो कुछ देखता है वह सब host के अपने session events (`tool/result`, `user/message`, `command/run`, `approval/asked`…) से होकर गुजरता है |
94
+
95
+ ## 📦 स्थापना
96
+
97
+ चार दस्तावेज़ित channels — कोई एक चुनें।
98
+
99
+ | चैनल | कमांड | नोट्स |
100
+ |---|---|---|
101
+ | **npm registry** | `dsh plugin --profile <name> add @perrylink/dsh-github` | npm पर प्रकाशित — सबसे सरल channel |
102
+ | **npm tarball** | `dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz` | built `lib/` के साथ आता है — कोई build permission आवश्यक नहीं |
103
+ | **git source** | `dsh plugin --profile <name> add "github:PerryLink/dsh-github#<sha>"` | `prepare` + `allowBuilds` चाहिए (नीचे देखें); commit को pin करें |
104
+ | **local link** | `pnpm link --dir .` then `dsh plugin add @perrylink/dsh-github` | विकास |
105
+
106
+ > npm package `@perrylink` scope के अंतर्गत प्रकाशित है क्योंकि unscoped `dsh-github` नाम registry पर किसी असंबंधित project के पास है। Plugin का module नाम `dsh-github` ही रहता है।
107
+
108
+ Git इंस्टॉल: pnpm ≥10 किसी git dependency के `prepare` को तब तक अस्वीकार करता है जब तक allowlisted न हो — `dsh` सटीक key प्रिंट करता है; उसे profile के `pnpm-workspace.yaml` में कॉपी करें:
109
+
110
+ ```yaml
111
+ allowBuilds:
112
+ '@perrylink/dsh-github': true
113
+ ```
114
+
115
+ `prepare` script (`scripts/prepare.mjs`) स्व-निहित (self-contained) है: जब कोई compiler उपलब्ध हो तो यह TypeScript से build करता है, अन्यथा **committed `lib/` artifacts** पर fallback करता है, और दोनों के अभाव में loud रूप से fail होता है।
116
+
117
+ **अनइंस्टॉल:** `dsh plugin --profile <name> remove @perrylink/dsh-github`।
118
+
119
+ ## ⚙️ कॉन्फ़िगरेशन
120
+
121
+ Load time पर Schemastery-सत्यापित (fail loud)। Profile के `cordis.patch.yml` में कोई भी key override करें (पूरी row config बदल दी जाती है, कभी deep-merged नहीं होती)।
122
+
123
+ | कुंजी | डिफ़ॉल्ट | अर्थ |
124
+ |---|---|---|
125
+ | `tokenSource` | `auto` | `auto` (credentials → env → gh) या `credentials` / `env` / `gh` में से कोई एक |
126
+ | `tokenRef` | `GITHUB_TOKEN` | Credential-seam reference / environment-variable नाम |
127
+ | `defaultOwnerRepo` | — | जब कोई call `owner/repo` नाम न दे और git के पास कोई origin न हो तो Fallback `owner/repo` |
128
+ | `autoCommit` | `false` | क्या `/pr create` model को पहले commit+push करने का निर्देश दे सकता है |
129
+ | `maxDiffChars` | `8000` | reviews में पढ़े जाने वाले PR diffs की character सीमा (cap) |
130
+ | `renderExcerptChars` | `2000` | tool output में render किए जाने वाले diff excerpt की character सीमा |
131
+ | `maxComments` | `20` | `gh_review` द्वारा सूचीबद्ध PR comments की सीमा |
132
+ | `reviewJobTimeoutMs` | `600000` | एक background review job की समय-सीमा (`timeout` के साथ fail होता है) |
133
+ | `maxReviewRecords` | `50` | in-memory review-job records की सीमा; सबसे पुराने settled records पहले evict होते हैं |
134
+ | `reviewMode` | `static` | Review engine: `static` (deterministic analyzer) या `model` (host के `subagents` seam के ज़रिए one-shot subagent; seam अनुपस्थित होने पर fail loud) |
135
+ | `modelReviewProvider` | — | `reviewMode: "model"` के लिए subagent provider नाम; डिफ़ॉल्ट रूप से पहले registered provider का उपयोग |
136
+ | `maxRetries` | `3` | प्रति request 429 retry प्रयास |
137
+ | `retryBaseMs` | `500` | Retry backoff आधार (प्रति प्रयास दोगुना) |
138
+ | `retryMaxWaitMs` | `60000` | Retry backoff की अधिकतम सीमा |
139
+ | `apiBaseUrl` | `https://api.github.com` | GitHub REST base URL (GitHub Enterprise) |
140
+ | `allowedActions` | `['pr.create','review.post','issue.create','issue.comment','issue.close']` | Write-action whitelist; बाकी सब approval से पहले अस्वीकार |
141
+ | `workspaceDir` | process cwd | read-only git inspection के लिए working directory |
142
+
143
+ ## 🛠 टूल्स
144
+
145
+ | टूल | प्रकार | पैरामीटर | लौटाता है |
146
+ |---|---|---|---|
147
+ | `pr_create` | write | `title*`, `body?`, `base?`, `head?`, `draft?`, `ownerRepo?` | `{status:'created', url, number, title, state, draft, base, head, rateLimit}` या structured error |
148
+ | `gh_review` | read | `pr*` (number / `#n` / `o/r#n` / URL), `fields?`, `maxDiffChars?` | metadata, capped diff (पूरा `diff.text` + bounded `diff.excerpt` + per-file stats), comments, CI, static findings, per-section `error` fields, rate limit |
149
+ | `gh_issue` | read | `action*` (`list`/`get`/`comments`), `ownerRepo?`, `issueNumber?`, `state?`, `limit?` | normalized items (हर एक `kind: issue/pr/comment` marked) + rate limit |
150
+ | `review_post` | write | `jobId*`, `mode?` (`summary`/`inline`), `body?` | `{status:'posted', mode, url, commentId?, reviewId?, findings, rateLimit}` या structured error |
151
+ | `issue_open` | write | `title*`, `body?`, `labels?`, `ownerRepo?` | `{status:'created', url, number, title, rateLimit}` या structured error |
152
+ | `issue_comment` | write | `issueNumber*`, `body*`, `ownerRepo?` | `{status:'commented', url, commentId, issueNumber, rateLimit}` या structured error |
153
+ | `issue_close` | write | `issueNumber*`, `ownerRepo?`, `stateReason?` (`completed`/`not_planned`) | `{status:'closed', url, number, title, rateLimit}` या structured error |
154
+ | `gh_search` | read | `q*`, `sort?`, `order?`, `perPage?` | `{query, total, items[{number,title,state,kind,author,url,repo,comments,createdAt}], rateLimit}` या structured error |
155
+
156
+ `execute` केवल `output.schema` द्वारा घोषित canonical JSON लौटाता है। Missing-token और GitHub-API failures structured error variants हैं जो rate-limit facts रखते हैं; infrastructure failures throw करते हैं (→ `isError`)। `exec.signal` का हर जगह सम्मान किया जाता है।
157
+
158
+ ## ⌨️ कमांड
159
+
160
+ | कमांड | प्रभाव |
161
+ |---|---|
162
+ | `/pr create [title]` | git स्थिति पढ़ता है और model के लिए एक `pr_create` instruction queue करता है (draft body, defaults, `autoCommit` न हो तो कोई commit/push नहीं)। PR बनाने पर approval माँगा जाता है। |
163
+ | `/review <pr>` | एक background review job शुरू करता है; job id प्रिंट करता है। पूर्णता की घोषणा host करता है; उसे `job_output` से पढ़ें। |
164
+ | `/review <pr> --max-diff <n> --no-ci --no-comments` | Per-job overrides: diff cap और job कौन-से supplementary sections fetch करता है। |
165
+ | `/review stop <jobId>` | job रद्द करता है (local control, कोई GitHub write नहीं)। |
166
+ | `/review post <jobId>` | model के लिए एक `review_post` instruction queue करता है (summary या inline); पोस्ट करने पर approval माँगा जाता है। |
167
+ | `/issue open <title>` | model के लिए एक `issue_open` instruction queue करता है; बनाने पर approval माँगा जाता है। |
168
+
169
+ ## 🏗 आर्किटेक्चर
170
+
171
+ ```
172
+ ┌───────────────────────────────────────────────┐
173
+ │ dsh-github │
174
+ │ │
175
+ मानव ─── /pr ────┼──► git reader (read-only) ──► agent.followup │
176
+ /review ───┼──► ctx.jobs.start("github-review") ──► job │
177
+ /issue ────┼──► agent.followup │
178
+ │ │
179
+ मॉडल ─── pr_create / gh_review / gh_issue / review_post / │
180
+ issue_open / issue_comment / issue_close / gh_search │
181
+ (defineTool, canonical JSON only) │
182
+ │ │
183
+ └───────┬───────────────┬───────────────┬───────┘
184
+ │ │ │
185
+ tools/pre-execute credential GitHub REST
186
+ approval gate resolution client (fetch,
187
+ (ask | deny) (seam → env → 429 retry,
188
+ gh CLI, per-op) rate-limit)
189
+ ```
190
+
191
+ - **Credential seam.** `tokenSource: auto` प्रति operation क्रम में resolve करता है: credentials seam (`GITHUB_TOKEN` reference) → environment variable → `gh` CLI token। यह मान एक local variable है जो REST client को दिया जाता है; यह कभी canonical values, renders, cards, command outputs, injected notices, job output, approval reasons, या error messages में नहीं जाता।
192
+ - **Approval.** सभी writes model tools से होकर गुजरते हैं। एक `tools/pre-execute` waterfall listener पाँच write tools के लिए `ask` लौटाता है, इसलिए registry `ctx.approval` के ज़रिए मानव से पूछता है (host `approval/asked` + `approval/decided` audit pair log करता है) और बिना answerer के fail closed हो जाता है। Approval reasons यह पूर्व-झलक देते हैं कि क्या प्रकाशित होगा (titles, body sizes, और overridden review body की पहली line)। Commands कभी सीधे write नहीं करते: command handlers बिना किसी open turn के चलते हैं, इसलिए approval seam उनके लिए संरचनात्मक रूप से बंद है — एक write command read-only context इकट्ठा करता है, फिर एजेंट को जगाता है (idle होने पर `followup`, busy होने पर `inject`) ताकि model gated tool को एक turn के भीतर चलाए।
193
+ - **Background review.** `/review <pr>` `ctx.jobs` पर एक `github-review` job शुरू करता है (label, owner, timeout, cancelable)। Job प्रति operation token resolve करता है, PR metadata fetch करता है (inline posting के लिए head-commit SHA कैप्चर करते हुए), capped diff, और — जब तक disabled न हो — CI check runs और existing review comments, फिर एक deterministic multi-file analyzer चलाता है (`src/review.ts`: hardcoded secrets, Google API keys, credential assignments, debug artifacts, eval, TODO markers, long lines, oversized changes) — शून्य tokens खर्च, पूर्णतः testable। `reviewMode: "model"` होने पर, job इसके बजाय capped diff को host के `subagents` seam के ज़रिए एक one-shot subagent को सौंपता है (owning agent parent होता है) और child के Markdown output को postable report के रूप में store करता है; seam या provider अनुपस्थित होने पर fail loud होता है। Supplementary fetch failures output में नोट किए जाते हैं बिना job को fail किए। Completion notices शुरू करने वाले session तक host के `dsh-tool-jobs` consumer के ज़रिए पहुँचते हैं; model रिपोर्ट को मौजूदा `job_output` tool से पढ़ता है और उसे `review_post` से प्रकाशित करता है — approval आवश्यक।
194
+ - **Model-visible ⇔ logged.** Plugin **कोई custom session event types नहीं** जोड़ता। Out-of-repo event types host के `KNOWN_SESSION_EVENT_TYPES` में नहीं हैं, इसलिए एक unknown required event plugin हटाने के बाद session log को अपठनीय बना देता (host जानबूझकर external plugins के लिए registration surface को defer करता है)। इसलिए सारा model-visible content host-logged surfaces से होकर बहता है: `tool/result` canonical values, `agent.inject`/`agent.followup` के ज़रिए `user/message` notices, `command/run` + `command/done` lifecycle pair, और `approval/asked` + `approval/decided` audit pair।
195
+ - **Pure presenters.** `presentCall`/`presentResult` `args` (+ persisted `result.meta`) के pure functions हैं, जो live streaming और log replay पर समान रहते हैं। PR creation PR URL के साथ एक generic card दिखाता है।
196
+
197
+ ## 🔒 सुरक्षा सीमाएँ
198
+
199
+ - Token प्रति operation configured source (credentials seam, environment, या `gh` CLI) से पढ़ा जाता है और केवल REST client के Authorization header में भेजा जाता है। यह कभी logged, कभी rendered, कभी injected, कभी session log में appended, और कभी error messages में नहीं आता।
200
+ - हर GitHub write के लिए `ctx.approval` से `allowed-once` आवश्यक है (default policy `ask`); `rejected`, `cancelled`, और `unavailable` सभी fail closed होते हैं।
201
+ - `/pr create` कभी खुद commit या push नहीं करता; `autoCommit: true` के साथ model वे writes bash tool के अपने approval gate से करता है। dsh-github git identity (dsh-git-identity का काम) या worktrees (dsh-worktree का काम) का प्रबंधन **नहीं** करता।
202
+ - Review job कोई write नहीं करता: यह एक diff पढ़ता है और रिपोर्ट को process memory में रखता है; केवल `review_post` approval के बाद प्रकाशित करता है।
203
+ - Posted comments diff से लिए गए file names को interpolate करते हैं, जो untrusted repository content हैं: `formatPostBody` file names को backtick-escape और HTML-escape करता है ताकि कोई hostile PR review comment में Markdown inject न कर सके।
204
+ - GitHub से पढ़े गए issue/PR bodies, comments, और search results external untrusted content हैं जो model context में प्रवेश करते हैं — web fetching जैसा ही inherent tradeoff; plugin उन्हें अपने renders में external content के रूप में mark करता है।
205
+ - Rate limits: 429s को backoff के साथ retry किया जाता है और शेष quota हर result पर (failures सहित) model को दिखाया जाता है।
206
+
207
+ ## ⚠️ ज्ञात सीमाएँ
208
+
209
+ - **कोई custom session events नहीं** — जानबूझकर (Architecture देखें); audit trails host के अपने event vocabulary पर निर्भर करते हैं।
210
+ - **Static analyzer by default** — deterministic rules (`src/review.ts`), शून्य tokens, reproducible। `reviewMode: "model"` LLM review के लिए capped diff को host के `subagents` seam के ज़रिए एक one-shot subagent को सौंपता है (tokens खर्च होते हैं; seam और एक registered provider की आवश्यकता होती है)।
211
+ - **Jobs और records process-local हैं** — review report plugin memory में job id के आधार पर रहता है, जो host job registry के lifetime से मेल खाता है; record map `maxReviewRecords` से capped है (सबसे पुराने settled records पहले evict होते हैं)।
212
+ - **npm `latest` dist-tags पुराने हैं** — plugin `^0.1.0-rc.5` peer ranges घोषित करता है ताकि यह `dsh-base` द्वारा दिए गए profile closure के विरुद्ध resolve हो, और विकास के लिए `0.1.0-rc.6` pin करता है। कभी भी bare `npm i @deepseek-ai/dsh-tools` से install न करें।
213
+ - **CI / GitHub Action** (`dsh-github-action`, claude-code-action / codex-action की भावना में headless review→comment loop) एक नियोजित v2 companion repository है।
214
+
215
+ ## 🧪 विकास
216
+
217
+ ```sh
218
+ pnpm install
219
+ pnpm test # vitest: config, credentials, 429/retry, tools, commands, jobs, approval gate, token non-leakage
220
+ pnpm typecheck
221
+ pnpm build # tsc → lib/ (noEmitOnError)
222
+ pnpm pack # installable tarball
223
+ pnpm run check:readmes # cross-checks TOC anchors in all 5 READMEs
224
+ ```
225
+
226
+ Tests injected runners के ज़रिए GitHub API, `gh` CLI, और git को mock करते हैं — कोई network नहीं, कोई real credentials नहीं। `test/security.test.ts` पुष्टि करता है कि token string किसी भी model- या human-visible output में कभी नहीं आता। `test/e2e.test.ts` में opt-in real-API smoke tests हैं जो `GITHUB_TOKEN` सेट न होने पर खुद को skip कर लेते हैं (केवल read-only endpoints)।
227
+
228
+ ## 🗂 रिपॉज़िटरी संरचना
229
+
230
+ ```
231
+ src/index.ts plugin entry (name/inject/apply, applyWithDeps for tests)
232
+ src/config.ts Schemastery Config
233
+ src/types.ts local structural views of host services + Context merging
234
+ src/credential.ts token resolution (seam → env → gh), per operation
235
+ src/github.ts REST client: 429 retry, rate limits, diff media type
236
+ src/git.ts read-only git inspection + origin parsing for any API host
237
+ src/review.ts deterministic diff analyzer + sanitized comment drafting
238
+ src/jobs.ts github-review background job producer (metadata + diff + CI + comments)
239
+ src/approval-gate.ts tools/pre-execute ask/deny gate with write previews
240
+ src/tools.ts the eight model-facing tools
241
+ src/commands.ts /pr, /review, /issue
242
+ src/present.ts pure UI-card presenters
243
+ test/ vitest suite + mock host scaffolding + opt-in e2e smoke
244
+ cordis.patch.yml bundle patch (one insert row)
245
+ scripts/prepare.mjs self-contained git-install build
246
+ ```
247
+
248
+ ## 🏷 विषय
249
+
250
+ अनुशंसित GitHub repository topics (उन्हें repo settings में सेट करें — वे [`dsh-plugin` topic page](https://github.com/topics/dsh-plugin) और DSH plugin marketplaces को शक्ति देते हैं):
251
+
252
+ `dsh` · `dsh-plugin` · `deepseek-harness` · `github` · `pull-request` · `code-review` · `issue-tracker`
253
+
254
+ ## लाइसेंस
255
+
256
+ [Apache License 2.0](LICENSE)
package/README.md ADDED
@@ -0,0 +1,257 @@
1
+ <h1 align="center">dsh-github</h1>
2
+
3
+ <p align="center">
4
+ <b>Bring GitHub into DeepSeek Harness.</b><br/>
5
+ Create pull requests · review PRs with inline or summary comments · manage issues · search — every write gated by human approval, token never logged.
6
+ </p>
7
+
8
+ <p align="center">
9
+ <a href="README.zh-CN.md">中文</a> ·
10
+ <a href="README.es.md">Español</a> ·
11
+ <a href="README.pt.md">Português</a> ·
12
+ <a href="README.hi.md">हिन्दी</a>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License: Apache 2.0">
17
+ <img src="https://img.shields.io/badge/dsh-0.1.0--rc.6-4D6BFE" alt="dsh: 0.1.0-rc.6">
18
+ <img src="https://img.shields.io/badge/dsh-dsh--plugin-4D6BFE" alt="dsh-plugin">
19
+ <img src="https://img.shields.io/badge/node-%5E22.19%20%7C%7C%20%3E%3D24-brightgreen" alt="Node: ^22.19 || >=24">
20
+ <img src="https://github.com/PerryLink/dsh-github/actions/workflows/ci.yml/badge.svg" alt="CI">
21
+ <img src="https://img.shields.io/badge/documents-EN%2FZH%2FES%2FPT%2FHI-8257D0" alt="Documents: EN/ZH/ES/PT/HI">
22
+ </p>
23
+
24
+ ---
25
+
26
+ **dsh-github** is a bundle plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) — the "everything is a plugin" agent harness. It fills the GitHub gap between dsh and tools like [Claude Code](https://github.com/anthropics/claude-code) (`gh claude` / [claude-code-action](https://github.com/anthropics/claude-code-action)) and [Codex](https://github.com/openai/codex) (`@codex review` / Autofix CI): your agent can **read a PR, review a PR, open a PR, comment on and close issues, and search** — while a human approves every write and the token stays secret.
27
+
28
+ - 🛠 **8 tools** — `pr_create` · `gh_review` · `review_post` · `gh_issue` · `issue_open` · `issue_comment` · `issue_close` · `gh_search`, all canonical-JSON via `defineTool`
29
+ - ⌨️ **3 command families** — `/pr create` · `/review` (start/stop/post) · `/issue open`
30
+ - 📝 **Inline reviews** — `review_post` posts either one summary comment or line-anchored review comments against the PR head commit
31
+ - 🔒 **Approval-gated writes** — every GitHub write goes through `ctx.approval` (default `ask`, fail-closed); approval reasons preview titles, body sizes, and comment overrides
32
+ - 🗝 **Token secrecy** — credentials seam → environment → `gh` CLI, resolved per operation, never in logs, events, renders, or errors
33
+ - 🖥 **Background review jobs** — `/review` runs on `ctx.jobs` with the host's own `job_list` / `job_output` / `job_kill` surface, and reports CI status and comment counts alongside the findings
34
+ - 🤖 **Model review option** — `reviewMode: "model"` delegates the capped diff to a one-shot subagent through the host's `subagents` seam; the default `static` mode stays deterministic and token-free
35
+ - 🚦 **429 backoff + quota surfacing** — the model sees the remaining rate limit on every result, including failures; per-section fetch errors are surfaced instead of swallowed
36
+ - 🌐 **5-language docs** — English · 中文 · Español · Português · हिन्दी
37
+
38
+ ---
39
+
40
+ ## 📚 Table of contents
41
+
42
+ - [Quick start](#🚀-quick-start)
43
+ - [Features](#✨-features)
44
+ - [Installation](#📦-installation)
45
+ - [Configuration](#⚙️-configuration)
46
+ - [Tools](#🛠-tools)
47
+ - [Commands](#⌨️-commands)
48
+ - [Architecture](#🏗-architecture)
49
+ - [Security boundaries](#🔒-security-boundaries)
50
+ - [Known limitations](#⚠️-known-limitations)
51
+ - [Development](#🧪-development)
52
+ - [Repository layout](#🗂-repository-layout)
53
+ - [Topics](#🏷-topics)
54
+ - [License](#license)
55
+
56
+ ## 🚀 Quick start
57
+
58
+ ```sh
59
+ # 1. install (npm registry — simplest; or use the tarball channel below)
60
+ dsh plugin --profile <name> add @perrylink/dsh-github
61
+ # tarball channel (no registry needed):
62
+ # pnpm pack → dsh-github-0.4.0.tgz
63
+ # dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz
64
+
65
+ # 2. configure a GitHub token (recommended: the credentials seam)
66
+ # $DSH_HOME/.credentials.yaml
67
+ # GITHUB_TOKEN: <your token>
68
+
69
+ # 3. use it — in the dsh web UI or headless
70
+ # /pr create "add dark mode" → agent drafts & opens the PR (approval required)
71
+ # /review 42 → background review job, read it with job_output
72
+ # /review post github-review-1 → publish the review comment (approval required)
73
+ # /issue open "crash on startup" → agent opens the issue (approval required)
74
+ ```
75
+
76
+ Verify: `dsh --profile <name> --dump-config` must show the `# == dsh-github` section with **no FAILED lines**.
77
+
78
+ ## ✨ Features
79
+
80
+ | Area | What you get |
81
+ |---|---|
82
+ | **Create PRs** | `/pr create [title]` reads git state (branch, changed files, commits ahead) and hands the agent a draft; `pr_create` opens the PR and returns its URL |
83
+ | **Review PRs** | `gh_review` summarizes metadata, capped diff (full text in the canonical value, bounded excerpt in the render), comments, CI status, and static findings — per-section fetch failures are reported as `diff.error` / `comments.error` / `ci.error` |
84
+ | **Post reviews** | `review_post` publishes one aggregated issue-level comment (`mode: "summary"`, default) or line-anchored review comments on the PR head commit (`mode: "inline"`); a `body` override lets the model polish the comment first — after human approval |
85
+ | **Background reviews** | `/review <pr>` fetches metadata, the capped diff, CI checks, and existing comments in a `ctx.jobs` job; the completion output carries the findings summary, CI status, and comment count. `reviewMode: "model"` delegates the diff to a one-shot subagent instead of the static analyzer |
86
+ | **Read issues** | `gh_issue` lists / gets / comments; pull requests in listings are marked `kind: "pr"` |
87
+ | **Manage issues** | `issue_open` creates, `issue_comment` comments (also works on PRs), `issue_close` closes with an optional state reason — all approval-gated |
88
+ | **Search** | `gh_search` queries issues and pull requests with GitHub search syntax, surfacing the separate search quota |
89
+ | **Approval** | `tools/pre-execute` asks `ctx.approval` for every write; `allowedActions` whitelist denies before prompting |
90
+ | **Secret safety** | Token is read per operation and sent only in the Authorization header; a dedicated test asserts it never appears in any visible output |
91
+ | **Resilience** | 429 retry with `Retry-After`/`x-ratelimit-reset` backoff; read tools are concurrency-safe; all calls honor cancellation |
92
+ | **Observability** | Model-visible ⇔ logged: everything the model sees flows through the host's own session events (`tool/result`, `user/message`, `command/run`, `approval/asked`…) |
93
+
94
+ ## 📦 Installation
95
+
96
+ Four documented channels — pick one.
97
+
98
+ | Channel | Command | Notes |
99
+ |---|---|---|
100
+ | **npm registry** | `dsh plugin --profile <name> add @perrylink/dsh-github` | Published package — the simplest channel |
101
+ | **npm tarball** | `dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz` | Ships with `lib/` built — no build permission |
102
+ | **git source** | `dsh plugin --profile <name> add "github:PerryLink/dsh-github#<sha>"` | Needs `prepare` + `allowBuilds` (see below); pin the commit |
103
+ | **local link** | `pnpm link --dir .` then `dsh plugin add @perrylink/dsh-github` | Development |
104
+
105
+ > The npm package is published under the `@perrylink` scope because the
106
+ > unscoped `dsh-github` name is owned by an unrelated project on the registry.
107
+ > The plugin's module name stays `dsh-github`.
108
+
109
+ Git installs: pnpm ≥10 refuses a git dependency's `prepare` until allowlisted — `dsh` prints the exact key; copy it into the profile's `pnpm-workspace.yaml`:
110
+
111
+ ```yaml
112
+ allowBuilds:
113
+ '@perrylink/dsh-github': true
114
+ ```
115
+
116
+ The `prepare` script (`scripts/prepare.mjs`) is self-contained: it builds with TypeScript when a compiler is resolvable, otherwise falls back to the **committed `lib/` artifacts**, and fails loud with neither.
117
+
118
+ **Uninstall:** `dsh plugin --profile <name> remove @perrylink/dsh-github`.
119
+
120
+ ## ⚙️ Configuration
121
+
122
+ Schemastery-validated at load time (fail loud). Override any key in the profile's `cordis.patch.yml` (the whole row config is replaced, never deep-merged).
123
+
124
+ | Key | Default | Meaning |
125
+ |---|---|---|
126
+ | `tokenSource` | `auto` | `auto` (credentials → env → gh) or one of `credentials` / `env` / `gh` |
127
+ | `tokenRef` | `GITHUB_TOKEN` | Credential-seam reference / environment-variable name |
128
+ | `defaultOwnerRepo` | — | Fallback `owner/repo` when a call names none and git has no origin |
129
+ | `autoCommit` | `false` | Whether `/pr create` may instruct the model to commit+push first |
130
+ | `maxDiffChars` | `8000` | Character cap for PR diffs read into reviews |
131
+ | `renderExcerptChars` | `2000` | Character cap for the diff excerpt rendered into tool output |
132
+ | `maxComments` | `20` | Cap for PR comments listed by `gh_review` |
133
+ | `reviewJobTimeoutMs` | `600000` | Deadline for one background review job (fails with `timeout`) |
134
+ | `maxReviewRecords` | `50` | Cap for in-memory review-job records; oldest settled records evict first |
135
+ | `reviewMode` | `static` | Review engine: `static` (deterministic analyzer) or `model` (one-shot subagent through the host's `subagents` seam; fails loud when the seam is absent) |
136
+ | `modelReviewProvider` | — | Subagent provider name for `reviewMode: "model"`; defaults to the first registered provider |
137
+ | `maxRetries` | `3` | 429 retry attempts per request |
138
+ | `retryBaseMs` | `500` | Retry backoff base (doubles per attempt) |
139
+ | `retryMaxWaitMs` | `60000` | Retry backoff ceiling |
140
+ | `apiBaseUrl` | `https://api.github.com` | GitHub REST base URL (GitHub Enterprise) |
141
+ | `allowedActions` | `['pr.create','review.post','issue.create','issue.comment','issue.close']` | Write-action whitelist; anything else is denied before approval |
142
+ | `workspaceDir` | process cwd | Working directory for read-only git inspection |
143
+
144
+ ## 🛠 Tools
145
+
146
+ | Tool | Kind | Parameters | Returns |
147
+ |---|---|---|---|
148
+ | `pr_create` | write | `title*`, `body?`, `base?`, `head?`, `draft?`, `ownerRepo?` | `{status:'created', url, number, title, state, draft, base, head, rateLimit}` or structured error |
149
+ | `gh_review` | read | `pr*` (number / `#n` / `o/r#n` / URL), `fields?`, `maxDiffChars?` | metadata, capped diff (full `diff.text` + bounded `diff.excerpt` + per-file stats), comments, CI, static findings, per-section `error` fields, rate limit |
150
+ | `gh_issue` | read | `action*` (`list`/`get`/`comments`), `ownerRepo?`, `issueNumber?`, `state?`, `limit?` | normalized items (each marked `kind: issue/pr/comment`) + rate limit |
151
+ | `review_post` | write | `jobId*`, `mode?` (`summary`/`inline`), `body?` | `{status:'posted', mode, url, commentId?, reviewId?, findings, rateLimit}` or structured error |
152
+ | `issue_open` | write | `title*`, `body?`, `labels?`, `ownerRepo?` | `{status:'created', url, number, title, rateLimit}` or structured error |
153
+ | `issue_comment` | write | `issueNumber*`, `body*`, `ownerRepo?` | `{status:'commented', url, commentId, issueNumber, rateLimit}` or structured error |
154
+ | `issue_close` | write | `issueNumber*`, `ownerRepo?`, `stateReason?` (`completed`/`not_planned`) | `{status:'closed', url, number, title, rateLimit}` or structured error |
155
+ | `gh_search` | read | `q*`, `sort?`, `order?`, `perPage?` | `{query, total, items[{number,title,state,kind,author,url,repo,comments,createdAt}], rateLimit}` or structured error |
156
+
157
+ `execute` returns only the canonical JSON declared by `output.schema`. Missing-token and GitHub-API failures are structured error variants carrying rate-limit facts; infrastructure failures throw (→ `isError`). `exec.signal` is honored everywhere.
158
+
159
+ ## ⌨️ Commands
160
+
161
+ | Command | Effect |
162
+ |---|---|
163
+ | `/pr create [title]` | Reads git state and queues a `pr_create` instruction for the model (draft body, defaults, no commit/push unless `autoCommit`). Creating the PR asks for approval. |
164
+ | `/review <pr>` | Starts a background review job; prints the job id. Completion is announced by the host; read it with `job_output`. |
165
+ | `/review <pr> --max-diff <n> --no-ci --no-comments` | Per-job overrides: diff cap and which supplementary sections the job fetches. |
166
+ | `/review stop <jobId>` | Cancels the job (local control, no GitHub write). |
167
+ | `/review post <jobId>` | Queues a `review_post` instruction for the model (summary or inline); posting asks for approval. |
168
+ | `/issue open <title>` | Queues an `issue_open` instruction for the model; creating asks for approval. |
169
+
170
+ ## 🏗 Architecture
171
+
172
+ ```
173
+ ┌───────────────────────────────────────────────┐
174
+ │ dsh-github │
175
+ │ │
176
+ humans ─── /pr ────┼──► git reader (read-only) ──► agent.followup │
177
+ /review ───┼──► ctx.jobs.start("github-review") ──► job │
178
+ /issue ────┼──► agent.followup │
179
+ │ │
180
+ model ─── pr_create / gh_review / gh_issue / review_post / │
181
+ issue_open / issue_comment / issue_close / gh_search │
182
+ (defineTool, canonical JSON only) │
183
+ │ │
184
+ └───────┬───────────────┬───────────────┬───────┘
185
+ │ │ │
186
+ tools/pre-execute credential GitHub REST
187
+ approval gate resolution client (fetch,
188
+ (ask | deny) (seam → env → 429 retry,
189
+ gh CLI, per-op) rate-limit)
190
+ ```
191
+
192
+ - **Credential seam.** `tokenSource: auto` resolves per operation in the order credentials seam (`GITHUB_TOKEN` reference) → environment variable → `gh` CLI token. The value is a local variable handed to the REST client; it never enters canonical values, renders, cards, command outputs, injected notices, job output, approval reasons, or error messages.
193
+ - **Approval.** All writes flow through model tools. A `tools/pre-execute` waterfall listener returns `ask` for the five write tools, so the registry asks the human through `ctx.approval` (the host logs the `approval/asked` + `approval/decided` audit pair) and fails closed without an answerer. Approval reasons preview what would be published (titles, body sizes, and the first line of an overridden review body). Commands never write directly: command handlers run with no open turn, so the approval seam is structurally closed to them — a write command gathers read-only context, then wakes the agent (`followup` when idle, `inject` when busy) so the model runs the gated tool inside a turn.
194
+ - **Background review.** `/review <pr>` starts a `github-review` job on `ctx.jobs` (label, owner, timeout, cancelable). The job resolves the token per operation, fetches the PR metadata (capturing the head-commit SHA for inline posting), the capped diff, and — unless disabled — CI check runs and existing review comments, then runs a deterministic multi-file analyzer (`src/review.ts`: hardcoded secrets, Google API keys, credential assignments, debug artifacts, eval, TODO markers, long lines, oversized changes) — zero tokens spent, fully testable. With `reviewMode: "model"`, the job instead hands the capped diff to a one-shot subagent through the host's `subagents` seam (the owning agent is the parent) and stores the child's Markdown output as the postable report; a missing seam or provider fails loud. Supplementary fetch failures are noted in the output without failing the job. Completion notices reach the initiating session through the host's `dsh-tool-jobs` consumer; the model reads the report via the existing `job_output` tool and publishes it with `review_post` — approval required.
195
+ - **Model-visible ⇔ logged.** The plugin appends **no custom session event types**. Out-of-repo event types are not in the host's `KNOWN_SESSION_EVENT_TYPES`, so an unknown required event would make the session log unreadable after plugin removal (the host deliberately defers a registration surface for external plugins). All model-visible content therefore flows through host-logged surfaces: `tool/result` canonical values, `user/message` notices via `agent.inject`/`agent.followup`, the `command/run` + `command/done` lifecycle pair, and the `approval/asked` + `approval/decided` audit pair.
196
+ - **Pure presenters.** `presentCall`/`presentResult` are pure functions of `args` (+ the persisted `result.meta`), identical on live streaming and log replay. PR creation shows a generic card with the PR URL.
197
+
198
+ ## 🔒 Security boundaries
199
+
200
+ - The token is read per operation from the configured source (credentials seam, environment, or `gh` CLI) and sent only in the REST client's Authorization header. It is never logged, never rendered, never injected, never appended to the session log, and never appears in error messages.
201
+ - Every GitHub write requires `allowed-once` from `ctx.approval` (default policy `ask`); `rejected`, `cancelled`, and `unavailable` all fail closed.
202
+ - `/pr create` never commits or pushes by itself; with `autoCommit: true` the model performs those writes through the bash tool's own approval gate. dsh-github does **not** manage git identity (dsh-git-identity's job) or worktrees (dsh-worktree's job).
203
+ - The review job performs no writes: it reads a diff and stores a report in process memory; only `review_post` publishes, after approval.
204
+ - Posted comments interpolate diff-derived file names, which are untrusted repository content: `formatPostBody` backtick-escapes and HTML-escapes file names so a hostile PR cannot inject Markdown into the review comment.
205
+ - Issue/PR bodies, comments, and search results read from GitHub are external untrusted content that enters model context — the same inherent tradeoff as web fetching; the plugin marks them as external content in its renders.
206
+ - Rate limits: 429s are retried with backoff and the remaining quota is surfaced to the model on every result, including failures.
207
+
208
+ ## ⚠️ Known limitations
209
+
210
+ - **No custom session events** — deliberate (see Architecture); audit trails rely on the host's own event vocabulary.
211
+ - **Static analyzer by default** — deterministic rules (`src/review.ts`), zero tokens, reproducible. `reviewMode: "model"` delegates the capped diff to a one-shot subagent through the host's `subagents` seam for an LLM review (costs tokens; requires the seam and a registered provider).
212
+ - **Jobs and records are process-local** — the review report lives in plugin memory keyed by job id, matching the host job registry's lifetime; the record map is capped by `maxReviewRecords` (oldest settled records evict first).
213
+ - **npm `latest` dist-tags are stale** — the plugin declares `^0.1.0-rc.5` peer ranges so it resolves against the profile closure that `dsh-base` provides, and pins `0.1.0-rc.6` for development. Never install by bare `npm i @deepseek-ai/dsh-tools`.
214
+ - **CI / GitHub Action** (`dsh-github-action`, headless review→comment loop in the spirit of claude-code-action / codex-action) is a planned v2 companion repository.
215
+
216
+ ## 🧪 Development
217
+
218
+ ```sh
219
+ pnpm install
220
+ pnpm test # vitest: config, credentials, 429/retry, tools, commands, jobs, approval gate, token non-leakage
221
+ pnpm typecheck
222
+ pnpm build # tsc → lib/ (noEmitOnError)
223
+ pnpm pack # installable tarball
224
+ pnpm run check:readmes # cross-checks TOC anchors in all 5 READMEs
225
+ ```
226
+
227
+ Tests mock the GitHub API, the `gh` CLI, and git through injected runners — no network, no real credentials. `test/security.test.ts` asserts the token string never appears in any model- or human-visible output. `test/e2e.test.ts` contains opt-in real-API smoke tests that self-skip unless `GITHUB_TOKEN` is set (read-only endpoints only).
228
+
229
+ ## 🗂 Repository layout
230
+
231
+ ```
232
+ src/index.ts plugin entry (name/inject/apply, applyWithDeps for tests)
233
+ src/config.ts Schemastery Config
234
+ src/types.ts local structural views of host services + Context merging
235
+ src/credential.ts token resolution (seam → env → gh), per operation
236
+ src/github.ts REST client: 429 retry, rate limits, diff media type
237
+ src/git.ts read-only git inspection + origin parsing for any API host
238
+ src/review.ts deterministic diff analyzer + sanitized comment drafting
239
+ src/jobs.ts github-review background job producer (metadata + diff + CI + comments)
240
+ src/approval-gate.ts tools/pre-execute ask/deny gate with write previews
241
+ src/tools.ts the eight model-facing tools
242
+ src/commands.ts /pr, /review, /issue
243
+ src/present.ts pure UI-card presenters
244
+ test/ vitest suite + mock host scaffolding + opt-in e2e smoke
245
+ cordis.patch.yml bundle patch (one insert row)
246
+ scripts/prepare.mjs self-contained git-install build
247
+ ```
248
+
249
+ ## 🏷 Topics
250
+
251
+ Recommended GitHub repository topics (set them in the repo settings — they power the [`dsh-plugin` topic page](https://github.com/topics/dsh-plugin) and the DSH plugin marketplaces):
252
+
253
+ `dsh` · `dsh-plugin` · `deepseek-harness` · `github` · `pull-request` · `code-review` · `issue-tracker`
254
+
255
+ ## License
256
+
257
+ [Apache License 2.0](LICENSE)