@mayurdluffy/ccwf 0.0.0-stage → 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.
Files changed (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -2
  3. package/bin/ccwf.js +7 -0
  4. package/lib/index.js +312 -0
  5. package/lib/installer.js +127 -0
  6. package/lib/machine.js +167 -0
  7. package/lib/merge.js +92 -0
  8. package/lib/modules.js +199 -0
  9. package/package.json +45 -4
  10. package/templates/agent-memory/MEMORY.md +4 -0
  11. package/templates/blocks/browser.md +9 -0
  12. package/templates/blocks/cbm.md +9 -0
  13. package/templates/blocks/core.md +35 -0
  14. package/templates/blocks/memory.md +7 -0
  15. package/templates/blocks/tracking.md +11 -0
  16. package/templates/blocks/workers.md +3 -0
  17. package/templates/cursor-cli.json +17 -0
  18. package/templates/cursor-rule.mdc +6 -0
  19. package/templates/docs/BACKLOG.md +4 -0
  20. package/templates/docs/DECISIONS.md +4 -0
  21. package/templates/docs/FEATURES.md +8 -0
  22. package/templates/docs/GLOSSARY.md +3 -0
  23. package/templates/docs/adr/.gitkeep +0 -0
  24. package/templates/docs/agents/domain.md +52 -0
  25. package/templates/docs/agents/issue-tracker.md +30 -0
  26. package/templates/docs/agents/setup.md +48 -0
  27. package/templates/docs/agents/triage-labels.md +15 -0
  28. package/templates/docs/agents/workflow.md +58 -0
  29. package/templates/machine.json +47 -0
  30. package/templates/skills/agent-browser/LICENSE +202 -0
  31. package/templates/skills/agent-browser/SKILL.md +51 -0
  32. package/templates/skills/commit/SKILL.md +77 -0
  33. package/templates/skills/orchestrate-workers/HC.md +10 -0
  34. package/templates/skills/orchestrate-workers/SKILL.md +138 -0
  35. package/templates/skills/orchestrate-workers/approve.sh +7 -0
  36. package/templates/skills/orchestrate-workers/claude-worker-settings.json +14 -0
  37. package/templates/skills/orchestrate-workers/end.sh +13 -0
  38. package/templates/skills/orchestrate-workers/grid.sh +24 -0
  39. package/templates/skills/orchestrate-workers/pane.sh +51 -0
  40. package/templates/skills/orchestrate-workers/watch.sh +42 -0
  41. package/templates/skills/orchestrate-workers/workers.conf +8 -0
  42. package/templates/skills/verify-ui/PLAYBOOK.md +81 -0
  43. package/templates/skills/verify-ui/SKILL.md +88 -0
  44. package/templates/skills/verify-ui/lib.sh +63 -0
  45. package/templates/skills/verify-ui/probe.sh +78 -0
  46. package/templates/skills/verify-ui/run.sh +113 -0
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env zsh
2
+ # Run browser scenarios with agent-browser and print one PASS/FAIL line each, then a SUITE line.
3
+ # Usage: run.sh <scenario.txt|dir> [...] BASE_URL comes from verify-ui.conf
4
+ # Exit 0 = all pass, 1 = a check failed, 2 = setup problem.
5
+ #
6
+ # Scenario lines (one per line; # comments and blank lines ignored; every expect waits up to 5s):
7
+ # open <path-or-url> navigate (a path is joined to BASE_URL)
8
+ # expect-text <text> the accessibility tree contains the text
9
+ # expect-no-text <text> the text stays absent for 1.5s
10
+ # expect-url <substring> the current URL contains it
11
+ # expect-visible <selector> the element is visible
12
+ # expect-count <selector> <n> exactly n elements match
13
+ # expect-value <selector> <text> an input holds exactly this value
14
+ # expect-storage <key> <substring> localStorage[key] contains it (what was really saved)
15
+ # expect-request <METHOD> <url-part> [status] the page made this request (the API was really called)
16
+ # expect-status <path> <code> HTTP status of a direct request, without the browser
17
+ # expect-eval <js expression> evaluates to true in the page
18
+ # expect-a11y [impacts] no axe violations of these impacts (default critical,serious)
19
+ # allow-console <regex> console errors matching this are expected in this scenario
20
+ # allow-request <regex> 4xx/5xx requests matching this are expected (e.g. a 401 check)
21
+ # shot <name> save a screenshot as evidence (a drawing, layout); path is printed
22
+ # <anything else> an agent-browser command, must succeed:
23
+ # find role button click --name "Save", fill, press, wait --text,
24
+ # set viewport 390 844, set offline on, network route <url> --abort
25
+ # Arguments with spaces: quote them where a command takes more than one (expect-value "#name" "Sam").
26
+ #
27
+ # After every scenario, automatically: no uncaught page errors, no console errors, no 4xx/5xx
28
+ # request to the app (unhandled promise rejections count as page errors). On FAIL the full tree, console,
29
+ # errors, network list and a screenshot are saved; the FAIL block prints the folder.
30
+ . ${0:A:h}/lib.sh
31
+ need_server
32
+
33
+ files=()
34
+ for a in "$@"; do
35
+ if [[ -d $a ]]; then files+=("$a"/*.txt(N)); else files+=("$a"); fi
36
+ done
37
+ (( ${#files} )) || { echo "SETUP: no scenario files"; exit 2; }
38
+
39
+ has_text() { tree | grep -qF -- "$1"; }
40
+ url_has() { [[ $(ab get url) == *$1* ]]; }
41
+ is_visible() { [[ $(ab is visible "$1") == true ]]; }
42
+ count_is() { [[ $(ab get count "$1") == $2 ]]; }
43
+ value_is() { [[ $(ab get value "$1") == $2 ]]; }
44
+ stored() { ab storage local "$1" | grep -qF -- "$2"; }
45
+ requested() { requests | grep -F -- "] $1 " | grep -F -- "$2" | grep -qE "\) ${3:-[0-9]*}\$"; }
46
+ js_true() { [[ $(ab eval -b "$(print -rn -- "$1" | base64)") == true ]]; }
47
+
48
+ passed=0; failed=0; S=""
49
+ trap '[[ -n $S ]] && ab close >/dev/null 2>&1' EXIT; trap 'exit 130' INT TERM # an interrupted run must not leave a browser behind
50
+ for f in $files; do
51
+ name=${f:t:r}; S=verify-$name-$$; out=$outroot/$name
52
+ step=0; fail=""; okcon=""; okreq=""; shots=()
53
+ rm -rf "$out"
54
+ while IFS= read -r line || [[ -n $line ]]; do
55
+ [[ -z ${line// } || $line == \#* ]] && continue
56
+ (( step++ ))
57
+ cmd=${line%% *}; arg=${line#* }; w=("${(@Q)${(z)arg}}")
58
+ case $cmd in
59
+ open) o=$(ab_open "$arg") || fail="open $arg: $(print -r -- "$o" | tail -1)" ;;
60
+ expect-text) poll has_text "$arg" || fail="text not found: $arg" ;;
61
+ expect-no-text) for i in 1 2 3; do has_text "$arg" && { fail="unexpected text: $arg"; break; }; sleep 0.5; done ;;
62
+ expect-url) poll url_has "$arg" || fail="url is $(ab get url), wanted *$arg*" ;;
63
+ expect-visible) poll is_visible "$arg" || fail="not visible: $arg" ;;
64
+ expect-count) poll count_is "${(j: :)w[1,-2]}" "$w[-1]" || fail="count of ${(j: :)w[1,-2]} is $(ab get count "${(j: :)w[1,-2]}"), wanted $w[-1]" ;;
65
+ expect-value) poll value_is "$w[1]" "${(j: :)w[2,-1]}" || fail="value of $w[1] is '$(ab get value "$w[1]")', wanted '${(j: :)w[2,-1]}'" ;;
66
+ expect-storage) poll stored "$w[1]" "${(j: :)w[2,-1]}" || fail="localStorage $w[1] lacks '${(j: :)w[2,-1]}': $(ab storage local "$w[1]" | short)" ;;
67
+ expect-request) poll requested "$w[1]" "$w[2]" "$w[3]" || fail="no $w[1] request matching '$w[2]'${w[3]:+ with status $w[3]}; api calls seen: $(api_requests | tail -3 | short | tr '\n' ' ')" ;;
68
+ expect-status) got=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "$base$w[1]")
69
+ [[ $got == $w[2] ]] || fail="$w[1] returned $got, wanted $w[2]" ;;
70
+ expect-eval) poll js_true "$arg" || fail="not true: $arg" ;;
71
+ expect-a11y) [[ $arg == $cmd ]] && arg=critical,serious
72
+ v=$(ab a11y | grep -E "^\[(${arg//,/|})\]" | short)
73
+ [[ -n $v ]] && fail="accessibility: $(print -r -- "$v" | head -4 | tr '\n' ' ')" ;;
74
+ allow-console) okcon=${okcon:+$okcon|}$arg ;;
75
+ allow-request) okreq=${okreq:+$okreq|}$arg ;;
76
+ shot) mkdir -p "$out"; o=$(ab screenshot "$out/$arg.png") && shots+=("$out/$arg.png") || fail="screenshot: $o" ;;
77
+ *) o=$(eval "ab $line") || fail="'$line' failed: $(print -r -- "$o" | tail -2 | tr '\n' ' ')" ;;
78
+ esac
79
+ [[ -n $fail ]] && { fail="step $step: $fail"; break; }
80
+ done < "$f"
81
+
82
+ if [[ -z $fail ]]; then
83
+ e=$(page_errors | head -3 | short)
84
+ [[ -n $e ]] && fail="page errors: $e"
85
+ fi
86
+ if [[ -z $fail ]]; then
87
+ e=$(console_of error | grep -vE -- "${okcon:-^$}" | sort -u | head -3 | short)
88
+ [[ -n $e ]] && fail="console errors: $e"
89
+ fi
90
+ if [[ -z $fail ]]; then
91
+ e=$(bad_requests | grep -vE -- "${okreq:-^$}" | head -3 | short)
92
+ [[ -n $e ]] && fail="failed requests: $e"
93
+ fi
94
+
95
+ # Build the result first and print it after the browser is closed, so a reader that stops
96
+ # early (| head) cannot strand the browser.
97
+ if [[ -n $fail ]]; then
98
+ rep="FAIL $name: $fail"$'\n'" url: $(ab get url)"$'\n'"$(itree | head -15 | short | sed 's/^/ | /')"
99
+ evidence "$out"; ab screenshot "$out/fail.png" >/dev/null
100
+ rep+=$'\n'" evidence: $out (tree.txt console.txt errors.txt network.txt fail.png)"
101
+ (( failed++ ))
102
+ else
103
+ warn=$(console_of warning | wc -l | tr -d ' ')
104
+ (( warn )) && warn=", $warn console warnings" || warn=""
105
+ rep="PASS $name ($step steps$warn)"
106
+ (( ${#shots} )) && rep+=$'\n'" shots: $shots"
107
+ (( passed++ ))
108
+ fi
109
+ ab close >/dev/null 2>&1; S=""
110
+ print -r -- "$rep"
111
+ done
112
+ echo "SUITE: $passed passed, $failed failed"
113
+ (( failed == 0 ))