@flame0510/project-aether 1.6.2 → 1.8.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 (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -2
  3. package/agent-templates/atlas/HEARTBEAT.md +1 -1
  4. package/app/agents/ImageDownloadBanner.tsx +171 -37
  5. package/app/api/agents/download-image/route.ts +29 -5
  6. package/app/api/agents/image-status/route.ts +17 -2
  7. package/app/api/assistant/route.ts +21 -5
  8. package/app/api/auth/login/route.ts +2 -2
  9. package/app/api/metrics/route.ts +126 -23
  10. package/app/api/setup/agent-image/route.ts +6 -4
  11. package/app/api/system-health/route.ts +25 -21
  12. package/app/components/DashboardToolbar.tsx +2 -2
  13. package/app/components/LineageGraphPage.tsx +4 -4
  14. package/app/components/SessionDrawer.tsx +8 -8
  15. package/app/components/Sidebar.tsx +10 -0
  16. package/app/components/Skeleton.tsx +4 -1
  17. package/app/components/SystemCockpit.tsx +83 -3
  18. package/app/components/ui/Meter.tsx +34 -0
  19. package/app/components/ui/TimeSeriesChart.tsx +226 -0
  20. package/app/components/ui/index.ts +2 -0
  21. package/app/globals.css +42 -1
  22. package/app/setup/PageClient.tsx +1 -1
  23. package/app/system/PageClient.tsx +263 -0
  24. package/app/system/SystemSkeleton.tsx +115 -0
  25. package/app/system/loading.tsx +13 -0
  26. package/app/system/page.tsx +5 -0
  27. package/bin/postinstall.js +5 -1
  28. package/daemon.js +274 -214
  29. package/docs/ARCHITECTURE.md +65 -34
  30. package/docs/CONTAINER-TERMINAL.md +17 -8
  31. package/docs/DESIGN-SYSTEM.md +22 -12
  32. package/docs/FRONTEND-ARCHITECTURE.md +8 -4
  33. package/docs/REV4A.md +37 -86
  34. package/docs/dev/API-REFERENCE.md +102 -19
  35. package/docs/dev/DATABASE.md +79 -28
  36. package/docs/dev/SESSION-MAINTENANCE-PLAN.md +6 -6
  37. package/docs/rag/DATA-FRESHNESS.md +31 -15
  38. package/docs/rag/GLOSSARY.md +8 -5
  39. package/docs/rag/REV4A-OVERVIEW.md +14 -7
  40. package/docs/rag/WHAT-I-CAN-ANSWER.md +4 -3
  41. package/lib/agent-images.ts +43 -14
  42. package/lib/buildAgentImage.ts +142 -6
  43. package/lib/db-bootstrap.mjs +0 -11
  44. package/lib/metrics-db.ts +48 -0
  45. package/lib/patterns/sessionPresentation.ts +4 -2
  46. package/lib/rev4a-auth.d.ts +1 -0
  47. package/lib/rev4a-auth.js +18 -2
  48. package/next.config.mjs +9 -1
  49. package/package.json +2 -2
  50. package/scripts/backup.sh +48 -54
  51. package/scripts/check-language.mjs +21 -3
  52. package/scripts/restore.sh +77 -59
@@ -4,7 +4,7 @@
4
4
  * identifiers, comments, docs, UI strings (AGENTS.md §2.1).
5
5
  *
6
6
  * The word list is deliberately conservative: only words that are **not** English words.
7
- * `come`, `per`, `non`, `la`, `al`, `tra` are left out on purpose, they would fire on
7
+ * `come`, `per`, `non`, `la`, `al` are left out on purpose, they would fire on
8
8
  * English text; the list is content words plus unmistakable function words. A line
9
9
  * carrying `lang-ok` is skipped, for the legitimate case where the Italian is the point
10
10
  * (a fixture, a note about the rule):
@@ -12,8 +12,9 @@
12
12
  * // lang-ok: the exact text a user reported
13
13
  *
14
14
  * It catches Italian *words*, not Italian thinking written in English, and it never
15
- * translates: the fix is manual. Wired into the release workflow (a release cannot ship
16
- * Italian) and available locally as `npm run check:language`.
15
+ * translates: the fix is manual. Run by CI on every push to main and every pull request,
16
+ * again by the release workflow before publishing, and available locally as
17
+ * `npm run check:language` (and as a pre-commit hook, `.githooks/pre-commit`).
17
18
  *
18
19
  * Usage:
19
20
  * node scripts/check-language.mjs # every tracked file
@@ -35,6 +36,23 @@ const WORDS = [
35
36
  'essere', 'fare', 'dove', 'nuovo', 'nuova', 'vecchio', 'vecchia', 'davvero', 'invece',
36
37
  'inoltre', 'quindi', 'della', 'delle', 'degli', 'nella', 'nelle', 'negli', 'dalla', 'dalle',
37
38
  'dallo', 'allo', 'alla', 'sul', 'sulla', 'nessuno', 'nessuna', 'adesso', 'subito', 'oggi', 'ieri',
39
+ // Added 2026-09-24, after three lines survived the list above — one of them a UI string
40
+ // ('Include OpenRouter e altri provider…' in the system-health recommendations).
41
+ 'compila', 'compilare', 'compilato', 'pubblica', 'pubblico', 'pubblicare', 'pubblicato',
42
+ 'altro', 'altra', 'altri', 'altre', 'giorno', 'giorni', 'mese', 'settimana', 'settimane',
43
+ 'aggiorna', 'aggiornare', 'aggiornamento', 'aggiornato', 'controllo', 'controlla', 'controllare',
44
+ 'verifica', 'verificare', 'esempio', 'esempi', 'funziona', 'funzione', 'funzioni',
45
+ 'creare', 'cancella', 'cancellare', 'scarica', 'scaricare', 'usare', 'usato', 'utilizzo',
46
+ 'riga', 'parola', 'parole', 'elenco', 'codice', 'chiave', 'chiavi', 'prova', 'risultato',
47
+ 'risultati', 'stesso', 'stessa', 'stessi', 'stesse', 'ancora', 'sempre', 'dopo', 'forse',
48
+ 'puoi', 'posso', 'siamo', 'abbiamo', 'erano', 'servono', 'vuole', 'vuoi', 'quale', 'quali',
49
+ 'disponibile', 'necessario', 'corretto', 'sbagliato', 'mancante', 'vuoto', 'ultimo', 'ultima',
50
+ 'italiano', 'italiana', 'italiane', 'inglese', 'pero', 'cosi', 'piu', 'ecco', 'grazie',
51
+ // Added after a later review found UI labels, alert text and a doc line the list above
52
+ // missed (session drawer, lineage and dashboard toolbars, system-health alerts).
53
+ 'stato', 'tipo', 'costo', 'costi', 'durata', 'inizio', 'aggiorn', 'azioni', 'recenti',
54
+ 'grafo', 'reimposta', 'periodo', 'agenti', 'agente', 'apri', 'soglia', 'coprire',
55
+ 'contenuti', 'allinea', 'allineare', 'campioni', 'consecutivi',
38
56
  ];
39
57
 
40
58
  const EXTENSIONS = ['.ts', '.tsx', '.js', '.mjs', '.cjs', '.md', '.json', '.sh', '.yml', '.yaml', '.css', '.html'];
@@ -1,82 +1,100 @@
1
1
  #!/usr/bin/env bash
2
- # restore.sh — Restore Rev4a data from a backup archive
2
+ # restore.sh — restore Rev4a's data directory from a backup.sh archive
3
3
  #
4
4
  # Usage:
5
- # sudo bash scripts/restore.sh backups/rev4a-backup-20260724-120000.tar.gz
5
+ # bash scripts/restore.sh ~/rev4a-backups/rev4a-backup-20260926-120000.tar.gz
6
6
  #
7
- # The script restores:
8
- # - data/*.db
9
- # - data/provider-keys.json
10
- # - data/agents-token.json
11
- # - models.config.json
12
- # - .env
7
+ # Restores into $REV4A_DATA_DIR when set, otherwise ~/.config/rev4a — the directory
8
+ # backup.sh archived. Run it as the user Rev4a runs as: under `sudo` HOME becomes /root
9
+ # and REV4A_DATA_DIR is dropped, so pass it explicitly (`sudo REV4A_DATA_DIR=… bash …`).
13
10
  #
14
- # Existing files are backed up to a .pre-restore directory before overwriting.
11
+ # The data directory is replaced as a whole, not overwritten file by file: a file the
12
+ # backup does not have (a leftover SQLite -wal, for one) would otherwise be mixed into
13
+ # the restored state. The current contents are archived first into ~/rev4a-backups, so a
14
+ # restore can itself be undone.
15
+ #
16
+ # Rev4a must not be running. When the rev4a systemd service is active it is stopped (and
17
+ # must be started again afterwards); a `rev4a serve` started any other way makes the
18
+ # script refuse until it is stopped.
15
19
  set -euo pipefail
16
20
 
17
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
- REV4A_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
19
-
21
+ DATA_DIR="${REV4A_DATA_DIR:-${HOME}/.config/rev4a}"
22
+ PRE_DIR="${HOME}/rev4a-backups"
20
23
  ARCHIVE="${1:-}"
21
24
 
22
25
  if [[ -z "$ARCHIVE" ]]; then
23
- echo "Usage: sudo bash scripts/restore.sh <backup-archive.tar.gz>"
26
+ echo "Usage: bash scripts/restore.sh <rev4a-backup-….tar.gz>"
24
27
  echo ""
25
- echo "Available backups:"
26
- if [[ -d "${REV4A_ROOT}/backups" ]]; then
27
- ls -lh "${REV4A_ROOT}/backups/"*.tar.gz 2>/dev/null || echo " (none)"
28
- else
29
- echo " (no backups directory)"
30
- fi
28
+ echo "Backups in ~/rev4a-backups:"
29
+ ls -lh "${HOME}/rev4a-backups/"rev4a-backup-*.tar.gz 2>/dev/null || echo " (none)"
31
30
  exit 1
32
31
  fi
33
-
34
32
  if [[ ! -f "$ARCHIVE" ]]; then
35
- echo "Error: Archive not found: $ARCHIVE"
33
+ echo "Error: archive not found: $ARCHIVE" >&2
36
34
  exit 1
37
35
  fi
36
+ if [[ ! -d "$DATA_DIR" ]]; then
37
+ # Restoring into a directory nothing reads would "succeed" and change nothing. On a new
38
+ # machine, create it first — the check is only there to catch a wrong path.
39
+ echo "Error: Rev4a data directory not found: $DATA_DIR" >&2
40
+ echo "Set REV4A_DATA_DIR to the directory Rev4a uses, or create it first on a new machine." >&2
41
+ exit 1
42
+ fi
43
+ # The real directory: when the path is a symlink, the swap below replaces its target.
44
+ DATA_DIR="$(cd "$DATA_DIR" && pwd -P)"
38
45
 
39
- echo "Restoring Rev4a from: $ARCHIVE"
40
- echo ""
41
-
42
- # Create pre-restore backup of current state
43
- PRE_DIR="${REV4A_ROOT}/backups/.pre-restore-$(date -u +%Y%m%d-%H%M%S)"
44
- mkdir -p "$PRE_DIR"
45
-
46
- echo "Saving current state to: $PRE_DIR"
47
- cd "$REV4A_ROOT"
48
- for f in data/*.db data/*.db-shm data/*.db-wal data/provider-keys.json data/agents-token.json models.config.json .env; do
49
- if [[ -f "$f" ]]; then
50
- cp --parents "$f" "$PRE_DIR/" 2>/dev/null || true
51
- fi
52
- done
46
+ # Refuse an archive that is not a backup.sh archive of a Rev4a data directory. The listing
47
+ # is read whole: `grep -q` would stop reading early and, with pipefail, turn tar's SIGPIPE
48
+ # into a false refusal on large archives.
49
+ LISTING="$(tar -tvzf "$ARCHIVE")"
50
+ if ! grep -E '[[:space:]]\./(\.env|data/)' <<<"$LISTING" >/dev/null; then
51
+ echo "Error: $ARCHIVE does not look like a Rev4a data backup (no .env or data/ inside)." >&2
52
+ exit 1
53
+ fi
54
+ # backup.sh never stores links; a link in the archive could point outside the data directory.
55
+ if grep -E '^[lh]' <<<"$LISTING" >/dev/null; then
56
+ echo "Error: $ARCHIVE contains symbolic or hard links — refusing to restore it." >&2
57
+ exit 1
58
+ fi
53
59
 
54
- # Stop Rev4a services before restore
55
- if systemctl is-active --quiet rev4a.service 2>/dev/null; then
56
- echo "Stopping Rev4a services..."
57
- sudo systemctl stop rev4a.service
58
- echo "Services stopped."
60
+ if command -v systemctl >/dev/null 2>&1 && systemctl is-active --quiet rev4a.service 2>/dev/null; then
61
+ echo "Stopping rev4a.service..."
62
+ systemctl stop rev4a.service
63
+ STOPPED=1
64
+ fi
65
+ if pgrep -f 'rev4a(\.js)? serve' >/dev/null 2>&1; then
66
+ echo "Error: Rev4a is running (rev4a serve). Stop it first: it keeps the databases open." >&2
67
+ exit 1
59
68
  fi
60
69
 
61
- # Extract the archive
62
- echo "Extracting backup..."
63
- tar -xzf "$ARCHIVE" -C "$REV4A_ROOT"
70
+ umask 077
71
+ mkdir -p "$PRE_DIR"
72
+ PRE="${PRE_DIR}/rev4a-pre-restore-$(date -u +%Y%m%d-%H%M%S).tar.gz"
73
+ echo "Archiving the current state first: $PRE"
74
+ set -o noclobber
75
+ tar -C "$DATA_DIR" -czf - . > "$PRE"
76
+ set +o noclobber
77
+ chmod 600 "$PRE"
64
78
 
65
- # Fix permissions
66
- chmod 600 "${REV4A_ROOT}/.env" 2>/dev/null || true
67
- chmod 600 "${REV4A_ROOT}/data/provider-keys.json" 2>/dev/null || true
68
- chmod 600 "${REV4A_ROOT}/data/agents-token.json" 2>/dev/null || true
79
+ # Extract next to the data directory, then swap: a failed extraction leaves the current
80
+ # data untouched, and nothing from the current state survives into the restored one.
81
+ PARENT="$(dirname "$DATA_DIR")"
82
+ STAGE="$(mktemp -d "${PARENT}/.rev4a-restore.XXXXXX")"
83
+ trap 'rm -rf "$STAGE"' EXIT
84
+ echo "Restoring into: $DATA_DIR"
85
+ tar -C "$STAGE" --no-same-owner -xzf "$ARCHIVE"
86
+ find "$STAGE" -type d -exec chmod 700 {} +
87
+ [[ -f "$STAGE/.env" ]] && chmod 600 "$STAGE/.env"
88
+ [[ -d "$STAGE/data" ]] && find "$STAGE/data" -type f -exec chmod 600 {} +
89
+
90
+ OLD="${PARENT}/.rev4a-replaced.$$"
91
+ mv "$DATA_DIR" "$OLD"
92
+ mv "$STAGE" "$DATA_DIR"
93
+ trap - EXIT
94
+ rm -rf "$OLD"
69
95
 
70
96
  echo ""
71
- echo "=============================================="
72
- echo " Restore complete!"
73
- echo "=============================================="
74
- echo ""
75
- echo " Previous state saved to: ${PRE_DIR}"
76
- echo ""
77
- echo " To restart Rev4a:"
78
- echo " sudo systemctl start rev4a.service"
79
- echo ""
80
- echo " If something went wrong, restore previous state from:"
81
- echo " ${PRE_DIR}"
82
- echo "=============================================="
97
+ echo "Restore complete."
98
+ echo "The previous state is in: $PRE"
99
+ [[ -n "${STOPPED:-}" ]] && echo "Start Rev4a again: systemctl start rev4a.service"
100
+ exit 0