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.
Files changed (136) hide show
  1. package/.devcontainer/.env +4 -6
  2. package/.devcontainer/.env.example +29 -0
  3. package/.devcontainer/.gitignore +8 -0
  4. package/.devcontainer/.secrets.example +12 -0
  5. package/.devcontainer/CHANGELOG.md +130 -0
  6. package/.devcontainer/CLAUDE.md +56 -19
  7. package/.devcontainer/README.md +111 -56
  8. package/.devcontainer/config/{main-system-prompt.md → defaults/main-system-prompt.md} +72 -0
  9. package/.devcontainer/config/file-manifest.json +20 -0
  10. package/.devcontainer/devcontainer.json +20 -0
  11. package/.devcontainer/docs/configuration-reference.md +90 -0
  12. package/.devcontainer/docs/keybindings.md +100 -0
  13. package/.devcontainer/docs/optional-features.md +129 -0
  14. package/.devcontainer/docs/plugins.md +154 -0
  15. package/.devcontainer/docs/troubleshooting.md +128 -0
  16. package/.devcontainer/features/agent-browser/install.sh +6 -0
  17. package/.devcontainer/features/ast-grep/install.sh +6 -0
  18. package/.devcontainer/features/biome/README.md +27 -0
  19. package/.devcontainer/features/biome/install.sh +6 -0
  20. package/.devcontainer/features/ccburn/install.sh +6 -0
  21. package/.devcontainer/features/ccstatusline/devcontainer-feature.json +5 -0
  22. package/.devcontainer/features/ccstatusline/install.sh +7 -0
  23. package/.devcontainer/features/ccusage/install.sh +6 -0
  24. package/.devcontainer/features/claude-monitor/install.sh +6 -0
  25. package/.devcontainer/features/dprint/README.md +30 -0
  26. package/.devcontainer/features/dprint/devcontainer-feature.json +18 -0
  27. package/.devcontainer/features/dprint/install.sh +131 -0
  28. package/.devcontainer/features/hadolint/README.md +35 -0
  29. package/.devcontainer/features/hadolint/devcontainer-feature.json +13 -0
  30. package/.devcontainer/features/hadolint/install.sh +86 -0
  31. package/.devcontainer/features/lsp-servers/devcontainer-feature.json +5 -0
  32. package/.devcontainer/features/lsp-servers/install.sh +7 -0
  33. package/.devcontainer/features/mcp-qdrant/devcontainer-feature.json +5 -0
  34. package/.devcontainer/features/mcp-qdrant/install.sh +13 -6
  35. package/.devcontainer/features/mcp-reasoner/devcontainer-feature.json +5 -0
  36. package/.devcontainer/features/mcp-reasoner/install.sh +8 -1
  37. package/.devcontainer/features/notify-hook/devcontainer-feature.json +5 -0
  38. package/.devcontainer/features/notify-hook/install.sh +7 -0
  39. package/.devcontainer/features/ruff/README.md +26 -0
  40. package/.devcontainer/features/ruff/devcontainer-feature.json +21 -0
  41. package/.devcontainer/features/ruff/install.sh +74 -0
  42. package/.devcontainer/features/shellcheck/README.md +38 -0
  43. package/.devcontainer/features/shellcheck/devcontainer-feature.json +13 -0
  44. package/.devcontainer/features/shellcheck/install.sh +24 -0
  45. package/.devcontainer/features/shfmt/README.md +37 -0
  46. package/.devcontainer/features/shfmt/devcontainer-feature.json +13 -0
  47. package/.devcontainer/features/shfmt/install.sh +85 -0
  48. package/.devcontainer/features/splitrail/devcontainer-feature.json +5 -0
  49. package/.devcontainer/features/splitrail/install.sh +7 -0
  50. package/.devcontainer/features/tmux/install.sh +8 -0
  51. package/.devcontainer/features/tree-sitter/install.sh +6 -0
  52. package/.devcontainer/plugins/devs-marketplace/.claude-plugin/marketplace.json +3 -10
  53. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/.claude-plugin/plugin.json +1 -1
  54. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/__pycache__/format-on-stop.cpython-314.pyc +0 -0
  55. package/.devcontainer/plugins/devs-marketplace/plugins/auto-formatter/scripts/format-on-stop.py +114 -9
  56. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/.claude-plugin/plugin.json +1 -1
  57. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/hooks/hooks.json +4 -5
  58. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/__pycache__/lint-file.cpython-314.pyc +0 -0
  59. package/.devcontainer/plugins/devs-marketplace/plugins/auto-linter/scripts/lint-file.py +478 -76
  60. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/.claude-plugin/plugin.json +1 -1
  61. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/AGENT-REDIRECTION.md +226 -0
  62. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/architect.md +17 -0
  63. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/bash-exec.md +4 -4
  64. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/claude-guide.md +14 -23
  65. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/debug-logs.md +2 -0
  66. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/dependency-analyst.md +2 -0
  67. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +13 -0
  68. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/explorer.md +2 -0
  69. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/generalist.md +10 -1
  70. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/migrator.md +6 -0
  71. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/refactorer.md +4 -0
  72. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +36 -23
  73. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/statusline-config.md +3 -3
  74. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/test-writer.md +3 -0
  75. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +39 -0
  76. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/advisory-test-runner.cpython-314.pyc +0 -0
  77. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/collect-edited-files.cpython-314.pyc +0 -0
  78. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/commit-reminder.cpython-314.pyc +0 -0
  79. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/git-state-injector.cpython-314.pyc +0 -0
  80. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/redirect-builtin-agents.cpython-314.pyc +0 -0
  81. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/ticket-linker.cpython-314.pyc +0 -0
  82. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/__pycache__/todo-harvester.cpython-314.pyc +0 -0
  83. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/advisory-test-runner.py +174 -0
  84. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/collect-edited-files.py +8 -6
  85. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/commit-reminder.py +90 -0
  86. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/git-state-injector.py +114 -0
  87. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/skill-suggester.py +61 -0
  88. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/ticket-linker.py +137 -0
  89. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/scripts/todo-harvester.py +130 -0
  90. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/SKILL.md +224 -0
  91. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/error-handling.md +166 -0
  92. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/api-design/references/rest-conventions.md +215 -0
  93. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/SKILL.md +211 -0
  94. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/ast-grep-patterns/references/language-patterns.md +327 -0
  95. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/SKILL.md +134 -0
  96. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/ecosystem-commands.md +264 -0
  97. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/dependency-management/references/license-compliance.md +80 -0
  98. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/SKILL.md +153 -0
  99. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/api-doc-templates.md +221 -0
  100. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/documentation-patterns/references/docstring-formats.md +296 -0
  101. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/SKILL.md +150 -0
  102. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/javascript-migrations.md +179 -0
  103. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/migration-patterns/references/python-migrations.md +141 -0
  104. package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/specification-writing/SKILL.md +32 -0
  105. package/.devcontainer/plugins/devs-marketplace/plugins/dangerous-command-blocker/scripts/__pycache__/block-dangerous.cpython-314.pyc +0 -0
  106. package/.devcontainer/plugins/devs-marketplace/plugins/notify-hook/hooks/hooks.json +1 -1
  107. package/.devcontainer/plugins/devs-marketplace/plugins/protected-files-guard/scripts/__pycache__/guard-protected.cpython-314.pyc +0 -0
  108. package/.devcontainer/scripts/check-setup.sh +72 -0
  109. package/.devcontainer/scripts/setup-aliases.sh +43 -3
  110. package/.devcontainer/scripts/setup-auth.sh +74 -0
  111. package/.devcontainer/scripts/setup-config.sh +112 -22
  112. package/.devcontainer/scripts/setup-update-claude.sh +8 -0
  113. package/.devcontainer/scripts/setup.sh +46 -13
  114. package/README.md +23 -190
  115. package/package.json +1 -1
  116. package/setup.js +245 -71
  117. package/.devcontainer/features/claude-code/README.md +0 -498
  118. package/.devcontainer/features/claude-code/config/settings.json +0 -72
  119. package/.devcontainer/features/claude-code/config/system-prompt.md +0 -118
  120. package/.devcontainer/features/claude-code/config/world-building-sp.md +0 -1432
  121. package/.devcontainer/features/claude-code/devcontainer-feature.json +0 -42
  122. package/.devcontainer/features/claude-code/install.sh +0 -466
  123. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/.claude-plugin/plugin.json +0 -7
  124. package/.devcontainer/plugins/devs-marketplace/plugins/planning-reminder/hooks/hooks.json +0 -17
  125. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/.claude-plugin/plugin.json +0 -6
  126. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/config/planning-instructions.md +0 -14
  127. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/functional-conjuring-map.md +0 -989
  128. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/hooks/hooks.json +0 -33
  129. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/__pycache__/post-enhance-task.cpython-314.pyc +0 -0
  130. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhance-planning.py +0 -71
  131. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-plan.sh +0 -68
  132. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/enhancers/enhance-task.sh +0 -120
  133. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-plan.py +0 -133
  134. package/.devcontainer/plugins/devs-marketplace/plugins/workflow-enhancer/scripts/post-enhance-task.py +0 -253
  135. /package/.devcontainer/config/{keybindings.json → defaults/keybindings.json} +0 -0
  136. /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
