@forhuman/flowmcp 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/lib/ui.sh ADDED
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env bash
2
+ # Terminal output helpers: colors auto-disable when not a real TTY, when
3
+ # NO_COLOR is set, or when TERM=dumb — so agent tool-call output and piped
4
+ # logs stay plain text, never raw ANSI escapes.
5
+
6
+ if [[ -t 1 && -z "${NO_COLOR:-}" && "${TERM:-dumb}" != "dumb" ]]; then
7
+ WFW_C_RESET=$'\033[0m'
8
+ WFW_C_BOLD=$'\033[1m'
9
+ WFW_C_DIM=$'\033[2m'
10
+ WFW_C_GREEN=$'\033[32m'
11
+ WFW_C_RED=$'\033[31m'
12
+ WFW_C_GRAY=$'\033[90m'
13
+ # forhuman palette — used for all CLI chrome (banner accents, next/hint labels).
14
+ WFW_C_YELLOW=$'\033[38;2;255;190;0m' # forhuman yellow #FFBE00 — hint/warn
15
+ WFW_C_CYAN=$'\033[38;2;1;46;220m' # forhuman blue #012EDC — next / accents
16
+ # Webflow's own brand blue, used ONLY for the Webflow "W" logo glyph —
17
+ # deliberately kept true to Webflow's real color, not the forhuman palette.
18
+ WFW_C_BRAND=$'\033[38;2;45;113;236m' # Webflow blue #2D71EC
19
+ WFW_C_BRAND_DIM=$'\033[38;2;22;56;118m' # dimmed brand blue, for the "breathing" idle frame
20
+ else
21
+ WFW_C_RESET="" WFW_C_BOLD="" WFW_C_DIM="" WFW_C_GREEN="" WFW_C_RED="" WFW_C_YELLOW="" WFW_C_CYAN="" WFW_C_GRAY="" WFW_C_BRAND="" WFW_C_BRAND_DIM=""
22
+ fi
23
+
24
+ # Webflow "W" mark, rasterized from the brand SVG into half-block glyphs
25
+ # (▀▄█) so it renders in any terminal — no image protocol dependency.
26
+ WFW_LOGO_LINES=(
27
+ '████████████ ██████████ ▄█████████████'
28
+ '████████████ ███████████ ▄█████████████'
29
+ '████████████ ████████████ ▄█████████████'
30
+ '████████████ █████████████ ▄█████████████'
31
+ '████████████ ██████████████▄█████████████'
32
+ '████████████████████████████████████████'
33
+ ' ▄█████████████████████████████'
34
+ ' ▄▄██████████████████████████████'
35
+ '▄▄▄██████████████████████████████████'
36
+ '█████████████████████▀▄█████████████'
37
+ '███████████████████▀ ▄█████████████'
38
+ '████████████████▀▀ ▄█████████████'
39
+ '█████████████▀▀ ▄█████████████'
40
+ '████████▀▀ ▄█████████████'
41
+ )
42
+
43
+ # wfw_logo [color] — prints the Webflow "W" mark in the given color
44
+ # (defaults to brand blue). Prints nothing when colors are disabled — the
45
+ # glyph reads as noise without color, so callers should have a plain-text
46
+ # fallback for non-TTY/NO_COLOR contexts.
47
+ wfw_logo() {
48
+ local color="${1:-$WFW_C_BRAND}"
49
+ [[ -z "$WFW_C_RESET" ]] && return 0
50
+ local line
51
+ for line in "${WFW_LOGO_LINES[@]}"; do
52
+ printf "%s%s%s\n" "$color" "$line" "$WFW_C_RESET"
53
+ done
54
+ }
55
+
56
+ wfw_say_ok() { echo "${WFW_C_GREEN}ok${WFW_C_RESET} $*"; }
57
+ wfw_say_err() { echo "${WFW_C_RED}error${WFW_C_RESET} $*" >&2; }
58
+ wfw_say_warn() { echo "${WFW_C_YELLOW}warn${WFW_C_RESET} $*" >&2; }
59
+ wfw_say_hint() { echo "${WFW_C_YELLOW}hint${WFW_C_RESET} $*" >&2; }
60
+ wfw_say_next() { echo "${WFW_C_CYAN}next${WFW_C_RESET} $*"; }
61
+
62
+ # wfw_status_color <word> -> colorizes ok/pass/available/available green,
63
+ # fail/error/taken red, anything else (e.g. "never") dim gray.
64
+ wfw_status_color() {
65
+ local s="$1"
66
+ case "$s" in
67
+ ok|pass|available) echo "${WFW_C_GREEN}${s}${WFW_C_RESET}" ;;
68
+ fail|error|taken) echo "${WFW_C_RED}${s}${WFW_C_RESET}" ;;
69
+ *) echo "${WFW_C_GRAY}${s}${WFW_C_RESET}" ;;
70
+ esac
71
+ }
72
+
73
+ # wfw_status_color_padded <status> <width> — colorize, then pad on VISIBLE
74
+ # length (not the ANSI-code length) so table columns stay aligned.
75
+ wfw_status_color_padded() {
76
+ local s="$1"
77
+ local width="$2"
78
+ local pad=$(( width - ${#s} ))
79
+ (( pad < 0 )) && pad=0
80
+ printf "%s%s" "$(wfw_status_color "$s")" "$(printf "%${pad}s" "")"
81
+ }
82
+
83
+ wfw_version() {
84
+ local pkg="$WFW_LIB_DIR/../package.json"
85
+ if [[ -f "$pkg" ]]; then
86
+ jq -r '.version' "$pkg" 2>/dev/null || echo "0.0.0-dev"
87
+ else
88
+ echo "0.0.0-dev"
89
+ fi
90
+ }
91
+
92
+ # wfw_wait_with_logo <background-pid> — redraws the logo, alternating
93
+ # brand/dim color for a "breathing" effect, until the given background job
94
+ # exits. No-op (prints nothing) when colors are disabled — caller should
95
+ # print its own plain-text waiting message before calling this.
96
+ wfw_wait_with_logo() {
97
+ local pid="$1" n="${#WFW_LOGO_LINES[@]}" frame=0 status=0
98
+ if [[ -z "$WFW_C_RESET" ]]; then
99
+ if wait "$pid"; then status=0; else status=$?; fi
100
+ return $status
101
+ fi
102
+ while kill -0 "$pid" 2>/dev/null; do
103
+ if (( frame % 2 == 0 )); then wfw_logo "$WFW_C_BRAND"; else wfw_logo "$WFW_C_BRAND_DIM"; fi
104
+ frame=$(( frame + 1 ))
105
+ sleep 0.6
106
+ printf "\033[%dA" "$n"
107
+ done
108
+ if wait "$pid"; then status=0; else status=$?; fi
109
+ printf "\033[0J" # clear from cursor to end of screen (removes last logo frame)
110
+ return $status
111
+ }
112
+
113
+ wfw_banner() {
114
+ if [[ -n "$WFW_C_RESET" ]]; then
115
+ wfw_logo
116
+ echo "${WFW_C_BOLD}flowmcp${WFW_C_RESET} ${WFW_C_DIM}v$(wfw_version)${WFW_C_RESET} ${WFW_C_YELLOW}·${WFW_C_RESET} ${WFW_C_CYAN}by forhuman${WFW_C_RESET}"
117
+ else
118
+ echo "flowmcp v$(wfw_version) · by forhuman"
119
+ fi
120
+ echo "${WFW_C_DIM}$(wfw_t tagline)${WFW_C_RESET}"
121
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@forhuman/flowmcp",
3
+ "version": "0.1.0",
4
+ "description": "Manage multiple Webflow MCP server connections (one per client/org) without ever letting an API token pass through agent context.",
5
+ "license": "MIT",
6
+ "bin": {
7
+ "flowmcp": "bin/flowmcp",
8
+ "fmcp": "bin/flowmcp"
9
+ },
10
+ "files": [
11
+ "bin",
12
+ "commands",
13
+ "lib",
14
+ "SKILL.md",
15
+ "README.md",
16
+ "LICENSE",
17
+ "CONTRIBUTING.md",
18
+ "friction.md",
19
+ "cases"
20
+ ],
21
+ "publishConfig": {
22
+ "access": "public"
23
+ },
24
+ "engines": {
25
+ "node": ">=18"
26
+ },
27
+ "os": [
28
+ "darwin",
29
+ "linux"
30
+ ],
31
+ "keywords": [
32
+ "webflow",
33
+ "mcp",
34
+ "model-context-protocol",
35
+ "claude-code",
36
+ "claude-desktop",
37
+ "cursor",
38
+ "cli",
39
+ "skill",
40
+ "agency",
41
+ "keychain"
42
+ ],
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/fiorellacisneros/flowmcp.git"
46
+ },
47
+ "homepage": "https://github.com/fiorellacisneros/flowmcp#readme",
48
+ "bugs": {
49
+ "url": "https://github.com/fiorellacisneros/flowmcp/issues"
50
+ }
51
+ }