clawforge-cli 1.2.0__tar.gz → 1.3.0__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 (137) hide show
  1. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/CHANGELOG.md +37 -0
  2. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/Formula/clawforge.rb +1 -0
  3. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PKG-INFO +1 -1
  4. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/SKILL.md +12 -1
  5. clawforge_cli-1.3.0/VERSION +1 -0
  6. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/clawforge +10 -0
  7. clawforge_cli-1.3.0/bin/completions.sh +68 -0
  8. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/doctor.sh +63 -0
  9. clawforge_cli-1.3.0/bin/export.sh +125 -0
  10. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/on-complete.sh +51 -3
  11. clawforge_cli-1.3.0/bin/profile.sh +138 -0
  12. clawforge_cli-1.3.0/bin/replay.sh +134 -0
  13. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/spawn-agent.sh +37 -1
  14. clawforge_cli-1.3.0/completions/_clawforge +82 -0
  15. clawforge_cli-1.3.0/completions/clawforge.bash +60 -0
  16. clawforge_cli-1.3.0/completions/clawforge.fish +33 -0
  17. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/README.md +1 -0
  18. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/command-reference.md +37 -0
  19. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/package.json +1 -1
  20. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/pyproject.toml +1 -1
  21. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/run-all-tests.sh +1 -1
  22. clawforge_cli-1.3.0/tests/test-dx.sh +145 -0
  23. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-observability.sh +1 -1
  24. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-power.sh +1 -1
  25. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-practical.sh +1 -1
  26. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-reliability.sh +1 -1
  27. clawforge_cli-1.2.0/VERSION +0 -1
  28. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/ci.yml +0 -0
  29. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/publish-npm.yml +0 -0
  30. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/publish-pypi.yml +0 -0
  31. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/update-homebrew.yml +0 -0
  32. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/version-sync.yml +0 -0
  33. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.gitignore +0 -0
  34. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/LICENSE +0 -0
  35. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v05.md +0 -0
  36. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v06.md +0 -0
  37. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v07.md +0 -0
  38. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/README.md +0 -0
  39. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/attach.sh +0 -0
  40. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/check-agents.sh +0 -0
  41. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/clean.sh +0 -0
  42. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/config.sh +0 -0
  43. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/conflicts.sh +0 -0
  44. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/cost.sh +0 -0
  45. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/dashboard.sh +0 -0
  46. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/diff.sh +0 -0
  47. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/eval.sh +0 -0
  48. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/history.sh +0 -0
  49. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/init.sh +0 -0
  50. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/learn.sh +0 -0
  51. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/logs.sh +0 -0
  52. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/memory.sh +0 -0
  53. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/merge-helper.sh +0 -0
  54. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/multi-review.sh +0 -0
  55. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/notify.sh +0 -0
  56. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/parse-cost.sh +0 -0
  57. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/pr.sh +0 -0
  58. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/resume.sh +0 -0
  59. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/review-mode.sh +0 -0
  60. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/review-pr.sh +0 -0
  61. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/routing.sh +0 -0
  62. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/scope-task.sh +0 -0
  63. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/sprint.sh +0 -0
  64. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/steer.sh +0 -0
  65. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/stop.sh +0 -0
  66. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/summary.sh +0 -0
  67. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/swarm.sh +0 -0
  68. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/templates.sh +0 -0
  69. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/clawforge/__init__.py +0 -0
  70. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/clawforge/cli.py +0 -0
  71. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/defaults.json +0 -0
  72. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/prompt-templates/default.md +0 -0
  73. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/routing-defaults.json +0 -0
  74. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/IMPLEMENTATION-v04.md +0 -0
  75. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/PRD-v04.md +0 -0
  76. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/PUBLISHING-CHECKLIST.md +0 -0
  77. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/RELEASE.md +0 -0
  78. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/architecture.md +0 -0
  79. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/configuration.md +0 -0
  80. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/dashboard.md +0 -0
  81. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/evaluation.md +0 -0
  82. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/faq.md +0 -0
  83. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/fleet-ops.md +0 -0
  84. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/getting-started.md +0 -0
  85. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/scenarios.md +0 -0
  86. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/troubleshooting.md +0 -0
  87. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/workflow-modes.md +0 -0
  88. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/run-log.example.jsonl +0 -0
  89. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/run-log.schema.json +0 -0
  90. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/scorecard.md +0 -0
  91. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/install.sh +0 -0
  92. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/common.sh +0 -0
  93. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/bugfix.json +0 -0
  94. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/migration.json +0 -0
  95. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/refactor.json +0 -0
  96. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/security-audit.json +0 -0
  97. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/test-coverage.json +0 -0
  98. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/registry/conflicts.jsonl +0 -0
  99. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/registry/costs.jsonl +0 -0
  100. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-ci-loop.sh +0 -0
  101. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-clean.sh +0 -0
  102. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-cli.sh +0 -0
  103. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-conflicts.sh +0 -0
  104. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-cost.sh +0 -0
  105. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-dashboard.sh +0 -0
  106. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-eval.sh +0 -0
  107. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-foundation.sh +0 -0
  108. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-history.sh +0 -0
  109. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-init.sh +0 -0
  110. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-learn.sh +0 -0
  111. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-management.sh +0 -0
  112. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-memory.sh +0 -0
  113. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-merge.sh +0 -0
  114. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-modes.sh +0 -0
  115. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-multi-repo.sh +0 -0
  116. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-notify.sh +0 -0
  117. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-openclaw.sh +0 -0
  118. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-registry.sh +0 -0
  119. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-review.sh +0 -0
  120. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-routing.sh +0 -0
  121. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-scope.sh +0 -0
  122. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-spawn.sh +0 -0
  123. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-templates.sh +0 -0
  124. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-tui.sh +0 -0
  125. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-watch.sh +0 -0
  126. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/PRD.md +0 -0
  127. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/agent.go +0 -0
  128. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/animation.go +0 -0
  129. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/dashboard.go +0 -0
  130. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/filter.go +0 -0
  131. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/go.mod +0 -0
  132. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/go.sum +0 -0
  133. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/keybindings.go +0 -0
  134. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/main.go +0 -0
  135. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/model.go +0 -0
  136. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/steer.go +0 -0
  137. {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/styles.go +0 -0
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## v1.3.0 — Developer Experience
4
+
5
+ ### Task Dependencies
6
+ - `--after <id>` flag on spawn/sprint — chain tasks so B starts when A completes
7
+ - Configurable timeout via `CLAWFORGE_DEP_TIMEOUT` (default: 1 hour)
8
+ - Auto-aborts if dependency fails/times out/cancelled
9
+
10
+ ### Agent Profiles (`clawforge profile`)
11
+ - Save reusable parameter presets: `clawforge profile create fast --agent claude --model haiku --timeout 5`
12
+ - `profile list|show|create|delete|use`
13
+ - Use with spawn: `clawforge sprint --repo . --task "fix" $(clawforge profile use fast)`
14
+
15
+ ### Replay (`clawforge replay`)
16
+ - Re-run completed/failed tasks with same parameters on a fresh worktree
17
+ - Override model/agent: `clawforge replay 1 --model claude-opus-4`
18
+ - Auto-generates retry branch names (`feature-retry-1`, `-retry-2`, etc.)
19
+
20
+ ### Export (`clawforge export`)
21
+ - Full task history as markdown or JSON report
22
+ - Filter by status, date range
23
+ - Summary stats with cost totals
24
+
25
+ ### Shell Completions (`clawforge completions`)
26
+ - Tab completion for bash, zsh, and fish
27
+ - `clawforge completions zsh` — one command install
28
+
29
+ ### Discord/Slack Webhooks
30
+ - `on-complete` now supports Discord and Slack webhook formats
31
+ - Configure globally: `clawforge config set discord_webhook https://...`
32
+ - Rich Discord embeds with color-coded status
33
+
34
+ ### Doctor Enhancements
35
+ - Lock file health checks
36
+ - Config JSON validation
37
+ - Profile validation
38
+ - Auto-fix for all new checks with `--fix`
39
+
3
40
  ## v1.2.0 — Power Features
4
41
 
5
42
  ### User Config (`clawforge config`)
@@ -2,6 +2,7 @@ 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
4
  url "https://github.com/cyperx84/clawforge/archive/refs/tags/v1.2.0.tar.gz"
5
+ sha256 "4364bb00aadf4b4f762be5e859a5be33a3f561ded134610691f1ac4cc4492b6e"
5
6
  sha256 "6da402969628cc5a0dbafdcfca2596bced80692a714672ccb9e39c45f121465c"
6
7
  # sha256 will be filled by CI
7
8
  license "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clawforge-cli
3
- Version: 1.2.0
3
+ Version: 1.3.0
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
@@ -11,7 +11,7 @@ metadata:
11
11
  }
