@poodle64/librarian 2026.9.2 → 2026.9.4
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.
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
|
|
42
42
|
// What the agent is being asked about — chat with this document, this
|
|
43
43
|
// collection, or the whole library. Callers that have no narrower scope
|
|
44
|
-
// pass neither name
|
|
44
|
+
// pass neither name, leaving "All collections" the sole entry — and a
|
|
45
|
+
// sole entry is not a choice, so `hasChoice` below hides it rather than
|
|
46
|
+
// rendering a chip with nothing to switch to.
|
|
45
47
|
const choices = $derived(
|
|
46
48
|
[
|
|
47
49
|
documentName ? { id: 'document' as const, label: documentName } : null,
|
|
@@ -50,6 +52,12 @@
|
|
|
50
52
|
].filter((c) => c !== null)
|
|
51
53
|
);
|
|
52
54
|
|
|
55
|
+
// A room with one shelf set has one scope, fixed by the caller never
|
|
56
|
+
// passing a name — no pick to make, so the row renders nothing rather
|
|
57
|
+
// than a chip that only ever reselects itself (design-system, the
|
|
58
|
+
// fixed-scope Composer defect).
|
|
59
|
+
const hasChoice = $derived(choices.length > 1);
|
|
60
|
+
|
|
53
61
|
// Three chips in a narrow column clipped all three to fragments
|
|
54
62
|
// ("defence-s…", "All colle…"). Wrapping beats truncating: a chip a reader
|
|
55
63
|
// cannot finish reading is not a control, it is decoration.
|
|
@@ -76,20 +84,22 @@
|
|
|
76
84
|
></textarea>
|
|
77
85
|
|
|
78
86
|
<div class="flex items-center gap-2 px-3 pb-2.5">
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
{#if hasChoice}
|
|
88
|
+
<div class="flex min-w-0 flex-wrap items-center gap-1">
|
|
89
|
+
{#each choices as choice (choice.id)}
|
|
90
|
+
<button
|
|
91
|
+
type="button"
|
|
92
|
+
onclick={() => onscope(choice.id)}
|
|
93
|
+
class="max-w-full truncate rounded-full px-2 py-0.5 text-xs transition-colors {scope ===
|
|
94
|
+
choice.id
|
|
95
|
+
? 'bg-primary/15 text-foreground border-primary/40 border'
|
|
96
|
+
: 'text-muted-foreground hover:text-foreground border border-transparent'}"
|
|
97
|
+
>
|
|
98
|
+
{choice.label}
|
|
99
|
+
</button>
|
|
100
|
+
{/each}
|
|
101
|
+
</div>
|
|
102
|
+
{/if}
|
|
93
103
|
<span class="flex-1"></span>
|
|
94
104
|
{#if running}
|
|
95
105
|
<button
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The scope chip renders only when there is a genuine pick between two or
|
|
3
|
+
* more scopes (design-system, the fixed-scope Composer defect). A room with
|
|
4
|
+
* one shelf set passes neither `documentName` nor `collectionName`, leaving
|
|
5
|
+
* "All collections" as the sole entry — and a sole entry is console
|
|
6
|
+
* furniture, not a control.
|
|
7
|
+
*/
|
|
8
|
+
import { describe, it, expect } from 'vitest';
|
|
9
|
+
import { render, screen } from '@testing-library/svelte';
|
|
10
|
+
import Composer from './composer.svelte';
|
|
11
|
+
describe('Composer scope chip', () => {
|
|
12
|
+
it('renders nothing when the caller has fixed the scope', () => {
|
|
13
|
+
render(Composer, {
|
|
14
|
+
props: {
|
|
15
|
+
value: '',
|
|
16
|
+
running: false,
|
|
17
|
+
scope: 'library',
|
|
18
|
+
onscope: () => { },
|
|
19
|
+
onsubmit: () => { },
|
|
20
|
+
onstop: () => { }
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
expect(screen.queryByText('All collections')).not.toBeInTheDocument();
|
|
24
|
+
});
|
|
25
|
+
it('renders chips once a narrower scope is offered', () => {
|
|
26
|
+
render(Composer, {
|
|
27
|
+
props: {
|
|
28
|
+
value: '',
|
|
29
|
+
running: false,
|
|
30
|
+
scope: 'library',
|
|
31
|
+
collectionName: 'household-legal',
|
|
32
|
+
onscope: () => { },
|
|
33
|
+
onsubmit: () => { },
|
|
34
|
+
onstop: () => { }
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
expect(screen.getByText('All collections')).toBeInTheDocument();
|
|
38
|
+
expect(screen.getByText('household-legal')).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -146,6 +146,12 @@
|
|
|
146
146
|
requirement numbers — so it is the main way a reader picks a reference
|
|
147
147
|
out of a paragraph. Bordered rather than merely tinted, because a tint
|
|
148
148
|
alone is invisible against this palette's flat surfaces. */
|
|
149
|
+
/* Inline, in running text: wraps at word boundaries like the prose around it
|
|
150
|
+
rather than scrolling in its own box — that pattern is reserved for wide
|
|
151
|
+
BLOCK content (a table, a fenced code block) that a reader scrolls past;
|
|
152
|
+
an inline identifier a reader is reading stays in flow. A long citation
|
|
153
|
+
title is exactly the case: nowrap clipped it at the container edge on a
|
|
154
|
+
phone with no way to read the rest. */
|
|
149
155
|
.agent-prose :global(code) {
|
|
150
156
|
font-family: var(--ds-font-mono, monospace);
|
|
151
157
|
font-size: 0.8125em;
|
|
@@ -153,7 +159,8 @@
|
|
|
153
159
|
border: 1px solid var(--border);
|
|
154
160
|
border-radius: 0.35em;
|
|
155
161
|
padding: 0.1em 0.35em;
|
|
156
|
-
white-space:
|
|
162
|
+
white-space: normal;
|
|
163
|
+
overflow-wrap: anywhere;
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
.agent-prose :global(pre) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/librarian",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.4",
|
|
4
4
|
"description": "Milton's conversation surface as a consumable Svelte 5 package: the stream client, transcript state and chat components (transcript, composer, markdown) every household app renders instead of rebuilding.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|