claude-agent-framework 1.0.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.
Files changed (111) hide show
  1. package/README.md +128 -0
  2. package/bin/claude-framework +3 -0
  3. package/framework/agents/design-lead.md +240 -0
  4. package/framework/agents/product-owner.md +179 -0
  5. package/framework/agents/tech-lead.md +226 -0
  6. package/framework/commands/ayuda.md +127 -0
  7. package/framework/commands/a/303/261adir.md +98 -0
  8. package/framework/commands/backup.md +397 -0
  9. package/framework/commands/cambiar.md +110 -0
  10. package/framework/commands/cloud.md +457 -0
  11. package/framework/commands/code.md +142 -0
  12. package/framework/commands/debug.md +334 -0
  13. package/framework/commands/deploy.md +383 -0
  14. package/framework/commands/deshacer.md +120 -0
  15. package/framework/commands/estado.md +218 -0
  16. package/framework/commands/explica.md +227 -0
  17. package/framework/commands/feature.md +120 -0
  18. package/framework/commands/git.md +427 -0
  19. package/framework/commands/historial.md +202 -0
  20. package/framework/commands/learn.md +408 -0
  21. package/framework/commands/movil.md +245 -0
  22. package/framework/commands/nuevo.md +118 -0
  23. package/framework/commands/plan.md +134 -0
  24. package/framework/commands/prd.md +113 -0
  25. package/framework/commands/probar.md +148 -0
  26. package/framework/commands/revisar.md +208 -0
  27. package/framework/commands/seeds.md +230 -0
  28. package/framework/commands/seguridad.md +226 -0
  29. package/framework/commands/tasks.md +157 -0
  30. package/framework/skills/architecture/algorithms.md +970 -0
  31. package/framework/skills/architecture/clean-code.md +1080 -0
  32. package/framework/skills/architecture/design-patterns.md +1984 -0
  33. package/framework/skills/architecture/functional-programming.md +972 -0
  34. package/framework/skills/architecture/solid.md +991 -0
  35. package/framework/skills/cloud/cloud-aws.md +848 -0
  36. package/framework/skills/cloud/cloud-azure.md +931 -0
  37. package/framework/skills/cloud/cloud-gcp.md +848 -0
  38. package/framework/skills/cloud/message-queues.md +1229 -0
  39. package/framework/skills/core/accessibility.md +401 -0
  40. package/framework/skills/core/api.md +474 -0
  41. package/framework/skills/core/authentication.md +306 -0
  42. package/framework/skills/core/authorization.md +388 -0
  43. package/framework/skills/core/background-jobs.md +341 -0
  44. package/framework/skills/core/caching.md +473 -0
  45. package/framework/skills/core/code-review.md +341 -0
  46. package/framework/skills/core/controllers.md +290 -0
  47. package/framework/skills/core/cua.md +285 -0
  48. package/framework/skills/core/documentation.md +472 -0
  49. package/framework/skills/core/file-uploads.md +351 -0
  50. package/framework/skills/core/hotwire-native.md +296 -0
  51. package/framework/skills/core/hotwire.md +278 -0
  52. package/framework/skills/core/i18n.md +334 -0
  53. package/framework/skills/core/imports-exports.md +750 -0
  54. package/framework/skills/core/infrastructure.md +337 -0
  55. package/framework/skills/core/models.md +228 -0
  56. package/framework/skills/core/notifications.md +672 -0
  57. package/framework/skills/core/payments.md +581 -0
  58. package/framework/skills/core/performance.md +361 -0
  59. package/framework/skills/core/rails-scaffold.md +131 -0
  60. package/framework/skills/core/search.md +518 -0
  61. package/framework/skills/core/security.md +565 -0
  62. package/framework/skills/core/seeds.md +307 -0
  63. package/framework/skills/core/seo.md +542 -0
  64. package/framework/skills/core/testing.md +393 -0
  65. package/framework/skills/core/views.md +260 -0
  66. package/framework/skills/core/websockets.md +564 -0
  67. package/framework/skills/data/advanced-sql.md +1204 -0
  68. package/framework/skills/data/nosql.md +1141 -0
  69. package/framework/skills/devops/containers-advanced.md +1237 -0
  70. package/framework/skills/devops/debugging.md +834 -0
  71. package/framework/skills/devops/git-workflow.md +752 -0
  72. package/framework/skills/devops/networking.md +932 -0
  73. package/framework/skills/devops/shell-scripting.md +1132 -0
  74. package/framework/sub-agents/architecture-patterns-agent.md +1450 -0
  75. package/framework/sub-agents/cloud-agent.md +677 -0
  76. package/framework/sub-agents/data.md +504 -0
  77. package/framework/sub-agents/debugging-agent.md +554 -0
  78. package/framework/sub-agents/devops.md +483 -0
  79. package/framework/sub-agents/docs.md +176 -0
  80. package/framework/sub-agents/frontend-dev.md +349 -0
  81. package/framework/sub-agents/git-workflow-agent.md +697 -0
  82. package/framework/sub-agents/integrations.md +630 -0
  83. package/framework/sub-agents/native-dev.md +434 -0
  84. package/framework/sub-agents/qa.md +138 -0
  85. package/framework/sub-agents/rails-dev.md +375 -0
  86. package/framework/sub-agents/security.md +526 -0
  87. package/framework/sub-agents/ui.md +437 -0
  88. package/framework/sub-agents/ux.md +284 -0
  89. package/framework/templates/api-spec.md +500 -0
  90. package/framework/templates/component-spec.md +248 -0
  91. package/framework/templates/feature.json +13 -0
  92. package/framework/templates/model-spec.md +318 -0
  93. package/framework/templates/prd-template.md +80 -0
  94. package/framework/templates/task-plan.md +122 -0
  95. package/framework/templates/task-user-story.md +52 -0
  96. package/framework/templates/technical-spec.md +260 -0
  97. package/framework/templates/user-story.md +95 -0
  98. package/package.json +42 -0
  99. package/project-templates/CLAUDE.md +42 -0
  100. package/project-templates/contexts/architecture.md +25 -0
  101. package/project-templates/contexts/conventions.md +46 -0
  102. package/project-templates/contexts/design-system.md +47 -0
  103. package/project-templates/contexts/requirements.md +38 -0
  104. package/project-templates/contexts/stack.md +30 -0
  105. package/project-templates/history/active/models.md +11 -0
  106. package/project-templates/history/changelog.md +15 -0
  107. package/project-templates/workspace/.gitkeep +0 -0
  108. package/src/cli.js +52 -0
  109. package/src/init.js +104 -0
  110. package/src/status.js +75 -0
  111. package/src/update.js +88 -0