12
12
  ---
13
13
 
14
- # ClawForge v1.2 — Multi-Mode Coding Workflow + Fleet Ops
14
+ # ClawForge v1.3 — Multi-Mode Coding Workflow + Fleet Ops
15
15
 
16
16
  ## Overview
17
17
 
@@ -37,6 +37,17 @@ clawforge sprint --template bugfix "Fix auth race" --budget 3.00 --ci-loop
37
37
  clawforge swarm --json --notify --webhook https://example.com/hook "Migrate tests"
38
38
  ```
39
39
 
40
+ ### New in v1.3
41
+
42
+ ```bash
43
+ clawforge profile create fast --agent claude --model haiku --timeout 5 # Reusable presets
44
+ clawforge sprint --repo . --task "tests" --after 1 # Task chaining
45
+ clawforge replay 1 # Re-run task
46
+ clawforge export --format json --save report.json # Export history
47
+ clawforge completions zsh # Tab completions
48
+ clawforge config set discord_webhook https://discord.com/api/webhooks/... # Notifications
49
+ ```
50
+
40
51
  ### New in v1.2
41
52
 
42
53
  ```bash
@@ -0,0 +1 @@
1
+ 1.3.0
@@ -81,6 +81,12 @@ Power Features (v1.2):
81
81
  summary AI-generated summary of what an agent did
