@hybroai/cli 0.4.5 → 0.4.7

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 (2) hide show
  1. package/bin/hybro +74 -11
  2. package/package.json +1 -1
package/bin/hybro CHANGED
@@ -5,7 +5,7 @@
5
5
  # package's bin, and the release asset that install.sh installs (release mode).
6
6
  set -u
7
7
 
8
- HYBRO_VERSION="0.4.5" # x-release-please-version
8
+ HYBRO_VERSION="0.4.7" # x-release-please-version
9
9
 
10
10
  GITHUB_REPO="hybroai/hybro"
11
11
  RELEASE_IMAGE="ghcr.io/hybroai/hybro"
@@ -78,7 +78,7 @@ Hybro $HYBRO_VERSION: AI agents and rooms in one container.
78
78
  Usage: $CLI [command] [options]
79
79
 
80
80
  Commands:
81
- start Start Hybro and follow its logs (the default command)
81
+ start Start Hybro and show only its errors (the default command)
82
82
  stop Stop Hybro
83
83
  status Show whether Hybro is running and its address
84
84
  logs Show Hybro's logs; docker logs options such as -f pass through
@@ -348,17 +348,62 @@ start_container() {
348
348
  die "cannot start the $CONTAINER container"
349
349
  }
350
350
 
351
+ READY_TIMEOUT=180
352
+ # Any HTTP answer counts, as /health answers 503 while a dependency is degraded.
353
+ # The backend and the frontend first: Caddy logs an error for each request it
354
+ # cannot proxy.
355
+ HEALTH_PROBE='import http.client
356
+ for port, path in ((8000, "/health"), (3000, "/"), (8080, "/health")):
357
+ connection = http.client.HTTPConnection("127.0.0.1", port, timeout=2)
358
+ connection.request("GET", path)
359
+ connection.getresponse()'
360
+
361
+ # Waits until the backend, the frontend and Caddy answer; fails on Ctrl-C,
362
+ # when the container stops, or when the timeout passes.
363
+ wait_ready() {
364
+ started=$(date +%s)
365
+ while :; do
366
+ [ "$INTERRUPTED" = 0 ] || return 1
367
+ [ "$(container_state)" = running ] || return 1
368
+ docker exec "$CONTAINER" "$DIAG_PYTHON" -c "$HEALTH_PROBE" >/dev/null 2>&1 && break
369
+ [ $(($(date +%s) - started)) -lt "$READY_TIMEOUT" ] || return 1
370
+ sleep 1
371
+ done
372
+ [ "$INTERRUPTED" = 0 ] || return 1
373
+ READY_SECONDS=$(($(date +%s) - started))
374
+ }
375
+
376
+ stop_on_interrupt() {
377
+ [ "$INTERRUPTED" = 1 ] || return 0
378
+ say "Stopping Hybro..."
379
+ docker stop "$CONTAINER" >/dev/null || die "cannot stop $CONTAINER"
380
+ exit 0
381
+ }
382
+
383
+ # The foreground start: a ready line, then only errors, including those logged
384
+ # while starting; mongod, Caddy and the agents warn on every normal start.
385
+ # supervisord lines carry no program name and are always shown. Ctrl-C stops
386
+ # Hybro.
351
387
  follow_logs() {
352
- say "Following the logs; press Ctrl-C to stop Hybro."
388
+ say "Starting Hybro $HYBRO_VERSION..."
353
389
  INTERRUPTED=0
354
390
  trap 'INTERRUPTED=1' INT
355
- docker logs -f "$CONTAINER"
356
- trap - INT
357
- if [ "$INTERRUPTED" = 1 ]; then
358
- say "Stopping Hybro..."
359
- docker stop "$CONTAINER" >/dev/null || die "cannot stop $CONTAINER"
360
- exit 0
391
+ if ! wait_ready; then
392
+ trap - INT
393
+ stop_on_interrupt
394
+ docker logs --tail 30 "$CONTAINER" 2>&1
395
+ if [ "$(container_state)" = running ]; then
396
+ err "Hybro did not become ready within ${READY_TIMEOUT}s; it is still running."
397
+ die "Follow its logs with: $CLI logs -f, or stop it with: $CLI stop"
398
+ fi
399
+ code=$(docker container inspect -f '{{.State.ExitCode}}' "$CONTAINER" 2>/dev/null)
400
+ die "Hybro stopped before it was ready (exit code ${code:-unknown}). Show the logs with: $CLI logs"
361
401
  fi
402
+ say "Hybro is ready at $url (${READY_SECONDS}s). Press Ctrl-C to stop."
403
+ say "Full logs: $CLI logs -f"
404
+ docker logs -f "$CONTAINER" 2>&1 | filter_logs "" "$(log_levels error)" ""
405
+ trap - INT
406
+ stop_on_interrupt
362
407
  code=$(docker container inspect -f '{{.State.ExitCode}}' "$CONTAINER" 2>/dev/null)
363
408
  die "Hybro stopped (exit code ${code:-unknown}). Show the logs with: $CLI logs"
364
409
  }
@@ -453,8 +498,8 @@ cmd_start() {
453
498
  ensure_image
454
499
  start_container
455
500
  url=$(url_for "$BIND" "$PORT")
456
- say "Hybro is starting at $url"
457
501
  if [ "$DETACH" = 1 ]; then
502
+ say "Hybro is starting at $url"
458
503
  say "Running in the background. Stop it with: $CLI stop"
459
504
  return 0
460
505
  fi
@@ -547,7 +592,13 @@ cmd_logs() {
547
592
  # docker's own errors carry no program prefix and are always shown; its exit
548
593
  # status reaches awk as a sentinel line so a failure is not masked by the pipe.
549
594
  { docker logs "$@" "$CONTAINER" 2>&1 || echo "hybro_docker_exit=$?"; } |
550
- awk -v service="$service" -v levels="$levels" -v trace="$trace" '
595
+ filter_logs "$service" "$levels" "$trace"
596
+ }
597
+
598
+ # filter_logs <service> <level alternation> <trace id>: filters docker logs
599
+ # lines on stdin. A hybro_docker_exit=<n> line sets the exit status.
600
+ filter_logs() {
601
+ awk -v service="$1" -v levels="$2" -v trace="$3" '
551
602
  /^hybro_docker_exit=[0-9]+$/ { code = substr($0, 19) + 0; next }
552
603
  {
553
604
  split_at = index($0, " | ")
@@ -564,7 +615,19 @@ cmd_logs() {
564
615
  }
565
616
  # JSON lines write level before any message text; logfmt lines start
566
617
  # with it or with timestamp then level. Plain text has no level.
618
+ # mongod writes its severity as "s": F, E, W, I, or D1 to D5.
567
619
  function level_of(text, value) {
620
+ if (match(text, /^[{]"t":[{][^}]*[}],"s":"[^"]*"/)) {
621
+ value = substr(text, RSTART, RLENGTH)
622
+ sub(/^.*"s":"/, "", value)
623
+ sub(/"$/, "", value)
624
+ if (value == "F") return "fatal"
625
+ if (value == "E") return "error"
626
+ if (value == "W") return "warning"
627
+ if (value == "I") return "info"
628
+ if (value ~ /^D[1-5]$/) return "debug"
629
+ return ""
630
+ }
568
631
  if (substr(text, 1, 1) == "{") {
569
632
  if (!match(text, /"level":"[^"]*"/)) return ""
570
633
  return substr(text, RSTART + 9, RLENGTH - 10)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hybroai/cli",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "description": "Hybro command line: run Hybro, AI agents and rooms in one Docker container",
5
5
  "keywords": [
6
6
  "hybro",