@design-ai/cli
Advanced tools
| <!-- hand-written --> | ||
| --- | ||
| title: Korean B2B density conventions | ||
| applies_to: [web, mobile, all-ui, korean] | ||
| version: 1.0.0 | ||
| last_updated: 2026-07 | ||
| stability: stable | ||
| --- | ||
| # Korean B2B density conventions | ||
| Korean enterprise software — ERP, HR, groupware, admin consoles, financial back-office — is visibly denser than its Western counterpart, and denser again than Korean *consumer* apps. A Western enterprise layout ported unchanged into a Korean B2B product reads as sparse, slow, and "not serious." This file is the density half of the Korean playbook; for consumer density and the broader Korean conventions, see [`knowledge/i18n/korean-product-conventions.md`](korean-product-conventions.md). | ||
| ## Why Korean B2B is denser | ||
| - **Information-per-screen is a value, not a cost.** Power users (accountants, HR admins, operators) work the same screens all day and want everything in view — more rows, more columns, fewer clicks to the next field. Scrolling and pagination read as friction, not breathing room. | ||
| - **The reference points are dense.** 더존, 영림원, SAP-Korea deployments, government e-gov portals, and bank back-office tools set the expectation. Naver Works / Kakao Work admin, Toss Business, and 뱅크샐러드 business consoles are the modern-but-still-dense benchmark. | ||
| - **Hangul carries more meaning per character.** A Korean label is often shorter than its English equivalent for the same content, so the same row holds more without feeling cramped. | ||
| This is a deliberate register, not clutter. The craft is being dense **and** legible — not dense **and** broken. | ||
| ## The density ladder | ||
| Pick a mode per surface and hold it. Do not mix comfortable and compact rows in one table. | ||
| | Mode | Row height (approx) | Use for | | ||
| | --- | --- | --- | | ||
| | **Comfortable** | 48–56px | Consumer-facing, onboarding, marketing-in-product, low-frequency admin | | ||
| | **Cozy** (default KR B2B) | 36–44px | Most enterprise tables, forms, lists — the Korean B2B baseline | | ||
| | **Compact** | 28–32px | Data grids for power users, financial ledgers, high-row-count monitoring | | ||
| Western enterprise defaults to Comfortable; **Korean B2B defaults to Cozy.** Porting in usually means dropping one rung: reduce vertical padding ~15–25% and expect 30–50% more rows per fold. Offer a density toggle (Comfortable / Cozy / Compact) on heavy data surfaces so individual operators can go denser; persist the choice per user. | ||
| ## Tables are the center of gravity | ||
| Korean B2B UIs are table-first. Most screens are a filter bar plus a table. | ||
| - **Many columns are normal.** 8–15 columns is routine; horizontal scroll with a **frozen first column** (and often a frozen header row) beats hiding columns behind a menu. | ||
| - **Compact rows, aligned numerals.** Right-align numbers and currency, use tabular figures, and keep row height in the Cozy/Compact band. See [`knowledge/patterns/money-and-amount.md`](../patterns/money-and-amount.md) for amount formatting. | ||
| - **Inline row actions.** Put edit / delete / detail as compact icon buttons or a trailing action cell, not behind a per-row overflow menu that costs an extra click. | ||
| - **Sticky context.** Freeze the header and the key identity column (사번, 거래처, 전표번호) so the operator never loses the row's identity while scrolling wide. | ||
| - **Totals and subtotals in view.** A pinned footer row with sums/counts is expected on financial and inventory tables — operators reconcile against it constantly. | ||
| - **Zebra or hairline rules, not heavy borders.** At Cozy/Compact density, 1px hairline separators or subtle zebra striping keep rows scannable without adding visual weight. | ||
| ## Forms at density | ||
| - **Label-left (horizontal) layout** is the Korean B2B default for data-entry forms — it packs more fields per vertical space than label-top and matches the ledger-like mental model. Label-top is for consumer/onboarding. | ||
| - **Multi-column forms.** Two or three field columns per row are normal for registration and master-data screens. Group by section with thin dividers, not big gaps. | ||
| - **Tight field spacing.** Reduce inter-field vertical rhythm versus consumer forms; keep it consistent so the grid reads cleanly. See [`knowledge/patterns/form-design.md`](../patterns/form-design.md). | ||
| - **Required/optional density.** Mark required with a compact indicator (asterisk or a small "필수" chip); don't spend a whole helper-text line per field unless the rule is non-obvious. | ||
| - **Keyboard-first.** Power users tab through fields fast. Preserve a logical tab order, support Enter-to-next where appropriate, and don't trap focus in date/select popovers. | ||
| ## Lists, trees, and navigation | ||
| - **Dense list rows** with secondary metadata inline (status chip, date, owner on one line) rather than stacked. See [`knowledge/patterns/list-and-feed.md`](../patterns/list-and-feed.md). | ||
| - **Tree navigation** (조직도, 계정과목, 메뉴 권한) is common and should stay compact — small row height, clear expand affordances, many levels visible at once. | ||
| - **Persistent side navigation** with dense, possibly two-level menus is expected over hamburger-hidden nav; enterprise users want the whole map visible. This is the opposite of the consumer preference noted in [`korean-product-conventions.md`](korean-product-conventions.md). | ||
| ## Typography at density | ||
| - **Base size can drop, but not below legibility.** 13–14px body is common in KR B2B tables (vs 16px consumer). Do not go below ~12px for Hangul primary content — Hangul syllable blocks lose legibility faster than Latin at small sizes. | ||
| - **Line-height stays generous relative to size.** Even dense Korean text needs ~1.4–1.5 line-height for the syllable blocks to breathe; do not crush leading to save space. See [`knowledge/i18n/korean-typography.md`](korean-typography.md). | ||
| - **Numerals: tabular, aligned.** Financial density depends on figures lining up. | ||
| - **Truncate with intent.** Ellipsize long values with a tooltip/title for the full string rather than wrapping and breaking row rhythm. | ||
| ## Density must not break accessibility | ||
| Density is the constraint; accessibility is the floor. When they conflict, accessibility wins. | ||
| - **Touch targets.** On touch/hybrid B2B (tablets on the floor, POS, hospital carts), keep interactive targets ≥ 44×44px *hit area* even when the visual row is compact — expand the clickable area beyond the visible cell rather than shrinking the target. | ||
| - **Contrast holds at every density.** Hairline separators and secondary text must still meet WCAG contrast; dense does not mean low-contrast gray-on-gray. See [`knowledge/a11y/contrast.md`](../a11y/contrast.md). | ||
| - **Focus visibility.** A visible focus ring is non-negotiable for keyboard-driven data entry; ensure it is not clipped by tight row borders. See [`knowledge/a11y/keyboard-and-focus.md`](../a11y/keyboard-and-focus.md). | ||
| - **Density toggle as an a11y affordance.** Offering Comfortable mode is itself an accessibility accommodation for users who need larger targets and text. | ||
| ## Tokens consumed | ||
| ``` | ||
| --space-2xs, --space-xs (dense row padding, inter-field gaps) | ||
| --space-sm (section spacing at density) | ||
| --row-height-compact (or --space-based row sizing) | ||
| --font-size-sm (13–14px dense body) | ||
| --line-height-normal (~1.4–1.5 for Hangul) | ||
| --color-border-subtle (hairline separators) | ||
| --color-bg-subtle (zebra striping) | ||
| --color-text-secondary (inline metadata) | ||
| --color-text-tabular (aligned numerals) | ||
| ``` | ||
| Define a **density scale** as tokens (comfortable / cozy / compact row heights + padding) so the toggle flips a token set, not ad-hoc per-component values. | ||
| ## Don't | ||
| - Don't ship Western enterprise comfortable-density defaults unchanged into a Korean B2B product — it reads as sparse and unserious. | ||
| - Don't hide columns behind menus to avoid width — Korean power users prefer horizontal scroll with frozen columns. | ||
| - Don't mix row-height modes within one table. | ||
| - Don't crush Hangul below ~12px or crush line-height to gain rows — legibility breaks before the space saved is worth it. | ||
| - Don't let density erode contrast, focus rings, or touch-target hit areas. | ||
| - Don't bury per-row actions behind an overflow menu on high-frequency screens — inline them. | ||
| - Don't apply consumer nav patterns (hamburger, hidden tabs) to enterprise — surface the full dense menu. | ||
| ## Cross-reference | ||
| - [`knowledge/i18n/korean-product-conventions.md`](korean-product-conventions.md) — consumer density and the broader Korean conventions this file specializes from | ||
| - [`knowledge/i18n/korean-typography.md`](korean-typography.md) — Hangul sizing and line-height at density | ||
| - [`knowledge/patterns/form-design.md`](../patterns/form-design.md) — label-left, multi-column, dense forms | ||
| - [`knowledge/patterns/list-and-feed.md`](../patterns/list-and-feed.md) — dense list rows and data grids | ||
| - [`knowledge/patterns/money-and-amount.md`](../patterns/money-and-amount.md) — tabular numerals and aligned amounts | ||
| - [`knowledge/a11y/contrast.md`](../a11y/contrast.md), [`knowledge/a11y/keyboard-and-focus.md`](../a11y/keyboard-and-focus.md) — the accessibility floor density must respect |
| <!-- hand-written --> | ||
| --- | ||
| title: Async control patterns | ||
| applies_to: [web, mobile, all-ui] | ||
| version: 1.0.0 | ||
| last_updated: 2026-07 | ||
| stability: stable | ||
| --- | ||
| # Async control patterns | ||
| Every action that talks to a server has an in-flight life. This file is about that life — the moment between the tap and the answer — not about the error screen at the end (see [`patterns/error-states.md`](error-states.md) for that). Get the in-flight state wrong and you get the two most common async bugs in product UIs: double submits and stuck spinners. | ||
| ## The async action lifecycle | ||
| Every async action moves through the same four states. Model them explicitly; do not infer "loading" from the absence of data. | ||
| ``` | ||
| idle ──trigger──▶ pending ──┬──▶ success ──▶ idle | ||
| ▲ │ | ||
| └─────────────────────────┴──▶ error ────▶ idle (retryable) | ||
| ``` | ||
| | State | The control shows | The user can | | ||
| | --- | --- | --- | | ||
| | **idle** | Its normal, enabled label | Trigger the action | | ||
| | **pending** | Busy affordance + disabled | Wait, or cancel (if cancellable) | | ||
| | **success** | Brief confirmation, then idle | Continue | | ||
| | **error** | Recovery affordance | Retry or recover — see `error-states.md` | | ||
| Rule: a control never sits in `pending` forever. Every request has a timeout that forces it to `error`. | ||
| ## Action controls during pending | ||
| The trigger control (button, menu item, toggle) is where most async bugs live. | ||
| | Do | Don't | | ||
| | --- | --- | | ||
| | Disable the control while its own action is in flight | Leave it clickable and hope | | ||
| | Show a busy affordance **inside or beside** the control | Replace the whole screen with a spinner for a single button | | ||
| | Keep the label readable — swap to a present-progressive verb | Blank the label to just a spinner (the user forgets what they clicked) | | ||
| | Restore the control on success **and** error | Leave it disabled after a failed request | | ||
| Label swap, Korean and English: | ||
| | Idle | Pending | Done | | ||
| | --- | --- | --- | | ||
| | 저장 | 저장 중… | 저장됨 | | ||
| | 불러오기 | 불러오는 중… | — | | ||
| | 결제하기 | 결제 처리 중… | 결제 완료 | | ||
| | 제출 | 제출 중… | — | | ||
| ``` | ||
| ┌─────────────────┐ ┌─────────────────┐ | ||
| │ 저장 │ → │ ◌ 저장 중… │ (disabled, spinner leads label) | ||
| └─────────────────┘ └─────────────────┘ | ||
| ``` | ||
| ## Double-submit prevention | ||
| The single most important async rule: **a control that started an action cannot start it again until that action resolves.** Disabling on `pending` handles the fast double-tap. Also guard the handler itself, because disabled is a UI state that a determined tap (or a slow render) can beat. | ||
| ```tsx | ||
| function SubmitButton({ onSubmit }) { | ||
| const [status, setStatus] = useState("idle"); // idle | pending | error | ||
| async function handleClick() { | ||
| if (status === "pending") return; // guard: not just the disabled attr | ||
| setStatus("pending"); | ||
| try { | ||
| await onSubmit(); | ||
| setStatus("idle"); | ||
| } catch (err) { | ||
| setStatus("error"); // hand off to error-states.md | ||
| } | ||
| } | ||
| return ( | ||
| <Button onClick={handleClick} disabled={status === "pending"} aria-busy={status === "pending"}> | ||
| {status === "pending" ? "저장 중…" : "저장"} | ||
| </Button> | ||
| ); | ||
| } | ||
| ``` | ||
| For money and irreversible actions (payment, transfer, delete), double-submit guarding is a correctness requirement, not a nicety. Pair the client guard with a server-side idempotency key — cite [`patterns/money-and-amount.md`](money-and-amount.md). | ||
| ## Choosing a loading affordance by duration | ||
| Match the indicator to how long the wait actually is. Guessing wrong is worse than no indicator. | ||
| | Expected wait | Affordance | Why | | ||
| | --- | --- | --- | | ||
| | < 100ms | **Nothing** | Faster than perception; a flashed spinner reads as a glitch | | ||
| | 100ms – 1s | **In-place busy** (button spinner, subtle) | Confirms the tap registered | | ||
| | 1s – 10s | **Skeleton** (for content) or **progress** (for known-length work) | Shows shape/position; feels faster than a spinner | | ||
| | > 10s | **Progress + cancel + background option** | Let the user leave and be notified | | ||
| | Unknown length | **Indeterminate spinner with a timeout** | Never an infinite bar | | ||
| Spinner vs skeleton: a spinner says "something is happening"; a skeleton says "*this* is what's coming and where." Prefer skeletons for content regions (lists, cards, detail panes) — see [`patterns/list-and-feed.md`](list-and-feed.md). Reserve spinners for actions and small inline waits. | ||
| Anti-flicker: if you show a delayed spinner (only after 100–300ms), also hold it for a minimum (~300ms) once shown, so a request that resolves at 310ms doesn't flash. Delay-in, min-hold-out. | ||
| ## Optimistic updates | ||
| Apply the change in the UI immediately, before the server confirms, then reconcile. | ||
| Use optimistic when: the action almost always succeeds, is cheap to reverse, and the wait would break flow — likes, toggles, reordering, adding a to-do, marking read. | ||
| Do **not** use optimistic when: the action is money, irreversible, or the server is the source of truth for the result (payment, booking a seat, submitting an exam). There, show real `pending` and wait. | ||
| ``` | ||
| tap ─▶ update UI now ─▶ fire request ─┬─ ok: keep, drop the "syncing" mark | ||
| └─ fail: roll back to prior value + show why | ||
| ``` | ||
| Rules: | ||
| - Keep the pre-action value so you can roll back exactly. | ||
| - Mark optimistic items as unconfirmed (subtle) until the server agrees, so a rollback isn't a jarring surprise. | ||
| - On rollback, tell the user what reverted and why — a silent snap-back looks like a bug. | ||
| ## Debounce and throttle for async-triggering input | ||
| Input that fires requests as the user types or drags must be rate-limited, or it floods the server and races itself. | ||
| | Technique | Fires | Use for | | ||
| | --- | --- | --- | | ||
| | **Debounce** (wait for a pause) | Once, after input stops for N ms | Search-as-you-type (250–350ms), autosave (500ms–2s) | | ||
| | **Throttle** (at most every N ms) | On a steady cadence | Drag/scroll-driven fetches, live position updates | | ||
| | **Leading + trailing** | Immediately, then once more at the end | Feels responsive but still settles | | ||
| Debounce is about *when to fire*; cancellation (next section) is about *what to do with requests already in flight*. You need both. | ||
| ## Cancellation and out-of-order responses | ||
| Two requests fired in order can return out of order. Without cancellation, an older, slower response overwrites a newer one — the classic "I typed 서울, it shows 서" bug. | ||
| - Cancel the previous in-flight request when a new one supersedes it (`AbortController` on the web). | ||
| - Cancel in-flight requests when the component unmounts or the user navigates away. | ||
| - If you cannot cancel, **guard on apply**: tag each request and ignore any response that isn't the latest. | ||
| ```tsx | ||
| useEffect(() => { | ||
| const controller = new AbortController(); | ||
| fetchResults(query, { signal: controller.signal }) | ||
| .then(setResults) | ||
| .catch(ignoreAbort); | ||
| return () => controller.abort(); // supersede on new query / unmount | ||
| }, [query]); | ||
| ``` | ||
| ## Concurrency policy | ||
| When the same action can be triggered while one is running, decide the policy on purpose: | ||
| | Policy | Behavior | Use for | | ||
| | --- | --- | --- | | ||
| | **Block** | Ignore new triggers until the current resolves | Submits, payments (with double-submit guard) | | ||
| | **Latest-wins** | Cancel the running one, keep only the newest | Search, filters, autosave | | ||
| | **Queue** | Run in order, one at a time | Ordered writes that must all land | | ||
| | **Parallel** | Let all run | Independent reads | | ||
| Default to **block** for writes and **latest-wins** for reads unless you have a reason otherwise. | ||
| ## Timeouts and the stuck-spinner failure | ||
| A spinner with no timeout is a trap: on a dropped connection it spins forever and the user is stuck. | ||
| - Give every request a client timeout (e.g. 10–30s by operation). | ||
| - On timeout, transition to `error` with a retry — hand off to [`patterns/error-states.md`](error-states.md) (network/server section, retry with backoff). | ||
| - For genuinely long work (video processing, exports), don't hold a spinner — move to a **background job** pattern: acknowledge, let the user leave, notify on completion. | ||
| ## Perceived performance | ||
| The felt speed of an async UI is mostly about what you show during the wait: | ||
| - **Optimistic UI** — instant for reversible actions (above). | ||
| - **Skeletons** — for content; show structure, not a void. | ||
| - **Stale-while-revalidate** — show the last known data immediately, refresh in the background, swap in quietly. Mark it subtly as refreshing so a change isn't startling. | ||
| - **Progressive reveal** — render what's ready (shell, then data) instead of blocking on the slowest piece. | ||
| ## Tokens consumed | ||
| ``` | ||
| --color-accent (spinner, progress fill) | ||
| --color-text-secondary (pending label, "저장 중…") | ||
| --color-text-tertiary (unconfirmed / optimistic mark, "동기화 중") | ||
| --color-bg-subtle (skeleton base) | ||
| --color-bg-elevated (skeleton shimmer highlight) | ||
| --radius-md | ||
| --space-xs, --space-sm | ||
| --duration-fast (spinner delay-in / min-hold) | ||
| --easing-standard | ||
| ``` | ||
| ## Accessibility | ||
| - Set `aria-busy="true"` on a control or region while its action is pending; clear it when resolved. | ||
| - Announce state changes politely: a visually-hidden `role="status"` (`aria-live="polite"`) region saying "저장 중" then "저장됨". Do not use `assertive` for routine progress — reserve that for errors (see `error-states.md`). | ||
| - Keep the control's accessible name stable and meaningful during pending — the label swap ("저장" → "저장 중…") is fine; an icon-only spinner with no name is not. | ||
| - On success that removes the control (e.g. a submit that navigates), move focus deliberately to the next logical element; never drop focus to `<body>`. | ||
| - Respect `prefers-reduced-motion`: swap spinners/shimmer for a static or fade indicator. | ||
| - Disabled-while-pending must still be perceivable — don't rely on color alone; the busy affordance carries the meaning. | ||
| ## Korean considerations | ||
| Per [`knowledge/i18n/korean-product-conventions.md`](../i18n/korean-product-conventions.md): | ||
| - Progress labels use the present-progressive `~중…`: "저장 중…", "불러오는 중…", "처리 중…", "결제 처리 중…". | ||
| - Keep pending labels short — Korean verbs + `중…` stay compact, so the button width rarely jumps. | ||
| - For payment and transfer flows, show explicit real `pending` (never optimistic) and a clear "결제 처리 중…" state; cite [`knowledge/i18n/korean-payments.md`](../i18n/korean-payments.md) for the surrounding flow and failure messages. | ||
| - Dense Korean B2B layouts favor in-place busy affordances (inline spinner, row-level skeleton) over full-page blocking overlays — cite [`knowledge/i18n/korean-product-conventions.md`](../i18n/korean-product-conventions.md) on density. | ||
| ## Don't | ||
| - Don't leave a control clickable during its own async action — the double-submit bug. | ||
| - Don't guard double-submit with the disabled attribute alone; guard the handler too. | ||
| - Don't show a spinner for a sub-100ms wait — it reads as a flicker. | ||
| - Don't show a spinner that can spin forever — every request has a timeout. | ||
| - Don't blank a button to a bare spinner; keep a readable pending label. | ||
| - Don't use optimistic updates for money, payments, or irreversible actions. | ||
| - Don't let an older response overwrite a newer one — cancel or guard-on-apply. | ||
| - Don't hold a full-screen spinner for long work — move it to a background job with notify. | ||
| - Don't roll back an optimistic change silently — say what reverted and why. | ||
| - Don't announce routine progress with `aria-live="assertive"` — that's for errors. | ||
| ## Cross-reference | ||
| - [`knowledge/patterns/error-states.md`](error-states.md) — where the `error` state goes: recovery, retry-with-backoff, network/server messages | ||
| - [`knowledge/patterns/form-design.md`](form-design.md) — submit buttons, validation-in-flight, form-level pending | ||
| - [`knowledge/patterns/list-and-feed.md`](list-and-feed.md) — skeletons, pull-to-refresh, infinite scroll loading | ||
| - [`knowledge/patterns/empty-states.md`](empty-states.md) — the resolved-but-no-data end state, distinct from loading | ||
| - [`knowledge/patterns/money-and-amount.md`](money-and-amount.md) — why money actions use real pending + idempotency, never optimistic | ||
| - [`knowledge/i18n/korean-payments.md`](../i18n/korean-payments.md) — payment in-flight and failure states |
| { | ||
| "name": "design-ai", | ||
| "version": "4.57.0", | ||
| "version": "4.58.0", | ||
| "description": "Senior product designer for any AI coding agent. 20 skills, 17 commands, 4 review agents covering UI/UX, website improvement, design systems, motion, illustration, print, video, game UI, conversational, and spatial design. Korean market depth.", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -31,3 +31,3 @@ // `design-ai route` — recommend commands, skills, and knowledge for a task brief. | ||
| console.log(" --limit N Maximum route recommendations to return, 1-10. Default: 3"); | ||
| console.log(" --explain Include route scoring and reference coverage details"); | ||
| console.log(" --explain Include route scoring, reference coverage, and related knowledge"); | ||
| console.log(" --eval-template Generate a runnable route eval checkpoint JSON template"); | ||
@@ -82,2 +82,13 @@ console.log(" --eval Run deterministic route-selection checkpoint cases"); | ||
| } | ||
| if (explain) { | ||
| const related = route.relatedKnowledge || []; | ||
| if (related.length === 0) { | ||
| console.log(" related: (none)"); | ||
| } else { | ||
| for (const item of related) { | ||
| console.log(` related: ${item.id} ${dim(`(score ${item.score.toFixed(2)})`)}`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
@@ -216,2 +227,3 @@ | ||
| limit: parsed.limit, | ||
| explain: parsed.explain, | ||
| }); | ||
@@ -218,0 +230,0 @@ |
@@ -112,3 +112,3 @@ // Corpus knowledge recall (retrieval-augmentation) for `design-ai prompt`/`pack` | ||
| const hits = query | ||
| ? rankedSearchCorpus({ query, designAiPath, dirs, limit: recallLimit }).hits | ||
| ? rankedSearchCorpus({ query, designAiPath, dirs, limit: recallLimit, excludeGeneratedIndex: true }).hits | ||
| : []; | ||
@@ -154,3 +154,3 @@ | ||
| const corpusHits = normalizedQuery | ||
| ? rankedSearchCorpus({ query: normalizedQuery, designAiPath, dirs, limit }).hits | ||
| ? rankedSearchCorpus({ query: normalizedQuery, designAiPath, dirs, limit, excludeGeneratedIndex: true }).hits | ||
| : []; | ||
@@ -157,0 +157,0 @@ const corpusSelected = corpusHits.map((hit) => ({ |
+62
-5
@@ -10,2 +10,3 @@ // Deterministic task routing for `design-ai route`. | ||
| import { parseBriefSourceFlag } from "./brief.mjs"; | ||
| import { rankedSearchCorpus } from "./search-ranked.mjs"; | ||
| import { suggestNearest, unknownOptionMessage } from "./suggest.mjs"; | ||
@@ -39,2 +40,13 @@ | ||
| const ROUTE_EVAL_DEFAULT_LIMIT = 3; | ||
| // Advisory "Related knowledge" recall (docs/AI-LEARNING-PHASE2.md, "Phase A | ||
| // implementation review" Q3): under `--explain` only, surface the top corpus | ||
| // knowledge/ files recalled by the shipped deterministic lexical scorer that the | ||
| // route's curated `knowledge` list does NOT already point to. Purely additive — | ||
| // it never changes route selection, ids, scores, or the curated list. Restricted | ||
| // to knowledge/ so it surfaces design knowledge, not docs/QUICKSTART. The recall | ||
| // pulls RELATED_KNOWLEDGE_RECALL_LIMIT candidates then keeps the top | ||
| // RELATED_KNOWLEDGE_KEEP after excluding the curated set. | ||
| const RELATED_KNOWLEDGE_DIRS = ["knowledge"]; | ||
| const RELATED_KNOWLEDGE_RECALL_LIMIT = 10; | ||
| const RELATED_KNOWLEDGE_KEEP = 3; | ||
| const CONFIDENCE_ORDER = { | ||
@@ -461,2 +473,31 @@ low: 1, | ||
| // Advisory related-knowledge recall for a single route. REUSES rankedSearchCorpus | ||
| // (the shipped deterministic lexical scorer — score desc, id asc) scoped to | ||
| // knowledge/, excludes the route's curated knowledge relPaths, and keeps the top | ||
| // RELATED_KNOWLEDGE_KEEP remaining. Returns [] on empty brief or no hits. | ||
| function relatedKnowledgeFor({ brief, sourceRoot, curatedRelPaths }) { | ||
| const query = String(brief || "").trim(); | ||
| if (!query) return []; | ||
| const curated = new Set(curatedRelPaths); | ||
| const { hits } = rankedSearchCorpus({ | ||
| query, | ||
| dirs: RELATED_KNOWLEDGE_DIRS, | ||
| limit: RELATED_KNOWLEDGE_RECALL_LIMIT, | ||
| designAiPath: sourceRoot, | ||
| // Recall/injection surface: keep generated index/meta docs (COVERAGE.md, | ||
| // INDEX.md, docs/reference/*) out of the advisory related-knowledge list. | ||
| excludeGeneratedIndex: true, | ||
| }); | ||
| return hits | ||
| .filter((hit) => !curated.has(hit.relPath)) | ||
| .slice(0, RELATED_KNOWLEDGE_KEEP) | ||
| .map((hit) => ({ | ||
| id: hit.relPath, | ||
| score: hit.score, | ||
| matchedTokens: hit.matchedTokens, | ||
| })); | ||
| } | ||
| function routeToResult(route, sourceRoot, hits, options = {}) { | ||
@@ -473,2 +514,13 @@ const command = route.command | ||
| // Advisory related-knowledge is attached ONLY when explain is requested, so the | ||
| // default `route` JSON stays byte-unchanged. `knowledge` already merges | ||
| // COMMON_KNOWLEDGE + route.knowledge, so its relPaths are the dedupe set. | ||
| const relatedKnowledge = options.explain | ||
| ? relatedKnowledgeFor({ | ||
| brief: options.brief || "", | ||
| sourceRoot, | ||
| curatedRelPaths: knowledge.map((entry) => entry.path), | ||
| }) | ||
| : null; | ||
| return { | ||
@@ -486,2 +538,3 @@ id: route.id, | ||
| explanation: routeExplanation({ hits, command, skills, agents, knowledge, forced, fallback, catalog }), | ||
| ...(relatedKnowledge ? { relatedKnowledge } : {}), | ||
| ...(forced ? { forced: true } : {}), | ||
@@ -509,6 +562,6 @@ ...(fallback ? { fallback: true } : {}), | ||
| function fallbackResult(sourceRoot) { | ||
| function fallbackResult(sourceRoot, options = {}) { | ||
| const route = ROUTES.find((item) => item.id === "design-from-brief"); | ||
| return { | ||
| ...routeToResult(route, sourceRoot, [], { fallback: true }), | ||
| ...routeToResult(route, sourceRoot, [], { fallback: true, ...options }), | ||
| confidence: "low", | ||
@@ -518,6 +571,10 @@ }; | ||
| export function routeBrief({ brief, sourceRoot, limit = 3 }) { | ||
| export function routeBrief({ brief, sourceRoot, limit = 3, explain = false }) { | ||
| const normalized = brief.trim(); | ||
| if (!normalized) return []; | ||
| // Only compute advisory related-knowledge under --explain; keep the default | ||
| // routing (keyword scoring, ordering, selection) completely unchanged. | ||
| const resultOptions = explain ? { explain: true, brief: normalized } : {}; | ||
| const scored = ROUTES | ||
@@ -531,6 +588,6 @@ .map((route) => ({ route, hits: keywordHits(normalized, route.keywords) })) | ||
| .slice(0, limit) | ||
| .map((item) => routeToResult(item.route, sourceRoot, item.hits)); | ||
| .map((item) => routeToResult(item.route, sourceRoot, item.hits, resultOptions)); | ||
| if (scored.length > 0) return scored; | ||
| return [fallbackResult(sourceRoot)]; | ||
| return [fallbackResult(sourceRoot, resultOptions)]; | ||
| } | ||
@@ -537,0 +594,0 @@ |
@@ -27,2 +27,18 @@ // Ranked (BM25-style) corpus search for `design-ai search --ranked`, plus the | ||
| // Predicate for GENERATED index/meta docs that must be kept out of the RECALL / | ||
| // context-injection layer (pack/prompt --with-recall, learn --recall corpus side, | ||
| // route --explain related knowledge). These files rank on keyword density but are | ||
| // meta/index tables, not design knowledge worth injecting into an agent's context. | ||
| // Rule: true when the basename is `COVERAGE.md` or `INDEX.md` (generated coverage | ||
| // table / component index), OR the forward-slash-normalized path starts with | ||
| // `docs/reference/` (generated upstream-reference pages). Raw `search --ranked` | ||
| // does NOT apply this — a user explicitly searching may legitimately want an index. | ||
| export function isGeneratedIndexDoc(relPath) { | ||
| const normalized = String(relPath || "").replace(/\\/g, "/"); | ||
| const basename = normalized.slice(normalized.lastIndexOf("/") + 1); | ||
| return basename === "COVERAGE.md" | ||
| || basename === "INDEX.md" | ||
| || normalized.startsWith("docs/reference/"); | ||
| } | ||
| // N = max(limit*5, 25): the number of top lexical candidates handed to the embedding | ||
@@ -70,2 +86,8 @@ // reranker. Documented constant (docs/AI-LEARNING-PHASE2.md, Phase B CLI wiring). | ||
| indexDir = defaultIndexDir(), | ||
| // Opt-in RECALL filter: when true, drop generated index/meta docs | ||
| // (isGeneratedIndexDoc) BEFORE applying `limit`, so the limit fills with real | ||
| // knowledge instead of index files. Default false keeps raw `search --ranked` | ||
| // byte-unchanged. Filtering before the limit preserves determinism (score desc, | ||
| // id asc) — the rank pass already orders fully, we only remove excluded ids. | ||
| excludeGeneratedIndex = false, | ||
| } = {}) { | ||
@@ -76,3 +98,13 @@ const documents = collectCorpusDocuments({ designAiPath, dirs }); | ||
| const hits = rankLexical(query, stats, { limit }).map((hit) => ({ | ||
| // When excluding, rank the FULL candidate pool first (limit = documents.length) | ||
| // so that filtering out index docs cannot let a real-knowledge hit fall off the | ||
| // pre-limit cutoff; then re-apply `limit`. Ordering is unchanged (score desc, id asc). | ||
| const ranked = rankLexical(query, stats, { | ||
| limit: excludeGeneratedIndex ? documents.length : limit, | ||
| }); | ||
| const filtered = excludeGeneratedIndex | ||
| ? ranked.filter((hit) => !isGeneratedIndexDoc(hit.id)).slice(0, limit) | ||
| : ranked; | ||
| const hits = filtered.map((hit) => ({ | ||
| relPath: hit.id, | ||
@@ -79,0 +111,0 @@ file: path.join(designAiPath, hit.id), |
| # External Publication Status | ||
| > Checked: 2026-07-02 | ||
| > Checked: 2026-07-03 | ||
| > Scope: npm registry, GitHub Pages, Homebrew tap, VS Code Marketplace, Claude/Codex MCP | ||
@@ -8,3 +8,3 @@ | ||
| Local release readiness is verified, GitHub Pages docs are publicly reachable, GitHub Release `v4.56.0` is published, and the Homebrew tap formula points at the `v4.56.0` release source tarball with a verified SHA-256. npm is publicly published at `@design-ai/cli@4.56.0`; publish run `28569283984` succeeded with provenance and the public registry smoke passed. The VS Code extension `sungjin.design-ai-vscode` is published to the VS Code Marketplace at version `0.4.1`; the Gallery API is reachable. The public npm MCP entrypoint and the local Claude Code / Codex MCP client registrations were rechecked on 2026-07-02. | ||
| npm is publicly published at `@design-ai/cli@4.57.0` (npm dist-tag `latest` = `4.57.0`); publish run `28663430171` from tag `v4.57.0` succeeded with provenance and all pre-publish gates green (8 audits, CLI unit tests, release self-tests, package contents, and the packed-tarball installed-package smoke on the 4.57.0 tarball). The automated post-publish live registry smoke step failed on a stale learn-relevance token-order assertion in `tools/audit/registry-smoke.py` — a verification-tool bug fixed on `main` in `710656a`, not a package defect; the published package is validated by the pre-publish packed-tarball smoke. GitHub Release `v4.57.0` is published, and the Homebrew tap formula points at the `v4.57.0` release source tarball with a verified SHA-256. The VS Code extension `sungjin.design-ai-vscode` remains published at `0.4.1`. GitHub Pages docs are publicly reachable. | ||
@@ -15,8 +15,8 @@ ## Results | ||
| |---|---|---|---| | ||
| | npm registry | `@design-ai/cli` | Published latest is `4.56.0`; publish run `28569283984` succeeded and public registry smoke passed for `@design-ai/cli@4.56.0`. | `evidence/cli-logs/npm-registry-status.log`, `evidence/cli-logs/npm-registry-smoke.log`, `evidence/cli-logs/npm-publish-v4.56.0-success.log` | | ||
| | npm registry | `@design-ai/cli` | Published latest is `4.57.0`; publish run `28663430171` (tag `v4.57.0`) succeeded with provenance. Pre-publish packed-tarball smoke passed on the 4.57.0 tarball; the post-publish live registry smoke failed on a stale assertion (fixed on `main` `710656a`). | publish run `28663430171`; `npm view @design-ai/cli version` → `4.57.0` | | ||
| | GitHub Pages | `https://sungjin9288.github.io/design-ai/` | Published and reachable: HTTP `200`, design-ai MkDocs page rendered | `evidence/cli-logs/github-pages-status.log` | | ||
| | Homebrew tap | `Formula/design-ai.rb` | Formula pinned to `v4.56.0` release source tarball with SHA-256 `507d2519296497defcd486c0ffc2b5164967a0bc540ddc31bc89502350688212`; Ruby syntax and `brew style` passed | `evidence/cli-logs/homebrew-formula-status.log` | | ||
| | Homebrew tap | `Formula/design-ai.rb` | Formula pinned to `v4.57.0` release source tarball with SHA-256 `c1fed279ed7bc2daf42473bd9a68cf3fa6df6823fe3390b2f2ccee8625407559` (recomputed from the published tag tarball) | `Formula/design-ai.rb` | | ||
| | VS Code Marketplace | `sungjin.design-ai-vscode` | Published: run `28431571256` published `v0.4.1`, and the Marketplace Gallery API returned visible version `0.4.1` on 2026-07-02. | `evidence/cli-logs/vscode-marketplace-status.log`, `evidence/cli-logs/vscode-marketplace-secret-status.log`, `evidence/cli-logs/vscode-extension-vsce-package.log`, `evidence/cli-logs/vscode-publish-workflow-status.log` | | ||
| | GitHub Release | `v4.56.0` | Published with release tarball asset `design-ai-cli-4.56.0.tgz` | `evidence/cli-logs/github-release-v4.56.0.log` | | ||
| | MCP server | `@design-ai/cli@4.56.0` / local clone | Public npm `design-ai-mcp` responds to initialize and tools/list with 10 tools; local Codex and Claude Code both report `design-ai` MCP as configured and connected. | `evidence/cli-logs/npm-registry-smoke.log`, `evidence/cli-logs/design-ai-mcp-client-status.log` | | ||
| | GitHub Release | `v4.57.0` | Published (not draft/prerelease) for tag `v4.57.0` at commit `4be46d7` | `gh release view v4.57.0` | | ||
| | MCP server | `@design-ai/cli@4.57.0` / local clone | Public npm `design-ai-mcp` responds to initialize and tools/list with 10 tools; local Codex and Claude Code both report `design-ai` MCP as configured and connected. | `evidence/cli-logs/npm-registry-smoke.log`, `evidence/cli-logs/design-ai-mcp-client-status.log` | | ||
@@ -23,0 +23,0 @@ ## Interpretation |
@@ -15,3 +15,3 @@ <!-- generated by tools/audit/check-coverage.py — do not hand-edit --> | ||
| | --- | --- | --- | | ||
| | Knowledge files | 92 | 77 hand-written + 15 generated | | ||
| | Knowledge files | 94 | 79 hand-written + 15 generated | | ||
| | Skills (PLAYBOOK + SKILL) | 20 | 20 with verification phase | | ||
@@ -34,3 +34,3 @@ | Worked examples | 221 | | | ||
| | `game-ui` | 5 | 5 | 0 | | ||
| | `i18n` | 6 | 6 | 0 | | ||
| | `i18n` | 7 | 7 | 0 | | ||
| | `icons` | 1 | 0 | 1 | | ||
@@ -40,3 +40,3 @@ | `illustration` | 5 | 5 | 0 | | ||
| | `motion` | 6 | 6 | 0 | | ||
| | `patterns` | 30 | 24 | 6 | | ||
| | `patterns` | 31 | 25 | 6 | | ||
| | `platforms` | 1 | 1 | 0 | | ||
@@ -55,3 +55,3 @@ | `print` | 6 | 6 | 0 | | ||
| | --- | --- | --- | --- | | ||
| | [knowledge/COVERAGE.md](../knowledge/COVERAGE.md) | 741 | generated | Coverage report | | ||
| | [knowledge/COVERAGE.md](../knowledge/COVERAGE.md) | 743 | generated | Coverage report | | ||
| | [knowledge/PRINCIPLES.md](../knowledge/PRINCIPLES.md) | 108 | hand-written | Design-AI principles | | ||
@@ -115,5 +115,6 @@ | ||
| | [knowledge/i18n/korean-app-store-visual.md](../knowledge/i18n/korean-app-store-visual.md) | 223 | hand-written | Korean app store visual design | | ||
| | [knowledge/i18n/korean-density-conventions.md](../knowledge/i18n/korean-density-conventions.md) | 108 | hand-written | Korean B2B density conventions | | ||
| | [knowledge/i18n/korean-document-style.md](../knowledge/i18n/korean-document-style.md) | 301 | hand-written | Korean document style | | ||
| | [knowledge/i18n/korean-payments.md](../knowledge/i18n/korean-payments.md) | 211 | hand-written | Korean payments | | ||
| | [knowledge/i18n/korean-product-conventions.md](../knowledge/i18n/korean-product-conventions.md) | 96 | hand-written | Korean product UX conventions | | ||
| | [knowledge/i18n/korean-product-conventions.md](../knowledge/i18n/korean-product-conventions.md) | 98 | hand-written | Korean product UX conventions | | ||
| | [knowledge/i18n/korean-publishing.md](../knowledge/i18n/korean-publishing.md) | 139 | hand-written | Korean app store & publishing requirements | | ||
@@ -159,2 +160,3 @@ | [knowledge/i18n/korean-typography.md](../knowledge/i18n/korean-typography.md) | 123 | hand-written | Korean (Hangul) typography for product UI | | ||
| | --- | --- | --- | --- | | ||
| | [knowledge/patterns/async-control.md](../knowledge/patterns/async-control.md) | 233 | hand-written | Async control patterns | | ||
| | [knowledge/patterns/auth-flow-design.md](../knowledge/patterns/auth-flow-design.md) | 316 | hand-written | Authentication flow design | | ||
@@ -171,4 +173,4 @@ | [knowledge/patterns/b2b-onboarding-flows.md](../knowledge/patterns/b2b-onboarding-flows.md) | 182 | hand-written | B2B onboarding flows | | ||
| | [knowledge/patterns/empty-states.md](../knowledge/patterns/empty-states.md) | 263 | hand-written | Empty states | | ||
| | [knowledge/patterns/error-states.md](../knowledge/patterns/error-states.md) | 318 | hand-written | Error states | | ||
| | [knowledge/patterns/form-design.md](../knowledge/patterns/form-design.md) | 237 | hand-written | Form design patterns | | ||
| | [knowledge/patterns/error-states.md](../knowledge/patterns/error-states.md) | 319 | hand-written | Error states | | ||
| | [knowledge/patterns/form-design.md](../knowledge/patterns/form-design.md) | 239 | hand-written | Form design patterns | | ||
| | [knowledge/patterns/information-architecture.md](../knowledge/patterns/information-architecture.md) | 341 | hand-written | Information architecture | | ||
@@ -175,0 +177,0 @@ | [knowledge/patterns/landing-hero-design.md](../knowledge/patterns/landing-hero-design.md) | 283 | hand-written | Landing hero design | |
@@ -61,2 +61,4 @@ <!-- hand-written --> | ||
| For enterprise / B2B density (denser again — ERP, HR, groupware, admin, financial back-office), see [`knowledge/i18n/korean-density-conventions.md`](korean-density-conventions.md). | ||
| ## Color associations | ||
@@ -63,0 +65,0 @@ |
@@ -315,2 +315,3 @@ <!-- hand-written --> | ||
| - [`knowledge/patterns/async-control.md`](async-control.md) — the in-flight state before the error: pending, retry-on-timeout, double-submit | ||
| - [`knowledge/patterns/empty-states.md`](empty-states.md) — when there's no data, but it's not an error | ||
@@ -317,0 +318,0 @@ - [`knowledge/patterns/form-design.md`](form-design.md) — validation errors at the field level |
@@ -235,4 +235,6 @@ <!-- hand-written --> | ||
| - [`knowledge/patterns/async-control.md`](async-control.md) — submit-in-flight, double-submit prevention, pending button states | ||
| - [knowledge/patterns/ux-guidelines.md](ux-guidelines.md) — broader UX rules | ||
| - [knowledge/i18n/korean-product-conventions.md](../i18n/korean-product-conventions.md) — Korean form expectations (phone, address, terms) | ||
| - [knowledge/a11y/keyboard-and-focus.md](../a11y/keyboard-and-focus.md) — keyboard navigation contract |
+1
-1
| { | ||
| "name": "@design-ai/cli", | ||
| "version": "4.57.0", | ||
| "version": "4.58.0", | ||
| "description": "Senior product designer for any AI coding agent. Installs design-ai (20 skills, 17 commands, 4 agents) into Claude Code globally. Korean market depth plus website improvement control tower.", | ||
@@ -5,0 +5,0 @@ "bin": { |
+4
-4
@@ -5,3 +5,3 @@ # Design AI | ||
| [](https://sungjin9288.github.io/design-ai/ko/) | ||
| [](knowledge/PRINCIPLES.md) | ||
| [](knowledge/PRINCIPLES.md) | ||
| [](examples/README.md) | ||
@@ -16,3 +16,3 @@ [](skills/README.md) | ||
| > **배포 상태, 2026-07-02 확인:** 로컬 `npm run release:check`는 통과했고, GitHub Pages 문서는 live 상태이며, GitHub Release `v4.56.0`과 npm `@design-ai/cli@4.56.0` publish 및 registry smoke가 확인됐어요. Homebrew formula는 `v4.56.0`에 pinning되어 있고, VS Code Marketplace에는 `sungjin.design-ai-vscode@0.4.1`이 공개되어 있어요. 자세한 내용은 [`docs/external-status.md`](docs/external-status.md)를 확인하세요. | ||
| > **배포 상태, 2026-07-03 확인:** 로컬 `npm run release:check`는 통과했고, GitHub Pages 문서는 live 상태이며, GitHub Release `v4.57.0`과 npm `@design-ai/cli@4.57.0`(`latest`) publish가 provenance와 함께 확인됐어요. Homebrew formula는 `v4.57.0`에 pinning되어 있고, VS Code Marketplace에는 `sungjin.design-ai-vscode@0.4.1`이 공개되어 있어요. v4.57.0 post-publish live registry smoke는 stale 어서션에 걸렸고(`main`에서 수정됨), 패키지는 pre-publish packed-tarball smoke로 검증됐어요. 자세한 내용은 [`docs/external-status.md`](docs/external-status.md)를 확인하세요. | ||
@@ -112,3 +112,3 @@ ## 한눈에 보는 커버리지 | ||
| │ | ||
| ├── knowledge/ # 92개 손으로 쓴 + 추출된 지식 파일 | ||
| ├── knowledge/ # 94개 손으로 쓴 + 추출된 지식 파일 | ||
| │ ├── design-tokens/ # W3C DTCG, OKLCH, HCT | ||
@@ -177,3 +177,3 @@ │ ├── components/ # Ant + MUI + shadcn 합성 | ||
| 전체 단계 로그는 [`docs/ROADMAP.md`](docs/ROADMAP.md), 현재 완료 범위는 [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md)에서 확인하세요. 현재 **v4.56.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, 90%+ component coverage가 완료됐어요. | ||
| 전체 단계 로그는 [`docs/ROADMAP.md`](docs/ROADMAP.md), 현재 완료 범위는 [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md)에서 확인하세요. 현재 **v4.57.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, 90%+ component coverage가 완료됐어요. | ||
@@ -180,0 +180,0 @@ 핵심 디자인 컨설팅 워크플로우는 로컬 릴리스 기준으로 준비되어 있어요. 웹사이트 개선 컨트롤 타워는 zero-dependency static Web App과 `website-improvement` route/skill/command로 제공되고, Site Profile, audit checklist, MCP readiness, refactor prompt, handoff evidence tracking, bundle export/verify/repair를 한 번에 다뤄요. 로컬 학습 선호도는 `design-ai learn`으로 관리해요 — profile bootstrap, feedback 캡처, 읽기 전용 signal registry, 반복 QA 신호에서 만드는 skill 제안, 그리고 backup/restore/curate/audit까지 전부 로컬에서만 동작하는 opt-in 기능이에요. AI 모델 학습이나 fine-tuning은 여전히 현재 배포 범위 밖이에요. |
+4
-4
@@ -5,3 +5,3 @@ # Design AI | ||
| [](https://sungjin9288.github.io/design-ai/) | ||
| [](knowledge/PRINCIPLES.md) | ||
| [](knowledge/PRINCIPLES.md) | ||
| [](examples/README.md) | ||
@@ -16,3 +16,3 @@ [](skills/README.md) | ||
| > **Distribution status, checked 2026-07-02:** local `npm run release:check` passes, GitHub Pages docs are live, GitHub Release `v4.56.0` is published, `@design-ai/cli@4.56.0` is public on npm with registry smoke coverage, the Homebrew formula is pinned to `v4.56.0`, and `sungjin.design-ai-vscode@0.4.1` is public on the VS Code Marketplace. See [`docs/external-status.md`](docs/external-status.md). | ||
| > **Distribution status, checked 2026-07-03:** local `npm run release:check` passes, GitHub Pages docs are live, GitHub Release `v4.57.0` is published, `@design-ai/cli@4.57.0` is public on npm (`latest`) with provenance and registry smoke coverage, the Homebrew formula is pinned to `v4.57.0`, and `sungjin.design-ai-vscode@0.4.1` is public on the VS Code Marketplace. The v4.57.0 post-publish live registry smoke hit a stale assertion (fixed on `main`); the package is validated by the pre-publish packed-tarball smoke. See [`docs/external-status.md`](docs/external-status.md). | ||
@@ -112,3 +112,3 @@ ## Coverage at a glance | ||
| │ | ||
| ├── knowledge/ # 92 hand-written + extracted knowledge files | ||
| ├── knowledge/ # 94 hand-written + extracted knowledge files | ||
| │ ├── design-tokens/ # Token systems (W3C DTCG, OKLCH, HCT) | ||
@@ -219,3 +219,3 @@ │ ├── components/ # Component synthesis (Ant + MUI + shadcn) | ||
| See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full phase log and [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md) for the current completion boundary. Currently at **v4.56.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, and 90%+ component coverage are complete. | ||
| See [`docs/ROADMAP.md`](docs/ROADMAP.md) for the full phase log and [`docs/PRODUCT-READINESS.md`](docs/PRODUCT-READINESS.md) for the current completion boundary. Currently at **v4.57.0**: public npm publish, provenance-backed GitHub Actions release, public registry smoke, Website Console MCP readiness, workspace learning restore/eval coverage, handoff bundle verification, and 90%+ component coverage are complete. | ||
@@ -222,0 +222,0 @@ Core design consulting workflows are locally release-ready. The website improvement control tower ships as a zero-dependency static Web App plus a `website-improvement` route/skill/command, covering Site Profiles, audit checklists, MCP readiness, refactor prompts, handoff evidence tracking, and bundle export/verify/repair. Local learning preferences are available through `design-ai learn` — profile bootstrap, feedback capture, a read-only signals registry, skill-proposal generation from repeated QA signals, and full backup/restore/curate/audit tooling, all local-only and opt-in. AI model training or fine-tuning remains outside the shipped scope. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
9888511
0.34%621
0.32%90429
0.11%