@flrande/bak-extension 0.6.3 → 0.6.5

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.
@@ -6,18 +6,97 @@
6
6
  var portInput = document.getElementById("port");
7
7
  var debugRichTextInput = document.getElementById("debugRichText");
8
8
  var saveBtn = document.getElementById("save");
9
+ var reconnectBtn = document.getElementById("reconnect");
9
10
  var disconnectBtn = document.getElementById("disconnect");
11
+ var connectionStateEl = document.getElementById("connectionState");
12
+ var tokenStateEl = document.getElementById("tokenState");
13
+ var reconnectStateEl = document.getElementById("reconnectState");
14
+ var connectionUrlEl = document.getElementById("connectionUrl");
15
+ var lastErrorEl = document.getElementById("lastError");
16
+ var lastBindingUpdateEl = document.getElementById("lastBindingUpdate");
17
+ var extensionVersionEl = document.getElementById("extensionVersion");
18
+ var sessionSummaryEl = document.getElementById("sessionSummary");
19
+ var sessionListEl = document.getElementById("sessionList");
20
+ var latestState = null;
10
21
  function setStatus(text, bad = false) {
11
22
  statusEl.textContent = text;
12
23
  statusEl.style.color = bad ? "#dc2626" : "#0f172a";
13
24
  }
25
+ function formatTimeAgo(at) {
26
+ if (typeof at !== "number") {
27
+ return "never";
28
+ }
29
+ const deltaSeconds = Math.max(0, Math.round((Date.now() - at) / 1e3));
30
+ if (deltaSeconds < 5) {
31
+ return "just now";
32
+ }
33
+ if (deltaSeconds < 60) {
34
+ return `${deltaSeconds}s ago`;
35
+ }
36
+ const deltaMinutes = Math.round(deltaSeconds / 60);
37
+ if (deltaMinutes < 60) {
38
+ return `${deltaMinutes}m ago`;
39
+ }
40
+ const deltaHours = Math.round(deltaMinutes / 60);
41
+ return `${deltaHours}h ago`;
42
+ }
43
+ function renderSessionBindings(state) {
44
+ sessionSummaryEl.textContent = `${state.count} sessions, ${state.attachedCount} attached, ${state.tabCount} tabs, ${state.detachedCount} detached`;
45
+ sessionListEl.replaceChildren();
46
+ for (const item of state.items) {
47
+ const li = document.createElement("li");
48
+ const location = item.windowId === null ? "no window" : `window ${item.windowId}`;
49
+ const active = item.activeTabId === null ? "no active tab" : `active ${item.activeTabId}`;
50
+ li.textContent = `${item.label}: ${item.tabCount} tabs, ${location}, ${active}`;
51
+ if (item.detached) {
52
+ li.style.color = "#b45309";
53
+ }
54
+ sessionListEl.appendChild(li);
55
+ }
56
+ }
57
+ function renderConnectionDetails(state) {
58
+ connectionStateEl.textContent = state.connectionState;
59
+ tokenStateEl.textContent = state.hasToken ? "configured" : "missing";
60
+ connectionUrlEl.textContent = state.wsUrl;
61
+ extensionVersionEl.textContent = state.extensionVersion;
62
+ if (state.manualDisconnect) {
63
+ reconnectStateEl.textContent = "manual disconnect";
64
+ } else if (typeof state.nextReconnectInMs === "number") {
65
+ const seconds = Math.max(0, Math.ceil(state.nextReconnectInMs / 100) / 10);
66
+ reconnectStateEl.textContent = `attempt ${state.reconnectAttempt}, retry in ${seconds}s`;
67
+ } else if (state.connected) {
68
+ reconnectStateEl.textContent = "connected";
69
+ } else {
70
+ reconnectStateEl.textContent = "idle";
71
+ }
72
+ if (state.lastError) {
73
+ const context = state.lastErrorContext ? `${state.lastErrorContext}: ` : "";
74
+ lastErrorEl.textContent = `${context}${state.lastError} (${formatTimeAgo(state.lastErrorAt)})`;
75
+ } else {
76
+ lastErrorEl.textContent = "none";
77
+ }
78
+ if (state.lastBindingUpdateReason) {
79
+ lastBindingUpdateEl.textContent = `${state.lastBindingUpdateReason} (${formatTimeAgo(state.lastBindingUpdateAt)})`;
80
+ } else {
81
+ lastBindingUpdateEl.textContent = "none";
82
+ }
83
+ }
14
84
  async function refreshState() {
15
85
  const state = await chrome.runtime.sendMessage({ type: "bak.getState" });
16
86
  if (state.ok) {
87
+ latestState = state;
17
88
  portInput.value = String(state.port);
18
89
  debugRichTextInput.checked = Boolean(state.debugRichText);
90
+ renderConnectionDetails(state);
91
+ renderSessionBindings(state.sessionBindings);
19
92
  if (state.connected) {
20
93
  setStatus("Connected to bak CLI");
94
+ } else if (state.connectionState === "missing-token") {
95
+ setStatus("Pair token is required", true);
96
+ } else if (state.connectionState === "manual") {
97
+ setStatus("Disconnected manually");
98
+ } else if (state.connectionState === "reconnecting") {
99
+ setStatus("Reconnecting to bak CLI", true);
21
100
  } else if (state.lastError) {
22
101
  setStatus(`Disconnected: ${state.lastError}`, true);
23
102
  } else {
@@ -28,7 +107,7 @@
28
107
  saveBtn.addEventListener("click", async () => {
29
108
  const token = tokenInput.value.trim();
30
109
  const port = Number.parseInt(portInput.value.trim(), 10);
31
- if (!token) {
110
+ if (!token && latestState?.hasToken !== true) {
32
111
  setStatus("Pair token is required", true);
33
112
  return;
34
113
  }
@@ -38,10 +117,15 @@
38
117
  }
39
118
  await chrome.runtime.sendMessage({
40
119
  type: "bak.updateConfig",
41
- token,
120
+ ...token ? { token } : {},
42
121
  port,
43
122
  debugRichText: debugRichTextInput.checked
44
123
  });
124
+ tokenInput.value = "";
125
+ await refreshState();
126
+ });
127
+ reconnectBtn.addEventListener("click", async () => {
128
+ await chrome.runtime.sendMessage({ type: "bak.reconnectNow" });
45
129
  await refreshState();
46
130
  });
47
131
  disconnectBtn.addEventListener("click", async () => {
@@ -49,4 +133,10 @@
49
133
  await refreshState();
50
134
  });
51
135
  void refreshState();
136
+ var refreshInterval = window.setInterval(() => {
137
+ void refreshState();
138
+ }, 1e3);
139
+ window.addEventListener("unload", () => {
140
+ window.clearInterval(refreshInterval);
141
+ });
52
142
  })();
package/dist/popup.html CHANGED
@@ -70,9 +70,50 @@
70
70
  background: #e2e8f0;
71
71
  color: #0f172a;
72
72
  }
