@pennyfarthing/core 7.8.0 → 7.8.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.
Files changed (132) hide show
  1. package/README.md +1 -1
  2. package/package.json +2 -1
  3. package/packages/core/dist/cli/commands/doctor.d.ts +3 -0
  4. package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -1
  5. package/packages/core/dist/cli/commands/doctor.js +20 -9
  6. package/packages/core/dist/cli/commands/doctor.js.map +1 -1
  7. package/pennyfarthing-dist/scripts/core/agent-session.sh +2 -2
  8. package/pennyfarthing-dist/scripts/core/prime.sh +8 -0
  9. package/pennyfarthing_scripts/__init__.py +17 -0
  10. package/pennyfarthing_scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  11. package/pennyfarthing_scripts/__pycache__/__init__.cpython-314.pyc +0 -0
  12. package/pennyfarthing_scripts/__pycache__/config.cpython-314.pyc +0 -0
  13. package/pennyfarthing_scripts/__pycache__/jira.cpython-314.pyc +0 -0
  14. package/pennyfarthing_scripts/__pycache__/jira_epic_creation.cpython-314.pyc +0 -0
  15. package/pennyfarthing_scripts/__pycache__/jira_sync.cpython-314.pyc +0 -0
  16. package/pennyfarthing_scripts/__pycache__/jira_sync_story.cpython-314.pyc +0 -0
  17. package/pennyfarthing_scripts/__pycache__/sprint.cpython-314.pyc +0 -0
  18. package/pennyfarthing_scripts/__pycache__/workflow.cpython-311.pyc +0 -0
  19. package/pennyfarthing_scripts/__pycache__/workflow.cpython-314.pyc +0 -0
  20. package/pennyfarthing_scripts/bellmode_hook.py +154 -0
  21. package/pennyfarthing_scripts/brownfield/__init__.py +35 -0
  22. package/pennyfarthing_scripts/brownfield/__main__.py +7 -0
  23. package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
  24. package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
  25. package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
  26. package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
  27. package/pennyfarthing_scripts/brownfield/cli.py +131 -0
  28. package/pennyfarthing_scripts/brownfield/discover.py +753 -0
  29. package/pennyfarthing_scripts/common/__init__.py +49 -0
  30. package/pennyfarthing_scripts/common/__pycache__/__init__.cpython-314.pyc +0 -0
  31. package/pennyfarthing_scripts/common/__pycache__/config.cpython-314.pyc +0 -0
  32. package/pennyfarthing_scripts/common/__pycache__/output.cpython-314.pyc +0 -0
  33. package/pennyfarthing_scripts/common/config.py +65 -0
  34. package/pennyfarthing_scripts/common/output.py +180 -0
  35. package/pennyfarthing_scripts/config.py +21 -0
  36. package/pennyfarthing_scripts/git/__init__.py +29 -0
  37. package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
  38. package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
  39. package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
  40. package/pennyfarthing_scripts/git/create_branches.py +439 -0
  41. package/pennyfarthing_scripts/git/status_all.py +310 -0
  42. package/pennyfarthing_scripts/hooks.py +455 -0
  43. package/pennyfarthing_scripts/jira/__init__.py +93 -0
  44. package/pennyfarthing_scripts/jira/__main__.py +10 -0
  45. package/pennyfarthing_scripts/jira/__pycache__/__init__.cpython-314.pyc +0 -0
  46. package/pennyfarthing_scripts/jira/__pycache__/__main__.cpython-314.pyc +0 -0
  47. package/pennyfarthing_scripts/jira/__pycache__/bidirectional.cpython-314.pyc +0 -0
  48. package/pennyfarthing_scripts/jira/__pycache__/claim.cpython-314.pyc +0 -0
  49. package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
  50. package/pennyfarthing_scripts/jira/__pycache__/client.cpython-314.pyc +0 -0
  51. package/pennyfarthing_scripts/jira/__pycache__/compat.cpython-314.pyc +0 -0
  52. package/pennyfarthing_scripts/jira/__pycache__/epic.cpython-314.pyc +0 -0
  53. package/pennyfarthing_scripts/jira/__pycache__/mappings.cpython-314.pyc +0 -0
  54. package/pennyfarthing_scripts/jira/__pycache__/models.cpython-314.pyc +0 -0
  55. package/pennyfarthing_scripts/jira/__pycache__/story.cpython-314.pyc +0 -0
  56. package/pennyfarthing_scripts/jira/__pycache__/sync.cpython-314.pyc +0 -0
  57. package/pennyfarthing_scripts/jira/bidirectional.py +561 -0
  58. package/pennyfarthing_scripts/jira/claim.py +211 -0
  59. package/pennyfarthing_scripts/jira/cli.py +150 -0
  60. package/pennyfarthing_scripts/jira/client.py +613 -0
  61. package/pennyfarthing_scripts/jira/epic.py +176 -0
  62. package/pennyfarthing_scripts/jira/story.py +219 -0
  63. package/pennyfarthing_scripts/jira/sync.py +350 -0
  64. package/pennyfarthing_scripts/jira_bidirectional_sync.py +37 -0
  65. package/pennyfarthing_scripts/jira_epic_creation.py +30 -0
  66. package/pennyfarthing_scripts/jira_sync.py +36 -0
  67. package/pennyfarthing_scripts/jira_sync_story.py +30 -0
  68. package/pennyfarthing_scripts/output.py +37 -0
  69. package/pennyfarthing_scripts/preflight/__init__.py +17 -0
  70. package/pennyfarthing_scripts/preflight/__main__.py +10 -0
  71. package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
  72. package/pennyfarthing_scripts/preflight/__pycache__/__main__.cpython-314.pyc +0 -0
  73. package/pennyfarthing_scripts/preflight/__pycache__/cli.cpython-314.pyc +0 -0
  74. package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
  75. package/pennyfarthing_scripts/preflight/cli.py +141 -0
  76. package/pennyfarthing_scripts/preflight/finish.py +382 -0
  77. package/pennyfarthing_scripts/pretooluse_hook.py +142 -0
  78. package/pennyfarthing_scripts/prime/__init__.py +38 -0
  79. package/pennyfarthing_scripts/prime/__main__.py +8 -0
  80. package/pennyfarthing_scripts/prime/__pycache__/__init__.cpython-314.pyc +0 -0
  81. package/pennyfarthing_scripts/prime/__pycache__/__main__.cpython-314.pyc +0 -0
  82. package/pennyfarthing_scripts/prime/__pycache__/cli.cpython-314.pyc +0 -0
  83. package/pennyfarthing_scripts/prime/__pycache__/loader.cpython-314.pyc +0 -0
  84. package/pennyfarthing_scripts/prime/__pycache__/models.cpython-314.pyc +0 -0
  85. package/pennyfarthing_scripts/prime/__pycache__/persona.cpython-314.pyc +0 -0
  86. package/pennyfarthing_scripts/prime/__pycache__/session.cpython-314.pyc +0 -0
  87. package/pennyfarthing_scripts/prime/__pycache__/workflow.cpython-314.pyc +0 -0
  88. package/pennyfarthing_scripts/prime/cli.py +220 -0
  89. package/pennyfarthing_scripts/prime/loader.py +239 -0
  90. package/pennyfarthing_scripts/sprint/__init__.py +66 -0
  91. package/pennyfarthing_scripts/sprint/__main__.py +10 -0
  92. package/pennyfarthing_scripts/sprint/__pycache__/__init__.cpython-314.pyc +0 -0
  93. package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
  94. package/pennyfarthing_scripts/sprint/__pycache__/archive.cpython-314.pyc +0 -0
  95. package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
  96. package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
  97. package/pennyfarthing_scripts/sprint/__pycache__/status.cpython-314.pyc +0 -0
  98. package/pennyfarthing_scripts/sprint/__pycache__/validator.cpython-314.pyc +0 -0
  99. package/pennyfarthing_scripts/sprint/__pycache__/work.cpython-314.pyc +0 -0
  100. package/pennyfarthing_scripts/sprint/archive.py +108 -0
  101. package/pennyfarthing_scripts/sprint/cli.py +124 -0
  102. package/pennyfarthing_scripts/sprint/loader.py +193 -0
  103. package/pennyfarthing_scripts/sprint/status.py +122 -0
  104. package/pennyfarthing_scripts/sprint/validator.py +405 -0
  105. package/pennyfarthing_scripts/sprint/work.py +192 -0
  106. package/pennyfarthing_scripts/story/__init__.py +67 -0
  107. package/pennyfarthing_scripts/story/__main__.py +10 -0
  108. package/pennyfarthing_scripts/story/cli.py +105 -0
  109. package/pennyfarthing_scripts/story/create.py +167 -0
  110. package/pennyfarthing_scripts/story/size.py +113 -0
  111. package/pennyfarthing_scripts/story/template.py +151 -0
  112. package/pennyfarthing_scripts/swebench.py +216 -0
  113. package/pennyfarthing_scripts/tests/__init__.py +1 -0
  114. package/pennyfarthing_scripts/tests/__pycache__/__init__.cpython-314.pyc +0 -0
  115. package/pennyfarthing_scripts/tests/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc +0 -0
  116. package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
  117. package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
  118. package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
  119. package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
  120. package/pennyfarthing_scripts/tests/conftest.py +106 -0
  121. package/pennyfarthing_scripts/tests/test_brownfield.py +842 -0
  122. package/pennyfarthing_scripts/tests/test_cli_modules.py +245 -0
  123. package/pennyfarthing_scripts/tests/test_common.py +180 -0
  124. package/pennyfarthing_scripts/tests/test_git_utils.py +866 -0
  125. package/pennyfarthing_scripts/tests/test_jira_package.py +334 -0
  126. package/pennyfarthing_scripts/tests/test_package_structure.py +372 -0
  127. package/pennyfarthing_scripts/tests/test_prime.py +397 -0
  128. package/pennyfarthing_scripts/tests/test_sprint_package.py +236 -0
  129. package/pennyfarthing_scripts/tests/test_sprint_validator.py +675 -0
  130. package/pennyfarthing_scripts/tests/test_story_package.py +156 -0
  131. package/pennyfarthing_scripts/welcome_hook.py +157 -0
  132. package/pennyfarthing_scripts/workflow.py +183 -0
