privateboard 0.1.0 → 0.1.3
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/cli.js +5281 -989
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/public/agent-overlay.js +3 -3
- package/public/agent-profile.css +5 -4
- package/public/agent-profile.js +35 -9
- package/public/app.js +4408 -580
- package/public/avatar-skill.js +6 -9
- package/public/home.html +1750 -0
- package/public/{prototype-dashboard.html → index.html} +2426 -321
- package/public/onboarding.js +40 -13
- package/public/quote-cta.css +269 -0
- package/public/quote-cta.js +553 -0
- package/public/report/spines/a16z-thesis.css +234 -87
- package/public/report/spines/anthropic-essay.css +587 -191
- package/public/report/spines/boardroom-dark.css +141 -67
- package/public/report/spines/gartner-note.css +105 -23
- package/public/report/spines/mckinsey-deck.css +102 -15
- package/public/report/spines/openai-paper.css +117 -20
- package/public/report.html +3882 -148
- package/public/room-settings.css +6 -4
- package/public/room-settings.js +19 -13
- package/public/themes.css +15 -2
- package/public/user-settings.css +37 -8
- package/public/user-settings.js +68 -164
package/public/onboarding.js
CHANGED
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
{
|
|
85
85
|
tag: "// pivot",
|
|
86
86
|
text: "Six months of runway, real users but flat MRR — pivot the product, hold the line, or shut it down?",
|
|
87
|
-
hint: "
|
|
88
|
-
tone: "
|
|
89
|
-
intensity: "
|
|
87
|
+
hint: "critique room: each director audits the plan — blocker / major / minor",
|
|
88
|
+
tone: "critique",
|
|
89
|
+
intensity: "sharp",
|
|
90
90
|
briefStyle: "auto",
|
|
91
91
|
agents: ["socrates", "first-principles", "long-horizon"],
|
|
92
92
|
},
|
|
@@ -112,9 +112,7 @@
|
|
|
112
112
|
// ── Provider catalogue ─────────────────────────────────
|
|
113
113
|
// Model providers shown on step 2. OpenRouter leads — it's the
|
|
114
114
|
// universal router that unlocks every model from a single key, so
|
|
115
|
-
// it's the lowest-friction first stop for new users.
|
|
116
|
-
// (Claude) is temporarily withheld; bring it back when the
|
|
117
|
-
// direct-Anthropic flow is ready.
|
|
115
|
+
// it's the lowest-friction first stop for new users.
|
|
118
116
|
// `slug` matches /api/keys/{slug} on the backend.
|
|
119
117
|
const KEY_PROVIDERS = [
|
|
120
118
|
{
|
|
@@ -125,6 +123,14 @@
|
|
|
125
123
|
help: "openrouter.ai/keys",
|
|
126
124
|
helpUrl: "https://openrouter.ai/keys",
|
|
127
125
|
},
|
|
126
|
+
{
|
|
127
|
+
slug: "anthropic",
|
|
128
|
+
label: "Claude",
|
|
129
|
+
sub: "Anthropic",
|
|
130
|
+
placeholder: "sk-ant-…",
|
|
131
|
+
help: "console.anthropic.com",
|
|
132
|
+
helpUrl: "https://console.anthropic.com/settings/keys",
|
|
133
|
+
},
|
|
128
134
|
{
|
|
129
135
|
slug: "openai",
|
|
130
136
|
label: "ChatGPT",
|
|
@@ -151,6 +157,7 @@
|
|
|
151
157
|
* and the Next-button enable state. */
|
|
152
158
|
let providerConfigured = {
|
|
153
159
|
openrouter: false,
|
|
160
|
+
anthropic: false,
|
|
154
161
|
openai: false,
|
|
155
162
|
google: false,
|
|
156
163
|
};
|
|
@@ -403,7 +410,7 @@
|
|
|
403
410
|
<div class="onb-field">
|
|
404
411
|
<div class="onb-field-label" data-onb-field-label>${escape(active.label)} API key</div>
|
|
405
412
|
<div class="onb-input-wrap">
|
|
406
|
-
<input class="onb-input" data-onb-key type="password" placeholder="${escape(active.placeholder)}" autocomplete="
|
|
413
|
+
<input class="onb-input" data-onb-key type="password" placeholder="${escape(active.placeholder)}" autocomplete="one-time-code" data-lpignore="true" data-1p-ignore="true" data-form-type="other" spellcheck="false" value="${escape(inputValue)}">
|
|
407
414
|
<button type="button" class="onb-input-reveal" data-onb-reveal aria-label="Show key" aria-pressed="false">show</button>
|
|
408
415
|
</div>
|
|
409
416
|
${status}
|
|
@@ -598,7 +605,23 @@
|
|
|
598
605
|
if (typeof window.boardroomModelsRefresh === "function") {
|
|
599
606
|
refreshes.push(Promise.resolve(window.boardroomModelsRefresh()).catch(() => {}));
|
|
600
607
|
}
|
|
601
|
-
Promise.all(refreshes).finally(() => {
|
|
608
|
+
Promise.all(refreshes).finally(() => {
|
|
609
|
+
if (continuation) {
|
|
610
|
+
continuation();
|
|
611
|
+
} else {
|
|
612
|
+
// Default skip path · the user dismissed onboarding without
|
|
613
|
+
// picking a starter or convene-your-own. Explicitly land
|
|
614
|
+
// them on the new-room composer. Without this, whatever
|
|
615
|
+
// composer mode the dashboard happened to settle into during
|
|
616
|
+
// boot stays put — and on first-run flows that's
|
|
617
|
+
// occasionally "agent" instead of "room", since the order
|
|
618
|
+
// of restore() / app.init() / refreshAgents isn't strictly
|
|
619
|
+
// guaranteed and the agents-tab restorer can win the race.
|
|
620
|
+
if (window.app && typeof window.app.setComposerMode === "function") {
|
|
621
|
+
window.app.setComposerMode("room");
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
});
|
|
602
625
|
}
|
|
603
626
|
|
|
604
627
|
async function createDemoRoom(spec) {
|
|
@@ -630,11 +653,15 @@
|
|
|
630
653
|
function openConveneAfter() {
|
|
631
654
|
setTimeout(() => {
|
|
632
655
|
// Convene-overlay was retired in favour of the inline composer.
|
|
633
|
-
//
|
|
634
|
-
//
|
|
635
|
-
//
|
|
656
|
+
// Use setComposerMode("room") (not closeRoom) so we explicitly
|
|
657
|
+
// pin the new-room composer · closeRoom inherits whatever
|
|
658
|
+
// composerMode is set, and during a boot race that flag can be
|
|
659
|
+
// "agent", which would land the user on the new-agent composer
|
|
660
|
+
// instead of the new-room one.
|
|
636
661
|
try {
|
|
637
|
-
if (window.app && typeof window.app.
|
|
662
|
+
if (window.app && typeof window.app.setComposerMode === "function") {
|
|
663
|
+
window.app.setComposerMode("room");
|
|
664
|
+
} else if (window.app && typeof window.app.closeRoom === "function") {
|
|
638
665
|
window.app.closeRoom();
|
|
639
666
|
} else if (typeof window.openConveneOverlay === "function") {
|
|
640
667
|
window.openConveneOverlay();
|
|
@@ -729,7 +756,7 @@
|
|
|
729
756
|
|
|
730
757
|
function show() {
|
|
731
758
|
if (document.getElementById("onb-overlay")) return;
|
|
732
|
-
// Claim the dashboard sub-state ·
|
|
759
|
+
// Claim the dashboard sub-state · the dashboard page runs a
|
|
733
760
|
// restore tick (~2.5s of 250ms retries) that re-opens whatever
|
|
734
761
|
// agent profile the user last viewed once refreshAgents mounts the
|
|
735
762
|
// sidebar rows. Onboarding always lands the user on a fresh room
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/* ═══════════════════════════════════════════
|
|
2
|
+
QUOTE CTA · selection-driven follow-up
|
|
3
|
+
═══════════════════════════════════════════
|
|
4
|
+
When the user selects text inside a director's message bubble,
|
|
5
|
+
a small floating bar appears above the selection with three
|
|
6
|
+
actions: Probe (opens an overlay), Second (one-click), or Save
|
|
7
|
+
(bookmark to chairman's notes). Probe / Second produce a user
|
|
8
|
+
message that quotes the snippet via markdown blockquote; Save
|
|
9
|
+
is a personal bookmark with no room interaction.
|
|
10
|
+
|
|
11
|
+
Visual vocabulary mirrors the rest of the app: panel-2 surface,
|
|
12
|
+
lime accent, mono micro-type for the action labels. Per the
|
|
13
|
+
no-coloured-left-borders rule, callouts use top tags + indent
|
|
14
|
+
instead of border-left treatments. */
|
|
15
|
+
|
|
16
|
+
/* Floating action bar · two segmented buttons above the selection.
|
|
17
|
+
Restrained surface · panel-2 base, neutral hairline border, soft
|
|
18
|
+
shadow for elevation. No lime border, no notch · the bar is just
|
|
19
|
+
text-and-icon, not a feature. Inter-button divider is structural
|
|
20
|
+
border-right between adjacent items, not a callout treatment. */
|
|
21
|
+
.qcta {
|
|
22
|
+
position: absolute;
|
|
23
|
+
z-index: 1400;
|
|
24
|
+
display: none;
|
|
25
|
+
background: var(--panel-2, #1A1A18);
|
|
26
|
+
border: 0.5px solid var(--line-strong, #3A3A35);
|
|
27
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
28
|
+
box-shadow: 0 4px 14px -6px rgba(0, 0, 0, 0.55);
|
|
29
|
+
white-space: nowrap;
|
|
30
|
+
user-select: none;
|
|
31
|
+
}
|
|
32
|
+
.qcta.open { display: inline-flex; align-items: stretch; }
|
|
33
|
+
|
|
34
|
+
.qcta-btn {
|
|
35
|
+
appearance: none;
|
|
36
|
+
background: transparent;
|
|
37
|
+
border: 0;
|
|
38
|
+
color: var(--text, #C8C5BE);
|
|
39
|
+
font-family: inherit;
|
|
40
|
+
font-size: 12px;
|
|
41
|
+
font-weight: 500;
|
|
42
|
+
letter-spacing: 0;
|
|
43
|
+
padding: 7px 13px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
display: inline-flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 6px;
|
|
48
|
+
transition: color 0.12s;
|
|
49
|
+
}
|
|
50
|
+
/* Tighten the inner edge of each button so the two CTAs sit close
|
|
51
|
+
together. Outer edges keep their 13px breathing room against the
|
|
52
|
+
bar border. */
|
|
53
|
+
.qcta-btn:not(:last-child) { padding-right: 6px; }
|
|
54
|
+
.qcta-btn:not(:first-child) { padding-left: 6px; }
|
|
55
|
+
.qcta-btn:hover { color: var(--lime, #6FB572); }
|
|
56
|
+
.qcta-btn:hover .ico { color: var(--lime, #6FB572); }
|
|
57
|
+
.qcta-btn .ico {
|
|
58
|
+
display: inline-flex;
|
|
59
|
+
align-items: center;
|
|
60
|
+
font-size: 12.5px;
|
|
61
|
+
font-weight: 500;
|
|
62
|
+
line-height: 1;
|
|
63
|
+
color: var(--text-soft, #8E8B83);
|
|
64
|
+
transition: color 0.12s;
|
|
65
|
+
}
|
|
66
|
+
.qcta-btn .ico svg { display: block; }
|
|
67
|
+
|
|
68
|
+
/* Read-only hint · shown only when the bar is in `qcta-readonly`
|
|
69
|
+
state (adjourned room). The buttons collapse out of the row and
|
|
70
|
+
the hint takes their place — the bar still pops up to acknowledge
|
|
71
|
+
the user's selection, but explains why probe / second can't fire. */
|
|
72
|
+
.qcta-hint {
|
|
73
|
+
display: none;
|
|
74
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
75
|
+
font-size: 11px;
|
|
76
|
+
font-weight: 500;
|
|
77
|
+
letter-spacing: 0.04em;
|
|
78
|
+
color: var(--text-soft, #8E8B83);
|
|
79
|
+
padding: 8px 13px;
|
|
80
|
+
white-space: nowrap;
|
|
81
|
+
}
|
|
82
|
+
/* Adjourned-room state · Probe / Second hide (they post to a
|
|
83
|
+
closed room), but Save stays — bookmarking from a finished
|
|
84
|
+
session is a primary use case. */
|
|
85
|
+
.qcta.qcta-readonly .qcta-btn:not(.qcta-btn-save) { display: none; }
|
|
86
|
+
.qcta.qcta-readonly .qcta-hint { display: inline-flex; align-items: center; }
|
|
87
|
+
|
|
88
|
+
/* ─── Save toast ─────────────────────────────────────────────
|
|
89
|
+
Lightweight feedback after a successful POST /api/notes (or a
|
|
90
|
+
failure). Bottom-center anchored, fades in/out. Lime for ok,
|
|
91
|
+
red-tinted for error. Click to dismiss early. */
|
|
92
|
+
.qcta-toast {
|
|
93
|
+
position: fixed;
|
|
94
|
+
bottom: 24px;
|
|
95
|
+
left: 50%;
|
|
96
|
+
transform: translate(-50%, 8px);
|
|
97
|
+
z-index: 1600;
|
|
98
|
+
background: var(--panel, #131312);
|
|
99
|
+
border: 0.5px solid var(--lime, #6FB572);
|
|
100
|
+
color: var(--text, #C8C5BE);
|
|
101
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
102
|
+
font-size: 11.5px;
|
|
103
|
+
font-weight: 500;
|
|
104
|
+
letter-spacing: 0.04em;
|
|
105
|
+
padding: 9px 16px;
|
|
106
|
+
pointer-events: none;
|
|
107
|
+
opacity: 0;
|
|
108
|
+
transition: opacity 0.16s ease-out, transform 0.16s ease-out;
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
box-shadow: 0 14px 30px -14px rgba(0, 0, 0, 0.55);
|
|
111
|
+
}
|
|
112
|
+
.qcta-toast.open {
|
|
113
|
+
opacity: 1;
|
|
114
|
+
transform: translate(-50%, 0);
|
|
115
|
+
pointer-events: auto;
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
}
|
|
118
|
+
.qcta-toast.kind-error {
|
|
119
|
+
border-color: #d36a6a;
|
|
120
|
+
color: #f0bdbd;
|
|
121
|
+
}
|
|
122
|
+
.qcta-toast.kind-ok::before {
|
|
123
|
+
content: "✓ ";
|
|
124
|
+
color: var(--lime, #6FB572);
|
|
125
|
+
font-weight: 700;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/* Ask-follow-up overlay · backdrop + modal. Same chrome family
|
|
129
|
+
as openSendChoiceModal (.pc-overlay) so the family stays coherent. */
|
|
130
|
+
.qask-overlay {
|
|
131
|
+
position: fixed;
|
|
132
|
+
inset: 0;
|
|
133
|
+
background: rgba(8, 8, 8, 0.5);
|
|
134
|
+
-webkit-backdrop-filter: blur(8px) saturate(1.05);
|
|
135
|
+
backdrop-filter: blur(8px) saturate(1.05);
|
|
136
|
+
z-index: 1500;
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
justify-content: center;
|
|
140
|
+
padding: 24px;
|
|
141
|
+
animation: qask-fade 0.16s ease-out;
|
|
142
|
+
}
|
|
143
|
+
@keyframes qask-fade { from { opacity: 0; } to { opacity: 1; } }
|
|
144
|
+
|
|
145
|
+
.qask-modal {
|
|
146
|
+
width: 100%;
|
|
147
|
+
max-width: 560px;
|
|
148
|
+
background: var(--panel, #131312);
|
|
149
|
+
border: 0.5px solid var(--lime, #6FB572);
|
|
150
|
+
color: var(--text, #C8C5BE);
|
|
151
|
+
display: flex;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
box-shadow: 0 30px 60px -20px rgba(0, 0, 0, 0.65);
|
|
154
|
+
animation: qask-rise 0.2s ease-out;
|
|
155
|
+
}
|
|
156
|
+
@keyframes qask-rise {
|
|
157
|
+
from { transform: translateY(8px); opacity: 0; }
|
|
158
|
+
to { transform: translateY(0); opacity: 1; }
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.qask-classification {
|
|
162
|
+
padding: 8px 14px;
|
|
163
|
+
border-bottom: 0.5px solid var(--line-bright, #2A2A26);
|
|
164
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
165
|
+
font-size: 9px;
|
|
166
|
+
letter-spacing: 0.18em;
|
|
167
|
+
text-transform: uppercase;
|
|
168
|
+
color: var(--text-faint, #3A382F);
|
|
169
|
+
display: flex;
|
|
170
|
+
justify-content: space-between;
|
|
171
|
+
align-items: center;
|
|
172
|
+
background: var(--panel-2, #1A1A18);
|
|
173
|
+
}
|
|
174
|
+
.qask-classification .dot { color: var(--lime, #6FB572); }
|
|
175
|
+
.qask-classification .right { color: var(--text-faint, #3A382F); }
|
|
176
|
+
|
|
177
|
+
.qask-body { padding: 18px 18px 14px; display: flex; flex-direction: column; gap: 12px; }
|
|
178
|
+
|
|
179
|
+
/* Quote callout · top tag + indented italic body. NO left-border
|
|
180
|
+
treatment per the project-wide rule. */
|
|
181
|
+
.qask-quote {
|
|
182
|
+
background: var(--panel-2, #1A1A18);
|
|
183
|
+
padding: 12px 14px;
|
|
184
|
+
display: flex;
|
|
185
|
+
flex-direction: column;
|
|
186
|
+
gap: 6px;
|
|
187
|
+
max-height: 180px;
|
|
188
|
+
overflow-y: auto;
|
|
189
|
+
}
|
|
190
|
+
.qask-quote-tag {
|
|
191
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
192
|
+
font-size: 9px;
|
|
193
|
+
letter-spacing: 0.18em;
|
|
194
|
+
text-transform: uppercase;
|
|
195
|
+
color: var(--text-faint, #3A382F);
|
|
196
|
+
font-weight: 700;
|
|
197
|
+
}
|
|
198
|
+
.qask-quote-body {
|
|
199
|
+
font-size: 12.5px;
|
|
200
|
+
line-height: 1.55;
|
|
201
|
+
color: var(--text-soft, #8E8B83);
|
|
202
|
+
font-style: italic;
|
|
203
|
+
white-space: pre-wrap;
|
|
204
|
+
word-break: break-word;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.qask-input-wrap {
|
|
208
|
+
border: 0.5px solid var(--line-strong, #3A3A35);
|
|
209
|
+
background: var(--bg, #0A0A0A);
|
|
210
|
+
display: flex;
|
|
211
|
+
align-items: stretch;
|
|
212
|
+
transition: border-color 0.12s;
|
|
213
|
+
}
|
|
214
|
+
.qask-input-wrap:focus-within { border-color: var(--lime, #6FB572); }
|
|
215
|
+
.qask-input-wrap::before {
|
|
216
|
+
content: ">";
|
|
217
|
+
color: var(--lime, #6FB572);
|
|
218
|
+
font-weight: 700;
|
|
219
|
+
font-size: 13px;
|
|
220
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
221
|
+
padding: 9px 0 0 11px;
|
|
222
|
+
align-self: flex-start;
|
|
223
|
+
}
|
|
224
|
+
.qask-input {
|
|
225
|
+
flex: 1;
|
|
226
|
+
border: none;
|
|
227
|
+
background: transparent;
|
|
228
|
+
font-family: var(--font-human, var(--mono));
|
|
229
|
+
font-size: 13.5px;
|
|
230
|
+
color: var(--text, #C8C5BE);
|
|
231
|
+
outline: none;
|
|
232
|
+
padding: 9px 12px;
|
|
233
|
+
letter-spacing: -0.003em;
|
|
234
|
+
width: 100%;
|
|
235
|
+
resize: none;
|
|
236
|
+
min-height: 72px;
|
|
237
|
+
line-height: 1.5;
|
|
238
|
+
}
|
|
239
|
+
.qask-input::placeholder { color: var(--text-faint, #3A382F); }
|
|
240
|
+
|
|
241
|
+
.qask-foot {
|
|
242
|
+
padding: 10px 14px;
|
|
243
|
+
border-top: 0.5px solid var(--line-bright, #2A2A26);
|
|
244
|
+
background: var(--panel-2, #1A1A18);
|
|
245
|
+
display: flex;
|
|
246
|
+
justify-content: flex-end;
|
|
247
|
+
align-items: center;
|
|
248
|
+
gap: 8px;
|
|
249
|
+
}
|
|
250
|
+
.qask-btn {
|
|
251
|
+
font-family: var(--mono, "Inter", system-ui, sans-serif);
|
|
252
|
+
font-size: 10px;
|
|
253
|
+
font-weight: 700;
|
|
254
|
+
text-transform: uppercase;
|
|
255
|
+
letter-spacing: 0.1em;
|
|
256
|
+
padding: 7px 14px;
|
|
257
|
+
border: 0.5px solid var(--line-strong, #3A3A35);
|
|
258
|
+
background: transparent;
|
|
259
|
+
color: var(--text-soft, #8E8B83);
|
|
260
|
+
cursor: pointer;
|
|
261
|
+
transition: border-color 0.12s, color 0.12s, background 0.12s;
|
|
262
|
+
}
|
|
263
|
+
.qask-btn:hover { border-color: var(--lime, #6FB572); color: var(--lime, #6FB572); }
|
|
264
|
+
.qask-btn.primary {
|
|
265
|
+
border-color: var(--lime, #6FB572);
|
|
266
|
+
color: var(--lime, #6FB572);
|
|
267
|
+
}
|
|
268
|
+
.qask-btn.primary:hover { background: var(--lime, #6FB572); color: var(--bg, #0A0A0A); }
|
|
269
|
+
.qask-btn[disabled] { opacity: 0.4; cursor: not-allowed; }
|