Skip to content

release: promote develop → main (v0.12.0)#1107

Merged
chronoai-shining merged 131 commits into
mainfrom
develop
Jun 15, 2026
Merged

release: promote develop → main (v0.12.0)#1107
chronoai-shining merged 131 commits into
mainfrom
develop

Conversation

@chronoai-shining

Copy link
Copy Markdown
Collaborator

Closes #1106.

Step 1 of the release procedure: promote developmain to cut v0.12.0 (minor — skillsets / skill-dependencies / assistant feature set; from v0.11.0).

Carries since v0.11.0: 28 unconsumed .changeset/*.md files + the curated .github/release-notes-20260612.md.

Highlights:

On merge, the changeset-release workflow opens the bot's release/v0.12.0 → main version-bump PR (Step 2).

chronoai-shining and others added 30 commits June 9, 2026 13:19
chore: sync main → develop after v0.11.0
Add the type layer for the Ornn Assistant chatbot's data path. The
assistant reuses the Playground SSE transport but speaks its own event
contract, so the strings are deliberately distinct (`chat_text_delta`
vs the Playground's `text-delta`) to keep the two streams from ever
cross-wiring.

The event union is a Zod discriminated union over
chat_start / chat_text_delta / chat_error / chat_finish / keepalive —
no `as any`. `parseAssistantEvent` validates each parsed SSE payload and
returns null for anything malformed / off-contract, so a drifting
backend surfaces as a dropped event rather than an untyped object
reaching React. `usage` on chat_finish is forward-compatible: known
fields optional, unknown keys stripped.

`AssistantMessage` is a structural subset of `PlaygroundMessage`
(id/role/content) so the existing ChatMessage renderer can paint
assistant turns without adaptation.
Zustand store for the assistant conversation, streaming state, the live
answer buffer, and the slide-in panel's open/closed state. Session-only
(NO persist) exactly like playgroundStore — the assistant is a transient
helper, not a saved thread, so conversation + panel state reset on
reload.

clearMessages resets the conversation but intentionally leaves panel
visibility untouched (clearing a chat shouldn't close the panel the
user is looking at). finalizeAssistantMessage is a no-op on an empty
buffer so an aborted-before-first-token turn doesn't push a blank
bubble.
POST /api/v1/assistant/chat streaming client, mirroring
playgroundStreamApi: canonical Bearer auth via the auth store's
ensureFreshToken, AbortController cancel, shared parseSseChunk. Every
parsed data: payload is validated through parseAssistantEvent before
dispatch; unrecognized events are debug-logged and skipped rather than
forwarded untyped.

Non-OK responses are decoded as RFC 7807 problem+json (per
docs/CONVENTIONS.md) — detail/code are lifted into a synthetic
chat_error event so the UI has one uniform failure channel regardless
of whether the failure was transport-level or a streamed error.
Drives the send → stream → display loop. Reuses the playground
typewriter pacer: chat_text_delta events fill a pending buffer that a
fixed-cadence pacer drains char-by-char, with adaptive catch-up so the
visible text stays within ~1s of what's been received. Terminal events
(chat_finish / chat_error / abort) flush the buffer immediately.

Errors surface on BOTH the store (inline panel display) and a toast, so
a user who scrolled away still sees the failure. keepalive heartbeats
are ignored. The in-flight stream and pacer interval are torn down on
unmount.
Mirror the backend LlmProviderModel contract (ornn-api settings
llmProviders/types.ts) on the web client: add enabledForAssistant +
defaultForAssistant to LlmProviderModel, and the matching optional
fields to ModelFlagsPatchInput so the admin drawer can PATCH the
assistant surface. The backend PATCH schema already accepts both as
optional booleans and the repository defaults them to false, so existing
provider docs deserialize unchanged.
Add a fourth surface column (Assistant) to the per-provider model
manager, mirroring Playground and Skill-Gen: an enable Toggle plus a
default Radio per model row, each firing the existing optimistic PATCH
with enabledForAssistant / defaultForAssistant. Switched the table off
table-fixed so four columns share width gracefully, and bumped the
archived-section colSpan to 4.

Column header copy stays inline English to match its hardcoded
Playground / Skill-Gen siblings in this admin-only drawer; the
user-facing assistant strings are fully i18n'd in the widget.
The per-provider row summary counted playground- and skillGen-enabled
models; add the assistant-enabled count so admins can see at a glance
how many models back the Ornn Assistant surface. Extends the
modelCounts i18n string (en + zh) with the new {{assistant}} slot.
… section (#970)

Adds the third LLM surface (after playground/skillGen) that backs the
Ornn Assistant repo-aware Q&A chatbot.

- LlmProviderModel gains per-surface flags enabledForAssistant /
  defaultForAssistant; SurfaceKey gains 'Assistant'. Reads of pre-#970
  provider docs default both to false so an existing model never
  auto-routes to the assistant until an admin opts it in.
- Surface union widened to 'playground'|'skillGen'|'assistant'. The
  surface-field helpers and the at-most-one-default-per-surface
  invariant are now table-driven (SURFACE_KEY + ALL_SURFACES) so a
  future surface is a one-line addition, not scattered ternaries.
- New 'assistant' settings section (defaultProviderId, defaultModelId,
  sseKeepAliveMs, defaultMonthlyQuota) mirroring playground/skillGen,
  registered in the section registry and exposed via
  SettingsService.getAssistant().

Surfaces stay independent: flipping the assistant default leaves the
playground/skillGen defaults untouched (covered by new unit tests for
resolver precedence + the cross-provider single-default invariant).
…rs (#970)

- GET /me/models accepts surface=assistant; resolution-error labels are
  table-driven so the assistant surface emits a coherent
  MODEL_UNAVAILABLE message instead of borrowing skill-generation's.
- bootstrap resolveLlmProviderForSurface / resolveSurfaceDefaults now
  resolve the 'assistant' surface from the new settings section. The
  shared NyxLlmClient is reused unchanged.
…#970)

Carried over from the ProviderEditDrawer test template; the models-drawer
test never references ReactNode. Removing it clears the
@typescript-eslint/no-unused-vars lint error.
A floating bottom-right launcher opens a corner chat panel that streams
repo-aware answers about Ornn. Reuses the Playground chat primitives
(ChatMessage / ChatInput) and the assistant data layer (useAssistantChat
+ useAssistantStore).

Forge Workshop language (docs/DESIGN.md): semantic tokens only,
letterpress impression shadows (cta-letterpress / card-impression),
press-DOWN launcher hover, Framer Motion panel reveal that collapses
under prefers-reduced-motion. a11y: ESC + backdrop close, focus moves
into the composer on open and returns to the launcher on close,
focus-visible ember rings, labelled controls, a status-role thinking
indicator. Empty state suggests the three example questions
("What is Ornn?", "How is Ornn different?", "Find a skill that does X");
clicking one fills the composer for editing before send.

All strings via react-i18next (en + zh). Session-scoped — no persistence.
Render <AssistantWidget /> from RootLayout, gated on useIsAuthenticated
so it only exists for signed-in users. The widget portals its own
launcher + panel to document.body, so mounting it here (rather than
inside <main>, which is overflow-hidden) keeps it clear of the layout
clip and above page content while staying below toasts.
…oader (#970)

Introduces the reusable KB primitives that ground the Ornn Assistant's
answers in the repo's own knowledge:

- tokens.ts: deterministic chars/4 token estimate + budget clamp +
  ASSISTANT_KB_TOKEN_BUDGET env resolution (default 18k). Model-agnostic
  on purpose — an exact tokenizer for one model is meaningless for
  another; determinism beats precision here.
- distiller.ts: the KbDistiller contract + DeterministicKbDistiller v1
  (markdown section extraction → per-source cap → titled concat → global
  budget clamp). The interface is the documented hook for a future
  LlmKbDistiller ("big model reads the repo at build time") — same
  contract, model-driven summarization swapped in underneath.
- loader.ts: cached, fail-soft runtime loader that reads the committed
  digest artifact, strips its provenance header, and defensively clamps
  to budget. A failed read degrades to empty grounding, never a crash.
- sources.ts: priority-ordered, capped source manifest (docs only, never
  code/secrets) consumed at build time.

Pure + deterministic by construction (no clocks/RNG/network). Unit tests
cover budget enforcement, section extraction, caching, and fail-soft.
Adds the build pipeline that turns the curated source manifest into the
runtime grounding artifact:

- scripts/build-assistant-kb.ts reads the manifest docs from the repo
  root, runs the DeterministicKbDistiller, and writes the committed
  digest.generated.md. Output carries an HTML-comment provenance header
  (stripped by the loader, never fed to the model) and NO timestamp, so
  re-running on unchanged inputs is byte-identical (clean diffs, stable
  CI). Missing source docs are skipped with a warning, not a failure.
- digest.generated.md: the committed artifact (~12.4k tokens, 6 sources)
  — README overview, CLAUDE positioning, ARCHITECTURE, the HTTP agent
  manual, API conventions, and a design overview slice.
- digest.artifact.test.ts guards the shipped artifact: non-empty, within
  budget, header hidden, Ornn-grounded, no secret-shaped content.
- package.json: `bun run build:assistant-kb` to regenerate.

Regenerate the artifact whenever the manifest or source docs change.
#970)

The Ornn Assistant is a billed LLM surface, so quota must reserve +
charge against it. Widen the quota `Surface` type to include 'assistant'
and resolve its default allotment from `assistant.defaultMonthlyQuota`.

Kept surgical to avoid frontend/admin ripple:
- `SURFACES` (admin-grant + redemption-code enums, quota-snapshot UI)
  stays ["playground","skillGen"]. The assistant isn't admin-grantable
  or redeemable in v1 — its allotment is the section default only.
- Introduced `GrantableSurface = SURFACES[number]`; grant/bulkGrant +
  the redemption grant entry use it, so they stay assignable to the
  notification layer's narrow surface type. The QuotaSnapshot shape is
  unchanged.
- `QuotaDefaults.defaultAssistantMonthly` is optional so existing
  resolver mocks keep compiling; the production resolver supplies it.
  Absent → 0 allotment (fail-closed) until wired.
…ce (#970)

The pure (HTTP-free) core of the Ornn Assistant — a non-agentic Q&A
pipeline:

- retrieval.ts: ScopedSkillRetriever runs visibility-scoped keyword
  search (scope "mixed") and enforces canReadSkill again at the
  projection layer, emitting RetrievedSkill — a SAFE projection (name,
  description, tags, category, createdOn, createdBy person-id). Listing
  fields explicitly (never spreading the doc) is the data-safety
  boundary: no createdByEmail/DisplayName, storageKey, skillHash,
  sharedWith* or any PII can leak.
- contextAssembler.ts: ASSISTANT_SYSTEM_PROMPT (grounded-Q&A persona,
  no fabrication, no cross-user data) + curated KB + scoped skills, all
  in one leading developer message; conversation turns follow verbatim.
- chatService.ts: emits chat_start → text deltas → chat_finish for ONE
  streamed completion with NO tools (the structural guarantee that the
  assistant can never trigger an execution loop). Retrieval failure is
  non-fatal (KB-only still answers); stream error → chat_error with a
  catalog code; best-effort usage on finish.

Tests pin the data-safety projection (incl. a projection-layer drop of
an unreadable skill), the no-tools guarantee, fail-soft retrieval, and
the event sequence.
Mounts the assistant endpoint following the playground reference +
CONVENTIONS pipeline: nyxidAuth → rateLimit(30/min) → validateBody →
resolveModel(assistant) → buildActorContext → quota reserve(assistant)
→ SSE stream → chargeOnCompletion. Model resolution + quota reserve run
before the stream so a misconfig/cap-hit returns clean RFC 7807 JSON;
in-stream failures surface as a chat_error event.

SSE frames carry both the native `event:` line and a JSON `data:` line
whose type matches (CONVENTIONS §6.3): chat_start / chat_text_delta /
chat_error / chat_finish + keepalive comment frames. Quota is reconciled
in a finally that always runs (commit on success / billed-then-aborted,
release on pre-token system error).

bootstrap wires wireAssistant over the shared NyxLlmClient + SkillRepo +
QuotaService, resolving the assistant surface defaults + sseKeepAliveMs
from settings, and warms the KB cache at boot. Route mounted under
/api/v1. Integration tests cover framing, auth/validation/model/quota
gates, and — mandatory — that a private skill + PII never reach the
streamed context through the real pipeline.
Adds assistantChatRequestBodySchema + assistantChatEventSchema and the
`POST /api/v1/assistant/chat` path (SSE response, 400/401/429/503 error
responses, "Assistant" tag) so the generated openapi.json documents the
new endpoint and its event contract.
Single minor changeset (fixed-versioned ornn-api + ornn-web) describing
the Ornn Assistant feature. Required by the check-changeset CI gate.
The Ornn Assistant endpoint POST /v1/assistant/chat ships without any new
contract surface to document, but its SSE event set and error behaviour
were undocumented. Two precise additions:

- CONVENTIONS.md §6.2: add the assistant row to the SSE endpoint mapping
  table — events chat_start, chat_text_delta, chat_error, chat_finish
  (the tool/file events from playground/chat do not apply here).
- ERRORS.md: note under upstream_unavailable that /assistant/chat
  introduces NO new error codes. Pre-stream failures reuse
  validation_error (400), authentication_required (401), rate_limited
  (429), and MODEL_NOT_ENABLED / MODEL_NOT_FOUND (400, only when an
  explicit modelId is supplied). In-stream LLM failure surfaces as an
  SSE chat_error event with code upstream_unavailable and no chat_finish.

Verified against ornn-api/src/domains/assistant/{routes,chatService}.ts
and the shared throwModelResolutionError helper.
Quality-review nit: the frontend assistantUsageSchema used
promptTokens/completionTokens while the backend AssistantUsage contract
(ornn-api domains/assistant/types.ts) and the OpenAPI spec emit
inputTokens/outputTokens/totalTokens. Rename the two drifted fields so a
populated chat_finish.usage validates instead of being silently stripped.
totalTokens was already correct.
Two quality-review a11y nits on the assistant panel:

- The panel declares role=dialog / aria-modal=true but had no focus
  trap, so Tab / Shift+Tab escaped to the backdrop'd page behind it. Add
  a trap scoped to the dialog via onKeyDown (currentTarget — no ref
  threading) that wraps focus at the first/last focusable. The existing
  focus-move-into-composer-on-open and restore-to-launcher-on-close
  behavior is unchanged.
- The header close / clear IconButtons were h-8 w-8 (32px), under the
  44px mobile touch-target guideline in docs/DESIGN.md. Bump the hit
  area to h-11 w-11 (44px); the launcher and suggestion rows already
  met it.
Security review finding #1 (LOW): the architecture + conventions KB
sources distilled whole docs, so internal infra surfaced in the digest
any authenticated user can elicit — env-var catalogs, internal proxy
header names (X-NyxID-*/X-Ornn-Caller-*), telemetry/observability
internals, and the user-directory section. No secret VALUES, but
needless internal-recon surface.

