@khanhspring/forge-module 1.2.0 → 1.3.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanhspring/forge-module",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Forge module repo skills for Claude Code — implement, contract-test, done, and more",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
  name: "forge-done"
3
3
  description: "Confirms all tasks for this module are complete and generates the module repo commit message. Module repo only — run /forge-close in the spec repo afterward to mark tasks done there."
4
4
  argument-hint: "Feature slug (e.g. 'user-registration')"
5
- compatibility: "Requires module repo with .forge/module.json and an initialized specs/ git submodule"
5
+ compatibility: "Requires module repo with .forge/module.json and an initialized specs/ link (git submodule or junction)"
6
6
  metadata:
7
7
  author: "forge-workflow"
8
8
  source: "module-skills/forge-done/SKILL.md"
@@ -28,7 +28,7 @@ is handled separately by `/forge-close` in the spec repo.
28
28
 
29
29
  ---
30
30
 
31
- ## Step 1 — Read task list (read-only from submodule)
31
+ ## Step 1 — Read task list (read-only from specs/)
32
32
 
33
33
  Read `{spec_submodule_path}/features/{slug}/tasks.md`.
34
34
 
@@ -40,8 +40,8 @@ If `tasks.md` is missing:
40
40
  > "No tasks file found at `specs/features/{slug}/tasks.md`.
41
41
  > Run `/forge-tasks {slug}` in the spec repo first."
42
42
 
43
- Note: the submodule is read-only — task checkboxes cannot be updated from here.
44
- That is handled by `/forge-close` in the spec repo.
43
+ Note: `specs/` is read-only from here regardless of link type — task checkboxes cannot be
44
+ updated from this repo. That is handled by `/forge-close` in the spec repo.
45
45
 
46
46
  ---
47
47
 
@@ -2,7 +2,7 @@
2
2
  name: "forge-implement"
3
3
  description: "Researches existing codebase patterns, clears ambiguities one at a time, challenges implementation concerns, then guides task-by-task implementation scoped to this module. No code written until plan is confirmed."
4
4
  argument-hint: "Feature slug (e.g. 'user-registration')"
5
- compatibility: "Requires module repo with .forge/module.json and an initialized specs/ git submodule"
5
+ compatibility: "Requires module repo with .forge/module.json and an initialized specs/ link (git submodule or junction)"
6
6
  metadata:
7
7
  author: "forge-workflow"
8
8
  source: "module-skills/forge-implement/SKILL.md"
@@ -25,7 +25,7 @@ presented the Implementation Plan and the user has explicitly confirmed it.
25
25
  ## Pre-check
26
26
 
27
27
  - Read `.forge/module.json` — if missing, say "Run `/forge-init` to set up this module repo first."
28
- - Get `spec_submodule_path` from module.json.
28
+ - Get `spec_submodule_path` and `spec_link_type` from module.json.
29
29
  - **Determine working scope:**
30
30
  - `module.json` has no `submodules` → scope = the module itself; use top-level `test_base_url` and `contract_glob`.
31
31
  - `module.json` has `submodules[]` → ask "Which submodule are you implementing? ({list submodule names})"
@@ -34,8 +34,9 @@ presented the Implementation Plan and the user has explicitly confirmed it.
34
34
  - If empty, scan `{spec_submodule_path}/features/*/tasks.md` for `### {scope-name}` headings
35
35
  (module name for simple modules, submodule name for submodules), list features with pending
36
36
  tasks, ask which to implement.
37
- - Check `git submodule status` — if specs/ is out of date, say:
37
+ - If `spec_link_type` is `"submodule"` (or unset), check `git submodule status` — if specs/ is out of date, say:
38
38
  > "Your specs submodule may be out of date. Run `git submodule update --remote specs` first, or continue with the current version?"
39
+ - If `spec_link_type` is `"junction"`, skip this check — a junction/symlink always reflects the live spec folder.
39
40
 
40
41
  ---
41
42
 
@@ -34,7 +34,9 @@ Before asking anything, silently scan the repo and note:
34
34
 
35
35
  1. **Stack detection** — does `pom.xml`, `build.gradle`, `package.json`, `go.mod`, `requirements.txt`, or similar exist? What versions are declared?
36
36
  2. **Port detection** — is a port configured in `application.yml`, `application.properties`, `.env`, `.env.example`, or `docker-compose.yml`?
37
- 3. **Specs submodule** — does `specs/` already exist as a directory or submodule?
37
+ 3. **Specs link** — does `specs/` already exist? If so, determine how: a git submodule
38
+ (check `.gitmodules` / `git submodule status`) or a junction/symlink (check if it's a
39
+ reparse point / symlink, e.g. `git submodule status` reports nothing but the dir exists).
38
40
  4. **CI** — does `.github/workflows/` already exist? Any contract test workflow present?
39
41
  5. **Existing CLAUDE.md** — already has project context written?
