alink-cli 0.8.6 → 0.8.8

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/bin.mjs CHANGED
@@ -51996,12 +51996,20 @@ const makeWsRpcLayer = (currentSession) => WsRpcGroup.toLayer(gen(function* () {
51996
51996
  return startup.enqueueCommand(dispatchEffect).pipe(mapError((cause) => toDispatchCommandError(cause, "Failed to dispatch orchestration command")));
51997
51997
  };
51998
51998
  const loadServerConfig = gen(function* () {
51999
+ console.error("[DEBUG-provider-checking-20260820] getConfig start");
51999
52000
  const keybindingsConfig = yield* keybindings.loadConfigState;
52001
+ console.error("[DEBUG-provider-checking-20260820] getConfig keybindings");
52000
52002
  const providers = yield* providerRegistry.getProviders;
52003
+ console.error("[DEBUG-provider-checking-20260820] getConfig providers");
52001
52004
  const settings = redactServerSettingsForClient(yield* serverSettings.getSettings);
52005
+ console.error("[DEBUG-provider-checking-20260820] getConfig settings");
52006
+ const environment = yield* serverEnvironment.getDescriptor;
52007
+ console.error("[DEBUG-provider-checking-20260820] getConfig environment");
52008
+ const auth = yield* serverAuth.getDescriptor();
52009
+ console.error("[DEBUG-provider-checking-20260820] getConfig auth");
52002
52010
  return {
52003
- environment: yield* serverEnvironment.getDescriptor,
52004
- auth: yield* serverAuth.getDescriptor(),
52011
+ environment,
52012
+ auth,
52005
52013
  cwd: config.cwd,
52006
52014
  keybindingsConfigPath: config.keybindingsConfigPath,
52007
52015
  keybindings: keybindingsConfig.keybindings,
@@ -52350,6 +52358,37 @@ function isEnvelope(value) {
52350
52358
  //#endregion
52351
52359
  //#region src/tunnel/bridge.ts
52352
52360
  const TUNNEL_SCOPES = [AuthOrchestrationReadScope, AuthOrchestrationOperateScope];
52361
+ function machineIdFromToken(token) {
52362
+ const parts = token.split(".");
52363
+ if (parts.length !== 3 || parts[0] !== "al1" || !parts[1]) return null;
52364
+ try {
52365
+ const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString("utf8"));
52366
+ return typeof payload.mid === "string" && payload.mid.length > 0 ? payload.mid : null;
52367
+ } catch {
52368
+ return null;
52369
+ }
52370
+ }
52371
+ function hubHttpUrl(hub) {
52372
+ const url = new URL(hub);
52373
+ url.protocol = url.protocol === "wss:" ? "https:" : "http:";
52374
+ url.pathname = "";
52375
+ url.search = "";
52376
+ url.hash = "";
52377
+ return url.toString().replace(/\/$/, "");
52378
+ }
52379
+ const uploadHubEnckey = (config) => gen(function* () {
52380
+ const machineId = machineIdFromToken(config.machineToken);
52381
+ if (!machineId) return yield* fail(/* @__PURE__ */ new Error("machine id is missing from the machine token"));
52382
+ const httpClient = yield* HttpClient;
52383
+ const request = yield* post$1(`${hubHttpUrl(config.hubUrl)}/api/machines/${encodeURIComponent(machineId)}/enckey`).pipe(setHeaders({
52384
+ authorization: `Bearer ${config.machineToken}`,
52385
+ "content-type": "application/json",
52386
+ "x-requested-with": "agentlink"
52387
+ }), bodyJson({ enckey: config.enckey }));
52388
+ yield* filterStatusOk(yield* httpClient.execute(request));
52389
+ return machineId;
52390
+ });
52391
+ const hubFrameDecoder = new TextDecoder();
52353
52392
  const ResponseDefectEncoded = (cause) => ({
52354
52393
  _tag: "Defect",
52355
52394
  defect: cause instanceof Error ? {
@@ -52386,17 +52425,30 @@ const makeTunnelSocketProtocol = gen(function* () {
52386
52425
  };
52387
52426
  clients.set(id, { write });
52388
52427
  clientIds.add(id);
52428
+ console.error("[DEBUG-provider-checking-20260820] rpc socket ready", { clientId: id });
52389
52429
  yield* socket.runRaw((data) => {
52390
52430
  try {
52431
+ console.error("[DEBUG-provider-checking-20260820] rpc input", { byteLength: typeof data === "string" ? data.length : data.byteLength });
52391
52432
  const decoded = parser.decode(data);
52433
+ console.error("[DEBUG-provider-checking-20260820] rpc decoded", {
52434
+ count: decoded.length,
52435
+ messages: decoded.map((item) => typeof item === "object" && item !== null ? {
52436
+ tag: "tag" in item ? String(item.tag) : void 0,
52437
+ id: "id" in item ? String(item.id) : void 0
52438
+ } : { type: typeof item })
52439
+ });
52392
52440
  if (decoded.length === 0) return void_$1;
52393
52441
  let i = 0;
52394
52442
  return whileLoop({
52395
52443
  while: () => i < decoded.length,
52396
- body: () => writeRequest(id, decoded[i++]),
52444
+ body: () => {
52445
+ console.error("[DEBUG-provider-checking-20260820] rpc dispatch", { clientId: id });
52446
+ return writeRequest(id, decoded[i++]);
52447
+ },
52397
52448
  step: () => void 0
52398
52449
  });
52399
52450
  } catch (cause) {
52451
+ console.error("[DEBUG-provider-checking-20260820] rpc decode error", { message: cause instanceof Error ? cause.message : String(cause) });
52400
52452
  if (isTagged(cause, "MaxBufferSizeExceeded")) return orDie(writeRaw(new CloseEvent(1009, String(cause))));
52401
52453
  const defect = parser.encode(ResponseDefectEncoded(cause));
52402
52454
  return defect === void 0 ? void_$1 : orDie(writeRaw(defect));
@@ -52433,6 +52485,12 @@ const splitHubFrame = (text) => {
52433
52485
  rest: text.slice(spaceAt + 1)
52434
52486
  };
52435
52487
  };
52488
+ function isHttpTunnelRequestFrame(value) {
52489
+ return typeof value === "object" && value !== null && value._tag === "HttpRequest" && typeof value.id === "string" && typeof value.method === "string" && typeof value.path === "string" && Array.isArray(value.headers) && (value.body === null || typeof value.body === "string");
52490
+ }
52491
+ function encodeHttpTunnelResponseFrame(frame) {
52492
+ return JSON.stringify(frame);
52493
+ }
52436
52494
  const makeTunnelSocket = (input) => {
52437
52495
  const runRaw = (handler, options) => scopedWith((scope) => gen(function* () {
52438
52496
  const fiberSet = yield* make$62().pipe(provide$2(scope));
@@ -52449,18 +52507,33 @@ const makeTunnelSocket = (input) => {
52449
52507
  return make$63({
52450
52508
  runRaw,
52451
52509
  writer: sync(() => (chunk) => sync(() => {
52452
- if (typeof chunk === "string") input.sendEncrypted(JSON.stringify(utf8ToEnvelope(input.enckey, chunk)));
52510
+ if (typeof chunk === "string") {
52511
+ console.error("[DEBUG-provider-checking-20260820] rpc outbound", { byteLength: chunk.length });
52512
+ input.sendEncrypted(JSON.stringify(utf8ToEnvelope(input.enckey, chunk)));
52513
+ }
52453
52514
  }))
52454
52515
  });
52455
52516
  };
52456
52517
  const runHubTunnel = (config) => gen(function* () {
52457
52518
  const serverAuth = yield* EnvironmentAuth;
52458
52519
  const sessionsStore = yield* SessionStore;
52520
+ const serverConfig = yield* ServerConfig;
52521
+ const httpClient = yield* HttpClient;
52459
52522
  yield* retry(gen(function* () {
52460
52523
  yield* logInfo("hub tunnel: connection effect entered");
52461
52524
  const url = `${config.hubUrl.replace(/\/+$/, "")}/daemon-tunnel?token=${encodeURIComponent(config.machineToken)}&v=1`;
52462
52525
  yield* logInfo("hub tunnel: connecting", { hubUrl: config.hubUrl });
52463
52526
  const socket = yield* makeWebSocket(url).pipe(provide$1(layerWebSocketConstructor));
52527
+ const upload = gen(function* () {
52528
+ const machineId = machineIdFromToken(config.machineToken);
52529
+ if (!machineId) {
52530
+ yield* logWarning$1("[daemon] enckey upload skipped: machine id missing from token");
52531
+ return;
52532
+ }
52533
+ yield* logInfo(`[daemon] uploading enckey for machine ${machineId}...`);
52534
+ yield* uploadHubEnckey(config);
52535
+ yield* logInfo("[daemon] enckey uploaded to hub for cross-device recovery");
52536
+ }).pipe(provideService(HttpClient, httpClient), catch_((error) => logError(`[daemon] enckey upload failed: ${String(error)}`)), asVoid);
52464
52537
  yield* addFinalizer((exit) => logInfo("hub tunnel: connection scope closing", { exit: String(exit) }));
52465
52538
  const tunnels = /* @__PURE__ */ new Map();
52466
52539
  const dropTunnel = (tunnelId) => {
@@ -52478,7 +52551,7 @@ const runHubTunnel = (config) => gen(function* () {
52478
52551
  const writeRaw = yield* socket.writer;
52479
52552
  yield* forever(take$1(outbox).pipe(flatMap$1(writeRaw)));
52480
52553
  }));
52481
- const attachTunnel = (tunnelId, live) => gen(function* () {
52554
+ const attachRpcTunnel = (tunnelId, live) => gen(function* () {
52482
52555
  yield* addFinalizer(() => sync(() => {
52483
52556
  if (tunnels.get(tunnelId) !== live) return;
52484
52557
  tunnels.delete(tunnelId);
@@ -52504,25 +52577,141 @@ const runHubTunnel = (config) => gen(function* () {
52504
52577
  }
52505
52578
  });
52506
52579
  const { protocol, onSocket } = yield* makeTunnelSocketProtocol.pipe(provide$1(layerJson));
52507
- yield* make$13(WsRpcGroup, { disableTracing: true }).pipe(provideService(Protocol, protocol), provide$1(makeWsRpcLayer({
52580
+ console.error("[DEBUG-provider-checking-20260820] rpc server starting");
52581
+ yield* forkScoped(make$13(WsRpcGroup, { disableTracing: true }).pipe(provideService(Protocol, protocol), provide$1(makeWsRpcLayer({
52508
52582
  sessionId: issued.sessionId,
52509
52583
  subject: "hub-tunnel",
52510
52584
  method: "bearer-access-token",
52511
52585
  scopes: [...TUNNEL_SCOPES]
52512
- }).pipe(provide(layer$8))), forkScoped);
52586
+ }).pipe(provideMerge(layerJson), provide(layer$8))), tapCause((cause) => logError("hub tunnel: RPC server failed", { cause: String(cause) }))));
52587
+ console.error("[DEBUG-provider-checking-20260820] rpc server started");
52513
52588
  yield* forkScoped(onSocket(socketAdapter));
52514
52589
  if (!writeHub(JSON.stringify({
52515
52590
  type: "tunnel_open",
52516
52591
  tunnelId
52517
52592
  }))) dropTunnel(tunnelId);
52518
- yield* logInfo("hub tunnel: attached", { tunnelId });
52593
+ yield* logInfo("hub tunnel: attached", {
52594
+ tunnelId,
52595
+ purpose: live.purpose
52596
+ });
52519
52597
  yield* _await(live.closed);
52520
52598
  }).pipe(catch_((error) => logWarning$1("hub tunnel: attach failed", {
52521
52599
  tunnelId,
52522
52600
  error
52523
52601
  })));
52524
- yield* socket.runRaw((data) => {
52525
- if (typeof data !== "string") return;
52602
+ const attachHttpTunnel = (tunnelId, live) => gen(function* () {
52603
+ yield* addFinalizer(() => sync(() => {
52604
+ if (tunnels.get(tunnelId) !== live) return;
52605
+ tunnels.delete(tunnelId);
52606
+ writeHub(JSON.stringify({
52607
+ type: "tunnel_close",
52608
+ tunnelId,
52609
+ code: 1011,
52610
+ reason: "daemon http tunnel ended"
52611
+ }));
52612
+ }));
52613
+ const issued = yield* serverAuth.issueSession({
52614
+ subject: "hub-tunnel-http",
52615
+ label: "AgentLink hub tunnel HTTP proxy",
52616
+ scopes: [...TUNNEL_SCOPES]
52617
+ });
52618
+ yield* addFinalizer(() => sessionsStore.markDisconnected(issued.sessionId).pipe(andThen(serverAuth.revokeSession(issued.sessionId)), ignore$1));
52619
+ yield* sessionsStore.markConnected(issued.sessionId);
52620
+ const localBaseUrl = `http://127.0.0.1:${serverConfig.port}`;
52621
+ const sendEncrypted = (frame) => {
52622
+ try {
52623
+ const envelope = utf8ToEnvelope(config.enckey, encodeHttpTunnelResponseFrame(frame));
52624
+ if (!writeHub(`${tunnelId} ${JSON.stringify(envelope)}`)) dropTunnel(tunnelId);
52625
+ } catch {
52626
+ dropTunnel(tunnelId);
52627
+ }
52628
+ };
52629
+ live.onDecryptedFrame = (frame) => {
52630
+ let requestFrame;
52631
+ try {
52632
+ const parsed = JSON.parse(frame);
52633
+ if (!isHttpTunnelRequestFrame(parsed)) {
52634
+ sendEncrypted({
52635
+ _tag: "HttpResponse",
52636
+ id: typeof parsed?.id === "string" ? parsed.id : "unknown",
52637
+ status: 400,
52638
+ statusText: "Bad Request",
52639
+ headers: [["content-type", "text/plain"]],
52640
+ body: Buffer.from("Invalid HTTP tunnel request frame").toString("base64")
52641
+ });
52642
+ return;
52643
+ }
52644
+ requestFrame = parsed;
52645
+ } catch {
52646
+ sendEncrypted({
52647
+ _tag: "HttpResponse",
52648
+ id: "unknown",
52649
+ status: 400,
52650
+ statusText: "Bad Request",
52651
+ headers: [["content-type", "text/plain"]],
52652
+ body: Buffer.from("Malformed HTTP tunnel request frame").toString("base64")
52653
+ });
52654
+ return;
52655
+ }
52656
+ runFork(gen(function* () {
52657
+ const targetUrl = `${localBaseUrl}${requestFrame.path}`;
52658
+ const headers = { authorization: `Bearer ${issued.token}` };
52659
+ for (const [key, value] of requestFrame.headers) {
52660
+ const lower = key.toLowerCase();
52661
+ if (lower === "authorization" || lower === "cookie") continue;
52662
+ headers[lower] = value;
52663
+ }
52664
+ let request = make$61(requestFrame.method)(targetUrl).pipe(setHeaders(headers));
52665
+ if (requestFrame.body !== null) request = setBody(uint8Array(Buffer.from(requestFrame.body, "base64")))(request);
52666
+ const response = yield* httpClient.execute(request);
52667
+ const responseBody = yield* response.arrayBuffer;
52668
+ const responseHeaders = [];
52669
+ for (const [key, value] of Object.entries(response.headers)) if (typeof value === "string") responseHeaders.push([key, value]);
52670
+ return {
52671
+ _tag: "HttpResponse",
52672
+ id: requestFrame.id,
52673
+ status: response.status,
52674
+ statusText: "",
52675
+ headers: responseHeaders,
52676
+ body: Buffer.from(responseBody).toString("base64")
52677
+ };
52678
+ }).pipe(match$2({
52679
+ onFailure: (cause) => ({
52680
+ _tag: "HttpResponse",
52681
+ id: requestFrame.id,
52682
+ status: 502,
52683
+ statusText: "Bad Gateway",
52684
+ headers: [["content-type", "text/plain"]],
52685
+ body: Buffer.from(cause instanceof Error ? cause.message : String(cause)).toString("base64")
52686
+ }),
52687
+ onSuccess: (response) => response
52688
+ }), tap((frame) => sync(() => sendEncrypted(frame)))));
52689
+ };
52690
+ if (!writeHub(JSON.stringify({
52691
+ type: "tunnel_open",
52692
+ tunnelId
52693
+ }))) dropTunnel(tunnelId);
52694
+ yield* logInfo("hub tunnel: attached", {
52695
+ tunnelId,
52696
+ purpose: live.purpose
52697
+ });
52698
+ yield* _await(live.closed);
52699
+ }).pipe(provideService(HttpClient, httpClient), catch_((error) => logWarning$1("hub tunnel: attach failed", {
52700
+ tunnelId,
52701
+ error
52702
+ })));
52703
+ let debugProviderCheckingFrameCount = 0;
52704
+ yield* socket.runRaw((rawData) => {
52705
+ if (debugProviderCheckingFrameCount < 20) {
52706
+ debugProviderCheckingFrameCount += 1;
52707
+ console.error("[DEBUG-provider-checking-20260820] hub frame", {
52708
+ count: debugProviderCheckingFrameCount,
52709
+ type: typeof rawData,
52710
+ byteLength: typeof rawData === "string" ? rawData.length : rawData instanceof Uint8Array ? rawData.byteLength : -1
52711
+ });
52712
+ }
52713
+ const data = typeof rawData === "string" ? rawData : rawData instanceof Uint8Array ? hubFrameDecoder.decode(rawData) : null;
52714
+ if (data === null) return;
52526
52715
  if (data.startsWith("{")) {
52527
52716
  let control;
52528
52717
  try {
@@ -52534,13 +52723,17 @@ const runHubTunnel = (config) => gen(function* () {
52534
52723
  const tunnelId = control.tunnelId;
52535
52724
  if (tunnels.has(tunnelId)) return;
52536
52725
  return gen(function* () {
52726
+ const closed = yield* make$70();
52727
+ const purpose = control.purpose === "http" ? "http" : "rpc";
52537
52728
  const live = {
52538
- closed: yield* make$70(),
52729
+ closed,
52539
52730
  pendingFrames: [],
52731
+ purpose,
52540
52732
  onDecryptedFrame: null
52541
52733
  };
52542
52734
  tunnels.set(tunnelId, live);
52543
- yield* forkScoped(scoped(attachTunnel(tunnelId, live)));
52735
+ if (purpose === "http") runFork(scoped(attachHttpTunnel(tunnelId, live)));
52736
+ else runFork(scoped(attachRpcTunnel(tunnelId, live)));
52544
52737
  });
52545
52738
  }
52546
52739
  if (control.type === "tunnel_close" && typeof control.tunnelId === "string") dropTunnel(control.tunnelId);
@@ -52563,12 +52756,17 @@ const runHubTunnel = (config) => gen(function* () {
52563
52756
  } catch {
52564
52757
  return dropTunnel(framed.tunnelId);
52565
52758
  }
52759
+ console.error("[DEBUG-provider-checking-20260820] frame decrypted", {
52760
+ tunnelId: framed.tunnelId,
52761
+ byteLength: frame.length,
52762
+ delivery: live.onDecryptedFrame ? "deliver" : "pending"
52763
+ });
52566
52764
  if (live.onDecryptedFrame) live.onDecryptedFrame(frame);
52567
52765
  else if (live.pendingFrames.length < 16) live.pendingFrames.push(frame);
52568
52766
  else dropTunnel(framed.tunnelId);
52569
52767
  return;
52570
52768
  }
52571
- }, { onOpen: logInfo("hub tunnel: connected to hub") }).pipe(tapDefect((cause) => logWarning$1("hub tunnel: hub socket defect", { cause: String(cause) })));
52769
+ }, { onOpen: logInfo("hub tunnel: connected to hub").pipe(tap(() => sync(() => void runFork(upload)))) }).pipe(tapDefect((cause) => logWarning$1("hub tunnel: hub socket defect", { cause: String(cause) })));
52572
52770
  yield* logWarning$1("hub tunnel: hub connection closed");
52573
52771
  }).pipe(scoped, tapError((error) => logWarning$1("hub tunnel: connection error", { error }))), {
52574
52772
  schedule: spaced("2 seconds"),