@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.
- package/app/TianshuBridge.swift +46 -11
- package/package.json +1 -1
package/app/TianshuBridge.swift
CHANGED
|
@@ -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
|
|
20
|
-
var
|
|
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.
|
|
95
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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": {
|