@triedotdev/mcp 1.0.169 → 1.0.170
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -545
- package/dist/chunk-2YXOBNKW.js +619 -0
- package/dist/chunk-2YXOBNKW.js.map +1 -0
- package/dist/chunk-QR64Y5TI.js +363 -0
- package/dist/chunk-QR64Y5TI.js.map +1 -0
- package/dist/cli/main.d.ts +0 -15
- package/dist/cli/main.js +356 -3098
- package/dist/cli/main.js.map +1 -1
- package/dist/index.js +2 -34
- package/dist/index.js.map +1 -1
- package/dist/server/mcp-server.js +2 -34
- package/package.json +8 -31
- package/dist/autonomy-config-FSERX3O3.js +0 -30
- package/dist/autonomy-config-FSERX3O3.js.map +0 -1
- package/dist/chat-store-JNGNTDSN.js +0 -15
- package/dist/chat-store-JNGNTDSN.js.map +0 -1
- package/dist/chunk-2HF65EHQ.js +0 -311
- package/dist/chunk-2HF65EHQ.js.map +0 -1
- package/dist/chunk-3XR6WVAW.js +0 -4011
- package/dist/chunk-3XR6WVAW.js.map +0 -1
- package/dist/chunk-43X6JBEM.js +0 -36
- package/dist/chunk-43X6JBEM.js.map +0 -1
- package/dist/chunk-6NLHFIYA.js +0 -344
- package/dist/chunk-6NLHFIYA.js.map +0 -1
- package/dist/chunk-7IO4YUI3.js +0 -1827
- package/dist/chunk-7IO4YUI3.js.map +0 -1
- package/dist/chunk-AHD2CBQ7.js +0 -846
- package/dist/chunk-AHD2CBQ7.js.map +0 -1
- package/dist/chunk-BUTOP5EB.js +0 -931
- package/dist/chunk-BUTOP5EB.js.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -11
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-EFWVF6TI.js +0 -267
- package/dist/chunk-EFWVF6TI.js.map +0 -1
- package/dist/chunk-F6WFNUAY.js +0 -216
- package/dist/chunk-F6WFNUAY.js.map +0 -1
- package/dist/chunk-FBNURWRY.js +0 -662
- package/dist/chunk-FBNURWRY.js.map +0 -1
- package/dist/chunk-FQ45QP5A.js +0 -361
- package/dist/chunk-FQ45QP5A.js.map +0 -1
- package/dist/chunk-FVRO5RN3.js +0 -1306
- package/dist/chunk-FVRO5RN3.js.map +0 -1
- package/dist/chunk-G2TGF6TR.js +0 -573
- package/dist/chunk-G2TGF6TR.js.map +0 -1
- package/dist/chunk-G3I7SZLW.js +0 -354
- package/dist/chunk-G3I7SZLW.js.map +0 -1
- package/dist/chunk-GTKYBOXL.js +0 -700
- package/dist/chunk-GTKYBOXL.js.map +0 -1
- package/dist/chunk-HVCDY3AK.js +0 -850
- package/dist/chunk-HVCDY3AK.js.map +0 -1
- package/dist/chunk-I2O5OYQT.js +0 -727
- package/dist/chunk-I2O5OYQT.js.map +0 -1
- package/dist/chunk-JVMBCWKS.js +0 -348
- package/dist/chunk-JVMBCWKS.js.map +0 -1
- package/dist/chunk-KCUOWRPX.js +0 -816
- package/dist/chunk-KCUOWRPX.js.map +0 -1
- package/dist/chunk-KDHN2ZQE.js +0 -313
- package/dist/chunk-KDHN2ZQE.js.map +0 -1
- package/dist/chunk-ME2OERF5.js +0 -345
- package/dist/chunk-ME2OERF5.js.map +0 -1
- package/dist/chunk-OBQ74FOU.js +0 -27
- package/dist/chunk-OBQ74FOU.js.map +0 -1
- package/dist/chunk-Q5EKA5YA.js +0 -254
- package/dist/chunk-Q5EKA5YA.js.map +0 -1
- package/dist/chunk-Q63FFI6D.js +0 -132
- package/dist/chunk-Q63FFI6D.js.map +0 -1
- package/dist/chunk-SASNMSB5.js +0 -12597
- package/dist/chunk-SASNMSB5.js.map +0 -1
- package/dist/chunk-T63OHG4Q.js +0 -440
- package/dist/chunk-T63OHG4Q.js.map +0 -1
- package/dist/chunk-TN5WEKWI.js +0 -173
- package/dist/chunk-TN5WEKWI.js.map +0 -1
- package/dist/chunk-VUL52BQL.js +0 -402
- package/dist/chunk-VUL52BQL.js.map +0 -1
- package/dist/chunk-VVITXIHN.js +0 -189
- package/dist/chunk-VVITXIHN.js.map +0 -1
- package/dist/chunk-WCN7S3EI.js +0 -14
- package/dist/chunk-WCN7S3EI.js.map +0 -1
- package/dist/chunk-XPZZFPBZ.js +0 -491
- package/dist/chunk-XPZZFPBZ.js.map +0 -1
- package/dist/chunk-ZJF5FTBX.js +0 -1396
- package/dist/chunk-ZJF5FTBX.js.map +0 -1
- package/dist/chunk-ZV2K6M7T.js +0 -74
- package/dist/chunk-ZV2K6M7T.js.map +0 -1
- package/dist/cli/create-agent.d.ts +0 -1
- package/dist/cli/create-agent.js +0 -1050
- package/dist/cli/create-agent.js.map +0 -1
- package/dist/cli/yolo-daemon.d.ts +0 -1
- package/dist/cli/yolo-daemon.js +0 -421
- package/dist/cli/yolo-daemon.js.map +0 -1
- package/dist/client-NJPZE5JT.js +0 -28
- package/dist/client-NJPZE5JT.js.map +0 -1
- package/dist/codebase-index-VAPF32XX.js +0 -12
- package/dist/codebase-index-VAPF32XX.js.map +0 -1
- package/dist/fast-analyzer-3GCCZMLK.js +0 -216
- package/dist/fast-analyzer-3GCCZMLK.js.map +0 -1
- package/dist/git-EO5SRFMN.js +0 -28
- package/dist/git-EO5SRFMN.js.map +0 -1
- package/dist/github-ingester-ZOKK6GRS.js +0 -11
- package/dist/github-ingester-ZOKK6GRS.js.map +0 -1
- package/dist/goal-manager-QUKX2W6C.js +0 -25
- package/dist/goal-manager-QUKX2W6C.js.map +0 -1
- package/dist/goal-validator-2SFSKKVU.js +0 -24
- package/dist/goal-validator-2SFSKKVU.js.map +0 -1
- package/dist/graph-B3NA4S7I.js +0 -10
- package/dist/graph-B3NA4S7I.js.map +0 -1
- package/dist/hypothesis-KCPBR652.js +0 -23
- package/dist/hypothesis-KCPBR652.js.map +0 -1
- package/dist/incident-index-EFNUSGWL.js +0 -11
- package/dist/incident-index-EFNUSGWL.js.map +0 -1
- package/dist/insight-store-EC4PLSAW.js +0 -22
- package/dist/insight-store-EC4PLSAW.js.map +0 -1
- package/dist/issue-store-YAXTNRRY.js +0 -36
- package/dist/issue-store-YAXTNRRY.js.map +0 -1
- package/dist/ledger-TWZTGDFA.js +0 -58
- package/dist/ledger-TWZTGDFA.js.map +0 -1
- package/dist/linear-ingester-XXPAZZRW.js +0 -11
- package/dist/linear-ingester-XXPAZZRW.js.map +0 -1
- package/dist/output-manager-RVJ37XKA.js +0 -13
- package/dist/output-manager-RVJ37XKA.js.map +0 -1
- package/dist/parse-goal-violation-SACGFG3C.js +0 -8
- package/dist/parse-goal-violation-SACGFG3C.js.map +0 -1
- package/dist/pattern-discovery-F7LU5K6E.js +0 -8
- package/dist/pattern-discovery-F7LU5K6E.js.map +0 -1
- package/dist/progress-SRQ2V3BP.js +0 -18
- package/dist/progress-SRQ2V3BP.js.map +0 -1
- package/dist/project-state-AHPA77SM.js +0 -28
- package/dist/project-state-AHPA77SM.js.map +0 -1
- package/dist/sync-M2FSWPBC.js +0 -12
- package/dist/sync-M2FSWPBC.js.map +0 -1
- package/dist/terminal-spawn-5YXDMUCF.js +0 -157
- package/dist/terminal-spawn-5YXDMUCF.js.map +0 -1
- package/dist/tiered-storage-DYNC5CQ6.js +0 -13
- package/dist/tiered-storage-DYNC5CQ6.js.map +0 -1
- package/dist/trie-agent-I3HAHY2G.js +0 -26
- package/dist/trie-agent-I3HAHY2G.js.map +0 -1
- package/dist/ui/chat.html +0 -1014
- package/dist/ui/goals.html +0 -967
- package/dist/ui/hypotheses.html +0 -1011
- package/dist/ui/ledger.html +0 -954
- package/dist/ui/nudges.html +0 -995
- package/dist/vibe-code-signatures-5ZULYP3D.js +0 -987
- package/dist/vibe-code-signatures-5ZULYP3D.js.map +0 -1
- package/dist/vulnerability-signatures-2URZSXAQ.js +0 -983
- package/dist/vulnerability-signatures-2URZSXAQ.js.map +0 -1
package/dist/chunk-F6WFNUAY.js
DELETED
|
@@ -1,216 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
loadConfig
|
|
3
|
-
} from "./chunk-XPZZFPBZ.js";
|
|
4
|
-
|
|
5
|
-
// src/ingest/github-ingester.ts
|
|
6
|
-
import path from "path";
|
|
7
|
-
import { execSync } from "child_process";
|
|
8
|
-
var TICKET_PATTERN = /\b([A-Z]{2,10}-\d+)\b/g;
|
|
9
|
-
var GitHubIngester = class {
|
|
10
|
-
graph;
|
|
11
|
-
constructor(graph) {
|
|
12
|
-
this.graph = graph;
|
|
13
|
-
}
|
|
14
|
-
async getApiToken() {
|
|
15
|
-
const config = await loadConfig();
|
|
16
|
-
return config.apiKeys?.github ?? process.env.GITHUB_TOKEN ?? null;
|
|
17
|
-
}
|
|
18
|
-
getRepoInfo(projectPath) {
|
|
19
|
-
try {
|
|
20
|
-
const url = execSync("git remote get-url origin", {
|
|
21
|
-
cwd: projectPath,
|
|
22
|
-
encoding: "utf-8",
|
|
23
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
24
|
-
}).trim();
|
|
25
|
-
const sshMatch = url.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
|
|
26
|
-
if (sshMatch) {
|
|
27
|
-
return { owner: sshMatch[1], name: sshMatch[2] };
|
|
28
|
-
}
|
|
29
|
-
const httpsMatch = url.match(/github\.com\/([^/]+)\/([^/.]+)/);
|
|
30
|
-
if (httpsMatch) {
|
|
31
|
-
return { owner: httpsMatch[1], name: httpsMatch[2] };
|
|
32
|
-
}
|
|
33
|
-
return null;
|
|
34
|
-
} catch {
|
|
35
|
-
return null;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
async syncPullRequests(owner, repo, token) {
|
|
39
|
-
const prs = await this.fetchJson(
|
|
40
|
-
`https://api.github.com/repos/${owner}/${repo}/pulls?state=open&per_page=50`,
|
|
41
|
-
token
|
|
42
|
-
);
|
|
43
|
-
let linkedTickets = 0;
|
|
44
|
-
let linkedFiles = 0;
|
|
45
|
-
for (const pr of prs) {
|
|
46
|
-
const filesChanged = await this.fetchPRFiles(owner, repo, pr.number, token);
|
|
47
|
-
const reviewStatus = await this.fetchReviewStatus(owner, repo, pr.number, token);
|
|
48
|
-
const ciStatus = await this.fetchCIStatus(owner, repo, pr.head.ref, token);
|
|
49
|
-
const linkedTicketIds = this.extractTicketIds(pr.title, pr.body);
|
|
50
|
-
const state = pr.draft ? "draft" : pr.state === "open" ? "open" : "closed";
|
|
51
|
-
const data = {
|
|
52
|
-
prNumber: pr.number,
|
|
53
|
-
title: pr.title,
|
|
54
|
-
url: pr.html_url,
|
|
55
|
-
state,
|
|
56
|
-
author: pr.user.login,
|
|
57
|
-
branch: pr.head.ref,
|
|
58
|
-
baseBranch: pr.base.ref,
|
|
59
|
-
isDraft: pr.draft,
|
|
60
|
-
filesChanged,
|
|
61
|
-
linkedTicketIds,
|
|
62
|
-
ciStatus,
|
|
63
|
-
reviewStatus,
|
|
64
|
-
createdAt: pr.created_at,
|
|
65
|
-
updatedAt: pr.updated_at,
|
|
66
|
-
...pr.merged_at != null && { mergedAt: pr.merged_at }
|
|
67
|
-
};
|
|
68
|
-
const prNodeId = `pr:${pr.number}`;
|
|
69
|
-
const existingNode = await this.graph.getNode("pull-request", prNodeId);
|
|
70
|
-
if (existingNode) {
|
|
71
|
-
await this.graph.updateNode("pull-request", prNodeId, data);
|
|
72
|
-
} else {
|
|
73
|
-
await this.graph.addNode("pull-request", data);
|
|
74
|
-
}
|
|
75
|
-
for (const file of filesChanged) {
|
|
76
|
-
const resolvedPath = path.resolve(this.graph.projectRoot, file);
|
|
77
|
-
const fileNode = await this.graph.getNode("file", resolvedPath);
|
|
78
|
-
if (fileNode) {
|
|
79
|
-
linkedFiles++;
|
|
80
|
-
await this.graph.addEdge(prNodeId, fileNode.id, "affects");
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
for (const ticketId of linkedTicketIds) {
|
|
84
|
-
const ticketNodeId = `linear:${ticketId}`;
|
|
85
|
-
const ticketNode = await this.graph.getNode("linear-ticket", ticketNodeId);
|
|
86
|
-
if (ticketNode) {
|
|
87
|
-
linkedTickets++;
|
|
88
|
-
await this.graph.addEdge(ticketNodeId, prNodeId, "implements");
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
return { prs: prs.length, linkedTickets, linkedFiles };
|
|
93
|
-
}
|
|
94
|
-
async syncIssues(owner, repo, token) {
|
|
95
|
-
const allItems = await this.fetchJson(
|
|
96
|
-
`https://api.github.com/repos/${owner}/${repo}/issues?state=open&per_page=50`,
|
|
97
|
-
token
|
|
98
|
-
);
|
|
99
|
-
const issues = allItems.filter((item) => !item.pull_request);
|
|
100
|
-
for (const issue of issues) {
|
|
101
|
-
const linkedTicketIds = this.extractTicketIds(issue.title, issue.body);
|
|
102
|
-
const data = {
|
|
103
|
-
issueNumber: issue.number,
|
|
104
|
-
title: issue.title,
|
|
105
|
-
url: issue.html_url,
|
|
106
|
-
state: issue.state,
|
|
107
|
-
labels: issue.labels.map((l) => l.name),
|
|
108
|
-
assignees: issue.assignees.map((a) => a.login),
|
|
109
|
-
body: issue.body ?? "",
|
|
110
|
-
linkedTicketIds,
|
|
111
|
-
createdAt: issue.created_at,
|
|
112
|
-
updatedAt: issue.updated_at,
|
|
113
|
-
...issue.closed_at != null && { closedAt: issue.closed_at }
|
|
114
|
-
};
|
|
115
|
-
const issueNodeId = `gh-issue:${issue.number}`;
|
|
116
|
-
const existingNode = await this.graph.getNode("github-issue", issueNodeId);
|
|
117
|
-
if (existingNode) {
|
|
118
|
-
await this.graph.updateNode("github-issue", issueNodeId, data);
|
|
119
|
-
} else {
|
|
120
|
-
await this.graph.addNode("github-issue", data);
|
|
121
|
-
}
|
|
122
|
-
for (const ticketId of linkedTicketIds) {
|
|
123
|
-
const ticketNodeId = `linear:${ticketId}`;
|
|
124
|
-
const ticketNode = await this.graph.getNode("linear-ticket", ticketNodeId);
|
|
125
|
-
if (ticketNode) {
|
|
126
|
-
await this.graph.addEdge(issueNodeId, ticketNodeId, "relatedTo");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return { issues: issues.length };
|
|
131
|
-
}
|
|
132
|
-
async fetchPRFiles(owner, repo, prNumber, token) {
|
|
133
|
-
try {
|
|
134
|
-
const files = await this.fetchJson(
|
|
135
|
-
`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/files?per_page=100`,
|
|
136
|
-
token
|
|
137
|
-
);
|
|
138
|
-
return files.map((f) => f.filename);
|
|
139
|
-
} catch {
|
|
140
|
-
return [];
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
async fetchReviewStatus(owner, repo, prNumber, token) {
|
|
144
|
-
try {
|
|
145
|
-
const reviews = await this.fetchJson(
|
|
146
|
-
`https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`,
|
|
147
|
-
token
|
|
148
|
-
);
|
|
149
|
-
if (reviews.length === 0) return "none";
|
|
150
|
-
const states = reviews.map((r) => r.state);
|
|
151
|
-
if (states.includes("CHANGES_REQUESTED")) return "changes_requested";
|
|
152
|
-
if (states.includes("APPROVED")) return "approved";
|
|
153
|
-
return "pending";
|
|
154
|
-
} catch {
|
|
155
|
-
return "none";
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
async fetchCIStatus(owner, repo, ref, token) {
|
|
159
|
-
try {
|
|
160
|
-
const status = await this.fetchJson(
|
|
161
|
-
`https://api.github.com/repos/${owner}/${repo}/commits/${ref}/status`,
|
|
162
|
-
token
|
|
163
|
-
);
|
|
164
|
-
switch (status.state) {
|
|
165
|
-
case "success":
|
|
166
|
-
return "passing";
|
|
167
|
-
case "failure":
|
|
168
|
-
case "error":
|
|
169
|
-
return "failing";
|
|
170
|
-
case "pending":
|
|
171
|
-
return "pending";
|
|
172
|
-
default:
|
|
173
|
-
return "unknown";
|
|
174
|
-
}
|
|
175
|
-
} catch {
|
|
176
|
-
return "unknown";
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
extractTicketIds(title, body) {
|
|
180
|
-
const text = `${title} ${body ?? ""}`;
|
|
181
|
-
const matches = text.match(TICKET_PATTERN);
|
|
182
|
-
return matches ? [...new Set(matches)] : [];
|
|
183
|
-
}
|
|
184
|
-
async fetchJson(url, token) {
|
|
185
|
-
const response = await fetch(url, {
|
|
186
|
-
headers: {
|
|
187
|
-
"Accept": "application/vnd.github.v3+json",
|
|
188
|
-
"Authorization": `Bearer ${token}`,
|
|
189
|
-
"User-Agent": "trie-agents",
|
|
190
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
if (response.status === 401) {
|
|
194
|
-
throw new Error(
|
|
195
|
-
"GitHub token is invalid or expired. Set a valid token:\n \u2022 Environment: GITHUB_TOKEN=ghp_...\n \u2022 Config: trie config \u2192 API Keys \u2192 GitHub"
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
if (response.status === 403) {
|
|
199
|
-
const resetHeader = response.headers.get("X-RateLimit-Reset");
|
|
200
|
-
const resetTime = resetHeader ? new Date(parseInt(resetHeader, 10) * 1e3).toLocaleTimeString() : "unknown";
|
|
201
|
-
throw new Error(`GitHub API rate limit exceeded. Resets at ${resetTime}.`);
|
|
202
|
-
}
|
|
203
|
-
if (response.status === 404) {
|
|
204
|
-
throw new Error("Repository not found or token lacks access. Ensure the token has `repo` scope.");
|
|
205
|
-
}
|
|
206
|
-
if (!response.ok) {
|
|
207
|
-
throw new Error(`GitHub API error ${response.status}: ${response.statusText}`);
|
|
208
|
-
}
|
|
209
|
-
return await response.json();
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
export {
|
|
214
|
-
GitHubIngester
|
|
215
|
-
};
|
|
216
|
-
//# sourceMappingURL=chunk-F6WFNUAY.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ingest/github-ingester.ts"],"sourcesContent":["import path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport { loadConfig } from '../config/loader.js';\nimport { ContextGraph } from '../context/graph.js';\nimport type { PullRequestNodeData, GitHubIssueNodeData } from '../context/nodes.js';\n\nconst TICKET_PATTERN = /\\b([A-Z]{2,10}-\\d+)\\b/g;\n\ninterface GitHubPR {\n number: number;\n title: string;\n html_url: string;\n state: string;\n draft: boolean;\n user: { login: string };\n head: { ref: string };\n base: { ref: string };\n body: string | null;\n created_at: string;\n updated_at: string;\n merged_at: string | null;\n}\n\ninterface GitHubFile {\n filename: string;\n}\n\ninterface GitHubReview {\n state: string;\n}\n\ninterface GitHubIssue {\n number: number;\n title: string;\n html_url: string;\n state: string;\n labels: Array<{ name: string }>;\n assignees: Array<{ login: string }>;\n body: string | null;\n pull_request?: unknown;\n created_at: string;\n updated_at: string;\n closed_at: string | null;\n}\n\ninterface GitHubCommitStatus {\n state: string;\n}\n\nexport interface GitHubSyncResult {\n prs: number;\n issues: number;\n linkedTickets: number;\n linkedFiles: number;\n}\n\nexport class GitHubIngester {\n private readonly graph: ContextGraph;\n\n constructor(graph: ContextGraph) {\n this.graph = graph;\n }\n\n async getApiToken(): Promise<string | null> {\n const config = await loadConfig();\n return config.apiKeys?.github ?? process.env.GITHUB_TOKEN ?? null;\n }\n\n getRepoInfo(projectPath: string): { owner: string; name: string } | null {\n try {\n const url = execSync('git remote get-url origin', {\n cwd: projectPath,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n\n // SSH: git@github.com:owner/repo.git\n const sshMatch = url.match(/github\\.com[:/]([^/]+)\\/([^/.]+)/);\n if (sshMatch) {\n return { owner: sshMatch[1]!, name: sshMatch[2]! };\n }\n\n // HTTPS: https://github.com/owner/repo.git\n const httpsMatch = url.match(/github\\.com\\/([^/]+)\\/([^/.]+)/);\n if (httpsMatch) {\n return { owner: httpsMatch[1]!, name: httpsMatch[2]! };\n }\n\n return null;\n } catch {\n return null;\n }\n }\n\n async syncPullRequests(owner: string, repo: string, token: string): Promise<{ prs: number; linkedTickets: number; linkedFiles: number }> {\n const prs = await this.fetchJson<GitHubPR[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls?state=open&per_page=50`,\n token,\n );\n\n let linkedTickets = 0;\n let linkedFiles = 0;\n\n for (const pr of prs) {\n const filesChanged = await this.fetchPRFiles(owner, repo, pr.number, token);\n const reviewStatus = await this.fetchReviewStatus(owner, repo, pr.number, token);\n const ciStatus = await this.fetchCIStatus(owner, repo, pr.head.ref, token);\n const linkedTicketIds = this.extractTicketIds(pr.title, pr.body);\n\n const state: PullRequestNodeData['state'] = pr.draft ? 'draft' : pr.state === 'open' ? 'open' : 'closed';\n\n const data: PullRequestNodeData = {\n prNumber: pr.number,\n title: pr.title,\n url: pr.html_url,\n state,\n author: pr.user.login,\n branch: pr.head.ref,\n baseBranch: pr.base.ref,\n isDraft: pr.draft,\n filesChanged,\n linkedTicketIds,\n ciStatus,\n reviewStatus,\n createdAt: pr.created_at,\n updatedAt: pr.updated_at,\n ...(pr.merged_at != null && { mergedAt: pr.merged_at }),\n };\n\n const prNodeId = `pr:${pr.number}`;\n\n const existingNode = await this.graph.getNode('pull-request', prNodeId);\n if (existingNode) {\n await this.graph.updateNode('pull-request', prNodeId, data);\n } else {\n await this.graph.addNode('pull-request', data);\n }\n\n // Link PR to files it touches (file node IDs are normalized absolute paths)\n for (const file of filesChanged) {\n const resolvedPath = path.resolve(this.graph.projectRoot, file);\n const fileNode = await this.graph.getNode('file', resolvedPath);\n if (fileNode) {\n linkedFiles++;\n await this.graph.addEdge(prNodeId, fileNode.id, 'affects');\n }\n }\n\n // Link Linear tickets to this PR\n for (const ticketId of linkedTicketIds) {\n const ticketNodeId = `linear:${ticketId}`;\n const ticketNode = await this.graph.getNode('linear-ticket', ticketNodeId);\n if (ticketNode) {\n linkedTickets++;\n await this.graph.addEdge(ticketNodeId, prNodeId, 'implements');\n }\n }\n }\n\n return { prs: prs.length, linkedTickets, linkedFiles };\n }\n\n async syncIssues(owner: string, repo: string, token: string): Promise<{ issues: number }> {\n const allItems = await this.fetchJson<GitHubIssue[]>(\n `https://api.github.com/repos/${owner}/${repo}/issues?state=open&per_page=50`,\n token,\n );\n\n // GitHub returns PRs in the issues endpoint — filter them out\n const issues = allItems.filter(item => !item.pull_request);\n\n for (const issue of issues) {\n const linkedTicketIds = this.extractTicketIds(issue.title, issue.body);\n\n const data: GitHubIssueNodeData = {\n issueNumber: issue.number,\n title: issue.title,\n url: issue.html_url,\n state: issue.state as 'open' | 'closed',\n labels: issue.labels.map(l => l.name),\n assignees: issue.assignees.map(a => a.login),\n body: issue.body ?? '',\n linkedTicketIds,\n createdAt: issue.created_at,\n updatedAt: issue.updated_at,\n ...(issue.closed_at != null && { closedAt: issue.closed_at }),\n };\n\n const issueNodeId = `gh-issue:${issue.number}`;\n\n const existingNode = await this.graph.getNode('github-issue', issueNodeId);\n if (existingNode) {\n await this.graph.updateNode('github-issue', issueNodeId, data);\n } else {\n await this.graph.addNode('github-issue', data);\n }\n\n // Link to related Linear tickets\n for (const ticketId of linkedTicketIds) {\n const ticketNodeId = `linear:${ticketId}`;\n const ticketNode = await this.graph.getNode('linear-ticket', ticketNodeId);\n if (ticketNode) {\n await this.graph.addEdge(issueNodeId, ticketNodeId, 'relatedTo');\n }\n }\n }\n\n return { issues: issues.length };\n }\n\n private async fetchPRFiles(owner: string, repo: string, prNumber: number, token: string): Promise<string[]> {\n try {\n const files = await this.fetchJson<GitHubFile[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/files?per_page=100`,\n token,\n );\n return files.map(f => f.filename);\n } catch {\n return [];\n }\n }\n\n private async fetchReviewStatus(\n owner: string,\n repo: string,\n prNumber: number,\n token: string,\n ): Promise<PullRequestNodeData['reviewStatus']> {\n try {\n const reviews = await this.fetchJson<GitHubReview[]>(\n `https://api.github.com/repos/${owner}/${repo}/pulls/${prNumber}/reviews`,\n token,\n );\n if (reviews.length === 0) return 'none';\n\n const states = reviews.map(r => r.state);\n if (states.includes('CHANGES_REQUESTED')) return 'changes_requested';\n if (states.includes('APPROVED')) return 'approved';\n return 'pending';\n } catch {\n return 'none';\n }\n }\n\n private async fetchCIStatus(\n owner: string,\n repo: string,\n ref: string,\n token: string,\n ): Promise<PullRequestNodeData['ciStatus']> {\n try {\n const status = await this.fetchJson<GitHubCommitStatus>(\n `https://api.github.com/repos/${owner}/${repo}/commits/${ref}/status`,\n token,\n );\n switch (status.state) {\n case 'success': return 'passing';\n case 'failure': case 'error': return 'failing';\n case 'pending': return 'pending';\n default: return 'unknown';\n }\n } catch {\n return 'unknown';\n }\n }\n\n private extractTicketIds(title: string, body: string | null): string[] {\n const text = `${title} ${body ?? ''}`;\n const matches = text.match(TICKET_PATTERN);\n return matches ? [...new Set(matches)] : [];\n }\n\n private async fetchJson<T>(url: string, token: string): Promise<T> {\n const response = await fetch(url, {\n headers: {\n 'Accept': 'application/vnd.github.v3+json',\n 'Authorization': `Bearer ${token}`,\n 'User-Agent': 'trie-agents',\n 'X-GitHub-Api-Version': '2022-11-28',\n },\n });\n\n if (response.status === 401) {\n throw new Error(\n 'GitHub token is invalid or expired. Set a valid token:\\n' +\n ' • Environment: GITHUB_TOKEN=ghp_...\\n' +\n ' • Config: trie config → API Keys → GitHub',\n );\n }\n\n if (response.status === 403) {\n const resetHeader = response.headers.get('X-RateLimit-Reset');\n const resetTime = resetHeader\n ? new Date(parseInt(resetHeader, 10) * 1000).toLocaleTimeString()\n : 'unknown';\n throw new Error(`GitHub API rate limit exceeded. Resets at ${resetTime}.`);\n }\n\n if (response.status === 404) {\n throw new Error('Repository not found or token lacks access. Ensure the token has `repo` scope.');\n }\n\n if (!response.ok) {\n throw new Error(`GitHub API error ${response.status}: ${response.statusText}`);\n }\n\n return (await response.json()) as T;\n }\n}\n"],"mappings":"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","names":[]}
|