82
82
  parse-cost Parse real cost/token data from agent output
83
83
 
84
+ Developer Experience (v1.3):
85
+ profile Manage reusable agent profiles (presets)
86
+ replay Re-run a completed task with same parameters
87
+ export Export task history as markdown/JSON report
88
+ completions Install shell tab completions (bash/zsh/fish)
89
+
84
90
  Evaluation (v0.6.2):
85
91
  eval Run-eval logging and weekly summaries
86
92
 
@@ -236,6 +242,10 @@ doctor) exec "${BIN_DIR}/doctor.sh" "$@" ;;
236
242
  multi-review) exec "${BIN_DIR}/multi-review.sh" "$@" ;;
237
243
  summary) exec "${BIN_DIR}/summary.sh" "$@" ;;
238
244
  parse-cost) exec "${BIN_DIR}/parse-cost.sh" "$@" ;;
245
+ profile) exec "${BIN_DIR}/profile.sh" "$@" ;;
246
+ replay) exec "${BIN_DIR}/replay.sh" "$@" ;;
247
+ export) exec "${BIN_DIR}/export.sh" "$@" ;;
248
+ completions) exec "${BIN_DIR}/completions.sh" "$@" ;;
239
249
  logs) exec "${BIN_DIR}/logs.sh" "$@" ;;
240
250
  on-complete) exec "${BIN_DIR}/on-complete.sh" "$@" ;;
241
251
 
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+ # completions.sh — Install shell completions for clawforge
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ COMP_DIR="${SCRIPT_DIR}/../completions"
7
+
8
+ usage() {
9
+ cat <<EOF
10
+ Usage: clawforge completions <shell>
11
+
12
+ Install tab completions for clawforge.
13
+
14
+ Shells:
15
+ bash Install bash completions
16
+ zsh Install zsh completions
17
+ fish Install fish completions
18
+ --help Show this help
19
+
20
+ Examples:
21
+ clawforge completions bash
22
+ clawforge completions zsh
23
+ clawforge completions fish
24
+
25
+ After installing, restart your shell or source the completion file.
26
+ EOF
27
+ }
28
+
29
+ [[ $# -eq 0 ]] && { usage; exit 0; }
30
+
31
+ case "$1" in
32
+ bash)
33
+ DEST="${BASH_COMPLETION_USER_DIR:-${HOME}/.local/share/bash-completion/completions}"
34
+ mkdir -p "$DEST"
35
+ cp "$COMP_DIR/clawforge.bash" "$DEST/clawforge"
36
+ echo "Installed bash completions to $DEST/clawforge"
37
+ echo "Restart your shell or run: source $DEST/clawforge"
38
+ ;;
39
+ zsh)
40
+ # Try homebrew zsh completions first, then user dir
41
+ if [[ -d "/opt/homebrew/share/zsh/site-functions" ]]; then
42
+ DEST="/opt/homebrew/share/zsh/site-functions"
43
+ elif [[ -d "${HOME}/.zsh/completions" ]]; then
44
+ DEST="${HOME}/.zsh/completions"
45
+ else
46
+ DEST="${HOME}/.zsh/completions"
47
+ mkdir -p "$DEST"
48
+ echo "Add to .zshrc: fpath=(~/.zsh/completions \$fpath)"
49
+ fi
50
+ cp "$COMP_DIR/_clawforge" "$DEST/_clawforge"
51
+ echo "Installed zsh completions to $DEST/_clawforge"
52
+ echo "Run: rm -f ~/.zcompdump && compinit"
53
+ ;;
54
+ fish)
55
+ DEST="${HOME}/.config/fish/completions"
56
+ mkdir -p "$DEST"
57
+ cp "$COMP_DIR/clawforge.fish" "$DEST/clawforge.fish"
58
+ echo "Installed fish completions to $DEST/clawforge.fish"
59
+ ;;
60
+ --help|-h)
61
+ usage
62
+ ;;
63
+ *)
64
+ echo "Unknown shell: $1"
65
+ echo "Supported: bash, zsh, fish"
66
+ exit 1
67
+ ;;
68
+ esac
@@ -181,6 +181,69 @@ else
181
181
  check OK "Disk check skipped (df unavailable)"
