clawforge-cli 1.5.4__tar.gz → 1.5.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/CHANGELOG.md +14 -0
  2. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/Formula/clawforge.rb +2 -1
  3. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/PKG-INFO +1 -1
  4. clawforge_cli-1.5.5/VERSION +1 -0
  5. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/spawn-agent.sh +6 -2
  6. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/package.json +1 -1
  7. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/pyproject.toml +1 -1
  8. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-dx.sh +3 -3
  9. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-observability.sh +1 -1
  10. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-power.sh +1 -1
  11. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-practical.sh +1 -1
  12. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-reliability.sh +1 -1
  13. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-web.sh +1 -1
  14. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/agent.go +3 -0
  15. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/dashboard.go +8 -4
  16. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/keybindings.go +83 -11
  17. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/model.go +2 -1
  18. clawforge_cli-1.5.4/VERSION +0 -1
  19. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.github/workflows/ci.yml +0 -0
  20. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.github/workflows/publish-npm.yml +0 -0
  21. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.github/workflows/publish-pypi.yml +0 -0
  22. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.github/workflows/update-homebrew.yml +0 -0
  23. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.github/workflows/version-sync.yml +0 -0
  24. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/.gitignore +0 -0
  25. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/LICENSE +0 -0
  26. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/PRD-v05.md +0 -0
  27. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/PRD-v06.md +0 -0
  28. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/PRD-v07.md +0 -0
  29. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/README.md +0 -0
  30. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/SKILL.md +0 -0
  31. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/attach.sh +0 -0
  32. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/check-agents.sh +0 -0
  33. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/clawforge +0 -0
  34. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/clawforge-web +0 -0
  35. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/clean.sh +0 -0
  36. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/completions.sh +0 -0
  37. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/config.sh +0 -0
  38. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/conflicts.sh +0 -0
  39. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/cost.sh +0 -0
  40. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/dashboard.sh +0 -0
  41. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/deps.sh +0 -0
  42. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/diff.sh +0 -0
  43. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/doctor.sh +0 -0
  44. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/eval.sh +0 -0
  45. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/export.sh +0 -0
  46. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/history.sh +0 -0
  47. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/init.sh +0 -0
  48. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/learn.sh +0 -0
  49. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/logs.sh +0 -0
  50. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/memory.sh +0 -0
  51. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/merge-helper.sh +0 -0
  52. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/multi-review.sh +0 -0
  53. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/notify.sh +0 -0
  54. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/on-complete.sh +0 -0
  55. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/parse-cost.sh +0 -0
  56. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/pr.sh +0 -0
  57. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/profile.sh +0 -0
  58. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/replay.sh +0 -0
  59. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/resume.sh +0 -0
  60. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/review-mode.sh +0 -0
  61. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/review-pr.sh +0 -0
  62. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/routing.sh +0 -0
  63. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/scope-task.sh +0 -0
  64. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/sprint.sh +0 -0
  65. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/steer.sh +0 -0
  66. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/stop.sh +0 -0
  67. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/summary.sh +0 -0
  68. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/swarm.sh +0 -0
  69. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/templates.sh +0 -0
  70. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/bin/web.sh +0 -0
  71. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/clawforge/__init__.py +0 -0
  72. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/clawforge/cli.py +0 -0
  73. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/completions/_clawforge +0 -0
  74. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/completions/clawforge.bash +0 -0
  75. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/completions/clawforge.fish +0 -0
  76. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/config/defaults.json +0 -0
  77. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/config/prompt-templates/default.md +0 -0
  78. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/config/routing-defaults.json +0 -0
  79. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/IMPLEMENTATION-v04.md +0 -0
  80. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/PRD-v04.md +0 -0
  81. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/PUBLISHING-CHECKLIST.md +0 -0
  82. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/README.md +0 -0
  83. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/RELEASE.md +0 -0
  84. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/architecture.md +0 -0
  85. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/command-reference.md +0 -0
  86. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/configuration.md +0 -0
  87. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/dashboard.md +0 -0
  88. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/evaluation.md +0 -0
  89. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/faq.md +0 -0
  90. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/fleet-ops.md +0 -0
  91. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/getting-started.md +0 -0
  92. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/scenarios.md +0 -0
  93. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/troubleshooting.md +0 -0
  94. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/docs/workflow-modes.md +0 -0
  95. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/evals/run-log.example.jsonl +0 -0
  96. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/evals/run-log.schema.json +0 -0
  97. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/evals/scorecard.md +0 -0
  98. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/install.sh +0 -0
  99. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/common.sh +0 -0
  100. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/templates/bugfix.json +0 -0
  101. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/templates/migration.json +0 -0
  102. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/templates/refactor.json +0 -0
  103. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/templates/security-audit.json +0 -0
  104. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/lib/templates/test-coverage.json +0 -0
  105. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/registry/conflicts.jsonl +0 -0
  106. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/registry/costs.jsonl +0 -0
  107. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/run-all-tests.sh +0 -0
  108. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-ci-loop.sh +0 -0
  109. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-clean.sh +0 -0
  110. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-cli.sh +0 -0
  111. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-conflicts.sh +0 -0
  112. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-cost.sh +0 -0
  113. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-dashboard.sh +0 -0
  114. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-deps.sh +0 -0
  115. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-eval.sh +0 -0
  116. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-foundation.sh +0 -0
  117. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-history.sh +0 -0
  118. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-init.sh +0 -0
  119. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-learn.sh +0 -0
  120. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-management.sh +0 -0
  121. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-memory.sh +0 -0
  122. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-merge.sh +0 -0
  123. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-modes.sh +0 -0
  124. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-multi-repo.sh +0 -0
  125. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-notify.sh +0 -0
  126. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-openclaw.sh +0 -0
  127. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-registry.sh +0 -0
  128. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-review.sh +0 -0
  129. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-routing.sh +0 -0
  130. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-scope.sh +0 -0
  131. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-spawn.sh +0 -0
  132. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-templates.sh +0 -0
  133. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-tui.sh +0 -0
  134. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tests/test-watch.sh +0 -0
  135. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/PRD.md +0 -0
  136. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/animation.go +0 -0
  137. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/filter.go +0 -0
  138. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/go.mod +0 -0
  139. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/go.sum +0 -0
  140. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/main.go +0 -0
  141. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/steer.go +0 -0
  142. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/tui/styles.go +0 -0
  143. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/web/go.mod +0 -0
  144. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/web/index.html +0 -0
  145. {clawforge_cli-1.5.4 → clawforge_cli-1.5.5}/web/main.go +0 -0
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.5.5 — TUI Observability: Logs + Diff Keys
4
+
5
+ ### Added
6
+ - `l` key in TUI dashboard: show last 50 lines of agent log in preview pane (reads log file; falls back to tmux capture for live sessions)
7
+ - `d` key in TUI dashboard: show `git diff --stat HEAD` for selected agent's worktree
8
+ - `Enter` now falls back to showing log file in preview when session is gone (instead of silent no-op)
9
+ - Agent log files auto-captured to `~/.clawforge/registry/logs/<branch>.log` via `tee` on spawn
10
+ - `log_path` stored in registry and surfaced to TUI
11
+ - `Esc` closes preview/log panel
12
+ - Navigation clears stale static preview content
13
+
14
+ ### Fixed
15
+ - `Enter` on finished/dead sessions silently did nothing — now shows log output
16
+
3
17
  ## v1.5.4 — TUI Attach + Agent Session Persistence
