@perrylink/dsh-github 0.4.0 → 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.es.md +29 -14
- package/README.hi.md +29 -14
- package/README.md +52 -14
- package/README.pt.md +30 -15
- package/README.zh-CN.md +52 -14
- 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 +138 -0
- package/scripts/action-post.mjs +48 -0
- package/scripts/check-readmes.mjs +113 -0
- package/scripts/prepare.mjs +34 -0
package/lib/approval-gate.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
const ACTION_BY_TOOL = {
|
|
2
2
|
pr_create: 'pr.create',
|
|
3
|
+
pr_merge: 'pr.merge',
|
|
4
|
+
pr_update: 'pr.update',
|
|
3
5
|
review_post: 'review.post',
|
|
4
6
|
issue_open: 'issue.create',
|
|
5
7
|
issue_comment: 'issue.comment',
|
|
6
8
|
issue_close: 'issue.close',
|
|
9
|
+
ci_run: 'ci.run',
|
|
7
10
|
};
|
|
8
11
|
/** Tools the gate intercepts; everything else delegates via next(). */
|
|
9
12
|
const WRITE_TOOLS = new Set(Object.keys(ACTION_BY_TOOL));
|
|
@@ -27,13 +30,35 @@ function askReason(toolName, args, state) {
|
|
|
27
30
|
if (toolName === 'pr_create') {
|
|
28
31
|
return `create GitHub pull request ${titledPreview(args)}`;
|
|
29
32
|
}
|
|
33
|
+
if (toolName === 'pr_merge') {
|
|
34
|
+
const target = typeof args.pr === 'string' ? ` ${args.pr}` : '';
|
|
35
|
+
const method = typeof args.mergeMethod === 'string' ? args.mergeMethod : 'merge';
|
|
36
|
+
const deleteBranch = args.deleteBranch === true ? ' (delete head branch after merge)' : '';
|
|
37
|
+
return `merge GitHub pull request${target} via ${method}${deleteBranch}`;
|
|
38
|
+
}
|
|
39
|
+
if (toolName === 'pr_update') {
|
|
40
|
+
const target = typeof args.pr === 'string' ? ` ${args.pr}` : '';
|
|
41
|
+
const edits = [];
|
|
42
|
+
if (typeof args.title === 'string')
|
|
43
|
+
edits.push(`title "${firstLine(args.title, 60)}"`);
|
|
44
|
+
if (typeof args.state === 'string')
|
|
45
|
+
edits.push(`state ${args.state}`);
|
|
46
|
+
if (typeof args.base === 'string')
|
|
47
|
+
edits.push(`base ${args.base}`);
|
|
48
|
+
if (typeof args.body === 'string' && args.body.trim().length > 0)
|
|
49
|
+
edits.push(`body ${args.body.trim().length} chars`);
|
|
50
|
+
return `update GitHub pull request${target}${edits.length > 0 ? ` (${edits.join('; ')})` : ''}`;
|
|
51
|
+
}
|
|
30
52
|
if (toolName === 'review_post') {
|
|
31
53
|
if (typeof args.jobId !== 'string')
|
|
32
54
|
return 'post GitHub review comments';
|
|
33
55
|
const record = state.records.get(args.jobId);
|
|
56
|
+
const isModelReview = record?.report !== null && record?.report !== undefined && record.report.findings.length === 0 && record.report.summary.startsWith('model review');
|
|
34
57
|
const target = record === undefined || record.report === null
|
|
35
58
|
? `job ${args.jobId}`
|
|
36
|
-
:
|
|
59
|
+
: isModelReview
|
|
60
|
+
? `PR #${record.pr} (model review)`
|
|
61
|
+
: `PR #${record.pr} (${record.report.findings.length} finding(s))`;
|
|
37
62
|
const mode = args.mode === 'inline' ? 'inline' : 'summary';
|
|
38
63
|
const override = typeof args.body === 'string' && args.body.trim().length > 0
|
|
39
64
|
? `; body override: ${firstLine(args.body.trim(), 80)}`
|
|
@@ -52,11 +77,21 @@ function askReason(toolName, args, state) {
|
|
|
52
77
|
const number = typeof args.issueNumber === 'number' ? ` #${args.issueNumber}` : '';
|
|
53
78
|
return `close GitHub issue${number}`;
|
|
54
79
|
}
|
|
80
|
+
if (toolName === 'ci_run') {
|
|
81
|
+
const target = typeof args.pr === 'string' ? ` ${args.pr}` : '';
|
|
82
|
+
const task = typeof args.task === 'string' ? args.task : 'review';
|
|
83
|
+
return `run CI ${task} for GitHub pull request${target} (posts review comments and a status check)`;
|
|
84
|
+
}
|
|
55
85
|
return 'perform a GitHub write action';
|
|
56
86
|
}
|
|
57
87
|
/**
|
|
58
88
|
* Register the approval gate. Registration is an effect: disposing the plugin
|
|
59
89
|
* fiber removes the listener.
|
|
90
|
+
*
|
|
91
|
+
* Unattended CI runs (`DSH_GITHUB_CI_DRIVER=1`) auto-allow exactly the
|
|
92
|
+
* actions listed in `ci.autoApprove` — the composite action composes that
|
|
93
|
+
* allowlist for the write the pipeline needs. Interactive sessions always
|
|
94
|
+
* ask, and actions missing from `allowedActions` stay denied everywhere.
|
|
60
95
|
* @param ctx - plugin context; the listener lives on the shared tools pipeline.
|
|
61
96
|
* @param state - plugin state used to enrich approval reasons.
|
|
62
97
|
* @returns the effect disposer.
|
|
@@ -69,6 +104,9 @@ export function registerApprovalGate(ctx, state) {
|
|
|
69
104
|
if (action === undefined || !state.config.allowedActions.includes(action)) {
|
|
70
105
|
return { kind: 'deny', reason: `dsh-github: action "${action ?? exec.name}" is not in allowedActions` };
|
|
71
106
|
}
|
|
107
|
+
if (state.isCiDriver && state.config.ci.autoApprove.includes(action)) {
|
|
108
|
+
return { kind: 'allow' };
|
|
109
|
+
}
|
|
72
110
|
return { kind: 'ask', reason: `dsh-github: ${askReason(exec.name, argumentsAsRecord(exec), state)}` };
|
|
73
111
|
});
|
|
74
112
|
}
|
package/lib/approval-gate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../src/approval-gate.ts"],"names":[],"mappings":"AAmBA,MAAM,cAAc,GAAiC;IACnD,SAAS,EAAE,WAAW;IACtB,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,cAAc;IAC1B,aAAa,EAAE,eAAe;IAC9B,WAAW,EAAE,aAAa;
|
|
1
|
+
{"version":3,"file":"approval-gate.js","sourceRoot":"","sources":["../src/approval-gate.ts"],"names":[],"mappings":"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"}
|
package/lib/ci/bot.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The PR review bot: a poll-driven scanner that reviews open pull requests
|
|
3
|
+
* with the shared CI pipeline and posts idempotent inline comments plus the
|
|
4
|
+
* status-check gate.
|
|
5
|
+
*
|
|
6
|
+
* Polling is the transport: a webhook endpoint would need a public listener
|
|
7
|
+
* (out of scope for a plugin), so the bot re-scans open PRs on
|
|
8
|
+
* `ci.pollIntervalMs` and treats every pass as event delivery — the pipeline's
|
|
9
|
+
* check-run + review-marker idempotency makes repeat deliveries harmless.
|
|
10
|
+
* `/ci scan` delivers the same "event" on demand. Concurrency inside one scan
|
|
11
|
+
* is capped by `ci.maxConcurrent`.
|
|
12
|
+
*
|
|
13
|
+
* Bot writes are plugin-internal automation, not model tool calls: they do
|
|
14
|
+
* not traverse the approval gate. They are switched by `ci.enabled` and
|
|
15
|
+
* scoped to exactly two GitHub surfaces — review comments and check runs —
|
|
16
|
+
* with the minimal-permission token resolved per operation.
|
|
17
|
+
* @module dsh-github/ci/bot
|
|
18
|
+
*/
|
|
19
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
20
|
+
import type { CommandsService } from '../types.ts';
|
|
21
|
+
import type { GithubState } from '../state.ts';
|
|
22
|
+
/** Live bot status surfaced by `/ci status`. */
|
|
23
|
+
export interface CiBotStatus {
|
|
24
|
+
polling: boolean;
|
|
25
|
+
scanning: boolean;
|
|
26
|
+
intervalMs: number;
|
|
27
|
+
lastScanAt: number | null;
|
|
28
|
+
lastScanPrs: number;
|
|
29
|
+
lastScanNeedsChanges: number;
|
|
30
|
+
lastScanErrors: number;
|
|
31
|
+
lastScanSummary: string;
|
|
32
|
+
}
|
|
33
|
+
/** Shared bot state; one instance per plugin fiber. */
|
|
34
|
+
export interface CiBot {
|
|
35
|
+
status(): CiBotStatus;
|
|
36
|
+
scan(signal?: AbortSignal): Promise<string>;
|
|
37
|
+
setPolling(enabled: boolean): void;
|
|
38
|
+
dispose(): void;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create the polling bot and register the `/ci` command family. Everything
|
|
42
|
+
* here is an effect of the calling fiber — disposing the plugin stops the
|
|
43
|
+
* interval and removes the commands.
|
|
44
|
+
* @param ctx - plugin context (owns the effect lifetime).
|
|
45
|
+
* @param commands - the host command registry.
|
|
46
|
+
* @param state - shared plugin state.
|
|
47
|
+
* @returns the bot handle (also returned by the effect disposer path).
|
|
48
|
+
*/
|
|
49
|
+
export declare function registerCiBot(ctx: Context, commands: CommandsService, state: GithubState): () => void;
|
|
50
|
+
//# sourceMappingURL=bot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.d.ts","sourceRoot":"","sources":["../../src/ci/bot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAoC,eAAe,EAAE,MAAM,aAAa,CAAA;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAG9C,gDAAgD;AAChD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;CACxB;AAOD,uDAAuD;AACvD,MAAM,WAAW,KAAK;IACpB,MAAM,IAAI,WAAW,CAAA;IACrB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IAC3C,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAA;IAClC,OAAO,IAAI,IAAI,CAAA;CAChB;AAID;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM,IAAI,CAsJrG"}
|
package/lib/ci/bot.js
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { runCiPipeline } from "./pipeline.js";
|
|
2
|
+
const SCAN_CAP = 50;
|
|
3
|
+
/**
|
|
4
|
+
* Create the polling bot and register the `/ci` command family. Everything
|
|
5
|
+
* here is an effect of the calling fiber — disposing the plugin stops the
|
|
6
|
+
* interval and removes the commands.
|
|
7
|
+
* @param ctx - plugin context (owns the effect lifetime).
|
|
8
|
+
* @param commands - the host command registry.
|
|
9
|
+
* @param state - shared plugin state.
|
|
10
|
+
* @returns the bot handle (also returned by the effect disposer path).
|
|
11
|
+
*/
|
|
12
|
+
export function registerCiBot(ctx, commands, state) {
|
|
13
|
+
let polling = state.config.ci.pollIntervalMs > 0;
|
|
14
|
+
let scanning = false;
|
|
15
|
+
let lastScanAt = null;
|
|
16
|
+
let lastScanPrs = 0;
|
|
17
|
+
let lastScanNeedsChanges = 0;
|
|
18
|
+
let lastScanErrors = 0;
|
|
19
|
+
let lastScanSummary = 'no scan yet';
|
|
20
|
+
const status = () => ({
|
|
21
|
+
polling,
|
|
22
|
+
scanning,
|
|
23
|
+
intervalMs: state.config.ci.pollIntervalMs,
|
|
24
|
+
lastScanAt,
|
|
25
|
+
lastScanPrs,
|
|
26
|
+
lastScanNeedsChanges,
|
|
27
|
+
lastScanErrors,
|
|
28
|
+
lastScanSummary,
|
|
29
|
+
});
|
|
30
|
+
const setPolling = (enabled) => {
|
|
31
|
+
polling = enabled;
|
|
32
|
+
};
|
|
33
|
+
/** One pass over the open PRs: pipeline per PR under the concurrency cap. */
|
|
34
|
+
const scan = async (signal) => {
|
|
35
|
+
if (scanning)
|
|
36
|
+
return 'a scan is already running';
|
|
37
|
+
scanning = true;
|
|
38
|
+
const started = Date.now();
|
|
39
|
+
let needsChanges = 0;
|
|
40
|
+
let errors = 0;
|
|
41
|
+
let reviewed = 0;
|
|
42
|
+
try {
|
|
43
|
+
const token = await state.resolveToken(signal);
|
|
44
|
+
if (!token.ok) {
|
|
45
|
+
lastScanErrors += 1;
|
|
46
|
+
lastScanSummary = `scan failed: ${token.error.message}`;
|
|
47
|
+
ctx.logger.warn(`dsh-github ci bot: ${token.error.message}`);
|
|
48
|
+
return lastScanSummary;
|
|
49
|
+
}
|
|
50
|
+
const client = state.client(token.token.value);
|
|
51
|
+
const repo = await state.resolveRepo(undefined, signal);
|
|
52
|
+
if (!repo.ok) {
|
|
53
|
+
lastScanErrors += 1;
|
|
54
|
+
lastScanSummary = `scan failed: ${repo.message}`;
|
|
55
|
+
ctx.logger.warn(`dsh-github ci bot: ${repo.message}`);
|
|
56
|
+
return lastScanSummary;
|
|
57
|
+
}
|
|
58
|
+
const open = await client.requestJson('GET', `/repos/${repo.repo}/pulls?state=open&per_page=${SCAN_CAP}`, { signal });
|
|
59
|
+
const prs = open.data.filter(item => item.number !== undefined).slice(0, SCAN_CAP);
|
|
60
|
+
const cap = state.config.ci.maxConcurrent;
|
|
61
|
+
const queue = [...prs];
|
|
62
|
+
const workers = Array.from({ length: Math.min(cap, queue.length) }, async () => {
|
|
63
|
+
for (;;) {
|
|
64
|
+
const item = queue.shift();
|
|
65
|
+
if (item === undefined)
|
|
66
|
+
return;
|
|
67
|
+
try {
|
|
68
|
+
const outcome = await runCiPipeline(state, { repo: repo.repo, pr: item.number, task: 'review', signal });
|
|
69
|
+
if (outcome.status === 'error') {
|
|
70
|
+
errors += 1;
|
|
71
|
+
ctx.logger.warn(`dsh-github ci bot: PR #${item.number} review failed: ${outcome.message}`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
reviewed += 1;
|
|
75
|
+
if (outcome.verdict === 'needs-changes')
|
|
76
|
+
needsChanges += 1;
|
|
77
|
+
ctx.logger.info(`dsh-github ci bot: PR #${item.number} → ${outcome.verdict}${outcome.alreadyReviewed ? ' (already reviewed)' : ''}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
errors += 1;
|
|
82
|
+
ctx.logger.warn(`dsh-github ci bot: PR #${item.number} review threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
await Promise.all(workers);
|
|
87
|
+
lastScanAt = Date.now();
|
|
88
|
+
lastScanPrs = reviewed;
|
|
89
|
+
lastScanNeedsChanges = needsChanges;
|
|
90
|
+
lastScanErrors = errors;
|
|
91
|
+
lastScanSummary = `scanned ${prs.length} open PR(s) in ${repo.repo}: ${reviewed} reviewed, ${needsChanges} needs-changes, ${errors} error(s) (${Date.now() - started}ms)`;
|
|
92
|
+
return lastScanSummary;
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
scanning = false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const timer = state.config.ci.pollIntervalMs > 0
|
|
99
|
+
? setInterval(() => {
|
|
100
|
+
if (polling)
|
|
101
|
+
void scan().catch(() => { });
|
|
102
|
+
}, state.config.ci.pollIntervalMs)
|
|
103
|
+
: undefined;
|
|
104
|
+
timer?.unref?.();
|
|
105
|
+
const register = (name, description, hint, handler) => commands.register({ name, description, input: { hint }, handler });
|
|
106
|
+
const disposers = [
|
|
107
|
+
register('ci', 'CI review bot: scan PRs, publish reviews and the status-check gate', 'scan | status | start | stop | run <pr>', async (invocation) => {
|
|
108
|
+
const [sub, ...rest] = invocation.rawInput.trim().split(/\s+/);
|
|
109
|
+
if (sub === undefined || sub.length === 0) {
|
|
110
|
+
const current = status();
|
|
111
|
+
return { kind: 'success', text: `CI bot: polling ${current.polling ? `on (every ${current.intervalMs}ms)` : 'off'}\n${current.lastScanSummary}\nUsage: /ci scan | status | start | stop | run <pr>` };
|
|
112
|
+
}
|
|
113
|
+
if (sub === 'scan') {
|
|
114
|
+
const result = await scan(invocation.signal);
|
|
115
|
+
return { kind: 'success', text: result };
|
|
116
|
+
}
|
|
117
|
+
if (sub === 'status') {
|
|
118
|
+
const current = status();
|
|
119
|
+
return {
|
|
120
|
+
kind: 'success',
|
|
121
|
+
text: `polling: ${current.polling ? `on (every ${current.intervalMs}ms)` : 'off'}\n`
|
|
122
|
+
+ `last scan: ${current.lastScanAt === null ? 'never' : new Date(current.lastScanAt).toISOString()}\n`
|
|
123
|
+
+ `${current.lastScanSummary}`,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (sub === 'start') {
|
|
127
|
+
if (state.config.ci.pollIntervalMs === 0) {
|
|
128
|
+
return { kind: 'error', text: 'ci.pollIntervalMs is 0: set a positive interval in cordis.yml to enable polling (or keep using /ci scan on demand).' };
|
|
129
|
+
}
|
|
130
|
+
setPolling(true);
|
|
131
|
+
return { kind: 'success', text: `CI bot polling enabled (every ${state.config.ci.pollIntervalMs}ms). Set ci.pollIntervalMs to 0 to disable at boot.` };
|
|
132
|
+
}
|
|
133
|
+
if (sub === 'stop') {
|
|
134
|
+
setPolling(false);
|
|
135
|
+
return { kind: 'success', text: 'CI bot polling disabled; /ci scan still runs on demand.' };
|
|
136
|
+
}
|
|
137
|
+
if (sub === 'run') {
|
|
138
|
+
const target = rest.join(' ').trim();
|
|
139
|
+
if (target.length === 0)
|
|
140
|
+
return { kind: 'error', text: 'Usage: /ci run <pr> (number, #number, owner/repo#number, or pull URL)' };
|
|
141
|
+
const ref = state.parsePrRef(target);
|
|
142
|
+
if (ref === null)
|
|
143
|
+
return { kind: 'error', text: `"${target}" is not a PR reference. Use a number, "#number", "owner/repo#number", or a pull URL.` };
|
|
144
|
+
const repoResult = ref.repo !== undefined ? { ok: true, repo: ref.repo } : await state.resolveRepo(undefined, invocation.signal);
|
|
145
|
+
if (!repoResult.ok)
|
|
146
|
+
return { kind: 'error', text: `${repoResult.message}. ${repoResult.guidance}` };
|
|
147
|
+
const outcome = await runCiPipeline(state, { repo: repoResult.repo, pr: ref.number, task: 'review', signal: invocation.signal });
|
|
148
|
+
if (outcome.status === 'error')
|
|
149
|
+
return { kind: 'error', text: `${outcome.message}${outcome.guidance !== undefined ? `\n${outcome.guidance}` : ''}` };
|
|
150
|
+
return {
|
|
151
|
+
kind: 'success',
|
|
152
|
+
text: `PR #${outcome.pr} (${outcome.repo}): verdict ${outcome.verdict}${outcome.alreadyReviewed ? ' (already reviewed at this head commit)' : ''}\n${outcome.summary}`
|
|
153
|
+
+ `${outcome.checkRun !== undefined ? `\ncheck: ${outcome.checkRun.url} (${outcome.checkRun.conclusion})` : ''}`
|
|
154
|
+
+ `${outcome.review !== undefined && outcome.review.url.length > 0 ? `\nreview: ${outcome.review.url}` : ''}`
|
|
155
|
+
+ `${outcome.files !== undefined ? `\nreports: ${outcome.files.json} · ${outcome.files.markdown}` : ''}`,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { kind: 'error', text: `unknown /ci subcommand "${sub}". Usage: /ci scan | status | start | stop | run <pr>` };
|
|
159
|
+
}),
|
|
160
|
+
];
|
|
161
|
+
return () => {
|
|
162
|
+
if (timer !== undefined)
|
|
163
|
+
clearInterval(timer);
|
|
164
|
+
for (const dispose of disposers)
|
|
165
|
+
dispose();
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=bot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bot.js","sourceRoot":"","sources":["../../src/ci/bot.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AA2B7C,MAAM,QAAQ,GAAG,EAAE,CAAA;AAEnB;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY,EAAE,QAAyB,EAAE,KAAkB;IACvF,IAAI,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC,CAAA;IAChD,IAAI,QAAQ,GAAG,KAAK,CAAA;IACpB,IAAI,UAAU,GAAkB,IAAI,CAAA;IACpC,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,oBAAoB,GAAG,CAAC,CAAA;IAC5B,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,IAAI,eAAe,GAAG,aAAa,CAAA;IAEnC,MAAM,MAAM,GAAG,GAAgB,EAAE,CAAC,CAAC;QACjC,OAAO;QACP,QAAQ;QACR,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc;QAC1C,UAAU;QACV,WAAW;QACX,oBAAoB;QACpB,cAAc;QACd,eAAe;KAChB,CAAC,CAAA;IAEF,MAAM,UAAU,GAAG,CAAC,OAAgB,EAAQ,EAAE;QAC5C,OAAO,GAAG,OAAO,CAAA;IACnB,CAAC,CAAA;IAED,6EAA6E;IAC7E,MAAM,IAAI,GAAG,KAAK,EAAE,MAAoB,EAAmB,EAAE;QAC3D,IAAI,QAAQ;YAAE,OAAO,2BAA2B,CAAA;QAChD,QAAQ,GAAG,IAAI,CAAA;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;QAC1B,IAAI,YAAY,GAAG,CAAC,CAAA;QACpB,IAAI,MAAM,GAAG,CAAC,CAAA;QACd,IAAI,QAAQ,GAAG,CAAC,CAAA;QAChB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;YAC9C,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;gBACd,cAAc,IAAI,CAAC,CAAA;gBACnB,eAAe,GAAG,gBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAA;gBACvD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC5D,OAAO,eAAe,CAAA;YACxB,CAAC;YACD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC9C,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;YACvD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;gBACb,cAAc,IAAI,CAAC,CAAA;gBACnB,eAAe,GAAG,gBAAgB,IAAI,CAAC,OAAO,EAAE,CAAA;gBAChD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,sBAAsB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAA;gBACrD,OAAO,eAAe,CAAA;YACxB,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAoB,KAAK,EAAE,UAAU,IAAI,CAAC,IAAI,8BAA8B,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAA;YACxI,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAA;YAClF,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAA;YACzC,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,CAAA;YACtB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI,EAAE;gBAC7E,SAAS,CAAC;oBACR,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,CAAA;oBAC1B,IAAI,IAAI,KAAK,SAAS;wBAAE,OAAM;oBAC9B,IAAI,CAAC;wBACH,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,EAAE,IAAI,CAAC,MAAgB,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAA;wBAClH,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;4BAC/B,MAAM,IAAI,CAAC,CAAA;4BACX,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,MAAM,mBAAmB,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;wBAC5F,CAAC;6BAAM,CAAC;4BACN,QAAQ,IAAI,CAAC,CAAA;4BACb,IAAI,OAAO,CAAC,OAAO,KAAK,eAAe;gCAAE,YAAY,IAAI,CAAC,CAAA;4BAC1D,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,MAAM,MAAM,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;wBACtI,CAAC;oBACH,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,MAAM,IAAI,CAAC,CAAA;wBACX,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,0BAA0B,IAAI,CAAC,MAAM,kBAAkB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;oBAClI,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAA;YACF,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;YAC1B,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAA;YACvB,WAAW,GAAG,QAAQ,CAAA;YACtB,oBAAoB,GAAG,YAAY,CAAA;YACnC,cAAc,GAAG,MAAM,CAAA;YACvB,eAAe,GAAG,WAAW,GAAG,CAAC,MAAM,kBAAkB,IAAI,CAAC,IAAI,KAAK,QAAQ,cAAc,YAAY,mBAAmB,MAAM,cAAc,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,KAAK,CAAA;YACzK,OAAO,eAAe,CAAA;QACxB,CAAC;gBAAS,CAAC;YACT,QAAQ,GAAG,KAAK,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,GAAG,CAAC;QAC9C,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE;YACf,IAAI,OAAO;gBAAE,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC1C,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,CAAC;QACpC,CAAC,CAAC,SAAS,CAAA;IACb,KAAK,EAAE,KAAK,EAAE,EAAE,CAAA;IAEhB,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAE,WAAmB,EAAE,IAAY,EAAE,OAAkF,EAAc,EAAE,CACnK,QAAQ,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;IAEpE,MAAM,SAAS,GAAG;QAChB,QAAQ,CAAC,IAAI,EAAE,oEAAoE,EAAE,yCAAyC,EAAE,KAAK,EAAE,UAAU,EAAE,EAAE;YACnJ,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAC9D,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAA;gBACxB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,mBAAmB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,eAAe,sDAAsD,EAAE,CAAA;YACvM,CAAC;YACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;gBAC5C,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;YAC1C,CAAC;YACD,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;gBACrB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAA;gBACxB,OAAO;oBACL,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,YAAY,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;0BAChF,cAAc,OAAO,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,WAAW,EAAE,IAAI;0BACpG,GAAG,OAAO,CAAC,eAAe,EAAE;iBACjC,CAAA;YACH,CAAC;YACD,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;gBACpB,IAAI,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;oBACzC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,qHAAqH,EAAE,CAAA;gBACvJ,CAAC;gBACD,UAAU,CAAC,IAAI,CAAC,CAAA;gBAChB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,iCAAiC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,qDAAqD,EAAE,CAAA;YACxJ,CAAC;YACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACnB,UAAU,CAAC,KAAK,CAAC,CAAA;gBACjB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,yDAAyD,EAAE,CAAA;YAC7F,CAAC;YACD,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;gBAClB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAA;gBACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,uEAAuE,EAAE,CAAA;gBAChI,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAA;gBACpC,IAAI,GAAG,KAAK,IAAI;oBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,MAAM,uFAAuF,EAAE,CAAA;gBACnJ,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAa,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,WAAW,CAAC,SAAS,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;gBACzI,IAAI,CAAC,UAAU,CAAC,EAAE;oBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC,OAAO,KAAK,UAAU,CAAC,QAAQ,EAAE,EAAE,CAAA;gBACnG,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,EAAE,EAAE,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAA;gBAChI,IAAI,OAAO,CAAC,MAAM,KAAK,OAAO;oBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAA;gBACpJ,OAAO;oBACL,IAAI,EAAE,SAAS;oBACf,IAAI,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,IAAI,cAAc,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE;0BAClK,GAAG,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,OAAO,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;0BAC9G,GAAG,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;0BAC3G,GAAG,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,cAAc,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;iBAC3G,CAAA;YACH,CAAC;YACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,2BAA2B,GAAG,uDAAuD,EAAE,CAAA;QACvH,CAAC,CAAC;KACH,CAAA;IAED,OAAO,GAAG,EAAE;QACV,IAAI,KAAK,KAAK,SAAS;YAAE,aAAa,CAAC,KAAK,CAAC,CAAA;QAC7C,KAAK,MAAM,OAAO,IAAI,SAAS;YAAE,OAAO,EAAE,CAAA;IAC5C,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Finding } from '../review.ts';
|
|
2
|
+
import { type GithubState, type RateLimitValue } from '../state.ts';
|
|
3
|
+
/** The gate verdict: pass, needs changes, or skipped by the filters. */
|
|
4
|
+
export type CiVerdict = 'pass' | 'needs-changes' | 'skipped';
|
|
5
|
+
/** Tasks the pipeline (and the `ci_run` tool) understands. */
|
|
6
|
+
export type CiTask = 'review' | 'analyze' | 'publish';
|
|
7
|
+
export interface CheckRunValue {
|
|
8
|
+
id: number;
|
|
9
|
+
url: string;
|
|
10
|
+
conclusion: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ReviewPostValue {
|
|
13
|
+
url: string;
|
|
14
|
+
inlineComments: number;
|
|
15
|
+
}
|
|
16
|
+
/** Successful pipeline result — the canonical JSON the `ci_run` tool returns. */
|
|
17
|
+
export interface CiRunResult {
|
|
18
|
+
status: 'ok';
|
|
19
|
+
repo: string;
|
|
20
|
+
pr: number;
|
|
21
|
+
headSha: string;
|
|
22
|
+
verdict: CiVerdict;
|
|
23
|
+
engine: 'static' | 'model';
|
|
24
|
+
findings: Finding[];
|
|
25
|
+
summary: string;
|
|
26
|
+
truncated: boolean;
|
|
27
|
+
/** A previous run for this head commit already published its outcome. */
|
|
28
|
+
alreadyReviewed: boolean;
|
|
29
|
+
/** Present when the diff text was requested (analyze task). */
|
|
30
|
+
diffText?: string;
|
|
31
|
+
checkRun?: CheckRunValue;
|
|
32
|
+
review?: ReviewPostValue;
|
|
33
|
+
files?: {
|
|
34
|
+
json: string;
|
|
35
|
+
markdown: string;
|
|
36
|
+
};
|
|
37
|
+
rateLimit: RateLimitValue;
|
|
38
|
+
}
|
|
39
|
+
/** Structured failure — token-free by construction. */
|
|
40
|
+
export interface CiRunError {
|
|
41
|
+
status: 'error';
|
|
42
|
+
code: string;
|
|
43
|
+
message: string;
|
|
44
|
+
guidance?: string;
|
|
45
|
+
rateLimit?: RateLimitValue;
|
|
46
|
+
}
|
|
47
|
+
export type CiRunOutcome = CiRunResult | CiRunError;
|
|
48
|
+
export interface CiRunOptions {
|
|
49
|
+
repo: string;
|
|
50
|
+
pr: number;
|
|
51
|
+
task: CiTask;
|
|
52
|
+
/** Diff cap for this run; defaults to the plugin config. */
|
|
53
|
+
maxDiffChars?: number;
|
|
54
|
+
/** Review-body override (model-authored, publish task). */
|
|
55
|
+
body?: string;
|
|
56
|
+
/** Extra findings authored by the model (publish task); merged with static ones. */
|
|
57
|
+
findings?: Finding[];
|
|
58
|
+
/** Post review comments; defaults to `ci.postComments`. */
|
|
59
|
+
postComments?: boolean;
|
|
60
|
+
/** Publish the status check; defaults to true for review/publish. */
|
|
61
|
+
postCheck?: boolean;
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
}
|
|
64
|
+
/** First line of the review body — the idempotency marker. */
|
|
65
|
+
export declare function reviewMarker(headSha: string): string;
|
|
66
|
+
/** Whether a review body carries our marker for the given head commit. */
|
|
67
|
+
export declare function hasReviewMarker(body: string | undefined, headSha: string): boolean;
|
|
68
|
+
/** Conclude the verdict from the findings under the configured `failOn` policy. */
|
|
69
|
+
export declare function verdictFor(findings: readonly Finding[], failOn: 'error' | 'warning'): CiVerdict;
|
|
70
|
+
/** Markdown report body written next to the JSON result. */
|
|
71
|
+
export declare function formatMarkdownReport(result: CiRunResult, options: {
|
|
72
|
+
blocking: boolean;
|
|
73
|
+
checkName: string;
|
|
74
|
+
}): string;
|
|
75
|
+
/**
|
|
76
|
+
* Run one CI pass over a pull request. Pure in the sense that every GitHub
|
|
77
|
+
* interaction goes through the per-operation token and the shared client;
|
|
78
|
+
* callers (bot, tool) own their own concurrency control.
|
|
79
|
+
* @param state - shared plugin state.
|
|
80
|
+
* @param options - target repo/PR, task, caps, and overrides.
|
|
81
|
+
* @returns the structured outcome; failures are token-free error variants.
|
|
82
|
+
*/
|
|
83
|
+
export declare function runCiPipeline(state: GithubState, options: CiRunOptions): Promise<CiRunOutcome>;
|
|
84
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/ci/pipeline.ts"],"names":[],"mappings":"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"}
|