agileflow 3.2.1 → 3.4.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/CHANGELOG.md +10 -0
- package/README.md +6 -6
- package/lib/feature-flags.js +32 -4
- package/lib/skill-loader.js +0 -1
- package/package.json +1 -1
- package/scripts/agileflow-statusline.sh +81 -0
- package/scripts/babysit-clear-restore.js +154 -0
- package/scripts/claude-tmux.sh +120 -24
- package/scripts/claude-watchdog.sh +225 -0
- package/scripts/generators/agent-registry.js +14 -1
- package/scripts/generators/inject-babysit.js +22 -9
- package/scripts/generators/inject-help.js +19 -9
- package/scripts/lib/README-portable-tasks.md +424 -0
- package/scripts/lib/audit-cleanup.js +250 -0
- package/scripts/lib/audit-registry.js +248 -0
- package/scripts/lib/configure-detect.js +20 -0
- package/scripts/lib/feature-catalog.js +13 -2
- package/scripts/lib/gate-enforcer.js +295 -0
- package/scripts/lib/model-profiles.js +98 -0
- package/scripts/lib/signal-detectors.js +1 -1
- package/scripts/lib/skill-catalog.js +557 -0
- package/scripts/lib/skill-recommender.js +311 -0
- package/scripts/lib/tdd-phase-manager.js +455 -0
- package/scripts/lib/team-events.js +76 -8
- package/scripts/lib/tmux-group-colors.js +113 -0
- package/scripts/messaging-bridge.js +209 -1
- package/scripts/spawn-audit-sessions.js +549 -0
- package/scripts/team-manager.js +37 -16
- package/scripts/tmux-close-windows.sh +180 -0
- package/scripts/tmux-restore-window.sh +67 -0
- package/scripts/tmux-save-closed-window.sh +35 -0
- package/src/core/agents/ads-audit-budget.md +181 -0
- package/src/core/agents/ads-audit-compliance.md +169 -0
- package/src/core/agents/ads-audit-creative.md +164 -0
- package/src/core/agents/ads-audit-google.md +226 -0
- package/src/core/agents/ads-audit-meta.md +183 -0
- package/src/core/agents/ads-audit-tracking.md +197 -0
- package/src/core/agents/ads-consensus.md +322 -0
- package/src/core/agents/brainstorm-analyzer-features.md +169 -0
- package/src/core/agents/brainstorm-analyzer-growth.md +161 -0
- package/src/core/agents/brainstorm-analyzer-integration.md +172 -0
- package/src/core/agents/brainstorm-analyzer-market.md +147 -0
- package/src/core/agents/brainstorm-analyzer-ux.md +167 -0
- package/src/core/agents/brainstorm-consensus.md +237 -0
- package/src/core/agents/completeness-analyzer-api.md +190 -0
- package/src/core/agents/completeness-analyzer-conditional.md +201 -0
- package/src/core/agents/completeness-analyzer-handlers.md +159 -0
- package/src/core/agents/completeness-analyzer-imports.md +159 -0
- package/src/core/agents/completeness-analyzer-routes.md +182 -0
- package/src/core/agents/completeness-analyzer-state.md +188 -0
- package/src/core/agents/completeness-analyzer-stubs.md +198 -0
- package/src/core/agents/completeness-consensus.md +286 -0
- package/src/core/agents/perf-consensus.md +2 -2
- package/src/core/agents/security-consensus.md +2 -2
- package/src/core/agents/seo-analyzer-content.md +167 -0
- package/src/core/agents/seo-analyzer-images.md +187 -0
- package/src/core/agents/seo-analyzer-performance.md +206 -0
- package/src/core/agents/seo-analyzer-schema.md +176 -0
- package/src/core/agents/seo-analyzer-sitemap.md +172 -0
- package/src/core/agents/seo-analyzer-technical.md +144 -0
- package/src/core/agents/seo-consensus.md +289 -0
- package/src/core/agents/test-consensus.md +2 -2
- package/src/core/commands/ads/audit.md +375 -0
- package/src/core/commands/ads/budget.md +97 -0
- package/src/core/commands/ads/competitor.md +112 -0
- package/src/core/commands/ads/creative.md +85 -0
- package/src/core/commands/ads/google.md +112 -0
- package/src/core/commands/ads/landing.md +119 -0
- package/src/core/commands/ads/linkedin.md +112 -0
- package/src/core/commands/ads/meta.md +91 -0
- package/src/core/commands/ads/microsoft.md +115 -0
- package/src/core/commands/ads/plan.md +321 -0
- package/src/core/commands/ads/tiktok.md +129 -0
- package/src/core/commands/ads/youtube.md +124 -0
- package/src/core/commands/ads.md +128 -0
- package/src/core/commands/babysit.md +250 -1344
- package/src/core/commands/code/completeness.md +466 -0
- package/src/core/commands/{audit → code}/legal.md +26 -16
- package/src/core/commands/{audit → code}/logic.md +27 -16
- package/src/core/commands/{audit → code}/performance.md +30 -20
- package/src/core/commands/{audit → code}/security.md +32 -19
- package/src/core/commands/{audit → code}/test.md +30 -20
- package/src/core/commands/{discovery → ideate}/brief.md +12 -12
- package/src/core/commands/{discovery/new.md → ideate/discover.md} +13 -13
- package/src/core/commands/ideate/features.md +435 -0
- package/src/core/commands/seo/audit.md +373 -0
- package/src/core/commands/seo/competitor.md +174 -0
- package/src/core/commands/seo/content.md +107 -0
- package/src/core/commands/seo/geo.md +229 -0
- package/src/core/commands/seo/hreflang.md +140 -0
- package/src/core/commands/seo/images.md +96 -0
- package/src/core/commands/seo/page.md +198 -0
- package/src/core/commands/seo/plan.md +163 -0
- package/src/core/commands/seo/programmatic.md +131 -0
- package/src/core/commands/seo/references/cwv-thresholds.md +64 -0
- package/src/core/commands/seo/references/eeat-framework.md +110 -0
- package/src/core/commands/seo/references/quality-gates.md +91 -0
- package/src/core/commands/seo/references/schema-types.md +102 -0
- package/src/core/commands/seo/schema.md +183 -0
- package/src/core/commands/seo/sitemap.md +97 -0
- package/src/core/commands/seo/technical.md +100 -0
- package/src/core/commands/seo.md +107 -0
- package/src/core/commands/skill/list.md +68 -212
- package/src/core/commands/skill/recommend.md +216 -0
- package/src/core/commands/tdd-next.md +238 -0
- package/src/core/commands/tdd.md +210 -0
- package/src/core/experts/_core-expertise.yaml +105 -0
- package/src/core/experts/analytics/expertise.yaml +5 -99
- package/src/core/experts/codebase-query/expertise.yaml +3 -72
- package/src/core/experts/compliance/expertise.yaml +6 -72
- package/src/core/experts/database/expertise.yaml +9 -52
- package/src/core/experts/documentation/expertise.yaml +7 -140
- package/src/core/experts/integrations/expertise.yaml +7 -127
- package/src/core/experts/mentor/expertise.yaml +8 -35
- package/src/core/experts/monitoring/expertise.yaml +7 -49
- package/src/core/experts/performance/expertise.yaml +1 -26
- package/src/core/experts/security/expertise.yaml +9 -34
- package/src/core/experts/ui/expertise.yaml +6 -36
- package/src/core/knowledge/ads/ad-audit-checklist-scoring.md +424 -0
- package/src/core/knowledge/ads/ad-optimization-logic.md +590 -0
- package/src/core/knowledge/ads/ad-technical-specifications.md +385 -0
- package/src/core/knowledge/ads/definitive-advertising-reference-2026.md +506 -0
- package/src/core/knowledge/ads/paid-advertising-research-2026.md +445 -0
- package/src/core/templates/agileflow-metadata.json +15 -1
- package/tools/cli/installers/ide/_base-ide.js +42 -5
- package/tools/cli/installers/ide/claude-code.js +13 -4
- package/tools/cli/lib/content-injector.js +160 -12
- package/tools/cli/lib/docs-setup.js +1 -1
- package/src/core/commands/skill/create.md +0 -698
- package/src/core/commands/skill/delete.md +0 -316
- package/src/core/commands/skill/edit.md +0 -359
- package/src/core/commands/skill/test.md +0 -394
- package/src/core/commands/skill/upgrade.md +0 -552
- package/src/core/templates/skill-template.md +0 -117
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.4.0] - 2026-02-28
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Ads audit system, SEO analysis, ultradeep concurrency controls, and domain-first command naming
|
|
14
|
+
|
|
15
|
+
## [3.3.0] - 2026-02-24
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Per-agent file tracking, tmux restore, and completeness audit
|
|
19
|
+
|
|
10
20
|
## [3.2.1] - 2026-02-21
|
|
11
21
|
|
|
12
22
|
### Added
|
package/README.md
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/agileflow)
|
|
6
|
-
[](https://docs.agileflow.projectquestorg.com/docs/commands)
|
|
7
|
+
[](https://docs.agileflow.projectquestorg.com/docs/agents)
|
|
8
8
|
[](https://docs.agileflow.projectquestorg.com/docs/features/skills)
|
|
9
9
|
|
|
10
10
|
**AI-driven agile development for Claude Code, Cursor, Windsurf, OpenAI Codex, and more.** Combining Scrum, Kanban, ADRs, and docs-as-code principles into one framework-agnostic system.
|
|
@@ -54,9 +54,9 @@ Traditional project management tools create friction between planning and execut
|
|
|
54
54
|
|
|
55
55
|
| Component | Count | Description |
|
|
56
56
|
|-----------|-------|-------------|
|
|
57
|
-
| [Commands](https://docs.agileflow.projectquestorg.com/docs/commands) |
|
|
58
|
-
| [Agents/Experts](https://docs.agileflow.projectquestorg.com/docs/agents) |
|
|
59
|
-
| [Skills](https://docs.agileflow.projectquestorg.com/docs/features/skills) | Dynamic |
|
|
57
|
+
| [Commands](https://docs.agileflow.projectquestorg.com/docs/commands) | 124 | Slash commands for agile workflows |
|
|
58
|
+
| [Agents/Experts](https://docs.agileflow.projectquestorg.com/docs/agents) | 111 | Specialized agents with self-improving knowledge bases |
|
|
59
|
+
| [Skills](https://docs.agileflow.projectquestorg.com/docs/features/skills) | Dynamic | Browse and install from skills.sh marketplace via `/agileflow:skill:recommend` |
|
|
60
60
|
|
|
61
61
|
---
|
|
62
62
|
|
|
@@ -66,7 +66,7 @@ Traditional project management tools create friction between planning and execut
|
|
|
66
66
|
|---------|-------------|------|
|
|
67
67
|
| Agent Expertise | Self-improving agents that maintain domain knowledge | [Learn more](https://docs.agileflow.projectquestorg.com/docs/features/agent-expertise-system) |
|
|
68
68
|
| Agent Teams | Multi-domain expert coordination with quality gates | [Learn more](https://docs.agileflow.projectquestorg.com/docs/features/agent-teams) |
|
|
69
|
-
| Skills System |
|
|
69
|
+
| Skills System | Browse and install skills from the skills.sh marketplace | [Learn more](https://docs.agileflow.projectquestorg.com/docs/features/skills) |
|
|
70
70
|
| Parallel Sessions | Isolated workspaces with boundary protection | [Learn more](https://docs.agileflow.projectquestorg.com/docs/features/parallel-sessions) |
|
|
71
71
|
| Loop Mode | Autonomous story execution until epic completion | [Learn more](https://docs.agileflow.projectquestorg.com/docs/features/loop-mode) |
|
|
72
72
|
| AI Council | Three-perspective strategic decision analysis | [Learn more](https://docs.agileflow.projectquestorg.com/docs/commands/council) |
|
package/lib/feature-flags.js
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Tools expected to be available when Agent Teams native mode is enabled.
|
|
16
|
+
* Used for feature detection and capability reporting.
|
|
17
|
+
*/
|
|
18
|
+
const AGENT_TEAMS_TOOLS = Object.freeze(['TeamCreate', 'SendMessage', 'ListTeams']);
|
|
19
|
+
|
|
14
20
|
// Lazy-load paths to avoid circular dependency issues
|
|
15
21
|
let _paths;
|
|
16
22
|
function getPaths() {
|
|
@@ -67,6 +73,24 @@ function getAgentTeamsMode(options = {}) {
|
|
|
67
73
|
return 'native';
|
|
68
74
|
}
|
|
69
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Get the list of Agent Teams tools available in the current environment.
|
|
78
|
+
*
|
|
79
|
+
* When Agent Teams is enabled (native mode), returns the expected tool names.
|
|
80
|
+
* When disabled, returns an empty array.
|
|
81
|
+
*
|
|
82
|
+
* @param {object} [options] - Options
|
|
83
|
+
* @param {string} [options.rootDir] - Project root directory
|
|
84
|
+
* @param {object} [options.metadata] - Pre-loaded metadata
|
|
85
|
+
* @returns {string[]} Array of available tool names
|
|
86
|
+
*/
|
|
87
|
+
function getAvailableTools(options = {}) {
|
|
88
|
+
if (!isAgentTeamsEnabled(options)) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
return [...AGENT_TEAMS_TOOLS];
|
|
92
|
+
}
|
|
93
|
+
|
|
70
94
|
/**
|
|
71
95
|
* Get all feature flags as an object.
|
|
72
96
|
*
|
|
@@ -77,10 +101,12 @@ function getAgentTeamsMode(options = {}) {
|
|
|
77
101
|
*/
|
|
78
102
|
function getFeatureFlags(options = {}) {
|
|
79
103
|
const metadata = options.metadata || loadMetadataSafe(options.rootDir);
|
|
104
|
+
const opts = { ...options, metadata };
|
|
80
105
|
|
|
81
106
|
return {
|
|
82
|
-
agentTeams: isAgentTeamsEnabled(
|
|
83
|
-
agentTeamsMode: getAgentTeamsMode(
|
|
107
|
+
agentTeams: isAgentTeamsEnabled(opts),
|
|
108
|
+
agentTeamsMode: getAgentTeamsMode(opts),
|
|
109
|
+
availableTools: getAvailableTools(opts),
|
|
84
110
|
};
|
|
85
111
|
}
|
|
86
112
|
|
|
@@ -93,12 +119,12 @@ function getFeatureFlags(options = {}) {
|
|
|
93
119
|
*/
|
|
94
120
|
function getAgentTeamsDisplayInfo(options = {}) {
|
|
95
121
|
const enabled = isAgentTeamsEnabled(options);
|
|
96
|
-
const mode = getAgentTeamsMode(options);
|
|
97
122
|
|
|
98
123
|
if (enabled) {
|
|
124
|
+
const tools = getAvailableTools(options);
|
|
99
125
|
return {
|
|
100
126
|
label: 'Agent Teams',
|
|
101
|
-
value:
|
|
127
|
+
value: `ENABLED (native, ${tools.length} tools)`,
|
|
102
128
|
status: 'enabled',
|
|
103
129
|
};
|
|
104
130
|
}
|
|
@@ -136,8 +162,10 @@ function loadMetadataSafe(rootDir) {
|
|
|
136
162
|
}
|
|
137
163
|
|
|
138
164
|
module.exports = {
|
|
165
|
+
AGENT_TEAMS_TOOLS,
|
|
139
166
|
isAgentTeamsEnabled,
|
|
140
167
|
getAgentTeamsMode,
|
|
168
|
+
getAvailableTools,
|
|
141
169
|
getFeatureFlags,
|
|
142
170
|
getAgentTeamsDisplayInfo,
|
|
143
171
|
};
|
package/lib/skill-loader.js
CHANGED
|
@@ -126,7 +126,6 @@ function loadSkill(skillDir) {
|
|
|
126
126
|
path: skillDir,
|
|
127
127
|
hasReferences: fs.existsSync(path.join(skillDir, 'references.md')),
|
|
128
128
|
hasCookbook: fs.existsSync(path.join(skillDir, 'cookbook')),
|
|
129
|
-
hasMcp: fs.existsSync(path.join(skillDir, '.mcp.json')),
|
|
130
129
|
metadata,
|
|
131
130
|
};
|
|
132
131
|
} catch {
|
package/package.json
CHANGED
|
@@ -88,6 +88,7 @@ SHOW_SESSION_TIME=false
|
|
|
88
88
|
SHOW_COST=false
|
|
89
89
|
SHOW_GIT=true
|
|
90
90
|
SHOW_SCALE=true
|
|
91
|
+
SHOW_ULTRADEEP=true
|
|
91
92
|
|
|
92
93
|
# Check agileflow-metadata.json for component settings
|
|
93
94
|
if [ -f "docs/00-meta/agileflow-metadata.json" ]; then
|
|
@@ -106,6 +107,7 @@ if [ -f "docs/00-meta/agileflow-metadata.json" ]; then
|
|
|
106
107
|
SHOW_COST=$(echo "$COMPONENTS" | jq -r '.cost | if . == null then true else . end')
|
|
107
108
|
SHOW_GIT=$(echo "$COMPONENTS" | jq -r '.git | if . == null then true else . end')
|
|
108
109
|
SHOW_SCALE=$(echo "$COMPONENTS" | jq -r '.scale | if . == null then true else . end')
|
|
110
|
+
SHOW_ULTRADEEP=$(echo "$COMPONENTS" | jq -r '.ultradeep | if . == null then true else . end')
|
|
109
111
|
fi
|
|
110
112
|
fi
|
|
111
113
|
|
|
@@ -669,6 +671,79 @@ if [ "$SHOW_SCALE" = "true" ] && [ -f "docs/09-agents/session-state.json" ]; the
|
|
|
669
671
|
fi
|
|
670
672
|
fi
|
|
671
673
|
|
|
674
|
+
# ============================================================================
|
|
675
|
+
# Ultradeep Audit Progress Detection
|
|
676
|
+
# ============================================================================
|
|
677
|
+
ULTRADEEP_DISPLAY=""
|
|
678
|
+
if [ "$SHOW_ULTRADEEP" = "true" ]; then
|
|
679
|
+
ULTRADEEP_DIR="docs/09-agents/ultradeep"
|
|
680
|
+
if [ -d "$ULTRADEEP_DIR" ]; then
|
|
681
|
+
# Find most recent trace directory by modification time
|
|
682
|
+
LATEST_TRACE=$(ls -td "$ULTRADEEP_DIR"/*/ 2>/dev/null | head -1)
|
|
683
|
+
if [ -n "$LATEST_TRACE" ]; then
|
|
684
|
+
ULTRA_STATUS_FILE="${LATEST_TRACE}_status.json"
|
|
685
|
+
if [ -f "$ULTRA_STATUS_FILE" ]; then
|
|
686
|
+
ULTRA_STATUS=$(cat "$ULTRA_STATUS_FILE" 2>/dev/null)
|
|
687
|
+
ULTRA_AUDIT_TYPE=$(echo "$ULTRA_STATUS" | jq -r '.audit_type // empty' 2>/dev/null)
|
|
688
|
+
ULTRA_TOTAL=$(echo "$ULTRA_STATUS" | jq -r '.analyzers | length' 2>/dev/null)
|
|
689
|
+
ULTRA_COMPLETED=$(echo "$ULTRA_STATUS" | jq -r '.completed | length' 2>/dev/null)
|
|
690
|
+
ULTRA_STARTED=$(echo "$ULTRA_STATUS" | jq -r '.started_at // empty' 2>/dev/null)
|
|
691
|
+
ULTRA_LAST_CHECKED=$(echo "$ULTRA_STATUS" | jq -r '.last_checked // empty' 2>/dev/null)
|
|
692
|
+
|
|
693
|
+
# Validate we got numeric values
|
|
694
|
+
[[ "$ULTRA_TOTAL" =~ ^[0-9]+$ ]] || ULTRA_TOTAL=0
|
|
695
|
+
[[ "$ULTRA_COMPLETED" =~ ^[0-9]+$ ]] || ULTRA_COMPLETED=0
|
|
696
|
+
|
|
697
|
+
if [ "$ULTRA_TOTAL" -gt 0 ] && [ -n "$ULTRA_AUDIT_TYPE" ]; then
|
|
698
|
+
# Staleness check: skip if started >60 min ago and no recent activity
|
|
699
|
+
ULTRA_STALE=false
|
|
700
|
+
if [ -n "$ULTRA_STARTED" ]; then
|
|
701
|
+
ULTRA_START_EPOCH=$(to_epoch "$ULTRA_STARTED" 2>/dev/null)
|
|
702
|
+
ULTRA_NOW=$(date +%s)
|
|
703
|
+
if [ -n "$ULTRA_START_EPOCH" ] && [ $((ULTRA_NOW - ULTRA_START_EPOCH)) -gt 3600 ]; then
|
|
704
|
+
# Started over 60 min ago - check last_checked
|
|
705
|
+
if [ -n "$ULTRA_LAST_CHECKED" ] && [ "$ULTRA_LAST_CHECKED" != "null" ]; then
|
|
706
|
+
ULTRA_LC_EPOCH=$(to_epoch "$ULTRA_LAST_CHECKED" 2>/dev/null)
|
|
707
|
+
if [ -n "$ULTRA_LC_EPOCH" ] && [ $((ULTRA_NOW - ULTRA_LC_EPOCH)) -gt 120 ]; then
|
|
708
|
+
ULTRA_STALE=true
|
|
709
|
+
fi
|
|
710
|
+
else
|
|
711
|
+
# No last_checked at all and started >60 min ago
|
|
712
|
+
ULTRA_STALE=true
|
|
713
|
+
fi
|
|
714
|
+
fi
|
|
715
|
+
fi
|
|
716
|
+
|
|
717
|
+
if [ "$ULTRA_STALE" = "false" ]; then
|
|
718
|
+
# Map audit type to color and prefix
|
|
719
|
+
case "$ULTRA_AUDIT_TYPE" in
|
|
720
|
+
logic) ULTRA_COLOR="\033[38;2;122;162;247m"; ULTRA_PREFIX="Logic" ;;
|
|
721
|
+
security) ULTRA_COLOR="\033[38;2;247;118;142m"; ULTRA_PREFIX="Sec" ;;
|
|
722
|
+
performance) ULTRA_COLOR="\033[38;2;115;218;202m"; ULTRA_PREFIX="Perf" ;;
|
|
723
|
+
test) ULTRA_COLOR="\033[38;2;224;175;104m"; ULTRA_PREFIX="Test" ;;
|
|
724
|
+
completeness) ULTRA_COLOR="\033[38;2;187;154;247m"; ULTRA_PREFIX="Comp" ;;
|
|
725
|
+
legal) ULTRA_COLOR="\033[38;2;158;206;106m"; ULTRA_PREFIX="Legal" ;;
|
|
726
|
+
*) ULTRA_COLOR="$DIM"; ULTRA_PREFIX="Audit" ;;
|
|
727
|
+
esac
|
|
728
|
+
|
|
729
|
+
# Build display with progress coloring
|
|
730
|
+
if [ "$ULTRA_COMPLETED" -eq "$ULTRA_TOTAL" ]; then
|
|
731
|
+
# All complete - green checkmark
|
|
732
|
+
ULTRADEEP_DISPLAY="${ULTRA_COLOR}${ULTRA_PREFIX}${RESET} ${GREEN}${ULTRA_COMPLETED}/${ULTRA_TOTAL}✓${RESET}"
|
|
733
|
+
elif [ "$ULTRA_COMPLETED" -gt 0 ]; then
|
|
734
|
+
# In progress
|
|
735
|
+
ULTRADEEP_DISPLAY="${ULTRA_COLOR}${ULTRA_PREFIX}${RESET} ${ULTRA_COLOR}${ULTRA_COMPLETED}/${ULTRA_TOTAL}${RESET}"
|
|
736
|
+
else
|
|
737
|
+
# Just started (0 complete) - dim the fraction
|
|
738
|
+
ULTRADEEP_DISPLAY="${ULTRA_COLOR}${ULTRA_PREFIX}${RESET} ${DIM}${ULTRA_COMPLETED}/${ULTRA_TOTAL}${RESET}"
|
|
739
|
+
fi
|
|
740
|
+
fi
|
|
741
|
+
fi
|
|
742
|
+
fi
|
|
743
|
+
fi
|
|
744
|
+
fi
|
|
745
|
+
fi
|
|
746
|
+
|
|
672
747
|
# ============================================================================
|
|
673
748
|
# Build Status Line
|
|
674
749
|
# ============================================================================
|
|
@@ -759,6 +834,12 @@ if [ "$SHOW_SCALE" = "true" ] && [ -n "$SCALE_DISPLAY" ]; then
|
|
|
759
834
|
OUTPUT="${OUTPUT}${SCALE_DISPLAY}"
|
|
760
835
|
fi
|
|
761
836
|
|
|
837
|
+
# Add ultradeep audit progress (if enabled and active)
|
|
838
|
+
if [ "$SHOW_ULTRADEEP" = "true" ] && [ -n "$ULTRADEEP_DISPLAY" ]; then
|
|
839
|
+
[ -n "$OUTPUT" ] && OUTPUT="${OUTPUT}${SEP}"
|
|
840
|
+
OUTPUT="${OUTPUT}${ULTRADEEP_DISPLAY}"
|
|
841
|
+
fi
|
|
842
|
+
|
|
762
843
|
# Session health indicator (next to git branch)
|
|
763
844
|
if [ "$SHOW_SESSION" = "true" ]; then
|
|
764
845
|
SCRIPTS_DIR="$(dirname "$0")"
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* babysit-clear-restore.js - SessionStart hook for babysit context preservation
|
|
4
|
+
*
|
|
5
|
+
* When context is cleared (e.g., after plan approval), this hook:
|
|
6
|
+
* 1. Detects source="clear" from Claude Code's SessionStart event
|
|
7
|
+
* 2. Checks if /babysit is active in session-state.json
|
|
8
|
+
* 3. If both, outputs the COMPACT_SUMMARY from the babysit command file
|
|
9
|
+
* 4. Sets last_precompact_at so the welcome script preserves active_commands
|
|
10
|
+
*
|
|
11
|
+
* This eliminates the need to manually embed babysit rules in plan files (Rule #6).
|
|
12
|
+
* The hook automatically injects the rules into the fresh context after clear.
|
|
13
|
+
*
|
|
14
|
+
* Exit codes:
|
|
15
|
+
* 0 = Success (always - SessionStart hooks should never block)
|
|
16
|
+
*
|
|
17
|
+
* Input: JSON on stdin with { source: "startup"|"resume"|"clear"|"compact", ... }
|
|
18
|
+
* Output: Babysit compact summary to stdout (appears as system-reminder)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const fs = require('fs');
|
|
22
|
+
const path = require('path');
|
|
23
|
+
|
|
24
|
+
const STDIN_TIMEOUT_MS = 3000;
|
|
25
|
+
|
|
26
|
+
function findProjectRoot() {
|
|
27
|
+
let dir = process.cwd();
|
|
28
|
+
while (dir !== '/') {
|
|
29
|
+
if (fs.existsSync(path.join(dir, '.agileflow'))) return dir;
|
|
30
|
+
if (fs.existsSync(path.join(dir, 'docs', '09-agents'))) return dir;
|
|
31
|
+
dir = path.dirname(dir);
|
|
32
|
+
}
|
|
33
|
+
return process.cwd();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ROOT = findProjectRoot();
|
|
37
|
+
|
|
38
|
+
function getSessionState() {
|
|
39
|
+
const statePath = path.join(ROOT, 'docs', '09-agents', 'session-state.json');
|
|
40
|
+
try {
|
|
41
|
+
if (fs.existsSync(statePath)) {
|
|
42
|
+
return JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
// Silently fail
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function isBabysitActive(state) {
|
|
51
|
+
if (!state) return false;
|
|
52
|
+
const activeCommands = state.active_commands || [];
|
|
53
|
+
return activeCommands.some(cmd => cmd.name === 'babysit');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function setPrecompactTimestamp(state) {
|
|
57
|
+
const statePath = path.join(ROOT, 'docs', '09-agents', 'session-state.json');
|
|
58
|
+
try {
|
|
59
|
+
state.last_precompact_at = new Date().toISOString();
|
|
60
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2) + '\n');
|
|
61
|
+
} catch (e) {
|
|
62
|
+
// Silently fail
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getBabysitCompactSummary() {
|
|
67
|
+
// Search for the babysit command file in known locations
|
|
68
|
+
const locations = [
|
|
69
|
+
path.join(ROOT, 'packages', 'cli', 'src', 'core', 'commands', 'babysit.md'),
|
|
70
|
+
path.join(ROOT, '.agileflow', 'commands', 'babysit.md'),
|
|
71
|
+
path.join(ROOT, '.claude', 'commands', 'agileflow', 'babysit.md'),
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
for (const filePath of locations) {
|
|
75
|
+
try {
|
|
76
|
+
if (!fs.existsSync(filePath)) continue;
|
|
77
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
78
|
+
const match = content.match(
|
|
79
|
+
/<!-- COMPACT_SUMMARY_START[\s\S]*?-->([\s\S]*?)<!-- COMPACT_SUMMARY_END -->/
|
|
80
|
+
);
|
|
81
|
+
if (match) {
|
|
82
|
+
return match[1].trim();
|
|
83
|
+
}
|
|
84
|
+
} catch (e) {
|
|
85
|
+
// Try next location
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Read stdin for hook event data
|
|
92
|
+
let inputData = '';
|
|
93
|
+
|
|
94
|
+
process.stdin.setEncoding('utf8');
|
|
95
|
+
|
|
96
|
+
process.stdin.on('data', chunk => {
|
|
97
|
+
inputData += chunk;
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
process.stdin.on('end', () => {
|
|
101
|
+
try {
|
|
102
|
+
const input = JSON.parse(inputData);
|
|
103
|
+
const source = input.source;
|
|
104
|
+
|
|
105
|
+
// Only act on "clear" events (context cleared after plan approval, /clear, etc.)
|
|
106
|
+
if (source !== 'clear') {
|
|
107
|
+
process.exit(0);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const state = getSessionState();
|
|
112
|
+
if (!isBabysitActive(state)) {
|
|
113
|
+
process.exit(0);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Set last_precompact_at so the welcome script preserves active_commands
|
|
118
|
+
// instead of clearing them (it checks this timestamp)
|
|
119
|
+
setPrecompactTimestamp(state);
|
|
120
|
+
|
|
121
|
+
// Output the babysit compact summary
|
|
122
|
+
const summary = getBabysitCompactSummary();
|
|
123
|
+
if (summary) {
|
|
124
|
+
console.log('## ACTIVE COMMAND: /agileflow:babysit (restored after context clear)');
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(summary);
|
|
127
|
+
} else {
|
|
128
|
+
// Fallback: output minimal babysit rules if command file not found
|
|
129
|
+
console.log('## /agileflow:babysit IS ACTIVE (restored after context clear)');
|
|
130
|
+
console.log('');
|
|
131
|
+
console.log('MANDATORY RULES:');
|
|
132
|
+
console.log('1. ALWAYS end responses with AskUserQuestion tool (specific options, not text)');
|
|
133
|
+
console.log('2. Use EnterPlanMode for non-trivial tasks');
|
|
134
|
+
console.log('3. Delegate complex work to domain experts via Task tool');
|
|
135
|
+
console.log('4. Track progress with TaskCreate/TaskUpdate for multi-step work');
|
|
136
|
+
console.log(
|
|
137
|
+
'5. ALWAYS suggest logic audit post-implementation (after tests pass, make Recommended)'
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
} catch (e) {
|
|
141
|
+
// Parse failed or other error - fail open
|
|
142
|
+
}
|
|
143
|
+
process.exit(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Handle no stdin (direct invocation or timeout)
|
|
147
|
+
process.stdin.on('error', () => {
|
|
148
|
+
process.exit(0);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Timeout safety - don't hang
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
process.exit(0);
|
|
154
|
+
}, STDIN_TIMEOUT_MS);
|
package/scripts/claude-tmux.sh
CHANGED
|
@@ -112,6 +112,8 @@ WINDOWS:
|
|
|
112
112
|
Alt+n/p Next/previous window
|
|
113
113
|
Alt+r Rename window
|
|
114
114
|
Alt+w Close window
|
|
115
|
+
Alt+W Batch close windows (picker)
|
|
116
|
+
Alt+t Reopen closed window
|
|
115
117
|
|
|
116
118
|
PANES:
|
|
117
119
|
Alt+d Split side by side
|
|
@@ -120,9 +122,14 @@ PANES:
|
|
|
120
122
|
Alt+z Zoom/unzoom pane
|
|
121
123
|
Alt+x Close pane
|
|
122
124
|
|
|
125
|
+
FREEZE RECOVERY:
|
|
126
|
+
Alt+k Send Ctrl+C twice (soft unfreeze)
|
|
127
|
+
Alt+K Force kill Claude process (keeps tab)
|
|
128
|
+
Alt+R Respawn pane (fresh shell)
|
|
129
|
+
|
|
123
130
|
OTHER:
|
|
124
|
-
Alt+
|
|
125
|
-
Alt+
|
|
131
|
+
Alt+b Scroll mode (browse history)
|
|
132
|
+
Alt+h Show keybind help panel
|
|
126
133
|
EOF
|
|
127
134
|
exit 0
|
|
128
135
|
fi
|
|
@@ -185,19 +192,24 @@ build_tab_format() {
|
|
|
185
192
|
# ── Inactive tab: gray text ─────────────────────────────────────────────
|
|
186
193
|
# " I:" prefix = 4 visible chars (wide); " I:" = 3 chars (narrow)
|
|
187
194
|
# Width = prefix + pN(name) + 1(space)
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
local
|
|
193
|
-
local
|
|
194
|
-
local
|
|
195
|
-
local
|
|
196
|
-
local
|
|
197
|
-
local
|
|
198
|
-
local
|
|
199
|
-
local
|
|
200
|
-
local
|
|
195
|
+
#
|
|
196
|
+
# Group color support: when @group_color is set on a window (e.g. by
|
|
197
|
+
# spawn-audit-sessions.js), show a colored dot prefix to visually
|
|
198
|
+
# identify grouped windows (ULTRADEEP audit tabs in main session).
|
|
199
|
+
local gc='#{?#{@group_color},#[fg=#{@group_color}]•,}'
|
|
200
|
+
local i0="${gc}"'#[fg=#8a8a8a] #I:#{p35:#{=35:window_name}} '
|
|
201
|
+
local i1="${gc}"'#[fg=#8a8a8a] #I:#{p22:#{=22:window_name}} '
|
|
202
|
+
local i2="${gc}"'#[fg=#8a8a8a] #I:#{p15:#{=15:window_name}} '
|
|
203
|
+
local i3="${gc}"'#[fg=#8a8a8a] #I:#{p12:#{=12:window_name}} '
|
|
204
|
+
local i4="${gc}"'#[fg=#8a8a8a] #I:#{p9:#{=9:window_name}} '
|
|
205
|
+
local i5="${gc}"'#[fg=#8a8a8a] #I:#{p7:#{=7:window_name}} '
|
|
206
|
+
local i6="${gc}"'#[fg=#8a8a8a] #I:#{p6:#{=6:window_name}} '
|
|
207
|
+
local i7="${gc}"'#[fg=#8a8a8a] #I:#{p5:#{=5:window_name}} '
|
|
208
|
+
local i8="${gc}"'#[fg=#8a8a8a] #I:#{p4:#{=4:window_name}} '
|
|
209
|
+
local i9="${gc}"'#[fg=#8a8a8a] #I:#{p3:#{=3:window_name}} '
|
|
210
|
+
local i10="${gc}"'#[fg=#8a8a8a] #I:#{p2:#{=2:window_name}} '
|
|
211
|
+
local i11="${gc}"'#[fg=#8a8a8a] #I:#{p1:#{=1:window_name}} '
|
|
212
|
+
local i12="${gc}"'#[fg=#8a8a8a] #I '
|
|
201
213
|
local i13='#[fg=#565a6e]#I'
|
|
202
214
|
|
|
203
215
|
# ── Tier selection: budget = width / windows ─────────────────────────────
|
|
@@ -240,6 +252,14 @@ configure_tmux_session() {
|
|
|
240
252
|
# Enable mouse support
|
|
241
253
|
tmux set-option -t "$target_session" mouse on
|
|
242
254
|
|
|
255
|
+
# Reduce escape-time from default 500ms to 10ms.
|
|
256
|
+
# The default causes two problems:
|
|
257
|
+
# 1) Arrow keys (which send \e[A etc.) get misinterpreted as Alt+[ if
|
|
258
|
+
# there's any delivery delay, accidentally triggering copy-mode.
|
|
259
|
+
# 2) Pressing Escape in Claude Code has a 500ms lag before tmux forwards it.
|
|
260
|
+
# 10ms is enough to detect genuine escape sequences on localhost/fast SSH.
|
|
261
|
+
tmux set-option -t "$target_session" escape-time 10
|
|
262
|
+
|
|
243
263
|
# Automatically renumber windows when one is closed (no gaps)
|
|
244
264
|
tmux set-option -t "$target_session" renumber-windows on
|
|
245
265
|
|
|
@@ -308,8 +328,14 @@ configure_tmux_session() {
|
|
|
308
328
|
# Alt+x to close current pane (with confirmation)
|
|
309
329
|
tmux bind-key -n M-x confirm-before -p "Close pane? (y/n)" kill-pane
|
|
310
330
|
|
|
311
|
-
# Alt+w to close current window (
|
|
312
|
-
tmux bind-key -n M-w confirm-before -p "Close window? (y/n)" kill-window
|
|
331
|
+
# Alt+w to close current window (save state for Alt+T restore, then kill)
|
|
332
|
+
tmux bind-key -n M-w confirm-before -p "Close window? (y/n)" "run-shell '\"\$AGILEFLOW_SCRIPTS/tmux-save-closed-window.sh\"' ; kill-window"
|
|
333
|
+
|
|
334
|
+
# Alt+W (uppercase) to batch-close windows via multi-select picker
|
|
335
|
+
tmux bind-key -n M-W display-popup -E -w 60 -h 20 "\"$AGILEFLOW_SCRIPTS/tmux-close-windows.sh\""
|
|
336
|
+
|
|
337
|
+
# Alt+t to restore the most recently closed window (like Ctrl+Shift+T in browsers)
|
|
338
|
+
tmux bind-key -n M-t run-shell '"$AGILEFLOW_SCRIPTS/tmux-restore-window.sh"'
|
|
313
339
|
|
|
314
340
|
# Alt+n/p for next/previous window
|
|
315
341
|
tmux bind-key -n M-n next-window
|
|
@@ -321,8 +347,39 @@ configure_tmux_session() {
|
|
|
321
347
|
# Alt+z to zoom/unzoom pane (fullscreen toggle)
|
|
322
348
|
tmux bind-key -n M-z resize-pane -Z
|
|
323
349
|
|
|
324
|
-
# Alt+
|
|
325
|
-
|
|
350
|
+
# Alt+b to enter copy mode (for scrolling / browsing history)
|
|
351
|
+
# NOTE: Do NOT use Alt+[ here — \e[ is the CSI prefix for arrow keys and
|
|
352
|
+
# function keys. Binding M-[ in the root table causes accidental copy-mode
|
|
353
|
+
# entry whenever an escape sequence is split by network latency, making the
|
|
354
|
+
# terminal appear to "lose focus" until Escape is pressed.
|
|
355
|
+
tmux bind-key -n M-b copy-mode
|
|
356
|
+
|
|
357
|
+
# Disable ALL command-prompt bindings in copy mode — they open a text input
|
|
358
|
+
# in the status bar which intercepts keystrokes and confuses the workflow.
|
|
359
|
+
# Navigation (arrows, scroll, mouse, PgUp/PgDn) and exit (q/Escape) still work.
|
|
360
|
+
#
|
|
361
|
+
# Emacs copy-mode: goto-line, search, jump-to-char, repeat-count
|
|
362
|
+
tmux unbind-key -T copy-mode g
|
|
363
|
+
tmux unbind-key -T copy-mode C-r
|
|
364
|
+
tmux unbind-key -T copy-mode C-s
|
|
365
|
+
tmux unbind-key -T copy-mode f
|
|
366
|
+
tmux unbind-key -T copy-mode F
|
|
367
|
+
tmux unbind-key -T copy-mode t
|
|
368
|
+
tmux unbind-key -T copy-mode T
|
|
369
|
+
for i in 1 2 3 4 5 6 7 8 9; do
|
|
370
|
+
tmux unbind-key -T copy-mode "M-$i"
|
|
371
|
+
done
|
|
372
|
+
# Vi copy-mode: goto-line, search, jump-to-char, repeat-count
|
|
373
|
+
tmux unbind-key -T copy-mode-vi :
|
|
374
|
+
tmux unbind-key -T copy-mode-vi /
|
|
375
|
+
tmux unbind-key -T copy-mode-vi ?
|
|
376
|
+
tmux unbind-key -T copy-mode-vi f
|
|
377
|
+
tmux unbind-key -T copy-mode-vi F
|
|
378
|
+
tmux unbind-key -T copy-mode-vi t
|
|
379
|
+
tmux unbind-key -T copy-mode-vi T
|
|
380
|
+
for i in 1 2 3 4 5 6 7 8 9; do
|
|
381
|
+
tmux unbind-key -T copy-mode-vi "$i"
|
|
382
|
+
done
|
|
326
383
|
|
|
327
384
|
# ─── Session Creation Keybindings ──────────────────────────────────────────
|
|
328
385
|
# Alt+s to create a new Claude window (starts fresh, future re-runs in same pane resume)
|
|
@@ -331,11 +388,31 @@ configure_tmux_session() {
|
|
|
331
388
|
|
|
332
389
|
# ─── Freeze Recovery Keybindings ───────────────────────────────────────────
|
|
333
390
|
# Alt+k to send Ctrl+C twice (soft interrupt for frozen processes)
|
|
334
|
-
|
|
391
|
+
# Uses #{pane_id} to target the correct pane even if focus shifts during the sleep
|
|
392
|
+
tmux bind-key -n M-k run-shell "tmux send-keys -t '#{pane_id}' C-c; sleep 0.5; tmux send-keys -t '#{pane_id}' C-c"
|
|
393
|
+
|
|
394
|
+
# Alt+K (uppercase) to force kill Claude process in pane without closing tab
|
|
395
|
+
# Finds the claude child process under the pane's shell and kills it,
|
|
396
|
+
# leaving the shell prompt intact so the user can restart or continue.
|
|
397
|
+
# Uses ps -o pid=,args= with grep to find claude, then cuts the PID (avoids awk quoting issues in tmux run-shell).
|
|
398
|
+
tmux bind-key -n M-K run-shell '\
|
|
399
|
+
PANE_PID=$(tmux display-message -p "#{pane_pid}"); \
|
|
400
|
+
CLAUDE_PID=$(ps --ppid "$PANE_PID" -o pid=,args= 2>/dev/null | grep -v "watchdog" | grep "claude" | head -1 | sed "s/^[[:space:]]*//" | cut -d" " -f1); \
|
|
401
|
+
if [ -n "$CLAUDE_PID" ]; then \
|
|
402
|
+
kill -TERM "$CLAUDE_PID" 2>/dev/null; \
|
|
403
|
+
sleep 2; \
|
|
404
|
+
kill -0 "$CLAUDE_PID" 2>/dev/null && kill -KILL "$CLAUDE_PID" 2>/dev/null; \
|
|
405
|
+
tmux display-message "Killed Claude process (PID $CLAUDE_PID)"; \
|
|
406
|
+
else \
|
|
407
|
+
tmux display-message "No Claude process found in this pane"; \
|
|
408
|
+
fi'
|
|
409
|
+
|
|
410
|
+
# Alt+R to respawn pane (kills everything in the pane, starts fresh shell)
|
|
411
|
+
tmux bind-key -n M-R respawn-pane -k
|
|
335
412
|
|
|
336
413
|
# ─── Help Panel ──────────────────────────────────────────────────────────
|
|
337
414
|
# Alt+h to show all Alt keybindings in a popup
|
|
338
|
-
tmux bind-key -n M-h display-popup -E -w 52 -h
|
|
415
|
+
tmux bind-key -n M-h display-popup -E -w 52 -h 32 "\
|
|
339
416
|
printf '\\n';\
|
|
340
417
|
printf ' \\033[1;38;5;208mSESSIONS\\033[0m\\n';\
|
|
341
418
|
printf ' Alt+s New Claude session\\n';\
|
|
@@ -348,6 +425,8 @@ configure_tmux_session() {
|
|
|
348
425
|
printf ' Alt+n/p Next / previous window\\n';\
|
|
349
426
|
printf ' Alt+r Rename window\\n';\
|
|
350
427
|
printf ' Alt+w Close window\\n';\
|
|
428
|
+
printf ' Alt+W Batch close windows\\n';\
|
|
429
|
+
printf ' Alt+t Reopen closed window\\n';\
|
|
351
430
|
printf '\\n';\
|
|
352
431
|
printf ' \\033[1;38;5;208mPANES\\033[0m\\n';\
|
|
353
432
|
printf ' Alt+d Split side by side\\n';\
|
|
@@ -355,11 +434,11 @@ configure_tmux_session() {
|
|
|
355
434
|
printf ' Alt+arrows Navigate panes\\n';\
|
|
356
435
|
printf ' Alt+z Zoom / unzoom\\n';\
|
|
357
436
|
printf ' Alt+x Close pane (confirm)\\n';\
|
|
358
|
-
printf ' Alt+K
|
|
359
|
-
printf ' Alt+R
|
|
437
|
+
printf ' Alt+K Force kill process\\n';\
|
|
438
|
+
printf ' Alt+R Respawn pane (fresh)\\n';\
|
|
360
439
|
printf '\\n';\
|
|
361
440
|
printf ' \\033[1;38;5;208mOTHER\\033[0m\\n';\
|
|
362
|
-
printf ' Alt+
|
|
441
|
+
printf ' Alt+b Scroll mode\\n';\
|
|
363
442
|
printf ' Alt+k Unfreeze (Ctrl+C x2)\\n';\
|
|
364
443
|
printf ' Alt+h This help\\n';\
|
|
365
444
|
printf '\\n';\
|
|
@@ -373,6 +452,14 @@ if [ "$REFRESH_CONFIG" = true ]; then
|
|
|
373
452
|
configure_tmux_session "$sid"
|
|
374
453
|
# Ensure AGILEFLOW_SCRIPTS is set (needed by Alt+S keybind)
|
|
375
454
|
tmux set-environment -t "$sid" AGILEFLOW_SCRIPTS "$SCRIPT_DIR" 2>/dev/null || true
|
|
455
|
+
# (Re)start watchdog if not running for this session
|
|
456
|
+
_EXISTING_WD=$(tmux show-environment -t "$sid" WATCHDOG_PID 2>/dev/null | cut -d= -f2)
|
|
457
|
+
if [ -z "$_EXISTING_WD" ] || ! kill -0 "$_EXISTING_WD" 2>/dev/null; then
|
|
458
|
+
"$SCRIPT_DIR/claude-watchdog.sh" "$sid" &
|
|
459
|
+
_WD_PID=$!
|
|
460
|
+
tmux set-environment -t "$sid" WATCHDOG_PID "$_WD_PID"
|
|
461
|
+
disown "$_WD_PID"
|
|
462
|
+
fi
|
|
376
463
|
REFRESHED=$((REFRESHED + 1))
|
|
377
464
|
done
|
|
378
465
|
if [ "$REFRESHED" -gt 0 ]; then
|
|
@@ -645,6 +732,15 @@ if [ -n "$CLAUDE_SESSION_FLAGS" ]; then
|
|
|
645
732
|
tmux set-environment -t "$SESSION_NAME" CLAUDE_SESSION_FLAGS "$CLAUDE_SESSION_FLAGS"
|
|
646
733
|
fi
|
|
647
734
|
|
|
735
|
+
# Start watchdog to auto-detect and kill frozen Claude processes
|
|
736
|
+
EXISTING_WD=$(tmux show-environment -t "$SESSION_NAME" WATCHDOG_PID 2>/dev/null | cut -d= -f2)
|
|
737
|
+
if [ -z "$EXISTING_WD" ] || ! kill -0 "$EXISTING_WD" 2>/dev/null; then
|
|
738
|
+
"$SCRIPT_DIR/claude-watchdog.sh" "$SESSION_NAME" &
|
|
739
|
+
_WD_PID=$!
|
|
740
|
+
tmux set-environment -t "$SESSION_NAME" WATCHDOG_PID "$_WD_PID"
|
|
741
|
+
disown "$_WD_PID"
|
|
742
|
+
fi
|
|
743
|
+
|
|
648
744
|
# Pre-seed @claude_uuid on initial pane if we found a recent conversation
|
|
649
745
|
if [ "$USE_RESUME" = true ] && [ -n "$RESUME_SESSION_ID" ]; then
|
|
650
746
|
tmux set-option -p -t "$SESSION_NAME" @claude_uuid "$RESUME_SESSION_ID" 2>/dev/null || true
|