byollm 0.1.0-alpha.97 → 0.1.0-alpha.99

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  > [!WARNING]
2
- > **Alpha (`0.1.0-alpha.97`) — under active development. Don't use this yet.**
2
+ > **Alpha (`0.1.0-alpha.99`) — under active development. Don't use this yet.**
3
3
  >
4
4
  > Install it deliberately: `npx byollm@latest`, or `npm install byollm@latest`.
5
5
  >
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  main
4
- } from "./chunk-R3WK5X6Q.js";
4
+ } from "./chunk-LPCHIPVJ.js";
5
5
 
6
6
  // src/bin.ts
7
7
  process.exitCode = await main(process.argv.slice(2));
@@ -4781,8 +4781,10 @@ import {
4781
4781
  ConsoleFrame,
4782
4782
  CONSOLE_FRAME_VERSION,
4783
4783
  CONSOLE_MAX_DATA_BYTES,
4784
+ consoleDataBytes,
4784
4785
  consoleEnvelope,
4785
4786
  consoleOrder,
4787
+ encodeConsoleData,
4786
4788
  keyId,
4787
4789
  open as open2,
4788
4790
  seal,
@@ -4790,6 +4792,9 @@ import {
4790
4792
  } from "@byollm/protocol";
4791
4793
  function consoleSession(deps) {
4792
4794
  const inbound = consoleOrder("browser");
4795
+ const log = deps.log ?? (() => void 0);
4796
+ let fromBrowser = 0;
4797
+ let toBrowser = 0;
4793
4798
  const boxKeyId = keyId(deps.keys.identityPublic);
4794
4799
  const browserKeyId = keyId(deps.browser.identity);
4795
4800
  let outSeq = 0;
@@ -4813,6 +4818,11 @@ function consoleSession(deps) {
4813
4818
  const finish = async (reason) => {
4814
4819
  if (ended !== void 0) return;
4815
4820
  ended = reason;
4821
+ log("console session ending", {
4822
+ reason,
4823
+ framesFromBrowser: fromBrowser,
4824
+ framesToBrowser: toBrowser
4825
+ });
4816
4826
  deps.shell.kill();
4817
4827
  try {
4818
4828
  outSeq += 1;
@@ -4836,12 +4846,20 @@ function consoleSession(deps) {
4836
4846
  for (let at = 0; at < chunk.length; at += CONSOLE_MAX_DATA_BYTES) {
4837
4847
  const slice = chunk.subarray(at, at + CONSOLE_MAX_DATA_BYTES);
4838
4848
  outSeq += 1;
4849
+ toBrowser += 1;
4839
4850
  void sealTo({
4840
4851
  v: CONSOLE_FRAME_VERSION,
4841
4852
  kind: "stdout",
4842
4853
  seq: outSeq,
4843
- data: slice.toString("base64")
4844
- }).catch(() => void finish("the console channel closed"));
4854
+ data: encodeConsoleData(slice)
4855
+ }).catch((cause) => {
4856
+ log("could not send output to the browser", {
4857
+ reason: cause instanceof Error ? cause.message : String(cause),
4858
+ fromBrowser,
4859
+ toBrowser
4860
+ });
4861
+ return finish("the console channel closed");
4862
+ });
4845
4863
  }
4846
4864
  });
4847
4865
  deps.shell.onExit((reason) => void finish(reason));
@@ -4902,10 +4920,12 @@ function consoleSession(deps) {
4902
4920
  }
4903
4921
  case "stdin":
4904
4922
  if (!started) return;
4905
- deps.shell.write(Buffer.from(frame.data, "base64"));
4923
+ fromBrowser += 1;
4924
+ deps.shell.write(Buffer.from(consoleDataBytes(frame.data)));
4906
4925
  return;
4907
4926
  case "resize":
4908
4927
  if (!started) return;
4928
+ fromBrowser += 1;
4909
4929
  deps.shell.resize(frame.cols, frame.rows);
4910
4930
  return;
4911
4931
  case "stdout":
@@ -4985,9 +5005,13 @@ async function openPtyShell(options) {
4985
5005
  }
4986
5006
 
4987
5007
  // src/console-agent-main.ts
4988
- import { SealedEnvelope as SealedEnvelopeSchema } from "@byollm/protocol";
4989
- var connectWebSocket = (url) => new Promise((resolve, reject) => {
4990
- const socket = new WebSocket(url);
5008
+ import {
5009
+ SealedEnvelope as SealedEnvelopeSchema,
5010
+ signRequest as signRequest2
5011
+ } from "@byollm/protocol";
5012
+ var CONSOLE_BOX_ENDPOINT = "/console/box";
5013
+ var connectWebSocket = (url, headers) => new Promise((resolve, reject) => {
5014
+ const socket = new WebSocket(url, { headers });
4991
5015
  socket.addEventListener("open", () => {
4992
5016
  resolve({
4993
5017
  send: (text) => {
@@ -5019,7 +5043,17 @@ async function runConsoleAgent(options) {
5019
5043
  cwd: options.cwd,
5020
5044
  env: options.env
5021
5045
  });
5022
- const socket = await (options.connect ?? connectWebSocket)(options.url);
5046
+ const signed = signRequest2(options.keys, {
5047
+ endpoint: CONSOLE_BOX_ENDPOINT,
5048
+ runnerId: options.runnerId,
5049
+ issuedAt: (options.now ?? Date.now)(),
5050
+ body: options.sessionId
5051
+ });
5052
+ const socket = await (options.connect ?? connectWebSocket)(options.url, {
5053
+ "x-byollm-runner": signed.runnerId,
5054
+ "x-byollm-issued-at": String(signed.issuedAt),
5055
+ "x-byollm-signature": signed.signature
5056
+ });
5023
5057
  const session = consoleSession({
5024
5058
  sessionId: options.sessionId,
5025
5059
  deadlineAt: options.deadlineAt,
@@ -5031,6 +5065,7 @@ async function runConsoleAgent(options) {
5031
5065
  return Promise.resolve();
5032
5066
  },
5033
5067
  record: options.record,
5068
+ log: options.log,
5034
5069
  now: options.now ?? (() => Date.now())
5035
5070
  });
5036
5071
  return new Promise((resolve) => {
@@ -5099,10 +5134,10 @@ var ConsoleAgentSpec = z5.object({
5099
5134
  }).strict();
5100
5135
 
5101
5136
  // src/console-listen.ts
5102
- import { signRequest as signRequest2 } from "@byollm/protocol";
5137
+ import { signRequest as signRequest3 } from "@byollm/protocol";
5103
5138
  var CONSOLE_DEVICE_ENDPOINT = "/console/device";
5104
5139
  var deviceHeaders = (keys, runnerId, now) => {
5105
- const signed = signRequest2(keys, {
5140
+ const signed = signRequest3(keys, {
5106
5141
  endpoint: CONSOLE_DEVICE_ENDPOINT,
5107
5142
  runnerId,
5108
5143
  issuedAt: now,
@@ -8883,15 +8918,28 @@ async function commandConsoleAgent(paths, args, io) {
8883
8918
  const url = `${paired.origin.replace(/^http/, "ws")}${CONSOLE_DEVICE_ENDPOINT}`;
8884
8919
  io.out(`listening for consoles on ${paired.origin}
8885
8920
  `);
8921
+ const consoleLog = (message, fields) => {
8922
+ io.out(`${JSON.stringify({ console: message, ...fields })}
8923
+ `);
8924
+ };
8886
8925
  consoleListener({
8887
8926
  url,
8888
8927
  runnerId: paired.runnerId,
8889
8928
  keys,
8890
8929
  run: (announcement) => runConsoleAgent({
8891
- url: `${paired.origin.replace(/^http/, "ws")}/console/box?session=${announcement.sessionId}`,
8930
+ /* The endpoint from one definition, shared with the signer that
8931
+ has to name it identically — a URL built here and a signature
8932
+ built there, disagreeing by a character, is a 401 nobody can
8933
+ read. */
8934
+ url: `${paired.origin.replace(/^http/, "ws")}${CONSOLE_BOX_ENDPOINT}?session=${announcement.sessionId}`,
8892
8935
  sessionId: announcement.sessionId,
8893
8936
  deadlineAt: announcement.deadlineAt,
8894
8937
  keys,
8938
+ /* The data door is authenticated too, and signs over the SESSION —
8939
+ a signature captured from one cannot be replayed to join
8940
+ another. Without this the dial is refused 401 before the
8941
+ handshake, which is what attempt six hit. */
8942
+ runnerId: paired.runnerId,
8895
8943
  browser: announcement.browser,
8896
8944
  command: process.env["BYOLLM_CONSOLE_SHELL"] ?? "/bin/sh",
8897
8945
  args: [],
@@ -8901,12 +8949,12 @@ async function commandConsoleAgent(paths, args, io) {
8901
8949
  io.out(`${JSON.stringify({ consoleSession: entry })}
8902
8950
  `);
8903
8951
  return Promise.resolve();
8904
- }
8952
+ },
8953
+ /* The agent's own half of the picture, on the same stream as the
8954
+ listener's — one place to read when a console goes quiet. */
8955
+ log: consoleLog
8905
8956
  }).then(() => void 0),
8906
- log: (message, fields) => {
8907
- io.out(`${JSON.stringify({ console: message, ...fields ?? {} })}
8908
- `);
8909
- }
8957
+ log: consoleLog
8910
8958
  });
8911
8959
  await new Promise(() => void 0);
8912
8960
  return 0;
@@ -8923,12 +8971,22 @@ async function commandConsoleAgent(paths, args, io) {
8923
8971
  io.err("That session description is not one this agent understands.\n");
8924
8972
  return 2;
8925
8973
  }
8974
+ const agentPairings = new Pairings(paths.pairings);
8975
+ await agentPairings.load();
8976
+ const agentPaired = agentPairings.list()[0];
8977
+ if (agentPaired === void 0) {
8978
+ io.err(
8979
+ "byollm console-agent cannot join a console: this device is not paired.\nThe hub will not accept an unsigned connection. Pair it first with `byollm connect`.\n"
8980
+ );
8981
+ return 1;
8982
+ }
8926
8983
  try {
8927
8984
  const why = await runConsoleAgent({
8928
8985
  url: session.data.url,
8929
8986
  sessionId: session.data.sessionId,
8930
8987
  deadlineAt: session.data.deadlineAt,
8931
8988
  keys,
8989
+ runnerId: agentPaired.runnerId,
8932
8990
  browser: session.data.browser,
8933
8991
  command: session.data.shell.command,
8934
8992
  args: session.data.shell.args,
@@ -10503,7 +10561,7 @@ async function exists(path) {
10503
10561
  }
10504
10562
 
10505
10563
  // src/index.ts
10506
- var DAEMON_VERSION = "0.1.0-alpha.97";
10564
+ var DAEMON_VERSION = "0.1.0-alpha.99";
10507
10565
  function daemonVersion() {
10508
10566
  return {
10509
10567
  daemon: DAEMON_VERSION,
@@ -10562,4 +10620,4 @@ export {
10562
10620
  runCli,
10563
10621
  main
10564
10622
  };
10565
- //# sourceMappingURL=chunk-R3WK5X6Q.js.map
10623
+ //# sourceMappingURL=chunk-LPCHIPVJ.js.map