specweave 0.30.19 → 0.32.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/CLAUDE.md +176 -2
- package/README.md +22 -0
- package/bin/specweave.js +18 -1
- package/dist/src/cli/commands/cache.d.ts +17 -0
- package/dist/src/cli/commands/cache.d.ts.map +1 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/cache.js.map +1 -0
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/plan/increment-detector.js +2 -2
- package/dist/src/cli/commands/plan/increment-detector.js.map +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js +1 -1
- package/dist/src/cli/commands/sync-spec-commits.js.map +1 -1
- package/dist/src/cli/commands/sync-specs.js +2 -2
- package/dist/src/cli/commands/sync-specs.js.map +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js +1 -1
- package/dist/src/cli/helpers/github/increment-profile-selector.js.map +1 -1
- package/dist/src/cli/workers/living-docs-worker.js +66 -1
- package/dist/src/cli/workers/living-docs-worker.js.map +1 -1
- package/dist/src/config/types.d.ts +203 -1208
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.d.ts.map +1 -1
- package/dist/src/core/discrepancy/increment-generator.js +5 -2
- package/dist/src/core/discrepancy/increment-generator.js.map +1 -1
- package/dist/src/core/external-tools/external-items-counter.d.ts +62 -0
- package/dist/src/core/external-tools/external-items-counter.d.ts.map +1 -0
- package/dist/src/core/external-tools/external-items-counter.js +206 -0
- package/dist/src/core/external-tools/external-items-counter.js.map +1 -0
- package/dist/src/core/external-tools/external-items-display.d.ts +39 -0
- package/dist/src/core/external-tools/external-items-display.d.ts.map +1 -0
- package/dist/src/core/external-tools/external-items-display.js +185 -0
- package/dist/src/core/external-tools/external-items-display.js.map +1 -0
- package/dist/src/core/external-tools/index.d.ts +8 -0
- package/dist/src/core/external-tools/index.d.ts.map +1 -0
- package/dist/src/core/external-tools/index.js +8 -0
- package/dist/src/core/external-tools/index.js.map +1 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts +39 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.js +188 -0
- package/dist/src/core/external-tools/providers/ado-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.d.ts +38 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.js +136 -0
- package/dist/src/core/external-tools/providers/github-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/providers/index.d.ts +7 -0
- package/dist/src/core/external-tools/providers/index.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/index.js +7 -0
- package/dist/src/core/external-tools/providers/index.js.map +1 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts +42 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.d.ts.map +1 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.js +153 -0
- package/dist/src/core/external-tools/providers/jira-items-adapter.js.map +1 -0
- package/dist/src/core/external-tools/types.d.ts +78 -0
- package/dist/src/core/external-tools/types.d.ts.map +1 -0
- package/dist/src/core/external-tools/types.js +19 -0
- package/dist/src/core/external-tools/types.js.map +1 -0
- package/dist/src/core/increment/duplicate-detector.js +2 -2
- package/dist/src/core/increment/duplicate-detector.js.map +1 -1
- package/dist/src/core/increment/increment-archiver.d.ts +24 -0
- package/dist/src/core/increment/increment-archiver.d.ts.map +1 -1
- package/dist/src/core/increment/increment-archiver.js +59 -2
- package/dist/src/core/increment/increment-archiver.js.map +1 -1
- package/dist/src/core/increment/increment-status.js +2 -2
- package/dist/src/core/increment/increment-status.js.map +1 -1
- package/dist/src/core/increment/increment-utils.d.ts +98 -37
- package/dist/src/core/increment/increment-utils.d.ts.map +1 -1
- package/dist/src/core/increment/increment-utils.js +119 -68
- package/dist/src/core/increment/increment-utils.js.map +1 -1
- package/dist/src/core/increment/metadata-validator.js +1 -1
- package/dist/src/core/increment/metadata-validator.js.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.d.ts.map +1 -1
- package/dist/src/core/increment/status-change-sync-trigger.js +4 -0
- package/dist/src/core/increment/status-change-sync-trigger.js.map +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js +1 -1
- package/dist/src/core/living-docs/feature-id-manager.js.map +1 -1
- package/dist/src/core/living-docs/hierarchy-mapper.js +3 -3
- package/dist/src/core/living-docs/hierarchy-mapper.js.map +1 -1
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts +18 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js +247 -0
- package/dist/src/core/living-docs/intelligent-analyzer/architecture-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts +15 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js +138 -0
- package/dist/src/core/living-docs/intelligent-analyzer/deep-repo-analyzer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts +24 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js +198 -0
- package/dist/src/core/living-docs/intelligent-analyzer/file-sampler.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts +17 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js +241 -0
- package/dist/src/core/living-docs/intelligent-analyzer/inconsistency-detector.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts +28 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js +197 -0
- package/dist/src/core/living-docs/intelligent-analyzer/index.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts +18 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js +154 -0
- package/dist/src/core/living-docs/intelligent-analyzer/organization-synthesizer.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts +42 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js +343 -0
- package/dist/src/core/living-docs/intelligent-analyzer/strategy-generator.js.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts +146 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.d.ts.map +1 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js +7 -0
- package/dist/src/core/living-docs/intelligent-analyzer/types.js.map +1 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts +5 -0
- package/dist/src/core/living-docs/living-docs-sync.d.ts.map +1 -1
- package/dist/src/core/living-docs/living-docs-sync.js +36 -2
- package/dist/src/core/living-docs/living-docs-sync.js.map +1 -1
- package/dist/src/core/llm/providers/azure-openai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/azure-openai-provider.js +1 -0
- package/dist/src/core/llm/providers/azure-openai-provider.js.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/bedrock-provider.js +2 -0
- package/dist/src/core/llm/providers/bedrock-provider.js.map +1 -1
- package/dist/src/core/llm/providers/openai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/openai-provider.js +1 -0
- package/dist/src/core/llm/providers/openai-provider.js.map +1 -1
- package/dist/src/core/llm/providers/vertex-ai-provider.d.ts.map +1 -1
- package/dist/src/core/llm/providers/vertex-ai-provider.js +1 -0
- package/dist/src/core/llm/providers/vertex-ai-provider.js.map +1 -1
- package/dist/src/core/sync/spec-increment-mapper.js +3 -3
- package/dist/src/core/sync/spec-increment-mapper.js.map +1 -1
- package/dist/src/importers/item-converter.d.ts +25 -0
- package/dist/src/importers/item-converter.d.ts.map +1 -1
- package/dist/src/importers/item-converter.js +135 -5
- package/dist/src/importers/item-converter.js.map +1 -1
- package/dist/src/init/architecture/types.d.ts +33 -140
- package/dist/src/init/architecture/types.d.ts.map +1 -1
- package/dist/src/init/compliance/types.d.ts +30 -27
- package/dist/src/init/compliance/types.d.ts.map +1 -1
- package/dist/src/init/repo/types.d.ts +11 -34
- package/dist/src/init/repo/types.d.ts.map +1 -1
- package/dist/src/init/research/src/config/types.d.ts +15 -82
- package/dist/src/init/research/src/config/types.d.ts.map +1 -1
- package/dist/src/init/research/types.d.ts +38 -93
- package/dist/src/init/research/types.d.ts.map +1 -1
- package/dist/src/init/team/types.d.ts +4 -42
- package/dist/src/init/team/types.d.ts.map +1 -1
- package/dist/src/types/dashboard-cache.d.ts +181 -0
- package/dist/src/types/dashboard-cache.d.ts.map +1 -0
- package/dist/src/types/dashboard-cache.js +65 -0
- package/dist/src/types/dashboard-cache.js.map +1 -0
- package/dist/src/utils/docs-validator.d.ts +131 -0
- package/dist/src/utils/docs-validator.d.ts.map +1 -0
- package/dist/src/utils/docs-validator.js +529 -0
- package/dist/src/utils/docs-validator.js.map +1 -0
- package/dist/src/utils/feature-id-collision.js +1 -1
- package/dist/src/utils/feature-id-collision.js.map +1 -1
- package/dist/src/utils/html-to-mdx.d.ts +1 -0
- package/dist/src/utils/html-to-mdx.d.ts.map +1 -1
- package/dist/src/utils/html-to-mdx.js +43 -5
- package/dist/src/utils/html-to-mdx.js.map +1 -1
- package/package.json +1 -5
- package/plugins/specweave/agents/pm/AGENT.md +10 -7
- package/plugins/specweave/commands/specweave-archive-features.md +5 -7
- package/plugins/specweave/commands/specweave-archive.md +2 -1
- package/plugins/specweave/commands/specweave-do.md +35 -1
- package/plugins/specweave/commands/specweave-done.md +96 -0
- package/plugins/specweave/commands/specweave-external.md +150 -0
- package/plugins/specweave/commands/specweave-import-external.md +45 -18
- package/plugins/specweave/commands/specweave-increment.md +331 -33
- package/plugins/specweave/commands/specweave-jobs.md +2 -2
- package/plugins/specweave/commands/specweave-progress.md +4 -4
- package/plugins/specweave/commands/specweave-restore-feature.md +5 -4
- package/plugins/specweave/commands/specweave-sync-docs.md +1 -1
- package/plugins/specweave/commands/specweave-sync-specs.md +216 -322
- package/plugins/specweave/commands/specweave-validate-features.md +13 -8
- package/plugins/specweave/hooks/docs-changed.sh.backup +79 -0
- package/plugins/specweave/hooks/hooks.json +33 -4
- package/plugins/specweave/hooks/human-input-required.sh.backup +75 -0
- package/plugins/specweave/hooks/lib/common-setup.sh +375 -0
- package/plugins/specweave/hooks/lib/crash-prevention.sh +336 -0
- package/plugins/specweave/hooks/post-first-increment.sh.backup +61 -0
- package/plugins/specweave/hooks/post-increment-change.sh.backup +98 -0
- package/plugins/specweave/hooks/post-increment-completion.sh.backup +231 -0
- package/plugins/specweave/hooks/post-increment-planning.sh.backup +1048 -0
- package/plugins/specweave/hooks/post-increment-status-change.sh.backup +147 -0
- package/plugins/specweave/hooks/post-spec-update.sh.backup +158 -0
- package/plugins/specweave/hooks/post-task-completion.sh +4 -23
- package/plugins/specweave/hooks/post-user-story-complete.sh.backup +179 -0
- package/plugins/specweave/hooks/pre-command-deduplication.sh +1 -6
- package/plugins/specweave/hooks/pre-command-deduplication.sh.backup +83 -0
- package/plugins/specweave/hooks/pre-implementation.sh.backup +67 -0
- package/plugins/specweave/hooks/pre-task-completion.sh +8 -37
- package/plugins/specweave/hooks/pre-task-completion.sh.backup +194 -0
- package/plugins/specweave/hooks/pre-tool-use.sh +2 -11
- package/plugins/specweave/hooks/pre-tool-use.sh.backup +133 -0
- package/plugins/specweave/hooks/universal/dispatcher.mjs +135 -42
- package/plugins/specweave/hooks/universal/fail-fast-wrapper.sh +183 -0
- package/plugins/specweave/hooks/universal/hook-wrapper.cmd +26 -26
- package/plugins/specweave/hooks/universal/session-start.cmd +16 -16
- package/plugins/specweave/hooks/universal/session-start.ps1 +16 -16
- package/plugins/specweave/hooks/user-prompt-submit.sh +140 -38
- package/plugins/specweave/hooks/user-prompt-submit.sh.backup +386 -0
- package/plugins/specweave/hooks/v2/dispatchers/post-tool-use.sh +12 -0
- package/plugins/specweave/hooks/v2/dispatchers/session-start.sh +89 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.sh +211 -0
- package/plugins/specweave/hooks/v2/guards/bash-file-guard.test.sh +163 -0
- package/plugins/specweave/hooks/v2/guards/completion-guard.sh +26 -28
- package/plugins/specweave/hooks/v2/guards/features-folder-guard.sh +50 -0
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js +2 -2
- package/plugins/specweave/lib/vendor/core/increment/duplicate-detector.js.map +1 -1
- package/plugins/specweave/scripts/README.md +166 -0
- package/plugins/specweave/scripts/cleanup-state.sh +142 -0
- package/plugins/specweave/scripts/force-kill.sh +142 -0
- package/plugins/specweave/scripts/jobs.js +171 -0
- package/plugins/specweave/scripts/progress.js +170 -0
- package/plugins/specweave/scripts/read-costs.sh +132 -0
- package/plugins/specweave/scripts/read-jobs.sh +324 -0
- package/plugins/specweave/scripts/read-progress.sh +185 -0
- package/plugins/specweave/scripts/read-status.sh +146 -0
- package/plugins/specweave/scripts/read-workflow.sh +173 -0
- package/plugins/specweave/scripts/rebuild-dashboard-cache.sh +327 -0
- package/plugins/specweave/scripts/session-watchdog.sh +192 -0
- package/plugins/specweave/scripts/status.js +154 -0
- package/plugins/specweave/scripts/update-dashboard-cache.sh +281 -0
- package/plugins/specweave/skills/increment-planner/SKILL.md +333 -24
- package/plugins/specweave/skills/increment-planner/templates/spec-multi-project.md +17 -9
- package/plugins/specweave/skills/increment-planner/templates/spec-single-project.md +6 -2
- package/plugins/specweave/skills/instant-status/SKILL.md +70 -0
- package/plugins/specweave-ado/hooks/post-living-docs-update.sh.backup +353 -0
- package/plugins/specweave-ado/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-ado/lib/enhanced-ado-sync.js +170 -0
- package/plugins/specweave-docs/commands/build.md +32 -4
- package/plugins/specweave-docs/commands/preview.md +43 -1
- package/plugins/specweave-docs/commands/validate.md +250 -0
- package/plugins/specweave-github/hooks/.specweave/logs/hooks-debug.log +1262 -626
- package/plugins/specweave-github/hooks/post-task-completion.sh.backup +258 -0
- package/plugins/specweave-github/lib/enhanced-github-sync.js +220 -0
- package/plugins/specweave-jira/hooks/post-task-completion.sh.backup +172 -0
- package/plugins/specweave-jira/lib/enhanced-jira-sync.js +134 -0
- package/plugins/specweave-release/hooks/.specweave/logs/dora-tracking.log +1254 -939
- package/plugins/specweave-release/hooks/post-task-completion.sh.backup +110 -0
- package/plugins/specweave/hooks/post-edit-spec.sh +0 -265
- package/plugins/specweave/hooks/post-write-spec.sh +0 -267
- package/plugins/specweave/hooks/pre-edit-spec.sh +0 -151
- package/plugins/specweave/hooks/pre-write-spec.sh +0 -151
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# update-dashboard-cache.sh - Incremental update of dashboard cache
|
|
3
|
+
#
|
|
4
|
+
# Usage: bash update-dashboard-cache.sh <incrementId> <changeType>
|
|
5
|
+
#
|
|
6
|
+
# Arguments:
|
|
7
|
+
# incrementId - Increment ID (e.g., "0117-instant-dashboard-cache")
|
|
8
|
+
# changeType - Type of change: metadata|tasks|spec|jobs
|
|
9
|
+
#
|
|
10
|
+
# Updates only the affected increment in the cache, not a full rebuild.
|
|
11
|
+
# Uses file locking for concurrent safety.
|
|
12
|
+
#
|
|
13
|
+
# Compatible with bash 3.x (macOS default)
|
|
14
|
+
|
|
15
|
+
set -e
|
|
16
|
+
|
|
17
|
+
INCREMENT_ID="${1:-}"
|
|
18
|
+
CHANGE_TYPE="${2:-}"
|
|
19
|
+
|
|
20
|
+
if [[ -z "$INCREMENT_ID" ]]; then
|
|
21
|
+
echo "❌ Usage: update-dashboard-cache.sh <incrementId> <changeType>"
|
|
22
|
+
exit 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Find project root
|
|
26
|
+
PROJECT_ROOT="$PWD"
|
|
27
|
+
while [[ "$PROJECT_ROOT" != "/" ]] && [[ ! -d "$PROJECT_ROOT/.specweave" ]]; do
|
|
28
|
+
PROJECT_ROOT=$(dirname "$PROJECT_ROOT")
|
|
29
|
+
done
|
|
30
|
+
|
|
31
|
+
if [[ ! -d "$PROJECT_ROOT/.specweave" ]]; then
|
|
32
|
+
echo "❌ No .specweave directory found"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
INCREMENTS_DIR="$PROJECT_ROOT/.specweave/increments"
|
|
37
|
+
STATE_DIR="$PROJECT_ROOT/.specweave/state"
|
|
38
|
+
CACHE_FILE="$STATE_DIR/dashboard.json"
|
|
39
|
+
LOCK_FILE="$STATE_DIR/.dashboard.lock"
|
|
40
|
+
TEMP_FILE="$STATE_DIR/.dashboard.json.tmp.$$"
|
|
41
|
+
|
|
42
|
+
# Check if jq is available
|
|
43
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
44
|
+
echo "❌ jq is required. Install with: brew install jq"
|
|
45
|
+
exit 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Acquire file lock (with timeout)
|
|
49
|
+
acquire_lock() {
|
|
50
|
+
local timeout=5
|
|
51
|
+
local count=0
|
|
52
|
+
while [[ -f "$LOCK_FILE" ]] && [[ $count -lt $timeout ]]; do
|
|
53
|
+
sleep 0.1
|
|
54
|
+
count=$((count + 1))
|
|
55
|
+
done
|
|
56
|
+
echo "$$" > "$LOCK_FILE"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
release_lock() {
|
|
60
|
+
rm -f "$LOCK_FILE"
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
# Cleanup on exit
|
|
64
|
+
cleanup() {
|
|
65
|
+
release_lock
|
|
66
|
+
rm -f "$TEMP_FILE"
|
|
67
|
+
}
|
|
68
|
+
trap cleanup EXIT
|
|
69
|
+
|
|
70
|
+
# If cache doesn't exist, do full rebuild
|
|
71
|
+
if [[ ! -f "$CACHE_FILE" ]]; then
|
|
72
|
+
bash "$PROJECT_ROOT/plugins/specweave/scripts/rebuild-dashboard-cache.sh" --quiet
|
|
73
|
+
exit 0
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Find increment directory
|
|
77
|
+
INCREMENT_DIR=""
|
|
78
|
+
for dir in "$INCREMENTS_DIR"/*"$INCREMENT_ID"*/; do
|
|
79
|
+
if [[ -d "$dir" ]]; then
|
|
80
|
+
INCREMENT_DIR="$dir"
|
|
81
|
+
INCREMENT_ID=$(basename "$dir")
|
|
82
|
+
break
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
|
|
86
|
+
if [[ -z "$INCREMENT_DIR" ]] || [[ ! -d "$INCREMENT_DIR" ]]; then
|
|
87
|
+
# Increment might have been archived or deleted
|
|
88
|
+
# Remove from cache if it exists
|
|
89
|
+
acquire_lock
|
|
90
|
+
if jq -e --arg id "$INCREMENT_ID" '.increments[$id]' "$CACHE_FILE" >/dev/null 2>&1; then
|
|
91
|
+
# Get old status for counter updates
|
|
92
|
+
old_status=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].status // "backlog"' "$CACHE_FILE")
|
|
93
|
+
old_type=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].type // "feature"' "$CACHE_FILE")
|
|
94
|
+
old_priority=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].priority // "P1"' "$CACHE_FILE")
|
|
95
|
+
|
|
96
|
+
# Remove increment and update counters
|
|
97
|
+
jq --arg id "$INCREMENT_ID" \
|
|
98
|
+
--arg old_status "$old_status" \
|
|
99
|
+
--arg old_type "$old_type" \
|
|
100
|
+
--arg old_priority "$old_priority" '
|
|
101
|
+
del(.increments[$id]) |
|
|
102
|
+
del(.mtimes[$id]) |
|
|
103
|
+
.summary.total -= 1 |
|
|
104
|
+
.summary[$old_status] -= 1 |
|
|
105
|
+
.summary.byType[$old_type] -= 1 |
|
|
106
|
+
.summary.byPriority[$old_priority] -= 1 |
|
|
107
|
+
.updatedAt = (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
108
|
+
' "$CACHE_FILE" > "$TEMP_FILE"
|
|
109
|
+
mv "$TEMP_FILE" "$CACHE_FILE"
|
|
110
|
+
fi
|
|
111
|
+
exit 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
metadata_file="$INCREMENT_DIR/metadata.json"
|
|
115
|
+
tasks_file="$INCREMENT_DIR/tasks.md"
|
|
116
|
+
spec_file="$INCREMENT_DIR/spec.md"
|
|
117
|
+
|
|
118
|
+
# Skip if no metadata
|
|
119
|
+
if [[ ! -f "$metadata_file" ]]; then
|
|
120
|
+
exit 0
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Read current values
|
|
124
|
+
status=$(jq -r '.status // "backlog"' "$metadata_file" 2>/dev/null)
|
|
125
|
+
type=$(jq -r '.type // "feature"' "$metadata_file" 2>/dev/null)
|
|
126
|
+
priority=$(jq -r '.priority // "P1"' "$metadata_file" 2>/dev/null)
|
|
127
|
+
title=$(jq -r '.title // ""' "$metadata_file" 2>/dev/null)
|
|
128
|
+
project=$(jq -r '.project // ""' "$metadata_file" 2>/dev/null)
|
|
129
|
+
created_at=$(jq -r '.createdAt // ""' "$metadata_file" 2>/dev/null)
|
|
130
|
+
user_stories=$(jq -c '.userStories // []' "$metadata_file" 2>/dev/null || echo "[]")
|
|
131
|
+
|
|
132
|
+
# Count tasks
|
|
133
|
+
total_tasks=0
|
|
134
|
+
completed_tasks=0
|
|
135
|
+
if [[ -f "$tasks_file" ]]; then
|
|
136
|
+
total_tasks=$(grep -c "^### T-" "$tasks_file" 2>/dev/null) || total_tasks=0
|
|
137
|
+
completed_tasks=$(grep "^\*\*Status\*\*:.*\[x\]" "$tasks_file" 2>/dev/null | wc -l | tr -d ' ') || completed_tasks=0
|
|
138
|
+
total_tasks="${total_tasks:-0}"
|
|
139
|
+
completed_tasks="${completed_tasks:-0}"
|
|
140
|
+
fi
|
|
141
|
+
if [[ "$total_tasks" -eq 0 ]]; then
|
|
142
|
+
total_tasks=$(jq -r '.tasks.total // 0' "$metadata_file" 2>/dev/null) || total_tasks=0
|
|
143
|
+
completed_tasks=$(jq -r '.tasks.completed // 0' "$metadata_file" 2>/dev/null) || completed_tasks=0
|
|
144
|
+
total_tasks="${total_tasks:-0}"
|
|
145
|
+
completed_tasks="${completed_tasks:-0}"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# Count ACs
|
|
149
|
+
total_acs=0
|
|
150
|
+
completed_acs=0
|
|
151
|
+
if [[ -f "$spec_file" ]]; then
|
|
152
|
+
total_acs=$(grep -c "\- \[.\] \*\*AC-" "$spec_file" 2>/dev/null) || total_acs=0
|
|
153
|
+
completed_acs=$(grep -c "\- \[x\] \*\*AC-" "$spec_file" 2>/dev/null) || completed_acs=0
|
|
154
|
+
total_acs="${total_acs:-0}"
|
|
155
|
+
completed_acs="${completed_acs:-0}"
|
|
156
|
+
fi
|
|
157
|
+
if [[ "$total_acs" -eq 0 ]]; then
|
|
158
|
+
total_acs=$(jq -r '.acceptanceCriteria.total // 0' "$metadata_file" 2>/dev/null) || total_acs=0
|
|
159
|
+
completed_acs=$(jq -r '.acceptanceCriteria.satisfied // 0' "$metadata_file" 2>/dev/null) || completed_acs=0
|
|
160
|
+
total_acs="${total_acs:-0}"
|
|
161
|
+
completed_acs="${completed_acs:-0}"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
# Get last activity
|
|
165
|
+
last_activity=""
|
|
166
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
167
|
+
last_activity=$(stat -f "%Sm" -t "%Y-%m-%dT%H:%M:%SZ" "$metadata_file" 2>/dev/null || echo "")
|
|
168
|
+
else
|
|
169
|
+
last_activity=$(stat -c "%y" "$metadata_file" 2>/dev/null | sed 's/ /T/' | cut -d. -f1)Z || echo ""
|
|
170
|
+
fi
|
|
171
|
+
|
|
172
|
+
# Get mtimes for stale detection
|
|
173
|
+
meta_mtime=0
|
|
174
|
+
tasks_mtime=0
|
|
175
|
+
spec_mtime=0
|
|
176
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
177
|
+
[[ -f "$metadata_file" ]] && meta_mtime=$(stat -f "%m" "$metadata_file" 2>/dev/null || echo "0")
|
|
178
|
+
[[ -f "$tasks_file" ]] && tasks_mtime=$(stat -f "%m" "$tasks_file" 2>/dev/null || echo "0")
|
|
179
|
+
[[ -f "$spec_file" ]] && spec_mtime=$(stat -f "%m" "$spec_file" 2>/dev/null || echo "0")
|
|
180
|
+
else
|
|
181
|
+
[[ -f "$metadata_file" ]] && meta_mtime=$(stat -c "%Y" "$metadata_file" 2>/dev/null || echo "0")
|
|
182
|
+
[[ -f "$tasks_file" ]] && tasks_mtime=$(stat -c "%Y" "$tasks_file" 2>/dev/null || echo "0")
|
|
183
|
+
[[ -f "$spec_file" ]] && spec_mtime=$(stat -c "%Y" "$spec_file" 2>/dev/null || echo "0")
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Acquire lock for update
|
|
187
|
+
acquire_lock
|
|
188
|
+
|
|
189
|
+
# Get old values for delta update
|
|
190
|
+
old_status=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].status // ""' "$CACHE_FILE" 2>/dev/null)
|
|
191
|
+
old_type=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].type // ""' "$CACHE_FILE" 2>/dev/null)
|
|
192
|
+
old_priority=$(jq -r --arg id "$INCREMENT_ID" '.increments[$id].priority // ""' "$CACHE_FILE" 2>/dev/null)
|
|
193
|
+
is_new=false
|
|
194
|
+
if [[ -z "$old_status" ]]; then
|
|
195
|
+
is_new=true
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# Build the increment update
|
|
199
|
+
increment_json=$(jq -n \
|
|
200
|
+
--arg status "$status" \
|
|
201
|
+
--arg type "$type" \
|
|
202
|
+
--arg priority "$priority" \
|
|
203
|
+
--arg title "$title" \
|
|
204
|
+
--arg project "$project" \
|
|
205
|
+
--argjson total_tasks "$total_tasks" \
|
|
206
|
+
--argjson completed_tasks "$completed_tasks" \
|
|
207
|
+
--argjson total_acs "$total_acs" \
|
|
208
|
+
--argjson completed_acs "$completed_acs" \
|
|
209
|
+
--arg created_at "$created_at" \
|
|
210
|
+
--arg last_activity "$last_activity" \
|
|
211
|
+
--argjson user_stories "$user_stories" \
|
|
212
|
+
'{
|
|
213
|
+
status: $status,
|
|
214
|
+
type: $type,
|
|
215
|
+
priority: $priority,
|
|
216
|
+
title: $title,
|
|
217
|
+
project: $project,
|
|
218
|
+
tasks: { total: $total_tasks, completed: $completed_tasks },
|
|
219
|
+
acs: { total: $total_acs, completed: $completed_acs },
|
|
220
|
+
createdAt: $created_at,
|
|
221
|
+
lastActivity: $last_activity,
|
|
222
|
+
userStories: $user_stories
|
|
223
|
+
}')
|
|
224
|
+
|
|
225
|
+
# Build mtime update
|
|
226
|
+
mtime_json=$(jq -n \
|
|
227
|
+
--argjson meta "$meta_mtime" \
|
|
228
|
+
--argjson tasks "$tasks_mtime" \
|
|
229
|
+
--argjson spec "$spec_mtime" \
|
|
230
|
+
'{ metadata: $meta, tasks: $tasks, spec: $spec }')
|
|
231
|
+
|
|
232
|
+
# Apply incremental update
|
|
233
|
+
if [[ "$is_new" == "true" ]]; then
|
|
234
|
+
# New increment - add to cache and increment counters
|
|
235
|
+
jq --arg id "$INCREMENT_ID" \
|
|
236
|
+
--argjson inc "$increment_json" \
|
|
237
|
+
--argjson mtime "$mtime_json" \
|
|
238
|
+
--arg status "$status" \
|
|
239
|
+
--arg type "$type" \
|
|
240
|
+
--arg priority "$priority" '
|
|
241
|
+
.increments[$id] = $inc |
|
|
242
|
+
.mtimes[$id] = $mtime |
|
|
243
|
+
.summary.total += 1 |
|
|
244
|
+
.summary[$status] += 1 |
|
|
245
|
+
.summary.byType[$type] += 1 |
|
|
246
|
+
.summary.byPriority[$priority] += 1 |
|
|
247
|
+
.updatedAt = (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
248
|
+
' "$CACHE_FILE" > "$TEMP_FILE"
|
|
249
|
+
else
|
|
250
|
+
# Existing increment - update and adjust counters if status/type/priority changed
|
|
251
|
+
jq --arg id "$INCREMENT_ID" \
|
|
252
|
+
--argjson inc "$increment_json" \
|
|
253
|
+
--argjson mtime "$mtime_json" \
|
|
254
|
+
--arg old_status "$old_status" \
|
|
255
|
+
--arg new_status "$status" \
|
|
256
|
+
--arg old_type "$old_type" \
|
|
257
|
+
--arg new_type "$type" \
|
|
258
|
+
--arg old_priority "$old_priority" \
|
|
259
|
+
--arg new_priority "$priority" '
|
|
260
|
+
.increments[$id] = $inc |
|
|
261
|
+
.mtimes[$id] = $mtime |
|
|
262
|
+
(if $old_status != $new_status then
|
|
263
|
+
.summary[$old_status] -= 1 |
|
|
264
|
+
.summary[$new_status] += 1
|
|
265
|
+
else . end) |
|
|
266
|
+
(if $old_type != $new_type then
|
|
267
|
+
.summary.byType[$old_type] -= 1 |
|
|
268
|
+
.summary.byType[$new_type] += 1
|
|
269
|
+
else . end) |
|
|
270
|
+
(if $old_priority != $new_priority then
|
|
271
|
+
.summary.byPriority[$old_priority] -= 1 |
|
|
272
|
+
.summary.byPriority[$new_priority] += 1
|
|
273
|
+
else . end) |
|
|
274
|
+
.updatedAt = (now | strftime("%Y-%m-%dT%H:%M:%SZ"))
|
|
275
|
+
' "$CACHE_FILE" > "$TEMP_FILE"
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
# Atomic write
|
|
279
|
+
mv "$TEMP_FILE" "$CACHE_FILE"
|
|
280
|
+
|
|
281
|
+
# Success - no output for silent operation in hooks
|
|
@@ -211,43 +211,298 @@ jq '.sync.profiles | to_entries[] | select(.value.provider == "ado") | .value.co
|
|
|
211
211
|
ls -la .specweave/docs/internal/specs/*/ # If sub-folders exist (not FS-XXX) → 2-level
|
|
212
212
|
```
|
|
213
213
|
|
|
214
|
-
**Project/Board Selection (MANDATORY BEFORE STEP 4!):**
|
|
214
|
+
**Project/Board Selection - ULTRA-SMART LOGIC (MANDATORY BEFORE STEP 4!):**
|
|
215
215
|
|
|
216
|
-
|
|
217
|
-
- ASK user: "Which project should this increment sync to?"
|
|
218
|
-
- Options: List from `structureConfig.projects`
|
|
219
|
-
- Store selected `PROJECT_ID`
|
|
216
|
+
**⚠️ CORE PRINCIPLE: Each User Story belongs to exactly ONE project (1-level) or ONE project+board (2-level). An increment can contain USs spanning MULTIPLE projects/boards.**
|
|
220
217
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
### SMART SELECTION DECISION TREE
|
|
221
|
+
|
|
222
|
+
**RULE 1: NO QUESTION IF ONLY 1 OPTION**
|
|
223
|
+
```
|
|
224
|
+
IF 1-level AND only 1 project → AUTO-SELECT silently
|
|
225
|
+
IF 2-level AND only 1 project AND only 1 board → AUTO-SELECT silently
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
**RULE 2: KEYWORD-BASED AUTO-DETECTION**
|
|
229
|
+
|
|
230
|
+
Analyze feature description and US content for keywords:
|
|
231
|
+
|
|
232
|
+
**Project-Level Keywords (1-level and 2-level):**
|
|
233
|
+
```
|
|
234
|
+
Frontend (FE) keywords:
|
|
235
|
+
UI, form, button, page, component, React, Vue, Angular, Next.js,
|
|
236
|
+
CSS, style, responsive, chart, dashboard, view, modal, widget,
|
|
237
|
+
Tailwind, Material-UI, Recharts
|
|
238
|
+
|
|
239
|
+
Backend (BE) keywords:
|
|
240
|
+
API, endpoint, REST, GraphQL, database, query, migration, service,
|
|
241
|
+
controller, authentication, JWT, session, middleware, CRUD,
|
|
242
|
+
Redis, PostgreSQL, MongoDB, microservice
|
|
243
|
+
|
|
244
|
+
Mobile keywords:
|
|
245
|
+
mobile, iOS, Android, React Native, Flutter, Expo, app, native,
|
|
246
|
+
push notification, offline, AsyncStorage, screen, touch, gesture
|
|
247
|
+
|
|
248
|
+
Infrastructure (INFRA) keywords:
|
|
249
|
+
deploy, CI/CD, Docker, Kubernetes, terraform, monitoring,
|
|
250
|
+
logging, pipeline, AWS, Azure, GCP, nginx, Helm, ArgoCD
|
|
251
|
+
|
|
252
|
+
Shared (SHARED) keywords:
|
|
253
|
+
types, interfaces, utilities, validators, shared, common, library,
|
|
254
|
+
SDK, models, constants, helpers
|
|
255
|
+
```
|
|
226
256
|
|
|
227
|
-
**
|
|
257
|
+
**Board-Level Keywords (2-level structures only):**
|
|
228
258
|
```
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
259
|
+
When project has multiple boards, also match board-specific keywords:
|
|
260
|
+
|
|
261
|
+
analytics/reporting: analytics, metrics, KPI, dashboard, report, chart, graph
|
|
262
|
+
user-management: user, auth, login, registration, profile, permissions, roles
|
|
263
|
+
integrations: integration, webhook, API, third-party, sync, import, export
|
|
264
|
+
payments: payment, billing, subscription, invoice, stripe, checkout
|
|
265
|
+
notifications: notification, alert, email, SMS, push, messaging
|
|
266
|
+
devops/platform: deploy, infrastructure, monitoring, CI/CD, pipeline
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
**RULE 3: CONFIDENCE CALCULATION FORMULA**
|
|
270
|
+
```
|
|
271
|
+
confidence = (matched_keywords / total_feature_keywords) × 100
|
|
272
|
+
|
|
273
|
+
Example: "Add React login form with JWT authentication"
|
|
274
|
+
Keywords found: React (FE), login (FE), form (FE), JWT (BE), authentication (BE)
|
|
275
|
+
FE matches: 3, BE matches: 2
|
|
276
|
+
FE confidence: 3/5 = 60%
|
|
277
|
+
BE confidence: 2/5 = 40%
|
|
278
|
+
→ Primary: FE (60%), Secondary: BE (40%)
|
|
279
|
+
→ SUGGEST: "Frontend (60%), but also touches Backend (40%)"
|
|
280
|
+
|
|
281
|
+
If multiple projects have similar confidence (within 15%):
|
|
282
|
+
→ Treat as MULTI-PROJECT feature
|
|
283
|
+
→ Auto-split USs by detected keywords
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**RULE 4: CONFIDENCE-BASED DECISION**
|
|
287
|
+
```
|
|
288
|
+
>80% single project → AUTO-SELECT with notification (no question)
|
|
289
|
+
50-80% single project → SUGGEST with quick confirm option
|
|
290
|
+
Multiple projects within 15% → AUTO-SPLIT across projects
|
|
291
|
+
<50% OR ambiguous → ASK user with all options
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**RULE 5: FALLBACK TO DEFAULTS**
|
|
295
|
+
```
|
|
296
|
+
IF US has explicit **Project**: field → USE IT
|
|
297
|
+
ELSE IF frontmatter has default_project → USE default_project
|
|
298
|
+
ELSE → ASK user (should not happen if flow followed correctly)
|
|
299
|
+
|
|
300
|
+
Same logic applies to **Board**: and default_board for 2-level
|
|
233
301
|
```
|
|
234
302
|
|
|
235
|
-
|
|
303
|
+
---
|
|
236
304
|
|
|
305
|
+
### DECISION FLOWCHART
|
|
306
|
+
|
|
307
|
+
```
|
|
308
|
+
START
|
|
309
|
+
│
|
|
310
|
+
▼
|
|
311
|
+
┌─────────────────────────────────────┐
|
|
312
|
+
│ 1. Detect structure level (1 or 2) │
|
|
313
|
+
│ 2. Count available projects/boards │
|
|
314
|
+
└─────────────────────────────────────┘
|
|
315
|
+
│
|
|
316
|
+
▼
|
|
317
|
+
┌─────────────────────────────────────┐
|
|
318
|
+
│ ONLY 1 PROJECT? │
|
|
319
|
+
│ (1-level: 1 project) │
|
|
320
|
+
│ (2-level: 1 project + 1 board) │
|
|
321
|
+
└─────────────────────────────────────┘
|
|
322
|
+
│
|
|
323
|
+
├── YES ──► AUTO-SELECT SILENTLY
|
|
324
|
+
│ Output: "✅ Project: {name} (auto-selected)"
|
|
325
|
+
│ NO QUESTION ASKED
|
|
326
|
+
│
|
|
327
|
+
▼ NO
|
|
328
|
+
┌─────────────────────────────────────┐
|
|
329
|
+
│ ANALYZE KEYWORDS in feature desc │
|
|
330
|
+
│ Calculate confidence per project │
|
|
331
|
+
└─────────────────────────────────────┘
|
|
332
|
+
│
|
|
333
|
+
├── HIGH CONFIDENCE (>80% single) ──► AUTO-SELECT + NOTIFY
|
|
334
|
+
│ Output: "✅ Detected: {project} (keywords: form, React)"
|
|
335
|
+
│
|
|
336
|
+
├── MULTI-PROJECT (within 15%) ──► AUTO-SPLIT USs
|
|
337
|
+
│ Output: "🔀 Multi-project detected:
|
|
338
|
+
│ • US-001 (Login UI) → web-app (60%)
|
|
339
|
+
│ • US-002 (Auth API) → api-service (55%)
|
|
340
|
+
│ Proceed? (Y/n)"
|
|
341
|
+
│
|
|
342
|
+
├── MEDIUM CONFIDENCE (50-80%) ──► SUGGEST + CONFIRM
|
|
343
|
+
│ Output: "📍 Suggested: {project}. Confirm? (Y/n)"
|
|
344
|
+
│
|
|
345
|
+
▼ LOW CONFIDENCE (<50%)
|
|
346
|
+
┌─────────────────────────────────────┐
|
|
347
|
+
│ ASK USER with ALL options listed │
|
|
348
|
+
│ multiSelect: true │
|
|
349
|
+
│ Show complete list (never truncate)│
|
|
350
|
+
└─────────────────────────────────────┘
|
|
237
351
|
```
|
|
238
|
-
🔍 Detected 2-level structure (ADO area path mapping)
|
|
239
|
-
Available projects: acme-corp
|
|
240
352
|
|
|
241
|
-
|
|
242
|
-
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### PER-USER-STORY ASSIGNMENT MODEL
|
|
356
|
+
|
|
357
|
+
**CRITICAL: Assignment is at USER STORY level, not increment level!**
|
|
358
|
+
|
|
359
|
+
Each US in spec.md has its own project (and board for 2-level):
|
|
360
|
+
|
|
361
|
+
```markdown
|
|
362
|
+
## User Stories
|
|
363
|
+
|
|
364
|
+
### US-001: Login Form UI
|
|
365
|
+
**Project**: web-app
|
|
366
|
+
**Board**: frontend <!-- 2-level only -->
|
|
367
|
+
**As a** user...
|
|
243
368
|
|
|
244
|
-
|
|
245
|
-
|
|
369
|
+
### US-002: Auth API Endpoints
|
|
370
|
+
**Project**: api-service
|
|
371
|
+
**Board**: backend <!-- 2-level only -->
|
|
372
|
+
**As a** developer...
|
|
246
373
|
|
|
247
|
-
|
|
374
|
+
### US-003: Mobile Login Screen
|
|
375
|
+
**Project**: mobile-app
|
|
376
|
+
**Board**: mobile-team <!-- 2-level only -->
|
|
377
|
+
**As a** mobile user...
|
|
248
378
|
```
|
|
249
379
|
|
|
250
|
-
**
|
|
380
|
+
**User can manually change project/board per US at any time by editing spec.md!**
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### EXAMPLE SCENARIOS
|
|
385
|
+
|
|
386
|
+
**Scenario 1: Single Project (NO QUESTION)**
|
|
387
|
+
```
|
|
388
|
+
Config: 1 project (my-app)
|
|
389
|
+
Feature: "Add user authentication"
|
|
390
|
+
|
|
391
|
+
→ AUTO-SELECT: my-app
|
|
392
|
+
→ Output: "✅ Project: my-app (single project - auto-selected)"
|
|
393
|
+
→ NO question asked
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
**Scenario 2: Multiple Projects, Clear Keywords (AUTO-DETECT)**
|
|
397
|
+
```
|
|
398
|
+
Config: 3 projects (web-app, api-service, mobile-app)
|
|
399
|
+
Feature: "Add React dashboard with charts"
|
|
400
|
+
|
|
401
|
+
→ Keyword analysis: "React" (FE), "dashboard" (FE), "charts" (FE)
|
|
402
|
+
→ Confidence: 95% → web-app
|
|
403
|
+
→ Output: "✅ Detected project: web-app (keywords: React, dashboard, charts)"
|
|
404
|
+
→ NO question asked (high confidence)
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**Scenario 3: Multiple Projects, Multi-Area Feature (SMART SPLIT)**
|
|
408
|
+
```
|
|
409
|
+
Config: 3 projects (web-app, api-service, shared-lib)
|
|
410
|
+
Feature: "User authentication with JWT"
|
|
411
|
+
|
|
412
|
+
→ Analyze: This spans FE (login form) + BE (auth API) + possibly shared (types)
|
|
413
|
+
→ Output:
|
|
414
|
+
"🔍 This feature likely spans multiple projects:
|
|
415
|
+
|
|
416
|
+
Based on 'user authentication with JWT', I'll create:
|
|
417
|
+
• US-001: Login/Register UI → web-app (keywords: UI, form)
|
|
418
|
+
• US-002: Auth API endpoints → api-service (keywords: API, JWT)
|
|
419
|
+
• US-003: Auth types/validators → shared-lib (keywords: types, shared)
|
|
420
|
+
|
|
421
|
+
✅ Proceed with this assignment? (Y/n)
|
|
422
|
+
💡 You can modify project per US in spec.md anytime"
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
**Scenario 4: 2-Level, Single Project, Auto-Detect Board**
|
|
426
|
+
```
|
|
427
|
+
Config: 1 project (enterprise-corp), 5 boards (analytics, frontend, backend, mobile, devops)
|
|
428
|
+
Feature: "Add reporting dashboard"
|
|
429
|
+
|
|
430
|
+
→ Project: AUTO-SELECT enterprise-corp (only option)
|
|
431
|
+
→ Board keywords: "reporting" → analytics, "dashboard" → frontend
|
|
432
|
+
→ Confidence: 70% analytics, 60% frontend
|
|
433
|
+
→ Output:
|
|
434
|
+
"✅ Project: enterprise-corp (auto-selected)
|
|
435
|
+
📍 Suggested board: analytics (keyword: reporting)
|
|
436
|
+
|
|
437
|
+
Confirm or select different board:
|
|
438
|
+
1. analytics (suggested)
|
|
439
|
+
2. frontend
|
|
440
|
+
3. backend
|
|
441
|
+
4. mobile
|
|
442
|
+
5. devops"
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Scenario 5: Completely Ambiguous (ASK WITH ALL OPTIONS)**
|
|
446
|
+
```
|
|
447
|
+
Config: 4 projects (proj-a, proj-b, proj-c, proj-d)
|
|
448
|
+
Feature: "Improve system performance"
|
|
449
|
+
|
|
450
|
+
→ Keyword analysis: No clear project match
|
|
451
|
+
→ Output:
|
|
452
|
+
"❓ Which project(s) should this increment target?
|
|
453
|
+
|
|
454
|
+
Available projects:
|
|
455
|
+
• proj-a - E-commerce frontend
|
|
456
|
+
• proj-b - Order processing API
|
|
457
|
+
• proj-c - Mobile shopping app
|
|
458
|
+
• proj-d - Infrastructure/DevOps
|
|
459
|
+
|
|
460
|
+
Select one or more (comma-separated, e.g., '1,2' or 'proj-a,proj-b'):"
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
### VALIDATION RULES
|
|
466
|
+
|
|
467
|
+
```
|
|
468
|
+
❌ FORBIDDEN: Asking project question when only 1 project exists
|
|
469
|
+
❌ FORBIDDEN: Asking board question when only 1 board exists in project
|
|
470
|
+
❌ FORBIDDEN: Hiding options behind "Let me see all" - ALWAYS show complete list
|
|
471
|
+
❌ FORBIDDEN: Truncating project/board lists
|
|
472
|
+
❌ FORBIDDEN: Assigning ALL USs to same project when content clearly differs
|
|
473
|
+
✅ REQUIRED: Auto-select when only 1 option available
|
|
474
|
+
✅ REQUIRED: Use keyword matching before asking user
|
|
475
|
+
✅ REQUIRED: Each US has explicit project (and board for 2-level) assignment
|
|
476
|
+
✅ REQUIRED: Allow user to modify assignments per-US in spec.md
|
|
477
|
+
✅ REQUIRED: When asking, show ALL options with descriptions
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
---
|
|
481
|
+
|
|
482
|
+
### SPEC.MD YAML FORMAT
|
|
483
|
+
|
|
484
|
+
**1-Level Structure:**
|
|
485
|
+
```yaml
|
|
486
|
+
---
|
|
487
|
+
increment: 0045-user-auth
|
|
488
|
+
title: "User Authentication"
|
|
489
|
+
# Optional default (used if US doesn't specify)
|
|
490
|
+
default_project: web-app
|
|
491
|
+
---
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**2-Level Structure:**
|
|
495
|
+
```yaml
|
|
496
|
+
---
|
|
497
|
+
increment: 0045-user-auth
|
|
498
|
+
title: "User Authentication"
|
|
499
|
+
# Optional defaults (used if US doesn't specify)
|
|
500
|
+
default_project: enterprise-corp
|
|
501
|
+
default_board: backend
|
|
502
|
+
---
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
**Store detected/selected values for use in STEP 4!**
|
|
251
506
|
|
|
252
507
|
---
|
|
253
508
|
|
|
@@ -445,6 +700,60 @@ const metadata = {
|
|
|
445
700
|
|
|
446
701
|
**DO NOT invoke Task() tool to spawn agents from this skill!**
|
|
447
702
|
|
|
703
|
+
### STEP 9: Trigger Living Docs & External Tool Sync (v0.32.2+)
|
|
704
|
+
|
|
705
|
+
**🔄 CRITICAL: After increment files are created, trigger sync to living docs AND external tools!**
|
|
706
|
+
|
|
707
|
+
This step uses the existing sync infrastructure to:
|
|
708
|
+
1. Create living docs (FS-XXX folder with FEATURE.md and us-*.md files)
|
|
709
|
+
2. Check permissions (`canUpsertInternalItems`) from `.specweave/config.json`
|
|
710
|
+
3. Sync to external tools (GitHub/JIRA/ADO) if configured and permitted
|
|
711
|
+
|
|
712
|
+
**Run the sync-specs command:**
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
/specweave:sync-specs {increment-id}
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
**Expected output:**
|
|
719
|
+
|
|
720
|
+
```
|
|
721
|
+
🔄 Syncing increment to living docs...
|
|
722
|
+
✅ Living docs synced: FS-021
|
|
723
|
+
Created: 4 files (FEATURE.md, us-001.md, us-002.md, us-003.md)
|
|
724
|
+
|
|
725
|
+
📡 Syncing to external tools: github
|
|
726
|
+
📋 Permissions: upsert=true, update=true, status=true
|
|
727
|
+
✅ Synced to GitHub: 0 updated, 3 created
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
**Permission handling (v0.32.2+):**
|
|
731
|
+
|
|
732
|
+
If `canUpsertInternalItems: false` in config:
|
|
733
|
+
```
|
|
734
|
+
⚠️ Skipping external sync - canUpsertInternalItems is disabled
|
|
735
|
+
💡 Enable in .specweave/config.json: sync.settings.canUpsertInternalItems: true
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
**Error handling:**
|
|
739
|
+
|
|
740
|
+
External tool sync failures are NON-BLOCKING:
|
|
741
|
+
```
|
|
742
|
+
⚠️ External sync failed: Rate limit exceeded
|
|
743
|
+
💡 Run /specweave:sync-specs {increment-id} to retry
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
**Output after sync:**
|
|
747
|
+
|
|
748
|
+
```
|
|
749
|
+
✅ Increment created and synced!
|
|
750
|
+
|
|
751
|
+
Next steps:
|
|
752
|
+
1. Review the increment plan and docs
|
|
753
|
+
2. Start implementation: /specweave:do {increment-id}
|
|
754
|
+
3. Monitor status: /specweave:status {increment-id}
|
|
755
|
+
```
|
|
756
|
+
|
|
448
757
|
---
|
|
449
758
|
|
|
450
759
|
## Model Selection for Tasks
|