@@ -0,0 +1,49 @@
1
+ """Common utilities for Pennyfarthing scripts.
2
+
3
+ This package provides shared utilities used across all CLI tools:
4
+ - output: Colored console output functions
5
+ - config: Project configuration loading
6
+ """
7
+
8
+ from pennyfarthing_scripts.common.output import (
9
+ Colors,
10
+ bold,
11
+ debug,
12
+ dim,
13
+ divider,
14
+ error,
15
+ header,
16
+ info,
17
+ success,
18
+ warn,
19
+ _colorize,
20
+ _supports_color,
21
+ )
22
+
23
+ from pennyfarthing_scripts.common.config import (
24
+ find_project_root,
25
+ get_project_root,
26
+ load_pennyfarthing_config,
27
+ load_yaml_config,
28
+ )
29
+
30
+ __all__ = [
31
+ # Output
32
+ "Colors",
33
+ "bold",
34
+ "debug",
35
+ "dim",
36
+ "divider",
37
+ "error",
38
+ "header",
39
+ "info",
40
+ "success",
41
+ "warn",
42
+ "_colorize",
43
+ "_supports_color",
44
+ # Config
45
+ "find_project_root",
46
+ "get_project_root",
47
+ "load_pennyfarthing_config",
48
+ "load_yaml_config",
49
+ ]
@@ -0,0 +1,65 @@
1
+ """
2
+ Configuration loading utilities for Pennyfarthing scripts.
3
+
4
+ Provides YAML config loading with graceful degradation for missing files.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ import yaml
11
+
12
+
13
+ def get_project_root(start_dir: Path | None = None) -> Path:
14
+ """Find the Pennyfarthing project root.
15
+
16
+ Walks up from start_dir (or cwd) looking for .pennyfarthing directory.
17
+
18
+ Args:
19
+ start_dir: Directory to start search from (defaults to cwd)
20
+
21
+ Returns:
22
+ Path to project root directory
23
+
24
+ Raises:
25
+ FileNotFoundError: If no .pennyfarthing directory found
26
+ """
27
+ current = Path(start_dir) if start_dir else Path.cwd()
28
+ current = current.resolve()
29
+
30
+ while current != current.parent:
31
+ if (current / ".pennyfarthing").is_dir():
32
+ return current
33
+ current = current.parent
34
+
35
+ raise FileNotFoundError("Could not find project root (no .pennyfarthing/ directory found)")
36
+
37
+
38
+ # Alias for backwards compatibility
39
+ find_project_root = get_project_root
40
+
41
+
42
+ def load_yaml_config(path: Path) -> dict[str, Any] | None:
43
+ """Load a YAML configuration file.
44
+
45
+ Args:
46
+ path: Path to the YAML file
47
+
48
+ Returns:
49
+ Parsed YAML as dict, or None if file doesn't exist
50
+ """
51
+ if not path.exists():
52
+ return None
53
+
54
+ with open(path, "r") as f:
55
+ return yaml.safe_load(f)
56
+
57
+
58
+ def load_pennyfarthing_config() -> dict[str, Any]:
59
+ """Load .pennyfarthing/config.local.yaml.
60
+
61
+ Returns:
62
+ Config dict, or empty dict if not found
63
+ """
64
+ config_path = get_project_root() / ".pennyfarthing" / "config.local.yaml"
65
+ return load_yaml_config(config_path) or {}
@@ -0,0 +1,180 @@
1
+ """
2
+ Console output utilities for Pennyfarthing scripts.
3
+
4
+ Provides consistent colored output for CLI tools:
5
+ - success(): Green [OK] prefix
6
+ - info(): Blue [INFO] prefix
7
+ - warn(): Yellow [WARN] prefix
8
+ - error(): Red [ERROR] prefix
9
+
10
+ Consolidates output formatting from jira_sync.py and provides
11
+ a consistent interface for all CLI scripts.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import os
17
+ import sys
18
+ from typing import TextIO
19
+
20
+
21
+ # ANSI color codes
22
+ class Colors:
23
+ """ANSI escape codes for terminal colors."""
24
+
25
+ RED = "\x1b[31m"
26
+ GREEN = "\x1b[32m"
27
+ YELLOW = "\x1b[33m"
28
+ BLUE = "\x1b[34m"
29
+ MAGENTA = "\x1b[35m"
30
+ CYAN = "\x1b[36m"
31
+ BOLD = "\x1b[1m"
32
+ DIM = "\x1b[2m"
33
+ RESET = "\x1b[0m"
34
+
35
+
36
+ def _supports_color(stream: TextIO) -> bool:
37
+ """Check if the output stream supports ANSI colors.
38
+
39
+ Args:
40
+ stream: Output stream to check
41
+
42
+ Returns:
43
+ True if colors are supported
44
+ """
45
+ # Check for NO_COLOR environment variable (standard)
46
+ if os.environ.get("NO_COLOR"):
47
+ return False
48
+
49
+ # Check for FORCE_COLOR environment variable
50
+ if os.environ.get("FORCE_COLOR"):
51
+ return True
52
+
53
+ # Check if stream is a TTY
54
+ if hasattr(stream, "isatty") and stream.isatty():
55
+ return True
56
+
57
+ return False
58
+
59
+
60
+ def _colorize(text: str, color: str, stream: TextIO = sys.stderr) -> str:
61
+ """Apply color to text if supported.
62
+
63
+ Args:
64
+ text: Text to colorize
65
+ color: ANSI color code
66
+ stream: Output stream (for TTY detection)
67
+
68
+ Returns:
69
+ Colorized text or plain text if colors not supported
70
+ """
71
+ if _supports_color(stream):
72
+ return f"{color}{text}{Colors.RESET}"
73
+ return text
74
+
75
+
76
+ def success(msg: str, file: TextIO = sys.stderr) -> None:
77
+ """Print success message with green [OK] prefix.
78
+
79
+ Args:
80
+ msg: Message to print
81
+ file: Output stream (default: stderr)
82
+ """
83
+ prefix = _colorize("[OK]", Colors.GREEN, file)
84
+ print(f"{prefix} {msg}", file=file)
85
+
86
+
87
+ def info(msg: str, file: TextIO = sys.stderr) -> None:
88
+ """Print info message with blue [INFO] prefix.
89
+
90
+ Args:
91
+ msg: Message to print
92
+ file: Output stream (default: stderr)
93
+ """
94
+ prefix = _colorize("[INFO]", Colors.BLUE, file)
95
+ print(f"{prefix} {msg}", file=file)
96
+
97
+
98
+ def warn(msg: str, file: TextIO = sys.stderr) -> None:
99
+ """Print warning message with yellow [WARN] prefix.
100
+
101
+ Args:
102
+ msg: Message to print
103
+ file: Output stream (default: stderr)
104
+ """
105
+ prefix = _colorize("[WARN]", Colors.YELLOW, file)
106
+ print(f"{prefix} {msg}", file=file)
107
+
108
+
109
+ def error(msg: str, file: TextIO = sys.stderr) -> None:
110
+ """Print error message with red [ERROR] prefix.
111
+
112
+ Args:
113
+ msg: Message to print
114
+ file: Output stream (default: stderr)
115
+ """
116
+ prefix = _colorize("[ERROR]", Colors.RED, file)
117
+ print(f"{prefix} {msg}", file=file)
118
+
119
+
120
+ def debug(msg: str, file: TextIO = sys.stderr) -> None:
121
+ """Print debug message with dim [DEBUG] prefix.
122
+
123
+ Args:
124
+ msg: Message to print
125
+ file: Output stream (default: stderr)
126
+ """
127
+ prefix = _colorize("[DEBUG]", Colors.DIM, file)
128
+ print(f"{prefix} {msg}", file=file)
129
+
130
+
131
+ def header(msg: str, char: str = "=", width: int = 60, file: TextIO = sys.stderr) -> None:
132
+ """Print a header with decorative lines.
133
+
134
+ Args:
135
+ msg: Header text
136
+ char: Character for decoration line
137
+ width: Total width of the line
138
+ file: Output stream (default: stderr)
139
+ """
140
+ line = char * width
141
+ print(f"\n{line}", file=file)
142
+ print(msg, file=file)
143
+ print(line, file=file)
144
+
145
+
146
+ def divider(char: str = "-", width: int = 40, file: TextIO = sys.stderr) -> None:
147
+ """Print a divider line.
148
+
149
+ Args:
150
+ char: Character for divider
151
+ width: Width of divider
152
+ file: Output stream (default: stderr)
153
+ """
154
+ print(char * width, file=file)
155
+
156
+
157
+ def bold(text: str, stream: TextIO = sys.stdout) -> str:
158
+ """Return bold text if colors supported.
159
+
160
+ Args:
161
+ text: Text to make bold
162
+ stream: Output stream (for TTY detection)
163
+
164
+ Returns:
165
+ Bold text or plain text
166
+ """
167
+ return _colorize(text, Colors.BOLD, stream)
168
+
169
+
170
+ def dim(text: str, stream: TextIO = sys.stdout) -> str:
171
+ """Return dimmed text if colors supported.
172
+
173
+ Args:
174
+ text: Text to dim
175
+ stream: Output stream (for TTY detection)
176
+
177
+ Returns:
178
+ Dimmed text or plain text
179
+ """
180
+ return _colorize(text, Colors.DIM, stream)
@@ -0,0 +1,21 @@
1
+ """
2
+ Configuration loading utilities for Pennyfarthing scripts.
3
+
4
+ This module re-exports from pennyfarthing_scripts.common.config for
5
+ backwards compatibility. New code should import from common.config directly.
6
+ """
7
+
8
+ # Re-export everything from the new location
9
+ from pennyfarthing_scripts.common.config import (
10
+ find_project_root,
11
+ get_project_root,
12
+ load_pennyfarthing_config,
13
+ load_yaml_config,
14
+ )
15
+
16
+ __all__ = [
17
+ "find_project_root",
18
+ "get_project_root",
19
+ "load_pennyfarthing_config",
20
+ "load_yaml_config",
21
+ ]
@@ -0,0 +1,29 @@
1
+ """
2
+ Git utilities for Pennyfarthing.
3
+
4
+ Story: MSSCI-12402 - Port git utility scripts to Python
5
+
6
+ This package provides async git operations for multi-repo management:
7
+ - status_all: Check git status across all repos in parallel
8
+ - create_branches: Create feature branches across repos in parallel
9
+ """
10
+
11
+ from pennyfarthing_scripts.git.status_all import (
12
+ RepoStatus,
13
+ get_all_repo_status,
14
+ format_status_brief,
15
+ format_status_full,
16
+ )
17
+ from pennyfarthing_scripts.git.create_branches import (
18
+ BranchResult,
19
+ create_feature_branches,
20
+ )
21
+
22
+ __all__ = [
23
+ "RepoStatus",
24
+ "get_all_repo_status",
25
+ "format_status_brief",
26
+ "format_status_full",
27
+ "BranchResult",
28
+ "create_feature_branches",
29
+ ]