From 09263a17eea278dc0cf1e064fd1afd12e1869f4b Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 11:33:25 +0530 Subject: [PATCH 01/11] Restructure Settings navigation and management surfaces --- apps/web/src/app/(app)/settings/ai/page.tsx | 59 ++---- .../app/(app)/settings/api-access/page.tsx | 8 +- .../src/app/(app)/settings/apps/[id]/page.tsx | 9 + .../app/(app)/settings/apps/apps-client.tsx | 33 ++- .../src/app/(app)/settings/calendar/page.tsx | 14 +- .../app/(app)/settings/integrations/page.tsx | 6 +- .../src/app/(app)/settings/library/page.tsx | 2 +- .../app/(app)/settings/mcp-access/page.tsx | 192 +++++++++--------- apps/web/src/app/(app)/settings/page.tsx | 28 +-- .../src/app/(app)/settings/profile/page.tsx | 37 ++-- .../src/app/(app)/settings/workflows/page.tsx | 16 +- .../src/components/settings-section-nav.tsx | 34 ++++ apps/web/src/components/sidebar.tsx | 2 +- apps/web/src/lib/settings-navigation.test.ts | 32 +-- apps/web/src/lib/settings-navigation.ts | 57 +++--- ...026-09-09-settings-implementation-loops.md | 61 ++++++ 16 files changed, 359 insertions(+), 231 deletions(-) create mode 100644 apps/web/src/app/(app)/settings/apps/[id]/page.tsx create mode 100644 apps/web/src/components/settings-section-nav.tsx create mode 100644 docs/superpowers/plans/2026-09-09-settings-implementation-loops.md diff --git a/apps/web/src/app/(app)/settings/ai/page.tsx b/apps/web/src/app/(app)/settings/ai/page.tsx index 1060b35e..3981cb3b 100644 --- a/apps/web/src/app/(app)/settings/ai/page.tsx +++ b/apps/web/src/app/(app)/settings/ai/page.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import { api } from '@/lib/api'; import { useAuth } from '@/lib/auth-context'; +import { SettingsSectionNav } from '@/components/settings-section-nav'; import { Database, Eye, EyeOff, KeyRound, Loader2, Mic, RotateCcw, Save, Server, Sparkles, Trash2 } from 'lucide-react'; type Provider = 'anthropic' | 'openai' | 'openrouter' | 'ollama'; @@ -53,6 +54,7 @@ export default function AISettingsPage() { const [cfg, setCfg] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); + const [section, setSection] = useState<'providers' | 'models' | 'search' | 'voice'>('providers'); const isAdmin = user?.role === 'owner' || user?.role === 'admin'; @@ -83,7 +85,7 @@ export default function AISettingsPage() { className="text-[18px] font-semibold mb-3" style={{ color: 'var(--foreground)', fontFamily: 'var(--font-heading)' }} > - AI providers + AI configuration
- AI providers for {org?.name ?? 'your workspace'} + AI configuration for {org?.name ?? 'your workspace'}

Bring your own provider. Deft can use managed keys or local Ollama, and the core workspace keeps @@ -137,25 +139,13 @@ export default function AISettingsPage() { )}

-
- - - -
- -
+ + -
+ -
+ -
+ ); diff --git a/apps/web/src/app/(app)/settings/workflows/page.tsx b/apps/web/src/app/(app)/settings/workflows/page.tsx index 1f268ac3..499ec489 100644 --- a/apps/web/src/app/(app)/settings/workflows/page.tsx +++ b/apps/web/src/app/(app)/settings/workflows/page.tsx @@ -1,6 +1,6 @@ 'use client'; -// Task 5.7 — Workflows settings page. Lists workflow_rules for the org +// Task 5.7 — Task rules settings page. Lists workflow_rules for the org // and a minimal create form: trigger (status-changed + target status) // and action checkboxes (add_comment / assign_to / add_label / notify). import { useCallback, useEffect, useState } from 'react'; @@ -31,7 +31,7 @@ const TARGET_STATUSES: Array<{ value: string; label: string }> = [ { value: 'cancelled', label: 'Cancelled' }, ]; -export default function WorkflowsPage() { +export default function TaskRulesPage() { const [rules, setRules] = useState([]); const [loading, setLoading] = useState(true); const [creating, setCreating] = useState(false); @@ -132,7 +132,7 @@ export default function WorkflowsPage() { }; const handleDelete = async (rule: WorkflowRule) => { - if (!window.confirm(`Delete workflow "${rule.name}"?`)) return; + if (!window.confirm(`Delete task rule "${rule.name}"?`)) return; const res = await api.delete(`/api/workflows/${rule.id}`); if (res.ok) setRules((prev) => prev.filter((r) => r.id !== rule.id)); }; @@ -143,7 +143,7 @@ export default function WorkflowsPage() {

- Workflows + Task rules

Run deterministic task automations for simple, repeatable handoffs. @@ -153,7 +153,7 @@ export default function WorkflowsPage() { )}

