browser-cookie-bridge 1.5.5 → 1.5.6

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Browser Cookie Bridge",
4
- "version": "1.5.5",
4
+ "version": "1.5.6",
5
5
  "description": "Transfers selected browser data locally between supported browsers and embedded app browsers.",
6
6
  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5o6lDkXzU/23Jm2QRk4mfuxNnr3VlEIjRHcZr93Gdo7PI7asHJQhigaMGT6UOz0lkaTn1F+TGIPlsJo9GNBSsxbCfxWoBSXcFQFrPolY5LEfKaMtZQQ6eb4UAnp+bbUwb1den4On0piWU47Yzl6i0Jcdg4EG5H1kCSF/6nJsbKgF7OTaR/3drULu40yRvflzSXRhly3UDO7c5mgHJsaMwVV+VILsxbcPOoRINjuo3zDC737HFs67dpf38xF3tjSVL0HURAWKKobMvfABiDfVEm5O0Lvf+57d1Ib12QLT2qtVXNDy3iYwX+w2S0wH2vIMsfvoFPlRdmeqft70kZOqXwIDAQAB",
7
7
  "permissions": ["alarms", "cookies", "history"],
@@ -10,8 +10,8 @@
10
10
  <key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
11
11
  <key>CFBundleName</key><string>Browser Cookie Bridge</string>
12
12
  <key>CFBundlePackageType</key><string>APPL</string>
13
- <key>CFBundleShortVersionString</key><string>1.5.5</string>
14
- <key>CFBundleVersion</key><string>42</string>
13
+ <key>CFBundleShortVersionString</key><string>1.5.6</string>
14
+ <key>CFBundleVersion</key><string>43</string>
15
15
  <key>LSMinimumSystemVersion</key><string>13.5</string>
16
16
  <key>NSHighResolutionCapable</key><true/>
17
17
  </dict>
@@ -34,6 +34,7 @@ struct BraveCodexSyncApp: App {
34
34
  final class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
35
35
  weak var model: SyncModel?
36
36
  private weak var mainWindow: NSWindow?
37
+ private var grokBotResultPanel: NSPanel?
37
38
  private var statusItem: NSStatusItem?
38
39
  private var syncMenuItem: NSMenuItem?
39
40
  private var updateMenuItem: NSMenuItem?
@@ -63,6 +64,18 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
63
64
  name: .syncStateChanged,
64
65
  object: nil
65
66
  )
67
+ NotificationCenter.default.addObserver(
68
+ self,
69
+ selector: #selector(showMainWindowNotification(_:)),
70
+ name: .showMainWindow,
71
+ object: nil
72
+ )
73
+ NotificationCenter.default.addObserver(
74
+ self,
75
+ selector: #selector(presentGrokBotResultNotification(_:)),
76
+ name: .presentGrokBotResult,
77
+ object: nil
78
+ )
66
79
  }
67
80
 
68
81
  func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { false }
@@ -186,8 +199,56 @@ final class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
186
199
  }
187
200
  }
188
201
 
202
+ @objc private func showMainWindowNotification(_ notification: Notification) {
203
+ showMainWindow()
204
+ }
205
+
206
+ @objc private func presentGrokBotResultNotification(_ notification: Notification) {
207
+ guard let model else { return }
208
+ showMainWindow()
209
+ grokBotResultPanel?.close()
210
+ grokBotResultPanel = nil
211
+ DispatchQueue.main.async { [weak self] in
212
+ guard let self, let model = self.model else { return }
213
+ self.presentGrokBotResultPanel(model: model)
214
+ }
215
+ }
216
+
217
+ private func presentGrokBotResultPanel(model: SyncModel) {
218
+ let panel = NSPanel(
219
+ contentRect: NSRect(x: 0, y: 0, width: 520, height: 520),
220
+ styleMask: [.titled, .closable, .fullSizeContentView],
221
+ backing: .buffered,
222
+ defer: false
223
+ )
224
+ panel.title = "Grok Bot transfer ready"
225
+ panel.titlebarAppearsTransparent = false
226
+ panel.isFloatingPanel = true
227
+ panel.level = .modalPanel
228
+ panel.collectionBehavior = [.moveToActiveSpace, .fullScreenAuxiliary]
229
+ panel.isReleasedWhenClosed = false
230
+ panel.center()
231
+ let dismissPanel = { [weak self] in
232
+ self?.grokBotResultPanel?.close()
233
+ self?.grokBotResultPanel = nil
234
+ }
235
+ panel.contentView = NSHostingView(
236
+ rootView: GrokBotResultSheet(onDone: dismissPanel).environmentObject(model)
237
+ )
238
+ panel.makeKeyAndOrderFront(nil)
239
+ NSApp.activate(ignoringOtherApps: true)
240
+ grokBotResultPanel = panel
241
+ }
242
+
189
243
  private func showMainWindow() {
190
244
  NSApp.setActivationPolicy(.regular)
245
+ if mainWindow == nil || mainWindow?.isVisible == false {
246
+ let candidate = NSApp.windows.first(where: { $0.canBecomeMain && $0.title == "Browser Cookie Bridge" })
247
+ ?? NSApp.windows.first(where: { $0.canBecomeMain })
248
+ ?? NSApp.windows.first
249
+ mainWindow = candidate
250
+ mainWindow?.delegate = self
251
+ }
191
252
  mainWindow?.makeKeyAndOrderFront(nil)
192
253
  NSApp.activate(ignoringOtherApps: true)
193
254
  }
