Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 83 additions & 18 deletions web/css/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -423,12 +423,14 @@ a:hover { color: var(--accent-2); }

/* ── Buttons ───────────────────────────────────────────────── */
.btn {
display: inline-flex; align-items: center; gap: 8px;
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
min-height: 36px; /* shared baseline so same-role buttons match exactly */
padding: 8px 14px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--r-sm);
font-family: var(--mono); font-size: 12px; color: var(--text);
font-family: var(--mono); font-size: 12px; line-height: 1.2; color: var(--text);
white-space: nowrap; /* labels never wrap → height/width stay stable (FIX 2c) */
cursor: pointer;
transition: all var(--t-fast);
}
Expand Down Expand Up @@ -482,7 +484,10 @@ a:hover { color: var(--accent-2); }
box-shadow: 0 0 0 3px var(--accent-tint);
}
.field textarea { min-height: 90px; resize: vertical; }
.modal .actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }
.modal .actions { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 20px; flex-wrap: wrap; }
/* All modal action buttons share .btn sizing; equal min-height + nowrap labels
keep same-role buttons identical and aligned regardless of label length. */
.modal .actions .btn { min-height: 38px; }

/* ── Footer ────────────────────────────────────────────────── */
.foot {
Expand Down Expand Up @@ -519,6 +524,57 @@ a:hover { color: var(--accent-2); }
.panel-head { flex-direction: column; align-items: start; }
.pipeline-row { grid-template-columns: 1fr; gap: 16px; }
.pipeline-row::before { display: none; }

/* ── Responsive topbar (FIX 1 / #262) ──────────────────────────
The single 64px no-wrap row crammed brand + Sign in + Submit a
paper + Submit Idea together; long labels wrapped to 2–3 lines
each, so every button was a different height and the row
overflowed below ~375px. Let the row wrap to two lines: brand
stays on the first line, the actions wrap onto their own line as
equal-height, equal-width compact buttons that never overflow. */
.topbar .row {
height: auto; min-height: 56px;
flex-wrap: wrap; gap: 8px 10px;
padding-top: 10px; padding-bottom: 10px;
}
.top-actions {
width: 100%;
gap: 8px;
flex-wrap: wrap;
justify-content: flex-start;
}
/* Buttons size to their (non-wrapping) label so no label is ever clipped,
and wrap to a new line when the row runs out of room. Equal min-height +
shared .btn styling keep them the same height and baseline-aligned
regardless of label length (FIX 2). */
.top-actions > * { flex: 0 1 auto; }
.top-actions .btn,
.top-actions .auth-chip {
justify-content: center;
padding-left: 12px; padding-right: 12px;
}

/* The sort/search .bar was a non-wrapping flex row with a 220px-min search
box, so it overflowed the viewport on phones (horizontal page scroll).
Let it wrap and let the search box take the full width of its own line. */
.bar { flex-wrap: wrap; }
.bar .grow { flex-basis: 100%; height: 0; } /* force the search onto its own row */
.bar .search { min-width: 0; width: 100%; }
}
/* ── Tabs scroll affordance (FIX 1 / FR-002) ────────────────────
.tabs-row scrolls horizontally with a hidden scrollbar, so on narrow
screens there was no hint that more tabs exist off-screen. A right-edge
fade signals "scroll for more"; it sits above the row and ignores
pointer events so taps still reach the tabs. */
.tabs .shell { position: relative; }
.tabs .shell::after {
content: ""; position: absolute; top: 0; right: 0; bottom: 0;
width: 28px; pointer-events: none;
background: linear-gradient(to right, transparent, var(--bg) 85%);
}
@media (min-width: 1100px) {
/* Wide enough that every tab fits — drop the fade to keep desktop clean. */
.tabs .shell::after { display: none; }
}

/* ── llmXive 002 additions: auth chip + artifact dialog + expanded kanban ───── */
Expand Down Expand Up @@ -597,12 +653,10 @@ a:hover { color: var(--accent-2); }
background: var(--accent-tint); color: var(--accent);
margin-top: 6px;
}
.artifact-dialog .ad-close {
background: transparent; border: 0; cursor: pointer;
font-size: 18px; color: var(--muted);
padding: 4px 10px; border-radius: var(--r-sm);
}
.artifact-dialog .ad-close:hover { color: var(--text); background: var(--bg-2); }
/* .ad-close now rides the shared .btn.ghost class (FIX 2). No bespoke sizing —
it inherits the same min-height / padding / font as every other .btn so the
head-action buttons are equal height and aligned. Only the icon size differs. */
.artifact-dialog .ad-close i { font-size: 14px; }

.artifact-dialog .ad-body {
display: grid;
Expand Down Expand Up @@ -777,6 +831,14 @@ a:hover { color: var(--accent-2); }
.artifact-dialog .ad-body { grid-template-columns: 1fr; }
.artifact-dialog .ad-pdf { min-height: 240px; }
}
@media (max-width: 560px) {
/* Stack the dialog title above its action buttons; the buttons then form
one equal-width row so Add review / Send feedback / Close are the same
height and aligned even on a phone (FIX 2). */
.artifact-dialog .ad-head { flex-direction: column; align-items: stretch; }
.artifact-dialog .ad-head-actions { justify-content: stretch; }
.artifact-dialog .ad-head-actions .btn { flex: 1 1 0; min-width: 0; }
}

/* about page extensions */
.pipeline.two-lane .lane {
Expand All @@ -795,9 +857,6 @@ a:hover { color: var(--accent-2); }
left: 5%; right: 5%;
}

/* hidden machine-readable threshold spans */
.thresholds { display: none; }

/* card stage badge */
.card .stage-pill {
font-family: var(--mono); font-size: 10px;
Expand Down Expand Up @@ -1114,13 +1173,19 @@ a:hover { color: var(--accent-2); }
.modal-msg.err { color: oklch(0.5 0.18 30); }
.modal-msg a { color: var(--accent); text-decoration: underline; }

.artifact-dialog .ad-head-actions { display: flex; align-items: center; gap: 8px; }
.artifact-dialog .ad-feedback-btn {
background: transparent; border: 1px solid var(--line-soft); border-radius: var(--r-sm);
color: var(--text-2); font-size: 12px; padding: 6px 10px; cursor: pointer;
display: inline-flex; align-items: center; gap: 6px;
/* Head-action buttons (Add review / Send feedback / Close) all ride the shared
.btn class now (FIX 2): equal min-height, identical padding/font/radius,
nowrap labels, baseline-aligned. The row keeps all three on one line on
normal/desktop dialogs (flex-shrink:0); the ≤560px rule below lets them
wrap into an equal-width row on phones without changing any button height. */
.artifact-dialog .ad-head-actions {
display: flex; align-items: center; gap: 8px;
justify-content: flex-end;
flex-shrink: 0;
}
.artifact-dialog .ad-feedback-btn:hover { border-color: var(--accent); color: var(--accent); }
/* Let the title block absorb the remaining width (and wrap its own text) so the
action row never gets squeezed into wrapping on wide dialogs. */
.artifact-dialog .ad-head > div:first-child { min-width: 0; flex: 1 1 auto; }
.artifact-dialog .ad-feedback {
border-bottom: 1px solid var(--line-soft); background: var(--bg-2);
padding: 14px 20px;
Expand Down
4 changes: 2 additions & 2 deletions web/data/projects.json
Original file line number Diff line number Diff line change
Expand Up @@ -10072,7 +10072,7 @@
"research_reviewer_data_quality_research",
"research_reviewer_filesystem_hygiene"
],
"description": "Seven specialist reviewers (idea quality, creativity, implementation correctness, completeness, code quality, data quality, filesystem hygiene) each vote. Acceptance requires both the points threshold and an accept verdict from every specialist. Human reviews count double.",
"description": "Eight specialist reviewers (a generic reviewer plus idea quality, creativity, implementation correctness, completeness, code quality, data quality, and filesystem hygiene) run an identify → revise → re-review convergence loop. Advancement requires unanimous panel acceptance within a 3-round cap; otherwise the project is kicked back to a prior stage. Human and simulated-personality reviews are advisory inputs routed through stage-aware triage, never a direct gate.",
"example_artifacts": [
{
"github_url": "https://github.com/ContextLab/llmXive/tree/main/projects/PROJ-651-grepseek-training-search-agents-for-dire",
Expand Down Expand Up @@ -10398,7 +10398,7 @@
"paper_reviewer_figure_critic",
"paper_reviewer_jargon_police"
],
"description": "Twelve specialist reviewers (writing, logic, claims, over-reach, safety/ethics, evidence, statistics, code, data, formatting, figures, jargon) each vote. Acceptance requires both the points threshold and an accept verdict from every specialist.",
"description": "Twelve specialist reviewers (writing, logic, claims, over-reach, safety/ethics, evidence, statistics, code, data, formatting, figures, jargon) run an identify → revise → re-review convergence loop. Advancement requires unanimous acceptance from every reviewer within a 3-round cap; otherwise the paper is kicked back carrying full provenance.",
"example_artifacts": [
{
"github_url": "https://github.com/ContextLab/llmXive/tree/main/projects/PROJ-651-grepseek-training-search-agents-for-dire",
Expand Down
16 changes: 5 additions & 11 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -275,20 +275,10 @@ <h2>About llmXive</h2>
</div>
</div>

<aside hidden id="llmxive-thresholds" class="thresholds">
<span data-threshold="research_review_accept_pts">5</span>
<span data-threshold="paper_review_accept_pts">5</span>
<span data-threshold="design_review_accept_pts">5</span>
<span data-threshold="implementation_plan_accept_pts">5</span>
<span data-threshold="llm_review_score">0.5</span>
<span data-threshold="human_review_score">1.0</span>
<span data-threshold="citation_overlap_min">0.7</span>
</aside>

<div class="about-grid">
<div class="about-block">
<h3>What is llmXive?</h3>
<p>llmXive automates scientific discovery end-to-end. A registry of 28 specialist agents — brainstormer, flesh-out, specifier, clarifier, planner, tasker, implementer, reviewer, paper-writer, figure-generator, statistician, proofreader, LaTeX builder, citation validator, and others — drives each project through two complete <a href="https://github.com/github/spec-kit" target="_blank" rel="noopener">Spec Kit</a> pipelines: one for the research itself and one for the paper that reports it.</p>
<p>llmXive automates scientific discovery end-to-end. A registry of specialist agents — brainstormer, flesh-out, specifier, clarifier, planner, tasker, implementer, paper-writer, figure-generator, statistician, proofreader, LaTeX builder, citation validator, and others, plus two panels of focused review lenses — drives each project through two complete <a href="https://github.com/github/spec-kit" target="_blank" rel="noopener">Spec Kit</a> pipelines: one for the research itself and one for the paper that reports it.</p>
</div>
<div class="about-block">
<h3>Spec Kit per project</h3>
Expand All @@ -298,6 +288,10 @@ <h3>Spec Kit per project</h3>
<h3>Two review gates — every specialist must accept</h3>
<p>Research review and paper review run an <strong>identify → revise → re-review</strong> convergence loop driven by the lane's panel — 8 research reviewers (idea quality, creativity, implementation correctness, completeness, code quality, data quality, filesystem hygiene, plus a generic reviewer) and 12 paper specialists (writing, logic, claims, over-reach, safety, evidence, statistics, code, data, formatting, figures, jargon). The gate is <strong>unanimous panel acceptance</strong> within a 3-round cap; otherwise the project is kicked back to a prior stage carrying full provenance. Human and simulated-personality reviews are <em>advisory inputs</em> via stage-aware triage; self-review is rejected by the schema. (Spec 015 supersedes the prior point-based gate.)</p>
</div>
<div class="about-block">
<h3>Claim verification — no fact ships unsourced</h3>
<p>Beyond the review gates, every factual claim in a generated artifact is detected, registered, and resolved against a real source; an unverifiable claim is marked <code>[UNRESOLVED-CLAIM: …]</code> and hard-blocks advancement (spec 016) — execution receipts are harness-signed so an agent can't forge a pass. When a claim can't be verified as written, an authoritative-fill step searches real sources (OEIS, Wikipedia, Wikidata, papers) and substitutes a value <em>only</em> if it is actually present in a fetched source, never model memory (spec 017). Verification picks a per-claim mode — exact count, approximate constant, safe symbolic computation, or source-fact (spec 018). For prose sources, a value is accepted only when the source semantically asserts that <em>this</em> subject has <em>this</em> value, not a coincidental digit match (spec 019).</p>
</div>
<div class="about-block">
<h3>Model selection — right-sized to each task</h3>
<p>Each pipeline step is associated with an appropriate open model. Long, complex tasks (planning, paper writing, deep review) are routed to Qwen3.5&nbsp;122B; faster, less complex tasks (clarifying questions, atomization, quick judgments) are routed to Gemma 3 27B. All inference runs on Dartmouth&rsquo;s <a href="https://rc.dartmouth.edu/ai/computing-resources/discovery-cluster/" target="_blank" rel="noopener">Discovery Cluster</a>, with a fallback to open-weight <a href="https://huggingface.co/" target="_blank" rel="noopener">Hugging&nbsp;Face</a> models run locally via <a href="https://huggingface.co/docs/transformers" target="_blank" rel="noopener">transformers</a> as needed.</p>
Expand Down
17 changes: 17 additions & 0 deletions web/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,23 @@
activate(tab.dataset.tab, tab);
}
if (document.fonts && document.fonts.ready) document.fonts.ready.then(init); else init();

// #262: in-page anchors (the brand `<a href="#papers">` and the About
// page's "Browse projects" / "Find something to review" buttons, which
// point at `#inProgress`) only rewrote the hash — there was no
// `hashchange` listener, so the active tab never switched. Route every
// hash that names a real tab through the same `activate()` path used on
// load, then scroll it into view. Unknown/empty hashes are a no-op so
// unrelated in-page anchors (e.g. `#how-to-contribute`) keep working.
window.addEventListener("hashchange", () => {
const name = (location.hash || "").slice(1);
if (!name) return;
const tab = tabs.find(t => t.dataset.tab === name);
if (!tab) return; // not a tab anchor — leave it alone
if (!tab.classList.contains("active")) activate(name, tab);
const panel = document.querySelector('.panel[data-panel="' + name + '"]');
(panel || tab).scrollIntoView({ behavior: "smooth", block: "start" });
});
// Recompute on font load (widths change once the web font swaps in).
if (document.fonts && document.fonts.ready) document.fonts.ready.then(positionUnderline);

Expand Down
15 changes: 7 additions & 8 deletions web/js/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,13 @@
}
const state = _randomState();
sessionStorage.setItem(KEY_STATE, state);
const authorize = _authorizeUrl();
// FR-011 (account-switching): route through github.com/logout first so the
// user is presented with GitHub's account/consent screen and a *different*
// account can be chosen. This works regardless of whether the OAuth proxy's
// /revoke route is deployed (it's the no-Worker-change fallback path); when
// /revoke IS deployed, signOut() also revokes the grant for good measure.
const logoutUrl = "https://github.com/logout?return_to=" + encodeURIComponent(authorize);
location.href = logoutUrl;
// Navigate STRAIGHT to GitHub's OAuth authorize URL so the user reaches the
// consent screen directly. We must NOT pre-route through github.com/logout:
// GitHub renders a sign-out confirmation page there and does not reliably
// honor return_to to a cross-site authorize URL, so the user would land on a
// sign-out page and never reach consent (issue #217). Account-switching lives
// behind the explicit signOut() action, which revokes the grant via /revoke.
location.href = _authorizeUrl();
}

// Non-blocking, dismissible notice (used when grant-revocation fails).
Expand Down
27 changes: 24 additions & 3 deletions web/js/dialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,16 @@
+ '<div class="ad-head">'
+ '<div><h2 class="ad-title">—</h2><span class="ad-stage-badge"></span></div>'
+ '<div class="ad-head-actions">'
+ '<button class="ad-feedback-btn" type="button"><i class="fa-regular fa-comment-dots"></i> Send feedback</button>'
+ '<button class="ad-close" aria-label="close"><i class="fa-solid fa-xmark"></i> Close</button>'
+ '<button class="btn ad-review-btn" type="button"><i class="fa-regular fa-pen-to-square"></i> Add review</button>'
+ '<button class="btn ad-feedback-btn" type="button"><i class="fa-regular fa-comment-dots"></i> Send feedback</button>'
+ '<button class="btn ghost ad-close" type="button" aria-label="close"><i class="fa-solid fa-xmark"></i> Close</button>'
+ '</div>'
+ '</div>'
+ '<div class="ad-feedback" hidden>'
+ '<div class="ad-fb-inner">'
+ '<label class="field"><span class="l">Your feedback on this artifact</span>'
+ '<textarea class="ad-fb-text" placeholder="What\'s missing, wrong, or could be improved? A maintenance agent will triage this to the right pipeline step within the hour."></textarea></label>'
+ '<div class="ad-fb-actions">'
+ '<div class="ad-fb-actions actions">'
+ '<span class="ad-fb-msg"></span>'
+ '<button class="btn ghost ad-fb-cancel" type="button">Cancel</button>'
+ '<button class="btn primary ad-fb-submit" type="button"><i class="fa-solid fa-paper-plane"></i> Submit feedback</button>'
Expand All @@ -103,6 +104,26 @@
fbPanel.hidden = !fbPanel.hidden;
if (!fbPanel.hidden) { fbMsg.innerHTML = ""; fbMsg.className = "ad-fb-msg"; fbText.focus(); }
});

// FIX 3 (#262 / #5): the human-review modal (#modal-review) existed but had
// no trigger anywhere in the UI. Open it from here, seeding the hidden
// #review-project-id with the project currently shown in this dialog so the
// submit handler in app.js posts the review against the right project.
// (Submission itself still requires GitHub login — #217 — handled in app.js.)
bd.querySelector(".ad-review-btn").addEventListener("click", () => {
const pid = _currentProject ? _currentProject.id : "";
const hidden = document.getElementById("review-project-id");
if (hidden) hidden.value = pid;
const m = document.getElementById("modal-review");
if (m) {
// Close this artifact dialog first: #ad-backdrop is appended to <body>
// after the static modals, so it would otherwise stack above
// #modal-review (same z-index) and hide it. Closing it also gives the
// reviewer a single, focused modal.
close();
m.classList.add("open");
}
});
bd.querySelector(".ad-fb-cancel").addEventListener("click", () => { fbPanel.hidden = true; });
bd.querySelector(".ad-fb-submit").addEventListener("click", async () => {
const Auth = window.LlmxiveAuth;
Expand Down
Loading
Loading