@tianshu-ai/local-bridge 0.6.2 → 0.7.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.
@@ -16,8 +16,9 @@ import Foundation
16
16
  struct Config: Codable {
17
17
  var server: String = "ws://localhost:3110/ws"
18
18
  var token: String = ""
19
- var engine: String = "own" // "own" | "stealth"
20
- var headless: Bool = false
19
+ var browser: Bool = true // expose browser tools (on by default)
20
+ var engine: String = "own" // "own" | "stealth" (browser sub-option)
21
+ var headless: Bool = false // browser sub-option
21
22
  var shell: Bool = false // expose exec + file sync (opt-in)
22
23
  var device: String = "" // empty → hostname
23
24
 
@@ -91,8 +92,12 @@ final class Bridge {
91
92
  }
92
93
  var args = ["--server", cfg.server]
93
94
  if !cfg.token.isEmpty { args += ["--token", cfg.token] }
94
- if cfg.engine == "stealth" { args += ["--browser-engine", "stealth"] }
95
- if cfg.headless { args += ["--headless"] }
95
+ if cfg.browser {
96
+ if cfg.engine == "stealth" { args += ["--browser-engine", "stealth"] }
97
+ if cfg.headless { args += ["--headless"] }
98
+ } else {
99
+ args += ["--no-browser"]
100
+ }
96
101
  if cfg.shell { args += ["--shell"] }
97
102
  if !cfg.device.isEmpty { args += ["--device", cfg.device] }
98
103
 
@@ -176,9 +181,9 @@ final class AppController: NSObject, NSApplicationDelegate {
176
181
  menu.addItem(statusMI)
177
182
  menu.addItem(NSMenuItem(title: "Server: \(cfg.server)", action: nil, keyEquivalent: ""))
178
183
  let eng = cfg.engine == "stealth" ? "stealth" : "own"
184
+ let browserDesc = cfg.browser ? "\(eng)\(cfg.headless ? " (headless)" : "")" : "off"
185
+ menu.addItem(NSMenuItem(title: "Browser: \(browserDesc)", action: nil, keyEquivalent: ""))
179
186
  menu.addItem(NSMenuItem(title: "Shell: \(cfg.shell ? "on" : "off")", action: nil, keyEquivalent: ""))
180
- menu.addItem(NSMenuItem(title: "Browser: \(eng)\(cfg.headless ? " (headless)" : "")",
181
- action: nil, keyEquivalent: ""))
182
187
  menu.addItem(.separator())
183
188
 
184
189
  if bridge.isRunning {
@@ -218,6 +223,7 @@ final class AppController: NSObject, NSApplicationDelegate {
218
223
 
219
224
  private var serverField: NSTextField!
220
225
  private var tokenField: NSTextField!
226
+ private var browserCheck: NSButton!
221
227
  private var enginePopup: NSPopUpButton!
222
228
  private var headlessCheck: NSButton!
223
229
  private var shellCheck: NSButton!
@@ -247,25 +253,41 @@ final class AppController: NSObject, NSApplicationDelegate {
247
253
  tokenField = NSTextField(frame: NSRect(x: 110, y: 170, width: 250, height: 24))
248
254
  tokenField.stringValue = cfg.token; v.addSubview(tokenField)
249
255
 
250
- v.addSubview(label("Browser", 134))
251
- enginePopup = NSPopUpButton(frame: NSRect(x: 110, y: 130, width: 250, height: 26))
256
+ // ── Capabilities (Browser + Shell are sibling optional tools) ──
257
+ let capLabel = NSTextField(labelWithString: "Capabilities")
258
+ capLabel.frame = NSRect(x: 16, y: 138, width: 200, height: 18)
259
+ capLabel.font = NSFont.boldSystemFont(ofSize: 12)
260
+ v.addSubview(capLabel)
261
+
262
+ // Browser (top-level toggle) + its sub-options (engine, headless).
263
+ browserCheck = NSButton(checkboxWithTitle: "Browser (control a local browser)",
264
+ target: self, action: #selector(toggleBrowserOptions))
265
+ browserCheck.frame = NSRect(x: 24, y: 116, width: 300, height: 20)
266
+ browserCheck.state = cfg.browser ? .on : .off
267
+ v.addSubview(browserCheck)
268
+
269
+ enginePopup = NSPopUpButton(frame: NSRect(x: 44, y: 88, width: 250, height: 26))
252
270
  enginePopup.addItems(withTitles: ["own (your Chrome)", "stealth (CloakBrowser)"])
253
271
  enginePopup.selectItem(at: cfg.engine == "stealth" ? 1 : 0)
254
272
  v.addSubview(enginePopup)
255
273
 
256
274
  headlessCheck = NSButton(checkboxWithTitle: "Headless (no window)", target: nil, action: nil)
257
- headlessCheck.frame = NSRect(x: 110, y: 98, width: 250, height: 20)
275
+ headlessCheck.frame = NSRect(x: 44, y: 66, width: 250, height: 20)
258
276
  headlessCheck.state = cfg.headless ? .on : .off
259
277
  v.addSubview(headlessCheck)
260
278
 
279
+ // Shell (sibling top-level toggle).
261
280
  shellCheck = NSButton(checkboxWithTitle: "Shell (run commands + sync files)", target: nil, action: nil)
262
- shellCheck.frame = NSRect(x: 110, y: 70, width: 260, height: 20)
281
+ shellCheck.frame = NSRect(x: 24, y: 40, width: 300, height: 20)
263
282
  shellCheck.state = cfg.shell ? .on : .off
264
283
  shellCheck.toolTip = "Exposes exec + file sync on your machine, jailed to ~/.tianshu_shell. Off by default; enable only for a server you trust."
265
284
  v.addSubview(shellCheck)
266
285
 
286
+ // Grey out browser sub-options when browser is off.
287
+ updateBrowserOptionsEnabled()
288
+
267
289
  let save = NSButton(title: "Save & Restart", target: self, action: #selector(saveSettings))
268
- save.frame = NSRect(x: 200, y: 18, width: 160, height: 32)
290
+ save.frame = NSRect(x: 200, y: 8, width: 160, height: 30)
269
291
  save.bezelStyle = .rounded
270
292
  v.addSubview(save)
271
293
  return v
@@ -275,6 +297,7 @@ final class AppController: NSObject, NSApplicationDelegate {
275
297
  cfg.server = serverField.stringValue.trimmingCharacters(in: .whitespaces)
276
298
  cfg.token = tokenField.stringValue.trimmingCharacters(in: .whitespaces)
277
299
  cfg.engine = enginePopup.indexOfSelectedItem == 1 ? "stealth" : "own"
300
+ cfg.browser = browserCheck.state == .on
278
301
  cfg.headless = headlessCheck.state == .on
279
302
  cfg.shell = shellCheck.state == .on
280
303
  cfg.save()
@@ -307,6 +330,18 @@ final class AppController: NSObject, NSApplicationDelegate {
307
330
  if let e = params["engine"] { enginePopup.selectItem(at: e == "stealth" ? 1 : 0) }
308
331
  if let h = params["headless"] { headlessCheck.state = (h == "1" || h == "true") ? .on : .off }
309
332
  if let s = params["shell"] { shellCheck.state = (s == "1" || s == "true") ? .on : .off }
333
+ if let b = params["browser"] { browserCheck.state = (b == "1" || b == "true") ? .on : .off }
334
+ updateBrowserOptionsEnabled()
335
+ }
336
+
337
+ // Enable/disable the browser sub-options (engine + headless) to
338
+ // reflect the top-level Browser toggle — they're meaningless when
339
+ // browser is off.
340
+ @objc func toggleBrowserOptions() { updateBrowserOptionsEnabled() }
341
+ private func updateBrowserOptionsEnabled() {
342
+ let on = browserCheck?.state == .on
343
+ enginePopup?.isEnabled = on
344
+ headlessCheck?.isEnabled = on
310
345
  }
311
346
 
312
347
  private func alert(_ title: String, _ body: String) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tianshu-ai/local-bridge",
3
- "version": "0.6.2",
3
+ "version": "0.7.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": {