opencode-forgekeeper 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -14
- package/dist/index.js +76 -71
- package/dist/tui.js +444 -101
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -296,8 +296,9 @@ title prefix. It doesn't poll or send review notifications, and the CLI shows no
|
|
|
296
296
|
|
|
297
297
|
## RPC
|
|
298
298
|
|
|
299
|
-
The server registers an [RPC](https://opencode.ai/v2/docs/build/plugins/rpc)
|
|
300
|
-
|
|
299
|
+
The server registers an [RPC](https://opencode.ai/v2/docs/build/plugins/rpc) with the ID
|
|
300
|
+
`opencode-forgekeeper`, defined in `src/rpc.ts`. The CLI uses it, and other plugins can call
|
|
301
|
+
`target` and listen for `targetChanged`:
|
|
301
302
|
|
|
302
303
|
- `target({ sessionID })` returns `{ url, issueUrl?, targets }` for explicit targets, and
|
|
303
304
|
`{}` in branch mode. `targets` lists every target as `{ url, issueUrl? }`. `url` and
|
|
@@ -318,18 +319,27 @@ plugin instance watches its own sessions.
|
|
|
318
319
|
|
|
319
320
|
## Migrating from opencode-forge-session-title
|
|
320
321
|
|
|
321
|
-
Replace `opencode-forge-session-title` with `opencode-forgekeeper` in `opencode.json`.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
| Entry point | Plugin ID
|
|
326
|
-
| ----------- |
|
|
327
|
-
| Server | `opencode-
|
|
328
|
-
| CLI | `pedropombeiro.forgekeeper`
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
322
|
+
Replace `opencode-forge-session-title` with `opencode-forgekeeper` in `opencode.json`. Upgrading
|
|
323
|
+
from `opencode-forgekeeper` 1.x works the same way, because 1.x used the same IDs as
|
|
324
|
+
`opencode-forge-session-title`.
|
|
325
|
+
|
|
326
|
+
| Entry point | Plugin ID | Stored state |
|
|
327
|
+
| ----------- | --------------------------- | ---------------------------------------------------------------------------------------- |
|
|
328
|
+
| Server | `opencode-forgekeeper` | Session targets, owned title prefixes, human-review baselines, and pending notifications |
|
|
329
|
+
| CLI | `pedropombeiro.forgekeeper` | None |
|
|
330
|
+
|
|
331
|
+
OpenCode scopes plugin storage by plugin ID, so nothing stored under the former ID,
|
|
332
|
+
`opencode-forge-session-title`, carries over:
|
|
333
|
+
|
|
334
|
+
- Sessions start in branch-based naming. Ask the agent to set their targets again.
|
|
335
|
+
- A title that kept a single-reference prefix from before, such as `[!456] Review`, now looks
|
|
336
|
+
like a reference that you wrote. Until you set a target, the status follows that PR/MR, labeled
|
|
337
|
+
"from the session title". Setting a target adds a second prefix, such as
|
|
338
|
+
`[#12, !45] [!456] Review`. Remove the older prefix by hand. Older prefixes with two
|
|
339
|
+
references, such as `[#12, !45]`, are replaced automatically.
|
|
340
|
+
- The first look at each PR/MR records a new review baseline, so comments posted before then
|
|
341
|
+
aren't announced.
|
|
342
|
+
- Callers of the RPC need the new ID, `opencode-forgekeeper`.
|
|
333
343
|
|
|
334
344
|
With default options, the new footer and review notifications start right away, and
|
|
335
345
|
notifications resume the session. Set `reviewStatus` to `false` to keep only titles, or
|
package/dist/index.js
CHANGED
|
@@ -185,10 +185,14 @@ class ForgeError extends Error {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
// packages/forgekeeper/src/graphql.ts
|
|
189
|
+
var query = (text) => text;
|
|
190
|
+
var typed = (transport) => async (host, query2, variables) => await transport(host, query2, variables);
|
|
191
|
+
|
|
188
192
|
// packages/forgekeeper/src/gitlab-feedback.ts
|
|
189
193
|
var PAGE_SIZE = 100;
|
|
190
194
|
var MAX_COMMENT_PAGES = 20;
|
|
191
|
-
var COMMENTS_QUERY = `query($project: ID!, $iid: String!, $before: String) {
|
|
195
|
+
var COMMENTS_QUERY = query(`query($project: ID!, $iid: String!, $before: String) {
|
|
192
196
|
currentUser { id }
|
|
193
197
|
project(fullPath: $project) {
|
|
194
198
|
mergeRequest(iid: $iid) {
|
|
@@ -202,7 +206,7 @@ var COMMENTS_QUERY = `query($project: ID!, $iid: String!, $before: String) {
|
|
|
202
206
|
}
|
|
203
207
|
}
|
|
204
208
|
}
|
|
205
|
-
}
|
|
209
|
+
}`);
|
|
206
210
|
var noteNumber = (id) => id.slice(id.lastIndexOf("/") + 1);
|
|
207
211
|
var timestamp = (node) => Date.parse(node.lastEditedAt ?? node.updatedAt ?? node.createdAt);
|
|
208
212
|
function toComment(node) {
|
|
@@ -221,7 +225,8 @@ function toComment(node) {
|
|
|
221
225
|
username: node.author.username
|
|
222
226
|
};
|
|
223
227
|
}
|
|
224
|
-
async function fetchComments(
|
|
228
|
+
async function fetchComments(transport, host, project, iid) {
|
|
229
|
+
const graphql = typed(transport);
|
|
225
230
|
const pages = [];
|
|
226
231
|
let viewerID;
|
|
227
232
|
let before;
|
|
@@ -235,8 +240,8 @@ async function fetchComments(graphql, host, project, iid) {
|
|
|
235
240
|
if (before)
|
|
236
241
|
variables.before = before;
|
|
237
242
|
const data = await graphql(host, COMMENTS_QUERY, variables);
|
|
238
|
-
viewerID ??= data
|
|
239
|
-
const connection = data
|
|
243
|
+
viewerID ??= data.currentUser?.id ?? undefined;
|
|
244
|
+
const connection = data.project?.mergeRequest?.notes;
|
|
240
245
|
if (!connection)
|
|
241
246
|
return page === 0 ? undefined : snapshot(false);
|
|
242
247
|
pages.push(connection.nodes.flatMap((node) => toComment(node) ?? []));
|
|
@@ -268,17 +273,17 @@ function mergeRequestsQuery(projectCount) {
|
|
|
268
273
|
mergeRequests(sourceBranches: [$branch], state: opened, first: 20) { nodes { ${MERGE_REQUEST_FIELDS} } }
|
|
269
274
|
}`).join(`
|
|
270
275
|
`);
|
|
271
|
-
return `query($branch: String!, ${variables}) {
|
|
276
|
+
return query(`query($branch: String!, ${variables}) {
|
|
272
277
|
${projects}
|
|
273
|
-
}
|
|
278
|
+
}`);
|
|
274
279
|
}
|
|
275
280
|
function mergeRequestQuery(projectCount) {
|
|
276
281
|
const variables = Array.from({ length: projectCount }, (_, index) => `$p${index}: ID!`).join(", ");
|
|
277
282
|
const projects = Array.from({ length: projectCount }, (_, index) => `p${index}: project(fullPath: $p${index}) { mergeRequest(iid: $iid) { ${MERGE_REQUEST_FIELDS} } }`).join(`
|
|
278
283
|
`);
|
|
279
|
-
return `query($iid: String!, ${variables}) {
|
|
284
|
+
return query(`query($iid: String!, ${variables}) {
|
|
280
285
|
${projects}
|
|
281
|
-
}
|
|
286
|
+
}`);
|
|
282
287
|
}
|
|
283
288
|
function mergeRequestNumbersQuery(projectCount) {
|
|
284
289
|
const variables = Array.from({ length: projectCount }, (_, index) => `$p${index}: ID!`).join(", ");
|
|
@@ -286,18 +291,18 @@ function mergeRequestNumbersQuery(projectCount) {
|
|
|
286
291
|
mergeRequests(sourceBranches: [$branch], state: opened, first: 20) { nodes { iid updatedAt sourceProject { fullPath } } }
|
|
287
292
|
}`).join(`
|
|
288
293
|
`);
|
|
289
|
-
return `query($branch: String!, ${variables}) {
|
|
294
|
+
return query(`query($branch: String!, ${variables}) {
|
|
290
295
|
${projects}
|
|
291
|
-
}
|
|
296
|
+
}`);
|
|
292
297
|
}
|
|
293
|
-
var SOURCE_BRANCH_QUERY = `query($project: ID!, $iid: String!) {
|
|
298
|
+
var SOURCE_BRANCH_QUERY = query(`query($project: ID!, $iid: String!) {
|
|
294
299
|
project(fullPath: $project) { mergeRequest(iid: $iid) { sourceBranch } }
|
|
295
|
-
}
|
|
296
|
-
var DISCUSSIONS_QUERY = `query($project: ID!, $iid: String!, $after: String) {
|
|
300
|
+
}`);
|
|
301
|
+
var DISCUSSIONS_QUERY = query(`query($project: ID!, $iid: String!, $after: String) {
|
|
297
302
|
project(fullPath: $project) {
|
|
298
303
|
mergeRequest(iid: $iid) { discussions(first: ${PAGE_SIZE2}, after: $after) { ${DISCUSSIONS} } }
|
|
299
304
|
}
|
|
300
|
-
}
|
|
305
|
+
}`);
|
|
301
306
|
function classifyError(message, code) {
|
|
302
307
|
const text = message.trim().replace(/^glab:\s*/, "") || `glab exited with code ${code}`;
|
|
303
308
|
if (/ENOENT|command not found/i.test(text))
|
|
@@ -312,8 +317,8 @@ function classifyError(message, code) {
|
|
|
312
317
|
}
|
|
313
318
|
var isResponse = (body) => typeof body === "object" && body !== null && (!("errors" in body) || Array.isArray(body.errors)) && (!("data" in body) || typeof body.data === "object");
|
|
314
319
|
function glabGraphQL(run, cwd) {
|
|
315
|
-
return async (host,
|
|
316
|
-
const args = ["api", "graphql", "--hostname", host, "-f", `query=${
|
|
320
|
+
return async (host, query2, variables) => {
|
|
321
|
+
const args = ["api", "graphql", "--hostname", host, "-f", `query=${query2}`];
|
|
317
322
|
for (const [name, value] of Object.entries(variables))
|
|
318
323
|
args.push("-f", `${name}=${value}`);
|
|
319
324
|
const result = await run("glab", args, cwd);
|
|
@@ -381,10 +386,10 @@ function duoState(state) {
|
|
|
381
386
|
}
|
|
382
387
|
|
|
383
388
|
class GitLabForge {
|
|
384
|
-
graphql;
|
|
385
389
|
traits = gitlabTraits;
|
|
390
|
+
graphql;
|
|
386
391
|
constructor(graphql) {
|
|
387
|
-
this.graphql = graphql;
|
|
392
|
+
this.graphql = typed(graphql);
|
|
388
393
|
}
|
|
389
394
|
async findByBranch(repository) {
|
|
390
395
|
const { source, targets, sourceBranch } = repository;
|
|
@@ -395,7 +400,7 @@ class GitLabForge {
|
|
|
395
400
|
const seen = new Set;
|
|
396
401
|
const nodes = [];
|
|
397
402
|
targets.forEach((_, index) => {
|
|
398
|
-
for (const node of data
|
|
403
|
+
for (const node of data[`p${index}`]?.mergeRequests?.nodes ?? []) {
|
|
399
404
|
if (node.sourceProject?.fullPath.toLowerCase() !== sourcePath)
|
|
400
405
|
continue;
|
|
401
406
|
const key = `${node.targetProject.fullPath}!${node.iid}`;
|
|
@@ -414,7 +419,7 @@ class GitLabForge {
|
|
|
414
419
|
targets.forEach((target, index) => variables[`p${index}`] = target.path);
|
|
415
420
|
const data = await this.graphql(source.host, mergeRequestNumbersQuery(targets.length), variables);
|
|
416
421
|
const sourcePath = source.path.toLowerCase();
|
|
417
|
-
const nodes = targets.flatMap((_, index) => data
|
|
422
|
+
const nodes = targets.flatMap((_, index) => data[`p${index}`]?.mergeRequests?.nodes ?? []);
|
|
418
423
|
return nodes.filter((node) => node.sourceProject?.fullPath.toLowerCase() === sourcePath).sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""))[0]?.iid;
|
|
419
424
|
}
|
|
420
425
|
async sourceBranch(ref) {
|
|
@@ -422,7 +427,7 @@ class GitLabForge {
|
|
|
422
427
|
project: ref.project,
|
|
423
428
|
iid: ref.iid
|
|
424
429
|
});
|
|
425
|
-
const branch = data
|
|
430
|
+
const branch = data.project?.mergeRequest?.sourceBranch;
|
|
426
431
|
return typeof branch === "string" && branch ? branch : undefined;
|
|
427
432
|
}
|
|
428
433
|
async findByNumber(projects, iid) {
|
|
@@ -433,7 +438,7 @@ class GitLabForge {
|
|
|
433
438
|
projects.forEach((project, index) => variables[`p${index}`] = project.path);
|
|
434
439
|
const data = await this.graphql(host, mergeRequestQuery(projects.length), variables);
|
|
435
440
|
for (let index = 0;index < projects.length; index++) {
|
|
436
|
-
const node = data
|
|
441
|
+
const node = data[`p${index}`]?.mergeRequest;
|
|
437
442
|
if (node)
|
|
438
443
|
return this.normalize(host, node);
|
|
439
444
|
}
|
|
@@ -449,7 +454,7 @@ class GitLabForge {
|
|
|
449
454
|
iid: node.iid,
|
|
450
455
|
after: page.endCursor
|
|
451
456
|
});
|
|
452
|
-
const next = data
|
|
457
|
+
const next = data.project?.mergeRequest?.discussions;
|
|
453
458
|
if (!next)
|
|
454
459
|
break;
|
|
455
460
|
count += countUnresolved(next);
|
|
@@ -505,8 +510,8 @@ var fields = `number title url state isDraft mergeable reviewDecision headRefOid
|
|
|
505
510
|
} } } } }`;
|
|
506
511
|
var MAX_PAGES = 50;
|
|
507
512
|
function ghGraphQL(run, cwd) {
|
|
508
|
-
return async (host,
|
|
509
|
-
const args = ["api", "graphql", "--hostname", host, "-f", `query=${
|
|
513
|
+
return async (host, query2, variables) => {
|
|
514
|
+
const args = ["api", "graphql", "--hostname", host, "-f", `query=${query2}`];
|
|
510
515
|
for (const [name, value] of Object.entries(variables))
|
|
511
516
|
args.push(typeof value === "number" ? "-F" : "-f", `${name}=${value}`);
|
|
512
517
|
const result = await run("gh", args, cwd);
|
|
@@ -596,17 +601,17 @@ var githubTraits = {
|
|
|
596
601
|
};
|
|
597
602
|
|
|
598
603
|
class GitHubForge {
|
|
599
|
-
graphql;
|
|
600
604
|
traits = githubTraits;
|
|
605
|
+
graphql;
|
|
601
606
|
constructor(graphql) {
|
|
602
|
-
this.graphql = graphql;
|
|
607
|
+
this.graphql = typed(graphql);
|
|
603
608
|
}
|
|
604
609
|
async findByNumber(projects, number) {
|
|
605
610
|
for (const project of projects) {
|
|
606
611
|
const [owner, repo] = project.path.split("/");
|
|
607
|
-
const data = await this.graphql(project.host, `query($owner:String!,$repo:String!,$number:Int!) {
|
|
612
|
+
const data = await this.graphql(project.host, query(`query($owner:String!,$repo:String!,$number:Int!) {
|
|
608
613
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) { ${fields} } }
|
|
609
|
-
}
|
|
614
|
+
}`), { owner, repo, number: Number(number) });
|
|
610
615
|
const node = data.repository?.pullRequest;
|
|
611
616
|
if (node)
|
|
612
617
|
return this.normalize(project.host, node);
|
|
@@ -617,10 +622,10 @@ class GitHubForge {
|
|
|
617
622
|
let newest;
|
|
618
623
|
for (const target of repository.targets) {
|
|
619
624
|
const [owner, repo] = target.path.split("/");
|
|
620
|
-
const data = await this.graphql(target.host, `query($owner:String!,$repo:String!,$branch:String!) {
|
|
625
|
+
const data = await this.graphql(target.host, query(`query($owner:String!,$repo:String!,$branch:String!) {
|
|
621
626
|
repository(owner:$owner,name:$repo) { pullRequests(first:100,states:OPEN,headRefName:$branch,orderBy:{field:UPDATED_AT,direction:DESC}) {
|
|
622
627
|
nodes { number updatedAt headRepository { nameWithOwner } }
|
|
623
|
-
} } }
|
|
628
|
+
} } }`), { owner, repo, branch: repository.sourceBranch });
|
|
624
629
|
const nodes = data.repository?.pullRequests?.nodes ?? [];
|
|
625
630
|
for (const node of nodes) {
|
|
626
631
|
if (node.headRepository?.nameWithOwner.toLowerCase() !== repository.source.path.toLowerCase())
|
|
@@ -633,11 +638,10 @@ class GitHubForge {
|
|
|
633
638
|
}
|
|
634
639
|
async sourceBranch(ref) {
|
|
635
640
|
const [owner, repo] = ref.project.split("/");
|
|
636
|
-
const data = await this.graphql(ref.host, `query($owner:String!,$repo:String!,$number:Int!) {
|
|
641
|
+
const data = await this.graphql(ref.host, query(`query($owner:String!,$repo:String!,$number:Int!) {
|
|
637
642
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) { headRefName } }
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
return typeof branch === "string" && branch ? branch : undefined;
|
|
643
|
+
}`), { owner, repo, number: Number(ref.iid) });
|
|
644
|
+
return data.repository?.pullRequest?.headRefName || undefined;
|
|
641
645
|
}
|
|
642
646
|
async findByBranch(repository) {
|
|
643
647
|
const found = new Map;
|
|
@@ -646,10 +650,10 @@ class GitHubForge {
|
|
|
646
650
|
let after;
|
|
647
651
|
let complete = false;
|
|
648
652
|
for (let page = 0;page < MAX_PAGES; page++) {
|
|
649
|
-
const data = await this.graphql(target.host, `query($owner:String!,$repo:String!,$branch:String!${after ? ",$after:String!" : ""}) {
|
|
653
|
+
const data = await this.graphql(target.host, query(`query($owner:String!,$repo:String!,$branch:String!${after ? ",$after:String!" : ""}) {
|
|
650
654
|
repository(owner:$owner,name:$repo) { pullRequests(first:100,states:OPEN,headRefName:$branch${after ? ",after:$after" : ""}) {
|
|
651
655
|
nodes { ${fields} } pageInfo { hasNextPage endCursor }
|
|
652
|
-
} } }
|
|
656
|
+
} } }`), { owner, repo, branch: repository.sourceBranch, ...after ? { after } : {} });
|
|
653
657
|
const pulls = data.repository?.pullRequests;
|
|
654
658
|
if (!pulls)
|
|
655
659
|
throw new ForgeError("request", "GitHub repository unavailable");
|
|
@@ -677,10 +681,10 @@ class GitHubForge {
|
|
|
677
681
|
const threads = [...node.reviewThreads.nodes];
|
|
678
682
|
let page = node.reviewThreads.pageInfo;
|
|
679
683
|
for (let count = 1;page?.hasNextPage && page.endCursor && count < MAX_PAGES; count++) {
|
|
680
|
-
const data = await this.graphql(host, `query($owner:String!,$repo:String!,$number:Int!,$after:String!) {
|
|
684
|
+
const data = await this.graphql(host, query(`query($owner:String!,$repo:String!,$number:Int!,$after:String!) {
|
|
681
685
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) {
|
|
682
686
|
reviewThreads(first:100,after:$after) { nodes { isResolved } pageInfo { hasNextPage endCursor } }
|
|
683
|
-
} } }
|
|
687
|
+
} } }`), { owner, repo, number: node.number, after: page.endCursor });
|
|
684
688
|
const next = data.repository?.pullRequest?.reviewThreads;
|
|
685
689
|
if (!next)
|
|
686
690
|
break;
|
|
@@ -698,10 +702,10 @@ class GitHubForge {
|
|
|
698
702
|
const contexts = [...rollup?.nodes ?? []];
|
|
699
703
|
let cursor = rollup?.pageInfo;
|
|
700
704
|
for (let count = 1;cursor?.hasNextPage && cursor.endCursor && count < MAX_PAGES; count++) {
|
|
701
|
-
const data = await this.graphql(host, `query($owner:String!,$repo:String!,$oid:GitObjectID!,$after:String!) {
|
|
705
|
+
const data = await this.graphql(host, query(`query($owner:String!,$repo:String!,$oid:GitObjectID!,$after:String!) {
|
|
702
706
|
repository(owner:$owner,name:$repo) { object(oid:$oid) { ... on Commit { statusCheckRollup {
|
|
703
707
|
contexts(first:100,after:$after) { nodes { __typename ... on CheckRun { status conclusion detailsUrl } ... on StatusContext { state targetUrl } } pageInfo { hasNextPage endCursor } }
|
|
704
|
-
} } } } }
|
|
708
|
+
} } } } }`), { owner, repo, oid: node.headRefOid, after: cursor.endCursor });
|
|
705
709
|
const next = data.repository?.object?.statusCheckRollup?.contexts;
|
|
706
710
|
if (!next)
|
|
707
711
|
break;
|
|
@@ -910,14 +914,15 @@ var target = {
|
|
|
910
914
|
additionalProperties: false
|
|
911
915
|
};
|
|
912
916
|
var key = { type: "string" };
|
|
913
|
-
var snapshot = { type: "object" };
|
|
917
|
+
var snapshot = { type: "object", title: "Snapshot" };
|
|
914
918
|
var status = {
|
|
915
919
|
type: "object",
|
|
916
920
|
properties: { enabled: { type: "boolean" }, snapshot },
|
|
917
|
-
required: ["enabled", "snapshot"]
|
|
921
|
+
required: ["enabled", "snapshot"],
|
|
922
|
+
additionalProperties: false
|
|
918
923
|
};
|
|
919
924
|
var ForgeSessionRpc = {
|
|
920
|
-
id: "opencode-
|
|
925
|
+
id: "opencode-forgekeeper",
|
|
921
926
|
methods: {
|
|
922
927
|
target: {
|
|
923
928
|
input: {
|
|
@@ -941,8 +946,12 @@ var ForgeSessionRpc = {
|
|
|
941
946
|
},
|
|
942
947
|
output: {
|
|
943
948
|
type: "object",
|
|
944
|
-
properties: {
|
|
945
|
-
|
|
949
|
+
properties: {
|
|
950
|
+
enabled: { type: "boolean" },
|
|
951
|
+
statuses: { type: "object", additionalProperties: snapshot }
|
|
952
|
+
},
|
|
953
|
+
required: ["enabled", "statuses"],
|
|
954
|
+
additionalProperties: false
|
|
946
955
|
}
|
|
947
956
|
},
|
|
948
957
|
release: {
|
|
@@ -952,7 +961,7 @@ var ForgeSessionRpc = {
|
|
|
952
961
|
required: ["clientID"],
|
|
953
962
|
additionalProperties: false
|
|
954
963
|
},
|
|
955
|
-
output: { type: "object" }
|
|
964
|
+
output: { type: "object", additionalProperties: false }
|
|
956
965
|
},
|
|
957
966
|
refresh: {
|
|
958
967
|
input: {
|
|
@@ -977,7 +986,8 @@ var ForgeSessionRpc = {
|
|
|
977
986
|
schema: {
|
|
978
987
|
type: "object",
|
|
979
988
|
properties: { directory: { type: "string" }, key, snapshot },
|
|
980
|
-
required: ["directory", "key", "snapshot"]
|
|
989
|
+
required: ["directory", "key", "snapshot"],
|
|
990
|
+
additionalProperties: false
|
|
981
991
|
}
|
|
982
992
|
},
|
|
983
993
|
notice: {
|
|
@@ -989,7 +999,8 @@ var ForgeSessionRpc = {
|
|
|
989
999
|
message: { type: "string" },
|
|
990
1000
|
variant: { type: "string", enum: ["info", "error"] }
|
|
991
1001
|
},
|
|
992
|
-
required: ["message", "variant"]
|
|
1002
|
+
required: ["message", "variant"],
|
|
1003
|
+
additionalProperties: false
|
|
993
1004
|
}
|
|
994
1005
|
}
|
|
995
1006
|
}
|
|
@@ -997,6 +1008,12 @@ var ForgeSessionRpc = {
|
|
|
997
1008
|
var HOME = "";
|
|
998
1009
|
var HEARTBEAT = 60000;
|
|
999
1010
|
var LEASE_TIME = 3 * HEARTBEAT;
|
|
1011
|
+
var implement = (handlers) => ({
|
|
1012
|
+
target: (input) => handlers.target(input),
|
|
1013
|
+
watch: (input) => handlers.watch(input),
|
|
1014
|
+
release: (input) => handlers.release(input),
|
|
1015
|
+
refresh: (input) => handlers.refresh(input)
|
|
1016
|
+
});
|
|
1000
1017
|
|
|
1001
1018
|
// packages/forgekeeper/src/automated-review-watch.ts
|
|
1002
1019
|
var requests = (lookup) => lookup?.kind === "found" ? lookup.requests : [];
|
|
@@ -1805,7 +1822,6 @@ var FEEDBACK_PREFIX = "status/feedback/";
|
|
|
1805
1822
|
var pendingPrefix = (sessionID) => `${PENDING_PREFIX}${encodeURIComponent(sessionID)}/`;
|
|
1806
1823
|
var pendingKey = (sessionID, url) => `${pendingPrefix(sessionID)}${encodeURIComponent(url)}`;
|
|
1807
1824
|
var feedbackRecordKey = (key2) => `${FEEDBACK_PREFIX}${encodeURIComponent(key2)}`;
|
|
1808
|
-
var LEGACY_KEYS = ["status/humanReviewFeedback", "status/automatedReviewPending"];
|
|
1809
1825
|
function userTitle(title, prefix) {
|
|
1810
1826
|
if (!title || !prefix)
|
|
1811
1827
|
return title;
|
|
@@ -1971,8 +1987,6 @@ async function setupStatus(ctx, settings, deps, host) {
|
|
|
1971
1987
|
});
|
|
1972
1988
|
invalidate = (sessionID) => service.invalidate(sessionID);
|
|
1973
1989
|
write(async () => {
|
|
1974
|
-
for (const key2 of LEGACY_KEYS)
|
|
1975
|
-
await ctx.storage.remove(key2);
|
|
1976
1990
|
const at = (deps.now ?? Date.now)();
|
|
1977
1991
|
for (const { key: key2, value } of await scanAll(FEEDBACK_PREFIX)) {
|
|
1978
1992
|
if (isExpired(value, at))
|
|
@@ -2095,7 +2109,7 @@ async function setupServer(ctx, lookups, status2) {
|
|
|
2095
2109
|
async function stateFor(sessionID) {
|
|
2096
2110
|
const started = revision(sessionID);
|
|
2097
2111
|
const stored = await ctx.storage.get(`sessions/${sessionID}`) ?? {};
|
|
2098
|
-
const targets = Array.isArray(stored.targets) ? stored.targets :
|
|
2112
|
+
const targets = Array.isArray(stored.targets) ? stored.targets : [];
|
|
2099
2113
|
if (revision(sessionID) === started)
|
|
2100
2114
|
known.set(sessionID, targets);
|
|
2101
2115
|
return { targets, ...stored.prefix ? { prefix: stored.prefix } : {} };
|
|
@@ -2115,24 +2129,15 @@ async function setupServer(ctx, lookups, status2) {
|
|
|
2115
2129
|
}
|
|
2116
2130
|
};
|
|
2117
2131
|
let watcher;
|
|
2118
|
-
const rpc = await ctx.rpc.register(ForgeSessionRpc, {
|
|
2119
|
-
target: async (
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
watch: async (input) => {
|
|
2124
|
-
const { clientID, keys, visible } = input;
|
|
2125
|
-
return watcher ? { enabled: true, statuses: json(watcher.service.watch(clientID, keys, visible)) } : { enabled: false, statuses: {} };
|
|
2126
|
-
},
|
|
2127
|
-
release: async (input) => {
|
|
2128
|
-
watcher?.service.release(input.clientID);
|
|
2132
|
+
const rpc = await ctx.rpc.register(ForgeSessionRpc, implement({
|
|
2133
|
+
target: async ({ sessionID }) => targetOutput((await stateFor(sessionID)).targets),
|
|
2134
|
+
watch: async ({ clientID, keys, visible }) => watcher ? { enabled: true, statuses: json(watcher.service.watch(clientID, keys, visible)) } : { enabled: false, statuses: {} },
|
|
2135
|
+
release: async ({ clientID }) => {
|
|
2136
|
+
watcher?.service.release(clientID);
|
|
2129
2137
|
return {};
|
|
2130
2138
|
},
|
|
2131
|
-
refresh: async (
|
|
2132
|
-
|
|
2133
|
-
return watcher ? { enabled: true, snapshot: json(await watcher.service.refresh(key2)) } : DISABLED;
|
|
2134
|
-
}
|
|
2135
|
-
});
|
|
2139
|
+
refresh: async ({ key: key2 }) => watcher ? { enabled: true, snapshot: json(await watcher.service.refresh(key2)) } : DISABLED
|
|
2140
|
+
}));
|
|
2136
2141
|
const settings = statusOptions(ctx.options);
|
|
2137
2142
|
if (status2 && settings.enabled) {
|
|
2138
2143
|
watcher = await setupStatus(ctx, settings, status2, {
|
|
@@ -2299,7 +2304,7 @@ async function setupServer(ctx, lookups, status2) {
|
|
|
2299
2304
|
|
|
2300
2305
|
// packages/forgekeeper/src/index.ts
|
|
2301
2306
|
var src_default = {
|
|
2302
|
-
id: "opencode-
|
|
2307
|
+
id: "opencode-forgekeeper",
|
|
2303
2308
|
async setup(ctx) {
|
|
2304
2309
|
const hosts = hostsFrom(ctx.options ?? {});
|
|
2305
2310
|
const stopped = new AbortController;
|
package/dist/tui.js
CHANGED
|
@@ -69,10 +69,14 @@ class ForgeError extends Error {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
// packages/forgekeeper/src/graphql.ts
|
|
73
|
+
var query = (text) => text;
|
|
74
|
+
var typed = (transport) => async (host, query2, variables) => await transport(host, query2, variables);
|
|
75
|
+
|
|
72
76
|
// packages/forgekeeper/src/gitlab-feedback.ts
|
|
73
77
|
var PAGE_SIZE = 100;
|
|
74
78
|
var MAX_COMMENT_PAGES = 20;
|
|
75
|
-
var COMMENTS_QUERY = `query($project: ID!, $iid: String!, $before: String) {
|
|
79
|
+
var COMMENTS_QUERY = query(`query($project: ID!, $iid: String!, $before: String) {
|
|
76
80
|
currentUser { id }
|
|
77
81
|
project(fullPath: $project) {
|
|
78
82
|
mergeRequest(iid: $iid) {
|
|
@@ -86,7 +90,7 @@ var COMMENTS_QUERY = `query($project: ID!, $iid: String!, $before: String) {
|
|
|
86
90
|
}
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
|
-
}
|
|
93
|
+
}`);
|
|
90
94
|
var noteNumber = (id) => id.slice(id.lastIndexOf("/") + 1);
|
|
91
95
|
var timestamp = (node) => Date.parse(node.lastEditedAt ?? node.updatedAt ?? node.createdAt);
|
|
92
96
|
function toComment(node) {
|
|
@@ -105,7 +109,8 @@ function toComment(node) {
|
|
|
105
109
|
username: node.author.username
|
|
106
110
|
};
|
|
107
111
|
}
|
|
108
|
-
async function fetchComments(
|
|
112
|
+
async function fetchComments(transport, host, project, iid) {
|
|
113
|
+
const graphql = typed(transport);
|
|
109
114
|
const pages = [];
|
|
110
115
|
let viewerID;
|
|
111
116
|
let before;
|
|
@@ -119,8 +124,8 @@ async function fetchComments(graphql, host, project, iid) {
|
|
|
119
124
|
if (before)
|
|
120
125
|
variables.before = before;
|
|
121
126
|
const data = await graphql(host, COMMENTS_QUERY, variables);
|
|
122
|
-
viewerID ??= data
|
|
123
|
-
const connection = data
|
|
127
|
+
viewerID ??= data.currentUser?.id ?? undefined;
|
|
128
|
+
const connection = data.project?.mergeRequest?.notes;
|
|
124
129
|
if (!connection)
|
|
125
130
|
return page === 0 ? undefined : snapshot(false);
|
|
126
131
|
pages.push(connection.nodes.flatMap((node) => toComment(node) ?? []));
|
|
@@ -152,17 +157,17 @@ function mergeRequestsQuery(projectCount) {
|
|
|
152
157
|
mergeRequests(sourceBranches: [$branch], state: opened, first: 20) { nodes { ${MERGE_REQUEST_FIELDS} } }
|
|
153
158
|
}`).join(`
|
|
154
159
|
`);
|
|
155
|
-
return `query($branch: String!, ${variables}) {
|
|
160
|
+
return query(`query($branch: String!, ${variables}) {
|
|
156
161
|
${projects}
|
|
157
|
-
}
|
|
162
|
+
}`);
|
|
158
163
|
}
|
|
159
164
|
function mergeRequestQuery(projectCount) {
|
|
160
165
|
const variables = Array.from({ length: projectCount }, (_, index) => `$p${index}: ID!`).join(", ");
|
|
161
166
|
const projects = Array.from({ length: projectCount }, (_, index) => `p${index}: project(fullPath: $p${index}) { mergeRequest(iid: $iid) { ${MERGE_REQUEST_FIELDS} } }`).join(`
|
|
162
167
|
`);
|
|
163
|
-
return `query($iid: String!, ${variables}) {
|
|
168
|
+
return query(`query($iid: String!, ${variables}) {
|
|
164
169
|
${projects}
|
|
165
|
-
}
|
|
170
|
+
}`);
|
|
166
171
|
}
|
|
167
172
|
function mergeRequestNumbersQuery(projectCount) {
|
|
168
173
|
const variables = Array.from({ length: projectCount }, (_, index) => `$p${index}: ID!`).join(", ");
|
|
@@ -170,18 +175,18 @@ function mergeRequestNumbersQuery(projectCount) {
|
|
|
170
175
|
mergeRequests(sourceBranches: [$branch], state: opened, first: 20) { nodes { iid updatedAt sourceProject { fullPath } } }
|
|
171
176
|
}`).join(`
|
|
172
177
|
`);
|
|
173
|
-
return `query($branch: String!, ${variables}) {
|
|
178
|
+
return query(`query($branch: String!, ${variables}) {
|
|
174
179
|
${projects}
|
|
175
|
-
}
|
|
180
|
+
}`);
|
|
176
181
|
}
|
|
177
|
-
var SOURCE_BRANCH_QUERY = `query($project: ID!, $iid: String!) {
|
|
182
|
+
var SOURCE_BRANCH_QUERY = query(`query($project: ID!, $iid: String!) {
|
|
178
183
|
project(fullPath: $project) { mergeRequest(iid: $iid) { sourceBranch } }
|
|
179
|
-
}
|
|
180
|
-
var DISCUSSIONS_QUERY = `query($project: ID!, $iid: String!, $after: String) {
|
|
184
|
+
}`);
|
|
185
|
+
var DISCUSSIONS_QUERY = query(`query($project: ID!, $iid: String!, $after: String) {
|
|
181
186
|
project(fullPath: $project) {
|
|
182
187
|
mergeRequest(iid: $iid) { discussions(first: ${PAGE_SIZE2}, after: $after) { ${DISCUSSIONS} } }
|
|
183
188
|
}
|
|
184
|
-
}
|
|
189
|
+
}`);
|
|
185
190
|
function classifyError(message, code) {
|
|
186
191
|
const text = message.trim().replace(/^glab:\s*/, "") || `glab exited with code ${code}`;
|
|
187
192
|
if (/ENOENT|command not found/i.test(text))
|
|
@@ -196,8 +201,8 @@ function classifyError(message, code) {
|
|
|
196
201
|
}
|
|
197
202
|
var isResponse = (body) => typeof body === "object" && body !== null && (!("errors" in body) || Array.isArray(body.errors)) && (!("data" in body) || typeof body.data === "object");
|
|
198
203
|
function glabGraphQL(run, cwd) {
|
|
199
|
-
return async (host,
|
|
200
|
-
const args = ["api", "graphql", "--hostname", host, "-f", `query=${
|
|
204
|
+
return async (host, query2, variables) => {
|
|
205
|
+
const args = ["api", "graphql", "--hostname", host, "-f", `query=${query2}`];
|
|
201
206
|
for (const [name, value] of Object.entries(variables))
|
|
202
207
|
args.push("-f", `${name}=${value}`);
|
|
203
208
|
const result = await run("glab", args, cwd);
|
|
@@ -265,10 +270,10 @@ function duoState(state) {
|
|
|
265
270
|
}
|
|
266
271
|
|
|
267
272
|
class GitLabForge {
|
|
268
|
-
graphql;
|
|
269
273
|
traits = gitlabTraits;
|
|
274
|
+
graphql;
|
|
270
275
|
constructor(graphql) {
|
|
271
|
-
this.graphql = graphql;
|
|
276
|
+
this.graphql = typed(graphql);
|
|
272
277
|
}
|
|
273
278
|
async findByBranch(repository) {
|
|
274
279
|
const { source, targets, sourceBranch } = repository;
|
|
@@ -279,7 +284,7 @@ class GitLabForge {
|
|
|
279
284
|
const seen = new Set;
|
|
280
285
|
const nodes = [];
|
|
281
286
|
targets.forEach((_, index) => {
|
|
282
|
-
for (const node of data
|
|
287
|
+
for (const node of data[`p${index}`]?.mergeRequests?.nodes ?? []) {
|
|
283
288
|
if (node.sourceProject?.fullPath.toLowerCase() !== sourcePath)
|
|
284
289
|
continue;
|
|
285
290
|
const key = `${node.targetProject.fullPath}!${node.iid}`;
|
|
@@ -298,7 +303,7 @@ class GitLabForge {
|
|
|
298
303
|
targets.forEach((target, index) => variables[`p${index}`] = target.path);
|
|
299
304
|
const data = await this.graphql(source.host, mergeRequestNumbersQuery(targets.length), variables);
|
|
300
305
|
const sourcePath = source.path.toLowerCase();
|
|
301
|
-
const nodes = targets.flatMap((_, index) => data
|
|
306
|
+
const nodes = targets.flatMap((_, index) => data[`p${index}`]?.mergeRequests?.nodes ?? []);
|
|
302
307
|
return nodes.filter((node) => node.sourceProject?.fullPath.toLowerCase() === sourcePath).sort((a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? ""))[0]?.iid;
|
|
303
308
|
}
|
|
304
309
|
async sourceBranch(ref) {
|
|
@@ -306,7 +311,7 @@ class GitLabForge {
|
|
|
306
311
|
project: ref.project,
|
|
307
312
|
iid: ref.iid
|
|
308
313
|
});
|
|
309
|
-
const branch = data
|
|
314
|
+
const branch = data.project?.mergeRequest?.sourceBranch;
|
|
310
315
|
return typeof branch === "string" && branch ? branch : undefined;
|
|
311
316
|
}
|
|
312
317
|
async findByNumber(projects, iid) {
|
|
@@ -317,7 +322,7 @@ class GitLabForge {
|
|
|
317
322
|
projects.forEach((project, index) => variables[`p${index}`] = project.path);
|
|
318
323
|
const data = await this.graphql(host, mergeRequestQuery(projects.length), variables);
|
|
319
324
|
for (let index = 0;index < projects.length; index++) {
|
|
320
|
-
const node = data
|
|
325
|
+
const node = data[`p${index}`]?.mergeRequest;
|
|
321
326
|
if (node)
|
|
322
327
|
return this.normalize(host, node);
|
|
323
328
|
}
|
|
@@ -333,7 +338,7 @@ class GitLabForge {
|
|
|
333
338
|
iid: node.iid,
|
|
334
339
|
after: page.endCursor
|
|
335
340
|
});
|
|
336
|
-
const next = data
|
|
341
|
+
const next = data.project?.mergeRequest?.discussions;
|
|
337
342
|
if (!next)
|
|
338
343
|
break;
|
|
339
344
|
count += countUnresolved(next);
|
|
@@ -389,8 +394,8 @@ var fields = `number title url state isDraft mergeable reviewDecision headRefOid
|
|
|
389
394
|
} } } } }`;
|
|
390
395
|
var MAX_PAGES = 50;
|
|
391
396
|
function ghGraphQL(run, cwd) {
|
|
392
|
-
return async (host,
|
|
393
|
-
const args = ["api", "graphql", "--hostname", host, "-f", `query=${
|
|
397
|
+
return async (host, query2, variables) => {
|
|
398
|
+
const args = ["api", "graphql", "--hostname", host, "-f", `query=${query2}`];
|
|
394
399
|
for (const [name, value] of Object.entries(variables))
|
|
395
400
|
args.push(typeof value === "number" ? "-F" : "-f", `${name}=${value}`);
|
|
396
401
|
const result = await run("gh", args, cwd);
|
|
@@ -480,17 +485,17 @@ var githubTraits = {
|
|
|
480
485
|
};
|
|
481
486
|
|
|
482
487
|
class GitHubForge {
|
|
483
|
-
graphql;
|
|
484
488
|
traits = githubTraits;
|
|
489
|
+
graphql;
|
|
485
490
|
constructor(graphql) {
|
|
486
|
-
this.graphql = graphql;
|
|
491
|
+
this.graphql = typed(graphql);
|
|
487
492
|
}
|
|
488
493
|
async findByNumber(projects, number) {
|
|
489
494
|
for (const project of projects) {
|
|
490
495
|
const [owner, repo] = project.path.split("/");
|
|
491
|
-
const data = await this.graphql(project.host, `query($owner:String!,$repo:String!,$number:Int!) {
|
|
496
|
+
const data = await this.graphql(project.host, query(`query($owner:String!,$repo:String!,$number:Int!) {
|
|
492
497
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) { ${fields} } }
|
|
493
|
-
}
|
|
498
|
+
}`), { owner, repo, number: Number(number) });
|
|
494
499
|
const node = data.repository?.pullRequest;
|
|
495
500
|
if (node)
|
|
496
501
|
return this.normalize(project.host, node);
|
|
@@ -501,10 +506,10 @@ class GitHubForge {
|
|
|
501
506
|
let newest;
|
|
502
507
|
for (const target of repository.targets) {
|
|
503
508
|
const [owner, repo] = target.path.split("/");
|
|
504
|
-
const data = await this.graphql(target.host, `query($owner:String!,$repo:String!,$branch:String!) {
|
|
509
|
+
const data = await this.graphql(target.host, query(`query($owner:String!,$repo:String!,$branch:String!) {
|
|
505
510
|
repository(owner:$owner,name:$repo) { pullRequests(first:100,states:OPEN,headRefName:$branch,orderBy:{field:UPDATED_AT,direction:DESC}) {
|
|
506
511
|
nodes { number updatedAt headRepository { nameWithOwner } }
|
|
507
|
-
} } }
|
|
512
|
+
} } }`), { owner, repo, branch: repository.sourceBranch });
|
|
508
513
|
const nodes = data.repository?.pullRequests?.nodes ?? [];
|
|
509
514
|
for (const node of nodes) {
|
|
510
515
|
if (node.headRepository?.nameWithOwner.toLowerCase() !== repository.source.path.toLowerCase())
|
|
@@ -517,11 +522,10 @@ class GitHubForge {
|
|
|
517
522
|
}
|
|
518
523
|
async sourceBranch(ref) {
|
|
519
524
|
const [owner, repo] = ref.project.split("/");
|
|
520
|
-
const data = await this.graphql(ref.host, `query($owner:String!,$repo:String!,$number:Int!) {
|
|
525
|
+
const data = await this.graphql(ref.host, query(`query($owner:String!,$repo:String!,$number:Int!) {
|
|
521
526
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) { headRefName } }
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
return typeof branch === "string" && branch ? branch : undefined;
|
|
527
|
+
}`), { owner, repo, number: Number(ref.iid) });
|
|
528
|
+
return data.repository?.pullRequest?.headRefName || undefined;
|
|
525
529
|
}
|
|
526
530
|
async findByBranch(repository) {
|
|
527
531
|
const found = new Map;
|
|
@@ -530,10 +534,10 @@ class GitHubForge {
|
|
|
530
534
|
let after;
|
|
531
535
|
let complete = false;
|
|
532
536
|
for (let page = 0;page < MAX_PAGES; page++) {
|
|
533
|
-
const data = await this.graphql(target.host, `query($owner:String!,$repo:String!,$branch:String!${after ? ",$after:String!" : ""}) {
|
|
537
|
+
const data = await this.graphql(target.host, query(`query($owner:String!,$repo:String!,$branch:String!${after ? ",$after:String!" : ""}) {
|
|
534
538
|
repository(owner:$owner,name:$repo) { pullRequests(first:100,states:OPEN,headRefName:$branch${after ? ",after:$after" : ""}) {
|
|
535
539
|
nodes { ${fields} } pageInfo { hasNextPage endCursor }
|
|
536
|
-
} } }
|
|
540
|
+
} } }`), { owner, repo, branch: repository.sourceBranch, ...after ? { after } : {} });
|
|
537
541
|
const pulls = data.repository?.pullRequests;
|
|
538
542
|
if (!pulls)
|
|
539
543
|
throw new ForgeError("request", "GitHub repository unavailable");
|
|
@@ -561,10 +565,10 @@ class GitHubForge {
|
|
|
561
565
|
const threads = [...node.reviewThreads.nodes];
|
|
562
566
|
let page = node.reviewThreads.pageInfo;
|
|
563
567
|
for (let count = 1;page?.hasNextPage && page.endCursor && count < MAX_PAGES; count++) {
|
|
564
|
-
const data = await this.graphql(host, `query($owner:String!,$repo:String!,$number:Int!,$after:String!) {
|
|
568
|
+
const data = await this.graphql(host, query(`query($owner:String!,$repo:String!,$number:Int!,$after:String!) {
|
|
565
569
|
repository(owner:$owner,name:$repo) { pullRequest(number:$number) {
|
|
566
570
|
reviewThreads(first:100,after:$after) { nodes { isResolved } pageInfo { hasNextPage endCursor } }
|
|
567
|
-
} } }
|
|
571
|
+
} } }`), { owner, repo, number: node.number, after: page.endCursor });
|
|
568
572
|
const next = data.repository?.pullRequest?.reviewThreads;
|
|
569
573
|
if (!next)
|
|
570
574
|
break;
|
|
@@ -582,10 +586,10 @@ class GitHubForge {
|
|
|
582
586
|
const contexts = [...rollup?.nodes ?? []];
|
|
583
587
|
let cursor = rollup?.pageInfo;
|
|
584
588
|
for (let count = 1;cursor?.hasNextPage && cursor.endCursor && count < MAX_PAGES; count++) {
|
|
585
|
-
const data = await this.graphql(host, `query($owner:String!,$repo:String!,$oid:GitObjectID!,$after:String!) {
|
|
589
|
+
const data = await this.graphql(host, query(`query($owner:String!,$repo:String!,$oid:GitObjectID!,$after:String!) {
|
|
586
590
|
repository(owner:$owner,name:$repo) { object(oid:$oid) { ... on Commit { statusCheckRollup {
|
|
587
591
|
contexts(first:100,after:$after) { nodes { __typename ... on CheckRun { status conclusion detailsUrl } ... on StatusContext { state targetUrl } } pageInfo { hasNextPage endCursor } }
|
|
588
|
-
} } } } }
|
|
592
|
+
} } } } }`), { owner, repo, oid: node.headRefOid, after: cursor.endCursor });
|
|
589
593
|
const next = data.repository?.object?.statusCheckRollup?.contexts;
|
|
590
594
|
if (!next)
|
|
591
595
|
break;
|
|
@@ -876,14 +880,15 @@ var target = {
|
|
|
876
880
|
additionalProperties: false
|
|
877
881
|
};
|
|
878
882
|
var key = { type: "string" };
|
|
879
|
-
var snapshot = { type: "object" };
|
|
883
|
+
var snapshot = { type: "object", title: "Snapshot" };
|
|
880
884
|
var status = {
|
|
881
885
|
type: "object",
|
|
882
886
|
properties: { enabled: { type: "boolean" }, snapshot },
|
|
883
|
-
required: ["enabled", "snapshot"]
|
|
887
|
+
required: ["enabled", "snapshot"],
|
|
888
|
+
additionalProperties: false
|
|
884
889
|
};
|
|
885
890
|
var ForgeSessionRpc = {
|
|
886
|
-
id: "opencode-
|
|
891
|
+
id: "opencode-forgekeeper",
|
|
887
892
|
methods: {
|
|
888
893
|
target: {
|
|
889
894
|
input: {
|
|
@@ -907,8 +912,12 @@ var ForgeSessionRpc = {
|
|
|
907
912
|
},
|
|
908
913
|
output: {
|
|
909
914
|
type: "object",
|
|
910
|
-
properties: {
|
|
911
|
-
|
|
915
|
+
properties: {
|
|
916
|
+
enabled: { type: "boolean" },
|
|
917
|
+
statuses: { type: "object", additionalProperties: snapshot }
|
|
918
|
+
},
|
|
919
|
+
required: ["enabled", "statuses"],
|
|
920
|
+
additionalProperties: false
|
|
912
921
|
}
|
|
913
922
|
},
|
|
914
923
|
release: {
|
|
@@ -918,7 +927,7 @@ var ForgeSessionRpc = {
|
|
|
918
927
|
required: ["clientID"],
|
|
919
928
|
additionalProperties: false
|
|
920
929
|
},
|
|
921
|
-
output: { type: "object" }
|
|
930
|
+
output: { type: "object", additionalProperties: false }
|
|
922
931
|
},
|
|
923
932
|
refresh: {
|
|
924
933
|
input: {
|
|
@@ -943,7 +952,8 @@ var ForgeSessionRpc = {
|
|
|
943
952
|
schema: {
|
|
944
953
|
type: "object",
|
|
945
954
|
properties: { directory: { type: "string" }, key, snapshot },
|
|
946
|
-
required: ["directory", "key", "snapshot"]
|
|
955
|
+
required: ["directory", "key", "snapshot"],
|
|
956
|
+
additionalProperties: false
|
|
947
957
|
}
|
|
948
958
|
},
|
|
949
959
|
notice: {
|
|
@@ -955,7 +965,8 @@ var ForgeSessionRpc = {
|
|
|
955
965
|
message: { type: "string" },
|
|
956
966
|
variant: { type: "string", enum: ["info", "error"] }
|
|
957
967
|
},
|
|
958
|
-
required: ["message", "variant"]
|
|
968
|
+
required: ["message", "variant"],
|
|
969
|
+
additionalProperties: false
|
|
959
970
|
}
|
|
960
971
|
}
|
|
961
972
|
}
|
|
@@ -1272,6 +1283,337 @@ var tui_default = {
|
|
|
1272
1283
|
});
|
|
1273
1284
|
return true;
|
|
1274
1285
|
};
|
|
1286
|
+
function DetailField(props) {
|
|
1287
|
+
const foreground = () => props.tone ? color(props.tone) : context.theme.text.base;
|
|
1288
|
+
return (() => {
|
|
1289
|
+
var _el$8 = _$createElement("text"), _el$9 = _$createTextNode(`: `), _el$0 = _$createElement("span");
|
|
1290
|
+
_$insertNode(_el$8, _el$9);
|
|
1291
|
+
_$insertNode(_el$8, _el$0);
|
|
1292
|
+
_$setProp(_el$8, "onMouseUp", () => props.url && openUrl(props.url));
|
|
1293
|
+
_$insert(_el$8, () => props.label, _el$9);
|
|
1294
|
+
_$insert(_el$0, _$createComponent(Show, {
|
|
1295
|
+
get when() {
|
|
1296
|
+
return props.url;
|
|
1297
|
+
},
|
|
1298
|
+
get fallback() {
|
|
1299
|
+
return (() => {
|
|
1300
|
+
var _el$1 = _$createElement("b");
|
|
1301
|
+
_$insert(_el$1, () => props.value);
|
|
1302
|
+
return _el$1;
|
|
1303
|
+
})();
|
|
1304
|
+
},
|
|
1305
|
+
children: (url) => (() => {
|
|
1306
|
+
var _el$10 = _$createElement("a"), _el$11 = _$createElement("u"), _el$12 = _$createElement("b");
|
|
1307
|
+
_$insertNode(_el$10, _el$11);
|
|
1308
|
+
_$insertNode(_el$11, _el$12);
|
|
1309
|
+
_$insert(_el$12, () => props.value);
|
|
1310
|
+
_$effect((_$p) => _$setProp(_el$10, "href", url(), _$p));
|
|
1311
|
+
return _el$10;
|
|
1312
|
+
})()
|
|
1313
|
+
}));
|
|
1314
|
+
_$effect((_p$) => {
|
|
1315
|
+
var _v$3 = context.theme.text.muted, _v$4 = {
|
|
1316
|
+
fg: foreground()
|
|
1317
|
+
};
|
|
1318
|
+
_v$3 !== _p$.e && (_p$.e = _$setProp(_el$8, "fg", _v$3, _p$.e));
|
|
1319
|
+
_v$4 !== _p$.t && (_p$.t = _$setProp(_el$0, "style", _v$4, _p$.t));
|
|
1320
|
+
return _p$;
|
|
1321
|
+
}, {
|
|
1322
|
+
e: undefined,
|
|
1323
|
+
t: undefined
|
|
1324
|
+
});
|
|
1325
|
+
return _el$8;
|
|
1326
|
+
})();
|
|
1327
|
+
}
|
|
1328
|
+
function RequestDetails(props) {
|
|
1329
|
+
const request = () => props.request;
|
|
1330
|
+
const traits = () => traitsOf(request());
|
|
1331
|
+
const review = () => automatedReview(request());
|
|
1332
|
+
return (() => {
|
|
1333
|
+
var _el$13 = _$createElement("box"), _el$14 = _$createElement("text"), _el$15 = _$createElement("a"), _el$16 = _$createElement("u"), _el$17 = _$createElement("b"), _el$18 = _$createTextNode(` `), _el$19 = _$createElement("box"), _el$20 = _$createElement("box"), _el$21 = _$createElement("text"), _el$22 = _$createElement("b");
|
|
1334
|
+
_$insertNode(_el$13, _el$14);
|
|
1335
|
+
_$insertNode(_el$13, _el$19);
|
|
1336
|
+
_$insertNode(_el$13, _el$20);
|
|
1337
|
+
_$setProp(_el$13, "gap", 1);
|
|
1338
|
+
_$setProp(_el$13, "flexShrink", 0);
|
|
1339
|
+
_$insertNode(_el$14, _el$15);
|
|
1340
|
+
_$setProp(_el$14, "onMouseUp", () => openUrl(request().url));
|
|
1341
|
+
_$insertNode(_el$15, _el$16);
|
|
1342
|
+
_$insertNode(_el$16, _el$17);
|
|
1343
|
+
_$insertNode(_el$17, _el$18);
|
|
1344
|
+
_$insert(_el$17, () => reference(request()), _el$18);
|
|
1345
|
+
_$insert(_el$17, () => request().title, null);
|
|
1346
|
+
_$setProp(_el$19, "flexShrink", 0);
|
|
1347
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1348
|
+
label: "State",
|
|
1349
|
+
get value() {
|
|
1350
|
+
return request().state;
|
|
1351
|
+
},
|
|
1352
|
+
get tone() {
|
|
1353
|
+
return request().state === "merged" ? "success" : undefined;
|
|
1354
|
+
}
|
|
1355
|
+
}), null);
|
|
1356
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1357
|
+
label: "Target",
|
|
1358
|
+
get value() {
|
|
1359
|
+
return `${request().targetProject} \u2192 ${request().targetBranch}`;
|
|
1360
|
+
}
|
|
1361
|
+
}), null);
|
|
1362
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1363
|
+
get label() {
|
|
1364
|
+
return traits().ci.charAt(0).toUpperCase() + traits().ci.slice(1);
|
|
1365
|
+
},
|
|
1366
|
+
get value() {
|
|
1367
|
+
return request().pipeline?.label ?? "none";
|
|
1368
|
+
},
|
|
1369
|
+
get tone() {
|
|
1370
|
+
return pipelineTone(request().pipeline);
|
|
1371
|
+
},
|
|
1372
|
+
get url() {
|
|
1373
|
+
return request().pipeline?.url;
|
|
1374
|
+
}
|
|
1375
|
+
}), null);
|
|
1376
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1377
|
+
label: "Unresolved threads",
|
|
1378
|
+
get value() {
|
|
1379
|
+
return `${request().unresolvedThreads}${request().threadsComplete ? "" : "+"}`;
|
|
1380
|
+
},
|
|
1381
|
+
get tone() {
|
|
1382
|
+
return request().unresolvedThreads || !request().threadsComplete ? "warning" : undefined;
|
|
1383
|
+
}
|
|
1384
|
+
}), null);
|
|
1385
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1386
|
+
label: "Draft",
|
|
1387
|
+
get value() {
|
|
1388
|
+
return yesNo(request().draft);
|
|
1389
|
+
},
|
|
1390
|
+
get tone() {
|
|
1391
|
+
return request().draft ? "warning" : undefined;
|
|
1392
|
+
}
|
|
1393
|
+
}), null);
|
|
1394
|
+
_$insert(_el$19, _$createComponent(DetailField, {
|
|
1395
|
+
label: "Conflicts",
|
|
1396
|
+
get value() {
|
|
1397
|
+
return _$memo(() => !!request().conflictsKnown)() ? yesNo(request().conflicts) : "unknown";
|
|
1398
|
+
},
|
|
1399
|
+
get tone() {
|
|
1400
|
+
return request().conflicts ? "error" : undefined;
|
|
1401
|
+
}
|
|
1402
|
+
}), null);
|
|
1403
|
+
_$insertNode(_el$20, _el$21);
|
|
1404
|
+
_$setProp(_el$20, "flexShrink", 0);
|
|
1405
|
+
_$insertNode(_el$21, _el$22);
|
|
1406
|
+
_$insertNode(_el$22, _$createTextNode(`Review and approval`));
|
|
1407
|
+
_$insert(_el$20, _$createComponent(For, {
|
|
1408
|
+
get each() {
|
|
1409
|
+
return traits().details(request());
|
|
1410
|
+
},
|
|
1411
|
+
children: (line) => {
|
|
1412
|
+
const separator = line.indexOf(": ");
|
|
1413
|
+
return separator < 0 ? (() => {
|
|
1414
|
+
var _el$29 = _$createElement("text");
|
|
1415
|
+
_$insert(_el$29, line);
|
|
1416
|
+
_$effect((_$p) => _$setProp(_el$29, "fg", context.theme.text.base, _$p));
|
|
1417
|
+
return _el$29;
|
|
1418
|
+
})() : _$createComponent(DetailField, {
|
|
1419
|
+
get label() {
|
|
1420
|
+
return line.slice(0, separator);
|
|
1421
|
+
},
|
|
1422
|
+
get value() {
|
|
1423
|
+
return line.slice(separator + 2);
|
|
1424
|
+
}
|
|
1425
|
+
});
|
|
1426
|
+
}
|
|
1427
|
+
}), null);
|
|
1428
|
+
_$insert(_el$20, _$createComponent(Show, {
|
|
1429
|
+
get when() {
|
|
1430
|
+
return review();
|
|
1431
|
+
},
|
|
1432
|
+
children: (value) => _$createComponent(DetailField, {
|
|
1433
|
+
get label() {
|
|
1434
|
+
return `${value().name} review`;
|
|
1435
|
+
},
|
|
1436
|
+
get value() {
|
|
1437
|
+
return value().label;
|
|
1438
|
+
},
|
|
1439
|
+
get tone() {
|
|
1440
|
+
return value().state === "running" ? "warning" : undefined;
|
|
1441
|
+
}
|
|
1442
|
+
})
|
|
1443
|
+
}), null);
|
|
1444
|
+
_$insert(_el$20, _$createComponent(Show, {
|
|
1445
|
+
get when() {
|
|
1446
|
+
return request().awaitingReviewers.length;
|
|
1447
|
+
},
|
|
1448
|
+
get children() {
|
|
1449
|
+
return _$createComponent(DetailField, {
|
|
1450
|
+
label: "Awaiting review",
|
|
1451
|
+
get value() {
|
|
1452
|
+
return request().awaitingReviewers.map((username) => `@${username}`).join(", ");
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
}), null);
|
|
1457
|
+
_$insert(_el$13, _$createComponent(Show, {
|
|
1458
|
+
get when() {
|
|
1459
|
+
return !request().reviewersComplete;
|
|
1460
|
+
},
|
|
1461
|
+
get children() {
|
|
1462
|
+
var _el$24 = _$createElement("text");
|
|
1463
|
+
_$insertNode(_el$24, _$createTextNode(`Reviewer list is partial`));
|
|
1464
|
+
_$effect((_$p) => _$setProp(_el$24, "fg", color("warning"), _$p));
|
|
1465
|
+
return _el$24;
|
|
1466
|
+
}
|
|
1467
|
+
}), null);
|
|
1468
|
+
_$insert(_el$13, _$createComponent(Show, {
|
|
1469
|
+
get when() {
|
|
1470
|
+
return _$memo(() => !!(props.head && request().headSha))() && props.head !== request().headSha;
|
|
1471
|
+
},
|
|
1472
|
+
get children() {
|
|
1473
|
+
var _el$26 = _$createElement("text"), _el$27 = _$createTextNode(`Local HEAD differs from the `), _el$28 = _$createTextNode(` head commit (unpushed or not fetched)`);
|
|
1474
|
+
_$insertNode(_el$26, _el$27);
|
|
1475
|
+
_$insertNode(_el$26, _el$28);
|
|
1476
|
+
_$insert(_el$26, () => traits().noun, _el$28);
|
|
1477
|
+
_$effect((_$p) => _$setProp(_el$26, "fg", color("warning"), _$p));
|
|
1478
|
+
return _el$26;
|
|
1479
|
+
}
|
|
1480
|
+
}), null);
|
|
1481
|
+
_$effect((_p$) => {
|
|
1482
|
+
var _v$5 = context.theme.text.base, _v$6 = request().url, _v$7 = context.theme.text.base;
|
|
1483
|
+
_v$5 !== _p$.e && (_p$.e = _$setProp(_el$14, "fg", _v$5, _p$.e));
|
|
1484
|
+
_v$6 !== _p$.t && (_p$.t = _$setProp(_el$15, "href", _v$6, _p$.t));
|
|
1485
|
+
_v$7 !== _p$.a && (_p$.a = _$setProp(_el$21, "fg", _v$7, _p$.a));
|
|
1486
|
+
return _p$;
|
|
1487
|
+
}, {
|
|
1488
|
+
e: undefined,
|
|
1489
|
+
t: undefined,
|
|
1490
|
+
a: undefined
|
|
1491
|
+
});
|
|
1492
|
+
return _el$13;
|
|
1493
|
+
})();
|
|
1494
|
+
}
|
|
1495
|
+
function StatusDetails(props) {
|
|
1496
|
+
const lookup = () => {
|
|
1497
|
+
const value = props.snapshot.lookup;
|
|
1498
|
+
return value?.kind === "found" ? value : undefined;
|
|
1499
|
+
};
|
|
1500
|
+
return (() => {
|
|
1501
|
+
var _el$30 = _$createElement("box");
|
|
1502
|
+
_$setProp(_el$30, "gap", 1);
|
|
1503
|
+
_$setProp(_el$30, "flexShrink", 0);
|
|
1504
|
+
_$insert(_el$30, _$createComponent(Show, {
|
|
1505
|
+
get when() {
|
|
1506
|
+
return lookup();
|
|
1507
|
+
},
|
|
1508
|
+
get fallback() {
|
|
1509
|
+
return (() => {
|
|
1510
|
+
var _el$31 = _$createElement("text");
|
|
1511
|
+
_$insert(_el$31, () => detailsMessage(props.snapshot));
|
|
1512
|
+
_$effect((_$p) => _$setProp(_el$31, "fg", props.snapshot.error ? color("error") : context.theme.text.muted, _$p));
|
|
1513
|
+
return _el$31;
|
|
1514
|
+
})();
|
|
1515
|
+
},
|
|
1516
|
+
children: (found) => [_$createComponent(Show, {
|
|
1517
|
+
get when() {
|
|
1518
|
+
return found().repository;
|
|
1519
|
+
},
|
|
1520
|
+
children: (repository) => (() => {
|
|
1521
|
+
var _el$36 = _$createElement("box");
|
|
1522
|
+
_$setProp(_el$36, "flexShrink", 0);
|
|
1523
|
+
_$insert(_el$36, _$createComponent(DetailField, {
|
|
1524
|
+
label: "Repository",
|
|
1525
|
+
get value() {
|
|
1526
|
+
return repository().source.path;
|
|
1527
|
+
}
|
|
1528
|
+
}), null);
|
|
1529
|
+
_$insert(_el$36, _$createComponent(DetailField, {
|
|
1530
|
+
label: "Branch",
|
|
1531
|
+
get value() {
|
|
1532
|
+
return _$memo(() => repository().branch === repository().sourceBranch)() ? repository().branch : `${repository().branch} (pushes to ${repository().sourceBranch})`;
|
|
1533
|
+
}
|
|
1534
|
+
}), null);
|
|
1535
|
+
return _el$36;
|
|
1536
|
+
})()
|
|
1537
|
+
}), _$createComponent(Show, {
|
|
1538
|
+
get when() {
|
|
1539
|
+
return _$memo(() => !!!found().repository)() && found().sessionTarget;
|
|
1540
|
+
},
|
|
1541
|
+
get children() {
|
|
1542
|
+
return _$createComponent(DetailField, {
|
|
1543
|
+
label: "Session target",
|
|
1544
|
+
get value() {
|
|
1545
|
+
return found().sessionTarget;
|
|
1546
|
+
}
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
}), _$createComponent(For, {
|
|
1550
|
+
get each() {
|
|
1551
|
+
return found().failed ?? [];
|
|
1552
|
+
},
|
|
1553
|
+
children: (failure) => (() => {
|
|
1554
|
+
var _el$37 = _$createElement("text"), _el$38 = _$createElement("b"), _el$40 = _$createTextNode(`
|
|
1555
|
+
`), _el$41 = _$createTextNode(`
|
|
1556
|
+
`);
|
|
1557
|
+
_$insertNode(_el$37, _el$38);
|
|
1558
|
+
_$insertNode(_el$37, _el$40);
|
|
1559
|
+
_$insertNode(_el$37, _el$41);
|
|
1560
|
+
_$insertNode(_el$38, _$createTextNode(`Unavailable`));
|
|
1561
|
+
_$insert(_el$37, () => failure.url, _el$41);
|
|
1562
|
+
_$insert(_el$37, () => failure.reason, null);
|
|
1563
|
+
_$effect((_$p) => _$setProp(_el$37, "fg", color("warning"), _$p));
|
|
1564
|
+
return _el$37;
|
|
1565
|
+
})()
|
|
1566
|
+
}), _$createComponent(Show, {
|
|
1567
|
+
get when() {
|
|
1568
|
+
return found().requests.length === 0;
|
|
1569
|
+
},
|
|
1570
|
+
get children() {
|
|
1571
|
+
var _el$32 = _$createElement("text");
|
|
1572
|
+
_$insertNode(_el$32, _$createTextNode(`No PR/MR status available.`));
|
|
1573
|
+
_$effect((_$p) => _$setProp(_el$32, "fg", context.theme.text.muted, _$p));
|
|
1574
|
+
return _el$32;
|
|
1575
|
+
}
|
|
1576
|
+
}), _$createComponent(For, {
|
|
1577
|
+
get each() {
|
|
1578
|
+
return found().requests;
|
|
1579
|
+
},
|
|
1580
|
+
children: (request) => _$createComponent(RequestDetails, {
|
|
1581
|
+
request,
|
|
1582
|
+
get head() {
|
|
1583
|
+
return found().repository?.head;
|
|
1584
|
+
}
|
|
1585
|
+
})
|
|
1586
|
+
}), _$createComponent(Show, {
|
|
1587
|
+
get when() {
|
|
1588
|
+
return props.snapshot.error;
|
|
1589
|
+
},
|
|
1590
|
+
children: (error) => (() => {
|
|
1591
|
+
var _el$42 = _$createElement("text"), _el$43 = _$createElement("b"), _el$44 = _$createTextNode(`Last refresh failed at `), _el$45 = _$createTextNode(`
|
|
1592
|
+
`);
|
|
1593
|
+
_$insertNode(_el$42, _el$43);
|
|
1594
|
+
_$insertNode(_el$42, _el$45);
|
|
1595
|
+
_$insertNode(_el$43, _el$44);
|
|
1596
|
+
_$insert(_el$43, () => new Date(error().at).toLocaleTimeString(), null);
|
|
1597
|
+
_$insert(_el$42, () => error().message, null);
|
|
1598
|
+
_$effect((_$p) => _$setProp(_el$42, "fg", color("error"), _$p));
|
|
1599
|
+
return _el$42;
|
|
1600
|
+
})()
|
|
1601
|
+
}), _$createComponent(Show, {
|
|
1602
|
+
get when() {
|
|
1603
|
+
return props.snapshot.fetchedAt !== undefined;
|
|
1604
|
+
},
|
|
1605
|
+
get children() {
|
|
1606
|
+
var _el$34 = _$createElement("text"), _el$35 = _$createTextNode(`Last fetched: `);
|
|
1607
|
+
_$insertNode(_el$34, _el$35);
|
|
1608
|
+
_$insert(_el$34, () => new Date(props.snapshot.fetchedAt).toLocaleTimeString(), null);
|
|
1609
|
+
_$effect((_$p) => _$setProp(_el$34, "fg", context.theme.text.muted, _$p));
|
|
1610
|
+
return _el$34;
|
|
1611
|
+
}
|
|
1612
|
+
})]
|
|
1613
|
+
}));
|
|
1614
|
+
return _el$30;
|
|
1615
|
+
})();
|
|
1616
|
+
}
|
|
1275
1617
|
function StatusDialog(props) {
|
|
1276
1618
|
const [terminalHeight, setTerminalHeight] = createSignal(context.renderer.height);
|
|
1277
1619
|
const onResize = () => setTerminalHeight(context.renderer.height);
|
|
@@ -1321,52 +1663,55 @@ var tui_default = {
|
|
|
1321
1663
|
}]
|
|
1322
1664
|
}));
|
|
1323
1665
|
return (() => {
|
|
1324
|
-
var _el$
|
|
1325
|
-
_$insertNode(_el$
|
|
1326
|
-
_$insertNode(_el$
|
|
1327
|
-
_$insertNode(_el$
|
|
1328
|
-
_$setProp(_el$
|
|
1329
|
-
_$setProp(_el$
|
|
1330
|
-
_$setProp(_el$
|
|
1331
|
-
_$setProp(_el$
|
|
1332
|
-
_$insertNode(_el$
|
|
1333
|
-
_$insertNode(_el$
|
|
1334
|
-
_$setProp(_el$
|
|
1335
|
-
_$setProp(_el$
|
|
1336
|
-
_$setProp(_el$
|
|
1337
|
-
_$setProp(_el$
|
|
1338
|
-
_$insertNode(_el$
|
|
1339
|
-
_$insertNode(_el$
|
|
1340
|
-
_$insertNode(_el$
|
|
1341
|
-
_$setProp(_el$
|
|
1342
|
-
_$
|
|
1343
|
-
_$setProp(_el$
|
|
1344
|
-
_$setProp(_el$
|
|
1345
|
-
_$setProp(_el$
|
|
1346
|
-
_$setProp(_el$13, "contentOptions", {
|
|
1666
|
+
var _el$46 = _$createElement("box"), _el$47 = _$createElement("box"), _el$48 = _$createElement("text"), _el$49 = _$createElement("b"), _el$51 = _$createElement("text"), _el$53 = _$createElement("scrollbox"), _el$54 = _$createElement("box");
|
|
1667
|
+
_$insertNode(_el$46, _el$47);
|
|
1668
|
+
_$insertNode(_el$46, _el$53);
|
|
1669
|
+
_$insertNode(_el$46, _el$54);
|
|
1670
|
+
_$setProp(_el$46, "paddingLeft", 2);
|
|
1671
|
+
_$setProp(_el$46, "paddingRight", 2);
|
|
1672
|
+
_$setProp(_el$46, "paddingBottom", 1);
|
|
1673
|
+
_$setProp(_el$46, "gap", 1);
|
|
1674
|
+
_$insertNode(_el$47, _el$48);
|
|
1675
|
+
_$insertNode(_el$47, _el$51);
|
|
1676
|
+
_$setProp(_el$47, "height", 1);
|
|
1677
|
+
_$setProp(_el$47, "flexShrink", 0);
|
|
1678
|
+
_$setProp(_el$47, "flexDirection", "row");
|
|
1679
|
+
_$setProp(_el$47, "justifyContent", "space-between");
|
|
1680
|
+
_$insertNode(_el$48, _el$49);
|
|
1681
|
+
_$insertNode(_el$49, _$createTextNode(`PR/MR status`));
|
|
1682
|
+
_$insertNode(_el$51, _$createTextNode(`esc`));
|
|
1683
|
+
_$setProp(_el$51, "onMouseUp", close);
|
|
1684
|
+
_$setProp(_el$53, "minHeight", 1);
|
|
1685
|
+
_$setProp(_el$53, "flexShrink", 0);
|
|
1686
|
+
_$setProp(_el$53, "scrollX", false);
|
|
1687
|
+
_$setProp(_el$53, "contentOptions", {
|
|
1347
1688
|
flexShrink: 0
|
|
1348
1689
|
});
|
|
1349
|
-
_$insert(_el$
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
_$
|
|
1690
|
+
_$insert(_el$53, _$createComponent(StatusDetails, {
|
|
1691
|
+
get snapshot() {
|
|
1692
|
+
return snapshot2();
|
|
1693
|
+
}
|
|
1694
|
+
}));
|
|
1695
|
+
_$setProp(_el$54, "height", 1);
|
|
1696
|
+
_$setProp(_el$54, "flexShrink", 0);
|
|
1697
|
+
_$setProp(_el$54, "flexDirection", "row");
|
|
1698
|
+
_$setProp(_el$54, "justifyContent", "flex-end");
|
|
1699
|
+
_$insert(_el$54, _$createComponent(For, {
|
|
1355
1700
|
each: ["close", "refresh"],
|
|
1356
1701
|
children: (action) => {
|
|
1357
1702
|
const disabled = () => action === "refresh" && snapshot2().loading;
|
|
1358
1703
|
const active = () => activeAction() === action && !disabled();
|
|
1359
1704
|
return (() => {
|
|
1360
|
-
var _el$
|
|
1361
|
-
_$insertNode(_el$
|
|
1362
|
-
_$setProp(_el$
|
|
1363
|
-
_$setProp(_el$
|
|
1364
|
-
_$setProp(_el$
|
|
1365
|
-
_$setProp(_el$
|
|
1705
|
+
var _el$55 = _$createElement("box"), _el$56 = _$createElement("text");
|
|
1706
|
+
_$insertNode(_el$55, _el$56);
|
|
1707
|
+
_$setProp(_el$55, "paddingLeft", 1);
|
|
1708
|
+
_$setProp(_el$55, "paddingRight", 1);
|
|
1709
|
+
_$setProp(_el$55, "flexShrink", 0);
|
|
1710
|
+
_$setProp(_el$55, "onMouseMove", () => {
|
|
1366
1711
|
if (!disabled())
|
|
1367
1712
|
setActiveAction(action);
|
|
1368
1713
|
});
|
|
1369
|
-
_$setProp(_el$
|
|
1714
|
+
_$setProp(_el$55, "onMouseUp", () => {
|
|
1370
1715
|
if (disabled())
|
|
1371
1716
|
return;
|
|
1372
1717
|
setActiveAction(action);
|
|
@@ -1375,37 +1720,35 @@ var tui_default = {
|
|
|
1375
1720
|
else
|
|
1376
1721
|
close();
|
|
1377
1722
|
});
|
|
1378
|
-
_$setProp(_el$
|
|
1379
|
-
_$insert(_el$
|
|
1723
|
+
_$setProp(_el$56, "wrapMode", "none");
|
|
1724
|
+
_$insert(_el$56, () => action === "close" ? "Close" : snapshot2().loading ? "Refreshing\u2026" : "Refresh");
|
|
1380
1725
|
_$effect((_p$) => {
|
|
1381
|
-
var _v$
|
|
1382
|
-
_v$
|
|
1383
|
-
_v$
|
|
1726
|
+
var _v$10 = active() ? context.theme.background.action.primary.focused : undefined, _v$11 = disabled() ? context.theme.text.action.primary.disabled : active() ? context.theme.text.action.primary.focused : context.theme.text.muted;
|
|
1727
|
+
_v$10 !== _p$.e && (_p$.e = _$setProp(_el$55, "backgroundColor", _v$10, _p$.e));
|
|
1728
|
+
_v$11 !== _p$.t && (_p$.t = _$setProp(_el$56, "fg", _v$11, _p$.t));
|
|
1384
1729
|
return _p$;
|
|
1385
1730
|
}, {
|
|
1386
1731
|
e: undefined,
|
|
1387
1732
|
t: undefined
|
|
1388
1733
|
});
|
|
1389
|
-
return _el$
|
|
1734
|
+
return _el$55;
|
|
1390
1735
|
})();
|
|
1391
1736
|
}
|
|
1392
1737
|
}));
|
|
1393
1738
|
_$effect((_p$) => {
|
|
1394
|
-
var _v$
|
|
1395
|
-
_v$
|
|
1396
|
-
_v$
|
|
1397
|
-
_v$
|
|
1398
|
-
_v$
|
|
1399
|
-
_v$7 !== _p$.i && (_p$.i = _$setProp(_el$14, "fg", _v$7, _p$.i));
|
|
1739
|
+
var _v$8 = contentHeight() + 5, _v$9 = context.theme.text.base, _v$0 = context.theme.text.muted, _v$1 = contentHeight();
|
|
1740
|
+
_v$8 !== _p$.e && (_p$.e = _$setProp(_el$46, "height", _v$8, _p$.e));
|
|
1741
|
+
_v$9 !== _p$.t && (_p$.t = _$setProp(_el$48, "fg", _v$9, _p$.t));
|
|
1742
|
+
_v$0 !== _p$.a && (_p$.a = _$setProp(_el$51, "fg", _v$0, _p$.a));
|
|
1743
|
+
_v$1 !== _p$.o && (_p$.o = _$setProp(_el$53, "height", _v$1, _p$.o));
|
|
1400
1744
|
return _p$;
|
|
1401
1745
|
}, {
|
|
1402
1746
|
e: undefined,
|
|
1403
1747
|
t: undefined,
|
|
1404
1748
|
a: undefined,
|
|
1405
|
-
o: undefined
|
|
1406
|
-
i: undefined
|
|
1749
|
+
o: undefined
|
|
1407
1750
|
});
|
|
1408
|
-
return _el$
|
|
1751
|
+
return _el$46;
|
|
1409
1752
|
})();
|
|
1410
1753
|
}
|
|
1411
1754
|
function showStatus(place = currentPlace()) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-forgekeeper",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "OpenCode plugin that tracks each session's GitHub and GitLab issues and PRs/MRs: title prefixes, a PR/MR status footer, and review notifications",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Pedro Pombeiro",
|