@bivy/bivy 0.17.3-staging.17 → 0.17.3-staging.19
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/dist/apps/styles.css +45 -21
- package/dist/server.js +15 -4
- package/dist/session/session-new-dedupe.js +1 -1
- package/package.json +1 -1
package/dist/apps/styles.css
CHANGED
|
@@ -1451,7 +1451,7 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1451
1451
|
.library-tile-file { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); }
|
|
1452
1452
|
.library-tile-ext { font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: 0.04em; }
|
|
1453
1453
|
.library-tile-caption { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding: 0 2px; }
|
|
1454
|
-
.library-tile-name
|
|
1454
|
+
.library-tile-name {
|
|
1455
1455
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
1456
1456
|
font-size: var(--text-sm); font-weight: var(--weight-medium); color: var(--ink);
|
|
1457
1457
|
}
|
|
@@ -1464,17 +1464,6 @@ button.sheet-action:last-child { border-bottom: 0; }
|
|
|
1464
1464
|
.library-source:hover { color: var(--ink); }
|
|
1465
1465
|
.library-source svg, .library-source-when { flex: none; }
|
|
1466
1466
|
.library-source-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1467
|
-
.library-list { list-style: none; margin: 0; padding: 0; }
|
|
1468
|
-
.library-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) 0; border-bottom: 1px solid var(--line); }
|
|
1469
|
-
.library-row:last-child { border-bottom: 0; }
|
|
1470
|
-
.library-row-icon {
|
|
1471
|
-
flex: none; width: 40px; height: 40px; display: grid; place-items: center;
|
|
1472
|
-
border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2);
|
|
1473
|
-
color: var(--ink); font-weight: var(--weight-semibold);
|
|
1474
|
-
}
|
|
1475
|
-
.library-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
|
|
1476
|
-
.library-row-name { font-size: var(--text-base); }
|
|
1477
|
-
.library-row-kind { color: var(--muted); font-weight: var(--weight-normal); }
|
|
1478
1467
|
@media (min-width: 640px) {
|
|
1479
1468
|
.library-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--space-6) var(--space-4); }
|
|
1480
1469
|
}
|
|
@@ -3034,18 +3023,53 @@ select.picker-search { appearance: auto; }
|
|
|
3034
3023
|
|
|
3035
3024
|
/* Artifacts sheet (components/ArtifactsSheet.tsx) — agent-sent attachments,
|
|
3036
3025
|
user uploads, and resolved inline images grouped by kind. */
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
.app
|
|
3040
|
-
.
|
|
3041
|
-
.
|
|
3042
|
-
.app-
|
|
3043
|
-
.app-
|
|
3026
|
+
/* An app, a view of it, or a server that could become one (AppRow.tsx): the
|
|
3027
|
+
same tile, type and trailing action in the chat card, the Apps page and the
|
|
3028
|
+
Apps sheet. Views nest inside their app's card as small rows. */
|
|
3029
|
+
.apps-card { border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); overflow-wrap: anywhere; }
|
|
3030
|
+
.apps-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
|
|
3031
|
+
.app-row { display: flex; align-items: center; gap: var(--space-3); min-width: 0; padding: var(--space-3); }
|
|
3032
|
+
.app-tile { flex: none; display: grid; place-items: center; inline-size: 40px; block-size: 40px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface-2); color: var(--ink); font-weight: var(--weight-semibold); }
|
|
3033
|
+
.app-row.small .app-tile { inline-size: 36px; block-size: 36px; border-radius: var(--radius-sm); color: var(--muted); }
|
|
3034
|
+
.app-tile-port { font-family: var(--font-mono); font-size: var(--text-xs); color: var(--ok); }
|
|
3035
|
+
.app-row-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
3036
|
+
.app-row-name { font-size: var(--text-base); font-weight: var(--weight-semibold); }
|
|
3037
|
+
.app-row.small .app-row-name { font-size: var(--text-sm); }
|
|
3038
|
+
.app-row-meta { color: var(--muted); font-size: var(--text-xs); line-height: var(--lh-xs); }
|
|
3039
|
+
.app-row-action { flex: none; display: flex; align-items: center; gap: var(--space-1); }
|
|
3040
|
+
.app-message { margin-block: var(--space-2); }
|
|
3041
|
+
|
|
3042
|
+
/* Apps sheet (AppsSheet.tsx): one card per app, its views nested, one primary
|
|
3043
|
+
action per view; secondary tools as quiet icon buttons; rare or destructive
|
|
3044
|
+
actions behind ⋯ (MoreMenu, the canonical .menu). Status uses .banner. */
|
|
3045
|
+
.apps-sheet { display: flex; flex-direction: column; gap: var(--space-4); padding: var(--space-2) var(--space-2) var(--space-4); }
|
|
3046
|
+
.apps-state { display: flex; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-6) 0; color: var(--muted); font-size: var(--text-sm); }
|
|
3047
|
+
.apps-group { display: flex; flex-direction: column; gap: var(--space-2); }
|
|
3048
|
+
.apps-group-title { margin: 0; padding: 0 var(--space-1); color: var(--muted); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; }
|
|
3049
|
+
.apps-view { display: flex; flex-direction: column; border-top: 1px solid var(--line); }
|
|
3050
|
+
.apps-cmd { display: block; margin: 0 var(--space-3) var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: var(--surface-2); color: var(--ink); font-family: var(--font-mono); font-size: var(--text-xs); white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
3051
|
+
.apps-view-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 0; padding: 0 var(--space-1) var(--space-1); }
|
|
3052
|
+
.apps-view-tools .btn { gap: 6px; padding-inline: var(--space-2); color: var(--muted); }
|
|
3053
|
+
.apps-view-tools .btn:hover:not(:disabled) { color: var(--ink); }
|
|
3054
|
+
.apps-more { position: relative; }
|
|
3055
|
+
.apps-view-tools .apps-more { margin-inline-start: auto; }
|
|
3056
|
+
.apps-more-menu { position: absolute; right: 0; top: calc(100% + var(--space-1)); z-index: var(--z-dropdown); }
|
|
3057
|
+
.apps-notice { display: flex; align-items: flex-start; gap: var(--space-2); margin: 0 var(--space-3) var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: color-mix(in srgb, var(--ok) 12%, transparent); font-size: var(--text-sm); }
|
|
3058
|
+
.apps-notice > svg { flex: none; margin-top: 1px; color: var(--ok); }
|
|
3059
|
+
.apps-notes { display: flex; flex-direction: column; gap: var(--space-2); margin: 0 var(--space-3) var(--space-3); padding-top: var(--space-3); border-top: 1px dashed var(--line); }
|
|
3060
|
+
.apps-notes-head { display: flex; align-items: center; gap: var(--space-2); color: var(--muted); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: 0.04em; text-transform: uppercase; }
|
|
3061
|
+
.apps-count { min-inline-size: 18px; padding: 0 6px; border-radius: var(--radius-full); background: var(--surface-3); color: var(--ink); text-align: center; letter-spacing: 0; }
|
|
3062
|
+
.apps-notes ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
|
|
3063
|
+
.apps-note { display: flex; flex-direction: column; gap: 2px; padding-inline-start: var(--space-3); border-inline-start: 2px solid var(--line-strong); }
|
|
3064
|
+
.apps-note-text { color: var(--ink); font-size: var(--text-sm); }
|
|
3065
|
+
.apps-notes-actions { display: flex; gap: var(--space-2); }
|
|
3066
|
+
.apps-empty { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); padding: var(--space-6) var(--space-4); color: var(--muted); font-size: var(--text-sm); text-align: center; }
|
|
3067
|
+
.apps-empty strong { color: var(--ink); font-size: var(--text-base); }
|
|
3068
|
+
.apps-empty p { margin: 0; max-inline-size: 34ch; }
|
|
3069
|
+
.apps-foot { margin: 0; padding: 0 var(--space-1); color: var(--muted); font-size: var(--text-xs); line-height: var(--lh-xs); }
|
|
3044
3070
|
/* Peek: an app preview framed in a drawer over the chat (PreviewPeek.tsx). */
|
|
3045
3071
|
.preview-peek { display: block; inline-size: 100%; block-size: 100%; border: 0; border-radius: var(--radius-md); background: var(--bg); }
|
|
3046
3072
|
.app-terminal-status { padding: var(--space-2) var(--space-4); margin: 0; color: var(--muted); font-size: var(--text-sm); }
|
|
3047
|
-
.app-view-command { overflow-wrap: anywhere; white-space: pre-wrap; font-size: var(--text-xs); color: var(--muted); }
|
|
3048
|
-
.app-view-row .artifact-main { flex-basis: 60%; }
|
|
3049
3073
|
.artifacts-group { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
|
|
3050
3074
|
.artifacts-group:last-child { margin-bottom: 0; }
|
|
3051
3075
|
.artifacts-group-title { font-size: 12px; font-weight: 600; opacity: 0.6; text-transform: uppercase; letter-spacing: 0.04em; }
|
package/dist/server.js
CHANGED
|
@@ -1941,10 +1941,13 @@ const dedupeSessionNew = (requestId, create) => sessionNewDedupe.run(requestId,
|
|
|
1941
1941
|
// generic key->promise cache as above, reused for a different key) — see
|
|
1942
1942
|
// issue #154's queued follow-ups. A client that isn't sure whether a queued
|
|
1943
1943
|
// item's send actually reached the node before the socket dropped (see
|
|
1944
|
-
//
|
|
1944
|
+
// FollowupCoordinator.retrySending) resends it verbatim after reconnecting;
|
|
1945
1945
|
// this makes that safe by collapsing a retried clientMessageId onto the
|
|
1946
|
-
// original broadcast + turn instead of double-prompting the runtime.
|
|
1947
|
-
|
|
1946
|
+
// original broadcast + turn instead of double-prompting the runtime. The key is
|
|
1947
|
+
// kept for a day, not session.new's 10 minutes: a phone backgrounded mid-send
|
|
1948
|
+
// can reconnect long after the turn ended, and an expired key turned its
|
|
1949
|
+
// retry into a fresh, duplicate turn at the bottom of the chat.
|
|
1950
|
+
const promptDedupe = createSessionNewDedupe({ ttlMs: 24 * 60 * 60_000 });
|
|
1948
1951
|
const dedupePrompt = (clientMessageId, run) => promptDedupe.run(clientMessageId, run);
|
|
1949
1952
|
// Preview traffic has isolated per-view origins and a private gateway. Relay
|
|
1950
1953
|
// delivery needs no listener; direct ingress is an optional operator override.
|
|
@@ -2910,7 +2913,7 @@ const RELAY_COMMANDS = {
|
|
|
2910
2913
|
relay?.sendEvent({ type: "integrations.updated", integrations: integrations.list() });
|
|
2911
2914
|
}
|
|
2912
2915
|
},
|
|
2913
|
-
async prompt(msg) {
|
|
2916
|
+
async prompt(msg, ctx) {
|
|
2914
2917
|
const text = String(msg.text ?? "").trim();
|
|
2915
2918
|
const { images, imageNotes, imageRefs, files } = attachmentsFrom(msg.attachments);
|
|
2916
2919
|
if (!text && !images.length && !files.length)
|
|
@@ -2963,6 +2966,14 @@ const RELAY_COMMANDS = {
|
|
|
2963
2966
|
eventLog.appendAttachments(record.id, promptText, [...imageRefs, ...fileRefs]);
|
|
2964
2967
|
const agentPrompt = promptForAgent(record, promptText);
|
|
2965
2968
|
const cmid = typeof msg.clientMessageId === "string" && msg.clientMessageId ? msg.clientMessageId : undefined;
|
|
2969
|
+
// A retry of a prompt we already took: the caller missed our echo (that is
|
|
2970
|
+
// why it retried), so acknowledge it again — to the caller only, since
|
|
2971
|
+
// other clients already rendered the first one. Without this the client
|
|
2972
|
+
// keeps the message "sending" and resends it on every reconnect.
|
|
2973
|
+
if (promptDedupe.has(cmid)) {
|
|
2974
|
+
ctx.reply({ type: "session.user_message", sessionId: record.id, text: promptText, clientMessageId: cmid, retry: true });
|
|
2975
|
+
return;
|
|
2976
|
+
}
|
|
2966
2977
|
void dedupePrompt(cmid, async () => {
|
|
2967
2978
|
broadcast({ type: "session.user_message", sessionId: record.id, text: promptText, clientMessageId: msg.clientMessageId });
|
|
2968
2979
|
void sessionNamer.maybeNameSession(record, promptText);
|
package/package.json
CHANGED