@pennyfarthing/core 7.6.1 → 7.8.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/README.md +109 -201
- package/package.json +1 -1
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +205 -0
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.js +31 -0
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/update.js +31 -0
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/pennyfarthing-dist/agents/architect.md +48 -53
- package/pennyfarthing-dist/agents/dev.md +74 -164
- package/pennyfarthing-dist/agents/devops.md +44 -39
- package/pennyfarthing-dist/agents/handoff.md +46 -23
- package/pennyfarthing-dist/agents/orchestrator.md +84 -255
- package/pennyfarthing-dist/agents/pm.md +40 -50
- package/pennyfarthing-dist/agents/reviewer-preflight.md +58 -26
- package/pennyfarthing-dist/agents/reviewer.md +107 -298
- package/pennyfarthing-dist/agents/sm-file-summary.md +51 -30
- package/pennyfarthing-dist/agents/sm-finish.md +59 -38
- package/pennyfarthing-dist/agents/sm-handoff.md +40 -33
- package/pennyfarthing-dist/agents/sm-setup.md +122 -45
- package/pennyfarthing-dist/agents/sm.md +204 -545
- package/pennyfarthing-dist/agents/tea.md +77 -146
- package/pennyfarthing-dist/agents/tech-writer.md +43 -24
- package/pennyfarthing-dist/agents/testing-runner.md +73 -30
- package/pennyfarthing-dist/agents/ux-designer.md +39 -25
- package/pennyfarthing-dist/agents/workflow-status-check.md +45 -17
- package/pennyfarthing-dist/commands/benchmark.md +19 -1
- package/pennyfarthing-dist/commands/continue-session.md +1 -1
- package/pennyfarthing-dist/commands/git-cleanup.md +43 -308
- package/pennyfarthing-dist/commands/solo.md +36 -0
- package/pennyfarthing-dist/commands/theme-maker.md +5 -5
- package/pennyfarthing-dist/commands/work.md +1 -1
- package/pennyfarthing-dist/guides/agent-behavior.md +22 -9
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +432 -0
- package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +27 -7
- package/pennyfarthing-dist/guides/scale-levels.md +114 -0
- package/pennyfarthing-dist/guides/xml-tags.md +335 -0
- package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +83 -83
- package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +1 -1
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +11 -11
- package/pennyfarthing-dist/scripts/core/agent-session.sh +13 -7
- package/pennyfarthing-dist/scripts/core/check-context.sh +9 -1
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +13 -2
- package/pennyfarthing-dist/scripts/core/prime.sh +3 -132
- package/pennyfarthing-dist/scripts/core/run.sh +9 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +45 -4
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +32 -7
- package/pennyfarthing-dist/scripts/hooks/__pycache__/question_reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +30 -11
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +80 -23
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +4 -4
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +499 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +7 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +94 -0
- package/pennyfarthing-dist/scripts/jira/README.md +10 -7
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +10 -152
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +14 -4
- package/pennyfarthing-dist/scripts/jira/jira-sync.sh +12 -4
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +11 -99
- package/pennyfarthing-dist/scripts/lib/common.sh +55 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +97 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +13 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +226 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +6 -5
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +319 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +27 -22
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.sh +6 -5
- package/pennyfarthing-dist/scripts/sprint/import_epic_to_future.py +270 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +14 -154
- package/pennyfarthing-dist/scripts/story/size-story.sh +12 -192
- package/pennyfarthing-dist/scripts/story/story-template.sh +12 -156
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +59 -0
- package/pennyfarthing-dist/scripts/test/ground-truth-judge.py +24 -93
- package/pennyfarthing-dist/scripts/test/swebench-judge.py +33 -59
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +8 -6
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +402 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +575 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +502 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +3 -476
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +61 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +13 -0
- package/pennyfarthing-dist/skills/judge/SKILL.md +57 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +52 -16
- package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +4 -22
- package/pennyfarthing-dist/skills/sprint/skill.md +1 -1
- package/pennyfarthing-dist/templates/settings.local.json.template +11 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +83 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-02-categorize.md +116 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-03-execute.md +210 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +88 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +71 -0
- package/pennyfarthing-dist/workflows/git-cleanup.yaml +59 -0
- package/pennyfarthing-dist/guides/XML-TAGS.md +0 -156
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.mjs +0 -380
- package/pennyfarthing-dist/scripts/hooks/tests/question-reflector.test.mjs +0 -545
- package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.mjs +0 -327
- package/pennyfarthing-dist/scripts/jira/jira-bidirectional-sync.test.mjs +0 -503
- package/pennyfarthing-dist/scripts/jira/jira-lib.mjs +0 -443
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.mjs +0 -208
- package/pennyfarthing-dist/scripts/jira/jira-sync.mjs +0 -198
- package/pennyfarthing-dist/scripts/misc/add-short-names.mjs +0 -264
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.mjs +0 -474
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.mjs +0 -377
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.js +0 -492
- /package/pennyfarthing-dist/guides/{AGENT-COORDINATION.md → agent-coordination.md} +0 -0
- /package/pennyfarthing-dist/guides/{HOOKS.md → hooks.md} +0 -0
- /package/pennyfarthing-dist/guides/{PROMPT-PATTERNS.md → prompt-patterns.md} +0 -0
- /package/pennyfarthing-dist/guides/{SESSION-ARTIFACTS.md → session-artifacts.md} +0 -0
|
@@ -13,13 +13,13 @@ theme:
|
|
|
13
13
|
default_humor: enabled
|
|
14
14
|
character_immersion: high
|
|
15
15
|
user_title: Bossmang
|
|
16
|
-
portrait_style: ",
|
|
16
|
+
portrait_style: ", russian constructivist style, bold geometric shapes, red and black color palette, propaganda poster aesthetic, angular compositions, industrial typography influence"
|
|
17
17
|
tier: S
|
|
18
18
|
|
|
19
19
|
agents:
|
|
20
20
|
orchestrator:
|
|
21
21
|
character: The Investigator
|
|
22
|
-
visual: "A gaunt man with hollow cheeks and
|
|
22
|
+
visual: "A gaunt man with hollow cheeks and detective fedora, trench coat silhouette, glowing blue eyes rendered as geometric shapes, stark angular shadows"
|
|
23
23
|
ocean:
|
|
24
24
|
O: 5
|
|
25
25
|
C: 3
|
|
@@ -51,7 +51,7 @@ agents:
|
|
|
51
51
|
shortName: Investigator
|
|
52
52
|
sm:
|
|
53
53
|
character: Camina Drummer
|
|
54
|
-
visual: "A fierce
|
|
54
|
+
visual: "A fierce woman with bold mohawk silhouette, geometric tattoo patterns, captain's jacket rendered in angular blocks, commanding diagonal composition"
|
|
55
55
|
# JOB FAIR OPTIMIZED: Drummer excels at sm coordination
|
|
56
56
|
ocean:
|
|
57
57
|
O: 3 # Belter culture
|
|
@@ -84,7 +84,7 @@ agents:
|
|
|
84
84
|
|
|
85
85
|
tea:
|
|
86
86
|
character: Amos Burton
|
|
87
|
-
visual: "A stocky muscular
|
|
87
|
+
visual: "A stocky muscular figure with shaved head, dead eyes as stark circles, mechanic's jumpsuit in bold flat shapes, industrial worker aesthetic"
|
|
88
88
|
# JOB FAIR OPTIMIZED: Amos excels at testing/breaking things
|
|
89
89
|
ocean:
|
|
90
90
|
O: 2 # Practical focus
|
|
@@ -117,7 +117,7 @@ agents:
|
|
|
117
117
|
|
|
118
118
|
dev:
|
|
119
119
|
character: Naomi Nagata
|
|
120
|
-
visual: "A tall
|
|
120
|
+
visual: "A tall woman with flowing curly hair as dynamic curves, angular features emphasized, engineer holding geometric tablet, diagonal thrust composition"
|
|
121
121
|
# JOB FAIR OPTIMIZED: Naomi excels at implementation
|
|
122
122
|
ocean:
|
|
123
123
|
O: 5 # Engineering genius
|
|
@@ -150,7 +150,7 @@ agents:
|
|
|
150
150
|
|
|
151
151
|
reviewer:
|
|
152
152
|
character: Chrisjen Avasarala
|
|
153
|
-
visual: "An elderly Indian woman with silver hair
|
|
153
|
+
visual: "An elderly Indian woman with silver hair as bold swoops, sari rendered in dramatic angular folds, geometric jewelry shapes, piercing gaze with sharp triangular shadows"
|
|
154
154
|
ocean:
|
|
155
155
|
O: 4
|
|
156
156
|
C: 5
|
|
@@ -182,7 +182,7 @@ agents:
|
|
|
182
182
|
shortName: Avasarala
|
|
183
183
|
architect:
|
|
184
184
|
character: Naomi Nagata (design mode)
|
|
185
|
-
visual: "A tall
|
|
185
|
+
visual: "A tall woman with flowing curly hair, standing at geometric holographic display, clean engineering uniform in flat shapes, contemplative expression with angular highlights"
|
|
186
186
|
ocean:
|
|
187
187
|
O: 5
|
|
188
188
|
C: 5
|
|
@@ -214,7 +214,7 @@ agents:
|
|
|
214
214
|
shortName: Naomi
|
|
215
215
|
pm:
|
|
216
216
|
character: Chrisjen Avasarala (planning mode)
|
|
217
|
-
visual: "An elderly Indian woman with silver hair
|
|
217
|
+
visual: "An elderly Indian woman with silver hair as bold swoops, formal diplomatic attire in angular blocks, geometric earrings, calculating strategic expression with stark shadows"
|
|
218
218
|
ocean:
|
|
219
219
|
O: 4
|
|
220
220
|
C: 5
|
|
@@ -246,7 +246,7 @@ agents:
|
|
|
246
246
|
shortName: Avasarala
|
|
247
247
|
tech-writer:
|
|
248
248
|
character: James Holden
|
|
249
|
-
visual: "A rugged man
|
|
249
|
+
visual: "A rugged man with wavy hair rendered as bold strokes, gray jumpsuit in flat geometric planes, coffee cup as iconic shape, idealistic upward gaze"
|
|
250
250
|
# JOB FAIR OPTIMIZED: Holden excels at documentation/broadcasting
|
|
251
251
|
ocean:
|
|
252
252
|
O: 4 # Idealistic vision
|
|
@@ -279,7 +279,7 @@ agents:
|
|
|
279
279
|
|
|
280
280
|
ux-designer:
|
|
281
281
|
character: Alex Kamal
|
|
282
|
-
visual: "A friendly man with
|
|
282
|
+
visual: "A friendly man with bold mustache silhouette, pilot suit with geometric military patches, warm expression through simplified shapes, circular helmet frame"
|
|
283
283
|
ocean:
|
|
284
284
|
O: 4
|
|
285
285
|
C: 3
|
|
@@ -311,7 +311,7 @@ agents:
|
|
|
311
311
|
shortName: Alex
|
|
312
312
|
devops:
|
|
313
313
|
character: Amos Burton (systems mode)
|
|
314
|
-
visual: "A stocky muscular
|
|
314
|
+
visual: "A stocky muscular figure with shaved head, maintenance jumpsuit in bold flat shapes, geometric tool belt, stoic expression with industrial worker aesthetic"
|
|
315
315
|
ocean:
|
|
316
316
|
O: 2
|
|
317
317
|
C: 4
|
|
@@ -211,16 +211,22 @@ case "$1" in
|
|
|
211
211
|
echo "$2" > "$AGENT_FILE"
|
|
212
212
|
echo "Session: $session_id -> $2"
|
|
213
213
|
|
|
214
|
-
#
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
#
|
|
220
|
-
|
|
214
|
+
# Context loading order (optimized for attention):
|
|
215
|
+
# 1. CLAUDE.md (system prompt - already loaded)
|
|
216
|
+
# 2. Agent definition + behavior guide (loaded by prime.sh FIRST)
|
|
217
|
+
# 3. Persona (output here, AFTER agent definition)
|
|
218
|
+
# 4. Session summary (loaded by prime.sh)
|
|
219
|
+
# 5. Sidecars (loaded by prime.sh LAST)
|
|
220
|
+
|
|
221
|
+
# Auto-prime loads agent definition FIRST (highest attention zone)
|
|
221
222
|
if [[ -f "$PROJECT_ROOT/.pennyfarthing/scripts/prime.sh" ]]; then
|
|
222
223
|
"$PROJECT_ROOT/.pennyfarthing/scripts/prime.sh" --quiet --agent "$2"
|
|
223
224
|
fi
|
|
225
|
+
|
|
226
|
+
# Output persona AFTER agent definition (character voice is supplementary)
|
|
227
|
+
if is_character_voice_enabled; then
|
|
228
|
+
output_persona "$2"
|
|
229
|
+
fi
|
|
224
230
|
;;
|
|
225
231
|
stop)
|
|
226
232
|
# Use provided session ID, fall back to SESSION_ID env var
|
|
@@ -204,9 +204,17 @@ if last_total is not None:
|
|
|
204
204
|
# Use usable percent for status decisions (more accurate for user)
|
|
205
205
|
if usable_pct > warning_threshold:
|
|
206
206
|
print('CONTEXT_STATUS=HIGH')
|
|
207
|
-
print('HANDOFF_MODE=auto')
|
|
208
207
|
else:
|
|
209
208
|
print('CONTEXT_STATUS=OK')
|
|
209
|
+
|
|
210
|
+
# RELAY_MODE: Output for handoff-marker.sh to use
|
|
211
|
+
print(f'RELAY_MODE={str(relay_mode).lower()}')
|
|
212
|
+
|
|
213
|
+
# HANDOFF_MODE: 'auto' if relay_mode enabled, 'ask' otherwise
|
|
214
|
+
# MSSCI-12395: relay_mode controls autohandoff independent of context level
|
|
215
|
+
if relay_mode:
|
|
216
|
+
print('HANDOFF_MODE=auto')
|
|
217
|
+
else:
|
|
210
218
|
print('HANDOFF_MODE=ask')
|
|
211
219
|
|
|
212
220
|
# TirePump: Use CONTEXT_CLEAR (clear + load next agent) when:
|
|
@@ -48,6 +48,7 @@ eval "$("$SCRIPT_DIR/check-context.sh" 2>/dev/null)" || true
|
|
|
48
48
|
# Default values if check-context.sh failed
|
|
49
49
|
IS_CYCLIST="${IS_CYCLIST:-false}"
|
|
50
50
|
USE_TIREPUMP="${USE_TIREPUMP:-false}"
|
|
51
|
+
RELAY_MODE="${RELAY_MODE:-false}"
|
|
51
52
|
|
|
52
53
|
# Generate marker based on environment
|
|
53
54
|
if [[ "$IS_ERROR" == "true" ]]; then
|
|
@@ -69,8 +70,18 @@ AGENT_COMMAND:
|
|
|
69
70
|
fallback: "Run \`/${NEXT_AGENT}\` to continue"
|
|
70
71
|
---
|
|
71
72
|
EOF
|
|
73
|
+
elif [[ "$RELAY_MODE" != "true" ]]; then
|
|
74
|
+
# Cyclist + Relay OFF - emit question marker for manual handoff confirmation
|
|
75
|
+
cat <<EOF
|
|
76
|
+
---
|
|
77
|
+
AGENT_COMMAND:
|
|
78
|
+
marker: "<!-- CYCLIST:QUESTION:yesno -->"
|
|
79
|
+
question: "Ready to hand off to /${NEXT_AGENT}?"
|
|
80
|
+
fallback: "Run \`/${NEXT_AGENT}\` to continue"
|
|
81
|
+
---
|
|
82
|
+
EOF
|
|
72
83
|
elif [[ "$USE_TIREPUMP" == "true" ]]; then
|
|
73
|
-
# Cyclist +
|
|
84
|
+
# Cyclist + Relay ON + high context - context clear marker
|
|
74
85
|
cat <<EOF
|
|
75
86
|
---
|
|
76
87
|
AGENT_COMMAND:
|
|
@@ -79,7 +90,7 @@ AGENT_COMMAND:
|
|
|
79
90
|
---
|
|
80
91
|
EOF
|
|
81
92
|
else
|
|
82
|
-
# Cyclist
|
|
93
|
+
# Cyclist + Relay ON + low context - handoff marker
|
|
83
94
|
cat <<EOF
|
|
84
95
|
---
|
|
85
96
|
AGENT_COMMAND:
|
|
@@ -1,136 +1,7 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
2
|
# prime.sh - Load essential project context at agent activation
|
|
3
3
|
# Usage: prime.sh [--minimal] [--full] [--quiet] [--agent <name>]
|
|
4
4
|
#
|
|
5
|
-
#
|
|
6
|
-
# 1. Sprint summary (current-sprint.yaml key fields)
|
|
7
|
-
# 2. Active session (.session/*-session.md)
|
|
8
|
-
# 3. Agent sidecar (if --agent provided)
|
|
9
|
-
# 4. Agent behavior guide (combined protocols for all agents)
|
|
10
|
-
# 5. Domain docs (--full only)
|
|
5
|
+
# Thin wrapper around python -m pennyfarthing_scripts.prime
|
|
11
6
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
# Load shared functions
|
|
15
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
16
|
-
source "$SCRIPT_DIR/../sprint/sprint-common.sh"
|
|
17
|
-
|
|
18
|
-
# Defaults
|
|
19
|
-
QUIET=false
|
|
20
|
-
MINIMAL=false
|
|
21
|
-
FULL=false
|
|
22
|
-
AGENT_NAME=""
|
|
23
|
-
|
|
24
|
-
# Parse arguments
|
|
25
|
-
while [[ $# -gt 0 ]]; do
|
|
26
|
-
case $1 in
|
|
27
|
-
--quiet) QUIET=true; shift ;;
|
|
28
|
-
--minimal) MINIMAL=true; shift ;;
|
|
29
|
-
--full) FULL=true; shift ;;
|
|
30
|
-
--agent) AGENT_NAME="$2"; shift 2 ;;
|
|
31
|
-
-h|--help)
|
|
32
|
-
echo "Usage: prime.sh [--minimal] [--full] [--quiet] [--agent <name>]"
|
|
33
|
-
echo " --minimal Skip all context (fastest)"
|
|
34
|
-
echo " --full Include domain docs from .claude/project/"
|
|
35
|
-
echo " --quiet Suppress section headers"
|
|
36
|
-
echo " --agent <name> Load agent's sidecar patterns"
|
|
37
|
-
exit 0
|
|
38
|
-
;;
|
|
39
|
-
*) shift ;;
|
|
40
|
-
esac
|
|
41
|
-
done
|
|
42
|
-
|
|
43
|
-
# Helper to print headers (respects --quiet)
|
|
44
|
-
print_header() {
|
|
45
|
-
if [[ "$QUIET" != "true" ]]; then
|
|
46
|
-
echo ""
|
|
47
|
-
echo "# $1"
|
|
48
|
-
fi
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
# CLAUDE.md is already loaded by Claude Code system prompt - skip it
|
|
52
|
-
|
|
53
|
-
# Stop here for minimal mode
|
|
54
|
-
if [[ "$MINIMAL" == "true" ]]; then
|
|
55
|
-
exit 0
|
|
56
|
-
fi
|
|
57
|
-
|
|
58
|
-
# 1. Sprint summary (uses shared functions from sprint-common.sh)
|
|
59
|
-
if [[ -f "$(get_sprint_file)" ]]; then
|
|
60
|
-
print_header "Sprint Context"
|
|
61
|
-
|
|
62
|
-
# Use shared functions for consistent output
|
|
63
|
-
summary=$(get_sprint_summary)
|
|
64
|
-
if [[ -n "$summary" ]]; then
|
|
65
|
-
echo "$summary"
|
|
66
|
-
fi
|
|
67
|
-
|
|
68
|
-
progress=$(get_sprint_progress)
|
|
69
|
-
if [[ -n "$progress" ]]; then
|
|
70
|
-
echo "$progress"
|
|
71
|
-
fi
|
|
72
|
-
fi
|
|
73
|
-
|
|
74
|
-
# 2. Active session (if exists) - extract header metadata + current assessment
|
|
75
|
-
SESSION_FILE=""
|
|
76
|
-
if [[ -d "$PROJECT_ROOT/.session" ]]; then
|
|
77
|
-
# Find a session file (typically only one active at a time)
|
|
78
|
-
SESSION_FILE=$(find "$PROJECT_ROOT/.session" -maxdepth 1 -name "*-session.md" -type f 2>/dev/null | head -1)
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
if [[ -n "$SESSION_FILE" && -f "$SESSION_FILE" ]]; then
|
|
82
|
-
print_header "Active Session: $(basename "$SESSION_FILE")"
|
|
83
|
-
|
|
84
|
-
# Extract header (everything before first ## heading)
|
|
85
|
-
# This includes: title, metadata fields (Phase, Workflow, Repos, Branch, etc.)
|
|
86
|
-
awk '/^## / {exit} {print}' "$SESSION_FILE"
|
|
87
|
-
|
|
88
|
-
# Find the most recent assessment section (workflow-agnostic)
|
|
89
|
-
# Assessment sections are named: "## {Agent} Assessment" (TEA, Dev, Reviewer, SM, etc.)
|
|
90
|
-
# Show the LAST one in the file as it represents current state
|
|
91
|
-
last_assessment=$(grep -n '^## .*Assessment' "$SESSION_FILE" | tail -1 | cut -d: -f1)
|
|
92
|
-
|
|
93
|
-
if [[ -n "$last_assessment" ]]; then
|
|
94
|
-
echo ""
|
|
95
|
-
echo "---"
|
|
96
|
-
# Extract from that line to next ## or EOF
|
|
97
|
-
awk -v start="$last_assessment" '
|
|
98
|
-
NR >= start {
|
|
99
|
-
if (NR > start && /^## /) exit
|
|
100
|
-
print
|
|
101
|
-
}
|
|
102
|
-
' "$SESSION_FILE"
|
|
103
|
-
fi
|
|
104
|
-
fi
|
|
105
|
-
|
|
106
|
-
# 3. Agent sidecar (if --agent provided)
|
|
107
|
-
if [[ -n "$AGENT_NAME" ]]; then
|
|
108
|
-
SIDECAR_DIR="$PROJECT_ROOT/.pennyfarthing/sidecars/${AGENT_NAME}"
|
|
109
|
-
if [[ -d "$SIDECAR_DIR" ]]; then
|
|
110
|
-
for pattern_file in "$SIDECAR_DIR"/*.md; do
|
|
111
|
-
if [[ -f "$pattern_file" ]]; then
|
|
112
|
-
print_header "Agent Sidecar: $(basename "$pattern_file")"
|
|
113
|
-
cat "$pattern_file"
|
|
114
|
-
fi
|
|
115
|
-
done
|
|
116
|
-
fi
|
|
117
|
-
fi
|
|
118
|
-
|
|
119
|
-
# 4. Agent behavior guide (combined protocols for all agents)
|
|
120
|
-
if [[ -n "$AGENT_NAME" ]]; then
|
|
121
|
-
BEHAVIOR_GUIDE="$PROJECT_ROOT/.pennyfarthing/guides/agent-behavior.md"
|
|
122
|
-
if [[ -f "$BEHAVIOR_GUIDE" ]]; then
|
|
123
|
-
print_header "Agent Behavior Guide"
|
|
124
|
-
cat "$BEHAVIOR_GUIDE"
|
|
125
|
-
fi
|
|
126
|
-
fi
|
|
127
|
-
|
|
128
|
-
# 5. Domain docs (--full only)
|
|
129
|
-
if [[ "$FULL" == "true" ]]; then
|
|
130
|
-
for doc in "$PROJECT_ROOT/.claude/project"/CLAUDE-*.md; do
|
|
131
|
-
if [[ -f "$doc" ]]; then
|
|
132
|
-
print_header "$(basename "$doc")"
|
|
133
|
-
cat "$doc"
|
|
134
|
-
fi
|
|
135
|
-
done
|
|
136
|
-
fi
|
|
7
|
+
exec python3 -m pennyfarthing_scripts.prime "$@"
|
|
@@ -64,6 +64,15 @@ fi
|
|
|
64
64
|
# Full path required - script must include category
|
|
65
65
|
SCRIPT_PATH="$SCRIPTS_DIR/$SCRIPT_NAME"
|
|
66
66
|
|
|
67
|
+
# Python-first dispatch: prefer .py over .sh when available
|
|
68
|
+
# This enables transparent migration of shell scripts to Python
|
|
69
|
+
SCRIPT_BASE="${SCRIPT_NAME%.sh}"
|
|
70
|
+
PYTHON_PATH="$SCRIPTS_DIR/${SCRIPT_BASE}.py"
|
|
71
|
+
|
|
72
|
+
if [[ -f "$PYTHON_PATH" ]] && command -v python3 &>/dev/null; then
|
|
73
|
+
exec python3 "$PYTHON_PATH" "$@"
|
|
74
|
+
fi
|
|
75
|
+
|
|
67
76
|
if [[ -f "$SCRIPT_PATH" ]]; then
|
|
68
77
|
exec "$SCRIPT_PATH" "$@"
|
|
69
78
|
else
|
|
@@ -143,6 +143,7 @@ echo " Branch: $BRANCH_NAME"
|
|
|
143
143
|
echo " Repos: $REPOS"
|
|
144
144
|
|
|
145
145
|
# Process repos based on selection
|
|
146
|
+
# When processing multiple repos, run in parallel for faster network I/O
|
|
146
147
|
case "$REPOS" in
|
|
147
148
|
api)
|
|
148
149
|
create_or_checkout_branch "$REPO_BASE/Pennyfarthing-api" "Pennyfarthing-api"
|
|
@@ -151,8 +152,42 @@ case "$REPOS" in
|
|
|
151
152
|
create_or_checkout_branch "$REPO_BASE/Pennyfarthing-ui" "Pennyfarthing-ui"
|
|
152
153
|
;;
|
|
153
154
|
all)
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
# Parallel execution for both repos
|
|
156
|
+
tmpdir=$(mktemp -d)
|
|
157
|
+
trap "rm -rf '$tmpdir'" EXIT
|
|
158
|
+
HAD_ERRORS=false
|
|
159
|
+
|
|
160
|
+
# Run both in parallel, capturing output
|
|
161
|
+
# Write to separate files to avoid race condition on shared file
|
|
162
|
+
(
|
|
163
|
+
create_or_checkout_branch "$REPO_BASE/Pennyfarthing-api" "Pennyfarthing-api"
|
|
164
|
+
echo "$REPO_BASE/Pennyfarthing-api:Pennyfarthing-api" > "$tmpdir/api.processed"
|
|
165
|
+
) > "$tmpdir/api.out" 2>&1 &
|
|
166
|
+
pid_api=$!
|
|
167
|
+
|
|
168
|
+
(
|
|
169
|
+
create_or_checkout_branch "$REPO_BASE/Pennyfarthing-ui" "Pennyfarthing-ui"
|
|
170
|
+
echo "$REPO_BASE/Pennyfarthing-ui:Pennyfarthing-ui" > "$tmpdir/ui.processed"
|
|
171
|
+
) > "$tmpdir/ui.out" 2>&1 &
|
|
172
|
+
pid_ui=$!
|
|
173
|
+
|
|
174
|
+
# Wait for both and capture exit codes
|
|
175
|
+
wait $pid_api; rc_api=$?
|
|
176
|
+
wait $pid_ui; rc_ui=$?
|
|
177
|
+
|
|
178
|
+
# Show output in order
|
|
179
|
+
[ -f "$tmpdir/api.out" ] && cat "$tmpdir/api.out"
|
|
180
|
+
[ -f "$tmpdir/ui.out" ] && cat "$tmpdir/ui.out"
|
|
181
|
+
|
|
182
|
+
# Rebuild PROCESSED_REPOS from separate files (avoids race condition)
|
|
183
|
+
[ -f "$tmpdir/api.processed" ] && PROCESSED_REPOS+=("$(cat "$tmpdir/api.processed")")
|
|
184
|
+
[ -f "$tmpdir/ui.processed" ] && PROCESSED_REPOS+=("$(cat "$tmpdir/ui.processed")")
|
|
185
|
+
|
|
186
|
+
# Check for failures
|
|
187
|
+
if [ $rc_api -ne 0 ] || [ $rc_ui -ne 0 ]; then
|
|
188
|
+
echo "⚠️ Some repos had errors"
|
|
189
|
+
HAD_ERRORS=true
|
|
190
|
+
fi
|
|
156
191
|
;;
|
|
157
192
|
esac
|
|
158
193
|
|
|
@@ -222,5 +257,11 @@ done
|
|
|
222
257
|
|
|
223
258
|
echo ""
|
|
224
259
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
225
|
-
|
|
226
|
-
echo "
|
|
260
|
+
if [ "$HAD_ERRORS" = true ]; then
|
|
261
|
+
echo "⚠️ Done with errors. Check output above."
|
|
262
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
263
|
+
exit 1
|
|
264
|
+
else
|
|
265
|
+
echo "✅ Done! All branches verified and ready."
|
|
266
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
267
|
+
fi
|
|
@@ -82,15 +82,26 @@ if ! $BRIEF; then
|
|
|
82
82
|
echo ""
|
|
83
83
|
fi
|
|
84
84
|
|
|
85
|
-
# Check each repo from configuration
|
|
85
|
+
# Check each repo from configuration (parallelized for performance)
|
|
86
86
|
repo_count=$(get_repo_count)
|
|
87
87
|
if [[ "$repo_count" -eq 0 ]]; then
|
|
88
88
|
# No repos configured, just show current directory
|
|
89
89
|
show_repo_status "Project" "$PROJECT_ROOT"
|
|
90
90
|
else
|
|
91
|
+
# Create temp dir for parallel output capture
|
|
92
|
+
tmpdir=$(mktemp -d)
|
|
93
|
+
trap "rm -rf '$tmpdir'" EXIT
|
|
94
|
+
|
|
95
|
+
# Launch status checks in parallel
|
|
91
96
|
for repo in $(get_repos); do
|
|
92
97
|
repo_path=$(get_repo_full_path "$repo")
|
|
93
|
-
show_repo_status "$repo" "$repo_path"
|
|
98
|
+
(show_repo_status "$repo" "$repo_path" > "$tmpdir/$repo.out" 2>&1) &
|
|
99
|
+
done
|
|
100
|
+
wait
|
|
101
|
+
|
|
102
|
+
# Output results in order
|
|
103
|
+
for repo in $(get_repos); do
|
|
104
|
+
[ -f "$tmpdir/$repo.out" ] && cat "$tmpdir/$repo.out"
|
|
94
105
|
done
|
|
95
106
|
fi
|
|
96
107
|
|
|
@@ -108,14 +119,28 @@ if ! $BRIEF; then
|
|
|
108
119
|
unpushed=$(git -C "$PROJECT_ROOT" log origin/develop..HEAD --oneline 2>/dev/null | wc -l | tr -d ' ')
|
|
109
120
|
total_unpushed=$((total_unpushed + unpushed))
|
|
110
121
|
else
|
|
122
|
+
# Parallelize summary collection
|
|
123
|
+
summary_tmp=$(mktemp -d)
|
|
111
124
|
for repo in $(get_repos); do
|
|
112
125
|
repo_path=$(get_repo_full_path "$repo")
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
(
|
|
127
|
+
[ -d "$repo_path/.git" ] || [ -d "$repo_path" ] || exit 0
|
|
128
|
+
count=$(git -C "$repo_path" status --short 2>/dev/null | wc -l | tr -d ' ')
|
|
129
|
+
unpushed=$(git -C "$repo_path" log origin/develop..HEAD --oneline 2>/dev/null | wc -l | tr -d ' ')
|
|
130
|
+
echo "$count $unpushed" > "$summary_tmp/$repo.count"
|
|
131
|
+
) &
|
|
132
|
+
done
|
|
133
|
+
wait
|
|
134
|
+
|
|
135
|
+
# Aggregate results
|
|
136
|
+
for repo in $(get_repos); do
|
|
137
|
+
if [ -f "$summary_tmp/$repo.count" ]; then
|
|
138
|
+
read count unpushed < "$summary_tmp/$repo.count"
|
|
139
|
+
total_changes=$((total_changes + count))
|
|
140
|
+
total_unpushed=$((total_unpushed + unpushed))
|
|
141
|
+
fi
|
|
118
142
|
done
|
|
143
|
+
rm -rf "$summary_tmp"
|
|
119
144
|
fi
|
|
120
145
|
|
|
121
146
|
if [ "$total_changes" -eq 0 ] && [ "$total_unpushed" -eq 0 ]; then
|
|
Binary file
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# Claude's next API call.
|
|
9
9
|
#
|
|
10
10
|
# Configuration files:
|
|
11
|
-
# .pennyfarthing/
|
|
11
|
+
# .pennyfarthing/config.local.yaml - workflow.bell_mode: true/false
|
|
12
12
|
# .pennyfarthing/bell-queue.json - [{ "text": "...", "images": [...] }, ...]
|
|
13
13
|
#
|
|
14
14
|
# Output format (when injecting):
|
|
@@ -35,15 +35,17 @@ if [[ ! -d "$PROJECT_ROOT/.pennyfarthing" ]]; then
|
|
|
35
35
|
exit 0
|
|
36
36
|
fi
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
CONFIG_LOCAL_YAML="$PROJECT_ROOT/.pennyfarthing/config.local.yaml"
|
|
39
39
|
BELL_QUEUE_FILE="$PROJECT_ROOT/.pennyfarthing/bell-queue.json"
|
|
40
40
|
|
|
41
|
-
# Check if bell mode is enabled
|
|
42
|
-
if [[ ! -f "$
|
|
41
|
+
# Check if bell mode is enabled in config.local.yaml
|
|
42
|
+
if [[ ! -f "$CONFIG_LOCAL_YAML" ]]; then
|
|
43
43
|
exit 0
|
|
44
44
|
fi
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
# Parse YAML to check workflow.bell_mode - look for "bell_mode: true"
|
|
47
|
+
# This handles both "bell_mode: true" and " bell_mode: true" (indented under workflow)
|
|
48
|
+
ENABLED=$(grep -E '^\s*bell_mode:\s*true' "$CONFIG_LOCAL_YAML" 2>/dev/null || true)
|
|
47
49
|
if [[ -z "$ENABLED" ]]; then
|
|
48
50
|
exit 0
|
|
49
51
|
fi
|
|
@@ -67,6 +69,13 @@ if [[ -z "$FIRST_MESSAGE_TEXT" ]]; then
|
|
|
67
69
|
exit 0
|
|
68
70
|
fi
|
|
69
71
|
|
|
72
|
+
# Get Cyclist port (if running)
|
|
73
|
+
CYCLIST_PORT=""
|
|
74
|
+
PORT_FILE="$PROJECT_ROOT/.cyclist-port"
|
|
75
|
+
if [[ -f "$PORT_FILE" ]]; then
|
|
76
|
+
CYCLIST_PORT=$(cat "$PORT_FILE" 2>/dev/null)
|
|
77
|
+
fi
|
|
78
|
+
|
|
70
79
|
# Output the hook response JSON
|
|
71
80
|
cat << EOF
|
|
72
81
|
{
|
|
@@ -77,11 +86,21 @@ cat << EOF
|
|
|
77
86
|
}
|
|
78
87
|
EOF
|
|
79
88
|
|
|
80
|
-
# Remove the first message from the queue
|
|
81
|
-
#
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
89
|
+
# Remove the first message from the queue and notify Cyclist
|
|
90
|
+
# Run in background to avoid blocking hook response
|
|
91
|
+
(
|
|
92
|
+
# Dequeue using jq if available
|
|
93
|
+
if command -v jq &> /dev/null; then
|
|
94
|
+
jq 'if length > 0 then .[1:] else [] end' "$BELL_QUEUE_FILE" > "$BELL_QUEUE_FILE.tmp" 2>/dev/null && mv "$BELL_QUEUE_FILE.tmp" "$BELL_QUEUE_FILE"
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# Notify Cyclist browser to dequeue and display the message
|
|
98
|
+
if [[ -n "$CYCLIST_PORT" ]] && [[ "$CYCLIST_PORT" =~ ^[0-9]+$ ]]; then
|
|
99
|
+
curl -s -X POST "http://localhost:$CYCLIST_PORT/api/bell-consumed" \
|
|
100
|
+
-H "Content-Type: application/json" \
|
|
101
|
+
-d "{\"text\": \"$FIRST_MESSAGE_TEXT\"}" \
|
|
102
|
+
>/dev/null 2>&1 || true
|
|
103
|
+
fi
|
|
104
|
+
) &
|
|
86
105
|
|
|
87
106
|
exit 0
|