kather-relay 0.1.0 → 0.2.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.
- package/README.md +5 -3
- package/dist/kather-relay.mjs +362 -62
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,11 +5,13 @@ Le Relais de [Kather](https://kather.katalyx.fr) : il fait apparaître les Agent
|
|
|
5
5
|
Node 22.12 ou plus.
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
|
-
npx kather-relay connect https://kather.katalyx.fr # code à confirmer dans Kather, puis consentement T3 Code (Full access)
|
|
9
|
-
npx kather-relay install-service # service utilisateur (systemd --user, launchd)
|
|
10
|
-
npx kather-relay status # appairage, T3 Code, service
|
|
8
|
+
npx kather-relay@latest connect https://kather.katalyx.fr # code à confirmer dans Kather, puis consentement T3 Code (Full access)
|
|
9
|
+
npx kather-relay@latest install-service # service utilisateur (systemd --user, launchd)
|
|
10
|
+
npx kather-relay@latest status # appairage, T3 Code, service
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Le plus simple : dans Kather, copie le prompt d'installation du Relais et colle-le dans ton T3 Code.
|
|
14
14
|
|
|
15
|
+
Kather refuse un Relais trop ancien (bandeau « Mets à jour ton Relais ») : relance `npx kather-relay@latest install-service`, qui remplace la copie du service.
|
|
16
|
+
|
|
15
17
|
Autres commandes : `kather-relay login` (reconnecter T3 Code), `kather-relay run` (au premier plan), `kather-relay uninstall-service`. Option `--redirect-host localhost` si T3 Code refuse la redirection vers `127.0.0.1`.
|
package/dist/kather-relay.mjs
CHANGED
|
@@ -3776,6 +3776,22 @@ import { hostname as hostname3 } from "node:os";
|
|
|
3776
3776
|
import { dirname, join as join3, resolve } from "node:path";
|
|
3777
3777
|
import { pathToFileURL } from "node:url";
|
|
3778
3778
|
|
|
3779
|
+
// ../../packages/shared/src/geometry.ts
|
|
3780
|
+
function rectangle(minX, minZ, maxX, maxZ) {
|
|
3781
|
+
return [
|
|
3782
|
+
{ x: minX, z: minZ },
|
|
3783
|
+
{ x: maxX, z: minZ },
|
|
3784
|
+
{ x: maxX, z: maxZ },
|
|
3785
|
+
{ x: minX, z: maxZ }
|
|
3786
|
+
];
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3789
|
+
// ../../packages/shared/src/ranges.ts
|
|
3790
|
+
var NAME_TAG_RANGE = 6;
|
|
3791
|
+
|
|
3792
|
+
// ../../packages/shared/src/agent-scene.ts
|
|
3793
|
+
var AGENT_PILL_RANGE = NAME_TAG_RANGE * 2;
|
|
3794
|
+
|
|
3779
3795
|
// ../../node_modules/.pnpm/zod@4.6.7/node_modules/zod/v4/classic/external.js
|
|
3780
3796
|
var external_exports = {};
|
|
3781
3797
|
__export(external_exports, {
|
|
@@ -23512,6 +23528,24 @@ function katherStatusOf(t3Status, pendingRequestCount = 0) {
|
|
|
23512
23528
|
if (pendingRequestCount > 0) return "waiting";
|
|
23513
23529
|
return BY_T3_STATUS[t3Status] ?? "available";
|
|
23514
23530
|
}
|
|
23531
|
+
var short = external_exports.string().max(2e3);
|
|
23532
|
+
var pendingRequestSchema = external_exports.object({
|
|
23533
|
+
requestId: external_exports.string().min(1).max(512),
|
|
23534
|
+
questions: external_exports.array(
|
|
23535
|
+
external_exports.object({
|
|
23536
|
+
id: external_exports.string().min(1).max(512),
|
|
23537
|
+
header: short.nullable(),
|
|
23538
|
+
question: short,
|
|
23539
|
+
options: external_exports.array(external_exports.object({ label: short, value: short.optional(), description: short.optional() })).max(20),
|
|
23540
|
+
multiSelect: external_exports.boolean()
|
|
23541
|
+
})
|
|
23542
|
+
).max(10)
|
|
23543
|
+
});
|
|
23544
|
+
var agentRequestSchema = external_exports.discriminatedUnion("kind", [
|
|
23545
|
+
external_exports.object({ kind: external_exports.literal("question"), request: pendingRequestSchema }),
|
|
23546
|
+
external_exports.object({ kind: external_exports.literal("approval") })
|
|
23547
|
+
]);
|
|
23548
|
+
var agentPlaceSchema = external_exports.enum(["desk", "raised", "coming", "near", "returning"]);
|
|
23515
23549
|
var agentViewSchema = external_exports.object({
|
|
23516
23550
|
/** Identité stable : `environmentId` T3 + `threadId`. */
|
|
23517
23551
|
id: external_exports.string(),
|
|
@@ -23524,11 +23558,19 @@ var agentViewSchema = external_exports.object({
|
|
|
23524
23558
|
title: external_exports.string(),
|
|
23525
23559
|
project: external_exports.string().nullable(),
|
|
23526
23560
|
status: agentStatusSchema,
|
|
23527
|
-
|
|
23561
|
+
/**
|
|
23562
|
+
* Ce que l'Agent attend, en Attend ; `null` sinon, et pour qui ne peut pas lire le fil (un
|
|
23563
|
+
* Invité, un autre Membre face à un Agent privé).
|
|
23564
|
+
*/
|
|
23565
|
+
request: agentRequestSchema.nullable(),
|
|
23566
|
+
/** La marque À relire (glossaire), tenue par le serveur : visible de tous, Invités compris. */
|
|
23567
|
+
toReview: external_exports.boolean(),
|
|
23528
23568
|
subagents: external_exports.object({ active: external_exports.number().int(), total: external_exports.number().int() }),
|
|
23529
23569
|
/** La rangée du Propriétaire et le Poste dans la rangée ; `null` : « sans Poste ». */
|
|
23530
23570
|
rowIndex: external_exports.number().int().nullable(),
|
|
23531
23571
|
deskIndex: external_exports.number().int().nullable(),
|
|
23572
|
+
/** Où il en est dans la scène : à son Poste, en route, près de son Propriétaire… */
|
|
23573
|
+
place: agentPlaceSchema,
|
|
23532
23574
|
/** Hors ligne depuis cet instant (ms depuis l'époque), ou `null` si le Relais répond. */
|
|
23533
23575
|
offlineSince: external_exports.number().nullable(),
|
|
23534
23576
|
/** Réglé par le Propriétaire (US 71) : les autres ne voient que Statut, titre et Propriétaire. */
|
|
@@ -23542,6 +23584,12 @@ var agentRowOwnerSchema = external_exports.object({
|
|
|
23542
23584
|
name: external_exports.string(),
|
|
23543
23585
|
outfit: external_exports.string()
|
|
23544
23586
|
});
|
|
23587
|
+
var agentPoseSchema = external_exports.object({
|
|
23588
|
+
id: external_exports.string(),
|
|
23589
|
+
x: external_exports.number(),
|
|
23590
|
+
z: external_exports.number(),
|
|
23591
|
+
heading: external_exports.number()
|
|
23592
|
+
});
|
|
23545
23593
|
var agentsMessageSchema = external_exports.discriminatedUnion("event", [
|
|
23546
23594
|
external_exports.object({
|
|
23547
23595
|
type: external_exports.literal("agents"),
|
|
@@ -23559,19 +23607,6 @@ var agentsMessageSchema = external_exports.discriminatedUnion("event", [
|
|
|
23559
23607
|
})
|
|
23560
23608
|
]);
|
|
23561
23609
|
var agentAlertSchema = external_exports.enum(["waiting", "done"]);
|
|
23562
|
-
var short = external_exports.string().max(2e3);
|
|
23563
|
-
var pendingRequestSchema = external_exports.object({
|
|
23564
|
-
requestId: external_exports.string().min(1).max(512),
|
|
23565
|
-
questions: external_exports.array(
|
|
23566
|
-
external_exports.object({
|
|
23567
|
-
id: external_exports.string().min(1).max(512),
|
|
23568
|
-
header: short.nullable(),
|
|
23569
|
-
question: short,
|
|
23570
|
-
options: external_exports.array(external_exports.object({ label: short, value: short.optional(), description: short.optional() })).max(20),
|
|
23571
|
-
multiSelect: external_exports.boolean()
|
|
23572
|
-
})
|
|
23573
|
-
).max(10)
|
|
23574
|
-
});
|
|
23575
23610
|
var looseRequestSchema = external_exports.looseObject({
|
|
23576
23611
|
requestId: external_exports.string().min(1).max(512),
|
|
23577
23612
|
questions: external_exports.array(
|
|
@@ -23590,15 +23625,23 @@ var looseRequestSchema = external_exports.looseObject({
|
|
|
23590
23625
|
})
|
|
23591
23626
|
).max(10)
|
|
23592
23627
|
});
|
|
23593
|
-
|
|
23594
|
-
|
|
23595
|
-
|
|
23596
|
-
return
|
|
23597
|
-
|
|
23598
|
-
|
|
23599
|
-
|
|
23600
|
-
|
|
23601
|
-
|
|
23628
|
+
function pendingRequestsFrom(result) {
|
|
23629
|
+
const parsed = external_exports.looseObject({ requests: external_exports.array(looseRequestSchema).max(20) }).safeParse(result);
|
|
23630
|
+
if (!parsed.success) return null;
|
|
23631
|
+
return parsed.data.requests.map((r) => ({
|
|
23632
|
+
requestId: r.requestId,
|
|
23633
|
+
questions: r.questions.map((q) => ({
|
|
23634
|
+
id: q.id,
|
|
23635
|
+
header: q.header ?? null,
|
|
23636
|
+
question: q.question ?? "",
|
|
23637
|
+
options: (q.options ?? []).map((o) => ({
|
|
23638
|
+
label: o.label,
|
|
23639
|
+
...o.value != null ? { value: String(o.value) } : {},
|
|
23640
|
+
...o.description ? { description: o.description } : {}
|
|
23641
|
+
})),
|
|
23642
|
+
multiSelect: q.multiSelect ?? false
|
|
23643
|
+
}))
|
|
23644
|
+
}));
|
|
23602
23645
|
}
|
|
23603
23646
|
|
|
23604
23647
|
// ../../packages/shared/src/appearance.ts
|
|
@@ -23815,7 +23858,7 @@ var parisParts = new Intl.DateTimeFormat("en-GB", {
|
|
|
23815
23858
|
});
|
|
23816
23859
|
|
|
23817
23860
|
// ../../packages/shared/src/relay-protocol.ts
|
|
23818
|
-
var RELAY_PROTOCOL_VERSION =
|
|
23861
|
+
var RELAY_PROTOCOL_VERSION = 3;
|
|
23819
23862
|
var RELAY_HEARTBEAT_MS = 3e4;
|
|
23820
23863
|
var id = external_exports.string().min(1).max(512);
|
|
23821
23864
|
var name = external_exports.string().max(500);
|
|
@@ -23829,8 +23872,12 @@ var relayAgentSchema = external_exports.object({
|
|
|
23829
23872
|
projectId: id.nullable(),
|
|
23830
23873
|
projectName: name.nullable(),
|
|
23831
23874
|
status: agentStatusSchema,
|
|
23832
|
-
/**
|
|
23833
|
-
|
|
23875
|
+
/**
|
|
23876
|
+
* Le résumé de ce que l'Agent attend, en Attend : la première demande listée par
|
|
23877
|
+
* `t3_pending_request` (question et options), ou `approval` quand T3 Code compte une demande
|
|
23878
|
+
* sans en lister aucune. `null` hors Attend, ou tant que la demande n'a pas pu être lue.
|
|
23879
|
+
*/
|
|
23880
|
+
request: agentRequestSchema.nullable(),
|
|
23834
23881
|
subagents: subagentCountSchema,
|
|
23835
23882
|
/** Le lien du thread dans T3 Code (`t3-thread://…`), pour l'y ouvrir. */
|
|
23836
23883
|
link: external_exports.string().max(2e3).nullable()
|
|
@@ -23880,6 +23927,11 @@ var relayMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
23880
23927
|
hasMore: external_exports.boolean()
|
|
23881
23928
|
}),
|
|
23882
23929
|
external_exports.object({ type: external_exports.literal("t3.auth"), ...t3AuthSchema.shape }),
|
|
23930
|
+
/**
|
|
23931
|
+
* Un Agent a écrit à un autre Agent de la même machine : un `user_message` de `toThreadId`
|
|
23932
|
+
* porte `createdBy: "agent"` et `senderThreadId: fromThreadId`. Jamais pour un sous-agent.
|
|
23933
|
+
*/
|
|
23934
|
+
external_exports.object({ type: external_exports.literal("agents.exchange"), fromThreadId: id, toThreadId: id }),
|
|
23883
23935
|
external_exports.discriminatedUnion("ok", [
|
|
23884
23936
|
external_exports.object({
|
|
23885
23937
|
type: external_exports.literal("command.result"),
|
|
@@ -24037,13 +24089,19 @@ var clientMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
24037
24089
|
external_exports.union([external_exports.string().max(2e4), external_exports.array(external_exports.string().max(2e3)).max(20)])
|
|
24038
24090
|
)
|
|
24039
24091
|
}),
|
|
24040
|
-
external_exports.object({ type: external_exports.literal("agent.setPrivate"), agentId: ref, ref, private: external_exports.boolean() })
|
|
24092
|
+
external_exports.object({ type: external_exports.literal("agent.setPrivate"), agentId: ref, ref, private: external_exports.boolean() }),
|
|
24093
|
+
/**
|
|
24094
|
+
* « Retirer de l'Espace » (US 35) : le Propriétaire retire tout de suite un Agent Hors ligne, au
|
|
24095
|
+
* lieu d'attendre 24 h. S'il revient en ligne, il réapparaît comme un nouvel Agent.
|
|
24096
|
+
*/
|
|
24097
|
+
external_exports.object({ type: external_exports.literal("agent.remove"), agentId: ref, ref })
|
|
24041
24098
|
]);
|
|
24042
24099
|
var deliverySchema = external_exports.enum(["started", "queued", "steered"]);
|
|
24043
24100
|
var agentErrorSchema = external_exports.enum([
|
|
24044
24101
|
"forbidden",
|
|
24045
24102
|
"unknown-agent",
|
|
24046
24103
|
"offline",
|
|
24104
|
+
"online",
|
|
24047
24105
|
"refused",
|
|
24048
24106
|
"escalation",
|
|
24049
24107
|
"failed"
|
|
@@ -24075,14 +24133,14 @@ var serverMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
24075
24133
|
occupants: external_exports.array(external_exports.object({ id: external_exports.string(), ...poseSchema.shape, audioKey: audioKeySchema }))
|
|
24076
24134
|
}),
|
|
24077
24135
|
/**
|
|
24078
|
-
* Ma clé audio et les identités autorisées à s'abonner à mon micro
|
|
24079
|
-
*
|
|
24080
|
-
* `setTrackSubscriptionPermissions`.
|
|
24136
|
+
* Ma clé audio et les identités autorisées à s'abonner à mon micro, ma caméra et mon écran : les
|
|
24137
|
+
* occupants de même clé, ceux du dehors quand je suis dehors (`listenersAllowed`). Envoyé à
|
|
24138
|
+
* l'entrée, puis à chaque changement ; le client le pose par `setTrackSubscriptionPermissions`.
|
|
24081
24139
|
*/
|
|
24082
24140
|
external_exports.object({
|
|
24083
24141
|
type: external_exports.literal("audio"),
|
|
24084
24142
|
key: audioKeySchema,
|
|
24085
|
-
allowed: external_exports.array(external_exports.string())
|
|
24143
|
+
allowed: external_exports.array(external_exports.string())
|
|
24086
24144
|
}),
|
|
24087
24145
|
/** Création d'un Aparté ou changement de ses participants, pour tout l'Espace. */
|
|
24088
24146
|
external_exports.object({ type: external_exports.literal("aparte.update"), aparte: aparteSchema }),
|
|
@@ -24118,6 +24176,11 @@ var serverMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
24118
24176
|
external_exports.object({ type: external_exports.literal("correction"), ...poseSchema.shape }),
|
|
24119
24177
|
/** Les Agents de l'Espace : instantané à l'entrée, puis changements. */
|
|
24120
24178
|
agentsMessageSchema,
|
|
24179
|
+
/**
|
|
24180
|
+
* 15 Hz, à tout l'Espace : la position des Agents hors de leur Poste, calculée par le serveur
|
|
24181
|
+
* (en route, dans une file). Un Agent absent de la liste est à son Poste. Envoyé aussi à l'entrée.
|
|
24182
|
+
*/
|
|
24183
|
+
external_exports.object({ type: external_exports.literal("agents.poses"), poses: external_exports.array(agentPoseSchema) }),
|
|
24121
24184
|
/** Le fil d'un Agent, à qui a le droit de le lire et l'a ouvert : ses derniers éléments. */
|
|
24122
24185
|
external_exports.object({
|
|
24123
24186
|
type: external_exports.literal("agent.thread"),
|
|
@@ -24146,6 +24209,17 @@ var serverMessageSchema = external_exports.discriminatedUnion("type", [
|
|
|
24146
24209
|
error: agentErrorSchema
|
|
24147
24210
|
})
|
|
24148
24211
|
]),
|
|
24212
|
+
/**
|
|
24213
|
+
* Aux Membres de l'Espace (pas aux Invités) : l'Agent `from` vient d'écrire à l'Agent `to`, de
|
|
24214
|
+
* la même machine. Le client trace un trait entre eux pendant ~10 s (`AGENT_LINK_MS`).
|
|
24215
|
+
*/
|
|
24216
|
+
external_exports.object({ type: external_exports.literal("agents.exchange"), from: external_exports.string(), to: external_exports.string() }),
|
|
24217
|
+
/**
|
|
24218
|
+
* Au Propriétaire : ses Relais refusés parce que trop anciens (leurs noms), pour le bandeau
|
|
24219
|
+
* « Mets à jour ton Relais ». Envoyé à l'entrée s'il y en a, et à chaque changement ; une liste
|
|
24220
|
+
* vide retire le bandeau.
|
|
24221
|
+
*/
|
|
24222
|
+
external_exports.object({ type: external_exports.literal("relays.outdated"), relays: external_exports.array(external_exports.string()) }),
|
|
24149
24223
|
/** Au Propriétaire seulement : son Agent attend ou a fini (US 66). */
|
|
24150
24224
|
external_exports.object({
|
|
24151
24225
|
type: external_exports.literal("notify"),
|
|
@@ -24183,9 +24257,6 @@ var TEXTS = {
|
|
|
24183
24257
|
tu: "La connexion avec Google a \xE9chou\xE9. R\xE9essaie dans un instant.",
|
|
24184
24258
|
vous: "La connexion avec Google a \xE9chou\xE9. R\xE9essayez dans un instant."
|
|
24185
24259
|
},
|
|
24186
|
-
"space.choose.title": { tu: "O\xF9 veux-tu entrer ?", vous: "O\xF9 voulez-vous entrer ?" },
|
|
24187
|
-
"space.choose.enter": same("Entrer"),
|
|
24188
|
-
"space.choose.last": same("Dernier utilis\xE9"),
|
|
24189
24260
|
"space.none": {
|
|
24190
24261
|
tu: "Tu n\u2019as acc\xE8s \xE0 aucun Espace. Demande l\u2019acc\xE8s \xE0 un associ\xE9 de Katalyx.",
|
|
24191
24262
|
vous: "Vous n\u2019avez acc\xE8s \xE0 aucun Espace."
|
|
@@ -24193,10 +24264,37 @@ var TEXTS = {
|
|
|
24193
24264
|
"space.entering": same("Entr\xE9e dans l\u2019Espace {space}\u2026"),
|
|
24194
24265
|
"space.title": same("Espace {space}"),
|
|
24195
24266
|
"space.help": {
|
|
24196
|
-
tu: "Clique au sol ou marche avec Z Q S D. Clic droit gliss\xE9 pour tourner la cam\xE9ra, molette pour zoomer.",
|
|
24267
|
+
tu: "Clique au sol ou marche avec Z Q S D. Clic droit gliss\xE9 pour tourner la cam\xE9ra, molette pour zoomer. Clique sur un robot pour ouvrir son Agent.",
|
|
24197
24268
|
vous: "Cliquez au sol ou marchez avec Z Q S D. Clic droit gliss\xE9 pour tourner la cam\xE9ra, molette pour zoomer."
|
|
24198
24269
|
},
|
|
24199
|
-
"
|
|
24270
|
+
"space.help.dismiss": same("Compris"),
|
|
24271
|
+
// Les Coins de l'Espace (ADR 0008).
|
|
24272
|
+
"corner.space": same("L\u2019Espace"),
|
|
24273
|
+
"corner.space.menu": same("Changer d\u2019Espace ou se d\xE9connecter"),
|
|
24274
|
+
"corner.space.guestMenu": same("Se d\xE9connecter"),
|
|
24275
|
+
"corner.people": same("Pr\xE9sents, Agents et R\xE9glages"),
|
|
24276
|
+
"corner.me": same("Mes commandes"),
|
|
24277
|
+
"corner.view": same("La vue"),
|
|
24278
|
+
"presents.button": same("Pr\xE9sents ({count})"),
|
|
24279
|
+
"agents.button": same("Agents"),
|
|
24280
|
+
"agents.waitingOne": { tu: "1 t\u2019attend", vous: "1 vous attend" },
|
|
24281
|
+
"agents.waitingCount": { tu: "{count} t\u2019attendent", vous: "{count} vous attendent" },
|
|
24282
|
+
"agents.reviewCount": same("{count} \xE0 relire"),
|
|
24283
|
+
"me.place.passage": same("Passage"),
|
|
24284
|
+
"moment.label": same("Action du moment"),
|
|
24285
|
+
"moment.aparte": same("Apart\xE9 avec {names}"),
|
|
24286
|
+
"moment.enter": same("Entr\xE9e"),
|
|
24287
|
+
"drawer.close": same("Fermer (\xC9chap)"),
|
|
24288
|
+
"drawer.back": same("Retour \xE0 la liste"),
|
|
24289
|
+
goTo: same("Aller vers"),
|
|
24290
|
+
// Raccourcis (Réglages > Raccourcis).
|
|
24291
|
+
"shortcuts.walk": same("Marcher"),
|
|
24292
|
+
"shortcuts.mic": same("Couper ou rouvrir le micro"),
|
|
24293
|
+
"shortcuts.videos": same("Basculer entre l\u2019Espace et la Vue Vid\xE9os"),
|
|
24294
|
+
"shortcuts.open": same("Ouvrir l\u2019Agent vis\xE9"),
|
|
24295
|
+
"shortcuts.send": same("Envoyer un message \xE0 l\u2019Agent"),
|
|
24296
|
+
"shortcuts.escape": same("Fermer le tiroir, sortir du plein \xE9cran"),
|
|
24297
|
+
"shortcuts.turn": same("Quart de tour, en vue Iso"),
|
|
24200
24298
|
"menu.switchSpace": same("Changer d\u2019Espace"),
|
|
24201
24299
|
"menu.settings": same("R\xE9glages"),
|
|
24202
24300
|
"menu.invite": same("Inviter"),
|
|
@@ -24212,6 +24310,11 @@ var TEXTS = {
|
|
|
24212
24310
|
vous: "L\u2019enregistrement a \xE9chou\xE9. R\xE9essayez dans un instant."
|
|
24213
24311
|
},
|
|
24214
24312
|
"appearance.legend": { tu: "Ton Apparence", vous: "Votre Apparence" },
|
|
24313
|
+
"appearance.change": same("Changer"),
|
|
24314
|
+
"appearance.drawn": {
|
|
24315
|
+
tu: "Tir\xE9e au hasard. \xAB Changer \xBB en tire une autre.",
|
|
24316
|
+
vous: "Tir\xE9e au hasard. \xAB Changer \xBB en tire une autre."
|
|
24317
|
+
},
|
|
24215
24318
|
"appearance.skin": same("Peau"),
|
|
24216
24319
|
"appearance.outfit": same("Tenue"),
|
|
24217
24320
|
"appearance.hairStyle": same("Coiffure"),
|
|
@@ -24264,8 +24367,8 @@ var TEXTS = {
|
|
|
24264
24367
|
},
|
|
24265
24368
|
// Le temps que la restriction du micro s'applique : rien n'est encore promis.
|
|
24266
24369
|
"zone.bannerPending": {
|
|
24267
|
-
tu: "Zone priv\xE9e : {name} \xB7 Micro
|
|
24268
|
-
vous: "Zone priv\xE9e : {name} \xB7 Micro
|
|
24370
|
+
tu: "Zone priv\xE9e : {name} \xB7 Micro et cam\xE9ra suspendus le temps de fermer la Zone",
|
|
24371
|
+
vous: "Zone priv\xE9e : {name} \xB7 Micro et cam\xE9ra suspendus le temps de fermer la Zone"
|
|
24269
24372
|
},
|
|
24270
24373
|
"aparte.name": same("Apart\xE9"),
|
|
24271
24374
|
"aparte.label": same("Apart\xE9 \xB7 {count}"),
|
|
@@ -24301,16 +24404,17 @@ var TEXTS = {
|
|
|
24301
24404
|
vous: "Approchez-vous du cercle de l\u2019Apart\xE9 pour frapper."
|
|
24302
24405
|
},
|
|
24303
24406
|
"aparte.refused.unknown": same("Cet Apart\xE9 est termin\xE9."),
|
|
24304
|
-
"controls.label": same("Barre de contr\xF4le"),
|
|
24305
24407
|
"camera.label": same("Cam\xE9ra"),
|
|
24306
24408
|
"camera.libre": same("Libre"),
|
|
24307
24409
|
"camera.iso": same("Iso"),
|
|
24308
24410
|
"camera.dessus": same("Dessus"),
|
|
24309
24411
|
"camera.turnLeft": same("Tourner d\u2019un quart de tour \xE0 gauche (A)"),
|
|
24310
24412
|
"camera.turnRight": same("Tourner d\u2019un quart de tour \xE0 droite (E)"),
|
|
24311
|
-
"rings.toggle": same("
|
|
24312
|
-
"
|
|
24313
|
-
|
|
24413
|
+
"rings.toggle": same("Port\xE9e de voix"),
|
|
24414
|
+
"rings.hint": {
|
|
24415
|
+
tu: "Montre jusqu\u2019o\xF9 on t\u2019entend (2 m et 6 m)",
|
|
24416
|
+
vous: "Montre jusqu\u2019o\xF9 on vous entend (2 m et 6 m)"
|
|
24417
|
+
},
|
|
24314
24418
|
"presents.title": same("Pr\xE9sents"),
|
|
24315
24419
|
"presents.member": same("Membre"),
|
|
24316
24420
|
"presents.guest": same("Invit\xE9"),
|
|
@@ -24325,6 +24429,56 @@ var TEXTS = {
|
|
|
24325
24429
|
tu: "Le nom que les autres voient sur ton \xE9tiquette et dans la liste des Pr\xE9sents.",
|
|
24326
24430
|
vous: "Le nom que les autres voient sur votre \xE9tiquette et dans la liste des Pr\xE9sents."
|
|
24327
24431
|
},
|
|
24432
|
+
"settings.audio": same("Micro et sortie"),
|
|
24433
|
+
"settings.camera": same("Cam\xE9ra et \xE9cran"),
|
|
24434
|
+
"settings.camera.lead": {
|
|
24435
|
+
tu: "Ta cam\xE9ra est coup\xE9e \xE0 chaque entr\xE9e. Allum\xE9e, elle est visible de tout l\u2019Espace en petit, en grand \xE0 moins de 2 m ; dans une Salle ou un Apart\xE9, de ceux qui y sont seulement.",
|
|
24436
|
+
vous: "Votre cam\xE9ra est coup\xE9e \xE0 chaque entr\xE9e. Allum\xE9e, elle est visible de tout l\u2019Espace en petit, en grand \xE0 moins de 2 m ; dans une Salle ou un Apart\xE9, de ceux qui y sont seulement."
|
|
24437
|
+
},
|
|
24438
|
+
"settings.camera.device": same("Cam\xE9ra"),
|
|
24439
|
+
"settings.camera.default": same("Cam\xE9ra par d\xE9faut"),
|
|
24440
|
+
"settings.camera.atEntry": {
|
|
24441
|
+
tu: "Allumer ma cam\xE9ra en entrant",
|
|
24442
|
+
vous: "Allumer ma cam\xE9ra en entrant"
|
|
24443
|
+
},
|
|
24444
|
+
// Vidéo et partage d'écran (ADR 0009).
|
|
24445
|
+
"video.cameraOn": same("Allumer la cam\xE9ra"),
|
|
24446
|
+
"video.cameraOff": same("Couper la cam\xE9ra"),
|
|
24447
|
+
"video.cameraHint": same("Visible de tout l\u2019Espace en petit, en grand \xE0 moins de 2 m"),
|
|
24448
|
+
"video.cameraError.denied": {
|
|
24449
|
+
tu: "Cam\xE9ra refus\xE9e : autorise-la dans les r\xE9glages du navigateur.",
|
|
24450
|
+
vous: "Cam\xE9ra refus\xE9e : autorisez-la dans les r\xE9glages du navigateur."
|
|
24451
|
+
},
|
|
24452
|
+
"video.cameraError.unavailable": same("Cam\xE9ra indisponible"),
|
|
24453
|
+
"video.shareStart": same("Partager l\u2019\xE9cran"),
|
|
24454
|
+
"video.shareStop": same("Arr\xEAter le partage d\u2019\xE9cran"),
|
|
24455
|
+
"video.bandeau": same("Bandeau des vid\xE9os"),
|
|
24456
|
+
"video.more": same("Voir les {count} autres vid\xE9os"),
|
|
24457
|
+
"video.cameraMuted": same("cam\xE9ra coup\xE9e"),
|
|
24458
|
+
"video.screenOf": same("\xC9cran de {name}"),
|
|
24459
|
+
"video.myScreen": { tu: "Ton \xE9cran", vous: "Votre \xE9cran" },
|
|
24460
|
+
"video.mini": same("Vid\xE9o de {name}"),
|
|
24461
|
+
"video.enlarge": same("Agrandir"),
|
|
24462
|
+
"video.view": same("Vue Vid\xE9os"),
|
|
24463
|
+
"video.toggle": same("Espace ou Vue Vid\xE9os (V)"),
|
|
24464
|
+
"video.toggle.space": same("Espace"),
|
|
24465
|
+
"video.toggle.videos": same("Vid\xE9os"),
|
|
24466
|
+
"video.propose": same("Vue Vid\xE9os"),
|
|
24467
|
+
"video.later": same("Plus tard"),
|
|
24468
|
+
"video.back": same("Revenir \xE0 l\u2019Espace"),
|
|
24469
|
+
"video.around": { tu: "Autour de toi", vous: "Autour de vous" },
|
|
24470
|
+
"video.alone": {
|
|
24471
|
+
tu: "Personne \xE0 moins de 2 m. Approche-toi de quelqu\u2019un ou allume ta cam\xE9ra.",
|
|
24472
|
+
vous: "Personne \xE0 moins de 2 m. Approchez-vous de quelqu\u2019un ou allumez votre cam\xE9ra."
|
|
24473
|
+
},
|
|
24474
|
+
"video.mosaic": same("Revenir \xE0 la mosa\xEFque"),
|
|
24475
|
+
"video.fullscreen": same("Plein \xE9cran"),
|
|
24476
|
+
"video.fullscreenExit": same("Quitter le plein \xE9cran (\xC9chap)"),
|
|
24477
|
+
"video.zoomLevel": same("Niveau de zoom"),
|
|
24478
|
+
"video.fit": same("Ajuster"),
|
|
24479
|
+
"video.actualSize": same("Taille r\xE9elle (1:1)"),
|
|
24480
|
+
"video.zoomHint": same("Ctrl + molette ou pincement pour zoomer, glisser pour se d\xE9placer"),
|
|
24481
|
+
"settings.shortcuts": same("Raccourcis"),
|
|
24328
24482
|
"settings.save": same("Enregistrer"),
|
|
24329
24483
|
"settings.saved": same("Enregistr\xE9."),
|
|
24330
24484
|
"settings.failed": {
|
|
@@ -24343,18 +24497,52 @@ var TEXTS = {
|
|
|
24343
24497
|
"agents.status.waiting": same("Attend"),
|
|
24344
24498
|
"agents.status.available": same("Disponible"),
|
|
24345
24499
|
"agents.status.failed": same("En \xE9chec"),
|
|
24346
|
-
"agents.
|
|
24347
|
-
"agents.
|
|
24348
|
-
"agents.
|
|
24500
|
+
"agents.status.review": same("\xC0 relire"),
|
|
24501
|
+
"agents.status.offline": same("Hors ligne"),
|
|
24502
|
+
"agents.filter": same("Quels Agents"),
|
|
24503
|
+
"agents.filter.all": same("Tous"),
|
|
24504
|
+
"agents.filter.mine": same("Les miens"),
|
|
24505
|
+
"agents.group.waiting": same("Attend une r\xE9ponse"),
|
|
24506
|
+
"agents.group.review": same("\xC0 relire"),
|
|
24507
|
+
"agents.group.failed": same("En \xE9chec"),
|
|
24508
|
+
"agents.group.working": same("Travaille"),
|
|
24509
|
+
"agents.group.available": same("Disponible"),
|
|
24510
|
+
"agents.group.offline": same("Hors ligne ({count})"),
|
|
24511
|
+
"agents.chip.waiting": same("R\xE9ponse"),
|
|
24512
|
+
// Demandes, À relire et Relais v2.
|
|
24513
|
+
"agents.answer": same("R\xE9pondre \xE0 \xAB {title} \xBB"),
|
|
24514
|
+
"agents.answer.other": same("Autre r\xE9ponse\u2026"),
|
|
24515
|
+
"agents.answer.open": same("R\xE9pondre\u2026"),
|
|
24516
|
+
"bubble.waiting": same("Attend une r\xE9ponse"),
|
|
24517
|
+
"bubble.review": same("\xC0 relire"),
|
|
24518
|
+
"bubble.approval": same("Approbation en attente"),
|
|
24519
|
+
"agents.exchange": same("\xAB {from} \xBB \xE9crit \xE0 \xAB {to} \xBB"),
|
|
24520
|
+
"relays.outdated": {
|
|
24521
|
+
tu: "Mets \xE0 jour ton Relais \xAB {names} \xBB : il est trop ancien pour ce Kather et ses Agents n\u2019apparaissent plus. Lance npx kather-relay@latest install-service sur cette machine.",
|
|
24522
|
+
vous: "Ce Relais est trop ancien pour ce Kather."
|
|
24523
|
+
},
|
|
24524
|
+
"protocol.outdated": {
|
|
24525
|
+
tu: "Kather a \xE9t\xE9 mis \xE0 jour : recharge la page pour continuer.",
|
|
24526
|
+
vous: "Kather a \xE9t\xE9 mis \xE0 jour : rechargez la page pour continuer."
|
|
24527
|
+
},
|
|
24528
|
+
"protocol.outdated.title": same("Nouvelle version de Kather"),
|
|
24529
|
+
"protocol.reload": same("Recharger"),
|
|
24530
|
+
"agents.chip.review": same("\xC0 relire"),
|
|
24531
|
+
"agents.chip.failed": same("\xC9chec"),
|
|
24532
|
+
"agents.mineEmpty": {
|
|
24533
|
+
tu: "Aucun de tes Agents n\u2019est dans cet Espace.",
|
|
24534
|
+
vous: "Aucun Agent."
|
|
24535
|
+
},
|
|
24349
24536
|
"agents.noDesk": same("sans Poste"),
|
|
24350
|
-
"agents.
|
|
24351
|
-
"agents.
|
|
24537
|
+
"agents.where.comingToMe": { tu: "en route vers toi", vous: "en route vers vous" },
|
|
24538
|
+
"agents.where.coming": same("en route vers {name}"),
|
|
24539
|
+
"agents.where.nearMe": { tu: "pr\xE8s de toi", vous: "pr\xE8s de vous" },
|
|
24540
|
+
"agents.where.near": same("pr\xE8s de {name}"),
|
|
24541
|
+
"agents.where.returning": same("rentre \xE0 son Poste"),
|
|
24542
|
+
"agents.where.raised": same("main lev\xE9e \xE0 son Poste"),
|
|
24352
24543
|
// Panneau d'un Agent (US 67 à 71, 76, 77).
|
|
24353
24544
|
"agent.panel": same("Agent \xAB {title} \xBB"),
|
|
24354
|
-
"agent.open": same("Ouvrir le panneau de l\u2019Agent"),
|
|
24355
24545
|
"agent.prompt": same("Ouvrir \xAB {title} \xBB"),
|
|
24356
|
-
"agent.close": same("Fermer le panneau"),
|
|
24357
|
-
"agent.owner": same("Agent de {name}"),
|
|
24358
24546
|
"agent.readOnly": same("Lecture seule \xB7 Agent de {name}"),
|
|
24359
24547
|
"agent.restricted.private": same(
|
|
24360
24548
|
"Agent priv\xE9 : seuls son Statut, son titre et son Propri\xE9taire sont visibles."
|
|
@@ -24380,6 +24568,7 @@ var TEXTS = {
|
|
|
24380
24568
|
"agent.error.forbidden": same("Seul le Propri\xE9taire peut \xE9crire \xE0 cet Agent."),
|
|
24381
24569
|
"agent.error.unknown-agent": same("Cet Agent n\u2019est plus l\xE0."),
|
|
24382
24570
|
"agent.error.offline": same("Agent hors ligne : le Relais ou T3 Code ne r\xE9pond pas."),
|
|
24571
|
+
"agent.error.online": same("Cet Agent est de nouveau en ligne : il reste dans l\u2019Espace."),
|
|
24383
24572
|
"agent.error.refused": same("Le Relais a refus\xE9 cette op\xE9ration."),
|
|
24384
24573
|
"agent.error.escalation": {
|
|
24385
24574
|
tu: "T3 Code refuse : ce thread tourne dans un mode plus large que l\u2019autorisation du Relais. Reconnecte ton T3 Code en Full access (kather-relay login).",
|
|
@@ -24391,13 +24580,30 @@ var TEXTS = {
|
|
|
24391
24580
|
),
|
|
24392
24581
|
"agent.request": same("Demande en attente"),
|
|
24393
24582
|
"agent.request.loading": same("Lecture de la demande\u2026"),
|
|
24394
|
-
"agent.request.
|
|
24395
|
-
tu: "L\u2019Agent attend, mais pas une r\xE9ponse \xE0 une question : cette demande (une permission, sans doute) se traite dans T3 Code.",
|
|
24396
|
-
vous: "L\u2019Agent attend une demande qui se traite dans T3 Code."
|
|
24397
|
-
},
|
|
24583
|
+
"agent.request.reread": same("Relire la demande"),
|
|
24398
24584
|
"agent.request.other": same("Autre r\xE9ponse"),
|
|
24399
24585
|
"agent.request.answer": same("R\xE9pondre"),
|
|
24400
24586
|
"agent.request.answered": same("R\xE9ponse envoy\xE9e."),
|
|
24587
|
+
"agent.menu": same("Plus d\u2019actions"),
|
|
24588
|
+
"agent.goToDesk": same("Aller \xE0 son Poste"),
|
|
24589
|
+
"agent.meta.mine": { tu: "\xE0 toi", vous: "\xE0 vous" },
|
|
24590
|
+
"agent.meta.of": same("de {name}"),
|
|
24591
|
+
"agent.offline.machine": same("La machine {machine} ne donne plus de nouvelles depuis {time}."),
|
|
24592
|
+
"agent.offline.unknown": same("Sa machine ne donne plus de nouvelles depuis {time}."),
|
|
24593
|
+
"agent.offline.back": same("Son fil reviendra quand son Relais sera relanc\xE9."),
|
|
24594
|
+
"agent.remove": same("Retirer de l\u2019Espace"),
|
|
24595
|
+
"agent.remove.hint": same(
|
|
24596
|
+
"Il dispara\xEEt pour tous et lib\xE8re son Poste ; s\u2019il revient en ligne, il r\xE9appara\xEEt comme un nouvel Agent."
|
|
24597
|
+
),
|
|
24598
|
+
"agent.removed": same("\xAB {title} \xBB a \xE9t\xE9 retir\xE9 de l\u2019Espace."),
|
|
24599
|
+
"agent.request.waiting": {
|
|
24600
|
+
tu: "L\u2019Agent attend ta r\xE9ponse",
|
|
24601
|
+
vous: "L\u2019Agent attend une r\xE9ponse"
|
|
24602
|
+
},
|
|
24603
|
+
"agent.request.collapse": same("Replier la demande"),
|
|
24604
|
+
"agent.request.expand": same("D\xE9plier la demande"),
|
|
24605
|
+
"agent.request.approve": same("\xC0 approuver dans T3 Code"),
|
|
24606
|
+
"agent.composer": same("\xC9crire \xE0 l\u2019Agent\u2026 (Ctrl+Entr\xE9e)"),
|
|
24401
24607
|
"agent.private": same("Priv\xE9"),
|
|
24402
24608
|
"agent.private.hint": {
|
|
24403
24609
|
tu: "Les autres Membres ne voient que son Statut et son titre, sans son fil.",
|
|
@@ -24425,7 +24631,7 @@ var TEXTS = {
|
|
|
24425
24631
|
tu: "Reconnecte ton T3 Code : l\u2019autorisation de \xAB {machine} \xBB a expir\xE9. Lance kather-relay login sur cette machine.",
|
|
24426
24632
|
vous: "Reconnectez votre T3 Code : l\u2019autorisation de \xAB {machine} \xBB a expir\xE9."
|
|
24427
24633
|
},
|
|
24428
|
-
"settings.relays": same("Relais"),
|
|
24634
|
+
"settings.relays": same("Relais et Agents"),
|
|
24429
24635
|
"relays.lead": {
|
|
24430
24636
|
tu: "Le Relais fait appara\xEEtre tes Agents T3 Code dans Kather. Il tourne sur ta machine : ton jeton T3 Code ne la quitte jamais.",
|
|
24431
24637
|
vous: "Le Relais fait appara\xEEtre vos Agents T3 Code dans Kather. Il tourne sur votre machine."
|
|
@@ -24436,7 +24642,7 @@ var TEXTS = {
|
|
|
24436
24642
|
vous: "Collez-le dans votre T3 Code : votre agent installe, appaire et lance le Relais."
|
|
24437
24643
|
},
|
|
24438
24644
|
"relays.prompt": same(
|
|
24439
|
-
"Installe et lance le Relais Kather sur cette machine. 1) V\xE9rifie que Node 22 ou plus est install\xE9. 2) Lance `npx kather-relay connect {url}` : il m\u2019affichera un code que je confirmerai dans le navigateur, puis il ouvrira la page de consentement de T3 Code, o\xF9 je choisirai Full access. 3) Installe ensuite le Relais en service utilisateur qui d\xE9marre avec ma session (systemd `--user` sous Linux, launchd sous macOS) avec `npx kather-relay install-service`, puis v\xE9rifie qu\u2019il tourne avec `npx kather-relay status`. Ne modifie aucun autre r\xE9glage de T3 Code."
|
|
24645
|
+
"Installe et lance le Relais Kather sur cette machine. 1) V\xE9rifie que Node 22 ou plus est install\xE9. 2) Lance `npx kather-relay@latest connect {url}` : il m\u2019affichera un code que je confirmerai dans le navigateur, puis il ouvrira la page de consentement de T3 Code, o\xF9 je choisirai Full access. 3) Installe ensuite le Relais en service utilisateur qui d\xE9marre avec ma session (systemd `--user` sous Linux, launchd sous macOS) avec `npx kather-relay@latest install-service`, puis v\xE9rifie qu\u2019il tourne avec `npx kather-relay@latest status`. Ne modifie aucun autre r\xE9glage de T3 Code."
|
|
24440
24646
|
),
|
|
24441
24647
|
"relays.prompt.copy": same("Copier le prompt"),
|
|
24442
24648
|
"relays.prompt.copied": same("Copi\xE9."),
|
|
@@ -24549,6 +24755,9 @@ var TEXTS = {
|
|
|
24549
24755
|
"invitations.pending": same("Espace {space} \xB7 lien valable jusqu\u2019au {date}"),
|
|
24550
24756
|
"invitations.entered": same("Espace {space} \xB7 Entr\xE9e, acc\xE8s jusqu\u2019\xE0 minuit"),
|
|
24551
24757
|
"invitations.revoke": same("R\xE9voquer"),
|
|
24758
|
+
"invitations.copy": same("Copier le lien"),
|
|
24759
|
+
"invitations.copied": same("Lien copi\xE9."),
|
|
24760
|
+
"invitations.fresh": same("Envoy\xE9e \xE0 l\u2019instant"),
|
|
24552
24761
|
"invitations.revoke.confirm": same("R\xE9voquer l\u2019invitation de {email} ?"),
|
|
24553
24762
|
"invitation.title": {
|
|
24554
24763
|
tu: "{inviter} t\u2019invite dans l\u2019Espace {space}",
|
|
@@ -24773,7 +24982,11 @@ var threadSchema = external_exports.looseObject({
|
|
|
24773
24982
|
link: external_exports.string().nullish(),
|
|
24774
24983
|
settled: external_exports.boolean().nullish(),
|
|
24775
24984
|
parentThreadId: external_exports.string().nullish(),
|
|
24776
|
-
relationshipToParent: external_exports.string().nullish()
|
|
24985
|
+
relationshipToParent: external_exports.string().nullish(),
|
|
24986
|
+
/** Change à chaque nouvel élément de la chronologie. */
|
|
24987
|
+
updatedAt: external_exports.string().nullish(),
|
|
24988
|
+
/** Tous les éléments de la chronologie, activité comprise. */
|
|
24989
|
+
itemCount: external_exports.number().int().nullish()
|
|
24777
24990
|
});
|
|
24778
24991
|
var threadPageSchema = external_exports.looseObject({
|
|
24779
24992
|
threads: external_exports.array(threadSchema),
|
|
@@ -24797,7 +25010,11 @@ var threadReadSchema = external_exports.looseObject({
|
|
|
24797
25010
|
type: external_exports.string(),
|
|
24798
25011
|
text: external_exports.string().nullish(),
|
|
24799
25012
|
textTruncated: external_exports.boolean().nullish(),
|
|
24800
|
-
updatedAt: external_exports.string().nullish()
|
|
25013
|
+
updatedAt: external_exports.string().nullish(),
|
|
25014
|
+
/** `agent` pour un message écrit par un autre fil, et pour les réponses de l'Agent. */
|
|
25015
|
+
createdBy: external_exports.string().nullish(),
|
|
25016
|
+
/** Le fil qui a écrit ce `user_message`, quand c'est un Agent. */
|
|
25017
|
+
senderThreadId: external_exports.string().nullish()
|
|
24801
25018
|
})
|
|
24802
25019
|
),
|
|
24803
25020
|
nextPosition: external_exports.number().int().nullish(),
|
|
@@ -24887,11 +25104,29 @@ function createT3(options) {
|
|
|
24887
25104
|
}
|
|
24888
25105
|
|
|
24889
25106
|
// src/version.ts
|
|
24890
|
-
var RELAY_VERSION = "0.
|
|
25107
|
+
var RELAY_VERSION = "0.2.0";
|
|
24891
25108
|
|
|
24892
25109
|
// src/relay.ts
|
|
24893
25110
|
var EXPIRY_WARNING_MS = 3 * 24 * 60 * 60 * 1e3;
|
|
24894
25111
|
var PROJECT_CACHE_MS = 6e4;
|
|
25112
|
+
var EXCHANGE_READ_ITEMS = 5;
|
|
25113
|
+
var EXCHANGE_MAX_PAGES = 20;
|
|
25114
|
+
async function readSince(client, threadId, after, added) {
|
|
25115
|
+
const items = [];
|
|
25116
|
+
const pages = added === null ? EXCHANGE_MAX_PAGES : Math.ceil(added / EXCHANGE_READ_ITEMS) + 1;
|
|
25117
|
+
let position = after;
|
|
25118
|
+
for (let page = 0; page < pages; page++) {
|
|
25119
|
+
const read = await client.readThread(threadId, {
|
|
25120
|
+
limit: EXCHANGE_READ_ITEMS,
|
|
25121
|
+
maxCharsPerItem: 1,
|
|
25122
|
+
...position >= 0 ? { afterPosition: position } : {}
|
|
25123
|
+
});
|
|
25124
|
+
items.push(...read.items);
|
|
25125
|
+
if (!read.hasMore || read.nextPosition == null) break;
|
|
25126
|
+
position = read.nextPosition;
|
|
25127
|
+
}
|
|
25128
|
+
return items;
|
|
25129
|
+
}
|
|
24895
25130
|
var MAX_RECONNECT_MS = 3e4;
|
|
24896
25131
|
var serialize = (agent) => JSON.stringify(agent);
|
|
24897
25132
|
function startRelay(options) {
|
|
@@ -24914,6 +25149,8 @@ function startRelay(options) {
|
|
|
24914
25149
|
const watched = /* @__PURE__ */ new Map();
|
|
24915
25150
|
let projects = null;
|
|
24916
25151
|
let lastPending = /* @__PURE__ */ new Map();
|
|
25152
|
+
let requests = /* @__PURE__ */ new Map();
|
|
25153
|
+
let timelines = /* @__PURE__ */ new Map();
|
|
24917
25154
|
const connectT3 = (from) => from ? createT3({
|
|
24918
25155
|
url: from.url,
|
|
24919
25156
|
accessToken: from.accessToken,
|
|
@@ -24965,6 +25202,62 @@ function startRelay(options) {
|
|
|
24965
25202
|
wake = done;
|
|
24966
25203
|
});
|
|
24967
25204
|
const pollSoon = () => wake?.();
|
|
25205
|
+
async function readRequests(client, waiting, pending) {
|
|
25206
|
+
const next = /* @__PURE__ */ new Map();
|
|
25207
|
+
await Promise.all(
|
|
25208
|
+
waiting.map(async (t) => {
|
|
25209
|
+
const count = pending.get(t.threadId) ?? 0;
|
|
25210
|
+
if (count === 0) return;
|
|
25211
|
+
const key = `${count}:${t.updatedAt ?? ""}`;
|
|
25212
|
+
const known = requests.get(t.threadId);
|
|
25213
|
+
if (known?.key === key) return void next.set(t.threadId, known);
|
|
25214
|
+
try {
|
|
25215
|
+
const listed = pendingRequestsFrom({ requests: await client.pendingRequests(t.threadId) });
|
|
25216
|
+
const first = listed?.[0];
|
|
25217
|
+
const request = !listed ? known?.request ?? null : first ? { kind: "question", request: first } : { kind: "approval" };
|
|
25218
|
+
next.set(t.threadId, { key: listed ? key : "", request });
|
|
25219
|
+
} catch (error62) {
|
|
25220
|
+
if (error62 instanceof T3Unauthorized || error62 instanceof T3Unreachable) throw error62;
|
|
25221
|
+
log(`demande du thread ${t.threadId} : ${String(error62)}`);
|
|
25222
|
+
next.set(t.threadId, { key: "", request: known?.request ?? null });
|
|
25223
|
+
}
|
|
25224
|
+
})
|
|
25225
|
+
);
|
|
25226
|
+
requests = next;
|
|
25227
|
+
}
|
|
25228
|
+
async function findExchanges(client, threads) {
|
|
25229
|
+
const next = /* @__PURE__ */ new Map();
|
|
25230
|
+
const changed = [];
|
|
25231
|
+
for (const t of threads) {
|
|
25232
|
+
if (!knownAgents.has(t.threadId)) continue;
|
|
25233
|
+
const current = { updatedAt: t.updatedAt ?? null, itemCount: t.itemCount ?? null };
|
|
25234
|
+
next.set(t.threadId, current);
|
|
25235
|
+
const before = timelines.get(t.threadId);
|
|
25236
|
+
if (!before || before.updatedAt === current.updatedAt || before.itemCount === null) continue;
|
|
25237
|
+
if (current.itemCount !== null && current.itemCount <= before.itemCount) continue;
|
|
25238
|
+
const added = current.itemCount === null ? null : current.itemCount - before.itemCount;
|
|
25239
|
+
changed.push({ threadId: t.threadId, after: before.itemCount - 1, added });
|
|
25240
|
+
}
|
|
25241
|
+
timelines = next;
|
|
25242
|
+
const reads = await Promise.allSettled(
|
|
25243
|
+
changed.map(({ threadId, after, added }) => readSince(client, threadId, after, added))
|
|
25244
|
+
);
|
|
25245
|
+
reads.forEach((read, i) => {
|
|
25246
|
+
const toThreadId = changed[i].threadId;
|
|
25247
|
+
if (read.status === "rejected") {
|
|
25248
|
+
if (read.reason instanceof T3Unauthorized || read.reason instanceof T3Unreachable) {
|
|
25249
|
+
throw read.reason;
|
|
25250
|
+
}
|
|
25251
|
+
return log(`\xE9changes du thread ${toThreadId} : ${String(read.reason)}`);
|
|
25252
|
+
}
|
|
25253
|
+
for (const item2 of read.value) {
|
|
25254
|
+
const from = item2.senderThreadId;
|
|
25255
|
+
if (item2.type !== "user_message" || item2.createdBy !== "agent" || !from) continue;
|
|
25256
|
+
if (from === toThreadId || !knownAgents.has(from)) continue;
|
|
25257
|
+
send({ type: "agents.exchange", fromThreadId: from, toThreadId });
|
|
25258
|
+
}
|
|
25259
|
+
});
|
|
25260
|
+
}
|
|
24968
25261
|
function agentsOf(threads, pending) {
|
|
24969
25262
|
const subagents = /* @__PURE__ */ new Map();
|
|
24970
25263
|
for (const t of threads) {
|
|
@@ -24983,7 +25276,7 @@ function startRelay(options) {
|
|
|
24983
25276
|
projectId: t.projectId ?? null,
|
|
24984
25277
|
projectName: t.projectId ? projects?.names.get(t.projectId) ?? null : null,
|
|
24985
25278
|
status: katherStatusOf(t.status, pendingCount),
|
|
24986
|
-
|
|
25279
|
+
request: pendingCount > 0 ? requests.get(t.threadId)?.request ?? null : null,
|
|
24987
25280
|
subagents: subagents.get(t.threadId) ?? { active: 0, total: 0 },
|
|
24988
25281
|
link: t.link ?? null
|
|
24989
25282
|
};
|
|
@@ -25032,7 +25325,9 @@ function startRelay(options) {
|
|
|
25032
25325
|
projects = { at: now(), names: await t3.projectNames() };
|
|
25033
25326
|
}
|
|
25034
25327
|
const client = t3;
|
|
25035
|
-
const waiting = threads.filter(
|
|
25328
|
+
const waiting = threads.filter(
|
|
25329
|
+
(t) => knownAgents.has(t.threadId) && (t.status === "waiting" || t.status === "running")
|
|
25330
|
+
);
|
|
25036
25331
|
const details = await Promise.allSettled(
|
|
25037
25332
|
waiting.map((t) => client.readThread(t.threadId, { limit: 1, maxCharsPerItem: 1 }))
|
|
25038
25333
|
);
|
|
@@ -25050,8 +25345,10 @@ function startRelay(options) {
|
|
|
25050
25345
|
pending.set(t.threadId, lastPending.get(t.threadId) ?? 0);
|
|
25051
25346
|
});
|
|
25052
25347
|
lastPending = pending;
|
|
25348
|
+
await readRequests(client, waiting, pending);
|
|
25053
25349
|
setAuth(expiryState());
|
|
25054
25350
|
publish(agentsOf(threads, pending));
|
|
25351
|
+
await findExchanges(client, threads);
|
|
25055
25352
|
for (const threadId of [...watched.keys()]) await sendThread(threadId);
|
|
25056
25353
|
} catch (error62) {
|
|
25057
25354
|
if (error62 instanceof T3Unauthorized) setAuth("expired");
|
|
@@ -25277,7 +25574,10 @@ function serviceDefinition(options) {
|
|
|
25277
25574
|
].join("\n"),
|
|
25278
25575
|
install: [
|
|
25279
25576
|
["systemctl", "--user", "daemon-reload"],
|
|
25280
|
-
["systemctl", "--user", "enable",
|
|
25577
|
+
["systemctl", "--user", "enable", SERVICE_NAME],
|
|
25578
|
+
// `restart` démarre un service arrêté et relance un service en cours : une mise à jour
|
|
25579
|
+
// (`npx kather-relay@latest install-service`) repart sur la nouvelle copie.
|
|
25580
|
+
["systemctl", "--user", "restart", SERVICE_NAME]
|
|
25281
25581
|
],
|
|
25282
25582
|
uninstall: [["systemctl", "--user", "disable", "--now", SERVICE_NAME]]
|
|
25283
25583
|
};
|
package/package.json
CHANGED