@pennyfarthing/core 11.2.0 → 11.2.2
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 +100 -40
- package/package.json +2 -1
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/doctor.js +474 -66
- package/packages/core/dist/cli/commands/doctor.js.map +1 -1
- package/packages/core/dist/cli/commands/init.js +4 -4
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/update.js +4 -5
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/utils/constants.d.ts +3 -8
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/constants.js +3 -4
- package/packages/core/dist/cli/utils/constants.js.map +1 -1
- package/packages/core/dist/cli/utils/settings.d.ts +7 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +70 -29
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.js +16 -16
- package/packages/core/dist/cli/utils/symlinks.js.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.d.ts +1 -1
- package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.js +1 -1
- package/packages/core/dist/consultation/dialogue-manager.js.map +1 -1
- package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -1
- package/packages/core/dist/consultation/tandem-metrics.d.ts +91 -0
- package/packages/core/dist/consultation/tandem-metrics.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.js +131 -0
- package/packages/core/dist/consultation/tandem-metrics.js.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts +18 -0
- package/packages/core/dist/consultation/tandem-metrics.test.d.ts.map +1 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js +457 -0
- package/packages/core/dist/consultation/tandem-metrics.test.js.map +1 -0
- package/packages/core/dist/public/css/react.css +1 -1
- package/packages/core/dist/public/js/react/react.js +14 -14
- package/packages/core/dist/server/api/agent-load.js +1 -1
- package/packages/core/dist/server/api/agent-load.js.map +1 -1
- package/packages/core/dist/server/api/git.d.ts.map +1 -1
- package/packages/core/dist/server/api/git.js +0 -1
- package/packages/core/dist/server/api/git.js.map +1 -1
- package/packages/core/dist/server/api/index.d.ts +2 -0
- package/packages/core/dist/server/api/index.d.ts.map +1 -1
- package/packages/core/dist/server/api/index.js +2 -0
- package/packages/core/dist/server/api/index.js.map +1 -1
- package/packages/core/dist/server/api/project-info.d.ts +11 -0
- package/packages/core/dist/server/api/project-info.d.ts.map +1 -0
- package/packages/core/dist/server/api/project-info.js +18 -0
- package/packages/core/dist/server/api/project-info.js.map +1 -0
- package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
- package/packages/core/dist/server/otlp-receiver.js +18 -1
- package/packages/core/dist/server/otlp-receiver.js.map +1 -1
- package/packages/core/dist/server/otlp-receiver.test.js +1 -1
- package/packages/core/dist/server/otlp-receiver.test.js.map +1 -1
- package/packages/core/dist/server/server.d.ts +0 -3
- package/packages/core/dist/server/server.d.ts.map +1 -1
- package/packages/core/dist/server/server.js +5 -38
- package/packages/core/dist/server/server.js.map +1 -1
- package/packages/core/dist/server/server.test.d.ts +1 -1
- package/packages/core/dist/server/server.test.js +12 -23
- package/packages/core/dist/server/server.test.js.map +1 -1
- package/packages/core/dist/server/settings.d.ts +1 -0
- package/packages/core/dist/server/settings.d.ts.map +1 -1
- package/packages/core/dist/server/settings.js +13 -0
- package/packages/core/dist/server/settings.js.map +1 -1
- package/packages/core/dist/shared/capabilities.d.ts +88 -0
- package/packages/core/dist/shared/capabilities.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.js +133 -0
- package/packages/core/dist/shared/capabilities.js.map +1 -0
- package/packages/core/dist/shared/capabilities.test.d.ts +2 -0
- package/packages/core/dist/shared/capabilities.test.d.ts.map +1 -0
- package/packages/core/dist/shared/capabilities.test.js +217 -0
- package/packages/core/dist/shared/capabilities.test.js.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.d.ts +47 -0
- package/packages/core/dist/shared/spawn-prompt.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.js +82 -0
- package/packages/core/dist/shared/spawn-prompt.js.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts +2 -0
- package/packages/core/dist/shared/spawn-prompt.test.d.ts.map +1 -0
- package/packages/core/dist/shared/spawn-prompt.test.js +251 -0
- package/packages/core/dist/shared/spawn-prompt.test.js.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts +18 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js +434 -0
- package/packages/core/dist/workflow/tandem-workflow-templates.test.js.map +1 -0
- package/packages/core/dist/workflow/team-lifecycle.d.ts +169 -0
- package/packages/core/dist/workflow/team-lifecycle.d.ts.map +1 -0
- package/packages/core/dist/workflow/team-lifecycle.js +217 -0
- package/packages/core/dist/workflow/team-lifecycle.js.map +1 -0
- package/packages/core/dist/workflow/team-lifecycle.test.d.ts +20 -0
- package/packages/core/dist/workflow/team-lifecycle.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/team-lifecycle.test.js +966 -0
- package/packages/core/dist/workflow/team-lifecycle.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts +32 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.js +120 -0
- package/packages/core/dist/workflow/workflow-schema.js.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -1
- package/packages/core/dist/workflow/workflow-schema.test.js +570 -1
- package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-team-templates.test.d.ts +17 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.js +275 -0
- package/packages/core/dist/workflow/workflow-team-templates.test.js.map +1 -0
- package/pennyfarthing-dist/agents/dev.md +21 -12
- package/pennyfarthing-dist/agents/reviewer.md +23 -4
- package/pennyfarthing-dist/agents/sm-finish.md +19 -2
- package/pennyfarthing-dist/agents/sm-setup.md +7 -7
- package/pennyfarthing-dist/agents/sm.md +12 -12
- package/pennyfarthing-dist/agents/tea.md +2 -2
- package/pennyfarthing-dist/agents/testing-runner.md +1 -1
- package/pennyfarthing-dist/commands/pf-architect.md +1 -1
- package/pennyfarthing-dist/commands/pf-ba.md +1 -1
- package/pennyfarthing-dist/commands/pf-chore.md +2 -2
- package/pennyfarthing-dist/commands/pf-dev.md +1 -1
- package/pennyfarthing-dist/commands/pf-devops.md +1 -1
- package/pennyfarthing-dist/commands/pf-epic.md +6 -6
- package/pennyfarthing-dist/commands/pf-git.md +12 -10
- package/pennyfarthing-dist/commands/pf-health-check.md +1 -1
- package/pennyfarthing-dist/commands/pf-help.md +12 -12
- package/pennyfarthing-dist/commands/pf-orchestrator.md +1 -1
- package/pennyfarthing-dist/commands/pf-pm.md +1 -1
- package/pennyfarthing-dist/commands/pf-prime.md +8 -8
- package/pennyfarthing-dist/commands/pf-reviewer.md +1 -1
- package/pennyfarthing-dist/commands/pf-session.md +7 -7
- package/pennyfarthing-dist/commands/pf-sm.md +1 -1
- package/pennyfarthing-dist/commands/pf-sprint.md +7 -7
- package/pennyfarthing-dist/commands/pf-tea.md +1 -1
- package/pennyfarthing-dist/commands/pf-tech-writer.md +1 -1
- package/pennyfarthing-dist/commands/pf-theme.md +9 -9
- package/pennyfarthing-dist/commands/pf-ux-designer.md +1 -1
- package/pennyfarthing-dist/commands/pf-work.md +1 -1
- package/pennyfarthing-dist/gates/approval.md +63 -0
- package/pennyfarthing-dist/gates/confidence-sm.md +71 -0
- package/pennyfarthing-dist/gates/context-ok.md +56 -0
- package/pennyfarthing-dist/gates/evaluations/confidence-sm.md +54 -0
- package/pennyfarthing-dist/gates/quality-pass.md +67 -0
- package/pennyfarthing-dist/gates/tests-fail.md +84 -0
- package/pennyfarthing-dist/gates/tests-pass.md +79 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +84 -29
- package/pennyfarthing-dist/guides/agent-coordination.md +10 -10
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +6 -6
- package/pennyfarthing-dist/guides/agent-template-tactical.md +1 -1
- package/pennyfarthing-dist/guides/bell-mode.md +1 -1
- package/pennyfarthing-dist/guides/bikerack.md +10 -10
- package/pennyfarthing-dist/guides/brownfield-tools.md +24 -24
- package/pennyfarthing-dist/guides/command-tag-taxonomy.md +1 -1
- package/pennyfarthing-dist/guides/gate-schema.md +2 -2
- package/pennyfarthing-dist/guides/gates.md +3 -3
- package/pennyfarthing-dist/guides/handoff-cli.md +8 -8
- package/pennyfarthing-dist/guides/hooks.md +29 -29
- package/pennyfarthing-dist/guides/prime.md +2 -2
- package/pennyfarthing-dist/guides/reflector.md +1 -1
- package/pennyfarthing-dist/guides/skill-schema.md +6 -6
- package/pennyfarthing-dist/guides/tandem-protocol.md +3 -3
- package/pennyfarthing-dist/guides/workflow-schema.md +1 -1
- package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
- package/pennyfarthing-dist/guides/xml-tags.md +8 -8
- package/pennyfarthing-dist/scripts/README.md +4 -4
- package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -5
- package/pennyfarthing-dist/scripts/core/check-context.sh +3 -1
- package/pennyfarthing-dist/scripts/core/pf.sh +5 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +4 -89
- package/pennyfarthing-dist/scripts/core/prime.sh +2 -25
- package/pennyfarthing-dist/scripts/git/README.md +14 -14
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +2 -3
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +2 -3
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +2 -3
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +2 -4
- package/pennyfarthing-dist/scripts/hooks/README.md +6 -6
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +4 -183
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +4 -95
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +3 -31
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +5 -4
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +29 -34
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +4 -71
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +3 -19
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +4 -30
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +3 -32
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +4 -65
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +4 -78
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +3 -93
- package/pennyfarthing-dist/scripts/lib/env.sh +34 -0
- package/pennyfarthing-dist/scripts/lib/run-pf.sh +39 -0
- package/pennyfarthing-dist/scripts/misc/README.md +1 -1
- package/pennyfarthing-dist/scripts/misc/statusline.sh +4 -301
- package/pennyfarthing-dist/scripts/sprint/README.md +21 -21
- package/pennyfarthing-dist/scripts/workflow/README.md +2 -2
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +2 -16
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +3 -3
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +3 -3
- package/pennyfarthing-dist/skills/pf-bc/examples.md +23 -23
- package/pennyfarthing-dist/skills/pf-bc/skill.md +17 -17
- package/pennyfarthing-dist/skills/pf-bc/usage.md +8 -8
- package/pennyfarthing-dist/skills/pf-jira/SKILL.md +15 -15
- package/pennyfarthing-dist/skills/pf-jira/examples.md +48 -48
- package/pennyfarthing-dist/skills/pf-jira/usage.md +15 -15
- package/pennyfarthing-dist/skills/pf-sprint/examples.md +80 -80
- package/pennyfarthing-dist/skills/pf-sprint/skill.md +35 -35
- package/pennyfarthing-dist/skills/pf-sprint/usage.md +30 -30
- package/pennyfarthing-dist/skills/pf-theme/examples.md +15 -15
- package/pennyfarthing-dist/skills/pf-theme/skill.md +6 -6
- package/pennyfarthing-dist/skills/pf-theme/usage.md +5 -5
- package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -27
- package/pennyfarthing-dist/skills/pf-workflow/skill.md +11 -11
- package/pennyfarthing-dist/skills/pf-workflow/usage.md +11 -11
- package/pennyfarthing-dist/skills/skill-registry.yaml +19 -19
- package/pennyfarthing-dist/templates/settings.local.json.template +19 -10
- package/pennyfarthing-dist/workflows/bdd-team.yaml +89 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
- package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
- package/pennyfarthing-dist/workflows/project-setup/steps/step-01-discover.md +47 -0
- package/pennyfarthing-dist/workflows/tdd-team.yaml +80 -0
- package/pennyfarthing-dist/workflows/tdd.yaml +11 -2
- package/pennyfarthing_scripts/CLAUDE.md +19 -10
- package/pennyfarthing_scripts/__init__.py +1 -1
- package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/bellmode_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/context.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/split.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/cli.py +2 -2
- package/pennyfarthing_scripts/bellmode_hook.py +9 -296
- package/pennyfarthing_scripts/bikerack/__pycache__/audit_log_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/context_meter_footer.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/events.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/portrait_resolver.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_data.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/story_detail_screen.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/audit_log_panel.py +161 -0
- package/pennyfarthing_scripts/bikerack/base_panel.py +27 -4
- package/pennyfarthing_scripts/bikerack/changed_panel.py +96 -4
- package/pennyfarthing_scripts/bikerack/context_meter_footer.py +88 -0
- package/pennyfarthing_scripts/bikerack/debug_panel.py +1 -1
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +30 -0
- package/pennyfarthing_scripts/bikerack/events.py +28 -0
- package/pennyfarthing_scripts/bikerack/launcher.py +6 -6
- package/pennyfarthing_scripts/bikerack/portrait_resolver.py +139 -0
- package/pennyfarthing_scripts/bikerack/progress_panel.py +0 -1
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +373 -142
- package/pennyfarthing_scripts/bikerack/story_detail_data.py +247 -0
- package/pennyfarthing_scripts/bikerack/story_detail_screen.py +177 -0
- package/pennyfarthing_scripts/bikerack/tui.py +304 -62
- package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
- package/pennyfarthing_scripts/cli.py +5 -0
- package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/common/config.py +29 -2
- package/pennyfarthing_scripts/common/pr_config.py +38 -0
- package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/consultation/cli.py +3 -3
- package/pennyfarthing_scripts/context.py +3 -3
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/hooks_installer.py +2 -3
- package/pennyfarthing_scripts/git/status_all.py +1 -1
- package/pennyfarthing_scripts/git/worktree.py +2 -2
- package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/marker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/phase_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/handoff/cli.py +33 -1
- package/pennyfarthing_scripts/handoff/complete_phase.py +28 -0
- package/pennyfarthing_scripts/handoff/marker.py +15 -15
- package/pennyfarthing_scripts/handoff/phase_check.py +96 -0
- package/pennyfarthing_scripts/handoff/resolve_gate.py +13 -1
- package/pennyfarthing_scripts/hooks/__init__.py +442 -0
- package/pennyfarthing_scripts/hooks/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/bell_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_breaker.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/context_warning.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/cyclist_pretooluse.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/pre_edit_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/reflector_check.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_start.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/session_stop.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/sprint_yaml_validation.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/__pycache__/statusline.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/hooks/bell_mode.py +214 -0
- package/pennyfarthing_scripts/hooks/cli.py +96 -0
- package/pennyfarthing_scripts/hooks/context_breaker.py +104 -0
- package/pennyfarthing_scripts/hooks/context_warning.py +66 -0
- package/pennyfarthing_scripts/hooks/cyclist_pretooluse.py +129 -0
- package/pennyfarthing_scripts/hooks/pre_edit_check.py +77 -0
- package/pennyfarthing_scripts/hooks/reflector_check.py +270 -0
- package/pennyfarthing_scripts/hooks/schema_validation.py +202 -0
- package/pennyfarthing_scripts/hooks/session_start.py +294 -0
- package/pennyfarthing_scripts/hooks/session_stop.py +111 -0
- package/pennyfarthing_scripts/hooks/sprint_yaml_validation.py +97 -0
- package/pennyfarthing_scripts/hooks/statusline.py +429 -0
- package/pennyfarthing_scripts/hooks.py +27 -432
- package/pennyfarthing_scripts/pretooluse_hook.py +3 -185
- package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/heatmap.py +3 -15
- package/pennyfarthing_scripts/prime/workflow.py +2 -1
- package/pennyfarthing_scripts/schema_validation_hook.py +3 -298
- package/pennyfarthing_scripts/session_start_hook.py +4 -186
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/cli.py +121 -0
- package/pennyfarthing_scripts/sprint/loader.py +154 -3
- package/pennyfarthing_scripts/sprint/story_update.py +26 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_list_team.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_bikerack.py +26 -26
- package/pennyfarthing_scripts/tests/test_dialogue_manager.py +0 -1
- package/pennyfarthing_scripts/tests/test_sprint_panel.py +344 -265
- package/pennyfarthing_scripts/tests/test_workflow_list_team.py +147 -0
- package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/skill_command.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/tandem_awareness.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/team_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/__pycache__/workflow.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/validate/adapters/team_mode.py +323 -0
- package/pennyfarthing_scripts/validate/adapters/workflow.py +19 -0
- package/pennyfarthing_scripts/welcome_hook.py +3 -149
- package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/__pycache__/team_lifecycle.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/workflow/cli.py +22 -20
- package/pennyfarthing_scripts/workflow/state.py +0 -1
- package/pennyfarthing_scripts/workflow/team_lifecycle.py +256 -0
- package/packages/core/dist/cli/cyclist-migration.test.d.ts +0 -16
- package/packages/core/dist/cli/cyclist-migration.test.d.ts.map +0 -1
- package/packages/core/dist/cli/cyclist-migration.test.js +0 -229
- package/packages/core/dist/cli/cyclist-migration.test.js.map +0 -1
- package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
- package/packages/core/dist/scripts/theme-detail.test.d.ts.map +0 -1
- package/packages/core/dist/scripts/theme-detail.test.js +0 -199
- package/packages/core/dist/scripts/theme-detail.test.js.map +0 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import { describe, it } from 'node:test';
|
|
14
14
|
import assert from 'node:assert';
|
|
15
15
|
// Import the validator function
|
|
16
|
-
import { validateWorkflow } from './workflow-schema.js';
|
|
16
|
+
import { validateWorkflow, VALID_AGENT_NAMES } from './workflow-schema.js';
|
|
17
17
|
describe('Workflow Schema Validation (31-1)', () => {
|
|
18
18
|
describe('Valid workflows', () => {
|
|
19
19
|
it('should accept a minimal valid workflow', () => {
|
|
@@ -701,4 +701,573 @@ describe('Tandem validation (95-1)', () => {
|
|
|
701
701
|
});
|
|
702
702
|
});
|
|
703
703
|
});
|
|
704
|
+
// ==========================================================================
|
|
705
|
+
// Story 86-9: Native team block on workflow phases
|
|
706
|
+
// ==========================================================================
|
|
707
|
+
describe('Team block validation (86-9)', () => {
|
|
708
|
+
// ========================================================================
|
|
709
|
+
// AC1: team: block parsed from workflow YAML phases (sibling to tandem:)
|
|
710
|
+
// ========================================================================
|
|
711
|
+
describe('Valid team configurations', () => {
|
|
712
|
+
it('should accept phase with team block and teammates', () => {
|
|
713
|
+
const workflow = {
|
|
714
|
+
workflow: {
|
|
715
|
+
name: 'team-basic',
|
|
716
|
+
phases: [
|
|
717
|
+
{
|
|
718
|
+
name: 'green',
|
|
719
|
+
agent: 'dev',
|
|
720
|
+
team: {
|
|
721
|
+
teammates: [
|
|
722
|
+
{ agent: 'architect', task: 'Review architecture decisions' },
|
|
723
|
+
{ agent: 'tea', task: 'Monitor test coverage' }
|
|
724
|
+
]
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
]
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
const result = validateWorkflow(workflow);
|
|
731
|
+
assert.strictEqual(result.valid, true, 'Should accept phase with team block');
|
|
732
|
+
assert.ok(result.workflow?.phases?.[0].team, 'Parsed phase should have team property');
|
|
733
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates.length, 2);
|
|
734
|
+
});
|
|
735
|
+
it('should accept phase with both team and tandem blocks', () => {
|
|
736
|
+
const workflow = {
|
|
737
|
+
workflow: {
|
|
738
|
+
name: 'team-and-tandem',
|
|
739
|
+
phases: [
|
|
740
|
+
{
|
|
741
|
+
name: 'green',
|
|
742
|
+
agent: 'dev',
|
|
743
|
+
tandem: {
|
|
744
|
+
partner: 'pm',
|
|
745
|
+
scope: 'file-watch'
|
|
746
|
+
},
|
|
747
|
+
team: {
|
|
748
|
+
teammates: [
|
|
749
|
+
{ agent: 'architect', task: 'Guide patterns' }
|
|
750
|
+
]
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
]
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
const result = validateWorkflow(workflow);
|
|
757
|
+
assert.strictEqual(result.valid, true, 'Should accept phase with both team and tandem');
|
|
758
|
+
assert.ok(result.workflow?.phases?.[0].tandem, 'Should preserve tandem');
|
|
759
|
+
assert.ok(result.workflow?.phases?.[0].team, 'Should preserve team');
|
|
760
|
+
});
|
|
761
|
+
// AC2: Properties: teammates (list of agent + task), model, display
|
|
762
|
+
it('should accept team block with all properties', () => {
|
|
763
|
+
const workflow = {
|
|
764
|
+
workflow: {
|
|
765
|
+
name: 'team-full',
|
|
766
|
+
phases: [
|
|
767
|
+
{
|
|
768
|
+
name: 'green',
|
|
769
|
+
agent: 'dev',
|
|
770
|
+
team: {
|
|
771
|
+
teammates: [
|
|
772
|
+
{ agent: 'architect', task: 'Review architecture' }
|
|
773
|
+
],
|
|
774
|
+
model: 'haiku',
|
|
775
|
+
display: 'in-process'
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
]
|
|
779
|
+
}
|
|
780
|
+
};
|
|
781
|
+
const result = validateWorkflow(workflow);
|
|
782
|
+
assert.strictEqual(result.valid, true, 'Should accept team with all properties');
|
|
783
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.model, 'haiku');
|
|
784
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.display, 'in-process');
|
|
785
|
+
});
|
|
786
|
+
it('should accept team block with only teammates (model and display optional)', () => {
|
|
787
|
+
const workflow = {
|
|
788
|
+
workflow: {
|
|
789
|
+
name: 'team-minimal',
|
|
790
|
+
phases: [
|
|
791
|
+
{
|
|
792
|
+
name: 'green',
|
|
793
|
+
agent: 'dev',
|
|
794
|
+
team: {
|
|
795
|
+
teammates: [
|
|
796
|
+
{ agent: 'architect', task: 'Review code' }
|
|
797
|
+
]
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
]
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
const result = validateWorkflow(workflow);
|
|
804
|
+
assert.strictEqual(result.valid, true, 'Should accept team with only teammates');
|
|
805
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.model, undefined);
|
|
806
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.display, undefined);
|
|
807
|
+
});
|
|
808
|
+
// AC3: Each teammate entry has: agent (required), task (description string)
|
|
809
|
+
it('should accept teammate with agent and task', () => {
|
|
810
|
+
const workflow = {
|
|
811
|
+
workflow: {
|
|
812
|
+
name: 'team-teammate-full',
|
|
813
|
+
phases: [
|
|
814
|
+
{
|
|
815
|
+
name: 'green',
|
|
816
|
+
agent: 'dev',
|
|
817
|
+
team: {
|
|
818
|
+
teammates: [
|
|
819
|
+
{ agent: 'tea', task: 'Monitor test failures and suggest fixes' }
|
|
820
|
+
]
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
const result = validateWorkflow(workflow);
|
|
827
|
+
assert.strictEqual(result.valid, true, 'Should accept teammate with agent and task');
|
|
828
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates[0].agent, 'tea');
|
|
829
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates[0].task, 'Monitor test failures and suggest fixes');
|
|
830
|
+
});
|
|
831
|
+
it('should accept teammate with only agent (task is optional)', () => {
|
|
832
|
+
const workflow = {
|
|
833
|
+
workflow: {
|
|
834
|
+
name: 'team-no-task',
|
|
835
|
+
phases: [
|
|
836
|
+
{
|
|
837
|
+
name: 'green',
|
|
838
|
+
agent: 'dev',
|
|
839
|
+
team: {
|
|
840
|
+
teammates: [
|
|
841
|
+
{ agent: 'architect' }
|
|
842
|
+
]
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
]
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
const result = validateWorkflow(workflow);
|
|
849
|
+
assert.strictEqual(result.valid, true, 'Should accept teammate without task');
|
|
850
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates[0].agent, 'architect');
|
|
851
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates[0].task, undefined);
|
|
852
|
+
});
|
|
853
|
+
it('should parse display value "tmux" correctly', () => {
|
|
854
|
+
const workflow = {
|
|
855
|
+
workflow: {
|
|
856
|
+
name: 'team-tmux',
|
|
857
|
+
phases: [
|
|
858
|
+
{
|
|
859
|
+
name: 'green',
|
|
860
|
+
agent: 'dev',
|
|
861
|
+
team: {
|
|
862
|
+
teammates: [{ agent: 'architect' }],
|
|
863
|
+
display: 'tmux'
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
]
|
|
867
|
+
}
|
|
868
|
+
};
|
|
869
|
+
const result = validateWorkflow(workflow);
|
|
870
|
+
assert.strictEqual(result.valid, true, 'Should accept tmux display mode');
|
|
871
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.display, 'tmux');
|
|
872
|
+
});
|
|
873
|
+
it('should accept multiple teammates in a single phase', () => {
|
|
874
|
+
const workflow = {
|
|
875
|
+
workflow: {
|
|
876
|
+
name: 'team-multi',
|
|
877
|
+
phases: [
|
|
878
|
+
{
|
|
879
|
+
name: 'green',
|
|
880
|
+
agent: 'dev',
|
|
881
|
+
team: {
|
|
882
|
+
teammates: [
|
|
883
|
+
{ agent: 'architect', task: 'Review patterns' },
|
|
884
|
+
{ agent: 'tea', task: 'Monitor tests' },
|
|
885
|
+
{ agent: 'pm', task: 'Validate requirements' }
|
|
886
|
+
]
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
]
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
const result = validateWorkflow(workflow);
|
|
893
|
+
assert.strictEqual(result.valid, true, 'Should accept multiple teammates');
|
|
894
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates.length, 3);
|
|
895
|
+
});
|
|
896
|
+
});
|
|
897
|
+
// ========================================================================
|
|
898
|
+
// AC3 & AC4: Validation of teammate entries and agent names
|
|
899
|
+
// ========================================================================
|
|
900
|
+
describe('Invalid team configurations', () => {
|
|
901
|
+
it('should reject non-object team value', () => {
|
|
902
|
+
const workflow = {
|
|
903
|
+
workflow: {
|
|
904
|
+
name: 'team-string',
|
|
905
|
+
phases: [
|
|
906
|
+
{
|
|
907
|
+
name: 'green',
|
|
908
|
+
agent: 'dev',
|
|
909
|
+
team: 'architect'
|
|
910
|
+
}
|
|
911
|
+
]
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
const result = validateWorkflow(workflow);
|
|
915
|
+
assert.strictEqual(result.valid, false, 'Should reject non-object team');
|
|
916
|
+
assert.ok(result.errors?.some(e => e.field === 'workflow.phases[0].team' && e.message.includes('object')), 'Should report team must be an object');
|
|
917
|
+
});
|
|
918
|
+
it('should reject team block without teammates', () => {
|
|
919
|
+
const workflow = {
|
|
920
|
+
workflow: {
|
|
921
|
+
name: 'team-no-teammates',
|
|
922
|
+
phases: [
|
|
923
|
+
{
|
|
924
|
+
name: 'green',
|
|
925
|
+
agent: 'dev',
|
|
926
|
+
team: {
|
|
927
|
+
model: 'haiku'
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
]
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
const result = validateWorkflow(workflow);
|
|
934
|
+
assert.strictEqual(result.valid, false, 'Should reject team without teammates');
|
|
935
|
+
assert.ok(result.errors?.some(e => e.field?.includes('team.teammates') && e.message.includes('required')), 'Should report teammates is required');
|
|
936
|
+
});
|
|
937
|
+
it('should reject team block with empty teammates array', () => {
|
|
938
|
+
const workflow = {
|
|
939
|
+
workflow: {
|
|
940
|
+
name: 'team-empty-teammates',
|
|
941
|
+
phases: [
|
|
942
|
+
{
|
|
943
|
+
name: 'green',
|
|
944
|
+
agent: 'dev',
|
|
945
|
+
team: {
|
|
946
|
+
teammates: []
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
const result = validateWorkflow(workflow);
|
|
953
|
+
assert.strictEqual(result.valid, false, 'Should reject empty teammates array');
|
|
954
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates') && e.message.includes('at least one')), 'Should report need for at least one teammate');
|
|
955
|
+
});
|
|
956
|
+
it('should reject team block with non-array teammates', () => {
|
|
957
|
+
const workflow = {
|
|
958
|
+
workflow: {
|
|
959
|
+
name: 'team-bad-teammates',
|
|
960
|
+
phases: [
|
|
961
|
+
{
|
|
962
|
+
name: 'green',
|
|
963
|
+
agent: 'dev',
|
|
964
|
+
team: {
|
|
965
|
+
teammates: 'architect'
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
]
|
|
969
|
+
}
|
|
970
|
+
};
|
|
971
|
+
const result = validateWorkflow(workflow);
|
|
972
|
+
assert.strictEqual(result.valid, false, 'Should reject non-array teammates');
|
|
973
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates') && e.message.includes('array')), 'Should report teammates must be an array');
|
|
974
|
+
});
|
|
975
|
+
// AC3: agent is required
|
|
976
|
+
it('should reject teammate entry missing agent', () => {
|
|
977
|
+
const workflow = {
|
|
978
|
+
workflow: {
|
|
979
|
+
name: 'team-no-agent',
|
|
980
|
+
phases: [
|
|
981
|
+
{
|
|
982
|
+
name: 'green',
|
|
983
|
+
agent: 'dev',
|
|
984
|
+
team: {
|
|
985
|
+
teammates: [
|
|
986
|
+
{ task: 'Do something' }
|
|
987
|
+
]
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
]
|
|
991
|
+
}
|
|
992
|
+
};
|
|
993
|
+
const result = validateWorkflow(workflow);
|
|
994
|
+
assert.strictEqual(result.valid, false, 'Should reject teammate without agent');
|
|
995
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[0].agent') && e.message.includes('required')), 'Should report agent is required');
|
|
996
|
+
});
|
|
997
|
+
it('should reject teammate entry with non-string agent', () => {
|
|
998
|
+
const workflow = {
|
|
999
|
+
workflow: {
|
|
1000
|
+
name: 'team-bad-agent-type',
|
|
1001
|
+
phases: [
|
|
1002
|
+
{
|
|
1003
|
+
name: 'green',
|
|
1004
|
+
agent: 'dev',
|
|
1005
|
+
team: {
|
|
1006
|
+
teammates: [
|
|
1007
|
+
{ agent: 123 }
|
|
1008
|
+
]
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
]
|
|
1012
|
+
}
|
|
1013
|
+
};
|
|
1014
|
+
const result = validateWorkflow(workflow);
|
|
1015
|
+
assert.strictEqual(result.valid, false, 'Should reject non-string agent');
|
|
1016
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[0].agent') && e.message.includes('string')), 'Should report agent must be a string');
|
|
1017
|
+
});
|
|
1018
|
+
// AC4: Schema validation: teammate agents must be valid agent names
|
|
1019
|
+
it('should reject teammate with invalid agent name', () => {
|
|
1020
|
+
const workflow = {
|
|
1021
|
+
workflow: {
|
|
1022
|
+
name: 'team-invalid-agent',
|
|
1023
|
+
phases: [
|
|
1024
|
+
{
|
|
1025
|
+
name: 'green',
|
|
1026
|
+
agent: 'dev',
|
|
1027
|
+
team: {
|
|
1028
|
+
teammates: [
|
|
1029
|
+
{ agent: 'not-a-real-agent', task: 'Do stuff' }
|
|
1030
|
+
]
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
]
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
1036
|
+
const result = validateWorkflow(workflow);
|
|
1037
|
+
assert.strictEqual(result.valid, false, 'Should reject invalid agent name');
|
|
1038
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[0].agent') &&
|
|
1039
|
+
e.message.includes('not-a-real-agent')), 'Should report the invalid agent name in error message');
|
|
1040
|
+
});
|
|
1041
|
+
it('should reject multiple invalid agent names with individual errors', () => {
|
|
1042
|
+
const workflow = {
|
|
1043
|
+
workflow: {
|
|
1044
|
+
name: 'team-multi-invalid',
|
|
1045
|
+
phases: [
|
|
1046
|
+
{
|
|
1047
|
+
name: 'green',
|
|
1048
|
+
agent: 'dev',
|
|
1049
|
+
team: {
|
|
1050
|
+
teammates: [
|
|
1051
|
+
{ agent: 'architect', task: 'Valid one' },
|
|
1052
|
+
{ agent: 'fake-agent', task: 'Invalid' },
|
|
1053
|
+
{ agent: 'also-fake', task: 'Also invalid' }
|
|
1054
|
+
]
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
]
|
|
1058
|
+
}
|
|
1059
|
+
};
|
|
1060
|
+
const result = validateWorkflow(workflow);
|
|
1061
|
+
assert.strictEqual(result.valid, false, 'Should reject with invalid agents');
|
|
1062
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[1].agent')), 'Should flag second teammate');
|
|
1063
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[2].agent')), 'Should flag third teammate');
|
|
1064
|
+
});
|
|
1065
|
+
it('should accept all valid main agent names as teammates', () => {
|
|
1066
|
+
// Every valid agent should work as a teammate
|
|
1067
|
+
const teammates = VALID_AGENT_NAMES.map(name => ({ agent: name, task: `Task for ${name}` }));
|
|
1068
|
+
const workflow = {
|
|
1069
|
+
workflow: {
|
|
1070
|
+
name: 'team-all-valid',
|
|
1071
|
+
phases: [
|
|
1072
|
+
{
|
|
1073
|
+
name: 'green',
|
|
1074
|
+
agent: 'dev',
|
|
1075
|
+
team: { teammates }
|
|
1076
|
+
}
|
|
1077
|
+
]
|
|
1078
|
+
}
|
|
1079
|
+
};
|
|
1080
|
+
const result = validateWorkflow(workflow);
|
|
1081
|
+
assert.strictEqual(result.valid, true, `Should accept all valid agent names: ${VALID_AGENT_NAMES.join(', ')}`);
|
|
1082
|
+
assert.strictEqual(result.workflow?.phases?.[0].team?.teammates.length, VALID_AGENT_NAMES.length);
|
|
1083
|
+
});
|
|
1084
|
+
it('should reject invalid display value', () => {
|
|
1085
|
+
const workflow = {
|
|
1086
|
+
workflow: {
|
|
1087
|
+
name: 'team-bad-display',
|
|
1088
|
+
phases: [
|
|
1089
|
+
{
|
|
1090
|
+
name: 'green',
|
|
1091
|
+
agent: 'dev',
|
|
1092
|
+
team: {
|
|
1093
|
+
teammates: [{ agent: 'architect' }],
|
|
1094
|
+
display: 'split-screen'
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
]
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
const result = validateWorkflow(workflow);
|
|
1101
|
+
assert.strictEqual(result.valid, false, 'Should reject invalid display value');
|
|
1102
|
+
assert.ok(result.errors?.some(e => e.field?.includes('team.display')), 'Should report invalid display');
|
|
1103
|
+
});
|
|
1104
|
+
it('should reject non-string model value', () => {
|
|
1105
|
+
const workflow = {
|
|
1106
|
+
workflow: {
|
|
1107
|
+
name: 'team-bad-model',
|
|
1108
|
+
phases: [
|
|
1109
|
+
{
|
|
1110
|
+
name: 'green',
|
|
1111
|
+
agent: 'dev',
|
|
1112
|
+
team: {
|
|
1113
|
+
teammates: [{ agent: 'architect' }],
|
|
1114
|
+
model: 42
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
]
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
const result = validateWorkflow(workflow);
|
|
1121
|
+
assert.strictEqual(result.valid, false, 'Should reject non-string model');
|
|
1122
|
+
assert.ok(result.errors?.some(e => e.field?.includes('team.model') && e.message.includes('string')), 'Should report model must be a string');
|
|
1123
|
+
});
|
|
1124
|
+
it('should reject non-string task value', () => {
|
|
1125
|
+
const workflow = {
|
|
1126
|
+
workflow: {
|
|
1127
|
+
name: 'team-bad-task',
|
|
1128
|
+
phases: [
|
|
1129
|
+
{
|
|
1130
|
+
name: 'green',
|
|
1131
|
+
agent: 'dev',
|
|
1132
|
+
team: {
|
|
1133
|
+
teammates: [
|
|
1134
|
+
{ agent: 'architect', task: 123 }
|
|
1135
|
+
]
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
]
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
const result = validateWorkflow(workflow);
|
|
1142
|
+
assert.strictEqual(result.valid, false, 'Should reject non-string task');
|
|
1143
|
+
assert.ok(result.errors?.some(e => e.field?.includes('teammates[0].task') && e.message.includes('string')), 'Should report task must be a string');
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
// ========================================================================
|
|
1147
|
+
// AC6: Backward compatible: phases without team: unchanged
|
|
1148
|
+
// ========================================================================
|
|
1149
|
+
describe('Backward compatibility', () => {
|
|
1150
|
+
it('should validate existing workflows without team blocks unchanged', () => {
|
|
1151
|
+
const workflow = {
|
|
1152
|
+
workflow: {
|
|
1153
|
+
name: 'tdd',
|
|
1154
|
+
description: 'Standard TDD workflow',
|
|
1155
|
+
phases: [
|
|
1156
|
+
{ name: 'setup', agent: 'sm' },
|
|
1157
|
+
{ name: 'red', agent: 'tea', gate: { type: 'tests_fail' } },
|
|
1158
|
+
{ name: 'green', agent: 'dev', gate: { type: 'tests_pass' } },
|
|
1159
|
+
{ name: 'review', agent: 'reviewer', gate: { type: 'approval' } },
|
|
1160
|
+
{ name: 'finish', agent: 'sm' }
|
|
1161
|
+
]
|
|
1162
|
+
}
|
|
1163
|
+
};
|
|
1164
|
+
const result = validateWorkflow(workflow);
|
|
1165
|
+
assert.strictEqual(result.valid, true, 'Existing workflow without team should still validate');
|
|
1166
|
+
assert.strictEqual(result.workflow?.phases?.length, 5);
|
|
1167
|
+
});
|
|
1168
|
+
it('should have undefined team on phases without team block', () => {
|
|
1169
|
+
const workflow = {
|
|
1170
|
+
workflow: {
|
|
1171
|
+
name: 'no-team',
|
|
1172
|
+
phases: [
|
|
1173
|
+
{ name: 'work', agent: 'dev' }
|
|
1174
|
+
]
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
const result = validateWorkflow(workflow);
|
|
1178
|
+
assert.strictEqual(result.valid, true);
|
|
1179
|
+
assert.strictEqual(result.workflow?.phases?.[0].team, undefined, 'Phase without team should have undefined team');
|
|
1180
|
+
});
|
|
1181
|
+
it('should validate tdd-tandem workflow with tandem but no team unchanged', () => {
|
|
1182
|
+
const workflow = {
|
|
1183
|
+
workflow: {
|
|
1184
|
+
name: 'tdd-tandem',
|
|
1185
|
+
phases: [
|
|
1186
|
+
{ name: 'setup', agent: 'sm' },
|
|
1187
|
+
{
|
|
1188
|
+
name: 'red', agent: 'tea',
|
|
1189
|
+
gate: { type: 'tests_fail' },
|
|
1190
|
+
tandem: { partner: 'architect', scope: 'file-watch' }
|
|
1191
|
+
},
|
|
1192
|
+
{
|
|
1193
|
+
name: 'green', agent: 'dev',
|
|
1194
|
+
gate: { type: 'tests_pass' },
|
|
1195
|
+
tandem: { partner: 'architect', scope: 'file-watch' }
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
name: 'review', agent: 'reviewer',
|
|
1199
|
+
gate: { type: 'approval' },
|
|
1200
|
+
tandem: { partner: 'pm', scope: 'file-watch' }
|
|
1201
|
+
},
|
|
1202
|
+
{ name: 'finish', agent: 'sm' }
|
|
1203
|
+
]
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
const result = validateWorkflow(workflow);
|
|
1207
|
+
assert.strictEqual(result.valid, true, 'tdd-tandem without team blocks should validate');
|
|
1208
|
+
// Tandem should be preserved, team should be undefined
|
|
1209
|
+
assert.ok(result.workflow?.phases?.[1].tandem, 'Tandem should be preserved on red phase');
|
|
1210
|
+
assert.strictEqual(result.workflow?.phases?.[1].team, undefined, 'Team should be undefined when not specified');
|
|
1211
|
+
});
|
|
1212
|
+
});
|
|
1213
|
+
// ========================================================================
|
|
1214
|
+
// AC7: workflow-status-check subagent reports team configuration per phase
|
|
1215
|
+
// (Tests verify team config is accessible from parsed workflow output)
|
|
1216
|
+
// ========================================================================
|
|
1217
|
+
describe('Team configuration reporting', () => {
|
|
1218
|
+
it('should expose complete team config in parsed workflow for status reporting', () => {
|
|
1219
|
+
const workflow = {
|
|
1220
|
+
workflow: {
|
|
1221
|
+
name: 'tdd-team',
|
|
1222
|
+
phases: [
|
|
1223
|
+
{ name: 'setup', agent: 'sm' },
|
|
1224
|
+
{
|
|
1225
|
+
name: 'red', agent: 'tea',
|
|
1226
|
+
team: {
|
|
1227
|
+
teammates: [
|
|
1228
|
+
{ agent: 'architect', task: 'Review test strategy' }
|
|
1229
|
+
],
|
|
1230
|
+
model: 'haiku',
|
|
1231
|
+
display: 'in-process'
|
|
1232
|
+
}
|
|
1233
|
+
},
|
|
1234
|
+
{
|
|
1235
|
+
name: 'green', agent: 'dev',
|
|
1236
|
+
team: {
|
|
1237
|
+
teammates: [
|
|
1238
|
+
{ agent: 'architect', task: 'Guide patterns' },
|
|
1239
|
+
{ agent: 'tea', task: 'Monitor coverage' }
|
|
1240
|
+
],
|
|
1241
|
+
model: 'sonnet'
|
|
1242
|
+
}
|
|
1243
|
+
},
|
|
1244
|
+
{ name: 'review', agent: 'reviewer' },
|
|
1245
|
+
{ name: 'finish', agent: 'sm' }
|
|
1246
|
+
]
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
const result = validateWorkflow(workflow);
|
|
1250
|
+
assert.strictEqual(result.valid, true, 'Team workflow should validate');
|
|
1251
|
+
// Verify phases WITHOUT team have no team config
|
|
1252
|
+
assert.strictEqual(result.workflow?.phases?.[0].team, undefined, 'setup has no team');
|
|
1253
|
+
assert.strictEqual(result.workflow?.phases?.[3].team, undefined, 'review has no team');
|
|
1254
|
+
assert.strictEqual(result.workflow?.phases?.[4].team, undefined, 'finish has no team');
|
|
1255
|
+
// Verify phases WITH team have complete config accessible
|
|
1256
|
+
const redTeam = result.workflow?.phases?.[1].team;
|
|
1257
|
+
assert.ok(redTeam, 'red phase should have team config');
|
|
1258
|
+
assert.strictEqual(redTeam?.teammates.length, 1);
|
|
1259
|
+
assert.strictEqual(redTeam?.teammates[0].agent, 'architect');
|
|
1260
|
+
assert.strictEqual(redTeam?.teammates[0].task, 'Review test strategy');
|
|
1261
|
+
assert.strictEqual(redTeam?.model, 'haiku');
|
|
1262
|
+
assert.strictEqual(redTeam?.display, 'in-process');
|
|
1263
|
+
const greenTeam = result.workflow?.phases?.[2].team;
|
|
1264
|
+
assert.ok(greenTeam, 'green phase should have team config');
|
|
1265
|
+
assert.strictEqual(greenTeam?.teammates.length, 2);
|
|
1266
|
+
assert.strictEqual(greenTeam?.teammates[0].agent, 'architect');
|
|
1267
|
+
assert.strictEqual(greenTeam?.teammates[1].agent, 'tea');
|
|
1268
|
+
assert.strictEqual(greenTeam?.model, 'sonnet');
|
|
1269
|
+
assert.strictEqual(greenTeam?.display, undefined, 'display should be undefined when not set');
|
|
1270
|
+
});
|
|
1271
|
+
});
|
|
1272
|
+
});
|
|
704
1273
|
//# sourceMappingURL=workflow-schema.test.js.map
|