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,336 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Experience-Level Testing for Critical Infrastructure
|
|
4
|
+
#
|
|
5
|
+
# Tests ACTUAL USER WORKFLOWS, not just code paths.
|
|
6
|
+
# Simulates real scenarios that would cause work loss.
|
|
7
|
+
#
|
|
8
|
+
# @purpose Test critical infrastructure from user's perspective
|
|
9
|
+
|
|
10
|
+
set -e
|
|
11
|
+
|
|
12
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
13
|
+
REPO_DIR="$(git rev-parse --path-format=absolute --git-common-dir 2>/dev/null || echo ".")"
|
|
14
|
+
REPO_DIR="${REPO_DIR%/.git}"
|
|
15
|
+
|
|
16
|
+
# Colors
|
|
17
|
+
RED='\033[0;31m'
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[1;33m'
|
|
20
|
+
BLUE='\033[0;34m'
|
|
21
|
+
NC='\033[0m'
|
|
22
|
+
|
|
23
|
+
TESTS_PASSED=0
|
|
24
|
+
TESTS_FAILED=0
|
|
25
|
+
|
|
26
|
+
pass() {
|
|
27
|
+
echo -e "${GREEN}✓${NC} $1"
|
|
28
|
+
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
fail() {
|
|
32
|
+
echo -e "${RED}✗${NC} $1"
|
|
33
|
+
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
section() {
|
|
37
|
+
echo ""
|
|
38
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
39
|
+
echo -e "${BLUE}$1${NC}"
|
|
40
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# ==============================================================================
|
|
44
|
+
# Experience Test 1: Ctrl+C During Auto-Commit
|
|
45
|
+
# ==============================================================================
|
|
46
|
+
|
|
47
|
+
test_ctrl_c_experience() {
|
|
48
|
+
section "Experience Test 1: Ctrl+C During Auto-Commit"
|
|
49
|
+
|
|
50
|
+
echo "Scenario: User presses Ctrl+C while auto-commit is running"
|
|
51
|
+
echo "Expected: Final commit happens, no work lost"
|
|
52
|
+
echo ""
|
|
53
|
+
|
|
54
|
+
# Check that signal handling is in place
|
|
55
|
+
if grep -q "trap graceful_shutdown SIGINT SIGTERM" "$SCRIPT_DIR/auto-commit.sh"; then
|
|
56
|
+
pass "Signal trap will catch Ctrl+C"
|
|
57
|
+
else
|
|
58
|
+
fail "No signal trap - Ctrl+C will lose work"
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Check that graceful shutdown commits
|
|
62
|
+
if grep -A10 "graceful_shutdown()" "$SCRIPT_DIR/auto-commit.sh" | grep -q "do_commit"; then
|
|
63
|
+
pass "Graceful shutdown runs final commit"
|
|
64
|
+
else
|
|
65
|
+
fail "Graceful shutdown doesn't commit - work lost"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# Check that it also commits submodules
|
|
69
|
+
if grep -A10 "graceful_shutdown()" "$SCRIPT_DIR/auto-commit.sh" | grep -q "commit_submodules"; then
|
|
70
|
+
pass "Graceful shutdown commits submodules too"
|
|
71
|
+
else
|
|
72
|
+
fail "Submodule changes lost on Ctrl+C"
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
echo ""
|
|
76
|
+
echo "User Experience: Press Ctrl+C → See 'saving final changes' → Changes committed → Clean exit"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# ==============================================================================
|
|
80
|
+
# Experience Test 2: Crashed Session, Fresh Start
|
|
81
|
+
# ==============================================================================
|
|
82
|
+
|
|
83
|
+
test_crash_recovery_experience() {
|
|
84
|
+
section "Experience Test 2: Crashed Session Recovery"
|
|
85
|
+
|
|
86
|
+
echo "Scenario: Session crashed yesterday, user starts new session today"
|
|
87
|
+
echo "Expected: Prompted to save uncommitted work from crashed session"
|
|
88
|
+
echo ""
|
|
89
|
+
|
|
90
|
+
# Check that session-init scans for uncommitted work
|
|
91
|
+
if grep -q "Check for uncommitted work in stale sessions" "$SCRIPT_DIR/session-init.sh"; then
|
|
92
|
+
pass "Session start checks for abandoned work"
|
|
93
|
+
else
|
|
94
|
+
fail "No check for crashed session work - silently lost"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Check that user is prompted, not auto-committed silently
|
|
98
|
+
if grep -q "Options:" "$SCRIPT_DIR/session-init.sh" && grep -q "Choose \[1-3\]" "$SCRIPT_DIR/session-init.sh"; then
|
|
99
|
+
pass "User is prompted to review abandoned work"
|
|
100
|
+
else
|
|
101
|
+
fail "No user prompt - work handled without consent"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# Check that auto-commit is an option
|
|
105
|
+
if grep -q "Auto-commit all and continue" "$SCRIPT_DIR/session-init.sh"; then
|
|
106
|
+
pass "User can auto-commit with one choice"
|
|
107
|
+
else
|
|
108
|
+
fail "No quick auto-commit option"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
echo ""
|
|
112
|
+
echo "User Experience: Start session → See 'Found 2 sessions with uncommitted work' → Choose option → Work saved → Continue"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
# ==============================================================================
|
|
116
|
+
# Experience Test 3: Someone Else Pushed, I Start Session
|
|
117
|
+
# ==============================================================================
|
|
118
|
+
|
|
119
|
+
test_team_sync_experience() {
|
|
120
|
+
section "Experience Test 3: Team Member Pushed Changes"
|
|
121
|
+
|
|
122
|
+
echo "Scenario: Teammate pushed to main, I start a new session"
|
|
123
|
+
echo "Expected: My session starts with their latest changes"
|
|
124
|
+
echo ""
|
|
125
|
+
|
|
126
|
+
# Check that session-sync exists and is tracked
|
|
127
|
+
if git ls-files "$SCRIPT_DIR/session-sync.sh" >/dev/null 2>&1; then
|
|
128
|
+
pass "session-sync.sh is tracked in git (all worktrees get it)"
|
|
129
|
+
else
|
|
130
|
+
fail "session-sync.sh not tracked - worktrees won't have sync"
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# Check that it's called on session start
|
|
134
|
+
if grep -q "session-sync" "$SCRIPT_DIR/session-init.sh" 2>/dev/null || \
|
|
135
|
+
grep -q "session-sync" "$REPO_DIR/.claude/settings.json" 2>/dev/null; then
|
|
136
|
+
pass "Session start triggers sync"
|
|
137
|
+
else
|
|
138
|
+
fail "Sync not triggered on session start"
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Check that sync pulls main
|
|
142
|
+
if grep -q "git pull origin" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
|
|
143
|
+
pass "Sync pulls latest from origin"
|
|
144
|
+
else
|
|
145
|
+
fail "Sync doesn't pull - user starts with stale code"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
echo ""
|
|
149
|
+
echo "User Experience: Start session → Syncing repos → Up to date → See teammate's changes → Continue"
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
# ==============================================================================
|
|
153
|
+
# Experience Test 4: I Have Unmerged Work, Someone Runs Doctor
|
|
154
|
+
# ==============================================================================
|
|
155
|
+
|
|
156
|
+
test_unmerged_work_safety() {
|
|
157
|
+
section "Experience Test 4: Protecting Unmerged Work"
|
|
158
|
+
|
|
159
|
+
echo "Scenario: My branch has 4 commits, teammate runs 'doctor --fix'"
|
|
160
|
+
echo "Expected: My work is NOT deleted"
|
|
161
|
+
echo ""
|
|
162
|
+
|
|
163
|
+
# Check that doctor separates merged vs unmerged
|
|
164
|
+
if grep -q "⚠️ UNMERGED (do NOT delete)" "$SCRIPT_DIR/jfl-doctor.sh"; then
|
|
165
|
+
pass "Doctor clearly labels unmerged branches"
|
|
166
|
+
else
|
|
167
|
+
fail "Doctor doesn't distinguish merged vs unmerged"
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Check that --fix never deletes unmerged (check code, not output)
|
|
171
|
+
# The key is: only $merged_list is deleted, never $unmerged_list
|
|
172
|
+
if grep -A20 "if \[\[ \$unmerged_orphans -gt 0 \]\]" "$SCRIPT_DIR/jfl-doctor.sh" | \
|
|
173
|
+
grep -q "UNMERGED.*do NOT delete"; then
|
|
174
|
+
pass "--fix mode labels unmerged branches correctly"
|
|
175
|
+
else
|
|
176
|
+
fail "DANGER: --fix might delete unmerged work"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
# Check that only merged branches are deleted
|
|
180
|
+
if grep -B5 "git branch -D" "$SCRIPT_DIR/jfl-doctor.sh" | grep -q "merged_orphans -gt 0"; then
|
|
181
|
+
pass "Only deletes branches that are fully merged"
|
|
182
|
+
else
|
|
183
|
+
fail "Deletion logic might be unsafe"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
echo ""
|
|
187
|
+
echo "User Experience: Teammate runs doctor --fix → My unmerged branch preserved → I can continue work"
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
# ==============================================================================
|
|
191
|
+
# Experience Test 5: Network Fails During Sync
|
|
192
|
+
# ==============================================================================
|
|
193
|
+
|
|
194
|
+
test_network_failure_graceful() {
|
|
195
|
+
section "Experience Test 5: Network Failure Handling"
|
|
196
|
+
|
|
197
|
+
echo "Scenario: Network goes down during session sync"
|
|
198
|
+
echo "Expected: Graceful warning, session continues with local state"
|
|
199
|
+
echo ""
|
|
200
|
+
|
|
201
|
+
# Check for network error handling
|
|
202
|
+
if grep -q "Could not fetch.*no network" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
|
|
203
|
+
pass "Network failures handled gracefully"
|
|
204
|
+
else
|
|
205
|
+
fail "Network failure might crash session"
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
# Check that sync doesn't block on network failure
|
|
209
|
+
if grep -A5 "git fetch origin" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "|| {"; then
|
|
210
|
+
pass "Fetch failures don't block session"
|
|
211
|
+
else
|
|
212
|
+
fail "Session might hang on network failure"
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Check that user is warned but can continue
|
|
216
|
+
if grep -q "WARNING.*network" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
|
|
217
|
+
pass "User warned about network issues"
|
|
218
|
+
else
|
|
219
|
+
fail "Silent network failure - user confused"
|
|
220
|
+
fi
|
|
221
|
+
|
|
222
|
+
echo ""
|
|
223
|
+
echo "User Experience: Start session → 'WARNING: Could not fetch (no network?)' → Continue working offline"
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
# ==============================================================================
|
|
227
|
+
# Experience Test 6: Uncommitted Changes + Behind Origin
|
|
228
|
+
# ==============================================================================
|
|
229
|
+
|
|
230
|
+
test_uncommitted_and_behind() {
|
|
231
|
+
section "Experience Test 6: Uncommitted Changes + Behind Origin"
|
|
232
|
+
|
|
233
|
+
echo "Scenario: I have uncommitted work, main is behind origin"
|
|
234
|
+
echo "Expected: Sync refuses to pull, warns me, preserves my work"
|
|
235
|
+
echo ""
|
|
236
|
+
|
|
237
|
+
# Check for uncommitted + behind detection
|
|
238
|
+
if grep -q "has uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null; then
|
|
239
|
+
pass "Detects dangerous situation (uncommitted + behind)"
|
|
240
|
+
else
|
|
241
|
+
fail "Doesn't detect uncommitted + behind - might lose work"
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# Check that it exits with error
|
|
245
|
+
if grep -A5 "uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "exit 1\|FAILURES="; then
|
|
246
|
+
pass "Blocks sync to prevent data loss"
|
|
247
|
+
else
|
|
248
|
+
fail "Doesn't block sync - work could be lost"
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
# Check that it tells user what to do
|
|
252
|
+
if grep -A5 "uncommitted changes AND is behind" "$SCRIPT_DIR/session-sync.sh" 2>/dev/null | grep -q "commit or stash"; then
|
|
253
|
+
pass "Guides user to resolve safely"
|
|
254
|
+
else
|
|
255
|
+
fail "No guidance - user stuck"
|
|
256
|
+
fi
|
|
257
|
+
|
|
258
|
+
echo ""
|
|
259
|
+
echo "User Experience: Start session → 'ERROR: uncommitted changes AND behind' → Commit first → Retry → Success"
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# ==============================================================================
|
|
263
|
+
# CI/CD Integration Check
|
|
264
|
+
# ==============================================================================
|
|
265
|
+
|
|
266
|
+
test_ci_integration() {
|
|
267
|
+
section "CI/CD Integration"
|
|
268
|
+
|
|
269
|
+
echo "Checking if tests are integrated into CI/CD pipeline"
|
|
270
|
+
echo ""
|
|
271
|
+
|
|
272
|
+
# Check for GitHub Actions workflow
|
|
273
|
+
if [[ -f "$REPO_DIR/.github/workflows/test-critical-infrastructure.yml" ]]; then
|
|
274
|
+
pass "GitHub Actions workflow exists for tests"
|
|
275
|
+
else
|
|
276
|
+
echo -e "${YELLOW}⚠${NC} No GitHub Actions workflow (recommended)"
|
|
277
|
+
echo " Create .github/workflows/test-critical-infrastructure.yml"
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
# Check for pre-commit hook
|
|
281
|
+
if [[ -f "$REPO_DIR/.git/hooks/pre-commit" ]] || \
|
|
282
|
+
[[ -f "$REPO_DIR/.husky/pre-commit" ]]; then
|
|
283
|
+
pass "Pre-commit hook exists"
|
|
284
|
+
else
|
|
285
|
+
echo -e "${YELLOW}⚠${NC} No pre-commit hook (recommended)"
|
|
286
|
+
echo " Run tests before commit to catch issues early"
|
|
287
|
+
fi
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
# ==============================================================================
|
|
291
|
+
# Run All Experience Tests
|
|
292
|
+
# ==============================================================================
|
|
293
|
+
|
|
294
|
+
main() {
|
|
295
|
+
echo ""
|
|
296
|
+
echo "╔══════════════════════════════════════════════════════════╗"
|
|
297
|
+
echo "║ Experience-Level Testing ║"
|
|
298
|
+
echo "║ Testing Actual User Workflows ║"
|
|
299
|
+
echo "╚══════════════════════════════════════════════════════════╝"
|
|
300
|
+
|
|
301
|
+
test_ctrl_c_experience
|
|
302
|
+
test_crash_recovery_experience
|
|
303
|
+
test_team_sync_experience
|
|
304
|
+
test_unmerged_work_safety
|
|
305
|
+
test_network_failure_graceful
|
|
306
|
+
test_uncommitted_and_behind
|
|
307
|
+
test_ci_integration
|
|
308
|
+
|
|
309
|
+
# Summary
|
|
310
|
+
echo ""
|
|
311
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
312
|
+
echo -e "${BLUE}Test Results${NC}"
|
|
313
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
314
|
+
echo -e "${GREEN}Passed:${NC} $TESTS_PASSED"
|
|
315
|
+
if [[ $TESTS_FAILED -gt 0 ]]; then
|
|
316
|
+
echo -e "${RED}Failed:${NC} $TESTS_FAILED"
|
|
317
|
+
echo ""
|
|
318
|
+
echo -e "${RED}EXPERIENCE-LEVEL ISSUES FOUND${NC}"
|
|
319
|
+
echo "Fix these before releasing to users"
|
|
320
|
+
exit 1
|
|
321
|
+
else
|
|
322
|
+
echo ""
|
|
323
|
+
echo -e "${GREEN}✓ All user experience paths protected${NC}"
|
|
324
|
+
echo ""
|
|
325
|
+
echo "Verified workflows:"
|
|
326
|
+
echo " • Ctrl+C doesn't lose work"
|
|
327
|
+
echo " • Crashed sessions recovered"
|
|
328
|
+
echo " • Team changes synced automatically"
|
|
329
|
+
echo " • Unmerged work never deleted"
|
|
330
|
+
echo " • Network failures handled gracefully"
|
|
331
|
+
echo " • Uncommitted + behind detected safely"
|
|
332
|
+
exit 0
|
|
333
|
+
fi
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
main "$@"
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# Test Suite: Session Cleanup
|
|
4
|
+
#
|
|
5
|
+
# Tests session-cleanup.sh against critical safety requirements:
|
|
6
|
+
# - NEVER loses uncommitted work
|
|
7
|
+
# - NEVER loses conflicting changes
|
|
8
|
+
# - ONLY auto-merges safe commits (auto-saves, journal entries)
|
|
9
|
+
# - ALWAYS preserves journal entries
|
|
10
|
+
# - Properly removes worktrees after successful merge
|
|
11
|
+
# - Handles all exit scenarios (normal, Ctrl+C, crash, kill)
|
|
12
|
+
|
|
13
|
+
set -e
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
REPO_DIR="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
17
|
+
|
|
18
|
+
# Colors
|
|
19
|
+
RED='\033[0;31m'
|
|
20
|
+
GREEN='\033[0;32m'
|
|
21
|
+
YELLOW='\033[1;33m'
|
|
22
|
+
NC='\033[0m' # No Color
|
|
23
|
+
|
|
24
|
+
TESTS_RUN=0
|
|
25
|
+
TESTS_PASSED=0
|
|
26
|
+
TESTS_FAILED=0
|
|
27
|
+
|
|
28
|
+
print_test() {
|
|
29
|
+
echo ""
|
|
30
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
31
|
+
echo "TEST: $1"
|
|
32
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
pass() {
|
|
36
|
+
echo -e "${GREEN}✓ PASS${NC}: $1"
|
|
37
|
+
TESTS_PASSED=$((TESTS_PASSED + 1))
|
|
38
|
+
TESTS_RUN=$((TESTS_RUN + 1))
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fail() {
|
|
42
|
+
echo -e "${RED}✗ FAIL${NC}: $1"
|
|
43
|
+
TESTS_FAILED=$((TESTS_FAILED + 1))
|
|
44
|
+
TESTS_RUN=$((TESTS_RUN + 1))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
anti_test() {
|
|
48
|
+
echo -e "${YELLOW}⚠ ANTI-TEST${NC}: $1 (should NOT happen)"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
52
|
+
# Safety Tests - CRITICAL: Must never lose work
|
|
53
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
54
|
+
|
|
55
|
+
print_test "SAFETY: Cleanup script exists and is executable"
|
|
56
|
+
if [[ -f "$SCRIPT_DIR/session-cleanup.sh" ]]; then
|
|
57
|
+
pass "session-cleanup.sh exists"
|
|
58
|
+
else
|
|
59
|
+
fail "session-cleanup.sh not found"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if [[ -x "$SCRIPT_DIR/session-cleanup.sh" ]]; then
|
|
63
|
+
pass "session-cleanup.sh is executable"
|
|
64
|
+
else
|
|
65
|
+
fail "session-cleanup.sh not executable"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
print_test "SAFETY: Script has auto-commit before merge"
|
|
69
|
+
if grep -q "git add -A" "$SCRIPT_DIR/session-cleanup.sh" && \
|
|
70
|
+
grep -q "git commit" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
71
|
+
pass "Auto-commits before attempting merge"
|
|
72
|
+
else
|
|
73
|
+
fail "Missing auto-commit before merge - WILL LOSE WORK"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
print_test "SAFETY: Script checks if on session branch"
|
|
77
|
+
if grep -q 'if.*session-' "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
78
|
+
pass "Checks for session branch before cleanup"
|
|
79
|
+
else
|
|
80
|
+
fail "Doesn't check branch type - might cleanup non-session branches"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
print_test "SAFETY: Script aborts merge on conflicts"
|
|
84
|
+
if grep -q "git merge --abort" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
85
|
+
pass "Aborts merge on conflicts (preserves work)"
|
|
86
|
+
else
|
|
87
|
+
fail "Doesn't abort on conflicts - WILL LOSE CONFLICTING CHANGES"
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
print_test "SAFETY: Script uses auto-resolve strategy for .jfl/ conflicts"
|
|
91
|
+
if grep -q -- "-X ours" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
92
|
+
pass "Uses -X ours for auto-resolving .jfl/ conflicts"
|
|
93
|
+
else
|
|
94
|
+
fail "Missing conflict resolution strategy - merges will fail unnecessarily"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
print_test "ANTI-TEST: Script doesn't use --force flags"
|
|
98
|
+
anti_test "git push --force"
|
|
99
|
+
if grep -q "push.*--force" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
100
|
+
fail "Uses --force push - DANGEROUS"
|
|
101
|
+
else
|
|
102
|
+
pass "No --force push (safe)"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
anti_test "git clean -f"
|
|
106
|
+
if grep -q "git clean" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
107
|
+
fail "Uses git clean - WILL LOSE UNTRACKED FILES"
|
|
108
|
+
else
|
|
109
|
+
pass "No git clean (safe)"
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
anti_test "git reset --hard"
|
|
113
|
+
if grep -q "reset.*--hard" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
114
|
+
fail "Uses reset --hard - WILL LOSE UNCOMMITTED WORK"
|
|
115
|
+
else
|
|
116
|
+
pass "No reset --hard (safe)"
|
|
117
|
+
fi
|
|
118
|
+
|
|
119
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
120
|
+
# Integration Tests - Works with existing infrastructure
|
|
121
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
122
|
+
|
|
123
|
+
print_test "INTEGRATION: Stop hook calls session-cleanup.sh"
|
|
124
|
+
SETTINGS_FILE="$REPO_DIR/.claude/settings.json"
|
|
125
|
+
if [[ -f "$SETTINGS_FILE" ]]; then
|
|
126
|
+
if grep -q "session-cleanup.sh" "$SETTINGS_FILE"; then
|
|
127
|
+
pass "Stop hook configured to run cleanup"
|
|
128
|
+
else
|
|
129
|
+
fail "Stop hook doesn't call session-cleanup.sh"
|
|
130
|
+
fi
|
|
131
|
+
else
|
|
132
|
+
fail ".claude/settings.json not found"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
print_test "INTEGRATION: Signal handler calls session-cleanup.sh"
|
|
136
|
+
AUTO_COMMIT_SCRIPT="$SCRIPT_DIR/auto-commit.sh"
|
|
137
|
+
if [[ -f "$AUTO_COMMIT_SCRIPT" ]]; then
|
|
138
|
+
if grep -A 10 "graceful_shutdown" "$AUTO_COMMIT_SCRIPT" | grep -q "session-cleanup.sh"; then
|
|
139
|
+
pass "Signal handler calls cleanup on Ctrl+C/kill"
|
|
140
|
+
else
|
|
141
|
+
fail "Signal handler doesn't call session-cleanup.sh - branches pile up on Ctrl+C"
|
|
142
|
+
fi
|
|
143
|
+
else
|
|
144
|
+
fail "auto-commit.sh not found"
|
|
145
|
+
fi
|
|
146
|
+
|
|
147
|
+
print_test "INTEGRATION: Signal traps are set"
|
|
148
|
+
if grep -q "trap.*graceful_shutdown.*SIGINT.*SIGTERM" "$AUTO_COMMIT_SCRIPT"; then
|
|
149
|
+
pass "Signal traps set for SIGINT and SIGTERM"
|
|
150
|
+
else
|
|
151
|
+
fail "Missing signal traps - Ctrl+C won't trigger cleanup"
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
155
|
+
# Functional Tests - Script behavior
|
|
156
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
157
|
+
|
|
158
|
+
print_test "FUNCTIONAL: Script skips cleanup on non-session branches"
|
|
159
|
+
CLEANUP_OUTPUT=$("$SCRIPT_DIR/session-cleanup.sh" 2>&1 || true)
|
|
160
|
+
CURRENT_BRANCH=$(git branch --show-current)
|
|
161
|
+
|
|
162
|
+
if [[ ! "$CURRENT_BRANCH" =~ ^session- ]]; then
|
|
163
|
+
if echo "$CLEANUP_OUTPUT" | grep -q "Not a session branch"; then
|
|
164
|
+
pass "Skips cleanup on non-session branch (main)"
|
|
165
|
+
else
|
|
166
|
+
fail "Doesn't skip non-session branches - might cleanup main!"
|
|
167
|
+
fi
|
|
168
|
+
else
|
|
169
|
+
pass "Currently on session branch, skipping non-session test"
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
print_test "FUNCTIONAL: Script switches to main before merge"
|
|
173
|
+
if grep -q "git checkout main" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
174
|
+
pass "Switches to main before merging"
|
|
175
|
+
else
|
|
176
|
+
fail "Doesn't checkout main - merge will fail"
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
print_test "FUNCTIONAL: Script removes worktree after successful merge"
|
|
180
|
+
if grep -q "git worktree.*remove" "$SCRIPT_DIR/session-cleanup.sh" || \
|
|
181
|
+
grep -q "rm -rf.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
182
|
+
pass "Removes worktree after merge"
|
|
183
|
+
else
|
|
184
|
+
fail "Doesn't remove worktree - will pile up disk usage"
|
|
185
|
+
fi
|
|
186
|
+
|
|
187
|
+
print_test "FUNCTIONAL: Script deletes branch after successful merge"
|
|
188
|
+
if grep -q "git branch -D" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
189
|
+
pass "Deletes branch after successful merge"
|
|
190
|
+
else
|
|
191
|
+
fail "Doesn't delete branch - will pile up branches"
|
|
192
|
+
fi
|
|
193
|
+
|
|
194
|
+
print_test "FUNCTIONAL: Script handles missing worktree gracefully"
|
|
195
|
+
if grep -q "\[ -n.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh" || \
|
|
196
|
+
grep -q "\[ -d.*WORKTREE" "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
197
|
+
pass "Checks if worktree exists before removing"
|
|
198
|
+
else
|
|
199
|
+
fail "Doesn't check worktree existence - might error on missing worktree"
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
203
|
+
# Edge Cases
|
|
204
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
205
|
+
|
|
206
|
+
print_test "EDGE CASE: Script handles 'not on a branch' scenario"
|
|
207
|
+
if grep -q 'if \[ -z.*BRANCH' "$SCRIPT_DIR/session-cleanup.sh"; then
|
|
208
|
+
pass "Checks if on a branch (handles detached HEAD)"
|
|
209
|
+
else
|
|
210
|
+
fail "Doesn't check for detached HEAD - will fail in that state"
|
|
211
|
+
fi
|
|
212
|
+
|
|
213
|
+
print_test "EDGE CASE: Script exits cleanly on all paths"
|
|
214
|
+
if tail -5 "$SCRIPT_DIR/session-cleanup.sh" | grep -q "exit 0"; then
|
|
215
|
+
pass "Script exits cleanly (exit 0)"
|
|
216
|
+
else
|
|
217
|
+
fail "Script might exit with error code - will break hooks"
|
|
218
|
+
fi
|
|
219
|
+
|
|
220
|
+
print_test "EDGE CASE: Script doesn't fail entire hook chain"
|
|
221
|
+
# Check that cleanup is called with || true in hooks
|
|
222
|
+
if grep -q "session-cleanup.sh.*||" "$SETTINGS_FILE" 2>/dev/null; then
|
|
223
|
+
pass "Cleanup failure doesn't break hook chain"
|
|
224
|
+
else
|
|
225
|
+
fail "Cleanup failure could break Stop hook - session won't end"
|
|
226
|
+
fi
|
|
227
|
+
|
|
228
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
229
|
+
# Performance Tests
|
|
230
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
231
|
+
|
|
232
|
+
print_test "PERFORMANCE: Cleanup redirects to log file"
|
|
233
|
+
if grep -q "session-cleanup.sh.*>>" "$SETTINGS_FILE" 2>/dev/null; then
|
|
234
|
+
pass "Cleanup output goes to log file (doesn't spam user)"
|
|
235
|
+
else
|
|
236
|
+
fail "Cleanup output not redirected - will spam terminal"
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
print_test "PERFORMANCE: Cleanup runs in background/async"
|
|
240
|
+
if grep -q "session-cleanup.sh.*2>&1" "$SETTINGS_FILE" 2>/dev/null; then
|
|
241
|
+
pass "Cleanup stderr redirected (clean output)"
|
|
242
|
+
else
|
|
243
|
+
fail "Cleanup stderr not redirected - errors spam terminal"
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
247
|
+
# Summary
|
|
248
|
+
# ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
249
|
+
|
|
250
|
+
echo ""
|
|
251
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
252
|
+
echo "TEST SUMMARY"
|
|
253
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
254
|
+
echo "Total tests: $TESTS_RUN"
|
|
255
|
+
echo -e "${GREEN}Passed:${NC} $TESTS_PASSED"
|
|
256
|
+
echo -e "${RED}Failed:${NC} $TESTS_FAILED"
|
|
257
|
+
|
|
258
|
+
if [ $TESTS_FAILED -eq 0 ]; then
|
|
259
|
+
echo ""
|
|
260
|
+
echo -e "${GREEN}✓ All tests passed!${NC}"
|
|
261
|
+
echo "Session cleanup is safe and ready for production."
|
|
262
|
+
exit 0
|
|
263
|
+
else
|
|
264
|
+
echo ""
|
|
265
|
+
echo -e "${RED}✗ $TESTS_FAILED test(s) failed!${NC}"
|
|
266
|
+
echo "Fix failing tests before deploying to ensure work is never lost."
|
|
267
|
+
exit 1
|
|
268
|
+
fi
|