@@ -241,9 +302,6 @@ struct ContentView: View {
241
302
  .sheet(isPresented: $model.showingBrowserlessSetup) {
242
303
  BrowserlessSetupSheet().environmentObject(model)
243
304
  }
244
- .sheet(isPresented: $model.showingGrokBotResult) {
245
- GrokBotResultSheet().environmentObject(model)
246
- }
247
305
  }
248
306
 
249
307
  private var header: some View {
@@ -1170,6 +1228,7 @@ enum Theme {
1170
1228
  struct GrokBotResultSheet: View {
1171
1229
  @EnvironmentObject private var model: SyncModel
1172
1230
  @Environment(\.dismiss) private var dismiss
1231
+ var onDone: (() -> Void)?
1173
1232
 
1174
1233
  var body: some View {
1175
1234
  VStack(alignment: .leading, spacing: 16) {
@@ -1228,7 +1287,10 @@ struct GrokBotResultSheet: View {
1228
1287
  NSPasteboard.general.setString(model.grokBotPrompt, forType: .string)
1229
1288
  }
1230
1289
  Spacer()
1231
- Button("Done") { dismiss() }
1290
+ Button("Done") {
1291
+ onDone?()
1292
+ dismiss()
1293
+ }
1232
1294
  .keyboardShortcut(.defaultAction)
1233
1295
  }
1234
1296
  .controlSize(.regular)
@@ -8,6 +8,8 @@ extension Notification.Name {
8
8
  static let nativeAlert = Notification.Name("BraveCodexSync.nativeAlert")
9
9
  static let updateStateChanged = Notification.Name("BraveCodexSync.updateStateChanged")
10
10
  static let syncStateChanged = Notification.Name("BraveCodexSync.syncStateChanged")
11
+ static let showMainWindow = Notification.Name("BraveCodexSync.showMainWindow")
12
+ static let presentGrokBotResult = Notification.Name("BraveCodexSync.presentGrokBotResult")
11
13
  }
12
14
 
13
15
  struct NativeAlert {
@@ -99,7 +101,6 @@ final class SyncModel: ObservableObject {
99
101
  @Published var browserlessOnlyDomains = ""
100
102
  @Published var grokBotOnlyDomains = ""
101
103
  @Published var showingBrowserlessSetup = false
102
- @Published var showingGrokBotResult = false
103
104
  @Published var grokBotPrompt = ""
104
105
  @Published var grokBotOutputPath = ""
105
106
  @Published var browserlessAssessment: BrowserlessProfileAssessment?
@@ -118,6 +119,16 @@ final class SyncModel: ObservableObject {
118
119
  private var appLoginAgent: URL { home.appending(path: "Library/LaunchAgents/com.apoorvdarshan.brave-codex-cookie-sync.app-login.plist") }
119
120
  private var endpointStatusTimer: Timer?
120
121
  private var updateTimer: Timer?
122
+ private var activeGrokBotOutputPath: String?
123
+
124
+ private static let grokBotFallbackPrompt = """
125
+ On your Grok Bot cloud computer only — do not access my local Mac and do not print cookie values.
126
+
127
+ 1. Save the attached GrokBot-Import.bcbx to the cloud computer.
128
+ 2. Unzip it: unzip -o GrokBot-Import.bcbx -d bcb-import && cd bcb-import
129
+ 3. Run: node import.mjs
130
+ 4. Report only how many cookies were imported per domain, then delete the bcb-import folder and any copies of the bundle.
131
+ """
121
132
  private var didCheckAfterLaunch = false
122
133
  private var didConsumeUpdateResult = false
123
134
  private var assessedBrowserID: String?
@@ -725,7 +736,10 @@ final class SyncModel: ObservableObject {
725
736
  var environment: [String: String] = [:]
726
737
  var arguments = ["sync", "--timeout", isBrowserlessTarget ? "900" : "300"]
727
738
  if let grokBotOutputPath {
739
+ activeGrokBotOutputPath = grokBotOutputPath
728
740
  arguments.append(contentsOf: ["--output", grokBotOutputPath])
741
+ } else {
742
+ activeGrokBotOutputPath = nil
729
743
  }
730
744
  if isBrowserlessTarget {
731
745
  guard let token = BrowserlessCredentialStore.read() else {
@@ -760,12 +774,14 @@ final class SyncModel: ObservableObject {
760
774
  self.state = partial ? .warning : .success
761
775
  if self.isGrokBotTarget {
762
776
  let parsed = self.parseGrokBotResult(from: output)
763
- let outputPath = parsed?.outputPath ?? grokBotOutputPath ?? self.grokBotOutputPath
764
- self.grokBotOutputPath = outputPath
765
- self.grokBotPrompt = parsed?.prompt ?? Self.grokBotFallbackPrompt
777
+ let outputPath = parsed?.outputPath ?? self.activeGrokBotOutputPath ?? grokBotOutputPath ?? self.grokBotOutputPath
778
+ let prompt = parsed?.prompt ?? Self.grokBotFallbackPrompt
779
+ if !outputPath.isEmpty {
780
+ self.presentGrokBotResultSheet(prompt: prompt, outputPath: outputPath)
781
+ }
782
+ self.activeGrokBotOutputPath = nil
766
783
  self.primaryStatus = partial ? "Grok Bot transfer created with warnings" : "Grok Bot transfer file ready"
767
784
  self.secondaryStatus = self.lastMeaningfulLine(output) ?? "Attach the .bcbx file to any Grok Bot and paste the prompt"
768
- self.presentGrokBotResultSheet()
769
785
  } else {
770
786
  self.primaryStatus = self.isBrowserlessTarget
771
787
  ? (partial ? "Browserless profile uploaded with omissions" : "Browserless profile uploaded")
@@ -1171,21 +1187,6 @@ final class SyncModel: ObservableObject {
1171
1187
  isDirectTarget || selectedTargetID == "browserless" || isGrokBotTarget ? [] : [selectedSourceID, selectedTargetID]
1172
1188
  }
1173
1189
 
1174
- private static let grokBotFallbackPrompt = """
1175
- On your Grok Bot cloud computer only — do not access my local Mac and do not print cookie values.
1176
-
1177
- 1. Save the attached GrokBot-Import.bcbx to the cloud computer.
1178
- 2. Unzip it: unzip -o GrokBot-Import.bcbx -d bcb-import && cd bcb-import
1179
- 3. Run: node import.mjs
1180
- 4. Report only how many cookies were imported per domain, then delete the bcb-import folder and any copies of the bundle.
1181
- """
1182
-
1183
- private func presentGrokBotResultSheet() {
1184
- DispatchQueue.main.async { [weak self] in
1185
- self?.showingGrokBotResult = true
1186
- }
1187
- }
1188
-
1189
1190
  private struct GrokBotResultPayload: Decodable {
1190
1191
  let outputPath: String
1191
1192
  let prompt: String
@@ -1200,6 +1201,15 @@ On your Grok Bot cloud computer only — do not access my local Mac and do not p
1200
1201
  return try? JSONDecoder().decode(GrokBotResultPayload.self, from: data)
1201
1202
  }
1202
1203
 
1204
+ private func presentGrokBotResultSheet(prompt: String, outputPath: String) {
1205
+ grokBotPrompt = prompt
1206
+ grokBotOutputPath = outputPath
1207
+ NSPasteboard.general.clearContents()
1208
+ NSPasteboard.general.setString(prompt, forType: .string)
1209
+ NotificationCenter.default.post(name: .showMainWindow, object: nil)
1210
+ NotificationCenter.default.post(name: .presentGrokBotResult, object: nil)
1211
+ }
1212
+
1203
1213
  private func updateEndpointRunningStatus() {
1204
1214
  let wasDirectTargetRunning = directTargetRunning
1205
1215
  codexRunning = NSWorkspace.shared.runningApplications.contains {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browser-cookie-bridge",
3
- "version": "1.5.5",
3
+ "version": "1.5.6",
4
4
  "description": "Local-first cookie and session transfer for macOS with optional Browserless upload",
5
5
  "type": "module",
6
6
  "bin": {