@ui8kit/uxdx 0.1.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/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/uxdx.mjs +296 -0
- package/package.json +53 -0
- package/packages/sdlc/harness/README.md +58 -0
- package/packages/sdlc/harness/core/AGENTS.md +12 -0
- package/packages/sdlc/harness/core/README.md +15 -0
- package/packages/sdlc/harness/core/REVIEW.md +18 -0
- package/packages/sdlc/harness/core/changes/README.md +4 -0
- package/packages/sdlc/harness/core/cursor/rules/sdlc-core.mdc +15 -0
- package/packages/sdlc/harness/core/install.sh +3 -0
- package/packages/sdlc/harness/core/intent.md +25 -0
- package/packages/sdlc/harness/core/manifest.yaml +15 -0
- package/packages/sdlc/harness/core/plan.md +25 -0
- package/packages/sdlc/harness/core/sdlc.sh +230 -0
- package/packages/sdlc/harness/core/skills/sdlc-invariants/SKILL.md +20 -0
- package/packages/sdlc/harness/core/skills/sdlc-plan/SKILL.md +15 -0
- package/packages/sdlc/harness/core/spec.md +24 -0
- package/packages/sdlc/harness/core/start.sh +3 -0
- package/packages/sdlc/harness/full/AGENTS.md +15 -0
- package/packages/sdlc/harness/full/README.md +23 -0
- package/packages/sdlc/harness/full/REVIEW.md +19 -0
- package/packages/sdlc/harness/full/bands.yaml +13 -0
- package/packages/sdlc/harness/full/changes/README.md +4 -0
- package/packages/sdlc/harness/full/cursor/rules/sdlc-full.mdc +17 -0
- package/packages/sdlc/harness/full/evals/README.md +16 -0
- package/packages/sdlc/harness/full/hooks/README.md +17 -0
- package/packages/sdlc/harness/full/install.sh +3 -0
- package/packages/sdlc/harness/full/intent.md +26 -0
- package/packages/sdlc/harness/full/manifest.yaml +17 -0
- package/packages/sdlc/harness/full/plan.md +30 -0
- package/packages/sdlc/harness/full/sdlc.sh +230 -0
- package/packages/sdlc/harness/full/skills/sdlc-feedback/SKILL.md +18 -0
- package/packages/sdlc/harness/full/skills/sdlc-loop/SKILL.md +21 -0
- package/packages/sdlc/harness/full/skills/sdlc-review/SKILL.md +15 -0
- package/packages/sdlc/harness/full/spec.md +28 -0
- package/packages/sdlc/harness/full/start.sh +3 -0
- package/packages/sdlc/harness/light/AGENTS.md +13 -0
- package/packages/sdlc/harness/light/README.md +15 -0
- package/packages/sdlc/harness/light/changes/README.md +6 -0
- package/packages/sdlc/harness/light/cursor/rules/sdlc-light.mdc +16 -0
- package/packages/sdlc/harness/light/install.sh +3 -0
- package/packages/sdlc/harness/light/intent.md +24 -0
- package/packages/sdlc/harness/light/manifest.yaml +15 -0
- package/packages/sdlc/harness/light/plan.md +28 -0
- package/packages/sdlc/harness/light/sdlc.sh +230 -0
- package/packages/sdlc/harness/light/skills/sdlc-light/SKILL.md +30 -0
- package/packages/sdlc/harness/light/spec.md +23 -0
- package/packages/sdlc/harness/light/start.sh +3 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Run from a product repo after this pack is copied to .sdlc/
|
|
3
|
+
# .sdlc/sdlc.sh install
|
|
4
|
+
# .sdlc/sdlc.sh start <slug>
|
|
5
|
+
# .sdlc/sdlc.sh status
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SDLC_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
9
|
+
REPO_ROOT="$(CDPATH= cd -- "$SDLC_DIR/.." && pwd)"
|
|
10
|
+
MANIFEST="$SDLC_DIR/manifest.yaml"
|
|
11
|
+
BEGIN='<!-- sdlc-harness:begin -->'
|
|
12
|
+
END='<!-- sdlc-harness:end -->'
|
|
13
|
+
|
|
14
|
+
die() { printf 'sdlc: %s\n' "$*" >&2; exit 1; }
|
|
15
|
+
|
|
16
|
+
need_manifest() {
|
|
17
|
+
[[ -f "$MANIFEST" ]] || die "missing $MANIFEST (copy a harness pack into .sdlc/)"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
level() {
|
|
21
|
+
awk '/^level:[[:space:]]/ { print $2; exit }' "$MANIFEST"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
warn_location() {
|
|
25
|
+
local base
|
|
26
|
+
base="$(basename -- "$SDLC_DIR")"
|
|
27
|
+
if [[ "$base" != ".sdlc" ]]; then
|
|
28
|
+
printf 'sdlc: warning: script dir is %s (expected .sdlc in a product repo)\n' "$SDLC_DIR" >&2
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat <<EOF
|
|
34
|
+
Usage: .sdlc/sdlc.sh <command>
|
|
35
|
+
|
|
36
|
+
install Overlay Cursor rules/skills; merge AGENTS.md at repo root
|
|
37
|
+
start <slug> [opts] Copy templates into .sdlc/changes/<slug>/
|
|
38
|
+
status Show level, overlay, and changes
|
|
39
|
+
|
|
40
|
+
start options:
|
|
41
|
+
--force Overwrite files that already exist in the change folder
|
|
42
|
+
--intent Also copy intent.md (light/core; full always copies it)
|
|
43
|
+
--spec Also copy spec.md (light; core/full as below)
|
|
44
|
+
--boundary core: copy intent.md + spec.md + plan.md
|
|
45
|
+
|
|
46
|
+
Repo root is the parent of this .sdlc directory:
|
|
47
|
+
$REPO_ROOT
|
|
48
|
+
EOF
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
copy_rules() {
|
|
52
|
+
local src="$SDLC_DIR/cursor/rules" dest="$REPO_ROOT/.cursor/rules" f
|
|
53
|
+
[[ -d "$src" ]] || die "missing $src"
|
|
54
|
+
mkdir -p "$dest"
|
|
55
|
+
shopt -s nullglob
|
|
56
|
+
for f in "$src"/*.mdc; do
|
|
57
|
+
cp -- "$f" "$dest/"
|
|
58
|
+
printf 'sdlc: rule %s\n' "$dest/$(basename -- "$f")"
|
|
59
|
+
done
|
|
60
|
+
shopt -u nullglob
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
copy_skills() {
|
|
64
|
+
local src="$SDLC_DIR/skills" dest="$REPO_ROOT/.cursor/skills" d name
|
|
65
|
+
[[ -d "$src" ]] || die "missing $src"
|
|
66
|
+
mkdir -p "$dest"
|
|
67
|
+
shopt -s nullglob
|
|
68
|
+
for d in "$src"/*/; do
|
|
69
|
+
name="$(basename -- "$d")"
|
|
70
|
+
rm -rf -- "$dest/$name"
|
|
71
|
+
cp -R -- "$d" "$dest/$name"
|
|
72
|
+
printf 'sdlc: skill %s\n' "$dest/$name"
|
|
73
|
+
done
|
|
74
|
+
shopt -u nullglob
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
merge_agents() {
|
|
78
|
+
local overlay="$SDLC_DIR/AGENTS.md" dest="$REPO_ROOT/AGENTS.md" tmp
|
|
79
|
+
[[ -f "$overlay" ]] || die "missing $overlay"
|
|
80
|
+
if [[ ! -f "$dest" ]]; then
|
|
81
|
+
cp -- "$overlay" "$dest"
|
|
82
|
+
printf 'sdlc: created %s\n' "$dest"
|
|
83
|
+
return
|
|
84
|
+
fi
|
|
85
|
+
tmp="$(mktemp)"
|
|
86
|
+
if grep -F -q -- "$BEGIN" "$dest"; then
|
|
87
|
+
awk -v begin="$BEGIN" -v end="$END" -v overlay="$overlay" '
|
|
88
|
+
BEGIN {
|
|
89
|
+
while ((getline line < overlay) > 0) { o = o line "\n" }
|
|
90
|
+
close(overlay)
|
|
91
|
+
}
|
|
92
|
+
index($0, begin) == 1 {
|
|
93
|
+
printf "%s", o
|
|
94
|
+
skip = 1
|
|
95
|
+
next
|
|
96
|
+
}
|
|
97
|
+
skip {
|
|
98
|
+
if (index($0, end) == 1) skip = 0
|
|
99
|
+
next
|
|
100
|
+
}
|
|
101
|
+
{ print }
|
|
102
|
+
' "$dest" >"$tmp"
|
|
103
|
+
else
|
|
104
|
+
cat -- "$dest" >"$tmp"
|
|
105
|
+
printf '\n' >>"$tmp"
|
|
106
|
+
cat -- "$overlay" >>"$tmp"
|
|
107
|
+
fi
|
|
108
|
+
mv -- "$tmp" "$dest"
|
|
109
|
+
printf 'sdlc: merged overlay into %s\n' "$dest"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
cmd_install() {
|
|
113
|
+
need_manifest
|
|
114
|
+
warn_location
|
|
115
|
+
copy_rules
|
|
116
|
+
copy_skills
|
|
117
|
+
merge_agents
|
|
118
|
+
printf 'sdlc: install done (level %s) repo %s\n' "$(level)" "$REPO_ROOT"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
valid_slug() {
|
|
122
|
+
[[ "$1" =~ ^[a-z0-9][a-z0-9-]*$ ]] || die "slug must be kebab-case: $1"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
copy_template() {
|
|
126
|
+
local src="$SDLC_DIR/$1" dest="$2/$1"
|
|
127
|
+
[[ -f "$src" ]] || die "missing template $src"
|
|
128
|
+
if [[ -e "$dest" && "$FORCE" -eq 0 ]]; then
|
|
129
|
+
printf 'sdlc: skip existing %s (use --force)\n' "$dest"
|
|
130
|
+
return
|
|
131
|
+
fi
|
|
132
|
+
cp -- "$src" "$dest"
|
|
133
|
+
printf 'sdlc: %s\n' "$dest"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cmd_start() {
|
|
137
|
+
need_manifest
|
|
138
|
+
warn_location
|
|
139
|
+
local slug="" with_intent=0 with_spec=0 boundary=0
|
|
140
|
+
FORCE=0
|
|
141
|
+
while [[ $# -gt 0 ]]; do
|
|
142
|
+
case "$1" in
|
|
143
|
+
--force) FORCE=1; shift ;;
|
|
144
|
+
--intent) with_intent=1; shift ;;
|
|
145
|
+
--spec) with_spec=1; shift ;;
|
|
146
|
+
--boundary) boundary=1; shift ;;
|
|
147
|
+
--help|-h) usage; exit 0 ;;
|
|
148
|
+
-*) die "unknown option $1" ;;
|
|
149
|
+
*)
|
|
150
|
+
[[ -z "$slug" ]] || die "unexpected argument $1"
|
|
151
|
+
slug="$1"
|
|
152
|
+
shift
|
|
153
|
+
;;
|
|
154
|
+
esac
|
|
155
|
+
done
|
|
156
|
+
[[ -n "$slug" ]] || die "start requires <slug>"
|
|
157
|
+
valid_slug "$slug"
|
|
158
|
+
|
|
159
|
+
local lvl dest
|
|
160
|
+
lvl="$(level)"
|
|
161
|
+
dest="$SDLC_DIR/changes/$slug"
|
|
162
|
+
mkdir -p "$dest"
|
|
163
|
+
|
|
164
|
+
case "$lvl" in
|
|
165
|
+
light)
|
|
166
|
+
copy_template plan.md "$dest"
|
|
167
|
+
[[ "$with_intent" -eq 1 ]] && copy_template intent.md "$dest"
|
|
168
|
+
[[ "$with_spec" -eq 1 ]] && copy_template spec.md "$dest"
|
|
169
|
+
;;
|
|
170
|
+
core)
|
|
171
|
+
copy_template plan.md "$dest"
|
|
172
|
+
if [[ "$boundary" -eq 1 || "$with_intent" -eq 1 || "$with_spec" -eq 1 ]]; then
|
|
173
|
+
copy_template intent.md "$dest"
|
|
174
|
+
copy_template spec.md "$dest"
|
|
175
|
+
fi
|
|
176
|
+
;;
|
|
177
|
+
full)
|
|
178
|
+
copy_template intent.md "$dest"
|
|
179
|
+
copy_template spec.md "$dest"
|
|
180
|
+
copy_template plan.md "$dest"
|
|
181
|
+
;;
|
|
182
|
+
*)
|
|
183
|
+
die "unknown level in manifest: $lvl"
|
|
184
|
+
;;
|
|
185
|
+
esac
|
|
186
|
+
printf 'sdlc: change %s ready under %s\n' "$slug" "$dest"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
cmd_status() {
|
|
190
|
+
need_manifest
|
|
191
|
+
warn_location
|
|
192
|
+
local lvl
|
|
193
|
+
lvl="$(level)"
|
|
194
|
+
printf 'level: %s\n' "$lvl"
|
|
195
|
+
printf 'sdlc dir: %s\n' "$SDLC_DIR"
|
|
196
|
+
printf 'repo: %s\n' "$REPO_ROOT"
|
|
197
|
+
if [[ -f "$REPO_ROOT/AGENTS.md" ]] && grep -F -q -- "$BEGIN" "$REPO_ROOT/AGENTS.md"; then
|
|
198
|
+
printf 'AGENTS.md: overlay present\n'
|
|
199
|
+
else
|
|
200
|
+
printf 'AGENTS.md: overlay missing (run install)\n'
|
|
201
|
+
fi
|
|
202
|
+
if [[ -d "$REPO_ROOT/.cursor/rules" ]]; then
|
|
203
|
+
printf 'rules:\n'
|
|
204
|
+
ls -1 "$REPO_ROOT/.cursor/rules"/sdlc-*.mdc 2>/dev/null || printf ' (no sdlc-*.mdc)\n'
|
|
205
|
+
fi
|
|
206
|
+
printf 'changes:\n'
|
|
207
|
+
if [[ -d "$SDLC_DIR/changes" ]]; then
|
|
208
|
+
local d
|
|
209
|
+
shopt -s nullglob
|
|
210
|
+
for d in "$SDLC_DIR/changes"/*/; do
|
|
211
|
+
printf ' %s\n' "$(basename -- "$d")"
|
|
212
|
+
done
|
|
213
|
+
shopt -u nullglob
|
|
214
|
+
fi
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main() {
|
|
218
|
+
local cmd="${1:-}"
|
|
219
|
+
[[ -n "$cmd" ]] || { usage; exit 1; }
|
|
220
|
+
shift || true
|
|
221
|
+
case "$cmd" in
|
|
222
|
+
install) cmd_install "$@" ;;
|
|
223
|
+
start) cmd_start "$@" ;;
|
|
224
|
+
status) cmd_status "$@" ;;
|
|
225
|
+
-h|--help|help) usage ;;
|
|
226
|
+
*) die "unknown command $cmd" ;;
|
|
227
|
+
esac
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
main "$@"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-feedback
|
|
3
|
+
description: >-
|
|
4
|
+
Verify agent work with the repo's existing commands before claiming done.
|
|
5
|
+
Use in full-harness repos after implementation. Do not weaken tests to
|
|
6
|
+
make a task pass.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Feedback loop
|
|
10
|
+
|
|
11
|
+
1. Read verify commands from root `AGENTS.md` (or Makefile / package.json
|
|
12
|
+
scripts named there).
|
|
13
|
+
2. Run them. Paste or summarize the outcome.
|
|
14
|
+
3. If tests fail, fix production code, not the test, unless the change is the
|
|
15
|
+
test and `plan.md` says so.
|
|
16
|
+
4. For UI, use the repo's existing check (`bun run check`, screenshot, or
|
|
17
|
+
documented browser step). Do not add Playwright as a default gate.
|
|
18
|
+
5. Never report complete without the proof named in `plan.md`.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-loop
|
|
3
|
+
description: >-
|
|
4
|
+
Full AI-native SDLC loop for a solo developer. Use when working in a repo
|
|
5
|
+
with .sdlc/manifest.yaml level full. Drive intent.md, spec.md, plan.md in
|
|
6
|
+
order; do not skip to code on a non-trivial change.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Full SDLC loop
|
|
10
|
+
|
|
11
|
+
1. Write or update `.sdlc/changes/<slug>/intent.md`. The human corrects it
|
|
12
|
+
before spec.
|
|
13
|
+
2. Produce `spec.md` from the intent. Flag policy conflicts. Do not start
|
|
14
|
+
plan mode until the human accepts the spec (or explicitly says "small,
|
|
15
|
+
proceed").
|
|
16
|
+
3. Plan mode: `plan.md` with files, order, risks, proof. No file edits until
|
|
17
|
+
the plan is accepted.
|
|
18
|
+
4. Implement in one pass when the plan is tight. Update `plan.md` if you
|
|
19
|
+
diverge.
|
|
20
|
+
5. Hand off to skill `sdlc-feedback` before reporting done.
|
|
21
|
+
6. PR text points at the three artifacts. Review uses `sdlc-review`.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sdlc-review
|
|
3
|
+
description: >-
|
|
4
|
+
Review a PR against .sdlc/REVIEW.md, spec.md, and plan.md in a full-harness
|
|
5
|
+
repo. Use when reviewing diffs or addressing review comments.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# PR review (full)
|
|
9
|
+
|
|
10
|
+
1. Read `.sdlc/REVIEW.md` and the change's `spec.md` / `plan.md`.
|
|
11
|
+
2. Three passes: bugs, security, compliance with the artifacts.
|
|
12
|
+
3. Findings do not merge the PR. A human approves.
|
|
13
|
+
4. If the same mistake appears twice, add a line to product `AGENTS.md` or a
|
|
14
|
+
skill — not a one-off comment that will rot.
|
|
15
|
+
5. The agent that wrote the diff must not be treated as the approver.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Spec: <!-- title from intent -->
|
|
2
|
+
|
|
3
|
+
Intent: `.sdlc/changes/<slug>/intent.md`
|
|
4
|
+
Status: draft
|
|
5
|
+
|
|
6
|
+
## Requirements
|
|
7
|
+
|
|
8
|
+
What the change must do. Trace each item to the intent.
|
|
9
|
+
|
|
10
|
+
## Design
|
|
11
|
+
|
|
12
|
+
How it fits the existing codebase. Name surfaces (API, admin, BFF, host) —
|
|
13
|
+
do not invent a new plane.
|
|
14
|
+
|
|
15
|
+
## Skills and policies applied
|
|
16
|
+
|
|
17
|
+
Brand, security, UX, stack-contract — list the files that constrained this
|
|
18
|
+
spec (`AGENTS.md`, `.cursor/rules/*`, `.project/adr/*`).
|
|
19
|
+
|
|
20
|
+
## Areas of concern
|
|
21
|
+
|
|
22
|
+
Where policies conflict or evidence is missing. A human resolves each item
|
|
23
|
+
before plan mode. Do not leave a red flag for engineering to discover in the
|
|
24
|
+
diff.
|
|
25
|
+
|
|
26
|
+
## Open questions carried forward
|
|
27
|
+
|
|
28
|
+
Questions from `intent.md` that remain, with an owner.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- sdlc-harness:begin -->
|
|
2
|
+
## SDLC harness (light)
|
|
3
|
+
|
|
4
|
+
This repo uses the **light** pack from `hinddy/brainstorm` (`.harness-sdlc/light`).
|
|
5
|
+
Working copy: `.sdlc/`. Per-change artifacts: `.sdlc/changes/<slug>/`.
|
|
6
|
+
|
|
7
|
+
- Non-trivial work starts in plan mode. Commit `plan.md` before a large diff.
|
|
8
|
+
- `spec.md` is optional. Do not start a requirements theatre for a one-file fix.
|
|
9
|
+
- Verify with this repository's existing commands, listed in this `AGENTS.md`
|
|
10
|
+
or `.project/`. Do not add Playwright or extra browser suites as a default gate.
|
|
11
|
+
- Overlay rules: `.cursor/rules/sdlc-light.mdc`. Overlay skill: `sdlc-light`.
|
|
12
|
+
- Product rules and this file's stack contract win over the harness if they conflict.
|
|
13
|
+
<!-- sdlc-harness:end -->
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Light harness
|
|
2
|
+
|
|
3
|
+
For product repos that already have a contract (`AGENTS.md`, stack rules, tests).
|
|
4
|
+
Examples: AlexY OS, GitCourse, Lab, BrandOSS, ui8px-cli, FastyGo UI.
|
|
5
|
+
|
|
6
|
+
Copy this directory to `<repo>/.sdlc/`. Then overlay Cursor files — see
|
|
7
|
+
`../README.md`.
|
|
8
|
+
|
|
9
|
+
## Per change
|
|
10
|
+
|
|
11
|
+
1. `mkdir -p .sdlc/changes/<slug>`
|
|
12
|
+
2. Copy `plan.md` into that folder and fill it.
|
|
13
|
+
3. Add `intent.md` only if the origin is unclear (incident, external request).
|
|
14
|
+
4. Skip `spec.md` unless you are changing published IA or a user-visible contract.
|
|
15
|
+
5. Run the repo's existing verify command before calling the task done.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Light SDLC — plan.md and existing verify gates; no spec theatre
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Light SDLC overlay
|
|
7
|
+
|
|
8
|
+
This repository opted into `.sdlc` harness **light**.
|
|
9
|
+
|
|
10
|
+
- Put change artifacts under `.sdlc/changes/<slug>/`.
|
|
11
|
+
- Require `plan.md` for non-trivial diffs. `intent.md` is optional. Skip
|
|
12
|
+
`spec.md` unless published IA or a public contract changes.
|
|
13
|
+
- After code changes, run the verify command already documented in `AGENTS.md`.
|
|
14
|
+
- Do not add eval suites, managed hooks, or autonomous maintain loops.
|
|
15
|
+
- If this overlay disagrees with stack-contract or product `AGENTS.md`, the
|
|
16
|
+
product files win.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Intent (light — optional)
|
|
2
|
+
|
|
3
|
+
Author: <!-- name -->
|
|
4
|
+
Status: draft
|
|
5
|
+
Slug: <!-- kebab-case, matches .sdlc/changes/<slug>/ -->
|
|
6
|
+
|
|
7
|
+
## Problem
|
|
8
|
+
|
|
9
|
+
What cannot be done today, in the originator's words.
|
|
10
|
+
|
|
11
|
+
## Proposed outcome
|
|
12
|
+
|
|
13
|
+
What better looks like. One paragraph.
|
|
14
|
+
|
|
15
|
+
## Out of scope
|
|
16
|
+
|
|
17
|
+
What this change will not do.
|
|
18
|
+
|
|
19
|
+
## Constraints
|
|
20
|
+
|
|
21
|
+
Repo `AGENTS.md` and existing `.cursor/rules` stay in force. Do not invent
|
|
22
|
+
kinds, routes, or a second API.
|
|
23
|
+
|
|
24
|
+
## Open questions
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
level: light
|
|
2
|
+
version: 1
|
|
3
|
+
copy_to: .sdlc
|
|
4
|
+
cursor:
|
|
5
|
+
rules: cursor/rules
|
|
6
|
+
skills: skills
|
|
7
|
+
agents_md:
|
|
8
|
+
overlay: AGENTS.md
|
|
9
|
+
merge_markers:
|
|
10
|
+
begin: "<!-- sdlc-harness:begin -->"
|
|
11
|
+
end: "<!-- sdlc-harness:end -->"
|
|
12
|
+
artifacts:
|
|
13
|
+
required: [plan.md]
|
|
14
|
+
optional: [intent.md]
|
|
15
|
+
skip_by_default: [spec.md]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Plan (light)
|
|
2
|
+
|
|
3
|
+
From: <!-- intent/spec slug or issue URL -->
|
|
4
|
+
Status: draft
|
|
5
|
+
Author: <!-- engineer -->
|
|
6
|
+
|
|
7
|
+
## Files that change
|
|
8
|
+
|
|
9
|
+
-
|
|
10
|
+
|
|
11
|
+
## Order of work
|
|
12
|
+
|
|
13
|
+
1.
|
|
14
|
+
2.
|
|
15
|
+
|
|
16
|
+
## Tests / proof
|
|
17
|
+
|
|
18
|
+
Name the existing command that must pass (`make verify`, `bun run validate`,
|
|
19
|
+
`go test ./...`, or the repo's documented gate). Do not invent a parallel suite.
|
|
20
|
+
|
|
21
|
+
## Risks
|
|
22
|
+
|
|
23
|
+
-
|
|
24
|
+
|
|
25
|
+
## Non-goals
|
|
26
|
+
|
|
27
|
+
Do not expand product IA, add a second REST shape, or edit pinned modules to
|
|
28
|
+
ship this change.
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Run from a product repo after this pack is copied to .sdlc/
|
|
3
|
+
# .sdlc/sdlc.sh install
|
|
4
|
+
# .sdlc/sdlc.sh start <slug>
|
|
5
|
+
# .sdlc/sdlc.sh status
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SDLC_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
|
9
|
+
REPO_ROOT="$(CDPATH= cd -- "$SDLC_DIR/.." && pwd)"
|
|
10
|
+
MANIFEST="$SDLC_DIR/manifest.yaml"
|
|
11
|
+
BEGIN='<!-- sdlc-harness:begin -->'
|
|
12
|
+
END='<!-- sdlc-harness:end -->'
|
|
13
|
+
|
|
14
|
+
die() { printf 'sdlc: %s\n' "$*" >&2; exit 1; }
|
|
15
|
+
|
|
16
|
+
need_manifest() {
|
|
17
|
+
[[ -f "$MANIFEST" ]] || die "missing $MANIFEST (copy a harness pack into .sdlc/)"
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
level() {
|
|
21
|
+
awk '/^level:[[:space:]]/ { print $2; exit }' "$MANIFEST"
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
warn_location() {
|
|
25
|
+
local base
|
|
26
|
+
base="$(basename -- "$SDLC_DIR")"
|
|
27
|
+
if [[ "$base" != ".sdlc" ]]; then
|
|
28
|
+
printf 'sdlc: warning: script dir is %s (expected .sdlc in a product repo)\n' "$SDLC_DIR" >&2
|
|
29
|
+
fi
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
usage() {
|
|
33
|
+
cat <<EOF
|
|
34
|
+
Usage: .sdlc/sdlc.sh <command>
|
|
35
|
+
|
|
36
|
+
install Overlay Cursor rules/skills; merge AGENTS.md at repo root
|
|
37
|
+
start <slug> [opts] Copy templates into .sdlc/changes/<slug>/
|
|
38
|
+
status Show level, overlay, and changes
|
|
39
|
+
|
|
40
|
+
start options:
|
|
41
|
+
--force Overwrite files that already exist in the change folder
|
|
42
|
+
--intent Also copy intent.md (light/core; full always copies it)
|
|
43
|
+
--spec Also copy spec.md (light; core/full as below)
|
|
44
|
+
--boundary core: copy intent.md + spec.md + plan.md
|
|
45
|
+
|
|
46
|
+
Repo root is the parent of this .sdlc directory:
|
|
47
|
+
$REPO_ROOT
|
|
48
|
+
EOF
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
copy_rules() {
|
|
52
|
+
local src="$SDLC_DIR/cursor/rules" dest="$REPO_ROOT/.cursor/rules" f
|
|
53
|
+
[[ -d "$src" ]] || die "missing $src"
|
|
54
|
+
mkdir -p "$dest"
|
|
55
|
+
shopt -s nullglob
|
|
56
|
+
for f in "$src"/*.mdc; do
|
|
57
|
+
cp -- "$f" "$dest/"
|
|
58
|
+
printf 'sdlc: rule %s\n' "$dest/$(basename -- "$f")"
|
|
59
|
+
done
|
|
60
|
+
shopt -u nullglob
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
copy_skills() {
|
|
64
|
+
local src="$SDLC_DIR/skills" dest="$REPO_ROOT/.cursor/skills" d name
|
|
65
|
+
[[ -d "$src" ]] || die "missing $src"
|
|
66
|
+
mkdir -p "$dest"
|
|
67
|
+
shopt -s nullglob
|
|
68
|
+
for d in "$src"/*/; do
|
|
69
|
+
name="$(basename -- "$d")"
|
|
70
|
+
rm -rf -- "$dest/$name"
|
|
71
|
+
cp -R -- "$d" "$dest/$name"
|
|
72
|
+
printf 'sdlc: skill %s\n' "$dest/$name"
|
|
73
|
+
done
|
|
74
|
+
shopt -u nullglob
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
merge_agents() {
|
|
78
|
+
local overlay="$SDLC_DIR/AGENTS.md" dest="$REPO_ROOT/AGENTS.md" tmp
|
|
79
|
+
[[ -f "$overlay" ]] || die "missing $overlay"
|
|
80
|
+
if [[ ! -f "$dest" ]]; then
|
|
81
|
+
cp -- "$overlay" "$dest"
|
|
82
|
+
printf 'sdlc: created %s\n' "$dest"
|
|
83
|
+
return
|
|
84
|
+
fi
|
|
85
|
+
tmp="$(mktemp)"
|
|
86
|
+
if grep -F -q -- "$BEGIN" "$dest"; then
|
|
87
|
+
awk -v begin="$BEGIN" -v end="$END" -v overlay="$overlay" '
|
|
88
|
+
BEGIN {
|
|
89
|
+
while ((getline line < overlay) > 0) { o = o line "\n" }
|
|
90
|
+
close(overlay)
|
|
91
|
+
}
|
|
92
|
+
index($0, begin) == 1 {
|
|
93
|
+
printf "%s", o
|
|
94
|
+
skip = 1
|
|
95
|
+
next
|
|
96
|
+
}
|
|
97
|
+
skip {
|
|
98
|
+
if (index($0, end) == 1) skip = 0
|
|
99
|
+
next
|
|
100
|
+
}
|
|
101
|
+
{ print }
|
|
102
|
+
' "$dest" >"$tmp"
|
|
103
|
+
else
|
|
104
|
+
cat -- "$dest" >"$tmp"
|
|
105
|
+
printf '\n' >>"$tmp"
|
|
106
|
+
cat -- "$overlay" >>"$tmp"
|
|
107
|
+
fi
|
|
108
|
+
mv -- "$tmp" "$dest"
|
|
109
|
+
printf 'sdlc: merged overlay into %s\n' "$dest"
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
cmd_install() {
|
|
113
|
+
need_manifest
|
|
114
|
+
warn_location
|
|
115
|
+
copy_rules
|
|
116
|
+
copy_skills
|
|
117
|
+
merge_agents
|
|
118
|
+
printf 'sdlc: install done (level %s) repo %s\n' "$(level)" "$REPO_ROOT"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
valid_slug() {
|
|
122
|
+
[[ "$1" =~ ^[a-z0-9][a-z0-9-]*$ ]] || die "slug must be kebab-case: $1"
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
copy_template() {
|
|
126
|
+
local src="$SDLC_DIR/$1" dest="$2/$1"
|
|
127
|
+
[[ -f "$src" ]] || die "missing template $src"
|
|
128
|
+
if [[ -e "$dest" && "$FORCE" -eq 0 ]]; then
|
|
129
|
+
printf 'sdlc: skip existing %s (use --force)\n' "$dest"
|
|
130
|
+
return
|
|
131
|
+
fi
|
|
132
|
+
cp -- "$src" "$dest"
|
|
133
|
+
printf 'sdlc: %s\n' "$dest"
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cmd_start() {
|
|
137
|
+
need_manifest
|
|
138
|
+
warn_location
|
|
139
|
+
local slug="" with_intent=0 with_spec=0 boundary=0
|
|
140
|
+
FORCE=0
|
|
141
|
+
while [[ $# -gt 0 ]]; do
|
|
142
|
+
case "$1" in
|
|
143
|
+
--force) FORCE=1; shift ;;
|
|
144
|
+
--intent) with_intent=1; shift ;;
|
|
145
|
+
--spec) with_spec=1; shift ;;
|
|
146
|
+
--boundary) boundary=1; shift ;;
|
|
147
|
+
--help|-h) usage; exit 0 ;;
|
|
148
|
+
-*) die "unknown option $1" ;;
|
|
149
|
+
*)
|
|
150
|
+
[[ -z "$slug" ]] || die "unexpected argument $1"
|
|
151
|
+
slug="$1"
|
|
152
|
+
shift
|
|
153
|
+
;;
|
|
154
|
+
esac
|
|
155
|
+
done
|
|
156
|
+
[[ -n "$slug" ]] || die "start requires <slug>"
|
|
157
|
+
valid_slug "$slug"
|
|
158
|
+
|
|
159
|
+
local lvl dest
|
|
160
|
+
lvl="$(level)"
|
|
161
|
+
dest="$SDLC_DIR/changes/$slug"
|
|
162
|
+
mkdir -p "$dest"
|
|
163
|
+
|
|
164
|
+
case "$lvl" in
|
|
165
|
+
light)
|
|
166
|
+
copy_template plan.md "$dest"
|
|
167
|
+
[[ "$with_intent" -eq 1 ]] && copy_template intent.md "$dest"
|
|
168
|
+
[[ "$with_spec" -eq 1 ]] && copy_template spec.md "$dest"
|
|
169
|
+
;;
|
|
170
|
+
core)
|
|
171
|
+
copy_template plan.md "$dest"
|
|
172
|
+
if [[ "$boundary" -eq 1 || "$with_intent" -eq 1 || "$with_spec" -eq 1 ]]; then
|
|
173
|
+
copy_template intent.md "$dest"
|
|
174
|
+
copy_template spec.md "$dest"
|
|
175
|
+
fi
|
|
176
|
+
;;
|
|
177
|
+
full)
|
|
178
|
+
copy_template intent.md "$dest"
|
|
179
|
+
copy_template spec.md "$dest"
|
|
180
|
+
copy_template plan.md "$dest"
|
|
181
|
+
;;
|
|
182
|
+
*)
|
|
183
|
+
die "unknown level in manifest: $lvl"
|
|
184
|
+
;;
|
|
185
|
+
esac
|
|
186
|
+
printf 'sdlc: change %s ready under %s\n' "$slug" "$dest"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
cmd_status() {
|
|
190
|
+
need_manifest
|
|
191
|
+
warn_location
|
|
192
|
+
local lvl
|
|
193
|
+
lvl="$(level)"
|
|
194
|
+
printf 'level: %s\n' "$lvl"
|
|
195
|
+
printf 'sdlc dir: %s\n' "$SDLC_DIR"
|
|
196
|
+
printf 'repo: %s\n' "$REPO_ROOT"
|
|
197
|
+
if [[ -f "$REPO_ROOT/AGENTS.md" ]] && grep -F -q -- "$BEGIN" "$REPO_ROOT/AGENTS.md"; then
|
|
198
|
+
printf 'AGENTS.md: overlay present\n'
|
|
199
|
+
else
|
|
200
|
+
printf 'AGENTS.md: overlay missing (run install)\n'
|
|
201
|
+
fi
|
|
202
|
+
if [[ -d "$REPO_ROOT/.cursor/rules" ]]; then
|
|
203
|
+
printf 'rules:\n'
|
|
204
|
+
ls -1 "$REPO_ROOT/.cursor/rules"/sdlc-*.mdc 2>/dev/null || printf ' (no sdlc-*.mdc)\n'
|
|
205
|
+
fi
|
|
206
|
+
printf 'changes:\n'
|
|
207
|
+
if [[ -d "$SDLC_DIR/changes" ]]; then
|
|
208
|
+
local d
|
|
209
|
+
shopt -s nullglob
|
|
210
|
+
for d in "$SDLC_DIR/changes"/*/; do
|
|
211
|
+
printf ' %s\n' "$(basename -- "$d")"
|
|
212
|
+
done
|
|
213
|
+
shopt -u nullglob
|
|
214
|
+
fi
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main() {
|
|
218
|
+
local cmd="${1:-}"
|
|
219
|
+
[[ -n "$cmd" ]] || { usage; exit 1; }
|
|
220
|
+
shift || true
|
|
221
|
+
case "$cmd" in
|
|
222
|
+
install) cmd_install "$@" ;;
|
|
223
|
+
start) cmd_start "$@" ;;
|
|
224
|
+
status) cmd_status "$@" ;;
|
|
225
|
+
-h|--help|help) usage ;;
|
|
226
|
+
*) die "unknown command $cmd" ;;
|
|
227
|
+
esac
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
main "$@"
|