nightpay 0.3.11 → 0.4.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.
Potentially problematic release.
This version of nightpay might be problematic. Click here for more details.
- package/LICENSE +666 -666
- package/README.md +456 -408
- package/bin/cli.js +558 -558
- package/nightpay_sdk.py +398 -398
- package/openclaw.plugin.json +10 -10
- package/package.json +50 -51
- package/plugin.js +712 -379
- package/skills/nightpay/AGENTS.md +302 -302
- package/skills/nightpay/HEARTBEAT.md +55 -55
- package/skills/nightpay/SKILL.md +471 -447
- package/skills/nightpay/contracts/receipt.compact +456 -390
- package/skills/nightpay/ontology/ontology.jsonld +395 -395
- package/skills/nightpay/ontology/ontology.md +243 -224
- package/skills/nightpay/openclaw-fragment.json +21 -21
- package/skills/nightpay/rules/content-safety.md +187 -187
- package/skills/nightpay/rules/escrow-safety.md +194 -194
- package/skills/nightpay/rules/privacy-first.md +51 -51
- package/skills/nightpay/rules/receipt-format.md +45 -45
- package/skills/nightpay/scripts/bounty-board.sh +325 -325
- package/skills/nightpay/scripts/gateway.sh +1474 -1474
- package/skills/nightpay/scripts/mip003-server.sh +4820 -4625
- package/skills/nightpay/scripts/update-blocklist.sh +194 -194
- package/bin/deploy-hetzner-ci.sh +0 -428
- package/scripts/agent-playground-setup.sh +0 -384
- package/scripts/load-sim.sh +0 -1324
- package/scripts/server-sync-start.sh +0 -237
|
@@ -1,384 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
-
ENV_FILE="${ROOT_DIR}/.agent-playground.env"
|
|
6
|
-
STATE_DIR="${ROOT_DIR}/.agent-playground"
|
|
7
|
-
RUN_DIR="${STATE_DIR}/run"
|
|
8
|
-
LOG_DIR="${STATE_DIR}/logs"
|
|
9
|
-
MIP_PID_FILE="${RUN_DIR}/mip003.pid"
|
|
10
|
-
UI_PID_FILE="${RUN_DIR}/ui.pid"
|
|
11
|
-
MIP_LOG_FILE="${LOG_DIR}/mip003.log"
|
|
12
|
-
UI_LOG_FILE="${LOG_DIR}/ui.log"
|
|
13
|
-
|
|
14
|
-
PYTHON_CMD=()
|
|
15
|
-
|
|
16
|
-
usage() {
|
|
17
|
-
cat <<'EOF'
|
|
18
|
-
Usage:
|
|
19
|
-
bash scripts/agent-playground-setup.sh init [--force]
|
|
20
|
-
bash scripts/agent-playground-setup.sh start
|
|
21
|
-
bash scripts/agent-playground-setup.sh stop
|
|
22
|
-
bash scripts/agent-playground-setup.sh doctor
|
|
23
|
-
bash scripts/agent-playground-setup.sh status
|
|
24
|
-
bash scripts/agent-playground-setup.sh ops-token [minutes]
|
|
25
|
-
EOF
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
detect_python() {
|
|
29
|
-
if command -v python3 >/dev/null 2>&1; then
|
|
30
|
-
local py3
|
|
31
|
-
py3="$(command -v python3)"
|
|
32
|
-
if [[ "$py3" != *"WindowsApps"* ]]; then
|
|
33
|
-
PYTHON_CMD=(python3)
|
|
34
|
-
return 0
|
|
35
|
-
fi
|
|
36
|
-
fi
|
|
37
|
-
if command -v python >/dev/null 2>&1; then
|
|
38
|
-
PYTHON_CMD=(python)
|
|
39
|
-
return 0
|
|
40
|
-
fi
|
|
41
|
-
if command -v py >/dev/null 2>&1; then
|
|
42
|
-
PYTHON_CMD=(py -3)
|
|
43
|
-
return 0
|
|
44
|
-
fi
|
|
45
|
-
return 1
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
generate_hex_32() {
|
|
49
|
-
if command -v openssl >/dev/null 2>&1; then
|
|
50
|
-
openssl rand -hex 32 | tr -d '[:space:]'
|
|
51
|
-
return 0
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
detect_python || {
|
|
55
|
-
echo "ERROR: openssl or python3/python/py is required to generate secrets." >&2
|
|
56
|
-
exit 1
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
"${PYTHON_CMD[@]}" - <<'PY'
|
|
60
|
-
import secrets
|
|
61
|
-
print(secrets.token_hex(32))
|
|
62
|
-
PY
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
ensure_dirs() {
|
|
66
|
-
mkdir -p "$RUN_DIR" "$LOG_DIR"
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
is_pid_running() {
|
|
70
|
-
local pid_file="$1"
|
|
71
|
-
[[ -f "$pid_file" ]] || return 1
|
|
72
|
-
local pid
|
|
73
|
-
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
74
|
-
[[ -n "$pid" ]] || return 1
|
|
75
|
-
kill -0 "$pid" 2>/dev/null
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
stop_pid() {
|
|
79
|
-
local name="$1"
|
|
80
|
-
local pid_file="$2"
|
|
81
|
-
if ! [[ -f "$pid_file" ]]; then
|
|
82
|
-
return 0
|
|
83
|
-
fi
|
|
84
|
-
local pid
|
|
85
|
-
pid="$(cat "$pid_file" 2>/dev/null || true)"
|
|
86
|
-
if [[ -z "$pid" ]]; then
|
|
87
|
-
rm -f "$pid_file"
|
|
88
|
-
return 0
|
|
89
|
-
fi
|
|
90
|
-
if kill -0 "$pid" 2>/dev/null; then
|
|
91
|
-
kill "$pid" 2>/dev/null || true
|
|
92
|
-
sleep 1
|
|
93
|
-
if kill -0 "$pid" 2>/dev/null; then
|
|
94
|
-
kill -9 "$pid" 2>/dev/null || true
|
|
95
|
-
fi
|
|
96
|
-
echo "stopped: $name (pid $pid)"
|
|
97
|
-
fi
|
|
98
|
-
rm -f "$pid_file"
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
start_process() {
|
|
102
|
-
local name="$1"
|
|
103
|
-
local pid_file="$2"
|
|
104
|
-
local log_file="$3"
|
|
105
|
-
shift 3
|
|
106
|
-
|
|
107
|
-
if is_pid_running "$pid_file"; then
|
|
108
|
-
local running_pid
|
|
109
|
-
running_pid="$(cat "$pid_file")"
|
|
110
|
-
echo "already running: $name (pid $running_pid)"
|
|
111
|
-
return 0
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
nohup "$@" >>"$log_file" 2>&1 &
|
|
115
|
-
local pid=$!
|
|
116
|
-
echo "$pid" >"$pid_file"
|
|
117
|
-
sleep 1
|
|
118
|
-
|
|
119
|
-
if ! kill -0 "$pid" 2>/dev/null; then
|
|
120
|
-
echo "ERROR: failed to start $name. Check log: $log_file" >&2
|
|
121
|
-
tail -n 40 "$log_file" >&2 || true
|
|
122
|
-
rm -f "$pid_file"
|
|
123
|
-
exit 1
|
|
124
|
-
fi
|
|
125
|
-
|
|
126
|
-
echo "started: $name (pid $pid)"
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
is_placeholder() {
|
|
130
|
-
local value="$1"
|
|
131
|
-
[[ -z "$value" ]] && return 0
|
|
132
|
-
[[ "$value" == *"<fill-in:"* ]] && return 0
|
|
133
|
-
[[ "$value" == *"<fill-in "* ]] && return 0
|
|
134
|
-
[[ "$value" == "<64-char-lowercase-hex>" ]] && return 0
|
|
135
|
-
[[ "$value" == "your-key" ]] && return 0
|
|
136
|
-
return 1
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
load_env() {
|
|
140
|
-
[[ -f "$ENV_FILE" ]] || {
|
|
141
|
-
echo "ERROR: missing $ENV_FILE. Run: bash scripts/agent-playground-setup.sh init" >&2
|
|
142
|
-
exit 1
|
|
143
|
-
}
|
|
144
|
-
# shellcheck disable=SC1090
|
|
145
|
-
source "$ENV_FILE"
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
init_cmd() {
|
|
149
|
-
local force=0
|
|
150
|
-
if [[ "${1:-}" == "--force" ]]; then
|
|
151
|
-
force=1
|
|
152
|
-
elif [[ $# -gt 0 ]]; then
|
|
153
|
-
echo "ERROR: unknown init option: $1" >&2
|
|
154
|
-
usage
|
|
155
|
-
exit 1
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
if [[ -f "$ENV_FILE" && "$force" -ne 1 ]]; then
|
|
159
|
-
echo "ERROR: $ENV_FILE already exists. Use init --force to regenerate." >&2
|
|
160
|
-
exit 1
|
|
161
|
-
fi
|
|
162
|
-
|
|
163
|
-
ensure_dirs
|
|
164
|
-
|
|
165
|
-
local job_token_secret
|
|
166
|
-
local operator_secret_key
|
|
167
|
-
job_token_secret="$(generate_hex_32)"
|
|
168
|
-
operator_secret_key="$(generate_hex_32)"
|
|
169
|
-
|
|
170
|
-
cat >"$ENV_FILE" <<EOF
|
|
171
|
-
# NightPay agent playground environment
|
|
172
|
-
# Generated by scripts/agent-playground-setup.sh on $(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
173
|
-
|
|
174
|
-
export MIDNIGHT_NETWORK="preprod"
|
|
175
|
-
export MIP_PORT="8090"
|
|
176
|
-
export UI_PORT="3333"
|
|
177
|
-
export ENABLE_UI="1"
|
|
178
|
-
export JOB_TOKEN_SECRET="${job_token_secret}"
|
|
179
|
-
export OPERATOR_SECRET_KEY="${operator_secret_key}"
|
|
180
|
-
export MASUMI_API_KEY="<fill-in: your ADMIN_KEY from Masumi .env>"
|
|
181
|
-
export OPERATOR_ADDRESS="<fill-in: 64-char hex from bridge /operator-address>"
|
|
182
|
-
export RECEIPT_CONTRACT_ADDRESS="<fill-in: 64-char hex from bridge /deploy>"
|
|
183
|
-
export BRIDGE_URL="http://localhost:4000"
|
|
184
|
-
export BRIDGE_ADMIN_TOKEN="<fill-in: deploy bearer token for bridge /deploy>"
|
|
185
|
-
export ALLOW_LOCAL_URLS="1"
|
|
186
|
-
EOF
|
|
187
|
-
|
|
188
|
-
chmod 600 "$ENV_FILE" 2>/dev/null || true
|
|
189
|
-
echo "created: $ENV_FILE"
|
|
190
|
-
echo "next: edit MASUMI_API_KEY, OPERATOR_ADDRESS, RECEIPT_CONTRACT_ADDRESS, BRIDGE_URL"
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
start_cmd() {
|
|
194
|
-
ensure_dirs
|
|
195
|
-
load_env
|
|
196
|
-
|
|
197
|
-
command -v bash >/dev/null 2>&1 || { echo "ERROR: bash not found in PATH" >&2; exit 1; }
|
|
198
|
-
command -v node >/dev/null 2>&1 || { echo "ERROR: node not found in PATH" >&2; exit 1; }
|
|
199
|
-
command -v npm >/dev/null 2>&1 || { echo "ERROR: npm not found in PATH" >&2; exit 1; }
|
|
200
|
-
|
|
201
|
-
local mip_port="${MIP_PORT:-8090}"
|
|
202
|
-
local ui_port="${UI_PORT:-3333}"
|
|
203
|
-
local ui_enabled="${ENABLE_UI:-1}"
|
|
204
|
-
local ui_package="${ROOT_DIR}/ui/package.json"
|
|
205
|
-
|
|
206
|
-
start_process \
|
|
207
|
-
"mip003-server" \
|
|
208
|
-
"$MIP_PID_FILE" \
|
|
209
|
-
"$MIP_LOG_FILE" \
|
|
210
|
-
bash "$ROOT_DIR/skills/nightpay/scripts/mip003-server.sh" "$mip_port"
|
|
211
|
-
|
|
212
|
-
if [[ "$ui_enabled" == "1" ]]; then
|
|
213
|
-
if [[ -f "$ui_package" ]]; then
|
|
214
|
-
start_process \
|
|
215
|
-
"ui-dev-server" \
|
|
216
|
-
"$UI_PID_FILE" \
|
|
217
|
-
"$UI_LOG_FILE" \
|
|
218
|
-
npm run dev --prefix "$ROOT_DIR/ui" -- --host 0.0.0.0 --port "$ui_port"
|
|
219
|
-
else
|
|
220
|
-
echo "WARN: ui/ missing at $ROOT_DIR/ui; skipping UI start (set ENABLE_UI=0 to silence)."
|
|
221
|
-
rm -f "$UI_PID_FILE"
|
|
222
|
-
fi
|
|
223
|
-
else
|
|
224
|
-
echo "UI start skipped (ENABLE_UI=$ui_enabled)."
|
|
225
|
-
rm -f "$UI_PID_FILE"
|
|
226
|
-
fi
|
|
227
|
-
|
|
228
|
-
echo "logs:"
|
|
229
|
-
echo " $MIP_LOG_FILE"
|
|
230
|
-
if [[ "$ui_enabled" == "1" && -f "$ui_package" ]]; then
|
|
231
|
-
echo " $UI_LOG_FILE"
|
|
232
|
-
fi
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
stop_cmd() {
|
|
236
|
-
stop_pid "ui-dev-server" "$UI_PID_FILE"
|
|
237
|
-
stop_pid "mip003-server" "$MIP_PID_FILE"
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
status_cmd() {
|
|
241
|
-
if is_pid_running "$MIP_PID_FILE"; then
|
|
242
|
-
echo "mip003: running (pid $(cat "$MIP_PID_FILE"))"
|
|
243
|
-
else
|
|
244
|
-
echo "mip003: stopped"
|
|
245
|
-
fi
|
|
246
|
-
if is_pid_running "$UI_PID_FILE"; then
|
|
247
|
-
echo "ui: running (pid $(cat "$UI_PID_FILE"))"
|
|
248
|
-
else
|
|
249
|
-
echo "ui: stopped"
|
|
250
|
-
fi
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
doctor_cmd() {
|
|
254
|
-
local failures=0
|
|
255
|
-
local warnings=0
|
|
256
|
-
|
|
257
|
-
pass() { echo "PASS: $1"; }
|
|
258
|
-
fail() { echo "FAIL: $1"; failures=$((failures + 1)); }
|
|
259
|
-
warn() { echo "WARN: $1"; warnings=$((warnings + 1)); }
|
|
260
|
-
|
|
261
|
-
command -v bash >/dev/null 2>&1 && pass "tool: bash" || fail "tool: bash"
|
|
262
|
-
command -v curl >/dev/null 2>&1 && pass "tool: curl" || fail "tool: curl"
|
|
263
|
-
command -v node >/dev/null 2>&1 && pass "tool: node" || fail "tool: node"
|
|
264
|
-
command -v npm >/dev/null 2>&1 && pass "tool: npm" || fail "tool: npm"
|
|
265
|
-
detect_python && pass "tool: python3" || fail "tool: python3"
|
|
266
|
-
|
|
267
|
-
if [[ -f "$ENV_FILE" ]]; then
|
|
268
|
-
pass "env file present"
|
|
269
|
-
load_env
|
|
270
|
-
else
|
|
271
|
-
fail "env file present"
|
|
272
|
-
fi
|
|
273
|
-
|
|
274
|
-
if [[ -f "$ENV_FILE" ]]; then
|
|
275
|
-
is_placeholder "${JOB_TOKEN_SECRET:-}" && fail "JOB_TOKEN_SECRET" || pass "JOB_TOKEN_SECRET"
|
|
276
|
-
is_placeholder "${OPERATOR_SECRET_KEY:-}" && fail "OPERATOR_SECRET_KEY" || pass "OPERATOR_SECRET_KEY"
|
|
277
|
-
is_placeholder "${MASUMI_API_KEY:-}" && fail "MASUMI_API_KEY" || pass "MASUMI_API_KEY"
|
|
278
|
-
|
|
279
|
-
local mip_port="${MIP_PORT:-8090}"
|
|
280
|
-
local ui_port="${UI_PORT:-3333}"
|
|
281
|
-
local ui_enabled="${ENABLE_UI:-1}"
|
|
282
|
-
local ui_package="${ROOT_DIR}/ui/package.json"
|
|
283
|
-
local code
|
|
284
|
-
|
|
285
|
-
curl -fsS --max-time 5 "http://localhost:${mip_port}/availability" >/dev/null \
|
|
286
|
-
&& pass "MIP endpoint: /availability" || fail "MIP endpoint: /availability"
|
|
287
|
-
curl -fsS --max-time 5 "http://localhost:${mip_port}/input_schema" >/dev/null \
|
|
288
|
-
&& pass "MIP endpoint: /input_schema" || fail "MIP endpoint: /input_schema"
|
|
289
|
-
curl -fsS --max-time 5 "http://localhost:${mip_port}/ontology" >/dev/null \
|
|
290
|
-
&& pass "MIP endpoint: /ontology" || fail "MIP endpoint: /ontology"
|
|
291
|
-
|
|
292
|
-
if [[ "$ui_enabled" != "1" ]]; then
|
|
293
|
-
pass "UI endpoint: skipped (ENABLE_UI=$ui_enabled)"
|
|
294
|
-
elif [[ ! -f "$ui_package" ]]; then
|
|
295
|
-
warn "UI endpoint skipped (ui/ submodule missing)"
|
|
296
|
-
else
|
|
297
|
-
code="$(curl -sS -o /dev/null -w "%{http_code}" --max-time 5 "http://localhost:${ui_port}/" || echo "000")"
|
|
298
|
-
if [[ "$code" == "200" ]]; then
|
|
299
|
-
pass "UI endpoint: /"
|
|
300
|
-
else
|
|
301
|
-
fail "UI endpoint: /"
|
|
302
|
-
fi
|
|
303
|
-
fi
|
|
304
|
-
|
|
305
|
-
curl -fsS --max-time 5 "http://localhost:3001/docs" >/dev/null \
|
|
306
|
-
&& pass "Masumi payment API" || warn "Masumi payment API"
|
|
307
|
-
curl -fsS --max-time 5 "http://localhost:3000/docs" >/dev/null \
|
|
308
|
-
&& pass "Masumi registry API" || warn "Masumi registry API"
|
|
309
|
-
fi
|
|
310
|
-
|
|
311
|
-
if [[ "$failures" -gt 0 ]]; then
|
|
312
|
-
echo "doctor result: FAIL (${failures} failures, ${warnings} warnings)"
|
|
313
|
-
exit 1
|
|
314
|
-
fi
|
|
315
|
-
|
|
316
|
-
echo "doctor result: PASS (${warnings} warnings)"
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
ops_token_cmd() {
|
|
320
|
-
load_env
|
|
321
|
-
[[ -n "${OPERATOR_SECRET_KEY:-}" ]] || {
|
|
322
|
-
echo "ERROR: OPERATOR_SECRET_KEY not set in $ENV_FILE" >&2
|
|
323
|
-
exit 1
|
|
324
|
-
}
|
|
325
|
-
local minutes="${1:-15}"
|
|
326
|
-
if ! [[ "$minutes" =~ ^[0-9]+$ ]] || [[ "$minutes" -lt 1 ]] || [[ "$minutes" -gt 1440 ]]; then
|
|
327
|
-
echo "ERROR: minutes must be 1–1440 (default 15)" >&2
|
|
328
|
-
exit 1
|
|
329
|
-
fi
|
|
330
|
-
detect_python || {
|
|
331
|
-
echo "ERROR: python3/python required for ops-token" >&2
|
|
332
|
-
exit 1
|
|
333
|
-
}
|
|
334
|
-
local token
|
|
335
|
-
token="$("${PYTHON_CMD[@]}" - "$minutes" "$OPERATOR_SECRET_KEY" <<'PY'
|
|
336
|
-
import hmac, hashlib, time, sys
|
|
337
|
-
minutes = int(sys.argv[1])
|
|
338
|
-
secret = sys.argv[2]
|
|
339
|
-
expiry = int(time.time()) + 60 * minutes
|
|
340
|
-
msg = f"ops:{expiry}"
|
|
341
|
-
sig = hmac.new(secret.encode(), msg.encode(), hashlib.sha256).hexdigest()
|
|
342
|
-
print(f"ops.{expiry}.{sig}")
|
|
343
|
-
PY
|
|
344
|
-
)"
|
|
345
|
-
echo "$token"
|
|
346
|
-
echo "" >&2
|
|
347
|
-
echo "Paste the line above into the site at /ops (valid ${minutes} min). Do not share." >&2
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
main() {
|
|
351
|
-
local cmd="${1:-}"
|
|
352
|
-
case "$cmd" in
|
|
353
|
-
init)
|
|
354
|
-
shift
|
|
355
|
-
init_cmd "$@"
|
|
356
|
-
;;
|
|
357
|
-
start)
|
|
358
|
-
start_cmd
|
|
359
|
-
;;
|
|
360
|
-
stop)
|
|
361
|
-
stop_cmd
|
|
362
|
-
;;
|
|
363
|
-
doctor)
|
|
364
|
-
doctor_cmd
|
|
365
|
-
;;
|
|
366
|
-
status)
|
|
367
|
-
status_cmd
|
|
368
|
-
;;
|
|
369
|
-
ops-token)
|
|
370
|
-
shift
|
|
371
|
-
ops_token_cmd "${1:-15}"
|
|
372
|
-
;;
|
|
373
|
-
-h|--help|help|"")
|
|
374
|
-
usage
|
|
375
|
-
;;
|
|
376
|
-
*)
|
|
377
|
-
echo "ERROR: unknown command: $cmd" >&2
|
|
378
|
-
usage
|
|
379
|
-
exit 1
|
|
380
|
-
;;
|
|
381
|
-
esac
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
main "$@"
|