@zhangj1164/dsh-github-issue 0.2.0 → 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.
- package/LICENSE +21 -21
- package/README.i18n.yaml +6 -6
- package/README.md +73 -3
- package/README.zh.md +73 -3
- package/cordis.patch.yml +12 -1
- package/lib/client.d.ts +2 -2
- package/lib/index.d.ts +249 -6
- package/lib/index.js +1049 -6
- package/lib/types.d.ts +131 -1
- package/package.json +11 -3
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 zhangj1164
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 zhangj1164
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.i18n.yaml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Bilingual-pair consistency record: the git blob hash of each
|
|
2
|
-
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
-
# after editing either side, bring the other along and re-record with:
|
|
4
|
-
# pnpm run verify-translation-pairing --write packages/github-issue/dsh-github-issue/README.md
|
|
5
|
-
README.md:
|
|
6
|
-
README.zh.md:
|
|
1
|
+
# Bilingual-pair consistency record: the git blob hash of each
|
|
2
|
+
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
|
3
|
+
# after editing either side, bring the other along and re-record with:
|
|
4
|
+
# pnpm run verify-translation-pairing --write packages/github-issue/dsh-github-issue/README.md
|
|
5
|
+
README.md: 8bea5576f968f66e8eadb75bf5d6da52c2501df0
|
|
6
|
+
README.zh.md: d52ed1b3284b6c2d5e62eb3c5615c3396734b9ef
|
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
English | [中文](README.zh.md)
|
|
4
4
|
|
|
5
|
-
GitHub issue generation and optimization service for DeepSeek Harness. Builds structured issue reports from telemetry analysis, constructs pre-filled issue-creation URLs,
|
|
5
|
+
GitHub issue generation and optimization service for DeepSeek Harness. Builds structured issue reports from telemetry analysis, constructs pre-filled issue-creation URLs, optimizes natural-language issue descriptions with the configured model, and closes the intake loop: filing the report through the GitHub API, listing the issues that carry the claim label, and handing one to a fresh Session on the first startup of the local day.
|
|
6
6
|
|
|
7
7
|
## Plugin
|
|
8
8
|
|
|
9
|
-
`GithubIssueService extends TypertRemoteService` with `static inject = ['llm']`. The service uses `ctx.get('llm')` for model calls and exposes
|
|
9
|
+
`GithubIssueService extends TypertRemoteService` with `static inject = ['llm']`. The service uses `ctx.get('llm')` for model calls and exposes seven Remote methods callable by the client UI.
|
|
10
10
|
|
|
11
11
|
| Config | Default | Meaning |
|
|
12
12
|
|---|---|---|
|
|
@@ -15,6 +15,22 @@ GitHub issue generation and optimization service for DeepSeek Harness. Builds st
|
|
|
15
15
|
| `prefillTruncationNote` | a Chinese note | Appended to the issue body when the URL had to be shortened, so the reader knows the body is partial. |
|
|
16
16
|
| `provider` | unset | Provider route for model calls. Unset follows the deployment's `agentDefaultModel` selection, so a deployment can pin issue generation from `cordis.yml` alone. |
|
|
17
17
|
| `model` | unset | Model id for model calls. Unset follows the same fallback as `provider`. |
|
|
18
|
+
| `tokenEnv` | `GITHUB_TOKEN` | Environment variable read for the GitHub token when `token` is unset. An empty name disables the lookup. |
|
|
19
|
+
| `token` | unset | Explicit GitHub token. Set it when the deployment manages secrets itself; it wins over the environment and the command. |
|
|
20
|
+
| `tokenCommand` | `gh auth token` | Command whose standard output is the token, run once per process only when neither `token` nor `tokenEnv` supplies one. The default reuses the credential the `gh` CLI already stores; set it to an empty string to disable the lookup. |
|
|
21
|
+
| `tokenCommandTimeoutMs` | `10000` | Deadline for `tokenCommand`, in milliseconds. |
|
|
22
|
+
| `apiBaseUrl` | `https://api.github.com` | GitHub REST origin. An Enterprise deployment sets its own `https://host/api/v3`. |
|
|
23
|
+
| `requestTimeoutMs` | `15000` | Deadline for one GitHub REST request, in milliseconds. |
|
|
24
|
+
| `claimLabel` | `ready-for-agent` | Label that marks an issue claimable by the intake loop. The repository's triage vocabulary owns the value; this field only names which label counts. |
|
|
25
|
+
| `maxIssuesPerRun` | `3` | Largest number of issues one intake pass may dispatch. |
|
|
26
|
+
| `autopilotEnabled` | `false` | Whether the host checks for claimable issues on its first startup of the local day. Off by default: opening a Session without being asked is a deployment decision. |
|
|
27
|
+
| `autopilotCwd` | empty | Working directory the dispatched Sessions own. Empty follows the host's default directory. |
|
|
28
|
+
| `autopilotPreset` | empty | Agent preset the dispatched Sessions run. Empty follows the deployment default. |
|
|
29
|
+
| `autopilotTimeZone` | empty | IANA zone "today" is measured in. Empty follows the host's own zone, so the user's local midnight starts a new day. |
|
|
30
|
+
| `autopilotPrompt` | the built-in template | Prompt handed to every dispatched Session. Placeholders `{number}`, `{title}`, `{url}`, `{body}`, and `{labels}` are replaced; an unknown placeholder stays visible. |
|
|
31
|
+
| `dispatchTaskDelaySeconds` | `1` | Seconds between registering a dispatch's automation task and its delivery, 1–3600. The Schedule service refuses a non-positive delay, so this cannot be `0`. |
|
|
32
|
+
|
|
33
|
+
**Settings-editable fields.** Eight of these fields — `repoUrl`, `claimLabel`, `maxIssuesPerRun`, `autopilotEnabled`, `autopilotCwd`, `autopilotPreset`, `autopilotTimeZone`, and `autopilotPrompt` — are declared `.volatile()`, which is what lets `@zhangj1164/dsh-client-ui-memo-settings` expose them in the Settings panel: `dsh-settings` projects only volatile fields, an accepted write lands in the profile's user layer, and the service reads each value where it is used instead of copying it at construction, so the change reaches the running process without a restart. `autopilotEnabled` is read by the `Service.init` startup check, so flipping it applies from the next host start. The remaining fields stay deployment-only.
|
|
18
34
|
|
|
19
35
|
## Remote methods
|
|
20
36
|
|
|
@@ -23,6 +39,12 @@ GitHub issue generation and optimization service for DeepSeek Harness. Builds st
|
|
|
23
39
|
| `generateReport(request)` | Calls the model with a built-in structuring prompt to produce a uniform GitHub issue report from telemetry failure analysis. Returns a `GithubIssueReport` with title, body, and labels. The request names the `pluginIds` it covers — one report spans a whole suite — plus the analysis window and, per failure group, the route, the last failure time, and the attempts that followed it; the per-group facts are optional, and a missing one is passed to the model as `not recorded` rather than omitted. |
|
|
24
40
|
| `prefilledIssueUrl(request)` | Builds a pre-filled GitHub issue-creation URL from a report. Validates the repo URL; returns `invalid-url` on failure. Shortens the body when the composed URL would exceed `maxPrefillUrlLength`, which is a budget the title and labels also spend and percent-encoding inflates, so the check is on the URL rather than the body alone. |
|
|
25
41
|
| `optimizeIssue(request)` | Rewrites a natural-language description into a structured issue following a pinned Markdown template. Returns `empty-input` for blank descriptions, `route-missing` when no route resolves, `llm-failure` when the model call failed. |
|
|
42
|
+
| `createIssue(request)` | Files the report through the GitHub REST API and returns the created issue's `{ number, url }`. The body is filed without its leading `## title` heading, because GitHub takes the title as its own field. |
|
|
43
|
+
| `listClaimableIssues(request)` | Lists the open issues carrying the claim label, excluding pull requests, which GitHub's issue endpoints also return. |
|
|
44
|
+
| `dispatchIssue(request)` | Creates one Session through the Session controller, names it, and registers the rendered prompt as a one-shot automation task on the Schedule service, which delivers it into that Session; returns its `sessionId`. A deployment that mounts no Schedule service admits the prompt directly instead. |
|
|
45
|
+
| `runIntake(request)` | Runs one pass: lists the claimable issues, skips those an earlier pass already dispatched, dispatches the rest, and records the local day durably. |
|
|
46
|
+
|
|
47
|
+
The intake methods report one stable failure code instead of a raw `fetch` error: `auth-missing`, `auth-failure`, `rate-limited`, `invalid-repo`, `invalid-request`, `http-failure`, `network-failure`, `session-unavailable`, or `dispatch-failed`. `auth-missing` is separate from `auth-failure` because no credential and a rejected credential are different deployment problems with different fixes.
|
|
26
48
|
|
|
27
49
|
## Model route
|
|
28
50
|
|
|
@@ -54,6 +76,50 @@ Both `generateReport` and `optimizeIssue` use built-in system prompts that pin a
|
|
|
54
76
|
|
|
55
77
|
`generateReport` receives the analysis window and, per failure group, the route, the last failure time, and how many attempts of the same action followed it. Its system prompt requires those facts to be stated, forbids proposing a mechanism the analysis does not evidence — sampling parameters, token budgets, timeouts, chunking, and response parsing are named as examples — and requires a fact the analysis does not carry to be written as `not recorded`. Writing that collection must be added is explicitly ruled out: a missing fact can be an older event as easily as a gap, and the report cannot tell which.
|
|
56
78
|
|
|
79
|
+
## Issue intake loop
|
|
80
|
+
|
|
81
|
+
The loop has three steps, and this plugin owns the last two. The user describes a problem in natural language, `optimizeIssue` turns it into the pinned report, and `createIssue` files it. That replaces the point where the loop used to stop: a pre-filled URL still required the user to open the form and press Submit, so nothing could pick the issue up automatically.
|
|
82
|
+
|
|
83
|
+
`runIntake` then reads the issues that carry `claimLabel` and hands each one to a fresh Session, registered as a one-shot automation task. The Session is created through the Session controller, so it gets the same preset and workspace policy as one the user opened in the Web. The work is handed over as a task on the Schedule service — the same board the Web's **Automation tasks** page lists — and that service delivers the rendered prompt into the Session when the task comes due. A task always belongs to an existing Session, so the Session is created first; a deployment that mounts no Schedule service (a non-Web composition) admits the prompt directly with the controller's `prompt` instead, which is the same durable path the Web prompt uses: it records the message with a user source and queues it on the Session's Agent, resolving (and resuming) that Agent itself. Naming the Session is best-effort: a deployment that mounts no title service still gets a working Session.
|
|
84
|
+
|
|
85
|
+
The credential is resolved once per process, in this order: `token`, then `tokenEnv`, then `tokenCommand`. The default command is `gh auth token`, so a machine already logged in to GitHub needs no extra secret; a deployment that manages secrets itself sets `token` and disables the command with an empty string. The token is never logged.
|
|
86
|
+
|
|
87
|
+
### First startup of the day
|
|
88
|
+
|
|
89
|
+
`autopilotEnabled` turns on one check per local day at host startup. The local day is read from durable storage-domain state, so a restart later the same day does nothing, and an issue that was already dispatched is never dispatched again — its Session exists, and a second one would duplicate the work. The day is committed only after the listing succeeded, so a pass that could not reach GitHub is retried on the next startup instead of being remembered as done. A pass whose every dispatch failed is retried the same way: the day is committed only when an issue reached a Session or nothing needed dispatching, because remembering a broken dispatch as a finished day is what made a failing startup look like a day with nothing to do. The listing failure, the dispatch failures, and an intake state that cannot be opened are each written as a telemetry error event, so the reason a check did nothing is readable afterwards.
|
|
90
|
+
|
|
91
|
+
The check needs durable state and refuses to run without one: without a memory of what it dispatched, a restart would open a second Session for the same issue. It is also off by default, because opening a Session without being asked is a deployment decision rather than something a plugin install does on its own.
|
|
92
|
+
|
|
93
|
+
`@deepseek-ai/dsh-storage-domain` is an optional peer. Installing this package alone keeps the service loading, filing, and listing issues; only the daily check stays off, and the import happens when the check is enabled rather than when the module loads. Every DSH installation ships that package, so the missing case is a defence rather than a supported configuration.
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
# your cordis.yml, or your own bundle's patch
|
|
97
|
+
- insert:
|
|
98
|
+
- id: github-issue
|
|
99
|
+
name: @zhangj1164/dsh-github-issue
|
|
100
|
+
config:
|
|
101
|
+
repoUrl: https://github.com/your-org/your-repo
|
|
102
|
+
autopilotEnabled: true
|
|
103
|
+
autopilotCwd: /path/to/your-repo
|
|
104
|
+
claimLabel: ready-for-agent
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The host must be running for the check to happen at all; a day with no startup is a day with no check. That is the intended behavior — the check is a startup hook, not a scheduler — and the Automation tasks page now lists each dispatch as the one-shot task it registers, with the delivered ones showing as ended.
|
|
108
|
+
|
|
109
|
+
A dispatched Session runs the repository workflow itself, and that workflow starts with `git fetch`. Under the default `workspace-write` sandbox a network command is blocked and raises an approval prompt that an unattended dispatch cannot answer, so a deployment that wants the loop to run on its own should pin the permission preset to `danger-full-access` in its own patch layer:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
- id: permission
|
|
113
|
+
config:
|
|
114
|
+
presets:
|
|
115
|
+
read-only: { sandbox: read-only, approval: ask }
|
|
116
|
+
workspace-write: { sandbox: workspace-write, approval: ask }
|
|
117
|
+
danger-full-access: { sandbox: danger-full-access, approval: never }
|
|
118
|
+
defaultPreset: danger-full-access
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
That is a deployment-wide choice: it applies to every new Session the host creates, not only to dispatched ones.
|
|
122
|
+
|
|
57
123
|
## Requirement mapping
|
|
58
124
|
|
|
59
125
|
- **Req 8** — `generateReport` turns telemetry failure analysis into a uniform GitHub issue report that correlates each failure group against the plugin's feature code.
|
|
@@ -61,6 +127,8 @@ Both `generateReport` and `optimizeIssue` use built-in system prompts that pin a
|
|
|
61
127
|
- **Req 10** — Packaged as a standalone DSH plugin: this package declares its own `dsh.bundle` with `cordis.patch.yml`, so a deployment can install it on its own and any UI plugin can reach it. See "Adopting this plugin" below.
|
|
62
128
|
- **Req 11** — `optimizeIssue` rewrites a natural-language description into a structured issue using the configured model and a built-in structuring prompt. The `ui-memo` package calls this directly for its "Add Issue" editor.
|
|
63
129
|
- **Req 12** — Reusable: the issue report template, the prefill URL builder, and the optimization prompt are all generic and not memo-specific.
|
|
130
|
+
- **Req 13** — `createIssue` files the optimized report through the GitHub API, so "format the issue" and "file the issue" are one step instead of a form the user must submit.
|
|
131
|
+
- **Req 14** — `runIntake` and the first-startup check close the loop: a claimable issue becomes a Session without the user opening it by hand, and a dispatched issue is never dispatched twice.
|
|
64
132
|
|
|
65
133
|
## Adopting this plugin
|
|
66
134
|
|
|
@@ -112,4 +180,6 @@ Every subpath resolves to the flat `lib/*.js` layout tsdown emits.
|
|
|
112
180
|
## Known Limitations
|
|
113
181
|
|
|
114
182
|
- **Model dependency** — `inject: ['llm']` means the service will not activate without an LLM provider.
|
|
115
|
-
- **
|
|
183
|
+
- **No browser UI of its own** — this package registers no model tool and ships no browser UI. Installing it on its own gives a deployment `ctx.get('githubIssue')` and nothing a user can see or click; the visible entry point is `@zhangj1164/dsh-client-ui-memo`'s issue editor, whose "File on GitHub" button and log-analysis action reach it over Remote. Treat it as a backend that a UI plugin consumes, not as a standalone feature.
|
|
184
|
+
- **Dispatch needs the Web composition** — `dispatchIssue` and `runIntake` read `ctx.get('sessionController')` and, when it exists, `ctx.get('schedule')`. A headless or SDK-only composition that mounts no Session controller reports `session-unavailable` and files or lists issues only; one that mounts a controller but no Schedule service still dispatches, admitting the prompt directly.
|
|
185
|
+
- **The first-startup check is a startup hook, not a scheduler** — it runs only when the host starts. A deployment that keeps the host running across midnight gets the check on the next start, not at midnight.
|
package/README.zh.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 中文
|
|
4
4
|
|
|
5
|
-
DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issue 报告、生成预填 issue 创建 URL,并使用配置的模型优化自然语言 issue
|
|
5
|
+
DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issue 报告、生成预填 issue 创建 URL,并使用配置的模型优化自然语言 issue 描述;同时打通接单闭环:经 GitHub API 直接建单、拉取带接单标签的 issue,并在本地日期首次启动时把其中一个交给新会话。
|
|
6
6
|
|
|
7
7
|
## 插件
|
|
8
8
|
|
|
9
|
-
`GithubIssueService extends TypertRemoteService`,`static inject = ['llm']`。服务通过 `ctx.get('llm')`
|
|
9
|
+
`GithubIssueService extends TypertRemoteService`,`static inject = ['llm']`。服务通过 `ctx.get('llm')` 调用模型,暴露七个可由客户端 UI 直接调用的 Remote 方法。
|
|
10
10
|
|
|
11
11
|
| 配置 | 默认值 | 含义 |
|
|
12
12
|
|---|---|---|
|
|
@@ -15,6 +15,22 @@ DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issu
|
|
|
15
15
|
| `prefillTruncationNote` | 一段中文说明 | URL 需要缩短时追加到 issue 正文末尾,让读者知道正文是部分内容。 |
|
|
16
16
|
| `provider` | 未设置 | 模型调用的 provider 路由。未设置时跟随部署的 `agentDefaultModel` 选择,因此部署方仅通过 `cordis.yml` 就能把 issue 生成固定到某条路由。 |
|
|
17
17
|
| `model` | 未设置 | 模型调用的 model id。未设置时与 `provider` 采用同一回退。 |
|
|
18
|
+
| `tokenEnv` | `GITHUB_TOKEN` | `token` 未设置时读取 GitHub token 的环境变量名。空名称表示停用该查找。 |
|
|
19
|
+
| `token` | 未设置 | 显式 GitHub token。由部署自行管理密钥时设置;优先级高于环境变量与命令。 |
|
|
20
|
+
| `tokenCommand` | `gh auth token` | 标准输出即 token 的命令。仅在 `token` 与环境变量都没有提供时执行,且每个进程最多一次。默认复用 `gh` CLI 已保存的凭据,因此已登录 GitHub 的机器无需额外密钥;设为空字符串可停用该查找。 |
|
|
21
|
+
| `tokenCommandTimeoutMs` | `10000` | `tokenCommand` 的超时(毫秒)。 |
|
|
22
|
+
| `apiBaseUrl` | `https://api.github.com` | GitHub REST 源。GitHub Enterprise 部署设置自己的 `https://host/api/v3`。 |
|
|
23
|
+
| `requestTimeoutMs` | `15000` | 单次 GitHub REST 请求的超时(毫秒)。 |
|
|
24
|
+
| `claimLabel` | `ready-for-agent` | 标记「可接单」的标签。取值的归属是仓库的分诊词汇表;本字段只决定哪个标签算数。 |
|
|
25
|
+
| `maxIssuesPerRun` | `3` | 一次接单最多派发的 issue 数。 |
|
|
26
|
+
| `autopilotEnabled` | `false` | 是否在本地日期首次启动时检查可接单 issue。默认关闭:未经请求就打开会话是部署决定,而不是插件安装时替用户做的决定。 |
|
|
27
|
+
| `autopilotCwd` | 空 | 派发会话的工作目录。空值跟随宿主默认目录。 |
|
|
28
|
+
| `autopilotPreset` | 空 | 派发会话使用的 agent preset。空值跟随部署默认。 |
|
|
29
|
+
| `autopilotTimeZone` | 空 | 判定「今天」所用的 IANA 时区。空值跟随宿主自身时区,因此用户的本地午夜才是新一天的开始。 |
|
|
30
|
+
| `autopilotPrompt` | 内置模板 | 交给每个派发会话的提示词模板。占位符 `{number}`、`{title}`、`{url}`、`{body}`、`{labels}` 会被替换;未知占位符保留原样可见。 |
|
|
31
|
+
| `dispatchTaskDelaySeconds` | `1` | 派发时登记的自动化任务从登记到送达的秒数,1–3600。Schedule 服务拒绝非正数延迟,所以不能是 `0`。 |
|
|
32
|
+
|
|
33
|
+
**可在设置页编辑的字段。** 其中八个——`repoUrl`、`claimLabel`、`maxIssuesPerRun`、`autopilotEnabled`、`autopilotCwd`、`autopilotPreset`、`autopilotTimeZone`、`autopilotPrompt`——声明了 `.volatile()`,这正是 `@zhangj1164/dsh-client-ui-memo-settings` 能把它们放进设置面板的原因:`dsh-settings` 只投影易变字段,被接受的写入落进 profile 的用户层,而服务在用到的位置读取每个值、不在构造时拷贝,因此改动无需重启就能到达运行中的进程。`autopilotEnabled` 由 `Service.init` 的启动检查读取,拨动它从下一次宿主启动生效。其余字段仍只属于部署层。
|
|
18
34
|
|
|
19
35
|
## Remote 方法
|
|
20
36
|
|
|
@@ -23,6 +39,12 @@ DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issu
|
|
|
23
39
|
| `generateReport(request)` | 使用内置结构化提示词调用模型,从遥测失败分析生成统一的 GitHub issue 报告。返回包含标题、正文和标签的 `GithubIssueReport`。请求用 `pluginIds` 说明它覆盖哪些插件——一份报告覆盖整个套件——并携带分析时间窗,以及每组的路由、最近一次失败时间和之后的尝试次数;每组字段都可选,缺省时会以 `not recorded` 传给模型,而不是省略。 |
|
|
24
40
|
| `prefilledIssueUrl(request)` | 从报告构建预填 GitHub issue 创建 URL。校验仓库 URL;失败时返回 `invalid-url`。当拼装出的 URL 超过 `maxPrefillUrlLength` 时缩短正文——标题与标签占用同一份额度,百分号编码还会放大它,因此判定基于 URL 而不是仅基于正文长度。 |
|
|
25
41
|
| `optimizeIssue(request)` | 将自然语言描述重写为按固定 Markdown 模板组织的 issue。空描述返回 `empty-input`,无路由可解析时返回 `route-missing`,模型调用失败返回 `llm-failure`。 |
|
|
42
|
+
| `createIssue(request)` | 经 GitHub REST API 直接建单,返回新 issue 的 `{ number, url }`。正文写入时会去掉首行的 `## 标题`,因为 GitHub 把标题作为独立字段。 |
|
|
43
|
+
| `listClaimableIssues(request)` | 列出带接单标签的 open issue,并排除 PR——GitHub 的 issue 端点也会返回 PR。 |
|
|
44
|
+
| `dispatchIssue(request)` | 经 Session 控制器新建一个会话并命名,把渲染后的提示词登记为该会话上的一次性自动化任务,由 Schedule 服务送达;返回 `sessionId`。没有挂载 Schedule 服务的部署改为直接排入提示词。 |
|
|
45
|
+
| `runIntake(request)` | 执行一次接单:列出可接单 issue,跳过此前已派发的,派发其余,并把本地日期持久化。 |
|
|
46
|
+
|
|
47
|
+
接单方法只报一个稳定的失败码,而不是原始的 `fetch` 错误:`auth-missing`、`auth-failure`、`rate-limited`、`invalid-repo`、`invalid-request`、`http-failure`、`network-failure`、`session-unavailable`、`dispatch-failed`。`auth-missing` 与 `auth-failure` 分开,是因为「没有凭据」和「凭据被拒绝」是两种部署问题,修法不同。
|
|
26
48
|
|
|
27
49
|
## 模型路由
|
|
28
50
|
|
|
@@ -54,6 +76,50 @@ DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issu
|
|
|
54
76
|
|
|
55
77
|
`generateReport` 会收到分析时间窗,以及每组的失败路由、最近一次失败时间和之后的同动作尝试次数。它的系统提示词要求陈述这些事实,禁止提出分析未提供证据的机制——采样参数、token 预算、超时、分块与响应解析被点名为反例——并要求分析未携带的事实写作 `not recorded`。它也明确禁止写「需要补充采集」:缺失的事实既可能是旧事件,也可能是采集缺口,报告无从区分。
|
|
56
78
|
|
|
79
|
+
## Issue 接单闭环
|
|
80
|
+
|
|
81
|
+
闭环有三步,本插件负责后两步。用户用自然语言描述问题,`optimizeIssue` 把它变成固定模板的报告,`createIssue` 直接建单。这一步替换掉闭环原本停住的地方:预填 URL 仍然要用户打开表单并按下提交,任何东西都无法自动接住这个 issue。
|
|
82
|
+
|
|
83
|
+
`runIntake` 随后读取带 `claimLabel` 的 issue,并把每个交给一个新会话,同时登记为一次性自动化任务。会话经 Session 控制器创建,因此与用户在 Web 里新建的会话拿到相同的 preset 与工作区策略;工作本身以任务的形式交给 Schedule 服务——也就是 Web「自动化任务」页面列出的那块面板——由它在任务到点时把渲染好的提示词送进该会话。任务永远绑定一个已存在的会话,所以会话先建;没有挂载 Schedule 服务的部署(非 Web 组合)改为用控制器的 `prompt` 直接排入提示词,那正是 Web 端发提示词走的同一条持久路径:把消息以用户来源记录下来,排进会话 Agent 的收件箱,由控制器自己解析(必要时先恢复)那个 Agent。命名是尽力而为:没有挂载标题服务的部署依然得到一个可用的会话。
|
|
84
|
+
|
|
85
|
+
凭据每个进程只解析一次,顺序是 `token`、`tokenEnv`、`tokenCommand`。默认命令是 `gh auth token`,因此已经登录 GitHub 的机器不需要额外密钥;自行管理密钥的部署设置 `token` 并用空字符串停用命令。token 永远不会被记录到日志。
|
|
86
|
+
|
|
87
|
+
### 每天首次启动
|
|
88
|
+
|
|
89
|
+
`autopilotEnabled` 打开后,宿主启动时每个本地日期执行一次检查。本地日期从 storage-domain 的持久状态读取,因此同一天稍后重启什么也不做,已派发的 issue 永不再次派发——它的会话已经存在,再来一个只会重复劳动。只有列取成功后才提交日期,所以连不上 GitHub 的那次会在下次启动重试,而不会被记成已完成。每次派发都失败的那一次同样会重试:只有在有 issue 进入会话、或本来就没有需要派发的东西时才提交日期——把一次坏掉的派发记成「今天查过了」,正是让失败的启动看起来像「当天无事可做」的原因。列取失败、派发失败,以及打不开接单状态,都会写一条 telemetry 错误事件,事后能读到这次检查为什么什么都没做。
|
|
90
|
+
|
|
91
|
+
检查需要持久状态,没有就拒绝运行:没有「派发过什么」的记忆,重启会为同一个 issue 打开第二个会话。它也默认关闭,因为未经请求就打开会话是部署决定,而不是插件安装时自带的行为。
|
|
92
|
+
|
|
93
|
+
`@deepseek-ai/dsh-storage-domain` 是可选 peer。单独安装本包时服务照常加载、建单与列取都可用,只有每日检查保持关闭;该 import 发生在启用检查时,而不是模块加载时。每个 DSH 安装都自带这个包,因此「缺失」是防御性分支,而不是受支持的配置。
|
|
94
|
+
|
|
95
|
+
```yaml
|
|
96
|
+
# 你的 cordis.yml,或你自己 bundle 的 patch
|
|
97
|
+
- insert:
|
|
98
|
+
- id: github-issue
|
|
99
|
+
name: @zhangj1164/dsh-github-issue
|
|
100
|
+
config:
|
|
101
|
+
repoUrl: https://github.com/your-org/your-repo
|
|
102
|
+
autopilotEnabled: true
|
|
103
|
+
autopilotCwd: /path/to/your-repo
|
|
104
|
+
claimLabel: ready-for-agent
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
宿主必须在运行,检查才可能发生;没有启动的一天就没有检查。这是有意的行为——检查是启动钩子,不是调度器——而「自动化任务」页面现在会列出每次派发登记的那条一次性任务,已送达的显示为已结束。
|
|
108
|
+
|
|
109
|
+
派发出来的会话要自己跑仓库流程,第一步就是 `git fetch`。默认的 `workspace-write` 沙箱会拦住联网命令并弹出审批,而无人值守的派发无法回答它;因此想让闭环自己跑起来的部署,应在自己的 patch 层把权限预设固定为 `danger-full-access`:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
- id: permission
|
|
113
|
+
config:
|
|
114
|
+
presets:
|
|
115
|
+
read-only: { sandbox: read-only, approval: ask }
|
|
116
|
+
workspace-write: { sandbox: workspace-write, approval: ask }
|
|
117
|
+
danger-full-access: { sandbox: danger-full-access, approval: never }
|
|
118
|
+
defaultPreset: danger-full-access
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
这是部署级取舍:它对宿主新建的每个会话生效,而不只是派发的会话。
|
|
122
|
+
|
|
57
123
|
## 需求映射
|
|
58
124
|
|
|
59
125
|
- **需求 8** — `generateReport` 将遥测失败分析转化为统一的 GitHub issue 报告,将每个失败组与插件功能代码关联。
|
|
@@ -61,6 +127,8 @@ DSH 的 GitHub issue 生成与优化服务。从遥测分析构建结构化 issu
|
|
|
61
127
|
- **需求 10** — 封装为独立的 DSH 插件:此包自带 `dsh.bundle` 与 `cordis.patch.yml`,部署方可以单独安装,任何 UI 插件都能接入。见下文「接入本插件」。
|
|
62
128
|
- **需求 11** — `optimizeIssue` 使用配置的模型和内置的结构化提示词,将自然语言描述重写为结构化 issue。`ui-memo` 包直接调用此方法实现"添加 Issue"编辑器。
|
|
63
129
|
- **需求 12** — 可复用:issue 报告模板、预填 URL 构建器和优化提示词都是通用的,不特定于备忘功能。
|
|
130
|
+
- **需求 13** — `createIssue` 经 GitHub API 直接提交整理好的报告,于是「整理 issue」与「填写 issue」合成一步,而不是一个必须由用户提交的表单。
|
|
131
|
+
- **需求 14** — `runIntake` 与首次启动检查闭合了环路:可接单 issue 无需用户手动打开就变成一个会话,且已派发的 issue 不会被派发两次。
|
|
64
132
|
|
|
65
133
|
## 接入本插件
|
|
66
134
|
|
|
@@ -112,4 +180,6 @@ dsh plugin --profile web add @zhangj1164/dsh-telemetry @zhangj1164/dsh-github-is
|
|
|
112
180
|
## 已知限制
|
|
113
181
|
|
|
114
182
|
- **模型依赖** — `inject: ['llm']` 意味着服务在没有 LLM 提供方时不会激活。
|
|
115
|
-
-
|
|
183
|
+
- **自身没有浏览器界面** — 本包不注册模型工具,也不附带浏览器 UI。单独安装只会给部署带来 `ctx.get('githubIssue')`,用户看不到也点不到任何东西;可见的入口是 `@zhangj1164/dsh-client-ui-memo` 的 issue 编辑器(其「直接提交到 GitHub」按钮)与日志分析动作,它们经 Remote 调用本服务。请把它当作供 UI 插件消费的后端,而不是一个能独立使用的功能。
|
|
184
|
+
- **派发需要 Web 组合** — `dispatchIssue` 与 `runIntake` 读取 `ctx.get('sessionController')`,存在时再读 `ctx.get('schedule')`。没有 Session 控制器的 headless 或纯 SDK 组合会返回 `session-unavailable`,只能建单和列取;有控制器但没有 Schedule 服务的组合仍能派发,只是改为直接排入提示词。
|
|
185
|
+
- **首次启动检查是启动钩子,不是调度器** — 它只在宿主启动时运行。跨过午夜仍保持运行的部署会在下一次启动时检查,而不是在午夜检查。
|
package/cordis.patch.yml
CHANGED
|
@@ -11,9 +11,20 @@
|
|
|
11
11
|
#
|
|
12
12
|
# `repoUrl` is the repository new-issue links point at. Deployments override it
|
|
13
13
|
# in their own cordis.patch.yml; the value below is this project's own.
|
|
14
|
+
#
|
|
15
|
+
# The intake loop is off until a deployment turns it on. Enabling it needs the
|
|
16
|
+
# repository URL, the directory a dispatched Session owns, and a GitHub
|
|
17
|
+
# credential (the configured token environment variable, or the default
|
|
18
|
+
# `gh auth token` command):
|
|
19
|
+
#
|
|
20
|
+
# config:
|
|
21
|
+
# repoUrl: https://github.com/your-org/your-repo
|
|
22
|
+
# autopilotEnabled: true
|
|
23
|
+
# autopilotCwd: /path/to/your-repo
|
|
24
|
+
# claimLabel: ready-for-agent
|
|
14
25
|
|
|
15
26
|
- insert:
|
|
16
27
|
- id: github-issue
|
|
17
28
|
name: "@zhangj1164/dsh-github-issue"
|
|
18
29
|
config:
|
|
19
|
-
repoUrl: https://github.com/zhangj1164/dsh-mega-plugins
|
|
30
|
+
repoUrl: https://github.com/zhangj1164/dsh-mega-plugins
|
package/lib/client.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { GithubIssueAnalysisWindow, GithubIssueFailureGroupInput, GithubIssueFailureRoute, GithubIssueGenerateReportRequest, GithubIssueGenerateReportResult, GithubIssueOptimizeRequest, GithubIssueOptimizeResult, GithubIssuePrefillRequest, GithubIssuePrefillResult, GithubIssueReport } from "./types.js";
|
|
2
|
-
export type { GithubIssueAnalysisWindow, GithubIssueFailureGroupInput, GithubIssueFailureRoute, GithubIssueGenerateReportRequest, GithubIssueGenerateReportResult, GithubIssueOptimizeRequest, GithubIssueOptimizeResult, GithubIssuePrefillRequest, GithubIssuePrefillResult, GithubIssueReport };
|
|
1
|
+
import { GithubIssueAnalysisWindow, GithubIssueCreateRequest, GithubIssueCreateResult, GithubIssueCreated, GithubIssueDispatchRequest, GithubIssueDispatchResult, GithubIssueDispatched, GithubIssueFailure, GithubIssueFailureCode, GithubIssueFailureGroupInput, GithubIssueFailureRoute, GithubIssueGenerateReportRequest, GithubIssueGenerateReportResult, GithubIssueIntakeFailure, GithubIssueIntakeRequest, GithubIssueIntakeResult, GithubIssueIntakeValue, GithubIssueListRequest, GithubIssueListResult, GithubIssueOptimizeRequest, GithubIssueOptimizeResult, GithubIssuePrefillRequest, GithubIssuePrefillResult, GithubIssueReport, GithubIssueTask } from "./types.js";
|
|
2
|
+
export type { GithubIssueAnalysisWindow, GithubIssueCreateRequest, GithubIssueCreateResult, GithubIssueCreated, GithubIssueDispatchRequest, GithubIssueDispatchResult, GithubIssueDispatched, GithubIssueFailure, GithubIssueFailureCode, GithubIssueFailureGroupInput, GithubIssueFailureRoute, GithubIssueGenerateReportRequest, GithubIssueGenerateReportResult, GithubIssueIntakeFailure, GithubIssueIntakeRequest, GithubIssueIntakeResult, GithubIssueIntakeValue, GithubIssueListRequest, GithubIssueListResult, GithubIssueOptimizeRequest, GithubIssueOptimizeResult, GithubIssuePrefillRequest, GithubIssuePrefillResult, GithubIssueReport, GithubIssueTask };
|