@pjmendonca/devflow 1.9.0 → 1.10.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 +11 -1
- package/README.md +50 -48
- package/bin/create-devflow.js +140 -0
- package/lib/python-check.js +5 -5
- package/package.json +2 -1
- package/tooling/.automation/agents/dev.md +2 -2
- package/tooling/.automation/agents/reviewer.md +8 -8
- package/tooling/.automation/agents/sm.md +1 -1
- package/tooling/.automation/memory/knowledge/kg_integration-test.json +137 -1
- package/tooling/.automation/memory/knowledge/kg_test-story.json +438 -2
- package/tooling/.automation/memory/shared/shared_integration-test.json +25 -1
- package/tooling/.automation/memory/shared/shared_test-story.json +73 -1
- package/tooling/.automation/overrides/templates/reviewer/mentoring-reviewer.yaml +5 -5
- package/tooling/docs/DOC-STANDARD.md +21 -21
- package/tooling/docs/templates/bug-report.md +1 -1
- package/tooling/scripts/context_checkpoint.py +16 -16
- package/tooling/scripts/create-persona.py +7 -7
- package/tooling/scripts/create-persona.sh +4 -4
- package/tooling/scripts/init-project-workflow.sh +19 -19
- package/tooling/scripts/lib/__init__.py +1 -1
- package/tooling/scripts/lib/agent_handoff.py +4 -6
- package/tooling/scripts/lib/agent_router.py +6 -6
- package/tooling/scripts/lib/checkpoint-integration.sh +14 -14
- package/tooling/scripts/lib/claude-cli.sh +50 -50
- package/tooling/scripts/lib/cost_tracker.py +4 -4
- package/tooling/scripts/lib/errors.py +9 -9
- package/tooling/scripts/lib/pair_programming.py +5 -5
- package/tooling/scripts/lib/shared_memory.py +4 -4
- package/tooling/scripts/lib/swarm_orchestrator.py +18 -18
- package/tooling/scripts/new-doc.sh +12 -12
- package/tooling/scripts/personalize_agent.py +4 -4
- package/tooling/scripts/rollback-migration.sh +4 -4
- package/tooling/scripts/run-collab.ps1 +2 -2
- package/tooling/scripts/run-collab.py +13 -13
- package/tooling/scripts/run-story.py +1 -1
- package/tooling/scripts/run-story.sh +20 -20
- package/tooling/scripts/setup-checkpoint-service.sh +4 -4
- package/tooling/scripts/tech-debt-tracker.py +12 -12
- package/tooling/scripts/update_version.py +10 -10
- package/tooling/scripts/validate-overrides.py +10 -12
- package/tooling/scripts/validate-overrides.sh +7 -7
- package/tooling/scripts/validate_setup.py +8 -8
|
@@ -18,11 +18,11 @@ start_checkpoint_monitor() {
|
|
|
18
18
|
local session_id="${2:-auto}"
|
|
19
19
|
|
|
20
20
|
if [[ ! -f "$CHECKPOINT_SCRIPT" ]]; then
|
|
21
|
-
echo "
|
|
21
|
+
echo " Checkpoint script not found, skipping monitoring"
|
|
22
22
|
return 1
|
|
23
23
|
fi
|
|
24
24
|
|
|
25
|
-
echo "
|
|
25
|
+
echo " Starting context checkpoint monitor..."
|
|
26
26
|
echo " Watching: $log_file"
|
|
27
27
|
|
|
28
28
|
# Start monitor in background
|
|
@@ -34,7 +34,7 @@ start_checkpoint_monitor() {
|
|
|
34
34
|
local monitor_pid=$!
|
|
35
35
|
echo "$monitor_pid" > "${log_file}.checkpoint.pid"
|
|
36
36
|
|
|
37
|
-
echo "
|
|
37
|
+
echo " Checkpoint monitor started (PID: $monitor_pid)"
|
|
38
38
|
return 0
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -48,10 +48,10 @@ stop_checkpoint_monitor() {
|
|
|
48
48
|
if [[ -f "$pid_file" ]]; then
|
|
49
49
|
local pid=$(cat "$pid_file")
|
|
50
50
|
if kill -0 "$pid" 2>/dev/null; then
|
|
51
|
-
echo "
|
|
51
|
+
echo " Stopping checkpoint monitor (PID: $pid)"
|
|
52
52
|
kill "$pid" 2>/dev/null || true
|
|
53
53
|
rm -f "$pid_file"
|
|
54
|
-
echo "
|
|
54
|
+
echo " Checkpoint monitor stopped"
|
|
55
55
|
else
|
|
56
56
|
rm -f "$pid_file"
|
|
57
57
|
fi
|
|
@@ -65,7 +65,7 @@ create_story_checkpoint() {
|
|
|
65
65
|
local story_key="$1"
|
|
66
66
|
local reason="${2:-manual}"
|
|
67
67
|
|
|
68
|
-
echo "
|
|
68
|
+
echo " Creating checkpoint for story: $story_key"
|
|
69
69
|
|
|
70
70
|
python3 "$CHECKPOINT_SCRIPT" \
|
|
71
71
|
--checkpoint \
|
|
@@ -110,13 +110,13 @@ resume_from_checkpoint() {
|
|
|
110
110
|
local checkpoint_file=$(get_latest_checkpoint "$story_key")
|
|
111
111
|
|
|
112
112
|
if [[ -z "$checkpoint_file" ]]; then
|
|
113
|
-
echo "
|
|
113
|
+
echo " No checkpoint found for story: $story_key"
|
|
114
114
|
return 1
|
|
115
115
|
fi
|
|
116
116
|
|
|
117
117
|
local checkpoint_id=$(basename "$checkpoint_file" .json)
|
|
118
118
|
|
|
119
|
-
echo "
|
|
119
|
+
echo " Resuming from checkpoint: $checkpoint_id"
|
|
120
120
|
|
|
121
121
|
python3 "$CHECKPOINT_SCRIPT" \
|
|
122
122
|
--resume "$checkpoint_id"
|
|
@@ -130,13 +130,13 @@ resume_from_checkpoint() {
|
|
|
130
130
|
cleanup_old_checkpoints() {
|
|
131
131
|
local keep_count="${1:-10}"
|
|
132
132
|
|
|
133
|
-
echo "
|
|
133
|
+
echo " Cleaning up old checkpoints (keeping last $keep_count)..."
|
|
134
134
|
|
|
135
135
|
local checkpoints=$(find "$CHECKPOINT_DIR" -name "checkpoint_*.json" | sort -r)
|
|
136
136
|
local total=$(echo "$checkpoints" | wc -l | tr -d ' ')
|
|
137
137
|
|
|
138
138
|
if [[ $total -le $keep_count ]]; then
|
|
139
|
-
echo "
|
|
139
|
+
echo " No cleanup needed ($total checkpoints)"
|
|
140
140
|
return 0
|
|
141
141
|
fi
|
|
142
142
|
|
|
@@ -148,7 +148,7 @@ cleanup_old_checkpoints() {
|
|
|
148
148
|
rm -f "$file" "$summary_file"
|
|
149
149
|
done
|
|
150
150
|
|
|
151
|
-
echo "
|
|
151
|
+
echo " Deleted $delete_count old checkpoints"
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
################################################################################
|
|
@@ -164,9 +164,9 @@ log_checkpoint_info() {
|
|
|
164
164
|
═══════════════════════════════════════════════════════════════
|
|
165
165
|
|
|
166
166
|
Thresholds:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
Warning: 75% - Log notification
|
|
168
|
+
Critical: 85% - Auto-checkpoint created
|
|
169
|
+
Emergency: 95% - Force checkpoint + alert
|
|
170
170
|
|
|
171
171
|
Checkpoint directory: $CHECKPOINT_DIR
|
|
172
172
|
|
|
@@ -163,11 +163,11 @@ invoke_sm_story_context() {
|
|
|
163
163
|
# Show persona switch
|
|
164
164
|
print_persona_banner "SM (Scrum Master)" "Story Context Creation & Planning" "\033[1;33m" "$model"
|
|
165
165
|
|
|
166
|
-
echo "
|
|
166
|
+
echo "> Creating story context for: $story_key"
|
|
167
167
|
|
|
168
168
|
# Check if story file exists
|
|
169
169
|
if [[ ! -f "$story_file" ]]; then
|
|
170
|
-
echo "
|
|
170
|
+
echo " Story file not found: $story_file"
|
|
171
171
|
return 1
|
|
172
172
|
fi
|
|
173
173
|
|
|
@@ -218,21 +218,21 @@ invoke_dev_story() {
|
|
|
218
218
|
# Show persona switch
|
|
219
219
|
print_persona_banner "DEV (Developer)" "Story Implementation & Coding" "\033[1;32m" "$model"
|
|
220
220
|
|
|
221
|
-
echo "
|
|
221
|
+
echo "> Implementing story: $story_key"
|
|
222
222
|
|
|
223
223
|
# Check required files
|
|
224
224
|
if [[ ! -f "$story_file" ]]; then
|
|
225
|
-
echo "
|
|
225
|
+
echo " Story file not found: $story_file"
|
|
226
226
|
return 1
|
|
227
227
|
fi
|
|
228
228
|
|
|
229
229
|
if [[ ! -f "$context_file" ]]; then
|
|
230
|
-
echo "
|
|
230
|
+
echo " Context file not found: $context_file"
|
|
231
231
|
return 1
|
|
232
232
|
fi
|
|
233
233
|
|
|
234
234
|
# Pre-flight context check
|
|
235
|
-
echo "
|
|
235
|
+
echo " Checking context feasibility..."
|
|
236
236
|
check_context_feasibility "$story_file" "$context_file"
|
|
237
237
|
echo ""
|
|
238
238
|
|
|
@@ -310,10 +310,10 @@ invoke_sm_code_review() {
|
|
|
310
310
|
# Show persona switch
|
|
311
311
|
print_persona_banner "SM (Scrum Master)" "Code Review & Quality Assurance" "\033[1;35m" "$model"
|
|
312
312
|
|
|
313
|
-
echo "
|
|
313
|
+
echo "> Reviewing implementation: $story_key"
|
|
314
314
|
|
|
315
315
|
if [[ ! -f "$story_file" ]]; then
|
|
316
|
-
echo "
|
|
316
|
+
echo " Story file not found: $story_file"
|
|
317
317
|
return 1
|
|
318
318
|
fi
|
|
319
319
|
|
|
@@ -392,10 +392,10 @@ invoke_adversarial_review() {
|
|
|
392
392
|
# Show persona switch
|
|
393
393
|
print_persona_banner "REVIEWER (Adversarial)" "Critical Code Analysis" "\033[1;31m" "$model"
|
|
394
394
|
|
|
395
|
-
echo "
|
|
395
|
+
echo "> Running adversarial review: $story_key"
|
|
396
396
|
|
|
397
397
|
if [[ ! -f "$story_file" ]]; then
|
|
398
|
-
echo "
|
|
398
|
+
echo " Story file not found: $story_file"
|
|
399
399
|
return 1
|
|
400
400
|
fi
|
|
401
401
|
|
|
@@ -451,7 +451,7 @@ invoke_sm_draft_story() {
|
|
|
451
451
|
# Show persona switch
|
|
452
452
|
print_persona_banner "SM (Scrum Master)" "Story Drafting & Specification" "\033[1;33m" "$model"
|
|
453
453
|
|
|
454
|
-
echo "
|
|
454
|
+
echo "> Drafting story: $story_key"
|
|
455
455
|
|
|
456
456
|
# Extract epic number from story key (e.g., 3-5 -> 3)
|
|
457
457
|
local epic_num=$(echo "$story_key" | cut -d'-' -f1)
|
|
@@ -502,7 +502,7 @@ invoke_ba_requirements() {
|
|
|
502
502
|
# Show persona switch
|
|
503
503
|
print_persona_banner "BA (Business Analyst)" "Requirements Analysis & User Stories" "\033[1;34m" "$model"
|
|
504
504
|
|
|
505
|
-
echo "
|
|
505
|
+
echo "> Analyzing requirements for: $feature_name"
|
|
506
506
|
|
|
507
507
|
mkdir -p "$PROJECT_ROOT/docs/requirements"
|
|
508
508
|
|
|
@@ -544,7 +544,7 @@ invoke_architect_design() {
|
|
|
544
544
|
# Show persona switch
|
|
545
545
|
print_persona_banner "ARCHITECT" "Technical Design & Architecture" "\033[1;36m" "$model"
|
|
546
546
|
|
|
547
|
-
echo "
|
|
547
|
+
echo "> Creating technical specification for: $feature_name"
|
|
548
548
|
|
|
549
549
|
local prompt="Create a technical specification for: $feature_name
|
|
550
550
|
|
|
@@ -586,7 +586,7 @@ invoke_pm_epic() {
|
|
|
586
586
|
# Show persona switch
|
|
587
587
|
print_persona_banner "PM (Product Manager)" "Epic Planning & Prioritization" "\033[1;31m" "$model"
|
|
588
588
|
|
|
589
|
-
echo "
|
|
589
|
+
echo "> Planning epic: $epic_num"
|
|
590
590
|
|
|
591
591
|
local prompt="Plan and refine Epic $epic_num
|
|
592
592
|
|
|
@@ -627,7 +627,7 @@ invoke_writer_docs() {
|
|
|
627
627
|
# Show persona switch
|
|
628
628
|
print_persona_banner "WRITER (Technical Writer)" "Documentation & Content Creation" "\033[1;37m" "$model"
|
|
629
629
|
|
|
630
|
-
echo "
|
|
630
|
+
echo "> Creating documentation: $doc_type for $subject"
|
|
631
631
|
|
|
632
632
|
local prompt="Create $doc_type documentation for: $subject
|
|
633
633
|
|
|
@@ -670,7 +670,7 @@ execute_workflow_background() {
|
|
|
670
670
|
|
|
671
671
|
local log_file="$LOGS_DIR/${story_key}-${workflow_name}.log"
|
|
672
672
|
|
|
673
|
-
echo "
|
|
673
|
+
echo "> Starting background workflow: $workflow_name for $story_key"
|
|
674
674
|
|
|
675
675
|
# Execute in background
|
|
676
676
|
(
|
|
@@ -719,16 +719,16 @@ update_story_status() {
|
|
|
719
719
|
local new_status="$2"
|
|
720
720
|
local sprint_status_file="$PROJECT_ROOT/docs/sprint-status.yaml"
|
|
721
721
|
|
|
722
|
-
echo "
|
|
722
|
+
echo "> Updating sprint status: $story_key -> $new_status"
|
|
723
723
|
|
|
724
724
|
if [[ ! -f "$sprint_status_file" ]]; then
|
|
725
|
-
echo "
|
|
725
|
+
echo " Sprint status file not found: $sprint_status_file"
|
|
726
726
|
return 1
|
|
727
727
|
fi
|
|
728
728
|
|
|
729
729
|
# Check if story exists in file
|
|
730
730
|
if ! grep -q "^ $story_key:" "$sprint_status_file"; then
|
|
731
|
-
echo "
|
|
731
|
+
echo " Story $story_key not found in sprint-status.yaml"
|
|
732
732
|
return 1
|
|
733
733
|
fi
|
|
734
734
|
|
|
@@ -742,7 +742,7 @@ update_story_status() {
|
|
|
742
742
|
fi
|
|
743
743
|
|
|
744
744
|
if [[ $? -eq 0 ]]; then
|
|
745
|
-
echo "
|
|
745
|
+
echo " Status updated: $story_key -> $new_status"
|
|
746
746
|
|
|
747
747
|
# Update the 'updated' timestamp
|
|
748
748
|
local today=$(date +%Y-%m-%d)
|
|
@@ -756,7 +756,7 @@ update_story_status() {
|
|
|
756
756
|
|
|
757
757
|
return 0
|
|
758
758
|
else
|
|
759
|
-
echo "
|
|
759
|
+
echo " Failed to update status"
|
|
760
760
|
return 1
|
|
761
761
|
fi
|
|
762
762
|
}
|
|
@@ -770,13 +770,13 @@ auto_commit_changes() {
|
|
|
770
770
|
local story_key="$1"
|
|
771
771
|
local story_file="$STORIES_DIR/${story_key}.md"
|
|
772
772
|
|
|
773
|
-
echo "
|
|
773
|
+
echo "> Auto-committing changes..."
|
|
774
774
|
|
|
775
775
|
# Check if there are changes to commit
|
|
776
776
|
cd "$PROJECT_ROOT" || return 1
|
|
777
777
|
|
|
778
778
|
if ! git diff --quiet || ! git diff --cached --quiet || [[ -n $(git ls-files --others --exclude-standard) ]]; then
|
|
779
|
-
echo "
|
|
779
|
+
echo " Detected changes to commit"
|
|
780
780
|
|
|
781
781
|
# Extract story title from story file
|
|
782
782
|
local story_title=""
|
|
@@ -796,7 +796,7 @@ Automated implementation via Claude Code CLI
|
|
|
796
796
|
|
|
797
797
|
Story: $story_key
|
|
798
798
|
|
|
799
|
-
|
|
799
|
+
Generated with [Claude Code](https://claude.com/claude-code)
|
|
800
800
|
|
|
801
801
|
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
|
802
802
|
|
|
@@ -804,15 +804,15 @@ Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
|
|
804
804
|
git commit -m "$commit_msg"
|
|
805
805
|
|
|
806
806
|
if [[ $? -eq 0 ]]; then
|
|
807
|
-
echo "
|
|
808
|
-
echo "
|
|
807
|
+
echo " Changes committed successfully"
|
|
808
|
+
echo " Commit: $(git rev-parse --short HEAD)"
|
|
809
809
|
return 0
|
|
810
810
|
else
|
|
811
|
-
echo "
|
|
811
|
+
echo " Commit failed or no changes to commit"
|
|
812
812
|
return 1
|
|
813
813
|
fi
|
|
814
814
|
else
|
|
815
|
-
echo "
|
|
815
|
+
echo "No changes to commit"
|
|
816
816
|
return 0
|
|
817
817
|
fi
|
|
818
818
|
}
|
|
@@ -823,13 +823,13 @@ auto_create_pr() {
|
|
|
823
823
|
local story_file="$STORIES_DIR/${story_key}.md"
|
|
824
824
|
local branch_name="feature/$story_key"
|
|
825
825
|
|
|
826
|
-
echo "
|
|
826
|
+
echo "> Creating pull request..."
|
|
827
827
|
|
|
828
828
|
cd "$PROJECT_ROOT" || return 1
|
|
829
829
|
|
|
830
830
|
# Check if gh CLI is available
|
|
831
831
|
if ! command -v gh &> /dev/null; then
|
|
832
|
-
echo "
|
|
832
|
+
echo " GitHub CLI (gh) not found. Skipping PR creation."
|
|
833
833
|
echo " Install with: brew install gh"
|
|
834
834
|
return 1
|
|
835
835
|
fi
|
|
@@ -851,12 +851,12 @@ $(cat "$story_file")
|
|
|
851
851
|
|
|
852
852
|
---
|
|
853
853
|
|
|
854
|
-
|
|
854
|
+
Auto-generated via Claude Code CLI automation"
|
|
855
855
|
else
|
|
856
856
|
pr_title="$story_key implementation"
|
|
857
857
|
pr_body="Story: $story_key
|
|
858
858
|
|
|
859
|
-
|
|
859
|
+
Auto-generated via Claude Code CLI automation"
|
|
860
860
|
fi
|
|
861
861
|
|
|
862
862
|
# Create PR
|
|
@@ -867,10 +867,10 @@ $(cat "$story_file")
|
|
|
867
867
|
--head "$current_branch" 2>&1
|
|
868
868
|
|
|
869
869
|
if [[ $? -eq 0 ]]; then
|
|
870
|
-
echo "
|
|
870
|
+
echo " Pull request created"
|
|
871
871
|
return 0
|
|
872
872
|
else
|
|
873
|
-
echo "
|
|
873
|
+
echo " PR creation failed. You can create it manually with:"
|
|
874
874
|
echo " gh pr create --title \"$pr_title\" --base main"
|
|
875
875
|
return 1
|
|
876
876
|
fi
|
|
@@ -890,27 +890,27 @@ run_full_pipeline() {
|
|
|
890
890
|
# Phase 1: Create context if needed
|
|
891
891
|
local context_file="$STORIES_DIR/${story_key}.context.xml"
|
|
892
892
|
if [[ ! -f "$context_file" ]]; then
|
|
893
|
-
echo "
|
|
893
|
+
echo "> Phase 1: Creating story context..."
|
|
894
894
|
invoke_sm_story_context "$story_key"
|
|
895
895
|
if [[ $? -ne 0 ]]; then
|
|
896
|
-
echo "
|
|
896
|
+
echo " Context creation failed"
|
|
897
897
|
return 1
|
|
898
898
|
fi
|
|
899
|
-
echo "
|
|
899
|
+
echo " Context created"
|
|
900
900
|
echo ""
|
|
901
901
|
else
|
|
902
|
-
echo "
|
|
902
|
+
echo "[OK] Context already exists, skipping..."
|
|
903
903
|
echo ""
|
|
904
904
|
fi
|
|
905
905
|
|
|
906
906
|
# Phase 2: Development
|
|
907
|
-
echo "
|
|
907
|
+
echo "> Phase 2: Implementing story..."
|
|
908
908
|
invoke_dev_story "$story_key"
|
|
909
909
|
if [[ $? -ne 0 ]]; then
|
|
910
|
-
echo "
|
|
910
|
+
echo " Development failed"
|
|
911
911
|
return 1
|
|
912
912
|
fi
|
|
913
|
-
echo "
|
|
913
|
+
echo " Development complete"
|
|
914
914
|
echo ""
|
|
915
915
|
|
|
916
916
|
# Phase 2.5: Update status to 'review'
|
|
@@ -930,13 +930,13 @@ run_full_pipeline() {
|
|
|
930
930
|
fi
|
|
931
931
|
|
|
932
932
|
# Phase 3: Code review
|
|
933
|
-
echo "
|
|
933
|
+
echo "> Phase 3: Code review..."
|
|
934
934
|
invoke_sm_code_review "$story_key"
|
|
935
935
|
if [[ $? -ne 0 ]]; then
|
|
936
|
-
echo "
|
|
936
|
+
echo " Code review failed"
|
|
937
937
|
return 1
|
|
938
938
|
fi
|
|
939
|
-
echo "
|
|
939
|
+
echo " Code review complete"
|
|
940
940
|
echo ""
|
|
941
941
|
|
|
942
942
|
# Phase 4: Update status to 'done' (if review passed)
|
|
@@ -963,7 +963,7 @@ invoke_bugfix() {
|
|
|
963
963
|
# Show persona switch
|
|
964
964
|
print_persona_banner "MAINTAINER" "Bug Investigation & Fix" "\033[1;31m" "$model"
|
|
965
965
|
|
|
966
|
-
echo "
|
|
966
|
+
echo "> Investigating and fixing bug: $bug_id"
|
|
967
967
|
|
|
968
968
|
# Build prompt based on whether bug file exists
|
|
969
969
|
local prompt=""
|
|
@@ -1030,7 +1030,7 @@ invoke_refactor() {
|
|
|
1030
1030
|
# Show persona switch
|
|
1031
1031
|
print_persona_banner "MAINTAINER" "Code Refactoring & Improvement" "\033[1;35m" "$model"
|
|
1032
1032
|
|
|
1033
|
-
echo "
|
|
1033
|
+
echo "> Refactoring: $refactor_id"
|
|
1034
1034
|
|
|
1035
1035
|
local prompt=""
|
|
1036
1036
|
if [[ -f "$refactor_file" ]]; then
|
|
@@ -1095,7 +1095,7 @@ invoke_investigate() {
|
|
|
1095
1095
|
# Show persona switch
|
|
1096
1096
|
print_persona_banner "MAINTAINER" "Codebase Investigation & Analysis" "\033[1;36m" "$model"
|
|
1097
1097
|
|
|
1098
|
-
echo "
|
|
1098
|
+
echo "> Investigating: $topic"
|
|
1099
1099
|
|
|
1100
1100
|
local prompt="INVESTIGATE AND DOCUMENT: $topic
|
|
1101
1101
|
|
|
@@ -1141,7 +1141,7 @@ invoke_quickfix() {
|
|
|
1141
1141
|
# Show persona switch
|
|
1142
1142
|
print_persona_banner "MAINTAINER" "Quick Fix" "\033[1;33m" "$model"
|
|
1143
1143
|
|
|
1144
|
-
echo "
|
|
1144
|
+
echo "> Quick fix: $description"
|
|
1145
1145
|
|
|
1146
1146
|
local prompt="QUICK FIX: $description
|
|
1147
1147
|
|
|
@@ -1178,7 +1178,7 @@ invoke_migrate() {
|
|
|
1178
1178
|
# Show persona switch
|
|
1179
1179
|
print_persona_banner "MAINTAINER" "Migration & Upgrade" "\033[1;34m" "$model"
|
|
1180
1180
|
|
|
1181
|
-
echo "
|
|
1181
|
+
echo "> Running migration: $migration_id"
|
|
1182
1182
|
|
|
1183
1183
|
local prompt=""
|
|
1184
1184
|
if [[ -f "$migration_file" ]]; then
|
|
@@ -1238,7 +1238,7 @@ invoke_tech_debt() {
|
|
|
1238
1238
|
# Show persona switch
|
|
1239
1239
|
print_persona_banner "MAINTAINER" "Technical Debt Resolution" "\033[1;35m" "$model"
|
|
1240
1240
|
|
|
1241
|
-
echo "
|
|
1241
|
+
echo "> Resolving technical debt: $debt_id"
|
|
1242
1242
|
|
|
1243
1243
|
local prompt=""
|
|
1244
1244
|
if [[ -f "$debt_file" ]]; then
|
|
@@ -353,7 +353,7 @@ class CostTracker:
|
|
|
353
353
|
False,
|
|
354
354
|
"stop",
|
|
355
355
|
(
|
|
356
|
-
f"
|
|
356
|
+
f" BUDGET EXCEEDED - ${total_cost:.2f} spent of ${self.budget_limit_usd:.2f} limit. "
|
|
357
357
|
f"Action required: Increase budget or stop operations. "
|
|
358
358
|
f"Story: {self.story_key}"
|
|
359
359
|
),
|
|
@@ -363,7 +363,7 @@ class CostTracker:
|
|
|
363
363
|
True,
|
|
364
364
|
"critical",
|
|
365
365
|
(
|
|
366
|
-
f"
|
|
366
|
+
f"CRITICAL: {usage_pct * 100:.0f}% of budget used (${total_cost:.2f}). "
|
|
367
367
|
f"Only ${remaining:.2f} remaining. Consider wrapping up soon."
|
|
368
368
|
),
|
|
369
369
|
)
|
|
@@ -372,7 +372,7 @@ class CostTracker:
|
|
|
372
372
|
True,
|
|
373
373
|
"warning",
|
|
374
374
|
(
|
|
375
|
-
f"
|
|
375
|
+
f"WARNING: {usage_pct * 100:.0f}% of budget used (${total_cost:.2f}). "
|
|
376
376
|
f"${remaining:.2f} remaining of ${self.budget_limit_usd:.2f} budget."
|
|
377
377
|
),
|
|
378
378
|
)
|
|
@@ -380,7 +380,7 @@ class CostTracker:
|
|
|
380
380
|
return (
|
|
381
381
|
True,
|
|
382
382
|
"ok",
|
|
383
|
-
f"
|
|
383
|
+
f"Budget OK: {usage_pct * 100:.0f}% used (${total_cost:.2f}/${self.budget_limit_usd:.2f})",
|
|
384
384
|
)
|
|
385
385
|
|
|
386
386
|
def get_session_summary(self) -> dict:
|
|
@@ -100,7 +100,7 @@ class CostTrackingError(Exception):
|
|
|
100
100
|
parts.append(f" Agent: {self.context.agent}")
|
|
101
101
|
|
|
102
102
|
if self.suggestion:
|
|
103
|
-
parts.append(f"\n
|
|
103
|
+
parts.append(f"\n [TIP] Suggestion: {self.suggestion}")
|
|
104
104
|
|
|
105
105
|
if self.cause:
|
|
106
106
|
parts.append(f"\n Caused by: {type(self.cause).__name__}: {self.cause}")
|
|
@@ -235,7 +235,7 @@ def format_error_for_user(error: Exception, verbose: bool = False) -> str:
|
|
|
235
235
|
|
|
236
236
|
# Header
|
|
237
237
|
lines.append("━" * 60)
|
|
238
|
-
lines.append("
|
|
238
|
+
lines.append("[ERROR] Error Occurred")
|
|
239
239
|
lines.append("━" * 60)
|
|
240
240
|
|
|
241
241
|
if isinstance(error, CostTrackingError):
|
|
@@ -244,7 +244,7 @@ def format_error_for_user(error: Exception, verbose: bool = False) -> str:
|
|
|
244
244
|
lines.append(f"\n{type(error).__name__}: {error}")
|
|
245
245
|
|
|
246
246
|
if verbose:
|
|
247
|
-
lines.append("\n
|
|
247
|
+
lines.append("\n[STACK TRACE]:")
|
|
248
248
|
lines.append(traceback.format_exc())
|
|
249
249
|
|
|
250
250
|
lines.append("\n" + "━" * 60)
|
|
@@ -341,12 +341,12 @@ class ErrorReporter:
|
|
|
341
341
|
lines = []
|
|
342
342
|
|
|
343
343
|
if self.errors:
|
|
344
|
-
lines.append(f"\n
|
|
344
|
+
lines.append(f"\n[ERROR] {len(self.errors)} Error(s):")
|
|
345
345
|
for i, (error, context) in enumerate(self.errors, 1):
|
|
346
346
|
lines.append(f" {i}. [{context}] {error}")
|
|
347
347
|
|
|
348
348
|
if self.warnings:
|
|
349
|
-
lines.append(f"\n
|
|
349
|
+
lines.append(f"\n[WARNING] {len(self.warnings)} Warning(s):")
|
|
350
350
|
for i, (message, context) in enumerate(self.warnings, 1):
|
|
351
351
|
lines.append(f" {i}. [{context}] {message}")
|
|
352
352
|
|
|
@@ -373,22 +373,22 @@ def log_debug(message: str, **kwargs):
|
|
|
373
373
|
|
|
374
374
|
def log_info(message: str):
|
|
375
375
|
"""Log an info message."""
|
|
376
|
-
print(f"
|
|
376
|
+
print(f"[INFO] {message}")
|
|
377
377
|
|
|
378
378
|
|
|
379
379
|
def log_warning(message: str):
|
|
380
380
|
"""Log a warning message."""
|
|
381
|
-
print(f"
|
|
381
|
+
print(f"[WARNING] {message}", file=sys.stderr)
|
|
382
382
|
|
|
383
383
|
|
|
384
384
|
def log_error(message: str):
|
|
385
385
|
"""Log an error message."""
|
|
386
|
-
print(f"
|
|
386
|
+
print(f"[ERROR] {message}", file=sys.stderr)
|
|
387
387
|
|
|
388
388
|
|
|
389
389
|
def log_success(message: str):
|
|
390
390
|
"""Log a success message."""
|
|
391
|
-
print(f"
|
|
391
|
+
print(f"[OK] {message}")
|
|
392
392
|
|
|
393
393
|
|
|
394
394
|
# Verbose mode flag
|
|
@@ -239,7 +239,7 @@ class PairSession:
|
|
|
239
239
|
"""Log a message."""
|
|
240
240
|
if self.config.verbose:
|
|
241
241
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
|
242
|
-
emoji = {"DEV": "
|
|
242
|
+
emoji = {"DEV": "", "REVIEWER": "", "SYSTEM": ""}.get(agent, "•")
|
|
243
243
|
print(f"[{timestamp}] {emoji} [{agent}] {message}")
|
|
244
244
|
|
|
245
245
|
def _invoke_agent(self, agent: str, prompt: str) -> str:
|
|
@@ -378,10 +378,10 @@ Work in small, focused chunks. After each chunk, wait for reviewer feedback.
|
|
|
378
378
|
"## Reviewer Feedback (address these)",
|
|
379
379
|
"",
|
|
380
380
|
"**Issues to Fix:**",
|
|
381
|
-
*[f"-
|
|
381
|
+
*[f"- {issue}" for issue in previous_feedback.must_fix],
|
|
382
382
|
"",
|
|
383
383
|
"**Suggestions:**",
|
|
384
|
-
*[f"-
|
|
384
|
+
*[f"- {sug}" for sug in previous_feedback.suggestions],
|
|
385
385
|
]
|
|
386
386
|
)
|
|
387
387
|
base_prompt += f"\n\n{feedback_text}\n"
|
|
@@ -523,9 +523,9 @@ Work in small, focused chunks. After each chunk, wait for reviewer feedback.
|
|
|
523
523
|
|
|
524
524
|
if exchange.resolved or feedback.approved:
|
|
525
525
|
approved_chunks += 1
|
|
526
|
-
self._log("
|
|
526
|
+
self._log(" Chunk approved!", "SYSTEM")
|
|
527
527
|
else:
|
|
528
|
-
self._log("
|
|
528
|
+
self._log(" Moving on with unresolved issues", "SYSTEM")
|
|
529
529
|
|
|
530
530
|
self.exchanges.append(exchange)
|
|
531
531
|
|
|
@@ -117,7 +117,7 @@ class HandoffSummary:
|
|
|
117
117
|
def to_markdown(self) -> str:
|
|
118
118
|
"""Convert handoff to markdown format."""
|
|
119
119
|
lines = [
|
|
120
|
-
f"## Handoff: {self.from_agent}
|
|
120
|
+
f"## Handoff: {self.from_agent} -> {self.to_agent}",
|
|
121
121
|
"",
|
|
122
122
|
f"**Story**: {self.story_key}",
|
|
123
123
|
f"**Time**: {self.timestamp}",
|
|
@@ -136,11 +136,11 @@ class HandoffSummary:
|
|
|
136
136
|
if self.blockers_resolved:
|
|
137
137
|
lines.append("### Blockers Resolved")
|
|
138
138
|
for blocker in self.blockers_resolved:
|
|
139
|
-
lines.append(f"-
|
|
139
|
+
lines.append(f"- {blocker}")
|
|
140
140
|
lines.append("")
|
|
141
141
|
|
|
142
142
|
if self.watch_out_for:
|
|
143
|
-
lines.append("###
|
|
143
|
+
lines.append("### Watch Out For")
|
|
144
144
|
for warning in self.watch_out_for:
|
|
145
145
|
lines.append(f"- {warning}")
|
|
146
146
|
lines.append("")
|
|
@@ -516,7 +516,7 @@ class KnowledgeGraph:
|
|
|
516
516
|
lines.append("### Recent Handoffs")
|
|
517
517
|
for handoff in self.handoffs[-5:]:
|
|
518
518
|
lines.append(
|
|
519
|
-
f"- {handoff.from_agent}
|
|
519
|
+
f"- {handoff.from_agent} -> {handoff.to_agent}: {handoff.summary[:100]}..."
|
|
520
520
|
)
|
|
521
521
|
lines.append("")
|
|
522
522
|
|