@pennyfarthing/core 11.1.0 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/README.md +8 -8
  2. package/package.json +16 -14
  3. package/packages/core/dist/cli/utils/constants.d.ts +1 -1
  4. package/packages/core/dist/cli/utils/constants.d.ts.map +1 -1
  5. package/packages/core/dist/cli/utils/constants.js +2 -1
  6. package/packages/core/dist/cli/utils/constants.js.map +1 -1
  7. package/packages/core/dist/consultation/dialogue-manager.d.ts +75 -0
  8. package/packages/core/dist/consultation/dialogue-manager.d.ts.map +1 -0
  9. package/packages/core/dist/consultation/dialogue-manager.js +334 -0
  10. package/packages/core/dist/consultation/dialogue-manager.js.map +1 -0
  11. package/packages/core/dist/consultation/dialogue-manager.test.d.ts +19 -0
  12. package/packages/core/dist/consultation/dialogue-manager.test.d.ts.map +1 -0
  13. package/packages/core/dist/consultation/dialogue-manager.test.js +444 -0
  14. package/packages/core/dist/consultation/dialogue-manager.test.js.map +1 -0
  15. package/packages/core/dist/server/api/git.d.ts +13 -1
  16. package/packages/core/dist/server/api/git.d.ts.map +1 -1
  17. package/packages/core/dist/server/api/git.js +53 -34
  18. package/packages/core/dist/server/api/git.js.map +1 -1
  19. package/packages/core/dist/server/otlp-receiver.d.ts +16 -11
  20. package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -1
  21. package/packages/core/dist/server/otlp-receiver.js +185 -24
  22. package/packages/core/dist/server/otlp-receiver.js.map +1 -1
  23. package/packages/core/dist/server/otlp-receiver.test.d.ts +21 -0
  24. package/packages/core/dist/server/otlp-receiver.test.d.ts.map +1 -0
  25. package/packages/core/dist/server/otlp-receiver.test.js +446 -0
  26. package/packages/core/dist/server/otlp-receiver.test.js.map +1 -0
  27. package/packages/core/dist/shared/portrait-resolver.d.ts +9 -0
  28. package/packages/core/dist/shared/portrait-resolver.d.ts.map +1 -1
  29. package/packages/core/dist/shared/portrait-resolver.js +27 -0
  30. package/packages/core/dist/shared/portrait-resolver.js.map +1 -1
  31. package/packages/core/dist/shared/portrait-resolver.test.js +47 -1
  32. package/packages/core/dist/shared/portrait-resolver.test.js.map +1 -1
  33. package/packages/core/dist/shared/skill-search.test.js +2 -2
  34. package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts +13 -0
  35. package/packages/core/dist/shared/tandem-portrait-inventory.test.d.ts.map +1 -0
  36. package/packages/core/dist/shared/tandem-portrait-inventory.test.js +126 -0
  37. package/packages/core/dist/shared/tandem-portrait-inventory.test.js.map +1 -0
  38. package/pennyfarthing-dist/agents/dev.md +1 -1
  39. package/pennyfarthing-dist/agents/reviewer.md +1 -1
  40. package/pennyfarthing-dist/agents/sm-setup.md +1 -1
  41. package/pennyfarthing-dist/agents/sm.md +2 -2
  42. package/pennyfarthing-dist/agents/tea.md +1 -1
  43. package/pennyfarthing-dist/agents/testing-runner.md +2 -1
  44. package/pennyfarthing-dist/commands/pf-chore.md +2 -2
  45. package/pennyfarthing-dist/commands/pf-standalone.md +7 -2
  46. package/pennyfarthing-dist/guides/agent-behavior.md +1 -1
  47. package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +1 -1
  48. package/pennyfarthing-dist/guides/bikerack.md +3 -3
  49. package/pennyfarthing-dist/guides/hooks.md +1 -1
  50. package/pennyfarthing-dist/guides/worktree-mode.md +3 -3
  51. package/pennyfarthing-dist/guides/xml-tags.md +2 -2
  52. package/pennyfarthing-dist/scripts/README.md +1 -1
  53. package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
  54. package/pennyfarthing-dist/scripts/core/check-context.sh +1 -1
  55. package/pennyfarthing-dist/scripts/core/dialogue-manager.sh +322 -0
  56. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
  57. package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
  58. package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
  59. package/pennyfarthing-dist/scripts/git/README.md +24 -14
  60. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +5 -266
  61. package/pennyfarthing-dist/scripts/git/git-status-all.sh +5 -151
  62. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +6 -144
  63. package/pennyfarthing-dist/scripts/git/release.sh +0 -0
  64. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +5 -496
  65. package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
  66. package/pennyfarthing-dist/scripts/hooks/README.md +1 -1
  67. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +1 -1
  68. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
  69. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
  70. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  71. package/pennyfarthing-dist/scripts/hooks/dispatcher-template.sh +0 -0
  72. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +9 -11
  73. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
  74. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
  75. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
  76. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
  77. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
  78. package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
  79. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
  80. package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
  81. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
  82. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
  83. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +1 -1
  84. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
  85. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
  86. package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
  87. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
  88. package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
  89. package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
  90. package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
  91. package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
  92. package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
  93. package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
  94. package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
  95. package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
  96. package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
  97. package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
  98. package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
  99. package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
  100. package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
  101. package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
  102. package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
  103. package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
  104. package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
  105. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
  106. package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
  107. package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
  108. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
  109. package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
  110. package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
  111. package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
  112. package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
  113. package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
  114. package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
  115. package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
  116. package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
  117. package/pennyfarthing-dist/scripts/portraits/generate-tandem-portraits.sh +76 -0
  118. package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
  119. package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
  120. package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
  121. package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
  122. package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
  123. package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
  124. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
  125. package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
  126. package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
  127. package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
  128. package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
  129. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
  130. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
  131. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
  132. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
  133. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
  134. package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
  135. package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
  136. package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
  137. package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
  138. package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
  139. package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
  140. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
  141. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +4 -221
  142. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
  143. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +5 -13
  144. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +4 -123
  145. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +4 -33
  146. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +4 -156
  147. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +4 -131
  148. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +4 -249
  149. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +4 -160
  150. package/pennyfarthing-dist/skills/pf-bc/usage.md +1 -1
  151. package/pennyfarthing-dist/skills/pf-jira/examples.md +5 -2
  152. package/pennyfarthing-dist/skills/pf-story/scripts/create-story.sh +0 -0
  153. package/pennyfarthing-dist/skills/pf-story/scripts/size-story.sh +0 -0
  154. package/pennyfarthing-dist/skills/pf-story/scripts/story-template.sh +0 -0
  155. package/pennyfarthing-dist/skills/pf-workflow/examples.md +27 -16
  156. package/pennyfarthing-dist/skills/pf-workflow/skill.md +9 -12
  157. package/pennyfarthing-dist/skills/pf-workflow/usage.md +33 -8
  158. package/pennyfarthing-dist/workflows/bdd-tandem.yaml +18 -6
  159. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-01-analyze.md +1 -1
  160. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-04-verify.md +1 -1
  161. package/pennyfarthing-dist/workflows/git-cleanup/steps/step-05-complete.md +1 -1
  162. package/pennyfarthing-dist/workflows/review-tandem.yaml +65 -0
  163. package/pennyfarthing-dist/workflows/tdd-tandem.yaml +16 -8
  164. package/pennyfarthing_scripts/CLAUDE.md +26 -4
  165. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  166. package/pennyfarthing_scripts/__pycache__/hooks.cpython-314.pyc +0 -0
  167. package/pennyfarthing_scripts/__pycache__/pretooluse_hook.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/bc/cli.py +3 -5
  171. package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/bikerack/__pycache__/debug_panel.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/bikerack/__pycache__/portrait.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/bikerack/__pycache__/progress_panel.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
  184. package/pennyfarthing_scripts/bikerack/background_panel.py +86 -5
  185. package/pennyfarthing_scripts/bikerack/base_panel.py +62 -0
  186. package/pennyfarthing_scripts/bikerack/changed_panel.py +32 -28
  187. package/pennyfarthing_scripts/bikerack/cli.py +10 -11
  188. package/pennyfarthing_scripts/bikerack/debug_panel.py +31 -1
  189. package/pennyfarthing_scripts/bikerack/diffs_panel.py +74 -17
  190. package/pennyfarthing_scripts/bikerack/git_panel.py +103 -33
  191. package/pennyfarthing_scripts/bikerack/launcher.py +15 -15
  192. package/pennyfarthing_scripts/bikerack/progress_panel.py +315 -0
  193. package/pennyfarthing_scripts/bikerack/sprint_panel.py +158 -26
  194. package/pennyfarthing_scripts/bikerack/tui.py +336 -30
  195. package/pennyfarthing_scripts/bikerack/ws_client.py +2 -2
  196. package/pennyfarthing_scripts/cli.py +37 -65
  197. package/pennyfarthing_scripts/consultation/__init__.py +1 -0
  198. package/pennyfarthing_scripts/consultation/__pycache__/__init__.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/consultation/__pycache__/cli.cpython-314.pyc +0 -0
  200. package/pennyfarthing_scripts/consultation/cli.py +149 -0
  201. package/pennyfarthing_scripts/consultation/dialogue_manager.py +417 -0
  202. package/pennyfarthing_scripts/context.py +3 -3
  203. package/pennyfarthing_scripts/epic/__pycache__/__init__.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/epic/__pycache__/cli.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/git/__init__.py +12 -1
  206. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  207. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  208. package/pennyfarthing_scripts/git/__pycache__/hooks_installer.cpython-314.pyc +0 -0
  209. package/pennyfarthing_scripts/git/__pycache__/repos.cpython-314.pyc +0 -0
  210. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  211. package/pennyfarthing_scripts/git/__pycache__/worktree.cpython-314.pyc +0 -0
  212. package/pennyfarthing_scripts/git/create_branches.py +3 -4
  213. package/pennyfarthing_scripts/git/hooks_installer.py +152 -0
  214. package/pennyfarthing_scripts/git/repos.py +196 -0
  215. package/pennyfarthing_scripts/git/status_all.py +27 -11
  216. package/pennyfarthing_scripts/git/worktree.py +302 -0
  217. package/pennyfarthing_scripts/git_group/__pycache__/__init__.cpython-314.pyc +0 -0
  218. package/pennyfarthing_scripts/git_group/__pycache__/cli.cpython-314.pyc +0 -0
  219. package/pennyfarthing_scripts/git_group/cli.py +143 -40
  220. package/pennyfarthing_scripts/handoff/__pycache__/__init__.cpython-314.pyc +0 -0
  221. package/pennyfarthing_scripts/handoff/__pycache__/cli.cpython-314.pyc +0 -0
  222. package/pennyfarthing_scripts/handoff/__pycache__/complete_phase.cpython-314.pyc +0 -0
  223. package/pennyfarthing_scripts/handoff/__pycache__/resolve_gate.cpython-314.pyc +0 -0
  224. package/pennyfarthing_scripts/handoff/complete_phase.py +12 -0
  225. package/pennyfarthing_scripts/handoff/resolve_gate.py +5 -14
  226. package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  227. package/pennyfarthing_scripts/hooks.py +3 -17
  228. package/pennyfarthing_scripts/pretooluse_hook.py +1 -1
  229. package/pennyfarthing_scripts/prime/__pycache__/heatmap.cpython-314.pyc +0 -0
  230. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  231. package/pennyfarthing_scripts/prime/heatmap.py +655 -0
  232. package/pennyfarthing_scripts/session/__pycache__/__init__.cpython-314.pyc +0 -0
  233. package/pennyfarthing_scripts/session/__pycache__/cli.cpython-314.pyc +0 -0
  234. package/pennyfarthing_scripts/session_start_hook.py +1 -1
  235. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  236. package/pennyfarthing_scripts/sprint/loader.py +15 -1
  237. package/pennyfarthing_scripts/sprint/story_finish.py +14 -0
  238. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_cli.cpython-314-pytest-9.0.2.pyc +0 -0
  239. package/pennyfarthing_scripts/tests/__pycache__/test_handoff_e2e.cpython-314-pytest-9.0.2.pyc +0 -0
  240. package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
  241. package/pennyfarthing_scripts/tests/test_bikerack.py +51 -51
  242. package/pennyfarthing_scripts/tests/test_dialogue_manager.py +811 -0
  243. package/pennyfarthing_scripts/tests/test_handoff_cli.py +16 -11
  244. package/pennyfarthing_scripts/tests/test_workflow_check.py +2 -3
  245. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  246. package/pennyfarthing_scripts/validate/adapters/tandem_awareness.py +254 -0
  247. package/pennyfarthing_scripts/validate/cli.py +17 -5
  248. package/pennyfarthing_scripts/workflow/__init__.py +40 -0
  249. package/pennyfarthing_scripts/workflow/__pycache__/__init__.cpython-314.pyc +0 -0
  250. package/pennyfarthing_scripts/workflow/__pycache__/cli.cpython-314.pyc +0 -0
  251. package/pennyfarthing_scripts/workflow/__pycache__/helpers.cpython-314.pyc +0 -0
  252. package/pennyfarthing_scripts/workflow/__pycache__/scale.cpython-314.pyc +0 -0
  253. package/pennyfarthing_scripts/workflow/__pycache__/state.cpython-314.pyc +0 -0
  254. package/pennyfarthing_scripts/workflow/cli.py +1099 -0
  255. package/pennyfarthing_scripts/workflow/helpers.py +241 -0
  256. package/pennyfarthing_scripts/{workflow.py → workflow/scale.py} +0 -104
  257. package/pennyfarthing_scripts/workflow/state.py +112 -0
  258. package/scripts/README.md +41 -0
  259. package/pennyfarthing-dist/skills/pf-workflow/scripts/list-workflows.sh +0 -91
  260. package/pennyfarthing-dist/skills/pf-workflow/scripts/resume-workflow.sh +0 -163
  261. package/pennyfarthing-dist/skills/pf-workflow/scripts/show-workflow.sh +0 -138
  262. package/pennyfarthing-dist/skills/pf-workflow/scripts/start-workflow.sh +0 -273
  263. package/pennyfarthing-dist/skills/pf-workflow/scripts/workflow-status.sh +0 -167
