@pennyfarthing/core 10.3.0 → 10.4.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 (206) hide show
  1. package/README.md +3 -3
  2. package/package.json +14 -16
  3. package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
  4. package/packages/core/dist/cli/commands/init.js +3 -0
  5. package/packages/core/dist/cli/commands/init.js.map +1 -1
  6. package/packages/core/dist/cli/commands/update.d.ts.map +1 -1
  7. package/packages/core/dist/cli/commands/update.js +62 -122
  8. package/packages/core/dist/cli/commands/update.js.map +1 -1
  9. package/packages/core/dist/cli/commands/version-sentinel.test.d.ts +18 -0
  10. package/packages/core/dist/cli/commands/version-sentinel.test.d.ts.map +1 -0
  11. package/packages/core/dist/cli/commands/version-sentinel.test.js +120 -0
  12. package/packages/core/dist/cli/commands/version-sentinel.test.js.map +1 -0
  13. package/packages/core/dist/cli/utils/manifest.d.ts +1 -0
  14. package/packages/core/dist/cli/utils/manifest.d.ts.map +1 -1
  15. package/packages/core/dist/cli/utils/manifest.js.map +1 -1
  16. package/packages/core/dist/cli/utils/migrations.d.ts +88 -0
  17. package/packages/core/dist/cli/utils/migrations.d.ts.map +1 -0
  18. package/packages/core/dist/cli/utils/migrations.js +105 -0
  19. package/packages/core/dist/cli/utils/migrations.js.map +1 -0
  20. package/packages/core/dist/cli/utils/migrations.test.d.ts +23 -0
  21. package/packages/core/dist/cli/utils/migrations.test.d.ts.map +1 -0
  22. package/packages/core/dist/cli/utils/migrations.test.js +319 -0
  23. package/packages/core/dist/cli/utils/migrations.test.js.map +1 -0
  24. package/packages/core/dist/cli/utils/version-sentinel.d.ts +32 -0
  25. package/packages/core/dist/cli/utils/version-sentinel.d.ts.map +1 -0
  26. package/packages/core/dist/cli/utils/version-sentinel.js +49 -0
  27. package/packages/core/dist/cli/utils/version-sentinel.js.map +1 -0
  28. package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -1
  29. package/packages/core/dist/scripts/generate-spider-report.js +2 -0
  30. package/packages/core/dist/scripts/generate-spider-report.js.map +1 -1
  31. package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -1
  32. package/packages/core/dist/scripts/generate-spider.js +1 -0
  33. package/packages/core/dist/scripts/generate-spider.js.map +1 -1
  34. package/packages/core/dist/workflow/context-watch.d.ts +81 -0
  35. package/packages/core/dist/workflow/context-watch.d.ts.map +1 -0
  36. package/packages/core/dist/workflow/context-watch.js +236 -0
  37. package/packages/core/dist/workflow/context-watch.js.map +1 -0
  38. package/packages/core/dist/workflow/context-watch.test.d.ts +2 -0
  39. package/packages/core/dist/workflow/context-watch.test.d.ts.map +1 -0
  40. package/packages/core/dist/workflow/context-watch.test.js +747 -0
  41. package/packages/core/dist/workflow/context-watch.test.js.map +1 -0
  42. package/pennyfarthing-dist/agents/dev.md +47 -0
  43. package/pennyfarthing-dist/personas/themes/fifth-element.yaml +0 -1
  44. package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
  45. package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
  46. package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
  47. package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
  48. package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
  49. package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
  50. package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
  51. package/pennyfarthing-dist/scripts/git/git-status-all.sh +0 -0
  52. package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +0 -0
  53. package/pennyfarthing-dist/scripts/git/release.sh +0 -0
  54. package/pennyfarthing-dist/scripts/git/worktree-manager.sh +0 -0
  55. package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
  56. package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
  57. package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
  58. package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
  59. package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  60. package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
  61. package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
  62. package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +0 -0
  63. package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
  64. package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
  65. package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
  66. package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
  67. package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
  68. package/pennyfarthing-dist/scripts/hooks/session-start.sh +0 -0
  69. package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
  70. package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
  71. package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
  72. package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
  73. package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
  74. package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
  75. package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
  76. package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
  77. package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
  78. package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
  79. package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
  80. package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
  81. package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
  82. package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
  83. package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
  84. package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
  85. package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
  86. package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
  87. package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
  88. package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
  89. package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
  90. package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
  91. package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
  92. package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
  93. package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
  94. package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
  95. package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
  96. package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
  97. package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
  98. package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
  99. package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
  100. package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
  101. package/pennyfarthing-dist/scripts/misc/statusline.sh +2 -0
  102. package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
  103. package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
  104. package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +0 -0
  105. package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
  106. package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
  107. package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
  108. package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
  109. package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
  110. package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
  111. package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
  112. package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
  113. package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
  114. package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
  115. package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
  116. package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
  117. package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
  118. package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
  119. package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
  120. package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
  121. package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
  122. package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
  123. package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
  124. package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
  125. package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
  126. package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
  127. package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
  128. package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
  129. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
  130. package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
  131. package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
  132. package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
  133. package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
  134. package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
  135. package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
  136. package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
  137. package/pennyfarthing-dist/skills/story/scripts/create-story.sh +0 -0
  138. package/pennyfarthing-dist/skills/story/scripts/size-story.sh +0 -0
  139. package/pennyfarthing-dist/skills/story/scripts/story-template.sh +0 -0
  140. package/pennyfarthing-dist/skills/workflow/scripts/list-workflows.sh +0 -0
  141. package/pennyfarthing-dist/skills/workflow/scripts/resume-workflow.sh +0 -0
  142. package/pennyfarthing-dist/skills/workflow/scripts/show-workflow.sh +0 -0
  143. package/pennyfarthing-dist/skills/workflow/scripts/start-workflow.sh +0 -0
  144. package/pennyfarthing-dist/skills/workflow/scripts/workflow-status.sh +0 -0
  145. package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
  146. package/pennyfarthing_scripts/__pycache__/schema_validation_hook.cpython-314.pyc +0 -0
  147. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  148. package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
  149. package/pennyfarthing_scripts/bikerack/__pycache__/__main__.cpython-314.pyc +0 -0
  150. package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
  151. package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
  152. package/pennyfarthing_scripts/codemarkers/__pycache__/__init__.cpython-314.pyc +0 -0
  153. package/pennyfarthing_scripts/codemarkers/__pycache__/analyze.cpython-314.pyc +0 -0
  154. package/pennyfarthing_scripts/codemarkers/__pycache__/cli.cpython-314.pyc +0 -0
  155. package/pennyfarthing_scripts/codemarkers/__pycache__/models.cpython-314.pyc +0 -0
  156. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  157. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  158. package/pennyfarthing_scripts/deadcode/__pycache__/cli.cpython-314.pyc +0 -0
  159. package/pennyfarthing_scripts/healthscore/__pycache__/__init__.cpython-314.pyc +0 -0
  160. package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
  161. package/pennyfarthing_scripts/healthscore/__pycache__/cli.cpython-314.pyc +0 -0
  162. package/pennyfarthing_scripts/healthscore/__pycache__/models.cpython-314.pyc +0 -0
  163. package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
  164. package/pennyfarthing_scripts/hotspots/__pycache__/__init__.cpython-314.pyc +0 -0
  165. package/pennyfarthing_scripts/hotspots/__pycache__/analyze.cpython-314.pyc +0 -0
  166. package/pennyfarthing_scripts/hotspots/__pycache__/cli.cpython-314.pyc +0 -0
  167. package/pennyfarthing_scripts/hotspots/__pycache__/models.cpython-314.pyc +0 -0
  168. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  169. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  170. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  171. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  172. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  173. package/pennyfarthing_scripts/jira/__pycache__/create.cpython-314.pyc +0 -0
  174. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  175. package/pennyfarthing_scripts/jira/__pycache__/reconcile.cpython-314.pyc +0 -0
  176. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  177. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  178. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  179. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  180. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  181. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  182. package/pennyfarthing_scripts/prime/__pycache__/tiers.cpython-314.pyc +0 -0
  183. package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
  184. package/pennyfarthing_scripts/prime/version_sentinel.py +104 -0
  185. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  186. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  187. package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
  188. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  189. package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
  190. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  191. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  192. package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
  193. package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
  194. package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
  195. package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
  196. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  197. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  198. package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
  199. package/pennyfarthing_scripts/sprint/archive_epic.py +9 -1
  200. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  201. package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
  202. package/pennyfarthing_scripts/tests/test_version_sentinel.py +126 -0
  203. package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
  204. package/pennyfarthing_scripts/validate/__pycache__/__init__.cpython-314.pyc +0 -0
  205. package/pennyfarthing_scripts/validate/__pycache__/cli.cpython-314.pyc +0 -0
  206. package/scripts/README.md +0 -41
