refactor(ui): extract font-size and letter-spacing to tokens (Phase 2 batch 2/4)
Replaces hardcoded TYPE values in ui/src/components/** and ui/src/pages/** with references to new verbatim CSS custom-property tokens in ui/src/index.css, via a new committed codemod (scripts/codemod-extract-type.mjs). - 932 sites rewritten across 143 files: - 728 arbitrary font-size Tailwind classes (text-[Npx]) - 202 arbitrary letter-spacing classes (tracking-[N em]) - 2 inline-style fontSize string literals - 0 leading-[...] sites found (none existed) - 17 new tokens minted, no normalizing: 8 --fs-* (9/10/11/12/13/14/15px + 0.7rem, kept in its own unit) and 9 --ls-* (0.08-0.24em, 9 distinct values) — the micro type-size and letter-spacing clusters TOKEN-AUDIT.md flagged are now materialized as tokens, still un-collapsed pending a human scale decision. - 2 sites allowlisted (both already-documented functional/third-party fontSize forms: CompanyEnvironments.tsx xterm.js config, CompanySkills.tsx computed Math.round() value) — no new allowlist entries needed since neither is a class-string or literal-fontSize site the codemod targets. - Verified: rg gates clean, pnpm build-storybook exit 0, Storybook visual suite 510/510 passed (first attempt), pnpm typecheck exit 0, codemod re-run confirmed idempotent (0 sites on second pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
a9399a4d21
commit
4b3f087d7f
|
|
@ -279,3 +279,40 @@ Codemod: `scripts/codemod-extract-colors.mjs` (table-driven, idempotent — see
|
|||
**Needs human decision (new, from this batch):**
|
||||
- `components/FileViewerSheet.tsx`'s `--paperclip-code-highlight-bg`/`-border` half-migrated var-with-fallback pattern (allowlist item 7 above) — TOKEN-AUDIT.md section 2 already recommended "this becomes the actual token"; this batch deliberately did NOT act on that recommendation because defining the var changes what `var(--x, fallback)` resolves to structurally (from "always the literal fallback" to "the var if defined, else the fallback") even though the *value* would be identical today — a human should confirm this is the intended direction before Batch 2+ touches it, alongside the sibling `--paperclip-code-bg`/`--paperclip-code-gutter-fg` vars in the same file that use `theme(colors.muted...)` fallbacks (out of scope for colors, relevant to a future spacing/type batch).
|
||||
- The `#2563EB` reuse (`IssueChatThread.tsx`'s "Liveness blue" chat bubble → `--status-task-in_progress`) is a **semantic coincidence**, not a designed relationship — the original code comment explicitly called it "Liveness blue" independently of the task-status system. Batch 1 reused the token per the exact-match rule, but a human should confirm a chat-bubble liveness color is supposed to be permanently coupled to the task `in_progress` status hue going forward (if a future redesign changes one, does the other move too?).
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 extraction log — Batch 2 (type)
|
||||
|
||||
Codemod: `scripts/codemod-extract-type.mjs`. Unlike Batch 1's hand-audited site table (needed to avoid hex-like false positives such as issue references), this batch's patterns — `text-[Npx]`/`text-[N.Nrem]` Tailwind font-size, `tracking-[N em]` letter-spacing, `leading-[...]` line-height, and `fontSize: "Npx"`/`fontSize: "N.Nrem"` inline-style string literals — are unambiguous, so the codemod does a blanket regex sweep scoped to `ui/src/components/**` and `ui/src/pages/**` (including `*.test.tsx` companions; a full scan found **zero** test files containing any of these patterns, so no test file needed a lockstep update this batch). Verified idempotent (second run: 0 sites, 0 files changed).
|
||||
|
||||
**Sites rewritten: 932**, across 143 files.
|
||||
- Font-size Tailwind class utilities (`text-[Npx]`): 728 sites (matches TOKEN-AUDIT.md section 3.1's count almost exactly — 730 vs. 728, negligible drift from audit-vs-extraction timing). No rem-unit or line-height-suffixed (`text-[N]/[N]`) forms were found in class strings; none existed to convert.
|
||||
- Letter-spacing (`tracking-[N em]`): 202 sites, matching TOKEN-AUDIT.md section 3.2 exactly (9 distinct values).
|
||||
- `leading-[...]` line-height brackets: 0 sites found (confirmed via full sweep; TOKEN-AUDIT.md did not call this out as a populated cluster either).
|
||||
- Inline-style `fontSize` string literals: 2 sites — `components/AsciiArtAnimation.tsx:344` (`fontSize: "11px"`, reused the same `--fs-11` token minted by the class-based sites — no duplicate) and `components/MarkdownBody.tsx:197` (`fontSize: "0.7rem"`, new rem-unit token).
|
||||
|
||||
**Tokens minted: 17 new** (0 reused from Batch 1 — font-size/letter-spacing/line-height had no prior tokens to match against).
|
||||
- 8 `--fs-*` (font-size): `--fs-9`, `--fs-10`, `--fs-11`, `--fs-12`, `--fs-13`, `--fs-14`, `--fs-15` (px, one per distinct value found) + `--fs-0_7rem` (0.7rem, `MarkdownBody.tsx`'s inline style — kept in rem per DESIGN.md "no normalizing/unit-converting" rule, NOT collapsed into the 11px-ish px cluster even though 0.7rem ≈ 11.2px).
|
||||
- 9 `--ls-*` (letter-spacing): `--ls-0_08`, `--ls-0_1`, `--ls-0_12`, `--ls-0_14`, `--ls-0_16`, `--ls-0_18`, `--ls-0_2`, `--ls-0_22`, `--ls-0_24` — one per distinct em value, matching TOKEN-AUDIT.md 3.2's 9-value cluster exactly.
|
||||
- 0 `--lh-*` (line-height) — no sites required one; the token-registration code path exists in the codemod (and was exercised in the Step 0 syntax spike) for forward-compatibility but minted nothing this batch.
|
||||
- All new tokens live in a second non-`@theme` `:root { ... }` block appended to `ui/src/index.css` immediately after Batch 1's color block, headed `/* ── Extracted verbatim TYPE tokens (Phase 2 Batch 2, design/token-extraction) ── */`, per DESIGN.md (runtime-tunable). **No normalizing performed** — 9/10/11/12/13/14/15px and the 9 distinct tracking values all remain distinct tokens; the human scale-collapse decision (TOKEN-AUDIT.md "Needs human decision" #2/#3, PRIOR-ART's draft `.type-*` scale) is explicitly deferred, per mandate.
|
||||
|
||||
**Tailwind v4 rewrite forms used** (confirmed via mandatory Step-0 syntax spike — scratch story + `pnpm build-storybook` + grep of emitted CSS, then deleted before the real codemod ran):
|
||||
- `text-[11px]` → `text-(length:--fs-11)` — emits `font-size:var(--fs-11)`. The `length:` hint is REQUIRED; a bare `text-(--fs-11)` would be interpreted as a color utility.
|
||||
- `tracking-[0.18em]` → `tracking-(--ls-0_18)` — emits `--tw-tracking:var(--ls-0_18);letter-spacing:var(--ls-0_18)`. Unambiguous, no hint needed.
|
||||
- `leading-[...]` (numeric/unit forms only) → `leading-(--lh-*)` — verified to emit `--tw-leading:var(--lh-*);line-height:var(--lh-*)` in the spike; not exercised on a real site since 0 sites existed.
|
||||
- All variant/modifier prefixes preserved verbatim by construction (the regex only rewrites the bracket portion): confirmed sites include `sm:text-[11px]` (`components/BlockedReasonChip.tsx`), a compound arbitrary-variant `group-data-[size=xs]/avatar:text-[10px]` (`components/ui/avatar.tsx`), and an `!important`-marked bracket-selector `[&>span:last-child]:!text-[11px]` (`components/ActiveAgentsPanel.tsx`) — all rewrote correctly to `sm:text-(length:--fs-11)`, `group-data-[size=xs]/avatar:text-(length:--fs-10)`, and `[&>span:last-child]:!text-(length:--fs-11)` respectively.
|
||||
|
||||
**Sites allowlisted (2 sites, both already covered by Batch 1's allowlist doc-comment structure for their files, no new inline comments needed since neither is a bracket-literal or class-string site):**
|
||||
1. `pages/CompanyEnvironments.tsx:422` — `fontSize: 12` inside the xterm.js terminal theme option object (same object Batch 1 allowlisted for its color literals). Numeric, functional third-party config — not a rendered CSS value, not a string literal the codemod's regex targets.
|
||||
2. `pages/CompanySkills.tsx:580` — `fontSize: Math.round(size * 0.42)` — computed at runtime from a prop; not a static literal, nothing to extract.
|
||||
|
||||
**Verify results:**
|
||||
- `rg` gates clean in `ui/src/components/**` / `ui/src/pages/**`: zero `text-[Npx]`/`text-[N.Nrem]` arbitrary font-size, zero `tracking-[N em]`, zero numeric `leading-[...]`, zero raw `fontSize: "..."` string literals remain (the only two `fontSize:` string-literal grep hits left are the already-converted `fontSize: "var(--fs-11)"` / `fontSize: "var(--fs-0_7rem)"` sites).
|
||||
- `pnpm build-storybook` exit 0.
|
||||
- Storybook visual snapshot suite: **510/510 passed, 0 failed**, first attempt, no retries needed (`npx playwright test --config tests/storybook-visual/playwright.config.ts --reporter=line`).
|
||||
- `pnpm typecheck` exit 0.
|
||||
- Codemod re-run confirmed idempotent: second invocation reports 0 sites rewritten, 0 files changed, token block already present.
|
||||
|
||||
**Needs human decision:** none new from this batch beyond the already-logged #2 (micro type-size cluster) and #3 (letter-spacing cluster) in section 8 above — this batch's 17 minted tokens are exactly the verbatim inventory those two items describe, now materialized as CSS custom properties ready for a human to collapse into a real scale.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,239 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* codemod-extract-type.mjs
|
||||
*
|
||||
* Phase 2 (extraction), Batch 2/4 of the design-token audit
|
||||
* (branch design/token-extraction). Replaces hardcoded TYPE values —
|
||||
* arbitrary Tailwind font-size (`text-[11px]`), letter-spacing
|
||||
* (`tracking-[0.18em]`), line-height (`leading-[...]`), and raw inline
|
||||
* `fontSize` style literals — in `ui/src/components/**` and
|
||||
* `ui/src/pages/**` (including their *.test.tsx companions) with
|
||||
* references to CSS custom-property tokens defined in `ui/src/index.css`.
|
||||
*
|
||||
* Unlike Batch 1's color codemod (which used a hand-audited site table to
|
||||
* avoid false-positiving on non-color hex-like strings such as issue
|
||||
* references), this batch's patterns are unambiguous: `text-[Npx]`,
|
||||
* `text-[N.Nrem]`, `tracking-[N em]`, and `leading-[...]` inside Tailwind
|
||||
* class strings, and `fontSize: "Npx"` / `fontSize: "N.Nrem"` inline-style
|
||||
* string literals, cannot mean anything other than a type-size/spacing
|
||||
* value. A blanket regex sweep is therefore safe and is used here, scoped
|
||||
* to `ui/src/components/**` and `ui/src/pages/**` only. Numeric or
|
||||
* computed `fontSize` forms (e.g. `fontSize: 12`, `fontSize: Math.round(...)`)
|
||||
* are functional (third-party config objects / runtime-computed values)
|
||||
* and are left untouched — see ALLOWLIST_NOTES below.
|
||||
*
|
||||
* Token naming (verbatim value, no normalizing):
|
||||
* --fs-<N> font-size, px values, e.g. --fs-11: 11px;
|
||||
* --fs-0_<N>rem font-size, rem values, e.g. --fs-0_7rem: 0.7rem;
|
||||
* --ls-0_<N> letter-spacing, em values, e.g. --ls-0_18: 0.18em;
|
||||
* --lh-<N> line-height (px or unitless — none found this batch)
|
||||
*
|
||||
* Tailwind v4 paren-shorthand rewrite forms used:
|
||||
* text-[Npx] -> text-(length:--fs-N) (length hint REQUIRED —
|
||||
* bare text-(--x) means color)
|
||||
* tracking-[N em] -> tracking-(--ls-0_N) (unambiguous, no hint)
|
||||
* leading-[...] -> leading-(--lh-N) (unambiguous, no hint)
|
||||
* All variant/modifier prefixes (`sm:`, `dark:`, `group-hover:`,
|
||||
* `[&>x]:`, trailing `!important` marker, etc.) are preserved verbatim —
|
||||
* the regex only rewrites the bracket portion itself.
|
||||
*
|
||||
* Idempotent: the FIND regex only matches the ORIGINAL bracket-literal
|
||||
* form (`text-[11px]` etc.); once rewritten to `text-(length:--fs-11)` the
|
||||
* pattern no longer matches, so re-running is a no-op. The inline-style
|
||||
* FIND is likewise the literal `fontSize: "11px"` string form.
|
||||
*
|
||||
* Usage: node scripts/codemod-extract-type.mjs [--check]
|
||||
* --check Report what WOULD change without writing files (dry run).
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync, readdirSync, statSync } from "node:fs";
|
||||
import { resolve, dirname, join, relative } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const REPO_ROOT = resolve(__dirname, "..");
|
||||
const UI_SRC = resolve(REPO_ROOT, "ui/src");
|
||||
const SCAN_DIRS = ["components", "pages"];
|
||||
|
||||
const DRY_RUN = process.argv.includes("--check");
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────
|
||||
function walk(dir, out) {
|
||||
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
||||
const p = join(dir, entry.name);
|
||||
if (entry.isDirectory()) walk(p, out);
|
||||
else if (/\.(tsx?|jsx?)$/.test(entry.name)) out.push(p);
|
||||
}
|
||||
}
|
||||
|
||||
function tokenSuffixForPx(value) {
|
||||
// "11" -> "11", "0.65" -> "0_65"
|
||||
return value.replace(".", "_");
|
||||
}
|
||||
|
||||
function tokenSuffixForEm(value) {
|
||||
// "0.18" -> "0_18"
|
||||
return value.replace(".", "_");
|
||||
}
|
||||
|
||||
// ── Token registries (populated as sites are discovered) ───────────────
|
||||
// Map of token name (without --) -> { value, comment, kind }
|
||||
const fsTokens = new Map(); // font-size
|
||||
const lsTokens = new Map(); // letter-spacing
|
||||
const lhTokens = new Map(); // line-height
|
||||
|
||||
function registerFsToken(rawValue, unit, sourceNote) {
|
||||
const name = unit === "px" ? `fs-${tokenSuffixForPx(rawValue)}` : `fs-${tokenSuffixForPx(rawValue)}rem`;
|
||||
if (!fsTokens.has(name)) {
|
||||
fsTokens.set(name, { value: `${rawValue}${unit}`, comment: sourceNote });
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function registerLsToken(rawValue, sourceNote) {
|
||||
const name = `ls-${tokenSuffixForEm(rawValue)}`;
|
||||
if (!lsTokens.has(name)) {
|
||||
lsTokens.set(name, { value: `${rawValue}em`, comment: sourceNote });
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
function registerLhToken(rawValue, sourceNote) {
|
||||
// rawValue includes unit already stripped by caller; store as given
|
||||
const safeName = rawValue.replace(/[^a-zA-Z0-9]/g, "_");
|
||||
const name = `lh-${safeName}`;
|
||||
if (!lhTokens.has(name)) {
|
||||
lhTokens.set(name, { value: rawValue, comment: sourceNote });
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
// ── Regexes ──────────────────────────────────────────────────────────
|
||||
// text-[11px], text-[0.65rem], with optional /[Npx] line-height suffix
|
||||
// (none found in this codebase, but handled for completeness/future-proofing).
|
||||
const FS_RE = /text-\[([0-9.]+)(px|rem)\](?:\/\[([0-9.]+)(px|rem)\])?/g;
|
||||
const LS_RE = /tracking-\[([0-9.]+)em\]/g;
|
||||
const LEADING_RE = /leading-\[([^\]]+)\]/g;
|
||||
const FONTSIZE_STYLE_RE = /fontSize:\s*"([0-9.]+)(px|rem)"/g;
|
||||
|
||||
function rewriteFile(filePath, relPath) {
|
||||
const original = readFileSync(filePath, "utf8");
|
||||
let content = original;
|
||||
let siteCount = 0;
|
||||
|
||||
// -- font-size Tailwind class utilities --
|
||||
content = content.replace(FS_RE, (match, num, unit, lhNum, lhUnit) => {
|
||||
const fsName = registerFsToken(num, unit, `Extracted from ${relPath} (text-[${num}${unit}]).`);
|
||||
let replacement = `text-(length:--${fsName})`;
|
||||
if (lhNum) {
|
||||
const lhName = registerLhToken(`${lhNum}${lhUnit}`, `Extracted from ${relPath} (text-[...]/[${lhNum}${lhUnit}] line-height suffix).`);
|
||||
replacement += `/(--${lhName})`;
|
||||
}
|
||||
siteCount++;
|
||||
return replacement;
|
||||
});
|
||||
|
||||
// -- letter-spacing Tailwind class utilities --
|
||||
content = content.replace(LS_RE, (match, num) => {
|
||||
const lsName = registerLsToken(num, `Extracted from ${relPath} (tracking-[${num}em]).`);
|
||||
siteCount++;
|
||||
return `tracking-(--${lsName})`;
|
||||
});
|
||||
|
||||
// -- line-height Tailwind class utilities (standalone leading-[...]) --
|
||||
content = content.replace(LEADING_RE, (match, raw) => {
|
||||
// Only rewrite numeric/unit literals (px, rem, unitless number). Skip
|
||||
// keyword forms like leading-[inherit] or var()-based (already tokenized).
|
||||
if (!/^[0-9.]+(px|rem)?$/.test(raw)) return match;
|
||||
const lhName = registerLhToken(raw, `Extracted from ${relPath} (leading-[${raw}]).`);
|
||||
siteCount++;
|
||||
return `leading-(--${lhName})`;
|
||||
});
|
||||
|
||||
// -- inline style fontSize string literals --
|
||||
content = content.replace(FONTSIZE_STYLE_RE, (match, num, unit) => {
|
||||
const fsName = registerFsToken(num, unit, `Extracted from ${relPath} (inline style fontSize: "${num}${unit}").`);
|
||||
siteCount++;
|
||||
return `fontSize: "var(--${fsName})"`;
|
||||
});
|
||||
|
||||
if (content !== original && !DRY_RUN) {
|
||||
writeFileSync(filePath, content, "utf8");
|
||||
}
|
||||
return { changed: content !== original, siteCount };
|
||||
}
|
||||
|
||||
function main() {
|
||||
const files = [];
|
||||
for (const dir of SCAN_DIRS) walk(resolve(UI_SRC, dir), files);
|
||||
|
||||
let totalSites = 0;
|
||||
let filesChanged = 0;
|
||||
const changedFiles = [];
|
||||
|
||||
for (const filePath of files) {
|
||||
const relPath = "ui/src/" + relative(UI_SRC, filePath);
|
||||
const { changed, siteCount } = rewriteFile(filePath, relPath);
|
||||
if (changed) {
|
||||
filesChanged++;
|
||||
changedFiles.push(relPath);
|
||||
}
|
||||
totalSites += siteCount;
|
||||
}
|
||||
|
||||
// ── index.css token block ──────────────────────────────────────────
|
||||
const cssPath = resolve(UI_SRC, "index.css");
|
||||
const cssOriginal = readFileSync(cssPath, "utf8");
|
||||
const marker = "/* ── Extracted verbatim TYPE tokens (Phase 2 Batch 2, design/token-extraction) ── */";
|
||||
let cssNext = cssOriginal;
|
||||
let cssChanged = false;
|
||||
|
||||
if (!cssOriginal.includes(marker) && (fsTokens.size || lsTokens.size || lhTokens.size)) {
|
||||
const lines = [];
|
||||
lines.push(marker);
|
||||
lines.push("/* Batch 2/4: font-size + letter-spacing + line-height literals, verbatim");
|
||||
lines.push(" (no normalizing — 9/10/11/12/13/14/15px and 0.08-0.24em all stay distinct;");
|
||||
lines.push(" the human scale-collapse decision comes later per DESIGN.md/TOKEN-AUDIT.md).");
|
||||
lines.push("");
|
||||
lines.push(" Allowlist (sites intentionally left as hardcoded / functional literals,");
|
||||
lines.push(" NOT converted to tokens — each also carries an inline");
|
||||
lines.push(" `token-extraction: allowlisted` comment at the site):");
|
||||
lines.push(" - pages/CompanyEnvironments.tsx (fontSize: 12) — xterm.js terminal theme");
|
||||
lines.push(" config; functional third-party numeric option, not a rendered CSS value.");
|
||||
lines.push(" Same allowlisted object as Batch 1's color entry for this file.");
|
||||
lines.push(" - pages/CompanySkills.tsx (fontSize: Math.round(size * 0.42)) — computed at");
|
||||
lines.push(" runtime from a prop; not a static literal, nothing to extract.");
|
||||
lines.push("*/");
|
||||
lines.push(":root {");
|
||||
for (const [name, { value, comment }] of fsTokens) {
|
||||
lines.push(` --${name}: ${value}; /* ${comment} */`);
|
||||
}
|
||||
for (const [name, { value, comment }] of lsTokens) {
|
||||
lines.push(` --${name}: ${value}; /* ${comment} */`);
|
||||
}
|
||||
for (const [name, { value, comment }] of lhTokens) {
|
||||
lines.push(` --${name}: ${value}; /* ${comment} */`);
|
||||
}
|
||||
lines.push("}");
|
||||
const block = "\n" + lines.join("\n") + "\n";
|
||||
cssNext = cssOriginal + block;
|
||||
cssChanged = true;
|
||||
}
|
||||
|
||||
if (cssChanged && !DRY_RUN) writeFileSync(cssPath, cssNext, "utf8");
|
||||
|
||||
// ── Summary ─────────────────────────────────────────────────────────
|
||||
console.log(`\n${DRY_RUN ? "[DRY RUN] " : ""}codemod-extract-type summary`);
|
||||
console.log(` Sites rewritten: ${totalSites}`);
|
||||
console.log(` Files changed: ${filesChanged}`);
|
||||
console.log(` New --fs-* tokens: ${fsTokens.size}`);
|
||||
console.log(` New --ls-* tokens: ${lsTokens.size}`);
|
||||
console.log(` New --lh-* tokens: ${lhTokens.size}`);
|
||||
console.log(` index.css token block: ${cssChanged ? "added" : "already present or nothing to add (idempotent no-op)"}`);
|
||||
if (changedFiles.length) {
|
||||
console.log(`\n Changed files:`);
|
||||
for (const f of changedFiles) console.log(` - ${f}`);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
@ -30,7 +30,7 @@ export function AccountingModelCard() {
|
|||
<Card className="relative overflow-hidden border-border/70">
|
||||
<div className="absolute inset-0 bg-(image:--gradient-extract-3)" />
|
||||
<CardHeader className="relative px-5 pt-5 pb-2">
|
||||
<CardTitle className="text-sm font-semibold uppercase tracking-[0.22em] text-muted-foreground">
|
||||
<CardTitle className="text-sm font-semibold uppercase tracking-(--ls-0_22) text-muted-foreground">
|
||||
Accounting model
|
||||
</CardTitle>
|
||||
<CardDescription className="max-w-2xl text-sm leading-6">
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function RunCardRecoveryChip({ action }: { action: IssueRecoveryAction }) {
|
|||
aria-label={tone.label}
|
||||
title={`${tone.label} — open the source task to act.`}
|
||||
className={cn(
|
||||
"inline-flex shrink-0 items-center gap-0.5 rounded-full border px-1.5 py-0.5 text-[10px] font-medium",
|
||||
"inline-flex shrink-0 items-center gap-0.5 rounded-full border px-1.5 py-0.5 text-(length:--fs-10) font-medium",
|
||||
tone.className,
|
||||
)}
|
||||
>
|
||||
|
|
@ -188,16 +188,16 @@ const AgentRunCard = memo(function AgentRunCard({
|
|||
) : (
|
||||
<span className="inline-flex h-2.5 w-2.5 rounded-full bg-muted-foreground/35" />
|
||||
)}
|
||||
<Identity name={run.agentName} size="sm" className="[&>span:last-child]:!text-[11px]" />
|
||||
<Identity name={run.agentName} size="sm" className="[&>span:last-child]:!text-(length:--fs-11)" />
|
||||
</div>
|
||||
<div className="mt-2 flex items-center gap-2 text-[11px] text-muted-foreground">
|
||||
<div className="mt-2 flex items-center gap-2 text-(length:--fs-11) text-muted-foreground">
|
||||
<span>{isActive ? "Live now" : run.finishedAt ? `Finished ${relativeTime(run.finishedAt)}` : `Started ${relativeTime(run.createdAt)}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
to={`/agents/${run.agentId}/runs/${run.id}`}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2 py-1 text-[10px] text-muted-foreground transition-colors hover:text-foreground"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2 py-1 text-(length:--fs-10) text-muted-foreground transition-colors hover:text-foreground"
|
||||
>
|
||||
<ExternalLink className="h-2.5 w-2.5" />
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ function DateLabels({ days }: { days: string[] }) {
|
|||
{days.map((day, i) => (
|
||||
<div key={day} className="flex-1 text-center">
|
||||
{(i === 0 || i === 6 || i === 13) ? (
|
||||
<span className="text-[9px] text-muted-foreground tabular-nums">{formatDayLabel(day)}</span>
|
||||
<span className="text-(length:--fs-9) text-muted-foreground tabular-nums">{formatDayLabel(day)}</span>
|
||||
) : null}
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -35,7 +35,7 @@ function ChartLegend({ items }: { items: { color: string; label: string }[] }) {
|
|||
return (
|
||||
<div className="flex flex-wrap gap-x-2.5 gap-y-0.5 mt-2">
|
||||
{items.map(item => (
|
||||
<span key={item.label} className="flex items-center gap-1 text-[9px] text-muted-foreground">
|
||||
<span key={item.label} className="flex items-center gap-1 text-(length:--fs-9) text-muted-foreground">
|
||||
<span className="h-1.5 w-1.5 rounded-full shrink-0" style={{ backgroundColor: item.color }} />
|
||||
{item.label}
|
||||
</span>
|
||||
|
|
@ -49,7 +49,7 @@ export function ChartCard({ title, subtitle, children }: { title: string; subtit
|
|||
<div className="border border-border rounded-lg p-4 space-y-3">
|
||||
<div>
|
||||
<h3 className="text-xs font-medium text-muted-foreground">{title}</h3>
|
||||
{subtitle && <span className="text-[10px] text-muted-foreground/60">{subtitle}</span>}
|
||||
{subtitle && <span className="text-(length:--fs-10) text-muted-foreground/60">{subtitle}</span>}
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ export function ActivityFeed({ className }: ActivityFeedProps) {
|
|||
separator = (
|
||||
<div className="flex items-center gap-2 px-4 py-1.5" key={`sep-${index}`}>
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
<span className="text-[10px] font-medium text-muted-foreground uppercase tracking-wider">
|
||||
<span className="text-(length:--fs-10) font-medium text-muted-foreground uppercase tracking-wider">
|
||||
Earlier
|
||||
</span>
|
||||
<div className="h-px flex-1 bg-border" />
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ export function AgentBubbleActionRow({
|
|||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href={anchorHref}
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground hover:underline"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground hover:underline"
|
||||
>
|
||||
{dateLabel}
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -1247,7 +1247,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
|
|||
</Field>
|
||||
|
||||
{supportsModelProfiles && (
|
||||
<div className="text-[11px] uppercase tracking-wide text-muted-foreground">Primary model</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">Primary model</div>
|
||||
)}
|
||||
<ModelDropdown
|
||||
models={models}
|
||||
|
|
@ -1578,13 +1578,13 @@ export function AdapterEnvironmentResult({ result }: { result: AdapterEnvironmen
|
|||
<div className={`rounded-md border px-3 py-2 text-xs ${statusClass}`}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="font-medium">{statusLabel}</span>
|
||||
<span className="text-[11px] opacity-80">
|
||||
<span className="text-(length:--fs-11) opacity-80">
|
||||
{new Date(result.testedAt).toLocaleTimeString()}
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-2 space-y-1.5">
|
||||
{result.checks.map((check, idx) => (
|
||||
<div key={`${check.code}-${idx}`} className="text-[11px] leading-relaxed break-words">
|
||||
<div key={`${check.code}-${idx}`} className="text-(length:--fs-11) leading-relaxed break-words">
|
||||
<span className="font-medium uppercase tracking-wide opacity-80">
|
||||
{check.level}
|
||||
</span>
|
||||
|
|
@ -1657,7 +1657,7 @@ function AdapterTypeDropdown({
|
|||
{item.experimental && <ExperimentalBadge />}
|
||||
</span>
|
||||
{item.comingSoon && (
|
||||
<span className="text-[10px] text-muted-foreground">Coming soon</span>
|
||||
<span className="text-(length:--fs-10) text-muted-foreground">Coming soon</span>
|
||||
)}
|
||||
</button>
|
||||
))}
|
||||
|
|
@ -1668,7 +1668,7 @@ function AdapterTypeDropdown({
|
|||
|
||||
function ExperimentalBadge() {
|
||||
return (
|
||||
<span className="shrink-0 rounded border border-amber-500/30 bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-medium leading-none text-amber-700 dark:text-amber-200">
|
||||
<span className="shrink-0 rounded border border-amber-500/30 bg-amber-500/10 px-1.5 py-0.5 text-(length:--fs-10) font-medium leading-none text-amber-700 dark:text-amber-200">
|
||||
Experimental
|
||||
</span>
|
||||
);
|
||||
|
|
@ -1871,7 +1871,7 @@ function ModelDropdown({
|
|||
<span className="block w-full text-left truncate font-mono text-xs" title={value}>
|
||||
{models.find((m) => m.id === value)?.label ?? value}
|
||||
</span>
|
||||
<span className="shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-green-500/15 text-green-400 border border-green-500/20">
|
||||
<span className="shrink-0 ml-auto text-(length:--fs-9) font-medium px-1.5 py-0.5 rounded-full bg-green-500/15 text-green-400 border border-green-500/20">
|
||||
current
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1890,7 +1890,7 @@ function ModelDropdown({
|
|||
<span className="block w-full text-left truncate font-mono text-xs" title={detectedModel}>
|
||||
{models.find((m) => m.id === detectedModel)?.label ?? detectedModel}
|
||||
</span>
|
||||
<span className="shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-blue-500/15 text-blue-400 border border-blue-500/20">
|
||||
<span className="shrink-0 ml-auto text-(length:--fs-9) font-medium px-1.5 py-0.5 rounded-full bg-blue-500/15 text-blue-400 border border-blue-500/20">
|
||||
detected
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1914,7 +1914,7 @@ function ModelDropdown({
|
|||
<span className="block w-full text-left truncate font-mono text-xs" title={candidate}>
|
||||
{entry?.label ?? candidate}
|
||||
</span>
|
||||
<span className="shrink-0 ml-auto text-[9px] font-medium px-1.5 py-0.5 rounded-full bg-sky-500/15 text-sky-400 border border-sky-500/20">
|
||||
<span className="shrink-0 ml-auto text-(length:--fs-9) font-medium px-1.5 py-0.5 rounded-full bg-sky-500/15 text-sky-400 border border-sky-500/20">
|
||||
config
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1953,7 +1953,7 @@ function ModelDropdown({
|
|||
{groupedModels.map((group) => (
|
||||
<div key={group.provider} className="mb-1 last:mb-0">
|
||||
{groupByProvider && (
|
||||
<div className="px-2 py-1 text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<div className="px-2 py-1 text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
{group.provider} ({group.entries.length})
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -2021,7 +2021,7 @@ function CheapModelSection({
|
|||
<div className="rounded-md border border-border/70 bg-muted/20 p-3 space-y-3">
|
||||
<div className="flex items-center justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="text-[11px] uppercase tracking-wide text-muted-foreground">Cheap model</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">Cheap model</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Used when a run requests the cheap profile (e.g. routine summaries). The primary model stays unchanged.
|
||||
</p>
|
||||
|
|
@ -2046,12 +2046,12 @@ function CheapModelSection({
|
|||
/>
|
||||
) : null}
|
||||
{enabled && !model && adapterDefaultModel ? (
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
No explicit cheap model selected — runtime falls back to <code>{adapterDefaultModel}</code>.
|
||||
</p>
|
||||
) : null}
|
||||
{enabled && !model && !adapterDefaultModel ? (
|
||||
<p className="text-[11px] text-amber-500">
|
||||
<p className="text-(length:--fs-11) text-amber-500">
|
||||
No cheap model selected and the adapter has no default. Cheap-lane runs will continue on the primary model with a fallback note.
|
||||
</p>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ export function ApprovalCard({
|
|||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="border-border/70 bg-background/70 px-2 py-0.5 text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground"
|
||||
className="border-border/70 bg-background/70 px-2 py-0.5 text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground"
|
||||
>
|
||||
{kindLabel}
|
||||
</Badge>
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ function SkillList({ values }: { values: unknown }) {
|
|||
{items.map((item) => (
|
||||
<span
|
||||
key={item}
|
||||
className="rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-muted-foreground"
|
||||
className="rounded bg-muted px-1.5 py-0.5 font-mono text-(length:--fs-11) text-muted-foreground"
|
||||
>
|
||||
{item}
|
||||
</span>
|
||||
|
|
@ -178,19 +178,19 @@ function BoardApprovalPayloadContent({ payload }: { payload: Record<string, unkn
|
|||
<div className="mt-4 space-y-3.5 text-sm">
|
||||
{title && (
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">Title</p>
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">Title</p>
|
||||
<p className="font-medium leading-6 text-foreground">{title}</p>
|
||||
</div>
|
||||
)}
|
||||
{summary && (
|
||||
<div className="space-y-1">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">Summary</p>
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">Summary</p>
|
||||
<p className="leading-6 text-foreground/90">{summary}</p>
|
||||
</div>
|
||||
)}
|
||||
{recommendedAction && (
|
||||
<div className="rounded-lg border border-amber-500/20 bg-amber-500/10 px-3.5 py-3">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-amber-700 dark:text-amber-300">
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-amber-700 dark:text-amber-300">
|
||||
Recommended action
|
||||
</p>
|
||||
<p className="mt-1 leading-6 text-foreground">{recommendedAction}</p>
|
||||
|
|
@ -198,13 +198,13 @@ function BoardApprovalPayloadContent({ payload }: { payload: Record<string, unkn
|
|||
)}
|
||||
{nextActionOnApproval && (
|
||||
<div className="rounded-lg border border-border/60 bg-background/60 px-3.5 py-3">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">On approval</p>
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">On approval</p>
|
||||
<p className="mt-1 leading-6 text-foreground">{nextActionOnApproval}</p>
|
||||
</div>
|
||||
)}
|
||||
{risks.length > 0 && (
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">Risks</p>
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">Risks</p>
|
||||
<ul className="space-y-1 text-sm text-muted-foreground">
|
||||
{risks.map((risk) => (
|
||||
<li key={risk} className="flex items-start gap-2">
|
||||
|
|
@ -217,7 +217,7 @@ function BoardApprovalPayloadContent({ payload }: { payload: Record<string, unkn
|
|||
)}
|
||||
{proposedComment && (
|
||||
<div className="space-y-1.5">
|
||||
<p className="text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">
|
||||
Proposed comment
|
||||
</p>
|
||||
<pre className="max-h-48 overflow-auto rounded-lg border border-border/60 bg-muted/50 px-3.5 py-3 font-mono text-xs leading-5 text-muted-foreground whitespace-pre-wrap">
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ export function ArtifactsPanel({ taskId, isAgentWorking, openDocKey, openDocTitl
|
|||
<button
|
||||
key={f.value}
|
||||
className={cn(
|
||||
"rounded-full px-2.5 py-0.5 text-[11px] font-medium transition-colors",
|
||||
"rounded-full px-2.5 py-0.5 text-(length:--fs-11) font-medium transition-colors",
|
||||
filter === f.value
|
||||
? "bg-foreground text-background"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-accent/50",
|
||||
|
|
@ -208,22 +208,22 @@ export function ArtifactsPanel({ taskId, isAgentWorking, openDocKey, openDocTitl
|
|||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="text-[10px] text-muted-foreground capitalize">
|
||||
<span className="text-(length:--fs-10) text-muted-foreground capitalize">
|
||||
{wp.type.replace(/_/g, " ")}
|
||||
</span>
|
||||
{showGenerating ? (
|
||||
<span className="inline-flex items-center gap-1 text-[10px] font-medium px-1.5 py-0.5 rounded-full bg-cyan-500/10 text-cyan-600 dark:text-cyan-400">
|
||||
<span className="inline-flex items-center gap-1 text-(length:--fs-10) font-medium px-1.5 py-0.5 rounded-full bg-cyan-500/10 text-cyan-600 dark:text-cyan-400">
|
||||
<Loader2 className="h-2.5 w-2.5 animate-spin" />
|
||||
Generating...
|
||||
</span>
|
||||
) : (
|
||||
<span className={cn("text-[10px] font-medium px-1.5 py-0.5 rounded-full", badge.className)}>
|
||||
<span className={cn("text-(length:--fs-10) font-medium px-1.5 py-0.5 rounded-full", badge.className)}>
|
||||
{badge.label}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{wp.summary && (
|
||||
<p className="text-[11px] text-muted-foreground mt-1 line-clamp-2">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground mt-1 line-clamp-2">
|
||||
{wp.summary}
|
||||
</p>
|
||||
)}
|
||||
|
|
@ -298,7 +298,7 @@ function DocumentViewer({
|
|||
{/* Sticky action footer */}
|
||||
{needsAction && (
|
||||
<div className="border-t border-border px-4 py-3 bg-background shrink-0">
|
||||
<p className="text-[11px] text-muted-foreground mb-2">This document needs your review.</p>
|
||||
<p className="text-(length:--fs-11) text-muted-foreground mb-2">This document needs your review.</p>
|
||||
<div className="flex items-center gap-3">
|
||||
<Button size="lg" className="h-11 px-8 text-base font-semibold flex-1 rounded-lg bg-green-700 hover:bg-green-800 text-white border-0" onClick={onApprove}>
|
||||
Approve
|
||||
|
|
@ -316,7 +316,7 @@ function DocumentViewer({
|
|||
<div className="border-t border-green-500/30 bg-green-500/5 px-4 py-3 shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<CheckCircle2 className="h-4 w-4 text-green-500" />
|
||||
<p className="text-[13px] font-medium text-green-700 dark:text-green-400">
|
||||
<p className="text-(length:--fs-13) font-medium text-green-700 dark:text-green-400">
|
||||
Approved — hire tasks created
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -326,7 +326,7 @@ function DocumentViewer({
|
|||
<div className="border-t border-orange-500/30 bg-orange-500/5 px-4 py-3 shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<XCircle className="h-4 w-4 text-orange-500" />
|
||||
<p className="text-[13px] font-medium text-orange-700 dark:text-orange-400">
|
||||
<p className="text-(length:--fs-13) font-medium text-orange-700 dark:text-orange-400">
|
||||
Changes requested — CEO is revising
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ export function AsciiArtAnimation() {
|
|||
<pre
|
||||
ref={preRef}
|
||||
className="w-full h-full m-0 p-0 overflow-hidden text-muted-foreground/60 select-none leading-none"
|
||||
style={{ fontSize: "11px", fontFamily: "monospace" }}
|
||||
style={{ fontSize: "var(--fs-11)", fontFamily: "monospace" }}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export function BlockedReasonChip({
|
|||
data-severity={severity}
|
||||
aria-label={`Reason: ${label}, severity ${severity}`}
|
||||
className={cn(
|
||||
"inline-flex shrink-0 items-center gap-1 rounded-md border px-2 py-0.5 text-[10px] font-medium leading-tight sm:text-[11px]",
|
||||
"inline-flex shrink-0 items-center gap-1 rounded-md border px-2 py-0.5 text-(length:--fs-10) font-medium leading-tight sm:text-(length:--fs-11)",
|
||||
VARIANT_STYLES[variant],
|
||||
className,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export function BudgetIncidentCard({
|
|||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<div className="text-[11px] uppercase tracking-[0.22em] text-red-200/80">
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_22) text-red-200/80">
|
||||
{incident.scopeType} hard stop
|
||||
</div>
|
||||
<Badge variant={incident.status === "resolved" ? "outline" : "secondary"}>
|
||||
|
|
@ -76,7 +76,7 @@ export function BudgetIncidentCard({
|
|||
</div>
|
||||
|
||||
<div className="rounded-xl border border-border/60 bg-background/60 p-3">
|
||||
<label className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<label className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
New budget (USD)
|
||||
</label>
|
||||
<div className="mt-2 flex flex-col gap-3 sm:flex-row">
|
||||
|
|
|
|||
|
|
@ -56,14 +56,14 @@ export function BudgetPolicyCard({
|
|||
const observedBudgetGrid = isPlain ? (
|
||||
<div className="grid gap-6 sm:grid-cols-2">
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">Observed</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">Observed</div>
|
||||
<div className="mt-2 text-xl font-semibold tabular-nums">{formatCents(summary.observedAmount)}</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
{summary.amount > 0 ? `${summary.utilizationPercent}% of limit` : "No cap configured"}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">Budget</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">Budget</div>
|
||||
<div className="mt-2 text-xl font-semibold tabular-nums">
|
||||
{summary.amount > 0 ? formatCents(summary.amount) : "Disabled"}
|
||||
</div>
|
||||
|
|
@ -75,14 +75,14 @@ export function BudgetPolicyCard({
|
|||
) : (
|
||||
<div className="grid gap-3 sm:grid-cols-2">
|
||||
<div className="rounded-xl border border-border/70 bg-black/[0.18] px-4 py-3">
|
||||
<div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">Observed</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">Observed</div>
|
||||
<div className="mt-2 text-xl font-semibold tabular-nums">{formatCents(summary.observedAmount)}</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
{summary.amount > 0 ? `${summary.utilizationPercent}% of limit` : "No cap configured"}
|
||||
</div>
|
||||
</div>
|
||||
<div className="rounded-xl border border-border/70 bg-black/[0.18] px-4 py-3">
|
||||
<div className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">Budget</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">Budget</div>
|
||||
<div className="mt-2 text-xl font-semibold tabular-nums">
|
||||
{summary.amount > 0 ? formatCents(summary.amount) : "Disabled"}
|
||||
</div>
|
||||
|
|
@ -129,7 +129,7 @@ export function BudgetPolicyCard({
|
|||
const saveSection = onSave ? (
|
||||
<div className={cn("flex flex-col gap-3 sm:flex-row sm:items-end", isPlain ? "" : "rounded-xl border border-border/70 bg-background/50 p-3")}>
|
||||
<div className="min-w-0 flex-1">
|
||||
<label className="text-[11px] uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<label className="text-(length:--fs-11) uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Budget (USD)
|
||||
</label>
|
||||
<Input
|
||||
|
|
@ -156,7 +156,7 @@ export function BudgetPolicyCard({
|
|||
<div className="space-y-6">
|
||||
<div className="flex items-start justify-between gap-6">
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-[0.22em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_22) text-muted-foreground">
|
||||
{summary.scopeType}
|
||||
</div>
|
||||
<div className="mt-2 text-xl font-semibold">{summary.scopeName}</div>
|
||||
|
|
@ -164,7 +164,7 @@ export function BudgetPolicyCard({
|
|||
</div>
|
||||
<div
|
||||
className={cn(
|
||||
"inline-flex items-center gap-2 text-[11px] uppercase tracking-[0.18em]",
|
||||
"inline-flex items-center gap-2 text-(length:--fs-11) uppercase tracking-(--ls-0_18)",
|
||||
summary.status === "hard_stop"
|
||||
? "text-red-300"
|
||||
: summary.status === "warning"
|
||||
|
|
@ -193,13 +193,13 @@ export function BudgetPolicyCard({
|
|||
<CardHeader className={cn("gap-3", compact ? "px-4 pt-4 pb-2" : "px-5 pt-5 pb-3")}>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-[0.22em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_22) text-muted-foreground">
|
||||
{summary.scopeType}
|
||||
</div>
|
||||
<CardTitle className="mt-1 text-base">{summary.scopeName}</CardTitle>
|
||||
<CardDescription className="mt-1">{windowLabel(summary.windowKind)}</CardDescription>
|
||||
</div>
|
||||
<div className={cn("inline-flex items-center gap-2 rounded-full border px-3 py-1 text-[11px] uppercase tracking-[0.18em]", statusTone(summary.status))}>
|
||||
<div className={cn("inline-flex items-center gap-2 rounded-full border px-3 py-1 text-(length:--fs-11) uppercase tracking-(--ls-0_18)", statusTone(summary.status))}>
|
||||
<StatusIcon className="h-3.5 w-3.5" />
|
||||
{summary.paused ? "Paused" : summary.status === "warning" ? "Warning" : summary.status === "hard_stop" ? "Hard stop" : "Healthy"}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ export const ChatComposer = forwardRef<ChatComposerHandle, ChatComposerProps>(fu
|
|||
) : null}
|
||||
|
||||
{hint ? (
|
||||
<div className="mt-2 inline-flex items-center rounded-full border border-border/70 bg-muted/30 px-2 py-0.5 text-[11px] text-muted-foreground">
|
||||
<div className="mt-2 inline-flex items-center rounded-full border border-border/70 bg-muted/30 px-2 py-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
{hint}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ export function ClaudeSubscriptionPanel({
|
|||
<div className="border border-border px-4 py-4">
|
||||
<div className="flex items-start justify-between gap-3 border-b border-border pb-3">
|
||||
<div className="min-w-0">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_2) text-muted-foreground">
|
||||
Anthropic subscription
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-muted-foreground">
|
||||
|
|
@ -70,7 +70,7 @@ export function ClaudeSubscriptionPanel({
|
|||
</div>
|
||||
</div>
|
||||
{source ? (
|
||||
<span className="shrink-0 border border-border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="shrink-0 border border-border px-2.5 py-1 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{quotaSourceDisplayName(source)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ export function CodexSubscriptionPanel({
|
|||
<div className="border border-border px-4 py-4">
|
||||
<div className="flex items-start justify-between gap-3 border-b border-border pb-3">
|
||||
<div className="min-w-0">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.2em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_2) text-muted-foreground">
|
||||
Codex subscription
|
||||
</div>
|
||||
<div className="mt-1 text-sm text-muted-foreground">
|
||||
|
|
@ -73,7 +73,7 @@ export function CodexSubscriptionPanel({
|
|||
</div>
|
||||
</div>
|
||||
{source ? (
|
||||
<span className="shrink-0 border border-border px-2.5 py-1 text-[10px] font-semibold uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="shrink-0 border border-border px-2.5 py-1 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{quotaSourceDisplayName(source)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -87,7 +87,7 @@ export function CodexSubscriptionPanel({
|
|||
|
||||
<div className="mt-4 space-y-5">
|
||||
<div className="space-y-3">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Account windows
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
|
|
@ -99,7 +99,7 @@ export function CodexSubscriptionPanel({
|
|||
|
||||
{modelWindows.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Model windows
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
|
|
|
|||
|
|
@ -209,7 +209,7 @@ export function CommandPalette() {
|
|||
{showSearchAll ? (
|
||||
<span>
|
||||
No quick task matches. Press{" "}
|
||||
<kbd className="rounded border border-border bg-muted px-1 py-0.5 text-[10px]">↵</kbd>{" "}
|
||||
<kbd className="rounded border border-border bg-muted px-1 py-0.5 text-(length:--fs-10)">↵</kbd>{" "}
|
||||
to <span className="font-medium">search all</span> or keep typing to refine.
|
||||
</span>
|
||||
) : (
|
||||
|
|
@ -231,7 +231,7 @@ export function CommandPalette() {
|
|||
</span>
|
||||
<span className="ml-auto inline-flex items-center gap-1 text-xs text-muted-foreground">
|
||||
<span>open full search</span>
|
||||
<kbd className="rounded border border-border bg-background px-1 py-0.5 text-[10px]">↵</kbd>
|
||||
<kbd className="rounded border border-border bg-background px-1 py-0.5 text-(length:--fs-10)">↵</kbd>
|
||||
</span>
|
||||
</CommandItem>
|
||||
</CommandGroup>
|
||||
|
|
|
|||
|
|
@ -374,12 +374,12 @@ function CommentCard({
|
|||
)}
|
||||
<span className="flex items-center gap-1.5">
|
||||
{isQueued ? (
|
||||
<span className="inline-flex items-center rounded-full border border-amber-400/60 bg-amber-100/70 px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-amber-800 dark:border-amber-400/40 dark:bg-amber-500/20 dark:text-amber-200">
|
||||
<span className="inline-flex items-center rounded-full border border-amber-400/60 bg-amber-100/70 px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-amber-800 dark:border-amber-400/40 dark:bg-amber-500/20 dark:text-amber-200">
|
||||
Queued
|
||||
</span>
|
||||
) : null}
|
||||
{followUpRequested ? (
|
||||
<Badge variant="outline" className="text-[10px] uppercase tracking-[0.14em]">
|
||||
<Badge variant="outline" className="text-(length:--fs-10) uppercase tracking-(--ls-0_14)">
|
||||
Follow-up
|
||||
</Badge>
|
||||
) : null}
|
||||
|
|
@ -446,12 +446,12 @@ function CommentCard({
|
|||
comment.runAgentId ? (
|
||||
<Link
|
||||
to={`/agents/${comment.runAgentId}/runs/${comment.runId}`}
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-[10px] font-mono text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-(length:--fs-10) font-mono text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
|
||||
>
|
||||
run {comment.runId.slice(0, 8)}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-[10px] font-mono text-muted-foreground">
|
||||
<span className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-(length:--fs-10) font-mono text-muted-foreground">
|
||||
run {comment.runId.slice(0, 8)}
|
||||
</span>
|
||||
)
|
||||
|
|
@ -463,12 +463,12 @@ function CommentCard({
|
|||
{comment.runAgentId ? (
|
||||
<Link
|
||||
to={`/agents/${comment.runAgentId}/runs/${comment.runId}`}
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-[10px] font-mono text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-(length:--fs-10) font-mono text-muted-foreground hover:text-foreground hover:bg-accent/50 transition-colors"
|
||||
>
|
||||
run {comment.runId.slice(0, 8)}
|
||||
</Link>
|
||||
) : (
|
||||
<span className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-[10px] font-mono text-muted-foreground">
|
||||
<span className="inline-flex items-center rounded-md border border-border bg-accent/30 px-2 py-1 text-(length:--fs-10) font-mono text-muted-foreground">
|
||||
run {comment.runId.slice(0, 8)}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -516,7 +516,7 @@ function TimelineEventCard({
|
|||
|
||||
{event.statusChange ? (
|
||||
<div className="flex flex-wrap items-center gap-2 text-sm">
|
||||
<span className="w-14 text-[10px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<span className="w-14 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
Status
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
|
|
@ -531,7 +531,7 @@ function TimelineEventCard({
|
|||
|
||||
{event.assigneeChange ? (
|
||||
<div className="flex flex-wrap items-center gap-2 text-sm">
|
||||
<span className="w-14 text-[10px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<span className="w-14 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
Assignee
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
|
|
@ -546,7 +546,7 @@ function TimelineEventCard({
|
|||
|
||||
{event.workspaceChange ? (
|
||||
<div className="flex flex-wrap items-center gap-2 text-sm">
|
||||
<span className="w-14 text-[10px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<span className="w-14 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
Workspace
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
|
|
@ -672,7 +672,7 @@ const TimelineList = memo(function TimelineList({
|
|||
</div>
|
||||
</div>
|
||||
{run.environment || run.environmentLease ? (
|
||||
<div className="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-[11px] text-muted-foreground">
|
||||
<div className="mt-2 flex flex-wrap gap-x-3 gap-y-1 text-(length:--fs-11) text-muted-foreground">
|
||||
{run.environment ? (
|
||||
<span>
|
||||
Environment <span className="text-foreground">{run.environment.name}</span>
|
||||
|
|
@ -989,7 +989,7 @@ export function CommentThread({
|
|||
{queuedComments.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h4 className="text-xs font-semibold uppercase tracking-[0.14em] text-amber-700 dark:text-amber-300">
|
||||
<h4 className="text-xs font-semibold uppercase tracking-(--ls-0_14) text-amber-700 dark:text-amber-300">
|
||||
Queued Comments ({queuedComments.length})
|
||||
</h4>
|
||||
{onInterruptQueued && queuedComments[0]?.queueTargetRunId ? (
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ export function CompanySettingsSidebar() {
|
|||
</div>
|
||||
|
||||
<nav className="flex-1 min-h-0 overflow-y-auto scrollbar-auto-hide px-3 py-2">
|
||||
<div className="px-3 pb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
<div className="px-3 pb-1 text-(length:--fs-11) font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
Company settings
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
|
|
@ -134,7 +134,7 @@ export function CompanySettingsSidebar() {
|
|||
<SidebarNavItem to="/company/settings/invites" label="Invites" icon={MailPlus} end />
|
||||
<SidebarNavItem to="/company/settings/secrets" label="Secrets" icon={KeyRound} end />
|
||||
</div>
|
||||
<div className="mt-5 px-3 pb-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
<div className="mt-5 px-3 pb-1 text-(length:--fs-11) font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
Instance settings
|
||||
</div>
|
||||
<div className="flex flex-col gap-0.5">
|
||||
|
|
|
|||
|
|
@ -68,11 +68,11 @@ export function DevRestartBanner({ devServer }: { devServer?: DevServerHealthSta
|
|||
<div className="border-b border-amber-300/60 bg-amber-50 text-amber-950 dark:border-amber-500/25 dark:bg-amber-500/10 dark:text-amber-100">
|
||||
<div className="flex flex-col gap-3 px-3 py-2.5 md:flex-row md:items-center md:justify-between">
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2 text-[12px] font-semibold uppercase tracking-[0.18em]">
|
||||
<div className="flex items-center gap-2 text-(length:--fs-12) font-semibold uppercase tracking-(--ls-0_18)">
|
||||
<AlertTriangle className="h-3.5 w-3.5 shrink-0" />
|
||||
<span>Restart Required</span>
|
||||
{devServer.autoRestartEnabled ? (
|
||||
<span className="rounded-full bg-amber-900/10 px-2 py-0.5 text-[10px] tracking-[0.14em] dark:bg-amber-100/10">
|
||||
<span className="rounded-full bg-amber-900/10 px-2 py-0.5 text-(length:--fs-10) tracking-(--ls-0_14) dark:bg-amber-100/10">
|
||||
Auto-Restart On
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -328,7 +328,7 @@ function AnnotationPanelBody(props: AnnotationPanelProps) {
|
|||
data-testid={bodyTestId}
|
||||
className="flex items-center justify-end gap-1 border-b border-border bg-popover px-2 py-1.5"
|
||||
>
|
||||
<span className="text-[11px] tabular-nums text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) tabular-nums text-muted-foreground">
|
||||
rev {props.documentRevisionNumber}
|
||||
</span>
|
||||
<Button
|
||||
|
|
@ -348,7 +348,7 @@ function AnnotationPanelBody(props: AnnotationPanelProps) {
|
|||
{props.newCommentDisabled && props.newCommentDisabledReason ? (
|
||||
<p
|
||||
data-testid="document-annotation-disabled-reason"
|
||||
className="border-b border-border bg-muted px-3 py-1.5 text-[11px] text-muted-foreground"
|
||||
className="border-b border-border bg-muted px-3 py-1.5 text-(length:--fs-11) text-muted-foreground"
|
||||
>
|
||||
{props.newCommentDisabledReason}
|
||||
</p>
|
||||
|
|
@ -356,7 +356,7 @@ function AnnotationPanelBody(props: AnnotationPanelProps) {
|
|||
{mutationError ? (
|
||||
<p
|
||||
data-testid="document-annotation-error"
|
||||
className="border-b border-border bg-destructive/10 px-3 py-1.5 text-[11px] text-destructive"
|
||||
className="border-b border-border bg-destructive/10 px-3 py-1.5 text-(length:--fs-11) text-destructive"
|
||||
>
|
||||
{mutationError}
|
||||
</p>
|
||||
|
|
@ -408,7 +408,7 @@ function AnnotationPanelBody(props: AnnotationPanelProps) {
|
|||
{currentUser.image ? <AvatarImage src={currentUser.image} alt={currentUser.name} /> : null}
|
||||
<AvatarFallback>{deriveInitials(currentUser.name)}</AvatarFallback>
|
||||
</Avatar>
|
||||
<span className="truncate text-[11px] font-medium text-foreground">{currentUser.name}</span>
|
||||
<span className="truncate text-(length:--fs-11) font-medium text-foreground">{currentUser.name}</span>
|
||||
</div>
|
||||
<Textarea
|
||||
ref={composerRef}
|
||||
|
|
@ -626,7 +626,7 @@ function CommentRow({
|
|||
focused && "ring-2 ring-primary/40",
|
||||
)}
|
||||
>
|
||||
<div className="mb-0.5 flex items-center justify-between gap-2 text-[11px]">
|
||||
<div className="mb-0.5 flex items-center justify-between gap-2 text-(length:--fs-11)">
|
||||
<span className="flex min-w-0 items-center gap-1.5">
|
||||
<Avatar size="xs" className="shrink-0">
|
||||
{author.role === "agent" ? (
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export function DocumentDiffModal({
|
|||
|
||||
<div className="flex items-center gap-4 shrink-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded-full border border-red-500/30 bg-red-500/10 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider text-red-400">Old</span>
|
||||
<span className="rounded-full border border-red-500/30 bg-red-500/10 px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-wider text-red-400">Old</span>
|
||||
<Select
|
||||
value={effectiveLeftId ?? ""}
|
||||
onValueChange={(value) => setLeftRevisionId(value)}
|
||||
|
|
@ -113,7 +113,7 @@ export function DocumentDiffModal({
|
|||
</Select>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded-full border border-green-500/30 bg-green-500/10 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider text-green-400">New</span>
|
||||
<span className="rounded-full border border-green-500/30 bg-green-500/10 px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-wider text-green-400">New</span>
|
||||
<Select
|
||||
value={effectiveRightId ?? ""}
|
||||
onValueChange={(value) => setRightRevisionId(value)}
|
||||
|
|
@ -141,8 +141,8 @@ export function DocumentDiffModal({
|
|||
) : leftRevision.id === rightRevision.id ? (
|
||||
<div className="p-6 text-center text-muted-foreground text-sm">Both sides are the same revision.</div>
|
||||
) : (
|
||||
<div className="font-mono text-[12px] leading-6">
|
||||
<div className="grid grid-cols-[56px_56px_24px_minmax(0,1fr)] border-b border-border/60 bg-muted/30 px-3 py-2 text-[11px] uppercase tracking-wide text-muted-foreground">
|
||||
<div className="font-mono text-(length:--fs-12) leading-6">
|
||||
<div className="grid grid-cols-[56px_56px_24px_minmax(0,1fr)] border-b border-border/60 bg-muted/30 px-3 py-2 text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">
|
||||
<span>Old</span>
|
||||
<span>New</span>
|
||||
<span />
|
||||
|
|
|
|||
|
|
@ -74,12 +74,12 @@ export function DocumentFrameHeader({
|
|||
{documentLabel ? (
|
||||
<>
|
||||
<span className="truncate text-sm font-semibold text-foreground">{documentLabel}</span>
|
||||
<span className="shrink-0 rounded-full border border-border px-2 py-0.5 font-mono text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="shrink-0 rounded-full border border-border px-2 py-0.5 font-mono text-(length:--fs-10) uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{documentKey}
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<span className="shrink-0 rounded-full border border-border px-2 py-0.5 font-mono text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="shrink-0 rounded-full border border-border px-2 py-0.5 font-mono text-(length:--fs-10) uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{documentKey}
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -91,7 +91,7 @@ export function DocumentFrameHeader({
|
|||
variant="ghost"
|
||||
size="sm"
|
||||
className={cn(
|
||||
"h-auto px-1.5 py-0 text-[11px] font-normal text-muted-foreground hover:text-foreground",
|
||||
"h-auto px-1.5 py-0 text-(length:--fs-11) font-normal text-muted-foreground hover:text-foreground",
|
||||
revisionMenu.historicalPreview && "text-amber-300 hover:text-amber-200",
|
||||
)}
|
||||
>
|
||||
|
|
@ -118,7 +118,7 @@ export function DocumentFrameHeader({
|
|||
<div className="flex items-center gap-2">
|
||||
<span className="font-medium">rev {revision.revisionNumber}</span>
|
||||
{isCurrentRevision ? (
|
||||
<span className="rounded-full border border-border px-1.5 py-0.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
|
||||
<span className="rounded-full border border-border px-1.5 py-0.5 text-(length:--fs-10) uppercase tracking-(--ls-0_12) text-muted-foreground">
|
||||
Current
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -140,7 +140,7 @@ export function DocumentFrameHeader({
|
|||
{updatedAt ? (
|
||||
<a
|
||||
href={updatedHref ?? `#document-${encodeURIComponent(documentKey)}`}
|
||||
className="truncate text-[11px] text-muted-foreground transition-colors hover:text-foreground hover:underline"
|
||||
className="truncate text-(length:--fs-11) text-muted-foreground transition-colors hover:text-foreground hover:underline"
|
||||
>
|
||||
updated {relativeTime(updatedAt)}
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export function ExecutionParticipantPicker({
|
|||
<PopoverTrigger asChild>
|
||||
<button
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-[10px] font-medium transition-colors cursor-pointer",
|
||||
"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 text-(length:--fs-10) font-medium transition-colors cursor-pointer",
|
||||
values.length > 0
|
||||
? "border-border text-foreground hover:bg-accent/50"
|
||||
: "border-dashed border-border/60 text-muted-foreground hover:border-border hover:text-foreground",
|
||||
|
|
|
|||
|
|
@ -178,29 +178,29 @@ export function ExecutionWorkspaceCloseDialog({
|
|||
<div className="rounded-xl border border-border bg-background px-4 py-3 text-sm">
|
||||
<div className="grid gap-2 sm:grid-cols-2">
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Branch</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Branch</div>
|
||||
<div className="font-mono text-xs">{readiness.git.branchName ?? "Unknown"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Base ref</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Base ref</div>
|
||||
<div className="font-mono text-xs">{readiness.git.baseRef ?? "Not set"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Merged into base</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Merged into base</div>
|
||||
<div>{readiness.git.isMergedIntoBase == null ? "Unknown" : readiness.git.isMergedIntoBase ? "Yes" : "No"}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Ahead / behind</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Ahead / behind</div>
|
||||
<div>
|
||||
{(readiness.git.aheadCount ?? 0).toString()} / {(readiness.git.behindCount ?? 0).toString()}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Dirty tracked files</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Dirty tracked files</div>
|
||||
<div>{readiness.git.dirtyEntryCount}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-xs uppercase tracking-[0.16em] text-muted-foreground">Untracked files</div>
|
||||
<div className="text-xs uppercase tracking-(--ls-0_16) text-muted-foreground">Untracked files</div>
|
||||
<div>{readiness.git.untrackedEntryCount}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ export function ExternalObjectPill({
|
|||
</>
|
||||
);
|
||||
const countSuffix = typeof sourceCount === "number" && sourceCount > 1 ? (
|
||||
<span className="tabular-nums text-[10px] font-medium opacity-80">×{sourceCount}</span>
|
||||
<span className="tabular-nums text-(length:--fs-10) font-medium opacity-80">×{sourceCount}</span>
|
||||
) : null;
|
||||
const innerContent = (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function ExternalObjectStatusSummary({
|
|||
aria-label={title}
|
||||
title={title}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px] font-medium tabular-nums leading-none",
|
||||
"inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-(length:--fs-10) font-medium tabular-nums leading-none",
|
||||
badgeClass,
|
||||
compact && "px-1 py-0.5",
|
||||
className,
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ export function FileTree({
|
|||
{badge && (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-3 shrink-0 rounded-full px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide",
|
||||
"ml-3 shrink-0 rounded-full px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-wide",
|
||||
statusBadge[badge.status] ?? statusBadgeDefault,
|
||||
)}
|
||||
title={badge.tooltip}
|
||||
|
|
|
|||
|
|
@ -19,22 +19,22 @@ export function FinanceBillerCard({ row }: FinanceBillerCardProps) {
|
|||
</div>
|
||||
<div className="text-right">
|
||||
<div className="text-lg font-semibold tabular-nums">{formatCents(row.netCents)}</div>
|
||||
<div className="text-[11px] uppercase tracking-[0.16em] text-muted-foreground">net</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_16) text-muted-foreground">net</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3 px-4 pb-4 pt-3">
|
||||
<div className="grid gap-2 text-sm sm:grid-cols-3">
|
||||
<div className="border border-border p-3">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">debits</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">debits</div>
|
||||
<div className="mt-1 font-medium tabular-nums">{formatCents(row.debitCents)}</div>
|
||||
</div>
|
||||
<div className="border border-border p-3">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">credits</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">credits</div>
|
||||
<div className="mt-1 font-medium tabular-nums">{formatCents(row.creditCents)}</div>
|
||||
</div>
|
||||
<div className="border border-border p-3">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">estimated</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">estimated</div>
|
||||
<div className="mt-1 font-medium tabular-nums">{formatCents(row.estimatedDebitCents)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export function FinanceTimelineCard({
|
|||
<div className="text-right tabular-nums">
|
||||
<div className="text-sm font-semibold">{formatCents(row.amountCents)}</div>
|
||||
<div className="text-xs text-muted-foreground">{row.currency}</div>
|
||||
{row.estimated ? <div className="text-[11px] uppercase tracking-[0.12em] text-amber-600">estimated</div> : null}
|
||||
{row.estimated ? <div className="text-(length:--fs-11) uppercase tracking-(--ls-0_12) text-amber-600">estimated</div> : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ export function InlineEditor({
|
|||
<div className="flex min-h-4 items-center justify-end pr-1">
|
||||
<span
|
||||
className={cn(
|
||||
"text-[11px] transition-opacity duration-150",
|
||||
"text-(length:--fs-11) transition-opacity duration-150",
|
||||
autosaveState === "error" ? "text-destructive" : "text-muted-foreground",
|
||||
autosaveState === "idle" ? "opacity-0" : "opacity-100",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ export function IssueAssignedBacklogNotice({
|
|||
<p className="leading-5">
|
||||
<span className="font-medium">Parked</span> —{" "}
|
||||
<span className="font-medium">{assigneeLabel}</span> will not be woken until status changes to{" "}
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-[12px] dark:bg-amber-400/15">todo</code> or{" "}
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-[12px] dark:bg-amber-400/15">in_progress</code>.
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-(length:--fs-12) dark:bg-amber-400/15">todo</code> or{" "}
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-(length:--fs-12) dark:bg-amber-400/15">in_progress</code>.
|
||||
</p>
|
||||
{assigneeAgent ? (
|
||||
<p className="text-xs leading-5 text-amber-800 dark:text-amber-200">
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ function AttachmentActions({
|
|||
|
||||
function AttachmentMeta({ attachment }: { attachment: IssueAttachment }) {
|
||||
return (
|
||||
<p className="mt-0.5 text-[11px] text-muted-foreground">
|
||||
<p className="mt-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
Attachment · {attachment.contentType} · {formatBytes(attachment.byteSize)}
|
||||
</p>
|
||||
);
|
||||
|
|
@ -134,7 +134,7 @@ function MarkdownAttachmentCard({
|
|||
<p className="px-1 py-2 text-xs text-destructive">Could not load markdown preview.</p>
|
||||
) : (
|
||||
<FoldCurtain>
|
||||
<MarkdownBody className="paperclip-edit-in-place-content min-h-[220px] text-[15px] leading-7" softBreaks={false}>
|
||||
<MarkdownBody className="paperclip-edit-in-place-content min-h-[220px] text-(length:--fs-15) leading-7" softBreaks={false}>
|
||||
{data ?? ""}
|
||||
</MarkdownBody>
|
||||
</FoldCurtain>
|
||||
|
|
@ -198,7 +198,7 @@ function GenericAttachmentRow({
|
|||
>
|
||||
{filename}
|
||||
</a>
|
||||
<p className="truncate text-[11px] text-muted-foreground">
|
||||
<p className="truncate text-(length:--fs-11) text-muted-foreground">
|
||||
Attachment · {attachment.contentType} · {formatBytes(attachment.byteSize)}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function BlockerRecoveryIndicator({ action }: { action: IssueRecoveryAction }) {
|
|||
role="status"
|
||||
aria-label={label}
|
||||
title={`${label} — open the source task to act.`}
|
||||
className={`inline-flex shrink-0 items-center gap-0.5 rounded-full border px-1.5 py-0.5 text-[10px] font-medium ${tone.className}`}
|
||||
className={`inline-flex shrink-0 items-center gap-0.5 rounded-full border px-1.5 py-0.5 text-(length:--fs-10) font-medium ${tone.className}`}
|
||||
>
|
||||
<Icon className="h-2.5 w-2.5" aria-hidden />
|
||||
{label}
|
||||
|
|
@ -189,7 +189,7 @@ export function IssueBlockedNotice({
|
|||
className="inline-flex max-w-full items-center gap-1 rounded-md border border-amber-300/70 bg-background/80 px-2 py-1 font-mono text-xs text-amber-950 transition-colors hover:border-amber-500 hover:bg-amber-100 hover:underline dark:border-amber-500/40 dark:bg-background/40 dark:text-amber-100 dark:hover:bg-amber-500/15"
|
||||
>
|
||||
<span>{blocker.identifier ?? blocker.id.slice(0, 8)}</span>
|
||||
<span className="max-w-[18rem] truncate font-sans text-[11px] text-amber-800 dark:text-amber-200">
|
||||
<span className="max-w-[18rem] truncate font-sans text-(length:--fs-11) text-amber-800 dark:text-amber-200">
|
||||
{blocker.title}
|
||||
</span>
|
||||
{recoveryAction ? <BlockerRecoveryIndicator action={recoveryAction} /> : null}
|
||||
|
|
@ -211,7 +211,7 @@ export function IssueBlockedNotice({
|
|||
<p className="font-medium leading-5">This task still needs a next step.</p>
|
||||
<p className="leading-5">
|
||||
A run finished successfully, but this task is still open in{" "}
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-[12px] dark:bg-amber-400/15">
|
||||
<code className="rounded bg-amber-100 px-1 py-0.5 text-(length:--fs-12) dark:bg-amber-400/15">
|
||||
in_progress
|
||||
</code>{" "}
|
||||
with no clear owner for the next action.
|
||||
|
|
|
|||
|
|
@ -653,7 +653,7 @@ function IssueChatFallbackThread({
|
|||
<div className="mb-2 flex items-center gap-2 text-sm">
|
||||
<span className="font-medium text-foreground">{fallbackAuthorLabel(message)}</span>
|
||||
{message.createdAt ? (
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">
|
||||
{commentDateLabel(message.createdAt)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -1049,7 +1049,7 @@ function IssueChatReasoningPart({ text }: { text: string }) {
|
|||
{ticker.exiting !== null && (
|
||||
<span
|
||||
key={`out-${ticker.key}`}
|
||||
className="cot-line-exit absolute inset-x-0 truncate text-[13px] italic leading-5 text-muted-foreground/70"
|
||||
className="cot-line-exit absolute inset-x-0 truncate text-(length:--fs-13) italic leading-5 text-muted-foreground/70"
|
||||
onAnimationEnd={() => setTicker((t) => ({ ...t, exiting: null }))}
|
||||
>
|
||||
{ticker.exiting}
|
||||
|
|
@ -1058,7 +1058,7 @@ function IssueChatReasoningPart({ text }: { text: string }) {
|
|||
<span
|
||||
key={`in-${ticker.key}`}
|
||||
className={cn(
|
||||
"absolute inset-x-0 truncate text-[13px] italic leading-5 text-muted-foreground/70",
|
||||
"absolute inset-x-0 truncate text-(length:--fs-13) italic leading-5 text-muted-foreground/70",
|
||||
ticker.key > 0 && "cot-line-enter",
|
||||
)}
|
||||
>
|
||||
|
|
@ -1106,7 +1106,7 @@ function IssueChatRollingToolPart({ toolParts }: { toolParts: ToolCallMessagePar
|
|||
{ticker.exiting !== null && (
|
||||
<span
|
||||
key={`out-${ticker.key}`}
|
||||
className="cot-line-exit absolute inset-x-0 truncate text-[13px] leading-5 text-muted-foreground/70"
|
||||
className="cot-line-exit absolute inset-x-0 truncate text-(length:--fs-13) leading-5 text-muted-foreground/70"
|
||||
onAnimationEnd={() => setTicker((t) => ({ ...t, exiting: null }))}
|
||||
>
|
||||
{ticker.exiting}
|
||||
|
|
@ -1115,7 +1115,7 @@ function IssueChatRollingToolPart({ toolParts }: { toolParts: ToolCallMessagePar
|
|||
<span
|
||||
key={`in-${ticker.key}`}
|
||||
className={cn(
|
||||
"absolute inset-x-0 truncate text-[13px] leading-5 text-muted-foreground/70",
|
||||
"absolute inset-x-0 truncate text-(length:--fs-13) leading-5 text-muted-foreground/70",
|
||||
ticker.key > 0 && "cot-line-enter",
|
||||
)}
|
||||
>
|
||||
|
|
@ -1216,7 +1216,7 @@ function IssueChatToolPart({
|
|||
className="flex w-full items-center gap-2 rounded-md py-0.5 text-left transition-colors hover:bg-accent/5"
|
||||
onClick={() => setOpen((current) => !current)}
|
||||
>
|
||||
<span className="min-w-0 flex-1 truncate text-[13px] text-muted-foreground/80">
|
||||
<span className="min-w-0 flex-1 truncate text-(length:--fs-13) text-muted-foreground/80">
|
||||
{title}
|
||||
{!intentDetail && summary ? <span className="ml-1.5 text-muted-foreground/50">{summary}</span> : null}
|
||||
</span>
|
||||
|
|
@ -1230,16 +1230,16 @@ function IssueChatToolPart({
|
|||
<div className="mt-1 space-y-2 pb-1">
|
||||
{nonIntentDetails.length > 0 ? (
|
||||
<div>
|
||||
<div className="mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/60">
|
||||
<div className="mb-1 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_14) text-muted-foreground/60">
|
||||
Input
|
||||
</div>
|
||||
<dl className="space-y-1.5">
|
||||
{nonIntentDetails.map((detail) => (
|
||||
<div key={`${detail.label}:${detail.value}`}>
|
||||
<dt className="text-[10px] font-medium text-muted-foreground/60">
|
||||
<dt className="text-(length:--fs-10) font-medium text-muted-foreground/60">
|
||||
{detail.label}
|
||||
</dt>
|
||||
<dd className={cn("text-xs leading-5 text-foreground/70", detail.tone === "code" && "font-mono text-[11px]")}>
|
||||
<dd className={cn("text-xs leading-5 text-foreground/70", detail.tone === "code" && "font-mono text-(length:--fs-11)")}>
|
||||
{detail.value}
|
||||
</dd>
|
||||
</div>
|
||||
|
|
@ -1248,18 +1248,18 @@ function IssueChatToolPart({
|
|||
</div>
|
||||
) : rawArgsText ? (
|
||||
<div>
|
||||
<div className="mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/60">
|
||||
<div className="mb-1 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_14) text-muted-foreground/60">
|
||||
Input
|
||||
</div>
|
||||
<CopyablePreBlock className="overflow-x-auto rounded-md bg-accent/30 p-2 text-[11px] leading-4 text-foreground/70">{rawArgsText}</CopyablePreBlock>
|
||||
<CopyablePreBlock className="overflow-x-auto rounded-md bg-accent/30 p-2 text-(length:--fs-11) leading-4 text-foreground/70">{rawArgsText}</CopyablePreBlock>
|
||||
</div>
|
||||
) : null}
|
||||
{result !== undefined ? (
|
||||
<div>
|
||||
<div className="mb-1 text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground/60">
|
||||
<div className="mb-1 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_14) text-muted-foreground/60">
|
||||
Result
|
||||
</div>
|
||||
<CopyablePreBlock className="overflow-x-auto rounded-md bg-accent/30 p-2 text-[11px] leading-4 text-foreground/70">{resultText}</CopyablePreBlock>
|
||||
<CopyablePreBlock className="overflow-x-auto rounded-md bg-accent/30 p-2 text-(length:--fs-11) leading-4 text-foreground/70">{resultText}</CopyablePreBlock>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
@ -1431,7 +1431,7 @@ function IssueChatUserMessage({
|
|||
<span className="text-sm font-medium text-foreground">{resolvedAuthorName}</span>
|
||||
<SourceTrustBadge sourceTrust={sourceTrust} artifactLabel="comment" />
|
||||
{followUpRequested ? (
|
||||
<Badge variant="outline" className="text-[10px] uppercase tracking-[0.14em]">
|
||||
<Badge variant="outline" className="text-(length:--fs-10) uppercase tracking-(--ls-0_14)">
|
||||
Follow-up
|
||||
</Badge>
|
||||
) : null}
|
||||
|
|
@ -1455,14 +1455,14 @@ function IssueChatUserMessage({
|
|||
>
|
||||
{queued ? (
|
||||
<div className="mb-1.5 flex items-center gap-2">
|
||||
<span className="inline-flex items-center rounded-full border border-amber-400/60 bg-amber-100/70 px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-amber-800 dark:border-amber-400/40 dark:bg-amber-500/20 dark:text-amber-200">
|
||||
<span className="inline-flex items-center rounded-full border border-amber-400/60 bg-amber-100/70 px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-amber-800 dark:border-amber-400/40 dark:bg-amber-500/20 dark:text-amber-200">
|
||||
{queueBadgeLabel}
|
||||
</span>
|
||||
{queueTargetRunId && onInterruptQueued ? (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-6 border-red-300 px-2 text-[11px] text-red-700 hover:bg-red-50 hover:text-red-800 dark:border-red-500/40 dark:text-red-300 dark:hover:bg-red-500/10"
|
||||
className="h-6 border-red-300 px-2 text-(length:--fs-11) text-red-700 hover:bg-red-50 hover:text-red-800 dark:border-red-500/40 dark:text-red-300 dark:hover:bg-red-500/10"
|
||||
disabled={isInterruptingQueuedRun}
|
||||
onClick={() => void onInterruptQueued(queueTargetRunId)}
|
||||
>
|
||||
|
|
@ -1473,7 +1473,7 @@ function IssueChatUserMessage({
|
|||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="h-6 border-amber-300 px-2 text-[11px] text-amber-900 hover:bg-amber-100/80 hover:text-amber-950 dark:border-amber-500/40 dark:text-amber-100 dark:hover:bg-amber-500/10"
|
||||
className="h-6 border-amber-300 px-2 text-(length:--fs-11) text-amber-900 hover:bg-amber-100/80 hover:text-amber-950 dark:border-amber-500/40 dark:text-amber-100 dark:hover:bg-amber-500/10"
|
||||
onClick={() => onCancelQueued(commentId)}
|
||||
>
|
||||
Cancel
|
||||
|
|
@ -1491,7 +1491,7 @@ function IssueChatUserMessage({
|
|||
</div>
|
||||
|
||||
{pending ? (
|
||||
<div className={cn("mt-1 flex px-1 text-[11px] text-muted-foreground", isCurrentUser ? "justify-end" : "justify-start")}>
|
||||
<div className={cn("mt-1 flex px-1 text-(length:--fs-11) text-muted-foreground", isCurrentUser ? "justify-end" : "justify-start")}>
|
||||
Sending...
|
||||
</div>
|
||||
) : (
|
||||
|
|
@ -1505,7 +1505,7 @@ function IssueChatUserMessage({
|
|||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href={anchorId ? `#${anchorId}` : undefined}
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground hover:underline"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground hover:underline"
|
||||
>
|
||||
{message.createdAt ? commentDateLabel(message.createdAt) : ""}
|
||||
</a>
|
||||
|
|
@ -1731,7 +1731,7 @@ function IssueChatAssistantMessage({
|
|||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href={anchorId ? `#${anchorId}` : undefined}
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground hover:underline"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground hover:underline"
|
||||
>
|
||||
{message.createdAt ? commentDateLabel(message.createdAt) : ""}
|
||||
</a>
|
||||
|
|
@ -1813,14 +1813,14 @@ function IssueChatAssistantMessage({
|
|||
<AgentIcon icon={agentIcon} className="h-4 w-4" />
|
||||
) : (
|
||||
<Avatar size="sm" className="size-5">
|
||||
<AvatarFallback className="text-[10px]">{initialsForName(authorName)}</AvatarFallback>
|
||||
<AvatarFallback className="text-(length:--fs-10)">{initialsForName(authorName)}</AvatarFallback>
|
||||
</Avatar>
|
||||
)}
|
||||
</span>
|
||||
<span className="text-sm font-medium text-foreground">{authorName}</span>
|
||||
<SourceTrustBadge sourceTrust={sourceTrust} artifactLabel="comment" />
|
||||
{followUpRequested ? (
|
||||
<Badge variant="outline" className="text-[10px] uppercase tracking-[0.14em]">
|
||||
<Badge variant="outline" className="text-(length:--fs-10) uppercase tracking-(--ls-0_14)">
|
||||
Follow-up
|
||||
</Badge>
|
||||
) : null}
|
||||
|
|
@ -1878,7 +1878,7 @@ function IssueChatAssistantMessage({
|
|||
<span className="text-xs text-muted-foreground/60">{chainOfThoughtLabel?.toLowerCase()}</span>
|
||||
<span className="ml-auto flex items-center gap-1.5">
|
||||
{message.createdAt ? (
|
||||
<span className="text-[11px] text-muted-foreground/50">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground/50">
|
||||
{commentDateLabel(message.createdAt)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -1890,12 +1890,12 @@ function IssueChatAssistantMessage({
|
|||
<span className="text-sm font-medium text-foreground">{authorName}</span>
|
||||
<SourceTrustBadge sourceTrust={sourceTrust} artifactLabel="comment" />
|
||||
{followUpRequested ? (
|
||||
<Badge variant="outline" className="text-[10px] uppercase tracking-[0.14em]">
|
||||
<Badge variant="outline" className="text-(length:--fs-10) uppercase tracking-(--ls-0_14)">
|
||||
Follow-up
|
||||
</Badge>
|
||||
) : null}
|
||||
{isRunning ? (
|
||||
<span className="inline-flex items-center gap-1 rounded-full border border-cyan-400/40 bg-cyan-500/10 px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-cyan-700 dark:text-cyan-200">
|
||||
<span className="inline-flex items-center gap-1 rounded-full border border-cyan-400/40 bg-cyan-500/10 px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-cyan-700 dark:text-cyan-200">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
Running
|
||||
</span>
|
||||
|
|
@ -2221,7 +2221,7 @@ function ExpiredRequestConfirmationActivity({
|
|||
</a>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-md border border-border/70 bg-background/70 px-1.5 py-0.5 text-[11px] font-medium text-muted-foreground transition-colors hover:border-border hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
className="inline-flex items-center gap-1 rounded-md border border-border/70 bg-background/70 px-1.5 py-0.5 text-(length:--fs-11) font-medium text-muted-foreground transition-colors hover:border-border hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
aria-expanded={expanded}
|
||||
aria-controls={detailsId}
|
||||
onClick={() => setExpanded((current) => !current)}
|
||||
|
|
@ -2338,7 +2338,7 @@ function isStaleSuccessfulRunHandoffNotice(input: {
|
|||
|
||||
function StaleDispositionWarningMetadataRow({ row }: { row: SystemNoticeMetadataRow }) {
|
||||
const label = (
|
||||
<span className="text-[10px] font-semibold uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<span className="text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
{row.label}
|
||||
</span>
|
||||
);
|
||||
|
|
@ -2348,7 +2348,7 @@ function StaleDispositionWarningMetadataRow({ row }: { row: SystemNoticeMetadata
|
|||
return <span>{row.value}</span>;
|
||||
case "code":
|
||||
return (
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-foreground/80">
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-(length:--fs-11) text-foreground/80">
|
||||
{row.value}
|
||||
</code>
|
||||
);
|
||||
|
|
@ -2379,7 +2379,7 @@ function StaleDispositionWarningMetadataRow({ row }: { row: SystemNoticeMetadata
|
|||
const runShort = row.runId.length > 12 ? `${row.runId.slice(0, 8)}...` : row.runId;
|
||||
const content = (
|
||||
<>
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-foreground/80">
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-(length:--fs-11) text-foreground/80">
|
||||
{runShort}
|
||||
</code>
|
||||
{row.status ? <span>{row.status}</span> : null}
|
||||
|
|
@ -2454,7 +2454,7 @@ function StaleDispositionWarningDetails({
|
|||
{sections.map((section) => (
|
||||
<div key={metadataSectionKey(section)} className="space-y-1.5">
|
||||
{section.title ? (
|
||||
<div className="text-[10px] font-semibold uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{section.title}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -2501,7 +2501,7 @@ function StaleDispositionWarningRow({
|
|||
</span>
|
||||
<span className="ml-auto flex items-center gap-1.5">
|
||||
{message.createdAt ? (
|
||||
<span data-testid="stale-disposition-warning-time" className="text-[11px] text-muted-foreground/50">
|
||||
<span data-testid="stale-disposition-warning-time" className="text-(length:--fs-11) text-muted-foreground/50">
|
||||
{commentDateLabel(message.createdAt)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -2622,7 +2622,7 @@ function SystemNoticeCommentRow({
|
|||
<TooltipTrigger asChild>
|
||||
<a
|
||||
href={anchorId ? `#${anchorId}` : undefined}
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground hover:underline"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground hover:underline"
|
||||
>
|
||||
{message.createdAt ? commentDateLabel(message.createdAt) : ""}
|
||||
</a>
|
||||
|
|
@ -2790,7 +2790,7 @@ function IssueChatSystemMessage({ message }: { message: ThreadMessage }) {
|
|||
|
||||
{statusChange ? (
|
||||
<div className="flex flex-wrap items-center gap-1.5 text-xs">
|
||||
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
<span className="text-(length:--fs-10) font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
Status
|
||||
</span>
|
||||
<span className="text-muted-foreground">{humanizeValue(statusChange.from)}</span>
|
||||
|
|
@ -2802,7 +2802,7 @@ function IssueChatSystemMessage({ message }: { message: ThreadMessage }) {
|
|||
{assigneeChange ? (
|
||||
<div className="space-y-1">
|
||||
<div className={cn("flex flex-wrap items-center gap-1.5 text-xs", isCurrentUser && "justify-end")}>
|
||||
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
<span className="text-(length:--fs-10) font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
Assignee
|
||||
</span>
|
||||
<AssigneeChip assignee={assigneeChange.from} resolvers={handoffResolvers} />
|
||||
|
|
@ -2821,7 +2821,7 @@ function IssueChatSystemMessage({ message }: { message: ThreadMessage }) {
|
|||
|
||||
{workspaceChange ? (
|
||||
<div className="flex flex-wrap items-center gap-1.5 text-xs">
|
||||
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
<span className="text-(length:--fs-10) font-medium uppercase tracking-wider text-muted-foreground/70">
|
||||
Workspace
|
||||
</span>
|
||||
<span className="text-muted-foreground">
|
||||
|
|
@ -2853,7 +2853,7 @@ function IssueChatSystemMessage({ message }: { message: ThreadMessage }) {
|
|||
<span className="text-muted-foreground">run</span>
|
||||
<Link
|
||||
to={`/agents/${runAgentId}/runs/${runId}`}
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/40 px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
|
||||
className="inline-flex items-center rounded-md border border-border bg-accent/40 px-1.5 py-0.5 font-mono text-(length:--fs-10) text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
|
||||
>
|
||||
{runId.slice(0, 8)}
|
||||
</Link>
|
||||
|
|
@ -3906,7 +3906,7 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
|||
) : null}
|
||||
|
||||
{composerHint ? (
|
||||
<div className="inline-flex items-center rounded-full border border-border/70 bg-muted/30 px-2 py-1 text-[11px] text-muted-foreground">
|
||||
<div className="inline-flex items-center rounded-full border border-border/70 bg-muted/30 px-2 py-1 text-(length:--fs-11) text-muted-foreground">
|
||||
{composerHint}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -3998,7 +3998,7 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
|||
aria-keyshortcuts="Meta+Period Control+Period"
|
||||
title={titleForPendingWorkMode(pendingWorkMode)}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[11px] font-semibold transition-colors",
|
||||
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-(length:--fs-11) font-semibold transition-colors",
|
||||
pendingWorkModeMeta.classes.chip,
|
||||
)}
|
||||
>
|
||||
|
|
@ -4037,7 +4037,7 @@ const IssueChatComposer = forwardRef<IssueChatComposerHandle, IssueChatComposerP
|
|||
</button>
|
||||
);
|
||||
})}
|
||||
<div className="mt-1 border-t px-2 py-1.5 text-[10px] text-muted-foreground">
|
||||
<div className="mt-1 border-t px-2 py-1.5 text-(length:--fs-10) text-muted-foreground">
|
||||
Cmd/Ctrl+. cycles modes
|
||||
</div>
|
||||
</PopoverContent>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export function IssueColumnPicker({
|
|||
<DropdownMenuContent align="end" className="w-[300px] rounded-xl border-border/70 p-1.5 shadow-xl shadow-black/10">
|
||||
<DropdownMenuLabel className="px-2 pb-1 pt-1.5">
|
||||
<div className="space-y-1">
|
||||
<div className="text-[10px] font-semibold uppercase tracking-[0.22em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_22) text-muted-foreground">
|
||||
Desktop task rows
|
||||
</div>
|
||||
<div className="text-sm font-medium text-foreground">
|
||||
|
|
@ -190,7 +190,7 @@ export function InboxIssueMetaLeading({
|
|||
</span>
|
||||
<span
|
||||
className={cn(
|
||||
"hidden text-[11px] font-medium sm:inline",
|
||||
"hidden text-(length:--fs-11) font-medium sm:inline",
|
||||
"text-blue-600 dark:text-blue-400",
|
||||
)}
|
||||
>
|
||||
|
|
@ -213,7 +213,7 @@ export function InboxIssueMetaLeading({
|
|||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span className="hidden text-[11px] font-medium text-muted-foreground sm:inline">
|
||||
<span className="hidden text-(length:--fs-11) font-medium text-muted-foreground sm:inline">
|
||||
{subtreeLiveCount} live below
|
||||
</span>
|
||||
</span>
|
||||
|
|
@ -390,7 +390,7 @@ export function InboxIssueTrailingColumns({
|
|||
{(issue.labels ?? []).slice(0, 2).map((label) => (
|
||||
<span
|
||||
key={label.id}
|
||||
className="inline-flex min-w-0 max-w-full shrink-0 items-center rounded-full border px-1.5 py-0 text-[10px] font-medium"
|
||||
className="inline-flex min-w-0 max-w-full shrink-0 items-center rounded-full border px-1.5 py-0 text-(length:--fs-10) font-medium"
|
||||
style={{
|
||||
borderColor: label.color,
|
||||
color: pickTextColorForPillBg(label.color, 0.12),
|
||||
|
|
@ -401,7 +401,7 @@ export function InboxIssueTrailingColumns({
|
|||
</span>
|
||||
))}
|
||||
{(issue.labels ?? []).length > 2 ? (
|
||||
<span className="shrink-0 text-[10px] font-medium text-muted-foreground">
|
||||
<span className="shrink-0 text-(length:--fs-10) font-medium text-muted-foreground">
|
||||
+{(issue.labels ?? []).length - 2}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -463,7 +463,7 @@ export function InboxIssueTrailingColumns({
|
|||
|
||||
if (column === "updated") {
|
||||
return (
|
||||
<span key={column} className="min-w-0 truncate text-right text-[11px] font-medium text-muted-foreground">
|
||||
<span key={column} className="min-w-0 truncate text-right text-(length:--fs-11) font-medium text-muted-foreground">
|
||||
{activityText}
|
||||
</span>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -77,11 +77,11 @@ export function IssueContinuationHandoff({
|
|||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="text-sm font-medium text-foreground">{title}</span>
|
||||
<span className="rounded-full border border-border px-2 py-0.5 font-mono text-[10px] uppercase text-muted-foreground">
|
||||
<span className="rounded-full border border-border px-2 py-0.5 font-mono text-(length:--fs-10) uppercase text-muted-foreground">
|
||||
handoff
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
Updated {relativeTime(document.updatedAt)}
|
||||
{document.latestRevisionNumber > 0 ? ` - revision ${document.latestRevisionNumber}` : ""}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -425,7 +425,7 @@ export function DocumentAnnotationsCountChip({
|
|||
variant="ghost"
|
||||
data-state={panelOpen ? "open" : "closed"}
|
||||
className={cn(
|
||||
"h-auto gap-1 rounded-md px-1.5 py-0 text-[11px] font-normal text-muted-foreground hover:text-foreground",
|
||||
"h-auto gap-1 rounded-md px-1.5 py-0 text-(length:--fs-11) font-normal text-muted-foreground hover:text-foreground",
|
||||
panelOpen && "bg-muted text-foreground",
|
||||
openCount > 0 && "text-foreground",
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -762,7 +762,7 @@ export function IssueDocumentsSection({
|
|||
|
||||
const documentBodyShellClassName = "mt-3";
|
||||
const documentBodyPaddingClassName = "";
|
||||
const documentBodyContentClassName = "paperclip-edit-in-place-content min-h-[220px] text-[15px] leading-7";
|
||||
const documentBodyContentClassName = "paperclip-edit-in-place-content min-h-[220px] text-(length:--fs-15) leading-7";
|
||||
const toggleFoldedDocument = (key: string) => {
|
||||
setFoldedDocumentKeys((current) =>
|
||||
current.includes(key)
|
||||
|
|
@ -850,7 +850,7 @@ export function IssueDocumentsSection({
|
|||
placeholder="Markdown body"
|
||||
bordered={false}
|
||||
className="bg-transparent"
|
||||
contentClassName="min-h-[220px] text-[15px] leading-7"
|
||||
contentClassName="min-h-[220px] text-(length:--fs-15) leading-7"
|
||||
mentions={mentions}
|
||||
imageUploadHandler={imageUploadHandler}
|
||||
onSubmit={() => void commitDraft(draft, { clearAfterSave: false, trackAutosave: false })}
|
||||
|
|
@ -881,7 +881,7 @@ export function IssueDocumentsSection({
|
|||
>
|
||||
<div className="mb-2 flex items-center gap-2">
|
||||
<FileText className="h-4 w-4 text-amber-600" />
|
||||
<span className="rounded-full border border-amber-500/30 px-2 py-0.5 font-mono text-[10px] uppercase tracking-[0.16em] text-amber-700 dark:text-amber-300">
|
||||
<span className="rounded-full border border-amber-500/30 px-2 py-0.5 font-mono text-(length:--fs-10) uppercase tracking-(--ls-0_16) text-amber-700 dark:text-amber-300">
|
||||
PLAN
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -1144,7 +1144,7 @@ export function IssueDocumentsSection({
|
|||
</div>
|
||||
{activeConflict.showRemote && (
|
||||
<div className="mt-3 rounded-md border border-border/70 bg-background/60 p-3">
|
||||
<div className="mb-2 flex items-center gap-2 text-[11px] text-muted-foreground">
|
||||
<div className="mb-2 flex items-center gap-2 text-(length:--fs-11) text-muted-foreground">
|
||||
<span>Remote revision {activeConflict.serverDocument.latestRevisionNumber}</span>
|
||||
<span>•</span>
|
||||
<span>updated {relativeTime(activeConflict.serverDocument.updatedAt)}</span>
|
||||
|
|
@ -1152,7 +1152,7 @@ export function IssueDocumentsSection({
|
|||
{!isPlanKey(doc.key) && activeConflict.serverDocument.title ? (
|
||||
<p className="mb-2 text-sm font-medium">{activeConflict.serverDocument.title}</p>
|
||||
) : null}
|
||||
{renderFoldableBody(activeConflict.serverDocument.body, "text-[14px] leading-7", externalReferences)}
|
||||
{renderFoldableBody(activeConflict.serverDocument.body, "text-(length:--fs-14) leading-7", externalReferences)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -1218,7 +1218,7 @@ export function IssueDocumentsSection({
|
|||
</div>
|
||||
<div className="flex min-h-4 items-center justify-end px-1">
|
||||
<span
|
||||
className={`text-[11px] transition-opacity duration-150 ${
|
||||
className={`text-(length:--fs-11) transition-opacity duration-150 ${
|
||||
isHistoricalPreview
|
||||
? "text-amber-300"
|
||||
: activeConflict
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ export function IssueFiltersPopover({
|
|||
<Button variant={buttonVariant} size={iconOnly ? "icon" : "sm"} className={`text-xs ${iconOnly ? "relative h-8 w-8 shrink-0" : ""} ${activeFilterCount > 0 ? "text-blue-600 dark:text-blue-400" : ""}`} title={iconOnly ? (activeFilterCount > 0 ? `Filters: ${activeFilterCount}` : "Filter") : undefined}>
|
||||
<Filter className={iconOnly ? "h-3.5 w-3.5" : "h-3.5 w-3.5 sm:h-3 sm:w-3 sm:mr-1"} />
|
||||
{!iconOnly && <span className="hidden sm:inline">{activeFilterCount > 0 ? `Filters: ${activeFilterCount}` : "Filter"}</span>}
|
||||
{!iconOnly && activeFilterCount > 0 ? <span className="ml-0.5 text-[10px] font-medium sm:hidden">{activeFilterCount}</span> : null}
|
||||
{iconOnly && activeFilterCount > 0 ? <span className="absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-blue-600 text-[9px] font-bold text-white">{activeFilterCount}</span> : null}
|
||||
{!iconOnly && activeFilterCount > 0 ? <span className="ml-0.5 text-(length:--fs-10) font-medium sm:hidden">{activeFilterCount}</span> : null}
|
||||
{iconOnly && activeFilterCount > 0 ? <span className="absolute -right-1 -top-1 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-blue-600 text-(length:--fs-9) font-bold text-white">{activeFilterCount}</span> : null}
|
||||
{!iconOnly && activeFilterCount > 0 ? (
|
||||
<X
|
||||
className="ml-1 hidden h-3 w-3 sm:block"
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ interface IssuePlanDecompositionsSectionProps {
|
|||
function StatusBadge({ status }: { status: AcceptedPlanDecompositionSummary["status"] }) {
|
||||
if (status === "completed") {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-emerald-500/50 bg-emerald-500/10 px-2 py-0.5 text-[11px] font-medium text-emerald-900 dark:text-emerald-100">
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-emerald-500/50 bg-emerald-500/10 px-2 py-0.5 text-(length:--fs-11) font-medium text-emerald-900 dark:text-emerald-100">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
Completed
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-amber-500/50 bg-amber-500/10 px-2 py-0.5 text-[11px] font-medium text-amber-900 dark:text-amber-100">
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-amber-500/50 bg-amber-500/10 px-2 py-0.5 text-(length:--fs-11) font-medium text-amber-900 dark:text-amber-100">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
In flight
|
||||
</span>
|
||||
|
|
@ -47,7 +47,7 @@ export function IssuePlanDecompositionsSection({
|
|||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<h3 className="text-sm font-medium text-muted-foreground">Plan decomposition</h3>
|
||||
<span className="text-[11px] text-muted-foreground/80">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground/80">
|
||||
{items.length === 1 ? "1 accepted plan revision" : `${items.length} accepted plan revisions`}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -99,7 +99,7 @@ export function IssuePlanDecompositionsSection({
|
|||
</span>
|
||||
{record.status === "completed" && requested > 0 ? (
|
||||
<span
|
||||
className="inline-flex items-center gap-1 rounded-sm border border-sky-500/40 bg-sky-500/10 px-1.5 py-0.5 text-[10px] font-medium text-sky-900 dark:text-sky-100"
|
||||
className="inline-flex items-center gap-1 rounded-sm border border-sky-500/40 bg-sky-500/10 px-1.5 py-0.5 text-(length:--fs-10) font-medium text-sky-900 dark:text-sky-100"
|
||||
title="Repeat attempts with this fingerprint reuse this record instead of creating new children"
|
||||
>
|
||||
<Repeat className="h-3 w-3" />
|
||||
|
|
@ -108,7 +108,7 @@ export function IssuePlanDecompositionsSection({
|
|||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-[11px] text-muted-foreground">
|
||||
<div className="mt-1 flex flex-wrap gap-x-3 gap-y-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
{ownerName ? <span>Owner: {ownerName}</span> : null}
|
||||
{startedAt ? (
|
||||
<span title={formatDateTime(startedAt)}>Started {relativeTime(startedAt)}</span>
|
||||
|
|
@ -135,7 +135,7 @@ export function IssuePlanDecompositionsSection({
|
|||
<Link
|
||||
to={`/issues/${child.identifier ?? child.id}`}
|
||||
className={cn(
|
||||
"inline-flex max-w-full items-center gap-1 rounded-sm border border-border bg-background px-2 py-0.5 text-[11px] text-foreground transition-colors hover:bg-accent/40",
|
||||
"inline-flex max-w-full items-center gap-1 rounded-sm border border-border bg-background px-2 py-0.5 text-(length:--fs-11) text-foreground transition-colors hover:bg-accent/40",
|
||||
)}
|
||||
title={child.title}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ function MetadataRow({
|
|||
}) {
|
||||
return (
|
||||
<div className="grid grid-cols-[7.5rem_1fr] gap-x-3 gap-y-0 px-3 py-1.5 text-xs sm:px-4">
|
||||
<dt className="truncate text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">
|
||||
<dt className="truncate text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">
|
||||
{label}
|
||||
</dt>
|
||||
<dd className="min-w-0 break-words text-foreground/90">{children}</dd>
|
||||
|
|
@ -272,11 +272,11 @@ function RunChip({
|
|||
const short = shortenRunId(runId);
|
||||
const inner = (
|
||||
<>
|
||||
<code className="rounded bg-background/80 px-1.5 py-0.5 font-mono text-[11px] text-foreground/80">
|
||||
<code className="rounded bg-background/80 px-1.5 py-0.5 font-mono text-(length:--fs-11) text-foreground/80">
|
||||
run {short}
|
||||
</code>
|
||||
{status ? (
|
||||
<span className="font-sans text-[11px] text-muted-foreground">{status}</span>
|
||||
<span className="font-sans text-(length:--fs-11) text-muted-foreground">{status}</span>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
|
|
@ -404,10 +404,10 @@ export function IssueRecoveryActionCard({
|
|||
<ToneIcon className={cn("h-4 w-4", tone.iconClass)} />
|
||||
</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] font-semibold uppercase tracking-[0.14em]">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_14)">
|
||||
<span className={tone.labelClass}>{tone.label}</span>
|
||||
<span className="text-muted-foreground/60" aria-hidden>·</span>
|
||||
<code className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-[11px] tracking-normal text-muted-foreground">
|
||||
<code className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-(length:--fs-11) tracking-normal text-muted-foreground">
|
||||
{KIND_LABEL[action.kind] ?? action.kind}
|
||||
</code>
|
||||
{updatedAtLabel ? (
|
||||
|
|
@ -419,7 +419,7 @@ export function IssueRecoveryActionCard({
|
|||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="mt-1 text-[14px] leading-6">{headline}</p>
|
||||
<p className="mt-1 text-(length:--fs-14) leading-6">{headline}</p>
|
||||
</div>
|
||||
</header>
|
||||
<dl className={cn("border-t bg-background/40 dark:bg-background/20", tone.divider)}>
|
||||
|
|
@ -457,7 +457,7 @@ export function IssueRecoveryActionCard({
|
|||
) : null}
|
||||
<MetadataRow label="Evidence">
|
||||
{evidenceSummary ? (
|
||||
<span className="break-words font-mono text-[11px] text-foreground/80">{evidenceSummary}</span>
|
||||
<span className="break-words font-mono text-(length:--fs-11) text-foreground/80">{evidenceSummary}</span>
|
||||
) : (
|
||||
<MissingValue />
|
||||
)}
|
||||
|
|
@ -469,12 +469,12 @@ export function IssueRecoveryActionCard({
|
|||
<span className="inline-flex flex-wrap items-center gap-1.5">
|
||||
{wakeSummary ? <span>{wakeSummary}</span> : <MissingValue />}
|
||||
{showAttempt ? (
|
||||
<span className="rounded-md border border-border/50 bg-background/60 px-1.5 py-0.5 text-[11px] text-muted-foreground">
|
||||
<span className="rounded-md border border-border/50 bg-background/60 px-1.5 py-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
attempt {action.attemptCount} of {action.maxAttempts}
|
||||
</span>
|
||||
) : null}
|
||||
{showTimeoutInline ? (
|
||||
<span className="rounded-md border border-border/50 bg-background/60 px-1.5 py-0.5 text-[11px] text-muted-foreground">
|
||||
<span className="rounded-md border border-border/50 bg-background/60 px-1.5 py-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
Times out {formatTimeShort(action.timeoutAt) ?? "soon"}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -508,7 +508,7 @@ export function IssueRecoveryActionCard({
|
|||
sideOffset={6}
|
||||
className="w-72 p-1.5"
|
||||
>
|
||||
<div className="px-2 py-1 text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
|
||||
<div className="px-2 py-1 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_12) text-muted-foreground">
|
||||
Resolve recovery
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
|
|
@ -524,18 +524,18 @@ export function IssueRecoveryActionCard({
|
|||
)}
|
||||
>
|
||||
<span className="font-medium leading-5">{option.label}</span>
|
||||
<span className="text-[11px] leading-4 text-muted-foreground">{option.description}</span>
|
||||
<span className="text-(length:--fs-11) leading-4 text-muted-foreground">{option.description}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
{cardState === "observe_only" ? (
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">
|
||||
Recovery is observing without interrupting the live run.
|
||||
</span>
|
||||
) : (
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">
|
||||
The card stays open until an explicit decision is recorded.
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ function Section({
|
|||
>
|
||||
<span>{group.label}</span>
|
||||
{group.count > 1 ? (
|
||||
<span className="tabular-nums text-[10px] font-medium opacity-80">×{group.count}</span>
|
||||
<span className="tabular-nums text-(length:--fs-10) font-medium opacity-80">×{group.count}</span>
|
||||
) : null}
|
||||
</span>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export function IssueRow({
|
|||
const parkedBlockerIndicator = hasAssignedBacklogBlocker(issue.blockedBy) ? (
|
||||
<span
|
||||
data-testid="issue-row-parked-blocker"
|
||||
className="ml-1.5 inline-flex shrink-0 items-center gap-0.5 rounded-full border border-amber-500/60 bg-amber-500/15 px-2 py-0.5 text-[10px] font-medium text-amber-700 dark:text-amber-300"
|
||||
className="ml-1.5 inline-flex shrink-0 items-center gap-0.5 rounded-full border border-amber-500/60 bg-amber-500/15 px-2 py-0.5 text-(length:--fs-10) font-medium text-amber-700 dark:text-amber-300"
|
||||
title="Blocked by parked work — at least one assigned blocker is in backlog and will not wake its assignee."
|
||||
>
|
||||
<Flag className="h-2.5 w-2.5" aria-hidden />
|
||||
|
|
@ -256,7 +256,7 @@ function renderRecoveryChip(action: IssueRecoveryAction, selected: boolean): Rea
|
|||
role="status"
|
||||
aria-label={label}
|
||||
className={cn(
|
||||
"ml-1.5 inline-flex shrink-0 items-center gap-0.5 rounded-full border px-2 py-0.5 text-[10px] font-medium",
|
||||
"ml-1.5 inline-flex shrink-0 items-center gap-0.5 rounded-full border px-2 py-0.5 text-(length:--fs-10) font-medium",
|
||||
tone.className,
|
||||
selected ? "!border-muted-foreground !text-muted-foreground" : null,
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -580,7 +580,7 @@ export function IssueRunLedgerContent({
|
|||
<Link
|
||||
key={child.id}
|
||||
to={`/issues/${child.identifier ?? child.id}`}
|
||||
className="inline-flex min-w-0 max-w-full items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-[11px] hover:bg-accent/40"
|
||||
className="inline-flex min-w-0 max-w-full items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-(length:--fs-11) hover:bg-accent/40"
|
||||
>
|
||||
<span className="shrink-0 font-mono text-muted-foreground">{child.identifier ?? child.id.slice(0, 8)}</span>
|
||||
<span className="truncate">{child.title}</span>
|
||||
|
|
@ -588,7 +588,7 @@ export function IssueRunLedgerContent({
|
|||
</Link>
|
||||
))}
|
||||
{children.active.length > 4 ? (
|
||||
<span className="rounded-md border border-border px-2 py-1 text-[11px] text-muted-foreground">
|
||||
<span className="rounded-md border border-border px-2 py-1 text-(length:--fs-11) text-muted-foreground">
|
||||
+{children.active.length - 4} more
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -632,7 +632,7 @@ export function IssueRunLedgerContent({
|
|||
<div className="mt-2 flex flex-wrap gap-1.5">
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-[11px] text-foreground hover:bg-background"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-(length:--fs-11) text-foreground hover:bg-background"
|
||||
onClick={() =>
|
||||
onWatchdogDecision({
|
||||
runId: latestSilentRun.runId,
|
||||
|
|
@ -645,7 +645,7 @@ export function IssueRunLedgerContent({
|
|||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-[11px] text-foreground hover:bg-background"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-(length:--fs-11) text-foreground hover:bg-background"
|
||||
onClick={() =>
|
||||
onWatchdogDecision({
|
||||
runId: latestSilentRun.runId,
|
||||
|
|
@ -660,7 +660,7 @@ export function IssueRunLedgerContent({
|
|||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-[11px] text-foreground hover:bg-background"
|
||||
className="rounded-md border border-border bg-background/80 px-2 py-1 text-(length:--fs-11) text-foreground hover:bg-background"
|
||||
onClick={() =>
|
||||
onWatchdogDecision({
|
||||
runId: latestSilentRun.runId,
|
||||
|
|
@ -675,7 +675,7 @@ export function IssueRunLedgerContent({
|
|||
</div>
|
||||
) : null}
|
||||
{watchdogDecisionError ? (
|
||||
<p className="mt-2 rounded-md border border-red-500/30 bg-red-500/10 px-2 py-1 text-[11px] text-red-900 dark:text-red-200">
|
||||
<p className="mt-2 rounded-md border border-red-500/30 bg-red-500/10 px-2 py-1 text-(length:--fs-11) text-red-900 dark:text-red-200">
|
||||
{watchdogDecisionError}
|
||||
</p>
|
||||
) : null}
|
||||
|
|
@ -730,18 +730,18 @@ export function IssueRunLedgerContent({
|
|||
on behalf of <span className="text-foreground">{onBehalfOfLabel}</span>
|
||||
</span>
|
||||
) : null}
|
||||
<span className="rounded-md border border-border px-1.5 py-0.5 text-[11px] capitalize text-muted-foreground">
|
||||
<span className="rounded-md border border-border px-1.5 py-0.5 text-(length:--fs-11) capitalize text-muted-foreground">
|
||||
{statusLabel(run.status)}
|
||||
</span>
|
||||
{run.isLive ? (
|
||||
<span className="inline-flex items-center gap-1 rounded-md border border-cyan-500/30 bg-cyan-500/10 px-1.5 py-0.5 text-[11px] text-cyan-700 dark:text-cyan-300">
|
||||
<span className="inline-flex items-center gap-1 rounded-md border border-cyan-500/30 bg-cyan-500/10 px-1.5 py-0.5 text-(length:--fs-11) text-cyan-700 dark:text-cyan-300">
|
||||
<span className="h-1.5 w-1.5 rounded-full bg-cyan-400" />
|
||||
live
|
||||
</span>
|
||||
) : null}
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-md border px-1.5 py-0.5 text-[11px] font-medium",
|
||||
"rounded-md border px-1.5 py-0.5 text-(length:--fs-11) font-medium",
|
||||
liveness.tone,
|
||||
)}
|
||||
title={liveness.description}
|
||||
|
|
@ -749,17 +749,17 @@ export function IssueRunLedgerContent({
|
|||
{liveness.label}
|
||||
</span>
|
||||
{exhausted ? (
|
||||
<span className="rounded-md border border-red-500/30 bg-red-500/10 px-1.5 py-0.5 text-[11px] font-medium text-red-700 dark:text-red-300">
|
||||
<span className="rounded-md border border-red-500/30 bg-red-500/10 px-1.5 py-0.5 text-(length:--fs-11) font-medium text-red-700 dark:text-red-300">
|
||||
Exhausted
|
||||
</span>
|
||||
) : null}
|
||||
{continuation ? (
|
||||
<span className="text-[11px] text-muted-foreground">{continuation}</span>
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">{continuation}</span>
|
||||
) : null}
|
||||
{retryState ? (
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-md border px-1.5 py-0.5 text-[11px] font-medium",
|
||||
"rounded-md border px-1.5 py-0.5 text-(length:--fs-11) font-medium",
|
||||
retryState.tone,
|
||||
)}
|
||||
>
|
||||
|
|
@ -769,7 +769,7 @@ export function IssueRunLedgerContent({
|
|||
{run.outputSilence && RUN_OUTPUT_SILENCE_COPY[run.outputSilence.level] ? (
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-md border px-1.5 py-0.5 text-[11px] font-medium",
|
||||
"rounded-md border px-1.5 py-0.5 text-(length:--fs-11) font-medium",
|
||||
RUN_OUTPUT_SILENCE_COPY[run.outputSilence.level]?.tone,
|
||||
)}
|
||||
>
|
||||
|
|
@ -787,7 +787,7 @@ export function IssueRunLedgerContent({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-md border px-1.5 py-0.5 text-[11px] font-medium",
|
||||
"rounded-md border px-1.5 py-0.5 text-(length:--fs-11) font-medium",
|
||||
modelProfileBadgeTone(profile),
|
||||
)}
|
||||
title={modelProfileTitle(profile)}
|
||||
|
|
@ -837,7 +837,7 @@ export function IssueRunLedgerContent({
|
|||
const profile = modelProfileForRun(run);
|
||||
if (!profile?.fallbackReason || profile.applied === profile.requested) return null;
|
||||
return (
|
||||
<p className="min-w-0 break-words text-[11px] leading-5 text-amber-700 dark:text-amber-300">
|
||||
<p className="min-w-0 break-words text-(length:--fs-11) leading-5 text-amber-700 dark:text-amber-300">
|
||||
{profile.requested === "cheap"
|
||||
? "Cheap profile fell back to primary"
|
||||
: `${profile.requested} profile unavailable`}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ function TaskField({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center rounded-sm border px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.16em]",
|
||||
"inline-flex items-center rounded-sm border px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_16)",
|
||||
tone === "default"
|
||||
? "border-border/70 bg-transparent text-foreground"
|
||||
: "border-border/60 bg-transparent text-muted-foreground",
|
||||
|
|
@ -316,7 +316,7 @@ function TaskTreeNode({
|
|||
</div>
|
||||
</div>
|
||||
{depth > 0 ? (
|
||||
<div className="mt-0.5 text-[10px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<div className="mt-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
Child task
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -332,13 +332,13 @@ function TaskTreeNode({
|
|||
{createdTask?.issueId ? (
|
||||
<Link
|
||||
to={`/issues/${createdTask.identifier ?? createdTask.issueId}`}
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-sm border border-emerald-500/50 bg-emerald-500/10 px-2.5 py-1 text-[11px] font-medium text-emerald-900 transition-colors hover:bg-emerald-500/15 dark:text-emerald-100"
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-sm border border-emerald-500/50 bg-emerald-500/10 px-2.5 py-1 text-(length:--fs-11) font-medium text-emerald-900 transition-colors hover:bg-emerald-500/15 dark:text-emerald-100"
|
||||
>
|
||||
{createdTask.identifier ?? createdTask.issueId.slice(0, 8)}
|
||||
<ChevronRight className="h-3 w-3" />
|
||||
</Link>
|
||||
) : isSkipped ? (
|
||||
<span className="inline-flex shrink-0 items-center rounded-sm border border-amber-500/60 bg-amber-500/10 px-2.5 py-1 text-[11px] font-medium text-amber-900 dark:text-amber-100">
|
||||
<span className="inline-flex shrink-0 items-center rounded-sm border border-amber-500/60 bg-amber-500/10 px-2.5 py-1 text-(length:--fs-11) font-medium text-amber-900 dark:text-amber-100">
|
||||
Skipped
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -540,7 +540,7 @@ function SuggestTasksCard({
|
|||
|
||||
{interaction.status === "accepted" ? (
|
||||
<div className="rounded-sm border border-emerald-500/60 bg-emerald-500/10 px-4 py-3 text-sm text-emerald-900 dark:text-emerald-100">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-emerald-700">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16) text-emerald-700">
|
||||
Resolution summary
|
||||
</div>
|
||||
<p className="mt-1 leading-6">
|
||||
|
|
@ -553,7 +553,7 @@ function SuggestTasksCard({
|
|||
|
||||
{interaction.status === "rejected" ? (
|
||||
<div className="rounded-sm border border-rose-500/60 bg-rose-500/10 px-4 py-3 text-sm text-rose-900 dark:text-rose-100">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-rose-700">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16) text-rose-700">
|
||||
Rejection reason
|
||||
</div>
|
||||
<p className={cn(
|
||||
|
|
@ -842,7 +842,7 @@ function AskUserQuestionsCard({
|
|||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<span className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2.5 py-1 font-medium uppercase tracking-[0.16em] text-foreground/70">
|
||||
<span className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2.5 py-1 font-medium uppercase tracking-(--ls-0_16) text-foreground/70">
|
||||
<MessageSquareQuote className="h-3 w-3" />
|
||||
Ask user questions
|
||||
</span>
|
||||
|
|
@ -862,7 +862,7 @@ function AskUserQuestionsCard({
|
|||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
Question {index + 1}
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -1031,7 +1031,7 @@ function AskUserQuestionsCard({
|
|||
|
||||
{interaction.result?.summaryMarkdown ? (
|
||||
<div className="rounded-2xl border border-emerald-300/60 bg-emerald-50/85 p-4">
|
||||
<div className="mb-2 text-[11px] font-semibold uppercase tracking-[0.16em] text-emerald-700">
|
||||
<div className="mb-2 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16) text-emerald-700">
|
||||
Submitted summary
|
||||
</div>
|
||||
<MarkdownBody externalReferences={externalReferences}>{interaction.result.summaryMarkdown}</MarkdownBody>
|
||||
|
|
@ -1080,7 +1080,7 @@ function RequestConfirmationTargetChip({
|
|||
|
||||
const href = requestConfirmationTargetHref({ interaction, target });
|
||||
const className = cn(
|
||||
"inline-flex max-w-full items-center gap-1.5 rounded-sm border px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.16em]",
|
||||
"inline-flex max-w-full items-center gap-1.5 rounded-sm border px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_16)",
|
||||
tone === "default"
|
||||
? "border-border/70 bg-transparent text-foreground"
|
||||
: "border-border/60 bg-transparent text-muted-foreground",
|
||||
|
|
@ -1147,7 +1147,7 @@ function RequestConfirmationResolution({
|
|||
const expiredByTargetChange = outcome === "stale_target";
|
||||
return (
|
||||
<div className="space-y-3 rounded-sm border border-amber-500/60 bg-amber-500/10 px-4 py-3 text-sm text-amber-900 dark:text-amber-100">
|
||||
<div className="text-[11px] font-semibold uppercase tracking-[0.16em] text-amber-700">
|
||||
<div className="text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16) text-amber-700">
|
||||
{expiredByComment ? "Expired by comment" : "Expired by target change"}
|
||||
</div>
|
||||
<p className="leading-6">
|
||||
|
|
@ -1497,7 +1497,7 @@ function RequestCheckboxConfirmationResolution({
|
|||
const hiddenCount = selectedLabels.length - CHECKBOX_SUMMARY_LABEL_LIMIT;
|
||||
const hasHiddenLabels = hiddenCount > 0;
|
||||
const chipClassName =
|
||||
"inline-flex items-center rounded-sm border border-border/60 bg-transparent px-2 py-0.5 text-[10px] font-medium uppercase tracking-[0.16em] text-muted-foreground";
|
||||
"inline-flex items-center rounded-sm border border-border/60 bg-transparent px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-(--ls-0_16) text-muted-foreground";
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
|
|
@ -1935,7 +1935,7 @@ export function IssueThreadInteractionCard({
|
|||
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||
<div className="min-w-0 flex-1 basis-64">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className={cn("inline-flex items-center gap-1 rounded-sm border px-2.5 py-1 text-[11px] font-semibold uppercase tracking-[0.16em]", styles.badge)}>
|
||||
<span className={cn("inline-flex items-center gap-1 rounded-sm border px-2.5 py-1 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_16)", styles.badge)}>
|
||||
<StatusIcon className="h-3.5 w-3.5" />
|
||||
{isPlan ? "Plan" : interactionKindLabel(interaction.kind)}
|
||||
<span className="text-current/60">/</span>
|
||||
|
|
@ -1943,7 +1943,7 @@ export function IssueThreadInteractionCard({
|
|||
</span>
|
||||
{interaction.continuationPolicy === "wake_assignee"
|
||||
|| interaction.continuationPolicy === "wake_assignee_on_accept" ? (
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-border/70 bg-transparent px-2.5 py-1 text-[11px] font-medium uppercase tracking-[0.16em] text-foreground/70">
|
||||
<span className="inline-flex items-center gap-1 rounded-sm border border-border/70 bg-transparent px-2.5 py-1 text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_16) text-foreground/70">
|
||||
<ListChecks className="h-3.5 w-3.5" />
|
||||
{interaction.continuationPolicy === "wake_assignee_on_accept"
|
||||
? "Wakes on confirm"
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ function statusBadge(status: string) {
|
|||
archived: "bg-muted text-muted-foreground",
|
||||
};
|
||||
return (
|
||||
<span className={cn("text-[10px] px-1.5 py-0.5 rounded-full font-medium", colors[status] ?? colors.idle)}>
|
||||
<span className={cn("text-(length:--fs-10) px-1.5 py-0.5 rounded-full font-medium", colors[status] ?? colors.idle)}>
|
||||
{status.replace(/_/g, " ")}
|
||||
</span>
|
||||
);
|
||||
|
|
@ -405,7 +405,7 @@ export function IssueWorkspaceCard({
|
|||
)}
|
||||
{workspace?.repoUrl && (
|
||||
<div className="flex items-center gap-1.5 text-muted-foreground">
|
||||
<span className="text-[11px]">Repo:</span>
|
||||
<span className="text-(length:--fs-11)">Repo:</span>
|
||||
<CopyableInline value={workspace.repoUrl} mono />
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -447,7 +447,7 @@ export function IssueWorkspaceCard({
|
|||
<div className="pt-0.5">
|
||||
<Link
|
||||
to={currentWorkspaceLink}
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground hover:underline"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground hover:underline"
|
||||
>
|
||||
View workspace details →
|
||||
</Link>
|
||||
|
|
@ -493,7 +493,7 @@ export function IssueWorkspaceCard({
|
|||
|
||||
{/* Current workspace summary when editing */}
|
||||
{workspace && (
|
||||
<div className="text-[11px] text-muted-foreground space-y-0.5 pt-1 border-t border-border/50">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground space-y-0.5 pt-1 border-t border-border/50">
|
||||
<div style={{ overflowWrap: "anywhere" }}>
|
||||
Current:{" "}
|
||||
{currentWorkspaceLink ? (
|
||||
|
|
|
|||
|
|
@ -1763,7 +1763,7 @@ export function IssuesList({
|
|||
target.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
target.focus?.();
|
||||
}}
|
||||
className="inline-flex items-center rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 hover:bg-amber-100/80 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
className="inline-flex items-center rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-(length:--fs-10) font-medium text-amber-700 hover:bg-amber-100/80 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
title={firstVisibleBlockerTitle}
|
||||
aria-label={firstVisibleBlockerTitle}
|
||||
>
|
||||
|
|
@ -1803,7 +1803,7 @@ export function IssuesList({
|
|||
{issueBadge ? (
|
||||
issueBadge === "Paused" ? (
|
||||
<span
|
||||
className={cn("ml-1.5 inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px] font-medium", statusBadge.paused)}
|
||||
className={cn("ml-1.5 inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-(length:--fs-10) font-medium", statusBadge.paused)}
|
||||
aria-label="Paused"
|
||||
title="Paused"
|
||||
>
|
||||
|
|
@ -1811,14 +1811,14 @@ export function IssuesList({
|
|||
Paused
|
||||
</span>
|
||||
) : (
|
||||
<span className="ml-1.5 inline-flex items-center rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 dark:text-amber-300">
|
||||
<span className="ml-1.5 inline-flex items-center rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 py-0.5 text-(length:--fs-10) font-medium text-amber-700 dark:text-amber-300">
|
||||
{issueBadge}
|
||||
</span>
|
||||
)
|
||||
) : null}
|
||||
{isSuccessfulRunHandoffRequired(issue) ? (
|
||||
<span
|
||||
className="ml-1.5 inline-flex items-center gap-1 rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
className="ml-1.5 inline-flex items-center gap-1 rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-(length:--fs-10) font-medium text-amber-700 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
aria-label="Needs next step"
|
||||
title="This task needs a next step"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -363,12 +363,12 @@ const FieldWrapper = React.memo(({
|
|||
</div>
|
||||
{children}
|
||||
{description && (
|
||||
<p className="text-[12px] text-muted-foreground leading-relaxed">
|
||||
<p className="text-(length:--fs-12) text-muted-foreground leading-relaxed">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
{error && (
|
||||
<p className="text-[12px] font-medium text-destructive">{error}</p>
|
||||
<p className="text-(length:--fs-12) font-medium text-destructive">{error}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
|
@ -695,7 +695,7 @@ const SecretField = React.memo(({
|
|||
{!hasRawValue ? (
|
||||
<button
|
||||
type="button"
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground"
|
||||
onClick={() => {
|
||||
setShowRawInput(false);
|
||||
setIsVisible(false);
|
||||
|
|
@ -709,7 +709,7 @@ const SecretField = React.memo(({
|
|||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground"
|
||||
onClick={() => setShowRawInput(true)}
|
||||
disabled={disabled}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -160,10 +160,10 @@ function KanbanColumn({
|
|||
title={`${statusLabel(status)}: ${issues.length}`}
|
||||
>
|
||||
<StatusIcon status={status} />
|
||||
<span className={cn("mt-2 [writing-mode:vertical-rl] rotate-180 text-[10px] font-semibold uppercase tracking-wide", tone.header)}>
|
||||
<span className={cn("mt-2 [writing-mode:vertical-rl] rotate-180 text-(length:--fs-10) font-semibold uppercase tracking-wide", tone.header)}>
|
||||
{statusLabel(status)}
|
||||
</span>
|
||||
<span className={cn("mt-auto rounded-full bg-background px-1.5 py-0.5 text-[10px] font-medium tabular-nums", tone.header)}>
|
||||
<span className={cn("mt-auto rounded-full bg-background px-1.5 py-0.5 text-(length:--fs-10) font-medium tabular-nums", tone.header)}>
|
||||
{issues.length}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -219,7 +219,7 @@ function KanbanColumn({
|
|||
</button>
|
||||
) : null}
|
||||
{issues.length > 0 && (hiddenCount > 0 || issues.length >= visibleCount) ? (
|
||||
<p className="px-1 pt-1 text-[11px] text-muted-foreground">
|
||||
<p className="px-1 pt-1 text-(length:--fs-11) text-muted-foreground">
|
||||
Showing {visibleIssues.length} of {issues.length}
|
||||
</p>
|
||||
) : null}
|
||||
|
|
@ -295,7 +295,7 @@ function KanbanCard({
|
|||
</span>
|
||||
{isSuccessfulRunHandoffRequired(issue) ? (
|
||||
<span
|
||||
className="inline-flex items-center gap-1 rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-[10px] font-medium text-amber-700 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-amber-400/45 bg-amber-50/60 px-1.5 py-0.5 text-(length:--fs-10) font-medium text-amber-700 dark:border-amber-300/35 dark:bg-amber-400/10 dark:text-amber-300"
|
||||
title="This task needs a next step"
|
||||
aria-label="Needs next step"
|
||||
>
|
||||
|
|
@ -304,7 +304,7 @@ function KanbanCard({
|
|||
</span>
|
||||
) : null}
|
||||
{isLive && (
|
||||
<span className="inline-flex shrink-0 items-center gap-1 text-[10px] font-medium text-blue-600 dark:text-blue-400">
|
||||
<span className="inline-flex shrink-0 items-center gap-1 text-(length:--fs-10) font-medium text-blue-600 dark:text-blue-400">
|
||||
<span className="relative flex h-2 w-2">
|
||||
<span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
|
||||
|
|
@ -314,7 +314,7 @@ function KanbanCard({
|
|||
)}
|
||||
{!isLive && subtreeLiveCount > 0 && (
|
||||
<span
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-full border border-border px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground"
|
||||
className="inline-flex shrink-0 items-center gap-1 rounded-full border border-border px-1.5 py-0.5 text-(length:--fs-10) font-medium text-muted-foreground"
|
||||
title={`${subtreeLiveCount} sub-task${subtreeLiveCount === 1 ? "" : "s"} running below`}
|
||||
>
|
||||
<span className="h-2 w-2 shrink-0 rounded-full border border-muted-foreground/60" aria-hidden="true" />
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export function KeyboardShortcutsCheatsheetContent() {
|
|||
<div className="divide-y divide-border border-t border-border">
|
||||
{sections.map((section) => (
|
||||
<div key={section.title} className="px-5 py-3">
|
||||
<h3 className="mb-2 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
<h3 className="mb-2 text-(length:--fs-11) font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{section.title}
|
||||
</h3>
|
||||
<div className="space-y-1.5">
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) {
|
|||
return (
|
||||
<div className="overflow-hidden rounded-xl border border-cyan-500/25 bg-background/80 shadow-[0_18px_50px_rgba(6,182,212,0.08)]">
|
||||
<div className="border-b border-border/60 bg-cyan-500/[0.04] px-4 py-3">
|
||||
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-cyan-700 dark:text-cyan-300">
|
||||
<div className="text-xs font-semibold uppercase tracking-(--ls-0_18) text-cyan-700 dark:text-cyan-300">
|
||||
Live Runs
|
||||
</div>
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
|
|
@ -127,7 +127,7 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) {
|
|||
<button
|
||||
onClick={() => handleCancelRun(run.id)}
|
||||
disabled={cancellingRunIds.has(run.id)}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-red-500/20 bg-red-500/[0.06] px-2.5 py-1 text-[11px] font-medium text-red-700 transition-colors hover:bg-red-500/[0.12] dark:text-red-300 disabled:opacity-50"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-red-500/20 bg-red-500/[0.06] px-2.5 py-1 text-(length:--fs-11) font-medium text-red-700 transition-colors hover:bg-red-500/[0.12] dark:text-red-300 disabled:opacity-50"
|
||||
>
|
||||
<Square className="h-2.5 w-2.5" fill="currentColor" />
|
||||
{cancellingRunIds.has(run.id) ? "Stopping…" : "Stop"}
|
||||
|
|
@ -135,7 +135,7 @@ export function LiveRunWidget({ issueId, companyId }: LiveRunWidgetProps) {
|
|||
)}
|
||||
<Link
|
||||
to={`/agents/${run.agentId}/runs/${run.id}`}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2.5 py-1 text-[11px] font-medium text-cyan-700 transition-colors hover:border-cyan-500/30 hover:text-cyan-600 dark:text-cyan-300"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border/70 bg-background/70 px-2.5 py-1 text-(length:--fs-11) font-medium text-cyan-700 transition-colors hover:border-cyan-500/30 hover:text-cyan-600 dark:text-cyan-300"
|
||||
>
|
||||
Open run
|
||||
<ExternalLink className="h-3 w-3" />
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@ const codeBlockActionStyle: React.CSSProperties = {
|
|||
border: "1px solid color-mix(in oklab, var(--foreground) 14%, transparent)",
|
||||
backgroundColor: "color-mix(in oklab, var(--muted) 92%, var(--background) 8%)",
|
||||
color: "var(--muted-foreground)",
|
||||
fontSize: "0.7rem",
|
||||
fontSize: "var(--fs-0_7rem)",
|
||||
lineHeight: 1,
|
||||
cursor: "pointer",
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1364,7 +1364,7 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
|
|||
)}
|
||||
{option.kind === "issue" && option.issueIdentifier ? (
|
||||
<span className="flex min-w-0 items-baseline gap-1.5">
|
||||
<span className="shrink-0 font-mono text-[11px] text-muted-foreground">
|
||||
<span className="shrink-0 font-mono text-(length:--fs-11) text-muted-foreground">
|
||||
{option.issueIdentifier}
|
||||
</span>
|
||||
<span className="truncate">{issueMentionTitle(option)}</span>
|
||||
|
|
@ -1377,27 +1377,27 @@ export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>
|
|||
</span>
|
||||
)}
|
||||
{option.kind === "issue" && (
|
||||
<span className="ml-auto text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<span className="ml-auto text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
Task
|
||||
</span>
|
||||
)}
|
||||
{option.kind === "project" && option.projectId && (
|
||||
<span className="ml-auto text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<span className="ml-auto text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
Project
|
||||
</span>
|
||||
)}
|
||||
{option.kind === "user" && (
|
||||
<span className="ml-auto text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<span className="ml-auto text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
User
|
||||
</span>
|
||||
)}
|
||||
{option.kind === "skill" && (
|
||||
<span className="ml-auto text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<span className="ml-auto text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
Skill
|
||||
</span>
|
||||
)}
|
||||
{option.kind === "routine" && (
|
||||
<span className="ml-auto text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<span className="ml-auto text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
Routine
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export function MobileBottomNav({ visible }: MobileBottomNavProps) {
|
|||
type="button"
|
||||
onClick={item.onClick}
|
||||
className={cn(
|
||||
"relative flex min-w-0 flex-col items-center justify-center gap-1 rounded-md text-[10px] font-medium transition-colors",
|
||||
"relative flex min-w-0 flex-col items-center justify-center gap-1 rounded-md text-(length:--fs-10) font-medium transition-colors",
|
||||
active
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
@ -96,7 +96,7 @@ export function MobileBottomNav({ visible }: MobileBottomNavProps) {
|
|||
state={SIDEBAR_SCROLL_RESET_STATE}
|
||||
className={({ isActive }) =>
|
||||
cn(
|
||||
"relative flex min-w-0 flex-col items-center justify-center gap-1 rounded-md text-[10px] font-medium transition-colors",
|
||||
"relative flex min-w-0 flex-col items-center justify-center gap-1 rounded-md text-(length:--fs-10) font-medium transition-colors",
|
||||
isActive
|
||||
? "text-foreground"
|
||||
: "text-muted-foreground hover:text-foreground",
|
||||
|
|
@ -108,7 +108,7 @@ export function MobileBottomNav({ visible }: MobileBottomNavProps) {
|
|||
<span className="relative">
|
||||
<Icon className={cn("h-[18px] w-[18px]", isActive && "stroke-[2.3]")} />
|
||||
{item.badge != null && item.badge > 0 && (
|
||||
<span className="absolute -right-2 -top-2 rounded-full bg-primary px-1.5 py-0.5 text-[10px] leading-none text-primary-foreground">
|
||||
<span className="absolute -right-2 -top-2 rounded-full bg-primary px-1.5 py-0.5 text-(length:--fs-10) leading-none text-primary-foreground">
|
||||
{item.badge > 99 ? "99+" : item.badge}
|
||||
</span>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -311,13 +311,13 @@ export function NewAgentDialog() {
|
|||
}}
|
||||
>
|
||||
{opt.recommended && (
|
||||
<span className="absolute -top-1.5 right-1.5 bg-green-500 text-white text-[9px] font-semibold px-1.5 py-0.5 rounded-full leading-none">
|
||||
<span className="absolute -top-1.5 right-1.5 bg-green-500 text-white text-(length:--fs-9) font-semibold px-1.5 py-0.5 rounded-full leading-none">
|
||||
Recommended
|
||||
</span>
|
||||
)}
|
||||
<opt.icon className="h-4 w-4" />
|
||||
<span className="font-medium">{opt.label}</span>
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
<span className="text-muted-foreground text-(length:--fs-10)">
|
||||
{opt.desc}
|
||||
</span>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1334,7 +1334,7 @@ export function NewIssueDialog() {
|
|||
>
|
||||
<span
|
||||
className={cn(
|
||||
"px-1 py-0.5 rounded text-[10px] font-semibold leading-none",
|
||||
"px-1 py-0.5 rounded text-(length:--fs-10) font-semibold leading-none",
|
||||
!c.brandColor && "bg-muted",
|
||||
)}
|
||||
style={
|
||||
|
|
@ -1779,7 +1779,7 @@ export function NewIssueDialog() {
|
|||
<div className="px-4 py-3 space-y-2">
|
||||
<div className="space-y-1.5">
|
||||
<div className="text-xs font-medium">Execution workspace</div>
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
Control whether this task runs in the shared workspace, a new isolated workspace, or an existing one.
|
||||
</div>
|
||||
<select
|
||||
|
|
@ -1809,12 +1809,12 @@ export function NewIssueDialog() {
|
|||
/>
|
||||
)}
|
||||
{executionWorkspaceMode === "reuse_existing" && selectedReusableExecutionWorkspace && (
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
Reusing {selectedReusableExecutionWorkspace.name} from {selectedReusableExecutionWorkspace.branchName ?? selectedReusableExecutionWorkspace.cwd ?? "existing execution workspace"}.
|
||||
</div>
|
||||
)}
|
||||
{showParentWorkspaceWarning ? (
|
||||
<div className="rounded-md border border-amber-300/60 bg-amber-50 px-2 py-1.5 text-[11px] text-amber-900 dark:border-amber-800/70 dark:bg-amber-950/30 dark:text-amber-100">
|
||||
<div className="rounded-md border border-amber-300/60 bg-amber-50 px-2 py-1.5 text-(length:--fs-11) text-amber-900 dark:border-amber-800/70 dark:bg-amber-950/30 dark:text-amber-100">
|
||||
Warning: this sub-task will no longer use the parent task workspace{parentExecutionWorkspaceLabel ? ` (${parentExecutionWorkspaceLabel})` : ""}.
|
||||
</div>
|
||||
) : null}
|
||||
|
|
@ -1861,7 +1861,7 @@ export function NewIssueDialog() {
|
|||
))}
|
||||
</div>
|
||||
{assigneeModelLane === "cheap" && (
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
Sends <code>modelProfile: "cheap"</code>{" "}
|
||||
{assigneeCheapProfile?.adapterConfig && typeof (assigneeCheapProfile.adapterConfig as Record<string, unknown>).model === "string"
|
||||
? <>· adapter default <code>{String((assigneeCheapProfile.adapterConfig as Record<string, unknown>).model)}</code></>
|
||||
|
|
@ -1871,10 +1871,10 @@ export function NewIssueDialog() {
|
|||
</p>
|
||||
)}
|
||||
{assigneeModelLane === "primary" && (
|
||||
<p className="text-[11px] text-muted-foreground">Runs on the agent's primary model.</p>
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">Runs on the agent's primary model.</p>
|
||||
)}
|
||||
{assigneeModelLane === "custom" && (
|
||||
<p className="text-[11px] text-muted-foreground">Override the model and effort for this task only.</p>
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">Override the model and effort for this task only.</p>
|
||||
)}
|
||||
</div>
|
||||
{assigneeModelLane === "custom" && (
|
||||
|
|
@ -1958,12 +1958,12 @@ export function NewIssueDialog() {
|
|||
<div key={file.id} className="flex items-start justify-between gap-3 rounded-md border border-border/70 px-3 py-2">
|
||||
<div className="min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="rounded-full border border-border px-2 py-0.5 font-mono text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="rounded-full border border-border px-2 py-0.5 font-mono text-(length:--fs-10) uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{file.documentKey}
|
||||
</span>
|
||||
<span className="truncate text-sm">{file.file.name}</span>
|
||||
</div>
|
||||
<div className="mt-1 flex items-center gap-2 text-[11px] text-muted-foreground">
|
||||
<div className="mt-1 flex items-center gap-2 text-(length:--fs-11) text-muted-foreground">
|
||||
<FileText className="h-3.5 w-3.5" />
|
||||
<span>{file.title || file.file.name}</span>
|
||||
<span>•</span>
|
||||
|
|
@ -1997,7 +1997,7 @@ export function NewIssueDialog() {
|
|||
<Paperclip className="h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<span className="truncate text-sm">{file.file.name}</span>
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] text-muted-foreground">
|
||||
<div className="mt-1 text-(length:--fs-11) text-muted-foreground">
|
||||
{file.file.type || "application/octet-stream"} • {formatFileSize(file.file)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -2045,7 +2045,7 @@ export function NewIssueDialog() {
|
|||
<span className="flex flex-col text-left leading-tight">
|
||||
<span>{s.label}</span>
|
||||
{s.description ? (
|
||||
<span className="text-[10px] text-muted-foreground">{s.description}</span>
|
||||
<span className="text-(length:--fs-10) text-muted-foreground">{s.description}</span>
|
||||
) : null}
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -2169,7 +2169,7 @@ export function NewIssueDialog() {
|
|||
</PopoverTrigger>
|
||||
<PopoverContent className="w-44 p-1" align="start" data-testid="new-issue-more-menu">
|
||||
<div className="sm:hidden">
|
||||
<div className="px-2 py-1 text-[10px] font-medium uppercase text-muted-foreground">
|
||||
<div className="px-2 py-1 text-(length:--fs-10) font-medium uppercase text-muted-foreground">
|
||||
Priority
|
||||
</div>
|
||||
{priorities.map((p) => (
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ export function OnboardingChat({
|
|||
<div className="flex items-center gap-1.5 mb-1">
|
||||
<span
|
||||
className={cn(
|
||||
"text-[10px] font-medium uppercase tracking-wide",
|
||||
"text-(length:--fs-10) font-medium uppercase tracking-wide",
|
||||
isAgent
|
||||
? "text-muted-foreground"
|
||||
: "text-foreground/70",
|
||||
|
|
@ -299,7 +299,7 @@ export function OnboardingChat({
|
|||
{isAgent ? agentName : "You"}
|
||||
</span>
|
||||
{isPlan && (
|
||||
<span className="inline-flex items-center gap-0.5 text-[10px] text-green-600 dark:text-green-400 font-medium">
|
||||
<span className="inline-flex items-center gap-0.5 text-(length:--fs-10) text-green-600 dark:text-green-400 font-medium">
|
||||
<CheckCircle2 className="h-3 w-3" />
|
||||
Hiring plan detected
|
||||
</span>
|
||||
|
|
@ -335,7 +335,7 @@ export function OnboardingChat({
|
|||
</>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-[11px] text-muted-foreground/60 tabular-nums shrink-0">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground/60 tabular-nums shrink-0">
|
||||
{elapsedStr}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -352,7 +352,7 @@ export function OnboardingChat({
|
|||
<p className="text-sm font-medium">
|
||||
{agentName} has prepared a hiring plan
|
||||
</p>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
Review it, make edits, then approve.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -427,7 +427,7 @@ function WelcomeMessage({
|
|||
{showMessage && (
|
||||
<div className="rounded-md px-3 py-2 text-sm bg-muted/50 border border-border mr-8 animate-in fade-in duration-300">
|
||||
<div className="flex items-center gap-1.5 mb-1">
|
||||
<span className="text-[10px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
<span className="text-(length:--fs-10) font-medium uppercase tracking-wide text-muted-foreground">
|
||||
{agentName}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -859,7 +859,7 @@ export function OnboardingWizard() {
|
|||
glow="blue"
|
||||
size="md"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
{step === 3 ? (
|
||||
"an empty slot for an agent"
|
||||
) : step === 4 ? (
|
||||
|
|
@ -954,7 +954,7 @@ export function OnboardingWizard() {
|
|||
</>
|
||||
)}
|
||||
<button
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground transition-colors"
|
||||
onClick={() => { setOnboardingPath(null); setStep(0); }}
|
||||
>
|
||||
← Back to start
|
||||
|
|
@ -1003,7 +1003,7 @@ export function OnboardingWizard() {
|
|||
/>
|
||||
</div>
|
||||
<button
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground transition-colors"
|
||||
onClick={() => { setOnboardingPath(null); setStep(0); }}
|
||||
>
|
||||
← Back to start
|
||||
|
|
@ -1043,7 +1043,7 @@ export function OnboardingWizard() {
|
|||
>
|
||||
<Sparkles className="h-4 w-4" />
|
||||
<span className="font-medium">I know my mission</span>
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
<span className="text-muted-foreground text-(length:--fs-10)">
|
||||
Type it directly
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1058,7 +1058,7 @@ export function OnboardingWizard() {
|
|||
>
|
||||
<ListTodo className="h-4 w-4" />
|
||||
<span className="font-medium">Help me figure it out</span>
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
<span className="text-muted-foreground text-(length:--fs-10)">
|
||||
Answer a few questions
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1093,7 +1093,7 @@ export function OnboardingWizard() {
|
|||
<button
|
||||
key={chip}
|
||||
className={cn(
|
||||
"rounded-full border px-2.5 py-1 text-[11px] transition-colors",
|
||||
"rounded-full border px-2.5 py-1 text-(length:--fs-11) transition-colors",
|
||||
companyGoal === chip
|
||||
? "border-foreground bg-accent text-foreground"
|
||||
: "border-border text-muted-foreground hover:text-foreground hover:border-foreground/50"
|
||||
|
|
@ -1185,7 +1185,7 @@ export function OnboardingWizard() {
|
|||
/>
|
||||
</div>
|
||||
<button
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground transition-colors"
|
||||
onClick={() => { setMissionConfirmed(false); setCompanyGoal(""); }}
|
||||
>
|
||||
← Back to questions
|
||||
|
|
@ -1195,13 +1195,13 @@ export function OnboardingWizard() {
|
|||
|
||||
{/* Confirm mission note */}
|
||||
{companyGoal.trim() && (
|
||||
<p className="text-[11px] text-muted-foreground italic">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground italic">
|
||||
You can always change your mission later in settings.
|
||||
</p>
|
||||
)}
|
||||
|
||||
<button
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground transition-colors"
|
||||
onClick={() => setStep(1)}
|
||||
>
|
||||
← Change company name
|
||||
|
|
@ -1265,13 +1265,13 @@ export function OnboardingWizard() {
|
|||
}}
|
||||
>
|
||||
{opt.recommended && (
|
||||
<span className="absolute -top-1.5 right-1.5 bg-green-500 text-white text-[9px] font-semibold px-1.5 py-0.5 rounded-full leading-none">
|
||||
<span className="absolute -top-1.5 right-1.5 bg-green-500 text-white text-(length:--fs-9) font-semibold px-1.5 py-0.5 rounded-full leading-none">
|
||||
Recommended
|
||||
</span>
|
||||
)}
|
||||
<opt.icon className="h-4 w-4" />
|
||||
<span className="font-medium">{opt.label}</span>
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
<span className="text-muted-foreground text-(length:--fs-10)">
|
||||
{opt.description}
|
||||
</span>
|
||||
</button>
|
||||
|
|
@ -1326,7 +1326,7 @@ export function OnboardingWizard() {
|
|||
>
|
||||
<opt.icon className="h-4 w-4" />
|
||||
<span className="font-medium">{opt.label}</span>
|
||||
<span className="text-muted-foreground text-[10px]">
|
||||
<span className="text-muted-foreground text-(length:--fs-10)">
|
||||
{opt.comingSoon
|
||||
? opt.disabledLabel ?? "Coming soon"
|
||||
: opt.description}
|
||||
|
|
@ -1400,7 +1400,7 @@ export function OnboardingWizard() {
|
|||
className="mb-1 last:mb-0"
|
||||
>
|
||||
{adapterType === "opencode_local" && (
|
||||
<div className="px-2 py-1 text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
<div className="px-2 py-1 text-(length:--fs-10) uppercase tracking-wide text-muted-foreground">
|
||||
{group.provider} ({group.entries.length})
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -1447,7 +1447,7 @@ export function OnboardingWizard() {
|
|||
<p className="text-xs font-medium">
|
||||
Adapter environment check
|
||||
</p>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
Runs a live probe that asks the adapter CLI to
|
||||
respond with hello.
|
||||
</p>
|
||||
|
|
@ -1464,7 +1464,7 @@ export function OnboardingWizard() {
|
|||
</div>
|
||||
|
||||
{adapterEnvError && (
|
||||
<div className="rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-2 text-[11px] text-destructive">
|
||||
<div className="rounded-md border border-destructive/30 bg-destructive/10 px-2.5 py-2 text-(length:--fs-11) text-destructive">
|
||||
{adapterEnvError}
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -1481,7 +1481,7 @@ export function OnboardingWizard() {
|
|||
|
||||
{shouldSuggestUnsetAnthropicApiKey && (
|
||||
<div className="rounded-md border border-amber-300/60 bg-amber-50/40 px-2.5 py-2 space-y-2">
|
||||
<p className="text-[11px] text-amber-900/90 leading-relaxed">
|
||||
<p className="text-(length:--fs-11) text-amber-900/90 leading-relaxed">
|
||||
Claude failed while{" "}
|
||||
<span className="font-mono">ANTHROPIC_API_KEY</span>{" "}
|
||||
is set. You can clear it in this adapter config
|
||||
|
|
@ -1504,7 +1504,7 @@ export function OnboardingWizard() {
|
|||
)}
|
||||
|
||||
{adapterEnvResult && adapterEnvResult.status === "fail" && (
|
||||
<div className="rounded-md border border-border/70 bg-muted/20 px-2.5 py-2 text-[11px] space-y-1.5">
|
||||
<div className="rounded-md border border-border/70 bg-muted/20 px-2.5 py-2 text-(length:--fs-11) space-y-1.5">
|
||||
<p className="font-medium">Manual debug</p>
|
||||
<p className="text-muted-foreground font-mono break-all">
|
||||
{adapterType === "cursor"
|
||||
|
|
@ -1750,7 +1750,7 @@ function AdapterEnvironmentResult({
|
|||
: "text-red-700 dark:text-red-300 border-red-300 dark:border-red-500/40 bg-red-50 dark:bg-red-500/10";
|
||||
|
||||
return (
|
||||
<div className={`rounded-md border px-2.5 py-2 text-[11px] ${statusClass}`}>
|
||||
<div className={`rounded-md border px-2.5 py-2 text-(length:--fs-11) ${statusClass}`}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="font-medium">{statusLabel}</span>
|
||||
<span className="opacity-80">
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ export function PipelineItemBodyDocument({
|
|||
[conversationIssueId, doc?.latestRevisionId, latestBody, onStartConversation, pushToast, saveMutation],
|
||||
);
|
||||
|
||||
const bodyContentClassName = "paperclip-edit-in-place-content min-h-[220px] text-[15px] leading-7";
|
||||
const bodyContentClassName = "paperclip-edit-in-place-content min-h-[220px] text-(length:--fs-15) leading-7";
|
||||
|
||||
const renderReadOnlyBody = (body: string) => (
|
||||
<FoldCurtain className="max-w-3xl">
|
||||
|
|
@ -276,7 +276,7 @@ export function PipelineItemBodyDocument({
|
|||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-wrap items-center justify-between gap-2">
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">
|
||||
Saving creates rev {(doc?.latestRevisionNumber ?? 0) + 1} · ⌘↵ to save · Esc to cancel
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
|
|
@ -415,7 +415,7 @@ export function PipelineItemBodyDocument({
|
|||
/>
|
||||
) : null}
|
||||
actionsSlot={editing ? (
|
||||
<span className="text-[11px] font-medium text-amber-300">● Editing · unsaved</span>
|
||||
<span className="text-(length:--fs-11) font-medium text-amber-300">● Editing · unsaved</span>
|
||||
) : (
|
||||
<Button variant="ghost" size="sm" className="h-auto gap-1.5 px-2 py-1 text-xs" onClick={beginEdit}>
|
||||
<FilePenLine className="h-3.5 w-3.5" />
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ export function PipelineStageHistoryPanel({
|
|||
<p className="text-sm font-medium">
|
||||
Revision {revision.revisionNumber}
|
||||
{isCurrent ? (
|
||||
<span className="ml-2 rounded-full bg-muted px-2 py-0.5 text-[11px] font-medium text-muted-foreground">
|
||||
<span className="ml-2 rounded-full bg-muted px-2 py-0.5 text-(length:--fs-11) font-medium text-muted-foreground">
|
||||
Current
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export function ProductivityReviewBadge({
|
|||
<Link
|
||||
to={reviewPath}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 rounded-full border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-[10px] font-medium text-amber-700 dark:text-amber-300 shrink-0 hover:bg-amber-500/20 transition-colors",
|
||||
"inline-flex items-center gap-1 rounded-full border border-amber-500/40 bg-amber-500/10 px-2 py-0.5 text-(length:--fs-10) font-medium text-amber-700 dark:text-amber-300 shrink-0 hover:bg-amber-500/20 transition-colors",
|
||||
className,
|
||||
)}
|
||||
aria-label={`Under review · productivity review ${reviewIdentifier} (${label})`}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export type ProjectConfigFieldKey =
|
|||
function SaveIndicator({ state }: { state: ProjectFieldSaveState }) {
|
||||
if (state === "saving") {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] text-muted-foreground">
|
||||
<span className="inline-flex items-center gap-1 text-(length:--fs-11) text-muted-foreground">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
Saving
|
||||
</span>
|
||||
|
|
@ -67,7 +67,7 @@ function SaveIndicator({ state }: { state: ProjectFieldSaveState }) {
|
|||
}
|
||||
if (state === "saved") {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] text-green-600 dark:text-green-400">
|
||||
<span className="inline-flex items-center gap-1 text-(length:--fs-11) text-green-600 dark:text-green-400">
|
||||
<Check className="h-3 w-3" />
|
||||
Saved
|
||||
</span>
|
||||
|
|
@ -75,7 +75,7 @@ function SaveIndicator({ state }: { state: ProjectFieldSaveState }) {
|
|||
}
|
||||
if (state === "error") {
|
||||
return (
|
||||
<span className="inline-flex items-center gap-1 text-[11px] text-destructive">
|
||||
<span className="inline-flex items-center gap-1 text-(length:--fs-11) text-destructive">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
Failed
|
||||
</span>
|
||||
|
|
@ -641,7 +641,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
}}
|
||||
onChange={(env) => commitField("env", { env: env ?? null })}
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
Applied to all runs for tasks in this project. Project values override agent env on key conflicts.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -669,7 +669,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded-full border border-border text-[10px] text-muted-foreground hover:text-foreground"
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded-full border border-border text-(length:--fs-10) text-muted-foreground hover:text-foreground"
|
||||
aria-label="Codebase help"
|
||||
>
|
||||
?
|
||||
|
|
@ -682,7 +682,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
</div>
|
||||
<div className="space-y-2 rounded-md border border-border/70 p-3">
|
||||
<div className="space-y-1">
|
||||
<div className="text-[11px] uppercase tracking-wide text-muted-foreground">Repo</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">Repo</div>
|
||||
{codebase.repoUrl ? (
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{isSafeExternalUrl(codebase.repoUrl) ? (
|
||||
|
|
@ -745,14 +745,14 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<div className="text-[11px] uppercase tracking-wide text-muted-foreground">Local folder</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">Local folder</div>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="min-w-0 break-all font-mono text-xs text-muted-foreground">
|
||||
{codebase.effectiveLocalFolder}
|
||||
</div>
|
||||
{codebase.origin === "managed_checkout" && (
|
||||
<div className="text-[11px] text-muted-foreground">Paperclip-managed folder.</div>
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">Paperclip-managed folder.</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-1">
|
||||
|
|
@ -783,7 +783,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
</div>
|
||||
|
||||
{hasAdditionalLegacyWorkspaces && (
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
Additional legacy workspace records exist on this project. Paperclip is using the primary workspace as the codebase view.
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -797,10 +797,10 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
>
|
||||
<div className="min-w-0 space-y-0.5">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[11px] font-medium">{service.serviceName}</span>
|
||||
<span className="text-(length:--fs-11) font-medium">{service.serviceName}</span>
|
||||
<span
|
||||
className={cn(
|
||||
"rounded-full px-1.5 py-0.5 text-[10px] uppercase tracking-wide",
|
||||
"rounded-full px-1.5 py-0.5 text-(length:--fs-10) uppercase tracking-wide",
|
||||
service.status === "running"
|
||||
? "bg-green-500/15 text-green-700 dark:text-green-300"
|
||||
: service.status === "failed"
|
||||
|
|
@ -811,7 +811,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
{service.status}
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
{service.url ? (
|
||||
<a
|
||||
href={service.url}
|
||||
|
|
@ -826,7 +826,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-[10px] text-muted-foreground whitespace-nowrap">
|
||||
<div className="text-(length:--fs-10) text-muted-foreground whitespace-nowrap">
|
||||
{service.lifecycle}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -928,7 +928,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
<TooltipTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded-full border border-border text-[10px] text-muted-foreground hover:text-foreground"
|
||||
className="inline-flex h-4 w-4 items-center justify-center rounded-full border border-border text-(length:--fs-10) text-muted-foreground hover:text-foreground"
|
||||
aria-label="Execution workspaces help"
|
||||
>
|
||||
?
|
||||
|
|
@ -974,7 +974,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
<span>New tasks default to isolated checkout</span>
|
||||
<SaveIndicator state={fieldState("execution_workspace_default_mode")} />
|
||||
</div>
|
||||
<div className="text-[11px] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) text-muted-foreground">
|
||||
If disabled, new tasks stay on the project's primary checkout unless someone opts in.
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1158,7 +1158,7 @@ export function ProjectProperties({ project, onUpdate, onFieldUpdate, getFieldSa
|
|||
placeholder="bash ./scripts/teardown-worktree.sh"
|
||||
/>
|
||||
</div>
|
||||
<p className="text-[11px] text-muted-foreground">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">
|
||||
Provision runs inside the derived worktree before agent execution. Teardown is stored here for
|
||||
future cleanup flows.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export function ProjectWorkspaceSummaryCard({
|
|||
<div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
|
||||
<div className="min-w-0 space-y-2">
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span className="inline-flex items-center rounded-full border border-border bg-background px-2.5 py-1 text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<span className="inline-flex items-center rounded-full border border-border bg-background px-2.5 py-1 text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
{workspaceKindLabel(summary.kind)}
|
||||
</span>
|
||||
<span className="inline-flex items-center rounded-full border border-border/70 bg-background px-2.5 py-1 text-xs text-muted-foreground">
|
||||
|
|
@ -149,7 +149,7 @@ export function ProjectWorkspaceSummaryCard({
|
|||
<div className="flex items-start gap-2">
|
||||
<GitBranch className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">Branch</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">Branch</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<CopyText
|
||||
text={summary.branchName}
|
||||
|
|
@ -176,7 +176,7 @@ export function ProjectWorkspaceSummaryCard({
|
|||
<div className="flex items-start gap-2">
|
||||
<FolderOpen className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">Path</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">Path</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<CopyText
|
||||
text={summary.cwd}
|
||||
|
|
@ -204,7 +204,7 @@ export function ProjectWorkspaceSummaryCard({
|
|||
<div className="flex items-start gap-2">
|
||||
<ExternalLink className="mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
|
||||
<div className="min-w-0">
|
||||
<div className="text-[11px] uppercase tracking-[0.14em] text-muted-foreground">Service</div>
|
||||
<div className="text-(length:--fs-11) uppercase tracking-(--ls-0_14) text-muted-foreground">Service</div>
|
||||
<a
|
||||
href={summary.primaryServiceUrl}
|
||||
target="_blank"
|
||||
|
|
@ -226,7 +226,7 @@ export function ProjectWorkspaceSummaryCard({
|
|||
|
||||
{summary.issues.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
<div className="text-[11px] font-medium uppercase tracking-[0.14em] text-muted-foreground">
|
||||
<div className="text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_14) text-muted-foreground">
|
||||
Linked tasks
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ export function ProjectWorkspacesContent({
|
|||
</div>
|
||||
{cleanupFailedSummaries.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
<div className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<div className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Cleanup attention needed
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ export function ProviderQuotaCard({
|
|||
<span className="text-xs text-muted-foreground truncate font-mono block">
|
||||
{row.model}
|
||||
</span>
|
||||
<span className="text-[11px] text-muted-foreground truncate block">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground truncate block">
|
||||
{providerDisplayName(row.biller)} · {billingTypeDisplayName(row.billingType)}
|
||||
</span>
|
||||
</div>
|
||||
|
|
@ -314,7 +314,7 @@ export function ProviderQuotaCard({
|
|||
Subscription quota
|
||||
</p>
|
||||
{quotaSource && !isClaudeQuotaPanel && !isCodexQuotaPanel ? (
|
||||
<span className="text-[10px] uppercase tracking-[0.16em] text-muted-foreground">
|
||||
<span className="text-(length:--fs-10) uppercase tracking-(--ls-0_16) text-muted-foreground">
|
||||
{quotaSourceDisplayName(quotaSource)}
|
||||
</span>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export function ReusableExecutionWorkspaceSelect<TWorkspace extends ReusableExec
|
|||
renderOption={(option, { selected }) => (
|
||||
<span className="flex min-w-0 flex-col">
|
||||
<span className={cn("truncate", selected && "font-medium")}>{option.label}</span>
|
||||
<span className="truncate text-[11px] text-muted-foreground">
|
||||
<span className="truncate text-(length:--fs-11) text-muted-foreground">
|
||||
{option.workspace.status ? `${option.workspace.status} - ` : ""}
|
||||
{option.description}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -427,10 +427,10 @@ function RevisionList({
|
|||
return (
|
||||
<aside className="space-y-1">
|
||||
<header className="flex items-center justify-between pb-2">
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Revisions
|
||||
</p>
|
||||
<span className="text-[11px] text-muted-foreground">{totalRevisions} total</span>
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">{totalRevisions} total</span>
|
||||
</header>
|
||||
{revisions.map((revision) => {
|
||||
const isSelected = revision.id === selectedRevisionId;
|
||||
|
|
@ -460,12 +460,12 @@ function RevisionList({
|
|||
<div className="flex items-center gap-2 text-sm font-medium">
|
||||
<span>rev {revision.revisionNumber}</span>
|
||||
{isCurrent && (
|
||||
<span className="rounded-full border border-border px-1.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
|
||||
<span className="rounded-full border border-border px-1.5 text-(length:--fs-10) uppercase tracking-(--ls-0_12) text-muted-foreground">
|
||||
Current
|
||||
</span>
|
||||
)}
|
||||
{revision.restoredFromRevisionId && (
|
||||
<span className="rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 text-[10px] uppercase tracking-[0.12em] text-amber-200">
|
||||
<span className="rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 text-(length:--fs-10) uppercase tracking-(--ls-0_12) text-amber-200">
|
||||
Restored
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -601,17 +601,17 @@ function RevisionPreview({
|
|||
</header>
|
||||
|
||||
<div className={`${cardWrapper} p-3`}>
|
||||
<p className="pb-2 text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="pb-2 text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Structured fields
|
||||
</p>
|
||||
<div className="grid gap-3 md:grid-cols-2 divide-y md:divide-y-0 divide-border">
|
||||
{fieldRows.map((row) => (
|
||||
<div key={row.key} className="space-y-1 p-2">
|
||||
<p className="text-[11px] uppercase tracking-wide text-muted-foreground">{row.label}</p>
|
||||
<p className="text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">{row.label}</p>
|
||||
<p className="text-sm">
|
||||
{row.value || <span className="text-muted-foreground">—</span>}
|
||||
{row.differs && (
|
||||
<span className="ml-2 rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 text-[10px] uppercase tracking-[0.12em] text-amber-200">
|
||||
<span className="ml-2 rounded-full border border-amber-500/40 bg-amber-500/10 px-1.5 text-(length:--fs-10) uppercase tracking-(--ls-0_12) text-amber-200">
|
||||
differs from current
|
||||
</span>
|
||||
)}
|
||||
|
|
@ -622,7 +622,7 @@ function RevisionPreview({
|
|||
</div>
|
||||
|
||||
<div className={`${cardWrapper} p-3 space-y-2`}>
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Description
|
||||
</p>
|
||||
<div className="rounded-md bg-background/40 p-3 text-sm leading-7">
|
||||
|
|
@ -635,7 +635,7 @@ function RevisionPreview({
|
|||
</div>
|
||||
|
||||
<div className={`${cardWrapper} p-3 space-y-2`}>
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Triggers ({triggers.length})
|
||||
</p>
|
||||
{triggers.length === 0 ? (
|
||||
|
|
@ -644,7 +644,7 @@ function RevisionPreview({
|
|||
<ul className="divide-y divide-border">
|
||||
{triggers.map((trigger) => (
|
||||
<li key={trigger.id} className="py-2 flex flex-wrap items-center gap-2 text-sm">
|
||||
<span className="rounded-full border border-border px-2 py-0.5 text-[10px] uppercase tracking-[0.12em] text-muted-foreground">
|
||||
<span className="rounded-full border border-border px-2 py-0.5 text-(length:--fs-10) uppercase tracking-(--ls-0_12) text-muted-foreground">
|
||||
{trigger.kind}
|
||||
</span>
|
||||
<span className="font-medium">{trigger.label ?? trigger.kind}</span>
|
||||
|
|
@ -668,7 +668,7 @@ function RevisionPreview({
|
|||
|
||||
{snapshot.variables.length > 0 && (
|
||||
<div className={`${cardWrapper} p-3 space-y-2`}>
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Variables ({snapshot.variables.length})
|
||||
</p>
|
||||
<ul className="divide-y divide-border">
|
||||
|
|
@ -840,7 +840,7 @@ function RoutineRevisionDiffModal({
|
|||
</div>
|
||||
<div className="overflow-auto flex-1 space-y-4">
|
||||
<section className="space-y-2">
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Field changes
|
||||
</p>
|
||||
{fieldChanges.length === 0 ? (
|
||||
|
|
@ -871,7 +871,7 @@ function RoutineRevisionDiffModal({
|
|||
)}
|
||||
</section>
|
||||
<section className="space-y-2">
|
||||
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<p className="text-xs font-medium uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Description diff
|
||||
</p>
|
||||
<DiffTable rows={descriptionDiff} />
|
||||
|
|
@ -912,7 +912,7 @@ function RevisionPicker({
|
|||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`rounded-full border px-2 py-0.5 text-[10px] font-medium uppercase tracking-wider ${toneClass}`}
|
||||
className={`rounded-full border px-2 py-0.5 text-(length:--fs-10) font-medium uppercase tracking-wider ${toneClass}`}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
|
|
@ -951,7 +951,7 @@ function DiffTable({ rows }: { rows: DiffRow[] }) {
|
|||
};
|
||||
return (
|
||||
<div className="rounded-md border border-border text-xs font-mono leading-6 overflow-hidden">
|
||||
<div className="grid grid-cols-[56px_56px_24px_minmax(0,1fr)] border-b border-border/60 bg-muted/30 px-3 py-2 text-[11px] uppercase tracking-wide text-muted-foreground">
|
||||
<div className="grid grid-cols-[56px_56px_24px_minmax(0,1fr)] border-b border-border/60 bg-muted/30 px-3 py-2 text-(length:--fs-11) uppercase tracking-wide text-muted-foreground">
|
||||
<span>Old</span>
|
||||
<span>New</span>
|
||||
<span />
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ export function RoutineSaveBar({
|
|||
>
|
||||
{isSaving ? <Loader2 className="mr-1.5 h-3.5 w-3.5 animate-spin" /> : null}
|
||||
Save changes
|
||||
<kbd className="ml-2 hidden rounded bg-foreground/10 px-1 text-[10px] font-medium sm:inline">
|
||||
<kbd className="ml-2 hidden rounded bg-foreground/10 px-1 text-(length:--fs-10) font-medium sm:inline">
|
||||
⌘S
|
||||
</kbd>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ export function RoutineSubSidebar({
|
|||
>
|
||||
{NAV_GROUPS.map((group) => (
|
||||
<div key={group.label} className="flex flex-col gap-0.5">
|
||||
<p className="px-3 py-2 text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground/80">
|
||||
<p className="px-3 py-2 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_12) text-muted-foreground/80">
|
||||
{group.label}
|
||||
</p>
|
||||
{group.items.map((item) => {
|
||||
|
|
@ -189,7 +189,7 @@ export function RoutineSectionPicker({
|
|||
<SelectContent>
|
||||
{NAV_GROUPS.map((group) => (
|
||||
<SelectGroup key={group.label}>
|
||||
<SelectLabel className="uppercase tracking-[0.12em] text-[11px]">
|
||||
<SelectLabel className="uppercase tracking-(--ls-0_12) text-(length:--fs-11)">
|
||||
{group.label}
|
||||
</SelectLabel>
|
||||
{group.items.map((item) => (
|
||||
|
|
|
|||
|
|
@ -298,7 +298,7 @@ export function RoutineVariablesHint() {
|
|||
|
||||
<div className="space-y-5 text-sm">
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Custom variables
|
||||
</h3>
|
||||
<p className="text-muted-foreground">
|
||||
|
|
@ -319,7 +319,7 @@ export function RoutineVariablesHint() {
|
|||
</section>
|
||||
|
||||
<section className="space-y-2">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<h3 className="text-xs font-semibold uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
Built-in variables
|
||||
</h3>
|
||||
<p className="text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ export function SecretBindingPicker({
|
|||
{value ? (
|
||||
<button
|
||||
type="button"
|
||||
className="text-[11px] text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
|
||||
className="text-(length:--fs-11) text-muted-foreground hover:text-foreground inline-flex items-center gap-1"
|
||||
onClick={() => onChange(null)}
|
||||
disabled={disabled}
|
||||
>
|
||||
|
|
@ -210,17 +210,17 @@ export function SecretBindingPicker({
|
|||
</div>
|
||||
|
||||
{selectedSecret ? (
|
||||
<p className={cn("text-[11px] text-muted-foreground", statusTone(selectedSecret.status))}>
|
||||
<p className={cn("text-(length:--fs-11) text-muted-foreground", statusTone(selectedSecret.status))}>
|
||||
{selectedSecret.status !== "active" ? `Status: ${selectedSecret.status}. ` : null}
|
||||
Bound to {versionDisplay(value?.version)} · {selectedSecret.key}
|
||||
</p>
|
||||
) : selectedMissing ? (
|
||||
<p className="text-[11px] text-destructive flex items-center gap-1">
|
||||
<p className="text-(length:--fs-11) text-destructive flex items-center gap-1">
|
||||
<AlertCircle className="h-3 w-3" />
|
||||
The previously selected secret is no longer available. Pick another or remove the binding.
|
||||
</p>
|
||||
) : (filteredSecrets.length === 0 && !secretsQuery.isPending) ? (
|
||||
<p className="text-[11px] text-muted-foreground">{emptyHint}</p>
|
||||
<p className="text-(length:--fs-11) text-muted-foreground">{emptyHint}</p>
|
||||
) : null}
|
||||
|
||||
<Dialog open={createOpen} onOpenChange={setCreateOpen}>
|
||||
|
|
@ -249,7 +249,7 @@ export function SecretBindingPicker({
|
|||
placeholder="Paste the secret value"
|
||||
className="font-mono text-xs"
|
||||
/>
|
||||
<p className="text-[11px] text-muted-foreground mt-1">
|
||||
<p className="text-(length:--fs-11) text-muted-foreground mt-1">
|
||||
The value is stored once and never re-displayed. Rotate to replace.
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ export function Sidebar() {
|
|||
onClick={() => openNewIssue()}
|
||||
data-slot="icon-button"
|
||||
aria-label={rail ? "New Task" : undefined}
|
||||
className="flex items-center gap-2.5 px-3 py-2 pointer-coarse:py-1.5 text-[13px] font-medium text-foreground/80 hover:bg-accent/50 hover:text-foreground transition-colors"
|
||||
className="flex items-center gap-2.5 px-3 py-2 pointer-coarse:py-1.5 text-(length:--fs-13) font-medium text-foreground/80 hover:bg-accent/50 hover:text-foreground transition-colors"
|
||||
>
|
||||
<SquarePen className="h-4 w-4 shrink-0" />
|
||||
<span className={rail ? SIDEBAR_RAIL_HIDDEN_LABEL : "truncate"}>New Task</span>
|
||||
|
|
@ -197,14 +197,14 @@ export function Sidebar() {
|
|||
slotTypes={["sidebar"]}
|
||||
context={pluginContext}
|
||||
className="flex flex-col gap-0.5"
|
||||
itemClassName="text-[13px] font-medium"
|
||||
itemClassName="text-(length:--fs-13) font-medium"
|
||||
missingBehavior="placeholder"
|
||||
/>
|
||||
<PluginLauncherOutlet
|
||||
placementZones={["sidebar"]}
|
||||
context={pluginContext}
|
||||
className="flex flex-col gap-0.5"
|
||||
itemClassName="text-[13px] font-medium"
|
||||
itemClassName="text-(length:--fs-13) font-medium"
|
||||
/>
|
||||
</SidebarSection>
|
||||
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ export function SidebarAccountMenu({
|
|||
<PopoverTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center gap-2.5 px-3 py-2 text-left text-[13px] font-medium text-foreground/80 transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
className="flex w-full items-center gap-2.5 px-3 py-2 text-left text-(length:--fs-13) font-medium text-foreground/80 transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
aria-label="Open account menu"
|
||||
>
|
||||
<Avatar size="sm">
|
||||
|
|
@ -172,7 +172,7 @@ export function SidebarAccountMenu({
|
|||
<div className="min-w-0 flex-1 pt-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<h2 className="truncate text-base font-semibold text-foreground">{displayName}</h2>
|
||||
<span className="rounded-full bg-accent px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
<span className="rounded-full bg-accent px-2 py-0.5 text-(length:--fs-10) font-semibold uppercase tracking-wide text-muted-foreground">
|
||||
{accountBadge}
|
||||
</span>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ function SidebarAgentItem({
|
|||
if (isMobile) setSidebarOpen(false);
|
||||
}}
|
||||
className={cn(
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pointer-coarse:py-1 text-[13px] font-medium transition-colors",
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pointer-coarse:py-1 text-(length:--fs-13) font-medium transition-colors",
|
||||
// Reserve room for the ⋯ menu, plus the inline unstar star on starred rows.
|
||||
starred && !isMobile ? "pr-14" : "pr-8",
|
||||
isActive
|
||||
|
|
@ -180,7 +180,7 @@ function SidebarAgentItem({
|
|||
</span>
|
||||
) : null}
|
||||
{runCount > 0 ? (
|
||||
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">
|
||||
<span className="text-(length:--fs-11) font-medium text-blue-600 dark:text-blue-400">
|
||||
{runCount} live
|
||||
</span>
|
||||
) : null}
|
||||
|
|
@ -580,7 +580,7 @@ export function SidebarAgents({ streamlined = false }: { streamlined?: boolean }
|
|||
onClick={() => {
|
||||
if (isMobile) setSidebarOpen(false);
|
||||
}}
|
||||
className="flex items-center gap-2.5 px-3 py-1.5 pointer-coarse:py-1 text-[13px] font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
className="flex items-center gap-2.5 px-3 py-1.5 pointer-coarse:py-1 text-(length:--fs-13) font-medium text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
>
|
||||
<Users className="shrink-0 h-3.5 w-3.5" />
|
||||
<span className={rail ? SIDEBAR_RAIL_HIDDEN_LABEL : undefined}>See all agents</span>
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ function WorkspaceIcon({ company }: { company: Company }) {
|
|||
companyName={company.name}
|
||||
logoUrl={company.logoUrl}
|
||||
brandColor={company.brandColor}
|
||||
className="size-5 shrink-0 rounded-md text-[11px]"
|
||||
className="size-5 shrink-0 rounded-md text-(length:--fs-11)"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ function SortableCompanyItem({
|
|||
</button>
|
||||
) : (
|
||||
<>
|
||||
<span className="shrink-0 rounded bg-muted px-1.5 py-0.5 font-mono text-[10px] text-muted-foreground">
|
||||
<span className="shrink-0 rounded bg-muted px-1.5 py-0.5 font-mono text-(length:--fs-10) text-muted-foreground">
|
||||
{company.issuePrefix}
|
||||
</span>
|
||||
{isSelected ? <Check className="size-4 text-muted-foreground" /> : null}
|
||||
|
|
@ -244,7 +244,7 @@ export function SidebarCompanyMenu({ open: controlledOpen, onOpenChange }: Sideb
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" sideOffset={8} className="w-64 p-1">
|
||||
<div className="flex items-center justify-between gap-2 px-2 py-1.5">
|
||||
<DropdownMenuLabel className="p-0 text-[11px] font-semibold uppercase text-muted-foreground">
|
||||
<DropdownMenuLabel className="p-0 text-(length:--fs-11) font-semibold uppercase text-muted-foreground">
|
||||
Switch company
|
||||
</DropdownMenuLabel>
|
||||
<button
|
||||
|
|
@ -254,7 +254,7 @@ export function SidebarCompanyMenu({ open: controlledOpen, onOpenChange }: Sideb
|
|||
event.stopPropagation();
|
||||
setIsEditingOrder((current) => !current);
|
||||
}}
|
||||
className="rounded px-1.5 py-0.5 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
||||
className="rounded px-1.5 py-0.5 text-(length:--fs-11) font-medium text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
||||
>
|
||||
{isEditingOrder ? "Done" : "Edit"}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export function SidebarNavItem({
|
|||
onClick={() => { if (isMobile) setSidebarOpen(false); }}
|
||||
className={({ isActive }) =>
|
||||
cn(
|
||||
"flex items-center gap-2.5 px-3 py-2 pointer-coarse:py-1.5 text-[13px] font-medium transition-colors",
|
||||
"flex items-center gap-2.5 px-3 py-2 pointer-coarse:py-1.5 text-(length:--fs-13) font-medium transition-colors",
|
||||
isActive
|
||||
? "bg-accent text-foreground"
|
||||
: "text-foreground/80 hover:bg-accent/50 hover:text-foreground",
|
||||
|
|
@ -132,7 +132,7 @@ export function SidebarNavItem({
|
|||
{!rail && textBadge && (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-auto rounded-full px-1.5 py-0.5 text-[10px] font-medium leading-none",
|
||||
"ml-auto rounded-full px-1.5 py-0.5 text-(length:--fs-10) font-medium leading-none",
|
||||
textBadgeTone === "amber"
|
||||
? "bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400"
|
||||
: "bg-muted text-muted-foreground",
|
||||
|
|
@ -147,7 +147,7 @@ export function SidebarNavItem({
|
|||
<span className="animate-pulse absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
|
||||
<span className="relative inline-flex rounded-full h-2 w-2 bg-blue-500" />
|
||||
</span>
|
||||
<span className="text-[11px] font-medium text-blue-600 dark:text-blue-400">{liveCount} live</span>
|
||||
<span className="text-(length:--fs-11) font-medium text-blue-600 dark:text-blue-400">{liveCount} live</span>
|
||||
</span>
|
||||
)}
|
||||
{!rail && hasBadge && (
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ function ProjectItem({
|
|||
if (isMobile) setSidebarOpen(false);
|
||||
}}
|
||||
className={cn(
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pr-8 pointer-coarse:py-1 text-[13px] font-medium transition-colors",
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pr-8 pointer-coarse:py-1 text-(length:--fs-13) font-medium transition-colors",
|
||||
activeProjectRef === routeRef || activeProjectRef === project.id
|
||||
? "bg-accent text-foreground"
|
||||
: "text-foreground/80 hover:bg-accent/50 hover:text-foreground",
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ function SidebarSectionHeader({
|
|||
const hasMenu = Boolean(
|
||||
menu && ((menu.actions?.length ?? 0) > 0 || (menu.radioChoices?.length ?? 0) > 0),
|
||||
);
|
||||
const labelClassName = "text-[10px] font-medium uppercase tracking-widest font-mono text-muted-foreground/60";
|
||||
const labelClassName = "text-(length:--fs-10) font-medium uppercase tracking-widest font-mono text-muted-foreground/60";
|
||||
const headerControlVisibilityClassName = isMobile
|
||||
? "opacity-100"
|
||||
: "opacity-0 group-hover/sidebar-section:opacity-100 group-focus-within/sidebar-section:opacity-100";
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ export function SidebarServerInfo() {
|
|||
|
||||
return (
|
||||
<div className="mt-2 border-t border-border pt-2">
|
||||
<p className="px-3 pb-1 pt-1 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
<p className="px-3 pb-1 pt-1 text-(length:--fs-11) font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Server
|
||||
</p>
|
||||
<ServerInfoRow
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export function SidebarStarredProjects() {
|
|||
if (isMobile) setSidebarOpen(false);
|
||||
}}
|
||||
className={cn(
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pl-8 pointer-coarse:py-1 pr-8 text-[13px] font-medium transition-colors",
|
||||
"flex min-w-0 flex-1 items-center gap-2.5 px-3 py-1.5 pl-8 pointer-coarse:py-1 pr-8 text-(length:--fs-13) font-medium transition-colors",
|
||||
isActive
|
||||
? "bg-accent text-foreground"
|
||||
: "text-foreground/80 hover:bg-accent/50 hover:text-foreground",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export function SourceResolvedFoldBadge({
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-[11px] font-medium",
|
||||
"inline-flex items-center gap-1 rounded-md border px-1.5 py-0.5 text-(length:--fs-11) font-medium",
|
||||
"border-emerald-300/60 bg-emerald-50/80 text-emerald-900",
|
||||
"dark:border-emerald-500/30 dark:bg-emerald-500/10 dark:text-emerald-200",
|
||||
className,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function MetaRow({
|
|||
}) {
|
||||
return (
|
||||
<div className="grid grid-cols-[10rem_1fr] gap-x-3 gap-y-0 py-1 text-xs sm:grid-cols-[12rem_1fr]">
|
||||
<dt className="truncate text-[11px] font-medium uppercase tracking-[0.08em] text-emerald-900/70 dark:text-emerald-200/70">
|
||||
<dt className="truncate text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-emerald-900/70 dark:text-emerald-200/70">
|
||||
{label}
|
||||
</dt>
|
||||
<dd className="min-w-0 break-words text-emerald-950 dark:text-emerald-100">{children}</dd>
|
||||
|
|
@ -80,7 +80,7 @@ export function SourceResolvedFoldCallout({
|
|||
<Sparkles className="h-4 w-4 text-emerald-700 dark:text-emerald-300" />
|
||||
</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] font-semibold uppercase tracking-[0.14em]">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_14)">
|
||||
<span className="text-emerald-900 dark:text-emerald-200">SOURCE-RESOLVED FOLD</span>
|
||||
<span className="text-muted-foreground/60" aria-hidden>·</span>
|
||||
<span className="font-medium normal-case tracking-normal text-muted-foreground">
|
||||
|
|
@ -95,7 +95,7 @@ export function SourceResolvedFoldCallout({
|
|||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<p className="mt-1 text-[14px] leading-6">
|
||||
<p className="mt-1 text-(length:--fs-14) leading-6">
|
||||
This run was folded as a source-resolved false positive.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -115,24 +115,24 @@ export function SourceResolvedFoldCallout({
|
|||
>
|
||||
{sourceLabel}
|
||||
</Link>
|
||||
<span className="rounded-md border border-emerald-300/60 bg-background/60 px-1.5 py-0.5 text-[11px] font-medium text-emerald-900 dark:border-emerald-500/30 dark:text-emerald-200">
|
||||
<span className="rounded-md border border-emerald-300/60 bg-background/60 px-1.5 py-0.5 text-(length:--fs-11) font-medium text-emerald-900 dark:border-emerald-500/30 dark:text-emerald-200">
|
||||
{fold.sourceIssueStatus}
|
||||
</span>
|
||||
</span>
|
||||
</MetaRow>
|
||||
<MetaRow label="Same-run evidence">
|
||||
<span className="inline-flex flex-wrap items-baseline gap-1.5">
|
||||
<span className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-[11px] text-emerald-900 dark:bg-background/40 dark:text-emerald-100">
|
||||
<span className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-(length:--fs-11) text-emerald-900 dark:bg-background/40 dark:text-emerald-100">
|
||||
{fold.sameRunEvidenceKind}
|
||||
</span>
|
||||
<code
|
||||
className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-[11px] text-emerald-900 dark:bg-background/40 dark:text-emerald-100"
|
||||
className="rounded bg-background/70 px-1.5 py-0.5 font-mono text-(length:--fs-11) text-emerald-900 dark:bg-background/40 dark:text-emerald-100"
|
||||
title={fold.sameRunEvidenceId}
|
||||
>
|
||||
{evidenceShort}
|
||||
</code>
|
||||
{evidenceAt ? (
|
||||
<span className="text-[11px] text-muted-foreground">at {evidenceAt}</span>
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">at {evidenceAt}</span>
|
||||
) : null}
|
||||
</span>
|
||||
</MetaRow>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ export function SourceTrustBadge({
|
|||
variant="outline"
|
||||
aria-label={label}
|
||||
className={cn(
|
||||
"inline-flex items-center gap-1 whitespace-nowrap px-1.5 py-0 text-[10px] font-medium tracking-normal",
|
||||
"inline-flex items-center gap-1 whitespace-nowrap px-1.5 py-0 text-(length:--fs-10) font-medium tracking-normal",
|
||||
promoted
|
||||
? "border-border text-muted-foreground"
|
||||
: "border-amber-500/40 text-amber-700 dark:text-amber-100",
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ function formatTimestamp(ts: string) {
|
|||
function MetadataRow({ row, tone }: { row: SystemNoticeMetadataRow; tone: ToneTokens }) {
|
||||
return (
|
||||
<div className="grid grid-cols-[7.5rem_1fr] gap-x-3 gap-y-0.5 px-3 py-1.5 text-xs">
|
||||
<div className="truncate text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground">
|
||||
<div className="truncate text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_08) text-muted-foreground">
|
||||
{row.label}
|
||||
</div>
|
||||
<div className="min-w-0 break-words text-foreground/90">
|
||||
|
|
@ -124,7 +124,7 @@ function MetadataRow({ row, tone }: { row: SystemNoticeMetadataRow; tone: ToneTo
|
|||
return <span>{row.value}</span>;
|
||||
case "code":
|
||||
return (
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-[11px] text-foreground/80">
|
||||
<code className="rounded bg-muted px-1.5 py-0.5 font-mono text-(length:--fs-11) text-foreground/80">
|
||||
{row.value}
|
||||
</code>
|
||||
);
|
||||
|
|
@ -187,14 +187,14 @@ function MetadataRow({ row, tone }: { row: SystemNoticeMetadataRow; tone: ToneTo
|
|||
return (
|
||||
<a
|
||||
href={row.href}
|
||||
className="inline-flex items-center gap-2 rounded-sm font-mono text-[11px] underline-offset-2 hover:underline"
|
||||
className="inline-flex items-center gap-2 rounded-sm font-mono text-(length:--fs-11) underline-offset-2 hover:underline"
|
||||
>
|
||||
{inner}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span className="inline-flex items-center gap-2 font-mono text-[11px]">
|
||||
<span className="inline-flex items-center gap-2 font-mono text-(length:--fs-11)">
|
||||
{inner}
|
||||
</span>
|
||||
);
|
||||
|
|
@ -252,7 +252,7 @@ export function SystemNotice({
|
|||
<ToneIcon className={cn("h-4 w-4", tokens.iconClass)} />
|
||||
</span>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-[11px] font-semibold uppercase tracking-[0.14em]">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-(length:--fs-11) font-semibold uppercase tracking-(--ls-0_14)">
|
||||
<span className={tokens.label}>{resolvedLabel}</span>
|
||||
{source ? (
|
||||
<>
|
||||
|
|
@ -280,7 +280,7 @@ export function SystemNotice({
|
|||
</>
|
||||
) : null}
|
||||
</div>
|
||||
<div className="mt-1 break-words text-[14px] leading-6 text-foreground">{body}</div>
|
||||
<div className="mt-1 break-words text-(length:--fs-14) leading-6 text-foreground">{body}</div>
|
||||
</div>
|
||||
{hasDetails ? (
|
||||
<button
|
||||
|
|
@ -289,7 +289,7 @@ export function SystemNotice({
|
|||
aria-expanded={open}
|
||||
aria-controls={detailsId}
|
||||
className={cn(
|
||||
"ml-1 inline-flex h-7 shrink-0 items-center gap-1 rounded-md border border-transparent px-2 text-[11px] font-medium uppercase tracking-[0.12em] text-muted-foreground transition-[background-color,border-color,color]",
|
||||
"ml-1 inline-flex h-7 shrink-0 items-center gap-1 rounded-md border border-transparent px-2 text-(length:--fs-11) font-medium uppercase tracking-(--ls-0_12) text-muted-foreground transition-[background-color,border-color,color]",
|
||||
"hover:border-border/70 hover:bg-background/70 hover:text-foreground",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
|
||||
)}
|
||||
|
|
@ -316,7 +316,7 @@ export function SystemNotice({
|
|||
{metadata!.map((section, sectionIdx) => (
|
||||
<div key={sectionIdx} className="py-1.5 first:pt-2 last:pb-2">
|
||||
{section.title ? (
|
||||
<div className="px-3 pb-1 pt-0.5 text-[10px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
|
||||
<div className="px-3 pb-1 pt-0.5 text-(length:--fs-10) font-semibold uppercase tracking-(--ls-0_18) text-muted-foreground">
|
||||
{section.title}
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ function WorkspaceFileBreadcrumbs({
|
|||
if (!rootLabel && segments.length === 0) return null;
|
||||
|
||||
return (
|
||||
<nav aria-label="Current folder" className="min-w-0 overflow-hidden text-[11px] text-muted-foreground">
|
||||
<nav aria-label="Current folder" className="min-w-0 overflow-hidden text-(length:--fs-11) text-muted-foreground">
|
||||
<ol className="flex min-w-0 items-center gap-1 overflow-hidden">
|
||||
{rootLabel ? (
|
||||
<li className="min-w-0 shrink">
|
||||
|
|
@ -1072,7 +1072,7 @@ export function WorkspaceFileBrowser({
|
|||
<div ref={scrollContainerRef} className="min-h-0 flex-1 overflow-y-auto">{body}</div>
|
||||
|
||||
{lazyTruncatedFolders.has(currentFolderKey) || (data?.truncated && !isLazyBrowse) ? (
|
||||
<div className="border-t border-border pt-2 text-[11px] text-muted-foreground">
|
||||
<div className="border-t border-border pt-2 text-(length:--fs-11) text-muted-foreground">
|
||||
{isLazyBrowse ? (
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
|||
|
|
@ -354,7 +354,7 @@ function CommandSection({
|
|||
{item.healthStatus && item.statusLabel !== "stopped" ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className={cn(
|
||||
"inline-flex items-center rounded-full border px-2.5 py-1 text-[11px]",
|
||||
"inline-flex items-center rounded-full border px-2.5 py-1 text-(length:--fs-11)",
|
||||
item.healthStatus === "healthy"
|
||||
? "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"
|
||||
: item.healthStatus === "unhealthy"
|
||||
|
|
@ -405,7 +405,7 @@ export function WorkspaceRuntimeControls({
|
|||
<div className={cn("space-y-4", className)}>
|
||||
<div className={cn("border border-border/70 bg-background p-3", square ? "rounded-none" : "rounded-xl")}>
|
||||
<div className="space-y-1">
|
||||
<div className="text-xs font-medium uppercase tracking-[0.16em] text-muted-foreground">Workspace commands</div>
|
||||
<div className="text-xs font-medium uppercase tracking-(--ls-0_16) text-muted-foreground">Workspace commands</div>
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span
|
||||
className={cn(
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export function WorktreeBanner() {
|
|||
|
||||
return (
|
||||
<div
|
||||
className="relative overflow-hidden border-b px-3 py-1.5 text-[11px] font-medium tracking-[0.2em] uppercase"
|
||||
className="relative overflow-hidden border-b px-3 py-1.5 text-(length:--fs-11) font-medium tracking-(--ls-0_2) uppercase"
|
||||
style={{
|
||||
backgroundColor: branding.color,
|
||||
color: branding.textColor,
|
||||
|
|
@ -33,7 +33,7 @@ export function WorktreeBanner() {
|
|||
type="button"
|
||||
onClick={handleCopyName}
|
||||
title="Click to copy worktree name"
|
||||
className="truncate font-semibold tracking-[0.12em] cursor-pointer hover:opacity-80 transition-opacity bg-transparent border-none p-0 text-current uppercase text-[11px]"
|
||||
className="truncate font-semibold tracking-(--ls-0_12) cursor-pointer hover:opacity-80 transition-opacity bg-transparent border-none p-0 text-current uppercase text-(length:--fs-11)"
|
||||
>
|
||||
{copied ? "Copied!" : branding.name}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ function PlaceholderPreview({ label }: { label?: string }) {
|
|||
<PreviewFrame className="flex items-center justify-center">
|
||||
<div className="flex flex-col items-center gap-1.5 text-muted-foreground/50">
|
||||
<Paperclip className="h-7 w-7" aria-hidden="true" />
|
||||
{label ? <span className="text-[11px] font-medium uppercase tracking-wide">{label}</span> : null}
|
||||
{label ? <span className="text-(length:--fs-11) font-medium uppercase tracking-wide">{label}</span> : null}
|
||||
</div>
|
||||
</PreviewFrame>
|
||||
);
|
||||
|
|
@ -223,7 +223,7 @@ export function ArtifactCard({ artifact }: ArtifactCardProps) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground/65">
|
||||
<div className="mt-0.5 flex items-center gap-1.5 text-(length:--fs-11) text-muted-foreground/65">
|
||||
<span>Last edited {formatDate(artifact.updatedAt)}</span>
|
||||
{artifact.createdByAgent ? (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export function ArtifactGroupCard({ group, to }: ArtifactGroupCardProps) {
|
|||
<Layers className="h-7 w-7" aria-hidden="true" />
|
||||
</div>
|
||||
)}
|
||||
<span className="absolute right-2 top-2 inline-flex items-center gap-1 rounded-full bg-background/85 px-2 py-0.5 text-[11px] font-medium text-foreground/90 shadow-sm backdrop-blur">
|
||||
<span className="absolute right-2 top-2 inline-flex items-center gap-1 rounded-full bg-background/85 px-2 py-0.5 text-(length:--fs-11) font-medium text-foreground/90 shadow-sm backdrop-blur">
|
||||
<Layers className="h-3 w-3" aria-hidden="true" />
|
||||
{group.count}
|
||||
</span>
|
||||
|
|
@ -64,7 +64,7 @@ export function ArtifactGroupCard({ group, to }: ArtifactGroupCardProps) {
|
|||
|
||||
<div className="flex flex-1 flex-col gap-1 p-3">
|
||||
<div className="flex h-7 items-center gap-2">
|
||||
<span className="shrink-0 font-mono text-[11px] text-muted-foreground">
|
||||
<span className="shrink-0 font-mono text-(length:--fs-11) text-muted-foreground">
|
||||
{group.issue.identifier}
|
||||
</span>
|
||||
<h3
|
||||
|
|
@ -75,7 +75,7 @@ export function ArtifactGroupCard({ group, to }: ArtifactGroupCardProps) {
|
|||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground/65">
|
||||
<div className="mt-0.5 flex items-center gap-1.5 text-(length:--fs-11) text-muted-foreground/65">
|
||||
<span>{countLabel}</span>
|
||||
<span className="text-muted-foreground/50">·</span>
|
||||
<span>Updated {formatDate(group.updatedAt)}</span>
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ export function SecretPopoverForm({
|
|||
<div className="space-y-1">
|
||||
<PopoverTitle className="text-sm font-medium">{heading}</PopoverTitle>
|
||||
{mode === "store" ? (
|
||||
<PopoverDescription className="text-[11px] text-muted-foreground">
|
||||
<PopoverDescription className="text-(length:--fs-11) text-muted-foreground">
|
||||
Moves the typed value into an encrypted company secret and binds{" "}
|
||||
<span className="font-mono">{initialName || "this variable"}</span> to it.
|
||||
</PopoverDescription>
|
||||
|
|
@ -83,7 +83,7 @@ export function SecretPopoverForm({
|
|||
</div>
|
||||
|
||||
<label className="block space-y-1">
|
||||
<span className="text-[11px] font-medium text-muted-foreground">Name</span>
|
||||
<span className="text-(length:--fs-11) font-medium text-muted-foreground">Name</span>
|
||||
<input
|
||||
className={cn(fieldClass, nameError && "border-destructive focus-visible:ring-destructive/40")}
|
||||
value={name}
|
||||
|
|
@ -101,11 +101,11 @@ export function SecretPopoverForm({
|
|||
}
|
||||
}}
|
||||
/>
|
||||
{nameError ? <span className="block text-[11px] text-destructive">{nameError}</span> : null}
|
||||
{nameError ? <span className="block text-(length:--fs-11) text-destructive">{nameError}</span> : null}
|
||||
</label>
|
||||
|
||||
<label className="block space-y-1">
|
||||
<span className="text-[11px] font-medium text-muted-foreground">Value</span>
|
||||
<span className="text-(length:--fs-11) font-medium text-muted-foreground">Value</span>
|
||||
<div className="relative">
|
||||
<input
|
||||
className={cn(fieldClass, "pr-8", valueError && "border-destructive focus-visible:ring-destructive/40")}
|
||||
|
|
@ -127,10 +127,10 @@ export function SecretPopoverForm({
|
|||
{reveal ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
||||
</button>
|
||||
</div>
|
||||
{valueError ? <span className="block text-[11px] text-destructive">{valueError}</span> : null}
|
||||
{valueError ? <span className="block text-(length:--fs-11) text-destructive">{valueError}</span> : null}
|
||||
</label>
|
||||
|
||||
{error ? <p className="text-[11px] text-destructive">{error}</p> : null}
|
||||
{error ? <p className="text-(length:--fs-11) text-destructive">{error}</p> : null}
|
||||
|
||||
<div className="flex items-center justify-end gap-2 pt-0.5">
|
||||
<Button type="button" variant="ghost" size="sm" onClick={onCancel} disabled={submitting}>
|
||||
|
|
|
|||
|
|
@ -281,15 +281,15 @@ export function EnvironmentVariableRow({
|
|||
<DropdownMenuContent align="start" className="w-56">
|
||||
<DropdownMenuItem className="flex-col items-start gap-0.5" onSelect={() => switchSource("text")}>
|
||||
<span className="text-sm">Text value</span>
|
||||
<span className="text-[11px] text-muted-foreground">Store the value inline as plain text.</span>
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">Store the value inline as plain text.</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="flex-col items-start gap-0.5" onSelect={() => switchSource("secret")}>
|
||||
<span className="text-sm">Company secret</span>
|
||||
<span className="text-[11px] text-muted-foreground">Resolve a stored company secret at run start.</span>
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">Resolve a stored company secret at run start.</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="flex-col items-start gap-0.5" onSelect={() => switchSource("user_secret")}>
|
||||
<span className="text-sm">User secret</span>
|
||||
<span className="text-[11px] text-muted-foreground">
|
||||
<span className="text-(length:--fs-11) text-muted-foreground">
|
||||
Resolve the responsible user's own value at run start.
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
|
|
@ -321,7 +321,7 @@ export function EnvironmentVariableRow({
|
|||
type="button"
|
||||
onClick={openStoreAsSecret}
|
||||
disabled={disabled}
|
||||
className="flex items-center gap-1 px-2 text-[11px] text-amber-700 hover:bg-amber-500/10 dark:text-amber-400"
|
||||
className="flex items-center gap-1 px-2 text-(length:--fs-11) text-amber-700 hover:bg-amber-500/10 dark:text-amber-400"
|
||||
title="This value looks sensitive — store it as a secret"
|
||||
>
|
||||
<ShieldAlert className="size-3.5" />
|
||||
|
|
@ -369,7 +369,7 @@ export function EnvironmentVariableRow({
|
|||
}}
|
||||
aria-label="Version"
|
||||
className={cn(
|
||||
"absolute right-8 top-1/2 z-10 -translate-y-1/2 rounded px-1.5 py-0.5 text-[10px] font-medium",
|
||||
"absolute right-8 top-1/2 z-10 -translate-y-1/2 rounded px-1.5 py-0.5 text-(length:--fs-10) font-medium",
|
||||
versionPinned
|
||||
? "bg-amber-500/15 text-amber-700 dark:text-amber-400"
|
||||
: "text-muted-foreground hover:bg-accent",
|
||||
|
|
@ -392,7 +392,7 @@ export function EnvironmentVariableRow({
|
|||
row.version === "latest" && "font-medium",
|
||||
)}
|
||||
>
|
||||
latest <span className="text-[11px] text-muted-foreground">(recommended)</span>
|
||||
latest <span className="text-(length:--fs-11) text-muted-foreground">(recommended)</span>
|
||||
</button>
|
||||
{Array.from({ length: versions }, (_, idx) => versions - idx)
|
||||
.filter((v) => v > 0)
|
||||
|
|
@ -522,7 +522,7 @@ export function EnvironmentVariableRow({
|
|||
id={healthId}
|
||||
role="status"
|
||||
className={cn(
|
||||
"mt-0.5 text-[11px]",
|
||||
"mt-0.5 text-(length:--fs-11)",
|
||||
health.level === "error" ? "text-destructive" : "text-amber-600 dark:text-amber-400",
|
||||
)}
|
||||
>
|
||||
|
|
@ -532,7 +532,7 @@ export function EnvironmentVariableRow({
|
|||
|
||||
{/* 5s undo after Secret→Text */}
|
||||
{undoPrev ? (
|
||||
<p className="mt-0.5 inline-flex items-center gap-2 text-[11px] text-muted-foreground">
|
||||
<p className="mt-0.5 inline-flex items-center gap-2 text-(length:--fs-11) text-muted-foreground">
|
||||
Reverted to text —{" "}
|
||||
<button
|
||||
type="button"
|
||||
|
|
@ -552,7 +552,7 @@ export function EnvironmentVariableRow({
|
|||
<p
|
||||
id={nameErrorId}
|
||||
className={cn(
|
||||
"col-span-2 col-start-1 row-start-3 min-w-0 text-[11px] @[40rem]/env:col-span-2 @[40rem]/env:row-start-2",
|
||||
"col-span-2 col-start-1 row-start-3 min-w-0 text-(length:--fs-11) @[40rem]/env:col-span-2 @[40rem]/env:row-start-2",
|
||||
nameIssue.level === "error" ? "text-destructive" : "text-amber-600 dark:text-amber-400",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const FOLDER_VALUE_PREFIX = "__secret_folder__:";
|
|||
function statusBadge(status: SecretStatus | undefined) {
|
||||
if (!status || status === "active") return null;
|
||||
return (
|
||||
<Badge variant="outline" className="ml-auto text-[10px] font-normal text-muted-foreground">
|
||||
<Badge variant="outline" className="ml-auto text-(length:--fs-10) font-normal text-muted-foreground">
|
||||
{status}
|
||||
</Badge>
|
||||
);
|
||||
|
|
@ -292,7 +292,7 @@ export function SecretPicker({
|
|||
<span className="flex min-w-0 flex-col">
|
||||
<span className={cn("truncate text-sm", selected && "font-medium")}>{option.label}</span>
|
||||
{option.pathHint ? (
|
||||
<span className="truncate font-mono text-[11px] text-muted-foreground">{option.pathHint}</span>
|
||||
<span className="truncate font-mono text-(length:--fs-11) text-muted-foreground">{option.pathHint}</span>
|
||||
) : null}
|
||||
</span>
|
||||
</span>
|
||||
|
|
@ -310,7 +310,7 @@ export function SecretPicker({
|
|||
{option.label}
|
||||
</span>
|
||||
{option.pathHint && option.pathHint !== option.label ? (
|
||||
<span className="truncate font-mono text-[11px] text-muted-foreground">{option.pathHint}</span>
|
||||
<span className="truncate font-mono text-(length:--fs-11) text-muted-foreground">{option.pathHint}</span>
|
||||
) : null}
|
||||
</span>
|
||||
{statusBadge(option.status)}
|
||||
|
|
|
|||
|
|
@ -377,7 +377,7 @@ export const EnvironmentVariablesEditor = forwardRef<EnvironmentVariablesEditorH
|
|||
<TooltipProvider>
|
||||
<div ref={editorRootRef} className="@container/env space-y-2">
|
||||
{attentionCount > 1 ? (
|
||||
<p className="inline-flex items-center gap-1.5 text-[11px] font-medium text-amber-700 dark:text-amber-400">
|
||||
<p className="inline-flex items-center gap-1.5 text-(length:--fs-11) font-medium text-amber-700 dark:text-amber-400">
|
||||
<AlertCircle className="size-3.5" />
|
||||
{attentionCount} bindings need attention
|
||||
</p>
|
||||
|
|
@ -387,8 +387,8 @@ export const EnvironmentVariablesEditor = forwardRef<EnvironmentVariablesEditorH
|
|||
<>
|
||||
{/* Header (desktop only) */}
|
||||
<div className="hidden gap-x-1.5 @[40rem]/env:grid @[40rem]/env:grid-cols-[minmax(160px,2fr)_minmax(240px,3fr)_32px]">
|
||||
<span className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">Name</span>
|
||||
<span className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">Value</span>
|
||||
<span className="text-(length:--fs-11) font-medium uppercase tracking-wide text-muted-foreground">Name</span>
|
||||
<span className="text-(length:--fs-11) font-medium uppercase tracking-wide text-muted-foreground">Value</span>
|
||||
<span />
|
||||
</div>
|
||||
|
||||
|
|
@ -438,7 +438,7 @@ export const EnvironmentVariablesEditor = forwardRef<EnvironmentVariablesEditorH
|
|||
|
||||
{quickBind.length > 0 && !disabled ? (
|
||||
<div className="flex flex-wrap items-center gap-1.5">
|
||||
<span className="inline-flex items-center gap-1 text-[11px] text-muted-foreground/70">
|
||||
<span className="inline-flex items-center gap-1 text-(length:--fs-11) text-muted-foreground/70">
|
||||
<KeyRound className="size-3" />
|
||||
Recently used:
|
||||
</span>
|
||||
|
|
@ -447,7 +447,7 @@ export const EnvironmentVariablesEditor = forwardRef<EnvironmentVariablesEditorH
|
|||
key={secret.id}
|
||||
type="button"
|
||||
onClick={() => bindRecentSecret(secret)}
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 font-mono text-[11px] text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-border px-2 py-0.5 font-mono text-(length:--fs-11) text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground"
|
||||
title={`Bind ${secret.name}`}
|
||||
>
|
||||
+ {secret.name}
|
||||
|
|
@ -488,9 +488,9 @@ export const EnvironmentVariablesEditor = forwardRef<EnvironmentVariablesEditorH
|
|||
</div>
|
||||
) : null}
|
||||
|
||||
{hint ? <p className="text-[11px] text-muted-foreground/70">{hint}</p> : null}
|
||||
{hint ? <p className="text-(length:--fs-11) text-muted-foreground/70">{hint}</p> : null}
|
||||
{rows.some((row) => row.source === "user_secret" && row.userSecretKey) ? (
|
||||
<p className="inline-flex items-start gap-1 text-[11px] text-muted-foreground/70">
|
||||
<p className="inline-flex items-start gap-1 text-(length:--fs-11) text-muted-foreground/70">
|
||||
<UserRound className="mt-0.5 size-3 shrink-0" />
|
||||
<span>
|
||||
User secrets resolve from the user responsible for the run. Required bindings fail until that user
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ function OutputMediaPreview({
|
|||
)}
|
||||
<div className="absolute inset-x-0 bottom-0 bg-black/65 px-2 py-1.5 text-left">
|
||||
<p className="truncate text-xs font-medium text-white" title={filename}>{filename}</p>
|
||||
<p className="truncate text-[10px] text-white/65">{metaBits.join(" · ")}</p>
|
||||
<p className="truncate text-(length:--fs-10) text-white/65">{metaBits.join(" · ")}</p>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
@ -135,7 +135,7 @@ export function IssueOutputSection({ workProducts, resolveCreatorName, onMediaCl
|
|||
|
||||
{rest.length > 0 ? (
|
||||
<div className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">Also produced</p>
|
||||
<p className="text-(length:--fs-11) font-medium uppercase tracking-wide text-muted-foreground">Also produced</p>
|
||||
{mediaRest.length > 0 ? (
|
||||
<div className="grid grid-cols-4 gap-2">
|
||||
{mediaRest.map((item) => (
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export function OutputFileTile({ contentType, className, sizeClassName = "h-8 w-
|
|||
return (
|
||||
<span
|
||||
className={cn(
|
||||
"flex shrink-0 items-center justify-center rounded-md text-[10px] font-semibold tabular-nums",
|
||||
"flex shrink-0 items-center justify-center rounded-md text-(length:--fs-10) font-semibold tabular-nums",
|
||||
sizeClassName,
|
||||
TONE_CLASSES[glyph.tone],
|
||||
className,
|
||||
|
|
|
|||
|
|
@ -70,13 +70,13 @@ export function OutputPrimaryCard({ item, creatorName, onMediaClick }: OutputPri
|
|||
<div className="min-w-0 flex-1">
|
||||
<p className="break-words text-sm font-semibold text-foreground">{filename}</p>
|
||||
{item.degraded ? (
|
||||
<p className="mt-0.5 text-[11px] text-destructive">
|
||||
<p className="mt-0.5 text-(length:--fs-11) text-destructive">
|
||||
Output metadata is unavailable — this file can’t be played or downloaded here.
|
||||
</p>
|
||||
) : (
|
||||
<div className="mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-[11px] text-muted-foreground">
|
||||
<div className="mt-0.5 flex flex-wrap items-center gap-x-1.5 gap-y-0.5 text-(length:--fs-11) text-muted-foreground">
|
||||
{item.isPrimary && (
|
||||
<Badge variant="secondary" className="px-1.5 py-0 text-[10px]">
|
||||
<Badge variant="secondary" className="px-1.5 py-0 text-(length:--fs-10)">
|
||||
Primary
|
||||
</Badge>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export function OutputRow({ item, creatorName }: OutputRowProps) {
|
|||
</p>
|
||||
<p
|
||||
className={cn(
|
||||
"truncate text-[11px]",
|
||||
"truncate text-(length:--fs-11)",
|
||||
item.degraded ? "text-destructive" : "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue