@perrylink/dsh-github 0.4.1 → 0.6.1
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/README.es.md +30 -13
- package/README.hi.md +30 -13
- package/README.md +53 -13
- package/README.pt.md +31 -14
- package/README.zh-CN.md +53 -13
- package/action.yml +161 -0
- package/lib/approval-gate.d.ts +14 -9
- package/lib/approval-gate.d.ts.map +1 -1
- package/lib/approval-gate.js +39 -1
- package/lib/approval-gate.js.map +1 -1
- package/lib/ci/bot.d.ts +50 -0
- package/lib/ci/bot.d.ts.map +1 -0
- package/lib/ci/bot.js +168 -0
- package/lib/ci/bot.js.map +1 -0
- package/lib/ci/pipeline.d.ts +84 -0
- package/lib/ci/pipeline.d.ts.map +1 -0
- package/lib/ci/pipeline.js +380 -0
- package/lib/ci/pipeline.js.map +1 -0
- package/lib/ci/review-rules.d.ts +41 -0
- package/lib/ci/review-rules.d.ts.map +1 -0
- package/lib/ci/review-rules.js +108 -0
- package/lib/ci/review-rules.js.map +1 -0
- package/lib/ci/tool.d.ts +4 -0
- package/lib/ci/tool.d.ts.map +1 -0
- package/lib/ci/tool.js +155 -0
- package/lib/ci/tool.js.map +1 -0
- package/lib/commands.d.ts.map +1 -1
- package/lib/commands.js +5 -2
- package/lib/commands.js.map +1 -1
- package/lib/config.d.ts +65 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +75 -2
- package/lib/config.js.map +1 -1
- package/lib/github.d.ts +11 -7
- package/lib/github.d.ts.map +1 -1
- package/lib/github.js +28 -7
- package/lib/github.js.map +1 -1
- package/lib/index.d.ts +15 -9
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +13 -1
- package/lib/index.js.map +1 -1
- package/lib/jobs.js +4 -3
- package/lib/jobs.js.map +1 -1
- package/lib/present.d.ts +146 -0
- package/lib/present.d.ts.map +1 -1
- package/lib/present.js +140 -1
- package/lib/present.js.map +1 -1
- package/lib/review.d.ts +11 -1
- package/lib/review.d.ts.map +1 -1
- package/lib/review.js +12 -9
- package/lib/review.js.map +1 -1
- package/lib/state.d.ts +3 -1
- package/lib/state.d.ts.map +1 -1
- package/lib/state.js +11 -6
- package/lib/state.js.map +1 -1
- package/lib/tools.d.ts +71 -0
- package/lib/tools.d.ts.map +1 -1
- package/lib/tools.js +379 -16
- package/lib/tools.js.map +1 -1
- package/package.json +6 -2
- package/scripts/action-patch.mjs +152 -0
- package/scripts/action-post.mjs +61 -0
- package/scripts/check-readmes.mjs +113 -0
- package/scripts/local-test.mjs +259 -0
- package/scripts/prepare.mjs +34 -0
package/README.es.md
CHANGED
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
**dsh-github** es un plugin bundle para [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) — el agente harness «todo es un plugin». Cubre el vacío de GitHub entre dsh y herramientas como [Claude Code](https://github.com/anthropics/claude-code) (`gh claude` / [claude-code-action](https://github.com/anthropics/claude-code-action)) y [Codex](https://github.com/openai/codex) (`@codex review` / Autofix CI): tu agente puede **leer una PR, revisar una PR, abrir una PR, comentar y cerrar issues, y buscar** — mientras un humano aprueba cada escritura y el token permanece en secreto.
|
|
27
|
+
**dsh-github** es un plugin bundle para [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (`dsh`) — el agente harness «todo es un plugin». Cubre el vacío de GitHub entre dsh y herramientas como [Claude Code](https://github.com/anthropics/claude-code) (`gh claude` / [claude-code-action](https://github.com/anthropics/claude-code-action)) y [Codex](https://github.com/openai/codex) (`@codex review` / Autofix CI): tu agente puede **leer una PR, revisar una PR, abrir una PR, fusionar y actualizar PRs, leer metadatos de repositorios y archivos, comentar y cerrar issues, y buscar** — mientras un humano aprueba cada escritura y el token permanece en secreto.
|
|
28
28
|
|
|
29
|
-
- 🛠 **
|
|
29
|
+
- 🛠 **12 herramientas** — `pr_create` · `pr_merge` · `pr_update` · `gh_review` · `review_post` · `gh_issue` · `issue_open` · `issue_comment` · `issue_close` · `gh_search` · `gh_repo` · `gh_file`, todas con JSON canónico mediante `defineTool`
|
|
30
30
|
- ⌨️ **3 familias de comandos** — `/pr create` · `/review` (start/stop/post) · `/issue open`
|
|
31
|
+
- 🔀 **Ciclo de vida completo de PRs** — crear → revisar → actualizar (título/cuerpo/estado/rama base) → fusionar (merge/squash/rebase, borrado opcional de la rama head)
|
|
31
32
|
- 📝 **Revisiones en línea** — `review_post` publica un único comentario de resumen o comentarios de revisión anclados por línea contra el commit head de la PR
|
|
32
33
|
- 🔒 **Escrituras con aprobación** — cada escritura en GitHub pasa por `ctx.approval` (`ask` por defecto, se cierra ante fallo); los motivos de aprobación previsualizan títulos, tamaños de cuerpo y anulaciones de comentarios
|
|
33
34
|
- 🗝 **Secreto del token** — capa de credenciales → entorno → CLI `gh`, resuelto por operación, nunca en registros, eventos, representaciones ni errores
|
|
@@ -60,8 +61,8 @@
|
|
|
60
61
|
# 1. instalar (registro npm — lo más simple; o usa el canal tarball de abajo)
|
|
61
62
|
dsh plugin --profile <name> add @perrylink/dsh-github
|
|
62
63
|
# canal tarball (sin necesidad de registro):
|
|
63
|
-
pnpm pack
|
|
64
|
-
dsh plugin --profile <name> add ./dsh-github
|
|
64
|
+
# pnpm pack → dsh-github-<version>.tgz
|
|
65
|
+
# dsh plugin --profile <name> add ./dsh-github-<version>.tgz
|
|
65
66
|
|
|
66
67
|
# 2. configure a GitHub token (recommended: the credentials seam)
|
|
67
68
|
# $DSH_HOME/.credentials.yaml
|
|
@@ -81,9 +82,13 @@ Verificación: `dsh --profile <name> --dump-config` debe mostrar la sección `#
|
|
|
81
82
|
| Área | Qué obtienes |
|
|
82
83
|
|---|---|
|
|
83
84
|
| **Crear PRs** | `/pr create [title]` lee el estado de git (rama, archivos modificados, commits por delante) y entrega un borrador al agente; `pr_create` abre la PR y devuelve su URL |
|
|
85
|
+
| **Actualizar PRs** | `pr_update` edita título, cuerpo, estado o rama de destino — con aprobación como cualquier otra escritura |
|
|
86
|
+
| **Fusionar PRs** | `pr_merge` fusiona con `merge`/`squash`/`rebase`, título/mensaje de commit opcionales y borrado de la rama head tras la fusión |
|
|
84
87
|
| **Revisar PRs** | `gh_review` resume metadatos, diff limitado (texto completo en el valor canónico, extracto acotado en la representación), comentarios, estado de CI y hallazgos estáticos — los fallos de obtención por sección se informan como `diff.error` / `comments.error` / `ci.error` |
|
|
85
88
|
| **Publicar revisiones** | `review_post` publica un comentario agregado a nivel de issue (`mode: "summary"`, por defecto) o comentarios de revisión anclados por línea en el commit head de la PR (`mode: "inline"`); una anulación de `body` permite que el modelo pula primero el comentario — tras la aprobación humana |
|
|
86
89
|
| **Revisiones en segundo plano** | `/review <pr>` obtiene metadatos, el diff limitado, las comprobaciones de CI y los comentarios existentes en un job de `ctx.jobs`; la salida de finalización incluye el resumen de hallazgos, el estado de CI y el recuento de comentarios; `reviewMode: "model"` delega el diff a un subagente de un solo uso en lugar del analizador estático |
|
|
90
|
+
| **Leer repositorios** | `gh_repo` lee los metadatos del repositorio: descripción, rama por defecto, visibilidad, estrellas, forks, issues abiertas, lenguaje, licencia, temas |
|
|
91
|
+
| **Leer archivos** | `gh_file` lee un archivo en una rama/tag/commit con decodificación base64 y un límite configurable; los directorios devuelven un error estructurado |
|
|
87
92
|
| **Leer issues** | `gh_issue` lista / obtiene / comenta; los pull requests en los listados se marcan como `kind: "pr"` |
|
|
88
93
|
| **Gestionar issues** | `issue_open` crea, `issue_comment` comenta (también funciona en PRs), `issue_close` cierra con un motivo de estado opcional — todas con aprobación |
|
|
89
94
|
| **Buscar** | `gh_search` consulta issues y pull requests con la sintaxis de búsqueda de GitHub, mostrando la cuota de búsqueda independiente |
|
|
@@ -99,7 +104,7 @@ Cuatro canales documentados — elige uno.
|
|
|
99
104
|
| Canal | Comando | Notas |
|
|
100
105
|
|---|---|---|
|
|
101
106
|
| **npm registry** | `dsh plugin --profile <name> add @perrylink/dsh-github` | Publicado en npm — el canal más simple |
|
|
102
|
-
| **Tarball npm** | `dsh plugin --profile <name> add ./dsh-github
|
|
107
|
+
| **Tarball npm** | `dsh plugin --profile <name> add ./dsh-github-<version>.tgz` | Se distribuye con `lib/` compilado — sin permiso de compilación |
|
|
103
108
|
| **Fuente git** | `dsh plugin --profile <name> add "github:PerryLink/dsh-github#<sha>"` | Requiere `prepare` + `allowBuilds` (ver abajo); fija el commit |
|
|
104
109
|
| **Enlace local** | `pnpm link --dir .` y luego `dsh plugin add @perrylink/dsh-github` | Desarrollo |
|
|
105
110
|
|
|
@@ -131,21 +136,30 @@ Validado con Schemastery en el momento de carga (falla de forma evidente). Sobre
|
|
|
131
136
|
| `maxComments` | `20` | Límite para los comentarios de PR listados por `gh_review` |
|
|
132
137
|
| `reviewJobTimeoutMs` | `600000` | Plazo para un trabajo de revisión en segundo plano (falla con `timeout`) |
|
|
133
138
|
| `maxReviewRecords` | `50` | Límite para los registros en memoria de trabajos de revisión; los registros finalizados más antiguos se eliminan primero |
|
|
139
|
+
| `maxFileChars` | `12000` | Límite de caracteres para el contenido de archivos leído por `gh_file` |
|
|
140
|
+
| `maxFindings` | `50` | Límite de hallazgos del analizador por revisión |
|
|
141
|
+
| `maxLineLength` | `300` | Longitud de línea a partir de la cual el analizador marca un hallazgo de línea larga |
|
|
134
142
|
| `reviewMode` | `static` | Motor de revisión: `static` (analizador determinista) o `model` (subagente de un solo uso a través de la seam `subagents` del host; falla de forma evidente si la seam no está presente) |
|
|
135
143
|
| `modelReviewProvider` | — | Nombre del proveedor de subagente para `reviewMode: "model"`; por defecto, el primer proveedor registrado |
|
|
136
144
|
| `maxRetries` | `3` | Intentos de reintento 429 por solicitud |
|
|
137
145
|
| `retryBaseMs` | `500` | Base del retroceso de reintento (se duplica por intento) |
|
|
138
146
|
| `retryMaxWaitMs` | `60000` | Tope del retroceso de reintento |
|
|
147
|
+
| `requestTimeoutMs` | `30000` | Tiempo máximo por solicitud; aborta el fetch al superarse |
|
|
139
148
|
| `apiBaseUrl` | `https://api.github.com` | URL base de la API REST de GitHub (GitHub Enterprise) |
|
|
140
|
-
| `allowedActions` | `['pr.create','review.post','issue.create','issue.comment','issue.close']` | Lista blanca de acciones de escritura; cualquier otra se deniega antes de la aprobación |
|
|
149
|
+
| `allowedActions` | `['pr.create','pr.merge','pr.update','review.post','issue.create','issue.comment','issue.close','ci.run']` | Lista blanca de acciones de escritura; cualquier otra se deniega antes de la aprobación |
|
|
141
150
|
| `workspaceDir` | process cwd | Directorio de trabajo para la inspección de git de solo lectura |
|
|
151
|
+
| `ci` | `{ enabled: false, … }` | Sección de integración CI: bot de revisión por sondeo, puerta de status-check y la herramienta de un solo uso `ci_run` (contiene todas las claves `ci.*`) |
|
|
142
152
|
|
|
143
153
|
## 🛠 Herramientas
|
|
144
154
|
|
|
145
155
|
| Herramienta | Tipo | Parámetros | Devuelve |
|
|
146
156
|
|---|---|---|---|
|
|
147
157
|
| `pr_create` | escritura | `title*`, `body?`, `base?`, `head?`, `draft?`, `ownerRepo?` | `{status:'created', url, number, title, state, draft, base, head, rateLimit}` o error estructurado |
|
|
158
|
+
| `pr_merge` | escritura | `pr*` (número / `#n` / `o/r#n` / URL), `mergeMethod?`, `commitTitle?`, `commitMessage?`, `deleteBranch?` | `{status:'merged', merged, sha?, message, url, branchDeleted, branchDeleteNote?, rateLimit}` o error estructurado |
|
|
159
|
+
| `pr_update` | escritura | `pr*` (número / `#n` / `o/r#n` / URL), `title?`, `body?`, `state?` (`open`/`closed`), `base?` | `{status:'updated', url, number, title, state, base, rateLimit}` o error estructurado |
|
|
148
160
|
| `gh_review` | lectura | `pr*` (número / `#n` / `o/r#n` / URL), `fields?`, `maxDiffChars?` | metadatos, diff limitado (texto completo `diff.text` + extracto acotado `diff.excerpt` + estadísticas por archivo), comentarios, CI, hallazgos estáticos, campos de `error` por sección, límite de velocidad |
|
|
161
|
+
| `gh_repo` | lectura | `ownerRepo?` | `{repo, description, defaultBranch, visibility, stars, forks, openIssues, language, license, topics, url, updatedAt, rateLimit}` o error estructurado |
|
|
162
|
+
| `gh_file` | lectura | `ownerRepo?`, `path*`, `ref?`, `maxChars?` | `{repo, path, ref, size, truncated, content, sha, url, rateLimit}` o error estructurado |
|
|
149
163
|
| `gh_issue` | lectura | `action*` (`list`/`get`/`comments`), `ownerRepo?`, `issueNumber?`, `state?`, `limit?` | elementos normalizados (cada uno marcado `kind: issue/pr/comment`) + límite de velocidad |
|
|
150
164
|
| `review_post` | escritura | `jobId*`, `mode?` (`summary`/`inline`), `body?` | `{status:'posted', mode, url, commentId?, reviewId?, findings, rateLimit}` o error estructurado |
|
|
151
165
|
| `issue_open` | escritura | `title*`, `body?`, `labels?`, `ownerRepo?` | `{status:'created', url, number, title, rateLimit}` o error estructurado |
|
|
@@ -176,8 +190,9 @@ Validado con Schemastery en el momento de carga (falla de forma evidente). Sobre
|
|
|
176
190
|
/review ───┼──► ctx.jobs.start("github-review") ──► job │
|
|
177
191
|
/issue ────┼──► agent.followup │
|
|
178
192
|
│ │
|
|
179
|
-
modelo ─── pr_create /
|
|
180
|
-
|
|
193
|
+
modelo ─── pr_create / pr_merge / pr_update / gh_review / │
|
|
194
|
+
review_post / gh_issue / issue_open / issue_comment / │
|
|
195
|
+
issue_close / gh_search / gh_repo / gh_file │
|
|
181
196
|
(defineTool, canonical JSON only) │
|
|
182
197
|
│ │
|
|
183
198
|
└───────┬───────────────┬───────────────┬───────┘
|
|
@@ -189,7 +204,7 @@ Validado con Schemastery en el momento de carga (falla de forma evidente). Sobre
|
|
|
189
204
|
```
|
|
190
205
|
|
|
191
206
|
- **Capa de credenciales.** `tokenSource: auto` resuelve por operación en el orden: capa de credenciales (referencia `GITHUB_TOKEN`) → variable de entorno → token de la CLI `gh`. El valor es una variable local entregada al cliente REST; nunca entra en valores canónicos, representaciones, tarjetas, salidas de comandos, avisos inyectados, salidas de trabajos, motivos de aprobación ni mensajes de error.
|
|
192
|
-
- **Aprobación.** Todas las escrituras fluyen a través de las herramientas del modelo. Un listener waterfall `tools/pre-execute` devuelve `ask` para las
|
|
207
|
+
- **Aprobación.** Todas las escrituras fluyen a través de las herramientas del modelo. Un listener waterfall `tools/pre-execute` devuelve `ask` para las siete herramientas de escritura, de modo que el registro le pregunta al humano mediante `ctx.approval` (el host registra el par de auditoría `approval/asked` + `approval/decided`) y se cierra ante fallo si no hay quien responda. Los motivos de aprobación previsualizan lo que se va a publicar (títulos, tamaños de cuerpo, métodos de fusión y la primera línea de un cuerpo de revisión anulado). Los comandos nunca escriben directamente: los manejadores de comandos se ejecutan sin un turno abierto, por lo que la capa de aprobación está estructuralmente cerrada para ellos — un comando de escritura reúne contexto de solo lectura y luego despierta al agente (`followup` cuando está inactivo, `inject` cuando está ocupado) para que el modelo ejecute la herramienta controlada dentro de un turno.
|
|
193
208
|
- **Revisión en segundo plano.** `/review <pr>` inicia un trabajo `github-review` en `ctx.jobs` (etiqueta, propietario, tiempo límite, cancelable). El trabajo resuelve el token por operación, obtiene los metadatos de la PR (capturando el SHA del commit head para la publicación en línea), el diff limitado y —salvo que se desactive— las ejecuciones de comprobación de CI y los comentarios de revisión existentes, y luego ejecuta un analizador multiarchivo determinista (`src/review.ts`: secretos codificados, claves de API de Google, asignaciones de credenciales, artefactos de depuración, eval, marcadores TODO, líneas largas, cambios sobredimensionados) — cero tokens gastados, totalmente comprobable. Con `reviewMode: "model"`, el trabajo entrega el diff limitado a un subagente de un solo uso a través de la seam `subagents` del host (el agente propietario es el padre) y guarda la salida Markdown del hijo como el informe publicable; una seam o proveedor faltante falla de forma evidente. Los fallos de obtención de secciones suplementarias se anotan en la salida sin hacer fallar el trabajo. Los avisos de finalización llegan a la sesión iniciadora a través del consumidor `dsh-tool-jobs` del host; el modelo lee el informe mediante la herramienta existente `job_output` y lo publica con `review_post` — requiere aprobación.
|
|
194
209
|
- **Visible para el modelo ⇔ registrado.** El plugin no añade **ningún tipo de evento de sesión personalizado**. Los tipos de eventos fuera del repositorio no están en `KNOWN_SESSION_EVENT_TYPES` del host, por lo que un evento obligatorio desconocido haría ilegible el registro de sesión tras eliminar el plugin (el host difiere deliberadamente una superficie de registro para plugins externos). Por tanto, todo el contenido visible para el modelo fluye a través de superficies registradas por el host: valores canónicos `tool/result`, avisos `user/message` mediante `agent.inject`/`agent.followup`, el par de ciclo de vida `command/run` + `command/done` y el par de auditoría `approval/asked` + `approval/decided`.
|
|
195
210
|
- **Presentadores puros.** `presentCall`/`presentResult` son funciones puras de `args` (+ el `result.meta` persistido), idénticas en transmisión en vivo y en reproducción del registro. La creación de una PR muestra una tarjeta genérica con la URL de la PR.
|
|
@@ -201,7 +216,7 @@ Validado con Schemastery en el momento de carga (falla de forma evidente). Sobre
|
|
|
201
216
|
- `/pr create` nunca hace commit ni push por sí mismo; con `autoCommit: true`, el modelo realiza esas escrituras a través de la propia puerta de aprobación de la herramienta bash. dsh-github **no** gestiona la identidad de git (tarea de dsh-git-identity) ni los worktrees (tarea de dsh-worktree).
|
|
202
217
|
- El trabajo de revisión no realiza escrituras: lee un diff y guarda un informe en la memoria del proceso; solo `review_post` publica, tras la aprobación.
|
|
203
218
|
- Los comentarios publicados interpolan nombres de archivo derivados del diff, que son contenido de repositorio no confiable: `formatPostBody` escapa las comillas invertidas y escapa en HTML los nombres de archivo para que una PR hostil no pueda inyectar Markdown en el comentario de revisión.
|
|
204
|
-
-
|
|
219
|
+
- El contenido de archivos leído por `gh_file` y los cuerpos de issues/PRs, los comentarios y los resultados de búsqueda leídos de GitHub son contenido externo no confiable que entra en el contexto del modelo — la misma contrapartida inherente que la obtención web; el plugin los marca como contenido externo en sus representaciones.
|
|
205
220
|
- Límites de velocidad: los 429 se reintentan con retroceso y la cuota restante se muestra al modelo en cada resultado, incluidos los fallos.
|
|
206
221
|
|
|
207
222
|
## ⚠️ Limitaciones conocidas
|
|
@@ -210,7 +225,7 @@ Validado con Schemastery en el momento de carga (falla de forma evidente). Sobre
|
|
|
210
225
|
- **Analizador estático por defecto** — reglas deterministas (`src/review.ts`), cero tokens, reproducible. `reviewMode: "model"` delega el diff limitado a un subagente de un solo uso a través de la seam `subagents` del host para una revisión por LLM (consume tokens; requiere la seam y un proveedor registrado).
|
|
211
226
|
- **Trabajos y registros locales al proceso** — el informe de revisión vive en la memoria del plugin indexado por el id del trabajo, coincidiendo con el ciclo de vida del registro de trabajos del host; el mapa de registros está limitado por `maxReviewRecords` (los registros finalizados más antiguos se eliminan primero).
|
|
212
227
|
- **Las dist-tags `latest` de npm están obsoletas** — el plugin declara rangos de pares `^0.1.0-rc.5` para resolverse contra el cierre de perfil que proporciona `dsh-base`, y fija `0.1.0-rc.6` para desarrollo. Nunca instales con un simple `npm i @deepseek-ai/dsh-tools`.
|
|
213
|
-
- **CI / GitHub Action** (`
|
|
228
|
+
- **CI / GitHub Action** — incluido en este repositorio (v0.6.0): una acción compuesta (`action.yml`) que revisa PRs, arregla CI y escribe el informe; un bot de revisión por sondeo con comentarios inline idempotentes; y una puerta de status-check. Todas las escrituras siguen sujetas a aprobación.
|
|
214
229
|
|
|
215
230
|
## 🧪 Desarrollo
|
|
216
231
|
|
|
@@ -220,11 +235,13 @@ pnpm test # vitest: config, credentials, 429/retry, tools, commands, jo
|
|
|
220
235
|
pnpm typecheck
|
|
221
236
|
pnpm build # tsc → lib/ (noEmitOnError)
|
|
222
237
|
pnpm pack # installable tarball
|
|
223
|
-
pnpm run check:readmes # cross-checks TOC anchors in all 5 READMEs
|
|
238
|
+
pnpm run check:readmes # cross-checks TOC anchors, tools, and config keys in all 5 READMEs
|
|
224
239
|
```
|
|
225
240
|
|
|
226
241
|
Las pruebas simulan la API de GitHub, la CLI `gh` y git mediante runners inyectados — sin red, sin credenciales reales. `test/security.test.ts` verifica que la cadena del token nunca aparece en ninguna salida visible para el modelo o para el humano. `test/e2e.test.ts` contiene pruebas de humo optativas de la API real que se omiten automáticamente salvo que `DSH_GITHUB_E2E_TOKEN` esté definido (solo endpoints de solo lectura).
|
|
227
242
|
|
|
243
|
+
Para ejercitar la acción compuesta localmente, ejecuta `node scripts/local-test.mjs --owner-repo you/repo --pr 42` (consulta `--help` para todas las opciones). El simulador fija explícitamente `DSH_HOME`, `DSH_PROFILE_DIR`, `RUNNER_TEMP` y el directorio de salida dentro de un sandbox nuevo del directorio temporal del sistema para cada paso — tu dsh home real nunca se lee ni se escribe, incluso si existe un `DSH_HOME` de ámbito máquina — y reproduce los pasos install → prepare → run headless → post de `action.yml`. `action-patch.mjs` y `action-post.mjs` se niegan a ejecutarse fuera de un runner de GitHub Actions, de modo que la acción no puede escribir overlays de perfil ni informes en ubicaciones locales desconocidas.
|
|
244
|
+
|
|
228
245
|
## 🗂 Estructura del repositorio
|
|
229
246
|
|
|
230
247
|
```
|
|
@@ -237,7 +254,7 @@ src/git.ts read-only git inspection + origin parsing for any API host
|
|
|
237
254
|
src/review.ts deterministic diff analyzer + sanitized comment drafting
|
|
238
255
|
src/jobs.ts github-review background job producer (metadata + diff + CI + comments)
|
|
239
256
|
src/approval-gate.ts tools/pre-execute ask/deny gate with write previews
|
|
240
|
-
src/tools.ts the
|
|
257
|
+
src/tools.ts the twelve model-facing tools
|
|
241
258
|
src/commands.ts /pr, /review, /issue
|
|
242
259
|
src/present.ts pure UI-card presenters
|
|
243
260
|
test/ vitest suite + mock host scaffolding + opt-in e2e smoke
|
package/README.hi.md
CHANGED
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
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 गुप्त रहता है।
|
|
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 खोल सकता है, PRs को merge और update कर सकता है, repo metadata और files पढ़ सकता है, issues पर comment कर सकता है और उन्हें close कर सकता है, और खोज सकता है** — जबकि हर write को एक मानव अनुमोदित (approve) करता है और token गुप्त रहता है।
|
|
28
28
|
|
|
29
|
-
- 🛠 **
|
|
29
|
+
- 🛠 **12 टूल्स** — `pr_create` · `pr_merge` · `pr_update` · `gh_review` · `review_post` · `gh_issue` · `issue_open` · `issue_comment` · `issue_close` · `gh_search` · `gh_repo` · `gh_file`, सभी `defineTool` के ज़रिए canonical-JSON
|
|
30
30
|
- ⌨️ **3 कमांड परिवार** — `/pr create` · `/review` (start/stop/post) · `/issue open`
|
|
31
|
+
- 🔀 **पूरा PR lifecycle** — बनाएँ → समीक्षा करें → update करें (title/body/state/base branch) → merge करें (merge/squash/rebase, वैकल्पिक head-branch deletion)
|
|
31
32
|
- 📝 **Inline reviews** — `review_post` एक summary comment या PR head commit के विरुद्ध line-anchored review comments प्रकाशित करता है
|
|
32
33
|
- 🔒 **Approval-नियंत्रित writes** — हर GitHub write `ctx.approval` से होकर गुजरता है (डिफ़ॉल्ट `ask`, fail-closed); approval reasons titles, body sizes, और comment overrides की पूर्व-झलक देते हैं
|
|
33
34
|
- 🗝 **Token गोपनीयता** — credentials seam → environment → `gh` CLI, प्रति operation resolved, कभी logs, events, renders, या errors में नहीं
|
|
@@ -60,8 +61,8 @@
|
|
|
60
61
|
# 1. install (npm registry — सबसे सरल; या नीचे दिया गया tarball channel इस्तेमाल करें)
|
|
61
62
|
dsh plugin --profile <name> add @perrylink/dsh-github
|
|
62
63
|
# tarball channel (registry की ज़रूरत नहीं):
|
|
63
|
-
pnpm pack
|
|
64
|
-
dsh plugin --profile <name> add ./dsh-github
|
|
64
|
+
# pnpm pack → dsh-github-<version>.tgz
|
|
65
|
+
# dsh plugin --profile <name> add ./dsh-github-<version>.tgz
|
|
65
66
|
|
|
66
67
|
# 2. configure a GitHub token (recommended: the credentials seam)
|
|
67
68
|
# $DSH_HOME/.credentials.yaml
|
|
@@ -81,9 +82,13 @@ dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz
|
|
|
81
82
|
| क्षेत्र | आपको क्या मिलता है |
|
|
82
83
|
|---|---|
|
|
83
84
|
| **PR बनाएँ** | `/pr create [title]` git स्थिति (branch, changed files, commits ahead) पढ़ता है और एजेंट को एक draft देता है; `pr_create` PR खोलता है और उसका URL लौटाता है |
|
|
85
|
+
| **PR update करें** | `pr_update` title, body, state, या base branch को संपादित करता है — हर दूसरे write की तरह approval-नियंत्रित |
|
|
86
|
+
| **PR merge करें** | `pr_merge` `merge`/`squash`/`rebase` से merge करता है, वैकल्पिक commit title/message और merge के बाद head-branch deletion |
|
|
84
87
|
| **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
88
|
| **समीक्षाएँ पोस्ट करें** | `review_post` एक aggregated issue-level comment (`mode: "summary"`, डिफ़ॉल्ट) या PR head commit पर line-anchored review comments (`mode: "inline"`) प्रकाशित करता है; एक `body` override model को पहले comment को निखारने देता है — मानवीय approval के बाद |
|
|
86
89
|
| **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 को सौंपता है |
|
|
90
|
+
| **Repos पढ़ें** | `gh_repo` repository metadata पढ़ता है: description, default branch, visibility, stars, forks, open issues, language, license, topics |
|
|
91
|
+
| **Files पढ़ें** | `gh_file` किसी branch/tag/commit पर एक file पढ़ता है, base64 decoding और configurable cap के साथ; directories एक structured error लौटाती हैं |
|
|
87
92
|
| **Issues पढ़ें** | `gh_issue` lists / gets / comments करता है; listings में pull requests `kind: "pr"` के रूप में marked होते हैं |
|
|
88
93
|
| **Issues प्रबंधित करें** | `issue_open` बनाता है, `issue_comment` comment करता है (PRs पर भी काम करता है), `issue_close` एक optional state reason के साथ close करता है — सभी approval-नियंत्रित |
|
|
89
94
|
| **खोजें** | `gh_search` GitHub search syntax से issues और pull requests को query करता है, अलग search quota दिखाता है |
|
|
@@ -99,7 +104,7 @@ dsh plugin --profile <name> add ./dsh-github-0.4.0.tgz
|
|
|
99
104
|
| चैनल | कमांड | नोट्स |
|
|
100
105
|
|---|---|---|
|
|
101
106
|
| **npm registry** | `dsh plugin --profile <name> add @perrylink/dsh-github` | npm पर प्रकाशित — सबसे सरल channel |
|
|
102
|
-
| **npm tarball** | `dsh plugin --profile <name> add ./dsh-github
|
|
107
|
+
| **npm tarball** | `dsh plugin --profile <name> add ./dsh-github-<version>.tgz` | built `lib/` के साथ आता है — कोई build permission आवश्यक नहीं |
|
|
103
108
|
| **git source** | `dsh plugin --profile <name> add "github:PerryLink/dsh-github#<sha>"` | `prepare` + `allowBuilds` चाहिए (नीचे देखें); commit को pin करें |
|
|
104
109
|
| **local link** | `pnpm link --dir .` then `dsh plugin add @perrylink/dsh-github` | विकास |
|
|
105
110
|
|
|
@@ -131,21 +136,30 @@ Load time पर Schemastery-सत्यापित (fail loud)। Profile क
|
|
|
131
136
|
| `maxComments` | `20` | `gh_review` द्वारा सूचीबद्ध PR comments की सीमा |
|
|
132
137
|
| `reviewJobTimeoutMs` | `600000` | एक background review job की समय-सीमा (`timeout` के साथ fail होता है) |
|
|
133
138
|
| `maxReviewRecords` | `50` | in-memory review-job records की सीमा; सबसे पुराने settled records पहले evict होते हैं |
|
|
139
|
+
| `maxFileChars` | `12000` | `gh_file` द्वारा पढ़े गए file contents की character सीमा |
|
|
140
|
+
| `maxFindings` | `50` | प्रति review analyzer findings की सीमा |
|
|
141
|
+
| `maxLineLength` | `300` | line length जिसके पार analyzer long-line finding flag करता है |
|
|
134
142
|
| `reviewMode` | `static` | Review engine: `static` (deterministic analyzer) या `model` (host के `subagents` seam के ज़रिए one-shot subagent; seam अनुपस्थित होने पर fail loud) |
|
|
135
143
|
| `modelReviewProvider` | — | `reviewMode: "model"` के लिए subagent provider नाम; डिफ़ॉल्ट रूप से पहले registered provider का उपयोग |
|
|
136
144
|
| `maxRetries` | `3` | प्रति request 429 retry प्रयास |
|
|
137
145
|
| `retryBaseMs` | `500` | Retry backoff आधार (प्रति प्रयास दोगुना) |
|
|
138
146
|
| `retryMaxWaitMs` | `60000` | Retry backoff की अधिकतम सीमा |
|
|
147
|
+
| `requestTimeoutMs` | `30000` | प्रति request का hard timeout; exceed होने पर fetch abort |
|
|
139
148
|
| `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 से पहले अस्वीकार |
|
|
149
|
+
| `allowedActions` | `['pr.create','pr.merge','pr.update','review.post','issue.create','issue.comment','issue.close','ci.run']` | Write-action whitelist; बाकी सब approval से पहले अस्वीकार |
|
|
141
150
|
| `workspaceDir` | process cwd | read-only git inspection के लिए working directory |
|
|
151
|
+
| `ci` | `{ enabled: false, … }` | CI integration section: polling review bot, status-check gate, और one-shot `ci_run` tool (सभी `ci.*` keys इसी में हैं) |
|
|
142
152
|
|
|
143
153
|
## 🛠 टूल्स
|
|
144
154
|
|
|
145
155
|
| टूल | प्रकार | पैरामीटर | लौटाता है |
|
|
146
156
|
|---|---|---|---|
|
|
147
157
|
| `pr_create` | write | `title*`, `body?`, `base?`, `head?`, `draft?`, `ownerRepo?` | `{status:'created', url, number, title, state, draft, base, head, rateLimit}` या structured error |
|
|
158
|
+
| `pr_merge` | write | `pr*` (number / `#n` / `o/r#n` / URL), `mergeMethod?`, `commitTitle?`, `commitMessage?`, `deleteBranch?` | `{status:'merged', merged, sha?, message, url, branchDeleted, branchDeleteNote?, rateLimit}` या structured error |
|
|
159
|
+
| `pr_update` | write | `pr*` (number / `#n` / `o/r#n` / URL), `title?`, `body?`, `state?` (`open`/`closed`), `base?` | `{status:'updated', url, number, title, state, base, rateLimit}` या structured error |
|
|
148
160
|
| `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 |
|
|
161
|
+
| `gh_repo` | read | `ownerRepo?` | `{repo, description, defaultBranch, visibility, stars, forks, openIssues, language, license, topics, url, updatedAt, rateLimit}` या structured error |
|
|
162
|
+
| `gh_file` | read | `ownerRepo?`, `path*`, `ref?`, `maxChars?` | `{repo, path, ref, size, truncated, content, sha, url, rateLimit}` या structured error |
|
|
149
163
|
| `gh_issue` | read | `action*` (`list`/`get`/`comments`), `ownerRepo?`, `issueNumber?`, `state?`, `limit?` | normalized items (हर एक `kind: issue/pr/comment` marked) + rate limit |
|
|
150
164
|
| `review_post` | write | `jobId*`, `mode?` (`summary`/`inline`), `body?` | `{status:'posted', mode, url, commentId?, reviewId?, findings, rateLimit}` या structured error |
|
|
151
165
|
| `issue_open` | write | `title*`, `body?`, `labels?`, `ownerRepo?` | `{status:'created', url, number, title, rateLimit}` या structured error |
|
|
@@ -176,8 +190,9 @@ Load time पर Schemastery-सत्यापित (fail loud)। Profile क
|
|
|
176
190
|
/review ───┼──► ctx.jobs.start("github-review") ──► job │
|
|
177
191
|
/issue ────┼──► agent.followup │
|
|
178
192
|
│ │
|
|
179
|
-
मॉडल ─── pr_create /
|
|
180
|
-
|
|
193
|
+
मॉडल ─── pr_create / pr_merge / pr_update / gh_review / │
|
|
194
|
+
review_post / gh_issue / issue_open / issue_comment / │
|
|
195
|
+
issue_close / gh_search / gh_repo / gh_file │
|
|
181
196
|
(defineTool, canonical JSON only) │
|
|
182
197
|
│ │
|
|
183
198
|
└───────┬───────────────┬───────────────┬───────┘
|
|
@@ -189,7 +204,7 @@ Load time पर Schemastery-सत्यापित (fail loud)। Profile क
|
|
|
189
204
|
```
|
|
190
205
|
|
|
191
206
|
- **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
|
|
207
|
+
- **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, merge methods, और 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
208
|
- **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
209
|
- **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
210
|
- **Pure presenters.** `presentCall`/`presentResult` `args` (+ persisted `result.meta`) के pure functions हैं, जो live streaming और log replay पर समान रहते हैं। PR creation PR URL के साथ एक generic card दिखाता है।
|
|
@@ -201,7 +216,7 @@ Load time पर Schemastery-सत्यापित (fail loud)। Profile क
|
|
|
201
216
|
- `/pr create` कभी खुद commit या push नहीं करता; `autoCommit: true` के साथ model वे writes bash tool के अपने approval gate से करता है। dsh-github git identity (dsh-git-identity का काम) या worktrees (dsh-worktree का काम) का प्रबंधन **नहीं** करता।
|
|
202
217
|
- Review job कोई write नहीं करता: यह एक diff पढ़ता है और रिपोर्ट को process memory में रखता है; केवल `review_post` approval के बाद प्रकाशित करता है।
|
|
203
218
|
- 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 करता है।
|
|
219
|
+
- `gh_file` द्वारा पढ़े गए file contents और GitHub से पढ़े गए issue/PR bodies, comments, और search results external untrusted content हैं जो model context में प्रवेश करते हैं — web fetching जैसा ही inherent tradeoff; plugin उन्हें अपने renders में external content के रूप में mark करता है।
|
|
205
220
|
- Rate limits: 429s को backoff के साथ retry किया जाता है और शेष quota हर result पर (failures सहित) model को दिखाया जाता है।
|
|
206
221
|
|
|
207
222
|
## ⚠️ ज्ञात सीमाएँ
|
|
@@ -210,7 +225,7 @@ Load time पर Schemastery-सत्यापित (fail loud)। Profile क
|
|
|
210
225
|
- **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
226
|
- **Jobs और records process-local हैं** — review report plugin memory में job id के आधार पर रहता है, जो host job registry के lifetime से मेल खाता है; record map `maxReviewRecords` से capped है (सबसे पुराने settled records पहले evict होते हैं)।
|
|
212
227
|
- **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** (
|
|
228
|
+
- **CI / GitHub Action** — इसी repository में शामिल है (v0.6.0): एक composite action (`action.yml`) जो PRs की समीक्षा करती है, CI ठीक करती है, और report लिखती है; idempotent inline comments वाला polling review bot; और एक status-check gate। हर write approval-gated रहता है।
|
|
214
229
|
|
|
215
230
|
## 🧪 विकास
|
|
216
231
|
|
|
@@ -220,11 +235,13 @@ pnpm test # vitest: config, credentials, 429/retry, tools, commands, jo
|
|
|
220
235
|
pnpm typecheck
|
|
221
236
|
pnpm build # tsc → lib/ (noEmitOnError)
|
|
222
237
|
pnpm pack # installable tarball
|
|
223
|
-
pnpm run check:readmes # cross-checks TOC anchors in all 5 READMEs
|
|
238
|
+
pnpm run check:readmes # cross-checks TOC anchors, tools, and config keys in all 5 READMEs
|
|
224
239
|
```
|
|
225
240
|
|
|
226
241
|
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 हैं जो `DSH_GITHUB_E2E_TOKEN` सेट न होने पर खुद को skip कर लेते हैं (केवल read-only endpoints)।
|
|
227
242
|
|
|
243
|
+
Composite action को locally आज़माने के लिए `node scripts/local-test.mjs --owner-repo you/repo --pr 42` चलाएँ (सभी options के लिए `--help` देखें)। Simulator हर spawned step के लिए `DSH_HOME`, `DSH_PROFILE_DIR`, `RUNNER_TEMP`, और output directory को system temp directory के एक नए sandbox में स्पष्ट रूप से fix करता है — आपका real dsh home कभी पढ़ा या लिखा नहीं जाता, चाहे machine-scope `DSH_HOME` मौजूद हो — और `action.yml` के install → prepare → headless run → post चरणों को replay करता है। `action-patch.mjs` और `action-post.mjs` GitHub Actions runner के बाहर चलने से मना कर देते हैं, इसलिए action किसी अज्ञात local location में profile overlay या report नहीं लिख सकता।
|
|
244
|
+
|
|
228
245
|
## 🗂 रिपॉज़िटरी संरचना
|
|
229
246
|
|
|
230
247
|
```
|
|
@@ -237,7 +254,7 @@ src/git.ts read-only git inspection + origin parsing for any API host
|
|
|
237
254
|
src/review.ts deterministic diff analyzer + sanitized comment drafting
|
|
238
255
|
src/jobs.ts github-review background job producer (metadata + diff + CI + comments)
|
|
239
256
|
src/approval-gate.ts tools/pre-execute ask/deny gate with write previews
|
|
240
|
-
src/tools.ts the
|
|
257
|
+
src/tools.ts the twelve model-facing tools
|
|
241
258
|
src/commands.ts /pr, /review, /issue
|
|
242
259
|
src/present.ts pure UI-card presenters
|
|
243
260
|
test/ vitest suite + mock host scaffolding + opt-in e2e smoke
|
package/README.md
CHANGED
|
@@ -23,10 +23,11 @@
|
|
|
23
23
|
|
|
24
24
|
---
|
|
25
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.
|
|
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, merge and update PRs, read repo metadata and files, comment on and close issues, and search** — while a human approves every write and the token stays secret.
|
|
27
27
|
|
|
28
|
-
- 🛠 **
|
|
28
|
+
- 🛠 **12 tools** — `pr_create` · `pr_merge` · `pr_update` · `gh_review` · `review_post` · `gh_issue` · `issue_open` · `issue_comment` · `issue_close` · `gh_search` · `gh_repo` · `gh_file`, all canonical-JSON via `defineTool`
|
|
29
29
|
- ⌨️ **3 command families** — `/pr create` · `/review` (start/stop/post) · `/issue open`
|
|
30
|
+
- 🔀 **Full PR lifecycle** — create → review → update (title/body/state/base) → merge (merge/squash/rebase, optional head-branch delete)
|
|
30
31
|
- 📝 **Inline reviews** — `review_post` posts either one summary comment or line-anchored review comments against the PR head commit
|
|
31
32
|
- 🔒 **Approval-gated writes** — every GitHub write goes through `ctx.approval` (default `ask`, fail-closed); approval reasons preview titles, body sizes, and comment overrides
|
|
32
33
|
- 🗝 **Token secrecy** — credentials seam → environment → `gh` CLI, resolved per operation, never in logs, events, renders, or errors
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
- [Repository layout](#🗂-repository-layout)
|
|
53
54
|
- [Topics](#🏷-topics)
|
|
54
55
|
- [License](#license)
|
|
56
|
+
- [PerryLink DSH Plugin Family](#perrylink-dsh-plugin-family)
|
|
55
57
|
|
|
56
58
|
## 🚀 Quick start
|
|
57
59
|
|
|
@@ -59,8 +61,8 @@
|
|
|
59
61
|
# 1. install (npm registry — simplest; or use the tarball channel below)
|
|
60
62
|
dsh plugin --profile <name> add @perrylink/dsh-github
|
|
61
63
|
# tarball channel (no registry needed):
|
|
62
|
-
# pnpm pack → dsh-github
|
|
63
|
-
# dsh plugin --profile <name> add ./dsh-github
|
|
64
|
+
# pnpm pack → dsh-github-<version>.tgz
|
|
65
|
+
# dsh plugin --profile <name> add ./dsh-github-<version>.tgz
|
|
64
66
|
|
|
65
67
|
# 2. configure a GitHub token (recommended: the credentials seam)
|
|
66
68
|
# $DSH_HOME/.credentials.yaml
|
|
@@ -80,9 +82,13 @@ Verify: `dsh --profile <name> --dump-config` must show the `# == dsh-github` sec
|
|
|
80
82
|
| Area | What you get |
|
|
81
83
|
|---|---|
|
|
82
84
|
| **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 |
|
|
85
|
+
| **Update PRs** | `pr_update` edits title, body, state, or target branch — approval-gated like every other write |
|
|
86
|
+
| **Merge PRs** | `pr_merge` merges with `merge`/`squash`/`rebase`, optional commit title/message and head-branch deletion after the merge |
|
|
83
87
|
| **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
88
|
| **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
89
|
| **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 |
|
|
90
|
+
| **Read repos** | `gh_repo` reads repository metadata: description, default branch, visibility, stars, forks, open issues, language, license, topics |
|
|
91
|
+
| **Read files** | `gh_file` reads one file at a branch/tag/commit with base64 decoding and a configurable cap; directories report a structured error |
|
|
86
92
|
| **Read issues** | `gh_issue` lists / gets / comments; pull requests in listings are marked `kind: "pr"` |
|
|
87
93
|
| **Manage issues** | `issue_open` creates, `issue_comment` comments (also works on PRs), `issue_close` closes with an optional state reason — all approval-gated |
|
|
88
94
|
| **Search** | `gh_search` queries issues and pull requests with GitHub search syntax, surfacing the separate search quota |
|
|
@@ -98,7 +104,7 @@ Four documented channels — pick one.
|
|
|
98
104
|
| Channel | Command | Notes |
|
|
99
105
|
|---|---|---|
|
|
100
106
|
| **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
|
|
107
|
+
| **npm tarball** | `dsh plugin --profile <name> add ./dsh-github-<version>.tgz` | Ships with `lib/` built — no build permission |
|
|
102
108
|
| **git source** | `dsh plugin --profile <name> add "github:PerryLink/dsh-github#<sha>"` | Needs `prepare` + `allowBuilds` (see below); pin the commit |
|
|
103
109
|
| **local link** | `pnpm link --dir .` then `dsh plugin add @perrylink/dsh-github` | Development |
|
|
104
110
|
|
|
@@ -132,21 +138,30 @@ Schemastery-validated at load time (fail loud). Override any key in the profile'
|
|
|
132
138
|
| `maxComments` | `20` | Cap for PR comments listed by `gh_review` |
|
|
133
139
|
| `reviewJobTimeoutMs` | `600000` | Deadline for one background review job (fails with `timeout`) |
|
|
134
140
|
| `maxReviewRecords` | `50` | Cap for in-memory review-job records; oldest settled records evict first |
|
|
141
|
+
| `maxFileChars` | `12000` | Character cap for file contents read by `gh_file` |
|
|
142
|
+
| `maxFindings` | `50` | Cap for analyzer findings per review |
|
|
143
|
+
| `maxLineLength` | `300` | Line length beyond which the analyzer flags a long-line finding |
|
|
135
144
|
| `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
145
|
| `modelReviewProvider` | — | Subagent provider name for `reviewMode: "model"`; defaults to the first registered provider |
|
|
137
146
|
| `maxRetries` | `3` | 429 retry attempts per request |
|
|
138
147
|
| `retryBaseMs` | `500` | Retry backoff base (doubles per attempt) |
|
|
139
148
|
| `retryMaxWaitMs` | `60000` | Retry backoff ceiling |
|
|
149
|
+
| `requestTimeoutMs` | `30000` | Hard per-request timeout; aborts the fetch when exceeded |
|
|
140
150
|
| `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 |
|
|
151
|
+
| `allowedActions` | `['pr.create','pr.merge','pr.update','review.post','issue.create','issue.comment','issue.close','ci.run']` | Write-action whitelist; anything else is denied before approval |
|
|
142
152
|
| `workspaceDir` | process cwd | Working directory for read-only git inspection |
|
|
153
|
+
| `ci` | `{ enabled: false, … }` | CI integration section: polling review bot, status-check gate, and the one-shot `ci_run` tool (all `ci.*` keys live inside it) |
|
|
143
154
|
|
|
144
155
|
## 🛠 Tools
|
|
145
156
|
|
|
146
157
|
| Tool | Kind | Parameters | Returns |
|
|
147
158
|
|---|---|---|---|
|
|
148
159
|
| `pr_create` | write | `title*`, `body?`, `base?`, `head?`, `draft?`, `ownerRepo?` | `{status:'created', url, number, title, state, draft, base, head, rateLimit}` or structured error |
|
|
160
|
+
| `pr_merge` | write | `pr*` (number / `#n` / `o/r#n` / URL), `mergeMethod?`, `commitTitle?`, `commitMessage?`, `deleteBranch?` | `{status:'merged', merged, sha?, message, url, branchDeleted, branchDeleteNote?, rateLimit}` or structured error |
|
|
161
|
+
| `pr_update` | write | `pr*` (number / `#n` / `o/r#n` / URL), `title?`, `body?`, `state?` (`open`/`closed`), `base?` | `{status:'updated', url, number, title, state, base, rateLimit}` or structured error |
|
|
149
162
|
| `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 |
|
|
163
|
+
| `gh_repo` | read | `ownerRepo?` | `{repo, description, defaultBranch, visibility, stars, forks, openIssues, language, license, topics, url, updatedAt, rateLimit}` or structured error |
|
|
164
|
+
| `gh_file` | read | `ownerRepo?`, `path*`, `ref?`, `maxChars?` | `{repo, path, ref, size, truncated, content, sha, url, rateLimit}` or structured error |
|
|
150
165
|
| `gh_issue` | read | `action*` (`list`/`get`/`comments`), `ownerRepo?`, `issueNumber?`, `state?`, `limit?` | normalized items (each marked `kind: issue/pr/comment`) + rate limit |
|
|
151
166
|
| `review_post` | write | `jobId*`, `mode?` (`summary`/`inline`), `body?` | `{status:'posted', mode, url, commentId?, reviewId?, findings, rateLimit}` or structured error |
|
|
152
167
|
| `issue_open` | write | `title*`, `body?`, `labels?`, `ownerRepo?` | `{status:'created', url, number, title, rateLimit}` or structured error |
|
|
@@ -177,8 +192,9 @@ Schemastery-validated at load time (fail loud). Override any key in the profile'
|
|
|
177
192
|
/review ───┼──► ctx.jobs.start("github-review") ──► job │
|
|
178
193
|
/issue ────┼──► agent.followup │
|
|
179
194
|
│ │
|
|
180
|
-
model ─── pr_create /
|
|
181
|
-
|
|
195
|
+
model ─── pr_create / pr_merge / pr_update / gh_review / │
|
|
196
|
+
review_post / gh_issue / issue_open / issue_comment / │
|
|
197
|
+
issue_close / gh_search / gh_repo / gh_file │
|
|
182
198
|
(defineTool, canonical JSON only) │
|
|
183
199
|
│ │
|
|
184
200
|
└───────┬───────────────┬───────────────┬───────┘
|
|
@@ -190,7 +206,7 @@ Schemastery-validated at load time (fail loud). Override any key in the profile'
|
|
|
190
206
|
```
|
|
191
207
|
|
|
192
208
|
- **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
|
|
209
|
+
- **Approval.** All writes flow through model tools. A `tools/pre-execute` waterfall listener returns `ask` for the seven 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, merge methods, 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
210
|
- **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
211
|
- **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
212
|
- **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.
|
|
@@ -202,7 +218,7 @@ Schemastery-validated at load time (fail loud). Override any key in the profile'
|
|
|
202
218
|
- `/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
219
|
- The review job performs no writes: it reads a diff and stores a report in process memory; only `review_post` publishes, after approval.
|
|
204
220
|
- 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
|
-
-
|
|
221
|
+
- File contents read by `gh_file` and 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
222
|
- Rate limits: 429s are retried with backoff and the remaining quota is surfaced to the model on every result, including failures.
|
|
207
223
|
|
|
208
224
|
## ⚠️ Known limitations
|
|
@@ -211,7 +227,7 @@ Schemastery-validated at load time (fail loud). Override any key in the profile'
|
|
|
211
227
|
- **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
228
|
- **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
229
|
- **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** (`
|
|
230
|
+
- **CI / GitHub Action** — ships in this repository (v0.6.0): a composite action (`action.yml`) that reviews PRs, fixes CI, and writes the report; a polling review bot with idempotent inline comments; and a status-check gate. Every write stays approval-gated.
|
|
215
231
|
|
|
216
232
|
## 🧪 Development
|
|
217
233
|
|
|
@@ -221,11 +237,13 @@ pnpm test # vitest: config, credentials, 429/retry, tools, commands, jo
|
|
|
221
237
|
pnpm typecheck
|
|
222
238
|
pnpm build # tsc → lib/ (noEmitOnError)
|
|
223
239
|
pnpm pack # installable tarball
|
|
224
|
-
pnpm run check:readmes # cross-checks TOC anchors in all 5 READMEs
|
|
240
|
+
pnpm run check:readmes # cross-checks TOC anchors, tools, and config keys in all 5 READMEs
|
|
225
241
|
```
|
|
226
242
|
|
|
227
243
|
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 `DSH_GITHUB_E2E_TOKEN` is set (read-only endpoints only; the dedicated variable keeps the unit suite hermetic).
|
|
228
244
|
|
|
245
|
+
To exercise the composite action locally, run `node scripts/local-test.mjs --owner-repo you/repo --pr 42` (see `--help` for all options). The simulator hardcodes `DSH_HOME`, `DSH_PROFILE_DIR`, `RUNNER_TEMP`, and the output directory under a fresh system-temp sandbox for every spawned step — your real dsh home is never read or written, even when a machine-scope `DSH_HOME` exists — and replays the install → prepare → headless run → post steps of `action.yml`. `action-patch.mjs` and `action-post.mjs` refuse to run outside a GitHub Actions runner, so the action cannot write profile overlays or reports into unknown local locations.
|
|
246
|
+
|
|
229
247
|
## 🗂 Repository layout
|
|
230
248
|
|
|
231
249
|
```
|
|
@@ -238,7 +256,7 @@ src/git.ts read-only git inspection + origin parsing for any API host
|
|
|
238
256
|
src/review.ts deterministic diff analyzer + sanitized comment drafting
|
|
239
257
|
src/jobs.ts github-review background job producer (metadata + diff + CI + comments)
|
|
240
258
|
src/approval-gate.ts tools/pre-execute ask/deny gate with write previews
|
|
241
|
-
src/tools.ts the
|
|
259
|
+
src/tools.ts the twelve model-facing tools
|
|
242
260
|
src/commands.ts /pr, /review, /issue
|
|
243
261
|
src/present.ts pure UI-card presenters
|
|
244
262
|
test/ vitest suite + mock host scaffolding + opt-in e2e smoke
|
|
@@ -255,3 +273,25 @@ Recommended GitHub repository topics (set them in the repo settings — they pow
|
|
|
255
273
|
## License
|
|
256
274
|
|
|
257
275
|
[Apache License 2.0](LICENSE)
|
|
276
|
+
|
|
277
|
+
## PerryLink DSH Plugin Family
|
|
278
|
+
|
|
279
|
+
This project is one of the [15 DeepSeek Harness plugins](https://github.com/PerryLink) maintained by [PerryLink](https://github.com/PerryLink). If this one helps you, the others likely will too:
|
|
280
|
+
|
|
281
|
+
| Plugin | One-liner |
|
|
282
|
+
|---|---|
|
|
283
|
+
| [dsh-mcp-panel](https://github.com/PerryLink/dsh-mcp-panel) | Read-only MCP runtime panel: /mcp command + Settings tab with status, tools and errors |
|
|
284
|
+
| [dsh-doublecheck](https://github.com/PerryLink/dsh-doublecheck) | Engineering-discipline guard: requirements grill, test gates, adversary review |
|
|
285
|
+
| [dsh-background-agents](https://github.com/PerryLink/dsh-background-agents) | Durable background child agents with a Web UI sidebar, messaging and interrupt |
|
|
286
|
+
| [dsh-lsp-actions](https://github.com/PerryLink/dsh-lsp-actions) | LSP diagnostics, formatting, completion, code actions and rename over language servers |
|
|
287
|
+
| [dsh-output-styles](https://github.com/PerryLink/dsh-output-styles) | Claude Code outputStyles-equivalent runtime style switching |
|
|
288
|
+
| [dsh-checkpoint-rewind](https://github.com/PerryLink/dsh-checkpoint-rewind) | Claude Code /rewind-equivalent: snapshots, session forks, one-shot restore |
|
|
289
|
+
| [dsh-permission-rules](https://github.com/PerryLink/dsh-permission-rules) | Claude Code-style declarative allow/deny/ask permission rules with audit |
|
|
290
|
+
| [dsh-auto-review](https://github.com/PerryLink/dsh-auto-review) | Second-model auto-review on the approval chain, fail-closed by default |
|
|
291
|
+
| [dsh-memento](https://github.com/PerryLink/dsh-memento) | Approval-gated cross-session memory: ctx.memory seam + SQLite + memory tool |
|
|
292
|
+
| [dsh-skill-pack-security](https://github.com/PerryLink/dsh-skill-pack-security) | Security-audit skill pack: secret scan, dependency and supply-chain review |
|
|
293
|
+
| [dsh-session-pin](https://github.com/PerryLink/dsh-session-pin) | Pin sessions in the Web sidebar with durable ordering |
|
|
294
|
+
| [dsh-composer-history](https://github.com/PerryLink/dsh-composer-history) | Terminal-style input history for the web composer: arrows, Ctrl+R search |
|
|
295
|
+
| **[dsh-github](https://github.com/PerryLink/dsh-github)** | GitHub PR/issues integration for DSH, every write gated by approval |
|
|
296
|
+
| [dsh-plugin-guide](https://github.com/PerryLink/dsh-plugin-guide) | Plugin-development knowledge base as an on-demand agent skill |
|
|
297
|
+
| [dsh-claude-move](https://github.com/PerryLink/dsh-claude-move) | Migrate Claude Code sessions, memory, skills and CLAUDE.md into DSH |
|