yaic 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.claude/agents/ralph-qa.md +101 -0
- data/.claude/ralph/bin/dump-pid.sh +3 -0
- data/.claude/ralph/bin/kill-claude +6 -0
- data/.claude/ralph/bin/start-ralph +44 -0
- data/.claude/ralph/bin/stop-hook.sh +9 -0
- data/.claude/ralph/bin/stop-ralph +17 -0
- data/.claude/ralph/prompt.md +218 -0
- data/.claude/settings.json +26 -0
- data/.gitmodules +3 -0
- data/CLAUDE.md +65 -0
- data/README.md +106 -17
- data/Rakefile +8 -0
- data/devenv.nix +1 -0
- data/docs/agents/data-model.md +150 -0
- data/docs/agents/ralph/features/01-message-parsing.md.done +160 -0
- data/docs/agents/ralph/features/01-tcpsocket-refactor.md.done +109 -0
- data/docs/agents/ralph/features/02-connection-socket.md.done +138 -0
- data/docs/agents/ralph/features/02-simplified-client-api.md.done +306 -0
- data/docs/agents/ralph/features/03-registration.md.done +147 -0
- data/docs/agents/ralph/features/04-ping-pong.md.done +109 -0
- data/docs/agents/ralph/features/05-event-system.md.done +167 -0
- data/docs/agents/ralph/features/06-privmsg-notice.md.done +163 -0
- data/docs/agents/ralph/features/07-join-part.md.done +190 -0
- data/docs/agents/ralph/features/08-quit.md.done +118 -0
- data/docs/agents/ralph/features/09-nick-change.md.done +109 -0
- data/docs/agents/ralph/features/10-topic.md.done +145 -0
- data/docs/agents/ralph/features/11-kick.md.done +122 -0
- data/docs/agents/ralph/features/12-names.md.done +124 -0
- data/docs/agents/ralph/features/13-mode.md.done +174 -0
- data/docs/agents/ralph/features/14-who-whois.md.done +188 -0
- data/docs/agents/ralph/features/15-client-api.md.done +180 -0
- data/docs/agents/ralph/features/16-ssl-test-infrastructure.md.done +50 -0
- data/docs/agents/ralph/features/17-github-actions-ci.md.done +70 -0
- data/docs/agents/ralph/features/18-brakeman-security-scanning.md.done +67 -0
- data/docs/agents/ralph/features/19-fix-qa.md.done +73 -0
- data/docs/agents/ralph/features/20-test-optimization.md.done +70 -0
- data/docs/agents/ralph/features/21-test-parallelization.md.done +56 -0
- data/docs/agents/ralph/features/22-wait-until-pattern.md.done +90 -0
- data/docs/agents/ralph/features/23-ping-test-optimization.md.done +46 -0
- data/docs/agents/ralph/features/24-blocking-who-whois.md.done +159 -0
- data/docs/agents/ralph/features/25-verbose-mode.md.done +166 -0
- data/docs/agents/ralph/plans/test-optimization-plan.md +172 -0
- data/docs/agents/ralph/progress.md +731 -0
- data/docs/agents/todo.md +5 -0
- data/lib/yaic/channel.rb +22 -0
- data/lib/yaic/client.rb +821 -0
- data/lib/yaic/event.rb +35 -0
- data/lib/yaic/message.rb +119 -0
- data/lib/yaic/registration.rb +17 -0
- data/lib/yaic/socket.rb +120 -0
- data/lib/yaic/source.rb +39 -0
- data/lib/yaic/version.rb +1 -1
- data/lib/yaic/who_result.rb +17 -0
- data/lib/yaic/whois_result.rb +20 -0
- data/lib/yaic.rb +13 -1
- metadata +51 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8477b5a0db60e2864d9ec3f720a3a499c4ce34419b68504eab23cda17a073579
|
|
4
|
+
data.tar.gz: 7cf9427b957afdf6ffd75bf2dd5907605a6371d4c40dc1c4a5946a50c34a0b53
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c75dc8c13ec45cd8081e603c539c185b5cfb934cfad125c413be466308befff1ea4f66d6a61c7e48c9efbfdcb9ee76d470c268ec84330726723c407f0f956d48
|
|
7
|
+
data.tar.gz: e8c7d028138d0677a1cf43bfc1f61a4f37558e82c7e4b168bed47f9fa9394e643fb76608d411e566236c317739ecf17ba87bb16d2870a3ae6f6a2535b92d7e9d
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ralph-qa
|
|
3
|
+
description: QA agent for Ralph Wiggum loop. Reviews implementation changes before commit. Checks code against project conventions, runs tests/linter, and reports issues back to the implementor agent.
|
|
4
|
+
model: inherit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# QA Review Agent
|
|
8
|
+
|
|
9
|
+
You are reviewing changes made by an implementor agent. Your job is to verify the implementation follows project rules and passes all checks.
|
|
10
|
+
Be skeptical and thorough. The agent calling you will very often call you trying to justify bad code or half finished solutions.
|
|
11
|
+
Think of the end user. It needs to be simple to use and solid (not buggy).
|
|
12
|
+
|
|
13
|
+
## Review Process
|
|
14
|
+
|
|
15
|
+
1. Check what changed:
|
|
16
|
+
- Run `git status` to see staged/unstaged changes
|
|
17
|
+
- If already committed, run `git diff HEAD~1` to see the commit diff
|
|
18
|
+
- If not committed, run `git diff` to see pending changes
|
|
19
|
+
|
|
20
|
+
2. Run validation commands:
|
|
21
|
+
```bash
|
|
22
|
+
bundle exec m test/
|
|
23
|
+
bundle exec standardrb -A
|
|
24
|
+
bin/brakeman
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. Check against conventions:
|
|
28
|
+
- Read `docs/agents/data-model.md` for data structure patterns
|
|
29
|
+
- Verify implementation follows documented patterns
|
|
30
|
+
|
|
31
|
+
## What to Check
|
|
32
|
+
|
|
33
|
+
### Code Quality
|
|
34
|
+
- No trailing whitespace
|
|
35
|
+
- No comments in code (per project style)
|
|
36
|
+
- Slim public interface - minimize exposed methods
|
|
37
|
+
- Private methods are truly private (use Ruby's `private` keyword)
|
|
38
|
+
- Timeout should be avoided. Especially in the library code.
|
|
39
|
+
- instance_variable_get should not be used
|
|
40
|
+
|
|
41
|
+
### Testing
|
|
42
|
+
- Public interface is tested thoroughly
|
|
43
|
+
- Tests verify RFC compliance where applicable
|
|
44
|
+
- Tests use minitest assertions properly
|
|
45
|
+
- Integration tests use inspircd docker container where relevant
|
|
46
|
+
- Unit tests are fast and isolated
|
|
47
|
+
- Be HIGHLY skeptical of skipped tests. Make sure the agent didn't skip test needlessly. If the agent skipped a test because it is not able to implement the test it should reach out with the ask question tool. Skipping test should be for feature we're gonna implement later. Not because it's hard to make the test pass or some dependency is missing. If a test doesn't pass because say a dependency is unreachable, the agent should ask the user a question using the ask question tool.
|
|
48
|
+
- Assume the test server is already running unless you see the test fail because of it.
|
|
49
|
+
|
|
50
|
+
### Test Optimization Specific (for test speedup tasks)
|
|
51
|
+
- **CRITICAL**: No tests should be removed or skipped to make things faster
|
|
52
|
+
- Test count must remain the same or increase
|
|
53
|
+
- Assertions should not be weakened
|
|
54
|
+
- If a test is refactored, it must test the same behavior
|
|
55
|
+
- Ideally no sleep or timeout. If they can be removed without hurting readability that's preferable.
|
|
56
|
+
- Any mocking introduced must still test the same behavior
|
|
57
|
+
- Verify the optimization actually reduces test time
|
|
58
|
+
|
|
59
|
+
### RFC Compliance
|
|
60
|
+
- Message parsing follows IRC protocol spec
|
|
61
|
+
- Numeric codes match documented values
|
|
62
|
+
- Event names and payloads match feature specs
|
|
63
|
+
- Edge cases from RFC are handled (empty params, special chars)
|
|
64
|
+
- If you need to check the RFC you can find it here: docs/agents/rfc/modern-irc/
|
|
65
|
+
|
|
66
|
+
### Linting
|
|
67
|
+
- standardrb passes with no errors
|
|
68
|
+
- Run with `-A` to auto-fix where possible
|
|
69
|
+
|
|
70
|
+
### Security
|
|
71
|
+
- brakeman passes with no warnings
|
|
72
|
+
- Run `bin/brakeman` to check for security issues
|
|
73
|
+
|
|
74
|
+
## Running Tests
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
bundle exec m test/ # Run all tests
|
|
78
|
+
bundle exec m test/unit/ # Run unit tests only
|
|
79
|
+
bundle exec m test/integration/ # Run integration tests only
|
|
80
|
+
bundle exec m test/file_test.rb # Run specific file
|
|
81
|
+
bundle exec m test/file_test.rb:42 # Run specific test by line
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Tips
|
|
85
|
+
- While the test might not be parallelizable yet, it should be fine to run test, linting and security check in parallel.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
## Reporting Back
|
|
90
|
+
|
|
91
|
+
Report to the implementor agent:
|
|
92
|
+
|
|
93
|
+
**If compliant:**
|
|
94
|
+
> QA PASSED. All checks passed, code follows conventions.
|
|
95
|
+
|
|
96
|
+
**If issues found:**
|
|
97
|
+
> QA FAILED. Issues found:
|
|
98
|
+
> - [Issue 1]: [Description]. [How to fix].
|
|
99
|
+
> - [Issue 2]: [Description]. [How to fix].
|
|
100
|
+
>
|
|
101
|
+
> Required fixes: [list specific changes needed]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
trap '' TERM HUP
|
|
5
|
+
|
|
6
|
+
export CLAUDE_PROJECT_DIR="$(pwd)"
|
|
7
|
+
RALPH_DIR=".claude/ralph"
|
|
8
|
+
PROMPT_FILE="$RALPH_DIR/prompt.md"
|
|
9
|
+
CONTROL_FILE="$RALPH_DIR/loop-control"
|
|
10
|
+
|
|
11
|
+
if [ -n "$1" ]; then
|
|
12
|
+
PROMPT_OVERRIDE="$1"
|
|
13
|
+
elif [ ! -f "$PROMPT_FILE" ]; then
|
|
14
|
+
echo "Error: $PROMPT_FILE not found"
|
|
15
|
+
echo "Usage: start-ralph [prompt]"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
touch "$CONTROL_FILE"
|
|
20
|
+
|
|
21
|
+
FEATURES_DIR="docs/agents/ralph/features"
|
|
22
|
+
|
|
23
|
+
while [ -f "$CONTROL_FILE" ]; do
|
|
24
|
+
REMAINING=$(find "$FEATURES_DIR" -name "*.md" ! -name "*.md.done" 2>/dev/null | wc -l | tr -d ' ')
|
|
25
|
+
if [ "$REMAINING" -eq 0 ]; then
|
|
26
|
+
echo "All features complete. Exiting loop."
|
|
27
|
+
rm -f "$CONTROL_FILE"
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
echo "Features remaining: $REMAINING"
|
|
32
|
+
|
|
33
|
+
if [ -n "$PROMPT_OVERRIDE" ]; then
|
|
34
|
+
PROMPT_CONTENT="$PROMPT_OVERRIDE"
|
|
35
|
+
else
|
|
36
|
+
PROMPT_CONTENT=$(cat "$PROMPT_FILE")
|
|
37
|
+
fi
|
|
38
|
+
|
|
39
|
+
echo "Starting new session..."
|
|
40
|
+
RALPH_WIGGUM_LOOP=true claude --permission-mode acceptEdits "$PROMPT_CONTENT" || true
|
|
41
|
+
|
|
42
|
+
echo ""
|
|
43
|
+
echo "Session ended. Checking if loop should continue..."
|
|
44
|
+
done
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
[ "$RALPH_WIGGUM_LOOP" != "true" ] && exit 0
|
|
3
|
+
cat << 'JSON'
|
|
4
|
+
{
|
|
5
|
+
"decision": "block",
|
|
6
|
+
"continue": true,
|
|
7
|
+
"reason": "If you are blocked, confused, or need clarification, DO NOT EXIT OR STOP WORKING - use the AskUserQuestion tool and wait for a response. You cannot exit or stop until you have COMPLETED a feature or the user quit for you. If you have completed a feature (tests pass, QA passed, feature marked .done), exit by calling .claude/ralph/bin/kill-claude."
|
|
8
|
+
}
|
|
9
|
+
JSON
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
CONTROL_FILE=".claude/ralph/loop-control"
|
|
3
|
+
PID_FILE=".claude/ralph/pid"
|
|
4
|
+
|
|
5
|
+
if [ ! -f "$CONTROL_FILE" ]; then
|
|
6
|
+
echo "No running loop found."
|
|
7
|
+
exit 1
|
|
8
|
+
fi
|
|
9
|
+
|
|
10
|
+
rm "$CONTROL_FILE"
|
|
11
|
+
|
|
12
|
+
if [ -f "$PID_FILE" ]; then
|
|
13
|
+
kill $(cat "$PID_FILE") 2>/dev/null
|
|
14
|
+
rm -f "$PID_FILE"
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
echo "Loop stopped."
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Feature Implementor
|
|
2
|
+
|
|
3
|
+
You are implementing features for YAIC (Yet Another IRC Client), a low-level Ruby IRC client library. Work through features one at a time, following the specs exactly.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
EXIT_SCRIPT: .claude/ralph/bin/kill-claude
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Project Context
|
|
12
|
+
|
|
13
|
+
- **Data model**: See `docs/agents/data-model.md`
|
|
14
|
+
- **RFC reference**: See `docs/agents/rfc/modern-irc/` (large, query specific files as needed)
|
|
15
|
+
- **Features**: See `docs/agents/ralph/features/`
|
|
16
|
+
- **Progress**: See `docs/agents/ralph/progress.md`
|
|
17
|
+
|
|
18
|
+
## Running Things
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bundle exec m test/
|
|
22
|
+
bundle exec m test/unit/
|
|
23
|
+
bundle exec m test/integration/
|
|
24
|
+
bundle exec m test/file_test.rb
|
|
25
|
+
bundle exec m test/file_test.rb:42
|
|
26
|
+
|
|
27
|
+
bundle exec standardrb -A
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Integration Test Server
|
|
31
|
+
|
|
32
|
+
For integration tests, use the inspircd Docker container:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
docker run -d --name inspircd -p 6667:6667 -p 6697:6697 inspircd/inspircd-docker
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Configure tests to connect to localhost:6667 (plain) or localhost:6697 (SSL).
|
|
39
|
+
|
|
40
|
+
**IMPORTANT**: Assume the IRC server is already running. Do NOT check if it's running before running tests. If tests fail with connection errors suggesting the server is not running, use `AskUserQuestion` to ask the user if the server is running.
|
|
41
|
+
|
|
42
|
+
## Project Style
|
|
43
|
+
|
|
44
|
+
- No trailing whitespace
|
|
45
|
+
- No comments in code
|
|
46
|
+
- Slim public interface - minimize exposed methods
|
|
47
|
+
- Use Ruby's `private` keyword for internal methods
|
|
48
|
+
- Use standardrb for linting (run with -A to auto-fix)
|
|
49
|
+
- UTF-8 encoding throughout
|
|
50
|
+
|
|
51
|
+
## Workflow
|
|
52
|
+
|
|
53
|
+
### 1. Check Progress
|
|
54
|
+
|
|
55
|
+
Read `docs/agents/ralph/progress.md` to see:
|
|
56
|
+
- What's been done
|
|
57
|
+
- What to work on next
|
|
58
|
+
- Any notes from previous sessions
|
|
59
|
+
|
|
60
|
+
### 2. Pick a Feature
|
|
61
|
+
|
|
62
|
+
Choose from `.claude/ralph/features/`. Pick a `.md` file (not `.md.done`) whose dependencies are satisfied.
|
|
63
|
+
|
|
64
|
+
If unclear which to pick, check `docs/agents/ralph/progress.md` for suggestions.
|
|
65
|
+
|
|
66
|
+
### 3. Implement the Feature
|
|
67
|
+
|
|
68
|
+
Read the feature spec thoroughly. It contains:
|
|
69
|
+
- Description of the behavior
|
|
70
|
+
- Models/data involved
|
|
71
|
+
- Test descriptions
|
|
72
|
+
- Implementation notes
|
|
73
|
+
- Dependencies
|
|
74
|
+
|
|
75
|
+
Implement:
|
|
76
|
+
1. Write tests first (based on spec's test descriptions)
|
|
77
|
+
2. Write code to make tests pass
|
|
78
|
+
3. Run tests to verify
|
|
79
|
+
4. Run linter
|
|
80
|
+
|
|
81
|
+
### 4. QA Review (REQUIRED)
|
|
82
|
+
|
|
83
|
+
**A feature CANNOT be marked as done unless QA approves it.**
|
|
84
|
+
|
|
85
|
+
After tests pass, run the QA agent:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
claude --agent-prompt .claude/agents/ralph-qa.md
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Wait for QA to complete. The QA agent will review your implementation and either:
|
|
92
|
+
- **APPROVE**: You may proceed to commit and mark complete
|
|
93
|
+
- **FAIL**: You must fix the issues and re-run QA
|
|
94
|
+
|
|
95
|
+
**If QA fails:**
|
|
96
|
+
1. Read the QA feedback carefully
|
|
97
|
+
2. Fix all issues identified
|
|
98
|
+
3. Run tests again
|
|
99
|
+
4. Re-run the QA agent
|
|
100
|
+
5. Repeat until QA approves
|
|
101
|
+
|
|
102
|
+
Do NOT proceed to commit until QA has approved the implementation.
|
|
103
|
+
|
|
104
|
+
### 5. Mark Complete
|
|
105
|
+
|
|
106
|
+
When feature is done, tests pass, and **QA has approved**:
|
|
107
|
+
|
|
108
|
+
1. Rename the feature file:
|
|
109
|
+
```bash
|
|
110
|
+
mv docs/agents/ralph/features/feature-name.md docs/agents/ralph/features/feature-name.md.done
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
2. Update `docs/agents/ralph/progress.md`:
|
|
114
|
+
- Add entry to Session History
|
|
115
|
+
- Update Current State
|
|
116
|
+
- Suggest next feature
|
|
117
|
+
|
|
118
|
+
3. Commit your changes:
|
|
119
|
+
```bash
|
|
120
|
+
git add -A
|
|
121
|
+
git commit --no-gpg-sign -m "Implement [feature-name]"
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**CRITICAL: Always commit before exiting. Never exit without committing your work.**
|
|
125
|
+
|
|
126
|
+
### 6. Exit
|
|
127
|
+
|
|
128
|
+
**ONLY after QA has approved and the feature is marked complete**, exit by running:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
.claude/ralph/bin/kill-claude
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**IMPORTANT**: The kill script must be run with the sandbox disabled (`dangerouslyDisableSandbox: true`) because it needs to send signals to processes.
|
|
135
|
+
|
|
136
|
+
The loop will restart you with fresh context.
|
|
137
|
+
|
|
138
|
+
**CRITICAL: NEVER call the exit script if you are blocked or have a question. Use `AskUserQuestion` instead and wait for the human to respond.**
|
|
139
|
+
|
|
140
|
+
## Rules
|
|
141
|
+
|
|
142
|
+
### Do
|
|
143
|
+
|
|
144
|
+
- Follow the spec exactly
|
|
145
|
+
- Write tests based on the spec's test descriptions
|
|
146
|
+
- Use `AskUserQuestion` if something is unclear or blocking
|
|
147
|
+
- Update progress.md with useful notes for future sessions
|
|
148
|
+
- Exit after each feature (keeps context fresh)
|
|
149
|
+
- Test for RFC compliance
|
|
150
|
+
|
|
151
|
+
### Don't
|
|
152
|
+
|
|
153
|
+
- Change test assertions without asking first
|
|
154
|
+
- Skip tests
|
|
155
|
+
- Implement features out of dependency order
|
|
156
|
+
- Stay in one session for multiple features (exit and restart)
|
|
157
|
+
- Exit without updating progress.md
|
|
158
|
+
- Exit without committing your work
|
|
159
|
+
- Add comments to code
|
|
160
|
+
- Create documentation files unless explicitly asked
|
|
161
|
+
- Mark a feature complete without QA approval
|
|
162
|
+
- Skip QA or proceed after QA failure without fixing issues
|
|
163
|
+
- **NEVER call the exit script when blocked or confused - use AskUserQuestion instead**
|
|
164
|
+
|
|
165
|
+
## If Blocked
|
|
166
|
+
|
|
167
|
+
If you can't proceed:
|
|
168
|
+
1. Use `AskUserQuestion` to ask the human
|
|
169
|
+
2. Wait for their response
|
|
170
|
+
3. Continue working after they answer
|
|
171
|
+
|
|
172
|
+
**DO NOT exit when blocked. DO NOT call the kill script. Stay in the session and use AskUserQuestion.**
|
|
173
|
+
|
|
174
|
+
## Session Notes Format
|
|
175
|
+
|
|
176
|
+
When updating progress.md, use this format:
|
|
177
|
+
|
|
178
|
+
```markdown
|
|
179
|
+
### Session [DATE]
|
|
180
|
+
|
|
181
|
+
**Feature**: [feature-name]
|
|
182
|
+
**Status**: Completed | Blocked | In Progress
|
|
183
|
+
|
|
184
|
+
**What was done**:
|
|
185
|
+
- [bullet points]
|
|
186
|
+
|
|
187
|
+
**Notes for next session**:
|
|
188
|
+
- [anything important to know]
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## File Structure
|
|
192
|
+
|
|
193
|
+
Expected project structure after implementation:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
lib/
|
|
197
|
+
yaic.rb
|
|
198
|
+
yaic/
|
|
199
|
+
version.rb
|
|
200
|
+
client.rb
|
|
201
|
+
message.rb
|
|
202
|
+
source.rb
|
|
203
|
+
socket.rb
|
|
204
|
+
event.rb
|
|
205
|
+
channel.rb
|
|
206
|
+
...
|
|
207
|
+
|
|
208
|
+
test/
|
|
209
|
+
test_helper.rb
|
|
210
|
+
unit/
|
|
211
|
+
message_test.rb
|
|
212
|
+
source_test.rb
|
|
213
|
+
...
|
|
214
|
+
integration/
|
|
215
|
+
connection_test.rb
|
|
216
|
+
channel_test.rb
|
|
217
|
+
...
|
|
218
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/ralph/bin/dump-pid.sh"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"Stop": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/ralph/bin/stop-hook.sh"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
data/.gitmodules
ADDED
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
Yaic (Yet Another IRC Client) is a Ruby gem that provides an IRC client library. It handles IRC protocol messaging, event handling, channel management, and connection state.
|
|
8
|
+
|
|
9
|
+
**Minimum Ruby version: 3.2**
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### Testing
|
|
14
|
+
```bash
|
|
15
|
+
rake test # Run all tests
|
|
16
|
+
rake test_unit # Run unit tests only
|
|
17
|
+
rake test_integration # Run integration tests only
|
|
18
|
+
m test/unit/message_test.rb:42 # Run single test by line number
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Linting
|
|
22
|
+
```bash
|
|
23
|
+
bundle exec standardrb -A # Run linter with auto-fix
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Security
|
|
27
|
+
```bash
|
|
28
|
+
bin/brakeman # Run security scanner
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Integration Test Setup
|
|
32
|
+
Integration tests require a running IRC server (InspIRCd via Docker):
|
|
33
|
+
```bash
|
|
34
|
+
bin/start-irc-server # Start IRC server container (ports 6667/6697)
|
|
35
|
+
bin/stop-irc-server # Stop IRC server container
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Architecture
|
|
39
|
+
|
|
40
|
+
### Core Components
|
|
41
|
+
|
|
42
|
+
- **Client** (`lib/yaic/client.rb`): Main IRC client class. Manages connection state, handles incoming IRC messages, maintains channel/user state, and provides event emission system with `on`/`off` handlers.
|
|
43
|
+
|
|
44
|
+
- **Message** (`lib/yaic/message.rb`): Parses and serializes IRC protocol messages (source, command, params).
|
|
45
|
+
|
|
46
|
+
- **Socket** (`lib/yaic/socket.rb`): TCP socket wrapper with SSL support.
|
|
47
|
+
|
|
48
|
+
- **Channel** (`lib/yaic/channel.rb`): Tracks channel state including users, modes, and topic.
|
|
49
|
+
|
|
50
|
+
- **Event** (`lib/yaic/event.rb`): Event objects emitted for IRC events (`:message`, `:join`, `:part`, etc.).
|
|
51
|
+
|
|
52
|
+
### Event System
|
|
53
|
+
|
|
54
|
+
Client uses an event-based model:
|
|
55
|
+
```ruby
|
|
56
|
+
client.on(:message) { |event| handle_message(event) }
|
|
57
|
+
client.on(:join) { |event| handle_join(event) }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Events: `:raw`, `:connect`, `:disconnect`, `:message`, `:notice`, `:join`, `:part`, `:quit`, `:kick`, `:nick`, `:topic`, `:mode`, `:names`, `:who`, `:whois`, `:error`
|
|
61
|
+
|
|
62
|
+
### Test Structure
|
|
63
|
+
|
|
64
|
+
- `test/unit/` - Unit tests mocking the socket layer
|
|
65
|
+
- `test/integration/` - Integration tests against real IRC server (InspIRCd)
|
data/README.md
CHANGED
|
@@ -1,39 +1,128 @@
|
|
|
1
1
|
# Yaic
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/yaic`. To experiment with that code, run `bin/console` for an interactive prompt.
|
|
3
|
+
Yet Another IRC Client - A Ruby IRC client library.
|
|
6
4
|
|
|
7
5
|
## Installation
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
Add to your Gemfile:
|
|
8
|
+
|
|
9
|
+
```ruby
|
|
10
|
+
gem "yaic"
|
|
11
|
+
```
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
Or install directly:
|
|
12
14
|
|
|
13
15
|
```bash
|
|
14
|
-
|
|
16
|
+
gem install yaic
|
|
15
17
|
```
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
## Quick Start
|
|
18
20
|
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
+
```ruby
|
|
22
|
+
require "yaic"
|
|
23
|
+
|
|
24
|
+
client = Yaic::Client.new(
|
|
25
|
+
server: "irc.libera.chat",
|
|
26
|
+
port: 6697,
|
|
27
|
+
ssl: true,
|
|
28
|
+
nickname: "mynick",
|
|
29
|
+
username: "myuser",
|
|
30
|
+
realname: "My Real Name"
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
client.on(:message) { |event| puts "#{event.source.nick}: #{event.text}" }
|
|
34
|
+
|
|
35
|
+
client.connect
|
|
36
|
+
client.join("#ruby")
|
|
37
|
+
client.privmsg("#ruby", "Hello!")
|
|
38
|
+
client.quit
|
|
21
39
|
```
|
|
22
40
|
|
|
23
|
-
##
|
|
41
|
+
## Events
|
|
24
42
|
|
|
25
|
-
|
|
43
|
+
Subscribe to events with `on`:
|
|
26
44
|
|
|
27
|
-
|
|
45
|
+
```ruby
|
|
46
|
+
client.on(:message) { |event| ... }
|
|
47
|
+
client.on(:join) { |event| ... }
|
|
48
|
+
```
|
|
28
49
|
|
|
29
|
-
|
|
50
|
+
Unsubscribe with `off`:
|
|
30
51
|
|
|
31
|
-
|
|
52
|
+
```ruby
|
|
53
|
+
client.off(:message)
|
|
54
|
+
```
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
| Event | Attributes |
|
|
57
|
+
|-------|------------|
|
|
58
|
+
| `:raw` | `message` - Raw IRC message |
|
|
59
|
+
| `:connect` | `server` - Server name |
|
|
60
|
+
| `:disconnect` | - |
|
|
61
|
+
| `:message` | `source`, `target`, `text` |
|
|
62
|
+
| `:notice` | `source`, `target`, `text` |
|
|
63
|
+
| `:join` | `channel`, `user` |
|
|
64
|
+
| `:part` | `channel`, `user`, `reason` |
|
|
65
|
+
| `:quit` | `user`, `reason` |
|
|
66
|
+
| `:kick` | `channel`, `user`, `by`, `reason` |
|
|
67
|
+
| `:nick` | `old_nick`, `new_nick` |
|
|
68
|
+
| `:topic` | `channel`, `topic`, `setter` |
|
|
69
|
+
| `:mode` | `target`, `modes`, `args` |
|
|
70
|
+
| `:names` | `channel`, `users` |
|
|
71
|
+
| `:who` | `channel`, `user`, `host`, `server`, `nick`, `away`, `realname` |
|
|
72
|
+
| `:whois` | `result` (WhoisResult object) |
|
|
73
|
+
| `:error` | `numeric`, `message` |
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
client.connect # Connect and register
|
|
79
|
+
client.quit("Goodbye") # Disconnect with optional message
|
|
80
|
+
|
|
81
|
+
client.join("#channel") # Join a channel
|
|
82
|
+
client.join("#channel", "key") # Join with key
|
|
83
|
+
client.part("#channel") # Leave a channel
|
|
84
|
+
client.part("#channel", "reason") # Leave with reason
|
|
85
|
+
|
|
86
|
+
client.privmsg("#channel", "Hi") # Send message to channel
|
|
87
|
+
client.privmsg("nick", "Hello") # Send private message
|
|
88
|
+
client.msg("#channel", "Hi") # Alias for privmsg
|
|
89
|
+
client.notice("#channel", "Info") # Send notice
|
|
90
|
+
|
|
91
|
+
client.nick("newnick") # Change nickname
|
|
92
|
+
client.topic("#channel") # Request topic
|
|
93
|
+
client.topic("#channel", "New") # Set topic
|
|
94
|
+
client.kick("#channel", "nick") # Kick user
|
|
95
|
+
client.mode("#channel", "+o", "nick") # Set mode
|
|
96
|
+
|
|
97
|
+
client.who("#channel") # WHO query
|
|
98
|
+
client.whois("nick") # WHOIS query
|
|
99
|
+
client.names("#channel") # NAMES query
|
|
100
|
+
```
|
|
34
101
|
|
|
35
|
-
|
|
102
|
+
## Threading
|
|
103
|
+
|
|
104
|
+
The client spawns a background thread to read incoming messages. Event handlers are called from this thread. All public methods are thread-safe.
|
|
105
|
+
|
|
106
|
+
## Channel State
|
|
107
|
+
|
|
108
|
+
Access joined channels:
|
|
109
|
+
|
|
110
|
+
```ruby
|
|
111
|
+
client.channels["#ruby"] # => Channel object
|
|
112
|
+
client.channels["#ruby"].users # => {"nick" => Set[:op, :voice], ...}
|
|
113
|
+
client.channels["#ruby"].topic # => "Ruby programming"
|
|
114
|
+
client.channels["#ruby"].modes # => {:moderated => true, ...}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Development
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
rake test # Run all tests
|
|
121
|
+
rake test_unit # Run unit tests only
|
|
122
|
+
rake test_integration # Run integration tests (requires IRC server)
|
|
123
|
+
bundle exec standardrb -A # Run linter
|
|
124
|
+
```
|
|
36
125
|
|
|
37
126
|
## License
|
|
38
127
|
|
|
39
|
-
|
|
128
|
+
MIT License
|
data/Rakefile
CHANGED
|
@@ -5,6 +5,14 @@ require "minitest/test_task"
|
|
|
5
5
|
|
|
6
6
|
Minitest::TestTask.create
|
|
7
7
|
|
|
8
|
+
Minitest::TestTask.create(:test_unit) do |t|
|
|
9
|
+
t.test_globs = ["test/unit/**/*_test.rb", "test/test_yaic.rb"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
Minitest::TestTask.create(:test_integration) do |t|
|
|
13
|
+
t.test_globs = ["test/integration/**/*_test.rb"]
|
|
14
|
+
end
|
|
15
|
+
|
|
8
16
|
require "standard/rake"
|
|
9
17
|
|
|
10
18
|
task default: %i[test standard]
|