clankerbend 0.1.0 → 0.1.2
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/DEVELOPERS.md +6 -6
- package/README.md +31 -14
- package/apps/README.md +3 -3
- package/apps/sticky-notes/README.md +2 -2
- package/apps/sticky-notes/{onewhack.manifest.json → clankerbend.manifest.json} +1 -1
- package/apps/sticky-notes/package.json +3 -3
- package/apps/sticky-notes/public/app.js +42 -9
- package/apps/sticky-notes/src/sticky-notes-app.js +17 -21
- package/apps/vim-nav/README.md +22 -22
- package/apps/vim-nav/{onewhack.manifest.json → clankerbend.manifest.json} +4 -4
- package/apps/vim-nav/package.json +3 -3
- package/apps/vim-nav/public/app.js +44 -11
- package/apps/vim-nav/public/index.html +2 -2
- package/apps/vim-nav/server.mjs +2 -2
- package/apps/vim-nav/src/vim-nav-app.js +5 -5
- package/assets/clankerbend-banner.webp +0 -0
- package/assets/clankerbend-demo-thumbnail.webp +0 -0
- package/assets/clankerbend.svg +26 -0
- package/cli.mjs +22 -11
- package/docs/app-lifecycle.md +9 -9
- package/docs/app-manifest.md +4 -4
- package/docs/author-guide.md +5 -5
- package/docs/launcher-profiles.md +45 -10
- package/docs/protocol.md +248 -241
- package/host/README.md +4 -4
- package/host/src/app-registry.js +8 -6
- package/host/src/codex-desktop-cdp-adapter.js +85 -65
- package/host/src/codex-desktop-renderer-bridge.js +839 -270
- package/host/src/index.js +186 -34
- package/launch/accounts.mjs +360 -0
- package/launch/codex-mux-adapter.mjs +175 -0
- package/launch/profiles.mjs +40 -16
- package/launch/runtime-paths.mjs +9 -6
- package/launch/test-accounts.mjs +71 -0
- package/package.json +12 -10
- package/scripts/release-npm.mjs +1 -2
- package/server.mjs +21 -14
- package/assets/onewhack.jpg +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
(function installCodexVimNavigator() {
|
|
2
2
|
const VIM_NAV_APP_ID = "onewill.vim-nav";
|
|
3
|
-
const BRIDGE_VERSION =
|
|
4
|
-
const RUNTIME_KEY = "
|
|
3
|
+
const BRIDGE_VERSION = 115;
|
|
4
|
+
const RUNTIME_KEY = "__clankerbendRuntime";
|
|
5
5
|
const STYLE_ID = "codex-vim-nav-style";
|
|
6
6
|
const ANNOTATION_CLASS = "codex-vim-nav-annotation";
|
|
7
7
|
const ANCHOR_CLASS = "codex-vim-nav-anchor";
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
const HIGHLIGHT_CLASS = "codex-vim-nav-highlight";
|
|
10
10
|
const STATUS_CHROME_CLASS = "codex-vim-nav-status-chrome";
|
|
11
11
|
const MODE_BADGE_ID = "codex-vim-nav-mode-badge";
|
|
12
|
-
const HOST_UI_CLASS = "
|
|
13
|
-
const SELECTION_MENU_ID = "
|
|
14
|
-
const
|
|
15
|
-
const
|
|
12
|
+
const HOST_UI_CLASS = "clankerbend-host-ui";
|
|
13
|
+
const SELECTION_MENU_ID = "clankerbend-selection-menu";
|
|
14
|
+
const ACCOUNT_SWITCHER_ID = "clankerbend-account-switcher";
|
|
15
|
+
const OVERLAY_ID = "clankerbend-anchored-overlay";
|
|
16
|
+
const COMPOSER_CHIPS_ID = "clankerbend-composer-chips";
|
|
16
17
|
const SELECTOR = [
|
|
17
18
|
"[data-content-search-unit-key]",
|
|
18
19
|
"[data-turn-key]",
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
"[data-thread-user-message-navigation-item-id]"
|
|
21
22
|
].join(",");
|
|
22
23
|
|
|
23
|
-
const existingBridge =
|
|
24
|
+
const existingBridge = clankerbendRuntime().getBridge(VIM_NAV_APP_ID);
|
|
24
25
|
if (existingBridge?.name === "vim-nav" && existingBridge?.version === BRIDGE_VERSION) {
|
|
25
26
|
return existingBridge.snapshot();
|
|
26
27
|
}
|
|
@@ -36,9 +37,9 @@
|
|
|
36
37
|
vimMode: false,
|
|
37
38
|
helpOpen: false,
|
|
38
39
|
badgeHidden: readBadgeHidden(),
|
|
39
|
-
|
|
40
|
+
metaDown: false,
|
|
40
41
|
altDown: false,
|
|
41
|
-
|
|
42
|
+
metaAltToggleDown: false,
|
|
42
43
|
pendingKeys: "",
|
|
43
44
|
countPrefix: "",
|
|
44
45
|
anchorOrder: [],
|
|
@@ -60,11 +61,19 @@
|
|
|
60
61
|
lastBottomJump: null,
|
|
61
62
|
lastOrderFallback: null,
|
|
62
63
|
commandChain: Promise.resolve(),
|
|
64
|
+
relativeMoveInFlight: false,
|
|
65
|
+
pendingRelativeDelta: 0,
|
|
63
66
|
hostState: null,
|
|
64
67
|
hostEvents: [],
|
|
65
68
|
activeTextSelection: null,
|
|
66
69
|
lastSelectionMenuAt: 0,
|
|
67
70
|
renderedOverlaySignature: null,
|
|
71
|
+
accountUiStatus: "",
|
|
72
|
+
accountAddOpen: false,
|
|
73
|
+
accountAddLabel: "",
|
|
74
|
+
accountManageOpen: false,
|
|
75
|
+
accountPendingAdoptId: null,
|
|
76
|
+
accountPendingDeleteId: null,
|
|
68
77
|
pendingComposerSubmission: null,
|
|
69
78
|
submittedComposerSubmissions: []
|
|
70
79
|
};
|
|
@@ -119,6 +128,7 @@
|
|
|
119
128
|
color: #241f12 !important;
|
|
120
129
|
}
|
|
121
130
|
#${OVERLAY_ID} button,
|
|
131
|
+
#${ACCOUNT_SWITCHER_ID} button,
|
|
122
132
|
#${COMPOSER_CHIPS_ID} button {
|
|
123
133
|
appearance: none !important;
|
|
124
134
|
border: 0 !important;
|
|
@@ -129,6 +139,202 @@
|
|
|
129
139
|
font: 650 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
130
140
|
padding: 7px 8px !important;
|
|
131
141
|
}
|
|
142
|
+
#${ACCOUNT_SWITCHER_ID} {
|
|
143
|
+
display: grid !important;
|
|
144
|
+
gap: 7px !important;
|
|
145
|
+
min-width: 220px !important;
|
|
146
|
+
max-width: 320px !important;
|
|
147
|
+
border-top: 1px solid rgba(148, 163, 184, .24) !important;
|
|
148
|
+
border-bottom: 1px solid rgba(148, 163, 184, .18) !important;
|
|
149
|
+
margin: 5px 0 !important;
|
|
150
|
+
padding: 8px 4px !important;
|
|
151
|
+
color: inherit !important;
|
|
152
|
+
}
|
|
153
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-head {
|
|
154
|
+
display: flex !important;
|
|
155
|
+
align-items: center !important;
|
|
156
|
+
justify-content: space-between !important;
|
|
157
|
+
gap: 8px !important;
|
|
158
|
+
padding: 0 6px !important;
|
|
159
|
+
}
|
|
160
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-title {
|
|
161
|
+
color: currentColor !important;
|
|
162
|
+
font: 700 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
163
|
+
letter-spacing: 0 !important;
|
|
164
|
+
}
|
|
165
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-status {
|
|
166
|
+
color: color-mix(in srgb, currentColor 62%, transparent) !important;
|
|
167
|
+
font: 500 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
168
|
+
overflow: hidden !important;
|
|
169
|
+
text-overflow: ellipsis !important;
|
|
170
|
+
white-space: nowrap !important;
|
|
171
|
+
}
|
|
172
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-list {
|
|
173
|
+
display: grid !important;
|
|
174
|
+
gap: 2px !important;
|
|
175
|
+
}
|
|
176
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-row {
|
|
177
|
+
display: grid !important;
|
|
178
|
+
grid-template-columns: minmax(0, 1fr) auto !important;
|
|
179
|
+
align-items: center !important;
|
|
180
|
+
gap: 5px !important;
|
|
181
|
+
border-radius: 6px !important;
|
|
182
|
+
padding: 2px !important;
|
|
183
|
+
}
|
|
184
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-row.is-active {
|
|
185
|
+
background: rgba(143, 199, 212, .14) !important;
|
|
186
|
+
}
|
|
187
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-main {
|
|
188
|
+
display: grid !important;
|
|
189
|
+
min-width: 0 !important;
|
|
190
|
+
border-radius: 5px !important;
|
|
191
|
+
padding: 6px !important;
|
|
192
|
+
text-align: left !important;
|
|
193
|
+
color: inherit !important;
|
|
194
|
+
}
|
|
195
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-main:hover,
|
|
196
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-icon:hover {
|
|
197
|
+
background: rgba(148, 163, 184, .16) !important;
|
|
198
|
+
}
|
|
199
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-label,
|
|
200
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-meta {
|
|
201
|
+
overflow: hidden !important;
|
|
202
|
+
text-overflow: ellipsis !important;
|
|
203
|
+
white-space: nowrap !important;
|
|
204
|
+
}
|
|
205
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-label {
|
|
206
|
+
font: 650 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
207
|
+
}
|
|
208
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-meta {
|
|
209
|
+
color: color-mix(in srgb, currentColor 58%, transparent) !important;
|
|
210
|
+
font: 500 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
211
|
+
}
|
|
212
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-icon {
|
|
213
|
+
width: 28px !important;
|
|
214
|
+
height: 28px !important;
|
|
215
|
+
display: inline-grid !important;
|
|
216
|
+
place-items: center !important;
|
|
217
|
+
border-radius: 5px !important;
|
|
218
|
+
color: color-mix(in srgb, currentColor 76%, transparent) !important;
|
|
219
|
+
padding: 0 !important;
|
|
220
|
+
}
|
|
221
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-actions {
|
|
222
|
+
display: grid !important;
|
|
223
|
+
grid-template-columns: 1fr 1fr !important;
|
|
224
|
+
gap: 4px !important;
|
|
225
|
+
}
|
|
226
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-actions button {
|
|
227
|
+
border-radius: 5px !important;
|
|
228
|
+
background: rgba(148, 163, 184, .12) !important;
|
|
229
|
+
color: inherit !important;
|
|
230
|
+
min-width: 0 !important;
|
|
231
|
+
}
|
|
232
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-add-form {
|
|
233
|
+
display: grid !important;
|
|
234
|
+
gap: 6px !important;
|
|
235
|
+
border-radius: 6px !important;
|
|
236
|
+
background: rgba(148, 163, 184, .10) !important;
|
|
237
|
+
padding: 6px !important;
|
|
238
|
+
}
|
|
239
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-add-form input {
|
|
240
|
+
width: 100% !important;
|
|
241
|
+
min-width: 0 !important;
|
|
242
|
+
border: 1px solid rgba(148, 163, 184, .32) !important;
|
|
243
|
+
border-radius: 5px !important;
|
|
244
|
+
background: rgba(0, 0, 0, .18) !important;
|
|
245
|
+
color: inherit !important;
|
|
246
|
+
font: 500 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
247
|
+
outline: none !important;
|
|
248
|
+
padding: 7px 8px !important;
|
|
249
|
+
}
|
|
250
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-add-form input:focus {
|
|
251
|
+
border-color: rgba(143, 199, 212, .76) !important;
|
|
252
|
+
box-shadow: 0 0 0 2px rgba(143, 199, 212, .18) !important;
|
|
253
|
+
}
|
|
254
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-add-actions {
|
|
255
|
+
display: grid !important;
|
|
256
|
+
grid-template-columns: 1fr 1fr !important;
|
|
257
|
+
gap: 4px !important;
|
|
258
|
+
}
|
|
259
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-add-actions button {
|
|
260
|
+
background: rgba(148, 163, 184, .14) !important;
|
|
261
|
+
}
|
|
262
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage {
|
|
263
|
+
display: grid !important;
|
|
264
|
+
gap: 7px !important;
|
|
265
|
+
border-top: 1px solid rgba(148, 163, 184, .18) !important;
|
|
266
|
+
padding-top: 7px !important;
|
|
267
|
+
}
|
|
268
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-head {
|
|
269
|
+
display: flex !important;
|
|
270
|
+
align-items: baseline !important;
|
|
271
|
+
justify-content: space-between !important;
|
|
272
|
+
gap: 8px !important;
|
|
273
|
+
padding: 0 6px !important;
|
|
274
|
+
}
|
|
275
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-head strong {
|
|
276
|
+
font: 700 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
277
|
+
}
|
|
278
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-head span {
|
|
279
|
+
color: color-mix(in srgb, currentColor 58%, transparent) !important;
|
|
280
|
+
font: 500 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
281
|
+
}
|
|
282
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-list {
|
|
283
|
+
display: grid !important;
|
|
284
|
+
gap: 6px !important;
|
|
285
|
+
max-height: 204px !important;
|
|
286
|
+
overflow-y: auto !important;
|
|
287
|
+
overscroll-behavior: contain !important;
|
|
288
|
+
padding-right: 2px !important;
|
|
289
|
+
}
|
|
290
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-list::-webkit-scrollbar {
|
|
291
|
+
width: 8px !important;
|
|
292
|
+
}
|
|
293
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-list::-webkit-scrollbar-thumb {
|
|
294
|
+
border-radius: 999px !important;
|
|
295
|
+
background: rgba(148, 163, 184, .34) !important;
|
|
296
|
+
}
|
|
297
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-row {
|
|
298
|
+
display: grid !important;
|
|
299
|
+
grid-template-columns: minmax(0, 1fr) auto !important;
|
|
300
|
+
align-items: center !important;
|
|
301
|
+
gap: 7px !important;
|
|
302
|
+
border-radius: 6px !important;
|
|
303
|
+
background: rgba(148, 163, 184, .10) !important;
|
|
304
|
+
padding: 6px !important;
|
|
305
|
+
}
|
|
306
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-title {
|
|
307
|
+
display: grid !important;
|
|
308
|
+
min-width: 0 !important;
|
|
309
|
+
}
|
|
310
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-title strong,
|
|
311
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-title span {
|
|
312
|
+
overflow: hidden !important;
|
|
313
|
+
text-overflow: ellipsis !important;
|
|
314
|
+
white-space: nowrap !important;
|
|
315
|
+
}
|
|
316
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-title strong {
|
|
317
|
+
font: 650 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
318
|
+
}
|
|
319
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-title span {
|
|
320
|
+
color: color-mix(in srgb, currentColor 58%, transparent) !important;
|
|
321
|
+
font: 500 11px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
322
|
+
}
|
|
323
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-actions {
|
|
324
|
+
display: flex !important;
|
|
325
|
+
align-items: center !important;
|
|
326
|
+
justify-content: flex-end !important;
|
|
327
|
+
gap: 4px !important;
|
|
328
|
+
}
|
|
329
|
+
#${ACCOUNT_SWITCHER_ID} .clankerbend-account-manage-actions button {
|
|
330
|
+
background: rgba(148, 163, 184, .14) !important;
|
|
331
|
+
white-space: nowrap !important;
|
|
332
|
+
padding: 6px 7px !important;
|
|
333
|
+
}
|
|
334
|
+
#${ACCOUNT_SWITCHER_ID} button:disabled {
|
|
335
|
+
cursor: default !important;
|
|
336
|
+
opacity: .55 !important;
|
|
337
|
+
}
|
|
132
338
|
#${OVERLAY_ID} {
|
|
133
339
|
position: fixed !important;
|
|
134
340
|
z-index: 2147483004 !important;
|
|
@@ -159,7 +365,7 @@
|
|
|
159
365
|
font: 13px/1.35 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
160
366
|
padding: 9px !important;
|
|
161
367
|
}
|
|
162
|
-
#${OVERLAY_ID} .
|
|
368
|
+
#${OVERLAY_ID} .clankerbend-overlay-actions {
|
|
163
369
|
display: flex !important;
|
|
164
370
|
justify-content: flex-end !important;
|
|
165
371
|
gap: 6px !important;
|
|
@@ -168,6 +374,10 @@
|
|
|
168
374
|
background: rgba(80, 65, 20, .78) !important;
|
|
169
375
|
color: #fff7d7 !important;
|
|
170
376
|
}
|
|
377
|
+
#${OVERLAY_ID} button.clankerbend-overlay-secondary {
|
|
378
|
+
background: transparent !important;
|
|
379
|
+
color: rgba(58, 45, 12, .82) !important;
|
|
380
|
+
}
|
|
171
381
|
#${COMPOSER_CHIPS_ID} {
|
|
172
382
|
position: absolute !important;
|
|
173
383
|
z-index: 2147483002 !important;
|
|
@@ -180,7 +390,7 @@
|
|
|
180
390
|
#${COMPOSER_CHIPS_ID}.is-visible {
|
|
181
391
|
display: flex !important;
|
|
182
392
|
}
|
|
183
|
-
#${COMPOSER_CHIPS_ID} .
|
|
393
|
+
#${COMPOSER_CHIPS_ID} .clankerbend-context-chip {
|
|
184
394
|
display: inline-flex !important;
|
|
185
395
|
align-items: center !important;
|
|
186
396
|
gap: 5px !important;
|
|
@@ -194,7 +404,7 @@
|
|
|
194
404
|
padding: 5px 8px !important;
|
|
195
405
|
pointer-events: auto !important;
|
|
196
406
|
}
|
|
197
|
-
.
|
|
407
|
+
.clankerbend-submitted-context-row .clankerbend-context-chip {
|
|
198
408
|
display: inline-flex !important;
|
|
199
409
|
align-items: center !important;
|
|
200
410
|
gap: 5px !important;
|
|
@@ -206,24 +416,24 @@
|
|
|
206
416
|
font: 600 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
|
|
207
417
|
padding: 5px 8px !important;
|
|
208
418
|
}
|
|
209
|
-
.
|
|
419
|
+
.clankerbend-submitted-context-row .clankerbend-context-chip::before {
|
|
210
420
|
content: "□" !important;
|
|
211
421
|
color: #8a7327 !important;
|
|
212
422
|
font-size: 10px !important;
|
|
213
423
|
line-height: 1 !important;
|
|
214
424
|
}
|
|
215
|
-
#${COMPOSER_CHIPS_ID} .
|
|
425
|
+
#${COMPOSER_CHIPS_ID} .clankerbend-context-chip::before {
|
|
216
426
|
content: "□" !important;
|
|
217
427
|
color: #8a7327 !important;
|
|
218
428
|
font-size: 10px !important;
|
|
219
429
|
line-height: 1 !important;
|
|
220
430
|
}
|
|
221
|
-
#${COMPOSER_CHIPS_ID} .
|
|
431
|
+
#${COMPOSER_CHIPS_ID} .clankerbend-context-chip span {
|
|
222
432
|
overflow: hidden !important;
|
|
223
433
|
text-overflow: ellipsis !important;
|
|
224
434
|
white-space: nowrap !important;
|
|
225
435
|
}
|
|
226
|
-
#${COMPOSER_CHIPS_ID} .
|
|
436
|
+
#${COMPOSER_CHIPS_ID} .clankerbend-context-chip button {
|
|
227
437
|
padding: 0 2px !important;
|
|
228
438
|
color: #725f20 !important;
|
|
229
439
|
}
|
|
@@ -380,7 +590,7 @@
|
|
|
380
590
|
const titleRow = document.createElement("div");
|
|
381
591
|
titleRow.className = "codex-vim-nav-title-row";
|
|
382
592
|
const title = document.createElement("strong");
|
|
383
|
-
title.textContent = "
|
|
593
|
+
title.textContent = "VimNav";
|
|
384
594
|
const mode = document.createElement("span");
|
|
385
595
|
mode.className = "codex-vim-nav-state";
|
|
386
596
|
mode.textContent = `[${state.vimMode ? "ON" : "OFF"}]`;
|
|
@@ -388,7 +598,7 @@
|
|
|
388
598
|
dismiss.type = "button";
|
|
389
599
|
dismiss.className = "codex-vim-nav-dismiss";
|
|
390
600
|
dismiss.textContent = "x";
|
|
391
|
-
dismiss.title = "Hide VimNav badge until
|
|
601
|
+
dismiss.title = "Hide VimNav badge until Cmd-Option";
|
|
392
602
|
dismiss.addEventListener("click", (event) => {
|
|
393
603
|
event.preventDefault();
|
|
394
604
|
event.stopPropagation();
|
|
@@ -403,12 +613,23 @@
|
|
|
403
613
|
helpButton.className = "codex-vim-nav-help-toggle";
|
|
404
614
|
helpButton.textContent = "?";
|
|
405
615
|
helpButton.title = "Toggle VimNav help";
|
|
406
|
-
|
|
616
|
+
const activateHelp = (event) => {
|
|
407
617
|
event.preventDefault();
|
|
408
618
|
event.stopPropagation();
|
|
619
|
+
event.stopImmediatePropagation?.();
|
|
620
|
+
if (event.type === "click" && helpButton.dataset.clankerbendPressed === "true") {
|
|
621
|
+
helpButton.dataset.clankerbendPressed = "";
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
if (event.type !== "click" && helpButton.dataset.clankerbendPressed === "true") return;
|
|
625
|
+
if (event.type !== "click") helpButton.dataset.clankerbendPressed = "true";
|
|
409
626
|
toggleHelp();
|
|
410
|
-
}
|
|
411
|
-
|
|
627
|
+
};
|
|
628
|
+
helpButton.addEventListener("pointerdown", activateHelp);
|
|
629
|
+
helpButton.addEventListener("mousedown", activateHelp);
|
|
630
|
+
helpButton.addEventListener("touchstart", activateHelp, { passive: false });
|
|
631
|
+
helpButton.addEventListener("click", activateHelp);
|
|
632
|
+
toggleRow.append("(Cmd-Option toggles, ", helpButton, " for help)");
|
|
412
633
|
badge.appendChild(toggleRow);
|
|
413
634
|
if (buffer) {
|
|
414
635
|
const row = document.createElement("div");
|
|
@@ -1297,13 +1518,13 @@
|
|
|
1297
1518
|
if (!(el instanceof HTMLElement)) continue;
|
|
1298
1519
|
el.classList.add(ANCHOR_CLASS);
|
|
1299
1520
|
el.classList.toggle(CURRENT_CLASS, item.anchorId === state.currentAnchorId);
|
|
1300
|
-
let label = el.querySelector(`.${ANNOTATION_CLASS}[data-anchor-id="${cssEscape(item.anchorId)}"][data-
|
|
1521
|
+
let label = el.querySelector(`.${ANNOTATION_CLASS}[data-anchor-id="${cssEscape(item.anchorId)}"][data-clankerbend-app-id="${VIM_NAV_APP_ID}"]`);
|
|
1301
1522
|
if (!label) {
|
|
1302
1523
|
label = document.createElement("button");
|
|
1303
1524
|
label.type = "button";
|
|
1304
1525
|
label.className = ANNOTATION_CLASS;
|
|
1305
1526
|
label.dataset.anchorId = item.anchorId;
|
|
1306
|
-
label.dataset.
|
|
1527
|
+
label.dataset.clankerbendAppId = VIM_NAV_APP_ID;
|
|
1307
1528
|
label.addEventListener("click", (event) => {
|
|
1308
1529
|
event.preventDefault();
|
|
1309
1530
|
event.stopImmediatePropagation();
|
|
@@ -1318,10 +1539,10 @@
|
|
|
1318
1539
|
}
|
|
1319
1540
|
label.textContent = markerGlyph(item);
|
|
1320
1541
|
label.title = item.indexed
|
|
1321
|
-
? `
|
|
1322
|
-
: `
|
|
1542
|
+
? `VimNav ${item.order}: ${item.inferredRole || item.kind}`
|
|
1543
|
+
: `VimNav index pending: ${item.inferredRole || item.kind}`;
|
|
1323
1544
|
label.setAttribute("aria-label", label.title);
|
|
1324
|
-
|
|
1545
|
+
clankerbendRuntime().placeAnnotation?.(el, {
|
|
1325
1546
|
appId: VIM_NAV_APP_ID,
|
|
1326
1547
|
anchorId: item.anchorId,
|
|
1327
1548
|
markerId: `vim-nav:${item.anchorId}`,
|
|
@@ -1329,9 +1550,9 @@
|
|
|
1329
1550
|
element: label
|
|
1330
1551
|
}) || el.insertAdjacentElement("afterbegin", label);
|
|
1331
1552
|
}
|
|
1332
|
-
|
|
1333
|
-
document.querySelectorAll(`.${ANNOTATION_CLASS}[data-
|
|
1334
|
-
if (!ids.has(node.dataset.anchorId) && !node.closest(".
|
|
1553
|
+
clankerbendRuntime().removeAnnotations?.(VIM_NAV_APP_ID, ids);
|
|
1554
|
+
document.querySelectorAll(`.${ANNOTATION_CLASS}[data-clankerbend-app-id="${VIM_NAV_APP_ID}"]`).forEach((node) => {
|
|
1555
|
+
if (!ids.has(node.dataset.anchorId) && !node.closest(".clankerbend-transcript-annotation-slot")) node.remove();
|
|
1335
1556
|
});
|
|
1336
1557
|
}
|
|
1337
1558
|
|
|
@@ -1429,123 +1650,6 @@
|
|
|
1429
1650
|
});
|
|
1430
1651
|
}
|
|
1431
1652
|
|
|
1432
|
-
async function jumpRelativeMountedAcrossGap(delta, currentOrder, beforeAnchorId) {
|
|
1433
|
-
const targetIndex = currentOrder - 1 + delta;
|
|
1434
|
-
const indexedTarget = await mountTargetForIndex(targetIndex, delta, {
|
|
1435
|
-
approximate: true,
|
|
1436
|
-
preferExact: true
|
|
1437
|
-
});
|
|
1438
|
-
if (indexedTarget && indexedTarget.anchorId !== beforeAnchorId) {
|
|
1439
|
-
setCurrent(indexedTarget.anchorId, "adapter", indexedTarget.order - 1);
|
|
1440
|
-
return scrollToAnchor(indexedTarget.anchorId, {
|
|
1441
|
-
behavior: "auto",
|
|
1442
|
-
block: "start",
|
|
1443
|
-
indexHint: indexedTarget.order - 1
|
|
1444
|
-
});
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
for (let attempt = 0; attempt < 5; attempt += 1) {
|
|
1448
|
-
const mounted = anchors().sort((a, b) => a.order - b.order);
|
|
1449
|
-
const adjacent = delta < 0
|
|
1450
|
-
? [...mounted].reverse().find((item) => item.order < currentOrder && item.anchorId !== beforeAnchorId)
|
|
1451
|
-
: mounted.find((item) => item.order > currentOrder && item.anchorId !== beforeAnchorId);
|
|
1452
|
-
if (adjacent) {
|
|
1453
|
-
setCurrent(adjacent.anchorId, "adapter", adjacent.order - 1);
|
|
1454
|
-
return scrollToAnchor(adjacent.anchorId, {
|
|
1455
|
-
behavior: "auto",
|
|
1456
|
-
block: blockForAnchorVisibility(adjacent.anchorId, "start"),
|
|
1457
|
-
indexHint: adjacent.order - 1
|
|
1458
|
-
});
|
|
1459
|
-
}
|
|
1460
|
-
await delay(90);
|
|
1461
|
-
}
|
|
1462
|
-
|
|
1463
|
-
const searchRoot = () => findScrollContainer() || nearestScrollContainer(anchorElements()[0] || findAnchor(state.currentAnchorId) || document.body);
|
|
1464
|
-
let root = searchRoot();
|
|
1465
|
-
const viewport = Math.min(root.clientHeight || window.innerHeight || 720, 1200);
|
|
1466
|
-
const step = delta < 0
|
|
1467
|
-
? Math.max(520, viewport * 1.45)
|
|
1468
|
-
: Math.max(520, Math.min(viewport, 900) * 1.35);
|
|
1469
|
-
const attempts = [];
|
|
1470
|
-
for (let attempt = 0; attempt < 18; attempt += 1) {
|
|
1471
|
-
root = searchRoot();
|
|
1472
|
-
const beforeTop = scrollTopOf(root);
|
|
1473
|
-
scrollRootTo(root, scrollTopForViewportDelta(root, delta < 0 ? -step : step));
|
|
1474
|
-
await delay(80);
|
|
1475
|
-
const mounted = anchors().sort((a, b) => a.order - b.order);
|
|
1476
|
-
const target = delta < 0
|
|
1477
|
-
? [...mounted].reverse().find((item) =>
|
|
1478
|
-
item.order < currentOrder && item.anchorId !== beforeAnchorId
|
|
1479
|
-
)
|
|
1480
|
-
: mounted.find((item) =>
|
|
1481
|
-
item.order > currentOrder && item.anchorId !== beforeAnchorId
|
|
1482
|
-
);
|
|
1483
|
-
attempts.push({
|
|
1484
|
-
attempt,
|
|
1485
|
-
beforeTop: Math.round(beforeTop),
|
|
1486
|
-
afterTop: Math.round(scrollTopOf(root)),
|
|
1487
|
-
mounted: mounted.map((item) => item.order)
|
|
1488
|
-
});
|
|
1489
|
-
state.lastMountSearch = { mode: "relative-mounted-gap", direction: delta, currentOrder, attempts: attempts.slice(-5) };
|
|
1490
|
-
if (target) {
|
|
1491
|
-
setCurrent(target.anchorId, "adapter", target.order - 1);
|
|
1492
|
-
return scrollToAnchor(target.anchorId, {
|
|
1493
|
-
behavior: "auto",
|
|
1494
|
-
block: "start",
|
|
1495
|
-
indexHint: target.order - 1
|
|
1496
|
-
});
|
|
1497
|
-
}
|
|
1498
|
-
if (Math.abs(scrollTopOf(root) - beforeTop) <= 1) break;
|
|
1499
|
-
}
|
|
1500
|
-
if (delta > 0) {
|
|
1501
|
-
root = searchRoot();
|
|
1502
|
-
scrollRootTo(root, scrollRootRange(root).max);
|
|
1503
|
-
await delay(120);
|
|
1504
|
-
const mounted = anchors().sort((a, b) => a.order - b.order);
|
|
1505
|
-
const target = mounted.find((item) =>
|
|
1506
|
-
item.order > currentOrder && item.anchorId !== beforeAnchorId
|
|
1507
|
-
) || mounted[mounted.length - 1];
|
|
1508
|
-
if (target && target.anchorId !== beforeAnchorId && target.order > currentOrder) {
|
|
1509
|
-
setCurrent(target.anchorId, "adapter", target.order - 1);
|
|
1510
|
-
return scrollToAnchor(target.anchorId, {
|
|
1511
|
-
behavior: "auto",
|
|
1512
|
-
block: "start",
|
|
1513
|
-
indexHint: target.order - 1
|
|
1514
|
-
});
|
|
1515
|
-
}
|
|
1516
|
-
}
|
|
1517
|
-
if (delta > 0 && currentOrder < lastKnownIndex() + 1) {
|
|
1518
|
-
return jumpToBottom();
|
|
1519
|
-
}
|
|
1520
|
-
if (delta < 0 && currentOrder > 1) {
|
|
1521
|
-
return jumpToIndex(0, { block: "start", direction: -1, behavior: "auto" });
|
|
1522
|
-
}
|
|
1523
|
-
return jumpRelativeMounted(delta);
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
|
-
function renderedCurrentOrder() {
|
|
1527
|
-
const desiredTop = topVisibleInset() + 8;
|
|
1528
|
-
const visibleMarker = Array.from(document.querySelectorAll(`.${ANNOTATION_CLASS}`))
|
|
1529
|
-
.map((marker) => {
|
|
1530
|
-
const rect = marker.getBoundingClientRect();
|
|
1531
|
-
return {
|
|
1532
|
-
order: Number(marker.textContent.trim()),
|
|
1533
|
-
top: rect.top,
|
|
1534
|
-
bottom: rect.bottom
|
|
1535
|
-
};
|
|
1536
|
-
})
|
|
1537
|
-
.filter((item) =>
|
|
1538
|
-
Number.isSafeInteger(item.order) &&
|
|
1539
|
-
item.bottom >= topVisibleInset() &&
|
|
1540
|
-
item.top <= viewportSafeBottom()
|
|
1541
|
-
)
|
|
1542
|
-
.sort((a, b) => Math.abs(a.top - desiredTop) - Math.abs(b.top - desiredTop))[0];
|
|
1543
|
-
if (visibleMarker) return visibleMarker.order;
|
|
1544
|
-
const currentMarker = document.querySelector(`.${CURRENT_CLASS} .${ANNOTATION_CLASS}`);
|
|
1545
|
-
const currentValue = Number(currentMarker?.textContent?.trim());
|
|
1546
|
-
return Number.isSafeInteger(currentValue) ? currentValue : null;
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
1653
|
function mountedFloorTargetForIndex(index) {
|
|
1550
1654
|
const visible = viewportVisibleAnchors(anchors()).sort((a, b) => a.order - b.order);
|
|
1551
1655
|
const visibleExact = visible.find((item) => item.order - 1 === index);
|
|
@@ -1791,59 +1895,56 @@
|
|
|
1791
1895
|
});
|
|
1792
1896
|
}
|
|
1793
1897
|
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
const
|
|
1898
|
+
function jumpRelativeFast(delta) {
|
|
1899
|
+
if (!hasAppServerOrder()) return jumpRelativeMounted(delta);
|
|
1900
|
+
const startIndex = currentIndex();
|
|
1901
|
+
const targetIndex = startIndex + delta;
|
|
1902
|
+
const lastIndex = lastKnownIndex();
|
|
1903
|
+
if (targetIndex < 0 || targetIndex > lastIndex) {
|
|
1904
|
+
state.lastRelativeDebug = {
|
|
1905
|
+
delta,
|
|
1906
|
+
path: "edge",
|
|
1907
|
+
startIndex,
|
|
1908
|
+
targetIndex,
|
|
1909
|
+
lastIndex
|
|
1910
|
+
};
|
|
1911
|
+
return {
|
|
1912
|
+
ok: true,
|
|
1913
|
+
noop: true,
|
|
1914
|
+
edge: delta < 0 ? "top" : "bottom",
|
|
1915
|
+
anchorId: state.currentAnchorId
|
|
1916
|
+
};
|
|
1917
|
+
}
|
|
1918
|
+
const targetId = state.anchorOrder[targetIndex] || state.anchorIdByIndex[targetIndex] || null;
|
|
1797
1919
|
const mounted = anchors().sort((a, b) => a.order - b.order);
|
|
1798
|
-
const
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
}
|
|
1802
|
-
if (!currentVisible && visible.length && !selectedIsMounted) {
|
|
1803
|
-
const target = delta < 0
|
|
1804
|
-
? visible.sort((a, b) => a.viewportTop - b.viewportTop)[0]
|
|
1805
|
-
: visible.sort((a, b) => b.viewportBottom - a.viewportBottom)[0];
|
|
1806
|
-
if (target) setCurrent(target.anchorId, "adapter", target.order - 1);
|
|
1807
|
-
}
|
|
1808
|
-
const renderedOrder = renderedCurrentOrder();
|
|
1809
|
-
const selectedOrder = state.currentAnchorId ? anchorNumber(state.currentAnchorId) : null;
|
|
1810
|
-
const currentAnchorOrder = selectedIsMounted ? selectedOrder : renderedOrder || selectedOrder;
|
|
1811
|
-
const currentOrder = currentAnchorOrder != null && currentAnchorOrder <= state.anchorOrder.length
|
|
1812
|
-
? currentAnchorOrder
|
|
1813
|
-
: Number.isInteger(state.currentIndexValue) ? state.currentIndexValue + 1 : null;
|
|
1814
|
-
const adjacentMounted = delta < 0
|
|
1815
|
-
? [...mounted].reverse().find((item) => item.order < currentOrder && item.anchorId !== state.currentAnchorId)
|
|
1816
|
-
: mounted.find((item) => item.order > currentOrder && item.anchorId !== state.currentAnchorId);
|
|
1920
|
+
const target = targetId
|
|
1921
|
+
? mounted.find((item) => item.anchorId === targetId)
|
|
1922
|
+
: mounted.find((item) => item.order - 1 === targetIndex);
|
|
1817
1923
|
state.lastRelativeDebug = {
|
|
1818
1924
|
delta,
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
selectedIsMounted,
|
|
1824
|
-
adjacent: adjacentMounted ? { order: adjacentMounted.order, anchorId: adjacentMounted.anchorId } : null,
|
|
1925
|
+
path: "fast",
|
|
1926
|
+
startIndex,
|
|
1927
|
+
targetIndex,
|
|
1928
|
+
target: target ? { order: target.order, anchorId: target.anchorId } : null,
|
|
1825
1929
|
mounted: mounted.map((item) => item.order)
|
|
1826
1930
|
};
|
|
1827
|
-
if (
|
|
1828
|
-
|
|
1829
|
-
|
|
1931
|
+
if (!target || !findAnchor(target.anchorId)) {
|
|
1932
|
+
return jumpToIndex(targetIndex, {
|
|
1933
|
+
block: "start",
|
|
1934
|
+
direction: delta,
|
|
1830
1935
|
behavior: "auto",
|
|
1831
|
-
|
|
1832
|
-
|
|
1936
|
+
approximate: true,
|
|
1937
|
+
preferExact: true,
|
|
1938
|
+
resolveMissing: "floor-on-overshoot",
|
|
1939
|
+
skipScrollIfResolvedFloor: true
|
|
1833
1940
|
});
|
|
1834
1941
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
const afterIndex = state.anchorOrder.indexOf(state.currentAnchorId);
|
|
1842
|
-
const moved = result?.ok &&
|
|
1843
|
-
state.currentAnchorId !== beforeAnchorId &&
|
|
1844
|
-
(delta < 0 ? afterIndex < beforeIndex : afterIndex > beforeIndex);
|
|
1845
|
-
if (moved) return result;
|
|
1846
|
-
return jumpRelativeMountedAcrossGap(delta, currentOrder, beforeAnchorId);
|
|
1942
|
+
setCurrent(target.anchorId, "adapter", target.order - 1);
|
|
1943
|
+
return scrollToAnchor(target.anchorId, {
|
|
1944
|
+
behavior: "auto",
|
|
1945
|
+
block: "start",
|
|
1946
|
+
indexHint: target.order - 1
|
|
1947
|
+
});
|
|
1847
1948
|
}
|
|
1848
1949
|
|
|
1849
1950
|
function jumpToNumberIndex(requested) {
|
|
@@ -2173,14 +2274,14 @@
|
|
|
2173
2274
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
2174
2275
|
}
|
|
2175
2276
|
|
|
2176
|
-
function
|
|
2277
|
+
function clankerbendRuntime() {
|
|
2177
2278
|
if (window[RUNTIME_KEY]?.registerApp) return window[RUNTIME_KEY];
|
|
2178
2279
|
const runtime = {
|
|
2179
2280
|
protocolVersion: null,
|
|
2180
2281
|
hostUrl: null,
|
|
2181
2282
|
apps: {},
|
|
2182
2283
|
registerApp(app) {
|
|
2183
|
-
if (!app?.appId) throw new Error("
|
|
2284
|
+
if (!app?.appId) throw new Error("ClankerBend appId is required");
|
|
2184
2285
|
const current = this.apps[app.appId] || {};
|
|
2185
2286
|
const currentVersion = Number(current.bridge?.version);
|
|
2186
2287
|
const nextVersion = Number(app.bridge?.version);
|
|
@@ -2191,7 +2292,7 @@
|
|
|
2191
2292
|
Number.isFinite(nextVersion) &&
|
|
2192
2293
|
nextVersion < currentVersion
|
|
2193
2294
|
) {
|
|
2194
|
-
throw new Error("
|
|
2295
|
+
throw new Error("ClankerBend app bridge version regressed for " + app.appId);
|
|
2195
2296
|
}
|
|
2196
2297
|
const slot = {
|
|
2197
2298
|
...current,
|
|
@@ -2234,6 +2335,8 @@
|
|
|
2234
2335
|
|
|
2235
2336
|
function applyHostState(hostState) {
|
|
2236
2337
|
state.hostState = hostState || null;
|
|
2338
|
+
settleAccountUiStatus();
|
|
2339
|
+
renderCodexAccountSwitcher();
|
|
2237
2340
|
renderSelectionMenu();
|
|
2238
2341
|
renderOverlay();
|
|
2239
2342
|
renderComposerContextChips();
|
|
@@ -2242,6 +2345,430 @@
|
|
|
2242
2345
|
return { ok: true };
|
|
2243
2346
|
}
|
|
2244
2347
|
|
|
2348
|
+
function settleAccountUiStatus() {
|
|
2349
|
+
if (state.accountUiStatus !== "Saving default...") return;
|
|
2350
|
+
if (state.hostState?.codexAccounts?.switching) return;
|
|
2351
|
+
state.accountUiStatus = "Default saved";
|
|
2352
|
+
setTimeout(() => {
|
|
2353
|
+
if (state.accountUiStatus !== "Default saved") return;
|
|
2354
|
+
state.accountUiStatus = "";
|
|
2355
|
+
renderCodexAccountSwitcher();
|
|
2356
|
+
}, 1400);
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
function codexAccountsState() {
|
|
2360
|
+
return state.hostState?.codexAccounts || null;
|
|
2361
|
+
}
|
|
2362
|
+
|
|
2363
|
+
function visibleElement(el) {
|
|
2364
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
2365
|
+
if (!el.isConnected) return false;
|
|
2366
|
+
if (isHostUiElement(el)) return false;
|
|
2367
|
+
const rect = el.getBoundingClientRect();
|
|
2368
|
+
if (rect.width <= 0 || rect.height <= 0) return false;
|
|
2369
|
+
const style = getComputedStyle(el);
|
|
2370
|
+
return style.visibility !== "hidden" && style.display !== "none";
|
|
2371
|
+
}
|
|
2372
|
+
|
|
2373
|
+
function normalizedText(el) {
|
|
2374
|
+
return String(el?.innerText || el?.textContent || "").replace(/\s+/g, " ").trim();
|
|
2375
|
+
}
|
|
2376
|
+
|
|
2377
|
+
function findLogoutMenuItem() {
|
|
2378
|
+
const candidates = Array.from(document.querySelectorAll("button,a,[role='menuitem'],[role='button']"))
|
|
2379
|
+
.filter(visibleElement)
|
|
2380
|
+
.map((el) => {
|
|
2381
|
+
const text = normalizedText(el);
|
|
2382
|
+
const label = [text, el.getAttribute("aria-label"), el.getAttribute("title")].filter(Boolean).join(" ");
|
|
2383
|
+
return { el, label };
|
|
2384
|
+
})
|
|
2385
|
+
.filter((candidate) => /\b(log\s*out|logout|sign\s*out)\b/i.test(candidate.label));
|
|
2386
|
+
return candidates
|
|
2387
|
+
.map((candidate) => candidate.el.closest?.("button,a,[role='menuitem']") || candidate.el)
|
|
2388
|
+
.find((el) => el instanceof HTMLElement && visibleElement(el)) || null;
|
|
2389
|
+
}
|
|
2390
|
+
|
|
2391
|
+
function accountMenuInsertionParent(logoutItem) {
|
|
2392
|
+
if (!(logoutItem instanceof HTMLElement)) return null;
|
|
2393
|
+
for (let node = logoutItem.parentElement; node && node !== document.body && node !== document.documentElement; node = node.parentElement) {
|
|
2394
|
+
if (isHostUiElement(node)) return null;
|
|
2395
|
+
const rect = node.getBoundingClientRect();
|
|
2396
|
+
if (rect.width < 150 || rect.width > 520 || rect.height < 40 || rect.height > window.innerHeight * 0.9) continue;
|
|
2397
|
+
if (node.contains(logoutItem)) return node;
|
|
2398
|
+
}
|
|
2399
|
+
return logoutItem.parentElement;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
function accountMenuInsertionReference(parent, logoutItem) {
|
|
2403
|
+
if (!(parent instanceof HTMLElement) || !(logoutItem instanceof HTMLElement)) return null;
|
|
2404
|
+
let reference = logoutItem;
|
|
2405
|
+
while (reference?.parentElement && reference.parentElement !== parent) {
|
|
2406
|
+
reference = reference.parentElement;
|
|
2407
|
+
}
|
|
2408
|
+
return reference?.parentElement === parent ? reference : null;
|
|
2409
|
+
}
|
|
2410
|
+
|
|
2411
|
+
function accountUiSignature(accountsState) {
|
|
2412
|
+
const accounts = accountsState?.accounts || [];
|
|
2413
|
+
return JSON.stringify({
|
|
2414
|
+
active: accountsState?.activeAccountId || null,
|
|
2415
|
+
def: accountsState?.clankerbendDefaultAccountId || null,
|
|
2416
|
+
switching: Boolean(accountsState?.switching),
|
|
2417
|
+
status: state.accountUiStatus,
|
|
2418
|
+
addOpen: state.accountAddOpen,
|
|
2419
|
+
manageOpen: state.accountManageOpen,
|
|
2420
|
+
pendingAdopt: state.accountPendingAdoptId,
|
|
2421
|
+
pendingDelete: state.accountPendingDeleteId,
|
|
2422
|
+
accounts: accounts.map((account) => [
|
|
2423
|
+
account.id,
|
|
2424
|
+
account.kind,
|
|
2425
|
+
account.label,
|
|
2426
|
+
account.codexHome,
|
|
2427
|
+
account.auth?.authJson ? 1 : 0,
|
|
2428
|
+
account.backup ? 1 : 0
|
|
2429
|
+
])
|
|
2430
|
+
});
|
|
2431
|
+
}
|
|
2432
|
+
|
|
2433
|
+
function renderCodexAccountSwitcher() {
|
|
2434
|
+
const accountsState = codexAccountsState();
|
|
2435
|
+
const logoutItem = findLogoutMenuItem();
|
|
2436
|
+
if (!accountsState?.available || !logoutItem) {
|
|
2437
|
+
document.getElementById(ACCOUNT_SWITCHER_ID)?.remove();
|
|
2438
|
+
return;
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
const parent = accountMenuInsertionParent(logoutItem);
|
|
2442
|
+
if (!(parent instanceof HTMLElement)) return;
|
|
2443
|
+
const reference = accountMenuInsertionReference(parent, logoutItem);
|
|
2444
|
+
if (!(reference instanceof HTMLElement)) return;
|
|
2445
|
+
let ui = document.getElementById(ACCOUNT_SWITCHER_ID);
|
|
2446
|
+
if (ui && ui.parentElement !== parent) {
|
|
2447
|
+
ui.remove();
|
|
2448
|
+
ui = null;
|
|
2449
|
+
}
|
|
2450
|
+
if (!ui) {
|
|
2451
|
+
ui = document.createElement("div");
|
|
2452
|
+
ui.id = ACCOUNT_SWITCHER_ID;
|
|
2453
|
+
ui.className = HOST_UI_CLASS;
|
|
2454
|
+
stopNativeMenuPropagation(ui);
|
|
2455
|
+
parent.insertBefore(ui, reference);
|
|
2456
|
+
} else if (ui.nextElementSibling !== reference) {
|
|
2457
|
+
parent.insertBefore(ui, reference);
|
|
2458
|
+
}
|
|
2459
|
+
|
|
2460
|
+
const signature = accountUiSignature(accountsState);
|
|
2461
|
+
if (ui.dataset.signature === signature) return;
|
|
2462
|
+
ui.dataset.signature = signature;
|
|
2463
|
+
ui.replaceChildren();
|
|
2464
|
+
|
|
2465
|
+
const head = document.createElement("div");
|
|
2466
|
+
head.className = "clankerbend-account-head";
|
|
2467
|
+
const title = document.createElement("div");
|
|
2468
|
+
title.className = "clankerbend-account-title";
|
|
2469
|
+
title.textContent = "ClankerID";
|
|
2470
|
+
const status = document.createElement("div");
|
|
2471
|
+
status.className = "clankerbend-account-status";
|
|
2472
|
+
status.textContent = state.accountUiStatus || (accountsState.switching ? "Switching..." : `${accountsState.accounts?.length || 0}/${accountsState.maxAccounts || 20}`);
|
|
2473
|
+
head.append(title, status);
|
|
2474
|
+
ui.appendChild(head);
|
|
2475
|
+
|
|
2476
|
+
if (state.accountManageOpen) {
|
|
2477
|
+
ui.appendChild(renderCodexAccountManage(accountsState));
|
|
2478
|
+
} else {
|
|
2479
|
+
const list = document.createElement("div");
|
|
2480
|
+
list.className = "clankerbend-account-list";
|
|
2481
|
+
for (const account of accountsState.accounts || []) {
|
|
2482
|
+
list.appendChild(renderCodexAccountRow(account, accountsState));
|
|
2483
|
+
}
|
|
2484
|
+
ui.appendChild(list);
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
const actions = document.createElement("div");
|
|
2488
|
+
actions.className = "clankerbend-account-actions";
|
|
2489
|
+
const add = document.createElement("button");
|
|
2490
|
+
add.type = "button";
|
|
2491
|
+
add.textContent = "Add account";
|
|
2492
|
+
add.disabled = Boolean(accountsState.switching) || (accountsState.accounts?.length || 0) >= (accountsState.maxAccounts || 20);
|
|
2493
|
+
bindInjectedActivation(add, () => {
|
|
2494
|
+
state.accountAddOpen = true;
|
|
2495
|
+
state.accountUiStatus = "";
|
|
2496
|
+
renderCodexAccountSwitcher();
|
|
2497
|
+
setTimeout(() => {
|
|
2498
|
+
document.querySelector(`#${ACCOUNT_SWITCHER_ID} input[data-clankerbend-account-label]`)?.focus?.({ preventScroll: true });
|
|
2499
|
+
}, 0);
|
|
2500
|
+
});
|
|
2501
|
+
const manage = document.createElement("button");
|
|
2502
|
+
manage.type = "button";
|
|
2503
|
+
manage.textContent = state.accountManageOpen ? "Done" : "Manage";
|
|
2504
|
+
bindInjectedActivation(manage, () => {
|
|
2505
|
+
state.accountManageOpen = !state.accountManageOpen;
|
|
2506
|
+
state.accountPendingAdoptId = null;
|
|
2507
|
+
state.accountPendingDeleteId = null;
|
|
2508
|
+
state.accountUiStatus = "";
|
|
2509
|
+
renderCodexAccountSwitcher();
|
|
2510
|
+
});
|
|
2511
|
+
actions.append(add, manage);
|
|
2512
|
+
ui.appendChild(actions);
|
|
2513
|
+
if (state.accountAddOpen) ui.appendChild(renderCodexAccountAddForm(accountsState));
|
|
2514
|
+
}
|
|
2515
|
+
|
|
2516
|
+
function renderCodexAccountAddForm(accountsState) {
|
|
2517
|
+
const form = document.createElement("div");
|
|
2518
|
+
form.className = "clankerbend-account-add-form";
|
|
2519
|
+
|
|
2520
|
+
const input = document.createElement("input");
|
|
2521
|
+
input.type = "text";
|
|
2522
|
+
input.dataset.clankerbendAccountLabel = "true";
|
|
2523
|
+
input.placeholder = "Account label";
|
|
2524
|
+
input.value = state.accountAddLabel || "";
|
|
2525
|
+
input.autocomplete = "off";
|
|
2526
|
+
input.spellcheck = false;
|
|
2527
|
+
const stopInputEvent = (event) => {
|
|
2528
|
+
event.stopPropagation();
|
|
2529
|
+
event.stopImmediatePropagation?.();
|
|
2530
|
+
};
|
|
2531
|
+
input.addEventListener("pointerdown", stopInputEvent, true);
|
|
2532
|
+
input.addEventListener("mousedown", stopInputEvent, true);
|
|
2533
|
+
input.addEventListener("click", stopInputEvent, true);
|
|
2534
|
+
input.addEventListener("input", () => {
|
|
2535
|
+
state.accountAddLabel = input.value;
|
|
2536
|
+
});
|
|
2537
|
+
input.addEventListener("keydown", (event) => {
|
|
2538
|
+
event.stopPropagation();
|
|
2539
|
+
event.stopImmediatePropagation?.();
|
|
2540
|
+
if (event.key === "Enter") {
|
|
2541
|
+
event.preventDefault();
|
|
2542
|
+
submitCodexAccountAdd(input.value);
|
|
2543
|
+
} else if (event.key === "Escape") {
|
|
2544
|
+
event.preventDefault();
|
|
2545
|
+
cancelCodexAccountAdd();
|
|
2546
|
+
}
|
|
2547
|
+
}, true);
|
|
2548
|
+
|
|
2549
|
+
const buttons = document.createElement("div");
|
|
2550
|
+
buttons.className = "clankerbend-account-add-actions";
|
|
2551
|
+
const cancel = document.createElement("button");
|
|
2552
|
+
cancel.type = "button";
|
|
2553
|
+
cancel.textContent = "Cancel";
|
|
2554
|
+
bindInjectedActivation(cancel, cancelCodexAccountAdd);
|
|
2555
|
+
const create = document.createElement("button");
|
|
2556
|
+
create.type = "button";
|
|
2557
|
+
create.textContent = "Create";
|
|
2558
|
+
create.disabled = Boolean(accountsState.switching);
|
|
2559
|
+
bindInjectedActivation(create, () => submitCodexAccountAdd(input.value));
|
|
2560
|
+
buttons.append(cancel, create);
|
|
2561
|
+
form.append(input, buttons);
|
|
2562
|
+
return form;
|
|
2563
|
+
}
|
|
2564
|
+
|
|
2565
|
+
function cancelCodexAccountAdd() {
|
|
2566
|
+
state.accountAddOpen = false;
|
|
2567
|
+
state.accountAddLabel = "";
|
|
2568
|
+
state.accountUiStatus = "";
|
|
2569
|
+
renderCodexAccountSwitcher();
|
|
2570
|
+
}
|
|
2571
|
+
|
|
2572
|
+
function submitCodexAccountAdd(rawLabel) {
|
|
2573
|
+
const label = String(rawLabel || "").trim();
|
|
2574
|
+
if (!label) {
|
|
2575
|
+
state.accountUiStatus = "Label required";
|
|
2576
|
+
renderCodexAccountSwitcher();
|
|
2577
|
+
setTimeout(() => {
|
|
2578
|
+
if (state.accountUiStatus !== "Label required") return;
|
|
2579
|
+
state.accountUiStatus = "";
|
|
2580
|
+
renderCodexAccountSwitcher();
|
|
2581
|
+
}, 1400);
|
|
2582
|
+
return;
|
|
2583
|
+
}
|
|
2584
|
+
state.accountAddOpen = false;
|
|
2585
|
+
state.accountAddLabel = "";
|
|
2586
|
+
state.accountUiStatus = "Creating...";
|
|
2587
|
+
renderCodexAccountSwitcher();
|
|
2588
|
+
enqueueHostEvent({ kind: "codexAccountCreateAndSwitch", label });
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
function renderCodexAccountManage(accountsState) {
|
|
2592
|
+
const wrap = document.createElement("div");
|
|
2593
|
+
wrap.className = "clankerbend-account-manage";
|
|
2594
|
+
const head = document.createElement("div");
|
|
2595
|
+
head.className = "clankerbend-account-manage-head";
|
|
2596
|
+
const title = document.createElement("strong");
|
|
2597
|
+
title.textContent = "Manage profiles";
|
|
2598
|
+
const count = document.createElement("span");
|
|
2599
|
+
const managed = (accountsState.accounts || []).filter((account) => account.kind === "managed");
|
|
2600
|
+
count.textContent = `${managed.length} managed`;
|
|
2601
|
+
head.append(title, count);
|
|
2602
|
+
wrap.appendChild(head);
|
|
2603
|
+
const list = document.createElement("div");
|
|
2604
|
+
list.className = "clankerbend-account-manage-list";
|
|
2605
|
+
if (!managed.length) {
|
|
2606
|
+
const row = document.createElement("div");
|
|
2607
|
+
row.className = "clankerbend-account-manage-row";
|
|
2608
|
+
const title = document.createElement("div");
|
|
2609
|
+
title.className = "clankerbend-account-manage-title";
|
|
2610
|
+
const strong = document.createElement("strong");
|
|
2611
|
+
strong.textContent = "No managed accounts";
|
|
2612
|
+
const hint = document.createElement("span");
|
|
2613
|
+
hint.textContent = "Create one with Add account.";
|
|
2614
|
+
title.append(strong, hint);
|
|
2615
|
+
row.appendChild(title);
|
|
2616
|
+
list.appendChild(row);
|
|
2617
|
+
wrap.appendChild(list);
|
|
2618
|
+
return wrap;
|
|
2619
|
+
}
|
|
2620
|
+
for (const account of managed) list.appendChild(renderCodexAccountManageRow(account, accountsState));
|
|
2621
|
+
wrap.appendChild(list);
|
|
2622
|
+
return wrap;
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
function renderCodexAccountManageRow(account, accountsState) {
|
|
2626
|
+
const row = document.createElement("div");
|
|
2627
|
+
row.className = "clankerbend-account-manage-row";
|
|
2628
|
+
row.title = accountCodexHomeTitle(account);
|
|
2629
|
+
const title = document.createElement("div");
|
|
2630
|
+
title.className = "clankerbend-account-manage-title";
|
|
2631
|
+
const strong = document.createElement("strong");
|
|
2632
|
+
strong.textContent = account.label || account.id;
|
|
2633
|
+
const hint = document.createElement("span");
|
|
2634
|
+
const pendingAdopt = state.accountPendingAdoptId === account.id;
|
|
2635
|
+
const pendingDelete = state.accountPendingDeleteId === account.id;
|
|
2636
|
+
hint.textContent = pendingAdopt
|
|
2637
|
+
? "Replace ~/.codex with this profile; current primary is backed up."
|
|
2638
|
+
: pendingDelete
|
|
2639
|
+
? "Hide this profile and move its files to archive storage."
|
|
2640
|
+
: [account.auth?.authJson ? "signed in" : "not signed in", account.backup ? "backup" : ""].filter(Boolean).join(" · ");
|
|
2641
|
+
title.append(strong, hint);
|
|
2642
|
+
|
|
2643
|
+
const actions = document.createElement("div");
|
|
2644
|
+
actions.className = "clankerbend-account-manage-actions";
|
|
2645
|
+
const adopt = document.createElement("button");
|
|
2646
|
+
adopt.type = "button";
|
|
2647
|
+
adopt.textContent = pendingAdopt ? "Replace ~/.codex" : "Make primary";
|
|
2648
|
+
adopt.title = "Make this the primary Codex home";
|
|
2649
|
+
adopt.disabled = Boolean(accountsState.switching);
|
|
2650
|
+
bindInjectedActivation(adopt, () => {
|
|
2651
|
+
if (!pendingAdopt) {
|
|
2652
|
+
state.accountPendingAdoptId = account.id;
|
|
2653
|
+
state.accountPendingDeleteId = null;
|
|
2654
|
+
state.accountUiStatus = "";
|
|
2655
|
+
renderCodexAccountSwitcher();
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
state.accountUiStatus = "Making primary...";
|
|
2659
|
+
state.accountPendingAdoptId = null;
|
|
2660
|
+
renderCodexAccountSwitcher();
|
|
2661
|
+
enqueueHostEvent({ kind: "codexAccountAdoptAsPrimary", accountId: account.id });
|
|
2662
|
+
});
|
|
2663
|
+
|
|
2664
|
+
const remove = document.createElement("button");
|
|
2665
|
+
remove.type = "button";
|
|
2666
|
+
remove.textContent = pendingDelete ? "Archive profile" : "Archive";
|
|
2667
|
+
remove.title = "Archive this managed profile";
|
|
2668
|
+
remove.disabled = Boolean(accountsState.switching) || account.id === accountsState.activeAccountId;
|
|
2669
|
+
bindInjectedActivation(remove, () => {
|
|
2670
|
+
if (!pendingDelete) {
|
|
2671
|
+
state.accountPendingDeleteId = account.id;
|
|
2672
|
+
state.accountPendingAdoptId = null;
|
|
2673
|
+
state.accountUiStatus = "";
|
|
2674
|
+
renderCodexAccountSwitcher();
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
state.accountUiStatus = "Archiving...";
|
|
2678
|
+
state.accountPendingDeleteId = null;
|
|
2679
|
+
renderCodexAccountSwitcher();
|
|
2680
|
+
enqueueHostEvent({ kind: "codexAccountDelete", accountId: account.id });
|
|
2681
|
+
});
|
|
2682
|
+
|
|
2683
|
+
actions.append(adopt, remove);
|
|
2684
|
+
row.append(title, actions);
|
|
2685
|
+
return row;
|
|
2686
|
+
}
|
|
2687
|
+
|
|
2688
|
+
function stopNativeMenuPropagation(el) {
|
|
2689
|
+
const stop = (event) => {
|
|
2690
|
+
event.stopPropagation();
|
|
2691
|
+
event.stopImmediatePropagation?.();
|
|
2692
|
+
};
|
|
2693
|
+
el.addEventListener("pointerdown", stop);
|
|
2694
|
+
el.addEventListener("mousedown", stop);
|
|
2695
|
+
el.addEventListener("touchstart", stop, { passive: false });
|
|
2696
|
+
el.addEventListener("click", stop);
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
function bindInjectedActivation(button, handler) {
|
|
2700
|
+
let lastRunAt = 0;
|
|
2701
|
+
const run = (event) => {
|
|
2702
|
+
event.preventDefault();
|
|
2703
|
+
event.stopPropagation();
|
|
2704
|
+
event.stopImmediatePropagation?.();
|
|
2705
|
+
if (button.disabled) return;
|
|
2706
|
+
const now = Date.now();
|
|
2707
|
+
if (now - lastRunAt < 450) return;
|
|
2708
|
+
lastRunAt = now;
|
|
2709
|
+
handler(event);
|
|
2710
|
+
};
|
|
2711
|
+
button.addEventListener("pointerdown", run, true);
|
|
2712
|
+
button.addEventListener("mousedown", run, true);
|
|
2713
|
+
button.addEventListener("touchstart", run, { capture: true, passive: false });
|
|
2714
|
+
button.addEventListener("click", run, true);
|
|
2715
|
+
}
|
|
2716
|
+
|
|
2717
|
+
function renderCodexAccountRow(account, accountsState) {
|
|
2718
|
+
const row = document.createElement("div");
|
|
2719
|
+
row.className = `clankerbend-account-row${account.id === accountsState.activeAccountId ? " is-active" : ""}`;
|
|
2720
|
+
|
|
2721
|
+
const main = document.createElement("button");
|
|
2722
|
+
main.type = "button";
|
|
2723
|
+
main.className = "clankerbend-account-main";
|
|
2724
|
+
main.disabled = Boolean(accountsState.switching) || account.id === accountsState.activeAccountId;
|
|
2725
|
+
main.title = [
|
|
2726
|
+
account.id === accountsState.activeAccountId ? "Current Codex account profile" : `Switch to ${account.label || account.id}`,
|
|
2727
|
+
accountCodexHomeTitle(account)
|
|
2728
|
+
].filter(Boolean).join("\n");
|
|
2729
|
+
bindInjectedActivation(main, () => {
|
|
2730
|
+
if (account.id === accountsState.activeAccountId) return;
|
|
2731
|
+
state.accountUiStatus = "Switching...";
|
|
2732
|
+
renderCodexAccountSwitcher();
|
|
2733
|
+
enqueueHostEvent({ kind: "codexAccountSwitch", accountId: account.id });
|
|
2734
|
+
});
|
|
2735
|
+
|
|
2736
|
+
const label = document.createElement("span");
|
|
2737
|
+
label.className = "clankerbend-account-label";
|
|
2738
|
+
label.textContent = account.label || account.id;
|
|
2739
|
+
const meta = document.createElement("span");
|
|
2740
|
+
meta.className = "clankerbend-account-meta";
|
|
2741
|
+
meta.textContent = [
|
|
2742
|
+
account.kind,
|
|
2743
|
+
account.id === accountsState.clankerbendDefaultAccountId ? "default" : "",
|
|
2744
|
+
account.auth?.authJson ? "signed in" : "not signed in"
|
|
2745
|
+
].filter(Boolean).join(" · ");
|
|
2746
|
+
main.append(label, meta);
|
|
2747
|
+
|
|
2748
|
+
const def = document.createElement("button");
|
|
2749
|
+
def.type = "button";
|
|
2750
|
+
def.className = "clankerbend-account-icon";
|
|
2751
|
+
def.textContent = account.id === accountsState.clankerbendDefaultAccountId ? "✓" : "☆";
|
|
2752
|
+
def.setAttribute("aria-label", account.id === accountsState.clankerbendDefaultAccountId ? "Launches by default" : "Launch by default");
|
|
2753
|
+
def.title = [
|
|
2754
|
+
account.id === accountsState.clankerbendDefaultAccountId ? "Launches by default" : "Launch by default",
|
|
2755
|
+
accountCodexHomeTitle(account)
|
|
2756
|
+
].filter(Boolean).join("\n");
|
|
2757
|
+
def.disabled = Boolean(accountsState.switching) || account.id === accountsState.clankerbendDefaultAccountId;
|
|
2758
|
+
bindInjectedActivation(def, () => {
|
|
2759
|
+
state.accountUiStatus = "Saving default...";
|
|
2760
|
+
renderCodexAccountSwitcher();
|
|
2761
|
+
enqueueHostEvent({ kind: "codexAccountSetDefault", accountId: account.id });
|
|
2762
|
+
});
|
|
2763
|
+
|
|
2764
|
+
row.append(main, def);
|
|
2765
|
+
return row;
|
|
2766
|
+
}
|
|
2767
|
+
|
|
2768
|
+
function accountCodexHomeTitle(account) {
|
|
2769
|
+
return account?.codexHome ? `CODEX_HOME: ${account.codexHome}` : "";
|
|
2770
|
+
}
|
|
2771
|
+
|
|
2245
2772
|
function hostSelectionActions() {
|
|
2246
2773
|
return (state.hostState?.selectionActions || [])
|
|
2247
2774
|
.filter((action) => action?.enabled !== false && action.appliesTo === "text-selection");
|
|
@@ -2332,7 +2859,7 @@
|
|
|
2332
2859
|
function hideSelectionMenu() {
|
|
2333
2860
|
const menu = document.getElementById(SELECTION_MENU_ID);
|
|
2334
2861
|
menu?.remove();
|
|
2335
|
-
document.querySelectorAll("[data-
|
|
2862
|
+
document.querySelectorAll("[data-clankerbend-native-selection-action='true']").forEach((node) => node.remove());
|
|
2336
2863
|
}
|
|
2337
2864
|
|
|
2338
2865
|
function selectionPayloadForAction(action, selection) {
|
|
@@ -2419,7 +2946,7 @@
|
|
|
2419
2946
|
|
|
2420
2947
|
function extendNativeSelectionToolbar(toolbar, target) {
|
|
2421
2948
|
if (!(toolbar instanceof HTMLElement)) return;
|
|
2422
|
-
toolbar.dataset.
|
|
2949
|
+
toolbar.dataset.clankerbendNativeSelectionToolbar = "true";
|
|
2423
2950
|
toolbar.style.setProperty("display", "inline-flex", "important");
|
|
2424
2951
|
toolbar.style.setProperty("align-items", "center", "important");
|
|
2425
2952
|
toolbar.style.setProperty("flex-wrap", "nowrap", "important");
|
|
@@ -2465,7 +2992,7 @@
|
|
|
2465
2992
|
triggerSelectionAction(action, selection);
|
|
2466
2993
|
};
|
|
2467
2994
|
button.type = "button";
|
|
2468
|
-
button.dataset.
|
|
2995
|
+
button.dataset.clankerbendNativeSelectionAction = "true";
|
|
2469
2996
|
button.textContent = nativeSelectionButtonLabel(action);
|
|
2470
2997
|
button.title = action.label || action.type;
|
|
2471
2998
|
button.style.cssText = [
|
|
@@ -2503,7 +3030,7 @@
|
|
|
2503
3030
|
function injectNativeSelectionActions(selection, actions) {
|
|
2504
3031
|
const toolbar = nativeSelectionToolbar();
|
|
2505
3032
|
if (!toolbar) return false;
|
|
2506
|
-
document.querySelectorAll("[data-
|
|
3033
|
+
document.querySelectorAll("[data-clankerbend-native-selection-action='true']").forEach((node) => node.remove());
|
|
2507
3034
|
const target = nativeSelectionInsertionTarget(toolbar);
|
|
2508
3035
|
extendNativeSelectionToolbar(toolbar, target);
|
|
2509
3036
|
const referenceButton = nativeSelectionReferenceButton(toolbar);
|
|
@@ -2525,7 +3052,7 @@
|
|
|
2525
3052
|
const actions = hostSelectionActions();
|
|
2526
3053
|
if (!selection || !actions.length) {
|
|
2527
3054
|
menu?.remove();
|
|
2528
|
-
document.querySelectorAll("[data-
|
|
3055
|
+
document.querySelectorAll("[data-clankerbend-native-selection-action='true']").forEach((node) => node.remove());
|
|
2529
3056
|
return;
|
|
2530
3057
|
}
|
|
2531
3058
|
if (injectNativeSelectionActions(selection, actions)) {
|
|
@@ -2563,8 +3090,8 @@
|
|
|
2563
3090
|
}
|
|
2564
3091
|
|
|
2565
3092
|
function overlayFieldValues(el) {
|
|
2566
|
-
return Object.fromEntries([...el.querySelectorAll("[data-
|
|
2567
|
-
.map((input) => [input.dataset.
|
|
3093
|
+
return Object.fromEntries([...el.querySelectorAll("[data-clankerbend-field-id]")]
|
|
3094
|
+
.map((input) => [input.dataset.clankerbendFieldId, input.value || ""]));
|
|
2568
3095
|
}
|
|
2569
3096
|
|
|
2570
3097
|
function positionOverlay(el, overlay) {
|
|
@@ -2613,13 +3140,13 @@
|
|
|
2613
3140
|
return;
|
|
2614
3141
|
}
|
|
2615
3142
|
const currentValues = overlayFieldValues(el);
|
|
2616
|
-
const activeFieldId = document.activeElement?.dataset?.
|
|
3143
|
+
const activeFieldId = document.activeElement?.dataset?.clankerbendFieldId || null;
|
|
2617
3144
|
const fields = (overlay.fields || []).map((field) => {
|
|
2618
3145
|
const input = field.kind === "textarea" ? document.createElement("textarea") : document.createElement("input");
|
|
2619
3146
|
input.name = field.fieldId;
|
|
2620
3147
|
input.placeholder = field.label || field.fieldId;
|
|
2621
3148
|
input.value = currentValues[field.fieldId] ?? field.value ?? "";
|
|
2622
|
-
input.dataset.
|
|
3149
|
+
input.dataset.clankerbendFieldId = field.fieldId;
|
|
2623
3150
|
return input;
|
|
2624
3151
|
});
|
|
2625
3152
|
const titleText = String(overlay.title || "").trim();
|
|
@@ -2627,14 +3154,22 @@
|
|
|
2627
3154
|
const title = titleText && titleText !== firstFieldLabel ? document.createElement("strong") : null;
|
|
2628
3155
|
if (title) title.textContent = titleText;
|
|
2629
3156
|
const actions = document.createElement("div");
|
|
2630
|
-
actions.className = "
|
|
3157
|
+
actions.className = "clankerbend-overlay-actions";
|
|
2631
3158
|
for (const action of overlay.actions || []) {
|
|
2632
3159
|
const button = document.createElement("button");
|
|
2633
3160
|
button.type = "button";
|
|
2634
3161
|
button.textContent = action.label || "Apply";
|
|
3162
|
+
button.className = action.type === "overlay.close" ? "clankerbend-overlay-secondary" : "clankerbend-overlay-primary";
|
|
2635
3163
|
button.addEventListener("click", () => {
|
|
2636
|
-
|
|
2637
|
-
|
|
3164
|
+
if (action.type === "overlay.close") {
|
|
3165
|
+
enqueueHostEvent({
|
|
3166
|
+
kind: "overlayClose",
|
|
3167
|
+
overlayId: overlay.overlayId
|
|
3168
|
+
});
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
const values = Object.fromEntries([...el.querySelectorAll("[data-clankerbend-field-id]")]
|
|
3172
|
+
.map((input) => [input.dataset.clankerbendFieldId, input.value || ""]));
|
|
2638
3173
|
enqueueHostEvent({
|
|
2639
3174
|
kind: "appAction",
|
|
2640
3175
|
appId: overlay.appId,
|
|
@@ -2653,7 +3188,7 @@
|
|
|
2653
3188
|
el.classList.add("is-visible");
|
|
2654
3189
|
positionOverlay(el, overlay);
|
|
2655
3190
|
const activeField = activeFieldId
|
|
2656
|
-
? [...el.querySelectorAll("[data-
|
|
3191
|
+
? [...el.querySelectorAll("[data-clankerbend-field-id]")].find((field) => field.dataset.clankerbendFieldId === activeFieldId)
|
|
2657
3192
|
: null;
|
|
2658
3193
|
const firstField = fields.find((field) => field instanceof HTMLTextAreaElement || field instanceof HTMLInputElement);
|
|
2659
3194
|
setTimeout(() => focusOverlayField(activeField || firstField), 0);
|
|
@@ -2738,7 +3273,7 @@
|
|
|
2738
3273
|
}
|
|
2739
3274
|
el.replaceChildren(...items.map((item) => {
|
|
2740
3275
|
const chip = document.createElement("div");
|
|
2741
|
-
chip.className = "
|
|
3276
|
+
chip.className = "clankerbend-context-chip";
|
|
2742
3277
|
const label = document.createElement("span");
|
|
2743
3278
|
label.textContent = item.label || item.body || item.itemId;
|
|
2744
3279
|
chip.title = item.body || item.label || item.itemId;
|
|
@@ -2817,10 +3352,10 @@
|
|
|
2817
3352
|
return true;
|
|
2818
3353
|
}
|
|
2819
3354
|
|
|
2820
|
-
function
|
|
3355
|
+
function clankerbendSubmitPrompt(submission) {
|
|
2821
3356
|
const lines = [
|
|
2822
|
-
`[[
|
|
2823
|
-
"Use these
|
|
3357
|
+
`[[CLANKERBEND_CONTEXT:${submission.submissionId}]]`,
|
|
3358
|
+
"Use these ClankerBend sticky notes as context. Do not mention the marker."
|
|
2824
3359
|
];
|
|
2825
3360
|
for (const [index, item] of submission.items.entries()) {
|
|
2826
3361
|
const selected = item.range?.quote || item.range?.text || item.label || "";
|
|
@@ -2841,16 +3376,16 @@
|
|
|
2841
3376
|
}
|
|
2842
3377
|
}
|
|
2843
3378
|
lines.push(
|
|
2844
|
-
`[[/
|
|
3379
|
+
`[[/CLANKERBEND_CONTEXT:${submission.submissionId}]]`,
|
|
2845
3380
|
"",
|
|
2846
|
-
submission.userText || "Use the
|
|
3381
|
+
submission.userText || "Use the ClankerBend context above."
|
|
2847
3382
|
);
|
|
2848
3383
|
return lines.join("\n");
|
|
2849
3384
|
}
|
|
2850
3385
|
|
|
2851
3386
|
function submittedChipRow(submission) {
|
|
2852
3387
|
const row = document.createElement("div");
|
|
2853
|
-
row.className = "
|
|
3388
|
+
row.className = "clankerbend-submitted-context-row";
|
|
2854
3389
|
row.style.cssText = [
|
|
2855
3390
|
"display:flex",
|
|
2856
3391
|
"flex-wrap:wrap",
|
|
@@ -2859,7 +3394,7 @@
|
|
|
2859
3394
|
].join(";");
|
|
2860
3395
|
for (const item of submission.items) {
|
|
2861
3396
|
const chip = document.createElement("span");
|
|
2862
|
-
chip.className = "
|
|
3397
|
+
chip.className = "clankerbend-context-chip";
|
|
2863
3398
|
chip.textContent = item.label || item.body || item.itemId;
|
|
2864
3399
|
chip.title = item.body || item.label || item.itemId;
|
|
2865
3400
|
row.appendChild(chip);
|
|
@@ -2870,15 +3405,15 @@
|
|
|
2870
3405
|
function maskSubmittedComposerContexts() {
|
|
2871
3406
|
if (!state.submittedComposerSubmissions.length) return;
|
|
2872
3407
|
for (const submission of state.submittedComposerSubmissions) {
|
|
2873
|
-
const marker = `[[
|
|
3408
|
+
const marker = `[[CLANKERBEND_CONTEXT:${submission.submissionId}]]`;
|
|
2874
3409
|
const candidates = Array.from(document.querySelectorAll("main *, [role='main'] *, body *"))
|
|
2875
3410
|
.filter((el) => el instanceof HTMLElement && !isHostUiElement(el))
|
|
2876
3411
|
.filter((el) => (el.innerText || el.textContent || "").includes(marker))
|
|
2877
3412
|
.filter((el) => !Array.from(el.children || []).some((child) => (child.innerText || child.textContent || "").includes(marker)))
|
|
2878
3413
|
.sort((a, b) => (a.textContent || "").length - (b.textContent || "").length);
|
|
2879
3414
|
const target = candidates[0];
|
|
2880
|
-
if (!target || target.dataset.
|
|
2881
|
-
target.dataset.
|
|
3415
|
+
if (!target || target.dataset.clankerbendMaskedSubmission === submission.submissionId) continue;
|
|
3416
|
+
target.dataset.clankerbendMaskedSubmission = submission.submissionId;
|
|
2882
3417
|
const prompt = document.createElement("span");
|
|
2883
3418
|
prompt.textContent = submission.userText || "";
|
|
2884
3419
|
target.replaceChildren(submittedChipRow(submission), prompt);
|
|
@@ -2904,7 +3439,7 @@
|
|
|
2904
3439
|
items: items.map((item) => ({ ...item })),
|
|
2905
3440
|
submittedAt: Date.now()
|
|
2906
3441
|
};
|
|
2907
|
-
const nextText =
|
|
3442
|
+
const nextText = clankerbendSubmitPrompt(submission);
|
|
2908
3443
|
if (!setComposerText(input, nextText)) return false;
|
|
2909
3444
|
state.pendingComposerSubmission = submission;
|
|
2910
3445
|
state.submittedComposerSubmissions = [...state.submittedComposerSubmissions, submission].slice(-8);
|
|
@@ -2941,22 +3476,22 @@
|
|
|
2941
3476
|
}
|
|
2942
3477
|
|
|
2943
3478
|
function installComposerSubmitInterceptor() {
|
|
2944
|
-
if (window.
|
|
2945
|
-
window.
|
|
2946
|
-
window.
|
|
3479
|
+
if (window.__clankerbendComposerSubmitInterceptorInstalled) return;
|
|
3480
|
+
window.__clankerbendComposerSubmitInterceptorInstalled = true;
|
|
3481
|
+
window.__clankerbendComposerSubmitClickHandler = (event) => {
|
|
2947
3482
|
if (isComposerSubmitButton(event.target)) prepareComposerContextForSubmit();
|
|
2948
3483
|
};
|
|
2949
|
-
window.
|
|
3484
|
+
window.__clankerbendComposerSubmitKeyHandler = (event) => {
|
|
2950
3485
|
if (event.key !== "Enter" || event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return;
|
|
2951
3486
|
const input = composerInputElement();
|
|
2952
3487
|
if (input && (event.target === input || input.contains?.(event.target))) prepareComposerContextForSubmit();
|
|
2953
3488
|
};
|
|
2954
|
-
document.addEventListener("click", window.
|
|
2955
|
-
document.addEventListener("keydown", window.
|
|
3489
|
+
document.addEventListener("click", window.__clankerbendComposerSubmitClickHandler, true);
|
|
3490
|
+
document.addEventListener("keydown", window.__clankerbendComposerSubmitKeyHandler, true);
|
|
2956
3491
|
}
|
|
2957
3492
|
|
|
2958
|
-
function
|
|
2959
|
-
return String(
|
|
3493
|
+
function clankerbendAppUrl() {
|
|
3494
|
+
return String(clankerbendRuntime().getEntryUrl(VIM_NAV_APP_ID) || "").trim();
|
|
2960
3495
|
}
|
|
2961
3496
|
|
|
2962
3497
|
async function ensureNativeBrowserPanel() {
|
|
@@ -3010,8 +3545,8 @@
|
|
|
3010
3545
|
}
|
|
3011
3546
|
|
|
3012
3547
|
async function doOpenPanel() {
|
|
3013
|
-
const serverUrl =
|
|
3014
|
-
if (!serverUrl) return { ok: false, error: "
|
|
3548
|
+
const serverUrl = clankerbendAppUrl().replace(/\/$/, "");
|
|
3549
|
+
if (!serverUrl) return { ok: false, error: "ClankerBend host URL missing" };
|
|
3015
3550
|
const panelUrl = `${serverUrl}/`;
|
|
3016
3551
|
const webviews = () => Array.from(document.querySelectorAll("webview, iframe"));
|
|
3017
3552
|
const normalizedSrc = (el) => String(el.getAttribute("src") || "")
|
|
@@ -3076,7 +3611,7 @@
|
|
|
3076
3611
|
: null;
|
|
3077
3612
|
};
|
|
3078
3613
|
const installPanelIframe = async () => {
|
|
3079
|
-
const existing = document.getElementById("
|
|
3614
|
+
const existing = document.getElementById("clankerbend-vim-nav-side-panel-frame");
|
|
3080
3615
|
if (existing) {
|
|
3081
3616
|
existing.setAttribute("src", panelUrl);
|
|
3082
3617
|
await delay(300);
|
|
@@ -3109,10 +3644,10 @@
|
|
|
3109
3644
|
if (!input && !/new tab|start browsing|enter a url|browser/i.test(panelText)) return null;
|
|
3110
3645
|
if (getComputedStyle(panel).position === "static") panel.style.position = "relative";
|
|
3111
3646
|
const frame = document.createElement("iframe");
|
|
3112
|
-
frame.id = "
|
|
3647
|
+
frame.id = "clankerbend-vim-nav-side-panel-frame";
|
|
3113
3648
|
frame.src = panelUrl;
|
|
3114
|
-
frame.title = "
|
|
3115
|
-
frame.setAttribute("data-
|
|
3649
|
+
frame.title = "VimNav";
|
|
3650
|
+
frame.setAttribute("data-clankerbend-panel-frame", VIM_NAV_APP_ID);
|
|
3116
3651
|
frame.style.cssText = [
|
|
3117
3652
|
"position:absolute",
|
|
3118
3653
|
"left:0",
|
|
@@ -3154,12 +3689,12 @@
|
|
|
3154
3689
|
if (!browserUrlInput() && !localServerButton()) {
|
|
3155
3690
|
return { ok: false, error: "native Browser panel controls not found", debug: panelDebug({ stage: "no-controls" }) };
|
|
3156
3691
|
}
|
|
3157
|
-
return { ok: false, error: "native Browser panel did not navigate to
|
|
3692
|
+
return { ok: false, error: "native Browser panel did not navigate to VimNav", debug: panelDebug({ stage: "not-navigated" }) };
|
|
3158
3693
|
}
|
|
3159
3694
|
|
|
3160
3695
|
function shouldIgnoreKey(event) {
|
|
3696
|
+
if (effectiveCommandOption(event)) return false;
|
|
3161
3697
|
if (event.metaKey) return true;
|
|
3162
|
-
if (effectiveCtrlAlt(event)) return false;
|
|
3163
3698
|
if (state.vimMode) return false;
|
|
3164
3699
|
if (event.defaultPrevented) return true;
|
|
3165
3700
|
if (event.ctrlKey || event.altKey) return true;
|
|
@@ -3170,25 +3705,25 @@
|
|
|
3170
3705
|
}
|
|
3171
3706
|
|
|
3172
3707
|
function isModifierOnlyKey(event) {
|
|
3173
|
-
return event.key === "
|
|
3708
|
+
return event.key === "Meta" ||
|
|
3174
3709
|
event.key === "Alt" ||
|
|
3175
|
-
event.code === "
|
|
3176
|
-
event.code === "
|
|
3710
|
+
event.code === "MetaLeft" ||
|
|
3711
|
+
event.code === "MetaRight" ||
|
|
3177
3712
|
event.code === "AltLeft" ||
|
|
3178
3713
|
event.code === "AltRight";
|
|
3179
3714
|
}
|
|
3180
3715
|
|
|
3181
3716
|
function updateModifierState(event, isDown) {
|
|
3182
|
-
if (event.key === "
|
|
3183
|
-
state.
|
|
3717
|
+
if (event.key === "Meta" || event.code === "MetaLeft" || event.code === "MetaRight") {
|
|
3718
|
+
state.metaDown = Boolean(isDown);
|
|
3184
3719
|
}
|
|
3185
3720
|
if (event.key === "Alt" || event.code === "AltLeft" || event.code === "AltRight") {
|
|
3186
3721
|
state.altDown = Boolean(isDown);
|
|
3187
3722
|
}
|
|
3188
3723
|
}
|
|
3189
3724
|
|
|
3190
|
-
function
|
|
3191
|
-
return Boolean((event.
|
|
3725
|
+
function effectiveCommandOption(event) {
|
|
3726
|
+
return Boolean((event.metaKey && event.altKey) || (state.metaDown && state.altDown));
|
|
3192
3727
|
}
|
|
3193
3728
|
|
|
3194
3729
|
function digitFromKeyEvent(event) {
|
|
@@ -3228,12 +3763,44 @@
|
|
|
3228
3763
|
return null;
|
|
3229
3764
|
});
|
|
3230
3765
|
};
|
|
3231
|
-
|
|
3766
|
+
const runRelativeCommand = (name, delta, commandForDelta) => {
|
|
3767
|
+
if (state.relativeMoveInFlight) {
|
|
3768
|
+
state.pendingRelativeDelta = Math.max(-1, Math.min(1, state.pendingRelativeDelta + Math.sign(delta)));
|
|
3769
|
+
state.lastCommandResult = { name, pending: true, pendingRelativeDelta: state.pendingRelativeDelta };
|
|
3770
|
+
ensureModeBadge();
|
|
3771
|
+
return;
|
|
3772
|
+
}
|
|
3773
|
+
const prefixBefore = state.countPrefix;
|
|
3774
|
+
state.relativeMoveInFlight = true;
|
|
3775
|
+
state.commandChain = state.commandChain
|
|
3776
|
+
.catch(() => {})
|
|
3777
|
+
.then(async () => {
|
|
3778
|
+
let step = Math.sign(delta);
|
|
3779
|
+
let result = null;
|
|
3780
|
+
try {
|
|
3781
|
+
while (step) {
|
|
3782
|
+
result = await Promise.resolve().then(() => commandForDelta(step));
|
|
3783
|
+
state.lastCommandResult = { name, prefixBefore, result };
|
|
3784
|
+
ensureModeBadge();
|
|
3785
|
+
step = state.pendingRelativeDelta;
|
|
3786
|
+
state.pendingRelativeDelta = 0;
|
|
3787
|
+
}
|
|
3788
|
+
return result;
|
|
3789
|
+
} catch (err) {
|
|
3790
|
+
state.lastCommandResult = { name, prefixBefore, ok: false, error: err?.message || String(err) };
|
|
3791
|
+
ensureModeBadge();
|
|
3792
|
+
return null;
|
|
3793
|
+
} finally {
|
|
3794
|
+
state.relativeMoveInFlight = false;
|
|
3795
|
+
}
|
|
3796
|
+
});
|
|
3797
|
+
};
|
|
3798
|
+
if (effectiveCommandOption(event)) {
|
|
3232
3799
|
if (isModifierOnlyKey(event)) {
|
|
3233
3800
|
event.preventDefault();
|
|
3234
3801
|
event.stopImmediatePropagation();
|
|
3235
|
-
if (!event.repeat && !state.
|
|
3236
|
-
state.
|
|
3802
|
+
if (!event.repeat && !state.metaAltToggleDown) {
|
|
3803
|
+
state.metaAltToggleDown = true;
|
|
3237
3804
|
setVimMode(!state.vimMode);
|
|
3238
3805
|
}
|
|
3239
3806
|
return;
|
|
@@ -3249,35 +3816,35 @@
|
|
|
3249
3816
|
if (code === "KeyJ" || key === "j" || key === "ArrowDown") {
|
|
3250
3817
|
event.preventDefault();
|
|
3251
3818
|
event.stopImmediatePropagation();
|
|
3252
|
-
|
|
3819
|
+
runRelativeCommand("cmd-option-j", 1, (step) => withVisibleMountedIndex(() => jumpRelativeFast(step)));
|
|
3253
3820
|
} else if (code === "KeyK" || key === "k" || key === "ArrowUp") {
|
|
3254
3821
|
event.preventDefault();
|
|
3255
3822
|
event.stopImmediatePropagation();
|
|
3256
|
-
|
|
3823
|
+
runRelativeCommand("cmd-option-k", -1, (step) => withVisibleMountedIndex(() => jumpRelativeFast(step)));
|
|
3257
3824
|
} else if ((code === "KeyG" && event.shiftKey) || key === "G" || key === "End") {
|
|
3258
3825
|
event.preventDefault();
|
|
3259
3826
|
event.stopImmediatePropagation();
|
|
3260
|
-
runCommand("
|
|
3827
|
+
runCommand("cmd-option-G", () => afterIndexing(() => jumpToBottom()));
|
|
3261
3828
|
} else if (code === "KeyG" || key === "g" || key === "Home") {
|
|
3262
3829
|
event.preventDefault();
|
|
3263
3830
|
event.stopImmediatePropagation();
|
|
3264
|
-
runCommand("
|
|
3831
|
+
runCommand("cmd-option-g", () => afterIndexing(() => jumpToIndex(0, { block: "start", behavior: "auto" })));
|
|
3265
3832
|
} else if (key === "[" || (code === "BracketLeft" && !event.shiftKey)) {
|
|
3266
3833
|
event.preventDefault();
|
|
3267
3834
|
event.stopImmediatePropagation();
|
|
3268
|
-
runCommand("
|
|
3835
|
+
runCommand("cmd-option-[", () => alignCurrent("start"));
|
|
3269
3836
|
} else if (key === "]" || (code === "BracketRight" && !event.shiftKey)) {
|
|
3270
3837
|
event.preventDefault();
|
|
3271
3838
|
event.stopImmediatePropagation();
|
|
3272
|
-
runCommand("
|
|
3839
|
+
runCommand("cmd-option-]", () => alignCurrent("end"));
|
|
3273
3840
|
} else if (key === "{" || (code === "BracketLeft" && event.shiftKey) || key === "PageUp") {
|
|
3274
3841
|
event.preventDefault();
|
|
3275
3842
|
event.stopImmediatePropagation();
|
|
3276
|
-
runCommand("
|
|
3843
|
+
runCommand("cmd-option-{", () => jumpRole("user", -1));
|
|
3277
3844
|
} else if (key === "}" || (code === "BracketRight" && event.shiftKey) || key === "PageDown") {
|
|
3278
3845
|
event.preventDefault();
|
|
3279
3846
|
event.stopImmediatePropagation();
|
|
3280
|
-
runCommand("
|
|
3847
|
+
runCommand("cmd-option-}", () => jumpRole("user", 1));
|
|
3281
3848
|
} else if (key === "?" || (code === "Slash" && event.shiftKey)) {
|
|
3282
3849
|
event.preventDefault();
|
|
3283
3850
|
event.stopImmediatePropagation();
|
|
@@ -3349,12 +3916,12 @@
|
|
|
3349
3916
|
event.preventDefault();
|
|
3350
3917
|
state.countPrefix = "";
|
|
3351
3918
|
ensureModeBadge();
|
|
3352
|
-
|
|
3919
|
+
runRelativeCommand("j", 1, (step) => withVisibleMountedIndex(() => jumpRelativeFast(step)));
|
|
3353
3920
|
} else if (code === "KeyK" || key === "k") {
|
|
3354
3921
|
event.preventDefault();
|
|
3355
3922
|
state.countPrefix = "";
|
|
3356
3923
|
ensureModeBadge();
|
|
3357
|
-
|
|
3924
|
+
runRelativeCommand("k", -1, (step) => withVisibleMountedIndex(() => jumpRelativeFast(step)));
|
|
3358
3925
|
} else if ((code === "KeyG" && event.shiftKey) || key === "G") {
|
|
3359
3926
|
event.preventDefault();
|
|
3360
3927
|
const prefix = state.countPrefix;
|
|
@@ -3391,10 +3958,10 @@
|
|
|
3391
3958
|
|
|
3392
3959
|
function handleKeyUp(event) {
|
|
3393
3960
|
updateModifierState(event, false);
|
|
3394
|
-
if ((event.key === "
|
|
3395
|
-
state.
|
|
3396
|
-
!
|
|
3397
|
-
state.
|
|
3961
|
+
if ((event.key === "Meta" || event.key === "Alt" || !event.metaKey || !event.altKey) &&
|
|
3962
|
+
state.metaAltToggleDown &&
|
|
3963
|
+
!effectiveCommandOption(event)) {
|
|
3964
|
+
state.metaAltToggleDown = false;
|
|
3398
3965
|
}
|
|
3399
3966
|
}
|
|
3400
3967
|
|
|
@@ -3409,9 +3976,9 @@
|
|
|
3409
3976
|
}
|
|
3410
3977
|
|
|
3411
3978
|
function resetModifierState() {
|
|
3412
|
-
state.
|
|
3979
|
+
state.metaDown = false;
|
|
3413
3980
|
state.altDown = false;
|
|
3414
|
-
state.
|
|
3981
|
+
state.metaAltToggleDown = false;
|
|
3415
3982
|
}
|
|
3416
3983
|
|
|
3417
3984
|
function snapshot() {
|
|
@@ -3464,10 +4031,10 @@
|
|
|
3464
4031
|
document.removeEventListener("keydown", window.__codexVimNavKeyHandler, true);
|
|
3465
4032
|
window.removeEventListener("keyup", window.__codexVimNavKeyUpHandler, true);
|
|
3466
4033
|
document.removeEventListener("keyup", window.__codexVimNavKeyUpHandler, true);
|
|
3467
|
-
document.removeEventListener("mouseup", window.
|
|
4034
|
+
document.removeEventListener("mouseup", window.__clankerbendTextSelectionHandler, true);
|
|
3468
4035
|
window.__codexVimNavKeyHandler = handleKey;
|
|
3469
4036
|
window.__codexVimNavKeyUpHandler = handleKeyUp;
|
|
3470
|
-
window.
|
|
4037
|
+
window.__clankerbendTextSelectionHandler = handlePossibleTextSelection;
|
|
3471
4038
|
window.addEventListener("keydown", handleKey, true);
|
|
3472
4039
|
document.addEventListener("keydown", handleKey, true);
|
|
3473
4040
|
window.addEventListener("keyup", handleKeyUp, true);
|
|
@@ -3478,6 +4045,7 @@
|
|
|
3478
4045
|
const mutationObserver = new MutationObserver(() => {
|
|
3479
4046
|
state.version += 1;
|
|
3480
4047
|
scheduleAnnotationRefresh();
|
|
4048
|
+
renderCodexAccountSwitcher();
|
|
3481
4049
|
maskSubmittedComposerContexts();
|
|
3482
4050
|
});
|
|
3483
4051
|
window.addEventListener("resize", resizeHandler);
|
|
@@ -3489,14 +4057,15 @@
|
|
|
3489
4057
|
window.removeEventListener("keyup", handleKeyUp, true);
|
|
3490
4058
|
document.removeEventListener("keyup", handleKeyUp, true);
|
|
3491
4059
|
document.removeEventListener("mouseup", handlePossibleTextSelection, true);
|
|
3492
|
-
document.removeEventListener("click", window.
|
|
3493
|
-
document.removeEventListener("keydown", window.
|
|
4060
|
+
document.removeEventListener("click", window.__clankerbendComposerSubmitClickHandler, true);
|
|
4061
|
+
document.removeEventListener("keydown", window.__clankerbendComposerSubmitKeyHandler, true);
|
|
4062
|
+
document.getElementById(ACCOUNT_SWITCHER_ID)?.remove();
|
|
3494
4063
|
window.removeEventListener("resize", resizeHandler);
|
|
3495
4064
|
window.removeEventListener("blur", blurHandler);
|
|
3496
4065
|
mutationObserver.disconnect();
|
|
3497
4066
|
if (annotationRefreshTimer) clearTimeout(annotationRefreshTimer);
|
|
3498
4067
|
annotationRefreshTimer = null;
|
|
3499
|
-
window.
|
|
4068
|
+
window.__clankerbendComposerSubmitInterceptorInstalled = false;
|
|
3500
4069
|
};
|
|
3501
4070
|
|
|
3502
4071
|
const bridge = {
|
|
@@ -3508,18 +4077,18 @@
|
|
|
3508
4077
|
openPanel,
|
|
3509
4078
|
scrollToAnchor,
|
|
3510
4079
|
highlightAnchor,
|
|
3511
|
-
highlightRange: (range, options) =>
|
|
3512
|
-
?
|
|
4080
|
+
highlightRange: (range, options) => clankerbendRuntime().highlightRange
|
|
4081
|
+
? clankerbendRuntime().highlightRange(range, options)
|
|
3513
4082
|
: highlightAnchor(range?.anchorId, options),
|
|
3514
4083
|
setAnnotations,
|
|
3515
4084
|
setTranscriptOrder,
|
|
3516
4085
|
primeAnchorOrder,
|
|
3517
4086
|
jumpToIndex,
|
|
3518
|
-
|
|
4087
|
+
jumpRelativeFast,
|
|
3519
4088
|
__testUpdateTextSelectionFromDom: updateTextSelectionFromDom
|
|
3520
4089
|
};
|
|
3521
4090
|
|
|
3522
|
-
|
|
4091
|
+
clankerbendRuntime().registerApp({
|
|
3523
4092
|
appId: VIM_NAV_APP_ID,
|
|
3524
4093
|
capabilities: {
|
|
3525
4094
|
transcriptRead: true,
|