@frockbot/plugin-flock 0.3.4 → 0.3.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.
package/assets/manifest.json
CHANGED
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"id": "matte-black-top-hat",
|
|
55
|
-
"label": "Matte-black top hat
|
|
55
|
+
"label": "Matte-black top hat",
|
|
56
56
|
"parent": "upper-neutral",
|
|
57
57
|
"kind": "headwear"
|
|
58
58
|
},
|
|
@@ -278,7 +278,7 @@
|
|
|
278
278
|
},
|
|
279
279
|
{
|
|
280
280
|
"id": "purple-scarf",
|
|
281
|
-
"label": "Purple silk scarf
|
|
281
|
+
"label": "Purple silk scarf",
|
|
282
282
|
"parent": "lower-neutral",
|
|
283
283
|
"kind": "neckwear"
|
|
284
284
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frockbot/plugin-flock",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -27,16 +27,16 @@
|
|
|
27
27
|
"typecheck": "vue-tsc --noEmit -p tsconfig.json"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@frockbot/client-core": "0.3.
|
|
31
|
-
"@frockbot/client-ui": "0.3.
|
|
32
|
-
"@frockbot/configuration-core": "0.3.
|
|
33
|
-
"@frockbot/kernel-contracts": "0.3.
|
|
34
|
-
"@frockbot/plugin-shell": "0.3.
|
|
30
|
+
"@frockbot/client-core": "0.3.6",
|
|
31
|
+
"@frockbot/client-ui": "0.3.6",
|
|
32
|
+
"@frockbot/configuration-core": "0.3.6",
|
|
33
|
+
"@frockbot/kernel-contracts": "0.3.6",
|
|
34
|
+
"@frockbot/plugin-shell": "0.3.6",
|
|
35
35
|
"cordis": "4.0.0-rc.8",
|
|
36
36
|
"vue": "3.5.41"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@frockbot/plugin-testkit": "0.3.
|
|
39
|
+
"@frockbot/plugin-testkit": "0.3.6",
|
|
40
40
|
"@types/bun": "1.4.0",
|
|
41
41
|
"@vitejs/plugin-vue": "6.0.8",
|
|
42
42
|
"css-tree": "2.3.1",
|
|
@@ -123,10 +123,7 @@ onBeforeUnmount(() => restoreFocus?.focus());
|
|
|
123
123
|
: "Change the look"
|
|
124
124
|
}}
|
|
125
125
|
</h1>
|
|
126
|
-
<p>
|
|
127
|
-
Keep this look or tailor each layer. Your choice is saved with the
|
|
128
|
-
Bot.
|
|
129
|
-
</p>
|
|
126
|
+
<p>Keep this look, or change any layer.</p>
|
|
130
127
|
<label v-if="flock.overlay === 'create'" class="flock-name"
|
|
131
128
|
>Bot name<input
|
|
132
129
|
v-model.trim="flock.draftName"
|
|
@@ -45,7 +45,7 @@ function botName(botId: string, fallback: string): string {
|
|
|
45
45
|
return flock.value.profiles[botId]?.name ?? fallback;
|
|
46
46
|
}
|
|
47
47
|
function botSubtitle(botId: string): string {
|
|
48
|
-
return flock.value.profiles[botId]?.title ??
|
|
48
|
+
return flock.value.profiles[botId]?.title ?? "No messages yet";
|
|
49
49
|
}
|
|
50
50
|
function previewText(botId: string): string {
|
|
51
51
|
return flock.value.unread[botId]?.lastMessage?.text ?? botSubtitle(botId);
|
package/src/client/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClientPlugin } from "@frockbot/client-core";
|
|
2
2
|
import type { FrockBotWebData } from "@frockbot/plugin-shell/shared";
|
|
3
|
-
import { ref, type Ref } from "vue";
|
|
3
|
+
import { ref, watch, type Ref } from "vue";
|
|
4
4
|
import {
|
|
5
5
|
decodeBotLifecycleDirectoryViewV1,
|
|
6
6
|
decodeBotIdentityDirectoryViewV1,
|
|
@@ -91,6 +91,8 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
91
91
|
throw new Error("Flock hosted transport is unavailable");
|
|
92
92
|
const request = ctx.transport.hostedRequest.bind(ctx.transport);
|
|
93
93
|
let shell: Ref<FrockBotWebData> | undefined;
|
|
94
|
+
/** Stops the watcher that keeps a renamed Bot's sidebar row in step. */
|
|
95
|
+
let stopNameWatch: (() => void) | undefined;
|
|
94
96
|
let authenticatedUserId: string | undefined;
|
|
95
97
|
let loadGeneration = 0;
|
|
96
98
|
let selectionGeneration = 0;
|
|
@@ -117,6 +119,24 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
117
119
|
draftSheep: randomSheepRecipeV1(),
|
|
118
120
|
bindShell(value) {
|
|
119
121
|
shell = value;
|
|
122
|
+
// A rename is saved on the Bot's own settings, and the sidebar reads a
|
|
123
|
+
// directory it loaded once — so the row kept the old name until the page
|
|
124
|
+
// was reloaded. The row follows the settings the Shell is already
|
|
125
|
+
// holding rather than waiting for a second read of the directory.
|
|
126
|
+
stopNameWatch?.();
|
|
127
|
+
stopNameWatch = watch(
|
|
128
|
+
() => value.value.botSettings?.profile.name,
|
|
129
|
+
(name) => {
|
|
130
|
+
const botId = value.value.botSettings?.botId;
|
|
131
|
+
if (!botId || !name) return;
|
|
132
|
+
const profile = state.value.profiles[botId];
|
|
133
|
+
if (!profile || profile.name === name) return;
|
|
134
|
+
state.value.profiles = {
|
|
135
|
+
...state.value.profiles,
|
|
136
|
+
[botId]: { ...profile, name },
|
|
137
|
+
};
|
|
138
|
+
},
|
|
139
|
+
);
|
|
120
140
|
},
|
|
121
141
|
async load() {
|
|
122
142
|
const generation = ++loadGeneration;
|
|
@@ -158,9 +178,7 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
158
178
|
if (receipt) {
|
|
159
179
|
clearPendingCreate(userId);
|
|
160
180
|
if (receipt.status === "rejected")
|
|
161
|
-
throw new Error(
|
|
162
|
-
receipt.failure ?? "Pending Bot creation was rejected",
|
|
163
|
-
);
|
|
181
|
+
throw new Error(receipt.failure ?? "Couldn't create the Bot.");
|
|
164
182
|
}
|
|
165
183
|
state.value.directory = decodeDirectoryViewV1(
|
|
166
184
|
await request("/api/bots"),
|
|
@@ -220,7 +238,11 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
220
238
|
const selected = preferredBot?.botId ?? activeBots[0]?.botId;
|
|
221
239
|
if (preferred && !preferredBot) replacePreferredBot(selected);
|
|
222
240
|
if (selected && shell) await state.value.select(selected);
|
|
223
|
-
|
|
241
|
+
// Only a User with no Bots at all is asked to make one. Archiving your
|
|
242
|
+
// last Bot leaves you with an archived list to restore from, and a
|
|
243
|
+
// dialog opening over it puts its backdrop between you and Restore.
|
|
244
|
+
else if (!selected && state.value.directory.bots.length === 0)
|
|
245
|
+
state.value.openCreate();
|
|
224
246
|
} catch (error) {
|
|
225
247
|
state.value.error =
|
|
226
248
|
error instanceof Error ? error.message : "Could not load your flock";
|
|
@@ -235,6 +257,26 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
235
257
|
state.value.unread = Object.fromEntries(
|
|
236
258
|
directory.unread.map((view) => [view.botId, view]),
|
|
237
259
|
);
|
|
260
|
+
// A Turn that settles in the conversation the User is looking at has
|
|
261
|
+
// been read by the time it arrives, so the badge that counted it is
|
|
262
|
+
// wrong the instant it appears. Reading up to it is still the explicit
|
|
263
|
+
// authenticated command; what the poll refreshed is only which cursor it
|
|
264
|
+
// names. Every other Bot's badge is left exactly as the fan-out said.
|
|
265
|
+
const openBotId = shell?.value.activeBotId;
|
|
266
|
+
if (
|
|
267
|
+
openBotId &&
|
|
268
|
+
(state.value.unread[openBotId]?.count ?? 0) > 0 &&
|
|
269
|
+
!state.value.unread[openBotId]?.manuallyUnread &&
|
|
270
|
+
typeof document !== "undefined" &&
|
|
271
|
+
document.visibilityState === "visible" &&
|
|
272
|
+
document.hasFocus()
|
|
273
|
+
) {
|
|
274
|
+
try {
|
|
275
|
+
await state.value.markRead(openBotId);
|
|
276
|
+
} catch {
|
|
277
|
+
// The badge stays until the next poll; nothing durable is lost.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
238
280
|
},
|
|
239
281
|
async markRead(botId) {
|
|
240
282
|
const cursor = state.value.unread[botId]?.lastActivityCursor;
|
|
@@ -340,9 +382,9 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
340
382
|
),
|
|
341
383
|
);
|
|
342
384
|
if (receipt.status === "rejected")
|
|
343
|
-
throw new Error(receipt.failure ?? "
|
|
385
|
+
throw new Error(receipt.failure ?? "Couldn't archive this Bot.");
|
|
344
386
|
if (receipt.status === "pending") {
|
|
345
|
-
state.value.error = "
|
|
387
|
+
state.value.error = "Still archiving — this will finish shortly.";
|
|
346
388
|
return;
|
|
347
389
|
}
|
|
348
390
|
state.value.overlay = undefined;
|
|
@@ -368,9 +410,9 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
368
410
|
),
|
|
369
411
|
);
|
|
370
412
|
if (receipt.status === "rejected")
|
|
371
|
-
throw new Error(receipt.failure ?? "
|
|
413
|
+
throw new Error(receipt.failure ?? "Couldn't restore this Bot.");
|
|
372
414
|
if (receipt.status === "pending") {
|
|
373
|
-
state.value.error = "
|
|
415
|
+
state.value.error = "Still restoring — this will finish shortly.";
|
|
374
416
|
return;
|
|
375
417
|
}
|
|
376
418
|
await state.value.load();
|
|
@@ -399,18 +441,16 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
399
441
|
clearPendingSheep(userId, botId);
|
|
400
442
|
if (receipt.status === "rejected")
|
|
401
443
|
reconciliationFailure =
|
|
402
|
-
receipt.failure ?? "
|
|
444
|
+
receipt.failure ?? "Couldn't save the sheep.";
|
|
403
445
|
} catch (error) {
|
|
404
446
|
if (!isDefinitiveFlockFailure(error)) {
|
|
405
447
|
state.value.error =
|
|
406
|
-
"
|
|
448
|
+
"Your last change to this sheep didn't save. Try again.";
|
|
407
449
|
return;
|
|
408
450
|
}
|
|
409
451
|
clearPendingSheep(userId, botId);
|
|
410
452
|
reconciliationFailure =
|
|
411
|
-
error instanceof Error
|
|
412
|
-
? error.message
|
|
413
|
-
: "Pending sheep update was rejected";
|
|
453
|
+
error instanceof Error ? error.message : "Couldn't save the sheep.";
|
|
414
454
|
}
|
|
415
455
|
try {
|
|
416
456
|
identity = decodeSheepIdentityViewV1(
|
|
@@ -421,7 +461,7 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
421
461
|
state.value.error =
|
|
422
462
|
error instanceof Error
|
|
423
463
|
? error.message
|
|
424
|
-
: "
|
|
464
|
+
: "Couldn't finish saving your last change.";
|
|
425
465
|
return;
|
|
426
466
|
}
|
|
427
467
|
}
|
|
@@ -459,7 +499,7 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
459
499
|
);
|
|
460
500
|
if (receipt.status === "rejected") {
|
|
461
501
|
clearPendingCreate(userId);
|
|
462
|
-
throw new Error(receipt.failure ?? "
|
|
502
|
+
throw new Error(receipt.failure ?? "Couldn't create the Bot.");
|
|
463
503
|
}
|
|
464
504
|
clearPendingCreate(userId);
|
|
465
505
|
replacePreferredBot(command.botId);
|
|
@@ -501,7 +541,7 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
501
541
|
);
|
|
502
542
|
if (receipt.status === "rejected") {
|
|
503
543
|
clearPendingSheep(userId, botId);
|
|
504
|
-
throw new Error(receipt.failure ?? "
|
|
544
|
+
throw new Error(receipt.failure ?? "Couldn't save the sheep.");
|
|
505
545
|
}
|
|
506
546
|
clearPendingSheep(userId, botId);
|
|
507
547
|
state.value.identities[botId] = decodeSheepIdentityViewV1(
|
|
@@ -588,6 +628,7 @@ export const flockClientPlugin: ClientPlugin = (ctx) => {
|
|
|
588
628
|
|
|
589
629
|
return [
|
|
590
630
|
() => clearInterval(poll),
|
|
631
|
+
() => stopNameWatch?.(),
|
|
591
632
|
ctx.provide(flockWebDataKey, state),
|
|
592
633
|
ctx.slot({
|
|
593
634
|
slot: "frockbot.sidebar-bots",
|