monol-plugin-scout 2.1.3 → 4.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 (87) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/CHANGELOG.md +244 -0
  3. package/monol-plugin-scout-pkg/CLAUDE.md +125 -8
  4. package/monol-plugin-scout-pkg/api/mock/categories.json +81 -0
  5. package/monol-plugin-scout-pkg/api/mock/insights.json +111 -0
  6. package/monol-plugin-scout-pkg/api/mock/marketplace.json +501 -0
  7. package/monol-plugin-scout-pkg/api/mock/trending.json +96 -0
  8. package/monol-plugin-scout-pkg/commands/console.md +79 -0
  9. package/monol-plugin-scout-pkg/commands/frequency.md +32 -0
  10. package/monol-plugin-scout-pkg/commands/install.md +32 -0
  11. package/monol-plugin-scout-pkg/commands/priority.md +30 -0
  12. package/monol-plugin-scout-pkg/commands/quiet.md +32 -0
  13. package/monol-plugin-scout-pkg/commands/schedule.md +32 -0
  14. package/monol-plugin-scout-pkg/commands/scout.md +8 -5
  15. package/monol-plugin-scout-pkg/commands/skills.md +160 -0
  16. package/monol-plugin-scout-pkg/commands/team.md +32 -0
  17. package/monol-plugin-scout-pkg/commands/timing.md +32 -0
  18. package/monol-plugin-scout-pkg/commands/trust.md +85 -0
  19. package/monol-plugin-scout-pkg/commands/trusted-install.md +98 -0
  20. package/monol-plugin-scout-pkg/commands/uninstall.md +31 -0
  21. package/monol-plugin-scout-pkg/config.yaml +57 -0
  22. package/monol-plugin-scout-pkg/data/.cache/676d5ab664292155e5f509c69d4edae1 +10 -0
  23. package/monol-plugin-scout-pkg/data/.session +8 -0
  24. package/monol-plugin-scout-pkg/data/analytics.json +102 -0
  25. package/monol-plugin-scout-pkg/data/history.json +67 -11
  26. package/monol-plugin-scout-pkg/data/logs/scout.log +1 -0
  27. package/monol-plugin-scout-pkg/data/schedules.json +17 -0
  28. package/monol-plugin-scout-pkg/data/team.json +53 -0
  29. package/monol-plugin-scout-pkg/data/usage.json +100 -7
  30. package/monol-plugin-scout-pkg/docs/ARCHITECTURE.md +201 -0
  31. package/monol-plugin-scout-pkg/hooks/generate-insights.sh +102 -0
  32. package/monol-plugin-scout-pkg/hooks/hooks.json +36 -1
  33. package/monol-plugin-scout-pkg/hooks/on-session-end.sh +136 -0
  34. package/monol-plugin-scout-pkg/hooks/on-session-start.sh +43 -0
  35. package/monol-plugin-scout-pkg/hooks/on-stop.md +79 -0
  36. package/monol-plugin-scout-pkg/hooks/open-console.sh +111 -0
  37. package/monol-plugin-scout-pkg/hooks/open-dashboard.sh +61 -0
  38. package/monol-plugin-scout-pkg/hooks/track-usage.sh +59 -0
  39. package/monol-plugin-scout-pkg/lib/ai-recommender.sh +505 -0
  40. package/monol-plugin-scout-pkg/lib/cache.sh +194 -0
  41. package/monol-plugin-scout-pkg/lib/data-validator.sh +360 -0
  42. package/monol-plugin-scout-pkg/lib/error-handler.sh +296 -0
  43. package/monol-plugin-scout-pkg/lib/logger.sh +263 -0
  44. package/monol-plugin-scout-pkg/lib/plugin-manager.sh +239 -0
  45. package/monol-plugin-scout-pkg/lib/priority-scorer.sh +262 -0
  46. package/monol-plugin-scout-pkg/lib/profile-learner.sh +339 -0
  47. package/monol-plugin-scout-pkg/lib/project-analyzer.sh +281 -0
  48. package/monol-plugin-scout-pkg/lib/recommendation-controller.sh +290 -0
  49. package/monol-plugin-scout-pkg/lib/rejection-learner.sh +232 -0
  50. package/monol-plugin-scout-pkg/lib/scheduler.sh +275 -0
  51. package/monol-plugin-scout-pkg/lib/skill-scout.sh +729 -0
  52. package/monol-plugin-scout-pkg/lib/sync.sh +221 -0
  53. package/monol-plugin-scout-pkg/lib/team-learner.sh +450 -0
  54. package/monol-plugin-scout-pkg/lib/team-manager.sh +369 -0
  55. package/monol-plugin-scout-pkg/lib/trend-learner.sh +428 -0
  56. package/monol-plugin-scout-pkg/lib/trust-manager.sh +261 -0
  57. package/monol-plugin-scout-pkg/lib/trusted-installer.sh +738 -0
  58. package/monol-plugin-scout-pkg/plugin.json +3 -2
  59. package/monol-plugin-scout-pkg/skills/audit.md +6 -0
  60. package/monol-plugin-scout-pkg/skills/cleanup.md +6 -0
  61. package/monol-plugin-scout-pkg/skills/compare.md +6 -0
  62. package/monol-plugin-scout-pkg/skills/console.md +315 -0
  63. package/monol-plugin-scout-pkg/skills/explore.md +6 -0
  64. package/monol-plugin-scout-pkg/skills/fork.md +6 -0
  65. package/monol-plugin-scout-pkg/skills/frequency.md +93 -0
  66. package/monol-plugin-scout-pkg/skills/install.md +127 -0
  67. package/monol-plugin-scout-pkg/skills/priority.md +77 -0
  68. package/monol-plugin-scout-pkg/skills/quiet.md +73 -0
  69. package/monol-plugin-scout-pkg/skills/schedule.md +95 -0
  70. package/monol-plugin-scout-pkg/skills/scout.md +27 -17
  71. package/monol-plugin-scout-pkg/skills/skills.md +230 -0
  72. package/monol-plugin-scout-pkg/skills/team.md +117 -0
  73. package/monol-plugin-scout-pkg/skills/timing.md +97 -0
  74. package/monol-plugin-scout-pkg/skills/trust.md +120 -0
  75. package/monol-plugin-scout-pkg/skills/trusted-install.md +264 -0
  76. package/monol-plugin-scout-pkg/skills/uninstall.md +100 -0
  77. package/monol-plugin-scout-pkg/web/components/activity-chart.js +208 -0
  78. package/monol-plugin-scout-pkg/web/components/index.js +27 -0
  79. package/monol-plugin-scout-pkg/web/components/insight-card.js +365 -0
  80. package/monol-plugin-scout-pkg/web/components/overview.js +154 -0
  81. package/monol-plugin-scout-pkg/web/components/plugin-list.js +242 -0
  82. package/monol-plugin-scout-pkg/web/components/stats-card.js +126 -0
  83. package/monol-plugin-scout-pkg/web/components/team-list.js +346 -0
  84. package/monol-plugin-scout-pkg/web/console.html +2098 -0
  85. package/monol-plugin-scout-pkg/web/dashboard.html +2106 -0
  86. package/monol-plugin-scout-pkg/web/manifest.json +29 -0
  87. package/package.json +1 -1