73
+ #reconnect {
74
+ background: #dbeafe;
75
+ color: #1d4ed8;
76
+ }
73
77
  #status {
74
78
  margin-top: 10px;
75
79
  font-size: 12px;
80
+ font-weight: 600;
81
+ }
82
+ .panel {
83
+ margin-top: 12px;
84
+ padding: 10px;
85
+ border: 1px solid #cbd5e1;
86
+ border-radius: 8px;
87
+ background: rgba(255, 255, 255, 0.8);
88
+ }
89
+ .panel h2 {
90
+ margin: 0 0 8px;
91
+ font-size: 12px;
92
+ }
93
+ .meta-grid {
94
+ display: grid;
95
+ grid-template-columns: auto 1fr;
96
+ gap: 6px 10px;
97
+ font-size: 11px;
98
+ }
99
+ .meta-grid dt {
100
+ color: #475569;
101
+ }
102
+ .meta-grid dd {
103
+ margin: 0;
104
+ color: #0f172a;
105
+ word-break: break-word;
106
+ }
107
+ #sessionList {
108
+ margin: 0;
109
+ padding-left: 16px;
110
+ font-size: 11px;
111
+ color: #0f172a;
112
+ }
113
+ #sessionList:empty::before {
114
+ content: "No tracked sessions";
115
+ color: #64748b;
116
+ margin-left: -16px;
76
117
  }