@@ -7,7 +7,7 @@
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "/usr/local/bin/claude-notify",
10
+ "command": "claude-notify",
11
11
  "timeout": 5
12
12
  }
13
13
  ]
@@ -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 -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
76
- echo " claude -> claude with \$CLAUDE_CONFIG_DIR/system-prompt.md"
77
- echo " ccraw -> vanilla claude without any config"
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 Claude configuration files to workspace
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
- TARGET_DIR="${CLAUDE_CONFIG_DIR:?CLAUDE_CONFIG_DIR not set}"
6
- OVERWRITE="${OVERWRITE_CONFIG:-false}"
7
-
8
- echo "[setup-config] Copying configuration files..."
9
- [ "$OVERWRITE" = "true" ] && echo "[setup-config] Overwrite mode enabled"
10
-
11
- mkdir -p "$TARGET_DIR"
12
-
13
- copy_file() {
14
- local file="$1"
15
- if [ -f "$CONFIG_DIR/$file" ]; then
16
- if [ "$OVERWRITE" = "true" ] || [ ! -f "$TARGET_DIR/$file" ]; then
17
- cp "$CONFIG_DIR/$file" "$TARGET_DIR/$file"
18
- chown "$(id -un):$(id -gn)" "$TARGET_DIR/$file" 2>/dev/null || true
19
- echo "[setup-config] Copied $file"
20
- else
21
- echo "[setup-config] $file already exists, skipping"
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
- copy_file "settings.json"
27
- copy_file "keybindings.json"
28
- copy_file "main-system-prompt.md"
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
- echo "[setup-config] Configuration complete"
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