@sassywares/skills 0.5.2 → 0.5.4
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/README.md +14 -8
- package/package.json +1 -1
- package/skills/sassy-babysit/SKILL.md +5 -3
- package/skills/sassy-commit/SKILL.md +1 -1
- package/skills/sassy-commit-push-pr/SKILL.md +5 -3
- package/skills/sassy-setup/assets/sassywares-readme.md +1 -1
- package/skills/sassy-setup/references/config.md +20 -8
- package/skills/sassy-setup/scripts/detect.sh +29 -7
- package/skills/sassy-ship/SKILL.md +2 -2
package/README.md
CHANGED
|
@@ -133,8 +133,11 @@ knowledge:
|
|
|
133
133
|
write: true # false = this project takes no learnings
|
|
134
134
|
git:
|
|
135
135
|
repo: origin # a remote name | workspace (repos below, none here) | none (no git)
|
|
136
|
-
#
|
|
137
|
-
|
|
136
|
+
base_map: # head branch -> the base it targets
|
|
137
|
+
"*": staging # ordinary work branches from and targets staging
|
|
138
|
+
staging: main # staging releases to main
|
|
139
|
+
# remote: owner/backup # workspace only: the snapshot mirror
|
|
140
|
+
# mirror_branch: main # workspace only: the mirror's branch
|
|
138
141
|
repos: # workspace only: each nested repo -> the base its PRs target
|
|
139
142
|
fe: dev
|
|
140
143
|
commit:
|
|
@@ -143,17 +146,20 @@ pr:
|
|
|
143
146
|
babysit: true
|
|
144
147
|
merge: false # true authorizes merging every babysat PR here
|
|
145
148
|
delete_branch: false
|
|
146
|
-
hooks:
|
|
149
|
+
hooks:
|
|
147
150
|
pr:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
151
|
+
"*": # keyed by the PR's HEAD branch
|
|
152
|
+
before_create: [tap2-version mode:auto] # after the commit, before the PR opens
|
|
153
|
+
after_create: [] # the moment the PR exists
|
|
154
|
+
before_merge: [] # this run is about to merge
|
|
155
|
+
after_merge: [] # this run observed the merge
|
|
156
|
+
staging: # a per-point override for one head
|
|
157
|
+
before_create: []
|
|
152
158
|
```
|
|
153
159
|
|
|
154
160
|
### Extending the pipeline
|
|
155
161
|
|
|
156
|
-
A project adds its own steps by naming a skill that lives in its own `.agents/skills/`. Nothing declared means nothing runs.
|
|
162
|
+
A project adds its own steps by naming a skill that lives in its own `.agents/skills/`. Nothing declared means nothing runs. Keys are the **head** branch — the one a PR comes from — and every point can be overridden per head; entries may carry args (`<skill> <args…>`).
|
|
157
163
|
|
|
158
164
|
| Hook | Runs | Typical use |
|
|
159
165
|
|---|---|---|
|
package/package.json
CHANGED
|
@@ -21,7 +21,9 @@ Keep an open PR moving toward merge by reacting to three streams as each arrives
|
|
|
21
21
|
|
|
22
22
|
An explicit token always beats the config.
|
|
23
23
|
|
|
24
|
-
**Config.** Resolve `.sassywares/config.yaml` (nearest, walking up) per the `sassy-setup` skill's `references/config.md`. Precedence: explicit token > session instruction > config > skill default. `pr.*` seeds `merge` and `delete_branch`;
|
|
24
|
+
**Config.** Resolve `.sassywares/config.yaml` (nearest, walking up) per the `sassy-setup` skill's `references/config.md`. Precedence: explicit token > session instruction > config > skill default. `pr.*` seeds `merge` and `delete_branch`; merge hooks come from `hooks.pr` for this run's head.
|
|
25
|
+
|
|
26
|
+
**Keys are the head branch.** Resolve per head: the exact head, then the longest matching family (`release/*`), then `"*"`. Each point overrides independently. An entry is `<skill> <args…>` — split on the first whitespace and pass the args verbatim.
|
|
25
27
|
|
|
26
28
|
**One PR per run.** This skill watches the PR resolved from the argument or the current branch. A workspace fan-out is N runs, one per PR, and `pr.merge` never merges a fan-out — that needs an explicit say-so per PR.
|
|
27
29
|
|
|
@@ -35,7 +37,7 @@ An explicit token always beats the config.
|
|
|
35
37
|
|
|
36
38
|
Snapshot the PR state first, then act in this order:
|
|
37
39
|
|
|
38
|
-
1. **Terminal** — `MERGED`/`CLOSED` → if it is `MERGED` and `
|
|
40
|
+
1. **Terminal** — `MERGED`/`CLOSED` → if it is `MERGED` and `after_merge` resolves for this PR's head, run those hooks once (see Step 3) before stopping.
|
|
39
41
|
2. **Capture the head SHA** — a later push invalidates this snapshot's CI.
|
|
40
42
|
3. **Feedback before CI** — fetch open review threads (`gh pr view --json reviewThreads,comments`). Address each actionable thread: reply, then fix. Use `sassy-debug` for a real defect. Never wait for a reviewer who is "still reviewing" before acting on feedback already posted.
|
|
41
43
|
4. **Stale-SHA cancellation** — if the head moved since step 2, skip the CI work for this snapshot.
|
|
@@ -50,7 +52,7 @@ Stop when any holds:
|
|
|
50
52
|
- **Terminal** — merged or closed.
|
|
51
53
|
- **Looks ready** — `MERGEABLE`, `CLEAN`, all checks terminal, no open review threads, no currency blocker, zero `needs-human` items. With `merge:on`, run the merge (and `delete-branch:on` branch deletion if set) before treating this as a stop; the merge turns it into the **Terminal** stop.
|
|
52
54
|
|
|
53
|
-
**Merge hooks.** Immediately before merging,
|
|
55
|
+
**Merge hooks.** Immediately before merging, resolve `before_merge` for this PR's head and run each entry in declared order — one `worker` per hook, with the same brief every hook gets: plan path, changed files, artifact paths, base, branch, commit hash, and the PR URL plus head SHA. These run before the merge, so they must leave the tree clean. A missing skill or a `blocked` result means **do not merge**: report it and stop at Blocked. After a successful merge, resolve `after_merge` for this PR's head and run each entry the same way; these follow the merge, so they must leave the tree clean. In a workspace fan-out, everything is per PR.
|
|
54
56
|
|
|
55
57
|
**Which merge hook fires.** `before_merge` needs a merge this run will perform. `after_merge` fires whenever this run observes the PR merged, including one that was already merged when the run started — so it must be idempotent.
|
|
56
58
|
|
|
@@ -30,7 +30,7 @@ Treat the reads as a snapshot; re-read branch and staged set right before commit
|
|
|
30
30
|
|
|
31
31
|
**Config.** Resolve `.sassywares/config.yaml` (nearest, walking up) per the `sassy-setup` skill's `references/config.md`. Precedence: explicit token > session instruction > config > skill default. `commit.branch` supplies the default.
|
|
32
32
|
|
|
33
|
-
**Branch option.** `branch:current|new [<name>]`. `current` commits on the checked-out branch. `new` cuts a branch from `origin/<base>` — `<base>` is `
|
|
33
|
+
**Branch option.** `branch:current|new [<name>]`. `current` commits on the checked-out branch. `new` cuts a branch from `origin/<base>` — `<base>` is `base_map` from the repo's own config when it has one, else `repos[<dir>]` from the workspace config, else the probed base **confirmed with the user** — named `<name>` when given, else from the change. `sassy-commit-push-pr` forwards its own `branch` choice here.
|
|
34
34
|
|
|
35
35
|
**Not in a workspace root, not outside git.** With `git.repo: workspace` there is no local commit to make: refuse in one line and name the snapshot instead. With `git.repo: none`, refuse and say the project is deliberately outside git. Inside a nested repo, a normal commit is correct — the nearest work tree is the repo.
|
|
36
36
|
|
|
@@ -16,7 +16,9 @@ disable-model-invocation: true
|
|
|
16
16
|
|
|
17
17
|
**Options.** `branch:new|current` selects the branch policy below. `babysit:on|off` (default `on`) controls the closing babysit. `checkpoint` bounds that babysit to a single tick. `merge:on|off` and `delete-branch:on|off` (both default `off`) are forwarded unchanged to `sassy-babysit`.
|
|
18
18
|
|
|
19
|
-
**Config.** Resolve `.sassywares/config.yaml` (nearest, walking up) per the `sassy-setup` skill's `references/config.md`. Precedence: explicit token > session instruction > config > skill default. `commit.branch` seeds the branch policy, `pr.*` seeds the babysit options, and `hooks.pr
|
|
19
|
+
**Config.** Resolve `.sassywares/config.yaml` (nearest, walking up) per the `sassy-setup` skill's `references/config.md`. Precedence: explicit token > session instruction > config > skill default. `commit.branch` seeds the branch policy, `pr.*` seeds the babysit options, and `hooks.pr` supplies the `before_create` / `after_create` steps for this run's head.
|
|
20
|
+
|
|
21
|
+
**Keys are the head branch.** Resolve per head: the exact head, then the longest matching family (`release/*`), then `"*"`. Each point overrides independently. An entry is `<skill> <args…>` — split on the first whitespace and pass the args verbatim.
|
|
20
22
|
|
|
21
23
|
## Context
|
|
22
24
|
|
|
@@ -37,14 +39,14 @@ Only an exit-0 empty list means "no open PR". A non-zero exit means **unknown**
|
|
|
37
39
|
|
|
38
40
|
**Branch policy.** Default: if on the base branch or detached HEAD, create a feature branch named from the work and say so. `branch:current` or a plain request keeps the checked-out branch (that run pushes and skips the PR). Never ask whether to branch. Forward the resolved choice to `sassy-commit`: `branch:new <name>` when this run creates a branch, else `branch:current`.
|
|
39
41
|
|
|
40
|
-
**Base branch.** `<base>` is `
|
|
42
|
+
**Base branch.** `<base>` is `base_map[<current head>]` from the nearest config — a nested repo's own config wins over the workspace's `repos[<dir>]` — falling back to `base_map["*"]`, else the probed remote HEAD **confirmed with the user before use**. The map is the reason a release PR targets `main` while the work sits on `staging`, with no token passed. An explicit `base:<branch>` token wins over all of them — use it when this PR targets something other than the day-to-day base, such as a release PR aimed at `main` while work lands on `staging`. **Never use `defaultBranchRef` as the PR base when the config names one.** Pass it explicitly: `gh pr create --base <base>`.
|
|
41
43
|
|
|
42
44
|
**Refused topologies.** From a `workspace` root there is no single PR to open — refuse in one line and point at `sassy-ship`, which owns the per-repo fan-out. With `git.repo: none`, refuse and say why. Neither ever pushes directly to a base branch.
|
|
43
45
|
|
|
44
46
|
## Steps
|
|
45
47
|
|
|
46
48
|
1. **Commit** — follow `sassy-commit` with the branch choice from the policy above (named files only, outcome-stating message). Honor an `exclude:<paths>` token if present.
|
|
47
|
-
2. **`before_create` hooks.**
|
|
49
|
+
2. **`before_create` hooks.** Resolve `before_create` for the head branch (`base_map` decides the base, the head is the branch you are on); empty means skip. Split each entry on the first whitespace — the first token is the skill, the rest are its args. Run each name in declared order, one `worker` per hook, whose task is *read `<repo>/.agents/skills/<name>/SKILL.md` and follow it* plus a brief: plan path, changed files, artifact paths, base, branch, and the commit hash. This point runs **after** the commit, so a hook may write and commit its own artifacts — push whatever ends up on the branch. A missing skill or a `blocked` result stops the run and names the hook; a `needs-decision` result comes back to you to present.
|
|
48
50
|
3. **Pre-push gate** — resolve any pre-push or review-ready requirement from the project's active instructions. Only evidence valid for the exact commit being sent satisfies it; otherwise stop and report what is missing. If none, proceed.
|
|
49
51
|
4. **Push** — `git push -u origin <branch>` for a new branch, else `git push`. Re-verify branch and remote first, and re-check that the branch is ahead of origin after any hook commits.
|
|
50
52
|
5. **Compose the PR title and body**
|
|
@@ -31,4 +31,4 @@ If a skill tells you another skill is missing, run `skills:sync` and restart. Su
|
|
|
31
31
|
|
|
32
32
|
## Hooks
|
|
33
33
|
|
|
34
|
-
`hooks.pr
|
|
34
|
+
`hooks.pr` names project skills that run inside the PR pipeline, keyed by the PR's **head** branch: `"*"` for every PR, an exact branch, or a family such as `release/*`, overriding per point (`before_create`, `after_create`, `before_merge`, `after_merge`). An entry is `<skill> <args…>`; the args mean whatever that skill says they mean — `mode:auto` pre-authorizes the step. Hooks are ordinary skills in `.agents/skills/`, which makes them **code**: review them like code, and never point a hook at a copy of a suite skill.
|
|
@@ -157,8 +157,9 @@ feature/x --base_map["*"]--> staging --base_map[staging]--> main
|
|
|
157
157
|
```
|
|
158
158
|
|
|
159
159
|
1. `base_map[<head>]` — the exact rung
|
|
160
|
-
2. `
|
|
161
|
-
3.
|
|
160
|
+
2. the longest matching family key (`release/*`) — a nested rung
|
|
161
|
+
3. `base_map["*"]` — ordinary work
|
|
162
|
+
4. stop and ask; never guess
|
|
162
163
|
|
|
163
164
|
A rung is a release edge: standing on `staging`, a PR targets `main` without
|
|
164
165
|
anyone passing `base:main`. Add a rung for any branch that releases elsewhere; a
|
|
@@ -169,10 +170,21 @@ The probed remote default is only useful as a hint for `"*"`: it tells you where
|
|
|
169
170
|
the repository considers work to land, not what every branch targets. Confirm it
|
|
170
171
|
before writing.
|
|
171
172
|
|
|
173
|
+
`--head <branch>` prints the resolution for one head: the base (repo topology)
|
|
174
|
+
and all four hook points. Use it instead of merging maps by hand.
|
|
175
|
+
|
|
172
176
|
In a `workspace`, `base_map` does not apply — there are no branches at the
|
|
173
|
-
workspace level.
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
workspace level. A nested repo's base resolves in this order:
|
|
178
|
+
|
|
179
|
+
1. that repo's own `.sassywares/config.yaml` → `base_map` — **authoritative**
|
|
180
|
+
2. `repos[<dir>]` in the workspace config — the inventory, and the fallback for a
|
|
181
|
+
repo that carries no config
|
|
182
|
+
3. stop and ask
|
|
183
|
+
|
|
184
|
+
`repos` exists because a workspace can hold repos you do not own and cannot add a
|
|
185
|
+
config to. When a repo has both, the nested config wins and `--check` reports
|
|
186
|
+
the disagreement rather than picking silently. A nested config needs no ladder
|
|
187
|
+
of its own unless its PRs target more than one branch.
|
|
176
188
|
|
|
177
189
|
**Branch name**, one per run. Derived once from the plan slug or topic before the
|
|
178
190
|
first commit, then passed to every repo. Multi-repo runs pass
|
|
@@ -230,9 +242,9 @@ Per point, independently:
|
|
|
230
242
|
3. `"*"`
|
|
231
243
|
|
|
232
244
|
The first rule that declares a value for that point wins and the rest are not
|
|
233
|
-
merged
|
|
234
|
-
`after_merge` from `"*"`.
|
|
235
|
-
|
|
245
|
+
merged, so a `staging` entry that sets only `before_create` still inherits
|
|
246
|
+
`after_merge` from `"*"`. When two families match one head, the longer prefix
|
|
247
|
+
wins — `release/v2/*` beats `release/*`.
|
|
236
248
|
|
|
237
249
|
### Entries carry arguments
|
|
238
250
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
#
|
|
7
7
|
# Usage:
|
|
8
8
|
# detect.sh [--root DIR] print a proposed config to stdout
|
|
9
|
+
# detect.sh [--head BRANCH] resolve the base and hooks for one head
|
|
9
10
|
# detect.sh [--root DIR] --check compare the existing config to reality
|
|
10
11
|
set -euo pipefail
|
|
11
12
|
|
|
@@ -130,10 +131,13 @@ yaml_flat() {
|
|
|
130
131
|
path = ""
|
|
131
132
|
for (i = 1; i <= sp; i++) if (sd[i] < d) path = path (path == "" ? "" : us) sk[i]
|
|
132
133
|
print path (path == "" ? "" : us) key "\t" val
|
|
133
|
-
}' "$CONFIG"
|
|
134
|
+
}' "${1:-$CONFIG}"
|
|
134
135
|
}
|
|
135
136
|
|
|
136
|
-
yflat() { yaml_flat | awk -F'\t' -v p="$1" '$1 == p { print $2; exit }'; }
|
|
137
|
+
yflat() { yaml_flat "$CONFIG" | awk -F'\t' -v p="$1" '$1 == p { print $2; exit }'; }
|
|
138
|
+
|
|
139
|
+
# yflat_in FILE PATH — the same reader against another config file.
|
|
140
|
+
yflat_in() { yaml_flat "$1" | awk -F'\t' -v p="$2" '$1 == p { print $2; exit }'; }
|
|
137
141
|
|
|
138
142
|
list_items() {
|
|
139
143
|
printf '%s' "$1" | sed -e 's/^\[//' -e 's/\]$//' | tr ',' '\n' \
|
|
@@ -154,7 +158,7 @@ map_match() {
|
|
|
154
158
|
if [[ "$head" == "$stem"* ]] && (( ${#stem} > bestlen )); then
|
|
155
159
|
best="$pat"; bestlen=${#stem}
|
|
156
160
|
fi
|
|
157
|
-
done < <(yaml_flat | awk -F'\t' -v us="$US" -v sec="$section" \
|
|
161
|
+
done < <(yaml_flat "$CONFIG" | awk -F'\t' -v us="$US" -v sec="$section" \
|
|
158
162
|
'{n=split($1,a,us); if (n==3 && a[1]=="git" && a[2]==sec) print a[3]}' | sort -u)
|
|
159
163
|
if [[ -n "$best" ]]; then
|
|
160
164
|
v="$(yflat "git${US}${section}${US}${best}")"
|
|
@@ -290,6 +294,9 @@ if (( CHECK )); then
|
|
|
290
294
|
fi
|
|
291
295
|
|
|
292
296
|
if [[ "$TOPOLOGY" == "repo" ]]; then
|
|
297
|
+
if [[ -n "$(yflat "git${US}remote")" ]]; then
|
|
298
|
+
bad "git.remote is workspace-only — a repo config names its remote in git.repo"
|
|
299
|
+
fi
|
|
293
300
|
if [[ -z "$(yflat "git${US}base_map${US}*")" ]]; then
|
|
294
301
|
bad "git.base_map has no \"*\" entry — it is the base for ordinary work"
|
|
295
302
|
else
|
|
@@ -299,7 +306,7 @@ if (( CHECK )); then
|
|
|
299
306
|
"*") ;;
|
|
300
307
|
*"*") [[ "${pat%\*}" != *"*" ]] || bad "base_map key '$pat': only one trailing * is allowed" ;;
|
|
301
308
|
esac
|
|
302
|
-
done < <(yaml_flat | awk -F'\t' -v us="$US" '{n=split($1,a,us); if (n==3 && a[1]=="git" && a[2]=="base_map") print a[3]}' | sort -u)
|
|
309
|
+
done < <(yaml_flat "$CONFIG" | awk -F'\t' -v us="$US" '{n=split($1,a,us); if (n==3 && a[1]=="git" && a[2]=="base_map") print a[3]}' | sort -u)
|
|
303
310
|
head_ref="${HEAD_ARG:-$(git -C "$ROOT" branch --show-current 2>/dev/null || true)}"
|
|
304
311
|
if [[ -n "$head_ref" ]]; then
|
|
305
312
|
# the --head readout below prints this line; avoid printing it twice
|
|
@@ -339,8 +346,22 @@ if (( CHECK )); then
|
|
|
339
346
|
[[ -n "$name" ]] || continue
|
|
340
347
|
base="$(detect_base "$ROOT/$name")"
|
|
341
348
|
listed="$(block_value repos "$name" || true)"
|
|
342
|
-
|
|
343
|
-
|
|
349
|
+
# A nested repo's own config is authoritative; `repos` is the inventory and
|
|
350
|
+
# the fallback for repos that have none.
|
|
351
|
+
nested="$ROOT/$name/.sassywares/config.yaml"
|
|
352
|
+
nested_base=""
|
|
353
|
+
[[ -f "$nested" ]] && nested_base="$(yflat_in "$nested" "git${US}base_map${US}*")"
|
|
354
|
+
|
|
355
|
+
if [[ -n "$nested_base" ]]; then
|
|
356
|
+
if [[ -n "$listed" && "$listed" != "$nested_base" ]]; then
|
|
357
|
+
bad "repos.$name is '$listed' but $name/.sassywares/config.yaml maps \"*\" to '$nested_base' — the nested config wins; fix or drop the repos entry"
|
|
358
|
+
elif [[ -z "$listed" ]]; then
|
|
359
|
+
note " $name: base '$nested_base' from its own config (no repos entry needed)"
|
|
360
|
+
else
|
|
361
|
+
note " $name: base '$nested_base' (agrees with its own config)"
|
|
362
|
+
fi
|
|
363
|
+
elif [[ -z "$listed" ]]; then
|
|
364
|
+
bad "repos has no entry for '$name' and $name carries no config (remote default: ${base:-unknown})"
|
|
344
365
|
elif [[ -n "$base" && "$listed" != "$base" ]]; then
|
|
345
366
|
note " repos.$name '$listed' overrides the remote default '$base' — expected for an integration branch"
|
|
346
367
|
fi
|
|
@@ -454,7 +475,8 @@ EOF
|
|
|
454
475
|
else
|
|
455
476
|
printf ' "*": %s # base for ordinary work; never guessed\n' "<confirm by hand>"
|
|
456
477
|
fi
|
|
457
|
-
printf ' # staging: main
|
|
478
|
+
printf ' # staging: main # uncomment when a branch releases somewhere else\n'
|
|
479
|
+
printf ' # release/*: main # a family of heads, longest prefix wins\n'
|
|
458
480
|
cat <<'EOF'
|
|
459
481
|
|
|
460
482
|
# workspace only: each nested repo folder -> the base its PRs target
|
|
@@ -22,14 +22,14 @@ disable-model-invocation: true
|
|
|
22
22
|
|
|
23
23
|
## Steps (in order)
|
|
24
24
|
|
|
25
|
-
1. **Review gate.** In `mode:manual` only: present a compact shipping summary — the plan or topic, the changes from the cycle results, the docs the close-out expects to write, the branch/PR target, the babysit options, and **the hooks this run
|
|
25
|
+
1. **Review gate.** In `mode:manual` only: present a compact shipping summary — the plan or topic, the changes from the cycle results, the docs the close-out expects to write, the branch/PR target, the babysit options, and **the hooks resolved for this run's head — point, skill, and args — or that none are declared** — and wait. In `mode:auto`, skip this gate.
|
|
26
26
|
2. **Compound (conditional).** If the work produced a qualifying learning, dispatch a `worker` whose task is: *load the `sassy-compound` skill and follow it with `mode:auto`* — with a compact learnings brief (the solved problems, root causes, and solutions taken from the cycle results, not from re-reading the tree). It always gets `mode:auto` because ship's own gate already covered the approval. Skip cleanly when nothing qualifies, and skip entirely when `knowledge.write` is `false`.
|
|
27
27
|
3. **Handbook (conditional).** If the feature is self-contained and independent enough that a teammate would benefit from a handover, dispatch a `worker` whose task is: *load the `sassy-handbook` skill and follow it* — with the plan path and topic. The worker reads the tree itself. Skip for small or tightly-coupled changes.
|
|
28
28
|
4. **Commit or snapshot.** After the review gate — never before it — the docs and any remaining code become durable.
|
|
29
29
|
- **`git.repo` is a remote.** Dispatch a `worker`: *load the `sassy-commit` skill and follow it*, naming that the commit must include the plan, any new solutions docs, the concepts file, `AGENTS.md`, and any handbook just written — resolved from `artifacts.*`, never hardcoded. Use `branch:current` when already on a feature branch, so the docs land with the phase commits. When the checked-out branch is the base branch, use `branch:new <name>` so the branch is created from `origin/<base>` and carries every phase commit; a workspace run passes the run's shared branch name. Never push directly to the base branch. It returns the hash and subject.
|
|
30
30
|
- **`git.repo: workspace`.** Commit code inside each affected repo on the run's shared branch (cut once on the run's first commit, `branch:current` after), then run `.sassywares/workspace/snapshot`. The snapshot is the workspace's commit and it runs every time, right after approval. A missing or outdated `.sassywares/workspace/snapshot` is a blocker: report it and say to run `sassy-setup`.
|
|
31
31
|
- **`git.repo: none`.** No commit exists here. Report that the work is not persisted and stop.
|
|
32
|
-
5. **PR.** In a `remote` repo, dispatch a `worker`: *load the `sassy-commit-push-pr` skill and follow it with `branch:current` and `babysit:off`, forwarding `base:<branch>` when the caller supplied one* (step 6 owns the babysit). It returns the PR URL. In a `workspace`, open one PR per affected repo — the same branch name in each, `--base` from that repo's `repos` entry — and return a table. A touched repo missing from `repos`, or a base that cannot be resolved, is a stop-and-ask, never a guess. `none` opens nothing.
|
|
32
|
+
5. **PR.** In a `remote` repo, dispatch a `worker`: *load the `sassy-commit-push-pr` skill and follow it with `branch:current` and `babysit:off`, forwarding `base:<branch>` when the caller supplied one* (step 6 owns the babysit). It returns the PR URL. In a `workspace`, open one PR per affected repo — the same branch name in each, `--base` from that repo's own `base_map` when it carries a `.sassywares/config.yaml`, else its `repos` entry — and return a table. A touched repo missing from `repos`, or a base that cannot be resolved, is a stop-and-ask, never a guess. `none` opens nothing.
|
|
33
33
|
|
|
34
34
|
**The PR step owns the PR hooks.** `before_create` and `after_create` run inside `sassy-commit-push-pr`, once per PR; ship neither runs nor repeats them.
|
|
35
35
|
6. **Babysit.** With `pr.babysit` (default `true`), dispatch a `worker`: *load the `sassy-babysit` skill and follow it for the PR just created, one checkpoint*, forwarding any `merge:on|off` and `delete-branch:on|off` the caller supplied, else `pr.merge` and `pr.delete_branch`. It reports looks-ready or blocked. For a continuous watch, tell the user to run `sassy-babysit` in-session.
|