linkshell-cli 0.2.126 → 0.3.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.
@@ -21,7 +21,6 @@ import { getLanIp } from "../utils/lan-ip.js";
21
21
  import { startKeepAwake, type KeepAwakeHandle } from "../utils/keep-awake.js";
22
22
  import { loadOrCreateMachineIdentity, type MachineIdentity } from "../machine-id.js";
23
23
  import { getValidToken } from "../auth.js";
24
- import { AgentSessionProxy } from "./acp/agent-session.js";
25
24
  import { AgentWorkspaceProxy } from "./acp/agent-workspace.js";
26
25
  import { detectAvailableProviders, type AgentProvider } from "./acp/provider-resolver.js";
27
26
 
@@ -137,7 +136,6 @@ export class BridgeSession {
137
136
  private screenShare: ScreenShare | undefined;
138
137
  private tunnelSockets = new Map<string, WebSocket>();
139
138
  private keepAwake: KeepAwakeHandle | undefined;
140
- private agentSession: AgentSessionProxy | undefined;
141
139
  private agentWorkspace: AgentWorkspaceProxy | undefined;
142
140
  private machineIdentity: MachineIdentity | undefined;
143
141
 
@@ -169,16 +167,13 @@ export class BridgeSession {
169
167
  ? [normalizeAgentProvider(this.options.agentProvider)]
170
168
  : detectAvailableProviders();
171
169
  const agentOptions = {
172
- sessionId: this.sessionId,
170
+ hostDeviceId: this.sessionId,
173
171
  cwd: process.cwd(),
174
172
  availableProviders,
175
173
  command: this.options.agentCommand,
176
174
  verbose: this.options.verbose,
177
175
  send: (envelope: Envelope) => this.send(envelope),
178
176
  };
179
- this.agentSession = new AgentSessionProxy({
180
- ...agentOptions,
181
- });
182
177
  this.agentWorkspace = new AgentWorkspaceProxy({
183
178
  ...agentOptions,
184
179
  });
@@ -374,7 +369,7 @@ export class BridgeSession {
374
369
  if (existing) {
375
370
  this.send(createEnvelope({
376
371
  type: "terminal.spawned",
377
- sessionId: this.sessionId,
372
+ hostDeviceId: this.sessionId,
378
373
  terminalId: existing.id,
379
374
  payload: { terminalId: existing.id, cwd: existing.cwd, shell: this.options.providerConfig.command },
380
375
  }));
@@ -384,7 +379,7 @@ export class BridgeSession {
384
379
  await this.spawnTerminal(newId, normalizedCwd);
385
380
  this.send(createEnvelope({
386
381
  type: "terminal.spawned",
387
- sessionId: this.sessionId,
382
+ hostDeviceId: this.sessionId,
388
383
  terminalId: newId,
389
384
  payload: { terminalId: newId, cwd: normalizedCwd, shell: this.options.providerConfig.command },
390
385
  }));
@@ -392,7 +387,7 @@ export class BridgeSession {
392
387
  this.log(`failed to spawn terminal ${newId}: ${err}`);
393
388
  this.send(createEnvelope({
394
389
  type: "terminal.exit",
395
- sessionId: this.sessionId,
390
+ hostDeviceId: this.sessionId,
396
391
  terminalId: newId,
397
392
  payload: { exitCode: 1, signal: 0 },
398
393
  }));
@@ -434,13 +429,13 @@ export class BridgeSession {
434
429
  });
435
430
  this.send(createEnvelope({
436
431
  type: "terminal.browse.result",
437
- sessionId: this.sessionId,
432
+ hostDeviceId: this.sessionId,
438
433
  payload: { path: browsePath, entries, requestId: p.requestId },
439
434
  }));
440
435
  } catch (err: unknown) {
441
436
  this.send(createEnvelope({
442
437
  type: "terminal.browse.result",
443
- sessionId: this.sessionId,
438
+ hostDeviceId: this.sessionId,
444
439
  payload: { path: browsePath, entries: [], error: (err as Error).message, requestId: p.requestId },
445
440
  }));
446
441
  }
@@ -469,7 +464,7 @@ export class BridgeSession {
469
464
  }
470
465
  this.send(createEnvelope({
471
466
  type: "terminal.file.read.result",
472
- sessionId: this.sessionId,
467
+ hostDeviceId: this.sessionId,
473
468
  payload: {
474
469
  path: filePath,
475
470
  content: buffer.toString("utf8"),
@@ -482,7 +477,7 @@ export class BridgeSession {
482
477
  } catch (err: unknown) {
483
478
  this.send(createEnvelope({
484
479
  type: "terminal.file.read.result",
485
- sessionId: this.sessionId,
480
+ hostDeviceId: this.sessionId,
486
481
  payload: {
487
482
  path: filePath,
488
483
  content: "",
@@ -513,13 +508,13 @@ export class BridgeSession {
513
508
  }));
514
509
  this.send(createEnvelope({
515
510
  type: "terminal.browse.result",
516
- sessionId: this.sessionId,
511
+ hostDeviceId: this.sessionId,
517
512
  payload: { path: parentPath, entries },
518
513
  }));
519
514
  } catch (err: unknown) {
520
515
  this.send(createEnvelope({
521
516
  type: "terminal.browse.result",
522
- sessionId: this.sessionId,
517
+ hostDeviceId: this.sessionId,
523
518
  payload: { path: dirPath, entries: [], error: (err as Error).message },
524
519
  }));
525
520
  }
@@ -560,23 +555,21 @@ export class BridgeSession {
560
555
  } catch {}
561
556
  this.send(createEnvelope({
562
557
  type: "terminal.history.response",
563
- sessionId: this.sessionId,
558
+ hostDeviceId: this.sessionId,
564
559
  payload: { entries, shell },
565
560
  }));
566
561
  break;
567
562
  }
568
- case "device.ack":
569
- case "session.ack": {
570
- const p = parseTypedPayload(envelope.type === "device.ack" ? "device.ack" : "session.ack", envelope.payload);
563
+ case "device.ack": {
564
+ const p = parseTypedPayload("device.ack", envelope.payload);
571
565
  const term = this.terminals.get(tid);
572
566
  if (term) {
573
567
  term.scrollback.trimUpTo(p.seq);
574
568
  }
575
569
  break;
576
570
  }
577
- case "device.resume":
578
- case "session.resume": {
579
- const p = parseTypedPayload(envelope.type === "device.resume" ? "device.resume" : "session.resume", envelope.payload);
571
+ case "device.resume": {
572
+ const p = parseTypedPayload("device.resume", envelope.payload);
580
573
  // Replay all terminals
581
574
  for (const [termId, term] of this.terminals) {
582
575
  this.replayFrom(
@@ -590,7 +583,6 @@ export class BridgeSession {
590
583
  break;
591
584
  }
592
585
  case "device.heartbeat":
593
- case "session.heartbeat":
594
586
  break;
595
587
  case "screen.start": {
596
588
  const p = parseTypedPayload("screen.start", envelope.payload);
@@ -611,67 +603,6 @@ export class BridgeSession {
611
603
  this.screenShare?.handleIceCandidate(p.candidate, p.sdpMid, p.sdpMLineIndex);
612
604
  break;
613
605
  }
614
- case "agent.initialize":
615
- case "agent.session.new":
616
- case "agent.session.load":
617
- case "agent.session.list":
618
- case "agent.prompt":
619
- case "agent.cancel": {
620
- if (!this.agentSession) {
621
- this.send(
622
- createEnvelope({
623
- type: "agent.capabilities",
624
- sessionId: this.sessionId,
625
- payload: {
626
- enabled: false,
627
- provider: normalizeAgentProvider(
628
- this.options.agentProvider ?? "codex",
629
- ),
630
- machineId: this.machineIdentity?.machineId,
631
- error: "Agent GUI is not enabled. Start CLI with --agent-ui.",
632
- supportsSessionList: false,
633
- supportsSessionLoad: false,
634
- supportsImages: false,
635
- supportsAudio: false,
636
- supportsPermission: false,
637
- supportsPlan: false,
638
- supportsCancel: false,
639
- },
640
- }),
641
- );
642
- break;
643
- }
644
- await this.agentSession.handleEnvelope(envelope);
645
- break;
646
- }
647
- case "agent.permission.response": {
648
- if (!this.agentSession) {
649
- this.send(
650
- createEnvelope({
651
- type: "agent.capabilities",
652
- sessionId: this.sessionId,
653
- payload: {
654
- enabled: false,
655
- provider: normalizeAgentProvider(
656
- this.options.agentProvider ?? "codex",
657
- ),
658
- machineId: this.machineIdentity?.machineId,
659
- error: "Agent GUI is not enabled. Start CLI with --agent-ui.",
660
- supportsSessionList: false,
661
- supportsSessionLoad: false,
662
- supportsImages: false,
663
- supportsAudio: false,
664
- supportsPermission: false,
665
- supportsPlan: false,
666
- supportsCancel: false,
667
- },
668
- }),
669
- );
670
- break;
671
- }
672
- await this.agentSession.handleEnvelope(envelope);
673
- break;
674
- }
675
606
  case "agent.v2.capabilities.request":
676
607
  case "agent.v2.conversation.open":
677
608
  case "agent.v2.conversation.list":
@@ -685,7 +616,7 @@ export class BridgeSession {
685
616
  this.send(
686
617
  createEnvelope({
687
618
  type: "agent.v2.capabilities",
688
- sessionId: this.sessionId,
619
+ hostDeviceId: this.sessionId,
689
620
  payload: {
690
621
  enabled: false,
691
622
  provider: normalizeAgentProvider(
@@ -782,7 +713,7 @@ export class BridgeSession {
782
713
  this.send(
783
714
  createEnvelope({
784
715
  type: "tunnel.response",
785
- sessionId: this.sessionId,
716
+ hostDeviceId: this.sessionId,
786
717
  payload: {
787
718
  requestId,
788
719
  statusCode: proxyRes.statusCode ?? 200,
@@ -799,7 +730,7 @@ export class BridgeSession {
799
730
  this.send(
800
731
  createEnvelope({
801
732
  type: "tunnel.response",
802
- sessionId: this.sessionId,
733
+ hostDeviceId: this.sessionId,
803
734
  payload: {
804
735
  requestId,
805
736
  statusCode: proxyRes.statusCode ?? 200,
@@ -845,7 +776,7 @@ export class BridgeSession {
845
776
  this.send(
846
777
  createEnvelope({
847
778
  type: "tunnel.ws.data",
848
- sessionId: this.sessionId,
779
+ hostDeviceId: this.sessionId,
849
780
  payload: {
850
781
  requestId,
851
782
  data: buf.toString("base64"),
@@ -861,7 +792,7 @@ export class BridgeSession {
861
792
  this.send(
862
793
  createEnvelope({
863
794
  type: "tunnel.ws.close",
864
- sessionId: this.sessionId,
795
+ hostDeviceId: this.sessionId,
865
796
  payload: {
866
797
  requestId,
867
798
  code: safeCode,
@@ -876,7 +807,7 @@ export class BridgeSession {
876
807
  this.send(
877
808
  createEnvelope({
878
809
  type: "tunnel.ws.close",
879
- sessionId: this.sessionId,
810
+ hostDeviceId: this.sessionId,
880
811
  payload: {
881
812
  requestId,
882
813
  code: 1001,
@@ -914,7 +845,7 @@ export class BridgeSession {
914
845
  this.send(
915
846
  createEnvelope({
916
847
  type: "tunnel.response",
917
- sessionId: this.sessionId,
848
+ hostDeviceId: this.sessionId,
918
849
  payload: {
919
850
  requestId,
920
851
  statusCode,
@@ -935,7 +866,7 @@ export class BridgeSession {
935
866
  }));
936
867
  this.send(createEnvelope({
937
868
  type: "terminal.list",
938
- sessionId: this.sessionId,
869
+ hostDeviceId: this.sessionId,
939
870
  payload: { terminals },
940
871
  }));
941
872
  }
@@ -953,7 +884,7 @@ export class BridgeSession {
953
884
  this.send(
954
885
  createEnvelope({
955
886
  type: "terminal.output",
956
- sessionId: this.sessionId,
887
+ hostDeviceId: this.sessionId,
957
888
  terminalId,
958
889
  seq: msg.seq,
959
890
  payload: { ...payload, isReplay: true },
@@ -993,7 +924,7 @@ export class BridgeSession {
993
924
  const seq = term.outputSeq++;
994
925
  const envelope = createEnvelope({
995
926
  type: "terminal.output",
996
- sessionId: this.sessionId,
927
+ hostDeviceId: this.sessionId,
997
928
  terminalId,
998
929
  seq,
999
930
  payload: {
@@ -1012,7 +943,7 @@ export class BridgeSession {
1012
943
  term.status = "exited";
1013
944
  this.send(createEnvelope({
1014
945
  type: "terminal.exit",
1015
- sessionId: this.sessionId,
946
+ hostDeviceId: this.sessionId,
1016
947
  terminalId,
1017
948
  payload: { exitCode, signal },
1018
949
  }));
@@ -1040,8 +971,6 @@ export class BridgeSession {
1040
971
  }
1041
972
  const machineId = this.machineIdentity?.machineId;
1042
973
  const enriched = machineId && (
1043
- message.type === "agent.capabilities" ||
1044
- message.type === "agent.snapshot" ||
1045
974
  message.type === "agent.v2.capabilities" ||
1046
975
  message.type === "agent.v2.snapshot"
1047
976
  )
@@ -1082,7 +1011,7 @@ export class BridgeSession {
1082
1011
  this.send(
1083
1012
  createEnvelope({
1084
1013
  type: "screen.status",
1085
- sessionId: this.sessionId,
1014
+ hostDeviceId: this.sessionId,
1086
1015
  payload: { active: false, mode: "off" as const, error: "Screen sharing not enabled on host. Start CLI with --screen flag." },
1087
1016
  }),
1088
1017
  );
@@ -1095,7 +1024,7 @@ export class BridgeSession {
1095
1024
  if (ScreenShare.isAvailable()) {
1096
1025
  this.log("WebRTC available, starting screen share");
1097
1026
  this.screenShare = new ScreenShare({
1098
- sessionId: this.sessionId,
1027
+ hostDeviceId: this.sessionId,
1099
1028
  fps,
1100
1029
  quality,
1101
1030
  scale,
@@ -1118,7 +1047,7 @@ export class BridgeSession {
1118
1047
  fps,
1119
1048
  quality,
1120
1049
  scale,
1121
- sessionId: this.sessionId,
1050
+ hostDeviceId: this.sessionId,
1122
1051
  onFrame: (envelope) => this.send(envelope),
1123
1052
  onStatus: (envelope) => this.send(envelope),
1124
1053
  });
@@ -1177,8 +1106,6 @@ export class BridgeSession {
1177
1106
  this.exited = true;
1178
1107
  this.stopHeartbeat();
1179
1108
  this.stopScreenCapture();
1180
- this.agentSession?.stop();
1181
- this.agentSession = undefined;
1182
1109
  this.agentWorkspace?.stop();
1183
1110
  this.agentWorkspace = undefined;
1184
1111
  this.keepAwake?.stop();
@@ -10,7 +10,7 @@ export interface ScreenFallbackOptions {
10
10
  fps: number;
11
11
  quality: number;
12
12
  scale: number;
13
- sessionId: string;
13
+ hostDeviceId: string;
14
14
  onFrame: (envelope: Envelope) => void;
15
15
  onStatus: (envelope: Envelope) => void;
16
16
  }
@@ -38,7 +38,7 @@ export class ScreenFallback {
38
38
  this.options.onStatus(
39
39
  createEnvelope({
40
40
  type: "screen.status",
41
- sessionId: this.options.sessionId,
41
+ hostDeviceId: this.options.hostDeviceId,
42
42
  payload: { active: true, mode: "fallback" as const },
43
43
  }),
44
44
  );
@@ -64,7 +64,7 @@ export class ScreenFallback {
64
64
  this.options.onStatus(
65
65
  createEnvelope({
66
66
  type: "screen.status",
67
- sessionId: this.options.sessionId,
67
+ hostDeviceId: this.options.hostDeviceId,
68
68
  payload: { active: false, mode: "off" as const },
69
69
  }),
70
70
  );
@@ -88,7 +88,7 @@ export class ScreenFallback {
88
88
  this.options.onFrame(
89
89
  createEnvelope({
90
90
  type: "screen.frame",
91
- sessionId: this.options.sessionId,
91
+ hostDeviceId: this.options.hostDeviceId,
92
92
  payload: {
93
93
  data: base64,
94
94
  width: dims.width,
@@ -108,7 +108,7 @@ export class ScreenFallback {
108
108
  this.options.onFrame(
109
109
  createEnvelope({
110
110
  type: "screen.frame",
111
- sessionId: this.options.sessionId,
111
+ hostDeviceId: this.options.hostDeviceId,
112
112
  payload: {
113
113
  data: chunk,
114
114
  width: dims.width,
@@ -22,7 +22,7 @@ function detectMacScreenIndex(): string {
22
22
  }
23
23
 
24
24
  export interface ScreenShareOptions {
25
- sessionId: string;
25
+ hostDeviceId: string;
26
26
  fps: number;
27
27
  quality: number;
28
28
  scale: number;
@@ -111,7 +111,7 @@ export class ScreenShare {
111
111
  this.options.onSignal(
112
112
  createEnvelope({
113
113
  type: "screen.ice",
114
- sessionId: this.options.sessionId,
114
+ hostDeviceId: this.options.hostDeviceId,
115
115
  payload: {
116
116
  candidate: candidate.candidate,
117
117
  sdpMid: candidate.sdpMid ?? null,
@@ -128,7 +128,7 @@ export class ScreenShare {
128
128
  this.options.onStatus(
129
129
  createEnvelope({
130
130
  type: "screen.status",
131
- sessionId: this.options.sessionId,
131
+ hostDeviceId: this.options.hostDeviceId,
132
132
  payload: { active: true, mode: "webrtc" as const },
133
133
  }),
134
134
  );
@@ -136,7 +136,7 @@ export class ScreenShare {
136
136
  this.options.onStatus(
137
137
  createEnvelope({
138
138
  type: "screen.status",
139
- sessionId: this.options.sessionId,
139
+ hostDeviceId: this.options.hostDeviceId,
140
140
  payload: { active: false, mode: "off" as const, error: `WebRTC ${state}` },
141
141
  }),
142
142
  );
@@ -152,7 +152,7 @@ export class ScreenShare {
152
152
  this.options.onStatus(
153
153
  createEnvelope({
154
154
  type: "screen.status",
155
- sessionId: this.options.sessionId,
155
+ hostDeviceId: this.options.hostDeviceId,
156
156
  payload: { active: true, mode: "webrtc" as const },
157
157
  }),
158
158
  );
@@ -160,7 +160,7 @@ export class ScreenShare {
160
160
  this.options.onSignal(
161
161
  createEnvelope({
162
162
  type: "screen.offer",
163
- sessionId: this.options.sessionId,
163
+ hostDeviceId: this.options.hostDeviceId,
164
164
  payload: { sdp: offer.sdp },
165
165
  }),
166
166
  );
@@ -172,7 +172,7 @@ export class ScreenShare {
172
172
  this.options.onStatus(
173
173
  createEnvelope({
174
174
  type: "screen.status",
175
- sessionId: this.options.sessionId,
175
+ hostDeviceId: this.options.hostDeviceId,
176
176
  payload: {
177
177
  active: false,
178
178
  mode: "off" as const,
@@ -221,7 +221,7 @@ export class ScreenShare {
221
221
  this.options.onStatus(
222
222
  createEnvelope({
223
223
  type: "screen.status",
224
- sessionId: this.options.sessionId,
224
+ hostDeviceId: this.options.hostDeviceId,
225
225
  payload: { active: false, mode: "off" as const },
226
226
  }),
227
227
  );