specweave 0.16.1 → 0.16.2

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": "0.16.1",
3
+ "version": "0.16.2",
4
4
  "description": "Spec-driven development framework for Claude Code. AI-native workflow with living documentation, intelligent agents, and multilingual support (9 languages). Enterprise-grade traceability with permanent specs and temporary increments.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -347,16 +347,52 @@ create_github_issue() {
347
347
  }
348
348
  ' "$tasks_file")
349
349
 
350
- # Detect repository from git remote
351
- local repo=$(git remote get-url origin 2>/dev/null | sed 's/.*github\.com[:/]\(.*\)\.git/\1/' | sed 's/.*github\.com[:/]\(.*\)/\1/')
350
+ # Detect repository from profile-based config
351
+ local repo=""
352
+ local owner=""
353
+ local repo_name=""
352
354
 
355
+ # First, check if increment has a specific githubProfile in metadata
356
+ local metadata_file="$2/metadata.json"
357
+ local profile_id=""
358
+
359
+ if [ -f "$metadata_file" ]; then
360
+ profile_id=$(cat "$metadata_file" 2>/dev/null | grep -o '"githubProfile"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)".*/\1/')
361
+ log_debug "Found githubProfile in metadata: $profile_id"
362
+ fi
363
+
364
+ # If no profile in metadata, use activeProfile from config
365
+ if [ -z "$profile_id" ]; then
366
+ profile_id=$(cat "$CONFIG_FILE" 2>/dev/null | grep -o '"activeProfile"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)".*/\1/')
367
+ log_debug "Using activeProfile from config: $profile_id"
368
+ fi
369
+
370
+ if [ -n "$profile_id" ]; then
371
+ # Extract owner and repo from the profile
372
+ local profile_section=$(cat "$CONFIG_FILE" 2>/dev/null | awk "/$profile_id/,/^[[:space:]]*\}/{print}")
373
+ owner=$(echo "$profile_section" | grep -o '"owner"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)".*/\1/')
374
+ repo_name=$(echo "$profile_section" | grep -o '"repo"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)".*/\1/')
375
+
376
+ if [ -n "$owner" ] && [ -n "$repo_name" ]; then
377
+ repo="$owner/$repo_name"
378
+ log_debug "Using repo from profile: $repo"
379
+ fi
380
+ fi
381
+
382
+ # Fallback to git remote detection if no profile config found
383
+ if [ -z "$repo" ]; then
384
+ repo=$(git remote get-url origin 2>/dev/null | sed 's/.*github\.com[:/]\(.*\)\.git/\1/' | sed 's/.*github\.com[:/]\(.*\)/\1/')
385
+ log_debug "Fallback to git remote: $repo"
386
+ fi
387
+
388
+ # Legacy fallback to old config format
353
389
  if [ -z "$repo" ]; then
354
- # Fallback to config
355
390
  repo=$(cat "$CONFIG_FILE" 2>/dev/null | grep -A 5 '"sync"' | grep -o '"repo"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)".*/\1/')
391
+ log_debug "Legacy fallback to old config: $repo"
356
392
  fi
357
393
 
358
394
  if [ -z "$repo" ]; then
359
- log_error "Could not detect GitHub repository"
395
+ log_error "Could not detect GitHub repository from profile or git remote"
360
396
  return 1
361
397
  fi
362
398
 
@@ -444,7 +480,15 @@ EOF
444
480
  # Update existing metadata.json with github section
445
481
  if command -v jq >/dev/null 2>&1; then
446
482
  local temp_metadata=$(mktemp)
447
- jq ". + {\"github\": {\"issue\": $issue_number, \"url\": \"$issue_url\", \"synced\": \"$current_timestamp\"}}" "$metadata_file" > "$temp_metadata"
483
+ local jq_update=". + {\"github\": {\"issue\": $issue_number, \"url\": \"$issue_url\", \"synced\": \"$current_timestamp\"}"
484
+
485
+ # Add profile ID if we have it
486
+ if [ -n "$profile_id" ]; then
487
+ jq_update="$jq_update, \"githubProfile\": \"$profile_id\""
488
+ jq_update=". + {\"github\": {\"issue\": $issue_number, \"url\": \"$issue_url\", \"synced\": \"$current_timestamp\"}, \"githubProfile\": \"$profile_id\"}"
489
+ fi
490
+
491
+ jq "$jq_update" "$metadata_file" > "$temp_metadata"
448
492
  mv "$temp_metadata" "$metadata_file"
