Skip to content

Commit 2fb1d5f

Browse files
konardclaude
andcommitted
Implement rubber duck debugging bot for issue #142
Added RubberDuckTrigger and RubberDuckDialogTrigger to provide interactive debugging assistance via GitHub issues. Features: - Responds to trigger words: "help", "help me", "sos", "помощь", "помогите", "помогите мне", "спасите" - Asks if user has a problem with code in both English and Russian - Provides structured debugging guidance when user responds "yes" or "да" - Follows rubber duck debugging methodology with step-by-step problem solving 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 327fe0d commit 2fb1d5f

File tree

3 files changed

+209
-1
lines changed

3 files changed

+209
-1
lines changed

csharp/Platform.Bot/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private static async Task<int> Main(string[] args)
9595
var dbContext = new FileStorage(databaseFilePath?.FullName ?? new TemporaryFile().Filename);
9696
Console.WriteLine($"Bot has been started. {Environment.NewLine}Press CTRL+C to close");
9797
var githubStorage = new GitHubStorage(githubUserName, githubApiToken, githubApplicationName);
98-
var issueTracker = new IssueTracker(githubStorage, new HelloWorldTrigger(githubStorage, dbContext, fileSetName), new OrganizationLastMonthActivityTrigger(githubStorage), new LastCommitActivityTrigger(githubStorage), new AdminAuthorIssueTriggerDecorator(new ProtectDefaultBranchTrigger(githubStorage), githubStorage), new AdminAuthorIssueTriggerDecorator(new ChangeOrganizationRepositoriesDefaultBranchTrigger(githubStorage, dbContext), githubStorage), new AdminAuthorIssueTriggerDecorator(new ChangeOrganizationPullRequestsBaseBranchTrigger(githubStorage, dbContext), githubStorage));
98+
var issueTracker = new IssueTracker(githubStorage, new HelloWorldTrigger(githubStorage, dbContext, fileSetName), new OrganizationLastMonthActivityTrigger(githubStorage), new LastCommitActivityTrigger(githubStorage), new RubberDuckTrigger(githubStorage), new RubberDuckDialogTrigger(githubStorage), new AdminAuthorIssueTriggerDecorator(new ProtectDefaultBranchTrigger(githubStorage), githubStorage), new AdminAuthorIssueTriggerDecorator(new ChangeOrganizationRepositoriesDefaultBranchTrigger(githubStorage, dbContext), githubStorage), new AdminAuthorIssueTriggerDecorator(new ChangeOrganizationPullRequestsBaseBranchTrigger(githubStorage, dbContext), githubStorage));
9999
var pullRequenstTracker = new PullRequestTracker(githubStorage, new MergeDependabotBumpsTrigger(githubStorage));
100100
var timestampTracker = new DateTimeTracker(githubStorage, new CreateAndSaveOrganizationRepositoriesMigrationTrigger(githubStorage, dbContext, Path.Combine(Directory.GetCurrentDirectory(), "/github-migrations")));
101101
var cancellation = new CancellationTokenSource();
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Interfaces;
4+
using Octokit;
5+
using Storage.Remote.GitHub;
6+
7+
namespace Platform.Bot.Triggers
8+
{
9+
using TContext = Issue;
10+
/// <summary>
11+
/// <para>
12+
/// Represents the rubber duck debugging dialog continuation trigger.
13+
/// </para>
14+
/// <para></para>
15+
/// </summary>
16+
/// <seealso cref="ITrigger{TContext}"/>
17+
internal class RubberDuckDialogTrigger : ITrigger<TContext>
18+
{
19+
private readonly GitHubStorage _storage;
20+
21+
/// <summary>
22+
/// <para>
23+
/// Initializes a new <see cref="RubberDuckDialogTrigger"/> instance.
24+
/// </para>
25+
/// <para></para>
26+
/// </summary>
27+
/// <param name="storage">
28+
/// <para>A git hub api.</para>
29+
/// <para></para>
30+
/// </param>
31+
public RubberDuckDialogTrigger(GitHubStorage storage)
32+
{
33+
this._storage = storage;
34+
}
35+
36+
/// <summary>
37+
/// <para>
38+
/// Actions the context.
39+
/// </para>
40+
/// <para></para>
41+
/// </summary>
42+
/// <param name="context">
43+
/// <para>The context.</para>
44+
/// <para></para>
45+
/// </param>
46+
public async Task Action(TContext context)
47+
{
48+
var debuggingGuide = $@"🦆 **Great! Let's debug together!**
49+
50+
I'm your rubber duck debugging assistant. Please follow these steps:
51+
52+
## Step 1: Describe Your Problem
53+
Please tell me:
54+
- **What are you trying to do?**
55+
- **What is happening instead?**
56+
- **What error messages (if any) are you seeing?**
57+
58+
## Step 2: Show Me The Code
59+
- Share the relevant code snippet
60+
- Include any error messages or unexpected output
61+
62+
## Step 3: Recent Changes
63+
- **What was the last thing you changed before this problem appeared?**
64+
- Have you tried undoing recent changes?
65+
66+
## Step 4: Let's Think Through This Together
67+
I'll help you by asking questions like:
68+
- What assumptions are you making about the code?
69+
- Can you trace through the code line by line?
70+
- Have you checked the most obvious things first?
71+
72+
## Step 5: Problem-Solving Techniques
73+
We can try:
74+
- Adding debug logging/print statements
75+
- Testing with simpler inputs
76+
- Checking documentation
77+
- Looking for similar examples
78+
79+
**🎯 Often, just explaining your problem step-by-step to me will help you spot the issue!**
80+
81+
Go ahead and describe your problem in detail. I'm listening! 👂";
82+
83+
await _storage.CreateIssueComment(context.Repository.Id, context.Number, debuggingGuide);
84+
}
85+
86+
/// <summary>
87+
/// <para>
88+
/// Determines whether this instance condition.
89+
/// </para>
90+
/// <para></para>
91+
/// </summary>
92+
/// <param name="context">
93+
/// <para>The context.</para>
94+
/// <para></para>
95+
/// </param>
96+
/// <returns>
97+
/// <para>The bool</para>
98+
/// <para></para>
99+
/// </returns>
100+
public async Task<bool> Condition(TContext context)
101+
{
102+
var title = context.Title.ToLower().Trim();
103+
return title == "yes" || title == "да";
104+
}
105+
}
106+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System;
2+
using System.Threading.Tasks;
3+
using Interfaces;
4+
using Octokit;
5+
using Storage.Remote.GitHub;
6+
7+
namespace Platform.Bot.Triggers
8+
{
9+
using TContext = Issue;
10+
/// <summary>
11+
/// <para>
12+
/// Represents the rubber duck debugging trigger.
13+
/// </para>
14+
/// <para></para>
15+
/// </summary>
16+
/// <seealso cref="ITrigger{TContext}"/>
17+
internal class RubberDuckTrigger : ITrigger<TContext>
18+
{
19+
private readonly GitHubStorage _storage;
20+
21+
/// <summary>
22+
/// <para>
23+
/// Initializes a new <see cref="RubberDuckTrigger"/> instance.
24+
/// </para>
25+
/// <para></para>
26+
/// </summary>
27+
/// <param name="storage">
28+
/// <para>A git hub api.</para>
29+
/// <para></para>
30+
/// </param>
31+
public RubberDuckTrigger(GitHubStorage storage)
32+
{
33+
this._storage = storage;
34+
}
35+
36+
/// <summary>
37+
/// <para>
38+
/// Actions the context.
39+
/// </para>
40+
/// <para></para>
41+
/// </summary>
42+
/// <param name="context">
43+
/// <para>The context.</para>
44+
/// <para></para>
45+
/// </param>
46+
public async Task Action(TContext context)
47+
{
48+
var openerQuestion = $@"🦆 **Rubber Duck Debugging Assistant**
49+
50+
Do you have problem with code?
51+
У вас проблема с кодом?
52+
53+
**Instructions:**
54+
- Reply with **""Yes""** or **""Да""** to start debugging session
55+
- I'll guide you through the problem-solving process step by step
56+
- Explaining your problem to me (the rubber duck) often helps you find the solution yourself!
57+
58+
**Common debugging steps I can help with:**
59+
1. Understanding the problem clearly
60+
2. Breaking down the problem into smaller parts
61+
3. Checking assumptions
62+
4. Reviewing recent changes
63+
5. Testing hypotheses
64+
6. Finding similar examples
65+
66+
Ready to debug? 🐛➡️✨";
67+
68+
await _storage.CreateIssueComment(context.Repository.Id, context.Number, openerQuestion);
69+
}
70+
71+
/// <summary>
72+
/// <para>
73+
/// Determines whether this instance condition.
74+
/// </para>
75+
/// <para></para>
76+
/// </summary>
77+
/// <param name="context">
78+
/// <para>The context.</para>
79+
/// <para></para>
80+
/// </param>
81+
/// <returns>
82+
/// <para>The bool</para>
83+
/// <para></para>
84+
/// </returns>
85+
public async Task<bool> Condition(TContext context)
86+
{
87+
var title = context.Title.ToLower().Trim();
88+
var triggerWords = new[]
89+
{
90+
"help",
91+
"help me",
92+
"sos",
93+
"помощь",
94+
"помогите",
95+
"помогите мне",
96+
"спасите"
97+
};
98+
99+
return Array.Exists(triggerWords, trigger => title == trigger);
100+
}
101+
}
102+
}

0 commit comments

Comments
 (0)