@vicfei/dsh-super-agent 0.5.1 → 0.6.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/README.md +17 -1
- package/README.zh-CN.md +17 -2
- package/dist/cli.js +62 -11
- package/dist/cli.js.map +1 -1
- package/dist/domain.d.ts +21 -0
- package/dist/domain.js +13 -0
- package/dist/domain.js.map +1 -1
- package/dist/engine.d.ts +25 -0
- package/dist/engine.js +49 -0
- package/dist/engine.js.map +1 -1
- package/dist/github/app-auth.d.ts +33 -0
- package/dist/github/app-auth.js +102 -0
- package/dist/github/app-auth.js.map +1 -0
- package/dist/github/client.d.ts +44 -0
- package/dist/github/client.js +27 -2
- package/dist/github/client.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/merge.d.ts +28 -0
- package/dist/merge.js +129 -0
- package/dist/merge.js.map +1 -0
- package/dist/panel.d.ts +1 -0
- package/dist/panel.html +44 -0
- package/dist/panel.js +1 -0
- package/dist/panel.js.map +1 -1
- package/dist/usage.d.ts +2 -2
- package/dist/usage.js +7 -5
- package/dist/usage.js.map +1 -1
- package/dist/watch.js +5 -2
- package/dist/watch.js.map +1 -1
- package/dist/work.d.ts +10 -0
- package/dist/work.js +20 -2
- package/dist/work.js.map +1 -1
- package/examples/policy.json +7 -0
- package/package.json +3 -2
package/dist/github/client.d.ts
CHANGED
|
@@ -22,20 +22,53 @@ export interface GhPull extends GhItemBase {
|
|
|
22
22
|
number: number;
|
|
23
23
|
title: string | null;
|
|
24
24
|
}
|
|
25
|
+
/** Full pull detail for the merge gate (GET /repos/:o/:r/pulls/:n). */
|
|
26
|
+
export interface GhPullDetail {
|
|
27
|
+
number: number;
|
|
28
|
+
state: "open" | "closed";
|
|
29
|
+
draft: boolean;
|
|
30
|
+
merged: boolean;
|
|
31
|
+
/** null while GitHub has not computed mergeability — treat as "not yet", fail-closed. */
|
|
32
|
+
mergeable: boolean | null;
|
|
33
|
+
head: {
|
|
34
|
+
ref: string;
|
|
35
|
+
sha: string;
|
|
36
|
+
};
|
|
37
|
+
additions: number;
|
|
38
|
+
deletions: number;
|
|
39
|
+
}
|
|
40
|
+
export interface GhReview {
|
|
41
|
+
id: number;
|
|
42
|
+
user: GhActor | null;
|
|
43
|
+
/** APPROVED | CHANGES_REQUESTED | COMMENTED | PENDING | DISMISSED — a reviewer's latest non-comment stance is their effective one. */
|
|
44
|
+
state: string;
|
|
45
|
+
commit_id: string;
|
|
46
|
+
submitted_at: string;
|
|
47
|
+
}
|
|
25
48
|
export interface GhReviewComment extends GhItemBase {
|
|
26
49
|
/** api url of the parent pull. */
|
|
27
50
|
pull_request_url: string;
|
|
28
51
|
in_reply_to_id?: number;
|
|
29
52
|
}
|
|
53
|
+
/** Mutable credential source (App installation tokens): fetched per request, invalidated on 401. */
|
|
54
|
+
export interface TokenProvider {
|
|
55
|
+
get(): Promise<string>;
|
|
56
|
+
/** The client calls this when a request got 401 — drop cached state before the single retry. */
|
|
57
|
+
onAuthFailure(): void;
|
|
58
|
+
}
|
|
30
59
|
export declare class GitHubClient {
|
|
31
60
|
private readonly fetchImpl;
|
|
32
61
|
private readonly apiBase;
|
|
33
62
|
constructor(opts?: {
|
|
34
63
|
token?: string;
|
|
64
|
+
tokenProvider?: TokenProvider;
|
|
35
65
|
fetchImpl?: typeof fetch;
|
|
36
66
|
apiBase?: string;
|
|
37
67
|
});
|
|
38
68
|
private readonly token;
|
|
69
|
+
private readonly tokenProvider;
|
|
70
|
+
/** The credential actually in use — PAT, installation token, or undefined (anonymous). */
|
|
71
|
+
currentToken(): Promise<string | undefined>;
|
|
39
72
|
private request;
|
|
40
73
|
/** Newest-first single page. Filtering by read position happens in the Source. */
|
|
41
74
|
private list;
|
|
@@ -59,5 +92,16 @@ export declare class GitHubClient {
|
|
|
59
92
|
number: number;
|
|
60
93
|
html_url: string;
|
|
61
94
|
}>;
|
|
95
|
+
getPull(repo: string, number: number): Promise<GhPullDetail>;
|
|
96
|
+
listReviews(repo: string, number: number): Promise<GhReview[]>;
|
|
97
|
+
/** SHA-pinned merge: if the head moved since evaluation, GitHub rejects — we never merge unreviewed bytes. */
|
|
98
|
+
mergePullRequest(repo: string, number: number, opts: {
|
|
99
|
+
sha: string;
|
|
100
|
+
merge_method: "squash" | "merge" | "rebase";
|
|
101
|
+
}): Promise<{
|
|
102
|
+
merged: boolean;
|
|
103
|
+
sha?: string;
|
|
104
|
+
}>;
|
|
105
|
+
deleteBranch(repo: string, branch: string): Promise<unknown>;
|
|
62
106
|
}
|
|
63
107
|
export {};
|
package/dist/github/client.js
CHANGED
|
@@ -7,19 +7,31 @@ export class GitHubClient {
|
|
|
7
7
|
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
8
8
|
this.apiBase = opts.apiBase ?? "https://api.github.com";
|
|
9
9
|
this.token = opts.token ?? "";
|
|
10
|
+
this.tokenProvider = opts.tokenProvider ?? null;
|
|
10
11
|
}
|
|
11
12
|
token;
|
|
12
|
-
|
|
13
|
+
tokenProvider;
|
|
14
|
+
/** The credential actually in use — PAT, installation token, or undefined (anonymous). */
|
|
15
|
+
async currentToken() {
|
|
16
|
+
return this.tokenProvider ? this.tokenProvider.get() : this.token || undefined;
|
|
17
|
+
}
|
|
18
|
+
async request(method, path, body, retry = true) {
|
|
19
|
+
const token = this.tokenProvider ? await this.tokenProvider.get() : this.token;
|
|
13
20
|
const res = await this.fetchImpl(`${this.apiBase}${path}`, {
|
|
14
21
|
method,
|
|
15
22
|
headers: {
|
|
16
23
|
accept: "application/vnd.github+json",
|
|
17
24
|
"x-github-api-version": "2022-11-28",
|
|
18
|
-
...(
|
|
25
|
+
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
19
26
|
...(body !== undefined ? { "content-type": "application/json" } : {}),
|
|
20
27
|
},
|
|
21
28
|
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
22
29
|
});
|
|
30
|
+
if (res.status === 401 && retry && this.tokenProvider) {
|
|
31
|
+
// A cached installation token expired mid-cycle: drop it and try exactly once more.
|
|
32
|
+
this.tokenProvider.onAuthFailure();
|
|
33
|
+
return this.request(method, path, body, false);
|
|
34
|
+
}
|
|
23
35
|
if (!res.ok) {
|
|
24
36
|
const text = await res.text().catch(() => "");
|
|
25
37
|
// The three failures a fresh install hits; the raw body alone is cryptic (M5-5).
|
|
@@ -67,5 +79,18 @@ export class GitHubClient {
|
|
|
67
79
|
createPullRequest(repo, pr) {
|
|
68
80
|
return this.request("POST", `/repos/${repo}/pulls`, pr);
|
|
69
81
|
}
|
|
82
|
+
getPull(repo, number) {
|
|
83
|
+
return this.request("GET", `/repos/${repo}/pulls/${number}`);
|
|
84
|
+
}
|
|
85
|
+
listReviews(repo, number) {
|
|
86
|
+
return this.request("GET", `/repos/${repo}/pulls/${number}/reviews`);
|
|
87
|
+
}
|
|
88
|
+
/** SHA-pinned merge: if the head moved since evaluation, GitHub rejects — we never merge unreviewed bytes. */
|
|
89
|
+
mergePullRequest(repo, number, opts) {
|
|
90
|
+
return this.request("PUT", `/repos/${repo}/pulls/${number}/merge`, opts);
|
|
91
|
+
}
|
|
92
|
+
deleteBranch(repo, branch) {
|
|
93
|
+
return this.request("DELETE", `/repos/${repo}/git/refs/heads/${branch}`);
|
|
94
|
+
}
|
|
70
95
|
}
|
|
71
96
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/github/client.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,0FAA0F;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/github/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
export * from "./domain.js";
|
|
2
2
|
export { evaluateGate, resolveCandidate, type GateResult, type Resolution, type Assessment } from "./gate.js";
|
|
3
3
|
export { Engine, type IngestItem, type TicketView, type DecisionView, type IngestReport } from "./engine.js";
|
|
4
|
-
export { GitHubClient } from "./github/client.js";
|
|
4
|
+
export { GitHubClient, type TokenProvider } from "./github/client.js";
|
|
5
|
+
export { AppTokenProvider, appAuthFromEnv, signAppJwt, type AppAuthEnv, type AppAuthOptions } from "./github/app-auth.js";
|
|
5
6
|
export { GitHubSource, isBotActor } from "./github/source.js";
|
|
6
7
|
export { FileSourceState, type StateStore, type SourceState } from "./github/state.js";
|
|
7
8
|
export { Executor, renderPrompt, type ExecutorConfig, type ExecutorResult } from "./executor.js";
|
|
8
9
|
export { runWork, deliverPullRequest, type WorkReport } from "./work.js";
|
|
9
10
|
export { runWatch, type WatchOptions } from "./watch.js";
|
|
11
|
+
export { evaluateMerge, runMergeSweep, type MergeCheck, type MergeSweepLine } from "./merge.js";
|
|
10
12
|
export { classify, formatOutcome, type PollOutcome } from "./runner.js";
|
|
11
13
|
export { llmAssessor, stubAssessor, type Assessor } from "./assess.js";
|
|
12
14
|
export { clipReply, wordCount } from "./clip.js";
|
package/dist/index.js
CHANGED
|
@@ -4,11 +4,13 @@ export * from "./domain.js";
|
|
|
4
4
|
export { evaluateGate, resolveCandidate } from "./gate.js";
|
|
5
5
|
export { Engine } from "./engine.js";
|
|
6
6
|
export { GitHubClient } from "./github/client.js";
|
|
7
|
+
export { AppTokenProvider, appAuthFromEnv, signAppJwt } from "./github/app-auth.js";
|
|
7
8
|
export { GitHubSource, isBotActor } from "./github/source.js";
|
|
8
9
|
export { FileSourceState } from "./github/state.js";
|
|
9
10
|
export { Executor, renderPrompt } from "./executor.js";
|
|
10
11
|
export { runWork, deliverPullRequest } from "./work.js";
|
|
11
12
|
export { runWatch } from "./watch.js";
|
|
13
|
+
export { evaluateMerge, runMergeSweep } from "./merge.js";
|
|
12
14
|
export { classify, formatOutcome } from "./runner.js";
|
|
13
15
|
export { llmAssessor, stubAssessor } from "./assess.js";
|
|
14
16
|
export { clipReply, wordCount } from "./clip.js";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,iFAAiF;AAEjF,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAqD,MAAM,WAAW,CAAC;AAC9G,OAAO,EAAE,MAAM,EAA0E,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,iFAAiF;AAEjF,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAqD,MAAM,WAAW,CAAC;AAC9G,OAAO,EAAE,MAAM,EAA0E,MAAM,aAAa,CAAC;AAC7G,OAAO,EAAE,YAAY,EAAsB,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AAC1H,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAqC,MAAM,mBAAmB,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAA4C,MAAM,eAAe,CAAC;AACjG,OAAO,EAAE,OAAO,EAAE,kBAAkB,EAAmB,MAAM,WAAW,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAqB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAwC,MAAM,YAAY,CAAC;AAChG,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAoB,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,WAAW,EAAE,YAAY,EAAiB,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/merge.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { MergePolicy, Policy } from "./domain.js";
|
|
2
|
+
import type { Engine } from "./engine.js";
|
|
3
|
+
import type { GitHubClient, GhPullDetail, GhReview } from "./github/client.js";
|
|
4
|
+
export interface MergeCheck {
|
|
5
|
+
ok: boolean;
|
|
6
|
+
reasons: string[];
|
|
7
|
+
/** Set when ok: the allowed-list reviewer whose approval covers the head. */
|
|
8
|
+
approvedBy?: string;
|
|
9
|
+
changedLines: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Pure evaluation (unit-tested like the gate): would this PR merge under this policy?
|
|
13
|
+
* Structural first (draft / conflict / branch / size), then review stances — a reviewer's
|
|
14
|
+
* latest APPROVED | CHANGES_REQUESTED | DISMISSED review is their effective stance
|
|
15
|
+
* (COMMENTED/PENDING don't move it; a dismissal clears it).
|
|
16
|
+
*/
|
|
17
|
+
export declare function evaluateMerge(pr: GhPullDetail, reviews: GhReview[], policy: MergePolicy, allowedList: string[]): MergeCheck;
|
|
18
|
+
export interface MergeSweepLine {
|
|
19
|
+
pr: number;
|
|
20
|
+
action: "merged" | "waiting" | "closed" | "already-merged";
|
|
21
|
+
reasons?: string[];
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Idempotent sweep over our open deliveries: sync PRs closed on GitHub, evaluate the rest,
|
|
25
|
+
* merge only zero-reason PRs, post a clipped merge reply through the outbox, prune the branch.
|
|
26
|
+
* Per-delivery errors degrade to "waiting" — the next cycle retries (fail-closed).
|
|
27
|
+
*/
|
|
28
|
+
export declare function runMergeSweep(engine: Engine, client: GitHubClient, repo: string, policy: Policy, log?: (l: string) => void): Promise<MergeSweepLine[]>;
|
package/dist/merge.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Auto-merge with delivery requirements (docs/ROADMAP M6-1) — the structural brakes:
|
|
2
|
+
// every merge condition is a checkable fact about the PR, never model judgment. Fail-closed:
|
|
3
|
+
// any miss is a recorded reason, ok requires zero reasons, and the merge PUT is pinned to the
|
|
4
|
+
// exact SHA that was approved — if the head moved, GitHub rejects and the next cycle re-evaluates.
|
|
5
|
+
import { clipReply } from "./clip.js";
|
|
6
|
+
import { mergePolicyOf } from "./domain.js";
|
|
7
|
+
import { drainReplyEffects } from "./work.js";
|
|
8
|
+
const TICKET_BRANCH = /^dsh\/ticket-\d+$/;
|
|
9
|
+
function isBotReview(r) {
|
|
10
|
+
return !r.user || r.user.type === "Bot" || r.user.login.endsWith("[bot]");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Pure evaluation (unit-tested like the gate): would this PR merge under this policy?
|
|
14
|
+
* Structural first (draft / conflict / branch / size), then review stances — a reviewer's
|
|
15
|
+
* latest APPROVED | CHANGES_REQUESTED | DISMISSED review is their effective stance
|
|
16
|
+
* (COMMENTED/PENDING don't move it; a dismissal clears it).
|
|
17
|
+
*/
|
|
18
|
+
export function evaluateMerge(pr, reviews, policy, allowedList) {
|
|
19
|
+
const reasons = [];
|
|
20
|
+
const changedLines = pr.additions + pr.deletions;
|
|
21
|
+
let approvedBy;
|
|
22
|
+
if (pr.merged)
|
|
23
|
+
reasons.push("already merged");
|
|
24
|
+
if (pr.draft)
|
|
25
|
+
reasons.push("draft PR");
|
|
26
|
+
if (pr.mergeable === false)
|
|
27
|
+
reasons.push("merge conflict");
|
|
28
|
+
else if (pr.mergeable === null)
|
|
29
|
+
reasons.push("mergeability not computed yet");
|
|
30
|
+
if (!TICKET_BRANCH.test(pr.head.ref))
|
|
31
|
+
reasons.push(`not a ticket branch: ${pr.head.ref}`);
|
|
32
|
+
if (changedLines > policy.maxChangedLines)
|
|
33
|
+
reasons.push(`±${changedLines} lines > cap ${policy.maxChangedLines}`);
|
|
34
|
+
if (reasons.length === 0) {
|
|
35
|
+
const allowed = new Set(allowedList.map((s) => s.toLowerCase()));
|
|
36
|
+
const stance = new Map();
|
|
37
|
+
for (const r of reviews) {
|
|
38
|
+
if (isBotReview(r))
|
|
39
|
+
continue; // bots have no standing — neither approve nor veto
|
|
40
|
+
const login = r.user.login;
|
|
41
|
+
if (!allowed.has(login.toLowerCase()))
|
|
42
|
+
continue; // only allowed-list reviewers count
|
|
43
|
+
if (r.state !== "APPROVED" && r.state !== "CHANGES_REQUESTED" && r.state !== "DISMISSED")
|
|
44
|
+
continue;
|
|
45
|
+
const prev = stance.get(login);
|
|
46
|
+
if (!prev || r.submitted_at > prev.at || (r.submitted_at === prev.at && r.id > prev.id)) {
|
|
47
|
+
stance.set(login, { state: r.state, commitId: r.commit_id, at: r.submitted_at, id: r.id });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
let hasApproval = false;
|
|
51
|
+
let hasCoveringApproval = false;
|
|
52
|
+
for (const [login, s] of stance) {
|
|
53
|
+
if (s.state === "CHANGES_REQUESTED")
|
|
54
|
+
reasons.push(`changes requested by @${login} — blocks until re-reviewed`);
|
|
55
|
+
if (s.state === "APPROVED") {
|
|
56
|
+
hasApproval = true;
|
|
57
|
+
if (!policy.requireApprovalCoveringHead || s.commitId === pr.head.sha) {
|
|
58
|
+
hasCoveringApproval = true;
|
|
59
|
+
approvedBy = login;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!hasApproval)
|
|
64
|
+
reasons.push("no approving review from an allowed-list member");
|
|
65
|
+
else if (!hasCoveringApproval)
|
|
66
|
+
reasons.push(`no approval covers head ${pr.head.sha.slice(0, 7)} — stale approvals do not count`);
|
|
67
|
+
}
|
|
68
|
+
return { ok: reasons.length === 0, reasons, ...(approvedBy ? { approvedBy } : {}), changedLines };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Idempotent sweep over our open deliveries: sync PRs closed on GitHub, evaluate the rest,
|
|
72
|
+
* merge only zero-reason PRs, post a clipped merge reply through the outbox, prune the branch.
|
|
73
|
+
* Per-delivery errors degrade to "waiting" — the next cycle retries (fail-closed).
|
|
74
|
+
*/
|
|
75
|
+
export async function runMergeSweep(engine, client, repo, policy, log = () => { }) {
|
|
76
|
+
const merge = mergePolicyOf(policy);
|
|
77
|
+
if (!merge.enabled)
|
|
78
|
+
return [];
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const d of engine.openDeliveries(repo)) {
|
|
81
|
+
try {
|
|
82
|
+
const pr = await client.getPull(repo, d.prNumber);
|
|
83
|
+
if (pr.state === "closed") {
|
|
84
|
+
engine.finishDelivery(d.id, pr.merged ? "merged" : "closed");
|
|
85
|
+
out.push({ pr: d.prNumber, action: pr.merged ? "merged" : "closed" });
|
|
86
|
+
log(`#${d.prNumber} ${pr.merged ? "merged" : "closed"} on GitHub — delivery synced`);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (pr.merged) {
|
|
90
|
+
engine.finishDelivery(d.id, "merged");
|
|
91
|
+
out.push({ pr: d.prNumber, action: "already-merged" });
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
const reviews = await client.listReviews(repo, d.prNumber);
|
|
95
|
+
const check = evaluateMerge(pr, reviews, merge, policy.allowedList);
|
|
96
|
+
if (!check.ok) {
|
|
97
|
+
out.push({ pr: d.prNumber, action: "waiting", reasons: check.reasons });
|
|
98
|
+
log(`#${d.prNumber} holds: ${check.reasons.join("; ")}`);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const m = await client.mergePullRequest(repo, pr.number, { sha: pr.head.sha, merge_method: merge.method });
|
|
102
|
+
if (!m.merged) {
|
|
103
|
+
out.push({ pr: d.prNumber, action: "waiting", reasons: ["merge API declined (head moved?) — will re-evaluate"] });
|
|
104
|
+
log(`#${d.prNumber} merge declined — re-evaluating next cycle`);
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
engine.enqueueReply(`merge-report:${d.prNumber}`, d.threadId, clipReply(`PR #${pr.number} merged (${merge.method}) — approved by @${check.approvedBy} covering ${pr.head.sha.slice(0, 7)} · ±${check.changedLines} lines. This is by an automated agent, not a human.`, 150));
|
|
108
|
+
engine.finishDelivery(d.id, "merged");
|
|
109
|
+
if (merge.deleteBranch) {
|
|
110
|
+
try {
|
|
111
|
+
await client.deleteBranch(repo, d.branch);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
log(`#${d.prNumber} branch ${d.branch} not deleted (best effort)`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
out.push({ pr: d.prNumber, action: "merged" });
|
|
118
|
+
log(`#${d.prNumber} merged (${merge.method}) — approved by @${check.approvedBy}`);
|
|
119
|
+
}
|
|
120
|
+
catch (e) {
|
|
121
|
+
out.push({ pr: d.prNumber, action: "waiting", reasons: [e instanceof Error ? e.message : String(e)] });
|
|
122
|
+
log(`#${d.prNumber} sweep error: ${e instanceof Error ? e.message : e}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (out.length > 0)
|
|
126
|
+
await drainReplyEffects(engine, client, repo);
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"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"}
|
package/dist/panel.d.ts
CHANGED
|
@@ -4,5 +4,6 @@ export interface PanelState {
|
|
|
4
4
|
policy: ReturnType<Engine["policy"]>;
|
|
5
5
|
tickets: ReturnType<Engine["tickets"]>;
|
|
6
6
|
decisions: ReturnType<Engine["decisions"]>;
|
|
7
|
+
deliveries: ReturnType<Engine["deliveries"]>;
|
|
7
8
|
}
|
|
8
9
|
export declare function startPanel(engine: Engine, port: number, host?: string): Promise<Server>;
|
package/dist/panel.html
CHANGED
|
@@ -50,6 +50,12 @@
|
|
|
50
50
|
<h2>Awaiting a human</h2>
|
|
51
51
|
<div id="awaiting"></div>
|
|
52
52
|
|
|
53
|
+
<h2>By person</h2>
|
|
54
|
+
<div id="persons"></div>
|
|
55
|
+
|
|
56
|
+
<h2>Pull requests</h2>
|
|
57
|
+
<div id="deliveries"></div>
|
|
58
|
+
|
|
53
59
|
<h2>Observe records — would accept</h2>
|
|
54
60
|
<div id="shadows"></div>
|
|
55
61
|
|
|
@@ -89,6 +95,44 @@ async function render() {
|
|
|
89
95
|
+ revoked.map(t => `<div class="card"><span class="badge b-ignore">revoked</span>
|
|
90
96
|
ticket #${t.id} — ${esc(t.revokedReason)}</div>`).join('');
|
|
91
97
|
|
|
98
|
+
// By person (M6-3): the opener is who the work is *for* — one card per person with their
|
|
99
|
+
// stage counts and where their delivered PRs stand.
|
|
100
|
+
const openerOf = new Map(s.tickets.map(t => [t.id, t.opener]));
|
|
101
|
+
const persons = new Map();
|
|
102
|
+
for (const t of s.tickets) {
|
|
103
|
+
const p = persons.get(t.opener) ?? { tickets: [], deliveries: [] };
|
|
104
|
+
p.tickets.push(t);
|
|
105
|
+
persons.set(t.opener, p);
|
|
106
|
+
}
|
|
107
|
+
for (const d of s.deliveries || []) {
|
|
108
|
+
const who = openerOf.get(d.ticketId) ?? '(unknown opener)';
|
|
109
|
+
const p = persons.get(who) ?? { tickets: [], deliveries: [] };
|
|
110
|
+
p.deliveries.push(d);
|
|
111
|
+
persons.set(who, p);
|
|
112
|
+
}
|
|
113
|
+
document.getElementById('persons').innerHTML = persons.size === 0
|
|
114
|
+
? '<div class="quiet">no tickets yet</div>'
|
|
115
|
+
: [...persons.entries()].map(([who, p]) => {
|
|
116
|
+
const counts = ['queued', 'working', 'needs-person', 'ended']
|
|
117
|
+
.map(st => p.tickets.filter(t => t.stage === st).length)
|
|
118
|
+
.map((n, i) => n > 0 ? `<span class="quiet">${['queued','working','needs-person','ended'][i]}:${n}</span>` : '')
|
|
119
|
+
.filter(Boolean).join(' · ');
|
|
120
|
+
const dels = p.deliveries.map(d => `PR #${d.prNumber} ${d.state}`).join(' · ');
|
|
121
|
+
return `<div class="card"><b>${esc(who)}</b> — ${counts || 'no open work'}${dels ? `<div class="quiet">${dels}</div>` : ''}</div>`;
|
|
122
|
+
}).join('');
|
|
123
|
+
|
|
124
|
+
const deliveries = s.deliveries || [];
|
|
125
|
+
const mergeOn = !!(s.policy && s.policy.merge && s.policy.merge.enabled);
|
|
126
|
+
document.getElementById('deliveries').innerHTML = deliveries.length === 0
|
|
127
|
+
? '<div class="quiet">no pull requests opened</div>'
|
|
128
|
+
: deliveries.map(d => {
|
|
129
|
+
const cls = d.state === 'merged' ? 'b-accept' : d.state === 'closed' ? 'b-ignore' : 'b-shadow';
|
|
130
|
+
const note = d.state === 'open' ? (mergeOn ? 'awaiting merge requirements' : 'auto-merge off (policy.merge)') : '';
|
|
131
|
+
return `<div class="card"><span class="badge ${cls}">${d.state}</span>
|
|
132
|
+
PR #${esc(d.prNumber)} ${esc(d.branch)} · ticket #${d.ticketId}
|
|
133
|
+
<span class="quiet">${esc(note)}</span></div>`;
|
|
134
|
+
}).join('');
|
|
135
|
+
|
|
92
136
|
const shadows = s.decisions.filter(d => d.wouldAccept);
|
|
93
137
|
document.getElementById('shadows').innerHTML = shadows.length === 0
|
|
94
138
|
? '<div class="quiet">no shadow records</div>'
|
package/dist/panel.js
CHANGED
|
@@ -19,6 +19,7 @@ export function startPanel(engine, port, host = "127.0.0.1") {
|
|
|
19
19
|
policy: engine.policy(),
|
|
20
20
|
tickets: engine.tickets(),
|
|
21
21
|
decisions: engine.decisions(50),
|
|
22
|
+
deliveries: engine.deliveries(30),
|
|
22
23
|
};
|
|
23
24
|
send(200, "application/json", JSON.stringify(state));
|
|
24
25
|
return;
|
package/dist/panel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panel.js","sourceRoot":"","sources":["../src/panel.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,wFAAwF;AAExF,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAIvC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,GAAG,CAAC,cAAc,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"panel.js","sourceRoot":"","sources":["../src/panel.ts"],"names":[],"mappings":"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"}
|
package/dist/usage.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const USAGE = "dsh-super-agent \u2014 admission control, observe mode & tickets for any CLI coding agent\n\nUsage: dsh-super-agent <command> [options]\n\nCommands:\n poll one pass: poll GitHub \u2192 gate \u2192 (assessment) \u2192 record; --post also drains queued replies\n work claim queued tickets \u2192 run the executor in a worktree \u2192 report\n watch poll + work + panel as one daemon (Ctrl-C stops after the current cycle)\n tickets list tickets; \"tickets stop <id>\" ends one\n panel serve the awaiting-human panel (http://127.0.0.1:8787)\n help show this usage\n\nCommon options:\n --repo owner/name repository to watch\n --agent-login <login> the agent's GitHub login (mention detection)\n --config <file> policy config (default policy.json, auto-scaffolded from examples/)\n --executor-config <file> executor config (default executor.json, auto-scaffolded from examples/)\n --db <file> state database (default .state/engine.db)\n --token <token> GitHub token (or env GITHUB_TOKEN)\n --assessment <mode> stub-positive | stub-negative | llm\n --interval <seconds> watch poll interval (\u00B120% jitter)\n --no-panel watch without the panel server\n --post poll also posts queued replies (needs a token)\n\nEnvironment: GITHUB_TOKEN, ASSESS_BASE_URL, ASSESS_MODEL, ASSESS_API_KEY, PANEL_PORT.\nDocs: https://github.com/vicfei/dsh-super-agent#quick-start";
|
|
1
|
+
export declare const USAGE = "dsh-super-agent \u2014 admission control, observe mode & tickets for any CLI coding agent\n\nUsage: dsh-super-agent <command> [options]\n\nCommands:\n poll one pass: poll GitHub \u2192 gate \u2192 (assessment) \u2192 record; --post also drains queued replies\n work claim queued tickets \u2192 run the executor in a worktree \u2192 report\n watch poll + work + panel as one daemon (Ctrl-C stops after the current cycle)\n tickets list tickets; \"tickets stop <id>\" ends one\n panel serve the awaiting-human panel (http://127.0.0.1:8787)\n merge sweep open ticket PRs \u2014 merge those meeting policy.merge requirements (default off)\n help show this usage\n\nCommon options:\n --repo owner/name repository to watch\n --agent-login <login> the agent's GitHub login (mention detection)\n --config <file> policy config (default policy.json, auto-scaffolded from examples/)\n --executor-config <file> executor config (default executor.json, auto-scaffolded from examples/)\n --db <file> state database (default .state/engine.db)\n --token <token> GitHub token (or env GITHUB_TOKEN)\n --assessment <mode> stub-positive | stub-negative | llm\n --interval <seconds> watch poll interval (\u00B120% jitter)\n --no-panel watch without the panel server\n --post poll also posts queued replies (needs a token)\n\nEnvironment: GITHUB_TOKEN, or GitHub App auth (GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY[_PATH],\noptional GITHUB_APP_INSTALLATION_ID), ASSESS_BASE_URL, ASSESS_MODEL, ASSESS_API_KEY, PANEL_PORT.\nDocs: https://github.com/vicfei/dsh-super-agent#quick-start";
|
|
2
2
|
export declare function examplePath(name: string): string | null;
|
|
3
3
|
/** Copy the packaged example to `target` when neither exists yet. True ⇒ caller should tell the user to edit & rerun. */
|
|
4
4
|
export declare function scaffoldFromExample(target: string, example: string): boolean;
|
|
5
|
-
export declare const NO_TOKEN_HINT = "[warn]
|
|
5
|
+
export declare const NO_TOKEN_HINT = "[warn] no GitHub credential \u2014 anonymous mode: public repos only, ~60 requests/hour,\n replies & PRs stay queued in the local outbox until a credential appears.\n export GITHUB_TOKEN (a read-only PAT is enough to start:\n https://github.com/settings/personal-access-tokens/new), or set up GitHub App auth \u2014 see README";
|
package/dist/usage.js
CHANGED
|
@@ -14,6 +14,7 @@ Commands:
|
|
|
14
14
|
watch poll + work + panel as one daemon (Ctrl-C stops after the current cycle)
|
|
15
15
|
tickets list tickets; "tickets stop <id>" ends one
|
|
16
16
|
panel serve the awaiting-human panel (http://127.0.0.1:8787)
|
|
17
|
+
merge sweep open ticket PRs — merge those meeting policy.merge requirements (default off)
|
|
17
18
|
help show this usage
|
|
18
19
|
|
|
19
20
|
Common options:
|
|
@@ -28,7 +29,8 @@ Common options:
|
|
|
28
29
|
--no-panel watch without the panel server
|
|
29
30
|
--post poll also posts queued replies (needs a token)
|
|
30
31
|
|
|
31
|
-
Environment: GITHUB_TOKEN,
|
|
32
|
+
Environment: GITHUB_TOKEN, or GitHub App auth (GITHUB_APP_ID + GITHUB_APP_PRIVATE_KEY[_PATH],
|
|
33
|
+
optional GITHUB_APP_INSTALLATION_ID), ASSESS_BASE_URL, ASSESS_MODEL, ASSESS_API_KEY, PANEL_PORT.
|
|
32
34
|
Docs: https://github.com/vicfei/dsh-super-agent#quick-start`;
|
|
33
35
|
const examplesDir = join(dirname(fileURLToPath(import.meta.url)), "..", "examples");
|
|
34
36
|
export function examplePath(name) {
|
|
@@ -43,8 +45,8 @@ export function scaffoldFromExample(target, example) {
|
|
|
43
45
|
copyFileSync(src, target);
|
|
44
46
|
return true;
|
|
45
47
|
}
|
|
46
|
-
export const NO_TOKEN_HINT = `[warn]
|
|
47
|
-
replies & PRs stay queued in the local outbox until a
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
export const NO_TOKEN_HINT = `[warn] no GitHub credential — anonymous mode: public repos only, ~60 requests/hour,
|
|
49
|
+
replies & PRs stay queued in the local outbox until a credential appears.
|
|
50
|
+
export GITHUB_TOKEN (a read-only PAT is enough to start:
|
|
51
|
+
https://github.com/settings/personal-access-tokens/new), or set up GitHub App auth — see README`;
|
|
50
52
|
//# sourceMappingURL=usage.js.map
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,4FAA4F;AAC5F,yEAAyE;AAEzE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,4FAA4F;AAC5F,yEAAyE;AAEzE,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;4DA2BuC,CAAC;AAE7D,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAEpF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAClC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAClC,CAAC;AAED,yHAAyH;AACzH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,OAAe;IACjE,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;;;uGAG0E,CAAC"}
|
package/dist/watch.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// one process, forever (or until SIGINT/SIGTERM — the current cycle finishes first).
|
|
3
3
|
// Interval gets jitter so a fleet of watchers doesn't thunder-herd the API; errors
|
|
4
4
|
// back off exponentially up to a 10-minute cap instead of dying.
|
|
5
|
+
import { runMergeSweep } from "./merge.js";
|
|
5
6
|
import { classify, formatOutcome } from "./runner.js";
|
|
6
7
|
import { runWork } from "./work.js";
|
|
7
8
|
const MAX_BACKOFF_MS = 10 * 60 * 1000;
|
|
@@ -44,8 +45,10 @@ async function runCycle(opts, log) {
|
|
|
44
45
|
const reports = await runWork(engine, executor, repo, client);
|
|
45
46
|
for (const r of reports)
|
|
46
47
|
log(`#${r.ticketId} [${r.outcome}] ${r.detail}`);
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
// Auto-merge sweep (M6-1) — no-op unless policy.merge.enabled; structural brakes inside.
|
|
49
|
+
const merged = client ? await runMergeSweep(engine, client, repo, policy, (l) => log(`[merge] ${l}`)) : [];
|
|
50
|
+
if (batch.length > 0 || reports.length > 0 || report.refusals.length > 0 || merged.length > 0) {
|
|
51
|
+
log(`— cycle: fresh=${report.fresh} opened=${report.ticketsOpened} resumed=${report.resumed} worked=${reports.length} merged=${merged.length}`);
|
|
49
52
|
return true;
|
|
50
53
|
}
|
|
51
54
|
return false;
|
package/dist/watch.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"watch.js","sourceRoot":"","sources":["../src/watch.ts"],"names":[],"mappings":"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"}
|
package/dist/work.d.ts
CHANGED
|
@@ -7,8 +7,18 @@ export interface WorkReport {
|
|
|
7
7
|
outcome: "done" | "failed" | "refused";
|
|
8
8
|
detail: string;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Git-over-https auth for the ticket-branch push (M6-2): installation tokens and PATs both
|
|
12
|
+
* authenticate as x-access-token. Scoped to https://github.com, so local file remotes (tests)
|
|
13
|
+
* and ssh remotes are untouched — those keep their ambient credentials.
|
|
14
|
+
*/
|
|
15
|
+
export declare function pushAuthArgs(token: string | undefined): string[];
|
|
10
16
|
export interface DeliveryOutcome {
|
|
11
17
|
prUrl?: string;
|
|
18
|
+
/** Set when a PR opened — enough for the engine to track it for the merge sweep. */
|
|
19
|
+
prNumber?: number;
|
|
20
|
+
branch?: string;
|
|
21
|
+
headSha?: string;
|
|
12
22
|
error?: string;
|
|
13
23
|
}
|
|
14
24
|
/**
|
package/dist/work.js
CHANGED
|
@@ -13,6 +13,17 @@ function git(dir, args) {
|
|
|
13
13
|
child.on("close", (code) => (code === 0 ? resolve(out.trim()) : reject(new Error(`git ${args.join(" ")} → ${code}: ${err.trim().slice(0, 200)}`))));
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Git-over-https auth for the ticket-branch push (M6-2): installation tokens and PATs both
|
|
18
|
+
* authenticate as x-access-token. Scoped to https://github.com, so local file remotes (tests)
|
|
19
|
+
* and ssh remotes are untouched — those keep their ambient credentials.
|
|
20
|
+
*/
|
|
21
|
+
export function pushAuthArgs(token) {
|
|
22
|
+
if (!token)
|
|
23
|
+
return [];
|
|
24
|
+
const basic = Buffer.from(`x-access-token:${token}`).toString("base64");
|
|
25
|
+
return ["-c", `http.https://github.com/.extraheader=AUTHORIZATION: basic ${basic}`];
|
|
26
|
+
}
|
|
16
27
|
/**
|
|
17
28
|
* PR delivery (docs/003: results return via the Source): if the worker committed anything
|
|
18
29
|
* beyond its base, push the ticket branch and open a pull request. Delivery failures
|
|
@@ -24,7 +35,8 @@ export async function deliverPullRequest(client, repo, ticket, trigger, result)
|
|
|
24
35
|
if (count === 0)
|
|
25
36
|
return {}; // nothing to deliver
|
|
26
37
|
const branch = `dsh/ticket-${ticket.id}`;
|
|
27
|
-
await git(result.worktree, ["
|
|
38
|
+
const headSha = await git(result.worktree, ["rev-parse", "HEAD"]);
|
|
39
|
+
await git(result.worktree, [...pushAuthArgs(await client.currentToken()), "push", "origin", `HEAD:refs/heads/${branch}`]);
|
|
28
40
|
const base = await client.getDefaultBranch(repo);
|
|
29
41
|
const firstLine = trigger.body.trim().split("\n")[0].slice(0, 72) || "ticket work";
|
|
30
42
|
const pr = await client.createPullRequest(repo, {
|
|
@@ -47,7 +59,7 @@ export async function deliverPullRequest(client, repo, ticket, trigger, result)
|
|
|
47
59
|
"```",
|
|
48
60
|
].join("\n"),
|
|
49
61
|
});
|
|
50
|
-
return { prUrl: pr.html_url };
|
|
62
|
+
return { prUrl: pr.html_url, prNumber: pr.number, branch, headSha };
|
|
51
63
|
}
|
|
52
64
|
catch (e) {
|
|
53
65
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
@@ -74,6 +86,12 @@ export async function runWork(engine, executor, repo, client) {
|
|
|
74
86
|
if (ok) {
|
|
75
87
|
engine.completeTicket(t.id);
|
|
76
88
|
const delivery = client ? await deliverPullRequest(client, repo, t, { body: t.body, author: t.author }, result) : {};
|
|
89
|
+
if (delivery.prNumber !== undefined) {
|
|
90
|
+
engine.recordDelivery({
|
|
91
|
+
repo, prNumber: delivery.prNumber, ticketId: t.id, threadId: t.threadId,
|
|
92
|
+
branch: delivery.branch, headSha: delivery.headSha,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
77
95
|
let body = reportBody(t.id, result);
|
|
78
96
|
if (delivery.prUrl)
|
|
79
97
|
body += `\n\nPR: ${delivery.prUrl}`;
|