4
18
 
5
19
  ### Fixed
@@ -1,7 +1,8 @@
1
1
  class Clawforge < Formula
2
2
  desc "Multi-mode coding workflow CLI for orchestrating AI coding agents"
3
3
  homepage "https://github.com/cyperx84/clawforge"
4
- url "https://github.com/cyperx84/clawforge/archive/refs/tags/v1.5.3.tar.gz"
4
+ url "https://github.com/cyperx84/clawforge/archive/refs/tags/v1.5.4.tar.gz"
5
+ sha256 "549b3ebf95c953cd4f366b5a251786c994726761c9d4ed6255b996b6458cf695"
5
6
  sha256 "2730fca0066fda9d3c864802c4346ab7c39d0daee39a254cc5cebd2694d4a1db"
6
7
  sha256 "a026cb0df5b7c3efae439a9ca912e728843deb56c70441591c9064f81a1041ae"
7
8
  sha256 "27cca187828366d138dbde81f99f313e065c656be7073452ccc016eb5dba16db"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clawforge-cli
3
- Version: 1.5.4
3
+ Version: 1.5.5
4
4
  Summary: Multi-mode coding workflow CLI for orchestrating AI coding agents
5
5
  Project-URL: Homepage, https://github.com/cyperx84/clawforge
6
6
  Project-URL: Repository, https://github.com/cyperx84/clawforge