@@ -65,7 +65,11 @@ def ensure_archive_file(project_root: Path | None = None) -> Path:
65
65
 
66
66
  sprint_name = sprint_info.get("jira_sprint_name", "Unknown Sprint")
67
67
  sprint_id = sprint_info.get("jira_sprint_id", "")
68
+ sprint_number = sprint_info.get("number", "")
68
69
  goal = sprint_info.get("goal", "")
70
+ start_date = sprint_info.get("start_date", "")
71
+ end_date = sprint_info.get("end_date", "")
72
+ status = sprint_info.get("status", "active")
69
73
 
70
74
  template = f"""# Sprint {sprint_name} - Completed Work
71
75
  # Jira Sprint ID: {sprint_id}
@@ -73,9 +77,13 @@ def ensure_archive_file(project_root: Path | None = None) -> Path:
73
77
 
74
78
  sprint:
75
79
  name: "{sprint_name}"
80
+ number: {sprint_number}
76
81
  jira_sprint_id: {sprint_id}
77
82
  jira_sprint_name: "{sprint_name}"
78
83
  goal: {goal}
84
+ start_date: {start_date}
85
+ end_date: {end_date}
86
+ status: {status}
79
87
 
80
88
  completed_epics:
81
89
  # Epic shard files live in sprint/archive/epic-{{ref}}.yaml
@@ -183,7 +191,7 @@ def is_epic_complete(epic: dict[str, Any]) -> tuple[bool, list[str]]:
183
191
  incomplete = []
184
192
  for story in stories:
185
193
  story_status = story.get("status", "backlog")
186
- if story_status not in ("done", "completed", "cancelled"):
194
+ if story_status not in ("done", "completed", "canceled", "cancelled"):
187
195
  incomplete.append(story.get("id", "unknown"))
188
196
 
189
197
  return len(incomplete) == 0, incomplete
@@ -0,0 +1,126 @@
1
+ """Tests for MSSCI-14698: Version sentinel detection in prime.
2
+
3
+ Story 98-1: pf agent start (prime) compares .pennyfarthing/.installed-version
4
+ sentinel against package version. On mismatch, triggers auto-update.
5
+
6
+ Acceptance Criteria tested here:
7
+ - AC3: pf agent start (prime) compares sentinel version against package version
8
+ - AC4: On version mismatch, auto-runs pennyfarthing update --auto
9
+ - AC6: Missing sentinel file treated as version mismatch (triggers update)
10
+
11
+ (AC1, AC2, AC5 tested in TypeScript: packages/core/src/cli/commands/version-sentinel.test.ts)
12
+ """
13
+
14
+ from pathlib import Path
15
+ from unittest.mock import patch, MagicMock
16
+
17
+ import pytest
18
+
19
+ # Module to be implemented
20
+ from pennyfarthing_scripts.prime.version_sentinel import (
21
+ read_sentinel_version,
22
+ get_package_version,
23
+ check_version_mismatch,
24
+ )
25
+
26
+
27
+ class TestReadSentinelVersion:
28
+ """Tests for reading the sentinel file."""
29
+
30
+ def test_reads_version_from_sentinel_file(self, tmp_path: Path) -> None:
31
+ """AC3: Should read version from .pennyfarthing/.installed-version."""
32
+ pf_dir = tmp_path / ".pennyfarthing"
33
+ pf_dir.mkdir()
34
+ sentinel = pf_dir / ".installed-version"
35
+ sentinel.write_text("10.3.1\n")
36
+
37
+ version = read_sentinel_version(tmp_path)
38
+ assert version == "10.3.1"
39
+
40
+ def test_returns_none_when_sentinel_missing(self, tmp_path: Path) -> None:
41
+ """AC6: Missing sentinel file should return None."""
42
+ pf_dir = tmp_path / ".pennyfarthing"
43
+ pf_dir.mkdir()
44
+ # No .installed-version file
45
+
46
+ version = read_sentinel_version(tmp_path)
47
+ assert version is None
48
+
49
+ def test_returns_none_when_pennyfarthing_dir_missing(self, tmp_path: Path) -> None:
50
+ """AC6: Missing .pennyfarthing/ directory should return None."""
51
+ version = read_sentinel_version(tmp_path)
52
+ assert version is None
53
+
54
+ def test_trims_whitespace(self, tmp_path: Path) -> None:
55
+ """Should handle extra whitespace in sentinel file."""
56
+ pf_dir = tmp_path / ".pennyfarthing"
57
+ pf_dir.mkdir()
58
+ sentinel = pf_dir / ".installed-version"
59
+ sentinel.write_text(" 10.3.1 \n")
60
+
61
+ version = read_sentinel_version(tmp_path)
62
+ assert version == "10.3.1"
63
+
64
+ def test_returns_none_for_empty_file(self, tmp_path: Path) -> None:
65
+ """Should return None for empty sentinel file."""
66
+ pf_dir = tmp_path / ".pennyfarthing"
67
+ pf_dir.mkdir()
68
+ sentinel = pf_dir / ".installed-version"
69
+ sentinel.write_text("")
70
+
71
+ version = read_sentinel_version(tmp_path)
72
+ assert version is None
73
+
74
+
75
+ class TestCheckVersionMismatch:
76
+ """Tests for version comparison and auto-update triggering."""
77
+
78
+ def test_no_mismatch_when_versions_match(self, tmp_path: Path) -> None:
79
+ """AC3: No mismatch when sentinel matches package version."""
80
+ pf_dir = tmp_path / ".pennyfarthing"
81
+ pf_dir.mkdir()
82
+ sentinel = pf_dir / ".installed-version"
83
+ sentinel.write_text("10.3.1\n")
84
+
85
+ result = check_version_mismatch(tmp_path, package_version="10.3.1")
86
+ assert result.needs_update is False
87
+
88
+ def test_mismatch_when_versions_differ(self, tmp_path: Path) -> None:
89
+ """AC3/AC4: Mismatch when sentinel differs from package version."""
90
+ pf_dir = tmp_path / ".pennyfarthing"
91
+ pf_dir.mkdir()
92
+ sentinel = pf_dir / ".installed-version"
93
+ sentinel.write_text("10.2.0\n")
94
+
95
+ result = check_version_mismatch(tmp_path, package_version="10.3.1")
96
+ assert result.needs_update is True
97
+ assert result.installed_version == "10.2.0"
98
+ assert result.package_version == "10.3.1"
99
+
100
+ def test_mismatch_when_sentinel_missing(self, tmp_path: Path) -> None:
101
+ """AC6: Missing sentinel file treated as version mismatch."""
102
+ pf_dir = tmp_path / ".pennyfarthing"
103
+ pf_dir.mkdir()
104
+ # No sentinel file
105
+
106
+ result = check_version_mismatch(tmp_path, package_version="10.3.1")
107
+ assert result.needs_update is True
108
+ assert result.installed_version is None
109
+
110
+ def test_mismatch_when_pennyfarthing_dir_missing(self, tmp_path: Path) -> None:
111
+ """AC6: Missing .pennyfarthing/ directory treated as mismatch."""
112
+ result = check_version_mismatch(tmp_path, package_version="10.3.1")
113
+ assert result.needs_update is True
114
+ assert result.installed_version is None
115
+
116
+ def test_result_includes_both_versions(self, tmp_path: Path) -> None:
117
+ """Result should include both installed and package version for reporting."""
118
+ pf_dir = tmp_path / ".pennyfarthing"
119
+ pf_dir.mkdir()
120
+ sentinel = pf_dir / ".installed-version"
121
+ sentinel.write_text("10.2.0\n")
122
+
123
+ result = check_version_mismatch(tmp_path, package_version="10.3.1")
124
+ assert result.installed_version == "10.2.0"
125
+ assert result.package_version == "10.3.1"
126
+ assert result.needs_update is True
package/scripts/README.md DELETED
@@ -1,41 +0,0 @@
1
- # Meta Scripts
2
-
3
- **These scripts are NOT distributed to users.** They are for Pennyfarthing framework development only.
4
-
5
- ## Contents
6
-
7
- | Script | Purpose |
8
- |--------|---------|
9
- | `deploy.sh` | Release Pennyfarthing (version bump, tag, push, GitHub release) |
10
- | `cyclist-debug.mjs` | Debug Cyclist connection |
11
- | `handoff-cli.{sh,js}` | Test handoff flow |
12
- | `verify-visual-mapping.js` | Verify theme visual mappings |
13
- | `migrate-assets-to-slug.sh` | One-time migration script |
14
- | `resize-portraits.sh` | Resize portrait images |
15
- | `resolve-portrait.mjs` | Portrait resolution logic |
16
- | `validate-refs.js` | Validate internal references |
17
-
18
- > Benchmark scripts have been moved to `packages/benchmark/`.
19
-
20
- ## Usage
21
-
22
- Run from pennyfarthing repo root:
23
-
24
- ```bash
25
- # Release a new version
26
- ./scripts/deploy.sh --dry-run patch
27
- ./scripts/deploy.sh patch
28
- ```
29
-
30
- ## Where Should My Script Go?
31
-
32
- **Put it here if:**
33
- - It's for framework development/CI only
34
- - Users should NOT have access to it
35
- - It uses GPU/heavy dependencies (keep in meta, not distributed)
36
-
37
- **Put it in `pennyfarthing-dist/scripts/` if:**
38
- - Users need it for their workflows
39
- - It's part of the sprint/story/jira tooling
40
-
41
- See `CLAUDE.md` for the full decision tree.