@@ -75,14 +75,14 @@ class WheelHubClient:
75
75
  cb(new_state)
76
76
 
77
77
  def discover_port(self) -> int:
78
- """Read port from .bikerack-port file, fallback to DEFAULT_PORT.
78
+ """Read port from .wheelhub-port file, fallback to DEFAULT_PORT.
79
79
 
80
80
  Priority: explicit port > port file > DEFAULT_PORT.
81
81
  """
82
82
  if self._port is not None:
83
83
  return self._port
84
84
  if self._project_dir is not None:
85
- port_file = self._project_dir / ".bikerack-port"
85
+ port_file = self._project_dir / ".wheelhub-port"
86
86
  if port_file.exists():
87
87
  try:
88
88
  return int(port_file.read_text().strip())
@@ -137,6 +137,11 @@ from pennyfarthing_scripts.epic.cli import epic # noqa: E402
137
137
 
138
138
  cli.add_command(epic)
139
139
 
140
+ # Import and register consultation group
141
+ from pennyfarthing_scripts.consultation.cli import consultation # noqa: E402
142
+
143
+ cli.add_command(consultation)
144
+
140
145
 
141
146
  @cli.group()
142
147
  def agent():
@@ -144,7 +149,8 @@ def agent():
144
149
 
145
150
  \b
146
151
  Commands:
147
- start - Start an agent session with context
152
+ start - Start an agent session with context
153
+ heatmap - Visualize context distribution and attention
148
154
  """
