lastlight 0.4.0 → 0.5.1
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 +17 -6
- package/deploy/entrypoint.sh +21 -6
- package/deploy/sandbox-entrypoint.sh +1 -1
- package/dist/config.d.ts +12 -1
- package/dist/config.js +26 -6
- package/dist/config.js.map +1 -1
- package/dist/connectors/messaging/base.js +22 -9
- package/dist/connectors/messaging/base.js.map +1 -1
- package/dist/connectors/slack/connector.d.ts +62 -9
- package/dist/connectors/slack/connector.js +216 -63
- package/dist/connectors/slack/connector.js.map +1 -1
- package/dist/connectors/slack/connector.test.d.ts +1 -0
- package/dist/connectors/slack/connector.test.js +135 -0
- package/dist/connectors/slack/connector.test.js.map +1 -0
- package/dist/connectors/types.d.ts +7 -0
- package/dist/engine/agent-executor.d.ts +32 -10
- package/dist/engine/agent-executor.js +239 -1
- package/dist/engine/agent-executor.js.map +1 -1
- package/dist/engine/agent-executor.seam.test.d.ts +1 -0
- package/dist/engine/agent-executor.seam.test.js +57 -0
- package/dist/engine/agent-executor.seam.test.js.map +1 -0
- package/dist/engine/dispatcher.d.ts +13 -0
- package/dist/engine/dispatcher.js +26 -7
- package/dist/engine/dispatcher.js.map +1 -1
- package/dist/engine/dispatcher.test.js.map +1 -1
- package/dist/engine/message-batcher.d.ts +32 -0
- package/dist/engine/message-batcher.js +109 -0
- package/dist/engine/message-batcher.js.map +1 -0
- package/dist/engine/message-batcher.test.d.ts +1 -0
- package/dist/engine/message-batcher.test.js +109 -0
- package/dist/engine/message-batcher.test.js.map +1 -0
- package/dist/engine/profiles.d.ts +9 -0
- package/dist/engine/profiles.js.map +1 -1
- package/dist/evals-api.d.ts +24 -0
- package/dist/evals-api.js +22 -0
- package/dist/evals-api.js.map +1 -0
- package/dist/index.js +41 -4
- package/dist/index.js.map +1 -1
- package/dist/sandbox/command-exec.integration.test.d.ts +1 -0
- package/dist/sandbox/command-exec.integration.test.js +183 -0
- package/dist/sandbox/command-exec.integration.test.js.map +1 -0
- package/dist/sandbox/docker.d.ts +32 -0
- package/dist/sandbox/docker.js +109 -4
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/workflows/loader.test.js +83 -0
- package/dist/workflows/loader.test.js.map +1 -1
- package/dist/workflows/phase-executor.d.ts +28 -3
- package/dist/workflows/phase-executor.js +170 -45
- package/dist/workflows/phase-executor.js.map +1 -1
- package/dist/workflows/phase-executor.test.js +64 -1
- package/dist/workflows/phase-executor.test.js.map +1 -1
- package/dist/workflows/runner.test.js +32 -27
- package/dist/workflows/runner.test.js.map +1 -1
- package/dist/workflows/schema.d.ts +20 -0
- package/dist/workflows/schema.js +72 -2
- package/dist/workflows/schema.js.map +1 -1
- package/package.json +12 -2
- package/sandbox.Dockerfile +7 -0
- package/skills/browser-qa/scripts/agent-browser.mjs +15 -0
- package/skills/demo/SKILL.md +45 -19
- package/skills/demo/scripts/compose-demo.sh +77 -39
- package/workflows/examples/bash-smoke.yaml +41 -0
- package/workflows/prompts/demo.md +27 -5
- package/workflows/qa-test.yaml +1 -1
- package/workflows/verify.yaml +1 -1
|
@@ -9,16 +9,19 @@
|
|
|
9
9
|
# compose-demo.sh --output demo.mp4 --title "PR #42 — Add dark mode" \
|
|
10
10
|
# [--subtitle "..."] [--layout single|side-by-side] \
|
|
11
11
|
# [--labels "BEFORE (main)" "AFTER (PR)"] [--speed 1.5] \
|
|
12
|
-
# [--trim START:END] [--target-size-mb
|
|
13
|
-
# [--title-secs 2.5] <clip1.webm> [clip2.webm]
|
|
12
|
+
# [--trim START:END] [--target-size-mb 10] [--crf 18] \
|
|
13
|
+
# [--width 1920] [--height 1080] [--title-secs 2.5] <clip1.webm> [clip2.webm]
|
|
14
14
|
#
|
|
15
15
|
# What it does:
|
|
16
16
|
# 1. Normalizes each input clip (optional trim, speed-up, scale+pad to the
|
|
17
|
-
# panel size, fps/pixfmt/SAR normalize, optional per-panel
|
|
17
|
+
# panel size with lanczos, fps/pixfmt/SAR normalize, optional per-panel
|
|
18
|
+
# label).
|
|
18
19
|
# 2. Lays out the body: a single panel, or two panels side-by-side (hstack).
|
|
19
20
|
# 3. Prepends a title/subtitle card (solid bg + drawtext).
|
|
20
|
-
# 4.
|
|
21
|
-
#
|
|
21
|
+
# 4. Quality-first H.264 encode: a single-pass CRF encode (sharp for UI
|
|
22
|
+
# screencasts) that usually lands well under --target-size-mb; only if it
|
|
23
|
+
# overshoots does it fall back to a size-targeted two-pass ABR encode.
|
|
24
|
+
# yuv420p + +faststart for web streaming.
|
|
22
25
|
# 5. Prints an ffprobe summary (resolution / duration / size).
|
|
23
26
|
#
|
|
24
27
|
# Prerequisites: ffmpeg, ffprobe (baked into lastlight-sandbox-qa:latest).
|
|
@@ -40,9 +43,10 @@ LABEL1=""
|
|
|
40
43
|
LABEL2=""
|
|
41
44
|
SPEED="1"
|
|
42
45
|
TRIM=""
|
|
43
|
-
TARGET_MB="
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
TARGET_MB="10"
|
|
47
|
+
CRF="18"
|
|
48
|
+
WIDTH="1920"
|
|
49
|
+
HEIGHT="1080"
|
|
46
50
|
TITLE_SECS="2.5"
|
|
47
51
|
CLIPS=()
|
|
48
52
|
|
|
@@ -57,6 +61,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
57
61
|
--speed) SPEED="$2"; shift 2;;
|
|
58
62
|
--trim) TRIM="$2"; shift 2;;
|
|
59
63
|
--target-size-mb) TARGET_MB="$2"; shift 2;;
|
|
64
|
+
--crf) CRF="$2"; shift 2;;
|
|
60
65
|
--width) WIDTH="$2"; shift 2;;
|
|
61
66
|
--height) HEIGHT="$2"; shift 2;;
|
|
62
67
|
--title-secs) TITLE_SECS="$2"; shift 2;;
|
|
@@ -94,11 +99,19 @@ if [[ -n "$FONT" ]]; then FONTARG="fontfile=${FONT}"; else FONTARG="font=Sans";
|
|
|
94
99
|
# gracefully on a build without it (omit text overlays) rather than failing the
|
|
95
100
|
# whole compose — the demo video is still worth shipping.
|
|
96
101
|
HAS_DRAWTEXT=0
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
# Detect the drawtext filter WITHOUT a pipe. Under `set -o pipefail`, any
|
|
103
|
+
# `ffmpeg -filters | grep -q drawtext` (or even `printf "$var" | grep -q`) is a
|
|
104
|
+
# false-negative trap: `grep -q` exits on the first match and closes the pipe,
|
|
105
|
+
# the writer (still emitting — `drawtext` sits ~16 KB into ~38 KB of output)
|
|
106
|
+
# dies with SIGPIPE (141), and `pipefail` promotes that to the pipeline's exit
|
|
107
|
+
# status, so the `if` wrongly concludes drawtext is absent (~19 of 20 runs).
|
|
108
|
+
# Capture into a variable and match with a pure bash `case` — no subprocess,
|
|
109
|
+
# no pipe, no SIGPIPE.
|
|
110
|
+
FFMPEG_FILTERS="$(ffmpeg -hide_banner -filters 2>/dev/null || true)"
|
|
111
|
+
case "$FFMPEG_FILTERS" in
|
|
112
|
+
*drawtext*) HAS_DRAWTEXT=1 ;;
|
|
113
|
+
*) echo "compose-demo.sh: warning: this ffmpeg lacks the drawtext filter — title card and labels omitted." >&2 ;;
|
|
114
|
+
esac
|
|
102
115
|
|
|
103
116
|
# Panel size: side-by-side splits the width into two equal panels.
|
|
104
117
|
PH="$HEIGHT"
|
|
@@ -115,17 +128,19 @@ build_panel() {
|
|
|
115
128
|
[[ -n "$end" ]] && trim_args+=(-to "$end")
|
|
116
129
|
fi
|
|
117
130
|
local vf="setpts=PTS/${SPEED}"
|
|
118
|
-
vf+=",scale=${PW}:${PH}:force_original_aspect_ratio=decrease"
|
|
131
|
+
vf+=",scale=${PW}:${PH}:force_original_aspect_ratio=decrease:flags=lanczos"
|
|
119
132
|
vf+=",pad=${PW}:${PH}:(ow-iw)/2:(oh-ih)/2:color=black"
|
|
120
133
|
vf+=",fps=30,format=yuv420p,setsar=1"
|
|
121
134
|
if [[ -n "$labelfile" && "$HAS_DRAWTEXT" == "1" ]]; then
|
|
122
|
-
|
|
123
|
-
|
|
135
|
+
# Anchor labels to the TOP of the panel. At the bottom they're hidden behind
|
|
136
|
+
# the browser/GitHub video player's control bar (scrubber + play button).
|
|
137
|
+
vf+=",drawtext=${FONTARG}:textfile=${labelfile}:x=(w-text_w)/2:y=28"
|
|
138
|
+
vf+=":fontsize=34:fontcolor=white:box=1:boxcolor=black@0.55:boxborderw=14"
|
|
124
139
|
fi
|
|
125
140
|
# `${arr[@]+"${arr[@]}"}` expands to nothing when the array is empty without
|
|
126
141
|
# tripping `set -u` (an empty `"${arr[@]}"` errors on bash < 4.4, e.g. macOS).
|
|
127
142
|
ffmpeg -y -loglevel error ${trim_args[@]+"${trim_args[@]}"} -i "$input" \
|
|
128
|
-
-vf "$vf" -an -c:v libx264 -crf
|
|
143
|
+
-vf "$vf" -an -c:v libx264 -crf "$CRF" -preset medium "$outfile"
|
|
129
144
|
}
|
|
130
145
|
|
|
131
146
|
# Per-panel labels (side-by-side) written to files to avoid drawtext escaping.
|
|
@@ -140,9 +155,16 @@ build_panel "${CLIPS[0]}" "$WORK/panel0.mp4" "$LABELFILE1" 1
|
|
|
140
155
|
BODY="$WORK/body.mp4"
|
|
141
156
|
if [[ "$LAYOUT" == "side-by-side" ]]; then
|
|
142
157
|
build_panel "${CLIPS[1]}" "$WORK/panel1.mp4" "$LABELFILE2" 1
|
|
158
|
+
# Pad the shorter panel by freezing its last frame so both stay aligned for the
|
|
159
|
+
# full body. Without this, hstack lets the shorter side end early and go
|
|
160
|
+
# blank/black — which reads as "the before didn't render".
|
|
161
|
+
D0="$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$WORK/panel0.mp4" || echo 0)"
|
|
162
|
+
D1="$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$WORK/panel1.mp4" || echo 0)"
|
|
163
|
+
PAD0="$(awk -v a="$D0" -v b="$D1" 'BEGIN{d=b-a; if(d<0)d=0; printf "%.3f", d}')"
|
|
164
|
+
PAD1="$(awk -v a="$D0" -v b="$D1" 'BEGIN{d=a-b; if(d<0)d=0; printf "%.3f", d}')"
|
|
143
165
|
ffmpeg -y -loglevel error -i "$WORK/panel0.mp4" -i "$WORK/panel1.mp4" \
|
|
144
|
-
-filter_complex "[0:v][1:v]hstack=inputs=2,format=yuv420p,setsar=1[v]" \
|
|
145
|
-
-map "[v]" -an -c:v libx264 -crf
|
|
166
|
+
-filter_complex "[0:v]tpad=stop_mode=clone:stop_duration=${PAD0}[p0];[1:v]tpad=stop_mode=clone:stop_duration=${PAD1}[p1];[p0][p1]hstack=inputs=2,format=yuv420p,setsar=1[v]" \
|
|
167
|
+
-map "[v]" -an -c:v libx264 -crf "$CRF" -preset medium "$BODY"
|
|
146
168
|
else
|
|
147
169
|
BODY="$WORK/panel0.mp4"
|
|
148
170
|
fi
|
|
@@ -159,25 +181,14 @@ if [[ "$HAS_DRAWTEXT" == "1" ]]; then
|
|
|
159
181
|
fi
|
|
160
182
|
TITLE_VF+=",format=yuv420p"
|
|
161
183
|
ffmpeg -y -loglevel error -f lavfi -i "color=c=0x101418:s=${WIDTH}x${HEIGHT}:d=${TITLE_SECS}:r=30" \
|
|
162
|
-
-vf "$TITLE_VF" -c:v libx264 -crf
|
|
184
|
+
-vf "$TITLE_VF" -c:v libx264 -crf "$CRF" -preset medium "$WORK/title.mp4"
|
|
163
185
|
TITLE_CLIP="$WORK/title.mp4"
|
|
164
186
|
TITLE_DUR="$TITLE_SECS"
|
|
165
187
|
fi
|
|
166
188
|
|
|
167
|
-
# ── Stage C: (concat title +) body
|
|
168
|
-
BODY_DUR="$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$BODY" || echo 0)"
|
|
169
|
-
TOTAL_DUR="$(awk -v a="$TITLE_DUR" -v b="$BODY_DUR" 'BEGIN{printf "%.3f", a + b}')"
|
|
170
|
-
# Target video bitrate (kbit/s) = target_bytes * 8 / duration / 1000, with a
|
|
171
|
-
# small headroom factor for the muxer; floored so very short clips still encode.
|
|
172
|
-
BR_K="$(awk -v mb="$TARGET_MB" -v d="$TOTAL_DUR" 'BEGIN{
|
|
173
|
-
if (d <= 0) d = 1;
|
|
174
|
-
br = (mb * 1024 * 1024 * 8) / d / 1000 * 0.92;
|
|
175
|
-
if (br < 200) br = 200;
|
|
176
|
-
printf "%d", br;
|
|
177
|
-
}')"
|
|
178
|
-
|
|
189
|
+
# ── Stage C: (concat title +) body → final mp4 ───────────────────────────────
|
|
179
190
|
# With a title card: concat it ahead of the body. Without: pass the body
|
|
180
|
-
# through (`null`) so the same
|
|
191
|
+
# through (`null`) so the same encode applies either way.
|
|
181
192
|
if [[ -n "$TITLE_CLIP" ]]; then
|
|
182
193
|
IN_ARGS=(-i "$TITLE_CLIP" -i "$BODY")
|
|
183
194
|
FILTER='[0:v][1:v]concat=n=2:v=1:a=0[v]'
|
|
@@ -185,16 +196,43 @@ else
|
|
|
185
196
|
IN_ARGS=(-i "$BODY")
|
|
186
197
|
FILTER='[0:v]null[v]'
|
|
187
198
|
fi
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
199
|
+
|
|
200
|
+
# Quality-first: a single-pass CRF encode (visually crisp for UI screencasts —
|
|
201
|
+
# constant quality, not a starved average bitrate) usually lands well under the
|
|
202
|
+
# size cap. The old always-two-pass-ABR path starved short, near-static clips
|
|
203
|
+
# down to a few tens of KB; CRF spends the bits the content needs.
|
|
204
|
+
echo "compose-demo.sh: encoding (crf ${CRF}, preset slow)…" >&2
|
|
193
205
|
ffmpeg -y -loglevel error "${IN_ARGS[@]}" \
|
|
194
206
|
-filter_complex "$FILTER" -map "[v]" -an \
|
|
195
|
-
-c:v libx264 -
|
|
207
|
+
-c:v libx264 -crf "$CRF" -preset slow \
|
|
196
208
|
-pix_fmt yuv420p -movflags +faststart "$OUTPUT"
|
|
197
209
|
|
|
210
|
+
# Size cap: only if the quality encode overshoots --target-size-mb do we redo it
|
|
211
|
+
# as a size-targeted two-pass ABR encode (keeps it under GitHub's inline limit).
|
|
212
|
+
OUT_BYTES="$(wc -c < "$OUTPUT" | tr -d ' ')"
|
|
213
|
+
CAP_BYTES="$(awk -v mb="$TARGET_MB" 'BEGIN{printf "%d", mb*1024*1024}')"
|
|
214
|
+
if [[ "$OUT_BYTES" -gt "$CAP_BYTES" ]]; then
|
|
215
|
+
BODY_DUR="$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$BODY" || echo 0)"
|
|
216
|
+
TOTAL_DUR="$(awk -v a="$TITLE_DUR" -v b="$BODY_DUR" 'BEGIN{printf "%.3f", a + b}')"
|
|
217
|
+
# Target video bitrate (kbit/s) = target_bytes * 8 / duration / 1000, with a
|
|
218
|
+
# small headroom factor for the muxer; floored so very short clips still encode.
|
|
219
|
+
BR_K="$(awk -v mb="$TARGET_MB" -v d="$TOTAL_DUR" 'BEGIN{
|
|
220
|
+
if (d <= 0) d = 1;
|
|
221
|
+
br = (mb * 1024 * 1024 * 8) / d / 1000 * 0.92;
|
|
222
|
+
if (br < 200) br = 200;
|
|
223
|
+
printf "%d", br;
|
|
224
|
+
}')"
|
|
225
|
+
PASSLOG="$WORK/ff2pass"
|
|
226
|
+
echo "compose-demo.sh: crf encode was $(awk -v b="$OUT_BYTES" 'BEGIN{printf "%.1f", b/1024/1024}')MB > ${TARGET_MB}MB cap — re-encoding size-capped (${TOTAL_DUR}s → ${BR_K}kbit/s, two-pass)…" >&2
|
|
227
|
+
ffmpeg -y -loglevel error "${IN_ARGS[@]}" \
|
|
228
|
+
-filter_complex "$FILTER" -map "[v]" -an \
|
|
229
|
+
-c:v libx264 -b:v "${BR_K}k" -pass 1 -passlogfile "$PASSLOG" -preset medium -f mp4 /dev/null
|
|
230
|
+
ffmpeg -y -loglevel error "${IN_ARGS[@]}" \
|
|
231
|
+
-filter_complex "$FILTER" -map "[v]" -an \
|
|
232
|
+
-c:v libx264 -b:v "${BR_K}k" -pass 2 -passlogfile "$PASSLOG" -preset medium \
|
|
233
|
+
-pix_fmt yuv420p -movflags +faststart "$OUTPUT"
|
|
234
|
+
fi
|
|
235
|
+
|
|
198
236
|
# ── Stage D: report ───────────────────────────────────────────────────────────
|
|
199
237
|
RES="$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0:s=x "$OUTPUT" || echo '?')"
|
|
200
238
|
DUR="$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$OUTPUT" || echo '?')"
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
kind: agent
|
|
2
|
+
name: bash-smoke
|
|
3
|
+
description: "Smoke test for deterministic bash + script phases (run in sandbox)"
|
|
4
|
+
phases:
|
|
5
|
+
- name: phase_0
|
|
6
|
+
type: context
|
|
7
|
+
|
|
8
|
+
# Deterministic shell command in the sandbox. stdout is captured and exposed
|
|
9
|
+
# downstream via output_var.
|
|
10
|
+
- name: emit
|
|
11
|
+
type: bash
|
|
12
|
+
command: "echo hello-from-bash"
|
|
13
|
+
output_var: greeting
|
|
14
|
+
|
|
15
|
+
# A second bash phase reads the first phase's output via template substitution
|
|
16
|
+
# AND via the forwarded LL_OUT_<PHASE> env var.
|
|
17
|
+
- name: consume
|
|
18
|
+
type: bash
|
|
19
|
+
command: "echo template={{phaseOutputs.emit}} ; echo env=$LL_OUT_EMIT"
|
|
20
|
+
|
|
21
|
+
# Inline JS via node.
|
|
22
|
+
- name: js
|
|
23
|
+
type: script
|
|
24
|
+
runtime: js
|
|
25
|
+
script: |
|
|
26
|
+
console.log("node version:", process.version);
|
|
27
|
+
console.log("answer:", 6 * 7);
|
|
28
|
+
|
|
29
|
+
# Inline Python via uv. The PEP 723 block declares a dependency that uv
|
|
30
|
+
# resolves from PyPI (pypi.org is on the strict egress allowlist) into a
|
|
31
|
+
# cached venv. unrestricted_egress is NOT needed for PyPI.
|
|
32
|
+
- name: py
|
|
33
|
+
type: script
|
|
34
|
+
runtime: python
|
|
35
|
+
timeout_seconds: 120
|
|
36
|
+
script: |
|
|
37
|
+
# /// script
|
|
38
|
+
# dependencies = ["cowsay"]
|
|
39
|
+
# ///
|
|
40
|
+
import cowsay
|
|
41
|
+
cowsay.cow("hello from uv")
|
|
@@ -44,11 +44,33 @@ so `doctor` should pass.
|
|
|
44
44
|
|
|
45
45
|
## Workspace + run the app
|
|
46
46
|
|
|
47
|
-
You are already inside the **{{repo}}** repo
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
You are already inside the **{{repo}}** repo — the harness pre-cloned it and your
|
|
48
|
+
cwd is the repo root (no `cd`){{#if baseBranch}}, **checked out at the PR head
|
|
49
|
+
branch `{{branch}}`**, so the workspace already holds the PR's code: this checkout
|
|
50
|
+
*is* your "after" state{{/if}}. Follow the `building` skill to install
|
|
51
|
+
dependencies and start the dev-server in the background; poll with `curl` until
|
|
52
|
+
it answers on `localhost:<port>`.
|
|
53
|
+
|
|
54
|
+
{{#if baseBranch}}**This is a PR → record a `side-by-side` before/after.** Record
|
|
55
|
+
the **after** first, straight from the current checkout (`{{branch}}`) — do not
|
|
56
|
+
re-checkout for it. Then record the **before** from the base branch
|
|
57
|
+
`{{baseBranch}}`. The pre-clone is shallow + single-branch, so the base isn't
|
|
58
|
+
present locally yet — fetch it explicitly by ref (never trust an ambiguously
|
|
59
|
+
named local branch):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
git fetch --depth 1 origin {{baseBranch}}
|
|
63
|
+
git checkout -B {{baseBranch}}-base FETCH_HEAD
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Re-run `building`'s install + restart the dev-server after switching. When you
|
|
67
|
+
composite, the **first** clip is the left/BEFORE panel and the **second** is the
|
|
68
|
+
right/AFTER panel.
|
|
69
|
+
|
|
70
|
+
**Verify before you ship:** the disambiguating change must actually appear in the
|
|
71
|
+
*after* recording and be absent from the *before* (use the driver's `text`/
|
|
72
|
+
`assertText` to read it on both). If both states look identical, your checkout is
|
|
73
|
+
wrong — STOP and fix it; do not ship a side-by-side that proves nothing.{{/if}}
|
|
52
74
|
|
|
53
75
|
## Capture and compose
|
|
54
76
|
|
package/workflows/qa-test.yaml
CHANGED
|
@@ -76,7 +76,7 @@ phases:
|
|
|
76
76
|
# workflow-level `final_message`. Pure composition — no skills, no repo work.
|
|
77
77
|
- name: synthesize
|
|
78
78
|
label: Summary
|
|
79
|
-
depends_on: [qa_test]
|
|
79
|
+
depends_on: [qa_test, qa_browser]
|
|
80
80
|
prompt: prompts/qa-synth.md
|
|
81
81
|
model: "{{models.qa-test}}"
|
|
82
82
|
variant: "{{variants.qa-test}}"
|
package/workflows/verify.yaml
CHANGED
|
@@ -74,7 +74,7 @@ phases:
|
|
|
74
74
|
# workflow-level `final_message`. Pure composition — no skills, no repo work.
|
|
75
75
|
- name: synthesize
|
|
76
76
|
label: Summary
|
|
77
|
-
depends_on: [verify]
|
|
77
|
+
depends_on: [verify, verify_browser]
|
|
78
78
|
prompt: prompts/verify-synth.md
|
|
79
79
|
model: "{{models.verify}}"
|
|
80
80
|
variant: "{{variants.verify}}"
|