@@ -0,0 +1 @@
1
+ 1.5.5
@@ -114,6 +114,8 @@ else
114
114
  fi
115
115
 
116
116
  TMUX_SESSION="agent-${SAFE_BRANCH}"
117
+ LOGFILE="${CLAWFORGE_DIR}/registry/logs/${SAFE_BRANCH}.log"
118
+ mkdir -p "$(dirname "$LOGFILE")"
117
119
  MAX_RETRIES=$(config_get max_retries 3)
118
120
 
119
121
  log_info "Spawning agent: $RESOLVED_AGENT ($MODEL)"
@@ -183,6 +185,7 @@ TASK_JSON=$(jq -n \
183
185
  --arg desc "$TASK" \
184
186
  --arg repo "$REPO_ABS" \
185
187
  --arg wt "$WORKTREE_DIR" \
188
+ --arg log "$LOGFILE" \
186
189
  --arg branch "$BRANCH" \
187
190
  --argjson started "$NOW" \
188
191
  --argjson maxRetries "$MAX_RETRIES" \
@@ -194,6 +197,7 @@ TASK_JSON=$(jq -n \
194
197
  description: $desc,
195
198
  repo: $repo,
196
199
  worktree: $wt,
200
+ log_path: $log,
197
201
  branch: $branch,
198
202
  startedAt: $started,
199
203
  status: "spawned",
@@ -223,9 +227,9 @@ tmux kill-session -t "$TMUX_SESSION" 2>/dev/null || true
223
227
  # Build agent command — interactive mode so tmux attach works
224
228
  ESCAPED_PROMPT=$(echo "$FULL_PROMPT" | sed 's/"/\\"/g')
225
229
  if [[ "$RESOLVED_AGENT" == "claude" ]]; then
226
- AGENT_CMD="claude --model ${MODEL} --dangerously-skip-permissions --verbose -p \"${ESCAPED_PROMPT}\"; echo; echo \"[ClawForge] Agent finished. Press Enter to close.\"; read"
230
+ AGENT_CMD="claude --model ${MODEL} --dangerously-skip-permissions --verbose -p \"${ESCAPED_PROMPT}\" 2>&1 | tee \"${LOGFILE}\"; echo; echo \"[ClawForge] Agent finished. Press Enter to close.\"; read"
227
231
  elif [[ "$RESOLVED_AGENT" == "codex" ]]; then
228
- AGENT_CMD="codex --model ${MODEL} --dangerously-bypass-approvals-and-sandbox \"${ESCAPED_PROMPT}\"; echo; echo \"[ClawForge] Agent finished. Press Enter to close.\"; read"
232
+ AGENT_CMD="codex --model ${MODEL} --dangerously-bypass-approvals-and-sandbox \"${ESCAPED_PROMPT}\" 2>&1 | tee \"${LOGFILE}\"; echo; echo \"[ClawForge] Agent finished. Press Enter to close.\"; read"
229
233
  fi
230
234
 
231
235
  # Create tmux session and launch
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyperx/clawforge",
3
- "version": "1.5.4",
3
+ "version": "1.5.5",
4
4
  "description": "Multi-mode coding workflow CLI for orchestrating AI coding agents",
5
5
  "bin": {
6
6
  "@cyperx/clawforge": "./bin/clawforge"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "clawforge-cli"
3
- version = "1.5.4"
3
+ version = "1.5.5"
4
4
  description = "Multi-mode coding workflow CLI for orchestrating AI coding agents"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -134,10 +134,10 @@ assert_contains "help shows Developer Experience" "Developer Experience" "$cli_h
134
134
  # Test 11: version
135
135
  echo "Test 11: version"
136
136
  version=$(cat "${SCRIPT_DIR}/../VERSION")
137
- if [[ "$version" == "1.5.4" ]]; then
138
- echo " ✅ version is 1.5.4"; PASS=$((PASS+1))
137
+ if [[ "$version" == "1.5.5" ]]; then
138
+ echo " ✅ version is 1.5.5"; PASS=$((PASS+1))
139
139
  else
140
- echo " ❌ version is $version, expected 1.5.4"; FAIL=$((FAIL+1))
140
+ echo " ❌ version is $version, expected 1.5.5"; FAIL=$((FAIL+1))
141
141
  fi
142
142
 
143
143
  echo ""
@@ -77,7 +77,7 @@ assert_contains "dashboard help shows p key" "preview" "$tui_help"
77
77
  # Test 7: version
78
78
  echo "Test 7: version"
79
79
  version=$(cat "${SCRIPT_DIR}/../VERSION")
80
- assert_eq "version is 1.5.4" "1.5.4" "$version"
80
+ assert_eq "version is 1.5.5" "1.5.5" "$version"
81
81
 
82
82
  echo ""
83
83
  echo "Results: $PASS passed, $FAIL failed"
@@ -121,7 +121,7 @@ assert_contains "help shows Power Features" "Power Features" "$cli_help"
121
121
  # Test 13: version
122
122
  echo "Test 13: version"
123
123
  version=$(cat "${SCRIPT_DIR}/../VERSION")
124
- assert_eq "version is 1.5.4" "1.5.4" "$version"
124
+ assert_eq "version is 1.5.5" "1.5.5" "$version"
125
125
 
126
126
  echo ""
127
127
  echo "Results: $PASS passed, $FAIL failed"
@@ -96,7 +96,7 @@ assert_contains "watch checks terminal states" "done|failed|timeout|cancelled" "
96
96
  # Test 9: version
97
97
  echo "Test 9: version"
98
98
  version=$(cat "${SCRIPT_DIR}/../VERSION")
99
- assert_eq "version is 1.5.4" "1.5.4" "$version"
99
+ assert_eq "version is 1.5.5" "1.5.5" "$version"
100
100
 
101
101
  echo ""
102
102
  echo "Results: $PASS passed, $FAIL failed"
@@ -96,7 +96,7 @@ assert_contains "help shows Reliability" "Reliability" "$cli_help"
96
96
  # Test 11: version bump
97
97
  echo "Test 11: version"
98
98
  version=$(cat "${SCRIPT_DIR}/../VERSION")
99
- assert_eq "version is 1.5.4" "1.5.4" "$version"
99
+ assert_eq "version is 1.5.5" "1.5.5" "$version"
100
100
 
101
101
  # Test 12: doctor --fix runs without errors
102
102
  echo "Test 12: doctor --fix"
@@ -107,7 +107,7 @@ assert_contains "help shows Web Dashboard" "Web Dashboard" "$cli_help"
107
107
  # Test 7: version
108
108
  echo "Test 7: version"
109
109
  version=$(cat "${SCRIPT_DIR}/../VERSION")
110
- assert_eq "version is 1.5.4" "1.5.4" "$version"
110
+ assert_eq "version is 1.5.5" "1.5.5" "$version"
111
111
 
112
112
  echo ""
113
113
  echo "Results: $PASS passed, $FAIL failed"
@@ -25,6 +25,7 @@ type Agent struct {
25
25
  Conflicts int
26
26
  Description string
27
27
  Worktree string
28
+ LogPath string
28
29
  TmuxSession string
29
30
  }
30
31
 
@@ -42,6 +43,7 @@ type registryTask struct {
42
43
  Model string `json:"model"`
43
44
  Repo string `json:"repo"`
44
45
  CIStatus string `json:"ci_status"`
46
+ LogPath string `json:"log_path"`
45
47
  }
46
48
 
47
49
  type registryFile struct {
@@ -122,6 +124,7 @@ func LoadAgents() []Agent {
122
124
  Description: t.Description,
123
125
  Task: t.Description,
124
126
  Worktree: t.Worktree,
127
+ LogPath: t.LogPath,
125
128
  TmuxSession: t.TmuxSession,
126
129
  CI: ciIndicator(t.CIStatus),
127
130
  Cost: costs[t.ID],
@@ -114,11 +114,15 @@ func renderDashboard(m Model) string {
114
114
  fmt.Sprintf("── Preview: %s ──", selAgent.ID))
115
115
  b.WriteString(previewHeader)
116
116
  b.WriteString("\n")
117
- if selAgent.Preview != "" {
118
- b.WriteString(lipgloss.NewStyle().Faint(true).Render(selAgent.Preview))
119
- } else {
120
- b.WriteString(lipgloss.NewStyle().Faint(true).Render("(no output / not running)"))
117
+ // Static content (from l/d keys) takes priority over live tmux preview.
118
+ content := m.previewContent
119
+ if content == "" {
120
+ content = selAgent.Preview
121
121
  }
122
+ if content == "" {
123
+ content = "(no output / not running)"
124
+ }
125
+ b.WriteString(lipgloss.NewStyle().Faint(true).Render(content))
122
126
  b.WriteString("\n")
123
127
  }
124
128
  }
@@ -2,6 +2,7 @@ package main
2
2
 
3
3
  import (
4
4
  "fmt"
5
+ "os"
5
6
  "os/exec"
6
7
  "strings"
7
8
 
@@ -48,44 +49,51 @@ func handleKeyPress(m Model, msg tea.KeyPressMsg) (Model, tea.Cmd) {
48
49
  case "j", "down":
49
50
  if count > 0 && m.selected < count-1 {
50
51
  m.selected++
52
+ m.previewContent = "" // clear static preview on navigation
51
53
  }
52
54
  return m, nil
53
55
 
54
56
  case "k", "up":
55
57
  if m.selected > 0 {
56
58
  m.selected--
59
+ m.previewContent = "" // clear static preview on navigation
57
60
  }
58
61
  return m, nil
59
62
 
60
63
  case "g":
61
64
  m.selected = 0
65
+ m.previewContent = ""
62
66
  return m, nil
63
67
 
64
68
  case "G":
65
69
  if count > 0 {
66
70
  m.selected = count - 1
71
+ m.previewContent = ""
67
72
  }
68
73
  return m, nil
69
74
 
70
75
  case "enter":
71
76
  // Attach to selected agent's tmux session.
77
+ // If no live session, fall back to showing log in preview.
72
78
  if count > 0 {
73
79
  agent := agents[m.selected]
74
80
  session := agent.TmuxSession
75
81
  if session == "" {
76
82
  session = "clawforge-" + agent.ID
77
83
  }
78
- // Check if tmux session exists before trying to attach
84
+ // Check if tmux session exists before trying to attach.
79
85
  check := exec.Command("tmux", "has-session", "-t", session)
80
86
  if err := check.Run(); err != nil {
81
- // Session doesn't exist — show logs instead
82
- logCmd := exec.Command("tmux", "show-buffer", "-b", session)
83
- if logOut, logErr := logCmd.Output(); logErr == nil && len(logOut) > 0 {
84
- m.showPreview = true
85
- filtered := m.filteredAgents()
86
- if m.selected < len(filtered) {
87
- filtered[m.selected].Preview = string(logOut)
87
+ // No live session — show log file in preview instead.
88
+ m.showPreview = true
89
+ if agent.LogPath != "" {
90
+ if data, rerr := os.ReadFile(agent.LogPath); rerr == nil && len(data) > 0 {
91
+ m.previewContent = "(log)\n" + tailLines(string(data), 40)
92
+ } else {
93
+ m.previewContent = "(no log captured — session has ended)"
88
94
  }
95
+ } else {
96
+ m.previewContent = "(no live session and no log path recorded)"
89
97
  }
90
98
  return m, nil
91
99
  }
@@ -146,6 +154,7 @@ func handleKeyPress(m Model, msg tea.KeyPressMsg) (Model, tea.Cmd) {
146
154
  case "r":
147
155
  // Force refresh.
148
156
  m.agents = LoadAgents()
157
+ m.previewContent = ""
149
158
  // Clamp selection.
150
159
  filtered := m.filteredAgents()
151
160
  if m.selected >= len(filtered) {
@@ -153,8 +162,56 @@ func handleKeyPress(m Model, msg tea.KeyPressMsg) (Model, tea.Cmd) {
153
162
  }
154
163
  return m, nil
155
164
 
165
+ case "l":
166
+ // Show last 50 lines of agent log in preview pane.
167
+ if count > 0 {
168
+ agent := agents[m.selected]
169
+ m.showPreview = true
170
+ if agent.LogPath != "" {
171
+ if data, err := os.ReadFile(agent.LogPath); err == nil && len(data) > 0 {
172
+ m.previewContent = "(log) " + agent.ID + "\n" + tailLines(string(data), 50)
173
+ } else {
174
+ m.previewContent = "(no log yet for " + agent.ID + ")"
175
+ }
176
+ } else if agent.TmuxSession != "" {
177
+ // Fallback: capture from live tmux pane.
178
+ out, err := exec.Command("tmux", "capture-pane", "-t", agent.TmuxSession, "-p", "-S", "-50").Output()
179
+ if err == nil && len(out) > 0 {
180
+ m.previewContent = "(tmux) " + agent.ID + "\n" + string(out)
181
+ } else {
182
+ m.previewContent = "(no output captured for " + agent.ID + ")"
183
+ }
184
+ } else {
185
+ m.previewContent = "(no log path or tmux session for " + agent.ID + ")"
186
+ }
187
+ }
188
+ return m, nil
189
+
190
+ case "d":
191
+ // Show git diff --stat for selected agent's worktree.
192
+ if count > 0 {
193
+ agent := agents[m.selected]
194
+ m.showPreview = true
195
+ if agent.Worktree != "" {
196
+ out, err := exec.Command("git", "-C", agent.Worktree, "diff", "--stat", "HEAD").Output()
197
+ if err == nil && len(out) > 0 {
198
+ m.previewContent = "(diff) " + agent.ID + "\n" + string(out)
199
+ } else {
200
+ out2, _ := exec.Command("git", "-C", agent.Worktree, "status", "--short").Output()
201
+ m.previewContent = "(diff) " + agent.ID + " — no diff yet\n" + string(out2)
202
+ }
203
+ } else {
204
+ m.previewContent = "(no worktree recorded for " + agent.ID + ")"
205
+ }
206
+ }
207
+ return m, nil
208
+
156
209
  case "p":
210
+ // Toggle live preview pane (clears any static log/diff content).
157
211
  m.showPreview = !m.showPreview
212
+ if !m.showPreview {
213
+ m.previewContent = ""
214
+ }
158
215
  return m, nil
159
216
 
160
217
  case "n":
@@ -179,6 +236,10 @@ func handleKeyPress(m Model, msg tea.KeyPressMsg) (Model, tea.Cmd) {
179
236
  if m.showHelp {
180
237
  m.showHelp = false
181
238
  }
239
+ if m.previewContent != "" {
240
+ m.previewContent = ""
241
+ m.showPreview = false
242
+ }
182
243
  return m, nil
183
244
  }
184
245
 
@@ -214,18 +275,20 @@ func renderHelpOverlay(width int) string {
214
275
  desc string
215
276
  }{
216
277
  {"j/k", "Navigate agent list"},
217
- {"Enter", "Attach to selected agent's tmux session"},
278
+ {"Enter", "Attach to tmux session (or show log if session gone)"},
279
+ {"l", "Show agent log in preview pane"},
280
+ {"d", "Show git diff in preview pane"},
218
281
  {"s", "Steer selected agent (prompts for message)"},
219
282
  {"x", "Stop selected agent"},
220
283
  {"/", "Filter agents"},
221
284
  {"1/2/3", "Views: all / running / finished"},
222
285
  {"Tab", "Cycle views"},
223
286
  {"n", "Nudge selected running agent"},
224
- {"p", "Toggle output preview pane"},
287
+ {"p", "Toggle live output preview pane"},
225
288
  {"r", "Force refresh"},
226
289
  {"g/G", "Go to top/bottom"},
227
290
  {"?", "Toggle help overlay"},
228
- {"Esc", "Close modal/overlay"},
291
+ {"Esc", "Close modal/overlay/preview"},
229
292
  {"q", "Quit dashboard"},
230
293
  }
231
294
 
@@ -241,3 +304,12 @@ func renderHelpOverlay(width int) string {
241
304
  content := strings.Join(lines, "\n")
242
305
  return helpOverlayStyle.Render(content)
243
306
  }
307
+
308
+ // tailLines returns the last n lines of s.
309
+ func tailLines(s string, n int) string {
310
+ lines := strings.Split(strings.TrimRight(s, "\n"), "\n")
311
+ if len(lines) <= n {
312
+ return strings.Join(lines, "\n")
313
+ }
314
+ return strings.Join(lines[len(lines)-n:], "\n")
315
+ }
@@ -28,7 +28,8 @@ type Model struct {
28
28
  width int
29
29
  height int
30
30
  steerMode bool
31
- showPreview bool
31
+ showPreview bool
32
+ previewContent string // static content to show in preview (log, diff)
32
33
  steerInput string
33
34
  confirmStop bool
34
35
  frame int
@@ -1 +0,0 @@
1
- 1.5.4
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes