codeforge-dev 1.7.0 → 1.9.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 +181 -0
- package/.devcontainer/CLAUDE.md +57 -20
- package/.devcontainer/README.md +111 -56
- package/.devcontainer/config/{main-system-prompt.md → defaults/main-system-prompt.md} +72 -0
- package/.devcontainer/config/defaults/rules/spec-workflow.md +67 -0
- package/.devcontainer/config/defaults/rules/workspace-scope.md +7 -0
- package/.devcontainer/config/defaults/settings.json +67 -0
- package/.devcontainer/config/file-manifest.json +32 -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 +104 -104
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/.claude-plugin/plugin.json +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/README.md +158 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/hooks/hooks.json +39 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/collect-edited-files.py +47 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/format-on-stop.py +297 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/lint-file.py +536 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/auto-code-quality/scripts/syntax-validator.py +146 -0
- 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 +94 -1
- 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 +20 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/dependency-analyst.md +20 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/doc-writer.md +99 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/explorer.md +20 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/generalist.md +152 -9
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/git-archaeologist.md +18 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/migrator.md +114 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/perf-profiler.md +24 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/refactorer.md +101 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/researcher.md +33 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/security-auditor.md +24 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/agents/spec-writer.md +65 -24
- 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 +99 -1
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/hooks/hooks.json +100 -56
- 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/spec-reminder.py +121 -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/spec-check/SKILL.md +86 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/SKILL.md +97 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/backlog-template.md +7 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-init/references/roadmap-template.md +13 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/SKILL.md +101 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-new/references/template.md +110 -0
- package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-update/SKILL.md +124 -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 +117 -24
- package/.devcontainer/scripts/setup-update-claude.sh +8 -0
- package/.devcontainer/scripts/setup.sh +46 -13
- package/README.md +23 -190
- package/package.json +42 -42
- package/setup.js +245 -71
- package/.devcontainer/config/settings.json +0 -70
- 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
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Specification Template
|
|
2
|
+
|
|
3
|
+
Standard template for all feature specifications. Copy this structure when creating a new spec.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Template
|
|
8
|
+
|
|
9
|
+
```markdown
|
|
10
|
+
# Feature: [Name]
|
|
11
|
+
|
|
12
|
+
**Version:** v0.X.0
|
|
13
|
+
**Status:** planned
|
|
14
|
+
**Last Updated:** YYYY-MM-DD
|
|
15
|
+
|
|
16
|
+
## Intent
|
|
17
|
+
|
|
18
|
+
[What problem does this solve? Who has this problem? What's the cost of not solving it? 2-3 sentences.]
|
|
19
|
+
|
|
20
|
+
## Acceptance Criteria
|
|
21
|
+
|
|
22
|
+
[Testable criteria. Use Given/When/Then for complex flows, checklists for simple features, or tables for business rules. Every criterion must be verifiable.]
|
|
23
|
+
|
|
24
|
+
- [ ] [Criterion 1]
|
|
25
|
+
- [ ] [Criterion 2]
|
|
26
|
+
- [ ] [Criterion 3]
|
|
27
|
+
|
|
28
|
+
## Key Files
|
|
29
|
+
|
|
30
|
+
[File paths most relevant to implementation — paths an implementer should read first.]
|
|
31
|
+
|
|
32
|
+
**Backend:**
|
|
33
|
+
- `src/path/to/file.py` — [brief description]
|
|
34
|
+
|
|
35
|
+
**Frontend:**
|
|
36
|
+
- `src/web/path/to/component.svelte` — [brief description]
|
|
37
|
+
|
|
38
|
+
**Tests:**
|
|
39
|
+
- `tests/path/to/test_file.py` — [brief description]
|
|
40
|
+
|
|
41
|
+
## Schema / Data Model
|
|
42
|
+
|
|
43
|
+
[Reference migration files and model files by path. Describe what changes — do NOT paste DDL, Pydantic models, or TypeScript interfaces.]
|
|
44
|
+
|
|
45
|
+
- New table: `table_name` — see `src/db/migrations/NNN.sql`
|
|
46
|
+
- Modified: `existing_table` — added `column_name` column
|
|
47
|
+
|
|
48
|
+
## API Endpoints
|
|
49
|
+
|
|
50
|
+
| Method | Path | Description |
|
|
51
|
+
|--------|------|-------------|
|
|
52
|
+
| GET | `/api/resource` | List resources with pagination |
|
|
53
|
+
| POST | `/api/resource` | Create a new resource |
|
|
54
|
+
|
|
55
|
+
## Requirements
|
|
56
|
+
|
|
57
|
+
### Functional Requirements
|
|
58
|
+
|
|
59
|
+
- FR-1: [EARS format requirement — see specification-writing skill for templates]
|
|
60
|
+
- FR-2: When [event], the system shall [action].
|
|
61
|
+
- FR-3: If [unwanted condition], then the system shall [action].
|
|
62
|
+
|
|
63
|
+
### Non-Functional Requirements
|
|
64
|
+
|
|
65
|
+
- NFR-1: The system shall respond to [endpoint] within [N]ms at the [percentile] percentile.
|
|
66
|
+
- NFR-2: [Security, accessibility, scalability requirement]
|
|
67
|
+
|
|
68
|
+
## Dependencies
|
|
69
|
+
|
|
70
|
+
- [External system, library, or feature this depends on]
|
|
71
|
+
- [Blocked by: feature X must ship first]
|
|
72
|
+
|
|
73
|
+
## Out of Scope
|
|
74
|
+
|
|
75
|
+
- [Explicit non-goal 1 — prevents scope creep]
|
|
76
|
+
- [Explicit non-goal 2]
|
|
77
|
+
|
|
78
|
+
## Implementation Notes
|
|
79
|
+
|
|
80
|
+
[Post-implementation only. Leave empty in planned specs. After building, document what actually shipped vs. what was planned.]
|
|
81
|
+
|
|
82
|
+
## Discrepancies
|
|
83
|
+
|
|
84
|
+
[Post-implementation only. Document gaps between spec intent and actual build. Prevents next session from re-planning decided work.]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Field Descriptions
|
|
90
|
+
|
|
91
|
+
| Section | Required | When to Fill |
|
|
92
|
+
|---------|----------|-------------|
|
|
93
|
+
| Intent | Always | At creation |
|
|
94
|
+
| Acceptance Criteria | Always | At creation |
|
|
95
|
+
| Key Files | Always | At creation (update post-implementation) |
|
|
96
|
+
| Schema / Data Model | If applicable | At creation |
|
|
97
|
+
| API Endpoints | If applicable | At creation |
|
|
98
|
+
| Requirements | Always | At creation |
|
|
99
|
+
| Dependencies | If applicable | At creation |
|
|
100
|
+
| Out of Scope | Always | At creation |
|
|
101
|
+
| Implementation Notes | Post-implementation | After building |
|
|
102
|
+
| Discrepancies | Post-implementation | After building |
|
|
103
|
+
|
|
104
|
+
## Status Values
|
|
105
|
+
|
|
106
|
+
| Status | Meaning |
|
|
107
|
+
|--------|---------|
|
|
108
|
+
| `planned` | Spec written, implementation not started |
|
|
109
|
+
| `partial` | Some acceptance criteria implemented, work ongoing |
|
|
110
|
+
| `implemented` | All acceptance criteria met, as-built notes complete |
|
package/.devcontainer/plugins/devs-marketplace/plugins/code-directive/skills/spec-update/SKILL.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spec-update
|
|
3
|
+
description: >-
|
|
4
|
+
This skill should be used when the user asks to "update the spec",
|
|
5
|
+
"mark spec as implemented", "as-built update", "spec maintenance",
|
|
6
|
+
"update spec status", "finish the spec", or after implementing a
|
|
7
|
+
feature when the spec needs to reflect what was actually built.
|
|
8
|
+
version: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# As-Built Spec Update
|
|
12
|
+
|
|
13
|
+
## Mental Model
|
|
14
|
+
|
|
15
|
+
Specs that say "planned" after code ships cause the next AI session to re-plan already-done work. The as-built update is the final step of every implementation — it closes the loop between what was planned and what was built.
|
|
16
|
+
|
|
17
|
+
This is not optional. Every implementation ends with a spec update.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## The 6-Step Workflow
|
|
22
|
+
|
|
23
|
+
### Step 1: Find the Spec
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Glob: .specs/**/*.md
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Search for the feature name in spec file names and content. If the user provides a spec path or feature name as `$ARGUMENTS`, use that directly.
|
|
30
|
+
|
|
31
|
+
If no spec exists:
|
|
32
|
+
- For substantial changes: create one using `/spec-new`
|
|
33
|
+
- For trivial changes (bug fixes, config): note "spec not needed" and stop
|
|
34
|
+
|
|
35
|
+
### Step 2: Set Status
|
|
36
|
+
|
|
37
|
+
Update the `**Status:**` field:
|
|
38
|
+
- `implemented` — all acceptance criteria are met
|
|
39
|
+
- `partial` — some criteria met, work ongoing or deferred
|
|
40
|
+
|
|
41
|
+
Never leave status as `planned` after implementation work has been done.
|
|
42
|
+
|
|
43
|
+
### Step 3: Check Off Acceptance Criteria
|
|
44
|
+
|
|
45
|
+
Review each acceptance criterion in the spec:
|
|
46
|
+
- Mark as `[x]` if the criterion is met and verified (tests pass, behavior confirmed)
|
|
47
|
+
- Leave as `[ ]` if not yet implemented
|
|
48
|
+
- Add a note next to deferred criteria explaining why
|
|
49
|
+
|
|
50
|
+
If criteria were met through different means than originally planned, note the deviation.
|
|
51
|
+
|
|
52
|
+
### Step 4: Add Implementation Notes
|
|
53
|
+
|
|
54
|
+
In the `## Implementation Notes` section, document:
|
|
55
|
+
- **Deviations from the original spec** — what changed and why
|
|
56
|
+
- **Key design decisions made during implementation** — choices that weren't in the spec
|
|
57
|
+
- **Surprising findings** — edge cases discovered, performance characteristics, limitations
|
|
58
|
+
- **Trade-offs accepted** — what was sacrificed and why
|
|
59
|
+
|
|
60
|
+
Keep notes concise. Reference file paths, not code.
|
|
61
|
+
|
|
62
|
+
### Step 5: Update File Paths
|
|
63
|
+
|
|
64
|
+
In the `## Key Files` section:
|
|
65
|
+
- Add files that were created during implementation
|
|
66
|
+
- Remove files that no longer exist
|
|
67
|
+
- Update paths that moved
|
|
68
|
+
|
|
69
|
+
Verify paths exist before listing them. Use absolute project-relative paths.
|
|
70
|
+
|
|
71
|
+
### Step 6: Update Metadata
|
|
72
|
+
|
|
73
|
+
- Set `**Last Updated:**` to today's date (YYYY-MM-DD)
|
|
74
|
+
- Verify `**Version:**` is correct
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Handling Edge Cases
|
|
79
|
+
|
|
80
|
+
### Spec Already "Implemented"
|
|
81
|
+
|
|
82
|
+
If the spec is already marked `implemented` and new changes affect the feature:
|
|
83
|
+
1. Check if acceptance criteria still hold
|
|
84
|
+
2. Update Implementation Notes with the new changes
|
|
85
|
+
3. Add any new Discrepancies between spec and current code
|
|
86
|
+
4. Update Last Updated date
|
|
87
|
+
|
|
88
|
+
### No Spec Exists
|
|
89
|
+
|
|
90
|
+
If there is no spec for the feature:
|
|
91
|
+
1. Ask: is this a substantial feature or a minor fix?
|
|
92
|
+
2. For substantial features: create one with `/spec-new`, then update it
|
|
93
|
+
3. For minor fixes: no spec needed — report this and stop
|
|
94
|
+
|
|
95
|
+
### Spec Has Unresolved Discrepancies
|
|
96
|
+
|
|
97
|
+
If the `## Discrepancies` section has open items:
|
|
98
|
+
1. Check if the current implementation resolves any of them
|
|
99
|
+
2. Remove resolved discrepancies
|
|
100
|
+
3. Add any new discrepancies discovered
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Validation Checklist
|
|
105
|
+
|
|
106
|
+
Before finishing the update:
|
|
107
|
+
- [ ] Status reflects the actual implementation state
|
|
108
|
+
- [ ] All implemented acceptance criteria are checked off
|
|
109
|
+
- [ ] Implementation Notes document deviations from original spec
|
|
110
|
+
- [ ] File paths in Key Files are accurate and verified
|
|
111
|
+
- [ ] Last Updated date is today
|
|
112
|
+
- [ ] Spec is still ≤200 lines
|
|
113
|
+
- [ ] No source code was pasted inline (references only)
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Ambiguity Policy
|
|
118
|
+
|
|
119
|
+
- If unclear which spec to update, list all candidates and ask the user.
|
|
120
|
+
- If the implementation deviated significantly from the spec, document it
|
|
121
|
+
honestly in Implementation Notes — do not retroactively change the original
|
|
122
|
+
requirements to match what was built.
|
|
123
|
+
- If acceptance criteria are ambiguous about whether they're met, note the
|
|
124
|
+
ambiguity in Discrepancies rather than checking them off optimistically.
|
|
@@ -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,123 @@
|
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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)"
|
|
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"
|
|
51
|
+
fi
|
|
52
|
+
echo "$val"
|
|
24
53
|
}
|
|
25
54
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
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" ]
|
|
63
|
+
}
|
|
64
|
+
|
|
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
|
+
# Note: empty destFilename uses "__NONE__" sentinel because bash read collapses
|
|
70
|
+
# consecutive tab delimiters, which shifts fields when destFilename is empty.
|
|
71
|
+
jq -r '.[] | [.src, .dest, (.destFilename // "__NONE__"), (.enabled // true | tostring), (.overwrite // "if-changed")] | @tsv' "$MANIFEST" |
|
|
72
|
+
while IFS=$'\t' read -r src dest dest_filename enabled overwrite; do
|
|
73
|
+
# Skip disabled entries
|
|
74
|
+
if [ "$enabled" = "false" ]; then
|
|
75
|
+
log "Skipping $src (disabled)"
|
|
76
|
+
continue
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Resolve paths
|
|
80
|
+
src_path="$CONFIG_DIR/$src"
|
|
81
|
+
dest_dir=$(expand_vars "$dest")
|
|
82
|
+
[ "$dest_filename" = "__NONE__" ] && dest_filename=""
|
|
83
|
+
filename="${dest_filename:-${src##*/}}"
|
|
84
|
+
dest_path="$dest_dir/$filename"
|
|
85
|
+
|
|
86
|
+
# Validate source exists
|
|
87
|
+
if [ ! -f "$src_path" ]; then
|
|
88
|
+
warn "$src not found in config dir, skipping"
|
|
89
|
+
continue
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Ensure destination directory exists
|
|
93
|
+
mkdir -p "$dest_dir"
|
|
94
|
+
|
|
95
|
+
# Apply overwrite strategy
|
|
96
|
+
case "$overwrite" in
|
|
97
|
+
always)
|
|
98
|
+
cp "$src_path" "$dest_path"
|
|
99
|
+
log "Copied $src → $dest_path (always)"
|
|
100
|
+
;;
|
|
101
|
+
never)
|
|
102
|
+
if [ ! -f "$dest_path" ]; then
|
|
103
|
+
cp "$src_path" "$dest_path"
|
|
104
|
+
log "Copied $src → $dest_path (new)"
|
|
105
|
+
else
|
|
106
|
+
log "Skipping $src (exists, overwrite=never)"
|
|
107
|
+
fi
|
|
108
|
+
;;
|
|
109
|
+
if-changed | *)
|
|
110
|
+
if should_copy "$src_path" "$dest_path"; then
|
|
111
|
+
cp "$src_path" "$dest_path"
|
|
112
|
+
log "Copied $src → $dest_path (changed)"
|
|
113
|
+
else
|
|
114
|
+
log "Skipping $src (unchanged)"
|
|
115
|
+
fi
|
|
116
|
+
;;
|
|
117
|
+
esac
|
|
118
|
+
|
|
119
|
+
# Fix ownership
|
|
120
|
+
chown "$(id -un):$(id -gn)" "$dest_path" 2>/dev/null || true
|
|
121
|
+
done
|
|
29
122
|
|
|
30
|
-
|
|
123
|
+
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
|
|