@paperclipai_dld/plugin-github 2026.319.0-canary.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/constants.d.ts +38 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +30 -0
- package/dist/constants.js.map +1 -0
- package/dist/github-types.d.ts +86 -0
- package/dist/github-types.d.ts.map +1 -0
- package/dist/github-types.js +6 -0
- package/dist/github-types.js.map +1 -0
- package/dist/github.d.ts +55 -0
- package/dist/github.d.ts.map +1 -0
- package/dist/github.js +80 -0
- package/dist/github.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +4 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +96 -0
- package/dist/manifest.js.map +1 -0
- package/dist/sync.d.ts +44 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +107 -0
- package/dist/sync.js.map +1 -0
- package/dist/tools.d.ts +9 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +141 -0
- package/dist/tools.js.map +1 -0
- package/dist/verify-signature.d.ts +10 -0
- package/dist/verify-signature.d.ts.map +1 -0
- package/dist/verify-signature.js +21 -0
- package/dist/verify-signature.js.map +1 -0
- package/dist/worker.d.ts +3 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +368 -0
- package/dist/worker.js.map +1 -0
- package/package.json +29 -0
- package/src/constants.ts +48 -0
- package/src/github-types.ts +61 -0
- package/src/github.ts +152 -0
- package/src/index.ts +6 -0
- package/src/manifest.ts +105 -0
- package/src/sync.ts +193 -0
- package/src/tools.ts +172 -0
- package/src/verify-signature.ts +26 -0
- package/src/worker.ts +488 -0
- package/tsconfig.json +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Paperclip AI
|
|
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,38 @@
|
|
|
1
|
+
export declare const PLUGIN_ID = "paperclip-github";
|
|
2
|
+
export declare const PLUGIN_VERSION = "0.1.0";
|
|
3
|
+
export declare const WEBHOOK_KEYS: {
|
|
4
|
+
readonly github: "github-events";
|
|
5
|
+
};
|
|
6
|
+
export declare const SUPPORTED_GITHUB_EVENTS: readonly ["workflow_run", "check_run", "issues"];
|
|
7
|
+
export type SupportedGitHubEvent = (typeof SUPPORTED_GITHUB_EVENTS)[number];
|
|
8
|
+
export declare const TOOL_NAMES: {
|
|
9
|
+
readonly searchIssues: "github_search_issues";
|
|
10
|
+
readonly linkIssue: "github_link_issue";
|
|
11
|
+
readonly unlinkIssue: "github_unlink_issue";
|
|
12
|
+
};
|
|
13
|
+
export declare const JOB_KEYS: {
|
|
14
|
+
readonly syncLinkedIssues: "sync-linked-issues";
|
|
15
|
+
};
|
|
16
|
+
export declare const DEFAULT_CONFIG: {
|
|
17
|
+
readonly webhookSecret: "";
|
|
18
|
+
readonly companyId: "";
|
|
19
|
+
readonly goalId: "";
|
|
20
|
+
readonly defaultAssigneeAgentId: "";
|
|
21
|
+
readonly defaultRepo: "";
|
|
22
|
+
readonly githubTokenRef: "";
|
|
23
|
+
readonly syncDirection: "bidirectional";
|
|
24
|
+
readonly syncComments: false;
|
|
25
|
+
readonly skipSignatureVerification: false;
|
|
26
|
+
};
|
|
27
|
+
export type PluginConfig = {
|
|
28
|
+
webhookSecret?: string;
|
|
29
|
+
companyId?: string;
|
|
30
|
+
goalId?: string;
|
|
31
|
+
defaultAssigneeAgentId?: string;
|
|
32
|
+
defaultRepo?: string;
|
|
33
|
+
githubTokenRef?: string;
|
|
34
|
+
syncDirection?: "bidirectional" | "github-to-paperclip" | "paperclip-to-github";
|
|
35
|
+
syncComments?: boolean;
|
|
36
|
+
skipSignatureVerification?: boolean;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,SAAS,qBAAqB,CAAC;AAC5C,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,eAAO,MAAM,YAAY;;CAEf,CAAC;AAEX,eAAO,MAAM,uBAAuB,kDAI1B,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5E,eAAO,MAAM,UAAU;;;;CAIb,CAAC;AAEX,eAAO,MAAM,QAAQ;;CAEX,CAAC;AAEX,eAAO,MAAM,cAAc;;;;;;;;;;CAUjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,eAAe,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;IAChF,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yBAAyB,CAAC,EAAE,OAAO,CAAC;CACrC,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export const PLUGIN_ID = "paperclip-github";
|
|
2
|
+
export const PLUGIN_VERSION = "0.1.0";
|
|
3
|
+
export const WEBHOOK_KEYS = {
|
|
4
|
+
github: "github-events",
|
|
5
|
+
};
|
|
6
|
+
export const SUPPORTED_GITHUB_EVENTS = [
|
|
7
|
+
"workflow_run",
|
|
8
|
+
"check_run",
|
|
9
|
+
"issues",
|
|
10
|
+
];
|
|
11
|
+
export const TOOL_NAMES = {
|
|
12
|
+
searchIssues: "github_search_issues",
|
|
13
|
+
linkIssue: "github_link_issue",
|
|
14
|
+
unlinkIssue: "github_unlink_issue",
|
|
15
|
+
};
|
|
16
|
+
export const JOB_KEYS = {
|
|
17
|
+
syncLinkedIssues: "sync-linked-issues",
|
|
18
|
+
};
|
|
19
|
+
export const DEFAULT_CONFIG = {
|
|
20
|
+
webhookSecret: "",
|
|
21
|
+
companyId: "",
|
|
22
|
+
goalId: "",
|
|
23
|
+
defaultAssigneeAgentId: "",
|
|
24
|
+
defaultRepo: "",
|
|
25
|
+
githubTokenRef: "",
|
|
26
|
+
syncDirection: "bidirectional",
|
|
27
|
+
syncComments: false,
|
|
28
|
+
skipSignatureVerification: false,
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,eAAe;CACf,CAAC;AAEX,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,cAAc;IACd,WAAW;IACX,QAAQ;CACA,CAAC;AAIX,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,YAAY,EAAE,sBAAsB;IACpC,SAAS,EAAE,mBAAmB;IAC9B,WAAW,EAAE,qBAAqB;CAC1B,CAAC;AAEX,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,gBAAgB,EAAE,oBAAoB;CAC9B,CAAC;AAEX,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,aAAa,EAAE,EAAE;IACjB,SAAS,EAAE,EAAE;IACb,MAAM,EAAE,EAAE;IACV,sBAAsB,EAAE,EAAE;IAC1B,WAAW,EAAE,EAAE;IACf,cAAc,EAAE,EAAE;IAClB,aAAa,EAAE,eAAwB;IACvC,YAAY,EAAE,KAAK;IACnB,yBAAyB,EAAE,KAAK;CACxB,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal type definitions for the GitHub webhook payloads we care about.
|
|
3
|
+
* Only the fields we actually read are typed; the rest passes through as `unknown`.
|
|
4
|
+
*/
|
|
5
|
+
export interface GitHubWorkflowRunEvent {
|
|
6
|
+
action: "completed" | "requested" | "in_progress" | string;
|
|
7
|
+
workflow_run: {
|
|
8
|
+
id: number;
|
|
9
|
+
name: string;
|
|
10
|
+
head_branch: string;
|
|
11
|
+
head_sha: string;
|
|
12
|
+
status: string;
|
|
13
|
+
conclusion: "success" | "failure" | "cancelled" | "timed_out" | "action_required" | string | null;
|
|
14
|
+
html_url: string;
|
|
15
|
+
run_number: number;
|
|
16
|
+
run_attempt: number;
|
|
17
|
+
actor: {
|
|
18
|
+
login: string;
|
|
19
|
+
} | null;
|
|
20
|
+
head_commit: {
|
|
21
|
+
id: string;
|
|
22
|
+
message: string;
|
|
23
|
+
author: {
|
|
24
|
+
name: string;
|
|
25
|
+
email: string;
|
|
26
|
+
} | null;
|
|
27
|
+
} | null;
|
|
28
|
+
pull_requests: Array<{
|
|
29
|
+
number: number;
|
|
30
|
+
head: {
|
|
31
|
+
ref: string;
|
|
32
|
+
sha: string;
|
|
33
|
+
};
|
|
34
|
+
base: {
|
|
35
|
+
ref: string;
|
|
36
|
+
};
|
|
37
|
+
}>;
|
|
38
|
+
repository?: {
|
|
39
|
+
full_name: string;
|
|
40
|
+
html_url: string;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
repository: {
|
|
44
|
+
full_name: string;
|
|
45
|
+
html_url: string;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export interface GitHubCheckRunEvent {
|
|
49
|
+
action: "completed" | "created" | "rerequested" | "requested_action" | string;
|
|
50
|
+
check_run: {
|
|
51
|
+
id: number;
|
|
52
|
+
name: string;
|
|
53
|
+
status: string;
|
|
54
|
+
conclusion: "success" | "failure" | "cancelled" | "timed_out" | "action_required" | "skipped" | string | null;
|
|
55
|
+
html_url: string;
|
|
56
|
+
head_sha: string;
|
|
57
|
+
output: {
|
|
58
|
+
title: string | null;
|
|
59
|
+
summary: string | null;
|
|
60
|
+
};
|
|
61
|
+
check_suite: {
|
|
62
|
+
id: number;
|
|
63
|
+
head_branch: string;
|
|
64
|
+
pull_requests: Array<{
|
|
65
|
+
number: number;
|
|
66
|
+
head: {
|
|
67
|
+
ref: string;
|
|
68
|
+
sha: string;
|
|
69
|
+
};
|
|
70
|
+
base: {
|
|
71
|
+
ref: string;
|
|
72
|
+
};
|
|
73
|
+
}>;
|
|
74
|
+
} | null;
|
|
75
|
+
app: {
|
|
76
|
+
slug: string;
|
|
77
|
+
name: string;
|
|
78
|
+
} | null;
|
|
79
|
+
};
|
|
80
|
+
repository: {
|
|
81
|
+
full_name: string;
|
|
82
|
+
html_url: string;
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
export type GitHubWebhookPayload = GitHubWorkflowRunEvent | GitHubCheckRunEvent;
|
|
86
|
+
//# sourceMappingURL=github-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-types.d.ts","sourceRoot":"","sources":["../src/github-types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,MAAM,CAAC;IAC3D,YAAY,EAAE;QACZ,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,iBAAiB,GAAG,MAAM,GAAG,IAAI,CAAC;QAClG,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAChC,WAAW,EAAE;YACX,EAAE,EAAE,MAAM,CAAC;YACX,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,GAAG,IAAI,CAAC;SAChD,GAAG,IAAI,CAAC;QACT,aAAa,EAAE,KAAK,CAAC;YACnB,MAAM,EAAE,MAAM,CAAC;YACf,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;YACnC,IAAI,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;SACvB,CAAC,CAAC;QACH,UAAU,CAAC,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAC;KACtD,CAAC;IACF,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,aAAa,GAAG,kBAAkB,GAAG,MAAM,CAAC;IAC9E,SAAS,EAAE;QACT,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,iBAAiB,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAAC;QAC9G,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE;YACN,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;YACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;SACxB,CAAC;QACF,WAAW,EAAE;YACX,EAAE,EAAE,MAAM,CAAC;YACX,WAAW,EAAE,MAAM,CAAC;YACpB,aAAa,EAAE,KAAK,CAAC;gBACnB,MAAM,EAAE,MAAM,CAAC;gBACf,IAAI,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAC;oBAAC,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAC;gBACnC,IAAI,EAAE;oBAAE,GAAG,EAAE,MAAM,CAAA;iBAAE,CAAC;aACvB,CAAC,CAAC;SACJ,GAAG,IAAI,CAAC;QACT,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;KAC5C,CAAC;IACF,UAAU,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,MAAM,MAAM,oBAAoB,GAAG,sBAAsB,GAAG,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github-types.js","sourceRoot":"","sources":["../src/github-types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/dist/github.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub REST API client. Uses the plugin SDK's http.fetch for outbound calls
|
|
3
|
+
* so all requests go through the capability-gated host proxy.
|
|
4
|
+
*/
|
|
5
|
+
interface GitHubFetch {
|
|
6
|
+
(url: string, init?: RequestInit): Promise<Response>;
|
|
7
|
+
}
|
|
8
|
+
export interface GitHubIssue {
|
|
9
|
+
number: number;
|
|
10
|
+
title: string;
|
|
11
|
+
body: string | null;
|
|
12
|
+
state: "open" | "closed";
|
|
13
|
+
html_url: string;
|
|
14
|
+
labels: Array<{
|
|
15
|
+
name: string;
|
|
16
|
+
color: string;
|
|
17
|
+
}>;
|
|
18
|
+
assignees: Array<{
|
|
19
|
+
login: string;
|
|
20
|
+
}>;
|
|
21
|
+
created_at: string;
|
|
22
|
+
updated_at: string;
|
|
23
|
+
closed_at: string | null;
|
|
24
|
+
}
|
|
25
|
+
export interface GitHubComment {
|
|
26
|
+
id: number;
|
|
27
|
+
body: string;
|
|
28
|
+
user: {
|
|
29
|
+
login: string;
|
|
30
|
+
};
|
|
31
|
+
created_at: string;
|
|
32
|
+
html_url: string;
|
|
33
|
+
}
|
|
34
|
+
export interface GitHubSearchResult {
|
|
35
|
+
total_count: number;
|
|
36
|
+
items: GitHubIssue[];
|
|
37
|
+
}
|
|
38
|
+
export declare function searchIssues(fetch: GitHubFetch, token: string, repo: string, query: string): Promise<GitHubSearchResult>;
|
|
39
|
+
export declare function getIssue(fetch: GitHubFetch, token: string, owner: string, repo: string, number: number): Promise<GitHubIssue>;
|
|
40
|
+
export declare function updateIssueState(fetch: GitHubFetch, token: string, owner: string, repo: string, number: number, state: "open" | "closed"): Promise<GitHubIssue>;
|
|
41
|
+
export declare function listComments(fetch: GitHubFetch, token: string, owner: string, repo: string, number: number, since?: string): Promise<GitHubComment[]>;
|
|
42
|
+
export declare function createComment(fetch: GitHubFetch, token: string, owner: string, repo: string, number: number, body: string): Promise<GitHubComment>;
|
|
43
|
+
/**
|
|
44
|
+
* Parse a GitHub issue reference from various formats:
|
|
45
|
+
* - https://github.com/owner/repo/issues/123
|
|
46
|
+
* - owner/repo#123
|
|
47
|
+
* - #123 (requires default repo)
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseGitHubIssueRef(ref: string, defaultRepo?: string): {
|
|
50
|
+
owner: string;
|
|
51
|
+
repo: string;
|
|
52
|
+
number: number;
|
|
53
|
+
} | null;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=github.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,UAAU,WAAW;IACnB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtD;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,SAAS,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAUD,wBAAsB,YAAY,CAChC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC,CAO7B;AAED,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAMtB;AAED,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,QAAQ,GACvB,OAAO,CAAC,WAAW,CAAC,CAQtB;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,EAAE,CAAC,CAQ1B;AAED,wBAAsB,aAAa,CACjC,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CAQxB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,WAAW,CAAC,EAAE,MAAM,GACnB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkBxD"}
|
package/dist/github.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub REST API client. Uses the plugin SDK's http.fetch for outbound calls
|
|
3
|
+
* so all requests go through the capability-gated host proxy.
|
|
4
|
+
*/
|
|
5
|
+
const GITHUB_API = "https://api.github.com";
|
|
6
|
+
function headers(token) {
|
|
7
|
+
return {
|
|
8
|
+
Authorization: `Bearer ${token}`,
|
|
9
|
+
Accept: "application/vnd.github+json",
|
|
10
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export async function searchIssues(fetch, token, repo, query) {
|
|
14
|
+
const q = encodeURIComponent(`repo:${repo} is:issue ${query}`);
|
|
15
|
+
const res = await fetch(`${GITHUB_API}/search/issues?q=${q}&per_page=10`, {
|
|
16
|
+
headers: headers(token),
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok)
|
|
19
|
+
throw new Error(`GitHub search failed: ${res.status} ${res.statusText}`);
|
|
20
|
+
return res.json();
|
|
21
|
+
}
|
|
22
|
+
export async function getIssue(fetch, token, owner, repo, number) {
|
|
23
|
+
const res = await fetch(`${GITHUB_API}/repos/${owner}/${repo}/issues/${number}`, {
|
|
24
|
+
headers: headers(token),
|
|
25
|
+
});
|
|
26
|
+
if (!res.ok)
|
|
27
|
+
throw new Error(`GitHub get issue failed: ${res.status} ${res.statusText}`);
|
|
28
|
+
return res.json();
|
|
29
|
+
}
|
|
30
|
+
export async function updateIssueState(fetch, token, owner, repo, number, state) {
|
|
31
|
+
const res = await fetch(`${GITHUB_API}/repos/${owner}/${repo}/issues/${number}`, {
|
|
32
|
+
method: "PATCH",
|
|
33
|
+
headers: { ...headers(token), "Content-Type": "application/json" },
|
|
34
|
+
body: JSON.stringify({ state }),
|
|
35
|
+
});
|
|
36
|
+
if (!res.ok)
|
|
37
|
+
throw new Error(`GitHub update issue failed: ${res.status} ${res.statusText}`);
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
export async function listComments(fetch, token, owner, repo, number, since) {
|
|
41
|
+
const params = since ? `?since=${encodeURIComponent(since)}` : "";
|
|
42
|
+
const res = await fetch(`${GITHUB_API}/repos/${owner}/${repo}/issues/${number}/comments${params}`, { headers: headers(token) });
|
|
43
|
+
if (!res.ok)
|
|
44
|
+
throw new Error(`GitHub list comments failed: ${res.status} ${res.statusText}`);
|
|
45
|
+
return res.json();
|
|
46
|
+
}
|
|
47
|
+
export async function createComment(fetch, token, owner, repo, number, body) {
|
|
48
|
+
const res = await fetch(`${GITHUB_API}/repos/${owner}/${repo}/issues/${number}/comments`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: { ...headers(token), "Content-Type": "application/json" },
|
|
51
|
+
body: JSON.stringify({ body }),
|
|
52
|
+
});
|
|
53
|
+
if (!res.ok)
|
|
54
|
+
throw new Error(`GitHub create comment failed: ${res.status} ${res.statusText}`);
|
|
55
|
+
return res.json();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse a GitHub issue reference from various formats:
|
|
59
|
+
* - https://github.com/owner/repo/issues/123
|
|
60
|
+
* - owner/repo#123
|
|
61
|
+
* - #123 (requires default repo)
|
|
62
|
+
*/
|
|
63
|
+
export function parseGitHubIssueRef(ref, defaultRepo) {
|
|
64
|
+
const urlMatch = ref.match(/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)/);
|
|
65
|
+
if (urlMatch) {
|
|
66
|
+
return { owner: urlMatch[1], repo: urlMatch[2], number: parseInt(urlMatch[3], 10) };
|
|
67
|
+
}
|
|
68
|
+
const refMatch = ref.match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
69
|
+
if (refMatch) {
|
|
70
|
+
return { owner: refMatch[1], repo: refMatch[2], number: parseInt(refMatch[3], 10) };
|
|
71
|
+
}
|
|
72
|
+
const numMatch = ref.match(/^#?(\d+)$/);
|
|
73
|
+
if (numMatch && defaultRepo) {
|
|
74
|
+
const [owner, repo] = defaultRepo.split("/");
|
|
75
|
+
if (owner && repo)
|
|
76
|
+
return { owner, repo, number: parseInt(numMatch[1], 10) };
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../src/github.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as manifest } from "./manifest.js";
|
|
2
|
+
export * from "./constants.js";
|
|
3
|
+
export * from "./verify-signature.js";
|
|
4
|
+
export type * from "./github-types.js";
|
|
5
|
+
export * as sync from "./sync.js";
|
|
6
|
+
export * as githubApi from "./github.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AACtC,mBAAmB,mBAAmB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,eAAe,CAAC;AACpD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,uBAAuB,CAAC;AAEtC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,SAAS,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAG7E,QAAA,MAAM,QAAQ,EAAE,yBAmGf,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { DEFAULT_CONFIG, PLUGIN_ID, PLUGIN_VERSION, WEBHOOK_KEYS } from "./constants.js";
|
|
2
|
+
const manifest = {
|
|
3
|
+
id: PLUGIN_ID,
|
|
4
|
+
apiVersion: 1,
|
|
5
|
+
version: PLUGIN_VERSION,
|
|
6
|
+
displayName: "GitHub",
|
|
7
|
+
description: "GitHub integration for Paperclip. Phase 1: receives GitHub Actions webhook events (workflow_run, check_run) and creates Paperclip issues on CI failures. Phase 2: bidirectional issue sync, status bridging, and agent tools for searching and linking GitHub issues.",
|
|
8
|
+
author: "Paperclip",
|
|
9
|
+
categories: ["connector", "automation"],
|
|
10
|
+
capabilities: [
|
|
11
|
+
"webhooks.receive",
|
|
12
|
+
"issues.read",
|
|
13
|
+
"issues.create",
|
|
14
|
+
"issues.update",
|
|
15
|
+
"issue.comments.read",
|
|
16
|
+
"issue.comments.create",
|
|
17
|
+
"agents.read",
|
|
18
|
+
"agents.invoke",
|
|
19
|
+
"plugin.state.read",
|
|
20
|
+
"plugin.state.write",
|
|
21
|
+
"http.outbound",
|
|
22
|
+
"secrets.read-ref",
|
|
23
|
+
],
|
|
24
|
+
entrypoints: {
|
|
25
|
+
worker: "./dist/worker.js",
|
|
26
|
+
},
|
|
27
|
+
instanceConfigSchema: {
|
|
28
|
+
type: "object",
|
|
29
|
+
properties: {
|
|
30
|
+
webhookSecret: {
|
|
31
|
+
type: "string",
|
|
32
|
+
title: "GitHub Webhook Secret",
|
|
33
|
+
description: "Shared secret for HMAC-SHA256 signature verification of incoming GitHub webhooks.",
|
|
34
|
+
default: DEFAULT_CONFIG.webhookSecret,
|
|
35
|
+
},
|
|
36
|
+
companyId: {
|
|
37
|
+
type: "string",
|
|
38
|
+
title: "Company ID",
|
|
39
|
+
description: "Paperclip company ID where failure issues are created.",
|
|
40
|
+
default: DEFAULT_CONFIG.companyId,
|
|
41
|
+
},
|
|
42
|
+
goalId: {
|
|
43
|
+
type: "string",
|
|
44
|
+
title: "Goal ID",
|
|
45
|
+
description: "Goal to associate CI failure issues with.",
|
|
46
|
+
default: DEFAULT_CONFIG.goalId,
|
|
47
|
+
},
|
|
48
|
+
defaultAssigneeAgentId: {
|
|
49
|
+
type: "string",
|
|
50
|
+
title: "Default Assignee Agent ID",
|
|
51
|
+
description: "Agent to assign CI failure issues to when the committing agent cannot be determined.",
|
|
52
|
+
default: DEFAULT_CONFIG.defaultAssigneeAgentId,
|
|
53
|
+
},
|
|
54
|
+
defaultRepo: {
|
|
55
|
+
type: "string",
|
|
56
|
+
title: "Default Repository",
|
|
57
|
+
description: "Default GitHub repository in owner/repo format for agent tools and issue references.",
|
|
58
|
+
default: DEFAULT_CONFIG.defaultRepo,
|
|
59
|
+
},
|
|
60
|
+
githubTokenRef: {
|
|
61
|
+
type: "string",
|
|
62
|
+
title: "GitHub Token Secret Ref",
|
|
63
|
+
description: "Paperclip secret reference name (or ID) for a GitHub Personal Access Token with repo scope. Required for GitHub API calls (search, sync, agent tools).",
|
|
64
|
+
default: DEFAULT_CONFIG.githubTokenRef,
|
|
65
|
+
},
|
|
66
|
+
syncDirection: {
|
|
67
|
+
type: "string",
|
|
68
|
+
title: "Sync Direction",
|
|
69
|
+
enum: ["bidirectional", "github-to-paperclip", "paperclip-to-github"],
|
|
70
|
+
description: "Direction of issue state synchronisation when a GitHub link is active.",
|
|
71
|
+
default: DEFAULT_CONFIG.syncDirection,
|
|
72
|
+
},
|
|
73
|
+
syncComments: {
|
|
74
|
+
type: "boolean",
|
|
75
|
+
title: "Sync Comments",
|
|
76
|
+
description: "When enabled, new GitHub comments are mirrored to linked Paperclip issues.",
|
|
77
|
+
default: DEFAULT_CONFIG.syncComments,
|
|
78
|
+
},
|
|
79
|
+
skipSignatureVerification: {
|
|
80
|
+
type: "boolean",
|
|
81
|
+
title: "Skip Signature Verification",
|
|
82
|
+
description: "Development only — skip GitHub webhook HMAC verification.",
|
|
83
|
+
default: DEFAULT_CONFIG.skipSignatureVerification,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
webhooks: [
|
|
88
|
+
{
|
|
89
|
+
endpointKey: WEBHOOK_KEYS.github,
|
|
90
|
+
displayName: "GitHub Events",
|
|
91
|
+
description: "Receives workflow_run and check_run events from GitHub. Configure your GitHub repo webhook to POST to this endpoint.",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
export default manifest;
|
|
96
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEzF,MAAM,QAAQ,GAA8B;IAC1C,EAAE,EAAE,SAAS;IACb,UAAU,EAAE,CAAC;IACb,OAAO,EAAE,cAAc;IACvB,WAAW,EAAE,QAAQ;IACrB,WAAW,EACT,uQAAuQ;IACzQ,MAAM,EAAE,WAAW;IACnB,UAAU,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;IACvC,YAAY,EAAE;QACZ,kBAAkB;QAClB,aAAa;QACb,eAAe;QACf,eAAe;QACf,qBAAqB;QACrB,uBAAuB;QACvB,aAAa;QACb,eAAe;QACf,mBAAmB;QACnB,oBAAoB;QACpB,eAAe;QACf,kBAAkB;KACnB;IACD,WAAW,EAAE;QACX,MAAM,EAAE,kBAAkB;KAC3B;IACD,oBAAoB,EAAE;QACpB,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE;YACV,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,uBAAuB;gBAC9B,WAAW,EACT,mFAAmF;gBACrF,OAAO,EAAE,cAAc,CAAC,aAAa;aACtC;YACD,SAAS,EAAE;gBACT,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,YAAY;gBACnB,WAAW,EAAE,wDAAwD;gBACrE,OAAO,EAAE,cAAc,CAAC,SAAS;aAClC;YACD,MAAM,EAAE;gBACN,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,SAAS;gBAChB,WAAW,EAAE,2CAA2C;gBACxD,OAAO,EAAE,cAAc,CAAC,MAAM;aAC/B;YACD,sBAAsB,EAAE;gBACtB,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,2BAA2B;gBAClC,WAAW,EACT,sFAAsF;gBACxF,OAAO,EAAE,cAAc,CAAC,sBAAsB;aAC/C;YACD,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,oBAAoB;gBAC3B,WAAW,EACT,sFAAsF;gBACxF,OAAO,EAAE,cAAc,CAAC,WAAW;aACpC;YACD,cAAc,EAAE;gBACd,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,yBAAyB;gBAChC,WAAW,EACT,wJAAwJ;gBAC1J,OAAO,EAAE,cAAc,CAAC,cAAc;aACvC;YACD,aAAa,EAAE;gBACb,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,gBAAgB;gBACvB,IAAI,EAAE,CAAC,eAAe,EAAE,qBAAqB,EAAE,qBAAqB,CAAC;gBACrE,WAAW,EACT,wEAAwE;gBAC1E,OAAO,EAAE,cAAc,CAAC,aAAa;aACtC;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,eAAe;gBACtB,WAAW,EAAE,4EAA4E;gBACzF,OAAO,EAAE,cAAc,CAAC,YAAY;aACrC;YACD,yBAAyB,EAAE;gBACzB,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,6BAA6B;gBACpC,WAAW,EAAE,2DAA2D;gBACxE,OAAO,EAAE,cAAc,CAAC,yBAAyB;aAClD;SACF;KACF;IACD,QAAQ,EAAE;QACR;YACE,WAAW,EAAE,YAAY,CAAC,MAAM;YAChC,WAAW,EAAE,eAAe;YAC5B,WAAW,EACT,sHAAsH;SACzH;KACF;CACF,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
package/dist/sync.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync logic between GitHub Issues and Paperclip issues.
|
|
3
|
+
* Manages link state in plugin state storage and handles
|
|
4
|
+
* bidirectional status + comment syncing.
|
|
5
|
+
*
|
|
6
|
+
* SDK fix applied: removed `scopeId: "default"` from all `{ scopeKind: "instance" }` state
|
|
7
|
+
* calls — `scopeId` must be omitted for instance-scoped keys per current SDK contract.
|
|
8
|
+
*/
|
|
9
|
+
import type { PluginContext } from "@paperclipai_dld/plugin-sdk";
|
|
10
|
+
export interface IssueLink {
|
|
11
|
+
paperclipIssueId: string;
|
|
12
|
+
paperclipCompanyId: string;
|
|
13
|
+
ghOwner: string;
|
|
14
|
+
ghRepo: string;
|
|
15
|
+
ghNumber: number;
|
|
16
|
+
ghHtmlUrl: string;
|
|
17
|
+
syncDirection: "bidirectional" | "github-to-paperclip" | "paperclip-to-github";
|
|
18
|
+
lastSyncAt: string;
|
|
19
|
+
lastGhState: "open" | "closed";
|
|
20
|
+
lastCommentSyncAt: string | null;
|
|
21
|
+
}
|
|
22
|
+
export declare function getLink(ctx: PluginContext, paperclipIssueId: string): Promise<IssueLink | null>;
|
|
23
|
+
export declare function getLinkByGitHub(ctx: PluginContext, owner: string, repo: string, number: number): Promise<IssueLink | null>;
|
|
24
|
+
export declare function createLink(ctx: PluginContext, params: {
|
|
25
|
+
paperclipIssueId: string;
|
|
26
|
+
paperclipCompanyId: string;
|
|
27
|
+
ghOwner: string;
|
|
28
|
+
ghRepo: string;
|
|
29
|
+
ghNumber: number;
|
|
30
|
+
ghHtmlUrl: string;
|
|
31
|
+
ghState: "open" | "closed";
|
|
32
|
+
syncDirection: IssueLink["syncDirection"];
|
|
33
|
+
}): Promise<IssueLink>;
|
|
34
|
+
export declare function updateLink(ctx: PluginContext, paperclipIssueId: string, patch: Partial<Pick<IssueLink, "lastSyncAt" | "lastGhState" | "lastCommentSyncAt" | "syncDirection">>): Promise<IssueLink | null>;
|
|
35
|
+
export declare function deleteLink(ctx: PluginContext, paperclipIssueId: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Sync a GitHub issue state change to the linked Paperclip issue.
|
|
38
|
+
*/
|
|
39
|
+
export declare function syncGitHubStateToPaperclip(ctx: PluginContext, link: IssueLink, ghState: "open" | "closed"): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Sync new GitHub comments to the linked Paperclip issue.
|
|
42
|
+
*/
|
|
43
|
+
export declare function syncGitHubCommentsToPaperclip(ctx: PluginContext, link: IssueLink, fetch: PluginContext["http"]["fetch"], token: string): Promise<void>;
|
|
44
|
+
//# sourceMappingURL=sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../src/sync.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAMjE,MAAM,WAAW,SAAS;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,eAAe,GAAG,qBAAqB,GAAG,qBAAqB,CAAC;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC/B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAUD,wBAAsB,OAAO,CAC3B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAO3B;AAED,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAQ3B;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE;IACN,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC3B,aAAa,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;CAC3C,GACA,OAAO,CAAC,SAAS,CAAC,CAyBpB;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,EACxB,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,GAAG,aAAa,GAAG,mBAAmB,GAAG,eAAe,CAAC,CAAC,GACpG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAY3B;AAED,wBAAsB,UAAU,CAC9B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,GACvB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GAAG,QAAQ,GACzB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAsB,6BAA6B,CACjD,GAAG,EAAE,aAAa,EAClB,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EACrC,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAsBf"}
|
package/dist/sync.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync logic between GitHub Issues and Paperclip issues.
|
|
3
|
+
* Manages link state in plugin state storage and handles
|
|
4
|
+
* bidirectional status + comment syncing.
|
|
5
|
+
*
|
|
6
|
+
* SDK fix applied: removed `scopeId: "default"` from all `{ scopeKind: "instance" }` state
|
|
7
|
+
* calls — `scopeId` must be omitted for instance-scoped keys per current SDK contract.
|
|
8
|
+
*/
|
|
9
|
+
import * as github from "./github.js";
|
|
10
|
+
const LINK_PREFIX = "link:";
|
|
11
|
+
const GH_PREFIX = "gh:";
|
|
12
|
+
function linkStateKey(paperclipIssueId) {
|
|
13
|
+
return `${LINK_PREFIX}${paperclipIssueId}`;
|
|
14
|
+
}
|
|
15
|
+
function ghStateKey(owner, repo, number) {
|
|
16
|
+
return `${GH_PREFIX}${owner}/${repo}#${number}`;
|
|
17
|
+
}
|
|
18
|
+
export async function getLink(ctx, paperclipIssueId) {
|
|
19
|
+
const raw = await ctx.state.get({
|
|
20
|
+
scopeKind: "instance",
|
|
21
|
+
stateKey: linkStateKey(paperclipIssueId),
|
|
22
|
+
});
|
|
23
|
+
if (!raw)
|
|
24
|
+
return null;
|
|
25
|
+
return JSON.parse(String(raw));
|
|
26
|
+
}
|
|
27
|
+
export async function getLinkByGitHub(ctx, owner, repo, number) {
|
|
28
|
+
const raw = await ctx.state.get({
|
|
29
|
+
scopeKind: "instance",
|
|
30
|
+
stateKey: ghStateKey(owner, repo, number),
|
|
31
|
+
});
|
|
32
|
+
if (!raw)
|
|
33
|
+
return null;
|
|
34
|
+
const paperclipIssueId = String(raw);
|
|
35
|
+
return getLink(ctx, paperclipIssueId);
|
|
36
|
+
}
|
|
37
|
+
export async function createLink(ctx, params) {
|
|
38
|
+
const link = {
|
|
39
|
+
paperclipIssueId: params.paperclipIssueId,
|
|
40
|
+
paperclipCompanyId: params.paperclipCompanyId,
|
|
41
|
+
ghOwner: params.ghOwner,
|
|
42
|
+
ghRepo: params.ghRepo,
|
|
43
|
+
ghNumber: params.ghNumber,
|
|
44
|
+
ghHtmlUrl: params.ghHtmlUrl,
|
|
45
|
+
syncDirection: params.syncDirection,
|
|
46
|
+
lastSyncAt: new Date().toISOString(),
|
|
47
|
+
lastGhState: params.ghState,
|
|
48
|
+
lastCommentSyncAt: null,
|
|
49
|
+
};
|
|
50
|
+
await ctx.state.set({ scopeKind: "instance", stateKey: linkStateKey(params.paperclipIssueId) }, JSON.stringify(link));
|
|
51
|
+
await ctx.state.set({ scopeKind: "instance", stateKey: ghStateKey(params.ghOwner, params.ghRepo, params.ghNumber) }, params.paperclipIssueId);
|
|
52
|
+
return link;
|
|
53
|
+
}
|
|
54
|
+
export async function updateLink(ctx, paperclipIssueId, patch) {
|
|
55
|
+
const existing = await getLink(ctx, paperclipIssueId);
|
|
56
|
+
if (!existing)
|
|
57
|
+
return null;
|
|
58
|
+
const updated = { ...existing, ...patch };
|
|
59
|
+
await ctx.state.set({ scopeKind: "instance", stateKey: linkStateKey(paperclipIssueId) }, JSON.stringify(updated));
|
|
60
|
+
return updated;
|
|
61
|
+
}
|
|
62
|
+
export async function deleteLink(ctx, paperclipIssueId) {
|
|
63
|
+
const existing = await getLink(ctx, paperclipIssueId);
|
|
64
|
+
if (!existing)
|
|
65
|
+
return;
|
|
66
|
+
await ctx.state.delete({
|
|
67
|
+
scopeKind: "instance",
|
|
68
|
+
stateKey: linkStateKey(paperclipIssueId),
|
|
69
|
+
});
|
|
70
|
+
await ctx.state.delete({
|
|
71
|
+
scopeKind: "instance",
|
|
72
|
+
stateKey: ghStateKey(existing.ghOwner, existing.ghRepo, existing.ghNumber),
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Sync a GitHub issue state change to the linked Paperclip issue.
|
|
77
|
+
*/
|
|
78
|
+
export async function syncGitHubStateToPaperclip(ctx, link, ghState) {
|
|
79
|
+
if (link.syncDirection === "paperclip-to-github")
|
|
80
|
+
return;
|
|
81
|
+
if (link.lastGhState === ghState)
|
|
82
|
+
return;
|
|
83
|
+
const paperclipStatus = ghState === "closed" ? "done" : "in_progress";
|
|
84
|
+
await ctx.issues.update(link.paperclipIssueId, { status: paperclipStatus }, link.paperclipCompanyId);
|
|
85
|
+
await updateLink(ctx, link.paperclipIssueId, {
|
|
86
|
+
lastSyncAt: new Date().toISOString(),
|
|
87
|
+
lastGhState: ghState,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Sync new GitHub comments to the linked Paperclip issue.
|
|
92
|
+
*/
|
|
93
|
+
export async function syncGitHubCommentsToPaperclip(ctx, link, fetch, token) {
|
|
94
|
+
if (link.syncDirection === "paperclip-to-github")
|
|
95
|
+
return;
|
|
96
|
+
const comments = await github.listComments(fetch, token, link.ghOwner, link.ghRepo, link.ghNumber, link.lastCommentSyncAt ?? undefined);
|
|
97
|
+
for (const comment of comments) {
|
|
98
|
+
const body = `**[${comment.user.login} on GitHub](${comment.html_url}):**\n\n${comment.body}`;
|
|
99
|
+
await ctx.issues.createComment(link.paperclipIssueId, body, link.paperclipCompanyId);
|
|
100
|
+
}
|
|
101
|
+
if (comments.length > 0) {
|
|
102
|
+
await updateLink(ctx, link.paperclipIssueId, {
|
|
103
|
+
lastCommentSyncAt: new Date().toISOString(),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=sync.js.map
|