superkick 0.1.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 (199) hide show
  1. checksums.yaml +7 -0
  2. data/CLA.md +91 -0
  3. data/CLAUDE.md +2226 -0
  4. data/CONTRIBUTING.md +104 -0
  5. data/LICENSE +108 -0
  6. data/LICENSE-COMMERCIAL.md +39 -0
  7. data/PLAN.md +161 -0
  8. data/README.md +1155 -0
  9. data/exe/superkick +6 -0
  10. data/lib/superkick/agent/runtime.rb +82 -0
  11. data/lib/superkick/agent/runtimes/local.rb +74 -0
  12. data/lib/superkick/agent/runtimes.rb +4 -0
  13. data/lib/superkick/agent.rb +209 -0
  14. data/lib/superkick/agent_store.rb +85 -0
  15. data/lib/superkick/attach/client.rb +245 -0
  16. data/lib/superkick/attach/protocol.rb +71 -0
  17. data/lib/superkick/attach/server.rb +371 -0
  18. data/lib/superkick/budget_checker.rb +120 -0
  19. data/lib/superkick/buffer/client.rb +91 -0
  20. data/lib/superkick/buffer/server.rb +127 -0
  21. data/lib/superkick/cli/agent.rb +524 -0
  22. data/lib/superkick/cli/completion.rb +591 -0
  23. data/lib/superkick/cli/goal.rb +71 -0
  24. data/lib/superkick/cli/mcp.rb +34 -0
  25. data/lib/superkick/cli/monitor.rb +47 -0
  26. data/lib/superkick/cli/notifier.rb +39 -0
  27. data/lib/superkick/cli/repository.rb +46 -0
  28. data/lib/superkick/cli/server.rb +106 -0
  29. data/lib/superkick/cli/setup.rb +166 -0
  30. data/lib/superkick/cli/spawner.rb +85 -0
  31. data/lib/superkick/cli/team.rb +407 -0
  32. data/lib/superkick/cli.rb +175 -0
  33. data/lib/superkick/client_registry.rb +30 -0
  34. data/lib/superkick/configuration.rb +178 -0
  35. data/lib/superkick/connection.rb +56 -0
  36. data/lib/superkick/control/client.rb +78 -0
  37. data/lib/superkick/control/reply.rb +43 -0
  38. data/lib/superkick/control/server.rb +1271 -0
  39. data/lib/superkick/cost_accumulator.rb +53 -0
  40. data/lib/superkick/cost_extractor.rb +65 -0
  41. data/lib/superkick/cost_poller.rb +70 -0
  42. data/lib/superkick/driver/profile_source.rb +134 -0
  43. data/lib/superkick/driver.rb +179 -0
  44. data/lib/superkick/drivers/claude_code.rb +110 -0
  45. data/lib/superkick/drivers/codex.rb +57 -0
  46. data/lib/superkick/drivers/copilot.rb +75 -0
  47. data/lib/superkick/drivers/gemini.rb +86 -0
  48. data/lib/superkick/drivers/goose.rb +74 -0
  49. data/lib/superkick/drivers.rb +16 -0
  50. data/lib/superkick/drop.rb +80 -0
  51. data/lib/superkick/drops.rb +76 -0
  52. data/lib/superkick/environment_executor.rb +90 -0
  53. data/lib/superkick/goal.rb +95 -0
  54. data/lib/superkick/goals/agent_exit.rb +41 -0
  55. data/lib/superkick/goals/agent_signal.rb +42 -0
  56. data/lib/superkick/goals/command.rb +103 -0
  57. data/lib/superkick/history_buffer.rb +38 -0
  58. data/lib/superkick/hosted/attach/bridge.rb +52 -0
  59. data/lib/superkick/hosted/attach/client.rb +208 -0
  60. data/lib/superkick/hosted/attach/relay.rb +313 -0
  61. data/lib/superkick/hosted/attach/relay_store.rb +48 -0
  62. data/lib/superkick/hosted/bridge.rb +263 -0
  63. data/lib/superkick/hosted/buffer/bridge.rb +42 -0
  64. data/lib/superkick/hosted/buffer/client.rb +63 -0
  65. data/lib/superkick/hosted/buffer/relay.rb +126 -0
  66. data/lib/superkick/hosted/buffer/relay_store.rb +42 -0
  67. data/lib/superkick/hosted/control/client.rb +84 -0
  68. data/lib/superkick/hosted/mcp_proxy.rb +144 -0
  69. data/lib/superkick/inject_handler.rb +24 -0
  70. data/lib/superkick/injection_guard.rb +26 -0
  71. data/lib/superkick/injection_queue.rb +177 -0
  72. data/lib/superkick/injector.rb +65 -0
  73. data/lib/superkick/input_buffer.rb +171 -0
  74. data/lib/superkick/integrations/bugsnag/README.md +98 -0
  75. data/lib/superkick/integrations/bugsnag/spawner.rb +307 -0
  76. data/lib/superkick/integrations/bugsnag/templates/error_opened.liquid +17 -0
  77. data/lib/superkick/integrations/bugsnag.rb +7 -0
  78. data/lib/superkick/integrations/circleci/README.md +75 -0
  79. data/lib/superkick/integrations/circleci/monitor.rb +185 -0
  80. data/lib/superkick/integrations/circleci/probe.rb +36 -0
  81. data/lib/superkick/integrations/circleci/templates/ci_failure.liquid +8 -0
  82. data/lib/superkick/integrations/circleci/templates/ci_success.liquid +1 -0
  83. data/lib/superkick/integrations/circleci.rb +8 -0
  84. data/lib/superkick/integrations/datadog/README.md +253 -0
  85. data/lib/superkick/integrations/datadog/alert_goal.rb +94 -0
  86. data/lib/superkick/integrations/datadog/alert_monitor.rb +163 -0
  87. data/lib/superkick/integrations/datadog/alert_spawner.rb +201 -0
  88. data/lib/superkick/integrations/datadog/notification_templates/default.liquid +10 -0
  89. data/lib/superkick/integrations/datadog/notifier.rb +294 -0
  90. data/lib/superkick/integrations/datadog/spawner.rb +201 -0
  91. data/lib/superkick/integrations/datadog/templates/alert_changed.liquid +8 -0
  92. data/lib/superkick/integrations/datadog/templates/alert_escalated.liquid +8 -0
  93. data/lib/superkick/integrations/datadog/templates/alert_recovered.liquid +14 -0
  94. data/lib/superkick/integrations/datadog/templates/alert_triggered.liquid +29 -0
  95. data/lib/superkick/integrations/datadog/templates/error_opened.liquid +15 -0
  96. data/lib/superkick/integrations/datadog.rb +14 -0
  97. data/lib/superkick/integrations/docker/README.md +256 -0
  98. data/lib/superkick/integrations/docker/client.rb +295 -0
  99. data/lib/superkick/integrations/docker/runtime.rb +218 -0
  100. data/lib/superkick/integrations/docker.rb +4 -0
  101. data/lib/superkick/integrations/git/repository_source.rb +66 -0
  102. data/lib/superkick/integrations/git/version_control.rb +119 -0
  103. data/lib/superkick/integrations/git.rb +8 -0
  104. data/lib/superkick/integrations/github/README.md +300 -0
  105. data/lib/superkick/integrations/github/check_failed_spawner.rb +199 -0
  106. data/lib/superkick/integrations/github/drops.rb +114 -0
  107. data/lib/superkick/integrations/github/goal.rb +135 -0
  108. data/lib/superkick/integrations/github/issue_goal.rb +104 -0
  109. data/lib/superkick/integrations/github/issue_spawner.rb +160 -0
  110. data/lib/superkick/integrations/github/monitor.rb +251 -0
  111. data/lib/superkick/integrations/github/probe.rb +30 -0
  112. data/lib/superkick/integrations/github/repository_source.rb +228 -0
  113. data/lib/superkick/integrations/github/templates/check_failed.liquid +10 -0
  114. data/lib/superkick/integrations/github/templates/ci_failure.liquid +5 -0
  115. data/lib/superkick/integrations/github/templates/ci_success.liquid +1 -0
  116. data/lib/superkick/integrations/github/templates/issue_opened.liquid +20 -0
  117. data/lib/superkick/integrations/github/templates/pr_comment.liquid +2 -0
  118. data/lib/superkick/integrations/github/templates/pr_review.liquid +4 -0
  119. data/lib/superkick/integrations/github.rb +16 -0
  120. data/lib/superkick/integrations/honeybadger/README.md +97 -0
  121. data/lib/superkick/integrations/honeybadger/notification_templates/default.liquid +8 -0
  122. data/lib/superkick/integrations/honeybadger/notifier.rb +250 -0
  123. data/lib/superkick/integrations/honeybadger/spawner.rb +214 -0
  124. data/lib/superkick/integrations/honeybadger/templates/error_opened.liquid +17 -0
  125. data/lib/superkick/integrations/honeybadger.rb +9 -0
  126. data/lib/superkick/integrations/shell/README.md +83 -0
  127. data/lib/superkick/integrations/shell/monitor.rb +87 -0
  128. data/lib/superkick/integrations/shell/templates/shell_alert.liquid +6 -0
  129. data/lib/superkick/integrations/shell/templates/shell_success.liquid +6 -0
  130. data/lib/superkick/integrations/shell.rb +7 -0
  131. data/lib/superkick/integrations/shortcut/README.md +193 -0
  132. data/lib/superkick/integrations/shortcut/drops.rb +91 -0
  133. data/lib/superkick/integrations/shortcut/monitor.rb +582 -0
  134. data/lib/superkick/integrations/shortcut/probe.rb +34 -0
  135. data/lib/superkick/integrations/shortcut/spawner.rb +264 -0
  136. data/lib/superkick/integrations/shortcut/templates/related_story_changed.liquid +6 -0
  137. data/lib/superkick/integrations/shortcut/templates/story_blocker.liquid +8 -0
  138. data/lib/superkick/integrations/shortcut/templates/story_comment.liquid +5 -0
  139. data/lib/superkick/integrations/shortcut/templates/story_description_changed.liquid +19 -0
  140. data/lib/superkick/integrations/shortcut/templates/story_owner_changed.liquid +10 -0
  141. data/lib/superkick/integrations/shortcut/templates/story_ready.liquid +41 -0
  142. data/lib/superkick/integrations/shortcut/templates/story_state_changed.liquid +9 -0
  143. data/lib/superkick/integrations/shortcut/templates/story_unblocked.liquid +5 -0
  144. data/lib/superkick/integrations/shortcut.rb +11 -0
  145. data/lib/superkick/integrations/slack/README.md +297 -0
  146. data/lib/superkick/integrations/slack/drops.rb +70 -0
  147. data/lib/superkick/integrations/slack/notifier.rb +426 -0
  148. data/lib/superkick/integrations/slack/spawner.rb +251 -0
  149. data/lib/superkick/integrations/slack/templates/default.liquid +17 -0
  150. data/lib/superkick/integrations/slack/templates/slack_reply.liquid +3 -0
  151. data/lib/superkick/integrations/slack/templates/spawn/slack_message.liquid +10 -0
  152. data/lib/superkick/integrations/slack/thread_monitor.rb +161 -0
  153. data/lib/superkick/integrations/slack.rb +12 -0
  154. data/lib/superkick/liquid.rb +129 -0
  155. data/lib/superkick/local/repository_source.rb +148 -0
  156. data/lib/superkick/mcp_server.rb +596 -0
  157. data/lib/superkick/monitor.rb +215 -0
  158. data/lib/superkick/notification_dispatcher.rb +280 -0
  159. data/lib/superkick/notifier.rb +173 -0
  160. data/lib/superkick/notifier_state_store.rb +55 -0
  161. data/lib/superkick/notifier_template.rb +121 -0
  162. data/lib/superkick/notifiers/command.rb +124 -0
  163. data/lib/superkick/notifiers/terminal_bell.rb +41 -0
  164. data/lib/superkick/output_logger.rb +54 -0
  165. data/lib/superkick/poller.rb +126 -0
  166. data/lib/superkick/process_runner.rb +87 -0
  167. data/lib/superkick/pty_proxy.rb +403 -0
  168. data/lib/superkick/registry.rb +75 -0
  169. data/lib/superkick/repository_source.rb +195 -0
  170. data/lib/superkick/server.rb +211 -0
  171. data/lib/superkick/session_recorder.rb +154 -0
  172. data/lib/superkick/setup.rb +160 -0
  173. data/lib/superkick/spawn/agent_spawner.rb +311 -0
  174. data/lib/superkick/spawn/approval_store.rb +113 -0
  175. data/lib/superkick/spawn/handler.rb +144 -0
  176. data/lib/superkick/spawn/injector.rb +119 -0
  177. data/lib/superkick/spawn/workflow_executor.rb +196 -0
  178. data/lib/superkick/spawn/workflow_validator.rb +77 -0
  179. data/lib/superkick/spawner.rb +67 -0
  180. data/lib/superkick/supervisor.rb +516 -0
  181. data/lib/superkick/team/artifact_store.rb +92 -0
  182. data/lib/superkick/team/log.rb +140 -0
  183. data/lib/superkick/team/log_entry_drop.rb +34 -0
  184. data/lib/superkick/team/log_monitor.rb +84 -0
  185. data/lib/superkick/team/log_notifier.rb +96 -0
  186. data/lib/superkick/team/log_store.rb +40 -0
  187. data/lib/superkick/template_filters.rb +24 -0
  188. data/lib/superkick/template_renderer.rb +223 -0
  189. data/lib/superkick/templates/team_log/planning_agent.liquid +38 -0
  190. data/lib/superkick/templates/team_log/team_digest.liquid +45 -0
  191. data/lib/superkick/templates/team_log/teammate_message.liquid +7 -0
  192. data/lib/superkick/templates/team_log/worker_kickoff.liquid +37 -0
  193. data/lib/superkick/templates/workflow/workflow_triggered.liquid +22 -0
  194. data/lib/superkick/version.rb +5 -0
  195. data/lib/superkick/version_control.rb +135 -0
  196. data/lib/superkick/yaml_config.rb +302 -0
  197. data/lib/superkick.rb +198 -0
  198. data/plan.md +267 -0
  199. metadata +404 -0
