@qearlyao/familiar 0.1.0 → 0.1.2
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/HEARTBEAT.md +1 -1
- package/README.md +63 -4
- package/dist/agent.js +88 -36
- package/dist/browser-tools.js +0 -12
- package/dist/cli.js +68 -24
- package/dist/control.js +1 -0
- package/dist/discord.js +14 -2
- package/dist/hot-reload.js +132 -0
- package/dist/index.js +1 -0
- package/dist/runtime.js +1 -1
- package/dist/scheduler.js +3 -1
- package/dist/service.js +284 -0
- package/dist/web-auth.js +5 -2
- package/dist/web.js +6 -1
- package/package.json +9 -5
- package/scripts/install.ps1 +185 -0
- package/scripts/install.sh +226 -0
- package/skills/image-gen/SKILL.md +36 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
set -eu
|
|
3
|
+
|
|
4
|
+
PACKAGE="@qearlyao/familiar@latest"
|
|
5
|
+
WORKSPACE="${HOME}/.familiar"
|
|
6
|
+
BROWSER_HARNESS_DIR="${HOME}/Developer/browser-harness"
|
|
7
|
+
WITH_BROWSER=0
|
|
8
|
+
INSTALL_BROWSER_DEPS=0
|
|
9
|
+
SKIP_INIT=0
|
|
10
|
+
|
|
11
|
+
usage() {
|
|
12
|
+
cat <<'EOF'
|
|
13
|
+
Usage: install.sh [options]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--workspace <path> Workspace path to initialize. Defaults to ~/.familiar.
|
|
17
|
+
--with-browser Also install optional OpenCLI and browser-harness helpers.
|
|
18
|
+
--install-browser-deps
|
|
19
|
+
With --with-browser, install missing uv/Python 3.11 browser deps without prompting.
|
|
20
|
+
--skip-init Install familiar but do not run familiar init.
|
|
21
|
+
--package <spec> npm package spec to install. Defaults to @qearlyao/familiar@latest.
|
|
22
|
+
Advanced: installs the exact npm spec provided; use trusted specs only.
|
|
23
|
+
-h, --help Show this help.
|
|
24
|
+
EOF
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
while [ "$#" -gt 0 ]; do
|
|
28
|
+
case "$1" in
|
|
29
|
+
--workspace)
|
|
30
|
+
if [ "$#" -lt 2 ]; then
|
|
31
|
+
echo "Missing value for --workspace" >&2
|
|
32
|
+
exit 1
|
|
33
|
+
fi
|
|
34
|
+
WORKSPACE="$2"
|
|
35
|
+
shift 2
|
|
36
|
+
;;
|
|
37
|
+
--with-browser)
|
|
38
|
+
WITH_BROWSER=1
|
|
39
|
+
shift
|
|
40
|
+
;;
|
|
41
|
+
--install-browser-deps)
|
|
42
|
+
INSTALL_BROWSER_DEPS=1
|
|
43
|
+
shift
|
|
44
|
+
;;
|
|
45
|
+
--skip-init)
|
|
46
|
+
SKIP_INIT=1
|
|
47
|
+
shift
|
|
48
|
+
;;
|
|
49
|
+
--package)
|
|
50
|
+
if [ "$#" -lt 2 ]; then
|
|
51
|
+
echo "Missing value for --package" >&2
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
PACKAGE="$2"
|
|
55
|
+
shift 2
|
|
56
|
+
;;
|
|
57
|
+
-h | --help)
|
|
58
|
+
usage
|
|
59
|
+
exit 0
|
|
60
|
+
;;
|
|
61
|
+
*)
|
|
62
|
+
echo "Unknown option: $1" >&2
|
|
63
|
+
usage >&2
|
|
64
|
+
exit 1
|
|
65
|
+
;;
|
|
66
|
+
esac
|
|
67
|
+
done
|
|
68
|
+
|
|
69
|
+
need_command() {
|
|
70
|
+
if ! command -v "$1" >/dev/null 2>&1; then
|
|
71
|
+
echo "Missing required command: $1" >&2
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
refresh_browser_dep_path() {
|
|
77
|
+
for candidate in "${HOME}/.local/bin" "${HOME}/.cargo/bin"; do
|
|
78
|
+
if [ -d "$candidate" ]; then
|
|
79
|
+
case ":${PATH}:" in
|
|
80
|
+
*":${candidate}:"*) ;;
|
|
81
|
+
*) PATH="${candidate}:${PATH}" ;;
|
|
82
|
+
esac
|
|
83
|
+
fi
|
|
84
|
+
done
|
|
85
|
+
export PATH
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
confirm_browser_dep_install() {
|
|
89
|
+
if [ "$INSTALL_BROWSER_DEPS" -eq 1 ]; then
|
|
90
|
+
return 0
|
|
91
|
+
fi
|
|
92
|
+
if [ -r /dev/tty ] && [ -w /dev/tty ]; then
|
|
93
|
+
printf "%s Install it now? [y/N] " "$1" >/dev/tty
|
|
94
|
+
read -r answer </dev/tty || answer=""
|
|
95
|
+
case "$answer" in
|
|
96
|
+
y | Y | yes | YES) return 0 ;;
|
|
97
|
+
esac
|
|
98
|
+
fi
|
|
99
|
+
return 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
install_uv() {
|
|
103
|
+
echo "Installing uv for browser-harness..."
|
|
104
|
+
if command -v curl >/dev/null 2>&1; then
|
|
105
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
106
|
+
elif command -v wget >/dev/null 2>&1; then
|
|
107
|
+
wget -qO- https://astral.sh/uv/install.sh | sh
|
|
108
|
+
else
|
|
109
|
+
echo "Missing curl or wget, which is required to install uv automatically." >&2
|
|
110
|
+
echo "Install uv manually from https://docs.astral.sh/uv/ and rerun with --with-browser." >&2
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
refresh_browser_dep_path
|
|
114
|
+
if ! command -v uv >/dev/null 2>&1; then
|
|
115
|
+
echo "uv installer finished, but uv is not on PATH. Open a new terminal or add ~/.local/bin to PATH." >&2
|
|
116
|
+
exit 1
|
|
117
|
+
fi
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
ensure_uv() {
|
|
121
|
+
if command -v uv >/dev/null 2>&1; then
|
|
122
|
+
return 0
|
|
123
|
+
fi
|
|
124
|
+
if confirm_browser_dep_install "uv is required for browser-harness but was not found."; then
|
|
125
|
+
install_uv
|
|
126
|
+
return 0
|
|
127
|
+
fi
|
|
128
|
+
echo "Missing required command: uv" >&2
|
|
129
|
+
echo "Rerun with --with-browser --install-browser-deps to install uv and Python 3.11 automatically." >&2
|
|
130
|
+
exit 1
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
find_python() {
|
|
134
|
+
PYTHON_PATH=""
|
|
135
|
+
for candidate in python3 python; do
|
|
136
|
+
if command -v "$candidate" >/dev/null 2>&1; then
|
|
137
|
+
CANDIDATE_PATH="$(command -v "$candidate")"
|
|
138
|
+
if "$CANDIDATE_PATH" -c 'import sys; raise SystemExit(0 if sys.version_info >= (3, 11) else 1)' >/dev/null 2>&1; then
|
|
139
|
+
PYTHON_PATH="$CANDIDATE_PATH"
|
|
140
|
+
return 0
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
done
|
|
144
|
+
return 1
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
ensure_python() {
|
|
148
|
+
if find_python; then
|
|
149
|
+
return 0
|
|
150
|
+
fi
|
|
151
|
+
if confirm_browser_dep_install "Python 3.11+ is required for browser-harness but was not found."; then
|
|
152
|
+
echo "Installing Python 3.11 with uv for browser-harness..."
|
|
153
|
+
uv python install 3.11
|
|
154
|
+
PYTHON_PATH="3.11"
|
|
155
|
+
return 0
|
|
156
|
+
fi
|
|
157
|
+
echo "browser-harness requires Python 3.11 or newer." >&2
|
|
158
|
+
echo "Rerun with --with-browser --install-browser-deps to install uv-managed Python 3.11 automatically." >&2
|
|
159
|
+
exit 1
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
need_command node
|
|
163
|
+
need_command npm
|
|
164
|
+
if [ "$WITH_BROWSER" -eq 1 ]; then
|
|
165
|
+
need_command git
|
|
166
|
+
ensure_uv
|
|
167
|
+
ensure_python
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
NODE_VERSION="$(node -p "process.versions.node")"
|
|
171
|
+
NODE_MAJOR="$(node -p "Number(process.versions.node.split('.')[0])")"
|
|
172
|
+
if [ "$NODE_MAJOR" -lt 22 ]; then
|
|
173
|
+
echo "Familiar requires Node.js 22 or newer. Found Node.js ${NODE_VERSION}." >&2
|
|
174
|
+
echo "Node.js 24 LTS is recommended for the smoothest install." >&2
|
|
175
|
+
exit 1
|
|
176
|
+
fi
|
|
177
|
+
if [ "$NODE_MAJOR" -lt 24 ]; then
|
|
178
|
+
echo "Found Node.js ${NODE_VERSION}. Familiar supports Node.js 22+, but Node.js 24 LTS is recommended."
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
echo "Installing ${PACKAGE} globally..."
|
|
182
|
+
npm install -g "$PACKAGE"
|
|
183
|
+
|
|
184
|
+
if [ "$WITH_BROWSER" -eq 1 ]; then
|
|
185
|
+
echo "Installing optional OpenCLI browser helper..."
|
|
186
|
+
npm install -g @jackwener/opencli
|
|
187
|
+
|
|
188
|
+
echo "Installing optional browser-harness helper into ${BROWSER_HARNESS_DIR}..."
|
|
189
|
+
if [ -d "${BROWSER_HARNESS_DIR}/.git" ]; then
|
|
190
|
+
git -C "$BROWSER_HARNESS_DIR" pull --ff-only
|
|
191
|
+
elif [ -e "$BROWSER_HARNESS_DIR" ]; then
|
|
192
|
+
echo "Cannot install browser-harness: ${BROWSER_HARNESS_DIR} already exists and is not a git checkout." >&2
|
|
193
|
+
exit 1
|
|
194
|
+
else
|
|
195
|
+
mkdir -p "$(dirname "$BROWSER_HARNESS_DIR")"
|
|
196
|
+
git clone https://github.com/browser-use/browser-harness "$BROWSER_HARNESS_DIR"
|
|
197
|
+
fi
|
|
198
|
+
(cd "$BROWSER_HARNESS_DIR" && UV_PYTHON="$PYTHON_PATH" uv tool install -e .)
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
if ! command -v familiar >/dev/null 2>&1; then
|
|
202
|
+
echo "Installed package, but familiar is not on PATH." >&2
|
|
203
|
+
echo "Check your npm global bin directory and shell PATH, then rerun: familiar init ${WORKSPACE}" >&2
|
|
204
|
+
exit 1
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
if [ "$SKIP_INIT" -eq 0 ]; then
|
|
208
|
+
echo "Initializing or refreshing workspace defaults at ${WORKSPACE}..."
|
|
209
|
+
familiar init "$WORKSPACE"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
cat <<EOF
|
|
213
|
+
|
|
214
|
+
Familiar is installed.
|
|
215
|
+
|
|
216
|
+
Next steps:
|
|
217
|
+
1. Edit ${WORKSPACE}/.env
|
|
218
|
+
2. Edit ${WORKSPACE}/config.toml
|
|
219
|
+
3. Run: familiar run ${WORKSPACE}
|
|
220
|
+
|
|
221
|
+
Optional browser helpers:
|
|
222
|
+
curl -fsSL https://raw.githubusercontent.com/qearlyao/familiar/main/scripts/install.sh | sh -s -- --with-browser
|
|
223
|
+
|
|
224
|
+
browser-harness checkout:
|
|
225
|
+
${BROWSER_HARNESS_DIR}
|
|
226
|
+
EOF
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: image-gen
|
|
3
|
+
description: Read this skill before using the image_gen tool. Covers style preferences, reference image paths.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
## Reference Images
|
|
8
|
+
|
|
9
|
+
Folder: `~/.familiar/ref-images`
|
|
10
|
+
|
|
11
|
+
Available refs:
|
|
12
|
+
- `Ghost_bare_face_mask_off.png` - close-up portrait, sandy messy hair, no mask (full face visible)
|
|
13
|
+
- `Ghost_face_with_hair.png` — close-up portrait, sandy messy hair, lower-half black skull mask, shirtless with silver chain
|
|
14
|
+
- `Ghost_body_with_hair.jpg` — muscular shirtless upper body, left arm full tattoo sleeve, messy sandy hair, lower-half skull mask
|
|
15
|
+
- `Ghost_balaclava_hoodie_no_hair.jpg` — close-up portrait, full black balaclava with skull jaw paint, hood up (no hair showing)
|
|
16
|
+
- `Ghost_Back_view_fullbody_shape.jpg` — broad shoulders, fullbody back view
|
|
17
|
+
- `Ghost_skullmask_jeans_tactical_fullbody.png` — full tactical loadout (plate carrier, headset), hard skull mask piece over lower face/nose, blue jeans
|
|
18
|
+
- `Qearl_bust.jpg` — Qearl's bust likeness
|
|
19
|
+
|
|
20
|
+
**Rules:**
|
|
21
|
+
- Pick 1–3 refs that match the scene. Don't dump all in.
|
|
22
|
+
- Face ref + body ref relevant to outfit/context is usually right
|
|
23
|
+
- Different refs = different "form" — choose deliberately
|
|
24
|
+
- **Refs handle faces** — do NOT describe facial details in the prompt. Let the ref provide likeness.
|
|
25
|
+
|
|
26
|
+
## Style Preferences
|
|
27
|
+
|
|
28
|
+
- **Preferred:** daily life / selfie / phone POV — realistic, like a real photo
|
|
29
|
+
- **Avoid:** 3d rendering, illustration, anime styles
|
|
30
|
+
- **Be specific:** turn vague descriptions into clear, concrete visual details
|
|
31
|
+
- **Be structured:** organize as "subject (e.g. @img1, @img2) + outfit + style + environment + details"
|
|
32
|
+
- **Mask or Bare face** use bare face refs if u need a mask-off image, avoid describing mask-off when using mask-on refs
|
|
33
|
+
|
|
34
|
+
## Notes
|
|
35
|
+
- Set aspect ratio and resolution or size based on image type
|
|
36
|
+
- Camo paint is tied to the ref. For scenes where camo doesn't fit, you can explicitly note in the prompt: "remove camo eyes paint"
|