40
42
  6. **Monorepo signals** — does `nx.json`, `turbo.json`, `lerna.json`, `pnpm-workspace.yaml`, or
@@ -47,7 +49,7 @@ Report findings before asking anything:
47
49
  > "Here's what I found in this repo:
48
50
  > - Stack: {detected stack — or 'not detected'}
49
51
  > - Port: {detected port — or 'not found in config'}
50
- > - specs/ submodule: {exists / not present}
52
+ > - specs/: {not present / exists — git submodule / exists junction or symlink}
51
53
  > - GitHub Actions: {exists / not present}
52
54
  > {if monorepo signals}: - Looks like a monorepo — detected sub-apps: {list of dir names}
53
55
  >
@@ -99,14 +101,30 @@ Do not suggest a default — module names must be exact matches. Warn clearly:
99
101
  **Q2 — Module description**
100
102
  > "What does this module do? (one sentence)"
101
103
 
102
- **Q3 — Spec repo URL**
103
-
104
- If `specs/` already exists:
105
- > "I see a `specs/` directory already — is that the spec repo submodule? (yes/no)
106
- > If yes, what's the remote URL? (run `git remote -v` in `specs/` if unsure)"
107
-
108
- If not:
109
- > "What's the spec repo URL? (it will be added as a git submodule at `specs/`)"
104
+ **Q3 — Spec repo link**
105
+
106
+ If `specs/` already exists, confirm what was detected in Step 1 instead of asking from scratch:
107
+ - Detected as a git submodule → "I see `specs/` is already a git submodule — is that the spec
108
+ repo? (yes/no). If yes, what's the remote URL? (run `git remote -v` in `specs/` if unsure)"
109
+ - Detected as a junction/symlink → "I see `specs/` is already a local junction/symlink — what
110
+ local path does it point at? (confirm or correct)"
111
+ - Set `spec_link_type` accordingly and skip straight to Q4.
112
+
113
+ If `specs/` does not exist, ask how to link it:
114
+ > "How should this repo link to the spec repo?
115
+ > 1. **Git submodule** (default) — versioned and works across machines/CI, but needs
116
+ > `git submodule update --remote specs` to sync after spec repo changes.
117
+ > 2. **Junction / local link** — for when the spec repo and this module repo live on the same
118
+ > machine (solo/local dev). `specs/` always reflects the live folder, no sync command needed —
119
+ > but it won't survive being cloned elsewhere or used in CI, and skips version pinning."
120
+
121
+ - **If git submodule (or no answer / "default")**:
122
+ > "What's the spec repo URL? (it will be added as a git submodule at `specs/`)"
123
+ Set `spec_link_type: "submodule"`.
124
+ - **If junction/local link**:
125
+ > "What's the local path to the spec repo folder? (absolute path, e.g. `D:\Workspace\my-specs`
126
+ > or `/home/me/my-specs`)"
127
+ Set `spec_link_type: "junction"` and `spec_source_path` to the given absolute path.
110
128
 
111
129
  **Q4 — Port** _(skip entirely if Step 2-B was run — port belongs to each submodule, not the module)_
112
130
 
@@ -157,13 +175,19 @@ Show a full preview of everything that will be created or run:
157
175
  ```
158
176
  Ready to initialize. Here's what I'll do:
159
177
 
160
- {if specs/ not present}
178
+ {if specs/ not present, spec_link_type = submodule}
161
179
  git submodule add {spec-repo-url} specs
162
180
  git submodule update --init --recursive
163
181
 
182
+ {if specs/ not present, spec_link_type = junction}
183
+ {Windows} mklink /J specs "{spec-source-path}"
184
+ {macOS/Linux} ln -s "{spec-source-path}" specs
185
+ append `specs/` to .gitignore (junction contents aren't tracked by this repo)
186
+
164
187
  .forge/module.json
165
188
  {if single app}
166
189
  module: {module-name}
190
+ spec_link_type: {submodule | junction}
167
191
  test_base_url: http://localhost:{port}
168
192
  contract_glob: specs/contracts/{module-name}/*.yaml
169
193
  {if submodules}
@@ -192,12 +216,24 @@ Wait for confirmation. Do not write files or run git commands before the user sa
192
216
 
193
217
  ## Step 4 — Write files
194
218
 
195
- Run (if specs/ not already present):
219
+ Run (if specs/ not already present), based on the chosen `spec_link_type`:
220
+
221
+ **`submodule`:**
196
222
  ```bash
197
223
  git submodule add {spec-repo-url} specs
198
224
  git submodule update --init --recursive