@@ -171,7 +171,7 @@ export default function WorkflowsPage() {

- New workflow + New task rule

@@ -269,7 +269,7 @@ export default function WorkflowsPage() { style={{ background: 'var(--surface-container-low)', border: '1px dashed var(--border-default, var(--outline-variant))' }} > -

No workflows yet.

+

No task rules yet.

Start with a small rule like adding a label or notifying a lead when work moves to review.

diff --git a/apps/web/src/components/settings-section-nav.tsx b/apps/web/src/components/settings-section-nav.tsx new file mode 100644 index 00000000..93291551 --- /dev/null +++ b/apps/web/src/components/settings-section-nav.tsx @@ -0,0 +1,34 @@ +'use client'; + +/** Section buttons keep each form mounted so switching sections preserves drafts. */ +export function SettingsSectionNav({ + label, + sections, + value, + onChange, +}: { + label: string; + sections: readonly { id: T; label: string }[]; + value: T; + onChange: (value: T) => void; +}) { + return ( + + ); +} diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx index 354c7e85..9b9f8dd8 100644 --- a/apps/web/src/components/sidebar.tsx +++ b/apps/web/src/components/sidebar.tsx @@ -696,7 +696,7 @@ function SettingsSidebarContent({ onNav }: { onNav?: () => void }) { }} aria-expanded={advancedOpen} > - Advanced + {advancedGroup.label} {advancedOpen && ( diff --git a/apps/web/src/lib/settings-navigation.test.ts b/apps/web/src/lib/settings-navigation.test.ts index 1b22ebe0..c9e4f84e 100644 --- a/apps/web/src/lib/settings-navigation.test.ts +++ b/apps/web/src/lib/settings-navigation.test.ts @@ -2,25 +2,29 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { getSettingsNavGroups, isSettingsItemActive } from './settings-navigation'; -test('members see only personal workspace and personal connection settings', () => { - const items = getSettingsNavGroups('member').flatMap((group) => group.items); - assert.deepEqual(items.map((item) => item.name), ['General', 'Profile', 'License & source', 'Calendar', 'Connections']); - assert.equal(items.some((item) => item.href === '/settings/api-access'), false); +test('members and guests see personal settings without admin destinations', () => { + for (const role of ['member', 'guest'] as const) { + const items = getSettingsNavGroups(role).flatMap((group) => group.items); + assert.deepEqual(items.map((item) => item.href), ['/settings', '/settings/profile', '/settings/mcp-access', '/settings/calendar', '/license']); + } }); -test('owners get module administration as a primary workspace destination', () => { - const groups = getSettingsNavGroups('owner'); - const primary = groups.filter((group) => !group.advanced).flatMap((group) => group.items); - const advanced = groups.find((group) => group.advanced); - - assert.equal(primary.length, 9); - assert.ok(primary.some((item) => item.href === '/settings/modules')); - assert.ok(advanced); - assert.ok(advanced.items.some((item) => item.name === 'Mention groups')); - assert.ok(advanced.items.some((item) => item.name === 'API access')); +test('administrators get distinct personal, workspace and service connection destinations', () => { + for (const role of ['owner', 'admin'] as const) { + const groups = getSettingsNavGroups(role); + const groupFor = (href: string) => groups.find((group) => group.items.some((item) => item.href === href)); + assert.equal(groupFor('/settings/mcp-access')?.label, 'Your account'); + assert.equal(groupFor('/settings/integrations')?.label, 'Agents & AI'); + assert.equal(groupFor('/settings/api-access')?.advanced, true); + assert.equal(groupFor('/settings/modules')?.label, 'Workspace'); + assert.equal(groupFor('/settings/workflows')?.label, 'Work management'); + const hrefs = groups.flatMap((group) => group.items.map((item) => item.href)); + assert.equal(new Set(hrefs).size, hrefs.length); + } }); test('nested settings routes keep their parent navigation item active', () => { assert.equal(isSettingsItemActive('/settings/agent-employees/create', '/settings/agent-employees'), true); assert.equal(isSettingsItemActive('/settings/profile', '/settings'), false); + assert.equal(isSettingsItemActive('/settings/agent-employees', '/settings/agent'), false); }); diff --git a/apps/web/src/lib/settings-navigation.ts b/apps/web/src/lib/settings-navigation.ts index e25f3386..59a673d9 100644 --- a/apps/web/src/lib/settings-navigation.ts +++ b/apps/web/src/lib/settings-navigation.ts @@ -1,3 +1,5 @@ +import { APPS_ENABLED } from './feature-flags'; + export type SettingsRole = 'owner' | 'admin' | 'member' | 'guest'; export type SettingsNavItem = { @@ -18,47 +20,53 @@ const ADMIN_ROLES: SettingsRole[] = ['owner', 'admin']; export const settingsNavGroups: SettingsNavGroup[] = [ { - label: 'Account', - description: 'Your workspace preferences and identity.', + label: 'Your account', + description: 'Your identity, preferences and personal connections.', items: [ - { name: 'General', href: '/settings', description: 'Theme and settings overview.' }, + { name: 'Overview', href: '/settings', description: 'Find settings and change your appearance.' }, { name: 'Profile', href: '/settings/profile', description: 'Identity, status, notifications, and security.' }, - { name: 'License & source', href: '/license', description: 'View Deft\'s AGPL license and Corresponding Source.' }, + { name: 'Personal AI connections', href: '/settings/mcp-access', description: 'Connect Codex, Claude or another AI client acting as you.' }, + { name: 'Calendar connections', href: '/settings/calendar', description: 'Manage your external calendar subscriptions and personal Deft feed.' }, ], }, { label: 'Workspace', - description: 'People, teams, and shared time.', + description: 'People and tools shared by your workspace.', items: [ { name: 'People', href: '/settings/members', description: 'Invite people and manage workspace access.', roles: ADMIN_ROLES }, - { name: 'Teams', href: '/settings/teams', description: 'Organize people around ownership and linked work.', roles: ADMIN_ROLES }, - ...(APPS_ENABLED ? [{ name: 'Apps', href: '/settings/apps', description: 'Install and govern workspace Apps.', roles: ADMIN_ROLES }] : []), - { name: 'Modules', href: '/settings/modules', description: 'Install and govern workspace modules.', roles: ADMIN_ROLES }, - { name: 'Calendar', href: '/settings/calendar', description: 'Connect calendars with self-hostable ICS feeds.' }, + { name: 'Teams', href: '/settings/teams', description: 'Manage team membership and linked work.', roles: ADMIN_ROLES }, + ...(APPS_ENABLED ? [{ name: 'Apps', href: '/settings/apps', description: 'Manage installed Apps and their access.', roles: ADMIN_ROLES }] : []), + { name: 'Modules', href: '/settings/modules', description: 'Manage standalone Modules and collection agent access.', roles: ADMIN_ROLES }, + { name: 'Mention groups', href: '/settings/groups', description: 'Reusable @mention lists for chat; separate from team access.', roles: ADMIN_ROLES }, ], }, { - label: 'AI & Connections', - description: 'Shared agents and personal AI apps.', + label: 'Agents & AI', + description: 'Shared agents, model configuration and workspace policy.', items: [ - { name: 'Agent employees', href: '/settings/agent-employees', description: 'Manage agents that work alongside the team.', roles: ADMIN_ROLES }, - { name: 'Connections', href: '/settings/mcp-access', description: 'Connect Codex, Claude, ChatGPT, or another MCP client.' }, + { name: 'Agent employees', href: '/settings/agent-employees', description: 'Manage shared agents, their access and runtime setup.', roles: ADMIN_ROLES }, + { name: 'AI configuration', href: '/settings/ai', description: 'Configure model providers, search and voice features.', roles: ADMIN_ROLES }, + { name: 'Tool connections', href: '/settings/integrations', description: 'External MCP tool servers used by workspace agents and Apps.', roles: ADMIN_ROLES }, + { name: 'Policies & audit', href: '/settings/agent', description: 'Workspace trust defaults and action receipts.', roles: ADMIN_ROLES }, ], }, { - label: 'Advanced', - description: 'Specialist workspace, automation, AI, and developer controls.', - advanced: true, + label: 'Work management', + description: 'Reusable work, task rules and recovery.', items: [ - { name: 'Mention groups', href: '/settings/groups', description: 'Reusable @mention lists for chat.', roles: ADMIN_ROLES }, - { name: 'Tags', href: '/settings/tags', description: 'Review workspace labels and usage counts.', roles: ADMIN_ROLES }, - { name: 'Task templates', href: '/settings/library', description: 'Reusable task templates and work packs.', roles: ADMIN_ROLES }, - { name: 'Automations', href: '/settings/workflows', description: 'Task status-change rules.', roles: ADMIN_ROLES }, + { name: 'Task templates', href: '/settings/library', description: 'Reusable task sets for projects.', roles: ADMIN_ROLES }, + { name: 'Task rules', href: '/settings/workflows', description: 'Rules triggered by task status changes. App schedules live in Apps.', roles: ADMIN_ROLES }, + { name: 'Tags', href: '/settings/tags', description: 'Workspace labels and usage counts.', roles: ADMIN_ROLES }, { name: 'Project recovery', href: '/settings/projects', description: 'Restore recently deleted projects.', roles: ADMIN_ROLES }, - { name: 'Agent tool servers', href: '/settings/integrations', description: 'External MCP tools available to agents.', roles: ADMIN_ROLES }, - { name: 'AI providers', href: '/settings/ai', description: 'Model providers and local endpoints.', roles: ADMIN_ROLES }, - { name: 'Agent governance', href: '/settings/agent', description: 'Workspace trust defaults, activity, and audit.', roles: ADMIN_ROLES }, - { name: 'API access', href: '/settings/api-access', description: 'Service keys for scripts and runtimes.', roles: ADMIN_ROLES }, + ], + }, + { + label: 'Developer & operator', + description: 'Service credentials and self-hosted source information.', + advanced: true, + items: [ + { name: 'Service API access', href: '/settings/api-access', description: 'API keys for scripts and service runtimes.', roles: ADMIN_ROLES }, + { name: 'License & source', href: '/license', description: 'AGPL license and Corresponding Source.' }, ], }, ]; @@ -78,4 +86,3 @@ export function isSettingsItemActive(pathname: string, href: string) { if (href === '/settings') return pathname === href; return pathname === href || pathname.startsWith(`${href}/`); } -import { APPS_ENABLED } from './feature-flags'; diff --git a/docs/superpowers/plans/2026-09-09-settings-implementation-loops.md b/docs/superpowers/plans/2026-09-09-settings-implementation-loops.md new file mode 100644 index 00000000..af0cd3ff --- /dev/null +++ b/docs/superpowers/plans/2026-09-09-settings-implementation-loops.md @@ -0,0 +1,61 @@ +# Settings implementation loops + +The Settings exploration identified a structural problem: personal clients, shared +workspace tools, operator credentials and employee operations are presented as +overlapping destinations. The implementation should make the owner and purpose of +each setting clear while retaining existing permissions, API payloads and routes. + +## Loop 1: navigation and focused management surfaces + +- Group navigation into Your account, Workspace, Agents & AI, Work management, + and Developer & operator. Derive overview cards from the same role-filtered + navigation definitions. Keep all existing URLs. +- Open Apps on a searchable installed list. Give each App a detail URL at + `/settings/apps/[id]`, retaining its existing review and lifecycle controls. + Keep package inspection and developer pairing under Add or build an App. +- Put active personal connections before an expandable Add connection flow. + Keep token scopes, grants, revocation and archived activity unchanged. +- Separate Calendar into Connected calendars and Share Deft calendar; AI into + Providers, Model routing, Search and Voice; Profile into Identity, + Availability & notifications, and Security. +- Keep section contents mounted to retain unsaved drafts. Profile and preferences + still share their existing save request; password changes keep their independent + handler. No permission model, database or runtime changes belong in this loop. + +Acceptance: role/navigation tests, web typecheck and lint, rendered desktop/mobile +inspection, search and detail navigation, and draft retention across section +changes. Local UI checks use synthetic data and do not certify production writes. + +Validation on 2026-09-09: all three navigation tests passed; web typecheck and full +web lint passed, followed by focused lint after final edits. The local Next.js +renderer was inspected at 1440×900 and 390×844, in light and dark themes. +Connection inventory/setup, App search (including no matches), App detail refresh +and return navigation, and Profile/Calendar/model-routing draft retention were +exercised. Password changes, token issuance, App activation and real connector +calls were not executed. The fixture intentionally omitted realtime and dashboard +data; this is UI evidence, not a database-backed integration run or release gate. + +## Next loops + +1. **Module ownership.** The API rejects enable/disable and manifest changes to + App-owned Modules, but the module installation view currently omits ownership. + Add an explicit organization-scoped ownership field to the read contract and + route lifecycle management to the owning App. Preserve collection agent-access + policy controls and standalone Module management. Do not infer ownership from + manifest declarations: a staged App can request a Module it does not own. +2. **Canonical employee management.** Governance currently owns clone, save as + template, trust escalation and turn/receipt inspection that the employee list + does not expose. Move these into employee detail before removing the duplicate + roster. Retain developer/runtime setup links, confirmations and receipt checks. +3. **Foundation evidence.** Mandatory current-candidate boundary checks, public + App Kit distribution and explicit worker restart/restore evidence remain open. + A locally packed kit is not public distribution. A Settings PR is not Track A + recertification or Gate G clearance. +4. **Track B isolation.** The hostile static UI experiment blocked parent DOM, + cookie/storage access and fetch, but sandboxed frame self-navigation still + reached a local sink. Resolve that no-egress gap before freezing the manifest + and bridge contract or claiming an isolated Email Lite shell. + +Each implementation loop should produce a reviewable PR with fresh evidence. +PRs must remain unmerged until the user has reviewed them. Tracks B, C, D and +Gate G are not complete as a result of these Settings changes. From 6e0ec97b7d8a93e9e284f78e6b3f7d02757fa98f Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 12:16:40 +0530 Subject: [PATCH 02/11] fix(web): contain personal connection setup and cover expanded flow --- .../app/(app)/settings/mcp-access/page.tsx | 33 ++++++++++------- ...026-09-09-settings-implementation-loops.md | 36 +++++++++++++++++++ scripts/product-browser-smoke.mjs | 19 +++++++++- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/apps/web/src/app/(app)/settings/mcp-access/page.tsx b/apps/web/src/app/(app)/settings/mcp-access/page.tsx index a25df0fd..0f9c76c3 100644 --- a/apps/web/src/app/(app)/settings/mcp-access/page.tsx +++ b/apps/web/src/app/(app)/settings/mcp-access/page.tsx @@ -444,7 +444,7 @@ export default function McpAccessPage() { api.get('/api/oauth/grants'), api.get('/api/mcp-access/history'), ]); - if (readinessRes.ok) setRemote(await readinessRes.json()); + setRemote(readinessRes.ok ? await readinessRes.json() : null); if (grantsRes.ok) { const grantsBody = await grantsRes.json(); setGrants(grantsBody.grants ?? []); @@ -605,7 +605,7 @@ export default function McpAccessPage() { }, { label: 'Remote MCP server URL', - value: remote?.mcp_endpoint_url ?? 'Loading connector URL...', + value: remote?.mcp_endpoint_url ?? (loading ? 'Loading connector URL...' : 'Connector URL unavailable'), copyValue: remote?.mcp_endpoint_url, help: 'Paste this into Claude\'s required URL field.', }, @@ -753,18 +753,19 @@ export default function McpAccessPage() { key={client.id} type="button" onClick={() => chooseClient(client.id)} - className="rounded-md p-3 text-left transition-colors" + aria-pressed={active} + className="min-w-0 rounded-md p-3 text-left transition-colors" style={{ background: active ? 'color-mix(in srgb, var(--accent) 12%, var(--surface-container))' : 'var(--surface-container)', border: active ? '1px solid var(--accent)' : '1px solid var(--border-default)', }} > -
+
{clientIcon(client.id)} - {client.name} + {client.name}
{client.fit}
@@ -776,8 +777,8 @@ export default function McpAccessPage() {
-
-
+
+
{tokenSetupClient && (
@@ -798,6 +799,7 @@ export default function McpAccessPage() { key={preset.id} type="button" onClick={() => setAccessPreset(preset.id)} + aria-pressed={active} className="rounded-md p-3 text-left" style={{ background: active ? 'color-mix(in srgb, var(--accent) 12%, var(--surface-container))' : 'var(--surface-container)', @@ -849,11 +851,12 @@ export default function McpAccessPage() {

Generate a token, copy the config for {selectedClientOption.name}, then test it from the AI app.

-
+
setTokenName(e.target.value)} - className="h-10 rounded-md px-3 text-[13px] outline-none" + aria-label="Connection name" + className="min-w-0 h-10 rounded-md px-3 text-[13px] outline-none" style={{ background: 'var(--surface-container)', color: 'var(--text-primary)', border: '1px solid var(--border-default)' }} />
-
+

{isClaudeConnector ? 'Claude connector setup' : 'ChatGPT custom app setup'} @@ -919,9 +922,15 @@ export default function McpAccessPage() {

- {remote?.https_ready ? 'HTTPS ready' : 'Needs public HTTPS'} + {remote ? (remote.https_ready ? 'HTTPS ready' : 'Needs public HTTPS') : (loading ? 'Checking readiness...' : 'Status unavailable')}
+ {!loading && !remote && ( +
+

Could not load connector settings. Retry before connecting your AI app.

+ +
+ )}
@@ -1009,7 +1018,7 @@ export default function McpAccessPage() { )}
-
+
-
-
+
+ -
-
+ + +
+ + {setupStep === 2 && selectedClientOption.setupKind === 'agent' ? ( + Open Agent Employees + ) : setupStep < 3 ? ( + + ) : ( + + )} +
diff --git a/apps/web/src/components/settings-steps.tsx b/apps/web/src/components/settings-steps.tsx new file mode 100644 index 00000000..6af0533e --- /dev/null +++ b/apps/web/src/components/settings-steps.tsx @@ -0,0 +1,14 @@ +export function SettingsSteps({ steps, current }: { steps: readonly string[]; current: number }) { + return ( + + ); +} diff --git a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md index 209cc792..5b4435d7 100644 --- a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md +++ b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md @@ -6,7 +6,8 @@ a claim that Settings is complete. Resume from the first unfinished milestone. ## Workspace and existing evidence -Work in `C:/tmp/deft-settings-structure`, branch `codex/settings-structure`. +Work in `C:/tmp/deft-settings-structure`; current implementation branch is +`codex/settings-connection-flow`, based on `codex/settings-structure` at 5f6f0d86. PR #323 contains the first structural pass and connection overflow repair. Preserve the original worktree and unrelated changes. Keep milestones separately reviewable; use explicitly based follow-up branches/PRs for subsequent features, @@ -139,6 +140,29 @@ production deployment, real credential grants or external messages are implied. - Completed: existing route inventory and shared interaction specification above. - Existing repair: PR #323, commit 6e0ec97b, 54 rendered connection states verified; web lint/typecheck/navigation tests passed. Updated production smoke pending. -- Next: inspect full connection-page handlers and extract a client/access/connect/ - verify state model, then implement the reference flow on a follow-up branch. +- Implemented: guided connection setup on `codex/settings-connection-flow`: + compact client selection; access review; client-specific connection instructions; + explicit verification. Shared employee setup exits to its existing destination. + Added reusable SettingsSteps progress with current-step semantics and step focus. + Existing token scope payloads and OAuth permissions are unchanged. New tokens + lock the client, name and scopes, prevent duplicate generation, and require an + explicit saved-token acknowledgement before advancing. Back/Next retains drafts + and the one-time token. Clipboard failures produce local feedback. +- Verification uses the issued token_id against the existing inventory response; + it does not infer connection success from completing instructions or another + token's activity. Contextual memory guidance is expandable. +- Fresh evidence: all seven client branches traversed at 390 and 1440 CSS px, + without visible section overflow; name and custom permissions retained across + steps; rejected issuance kept the Connect step; inert synthetic issuance tested + acknowledgement gating, duplicate prevention, locked client/access controls and + pending verification despite another fixture token having recent use. The fixture + was returned to read-only mode afterward. Typecheck, full web lint, navigation + tests and smoke-script syntax passed. Production smoke now traverses the steps, + checks command containment and name retention; CI execution remains pending. +- Screenshots: `tmp/preview-evidence/guided-access-desktop.png` and + `guided-connect-mobile.png`. These are fixture-based visual evidence only. +- Next: finish connection management detail and local activity/error feedback, + strengthen keyboard/zoom and real issuance verification, then apply the shared + patterns to Profile/Calendar/AI. Module ownership and canonical employee work + require their explicit contract/control audits before implementation. - Open: dependency audit, real integration evidence, independent usability review. diff --git a/scripts/product-browser-smoke.mjs b/scripts/product-browser-smoke.mjs index 2a4ae348..2b85574b 100644 --- a/scripts/product-browser-smoke.mjs +++ b/scripts/product-browser-smoke.mjs @@ -120,6 +120,7 @@ async function main() { await page.getByText('Add connection', { exact: true }).click(); await page.getByRole('heading', { name: 'What do you want to connect?', exact: true }).waitFor(); await page.getByRole('button', { name: /^Claude Code Token setup/ }).click(); + await page.getByRole('button', { name: 'Review access', exact: true }).click(); await page.getByRole('button', { name: /^Choose individually/ }).click(); for (const width of [1440, 1024, 768, 390]) { await page.setViewportSize({ width, height: 900 }); @@ -131,6 +132,19 @@ async function main() { ); }); if (setupOverflow > 2) throw new Error(`Claude Code setup overflows its cards by ${setupOverflow}px at ${width}px`); + await page.getByRole('button', { name: 'Continue to connect', exact: true }).click(); + await page.getByRole('textbox', { name: 'Connection name', exact: true }).fill('Smoke test draft'); + const commandOverflow = await page.getByRole('textbox', { name: 'Connection name', exact: true }).evaluate((input) => { + const section = input.closest('section'); + return section.scrollWidth - section.clientWidth; + }); + if (commandOverflow > 2) throw new Error(`Claude Code command expands its card at ${width}px`); + await page.getByRole('button', { name: 'Back', exact: true }).click(); + await page.getByRole('button', { name: 'Continue to connect', exact: true }).click(); + if (await page.getByRole('textbox', { name: 'Connection name', exact: true }).inputValue() !== 'Smoke test draft') { + throw new Error('Connection name was lost between setup steps'); + } + await page.getByRole('button', { name: 'Back', exact: true }).click(); } record('Claude Code custom permissions stay inside setup cards at desktop, tablet and mobile widths'); From e2c9911138b326a01f3b6877ef3d9aec85bef67d Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:01:08 +0530 Subject: [PATCH 05/11] Redesign the complete personal AI connections page --- .../app/(app)/settings/mcp-access/page.tsx | 1664 ++++++++++------- .../2026-09-09-settings-maturity-program.md | 33 +- scripts/product-browser-smoke.mjs | 49 +- 3 files changed, 1034 insertions(+), 712 deletions(-) diff --git a/apps/web/src/app/(app)/settings/mcp-access/page.tsx b/apps/web/src/app/(app)/settings/mcp-access/page.tsx index e11cebde..d2903c98 100644 --- a/apps/web/src/app/(app)/settings/mcp-access/page.tsx +++ b/apps/web/src/app/(app)/settings/mcp-access/page.tsx @@ -2,29 +2,8 @@ import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import Link from 'next/link'; -import { - Activity, - Bot, - Check, - ChevronDown, - ChevronRight, - Code2, - Copy, - FileText, - Globe2, - History, - KeyRound, - Loader2, - Plug, - Settings2, - ShieldCheck, - Sparkles, - Terminal, - Trash2, - Wrench, -} from 'lucide-react'; +import { Bot, Check, ChevronDown, Code2, Copy, Globe2, KeyRound, Plug, Wrench } from 'lucide-react'; import { api } from '@/lib/api'; -import { PageHeader } from '@/components/page-header'; import { useSetPageContext } from '@/components/app-header-context'; import { SettingsSteps } from '@/components/settings-steps'; @@ -39,30 +18,19 @@ type McpToken = { }; const READ_SCOPES = ['read:workspace', 'read:wiki', 'read:tasks', 'read:messages', 'read:calendar', 'read:modules']; -const WRITE_SCOPES = ['write:tasks', 'write:messages', 'write:wiki', 'write:calendar', 'write:modules', 'write:workspace']; +const WRITE_SCOPES = [ + 'write:tasks', + 'write:messages', + 'write:wiki', + 'write:calendar', + 'write:modules', + 'write:workspace', +]; const COLLABORATE_SCOPES = [...READ_SCOPES, 'write:tasks', 'write:messages', 'write:wiki', 'write:modules']; const ALL_SCOPES = [...READ_SCOPES, ...WRITE_SCOPES]; const APP_SCOPES = ['read:apps', 'invoke:apps', 'read:app-runs']; const AVAILABLE_SCOPES = [...ALL_SCOPES, ...APP_SCOPES]; -const SCOPE_LABELS: Record = { - 'read:workspace': 'Workspace map, teammates, projects, receipts, and activity context', - 'read:wiki': 'Company, channel, and personal memory packets', - 'read:tasks': 'Task lists, task detail, comments, and progress', - 'read:messages': 'Visible spaces, threads, unread work, and chat search', - 'read:calendar': 'Native and ICS calendar context', - 'read:modules': 'Installed module schemas and records, such as the Contacts Directory', - 'read:apps': 'Installed App identities, reviewed grants, bindings, and health', - 'invoke:apps': 'Discover, prepare, and invoke reviewed App actions as you', - 'read:app-runs': 'Inspect authorized App Run status, safe previews, and retained results', - 'write:tasks': 'Create, update, transition, and comment on tasks', - 'write:messages': 'Post messages into spaces and DMs you can access', - 'write:wiki': 'Save or update wiki knowledge as you', - 'write:calendar': 'Create, update, and cancel your native Deft calendar events', - 'write:modules': 'Create, update, and archive records in enabled modules', - 'write:workspace': 'Manage your notes, inbox, approvals, projects, and agent operations', -}; - type ClientId = 'codex' | 'claude-code' | 'claude-desktop' | 'remote-web' | 'headless' | 'custom' | 'agent-employee'; type AccessPreset = 'read' | 'work' | 'operate' | 'custom'; @@ -81,7 +49,8 @@ const CLIENT_OPTIONS: ClientOption[] = [ id: 'codex', name: 'Codex', fit: 'Recommended token setup', - detail: 'Best for owner-operator workflows: triage messages, read tasks, write wiki, post updates, and leave receipts.', + detail: + 'Best for owner-operator workflows: triage messages, read tasks, write wiki, post updates, and leave receipts.', setupKind: 'token', defaultPreset: 'work', tokenName: 'Codex', @@ -99,7 +68,8 @@ const CLIENT_OPTIONS: ClientOption[] = [ id: 'claude-desktop', name: 'Claude / Claude Desktop', fit: 'Remote OAuth connector', - detail: 'Add Deft from Claude settings, not inside a chat. Claude connects from Anthropic cloud and authenticates through OAuth.', + detail: + 'Add Deft from Claude settings, not inside a chat. Claude connects from Anthropic cloud and authenticates through OAuth.', setupKind: 'oauth', defaultPreset: 'read', tokenName: 'Claude connector', @@ -108,7 +78,8 @@ const CLIENT_OPTIONS: ClientOption[] = [ id: 'remote-web', name: 'ChatGPT / hosted AI apps', fit: 'Plan-dependent access', - detail: 'ChatGPT Pro currently supports read/fetch. Full read/write MCP requires an eligible Business or Enterprise/Edu workspace using Developer Mode.', + detail: + 'ChatGPT Pro currently supports read/fetch. Full read/write MCP requires an eligible Business or Enterprise/Edu workspace using Developer Mode.', setupKind: 'oauth', defaultPreset: 'read', tokenName: 'Remote AI app', @@ -117,7 +88,8 @@ const CLIENT_OPTIONS: ClientOption[] = [ id: 'headless', name: 'Headless / automation', fit: 'Full workspace operation', - detail: 'For scripts and AI clients that operate notes, inbox, approvals, projects, calendar, and agent state without opening Deft.', + detail: + 'For scripts and AI clients that operate notes, inbox, approvals, projects, calendar, and agent state without opening Deft.', setupKind: 'token', defaultPreset: 'operate', tokenName: 'Headless operator', @@ -191,16 +163,6 @@ const READ_TEST_PROMPTS = [ 'Show me which Deft capabilities and tools this connection can use.', ]; -const COLLABORATE_TEST_PROMPTS = [ - 'Create a follow-up task from this discussion, post an update, and show me the receipt.', - 'Update the relevant wiki page with this decision without creating a duplicate.', -]; - -const OPERATE_TEST_PROMPTS = [ - 'Review my inbox, approvals, tasks, and calendar, then give me one prioritized operating brief.', - 'Create a calendar event for the agreed review, add a note with the agenda, and show me the receipts.', -]; - type RemoteReadiness = { public_url: string; mcp_endpoint_url: string; @@ -290,7 +252,7 @@ function actionResult(action: OAuthAuditAction): Record | null if (typeof text !== 'string') return null; try { const parsed = JSON.parse(text); - return parsed && typeof parsed === 'object' ? parsed as Record : null; + return parsed && typeof parsed === 'object' ? (parsed as Record) : null; } catch { return null; } @@ -331,20 +293,25 @@ function actionHref(action: OAuthAuditAction) { const toolName = typeof action.metadata?.tool_name === 'string' ? action.metadata.tool_name : null; const result = actionResult(action); if (!result) return null; - if ((toolName === 'task_create' || toolName === 'task_transition' || toolName === 'task_update' || toolName === 'comment_on_task') && typeof result.id === 'string') { + if ( + (toolName === 'task_create' || + toolName === 'task_transition' || + toolName === 'task_update' || + toolName === 'comment_on_task') && + typeof result.id === 'string' + ) { return `/tasks?task=${encodeURIComponent(result.id)}`; } - if ((toolName === 'message_post' || toolName === 'send_message') && typeof result.id === 'string' && typeof result.space_id === 'string') { + if ( + (toolName === 'message_post' || toolName === 'send_message') && + typeof result.id === 'string' && + typeof result.space_id === 'string' + ) { return `/chat?space=${encodeURIComponent(result.space_id)}&message=${encodeURIComponent(result.id)}`; } return null; } -function isStale(value: string | null | undefined) { - if (!value) return true; - return Date.now() - new Date(value).getTime() > 1000 * 60 * 60 * 24 * 14; -} - function clientById(id: ClientId) { return CLIENT_OPTIONS.find((client) => client.id === id) ?? CLIENT_OPTIONS[0]!; } @@ -358,7 +325,11 @@ function clientIcon(id: ClientId) { function RecentActionList({ actions }: { actions?: OAuthAuditAction[] }) { if (!actions?.length) { - return
No recent actions recorded.
; + return ( +
+ No recent actions recorded. +
+ ); } return (
@@ -366,18 +337,24 @@ function RecentActionList({ actions }: { actions?: OAuthAuditAction[] }) { const href = actionHref(action); const content = ( <> - + {actionTitle(action)} ({actionDetail(action)}) - {formatDate(action.created_at)} + + {formatDate(action.created_at)} + ); return href ? ( - + {content} ) : ( -
+
{content}
); @@ -386,11 +363,75 @@ function RecentActionList({ actions }: { actions?: OAuthAuditAction[] }) { ); } -function ScopePill({ scope }: { scope: string }) { +function permissionLabel(scope: string) { + const labels: Record = { + 'read:workspace': 'View workspace context, people and projects', + 'read:wiki': 'Read accessible knowledge and memory', + 'read:tasks': 'Read tasks, comments and progress', + 'read:messages': 'Read accessible conversations and unread messages', + 'read:calendar': 'Read your calendar context', + 'read:modules': 'Read accessible module records', + 'write:tasks': 'Create and update tasks and comments', + 'write:messages': 'Post messages in conversations you can access', + 'write:wiki': 'Create and update accessible knowledge', + 'write:calendar': 'Create, update and cancel your Deft events', + 'write:modules': 'Create, update and archive module records', + 'write:workspace': 'Manage your notes, inbox, approvals, projects and agent operations', + 'read:apps': 'View installed apps, permissions and health', + 'invoke:apps': 'Prepare and invoke reviewed app actions', + 'read:app-runs': 'Read authorized app run status and results', + }; + return labels[scope] ?? scope; +} + +function accessSummary(scopes: string[]) { + if (!scopes.length) return 'No permissions granted.'; + if (scopes.every((scope) => scope.startsWith('read:'))) return 'Read-only access within its granted permissions.'; + if (scopes.some((scope) => scope.startsWith('write:') || scope.startsWith('invoke:'))) + return 'Can read or make changes within its granted permissions.'; + return 'Access is defined by the permissions below.'; +} + +function PermissionDetails({ scopes }: { scopes: string[] }) { + return ( +
+ View {scopes.length} permissions +
    + {scopes.map((scope) => ( +
  • + {permissionLabel(scope)} + + {scope} + +
  • + ))} +
+
+ ); +} + +function CopyControl({ + label, + value, + copied, + onCopy, +}: { + label: string; + value: string; + copied: string | null; + onCopy: (label: string, value: string) => Promise; +}) { return ( - - {scope} - + ); } @@ -415,7 +456,18 @@ export default function McpAccessPage() { const [setupStep, setSetupStep] = useState(0); const [tokenSaved, setTokenSaved] = useState(false); const [issuedTokenId, setIssuedTokenId] = useState(null); + const [setupOpen, setSetupOpen] = useState(false); + const [setupStarted, setSetupStarted] = useState(false); + const [connectionQuery, setConnectionQuery] = useState(''); + const [confirmRevoke, setConfirmRevoke] = useState(null); + const [selectedGrantId, setSelectedGrantId] = useState(''); + const [loadFailures, setLoadFailures] = useState([]); + const loadRequest = useRef(0); const stepHeading = useRef(null); + const connectionsAction = useRef(null); + const revokeAction = useRef(null); + const revokeTriggers = useRef>({}); + const previousRevoke = useRef(null); const focusStep = useRef(false); const setupSteps = ['Choose app', 'Review access', 'Connect', 'Verify'] as const; @@ -426,10 +478,17 @@ export default function McpAccessPage() { useLayoutEffect(() => { if (focusStep.current) { - stepHeading.current?.focus(); + (setupOpen ? stepHeading.current : connectionsAction.current)?.focus(); focusStep.current = false; } - }, [setupStep]); + }, [setupStep, setupOpen]); + + useLayoutEffect(() => { + if (confirmRevoke) revokeAction.current?.focus(); + else if (previousRevoke.current) + (revokeTriggers.current[previousRevoke.current] ?? connectionsAction.current)?.focus(); + previousRevoke.current = confirmRevoke; + }, [confirmRevoke]); const selectedClientOption = clientById(selectedClient); const selectedScopes = useMemo(() => { @@ -438,51 +497,43 @@ export default function McpAccessPage() { if (accessPreset === 'operate') return ALL_SCOPES; return customScopes; }, [accessPreset, customScopes]); - const testPrompts = useMemo(() => { - const prompts = [...READ_TEST_PROMPTS]; - if (selectedScopes.some((scope) => ['write:tasks', 'write:messages', 'write:wiki', 'write:modules'].includes(scope))) { - prompts.push(...COLLABORATE_TEST_PROMPTS); - } - if (selectedScopes.includes('write:workspace') || selectedScopes.includes('write:calendar')) { - prompts.push(...OPERATE_TEST_PROMPTS); - } - return prompts; - }, [selectedScopes]); const load = useCallback(async () => { + const request = ++loadRequest.current; setLoading(true); - setError(null); - try { - const res = await api.get('/api/mcp-access/tokens'); - if (!res.ok) throw new Error(`HTTP ${res.status}`); - const body = await res.json(); - setTokens(body.tokens ?? []); - setEndpoint(body.mcp_endpoint_url ?? ''); - const [readinessRes, grantsRes, historyRes] = await Promise.all([ - api.get('/api/oauth/readiness'), - api.get('/api/oauth/grants'), - api.get('/api/mcp-access/history'), - ]); - setRemote(readinessRes.ok ? await readinessRes.json() : null); - if (grantsRes.ok) { - const grantsBody = await grantsRes.json(); - setGrants(grantsBody.grants ?? []); - } - if (historyRes.ok) { - const historyBody = await historyRes.json(); - setHistory({ - revoked_tokens: historyBody.revoked_tokens ?? [], - revoked_grants: historyBody.revoked_grants ?? [], - }); - } - } catch (err) { - setError((err as Error).message); - } finally { - setLoading(false); + const resources = [ + ['Personal tokens', '/api/mcp-access/tokens'], + ['Connector settings', '/api/oauth/readiness'], + ['App authorizations', '/api/oauth/grants'], + ['Connection history', '/api/mcp-access/history'], + ] as const; + const results = await Promise.allSettled( + resources.map(async ([, path]) => { + const response = await api.get(path); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }), + ); + if (request !== loadRequest.current) return; + const [tokenResult, readinessResult, grantResult, historyResult] = results; + if (tokenResult.status === 'fulfilled') { + setTokens(tokenResult.value.tokens ?? []); + setEndpoint(tokenResult.value.mcp_endpoint_url ?? ''); } + setRemote(readinessResult.status === 'fulfilled' ? readinessResult.value : null); + if (grantResult.status === 'fulfilled') setGrants(grantResult.value.grants ?? []); + if (historyResult.status === 'fulfilled') + setHistory({ + revoked_tokens: historyResult.value.revoked_tokens ?? [], + revoked_grants: historyResult.value.revoked_grants ?? [], + }); + setLoadFailures(results.flatMap((result, index) => (result.status === 'rejected' ? [resources[index][0]] : []))); + setLoading(false); }, []); - useEffect(() => { void load(); }, [load]); + useEffect(() => { + void load(); + }, [load]); function chooseClient(id: ClientId) { if (busy || newToken || id === selectedClient) return; @@ -495,14 +546,13 @@ export default function McpAccessPage() { } function toggleCustomScope(scope: string) { - setCustomScopes((current) => ( - current.includes(scope) - ? current.filter((item) => item !== scope) - : [...current, scope] - )); + setCustomScopes((current) => + current.includes(scope) ? current.filter((item) => item !== scope) : [...current, scope], + ); } async function copy(label: string, value: string) { + setError(null); try { await navigator.clipboard.writeText(value); setCopied(label); @@ -513,6 +563,7 @@ export default function McpAccessPage() { } async function createToken() { + if (busy || newToken || !selectedScopes.length) return; setBusy(true); setError(null); try { @@ -530,6 +581,7 @@ export default function McpAccessPage() { setTokenSaved(false); setEndpoint(body.mcp_endpoint_url ?? endpoint); await load(); + setConfirmRevoke(null); } catch (err) { setError((err as Error).message); } finally { @@ -544,8 +596,9 @@ export default function McpAccessPage() { const res = await api.delete(`/api/mcp-access/tokens/${id}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); await load(); - } catch (err) { - setError((err as Error).message); + setConfirmRevoke(null); + } catch { + setError('Could not confirm revocation. Refresh the connection list to check its status, then try again.'); } finally { setBusy(false); } @@ -558,8 +611,9 @@ export default function McpAccessPage() { const res = await api.delete(`/api/oauth/grants/${id}`); if (!res.ok) throw new Error(`HTTP ${res.status}`); await load(); - } catch (err) { - setError((err as Error).message); + setConfirmRevoke(null); + } catch { + setError('Could not confirm revocation. Refresh the connection list to check its status, then try again.'); } finally { setBusy(false); } @@ -583,17 +637,15 @@ export default function McpAccessPage() { if (selectedClient === 'claude-code') { return { title: 'Claude Code CLI', - detail: 'Run this in a terminal. Then use /mcp in Claude Code to verify the connection. Do not paste the token into a Claude chat.', + detail: + 'Run this in a terminal. Then use /mcp in Claude Code to verify the connection. Do not paste the token into a Claude chat.', value: `claude mcp add --transport http --scope user deft "${endpointForConfig}" --header "Authorization: Bearer ${tokenForConfig}"`, }; } return { title: 'Raw endpoint and bearer header', detail: 'Use this when your client asks for the MCP URL and authorization header separately.', - value: [ - `MCP URL: ${endpointForConfig}`, - `Authorization: Bearer ${tokenForConfig}`, - ].join('\n'), + value: [`MCP URL: ${endpointForConfig}`, `Authorization: Bearer ${tokenForConfig}`].join('\n'), }; }, [endpointForConfig, selectedClient, tokenForConfig]); @@ -609,7 +661,6 @@ export default function McpAccessPage() { ['Registration endpoint', remote?.registration_endpoint], ]; const isClaudeConnector = selectedClient === 'claude-desktop'; - const isChatGptConnector = selectedClient === 'remote-web'; const remoteSteps = isClaudeConnector ? [ 'In Claude, open Settings or Customize -> Connectors. Do not paste MCP JSON or tokens into a chat.', @@ -621,7 +672,7 @@ export default function McpAccessPage() { 'In ChatGPT web, enable developer mode for an eligible account, then open Settings -> Apps -> Create.', 'Use the Connector URL below and choose OAuth authentication. Deft publishes the discovery metadata automatically.', 'Click Scan Tools and complete the Deft authorization screen. Deft starts scope-less connections read-only; add write permissions only when your ChatGPT plan supports full MCP.', - 'Create the draft app, enable it in a new chat, and confirm a read. On Business or Enterprise/Edu, test a write action and approve ChatGPT\'s confirmation prompt.', + "Create the draft app, enable it in a new chat, and confirm a read. On Business or Enterprise/Edu, test a write action and approve ChatGPT's confirmation prompt.", ]; const claudeConnectorFields = [ { @@ -634,7 +685,7 @@ export default function McpAccessPage() { label: 'Remote MCP server URL', value: remote?.mcp_endpoint_url ?? (loading ? 'Loading connector URL...' : 'Connector URL unavailable'), copyValue: remote?.mcp_endpoint_url, - help: 'Paste this into Claude\'s required URL field.', + help: "Paste this into Claude's required URL field.", }, { label: 'OAuth Client ID (optional)', @@ -648,632 +699,853 @@ export default function McpAccessPage() { }, ]; + const connections = [ + ...tokens.map((token) => ({ + ...token, + key: `token:${token.id}`, + kind: 'token' as const, + label: 'Personal token', + displayName: token.name, + })), + ...grants.map((grant) => ({ + ...grant, + key: `grant:${grant.id}`, + kind: 'grant' as const, + label: 'App authorization', + displayName: grant.app_name, + })), + ]; + const filteredConnections = connections.filter((connection) => + `${connection.displayName} ${connection.label}`.toLowerCase().includes(connectionQuery.trim().toLowerCase()), + ); + const inventoryFailures = loadFailures.filter((name) => name === 'Personal tokens' || name === 'App authorizations'); + const selectedPreset = PRESETS.find((preset) => preset.id === accessPreset)!; + const verificationConnection = tokenSetupClient + ? issuedConnection + : grants.find((grant) => grant.id === selectedGrantId); + const verificationUnavailable = loadFailures.includes(tokenSetupClient ? 'Personal tokens' : 'App authorizations'); + const promptScopes = verificationConnection?.scopes ?? selectedScopes; + const prompt = promptScopes.includes('read:messages') + ? READ_TEST_PROMPTS[0] + : promptScopes.includes('read:tasks') + ? READ_TEST_PROMPTS[1] + : promptScopes.includes('read:wiki') + ? READ_TEST_PROMPTS[2] + : READ_TEST_PROMPTS[3]; + const border = { borderColor: 'var(--border-default)' }; + const muted = { color: 'var(--text-secondary)' }; + const buttonClass = + 'inline-flex min-h-10 items-center justify-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium focus-visible:outline-2 focus-visible:outline-offset-2 disabled:opacity-40'; + const primaryStyle = { background: 'var(--accent)', borderColor: 'var(--accent)', color: 'white' }; + + function openSetup() { + focusStep.current = true; + setSetupStarted(true); + setSetupOpen(true); + setError(null); + } + + function closeSetup() { + focusStep.current = true; + setSetupOpen(false); + } + + function finishSetup() { + closeSetup(); + setSetupStarted(false); + setSetupStep(0); + setNewToken(null); + setIssuedTokenId(null); + setTokenSaved(false); + setSelectedGrantId(''); + } + return (
- - -
- {error && ( -
- {error} -
- )} - {copied && ( -
- Copied {copied} +
+
+

Personal AI connections

+

+ Connect your AI apps to Deft. You control their access. +

+
+ {error && !setupOpen && !confirmRevoke && ( +
+

{error}

+
)} -
-
- -

Manage active connections

-
- {loading ? ( -
- ) : ( -
-
-
Personal tokens
- {tokens.length === 0 ? ( -

No personal MCP tokens yet.

- ) : ( -
- {tokens.map((token) => ( -
-
-
-
{token.name}
-
- {token.token_prefix}... / last used {formatDate(token.last_used_at)} -
-
- -
-
- {isStale(token.last_used_at) && ( - - {token.last_used_at ? 'stale' : 'unused'} - - )} - {token.scopes.map((scope) => ( - {scope} - ))} + {!setupOpen ? ( + <> +
+
+
+

+ Your connections +

+

+ These apps act as you and can only access work you can see. +

+
+ +
+ {newToken && !tokenSaved && ( +

+ Your new token is still in setup. Resume to save it before refreshing or leaving this page. +

+ )} +
+ + +
+ {inventoryFailures.length > 0 && ( +

+ Could not refresh {inventoryFailures.join(' and ').toLowerCase()}. The list may be incomplete or out + of date. Retry with Refresh. +

+ )} + {loading && connections.length === 0 ? ( +

+ Loading your connections… +

+ ) : filteredConnections.length === 0 ? ( +
+

+ {connectionQuery.trim() + ? 'No matching connections' + : inventoryFailures.length + ? 'Connections unavailable' + : 'Connect your first AI app'} +

+

+ {connectionQuery.trim() + ? 'Try a different name or clear your search.' + : inventoryFailures.length + ? 'Refresh to try loading your connections again.' + : 'Bring your workspace into Codex, Claude or another supported client.'} +

+ {connectionQuery.trim() && ( + + )} +
+ ) : ( +
+ {filteredConnections.map((connection) => ( +
+ + + {connection.kind === 'token' ? : } + + + {connection.displayName} + + {connection.label} ·{' '} + {connection.last_used_at + ? `Last used ${formatDate(connection.last_used_at)}` + : 'Not used yet'} + + + + +
+
+

Access

+

+ {accessSummary(connection.scopes)} +

+
-
-
Recent token activity
- +
+

Recent activity

+
-
- ))} -
- )} -
- -
-
OAuth app grants
- {grants.length === 0 ? ( -

No ChatGPT or Claude-style OAuth connections yet.

- ) : ( -
- {grants.map((grant) => ( -
-
-
-
{grant.app_name}
-
- {grant.connector_profile} / last used {formatDate(grant.last_used_at)} +

+ Added {formatDate(connection.created_at)} + {connection.kind === 'token' + ? ` · Token ${connection.token_prefix}…` + : ` · ${connection.connector_profile}`} +

+ {confirmRevoke === connection.key ? ( +
+ {error && ( +

+ {error} +

+ )} +

+ Revoke access for {connection.displayName}? It will stop accessing Deft. + To use it again, you will need to reconnect. +

+
+ +
- -
-
- {isStale(grant.last_used_at) && ( - - {grant.last_used_at ? 'stale' : 'unused'} - - )} - {grant.scopes.map((scope) => ( - {scope} - ))} -
- + )}
- ))} -
- )} -
-
- )} -
-
- Add connection -
- -

{setupSteps[setupStep]}

-

{setupStep === 0 ? 'Choose the app you want to use with Deft.' : `${selectedClientOption.name} · ${setupStep === 1 ? 'Understand what this connection can access.' : setupStep === 2 ? 'Follow the instructions for your app.' : 'Check that your app can reach Deft.'}`}

- {newToken && setupStep < 2 &&

This token’s app and access are fixed. Return to Connect to copy it, or finish setup before starting another connection.

} - {error &&

{error}

} - {copied &&

Copied {copied}

} -
-
+ ))} +
+ )} +
+ +
+ + {historyOpen && ( +
+ {loadFailures.includes('Connection history') ? ( +

+ History could not be refreshed. Use Refresh to retry. +

+ ) : loading && !history ? ( +

+ Loading history… +

+ ) : historyCount === 0 ? ( +

+ No revoked connections. +

+ ) : ( + [ + ...(history?.revoked_tokens.map((token) => ({ + ...token, + key: `token:${token.id}`, + displayName: token.name, + label: `Personal token ${token.token_prefix}…`, + })) ?? []), + ...(history?.revoked_grants.map((grant) => ({ + ...grant, + key: `grant:${grant.id}`, + displayName: grant.app_name, + label: grant.connector_profile, + })) ?? []), + ].map((connection) => ( +
+ + {connection.displayName} + + Revoked {formatDate(connection.revoked_at)} + + +

+ {connection.label} · Last used {formatDate(connection.last_used_at)} +

+ + +
+ )) + )} +
+ )} +
+ + ) : ( +
+ + +

+ {setupStep === 0 + ? 'Which app would you like to connect?' + : setupStep === 1 + ? `Review access for ${selectedClientOption.name}` + : setupStep === 2 + ? `Connect ${selectedClientOption.name}` + : 'Check your connection'} +

+

+ {setupStep === 0 + ? 'Choose an app to see its setup instructions.' + : setupStep === 1 + ? 'Choose the access this app needs. Every action is recorded under your name.' + : setupStep === 2 + ? 'Complete the setup in your app, then come back to check its activity.' + : 'Run a request from your app and check whether Deft receives it.'} +

+ {error && ( +

+ {error} +

+ )} + {newToken && setupStep < 2 && ( +

+ A token has already been issued with these permissions. Return to Connect to save it. Start another + connection after finishing this setup to choose different access. +

+ )} -
- {CLIENT_OPTIONS.map((client) => { - const active = client.id === selectedClient; - return ( + {setupStep === 0 && ( +
+ {CLIENT_OPTIONS.map((client) => ( - ); - })} -
-
-
-
+ ))} +
+ )} -
- )} - {selectedClientOption.setupKind === 'oauth' && setupStep === 2 && ( -
-
-
- + {setupStep === 2 && selectedClientOption.setupKind === 'oauth' && ( +
+ {!remote ? ( +
+

+ {loading + ? 'Loading connector settings…' + : 'Connector settings are unavailable. Retry before connecting your app.'} +

+
-
-
-
-

- {isClaudeConnector ? 'Claude connector setup' : 'ChatGPT custom app setup'} -

-

- {isClaudeConnector - ? 'Claude connectors are added from Claude settings at the account level. The URL/token cannot be pasted into an active chat and expected to work.' - : 'ChatGPT connects from OpenAI cloud, so Deft must be publicly reachable over HTTPS. The app uses Deft OAuth; do not paste a personal token into ChatGPT.'} -

-
- - {remote ? (remote.https_ready ? 'HTTPS ready' : 'Needs public HTTPS') : (loading ? 'Checking readiness...' : 'Status unavailable')} - -
- {!loading && !remote && ( -
-

Could not load connector settings. Retry before connecting your AI app.

- -
- )} -
-
- -
-
- {isClaudeConnector ? 'Use Claude settings, not chat' : 'Use the app connector settings'} + ) : ( + !remote.https_ready && ( +

+ Your Deft server needs a public HTTPS address before a hosted app can connect. Ask your workspace + administrator to configure it. +

+ ) + )} +
    + {remoteSteps.map((step) => ( +
  1. {step}
  2. + ))} +
+ {isClaudeConnector ? ( +
+ {claudeConnectorFields.map((field) => ( +
+
+
+

{field.label}

+

+ {field.value} +

-
    - {remoteSteps.map((step) =>
  1. {step}
  2. )} -
-
-
-
-
- Security note: never paste a live bearer token into Claude, ChatGPT, or any AI chat. If you already did, revoke that personal token below and generate a fresh one. Remote Claude connectors should authenticate through Deft OAuth. -
- {isChatGptConnector && ( -
- ChatGPT availability: full read/write custom MCP apps currently require Business or Enterprise/Edu on ChatGPT web. Pro developer mode is limited to read/fetch access. Workspace admin or developer-mode controls may also apply. -
- )} - {isClaudeConnector && ( -
-
Fill Claude's four fields like this
-
- {claudeConnectorFields.map((field) => ( -
-
-
-
{field.label}
-
{field.value}
-
- {field.copyValue && ( - - )} -
-

{field.help}

-
- ))} + {field.copyValue && ( + + )}
+

+ {field.help} +

- )} -
- {remoteRows.slice(0, 3).map(([label, value]) => ( -
-
{label}
-
- {value ?? 'Not loaded'} - {value && ( - - )} -
-
- ))} -
- -
-
-
- )} - - {selectedClientOption.setupKind === 'agent' && setupStep === 2 && ( -
-
-
- + ))}
-
-

Use Agent Employees for shared workers

-

- Personal AI app connections act as you. If Hermes, OpenClaw, Codex, or another runtime should be available to the whole company as an employee, onboard it as an Agent Employee instead. + ) : ( +

+
+

Connector URL

+ {remote?.mcp_endpoint_url && ( + + )} +
+

+ {remote?.mcp_endpoint_url ?? 'Unavailable'}

-
-
+ )} +

+ Sign in through Deft’s authorization screen. Do not paste a personal token into a hosted AI chat. +

+
)} -
- -
- - + )} -
-
- - {setupStep === 2 && selectedClientOption.setupKind === 'agent' ? ( - Open Agent Employees - ) : setupStep < 3 ? ( +
- ) : ( - - )} -
-
- -
- - - {advancedOpen && ( -
- {remoteRows.map(([label, value]) => ( -
-
{label}
-
- {value ?? 'Not loaded'} - {value && ( - - )} -
-
- ))} -
-
Supported remote scopes
-
- {(remote?.scopes ?? AVAILABLE_SCOPES).map((scope) => )} + {setupStep === 2 && selectedClientOption.setupKind === 'agent' ? ( + + Open Agent Employees + + ) : setupStep < 3 ? ( + + ) : ( +
+ +
-
+ )}
- )} -
+
+ )} -
+
- - {historyOpen && ( -
- {!history || historyCount === 0 ? ( -

No revoked connections yet.

- ) : ( - <> - {history.revoked_tokens.length > 0 && ( -
-
- Personal tokens -
-
- {history.revoked_tokens.map((token) => ( -
-
-
-
{token.name}
-
- {token.token_prefix}... / revoked {formatDate(token.revoked_at)} / last used {formatDate(token.last_used_at)} -
-
- - revoked - -
-
- {token.scopes.map((scope) => ( - {scope} - ))} -
- -
- ))} -
-
- )} - - {history.revoked_grants.length > 0 && ( -
-
- AI app connections -
-
- {history.revoked_grants.map((grant) => ( -
-
-
-
{grant.app_name}
-
- {grant.connector_profile} / revoked {formatDate(grant.revoked_at)} / last used {formatDate(grant.last_used_at)} -
-
- - revoked - -
-
- {grant.scopes.map((scope) => ( - {scope} - ))} -
- -
- ))} -
-
- )} - + {advancedOpen && ( +
+ {loadFailures.includes('Connector settings') && ( +
+

Connector metadata is unavailable.

+ +
)} + {[['MCP endpoint', endpoint || undefined], ...remoteRows].map(([label, value]) => ( +
+
+

{label}

+ + {value ?? 'Unavailable'} + +
+ {value && } +
+ ))} + +
+ Memory context +
+ {CONTEXT_PACKET_CARDS.map((card) => ( +
+
{card.title}
+
+ {card.detail} +
+
+ ))} +
+
)}
diff --git a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md index 5b4435d7..b3dd8502 100644 --- a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md +++ b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md @@ -161,8 +161,33 @@ production deployment, real credential grants or external messages are implied. checks command containment and name retention; CI execution remains pending. - Screenshots: `tmp/preview-evidence/guided-access-desktop.png` and `guided-connect-mobile.png`. These are fixture-based visual evidence only. -- Next: finish connection management detail and local activity/error feedback, - strengthen keyboard/zoom and real issuance verification, then apply the shared - patterns to Profile/Calendar/AI. Module ownership and canonical employee work - require their explicit contract/control audits before implementation. +- Whole-page follow-through (PR #324, stacked on #323): replaced the management + dashboard with a searchable unified token/authorization list, expandable access + and activity, inline revoke confirmation, and restrained history/developer + disclosures. Setup is a separate view with compact client rows, a plain-language + access selector, focused credential instructions and connection-specific checks. + Cancelling preserves drafts; finishing clears the acknowledged credential. + Partial request failures retain the last inventory with an explicit warning; + history and metadata failures have distinct retry states. Verification prompts + follow the selected connection's actual permissions. Copy feedback is local. +- Fresh whole-page evidence: seven client paths at 390 and 1440 CSS px without + section overflow; management and expanded revoke confirmation also checked at + 320 px. Inspected dark desktop/mobile and light desktop/reflow layouts. Tested + search/clear, empty state, partial load failures/recovery, token and grant revoke, + failed revoke/retry, custom-scope validation, draft retention, inert issuance, + acknowledgement/duplicate guards, pending and fixture-observed activity, + grant-specific prompt permissions, and focus on steps/confirm/cancel/finish. + Web typecheck, full web lint, three navigation tests, smoke syntax and diff check + passed. Production smoke now includes issuance/acknowledgement/revoke against + its disposable seeded backend; that updated smoke has not been run locally. +- Current screenshots: `tmp/preview-evidence/connections-whole-desktop.png`, + `connections-whole-mobile.png`, `connections-whole-light.png`, and + `connections-access-desktop.png` / `connections-access-mobile.png`. + All are synthetic fixture evidence, not proof of OAuth or persistence. Browser + zoom and screen-reader acceptance remain unverified; narrow reflow is not a zoom + test. The preview fixture returns to read-only mode after the interaction pass. +- Next: obtain database-backed integration and independent usability evidence for + this page, strengthen zoom/screen-reader acceptance, then apply the patterns to + Profile/Calendar/AI. Module ownership and canonical employee work require their + explicit contract/control audits before implementation. - Open: dependency audit, real integration evidence, independent usability review. diff --git a/scripts/product-browser-smoke.mjs b/scripts/product-browser-smoke.mjs index 2b85574b..6cdcccf4 100644 --- a/scripts/product-browser-smoke.mjs +++ b/scripts/product-browser-smoke.mjs @@ -107,7 +107,7 @@ async function main() { ['/settings', 'Settings'], ['/settings/profile', 'Profile'], ['/settings/apps', 'Apps'], - ['/settings/mcp-access', 'Manage active connections'], + ['/settings/mcp-access', 'Your connections'], ]) { await settle(page, path); await page.getByRole('heading', { name: heading }).first().waitFor({ timeout: 10_000 }); @@ -117,20 +117,17 @@ async function main() { } record('Navigate core settings surfaces'); - await page.getByText('Add connection', { exact: true }).click(); - await page.getByRole('heading', { name: 'What do you want to connect?', exact: true }).waitFor(); - await page.getByRole('button', { name: /^Claude Code Token setup/ }).click(); + await page.getByRole('searchbox', { name: 'Search connections' }).fill('no-such-smoke-connection'); + await page.getByRole('heading', { name: 'No matching connections' }).waitFor(); + await page.getByRole('button', { name: 'Clear search', exact: true }).click(); + await page.getByRole('button', { name: 'Add connection', exact: true }).click(); + await page.getByRole('heading', { name: 'Which app would you like to connect?', exact: true }).waitFor(); + await page.getByRole('button', { name: /^Claude Code Use a personal token/ }).click(); await page.getByRole('button', { name: 'Review access', exact: true }).click(); - await page.getByRole('button', { name: /^Choose individually/ }).click(); + await page.getByRole('combobox', { name: 'Access level', exact: true }).selectOption('custom'); for (const width of [1440, 1024, 768, 390]) { await page.setViewportSize({ width, height: 900 }); - const setupOverflow = await page.locator('main aside').evaluate((aside) => { - const grid = aside.parentElement; - return Math.max( - grid.scrollWidth - grid.clientWidth, - ...Array.from(grid.querySelectorAll('section')).map((section) => section.scrollWidth - section.clientWidth), - ); - }); + const setupOverflow = await page.locator('section[aria-labelledby="setup-heading"]').evaluate((section) => section.scrollWidth - section.clientWidth); if (setupOverflow > 2) throw new Error(`Claude Code setup overflows its cards by ${setupOverflow}px at ${width}px`); await page.getByRole('button', { name: 'Continue to connect', exact: true }).click(); await page.getByRole('textbox', { name: 'Connection name', exact: true }).fill('Smoke test draft'); @@ -148,6 +145,34 @@ async function main() { } record('Claude Code custom permissions stay inside setup cards at desktop, tablet and mobile widths'); + for (const checkbox of await page.getByRole('checkbox').all()) await checkbox.uncheck(); + if (await page.getByRole('button', { name: 'Continue to connect', exact: true }).isEnabled()) { + throw new Error('Setup permits an empty permission selection'); + } + await page.getByRole('checkbox', { name: 'Read tasks, comments and progress', exact: true }).check(); + await page.getByRole('button', { name: 'Continue to connect', exact: true }).click(); + const personalConnectionName = `Browser smoke ${Date.now()}`; + await page.getByRole('textbox', { name: 'Connection name', exact: true }).fill(personalConnectionName); + await page.getByRole('button', { name: 'Generate token', exact: true }).click(); + await page.getByRole('checkbox', { name: 'I have saved this token securely.', exact: true }).waitFor({ timeout: 10_000 }); + if (await page.getByRole('button', { name: 'Check connection', exact: true }).isEnabled()) { + throw new Error('Setup skipped the one-time token acknowledgement'); + } + await page.getByRole('checkbox', { name: 'I have saved this token securely.', exact: true }).check(); + await page.getByRole('button', { name: 'Check connection', exact: true }).click(); + await page.getByRole('heading', { name: 'Waiting for the first request', exact: true }).waitFor(); + await page.getByRole('button', { name: 'Your connections', exact: true }).click(); + await page.getByRole('searchbox', { name: 'Search connections' }).fill(personalConnectionName); + await page.getByText(personalConnectionName, { exact: true }).click(); + await page.getByRole('button', { name: 'Revoke access', exact: true }).click(); + await page.getByRole('button', { name: 'Keep connection', exact: true }).click(); + await page.getByRole('button', { name: 'Revoke access', exact: true }).click(); + await page.getByRole('button', { name: 'Confirm revoke', exact: true }).click(); + await page.getByRole('heading', { name: 'No matching connections', exact: true }).waitFor(); + await page.getByRole('button', { name: /^Connection history/ }).click(); + await page.getByText(personalConnectionName, { exact: false }).last().waitFor(); + record('Create, acknowledge, inspect and revoke a personal connection without exposing its token'); + await page.setViewportSize({ width: 1440, height: 900 }); await settle(page, '/settings/modules'); const availableTab = page.getByRole('button', { name: /Available/i }).first(); From 6ca1bb7112d385494c888b4831a79780bdbd13f4 Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 14:15:27 +0530 Subject: [PATCH 06/11] Polish personal connection page contrast and layout --- .../(app)/settings/mcp-access/page.module.css | 98 +++++++++++++++++++ .../app/(app)/settings/mcp-access/page.tsx | 25 +++-- .../2026-09-09-settings-maturity-program.md | 10 ++ 3 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 apps/web/src/app/(app)/settings/mcp-access/page.module.css diff --git a/apps/web/src/app/(app)/settings/mcp-access/page.module.css b/apps/web/src/app/(app)/settings/mcp-access/page.module.css new file mode 100644 index 00000000..c943c12f --- /dev/null +++ b/apps/web/src/app/(app)/settings/mcp-access/page.module.css @@ -0,0 +1,98 @@ +.page { + /* Local contrast: the workspace ghost border is too faint for form controls. */ + --border-default: color-mix(in srgb, var(--text-primary) 17%, transparent); + --connection-action: #7056dc; + color: var(--text-primary); +} + +.page :is(button, a, input, select, summary, pre):focus-visible { + outline: 2px solid var(--primary); + outline-offset: 3px; +} + +.page :is(button, a, summary) { + transition: + background-color 140ms ease, + border-color 140ms ease, + box-shadow 140ms ease; +} + +.page button:not(:disabled):hover { + box-shadow: inset 0 0 0 100px color-mix(in srgb, var(--text-primary) 6%, transparent); +} + +.page button:disabled { + cursor: not-allowed; +} + +.page :is(input:not([type='checkbox']), select) { + background-color: var(--surface-container-low); + color: var(--text-primary); + border-color: color-mix(in srgb, var(--text-primary) 30%, transparent); +} + +.page input::placeholder { + color: var(--text-tertiary); + opacity: 1; +} + +.page input[type='checkbox'] { + width: 1rem; + height: 1rem; + accent-color: var(--accent); +} + +.page :is(summary, p, code, strong) { + overflow-wrap: anywhere; +} + +.page summary { + border-radius: 6px; +} + +.page summary:hover { + background-color: color-mix(in srgb, var(--text-primary) 4%, transparent); +} + +.connectionList { + background: var(--surface-container-low); + overflow: clip; +} + +.connectionList > details + details { + border-color: var(--border-default); +} + +.connectionList > details[open] { + background: color-mix(in srgb, var(--surface-container) 65%, var(--surface)); +} + +.connectionList > details > summary:focus-visible { + outline-offset: -2px; +} + +.setup { + width: 100%; + max-width: 44rem; +} + +.setup nav { + padding: 1rem; + border: 1px solid var(--border-default); + border-radius: 0.75rem; + background: var(--surface-container-low); +} + +.setup nav [aria-current='step'] > span:first-child { + background: var(--accent-muted); +} + +.clientChoice { + min-height: 4.5rem; +} + +@media (prefers-reduced-motion: reduce) { + .page :is(button, a, summary) { + transition: none; + } +} diff --git a/apps/web/src/app/(app)/settings/mcp-access/page.tsx b/apps/web/src/app/(app)/settings/mcp-access/page.tsx index d2903c98..015b949e 100644 --- a/apps/web/src/app/(app)/settings/mcp-access/page.tsx +++ b/apps/web/src/app/(app)/settings/mcp-access/page.tsx @@ -6,6 +6,7 @@ import { Bot, Check, ChevronDown, Code2, Copy, Globe2, KeyRound, Plug, Wrench } import { api } from '@/lib/api'; import { useSetPageContext } from '@/components/app-header-context'; import { SettingsSteps } from '@/components/settings-steps'; +import styles from './page.module.css'; type McpToken = { id: string; @@ -736,7 +737,11 @@ export default function McpAccessPage() { const muted = { color: 'var(--text-secondary)' }; const buttonClass = 'inline-flex min-h-10 items-center justify-center gap-2 rounded-lg border px-3 py-2 text-sm font-medium focus-visible:outline-2 focus-visible:outline-offset-2 disabled:opacity-40'; - const primaryStyle = { background: 'var(--accent)', borderColor: 'var(--accent)', color: 'white' }; + const primaryStyle = { + background: 'var(--connection-action)', + borderColor: 'var(--connection-action)', + color: 'white', + }; function openSetup() { focusStep.current = true; @@ -761,9 +766,9 @@ export default function McpAccessPage() { } return ( -
-
-
+
+
+

Personal AI connections

Connect your AI apps to Deft. You control their access. @@ -865,7 +870,7 @@ export default function McpAccessPage() { )}

) : ( -
+
{filteredConnections.map((connection) => (
@@ -877,7 +882,7 @@ export default function McpAccessPage() { {connection.displayName} - + {connection.label} ·{' '} {connection.last_used_at ? `Last used ${formatDate(connection.last_used_at)}` @@ -1029,7 +1034,7 @@ export default function McpAccessPage() {
) : ( -
+
{howToOpen && ( -
+

Apple Calendar.{' '} File → New Calendar Subscription → paste the URL. @@ -268,7 +268,7 @@ function OutboundSection() { {confirmRegen ? (

@@ -279,7 +279,7 @@ function OutboundSection() { type="button" onClick={() => setConfirmRegen(false)} disabled={regenerating} - className="h-8 px-3 text-[12px] font-medium rounded-md" + className="h-8 px-3 text-sm font-medium rounded-md" style={{ background: 'var(--surface)', color: 'var(--foreground)', border: '1px solid var(--border)' }} > Cancel @@ -288,7 +288,7 @@ function OutboundSection() { type="button" onClick={regenerate} disabled={regenerating} - className="h-8 px-3 flex items-center gap-1.5 text-[12px] font-medium rounded-md disabled:opacity-50" + className="h-8 px-3 flex items-center gap-1.5 text-sm font-medium rounded-md disabled:opacity-50" style={{ background: 'var(--error)', color: 'white' }} > @@ -301,7 +301,7 @@ function OutboundSection() { type="button" onClick={() => setConfirmRegen(true)} disabled={!feedUrl} - className="inline-flex items-center gap-1.5 text-[12px] disabled:opacity-50" + className="inline-flex items-center gap-1.5 text-sm disabled:opacity-50" style={{ color: 'var(--muted)' }} > @@ -336,7 +336,7 @@ function InboundSection() {

Connect external calendars to Deft @@ -344,15 +344,15 @@ function InboundSection() { {!showAdd && ( )}

-

+

Paste a secret ICS feed URL from Google, iCloud, or Outlook to read those events into Deft. The agent uses them for context — nothing's sent back.

@@ -369,14 +369,14 @@ function InboundSection() {
{loading ? (
Loading subscriptions…
) : subs.length === 0 ? (
No inbound calendar subscriptions yet. Add one above to start ingesting events. @@ -396,7 +396,7 @@ function InboundSection() { {whereOpen && ( -
+

Google Calendar.{' '} Settings → Settings for my calendars → pick the calendar → Integrate calendar → "Secret address in iCal format". @@ -491,12 +491,12 @@ function AddSubscriptionForm({ style={{ background: 'var(--card-bg)', border: '1px solid var(--border)' }} > {err && ( -

+
{err}
)}
-
-
@@ -539,10 +539,10 @@ function AddSubscriptionForm({
-

+

{preview.calendar_name || 'Calendar feed'}

-

+

Found {preview.event_count} event{preview.event_count === 1 ? '' : 's'}.

@@ -553,7 +553,7 @@ function AddSubscriptionForm({ {preview.upcoming.length > 0 && (
{preview.upcoming.map((event) => ( -
+
{event.title} {formatDateTime(event.starts_at)}
@@ -564,7 +564,7 @@ function AddSubscriptionForm({ )}
-
-
{TAG_COLORS.map(c => ( - diff --git a/docs/superpowers/audits/2026-09-09-settings-review-passes.md b/docs/superpowers/audits/2026-09-09-settings-review-passes.md new file mode 100644 index 00000000..5c29e477 --- /dev/null +++ b/docs/superpowers/audits/2026-09-09-settings-review-passes.md @@ -0,0 +1,83 @@ +# Settings review passes — 2026-09-09 + +Scope: visual and interaction review of the current Settings implementation on +`codex/settings-visual-polish`, using the localhost:3025 app and synthetic, +read-only API fixture. This is not a production integration certification. + +## Pass 1: route inventory and desktop layout + +Visited all 18 top-level Settings routes at 1440 CSS px. Pages loaded without a +rendered application crash or page-level horizontal overflow. Profile's initial +automated heading observation matched an Overview card during navigation; +the saved Profile screenshot and subsequent direct inspection verified the page. + +| Route | Desktop | Mobile initial layout (390 CSS px) | +| --- | --- | --- | +| `/settings` | Reviewed | Reviewed | +| `/settings/profile` | Reviewed | Reviewed | +| `/settings/mcp-access` | Reviewed | Reviewed | +| `/settings/calendar` | Reviewed | Reviewed | +| `/settings/members` | Reviewed | Reviewed | +| `/settings/teams` | Reviewed | Reviewed | +| `/settings/apps` | Reviewed | Reviewed | +| `/settings/modules` | Reviewed | Reviewed | +| `/settings/groups` | Reviewed | Reviewed | +| `/settings/agent-employees` | Reviewed | Reviewed | +| `/settings/ai` | Reviewed | Reviewed | +| `/settings/integrations` | Reviewed | Reviewed | +| `/settings/agent` | Reviewed | Reviewed | +| `/settings/library` | Reviewed | Missing title fixed | +| `/settings/workflows` | Reviewed | Narrow action fixed | +| `/settings/tags` | Reviewed | Initial layout fits; form overflow fixed | +| `/settings/projects` | Reviewed | Reviewed | +| `/settings/api-access` | Reviewed | Narrow action fixed | + +## Pass 2: mobile screenshots + +Saved and inspected initial screenshots for all 18 routes. Page-level width alone +was insufficient: a nested horizontal scrolling container hid overflowing tag-form +controls. The follow-up check measured individual visible control bounds too. + +Evidence: `tmp/preview-evidence/audit-mobile-0.png` through `audit-mobile-17.png`, +three `audit-sheet-*.png` contact sheets, and `settings-audit.json`. These ignored +local artifacts use sample data; they are not checked into the repository. + +## Pass 3: forms, secondary routes, and fixes + +Opened service-key, task-rule, tag, group, team and invitation forms at phone width. +Inspected agent creation and the staged Contacts App detail route. No invitations, +credentials, App activation, trust changes or external writes were performed. + +Reproduced and fixed: + +1. Task templates used a compact PageHeader without an alternative mobile title. + Removed compact mode; the title is now visibly rendered at 390px. +2. Task-rule creation action was squeezed into a tall, narrow label by the heading + row. Stack the header on narrow screens and keep the action from shrinking. +3. Service API creation action had the same problem. Applied the same bounded fix. +4. Tag creation's Create and Cancel controls extended to approximately 397px and + 441px on a 390px viewport. Use a two-row mobile grid and a shrinkable input. + Give the input, cancel control and colour buttons accessible names and expose + the selected colour with aria-pressed. + +Fresh recheck: zero offscreen tag controls at 390px and 320px; colour selection +updates aria-pressed; cancel closes the form. Inspected corrected screenshots for +all four pages: `audit-fixed-{tags,templates,rules,service}-mobile.png`. + +Web typecheck, focused ESLint for the four changed pages, three Settings navigation +tests, and git diff whitespace checks passed. No backend contracts changed. + +## Remaining evidence gaps + +- The four employee record routes (detail, developer, heartbeats, webhooks) need + populated employee records; this fixture has none. Their healthy rendered states + were not certified in this pass. +- Empty lists do not prove populated tables, long records, pagination or every + dialog state. The staged App detail is one sample, not lifecycle certification. +- Save persistence, real OAuth/MCP connections, role-based runtime authorization, + screen-reader use, browser zoom and exhaustive light-theme states remain outside + this pass. Previous light-theme inspection was representative, not exhaustive. +- Some existing forms still use placeholder-only labels and small controls. The + fixes above are specific findings, not a claim of complete accessibility. + +PR #325 remains stacked on #324 and unmerged for user review. diff --git a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md index f76ef30b..85473d99 100644 --- a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md +++ b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md @@ -215,3 +215,9 @@ production deployment, real credential grants or external messages are implied. shared visual baseline, not a completed individual redesign of every route. Fixture evidence: `tmp/preview-evidence/settings-*.png`. Persistence and full mobile/role coverage of the administration pages remain unverified. +- Three review passes completed over 18 top-level routes (desktop, mobile, forms). + Fixed missing mobile Task templates title, squeezed task-rule/service-key actions, + and tag-form overflow with accessible colour/cancel controls. Fresh 320/390px + rechecks, typecheck, focused lint and navigation tests passed. See + `docs/superpowers/audits/2026-09-09-settings-review-passes.md` for exact coverage + and gaps, including the four employee detail routes without fixture records. From 82e5ab9661e4b19745f1630319bc205ad15025ed Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:27:00 +0530 Subject: [PATCH 09/11] Patch vulnerable dependencies for Settings merge and demo closeout --- apps/web/package.json | 46 +- .../2026-09-09-settings-maturity-program.md | 18 + pnpm-lock.yaml | 964 +++++++++--------- pnpm-workspace.yaml | 6 +- 4 files changed, 526 insertions(+), 508 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index bfe00e20..70b8b518 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -17,27 +17,27 @@ "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@tailwindcss/postcss": "^4.3.3", - "@tiptap/core": "^3.30.4", - "@tiptap/extension-code-block-lowlight": "^3.30.4", - "@tiptap/extension-details": "^3.30.4", - "@tiptap/extension-document": "^3.30.4", - "@tiptap/extension-highlight": "^3.30.4", - "@tiptap/extension-image": "^3.30.4", - "@tiptap/extension-link": "^3.30.4", - "@tiptap/extension-paragraph": "^3.30.4", - "@tiptap/extension-placeholder": "^3.30.4", - "@tiptap/extension-table": "^3.30.4", - "@tiptap/extension-table-cell": "^3.30.4", - "@tiptap/extension-table-header": "^3.30.4", - "@tiptap/extension-table-row": "^3.30.4", - "@tiptap/extension-task-item": "^3.30.4", - "@tiptap/extension-task-list": "^3.30.4", - "@tiptap/extension-text": "^3.30.4", - "@tiptap/extension-underline": "^3.30.4", - "@tiptap/pm": "^3.30.4", - "@tiptap/react": "^3.30.4", - "@tiptap/starter-kit": "^3.30.4", - "@tiptap/suggestion": "^3.30.4", + "@tiptap/core": "^3.30.5", + "@tiptap/extension-code-block-lowlight": "^3.30.5", + "@tiptap/extension-details": "^3.30.5", + "@tiptap/extension-document": "^3.30.5", + "@tiptap/extension-highlight": "^3.30.5", + "@tiptap/extension-image": "^3.30.5", + "@tiptap/extension-link": "^3.30.5", + "@tiptap/extension-paragraph": "^3.30.5", + "@tiptap/extension-placeholder": "^3.30.5", + "@tiptap/extension-table": "^3.30.5", + "@tiptap/extension-table-cell": "^3.30.5", + "@tiptap/extension-table-header": "^3.30.5", + "@tiptap/extension-table-row": "^3.30.5", + "@tiptap/extension-task-item": "^3.30.5", + "@tiptap/extension-task-list": "^3.30.5", + "@tiptap/extension-text": "^3.30.5", + "@tiptap/extension-underline": "^3.30.5", + "@tiptap/pm": "^3.30.5", + "@tiptap/react": "^3.30.5", + "@tiptap/starter-kit": "^3.30.5", + "@tiptap/suggestion": "^3.30.5", "@types/react-resizable": "^4.0.0", "@types/turndown": "^5.0.6", "d3-drag": "^3.0.0", @@ -47,7 +47,7 @@ "dompurify": "^3.4.13", "lowlight": "^3.3.0", "lucide-react": "^1.31.0", - "next": "16.3.1", + "next": "16.3.3", "postcss": "^8.5.26", "react": "^19.2.8", "react-dom": "^19.2.8", @@ -75,7 +75,7 @@ "@types/react-grid-layout": "^1.3.6", "@types/simple-peer": "^9.11.9", "eslint": "^9.39.5", - "eslint-config-next": "16.3.1", + "eslint-config-next": "16.3.3", "typescript": "^6.0.3" } } diff --git a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md index 85473d99..617dde59 100644 --- a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md +++ b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md @@ -221,3 +221,21 @@ production deployment, real credential grants or external messages are implied. rechecks, typecheck, focused lint and navigation tests passed. See `docs/superpowers/audits/2026-09-09-settings-review-passes.md` for exact coverage and gaps, including the four employee detail routes without fixture records. + +## Merge and demo closeout — 2026-09-09 + +The user approved merging the Settings stack and updating demo.deft.ing. PR #323 +is the consolidated candidate incorporating #324 and #325. Keep the schedule +deleted. Remaining Track B/C/D and Gate G work is outside this UI closeout. + +The final dependency audit reproduced eight advisories. Updated Next.js and its +ESLint config to 16.3.3, the Tiptap family to a patched compatible release, and +Hono, Sharp and js-yaml overrides. The regenerated lockfile passes the full +low-threshold pnpm audit with no known vulnerabilities. Full candidate CI remains +the merge gate; no bypass of image scanning or database-backed browser smoke. + +Demo currently runs preview.14 (6d39e0e). Deploy the merged revision through a +separate source checkout, preserve site configuration and existing feature flags, +record the old image, take a stopped database/uploads/configuration backup, and +rehearse the versioned upgrade against a restored database before live cutover. +Verify doctor, connector smoke, build identity and rendered Settings after deploy. diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4b31fa58..b658354c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,13 +12,13 @@ overrides: engine.io: ^6.6.7 esbuild: ^0.28.1 fast-uri: ^3.1.5 - hono: ^4.12.34 + hono: ^4.13.5 ip-address: ^10.3.1 - js-yaml: ^4.3.1 + js-yaml: ^4.3.2 nanoid: ^3.3.17 postcss: ^8.5.23 qs: ^6.15.2 - sharp: ^0.35.3 + sharp: ^0.35.4 socket.io-parser: ^4.2.7 ws: ^8.21.0 @@ -55,7 +55,7 @@ importers: version: link:../../packages/shared '@hono/node-server': specifier: ^2.0.12 - version: 2.1.1(hono@4.13.2) + version: 2.1.1(hono@4.13.7) bcryptjs: specifier: ^3.0.3 version: 3.0.3 @@ -69,11 +69,11 @@ importers: specifier: 0.8.3 version: 0.8.3 hono: - specifier: ^4.12.34 - version: 4.13.2 + specifier: ^4.13.5 + version: 4.13.7 hono-rate-limiter: specifier: ^0.5.3 - version: 0.5.3(hono@4.13.2) + version: 0.5.3(hono@4.13.7) jsonwebtoken: specifier: ^9.0.3 version: 9.0.3 @@ -133,68 +133,68 @@ importers: specifier: ^4.3.3 version: 4.3.3 '@tiptap/core': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/pm@3.30.4) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/pm@3.31.3) '@tiptap/extension-code-block-lowlight': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/extension-code-block@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)(highlight.js@11.11.1)(lowlight@3.3.0) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/extension-code-block@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(highlight.js@11.11.1)(lowlight@3.3.0) '@tiptap/extension-details': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/extension-text-style@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)))(@tiptap/pm@3.30.4) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/extension-text-style@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)))(@tiptap/pm@3.31.3) '@tiptap/extension-document': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-highlight': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-image': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-link': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) '@tiptap/extension-paragraph': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-placeholder': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-table': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) '@tiptap/extension-table-cell': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-table-header': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-table-row': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-task-item': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-task-list': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) '@tiptap/extension-text': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/extension-underline': - specifier: ^3.30.4 - version: 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) + specifier: ^3.30.5 + version: 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) '@tiptap/pm': - specifier: ^3.30.4 - version: 3.30.4 + specifier: ^3.30.5 + version: 3.31.3 '@tiptap/react': - specifier: ^3.30.4 - version: 3.30.4(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: ^3.30.5 + version: 3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) '@tiptap/starter-kit': - specifier: ^3.30.4 - version: 3.30.4 + specifier: ^3.30.5 + version: 3.31.3 '@tiptap/suggestion': - specifier: ^3.30.4 - version: 3.30.4(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + specifier: ^3.30.5 + version: 3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) '@types/react-resizable': specifier: ^4.0.0 version: 4.0.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8) @@ -223,8 +223,8 @@ importers: specifier: ^1.31.0 version: 1.31.0(react@19.2.8) next: - specifier: 16.3.1 - version: 16.3.1(@babel/core@7.29.7)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + specifier: 16.3.3 + version: 16.3.3(@babel/core@7.29.7)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) postcss: specifier: ^8.5.23 version: 8.5.26 @@ -302,8 +302,8 @@ importers: specifier: ^9.39.5 version: 9.39.5(jiti@2.7.0) eslint-config-next: - specifier: 16.3.1 - version: 16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3) + specifier: 16.3.3 + version: 16.3.3(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3) typescript: specifier: ^6.0.3 version: 6.0.3 @@ -884,7 +884,7 @@ packages: resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} engines: {node: '>=20'} peerDependencies: - hono: ^4.12.34 + hono: ^4.13.5 '@humanfs/core@0.19.2': resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} @@ -910,160 +910,160 @@ packages: resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.35.3': - resolution: {integrity: sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==} + '@img/sharp-darwin-arm64@0.35.4': + resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.35.3': - resolution: {integrity: sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==} + '@img/sharp-darwin-x64@0.35.4': + resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-freebsd-wasm32@0.35.3': - resolution: {integrity: sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==} + '@img/sharp-freebsd-wasm32@0.35.4': + resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} engines: {node: '>=20.9.0'} os: [freebsd] - '@img/sharp-libvips-darwin-arm64@1.3.2': - resolution: {integrity: sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==} + '@img/sharp-libvips-darwin-arm64@1.3.3': + resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.3.2': - resolution: {integrity: sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==} + '@img/sharp-libvips-darwin-x64@1.3.3': + resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.3.2': - resolution: {integrity: sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==} + '@img/sharp-libvips-linux-arm64@1.3.3': + resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-arm@1.3.2': - resolution: {integrity: sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==} + '@img/sharp-libvips-linux-arm@1.3.3': + resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.3.2': - resolution: {integrity: sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==} + '@img/sharp-libvips-linux-ppc64@1.3.3': + resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.3.2': - resolution: {integrity: sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==} + '@img/sharp-libvips-linux-riscv64@1.3.3': + resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.3.2': - resolution: {integrity: sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==} + '@img/sharp-libvips-linux-s390x@1.3.3': + resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-libvips-linux-x64@1.3.2': - resolution: {integrity: sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==} + '@img/sharp-libvips-linux-x64@1.3.3': + resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': - resolution: {integrity: sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==} + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.3.2': - resolution: {integrity: sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==} + '@img/sharp-libvips-linuxmusl-x64@1.3.3': + resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-linux-arm64@0.35.3': - resolution: {integrity: sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==} + '@img/sharp-linux-arm64@0.35.4': + resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@img/sharp-linux-arm@0.35.3': - resolution: {integrity: sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==} + '@img/sharp-linux-arm@0.35.4': + resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} engines: {node: '>=20.9.0'} cpu: [arm] os: [linux] libc: [glibc] - '@img/sharp-linux-ppc64@0.35.3': - resolution: {integrity: sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==} + '@img/sharp-linux-ppc64@0.35.4': + resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} engines: {node: '>=20.9.0'} cpu: [ppc64] os: [linux] libc: [glibc] - '@img/sharp-linux-riscv64@0.35.3': - resolution: {integrity: sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==} + '@img/sharp-linux-riscv64@0.35.4': + resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} engines: {node: '>=20.9.0'} cpu: [riscv64] os: [linux] libc: [glibc] - '@img/sharp-linux-s390x@0.35.3': - resolution: {integrity: sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==} + '@img/sharp-linux-s390x@0.35.4': + resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} engines: {node: '>=20.9.0'} cpu: [s390x] os: [linux] libc: [glibc] - '@img/sharp-linux-x64@0.35.3': - resolution: {integrity: sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==} + '@img/sharp-linux-x64@0.35.4': + resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.35.3': - resolution: {integrity: sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==} + '@img/sharp-linuxmusl-arm64@0.35.4': + resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] libc: [musl] - '@img/sharp-linuxmusl-x64@0.35.3': - resolution: {integrity: sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==} + '@img/sharp-linuxmusl-x64@0.35.4': + resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] libc: [musl] - '@img/sharp-wasm32@0.35.3': - resolution: {integrity: sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==} + '@img/sharp-wasm32@0.35.4': + resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} engines: {node: '>=20.9.0'} - '@img/sharp-webcontainers-wasm32@0.35.3': - resolution: {integrity: sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==} + '@img/sharp-webcontainers-wasm32@0.35.4': + resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.35.3': - resolution: {integrity: sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==} + '@img/sharp-win32-arm64@0.35.4': + resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.35.3': - resolution: {integrity: sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==} + '@img/sharp-win32-ia32@0.35.4': + resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.35.3': - resolution: {integrity: sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==} + '@img/sharp-win32-x64@0.35.4': + resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] @@ -1106,60 +1106,60 @@ packages: resolution: {integrity: sha512-r3ZZhRjEcfEdKIZnoB1RusNgvHuaBRqfCzV4Gi+5A9yUX0S4HTws/ASWqt13wL4y4I+0rqsWGdA2w7EQXHi3+Q==} engines: {node: '>=19.0.0'} - '@next/env@16.3.1': - resolution: {integrity: sha512-35G3xwkQUb2oETSDjFXGrVugknoayLFBh7vSE+yAcl9IP2zT9wyGwq7297AYHR11kJld807t5f8AJBs6WBzXsQ==} + '@next/env@16.3.3': + resolution: {integrity: sha512-U2eYQRwXj+dsqxV79zFqExDdatnNY/ZWc2nsJU1p/OgT7fd3dXwlF6OjYaFQCfMoeTA19PWq+wVmYgimVA+V+g==} - '@next/eslint-plugin-next@16.3.1': - resolution: {integrity: sha512-B4SznlXwVpaLDa7Tbi6zLuueria2d/PmFDhXyDymPGrk2r1n/RMJmcn5FZq1L64k+Jsyte1lKvOr7lP9Xo80mQ==} + '@next/eslint-plugin-next@16.3.3': + resolution: {integrity: sha512-pbEh30vvjKpDoTAmo1v3q2uM4JUi8QaEBpbmjWvGfoec2jLghy/WNtvzAT0bk+Ik9oz6etjt4YjXEk4BQnicCw==} - '@next/swc-darwin-arm64@16.3.1': - resolution: {integrity: sha512-ABMIu2zQ7cnNIHm5ivKGwZwUrm0pAai3yiJ/gK/rF1c1VP9UOnj7XECbMKFdVKp9I9eMYq9NoDs1WXOoowxzJw==} + '@next/swc-darwin-arm64@16.3.3': + resolution: {integrity: sha512-8Hiv32QJPwdV6KYJ8meR9SBA061tQqnIKTJDocvOXlEQqib0xMFpzArosuffFUUc0sslbh7QQ8a3Yey1QV8EIw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.3.1': - resolution: {integrity: sha512-gNG21e/UnrroeScbY/QndUEdl0mF1FRibW7BBeYUz/5ABCepjqDdEdgr592vpzMtCn/m7FTjYq3TN4TpyDnutw==} + '@next/swc-darwin-x64@16.3.3': + resolution: {integrity: sha512-A1lgKgwVchRYmSe467zdwhxT9040dd8lH+o65sL5Jet8fjB4kegw/rDyPIpYVRb6jAqwXFOJpjIXJLxQKLiE3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.3.1': - resolution: {integrity: sha512-6B6Lw016iwNUQuaJoraMMTLh6TwHzFUtxipSScD1F3YyymcrRWkobodRS2ftIOkF5vrs4zNlyUrTC5YZQ9Lz5w==} + '@next/swc-linux-arm64-gnu@16.3.3': + resolution: {integrity: sha512-bf0FIssMFueU2dm7vQEWWxk0c8UjKTdW0yzuh0sQsD8pf1+KCLDdaqhYZNMYGmXwEOiHAUzgBKudovIlcvvBjg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.3.1': - resolution: {integrity: sha512-JUiPXZKK9wOhjf4MgDiH29GZLxfqOesbLtHq2pDxwH/WwscTRV2ToymnOTh1egzaZf0ueUf8T2+CeYTGHjW0Iw==} + '@next/swc-linux-arm64-musl@16.3.3': + resolution: {integrity: sha512-W7viwCk9JY/cAkdz/A273rd5bb3RgT/IHwR7Upv90tunjBWNtAAhGhoecHh+teRNRSinuAFmE+l7fwZ4YKkrXg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.3.1': - resolution: {integrity: sha512-Uog9jsrmIRIL/lfvIp9htmskSNC7JcQsMVucXL2V2YY1y/D9IUN3LPEafqy0zRJ2cIU1SQ0V6F6TlffQ+pLAGg==} + '@next/swc-linux-x64-gnu@16.3.3': + resolution: {integrity: sha512-0W46zw1N3ODpI6n0GeivHvvob1pooozgZVqy65k0mh4/7vr+FbY9+WpHzNVXjHipJf/A3FDheBG19H1s5A25rA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.3.1': - resolution: {integrity: sha512-6yy3FT13KgUFOj5H8bl8w/6nKiJwHIvbtwh1V+1acsu+7y4tJjnemSa6mhsh53BeoVrlozE+fMgZhXH46WmjMA==} + '@next/swc-linux-x64-musl@16.3.3': + resolution: {integrity: sha512-H4mBso8ZTMBPtdT0PN0pBx2ayTvQuTuvS6qT13d77yVFJXAPCxkyIhLTmdMaGTJs0krQYI/qpzdHijCeihXhbg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.3.1': - resolution: {integrity: sha512-iOoN1QecUoGNZik536U/vtK43YwgyrCsGIkth52yIkl612n+0C9MjSnJbQAikISpb+WYRooBVhaDlUW7iZoKog==} + '@next/swc-win32-arm64-msvc@16.3.3': + resolution: {integrity: sha512-cTMUJpcEGmeywofCUfhR+rSsoE33+rVPnPEYNTNdLNlsOeEg/vktOsKUSTb28vUGqD2jkm4Zaskcwn7OCI6FQg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.3.1': - resolution: {integrity: sha512-d/k+PpAriUPaeMJJOG7HUSdqfEX46FEPWU1p3/nm2ACmXhj9hFEWdFODUBIpkuijXYkfL90qZzTqVPRp4BW/hw==} + '@next/swc-win32-x64-msvc@16.3.3': + resolution: {integrity: sha512-2VR4cTBzHXaBjnGsuH6GyJjENzQOmHeAh11uY1iUhjm3j5dEUrVJuUj+VL78jaGi/Dik8xS76zEj18BsFhlVZQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -1287,21 +1287,21 @@ packages: '@tailwindcss/postcss@4.3.3': resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} - '@tiptap/core@3.30.4': - resolution: {integrity: sha512-V9yKuUfV8qC9WBrnVxkFWmYLBomc3d1CwXoFSjED5DRu5q2oyxv07F+jOJSRogJAY+feHjuxvjhixwxeHm2DXQ==} + '@tiptap/core@3.31.3': + resolution: {integrity: sha512-Cz50pvciQrxdSxgTkHOVz0uD0Yl/8Xt0QatGD6ILm47jW8EzyHR9RkUGs/D5IqzXKuVPntfw1ttaT926vXfiRg==} peerDependencies: - '@tiptap/pm': 3.30.4 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-blockquote@3.30.4': - resolution: {integrity: sha512-n25/pFfDpZRJS4f6Ga/PkNrQFBEr3pRvPkDlY99kl8Kt8jFa1EUxbx+uUVIilqwiUjUnHtwCfqjSDFooQjezjg==} + '@tiptap/extension-blockquote@3.31.3': + resolution: {integrity: sha512-fyY2XMbyDDDfOTQ1Qdrnqa1qwC9DWE4n7AfE0EKQI0G8MfLV8RaDlLDcOZDJ9JbMPY7/Gx7EjyK4NKxSW9n2hQ==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-bold@3.30.4': - resolution: {integrity: sha512-eCOkf+/jdQte7lTZ4pQF10akrsFM4TzYc0ysSAkPa7QA+ex1aI8QT5UUx+mK8RwFo57lqE8PCX/Mx1gTqlCDnQ==} + '@tiptap/extension-bold@3.31.3': + resolution: {integrity: sha512-dIuYhKk8TitKU/FeDpoTeWZhU42YgDN5npgWNjAmMmRktPdoxnH3/wGSiwXlqZgJWjehN7kPWDePWpJeAImGpQ==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 '@tiptap/extension-bubble-menu@3.31.3': resolution: {integrity: sha512-EV6ZnwKc++2OM/OcD54n8s1B7C9LP7GKAtdEPwu0t3BYJf3sG8Ueoinf7SgGPO9oMPg96GneOkDNm1urMV167g==} @@ -1309,47 +1309,47 @@ packages: '@tiptap/core': 3.31.3 '@tiptap/pm': 3.31.3 - '@tiptap/extension-bullet-list@3.30.4': - resolution: {integrity: sha512-kJFOF3U4b1ad4T7Vm+CIIp+nxcr6wwWVeqpVe6Jhq9gudsWCKP0+KVAmOiJCePoDu9fpc/ZuGMXDefXYnyQDxg==} + '@tiptap/extension-bullet-list@3.31.3': + resolution: {integrity: sha512-qEyyoPapPef4LO8XKaN83bxtaNzkJ4kFn/IxLnEKd4BJ3Mvi4MH2yJYlyDqwFnMoev4pMA1zBHRAt/C0THRmZw==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-code-block-lowlight@3.30.4': - resolution: {integrity: sha512-oXZdrUWp530PT3q5E/ZewigjelHvExMDEyS+HusNF/rUXnmBugt4RszkA3lO38VYNoa/8FiOdRW+/yx1SYXlxw==} + '@tiptap/extension-code-block-lowlight@3.31.3': + resolution: {integrity: sha512-DN21CYEL4bm01vyB/wiyDPKrpiyalI5okTWx90jRuTqRzbnkPlnng1Vdo9L220w3GXct5Exe6iI01E7F19bC5A==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/extension-code-block': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/extension-code-block': 3.31.3 + '@tiptap/pm': 3.31.3 highlight.js: ^11 lowlight: ^2 || ^3 - '@tiptap/extension-code-block@3.30.4': - resolution: {integrity: sha512-eKLKxgLCvi+M5tiLkW+fIMzDtR7HvSKnigSE9RYHZmzSrv1ejVjgNj5FH8nGTim98hXiQGfWotss3zqG6bpdDw==} + '@tiptap/extension-code-block@3.31.3': + resolution: {integrity: sha512-nvknt4FhyJQjYcvxptmeUlFsIAc8ibua3E5BN4Pim374/9RWepH4cdE9X0/qUTtguHElLx0iKtSIY3rW2qGTFA==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-code@3.30.4': - resolution: {integrity: sha512-z9v9rBA/0MecUvf8QkcKKOGgceO9X3DT/JvFNka8Mdd68V5fhBs0jGsxYrj3qDWtdXyyUQIWs0t8HzL6LTdLiA==} + '@tiptap/extension-code@3.31.3': + resolution: {integrity: sha512-SzxOqchrD2AcN3uT67PjKmRFEMOU3vNNiwNaamZJUbZrI6Hmy+bvdHJrc3jrIddyyCrAtsnAfRI0cmorW1jGfg==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-details@3.30.4': - resolution: {integrity: sha512-a+UJjPxr77zVI1oCzDO/9lRkTdIg830oO+otMTOnM6xCmLIpxktDikCkYP1kJyU5GO6Fwp26J39MGKWUNIizXA==} + '@tiptap/extension-details@3.31.3': + resolution: {integrity: sha512-J5kdZy31wb97iKUR4sDsX0sEyRPlTijKKRAnVbInY2aNdFuNBTBdMPmblEJztxfMN+TmDrU2kCVv72J9B1SrJg==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/extension-text-style': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/extension-text-style': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-document@3.30.4': - resolution: {integrity: sha512-N+FbI+X1FVH8HxsM8C4fNkkzKXiyhXc9oh9oSqAIKOAAYGAjnHLMxW9TzYXbvm60SlAn6DIMypNf6nULGEc1oQ==} + '@tiptap/extension-document@3.31.3': + resolution: {integrity: sha512-EexgmqnyDNyGlISxo7SMrp5MygpJYmqD+0cY5jB6L1U6L4CpKKRWUt8OO1sWzEHDE1+TTvwt+WIFoIWAziOtEA==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-dropcursor@3.30.4': - resolution: {integrity: sha512-P1V0y/FKdyNVBImeW3WN+uGI77Uboc0dW44izAjrII0jcW2KUoBQeNrbbm9UZR1xuRvQJ1Z0OrFHmYrxP5ClNQ==} + '@tiptap/extension-dropcursor@3.31.3': + resolution: {integrity: sha512-NWomSfu5CSC7VacnMSDzKT8qm66SzMfZwVPEtwY5bPpRTJgTiT1rNK0neDrrzfMN27MfylGyKWWf7Q5Qf8w/fg==} peerDependencies: - '@tiptap/extensions': 3.30.4 + '@tiptap/extensions': 3.31.3 '@tiptap/extension-floating-menu@3.31.3': resolution: {integrity: sha512-rd4VJ9PGSP9Eop8ZTEwaLZcMzMXLuJKe3hUNf58rq+zANpwM+9fI+vB7g9MAc3eXwUNDxNDVACFIL2oeBqpQ3A==} @@ -1358,158 +1358,158 @@ packages: '@tiptap/core': 3.31.3 '@tiptap/pm': 3.31.3 - '@tiptap/extension-gapcursor@3.30.4': - resolution: {integrity: sha512-wsuXsB8Rp9BgfWlWYsRVzoHg9LwhoPAQGaw/gku1buDSTMcbLYQvok5MwJ/uJRECaJRLGgbUe5WBXoRvSY+o3g==} + '@tiptap/extension-gapcursor@3.31.3': + resolution: {integrity: sha512-EBXKb1FrVStsNYCcRGtd9jmzveCvR+eqgg1rVqoONrqFK6U7bga6LN+1dMKroP1kliDVgveYkP3vRYxqw+rFqg==} peerDependencies: - '@tiptap/extensions': 3.30.4 + '@tiptap/extensions': 3.31.3 - '@tiptap/extension-hard-break@3.30.4': - resolution: {integrity: sha512-eZ66SyfgmMK861S5SYtQROT/+ZfXtDHxllz7ao+X+dcl+DMdffmOzBeSfwrHQENmgl7umjbdAjqC7PT95jaU+w==} + '@tiptap/extension-hard-break@3.31.3': + resolution: {integrity: sha512-QAdCvNO4+yW9ATwsrej11NTkDYFqPLIEQr3ARNrKOK1qaiS7A0fia2SEukb/hrkP3A6mbozhoQt2r2RGUf/DpQ==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-heading@3.30.4': - resolution: {integrity: sha512-sVJxoRnbfK/QC7IoUw/Ezzx9b87+cqFz5d5WZvN8O8yobDWuh7IS8ZgqZiPypTW5RuhnZI+ahvmSyO3WLm8q5Q==} + '@tiptap/extension-heading@3.31.3': + resolution: {integrity: sha512-rk5VHMAeQcg06SLauN6EGdD2jc0O2qY8QkZYPd0LxNvLblw2BxBx+lxUQSYwLAT9Ie5914gKIK2YbRyO2Ts3ig==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-highlight@3.30.4': - resolution: {integrity: sha512-4EsZeEWB8NAZOLE1gSUFJQgF9sgaCRbGb47Posnjq4I2DMYuZGnyl2n0c0v/R06LV5ahz4IZvSZ4JskkSFsvIQ==} + '@tiptap/extension-highlight@3.31.3': + resolution: {integrity: sha512-97m1nDzTAjJaJZWe5hVOBMC2rjBZvEwTXA39zhjnaE/snb8Cy4H9A3+/sw9HQJBXMoG7tdOPG9kUlM3weYtLcQ==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-horizontal-rule@3.30.4': - resolution: {integrity: sha512-RmvjVVkUf5pF70XvwI7Sb4vIUSDbLTLEcFl1l5X9vPcDgDT5G0SiUL6l8F49+qYc6wrMvnLcenApnAiiQ0Vbpw==} + '@tiptap/extension-horizontal-rule@3.31.3': + resolution: {integrity: sha512-YnHGy2KShRwvCseAmmxl9VP7R0qaj8QMp3DA6DJWZqp7r5gLGvDkAqhedxqqefqsE4Y43hjkBdjtB9Ce78LkIw==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-image@3.30.4': - resolution: {integrity: sha512-BwO+SJ+1ZWFLDFbebT80q0PlsbrnmWRExzQqurubM93M22SlADnQxNzS7AKfNmv/e3qKAAXXsoBOkx66BuFjaQ==} + '@tiptap/extension-image@3.31.3': + resolution: {integrity: sha512-wWNG9BOtx2Cg4vwxPVGDIJ5DGX+ETkldeoaFJLB1NXUL4OPUiVTf8cHZ+hdYgJWP704BEB7jQgjlpvdi6VigTg==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-italic@3.30.4': - resolution: {integrity: sha512-6cEjcyjPRcLEMB75BwiUc6S7yzkqc7VPXCeRgY26UqMg4AvcLrseY70+pO4sLv3n2DS5w8DBbMXZJ4rb1BhpUw==} + '@tiptap/extension-italic@3.31.3': + resolution: {integrity: sha512-ibGvdvAPyfxBMUVNRI43eb9h2/Jka1MRG5GtnGqbcCX/2+Y/y0EOfFrPQPkuYphiWQYyu9+FzPKMB/pjuaLuKQ==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-link@3.30.4': - resolution: {integrity: sha512-HPHaey3+nQZl+lsr/RvjoXSgSC67SAkNEF4qNELzzDwMUfI0UrZ3H/HhBe6XBeRnGli9gfuSpeRkh63ke5JpOw==} + '@tiptap/extension-link@3.31.3': + resolution: {integrity: sha512-986wOQzTL9Zr5lf84LCLpm+YOms8A0K39/8DVoqRfebqcOe0/eq4bnztmAlfabOd+kJY92g3AgZERFUx/w+dcw==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-list-item@3.30.4': - resolution: {integrity: sha512-8E1ffdC7v3dwSrsqyxY3YP5uEQHTrwBDDmYF6o2YoHfzQ9nhXX5GmBz8fTxukjXUzSpuO76N/gwHIM8hBfdxMQ==} + '@tiptap/extension-list-item@3.31.3': + resolution: {integrity: sha512-4QlKOriJJMvg95QJTEsy9BUYPBQ6UvJyb8WURRwdUtQUkkqb8h32lg/eyQUv2FzW9IT1AdUyNZfVaxH64kRfQA==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-list-keymap@3.30.4': - resolution: {integrity: sha512-6RIzF3aThqIt4sia81K+6wA7H7bgPKjd3D66qLOGxdqdyfnAegk0OD5pUYhMZKhDCWGYKylyRVd2yIn/VNXqAg==} + '@tiptap/extension-list-keymap@3.31.3': + resolution: {integrity: sha512-If8UOEdDZbPJU6iYTvLtH6DOp2KBy6BKxg9UELL1AevVetGHEF/7lW8hP50Gn1tHMVpPRqmhSzVrJRpEJJgb/Q==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-list@3.30.4': - resolution: {integrity: sha512-Usqez9DBRoG78tdLwPDcd1j1mBBU7mr5D2yrRP2JL/eXXkhAfdWqEFRYXwct5T4/o9JkGcW3aQf+gUvp12v0pw==} + '@tiptap/extension-list@3.31.3': + resolution: {integrity: sha512-LoveGnC0FVdCV4jUNBaG1ZA+KWE07+adzV3kGy6uUYFcJEjbVUHTnPDrBOob3IwOSO3sCwIkvQb6EVYeXn/4yg==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-ordered-list@3.30.4': - resolution: {integrity: sha512-hInlH8I2UFGGULm9XLPtLWWFBECrYf/eNkloQb+udbF7ltLBL5JRCPcB3aM29qSSUQVxCCN8ICHdbwgpnTUAsw==} + '@tiptap/extension-ordered-list@3.31.3': + resolution: {integrity: sha512-mp3g11NgA/PYu8rj7J7Ez3l4qBy6WfTSmHIG4PZvEGG5w2oUAIkgb9DU7nPPzjmeme27oazFYZw+AtZA0+u4tw==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-paragraph@3.30.4': - resolution: {integrity: sha512-gM0WXvOP1tNcvpyRXTCtGhwVxye0VaFMCzDPjLrVAUtZMpo3cOrqDSrFl5tCurA59Qc2p5TUOR4g3/fKw8Yx9Q==} + '@tiptap/extension-paragraph@3.31.3': + resolution: {integrity: sha512-+iPku7wJfy5hbNDNLX8dveFtYVsZMmh7vztjuq8hT3mipSC4IByDehDbU8fzUCjfXiEzmI7mQn7c8LGmHULuzA==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-placeholder@3.30.4': - resolution: {integrity: sha512-Bbwzse6oTNwkQVmBQF45YJ/zpFQut52tT+s+u6cWi/SwyYTMeaU4XNOV6KidkM8urERFCkF/PplAevusvWuowA==} + '@tiptap/extension-placeholder@3.31.3': + resolution: {integrity: sha512-9jYtR8ELEw7GVaruyrm4oFkPcjig9Q+crc+dpmarhBNXUmxagCdlhVzNwCJ2WJRzvBAtx59sEYqNTU38Wx8S3A==} peerDependencies: - '@tiptap/extensions': 3.30.4 + '@tiptap/extensions': 3.31.3 - '@tiptap/extension-strike@3.30.4': - resolution: {integrity: sha512-iM3QhkEvNwDsxyNKTZM4wwqYhIKOjgXHTamPWnCICrPQ3aYFVdidfpDMePlHl6XL8aEAqPa1Xlj0aumFvSphOQ==} + '@tiptap/extension-strike@3.31.3': + resolution: {integrity: sha512-G29bhKttYwcKHT+BI6emWVFol3RO/gUXxQVcmr/iT8LXXy7j8J6HFUnsKM+Kg5YlP1rxMRgsa65dbrQVahZi0A==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-table-cell@3.30.4': - resolution: {integrity: sha512-/jlC9ucT7C0D0mzFRksfx4lx6lpWXc7OpAZv9Ml+Bitex6ghyW2ownxDzIfaAVBNv2KZY3uOpsQ2lOBItjehJg==} + '@tiptap/extension-table-cell@3.31.3': + resolution: {integrity: sha512-5nueKR/p/IX6B4etWqHjyRsjNfDf6dJZaRgfw1/1l90CJe2h3tTZk4JbUKWN3Mo4FzZuYKzmU3fxcZ8pSVOeJQ==} peerDependencies: - '@tiptap/extension-table': 3.30.4 + '@tiptap/extension-table': 3.31.3 - '@tiptap/extension-table-header@3.30.4': - resolution: {integrity: sha512-9Uk/R0tOUKVDKZUmAZncxT93SwzfsJvHFfutd8qZNB4+Mg74sSSN3vVjcfCPAUqqVrxV8hXdoN8+3MqP2INPFQ==} + '@tiptap/extension-table-header@3.31.3': + resolution: {integrity: sha512-sstVtNQiBYX4P16vlhwBYPsthxDnodHWQfGq0EUQM40Z7H796Lgh9t1qYtu8yARQuHKzvINRwJCSy6DZ8YTDtQ==} peerDependencies: - '@tiptap/extension-table': 3.30.4 + '@tiptap/extension-table': 3.31.3 - '@tiptap/extension-table-row@3.30.4': - resolution: {integrity: sha512-IiUvR73B7vU0WJW+zVAr7VRCtt9pHZW/v67QNAD0EZ52fJLA6UV/TzZbX58JqTRUtpdpGLkdiOLMVgZTP9rUrQ==} + '@tiptap/extension-table-row@3.31.3': + resolution: {integrity: sha512-up6tDK+hYVTFDeJ3XqKO0WJqBzyXNfGxMoimo5h83jrq9dcNh0oPCOzglZ7rdo8GH9I3VJ2fNKxxU2Eg2HcMoQ==} peerDependencies: - '@tiptap/extension-table': 3.30.4 + '@tiptap/extension-table': 3.31.3 - '@tiptap/extension-table@3.30.4': - resolution: {integrity: sha512-hH6E4y4QK8F2h4Eb/qiu8/tRXSQPbJn8pNOIQqcvA30luUnFWSpqHFDxO/a/XrzwF6F1l268WTekrn0PKogOzg==} + '@tiptap/extension-table@3.31.3': + resolution: {integrity: sha512-7cnVPHhdiGGeauYqca6JVyPLTqZbqFEEk9nn2e2E8+fBo6zVtV07AktJBqth/XEzjZxcUmGxjoeuWYAisWjUHg==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-task-item@3.30.4': - resolution: {integrity: sha512-PArRkxRkajtqkCV7wICVCkh6LBtQhvMqRgPmoEfdOIwGSnaWXCmAe8AmtLmCjhtHRxZ5aJlYH2C0/vm2ocoYxg==} + '@tiptap/extension-task-item@3.31.3': + resolution: {integrity: sha512-gCWvvXsCzi9tVFXPqKlkbU81XxtIdfjGy7FM9QFRKiWAvq5uv+Q5nvwrCyMVyP4bA7zRGWFaPzwjL68djgzoBw==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-task-list@3.30.4': - resolution: {integrity: sha512-X83/OuCBnY97rEusL+1figMUv+aaJiSJuSKdOjm3zJi3M1KI0GbyBVZ3/LL5Y2hynfeu1rOEVd/fkaP3Z/HUBw==} + '@tiptap/extension-task-list@3.31.3': + resolution: {integrity: sha512-3WgVzmfEnDbmxbjUBlvTiKpT53KSBnnYhXUVQxM0nz1vpoWG8QifhsnCVsNI6TZmhgR0x/jY+UW9Hc/WLF8DkQ==} peerDependencies: - '@tiptap/extension-list': 3.30.4 + '@tiptap/extension-list': 3.31.3 - '@tiptap/extension-text-style@3.30.4': - resolution: {integrity: sha512-BNd+qnXHVHBk7qAGyXpa2U4mvSNZKmc0vP0uH6V8+OQBw6Kl9WzTWv+V2qX+yjXFs/A2Bl/XVTdWaHctGxW/hg==} + '@tiptap/extension-text-style@3.31.3': + resolution: {integrity: sha512-wgjWWrjZwRZHiaDTQPX2am1y/4ePgRgGWF/2MOfSb7g4d5229p4aVtbT1JT7wu9z8OC482pEqcTlhdvgftvW7A==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-text@3.30.4': - resolution: {integrity: sha512-bzgVlPhkVan+m6jycXkyq08fKCNyQff/cl/5U+/wQf8s3GlX+Le2/pTxbbC3ClfO1D8VLzLwcd2HJTYIoBOdAA==} + '@tiptap/extension-text@3.31.3': + resolution: {integrity: sha512-gdsWtF+taeaCu6V+5Ct10fGo0ACUy1GnYtbb+mcathBt8OqbT+Ws60p/yEmKesBDz2Hn+B5IcWy6+2BBZl5ZTg==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extension-underline@3.30.4': - resolution: {integrity: sha512-h6nM3ykKswJLWvJVD1eiUFbanNmNj2SeV+2vuW666/xOy2WPyMnE2NZnsbvCKeK0wlUj7AE3l1m602mFwA4sDg==} + '@tiptap/extension-underline@3.31.3': + resolution: {integrity: sha512-HghdJaOwRqYzsAxqSyNyb+IWyOMcdCl8IoiBETA9BZCJAqdXzFLcuWp7CqCqJPam9dgkWosSoHqTCAO4nTBfpw==} peerDependencies: - '@tiptap/core': 3.30.4 + '@tiptap/core': 3.31.3 - '@tiptap/extensions@3.30.4': - resolution: {integrity: sha512-WeBl/ggeNCOoOySX7647lwtSUHWbCh8I1Qqp8NQBsGyHXEE6/7jHbKcxpw4fplOgScgVMfPz8WZ+3yrfXYCUFw==} + '@tiptap/extensions@3.31.3': + resolution: {integrity: sha512-8sJNPGGUe8f3aDojcOW5cfVL7I5NrBbE0UWxG08qoi9Tea6qWbvQJsCR9tsrOapr/DaLr3kpbGZ9s1gEEfcNcA==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 - '@tiptap/pm@3.30.4': - resolution: {integrity: sha512-oPbE+BOzzDKkxsvF9wepTWELvq385oifDkKIigqKCPKpGqplEIHIjNztCj/nOqHCfJBiU9LcoyyWH0qkHAQ9TQ==} + '@tiptap/pm@3.31.3': + resolution: {integrity: sha512-sZime0SWsz/k62W2WvHx5Ig7G2h7kVhrrmnqy+wEgIHfDwEfOlelRjaWCiBCFlF7dxGUntJusCh9FxlLhni0Ag==} - '@tiptap/react@3.30.4': - resolution: {integrity: sha512-NxGcKg4xBF6ngk6xORyzRCvG9zb7Z/cf59GpDBsiYpPpD/6m+J4kfNF0KVIOhRSAhNxm2u2ZPuGIWBtS/CDUBQ==} + '@tiptap/react@3.31.3': + resolution: {integrity: sha512-QiwQqvaLFLm5EMFu5tg7nAgXJxCUiUTLD8EsK+TqVV5P4bqOoMOCM39khbhXTJyahCuYpiFWx5YOSDtC/JiPtg==} peerDependencies: - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0 '@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0 react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tiptap/starter-kit@3.30.4': - resolution: {integrity: sha512-rZiv2QOqfQU4/MNsAmvbymIwx0tKrGrtdJg76aEaej+aGU1QNDhZbUNutV8AnZxFjSJMm8rt810qzAU98OmCAg==} + '@tiptap/starter-kit@3.31.3': + resolution: {integrity: sha512-WKof9RewdmGHvWJ1wn0/HVNG2mV+HOgVRyJkKekuM9fgr6BZAAH/xZsWE1eon+94JnQ+KtK2ThydXQM/qc6b2A==} - '@tiptap/suggestion@3.30.4': - resolution: {integrity: sha512-viJYyd8xyYFlJmvxPphj/gojMwDIT1g2HRWEzKstbcLb1ox8X+Ijy45PlqgCJFIIxO9RicfIxdaR/hMK2tqG2Q==} + '@tiptap/suggestion@3.31.3': + resolution: {integrity: sha512-z1OQ/Yx6seMZehi1AcmNkyJ8qkHQzybArmCyRdmreS4YL9C4bPMBe5lbMfFsArYs+KD5JyHwps5j7J/YE5BIuw==} peerDependencies: '@floating-ui/dom': ^1.0.0 - '@tiptap/core': 3.30.4 - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3 + '@tiptap/pm': 3.31.3 '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} @@ -2313,8 +2313,8 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - eslint-config-next@16.3.1: - resolution: {integrity: sha512-0vtrpwFVHFEkycUgV/DyrG29OS+HSRdah5Yu8YuZoiBMtlAT6NIiWzaLwDkJZxr2kGfx+9LIvfQ7KHAlEs0VsA==} + eslint-config-next@16.3.3: + resolution: {integrity: sha512-teqtsR26tnlfXFHfVLTM/4tzEzU8DMu6GS1sddZzhfGzgd2f2ofbgDUcsk6cssSCzX6Tk6fmWifJcdANSdPJrw==} peerDependencies: eslint: '>=9.0.0' typescript: '>=3.3.1' @@ -2634,14 +2634,14 @@ packages: hono-rate-limiter@0.5.3: resolution: {integrity: sha512-M0DxbVMpPELEzLi0AJg1XyBHLGJXz7GySjsPoK+gc5YeeBsdGDGe+2RvVuCAv8ydINiwlbxqYMNxUEyYfRji/A==} peerDependencies: - hono: ^4.12.34 + hono: ^4.13.5 unstorage: ^1.17.3 peerDependenciesMeta: unstorage: optional: true - hono@4.13.2: - resolution: {integrity: sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA==} + hono@4.13.7: + resolution: {integrity: sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==} engines: {node: '>=16.9.0'} html-url-attributes@3.0.1: @@ -2827,8 +2827,8 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-yaml@4.3.1: - resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true jsesc@3.1.0: @@ -3197,8 +3197,8 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - next@16.3.1: - resolution: {integrity: sha512-hsAp0i7Rh+/dhe7DGIeN2YlpLM1DP4MNxti9EtDMtqcO612X81MvvEj388/oTce9U1EcEIOWDlGq0zRwrBKvuA==} + next@16.3.3: + resolution: {integrity: sha512-tuRTx1nQ/yVw83cwJBo9F+njGUgMn3UHQycreWHB8XsStvvAh1AthbI8/4IpKnFaF58F+iSiHejYOlMQ/eq83g==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -3596,8 +3596,8 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - sharp@0.35.3: - resolution: {integrity: sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==} + sharp@0.35.4: + resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} engines: {node: '>=20.9.0'} peerDependencies: '@types/node': '*' @@ -4331,7 +4331,7 @@ snapshots: globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.3.1 + js-yaml: 4.3.2 minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -4357,9 +4357,9 @@ snapshots: '@floating-ui/utils@0.2.12': {} - '@hono/node-server@2.1.1(hono@4.13.2)': + '@hono/node-server@2.1.1(hono@4.13.7)': dependencies: - hono: 4.13.2 + hono: 4.13.7 '@humanfs/core@0.19.2': dependencies: @@ -4380,108 +4380,108 @@ snapshots: '@img/colour@1.1.0': optional: true - '@img/sharp-darwin-arm64@0.35.3': + '@img/sharp-darwin-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.3.2 + '@img/sharp-libvips-darwin-arm64': 1.3.3 optional: true - '@img/sharp-darwin-x64@0.35.3': + '@img/sharp-darwin-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.3.2 + '@img/sharp-libvips-darwin-x64': 1.3.3 optional: true - '@img/sharp-freebsd-wasm32@0.35.3': + '@img/sharp-freebsd-wasm32@0.35.4': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.3.2': + '@img/sharp-libvips-darwin-arm64@1.3.3': optional: true - '@img/sharp-libvips-darwin-x64@1.3.2': + '@img/sharp-libvips-darwin-x64@1.3.3': optional: true - '@img/sharp-libvips-linux-arm64@1.3.2': + '@img/sharp-libvips-linux-arm64@1.3.3': optional: true - '@img/sharp-libvips-linux-arm@1.3.2': + '@img/sharp-libvips-linux-arm@1.3.3': optional: true - '@img/sharp-libvips-linux-ppc64@1.3.2': + '@img/sharp-libvips-linux-ppc64@1.3.3': optional: true - '@img/sharp-libvips-linux-riscv64@1.3.2': + '@img/sharp-libvips-linux-riscv64@1.3.3': optional: true - '@img/sharp-libvips-linux-s390x@1.3.2': + '@img/sharp-libvips-linux-s390x@1.3.3': optional: true - '@img/sharp-libvips-linux-x64@1.3.2': + '@img/sharp-libvips-linux-x64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.3.2': + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.3.2': + '@img/sharp-libvips-linuxmusl-x64@1.3.3': optional: true - '@img/sharp-linux-arm64@0.35.3': + '@img/sharp-linux-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.3.2 + '@img/sharp-libvips-linux-arm64': 1.3.3 optional: true - '@img/sharp-linux-arm@0.35.3': + '@img/sharp-linux-arm@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.3.2 + '@img/sharp-libvips-linux-arm': 1.3.3 optional: true - '@img/sharp-linux-ppc64@0.35.3': + '@img/sharp-linux-ppc64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.3.2 + '@img/sharp-libvips-linux-ppc64': 1.3.3 optional: true - '@img/sharp-linux-riscv64@0.35.3': + '@img/sharp-linux-riscv64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.3.2 + '@img/sharp-libvips-linux-riscv64': 1.3.3 optional: true - '@img/sharp-linux-s390x@0.35.3': + '@img/sharp-linux-s390x@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.3.2 + '@img/sharp-libvips-linux-s390x': 1.3.3 optional: true - '@img/sharp-linux-x64@0.35.3': + '@img/sharp-linux-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.3.2 + '@img/sharp-libvips-linux-x64': 1.3.3 optional: true - '@img/sharp-linuxmusl-arm64@0.35.3': + '@img/sharp-linuxmusl-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 optional: true - '@img/sharp-linuxmusl-x64@0.35.3': + '@img/sharp-linuxmusl-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 optional: true - '@img/sharp-wasm32@0.35.3': + '@img/sharp-wasm32@0.35.4': dependencies: '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-webcontainers-wasm32@0.35.3': + '@img/sharp-webcontainers-wasm32@0.35.4': dependencies: - '@img/sharp-wasm32': 0.35.3 + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-win32-arm64@0.35.3': + '@img/sharp-win32-arm64@0.35.4': optional: true - '@img/sharp-win32-ia32@0.35.3': + '@img/sharp-win32-ia32@0.35.4': optional: true - '@img/sharp-win32-x64@0.35.3': + '@img/sharp-win32-x64@0.35.4': optional: true '@jridgewell/gen-mapping@0.3.13': @@ -4528,37 +4528,37 @@ snapshots: '@neondatabase/serverless@1.1.0': {} - '@next/env@16.3.1': {} + '@next/env@16.3.3': {} - '@next/eslint-plugin-next@16.3.1(eslint@9.39.5(jiti@2.7.0))': + '@next/eslint-plugin-next@16.3.3(eslint@9.39.5(jiti@2.7.0))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(jiti@2.7.0)) fast-glob: 3.3.1 transitivePeerDependencies: - eslint - '@next/swc-darwin-arm64@16.3.1': + '@next/swc-darwin-arm64@16.3.3': optional: true - '@next/swc-darwin-x64@16.3.1': + '@next/swc-darwin-x64@16.3.3': optional: true - '@next/swc-linux-arm64-gnu@16.3.1': + '@next/swc-linux-arm64-gnu@16.3.3': optional: true - '@next/swc-linux-arm64-musl@16.3.1': + '@next/swc-linux-arm64-musl@16.3.3': optional: true - '@next/swc-linux-x64-gnu@16.3.1': + '@next/swc-linux-x64-gnu@16.3.3': optional: true - '@next/swc-linux-x64-musl@16.3.1': + '@next/swc-linux-x64-musl@16.3.3': optional: true - '@next/swc-win32-arm64-msvc@16.3.1': + '@next/swc-win32-arm64-msvc@16.3.3': optional: true - '@next/swc-win32-x64-msvc@16.3.1': + '@next/swc-win32-x64-msvc@16.3.3': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4656,175 +4656,175 @@ snapshots: postcss: 8.5.26 tailwindcss: 4.3.3 - '@tiptap/core@3.30.4(@tiptap/pm@3.30.4)': + '@tiptap/core@3.31.3(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/pm': 3.30.4 + '@tiptap/pm': 3.31.3 - '@tiptap/extension-blockquote@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-blockquote@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-bold@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-bold@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-bubble-menu@3.31.3(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-bubble-menu@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: '@floating-ui/dom': 1.8.0 - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 optional: true - '@tiptap/extension-bullet-list@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-bullet-list@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-code-block-lowlight@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/extension-code-block@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)(highlight.js@11.11.1)(lowlight@3.3.0)': + '@tiptap/extension-code-block-lowlight@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/extension-code-block@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(highlight.js@11.11.1)(lowlight@3.3.0)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/extension-code-block': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/extension-code-block': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 highlight.js: 11.11.1 lowlight: 3.3.0 - '@tiptap/extension-code-block@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-code-block@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-code@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-code@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-details@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/extension-text-style@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)))(@tiptap/pm@3.30.4)': + '@tiptap/extension-details@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/extension-text-style@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/extension-text-style': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/extension-text-style': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-document@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-document@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-dropcursor@3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-dropcursor@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-floating-menu@3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-floating-menu@3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: '@floating-ui/dom': 1.8.0 - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 optional: true - '@tiptap/extension-gapcursor@3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-gapcursor@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-hard-break@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-hard-break@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-heading@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-heading@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-highlight@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-highlight@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-horizontal-rule@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-horizontal-rule@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-image@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-image@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-italic@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-italic@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-link@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-link@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 linkifyjs: 4.3.3 - '@tiptap/extension-list-item@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-list-item@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-list-keymap@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-list-keymap@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-ordered-list@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-ordered-list@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-paragraph@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-paragraph@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-placeholder@3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-placeholder@3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extensions': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-strike@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-strike@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-table-cell@3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-table-cell@3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-table': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-table': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-table-header@3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-table-header@3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-table': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-table': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-table-row@3.30.4(@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-table-row@3.31.3(@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-table': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-table': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-table@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extension-table@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/extension-task-item@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-task-item@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-task-list@3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4))': + '@tiptap/extension-task-list@3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) - '@tiptap/extension-text-style@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-text-style@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-text@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-text@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extension-underline@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))': + '@tiptap/extension-underline@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) - '@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 - '@tiptap/pm@3.30.4': + '@tiptap/pm@3.31.3': dependencies: prosemirror-changeset: 2.4.2 prosemirror-commands: 1.7.2 @@ -4840,10 +4840,10 @@ snapshots: prosemirror-transform: 1.12.1 prosemirror-view: 1.42.3 - '@tiptap/react@3.30.4(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + '@tiptap/react@3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 '@types/react': 19.2.18 '@types/react-dom': 19.2.4(@types/react@19.2.18) '@types/use-sync-external-store': 0.0.6 @@ -4852,43 +4852,43 @@ snapshots: react-dom: 19.2.8(react@19.2.8) use-sync-external-store: 1.6.0(react@19.2.8) optionalDependencies: - '@tiptap/extension-bubble-menu': 3.31.3(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-floating-menu': 3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) + '@tiptap/extension-bubble-menu': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-floating-menu': 3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) transitivePeerDependencies: - '@floating-ui/dom' - '@tiptap/starter-kit@3.30.4': - dependencies: - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/extension-blockquote': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-bold': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-bullet-list': 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-code': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-code-block': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-document': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-dropcursor': 3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-gapcursor': 3.30.4(@tiptap/extensions@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-hard-break': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-heading': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-horizontal-rule': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-italic': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-link': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-list': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/extension-list-item': 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-list-keymap': 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-ordered-list': 3.30.4(@tiptap/extension-list@3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)) - '@tiptap/extension-paragraph': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-strike': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-text': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extension-underline': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4)) - '@tiptap/extensions': 3.30.4(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 - - '@tiptap/suggestion@3.30.4(@floating-ui/dom@1.8.0)(@tiptap/core@3.30.4(@tiptap/pm@3.30.4))(@tiptap/pm@3.30.4)': + '@tiptap/starter-kit@3.31.3': + dependencies: + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/extension-blockquote': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-bold': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-bullet-list': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-code': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-code-block': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-document': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-dropcursor': 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-gapcursor': 3.31.3(@tiptap/extensions@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-hard-break': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-heading': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-horizontal-rule': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-italic': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-link': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-list': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/extension-list-item': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-list-keymap': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-ordered-list': 3.31.3(@tiptap/extension-list@3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)) + '@tiptap/extension-paragraph': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-strike': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-text': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extension-underline': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3)) + '@tiptap/extensions': 3.31.3(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 + + '@tiptap/suggestion@3.31.3(@floating-ui/dom@1.8.0)(@tiptap/core@3.31.3(@tiptap/pm@3.31.3))(@tiptap/pm@3.31.3)': dependencies: '@floating-ui/dom': 1.8.0 - '@tiptap/core': 3.30.4(@tiptap/pm@3.30.4) - '@tiptap/pm': 3.30.4 + '@tiptap/core': 3.31.3(@tiptap/pm@3.31.3) + '@tiptap/pm': 3.31.3 '@tybys/wasm-util@0.10.3': dependencies: @@ -5745,9 +5745,9 @@ snapshots: escape-string-regexp@5.0.0: {} - eslint-config-next@16.3.1(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3): + eslint-config-next@16.3.3(@typescript-eslint/parser@8.67.0(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3))(eslint@9.39.5(jiti@2.7.0))(typescript@6.0.3): dependencies: - '@next/eslint-plugin-next': 16.3.1(eslint@9.39.5(jiti@2.7.0)) + '@next/eslint-plugin-next': 16.3.3(eslint@9.39.5(jiti@2.7.0)) eslint: 9.39.5(jiti@2.7.0) eslint-import-resolver-node: 0.3.10 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.5(jiti@2.7.0)) @@ -6155,11 +6155,11 @@ snapshots: highlight.js@11.11.1: {} - hono-rate-limiter@0.5.3(hono@4.13.2): + hono-rate-limiter@0.5.3(hono@4.13.7): dependencies: - hono: 4.13.2 + hono: 4.13.7 - hono@4.13.2: {} + hono@4.13.7: {} html-url-attributes@3.0.1: {} @@ -6343,7 +6343,7 @@ snapshots: js-tokens@4.0.0: {} - js-yaml@4.3.1: + js-yaml@4.3.2: dependencies: argparse: 2.0.1 @@ -6890,9 +6890,9 @@ snapshots: negotiator@0.6.3: {} - next@16.3.1(@babel/core@7.29.7)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): + next@16.3.3(@babel/core@7.29.7)(@types/node@26.2.0)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): dependencies: - '@next/env': 16.3.1 + '@next/env': 16.3.3 '@swc/helpers': 0.5.23 baseline-browser-mapping: 2.11.14 caniuse-lite: 1.0.30001809 @@ -6901,15 +6901,15 @@ snapshots: react-dom: 19.2.8(react@19.2.8) styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.8) optionalDependencies: - '@next/swc-darwin-arm64': 16.3.1 - '@next/swc-darwin-x64': 16.3.1 - '@next/swc-linux-arm64-gnu': 16.3.1 - '@next/swc-linux-arm64-musl': 16.3.1 - '@next/swc-linux-x64-gnu': 16.3.1 - '@next/swc-linux-x64-musl': 16.3.1 - '@next/swc-win32-arm64-msvc': 16.3.1 - '@next/swc-win32-x64-msvc': 16.3.1 - sharp: 0.35.3(@types/node@26.2.0) + '@next/swc-darwin-arm64': 16.3.3 + '@next/swc-darwin-x64': 16.3.3 + '@next/swc-linux-arm64-gnu': 16.3.3 + '@next/swc-linux-arm64-musl': 16.3.3 + '@next/swc-linux-x64-gnu': 16.3.3 + '@next/swc-linux-x64-musl': 16.3.3 + '@next/swc-win32-arm64-msvc': 16.3.3 + '@next/swc-win32-x64-msvc': 16.3.3 + sharp: 0.35.4(@types/node@26.2.0) transitivePeerDependencies: - '@babel/core' - '@types/node' @@ -7393,37 +7393,37 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.2 - sharp@0.35.3(@types/node@26.2.0): + sharp@0.35.4(@types/node@26.2.0): dependencies: '@img/colour': 1.1.0 detect-libc: 2.1.2 semver: 7.8.5 optionalDependencies: - '@img/sharp-darwin-arm64': 0.35.3 - '@img/sharp-darwin-x64': 0.35.3 - '@img/sharp-freebsd-wasm32': 0.35.3 - '@img/sharp-libvips-darwin-arm64': 1.3.2 - '@img/sharp-libvips-darwin-x64': 1.3.2 - '@img/sharp-libvips-linux-arm': 1.3.2 - '@img/sharp-libvips-linux-arm64': 1.3.2 - '@img/sharp-libvips-linux-ppc64': 1.3.2 - '@img/sharp-libvips-linux-riscv64': 1.3.2 - '@img/sharp-libvips-linux-s390x': 1.3.2 - '@img/sharp-libvips-linux-x64': 1.3.2 - '@img/sharp-libvips-linuxmusl-arm64': 1.3.2 - '@img/sharp-libvips-linuxmusl-x64': 1.3.2 - '@img/sharp-linux-arm': 0.35.3 - '@img/sharp-linux-arm64': 0.35.3 - '@img/sharp-linux-ppc64': 0.35.3 - '@img/sharp-linux-riscv64': 0.35.3 - '@img/sharp-linux-s390x': 0.35.3 - '@img/sharp-linux-x64': 0.35.3 - '@img/sharp-linuxmusl-arm64': 0.35.3 - '@img/sharp-linuxmusl-x64': 0.35.3 - '@img/sharp-webcontainers-wasm32': 0.35.3 - '@img/sharp-win32-arm64': 0.35.3 - '@img/sharp-win32-ia32': 0.35.3 - '@img/sharp-win32-x64': 0.35.3 + '@img/sharp-darwin-arm64': 0.35.4 + '@img/sharp-darwin-x64': 0.35.4 + '@img/sharp-freebsd-wasm32': 0.35.4 + '@img/sharp-libvips-darwin-arm64': 1.3.3 + '@img/sharp-libvips-darwin-x64': 1.3.3 + '@img/sharp-libvips-linux-arm': 1.3.3 + '@img/sharp-libvips-linux-arm64': 1.3.3 + '@img/sharp-libvips-linux-ppc64': 1.3.3 + '@img/sharp-libvips-linux-riscv64': 1.3.3 + '@img/sharp-libvips-linux-s390x': 1.3.3 + '@img/sharp-libvips-linux-x64': 1.3.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + '@img/sharp-linux-arm': 0.35.4 + '@img/sharp-linux-arm64': 0.35.4 + '@img/sharp-linux-ppc64': 0.35.4 + '@img/sharp-linux-riscv64': 0.35.4 + '@img/sharp-linux-s390x': 0.35.4 + '@img/sharp-linux-x64': 0.35.4 + '@img/sharp-linuxmusl-arm64': 0.35.4 + '@img/sharp-linuxmusl-x64': 0.35.4 + '@img/sharp-webcontainers-wasm32': 0.35.4 + '@img/sharp-win32-arm64': 0.35.4 + '@img/sharp-win32-ia32': 0.35.4 + '@img/sharp-win32-x64': 0.35.4 '@types/node': 26.2.0 optional: true diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 40d386b9..5afcb2c0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -10,13 +10,13 @@ overrides: engine.io: ^6.6.7 esbuild: ^0.28.1 fast-uri: ^3.1.5 - hono: ^4.12.34 + hono: ^4.13.5 ip-address: ^10.3.1 - js-yaml: ^4.3.1 + js-yaml: ^4.3.2 nanoid: ^3.3.17 postcss: ^8.5.23 qs: ^6.15.2 - sharp: ^0.35.3 + sharp: ^0.35.4 socket.io-parser: ^4.2.7 ws: ^8.21.0 allowBuilds: From a7394441e9a11b6e4b8f64f66e759a504f419c27 Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:30:04 +0530 Subject: [PATCH 10/11] Record actual public demo routing for closeout --- docs/superpowers/plans/2026-09-09-settings-maturity-program.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md index 617dde59..1849e75f 100644 --- a/docs/superpowers/plans/2026-09-09-settings-maturity-program.md +++ b/docs/superpowers/plans/2026-09-09-settings-maturity-program.md @@ -234,7 +234,8 @@ Hono, Sharp and js-yaml overrides. The regenerated lockfile passes the full low-threshold pnpm audit with no known vulnerabilities. Full candidate CI remains the merge gate; no bypass of image scanning or database-backed browser smoke. -Demo currently runs preview.14 (6d39e0e). Deploy the merged revision through a +The public demo routes to the RC1 UI candidate in b3appsprivate20260906; the older +preview.14 container remains separate. Deploy the merged revision through a separate source checkout, preserve site configuration and existing feature flags, record the old image, take a stopped database/uploads/configuration backup, and rehearse the versioned upgrade against a restored database before live cutover. From 340c71576cce3a2f0807f60b1ebeb31603d93b48 Mon Sep 17 00:00:00 2001 From: Maneek21 <208369276+Maneek21@users.noreply.github.com> Date: Wed, 9 Sep 2026 15:42:20 +0530 Subject: [PATCH 11/11] Check visible revoked connection summary in browser smoke --- scripts/product-browser-smoke.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/product-browser-smoke.mjs b/scripts/product-browser-smoke.mjs index 6cdcccf4..a61af459 100644 --- a/scripts/product-browser-smoke.mjs +++ b/scripts/product-browser-smoke.mjs @@ -170,7 +170,7 @@ async function main() { await page.getByRole('button', { name: 'Confirm revoke', exact: true }).click(); await page.getByRole('heading', { name: 'No matching connections', exact: true }).waitFor(); await page.getByRole('button', { name: /^Connection history/ }).click(); - await page.getByText(personalConnectionName, { exact: false }).last().waitFor(); + await page.locator('summary').filter({ hasText: personalConnectionName }).waitFor(); record('Create, acknowledge, inspect and revoke a personal connection without exposing its token'); await page.setViewportSize({ width: 1440, height: 900 });