@lengmoxxl/sdk 0.1.3 → 0.1.4

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
@@ -32,8 +32,8 @@ connection.disconnect();
32
32
 
33
33
  `openMachine` returns a `MachineConnection`; every call opens its own. Sharing one belongs to the caller: a
34
34
  connection is reference counted, so callers that hand the same one around keep it alive until the last
35
- `disconnect()`. `openMachine({ type: 'ssh', host, agent })` installs the carrier agent on the host first when
36
- `agent` is given.
35
+ `disconnect()`. `openMachine({ type: 'ssh', host, agent })` calls `agent(host)` before it connects: putting
36
+ the carrier agent on the host belongs to the app that embeds the SDK.
37
37
 
38
38
  - `connection.pty` - `list`, `cwd`, `create`, `attach`, `close`
39
39
  - `connection.fs` - `stat`, `readDirectory`, `readFile`
package/dist/agent.d.ts CHANGED
@@ -1,5 +1 @@
1
- import type { AgentInfo } from './types';
2
1
  export declare function agentCommand(command: string): string;
3
- export declare function ensureAgent(host: string, { version, prefixes, signal }: AgentInfo & {
4
- signal?: AbortSignal;
5
- }): Promise<void>;
@@ -4,6 +4,7 @@ export declare class MachineConnection {
4
4
  private options;
5
5
  private listeners;
6
6
  private terminals;
7
+ port?: number;
7
8
  private instance?;
8
9
  readonly ready: Promise<void>;
9
10
  private resolveReady;
package/dist/index.cjs CHANGED
@@ -30,14 +30,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ agentCommand: () => agentCommand,
33
34
  openMachine: () => openMachine
34
35
  });
35
36
  module.exports = __toCommonJS(index_exports);
36
37
 
37
38
  // connection.ts
38
- var import_node_child_process2 = require("node:child_process");
39
+ var import_node_child_process = require("node:child_process");
39
40
  var import_node_net = require("node:net");
40
- var import_node_util2 = require("node:util");
41
+ var import_node_util = require("node:util");
41
42
  var import_ws = __toESM(require("ws"));
42
43
 
43
44
  // pty.ts
@@ -111,61 +112,14 @@ var Pty = class {
111
112
  };
112
113
 
113
114
  // agent.ts
114
- var import_node_child_process = require("node:child_process");
115
- var import_node_util = require("node:util");
116
- var exec = (0, import_node_util.promisify)(import_node_child_process.execFile);
117
- var DOWNLOAD_TIMEOUT = 3e4;
118
115
  function agentCommand(command) {
119
116
  const home = process.env.WANGCAI_HOME;
120
117
  const exportHome = home ? `export WANGCAI_HOME='${home.replace(/'/g, String.raw`'\''`)}'; ` : "";
121
118
  return `${exportHome}export PATH="$HOME/.local/bin:$PATH"; ${command}`;
122
119
  }
123
- async function ensureAgent(host, { version, prefixes, signal }) {
124
- const targets = {
125
- "Darwin x86_64": "x86_64-apple-darwin",
126
- "Darwin arm64": "aarch64-apple-darwin",
127
- "Linux x86_64": "x86_64-unknown-linux-musl"
128
- };
129
- const remote = (command) => ["-T", "-o", "BatchMode=yes", "-o", "ConnectTimeout=8", host, command];
130
- const probe = await exec("ssh", remote(agentCommand("uname -s -m; wangcai --version 2>/dev/null; true")), { timeout: 3e4, signal }).catch(() => void 0);
131
- const [platform, installed] = (probe?.stdout ?? "").split("\n").map((line) => line.trim());
132
- if (!platform) return;
133
- const target = targets[platform];
134
- if (!target) throw new Error(`${platform} \u4E0A\u6682\u4E0D\u652F\u6301\u81EA\u52A8\u5B89\u88C5 agent`);
135
- if (installed === `wangcai ${version}`) return;
136
- const failures = [];
137
- for (const prefix of prefixes) {
138
- signal?.throwIfAborted();
139
- const url = `${prefix}/v${version}/wangcai-${target}`;
140
- const deadline = AbortSignal.timeout(DOWNLOAD_TIMEOUT);
141
- let binary;
142
- try {
143
- const response = await fetch(url, { signal: signal ? AbortSignal.any([signal, deadline]) : deadline });
144
- if (!response.ok) throw new Error(`${response.status} ${response.statusText}`);
145
- binary = Buffer.from(await response.arrayBuffer());
146
- } catch (error) {
147
- failures.push(`${url}
148
- ${error instanceof Error ? error.message : String(error)}`);
149
- continue;
150
- }
151
- await new Promise((resolve, reject) => {
152
- const child = (0, import_node_child_process.spawn)("ssh", remote("mkdir -p ~/.local/bin && cat > ~/.local/bin/.wangcai.tmp && chmod 755 ~/.local/bin/.wangcai.tmp && mv ~/.local/bin/.wangcai.tmp ~/.local/bin/wangcai"), { stdio: ["pipe", "ignore", "pipe"] });
153
- let stderr = "";
154
- child.stderr.on("data", (chunk) => {
155
- stderr += chunk;
156
- });
157
- child.on("error", reject);
158
- child.on("close", (code) => code === 0 ? resolve() : reject(new Error(stderr.trim() || `\u5199\u5165 agent \u5931\u8D25\uFF08ssh \u9000\u51FA\u7801 ${code}\uFF09`)));
159
- child.stdin.end(binary);
160
- });
161
- return;
162
- }
163
- throw new Error(`\u4E0B\u8F7D agent \u5931\u8D25\uFF1A
164
- ${failures.join("\n\n")}`);
165
- }
166
120
 
