agentk8 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.
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/agentk +481 -0
- package/bin/agentk-wrapper.js +35 -0
- package/bin/postinstall.js +97 -0
- package/lib/core.sh +281 -0
- package/lib/ipc.sh +501 -0
- package/lib/spawn.sh +398 -0
- package/lib/ui.sh +415 -0
- package/lib/visual.sh +349 -0
- package/modes/dev/engineer.md +118 -0
- package/modes/dev/orchestrator.md +110 -0
- package/modes/dev/security.md +221 -0
- package/modes/dev/tester.md +161 -0
- package/modes/ml/data-engineer.md +244 -0
- package/modes/ml/evaluator.md +265 -0
- package/modes/ml/ml-engineer.md +239 -0
- package/modes/ml/orchestrator.md +145 -0
- package/modes/ml/researcher.md +198 -0
- package/modes/shared/scout.md +270 -0
- package/package.json +49 -0
package/lib/spawn.sh
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# AGENT-K Spawn Library
|
|
3
|
+
# Claude subprocess spawning and management
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Source dependencies
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "$SCRIPT_DIR/core.sh"
|
|
10
|
+
source "$SCRIPT_DIR/ipc.sh"
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# GLOBALS
|
|
14
|
+
# =============================================================================
|
|
15
|
+
|
|
16
|
+
# Track spawned agent PIDs
|
|
17
|
+
declare -A AGENT_PIDS=()
|
|
18
|
+
declare -A AGENT_TASKS=()
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# AGENT PROMPT LOADING
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
get_agent_prompt_file() {
|
|
25
|
+
local mode="$1"
|
|
26
|
+
local agent="$2"
|
|
27
|
+
|
|
28
|
+
local prompt_file
|
|
29
|
+
|
|
30
|
+
# Check for shared agents first
|
|
31
|
+
if [[ -f "$AGENTK_ROOT/modes/shared/${agent}.md" ]]; then
|
|
32
|
+
prompt_file="$AGENTK_ROOT/modes/shared/${agent}.md"
|
|
33
|
+
else
|
|
34
|
+
prompt_file="$AGENTK_ROOT/modes/${mode}/${agent}.md"
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
if [[ -f "$prompt_file" ]]; then
|
|
38
|
+
echo "$prompt_file"
|
|
39
|
+
else
|
|
40
|
+
log_error "Agent prompt not found: $prompt_file"
|
|
41
|
+
return 1
|
|
42
|
+
fi
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
load_agent_prompt() {
|
|
46
|
+
local mode="$1"
|
|
47
|
+
local agent="$2"
|
|
48
|
+
|
|
49
|
+
local prompt_file
|
|
50
|
+
prompt_file=$(get_agent_prompt_file "$mode" "$agent")
|
|
51
|
+
|
|
52
|
+
if [[ -f "$prompt_file" ]]; then
|
|
53
|
+
cat "$prompt_file"
|
|
54
|
+
else
|
|
55
|
+
return 1
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
build_agent_system_prompt() {
|
|
60
|
+
local mode="$1"
|
|
61
|
+
local agent="$2"
|
|
62
|
+
local task_context="${3:-}"
|
|
63
|
+
|
|
64
|
+
local date_context
|
|
65
|
+
date_context=$(get_date_context)
|
|
66
|
+
|
|
67
|
+
local agent_prompt
|
|
68
|
+
agent_prompt=$(load_agent_prompt "$mode" "$agent")
|
|
69
|
+
|
|
70
|
+
cat <<EOF
|
|
71
|
+
$date_context
|
|
72
|
+
|
|
73
|
+
$agent_prompt
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
CURRENT TASK CONTEXT:
|
|
77
|
+
$task_context
|
|
78
|
+
EOF
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
# =============================================================================
|
|
82
|
+
# AGENT SPAWNING
|
|
83
|
+
# =============================================================================
|
|
84
|
+
|
|
85
|
+
spawn_agent() {
|
|
86
|
+
local agent="$1"
|
|
87
|
+
local task_id="$2"
|
|
88
|
+
local mode="${3:-dev}"
|
|
89
|
+
|
|
90
|
+
local task_file
|
|
91
|
+
task_file=$(get_task_file "$task_id")
|
|
92
|
+
|
|
93
|
+
if [[ ! -f "$task_file" ]]; then
|
|
94
|
+
log_error "Task not found: $task_id"
|
|
95
|
+
return 1
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
# Read task details
|
|
99
|
+
local prompt
|
|
100
|
+
prompt=$(jq -r '.prompt' "$task_file")
|
|
101
|
+
local context_files
|
|
102
|
+
context_files=$(jq -r '.context.files | join(", ")' "$task_file")
|
|
103
|
+
|
|
104
|
+
local task_context="Task ID: $task_id
|
|
105
|
+
Prompt: $prompt
|
|
106
|
+
Context Files: $context_files"
|
|
107
|
+
|
|
108
|
+
# Build system prompt
|
|
109
|
+
local system_prompt
|
|
110
|
+
system_prompt=$(build_agent_system_prompt "$mode" "$agent" "$task_context")
|
|
111
|
+
|
|
112
|
+
# Update task status
|
|
113
|
+
update_task_status "$task_id" "$STATUS_IN_PROGRESS"
|
|
114
|
+
update_session_agent "$agent" "working" "Processing task $task_id"
|
|
115
|
+
|
|
116
|
+
# Get agent log file
|
|
117
|
+
local log_file
|
|
118
|
+
log_file=$(get_agent_log "$agent")
|
|
119
|
+
|
|
120
|
+
log_info "Spawning agent: $agent for task: $task_id"
|
|
121
|
+
|
|
122
|
+
# Spawn claude in background
|
|
123
|
+
(
|
|
124
|
+
# Write system prompt to temp file for claude to read
|
|
125
|
+
local prompt_file
|
|
126
|
+
prompt_file=$(mktemp)
|
|
127
|
+
echo "$system_prompt" > "$prompt_file"
|
|
128
|
+
|
|
129
|
+
# Run claude with the task
|
|
130
|
+
local output
|
|
131
|
+
if output=$(claude --print "$prompt" --system-prompt "$prompt_file" 2>&1); then
|
|
132
|
+
# Success - create result
|
|
133
|
+
create_result "$task_id" "$agent" "$STATUS_COMPLETED" "$output" "[]" "[]"
|
|
134
|
+
update_session_agent "$agent" "done" "Completed task $task_id"
|
|
135
|
+
else
|
|
136
|
+
# Failed
|
|
137
|
+
create_result "$task_id" "$agent" "$STATUS_FAILED" "$output" "[]" "[]"
|
|
138
|
+
update_session_agent "$agent" "failed" "Failed task $task_id"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Cleanup
|
|
142
|
+
rm -f "$prompt_file"
|
|
143
|
+
|
|
144
|
+
) >> "$log_file" 2>&1 &
|
|
145
|
+
|
|
146
|
+
local pid=$!
|
|
147
|
+
AGENT_PIDS[$agent]=$pid
|
|
148
|
+
AGENT_TASKS[$agent]=$task_id
|
|
149
|
+
|
|
150
|
+
log_debug "Agent $agent spawned with PID: $pid"
|
|
151
|
+
echo "$pid"
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
spawn_agent_interactive() {
|
|
155
|
+
local agent="$1"
|
|
156
|
+
local mode="${2:-dev}"
|
|
157
|
+
local initial_prompt="${3:-}"
|
|
158
|
+
|
|
159
|
+
# Build system prompt
|
|
160
|
+
local system_prompt
|
|
161
|
+
system_prompt=$(build_agent_system_prompt "$mode" "$agent" "Interactive session")
|
|
162
|
+
|
|
163
|
+
# Write system prompt to temp file
|
|
164
|
+
local prompt_file
|
|
165
|
+
prompt_file=$(mktemp)
|
|
166
|
+
echo "$system_prompt" > "$prompt_file"
|
|
167
|
+
|
|
168
|
+
log_info "Starting interactive session with agent: $agent"
|
|
169
|
+
|
|
170
|
+
# Run claude interactively
|
|
171
|
+
if [[ -n "$initial_prompt" ]]; then
|
|
172
|
+
claude --system-prompt "$prompt_file" "$initial_prompt"
|
|
173
|
+
else
|
|
174
|
+
claude --system-prompt "$prompt_file"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
# Cleanup
|
|
178
|
+
rm -f "$prompt_file"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# =============================================================================
|
|
182
|
+
# AGENT MANAGEMENT
|
|
183
|
+
# =============================================================================
|
|
184
|
+
|
|
185
|
+
is_agent_running() {
|
|
186
|
+
local agent="$1"
|
|
187
|
+
|
|
188
|
+
if [[ -z "${AGENT_PIDS[$agent]:-}" ]]; then
|
|
189
|
+
return 1
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
local pid="${AGENT_PIDS[$agent]}"
|
|
193
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
194
|
+
return 0
|
|
195
|
+
else
|
|
196
|
+
# Agent finished, clean up
|
|
197
|
+
unset AGENT_PIDS[$agent]
|
|
198
|
+
return 1
|
|
199
|
+
fi
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
wait_agent() {
|
|
203
|
+
local agent="$1"
|
|
204
|
+
local timeout="${2:-300}"
|
|
205
|
+
|
|
206
|
+
if [[ -z "${AGENT_PIDS[$agent]:-}" ]]; then
|
|
207
|
+
log_warn "Agent not running: $agent"
|
|
208
|
+
return 1
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
local pid="${AGENT_PIDS[$agent]}"
|
|
212
|
+
local elapsed=0
|
|
213
|
+
|
|
214
|
+
while kill -0 "$pid" 2>/dev/null && [[ $elapsed -lt $timeout ]]; do
|
|
215
|
+
sleep 1
|
|
216
|
+
elapsed=$((elapsed + 1))
|
|
217
|
+
done
|
|
218
|
+
|
|
219
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
220
|
+
log_warn "Timeout waiting for agent: $agent"
|
|
221
|
+
return 1
|
|
222
|
+
fi
|
|
223
|
+
|
|
224
|
+
# Get exit status
|
|
225
|
+
wait "$pid" 2>/dev/null || true
|
|
226
|
+
unset AGENT_PIDS[$agent]
|
|
227
|
+
|
|
228
|
+
log_debug "Agent $agent finished"
|
|
229
|
+
return 0
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
kill_agent() {
|
|
233
|
+
local agent="$1"
|
|
234
|
+
|
|
235
|
+
if [[ -z "${AGENT_PIDS[$agent]:-}" ]]; then
|
|
236
|
+
log_warn "Agent not running: $agent"
|
|
237
|
+
return 0
|
|
238
|
+
fi
|
|
239
|
+
|
|
240
|
+
local pid="${AGENT_PIDS[$agent]}"
|
|
241
|
+
|
|
242
|
+
# Try graceful shutdown first
|
|
243
|
+
kill -TERM "$pid" 2>/dev/null || true
|
|
244
|
+
sleep 1
|
|
245
|
+
|
|
246
|
+
# Force kill if still running
|
|
247
|
+
if kill -0 "$pid" 2>/dev/null; then
|
|
248
|
+
kill -KILL "$pid" 2>/dev/null || true
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
# Cancel any active task
|
|
252
|
+
if [[ -n "${AGENT_TASKS[$agent]:-}" ]]; then
|
|
253
|
+
cancel_task "${AGENT_TASKS[$agent]}"
|
|
254
|
+
unset AGENT_TASKS[$agent]
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
unset AGENT_PIDS[$agent]
|
|
258
|
+
update_session_agent "$agent" "stopped" "Killed by user"
|
|
259
|
+
|
|
260
|
+
log_info "Killed agent: $agent"
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
kill_all_agents() {
|
|
264
|
+
for agent in "${!AGENT_PIDS[@]}"; do
|
|
265
|
+
kill_agent "$agent"
|
|
266
|
+
done
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
# =============================================================================
|
|
270
|
+
# AGENT STATUS
|
|
271
|
+
# =============================================================================
|
|
272
|
+
|
|
273
|
+
get_agent_status() {
|
|
274
|
+
local agent="$1"
|
|
275
|
+
|
|
276
|
+
if is_agent_running "$agent"; then
|
|
277
|
+
echo "running"
|
|
278
|
+
elif [[ -n "${AGENT_TASKS[$agent]:-}" ]]; then
|
|
279
|
+
local task_status
|
|
280
|
+
task_status=$(get_task_status "${AGENT_TASKS[$agent]}")
|
|
281
|
+
echo "$task_status"
|
|
282
|
+
else
|
|
283
|
+
echo "idle"
|
|
284
|
+
fi
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
get_all_agent_status() {
|
|
288
|
+
local mode="${1:-dev}"
|
|
289
|
+
local agents=()
|
|
290
|
+
|
|
291
|
+
case "$mode" in
|
|
292
|
+
dev) agents=("orchestrator" "engineer" "tester" "security" "scout") ;;
|
|
293
|
+
ml) agents=("orchestrator" "researcher" "ml-engineer" "data-engineer" "evaluator" "scout") ;;
|
|
294
|
+
esac
|
|
295
|
+
|
|
296
|
+
echo "{"
|
|
297
|
+
local first=true
|
|
298
|
+
for agent in "${agents[@]}"; do
|
|
299
|
+
local status
|
|
300
|
+
status=$(get_agent_status "$agent")
|
|
301
|
+
local message=""
|
|
302
|
+
|
|
303
|
+
if [[ -n "${AGENT_TASKS[$agent]:-}" ]]; then
|
|
304
|
+
message=$(get_task_field "${AGENT_TASKS[$agent]}" "prompt" | head -c 50)
|
|
305
|
+
fi
|
|
306
|
+
|
|
307
|
+
if [[ "$first" == "true" ]]; then
|
|
308
|
+
first=false
|
|
309
|
+
else
|
|
310
|
+
echo ","
|
|
311
|
+
fi
|
|
312
|
+
|
|
313
|
+
printf ' "%s": {"status": "%s", "message": "%s"}' "$agent" "$status" "$message"
|
|
314
|
+
done
|
|
315
|
+
echo
|
|
316
|
+
echo "}"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# =============================================================================
|
|
320
|
+
# AGENT LOG VIEWING
|
|
321
|
+
# =============================================================================
|
|
322
|
+
|
|
323
|
+
view_agent_log() {
|
|
324
|
+
local agent="$1"
|
|
325
|
+
local lines="${2:-50}"
|
|
326
|
+
|
|
327
|
+
local log_file
|
|
328
|
+
log_file=$(get_agent_log "$agent")
|
|
329
|
+
|
|
330
|
+
if [[ -f "$log_file" ]]; then
|
|
331
|
+
tail -n "$lines" "$log_file"
|
|
332
|
+
else
|
|
333
|
+
echo "No logs found for agent: $agent"
|
|
334
|
+
fi
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
follow_agent_log() {
|
|
338
|
+
local agent="$1"
|
|
339
|
+
|
|
340
|
+
local log_file
|
|
341
|
+
log_file=$(get_agent_log "$agent")
|
|
342
|
+
|
|
343
|
+
if [[ -f "$log_file" ]]; then
|
|
344
|
+
tail -f "$log_file"
|
|
345
|
+
else
|
|
346
|
+
echo "No logs found for agent: $agent"
|
|
347
|
+
fi
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
clear_agent_log() {
|
|
351
|
+
local agent="$1"
|
|
352
|
+
|
|
353
|
+
local log_file
|
|
354
|
+
log_file=$(get_agent_log "$agent")
|
|
355
|
+
|
|
356
|
+
if [[ -f "$log_file" ]]; then
|
|
357
|
+
> "$log_file"
|
|
358
|
+
log_debug "Cleared log for agent: $agent"
|
|
359
|
+
fi
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
# =============================================================================
|
|
363
|
+
# PARALLEL SPAWNING
|
|
364
|
+
# =============================================================================
|
|
365
|
+
|
|
366
|
+
spawn_agents_parallel() {
|
|
367
|
+
local mode="$1"
|
|
368
|
+
shift
|
|
369
|
+
local task_ids=("$@")
|
|
370
|
+
|
|
371
|
+
local pids=()
|
|
372
|
+
|
|
373
|
+
for task_id in "${task_ids[@]}"; do
|
|
374
|
+
local assigned_to
|
|
375
|
+
assigned_to=$(get_task_field "$task_id" "assigned_to")
|
|
376
|
+
|
|
377
|
+
spawn_agent "$assigned_to" "$task_id" "$mode" &
|
|
378
|
+
pids+=($!)
|
|
379
|
+
done
|
|
380
|
+
|
|
381
|
+
# Wait for all spawns to complete
|
|
382
|
+
for pid in "${pids[@]}"; do
|
|
383
|
+
wait "$pid" 2>/dev/null || true
|
|
384
|
+
done
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
# =============================================================================
|
|
388
|
+
# CLEANUP
|
|
389
|
+
# =============================================================================
|
|
390
|
+
|
|
391
|
+
cleanup_agents() {
|
|
392
|
+
log_info "Cleaning up agents..."
|
|
393
|
+
kill_all_agents
|
|
394
|
+
cancel_all_tasks
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
# Trap for cleanup on exit
|
|
398
|
+
trap cleanup_agents EXIT INT TERM
|