@open330/oac-completion 2026.2.17

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Open330
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.
@@ -0,0 +1,87 @@
1
+ import { ResolvedRepo, Task, ExecutionResult, OacConfig, OacEventBus } from '@open330/oac-core';
2
+ import { Octokit } from '@octokit/rest';
3
+
4
+ interface PRCreationParams {
5
+ repo: ResolvedRepo;
6
+ task: Task;
7
+ result: ExecutionResult;
8
+ branchName: string;
9
+ baseBranch: string;
10
+ }
11
+ interface CreatedPR {
12
+ number: number;
13
+ url: string;
14
+ sha: string;
15
+ }
16
+ interface CompletionResult {
17
+ prUrl?: string;
18
+ commitSha?: string;
19
+ summary: string;
20
+ filesChanged: number;
21
+ tokensUsed: number;
22
+ }
23
+ interface ExternalTaskRef {
24
+ provider: string;
25
+ externalId: string;
26
+ url?: string;
27
+ }
28
+ interface ProjectManagementProvider {
29
+ readonly id: string;
30
+ readonly name: string;
31
+ ping(): Promise<boolean>;
32
+ notifyStarted(ref: ExternalTaskRef): Promise<void>;
33
+ notifyPRCreated(ref: ExternalTaskRef, prUrl: string): Promise<void>;
34
+ notifyCompleted(ref: ExternalTaskRef, result: CompletionResult): Promise<void>;
35
+ notifyFailed(ref: ExternalTaskRef, error: string): Promise<void>;
36
+ }
37
+
38
+ declare function createPR(params: PRCreationParams, octokit: Octokit): Promise<CreatedPR>;
39
+ declare function pushBranch(repo: ResolvedRepo, branchName: string): Promise<string>;
40
+
41
+ declare function linkIssueToePR(repo: ResolvedRepo, task: Task, pr: CreatedPR, octokit: Octokit): Promise<void>;
42
+ declare const linkIssueToPR: typeof linkIssueToePR;
43
+
44
+ interface DiffValidationConfig {
45
+ maxDiffLines?: number;
46
+ forbiddenPatterns?: RegExp[];
47
+ protectedFiles?: string[];
48
+ }
49
+ interface ValidationResult {
50
+ valid: boolean;
51
+ warnings: string[];
52
+ errors: string[];
53
+ }
54
+ declare function validateDiff(repoPath: string, config?: DiffValidationConfig | OacConfig): Promise<ValidationResult>;
55
+
56
+ interface CompletionHandlerOptions {
57
+ octokit: Octokit;
58
+ eventBus: OacEventBus;
59
+ providers?: ProjectManagementProvider[];
60
+ diffValidationConfig?: DiffValidationConfig | OacConfig;
61
+ }
62
+ interface CompletionHandlerParams extends PRCreationParams {
63
+ jobId: string;
64
+ externalTaskRef?: ExternalTaskRef;
65
+ diffValidationConfig?: DiffValidationConfig | OacConfig;
66
+ }
67
+ declare class CompletionHandler {
68
+ private readonly octokit;
69
+ private readonly eventBus;
70
+ private readonly providers;
71
+ private readonly diffValidationConfig?;
72
+ constructor(options: CompletionHandlerOptions);
73
+ handle(params: CompletionHandlerParams): Promise<CompletionResult>;
74
+ complete(params: CompletionHandlerParams): Promise<CompletionResult>;
75
+ private emitProgress;
76
+ private handleValidationResult;
77
+ private tryLinkIssue;
78
+ private notifyStarted;
79
+ private notifyPRCreated;
80
+ private notifyCompleted;
81
+ private notifyFailed;
82
+ private notifyProviders;
83
+ private resolveExternalTaskRef;
84
+ private normalizePipelineError;
85
+ }
86
+
87
+ export { CompletionHandler, type CompletionHandlerOptions, type CompletionHandlerParams, type CompletionResult, type CreatedPR, type DiffValidationConfig, type ExternalTaskRef, type PRCreationParams, type ProjectManagementProvider, type ValidationResult, createPR, linkIssueToPR, linkIssueToePR, pushBranch, validateDiff };
package/dist/index.js ADDED
@@ -0,0 +1,591 @@
1
+ // src/github-pr.ts
2
+ import { completionError } from "@open330/oac-core";
3
+ import { simpleGit } from "simple-git";
4
+ async function createPR(params, octokit) {
5
+ const { repo, task, result, branchName, baseBranch } = params;
6
+ const pushedSha = await pushBranch(repo, branchName);
7
+ const body = await buildPrBody(params);
8
+ try {
9
+ const created = await octokit.pulls.create({
10
+ owner: repo.owner,
11
+ repo: repo.name,
12
+ title: `[OAC] ${task.title}`,
13
+ body,
14
+ head: branchName,
15
+ base: baseBranch,
16
+ draft: false
17
+ });
18
+ await addLabels(octokit, repo, created.data.number, ["oac-contribution", task.source]);
19
+ return {
20
+ number: created.data.number,
21
+ url: created.data.html_url,
22
+ sha: created.data.head.sha || pushedSha
23
+ };
24
+ } catch (error) {
25
+ throw completionError(
26
+ "PR_CREATION_FAILED",
27
+ `Failed to create PR for "${repo.fullName}" on branch "${branchName}".`,
28
+ {
29
+ cause: error,
30
+ context: {
31
+ repo: repo.fullName,
32
+ branchName,
33
+ baseBranch,
34
+ taskId: task.id
35
+ }
36
+ }
37
+ );
38
+ }
39
+ }
40
+ async function pushBranch(repo, branchName) {
41
+ const git = simpleGit(resolveGitPath(repo));
42
+ const headSha = (await git.revparse(["HEAD"])).trim();
43
+ try {
44
+ const remoteSha = await readRemoteBranchSha(git, branchName);
45
+ if (remoteSha !== headSha) {
46
+ await git.push("origin", branchName);
47
+ }
48
+ } catch (error) {
49
+ try {
50
+ await git.raw(["push", "--set-upstream", "origin", branchName]);
51
+ } catch (retryError) {
52
+ throw completionError(
53
+ "PR_PUSH_REJECTED",
54
+ `Failed to push branch "${branchName}" for "${repo.fullName}".`,
55
+ {
56
+ cause: retryError,
57
+ context: {
58
+ repo: repo.fullName,
59
+ branchName,
60
+ headSha,
61
+ initialError: error instanceof Error ? error.message : "unknown push error"
62
+ }
63
+ }
64
+ );
65
+ }
66
+ }
67
+ return headSha;
68
+ }
69
+ async function buildPrBody(params) {
70
+ const { repo, task, result, baseBranch, branchName } = params;
71
+ const diffStats = await resolveDiffStats(repo, baseBranch, branchName);
72
+ const linkedIssue = task.linkedIssue ? `
73
+ Fixes #${task.linkedIssue.number}
74
+ ` : "\n";
75
+ const agentLabel = resolveAgentLabel(task.metadata);
76
+ const durationText = formatDurationSeconds(result.duration);
77
+ const summaryText = task.description.trim().length > 0 ? task.description.trim() : `Automated contribution for task "${task.title}".`;
78
+ const filesChanged = result.filesChanged.length || diffStats.filesChanged;
79
+ const filesPreview = renderFilesPreview(result.filesChanged);
80
+ return [
81
+ "## Summary",
82
+ "",
83
+ summaryText,
84
+ "",
85
+ "## Changes",
86
+ "",
87
+ filesPreview,
88
+ "",
89
+ `- **Files changed:** ${filesChanged}`,
90
+ `- **Lines added:** ${diffStats.linesAdded}`,
91
+ `- **Lines removed:** ${diffStats.linesRemoved}`,
92
+ "",
93
+ "## Context",
94
+ "",
95
+ `- **Task source:** ${task.source}`,
96
+ `- **Agent:** ${agentLabel}`,
97
+ `- **Tokens used:** ${result.totalTokensUsed}`,
98
+ `- **Execution time:** ${durationText}`,
99
+ linkedIssue.trimEnd(),
100
+ "",
101
+ "---",
102
+ "*This PR was automatically generated by OAC.*"
103
+ ].join("\n");
104
+ }
105
+ async function resolveDiffStats(repo, baseBranch, branchName) {
106
+ const git = simpleGit(resolveGitPath(repo));
107
+ const ranges = [
108
+ [`origin/${baseBranch}...${branchName}`],
109
+ [`${baseBranch}...${branchName}`],
110
+ ["HEAD"],
111
+ []
112
+ ];
113
+ for (const range of ranges) {
114
+ try {
115
+ const summary = await git.diffSummary(range);
116
+ return {
117
+ filesChanged: summary.changed,
118
+ linesAdded: summary.insertions,
119
+ linesRemoved: summary.deletions
120
+ };
121
+ } catch {
122
+ }
123
+ }
124
+ return {
125
+ filesChanged: 0,
126
+ linesAdded: 0,
127
+ linesRemoved: 0
128
+ };
129
+ }
130
+ async function addLabels(octokit, repo, prNumber, labels) {
131
+ const uniqueLabels = [...new Set(labels.map((label) => label.trim()).filter(Boolean))];
132
+ if (uniqueLabels.length === 0) {
133
+ return;
134
+ }
135
+ try {
136
+ await octokit.issues.addLabels({
137
+ owner: repo.owner,
138
+ repo: repo.name,
139
+ issue_number: prNumber,
140
+ labels: uniqueLabels
141
+ });
142
+ } catch {
143
+ }
144
+ }
145
+ function resolveGitPath(repo) {
146
+ return repo.worktreePath.trim().length > 0 ? repo.worktreePath : repo.localPath;
147
+ }
148
+ async function readRemoteBranchSha(git, branchName) {
149
+ const remoteHeads = await git.listRemote(["--heads", "origin", branchName]);
150
+ const firstLine = remoteHeads.split("\n").map((line) => line.trim()).find((line) => line.length > 0);
151
+ if (!firstLine) {
152
+ return void 0;
153
+ }
154
+ const [sha] = firstLine.split(/\s+/);
155
+ return sha;
156
+ }
157
+ function resolveAgentLabel(metadata) {
158
+ const fromAgent = readMetadataString(metadata, ["agent", "agentName", "provider"]);
159
+ return fromAgent ?? "unknown";
160
+ }
161
+ function readMetadataString(metadata, keys) {
162
+ for (const key of keys) {
163
+ const value = metadata[key];
164
+ if (typeof value === "string" && value.trim().length > 0) {
165
+ return value.trim();
166
+ }
167
+ }
168
+ return void 0;
169
+ }
170
+ function renderFilesPreview(files) {
171
+ if (files.length === 0) {
172
+ return "- No file list was reported by the execution step.";
173
+ }
174
+ const preview = files.slice(0, 15).map((path) => `- \`${path}\``);
175
+ if (files.length > 15) {
176
+ preview.push(`- ...and ${files.length - 15} more file(s)`);
177
+ }
178
+ return preview.join("\n");
179
+ }
180
+ function formatDurationSeconds(duration) {
181
+ if (!Number.isFinite(duration) || duration <= 0) {
182
+ return "0s";
183
+ }
184
+ const seconds = duration > 1e3 ? duration / 1e3 : duration;
185
+ if (seconds >= 100) {
186
+ return `${Math.round(seconds)}s`;
187
+ }
188
+ return `${seconds.toFixed(1)}s`;
189
+ }
190
+
191
+ // src/issue-linker.ts
192
+ import { completionError as completionError2 } from "@open330/oac-core";
193
+ async function linkIssueToePR(repo, task, pr, octokit) {
194
+ if (!task.linkedIssue) {
195
+ return;
196
+ }
197
+ const issueNumber = task.linkedIssue.number;
198
+ try {
199
+ const issue = await octokit.issues.get({
200
+ owner: repo.owner,
201
+ repo: repo.name,
202
+ issue_number: issueNumber
203
+ });
204
+ if (issue.data.state === "closed") {
205
+ return;
206
+ }
207
+ await octokit.issues.createComment({
208
+ owner: repo.owner,
209
+ repo: repo.name,
210
+ issue_number: issueNumber,
211
+ body: `OAC opened a PR for this issue: ${pr.url}`
212
+ });
213
+ } catch (error) {
214
+ if (isNonBlockingIssueError(error)) {
215
+ return;
216
+ }
217
+ throw completionError2(
218
+ "PR_CREATION_FAILED",
219
+ `Failed to link issue #${issueNumber} to PR #${pr.number}.`,
220
+ {
221
+ cause: error,
222
+ context: {
223
+ repo: repo.fullName,
224
+ issueNumber,
225
+ prNumber: pr.number
226
+ }
227
+ }
228
+ );
229
+ }
230
+ }
231
+ var linkIssueToPR = linkIssueToePR;
232
+ function isNonBlockingIssueError(error) {
233
+ if (!isStatusError(error)) {
234
+ return false;
235
+ }
236
+ return error.status === 404 || error.status === 410 || error.status === 422;
237
+ }
238
+ function isStatusError(error) {
239
+ return typeof error === "object" && error !== null && "status" in error;
240
+ }
241
+
242
+ // src/diff-validator.ts
243
+ import { basename } from "path";
244
+ import { simpleGit as simpleGit2 } from "simple-git";
245
+ var DEFAULT_MAX_DIFF_LINES = 500;
246
+ var DEFAULT_FORBIDDEN_PATTERNS = [
247
+ /eval\s*\(/,
248
+ /new\s+Function\s*\(/,
249
+ /child_process/,
250
+ /\bexecSync\s*\(/,
251
+ /\bspawnSync\s*\(/
252
+ ];
253
+ var DEFAULT_PROTECTED_FILES = [".env*", "*.pem", "*.key"];
254
+ async function validateDiff(repoPath, config) {
255
+ const git = simpleGit2(repoPath);
256
+ const settings = resolveValidationConfig(config);
257
+ const warnings = [];
258
+ const errors = [];
259
+ const [diffSummary, changedFiles, patch] = await Promise.all([
260
+ readDiffSummary(git),
261
+ readChangedFiles(git),
262
+ readPatch(git)
263
+ ]);
264
+ const totalLinesChanged = diffSummary.insertions + diffSummary.deletions;
265
+ if (totalLinesChanged > settings.maxDiffLines) {
266
+ errors.push(
267
+ `Diff too large: ${totalLinesChanged} changed lines exceeds maxDiffLines=${settings.maxDiffLines}.`
268
+ );
269
+ } else if (totalLinesChanged > Math.floor(settings.maxDiffLines * 0.8)) {
270
+ warnings.push(
271
+ `Diff is near the maximum size (${totalLinesChanged}/${settings.maxDiffLines} changed lines).`
272
+ );
273
+ }
274
+ if (totalLinesChanged === 0) {
275
+ warnings.push("No changed lines detected in the current diff.");
276
+ }
277
+ const protectedFileHits = changedFiles.filter(
278
+ (path) => settings.protectedFiles.some((pattern) => matchesGlob(path, pattern))
279
+ );
280
+ if (protectedFileHits.length > 0) {
281
+ errors.push(`Protected files were modified: ${protectedFileHits.join(", ")}.`);
282
+ }
283
+ const forbiddenHits = findForbiddenPatternHits(patch, settings.forbiddenPatterns);
284
+ errors.push(...forbiddenHits);
285
+ return {
286
+ valid: errors.length === 0,
287
+ warnings,
288
+ errors
289
+ };
290
+ }
291
+ async function readDiffSummary(git) {
292
+ try {
293
+ return await git.diffSummary(["HEAD"]);
294
+ } catch {
295
+ return git.diffSummary();
296
+ }
297
+ }
298
+ async function readChangedFiles(git) {
299
+ const withHead = await tryGitDiff(git, ["--name-only", "HEAD"]);
300
+ const output = withHead ?? await git.diff(["--name-only"]);
301
+ return output.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
302
+ }
303
+ async function readPatch(git) {
304
+ const withHead = await tryGitDiff(git, ["--no-color", "--unified=0", "HEAD"]);
305
+ if (withHead !== void 0) {
306
+ return withHead;
307
+ }
308
+ return git.diff(["--no-color", "--unified=0"]);
309
+ }
310
+ async function tryGitDiff(git, args) {
311
+ try {
312
+ return await git.diff(args);
313
+ } catch {
314
+ return void 0;
315
+ }
316
+ }
317
+ function resolveValidationConfig(config) {
318
+ const diffConfig = isOacConfig(config) ? void 0 : config;
319
+ const maxDiffLines = isOacConfig(config) ? config.execution.validation.maxDiffLines : diffConfig?.maxDiffLines;
320
+ return {
321
+ maxDiffLines: typeof maxDiffLines === "number" && maxDiffLines > 0 ? Math.floor(maxDiffLines) : DEFAULT_MAX_DIFF_LINES,
322
+ forbiddenPatterns: Array.isArray(diffConfig?.forbiddenPatterns) && diffConfig.forbiddenPatterns.length > 0 ? diffConfig.forbiddenPatterns : DEFAULT_FORBIDDEN_PATTERNS,
323
+ protectedFiles: Array.isArray(diffConfig?.protectedFiles) && diffConfig.protectedFiles.length > 0 ? diffConfig.protectedFiles : DEFAULT_PROTECTED_FILES
324
+ };
325
+ }
326
+ function isOacConfig(value) {
327
+ return typeof value === "object" && value !== null && "execution" in value && typeof value.execution === "object";
328
+ }
329
+ function findForbiddenPatternHits(diffPatch, patterns) {
330
+ const hits = /* @__PURE__ */ new Set();
331
+ let currentFile = "(unknown)";
332
+ for (const line of diffPatch.split("\n")) {
333
+ if (line.startsWith("+++ b/")) {
334
+ currentFile = line.slice("+++ b/".length).trim();
335
+ continue;
336
+ }
337
+ if (!line.startsWith("+") || line.startsWith("+++")) {
338
+ continue;
339
+ }
340
+ const addedLine = line.slice(1);
341
+ for (const pattern of patterns) {
342
+ if (patternMatches(pattern, addedLine)) {
343
+ const preview = truncate(addedLine.trim(), 120);
344
+ hits.add(`Forbidden pattern "${pattern}" found in ${currentFile}: "${preview}".`);
345
+ }
346
+ }
347
+ }
348
+ return [...hits];
349
+ }
350
+ function patternMatches(pattern, input) {
351
+ const normalizedFlags = pattern.flags.replaceAll("g", "");
352
+ const matcher = new RegExp(pattern.source, normalizedFlags);
353
+ return matcher.test(input);
354
+ }
355
+ function matchesGlob(path, pattern) {
356
+ const regex = globToRegex(pattern);
357
+ const filename = basename(path);
358
+ return regex.test(path) || regex.test(filename);
359
+ }
360
+ function globToRegex(glob) {
361
+ const escaped = glob.replaceAll(/[-/\\^$+?.()|[\]{}]/g, "\\$&").replaceAll("*", ".*");
362
+ return new RegExp(`^${escaped}$`);
363
+ }
364
+ function truncate(value, maxLength) {
365
+ if (value.length <= maxLength) {
366
+ return value;
367
+ }
368
+ return `${value.slice(0, maxLength - 3)}...`;
369
+ }
370
+
371
+ // src/handler.ts
372
+ import {
373
+ OacError,
374
+ completionError as completionError3,
375
+ executionError
376
+ } from "@open330/oac-core";
377
+ var CompletionHandler = class {
378
+ octokit;
379
+ eventBus;
380
+ providers;
381
+ diffValidationConfig;
382
+ constructor(options) {
383
+ this.octokit = options.octokit;
384
+ this.eventBus = options.eventBus;
385
+ this.providers = options.providers ?? [];
386
+ this.diffValidationConfig = options.diffValidationConfig;
387
+ }
388
+ async handle(params) {
389
+ return this.complete(params);
390
+ }
391
+ async complete(params) {
392
+ const warnings = [];
393
+ const externalTaskRef = this.resolveExternalTaskRef(params.task, params.externalTaskRef);
394
+ try {
395
+ this.emitProgress(params.jobId, params.result.totalTokensUsed, "completion:validateDiff");
396
+ const validation = await validateDiff(
397
+ resolveRepoPath(params.repo),
398
+ params.diffValidationConfig ?? this.diffValidationConfig
399
+ );
400
+ this.handleValidationResult(validation);
401
+ warnings.push(...validation.warnings);
402
+ warnings.push(...await this.notifyStarted(externalTaskRef));
403
+ this.emitProgress(params.jobId, params.result.totalTokensUsed, "completion:pushBranch");
404
+ await pushBranch(params.repo, params.branchName);
405
+ this.emitProgress(params.jobId, params.result.totalTokensUsed, "completion:createPR");
406
+ const pr = await createPR(params, this.octokit);
407
+ this.eventBus.emit("pr:created", { jobId: params.jobId, prUrl: pr.url });
408
+ this.emitProgress(params.jobId, params.result.totalTokensUsed, "completion:linkIssue");
409
+ const linkIssueWarning = await this.tryLinkIssue(params.repo, params.task, pr);
410
+ if (linkIssueWarning) {
411
+ warnings.push(linkIssueWarning);
412
+ }
413
+ this.emitProgress(params.jobId, params.result.totalTokensUsed, "completion:notifyWebhooks");
414
+ warnings.push(...await this.notifyPRCreated(externalTaskRef, pr));
415
+ const completionResult = buildCompletionResult(params, pr, warnings);
416
+ warnings.push(...await this.notifyCompleted(externalTaskRef, completionResult));
417
+ return completionResult;
418
+ } catch (error) {
419
+ const normalizedError = this.normalizePipelineError(error, params);
420
+ this.eventBus.emit("execution:failed", {
421
+ jobId: params.jobId,
422
+ error: normalizedError
423
+ });
424
+ await this.notifyFailed(externalTaskRef, normalizedError.message);
425
+ throw normalizedError;
426
+ }
427
+ }
428
+ emitProgress(jobId, tokensUsed, stage) {
429
+ this.eventBus.emit("execution:progress", {
430
+ jobId,
431
+ tokensUsed,
432
+ stage
433
+ });
434
+ }
435
+ handleValidationResult(validation) {
436
+ if (validation.valid) {
437
+ return;
438
+ }
439
+ const hasForbiddenPattern = validation.errors.some(
440
+ (message) => message.toLowerCase().includes("forbidden pattern")
441
+ );
442
+ const errorCode = hasForbiddenPattern ? "VALIDATION_FORBIDDEN_PATTERN" : "VALIDATION_DIFF_TOO_LARGE";
443
+ throw executionError(errorCode, "Diff validation failed.", {
444
+ context: {
445
+ errors: validation.errors,
446
+ warnings: validation.warnings
447
+ }
448
+ });
449
+ }
450
+ async tryLinkIssue(repo, task, pr) {
451
+ try {
452
+ await linkIssueToePR(repo, task, pr, this.octokit);
453
+ return void 0;
454
+ } catch (error) {
455
+ return `Issue linking warning: ${toErrorMessage(error)}`;
456
+ }
457
+ }
458
+ async notifyStarted(ref) {
459
+ return this.notifyProviders(
460
+ ref,
461
+ "notifyStarted",
462
+ (provider, taskRef) => provider.notifyStarted(taskRef)
463
+ );
464
+ }
465
+ async notifyPRCreated(ref, pr) {
466
+ return this.notifyProviders(
467
+ ref,
468
+ "notifyPRCreated",
469
+ (provider, taskRef) => provider.notifyPRCreated(taskRef, pr.url)
470
+ );
471
+ }
472
+ async notifyCompleted(ref, result) {
473
+ return this.notifyProviders(
474
+ ref,
475
+ "notifyCompleted",
476
+ (provider, taskRef) => provider.notifyCompleted(taskRef, result)
477
+ );
478
+ }
479
+ async notifyFailed(ref, message) {
480
+ await this.notifyProviders(
481
+ ref,
482
+ "notifyFailed",
483
+ (provider, taskRef) => provider.notifyFailed(taskRef, message)
484
+ );
485
+ }
486
+ async notifyProviders(ref, operationName, operation) {
487
+ if (!ref) {
488
+ return [];
489
+ }
490
+ const selectedProviders = this.providers.filter((provider) => provider.id === ref.provider);
491
+ if (selectedProviders.length === 0) {
492
+ return [];
493
+ }
494
+ const results = await Promise.allSettled(
495
+ selectedProviders.map(async (provider) => {
496
+ const isReachable = await provider.ping();
497
+ if (!isReachable) {
498
+ throw new Error(`Provider "${provider.id}" is unreachable.`);
499
+ }
500
+ await operation(provider, ref);
501
+ })
502
+ );
503
+ const warnings = [];
504
+ for (let index = 0; index < results.length; index += 1) {
505
+ const result = results[index];
506
+ if (result.status === "fulfilled") {
507
+ continue;
508
+ }
509
+ warnings.push(
510
+ `${operationName} failed for provider "${selectedProviders[index].id}": ${toErrorMessage(result.reason)}`
511
+ );
512
+ }
513
+ return warnings;
514
+ }
515
+ resolveExternalTaskRef(task, providedRef) {
516
+ if (providedRef) {
517
+ return providedRef;
518
+ }
519
+ if (task.linkedIssue) {
520
+ return {
521
+ provider: "github",
522
+ externalId: `#${task.linkedIssue.number}`,
523
+ url: task.linkedIssue.url
524
+ };
525
+ }
526
+ const metadata = task.metadata;
527
+ const provider = readMetadataString2(metadata, "externalProvider");
528
+ const externalId = readMetadataString2(metadata, "externalId");
529
+ const url = readMetadataString2(metadata, "externalUrl");
530
+ if (!provider || !externalId) {
531
+ return void 0;
532
+ }
533
+ return { provider, externalId, url };
534
+ }
535
+ normalizePipelineError(error, params) {
536
+ if (error instanceof OacError) {
537
+ return error;
538
+ }
539
+ return completionError3(
540
+ "PR_CREATION_FAILED",
541
+ `Completion pipeline failed for task "${params.task.id}" in "${params.repo.fullName}": ${toErrorMessage(
542
+ error
543
+ )}`,
544
+ {
545
+ cause: error,
546
+ context: {
547
+ jobId: params.jobId,
548
+ taskId: params.task.id,
549
+ repo: params.repo.fullName,
550
+ branchName: params.branchName
551
+ }
552
+ }
553
+ );
554
+ }
555
+ };
556
+ function buildCompletionResult(params, pr, warnings) {
557
+ const filesChanged = params.result.filesChanged.length;
558
+ const warningSuffix = warnings.length > 0 ? ` Completed with ${warnings.length} warning(s).` : "";
559
+ return {
560
+ prUrl: pr.url,
561
+ commitSha: pr.sha,
562
+ summary: `Created PR #${pr.number} for "${params.task.title}".${warningSuffix}`,
563
+ filesChanged,
564
+ tokensUsed: params.result.totalTokensUsed
565
+ };
566
+ }
567
+ function resolveRepoPath(repo) {
568
+ return repo.worktreePath.trim().length > 0 ? repo.worktreePath : repo.localPath;
569
+ }
570
+ function readMetadataString2(metadata, key) {
571
+ const value = metadata[key];
572
+ if (typeof value === "string" && value.trim().length > 0) {
573
+ return value.trim();
574
+ }
575
+ return void 0;
576
+ }
577
+ function toErrorMessage(error) {
578
+ if (error instanceof Error && error.message.trim().length > 0) {
579
+ return error.message.trim();
580
+ }
581
+ return "Unknown error";
582
+ }
583
+ export {
584
+ CompletionHandler,
585
+ createPR,
586
+ linkIssueToPR,
587
+ linkIssueToePR,
588
+ pushBranch,
589
+ validateDiff
590
+ };
591
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/github-pr.ts","../src/issue-linker.ts","../src/diff-validator.ts","../src/handler.ts"],"sourcesContent":["import { type ResolvedRepo, completionError } from \"@open330/oac-core\";\nimport type { Octokit } from \"@octokit/rest\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\n\nimport type { CreatedPR, PRCreationParams } from \"./types.js\";\n\ninterface PRDiffStats {\n filesChanged: number;\n linesAdded: number;\n linesRemoved: number;\n}\n\nexport async function createPR(params: PRCreationParams, octokit: Octokit): Promise<CreatedPR> {\n const { repo, task, result, branchName, baseBranch } = params;\n const pushedSha = await pushBranch(repo, branchName);\n const body = await buildPrBody(params);\n\n try {\n const created = await octokit.pulls.create({\n owner: repo.owner,\n repo: repo.name,\n title: `[OAC] ${task.title}`,\n body,\n head: branchName,\n base: baseBranch,\n draft: false,\n });\n\n await addLabels(octokit, repo, created.data.number, [\"oac-contribution\", task.source]);\n\n return {\n number: created.data.number,\n url: created.data.html_url,\n sha: created.data.head.sha || pushedSha,\n };\n } catch (error) {\n throw completionError(\n \"PR_CREATION_FAILED\",\n `Failed to create PR for \"${repo.fullName}\" on branch \"${branchName}\".`,\n {\n cause: error,\n context: {\n repo: repo.fullName,\n branchName,\n baseBranch,\n taskId: task.id,\n },\n },\n );\n }\n}\n\nexport async function pushBranch(repo: ResolvedRepo, branchName: string): Promise<string> {\n const git = simpleGit(resolveGitPath(repo));\n const headSha = (await git.revparse([\"HEAD\"])).trim();\n\n try {\n const remoteSha = await readRemoteBranchSha(git, branchName);\n if (remoteSha !== headSha) {\n await git.push(\"origin\", branchName);\n }\n } catch (error) {\n try {\n await git.raw([\"push\", \"--set-upstream\", \"origin\", branchName]);\n } catch (retryError) {\n throw completionError(\n \"PR_PUSH_REJECTED\",\n `Failed to push branch \"${branchName}\" for \"${repo.fullName}\".`,\n {\n cause: retryError,\n context: {\n repo: repo.fullName,\n branchName,\n headSha,\n initialError: error instanceof Error ? error.message : \"unknown push error\",\n },\n },\n );\n }\n }\n\n return headSha;\n}\n\nasync function buildPrBody(params: PRCreationParams): Promise<string> {\n const { repo, task, result, baseBranch, branchName } = params;\n const diffStats = await resolveDiffStats(repo, baseBranch, branchName);\n const linkedIssue = task.linkedIssue ? `\\nFixes #${task.linkedIssue.number}\\n` : \"\\n\";\n const agentLabel = resolveAgentLabel(task.metadata);\n const durationText = formatDurationSeconds(result.duration);\n const summaryText =\n task.description.trim().length > 0\n ? task.description.trim()\n : `Automated contribution for task \"${task.title}\".`;\n const filesChanged = result.filesChanged.length || diffStats.filesChanged;\n const filesPreview = renderFilesPreview(result.filesChanged);\n\n return [\n \"## Summary\",\n \"\",\n summaryText,\n \"\",\n \"## Changes\",\n \"\",\n filesPreview,\n \"\",\n `- **Files changed:** ${filesChanged}`,\n `- **Lines added:** ${diffStats.linesAdded}`,\n `- **Lines removed:** ${diffStats.linesRemoved}`,\n \"\",\n \"## Context\",\n \"\",\n `- **Task source:** ${task.source}`,\n `- **Agent:** ${agentLabel}`,\n `- **Tokens used:** ${result.totalTokensUsed}`,\n `- **Execution time:** ${durationText}`,\n linkedIssue.trimEnd(),\n \"\",\n \"---\",\n \"*This PR was automatically generated by OAC.*\",\n ].join(\"\\n\");\n}\n\nasync function resolveDiffStats(\n repo: ResolvedRepo,\n baseBranch: string,\n branchName: string,\n): Promise<PRDiffStats> {\n const git = simpleGit(resolveGitPath(repo));\n const ranges = [\n [`origin/${baseBranch}...${branchName}`],\n [`${baseBranch}...${branchName}`],\n [\"HEAD\"],\n [],\n ] as string[][];\n\n for (const range of ranges) {\n try {\n const summary = await git.diffSummary(range);\n return {\n filesChanged: summary.changed,\n linesAdded: summary.insertions,\n linesRemoved: summary.deletions,\n };\n } catch {}\n }\n\n return {\n filesChanged: 0,\n linesAdded: 0,\n linesRemoved: 0,\n };\n}\n\nasync function addLabels(\n octokit: Octokit,\n repo: ResolvedRepo,\n prNumber: number,\n labels: string[],\n): Promise<void> {\n const uniqueLabels = [...new Set(labels.map((label) => label.trim()).filter(Boolean))];\n if (uniqueLabels.length === 0) {\n return;\n }\n\n try {\n await octokit.issues.addLabels({\n owner: repo.owner,\n repo: repo.name,\n issue_number: prNumber,\n labels: uniqueLabels,\n });\n } catch {\n // Labeling failure should not block PR creation.\n }\n}\n\nfunction resolveGitPath(repo: ResolvedRepo): string {\n return repo.worktreePath.trim().length > 0 ? repo.worktreePath : repo.localPath;\n}\n\nasync function readRemoteBranchSha(\n git: SimpleGit,\n branchName: string,\n): Promise<string | undefined> {\n const remoteHeads = await git.listRemote([\"--heads\", \"origin\", branchName]);\n const firstLine = remoteHeads\n .split(\"\\n\")\n .map((line) => line.trim())\n .find((line) => line.length > 0);\n\n if (!firstLine) {\n return undefined;\n }\n\n const [sha] = firstLine.split(/\\s+/);\n return sha;\n}\n\nfunction resolveAgentLabel(metadata: Record<string, unknown>): string {\n const fromAgent = readMetadataString(metadata, [\"agent\", \"agentName\", \"provider\"]);\n return fromAgent ?? \"unknown\";\n}\n\nfunction readMetadataString(metadata: Record<string, unknown>, keys: string[]): string | undefined {\n for (const key of keys) {\n const value = metadata[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n }\n return undefined;\n}\n\nfunction renderFilesPreview(files: string[]): string {\n if (files.length === 0) {\n return \"- No file list was reported by the execution step.\";\n }\n\n const preview = files.slice(0, 15).map((path) => `- \\`${path}\\``);\n if (files.length > 15) {\n preview.push(`- ...and ${files.length - 15} more file(s)`);\n }\n\n return preview.join(\"\\n\");\n}\n\nfunction formatDurationSeconds(duration: number): string {\n if (!Number.isFinite(duration) || duration <= 0) {\n return \"0s\";\n }\n\n const seconds = duration > 1_000 ? duration / 1_000 : duration;\n if (seconds >= 100) {\n return `${Math.round(seconds)}s`;\n }\n\n return `${seconds.toFixed(1)}s`;\n}\n","import { type ResolvedRepo, type Task, completionError } from \"@open330/oac-core\";\nimport type { Octokit } from \"@octokit/rest\";\n\nimport type { CreatedPR } from \"./types.js\";\n\nexport async function linkIssueToePR(\n repo: ResolvedRepo,\n task: Task,\n pr: CreatedPR,\n octokit: Octokit,\n): Promise<void> {\n if (!task.linkedIssue) {\n return;\n }\n\n const issueNumber = task.linkedIssue.number;\n\n try {\n const issue = await octokit.issues.get({\n owner: repo.owner,\n repo: repo.name,\n issue_number: issueNumber,\n });\n\n if (issue.data.state === \"closed\") {\n return;\n }\n\n await octokit.issues.createComment({\n owner: repo.owner,\n repo: repo.name,\n issue_number: issueNumber,\n body: `OAC opened a PR for this issue: ${pr.url}`,\n });\n } catch (error) {\n if (isNonBlockingIssueError(error)) {\n return;\n }\n\n throw completionError(\n \"PR_CREATION_FAILED\",\n `Failed to link issue #${issueNumber} to PR #${pr.number}.`,\n {\n cause: error,\n context: {\n repo: repo.fullName,\n issueNumber,\n prNumber: pr.number,\n },\n },\n );\n }\n}\n\nexport const linkIssueToPR = linkIssueToePR;\n\nfunction isNonBlockingIssueError(error: unknown): boolean {\n if (!isStatusError(error)) {\n return false;\n }\n\n return error.status === 404 || error.status === 410 || error.status === 422;\n}\n\nfunction isStatusError(error: unknown): error is { status?: number } {\n return typeof error === \"object\" && error !== null && \"status\" in error;\n}\n","import { basename } from \"node:path\";\n\nimport type { OacConfig } from \"@open330/oac-core\";\nimport { type SimpleGit, simpleGit } from \"simple-git\";\n\nconst DEFAULT_MAX_DIFF_LINES = 500;\nconst DEFAULT_FORBIDDEN_PATTERNS: RegExp[] = [\n /eval\\s*\\(/,\n /new\\s+Function\\s*\\(/,\n /child_process/,\n /\\bexecSync\\s*\\(/,\n /\\bspawnSync\\s*\\(/,\n];\nconst DEFAULT_PROTECTED_FILES = [\".env*\", \"*.pem\", \"*.key\"];\n\ninterface ResolvedValidationConfig {\n maxDiffLines: number;\n forbiddenPatterns: RegExp[];\n protectedFiles: string[];\n}\n\nexport interface DiffValidationConfig {\n maxDiffLines?: number;\n forbiddenPatterns?: RegExp[];\n protectedFiles?: string[];\n}\n\nexport interface ValidationResult {\n valid: boolean;\n warnings: string[];\n errors: string[];\n}\n\nexport async function validateDiff(\n repoPath: string,\n config?: DiffValidationConfig | OacConfig,\n): Promise<ValidationResult> {\n const git = simpleGit(repoPath);\n const settings = resolveValidationConfig(config);\n const warnings: string[] = [];\n const errors: string[] = [];\n\n const [diffSummary, changedFiles, patch] = await Promise.all([\n readDiffSummary(git),\n readChangedFiles(git),\n readPatch(git),\n ]);\n\n const totalLinesChanged = diffSummary.insertions + diffSummary.deletions;\n if (totalLinesChanged > settings.maxDiffLines) {\n errors.push(\n `Diff too large: ${totalLinesChanged} changed lines exceeds maxDiffLines=${settings.maxDiffLines}.`,\n );\n } else if (totalLinesChanged > Math.floor(settings.maxDiffLines * 0.8)) {\n warnings.push(\n `Diff is near the maximum size (${totalLinesChanged}/${settings.maxDiffLines} changed lines).`,\n );\n }\n\n if (totalLinesChanged === 0) {\n warnings.push(\"No changed lines detected in the current diff.\");\n }\n\n const protectedFileHits = changedFiles.filter((path) =>\n settings.protectedFiles.some((pattern) => matchesGlob(path, pattern)),\n );\n if (protectedFileHits.length > 0) {\n errors.push(`Protected files were modified: ${protectedFileHits.join(\", \")}.`);\n }\n\n const forbiddenHits = findForbiddenPatternHits(patch, settings.forbiddenPatterns);\n errors.push(...forbiddenHits);\n\n return {\n valid: errors.length === 0,\n warnings,\n errors,\n };\n}\n\nasync function readDiffSummary(git: SimpleGit) {\n try {\n return await git.diffSummary([\"HEAD\"]);\n } catch {\n return git.diffSummary();\n }\n}\n\nasync function readChangedFiles(git: SimpleGit): Promise<string[]> {\n const withHead = await tryGitDiff(git, [\"--name-only\", \"HEAD\"]);\n const output = withHead ?? (await git.diff([\"--name-only\"]));\n\n return output\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n}\n\nasync function readPatch(git: SimpleGit): Promise<string> {\n const withHead = await tryGitDiff(git, [\"--no-color\", \"--unified=0\", \"HEAD\"]);\n if (withHead !== undefined) {\n return withHead;\n }\n return git.diff([\"--no-color\", \"--unified=0\"]);\n}\n\nasync function tryGitDiff(git: SimpleGit, args: string[]): Promise<string | undefined> {\n try {\n return await git.diff(args);\n } catch {\n return undefined;\n }\n}\n\nfunction resolveValidationConfig(\n config?: DiffValidationConfig | OacConfig,\n): ResolvedValidationConfig {\n const diffConfig = isOacConfig(config) ? undefined : config;\n const maxDiffLines = isOacConfig(config)\n ? config.execution.validation.maxDiffLines\n : diffConfig?.maxDiffLines;\n\n return {\n maxDiffLines:\n typeof maxDiffLines === \"number\" && maxDiffLines > 0\n ? Math.floor(maxDiffLines)\n : DEFAULT_MAX_DIFF_LINES,\n forbiddenPatterns:\n Array.isArray(diffConfig?.forbiddenPatterns) && diffConfig.forbiddenPatterns.length > 0\n ? diffConfig.forbiddenPatterns\n : DEFAULT_FORBIDDEN_PATTERNS,\n protectedFiles:\n Array.isArray(diffConfig?.protectedFiles) && diffConfig.protectedFiles.length > 0\n ? diffConfig.protectedFiles\n : DEFAULT_PROTECTED_FILES,\n };\n}\n\nfunction isOacConfig(value: DiffValidationConfig | OacConfig | undefined): value is OacConfig {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"execution\" in value &&\n typeof (value as { execution?: unknown }).execution === \"object\"\n );\n}\n\nfunction findForbiddenPatternHits(diffPatch: string, patterns: RegExp[]): string[] {\n const hits = new Set<string>();\n let currentFile = \"(unknown)\";\n\n for (const line of diffPatch.split(\"\\n\")) {\n if (line.startsWith(\"+++ b/\")) {\n currentFile = line.slice(\"+++ b/\".length).trim();\n continue;\n }\n\n if (!line.startsWith(\"+\") || line.startsWith(\"+++\")) {\n continue;\n }\n\n const addedLine = line.slice(1);\n for (const pattern of patterns) {\n if (patternMatches(pattern, addedLine)) {\n const preview = truncate(addedLine.trim(), 120);\n hits.add(`Forbidden pattern \"${pattern}\" found in ${currentFile}: \"${preview}\".`);\n }\n }\n }\n\n return [...hits];\n}\n\nfunction patternMatches(pattern: RegExp, input: string): boolean {\n const normalizedFlags = pattern.flags.replaceAll(\"g\", \"\");\n const matcher = new RegExp(pattern.source, normalizedFlags);\n return matcher.test(input);\n}\n\nfunction matchesGlob(path: string, pattern: string): boolean {\n const regex = globToRegex(pattern);\n const filename = basename(path);\n return regex.test(path) || regex.test(filename);\n}\n\nfunction globToRegex(glob: string): RegExp {\n const escaped = glob.replaceAll(/[-/\\\\^$+?.()|[\\]{}]/g, \"\\\\$&\").replaceAll(\"*\", \".*\");\n return new RegExp(`^${escaped}$`);\n}\n\nfunction truncate(value: string, maxLength: number): string {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength - 3)}...`;\n}\n","import {\n type OacConfig,\n OacError,\n type OacEventBus,\n type ResolvedRepo,\n type Task,\n completionError,\n executionError,\n} from \"@open330/oac-core\";\nimport type { Octokit } from \"@octokit/rest\";\n\nimport {\n type DiffValidationConfig,\n type ValidationResult,\n validateDiff,\n} from \"./diff-validator.js\";\nimport { createPR, pushBranch } from \"./github-pr.js\";\nimport { linkIssueToePR } from \"./issue-linker.js\";\nimport type {\n CompletionResult,\n CreatedPR,\n ExternalTaskRef,\n PRCreationParams,\n ProjectManagementProvider,\n} from \"./types.js\";\n\nexport interface CompletionHandlerOptions {\n octokit: Octokit;\n eventBus: OacEventBus;\n providers?: ProjectManagementProvider[];\n diffValidationConfig?: DiffValidationConfig | OacConfig;\n}\n\nexport interface CompletionHandlerParams extends PRCreationParams {\n jobId: string;\n externalTaskRef?: ExternalTaskRef;\n diffValidationConfig?: DiffValidationConfig | OacConfig;\n}\n\nexport class CompletionHandler {\n private readonly octokit: Octokit;\n private readonly eventBus: OacEventBus;\n private readonly providers: ProjectManagementProvider[];\n private readonly diffValidationConfig?: DiffValidationConfig | OacConfig;\n\n public constructor(options: CompletionHandlerOptions) {\n this.octokit = options.octokit;\n this.eventBus = options.eventBus;\n this.providers = options.providers ?? [];\n this.diffValidationConfig = options.diffValidationConfig;\n }\n\n public async handle(params: CompletionHandlerParams): Promise<CompletionResult> {\n return this.complete(params);\n }\n\n public async complete(params: CompletionHandlerParams): Promise<CompletionResult> {\n const warnings: string[] = [];\n const externalTaskRef = this.resolveExternalTaskRef(params.task, params.externalTaskRef);\n\n try {\n this.emitProgress(params.jobId, params.result.totalTokensUsed, \"completion:validateDiff\");\n const validation = await validateDiff(\n resolveRepoPath(params.repo),\n params.diffValidationConfig ?? this.diffValidationConfig,\n );\n this.handleValidationResult(validation);\n warnings.push(...validation.warnings);\n\n warnings.push(...(await this.notifyStarted(externalTaskRef)));\n\n this.emitProgress(params.jobId, params.result.totalTokensUsed, \"completion:pushBranch\");\n await pushBranch(params.repo, params.branchName);\n\n this.emitProgress(params.jobId, params.result.totalTokensUsed, \"completion:createPR\");\n const pr = await createPR(params, this.octokit);\n this.eventBus.emit(\"pr:created\", { jobId: params.jobId, prUrl: pr.url });\n\n this.emitProgress(params.jobId, params.result.totalTokensUsed, \"completion:linkIssue\");\n const linkIssueWarning = await this.tryLinkIssue(params.repo, params.task, pr);\n if (linkIssueWarning) {\n warnings.push(linkIssueWarning);\n }\n\n this.emitProgress(params.jobId, params.result.totalTokensUsed, \"completion:notifyWebhooks\");\n warnings.push(...(await this.notifyPRCreated(externalTaskRef, pr)));\n\n const completionResult = buildCompletionResult(params, pr, warnings);\n warnings.push(...(await this.notifyCompleted(externalTaskRef, completionResult)));\n\n return completionResult;\n } catch (error) {\n const normalizedError = this.normalizePipelineError(error, params);\n this.eventBus.emit(\"execution:failed\", {\n jobId: params.jobId,\n error: normalizedError,\n });\n await this.notifyFailed(externalTaskRef, normalizedError.message);\n throw normalizedError;\n }\n }\n\n private emitProgress(jobId: string, tokensUsed: number, stage: string): void {\n this.eventBus.emit(\"execution:progress\", {\n jobId,\n tokensUsed,\n stage,\n });\n }\n\n private handleValidationResult(validation: ValidationResult): void {\n if (validation.valid) {\n return;\n }\n\n const hasForbiddenPattern = validation.errors.some((message) =>\n message.toLowerCase().includes(\"forbidden pattern\"),\n );\n const errorCode = hasForbiddenPattern\n ? \"VALIDATION_FORBIDDEN_PATTERN\"\n : \"VALIDATION_DIFF_TOO_LARGE\";\n\n throw executionError(errorCode, \"Diff validation failed.\", {\n context: {\n errors: validation.errors,\n warnings: validation.warnings,\n },\n });\n }\n\n private async tryLinkIssue(\n repo: ResolvedRepo,\n task: Task,\n pr: CreatedPR,\n ): Promise<string | undefined> {\n try {\n await linkIssueToePR(repo, task, pr, this.octokit);\n return undefined;\n } catch (error) {\n return `Issue linking warning: ${toErrorMessage(error)}`;\n }\n }\n\n private async notifyStarted(ref: ExternalTaskRef | undefined): Promise<string[]> {\n return this.notifyProviders(ref, \"notifyStarted\", (provider, taskRef) =>\n provider.notifyStarted(taskRef),\n );\n }\n\n private async notifyPRCreated(\n ref: ExternalTaskRef | undefined,\n pr: CreatedPR,\n ): Promise<string[]> {\n return this.notifyProviders(ref, \"notifyPRCreated\", (provider, taskRef) =>\n provider.notifyPRCreated(taskRef, pr.url),\n );\n }\n\n private async notifyCompleted(\n ref: ExternalTaskRef | undefined,\n result: CompletionResult,\n ): Promise<string[]> {\n return this.notifyProviders(ref, \"notifyCompleted\", (provider, taskRef) =>\n provider.notifyCompleted(taskRef, result),\n );\n }\n\n private async notifyFailed(ref: ExternalTaskRef | undefined, message: string): Promise<void> {\n await this.notifyProviders(ref, \"notifyFailed\", (provider, taskRef) =>\n provider.notifyFailed(taskRef, message),\n );\n }\n\n private async notifyProviders(\n ref: ExternalTaskRef | undefined,\n operationName: string,\n operation: (provider: ProjectManagementProvider, taskRef: ExternalTaskRef) => Promise<void>,\n ): Promise<string[]> {\n if (!ref) {\n return [];\n }\n\n const selectedProviders = this.providers.filter((provider) => provider.id === ref.provider);\n if (selectedProviders.length === 0) {\n return [];\n }\n\n const results = await Promise.allSettled(\n selectedProviders.map(async (provider) => {\n const isReachable = await provider.ping();\n if (!isReachable) {\n throw new Error(`Provider \"${provider.id}\" is unreachable.`);\n }\n await operation(provider, ref);\n }),\n );\n\n const warnings: string[] = [];\n for (let index = 0; index < results.length; index += 1) {\n const result = results[index];\n if (result.status === \"fulfilled\") {\n continue;\n }\n\n warnings.push(\n `${operationName} failed for provider \"${\n selectedProviders[index].id\n }\": ${toErrorMessage(result.reason)}`,\n );\n }\n\n return warnings;\n }\n\n private resolveExternalTaskRef(\n task: Task,\n providedRef?: ExternalTaskRef,\n ): ExternalTaskRef | undefined {\n if (providedRef) {\n return providedRef;\n }\n\n if (task.linkedIssue) {\n return {\n provider: \"github\",\n externalId: `#${task.linkedIssue.number}`,\n url: task.linkedIssue.url,\n };\n }\n\n const metadata = task.metadata as Record<string, unknown>;\n const provider = readMetadataString(metadata, \"externalProvider\");\n const externalId = readMetadataString(metadata, \"externalId\");\n const url = readMetadataString(metadata, \"externalUrl\");\n\n if (!provider || !externalId) {\n return undefined;\n }\n\n return { provider, externalId, url };\n }\n\n private normalizePipelineError(error: unknown, params: CompletionHandlerParams): OacError {\n if (error instanceof OacError) {\n return error;\n }\n\n return completionError(\n \"PR_CREATION_FAILED\",\n `Completion pipeline failed for task \"${params.task.id}\" in \"${params.repo.fullName}\": ${toErrorMessage(\n error,\n )}`,\n {\n cause: error,\n context: {\n jobId: params.jobId,\n taskId: params.task.id,\n repo: params.repo.fullName,\n branchName: params.branchName,\n },\n },\n );\n }\n}\n\nfunction buildCompletionResult(\n params: CompletionHandlerParams,\n pr: CreatedPR,\n warnings: string[],\n): CompletionResult {\n const filesChanged = params.result.filesChanged.length;\n const warningSuffix = warnings.length > 0 ? ` Completed with ${warnings.length} warning(s).` : \"\";\n\n return {\n prUrl: pr.url,\n commitSha: pr.sha,\n summary: `Created PR #${pr.number} for \"${params.task.title}\".${warningSuffix}`,\n filesChanged,\n tokensUsed: params.result.totalTokensUsed,\n };\n}\n\nfunction resolveRepoPath(repo: ResolvedRepo): string {\n return repo.worktreePath.trim().length > 0 ? repo.worktreePath : repo.localPath;\n}\n\nfunction readMetadataString(metadata: Record<string, unknown>, key: string): string | undefined {\n const value = metadata[key];\n if (typeof value === \"string\" && value.trim().length > 0) {\n return value.trim();\n }\n return undefined;\n}\n\nfunction toErrorMessage(error: unknown): string {\n if (error instanceof Error && error.message.trim().length > 0) {\n return error.message.trim();\n }\n return \"Unknown error\";\n}\n"],"mappings":"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","names":["completionError","simpleGit","completionError","readMetadataString","completionError"]}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "@open330/oac-completion",
3
+ "version": "2026.2.17",
4
+ "description": "PR creation and post-execution completion for OAC",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/Open330/open-agent-contribution.git",
9
+ "directory": "packages/completion"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "import": "./dist/index.js",
17
+ "types": "./dist/index.d.ts"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "engines": {
27
+ "node": ">=22.0.0"
28
+ },
29
+ "dependencies": {
30
+ "@octokit/rest": "^21.1.1",
31
+ "simple-git": "^3.27.0",
32
+ "@open330/oac-core": "2026.2.17"
33
+ },
34
+ "devDependencies": {
35
+ "tsup": "^8.3.6",
36
+ "typescript": "^5.7.3"
37
+ },
38
+ "scripts": {
39
+ "build": "tsup src/index.ts --format esm --dts",
40
+ "test": "vitest run",
41
+ "typecheck": "tsc --noEmit"
42
+ }
43
+ }