intermesh 0.4.4__tar.gz → 0.4.5__tar.gz
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.
- {intermesh-0.4.4 → intermesh-0.4.5}/PKG-INFO +1 -1
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/__init__.py +1 -1
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/admin.py +28 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/agent.py +20 -2
- intermesh-0.4.5/intermesh/backpressure.py +238 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/404.html +1 -1
- intermesh-0.4.4/intermesh/console/_next/static/chunks/app/(app)/layout-f4df5f69d3f589c2.js → intermesh-0.4.5/intermesh/console/_next/static/chunks/app/(app)/layout-5acef3b51b22acab.js +1 -1
- intermesh-0.4.5/intermesh/console/_next/static/chunks/app/page-a7b8793e2971aba6.js +1 -0
- intermesh-0.4.5/intermesh/console/_next/static/chunks/app/pricing/page-0cf2650bbac40063.js +1 -0
- intermesh-0.4.4/intermesh/console/_next/static/chunks/app/privacy/page-a174a9a93fe3878b.js → intermesh-0.4.5/intermesh/console/_next/static/chunks/app/privacy/page-108901b94493a585.js +1 -1
- intermesh-0.4.5/intermesh/console/_next/static/chunks/app/terms/page-9a0f507db0aa3753.js +1 -0
- intermesh-0.4.5/intermesh/console/agents.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/agents.txt +2 -2
- intermesh-0.4.5/intermesh/console/billing.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/billing.txt +2 -2
- intermesh-0.4.5/intermesh/console/dashboard.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/dashboard.txt +2 -2
- intermesh-0.4.5/intermesh/console/index.html +16 -0
- intermesh-0.4.5/intermesh/console/keys.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/keys.txt +2 -2
- intermesh-0.4.5/intermesh/console/resumes.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/resumes.txt +2 -2
- intermesh-0.4.5/intermesh/console/security.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/security.txt +2 -2
- intermesh-0.4.5/intermesh/console/settings.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/settings.txt +2 -2
- intermesh-0.4.5/intermesh/console/topology.html +16 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/topology.txt +2 -2
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/hub.py +105 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/PKG-INFO +1 -1
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/SOURCES.txt +8 -7
- {intermesh-0.4.4 → intermesh-0.4.5}/pyproject.toml +1 -1
- intermesh-0.4.4/intermesh/console/_next/static/chunks/app/page-87a495a94367a354.js +0 -1
- intermesh-0.4.4/intermesh/console/_next/static/chunks/app/pricing/page-2974422c8313b9fb.js +0 -1
- intermesh-0.4.4/intermesh/console/_next/static/chunks/app/terms/page-9edb6611123f297b.js +0 -1
- intermesh-0.4.4/intermesh/console/agents.html +0 -16
- intermesh-0.4.4/intermesh/console/billing.html +0 -16
- intermesh-0.4.4/intermesh/console/dashboard.html +0 -16
- intermesh-0.4.4/intermesh/console/index.html +0 -16
- intermesh-0.4.4/intermesh/console/keys.html +0 -16
- intermesh-0.4.4/intermesh/console/resumes.html +0 -16
- intermesh-0.4.4/intermesh/console/security.html +0 -16
- intermesh-0.4.4/intermesh/console/settings.html +0 -16
- intermesh-0.4.4/intermesh/console/topology.html +0 -16
- {intermesh-0.4.4 → intermesh-0.4.5}/README.md +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/adapters.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/apikeys.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/approval.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/audit.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/bridge.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/cli.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/config.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/__init__.py +0 -0
- {intermesh-0.4.4/intermesh/console/_next/static/KMDTX1M4Qps8KJbsS4qfy → intermesh-0.4.5/intermesh/console/_next/static/8A7tou8DfWGFVRtP-NDfC}/_buildManifest.js +0 -0
- {intermesh-0.4.4/intermesh/console/_next/static/KMDTX1M4Qps8KJbsS4qfy → intermesh-0.4.5/intermesh/console/_next/static/8A7tou8DfWGFVRtP-NDfC}/_ssgManifest.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/117-279de47ad86d55f2.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/283-7828913da424ef26.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/44530001-792177c4c52bbd93.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/451-d950d00746903c71.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/67.55c167dcccf37409.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/845-1b26226a3e7e86ee.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/agents/page-e2b539ca4d8e901f.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/billing/page-ad7e25cb466a1d75.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/dashboard/page-ef7c7b6a0300c304.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/keys/page-38e3537a90794291.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/resumes/page-b92a0a12233cda42.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/security/page-2b0ec08aad65bca2.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/settings/page-ecd261e5d7fcb349.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/(app)/topology/page-faa778b14d5de62f.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/_not-found/page-6d4614157fff2d5f.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/docs/page-9b599783e780a1ca.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/app/layout-904d511bcfb3dc49.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/fd9d1056-d17313c03983f67e.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/framework-f66176bb897dc684.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/main-3dfb547d0081738b.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/main-app-bcf1b654d275aa86.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/pages/_app-72b849fbd24ac258.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/pages/_error-7ba65e1336b92748.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/polyfills-42372ed130431b0a.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/chunks/webpack-881ca5d5b20426f9.js +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/_next/static/css/d3ada213244fbd00.css +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/icon.png +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/intermesh-logo.png +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/console/opengraph-image +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/crypto.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/egress.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/escrow.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/guardrails.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/hardware.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/health.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/identity.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/logger.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/message.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/metrics.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/peering.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/pipeline.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/policy.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/ratelimit.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/schema.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/secret.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/signing.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/snapshot.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/store.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh/task.py +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/dependency_links.txt +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/entry_points.txt +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/requires.txt +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/intermesh.egg-info/top_level.txt +0 -0
- {intermesh-0.4.4 → intermesh-0.4.5}/setup.cfg +0 -0
|
@@ -97,6 +97,7 @@ class AdminContext:
|
|
|
97
97
|
snapshot_dir: Any = None,
|
|
98
98
|
pending_approvals: Any = None,
|
|
99
99
|
finalize_task: Callable | None = None,
|
|
100
|
+
backpressure: Any = None,
|
|
100
101
|
):
|
|
101
102
|
# Tâches retenues en attente d'arbitrage humain, et le moyen de les
|
|
102
103
|
# relâcher. `finalize_task` est le même chemin que celui d'une
|
|
@@ -116,6 +117,10 @@ class AdminContext:
|
|
|
116
117
|
self.my_org = my_org
|
|
117
118
|
self.remember_task = remember_task
|
|
118
119
|
self.send_to_agent = send_to_agent
|
|
120
|
+
# Portail de contre-pression, pour exposer la saturation : sans ce
|
|
121
|
+
# chiffre, un exploitant ne voit la saturation qu'au moment où les
|
|
122
|
+
# clients tombent en délai d'attente.
|
|
123
|
+
self.backpressure = backpressure
|
|
119
124
|
self.hub_version = hub_version
|
|
120
125
|
# Organisation du porteur du token, et `True` si son rôle est
|
|
121
126
|
# `org_admin` — auquel cas chaque commande doit filtrer sa vue et
|
|
@@ -216,10 +221,33 @@ def _hub_info(ctx: AdminContext, params: dict) -> dict:
|
|
|
216
221
|
"api_keys": api_keys_count,
|
|
217
222
|
"api_keys_source": ctx.api_keys.source,
|
|
218
223
|
"api_keys_mutable": ctx.api_keys.mutable,
|
|
224
|
+
"load": _load_snapshot(ctx),
|
|
219
225
|
"server_time": time.time(),
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
|
|
229
|
+
def _load_snapshot(ctx: AdminContext) -> dict:
|
|
230
|
+
"""Charge et saturation, ou `None` hors contre-pression.
|
|
231
|
+
|
|
232
|
+
Rendu dans `hub.info` plutôt que dans une commande à part : c'est la
|
|
233
|
+
première chose qu'un exploitant consulte, et l'y cacher derrière un
|
|
234
|
+
second appel revient à ne pas l'exposer.
|
|
235
|
+
"""
|
|
236
|
+
gate = getattr(ctx, "backpressure", None)
|
|
237
|
+
if gate is None:
|
|
238
|
+
return {"enabled": False, "note": "contre-pression non configurée"}
|
|
239
|
+
|
|
240
|
+
in_flight = 0
|
|
241
|
+
queued = 0
|
|
242
|
+
for task in ctx.task_registry.values():
|
|
243
|
+
if task.status.value in ("completed", "failed"):
|
|
244
|
+
continue
|
|
245
|
+
in_flight += 1
|
|
246
|
+
if task.status.value == "pending":
|
|
247
|
+
queued += 1
|
|
248
|
+
return gate.snapshot(in_flight, queued)
|
|
249
|
+
|
|
250
|
+
|
|
223
251
|
def _agents_list(ctx: AdminContext, params: dict) -> dict:
|
|
224
252
|
"""
|
|
225
253
|
Inventaire complet : les agents connectés, mais aussi ceux connus et
|
|
@@ -465,9 +465,27 @@ class InterMeshAgent:
|
|
|
465
465
|
future.set_exception(PermissionError(msg.content))
|
|
466
466
|
else:
|
|
467
467
|
future.set_exception(RuntimeError(msg.content))
|
|
468
|
-
|
|
469
|
-
|
|
468
|
+
# Un refus qui nomme sa tâche ne concerne qu'elle. Faire
|
|
469
|
+
# échouer toutes les tâches en vol sur un refus ciblé
|
|
470
|
+
# était sans conséquence tant que les erreurs étaient
|
|
471
|
+
# rares ; sous contre-pression elles sont fréquentes, et
|
|
472
|
+
# un seul refus aurait anéanti tout le travail légitime
|
|
473
|
+
# du même orchestrateur.
|
|
474
|
+
named = (msg.content.get("task_id")
|
|
475
|
+
if isinstance(msg.content, dict) else None)
|
|
476
|
+
if named:
|
|
477
|
+
fut = self._pending_tasks.pop(named, None)
|
|
478
|
+
if fut is not None and not fut.done():
|
|
470
479
|
fut.set_exception(RuntimeError(msg.content))
|
|
480
|
+
else:
|
|
481
|
+
# Erreur qui ne nomme aucune tâche : escrow refusé,
|
|
482
|
+
# garde-fou, rupture de lien. On ne peut pas savoir
|
|
483
|
+
# laquelle est visée, donc toutes tombent — c'est le
|
|
484
|
+
# comportement historique, et le restreindre ici
|
|
485
|
+
# laissait ces refus sans effet.
|
|
486
|
+
for tid, fut in list(self._pending_tasks.items()):
|
|
487
|
+
if not fut.done():
|
|
488
|
+
fut.set_exception(RuntimeError(msg.content))
|
|
471
489
|
self._pending_tasks.pop(tid)
|
|
472
490
|
|
|
473
491
|
except websockets.ConnectionClosed:
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Contre-pression : dire non quand le Hub est saturé, plutôt que d'accepter.
|
|
3
|
+
|
|
4
|
+
Le garde-fou existant plafonne les soumissions **par agent** (60/minute).
|
|
5
|
+
Il protège d'un agent devenu fou, pas de la saturation : cent agents
|
|
6
|
+
sages, à un tiers de leur quota chacun, dépassent largement ce qu'un Hub
|
|
7
|
+
soutient.
|
|
8
|
+
|
|
9
|
+
Ce que le banc de mesure a montré, et qu'il ne faut pas contredire sans
|
|
10
|
+
nouvelle mesure :
|
|
11
|
+
|
|
12
|
+
* plafond observé sur un Hub : environ 11 tâches/s, indépendant du
|
|
13
|
+
nombre d'agents (78 comme 234) — c'est le Hub qui borne, pas la flotte ;
|
|
14
|
+
* zone saine : jusqu'à 8 tâches/s avec chiffrement, p50 sous la seconde ;
|
|
15
|
+
* au-delà, le Hub acceptait tout, mettait en file, la latence explosait,
|
|
16
|
+
et les clients mouraient sur un délai de ping WebSocket. Le processus
|
|
17
|
+
survivait, mais **aucun signal ne disait que le Hub était saturé**.
|
|
18
|
+
|
|
19
|
+
Un refus explicite vaut mieux qu'une acceptation qui n'aboutira pas :
|
|
20
|
+
l'émetteur peut réessayer plus tard, réduire sa cadence, ou basculer
|
|
21
|
+
ailleurs. Une file qui gonfle en silence ne lui laisse que le délai
|
|
22
|
+
d'attente, c'est-à-dire l'ignorance.
|
|
23
|
+
|
|
24
|
+
Ce module ne connaît rien du Hub : il reçoit les compteurs et rend une
|
|
25
|
+
décision. C'est ce qui le rend vérifiable sans réseau.
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import os
|
|
31
|
+
import time
|
|
32
|
+
from dataclasses import dataclass, field
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _env_int(name: str, default: int) -> int:
|
|
36
|
+
raw = os.environ.get(name)
|
|
37
|
+
if raw is None or not str(raw).strip():
|
|
38
|
+
return default
|
|
39
|
+
try:
|
|
40
|
+
value = int(str(raw).strip())
|
|
41
|
+
except ValueError:
|
|
42
|
+
return default
|
|
43
|
+
return value if value >= 0 else default
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _env_bool(name: str, default: bool) -> bool:
|
|
47
|
+
raw = os.environ.get(name)
|
|
48
|
+
if raw is None:
|
|
49
|
+
return default
|
|
50
|
+
return str(raw).strip().lower() not in ("0", "false", "no", "off", "")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class BackpressureLimits:
|
|
55
|
+
"""Les trois plafonds, et l'interrupteur.
|
|
56
|
+
|
|
57
|
+
Les défauts viennent de la mesure, pas d'une intuition : 10 tâches/s
|
|
58
|
+
est le plafond observé arrondi, et laisse la zone saine (8/s) intacte.
|
|
59
|
+
Un déploiement qui mesure autre chose sur son propre matériel doit les
|
|
60
|
+
relever — d'où des réglages, et non des constantes.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
max_tasks_per_sec: int = 10
|
|
64
|
+
max_in_flight: int = 200
|
|
65
|
+
max_queue_depth: int = 100
|
|
66
|
+
enabled: bool = True
|
|
67
|
+
|
|
68
|
+
@classmethod
|
|
69
|
+
def from_env(cls) -> "BackpressureLimits":
|
|
70
|
+
return cls(
|
|
71
|
+
max_tasks_per_sec=_env_int("INTERMESH_MAX_TASKS_PER_SEC", 10),
|
|
72
|
+
max_in_flight=_env_int("INTERMESH_MAX_TASKS_IN_FLIGHT", 200),
|
|
73
|
+
max_queue_depth=_env_int("INTERMESH_MAX_TASK_QUEUE_DEPTH", 100),
|
|
74
|
+
enabled=_env_bool("INTERMESH_BACKPRESSURE_ENABLED", True),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class Rejection:
|
|
80
|
+
"""Un refus, avec de quoi agir : pourquoi, et dans combien de temps."""
|
|
81
|
+
|
|
82
|
+
reason: str # rate_limited | in_flight_limit | task_queue_full
|
|
83
|
+
retry_after_ms: int
|
|
84
|
+
queue_depth: int
|
|
85
|
+
in_flight: int
|
|
86
|
+
limits: BackpressureLimits
|
|
87
|
+
|
|
88
|
+
code: str = "HUB_SATURATED"
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> dict:
|
|
91
|
+
return {
|
|
92
|
+
"code": self.code,
|
|
93
|
+
"reason": self.reason,
|
|
94
|
+
"retry_after_ms": self.retry_after_ms,
|
|
95
|
+
"queue_depth": self.queue_depth,
|
|
96
|
+
"in_flight": self.in_flight,
|
|
97
|
+
"hub_tasks_per_sec_limit": self.limits.max_tasks_per_sec,
|
|
98
|
+
"hub_in_flight_limit": self.limits.max_in_flight,
|
|
99
|
+
"hub_queue_depth_limit": self.limits.max_queue_depth,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
def __str__(self) -> str:
|
|
103
|
+
return (f"HUB_SATURATED ({self.reason}) : le Hub refuse cette tâche pour "
|
|
104
|
+
f"ne pas la mettre dans une file qui n'avancera pas. "
|
|
105
|
+
f"Réessayez dans {self.retry_after_ms} ms. "
|
|
106
|
+
f"File {self.queue_depth}/{self.limits.max_queue_depth}, "
|
|
107
|
+
f"en vol {self.in_flight}/{self.limits.max_in_flight}, "
|
|
108
|
+
f"plafond {self.limits.max_tasks_per_sec} tâches/s.")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class BackpressureGate:
|
|
112
|
+
"""Décide d'accepter ou de refuser une soumission.
|
|
113
|
+
|
|
114
|
+
Le débit est contrôlé par un seau à jetons plutôt qu'une fenêtre
|
|
115
|
+
glissante : à cadence régulière les deux se valent, mais le seau
|
|
116
|
+
absorbe une rafale courte sans la refuser, ce qui correspond à ce que
|
|
117
|
+
fait un orchestrateur qui découpe un travail en lots.
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
def __init__(self, limits: BackpressureLimits | None = None,
|
|
121
|
+
now: float | None = None):
|
|
122
|
+
self.limits = limits or BackpressureLimits()
|
|
123
|
+
# Le seau démarre plein : un Hub qui vient de démarrer ne doit pas
|
|
124
|
+
# refuser la première rafale au motif qu'il n'a pas encore
|
|
125
|
+
# accumulé de jetons.
|
|
126
|
+
self._tokens = float(self.limits.max_tasks_per_sec)
|
|
127
|
+
self._last = now if now is not None else time.monotonic()
|
|
128
|
+
|
|
129
|
+
self.accepted = 0
|
|
130
|
+
self.rejected = 0
|
|
131
|
+
self.rejected_by_reason: dict[str, int] = {}
|
|
132
|
+
self._last_logged: float | None = None
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------
|
|
135
|
+
|
|
136
|
+
def _refill(self, now: float) -> None:
|
|
137
|
+
elapsed = max(0.0, now - self._last)
|
|
138
|
+
self._last = now
|
|
139
|
+
capacity = float(self.limits.max_tasks_per_sec)
|
|
140
|
+
self._tokens = min(capacity, self._tokens + elapsed * capacity)
|
|
141
|
+
|
|
142
|
+
def _retry_after_ms(self) -> int:
|
|
143
|
+
"""Délai avant qu'un jeton soit à nouveau disponible.
|
|
144
|
+
|
|
145
|
+
Renvoyé au client pour qu'il attende la bonne durée plutôt que de
|
|
146
|
+
réessayer aussitôt — un réessai immédiat aggrave la saturation
|
|
147
|
+
qu'il vient de rencontrer.
|
|
148
|
+
"""
|
|
149
|
+
rate = self.limits.max_tasks_per_sec
|
|
150
|
+
if rate <= 0:
|
|
151
|
+
return 1000
|
|
152
|
+
missing = max(0.0, 1.0 - self._tokens)
|
|
153
|
+
return max(1, int(round((missing / rate) * 1000)))
|
|
154
|
+
|
|
155
|
+
# ------------------------------------------------------------------
|
|
156
|
+
|
|
157
|
+
def admit(self, in_flight: int, queue_depth: int,
|
|
158
|
+
now: float | None = None) -> Rejection | None:
|
|
159
|
+
"""Renvoie None si la tâche est acceptée, sinon le refus.
|
|
160
|
+
|
|
161
|
+
L'ordre des contrôles n'est pas indifférent : les plafonds d'état
|
|
162
|
+
(en vol, file) passent avant le débit, parce qu'un Hub déjà plein
|
|
163
|
+
doit refuser même s'il lui reste des jetons — sinon on accepterait
|
|
164
|
+
une tâche dont on sait déjà qu'elle attendra.
|
|
165
|
+
"""
|
|
166
|
+
if not self.limits.enabled:
|
|
167
|
+
self.accepted += 1
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
now = time.monotonic() if now is None else now
|
|
171
|
+
|
|
172
|
+
if self.limits.max_in_flight and in_flight >= self.limits.max_in_flight:
|
|
173
|
+
return self._refuse("in_flight_limit", 1000, in_flight, queue_depth)
|
|
174
|
+
|
|
175
|
+
if self.limits.max_queue_depth and queue_depth >= self.limits.max_queue_depth:
|
|
176
|
+
return self._refuse("task_queue_full", 1000, in_flight, queue_depth)
|
|
177
|
+
|
|
178
|
+
self._refill(now)
|
|
179
|
+
if self.limits.max_tasks_per_sec and self._tokens < 1.0:
|
|
180
|
+
return self._refuse("rate_limited", self._retry_after_ms(),
|
|
181
|
+
in_flight, queue_depth)
|
|
182
|
+
|
|
183
|
+
self._tokens -= 1.0
|
|
184
|
+
self.accepted += 1
|
|
185
|
+
return None
|
|
186
|
+
|
|
187
|
+
def _refuse(self, reason: str, retry_after_ms: int,
|
|
188
|
+
in_flight: int, queue_depth: int) -> Rejection:
|
|
189
|
+
self.rejected += 1
|
|
190
|
+
self.rejected_by_reason[reason] = self.rejected_by_reason.get(reason, 0) + 1
|
|
191
|
+
return Rejection(
|
|
192
|
+
reason=reason, retry_after_ms=retry_after_ms,
|
|
193
|
+
queue_depth=queue_depth, in_flight=in_flight, limits=self.limits,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# ------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
def note_rejection(self, now: float, window_s: float = 10.0) -> bool:
|
|
199
|
+
"""Faut-il journaliser ce refus ? Une fois par période, pas plus.
|
|
200
|
+
|
|
201
|
+
Écrire chaque refus dans la chaîne d'audit ajoute un hachage Merkle
|
|
202
|
+
par refus — donc du travail proportionnel à la saturation, au pire
|
|
203
|
+
moment. Le compte exact reste disponible dans les compteurs ; ce
|
|
204
|
+
qu'un exploitant a besoin de voir dans l'audit, c'est *quand* le Hub
|
|
205
|
+
est entré en saturation, pas les milliers de refus qui suivent.
|
|
206
|
+
"""
|
|
207
|
+
if self._last_logged is None or (now - self._last_logged) >= window_s:
|
|
208
|
+
self._last_logged = now
|
|
209
|
+
return True
|
|
210
|
+
return False
|
|
211
|
+
|
|
212
|
+
def snapshot(self, in_flight: int, queue_depth: int) -> dict:
|
|
213
|
+
"""État lisible par un exploitant ou une sonde."""
|
|
214
|
+
return {
|
|
215
|
+
"enabled": self.limits.enabled,
|
|
216
|
+
"in_flight": in_flight,
|
|
217
|
+
"queue_depth": queue_depth,
|
|
218
|
+
"accepted_total": self.accepted,
|
|
219
|
+
"rejected_total": self.rejected,
|
|
220
|
+
"rejected_by_reason": dict(self.rejected_by_reason),
|
|
221
|
+
"tokens_available": round(self._tokens, 2),
|
|
222
|
+
"limits": {
|
|
223
|
+
"tasks_per_sec": self.limits.max_tasks_per_sec,
|
|
224
|
+
"in_flight": self.limits.max_in_flight,
|
|
225
|
+
"queue_depth": self.limits.max_queue_depth,
|
|
226
|
+
},
|
|
227
|
+
# Ce que l'exploitant regarde en premier : suis-je proche du mur ?
|
|
228
|
+
"saturation": {
|
|
229
|
+
"in_flight_pct": _pct(in_flight, self.limits.max_in_flight),
|
|
230
|
+
"queue_depth_pct": _pct(queue_depth, self.limits.max_queue_depth),
|
|
231
|
+
},
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _pct(value: int, limit: int) -> int:
|
|
236
|
+
if not limit:
|
|
237
|
+
return 0
|
|
238
|
+
return min(100, int(round(100.0 * value / limit)))
|
|
@@ -13,4 +13,4 @@
|
|
|
13
13
|
document.documentElement.classList.add('theme-ready');
|
|
14
14
|
});
|
|
15
15
|
})();
|
|
16
|
-
</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="min-h-screen bg-white font-sans text-slate-900 antialiased selection:bg-cyan-500/25 dark:bg-[#08080A] dark:text-slate-100"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-881ca5d5b20426f9.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/d3ada213244fbd00.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\nb:I[1060,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"
|
|
16
|
+
</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="min-h-screen bg-white font-sans text-slate-900 antialiased selection:bg-cyan-500/25 dark:bg-[#08080A] dark:text-slate-100"><div style="font-family:system-ui,"Segoe UI",Roboto,Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji";height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><script src="/_next/static/chunks/webpack-881ca5d5b20426f9.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/d3ada213244fbd00.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[4707,[],\"\"]\n5:I[6423,[],\"\"]\nb:I[1060,[],\"\"]\n6:{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"}\n7:{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"}\n8:{\"display\":\"inline-block\"}\n9:{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0}\nc:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"8A7tou8DfWGFVRtP-NDfC\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"_not-found\"],\"initialTree\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null],null],null]},[null,[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"/_not-found\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/d3ada213244fbd00.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n(function () {\\n try {\\n var stored = localStorage.getItem('intermesh-theme');\\n var dark = stored\\n ? stored === 'dark'\\n : window.matchMedia('(prefers-color-scheme: dark)').matches;\\n document.documentElement.classList.toggle('dark', dark);\\n } catch (e) {\\n document.documentElement.classList.add('dark');\\n }\\n requestAnimationFrame(function () {\\n document.documentElement.classList.add('theme-ready');\\n });\\n})();\\n\"}}]}],[\"$\",\"body\",null,{\"className\":\"min-h-screen bg-white font-sans text-slate-900 antialiased selection:bg-cyan-500/25 dark:bg-[#08080A] dark:text-slate-100\",\"suppressHydrationWarning\":true,\"children\":[\"$\",\"$L4\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L5\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$6\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$7\",\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":\"$8\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$9\",\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]}]]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],\"$La\"],\"globalErrorComponent\":\"$b\",\"missingSlots\":\"$Wc\"}]\n"])</script><script>self.__next_f.push([1,"a:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"InterMesh — The coordination protocol for AI agents\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Open-source protocol that lets AI agents find each other, delegate work, and negotiate across organizations — with end-to-end encryption and a verifiable audit log.\"}],[\"$\",\"meta\",\"4\",{\"name\":\"keywords\",\"content\":\"AI agents,agent protocol,multi-agent,agent coordination,open source,MCP,A2A\"}],[\"$\",\"meta\",\"5\",{\"name\":\"robots\",\"content\":\"index, follow\"}],[\"$\",\"link\",\"6\",{\"rel\":\"canonical\",\"href\":\"https://intermesh.site\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:title\",\"content\":\"InterMesh — The coordination protocol for AI agents\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:description\",\"content\":\"Let AI agents discover each other, talk, and delegate work — across teams, and across the boundary between two organizations that do not trust each other.\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:url\",\"content\":\"https://intermesh.site\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:site_name\",\"content\":\"InterMesh\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"12\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"13\",{\"name\":\"twitter:title\",\"content\":\"InterMesh — The coordination protocol for AI agents\"}],[\"$\",\"meta\",\"14\",{\"name\":\"twitter:description\",\"content\":\"Open-source protocol for AI agents that work together, across organizations. End-to-end encrypted, with a verifiable audit log.\"}]]\n3:null\n"])</script></body></html>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[814],{152:function(e,t,s){Promise.resolve().then(s.bind(s,247))},401:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]])},4001:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Key",[["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["path",{d:"m15.5 7.5 3 3L22 7l-3-3",key:"1rn1fs"}]])},3420:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]])},9076:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("RotateCcw",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]])},3247:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]])},4286:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("ShieldCheck",[["path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10",key:"1irkt0"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]])},5805:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]])},2489:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]])},247:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return O}});var n=s(7437),r=s(2265),a=s(7648),i=s(5475),l=s(9763);let o=(0,l.Z)("LayoutDashboard",[["rect",{width:"7",height:"9",x:"3",y:"3",rx:"1",key:"10lvy0"}],["rect",{width:"7",height:"5",x:"14",y:"3",rx:"1",key:"16une8"}],["rect",{width:"7",height:"9",x:"14",y:"12",rx:"1",key:"1hutg5"}],["rect",{width:"7",height:"5",x:"3",y:"16",rx:"1",key:"ldoo1y"}]]);var c=s(3420),d=s(5805);let h=(0,l.Z)("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);var x=s(4001),u=s(4286);let m=(0,l.Z)("CreditCard",[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]]),p=(0,l.Z)("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),f=(0,l.Z)("BookOpen",[["path",{d:"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z",key:"vv98re"}],["path",{d:"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z",key:"1cyq3y"}]]);var b=s(9111),g=s(8933),w=s(3247);let y=(0,l.Z)("HelpCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]]),v=(0,l.Z)("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]),j=(0,l.Z)("Bell",[["path",{d:"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9",key:"1qo2s2"}],["path",{d:"M10.3 21a1.94 1.94 0 0 0 3.4 0",key:"qgo35s"}]]),k=(0,l.Z)("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]),N=(0,l.Z)("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);var C=s(2489),Z=s(401);let M=[{id:"overview",label:"Overview & Quotas",description:"Main dashboard and agent limits",href:"/dashboard",icon:o,group:"Navigation"},{id:"agents",label:"Agents Directory",description:"List of connected agents",href:"/agents",icon:d.Z,group:"Navigation"},{id:"keys",label:"API Keys & Licenses",description:"Manage keys and licenses",href:"/keys",icon:x.Z,group:"Navigation"},{id:"security",label:"Audit Log & RBAC",description:"Audit log and permissions",href:"/security",icon:u.Z,group:"Navigation"},{id:"billing",label:"Billing & Plans",description:"Subscription and pricing",href:"/billing",icon:m,group:"Navigation"},{id:"settings",label:"Workspace Settings",description:"Organization settings, members and webhooks",href:"/settings",icon:p,group:"Navigation"},{id:"docs",label:"RFC-001 Documentation",description:"InterMesh protocol specification",href:"/docs",icon:h,group:"Resources"}],S=[],E={"/dashboard":"Overview","/topology":"Topology","/agents":"Agents","/keys":"API keys","/security":"Audit log","/billing":"Billing","/settings":"Settings"};function I(){var e;let t=(0,i.useRouter)(),l=null!==(e=E[(0,i.usePathname)()])&&void 0!==e?e:"Overview",[o,c]=(0,r.useState)(!1),[d,x]=(0,r.useState)(""),[u,m]=(0,r.useState)(!1),[f,I]=(0,r.useState)(!1),[z,L]=(0,r.useState)(!1),[A,T]=(0,r.useState)(S),[R,q]=(0,r.useState)(0),O=(0,r.useRef)(null),H=(0,r.useRef)(null),_=(0,r.useRef)(null),P=(0,r.useRef)(null),F=A.filter(e=>e.unread).length,D=async()=>{if(L(!1),(0,g.j)()){let{signOut:e}=await s.e(67).then(s.bind(s,3067));await e()}t.push("/auth")},U=M.filter(e=>{let t=d.toLowerCase().trim();return!t||e.label.toLowerCase().includes(t)||e.description.toLowerCase().includes(t)||e.group.toLowerCase().includes(t)}),B=U.reduce((e,t)=>(e[t.group]||(e[t.group]=[]),e[t.group].push(t),e),{});(0,r.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&"k"===e.key.toLowerCase()&&(e.preventDefault(),c(!0),m(!1),I(!1),L(!1)),"Escape"===e.key&&(c(!1),m(!1),I(!1),L(!1))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[]),(0,r.useEffect)(()=>{o?(setTimeout(()=>{var e;return null===(e=O.current)||void 0===e?void 0:e.focus()},50),q(0)):x("")},[o]),(0,r.useEffect)(()=>{let e=e=>{let t=e.target;H.current&&!H.current.contains(t)&&m(!1),_.current&&!_.current.contains(t)&&I(!1),P.current&&!P.current.contains(t)&&L(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[]);let J=e=>{c(!1),x(""),t.push(e)};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("header",{className:"sticky top-0 z-20 flex h-14 items-center justify-between border-b px-6 backdrop-blur-xl md:px-8 ".concat(b.T5," ").concat(b.jF),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-sm",children:[(0,n.jsx)("span",{className:"text-slate-400",children:"Control plane"}),(0,n.jsx)("span",{className:"text-slate-500",children:"/"}),(0,n.jsx)("span",{className:"font-medium text-white",children:l})]}),(0,n.jsxs)("div",{className:"flex items-center space-x-3 md:space-x-4",children:[(0,n.jsxs)("button",{onClick:()=>c(!0),className:"hidden md:flex items-center bg-[#141519] border border-white/10 rounded-md px-3 py-1.5 text-xs text-slate-400 w-64 hover:border-white/20 transition text-left",children:[(0,n.jsx)(w.Z,{className:"w-3.5 h-3.5 mr-2 text-slate-400"}),(0,n.jsx)("span",{className:"flex-1 text-slate-400",children:"Search agents, keys..."}),(0,n.jsx)("span",{className:"text-[10px] font-mono border border-white/20 rounded px-1 text-slate-400",children:"⌘K"})]}),(0,n.jsx)("button",{onClick:()=>c(!0),className:"md:hidden text-slate-400 hover:text-white transition p-1",children:(0,n.jsx)(w.Z,{className:"w-4 h-4"})}),(0,n.jsxs)("div",{className:"relative",ref:_,children:[(0,n.jsx)("button",{onClick:()=>I(e=>!e),className:"text-slate-400 hover:text-white transition p-1 rounded ".concat(f?"text-white bg-white/5":""),children:(0,n.jsx)(y,{className:"w-4 h-4"})}),f&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-64 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsx)("div",{className:"px-4 py-3 border-b border-white/10",children:(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Help & Resources"})}),(0,n.jsxs)("div",{className:"p-2 space-y-0.5",children:[(0,n.jsxs)(a.default,{href:"/docs",onClick:()=>I(!1),className:"flex items-center justify-between px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsxs)("span",{className:"flex items-center space-x-2",children:[(0,n.jsx)(h,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"RFC-001 Spec"})]}),(0,n.jsx)(v,{className:"w-3 h-3 text-slate-400"})]}),(0,n.jsx)("a",{href:"https://github.com/intermeshteam/intermesh",target:"_blank",className:"flex items-center justify-between px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:(0,n.jsxs)("span",{className:"flex items-center space-x-2",children:[(0,n.jsx)(v,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"GitHub Repository"})]})})]})]})]}),(0,n.jsxs)("div",{className:"relative",ref:H,children:[(0,n.jsxs)("button",{onClick:()=>m(e=>!e),className:"relative text-slate-400 hover:text-white transition p-1 rounded ".concat(u?"text-white bg-white/5":""),children:[(0,n.jsx)(j,{className:"w-4 h-4"}),F>0&&(0,n.jsx)("span",{className:"absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-red-500 text-[9px] font-bold text-white flex items-center justify-center",children:F})]}),u&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-80 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsxs)("div",{className:"px-4 py-3 border-b border-white/10 flex items-center justify-between",children:[(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Notifications"}),F>0&&(0,n.jsx)("button",{onClick:()=>{T(e=>e.map(e=>({...e,unread:!1})))},className:"text-[11px] text-slate-400 hover:text-white transition",children:"Tout marquer lu"})]}),(0,n.jsx)("div",{className:"max-h-80 overflow-y-auto",children:A.map(e=>(0,n.jsxs)("div",{className:"p-3 border-b border-white/5 hover:bg-white/[0.02]",children:[(0,n.jsx)("div",{className:"text-xs font-semibold text-white",children:e.title}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 mt-0.5",children:e.body})]},e.id))})]})]}),(0,n.jsxs)("div",{className:"relative",ref:P,children:[(0,n.jsx)("button",{onClick:()=>L(e=>!e),className:"w-7 h-7 rounded-full bg-white/10 border border-white/20 text-white font-mono font-bold text-xs flex items-center justify-center hover:bg-white/15 transition",children:"AC"}),z&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-64 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsxs)("div",{className:"px-4 py-3 border-b border-white/10",children:[(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Local workspace"}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 font-mono mt-0.5",children:"self-hosted"})]}),(0,n.jsxs)("div",{className:"p-2 space-y-0.5",children:[(0,n.jsxs)(a.default,{href:"/dashboard",onClick:()=>L(!1),className:"flex items-center space-x-2 px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsx)(k,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Account Overview"})]}),(0,n.jsxs)(a.default,{href:"/settings",onClick:()=>L(!1),className:"flex items-center space-x-2 px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsx)(p,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Workspace Settings"})]})]}),(0,n.jsx)("div",{className:"p-2 border-t border-white/10",children:(0,n.jsxs)("button",{onClick:D,className:"flex w-full items-center space-x-2 px-3 py-2 rounded-lg text-xs text-red-400 hover:bg-red-500/10 transition",children:[(0,n.jsx)(N,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Log out"})]})})]})]})]})]}),o&&(0,n.jsxs)("div",{className:"fixed inset-0 z-[100] flex items-start justify-center pt-[12vh] px-4",children:[(0,n.jsx)("div",{className:"absolute inset-0 bg-black/70 backdrop-blur-sm",onClick:()=>c(!1)}),(0,n.jsxs)("div",{className:"relative w-full max-w-xl bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden",children:[(0,n.jsxs)("div",{className:"flex items-center px-4 border-b border-white/10",children:[(0,n.jsx)(w.Z,{className:"w-4 h-4 text-slate-400 mr-3"}),(0,n.jsx)("input",{ref:O,value:d,onChange:e=>{x(e.target.value),q(0)},onKeyDown:e=>{"ArrowDown"===e.key?(e.preventDefault(),q(e=>Math.min(e+1,Math.max(U.length-1,0)))):"ArrowUp"===e.key?(e.preventDefault(),q(e=>Math.max(e-1,0))):"Enter"===e.key&&U[R]&&(e.preventDefault(),J(U[R].href))},placeholder:"Search agents, keys, settings...",className:"flex-1 bg-transparent py-3.5 text-sm text-white outline-none placeholder:text-slate-400"}),(0,n.jsx)("button",{onClick:()=>c(!1),className:"text-slate-400 hover:text-white p-1",children:(0,n.jsx)(C.Z,{className:"w-4 h-4"})})]}),(0,n.jsx)("div",{className:"max-h-80 overflow-y-auto p-2",children:0===U.length?(0,n.jsxs)("div",{className:"px-3 py-8 text-center text-xs text-slate-400",children:["No results for “",d,"”"]}):Object.entries(B).map(e=>{let[t,s]=e;return(0,n.jsxs)("div",{className:"mb-2",children:[(0,n.jsx)("div",{className:"px-3 py-1.5 text-[10px] font-mono uppercase tracking-wider text-slate-400",children:t}),s.map(e=>{let t=U.findIndex(t=>t.id===e.id),s=e.icon,r=t===R;return(0,n.jsxs)("button",{onClick:()=>J(e.href),onMouseEnter:()=>q(t),className:"w-full flex items-center space-x-3 px-3 py-2.5 rounded-lg text-left transition ".concat(r?"bg-white/10 text-white":"text-slate-300 hover:bg-white/5"),children:[(0,n.jsx)(s,{className:"w-4 h-4 shrink-0 ".concat(r?"text-white":"text-slate-400")}),(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("div",{className:"text-xs font-medium truncate",children:e.label}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 truncate",children:e.description})]}),r&&(0,n.jsx)(Z.Z,{className:"w-3.5 h-3.5 text-slate-400 shrink-0"})]},e.id)})]},t)})})]})]})]})}var z=s(9057),L=s(9076);let A=(0,l.Z)("Pencil",[["path",{d:"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z",key:"5qss01"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);var T=s(5128);function R(){let[e,t]=(0,r.useState)(T.dE),[s,a]=(0,r.useState)("checking"),[i,l]=(0,r.useState)(!1),[o,c]=(0,r.useState)(""),[d,h]=(0,r.useState)(!1),x=(0,r.useRef)(null),u=(0,r.useCallback)(e=>{var t;if(null===(t=x.current)||void 0===t||t.close(),(0,T.Hr)(e)){a("blocked");return}a("checking");let s=!1,n=e=>{s||(s=!0,a(e))};try{let t=new WebSocket(e);x.current=t;let s=setTimeout(()=>{n("offline"),t.close()},4e3);t.onopen=()=>{clearTimeout(s),n("online"),t.close()},t.onerror=()=>{clearTimeout(s),n("offline")},t.onclose=()=>{clearTimeout(s),n("offline")}}catch(e){n("offline")}},[]);(0,r.useEffect)(()=>{let e=(0,T.pP)();return t(e),u(e),()=>{var e;return null===(e=x.current)||void 0===e?void 0:e.close()}},[u]);let m=()=>{let e=o.trim();if(!(0,T.qW)(e)){h(!0);return}(0,T.y2)(e),t(e),l(!1),u(e)};return i?(0,n.jsxs)("div",{className:"space-y-2",children:[(0,n.jsx)("label",{className:"text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-500",children:"Hub address"}),(0,n.jsx)("input",{value:o,autoFocus:!0,onChange:e=>{c(e.target.value),h(!1)},onKeyDown:e=>{"Enter"===e.key&&m(),"Escape"===e.key&&l(!1)},placeholder:"ws://localhost:8765",className:"w-full rounded border bg-white/[0.04] px-2 py-1.5 font-mono text-[11px] text-slate-100 outline-none focus:border-cyan-500/50 ".concat(d?"border-red-500/50":"border-white/[0.1]")}),d&&(0,n.jsx)("p",{className:"text-[10px] text-red-400",children:"Must start with ws:// or wss://"}),(0,n.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,n.jsxs)("button",{onClick:m,className:"inline-flex items-center gap-1 rounded bg-white/10 px-2 py-1 text-[10px] font-medium text-slate-100 transition hover:bg-white/[0.16]",children:[(0,n.jsx)(Z.Z,{className:"h-3 w-3"})," Save"]}),(0,n.jsxs)("button",{onClick:()=>l(!1),className:"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] text-slate-400 transition hover:text-slate-100",children:[(0,n.jsx)(C.Z,{className:"h-3 w-3"})," Cancel"]}),(0,n.jsx)("button",{onClick:()=>{(0,T.l8)(),t(T.dE),l(!1),u(T.dE)},title:"Reset to ".concat(T.dE),className:"ml-auto inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] text-slate-500 transition hover:text-slate-300",children:(0,n.jsx)(L.Z,{className:"h-3 w-3"})})]})]}):(0,n.jsxs)("div",{className:"space-y-1.5",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("span",{className:"text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-500",children:"Hub"}),(0,n.jsx)("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full ".concat("online"===s?"bg-emerald-400":"offline"===s?"bg-red-400":"blocked"===s?"bg-amber-400":"bg-slate-500 animate-pulse"),"aria-hidden":!0}),(0,n.jsx)("span",{className:"text-[10px] text-slate-400",children:"online"===s?"Connected":"offline"===s?"Not reachable":"blocked"===s?"Blocked by the browser":"Checking…"}),(0,n.jsx)("button",{onClick:()=>{c(e),h(!1),l(!0)},title:"Change hub address",className:"ml-auto text-slate-500 transition hover:text-slate-200","aria-label":"Change hub address",children:(0,n.jsx)(A,{className:"h-3 w-3"})})]}),(0,n.jsx)("div",{className:"truncate font-mono text-[11px] text-slate-400",title:e,children:e.replace(/^wss?:\/\//,"")}),"offline"===s&&(0,n.jsxs)("p",{className:"text-[10px] leading-relaxed text-slate-500",children:["Start one with"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono text-slate-300",children:"intermesh hub"}),", then refresh."]}),"blocked"===s&&(0,n.jsxs)("p",{className:"text-[10px] leading-relaxed text-amber-400/80",children:["This page is served over HTTPS, so it cannot open a plain"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"ws://"})," socket to another machine — the browser refuses before connecting. A remote hub has to serve"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"wss://"})," (",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"--tls-cert"})," /"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"--tls-key"}),"). Only localhost is exempt."]})]})}let q=[{label:"Control plane",items:[{name:"Overview",href:"/dashboard",icon:o},{name:"Topology",href:"/topology",icon:c.Z},{name:"Agents",href:"/agents",icon:d.Z},{name:"Summaries",href:"/resumes",icon:h},{name:"API keys",href:"/keys",icon:x.Z},{name:"Audit log",href:"/security",icon:u.Z},{name:"Billing",href:"/billing",icon:m}]},{label:"Workspace",items:[{name:"Settings",href:"/settings",icon:p}]}];function O(e){let{children:t}=e,s=(0,i.usePathname)();return(0,n.jsxs)("div",{className:"dark flex min-h-screen font-sans text-slate-100 ".concat(b._5),children:[(0,n.jsxs)("aside",{className:"fixed bottom-0 left-0 top-0 z-30 flex w-[248px] shrink-0 flex-col justify-between border-r ".concat(b.T5," ").concat(b.iX),children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"flex h-14 items-center gap-2.5 border-b px-5 ".concat(b.T5),children:(0,n.jsxs)(a.default,{href:"/",className:"flex items-center gap-2.5 transition hover:opacity-80",children:[(0,n.jsx)(z.Z,{className:"h-5 w-5 shrink-0"}),(0,n.jsx)("span",{className:"text-sm font-bold tracking-[0.16em] text-white",children:"INTERMESH"})]})}),(0,n.jsx)("nav",{className:"space-y-6 px-3 py-5",children:q.map(e=>(0,n.jsxs)("div",{className:"space-y-1",children:[(0,n.jsx)("div",{className:"px-3 pb-1.5 ".concat(b.NE),children:e.label}),e.items.map(e=>{let t=e.icon,r=s===e.href;return(0,n.jsxs)(a.default,{href:e.href,className:"group relative flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition ".concat(r?"bg-cyan-500/[0.08] font-medium text-white":"text-slate-400 hover:bg-white/[0.04] hover:text-slate-100"),children:[r&&(0,n.jsx)("span",{className:"absolute inset-y-1.5 left-0 w-[2px] rounded-full bg-gradient-to-b from-cyan-400 to-violet-400"}),(0,n.jsx)(t,{className:"h-[17px] w-[17px] stroke-[1.6] transition ".concat(r?"text-cyan-300":"text-slate-400 group-hover:text-slate-300")}),(0,n.jsx)("span",{children:e.name})]},e.href)})]},e.label))})]}),(0,n.jsxs)("div",{className:"space-y-3 border-t px-5 py-4 ".concat(b.T5),children:[(0,n.jsxs)(a.default,{href:"/docs",className:"flex items-center gap-2 text-xs text-slate-400 transition hover:text-slate-100",children:[(0,n.jsx)(f,{className:"h-3.5 w-3.5 stroke-[1.6]"}),(0,n.jsx)("span",{children:"Docs — RFC-001"})]}),(0,n.jsx)(R,{})]})]}),(0,n.jsxs)("div",{className:"ml-[248px] flex min-h-screen flex-1 flex-col",children:[(0,n.jsx)(I,{}),(0,n.jsx)("main",{className:"w-full max-w-[1400px] flex-1 p-6 md:p-8",children:t})]})]})}},9057:function(e,t,s){"use strict";s.d(t,{Z:function(){return r}});var n=s(7437);function r(e){let{className:t="w-7 h-7"}=e;return(0,n.jsx)("img",{src:"/intermesh-logo.png",alt:"InterMesh",className:"object-contain ".concat(t)})}s(2265)},5128:function(e,t,s){"use strict";s.d(t,{Hr:function(){return i},_z:function(){return d},dE:function(){return r},l8:function(){return c},pP:function(){return l},qW:function(){return a},y2:function(){return o}});let n="intermesh.hub_url",r="ws://localhost:8765";function a(e){try{let t=new URL(e);return"ws:"===t.protocol||"wss:"===t.protocol}catch(e){return!1}}function i(e){if("https:"!==window.location.protocol)return!1;try{var t;let s=new URL(e);return"ws:"===s.protocol&&(t=s.hostname,!("localhost"===t||t.endsWith(".localhost"))&&"127.0.0.1"!==t&&"[::1]"!==t&&"::1"!==t)}catch(e){return!1}}function l(){try{let e=window.localStorage.getItem(n);if(e&&a(e))return e}catch(e){}return r}function o(e){let t=e.trim();if(!a(t))return!1;try{window.localStorage.setItem(n,t)}catch(e){return!1}return!0}function c(){try{window.localStorage.removeItem(n)}catch(e){}}function d(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:l();try{return new WebSocket(e)}catch(e){return null}}},8933:function(e,t,s){"use strict";s.d(t,{e:function(){return r},j:function(){return a}});var n=s(8113);function r(){let e="https://bqcuojhtmtueralmscje.supabase.co",t="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJxY3Vvamh0bXR1ZXJhbG1zY2plIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODgwMjQ1MjksImV4cCI6MjEwMzYwMDUyOX0.KpMVzOhJSGSntfyIrAbF2JTE8StZ8S_jN6I2CNfOCZo";if(!e||!t)throw Error("Supabase is not configured. Copy .env.example to .env.local and set NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY.");return(0,n.A)(e,t)}function a(){return!0}},9111:function(e,t,s){"use strict";s.d(t,{Fb:function(){return o},NE:function(){return h},T5:function(){return i},TU:function(){return l},_5:function(){return n},iX:function(){return r},ii:function(){return u},jF:function(){return a},kj:function(){return d},t7:function(){return c},zM:function(){return x}});let n="bg-[#0A0A0C]",r="bg-[#0C0C0F]",a="bg-[#0C0C0F]/80",i="border-white/[0.07]",l="rounded-xl border ".concat(i," ").concat("bg-[#111114]"),o="text-slate-100",c="text-slate-300",d="text-slate-400",h="text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-400",x="font-mono text-3xl font-semibold tabular-nums text-white",u={accent:{text:"text-cyan-300",soft:"bg-cyan-500/10 ring-1 ring-cyan-400/20",dot:"bg-cyan-400"},info:{text:"text-violet-300",soft:"bg-violet-500/10 ring-1 ring-violet-400/20",dot:"bg-violet-400"},positive:{text:"text-emerald-300",soft:"bg-emerald-500/10 ring-1 ring-emerald-400/20",dot:"bg-emerald-400"},warning:{text:"text-amber-300",soft:"bg-amber-500/10 ring-1 ring-amber-400/20",dot:"bg-amber-400"},danger:{text:"text-rose-300",soft:"bg-rose-500/10 ring-1 ring-rose-400/20",dot:"bg-rose-400"},neutral:{text:"text-slate-300",soft:"bg-white/[0.06] ring-1 ring-white/10",dot:"bg-slate-400"}}}},function(e){e.O(0,[762,451,283,971,117,744],function(){return e(e.s=152)}),_N_E=e.O()}]);
|
|
1
|
+
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[814],{152:function(e,t,s){Promise.resolve().then(s.bind(s,247))},401:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]])},4001:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Key",[["circle",{cx:"7.5",cy:"15.5",r:"5.5",key:"yqb3hr"}],["path",{d:"m21 2-9.6 9.6",key:"1j0ho8"}],["path",{d:"m15.5 7.5 3 3L22 7l-3-3",key:"1rn1fs"}]])},3420:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Network",[["rect",{x:"16",y:"16",width:"6",height:"6",rx:"1",key:"4q2zg0"}],["rect",{x:"2",y:"16",width:"6",height:"6",rx:"1",key:"8cvhb9"}],["rect",{x:"9",y:"2",width:"6",height:"6",rx:"1",key:"1egb70"}],["path",{d:"M5 16v-3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3",key:"1jsf9p"}],["path",{d:"M12 12V8",key:"2874zd"}]])},9076:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("RotateCcw",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}]])},3247:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Search",[["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}],["path",{d:"m21 21-4.3-4.3",key:"1qie3q"}]])},4286:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("ShieldCheck",[["path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10",key:"1irkt0"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]])},5805:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("Users",[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["path",{d:"M16 3.13a4 4 0 0 1 0 7.75",key:"1da9ce"}]])},2489:function(e,t,s){"use strict";s.d(t,{Z:function(){return n}});let n=(0,s(9763).Z)("X",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]])},247:function(e,t,s){"use strict";s.r(t),s.d(t,{default:function(){return H}});var n=s(7437),r=s(2265),a=s(7648),i=s(5475),l=s(9763);let o=(0,l.Z)("LayoutDashboard",[["rect",{width:"7",height:"9",x:"3",y:"3",rx:"1",key:"10lvy0"}],["rect",{width:"7",height:"5",x:"14",y:"3",rx:"1",key:"16une8"}],["rect",{width:"7",height:"9",x:"14",y:"12",rx:"1",key:"1hutg5"}],["rect",{width:"7",height:"5",x:"3",y:"16",rx:"1",key:"ldoo1y"}]]);var c=s(3420),d=s(5805);let h=(0,l.Z)("FileText",[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z",key:"1rqfz7"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M10 9H8",key:"b1mrlr"}],["path",{d:"M16 13H8",key:"t4e002"}],["path",{d:"M16 17H8",key:"z1uh3a"}]]);var x=s(4001),u=s(4286);let m=(0,l.Z)("CreditCard",[["rect",{width:"20",height:"14",x:"2",y:"5",rx:"2",key:"ynyp8z"}],["line",{x1:"2",x2:"22",y1:"10",y2:"10",key:"1b3vmo"}]]),p=(0,l.Z)("Settings",[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z",key:"1qme2f"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),f=(0,l.Z)("BookOpen",[["path",{d:"M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z",key:"vv98re"}],["path",{d:"M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z",key:"1cyq3y"}]]);var b=s(9111),g=s(8933),w=s(3247);let y=(0,l.Z)("HelpCircle",[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3",key:"1u773s"}],["path",{d:"M12 17h.01",key:"p32p05"}]]),v=(0,l.Z)("ExternalLink",[["path",{d:"M15 3h6v6",key:"1q9fwt"}],["path",{d:"M10 14 21 3",key:"gplh6r"}],["path",{d:"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",key:"a6xqqp"}]]),j=(0,l.Z)("Bell",[["path",{d:"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9",key:"1qo2s2"}],["path",{d:"M10.3 21a1.94 1.94 0 0 0 3.4 0",key:"qgo35s"}]]),k=(0,l.Z)("User",[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]]),N=(0,l.Z)("LogOut",[["path",{d:"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4",key:"1uf3rs"}],["polyline",{points:"16 17 21 12 16 7",key:"1gabdz"}],["line",{x1:"21",x2:"9",y1:"12",y2:"12",key:"1uyos4"}]]);var C=s(2489),Z=s(401);let M=[{id:"overview",label:"Overview & Quotas",description:"Main dashboard and agent limits",href:"/dashboard",icon:o,group:"Navigation"},{id:"agents",label:"Agents Directory",description:"List of connected agents",href:"/agents",icon:d.Z,group:"Navigation"},{id:"keys",label:"API Keys & Licenses",description:"Manage keys and licenses",href:"/keys",icon:x.Z,group:"Navigation"},{id:"security",label:"Audit Log & RBAC",description:"Audit log and permissions",href:"/security",icon:u.Z,group:"Navigation"},{id:"billing",label:"Billing & Plans",description:"Subscription and pricing",href:"/billing",icon:m,group:"Navigation"},{id:"settings",label:"Workspace Settings",description:"Organization settings, members and webhooks",href:"/settings",icon:p,group:"Navigation"},{id:"docs",label:"RFC-001 Documentation",description:"InterMesh protocol specification",href:"/docs",icon:h,group:"Resources"}],S=[],E={"/dashboard":"Overview","/topology":"Topology","/agents":"Agents","/keys":"API keys","/security":"Audit log","/billing":"Billing","/settings":"Settings"};function I(){var e;let t=(0,i.useRouter)(),l=null!==(e=E[(0,i.usePathname)()])&&void 0!==e?e:"Overview",[o,c]=(0,r.useState)(!1),[d,x]=(0,r.useState)(""),[u,m]=(0,r.useState)(!1),[f,I]=(0,r.useState)(!1),[z,L]=(0,r.useState)(!1),[A,T]=(0,r.useState)(S),[R,q]=(0,r.useState)(0),O=(0,r.useRef)(null),H=(0,r.useRef)(null),_=(0,r.useRef)(null),P=(0,r.useRef)(null),F=A.filter(e=>e.unread).length,D=async()=>{if(L(!1),(0,g.j)()){let{signOut:e}=await s.e(67).then(s.bind(s,3067));await e()}t.push("/auth")},U=M.filter(e=>{let t=d.toLowerCase().trim();return!t||e.label.toLowerCase().includes(t)||e.description.toLowerCase().includes(t)||e.group.toLowerCase().includes(t)}),B=U.reduce((e,t)=>(e[t.group]||(e[t.group]=[]),e[t.group].push(t),e),{});(0,r.useEffect)(()=>{let e=e=>{(e.metaKey||e.ctrlKey)&&"k"===e.key.toLowerCase()&&(e.preventDefault(),c(!0),m(!1),I(!1),L(!1)),"Escape"===e.key&&(c(!1),m(!1),I(!1),L(!1))};return window.addEventListener("keydown",e),()=>window.removeEventListener("keydown",e)},[]),(0,r.useEffect)(()=>{o?(setTimeout(()=>{var e;return null===(e=O.current)||void 0===e?void 0:e.focus()},50),q(0)):x("")},[o]),(0,r.useEffect)(()=>{let e=e=>{let t=e.target;H.current&&!H.current.contains(t)&&m(!1),_.current&&!_.current.contains(t)&&I(!1),P.current&&!P.current.contains(t)&&L(!1)};return document.addEventListener("mousedown",e),()=>document.removeEventListener("mousedown",e)},[]);let J=e=>{c(!1),x(""),t.push(e)};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsxs)("header",{className:"sticky top-0 z-20 flex h-14 items-center justify-between border-b px-6 backdrop-blur-xl md:px-8 ".concat(b.T5," ").concat(b.jF),children:[(0,n.jsxs)("div",{className:"flex items-center gap-2 text-sm",children:[(0,n.jsx)("span",{className:"text-slate-400",children:"Control plane"}),(0,n.jsx)("span",{className:"text-slate-500",children:"/"}),(0,n.jsx)("span",{className:"font-medium text-white",children:l})]}),(0,n.jsxs)("div",{className:"flex items-center space-x-3 md:space-x-4",children:[(0,n.jsxs)("button",{onClick:()=>c(!0),className:"hidden md:flex items-center bg-[#141519] border border-white/10 rounded-md px-3 py-1.5 text-xs text-slate-400 w-64 hover:border-white/20 transition text-left",children:[(0,n.jsx)(w.Z,{className:"w-3.5 h-3.5 mr-2 text-slate-400"}),(0,n.jsx)("span",{className:"flex-1 text-slate-400",children:"Search agents, keys..."}),(0,n.jsx)("span",{className:"text-[10px] font-mono border border-white/20 rounded px-1 text-slate-400",children:"⌘K"})]}),(0,n.jsx)("button",{onClick:()=>c(!0),className:"md:hidden text-slate-400 hover:text-white transition p-1",children:(0,n.jsx)(w.Z,{className:"w-4 h-4"})}),(0,n.jsxs)("div",{className:"relative",ref:_,children:[(0,n.jsx)("button",{onClick:()=>I(e=>!e),className:"text-slate-400 hover:text-white transition p-1 rounded ".concat(f?"text-white bg-white/5":""),children:(0,n.jsx)(y,{className:"w-4 h-4"})}),f&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-64 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsx)("div",{className:"px-4 py-3 border-b border-white/10",children:(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Help & Resources"})}),(0,n.jsxs)("div",{className:"p-2 space-y-0.5",children:[(0,n.jsxs)(a.default,{href:"/docs",onClick:()=>I(!1),className:"flex items-center justify-between px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsxs)("span",{className:"flex items-center space-x-2",children:[(0,n.jsx)(h,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"RFC-001 Spec"})]}),(0,n.jsx)(v,{className:"w-3 h-3 text-slate-400"})]}),(0,n.jsx)("a",{href:"https://github.com/intermeshteam/intermesh",target:"_blank",className:"flex items-center justify-between px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:(0,n.jsxs)("span",{className:"flex items-center space-x-2",children:[(0,n.jsx)(v,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"GitHub Repository"})]})})]})]})]}),(0,n.jsxs)("div",{className:"relative",ref:H,children:[(0,n.jsxs)("button",{onClick:()=>m(e=>!e),className:"relative text-slate-400 hover:text-white transition p-1 rounded ".concat(u?"text-white bg-white/5":""),children:[(0,n.jsx)(j,{className:"w-4 h-4"}),F>0&&(0,n.jsx)("span",{className:"absolute -top-0.5 -right-0.5 w-4 h-4 rounded-full bg-red-500 text-[9px] font-bold text-white flex items-center justify-center",children:F})]}),u&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-80 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsxs)("div",{className:"px-4 py-3 border-b border-white/10 flex items-center justify-between",children:[(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Notifications"}),F>0&&(0,n.jsx)("button",{onClick:()=>{T(e=>e.map(e=>({...e,unread:!1})))},className:"text-[11px] text-slate-400 hover:text-white transition",children:"Tout marquer lu"})]}),(0,n.jsx)("div",{className:"max-h-80 overflow-y-auto",children:A.map(e=>(0,n.jsxs)("div",{className:"p-3 border-b border-white/5 hover:bg-white/[0.02]",children:[(0,n.jsx)("div",{className:"text-xs font-semibold text-white",children:e.title}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 mt-0.5",children:e.body})]},e.id))})]})]}),(0,n.jsxs)("div",{className:"relative",ref:P,children:[(0,n.jsx)("button",{onClick:()=>L(e=>!e),className:"w-7 h-7 rounded-full bg-white/10 border border-white/20 text-white font-mono font-bold text-xs flex items-center justify-center hover:bg-white/15 transition",children:"AC"}),z&&(0,n.jsxs)("div",{className:"absolute right-0 mt-2 w-64 bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50",children:[(0,n.jsxs)("div",{className:"px-4 py-3 border-b border-white/10",children:[(0,n.jsx)("div",{className:"text-sm font-semibold text-white",children:"Local workspace"}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 font-mono mt-0.5",children:"self-hosted"})]}),(0,n.jsxs)("div",{className:"p-2 space-y-0.5",children:[(0,n.jsxs)(a.default,{href:"/dashboard",onClick:()=>L(!1),className:"flex items-center space-x-2 px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsx)(k,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Account Overview"})]}),(0,n.jsxs)(a.default,{href:"/settings",onClick:()=>L(!1),className:"flex items-center space-x-2 px-3 py-2 rounded-lg text-xs text-slate-300 hover:bg-white/5 hover:text-white transition",children:[(0,n.jsx)(p,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Workspace Settings"})]})]}),(0,n.jsx)("div",{className:"p-2 border-t border-white/10",children:(0,n.jsxs)("button",{onClick:D,className:"flex w-full items-center space-x-2 px-3 py-2 rounded-lg text-xs text-red-400 hover:bg-red-500/10 transition",children:[(0,n.jsx)(N,{className:"w-3.5 h-3.5"}),(0,n.jsx)("span",{children:"Log out"})]})})]})]})]})]}),o&&(0,n.jsxs)("div",{className:"fixed inset-0 z-[100] flex items-start justify-center pt-[12vh] px-4",children:[(0,n.jsx)("div",{className:"absolute inset-0 bg-black/70 backdrop-blur-sm",onClick:()=>c(!1)}),(0,n.jsxs)("div",{className:"relative w-full max-w-xl bg-[#111114] border border-white/10 rounded-xl shadow-2xl overflow-hidden",children:[(0,n.jsxs)("div",{className:"flex items-center px-4 border-b border-white/10",children:[(0,n.jsx)(w.Z,{className:"w-4 h-4 text-slate-400 mr-3"}),(0,n.jsx)("input",{ref:O,value:d,onChange:e=>{x(e.target.value),q(0)},onKeyDown:e=>{"ArrowDown"===e.key?(e.preventDefault(),q(e=>Math.min(e+1,Math.max(U.length-1,0)))):"ArrowUp"===e.key?(e.preventDefault(),q(e=>Math.max(e-1,0))):"Enter"===e.key&&U[R]&&(e.preventDefault(),J(U[R].href))},placeholder:"Search agents, keys, settings...",className:"flex-1 bg-transparent py-3.5 text-sm text-white outline-none placeholder:text-slate-400"}),(0,n.jsx)("button",{onClick:()=>c(!1),className:"text-slate-400 hover:text-white p-1",children:(0,n.jsx)(C.Z,{className:"w-4 h-4"})})]}),(0,n.jsx)("div",{className:"max-h-80 overflow-y-auto p-2",children:0===U.length?(0,n.jsxs)("div",{className:"px-3 py-8 text-center text-xs text-slate-400",children:["No results for “",d,"”"]}):Object.entries(B).map(e=>{let[t,s]=e;return(0,n.jsxs)("div",{className:"mb-2",children:[(0,n.jsx)("div",{className:"px-3 py-1.5 text-[10px] font-mono uppercase tracking-wider text-slate-400",children:t}),s.map(e=>{let t=U.findIndex(t=>t.id===e.id),s=e.icon,r=t===R;return(0,n.jsxs)("button",{onClick:()=>J(e.href),onMouseEnter:()=>q(t),className:"w-full flex items-center space-x-3 px-3 py-2.5 rounded-lg text-left transition ".concat(r?"bg-white/10 text-white":"text-slate-300 hover:bg-white/5"),children:[(0,n.jsx)(s,{className:"w-4 h-4 shrink-0 ".concat(r?"text-white":"text-slate-400")}),(0,n.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,n.jsx)("div",{className:"text-xs font-medium truncate",children:e.label}),(0,n.jsx)("div",{className:"text-[11px] text-slate-400 truncate",children:e.description})]}),r&&(0,n.jsx)(Z.Z,{className:"w-3.5 h-3.5 text-slate-400 shrink-0"})]},e.id)})]},t)})})]})]})]})}var z=s(2615),L=s(9057),A=s(9076);let T=(0,l.Z)("Pencil",[["path",{d:"M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z",key:"5qss01"}],["path",{d:"m15 5 4 4",key:"1mk7zo"}]]);var R=s(5128);function q(){let[e,t]=(0,r.useState)(R.dE),[s,a]=(0,r.useState)("checking"),[i,l]=(0,r.useState)(!1),[o,c]=(0,r.useState)(""),[d,h]=(0,r.useState)(!1),x=(0,r.useRef)(null),u=(0,r.useCallback)(e=>{var t;if(null===(t=x.current)||void 0===t||t.close(),(0,R.Hr)(e)){a("blocked");return}a("checking");let s=!1,n=e=>{s||(s=!0,a(e))};try{let t=new WebSocket(e);x.current=t;let s=setTimeout(()=>{n("offline"),t.close()},4e3);t.onopen=()=>{clearTimeout(s),n("online"),t.close()},t.onerror=()=>{clearTimeout(s),n("offline")},t.onclose=()=>{clearTimeout(s),n("offline")}}catch(e){n("offline")}},[]);(0,r.useEffect)(()=>{let e=(0,R.pP)();return t(e),u(e),()=>{var e;return null===(e=x.current)||void 0===e?void 0:e.close()}},[u]);let m=()=>{let e=o.trim();if(!(0,R.qW)(e)){h(!0);return}(0,R.y2)(e),t(e),l(!1),u(e)};return i?(0,n.jsxs)("div",{className:"space-y-2",children:[(0,n.jsx)("label",{className:"text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-500",children:"Hub address"}),(0,n.jsx)("input",{value:o,autoFocus:!0,onChange:e=>{c(e.target.value),h(!1)},onKeyDown:e=>{"Enter"===e.key&&m(),"Escape"===e.key&&l(!1)},placeholder:"ws://localhost:8765",className:"w-full rounded border bg-white/[0.04] px-2 py-1.5 font-mono text-[11px] text-slate-100 outline-none focus:border-cyan-500/50 ".concat(d?"border-red-500/50":"border-white/[0.1]")}),d&&(0,n.jsx)("p",{className:"text-[10px] text-red-400",children:"Must start with ws:// or wss://"}),(0,n.jsxs)("div",{className:"flex items-center gap-1.5",children:[(0,n.jsxs)("button",{onClick:m,className:"inline-flex items-center gap-1 rounded bg-white/10 px-2 py-1 text-[10px] font-medium text-slate-100 transition hover:bg-white/[0.16]",children:[(0,n.jsx)(Z.Z,{className:"h-3 w-3"})," Save"]}),(0,n.jsxs)("button",{onClick:()=>l(!1),className:"inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] text-slate-400 transition hover:text-slate-100",children:[(0,n.jsx)(C.Z,{className:"h-3 w-3"})," Cancel"]}),(0,n.jsx)("button",{onClick:()=>{(0,R.l8)(),t(R.dE),l(!1),u(R.dE)},title:"Reset to ".concat(R.dE),className:"ml-auto inline-flex items-center gap-1 rounded px-2 py-1 text-[10px] text-slate-500 transition hover:text-slate-300",children:(0,n.jsx)(A.Z,{className:"h-3 w-3"})})]})]}):(0,n.jsxs)("div",{className:"space-y-1.5",children:[(0,n.jsxs)("div",{className:"flex items-center gap-2",children:[(0,n.jsx)("span",{className:"text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-500",children:"Hub"}),(0,n.jsx)("span",{className:"h-1.5 w-1.5 shrink-0 rounded-full ".concat("online"===s?"bg-emerald-400":"offline"===s?"bg-red-400":"blocked"===s?"bg-amber-400":"bg-slate-500 animate-pulse"),"aria-hidden":!0}),(0,n.jsx)("span",{className:"text-[10px] text-slate-400",children:"online"===s?"Connected":"offline"===s?"Not reachable":"blocked"===s?"Blocked by the browser":"Checking…"}),(0,n.jsx)("button",{onClick:()=>{c(e),h(!1),l(!0)},title:"Change hub address",className:"ml-auto text-slate-500 transition hover:text-slate-200","aria-label":"Change hub address",children:(0,n.jsx)(T,{className:"h-3 w-3"})})]}),(0,n.jsx)("div",{className:"truncate font-mono text-[11px] text-slate-400",title:e,children:e.replace(/^wss?:\/\//,"")}),"offline"===s&&(0,n.jsxs)("p",{className:"text-[10px] leading-relaxed text-slate-500",children:["Start one with"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono text-slate-300",children:"intermesh hub"}),", then refresh."]}),"blocked"===s&&(0,n.jsxs)("p",{className:"text-[10px] leading-relaxed text-amber-400/80",children:["This page is served over HTTPS, so it cannot open a plain"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"ws://"})," socket to another machine — the browser refuses before connecting. A remote hub has to serve"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"wss://"})," (",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"--tls-cert"})," /"," ",(0,n.jsx)("code",{className:"rounded bg-white/[0.06] px-1 py-0.5 font-mono",children:"--tls-key"}),"). Only localhost is exempt."]})]})}let O=[{label:"Control plane",items:[{name:"Overview",href:"/dashboard",icon:o},{name:"Topology",href:"/topology",icon:c.Z},{name:"Agents",href:"/agents",icon:d.Z},{name:"Summaries",href:"/resumes",icon:h},{name:"API keys",href:"/keys",icon:x.Z},{name:"Audit log",href:"/security",icon:u.Z},{name:"Billing",href:"/billing",icon:m}]},{label:"Workspace",items:[{name:"Settings",href:"/settings",icon:p}]}];function H(e){let{children:t}=e,s=(0,i.usePathname)();return(0,n.jsxs)("div",{className:"dark flex min-h-screen font-sans text-slate-100 ".concat(b._5),children:[(0,n.jsxs)("aside",{className:"fixed bottom-0 left-0 top-0 z-30 flex w-[248px] shrink-0 flex-col justify-between border-r ".concat(b.T5," ").concat(b.iX),children:[(0,n.jsxs)("div",{children:[(0,n.jsx)("div",{className:"flex h-14 items-center gap-2.5 border-b px-5 ".concat(b.T5),children:(0,n.jsxs)(a.default,{href:"/",className:"flex items-center gap-2.5 transition hover:opacity-80",children:[(0,n.jsx)(L.Z,{className:"h-5 w-5 shrink-0"}),(0,n.jsx)(z.Z,{className:"text-sm font-bold tracking-[0.16em] text-white"})]})}),(0,n.jsx)("nav",{className:"space-y-6 px-3 py-5",children:O.map(e=>(0,n.jsxs)("div",{className:"space-y-1",children:[(0,n.jsx)("div",{className:"px-3 pb-1.5 ".concat(b.NE),children:e.label}),e.items.map(e=>{let t=e.icon,r=s===e.href;return(0,n.jsxs)(a.default,{href:e.href,className:"group relative flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition ".concat(r?"bg-cyan-500/[0.08] font-medium text-white":"text-slate-400 hover:bg-white/[0.04] hover:text-slate-100"),children:[r&&(0,n.jsx)("span",{className:"absolute inset-y-1.5 left-0 w-[2px] rounded-full bg-gradient-to-b from-cyan-400 to-violet-400"}),(0,n.jsx)(t,{className:"h-[17px] w-[17px] stroke-[1.6] transition ".concat(r?"text-cyan-300":"text-slate-400 group-hover:text-slate-300")}),(0,n.jsx)("span",{children:e.name})]},e.href)})]},e.label))})]}),(0,n.jsxs)("div",{className:"space-y-3 border-t px-5 py-4 ".concat(b.T5),children:[(0,n.jsxs)(a.default,{href:"/docs",className:"flex items-center gap-2 text-xs text-slate-400 transition hover:text-slate-100",children:[(0,n.jsx)(f,{className:"h-3.5 w-3.5 stroke-[1.6]"}),(0,n.jsx)("span",{children:"Docs — RFC-001"})]}),(0,n.jsx)(q,{})]})]}),(0,n.jsxs)("div",{className:"ml-[248px] flex min-h-screen flex-1 flex-col",children:[(0,n.jsx)(I,{}),(0,n.jsx)("main",{className:"w-full max-w-[1400px] flex-1 p-6 md:p-8",children:t})]})]})}},2615:function(e,t,s){"use strict";s.d(t,{Z:function(){return r}});var n=s(7437);function r(e){let{className:t="",as:s="span"}=e;return(0,n.jsx)(s,{className:"notranslate ".concat(t),translate:"no",children:"INTERMESH"})}s(2265)},9057:function(e,t,s){"use strict";s.d(t,{Z:function(){return r}});var n=s(7437);function r(e){let{className:t="w-7 h-7"}=e;return(0,n.jsx)("img",{src:"/intermesh-logo.png",alt:"InterMesh",className:"object-contain ".concat(t)})}s(2265)},5128:function(e,t,s){"use strict";s.d(t,{Hr:function(){return i},_z:function(){return d},dE:function(){return r},l8:function(){return c},pP:function(){return l},qW:function(){return a},y2:function(){return o}});let n="intermesh.hub_url",r="ws://localhost:8765";function a(e){try{let t=new URL(e);return"ws:"===t.protocol||"wss:"===t.protocol}catch(e){return!1}}function i(e){if("https:"!==window.location.protocol)return!1;try{var t;let s=new URL(e);return"ws:"===s.protocol&&(t=s.hostname,!("localhost"===t||t.endsWith(".localhost"))&&"127.0.0.1"!==t&&"[::1]"!==t&&"::1"!==t)}catch(e){return!1}}function l(){try{let e=window.localStorage.getItem(n);if(e&&a(e))return e}catch(e){}return r}function o(e){let t=e.trim();if(!a(t))return!1;try{window.localStorage.setItem(n,t)}catch(e){return!1}return!0}function c(){try{window.localStorage.removeItem(n)}catch(e){}}function d(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:l();try{return new WebSocket(e)}catch(e){return null}}},8933:function(e,t,s){"use strict";s.d(t,{e:function(){return r},j:function(){return a}});var n=s(8113);function r(){let e="https://bqcuojhtmtueralmscje.supabase.co",t="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImJxY3Vvamh0bXR1ZXJhbG1zY2plIiwicm9sZSI6ImFub24iLCJpYXQiOjE3ODgwMjQ1MjksImV4cCI6MjEwMzYwMDUyOX0.KpMVzOhJSGSntfyIrAbF2JTE8StZ8S_jN6I2CNfOCZo";if(!e||!t)throw Error("Supabase is not configured. Copy .env.example to .env.local and set NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY.");return(0,n.A)(e,t)}function a(){return!0}},9111:function(e,t,s){"use strict";s.d(t,{Fb:function(){return o},NE:function(){return h},T5:function(){return i},TU:function(){return l},_5:function(){return n},iX:function(){return r},ii:function(){return u},jF:function(){return a},kj:function(){return d},t7:function(){return c},zM:function(){return x}});let n="bg-[#0A0A0C]",r="bg-[#0C0C0F]",a="bg-[#0C0C0F]/80",i="border-white/[0.07]",l="rounded-xl border ".concat(i," ").concat("bg-[#111114]"),o="text-slate-100",c="text-slate-300",d="text-slate-400",h="text-[10px] font-semibold uppercase tracking-[0.14em] text-slate-400",x="font-mono text-3xl font-semibold tabular-nums text-white",u={accent:{text:"text-cyan-300",soft:"bg-cyan-500/10 ring-1 ring-cyan-400/20",dot:"bg-cyan-400"},info:{text:"text-violet-300",soft:"bg-violet-500/10 ring-1 ring-violet-400/20",dot:"bg-violet-400"},positive:{text:"text-emerald-300",soft:"bg-emerald-500/10 ring-1 ring-emerald-400/20",dot:"bg-emerald-400"},warning:{text:"text-amber-300",soft:"bg-amber-500/10 ring-1 ring-amber-400/20",dot:"bg-amber-400"},danger:{text:"text-rose-300",soft:"bg-rose-500/10 ring-1 ring-rose-400/20",dot:"bg-rose-400"},neutral:{text:"text-slate-300",soft:"bg-white/[0.06] ring-1 ring-white/10",dot:"bg-slate-400"}}}},function(e){e.O(0,[762,451,283,971,117,744],function(){return e(e.s=152)}),_N_E=e.O()}]);
|