@pennyfarthing/core 7.9.2 → 7.9.5
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/package.json +2 -2
- package/pennyfarthing-dist/agents/README.md +348 -0
- package/pennyfarthing-dist/agents/architect.md +180 -0
- package/pennyfarthing-dist/agents/dev.md +169 -0
- package/pennyfarthing-dist/agents/devops.md +203 -0
- package/pennyfarthing-dist/agents/handoff.md +235 -0
- package/pennyfarthing-dist/agents/orchestrator.md +182 -0
- package/pennyfarthing-dist/agents/pm.md +152 -0
- package/pennyfarthing-dist/agents/reviewer-preflight.md +129 -0
- package/pennyfarthing-dist/agents/reviewer.md +180 -0
- package/pennyfarthing-dist/agents/sm-file-summary.md +79 -0
- package/pennyfarthing-dist/agents/sm-finish.md +82 -0
- package/pennyfarthing-dist/agents/sm-handoff.md +129 -0
- package/pennyfarthing-dist/agents/sm-setup.md +251 -0
- package/pennyfarthing-dist/agents/sm.md +284 -0
- package/pennyfarthing-dist/agents/tea.md +161 -0
- package/pennyfarthing-dist/agents/tech-writer.md +226 -0
- package/pennyfarthing-dist/agents/testing-runner.md +184 -0
- package/pennyfarthing-dist/agents/ux-designer.md +236 -0
- package/pennyfarthing-dist/agents/workflow-status-check.md +96 -0
- package/pennyfarthing-dist/commands/architect.md +7 -0
- package/pennyfarthing-dist/commands/benchmark-control.md +69 -0
- package/pennyfarthing-dist/commands/benchmark.md +485 -0
- package/pennyfarthing-dist/commands/brainstorming.md +91 -0
- package/pennyfarthing-dist/commands/check.md +156 -0
- package/pennyfarthing-dist/commands/chore.md +178 -0
- package/pennyfarthing-dist/commands/close-epic.md +139 -0
- package/pennyfarthing-dist/commands/continue-session.md +184 -0
- package/pennyfarthing-dist/commands/create-branches-from-story.md +358 -0
- package/pennyfarthing-dist/commands/create-theme.md +29 -0
- package/pennyfarthing-dist/commands/dev.md +7 -0
- package/pennyfarthing-dist/commands/devops.md +7 -0
- package/pennyfarthing-dist/commands/git-cleanup.md +51 -0
- package/pennyfarthing-dist/commands/health-check.md +141 -0
- package/pennyfarthing-dist/commands/help.md +264 -0
- package/pennyfarthing-dist/commands/job-fair.md +102 -0
- package/pennyfarthing-dist/commands/list-themes.md +21 -0
- package/pennyfarthing-dist/commands/orchestrator.md +7 -0
- package/pennyfarthing-dist/commands/parallel-work.md +71 -0
- package/pennyfarthing-dist/commands/party-mode.md +77 -0
- package/pennyfarthing-dist/commands/permissions.md +193 -0
- package/pennyfarthing-dist/commands/pm.md +7 -0
- package/pennyfarthing-dist/commands/prime.md +140 -0
- package/pennyfarthing-dist/commands/release.md +58 -0
- package/pennyfarthing-dist/commands/repo-status.md +49 -0
- package/pennyfarthing-dist/commands/retro.md +200 -0
- package/pennyfarthing-dist/commands/reviewer.md +7 -0
- package/pennyfarthing-dist/commands/run-ci.md +116 -0
- package/pennyfarthing-dist/commands/set-theme.md +56 -0
- package/pennyfarthing-dist/commands/show-theme.md +21 -0
- package/pennyfarthing-dist/commands/sm.md +7 -0
- package/pennyfarthing-dist/commands/solo.md +447 -0
- package/pennyfarthing-dist/commands/sprint-planning.md +109 -0
- package/pennyfarthing-dist/commands/sprint.md +133 -0
- package/pennyfarthing-dist/commands/standalone.md +194 -0
- package/pennyfarthing-dist/commands/start-epic.md +168 -0
- package/pennyfarthing-dist/commands/sync-epic-to-jira.md +184 -0
- package/pennyfarthing-dist/commands/sync-work-with-sprint.md +373 -0
- package/pennyfarthing-dist/commands/tea.md +7 -0
- package/pennyfarthing-dist/commands/tech-writer.md +7 -0
- package/pennyfarthing-dist/commands/theme-maker.md +676 -0
- package/pennyfarthing-dist/commands/update-domain-docs.md +83 -0
- package/pennyfarthing-dist/commands/ux-designer.md +7 -0
- package/pennyfarthing-dist/commands/work.md +23 -0
- package/pennyfarthing-dist/commands/workflow.md +21 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +311 -0
- package/pennyfarthing-dist/guides/agent-coordination.md +480 -0
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +432 -0
- package/pennyfarthing-dist/guides/agent-template-strategic.md +148 -0
- package/pennyfarthing-dist/guides/agent-template-tactical.md +162 -0
- package/pennyfarthing-dist/guides/hooks.md +230 -0
- package/pennyfarthing-dist/guides/measurement-framework.md +210 -0
- package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +766 -0
- package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +574 -0
- package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +488 -0
- package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +402 -0
- package/pennyfarthing-dist/guides/permission-protocol.md +188 -0
- package/pennyfarthing-dist/guides/persona-loading.md +46 -0
- package/pennyfarthing-dist/guides/prompt-patterns.md +338 -0
- package/pennyfarthing-dist/guides/scale-levels.md +114 -0
- package/pennyfarthing-dist/guides/session-artifacts.md +193 -0
- package/pennyfarthing-dist/guides/workflow-schema.md +257 -0
- package/pennyfarthing-dist/guides/worktree-mode.md +113 -0
- package/pennyfarthing-dist/guides/xml-tags.md +335 -0
- package/pennyfarthing-dist/output-styles/teaching.md +33 -0
- package/pennyfarthing-dist/output-styles/terse.md +20 -0
- package/pennyfarthing-dist/output-styles/verbose.md +28 -0
- package/pennyfarthing-dist/personas/BENCHMARK-METHODOLOGY.md +105 -0
- package/pennyfarthing-dist/personas/OCEAN-BENCHMARKING.md +210 -0
- package/pennyfarthing-dist/personas/TRAIL-OCEAN-MAPPING.md +168 -0
- package/pennyfarthing-dist/personas/ZEITGEIST-ANALYSIS.md +171 -0
- package/pennyfarthing-dist/personas/attributes.yaml +69 -0
- package/pennyfarthing-dist/personas/scripts/add-zeitgeist-calibrated.py +81 -0
- package/pennyfarthing-dist/personas/scripts/add-zeitgeist-scores.sh +56 -0
- package/pennyfarthing-dist/personas/themes/1984.yaml +304 -0
- package/pennyfarthing-dist/personas/themes/a-team.yaml +331 -0
- package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +324 -0
- package/pennyfarthing-dist/personas/themes/all-stars.yaml +326 -0
- package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +298 -0
- package/pennyfarthing-dist/personas/themes/arcane.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +327 -0
- package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/babylon-5.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/black-sails.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/blade-runner.yaml +289 -0
- package/pennyfarthing-dist/personas/themes/bobiverse.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +319 -0
- package/pennyfarthing-dist/personas/themes/catch-22.yaml +304 -0
- package/pennyfarthing-dist/personas/themes/classical-composers.yaml +302 -0
- package/pennyfarthing-dist/personas/themes/control.yaml +201 -0
- package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +315 -0
- package/pennyfarthing-dist/personas/themes/deadwood.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/dickens.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/discworld.yaml +334 -0
- package/pennyfarthing-dist/personas/themes/doctor-who.yaml +284 -0
- package/pennyfarthing-dist/personas/themes/don-quixote.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/dune.yaml +301 -0
- package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/fargo.yaml +322 -0
- package/pennyfarthing-dist/personas/themes/film-auteurs.yaml +304 -0
- package/pennyfarthing-dist/personas/themes/firefly.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/foundation.yaml +284 -0
- package/pennyfarthing-dist/personas/themes/futurama.yaml +313 -0
- package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +284 -0
- package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +365 -0
- package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +326 -0
- package/pennyfarthing-dist/personas/themes/hannibal.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/harry-potter.yaml +316 -0
- package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +285 -0
- package/pennyfarthing-dist/personas/themes/historical-figures.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +323 -0
- package/pennyfarthing-dist/personas/themes/house-md.yaml +313 -0
- package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +283 -0
- package/pennyfarthing-dist/personas/themes/inspector-morse.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/jane-austen.yaml +281 -0
- package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/justified.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +343 -0
- package/pennyfarthing-dist/personas/themes/les-miserables.yaml +293 -0
- package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +326 -0
- package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +325 -0
- package/pennyfarthing-dist/personas/themes/mad-max.yaml +349 -0
- package/pennyfarthing-dist/personas/themes/mad-men.yaml +283 -0
- package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/mash.yaml +329 -0
- package/pennyfarthing-dist/personas/themes/mass-effect.yaml +283 -0
- package/pennyfarthing-dist/personas/themes/military-commanders.yaml +298 -0
- package/pennyfarthing-dist/personas/themes/moby-dick.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/monty-python.yaml +297 -0
- package/pennyfarthing-dist/personas/themes/neuromancer.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +321 -0
- package/pennyfarthing-dist/personas/themes/parks-and-rec.yaml +364 -0
- package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +292 -0
- package/pennyfarthing-dist/personas/themes/princess-bride.yaml +344 -0
- package/pennyfarthing-dist/personas/themes/renaissance-masters.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/rome.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/russian-masters.yaml +310 -0
- package/pennyfarthing-dist/personas/themes/sandman.yaml +282 -0
- package/pennyfarthing-dist/personas/themes/scientific-revolutionaries.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/shakespeare.yaml +295 -0
- package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +283 -0
- package/pennyfarthing-dist/personas/themes/snow-crash.yaml +290 -0
- package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +358 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +327 -0
- package/pennyfarthing-dist/personas/themes/star-wars.yaml +297 -0
- package/pennyfarthing-dist/personas/themes/succession.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/superfriends.yaml +332 -0
- package/pennyfarthing-dist/personas/themes/ted-lasso.yaml +359 -0
- package/pennyfarthing-dist/personas/themes/the-americans.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/the-crown.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +337 -0
- package/pennyfarthing-dist/personas/themes/the-good-place.yaml +315 -0
- package/pennyfarthing-dist/personas/themes/the-matrix.yaml +342 -0
- package/pennyfarthing-dist/personas/themes/the-odyssey.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/the-office.yaml +323 -0
- package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/the-wire.yaml +303 -0
- package/pennyfarthing-dist/personas/themes/the-witcher.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/twin-peaks.yaml +296 -0
- package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +294 -0
- package/pennyfarthing-dist/personas/themes/watchmen.yaml +285 -0
- package/pennyfarthing-dist/personas/themes/west-wing.yaml +285 -0
- package/pennyfarthing-dist/personas/themes/world-explorers.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +299 -0
- package/pennyfarthing-dist/personas/themes/x-files.yaml +296 -0
- package/pennyfarthing-dist/personas/zeitgeist-scores.yaml +1172 -0
- package/pennyfarthing-dist/scripts/README.md +87 -0
- package/pennyfarthing-dist/scripts/core/README.md +26 -0
- package/pennyfarthing-dist/scripts/core/agent-session.sh +383 -0
- package/pennyfarthing-dist/scripts/core/check-context.sh +280 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +101 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +95 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +30 -0
- package/pennyfarthing-dist/scripts/core/run.sh +92 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +21 -0
- package/pennyfarthing-dist/scripts/git/README.md +25 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +267 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +152 -0
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +91 -0
- package/pennyfarthing-dist/scripts/git/release.sh +215 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +494 -0
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +162 -0
- package/pennyfarthing-dist/scripts/hooks/README.md +32 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +106 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +60 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +65 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +35 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +166 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +107 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +71 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +54 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +20 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +499 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +97 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +65 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +94 -0
- package/pennyfarthing-dist/scripts/jira/README.md +36 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +101 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +97 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +22 -0
- package/pennyfarthing-dist/scripts/jira/jira-lib.sh +464 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +266 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +18 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync.sh +16 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +16 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-to-jira.sh +16 -0
- package/pennyfarthing-dist/scripts/lib/README.md +29 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +177 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +136 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +212 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +269 -0
- package/pennyfarthing-dist/scripts/lib/find-root.sh +35 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +186 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +76 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +102 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +97 -0
- package/pennyfarthing-dist/scripts/misc/README.md +44 -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/backlog.sh +91 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +247 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +231 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +122 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +74 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +10 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +319 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +141 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +778 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +219 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +7 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +319 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +193 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +259 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +270 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +160 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +400 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +54 -0
- package/pennyfarthing-dist/scripts/sprint/README.md +29 -0
- package/pennyfarthing-dist/scripts/sprint/archive-story.sh +139 -0
- package/pennyfarthing-dist/scripts/sprint/available-stories.sh +97 -0
- package/pennyfarthing-dist/scripts/sprint/check-story.sh +164 -0
- package/pennyfarthing-dist/scripts/sprint/get-epic-field.sh +58 -0
- package/pennyfarthing-dist/scripts/sprint/get-story-field.sh +69 -0
- package/pennyfarthing-dist/scripts/sprint/import-epic-to-future.sh +10 -0
- package/pennyfarthing-dist/scripts/sprint/import_epic_to_future.py +270 -0
- package/pennyfarthing-dist/scripts/sprint/list-future.sh +151 -0
- package/pennyfarthing-dist/scripts/sprint/new-sprint.sh +116 -0
- package/pennyfarthing-dist/scripts/sprint/promote-epic.sh +154 -0
- package/pennyfarthing-dist/scripts/sprint/sprint-common.sh +421 -0
- package/pennyfarthing-dist/scripts/sprint/sprint-info.sh +39 -0
- package/pennyfarthing-dist/scripts/sprint/sprint-metrics.sh +241 -0
- package/pennyfarthing-dist/scripts/sprint/sprint-status.sh +134 -0
- package/pennyfarthing-dist/scripts/story/README.md +23 -0
- package/pennyfarthing-dist/scripts/story/create-story.sh +19 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +18 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +18 -0
- package/pennyfarthing-dist/scripts/test/README.md +23 -0
- package/pennyfarthing-dist/scripts/test/ensure-swebench-data.sh +59 -0
- package/pennyfarthing-dist/scripts/test/ground-truth-judge.py +220 -0
- package/pennyfarthing-dist/scripts/test/swebench-judge.py +374 -0
- package/pennyfarthing-dist/scripts/test/test-cache.sh +165 -0
- package/pennyfarthing-dist/scripts/test/test-setup.sh +337 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +582 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +515 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +599 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +332 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +573 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +859 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +662 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +589 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +105 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +597 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +514 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +517 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +331 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +647 -0
- package/pennyfarthing-dist/scripts/theme/README.md +22 -0
- package/pennyfarthing-dist/scripts/theme/compute-theme-tiers.sh +13 -0
- package/pennyfarthing-dist/scripts/theme/compute_theme_tiers.py +402 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +73 -0
- package/pennyfarthing-dist/scripts/theme/update-theme-tiers.sh +97 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +576 -0
- package/pennyfarthing-dist/scripts/workflow/README.md +28 -0
- package/pennyfarthing-dist/scripts/workflow/check.py +502 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +24 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +159 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +228 -0
- 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/scripts/workflow/list-workflows.sh +130 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +40 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +163 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +138 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +256 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +167 -0
- package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +242 -0
- package/pennyfarthing-dist/skills/changelog/SKILL.md +367 -0
- package/pennyfarthing-dist/skills/code-review/SKILL.md +168 -0
- package/pennyfarthing-dist/skills/context-engineering/SKILL.md +274 -0
- package/pennyfarthing-dist/skills/cyclist/SKILL.md +88 -0
- package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +437 -0
- package/pennyfarthing-dist/skills/finalize-run/SKILL.md +258 -0
- package/pennyfarthing-dist/skills/jira/SKILL.md +484 -0
- package/pennyfarthing-dist/skills/judge/SKILL.md +636 -0
- package/pennyfarthing-dist/skills/just/SKILL.md +403 -0
- package/pennyfarthing-dist/skills/mermaid/SKILL.md +240 -0
- package/pennyfarthing-dist/skills/otel/skill.md +223 -0
- package/pennyfarthing-dist/skills/permissions/skill.md +172 -0
- package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +178 -0
- package/pennyfarthing-dist/skills/skill-registry.schema.json +107 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +393 -0
- package/pennyfarthing-dist/skills/sprint/scripts/archive-story.sh +101 -0
- package/pennyfarthing-dist/skills/sprint/scripts/available-stories.sh +97 -0
- package/pennyfarthing-dist/skills/sprint/scripts/check-story.sh +164 -0
- package/pennyfarthing-dist/skills/sprint/scripts/create-jira-epic.sh +101 -0
- package/pennyfarthing-dist/skills/sprint/scripts/new-sprint.sh +116 -0
- package/pennyfarthing-dist/skills/sprint/scripts/promote-epic.sh +164 -0
- package/pennyfarthing-dist/skills/sprint/scripts/sprint-info.sh +39 -0
- package/pennyfarthing-dist/skills/sprint/scripts/sprint-status.sh +147 -0
- package/pennyfarthing-dist/skills/sprint/scripts/sync-epic-jira.sh +86 -0
- package/pennyfarthing-dist/skills/sprint/skill.md +465 -0
- package/pennyfarthing-dist/skills/story/scripts/create-story.sh +159 -0
- package/pennyfarthing-dist/skills/story/scripts/size-story.sh +198 -0
- package/pennyfarthing-dist/skills/story/scripts/story-template.sh +162 -0
- package/pennyfarthing-dist/skills/story/skill.md +219 -0
- package/pennyfarthing-dist/skills/systematic-debugging/SKILL.md +390 -0
- package/pennyfarthing-dist/skills/testing/SKILL.md +99 -0
- package/pennyfarthing-dist/skills/testing/references/troubleshooting.md +124 -0
- package/pennyfarthing-dist/skills/theme/skill.md +129 -0
- package/pennyfarthing-dist/skills/theme-creation/SKILL.md +174 -0
- package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +91 -0
- package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +163 -0
- package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +138 -0
- package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +273 -0
- package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +167 -0
- package/pennyfarthing-dist/skills/workflow/skill.md +337 -0
- package/pennyfarthing-dist/skills/yq/SKILL.md +264 -0
- package/pennyfarthing-dist/templates/LEADERBOARD.schema.yaml +187 -0
- package/pennyfarthing-dist/templates/LEADERBOARD.template.md +59 -0
- package/pennyfarthing-dist/templates/agent-scopes.yaml.template +276 -0
- package/pennyfarthing-dist/templates/pennyfarthing-settings.yaml.template +61 -0
- package/pennyfarthing-dist/templates/persona-config.yaml.template +22 -0
- package/pennyfarthing-dist/templates/preferences.yaml.template +15 -0
- package/pennyfarthing-dist/templates/settings.local.json.template +101 -0
- package/pennyfarthing-dist/templates/setup-env.sh.template +18 -0
- package/pennyfarthing-dist/templates/shared-context.md.template +70 -0
- package/pennyfarthing-dist/templates/sidecar/decisions.md.template +40 -0
- package/pennyfarthing-dist/templates/sidecar/gotchas.md.template +37 -0
- package/pennyfarthing-dist/templates/sidecar/patterns.md.template +34 -0
- package/pennyfarthing-dist/workflows/agent-docs.yaml +70 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-01-initialize.md +101 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-01b-continue.md +93 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-02-context.md +115 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-03-patterns.md +133 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-04-components.md +138 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-05-interfaces.md +133 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-06-risks.md +142 -0
- package/pennyfarthing-dist/workflows/architecture/steps/step-07-document.md +160 -0
- package/pennyfarthing-dist/workflows/architecture/templates/architecture-decision.md +102 -0
- package/pennyfarthing-dist/workflows/architecture.yaml +65 -0
- package/pennyfarthing-dist/workflows/bdd.yaml +60 -0
- package/pennyfarthing-dist/workflows/brainstorming/brain-methods.csv +62 -0
- package/pennyfarthing-dist/workflows/brainstorming/checklist.md +44 -0
- package/pennyfarthing-dist/workflows/brainstorming/instructions.md +736 -0
- package/pennyfarthing-dist/workflows/brainstorming/workflow.yaml +49 -0
- package/pennyfarthing-dist/workflows/code-review/checklist.md +23 -0
- package/pennyfarthing-dist/workflows/code-review/instructions.md +234 -0
- package/pennyfarthing-dist/workflows/code-review/workflow.yaml +51 -0
- package/pennyfarthing-dist/workflows/dev-story/checklist.md +80 -0
- package/pennyfarthing-dist/workflows/dev-story/instructions.xml +410 -0
- package/pennyfarthing-dist/workflows/dev-story/workflow.yaml +50 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-01-validate-prerequisites.md +256 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-02-design-epics.md +233 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-03-create-stories.md +272 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-04-final-validation.md +153 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +122 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/templates/epics-template.md +57 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/workflow.yaml +28 -0
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +101 -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 +224 -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 +79 -0
- package/pennyfarthing-dist/workflows/git-cleanup.yaml +59 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-01-document-discovery.md +190 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-02-prd-analysis.md +178 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-03-epic-coverage-validation.md +179 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-04-ux-alignment.md +139 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-05-epic-quality-review.md +252 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/steps/step-06-final-assessment.md +133 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/templates/readiness-report-template.md +4 -0
- package/pennyfarthing-dist/workflows/implementation-readiness/workflow.yaml +40 -0
- package/pennyfarthing-dist/workflows/prd/data/domain-complexity.csv +13 -0
- package/pennyfarthing-dist/workflows/prd/data/prd-purpose.md +197 -0
- package/pennyfarthing-dist/workflows/prd/data/project-types.csv +11 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-01-init.md +191 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-01b-continue.md +153 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-02-discovery.md +224 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-03-success.md +226 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-04-journeys.md +213 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-05-domain.md +207 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-06-innovation.md +226 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-07-project-type.md +237 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-08-scoping.md +228 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-09-functional.md +231 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-10-nonfunctional.md +242 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-11-polish.md +217 -0
- package/pennyfarthing-dist/workflows/prd/steps-c/step-12-complete.md +180 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01-discovery.md +247 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-01b-legacy-conversion.md +208 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-02-review.md +249 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-03-edit.md +253 -0
- package/pennyfarthing-dist/workflows/prd/steps-e/step-e-04-complete.md +168 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-01-discovery.md +218 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02-format-detection.md +191 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-02b-parity-check.md +209 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-03-density-validation.md +174 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-04-brief-coverage-validation.md +214 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-05-measurability-validation.md +228 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-06-traceability-validation.md +217 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-07-implementation-leakage-validation.md +205 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +243 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-09-project-type-validation.md +263 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-10-smart-validation.md +209 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-11-holistic-quality-validation.md +264 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-12-completeness-validation.md +242 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-13-report-complete.md +232 -0
- package/pennyfarthing-dist/workflows/prd/templates/prd-template.md +10 -0
- package/pennyfarthing-dist/workflows/prd/workflow.yaml +42 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-01-init.md +177 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-01b-continue.md +161 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-02-vision.md +199 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-03-users.md +202 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-04-metrics.md +205 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-05-scope.md +219 -0
- package/pennyfarthing-dist/workflows/product-brief/steps/step-06-complete.md +194 -0
- package/pennyfarthing-dist/workflows/product-brief/templates/product-brief.template.md +10 -0
- package/pennyfarthing-dist/workflows/product-brief/workflow.yaml +31 -0
- package/pennyfarthing-dist/workflows/project-context/project-context-template.md +21 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-01-discover.md +184 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-02-generate.md +318 -0
- package/pennyfarthing-dist/workflows/project-context/steps/step-03-complete.md +278 -0
- package/pennyfarthing-dist/workflows/project-context/workflow.yaml +27 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-01-mode-detection.md +156 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-02-context-gathering.md +120 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-03-execute.md +113 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-04-self-check.md +113 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-05-adversarial-review.md +106 -0
- package/pennyfarthing-dist/workflows/quick-dev/steps/step-06-resolve-findings.md +140 -0
- package/pennyfarthing-dist/workflows/quick-dev/workflow.yaml +27 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +189 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +144 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +128 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +191 -0
- package/pennyfarthing-dist/workflows/quick-spec/tech-spec-template.md +74 -0
- package/pennyfarthing-dist/workflows/quick-spec/workflow.yaml +27 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-01-init.md +137 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-02-domain-analysis.md +229 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-03-competitive-landscape.md +238 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-04-regulatory-focus.md +206 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-05-technical-trends.md +234 -0
- package/pennyfarthing-dist/workflows/research/steps-domain/step-06-research-synthesis.md +443 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-01-init.md +182 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-behavior.md +237 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-02-customer-insights.md +200 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-03-customer-pain-points.md +249 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-04-customer-decisions.md +259 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-05-competitive-analysis.md +177 -0
- package/pennyfarthing-dist/workflows/research/steps-market/step-06-research-completion.md +475 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-01-init.md +137 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-02-technical-overview.md +239 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-03-integration-patterns.md +248 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-04-architectural-patterns.md +202 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-05-implementation-research.md +239 -0
- package/pennyfarthing-dist/workflows/research/steps-technical/step-06-research-synthesis.md +486 -0
- package/pennyfarthing-dist/workflows/research/templates/research.template.md +29 -0
- package/pennyfarthing-dist/workflows/research/workflow.yaml +45 -0
- package/pennyfarthing-dist/workflows/retrospective/checklist.md +31 -0
- package/pennyfarthing-dist/workflows/retrospective/instructions.md +1443 -0
- package/pennyfarthing-dist/workflows/retrospective/workflow.yaml +50 -0
- package/pennyfarthing-dist/workflows/sprint-planning/checklist.md +33 -0
- package/pennyfarthing-dist/workflows/sprint-planning/sprint-status-template.yaml +55 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-01-parse-epic-files.md +54 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-02-build-sprint-status.md +44 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-03-status-detection.md +64 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-04-generate-status-file.md +73 -0
- package/pennyfarthing-dist/workflows/sprint-planning/steps/step-05-validate-and-report.md +56 -0
- package/pennyfarthing-dist/workflows/sprint-planning/workflow.yaml +34 -0
- package/pennyfarthing-dist/workflows/tdd.yaml +50 -0
- package/pennyfarthing-dist/workflows/trivial.yaml +40 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-01-init.md +135 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-01b-continue.md +127 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-02-discovery.md +190 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-03-core-experience.md +216 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-04-emotional-response.md +219 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-05-inspiration.md +234 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-06-design-system.md +252 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-07-defining-experience.md +254 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-08-visual-foundation.md +224 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-09-design-directions.md +224 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-10-user-journeys.md +241 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-11-component-strategy.md +248 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-12-ux-patterns.md +237 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-13-responsive-accessibility.md +264 -0
- package/pennyfarthing-dist/workflows/ux-design/steps/step-14-complete.md +228 -0
- package/pennyfarthing-dist/workflows/ux-design/ux-design-template.md +13 -0
- package/pennyfarthing-dist/workflows/ux-design/workflow.yaml +41 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Individual Portrait Generator for Pennyfarthing Themes
|
|
4
|
+
|
|
5
|
+
Generates 10 individual portraits per theme using Stable Diffusion SDXL on M3 Max (MPS).
|
|
6
|
+
Reads visual prompts from theme YAML files in two locations:
|
|
7
|
+
- Built-in: pennyfarthing-dist/personas/themes/
|
|
8
|
+
- Custom: .claude/pennyfarthing/themes/ (takes precedence)
|
|
9
|
+
|
|
10
|
+
Output: pennyfarthing-dist/personas/portraits/{theme}/{slug}-{OCEAN}.png (512x512px each)
|
|
11
|
+
|
|
12
|
+
Usage:
|
|
13
|
+
python3 scripts/generate-portraits.py [--dry-run] [--theme THEME]
|
|
14
|
+
python3 scripts/generate-portraits.py --theme gilligans-island --dry-run
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
import warnings
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
|
|
24
|
+
# Suppress progress bars before importing torch/diffusers
|
|
25
|
+
os.environ["TQDM_DISABLE"] = "1"
|
|
26
|
+
|
|
27
|
+
# Suppress CUDA warnings on MPS (Apple Silicon)
|
|
28
|
+
warnings.filterwarnings("ignore", message=".*CUDA is not available.*")
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
import yaml
|
|
32
|
+
except ImportError:
|
|
33
|
+
print("Missing PyYAML: pip install pyyaml")
|
|
34
|
+
sys.exit(1)
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
import torch
|
|
38
|
+
from diffusers import StableDiffusionXLPipeline, DPMSolverMultistepScheduler
|
|
39
|
+
from diffusers.utils import logging as diffusers_logging
|
|
40
|
+
from PIL import Image
|
|
41
|
+
HAS_TORCH = True
|
|
42
|
+
# Suppress diffusers progress bar
|
|
43
|
+
diffusers_logging.disable_progress_bar()
|
|
44
|
+
except ImportError as e:
|
|
45
|
+
HAS_TORCH = False
|
|
46
|
+
TORCH_ERROR = str(e)
|
|
47
|
+
|
|
48
|
+
# CLIP tokenizer for accurate token counting (optional - falls back to word estimate)
|
|
49
|
+
try:
|
|
50
|
+
from transformers import CLIPTokenizer
|
|
51
|
+
CLIP_TOKENIZER = CLIPTokenizer.from_pretrained("openai/clip-vit-large-patch14")
|
|
52
|
+
HAS_CLIP_TOKENIZER = True
|
|
53
|
+
except Exception:
|
|
54
|
+
CLIP_TOKENIZER = None
|
|
55
|
+
HAS_CLIP_TOKENIZER = False
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# Configuration
|
|
59
|
+
SCRIPT_DIR = Path(__file__).parent
|
|
60
|
+
PROJECT_ROOT = SCRIPT_DIR.parent
|
|
61
|
+
BUILTIN_THEMES_DIR = PROJECT_ROOT / "pennyfarthing-dist" / "personas" / "themes"
|
|
62
|
+
CUSTOM_THEMES_DIR = PROJECT_ROOT / ".claude" / "pennyfarthing" / "themes"
|
|
63
|
+
OUTPUT_DIR = PROJECT_ROOT / "pennyfarthing-dist" / "personas" / "portraits"
|
|
64
|
+
MODEL_ID = "stabilityai/stable-diffusion-xl-base-1.0"
|
|
65
|
+
|
|
66
|
+
# SDXL generates at 1024x1024, we'll resize to 512x512
|
|
67
|
+
GENERATION_SIZE = 1024
|
|
68
|
+
OUTPUT_SIZE = 512
|
|
69
|
+
|
|
70
|
+
# Generation parameters
|
|
71
|
+
NUM_INFERENCE_STEPS = 30
|
|
72
|
+
GUIDANCE_SCALE = 7.5
|
|
73
|
+
|
|
74
|
+
# CLIP token limit - prompts are truncated beyond this
|
|
75
|
+
CLIP_MAX_TOKENS = 77
|
|
76
|
+
|
|
77
|
+
# Role order for the 10 agents
|
|
78
|
+
ROLES = [
|
|
79
|
+
"orchestrator", "sm", "tea", "dev", "reviewer",
|
|
80
|
+
"architect", "pm", "tech-writer", "ux-designer", "devops"
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
# Default style suffix (visual description comes first for emphasis)
|
|
84
|
+
# Themes can override this by setting 'portrait_style' in their theme metadata
|
|
85
|
+
DEFAULT_STYLE_SUFFIX = ", traditional woodcut portrait bust, black and white, bold linework, crosshatching, medieval style"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def to_slug(name: str) -> str:
|
|
89
|
+
"""Convert a name to URL-safe slug (lowercase kebab-case)."""
|
|
90
|
+
import re
|
|
91
|
+
slug = name.lower()
|
|
92
|
+
slug = re.sub(r'[^a-z0-9]+', '-', slug)
|
|
93
|
+
slug = re.sub(r'^-|-$', '', slug)
|
|
94
|
+
return slug
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def count_clip_tokens(text: str) -> int:
|
|
98
|
+
"""Count CLIP tokens in text. Uses actual tokenizer if available, else estimates."""
|
|
99
|
+
if HAS_CLIP_TOKENIZER and CLIP_TOKENIZER:
|
|
100
|
+
tokens = CLIP_TOKENIZER.encode(text)
|
|
101
|
+
return len(tokens)
|
|
102
|
+
else:
|
|
103
|
+
# Fallback: estimate ~1.3 tokens per word (empirical average for CLIP)
|
|
104
|
+
return int(len(text.split()) * 1.3)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def truncate_prompt_to_clip_limit(visual: str, style_suffix: str, max_tokens: int = CLIP_MAX_TOKENS) -> tuple[str, bool]:
|
|
108
|
+
"""Truncate prompt to fit within CLIP token limit.
|
|
109
|
+
|
|
110
|
+
Strategy: Prioritize the visual description over the style suffix.
|
|
111
|
+
If combined prompt exceeds limit, progressively trim the visual description.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
tuple: (truncated_prompt, was_truncated)
|
|
115
|
+
"""
|
|
116
|
+
combined = f"{visual}{style_suffix}"
|
|
117
|
+
token_count = count_clip_tokens(combined)
|
|
118
|
+
|
|
119
|
+
if token_count <= max_tokens:
|
|
120
|
+
return combined, False
|
|
121
|
+
|
|
122
|
+
# Need to truncate - prioritize visual by trimming words from end
|
|
123
|
+
visual_words = visual.split()
|
|
124
|
+
style_tokens = count_clip_tokens(style_suffix)
|
|
125
|
+
available_for_visual = max_tokens - style_tokens - 2 # Buffer for safety
|
|
126
|
+
|
|
127
|
+
# Binary search for optimal truncation point
|
|
128
|
+
while visual_words and count_clip_tokens(" ".join(visual_words)) > available_for_visual:
|
|
129
|
+
visual_words = visual_words[:-1]
|
|
130
|
+
|
|
131
|
+
truncated_visual = " ".join(visual_words)
|
|
132
|
+
if truncated_visual and not truncated_visual.endswith((",", ".", ";")):
|
|
133
|
+
truncated_visual = truncated_visual.rstrip(",. ")
|
|
134
|
+
|
|
135
|
+
return f"{truncated_visual}{style_suffix}", True
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def ocean_suffix(ocean: dict) -> str:
|
|
139
|
+
"""Generate OCEAN suffix from scores (e.g., '54432' for O=5,C=4,E=4,A=3,N=2)."""
|
|
140
|
+
return f"{ocean['O']}{ocean['C']}{ocean['E']}{ocean['A']}{ocean['N']}"
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def generate_portrait_filename(short_name: str, ocean: dict) -> str:
|
|
144
|
+
"""Generate portrait filename from shortName and OCEAN scores.
|
|
145
|
+
|
|
146
|
+
Format: {shortName-slug}-{OCEAN}.png (e.g., 'yoda-54242.png')
|
|
147
|
+
"""
|
|
148
|
+
slug = to_slug(short_name)
|
|
149
|
+
return f"{slug}-{ocean_suffix(ocean)}.png"
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def parse_theme_file(theme_path: Path) -> dict:
|
|
153
|
+
"""Parse theme YAML file to extract visual prompts for each agent."""
|
|
154
|
+
with open(theme_path, "r", encoding="utf-8") as f:
|
|
155
|
+
data = yaml.safe_load(f)
|
|
156
|
+
|
|
157
|
+
theme_metadata = data.get("theme", {})
|
|
158
|
+
result = {
|
|
159
|
+
"theme": theme_path.stem,
|
|
160
|
+
"source": theme_metadata.get("source", ""),
|
|
161
|
+
"portrait_style": theme_metadata.get("portrait_style", None),
|
|
162
|
+
"characters": {}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
agents = data.get("agents", {})
|
|
166
|
+
for role, agent_data in agents.items():
|
|
167
|
+
if isinstance(agent_data, dict) and "visual" in agent_data:
|
|
168
|
+
# Get shortName, fallback to first word of character name
|
|
169
|
+
character = agent_data.get("character", role)
|
|
170
|
+
short_name = agent_data.get("shortName", character.split()[0])
|
|
171
|
+
ocean = agent_data.get("ocean", {})
|
|
172
|
+
|
|
173
|
+
# Generate filename if OCEAN scores are available
|
|
174
|
+
if ocean and all(k in ocean for k in ['O', 'C', 'E', 'A', 'N']):
|
|
175
|
+
filename = generate_portrait_filename(short_name, ocean)
|
|
176
|
+
else:
|
|
177
|
+
# Fallback to role-based name if no OCEAN scores
|
|
178
|
+
filename = f"{role}.png"
|
|
179
|
+
|
|
180
|
+
result["characters"][role] = {
|
|
181
|
+
"name": character,
|
|
182
|
+
"shortName": short_name,
|
|
183
|
+
"visual": agent_data["visual"],
|
|
184
|
+
"ocean": ocean,
|
|
185
|
+
"filename": filename
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return result
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def build_portrait_prompt(visual: str, style_suffix: str = None) -> tuple[str, bool, int]:
|
|
192
|
+
"""Build a prompt for portrait generation with CLIP token limit enforcement.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
visual: The character's visual description from theme YAML
|
|
196
|
+
style_suffix: Optional theme-specific style suffix. Falls back to DEFAULT_STYLE_SUFFIX.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
tuple: (prompt, was_truncated, token_count)
|
|
200
|
+
"""
|
|
201
|
+
suffix = style_suffix if style_suffix is not None else DEFAULT_STYLE_SUFFIX
|
|
202
|
+
prompt, was_truncated = truncate_prompt_to_clip_limit(visual, suffix)
|
|
203
|
+
token_count = count_clip_tokens(prompt)
|
|
204
|
+
return prompt, was_truncated, token_count
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def load_pipeline():
|
|
208
|
+
"""Load SDXL pipeline on MPS."""
|
|
209
|
+
print("\nLoading SDXL model on MPS...")
|
|
210
|
+
print("(First run downloads ~6.5GB model)")
|
|
211
|
+
|
|
212
|
+
# Use float32 on MPS to avoid NaN issues with float16
|
|
213
|
+
pipe = StableDiffusionXLPipeline.from_pretrained(
|
|
214
|
+
MODEL_ID,
|
|
215
|
+
torch_dtype=torch.float32,
|
|
216
|
+
use_safetensors=True,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
|
|
220
|
+
pipe = pipe.to("mps")
|
|
221
|
+
pipe.enable_attention_slicing()
|
|
222
|
+
|
|
223
|
+
print("Model loaded.\n")
|
|
224
|
+
return pipe
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def generate_portrait(pipe, prompt: str, seed: int = 42) -> "Image.Image":
|
|
228
|
+
"""Generate a single portrait."""
|
|
229
|
+
# Use CPU generator for MPS compatibility
|
|
230
|
+
generator = torch.Generator().manual_seed(seed)
|
|
231
|
+
|
|
232
|
+
with torch.no_grad():
|
|
233
|
+
result = pipe(
|
|
234
|
+
prompt=prompt,
|
|
235
|
+
negative_prompt="color, grayscale, photorealistic, blurry, deformed",
|
|
236
|
+
width=GENERATION_SIZE,
|
|
237
|
+
height=GENERATION_SIZE,
|
|
238
|
+
num_inference_steps=NUM_INFERENCE_STEPS,
|
|
239
|
+
guidance_scale=GUIDANCE_SCALE,
|
|
240
|
+
generator=generator,
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
image = result.images[0]
|
|
244
|
+
# Resize to output size
|
|
245
|
+
return image.resize((OUTPUT_SIZE, OUTPUT_SIZE), Image.Resampling.LANCZOS)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def main():
|
|
249
|
+
parser = argparse.ArgumentParser(description="Generate individual portraits from theme YAML files")
|
|
250
|
+
parser.add_argument("--dry-run", action="store_true", help="List without generating")
|
|
251
|
+
parser.add_argument("--theme", type=str, help="Generate only this theme")
|
|
252
|
+
parser.add_argument("--role", type=str, help="Generate only this role (with --theme)")
|
|
253
|
+
parser.add_argument("--seed", type=int, default=42, help="Random seed")
|
|
254
|
+
parser.add_argument("--skip-existing", action="store_true", help="Skip existing files")
|
|
255
|
+
parser.add_argument("--output-dir", type=str, help="Output to different directory (default: pennyfarthing-dist/personas/portraits)")
|
|
256
|
+
args = parser.parse_args()
|
|
257
|
+
|
|
258
|
+
# Determine output directory
|
|
259
|
+
output_base = Path(args.output_dir) if args.output_dir else OUTPUT_DIR
|
|
260
|
+
|
|
261
|
+
# Find theme files from both built-in and custom directories
|
|
262
|
+
# Custom themes take precedence over built-in themes with same name
|
|
263
|
+
theme_map = {}
|
|
264
|
+
|
|
265
|
+
# First add built-in themes
|
|
266
|
+
if BUILTIN_THEMES_DIR.exists():
|
|
267
|
+
for tf in BUILTIN_THEMES_DIR.glob("*.yaml"):
|
|
268
|
+
theme_map[tf.stem] = tf
|
|
269
|
+
|
|
270
|
+
# Then add/override with custom themes
|
|
271
|
+
if CUSTOM_THEMES_DIR.exists():
|
|
272
|
+
for tf in CUSTOM_THEMES_DIR.glob("*.yaml"):
|
|
273
|
+
theme_map[tf.stem] = tf
|
|
274
|
+
|
|
275
|
+
theme_files = sorted(theme_map.values(), key=lambda p: p.stem)
|
|
276
|
+
|
|
277
|
+
if args.theme:
|
|
278
|
+
if args.theme in theme_map:
|
|
279
|
+
theme_files = [theme_map[args.theme]]
|
|
280
|
+
else:
|
|
281
|
+
print(f"Theme '{args.theme}' not found")
|
|
282
|
+
print(f" Searched: {BUILTIN_THEMES_DIR}")
|
|
283
|
+
print(f" Searched: {CUSTOM_THEMES_DIR}")
|
|
284
|
+
sys.exit(1)
|
|
285
|
+
|
|
286
|
+
print(f"Theme sources:")
|
|
287
|
+
print(f" Built-in: {BUILTIN_THEMES_DIR}")
|
|
288
|
+
print(f" Custom: {CUSTOM_THEMES_DIR}")
|
|
289
|
+
print(f"Found {len(theme_files)} themes")
|
|
290
|
+
print(f"Output: {output_base}/{{theme}}/{{slug}}-{{OCEAN}}.png")
|
|
291
|
+
|
|
292
|
+
if args.dry_run:
|
|
293
|
+
print(f"\nCLIP token limit: {CLIP_MAX_TOKENS} tokens")
|
|
294
|
+
print(f"Tokenizer: {'CLIP (accurate)' if HAS_CLIP_TOKENIZER else 'word estimate (fallback)'}")
|
|
295
|
+
print("\nDry run - portraits to generate:")
|
|
296
|
+
truncation_warnings = []
|
|
297
|
+
for tf in theme_files:
|
|
298
|
+
parsed = parse_theme_file(tf)
|
|
299
|
+
theme_dir = output_base / parsed["theme"]
|
|
300
|
+
char_count = len(parsed["characters"])
|
|
301
|
+
style_desc = parsed["portrait_style"][:60] + "..." if parsed["portrait_style"] and len(parsed["portrait_style"]) > 60 else parsed["portrait_style"]
|
|
302
|
+
style_display = style_desc if style_desc else "(default woodcut)"
|
|
303
|
+
print(f"\n {parsed['theme']}/ ({char_count} characters with visual)")
|
|
304
|
+
print(f" Style: {style_display}")
|
|
305
|
+
for role in ROLES:
|
|
306
|
+
if role in parsed["characters"]:
|
|
307
|
+
char = parsed["characters"][role]
|
|
308
|
+
out_path = theme_dir / char["filename"]
|
|
309
|
+
status = "EXISTS" if out_path.exists() else "PENDING"
|
|
310
|
+
|
|
311
|
+
# Check token count and truncation
|
|
312
|
+
prompt, was_truncated, token_count = build_portrait_prompt(char["visual"], parsed["portrait_style"])
|
|
313
|
+
token_status = f"{token_count}tok"
|
|
314
|
+
if was_truncated:
|
|
315
|
+
token_status = f"⚠️ {token_count}tok TRUNCATED"
|
|
316
|
+
truncation_warnings.append((parsed["theme"], role, char["filename"]))
|
|
317
|
+
|
|
318
|
+
visual_preview = char["visual"][:40] + "..." if len(char["visual"]) > 40 else char["visual"]
|
|
319
|
+
print(f" [{status}] {char['filename']} ({token_status}): {visual_preview}")
|
|
320
|
+
else:
|
|
321
|
+
print(f" [SKIP] {role}: no visual field")
|
|
322
|
+
|
|
323
|
+
if truncation_warnings:
|
|
324
|
+
print(f"\n{'='*60}")
|
|
325
|
+
print(f"⚠️ WARNING: {len(truncation_warnings)} prompts will be truncated!")
|
|
326
|
+
print(f" CLIP limit is {CLIP_MAX_TOKENS} tokens. Consider shortening:")
|
|
327
|
+
for theme, role, filename in truncation_warnings[:10]:
|
|
328
|
+
print(f" - {theme}/{filename} ({role})")
|
|
329
|
+
if len(truncation_warnings) > 10:
|
|
330
|
+
print(f" ... and {len(truncation_warnings) - 10} more")
|
|
331
|
+
return
|
|
332
|
+
|
|
333
|
+
# Check for torch
|
|
334
|
+
if not HAS_TORCH:
|
|
335
|
+
print(f"Missing required package: {TORCH_ERROR}")
|
|
336
|
+
print("\nInstall: pip install diffusers transformers accelerate torch pillow")
|
|
337
|
+
sys.exit(1)
|
|
338
|
+
|
|
339
|
+
# Load model
|
|
340
|
+
pipe = load_pipeline()
|
|
341
|
+
|
|
342
|
+
# Track results
|
|
343
|
+
successful = 0
|
|
344
|
+
failed = []
|
|
345
|
+
truncated = []
|
|
346
|
+
start_time = datetime.now()
|
|
347
|
+
|
|
348
|
+
total_themes = len(theme_files)
|
|
349
|
+
for theme_idx, tf in enumerate(theme_files, 1):
|
|
350
|
+
parsed = parse_theme_file(tf)
|
|
351
|
+
theme = parsed["theme"]
|
|
352
|
+
theme_dir = output_base / theme
|
|
353
|
+
theme_dir.mkdir(parents=True, exist_ok=True)
|
|
354
|
+
|
|
355
|
+
roles_to_gen = [args.role] if args.role else ROLES
|
|
356
|
+
print(f"\n[{theme_idx}/{total_themes}] Theme: {theme}")
|
|
357
|
+
|
|
358
|
+
for role in roles_to_gen:
|
|
359
|
+
if role not in parsed["characters"]:
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
char = parsed["characters"][role]
|
|
363
|
+
out_path = theme_dir / char["filename"]
|
|
364
|
+
if args.skip_existing and out_path.exists():
|
|
365
|
+
print(f" SKIP (exists): {char['filename']}")
|
|
366
|
+
continue
|
|
367
|
+
|
|
368
|
+
prompt, was_truncated, token_count = build_portrait_prompt(char["visual"], parsed["portrait_style"])
|
|
369
|
+
|
|
370
|
+
if was_truncated:
|
|
371
|
+
truncated.append((theme, char["filename"], token_count))
|
|
372
|
+
print(f" WARNING: Truncated {char['filename']} to {token_count} tokens")
|
|
373
|
+
|
|
374
|
+
print(f" Generating: {char['filename']} ({char['name']})...")
|
|
375
|
+
print(f" Prompt: {prompt}")
|
|
376
|
+
try:
|
|
377
|
+
# Vary seed per character for diversity (base_seed + role_index)
|
|
378
|
+
role_seed = args.seed + ROLES.index(role)
|
|
379
|
+
image = generate_portrait(pipe, prompt, seed=role_seed)
|
|
380
|
+
image.save(out_path, "PNG")
|
|
381
|
+
successful += 1
|
|
382
|
+
print(f" DONE: {char['filename']}")
|
|
383
|
+
except Exception as e:
|
|
384
|
+
failed.append((theme, char["filename"], str(e)))
|
|
385
|
+
print(f" FAILED: {char['filename']}: {e}")
|
|
386
|
+
|
|
387
|
+
# Summary
|
|
388
|
+
elapsed = datetime.now() - start_time
|
|
389
|
+
print(f"\n{'='*50}")
|
|
390
|
+
print(f"Complete: {successful} portraits in {elapsed}")
|
|
391
|
+
if truncated:
|
|
392
|
+
print(f"Truncated: {len(truncated)} prompts exceeded {CLIP_MAX_TOKENS} token limit")
|
|
393
|
+
if failed:
|
|
394
|
+
print(f"Failed: {len(failed)}")
|
|
395
|
+
for t, r, e in failed:
|
|
396
|
+
print(f" - {t}/{r}: {e}")
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
if __name__ == "__main__":
|
|
400
|
+
main()
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Portrait Generator Wrapper
|
|
4
|
+
# Activates venv and runs generate-portraits.py with all arguments
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ./scripts/generate-portraits.sh --theme arthurian-mythos --dry-run
|
|
8
|
+
# ./scripts/generate-portraits.sh --theme shakespeare
|
|
9
|
+
# ./scripts/generate-portraits.sh --theme star-trek-tos --output-dir /tmp/portraits
|
|
10
|
+
# ./scripts/generate-portraits.sh --help
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
|
|
14
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
15
|
+
|
|
16
|
+
# Find PROJECT_ROOT by looking for .pennyfarthing or pennyfarthing-dist marker
|
|
17
|
+
_dir="$SCRIPT_DIR"
|
|
18
|
+
while [[ ! -d "$_dir/.pennyfarthing" ]] && [[ ! -d "$_dir/pennyfarthing-dist" ]] && [[ "$_dir" != "/" ]]; do
|
|
19
|
+
_dir="$(dirname "$_dir")"
|
|
20
|
+
done
|
|
21
|
+
PROJECT_ROOT="$_dir"
|
|
22
|
+
|
|
23
|
+
# If we're in the pennyfarthing repo itself, look for .venv there
|
|
24
|
+
# If we're in a user project, .venv should be at project root
|
|
25
|
+
VENV_DIR="$PROJECT_ROOT/.venv"
|
|
26
|
+
PYTHON_SCRIPT="$SCRIPT_DIR/generate-portraits.py"
|
|
27
|
+
|
|
28
|
+
# Check venv exists
|
|
29
|
+
if [[ ! -d "$VENV_DIR" ]]; then
|
|
30
|
+
echo "Error: Virtual environment not found at $VENV_DIR"
|
|
31
|
+
echo "Create it with: python3 -m venv .venv"
|
|
32
|
+
echo "Then install: pip install diffusers transformers accelerate torch pillow pyyaml"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Check Python script exists
|
|
37
|
+
if [[ ! -f "$PYTHON_SCRIPT" ]]; then
|
|
38
|
+
echo "Error: generate-portraits.py not found at $PYTHON_SCRIPT"
|
|
39
|
+
exit 1
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Activate venv and run
|
|
43
|
+
source "$VENV_DIR/bin/activate"
|
|
44
|
+
|
|
45
|
+
# Verify torch is available
|
|
46
|
+
if ! python -c "import torch" 2>/dev/null; then
|
|
47
|
+
echo "Error: torch not installed in venv"
|
|
48
|
+
echo "Install with: pip install diffusers transformers accelerate torch pillow"
|
|
49
|
+
deactivate
|
|
50
|
+
exit 1
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# Run the portrait generator with all passed arguments
|
|
54
|
+
python "$PYTHON_SCRIPT" "$@"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Sprint Scripts
|
|
2
|
+
|
|
3
|
+
Scripts for sprint YAML operations and sprint management.
|
|
4
|
+
|
|
5
|
+
## Scripts
|
|
6
|
+
|
|
7
|
+
| Script | Purpose |
|
|
8
|
+
|--------|---------|
|
|
9
|
+
| `sprint-status.sh` | Show current sprint status and metrics |
|
|
10
|
+
| `sprint-info.sh` | Display sprint information |
|
|
11
|
+
| `available-stories.sh` | List available stories in backlog |
|
|
12
|
+
| `archive-story.sh` | Archive completed story to sprint archive |
|
|
13
|
+
| `check-story.sh` | Check story details and readiness |
|
|
14
|
+
| `new-sprint.sh` | Create a new sprint |
|
|
15
|
+
| `promote-epic.sh` | Move epic from planning to current sprint |
|
|
16
|
+
| `sprint-common.sh` | Shared sprint utilities (library) |
|
|
17
|
+
| `sprint-metrics.sh` | Calculate sprint metrics |
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
.pennyfarthing/scripts/core/run.sh sprint/sprint-status.sh
|
|
23
|
+
.pennyfarthing/scripts/core/run.sh sprint/available-stories.sh
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Ownership
|
|
27
|
+
|
|
28
|
+
- **Primary users:** SM agent, `/sprint` skill
|
|
29
|
+
- **Maintained by:** Core Pennyfarthing team
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Archive a completed story from current-sprint.yaml to the sprint archive
|
|
3
|
+
# Usage: .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh <story-id> [pr-number] [--apply]
|
|
4
|
+
#
|
|
5
|
+
# Example: .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh MSSCI-11945 368
|
|
6
|
+
# .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh MSSCI-11945 368 --apply
|
|
7
|
+
#
|
|
8
|
+
# Options:
|
|
9
|
+
# --apply Also remove story from current-sprint.yaml (atomic operation)
|
|
10
|
+
|
|
11
|
+
set -euo pipefail
|
|
12
|
+
|
|
13
|
+
STORY_ID="${1:-}"
|
|
14
|
+
PR_NUMBER=""
|
|
15
|
+
APPLY_FLAG=false
|
|
16
|
+
|
|
17
|
+
# Parse positional and flag arguments
|
|
18
|
+
shift || true
|
|
19
|
+
for arg in "$@"; do
|
|
20
|
+
case $arg in
|
|
21
|
+
--apply)
|
|
22
|
+
APPLY_FLAG=true
|
|
23
|
+
;;
|
|
24
|
+
*)
|
|
25
|
+
# If not a flag, it's the PR number
|
|
26
|
+
if [[ -z "$PR_NUMBER" ]]; then
|
|
27
|
+
PR_NUMBER="$arg"
|
|
28
|
+
fi
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
32
|
+
|
|
33
|
+
if [[ -z "$STORY_ID" ]]; then
|
|
34
|
+
echo "Usage: archive-story.sh <story-id> [pr-number] [--apply]"
|
|
35
|
+
echo "Example: archive-story.sh MSSCI-11945 368"
|
|
36
|
+
echo " archive-story.sh MSSCI-11945 368 --apply"
|
|
37
|
+
echo ""
|
|
38
|
+
echo "Options:"
|
|
39
|
+
echo " --apply Also remove story from current-sprint.yaml"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# PROJECT_ROOT should be set by run.sh, but find it if not
|
|
44
|
+
if [[ -z "${PROJECT_ROOT:-}" ]]; then
|
|
45
|
+
d="$PWD"
|
|
46
|
+
while [[ ! -d "$d/.pennyfarthing" ]] && [[ "$d" != "/" ]]; do
|
|
47
|
+
d="$(dirname "$d")"
|
|
48
|
+
done
|
|
49
|
+
PROJECT_ROOT="$d"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
SPRINT_FILE="$PROJECT_ROOT/sprint/current-sprint.yaml"
|
|
53
|
+
|
|
54
|
+
if [[ ! -f "$SPRINT_FILE" ]]; then
|
|
55
|
+
echo "Error: Sprint file not found at $SPRINT_FILE"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Extract sprint name to determine archive file
|
|
60
|
+
# Try jira_sprint_name first (newer format), then fall back to name (older format)
|
|
61
|
+
SPRINT_NAME=$(grep -E "^\s+jira_sprint_name:" "$SPRINT_FILE" | head -1 | sed 's/.*TO Sprint \([0-9]*\).*/\1/')
|
|
62
|
+
if [[ -z "$SPRINT_NAME" ]]; then
|
|
63
|
+
SPRINT_NAME=$(grep -E "^\s+name:" "$SPRINT_FILE" | head -1 | sed 's/.*"TO Sprint \([0-9]*\)".*/\1/')
|
|
64
|
+
fi
|
|
65
|
+
if [[ -z "$SPRINT_NAME" ]]; then
|
|
66
|
+
echo "Error: Could not extract sprint name from $SPRINT_FILE"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
ARCHIVE_FILE="$PROJECT_ROOT/sprint/archive/sprint-${SPRINT_NAME}-completed.yaml"
|
|
71
|
+
|
|
72
|
+
# Check if archive file exists
|
|
73
|
+
if [[ ! -f "$ARCHIVE_FILE" ]]; then
|
|
74
|
+
echo "Error: Archive file not found at $ARCHIVE_FILE"
|
|
75
|
+
echo "Create it first with new-sprint.sh or manually"
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Use yq to extract story data
|
|
80
|
+
if ! command -v yq &> /dev/null; then
|
|
81
|
+
echo "Error: yq is required but not installed"
|
|
82
|
+
echo "Install with: brew install yq"
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# Find the story in current sprint
|
|
87
|
+
STORY_DATA=$(yq eval ".epics[].stories[] | select(.id == \"$STORY_ID\")" "$SPRINT_FILE")
|
|
88
|
+
|
|
89
|
+
if [[ -z "$STORY_DATA" ]]; then
|
|
90
|
+
echo "Error: Story $STORY_ID not found in $SPRINT_FILE"
|
|
91
|
+
exit 1
|
|
92
|
+
fi
|
|
93
|
+
|
|
94
|
+
# Extract story fields
|
|
95
|
+
TITLE=$(echo "$STORY_DATA" | yq eval '.title' -)
|
|
96
|
+
POINTS=$(echo "$STORY_DATA" | yq eval '.points' -)
|
|
97
|
+
EPIC_ID=$(yq eval ".epics[] | select(.stories[].id == \"$STORY_ID\") | .id" "$SPRINT_FILE" | head -1)
|
|
98
|
+
|
|
99
|
+
# Get today's date
|
|
100
|
+
COMPLETED_DATE=$(date +%Y-%m-%d)
|
|
101
|
+
|
|
102
|
+
# Build the archive entry
|
|
103
|
+
echo ""
|
|
104
|
+
echo "Archiving story:"
|
|
105
|
+
echo " ID: $STORY_ID"
|
|
106
|
+
echo " Title: $TITLE"
|
|
107
|
+
echo " Points: $POINTS"
|
|
108
|
+
echo " Epic: $EPIC_ID"
|
|
109
|
+
echo " Completed: $COMPLETED_DATE"
|
|
110
|
+
[[ -n "$PR_NUMBER" ]] && echo " PR: $PR_NUMBER"
|
|
111
|
+
echo ""
|
|
112
|
+
|
|
113
|
+
# Append to archive file
|
|
114
|
+
{
|
|
115
|
+
echo " - id: $STORY_ID"
|
|
116
|
+
echo " epic: $EPIC_ID"
|
|
117
|
+
echo " title: \"$TITLE\""
|
|
118
|
+
echo " points: $POINTS"
|
|
119
|
+
echo " completed: $COMPLETED_DATE"
|
|
120
|
+
[[ -n "$PR_NUMBER" ]] && echo " pr: $PR_NUMBER"
|
|
121
|
+
} >> "$ARCHIVE_FILE"
|
|
122
|
+
|
|
123
|
+
echo "Added to $ARCHIVE_FILE"
|
|
124
|
+
|
|
125
|
+
# Remove from current sprint (if --apply)
|
|
126
|
+
if $APPLY_FLAG; then
|
|
127
|
+
echo ""
|
|
128
|
+
echo "Removing story from current sprint..."
|
|
129
|
+
yq eval -i "del(.epics[].stories[] | select(.id == \"$STORY_ID\"))" "$SPRINT_FILE"
|
|
130
|
+
echo "✓ Story removed from $SPRINT_FILE"
|
|
131
|
+
echo ""
|
|
132
|
+
echo "If the epic has no more stories, you may want to remove the empty epic section."
|
|
133
|
+
else
|
|
134
|
+
echo ""
|
|
135
|
+
echo "To also remove from $SPRINT_FILE, re-run with --apply:"
|
|
136
|
+
echo " .pennyfarthing/scripts/core/run.sh sprint/archive-story.sh $STORY_ID ${PR_NUMBER:-<pr>} --apply"
|
|
137
|
+
echo ""
|
|
138
|
+
echo "Or manually: yq eval -i 'del(.epics[].stories[] | select(.id == \"$STORY_ID\"))' $SPRINT_FILE"
|
|
139
|
+
fi
|