149
155
  pass
150
156
 
@@ -193,78 +199,44 @@ def agent_start(
193
199
  raise SystemExit(exit_code)
194
200
 
195
201
 
196
- @cli.group()
197
- def workflow():
198
- """Workflow state and phase management.
199
-
200
- \b
201
- Commands:
202
- check - Check current workflow state
203
- phase-check - Verify phase ownership
204
- handoff - Emit handoff marker
205
- """
206
- pass
207
-
208
-
209
- @workflow.command("check")
210
- @click.option("--json", "output_json", is_flag=True, help="Output as JSON")
211
- def workflow_check(output_json: bool):
212
- """Check current workflow state.
213
-
214
- Returns the current story ID, phase, and workflow state.
215
- """
216
- # Lazy import - only load when command is actually invoked
217
- from pennyfarthing_scripts.workflow import get_workflow_state
218
-
219
- state = get_workflow_state()
220
-
221
- if output_json:
222
- import json
223
-
224
- click.echo(json.dumps(state, indent=2))
225
- else:
226
- click.echo(f"State: {state.get('state', 'unknown')}")
227
- if state.get("story_id"):
228
- click.echo(f"Story: {state['story_id']}")
229
- if state.get("workflow"):
230
- click.echo(f"Workflow: {state['workflow']}")
231
- if state.get("phase"):
232
- click.echo(f"Phase: {state['phase']}")
233
-
202
+ @agent.command("heatmap")
203
+ @click.argument("name", required=False)
204
+ @click.option("--all", "show_all", is_flag=True, help="Show summary across all primary agents")
205
+ @click.option("--csv", "csv_output", is_flag=True, help="Output CSV for machine consumption")
206
+ @click.option("--json", "json_output", is_flag=True, help="Output JSON")
207
+ def agent_heatmap(
208
+ name: str | None,
209
+ show_all: bool,
210
+ csv_output: bool,
211
+ json_output: bool,
212
+ ):
213
+ """Visualize context distribution and attention for agent activation.
234
214
 
235
- @workflow.command("phase-check")
236
- @click.argument("workflow_name")
237
- @click.argument("phase")
238
- def workflow_phase_check(workflow_name: str, phase: str):
239
- """Check which agent owns a workflow phase.
215
+ Shows a heat map of how tokens are distributed across sections of an
216
+ agent's activation context, with attention scores based on the
217
+ "Lost in the Middle" U-shaped attention model.
240
218
 
241
219
  \b
242
- Arguments:
243
- WORKFLOW_NAME - The workflow type (tdd, trivial, etc.)
244
- PHASE - The phase to check (red, implement, review, etc.)
220
+ Examples:
221
+ pf agent heatmap sm # Detailed view for SM
222
+ pf agent heatmap --all # Summary across all agents
223
+ pf agent heatmap dev --json # JSON output for tooling
245
224
  """
246
- # Lazy import
247
- from pennyfarthing_scripts.workflow import get_phase_owner
225
+ from pennyfarthing_scripts.prime.heatmap import run_heatmap
248
226
 
249
- owner = get_phase_owner(workflow_name, phase)
250
- click.echo(owner)
227
+ exit_code = run_heatmap(
228
+ agent_name=name,
229
+ show_all=show_all,
230
+ csv_output=csv_output,
231
+ json_output=json_output,
232
+ )
233
+ raise SystemExit(exit_code)
251
234
 
252
235
 
253
- @workflow.command("handoff")
254
- @click.argument("next_agent")
255
- def workflow_handoff(next_agent: str):
256
- """Emit a handoff marker for Cyclist.
236
+ # Import and register workflow group
237
+ from pennyfarthing_scripts.workflow.cli import workflow # noqa: E402
257
238
 
258
- \b
259
- Arguments:
260
- NEXT_AGENT - The agent to hand off to (tea, dev, reviewer, etc.)
261
- """
262
- # Output the marker format expected by Cyclist
263
- click.echo("---")
264
- click.echo("AGENT_COMMAND:")
265
- click.echo(f' marker: "<!-- CYCLIST:HANDOFF:/{next_agent} -->"')
266
- click.echo(f' fallback: "Run `/{next_agent}` to continue"')
267
- click.echo("---")
239
+ cli.add_command(workflow)
268
240
 
269
241
 
270
242
  @cli.command("help")
@@ -0,0 +1 @@
1
+ """Consultation package — Dialogue file management for tandem agent consultation."""
@@ -0,0 +1,149 @@
1
+ """Click CLI for consultation dialogue management.
2
+
3
+ Provides `pf consultation` group with subcommands matching
4
+ the bash wrapper dialogue-manager.sh interface.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from datetime import datetime, timezone
10
+ from pathlib import Path
11
+
12
+ import click
13
+
14
+
15
+ @click.group()
16
+ def consultation():
17
+ """Tandem consultation dialogue management.
18
+
19
+ \b
20
+ Subcommands:
21
+ init - Create dialogue file
22
+ append - Append exchange
23
+ outcome - Update outcome
24
+ summarize - Refresh summary
25
+ archive - Archive dialogue file
26
+ """
27
+ pass
28
+
29
+
30
+ @consultation.command()
31
+ @click.argument("story_id")
32
+ @click.argument("workflow")
33
+ @click.argument("leader")
34
+ @click.argument("partner")
35
+ def init(story_id: str, workflow: str, leader: str, partner: str) -> None:
36
+ """Create a new dialogue file."""
37
+ from pennyfarthing_scripts.consultation.dialogue_manager import (
38
+ DialogueHeader,
39
+ create_dialogue_content,
40
+ )
41
+
42
+ header = DialogueHeader(
43
+ story_id=story_id,
44
+ workflow=workflow,
45
+ leader=leader,
46
+ partner=partner,
47
+ started_at=datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
48
+ )
49
+
50
+ content = create_dialogue_content(header)
51
+ session_dir = Path(".session")
52
+ session_dir.mkdir(parents=True, exist_ok=True)
53
+ dialogue_path = session_dir / f"{story_id}-dialogue.md"
54
+ dialogue_path.write_text(content, encoding="utf-8")
55
+
56
+ click.echo(f"Created {dialogue_path}")
57
+
58
+
59
+ @consultation.command()
60
+ @click.argument("story_id")
61
+ @click.argument("question")
62
+ @click.argument("recommendation")
63
+ @click.argument("confidence")
64
+ def append(story_id: str, question: str, recommendation: str, confidence: str) -> None:
65
+ """Append an exchange to a dialogue file."""
66
+ from pennyfarthing_scripts.consultation.dialogue_manager import (
67
+ DialogueExchange,
68
+ append_exchange_to_file,
69
+ parse_dialogue_exchanges,
70
+ )
71
+
72
+ dialogue_path = Path(".session") / f"{story_id}-dialogue.md"
73
+ if not dialogue_path.exists():
74
+ click.echo(f"Dialogue file not found: {dialogue_path}", err=True)
75
+ raise SystemExit(1)
76
+
77
+ content = dialogue_path.read_text(encoding="utf-8")
78
+ existing = parse_dialogue_exchanges(content)
79
+ next_num = len(existing) + 1
80
+
81
+ exchange = DialogueExchange(
82
+ number=next_num,
83
+ timestamp=datetime.now(timezone.utc).strftime("%H:%M"),
84
+ leader="",
85
+ partner="",
86
+ question=question,
87
+ recommendation=recommendation,
88
+ confidence=confidence,
89
+ )
90
+
91
+ result = append_exchange_to_file(dialogue_path, exchange)
92
+ if result.success:
93
+ click.echo(f"Appended exchange {next_num}")
94
+ else:
95
+ click.echo(f"Error: {result.error}", err=True)
96
+ raise SystemExit(1)
97
+
98
+
99
+ @consultation.command()
100
+ @click.argument("story_id")
101
+ @click.argument("exchange_num", type=int)
102
+ @click.argument("outcome_value")
103
+ @click.option("--note", default=None, help="Outcome note")
104
+ def outcome(story_id: str, exchange_num: int, outcome_value: str, note: str | None) -> None:
105
+ """Update outcome of an exchange."""
106
+ from pennyfarthing_scripts.consultation.dialogue_manager import (
107
+ update_outcome_in_file,
108
+ )
109
+
110
+ dialogue_path = Path(".session") / f"{story_id}-dialogue.md"
111
+ result = update_outcome_in_file(dialogue_path, exchange_num, outcome_value, note) # type: ignore[arg-type]
112
+ if result.success:
113
+ click.echo(f"Updated exchange {exchange_num} outcome to {outcome_value}")
114
+ else:
115
+ click.echo(f"Error: {result.error}", err=True)
116
+ raise SystemExit(1)
117
+
118
+
119
+ @consultation.command()
120
+ @click.argument("story_id")
121
+ def summarize(story_id: str) -> None:
122
+ """Refresh dialogue summary."""
123
+ from pennyfarthing_scripts.consultation.dialogue_manager import refresh_summary
124
+
125
+ dialogue_path = Path(".session") / f"{story_id}-dialogue.md"
126
+ result = refresh_summary(dialogue_path)
127
+ if result.success:
128
+ total = result.data.get("totalExchanges", 0) if result.data else 0
129
+ click.echo(f"Summary refreshed ({total} exchanges)")
130
+ else:
131
+ click.echo(f"Error: {result.error}", err=True)
132
+ raise SystemExit(1)
133
+
134
+
135
+ @consultation.command()
136
+ @click.argument("story_id")
137
+ @click.option("--jira-key", default=None, help="Jira key for archive filename")
138
+ def archive(story_id: str, jira_key: str | None) -> None:
139
+ """Archive dialogue file."""
140
+ from pennyfarthing_scripts.consultation.dialogue_manager import archive_dialogue
141
+
142
+ dialogue_path = Path(".session") / f"{story_id}-dialogue.md"
143
+ archive_dir = Path(".session") / "archive"
144
+ result = archive_dialogue(dialogue_path, archive_dir, jira_key=jira_key, story_id=story_id)
145
+ if result.success:
146
+ click.echo(f"Archived to {result.data.get('archivePath', archive_dir)}" if result.data else "Archived")
147
+ else:
148
+ click.echo(f"Error: {result.error}", err=True)
149
+ raise SystemExit(1)