199
225
  ```
200
226
 
227
+ **`junction`:**
228
+ ```bash
229
+ # Windows
230
+ mklink /J specs "{spec-source-path}"
231
+ # macOS/Linux
232
+ ln -s "{spec-source-path}" specs
233
+ ```
234
+ Then append `specs/` to `.gitignore` — a junction/symlink's contents belong to the spec repo,
235
+ not this one, and must not be tracked or committed here.
236
+
201
237
  Write `.forge/module.json`:
202
238
 
203
239
  **For a single-app module** (no sub-apps):
@@ -205,11 +241,14 @@ Write `.forge/module.json`:
205
241
  {
206
242
  "module": "{module-name}",
207
243
  "spec_submodule_path": "specs",
244
+ "spec_link_type": "submodule",
208
245
  "specmatic_version": "2.x",
209
246
  "test_base_url": "http://localhost:{port}",
210
247
  "contract_glob": "specs/contracts/{module-name}/*.yaml"
211
248
  }
212
249
  ```
250
+ `spec_link_type` is `"submodule"` (default) or `"junction"`. When `"junction"`, also write
251
+ `"spec_source_path": "{absolute-local-path}"` so the link can be recreated if it's ever lost.
213
252
 
214
253
  **Module with submodules** — no top-level `port` or `test_base_url`; each submodule owns those.
215
254
  Submodules have no `repo` field — they are in the same repo as the parent module:
@@ -217,6 +256,7 @@ Submodules have no `repo` field — they are in the same repo as the parent modu
217
256
  {
218
257
  "module": "{module-name}",
219
258
  "spec_submodule_path": "specs",
259
+ "spec_link_type": "submodule",
220
260
  "specmatic_version": "2.x",
221
261
  "submodules": [
222
262
  {
@@ -253,9 +293,15 @@ _(Single app: show Stack + Port inline. Monorepo: replace with a table.)_
253
293
  5. (then in the spec repo) `/forge-close {slug} {module}` — mark tasks done there
254
294
 
255
295
  ## Spec repo
256
- Linked via git submodule at `specs/`.
296
+ _(submodule)_ Linked via git submodule at `specs/`.
257
297
  Run `git submodule update --remote specs` before starting a new feature,
258
298
  and again after `/forge-close` is run in the spec repo to sync task status.
299
+
300
+ _(junction)_ Linked via local junction/symlink at `specs/` → `{spec-source-path}`.
301
+ Always reflects the live spec repo folder — no sync command needed. This only works while
302
+ both repos are on the same machine; switch to a git submodule (`/forge-init` again, or
303
+ re-run link setup) before cloning this repo elsewhere or using it in CI.
304
+
259
305
  Project-wide domain context (actors, glossary, principles) lives at `specs/CONTEXT.md`
260
306
  — read it before implementing.
261
307
 
@@ -2,7 +2,7 @@
2
2
  name: "forge-tasks"
3
3
  description: "Lists all tasks assigned to this module across every feature, with completion status, by scanning the spec submodule. Module repo task dashboard."
4
4
  argument-hint: ""
5
- compatibility: "Requires module repo with .forge/module.json and an initialized specs/ git submodule"
5
+ compatibility: "Requires module repo with .forge/module.json and an initialized specs/ link (git submodule or junction)"
6
6
  metadata:
7
7
  author: "forge-workflow"
8
8
  source: "module-skills/forge-tasks/SKILL.md"
@@ -15,10 +15,15 @@ disable-model-invocation: true
15
15
  Show all tasks assigned to this module across all features.
16
16
 
17
17
  ## Pre-check
18
- - Read `.forge/module.json` for `module` and `spec_submodule_path`.
18
+ - Read `.forge/module.json` for `module`, `spec_submodule_path`, and `spec_link_type`.
19
19
  If missing: "Run `/forge-init` to set up this module repo first."
20
- - If `specs/` is not initialized: suggest `git submodule update --init --recursive`
21
- - Optionally suggest `git submodule update --remote specs` to get the latest task status.
20
+ - If `spec_link_type` is `"submodule"` (or unset, for repos initialized before this field existed):
21
+ - If `specs/` is not initialized: suggest `git submodule update --init --recursive`
22
+ - Optionally suggest `git submodule update --remote specs` to get the latest task status.
23
+ - If `spec_link_type` is `"junction"`:
24
+ - If `specs/` is missing or broken, suggest recreating the link at `spec_source_path`
25
+ (Windows: `mklink /J specs "{spec_source_path}"`; macOS/Linux: `ln -s "{spec_source_path}" specs`).
26
+ - No sync command needed — a junction/symlink always reflects the live folder.
22
27
 
23
28
  ## Steps
24
29
 
@@ -65,7 +70,8 @@ Feature: user-registration [Open]
65
70
  ```
66
71
 
67
72
  If no tasks reference this module across any feature:
68
- > "No tasks found for `{module}`. Either no feature targets this module yet, or the specs
69
- > submodule is out of date — try `git submodule update --remote specs`."
73
+ > "No tasks found for `{module}`. Either no feature targets this module yet, {if submodule}
74
+ > or the specs submodule is out of date — try `git submodule update --remote specs`.
75
+ > {if junction} or the linked spec folder doesn't have it yet."
70
76
 
71
77
  After showing: "Tell me which feature to implement, or run `/forge-implement {slug}`."