@@ -0,0 +1,360 @@
1
+ #!/bin/bash
2
+ # Plugin Scout - 데이터 검증 유틸리티
3
+ # JSON 파일 검증 및 복구
4
+
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}"
6
+ DATA_DIR="$PLUGIN_ROOT/data"
7
+ BACKUP_DIR="$DATA_DIR/backups"
8
+
9
+ # 백업 디렉토리 생성
10
+ mkdir -p "$BACKUP_DIR"
11
+
12
+ # JSON 파일 유효성 검사
13
+ validate_json() {
14
+ local file="$1"
15
+
16
+ if [ ! -f "$file" ]; then
17
+ echo "error:not_found"
18
+ return 1
19
+ fi
20
+
21
+ if ! command -v jq &> /dev/null; then
22
+ echo "error:jq_not_found"
23
+ return 1
24
+ fi
25
+
26
+ if jq empty "$file" 2>/dev/null; then
27
+ echo "valid"
28
+ return 0
29
+ else
30
+ echo "error:invalid_json"
31
+ return 1
32
+ fi
33
+ }
34
+
35
+ # 파일 백업
36
+ backup_file() {
37
+ local file="$1"
38
+ local filename=$(basename "$file")
39
+ local timestamp=$(date +"%Y%m%d_%H%M%S")
40
+ local backup_path="$BACKUP_DIR/${filename}.${timestamp}.bak"
41
+
42
+ if [ -f "$file" ]; then
43
+ cp "$file" "$backup_path"
44
+ echo "$backup_path"
45
+ fi
46
+ }
47
+
48
+ # history.json 스키마 검증
49
+ validate_history() {
50
+ local file="$DATA_DIR/history.json"
51
+
52
+ if ! validate_json "$file" >/dev/null; then
53
+ echo "invalid"
54
+ return 1
55
+ fi
56
+
57
+ # 필수 필드 검증
58
+ local has_version=$(jq -r 'has("version")' "$file")
59
+ local has_declined=$(jq -r 'has("declined")' "$file")
60
+ local has_preferences=$(jq -r 'has("preferences")' "$file")
61
+
62
+ if [ "$has_version" = "true" ] && [ "$has_declined" = "true" ] && [ "$has_preferences" = "true" ]; then
63
+ echo "valid"
64
+ return 0
65
+ else
66
+ echo "missing_fields"
67
+ return 1
68
+ fi
69
+ }
70
+
71
+ # usage.json 스키마 검증
72
+ validate_usage() {
73
+ local file="$DATA_DIR/usage.json"
74
+
75
+ if ! validate_json "$file" >/dev/null; then
76
+ echo "invalid"
77
+ return 1
78
+ fi
79
+
80
+ # 필수 필드 검증
81
+ local has_plugins=$(jq -r 'has("plugins")' "$file")
82
+ local has_sessions=$(jq -r 'has("sessions")' "$file")
83
+
84
+ if [ "$has_plugins" = "true" ] && [ "$has_sessions" = "true" ]; then
85
+ echo "valid"
86
+ return 0
87
+ else
88
+ echo "missing_fields"
89
+ return 1
90
+ fi
91
+ }
92
+
93
+ # team.json 스키마 검증
94
+ validate_team() {
95
+ local file="$DATA_DIR/team.json"
96
+
97
+ if ! validate_json "$file" >/dev/null; then
98
+ echo "invalid"
99
+ return 1
100
+ fi
101
+
102
+ # 필수 필드 검증
103
+ local has_version=$(jq -r 'has("version")' "$file")
104
+ local has_members=$(jq -r 'has("members")' "$file")
105
+ local has_stats=$(jq -r 'has("stats")' "$file")
106
+
107
+ if [ "$has_version" = "true" ] && [ "$has_members" = "true" ] && [ "$has_stats" = "true" ]; then
108
+ echo "valid"
109
+ return 0
110
+ else
111
+ echo "missing_fields"
112
+ return 1
113
+ fi
114
+ }
115
+
116
+ # history.json 초기화
117
+ init_history() {
118
+ local file="$DATA_DIR/history.json"
119
+ local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
120
+
121
+ # 기존 파일 백업
122
+ if [ -f "$file" ]; then
123
+ backup_file "$file"
124
+ fi
125
+
126
+ cat > "$file" << EOF
127
+ {
128
+ "version": "2.0.0",
129
+ "declined": {},
130
+ "installed": {},
131
+ "viewed": [],
132
+ "rejectionPatterns": {
133
+ "byCategory": {},
134
+ "byReason": {}
135
+ },
136
+ "rejectionReasons": {
137
+ "not-relevant": "프로젝트에 관련 없음",
138
+ "wrong-language": "다른 언어용",
139
+ "already-have": "유사 플러그인 보유",
140
+ "too-complex": "복잡함",
141
+ "security": "보안 우려",
142
+ "other": "기타"
143
+ },
144
+ "preferences": {
145
+ "categories": [],
146
+ "autoInstall": false,
147
+ "quietMode": false,
148
+ "recommendationCooldown": 30,
149
+ "maxRejectionsBeforeBlock": 3,
150
+ "maxRecommendationsPerSession": 1,
151
+ "maxRecommendationsPerDay": 3,
152
+ "smartTiming": {
153
+ "onlyAfterCommit": false,
154
+ "onlyAfterPR": false
155
+ }
156
+ },
157
+ "updatedAt": "$now"
158
+ }
159
+ EOF
160
+
161
+ echo "initialized"
162
+ }
163
+
164
+ # usage.json 초기화
165
+ init_usage() {
166
+ local file="$DATA_DIR/usage.json"
167
+ local now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
168
+
169
+ # 기존 파일 백업
170
+ if [ -f "$file" ]; then
171
+ backup_file "$file"
172
+ fi
173
+
174
+ cat > "$file" << EOF
175
+ {
176
+ "plugins": {},
177
+ "users": {},
178
+ "sessions": {
179
+ "total": 0,
180
+ "thisWeek": 0
181
+ },
182
+ "lastUpdated": "$now"
183
+ }
184
+ EOF
185
+
186
+ echo "initialized"
187
+ }
188
+
189
+ # 모든 데이터 파일 검증
190
+ validate_all() {
191
+ echo "=== Data Validation ==="
192
+ echo ""
193
+
194
+ local all_valid=true
195
+
196
+ # history.json
197
+ echo -n "history.json: "
198
+ if [ -f "$DATA_DIR/history.json" ]; then
199
+ local result=$(validate_history)
200
+ echo "$result"
201
+ [ "$result" != "valid" ] && all_valid=false
202
+ else
203
+ echo "not_found"
204
+ all_valid=false
205
+ fi
206
+
207
+ # usage.json
208
+ echo -n "usage.json: "
209
+ if [ -f "$DATA_DIR/usage.json" ]; then
210
+ local result=$(validate_usage)
211
+ echo "$result"
212
+ [ "$result" != "valid" ] && all_valid=false
213
+ else
214
+ echo "not_found"
215
+ all_valid=false
216
+ fi
217
+
218
+ # team.json
219
+ echo -n "team.json: "
220
+ if [ -f "$DATA_DIR/team.json" ]; then
221
+ local result=$(validate_team)
222
+ echo "$result"
223
+ [ "$result" != "valid" ] && all_valid=false
224
+ else
225
+ echo "not_found (optional)"
226
+ fi
227
+
228
+ # .session
229
+ echo -n ".session: "
230
+ if [ -f "$DATA_DIR/.session" ]; then
231
+ local result=$(validate_json "$DATA_DIR/.session")
232
+ echo "$result"
233
+ [ "$result" != "valid" ] && all_valid=false
234
+ else
235
+ echo "not_found (runtime)"
236
+ fi
237
+
238
+ echo ""
239
+ if [ "$all_valid" = "true" ]; then
240
+ echo "All data files are valid."
241
+ else
242
+ echo "Some data files need attention."
243
+ fi
244
+ }
245
+
246
+ # 손상된 파일 복구
247
+ repair() {
248
+ local file="$1"
249
+
250
+ case "$file" in
251
+ history)
252
+ echo "Repairing history.json..."
253
+ init_history
254
+ ;;
255
+ usage)
256
+ echo "Repairing usage.json..."
257
+ init_usage
258
+ ;;
259
+ all)
260
+ echo "Repairing all data files..."
261
+ init_history
262
+ init_usage
263
+ ;;
264
+ *)
265
+ echo "Usage: repair {history|usage|all}"
266
+ ;;
267
+ esac
268
+ }
269
+
270
+ # 백업 목록
271
+ list_backups() {
272
+ echo "=== Backups ==="
273
+ if [ -d "$BACKUP_DIR" ] && [ "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]; then
274
+ ls -la "$BACKUP_DIR"
275
+ else
276
+ echo "No backups found"
277
+ fi
278
+ }
279
+
280
+ # 백업에서 복원
281
+ restore_backup() {
282
+ local backup_file="$1"
283
+
284
+ if [ -z "$backup_file" ]; then
285
+ echo "Usage: restore <backup-file>"
286
+ list_backups
287
+ return 1
288
+ fi
289
+
290
+ local full_path="$BACKUP_DIR/$backup_file"
291
+ if [ ! -f "$full_path" ]; then
292
+ echo "Backup not found: $backup_file"
293
+ return 1
294
+ fi
295
+
296
+ # 파일명에서 원본 파일명 추출
297
+ local original_name=$(echo "$backup_file" | sed 's/\.[0-9]*_[0-9]*\.bak$//')
298
+ local target_file="$DATA_DIR/$original_name"
299
+
300
+ # 현재 파일 백업 후 복원
301
+ if [ -f "$target_file" ]; then
302
+ backup_file "$target_file"
303
+ fi
304
+
305
+ cp "$full_path" "$target_file"
306
+ echo "Restored: $original_name from $backup_file"
307
+ }
308
+
309
+ # CLI 인터페이스
310
+ case "$1" in
311
+ validate)
312
+ validate_all
313
+ ;;
314
+ check)
315
+ validate_json "$2"
316
+ ;;
317
+ history)
318
+ validate_history
319
+ ;;
320
+ usage)
321
+ validate_usage
322
+ ;;
323
+ team)
324
+ validate_team
325
+ ;;
326
+ init)
327
+ case "$2" in
328
+ history) init_history ;;
329
+ usage) init_usage ;;
330
+ *) echo "Usage: init {history|usage}" ;;
331
+ esac
332
+ ;;
333
+ repair)
334
+ repair "$2"
335
+ ;;
336
+ backup)
337
+ backup_file "$2"
338
+ ;;
339
+ backups)
340
+ list_backups
341
+ ;;
342
+ restore)
343
+ restore_backup "$2"
344
+ ;;
345
+ *)
346
+ echo "Usage: $0 {validate|check|history|usage|team|init|repair|backup|backups|restore}"
347
+ echo ""
348
+ echo "Commands:"
349
+ echo " validate - Validate all data files"
350
+ echo " check <file> - Check if JSON file is valid"
351
+ echo " history - Validate history.json schema"
352
+ echo " usage - Validate usage.json schema"
353
+ echo " team - Validate team.json schema"
354
+ echo " init <type> - Initialize data file (history|usage)"
355
+ echo " repair <type> - Repair corrupted file (history|usage|all)"
356
+ echo " backup <file> - Create backup of file"
357
+ echo " backups - List all backups"
358
+ echo " restore <backup> - Restore from backup"
359
+ ;;
360
+ esac
@@ -0,0 +1,296 @@
1
+ #!/bin/bash
2
+ # Plugin Scout - 에러 처리 유틸리티
3
+ # 에러 로깅, 복구, 알림
4
+
5
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(dirname "$0")/..}"
6
+ DATA_DIR="$PLUGIN_ROOT/data"
7
+ LOG_DIR="$DATA_DIR/logs"
8
+ ERROR_LOG="$LOG_DIR/error.log"
9
+
10
+ # 로그 디렉토리 생성
11
+ mkdir -p "$LOG_DIR"
12
+
13
+ # 에러 코드 정의 (bash 3.x 호환)
14
+ get_error_message() {
15
+ local code="$1"
16
+ case "$code" in
17
+ E001) echo "jq not found" ;;
18
+ E002) echo "Invalid JSON file" ;;
19
+ E003) echo "File not found" ;;
20
+ E004) echo "Permission denied" ;;
21
+ E005) echo "Network error" ;;
22
+ E006) echo "Data corruption" ;;
23
+ E007) echo "Unknown error" ;;
24
+ *) echo "Unknown error" ;;
25
+ esac
26
+ }
27
+
28
+ # 에러 로그 기록
29
+ log_error() {
30
+ local code="$1"
31
+ local default_msg=$(get_error_message "$code")
32
+ local message="${2:-$default_msg}"
33
+ local context="$3"
34
+ local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
35
+
36
+ # 로그 파일에 기록
37
+ echo "[$timestamp] [$code] $message ${context:+| Context: $context}" >> "$ERROR_LOG"
38
+
39
+ # stderr로도 출력 (디버깅용)
40
+ if [ "$SCOUT_DEBUG" = "true" ]; then
41
+ echo "ERROR [$code]: $message" >&2
42
+ fi
43
+ }
44
+
45
+ # 에러 처리 및 복구 시도
46
+ handle_error() {
47
+ local code="$1"
48
+ local context="$2"
49
+
50
+ log_error "$code" "" "$context"
51
+
52
+ case "$code" in
53
+ E001)
54
+ echo "jq is required. Install with: brew install jq"
55
+ return 1
56
+ ;;
57
+ E002)
58
+ # Invalid JSON - 복구 시도
59
+ echo "Attempting to recover invalid JSON..."
60
+ if [ -f "$PLUGIN_ROOT/lib/data-validator.sh" ]; then
61
+ bash "$PLUGIN_ROOT/lib/data-validator.sh" repair all
62
+ fi
63
+ ;;
64
+ E003)
65
+ # File not found - 초기화
66
+ echo "File not found. Initializing..."
67
+ if [ -f "$PLUGIN_ROOT/lib/data-validator.sh" ]; then
68
+ bash "$PLUGIN_ROOT/lib/data-validator.sh" init history
69
+ bash "$PLUGIN_ROOT/lib/data-validator.sh" init usage
70
+ fi
71
+ ;;
72
+ E004)
73
+ echo "Permission denied. Check file permissions."
74
+ return 1
75
+ ;;
76
+ E005)
77
+ echo "Network error. Will retry later."
78
+ return 1
79
+ ;;
80
+ E006)
81
+ echo "Data corruption detected. Attempting recovery..."
82
+ if [ -f "$PLUGIN_ROOT/lib/data-validator.sh" ]; then
83
+ bash "$PLUGIN_ROOT/lib/data-validator.sh" repair all
84
+ fi
85
+ ;;
86
+ *)
87
+ echo "Unknown error: $code"
88
+ return 1
89
+ ;;
90
+ esac
91
+ }
92
+
93
+ # 안전한 JSON 읽기
94
+ safe_json_read() {
95
+ local file="$1"
96
+ local query="${2:-.}"
97
+ local default="${3:-null}"
98
+
99
+ if [ ! -f "$file" ]; then
100
+ log_error "E003" "File not found" "$file"
101
+ echo "$default"
102
+ return 1
103
+ fi
104
+
105
+ if ! command -v jq &> /dev/null; then
106
+ log_error "E001" "jq not found"
107
+ echo "$default"
108
+ return 1
109
+ fi
110
+
111
+ local result
112
+ result=$(jq -r "$query" "$file" 2>/dev/null)
113
+ local exit_code=$?
114
+
115
+ if [ $exit_code -ne 0 ] || [ "$result" = "null" ] && [ "$default" != "null" ]; then
116
+ log_error "E002" "JSON read failed" "$file: $query"
117
+ echo "$default"
118
+ return 1
119
+ fi
120
+
121
+ echo "$result"
122
+ }
123
+
124
+ # 안전한 JSON 쓰기
125
+ safe_json_write() {
126
+ local file="$1"
127
+ local query="$2"
128
+
129
+ if ! command -v jq &> /dev/null; then
130
+ log_error "E001" "jq not found"
131
+ return 1
132
+ fi
133
+
134
+ if [ ! -f "$file" ]; then
135
+ log_error "E003" "File not found" "$file"
136
+ return 1
137
+ fi
138
+
139
+ local temp_file="${file}.tmp"
140
+
141
+ if ! jq "$query" "$file" > "$temp_file" 2>/dev/null; then
142
+ log_error "E002" "JSON write failed" "$file: $query"
143
+ rm -f "$temp_file"
144
+ return 1
145
+ fi
146
+
147
+ if ! mv "$temp_file" "$file"; then
148
+ log_error "E004" "Permission denied" "$file"
149
+ rm -f "$temp_file"
150
+ return 1
151
+ fi
152
+
153
+ return 0
154
+ }
155
+
156
+ # 에러 로그 조회
157
+ view_errors() {
158
+ local lines="${1:-20}"
159
+
160
+ if [ ! -f "$ERROR_LOG" ]; then
161
+ echo "No errors logged yet."
162
+ return
163
+ fi
164
+
165
+ echo "=== Recent Errors (last $lines) ==="
166
+ tail -n "$lines" "$ERROR_LOG"
167
+ }
168
+
169
+ # 에러 로그 정리
170
+ cleanup_errors() {
171
+ local days="${1:-7}"
172
+
173
+ if [ ! -f "$ERROR_LOG" ]; then
174
+ echo "No error log to clean."
175
+ return
176
+ fi
177
+
178
+ local cutoff_date=$(date -v-${days}d +"%Y-%m-%d" 2>/dev/null || date -d "$days days ago" +"%Y-%m-%d" 2>/dev/null)
179
+
180
+ if [ -n "$cutoff_date" ]; then
181
+ # 날짜 이후 로그만 유지
182
+ grep -E "^\[${cutoff_date}|^\[$(date +%Y-)" "$ERROR_LOG" > "$ERROR_LOG.tmp" 2>/dev/null
183
+ mv "$ERROR_LOG.tmp" "$ERROR_LOG"
184
+ echo "Cleaned errors older than $days days."
185
+ else
186
+ echo "Could not determine cutoff date."
187
+ fi
188
+ }
189
+
190
+ # 에러 통계
191
+ error_stats() {
192
+ if [ ! -f "$ERROR_LOG" ]; then
193
+ echo "No errors logged yet."
194
+ return
195
+ fi
196
+
197
+ echo "=== Error Statistics ==="
198
+ echo ""
199
+ echo "By Error Code:"
200
+ grep -oE '\[E[0-9]+\]' "$ERROR_LOG" | sort | uniq -c | sort -rn
201
+ echo ""
202
+ echo "By Date:"
203
+ grep -oE '^\[[0-9]{4}-[0-9]{2}-[0-9]{2}' "$ERROR_LOG" | sort | uniq -c | tail -7
204
+ echo ""
205
+ echo "Total Errors: $(wc -l < "$ERROR_LOG" | tr -d ' ')"
206
+ }
207
+
208
+ # 시스템 상태 확인
209
+ health_check() {
210
+ echo "=== Health Check ==="
211
+ echo ""
212
+
213
+ # jq 확인
214
+ echo -n "jq: "
215
+ if command -v jq &> /dev/null; then
216
+ echo "OK ($(jq --version))"
217
+ else
218
+ echo "NOT FOUND"
219
+ fi
220
+
221
+ # 데이터 디렉토리 확인
222
+ echo -n "Data directory: "
223
+ if [ -d "$DATA_DIR" ] && [ -w "$DATA_DIR" ]; then
224
+ echo "OK (writable)"
225
+ else
226
+ echo "ERROR (not writable)"
227
+ fi
228
+
229
+ # JSON 파일 확인
230
+ echo ""
231
+ echo "Data Files:"
232
+ for file in history.json usage.json team.json; do
233
+ echo -n " $file: "
234
+ if [ -f "$DATA_DIR/$file" ]; then
235
+ if jq empty "$DATA_DIR/$file" 2>/dev/null; then
236
+ echo "OK"
237
+ else
238
+ echo "INVALID JSON"
239
+ fi
240
+ else
241
+ echo "NOT FOUND"
242
+ fi
243
+ done
244
+
245
+ # 최근 에러 확인
246
+ echo ""
247
+ echo -n "Recent errors (24h): "
248
+ if [ -f "$ERROR_LOG" ]; then
249
+ local today=$(date +"%Y-%m-%d")
250
+ local count=$(grep -c "^\[$today" "$ERROR_LOG" 2>/dev/null || echo "0")
251
+ echo "$count"
252
+ else
253
+ echo "0"
254
+ fi
255
+ }
256
+
257
+ # CLI 인터페이스
258
+ case "$1" in
259
+ log)
260
+ log_error "$2" "$3" "$4"
261
+ ;;
262
+ handle)
263
+ handle_error "$2" "$3"
264
+ ;;
265
+ read)
266
+ safe_json_read "$2" "$3" "$4"
267
+ ;;
268
+ write)
269
+ safe_json_write "$2" "$3"
270
+ ;;
271
+ view)
272
+ view_errors "$2"
273
+ ;;
274
+ cleanup)
275
+ cleanup_errors "$2"
276
+ ;;
277
+ stats)
278
+ error_stats
279
+ ;;
280
+ health)
281
+ health_check
282
+ ;;
283
+ *)
284
+ echo "Usage: $0 {log|handle|read|write|view|cleanup|stats|health}"
285
+ echo ""
286
+ echo "Commands:"
287
+ echo " log <code> [msg] [ctx] - Log an error"
288
+ echo " handle <code> [ctx] - Handle error with recovery"
289
+ echo " read <file> [query] - Safe JSON read"
290
+ echo " write <file> <query> - Safe JSON write"
291
+ echo " view [lines] - View recent errors"
292
+ echo " cleanup [days] - Clean old error logs"
293
+ echo " stats - Show error statistics"
294
+ echo " health - System health check"
295
+ ;;
296
+ esac