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.
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/CHANGELOG.md +37 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/Formula/clawforge.rb +1 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PKG-INFO +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/SKILL.md +12 -1
- clawforge_cli-1.3.0/VERSION +1 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/clawforge +10 -0
- clawforge_cli-1.3.0/bin/completions.sh +68 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/doctor.sh +63 -0
- clawforge_cli-1.3.0/bin/export.sh +125 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/on-complete.sh +51 -3
- clawforge_cli-1.3.0/bin/profile.sh +138 -0
- clawforge_cli-1.3.0/bin/replay.sh +134 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/spawn-agent.sh +37 -1
- clawforge_cli-1.3.0/completions/_clawforge +82 -0
- clawforge_cli-1.3.0/completions/clawforge.bash +60 -0
- clawforge_cli-1.3.0/completions/clawforge.fish +33 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/README.md +1 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/command-reference.md +37 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/package.json +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/pyproject.toml +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/run-all-tests.sh +1 -1
- clawforge_cli-1.3.0/tests/test-dx.sh +145 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-observability.sh +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-power.sh +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-practical.sh +1 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-reliability.sh +1 -1
- clawforge_cli-1.2.0/VERSION +0 -1
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/ci.yml +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/publish-npm.yml +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/publish-pypi.yml +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/update-homebrew.yml +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.github/workflows/version-sync.yml +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/.gitignore +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/LICENSE +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v05.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v06.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/PRD-v07.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/README.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/attach.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/check-agents.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/clean.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/config.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/conflicts.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/cost.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/dashboard.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/diff.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/eval.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/history.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/init.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/learn.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/logs.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/memory.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/merge-helper.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/multi-review.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/notify.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/parse-cost.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/pr.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/resume.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/review-mode.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/review-pr.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/routing.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/scope-task.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/sprint.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/steer.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/stop.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/summary.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/swarm.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/bin/templates.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/clawforge/__init__.py +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/clawforge/cli.py +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/defaults.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/prompt-templates/default.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/config/routing-defaults.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/IMPLEMENTATION-v04.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/PRD-v04.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/PUBLISHING-CHECKLIST.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/RELEASE.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/architecture.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/configuration.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/dashboard.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/evaluation.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/faq.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/fleet-ops.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/getting-started.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/scenarios.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/troubleshooting.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/docs/workflow-modes.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/run-log.example.jsonl +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/run-log.schema.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/evals/scorecard.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/install.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/common.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/bugfix.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/migration.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/refactor.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/security-audit.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/lib/templates/test-coverage.json +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/registry/conflicts.jsonl +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/registry/costs.jsonl +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-ci-loop.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-clean.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-cli.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-conflicts.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-cost.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-dashboard.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-eval.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-foundation.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-history.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-init.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-learn.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-management.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-memory.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-merge.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-modes.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-multi-repo.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-notify.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-openclaw.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-registry.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-review.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-routing.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-scope.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-spawn.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-templates.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-tui.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tests/test-watch.sh +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/PRD.md +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/agent.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/animation.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/dashboard.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/filter.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/go.mod +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/go.sum +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/keybindings.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/main.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/model.go +0 -0
- {clawforge_cli-1.2.0 → clawforge_cli-1.3.0}/tui/steer.go +0 -0
- {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.
|
|
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.
|
|
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.
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|