Add a `headings` allow-list to both sources (mirroring README/DESIGN):
- architecture → Project Overview, External Services, Skill Format only
  (drops the PostHog/telemetry, caller-type-detection, env-var config,
  and user-directory sections).
- conventions → §1 Response/error, §2 URL structure, §3 HTTP semantics,
  §4 Query params, §6 SSE only (drops §5 Auth's internal X-NyxID-* note
  and §7–§12 deprecation/caching/observability/architecture internals).

Regenerated digest is clean of every internal-recon marker (grep ✓) and
still carries the user-relevant grounding; ~10.8k tokens, deterministic.
The grounding digest (digest.generated.md) is a committed build artifact
distilled from the repo docs. If a source doc or the source manifest
changes but the digest isn't regenerated, the assistant silently ships
stale grounding.

Add an `assistant-kb-freshness` CI job that rebuilds the digest with
`bun run build:assistant-kb` and `git diff --exit-code`s the artifact —
the build is deterministic (no timestamp/RNG), so a clean tree means the
committed digest is in sync. A stale digest fails the PR with a clear
"re-run build:assistant-kb and commit" annotation.
Quality review flagged that the SSE client had only indirect coverage
via the hook. Add a focused transport test that mocks fetch + the auth
store and exercises the four load-bearing behaviors:

  - POSTs to /api/v1/assistant/chat with the Bearer header and the
    {messages, modelId} JSON body
  - parses chat_* frames off the stream via the real sseParser, in order
    (incl. a frame split across two chunk boundaries → remainder buffering)
  - maps a non-OK RFC 7807 problem+json response to a synthetic
    chat_error carrying detail + code
  - wires the AbortController so handle.abort() cancels the request and
    the AbortError path stays silent (no spurious chat_error)