@@ -0,0 +1,564 @@
1
+ # Skill: WebSockets (Action Cable)
2
+
3
+ ## Purpose
4
+
5
+ Implementar funcionalidades en tiempo real usando Action Cable, el framework de WebSockets integrado en Rails.
6
+
7
+ ## Setup
8
+
9
+ ### Configuración básica
10
+
11
+ ```ruby
12
+ # config/cable.yml
13
+ development:
14
+ adapter: async
15
+
16
+ test:
17
+ adapter: test
18
+
19
+ production:
20
+ adapter: solid_cable # Rails 8
21
+ # O Redis:
22
+ # adapter: redis
23
+ # url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
24
+ # channel_prefix: myapp_production
25
+ ```
26
+
27
+ ```ruby
28
+ # config/environments/production.rb
29
+ config.action_cable.url = "wss://myapp.com/cable"
30
+ config.action_cable.allowed_request_origins = [
31
+ "https://myapp.com",
32
+ /https:\/\/.*\.myapp\.com/
33
+ ]
34
+ ```
35
+
36
+ ### JavaScript setup
37
+
38
+ ```javascript
39
+ // app/javascript/application.js
40
+ import "@hotwired/turbo-rails"
41
+ import "./channels"
42
+ ```
43
+
44
+ ```javascript
45
+ // app/javascript/channels/index.js
46
+ import { createConsumer } from "@hotwired/actioncable"
47
+ window.App = { cable: createConsumer() }
48
+ ```
49
+
50
+ ## Canales básicos
51
+
52
+ ### Canal de chat
53
+
54
+ ```ruby
55
+ # app/channels/chat_channel.rb
56
+ class ChatChannel < ApplicationCable::Channel
57
+ def subscribed
58
+ @room = Room.find(params[:room_id])
59
+
60
+ # Verificar autorización
61
+ reject unless can_access_room?
62
+
63
+ stream_for @room
64
+ end
65
+
66
+ def unsubscribed
67
+ # Limpiar cuando el usuario se desconecta
68
+ end
69
+
70
+ def speak(data)
71
+ message = @room.messages.create!(
72
+ user: current_user,
73
+ body: data["body"]
74
+ )
75
+
76
+ # Broadcast a todos los suscriptores
77
+ ChatChannel.broadcast_to(@room, {
78
+ message: render_message(message),
79
+ user_id: current_user.id
80
+ })
81
+ end
82
+
83
+ def typing
84
+ ChatChannel.broadcast_to(@room, {
85
+ type: "typing",
86
+ user_id: current_user.id,
87
+ user_name: current_user.name
88
+ })
89
+ end
90
+
91
+ private
92
+
93
+ def can_access_room?
94
+ @room.users.include?(current_user)
95
+ end
96
+
97
+ def render_message(message)
98
+ ApplicationController.render(
99
+ partial: "messages/message",
100
+ locals: { message: message }
101
+ )
102
+ end
103
+ end
104
+ ```
105
+
106
+ ```javascript
107
+ // app/javascript/channels/chat_channel.js
108
+ import consumer from "./consumer"
109
+
110
+ document.addEventListener("turbo:load", () => {
111
+ const chatRoom = document.getElementById("chat-room")
112
+ if (!chatRoom) return
113
+
114
+ const roomId = chatRoom.dataset.roomId
115
+
116
+ consumer.subscriptions.create(
117
+ { channel: "ChatChannel", room_id: roomId },
118
+ {
119
+ connected() {
120
+ console.log("Connected to chat")
121
+ },
122
+
123
+ disconnected() {
124
+ console.log("Disconnected from chat")
125
+ },
126
+
127
+ received(data) {
128
+ if (data.type === "typing") {
129
+ this.showTypingIndicator(data.user_name)
130
+ } else {
131
+ this.appendMessage(data.message)
132
+ }
133
+ },
134
+
135
+ speak(body) {
136
+ this.perform("speak", { body: body })
137
+ },
138
+
139
+ typing() {
140
+ this.perform("typing")
141
+ },
142
+
143
+ appendMessage(html) {
144
+ const messages = document.getElementById("messages")
145
+ messages.insertAdjacentHTML("beforeend", html)
146
+ messages.scrollTop = messages.scrollHeight
147
+ },
148
+
149
+ showTypingIndicator(userName) {
150
+ const indicator = document.getElementById("typing-indicator")
151
+ indicator.textContent = `${userName} is typing...`
152
+ indicator.classList.remove("hidden")
153
+
154
+ clearTimeout(this.typingTimeout)
155
+ this.typingTimeout = setTimeout(() => {
156
+ indicator.classList.add("hidden")
157
+ }, 2000)
158
+ }
159
+ }
160
+ )
161
+ })
162
+ ```
163
+
164
+ ### Canal de notificaciones
165
+
166
+ ```ruby
167
+ # app/channels/notifications_channel.rb
168
+ class NotificationsChannel < ApplicationCable::Channel
169
+ def subscribed
170
+ stream_for current_user
171
+ end
172
+
173
+ def mark_as_read(data)
174
+ notification = current_user.notifications.find(data["id"])
175
+ notification.mark_as_read!
176
+
177
+ NotificationsChannel.broadcast_to(current_user, {
178
+ type: "read",
179
+ id: notification.id
180
+ })
181
+ end
182
+ end
183
+ ```
184
+
185
+ ### Canal de presencia (quién está online)
186
+
187
+ ```ruby
188
+ # app/channels/presence_channel.rb
189
+ class PresenceChannel < ApplicationCable::Channel
190
+ def subscribed
191
+ @room = Room.find(params[:room_id])
192
+ stream_for @room
193
+
194
+ # Registrar usuario como online
195
+ add_user_to_presence
196
+
197
+ # Notificar a otros
198
+ broadcast_presence
199
+ end
200
+
201
+ def unsubscribed
202
+ remove_user_from_presence
203
+ broadcast_presence
204
+ end
205
+
206
+ private
207
+
208
+ def presence_key
209
+ "room:#{@room.id}:presence"
210
+ end
211
+
212
+ def add_user_to_presence
213
+ Rails.cache.write(
214
+ "#{presence_key}:#{current_user.id}",
215
+ { id: current_user.id, name: current_user.name },
216
+ expires_in: 5.minutes
217
+ )
218
+ end
219
+
220
+ def remove_user_from_presence
221
+ Rails.cache.delete("#{presence_key}:#{current_user.id}")
222
+ end
223
+
224
+ def online_users
225
+ keys = Rails.cache.redis.keys("#{presence_key}:*")
226
+ keys.map { |key| Rails.cache.read(key) }.compact
227
+ end
228
+
229
+ def broadcast_presence
230
+ PresenceChannel.broadcast_to(@room, {
231
+ type: "presence",
232
+ users: online_users
233
+ })
234
+ end
235
+ end
236
+ ```
237
+
238
+ ## Integración con Turbo Streams
239
+
240
+ ### Broadcast desde modelos
241
+
242
+ ```ruby
243
+ # app/models/message.rb
244
+ class Message < ApplicationRecord
245
+ belongs_to :room
246
+ belongs_to :user
247
+
248
+ # Broadcast automático con Turbo
249
+ broadcasts_to :room
250
+
251
+ # O personalizado:
252
+ after_create_commit -> {
253
+ broadcast_append_to room,
254
+ target: "messages",
255
+ partial: "messages/message",
256
+ locals: { message: self }
257
+ }
258
+
259
+ after_update_commit -> {
260
+ broadcast_replace_to room,
261
+ target: dom_id(self),
262
+ partial: "messages/message",
263
+ locals: { message: self }
264
+ }
265
+
266
+ after_destroy_commit -> {
267
+ broadcast_remove_to room, target: dom_id(self)
268
+ }
269
+ end
270
+ ```
271
+
272
+ ### Vista con Turbo Streams
273
+
274
+ ```erb
275
+ <%# app/views/rooms/show.html.erb %>
276
+ <div id="chat-room" data-room-id="<%= @room.id %>">
277
+ <%# Suscribirse a updates de Turbo Stream %>
278
+ <%= turbo_stream_from @room %>
279
+
280
+ <div id="messages" class="h-96 overflow-y-auto">
281
+ <%= render @room.messages.includes(:user).order(created_at: :asc) %>
282
+ </div>
283
+
284
+ <div id="typing-indicator" class="hidden text-sm text-gray-500 italic"></div>
285
+
286
+ <%= form_with url: room_messages_path(@room),
287
+ data: { controller: "chat", action: "submit->chat#send" } do |f| %>
288
+ <%= f.text_field :body,
289
+ placeholder: t(".type_message"),
290
+ autocomplete: "off",
291
+ data: { chat_target: "input", action: "input->chat#typing" },
292
+ class: "w-full px-4 py-2 border rounded-lg" %>
293
+ <% end %>
294
+ </div>
295
+ ```
296
+
297
+ ## Autenticación en canales
298
+
299
+ ```ruby
300
+ # app/channels/application_cable/connection.rb
301
+ module ApplicationCable
302
+ class Connection < ActionCable::Connection::Base
303
+ identified_by :current_user
304
+
305
+ def connect
306
+ self.current_user = find_verified_user
307
+ end
308
+
309
+ private
310
+
311
+ def find_verified_user
312
+ # Opción 1: Session-based (para apps web)
313
+ if verified_user = User.find_by(id: session["user_id"])
314
+ verified_user
315
+ # Opción 2: Token-based (para móvil/API)
316
+ elsif verified_user = User.find_by(auth_token: request.params[:token])
317
+ verified_user
318
+ else
319
+ reject_unauthorized_connection
320
+ end
321
+ end
322
+
323
+ def session
324
+ @session ||= cookies.encrypted[Rails.application.config.session_options[:key]]
325
+ end
326
+ end
327
+ end
328
+ ```
329
+
330
+ ## Patrones avanzados
331
+
332
+ ### Rate limiting
333
+
334
+ ```ruby
335
+ # app/channels/concerns/rate_limitable.rb
336
+ module RateLimitable
337
+ extend ActiveSupport::Concern
338
+
339
+ class_methods do
340
+ def rate_limit(method_name, limit:, period:)
341
+ original_method = instance_method(method_name)
342
+
343
+ define_method(method_name) do |data = {}|
344
+ key = "rate_limit:#{self.class.name}:#{method_name}:#{current_user.id}"
345
+ count = Rails.cache.increment(key, 1, expires_in: period)
346
+
347
+ if count > limit
348
+ transmit(error: "Rate limit exceeded. Try again later.")
349
+ return
350
+ end
351
+
352
+ original_method.bind(self).call(data)
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ # Uso en canal
359
+ class ChatChannel < ApplicationCable::Channel
360
+ include RateLimitable
361
+
362
+ rate_limit :speak, limit: 10, period: 1.minute
363
+ end
364
+ ```
365
+
366
+ ### Heartbeat para presencia
367
+
368
+ ```ruby
369
+ # app/channels/presence_channel.rb
370
+ class PresenceChannel < ApplicationCable::Channel
371
+ periodically :heartbeat, every: 30.seconds
372
+
373
+ def heartbeat
374
+ update_presence
375
+ broadcast_presence
376
+ end
377
+ end
378
+ ```
379
+
380
+ ### Broadcast condicional
381
+
382
+ ```ruby
383
+ # app/models/comment.rb
384
+ class Comment < ApplicationRecord
385
+ after_create_commit :broadcast_to_relevant_users
386
+
387
+ private
388
+
389
+ def broadcast_to_relevant_users
390
+ # Solo broadcast a usuarios que pueden ver el comentario
391
+ post.authorized_viewers.each do |user|
392
+ Turbo::StreamsChannel.broadcast_append_to(
393
+ [user, "notifications"],
394
+ target: "notifications",
395
+ partial: "notifications/new_comment",
396
+ locals: { comment: self }
397
+ )
398
+ end
399
+ end
400
+ end
401
+ ```
402
+
403
+ ## Stimulus Controller para WebSockets
404
+
405
+ ```javascript
406
+ // app/javascript/controllers/chat_controller.js
407
+ import { Controller } from "@hotwired/stimulus"
408
+ import consumer from "../channels/consumer"
409
+
410
+ export default class extends Controller {
411
+ static targets = ["input", "messages", "typing"]
412
+ static values = { roomId: Number }
413
+
414
+ connect() {
415
+ this.subscription = consumer.subscriptions.create(
416
+ { channel: "ChatChannel", room_id: this.roomIdValue },
417
+ {
418
+ connected: () => this.connected(),
419
+ disconnected: () => this.disconnected(),
420
+ received: (data) => this.received(data)
421
+ }
422
+ )
423
+ }
424
+
425
+ disconnect() {
426
+ this.subscription?.unsubscribe()
427
+ }
428
+
429
+ connected() {
430
+ this.element.classList.remove("opacity-50")
431
+ console.log("Chat connected")
432
+ }
433
+
434
+ disconnected() {
435
+ this.element.classList.add("opacity-50")
436
+ console.log("Chat disconnected")
437
+ }
438
+
439
+ received(data) {
440
+ switch (data.type) {
441
+ case "typing":
442
+ this.showTyping(data.user_name)
443
+ break
444
+ case "message":
445
+ this.appendMessage(data.html)
446
+ break
447
+ }
448
+ }
449
+
450
+ send(event) {
451
+ event.preventDefault()
452
+ const body = this.inputTarget.value.trim()
453
+ if (!body) return
454
+
455
+ this.subscription.perform("speak", { body })
456
+ this.inputTarget.value = ""
457
+ }
458
+
459
+ typing() {
460
+ this.subscription.perform("typing")
461
+ }
462
+
463
+ appendMessage(html) {
464
+ this.messagesTarget.insertAdjacentHTML("beforeend", html)
465
+ this.scrollToBottom()
466
+ }
467
+
468
+ showTyping(userName) {
469
+ this.typingTarget.textContent = `${userName} está escribiendo...`
470
+ this.typingTarget.classList.remove("hidden")
471
+
472
+ clearTimeout(this.typingTimeout)
473
+ this.typingTimeout = setTimeout(() => {
474
+ this.typingTarget.classList.add("hidden")
475
+ }, 2000)
476
+ }
477
+
478
+ scrollToBottom() {
479
+ this.messagesTarget.scrollTop = this.messagesTarget.scrollHeight
480
+ }
481
+ }
482
+ ```
483
+
484
+ ## Testing
485
+
486
+ ```ruby
487
+ # spec/channels/chat_channel_spec.rb
488
+ require "rails_helper"
489
+
490
+ RSpec.describe ChatChannel, type: :channel do
491
+ let(:user) { create(:user) }
492
+ let(:room) { create(:room, users: [user]) }
493
+
494
+ before do
495
+ stub_connection current_user: user
496
+ end
497
+
498
+ describe "#subscribed" do
499
+ it "subscribes to the room stream" do
500
+ subscribe(room_id: room.id)
501
+ expect(subscription).to be_confirmed
502
+ expect(subscription).to have_stream_for(room)
503
+ end
504
+
505
+ it "rejects unauthorized users" do
506
+ other_room = create(:room)
507
+ subscribe(room_id: other_room.id)
508
+ expect(subscription).to be_rejected
509
+ end
510
+ end
511
+
512
+ describe "#speak" do
513
+ before { subscribe(room_id: room.id) }
514
+
515
+ it "creates a message" do
516
+ expect {
517
+ perform :speak, body: "Hello!"
518
+ }.to change(Message, :count).by(1)
519
+ end
520
+
521
+ it "broadcasts the message" do
522
+ expect {
523
+ perform :speak, body: "Hello!"
524
+ }.to have_broadcasted_to(room).with(
525
+ hash_including(user_id: user.id)
526
+ )
527
+ end
528
+ end
529
+ end
530
+
531
+ # spec/support/action_cable.rb
532
+ RSpec.configure do |config|
533
+ config.include ActionCable::TestHelper
534
+ end
535
+ ```
536
+
537
+ ## Debugging
538
+
539
+ ```ruby
540
+ # config/environments/development.rb
541
+ # Habilitar logs de Action Cable
542
+ config.action_cable.log_tags = [:action_cable]
543
+ config.log_level = :debug
544
+
545
+ # Para ver mensajes en consola del navegador
546
+ # En app/channels/application_cable/channel.rb
547
+ class Channel < ActionCable::Channel::Base
548
+ rescue_from Exception do |exception|
549
+ Rails.logger.error "Channel error: #{exception.message}"
550
+ transmit(error: exception.message)
551
+ end
552
+ end
553
+ ```
554
+
555
+ ## Checklist
556
+
557
+ - [ ] cable.yml configurado para cada environment
558
+ - [ ] CORS configurado en producción
559
+ - [ ] Autenticación en Connection
560
+ - [ ] Autorización en cada Canal
561
+ - [ ] Turbo Streams integrado donde aplica
562
+ - [ ] Rate limiting implementado
563
+ - [ ] Tests de canales escritos
564
+ - [ ] Manejo de errores y reconexión