dsh-issue2pr 0.1.0 → 0.3.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.md +35 -13
- package/client.js +3701 -3227
- package/index.js +862 -658
- package/lib/assistant.js +3 -3
- package/lib/{pipeline.js → core/pipeline.js} +55 -4
- package/lib/{stageConfig.js → core/stageConfig.js} +24 -2
- package/lib/delegate/agents.js +204 -0
- package/lib/delegate/delegateVerify.js +125 -0
- package/lib/infra/repoState.js +59 -0
- package/lib/stages/helpers.js +3 -3
- package/lib/stages/p1-issue-analyzer.js +2 -2
- package/lib/stages/p10-failure.js +2 -2
- package/lib/stages/p11-pr-builder.js +2 -2
- package/lib/stages/p2-search.js +2 -2
- package/lib/stages/p3-code-understanding.js +2 -2
- package/lib/stages/p4-hypothesis.js +2 -2
- package/lib/stages/p5-planner.js +2 -2
- package/lib/stages/p6-coder.js +18 -11
- package/lib/stages/p7-patch.js +12 -3
- package/lib/stages/p8-test-runner.js +2 -2
- package/lib/stages/p9-reviewer.js +2 -2
- package/package.json +37 -8
- /package/lib/{store.js → core/store.js} +0 -0
- /package/lib/{connections.js → infra/connections.js} +0 -0
- /package/lib/{llm.js → infra/llm.js} +0 -0
package/lib/stages/p6-coder.js
CHANGED
|
@@ -6,11 +6,11 @@ import { spawn } from "node:child_process";
|
|
|
6
6
|
import { existsSync, readdirSync } from "node:fs";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { join } from "node:path";
|
|
9
|
-
import { writeArtifact, readArtifact } from "../store.js";
|
|
9
|
+
import { writeArtifact, readArtifact } from "../core/store.js";
|
|
10
10
|
import { requireArtifact, readRepoFile, logEvent } from "./helpers.js";
|
|
11
|
-
import { slugify, timestamp } from "../store.js";
|
|
12
|
-
import { saveRun, sessionPatchesReady } from "../pipeline.js";
|
|
13
|
-
import { sysOf, paramsOf } from "../stageConfig.js";
|
|
11
|
+
import { slugify, timestamp } from "../core/store.js";
|
|
12
|
+
import { saveRun, sessionPatchesReady } from "../core/pipeline.js";
|
|
13
|
+
import { sysOf, paramsOf } from "../core/stageConfig.js";
|
|
14
14
|
|
|
15
15
|
// —— claude CLI 进程管理(stop/删除 Run 时杀进程树,避免孤儿 claude 继续写仓库) ——
|
|
16
16
|
const activeExternals = new Map(); // runDir → ChildProcess
|
|
@@ -29,15 +29,18 @@ export function killExternal(runDir) {
|
|
|
29
29
|
|
|
30
30
|
// claude 可执行文件解析:阶段配置(params.claudeBin)> 环境变量 ISSUE2PR_CLAUDE_BIN > 常见安装位置探测。
|
|
31
31
|
// 开源环境安装路径各异,UI「配置」可显式指定;PATH 里未必有 claude(如 npm 全局目录不在系统 PATH)。
|
|
32
|
-
// preflight
|
|
33
|
-
export function
|
|
34
|
-
if (cfgBin) return cfgBin;
|
|
35
|
-
if (process.env.ISSUE2PR_CLAUDE_BIN) return process.env.ISSUE2PR_CLAUDE_BIN;
|
|
32
|
+
// preflight 端点与 lib/agents.js 的发现/门禁复用本函数做健康探测。
|
|
33
|
+
export function claudeCommonCandidates() {
|
|
36
34
|
const home = homedir();
|
|
37
|
-
|
|
35
|
+
return process.platform === "win32"
|
|
38
36
|
? [join(home, ".npm-global", "claude.cmd"), join(home, ".npm_global", "claude.cmd"), join(home, "AppData", "Roaming", "npm", "claude.cmd"), join(home, ".local", "bin", "claude.exe")]
|
|
39
37
|
: [join(home, ".local", "bin", "claude"), "/usr/local/bin/claude", "/opt/homebrew/bin/claude"];
|
|
40
|
-
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function resolveClaudeBin(cfgBin) {
|
|
41
|
+
if (cfgBin) return cfgBin;
|
|
42
|
+
if (process.env.ISSUE2PR_CLAUDE_BIN) return process.env.ISSUE2PR_CLAUDE_BIN;
|
|
43
|
+
return claudeCommonCandidates().find((p) => existsSync(p)) || "claude";
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
// 无人值守跑 claude:-p headless;skip-permissions 无交互放行;--add-dir 允许写 run 产物目录(cwd 是仓库)。
|
|
@@ -168,7 +171,11 @@ async function delegateClaude(rcx, graph) {
|
|
|
168
171
|
return { artifact: "06-implementation/", summary: "Claude Code 已执行任务包:" + countPatches(runDir) + " 份 patch + report,等待人工复核" + statsSummary(stats) };
|
|
169
172
|
}
|
|
170
173
|
|
|
171
|
-
|
|
174
|
+
// 认证类失败(403 IP 白名单 / 未登录)给出可操作引导——到项目页委外智能体卡片重跑门禁
|
|
175
|
+
const rawReason = r.error || (r.timeout ? "超时被终止" : "退出码 " + r.code + (r.stderr ? ":" + String(r.stderr).slice(0, 300) : ""));
|
|
176
|
+
const authHit = /40[13]|authenticat|api[- ]?key|ip access|not logged in/i.test(String(r.stderr || "") + "\n" + String(r.stdout || ""));
|
|
177
|
+
const reason = rawReason + (authHit
|
|
178
|
+
? ";疑似认证/授权问题——请到「项目」页委外智能体卡片重跑测试门禁(检查 Claude 登录状态、API Key 的 IP 白名单或代理出口)" : "");
|
|
172
179
|
setExec({ status: r.error ? "skipped" : "failed", exitCode: r.code, stats, error: String(reason).slice(0, 500), finishedAt: new Date().toISOString() });
|
|
173
180
|
logEvent(rcx, { kind: "tool", name: "Claude Code 执行未产出补丁", detail: String(reason).slice(0, 500), ok: false });
|
|
174
181
|
// 回退等人工:保持 external 语义(UI 显示"等外部执行"并拦截空产物 approve),人可接管 session-task.md
|
package/lib/stages/p7-patch.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import { appendArtifactLine } from "../store.js";
|
|
6
|
+
import { appendArtifactLine } from "../core/store.js";
|
|
7
7
|
import { logEvent } from "./helpers.js";
|
|
8
|
+
import { resetRepoClean } from "../infra/repoState.js";
|
|
8
9
|
|
|
9
10
|
// 带stdin输入的异步执行(git apply - 用 stdin 收 diff)
|
|
10
11
|
function execStdin(cmd, args, opts, input) {
|
|
@@ -27,12 +28,15 @@ async function hashRepo(repoDir) {
|
|
|
27
28
|
// patch 清单:优先 coder-report.json(builtin 写 patches 字段;claude 委托写 tasks 字段且
|
|
28
29
|
// patch 路径相对 06-implementation/,这里统一归一化为相对 runDir 全路径);
|
|
29
30
|
// report 缺失时退化为扫描目录(文件名序 = 应用序)。
|
|
30
|
-
|
|
31
|
+
// 导出供 delegateVerify 复用:验证清单 = P7 应用清单,同一口径。
|
|
32
|
+
export function collectPatches(runDir) {
|
|
31
33
|
const normalize = (p) => !p ? null
|
|
32
34
|
: { patch: p.startsWith("06-implementation/") ? p : "06-implementation/" + p.replace(/^\/+/, "") };
|
|
33
35
|
const reportPath = join(runDir, "06-implementation", "coder-report.json");
|
|
34
36
|
if (existsSync(reportPath)) {
|
|
35
|
-
|
|
37
|
+
let report;
|
|
38
|
+
try { report = JSON.parse(readFileSync(reportPath, "utf8")); }
|
|
39
|
+
catch { throw new Error("coder-report.json 损坏(非法 JSON),无法解析补丁清单;请回退 P6 重跑或修复报告文件"); }
|
|
36
40
|
const list = Array.isArray(report.patches) ? report.patches
|
|
37
41
|
: Array.isArray(report.tasks) ? report.tasks.map((t) => ({ patch: t.patch }))
|
|
38
42
|
: [];
|
|
@@ -47,6 +51,11 @@ function collectPatches(runDir) {
|
|
|
47
51
|
export default async function execute(rcx) {
|
|
48
52
|
const patches = collectPatches(rcx.runDir);
|
|
49
53
|
if (!patches.length) throw new Error("P7 无 patch 可应用(06-implementation/patches/ 为空且无 coder-report.json)");
|
|
54
|
+
// A1/A2 修复:应用补丁前先把工作区重置回 HEAD 基线。
|
|
55
|
+
// 打回重跑/回退重跑时上一轮已应用的补丁仍在工作区(直接 re-apply 必失败);
|
|
56
|
+
// worktree 兜底共用基线 repo 的路径下同理清残留。reset 不碰 .gitignore 的目录(如 node_modules)。
|
|
57
|
+
await resetRepoClean(rcx.repoDir);
|
|
58
|
+
logEvent(rcx, { kind: "git", name: "工作区基线重置", detail: "P7 应用补丁前 git reset --hard + git clean -fd" });
|
|
50
59
|
for (const p of patches) {
|
|
51
60
|
const diff = readFileSync(join(rcx.runDir, p.patch), "utf8");
|
|
52
61
|
const hashBefore = await hashRepo(rcx.repoDir);
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
import { exec } from "node:child_process";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import { writeArtifact } from "../store.js";
|
|
6
|
+
import { writeArtifact } from "../core/store.js";
|
|
7
7
|
import { logEvent } from "./helpers.js";
|
|
8
|
-
import { DEFAULT_TEST_TIMEOUT_MS } from "../stageConfig.js";
|
|
8
|
+
import { DEFAULT_TEST_TIMEOUT_MS } from "../core/stageConfig.js";
|
|
9
9
|
|
|
10
10
|
function detectCommand(repoDir) {
|
|
11
11
|
const pkg = join(repoDir, "package.json");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// lib/stages/p9-reviewer.js — 调研 §9:Review 是 PRBuilder 的前置门控
|
|
2
|
-
import { writeArtifact, readArtifact } from "../store.js";
|
|
2
|
+
import { writeArtifact, readArtifact } from "../core/store.js";
|
|
3
3
|
import { requireArtifact, maybeDelegate } from "./helpers.js";
|
|
4
|
-
import { sysOf, paramsOf } from "../stageConfig.js";
|
|
4
|
+
import { sysOf, paramsOf } from "../core/stageConfig.js";
|
|
5
5
|
|
|
6
6
|
export default async function execute(rcx) {
|
|
7
7
|
const delegated = await maybeDelegate(rcx, "P9");
|
package/package.json
CHANGED
|
@@ -1,25 +1,54 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-issue2pr",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Issue-to-PR 可验证交付链:项目配置 → 11 阶段流水线 → 人工复核 → PR 说明(DSH 全局插件)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
|
-
"exports": {
|
|
8
|
-
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.js",
|
|
9
|
+
"./client": "./client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "node --test \"tests/**/*.test.js\""
|
|
14
|
+
},
|
|
9
15
|
"repository": {
|
|
10
16
|
"type": "git",
|
|
11
17
|
"url": "git+https://github.com/LONGSASASASASA/dsh-issue2pr.git"
|
|
12
18
|
},
|
|
13
|
-
"keywords": [
|
|
19
|
+
"keywords": [
|
|
20
|
+
"dsh",
|
|
21
|
+
"dsh-plugin",
|
|
22
|
+
"deepseek-harness",
|
|
23
|
+
"issue",
|
|
24
|
+
"pull-request",
|
|
25
|
+
"pipeline",
|
|
26
|
+
"code-review",
|
|
27
|
+
"cordis"
|
|
28
|
+
],
|
|
14
29
|
"author": "LONGSASASASASA",
|
|
15
30
|
"license": "MIT",
|
|
16
|
-
"files": [
|
|
17
|
-
|
|
31
|
+
"files": [
|
|
32
|
+
"index.js",
|
|
33
|
+
"client.js",
|
|
34
|
+
"lib/",
|
|
35
|
+
"cordis.patch.yml",
|
|
36
|
+
"docs/assets/"
|
|
37
|
+
],
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"registry": "https://registry.npmjs.org/"
|
|
40
|
+
},
|
|
18
41
|
"dsh": {
|
|
19
|
-
"bundle": {
|
|
42
|
+
"bundle": {
|
|
43
|
+
"patch": "./cordis.patch.yml"
|
|
44
|
+
},
|
|
20
45
|
"client": {
|
|
21
46
|
"platform": "web",
|
|
22
|
-
"inject": [
|
|
47
|
+
"inject": [
|
|
48
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
49
|
+
"@deepseek-ai/dsh-client-locale",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
51
|
+
]
|
|
23
52
|
}
|
|
24
53
|
},
|
|
25
54
|
"peerDependencies": {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|