specweave 1.0.557 → 1.0.558

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": "specweave",
3
- "version": "1.0.557",
3
+ "version": "1.0.558",
4
4
  "description": "100+ domain-expert AI skills — PM, Architect, Frontend, QA, Security and more. Skills learn your team's patterns permanently. Spec-first planning, autonomous execution, multi-agent teams, synced to GitHub/JIRA. Claude Code, Cursor, Copilot & more.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,406 @@
1
+ ---
2
+ version: 1.0.0
3
+ description: >
4
+ Create and manage umbrella workspaces for multi-repo projects.
5
+ Activate when the user wants to: create umbrella, umbrella init, wrap in umbrella,
6
+ create workspace, setup multi-repo, migrate repos to umbrella, umbrella create,
7
+ new workspace, restructure into umbrella, "wrap this repo", "create umbrella for these repos",
8
+ "setup workspace with repos", "move repos into umbrella".
9
+ Do NOT activate for: add a repo to existing umbrella (use sw:get), add a feature,
10
+ add an increment, clone a repo (use sw:get).
11
+ triggers:
12
+ - "create umbrella"
13
+ - "umbrella init"
14
+ - "wrap in umbrella"
15
+ - "create workspace"
16
+ - "setup multi-repo"
17
+ - "migrate repos"
18
+ - "new workspace"
19
+ - "restructure into umbrella"
20
+ - "wrap this repo"
21
+ negative_triggers:
22
+ - "add a repo"
23
+ - "clone a repo"
24
+ - "add a feature"
25
+ - "create increment"
26
+ ---
27
+
28
+ # sw:umbrella — Create & Manage Umbrella Workspaces
29
+
30
+ Automates the creation of SpecWeave umbrella workspaces for multi-repo projects. Handles directory structure, repo cloning/migration, symlinks, `.env` consolidation, and SpecWeave initialization in a single flow.
31
+
32
+ ## Modes
33
+
34
+ | Mode | Use Case |
35
+ |------|----------|
36
+ | **init** | Create a new umbrella from scratch with remote and/or local repos |
37
+ | **wrap** | Wrap an existing local repo (or set of repos) into a new umbrella |
38
+
39
+ Detect mode from context:
40
+ - User provides repo URLs or org/repo references → **init**
41
+ - User is in a repo and says "wrap" or "restructure" → **wrap**
42
+ - Ambiguous → ask which mode
43
+
44
+ ---
45
+
46
+ ## Mode: init
47
+
48
+ Create a new umbrella workspace from scratch.
49
+
50
+ ### Step 1: Gather inputs
51
+
52
+ Extract from the user's message or ask:
53
+
54
+ | Input | Required | Default |
55
+ |-------|----------|---------|
56
+ | Umbrella name | Yes | — |
57
+ | Target directory | No | `~/Projects/{name}` |
58
+ | Repos to include | Yes | — |
59
+
60
+ **Repo source formats** (same as `sw:get`):
61
+ - GitHub shorthand: `owner/repo`
62
+ - Full URL: `https://github.com/org/repo`
63
+ - SSH: `git@github.com:org/repo`
64
+ - Local path: `~/Projects/my-repo` or `./my-repo`
65
+ - Mixed: any combination of the above
66
+
67
+ For local paths, also ask:
68
+ - Custom local name? (e.g., clone `owner/repo-long-name` as `repo`)
69
+
70
+ ### Step 2: Create umbrella root
71
+
72
+ ```bash
73
+ TARGET="${HOME}/Projects/${NAME}"
74
+ mkdir -p "${TARGET}"
75
+ cd "${TARGET}"
76
+ ```
77
+
78
+ **Guard**: If directory already exists and contains `.specweave/`, warn and ask whether to add repos to existing umbrella (delegates to `sw:get`) or abort.
79
+
80
+ ### Step 3: Initialize SpecWeave
81
+
82
+ ```bash
83
+ specweave init "${NAME}"
84
+ ```
85
+
86
+ This creates `.specweave/`, `config.json`, `CLAUDE.md`, `AGENTS.md`.
87
+
88
+ **Guard**: If `.specweave/config.json` already exists, skip this step.
89
+
90
+ ### Step 4: Add repos
91
+
92
+ **For each remote repo:**
93
+
94
+ ```bash
95
+ specweave get <source> [--prefix PREFIX]
96
+ ```
97
+
98
+ `specweave get` handles: clone into `repositories/{org}/{repo}/`, register in config.json, run `specweave init` in the repo.
99
+
100
+ **For each local repo:**
101
+
102
+ Local repos need special handling — `specweave get` expects a URL, not a local move.
103
+
104
+ ```bash
105
+ # 1. Detect org/repo from git remote
106
+ REMOTE_URL=$(git -C "${LOCAL_PATH}" remote get-url origin 2>/dev/null)
107
+ # Parse org and repo name from URL (handle HTTPS, SSH, GitHub shorthand)
108
+ # Example: git@github.com:antonoly/claude-code-anymodel.git → org=antonoly, repo=claude-code-anymodel
109
+
110
+ # 2. Allow custom local name (user may want 'claude-code' instead of 'claude-code-anymodel')
111
+ REPO_DIR="${CUSTOM_NAME:-${REPO_NAME}}"
112
+
113
+ # 3. Create target directory
114
+ mkdir -p "${TARGET}/repositories/${ORG}"
115
+
116
+ # 4. Move repo (REQUIRES USER CONFIRMATION — destructive operation)
117
+ mv "${LOCAL_PATH}" "${TARGET}/repositories/${ORG}/${REPO_DIR}"
118
+
119
+ # 5. Create symlink at original location for session compatibility
120
+ ln -s "${TARGET}/repositories/${ORG}/${REPO_DIR}" "${LOCAL_PATH}"
121
+
122
+ # 6. Register in config.json
123
+ # Read current config, add to umbrella.childRepos array
124
+ ```
125
+
126
+ **Registration** — after moving a local repo, add it to `.specweave/config.json`:
127
+
128
+ ```json
129
+ {
130
+ "umbrella": {
131
+ "childRepos": [
132
+ {
133
+ "id": "{repo-dir}",
134
+ "path": "repositories/{org}/{repo-dir}",
135
+ "name": "{repo-dir}",
136
+ "prefix": "{FIRST_3_UPPERCASE}",
137
+ "githubUrl": "{remote-url}"
138
+ }
139
+ ]
140
+ }
141
+ }
142
+ ```
143
+
144
+ Use `jq` to merge into existing config:
145
+
146
+ ```bash
147
+ jq --arg id "${REPO_DIR}" \
148
+ --arg path "repositories/${ORG}/${REPO_DIR}" \
149
+ --arg name "${REPO_DIR}" \
150
+ --arg prefix "${PREFIX}" \
151
+ --arg url "${REMOTE_URL}" \
152
+ '.umbrella.childRepos += [{"id": $id, "path": $path, "name": $name, "prefix": $prefix, "githubUrl": $url}]' \
153
+ .specweave/config.json > .specweave/config.tmp && mv .specweave/config.tmp .specweave/config.json
154
+ ```
155
+
156
+ ### Step 5: Consolidate .env files
157
+
158
+ Scan all repos for `.env` files and merge unique keys into umbrella root:
159
+
160
+ ```bash
161
+ # 1. Find all .env files in repos (never display values)
162
+ ENV_FILES=$(find repositories -maxdepth 3 -name ".env" -not -path "*/node_modules/*" 2>/dev/null)
163
+
164
+ if [ -n "${ENV_FILES}" ]; then
165
+ echo "Found .env files:"
166
+ for f in ${ENV_FILES}; do
167
+ echo " ${f} ($(grep -c '=' "${f}" 2>/dev/null || echo 0) variables)"
168
+ done
169
+
170
+ # 2. Merge unique keys (preserving first occurrence of each key)
171
+ # NEVER display values — only key names and counts
172
+ for f in ${ENV_FILES}; do
173
+ while IFS= read -r line; do
174
+ KEY=$(echo "${line}" | cut -d'=' -f1)
175
+ if [ -n "${KEY}" ] && ! grep -q "^${KEY}=" "${TARGET}/.env" 2>/dev/null; then
176
+ echo "${line}" >> "${TARGET}/.env"
177
+ fi
178
+ done < "${f}"
179
+ done
180
+
181
+ echo "Consolidated $(grep -c '=' "${TARGET}/.env" 2>/dev/null || echo 0) variables into umbrella .env"
182
+ fi
183
+ ```
184
+
185
+ **Guard**: If umbrella `.env` already exists, only add NEW keys (don't overwrite existing).
186
+
187
+ ### Step 6: Track symlinks
188
+
189
+ Write a manifest for future cleanup/reference:
190
+
191
+ ```bash
192
+ # Create or update symlink manifest
193
+ cat > .specweave/state/symlinks.json << EOF
194
+ {
195
+ "created": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
196
+ "symlinks": [
197
+ {
198
+ "target": "${TARGET}/repositories/${ORG}/${REPO_DIR}",
199
+ "link": "${LOCAL_PATH}",
200
+ "repo": "${REPO_DIR}"
201
+ }
202
+ ]
203
+ }
204
+ EOF
205
+ ```
206
+
207
+ ### Step 7: Generate fresh-setup script
208
+
209
+ Create a reproducible bootstrap script for new machines:
210
+
211
+ ```bash
212
+ cat > "${TARGET}/setup.sh" << 'SETUP_EOF'
213
+ #!/bin/bash
214
+ # Fresh setup script for {NAME}
215
+ # Run this on a new machine to recreate the umbrella workspace
216
+ set -euo pipefail
217
+
218
+ UMBRELLA_DIR="${HOME}/Projects/{NAME}"
219
+ mkdir -p "${UMBRELLA_DIR}"
220
+ cd "${UMBRELLA_DIR}"
221
+
222
+ # Initialize SpecWeave
223
+ specweave init "{NAME}"
224
+
225
+ # Clone repositories
226
+ {FOR_EACH_REPO}
227
+ specweave get {SOURCE} {FLAGS}
228
+ {END_FOR_EACH}
229
+
230
+ # Create .env placeholder
231
+ cat > .env << 'ENV_EOF'
232
+ # Fill in your secrets:
233
+ {FOR_EACH_KEY}
234
+ {KEY}=
235
+ {END_FOR_EACH}
236
+ ENV_EOF
237
+
238
+ echo "Umbrella workspace ready at ${UMBRELLA_DIR}"
239
+ echo "Fill in .env with your secrets, then: cd ${UMBRELLA_DIR} && claude"
240
+ SETUP_EOF
241
+ chmod +x "${TARGET}/setup.sh"
242
+ ```
243
+
244
+ Replace `{PLACEHOLDERS}` with actual values from the repos that were added.
245
+
246
+ ### Step 8: Verify
247
+
248
+ Run these checks and report results:
249
+
250
+ ```bash
251
+ # 1. All repos accessible
252
+ for repo in repositories/*/*; do
253
+ [ -d "${repo}/.git" ] && echo "OK: ${repo}" || echo "MISSING: ${repo}"
254
+ done
255
+
256
+ # 2. Config valid
257
+ jq '.umbrella.childRepos | length' .specweave/config.json
258
+
259
+ # 3. Symlinks valid (if any)
260
+ if [ -f .specweave/state/symlinks.json ]; then
261
+ jq -r '.symlinks[].link' .specweave/state/symlinks.json | while read link; do
262
+ [ -L "${link}" ] && echo "OK: ${link}" || echo "BROKEN: ${link}"
263
+ done
264
+ fi
265
+
266
+ # 4. .env exists (if consolidated)
267
+ [ -f .env ] && echo ".env: $(grep -c '=' .env) variables" || echo ".env: not created"
268
+ ```
269
+
270
+ ### Step 8 output format:
271
+
272
+ ```
273
+ Umbrella workspace created: {NAME}
274
+ Location: {TARGET}
275
+ Repos: {COUNT} registered
276
+ Symlinks: {COUNT} created
277
+ .env: {COUNT} variables consolidated
278
+ Setup script: {TARGET}/setup.sh
279
+
280
+ Next steps:
281
+ cd {TARGET} && claude
282
+ sw:get <more-repos> # add more repos
283
+ sw:sync-setup # configure GitHub/JIRA/ADO sync
284
+ ```
285
+
286
+ ---
287
+
288
+ ## Mode: wrap
289
+
290
+ Wrap an existing repo (or set of repos) into a new umbrella.
291
+
292
+ ### Step 1: Detect current repo
293
+
294
+ ```bash
295
+ # Must be inside a git repo
296
+ REMOTE_URL=$(git remote get-url origin 2>/dev/null)
297
+ # Parse org and repo name
298
+ REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
299
+ ```
300
+
301
+ If not in a git repo, abort with: "Must be inside a git repository. Use `sw:umbrella init` instead."
302
+
303
+ ### Step 2: Determine umbrella name
304
+
305
+ - User-specified: use that
306
+ - Default: `{repo-name}-umb`
307
+
308
+ ```bash
309
+ TARGET="${HOME}/Projects/${UMBRELLA_NAME}"
310
+ ```
311
+
312
+ **Guard**: If target already exists, ask whether to add this repo to it or choose a different name.
313
+
314
+ ### Step 3: Create umbrella and move repo
315
+
316
+ ```bash
317
+ # 1. Create umbrella structure
318
+ mkdir -p "${TARGET}/repositories/${ORG}"
319
+
320
+ # 2. CONFIRM with user before moving (destructive)
321
+ echo "Will move: ${REPO_ROOT} → ${TARGET}/repositories/${ORG}/${REPO_NAME}"
322
+
323
+ # 3. Move repo
324
+ mv "${REPO_ROOT}" "${TARGET}/repositories/${ORG}/${REPO_NAME}"
325
+
326
+ # 4. Create symlink at old location
327
+ ln -s "${TARGET}/repositories/${ORG}/${REPO_NAME}" "${REPO_ROOT}"
328
+ ```
329
+
330
+ ### Step 4: Initialize SpecWeave
331
+
332
+ ```bash
333
+ cd "${TARGET}"
334
+ specweave init "${UMBRELLA_NAME}"
335
+ ```
336
+
337
+ ### Step 5: Register repo
338
+
339
+ Same registration as init mode Step 4 (local repo section).
340
+
341
+ ### Step 6: Additional repos
342
+
343
+ Ask: "Would you like to add more repos to this umbrella?"
344
+
345
+ If yes, for each additional repo use `specweave get <source>` or the local move flow from init mode.
346
+
347
+ ### Step 7: Consolidate .env and verify
348
+
349
+ Same as init mode Steps 5-8.
350
+
351
+ ---
352
+
353
+ ## Symlink Management
354
+
355
+ Symlinks are tracked in `.specweave/state/symlinks.json` for reference and cleanup.
356
+
357
+ **To list symlinks:**
358
+ ```bash
359
+ jq -r '.symlinks[] | "\(.link) → \(.target)"' .specweave/state/symlinks.json
360
+ ```
361
+
362
+ **To remove symlinks** (when no longer needed):
363
+ ```bash
364
+ jq -r '.symlinks[].link' .specweave/state/symlinks.json | while read link; do
365
+ [ -L "${link}" ] && rm "${link}" && echo "Removed: ${link}"
366
+ done
367
+ ```
368
+
369
+ ---
370
+
371
+ ## .env Safety Rules
372
+
373
+ 1. **NEVER** display .env values — use `grep -c '='` for counts, `cut -d'=' -f1` for key names only
374
+ 2. **NEVER** commit .env files — verify `.gitignore` includes `.env*`
375
+ 3. When consolidating, preserve first occurrence of each key (don't overwrite)
376
+ 4. If a key exists in multiple repos with different values, note the conflict for the user (by key name only)
377
+
378
+ ---
379
+
380
+ ## Examples
381
+
382
+ | User says | Mode | Action |
383
+ |-----------|------|--------|
384
+ | "Create umbrella cloud-umb with org/api and org/web" | init | Clone 2 repos into new umbrella |
385
+ | "Create umbrella for claude-code and anymodel" | init | Prompt for URLs/locations, clone/move |
386
+ | "Wrap this repo in an umbrella" | wrap | Move current repo into new umbrella |
387
+ | "Restructure these projects into an umbrella workspace" | init | Gather repo list, create umbrella |
388
+ | "Setup multi-repo workspace" | init | Prompt for name and repos |
389
+ | "I need an umbrella for my-api, my-web, and my-shared" | init | Parse 3 repos, create umbrella |
390
+
391
+ ---
392
+
393
+ ## Verification Checklist
394
+
395
+ After creating the umbrella, verify all of these pass:
396
+
397
+ - [ ] `ls repositories/*/*/.git` — all repos have .git directories
398
+ - [ ] `jq '.umbrella.childRepos | length' .specweave/config.json` — matches repo count
399
+ - [ ] `jq '.umbrella.enabled' .specweave/config.json` — returns `true`
400
+ - [ ] `[ -f CLAUDE.md ]` — instruction file exists
401
+ - [ ] `[ -f .env ] || echo "no .env (expected if no secrets)"` — .env handled
402
+ - [ ] Symlinks resolve: `for l in $(jq -r '.symlinks[].link' .specweave/state/symlinks.json 2>/dev/null); do test -L "$l"; done`
403
+
404
+ ## Resources
405
+
406
+ - [Official Documentation](https://verified-skill.com/docs/reference/skills#umbrella)