codeforge-dev 1.7.0 → 1.8.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.
- package/.devcontainer/.env +4 -6
- package/.devcontainer/.env.example +29 -0
- package/.devcontainer/.gitignore +8 -0
- package/.devcontainer/.secrets.example +12 -0
- package/.devcontainer/CHANGELOG.md +130 -0
- package/.devcontainer/CLAUDE.md +56 -19
- package/.devcontainer/README.md +111 -56
- package/.devcontainer/config/{main-system-prompt.md → defaults/main-system-prompt.md} +72 -0
- package/.devcontainer/config/file-manifest.json +20 -0
- package/.devcontainer/devcontainer.json +20 -0
- package/.devcontainer/docs/configuration-reference.md +90 -0
- package/.devcontainer/docs/keybindings.md +100 -0
- package/.devcontainer/docs/optional-features.md +129 -0
- package/.devcontainer/docs/plugins.md +154 -0
- package/.devcontainer/docs/troubleshooting.md +128 -0
- package/.devcontainer/features/agent-browser/install.sh +6 -0
- package/.devcontainer/features/ast-grep/install.sh +6 -0
- package/.devcontainer/features/biome/README.md +27 -0
- package/.devcontainer/features/biome/install.sh +6 -0
- package/.devcontainer/features/ccburn/install.sh +6 -0
- package/.devcontainer/features/ccstatusline/devcontainer-feature.json +5 -0
- package/.devcontainer/features/ccstatusline/install.sh +7 -0
- package/.devcontainer/features/ccusage/install.sh +6 -0
- package/.devcontainer/features/claude-monitor/install.sh +6 -0
- package/.devcontainer/features/dprint/README.md +30 -0
- package/.devcontainer/features/dprint/devcontainer-feature.json +18 -0
- package/.devcontainer/features/dprint/install.sh +131 -0
- package/.devcontainer/features/hadolint/README.md +35 -0
- package/.devcontainer/features/hadolint/devcontainer-feature.json +13 -0
- package/.devcontainer/features/hadolint/install.sh +86 -0
- package/.devcontainer/features/lsp-servers/devcontainer-feature.json +5 -0
- package/.devcontainer/features/lsp-servers/install.sh +7 -0
- package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +5 -0
- package/.devcontainer/features/mcp-qdrant/install.sh +13 -6
- package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +5 -0
- package/.devcontainer/features/mcp-reasoner/install.sh +8 -1
- package/.devcontainer/features/notify-hook/devcontainer-feature.json +5 -0
- package/.devcontainer/features/notify-hook/install.sh +7 -0
- package/.devcontainer/features/ruff/README.md +26 -0
- package/.devcontainer/features/ruff/devcontainer-feature.json +21 -0
- package/.devcontainer/features/ruff/install.sh +74 -0
- package/.devcontainer/features/shellcheck/README.md +38 -0
- package/.devcontainer/features/shellcheck/devcontainer-feature.json +13 -0
- package/.devcontainer/features/shellcheck/install.sh +24 -0
- package/.devcontainer/features/shfmt/README.md +37 -0
- package/.devcontainer/features/shfmt/devcontainer-feature.json +13 -0
- package/.devcontainer/features/shfmt/install.sh +85 -0
- package/.devcontainer/features/splitrail/devcontainer-feature.json +5 -0
- package/.devcontainer/features/splitrail/install.sh +7 -0
- package/.devcontainer/features/tmux/install.sh +8 -0
- package/.devcontainer/features/tree-sitter/install.sh +6 -0
- package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +3 -10
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/__pycache__/format-on-stop.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +114 -9
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +4 -5
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/__pycache__/lint-file.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +478 -76
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/.claude-plugin/plugin.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/AGENT-REDIRECTION.md +226 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/architect.md +17 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/bash-exec.md +4 -4
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/claude-guide.md +14 -23
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/debug-logs.md +2 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/dependency-analyst.md +2 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +13 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/explorer.md +2 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/generalist.md +10 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/migrator.md +6 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/refactorer.md +4 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +36 -23
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/statusline-config.md +3 -3
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/test-writer.md +3 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +39 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/advisory-test-runner.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/collect-edited-files.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/commit-reminder.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/git-state-injector.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/redirect-builtin-agents.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/ticket-linker.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/todo-harvester.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/advisory-test-runner.py +174 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/collect-edited-files.py +8 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/commit-reminder.py +90 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/git-state-injector.py +114 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py +61 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/ticket-linker.py +137 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/todo-harvester.py +130 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/SKILL.md +224 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/error-handling.md +166 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/rest-conventions.md +215 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/SKILL.md +211 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/references/language-patterns.md +327 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/SKILL.md +134 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/ecosystem-commands.md +264 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/license-compliance.md +80 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/SKILL.md +153 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/api-doc-templates.md +221 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/docstring-formats.md +296 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/SKILL.md +150 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/javascript-migrations.md +179 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/python-migrations.md +141 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/SKILL.md +32 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/__pycache__/block-dangerous.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +1 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/__pycache__/guard-protected.cpython-314.pyc +0 -0
- package/.devcontainer/scripts/check-setup.sh +72 -0
- package/.devcontainer/scripts/setup-aliases.sh +43 -3
- package/.devcontainer/scripts/setup-auth.sh +74 -0
- package/.devcontainer/scripts/setup-config.sh +112 -22
- package/.devcontainer/scripts/setup-update-claude.sh +8 -0
- package/.devcontainer/scripts/setup.sh +46 -13
- package/README.md +23 -190
- package/package.json +1 -1
- package/setup.js +245 -71
- package/.devcontainer/features/claude-code/README.md +0 -498
- package/.devcontainer/features/claude-code/config/settings.json +0 -72
- package/.devcontainer/features/claude-code/config/system-prompt.md +0 -118
- package/.devcontainer/features/claude-code/config/world-building-sp.md +0 -1432
- package/.devcontainer/features/claude-code/devcontainer-feature.json +0 -42
- package/.devcontainer/features/claude-code/install.sh +0 -466
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +0 -7
- package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +0 -17
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +0 -6
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +0 -14
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +0 -989
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +0 -33
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +0 -71
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +0 -68
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +0 -120
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +0 -133
- package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +0 -253
- /package/.devcontainer/config/{keybindings.json → defaults/keybindings.json} +0 -0
- /package/.devcontainer/config/{settings.json → defaults/settings.json} +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Python Migration Patterns
|
|
2
|
+
|
|
3
|
+
## Python Version Upgrades (3.8 → 3.12)
|
|
4
|
+
|
|
5
|
+
### Typing Modernization
|
|
6
|
+
|
|
7
|
+
| Old Pattern (3.8) | New Pattern (3.10+) | Search Pattern |
|
|
8
|
+
|-------------------|---------------------|----------------|
|
|
9
|
+
| `Optional[X]` | `X \| None` | `from typing import Optional` |
|
|
10
|
+
| `Union[X, Y]` | `X \| Y` | `from typing import Union` |
|
|
11
|
+
| `List[str]` | `list[str]` | `from typing import List` |
|
|
12
|
+
| `Dict[str, int]` | `dict[str, int]` | `from typing import Dict` |
|
|
13
|
+
| `Tuple[int, ...]` | `tuple[int, ...]` | `from typing import Tuple` |
|
|
14
|
+
| `Set[str]` | `set[str]` | `from typing import Set` |
|
|
15
|
+
| `FrozenSet[str]` | `frozenset[str]` | `from typing import FrozenSet` |
|
|
16
|
+
| `Type[X]` | `type[X]` | `from typing import Type` |
|
|
17
|
+
|
|
18
|
+
**Migration step**: Replace all `typing` imports of built-in generics with lowercase equivalents. Remove unused `typing` imports after replacement.
|
|
19
|
+
|
|
20
|
+
### Deprecated / Removed Modules
|
|
21
|
+
|
|
22
|
+
| Module | Removed In | Replacement |
|
|
23
|
+
|--------|-----------|-------------|
|
|
24
|
+
| `distutils` | 3.12 | `setuptools`, `shutil` |
|
|
25
|
+
| `imp` | 3.12 | `importlib` |
|
|
26
|
+
| `lib2to3` | 3.13 | `libcst` or manual |
|
|
27
|
+
| `aifc` | 3.13 | Third-party audio libraries |
|
|
28
|
+
| `cgi` | 3.13 | `urllib.parse`, `email.message` |
|
|
29
|
+
| `cgitb` | 3.13 | `traceback` |
|
|
30
|
+
|
|
31
|
+
### collections.abc Migration
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
# Old (deprecated in 3.9, removed warning in 3.10+)
|
|
35
|
+
from collections import MutableMapping, Sequence, Iterable
|
|
36
|
+
|
|
37
|
+
# New
|
|
38
|
+
from collections.abc import MutableMapping, Sequence, Iterable
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Search for: `from collections import` and check if any imported names are ABCs.
|
|
42
|
+
|
|
43
|
+
### asyncio Changes
|
|
44
|
+
|
|
45
|
+
| Old Pattern | New Pattern (3.10+) | Version |
|
|
46
|
+
|------------|---------------------|---------|
|
|
47
|
+
| `asyncio.get_event_loop()` | `asyncio.get_running_loop()` (in async context) | 3.10 |
|
|
48
|
+
| `@asyncio.coroutine` / `yield from` | `async def` / `await` | 3.8 (removed 3.11) |
|
|
49
|
+
| `loop.create_task()` | `asyncio.create_task()` | 3.7 |
|
|
50
|
+
| `asyncio.wait(tasks)` | `asyncio.wait(tasks)` (must pass set) | 3.11 |
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Pydantic v1 → v2
|
|
55
|
+
|
|
56
|
+
### Complete API Mapping
|
|
57
|
+
|
|
58
|
+
| Pydantic v1 | Pydantic v2 | Notes |
|
|
59
|
+
|-------------|-------------|-------|
|
|
60
|
+
| `@validator('field')` | `@field_validator('field')` | Import from `pydantic` |
|
|
61
|
+
| `@validator('field', pre=True)` | `@field_validator('field', mode='before')` | `mode='before'` replaces `pre=True` |
|
|
62
|
+
| `@validator('field', always=True)` | `@field_validator('field')` + `@model_validator` | `always` removed; use model validator for defaults |
|
|
63
|
+
| `@root_validator` | `@model_validator` | Import from `pydantic` |
|
|
64
|
+
| `@root_validator(pre=True)` | `@model_validator(mode='before')` | Mode parameter |
|
|
65
|
+
| `.dict()` | `.model_dump()` | Method renamed |
|
|
66
|
+
| `.json()` | `.model_dump_json()` | Method renamed |
|
|
67
|
+
| `.parse_obj(data)` | `.model_validate(data)` | Class method renamed |
|
|
68
|
+
| `.parse_raw(json_str)` | `.model_validate_json(json_str)` | Class method renamed |
|
|
69
|
+
| `.schema()` | `.model_json_schema()` | Class method renamed |
|
|
70
|
+
| `.construct()` | `.model_construct()` | Class method renamed |
|
|
71
|
+
| `.copy()` | `.model_copy()` | Method renamed |
|
|
72
|
+
| `class Config:` | `model_config = ConfigDict(...)` | Inline config dict |
|
|
73
|
+
| `Config.schema_extra` | `model_config = ConfigDict(json_schema_extra=...)` | Renamed field |
|
|
74
|
+
| `Config.orm_mode = True` | `model_config = ConfigDict(from_attributes=True)` | Renamed field |
|
|
75
|
+
| `Config.allow_population_by_field_name` | `model_config = ConfigDict(populate_by_name=True)` | Renamed field |
|
|
76
|
+
| `Field(regex=...)` | `Field(pattern=...)` | Parameter renamed |
|
|
77
|
+
|
|
78
|
+
### Migration Steps
|
|
79
|
+
|
|
80
|
+
1. Update `pydantic` version in manifest: `pydantic>=2.0`
|
|
81
|
+
2. Convert `class Config:` blocks to `model_config = ConfigDict(...)` — add `from pydantic import ConfigDict`
|
|
82
|
+
3. Convert `@validator` to `@field_validator` — update signatures (first arg is now `cls`, values accessed differently)
|
|
83
|
+
4. Convert `@root_validator` to `@model_validator` — update mode parameter
|
|
84
|
+
5. Replace `.dict()` → `.model_dump()`, `.json()` → `.model_dump_json()`
|
|
85
|
+
6. Replace `.parse_obj()` → `.model_validate()`, `.parse_raw()` → `.model_validate_json()`
|
|
86
|
+
7. Run `pytest` after each step
|
|
87
|
+
|
|
88
|
+
### Validator Signature Change
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# v1
|
|
92
|
+
@validator('name')
|
|
93
|
+
def validate_name(cls, v, values):
|
|
94
|
+
return v.strip()
|
|
95
|
+
|
|
96
|
+
# v2
|
|
97
|
+
@field_validator('name')
|
|
98
|
+
@classmethod
|
|
99
|
+
def validate_name(cls, v: str, info: ValidationInfo) -> str:
|
|
100
|
+
return v.strip()
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Note: In v2, `info.data` replaces `values` for accessing other fields.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Django Version Upgrades
|
|
108
|
+
|
|
109
|
+
### Common Breaking Changes by Version
|
|
110
|
+
|
|
111
|
+
| Version | Key Changes |
|
|
112
|
+
|---------|------------|
|
|
113
|
+
| 3.2 → 4.0 | `default_app_config` removed, `USE_L10N` default changed to True |
|
|
114
|
+
| 4.0 → 4.1 | Async view support expanded, `assertFormError` signature changed |
|
|
115
|
+
| 4.1 → 4.2 | `CSRF_TRUSTED_ORIGINS` requires scheme, psycopg3 support |
|
|
116
|
+
| 4.2 → 5.0 | `DEFAULT_AUTO_FIELD` required, `logout()` changed to POST-only |
|
|
117
|
+
| 5.0 → 5.1 | `LoginRequiredMiddleware` added, `HttpResponse.content` stricter |
|
|
118
|
+
|
|
119
|
+
### Migration Steps
|
|
120
|
+
|
|
121
|
+
1. Run `python -m django check --deploy` to identify deprecation warnings.
|
|
122
|
+
2. Read the release notes for each version between current and target.
|
|
123
|
+
3. Upgrade one minor version at a time (4.0→4.1→4.2, not 4.0→4.2).
|
|
124
|
+
4. Run `python manage.py migrate` and `python manage.py test` after each version bump.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## SQLAlchemy 1.x → 2.x
|
|
129
|
+
|
|
130
|
+
### Key Changes
|
|
131
|
+
|
|
132
|
+
| SQLAlchemy 1.x | SQLAlchemy 2.x | Notes |
|
|
133
|
+
|----------------|----------------|-------|
|
|
134
|
+
| `session.query(Model)` | `select(Model)` + `session.execute()` | New select() style |
|
|
135
|
+
| `query.filter()` | `select().where()` | Method renamed |
|
|
136
|
+
| `query.all()` | `session.execute(stmt).scalars().all()` | Execution separated from query building |
|
|
137
|
+
| `Column(Integer)` | `mapped_column(Integer)` | New declarative style |
|
|
138
|
+
| `relationship()` | `relationship()` | Mostly compatible |
|
|
139
|
+
| `engine.execute()` | Removed | Use `with engine.connect() as conn: conn.execute()` |
|
|
140
|
+
|
|
141
|
+
Run with `SQLALCHEMY_WARN_20=1` environment variable to get deprecation warnings for 1.x patterns before migrating.
|
|
@@ -30,6 +30,18 @@ Write specifications with a hostile reader in mind -- someone who will interpret
|
|
|
30
30
|
|
|
31
31
|
---
|
|
32
32
|
|
|
33
|
+
## Spec Sizing & AI Context Rules
|
|
34
|
+
|
|
35
|
+
Specifications are loaded into AI context windows with limited capacity. Design for consumption.
|
|
36
|
+
|
|
37
|
+
**Hard limit:** ≤200 lines per spec file. If a feature needs more, split into sub-specs (one per sub-feature) with a ≤50 line overview linking them.
|
|
38
|
+
|
|
39
|
+
**Reference, don't reproduce:** Never inline source code, SQL DDL, Pydantic models, or TypeScript interfaces. Reference the file path and line range instead. The code is the source of truth — duplicated snippets go stale silently.
|
|
40
|
+
|
|
41
|
+
**Structure for independent loading:** Each spec file must be useful on its own. Include: version, status, last-updated date, intent, key file paths, and acceptance criteria in every spec.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
33
45
|
## EARS Requirement Formats
|
|
34
46
|
|
|
35
47
|
EARS (Easy Approach to Requirements Syntax) provides five templates that eliminate the most common ambiguities in natural-language requirements. Each template has a specific trigger pattern.
|
|
@@ -160,6 +172,17 @@ For requirements with multiple input/output combinations:
|
|
|
160
172
|
|
|
161
173
|
A complete specification follows this structure. Not every section is needed for every feature -- scale the document to the complexity.
|
|
162
174
|
|
|
175
|
+
Every spec file starts with metadata:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
# Feature: [Name]
|
|
179
|
+
**Version:** v0.X.0
|
|
180
|
+
**Status:** implemented | partial | planned
|
|
181
|
+
**Last Updated:** YYYY-MM-DD
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Status tells you whether to trust it, version tells you where it belongs, last-updated tells you when it was last verified.
|
|
185
|
+
|
|
163
186
|
### 1. Problem Statement
|
|
164
187
|
What problem does this feature solve? Who has this problem? What's the cost of not solving it? (2-3 sentences)
|
|
165
188
|
|
|
@@ -226,6 +249,15 @@ The cases nobody thinks about until they happen:
|
|
|
226
249
|
### 7. Out of Scope
|
|
227
250
|
Explicit non-goals to prevent scope creep (can reference the Scope section or expand here).
|
|
228
251
|
|
|
252
|
+
### 8. Key Files
|
|
253
|
+
Source files most relevant to this feature — paths an implementer should read.
|
|
254
|
+
|
|
255
|
+
### 9. Implementation Notes
|
|
256
|
+
Post-implementation only. Capture deviations from the original spec — what changed and why.
|
|
257
|
+
|
|
258
|
+
### 10. Discrepancies
|
|
259
|
+
Gaps between spec intent and actual build. Prevents the next session from re-planning decided work.
|
|
260
|
+
|
|
229
261
|
---
|
|
230
262
|
|
|
231
263
|
## Completeness Checklist
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Verify CodeForge setup is working correctly
|
|
3
|
+
# Run anytime with: check-setup
|
|
4
|
+
|
|
5
|
+
echo "CodeForge Setup Check"
|
|
6
|
+
echo "━━━━━━━━━━━━━━━━━━━━"
|
|
7
|
+
|
|
8
|
+
PASS=0; FAIL=0; WARN=0
|
|
9
|
+
|
|
10
|
+
check() {
|
|
11
|
+
local label="$1" cmd="$2"
|
|
12
|
+
if eval "$cmd" >/dev/null 2>&1; then
|
|
13
|
+
printf " ✓ %s\n" "$label"
|
|
14
|
+
PASS=$((PASS + 1))
|
|
15
|
+
else
|
|
16
|
+
printf " ✗ %s\n" "$label"
|
|
17
|
+
FAIL=$((FAIL + 1))
|
|
18
|
+
fi
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
warn_check() {
|
|
22
|
+
local label="$1" cmd="$2"
|
|
23
|
+
if eval "$cmd" >/dev/null 2>&1; then
|
|
24
|
+
printf " ✓ %s\n" "$label"
|
|
25
|
+
PASS=$((PASS + 1))
|
|
26
|
+
else
|
|
27
|
+
printf " ⚠ %s\n" "$label"
|
|
28
|
+
WARN=$((WARN + 1))
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "Core:"
|
|
34
|
+
check "Claude Code installed" "command -v claude"
|
|
35
|
+
check "cc alias available" "type cc"
|
|
36
|
+
check "Config directory exists" "[ -d '${CLAUDE_CONFIG_DIR:-/workspaces/.claude}' ]"
|
|
37
|
+
check "Settings file exists" "[ -f '${CLAUDE_CONFIG_DIR:-/workspaces/.claude}/settings.json' ]"
|
|
38
|
+
|
|
39
|
+
echo ""
|
|
40
|
+
echo "Authentication:"
|
|
41
|
+
warn_check "GitHub CLI authenticated" "gh auth status"
|
|
42
|
+
warn_check "Git user configured" "git config --global user.name"
|
|
43
|
+
|
|
44
|
+
echo ""
|
|
45
|
+
echo "Tools:"
|
|
46
|
+
check "Node.js" "command -v node"
|
|
47
|
+
check "Python" "command -v python3"
|
|
48
|
+
check "uv" "command -v uv"
|
|
49
|
+
warn_check "Go" "command -v go"
|
|
50
|
+
warn_check "Bun" "command -v bun"
|
|
51
|
+
warn_check "Docker" "command -v docker"
|
|
52
|
+
|
|
53
|
+
echo ""
|
|
54
|
+
echo "Development:"
|
|
55
|
+
warn_check "biome" "command -v biome"
|
|
56
|
+
warn_check "ruff" "command -v ruff"
|
|
57
|
+
warn_check "dprint" "command -v dprint"
|
|
58
|
+
warn_check "shfmt" "command -v shfmt"
|
|
59
|
+
warn_check "shellcheck" "command -v shellcheck"
|
|
60
|
+
warn_check "hadolint" "command -v hadolint"
|
|
61
|
+
warn_check "ast-grep" "command -v ast-grep"
|
|
62
|
+
warn_check "tmux" "command -v tmux"
|
|
63
|
+
|
|
64
|
+
echo ""
|
|
65
|
+
echo "━━━━━━━━━━━━━━━━━━━━"
|
|
66
|
+
echo " $PASS passed, $FAIL failed, $WARN warnings"
|
|
67
|
+
|
|
68
|
+
if [ $FAIL -gt 0 ]; then
|
|
69
|
+
echo ""
|
|
70
|
+
echo " Run 'cc-tools' for detailed version info."
|
|
71
|
+
exit 1
|
|
72
|
+
fi
|
|
@@ -12,6 +12,11 @@ ALIAS_CCRAW='alias ccraw="command claude"'
|
|
|
12
12
|
|
|
13
13
|
for rc in ~/.bashrc ~/.zshrc; do
|
|
14
14
|
if [ -f "$rc" ]; then
|
|
15
|
+
# --- Backup before modifying ---
|
|
16
|
+
cp "$rc" "${rc}.bak.$(date +%s)" 2>/dev/null || true
|
|
17
|
+
# Clean old backups (keep last 3)
|
|
18
|
+
ls -t "${rc}.bak."* 2>/dev/null | tail -n +4 | xargs rm -f 2>/dev/null || true
|
|
19
|
+
|
|
15
20
|
# --- Cleanup old definitions ---
|
|
16
21
|
|
|
17
22
|
# Remove old cc alias
|
|
@@ -46,6 +51,13 @@ for rc in ~/.bashrc ~/.zshrc; do
|
|
|
46
51
|
if grep -q "alias specwright=" "$rc" 2>/dev/null; then
|
|
47
52
|
sed -i '/alias specwright=/d' "$rc"
|
|
48
53
|
fi
|
|
54
|
+
# Remove old cc-tools/check-setup functions
|
|
55
|
+
if grep -q "^cc-tools()" "$rc" 2>/dev/null; then
|
|
56
|
+
sed -i '/^cc-tools() {/,/^}/d' "$rc"
|
|
57
|
+
fi
|
|
58
|
+
if grep -q "alias check-setup=" "$rc" 2>/dev/null; then
|
|
59
|
+
sed -i '/alias check-setup=/d' "$rc"
|
|
60
|
+
fi
|
|
49
61
|
|
|
50
62
|
# --- Add environment and aliases (idempotent) ---
|
|
51
63
|
# Guard: skip if aliases already present from a previous run
|
|
@@ -67,11 +79,39 @@ for rc in ~/.bashrc ~/.zshrc; do
|
|
|
67
79
|
echo "$ALIAS_CC" >> "$rc"
|
|
68
80
|
echo "$ALIAS_CLAUDE" >> "$rc"
|
|
69
81
|
echo "$ALIAS_CCRAW" >> "$rc"
|
|
82
|
+
|
|
83
|
+
# cc-tools: list all available CodeForge tools with version info
|
|
84
|
+
cat >> "$rc" << 'CCTOOLS_EOF'
|
|
85
|
+
cc-tools() {
|
|
86
|
+
echo "CodeForge Available Tools"
|
|
87
|
+
echo "━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
88
|
+
printf " %-20s %s\n" "COMMAND" "STATUS"
|
|
89
|
+
echo " ────────────────────────────────────"
|
|
90
|
+
for cmd in claude cc ccraw ccusage ccburn claude-monitor \
|
|
91
|
+
ruff biome dprint shfmt shellcheck hadolint \
|
|
92
|
+
ast-grep tree-sitter pyright typescript-language-server \
|
|
93
|
+
agent-browser gh docker git jq tmux bun go; do
|
|
94
|
+
if command -v "$cmd" >/dev/null 2>&1; then
|
|
95
|
+
ver=$("$cmd" --version 2>/dev/null | head -1 || echo "installed")
|
|
96
|
+
printf " %-20s ✓ %s\n" "$cmd" "$ver"
|
|
97
|
+
else
|
|
98
|
+
printf " %-20s ✗ not found\n" "$cmd"
|
|
99
|
+
fi
|
|
100
|
+
done
|
|
101
|
+
}
|
|
102
|
+
CCTOOLS_EOF
|
|
103
|
+
|
|
104
|
+
# check-setup: alias to the health check script
|
|
105
|
+
DEVCONTAINER_SCRIPTS="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
106
|
+
echo "alias check-setup='bash ${DEVCONTAINER_SCRIPTS}/check-setup.sh'" >> "$rc"
|
|
107
|
+
|
|
70
108
|
echo "[setup-aliases] Added aliases to $(basename $rc)"
|
|
71
109
|
fi
|
|
72
110
|
done
|
|
73
111
|
|
|
74
112
|
echo "[setup-aliases] Aliases configured:"
|
|
75
|
-
echo " cc
|
|
76
|
-
echo " claude
|
|
77
|
-
echo " ccraw
|
|
113
|
+
echo " cc -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
|
|
114
|
+
echo " claude -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
|
|
115
|
+
echo " ccraw -> vanilla claude without any config"
|
|
116
|
+
echo " cc-tools -> list all available CodeForge tools"
|
|
117
|
+
echo " check-setup -> verify CodeForge setup health"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Configure Git (GitHub CLI) and NPM authentication from .secrets file or environment variables.
|
|
3
|
+
# Environment variables override .secrets values, supporting Codespaces secrets and localEnv.
|
|
4
|
+
# Auth failure should not block other setup steps, so set -e is intentionally omitted.
|
|
5
|
+
|
|
6
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
7
|
+
DEVCONTAINER_DIR="$(dirname "$SCRIPT_DIR")"
|
|
8
|
+
SECRETS_FILE="$DEVCONTAINER_DIR/.secrets"
|
|
9
|
+
|
|
10
|
+
# Source .secrets file if it exists (env vars take precedence via :- defaults below)
|
|
11
|
+
if [ -f "$SECRETS_FILE" ]; then
|
|
12
|
+
echo "[setup-auth] Loading tokens from .secrets file"
|
|
13
|
+
set -a
|
|
14
|
+
source "$SECRETS_FILE"
|
|
15
|
+
set +a
|
|
16
|
+
else
|
|
17
|
+
echo "[setup-auth] No .secrets file found, using environment variables only"
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
AUTH_CONFIGURED=false
|
|
21
|
+
|
|
22
|
+
# --- GitHub CLI auth ---
|
|
23
|
+
if [ -n "$GH_TOKEN" ]; then
|
|
24
|
+
echo "[setup-auth] Authenticating GitHub CLI..."
|
|
25
|
+
# Capture token value then unset env var — gh refuses --with-token when
|
|
26
|
+
# GH_TOKEN is already exported (it says "use the env var instead").
|
|
27
|
+
_gh_token="$GH_TOKEN"
|
|
28
|
+
unset GH_TOKEN
|
|
29
|
+
if gh auth login --with-token <<< "$_gh_token" 2>/dev/null; then
|
|
30
|
+
echo "[setup-auth] GitHub CLI authenticated"
|
|
31
|
+
gh auth setup-git 2>/dev/null && echo "[setup-auth] Git credential helper configured"
|
|
32
|
+
AUTH_CONFIGURED=true
|
|
33
|
+
else
|
|
34
|
+
echo "[setup-auth] WARNING: GitHub CLI authentication failed"
|
|
35
|
+
fi
|
|
36
|
+
unset _gh_token
|
|
37
|
+
else
|
|
38
|
+
echo "[setup-auth] GH_TOKEN not set, skipping GitHub CLI auth"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# --- Git user config ---
|
|
42
|
+
if [ -n "$GH_USERNAME" ]; then
|
|
43
|
+
git config --global user.name "$GH_USERNAME"
|
|
44
|
+
echo "[setup-auth] Git user.name set to $GH_USERNAME"
|
|
45
|
+
unset GH_USERNAME
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
if [ -n "$GH_EMAIL" ]; then
|
|
49
|
+
git config --global user.email "$GH_EMAIL"
|
|
50
|
+
echo "[setup-auth] Git user.email set to $GH_EMAIL"
|
|
51
|
+
unset GH_EMAIL
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
# --- NPM auth ---
|
|
55
|
+
if [ -n "$NPM_TOKEN" ]; then
|
|
56
|
+
echo "[setup-auth] Configuring NPM registry auth..."
|
|
57
|
+
if npm config set "//registry.npmjs.org/:_authToken=$NPM_TOKEN" 2>/dev/null; then
|
|
58
|
+
echo "[setup-auth] NPM auth token configured"
|
|
59
|
+
AUTH_CONFIGURED=true
|
|
60
|
+
else
|
|
61
|
+
echo "[setup-auth] WARNING: NPM auth configuration failed"
|
|
62
|
+
fi
|
|
63
|
+
unset NPM_TOKEN
|
|
64
|
+
else
|
|
65
|
+
echo "[setup-auth] NPM_TOKEN not set, skipping NPM auth"
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# --- Summary ---
|
|
69
|
+
if [ "$AUTH_CONFIGURED" = true ]; then
|
|
70
|
+
echo "[setup-auth] Auth configuration complete"
|
|
71
|
+
else
|
|
72
|
+
echo "[setup-auth] No tokens provided — auth configuration skipped"
|
|
73
|
+
echo "[setup-auth] To configure, copy .secrets.example to .secrets and fill in your tokens"
|
|
74
|
+
fi
|
|
@@ -1,30 +1,120 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# Copy
|
|
2
|
+
# Copy configuration files to workspace based on file-manifest.json
|
|
3
3
|
|
|
4
4
|
CONFIG_DIR="${CONFIG_SOURCE_DIR:?CONFIG_SOURCE_DIR not set}"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
echo "[setup-config]
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
5
|
+
MANIFEST="$CONFIG_DIR/file-manifest.json"
|
|
6
|
+
|
|
7
|
+
log() { echo "[setup-config] $*"; }
|
|
8
|
+
warn() { echo "[setup-config] WARNING: $*"; }
|
|
9
|
+
err() { echo "[setup-config] ERROR: $*" >&2; }
|
|
10
|
+
|
|
11
|
+
# Deprecation notice if legacy OVERWRITE_CONFIG is still set
|
|
12
|
+
if [ -n "${OVERWRITE_CONFIG+x}" ]; then
|
|
13
|
+
warn "OVERWRITE_CONFIG is deprecated. Use per-file 'overwrite' in config/file-manifest.json instead."
|
|
14
|
+
fi
|
|
15
|
+
|
|
16
|
+
# ── Legacy fallback ──────────────────────────────────────────────
|
|
17
|
+
legacy_copy() {
|
|
18
|
+
local target_dir="${CLAUDE_CONFIG_DIR:?CLAUDE_CONFIG_DIR not set}"
|
|
19
|
+
warn "file-manifest.json not found, falling back to legacy copy"
|
|
20
|
+
mkdir -p "$target_dir"
|
|
21
|
+
for file in defaults/settings.json defaults/keybindings.json defaults/main-system-prompt.md; do
|
|
22
|
+
if [ -f "$CONFIG_DIR/$file" ]; then
|
|
23
|
+
local basename="${file##*/}"
|
|
24
|
+
cp "$CONFIG_DIR/$file" "$target_dir/$basename"
|
|
25
|
+
chown "$(id -un):$(id -gn)" "$target_dir/$basename" 2>/dev/null || true
|
|
26
|
+
log "Copied $basename (legacy)"
|
|
22
27
|
fi
|
|
28
|
+
done
|
|
29
|
+
log "Configuration complete (legacy)"
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if [ ! -f "$MANIFEST" ]; then
|
|
33
|
+
legacy_copy
|
|
34
|
+
exit 0
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# ── Validate manifest JSON ──────────────────────────────────────
|
|
38
|
+
if ! jq empty "$MANIFEST" 2>/dev/null; then
|
|
39
|
+
err "Invalid JSON in file-manifest.json"
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
|
|
43
|
+
# ── Variable expansion ───────────────────────────────────────────
|
|
44
|
+
expand_vars() {
|
|
45
|
+
local val="$1"
|
|
46
|
+
val="${val//\$\{CLAUDE_CONFIG_DIR\}/$CLAUDE_CONFIG_DIR}"
|
|
47
|
+
val="${val//\$\{WORKSPACE_ROOT\}/$WORKSPACE_ROOT}"
|
|
48
|
+
# Warn on any remaining unresolved ${...} tokens
|
|
49
|
+
if [[ "$val" =~ \$\{[^}]+\} ]]; then
|
|
50
|
+
warn "Unresolved variable in: $val"
|
|
23
51
|
fi
|
|
52
|
+
echo "$val"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# ── Change detection ─────────────────────────────────────────────
|
|
56
|
+
should_copy() {
|
|
57
|
+
local src="$1" dest="$2"
|
|
58
|
+
[ ! -f "$dest" ] && return 0
|
|
59
|
+
local src_hash dest_hash
|
|
60
|
+
src_hash=$(sha256sum "$src" | cut -d' ' -f1)
|
|
61
|
+
dest_hash=$(sha256sum "$dest" | cut -d' ' -f1)
|
|
62
|
+
[ "$src_hash" != "$dest_hash" ]
|
|
24
63
|
}
|
|
25
64
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
65
|
+
# ── Process manifest ─────────────────────────────────────────────
|
|
66
|
+
log "Copying configuration files..."
|
|
67
|
+
|
|
68
|
+
# Single jq invocation to extract all fields (reduces N×5 subprocess calls to 1)
|
|
69
|
+
jq -r '.[] | [.src, .dest, (.destFilename // ""), (.enabled // true | tostring), (.overwrite // "if-changed")] | @tsv' "$MANIFEST" |
|
|
70
|
+
while IFS=$'\t' read -r src dest dest_filename enabled overwrite; do
|
|
71
|
+
# Skip disabled entries
|
|
72
|
+
if [ "$enabled" = "false" ]; then
|
|
73
|
+
log "Skipping $src (disabled)"
|
|
74
|
+
continue
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# Resolve paths
|
|
78
|
+
src_path="$CONFIG_DIR/$src"
|
|
79
|
+
dest_dir=$(expand_vars "$dest")
|
|
80
|
+
filename="${dest_filename:-${src##*/}}"
|
|
81
|
+
dest_path="$dest_dir/$filename"
|
|
82
|
+
|
|
83
|
+
# Validate source exists
|
|
84
|
+
if [ ! -f "$src_path" ]; then
|
|
85
|
+
warn "$src not found in config dir, skipping"
|
|
86
|
+
continue
|
|
87
|
+
fi
|
|
88
|
+
|
|
89
|
+
# Ensure destination directory exists
|
|
90
|
+
mkdir -p "$dest_dir"
|
|
91
|
+
|
|
92
|
+
# Apply overwrite strategy
|
|
93
|
+
case "$overwrite" in
|
|
94
|
+
always)
|
|
95
|
+
cp "$src_path" "$dest_path"
|
|
96
|
+
log "Copied $src → $dest_path (always)"
|
|
97
|
+
;;
|
|
98
|
+
never)
|
|
99
|
+
if [ ! -f "$dest_path" ]; then
|
|
100
|
+
cp "$src_path" "$dest_path"
|
|
101
|
+
log "Copied $src → $dest_path (new)"
|
|
102
|
+
else
|
|
103
|
+
log "Skipping $src (exists, overwrite=never)"
|
|
104
|
+
fi
|
|
105
|
+
;;
|
|
106
|
+
if-changed|*)
|
|
107
|
+
if should_copy "$src_path" "$dest_path"; then
|
|
108
|
+
cp "$src_path" "$dest_path"
|
|
109
|
+
log "Copied $src → $dest_path (changed)"
|
|
110
|
+
else
|
|
111
|
+
log "Skipping $src (unchanged)"
|
|
112
|
+
fi
|
|
113
|
+
;;
|
|
114
|
+
esac
|
|
115
|
+
|
|
116
|
+
# Fix ownership
|
|
117
|
+
chown "$(id -un):$(id -gn)" "$dest_path" 2>/dev/null || true
|
|
118
|
+
done
|
|
29
119
|
|
|
30
|
-
|
|
120
|
+
log "Configuration complete"
|
|
@@ -8,10 +8,18 @@ echo "[update-claude] Checking for Claude Code updates..."
|
|
|
8
8
|
# === TMPDIR ===
|
|
9
9
|
_TMPDIR="${TMPDIR:-/tmp}"
|
|
10
10
|
|
|
11
|
+
# === LOCK FILE (prevent concurrent updates) ===
|
|
12
|
+
LOCK_FILE="${_TMPDIR}/claude-update.lock"
|
|
13
|
+
if ! mkdir "$LOCK_FILE" 2>/dev/null; then
|
|
14
|
+
echo "[update-claude] Another update is already running, skipping"
|
|
15
|
+
exit 0
|
|
16
|
+
fi
|
|
17
|
+
|
|
11
18
|
# === CLEANUP TRAP ===
|
|
12
19
|
cleanup() {
|
|
13
20
|
rm -f "${_TMPDIR}/claude-update" 2>/dev/null || true
|
|
14
21
|
rm -f "${_TMPDIR}/claude-update-manifest.json" 2>/dev/null || true
|
|
22
|
+
rm -rf "$LOCK_FILE" 2>/dev/null || true
|
|
15
23
|
}
|
|
16
24
|
trap cleanup EXIT
|
|
17
25
|
|