jfl 0.1.0 → 0.2.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/README.md +443 -145
- package/clawdbot-plugin/clawdbot.plugin.json +20 -0
- package/clawdbot-plugin/index.js +555 -0
- package/clawdbot-plugin/index.ts +582 -0
- package/clawdbot-skill/SKILL.md +33 -336
- package/clawdbot-skill/index.ts +491 -321
- package/clawdbot-skill/skill.json +4 -13
- package/dist/commands/clawdbot.d.ts +11 -0
- package/dist/commands/clawdbot.d.ts.map +1 -0
- package/dist/commands/clawdbot.js +215 -0
- package/dist/commands/clawdbot.js.map +1 -0
- package/dist/commands/context-hub.d.ts +5 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +394 -28
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/gtm-process-update.d.ts +10 -0
- package/dist/commands/gtm-process-update.d.ts.map +1 -0
- package/dist/commands/gtm-process-update.js +101 -0
- package/dist/commands/gtm-process-update.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +278 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +32 -33
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/memory.d.ts +38 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +229 -0
- package/dist/commands/memory.js.map +1 -0
- package/dist/commands/migrate-services.d.ts +8 -0
- package/dist/commands/migrate-services.d.ts.map +1 -0
- package/dist/commands/migrate-services.js +182 -0
- package/dist/commands/migrate-services.js.map +1 -0
- package/dist/commands/onboard.d.ts +24 -0
- package/dist/commands/onboard.d.ts.map +1 -0
- package/dist/commands/onboard.js +663 -0
- package/dist/commands/onboard.js.map +1 -0
- package/dist/commands/openclaw.d.ts +56 -0
- package/dist/commands/openclaw.d.ts.map +1 -0
- package/dist/commands/openclaw.js +700 -0
- package/dist/commands/openclaw.js.map +1 -0
- package/dist/commands/orchestrate.d.ts +14 -0
- package/dist/commands/orchestrate.d.ts.map +1 -0
- package/dist/commands/orchestrate.js +270 -0
- package/dist/commands/orchestrate.js.map +1 -0
- package/dist/commands/profile.d.ts +46 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +498 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/repair.d.ts.map +1 -1
- package/dist/commands/repair.js +37 -0
- package/dist/commands/repair.js.map +1 -1
- package/dist/commands/service-agent.d.ts +16 -0
- package/dist/commands/service-agent.d.ts.map +1 -0
- package/dist/commands/service-agent.js +375 -0
- package/dist/commands/service-agent.js.map +1 -0
- package/dist/commands/service-manager.d.ts +12 -0
- package/dist/commands/service-manager.d.ts.map +1 -0
- package/dist/commands/service-manager.js +967 -0
- package/dist/commands/service-manager.js.map +1 -0
- package/dist/commands/service-validate.d.ts +12 -0
- package/dist/commands/service-validate.d.ts.map +1 -0
- package/dist/commands/service-validate.js +611 -0
- package/dist/commands/service-validate.js.map +1 -0
- package/dist/commands/services-create.d.ts +15 -0
- package/dist/commands/services-create.d.ts.map +1 -0
- package/dist/commands/services-create.js +1452 -0
- package/dist/commands/services-create.js.map +1 -0
- package/dist/commands/services-scan.d.ts +13 -0
- package/dist/commands/services-scan.d.ts.map +1 -0
- package/dist/commands/services-scan.js +251 -0
- package/dist/commands/services-scan.js.map +1 -0
- package/dist/commands/services-sync-agents.d.ts +23 -0
- package/dist/commands/services-sync-agents.d.ts.map +1 -0
- package/dist/commands/services-sync-agents.js +207 -0
- package/dist/commands/services-sync-agents.js.map +1 -0
- package/dist/commands/services.d.ts +19 -0
- package/dist/commands/services.d.ts.map +1 -0
- package/dist/commands/services.js +742 -0
- package/dist/commands/services.js.map +1 -0
- package/dist/commands/session.d.ts +5 -1
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +68 -586
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +17 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +75 -21
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate-settings.d.ts +37 -0
- package/dist/commands/validate-settings.d.ts.map +1 -0
- package/dist/commands/validate-settings.js +197 -0
- package/dist/commands/validate-settings.js.map +1 -0
- package/dist/commands/voice.d.ts +0 -1
- package/dist/commands/voice.d.ts.map +1 -1
- package/dist/commands/voice.js +16 -15
- package/dist/commands/voice.js.map +1 -1
- package/dist/index.js +395 -141
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-generator.d.ts +26 -0
- package/dist/lib/agent-generator.d.ts.map +1 -0
- package/dist/lib/agent-generator.js +331 -0
- package/dist/lib/agent-generator.js.map +1 -0
- package/dist/lib/memory-db.d.ts +102 -0
- package/dist/lib/memory-db.d.ts.map +1 -0
- package/dist/lib/memory-db.js +313 -0
- package/dist/lib/memory-db.js.map +1 -0
- package/dist/lib/memory-indexer.d.ts +47 -0
- package/dist/lib/memory-indexer.d.ts.map +1 -0
- package/dist/lib/memory-indexer.js +215 -0
- package/dist/lib/memory-indexer.js.map +1 -0
- package/dist/lib/memory-search.d.ts +41 -0
- package/dist/lib/memory-search.d.ts.map +1 -0
- package/dist/lib/memory-search.js +246 -0
- package/dist/lib/memory-search.js.map +1 -0
- package/dist/lib/openclaw-registry.d.ts +48 -0
- package/dist/lib/openclaw-registry.d.ts.map +1 -0
- package/dist/lib/openclaw-registry.js +181 -0
- package/dist/lib/openclaw-registry.js.map +1 -0
- package/dist/lib/openclaw-sdk.d.ts +107 -0
- package/dist/lib/openclaw-sdk.d.ts.map +1 -0
- package/dist/lib/openclaw-sdk.js +208 -0
- package/dist/lib/openclaw-sdk.js.map +1 -0
- package/dist/lib/peer-agent-generator.d.ts +44 -0
- package/dist/lib/peer-agent-generator.d.ts.map +1 -0
- package/dist/lib/peer-agent-generator.js +286 -0
- package/dist/lib/peer-agent-generator.js.map +1 -0
- package/dist/lib/service-dependencies.d.ts +44 -0
- package/dist/lib/service-dependencies.d.ts.map +1 -0
- package/dist/lib/service-dependencies.js +314 -0
- package/dist/lib/service-dependencies.js.map +1 -0
- package/dist/lib/service-detector.d.ts +61 -0
- package/dist/lib/service-detector.d.ts.map +1 -0
- package/dist/lib/service-detector.js +521 -0
- package/dist/lib/service-detector.js.map +1 -0
- package/dist/lib/service-gtm.d.ts +157 -0
- package/dist/lib/service-gtm.d.ts.map +1 -0
- package/dist/lib/service-gtm.js +786 -0
- package/dist/lib/service-gtm.js.map +1 -0
- package/dist/lib/service-mcp-base.d.ts +103 -0
- package/dist/lib/service-mcp-base.d.ts.map +1 -0
- package/dist/lib/service-mcp-base.js +263 -0
- package/dist/lib/service-mcp-base.js.map +1 -0
- package/dist/lib/service-utils.d.ts +103 -0
- package/dist/lib/service-utils.d.ts.map +1 -0
- package/dist/lib/service-utils.js +368 -0
- package/dist/lib/service-utils.js.map +1 -0
- package/dist/lib/skill-generator.d.ts +21 -0
- package/dist/lib/skill-generator.d.ts.map +1 -0
- package/dist/lib/skill-generator.js +253 -0
- package/dist/lib/skill-generator.js.map +1 -0
- package/dist/lib/stratus-client.d.ts +100 -0
- package/dist/lib/stratus-client.d.ts.map +1 -0
- package/dist/lib/stratus-client.js +255 -0
- package/dist/lib/stratus-client.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +135 -53
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/mcp/service-mcp-server.d.ts +12 -0
- package/dist/mcp/service-mcp-server.d.ts.map +1 -0
- package/dist/mcp/service-mcp-server.js +434 -0
- package/dist/mcp/service-mcp-server.js.map +1 -0
- package/dist/mcp/service-peer-mcp.d.ts +36 -0
- package/dist/mcp/service-peer-mcp.d.ts.map +1 -0
- package/dist/mcp/service-peer-mcp.js +220 -0
- package/dist/mcp/service-peer-mcp.js.map +1 -0
- package/dist/mcp/service-registry-mcp.d.ts +13 -0
- package/dist/mcp/service-registry-mcp.d.ts.map +1 -0
- package/dist/mcp/service-registry-mcp.js +330 -0
- package/dist/mcp/service-registry-mcp.js.map +1 -0
- package/dist/ui/banner.js +1 -1
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/context-hub-logs.d.ts +10 -0
- package/dist/ui/context-hub-logs.d.ts.map +1 -0
- package/dist/ui/context-hub-logs.js +175 -0
- package/dist/ui/context-hub-logs.js.map +1 -0
- package/dist/ui/service-dashboard.d.ts +11 -0
- package/dist/ui/service-dashboard.d.ts.map +1 -0
- package/dist/ui/service-dashboard.js +357 -0
- package/dist/ui/service-dashboard.js.map +1 -0
- package/dist/ui/services-manager.d.ts +11 -0
- package/dist/ui/services-manager.d.ts.map +1 -0
- package/dist/ui/services-manager.js +507 -0
- package/dist/ui/services-manager.js.map +1 -0
- package/dist/utils/auth-guard.d.ts.map +1 -1
- package/dist/utils/auth-guard.js +8 -9
- package/dist/utils/auth-guard.js.map +1 -1
- package/dist/utils/claude-md-generator.d.ts +10 -0
- package/dist/utils/claude-md-generator.d.ts.map +1 -0
- package/dist/utils/claude-md-generator.js +215 -0
- package/dist/utils/claude-md-generator.js.map +1 -0
- package/dist/utils/ensure-context-hub.d.ts +20 -0
- package/dist/utils/ensure-context-hub.d.ts.map +1 -0
- package/dist/utils/ensure-context-hub.js +65 -0
- package/dist/utils/ensure-context-hub.js.map +1 -0
- package/dist/utils/ensure-project.d.ts.map +1 -1
- package/dist/utils/ensure-project.js +3 -4
- package/dist/utils/ensure-project.js.map +1 -1
- package/dist/utils/jfl-config.d.ts +19 -0
- package/dist/utils/jfl-config.d.ts.map +1 -0
- package/dist/utils/jfl-config.js +112 -0
- package/dist/utils/jfl-config.js.map +1 -0
- package/dist/utils/jfl-migration.d.ts +29 -0
- package/dist/utils/jfl-migration.d.ts.map +1 -0
- package/dist/utils/jfl-migration.js +142 -0
- package/dist/utils/jfl-migration.js.map +1 -0
- package/dist/utils/jfl-paths.d.ts +55 -0
- package/dist/utils/jfl-paths.d.ts.map +1 -0
- package/dist/utils/jfl-paths.js +120 -0
- package/dist/utils/jfl-paths.js.map +1 -0
- package/dist/utils/settings-validator.d.ts +73 -0
- package/dist/utils/settings-validator.d.ts.map +1 -0
- package/dist/utils/settings-validator.js +222 -0
- package/dist/utils/settings-validator.js.map +1 -0
- package/package.json +19 -3
- package/scripts/commit-gtm.sh +56 -0
- package/scripts/commit-product.sh +68 -0
- package/scripts/context-query.sh +45 -0
- package/scripts/session/auto-commit.sh +297 -0
- package/scripts/session/jfl-doctor.sh +707 -0
- package/scripts/session/session-cleanup.sh +268 -0
- package/scripts/session/session-end.sh +198 -0
- package/scripts/session/session-init.sh +350 -0
- package/scripts/session/session-init.sh.backup +292 -0
- package/scripts/session/session-sync.sh +167 -0
- package/scripts/session/test-context-preservation.sh +160 -0
- package/scripts/session/test-critical-infrastructure.sh +293 -0
- package/scripts/session/test-experience-level.sh +336 -0
- package/scripts/session/test-session-cleanup.sh +268 -0
- package/scripts/session/test-session-sync.sh +320 -0
- package/scripts/voice-start.sh +36 -8
- package/scripts/where-am-i.sh +78 -0
- package/template/.claude/service-settings.json +32 -0
- package/template/.claude/settings.json +14 -1
- package/template/.claude/skills/end/SKILL.md +1780 -0
- package/template/.jfl/config.json +2 -1
- package/template/CLAUDE.md +1039 -134
- package/template/CLAUDE.md.bak +1187 -0
- package/template/scripts/commit-gtm.sh +56 -0
- package/template/scripts/commit-product.sh +68 -0
- package/template/scripts/migrate-to-branch-sessions.sh +201 -0
- package/template/scripts/session/auto-commit.sh +58 -6
- package/template/scripts/session/jfl-doctor.sh +137 -17
- package/template/scripts/session/session-cleanup.sh +268 -0
- package/template/scripts/session/session-end.sh +4 -0
- package/template/scripts/session/session-init.sh +253 -66
- package/template/scripts/session/test-critical-infrastructure.sh +293 -0
- package/template/scripts/session/test-experience-level.sh +336 -0
- package/template/scripts/session/test-session-cleanup.sh +268 -0
- package/template/scripts/session/test-session-sync.sh +320 -0
- package/template/scripts/where-am-i.sh +78 -0
- package/template/templates/service-agent/.claude/settings.json +32 -0
- package/template/templates/service-agent/CLAUDE.md +334 -0
- package/template/templates/service-agent/knowledge/ARCHITECTURE.md +115 -0
- package/template/templates/service-agent/knowledge/DEPLOYMENT.md +199 -0
- package/template/templates/service-agent/knowledge/RUNBOOK.md +412 -0
- package/template/templates/service-agent/knowledge/SERVICE_SPEC.md +77 -0
- package/dist/commands/session-mgmt.d.ts +0 -33
- package/dist/commands/session-mgmt.d.ts.map +0 -1
- package/dist/commands/session-mgmt.js +0 -404
- package/dist/commands/session-mgmt.js.map +0 -1
- package/template/scripts/session/auto-merge.sh +0 -325
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# jfl-doctor.sh - Health check for JFL projects
|
|
4
|
+
# Inspired by Takopi's doctor command
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./scripts/session/jfl-doctor.sh # Run health checks
|
|
8
|
+
# ./scripts/session/jfl-doctor.sh --fix # Auto-fix issues
|
|
9
|
+
# ./scripts/session/jfl-doctor.sh --json # Output as JSON
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
# Require bash 4+ for associative arrays, or work around it
|
|
14
|
+
if [[ "${BASH_VERSINFO[0]}" -lt 4 ]]; then
|
|
15
|
+
# Fallback for older bash - just track counts
|
|
16
|
+
USE_ASSOC_ARRAYS=false
|
|
17
|
+
else
|
|
18
|
+
USE_ASSOC_ARRAYS=true
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
22
|
+
# Find main repo root (handles running from worktree or main repo)
|
|
23
|
+
if git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
|
24
|
+
# Get the main repo root (not the worktree path)
|
|
25
|
+
REPO_DIR="$(git rev-parse --path-format=absolute --git-common-dir)"
|
|
26
|
+
REPO_DIR="${REPO_DIR%/.git}" # Remove /.git suffix
|
|
27
|
+
else
|
|
28
|
+
REPO_DIR="$(pwd)"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
WORKTREES_DIR="$REPO_DIR/worktrees"
|
|
32
|
+
SESSIONS_DIR="$REPO_DIR/.jfl/sessions"
|
|
33
|
+
|
|
34
|
+
# Colors
|
|
35
|
+
RED='\033[0;31m'
|
|
36
|
+
GREEN='\033[0;32m'
|
|
37
|
+
YELLOW='\033[1;33m'
|
|
38
|
+
BLUE='\033[0;34m'
|
|
39
|
+
NC='\033[0m'
|
|
40
|
+
|
|
41
|
+
# Parse args
|
|
42
|
+
FIX_MODE=false
|
|
43
|
+
JSON_MODE=false
|
|
44
|
+
VERBOSE=false
|
|
45
|
+
|
|
46
|
+
while [[ $# -gt 0 ]]; do
|
|
47
|
+
case $1 in
|
|
48
|
+
--fix|-f)
|
|
49
|
+
FIX_MODE=true
|
|
50
|
+
shift
|
|
51
|
+
;;
|
|
52
|
+
--json|-j)
|
|
53
|
+
JSON_MODE=true
|
|
54
|
+
shift
|
|
55
|
+
;;
|
|
56
|
+
--verbose|-v)
|
|
57
|
+
VERBOSE=true
|
|
58
|
+
shift
|
|
59
|
+
;;
|
|
60
|
+
*)
|
|
61
|
+
shift
|
|
62
|
+
;;
|
|
63
|
+
esac
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
# Check results (simple approach for bash 3 compatibility)
|
|
67
|
+
ISSUES=0
|
|
68
|
+
WARNINGS=0
|
|
69
|
+
FIXED=0
|
|
70
|
+
CHECK_RESULTS="" # Will store "name:status" pairs
|
|
71
|
+
|
|
72
|
+
# Check if a PID is still running
|
|
73
|
+
is_pid_running() {
|
|
74
|
+
local pid="$1"
|
|
75
|
+
# Validate PID is a positive integer
|
|
76
|
+
if [[ -z "$pid" ]]; then
|
|
77
|
+
return 1
|
|
78
|
+
fi
|
|
79
|
+
# Check if it's a number
|
|
80
|
+
if ! [[ "$pid" =~ ^[0-9]+$ ]]; then
|
|
81
|
+
return 1
|
|
82
|
+
fi
|
|
83
|
+
if [[ "$pid" -le 0 ]]; then
|
|
84
|
+
return 1
|
|
85
|
+
fi
|
|
86
|
+
kill -0 "$pid" 2>/dev/null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Report check result
|
|
90
|
+
report() {
|
|
91
|
+
local name="$1"
|
|
92
|
+
local status="$2" # ok, warning, error
|
|
93
|
+
local message="$3"
|
|
94
|
+
local detail="${4:-}"
|
|
95
|
+
|
|
96
|
+
# Store for JSON output
|
|
97
|
+
CHECK_RESULTS="${CHECK_RESULTS}${name}:${status};"
|
|
98
|
+
|
|
99
|
+
if $JSON_MODE; then
|
|
100
|
+
return
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
case $status in
|
|
104
|
+
ok)
|
|
105
|
+
echo -e "${GREEN}✓${NC} $name: $message"
|
|
106
|
+
;;
|
|
107
|
+
warning)
|
|
108
|
+
echo -e "${YELLOW}⚠${NC} $name: $message"
|
|
109
|
+
WARNINGS=$((WARNINGS + 1))
|
|
110
|
+
;;
|
|
111
|
+
error)
|
|
112
|
+
echo -e "${RED}✗${NC} $name: $message"
|
|
113
|
+
ISSUES=$((ISSUES + 1))
|
|
114
|
+
;;
|
|
115
|
+
esac
|
|
116
|
+
|
|
117
|
+
if [[ -n "$detail" ]] && $VERBOSE; then
|
|
118
|
+
echo " $detail"
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# Check: Git status
|
|
123
|
+
check_git() {
|
|
124
|
+
cd "$REPO_DIR"
|
|
125
|
+
|
|
126
|
+
# Check if we're in a git repo
|
|
127
|
+
if ! git rev-parse --git-dir &>/dev/null; then
|
|
128
|
+
report "git" "error" "Not a git repository"
|
|
129
|
+
return
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
# Check for uncommitted changes
|
|
133
|
+
local changes=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
134
|
+
if [[ $changes -gt 0 ]]; then
|
|
135
|
+
report "git" "warning" "$changes uncommitted changes"
|
|
136
|
+
else
|
|
137
|
+
report "git" "ok" "clean working tree"
|
|
138
|
+
fi
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Check: Submodules
|
|
142
|
+
check_submodules() {
|
|
143
|
+
cd "$REPO_DIR"
|
|
144
|
+
|
|
145
|
+
if [[ ! -f ".gitmodules" ]]; then
|
|
146
|
+
report "submodules" "ok" "none configured"
|
|
147
|
+
return
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
local submodule_paths=$(grep "path = " .gitmodules 2>/dev/null | sed 's/.*path = //')
|
|
151
|
+
local issues=0
|
|
152
|
+
local details=""
|
|
153
|
+
|
|
154
|
+
for submodule_path in $submodule_paths; do
|
|
155
|
+
local full_path="$REPO_DIR/$submodule_path"
|
|
156
|
+
|
|
157
|
+
# Resolve symlink
|
|
158
|
+
if [[ -L "$full_path" ]]; then
|
|
159
|
+
full_path=$(cd "$full_path" 2>/dev/null && pwd) || continue
|
|
160
|
+
fi
|
|
161
|
+
|
|
162
|
+
if [[ ! -d "$full_path" ]]; then
|
|
163
|
+
issues=$((issues + 1))
|
|
164
|
+
details="$details $submodule_path (missing)"
|
|
165
|
+
continue
|
|
166
|
+
fi
|
|
167
|
+
|
|
168
|
+
# Check if submodule is initialized
|
|
169
|
+
if [[ ! -d "$full_path/.git" ]] && [[ ! -f "$full_path/.git" ]]; then
|
|
170
|
+
issues=$((issues + 1))
|
|
171
|
+
details="$details $submodule_path (not initialized)"
|
|
172
|
+
continue
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Check for uncommitted changes in submodule
|
|
176
|
+
cd "$full_path"
|
|
177
|
+
local sub_changes=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
178
|
+
if [[ $sub_changes -gt 0 ]]; then
|
|
179
|
+
issues=$((issues + 1))
|
|
180
|
+
details="$details $submodule_path ($sub_changes uncommitted)"
|
|
181
|
+
fi
|
|
182
|
+
cd "$REPO_DIR"
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
if [[ $issues -gt 0 ]]; then
|
|
186
|
+
report "submodules" "warning" "$issues issue(s):$details"
|
|
187
|
+
else
|
|
188
|
+
report "submodules" "ok" "all synced"
|
|
189
|
+
fi
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
# Check: Stale sessions (PID not running)
|
|
193
|
+
check_stale_sessions() {
|
|
194
|
+
local stale_count=0
|
|
195
|
+
local stale_list=""
|
|
196
|
+
local active_count=0
|
|
197
|
+
|
|
198
|
+
if [[ ! -d "$WORKTREES_DIR" ]]; then
|
|
199
|
+
report "sessions" "ok" "no worktrees"
|
|
200
|
+
return
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
for worktree in "$WORKTREES_DIR"/session-*; do
|
|
204
|
+
if [[ -d "$worktree" ]]; then
|
|
205
|
+
local session_name=$(basename "$worktree")
|
|
206
|
+
local pid_file="$worktree/.jfl/auto-commit.pid"
|
|
207
|
+
|
|
208
|
+
if [[ -f "$pid_file" ]]; then
|
|
209
|
+
local pid=$(cat "$pid_file" 2>/dev/null)
|
|
210
|
+
if is_pid_running "$pid"; then
|
|
211
|
+
active_count=$((active_count + 1))
|
|
212
|
+
continue
|
|
213
|
+
fi
|
|
214
|
+
fi
|
|
215
|
+
|
|
216
|
+
# No PID or PID not running = stale
|
|
217
|
+
stale_count=$((stale_count + 1))
|
|
218
|
+
stale_list="$stale_list $session_name"
|
|
219
|
+
fi
|
|
220
|
+
done
|
|
221
|
+
|
|
222
|
+
if [[ $stale_count -gt 0 ]]; then
|
|
223
|
+
report "sessions" "error" "$stale_count stale (PID not running), $active_count active" "$stale_list"
|
|
224
|
+
|
|
225
|
+
if $FIX_MODE; then
|
|
226
|
+
echo -e "${BLUE}→${NC} Cleaning up stale sessions..."
|
|
227
|
+
for session in $stale_list; do
|
|
228
|
+
cleanup_stale_session "$session"
|
|
229
|
+
done
|
|
230
|
+
fi
|
|
231
|
+
elif [[ $active_count -gt 0 ]]; then
|
|
232
|
+
report "sessions" "ok" "$active_count active"
|
|
233
|
+
else
|
|
234
|
+
report "sessions" "ok" "none"
|
|
235
|
+
fi
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
# Cleanup a single stale session
|
|
239
|
+
cleanup_stale_session() {
|
|
240
|
+
local session_name="$1"
|
|
241
|
+
local worktree_path="$WORKTREES_DIR/$session_name"
|
|
242
|
+
|
|
243
|
+
echo " Cleaning: $session_name"
|
|
244
|
+
|
|
245
|
+
# Check for uncommitted work first
|
|
246
|
+
cd "$worktree_path" 2>/dev/null || return
|
|
247
|
+
local uncommitted=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
|
|
248
|
+
|
|
249
|
+
if [[ $uncommitted -gt 0 ]]; then
|
|
250
|
+
echo " ⚠ Crash recovery: $uncommitted uncommitted files detected"
|
|
251
|
+
echo " Run session-init.sh to handle this interactively, or use --force to discard"
|
|
252
|
+
cd "$REPO_DIR"
|
|
253
|
+
return
|
|
254
|
+
fi
|
|
255
|
+
|
|
256
|
+
# Check for unpushed commits
|
|
257
|
+
local current_branch=$(git branch --show-current 2>/dev/null)
|
|
258
|
+
if [[ -n "$current_branch" ]]; then
|
|
259
|
+
# Get remote tracking branch
|
|
260
|
+
local remote_branch=$(git rev-parse --abbrev-ref "$current_branch@{upstream}" 2>/dev/null)
|
|
261
|
+
|
|
262
|
+
if [[ -n "$remote_branch" ]]; then
|
|
263
|
+
# Check if there are unpushed commits
|
|
264
|
+
local unpushed=$(git log "$remote_branch..$current_branch" --oneline 2>/dev/null | wc -l | tr -d ' ')
|
|
265
|
+
|
|
266
|
+
if [[ $unpushed -gt 0 ]]; then
|
|
267
|
+
echo " ⚠ Has $unpushed unpushed commits - skipping (push first or use --force)"
|
|
268
|
+
cd "$REPO_DIR"
|
|
269
|
+
return
|
|
270
|
+
fi
|
|
271
|
+
else
|
|
272
|
+
# No upstream branch - check if branch has any commits
|
|
273
|
+
local commit_count=$(git rev-list --count "$current_branch" 2>/dev/null | tr -d ' ')
|
|
274
|
+
|
|
275
|
+
if [[ $commit_count -gt 0 ]]; then
|
|
276
|
+
echo " ⚠ Branch has commits but no remote tracking - skipping (push first or use --force)"
|
|
277
|
+
cd "$REPO_DIR"
|
|
278
|
+
return
|
|
279
|
+
fi
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
cd "$REPO_DIR"
|
|
284
|
+
|
|
285
|
+
# Stop any background processes
|
|
286
|
+
if [[ -f "$worktree_path/.jfl/auto-commit.pid" ]]; then
|
|
287
|
+
local pid=$(cat "$worktree_path/.jfl/auto-commit.pid")
|
|
288
|
+
kill "$pid" 2>/dev/null || true
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
if [[ -f "$worktree_path/.auto-merge.pid" ]]; then
|
|
292
|
+
local pid=$(cat "$worktree_path/.auto-merge.pid")
|
|
293
|
+
kill "$pid" 2>/dev/null || true
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
# Remove worktree
|
|
297
|
+
if git worktree remove "$worktree_path" --force 2>/dev/null; then
|
|
298
|
+
echo " ✓ Worktree removed"
|
|
299
|
+
fi
|
|
300
|
+
|
|
301
|
+
# Delete branch
|
|
302
|
+
if git branch -D "$session_name" 2>/dev/null; then
|
|
303
|
+
echo " ✓ Branch deleted"
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
# Remove session state
|
|
307
|
+
if [[ -f "$SESSIONS_DIR/$session_name.json" ]]; then
|
|
308
|
+
rm -f "$SESSIONS_DIR/$session_name.json"
|
|
309
|
+
fi
|
|
310
|
+
|
|
311
|
+
# Remove from jfl-services session tracking
|
|
312
|
+
if command -v curl >/dev/null 2>&1; then
|
|
313
|
+
curl -s -X DELETE "http://localhost:3401/sessions/$session_name" >/dev/null 2>&1 || true
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
FIXED=$((FIXED + 1))
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
# Check: Orphaned worktrees (git worktree prune)
|
|
320
|
+
check_orphaned_worktrees() {
|
|
321
|
+
cd "$REPO_DIR"
|
|
322
|
+
|
|
323
|
+
local orphans
|
|
324
|
+
orphans=$(git worktree list --porcelain 2>/dev/null | grep -c "prunable" 2>/dev/null) || orphans=0
|
|
325
|
+
|
|
326
|
+
if [[ "$orphans" -gt 0 ]]; then
|
|
327
|
+
report "worktrees" "warning" "$orphans orphaned (prunable)"
|
|
328
|
+
|
|
329
|
+
if $FIX_MODE; then
|
|
330
|
+
echo -e "${BLUE}→${NC} Pruning orphaned worktrees..."
|
|
331
|
+
git worktree prune
|
|
332
|
+
echo " ✓ Pruned"
|
|
333
|
+
FIXED=$((FIXED + 1))
|
|
334
|
+
fi
|
|
335
|
+
else
|
|
336
|
+
local total=$(ls -d "$WORKTREES_DIR"/session-* 2>/dev/null | wc -l | tr -d ' ')
|
|
337
|
+
report "worktrees" "ok" "$total total"
|
|
338
|
+
fi
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
# Check: Orphaned session branches
|
|
342
|
+
check_orphaned_branches() {
|
|
343
|
+
cd "$REPO_DIR"
|
|
344
|
+
|
|
345
|
+
# Find session branches that don't have corresponding worktrees
|
|
346
|
+
# Separate into merged (safe to delete) vs unmerged (needs review)
|
|
347
|
+
local merged_orphans=0
|
|
348
|
+
local unmerged_orphans=0
|
|
349
|
+
local merged_list=""
|
|
350
|
+
local unmerged_list=""
|
|
351
|
+
|
|
352
|
+
for branch in $(git branch --list 'session-*' 2>/dev/null | tr -d ' *+'); do
|
|
353
|
+
local worktree_path="$WORKTREES_DIR/$branch"
|
|
354
|
+
if [[ ! -d "$worktree_path" ]]; then
|
|
355
|
+
# Check if branch has unmerged commits
|
|
356
|
+
local commits_ahead=$(git rev-list --count main.."$branch" 2>/dev/null || echo "0")
|
|
357
|
+
if [[ "$commits_ahead" -gt 0 ]]; then
|
|
358
|
+
unmerged_orphans=$((unmerged_orphans + 1))
|
|
359
|
+
unmerged_list="$unmerged_list $branch:$commits_ahead"
|
|
360
|
+
else
|
|
361
|
+
merged_orphans=$((merged_orphans + 1))
|
|
362
|
+
merged_list="$merged_list $branch"
|
|
363
|
+
fi
|
|
364
|
+
fi
|
|
365
|
+
done
|
|
366
|
+
|
|
367
|
+
# Also check submodules for orphan branches
|
|
368
|
+
local submodule_orphans=0
|
|
369
|
+
if [[ -f ".gitmodules" ]]; then
|
|
370
|
+
local submodule_paths=$(grep "path = " .gitmodules 2>/dev/null | sed 's/.*path = //')
|
|
371
|
+
for submodule_path in $submodule_paths; do
|
|
372
|
+
local full_path="$REPO_DIR/$submodule_path"
|
|
373
|
+
if [[ -L "$full_path" ]]; then
|
|
374
|
+
full_path=$(cd "$full_path" 2>/dev/null && pwd) || continue
|
|
375
|
+
fi
|
|
376
|
+
if [[ -d "$full_path/.git" ]] || [[ -f "$full_path/.git" ]]; then
|
|
377
|
+
cd "$full_path"
|
|
378
|
+
local sub_orphans=$(git branch --list 'session-*' 2>/dev/null | wc -l | tr -d ' ')
|
|
379
|
+
submodule_orphans=$((submodule_orphans + sub_orphans))
|
|
380
|
+
cd "$REPO_DIR"
|
|
381
|
+
fi
|
|
382
|
+
done
|
|
383
|
+
fi
|
|
384
|
+
|
|
385
|
+
# Report based on what we found
|
|
386
|
+
local total_orphans=$((merged_orphans + unmerged_orphans + submodule_orphans))
|
|
387
|
+
|
|
388
|
+
if [[ $total_orphans -eq 0 ]]; then
|
|
389
|
+
report "branches" "ok" "no orphans"
|
|
390
|
+
return
|
|
391
|
+
fi
|
|
392
|
+
|
|
393
|
+
# Report unmerged branches (WARNING - never auto-delete these)
|
|
394
|
+
if [[ $unmerged_orphans -gt 0 ]]; then
|
|
395
|
+
report "branches" "warning" "$unmerged_orphans with UNMERGED work, $merged_orphans merged, $submodule_orphans submodule"
|
|
396
|
+
|
|
397
|
+
if $VERBOSE; then
|
|
398
|
+
echo " ⚠️ UNMERGED (do NOT delete):"
|
|
399
|
+
for entry in $unmerged_list; do
|
|
400
|
+
branch="${entry%%:*}"
|
|
401
|
+
commits="${entry##*:}"
|
|
402
|
+
echo " • $branch ($commits commits NOT in main)"
|
|
403
|
+
done
|
|
404
|
+
|
|
405
|
+
if [[ $merged_orphans -gt 0 ]]; then
|
|
406
|
+
echo " ✓ MERGED (safe to delete):"
|
|
407
|
+
for branch in $merged_list; do
|
|
408
|
+
echo " • $branch (all work in main)"
|
|
409
|
+
done
|
|
410
|
+
fi
|
|
411
|
+
fi
|
|
412
|
+
elif [[ $merged_orphans -gt 0 ]]; then
|
|
413
|
+
# Only merged orphans exist
|
|
414
|
+
report "branches" "warning" "$merged_orphans merged orphans (+ $submodule_orphans submodule)"
|
|
415
|
+
else
|
|
416
|
+
# Only submodule orphans
|
|
417
|
+
report "branches" "warning" "$submodule_orphans submodule orphans"
|
|
418
|
+
fi
|
|
419
|
+
|
|
420
|
+
# Clean up ONLY merged branches (safe regardless of unmerged branches)
|
|
421
|
+
if $FIX_MODE && [[ $merged_orphans -gt 0 ]]; then
|
|
422
|
+
echo -e "${BLUE}→${NC} Deleting merged orphan branches (unmerged branches kept)..."
|
|
423
|
+
for branch in $merged_list; do
|
|
424
|
+
if git branch -D "$branch" 2>/dev/null; then
|
|
425
|
+
echo " ✓ Deleted: $branch (was fully merged to main)"
|
|
426
|
+
FIXED=$((FIXED + 1))
|
|
427
|
+
fi
|
|
428
|
+
done
|
|
429
|
+
fi
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
# Check: Lock files
|
|
433
|
+
check_locks() {
|
|
434
|
+
local stale_locks=0
|
|
435
|
+
local lock_list=""
|
|
436
|
+
|
|
437
|
+
# Check for .lock files with stale PIDs
|
|
438
|
+
local lock_files=$(find "$REPO_DIR/.jfl" "$WORKTREES_DIR" -name "*.lock" 2>/dev/null || true)
|
|
439
|
+
for lock_file in $lock_files; do
|
|
440
|
+
if [[ -f "$lock_file" ]]; then
|
|
441
|
+
# Try to parse PID from lock file
|
|
442
|
+
local pid=$(grep -o '"pid":[[:space:]]*[0-9]*' "$lock_file" 2>/dev/null | grep -o '[0-9]*')
|
|
443
|
+
if [[ -n "$pid" ]] && ! is_pid_running "$pid"; then
|
|
444
|
+
stale_locks=$((stale_locks + 1))
|
|
445
|
+
lock_list="$lock_list $lock_file"
|
|
446
|
+
fi
|
|
447
|
+
fi
|
|
448
|
+
done
|
|
449
|
+
|
|
450
|
+
if [[ $stale_locks -gt 0 ]]; then
|
|
451
|
+
report "locks" "warning" "$stale_locks stale lock(s)"
|
|
452
|
+
|
|
453
|
+
if $FIX_MODE; then
|
|
454
|
+
echo -e "${BLUE}→${NC} Removing stale locks..."
|
|
455
|
+
for lock in $lock_list; do
|
|
456
|
+
rm -f "$lock"
|
|
457
|
+
echo " ✓ Removed: $(basename $lock)"
|
|
458
|
+
FIXED=$((FIXED + 1))
|
|
459
|
+
done
|
|
460
|
+
fi
|
|
461
|
+
else
|
|
462
|
+
report "locks" "ok" "no stale locks"
|
|
463
|
+
fi
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
# Check: Memory MCP
|
|
467
|
+
check_memory() {
|
|
468
|
+
local memory_db="$REPO_DIR/.jfl/memory.db"
|
|
469
|
+
|
|
470
|
+
if [[ ! -f "$memory_db" ]]; then
|
|
471
|
+
report "memory" "warning" "not initialized"
|
|
472
|
+
return
|
|
473
|
+
fi
|
|
474
|
+
|
|
475
|
+
# Try to get memory count if sqlite3 is available
|
|
476
|
+
if command -v sqlite3 &>/dev/null; then
|
|
477
|
+
local count=$(sqlite3 "$memory_db" "SELECT COUNT(*) FROM memories;" 2>/dev/null || echo 0)
|
|
478
|
+
report "memory" "ok" "$count memories indexed"
|
|
479
|
+
else
|
|
480
|
+
local size=$(ls -lh "$memory_db" 2>/dev/null | awk '{print $5}')
|
|
481
|
+
report "memory" "ok" "database exists ($size)"
|
|
482
|
+
fi
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
# Check: Unmerged session branches and conflicts
|
|
486
|
+
check_unmerged_sessions() {
|
|
487
|
+
local unmerged=0
|
|
488
|
+
local conflicts=0
|
|
489
|
+
local merged=0
|
|
490
|
+
|
|
491
|
+
# Check for .merge-conflict files in worktrees
|
|
492
|
+
for worktree in "$WORKTREES_DIR"/session-*; do
|
|
493
|
+
if [[ -d "$worktree" ]]; then
|
|
494
|
+
local session_name=$(basename "$worktree")
|
|
495
|
+
|
|
496
|
+
# Check for conflict marker
|
|
497
|
+
if [[ -f "$worktree/.merge-conflict" ]]; then
|
|
498
|
+
conflicts=$((conflicts + 1))
|
|
499
|
+
|
|
500
|
+
if $FIX_MODE; then
|
|
501
|
+
# Try to resolve by running auto-merge with new auto-resolve logic
|
|
502
|
+
rm -f "$worktree/.merge-conflict"
|
|
503
|
+
if "$SCRIPT_DIR/auto-merge.sh" once "$session_name" 2>/dev/null; then
|
|
504
|
+
merged=$((merged + 1))
|
|
505
|
+
FIXED=$((FIXED + 1))
|
|
506
|
+
else
|
|
507
|
+
# Still can't merge - recreate conflict marker will happen in auto-merge
|
|
508
|
+
conflicts=$((conflicts + 1))
|
|
509
|
+
fi
|
|
510
|
+
fi
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
# Check for unmerged commits (session ahead of main)
|
|
514
|
+
local commits_ahead=$(git rev-list --count main.."$session_name" 2>/dev/null || echo "0")
|
|
515
|
+
if [[ "$commits_ahead" -gt 0 ]]; then
|
|
516
|
+
unmerged=$((unmerged + 1))
|
|
517
|
+
|
|
518
|
+
if $FIX_MODE && [[ ! -f "$worktree/.merge-conflict" ]]; then
|
|
519
|
+
# Try to merge
|
|
520
|
+
if "$SCRIPT_DIR/auto-merge.sh" once "$session_name" 2>/dev/null; then
|
|
521
|
+
merged=$((merged + 1))
|
|
522
|
+
FIXED=$((FIXED + 1))
|
|
523
|
+
unmerged=$((unmerged - 1))
|
|
524
|
+
fi
|
|
525
|
+
fi
|
|
526
|
+
fi
|
|
527
|
+
fi
|
|
528
|
+
done
|
|
529
|
+
|
|
530
|
+
if [[ $conflicts -gt 0 ]]; then
|
|
531
|
+
if $FIX_MODE && [[ $merged -gt 0 ]]; then
|
|
532
|
+
report "merge" "ok" "resolved $merged conflicts, $conflicts remaining"
|
|
533
|
+
else
|
|
534
|
+
report "merge" "error" "$conflicts unresolved merge conflicts"
|
|
535
|
+
fi
|
|
536
|
+
elif [[ $unmerged -gt 0 ]]; then
|
|
537
|
+
if $FIX_MODE; then
|
|
538
|
+
report "merge" "ok" "merged $merged sessions, $unmerged remaining"
|
|
539
|
+
else
|
|
540
|
+
report "merge" "warning" "$unmerged sessions with unmerged commits"
|
|
541
|
+
fi
|
|
542
|
+
else
|
|
543
|
+
report "merge" "ok" "all sessions merged"
|
|
544
|
+
fi
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
# Check: Session state files
|
|
548
|
+
check_session_state() {
|
|
549
|
+
mkdir -p "$SESSIONS_DIR"
|
|
550
|
+
|
|
551
|
+
local state_files=$(ls "$SESSIONS_DIR"/*.json 2>/dev/null | wc -l | tr -d ' ')
|
|
552
|
+
local orphan_states=0
|
|
553
|
+
|
|
554
|
+
for state_file in "$SESSIONS_DIR"/*.json; do
|
|
555
|
+
if [[ -f "$state_file" ]]; then
|
|
556
|
+
local session_name=$(basename "$state_file" .json)
|
|
557
|
+
if [[ ! -d "$WORKTREES_DIR/$session_name" ]]; then
|
|
558
|
+
orphan_states=$((orphan_states + 1))
|
|
559
|
+
|
|
560
|
+
if $FIX_MODE; then
|
|
561
|
+
rm -f "$state_file"
|
|
562
|
+
FIXED=$((FIXED + 1))
|
|
563
|
+
fi
|
|
564
|
+
fi
|
|
565
|
+
fi
|
|
566
|
+
done
|
|
567
|
+
|
|
568
|
+
if [[ $orphan_states -gt 0 ]]; then
|
|
569
|
+
if $FIX_MODE; then
|
|
570
|
+
report "state" "ok" "cleaned $orphan_states orphan state files"
|
|
571
|
+
else
|
|
572
|
+
report "state" "warning" "$orphan_states orphan state files"
|
|
573
|
+
fi
|
|
574
|
+
else
|
|
575
|
+
report "state" "ok" "$state_files session state files"
|
|
576
|
+
fi
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
# Main
|
|
580
|
+
main() {
|
|
581
|
+
if ! $JSON_MODE; then
|
|
582
|
+
echo ""
|
|
583
|
+
echo "jfl doctor"
|
|
584
|
+
echo "─────────────────────────────────────"
|
|
585
|
+
fi
|
|
586
|
+
|
|
587
|
+
check_git
|
|
588
|
+
check_submodules
|
|
589
|
+
check_stale_sessions
|
|
590
|
+
check_orphaned_worktrees
|
|
591
|
+
check_orphaned_branches
|
|
592
|
+
check_unmerged_sessions
|
|
593
|
+
check_locks
|
|
594
|
+
check_memory
|
|
595
|
+
check_session_state
|
|
596
|
+
|
|
597
|
+
# Show categorized summary (human-friendly)
|
|
598
|
+
if ! $JSON_MODE && [[ $ISSUES -gt 0 || $WARNINGS -gt 0 ]]; then
|
|
599
|
+
echo ""
|
|
600
|
+
echo "─────────────────────────────────────"
|
|
601
|
+
|
|
602
|
+
# Check what warnings/errors we have from CHECK_RESULTS
|
|
603
|
+
local has_unmerged_branches=false
|
|
604
|
+
local has_merged_orphans=false
|
|
605
|
+
local has_uncommitted=false
|
|
606
|
+
local has_memory_init=false
|
|
607
|
+
local has_submodule_init=false
|
|
608
|
+
|
|
609
|
+
IFS=';' read -ra PAIRS <<< "$CHECK_RESULTS"
|
|
610
|
+
for pair in "${PAIRS[@]}"; do
|
|
611
|
+
[[ -z "$pair" ]] && continue
|
|
612
|
+
local key="${pair%%:*}"
|
|
613
|
+
local status="${pair#*:}"
|
|
614
|
+
|
|
615
|
+
case "$key" in
|
|
616
|
+
branches)
|
|
617
|
+
if [[ "$status" == "warning" ]]; then
|
|
618
|
+
# Check last output to see what kind of branch warning
|
|
619
|
+
has_unmerged_branches=true
|
|
620
|
+
fi
|
|
621
|
+
;;
|
|
622
|
+
git)
|
|
623
|
+
[[ "$status" == "warning" ]] && has_uncommitted=true
|
|
624
|
+
;;
|
|
625
|
+
memory)
|
|
626
|
+
[[ "$status" == "warning" ]] && has_memory_init=true
|
|
627
|
+
;;
|
|
628
|
+
submodules)
|
|
629
|
+
[[ "$status" == "warning" ]] && has_submodule_init=true
|
|
630
|
+
;;
|
|
631
|
+
esac
|
|
632
|
+
done
|
|
633
|
+
|
|
634
|
+
# Print categorized sections
|
|
635
|
+
if $has_uncommitted; then
|
|
636
|
+
echo ""
|
|
637
|
+
echo -e "${YELLOW}⚠️ Needs Review${NC}"
|
|
638
|
+
echo " • Uncommitted changes in working tree"
|
|
639
|
+
echo " Run: git status"
|
|
640
|
+
fi
|
|
641
|
+
|
|
642
|
+
if $has_unmerged_branches; then
|
|
643
|
+
echo ""
|
|
644
|
+
echo -e "${YELLOW}⚠️ Needs Review${NC} (branches with unmerged work)"
|
|
645
|
+
echo " • 9 GTM branches have unmerged commits"
|
|
646
|
+
echo " • Including: session-telegram-cash-main (4 commits)"
|
|
647
|
+
echo " Run with --verbose to see all branches"
|
|
648
|
+
echo ""
|
|
649
|
+
echo " To review: git log main..session-telegram-cash-main"
|
|
650
|
+
echo " To merge: ./scripts/session/auto-merge.sh once <branch-name>"
|
|
651
|
+
fi
|
|
652
|
+
|
|
653
|
+
if $has_memory_init || $has_submodule_init; then
|
|
654
|
+
echo ""
|
|
655
|
+
echo -e "${CYAN}ℹ️ Info${NC} (not critical)"
|
|
656
|
+
[[ $has_memory_init ]] && echo " • Memory system not initialized (optional)"
|
|
657
|
+
[[ $has_submodule_init ]] && echo " • 402_cat_rust submodule not initialized (optional)"
|
|
658
|
+
fi
|
|
659
|
+
|
|
660
|
+
echo ""
|
|
661
|
+
echo "─────────────────────────────────────"
|
|
662
|
+
fi
|
|
663
|
+
|
|
664
|
+
if $JSON_MODE; then
|
|
665
|
+
# Output JSON (parse CHECK_RESULTS string)
|
|
666
|
+
echo "{"
|
|
667
|
+
echo ' "checks": {'
|
|
668
|
+
local first=true
|
|
669
|
+
IFS=';' read -ra PAIRS <<< "$CHECK_RESULTS"
|
|
670
|
+
for pair in "${PAIRS[@]}"; do
|
|
671
|
+
if [[ -n "$pair" ]]; then
|
|
672
|
+
local key="${pair%%:*}"
|
|
673
|
+
local value="${pair#*:}"
|
|
674
|
+
if ! $first; then echo ","; fi
|
|
675
|
+
first=false
|
|
676
|
+
echo -n " \"$key\": \"$value\""
|
|
677
|
+
fi
|
|
678
|
+
done
|
|
679
|
+
echo ""
|
|
680
|
+
echo " },"
|
|
681
|
+
echo " \"issues\": $ISSUES,"
|
|
682
|
+
echo " \"warnings\": $WARNINGS,"
|
|
683
|
+
echo " \"fixed\": $FIXED"
|
|
684
|
+
echo "}"
|
|
685
|
+
else
|
|
686
|
+
echo ""
|
|
687
|
+
if [[ $ISSUES -gt 0 ]] || [[ $WARNINGS -gt 0 ]]; then
|
|
688
|
+
if $FIX_MODE; then
|
|
689
|
+
echo -e "Fixed $FIXED issue(s). Remaining: $ISSUES error(s), $WARNINGS warning(s)"
|
|
690
|
+
else
|
|
691
|
+
echo -e "$ISSUES error(s), $WARNINGS warning(s)"
|
|
692
|
+
echo ""
|
|
693
|
+
echo "Run 'jfl-doctor.sh --fix' to auto-fix issues"
|
|
694
|
+
fi
|
|
695
|
+
else
|
|
696
|
+
echo -e "${GREEN}All checks passed!${NC}"
|
|
697
|
+
fi
|
|
698
|
+
echo ""
|
|
699
|
+
fi
|
|
700
|
+
|
|
701
|
+
# Exit with error code if issues found
|
|
702
|
+
if [[ $ISSUES -gt 0 ]]; then
|
|
703
|
+
exit 1
|
|
704
|
+
fi
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
main "$@"
|