167
121
  // connection.ts
168
- var exec2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
122
+ var exec = (0, import_node_util.promisify)(import_node_child_process.execFile);
169
123
  var MachineConnection = class {
170
124
  constructor(options) {
171
125
  this.options = options;
@@ -178,6 +132,8 @@ var MachineConnection = class {
178
132
  }
179
133
  listeners = /* @__PURE__ */ new Set();
180
134
  terminals = /* @__PURE__ */ new Map();
135
+ // Where the daemon listens: the window reaches it with this.
136
+ port;
181
137
  instance;
182
138
  ready;
183
139
  resolveReady;
@@ -300,12 +256,12 @@ var MachineConnection = class {
300
256
  let info;
301
257
  let port;
302
258
  if (this.options.type === "local") {
303
- const { stdout } = await exec2(this.options.binary ?? "wangcai", ["server", "start", "--json"], { timeout: 15e3 });
259
+ const { stdout } = await exec(this.options.binary ?? "wangcai", ["server", "start", "--json"], { timeout: 15e3 });
304
260
  info = JSON.parse(stdout);
305
261
  port = info.port;
306
262
  } else {
307
- if (this.options.agent) await ensureAgent(this.options.host, { ...this.options.agent, signal: this.options.signal });
308
- const { stdout } = await exec2("ssh", [
263
+ if (this.options.agent) await this.options.agent(this.options.host, this.options.signal);
264
+ const { stdout } = await exec("ssh", [
309
265
  "-T",
310
266
  "-o",
311
267
  "BatchMode=yes",
@@ -319,6 +275,7 @@ var MachineConnection = class {
319
275
  if (!current()) return;
320
276
  port = await this.forward(info.port, current);
321
277
  }
278
+ this.port = port;
322
279
  if (!current()) return;
323
280
  const socket = new import_ws.default(`ws://127.0.0.1:${port}`, { handshakeTimeout: 5e3, maxPayload: 64 * 1024 * 1024 });
324
281
  this.ws = socket;
@@ -415,7 +372,7 @@ var MachineConnection = class {
415
372
  const port = reservation.address().port;
416
373
  await new Promise((resolve) => reservation.close(() => resolve()));
417
374
  if (!current()) throw new Error("Connection cancelled");
418
- const tunnel = (0, import_node_child_process2.spawn)("ssh", [
375
+ const tunnel = (0, import_node_child_process.spawn)("ssh", [
419
376
  "-N",
420
377
  "-T",
421
378
  "-o",
@@ -521,5 +478,6 @@ async function openMachine(options) {
521
478
  }
522
479
  // Annotate the CommonJS export names for ESM import in node:
523
480
  0 && (module.exports = {
481
+ agentCommand,
524
482
  openMachine
525
483
  });
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { MachineConnection } from './connection';
2
2
  import type { ConnectionOptions } from './types';
3
- export type { AgentInfo, ConnectionOptions, FileClick, Machine, MachineState, Session, Size, Output, Snapshot, TerminalEvent, DirectoryEntry, ExecOptions, ExecResult, Profile, Theme, WorkspaceActive, WorkspaceRow, WorkspaceMenuItem } from './types';
3
+ export { agentCommand } from './agent';
4
+ export type { ConnectionOptions, FileClick, Machine, MachineState, Session, Size, Output, Snapshot, TerminalEvent, DirectoryEntry, ExecOptions, ExecResult, InstallAgent, Profile, Theme, WorkspaceActive, WorkspaceRow, WorkspaceMenuItem } from './types';
4
5
  export type { MachineConnection } from './connection';
5
6
  export type { Pty } from './pty';
6
7
  /** Opens one connection to a machine and waits for it to be ready. */
package/dist/types.d.ts CHANGED
@@ -1,7 +1,5 @@
1
- export interface AgentInfo {
2
- version: string;
3
- prefixes: string[];
4
- }
1
+ /** What puts the agent on an ssh machine, which the SDK calls before it connects to it. */
2
+ export type InstallAgent = (host: string, signal?: AbortSignal) => Promise<void>;
5
3
  /**
6
4
  * The workspace protocol. A plugin that init.ts lists under `workspaces` is a workspace provider, and
7
5
  * the app drives it through these `ui` methods:
@@ -58,7 +56,7 @@ export type ConnectionOptions = {
58
56
  } | {
59
57
  type: 'ssh';
60
58
  host: string;
61
- agent?: AgentInfo;
59
+ agent?: InstallAgent;
62
60
  signal?: AbortSignal;
63
61
  };
64
62
  export interface Size {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lengmoxxl/sdk",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Client SDK for WangCai: connect to a local or remote machine and drive its pty, files and git",
5
5
  "license": "MIT",
6
6
  "repository": {