bpsai-pair 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl
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.
Potentially problematic release.
This version of bpsai-pair might be problematic. Click here for more details.
- bpsai_pair/__init__.py +1 -1
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.agentpackignore +19 -1
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.github/workflows/project_tree.yml +29 -8
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/AGENTS.md +29 -0
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/CLAUDE.md +32 -0
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/agents.md +10 -1
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md +11 -1
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/scripts/README.md +1 -1
- bpsai_pair/ops.py +70 -71
- bpsai_pair-0.2.2.dist-info/METADATA +89 -0
- {bpsai_pair-0.2.0.dist-info → bpsai_pair-0.2.2.dist-info}/RECORD +14 -14
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/agents.md.bak +0 -196
- bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md.bak +0 -10
- bpsai_pair-0.2.0.dist-info/METADATA +0 -29
- {bpsai_pair-0.2.0.dist-info → bpsai_pair-0.2.2.dist-info}/WHEEL +0 -0
- {bpsai_pair-0.2.0.dist-info → bpsai_pair-0.2.2.dist-info}/entry_points.txt +0 -0
- {bpsai_pair-0.2.0.dist-info → bpsai_pair-0.2.2.dist-info}/top_level.txt +0 -0
bpsai_pair/__init__.py
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
# Default agent pack exclusions
|
|
1
|
+
# Default agent pack exclusions
|
|
2
|
+
.git/
|
|
3
|
+
.venv/
|
|
4
|
+
venv/
|
|
5
|
+
env/
|
|
6
|
+
__pycache__/
|
|
7
|
+
node_modules/
|
|
8
|
+
dist/
|
|
9
|
+
build/
|
|
10
|
+
*.log
|
|
11
|
+
*.bak
|
|
12
|
+
*.tgz
|
|
13
|
+
*.tar.gz
|
|
14
|
+
*.zip
|
|
15
|
+
.env
|
|
16
|
+
.env.*
|
|
17
|
+
*.pyc
|
|
18
|
+
.DS_Store
|
|
19
|
+
Thumbs.db
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
|
|
2
1
|
name: Refresh Project Tree
|
|
3
2
|
|
|
4
3
|
on:
|
|
5
4
|
schedule:
|
|
6
|
-
- cron: 17 3
|
|
5
|
+
- cron: '17 3 * * *' # Daily at 03:17 UTC
|
|
7
6
|
workflow_dispatch: {}
|
|
8
7
|
|
|
9
8
|
permissions:
|
|
@@ -14,20 +13,42 @@ jobs:
|
|
|
14
13
|
runs-on: ubuntu-latest
|
|
15
14
|
steps:
|
|
16
15
|
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
17
|
- name: Generate project tree
|
|
18
18
|
run: |
|
|
19
19
|
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
20
20
|
echo "# Project Tree (snapshot)" > context/project_tree.md
|
|
21
21
|
echo "_Generated: ${TS}_" >> context/project_tree.md
|
|
22
|
-
echo >> context/project_tree.md
|
|
23
|
-
echo
|
|
22
|
+
echo "" >> context/project_tree.md
|
|
23
|
+
echo '```' >> context/project_tree.md
|
|
24
|
+
|
|
25
|
+
# Use find to create tree (cross-platform)
|
|
26
|
+
find . \
|
|
27
|
+
-path './.git' -prune -o \
|
|
28
|
+
-path './node_modules' -prune -o \
|
|
29
|
+
-path './dist' -prune -o \
|
|
30
|
+
-path './build' -prune -o \
|
|
31
|
+
-path './.venv' -prune -o \
|
|
32
|
+
-path './__pycache__' -prune -o \
|
|
33
|
+
-path './tools/cli/dist' -prune -o \
|
|
34
|
+
-path './tools/cli/build' -prune -o \
|
|
35
|
+
-path './**/*.egg-info' -prune -o \
|
|
36
|
+
-type f -print -o \
|
|
37
|
+
-type d -print | \
|
|
38
|
+
sed 's|^\./||' | \
|
|
39
|
+
grep -v '^\.$' | \
|
|
40
|
+
sort >> context/project_tree.md
|
|
41
|
+
|
|
42
|
+
echo '```' >> context/project_tree.md
|
|
43
|
+
|
|
24
44
|
- name: Commit changes if any
|
|
25
45
|
run: |
|
|
26
|
-
git config user.name "github-actions"
|
|
27
|
-
git config user.email "actions@github.com"
|
|
46
|
+
git config user.name "github-actions[bot]"
|
|
47
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
28
48
|
git add context/project_tree.md || true
|
|
29
49
|
if ! git diff --cached --quiet; then
|
|
30
|
-
git commit -m "chore(context): refresh project_tree snapshot
|
|
50
|
+
git commit -m "chore(context): refresh project_tree snapshot [skip ci]"
|
|
51
|
+
git push
|
|
31
52
|
else
|
|
32
|
-
echo "No changes to commit."
|
|
53
|
+
echo "No changes to commit."
|
|
33
54
|
fi
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Agents Guide (Root Pointer)
|
|
2
|
+
|
|
3
|
+
Welcome, AI agent! This project uses PairCoder for AI pair programming.
|
|
4
|
+
|
|
5
|
+
## Where to Start
|
|
6
|
+
|
|
7
|
+
All instructions, context, and project information are maintained in the `/context` directory:
|
|
8
|
+
|
|
9
|
+
1. **Read first:** `/context/agents.md` - Complete playbook and guidelines
|
|
10
|
+
2. **Current state:** `/context/development.md` - Roadmap and Context Loop
|
|
11
|
+
3. **File structure:** `/context/project_tree.md` - Repository layout
|
|
12
|
+
4. **Component docs:** `/context/directory_notes/` - Directory-specific guidance
|
|
13
|
+
|
|
14
|
+
## Critical Reminder
|
|
15
|
+
|
|
16
|
+
Always check the Context Loop at the end of `/context/development.md` for:
|
|
17
|
+
- **Overall goal is:** The project's primary objective
|
|
18
|
+
- **Last action was:** What was just completed
|
|
19
|
+
- **Next action will be:** The immediate next step
|
|
20
|
+
- **Blockers/Risks:** Any issues needing attention
|
|
21
|
+
|
|
22
|
+
## After Making Changes
|
|
23
|
+
|
|
24
|
+
Update the Context Loop using:
|
|
25
|
+
```bash
|
|
26
|
+
bpsai-pair context-sync --last "What you did" --next "Next step" --blockers "Any issues"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Begin by reading `/context/agents.md` for complete instructions.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Claude Guide (Root Pointer)
|
|
2
|
+
|
|
3
|
+
Hello Claude! This project follows PairCoder conventions for AI pair programming.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
Your instructions are organized in the `/context` directory:
|
|
8
|
+
|
|
9
|
+
1. **Start here:** `/context/agents.md` - Full AI pairing playbook
|
|
10
|
+
2. **Project state:** `/context/development.md` - Current goals and progress
|
|
11
|
+
3. **Repository map:** `/context/project_tree.md` - File structure reference
|
|
12
|
+
|
|
13
|
+
## Working in This Repository
|
|
14
|
+
|
|
15
|
+
Before making any changes:
|
|
16
|
+
- Review the Context Loop in `/context/development.md`
|
|
17
|
+
- Understand the current phase and next actions
|
|
18
|
+
- Check for any blockers or risks
|
|
19
|
+
|
|
20
|
+
After making changes:
|
|
21
|
+
- Update the Context Loop to maintain continuity
|
|
22
|
+
- Use the provided CLI command or edit directly
|
|
23
|
+
- Keep changes focused and well-documented
|
|
24
|
+
|
|
25
|
+
## PairCoder Principles
|
|
26
|
+
|
|
27
|
+
- Maintain the Context Loop discipline
|
|
28
|
+
- Make small, reversible changes
|
|
29
|
+
- Add tests before implementing features
|
|
30
|
+
- Follow the project's established patterns
|
|
31
|
+
|
|
32
|
+
See `/context/agents.md` for detailed instructions.
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
# Agents Guide
|
|
1
|
+
# Agents Guide
|
|
2
|
+
|
|
3
|
+
This project uses a **Context Loop**. Always keep these fields current:
|
|
4
|
+
|
|
5
|
+
- **Overall goal is:** Single-sentence mission
|
|
6
|
+
- **Last action was:** What just completed
|
|
7
|
+
- **Next action will be:** The very next step
|
|
8
|
+
- **Blockers:** Known issues or decisions needed
|
|
9
|
+
|
|
10
|
+
### Working Rules for Agents\n- Do not modify or examine ignored directories (see `.agentpackignore`). Assume large assets exist even if excluded.\n- Prefer minimal, reversible changes.\n- After committing code, run `bpsai-pair context-sync` to update the loop.\n- Request a new context pack when the tree or docs change significantly.\n\n### Context Pack\nRun `bpsai-pair pack --out agent_pack.tgz` and upload to your session.\n
|
|
2
11
|
---
|
|
3
12
|
|
|
4
13
|
## Branch Discipline
|
|
@@ -1 +1,11 @@
|
|
|
1
|
-
# Development Log
|
|
1
|
+
# Development Log
|
|
2
|
+
|
|
3
|
+
**Phase:** (set by first feature)
|
|
4
|
+
**Primary Goal:** (set by first feature)
|
|
5
|
+
|
|
6
|
+
## Context Sync (AUTO-UPDATED)
|
|
7
|
+
|
|
8
|
+
- **Overall goal is:** (set by feature)
|
|
9
|
+
- **Last action was:** (set by feature)
|
|
10
|
+
- **Next action will be:** (set by feature)
|
|
11
|
+
- **Blockers:** (set by feature)
|
bpsai_pair/ops.py
CHANGED
|
@@ -17,12 +17,12 @@ import json
|
|
|
17
17
|
|
|
18
18
|
class GitOps:
|
|
19
19
|
"""Git operations helper."""
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
@staticmethod
|
|
22
22
|
def is_repo(path: Path) -> bool:
|
|
23
23
|
"""Check if path is a git repo."""
|
|
24
24
|
return (path / ".git").exists()
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
@staticmethod
|
|
27
27
|
def is_clean(path: Path) -> bool:
|
|
28
28
|
"""Check if working tree is clean."""
|
|
@@ -58,7 +58,7 @@ class GitOps:
|
|
|
58
58
|
return True
|
|
59
59
|
except:
|
|
60
60
|
return False
|
|
61
|
-
|
|
61
|
+
|
|
62
62
|
@staticmethod
|
|
63
63
|
def current_branch(path: Path) -> str:
|
|
64
64
|
"""Get current branch name."""
|
|
@@ -69,7 +69,7 @@ class GitOps:
|
|
|
69
69
|
text=True
|
|
70
70
|
)
|
|
71
71
|
return result.stdout.strip() if result.returncode == 0 else ""
|
|
72
|
-
|
|
72
|
+
|
|
73
73
|
@staticmethod
|
|
74
74
|
def create_branch(path: Path, branch: str, from_branch: str = "main") -> bool:
|
|
75
75
|
"""Create and checkout a new branch."""
|
|
@@ -81,10 +81,10 @@ class GitOps:
|
|
|
81
81
|
)
|
|
82
82
|
if check.returncode != 0:
|
|
83
83
|
return False
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
# Checkout source branch
|
|
86
86
|
subprocess.run(["git", "checkout", from_branch], cwd=path, capture_output=True)
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
# Pull if upstream exists
|
|
89
89
|
upstream = subprocess.run(
|
|
90
90
|
["git", "rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
@@ -93,7 +93,7 @@ class GitOps:
|
|
|
93
93
|
)
|
|
94
94
|
if upstream.returncode == 0:
|
|
95
95
|
subprocess.run(["git", "pull", "--ff-only"], cwd=path, capture_output=True)
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
# Create new branch
|
|
98
98
|
result = subprocess.run(
|
|
99
99
|
["git", "checkout", "-b", branch],
|
|
@@ -101,13 +101,13 @@ class GitOps:
|
|
|
101
101
|
capture_output=True
|
|
102
102
|
)
|
|
103
103
|
return result.returncode == 0
|
|
104
|
-
|
|
104
|
+
|
|
105
105
|
@staticmethod
|
|
106
106
|
def add_commit(path: Path, files: List[Path], message: str) -> bool:
|
|
107
107
|
"""Add files and commit."""
|
|
108
108
|
for f in files:
|
|
109
109
|
subprocess.run(["git", "add", str(f)], cwd=path, capture_output=True)
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
result = subprocess.run(
|
|
112
112
|
["git", "commit", "-m", message],
|
|
113
113
|
cwd=path,
|
|
@@ -118,19 +118,19 @@ class GitOps:
|
|
|
118
118
|
|
|
119
119
|
class ProjectTree:
|
|
120
120
|
"""Generate project tree snapshots."""
|
|
121
|
-
|
|
121
|
+
|
|
122
122
|
@staticmethod
|
|
123
123
|
def generate(root: Path, excludes: Optional[Set[str]] = None) -> str:
|
|
124
124
|
"""Generate a tree structure of the project."""
|
|
125
125
|
if excludes is None:
|
|
126
126
|
excludes = {
|
|
127
|
-
'.git', '.venv', 'venv', '__pycache__',
|
|
127
|
+
'.git', '.venv', 'venv', '__pycache__',
|
|
128
128
|
'node_modules', 'dist', 'build', '.mypy_cache',
|
|
129
129
|
'.pytest_cache', '.tox', '*.egg-info', '.DS_Store'
|
|
130
130
|
}
|
|
131
|
-
|
|
131
|
+
|
|
132
132
|
tree_lines = []
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
def should_skip(path: Path) -> bool:
|
|
135
135
|
name = path.name
|
|
136
136
|
for pattern in excludes:
|
|
@@ -139,20 +139,20 @@ class ProjectTree:
|
|
|
139
139
|
if name == pattern:
|
|
140
140
|
return True
|
|
141
141
|
return False
|
|
142
|
-
|
|
142
|
+
|
|
143
143
|
def walk_dir(dir_path: Path, prefix: str = ""):
|
|
144
144
|
items = sorted(dir_path.iterdir(), key=lambda x: (x.is_file(), x.name))
|
|
145
145
|
items = [i for i in items if not should_skip(i)]
|
|
146
|
-
|
|
146
|
+
|
|
147
147
|
for i, item in enumerate(items):
|
|
148
148
|
is_last = i == len(items) - 1
|
|
149
149
|
current = "└── " if is_last else "├── "
|
|
150
150
|
tree_lines.append(f"{prefix}{current}{item.name}")
|
|
151
|
-
|
|
151
|
+
|
|
152
152
|
if item.is_dir():
|
|
153
153
|
extension = " " if is_last else "│ "
|
|
154
154
|
walk_dir(item, prefix + extension)
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
tree_lines.append(".")
|
|
157
157
|
walk_dir(root)
|
|
158
158
|
return "\n".join(tree_lines)
|
|
@@ -160,7 +160,7 @@ class ProjectTree:
|
|
|
160
160
|
|
|
161
161
|
class ContextPacker:
|
|
162
162
|
"""Package context files for AI agents."""
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
@staticmethod
|
|
165
165
|
def read_ignore_patterns(ignore_file: Path) -> Set[str]:
|
|
166
166
|
"""Read patterns from .agentpackignore file."""
|
|
@@ -170,42 +170,41 @@ class ContextPacker:
|
|
|
170
170
|
for line in f:
|
|
171
171
|
line = line.strip()
|
|
172
172
|
if line and not line.startswith('#'):
|
|
173
|
-
patterns.add(line
|
|
173
|
+
patterns.add(line)
|
|
174
174
|
else:
|
|
175
175
|
# Default patterns
|
|
176
176
|
patterns = {
|
|
177
177
|
'.git', '.venv', '__pycache__', 'node_modules',
|
|
178
|
-
'dist', 'build', '*.log', '*.bak', '*.tgz',
|
|
178
|
+
'dist', 'build', '*.log', '*.bak', '*.tgz',
|
|
179
179
|
'*.tar.gz', '*.zip', '.env*'
|
|
180
180
|
}
|
|
181
181
|
return patterns
|
|
182
|
-
|
|
182
|
+
|
|
183
183
|
@staticmethod
|
|
184
184
|
def should_exclude(path: Path, patterns: Set[str]) -> bool:
|
|
185
185
|
"""Check if path should be excluded based on patterns."""
|
|
186
|
-
|
|
187
|
-
|
|
186
|
+
from pathlib import PurePath
|
|
187
|
+
|
|
188
|
+
p = PurePath(path.as_posix())
|
|
189
|
+
|
|
188
190
|
for pattern in patterns:
|
|
189
|
-
# Handle
|
|
190
|
-
if '
|
|
191
|
-
|
|
192
|
-
if
|
|
191
|
+
# Handle directory patterns (ending with /)
|
|
192
|
+
if pattern.endswith('/'):
|
|
193
|
+
dir_pattern = pattern.rstrip('/')
|
|
194
|
+
# Check if this is the directory itself or if it's inside the directory
|
|
195
|
+
if path.is_dir() and p.match(dir_pattern):
|
|
196
|
+
return True
|
|
197
|
+
if any(parent.match(dir_pattern) for parent in p.parents):
|
|
193
198
|
return True
|
|
194
|
-
|
|
199
|
+
# Handle file/general patterns
|
|
200
|
+
else:
|
|
201
|
+
if p.match(pattern):
|
|
195
202
|
return True
|
|
196
|
-
|
|
197
|
-
elif pattern.endswith('/'):
|
|
198
|
-
if path.is_dir() and path.name == pattern[:-1]:
|
|
203
|
+
if any(parent.match(pattern) for parent in p.parents):
|
|
199
204
|
return True
|
|
200
|
-
|
|
201
|
-
elif path.name == pattern:
|
|
202
|
-
return True
|
|
203
|
-
# Path contains pattern
|
|
204
|
-
elif pattern in path_str.split('/'):
|
|
205
|
-
return True
|
|
206
|
-
|
|
205
|
+
|
|
207
206
|
return False
|
|
208
|
-
|
|
207
|
+
|
|
209
208
|
@staticmethod
|
|
210
209
|
def pack(
|
|
211
210
|
root: Path,
|
|
@@ -217,33 +216,33 @@ class ContextPacker:
|
|
|
217
216
|
# Default files to include
|
|
218
217
|
context_files = [
|
|
219
218
|
root / "context" / "development.md",
|
|
220
|
-
root / "context" / "agents.md",
|
|
219
|
+
root / "context" / "agents.md",
|
|
221
220
|
root / "context" / "project_tree.md",
|
|
222
221
|
]
|
|
223
|
-
|
|
222
|
+
|
|
224
223
|
# Add directory_notes if it exists
|
|
225
224
|
dir_notes = root / "context" / "directory_notes"
|
|
226
225
|
if dir_notes.exists():
|
|
227
226
|
for note in dir_notes.rglob("*.md"):
|
|
228
227
|
context_files.append(note)
|
|
229
|
-
|
|
228
|
+
|
|
230
229
|
# Add extra files
|
|
231
230
|
if extra_files:
|
|
232
231
|
for extra in extra_files:
|
|
233
232
|
extra_path = root / extra
|
|
234
233
|
if extra_path.exists():
|
|
235
234
|
context_files.append(extra_path)
|
|
236
|
-
|
|
235
|
+
|
|
237
236
|
# Filter out non-existent files
|
|
238
237
|
context_files = [f for f in context_files if f.exists()]
|
|
239
|
-
|
|
238
|
+
|
|
240
239
|
if dry_run:
|
|
241
240
|
return context_files
|
|
242
|
-
|
|
241
|
+
|
|
243
242
|
# Read ignore patterns
|
|
244
243
|
ignore_file = root / ".agentpackignore"
|
|
245
244
|
patterns = ContextPacker.read_ignore_patterns(ignore_file)
|
|
246
|
-
|
|
245
|
+
|
|
247
246
|
# Create tarball
|
|
248
247
|
with tarfile.open(output, "w:gz") as tar:
|
|
249
248
|
for file_path in context_files:
|
|
@@ -251,13 +250,13 @@ class ContextPacker:
|
|
|
251
250
|
if not ContextPacker.should_exclude(file_path, patterns):
|
|
252
251
|
arcname = file_path.relative_to(root)
|
|
253
252
|
tar.add(file_path, arcname=str(arcname))
|
|
254
|
-
|
|
253
|
+
|
|
255
254
|
return context_files
|
|
256
255
|
|
|
257
256
|
|
|
258
257
|
class FeatureOps:
|
|
259
258
|
"""Operations for feature branch management."""
|
|
260
|
-
|
|
259
|
+
|
|
261
260
|
@staticmethod
|
|
262
261
|
def create_feature(
|
|
263
262
|
root: Path,
|
|
@@ -271,17 +270,17 @@ class FeatureOps:
|
|
|
271
270
|
# Check if working tree is clean
|
|
272
271
|
if not force and not GitOps.is_clean(root):
|
|
273
272
|
raise ValueError("Working tree not clean. Commit or stash changes, or use --force")
|
|
274
|
-
|
|
273
|
+
|
|
275
274
|
# Create branch
|
|
276
275
|
branch_name = f"{branch_type}/{name}"
|
|
277
276
|
if not GitOps.create_branch(root, branch_name):
|
|
278
277
|
raise ValueError(f"Failed to create branch {branch_name}")
|
|
279
|
-
|
|
278
|
+
|
|
280
279
|
# Ensure context directory structure
|
|
281
280
|
context_dir = root / "context"
|
|
282
281
|
context_dir.mkdir(exist_ok=True)
|
|
283
282
|
(context_dir / "directory_notes").mkdir(exist_ok=True)
|
|
284
|
-
|
|
283
|
+
|
|
285
284
|
# Update or create development.md
|
|
286
285
|
dev_file = context_dir / "development.md"
|
|
287
286
|
if not dev_file.exists():
|
|
@@ -301,7 +300,7 @@ class FeatureOps:
|
|
|
301
300
|
else:
|
|
302
301
|
# Update existing file
|
|
303
302
|
content = dev_file.read_text()
|
|
304
|
-
|
|
303
|
+
|
|
305
304
|
# Update Primary Goal
|
|
306
305
|
if primary_goal:
|
|
307
306
|
import re
|
|
@@ -315,7 +314,7 @@ class FeatureOps:
|
|
|
315
314
|
f'Overall goal is: {primary_goal}',
|
|
316
315
|
content
|
|
317
316
|
)
|
|
318
|
-
|
|
317
|
+
|
|
319
318
|
# Update Phase
|
|
320
319
|
if phase:
|
|
321
320
|
content = re.sub(
|
|
@@ -328,16 +327,16 @@ class FeatureOps:
|
|
|
328
327
|
f'Next action will be: {phase}',
|
|
329
328
|
content
|
|
330
329
|
)
|
|
331
|
-
|
|
330
|
+
|
|
332
331
|
# Update Last action
|
|
333
332
|
content = re.sub(
|
|
334
333
|
r'Last action was:.*',
|
|
335
334
|
f'Last action was: Created feature branch {branch_name}',
|
|
336
335
|
content
|
|
337
336
|
)
|
|
338
|
-
|
|
337
|
+
|
|
339
338
|
dev_file.write_text(content)
|
|
340
|
-
|
|
339
|
+
|
|
341
340
|
# Create agents.md if missing
|
|
342
341
|
agents_file = context_dir / "agents.md"
|
|
343
342
|
if not agents_file.exists():
|
|
@@ -360,7 +359,7 @@ This project uses a **Context Loop**. Always keep these fields current:
|
|
|
360
359
|
Run `bpsai-pair pack --out agent_pack.tgz` and upload to your session.
|
|
361
360
|
"""
|
|
362
361
|
agents_file.write_text(agents_content)
|
|
363
|
-
|
|
362
|
+
|
|
364
363
|
# Generate project tree
|
|
365
364
|
tree_file = context_dir / "project_tree.md"
|
|
366
365
|
tree_content = f"""# Project Tree (snapshot)
|
|
@@ -371,29 +370,29 @@ _Generated: {datetime.now(timezone.utc).isoformat()}Z_
|
|
|
371
370
|
```
|
|
372
371
|
"""
|
|
373
372
|
tree_file.write_text(tree_content)
|
|
374
|
-
|
|
373
|
+
|
|
375
374
|
# Commit changes
|
|
376
375
|
GitOps.add_commit(
|
|
377
376
|
root,
|
|
378
377
|
[dev_file, agents_file, tree_file],
|
|
379
378
|
f"feat(context): start {branch_name} — Primary Goal: {primary_goal or 'TBD'}"
|
|
380
379
|
)
|
|
381
|
-
|
|
380
|
+
|
|
382
381
|
return True
|
|
383
382
|
|
|
384
383
|
|
|
385
384
|
class LocalCI:
|
|
386
385
|
"""Cross-platform local CI runner."""
|
|
387
|
-
|
|
386
|
+
|
|
388
387
|
@staticmethod
|
|
389
388
|
def run_python_checks(root: Path) -> dict:
|
|
390
389
|
"""Run Python linting, formatting, and tests."""
|
|
391
390
|
results = {}
|
|
392
|
-
|
|
391
|
+
|
|
393
392
|
# Check if Python project
|
|
394
393
|
if not ((root / "pyproject.toml").exists() or (root / "requirements.txt").exists()):
|
|
395
394
|
return results
|
|
396
|
-
|
|
395
|
+
|
|
397
396
|
# Try to run ruff
|
|
398
397
|
try:
|
|
399
398
|
subprocess.run(["ruff", "format", "--check", "."], cwd=root, check=True)
|
|
@@ -401,46 +400,46 @@ class LocalCI:
|
|
|
401
400
|
results["ruff"] = "passed"
|
|
402
401
|
except:
|
|
403
402
|
results["ruff"] = "failed or not installed"
|
|
404
|
-
|
|
403
|
+
|
|
405
404
|
# Try to run mypy
|
|
406
405
|
try:
|
|
407
406
|
subprocess.run(["mypy", "."], cwd=root, check=True)
|
|
408
407
|
results["mypy"] = "passed"
|
|
409
408
|
except:
|
|
410
409
|
results["mypy"] = "failed or not installed"
|
|
411
|
-
|
|
410
|
+
|
|
412
411
|
# Try to run pytest
|
|
413
412
|
try:
|
|
414
413
|
subprocess.run(["pytest", "-q"], cwd=root, check=True)
|
|
415
414
|
results["pytest"] = "passed"
|
|
416
415
|
except:
|
|
417
416
|
results["pytest"] = "failed or not installed"
|
|
418
|
-
|
|
417
|
+
|
|
419
418
|
return results
|
|
420
|
-
|
|
419
|
+
|
|
421
420
|
@staticmethod
|
|
422
421
|
def run_node_checks(root: Path) -> dict:
|
|
423
422
|
"""Run Node.js linting, formatting, and tests."""
|
|
424
423
|
results = {}
|
|
425
|
-
|
|
424
|
+
|
|
426
425
|
if not (root / "package.json").exists():
|
|
427
426
|
return results
|
|
428
|
-
|
|
427
|
+
|
|
429
428
|
# Try npm commands
|
|
430
429
|
try:
|
|
431
430
|
subprocess.run(["npm", "run", "lint"], cwd=root, check=True)
|
|
432
431
|
results["eslint"] = "passed"
|
|
433
432
|
except:
|
|
434
433
|
results["eslint"] = "failed or not configured"
|
|
435
|
-
|
|
434
|
+
|
|
436
435
|
try:
|
|
437
436
|
subprocess.run(["npm", "test"], cwd=root, check=True)
|
|
438
437
|
results["npm test"] = "passed"
|
|
439
438
|
except:
|
|
440
439
|
results["npm test"] = "failed or not configured"
|
|
441
|
-
|
|
440
|
+
|
|
442
441
|
return results
|
|
443
|
-
|
|
442
|
+
|
|
444
443
|
@staticmethod
|
|
445
444
|
def run_all(root: Path) -> dict:
|
|
446
445
|
"""Run all applicable CI checks."""
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bpsai-pair
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: CLI for AI pair-coding workflow
|
|
5
|
+
Author: BPS AI Software
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: typer>=0.12
|
|
9
|
+
Requires-Dist: rich>=13.7
|
|
10
|
+
Requires-Dist: pyyaml>=6.0
|
|
11
|
+
|
|
12
|
+
# bpsai-pair CLI
|
|
13
|
+
|
|
14
|
+
The PairCoder CLI tool for AI pair programming workflows.
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
### Install from PyPI
|
|
19
|
+
```bash
|
|
20
|
+
pip install bpsai-pair
|
|
21
|
+
bpsai-pair --help
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Development Install
|
|
25
|
+
```bash
|
|
26
|
+
cd tools/cli
|
|
27
|
+
pip install -e .
|
|
28
|
+
bpsai-pair --help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### Initialize scaffolding (uses bundled template)
|
|
34
|
+
```bash
|
|
35
|
+
bpsai-pair-init
|
|
36
|
+
# or with main CLI:
|
|
37
|
+
bpsai-pair init
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Create feature branch
|
|
41
|
+
```bash
|
|
42
|
+
bpsai-pair feature auth-refactor \
|
|
43
|
+
--type refactor \
|
|
44
|
+
--primary "Decouple auth via DI" \
|
|
45
|
+
--phase "Refactor auth module + tests"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Pack context for AI
|
|
49
|
+
```bash
|
|
50
|
+
bpsai-pair pack --out agent_pack.tgz
|
|
51
|
+
bpsai-pair pack --list # Preview files
|
|
52
|
+
bpsai-pair pack --json # JSON output
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Update context loop
|
|
56
|
+
```bash
|
|
57
|
+
bpsai-pair context-sync \
|
|
58
|
+
--last "Initialized scaffolding" \
|
|
59
|
+
--next "Set up CI secrets" \
|
|
60
|
+
--blockers "None"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Commands
|
|
64
|
+
|
|
65
|
+
- `bpsai-pair init` - Initialize repo with PairCoder structure
|
|
66
|
+
- `bpsai-pair-init` - Quick init with bundled template (no args)
|
|
67
|
+
- `bpsai-pair feature` - Create feature/fix/refactor branch
|
|
68
|
+
- `bpsai-pair pack` - Package context for AI agents
|
|
69
|
+
- `bpsai-pair context-sync` - Update the Context Loop
|
|
70
|
+
- `bpsai-pair status` - Show current state
|
|
71
|
+
- `bpsai-pair validate` - Check repo structure
|
|
72
|
+
- `bpsai-pair ci` - Run local CI checks
|
|
73
|
+
|
|
74
|
+
## Development
|
|
75
|
+
|
|
76
|
+
Run tests:
|
|
77
|
+
```bash
|
|
78
|
+
pytest
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Build wheel:
|
|
82
|
+
```bash
|
|
83
|
+
python -m build
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Template
|
|
87
|
+
|
|
88
|
+
The CLI bundles a cookiecutter template in `bpsai_pair/data/cookiecutter-paircoder/`
|
|
89
|
+
that gets installed with the package and used by `bpsai-pair-init`.
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
bpsai_pair/__init__.py,sha256=
|
|
1
|
+
bpsai_pair/__init__.py,sha256=j8lrbjl_BGMHWus8G47VvaIP9w7kM_aQ7_kdGVY1hzM,379
|
|
2
2
|
bpsai_pair/__main__.py,sha256=Qd-f8z2Q2vpiEP2x6PBFsJrpACWDVxFKQk820MhFmHo,59
|
|
3
3
|
bpsai_pair/adapters.py,sha256=oowin5juQ9dTRwpHD8eJGBCahI2BoQZVEAhueDD821Y,323
|
|
4
4
|
bpsai_pair/cli.py,sha256=qc5Pcr8gUG-xuJtrqqMT-kxlHi6zUyPDIUrOIuE_110,18422
|
|
5
5
|
bpsai_pair/config.py,sha256=OIBaBkjz_jNsms4zjFxnmEN9gpqRLk1FTPq4ZBNkAUM,8750
|
|
6
6
|
bpsai_pair/init_bundled_cli.py,sha256=AjtdC7yt4p-FatYt5y65XEwH9CtSFKnRc09cgb0di3I,1906
|
|
7
7
|
bpsai_pair/jsonio.py,sha256=C_n42gPLRqjpif-AO0vjE3G1ae_v_PT3cywu7J4Xx-M,189
|
|
8
|
-
bpsai_pair/ops.py,sha256=
|
|
8
|
+
bpsai_pair/ops.py,sha256=BbGEefND2xLCpxtZvKJtyDVd_yWW61g-LtPWXsVTEys,14340
|
|
9
9
|
bpsai_pair/pyutils.py,sha256=5ub27mF4OIaGDm7CDacXsU_9FUZVaPOnYp2NyavFydo,998
|
|
10
10
|
bpsai_pair/utils.py,sha256=TzaN27qKsBlRQCYHBcA06ufQERcc1fcyyOY7QlJQv8M,289
|
|
11
11
|
bpsai_pair/data/cookiecutter-paircoder/cookiecutter.json,sha256=FoaPEPabd5AneVMamzBSw6QNsLZ3DhJRkNtmPOVtSIY,346
|
|
12
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.agentpackignore,sha256=
|
|
12
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.agentpackignore,sha256=CIhaDHCwLQMwHBtVEL5VVgM9c_OQ6jKvRU7H8kvSNEI,167
|
|
13
13
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.editorconfig,sha256=Qpd1apKmHcq5gVWI8jpoxAbY_LF_04tkclK06aE2lB0,235
|
|
14
14
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.gitignore,sha256=ylldDXITCRrj038OGp1pBwihuM4SA6vDvThOvilZV0Q,47
|
|
15
15
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.gitleaks.toml,sha256=STXJmj13hqxp9ejb2hImc1h72BPB_1qsgT_b86o0HYA,373
|
|
16
16
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.pre-commit-config.yaml,sha256=o9AmanEQcUJCYOlnKg4SNcA_rviJKbczGiijyp9oSdY,1021
|
|
17
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/AGENTS.md,sha256=sChAlA26eE_I57Sfv3d6gAbMsu0UQyYxUUtctIbx3RA,1046
|
|
18
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/CLAUDE.md,sha256=5u5fq0HQaRsOwfI_h6GmR7lI7mMt91Bfk4aYOLuIzwU,1012
|
|
17
19
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/CODEOWNERS,sha256=vWB4d6NzBm1qlhLs_4uFQFz6UDICn5Ehn0NUqvXlMYo,715
|
|
18
20
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/CONTRIBUTING.md,sha256=KdZ4GjoyWMSS_kSb4zI0riALXkGuXmsiT09yH5X3Ac4,1191
|
|
19
21
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/SECURITY.md,sha256=L6teX1-0xxToQek2m5lR8iEZlJdzg2TYwpSIIKZDTzE,495
|
|
20
22
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.github/PULL_REQUEST_TEMPLATE.md,sha256=VbjBqMsIcryg3YY8TL8NsGnnzE1Thz43MrBaI3-m5mU,1146
|
|
21
23
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.github/workflows/ci.yml,sha256=VisTKdEHgnL6902gqKczr5FXFZgJlmA0zw2FJBMjb2Q,2766
|
|
22
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.github/workflows/project_tree.yml,sha256=
|
|
23
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/agents.md,sha256=
|
|
24
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/
|
|
25
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md,sha256=wQIGHsI6YDQ_hv1Ps-xYXf9vLmGi73rWbwTGOzt2S60,295
|
|
26
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md.bak,sha256=Nm0e5ZNsTWawkcwU61m-6MFwseWouakPMWCwxCNElUY,251
|
|
24
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/.github/workflows/project_tree.yml,sha256=jCdBPZSVnoMlrZGZRPrfNI_omy2bBneP501iW0yQ4Nc,1702
|
|
25
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/agents.md,sha256=3sxgyfzfBY7tjJuGh5t1e9f4qFS8Z5iaT70OEKzB2Ig,827
|
|
26
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md,sha256=-1Woc7zLMw-YYkkE8_E0indISEiS0wv00qkpCEpyQm8,284
|
|
27
27
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/project_tree.md,sha256=ppNgU2afWoJOnSJbOl9GoJ8EuNT85N005_8LjilEN4w,89
|
|
28
28
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/directory_notes/.gitkeep,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
29
29
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/prompts/deep_research.yml,sha256=lhHG4JRi9Zdsq5J8TNaw2HeupD5oD7mm5J0XPNg1H9A,958
|
|
30
30
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/prompts/implementation.yml,sha256=co2EmK7ojw3lqeNXf99rlU3wxn6mrSuVAZGMlOEZHt4,639
|
|
31
31
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/prompts/roadmap.yml,sha256=EIdCo_EZpPZ9GXXg71IDgMooychyarWPpulojrcGIg8,498
|
|
32
|
-
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/scripts/README.md,sha256=
|
|
32
|
+
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/scripts/README.md,sha256=2eHMbeH479EQwq5QFz83Mw-cb_x2SeYlKolk5hfELIw,367
|
|
33
33
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/src/.gitkeep,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
34
34
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/templates/adr.md,sha256=y_9hvwCgzukpV2pYOjYGk4kD-a6YZZZJqflMjnHvbLE,460
|
|
35
35
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/templates/directory_note.md,sha256=FnNMtnD_CpvVzpp5VzQzS4qddFQ6jfyS8q36ff10DrA,346
|
|
36
36
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/tests/example_contract/README.md,sha256=x5ZpsFnN9QiMWtXJsYw9n27ik5Yf425N5tbzMKOpVQQ,109
|
|
37
37
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/tests/example_integration/README.md,sha256=_G9MzJQq1GR4fVSgGeUFVo2eyzDXJVQn6mqJ5He1Euk,150
|
|
38
|
-
bpsai_pair-0.2.
|
|
39
|
-
bpsai_pair-0.2.
|
|
40
|
-
bpsai_pair-0.2.
|
|
41
|
-
bpsai_pair-0.2.
|
|
42
|
-
bpsai_pair-0.2.
|
|
38
|
+
bpsai_pair-0.2.2.dist-info/METADATA,sha256=rz1nAlU4uxedrEUfYzndhr_A838a0UCHujUkBysVC_A,1812
|
|
39
|
+
bpsai_pair-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
40
|
+
bpsai_pair-0.2.2.dist-info/entry_points.txt,sha256=tK6yOUS1oseLus0bPQYd2cuLJgL1Zr3AGb_YPHVCtCI,101
|
|
41
|
+
bpsai_pair-0.2.2.dist-info/top_level.txt,sha256=kwTlUncK6pxJyQpZQdspexSc-kWtPvZkLUy4ji1P6LU,11
|
|
42
|
+
bpsai_pair-0.2.2.dist-info/RECORD,,
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
# Agents Guide — AI Pair Coding Playbook
|
|
2
|
-
|
|
3
|
-
**Purpose:** Make GPT-5 / Claude / CodeX effective partners for {{ cookiecutter.primary_goal }} while improving modularity, maintainability, and testability.
|
|
4
|
-
|
|
5
|
-
**Audience:** Engineers, Tech Leads, and AI Agents connected to this repo.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## 0) Ground Rules (READ FIRST)
|
|
10
|
-
|
|
11
|
-
* **Single Source of Truth:** This repository and the files in `/context` are canonical for all agent runs.
|
|
12
|
-
* **Safety First:** No destructive ops without backups and a PR. Agents must create `*.bak` or use Git branches.
|
|
13
|
-
* **Tests Before Changes:** Add/extend tests that fail *before* implementing a fix/refactor.
|
|
14
|
-
* **Small, Reviewable Diffs:** Keep changes scoped; open PRs early; link to the relevant roadmap task.
|
|
15
|
-
* **Update Context Every Run:** Always persist “Overall/Last/Next” (see §6) after actions.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 1) Repo Layout & Context Discipline
|
|
20
|
-
|
|
21
|
-
> Keep the agent’s attention on code that matters. Avoid token waste and blind spots.
|
|
22
|
-
|
|
23
|
-
* **Project Tree (authoritative sketch):**
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
.
|
|
27
|
-
├─ /src # Application code
|
|
28
|
-
├─ /tests # Unit/integration tests
|
|
29
|
-
├─ /services # External adapters, API clients
|
|
30
|
-
├─ /infra # IaC / deployment (optional)
|
|
31
|
-
├─ /docs # Human-readable docs
|
|
32
|
-
├─ /context # Agent context files (canonical)
|
|
33
|
-
│ ├─ development.md
|
|
34
|
-
│ ├─ agents.md
|
|
35
|
-
│ ├─ project_tree.md
|
|
36
|
-
│ └─ directory_notes/
|
|
37
|
-
├─ /assets/images # Large/media (EXCLUDED from agent context)
|
|
38
|
-
└─ ...
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
* **Explicit Exclusions:** `/assets/images`, `/dist`, `/build`, `/node_modules`, binaries, large JSON/CSV.
|
|
42
|
-
Agents must **assume these exist** and avoid recommending moves/rewrites.
|
|
43
|
-
|
|
44
|
-
* **Directory Notes (optional but powerful):**
|
|
45
|
-
Add `/context/directory_notes/<dir>.md` with:
|
|
46
|
-
|
|
47
|
-
* Purpose, entry points, invariants, dependency direction.
|
|
48
|
-
* “Do/Don’t” for this directory.
|
|
49
|
-
* Local glossary (domain terms, DTOs).
|
|
50
|
-
* Known pitfalls.
|
|
51
|
-
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
## 2) Branching & PR Conventions
|
|
55
|
-
|
|
56
|
-
* **Branch names:** `feature/<short-goal>` or `refactor/<module>` or `fix/<ticket-id>`
|
|
57
|
-
* **Create branch from:** `main`
|
|
58
|
-
* **PR template must include:**
|
|
59
|
-
|
|
60
|
-
* Goal link to `<PHASE N TASK>`
|
|
61
|
-
* Risk level (Low/Med/High)
|
|
62
|
-
* Test plan (automated + manual)
|
|
63
|
-
* Rollback plan
|
|
64
|
-
* Context update diff (what changed in `/context` files)
|
|
65
|
-
|
|
66
|
-
---
|
|
67
|
-
|
|
68
|
-
## 3) Operating Modes
|
|
69
|
-
|
|
70
|
-
### A) Non-Scripted (Live Collaboration)
|
|
71
|
-
|
|
72
|
-
1. Create branch: `git checkout -b feature/<FEATURE>`
|
|
73
|
-
2. Connect agent (Claude or GPT-5) to repo URL.
|
|
74
|
-
3. Attach context: `/context/development.md`, `/context/agents.md`, relevant `/context/directory_notes/*`.
|
|
75
|
-
4. **Prompt:**
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
PHASE 1 GOAL: <PHASE 1 GOAL>
|
|
79
|
-
Constraints: preserve public APIs, add tests first, no destructive ops.
|
|
80
|
-
Output: stepwise plan + minimal diffs per step.
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### B) Scripted (One-Pass Implementation)
|
|
84
|
-
|
|
85
|
-
1. Create branch: `git checkout -b feature/<FEATURE>`
|
|
86
|
-
2. Attach **only** relevant context files.
|
|
87
|
-
3. **Prompt:**
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
Create a comprehensive script/commit plan to accomplish <PHASE 1 GOAL> in one pass.
|
|
91
|
-
Requirements:
|
|
92
|
-
- Zero breakage; create backups where needed.
|
|
93
|
-
- Generate/modify tests first to capture intended behavior.
|
|
94
|
-
- Respect repo conventions, linting, and formatting.
|
|
95
|
-
- Produce: (a) ordered commit plan, (b) code patches, (c) updated docs, (d) updated context (see §6).
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## 4) Canonical Prompts
|
|
101
|
-
|
|
102
|
-
### 4.1 Deep Research (Kickoff)
|
|
103
|
-
|
|
104
|
-
```
|
|
105
|
-
You are a staff-level engineer embedded in this codebase.
|
|
106
|
-
Objective: Produce a comprehensive plan to improve modularity, maintainability, and achieve {{ cookiecutter.primary_goal }}.
|
|
107
|
-
Deliverables:
|
|
108
|
-
- Architecture review (current vs. target), explicit trade-offs.
|
|
109
|
-
- Refactoring map (by module), dependency inversion opportunities, interface boundaries.
|
|
110
|
-
- Test posture upgrade plan (unit/integration/contract), coverage deltas.
|
|
111
|
-
- Risks, complexity hotspots, and rollback strategies.
|
|
112
|
-
- 3-phase roadmap with measurable outcomes.
|
|
113
|
-
Constraints:
|
|
114
|
-
- Respect exclusions listed in agents.md.
|
|
115
|
-
- Assume assets exist where excluded.
|
|
116
|
-
- Prefer small, reversible changes; maximize seam creation for safe refactors.
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### 4.2 Roadmap → Files
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
Convert the roadmap into:
|
|
123
|
-
- /context/development.md (engineering tasks, test plans, risks)
|
|
124
|
-
- /context/agents.md (this file; update Operating Modes, Prompts if needed)
|
|
125
|
-
Ensure clear Phase 1/2/3 breakdown with milestone checklists and acceptance criteria.
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### 4.3 Implementation Guardrails (per task)
|
|
129
|
-
|
|
130
|
-
```
|
|
131
|
-
For TASK: <task-name>
|
|
132
|
-
- Propose minimal diff solution.
|
|
133
|
-
- Add/adjust tests first to lock behavior.
|
|
134
|
-
- Provide code patches and commands to run tests/lints.
|
|
135
|
-
- Call out risks + rollback.
|
|
136
|
-
- Update context loop (Overall/Last/Next).
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## 5) Testing & Quality Gates
|
|
142
|
-
|
|
143
|
-
* **Unit tests:** focus on pure logic and interfaces.
|
|
144
|
-
* **Integration tests:** external boundaries (DB, queues, HTTP) via testcontainers/mocks.
|
|
145
|
-
* **Contract tests:** for service clients with provider/consumer pacts if applicable.
|
|
146
|
-
* **Coverage targets:** raise or maintain ≥ <TARGET>% lines/branches where practical.
|
|
147
|
-
* **CI gates:** lint, type-check, build, test, basic security scan (SAST/dep audit).
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## 6) Context Loop (Mandatory)
|
|
152
|
-
|
|
153
|
-
Agents **must** persist this block at the end of every session in `/context/development.md` (and in any relevant directory note):
|
|
154
|
-
|
|
155
|
-
```
|
|
156
|
-
## Context Sync (AUTO-UPDATED)
|
|
157
|
-
Overall goal is: {{ cookiecutter.primary_goal }}
|
|
158
|
-
Last action was: <what changed and why> (commit SHA if available)
|
|
159
|
-
Next action will be: <smallest valuable step with owner>
|
|
160
|
-
Blockers/Risks: <if any>
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## 7) Failure Modes & Rollback
|
|
166
|
-
|
|
167
|
-
* **If tests fail:** revert last commit or apply backup. Fix tests first, then code.
|
|
168
|
-
* **If unintended API change:** restore interface, add regression test.
|
|
169
|
-
* **If scope creep:** park in `Phase N Backlog` with rationale.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
|
-
## 8) Example Exclusion Prompt
|
|
174
|
-
|
|
175
|
-
> *Drop into your agent prompt when large dirs are omitted.*
|
|
176
|
-
|
|
177
|
-
“Relevant image/media assets exist under `/assets/images` but are intentionally excluded from your context to conserve tokens. **Do not** propose changes that relocate, inline, or re-encode assets. Assume paths referenced in code are valid. Focus your analysis on `/src`, `/services`, and `/tests`. If a change seems to require asset inspection, propose an interface-level abstraction instead.”
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## 9) Definitions
|
|
182
|
-
|
|
183
|
-
* **Seam:** a point in code where behavior can be changed without editing the code (e.g., via interface, DI, adapter).
|
|
184
|
-
* **Backwards compatibility window:** period where both old and new APIs coexist with deprecation notices.
|
|
185
|
-
|
|
186
|
-
---
|
|
187
|
-
|
|
188
|
-
## 10) Tools & Commands (fill per repo)
|
|
189
|
-
|
|
190
|
-
* **Install:** `<cmd>`
|
|
191
|
-
* **Format/Lint:** `<cmd>`
|
|
192
|
-
* **Test (unit):** `<cmd>`
|
|
193
|
-
* **Test (integration):** `<cmd>`
|
|
194
|
-
* **Type check:** `<cmd>`
|
|
195
|
-
* **Local CI bundle:** `<cmd>`
|
|
196
|
-
|
bpsai_pair/data/cookiecutter-paircoder/{{cookiecutter.project_slug}}/context/development.md.bak
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
# Development Log
|
|
2
|
-
|
|
3
|
-
**Phase:** (set by first feature)
|
|
4
|
-
**Primary Goal:** (set by first feature)
|
|
5
|
-
|
|
6
|
-
## Context Sync (AUTO-UPDATED)
|
|
7
|
-
|
|
8
|
-
- **Overall goal is:** (set by feature)
|
|
9
|
-
- **Last action was:** (set by feature)
|
|
10
|
-
- **Next action will be:** (set by feature)
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: bpsai-pair
|
|
3
|
-
Version: 0.2.0
|
|
4
|
-
Summary: CLI for AI pair-coding workflow
|
|
5
|
-
Author: BPS AI Software
|
|
6
|
-
Requires-Python: >=3.9
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
Requires-Dist: typer>=0.12
|
|
9
|
-
Requires-Dist: rich>=13.7
|
|
10
|
-
Requires-Dist: pyyaml>=6.0
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# bpsai-pair CLI
|
|
14
|
-
|
|
15
|
-
## Quick start (local, un-packaged)
|
|
16
|
-
```
|
|
17
|
-
python -m tools.cli.bpsai_pair --help
|
|
18
|
-
python -m tools.cli.bpsai_pair init tools/cookiecutter-paircoder
|
|
19
|
-
python -m tools.cli.bpsai_pair feature auth-di --primary "Decouple auth via DI" --phase "Refactor auth + tests"
|
|
20
|
-
python -m tools.cli.bpsai_pair pack --extra README.md
|
|
21
|
-
python -m tools.cli.bpsai_pair context-sync --last "initialized scaffolding" --nxt "set up CI secrets" --blockers "none"
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Install as a CLI
|
|
25
|
-
```
|
|
26
|
-
cd tools/cli
|
|
27
|
-
pip install -e .
|
|
28
|
-
# now available as: bpsai-pair --help
|
|
29
|
-
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|