The sseParser and event schema are the real modules, so this also guards
the parse → validate → dispatch seam end to end.
…hatbot

[Feature] Ornn Assistant — repo-aware Q&A chatbot (API + web widget)
Adds the copy the redesigned Ornn Assistant needs (en + zh):

- assistant.signIn.{title,body,cta,dismiss} — the inline prompt shown
  when a signed-out visitor tries to send (the chat backend is
  authed-only, so we gate the send rather than 401).
- assistant.greeting — the mascot's friendly empty-state hello.
- assistant.mascotAlt — alt text for the mascot in non-decorative spots.

Tone matches the existing "Repo-aware answers" assistant voice.
…o-open (#976)

Substantial rewrite of the Ornn Assistant widget (UX redesign, #976).
Backend/data layer untouched.

- Mascot launcher: the floating pill is replaced by the Ornn mascot
  (src/assets/ornn-mascot.webp, the same character as the landing hero
  video) — ~88px, ambient ember/arc glow, motion-safe idle bob,
  press-down on tap, and an "Ask Ornn" hover/focus speech bubble. It is
  a real <button> (aria-label, keyboard-operable, focus-visible ring).
- Draggable anywhere: Framer `drag` constrained to a full-screen
  pointer-events-none container, `dragMomentum={false}`, position
  persisted to localStorage and clamped back into the viewport on
  restore + resize. A drag never opens the panel (click-vs-drag ref).
- Anonymous access: the auth gate is gone — the widget renders for
  everyone. A signed-out send is intercepted with an inline sign-in
  card (mascot + copy + "Sign in" → loginWithNyxID + "Maybe later")
  instead of hitting the authed-only backend. Authed send is unchanged.
- First-visit auto-open: opens the panel once (700ms after mount) when
  the `ornn:assistant:auto-opened` flag is unset, then sets it so later
  visits start collapsed.
- Animations: spring panel entrance, staggered empty-state content, a
  waving mascot greeting, and a mascot avatar in the header — all
  honor prefers-reduced-motion (content still fully appears).

Preserved: ESC + backdrop close, focus-in-on-open / restore-on-close,
focus trap, 44px header touch targets, markdown streaming via
ChatMessage, the 3 suggestions, and clear-conversation.

Tests reworked: anon launcher renders; anon send shows the prompt and
does NOT call sendMessage; the prompt initiates login; first-visit
auto-open fires once and is suppressed when flagged; suggestion / close
/ focus-trap / touch-target coverage kept. The framer-motion mock gains
useMotionValue and drops drag/gesture/animation props.
…itors (#976)

Moves the assistant mount from RootLayout (authed app shell only) to
AnalyticsRoot in App.tsx, so the mascot launcher floats over EVERY page
— including the landing page (which owns its own layout, not RootLayout)
and for anonymous visitors.

AnalyticsRoot lives inside the router, so it suppresses the widget on
the auth-handshake routes via useLocation (`/login`, `/oauth/*`) where a
floating chatbot would be noise.

RootLayout drops the import + `{isAuthenticated && <AssistantWidget/>}`;
useIsAuthenticated stays (still gates the QuotaChip).
chronoai-shining and others added 28 commits June 11, 2026 15:17
…viewer. Hover node -> floating dialog with package preview (compact MemberViewer). Direct SVG render + hover support in MermaidBlock for trusted graphs (the detail case). Updated comments + test.

Fulfills request to stop wasting space under the graph while keeping the package viewer functionality available on hover.
…er canvas, full space). Enlarge hover dialog. Version bump: drop patch, only minor+major (default minor). Update tests/docs.
…c edges, smooth no-blink hover per DESIGN). Fix hover popup: larger (460x420), fixed cursor-relative positioning (offset beside mouse). Update tests.
…HoverMember to prevent parent re-renders on node hover (eliminates blinking on nodes). Pure CSS hover remains.
…able data) + already had useCallback + memo on SkillsetDependencyGraph. This prevents the entire react-flow canvas from re-rendering on every node hover, which was causing all nodes to flash rapidly at high frequency. The hover state only affects the fixed popup dialog now.
…pendencyGraphCanvas to ensure ReactFlow has size on initial mount (inside animated PageTransition + flex layouts). This prevents the 'unexpected application error' when clicking a skillset card (the detail page now renders the canvas graph without size-related crash).
…th optional chaining and defaults to prevent any potential undefined clientX/Y or event issues on hover in the read-only canvas. This should stop any JS errors leading to the unexpected application error screen on skillset detail.
…Hooks / lint errors); move stabilization useMemos before early returns in detail page; clean test mock unused/any; restore click/remove functions. This fixes the lint failure in CI.
… committed junk (#1091)

Three fixes to get this PR's CI passing:
- typecheck: removed the unused `_setSource` alias (setSource is already used in
  clickNode), which tripped noUnusedLocals.
- test: bumpVersion only special-cased 'patch' and fell through 'minor'/'major'
  to a major bump, so the edit form auto-filled 2.0 instead of 1.1 and two
  SkillsetForm version tests failed. Fixed the branching: minor -> minor+1,
  major -> major+1.0 (patch dropped). Refreshed the stale 'patch' doc comments.
- repo hygiene: untrack the accidentally-committed disposable artifacts
  (.agents/, .auto/, skills-lock.json) and add them to .gitignore so they
  can't be re-added (CLAUDE.md: .auto is never committed).
…#1091)

git add -A had captured the worktree node_modules symlinks (mode 120000);
they dodge the 'node_modules/' gitignore (dir-only) and made the Docker
'COPY ornn-web/ ornn-web/' fail trying to replace the bun-installed node_modules
directory with a symlink file. Untrack all four and tighten .gitignore to
'node_modules' (matches the symlinks too).
…canvas-hover-fixes

fix(web): skillset member dep graph to react-flow canvas + hover preview dialog + anti-blink + version bump (minor/major only) + error fixes
…he dep graph (#1092)

Replace react-flow's default box node with a custom MemberSkillNode card
(code-glyph icon + name + version, hairline border, letterpress shadow, ember
hover/selected border) via nodeTypes on both the editor + read-only canvas. Give
the read-only detail graph the same directed arc-blue arrowed edges as the
editor (it previously rendered unstyled default edges). Swap the dotted
background for a faint blueprint Lines grid + a center→edge vignette on a dark
page base. Tokens-only per DESIGN.md — arc-blue diagrammatic, ember accent,
letterpress, no soft glow/gradient. Validated the look via an offline HTML mock.
…modern

Modern Forge card nodes + arc edges + blueprint grid for the dependency graph
…opup fix (#1094)

Dependency-graph polish:
- Edges animate with a gentle arc-blue flowing dash (defaultEdgeOptions.animated +
  a slower 0.9s/dash-7 CSS override, not react-flow's strobe).
- Every arrow carries a 'runs before' label (the canonical source-runs-before-
  target semantic; i18n en/zh) styled as a Forge card-chip pill via CSS
  (.react-flow__edge-text / -textbg).
- Read-only detail graph gains react-flow Controls (zoom in/out/fit) + minZoom/
  maxZoom; the editor already had them.
- Hover package-preview dialog: bigger (600px / 70vh, viewport-clamped) and it no
  longer disappears when the cursor crosses the node→dialog gap — a 250ms grace
  timer on node-leave is cancelled when the cursor enters the dialog, which now
  stays open while hovered and closes on its own mouseleave.
…edge-labels

Graph: animated edges, 'runs before' labels, read-only zoom, hover-popup fix
…ory with 25 updates (#1070)

Bumps the bun-minor-and-patch group with 24 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [eslint](https://github.com/eslint/eslint) | `10.2.0` | `10.4.1` |
| [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.59.3` | `8.61.0` |
| [hono](https://github.com/honojs/hono) | `4.12.18` | `4.12.25` |
| [mongodb](https://github.com/mongodb/node-mongodb-native) | `7.2.0` | `7.3.0` |
| [posthog-node](https://github.com/PostHog/posthog-js/tree/HEAD/packages/node) | `5.33.7` | `5.36.9` |
| [@types/bun](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/bun) | `1.3.13` | `1.3.14` |
| [mongodb-memory-server](https://github.com/typegoose/mongodb-memory-server/tree/HEAD/packages/mongodb-memory-server) | `11.1.0` | `11.2.0` |
| [@hookform/resolvers](https://github.com/react-hook-form/resolvers) | `5.2.2` | `5.4.0` |
| [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) | `5.100.10` | `5.101.0` |
| [framer-motion](https://github.com/motiondivision/motion) | `12.38.0` | `12.40.0` |
| [i18next](https://github.com/i18next/i18next) | `26.1.0` | `26.3.1` |
| [posthog-js](https://github.com/PostHog/posthog-js) | `1.373.2` | `1.384.0` |
| [react](https://github.com/facebook/react/tree/HEAD/packages/react) | `19.2.6` | `19.2.7` |
| [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) | `19.2.14` | `19.2.17` |
| [react-dom](https://github.com/facebook/react/tree/HEAD/packages/react-dom) | `19.2.6` | `19.2.7` |
| [react-hook-form](https://github.com/react-hook-form/react-hook-form) | `7.75.0` | `7.78.0` |
| [react-i18next](https://github.com/i18next/react-i18next) | `17.0.7` | `17.0.8` |
| [react-router](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router) | `7.15.0` | `7.17.0` |
| [react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom) | `7.15.0` | `7.17.0` |
| [zustand](https://github.com/pmndrs/zustand) | `5.0.13` | `5.0.14` |
| [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) | `6.0.1` | `6.0.2` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `4.1.6` | `4.1.8` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `8.0.12` | `8.0.16` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `4.1.6` | `4.1.8` |



Updates `eslint` from 10.2.0 to 10.4.1
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](eslint/eslint@v10.2.0...v10.4.1)

Updates `typescript-eslint` from 8.59.3 to 8.61.0
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.61.0/packages/typescript-eslint)

Updates `hono` from 4.12.18 to 4.12.25
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](honojs/hono@v4.12.18...v4.12.25)

Updates `mongodb` from 7.2.0 to 7.3.0
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md)
- [Commits](mongodb/node-mongodb-native@v7.2.0...v7.3.0)

Updates `posthog-node` from 5.33.7 to 5.36.9
- [Release notes](https://github.com/PostHog/posthog-js/releases)
- [Changelog](https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md)
- [Commits](https://github.com/PostHog/posthog-js/commits/posthog-node@5.36.9/packages/node)

Updates `@types/bun` from 1.3.13 to 1.3.14
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/bun)

Updates `bun-types` from 1.3.13 to 1.3.14
- [Release notes](https://github.com/oven-sh/bun/releases)
- [Commits](https://github.com/oven-sh/bun/commits/bun-v1.3.14/packages/bun-types)

Updates `mongodb-memory-server` from 11.1.0 to 11.2.0
- [Release notes](https://github.com/typegoose/mongodb-memory-server/releases)
- [Changelog](https://github.com/typegoose/mongodb-memory-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/typegoose/mongodb-memory-server/commits/v11.2.0/packages/mongodb-memory-server)

Updates `@hookform/resolvers` from 5.2.2 to 5.4.0
- [Release notes](https://github.com/react-hook-form/resolvers/releases)
- [Commits](react-hook-form/resolvers@v5.2.2...v5.4.0)

Updates `@tanstack/react-query` from 5.100.10 to 5.101.0
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.101.0/packages/react-query)

Updates `framer-motion` from 12.38.0 to 12.40.0
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](motiondivision/motion@v12.38.0...v12.40.0)

Updates `i18next` from 26.1.0 to 26.3.1
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](i18next/i18next@v26.1.0...v26.3.1)

Updates `posthog-js` from 1.373.2 to 1.384.0
- [Release notes](https://github.com/PostHog/posthog-js/releases)
- [Changelog](https://github.com/PostHog/posthog-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PostHog/posthog-js/compare/posthog-js@1.373.2...posthog-js@1.384.0)

Updates `react` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react)

Updates `@types/react` from 19.2.14 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `react-dom` from 19.2.6 to 19.2.7
- [Release notes](https://github.com/facebook/react/releases)
- [Changelog](https://github.com/react/react/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/react/commits/v19.2.7/packages/react-dom)

Updates `react-hook-form` from 7.75.0 to 7.78.0
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](react-hook-form/react-hook-form@v7.75.0...v7.78.0)

Updates `react-i18next` from 17.0.7 to 17.0.8
- [Changelog](https://github.com/i18next/react-i18next/blob/master/CHANGELOG.md)
- [Commits](i18next/react-i18next@v17.0.7...v17.0.8)

Updates `react-router` from 7.15.0 to 7.17.0
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router@7.17.0/packages/react-router)

Updates `react-router-dom` from 7.15.0 to 7.17.0
- [Release notes](https://github.com/remix-run/react-router/releases)
- [Changelog](https://github.com/remix-run/react-router/blob/main/packages/react-router-dom/CHANGELOG.md)
- [Commits](https://github.com/remix-run/react-router/commits/react-router-dom@7.17.0/packages/react-router-dom)

Updates `zustand` from 5.0.13 to 5.0.14
- [Release notes](https://github.com/pmndrs/zustand/releases)
- [Commits](pmndrs/zustand@v5.0.13...v5.0.14)

Updates `@types/react` from 19.2.14 to 19.2.17
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

Updates `@vitejs/plugin-react` from 6.0.1 to 6.0.2
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@6.0.2/packages/plugin-react)

Updates `@vitest/coverage-v8` from 4.1.6 to 4.1.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.8/packages/coverage-v8)

Updates `vite` from 8.0.12 to 8.0.16
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.16/packages/vite)

Updates `vitest` from 4.1.6 to 4.1.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Changelog](https://github.com/vitest-dev/vitest/blob/main/docs/releases.md)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.8/packages/vitest)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 10.4.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: typescript-eslint
  dependency-version: 8.61.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: hono
  dependency-version: 4.12.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: mongodb
  dependency-version: 7.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: posthog-node
  dependency-version: 5.36.9
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: "@types/bun"
  dependency-version: 1.3.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: bun-types
  dependency-version: 1.3.14
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: mongodb-memory-server
  dependency-version: 11.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: "@hookform/resolvers"
  dependency-version: 5.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.101.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: framer-motion
  dependency-version: 12.40.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: i18next
  dependency-version: 26.3.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: posthog-js
  dependency-version: 1.384.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: react
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: "@types/react"
  dependency-version: 19.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: react-dom
  dependency-version: 19.2.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: react-hook-form
  dependency-version: 7.78.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: react-i18next
  dependency-version: 17.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: react-router
  dependency-version: 7.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: react-router-dom
  dependency-version: 7.17.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: bun-minor-and-patch
- dependency-name: zustand
  dependency-version: 5.0.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: "@types/react"
  dependency-version: 19.2.17
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 6.0.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 4.1.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: vite
  dependency-version: 8.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
- dependency-name: vitest
  dependency-version: 4.1.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: bun-minor-and-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Shining <shining.wang@aelf.io>
… updates (#620)

Bumps the actions-all group with 2 updates in the / directory: [actions/create-github-app-token](https://github.com/actions/create-github-app-token) and [codecov/codecov-action](https://github.com/codecov/codecov-action).


Updates `actions/create-github-app-token` from 2 to 3
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Changelog](https://github.com/actions/create-github-app-token/blob/main/CHANGELOG.md)
- [Commits](actions/create-github-app-token@v2...v3)

Updates `codecov/codecov-action` from 4 to 7
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md)
- [Commits](codecov/codecov-action@v4...v7)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions-all
- dependency-name: codecov/codecov-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: actions-all
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Shining <shining.wang@aelf.io>
…#569)

Bumps oven/bun from 1.3.13 to 1.3.14.

---
updated-dependencies:
- dependency-name: oven/bun
  dependency-version: 1.3.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Shining <shining.wang@aelf.io>
…#568)

Bumps oven/bun from 1.3.13 to 1.3.14.

---
updated-dependencies:
- dependency-name: oven/bun
  dependency-version: 1.3.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Shining <shining.wang@aelf.io>
…ers/resolve (#845)

* feat(api): gate /users/search q + per-user rate limit on directory routes (#816)

Reject empty/1-char q via Zod min-length (env ORNN_USER_SEARCH_MIN_Q,
default 2) and mount the existing per-user rateLimit middleware on both
/users/search and /users/resolve (shared label users-directory, env
ORNN_USER_DIRECTORY_RATELIMIT_PER_MIN / _WINDOW_MS, default 30/min).
Repository empty-q branch intentionally untouched: admin/quota depends
on it; the enumeration gate lives in the route. Build/tests run
separately (scoped bun test + tsc, see PR).

* test(api): users-directory enumeration gate + rate-limit coverage (#816)

Empty/1-char q must 400 without touching the repository; 2-char prefix
resolves (typeahead positive control, email present); RL_MAX+1 bursts
on /users/search and /users/resolve both 429 with RFC 9239 headers;
shared users-directory label draws one per-user budget across routes.

* feat(web): require 2-char minimum before collaborator typeahead fires (#816)

The backend now 400s empty/1-char q on /users/search, so the picker no
longer fires on bare focus; a small i18n'd hint asks for 2+ characters.
Email stays the picker label — UserDirectoryEntry unchanged.

* docs: changeset for #816

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
…724) (#749)

* feat(api): launch-promo foundation — admin manual award + /me status (#724)

PR 1 of 2 for #724. Lands the data model, eligibility gate, redemption-
code minting, notification delivery, and the admin manual-award + caller
status endpoints. Cron + GitHub stargazers polling + NyxID GH-login
resolution + frontend UI are scoped for PR 2.

- launchPromo settings section: enabled, repoOwner/Name, totalSlots
  (default 500), awardPlayground/awardSkillGen (200), pollIntervalMs,
  codeExpiryDays, nyxidInviteCode. Defaults are conservative so the
  promo stays dormant until an admin turns it on.
- launch_promo_claims collection + repo (one doc per awarded user,
  _id=userId for PK idempotency; awardedAt desc index for admin
  observability).
- LaunchPromoService.awardUser: gates on enabled + rank ≤ totalSlots
  + slots remaining + not-already-claimed, mints a code via the
  existing redemption-codes service, drops a launchPromo.codeDelivered
  notification carrying the code + NyxID invite code, records the
  claim. Race-on-insert resolves cleanly to ALREADY_CLAIMED.
  Notification failure logged but doesn't roll back the claim.
- LaunchPromoService.getStatusForUser: composes the /me/launch-promo
  response.
- UserDirectoryRepository.getRegistrationRank: 1-based ranking by
  firstSeenAt asc, two queries, no scan.
- New launchPromo.codeDelivered NotificationCategory.
- Routes: GET /me/launch-promo, POST /admin/launch-promo/award/:userId
  (ornn:admin:skill), GET /admin/launch-promo/recent. Service-layer
  sentinels map to 400/403/404/409.

Coverage: 12 colocated unit tests on LaunchPromoService — happy path
+ every error sentinel + race-on-insert + notification-failure-does-
not-rollback. All green.

Fixes #724

* fix(api): lint + typecheck errors in launch-promo module (#749)

- Add type annotations for implicit 'any' parameters in service.test.ts
- Remove useless try/catch wrapper in repository.ts insert()
- Attach cause to re-thrown error in service.ts (preserve-caught-error)
- Add getLaunchPromo to fake SettingsService in export/import tests
- Remove unused expression hack in service.test.ts

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
…608) (#735)

After #574, chat-completion providers were routed to /chat/completions
with text deltas translated into Responses-API events — but the stream
parser dropped delta.tool_calls. The playground tool-use loop only
matches on Responses-API response.output_item.done with
item.type=function_call, so a tool call from a DeepSeek-style
provider never reached the loop. Models would emit
execute_in_sandbox(...) and the JSON arrived as plain assistant text
instead of triggering the sandbox — runtime-based and mixed skills
appeared to respond but never actually ran.

Fix in parseChatCompletionStream:

- Per-index Map<number, ToolCallAccumulator> carries {id, name,
  arguments}. Each delta.tool_calls[] chunk merges into its buffer
  (id+name on the first chunk, arguments JSON string accumulates).
- A turn flushes when ANY of: explicit finish_reason (tool_calls /
  stop / anything non-null), upstream [DONE], or stream EOF. A
  `flushed` guard makes flush idempotent so multiple end signals
  never produce duplicate events.
- The synthesized event matches the shape chatService already parses
  via outputItemDoneEventSchema, so zero changes are needed in the
  playground loop — its existing pendingToolCall capture works for
  both upstream formats.

Parallel tool calls within one turn are supported (one done event
per index, emitted in index order). Missing `index` falls back to 0.
Streams that close without [DONE] or finish_reason still flush at
EOF so buffered calls are never lost.

Coverage: 6 new tests in llm.test.ts cover chunked accumulation +
finish_reason flush, EOF flush without [DONE], parallel tool calls,
idempotent flush across finish_reason+[DONE], intermixed text+tool
deltas (event order), and missing index fallback. 17/17 green in
the file; full ornn-api suite no new regressions (18 unrelated
pre-existing failures in validateSkillFrontmatter #649).

Fixes #608
…tar CTA (#641)

* docs: elevate value-prop bullets in "What is Ornn" (#640)

Refactor the section so the three reasons-to-care are scannable in a
single glance instead of being threaded through flowing prose:

- Agents call it directly (HTTP / MCP, no human-in-the-loop UI)
- Model + runtime agnostic (Claude / GPT / Gemini / custom)
- Whole lifecycle in one API (search → ... → share)

The original "primary consumer" and "ornn-web is secondary" sentences
fold into a single closing paragraph to avoid duplication with the
bullets. The "agent-facing, not human marketplace" lead sentence stays
verbatim — that's the framing every downstream channel (HN, Reddit,
dev.to) hooks into.

No content removed, only reorganized; the lifecycle sequence is preserved
as inline code on the third bullet instead of a stand-alone fenced block.

* docs: add star call-to-action section above License (#640)

Standard early-stage OSS pattern. One short paragraph between the
Contributing section and the License section, acknowledging that stars
double as both a "this is solving a real problem" signal and the
threshold most awesome-list maintainers check before accepting a
project.

Deliberately not added as a banner / shields.io badge — at 12 stars a
"please star us" hero is more harmful than helpful; a quiet near-the-
bottom CTA reads as authentic instead of needy.

Not added to the top-of-README ToC since it's a CTA paragraph, not a
content section.

* docs: add "Try Ornn free" launch perk section after Quickstart (#640)

Insert a new section between Quickstart and "How Ornn compares" that
hooks readers at the moment they've just learned what Ornn does + how
to install it. Three-step redemption (star → sign in → enter NyxID
invite code NYX-2XXJI08A) plus the launch perk (first 500 users get
400 free GPT-5.5 conversations, split between Playground and Skill
Generation, no credit card, no expiry).

Matching anchor link added to the top-of-README ToC so the section is
reachable from the nav row, between Quickstart and How Ornn compares.

Placement rationale: above the comparison table — once the reader has
seen the value prop and how to use it, the perk converts; placing it
below the comparison or at the bottom dilutes the "I get it, let me
try" moment.

* chore: empty changeset for docs-only README polish (#640)

Required by CI (changeset gate). Empty frontmatter so no package
version is bumped — README polish doesn't change the public surface.

* chore(api): refresh assistant KB digest after README changes

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
…t pane scroll (#1100) (#1101)

* feat(web): fix graph hover popup to 800×40vh with independent pane scroll (#1100)

The popup dialog on the skillset detail dependency graph had variable
height and scrolled as one block. Pin it to a fixed 800×40vh size
(wider and shorter than the previous 600×60vh) and remove the outer
overflow-auto so the inner SkillPackagePreview panes (file tree,
content viewer) each scroll independently within the constrained
dialog.

* feat(web): enable node drag on skillset detail graph (#1100)

The read-only graph on the detail page locked nodes in place
(nodesDraggable=false, static computed nodes). Wire the interactive
useNodesState nodes and onNodesChange handler into the readOnly
ReactFlow render so users can reposition nodes while keeping the
canvas read-only (no connect/edit). Remove the now-dead staticNodes
and readOnlyFlowEdges memos.

Also give SkillsetMemberViewer an h-full class in preview mode so
it fills the fixed popup height and enables independent pane scroll.

* chore: add changeset for #1100

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
…ion (#1100) (#1102)

* feat(web): restore landing page announcement popups with glassmorphic style (#1100)

Retire the global top-right AnnouncementBanner in favour of the original
landing-only popup dialogs (AnnouncementPopup + LaunchCelebrationPopup).
Both popups are centered with proportional viewport margins (10vh/15vw)
and use a glassmorphic surface (bg-black/40 + backdrop-blur-2xl) with
light text token overrides for contrast over the dark hero video.

* chore(web): remove background plate from landing hero CTA buttons (#1100)

* feat(web): skillset graph popup — click-to-open, centered, blurred backdrop (#1100)

Replace hover-triggered cursor-following popup with a click-to-open
centered dialog. The dialog fills the viewport minus 15% margins on
all sides and shows a full-screen backdrop blur. Click the blurred
area or the × button to dismiss. Graph nodes now fire onNodeClick
instead of onNodeMouseEnter/Leave.

* chore(web): default Ornn assistant mascot to right-edge vertically centered (#1100)

* chore: add changeset for #1100

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
* feat(web): skill explorer for skillset member picker with scope tabs and version selection (#1100)

Replace the single typeahead input (public-only search) with a full skill
explorer panel: scope tabs (All / System / Public / My Skills / Shared),
debounced search, expandable skill cards showing description + visibility
badge, and inline version rows with add buttons. Keeps existing chip
display, validation, and raw name@version entry.

* fix(web): eliminate transparent flash on landing announcement popup mount (#1100)

Move bg-black/40 and backdrop-blur-2xl onto a static non-animated wrapper
div so the glass surface renders immediately. Only the inner content fades
in via a quick 0.15s opacity transition — no more brief fully-transparent
frame on popup open.

* chore: bump changeset to minor for skill explorer + popup fixes (#1100)

* fix(web): update SkillsetForm test to match new explorer search placeholder (#1100)

* fix(web): allow raw ref Enter without @ in explorer search (#1100)

Remove the query.includes('@') guard so that versionless refs typed
into the search bar still trigger validation and produce the proper
error message (restores test coverage).

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
* docs: release notes for 2026-06-12 release

* docs: add empty changeset for release-notes PR (#1104)

The release-notes-20260612 commit is docs-only and adds no version
bump, but changeset-check.yml blocks any develop-targeting PR that
doesn't add a .changeset/*.md file. Per the project convention,
docs-only PRs satisfy the gate with an empty changeset (bun changeset
--empty). Unblocks merging the curated release notes onto develop
ahead of the develop -> main release PR.

---------

Co-authored-by: Shining <250120269+chronoai-shining@users.noreply.github.com>
@chronoai-shining chronoai-shining merged commit ed24636 into main Jun 15, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant