privateboard 0.1.4 → 0.1.5
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 +1003 -284
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/public/agent-overlay.js +2 -0
- package/public/agent-profile.js +7 -3
- package/public/app.js +143 -31
- package/public/avatars/chair.svg +1 -98
- package/public/avatars/first-principles.svg +1 -122
- package/public/avatars/historian.svg +1 -0
- package/public/avatars/long-horizon.svg +1 -147
- package/public/avatars/phenomenologist.svg +1 -130
- package/public/avatars/socrates.svg +1 -187
- package/public/avatars/user-empathy.svg +1 -117
- package/public/avatars/value-investor.svg +1 -117
- package/public/index.html +38 -1
- package/public/new-agent.js +5 -3
- package/public/report/spines/a16z-thesis.css +10 -5
- package/public/report/spines/anthropic-essay.css +11 -4
- package/public/report/spines/boardroom-dark.css +15 -5
- package/public/report/spines/gartner-note.css +8 -3
- package/public/report/spines/mckinsey-deck.css +8 -3
- package/public/report/spines/openai-paper.css +8 -3
- package/public/report.html +570 -141
- package/public/room-settings.js +2 -0
- package/public/user-settings.css +178 -0
- package/public/user-settings.js +172 -17
package/package.json
CHANGED
package/public/agent-overlay.js
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
const MODEL_LABELS = {
|
|
18
18
|
"opus-4-7": { name: "Claude Opus 4.7", provider: "Anthropic" },
|
|
19
19
|
"sonnet-4-6": { name: "Claude Sonnet 4.6", provider: "Anthropic" },
|
|
20
|
+
"opus-4-6": { name: "Claude Opus 4.6", provider: "Anthropic" },
|
|
21
|
+
"opus-4-6-fast": { name: "Claude Opus 4.6 Fast", provider: "Anthropic" },
|
|
20
22
|
"haiku-4-5": { name: "Claude Haiku 4.5", provider: "Anthropic" },
|
|
21
23
|
"gpt-5-5": { name: "GPT-5.5", provider: "OpenAI" },
|
|
22
24
|
"gpt-5-4": { name: "GPT-5.4", provider: "OpenAI" },
|
package/public/agent-profile.js
CHANGED
|
@@ -586,6 +586,8 @@
|
|
|
586
586
|
const MODEL_LABELS = {
|
|
587
587
|
"sonnet-4-6": { name: "Sonnet 4.6", deck: "balanced · default" },
|
|
588
588
|
"opus-4-7": { name: "Opus 4.7", deck: "deep reasoning" },
|
|
589
|
+
"opus-4-6": { name: "Opus 4.6", deck: "prior-gen flagship" },
|
|
590
|
+
"opus-4-6-fast": { name: "Opus 4.6 Fast", deck: "faster 4.6 · same intelligence" },
|
|
589
591
|
"haiku-4-5": { name: "Haiku 4.5", deck: "fast · low-cost" },
|
|
590
592
|
"gpt-5-5": { name: "GPT-5.5", deck: "flagship · 1M ctx" },
|
|
591
593
|
"gpt-5-4": { name: "GPT-5.4", deck: "general · 1M ctx" },
|
|
@@ -1837,9 +1839,11 @@
|
|
|
1837
1839
|
// OpenRouter id, so verify + room calls hit the right model.
|
|
1838
1840
|
const PROFILE_MODELS = [
|
|
1839
1841
|
// Anthropic
|
|
1840
|
-
{ v: "opus-4-7", name: "Claude Opus 4.7",
|
|
1841
|
-
{ v: "sonnet-4-6", name: "Claude Sonnet 4.6",
|
|
1842
|
-
{ v: "
|
|
1842
|
+
{ v: "opus-4-7", name: "Claude Opus 4.7", provider: "Anthropic", deck: "deep reasoning · default" },
|
|
1843
|
+
{ v: "sonnet-4-6", name: "Claude Sonnet 4.6", provider: "Anthropic", deck: "balanced · 1M ctx" },
|
|
1844
|
+
{ v: "opus-4-6", name: "Claude Opus 4.6", provider: "Anthropic", deck: "prior-gen flagship" },
|
|
1845
|
+
{ v: "opus-4-6-fast", name: "Claude Opus 4.6 Fast", provider: "Anthropic", deck: "faster 4.6 · same intelligence" },
|
|
1846
|
+
{ v: "haiku-4-5", name: "Claude Haiku 4.5", provider: "Anthropic", deck: "fast · low-cost" },
|
|
1843
1847
|
// OpenAI
|
|
1844
1848
|
{ v: "gpt-5-5-pro", name: "GPT-5.5 Pro", provider: "OpenAI", deck: "flagship · 1M ctx" },
|
|
1845
1849
|
{ v: "gpt-5-5", name: "GPT-5.5", provider: "OpenAI", deck: "1M ctx" },
|
package/public/app.js
CHANGED
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
const MODEL_LABELS = {
|
|
20
20
|
"sonnet-4-6": "Sonnet 4.6",
|
|
21
21
|
"opus-4-7": "Opus 4.7",
|
|
22
|
+
"opus-4-6": "Opus 4.6",
|
|
23
|
+
"opus-4-6-fast": "Opus 4.6 Fast",
|
|
22
24
|
"haiku-4-5": "Haiku 4.5",
|
|
23
25
|
"gpt-5-5": "GPT-5.5",
|
|
24
26
|
"gpt-5-4": "GPT-5.4",
|
|
@@ -41,9 +43,11 @@
|
|
|
41
43
|
* enough context (label · provider · short deck) to choose at a
|
|
42
44
|
* glance. */
|
|
43
45
|
const AGENT_COMPOSER_MODELS = [
|
|
44
|
-
{ v: "opus-4-7", label: "Claude Opus 4.7",
|
|
45
|
-
{ v: "sonnet-4-6", label: "Claude Sonnet 4.6",
|
|
46
|
-
{ v: "
|
|
46
|
+
{ v: "opus-4-7", label: "Claude Opus 4.7", provider: "Anthropic", deck: "deep reasoning" },
|
|
47
|
+
{ v: "sonnet-4-6", label: "Claude Sonnet 4.6", provider: "Anthropic", deck: "balanced · default" },
|
|
48
|
+
{ v: "opus-4-6", label: "Claude Opus 4.6", provider: "Anthropic", deck: "prior-gen flagship" },
|
|
49
|
+
{ v: "opus-4-6-fast", label: "Claude Opus 4.6 Fast", provider: "Anthropic", deck: "faster 4.6 · same intelligence" },
|
|
50
|
+
{ v: "haiku-4-5", label: "Claude Haiku 4.5", provider: "Anthropic", deck: "fast · low-cost" },
|
|
47
51
|
{ v: "gpt-5-5-pro", label: "GPT-5.5 Pro", provider: "OpenAI", deck: "flagship · 1M ctx" },
|
|
48
52
|
{ v: "gpt-5-5", label: "GPT-5.5", provider: "OpenAI", deck: "1M ctx" },
|
|
49
53
|
{ v: "gpt-5-4", label: "GPT-5.4", provider: "OpenAI", deck: "general · 1M ctx" },
|
|
@@ -4155,10 +4159,25 @@
|
|
|
4155
4159
|
stats.probeCount > 0 ? `<span class="sa-chip"><span class="sa-chip-mark">✎</span>${stats.probeCount} ${this.escape(t.probed)}</span>` : "",
|
|
4156
4160
|
].filter(Boolean).join("");
|
|
4157
4161
|
|
|
4162
|
+
// Cap default-visible upvoted points at 2 · the rest collapse
|
|
4163
|
+
// behind a [+ N more] toggle. Long lists were dominating the
|
|
4164
|
+
// analytics tile; capping keeps the section as a tight strip
|
|
4165
|
+
// and lets the user opt in.
|
|
4166
|
+
const VALUE_PREVIEW_CAP = 2;
|
|
4167
|
+
const moreLabel = (n) => isZh ? `[ + 展开剩余 ${n} 条 ]` : `[ + show ${n} more ]`;
|
|
4168
|
+
const lessLabel = isZh ? "[ 收起 ]" : "[ collapse ]";
|
|
4158
4169
|
const upvotedHtml = stats.upvotedPoints.length > 0
|
|
4159
|
-
?
|
|
4160
|
-
|
|
4161
|
-
|
|
4170
|
+
? (() => {
|
|
4171
|
+
const items = stats.upvotedPoints.map((p, i) => {
|
|
4172
|
+
const cls = i >= VALUE_PREVIEW_CAP ? "sa-point sa-point-extra" : "sa-point";
|
|
4173
|
+
return `<li class="${cls}"><span class="sa-point-mark">▲</span><span class="sa-point-body">${this.escape(p.body)}</span></li>`;
|
|
4174
|
+
}).join("");
|
|
4175
|
+
const overflow = stats.upvotedPoints.length - VALUE_PREVIEW_CAP;
|
|
4176
|
+
const toggle = overflow > 0
|
|
4177
|
+
? `<button type="button" class="sa-points-toggle" data-sa-toggle aria-expanded="false" data-more-label="${this.escape(moreLabel(overflow))}" data-less-label="${this.escape(lessLabel)}">${this.escape(moreLabel(overflow))}</button>`
|
|
4178
|
+
: "";
|
|
4179
|
+
return `<ul class="sa-points" data-sa-points>${items}</ul>${toggle}`;
|
|
4180
|
+
})()
|
|
4162
4181
|
: "";
|
|
4163
4182
|
const valueBlock = (valueChips || upvotedHtml)
|
|
4164
4183
|
? `
|
|
@@ -4231,6 +4250,21 @@
|
|
|
4231
4250
|
} else {
|
|
4232
4251
|
briefCard.parentNode.insertBefore(block, briefCard);
|
|
4233
4252
|
}
|
|
4253
|
+
|
|
4254
|
+
// Wire the [+ show N more] toggle for the upvoted points list.
|
|
4255
|
+
const toggleBtn = block.querySelector("[data-sa-toggle]");
|
|
4256
|
+
if (toggleBtn) {
|
|
4257
|
+
const list = block.querySelector("[data-sa-points]");
|
|
4258
|
+
toggleBtn.addEventListener("click", () => {
|
|
4259
|
+
const expanded = toggleBtn.getAttribute("aria-expanded") === "true";
|
|
4260
|
+
const next = !expanded;
|
|
4261
|
+
toggleBtn.setAttribute("aria-expanded", String(next));
|
|
4262
|
+
if (list) list.classList.toggle("sa-points-expanded", next);
|
|
4263
|
+
toggleBtn.textContent = next
|
|
4264
|
+
? toggleBtn.dataset.lessLabel
|
|
4265
|
+
: toggleBtn.dataset.moreLabel;
|
|
4266
|
+
});
|
|
4267
|
+
}
|
|
4234
4268
|
},
|
|
4235
4269
|
|
|
4236
4270
|
renderPausedBar() {
|
|
@@ -8674,20 +8708,87 @@
|
|
|
8674
8708
|
.replace(/&[a-z]+;/gi, " "); // HTML entities
|
|
8675
8709
|
const cjk = stripped.match(/[一-鿿㐀-䶿豈--ゟ゠-ヿ]/g);
|
|
8676
8710
|
const cjkCount = cjk ? cjk.length : 0;
|
|
8677
|
-
|
|
8678
|
-
|
|
8679
|
-
|
|
8680
|
-
|
|
8681
|
-
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
|
|
8711
|
+
const isCjk = cjkCount >= stripped.length * 0.3 && cjkCount > 80;
|
|
8712
|
+
let count;
|
|
8713
|
+
let label;
|
|
8714
|
+
if (isCjk) {
|
|
8715
|
+
count = cjkCount;
|
|
8716
|
+
label = `~${count.toLocaleString("en-US")} 字`;
|
|
8717
|
+
} else {
|
|
8718
|
+
const words = stripped.trim().split(/\s+/).filter((w) => w.length > 0);
|
|
8719
|
+
count = words.length;
|
|
8720
|
+
if (count === 0) return null;
|
|
8721
|
+
label = count === 1 ? "1 word" : `${count.toLocaleString("en-US")} words`;
|
|
8722
|
+
}
|
|
8723
|
+
// Tone-aware sweet band · brainstorm recaps run lean (concrete
|
|
8724
|
+
// ideas, not deep analysis); standard rooms (constructive /
|
|
8725
|
+
// debate) land in the middle; research / critique rooms shoulder
|
|
8726
|
+
// a denser shape (assumptions + scenarios + indicators + threats
|
|
8727
|
+
// to validity all naturally lengthen the body).
|
|
8728
|
+
const tone = (this.currentRoom?.mode || "constructive").toLowerCase();
|
|
8729
|
+
const bandKind = tone === "brainstorm"
|
|
8730
|
+
? "lean"
|
|
8731
|
+
: (tone === "research" || tone === "critique" ? "dense" : "standard");
|
|
8732
|
+
// Brainstorm `lean` was originally 600-1500 zh / 400-1000 en —
|
|
8733
|
+
// calibrated against "quick recap" briefs with 1-2 directors.
|
|
8734
|
+
// That undercounted real brainstorm rooms: 3-4 directors × 2-3
|
|
8735
|
+
// rounds × 2-3 ideas-per-turn easily produces 12-20 ideas, each
|
|
8736
|
+
// worth 80-150 words (concept + why-it-matters + what-it-opens).
|
|
8737
|
+
// 1500-2200 words / 2000-3000 字 is a healthy, idea-dense
|
|
8738
|
+
// brainstorm — bumping the band so that lands in `sweet`, not
|
|
8739
|
+
// `dense`. Standard / dense bands unchanged.
|
|
8740
|
+
const bands = isCjk
|
|
8741
|
+
? ({
|
|
8742
|
+
lean: { sweetLo: 1000, sweetHi: 2200, denseHi: 3800, longHi: 5500 },
|
|
8743
|
+
standard: { sweetLo: 1500, sweetHi: 2800, denseHi: 4500, longHi: 6500 },
|
|
8744
|
+
dense: { sweetLo: 2500, sweetHi: 4500, denseHi: 6500, longHi: 8000 },
|
|
8745
|
+
})[bandKind]
|
|
8746
|
+
: ({
|
|
8747
|
+
lean: { sweetLo: 800, sweetHi: 1600, denseHi: 2800, longHi: 4000 },
|
|
8748
|
+
standard: { sweetLo: 1000, sweetHi: 1800, denseHi: 3000, longHi: 4500 },
|
|
8749
|
+
dense: { sweetLo: 1800, sweetHi: 3000, denseHi: 4500, longHi: 5500 },
|
|
8750
|
+
})[bandKind];
|
|
8751
|
+
let tier;
|
|
8752
|
+
if (count < bands.sweetLo) tier = "thin";
|
|
8753
|
+
else if (count <= bands.sweetHi) tier = "sweet";
|
|
8754
|
+
else if (count <= bands.denseHi) tier = "dense";
|
|
8755
|
+
else if (count <= bands.longHi) tier = "long";
|
|
8756
|
+
else tier = "too-long";
|
|
8757
|
+
return { label, tier, count, isCjk, tone, bands };
|
|
8758
|
+
},
|
|
8759
|
+
|
|
8760
|
+
/** Tooltip explaining what the brief-card word-count chip's colour
|
|
8761
|
+
* means · tone-aware so the user understands why a 2,500-word
|
|
8762
|
+
* brainstorm recap reads "dense" while the same length in a
|
|
8763
|
+
* research note reads "sweet." */
|
|
8764
|
+
_briefWordCountTip(wc) {
|
|
8765
|
+
if (!wc) return "";
|
|
8766
|
+
const isZh = wc.isCjk;
|
|
8767
|
+
const toneLabel = ({
|
|
8768
|
+
brainstorm: isZh ? "脑暴" : "brainstorm",
|
|
8769
|
+
constructive: isZh ? "构建" : "constructive",
|
|
8770
|
+
debate: isZh ? "辩论" : "debate",
|
|
8771
|
+
research: isZh ? "研究" : "research",
|
|
8772
|
+
critique: isZh ? "评审" : "critique",
|
|
8773
|
+
})[wc.tone] || wc.tone;
|
|
8774
|
+
const range = `${wc.bands.sweetLo.toLocaleString("en-US")}-${wc.bands.sweetHi.toLocaleString("en-US")}`;
|
|
8775
|
+
const unit = isZh ? "字" : "words";
|
|
8776
|
+
const copy = isZh
|
|
8777
|
+
? {
|
|
8778
|
+
"thin": `偏短 · ${toneLabel} 模式甜点区约 ${range} ${unit}`,
|
|
8779
|
+
"sweet": `甜点区 · ${toneLabel} 模式正合适`,
|
|
8780
|
+
"dense": `偏密集 · 已超出 ${toneLabel} 模式甜点区,但仍可读`,
|
|
8781
|
+
"long": `偏长 · 接近"会被存档而非阅读"的临界`,
|
|
8782
|
+
"too-long": `过长 · 大概率会被快速跳读`,
|
|
8783
|
+
}
|
|
8784
|
+
: {
|
|
8785
|
+
"thin": `Lean · ${toneLabel} sweet zone is ${range} ${unit}`,
|
|
8786
|
+
"sweet": `Sweet zone for ${toneLabel} · most read-through-able length`,
|
|
8787
|
+
"dense": `Dense · past the ${toneLabel} sweet zone, still readable`,
|
|
8788
|
+
"long": `Long · approaching "filed instead of read"`,
|
|
8789
|
+
"too-long": `Too long · likely to be skimmed, not read`,
|
|
8790
|
+
};
|
|
8791
|
+
return copy[wc.tier] || "";
|
|
8691
8792
|
},
|
|
8692
8793
|
|
|
8693
8794
|
/** Render the brief version tab strip · shared by both the error
|
|
@@ -8938,12 +9039,13 @@
|
|
|
8938
9039
|
? `<div class="brief-info brief-info-generating">${this.renderBriefStages(b)}</div>`
|
|
8939
9040
|
: (() => {
|
|
8940
9041
|
const wc = this._briefWordCount(b);
|
|
9042
|
+
const tip = this._briefWordCountTip(wc);
|
|
8941
9043
|
return `<div class="brief-info">
|
|
8942
9044
|
<div class="brief-kicker">// filed by ${this.escape(this.currentChair?.name || "the chair")}</div>
|
|
8943
9045
|
<h2 class="brief-title" data-brief-title>${this.escape(b.title || "(untitled)")}</h2>
|
|
8944
9046
|
<div class="brief-meta-row">
|
|
8945
9047
|
<span class="brief-meta-line">${this.currentMembers.length} authors</span>
|
|
8946
|
-
${wc ? `<span class="brief-meta-sep" aria-hidden="true">·</span><span class="brief-meta-line brief-meta-words">${this.escape(wc)}</span>` : ""}
|
|
9048
|
+
${wc ? `<span class="brief-meta-sep" aria-hidden="true">·</span><span class="brief-meta-line brief-meta-words is-${this.escape(wc.tier)}" title="${this.escape(tip)}">${this.escape(wc.label)}</span>` : ""}
|
|
8947
9049
|
<div class="brief-signed">
|
|
8948
9050
|
<div class="brief-signed-avatars">${signed}</div>
|
|
8949
9051
|
</div>
|
|
@@ -9742,16 +9844,14 @@
|
|
|
9742
9844
|
}
|
|
9743
9845
|
return;
|
|
9744
9846
|
}
|
|
9745
|
-
// Follow-up picker · row click
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
|
|
9753
|
-
return;
|
|
9754
|
-
}
|
|
9847
|
+
// Follow-up picker · row click is handled via the `change` event
|
|
9848
|
+
// on the inner checkbox (registered separately below), mirroring
|
|
9849
|
+
// the inline composer's pattern. The earlier `preventDefault` +
|
|
9850
|
+
// direct toggle approach left the checkbox's visual state stuck:
|
|
9851
|
+
// preventDefault cancelled the native toggle but the programmatic
|
|
9852
|
+
// `cb.checked = on` raced with the bubble in a way that didn't
|
|
9853
|
+
// visually re-mark the checkbox. The change-event flow lets the
|
|
9854
|
+
// browser draw the check, then syncs state from the new cb state.
|
|
9755
9855
|
// Click on a follow-up tile in the parent room's "Follow-up rooms"
|
|
9756
9856
|
// strip · navigate to the child. Click on the parent banner of a
|
|
9757
9857
|
// follow-up room · navigate up.
|
|
@@ -10359,6 +10459,18 @@
|
|
|
10359
10459
|
const id = row && row.getAttribute("data-composer-pick-id");
|
|
10360
10460
|
if (id) app.toggleComposerDirector(id);
|
|
10361
10461
|
});
|
|
10462
|
+
// Follow-up overlay's director picker · same pattern as the inline
|
|
10463
|
+
// composer above. Listen for `change` on the inner checkbox so the
|
|
10464
|
+
// browser draws the check first, then sync `_followupCastState`
|
|
10465
|
+
// from the post-toggle state. Was previously click + preventDefault,
|
|
10466
|
+
// which left the checkbox visually unticked.
|
|
10467
|
+
document.addEventListener("change", (e) => {
|
|
10468
|
+
const cb = e.target;
|
|
10469
|
+
if (!cb || !cb.matches || !cb.matches('[data-followup-pick-id] input[type="checkbox"]')) return;
|
|
10470
|
+
const row = cb.closest("[data-followup-pick-id]");
|
|
10471
|
+
const id = row && row.getAttribute("data-followup-pick-id");
|
|
10472
|
+
if (id) app.toggleFollowUpCastDirector(id);
|
|
10473
|
+
});
|
|
10362
10474
|
document.addEventListener("click", (e) => {
|
|
10363
10475
|
const btn = e.target.closest("[data-send-button]");
|
|
10364
10476
|
if (!btn) return;
|