@1agh/maude 0.19.1 → 0.20.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 (49) hide show
  1. package/package.json +9 -9
  2. package/plugins/design/dev-server/annotations-context-toolbar.tsx +112 -38
  3. package/plugins/design/dev-server/annotations-layer.tsx +204 -95
  4. package/plugins/design/dev-server/artboard-marquee.tsx +8 -4
  5. package/plugins/design/dev-server/bin/asset-sweep.sh +180 -0
  6. package/plugins/design/dev-server/bin/visual-sanity.sh +221 -0
  7. package/plugins/design/dev-server/canvas-lib.tsx +506 -30
  8. package/plugins/design/dev-server/canvas-shell.tsx +352 -20
  9. package/plugins/design/dev-server/client/hmr.mjs +28 -0
  10. package/plugins/design/dev-server/commands/annotation-strokes-command.ts +127 -0
  11. package/plugins/design/dev-server/commands/equal-spacing-command.ts +28 -0
  12. package/plugins/design/dev-server/commands/move-artboards-command.ts +158 -0
  13. package/plugins/design/dev-server/comments-overlay.tsx +12 -4
  14. package/plugins/design/dev-server/contextual-toolbar.tsx +241 -0
  15. package/plugins/design/dev-server/dist/client.bundle.js +3 -3
  16. package/plugins/design/dev-server/dist/runtime/motion.js +165 -0
  17. package/plugins/design/dev-server/dist/runtime/motion_react.js +409 -0
  18. package/plugins/design/dev-server/equal-spacing-detector.ts +98 -0
  19. package/plugins/design/dev-server/equal-spacing-handles.tsx +289 -0
  20. package/plugins/design/dev-server/handoff.ts +24 -0
  21. package/plugins/design/dev-server/http.ts +27 -0
  22. package/plugins/design/dev-server/input-router.tsx +52 -2
  23. package/plugins/design/dev-server/marquee-overlay.tsx +282 -0
  24. package/plugins/design/dev-server/runtime-bundle.ts +7 -0
  25. package/plugins/design/dev-server/test/annotation-strokes-command.test.ts +149 -0
  26. package/plugins/design/dev-server/test/annotations-layer.test.ts +44 -0
  27. package/plugins/design/dev-server/test/canvas-lib-motion.test.ts +131 -0
  28. package/plugins/design/dev-server/test/equal-spacing-detector.test.ts +93 -0
  29. package/plugins/design/dev-server/test/input-router.test.ts +87 -1
  30. package/plugins/design/dev-server/test/marquee-overlay.test.ts +94 -0
  31. package/plugins/design/dev-server/test/move-artboards-command.test.ts +108 -0
  32. package/plugins/design/dev-server/test/undo-stack.test.ts +211 -0
  33. package/plugins/design/dev-server/test/use-cursor-modifiers.test.ts +59 -0
  34. package/plugins/design/dev-server/test/use-keyboard-discipline.test.ts +27 -0
  35. package/plugins/design/dev-server/test/use-undo-stack.test.tsx +193 -0
  36. package/plugins/design/dev-server/undo-hud.tsx +95 -0
  37. package/plugins/design/dev-server/undo-stack.ts +240 -0
  38. package/plugins/design/dev-server/use-artboard-drag.tsx +6 -3
  39. package/plugins/design/dev-server/use-cursor-modifiers.tsx +122 -0
  40. package/plugins/design/dev-server/use-keyboard-discipline.tsx +125 -0
  41. package/plugins/design/dev-server/use-undo-stack.tsx +355 -0
  42. package/plugins/design/templates/_shell.html +17 -6
  43. package/plugins/design/templates/design-system-inspiration/SUB-AGENT-PROMPTS.md +245 -0
  44. package/plugins/design/templates/design-system-inspiration/_MAPPING.md +2 -2
  45. package/plugins/design/templates/design-system-inspiration/core/preview/_components.css.tpl +129 -0
  46. package/plugins/design/templates/design-system-inspiration/core/preview/_motion-readme.md.tpl +63 -0
  47. package/plugins/design/templates/design-system-inspiration/core/preview/motion.css.tpl +106 -0
  48. package/plugins/design/templates/design-system-inspiration/core/preview/motion.tsx.tpl +208 -0
  49. /package/plugins/design/templates/design-system-inspiration/core/preview/{motion.html → .archive/motion.html} +0 -0
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env bash
2
+ # asset-sweep.sh — pre-scaffold real-asset sweep for `/design:setup-ds`.
3
+ # Greps a target repo for production sources of logo/mark/wordmark/mascot/glyph/
4
+ # illustration BEFORE Batch A authors any placeholder. Single hit at a
5
+ # conventional path → copy 1:1. Multiple hits → caller asks user via
6
+ # AskUserQuestion. Zero hits → THEN placeholder authorship is permitted.
7
+ #
8
+ # Closes D-2 in the studyfi imprint-bootstrap retro (placeholder bleed).
9
+ # Spec: `.ai/plans/phase-3.7-setup-ds-hardening-and-motion-subsystem.md` Task 1.
10
+ #
11
+ # Usage:
12
+ # asset-sweep.sh --root <repo> [--query "logo,mark,wordmark,mascot,glyph,illustration"]
13
+ # [--depth 6] [--ext "svg,png"]
14
+ #
15
+ # Defaults:
16
+ # --query "logo,mark,wordmark,mascot,glyph,illustration"
17
+ # --depth 6 (`find -maxdepth`; capped to keep monorepo sweeps < 2s)
18
+ # --ext "svg" (svg-only by default — production marks are vector)
19
+ #
20
+ # Output: one JSON object on stdout, e.g.
21
+ # { "logo": ["packages/ui/src/components/ui/logo/logo.svg"],
22
+ # "mark": [],
23
+ # "wordmark": [],
24
+ # "mascot": [],
25
+ # "glyph": ["packages/ui/.../glyphs/sparkle.svg",
26
+ # "packages/ui/.../glyphs/check.svg"],
27
+ # "illustration": [] }
28
+ #
29
+ # Paths are relative to --root. Sorted lexicographically. Duplicates removed.
30
+ # Excludes: node_modules/, .git/, .design/_history/, .next/, dist/, build/.
31
+ #
32
+ # Exit: 0 always (zero hits is a valid result, not an error). 2 = bad args.
33
+
34
+ ROOT=""
35
+ QUERY="logo,mark,wordmark,mascot,glyph,illustration"
36
+ DEPTH=6
37
+ EXT="svg"
38
+
39
+ while [ $# -gt 0 ]; do
40
+ case "$1" in
41
+ --root) ROOT="$2"; shift 2 ;;
42
+ --query) QUERY="$2"; shift 2 ;;
43
+ --depth) DEPTH="$2"; shift 2 ;;
44
+ --ext) EXT="$2"; shift 2 ;;
45
+ --help|-h)
46
+ sed -n '2,30p' "$0" | sed 's/^# \?//'
47
+ exit 0
48
+ ;;
49
+ *)
50
+ echo "asset-sweep.sh: unknown arg '$1' (try --help)" >&2
51
+ exit 2
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ if [ -z "$ROOT" ]; then
57
+ echo "asset-sweep.sh: --root <repo> required" >&2
58
+ exit 2
59
+ fi
60
+ if [ ! -d "$ROOT" ]; then
61
+ echo "asset-sweep.sh: --root '$ROOT' is not a directory" >&2
62
+ exit 2
63
+ fi
64
+
65
+ # Resolve --root to an absolute path so the relative-path strip below is stable
66
+ # regardless of caller cwd.
67
+ ROOT_ABS=$(cd "$ROOT" && pwd)
68
+
69
+ # Build the find -name predicate for the extension list.
70
+ # EXT="svg,png" → \( -name "*.svg" -o -name "*.png" \)
71
+ ext_predicate=()
72
+ IFS=',' read -r -a EXT_ARR <<< "$EXT"
73
+ ext_predicate+=("(")
74
+ first=1
75
+ for e in "${EXT_ARR[@]}"; do
76
+ e_trim=$(echo "$e" | tr -d '[:space:]')
77
+ [ -z "$e_trim" ] && continue
78
+ if [ $first -eq 1 ]; then
79
+ ext_predicate+=("-name" "*.$e_trim")
80
+ first=0
81
+ else
82
+ ext_predicate+=("-o" "-name" "*.$e_trim")
83
+ fi
84
+ done
85
+ ext_predicate+=(")")
86
+
87
+ # Single find pass; bucket by noun in-memory. Earlier per-noun-find walked the
88
+ # tree N times (6× for default query) — ~4s on a 20k-file repo. Single pass
89
+ # pushes us under the 2s/50k budget from the phase plan.
90
+ #
91
+ # Match policy (case-insensitive): a file is bucketed under noun N if N appears
92
+ # as a substring of the basename OR as a path segment in the parent chain
93
+ # (catches `packages/ui/.../logo/logo.svg` AND `assets/glyphs/foo.svg`).
94
+
95
+ # Normalize nouns once.
96
+ IFS=',' read -r -a NOUNS <<< "$QUERY"
97
+ declare -a NOUNS_LC=()
98
+ for n in "${NOUNS[@]}"; do
99
+ n_trim=$(echo "$n" | tr -d '[:space:]')
100
+ [ -z "$n_trim" ] && continue
101
+ NOUNS_LC+=("$(printf '%s' "$n_trim" | tr '[:upper:]' '[:lower:]')")
102
+ done
103
+
104
+ # Buckets keyed by noun. Bash 4+ supports declare -A; macOS ships bash 3.2
105
+ # by default — fall back to a per-noun delimiter-joined string in flat vars.
106
+ declare -a BUCKETS=()
107
+ for _ in "${NOUNS_LC[@]}"; do BUCKETS+=(""); done
108
+
109
+ # Walk once. Prune vendor/build dirs to keep the tree small.
110
+ while IFS= read -r f; do
111
+ [ -z "$f" ] && continue
112
+ rel="${f#"$ROOT_ABS"/}"
113
+ base="${f##*/}"
114
+ base_lc=$(printf '%s' "$base" | tr '[:upper:]' '[:lower:]')
115
+ parent="${f%/*}"
116
+ parent_lc=$(printf '%s' "$parent" | tr '[:upper:]' '[:lower:]')
117
+ i=0
118
+ for noun in "${NOUNS_LC[@]}"; do
119
+ matched=0
120
+ case "$base_lc" in *"$noun"*) matched=1 ;; esac
121
+ if [ $matched -eq 0 ]; then
122
+ case "$parent_lc" in
123
+ *"/$noun"*|*"/$noun"|*"/${noun}s"*|*"/${noun}s") matched=1 ;;
124
+ esac
125
+ fi
126
+ if [ $matched -eq 1 ]; then
127
+ if [ -z "${BUCKETS[$i]}" ]; then
128
+ BUCKETS[$i]="$rel"
129
+ else
130
+ BUCKETS[$i]="${BUCKETS[$i]}"$'\n'"$rel"
131
+ fi
132
+ fi
133
+ i=$((i + 1))
134
+ done
135
+ done < <(
136
+ find "$ROOT_ABS" \
137
+ -maxdepth "$DEPTH" \
138
+ \( \
139
+ -path "*/node_modules" -o \
140
+ -path "*/.git" -o \
141
+ -path "*/.design/_history" -o \
142
+ -path "*/.next" -o \
143
+ -path "*/dist" -o \
144
+ -path "*/build" -o \
145
+ -path "*/coverage" -o \
146
+ -path "*/.turbo" -o \
147
+ -path "*/.cache" \
148
+ \) -prune -o \
149
+ -type f \
150
+ "${ext_predicate[@]}" \
151
+ -print 2>/dev/null
152
+ )
153
+
154
+ # JSON emission. Avoid jq as a hard dep (matches server-up.sh's defensive
155
+ # posture) — the JSON shape is small + predictable.
156
+ printf '{'
157
+ first=1
158
+ i=0
159
+ for noun in "${NOUNS_LC[@]}"; do
160
+ if [ $first -eq 0 ]; then printf ','; fi
161
+ first=0
162
+ printf '\n "%s": [' "$noun"
163
+ if [ -n "${BUCKETS[$i]}" ]; then
164
+ # Sort + dedupe, then JSON-emit.
165
+ printf '\n'
166
+ ln_first=1
167
+ while IFS= read -r hit; do
168
+ [ -z "$hit" ] && continue
169
+ esc=$(printf '%s' "$hit" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')
170
+ if [ $ln_first -eq 0 ]; then printf ',\n'; fi
171
+ ln_first=0
172
+ printf ' "%s"' "$esc"
173
+ done < <(printf '%s\n' "${BUCKETS[$i]}" | sort -u)
174
+ printf '\n ]'
175
+ else
176
+ printf ']'
177
+ fi
178
+ i=$((i + 1))
179
+ done
180
+ printf '\n}\n'
@@ -0,0 +1,221 @@
1
+ #!/usr/bin/env bash
2
+ # visual-sanity.sh — mandatory post-scaffold visual sanity gate for
3
+ # `/design:setup-ds`. Boots the dev-server (via server-up.sh), screenshots
4
+ # N specimens (via screenshot.sh) into `_history/_system/<ds>-visual-sanity-
5
+ # <ISO>/`, and exits non-zero on any failure so the caller can surface an
6
+ # `AskUserQuestion` ("dev-server boot failed: <reason> — skip visual sanity
7
+ # or fix and retry?"). Never silently elides the gate.
8
+ #
9
+ # Closes D-3 + D-4 in the imprint-bootstrap retro (sparkle overflow + broken
10
+ # relative-URL asset path — both would have been caught by one screenshot read).
11
+ # Spec: `.ai/plans/phase-3.7-setup-ds-hardening-and-motion-subsystem.md` Task 2.
12
+ #
13
+ # Usage:
14
+ # visual-sanity.sh --ds <ds-name>
15
+ # [--specimens "colors-accent,motion,logo"]
16
+ # [--root <repo>] [--out-dir <dir>]
17
+ # [--boot-timeout 15] [--shot-timeout 5]
18
+ # [--engine auto|agent-browser|playwright]
19
+ #
20
+ # Defaults:
21
+ # --root "$CLAUDE_PROJECT_DIR" → "$(git rev-parse --show-toplevel)" → cwd
22
+ # --specimens "colors-accent,motion,ui_kits-desktop-showcase"
23
+ # (signature trio — accent / motion / DS-in-use)
24
+ # caller may override with the roster-derived list of actually-
25
+ # written specimens to avoid screenshotting files that don't
26
+ # exist on the disk yet.
27
+ # --out-dir "<root>/.design/_history/_system/<ds>-visual-sanity-<ISO>"
28
+ # --boot-timeout 15 (server-up.sh polling window, in seconds)
29
+ # --shot-timeout 5 (screenshot.sh DC-mount poll window per specimen; bare
30
+ # DS-preview specimens have no [data-dc-screen] so the
31
+ # poll always exhausts — 5s is plenty for the page-load
32
+ # settle without burning 15s × N on every gate run)
33
+ #
34
+ # Output: one PNG path per line on stdout (composable in for-loops); the caller
35
+ # is expected to `Read` each PNG into context so the agent ACTUALLY SEES
36
+ # what shipped. JSON manifest written alongside as `_manifest.json`.
37
+ # Stderr: diagnostic, engine choice, timing, failure reasons.
38
+ # Exit:
39
+ # 0 success — all specimens screenshot successfully
40
+ # 1 dev-server boot failed (caller MUST surface AskUserQuestion)
41
+ # 2 bad args
42
+ # 3 one or more specimen screenshots failed
43
+ # 4 no specimens existed on disk (DS not scaffolded? typo?)
44
+
45
+ DS=""
46
+ SPECIMENS=""
47
+ ROOT=""
48
+ OUT_DIR=""
49
+ BOOT_TIMEOUT=15
50
+ SHOT_TIMEOUT=5
51
+ ENGINE="auto"
52
+
53
+ while [ $# -gt 0 ]; do
54
+ case "$1" in
55
+ --ds) DS="$2"; shift 2 ;;
56
+ --specimens) SPECIMENS="$2"; shift 2 ;;
57
+ --root) ROOT="$2"; shift 2 ;;
58
+ --out-dir) OUT_DIR="$2"; shift 2 ;;
59
+ --boot-timeout) BOOT_TIMEOUT="$2"; shift 2 ;;
60
+ --shot-timeout) SHOT_TIMEOUT="$2"; shift 2 ;;
61
+ --timeout) BOOT_TIMEOUT="$2"; SHOT_TIMEOUT="$2"; shift 2 ;; # legacy
62
+ --engine) ENGINE="$2"; shift 2 ;;
63
+ --help|-h)
64
+ sed -n '2,33p' "$0" | sed 's/^# \?//'
65
+ exit 0
66
+ ;;
67
+ *)
68
+ echo "visual-sanity.sh: unknown arg '$1' (try --help)" >&2
69
+ exit 2
70
+ ;;
71
+ esac
72
+ done
73
+
74
+ if [ -z "$DS" ]; then
75
+ echo "visual-sanity.sh: --ds <ds-name> required" >&2
76
+ exit 2
77
+ fi
78
+
79
+ # Resolve repo root.
80
+ if [ -z "$ROOT" ]; then
81
+ ROOT="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
82
+ fi
83
+ if [ ! -d "$ROOT" ]; then
84
+ echo "visual-sanity.sh: --root '$ROOT' is not a directory" >&2
85
+ exit 2
86
+ fi
87
+ ROOT_ABS=$(cd "$ROOT" && pwd)
88
+
89
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
90
+
91
+ DESIGN_ROOT="$ROOT_ABS/.design"
92
+ DS_PREVIEW="$DESIGN_ROOT/system/$DS/preview"
93
+ if [ ! -d "$DS_PREVIEW" ]; then
94
+ echo "visual-sanity.sh: preview directory not found at $DS_PREVIEW" >&2
95
+ echo " (is the DS scaffolded? did you mean a different --ds value?)" >&2
96
+ exit 4
97
+ fi
98
+
99
+ # Default specimen list: the signature trio (accent, motion, DS-in-use).
100
+ # Caller can pass a roster-derived list to override.
101
+ if [ -z "$SPECIMENS" ]; then
102
+ SPECIMENS="colors-accent,motion,ui_kits-desktop-showcase"
103
+ fi
104
+
105
+ # Filter specimens to those that actually exist on disk — the trio is a
106
+ # default that not every DS will have written (e.g. an early scaffold may
107
+ # not have ui_kits-* yet). Silently skipping a non-existent specimen is OK;
108
+ # the caller logs which ones we attempted vs. captured.
109
+ declare -a EXISTING=()
110
+ declare -a MISSING=()
111
+ IFS=',' read -r -a SPEC_ARR <<< "$SPECIMENS"
112
+ for s in "${SPEC_ARR[@]}"; do
113
+ s_trim=$(echo "$s" | tr -d '[:space:]')
114
+ [ -z "$s_trim" ] && continue
115
+ if [ -f "$DS_PREVIEW/${s_trim}.tsx" ]; then
116
+ EXISTING+=("$s_trim")
117
+ else
118
+ MISSING+=("$s_trim")
119
+ fi
120
+ done
121
+ if [ ${#EXISTING[@]} -eq 0 ]; then
122
+ echo "visual-sanity.sh: none of the requested specimens exist on disk under $DS_PREVIEW" >&2
123
+ printf ' missing: %s\n' "${MISSING[@]}" >&2
124
+ exit 4
125
+ fi
126
+ if [ ${#MISSING[@]} -gt 0 ]; then
127
+ echo "visual-sanity.sh: skipping ${#MISSING[@]} non-existent specimen(s): ${MISSING[*]}" >&2
128
+ fi
129
+
130
+ # ISO-like timestamp safe for filenames (no colons / spaces).
131
+ TS=$(date -u +"%Y%m%dT%H%M%SZ")
132
+
133
+ if [ -z "$OUT_DIR" ]; then
134
+ OUT_DIR="$DESIGN_ROOT/_history/_system/${DS}-visual-sanity-${TS}"
135
+ fi
136
+ mkdir -p "$OUT_DIR"
137
+
138
+ # Step 1 — boot the dev-server. Failure here is fatal: the caller MUST surface
139
+ # AskUserQuestion ("dev-server boot failed: <reason>; skip visual sanity or
140
+ # fix and retry?") rather than silently skipping the gate.
141
+ echo "→ booting dev-server (timeout ${BOOT_TIMEOUT}s)" >&2
142
+ PORT=$(bash "$SCRIPT_DIR/server-up.sh" --root "$ROOT_ABS" --timeout "$BOOT_TIMEOUT")
143
+ SERVER_RC=$?
144
+ if [ $SERVER_RC -ne 0 ] || [ -z "$PORT" ]; then
145
+ echo "✗ dev-server boot failed (server-up.sh exit $SERVER_RC); see $DESIGN_ROOT/_server.log" >&2
146
+ cat > "$OUT_DIR/_manifest.json" <<EOF
147
+ {
148
+ "ds": "$DS",
149
+ "ts": "$TS",
150
+ "status": "server-boot-failed",
151
+ "server_up_rc": $SERVER_RC,
152
+ "specimens_requested": $(printf '%s\n' "${SPEC_ARR[@]}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | sed '/^$/d' | sed 's/.*/"&"/' | paste -sd, -),
153
+ "specimens_captured": []
154
+ }
155
+ EOF
156
+ exit 1
157
+ fi
158
+ echo "✓ dev-server on port $PORT" >&2
159
+
160
+ # Step 2 — screenshot each existing specimen. Track captures vs failures.
161
+ declare -a CAPTURED=()
162
+ declare -a FAILED=()
163
+ for s in "${EXISTING[@]}"; do
164
+ REL="system/$DS/preview/${s}.tsx"
165
+ REL_ENC=$(printf '%s' "$REL" | sed 's/ /%20/g')
166
+ URL="http://localhost:${PORT}/_canvas-shell.html?canvas=${REL_ENC}"
167
+ OUT_PNG="$OUT_DIR/${s}.png"
168
+ echo "→ screenshot: $s" >&2
169
+ if bash "$SCRIPT_DIR/screenshot.sh" \
170
+ --url "$URL" \
171
+ --full \
172
+ --out "$OUT_PNG" \
173
+ --engine "$ENGINE" \
174
+ --timeout "$SHOT_TIMEOUT" >&2; then
175
+ echo "$OUT_PNG"
176
+ CAPTURED+=("$s")
177
+ else
178
+ echo "✗ screenshot failed: $s" >&2
179
+ FAILED+=("$s")
180
+ fi
181
+ done
182
+
183
+ # Step 3 — write manifest. Caller can parse this to know what was captured
184
+ # without re-listing the directory.
185
+ json_arr() {
186
+ # Print a JSON array literal from positional args. Empty → "[]".
187
+ if [ $# -eq 0 ]; then printf '[]'; return; fi
188
+ printf '['
189
+ i=0
190
+ for a in "$@"; do
191
+ if [ $i -gt 0 ]; then printf ', '; fi
192
+ printf '"%s"' "$a"
193
+ i=$((i + 1))
194
+ done
195
+ printf ']'
196
+ }
197
+
198
+ STATUS="ok"
199
+ [ ${#FAILED[@]} -gt 0 ] && STATUS="partial-failure"
200
+
201
+ {
202
+ printf '{\n'
203
+ printf ' "ds": "%s",\n' "$DS"
204
+ printf ' "ts": "%s",\n' "$TS"
205
+ printf ' "status": "%s",\n' "$STATUS"
206
+ printf ' "port": %s,\n' "$PORT"
207
+ printf ' "out_dir": "%s",\n' "$OUT_DIR"
208
+ printf ' "specimens_requested": %s,\n' "$(json_arr "${SPEC_ARR[@]}")"
209
+ printf ' "specimens_captured": %s,\n' "$(json_arr "${CAPTURED[@]}")"
210
+ printf ' "specimens_missing": %s,\n' "$(json_arr "${MISSING[@]}")"
211
+ printf ' "specimens_failed": %s\n' "$(json_arr "${FAILED[@]}")"
212
+ printf '}\n'
213
+ } > "$OUT_DIR/_manifest.json"
214
+
215
+ echo "→ manifest: $OUT_DIR/_manifest.json" >&2
216
+
217
+ if [ ${#FAILED[@]} -gt 0 ]; then
218
+ echo "✗ ${#FAILED[@]}/${#EXISTING[@]} specimen(s) failed to capture: ${FAILED[*]}" >&2
219
+ exit 3
220
+ fi
221
+ exit 0