opencode-pilot 0.18.0 → 0.18.2
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 +2 -3
- package/examples/config.yaml +2 -5
- package/examples/templates/review-feedback.md +2 -2
- package/package.json +1 -1
- package/service/poll-service.js +6 -1
- package/service/poller.js +21 -10
- package/service/presets/github.yaml +0 -17
- package/test/unit/poller.test.js +20 -0
- package/test/unit/repo-config.test.js +1 -24
package/README.md
CHANGED
|
@@ -65,11 +65,10 @@ Three ways to configure sources, from simplest to most flexible:
|
|
|
65
65
|
|
|
66
66
|
- `github/my-issues` - Issues assigned to me
|
|
67
67
|
- `github/review-requests` - PRs needing my review
|
|
68
|
-
- `github/my-prs-
|
|
69
|
-
- `github/my-prs-attention` - My PRs needing attention (conflicts OR feedback, with dynamic labeling)
|
|
68
|
+
- `github/my-prs-attention` - My PRs needing attention (conflicts OR human feedback)
|
|
70
69
|
- `linear/my-issues` - Linear tickets (requires `teamId`, `assigneeId`)
|
|
71
70
|
|
|
72
|
-
|
|
71
|
+
Session names for `my-prs-attention` indicate the condition: "Conflicts: {title}", "Feedback: {title}", or "Conflicts+Feedback: {title}".
|
|
73
72
|
|
|
74
73
|
### Prompt Templates
|
|
75
74
|
|
package/examples/config.yaml
CHANGED
|
@@ -27,16 +27,13 @@ sources:
|
|
|
27
27
|
|
|
28
28
|
- preset: github/review-requests
|
|
29
29
|
|
|
30
|
-
# PRs needing attention (conflicts OR feedback)
|
|
30
|
+
# PRs needing attention (conflicts OR human feedback)
|
|
31
31
|
# Session names dynamically indicate the condition: "Conflicts: ...", "Feedback: ...", or "Conflicts+Feedback: ..."
|
|
32
32
|
- preset: github/my-prs-attention
|
|
33
33
|
repos:
|
|
34
34
|
- myorg/backend
|
|
35
35
|
- myorg/frontend
|
|
36
36
|
|
|
37
|
-
# Alternative: Simple feedback-only trigger (use my-prs-attention for conflicts too)
|
|
38
|
-
# - preset: github/my-prs-feedback
|
|
39
|
-
|
|
40
37
|
# Linear (requires teamId and assigneeId)
|
|
41
38
|
- preset: linear/my-issues
|
|
42
39
|
args:
|
|
@@ -92,4 +89,4 @@ sources:
|
|
|
92
89
|
# ttl_days: 30
|
|
93
90
|
|
|
94
91
|
# Available presets: github/my-issues, github/review-requests,
|
|
95
|
-
# github/my-prs-
|
|
92
|
+
# github/my-prs-attention, linear/my-issues
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Address the review feedback on this PR:
|
|
1
|
+
Address the review feedback or merge conflicts on this PR:
|
|
2
2
|
|
|
3
3
|
{title}
|
|
4
4
|
|
|
5
5
|
{html_url}
|
|
6
6
|
|
|
7
|
-
Focus
|
|
7
|
+
Focus on unresolved review comments and merge conflicts. Make the requested changes and respond to reviewers. Skip any conversations that are already resolved.
|
package/package.json
CHANGED
package/service/poll-service.js
CHANGED
|
@@ -124,7 +124,12 @@ export async function pollOnce(options = {}) {
|
|
|
124
124
|
// Fetch items from source
|
|
125
125
|
if (!skipMcp) {
|
|
126
126
|
try {
|
|
127
|
-
|
|
127
|
+
// Get provider config - for MCP sources use source.tool.mcp, for CLI sources detect provider
|
|
128
|
+
let provider = source.tool.mcp;
|
|
129
|
+
if (!provider && Array.isArray(source.tool?.command) && source.tool.command[0] === 'gh') {
|
|
130
|
+
provider = 'github'; // CLI-based GitHub source
|
|
131
|
+
}
|
|
132
|
+
toolProviderConfig = getToolProviderConfig(provider);
|
|
128
133
|
items = await pollGenericSource(source, { toolProviderConfig });
|
|
129
134
|
debug(`Fetched ${items.length} items from ${sourceName}`);
|
|
130
135
|
|
package/service/poller.js
CHANGED
|
@@ -12,7 +12,7 @@ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
|
12
12
|
import fs from "fs";
|
|
13
13
|
import path from "path";
|
|
14
14
|
import os from "os";
|
|
15
|
-
import { getNestedValue } from "./utils.js";
|
|
15
|
+
import { getNestedValue, hasNonBotFeedback } from "./utils.js";
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Expand template string with item fields
|
|
@@ -501,6 +501,22 @@ export async function fetchGitHubComments(item, options = {}) {
|
|
|
501
501
|
}
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
/**
|
|
505
|
+
* Check if a source is a GitHub source (MCP or CLI-based)
|
|
506
|
+
* @param {object} source - Source configuration
|
|
507
|
+
* @returns {boolean} True if this is a GitHub source
|
|
508
|
+
*/
|
|
509
|
+
function isGitHubSource(source) {
|
|
510
|
+
// MCP-based GitHub source
|
|
511
|
+
if (source.tool?.mcp === "github") return true;
|
|
512
|
+
|
|
513
|
+
// CLI-based GitHub source (uses gh command)
|
|
514
|
+
const command = source.tool?.command;
|
|
515
|
+
if (Array.isArray(command) && command[0] === "gh") return true;
|
|
516
|
+
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
|
|
504
520
|
/**
|
|
505
521
|
* Enrich items with comments for bot filtering
|
|
506
522
|
*
|
|
@@ -514,7 +530,7 @@ export async function fetchGitHubComments(item, options = {}) {
|
|
|
514
530
|
*/
|
|
515
531
|
export async function enrichItemsWithComments(items, source, options = {}) {
|
|
516
532
|
// Skip if not configured or not a GitHub source
|
|
517
|
-
if (!source.filter_bot_comments || source
|
|
533
|
+
if (!source.filter_bot_comments || !isGitHubSource(source)) {
|
|
518
534
|
return items;
|
|
519
535
|
}
|
|
520
536
|
|
|
@@ -618,16 +634,11 @@ export function computeAttentionLabels(items, source) {
|
|
|
618
634
|
reasons.push('Conflicts');
|
|
619
635
|
}
|
|
620
636
|
|
|
621
|
-
// Check for human feedback
|
|
637
|
+
// Check for human feedback using the shared hasNonBotFeedback utility
|
|
638
|
+
// This properly handles known bots like 'linear' that don't have [bot] suffix
|
|
622
639
|
if (item._comments && item._comments.length > 0) {
|
|
623
640
|
const authorUsername = item.user?.login || item.author?.login;
|
|
624
|
-
|
|
625
|
-
const commenter = comment.user?.login || comment.author?.login;
|
|
626
|
-
const isBot = commenter?.includes('[bot]') || comment.user?.type === 'Bot';
|
|
627
|
-
const isAuthor = commenter === authorUsername;
|
|
628
|
-
return !isBot && !isAuthor;
|
|
629
|
-
});
|
|
630
|
-
if (hasHumanFeedback) {
|
|
641
|
+
if (hasNonBotFeedback(item._comments, authorUsername)) {
|
|
631
642
|
reasons.push('Feedback');
|
|
632
643
|
}
|
|
633
644
|
}
|
|
@@ -37,23 +37,6 @@ review-requests:
|
|
|
37
37
|
session:
|
|
38
38
|
name: "Review: {title}"
|
|
39
39
|
|
|
40
|
-
my-prs-feedback:
|
|
41
|
-
name: my-prs-feedback
|
|
42
|
-
tool:
|
|
43
|
-
# comments:>0 filter ensures only PRs with feedback are returned
|
|
44
|
-
command: ["gh", "search", "prs", "--author=@me", "--state=open", "comments:>0", "--json", "number,title,url,repository,state,body,updatedAt,commentsCount"]
|
|
45
|
-
item:
|
|
46
|
-
id: "{url}"
|
|
47
|
-
repo: "{repository.nameWithOwner}"
|
|
48
|
-
prompt: review-feedback
|
|
49
|
-
session:
|
|
50
|
-
name: "Feedback: {title}"
|
|
51
|
-
# Reprocess when PR is updated (new commits pushed, new comments, etc.)
|
|
52
|
-
# This ensures we re-trigger after addressing review feedback
|
|
53
|
-
reprocess_on:
|
|
54
|
-
- state
|
|
55
|
-
- updatedAt
|
|
56
|
-
|
|
57
40
|
my-prs-attention:
|
|
58
41
|
name: my-prs-attention
|
|
59
42
|
tool:
|
package/test/unit/poller.test.js
CHANGED
|
@@ -1013,5 +1013,25 @@ describe('poller.js', () => {
|
|
|
1013
1013
|
assert.strictEqual(result[0]._attention_label, 'PR');
|
|
1014
1014
|
assert.strictEqual(result[0]._has_attention, false);
|
|
1015
1015
|
});
|
|
1016
|
+
|
|
1017
|
+
test('ignores known bots without [bot] suffix (e.g., linear)', async () => {
|
|
1018
|
+
const { computeAttentionLabels } = await import('../../service/poller.js');
|
|
1019
|
+
|
|
1020
|
+
const items = [{
|
|
1021
|
+
number: 123,
|
|
1022
|
+
title: 'Test PR',
|
|
1023
|
+
user: { login: 'author' },
|
|
1024
|
+
_mergeable: 'MERGEABLE',
|
|
1025
|
+
_comments: [
|
|
1026
|
+
// Linear bot posts linkback comments without [bot] suffix
|
|
1027
|
+
{ user: { login: 'linear', type: 'User' }, body: '<!-- linear-linkback -->' }
|
|
1028
|
+
]
|
|
1029
|
+
}];
|
|
1030
|
+
|
|
1031
|
+
const result = computeAttentionLabels(items, {});
|
|
1032
|
+
|
|
1033
|
+
assert.strictEqual(result[0]._attention_label, 'PR');
|
|
1034
|
+
assert.strictEqual(result[0]._has_attention, false);
|
|
1035
|
+
});
|
|
1016
1036
|
});
|
|
1017
1037
|
});
|
|
@@ -679,24 +679,6 @@ sources:
|
|
|
679
679
|
assert.ok(sources[0].tool.command.includes('--review-requested=@me'), 'command should include review-requested filter');
|
|
680
680
|
});
|
|
681
681
|
|
|
682
|
-
test('expands github/my-prs-feedback preset', async () => {
|
|
683
|
-
writeFileSync(configPath, `
|
|
684
|
-
sources:
|
|
685
|
-
- preset: github/my-prs-feedback
|
|
686
|
-
`);
|
|
687
|
-
|
|
688
|
-
const { loadRepoConfig, getSources } = await import('../../service/repo-config.js');
|
|
689
|
-
loadRepoConfig(configPath);
|
|
690
|
-
const sources = getSources();
|
|
691
|
-
|
|
692
|
-
assert.strictEqual(sources[0].name, 'my-prs-feedback');
|
|
693
|
-
// GitHub presets now use gh CLI instead of MCP
|
|
694
|
-
assert.ok(sources[0].tool.command.includes('--author=@me'), 'command should include author filter');
|
|
695
|
-
assert.ok(sources[0].tool.command.includes('comments:>0'), 'command should filter for PRs with comments');
|
|
696
|
-
// This preset includes updatedAt in reprocess_on to catch new commits
|
|
697
|
-
assert.deepStrictEqual(sources[0].reprocess_on, ['state', 'updatedAt']);
|
|
698
|
-
});
|
|
699
|
-
|
|
700
682
|
test('expands github/my-prs-attention preset', async () => {
|
|
701
683
|
writeFileSync(configPath, `
|
|
702
684
|
sources:
|
|
@@ -774,7 +756,6 @@ sources:
|
|
|
774
756
|
sources:
|
|
775
757
|
- preset: github/my-issues
|
|
776
758
|
- preset: github/review-requests
|
|
777
|
-
- preset: github/my-prs-feedback
|
|
778
759
|
- preset: github/my-prs-attention
|
|
779
760
|
`);
|
|
780
761
|
|
|
@@ -860,7 +841,6 @@ sources:
|
|
|
860
841
|
sources:
|
|
861
842
|
- preset: github/my-issues
|
|
862
843
|
- preset: github/review-requests
|
|
863
|
-
- preset: github/my-prs-feedback
|
|
864
844
|
- preset: github/my-prs-attention
|
|
865
845
|
`);
|
|
866
846
|
|
|
@@ -874,11 +854,8 @@ sources:
|
|
|
874
854
|
// review-requests: "Review: {title}"
|
|
875
855
|
assert.strictEqual(sources[1].session.name, 'Review: {title}', 'review-requests should prefix with Review:');
|
|
876
856
|
|
|
877
|
-
// my-prs-feedback: "Feedback: {title}"
|
|
878
|
-
assert.strictEqual(sources[2].session.name, 'Feedback: {title}', 'my-prs-feedback should prefix with Feedback:');
|
|
879
|
-
|
|
880
857
|
// my-prs-attention: "{_attention_label}: {title}" (dynamic based on detected conditions)
|
|
881
|
-
assert.ok(sources[
|
|
858
|
+
assert.ok(sources[2].session.name.includes('_attention_label'), 'my-prs-attention should use dynamic label');
|
|
882
859
|
});
|
|
883
860
|
|
|
884
861
|
test('linear preset includes session name', async () => {
|