@tianshu-ai/local-bridge 0.4.1 → 0.6.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/update.js CHANGED
@@ -1,18 +1,23 @@
1
- // `tsbridge update` — check npm for a newer @tianshu-ai/local-bridge and
2
- // optionally self-update the global install.
1
+ // `tsbridge update` — self-update the global @tianshu-ai/local-bridge
2
+ // install. Behaviour mirrors `tianshu update` for a consistent CLI:
3
3
  //
4
- // Check-only by default; pass --yes to actually run the install. Uses
5
- // the npm registry JSON API (no auth) for the check, and `npm i -g` for
6
- // the apply so it works regardless of how the CLI was installed.
4
+ // tsbridge update → check + install if newer (default: install)
5
+ // tsbridge update --check → just compare; exit 1 if an update exists
6
+ // tsbridge update --dry-run → print the npm command, don't run it
7
+ // tsbridge update --tag next → target a non-`latest` dist-tag
8
+ //
9
+ // Exit codes:
10
+ // 0 → up to date, OR update succeeded, OR --check found nothing
11
+ // 1 → --check found an available update (script-friendly signal)
12
+ // 2 → error (network, npm install failed, git-checkout, …)
7
13
  import { createRequire } from "node:module";
8
14
  import { spawn } from "node:child_process";
9
- const PKG = "@tianshu-ai/local-bridge";
15
+ export const PACKAGE_NAME = "@tianshu-ai/local-bridge";
10
16
  const REGISTRY = "https://registry.npmjs.org";
11
17
  /** Installed version, read from this package's own package.json. */
12
18
  export function installedVersion() {
13
19
  try {
14
20
  const require = createRequire(import.meta.url);
15
- // dist/update.js → ../package.json
16
21
  const pkg = require("../package.json");
17
22
  return pkg.version ?? "0.0.0";
18
23
  }
@@ -20,51 +25,24 @@ export function installedVersion() {
20
25
  return "0.0.0";
21
26
  }
22
27
  }
