@paradow/ledge 0.33.0 → 0.35.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/dist/cli/index.js +39003 -46
- package/dist/cli/reduceWorker.js +2037 -0
- package/dist/ledge-guide.md +26 -49
- package/package.json +5 -1
- package/dist/cli/action-QW2ZQQBN.js +0 -27
- package/dist/cli/attach-ULTYWCJ7.js +0 -74
- package/dist/cli/bridge-CSLF7EW6.js +0 -70
- package/dist/cli/chunk-3DB3VOMM.js +0 -723
- package/dist/cli/chunk-4HXJQEUN.js +0 -118
- package/dist/cli/chunk-4VNKZOC2.js +0 -160
- package/dist/cli/chunk-6IYPRUQG.js +0 -17
- package/dist/cli/chunk-ASYAWVFW.js +0 -95
- package/dist/cli/chunk-CCSUP5ZI.js +0 -45
- package/dist/cli/chunk-CPERVAPQ.js +0 -232
- package/dist/cli/chunk-CSLVBADC.js +0 -60
- package/dist/cli/chunk-E3LXONBI.js +0 -6
- package/dist/cli/chunk-GXL3X7M7.js +0 -144
- package/dist/cli/chunk-HOOHS3MX.js +0 -39
- package/dist/cli/chunk-JEGPTNWV.js +0 -270
- package/dist/cli/chunk-K7UEKSB2.js +0 -305
- package/dist/cli/chunk-NLL2EQJ2.js +0 -94
- package/dist/cli/chunk-NWIICISV.js +0 -290
- package/dist/cli/chunk-OLLQBK6N.js +0 -41
- package/dist/cli/chunk-PZ3F4QH3.js +0 -9758
- package/dist/cli/chunk-U67V476Y.js +0 -35
- package/dist/cli/chunk-WXE2NOE5.js +0 -2674
- package/dist/cli/chunk-XOZD4BP5.js +0 -85
- package/dist/cli/daemon-5GT545BB.js +0 -2322
- package/dist/cli/decide-PFHHOCFZ.js +0 -59
- package/dist/cli/handover-EMO6JT7O.js +0 -17
- package/dist/cli/hook-W2BU74H5.js +0 -523
- package/dist/cli/launch-LP7YJR5N.js +0 -36
- package/dist/cli/send-NEI4X33R.js +0 -19
- package/dist/cli/setup-K42IVMHS.js +0 -38
- package/dist/cli/status-U2HGGKHF.js +0 -28
- package/dist/cli/task-PDDCE23D.js +0 -19
- package/dist/cli/team-S3ASP22H.js +0 -205
- package/dist/cli/tui-UPMRMCPC.js +0 -19216
- package/dist/cli/uninstall-4IMMR55T.js +0 -162
- package/dist/cli/version-LUMK3Z3T.js +0 -7
- package/dist/cli/who-NM3GPAPJ.js +0 -12
package/dist/ledge-guide.md
CHANGED
|
@@ -4,14 +4,14 @@ Ce guide est écrit à la main et versionné avec le code. Ledge le recopie dans
|
|
|
4
4
|
|
|
5
5
|
## Ce qu'est Ledge
|
|
6
6
|
|
|
7
|
-
Ledge veille sur les sessions d'agents de l'utilisateur : Claude Code, Codex, Cursor Agent et OMP, lancés dans WSL ou sur un serveur SSH. Il montre ce que fait chaque agent et ce qu'il attend. Il permet de répondre à une demande sans ouvrir son terminal
|
|
7
|
+
Ledge veille sur les sessions d'agents de l'utilisateur : Claude Code, Codex, Cursor Agent et OMP, lancés dans WSL ou sur un serveur SSH. Il montre ce que fait chaque agent et ce qu'il attend. Il permet de répondre à une demande sans ouvrir son terminal et de lancer des sessions.
|
|
8
8
|
|
|
9
|
-
- **Le daemon** (`ledge daemon`, paquet npm `@paradow/ledge`) tourne dans WSL ou sur un serveur. Il suit les sessions par leurs hooks et par tmux, garde les projets, les
|
|
9
|
+
- **Le daemon** (`ledge daemon`, paquet npm `@paradow/ledge`) tourne dans WSL ou sur un serveur. Il suit les sessions par leurs hooks et par tmux, garde les projets, les tâches et les messages entre sessions, et fait tourner le chat de Ledge. La CLI `ledge` lui parle :
|
|
10
10
|
- `ledge claude|codex|cursor` lance un agent suivi ;
|
|
11
11
|
- `ledge attach <id>` met le terminal sur une session ;
|
|
12
12
|
- `ledge who` et `ledge status` listent les sessions ;
|
|
13
13
|
- `ledge send` et `ledge read` servent aux messages entre sessions ;
|
|
14
|
-
- `ledge task`, `ledge decide`, `ledge
|
|
14
|
+
- `ledge task`, `ledge decide`, `ledge handover` et `ledge close` gèrent les tâches, les décisions, la passation de relais et la fermeture ;
|
|
15
15
|
- `ledge tui` est Ledge dans un terminal ;
|
|
16
16
|
- `ledge setup` et `ledge uninstall` installent et retirent les hooks et `~/.ledge`.
|
|
17
17
|
- **Ledge Desktop** est l'application Windows : la fenêtre principale (accueil, atelier, sessions, réglages) et l'**encoche**.
|
|
@@ -51,24 +51,16 @@ L'application s'ouvre ici. On y vient aussi par `/` ou par l'entrée « Accueil
|
|
|
51
51
|
#### Conversation (`conversation`)
|
|
52
52
|
|
|
53
53
|
C'est la conversation avec Ledge, en pleine largeur.
|
|
54
|
-
- On y pose des questions et on mentionne une session
|
|
54
|
+
- On y pose des questions et on mentionne une session.
|
|
55
55
|
- On y valide les cartes que Ledge propose.
|
|
56
|
-
- Le panneau « Le point » résume
|
|
56
|
+
- Le panneau « Le point » résume deux sections : « À toi » et « Confiées par Ledge ». Le bouton « Résumer la journée » est là aussi.
|
|
57
57
|
|
|
58
58
|
Y renvoyer l'utilisateur pour une longue discussion avec Ledge, ou pour faire le point sur la journée.
|
|
59
59
|
|
|
60
|
-
#### Équipes (`teams`)
|
|
61
|
-
|
|
62
|
-
Le catalogue a trois parties : « En cours » (les équipes actives), « Modèles » et « Rôles ».
|
|
63
|
-
- Les boutons « Lancer une session », « Monter une équipe… » et « Lancer cette équipe… » sont ici.
|
|
64
|
-
- Les rôles et les modèles se lisent ici mais se modifient dans leurs fichiers : `~/.ledge/roles/<id>.md` et `~/.ledge/teams/<id>.yaml`, ou les mêmes sous `<dépôt>/.ledge/`.
|
|
65
|
-
|
|
66
|
-
Y renvoyer l'utilisateur pour voir ou monter une équipe, ou pour consulter un rôle.
|
|
67
|
-
|
|
68
60
|
#### Tâches (`tasks`)
|
|
69
61
|
|
|
70
62
|
Toutes les tâches données entre sessions et par Ledge.
|
|
71
|
-
- Filtres : « Toutes / Ouvertes / Closes », donneur,
|
|
63
|
+
- Filtres : « Toutes / Ouvertes / Closes », donneur, « Décisions ».
|
|
72
64
|
- Une tâche ouverte montre son résultat, sa raison et son historique.
|
|
73
65
|
- Une décision se tranche ici : « Répondre », puis « Envoyer la réponse », puis « Confirmer l'envoi ».
|
|
74
66
|
|
|
@@ -80,10 +72,8 @@ Les conversations du jour avec Ledge, chacune avec « Voir dans la conversation
|
|
|
80
72
|
|
|
81
73
|
### Atelier (`overview`)
|
|
82
74
|
|
|
83
|
-
On y vient par Échap depuis l'accueil ou une session, par « Retour à l'atelier », ou par la vue « Atelier » de la barre latérale. Chaque projet est une table, avec ses agents assis autour et leurs sous-agents en petits bots.
|
|
75
|
+
On y vient par Échap depuis l'accueil ou une session, par « Retour à l'atelier », ou par la vue « Atelier » de la barre latérale. Chaque projet est une table, avec ses agents assis autour et leurs sous-agents en petits bots.
|
|
84
76
|
- Le menu d'une table propose « Nouvelle session », « Modifier le projet » et « Isoler cette table ».
|
|
85
|
-
- Le menu d'une pièce propose « Nouvelle équipe ici… ».
|
|
86
|
-
- Le menu d'une équipe propose « Voir les tâches » et « Dissoudre l'équipe ».
|
|
87
77
|
- On range une session en la glissant sur une table.
|
|
88
78
|
- Le zoom se règle au clavier (+, −, 0) ou avec `Ctrl` + molette.
|
|
89
79
|
- Le bureau « Parler à Ledge » ouvre le chat ancré.
|
|
@@ -91,6 +81,19 @@ On y vient par Échap depuis l'accueil ou une session, par « Retour à l'atelie
|
|
|
91
81
|
|
|
92
82
|
Y renvoyer l'utilisateur pour avoir une vue d'ensemble de qui travaille où, ou pour ranger une session dans un projet.
|
|
93
83
|
|
|
84
|
+
### OpenRig (`openrig`)
|
|
85
|
+
|
|
86
|
+
On y vient par « OpenRig » dans la barre latérale, sous « Atelier ». La page pilote OpenRig sur une machine ; les puces du haut changent de machine.
|
|
87
|
+
- **Daemon :** « Démarrer », « Arrêter », « Redémarrer ». La case « Au démarrage, relancer les rigs qui tournaient » lance `rig start --last` ; « Sans le kernel » ajoute `--no-kernel`.
|
|
88
|
+
- **Kernel :** l'opérateur d'OpenRig (le rig nommé `kernel`), avec « Démarrer », « Arrêter », « Redémarrer ».
|
|
89
|
+
- **Rigs :** chaque rig montre son état, ses sièges et son dernier snapshot ; un clic sur son nom déplie ses sièges. « Démarrer » lance `rig up <rig> --existing`, « Arrêter » `rig down <rig>`, « Redémarrer » les deux avec un snapshot.
|
|
90
|
+
- **Permissions au lancement** : « Celle de la spec », « Auto » (mode auto de Claude), « Standard », « Ouvert », « YOLO » (aucune demande) ou « Verrouillé », pour tout le rig ; la colonne « Permissions » de la table change un rôle. Avec YOLO, « Accepter les avertissements de premier lancement » (`--non-interruptive`) évite qu'un siège s'arrête sur l'avertissement de Claude.
|
|
91
|
+
- **± Sièges** (rig en marche) : un compteur par rôle ajoute des copies du premier siège du rôle (`build-2`, `build-3`) ou retire les dernières, sans arrêter le rig. Les sièges ajoutés sont reliés par paires ou chacun à tous (OpenRig 0.7 et plus), puis un snapshot garde la nouvelle taille pour un redémarrage.
|
|
92
|
+
- Tout arrêt ou redémarrage demande confirmation, nomme les sièges qui travaillent et montre la commande `rig` lancée.
|
|
93
|
+
- **Lancer un rig…** : choisir une spec (« mes specs » ou celles d'OpenRig), le dossier de travail et le nom, le nombre de sièges par rôle avec leur harnais et leur modèle, puis comment les sièges ajoutés délèguent (par paires ou chacun à tous). « Vérifier » montre ce que `rig up --plan` conclut et la spec qui sera lancée ; « Lancer » la lance. Une spec modifiée est écrite dans `~/.ledge/rigs/<nom>/`, et « Enregistrer dans mes specs » la garde dans la bibliothèque OpenRig.
|
|
94
|
+
|
|
95
|
+
Y renvoyer l'utilisateur pour démarrer, arrêter ou redémarrer OpenRig, son kernel ou un rig, ou pour lancer un rig (par exemple trois développeurs et trois relecteurs), sur n'importe quelle machine.
|
|
96
|
+
|
|
94
97
|
### Session (`session`)
|
|
95
98
|
|
|
96
99
|
On l'ouvre en cliquant sur un siège, sur une ligne de la barre latérale ou sur un élément « À toi ». On y accède aussi par `Alt+1…9`, par `Alt+←/→`, ou par `Ctrl+K`. Un sous-agent a sa propre page.
|
|
@@ -170,10 +173,9 @@ S'ouvre par `?`. Liste complète des raccourcis.
|
|
|
170
173
|
#### Nouvelle session (`launch`)
|
|
171
174
|
|
|
172
175
|
S'ouvre par `N` dans l'atelier, `Ctrl+Alt+N` partout, « Nouvelle session » dans la barre latérale ou un menu de table.
|
|
173
|
-
- **Champs :** consigne, agent (Claude Code, Codex, Cursor Agent, OMP), modèle et effort, projet, machine, dossiers et dépôts
|
|
174
|
-
- **Mode équipe :** « Nouvelle équipe ». On choisit un modèle, ou des sièges un par un, et le nom de l'équipe.
|
|
176
|
+
- **Champs :** consigne, agent (Claude Code, Codex, Cursor Agent, OMP), modèle et effort, projet, machine, dossiers et dépôts.
|
|
175
177
|
|
|
176
|
-
Y renvoyer l'utilisateur pour lancer lui-même une session
|
|
178
|
+
Y renvoyer l'utilisateur pour lancer lui-même une session avec des réglages précis.
|
|
177
179
|
|
|
178
180
|
#### Projet (`project`)
|
|
179
181
|
|
|
@@ -185,7 +187,7 @@ Crée (« Nouveau projet »), modifie ou supprime un projet. On y donne son nom,
|
|
|
185
187
|
|
|
186
188
|
## Ledge mobile
|
|
187
189
|
|
|
188
|
-
Une application web pour le téléphone, avec
|
|
190
|
+
Une application web pour le téléphone, avec trois onglets en bas : « À traiter », « Agents », « Ledge ». Pour la lier :
|
|
189
191
|
1. Sur le PC, dans Réglages › Accès mobile, activer l'accès, choisir le relais et se connecter avec GitHub.
|
|
190
192
|
2. Sur le téléphone, ouvrir l'adresse du relais et se connecter avec le même compte.
|
|
191
193
|
3. Comparer le code affiché sur les deux appareils et approuver sur le PC.
|
|
@@ -196,11 +198,11 @@ Les demandes en attente, les plus anciennes d'abord, filtrées par type (autoris
|
|
|
196
198
|
|
|
197
199
|
### Agents (`agents`)
|
|
198
200
|
|
|
199
|
-
Les sessions par projet
|
|
201
|
+
Les sessions par projet. Une session ouvre son fil.
|
|
200
202
|
|
|
201
203
|
### Ledge (`chat`)
|
|
202
204
|
|
|
203
|
-
Le chat de Ledge sur le téléphone, avec « Le point ». Les cartes proposent une session
|
|
205
|
+
Le chat de Ledge sur le téléphone, avec « Le point ». Les cartes proposent une session ou une tâche. Cette conversation est propre au téléphone.
|
|
204
206
|
|
|
205
207
|
### Fil d'une session (`thread`)
|
|
206
208
|
|
|
@@ -218,30 +220,6 @@ Une demande seule : autorisation, question, plan ou modifications. On l'approuve
|
|
|
218
220
|
|
|
219
221
|
S'ouvre depuis l'état de la liaison en en-tête. On y voit le PC, le compte, le serveur et les empreintes, et on y règle l'apparence. « Le PC » met à jour ou redémarre le daemon du PC. On peut aussi s'y déconnecter.
|
|
220
222
|
|
|
221
|
-
### Équipes (`teams`)
|
|
222
|
-
|
|
223
|
-
Les équipes et les rôles. « Nouvelle équipe », « Nouveau rôle ». « Lever » lance une équipe dans un projet, après confirmation par passkey.
|
|
224
|
-
|
|
225
|
-
### Éditeur d'équipe (`team`)
|
|
226
|
-
|
|
227
|
-
Les sièges d'une équipe, où la ranger (maison ou dépôt), Enregistrer ou Supprimer.
|
|
228
|
-
|
|
229
|
-
### Copier une équipe (`team-copy`)
|
|
230
|
-
|
|
231
|
-
Enregistre la composition d'une équipe en cours comme nouvelle équipe.
|
|
232
|
-
|
|
233
|
-
### Éditeur de rôle (`role`)
|
|
234
|
-
|
|
235
|
-
Identifiant, libellé, consigne, et les valeurs par défaut : outil, modèle, effort, autonomie.
|
|
236
|
-
|
|
237
|
-
### Équipe en cours (`live`)
|
|
238
|
-
|
|
239
|
-
La fiche d'une équipe active : ses sièges, sa consigne, « Modifier la composition », « Enregistrer comme équipe », « Dissoudre l'équipe ».
|
|
240
|
-
|
|
241
|
-
### Composition (`compose`)
|
|
242
|
-
|
|
243
|
-
Modifier les sièges d'une équipe en cours, puis « Appliquer ».
|
|
244
|
-
|
|
245
223
|
### Écrans qui s'affichent d'eux-mêmes
|
|
246
224
|
|
|
247
225
|
Ces écrans ne sont pas des adresses : l'application les montre d'elle-même, selon l'état de la liaison avec le PC.
|
|
@@ -255,11 +233,10 @@ Ces écrans ne sont pas des adresses : l'application les montre d'elle-même, se
|
|
|
255
233
|
|---|---|
|
|
256
234
|
| répondre à un agent, voir ses modifications | Session (desktop), Demande ou Fil (mobile) |
|
|
257
235
|
| voir ce qui l'attend | « À toi » (desktop), À traiter (mobile) |
|
|
258
|
-
| lancer une session
|
|
236
|
+
| lancer une session lui-même | Nouvelle session (`N`, `Ctrl+Alt+N`) |
|
|
259
237
|
| créer, modifier ou supprimer un projet | Réglages › Projets, ou le menu d'une table |
|
|
260
238
|
| renommer, archiver, supprimer une session, passer le relais | Session › « Gérer la session » |
|
|
261
239
|
| trancher une décision, suivre une tâche | Accueil › Tâches |
|
|
262
|
-
| écrire un rôle ou un modèle d'équipe | Ses fichiers `.ledge/roles` et `.ledge/teams`, ou Équipes (mobile) |
|
|
263
240
|
| ajouter un serveur | Réglages › Machines |
|
|
264
241
|
| lier un téléphone | Réglages › Accès mobile |
|
|
265
242
|
| changer l'agent du chat | Réglages › Général › Agent par défaut |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paradow/ledge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
4
4
|
"description": "Follow and answer your WSL agent sessions (Claude Code, Codex, Cursor Agent) from the Ledge island on Windows.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": { "ledge": "dist/cli/index.js" },
|
|
@@ -19,9 +19,12 @@
|
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"ink": "7.1.1",
|
|
22
|
+
"jpeg-js": "^0.4.4",
|
|
23
|
+
"pngjs": "^7.0.0",
|
|
22
24
|
"react": "^19.3.0",
|
|
23
25
|
"string-width": "^8.3.0",
|
|
24
26
|
"ws": "^8.18.0",
|
|
27
|
+
"yaml": "2.8.1",
|
|
25
28
|
"zod": "^3.23.8"
|
|
26
29
|
},
|
|
27
30
|
"devDependencies": {
|
|
@@ -30,6 +33,7 @@
|
|
|
30
33
|
"@ledge/seal": "workspace:*",
|
|
31
34
|
"@ledge/ui": "workspace:*",
|
|
32
35
|
"@types/node": "^22.7.0",
|
|
36
|
+
"@types/pngjs": "^6.0.5",
|
|
33
37
|
"@types/react": "^19.3.0",
|
|
34
38
|
"@types/ws": "^8.5.12",
|
|
35
39
|
"ink-testing-library": "4.0.0",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CLOSE_USAGE,
|
|
3
|
-
DAEMON_DOWN,
|
|
4
|
-
RUN_MS,
|
|
5
|
-
actionArgs,
|
|
6
|
-
callerOf,
|
|
7
|
-
closeArgs,
|
|
8
|
-
resultLine,
|
|
9
|
-
runClose,
|
|
10
|
-
runOnClient
|
|
11
|
-
} from "./chunk-XOZD4BP5.js";
|
|
12
|
-
import "./chunk-JEGPTNWV.js";
|
|
13
|
-
import "./chunk-ASYAWVFW.js";
|
|
14
|
-
import "./chunk-WXE2NOE5.js";
|
|
15
|
-
import "./chunk-HOOHS3MX.js";
|
|
16
|
-
import "./chunk-U67V476Y.js";
|
|
17
|
-
export {
|
|
18
|
-
CLOSE_USAGE,
|
|
19
|
-
DAEMON_DOWN,
|
|
20
|
-
RUN_MS,
|
|
21
|
-
actionArgs,
|
|
22
|
-
callerOf,
|
|
23
|
-
closeArgs,
|
|
24
|
-
resultLine,
|
|
25
|
-
runClose,
|
|
26
|
-
runOnClient
|
|
27
|
-
};
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
attachEnv
|
|
3
|
-
} from "./chunk-CPERVAPQ.js";
|
|
4
|
-
import "./chunk-PZ3F4QH3.js";
|
|
5
|
-
import "./chunk-OLLQBK6N.js";
|
|
6
|
-
import "./chunk-NWIICISV.js";
|
|
7
|
-
import "./chunk-3DB3VOMM.js";
|
|
8
|
-
import "./chunk-4VNKZOC2.js";
|
|
9
|
-
import "./chunk-JEGPTNWV.js";
|
|
10
|
-
import {
|
|
11
|
-
connect
|
|
12
|
-
} from "./chunk-ASYAWVFW.js";
|
|
13
|
-
import {
|
|
14
|
-
PROTOCOL_PORT,
|
|
15
|
-
backendOf
|
|
16
|
-
} from "./chunk-WXE2NOE5.js";
|
|
17
|
-
import "./chunk-E3LXONBI.js";
|
|
18
|
-
import {
|
|
19
|
-
realTmux
|
|
20
|
-
} from "./chunk-NLL2EQJ2.js";
|
|
21
|
-
import "./chunk-6IYPRUQG.js";
|
|
22
|
-
import "./chunk-HOOHS3MX.js";
|
|
23
|
-
import "./chunk-U67V476Y.js";
|
|
24
|
-
|
|
25
|
-
// src/cli/attach.ts
|
|
26
|
-
import { spawn } from "child_process";
|
|
27
|
-
var TMUX_SOCKET = "ledge";
|
|
28
|
-
function attachInherit(args, env) {
|
|
29
|
-
return new Promise((resolve) => {
|
|
30
|
-
const child = spawn("tmux", args, { stdio: "inherit", env });
|
|
31
|
-
child.on("error", () => resolve(1));
|
|
32
|
-
child.on("exit", (c) => resolve(c ?? 1));
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
async function nativeSession(id, port) {
|
|
36
|
-
try {
|
|
37
|
-
const c = await connect({ port, timeoutMs: 800 });
|
|
38
|
-
const snap = await c.next("snapshot");
|
|
39
|
-
await Promise.race([c.close(), new Promise((r) => setTimeout(r, 500))]);
|
|
40
|
-
const s = snap.sessions.find((x) => x.id === id);
|
|
41
|
-
return s && backendOf(s) === "omp-rpc" ? s.name : null;
|
|
42
|
-
} catch {
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
async function attach(id, opts = {}) {
|
|
47
|
-
if (!id) {
|
|
48
|
-
console.error("ledge attach: missing session id");
|
|
49
|
-
return 2;
|
|
50
|
-
}
|
|
51
|
-
const tmux = realTmux(opts.tmuxSocket ?? TMUX_SOCKET);
|
|
52
|
-
const tmuxName = `ledge-${id}`;
|
|
53
|
-
if (!await tmux.hasSession(tmuxName)) {
|
|
54
|
-
const native = await nativeSession(id, opts.port ?? PROTOCOL_PORT);
|
|
55
|
-
console.error(native ? `ledge attach: ${native} is driven by Ledge over OMP's own protocol: there is no terminal to attach to (open a shell from the app)` : `ledge attach: no session ${id}`);
|
|
56
|
-
return 1;
|
|
57
|
-
}
|
|
58
|
-
let title = tmuxName;
|
|
59
|
-
try {
|
|
60
|
-
const c = await connect({ port: opts.port ?? PROTOCOL_PORT, timeoutMs: 800 });
|
|
61
|
-
const snap = await c.next("snapshot");
|
|
62
|
-
title = snap.sessions.find((s) => s.id === id)?.title ?? title;
|
|
63
|
-
await Promise.race([c.close(), new Promise((r) => setTimeout(r, 500))]);
|
|
64
|
-
} catch {
|
|
65
|
-
}
|
|
66
|
-
const write = opts.write ?? ((s) => {
|
|
67
|
-
if (process.stdout.isTTY) process.stdout.write(s);
|
|
68
|
-
});
|
|
69
|
-
write(`\x1B]0;${title}\x07`);
|
|
70
|
-
return (opts.attach ?? attachInherit)(tmux.attachArgs(tmuxName, { readOnly: opts.readOnly }), attachEnv(process.env));
|
|
71
|
-
}
|
|
72
|
-
export {
|
|
73
|
-
attach
|
|
74
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MAX_FRAME,
|
|
3
|
-
readFrames
|
|
4
|
-
} from "./chunk-OLLQBK6N.js";
|
|
5
|
-
import {
|
|
6
|
-
PROTOCOL_PORT,
|
|
7
|
-
parseClientMessage,
|
|
8
|
-
parseServerMessage,
|
|
9
|
-
readDaemonToken
|
|
10
|
-
} from "./chunk-WXE2NOE5.js";
|
|
11
|
-
import "./chunk-HOOHS3MX.js";
|
|
12
|
-
import "./chunk-U67V476Y.js";
|
|
13
|
-
|
|
14
|
-
// src/cli/bridge.ts
|
|
15
|
-
import WebSocket from "ws";
|
|
16
|
-
function bearerHeaders() {
|
|
17
|
-
const token = readDaemonToken();
|
|
18
|
-
return token ? { authorization: `Bearer ${token}` } : {};
|
|
19
|
-
}
|
|
20
|
-
function bridge(opts = {}) {
|
|
21
|
-
const input = opts.input ?? process.stdin, output = opts.output ?? process.stdout;
|
|
22
|
-
const ws = new WebSocket(`ws://127.0.0.1:${opts.port ?? PROTOCOL_PORT}`, { maxPayload: MAX_FRAME, handshakeTimeout: 1e4, headers: bearerHeaders() });
|
|
23
|
-
return new Promise((resolve, reject) => {
|
|
24
|
-
let settled = false, off = () => {
|
|
25
|
-
};
|
|
26
|
-
const finish = (error) => {
|
|
27
|
-
if (settled) return;
|
|
28
|
-
settled = true;
|
|
29
|
-
off();
|
|
30
|
-
input.pause();
|
|
31
|
-
input.off("end", end);
|
|
32
|
-
input.off("error", fail);
|
|
33
|
-
output.off("error", fail);
|
|
34
|
-
output.off("drain", drain);
|
|
35
|
-
ws.terminate();
|
|
36
|
-
error ? reject(error) : resolve();
|
|
37
|
-
};
|
|
38
|
-
const fail = (e) => finish(e);
|
|
39
|
-
const end = () => ws.close();
|
|
40
|
-
const drain = () => ws.resume();
|
|
41
|
-
input.on("error", fail);
|
|
42
|
-
output.on("error", fail);
|
|
43
|
-
output.on("drain", drain);
|
|
44
|
-
ws.on("open", () => {
|
|
45
|
-
off = readFrames(input, (raw) => {
|
|
46
|
-
const msg = parseClientMessage(raw);
|
|
47
|
-
if (msg.type === "machines.set" || msg.type === "projects.set" || msg.type === "island.set") return;
|
|
48
|
-
if (ws.bufferedAmount > MAX_FRAME) throw new Error("Ledge bridge is overloaded");
|
|
49
|
-
ws.send(JSON.stringify(msg));
|
|
50
|
-
}, fail);
|
|
51
|
-
input.on("end", end);
|
|
52
|
-
if (input.readableEnded) end();
|
|
53
|
-
});
|
|
54
|
-
ws.on("message", (data) => {
|
|
55
|
-
try {
|
|
56
|
-
const msg = parseServerMessage(JSON.parse(String(data)));
|
|
57
|
-
if (msg.type === "machines" || msg.type === "projects" || msg.type === "island") return;
|
|
58
|
-
if (!output.write(`${JSON.stringify(msg)}
|
|
59
|
-
`)) ws.pause();
|
|
60
|
-
} catch (e) {
|
|
61
|
-
fail(e);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
ws.on("error", fail);
|
|
65
|
-
ws.on("close", (code) => finish(code === 1e3 || code === 1005 ? void 0 : new Error(`Ledge daemon disconnected (${code})`)));
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
export {
|
|
69
|
-
bridge
|
|
70
|
-
};
|