@nlaprell/shipit 1.0.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/.cursor/commands/create_intent_from_issue.md +28 -0
- package/.cursor/commands/create_pr.md +28 -0
- package/.cursor/commands/dashboard.md +39 -0
- package/.cursor/commands/deploy.md +152 -0
- package/.cursor/commands/drift_check.md +36 -0
- package/.cursor/commands/fix.md +39 -0
- package/.cursor/commands/generate_release_plan.md +31 -0
- package/.cursor/commands/generate_roadmap.md +38 -0
- package/.cursor/commands/help.md +37 -0
- package/.cursor/commands/init_project.md +26 -0
- package/.cursor/commands/kill.md +72 -0
- package/.cursor/commands/new_intent.md +68 -0
- package/.cursor/commands/pr.md +77 -0
- package/.cursor/commands/revert-plan.md +58 -0
- package/.cursor/commands/risk.md +64 -0
- package/.cursor/commands/rollback.md +43 -0
- package/.cursor/commands/scope_project.md +53 -0
- package/.cursor/commands/ship.md +345 -0
- package/.cursor/commands/status.md +71 -0
- package/.cursor/commands/suggest.md +44 -0
- package/.cursor/commands/test_shipit.md +197 -0
- package/.cursor/commands/verify.md +50 -0
- package/.cursor/rules/architect.mdc +84 -0
- package/.cursor/rules/assumption-extractor.mdc +95 -0
- package/.cursor/rules/docs.mdc +66 -0
- package/.cursor/rules/implementer.mdc +112 -0
- package/.cursor/rules/pm.mdc +136 -0
- package/.cursor/rules/qa.mdc +97 -0
- package/.cursor/rules/security.mdc +90 -0
- package/.cursor/rules/steward.mdc +99 -0
- package/.cursor/rules/test-runner.mdc +196 -0
- package/AGENTS.md +121 -0
- package/README.md +264 -0
- package/_system/architecture/CANON.md +159 -0
- package/_system/architecture/invariants.yml +87 -0
- package/_system/architecture/project-schema.json +98 -0
- package/_system/architecture/workflow-state-layout.md +68 -0
- package/_system/artifacts/SYSTEM_STATE.md +43 -0
- package/_system/artifacts/confidence-calibration.json +16 -0
- package/_system/artifacts/dependencies.md +46 -0
- package/_system/artifacts/framework-files-manifest.json +179 -0
- package/_system/artifacts/usage.json +1 -0
- package/_system/behaviors/DO_RELEASE.md +371 -0
- package/_system/behaviors/DO_RELEASE_AI.md +329 -0
- package/_system/behaviors/PREPARE_RELEASE.md +373 -0
- package/_system/behaviors/PREPARE_RELEASE_AI.md +234 -0
- package/_system/behaviors/WORK_ROOT_PLATFORM_ISSUES.md +140 -0
- package/_system/behaviors/WORK_TEST_PLAN_ISSUES.md +380 -0
- package/_system/do-not-repeat/abandoned-designs.md +18 -0
- package/_system/do-not-repeat/bad-patterns.md +19 -0
- package/_system/do-not-repeat/failed-experiments.md +18 -0
- package/_system/do-not-repeat/rejected-libraries.md +19 -0
- package/_system/drift/baselines.md +49 -0
- package/_system/drift/metrics.md +33 -0
- package/_system/golden-data/.gitkeep +0 -0
- package/_system/golden-data/README.md +47 -0
- package/_system/reports/mutation/mutation.html +492 -0
- package/_system/security/audit-allowlist.json +4 -0
- package/bin/create-shipit-app +29 -0
- package/bin/shipit +183 -0
- package/cli/src/commands/check.js +82 -0
- package/cli/src/commands/create.js +195 -0
- package/cli/src/commands/init.js +267 -0
- package/cli/src/commands/upgrade.js +196 -0
- package/cli/src/utils/config.js +27 -0
- package/cli/src/utils/file-copy.js +144 -0
- package/cli/src/utils/gitignore-merge.js +44 -0
- package/cli/src/utils/manifest.js +105 -0
- package/cli/src/utils/package-json-merge.js +163 -0
- package/cli/src/utils/project-json-merge.js +57 -0
- package/cli/src/utils/prompts.js +30 -0
- package/cli/src/utils/stack-detection.js +56 -0
- package/cli/src/utils/stack-files.js +364 -0
- package/cli/src/utils/upgrade-backup.js +159 -0
- package/cli/src/utils/version.js +64 -0
- package/dashboard-app/README.md +73 -0
- package/dashboard-app/eslint.config.js +23 -0
- package/dashboard-app/index.html +13 -0
- package/dashboard-app/package.json +30 -0
- package/dashboard-app/pnpm-lock.yaml +2721 -0
- package/dashboard-app/public/dashboard.json +66 -0
- package/dashboard-app/public/vite.svg +1 -0
- package/dashboard-app/src/App.css +141 -0
- package/dashboard-app/src/App.tsx +155 -0
- package/dashboard-app/src/assets/react.svg +1 -0
- package/dashboard-app/src/index.css +68 -0
- package/dashboard-app/src/main.tsx +10 -0
- package/dashboard-app/tsconfig.app.json +28 -0
- package/dashboard-app/tsconfig.json +4 -0
- package/dashboard-app/tsconfig.node.json +26 -0
- package/dashboard-app/vite.config.ts +7 -0
- package/package.json +116 -0
- package/scripts/README.md +70 -0
- package/scripts/audit-check.sh +125 -0
- package/scripts/calibration-report.sh +198 -0
- package/scripts/check-readiness.sh +155 -0
- package/scripts/collect-metrics.sh +116 -0
- package/scripts/command-manifest.yml +131 -0
- package/scripts/create-test-plan-issue.sh +110 -0
- package/scripts/dashboard-start.sh +16 -0
- package/scripts/deploy.sh +170 -0
- package/scripts/drift-check.sh +93 -0
- package/scripts/execute-rollback.sh +177 -0
- package/scripts/export-dashboard-json.js +208 -0
- package/scripts/fix-intents.sh +239 -0
- package/scripts/generate-dashboard.sh +136 -0
- package/scripts/generate-docs.sh +279 -0
- package/scripts/generate-project-context.sh +142 -0
- package/scripts/generate-release-plan.sh +443 -0
- package/scripts/generate-roadmap.sh +189 -0
- package/scripts/generate-system-state.sh +95 -0
- package/scripts/gh/create-intent-from-issue.sh +82 -0
- package/scripts/gh/create-issue-from-intent.sh +59 -0
- package/scripts/gh/create-pr.sh +41 -0
- package/scripts/gh/link-issue.sh +44 -0
- package/scripts/gh/on-ship-update-issue.sh +42 -0
- package/scripts/headless/README.md +8 -0
- package/scripts/headless/call-llm.js +109 -0
- package/scripts/headless/run-phase.sh +99 -0
- package/scripts/help.sh +271 -0
- package/scripts/init-project.sh +976 -0
- package/scripts/kill-intent.sh +125 -0
- package/scripts/lib/common.sh +29 -0
- package/scripts/lib/intent.sh +61 -0
- package/scripts/lib/progress.sh +57 -0
- package/scripts/lib/suggest-next.sh +131 -0
- package/scripts/lib/validate-intents.sh +240 -0
- package/scripts/lib/verify-outputs.sh +55 -0
- package/scripts/lib/workflow_state.sh +201 -0
- package/scripts/new-intent.sh +271 -0
- package/scripts/publish-npm.sh +28 -0
- package/scripts/scope-project.sh +380 -0
- package/scripts/setup-worktrees.sh +125 -0
- package/scripts/status.sh +278 -0
- package/scripts/suggest.sh +173 -0
- package/scripts/test-headless.sh +47 -0
- package/scripts/test-shipit.sh +52 -0
- package/scripts/test-workflow-state.sh +49 -0
- package/scripts/usage-report.sh +47 -0
- package/scripts/usage.sh +58 -0
- package/scripts/validate-cursor.sh +151 -0
- package/scripts/validate-project.sh +71 -0
- package/scripts/validate-vscode.sh +146 -0
- package/scripts/verify.sh +153 -0
- package/scripts/workflow-orchestrator.sh +97 -0
- package/scripts/workflow-templates/01_analysis.md.tpl +25 -0
- package/scripts/workflow-templates/02_plan.md.tpl +30 -0
- package/scripts/workflow-templates/03_implementation.md.tpl +25 -0
- package/scripts/workflow-templates/04_verification.md.tpl +29 -0
- package/scripts/workflow-templates/05_release_notes.md.tpl +16 -0
- package/scripts/workflow-templates/05_verification_legacy.md.tpl +6 -0
- package/scripts/workflow-templates/active.md.tpl +18 -0
- package/scripts/workflow-templates/phases.yml +39 -0
- package/stryker.conf.json +8 -0
- package/work/intent/templates/api-endpoint.md +124 -0
- package/work/intent/templates/bugfix.md +116 -0
- package/work/intent/templates/frontend-feature.md +115 -0
- package/work/intent/templates/generic.md +122 -0
- package/work/intent/templates/infra-change.md +121 -0
- package/work/intent/templates/refactor.md +116 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# AI-Assisted Project Scoping Script
|
|
4
|
+
# Breaks down project into features and generates initial intents
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
error_exit() {
|
|
9
|
+
echo "ERROR: $1" >&2
|
|
10
|
+
exit "${2:-1}"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
# Colors
|
|
14
|
+
GREEN='\033[0;32m'
|
|
15
|
+
YELLOW='\033[1;33m'
|
|
16
|
+
BLUE='\033[0;34m'
|
|
17
|
+
CYAN='\033[0;36m'
|
|
18
|
+
NC='\033[0m'
|
|
19
|
+
|
|
20
|
+
# Check if project.json exists
|
|
21
|
+
if [ ! -f "project.json" ]; then
|
|
22
|
+
error_exit "project.json not found. Run /init-project first." 1
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# Get project description
|
|
26
|
+
PROJECT_DESC="${1:-}"
|
|
27
|
+
if [ -z "$PROJECT_DESC" ]; then
|
|
28
|
+
read -p "Project description: " PROJECT_DESC
|
|
29
|
+
if [ -z "$PROJECT_DESC" ]; then
|
|
30
|
+
error_exit "Project description is required" 1
|
|
31
|
+
fi
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo -e "${BLUE}Scoping project: $PROJECT_DESC${NC}"
|
|
35
|
+
echo ""
|
|
36
|
+
|
|
37
|
+
# Read project metadata (prefer jq, fallback to node; avoid hard dependency on jq)
|
|
38
|
+
read_project_json_field() {
|
|
39
|
+
local expr="$1"
|
|
40
|
+
local fallback="$2"
|
|
41
|
+
|
|
42
|
+
if command -v jq >/dev/null 2>&1; then
|
|
43
|
+
local v
|
|
44
|
+
v="$(jq -r "$expr" project.json 2>/dev/null || true)"
|
|
45
|
+
if [ -z "$v" ] || [ "$v" = "null" ]; then
|
|
46
|
+
echo "$fallback"
|
|
47
|
+
else
|
|
48
|
+
echo "$v"
|
|
49
|
+
fi
|
|
50
|
+
return 0
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if command -v node >/dev/null 2>&1; then
|
|
54
|
+
node -e "
|
|
55
|
+
const fs = require('fs');
|
|
56
|
+
try {
|
|
57
|
+
const p = JSON.parse(fs.readFileSync('project.json','utf8'));
|
|
58
|
+
const v = (function(){
|
|
59
|
+
// supported expr values: .name, .techStack, .highRiskDomains
|
|
60
|
+
if ('$expr' === '.name') return p.name;
|
|
61
|
+
if ('$expr' === '.techStack') return p.techStack;
|
|
62
|
+
if ('$expr' === '.highRiskDomains | join(\", \")') return Array.isArray(p.highRiskDomains) ? p.highRiskDomains.join(', ') : undefined;
|
|
63
|
+
return undefined;
|
|
64
|
+
})();
|
|
65
|
+
process.stdout.write((v === undefined || v === null || v === '') ? '$fallback' : String(v));
|
|
66
|
+
} catch {
|
|
67
|
+
process.stdout.write('$fallback');
|
|
68
|
+
}
|
|
69
|
+
" 2>/dev/null || echo "$fallback"
|
|
70
|
+
return 0
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
echo "$fallback"
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
PROJECT_NAME="$(read_project_json_field '.name' 'project')"
|
|
77
|
+
TECH_STACK="$(read_project_json_field '.techStack' 'typescript-nodejs')"
|
|
78
|
+
HIGH_RISK="$(read_project_json_field '.highRiskDomains | join(", ")' 'none')"
|
|
79
|
+
|
|
80
|
+
echo -e "${YELLOW}Project Context:${NC}"
|
|
81
|
+
echo " Name: $PROJECT_NAME"
|
|
82
|
+
echo " Tech Stack: $TECH_STACK"
|
|
83
|
+
echo " High-Risk Domains: $HIGH_RISK"
|
|
84
|
+
echo ""
|
|
85
|
+
|
|
86
|
+
# Interactive follow-up questions with defaults (bash 3.2 compatible: no associative arrays)
|
|
87
|
+
FOLLOW_UP_QUESTIONS=(
|
|
88
|
+
"Is a UI required (API-only, CLI, Web)?"
|
|
89
|
+
"What persistence should be used (JSON file, SQLite, etc.)?"
|
|
90
|
+
"Single-user or multi-user?"
|
|
91
|
+
"Authentication required (none, API key, full auth)?"
|
|
92
|
+
"Any non-functional requirements (performance, scaling, etc.)?"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
FOLLOW_UP_DEFAULTS=(
|
|
96
|
+
"Web"
|
|
97
|
+
"JSON file"
|
|
98
|
+
"Single-user"
|
|
99
|
+
"none"
|
|
100
|
+
"Fast for typical use cases"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
FOLLOW_UP_ANSWERS=()
|
|
104
|
+
|
|
105
|
+
# Batch prompt: show all questions with defaults
|
|
106
|
+
echo -e "${YELLOW}Follow-Up Questions (required):${NC}"
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Review and edit answers below. Press Enter to accept default, or type new answer."
|
|
109
|
+
echo ""
|
|
110
|
+
|
|
111
|
+
for i in "${!FOLLOW_UP_QUESTIONS[@]}"; do
|
|
112
|
+
question="${FOLLOW_UP_QUESTIONS[$i]}"
|
|
113
|
+
default="${FOLLOW_UP_DEFAULTS[$i]}"
|
|
114
|
+
|
|
115
|
+
# Show question with default
|
|
116
|
+
echo -e "${CYAN}Q$((i + 1)):${NC} $question"
|
|
117
|
+
echo -e " ${YELLOW}Default:${NC} $default"
|
|
118
|
+
read -p " Your answer [$default]: " answer
|
|
119
|
+
|
|
120
|
+
# Use default if empty, otherwise use provided answer
|
|
121
|
+
if [ -z "$answer" ]; then
|
|
122
|
+
answer="$default"
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
FOLLOW_UP_ANSWERS+=("$answer")
|
|
126
|
+
echo ""
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
echo -e "${YELLOW}Review your answers:${NC}"
|
|
130
|
+
for i in "${!FOLLOW_UP_QUESTIONS[@]}"; do
|
|
131
|
+
echo " Q$((i + 1)): ${FOLLOW_UP_QUESTIONS[$i]}"
|
|
132
|
+
echo " A: ${FOLLOW_UP_ANSWERS[$i]}"
|
|
133
|
+
done
|
|
134
|
+
echo ""
|
|
135
|
+
read -p "Confirm answers? (y/n) [y]: " confirm
|
|
136
|
+
confirm="${confirm:-y}"
|
|
137
|
+
|
|
138
|
+
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
|
|
139
|
+
error_exit "Scoping cancelled. Re-run /scope-project to start over." 1
|
|
140
|
+
fi
|
|
141
|
+
echo ""
|
|
142
|
+
|
|
143
|
+
# Open questions (optional)
|
|
144
|
+
OPEN_QUESTIONS=()
|
|
145
|
+
echo -e "${YELLOW}Open Questions (optional, type 'done' when finished):${NC}"
|
|
146
|
+
while IFS= read -r line; do
|
|
147
|
+
[ "$line" = "done" ] && break
|
|
148
|
+
[ -z "$line" ] && continue
|
|
149
|
+
OPEN_QUESTIONS+=("$line")
|
|
150
|
+
done
|
|
151
|
+
echo ""
|
|
152
|
+
|
|
153
|
+
# Feature candidates (required)
|
|
154
|
+
FEATURES=()
|
|
155
|
+
echo -e "${YELLOW}Feature Candidates (required, one per line, type 'done' when finished):${NC}"
|
|
156
|
+
while IFS= read -r line; do
|
|
157
|
+
[ "$line" = "done" ] && break
|
|
158
|
+
[ -z "$line" ] && continue
|
|
159
|
+
FEATURES+=("$line")
|
|
160
|
+
done
|
|
161
|
+
|
|
162
|
+
if [ ${#FEATURES[@]} -eq 0 ]; then
|
|
163
|
+
error_exit "At least one feature candidate is required." 1
|
|
164
|
+
fi
|
|
165
|
+
echo ""
|
|
166
|
+
|
|
167
|
+
# Intent selection
|
|
168
|
+
echo -e "${YELLOW}Select features to generate intents:${NC}"
|
|
169
|
+
for i in "${!FEATURES[@]}"; do
|
|
170
|
+
idx=$((i + 1))
|
|
171
|
+
echo " $idx) ${FEATURES[$i]}"
|
|
172
|
+
done
|
|
173
|
+
read -p "Enter selection (all, none, or comma-separated numbers): " selection
|
|
174
|
+
|
|
175
|
+
SELECTED_FEATURES=()
|
|
176
|
+
case "$selection" in
|
|
177
|
+
all)
|
|
178
|
+
SELECTED_FEATURES=("${FEATURES[@]}")
|
|
179
|
+
;;
|
|
180
|
+
none)
|
|
181
|
+
SELECTED_FEATURES=()
|
|
182
|
+
;;
|
|
183
|
+
*)
|
|
184
|
+
IFS=',' read -r -a selected_indices <<< "$selection"
|
|
185
|
+
for raw_idx in "${selected_indices[@]}"; do
|
|
186
|
+
idx="$(echo "$raw_idx" | tr -d '[:space:]')"
|
|
187
|
+
if [[ "$idx" =~ ^[0-9]+$ ]] && [ "$idx" -ge 1 ] && [ "$idx" -le ${#FEATURES[@]} ]; then
|
|
188
|
+
SELECTED_FEATURES+=("${FEATURES[$((idx - 1))]}")
|
|
189
|
+
fi
|
|
190
|
+
done
|
|
191
|
+
;;
|
|
192
|
+
esac
|
|
193
|
+
|
|
194
|
+
# Create project-scope.md
|
|
195
|
+
SCOPE_FILE="project-scope.md"
|
|
196
|
+
{
|
|
197
|
+
echo "# Project Scope: $PROJECT_NAME"
|
|
198
|
+
echo ""
|
|
199
|
+
echo "**Generated:** $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
200
|
+
echo "**Description:** $PROJECT_DESC"
|
|
201
|
+
echo ""
|
|
202
|
+
echo "## Follow-Up Questions (with answers)"
|
|
203
|
+
echo ""
|
|
204
|
+
for i in "${!FOLLOW_UP_QUESTIONS[@]}"; do
|
|
205
|
+
echo "- Q: ${FOLLOW_UP_QUESTIONS[$i]}"
|
|
206
|
+
echo " A: ${FOLLOW_UP_ANSWERS[$i]}"
|
|
207
|
+
done
|
|
208
|
+
echo ""
|
|
209
|
+
echo "## Open Questions (unanswered)"
|
|
210
|
+
echo ""
|
|
211
|
+
if [ ${#OPEN_QUESTIONS[@]} -eq 0 ]; then
|
|
212
|
+
echo "(none)"
|
|
213
|
+
else
|
|
214
|
+
for q in "${OPEN_QUESTIONS[@]}"; do
|
|
215
|
+
echo "- $q"
|
|
216
|
+
done
|
|
217
|
+
fi
|
|
218
|
+
echo ""
|
|
219
|
+
echo "## Feature Candidates"
|
|
220
|
+
echo ""
|
|
221
|
+
for feature in "${FEATURES[@]}"; do
|
|
222
|
+
echo "- $feature"
|
|
223
|
+
done
|
|
224
|
+
echo ""
|
|
225
|
+
echo "## Intent Selection"
|
|
226
|
+
echo ""
|
|
227
|
+
if [ ${#SELECTED_FEATURES[@]} -eq 0 ]; then
|
|
228
|
+
echo "(none selected)"
|
|
229
|
+
else
|
|
230
|
+
for feature in "${SELECTED_FEATURES[@]}"; do
|
|
231
|
+
echo "- $feature"
|
|
232
|
+
done
|
|
233
|
+
fi
|
|
234
|
+
echo ""
|
|
235
|
+
echo "## Generated Intents"
|
|
236
|
+
echo ""
|
|
237
|
+
} > "$SCOPE_FILE" || error_exit "Failed to create project-scope.md"
|
|
238
|
+
|
|
239
|
+
echo -e "${GREEN}✓ Created $SCOPE_FILE${NC}"
|
|
240
|
+
|
|
241
|
+
# Create release plan stub if missing
|
|
242
|
+
RELEASE_DIR="work/release"
|
|
243
|
+
RELEASE_PLAN="$RELEASE_DIR/plan.md"
|
|
244
|
+
if [ ! -f "$RELEASE_PLAN" ]; then
|
|
245
|
+
mkdir -p "$RELEASE_DIR" || error_exit "Failed to create release directory"
|
|
246
|
+
cat > "$RELEASE_PLAN" << EOF || error_exit "Failed to create work/release/plan.md"
|
|
247
|
+
# Release Plan
|
|
248
|
+
|
|
249
|
+
**Generated:** $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
250
|
+
|
|
251
|
+
## Summary
|
|
252
|
+
|
|
253
|
+
- Total intents: 0
|
|
254
|
+
- Planned intents: 0
|
|
255
|
+
- Releases: 0
|
|
256
|
+
|
|
257
|
+
EOF
|
|
258
|
+
echo -e "${GREEN}✓ Created $RELEASE_PLAN${NC}"
|
|
259
|
+
fi
|
|
260
|
+
|
|
261
|
+
# Best-effort release plan generation if available
|
|
262
|
+
INTENT_BASE_DIR="work/intent"
|
|
263
|
+
INTENT_DIR="$INTENT_BASE_DIR/features"
|
|
264
|
+
TEMPLATE_FILE="$INTENT_BASE_DIR/_TEMPLATE.md"
|
|
265
|
+
|
|
266
|
+
if [ ${#SELECTED_FEATURES[@]} -gt 0 ]; then
|
|
267
|
+
if [ ! -f "$TEMPLATE_FILE" ]; then
|
|
268
|
+
error_exit "Template file not found: $TEMPLATE_FILE" 1
|
|
269
|
+
fi
|
|
270
|
+
mkdir -p "$INTENT_DIR" || error_exit "Failed to create intent directory: $INTENT_DIR"
|
|
271
|
+
|
|
272
|
+
LAST_INTENT=0
|
|
273
|
+
while IFS= read -r file; do
|
|
274
|
+
[ -e "$file" ] || continue
|
|
275
|
+
base="$(basename "$file")"
|
|
276
|
+
if [[ "$base" =~ ^F-([0-9]+)\.md$ ]]; then
|
|
277
|
+
num="${BASH_REMATCH[1]}"
|
|
278
|
+
if ((10#$num > LAST_INTENT)); then
|
|
279
|
+
LAST_INTENT=$((10#$num))
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
done < <(find "$INTENT_BASE_DIR" -type f -name 'F-*.md' 2>/dev/null)
|
|
283
|
+
NEXT_NUM=$((LAST_INTENT + 1))
|
|
284
|
+
|
|
285
|
+
GENERATED_INTENTS=()
|
|
286
|
+
for feature in "${SELECTED_FEATURES[@]}"; do
|
|
287
|
+
INTENT_ID="F-$(printf "%03d" $NEXT_NUM)"
|
|
288
|
+
NEXT_NUM=$((NEXT_NUM + 1))
|
|
289
|
+
|
|
290
|
+
read -p "Dependencies for $INTENT_ID (comma-separated or 'none'): " deps_input
|
|
291
|
+
deps_input="${deps_input:-none}"
|
|
292
|
+
DEP_LINES=()
|
|
293
|
+
if [ "$deps_input" != "none" ]; then
|
|
294
|
+
IFS=',' read -r -a dep_items <<< "$deps_input"
|
|
295
|
+
for dep in "${dep_items[@]}"; do
|
|
296
|
+
dep_trim="$(echo "$dep" | tr -d '[:space:]')"
|
|
297
|
+
[ -z "$dep_trim" ] && continue
|
|
298
|
+
DEP_LINES+=("- ${dep_trim}")
|
|
299
|
+
done
|
|
300
|
+
fi
|
|
301
|
+
if [ ${#DEP_LINES[@]} -eq 0 ]; then
|
|
302
|
+
DEP_LINES+=("- (none)")
|
|
303
|
+
fi
|
|
304
|
+
|
|
305
|
+
INTENT_FILE="$INTENT_DIR/$INTENT_ID.md"
|
|
306
|
+
TEMP_FILE="$(mktemp)"
|
|
307
|
+
MOTIVATION_FILE="$(mktemp)"
|
|
308
|
+
DEP_FILE="$(mktemp)"
|
|
309
|
+
|
|
310
|
+
sed -e "s/# F-###: Title/# $INTENT_ID: $feature/" \
|
|
311
|
+
-e "s/feature | bug | tech-debt/feature/" \
|
|
312
|
+
-e "s/planned | active | blocked | validating | shipped | killed/planned/" \
|
|
313
|
+
-e "s/p0 | p1 | p2 | p3/p2/" \
|
|
314
|
+
-e "s/s | m | l/m/" \
|
|
315
|
+
-e "s/R1 | R2 | R3 | R4/R2/" \
|
|
316
|
+
"$TEMPLATE_FILE" > "$TEMP_FILE" || error_exit "Failed to create intent template"
|
|
317
|
+
|
|
318
|
+
printf "%s\n" "- ${feature}" > "$MOTIVATION_FILE"
|
|
319
|
+
printf "%s\n" "${DEP_LINES[@]}" > "$DEP_FILE"
|
|
320
|
+
|
|
321
|
+
awk -v motivation_file="$MOTIVATION_FILE" -v deps_file="$DEP_FILE" '
|
|
322
|
+
$0 == "(Why it exists, 1–3 bullets)" {
|
|
323
|
+
while ((getline line < motivation_file) > 0) print line;
|
|
324
|
+
close(motivation_file);
|
|
325
|
+
next;
|
|
326
|
+
}
|
|
327
|
+
/^- \(Other intent IDs that must ship first\)$/ {
|
|
328
|
+
# Replace placeholder dependency lines with actual deps
|
|
329
|
+
# Ensure dependencies are written at column 0 (no leading whitespace)
|
|
330
|
+
while ((getline line < deps_file) > 0) {
|
|
331
|
+
# Remove any leading whitespace and ensure line starts with "- "
|
|
332
|
+
sub(/^[[:space:]]+/, "", line);
|
|
333
|
+
if (line !~ /^- /) {
|
|
334
|
+
line = "- " line;
|
|
335
|
+
}
|
|
336
|
+
print line;
|
|
337
|
+
}
|
|
338
|
+
close(deps_file);
|
|
339
|
+
# Skip remaining placeholder dependency lines
|
|
340
|
+
while (getline > 0) {
|
|
341
|
+
if (/^## / || /^$/) {
|
|
342
|
+
print;
|
|
343
|
+
break;
|
|
344
|
+
}
|
|
345
|
+
# Skip placeholder lines (lines starting with "- (")
|
|
346
|
+
if (!/^- \(/) {
|
|
347
|
+
print;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
next;
|
|
351
|
+
}
|
|
352
|
+
{ print }
|
|
353
|
+
' "$TEMP_FILE" > "$INTENT_FILE" || error_exit "Failed to create intent file"
|
|
354
|
+
|
|
355
|
+
rm -f "$TEMP_FILE" "$MOTIVATION_FILE" "$DEP_FILE"
|
|
356
|
+
|
|
357
|
+
GENERATED_INTENTS+=("$INTENT_ID")
|
|
358
|
+
done
|
|
359
|
+
|
|
360
|
+
{
|
|
361
|
+
echo ""
|
|
362
|
+
for id in "${GENERATED_INTENTS[@]}"; do
|
|
363
|
+
echo "- \`work/intent/features/${id}.md\`"
|
|
364
|
+
done
|
|
365
|
+
} >> "$SCOPE_FILE"
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
if [ -x "./scripts/generate-release-plan.sh" ]; then
|
|
369
|
+
./scripts/generate-release-plan.sh || echo "WARNING: release plan generation failed"
|
|
370
|
+
fi
|
|
371
|
+
|
|
372
|
+
if [ -x "./scripts/generate-roadmap.sh" ]; then
|
|
373
|
+
./scripts/generate-roadmap.sh || echo "WARNING: roadmap generation failed"
|
|
374
|
+
fi
|
|
375
|
+
# Show next-step suggestions
|
|
376
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
377
|
+
if [ -f "$SCRIPT_DIR/lib/suggest-next.sh" ]; then
|
|
378
|
+
source "$SCRIPT_DIR/lib/suggest-next.sh"
|
|
379
|
+
display_suggestions "scoping"
|
|
380
|
+
fi
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Setup Parallel Worktrees Script
|
|
4
|
+
# Creates isolated worktrees for parallel agent work
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
# Error handling
|
|
9
|
+
error_exit() {
|
|
10
|
+
echo "ERROR: $1" >&2
|
|
11
|
+
exit "${2:-1}"
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
# Validate prerequisites
|
|
15
|
+
command -v git >/dev/null 2>&1 || error_exit "git is required but not installed"
|
|
16
|
+
|
|
17
|
+
# Validate inputs
|
|
18
|
+
INTENT_ID="${1:-}"
|
|
19
|
+
if [ -z "$INTENT_ID" ]; then
|
|
20
|
+
error_exit "Usage: $0 <intent-id> [task-count]" 1
|
|
21
|
+
fi
|
|
22
|
+
|
|
23
|
+
TASK_COUNT="${2:-3}"
|
|
24
|
+
if ! [[ "$TASK_COUNT" =~ ^[0-9]+$ ]] || [ "$TASK_COUNT" -lt 1 ] || [ "$TASK_COUNT" -gt 10 ]; then
|
|
25
|
+
error_exit "Task count must be between 1 and 10" 1
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
BASE_DIR="$(pwd)"
|
|
29
|
+
WORKTREE_BASE="../worktree"
|
|
30
|
+
|
|
31
|
+
# Validate we're in a git repo
|
|
32
|
+
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
|
33
|
+
error_exit "Not a git repository. Run this from the repository root." 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
echo "Setting up $TASK_COUNT worktrees for intent $INTENT_ID"
|
|
37
|
+
|
|
38
|
+
# Create worktrees.json
|
|
39
|
+
WORKTREES_FILE="worktrees.json"
|
|
40
|
+
if [ -f "$WORKTREES_FILE" ]; then
|
|
41
|
+
echo "WARNING: $WORKTREES_FILE already exists. Backing up to ${WORKTREES_FILE}.bak"
|
|
42
|
+
cp "$WORKTREES_FILE" "${WORKTREES_FILE}.bak" || error_exit "Failed to backup existing worktrees.json"
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
cat > "$WORKTREES_FILE" << EOF || error_exit "Failed to create worktrees.json"
|
|
46
|
+
{
|
|
47
|
+
"intent_id": "$INTENT_ID",
|
|
48
|
+
"created": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
|
|
49
|
+
"tasks": [
|
|
50
|
+
EOF
|
|
51
|
+
|
|
52
|
+
for i in $(seq 1 $TASK_COUNT); do
|
|
53
|
+
WORKTREE_DIR="$WORKTREE_BASE-$i"
|
|
54
|
+
BRANCH="feature/$INTENT_ID-task-$i"
|
|
55
|
+
|
|
56
|
+
echo "Creating worktree $i: $WORKTREE_DIR"
|
|
57
|
+
|
|
58
|
+
# Check if worktree already exists
|
|
59
|
+
if [ -d "$WORKTREE_DIR" ]; then
|
|
60
|
+
echo "WARNING: Worktree $i already exists at $WORKTREE_DIR. Skipping..."
|
|
61
|
+
continue
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# Create worktree
|
|
65
|
+
if ! git worktree add "$WORKTREE_DIR" -b "$BRANCH" 2>/dev/null; then
|
|
66
|
+
echo "ERROR: Failed to create worktree $i. Branch $BRANCH may already exist."
|
|
67
|
+
echo "Try: git branch -D $BRANCH (if safe to delete)"
|
|
68
|
+
continue
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Create .agent-id file with unique integer per worktree
|
|
72
|
+
if ! echo "$i" > "$WORKTREE_DIR/.agent-id"; then
|
|
73
|
+
error_exit "Failed to create .agent-id in worktree $i"
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
# Register agent in coordination system
|
|
77
|
+
if [ -f "experimental/agent-coordinator.sh" ]; then
|
|
78
|
+
AGENT_ID="agent-$i"
|
|
79
|
+
# Agent will be registered when first task is assigned
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Add to worktrees.json
|
|
83
|
+
if [ $i -gt 1 ]; then
|
|
84
|
+
echo "," >> worktrees.json
|
|
85
|
+
fi
|
|
86
|
+
cat >> worktrees.json << EOF
|
|
87
|
+
{
|
|
88
|
+
"id": $i,
|
|
89
|
+
"description": "Task $i for $INTENT_ID",
|
|
90
|
+
"worktree": "$WORKTREE_DIR",
|
|
91
|
+
"branch": "$BRANCH",
|
|
92
|
+
"status": "pending",
|
|
93
|
+
"assigned_at": null,
|
|
94
|
+
"completed_at": null
|
|
95
|
+
}
|
|
96
|
+
EOF
|
|
97
|
+
done
|
|
98
|
+
|
|
99
|
+
cat >> "$WORKTREES_FILE" << EOF || error_exit "Failed to complete worktrees.json"
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
EOF
|
|
103
|
+
|
|
104
|
+
echo ""
|
|
105
|
+
echo "✓ Successfully created worktrees.json"
|
|
106
|
+
|
|
107
|
+
echo ""
|
|
108
|
+
echo "Worktrees created:"
|
|
109
|
+
for i in $(seq 1 $TASK_COUNT); do
|
|
110
|
+
echo " - $WORKTREE_BASE-$i (branch: feature/$INTENT_ID-task-$i)"
|
|
111
|
+
done
|
|
112
|
+
echo ""
|
|
113
|
+
echo "Next steps:"
|
|
114
|
+
echo "1. Open each worktree in a separate Cursor window"
|
|
115
|
+
echo "2. Each agent reads .agent-id to get their task number:"
|
|
116
|
+
echo " - Read the file: cat .agent-id (or read .agent-id in Cursor)"
|
|
117
|
+
echo " - The number in .agent-id corresponds to your task ID in worktrees.json"
|
|
118
|
+
echo " - Only work on the task matching your agent ID"
|
|
119
|
+
echo "3. Agents coordinate via worktrees.json in main repo"
|
|
120
|
+
echo ""
|
|
121
|
+
echo "Agent coordination:"
|
|
122
|
+
echo " - Each worktree has a .agent-id file containing a unique integer (1, 2, 3, etc.)"
|
|
123
|
+
echo " - Read your agent ID: AGENT_ID=\$(cat .agent-id)"
|
|
124
|
+
echo " - Find your task in worktrees.json where id == AGENT_ID"
|
|
125
|
+
echo " - Update your task status in worktrees.json as you progress"
|