77
118
  .hint {
78
119
  margin-top: 10px;
@@ -85,7 +126,7 @@
85
126
  <h1>Browser Agent Kit</h1>
86
127
  <label>
87
128
  Pair token
88
- <input id="token" placeholder="paste token from `bak pair`" />
129
+ <input id="token" placeholder="paste token from `bak pair` or leave blank to keep the saved token" />
89
130
  </label>
90
131
  <label>
91
132
  CLI port
@@ -97,9 +138,39 @@
97
138
  </label>
98
139
  <div class="row">
99
140
  <button id="save">Save & Connect</button>
141
+ <button id="reconnect">Reconnect</button>
142
+ </div>
143
+ <div class="row">
100
144
  <button id="disconnect">Disconnect</button>
101
145
  </div>
102
146
  <div id="status">Checking...</div>
147
+ <div class="panel">
148
+ <h2>Connection</h2>
149
+ <dl class="meta-grid">
150
+ <dt>State</dt>
151
+ <dd id="connectionState">-</dd>
152
+ <dt>Token</dt>
153
+ <dd id="tokenState">-</dd>
154
+ <dt>Reconnect</dt>
155
+ <dd id="reconnectState">-</dd>
156
+ <dt>CLI URL</dt>
157
+ <dd id="connectionUrl">-</dd>
158
+ <dt>Last error</dt>
159
+ <dd id="lastError">-</dd>
160
+ <dt>Last binding</dt>
161
+ <dd id="lastBindingUpdate">-</dd>
162
+ <dt>Extension</dt>
163
+ <dd id="extensionVersion">-</dd>
164
+ </dl>
165
+ </div>
166
+ <div class="panel">
167
+ <h2>Sessions</h2>
168
+ <dl class="meta-grid">
169
+ <dt>Tracked</dt>
170
+ <dd id="sessionSummary">-</dd>
171
+ </dl>
172
+ <ul id="sessionList"></ul>
173
+ </div>
103
174
  <div class="hint">Extension only connects to ws://127.0.0.1</div>
104
175
  <script src="./popup.global.js"></script>
105
176
  </body>
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@flrande/bak-extension",
3
- "version": "0.6.3",
3
+ "version": "0.6.5",
4
4
  "type": "module",
5
5
  "dependencies": {
6
- "@flrande/bak-protocol": "0.6.3"
6
+ "@flrande/bak-protocol": "0.6.5"
7
7
  },
8
8
  "devDependencies": {
9
9
  "@types/chrome": "^0.1.14",
package/public/popup.html CHANGED
@@ -70,9 +70,50 @@
70
70
  background: #e2e8f0;
71
71
  color: #0f172a;
72
72
  }
73
+ #reconnect {
74
+ background: #dbeafe;
75
+ color: #1d4ed8;
76
+ }
73
77
  #status {
74
78
  margin-top: 10px;
75
79
  font-size: 12px;
80
+ font-weight: 600;
81
+ }
82
+ .panel {
83
+ margin-top: 12px;
84
+ padding: 10px;
85
+ border: 1px solid #cbd5e1;
86
+ border-radius: 8px;
87
+ background: rgba(255, 255, 255, 0.8);
88
+ }
89
+ .panel h2 {
90
+ margin: 0 0 8px;
91
+ font-size: 12px;
92
+ }
93
+ .meta-grid {
94
+ display: grid;
95
+ grid-template-columns: auto 1fr;
96
+ gap: 6px 10px;
97
+ font-size: 11px;
98
+ }
99
+ .meta-grid dt {
100
+ color: #475569;
101
+ }
102
+ .meta-grid dd {
103
+ margin: 0;
104
+ color: #0f172a;
105
+ word-break: break-word;
106
+ }
107
+ #sessionList {
108
+ margin: 0;
109
+ padding-left: 16px;
110
+ font-size: 11px;
111
+ color: #0f172a;
112
+ }
113
+ #sessionList:empty::before {
114
+ content: "No tracked sessions";
115
+ color: #64748b;
116
+ margin-left: -16px;
76
117
  }
77
118
  .hint {
78
119
  margin-top: 10px;
@@ -85,7 +126,7 @@
85
126
  <h1>Browser Agent Kit</h1>
86
127
  <label>
87
128
  Pair token
88
- <input id="token" placeholder="paste token from `bak pair`" />
129
+ <input id="token" placeholder="paste token from `bak pair` or leave blank to keep the saved token" />
89
130
  </label>
90
131
  <label>
91
132
  CLI port
@@ -97,9 +138,39 @@
97
138
  </label>
98
139
  <div class="row">
99
140
  <button id="save">Save & Connect</button>
141
+ <button id="reconnect">Reconnect</button>
142
+ </div>
143
+ <div class="row">
100
144
  <button id="disconnect">Disconnect</button>
101
145
  </div>
102
146
  <div id="status">Checking...</div>
147
+ <div class="panel">
148
+ <h2>Connection</h2>
149
+ <dl class="meta-grid">
150
+ <dt>State</dt>
151
+ <dd id="connectionState">-</dd>
152
+ <dt>Token</dt>
153
+ <dd id="tokenState">-</dd>
154
+ <dt>Reconnect</dt>
155
+ <dd id="reconnectState">-</dd>
156
+ <dt>CLI URL</dt>
157
+ <dd id="connectionUrl">-</dd>
158
+ <dt>Last error</dt>
159
+ <dd id="lastError">-</dd>
160
+ <dt>Last binding</dt>
161
+ <dd id="lastBindingUpdate">-</dd>
162
+ <dt>Extension</dt>
163
+ <dd id="extensionVersion">-</dd>
164
+ </dl>
165
+ </div>
166
+ <div class="panel">
167
+ <h2>Sessions</h2>
168
+ <dl class="meta-grid">
169
+ <dt>Tracked</dt>
170
+ <dd id="sessionSummary">-</dd>
171
+ </dl>
172
+ <ul id="sessionList"></ul>
173
+ </div>
103
174
  <div class="hint">Extension only connects to ws://127.0.0.1</div>
104
175
  <script src="./popup.global.js"></script>
105
176
  </body>