@@ -0,0 +1,591 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Superkick
4
+ class CLI < Thor
5
+ class Completion < Thor
6
+ package_name "superkick completion"
7
+
8
+ desc "install SHELL", "Print shell completion script (bash or zsh)"
9
+ def install(shell = "bash")
10
+ case shell.downcase
11
+ when "bash"
12
+ $stdout.puts bash_completion_script
13
+ when "zsh"
14
+ $stdout.puts zsh_completion_script
15
+ else
16
+ warn "Unsupported shell: #{shell}. Use 'bash' or 'zsh'."
17
+ exit(1)
18
+ end
19
+ end
20
+
21
+ # ── Hidden helper subcommands for dynamic completions ──────────────
22
+ # Each outputs newline-separated values suitable for shell completion.
23
+ # All silently return nothing when the server is unavailable.
24
+
25
+ desc "agents", "List agent IDs", hide: true
26
+ option :spawned, type: :boolean, default: false, desc: "Only spawned agents"
27
+ option :team, type: :string, desc: "Filter by team ID"
28
+ def agents
29
+ params = {}
30
+ params[:team_id] = options[:team] if options[:team]
31
+ params[:spawned_only] = true if options[:spawned]
32
+ result = control_client.request("list_agents", **params)
33
+ (result[:agents] || []).each { $stdout.puts it[:agent_id] }
34
+ rescue
35
+ nil
36
+ end
37
+
38
+ desc "team-ids", "List team IDs", hide: true
39
+ def team_ids
40
+ result = control_client.request("list_teams")
41
+ (result[:teams] || []).each { $stdout.puts it[:team_id] }
42
+ rescue
43
+ nil
44
+ end
45
+
46
+ desc "spawner-names", "List spawner names", hide: true
47
+ def spawner_names
48
+ result = control_client.request("list_spawners")
49
+ (result[:spawners] || []).each { $stdout.puts it[:name] }
50
+ rescue
51
+ nil
52
+ end
53
+
54
+ desc "approval-ids", "List pending approval IDs", hide: true
55
+ def approval_ids
56
+ result = control_client.request("list_approvals")
57
+ (result[:approvals] || []).each { $stdout.puts it[:id] }
58
+ rescue
59
+ nil
60
+ end
61
+
62
+ desc "monitor-types", "List registered monitor types", hide: true
63
+ def monitor_types
64
+ result = control_client.request("discover_monitors")
65
+ (result[:available_monitors] || []).each { $stdout.puts it[:type] }
66
+ rescue
67
+ nil
68
+ end
69
+
70
+ desc "monitors-for AGENT_ID", "List monitor names on an agent", hide: true
71
+ def monitors_for(agent_id)
72
+ result = control_client.request("list_monitors", agent_id:)
73
+ (result[:monitors] || []).each { $stdout.puts it[:name] }
74
+ rescue
75
+ nil
76
+ end
77
+
78
+ desc "notifier-types", "List registered notifier types", hide: true
79
+ def notifier_types
80
+ result = control_client.request("discover_notifiers")
81
+ (result[:available_notifiers] || []).each { $stdout.puts it[:type] }
82
+ rescue
83
+ nil
84
+ end
85
+
86
+ desc "notifiers-for AGENT_ID", "List notifier names on an agent", hide: true
87
+ def notifiers_for(agent_id)
88
+ result = control_client.request("list_notifiers", agent_id:)
89
+ (result[:notifiers] || []).each { $stdout.puts it[:name] }
90
+ rescue
91
+ nil
92
+ end
93
+
94
+ desc "goal-types", "List registered goal types", hide: true
95
+ def goal_types
96
+ result = control_client.request("discover_goals")
97
+ (result[:available_goals] || []).each { $stdout.puts it[:type] }
98
+ rescue
99
+ nil
100
+ end
101
+
102
+ desc "goal-statuses", "List valid goal statuses", hide: true
103
+ def goal_statuses
104
+ %w[completed failed errored in_progress].each { $stdout.puts it }
105
+ end
106
+
107
+ desc "driver-names", "List registered driver names", hide: true
108
+ def driver_names
109
+ Superkick::Driver.registered.each_key { $stdout.puts it }
110
+ end
111
+
112
+ desc "repository-names", "List configured repository names", hide: true
113
+ def repository_names
114
+ result = control_client.request("discover_repositories")
115
+ (result[:repositories] || []).each { $stdout.puts it[:name] }
116
+ rescue
117
+ nil
118
+ end
119
+
120
+ desc "artifact-authors TEAM_ID", "List artifact authors for a team", hide: true
121
+ def artifact_authors(team_id)
122
+ result = control_client.request("list_team_artifacts", team_id:)
123
+ seen = {}
124
+ (result[:artifacts] || []).each do |a|
125
+ unless seen[a[:author]]
126
+ $stdout.puts a[:author]
127
+ seen[a[:author]] = true
128
+ end
129
+ end
130
+ rescue
131
+ nil
132
+ end
133
+
134
+ desc "artifact-names TEAM_ID AUTHOR", "List artifact names for a team/author", hide: true
135
+ def artifact_names(team_id, author)
136
+ result = control_client.request("list_team_artifacts", team_id:, author:)
137
+ (result[:artifacts] || []).each { $stdout.puts it[:name] }
138
+ rescue
139
+ nil
140
+ end
141
+
142
+ default_command :install
143
+
144
+ private
145
+
146
+ def control_client
147
+ @control_client ||= Control.client_from
148
+ end
149
+
150
+ def bash_completion_script
151
+ <<~'BASH'
152
+ # Superkick shell completion — add to .bashrc or .bash_profile:
153
+ # eval "$(superkick completion bash)"
154
+
155
+ _superkick_completions() {
156
+ local IFS=$'\n'
157
+ COMPREPLY=($(compgen -W "$1" -- "${COMP_WORDS[COMP_CWORD]}"))
158
+ }
159
+
160
+ _superkick_file_or_value() {
161
+ local cur="${COMP_WORDS[COMP_CWORD]}"
162
+ if [[ "$cur" == @* ]]; then
163
+ # Strip @ prefix, complete file paths, then re-add @
164
+ local prefix="${cur#@}"
165
+ COMPREPLY=($(compgen -f -- "$prefix"))
166
+ COMPREPLY=("${COMPREPLY[@]/#/@}")
167
+ fi
168
+ }
169
+
170
+ _superkick() {
171
+ local cur prev words cword
172
+ cur="${COMP_WORDS[COMP_CWORD]}"
173
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
174
+ words=("${COMP_WORDS[@]}")
175
+ cword=$COMP_CWORD
176
+
177
+ # Top-level commands
178
+ if [[ $cword -eq 1 ]]; then
179
+ _superkick_completions "server agent monitor spawner mcp team goal notifier repository approve reject approvals completion setup help"
180
+ return
181
+ fi
182
+
183
+ local subcmd="${words[1]}"
184
+
185
+ case "$subcmd" in
186
+ agent)
187
+ if [[ $cword -eq 2 ]]; then
188
+ _superkick_completions "start list cost log stop attach claim unclaim report-cost add-monitor remove-monitor add-notifier remove-notifier help"
189
+ return
190
+ fi
191
+
192
+ local agent_subcmd="${words[2]}"
193
+ case "$agent_subcmd" in
194
+ log|attach|report-cost|add-monitor|add-notifier)
195
+ if [[ $cword -eq 3 ]]; then
196
+ _superkick_completions "$(superkick completion agents 2>/dev/null)"
197
+ fi
198
+ ;;
199
+ stop|claim)
200
+ if [[ $cword -eq 3 ]]; then
201
+ _superkick_completions "$(superkick completion agents --spawned 2>/dev/null)"
202
+ fi
203
+ ;;
204
+ unclaim)
205
+ if [[ $cword -eq 3 ]]; then
206
+ _superkick_completions "$(superkick completion agents --spawned 2>/dev/null)"
207
+ fi
208
+ ;;
209
+ cost)
210
+ if [[ $cword -eq 3 ]]; then
211
+ _superkick_completions "$(superkick completion agents 2>/dev/null)"
212
+ fi
213
+ ;;
214
+ remove-monitor)
215
+ if [[ $cword -eq 3 ]]; then
216
+ _superkick_completions "$(superkick completion agents 2>/dev/null)"
217
+ elif [[ $cword -eq 4 ]]; then
218
+ _superkick_completions "$(superkick completion monitors-for "${words[3]}" 2>/dev/null)"
219
+ fi
220
+ ;;
221
+ remove-notifier)
222
+ if [[ $cword -eq 3 ]]; then
223
+ _superkick_completions "$(superkick completion agents 2>/dev/null)"
224
+ elif [[ $cword -eq 4 ]]; then
225
+ _superkick_completions "$(superkick completion notifiers-for "${words[3]}" 2>/dev/null)"
226
+ fi
227
+ ;;
228
+ start)
229
+ case "$prev" in
230
+ --driver|-d) _superkick_completions "$(superkick completion driver-names 2>/dev/null)" ;;
231
+ --team) _superkick_completions "$(superkick completion team-ids 2>/dev/null)" ;;
232
+ --driver_config_dir|--driver_command) compopt -o filenames; COMPREPLY=($(compgen -f -- "$cur")) ;;
233
+ esac
234
+ ;;
235
+ esac
236
+
237
+ # Option value completions for add-monitor/add-notifier
238
+ case "$agent_subcmd" in
239
+ add-monitor)
240
+ case "$prev" in
241
+ --type|-t) _superkick_completions "$(superkick completion monitor-types 2>/dev/null)" ;;
242
+ --config|-c) _superkick_file_or_value ;;
243
+ esac
244
+ ;;
245
+ add-notifier)
246
+ case "$prev" in
247
+ --type|-t) _superkick_completions "$(superkick completion notifier-types 2>/dev/null)" ;;
248
+ --config|-c) _superkick_file_or_value ;;
249
+ esac
250
+ ;;
251
+ esac
252
+ ;;
253
+
254
+ server)
255
+ if [[ $cword -eq 2 ]]; then
256
+ _superkick_completions "start stop status log help"
257
+ fi
258
+ ;;
259
+
260
+ monitor)
261
+ if [[ $cword -eq 2 ]]; then
262
+ _superkick_completions "list install-templates help"
263
+ fi
264
+ ;;
265
+
266
+ spawner)
267
+ if [[ $cword -eq 2 ]]; then
268
+ _superkick_completions "list start stop install-templates help"
269
+ elif [[ $cword -eq 3 ]]; then
270
+ case "${words[2]}" in
271
+ start|stop) _superkick_completions "$(superkick completion spawner-names 2>/dev/null)" ;;
272
+ esac
273
+ fi
274
+ ;;
275
+
276
+ mcp)
277
+ if [[ $cword -eq 2 ]]; then
278
+ _superkick_completions "start configure help"
279
+ fi
280
+ ;;
281
+
282
+ team)
283
+ if [[ $cword -eq 2 ]]; then
284
+ _superkick_completions "list status watch stop artifacts artifact message spawn-worker help"
285
+ return
286
+ fi
287
+
288
+ local team_subcmd="${words[2]}"
289
+ case "$team_subcmd" in
290
+ status|watch|stop|message|spawn-worker)
291
+ if [[ $cword -eq 3 ]]; then
292
+ _superkick_completions "$(superkick completion team-ids 2>/dev/null)"
293
+ fi
294
+ ;;
295
+ artifacts)
296
+ if [[ $cword -eq 3 ]]; then
297
+ _superkick_completions "$(superkick completion team-ids 2>/dev/null)"
298
+ fi
299
+ case "$prev" in
300
+ --author) _superkick_completions "$(superkick completion artifact-authors "${words[3]}" 2>/dev/null)" ;;
301
+ esac
302
+ ;;
303
+ artifact)
304
+ if [[ $cword -eq 3 ]]; then
305
+ _superkick_completions "$(superkick completion team-ids 2>/dev/null)"
306
+ elif [[ $cword -eq 4 ]]; then
307
+ _superkick_completions "$(superkick completion artifact-authors "${words[3]}" 2>/dev/null)"
308
+ elif [[ $cword -eq 5 ]]; then
309
+ _superkick_completions "$(superkick completion artifact-names "${words[3]}" "${words[4]}" 2>/dev/null)"
310
+ fi
311
+ ;;
312
+ esac
313
+
314
+ # Option value completions for spawn-worker
315
+ if [[ "$team_subcmd" == "spawn-worker" ]]; then
316
+ case "$prev" in
317
+ --repository|-r) _superkick_completions "$(superkick completion repository-names 2>/dev/null)" ;;
318
+ --goal_type) _superkick_completions "$(superkick completion goal-types 2>/dev/null)" ;;
319
+ --depends_on) _superkick_completions "$(superkick completion agents --team "${words[3]}" 2>/dev/null)" ;;
320
+ esac
321
+ fi
322
+ ;;
323
+
324
+ goal)
325
+ if [[ $cword -eq 2 ]]; then
326
+ _superkick_completions "list signal help"
327
+ elif [[ $cword -eq 3 ]]; then
328
+ case "${words[2]}" in
329
+ signal) _superkick_completions "$(superkick completion agents --spawned 2>/dev/null)" ;;
330
+ esac
331
+ elif [[ $cword -eq 4 ]]; then
332
+ case "${words[2]}" in
333
+ signal) _superkick_completions "$(superkick completion goal-statuses 2>/dev/null)" ;;
334
+ esac
335
+ fi
336
+ ;;
337
+
338
+ notifier)
339
+ if [[ $cword -eq 2 ]]; then
340
+ _superkick_completions "list help"
341
+ fi
342
+ ;;
343
+
344
+ repository)
345
+ if [[ $cword -eq 2 ]]; then
346
+ _superkick_completions "list help"
347
+ fi
348
+ ;;
349
+
350
+ approve)
351
+ if [[ $cword -eq 2 ]]; then
352
+ _superkick_completions "$(superkick completion approval-ids 2>/dev/null)"
353
+ fi
354
+ ;;
355
+
356
+ reject)
357
+ if [[ $cword -eq 2 ]]; then
358
+ _superkick_completions "$(superkick completion approval-ids 2>/dev/null)"
359
+ fi
360
+ ;;
361
+
362
+ completion)
363
+ if [[ $cword -eq 2 ]]; then
364
+ _superkick_completions "install bash zsh"
365
+ fi
366
+ ;;
367
+ esac
368
+ }
369
+
370
+ complete -F _superkick superkick
371
+ BASH
372
+ end
373
+
374
+ def zsh_completion_script
375
+ <<~'ZSH'
376
+ # Superkick shell completion — add to .zshrc:
377
+ # eval "$(superkick completion zsh)"
378
+
379
+ _superkick_from() {
380
+ local completions
381
+ completions=(${(f)"$(eval "$@" 2>/dev/null)"})
382
+ compadd -a completions
383
+ }
384
+
385
+ _superkick_file_or_value() {
386
+ local cur="${words[CURRENT]}"
387
+ if [[ "$cur" == @* ]]; then
388
+ # Strip @ prefix, complete file paths, then re-add @
389
+ local prefix="${cur#@}"
390
+ local -a files
391
+ files=(${(f)"$(compgen -f -- "$prefix" 2>/dev/null)"})
392
+ if [[ ${#files} -eq 0 ]]; then
393
+ _files -W / -P @
394
+ else
395
+ compadd -p @ -a files
396
+ fi
397
+ fi
398
+ }
399
+
400
+ _superkick() {
401
+ local -a subcmds agent_cmds server_cmds monitor_cmds spawner_cmds mcp_cmds
402
+ local -a team_cmds goal_cmds notifier_cmds repository_cmds
403
+
404
+ subcmds=(server agent monitor spawner mcp team goal notifier repository approve reject approvals completion setup help)
405
+ agent_cmds=(start list cost log stop attach claim unclaim report-cost add-monitor remove-monitor add-notifier remove-notifier help)
406
+ server_cmds=(start stop status log help)
407
+ monitor_cmds=(list install-templates help)
408
+ spawner_cmds=(list start stop install-templates help)
409
+ mcp_cmds=(start configure help)
410
+ team_cmds=(list status watch stop artifacts artifact message spawn-worker help)
411
+ goal_cmds=(list signal help)
412
+ notifier_cmds=(list help)
413
+ repository_cmds=(list help)
414
+
415
+ if (( CURRENT == 2 )); then
416
+ _describe 'command' subcmds
417
+ return
418
+ fi
419
+
420
+ case "${words[2]}" in
421
+ agent)
422
+ if (( CURRENT == 3 )); then
423
+ _describe 'subcommand' agent_cmds
424
+ return
425
+ fi
426
+
427
+ local agent_subcmd="${words[3]}"
428
+ case "$agent_subcmd" in
429
+ log|attach|report-cost|add-monitor|add-notifier)
430
+ if (( CURRENT == 4 )); then
431
+ _superkick_from "superkick completion agents"
432
+ fi
433
+ ;;
434
+ stop|claim|unclaim)
435
+ if (( CURRENT == 4 )); then
436
+ _superkick_from "superkick completion agents --spawned"
437
+ fi
438
+ ;;
439
+ cost)
440
+ if (( CURRENT == 4 )); then
441
+ _superkick_from "superkick completion agents"
442
+ fi
443
+ ;;
444
+ remove-monitor)
445
+ if (( CURRENT == 4 )); then
446
+ _superkick_from "superkick completion agents"
447
+ elif (( CURRENT == 5 )); then
448
+ _superkick_from "superkick completion monitors-for '${words[4]}'"
449
+ fi
450
+ ;;
451
+ remove-notifier)
452
+ if (( CURRENT == 4 )); then
453
+ _superkick_from "superkick completion agents"
454
+ elif (( CURRENT == 5 )); then
455
+ _superkick_from "superkick completion notifiers-for '${words[4]}'"
456
+ fi
457
+ ;;
458
+ start)
459
+ case "${words[CURRENT-1]}" in
460
+ --driver|-d) _superkick_from "superkick completion driver-names" ;;
461
+ --team) _superkick_from "superkick completion team-ids" ;;
462
+ --driver_config_dir|--driver_command) _files ;;
463
+ esac
464
+ ;;
465
+ esac
466
+
467
+ # Option value completions
468
+ case "$agent_subcmd" in
469
+ add-monitor)
470
+ case "${words[CURRENT-1]}" in
471
+ --type|-t) _superkick_from "superkick completion monitor-types" ;;
472
+ --config|-c) _superkick_file_or_value ;;
473
+ esac
474
+ ;;
475
+ add-notifier)
476
+ case "${words[CURRENT-1]}" in
477
+ --type|-t) _superkick_from "superkick completion notifier-types" ;;
478
+ --config|-c) _superkick_file_or_value ;;
479
+ esac
480
+ ;;
481
+ esac
482
+ ;;
483
+
484
+ server)
485
+ if (( CURRENT == 3 )); then _describe 'subcommand' server_cmds; fi ;;
486
+
487
+ monitor)
488
+ if (( CURRENT == 3 )); then _describe 'subcommand' monitor_cmds; fi ;;
489
+
490
+ spawner)
491
+ if (( CURRENT == 3 )); then
492
+ _describe 'subcommand' spawner_cmds
493
+ elif (( CURRENT == 4 )); then
494
+ case "${words[3]}" in
495
+ start|stop) _superkick_from "superkick completion spawner-names" ;;
496
+ esac
497
+ fi
498
+ ;;
499
+
500
+ mcp)
501
+ if (( CURRENT == 3 )); then _describe 'subcommand' mcp_cmds; fi ;;
502
+
503
+ team)
504
+ if (( CURRENT == 3 )); then
505
+ _describe 'subcommand' team_cmds
506
+ return
507
+ fi
508
+
509
+ local team_subcmd="${words[3]}"
510
+ case "$team_subcmd" in
511
+ status|watch|stop|message|spawn-worker)
512
+ if (( CURRENT == 4 )); then
513
+ _superkick_from "superkick completion team-ids"
514
+ fi
515
+ ;;
516
+ artifacts)
517
+ if (( CURRENT == 4 )); then
518
+ _superkick_from "superkick completion team-ids"
519
+ fi
520
+ case "${words[CURRENT-1]}" in
521
+ --author) _superkick_from "superkick completion artifact-authors '${words[4]}'" ;;
522
+ esac
523
+ ;;
524
+ artifact)
525
+ if (( CURRENT == 4 )); then
526
+ _superkick_from "superkick completion team-ids"
527
+ elif (( CURRENT == 5 )); then
528
+ _superkick_from "superkick completion artifact-authors '${words[4]}'"
529
+ elif (( CURRENT == 6 )); then
530
+ _superkick_from "superkick completion artifact-names '${words[4]}' '${words[5]}'"
531
+ fi
532
+ ;;
533
+ esac
534
+
535
+ # Option value completions for spawn-worker
536
+ if [[ "$team_subcmd" == "spawn-worker" ]]; then
537
+ case "${words[CURRENT-1]}" in
538
+ --repository|-r) _superkick_from "superkick completion repository-names" ;;
539
+ --goal_type) _superkick_from "superkick completion goal-types" ;;
540
+ --depends_on) _superkick_from "superkick completion agents --team '${words[4]}'" ;;
541
+ esac
542
+ fi
543
+ ;;
544
+
545
+ goal)
546
+ if (( CURRENT == 3 )); then
547
+ _describe 'subcommand' goal_cmds
548
+ elif (( CURRENT == 4 )); then
549
+ case "${words[3]}" in
550
+ signal) _superkick_from "superkick completion agents --spawned" ;;
551
+ esac
552
+ elif (( CURRENT == 5 )); then
553
+ case "${words[3]}" in
554
+ signal) _superkick_from "superkick completion goal-statuses" ;;
555
+ esac
556
+ fi
557
+ ;;
558
+
559
+ notifier)
560
+ if (( CURRENT == 3 )); then _describe 'subcommand' notifier_cmds; fi ;;
561
+
562
+ repository)
563
+ if (( CURRENT == 3 )); then _describe 'subcommand' repository_cmds; fi ;;
564
+
565
+ approve)
566
+ if (( CURRENT == 3 )); then
567
+ _superkick_from "superkick completion approval-ids"
568
+ fi
569
+ ;;
570
+
571
+ reject)
572
+ if (( CURRENT == 3 )); then
573
+ _superkick_from "superkick completion approval-ids"
574
+ fi
575
+ ;;
576
+
577
+ completion)
578
+ if (( CURRENT == 3 )); then
579
+ local -a comp_cmds=(install bash zsh)
580
+ _describe 'subcommand' comp_cmds
581
+ fi
582
+ ;;
583
+ esac
584
+ }
585
+
586
+ compdef _superkick superkick
587
+ ZSH
588
+ end
589
+ end
590
+ end
591
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Superkick
4
+ class CLI < Thor
5
+ class GoalCmd < Thor
6
+ package_name "superkick goal"
7
+
8
+ desc "list", "List available goal types"
9
+ def list
10
+ client = Control.client_from
11
+
12
+ unless client.alive?
13
+ $stdout.puts "Superkick server is not running."
14
+ return
15
+ end
16
+
17
+ result = client.request("discover_goals")
18
+ goals = result[:available_goals] || []
19
+
20
+ if goals.empty?
21
+ $stdout.puts "No goal types registered."
22
+ return
23
+ end
24
+
25
+ goals.each do |goal|
26
+ $stdout.puts "#{goal[:type]}:"
27
+ $stdout.puts " #{goal[:description]}" if goal[:description]
28
+ $stdout.puts " required config: #{goal[:required_config].join(", ")}" if goal[:required_config]&.any?
29
+ $stdout.puts ""
30
+ end
31
+ rescue Control::Client::ServerUnavailable
32
+ $stdout.puts "Superkick server is not running."
33
+ end
34
+
35
+ desc "signal AGENT_ID STATUS", "Signal a spawned agent's goal status"
36
+ long_desc <<~DESC
37
+ Signal the goal status of a spawned agent. Useful when a human has claimed
38
+ an agent and completed its task manually, or to force-complete a stuck agent
39
+ so downstream workflows fire correctly.
40
+
41
+ STATUS must be one of: completed, failed, errored, in_progress
42
+ DESC
43
+ option :summary, type: :string, aliases: "-s",
44
+ desc: "Brief summary of the outcome (forwarded to retry agents in workflow chains)"
45
+ def signal(agent_id, status)
46
+ unless %w[completed failed errored in_progress].include?(status)
47
+ warn "Invalid status: #{status}. Must be one of: completed, failed, errored, in_progress"
48
+ exit(1)
49
+ end
50
+
51
+ client = Control.client_from
52
+ result = client.request("signal_goal",
53
+ agent_id:,
54
+ status:,
55
+ summary: options[:summary])
56
+
57
+ if result.success?
58
+ $stdout.puts "Goal signaled: #{agent_id} -> #{status}"
59
+ else
60
+ warn "Error: #{result.error_message}"
61
+ exit(1)
62
+ end
63
+ rescue Control::Client::ServerUnavailable
64
+ warn "Superkick server is not running."
65
+ exit(1)
66
+ end
67
+
68
+ default_command :list
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Superkick
4
+ class CLI < Thor
5
+ class Mcp < Thor
6
+ package_name "superkick mcp"
7
+
8
+ desc "start", "Start the MCP stdio server (called by AI CLI, not users)"
9
+ def start
10
+ Superkick.load_config!
11
+
12
+ if Superkick.config.server_type == :hosted
13
+ Hosted::McpProxy.start
14
+ else
15
+ McpServer.start
16
+ end
17
+ end
18
+
19
+ desc "configure", "Configure the MCP server for the active driver"
20
+ def configure
21
+ Superkick.load_config!
22
+
23
+ unless Superkick.driver
24
+ warn "No driver configured. Set `driver:` in ~/.superkick/config.yml first."
25
+ exit(1)
26
+ end
27
+
28
+ Superkick.driver.install_mcp(exe_path: File.expand_path($PROGRAM_NAME))
29
+ end
30
+
31
+ default_command :start
32
+ end
33
+ end
34
+ end