23
- /** Fetch the latest published version + dist-tags from npm. */
24
- async function fetchLatest() {
28
+ async function fetchDistTag(tag) {
25
29
  try {
26
- const res = await fetch(`${REGISTRY}/${encodeURIComponent(PKG).replace("%40", "@")}/latest`, {
27
- headers: { accept: "application/json" },
28
- signal: AbortSignal.timeout(10_000),
29
- });
30
+ const url = `${REGISTRY}/${PACKAGE_NAME.replace("/", "%2f")}/${encodeURIComponent(tag)}`;
31
+ const res = await fetch(url, { headers: { accept: "application/json" }, signal: AbortSignal.timeout(10_000) });
30
32
  if (!res.ok)
31
- return null;
33
+ return { ok: false, error: `HTTP ${res.status}` };
32
34
  const json = (await res.json());
33
- return json.version ?? null;
35
+ if (!json.version)
36
+ return { ok: false, error: "no version in registry response" };
37
+ return { ok: true, version: json.version };
34
38
  }
35
- catch {
36
- return null;
37
- }
38
- }
39
- /** Semver-ish compare: returns true if `remote` is strictly newer than
40
- * `local`. Handles plain x.y.z; prerelease tags compare lexically as a
41
- * best-effort tiebreak. */
42
- function isNewer(remote, local) {
43
- const parse = (v) => {
44
- const [core, pre] = v.split("-", 2);
45
- const nums = core.split(".").map((n) => parseInt(n, 10) || 0);
46
- return { nums, pre: pre ?? "" };
47
- };
48
- const a = parse(remote);
49
- const b = parse(local);
50
- for (let i = 0; i < 3; i++) {
51
- const x = a.nums[i] ?? 0;
52
- const y = b.nums[i] ?? 0;
53
- if (x !== y)
54
- return x > y;
39
+ catch (err) {
40
+ return { ok: false, error: err instanceof Error ? err.message : String(err) };
55
41
  }
56
- // equal core: a release (no pre) beats a prerelease; else lexical
57
- if (a.pre === b.pre)
58
- return false;
59
- if (!a.pre)
60
- return true;
61
- if (!b.pre)
62
- return false;
63
- return a.pre > b.pre;
64
42
  }
65
- function runNpmInstall() {
43
+ function runNpmInstall(target) {
66
44
  return new Promise((resolve) => {
67
- const child = spawn("npm", ["install", "-g", `${PKG}@latest`], {
45
+ const child = spawn("npm", ["install", "-g", target], {
68
46
  stdio: "inherit",
69
47
  shell: process.platform === "win32",
70
48
  });
@@ -72,34 +50,40 @@ function runNpmInstall() {
72
50
  child.on("error", () => resolve(1));
73
51
  });
74
52
  }
75
- /** Run the update subcommand. `apply` = actually install the new version. */
76
- export async function runUpdate(apply) {
77
- const local = installedVersion();
78
- process.stdout.write(`[tsbridge] installed: v${local}\n`);
79
- process.stdout.write(`[tsbridge] checking ${REGISTRY} for a newer ${PKG}…\n`);
80
- const latest = await fetchLatest();
81
- if (!latest) {
82
- process.stderr.write("[tsbridge] could not reach the npm registry.\n");
83
- return 1;
53
+ /** `tsbridge update [--check] [--tag <name>] [--dry-run]`. */
54
+ export async function runUpdate(opts = {}) {
55
+ const tag = opts.tag ?? "latest";
56
+ const current = installedVersion();
57
+ console.log(`Current version: ${current}`);
58
+ const remote = await fetchDistTag(tag);
59
+ if (!remote.ok) {
60
+ console.error(`Couldn't reach npm registry: ${remote.error}`);
61
+ console.error("Check your network / proxy and retry. If you're offline, skip the update.");
62
+ return 2;
84
63
  }
85
- if (!isNewer(latest, local)) {
86
- process.stdout.write(`[tsbridge] up to date (latest is v${latest}).\n`);
64
+ console.log(`Latest on \`${tag}\`: ${remote.version}`);
65
+ if (current === remote.version) {
66
+ console.log("Already up to date.");
87
67
  return 0;
88
68
  }
89
- process.stdout.write(`[tsbridge] a newer version is available: v${latest}\n`);
90
- if (!apply) {
91
- process.stdout.write(`[tsbridge] to update, run:\n npm i -g ${PKG}@latest\n or:\n tsbridge update --yes\n`);
69
+ if (opts.check) {
70
+ console.log(`Update available: ${current} → ${remote.version}. Run \`tsbridge update\` to install.`);
71
+ return 1;
72
+ }
73
+ const target = `${PACKAGE_NAME}@${remote.version}`;
74
+ const cmd = `npm install -g ${target}`;
75
+ if (opts.dryRun) {
76
+ console.log(`Would run: ${cmd}`);
92
77
  return 0;
93
78
  }
94
- process.stdout.write(`[tsbridge] updating v${local} → v${latest}…\n`);
95
- const code = await runNpmInstall();
79
+ console.log(`Installing ${remote.version}…`);
80
+ const code = await runNpmInstall(target);
96
81
  if (code === 0) {
97
- process.stdout.write(`[tsbridge] updated to v${latest}. Restart any running bridge.\n`);
98
- }
99
- else {
100
- process.stderr.write(`[tsbridge] update failed (npm exit ${code}). Try manually: npm i -g ${PKG}@latest\n` +
101
- ` (a permission error usually means you need sudo, or a Node version manager's global dir.)\n`);
82
+ console.log(`Updated to ${remote.version}. Restart any running bridge (tsbridge --server …).`);
83
+ return 0;
102
84
  }
103
- return code;
85
+ console.error(`npm install failed (exit ${code}). Try manually: ${cmd}\n` +
86
+ " A permission error usually means you need sudo, or a Node version manager's global dir.");
87
+ return 2;
104
88
  }
105
89
  //# sourceMappingURL=update.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../src/update.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tianshu-ai/local-bridge",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Local bridge for tianshu — dial into a tianshu server over WebSocket and expose your machine's tools (browser, files, shell) to the agent via reverse-MCP.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -18,6 +18,7 @@
18
18
  },
19
19
  "files": [
20
20
  "dist",
21
+ "app/TianshuBridge.swift",
21
22
  "README.md"
22
23
  ],
23
24
  "scripts": {
package/dist/browser.js DELETED
@@ -1,170 +0,0 @@
1
- // Local browser tools, driven by Playwright against the user's OWN
2
- // Chrome — never a bundled/downloaded Chromium.
3
- //
4
- // Acquisition strategy (best → fallback), so we reuse the real browser
5
- // with its real fingerprint + logged-in cookies and avoid a heavy
6
- // download:
7
- //
8
- // 1. CONNECT over CDP to a Chrome the user already has running with
9
- // `--remote-debugging-port` (default probe: http://127.0.0.1:9222).
10
- // This is the user's actual browser — real profile, real session.
11
- // 2. LAUNCH the system-installed Google Chrome via Playwright's
12
- // `channel: "chrome"` (no Chromium download). Optionally reuse the
13
- // user's profile via `userDataDir` so logins carry over. Launched
14
- // with automation-detection softened.
15
- //
16
- // Nothing here downloads a browser; if neither path works the tool
17
- // returns a clear, actionable error.
18
- import { textResult } from "./protocol.js";
19
- // Args that soften automation detection (navigator.webdriver etc.).
20
- const STEALTH_ARGS = [
21
- "--disable-blink-features=AutomationControlled",
22
- "--no-default-browser-check",
23
- "--no-first-run",
24
- ];
25
- async function probeCdp(cdpUrl) {
26
- if (!cdpUrl)
27
- return false;
28
- try {
29
- const base = cdpUrl.replace(/\/$/, "");
30
- const res = await fetch(`${base}/json/version`, {
31
- signal: AbortSignal.timeout(2500),
32
- });
33
- return res.ok;
34
- }
35
- catch {
36
- return false;
37
- }
38
- }
39
- /** Acquire a Page, connecting to the user's Chrome or launching the
40
- * system Chrome. Cached after first success. */
41
- async function ensurePage(state, cfg) {
42
- if (state.page && !state.page.isClosed())
43
- return state.page;
44
- const { chromium } = await import("playwright");
45
- // 1) Connect to an already-running Chrome over CDP.
46
- if (!state.browser && !state.context && (await probeCdp(cfg.cdpUrl))) {
47
- try {
48
- const browser = await chromium.connectOverCDP(cfg.cdpUrl);
49
- state.browser = browser;
50
- const ctx = browser.contexts()[0] ?? (await browser.newContext());
51
- state.context = ctx;
52
- state.page = ctx.pages()[0] ?? (await ctx.newPage());
53
- state.how = `connected to your running Chrome at ${cfg.cdpUrl}`;
54
- cfg.log(state.how);
55
- return state.page;
56
- }
57
- catch (err) {
58
- cfg.log(`CDP connect failed (${err instanceof Error ? err.message : String(err)}); falling back to launch`);
59
- }
60
- }
61
- // 2) Launch the system-installed Chrome (no Chromium download).
62
- if (cfg.userDataDir) {
63
- // Persistent context reuses the user's profile → logged-in sessions.
64
- const ctx = await chromium.launchPersistentContext(cfg.userDataDir, {
65
- channel: cfg.channel,
66
- headless: !cfg.headful,
67
- args: STEALTH_ARGS,
68
- });
69
- state.context = ctx;
70
- state.page = ctx.pages()[0] ?? (await ctx.newPage());
71
- state.how = `launched system ${cfg.channel} with your profile (${cfg.userDataDir})`;
72
- }
73
- else {
74
- const browser = await chromium.launch({
75
- channel: cfg.channel,
76
- headless: !cfg.headful,
77
- args: STEALTH_ARGS,
78
- });
79
- state.browser = browser;
80
- state.context = await browser.newContext();
81
- state.page = await state.context.newPage();
82
- state.how = `launched system ${cfg.channel} (ephemeral profile)`;
83
- }
84
- cfg.log(state.how);
85
- return state.page;
86
- }
87
- export function makeBrowserTools(cfg) {
88
- const state = { browser: null, context: null, page: null, how: "" };
89
- const navigate = {
90
- descriptor: {
91
- name: "browser_navigate",
92
- description: "Open a URL in the user's local browser and return the page title. Uses their real Chrome (real cookies/session).",
93
- inputSchema: {
94
- type: "object",
95
- properties: { url: { type: "string", description: "Absolute http(s) URL to open." } },
96
- required: ["url"],
97
- },
98
- },
99
- async run(args) {
100
- const url = String(args.url ?? "");
101
- if (!/^https?:\/\//i.test(url))
102
- return textResult("url must be an absolute http(s) URL", true);
103
- const page = await ensurePage(state, cfg);
104
- await page.goto(url, { waitUntil: "domcontentloaded", timeout: 45_000 });
105
- const title = await page.title();
106
- return textResult(`Navigated to ${page.url()}\nTitle: ${title}\n(${state.how})`);
107
- },
108
- };
109
- const getText = {
110
- descriptor: {
111
- name: "browser_get_text",
112
- description: "Return the visible text of the current page (optionally a CSS selector).",
113
- inputSchema: {
114
- type: "object",
115
- properties: { selector: { type: "string", description: "Optional CSS selector; defaults to <body>." } },
116
- },
117
- },
118
- async run(args) {
119
- if (!state.page || state.page.isClosed())
120
- return textResult("no page open — call browser_navigate first", true);
121
- const selector = typeof args.selector === "string" && args.selector ? args.selector : "body";
122
- const text = await state.page.locator(selector).first().innerText({ timeout: 15_000 }).catch(() => "");
123
- return textResult(text.slice(0, 8000) || "(no text found)");
124
- },
125
- };
126
- const click = {
127
- descriptor: {
128
- name: "browser_click",
129
- description: "Click the first element matching a CSS selector on the current page.",
130
- inputSchema: {
131
- type: "object",
132
- properties: { selector: { type: "string" } },
133
- required: ["selector"],
134
- },
135
- },
136
- async run(args) {
137
- if (!state.page || state.page.isClosed())
138
- return textResult("no page open — call browser_navigate first", true);
139
- const selector = String(args.selector ?? "");
140
- await state.page.locator(selector).first().click({ timeout: 15_000 });
141
- return textResult(`clicked ${selector}\nNow at: ${state.page.url()}`);
142
- },
143
- };
144
- const screenshot = {
145
- descriptor: {
146
- name: "browser_screenshot",
147
- description: "Capture a screenshot of the current page. The image travels back to the server and is saved to your workspace; the tool returns its path (call bridge_view_image to look at it).",
148
- inputSchema: {
149
- type: "object",
150
- properties: { fullPage: { type: "boolean", description: "Capture the full scrollable page (default false)." } },
151
- },
152
- },
153
- async run(args) {
154
- if (!state.page || state.page.isClosed())
155
- return textResult("no page open — call browser_navigate first", true);
156
- const buf = await state.page.screenshot({ fullPage: args.fullPage === true, type: "png" });
157
- // Return the bytes as an MCP image block so the server can save
158
- // them under the user's workspace. Bytes do NOT enter the agent
159
- // context by default — the server stores + surfaces only a path.
160
- return {
161
- content: [
162
- { type: "text", text: `screenshot of ${state.page.url()}` },
163
- { type: "image", data: buf.toString("base64"), mimeType: "image/png" },
164
- ],
165
- };
166
- },
167
- };
168
- return [navigate, getText, click, screenshot];
169
- }
170
- //# sourceMappingURL=browser.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"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"}