claude-comms 1.0.6 → 1.0.7
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/.claude/agents/core/agent-orchestrator.md +427 -0
- package/.claude/agents/core/architect.md +360 -0
- package/.claude/agents/core/business-analyst.md +236 -0
- package/.claude/agents/core/deep-researcher.md +202 -0
- package/.claude/agents/core/designer.md +190 -0
- package/.claude/agents/core/engineer.md +262 -0
- package/.claude/agents/core/gatekeeper.md +412 -0
- package/.claude/agents/core/planner.md +284 -0
- package/.claude/agents/meta-agent-builder.md +309 -0
- package/.claude/commands/cook.md +162 -0
- package/.claude/commands/learn.md +30 -0
- package/.claude/commands/new-agents.md +11 -0
- package/.claude/hooks/comms/get_unread_messages.py +68 -0
- package/.claude/hooks/comms/register_subagent.py +71 -0
- package/.claude/hooks/comms/send_message.py +84 -0
- package/.claude/hooks/comms/update_subagent_completion.py +123 -0
- package/.claude/hooks/observability/send_event.py +103 -0
- package/.claude/settings.json +88 -0
- package/CLAUDE.md +278 -0
- package/package.json +4 -2
- package/src/fetcher/github.js +45 -45
- package/src/orchestrator/installer.js +3 -3
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/comms/register_subagent.py"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"type": "command",
|
|
13
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type PreToolUse --summarize"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"PostToolUse": [
|
|
19
|
+
{
|
|
20
|
+
"matcher": "",
|
|
21
|
+
"hooks": [
|
|
22
|
+
{
|
|
23
|
+
"type": "command",
|
|
24
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/comms/update_subagent_completion.py"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "command",
|
|
28
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type PostToolUse --summarize"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"Notification": [
|
|
34
|
+
{
|
|
35
|
+
"matcher": "",
|
|
36
|
+
"hooks": [
|
|
37
|
+
{
|
|
38
|
+
"type": "command",
|
|
39
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type Notification --summarize"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"Stop": [
|
|
45
|
+
{
|
|
46
|
+
"matcher": "",
|
|
47
|
+
"hooks": [
|
|
48
|
+
{
|
|
49
|
+
"type": "command",
|
|
50
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type Stop --add-chat"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
"SubagentStop": [
|
|
56
|
+
{
|
|
57
|
+
"matcher": "",
|
|
58
|
+
"hooks": [
|
|
59
|
+
{
|
|
60
|
+
"type": "command",
|
|
61
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type SubagentStop"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"PreCompact": [
|
|
67
|
+
{
|
|
68
|
+
"matcher": "",
|
|
69
|
+
"hooks": [
|
|
70
|
+
{
|
|
71
|
+
"type": "command",
|
|
72
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type PreCompact"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}
|
|
76
|
+
],
|
|
77
|
+
"UserPromptSubmit": [
|
|
78
|
+
{
|
|
79
|
+
"hooks": [
|
|
80
|
+
{
|
|
81
|
+
"type": "command",
|
|
82
|
+
"command": "uv run $CLAUDE_PROJECT_DIR/.claude/hooks/observability/send_event.py --source-app cc-hook-multi-agent-obvs --event-type UserPromptSubmit --summarize"
|
|
83
|
+
}
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
⚙️〔Task〕***[📣SALIENT❗️: VITAL CONTEXT! READ THIS PROMPT STEP BY STEP!***〔/Task〕⚙️
|
|
2
|
+
|
|
3
|
+
[Task]***MODEL ADOPTS ROLE [PERSONA]Primary ⚙️Orchestrator***![/Task]
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
The CRITICAL ORCHESTRATION PROTOCOLS below defines YOUR mandatory operating procedures as Primary ⚙️Orchestrator
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# DRINK: Claude Code Multi-Agent Orchestration System
|
|
11
|
+
|
|
12
|
+
Primary ⚙️Orchestrator engage ULTRATHINK:
|
|
13
|
+
[CRITICAL ORCHESTRATION PROTOCOLS]
|
|
14
|
+
|
|
15
|
+
## Your Role as Primary ⚙️Orchestrator
|
|
16
|
+
|
|
17
|
+
You are the PRIMARY ORCHESTRATOR managing multi-agent software delivery. The agent-orchestrator is your STRATEGIC ADVISOR ONLY - they provide recommendations but YOU make all execution decisions and launch all agents.
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
## Tasking Agents
|
|
21
|
+
### Core Naming Protocol
|
|
22
|
+
|
|
23
|
+
🚨 CRITICAL: Every agent MUST have a unique name (Unique human FirstName, Abstract obscure LastName) in Task() calls:
|
|
24
|
+
|
|
25
|
+
Format:
|
|
26
|
+
- description: "<FirstNameLastName>: <3-5 word task description>"
|
|
27
|
+
- prompt: "Your name is <FirstNameLastName>. [full task instruction and context]"
|
|
28
|
+
- subagent_type: Select from available agents based on task
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
- description: "JoseAsic: implement user authentication"
|
|
32
|
+
- prompt: "Your name is JoseAsic. Implement the user authentication feature..."
|
|
33
|
+
- subagent_type: "engineer"
|
|
34
|
+
|
|
35
|
+
⚡ **NEVER**: REUSE names in future batches, each agent exists for a single batch.
|
|
36
|
+
|
|
37
|
+
### Agent Prompt Template
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
"Your name is [FirstNameLastName].
|
|
41
|
+
Your Team Role is [Primary implementer | Support advisor | Parallel worker]
|
|
42
|
+
|
|
43
|
+
SCOPE: [Project-level | Phase-level (phase-id: XX-Name)]
|
|
44
|
+
|
|
45
|
+
YOUR TASK:
|
|
46
|
+
[Specific task description]
|
|
47
|
+
|
|
48
|
+
CONSTRAINTS:
|
|
49
|
+
[Any dependencies, interfaces, or requirements]
|
|
50
|
+
|
|
51
|
+
SUCCESS CRITERIA:
|
|
52
|
+
[What constitutes completion]
|
|
53
|
+
|
|
54
|
+
FILES TO READ FIRST:
|
|
55
|
+
- [filepath1] - [one sentence description]
|
|
56
|
+
- [filepath2] - [one sentence description]
|
|
57
|
+
|
|
58
|
+
TEAM COLLABORATION:
|
|
59
|
+
- Leverage your Team for [what]
|
|
60
|
+
- Support your Team with [what]
|
|
61
|
+
- Coordinate with your Team on [shared concern]
|
|
62
|
+
|
|
63
|
+
[FirstNameLastName], adopt 🤝 TEAMWORK to achieve maximum value delivered."
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
⚡ **ALWAYS**: Provide team collaboration instructions
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## Batch Parallelization Guide
|
|
71
|
+
|
|
72
|
+
### Intra-Batch Execution (True Parallelism)
|
|
73
|
+
- Launch multiple agents SIMULTANEOUSLY using multiple Task() invocations in a single message
|
|
74
|
+
- Agents within a batch have NO blocking dependencies - they work in parallel
|
|
75
|
+
- Agents CAN communicate and support each other through the messaging system
|
|
76
|
+
- All agents in a batch complete independently without waiting for others
|
|
77
|
+
|
|
78
|
+
Parallel Specialization Examples
|
|
79
|
+
- **Multiple Engineers**: Each owns different module/file
|
|
80
|
+
- **Multiple Gatekeepers**: One for code quality, one for UI/UX compliance
|
|
81
|
+
- **Support Roles**: Architect answers questions, Researcher provides data, Designer creates storybook assets
|
|
82
|
+
|
|
83
|
+
### Inter-Batch Sequencing (Dependencies)
|
|
84
|
+
- Wait for ALL agents in current batch to complete before launching next batch
|
|
85
|
+
- Use verification batches after implementation batches
|
|
86
|
+
- Cascade changes through re-verification when upstream modifications occur
|
|
87
|
+
|
|
88
|
+
Inter-Batch Example (Sequential)
|
|
89
|
+
```
|
|
90
|
+
Research/Architecture → Planning → Implementation → Verification → Next WorkPackage or Phase
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Orchestration Decision Tree
|
|
94
|
+
|
|
95
|
+
✅ When to parallelize:
|
|
96
|
+
- Independent work packages
|
|
97
|
+
- Multiple similar tasks (e.g., multiple API endpoints)
|
|
98
|
+
- Design + Research simultaneously
|
|
99
|
+
- Test writing alongside implementation
|
|
100
|
+
- Multiple reviewers for large changes
|
|
101
|
+
- NO blocking dependencies between agents
|
|
102
|
+
- NO file editing conflicts (only ONE agent edits each file)
|
|
103
|
+
- Agents collaborate via messaging but complete independently
|
|
104
|
+
- Support roles (Architect, Researcher, Designer) provide real-time guidance
|
|
105
|
+
- Multiple same-type agents OK with different focus areas
|
|
106
|
+
|
|
107
|
+
⚠️ When to sequence:
|
|
108
|
+
- ⚠️ Clear dependency chain exists
|
|
109
|
+
1. **Functional Dependencies**: Task B needs Task A's output
|
|
110
|
+
2. **File Dependencies**: Tasks modifying same file CANNOT be in same batch
|
|
111
|
+
3. **Verification Dependencies**: Gatekeepers ALWAYS follow implementation (NEVER same batch)
|
|
112
|
+
4. **Knowledge Dependencies**: Planner needs architecture/research to plan against
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
### Example Workflows
|
|
116
|
+
|
|
117
|
+
#### New Feature Workflow
|
|
118
|
+
1. **Discovery Batch**: [Researcher, Architect, Business-Analyst, Designer]
|
|
119
|
+
2. **Planning Batch**: [Planner] - creates phase-id and WPs
|
|
120
|
+
3. **Consult**: Agent-orchestrator reviews plan
|
|
121
|
+
4. **Implementation Batch**: [5-10 Engineers with distinct role and focus + support agents (maximum 10 total per batch) ]
|
|
122
|
+
5. **Verification + Reco Batch**: [1-3 Gatekeepers with different focus + agent-orchestrator]
|
|
123
|
+
|
|
124
|
+
#### Bug Fix Workflow
|
|
125
|
+
1. **Investigation Batch**: [Engineer, Architect] - diagnose collaboratively
|
|
126
|
+
2. **Planning Batch**: [Planner] - uses existing phase
|
|
127
|
+
3. **Fix Batch**: [Engineer-Fix, Engineer-Tests] - parallel, different files
|
|
128
|
+
4. **Verification Batch**: [Gatekeeper] - validates fix
|
|
129
|
+
|
|
130
|
+
#### Architecture Change Workflow
|
|
131
|
+
1. **Research Batch**: [Deep-Researcher, Architect]
|
|
132
|
+
2. **Planning Batch**: [Planner, Business-Analyst]
|
|
133
|
+
3. **Migration Batch**: [Multiple Engineers, supporting architect] - each owns different module
|
|
134
|
+
4. **Verification Batch**: [Multiple Gatekeepers] - compliance check
|
|
135
|
+
|
|
136
|
+
⚡ **NEVER**: Batch gatekeepers with implementation
|
|
137
|
+
|
|
138
|
+
### Batch Size Optimization
|
|
139
|
+
|
|
140
|
+
#### Maximize Parallelization
|
|
141
|
+
- Break work into smallest parallelizable units.
|
|
142
|
+
- Include 5-10 agents when possible
|
|
143
|
+
- Add support roles for real-time guidance
|
|
144
|
+
|
|
145
|
+
#### Example Large Batch (MAX=10)
|
|
146
|
+
```
|
|
147
|
+
7 Engineers (each owns specific files/modules) +
|
|
148
|
+
2 Support (Architect, Researcher) +
|
|
149
|
+
1 Designer (UI assets and guidance) =
|
|
150
|
+
10 agents working in parallel
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Performance Optimization Tips
|
|
154
|
+
|
|
155
|
+
1. **Maximize Batch Size**: Include as many parallel agents as have independent work
|
|
156
|
+
2. **Preemptive Support Agents**: Include Architect/Researcher in implementation batches for real-time guidance
|
|
157
|
+
3. **Early Testing**: Include Test suite focused engineers in implementation batches for immediate test creation
|
|
158
|
+
4. **Parallel Reviews**: Multiple reviewers can examine different aspects simultaneously
|
|
159
|
+
5. **Broadcast Coordination**: Agents should announce decisions/discoveries immediately
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
## Todo Evolution Pattern
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Initial → Agent-Orch Consultation → Refined/Resequenced →
|
|
167
|
+
Batch Complete → Update → Next Consultation → Iterate
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
⚡ **ALWAYS**: Update todos immediately
|
|
171
|
+
|
|
172
|
+
### Agent-Orchestrator Consultation
|
|
173
|
+
|
|
174
|
+
ALWAYS Consult After
|
|
175
|
+
- User provides assignment
|
|
176
|
+
- Every batch completion
|
|
177
|
+
- Discovering dependency conflicts
|
|
178
|
+
- Planning phase transitions
|
|
179
|
+
|
|
180
|
+
Provide to Advisor
|
|
181
|
+
- Original user assignment
|
|
182
|
+
- Current todos with batch history
|
|
183
|
+
- Agent responses from last batch
|
|
184
|
+
- Created/modified artifacts list
|
|
185
|
+
|
|
186
|
+
Apply Recommendations
|
|
187
|
+
- THINK HARD about dependencies identified
|
|
188
|
+
- Refine todos based on sequencing advice
|
|
189
|
+
- Adjust batch composition per suggestions
|
|
190
|
+
- Iterate until advisor approves plan
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
PRO TIP: gatekeeper and agent-orchestrator agents can work in parallel, and both usually follow an implementation Batch... Task them concurrently.
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
## Phase Management & Documentation Structure
|
|
200
|
+
|
|
201
|
+
### Three-Tier Documentation Hierarchy
|
|
202
|
+
|
|
203
|
+
1. **Source of Truth Specs** (`docs/project/spec/`)
|
|
204
|
+
- NO subdirectories
|
|
205
|
+
- Requirements documents that don't change unless user updates requirements
|
|
206
|
+
- Only Business-Analyst updates these when user changes requirements
|
|
207
|
+
|
|
208
|
+
2. **Project-Level Gold Docs** (`docs/project/guides/`)
|
|
209
|
+
- NO subdirectories
|
|
210
|
+
- Living documentation: roadmap, architecture, ADRs, design patterns
|
|
211
|
+
- ALWAYS update existing docs rather than creating new ones
|
|
212
|
+
- Each document has a distinct purpose
|
|
213
|
+
|
|
214
|
+
3. **Phase-Level Working Docs** (`docs/project/phases/<phase-id>/`)
|
|
215
|
+
- Created by Planner when starting a new phase
|
|
216
|
+
- Contains WP definitions, implementation notes, test plans
|
|
217
|
+
- Working documents for agent batches
|
|
218
|
+
|
|
219
|
+
### Phase Management Protocol
|
|
220
|
+
|
|
221
|
+
### New Feature Detection
|
|
222
|
+
**Indicators**: User describes new functionality, no existing phase context, major feature request
|
|
223
|
+
**Action**: Create phase-id format `XX-DescriptiveName` (e.g., `03-UserAuth`, `04-PaymentFlow`)
|
|
224
|
+
|
|
225
|
+
### Continuation Detection
|
|
226
|
+
**Indicators**: Bug fix, refinement, existing thread context, minor adjustment
|
|
227
|
+
**Action**: Use most recent phase if related, or create new.
|
|
228
|
+
|
|
229
|
+
### Multi-Phase Complexity Detection
|
|
230
|
+
**Indicators**: Sweeping refactor, multi-module impact, core business requirement change.
|
|
231
|
+
**Action**: work at project level. Refine roadmap, architecture. Itterate through phases
|
|
232
|
+
|
|
233
|
+
### Phase Creation
|
|
234
|
+
- Planner creates `docs/project/phases/<phase-id>/` directory
|
|
235
|
+
- All phase agents receive phase-id and directory path
|
|
236
|
+
- Phase contains: WP definitions, implementation notes, test artifacts
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
## Available Core Agents Reference
|
|
241
|
+
|
|
242
|
+
### Strategic Advisory
|
|
243
|
+
- **agent-orchestrator**: Your strategic advisor for batch composition and sequencing (NO file modifications)
|
|
244
|
+
|
|
245
|
+
### Planning & Requirements
|
|
246
|
+
- **planner**: Creates phases, roadmaps, and work packages (works at project or phase level)
|
|
247
|
+
- **business-analyst**: Maintains SoT requirements, validates acceptance criteria
|
|
248
|
+
|
|
249
|
+
### Design & Architecture
|
|
250
|
+
- **architect**: Defines system shape, interfaces, technology decisions, Designs test strategies
|
|
251
|
+
- **designer**: Creates UI/UX specifications, component libraries
|
|
252
|
+
|
|
253
|
+
### Implementation
|
|
254
|
+
- **engineer**: Implements features end-to-end with code, writes comprehensive test suites, and documentation
|
|
255
|
+
|
|
256
|
+
### Verification
|
|
257
|
+
- **gatekeeper**: Reviews code for quality, security, and standards compliance. Ensures all builds, tests, and checks pass. Script playwright to screenshot UI, then visually inspect and assess agsinst UI/UX design/guide.
|
|
258
|
+
|
|
259
|
+
### Research & Support
|
|
260
|
+
- **deep-researcher**: Conducts targeted research for technical decisions
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
## Critical Reminders
|
|
264
|
+
|
|
265
|
+
1. **You are the Primary Orchestrator** - agent-orchestrator only advises
|
|
266
|
+
2. **TodoWrite continuously** - Update after every action
|
|
267
|
+
3. **Batch everything possible** - Launch parallel agents in single message
|
|
268
|
+
4. **Verify everything** - No skipping quality gates
|
|
269
|
+
5. **Context discipline** - Give agents minimal but complete context
|
|
270
|
+
6. **Phase management** - Provide phase-id when working at phase level
|
|
271
|
+
7. **Document hierarchy** - Respect spec/ vs guides/ vs phases/
|
|
272
|
+
8. **Agent responses** - Process fully and feed to agent-orchestrator
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
[/CRITICAL ORCHESTRATION PROTOCOLS]
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
⚙️Remember: The key to effective orchestration is understanding which work can truly happen in parallel and launching those agents together, while respecting sequential dependencies between batches.⚙️
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-comms",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "NPX installer for Claude Code hooks and observability setup",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -77,7 +77,9 @@
|
|
|
77
77
|
"src/",
|
|
78
78
|
"templates/",
|
|
79
79
|
"README.md",
|
|
80
|
-
"CHANGELOG.md"
|
|
80
|
+
"CHANGELOG.md",
|
|
81
|
+
".claude/",
|
|
82
|
+
"CLAUDE.md"
|
|
81
83
|
],
|
|
82
84
|
"publishConfig": {
|
|
83
85
|
"access": "public"
|
package/src/fetcher/github.js
CHANGED
|
@@ -153,7 +153,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
153
153
|
*/
|
|
154
154
|
async fetchAsTarball(options = {}) {
|
|
155
155
|
const fetchOptions = this._prepareFetchOptions(options);
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
this.emit('progress', {
|
|
158
158
|
task: 'fetch_tarball',
|
|
159
159
|
current: 0,
|
|
@@ -164,9 +164,9 @@ class GitHubFetcher extends EventEmitter {
|
|
|
164
164
|
try {
|
|
165
165
|
// Download tarball from GitHub
|
|
166
166
|
const tarballBuffer = await this._downloadTarball(fetchOptions);
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
this.emit('progress', {
|
|
169
|
-
task: 'fetch_tarball',
|
|
169
|
+
task: 'fetch_tarball',
|
|
170
170
|
current: 50,
|
|
171
171
|
message: 'Extracting files from tarball...',
|
|
172
172
|
status: 'running'
|
|
@@ -591,17 +591,17 @@ class GitHubFetcher extends EventEmitter {
|
|
|
591
591
|
if (error.code === 'GITHUB_RATE_LIMIT') {
|
|
592
592
|
// Check if we should fail fast
|
|
593
593
|
this._shouldFailFastOnRateLimit();
|
|
594
|
-
|
|
594
|
+
|
|
595
595
|
// Calculate smart rate limit delay
|
|
596
596
|
const delay = this._calculateRateLimitDelay();
|
|
597
|
-
|
|
597
|
+
|
|
598
598
|
if (delay > 0) {
|
|
599
599
|
console.warn(`Rate limit exceeded. Waiting ${Math.round(delay / 1000)}s before retry ${attempt + 1}/${this.config.retryCount}`);
|
|
600
|
-
|
|
600
|
+
|
|
601
601
|
if (!this.config.token) {
|
|
602
602
|
console.warn('💡 Tip: Set GITHUB_TOKEN environment variable to increase rate limits (5,000/hour vs 60/hour)');
|
|
603
603
|
}
|
|
604
|
-
|
|
604
|
+
|
|
605
605
|
// Show countdown for longer waits
|
|
606
606
|
if (delay > 5000) {
|
|
607
607
|
await this._waitWithCountdown(delay);
|
|
@@ -656,8 +656,8 @@ class GitHubFetcher extends EventEmitter {
|
|
|
656
656
|
if (timeUntilReset > 5 * 60 * 1000) {
|
|
657
657
|
throw new GitHubAPIError(
|
|
658
658
|
`Rate limit reset time too far in future (${Math.round(timeUntilReset / 1000)}s). Consider using a GitHub token or try again later.`,
|
|
659
|
-
{
|
|
660
|
-
resetTime: this.rateLimitReset,
|
|
659
|
+
{
|
|
660
|
+
resetTime: this.rateLimitReset,
|
|
661
661
|
delaySeconds: Math.round(timeUntilReset / 1000),
|
|
662
662
|
suggestion: 'Use GITHUB_TOKEN environment variable to increase rate limits'
|
|
663
663
|
}
|
|
@@ -677,13 +677,13 @@ class GitHubFetcher extends EventEmitter {
|
|
|
677
677
|
}
|
|
678
678
|
|
|
679
679
|
const timeUntilReset = this.rateLimitReset - Date.now();
|
|
680
|
-
|
|
680
|
+
|
|
681
681
|
// Fail fast if rate limit won't reset for more than 5 minutes
|
|
682
682
|
if (timeUntilReset > 5 * 60 * 1000) {
|
|
683
683
|
throw new GitHubAPIError(
|
|
684
684
|
`Rate limit reset time too far in future (${Math.round(timeUntilReset / 1000)}s). Installation cancelled.`,
|
|
685
|
-
{
|
|
686
|
-
resetTime: this.rateLimitReset,
|
|
685
|
+
{
|
|
686
|
+
resetTime: this.rateLimitReset,
|
|
687
687
|
delaySeconds: Math.round(timeUntilReset / 1000),
|
|
688
688
|
suggestion: 'Use GITHUB_TOKEN environment variable or try again later'
|
|
689
689
|
}
|
|
@@ -701,17 +701,17 @@ class GitHubFetcher extends EventEmitter {
|
|
|
701
701
|
if (this.rateLimitReset && Date.now() < this.rateLimitReset) {
|
|
702
702
|
// Use smart rate limit delay calculation
|
|
703
703
|
const delay = this._calculateRateLimitDelay();
|
|
704
|
-
|
|
704
|
+
|
|
705
705
|
if (delay > 0) {
|
|
706
706
|
console.warn(`Rate limit active, waiting ${Math.round(delay / 1000)}s`);
|
|
707
|
-
|
|
707
|
+
|
|
708
708
|
if (delay > 5000) {
|
|
709
709
|
await this._waitWithCountdown(delay);
|
|
710
710
|
} else {
|
|
711
711
|
await this._sleep(delay);
|
|
712
712
|
}
|
|
713
713
|
}
|
|
714
|
-
|
|
714
|
+
|
|
715
715
|
this.rateLimitReset = null;
|
|
716
716
|
}
|
|
717
717
|
}
|
|
@@ -741,16 +741,16 @@ class GitHubFetcher extends EventEmitter {
|
|
|
741
741
|
async _waitWithCountdown(totalMs) {
|
|
742
742
|
const intervalMs = 1000; // Update every second
|
|
743
743
|
let remainingMs = totalMs;
|
|
744
|
-
|
|
744
|
+
|
|
745
745
|
while (remainingMs > 0) {
|
|
746
746
|
const remainingSeconds = Math.ceil(remainingMs / 1000);
|
|
747
747
|
process.stdout.write(`\r⏳ Rate limit wait: ${remainingSeconds}s remaining...`);
|
|
748
|
-
|
|
748
|
+
|
|
749
749
|
const sleepTime = Math.min(intervalMs, remainingMs);
|
|
750
750
|
await this._sleep(sleepTime);
|
|
751
751
|
remainingMs -= sleepTime;
|
|
752
752
|
}
|
|
753
|
-
|
|
753
|
+
|
|
754
754
|
process.stdout.write('\r✅ Rate limit wait complete.\n');
|
|
755
755
|
}
|
|
756
756
|
|
|
@@ -760,10 +760,10 @@ class GitHubFetcher extends EventEmitter {
|
|
|
760
760
|
*/
|
|
761
761
|
async _waitForRateLimit() {
|
|
762
762
|
const delay = this._calculateRateLimitDelay();
|
|
763
|
-
|
|
763
|
+
|
|
764
764
|
if (delay > 0) {
|
|
765
765
|
console.warn(`Rate limit active, waiting ${Math.round(delay / 1000)}s`);
|
|
766
|
-
|
|
766
|
+
|
|
767
767
|
if (delay > 5000) {
|
|
768
768
|
await this._waitWithCountdown(delay);
|
|
769
769
|
} else {
|
|
@@ -834,7 +834,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
834
834
|
const url = `${this.config.baseUrl}/repos/${this.repository.owner}/${this.repository.repo}/tarball/${version}`;
|
|
835
835
|
|
|
836
836
|
const response = await this._makeRequest(url);
|
|
837
|
-
|
|
837
|
+
|
|
838
838
|
if (!response.ok) {
|
|
839
839
|
throw new GitHubAPIError(
|
|
840
840
|
`Failed to download tarball: ${response.status} ${response.statusText}`,
|
|
@@ -844,7 +844,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
844
844
|
|
|
845
845
|
// Download tarball as buffer
|
|
846
846
|
const buffer = await response.buffer();
|
|
847
|
-
|
|
847
|
+
|
|
848
848
|
if (buffer.length === 0) {
|
|
849
849
|
throw new GitHubAPIError(
|
|
850
850
|
'Downloaded tarball is empty',
|
|
@@ -872,7 +872,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
872
872
|
|
|
873
873
|
// Create temporary directory for extraction
|
|
874
874
|
const tempDir = path.join(os.tmpdir(), `claude-extract-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
875
|
-
|
|
875
|
+
|
|
876
876
|
// Track files we want to keep
|
|
877
877
|
const wantedFiles = new Map();
|
|
878
878
|
let rootDirName = null;
|
|
@@ -882,7 +882,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
882
882
|
filter: (filePath, entry) => {
|
|
883
883
|
// Debug logging
|
|
884
884
|
console.log(`DEBUG: Processing ${filePath} (type: ${entry.type})`);
|
|
885
|
-
|
|
885
|
+
|
|
886
886
|
// Auto-detect root directory from first file/directory path
|
|
887
887
|
if (!rootDirName) {
|
|
888
888
|
// GitHub tarballs typically have format: "owner-repo-hash/path/to/file"
|
|
@@ -894,26 +894,26 @@ class GitHubFetcher extends EventEmitter {
|
|
|
894
894
|
}
|
|
895
895
|
|
|
896
896
|
// Remove root directory prefix to get actual file path
|
|
897
|
-
const actualPath = rootDirName && filePath.startsWith(rootDirName + '/') ?
|
|
897
|
+
const actualPath = rootDirName && filePath.startsWith(rootDirName + '/') ?
|
|
898
898
|
filePath.slice(rootDirName.length + 1) : filePath;
|
|
899
|
-
|
|
899
|
+
|
|
900
900
|
// Only extract files we care about
|
|
901
901
|
const isClaudeFile = actualPath.startsWith('.claude/') || actualPath === '.claude';
|
|
902
902
|
const isClaudeMd = actualPath === 'CLAUDE.md';
|
|
903
|
-
|
|
903
|
+
|
|
904
904
|
console.log(`DEBUG: ${actualPath} -> claude: ${isClaudeFile}, md: ${isClaudeMd}, type: ${entry.type}`);
|
|
905
|
-
|
|
905
|
+
|
|
906
906
|
if ((isClaudeFile || isClaudeMd) && entry.type === 'File') {
|
|
907
907
|
wantedFiles.set(filePath, actualPath);
|
|
908
908
|
console.log(`DEBUG: Will extract: ${filePath} -> ${actualPath}`);
|
|
909
909
|
return true;
|
|
910
910
|
}
|
|
911
|
-
|
|
911
|
+
|
|
912
912
|
// Also allow .claude directories to be processed for their children
|
|
913
913
|
if (isClaudeFile && entry.type === 'Directory') {
|
|
914
914
|
return true;
|
|
915
915
|
}
|
|
916
|
-
|
|
916
|
+
|
|
917
917
|
return false;
|
|
918
918
|
}
|
|
919
919
|
});
|
|
@@ -928,18 +928,18 @@ class GitHubFetcher extends EventEmitter {
|
|
|
928
928
|
extractStream.on('finish', async () => {
|
|
929
929
|
try {
|
|
930
930
|
console.log(`DEBUG: Processing ${wantedFiles.size} extracted files`);
|
|
931
|
-
|
|
931
|
+
|
|
932
932
|
// Process extracted files
|
|
933
933
|
for (const [extractedPath, actualPath] of wantedFiles) {
|
|
934
934
|
const fullPath = path.join(tempDir, extractedPath);
|
|
935
|
-
|
|
935
|
+
|
|
936
936
|
try {
|
|
937
937
|
const stats = await fs.promises.stat(fullPath);
|
|
938
|
-
|
|
938
|
+
|
|
939
939
|
if (stats.isFile()) {
|
|
940
940
|
const content = await fs.promises.readFile(fullPath, 'utf-8');
|
|
941
941
|
console.log(`DEBUG: Read ${actualPath} (${content.length} bytes)`);
|
|
942
|
-
|
|
942
|
+
|
|
943
943
|
if (actualPath === 'CLAUDE.md') {
|
|
944
944
|
const claudeMdFileObj = {
|
|
945
945
|
path: 'CLAUDE.md',
|
|
@@ -948,7 +948,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
948
948
|
type: 'file'
|
|
949
949
|
};
|
|
950
950
|
extractedFiles['CLAUDE.md'] = claudeMdFileObj;
|
|
951
|
-
console.log(
|
|
951
|
+
console.log('DEBUG: Added CLAUDE.md to result');
|
|
952
952
|
} else if (actualPath.startsWith('.claude/')) {
|
|
953
953
|
// Add to .claude files
|
|
954
954
|
const fileObj = {
|
|
@@ -957,10 +957,10 @@ class GitHubFetcher extends EventEmitter {
|
|
|
957
957
|
encoding: 'utf-8',
|
|
958
958
|
type: 'file'
|
|
959
959
|
};
|
|
960
|
-
|
|
960
|
+
|
|
961
961
|
extractedFiles['.claude'].files.push(fileObj);
|
|
962
962
|
console.log(`DEBUG: Added ${actualPath} to .claude files (${extractedFiles['.claude'].files.length} total)`);
|
|
963
|
-
|
|
963
|
+
|
|
964
964
|
// Build directory structure for compatibility
|
|
965
965
|
const relativePath = actualPath.slice('.claude/'.length);
|
|
966
966
|
this._addToDirectoryStructure(extractedFiles['.claude'], relativePath, fileObj);
|
|
@@ -983,7 +983,7 @@ class GitHubFetcher extends EventEmitter {
|
|
|
983
983
|
}
|
|
984
984
|
|
|
985
985
|
resolve(extractedFiles);
|
|
986
|
-
|
|
986
|
+
|
|
987
987
|
} catch (processingError) {
|
|
988
988
|
reject(new GitHubAPIError(
|
|
989
989
|
`File processing failed: ${processingError.message}`,
|
|
@@ -1010,15 +1010,15 @@ class GitHubFetcher extends EventEmitter {
|
|
|
1010
1010
|
* Add file to directory structure for compatibility with existing code
|
|
1011
1011
|
* @private
|
|
1012
1012
|
*/
|
|
1013
|
-
_addToDirectoryStructure(claudeDir, relativePath,
|
|
1013
|
+
_addToDirectoryStructure(claudeDir, relativePath, _fileObj) {
|
|
1014
1014
|
const parts = relativePath.split('/');
|
|
1015
1015
|
let currentLevel = claudeDir.children;
|
|
1016
1016
|
let currentPath = '.claude';
|
|
1017
|
-
|
|
1017
|
+
|
|
1018
1018
|
for (let i = 0; i < parts.length; i++) {
|
|
1019
1019
|
const part = parts[i];
|
|
1020
1020
|
currentPath = `${currentPath}/${part}`;
|
|
1021
|
-
|
|
1021
|
+
|
|
1022
1022
|
if (i === parts.length - 1) {
|
|
1023
1023
|
// This is the file
|
|
1024
1024
|
currentLevel.push({
|
|
@@ -1056,17 +1056,17 @@ async function fetchRepository(gitRef = 'main', options = {}) {
|
|
|
1056
1056
|
// Strategy 1: Tarball approach (fastest, single request)
|
|
1057
1057
|
console.log('Attempting tarball fetch strategy...');
|
|
1058
1058
|
const tarballFiles = await fetcher.fetchAsTarball({ version: gitRef });
|
|
1059
|
-
|
|
1059
|
+
|
|
1060
1060
|
return {
|
|
1061
1061
|
claudeDirectory: tarballFiles['.claude'],
|
|
1062
1062
|
claudeFile: tarballFiles['CLAUDE.md'],
|
|
1063
1063
|
files: [...(tarballFiles['.claude'].files || []), tarballFiles['CLAUDE.md']]
|
|
1064
1064
|
};
|
|
1065
|
-
|
|
1065
|
+
|
|
1066
1066
|
} catch (tarballError) {
|
|
1067
1067
|
console.warn(`Tarball fetch failed: ${tarballError.message}`);
|
|
1068
1068
|
console.log('Falling back to individual file fetch strategy...');
|
|
1069
|
-
|
|
1069
|
+
|
|
1070
1070
|
try {
|
|
1071
1071
|
// Strategy 2: Individual file fetch (fallback)
|
|
1072
1072
|
const [claudeDir, claudeMd] = await Promise.all([
|
|
@@ -1079,7 +1079,7 @@ async function fetchRepository(gitRef = 'main', options = {}) {
|
|
|
1079
1079
|
claudeFile: claudeMd,
|
|
1080
1080
|
files: [...(claudeDir.files || []), claudeMd]
|
|
1081
1081
|
};
|
|
1082
|
-
|
|
1082
|
+
|
|
1083
1083
|
} catch (fallbackError) {
|
|
1084
1084
|
console.error('Both tarball and individual fetch strategies failed');
|
|
1085
1085
|
throw new Error(
|