182
182
  fi
183
183
 
184
+ # 7. Lock file health
185
+ echo ""
186
+ echo "── Lock Files ────────────────────────────"
187
+ LOCK_FILE="${CLAWFORGE_DIR}/registry/.lock"
188
+ if [[ -f "$LOCK_FILE" ]]; then
189
+ LOCK_PID=$(cat "$LOCK_FILE" 2>/dev/null || true)
190
+ if [[ -n "$LOCK_PID" ]] && ! kill -0 "$LOCK_PID" 2>/dev/null; then
191
+ check WARN "Stale lock file (PID $LOCK_PID not running)"
192
+ if $FIX; then
193
+ rm -f "$LOCK_FILE"
194
+ echo " → Fixed: removed stale lock"
195
+ FIXED=$((FIXED+1))
196
+ fi
197
+ else
198
+ check OK "Lock file clean"
199
+ fi
200
+ else
201
+ check OK "No lock file"
202
+ fi
203
+
204
+ # 8. Config validation
205
+ echo ""
206
+ echo "── Configuration ─────────────────────────"
207
+ USER_CFG="${HOME}/.clawforge/config.json"
208
+ if [[ -f "$USER_CFG" ]]; then
209
+ if jq empty "$USER_CFG" 2>/dev/null; then
210
+ KEY_COUNT=$(jq 'keys | length' "$USER_CFG")
211
+ check OK "User config valid ($KEY_COUNT keys)"
212
+ else
213
+ check ERROR "User config is malformed JSON"
214
+ if $FIX; then
215
+ cp "$USER_CFG" "${USER_CFG}.bak"
216
+ echo '{}' > "$USER_CFG"
217
+ echo " → Fixed: reset config (backup at ${USER_CFG}.bak)"
218
+ FIXED=$((FIXED+1))
219
+ fi
220
+ fi
221
+ else
222
+ check OK "No user config (using defaults)"
223
+ fi
224
+
225
+ # 9. Profiles directory
226
+ PROFILES_DIR="${HOME}/.clawforge/profiles"
227
+ if [[ -d "$PROFILES_DIR" ]]; then
228
+ PROFILE_COUNT=$(find "$PROFILES_DIR" -maxdepth 1 -name "*.json" 2>/dev/null | wc -l | tr -d ' ')
229
+ check OK "$PROFILE_COUNT agent profile(s) configured"
230
+ # Validate each profile
231
+ shopt -s nullglob 2>/dev/null || true
232
+ for pf in "$PROFILES_DIR"/*.json; do
233
+ [[ -f "$pf" ]] || continue
234
+ if ! jq empty "$pf" 2>/dev/null; then
235
+ check WARN "Malformed profile: $(basename "$pf" .json)"
236
+ if $FIX; then
237
+ rm "$pf"
238
+ echo " → Fixed: removed malformed profile"
239
+ FIXED=$((FIXED+1))
240
+ fi
241
+ fi
242
+ done
243
+ else
244
+ check OK "No profiles directory"
245
+ fi
246
+
184
247
  # Summary
185
248
  echo ""
186
249
  echo "────────────────────────────────────────"
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env bash
2
+ # export.sh — Export task history as markdown or JSON report
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ source "${SCRIPT_DIR}/../lib/common.sh"
7
+
8
+ usage() {
9
+ cat <<EOF
10
+ Usage: clawforge export [options]
11
+
12
+ Export full task history as a report.
13
+
14
+ Options:
15
+ --format <fmt> Output format: markdown, json (default: markdown)
16
+ --status <status> Filter by status (done, failed, running, all) (default: all)
17
+ --since <date> Filter tasks since date (YYYY-MM-DD)
18
+ --save <path> Save to file (default: stdout)
19
+ --help Show this help
20
+
21
+ Examples:
22
+ clawforge export # Full markdown report
23
+ clawforge export --format json # JSON dump
24
+ clawforge export --status done --save report.md # Only completed tasks
25
+ clawforge export --since 2026-03-01 # Recent tasks only
26
+ EOF
27
+ }
28
+
29
+ FORMAT="markdown" STATUS_FILTER="all" SINCE="" SAVE_PATH=""
30
+
31
+ while [[ $# -gt 0 ]]; do
32
+ case "$1" in
33
+ --format) FORMAT="$2"; shift 2 ;;
34
+ --status) STATUS_FILTER="$2"; shift 2 ;;
35
+ --since) SINCE="$2"; shift 2 ;;
36
+ --save) SAVE_PATH="$2"; shift 2 ;;
37
+ --help|-h) usage; exit 0 ;;
38
+ --*) log_error "Unknown option: $1"; usage; exit 1 ;;
39
+ *) shift ;;
40
+ esac
41
+ done
42
+
43
+ _ensure_registry
44
+
45
+ # Gather all tasks (active + completed)
46
+ COMPLETED_FILE="${CLAWFORGE_DIR}/registry/completed-tasks.jsonl"
47
+ COSTS_FILE="${CLAWFORGE_DIR}/registry/costs.jsonl"
48
+
49
+ ALL_TASKS="[]"
50
+
51
+ # Active tasks
52
+ ACTIVE=$(jq '.tasks' "$REGISTRY_FILE" 2>/dev/null || echo '[]')
53
+ ALL_TASKS=$(echo "$ACTIVE" | jq '.')
54
+
55
+ # Completed tasks
56
+ if [[ -f "$COMPLETED_FILE" ]]; then
57
+ COMPLETED=$(jq -s '.' "$COMPLETED_FILE" 2>/dev/null || echo '[]')
58
+ ALL_TASKS=$(jq -s '.[0] + .[1] | unique_by(.id // .taskId)' <(echo "$ALL_TASKS") <(echo "$COMPLETED") 2>/dev/null || echo "$ALL_TASKS")
59
+ fi
60
+
61
+ # Apply filters
62
+ if [[ "$STATUS_FILTER" != "all" ]]; then
63
+ ALL_TASKS=$(echo "$ALL_TASKS" | jq --arg s "$STATUS_FILTER" '[.[] | select(.status == $s)]')
64
+ fi
65
+
66
+ if [[ -n "$SINCE" ]]; then
67
+ SINCE_TS=$(date -j -f "%Y-%m-%d" "$SINCE" "+%s" 2>/dev/null || date -d "$SINCE" "+%s" 2>/dev/null || echo "0")
68
+ SINCE_MS=$((SINCE_TS * 1000))
69
+ ALL_TASKS=$(echo "$ALL_TASKS" | jq --argjson s "$SINCE_MS" '[.[] | select((.startedAt // .timestamp // 0) >= $s)]')
70
+ fi
71
+
72
+ TASK_COUNT=$(echo "$ALL_TASKS" | jq 'length')
73
+
74
+ # Generate output
75
+ generate_markdown() {
76
+ echo "# ClawForge Task Report"
77
+ echo "Generated: $(date)"
78
+ echo "Tasks: $TASK_COUNT"
79
+ [[ "$STATUS_FILTER" != "all" ]] && echo "Filter: status=$STATUS_FILTER"
80
+ [[ -n "$SINCE" ]] && echo "Since: $SINCE"
81
+ echo ""
82
+
83
+ # Summary stats
84
+ DONE_COUNT=$(echo "$ALL_TASKS" | jq '[.[] | select(.status == "done")] | length')
85
+ FAIL_COUNT=$(echo "$ALL_TASKS" | jq '[.[] | select(.status == "failed")] | length')
86
+ RUN_COUNT=$(echo "$ALL_TASKS" | jq '[.[] | select(.status == "running")] | length')
87
+
88
+ echo "## Summary"
89
+ echo "| Status | Count |"
90
+ echo "|--------|-------|"
91
+ echo "| ✅ Done | $DONE_COUNT |"
92
+ echo "| ❌ Failed | $FAIL_COUNT |"
93
+ echo "| 🔄 Running | $RUN_COUNT |"
94
+ echo "| Total | $TASK_COUNT |"
95
+ echo ""
96
+
97
+ # Costs
98
+ if [[ -f "$COSTS_FILE" ]] && [[ -s "$COSTS_FILE" ]]; then
99
+ TOTAL_COST=$(jq -s '[.[].totalCost // 0] | add' "$COSTS_FILE" 2>/dev/null || echo "0")
100
+ TOTAL_TOKENS=$(jq -s '[.[].totalTokens // 0] | add' "$COSTS_FILE" 2>/dev/null || echo "0")
101
+ echo "## Costs"
102
+ echo "- Total cost: \$${TOTAL_COST}"
103
+ echo "- Total tokens: ${TOTAL_TOKENS}"
104
+ echo ""
105
+ fi
106
+
107
+ # Task details
108
+ echo "## Tasks"
109
+ echo ""
110
+
111
+ echo "$ALL_TASKS" | jq -r '.[] | "### #\(.short_id // "—") — \(.description // .desc // "—")\n- **Status:** \(.status // "—")\n- **Mode:** \(.mode // "—")\n- **Agent:** \(.agent // "—")\n- **Branch:** \(.branch // "—")\n"' 2>/dev/null || true
112
+ }
113
+
114
+ if [[ "$FORMAT" == "json" ]]; then
115
+ OUTPUT=$(echo "$ALL_TASKS" | jq '.')
116
+ else
117
+ OUTPUT=$(generate_markdown)
118
+ fi
119
+
120
+ if [[ -n "$SAVE_PATH" ]]; then
121
+ echo "$OUTPUT" > "$SAVE_PATH"
122
+ echo "Report saved to $SAVE_PATH ($TASK_COUNT tasks)"
123
+ else
124
+ echo "$OUTPUT"
125
+ fi
@@ -117,7 +117,55 @@ if [[ -n "$WEBHOOK" ]]; then
117
117
  fi
118
118
  fi
119
119
 
120
- # 3. Auto-clean
120
+ # 3. Discord/Slack webhook
121
+ DISCORD_WEBHOOK=$(echo "$TASK_DATA" | jq -r '.discord_webhook // empty')
122
+ if [[ -z "$DISCORD_WEBHOOK" ]]; then
123
+ DISCORD_WEBHOOK=$(config_get discord_webhook "")
124
+ fi
125
+ if [[ -n "$DISCORD_WEBHOOK" ]]; then
126
+ EMOJI="✅"
127
+ COLOR=5763719 # green
128
+ [[ "$STATUS" == "failed" ]] && { EMOJI="❌"; COLOR=15548997; } # red
129
+ [[ "$STATUS" == "timeout" ]] && { EMOJI="⏰"; COLOR=16776960; } # yellow
130
+ [[ "$STATUS" == "cancelled" ]] && { EMOJI="🚫"; COLOR=10070709; } # grey
131
+
132
+ DISCORD_PAYLOAD=$(jq -cn \
133
+ --arg title "${EMOJI} ClawForge #${SHORT_ID} ${STATUS}" \
134
+ --arg desc "$DESC" \
135
+ --arg mode "$MODE" \
136
+ --arg status "$STATUS" \
137
+ --argjson color "$COLOR" \
138
+ '{embeds:[{title:$title,description:$desc,color:$color,fields:[{name:"Mode",value:$mode,inline:true},{name:"Status",value:$status,inline:true}]}]}')
139
+
140
+ if $DRY_RUN; then
141
+ echo "[dry-run] Would send Discord webhook"
142
+ else
143
+ curl -s -X POST -H "Content-Type: application/json" -d "$DISCORD_PAYLOAD" "$DISCORD_WEBHOOK" >/dev/null 2>&1 || log_warn "Discord webhook failed"
144
+ log_info "Sent Discord notification"
145
+ fi
146
+ fi
147
+
148
+ SLACK_WEBHOOK=$(echo "$TASK_DATA" | jq -r '.slack_webhook // empty')
149
+ if [[ -z "$SLACK_WEBHOOK" ]]; then
150
+ SLACK_WEBHOOK=$(config_get slack_webhook "")
151
+ fi
152
+ if [[ -n "$SLACK_WEBHOOK" ]]; then
153
+ EMOJI="✅"
154
+ [[ "$STATUS" == "failed" ]] && EMOJI="❌"
155
+ [[ "$STATUS" == "timeout" ]] && EMOJI="⏰"
156
+ SLACK_PAYLOAD=$(jq -cn \
157
+ --arg text "${EMOJI} ClawForge #${SHORT_ID} ${STATUS}: ${DESC} (${MODE})" \
158
+ '{text:$text}')
159
+
160
+ if $DRY_RUN; then
161
+ echo "[dry-run] Would send Slack webhook"
162
+ else
163
+ curl -s -X POST -H "Content-Type: application/json" -d "$SLACK_PAYLOAD" "$SLACK_WEBHOOK" >/dev/null 2>&1 || log_warn "Slack webhook failed"
164
+ log_info "Sent Slack notification"
165
+ fi
166
+ fi
167
+
168
+ # 4. Auto-clean
121
169
  if [[ "$AUTO_CLEAN" == "true" ]]; then
122
170
  if $DRY_RUN; then
123
171
  echo "[dry-run] Would auto-clean task #${SHORT_ID}"
@@ -127,12 +175,12 @@ if [[ "$AUTO_CLEAN" == "true" ]]; then
127
175
  fi
128
176
  fi
129
177
 
130
- # 4. Mark hooks as fired
178
+ # 5. Mark hooks as fired
131
179
  if ! $DRY_RUN; then
132
180
  registry_update "$TASK_ID" "hooks_fired" 'true' 2>/dev/null || true
133
181
  fi
134
182
 
135
- # 5. Log completion
183
+ # 6. Log completion
136
184
  COMPLETION_LOG="${CLAWFORGE_DIR}/registry/completions.jsonl"
137
185
  if ! $DRY_RUN; then
138
186
  ENTRY=$(jq -cn \
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env bash
2
+ # profile.sh — Manage reusable agent profiles
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
6
+ source "${SCRIPT_DIR}/../lib/common.sh"
7
+
8
+ PROFILES_DIR="${HOME}/.clawforge/profiles"
9
+
10
+ usage() {
11
+ cat <<EOF
12
+ Usage: clawforge profile <subcommand> [args]
13
+
14
+ Manage reusable agent profiles (saved parameter presets).
15
+
16
+ Subcommands:
17
+ list List all profiles
18
+ show <name> Show profile details
19
+ create <name> [options] Create a new profile
20
+ delete <name> Delete a profile
21
+ use <name> Print spawn flags for a profile
22
+ --help Show this help
23
+
24
+ Create options:
25
+ --agent <name> Agent: claude or codex
26
+ --model <model> Model to use
27
+ --effort <level> Effort: high, medium, low
28
+ --timeout <minutes> Timeout in minutes
29
+ --auto-clean Enable auto-clean
30
+ --notify Enable notifications
31
+ --routing <strategy> Routing: auto, cheap, quality
32
+
33
+ Examples:
34
+ clawforge profile create fast --agent claude --model claude-haiku-3.5 --timeout 5
35
+ clawforge profile create quality --agent claude --model claude-opus-4 --effort high --notify
36
+ clawforge profile create cheap --agent codex --model gpt-5.2-codex --routing cheap
37
+ clawforge profile use fast
38
+ clawforge sprint --repo . --task "fix bug" $(clawforge profile use fast)
39
+ EOF
40
+ }
41
+
42
+ [[ $# -eq 0 ]] && { usage; exit 0; }
43
+
44
+ mkdir -p "$PROFILES_DIR"
45
+
46
+ case "$1" in
47
+ list)
48
+ echo "── Agent Profiles ──"
49
+ if [[ -z "$(ls -A "$PROFILES_DIR" 2>/dev/null)" ]]; then
50
+ echo "(none — create with: clawforge profile create <name>)"
51
+ exit 0
52
+ fi
53
+ for f in "$PROFILES_DIR"/*.json; do
54
+ [[ -f "$f" ]] || continue
55
+ name=$(basename "$f" .json)
56
+ agent=$(jq -r '.agent // "—"' "$f")
57
+ model=$(jq -r '.model // "—"' "$f")
58
+ printf " %-15s agent=%-8s model=%s\n" "$name" "$agent" "$model"
59
+ done
60
+ ;;
61
+
62
+ show)
63
+ [[ -z "${2:-}" ]] && { log_error "Profile name required"; exit 1; }
64
+ PROFILE_FILE="$PROFILES_DIR/$2.json"
65
+ [[ -f "$PROFILE_FILE" ]] || { log_error "Profile '$2' not found"; exit 1; }
66
+ echo "── Profile: $2 ──"
67
+ jq '.' "$PROFILE_FILE"
68
+ ;;
69
+
70
+ create)
71
+ shift
72
+ [[ -z "${1:-}" ]] && { log_error "Profile name required"; exit 1; }
73
+ PROFILE_NAME="$1"; shift
74
+
75
+ AGENT="" MODEL="" EFFORT="" TIMEOUT="" AUTO_CLEAN=false NOTIFY=false ROUTING=""
76
+ while [[ $# -gt 0 ]]; do
77
+ case "$1" in
78
+ --agent) AGENT="$2"; shift 2 ;;
79
+ --model) MODEL="$2"; shift 2 ;;
80
+ --effort) EFFORT="$2"; shift 2 ;;
81
+ --timeout) TIMEOUT="$2"; shift 2 ;;
82
+ --auto-clean) AUTO_CLEAN=true; shift ;;
83
+ --notify) NOTIFY=true; shift ;;
84
+ --routing) ROUTING="$2"; shift 2 ;;
85
+ *) log_error "Unknown option: $1"; exit 1 ;;
86
+ esac
87
+ done
88
+
89
+ PROFILE_FILE="$PROFILES_DIR/${PROFILE_NAME}.json"
90
+ jq -cn \
91
+ --arg agent "$AGENT" \
92
+ --arg model "$MODEL" \
93
+ --arg effort "$EFFORT" \
94
+ --arg timeout "$TIMEOUT" \
95
+ --argjson autoClean "$AUTO_CLEAN" \
96
+ --argjson notify "$NOTIFY" \
97
+ --arg routing "$ROUTING" \
98
+ '{agent:$agent,model:$model,effort:$effort,timeout:$timeout,autoClean:$autoClean,notify:$notify,routing:$routing} | with_entries(select(.value != "" and .value != null))' \
99
+ > "$PROFILE_FILE"
100
+
101
+ echo "Created profile '$PROFILE_NAME' at $PROFILE_FILE"
102
+ jq '.' "$PROFILE_FILE"
103
+ ;;
104
+
105
+ delete)
106
+ [[ -z "${2:-}" ]] && { log_error "Profile name required"; exit 1; }
107
+ PROFILE_FILE="$PROFILES_DIR/$2.json"
108
+ [[ -f "$PROFILE_FILE" ]] || { log_error "Profile '$2' not found"; exit 1; }
109
+ rm "$PROFILE_FILE"
110
+ echo "Deleted profile '$2'"
111
+ ;;
112
+
113
+ use)
114
+ [[ -z "${2:-}" ]] && { log_error "Profile name required"; exit 1; }
115
+ PROFILE_FILE="$PROFILES_DIR/$2.json"
116
+ [[ -f "$PROFILE_FILE" ]] || { log_error "Profile '$2' not found"; exit 1; }
117
+
118
+ FLAGS=""
119
+ agent=$(jq -r '.agent // empty' "$PROFILE_FILE")
120
+ model=$(jq -r '.model // empty' "$PROFILE_FILE")
121
+ effort=$(jq -r '.effort // empty' "$PROFILE_FILE")
122
+ timeout=$(jq -r '.timeout // empty' "$PROFILE_FILE")
123
+ auto_clean=$(jq -r '.autoClean // false' "$PROFILE_FILE")
124
+ notify=$(jq -r '.notify // false' "$PROFILE_FILE")
125
+
126
+ [[ -n "$agent" ]] && FLAGS+="--agent $agent "
127
+ [[ -n "$model" ]] && FLAGS+="--model $model "
128
+ [[ -n "$effort" ]] && FLAGS+="--effort $effort "
129
+ [[ -n "$timeout" ]] && FLAGS+="--timeout $timeout "
130
+ [[ "$auto_clean" == "true" ]] && FLAGS+="--auto-clean "
131
+ [[ "$notify" == "true" ]] && FLAGS+="--notify "
132
+
133
+ echo "$FLAGS"
134
+ ;;
135
+
136
+ --help|-h) usage ;;
137
+ *) log_error "Unknown subcommand: $1"; usage; exit 1 ;;
138
+ esac