claude-code-kanban 2.1.0 → 2.2.0-rc.10
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/hooks/agent-spy.sh +25 -2
- package/install.js +1 -0
- package/lib/parsers.js +37 -1
- package/package.json +2 -2
- package/public/app.js +857 -113
- package/public/index.html +36 -4
- package/public/style.css +315 -5
- package/server.js +277 -40
package/hooks/agent-spy.sh
CHANGED
|
@@ -16,6 +16,24 @@ eval "$(echo "$INPUT" | jq -r '
|
|
|
16
16
|
|
|
17
17
|
[ -z "$SESSION_ID" ] && exit 0
|
|
18
18
|
|
|
19
|
+
# Map session to custom task list on session start
|
|
20
|
+
if [ "$EVENT" = "SessionStart" ]; then
|
|
21
|
+
TASK_LIST_ID="${CLAUDE_CODE_TASK_LIST_ID:-}"
|
|
22
|
+
if [ -n "$TASK_LIST_ID" ]; then
|
|
23
|
+
CWD=$(echo "$INPUT" | jq -r '.cwd // ""')
|
|
24
|
+
MAPS_DIR="$HOME/.claude/agent-activity/_task-maps"
|
|
25
|
+
mkdir -p "$MAPS_DIR"
|
|
26
|
+
MAP_FILE="$MAPS_DIR/$TASK_LIST_ID.json"
|
|
27
|
+
TMP_FILE="$MAP_FILE.$$"
|
|
28
|
+
TS=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
29
|
+
EXISTING="{}"
|
|
30
|
+
[ -f "$MAP_FILE" ] && EXISTING=$(cat "$MAP_FILE")
|
|
31
|
+
echo "$EXISTING" | jq -c --arg sid "$SESSION_ID" --arg cwd "$CWD" --arg ts "$TS" \
|
|
32
|
+
'.[$sid] = {project: $cwd, updatedAt: $ts}' > "$TMP_FILE" && mv "$TMP_FILE" "$MAP_FILE"
|
|
33
|
+
fi
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
19
37
|
# PostToolUse / non-waiting PreToolUse: clear waiting state
|
|
20
38
|
if [ "$EVENT" = "PostToolUse" ] || { [ "$EVENT" = "PreToolUse" ] && [ "$TOOL_NAME" != "AskUserQuestion" ]; }; then
|
|
21
39
|
WFILE="$HOME/.claude/agent-activity/$SESSION_ID/_waiting.json"
|
|
@@ -86,12 +104,17 @@ if [ "$EVENT" = "SubagentStart" ]; then
|
|
|
86
104
|
{"agentId":"$AGENT_ID","type":"$AGENT_TYPE_RAW","status":"active","startedAt":"$TS","updatedAt":"$TS"}
|
|
87
105
|
EOF
|
|
88
106
|
# Write name→id mapping for TeammateIdle resolution
|
|
89
|
-
#
|
|
107
|
+
# Delete previous file only if not active (idle/stopped = teammate re-spawn, active = parallel subagent)
|
|
90
108
|
if [ -n "$AGENT_TYPE_RAW" ]; then
|
|
91
109
|
MAP_FILE="$DIR/_name-${AGENT_TYPE_RAW}.id"
|
|
92
110
|
if [ -f "$MAP_FILE" ]; then
|
|
93
111
|
OLD_ID=$(cat "$MAP_FILE")
|
|
94
|
-
[ -n "$OLD_ID" ] && [ "$OLD_ID" != "$AGENT_ID" ]
|
|
112
|
+
if [ -n "$OLD_ID" ] && [ "$OLD_ID" != "$AGENT_ID" ]; then
|
|
113
|
+
OLD_FILE="$DIR/$OLD_ID.json"
|
|
114
|
+
OLD_STATUS=""
|
|
115
|
+
[ -f "$OLD_FILE" ] && OLD_STATUS=$(jq -r '.status // ""' "$OLD_FILE" 2>/dev/null)
|
|
116
|
+
[ "$OLD_STATUS" != "active" ] && rm -f "$OLD_FILE"
|
|
117
|
+
fi
|
|
95
118
|
fi
|
|
96
119
|
echo -n "$AGENT_ID" > "$MAP_FILE"
|
|
97
120
|
fi
|
package/install.js
CHANGED
|
@@ -17,6 +17,7 @@ const AGENT_ACTIVITY_DIR = path.join(CLAUDE_DIR, 'agent-activity');
|
|
|
17
17
|
|
|
18
18
|
const HOOK_COMMAND = '~/.claude/hooks/agent-spy.sh';
|
|
19
19
|
const HOOK_EVENTS = [
|
|
20
|
+
{ event: 'SessionStart' },
|
|
20
21
|
{ event: 'SubagentStart' },
|
|
21
22
|
{ event: 'SubagentStop' },
|
|
22
23
|
{ event: 'TeammateIdle' },
|
package/lib/parsers.js
CHANGED
|
@@ -613,6 +613,41 @@ function findTerminatedTeammates(jsonlPath) {
|
|
|
613
613
|
return terminated;
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
+
function extractPromptFromTranscript(jsonlPath) {
|
|
617
|
+
const { openSync, readSync, closeSync } = fs;
|
|
618
|
+
const MAX_READ = 65536;
|
|
619
|
+
const CHUNK = 4096;
|
|
620
|
+
const fd = openSync(jsonlPath, 'r');
|
|
621
|
+
try {
|
|
622
|
+
let accumulated = '';
|
|
623
|
+
const buf = Buffer.alloc(CHUNK);
|
|
624
|
+
while (accumulated.length < MAX_READ) {
|
|
625
|
+
const bytesRead = readSync(fd, buf, 0, CHUNK, null);
|
|
626
|
+
if (bytesRead === 0) break;
|
|
627
|
+
accumulated += buf.toString('utf8', 0, bytesRead);
|
|
628
|
+
const nlIdx = accumulated.indexOf('\n');
|
|
629
|
+
if (nlIdx === -1) continue;
|
|
630
|
+
const firstLine = accumulated.slice(0, nlIdx);
|
|
631
|
+
try {
|
|
632
|
+
const obj = JSON.parse(firstLine);
|
|
633
|
+
if (obj.type === 'user') {
|
|
634
|
+
const content = obj.message?.content;
|
|
635
|
+
if (typeof content === 'string') return content.slice(0, 500);
|
|
636
|
+
if (Array.isArray(content)) {
|
|
637
|
+
for (const b of content) {
|
|
638
|
+
if (b.type === 'text' && b.text) return b.text.slice(0, 500);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
} catch (_) {}
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
} finally {
|
|
646
|
+
closeSync(fd);
|
|
647
|
+
}
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
|
|
616
651
|
module.exports = {
|
|
617
652
|
parseTask,
|
|
618
653
|
parseAgent,
|
|
@@ -624,5 +659,6 @@ module.exports = {
|
|
|
624
659
|
readRecentMessages,
|
|
625
660
|
buildAgentProgressMap,
|
|
626
661
|
readCompactSummaries,
|
|
627
|
-
findTerminatedTeammates
|
|
662
|
+
findTerminatedTeammates,
|
|
663
|
+
extractPromptFromTranscript
|
|
628
664
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-kanban",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0-rc.10",
|
|
4
4
|
"description": "A web-based Kanban board for viewing Claude Code tasks with agent teams support",
|
|
5
5
|
"main": "server.js",
|
|
6
6
|
"bin": {
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"start": "node server.js",
|
|
11
|
-
"dev": "node server.js
|
|
11
|
+
"dev": "node --watch server.js",
|
|
12
12
|
"test": "node --test test/contracts.test.js",
|
|
13
13
|
"test:hooks": "bash tests/test-agent-spy.sh",
|
|
14
14
|
"validate:schemas": "node test/validate-live-schemas.js",
|