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.
- checksums.yaml +7 -0
- data/CLA.md +91 -0
- data/CLAUDE.md +2226 -0
- data/CONTRIBUTING.md +104 -0
- data/LICENSE +108 -0
- data/LICENSE-COMMERCIAL.md +39 -0
- data/PLAN.md +161 -0
- data/README.md +1155 -0
- data/exe/superkick +6 -0
- data/lib/superkick/agent/runtime.rb +82 -0
- data/lib/superkick/agent/runtimes/local.rb +74 -0
- data/lib/superkick/agent/runtimes.rb +4 -0
- data/lib/superkick/agent.rb +209 -0
- data/lib/superkick/agent_store.rb +85 -0
- data/lib/superkick/attach/client.rb +245 -0
- data/lib/superkick/attach/protocol.rb +71 -0
- data/lib/superkick/attach/server.rb +371 -0
- data/lib/superkick/budget_checker.rb +120 -0
- data/lib/superkick/buffer/client.rb +91 -0
- data/lib/superkick/buffer/server.rb +127 -0
- data/lib/superkick/cli/agent.rb +524 -0
- data/lib/superkick/cli/completion.rb +591 -0
- data/lib/superkick/cli/goal.rb +71 -0
- data/lib/superkick/cli/mcp.rb +34 -0
- data/lib/superkick/cli/monitor.rb +47 -0
- data/lib/superkick/cli/notifier.rb +39 -0
- data/lib/superkick/cli/repository.rb +46 -0
- data/lib/superkick/cli/server.rb +106 -0
- data/lib/superkick/cli/setup.rb +166 -0
- data/lib/superkick/cli/spawner.rb +85 -0
- data/lib/superkick/cli/team.rb +407 -0
- data/lib/superkick/cli.rb +175 -0
- data/lib/superkick/client_registry.rb +30 -0
- data/lib/superkick/configuration.rb +178 -0
- data/lib/superkick/connection.rb +56 -0
- data/lib/superkick/control/client.rb +78 -0
- data/lib/superkick/control/reply.rb +43 -0
- data/lib/superkick/control/server.rb +1271 -0
- data/lib/superkick/cost_accumulator.rb +53 -0
- data/lib/superkick/cost_extractor.rb +65 -0
- data/lib/superkick/cost_poller.rb +70 -0
- data/lib/superkick/driver/profile_source.rb +134 -0
- data/lib/superkick/driver.rb +179 -0
- data/lib/superkick/drivers/claude_code.rb +110 -0
- data/lib/superkick/drivers/codex.rb +57 -0
- data/lib/superkick/drivers/copilot.rb +75 -0
- data/lib/superkick/drivers/gemini.rb +86 -0
- data/lib/superkick/drivers/goose.rb +74 -0
- data/lib/superkick/drivers.rb +16 -0
- data/lib/superkick/drop.rb +80 -0
- data/lib/superkick/drops.rb +76 -0
- data/lib/superkick/environment_executor.rb +90 -0
- data/lib/superkick/goal.rb +95 -0
- data/lib/superkick/goals/agent_exit.rb +41 -0
- data/lib/superkick/goals/agent_signal.rb +42 -0
- data/lib/superkick/goals/command.rb +103 -0
- data/lib/superkick/history_buffer.rb +38 -0
- data/lib/superkick/hosted/attach/bridge.rb +52 -0
- data/lib/superkick/hosted/attach/client.rb +208 -0
- data/lib/superkick/hosted/attach/relay.rb +313 -0
- data/lib/superkick/hosted/attach/relay_store.rb +48 -0
- data/lib/superkick/hosted/bridge.rb +263 -0
- data/lib/superkick/hosted/buffer/bridge.rb +42 -0
- data/lib/superkick/hosted/buffer/client.rb +63 -0
- data/lib/superkick/hosted/buffer/relay.rb +126 -0
- data/lib/superkick/hosted/buffer/relay_store.rb +42 -0
- data/lib/superkick/hosted/control/client.rb +84 -0
- data/lib/superkick/hosted/mcp_proxy.rb +144 -0
- data/lib/superkick/inject_handler.rb +24 -0
- data/lib/superkick/injection_guard.rb +26 -0
- data/lib/superkick/injection_queue.rb +177 -0
- data/lib/superkick/injector.rb +65 -0
- data/lib/superkick/input_buffer.rb +171 -0
- data/lib/superkick/integrations/bugsnag/README.md +98 -0
- data/lib/superkick/integrations/bugsnag/spawner.rb +307 -0
- data/lib/superkick/integrations/bugsnag/templates/error_opened.liquid +17 -0
- data/lib/superkick/integrations/bugsnag.rb +7 -0
- data/lib/superkick/integrations/circleci/README.md +75 -0
- data/lib/superkick/integrations/circleci/monitor.rb +185 -0
- data/lib/superkick/integrations/circleci/probe.rb +36 -0
- data/lib/superkick/integrations/circleci/templates/ci_failure.liquid +8 -0
- data/lib/superkick/integrations/circleci/templates/ci_success.liquid +1 -0
- data/lib/superkick/integrations/circleci.rb +8 -0
- data/lib/superkick/integrations/datadog/README.md +253 -0
- data/lib/superkick/integrations/datadog/alert_goal.rb +94 -0
- data/lib/superkick/integrations/datadog/alert_monitor.rb +163 -0
- data/lib/superkick/integrations/datadog/alert_spawner.rb +201 -0
- data/lib/superkick/integrations/datadog/notification_templates/default.liquid +10 -0
- data/lib/superkick/integrations/datadog/notifier.rb +294 -0
- data/lib/superkick/integrations/datadog/spawner.rb +201 -0
- data/lib/superkick/integrations/datadog/templates/alert_changed.liquid +8 -0
- data/lib/superkick/integrations/datadog/templates/alert_escalated.liquid +8 -0
- data/lib/superkick/integrations/datadog/templates/alert_recovered.liquid +14 -0
- data/lib/superkick/integrations/datadog/templates/alert_triggered.liquid +29 -0
- data/lib/superkick/integrations/datadog/templates/error_opened.liquid +15 -0
- data/lib/superkick/integrations/datadog.rb +14 -0
- data/lib/superkick/integrations/docker/README.md +256 -0
- data/lib/superkick/integrations/docker/client.rb +295 -0
- data/lib/superkick/integrations/docker/runtime.rb +218 -0
- data/lib/superkick/integrations/docker.rb +4 -0
- data/lib/superkick/integrations/git/repository_source.rb +66 -0
- data/lib/superkick/integrations/git/version_control.rb +119 -0
- data/lib/superkick/integrations/git.rb +8 -0
- data/lib/superkick/integrations/github/README.md +300 -0
- data/lib/superkick/integrations/github/check_failed_spawner.rb +199 -0
- data/lib/superkick/integrations/github/drops.rb +114 -0
- data/lib/superkick/integrations/github/goal.rb +135 -0
- data/lib/superkick/integrations/github/issue_goal.rb +104 -0
- data/lib/superkick/integrations/github/issue_spawner.rb +160 -0
- data/lib/superkick/integrations/github/monitor.rb +251 -0
- data/lib/superkick/integrations/github/probe.rb +30 -0
- data/lib/superkick/integrations/github/repository_source.rb +228 -0
- data/lib/superkick/integrations/github/templates/check_failed.liquid +10 -0
- data/lib/superkick/integrations/github/templates/ci_failure.liquid +5 -0
- data/lib/superkick/integrations/github/templates/ci_success.liquid +1 -0
- data/lib/superkick/integrations/github/templates/issue_opened.liquid +20 -0
- data/lib/superkick/integrations/github/templates/pr_comment.liquid +2 -0
- data/lib/superkick/integrations/github/templates/pr_review.liquid +4 -0
- data/lib/superkick/integrations/github.rb +16 -0
- data/lib/superkick/integrations/honeybadger/README.md +97 -0
- data/lib/superkick/integrations/honeybadger/notification_templates/default.liquid +8 -0
- data/lib/superkick/integrations/honeybadger/notifier.rb +250 -0
- data/lib/superkick/integrations/honeybadger/spawner.rb +214 -0
- data/lib/superkick/integrations/honeybadger/templates/error_opened.liquid +17 -0
- data/lib/superkick/integrations/honeybadger.rb +9 -0
- data/lib/superkick/integrations/shell/README.md +83 -0
- data/lib/superkick/integrations/shell/monitor.rb +87 -0
- data/lib/superkick/integrations/shell/templates/shell_alert.liquid +6 -0
- data/lib/superkick/integrations/shell/templates/shell_success.liquid +6 -0
- data/lib/superkick/integrations/shell.rb +7 -0
- data/lib/superkick/integrations/shortcut/README.md +193 -0
- data/lib/superkick/integrations/shortcut/drops.rb +91 -0
- data/lib/superkick/integrations/shortcut/monitor.rb +582 -0
- data/lib/superkick/integrations/shortcut/probe.rb +34 -0
- data/lib/superkick/integrations/shortcut/spawner.rb +264 -0
- data/lib/superkick/integrations/shortcut/templates/related_story_changed.liquid +6 -0
- data/lib/superkick/integrations/shortcut/templates/story_blocker.liquid +8 -0
- data/lib/superkick/integrations/shortcut/templates/story_comment.liquid +5 -0
- data/lib/superkick/integrations/shortcut/templates/story_description_changed.liquid +19 -0
- data/lib/superkick/integrations/shortcut/templates/story_owner_changed.liquid +10 -0
- data/lib/superkick/integrations/shortcut/templates/story_ready.liquid +41 -0
- data/lib/superkick/integrations/shortcut/templates/story_state_changed.liquid +9 -0
- data/lib/superkick/integrations/shortcut/templates/story_unblocked.liquid +5 -0
- data/lib/superkick/integrations/shortcut.rb +11 -0
- data/lib/superkick/integrations/slack/README.md +297 -0
- data/lib/superkick/integrations/slack/drops.rb +70 -0
- data/lib/superkick/integrations/slack/notifier.rb +426 -0
- data/lib/superkick/integrations/slack/spawner.rb +251 -0
- data/lib/superkick/integrations/slack/templates/default.liquid +17 -0
- data/lib/superkick/integrations/slack/templates/slack_reply.liquid +3 -0
- data/lib/superkick/integrations/slack/templates/spawn/slack_message.liquid +10 -0
- data/lib/superkick/integrations/slack/thread_monitor.rb +161 -0
- data/lib/superkick/integrations/slack.rb +12 -0
- data/lib/superkick/liquid.rb +129 -0
- data/lib/superkick/local/repository_source.rb +148 -0
- data/lib/superkick/mcp_server.rb +596 -0
- data/lib/superkick/monitor.rb +215 -0
- data/lib/superkick/notification_dispatcher.rb +280 -0
- data/lib/superkick/notifier.rb +173 -0
- data/lib/superkick/notifier_state_store.rb +55 -0
- data/lib/superkick/notifier_template.rb +121 -0
- data/lib/superkick/notifiers/command.rb +124 -0
- data/lib/superkick/notifiers/terminal_bell.rb +41 -0
- data/lib/superkick/output_logger.rb +54 -0
- data/lib/superkick/poller.rb +126 -0
- data/lib/superkick/process_runner.rb +87 -0
- data/lib/superkick/pty_proxy.rb +403 -0
- data/lib/superkick/registry.rb +75 -0
- data/lib/superkick/repository_source.rb +195 -0
- data/lib/superkick/server.rb +211 -0
- data/lib/superkick/session_recorder.rb +154 -0
- data/lib/superkick/setup.rb +160 -0
- data/lib/superkick/spawn/agent_spawner.rb +311 -0
- data/lib/superkick/spawn/approval_store.rb +113 -0
- data/lib/superkick/spawn/handler.rb +144 -0
- data/lib/superkick/spawn/injector.rb +119 -0
- data/lib/superkick/spawn/workflow_executor.rb +196 -0
- data/lib/superkick/spawn/workflow_validator.rb +77 -0
- data/lib/superkick/spawner.rb +67 -0
- data/lib/superkick/supervisor.rb +516 -0
- data/lib/superkick/team/artifact_store.rb +92 -0
- data/lib/superkick/team/log.rb +140 -0
- data/lib/superkick/team/log_entry_drop.rb +34 -0
- data/lib/superkick/team/log_monitor.rb +84 -0
- data/lib/superkick/team/log_notifier.rb +96 -0
- data/lib/superkick/team/log_store.rb +40 -0
- data/lib/superkick/template_filters.rb +24 -0
- data/lib/superkick/template_renderer.rb +223 -0
- data/lib/superkick/templates/team_log/planning_agent.liquid +38 -0
- data/lib/superkick/templates/team_log/team_digest.liquid +45 -0
- data/lib/superkick/templates/team_log/teammate_message.liquid +7 -0
- data/lib/superkick/templates/team_log/worker_kickoff.liquid +37 -0
- data/lib/superkick/templates/workflow/workflow_triggered.liquid +22 -0
- data/lib/superkick/version.rb +5 -0
- data/lib/superkick/version_control.rb +135 -0
- data/lib/superkick/yaml_config.rb +302 -0
- data/lib/superkick.rb +198 -0
- data/plan.md +267 -0
- 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
|