449
493
  else
450
494
  # Fallback: manual JSON construction (less reliable)
@@ -455,6 +499,7 @@ EOF
455
499
  "status": "active",
456
500
  "type": "feature",
457
501
  "created": "$current_timestamp",
502
+ "githubProfile": "$profile_id",
458
503
  "github": {
459
504
  "issue": $issue_number,
460
505
  "url": "$issue_url",
@@ -149,12 +149,19 @@ User: "I want to build real-time price tracking"
149
149
 
150
150
  increment-planner skill
151
151
 
152
- STEP 1: Scan existing docs
152
+ STEP 1: Determine increment number and check for duplicates
153
+ ├─ Use the Bash tool to run: node plugins/specweave/skills/increment-planner/scripts/feature-utils.js next
154
+ ├─ Get next available increment number (e.g., "0021")
155
+ ├─ Get short name from user description
156
+ ├─ Check if increment already exists using: node plugins/specweave/skills/increment-planner/scripts/feature-utils.js check-increment {number}
157
+ └─ If duplicate found, STOP and tell user: "Increment {number} already exists! Please use the existing increment."
158
+
159
+ STEP 2: Scan existing docs
153
160
  ├─ Read .specweave/docs/internal/strategy/ (existing requirements)
154
161
  ├─ Read .specweave/docs/internal/architecture/adr/ (existing decisions)
155
162
  └─ Pass existing context to agents
156
163
 
157
- STEP 2: Invoke PM Agent (🚨 MANDATORY - USE TASK TOOL)
164
+ STEP 3: Invoke PM Agent (🚨 MANDATORY - USE TASK TOOL)
158
165
 
159
166
  YOU MUST USE THE TASK TOOL - DO NOT SKIP:
160
167
 
@@ -206,7 +213,7 @@ Task(
206
213
 
207
214
  Wait for PM agent to complete!
208
215
 
209
- STEP 3: Invoke Architect Agent (🚨 MANDATORY - USE TASK TOOL)
216
+ STEP 4: Invoke Architect Agent (🚨 MANDATORY - USE TASK TOOL)
210
217
 
211
218
  YOU MUST USE THE TASK TOOL - DO NOT SKIP:
212
219
 
@@ -239,7 +246,7 @@ Task(
239
246
 
240
247
  Wait for Architect agent to complete!
241
248
 
242
- STEP 4: Invoke Test-Aware Planner Agent (🚨 MANDATORY - USE TASK TOOL)
249
+ STEP 5: Invoke Test-Aware Planner Agent (🚨 MANDATORY - USE TASK TOOL)
243
250
 
244
251
  YOU MUST USE THE TASK TOOL - DO NOT SKIP:
245
252
 
@@ -275,7 +282,7 @@ Task(
275
282
 
276
283
  Wait for test-aware-planner agent to complete!
277
284
 
278
- STEP 5: Validate Living Docs and Increment Files
285
+ STEP 6: Validate Living Docs and Increment Files
279
286
  ├─ Check .specweave/docs/internal/specs/spec-{number}-{name}/spec.md exists (SOURCE OF TRUTH)
280
287
  ├─ Check living spec.md contains ALL user stories, requirements, AC-IDs (with AC-IDs)
281
288
  ├─ Check .specweave/docs/internal/architecture/adr/ has ≥3 ADRs
@@ -3,8 +3,12 @@
3
3
  * Supports increment-planner skill with auto-numbering and name generation
4
4
  */
5
5
 
6
- const fs = require('fs');
7
- const path = require('path');
6
+ import fs from 'fs';
7
+ import path from 'path';
8
+ import { fileURLToPath } from 'url';
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
8
12
 
9
13
  /**
10
14
  * Stop words to filter from feature descriptions
@@ -198,7 +202,7 @@ function parseFeatureDescription(description) {
198
202
  };
199
203
  }
200
204
 
201
- module.exports = {
205
+ export {
202
206
  generateShortName,
203
207
  getNextFeatureNumber,
204
208
  featureExists,
@@ -210,8 +214,8 @@ module.exports = {
210
214
  STOP_WORDS
211
215
  };
212
216
 
213
- // CLI usage
214
- if (require.main === module) {
217
+ // CLI usage - check if this file is being run directly
218
+ if (import.meta.url === `file://${process.argv[1]}`) {
215
219
  const args = process.argv.slice(2);
216
220
 
217
221
  if (args.length === 0) {
@@ -219,6 +223,7 @@ if (require.main === module) {
219
223
  console.log(' node feature-utils.js shortname "feature description"');
220
224
  console.log(' node feature-utils.js next [features-dir]');
221
225
  console.log(' node feature-utils.js parse "feature description"');
226
+ console.log(' node feature-utils.js check-increment <number> [features-dir]');
222
227
  process.exit(0);
223
228
  }
224
229
 
@@ -243,6 +248,22 @@ if (require.main === module) {
243
248
  }
244
249
  break;
245
250
 
251
+ case 'check-increment':
252
+ if (args[1]) {
253
+ const incrementNumber = args[1];
254
+ const checkDir = args[2] || '.specweave/increments';
255
+ if (incrementNumberExists(incrementNumber, checkDir)) {
256
+ console.error(`ERROR: Increment ${incrementNumber} already exists!`);
257
+ process.exit(1);
258
+ } else {
259
+ console.log(`OK: Increment ${incrementNumber} is available`);
260
+ }
261
+ } else {
262
+ console.error('Error: Increment number required');
263
+ process.exit(1);
264
+ }
265
+ break;
266
+
246
267
  default:
247
268
  console.error(`Unknown command: ${command}`);
248
269
  process.exit(1);
@@ -208,11 +208,10 @@ Both approaches work perfectly - use whichever feels more natural!
208
208
  ### Increment Structure
209
209
 
210
210
  ```
211
- .specweave/increments/0001-user-auth/
211
+ .specweave/increments/0001-user-auth/ # ⚠️ ID must be unique!
212
212
  ├── spec.md # WHAT & WHY
213
213
  ├── plan.md # HOW
214
- ├── tasks.md # Implementation steps
215
- ├── tests.md # Test strategy
214
+ ├── tasks.md # Implementation steps with embedded tests
216
215
  ├── context-manifest.yaml # Selective context loading
217
216
  ├── logs/ # ✅ Execution logs, errors, AI sessions
218
217
  ├── scripts/ # ✅ Helper scripts, migrations, setup
@@ -278,12 +277,11 @@ Config: Auto-detected from project files
278
277
  │ │ │ ├── operations/ # Runbooks, monitoring
279
278
  │ │ │ └── governance/ # Security, compliance
280
279
  │ │ └── public/ # Published docs
281
- │ ├── increments/ # Features (auto-numbered)
282
- │ │ └── 0001-feature-name/
283
- │ │ ├── spec.md
284
- │ │ ├── plan.md
285
- │ │ ├── tasks.md
286
- │ │ ├── tests.md
280
+ │ ├── increments/ # Features (auto-numbered, UNIQUE IDs)
281
+ │ │ └── 0001-feature-name/ # ⚠️ Each ID must be unique (0001-9999)
282
+ │ │ ├── spec.md # What we're building
283
+ │ │ ├── plan.md # How we'll build it
284
+ │ │ ├── tasks.md # Tasks with embedded tests
287
285
  │ │ ├── logs/ # ✅ Put logs here
288
286
  │ │ ├── scripts/ # ✅ Put scripts here
289
287
  │ │ └── reports/ # ✅ Put reports here
@@ -436,6 +434,7 @@ Plugins are detected and suggested during `specweave init` based on:
436
434
  4. **Validated**: Every increment validated before closure
437
435
  5. **Traceable**: All work traces back to specs and requirements
438
436
  6. **Clean Organization**: All supporting files in increment folders, never root
437
+ 7. **No Duplicate Increments**: Each increment must have a unique 4-digit ID (0001-9999)
439
438
 
440
439
  ---
441
440