create-merlin-brain 3.2.0 → 3.3.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/bin/install.cjs +125 -12
- package/bin/merlin-cli.cjs +26 -0
- package/files/agents/code-organization-supervisor.md +1 -0
- package/files/agents/context-guardian.md +1 -0
- package/files/agents/docs-keeper.md +2 -1
- package/files/agents/dry-refactor.md +2 -1
- package/files/agents/elite-code-refactorer.md +1 -0
- package/files/agents/hardening-guard.md +2 -1
- package/files/agents/implementation-dev.md +2 -1
- package/files/agents/merlin-api-designer.md +1 -0
- package/files/agents/merlin-codebase-mapper.md +1 -0
- package/files/agents/merlin-debugger.md +1 -0
- package/files/agents/merlin-executor.md +1 -0
- package/files/agents/merlin-frontend.md +1 -0
- package/files/agents/merlin-integration-checker.md +1 -0
- package/files/agents/merlin-migrator.md +1 -0
- package/files/agents/merlin-milestone-auditor.md +1 -0
- package/files/agents/merlin-performance.md +1 -0
- package/files/agents/merlin-planner.md +2 -0
- package/files/agents/merlin-researcher.md +1 -0
- package/files/agents/merlin-reviewer.md +2 -0
- package/files/agents/merlin-security.md +2 -0
- package/files/agents/merlin-verifier.md +2 -0
- package/files/agents/merlin-work-verifier.md +1 -0
- package/files/agents/merlin.md +1 -0
- package/files/agents/ops-railway.md +2 -1
- package/files/agents/orchestrator-retrofit.md +1 -0
- package/files/agents/product-spec.md +3 -1
- package/files/agents/system-architect.md +3 -1
- package/files/agents/tests-qa.md +2 -1
- package/files/hooks/agent-sync.sh +44 -0
- package/files/hooks/lib/analytics.sh +74 -0
- package/files/hooks/lib/sights-check.sh +58 -0
- package/files/hooks/post-edit-logger.sh +33 -0
- package/files/hooks/pre-edit-sights-check.sh +38 -0
- package/files/hooks/session-end.sh +27 -0
- package/files/hooks/session-start.sh +31 -0
- package/files/hooks/stop-check.md +14 -0
- package/files/hooks/subagent-context.sh +36 -0
- package/files/hooks/task-completed-verify.md +14 -0
- package/files/hooks/task-completed-verify.sh +46 -0
- package/files/hooks/teammate-idle-verify.sh +41 -0
- package/files/loop/lib/sights.sh +15 -4
- package/files/loop/lib/teams.sh +143 -0
- package/files/loop/merlin-loop.sh +16 -0
- package/files/merlin/agents-sync.sh +163 -0
- package/files/merlin/analytics.sh +159 -0
- package/package.json +1 -1
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Merlin CLI: agents-sync.sh — sync, list, info for Merlin agents
|
|
3
|
+
# Usage: merlin agents [sync|list|info <name>]
|
|
4
|
+
set -euo pipefail
|
|
5
|
+
|
|
6
|
+
AGENTS_DIR="${HOME}/.claude/agents"
|
|
7
|
+
MERLIN_DIR="${HOME}/.claude/merlin"
|
|
8
|
+
LAST_SYNC="${MERLIN_DIR}/.last-agent-sync"
|
|
9
|
+
API_URL="${MERLIN_API_URL:-https://api.merlin.build}"
|
|
10
|
+
|
|
11
|
+
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
|
|
12
|
+
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; BOLD='\033[1m'
|
|
13
|
+
DIM='\033[2m'; RESET='\033[0m'
|
|
14
|
+
|
|
15
|
+
die() { echo -e "${RED}Error: $*${RESET}" >&2; exit 1; }
|
|
16
|
+
|
|
17
|
+
file_hash() {
|
|
18
|
+
md5sum "${1}" 2>/dev/null | cut -c1-8 || md5 -q "${1}" 2>/dev/null | cut -c1-8 || echo "unknown"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
json_field() {
|
|
22
|
+
echo "${1}" | python3 -c "import sys,json;print(json.load(sys.stdin).get('${2}',''))" 2>/dev/null || echo ""
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
json_agent_entry() {
|
|
26
|
+
echo "${1}" | python3 -c "
|
|
27
|
+
import sys,json
|
|
28
|
+
data=json.load(sys.stdin)
|
|
29
|
+
for a in data.get('agents',[]):
|
|
30
|
+
if a['name']=='${2}': print(json.dumps(a)); break
|
|
31
|
+
" 2>/dev/null || echo ""
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
cmd_sync() {
|
|
35
|
+
echo -e "\n${MAGENTA}${BOLD} 🔮 Merlin Agent Sync${RESET}\n"
|
|
36
|
+
echo -e "${DIM} Checking ${API_URL} for updates...${RESET}\n"
|
|
37
|
+
[ -d "${AGENTS_DIR}" ] || mkdir -p "${AGENTS_DIR}"
|
|
38
|
+
|
|
39
|
+
local installed="" count=0
|
|
40
|
+
for f in "${AGENTS_DIR}"/*.md; do
|
|
41
|
+
[ -f "${f}" ] || continue
|
|
42
|
+
local name hash
|
|
43
|
+
name=$(basename "${f}" .md); hash=$(file_hash "${f}")
|
|
44
|
+
installed="${installed}${name}:${hash},"; count=$((count + 1))
|
|
45
|
+
done
|
|
46
|
+
echo -e " ${DIM}Installed: ${count} agents${RESET}"
|
|
47
|
+
|
|
48
|
+
local response
|
|
49
|
+
response=$(curl -s --max-time 10 "${API_URL}/api/agents-sync/check?installed=${installed}" 2>/dev/null) || die "Cannot reach ${API_URL}"
|
|
50
|
+
local stale_count
|
|
51
|
+
stale_count=$(json_field "${response}" "count")
|
|
52
|
+
|
|
53
|
+
if [ "${stale_count:-0}" = "0" ]; then
|
|
54
|
+
echo -e "\n ${GREEN}✓ All agents are up to date!${RESET}\n"
|
|
55
|
+
date +%s > "${LAST_SYNC}"; return 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
echo -e " ${YELLOW}${stale_count} agent(s) need updating${RESET}\n"
|
|
59
|
+
local stale_names
|
|
60
|
+
stale_names=$(echo "${response}" | python3 -c "
|
|
61
|
+
import sys,json
|
|
62
|
+
for a in json.load(sys.stdin).get('stale',[]): print(a['name'])
|
|
63
|
+
" 2>/dev/null) || die "Failed to parse response"
|
|
64
|
+
|
|
65
|
+
local updated=0 failed=0
|
|
66
|
+
for agent_name in ${stale_names}; do
|
|
67
|
+
printf " Syncing %-35s " "${agent_name}..."
|
|
68
|
+
local content md_content
|
|
69
|
+
content=$(curl -s --max-time 10 "${API_URL}/api/agents-sync/${agent_name}" 2>/dev/null) || { echo -e "${RED}FAIL${RESET}"; failed=$((failed+1)); continue; }
|
|
70
|
+
md_content=$(json_field "${content}" "content")
|
|
71
|
+
if [ -n "${md_content}" ]; then
|
|
72
|
+
echo "${md_content}" > "${AGENTS_DIR}/${agent_name}.md"
|
|
73
|
+
echo -e "${GREEN}✓${RESET}"; updated=$((updated+1))
|
|
74
|
+
else
|
|
75
|
+
echo -e "${RED}EMPTY${RESET}"; failed=$((failed+1))
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
|
|
79
|
+
echo -e "\n ${GREEN}Updated: ${updated}${RESET}"
|
|
80
|
+
[ "${failed}" -gt 0 ] && echo -e " ${RED}Failed: ${failed}${RESET}"
|
|
81
|
+
echo ""; date +%s > "${LAST_SYNC}"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
cmd_list() {
|
|
85
|
+
echo -e "\n${MAGENTA}${BOLD} 🔮 Merlin Agents${RESET}\n"
|
|
86
|
+
[ -d "${AGENTS_DIR}" ] || die "No agents directory at ${AGENTS_DIR}"
|
|
87
|
+
|
|
88
|
+
local manifest=""
|
|
89
|
+
manifest=$(curl -s --max-time 5 "${API_URL}/api/agents-sync" 2>/dev/null) || manifest=""
|
|
90
|
+
|
|
91
|
+
local count=0
|
|
92
|
+
for f in "${AGENTS_DIR}"/*.md; do
|
|
93
|
+
[ -f "${f}" ] || continue
|
|
94
|
+
local name hash
|
|
95
|
+
name=$(basename "${f}" .md); hash=$(file_hash "${f}"); count=$((count+1))
|
|
96
|
+
|
|
97
|
+
local icon="${GREEN}●${RESET}"
|
|
98
|
+
if [ -n "${manifest}" ]; then
|
|
99
|
+
local entry cloud_hash
|
|
100
|
+
entry=$(json_agent_entry "${manifest}" "${name}")
|
|
101
|
+
if [ -n "${entry}" ]; then
|
|
102
|
+
cloud_hash=$(json_field "${entry}" "hash")
|
|
103
|
+
[ "${cloud_hash}" != "${hash}" ] && icon="${YELLOW}●${RESET}"
|
|
104
|
+
fi
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
local desc
|
|
108
|
+
desc=$(grep -m1 '^[^#<-]' "${f}" 2>/dev/null | head -c 60 || echo "")
|
|
109
|
+
printf " ${icon} ${BOLD}%-35s${RESET} ${DIM}%s${RESET}\n" "${name}" "${desc}"
|
|
110
|
+
done
|
|
111
|
+
|
|
112
|
+
echo -e "\n ${DIM}Total: ${count} agents${RESET}"
|
|
113
|
+
echo -e " ${GREEN}●${RESET} up to date ${YELLOW}●${RESET} update available\n"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
cmd_info() {
|
|
117
|
+
local name="${1:-}"
|
|
118
|
+
[ -n "${name}" ] || die "Usage: merlin agents info <name>"
|
|
119
|
+
local agent_file="${AGENTS_DIR}/${name}.md"
|
|
120
|
+
[ -f "${agent_file}" ] || die "Agent '${name}' not found"
|
|
121
|
+
|
|
122
|
+
echo -e "\n${MAGENTA}${BOLD} 🔮 Agent: ${name}${RESET}\n"
|
|
123
|
+
|
|
124
|
+
local hash lines size
|
|
125
|
+
hash=$(file_hash "${agent_file}")
|
|
126
|
+
lines=$(wc -l < "${agent_file}" | tr -d ' ')
|
|
127
|
+
size=$(wc -c < "${agent_file}" | tr -d ' ')
|
|
128
|
+
|
|
129
|
+
echo -e " ${CYAN}Hash:${RESET} ${hash}"
|
|
130
|
+
echo -e " ${CYAN}Lines:${RESET} ${lines}"
|
|
131
|
+
echo -e " ${CYAN}Size:${RESET} ${size} bytes"
|
|
132
|
+
echo -e " ${CYAN}Path:${RESET} ${agent_file}"
|
|
133
|
+
|
|
134
|
+
local cloud_info cloud_hash
|
|
135
|
+
cloud_info=$(curl -s --max-time 5 "${API_URL}/api/agents-sync/${name}" 2>/dev/null) || cloud_info=""
|
|
136
|
+
if [ -n "${cloud_info}" ]; then
|
|
137
|
+
cloud_hash=$(json_field "${cloud_info}" "hash")
|
|
138
|
+
if [ -n "${cloud_hash}" ]; then
|
|
139
|
+
[ "${cloud_hash}" = "${hash}" ] && echo -e " ${CYAN}Cloud:${RESET} ${GREEN}up to date${RESET}" || echo -e " ${CYAN}Cloud:${RESET} ${YELLOW}update available${RESET}"
|
|
140
|
+
fi
|
|
141
|
+
else
|
|
142
|
+
echo -e " ${CYAN}Cloud:${RESET} ${DIM}unavailable${RESET}"
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
echo -e "\n ${BOLD}Preview:${RESET}"
|
|
146
|
+
head -5 "${agent_file}" | sed 's/^/ /'
|
|
147
|
+
echo -e " ${DIM}...${RESET}\n"
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
subcmd="${1:-help}"
|
|
151
|
+
shift 2>/dev/null || true
|
|
152
|
+
|
|
153
|
+
case "${subcmd}" in
|
|
154
|
+
sync) cmd_sync ;;
|
|
155
|
+
list) cmd_list ;;
|
|
156
|
+
info) cmd_info "${1:-}" ;;
|
|
157
|
+
help|--help|-h)
|
|
158
|
+
echo -e "\n${BOLD}Usage:${RESET} merlin agents <command>\n"
|
|
159
|
+
echo -e " ${CYAN}sync${RESET} Sync agents from merlin.build cloud"
|
|
160
|
+
echo -e " ${CYAN}list${RESET} Show installed agents with update status"
|
|
161
|
+
echo -e " ${CYAN}info${RESET} <name> Show details for one agent\n" ;;
|
|
162
|
+
*) die "Unknown: ${subcmd}. Use: sync, list, info" ;;
|
|
163
|
+
esac
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Merlin Analytics CLI Viewer
|
|
4
|
+
# View, compare, upload, and clean session analytics data.
|
|
5
|
+
# Requires jq for JSON processing.
|
|
6
|
+
#
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
ANALYTICS_DIR="${HOME}/.claude/merlin/analytics"
|
|
10
|
+
API_URL="${MERLIN_API_URL:-https://auth.merlin.build}"
|
|
11
|
+
API_KEY="${MERLIN_API_KEY:-}"
|
|
12
|
+
|
|
13
|
+
# Colors
|
|
14
|
+
R='\033[0m' G='\033[32m' B='\033[34m' Y='\033[33m' DIM='\033[2m' BOLD='\033[1m'
|
|
15
|
+
GRN() { printf "${G}%s${R}" "$1"; }
|
|
16
|
+
BLU() { printf "${B}%s${R}" "$1"; }
|
|
17
|
+
GRY() { printf "${DIM}%s${R}" "$1"; }
|
|
18
|
+
|
|
19
|
+
check_jq() {
|
|
20
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
21
|
+
echo "Error: jq is required. Install: brew install jq (macOS) or apt install jq (Linux)"
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
fmt_duration() {
|
|
27
|
+
local s="${1:-0}"
|
|
28
|
+
if [ "$s" -ge 3600 ]; then printf "%dh %dm" $((s/3600)) $(((s%3600)/60))
|
|
29
|
+
elif [ "$s" -ge 60 ]; then printf "%dm %ds" $((s/60)) $((s%60))
|
|
30
|
+
else printf "%ds" "$s"; fi
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type_color() {
|
|
34
|
+
case "${1:-raw}" in
|
|
35
|
+
loop) GRN "$1" ;; hooks) BLU "$1" ;; *) GRY "$1" ;;
|
|
36
|
+
esac
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
# ─── Summary: Show last N sessions ──────────────────────────────────────────
|
|
40
|
+
cmd_summary() {
|
|
41
|
+
check_jq
|
|
42
|
+
local limit="${1:-10}"
|
|
43
|
+
local files
|
|
44
|
+
files=$(find "${ANALYTICS_DIR}" -name 'session-*.json' -not -name '*.uploaded.json' 2>/dev/null | sort -r | head -n "$limit")
|
|
45
|
+
|
|
46
|
+
if [ -z "$files" ]; then
|
|
47
|
+
echo "No analytics sessions found in ${ANALYTICS_DIR}"
|
|
48
|
+
return
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
printf "${BOLD}%-20s %-6s %8s %6s %5s %5s${R}\n" "DATE" "TYPE" "DURATION" "SIGHT" "FILES" "TASKS"
|
|
52
|
+
printf "%-20s %-6s %8s %6s %5s %5s\n" "────────────────────" "──────" "────────" "──────" "─────" "─────"
|
|
53
|
+
|
|
54
|
+
echo "$files" | while IFS= read -r f; do
|
|
55
|
+
[ -f "$f" ] || continue
|
|
56
|
+
local row
|
|
57
|
+
row=$(jq -r '[
|
|
58
|
+
.startTime // "unknown",
|
|
59
|
+
.sessionType // "raw",
|
|
60
|
+
(.durationSeconds // 0 | tostring),
|
|
61
|
+
(.summary.sightsCallCount // (.events | map(select(.type=="sights_call")) | length) // 0 | tostring),
|
|
62
|
+
(.summary.filesChanged // (.events | map(select(.type=="file_edit")) | length) // 0 | tostring),
|
|
63
|
+
(.summary.tasksCompleted // (.events | map(select(.type=="task_complete")) | length) // 0 | tostring)
|
|
64
|
+
] | @tsv' "$f" 2>/dev/null) || continue
|
|
65
|
+
local dt stype dur sight fchg tasks
|
|
66
|
+
IFS=$'\t' read -r dt stype dur sight fchg tasks <<< "$row"
|
|
67
|
+
local date_str="${dt:0:16}"
|
|
68
|
+
local dur_fmt; dur_fmt=$(fmt_duration "$dur")
|
|
69
|
+
printf "%-20s " "$date_str"
|
|
70
|
+
type_color "$stype"
|
|
71
|
+
printf "%*s %8s %6s %5s %5s\n" "$((6-${#stype}))" "" "$dur_fmt" "$sight" "$fchg" "$tasks"
|
|
72
|
+
done
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# ─── Compare: Average metrics by session type ───────────────────────────────
|
|
76
|
+
cmd_compare() {
|
|
77
|
+
check_jq
|
|
78
|
+
local files
|
|
79
|
+
files=$(find "${ANALYTICS_DIR}" -name 'session-*.json' 2>/dev/null)
|
|
80
|
+
[ -z "$files" ] && { echo "No sessions found."; return; }
|
|
81
|
+
|
|
82
|
+
printf "\n${BOLD}Session Type Comparison${R}\n"
|
|
83
|
+
printf "%-8s %6s %8s %6s %5s %5s\n" "TYPE" "COUNT" "AVG DUR" "SIGHTS" "FILES" "TASKS"
|
|
84
|
+
printf "%-8s %6s %8s %6s %5s %5s\n" "────────" "──────" "────────" "──────" "─────" "─────"
|
|
85
|
+
|
|
86
|
+
for stype in loop hooks raw; do
|
|
87
|
+
local stats
|
|
88
|
+
stats=$(echo "$files" | xargs -I{} jq -r "select(.sessionType == \"$stype\") |
|
|
89
|
+
[(.durationSeconds // 0), (.summary.sightsCallCount // 0), (.summary.filesChanged // 0), (.summary.tasksCompleted // 0)]
|
|
90
|
+
| @tsv" {} 2>/dev/null | awk -F'\t' '
|
|
91
|
+
{ n++; d+=$1; s+=$2; f+=$3; t+=$4 }
|
|
92
|
+
END { if(n>0) printf "%d\t%d\t%d\t%d\t%d", n, d/n, s/n, f/n, t/n; else printf "0\t0\t0\t0\t0" }
|
|
93
|
+
')
|
|
94
|
+
local cnt avg_d avg_s avg_f avg_t
|
|
95
|
+
IFS=$'\t' read -r cnt avg_d avg_s avg_f avg_t <<< "$stats"
|
|
96
|
+
[ "$cnt" -eq 0 ] && continue
|
|
97
|
+
local dur_fmt; dur_fmt=$(fmt_duration "$avg_d")
|
|
98
|
+
type_color "$stype"
|
|
99
|
+
printf "%*s %6s %8s %6s %5s %5s\n" "$((8-${#stype}))" "" "$cnt" "$dur_fmt" "$avg_s" "$avg_f" "$avg_t"
|
|
100
|
+
done
|
|
101
|
+
echo ""
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# ─── Upload: Send sessions to Merlin API ────────────────────────────────────
|
|
105
|
+
cmd_upload() {
|
|
106
|
+
check_jq
|
|
107
|
+
[ -z "${API_KEY}" ] && { echo "Error: MERLIN_API_KEY not set. Get your key at merlin.build/settings"; exit 1; }
|
|
108
|
+
|
|
109
|
+
local files
|
|
110
|
+
files=$(find "${ANALYTICS_DIR}" -name 'session-*.json' -not -name '*.uploaded.json' 2>/dev/null)
|
|
111
|
+
[ -z "$files" ] && { echo "No new sessions to upload."; return; }
|
|
112
|
+
|
|
113
|
+
local count; count=$(echo "$files" | wc -l | tr -d ' ')
|
|
114
|
+
echo "Uploading ${count} session(s)..."
|
|
115
|
+
|
|
116
|
+
local sessions="[]"
|
|
117
|
+
while IFS= read -r f; do
|
|
118
|
+
[ -f "$f" ] || continue
|
|
119
|
+
sessions=$(jq --slurpfile s "$f" '. + $s' <<< "$sessions" 2>/dev/null) || continue
|
|
120
|
+
done <<< "$files"
|
|
121
|
+
|
|
122
|
+
local resp
|
|
123
|
+
resp=$(curl -sS -X POST "${API_URL}/api/analytics/upload" \
|
|
124
|
+
-H "Authorization: Bearer ${API_KEY}" \
|
|
125
|
+
-H "Content-Type: application/json" \
|
|
126
|
+
-d "{\"sessions\": ${sessions}}" 2>&1) || { echo "Upload failed: $resp"; return 1; }
|
|
127
|
+
|
|
128
|
+
# Mark uploaded
|
|
129
|
+
echo "$files" | while IFS= read -r f; do
|
|
130
|
+
mv "$f" "${f%.json}.uploaded.json" 2>/dev/null || true
|
|
131
|
+
done
|
|
132
|
+
echo "Uploaded ${count} session(s) successfully."
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
# ─── Clean: Remove old sessions ─────────────────────────────────────────────
|
|
136
|
+
cmd_clean() {
|
|
137
|
+
local days="${1:-30}"
|
|
138
|
+
local count=0
|
|
139
|
+
find "${ANALYTICS_DIR}" -name 'session-*.json' -mtime +"$days" 2>/dev/null | while IFS= read -r f; do
|
|
140
|
+
rm -f "$f" && count=$((count + 1))
|
|
141
|
+
done
|
|
142
|
+
find "${ANALYTICS_DIR}" -name '*.uploaded.json' -mtime +"$days" 2>/dev/null -delete
|
|
143
|
+
echo "Cleaned sessions older than ${days} days."
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
# ─── Main ────────────────────────────────────────────────────────────────────
|
|
147
|
+
case "${1:-summary}" in
|
|
148
|
+
summary) cmd_summary "${2:-10}" ;;
|
|
149
|
+
compare) cmd_compare ;;
|
|
150
|
+
upload) cmd_upload ;;
|
|
151
|
+
clean) cmd_clean "${2:-30}" ;;
|
|
152
|
+
*)
|
|
153
|
+
echo "Usage: merlin analytics [summary|compare|upload|clean]"
|
|
154
|
+
echo " summary [N] Show last N sessions (default 10)"
|
|
155
|
+
echo " compare Compare metrics by session type"
|
|
156
|
+
echo " upload Upload sessions to merlin.build"
|
|
157
|
+
echo " clean [days] Remove sessions older than N days (default 30)"
|
|
158
|
+
;;
|
|
159
|
+
esac
|
package/package.json
CHANGED