mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-14 13:22:37 +00:00
* fix(app): preserve IME composition in form inputs Form model publication was replaying changing default text into the native or DOM editing surface. Keep the editing surface authoritative, defer web publication until composition commits, and reserve resetKey changes for explicit text replacement. * refactor(app): centralize text editing authority Route every app text field, including the composer and plugin runtime, through one platform-owned editing primitive. Its type and runtime reject controlled value replay, its command handle owns programmatic replacement, and lint prevents raw React Native TextInput imports outside the boundary. * fix(app): restore composer placeholder styling
329 lines
13 KiB
JSON
329 lines
13 KiB
JSON
{
|
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
"options": {
|
|
"typeAware": false
|
|
},
|
|
"ignorePatterns": [".dev/**"],
|
|
"plugins": ["react", "react-perf", "unicorn", "typescript", "oxc", "import", "promise"],
|
|
"categories": {
|
|
"correctness": "error",
|
|
"suspicious": "error",
|
|
"perf": "error"
|
|
},
|
|
"rules": {
|
|
"react/react-in-jsx-scope": "off",
|
|
|
|
"no-await-in-loop": "off",
|
|
|
|
"no-unused-expressions": "error",
|
|
"no-useless-catch": "error",
|
|
"preserve-caught-error": "error",
|
|
"require-await": "off",
|
|
"no-async-promise-executor": "error",
|
|
"no-useless-escape": "error",
|
|
"no-empty-pattern": "error",
|
|
"no-self-assign": "error",
|
|
"no-shadow": "error",
|
|
"unicorn/consistent-function-scoping": "off",
|
|
"unicorn/no-array-sort": "off",
|
|
|
|
"unicorn/no-useless-spread": "error",
|
|
"unicorn/no-useless-fallback-in-spread": "error",
|
|
"unicorn/no-new-array": "error",
|
|
"unicorn/no-empty-file": "error",
|
|
|
|
"promise/always-return": "error",
|
|
"promise/no-multiple-resolved": "error",
|
|
|
|
"react/no-array-index-key": "error",
|
|
"react/jsx-no-useless-fragment": "error",
|
|
"react/jsx-no-constructed-context-values": "error",
|
|
"react/no-unescaped-entities": "error",
|
|
"react/button-has-type": "error",
|
|
"react/jsx-max-depth": ["error", { "max": 6 }],
|
|
|
|
"react-hooks/rules-of-hooks": "error",
|
|
"react-hooks/exhaustive-deps": "error",
|
|
|
|
"react-perf/jsx-no-new-array-as-prop": "error",
|
|
"react-perf/jsx-no-new-function-as-prop": "error",
|
|
"react-perf/jsx-no-new-object-as-prop": "error",
|
|
"react-perf/jsx-no-jsx-as-prop": "error",
|
|
|
|
"oxc/no-map-spread": "error",
|
|
"oxc/no-async-endpoint-handlers": "error",
|
|
"oxc/only-used-in-recursion": "error",
|
|
|
|
"typescript/no-explicit-any": "error",
|
|
"typescript/prefer-as-const": "error",
|
|
"typescript/no-this-alias": "error",
|
|
"typescript/no-unnecessary-type-assertion": "error",
|
|
"typescript/consistent-type-definitions": ["error", "interface"],
|
|
|
|
"import/no-unassigned-import": [
|
|
"error",
|
|
{
|
|
"allow": [
|
|
"**/*.css",
|
|
"**/expo-router/entry",
|
|
"**/event-target-polyfill",
|
|
"**/dotenv/config",
|
|
"**/react-native",
|
|
"**/@/styles/unistyles",
|
|
"**/src/styles/unistyles",
|
|
"**/@/test/window-local-storage"
|
|
]
|
|
}
|
|
],
|
|
|
|
"no-nested-ternary": "error",
|
|
"no-unneeded-ternary": "error",
|
|
|
|
"complexity": ["error", { "max": 20 }],
|
|
"max-depth": ["error", { "max": 4 }],
|
|
"max-nested-callbacks": ["error", { "max": 3 }]
|
|
},
|
|
"overrides": [
|
|
{
|
|
"files": ["packages/app/src/**/*.{ts,tsx}"],
|
|
"rules": {
|
|
// React Native style arrays must read Unistyles proxies during render. Hoisting them to
|
|
// satisfy this allocation rule captures the temporary startup theme instead.
|
|
"react-perf/jsx-no-new-array-as-prop": "off",
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "react-native",
|
|
"importNames": ["TextInput"],
|
|
"message": "Use EditingTextInput from @/components/ui/text-input. Raw TextInput bypasses editing-surface authority and IME safety."
|
|
},
|
|
{
|
|
"name": "@tanstack/react-query",
|
|
"importNames": ["useQuery", "useInfiniteQuery", "useQueries"],
|
|
"message": "App reads must go through useReplicaQuery/useFetchQuery from @/data/query. Grandfathered files may only leave the override burn-down list."
|
|
},
|
|
{
|
|
"name": "react-native-unistyles",
|
|
"importNames": ["useUnistyles"],
|
|
"message": "useUnistyles is banned by docs/unistyles.md. Grandfathered files may only leave the override burn-down list."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"files": [
|
|
"packages/app/src/data/**/*.{ts,tsx}",
|
|
"packages/app/src/**/*.test.{ts,tsx}",
|
|
"packages/app/src/**/*.spec.{ts,tsx}"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "react-native",
|
|
"importNames": ["TextInput"],
|
|
"message": "Use EditingTextInput from @/components/ui/text-input. Raw TextInput bypasses editing-surface authority and IME safety."
|
|
},
|
|
{
|
|
"name": "react-native-unistyles",
|
|
"importNames": ["useUnistyles"],
|
|
"message": "useUnistyles is banned by docs/unistyles.md. Grandfathered files may only leave the override burn-down list."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
// Raw query burn-down: 34 files total; the 28 files below still enforce the useUnistyles ban.
|
|
{
|
|
"files": [
|
|
"packages/app/src/assistant-file-links/use-file-link.ts",
|
|
"packages/app/src/components/message.tsx",
|
|
"packages/app/src/components/worktree-setup-callout-source.tsx",
|
|
"packages/app/src/desktop/hooks/use-daemon-status.ts",
|
|
"packages/app/src/desktop/hooks/use-install-status.ts",
|
|
"packages/app/src/desktop/settings/desktop-settings.ts",
|
|
"packages/app/src/git/pull-request-panel/use-data.ts",
|
|
"packages/app/src/git/use-github-search-query.ts",
|
|
"packages/app/src/git/use-pr-status-query.ts",
|
|
"packages/app/src/git/use-status-query.ts",
|
|
"packages/app/src/hooks/use-archive-agent.ts",
|
|
"packages/app/src/hooks/use-agent-autocomplete.ts",
|
|
"packages/app/src/hooks/use-agent-commands-query.ts",
|
|
"packages/app/src/hooks/use-agent-history.ts",
|
|
"packages/app/src/hooks/use-branch-switcher.ts",
|
|
"packages/app/src/hooks/use-changes-preferences/index.ts",
|
|
"packages/app/src/hooks/use-draft-agent-features.ts",
|
|
"packages/app/src/hooks/use-form-preferences.ts",
|
|
"packages/app/src/hooks/use-is-local-daemon.ts",
|
|
"packages/app/src/hooks/use-keyboard-shortcut-overrides.ts",
|
|
"packages/app/src/hooks/use-preferred-editor.ts",
|
|
"packages/app/src/hooks/use-settings/index.ts",
|
|
"packages/app/src/panels/terminal-panel.tsx",
|
|
"packages/app/src/projects/icons.ts",
|
|
"packages/app/src/provider-usage/use-provider-usage.ts",
|
|
"packages/app/src/screens/project-settings-screen.tsx",
|
|
"packages/app/src/screens/workspace/use-workspace-checkout-status.ts",
|
|
"packages/app/src/workspace/desktop-open-targets.ts"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "react-native",
|
|
"importNames": ["TextInput"],
|
|
"message": "Use EditingTextInput from @/components/ui/text-input. Raw TextInput bypasses editing-surface authority and IME safety."
|
|
},
|
|
{
|
|
"name": "react-native-unistyles",
|
|
"importNames": ["useUnistyles"],
|
|
"message": "useUnistyles is banned by docs/unistyles.md. Grandfathered files may only leave the override burn-down list."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
// useUnistyles burn-down: 74 files total; the 68 files below still enforce the raw-query ban.
|
|
{
|
|
"files": [
|
|
"packages/app/src/app/_layout.tsx",
|
|
"packages/app/src/app/pair-scan.tsx",
|
|
"packages/app/src/components/adaptive-modal-sheet.tsx",
|
|
"packages/app/src/components/add-host-method-modal.tsx",
|
|
"packages/app/src/components/add-host-modal.tsx",
|
|
"packages/app/src/components/agent-list.tsx",
|
|
"packages/app/src/components/agent-status-dot.tsx",
|
|
"packages/app/src/components/attachment-lightbox.tsx",
|
|
"packages/app/src/desktop/browser/pane/index.electron.tsx",
|
|
"packages/app/src/desktop/browser/pane/index.tsx",
|
|
"packages/app/src/desktop/browser/pane/index.web.tsx",
|
|
"packages/app/src/components/command-center.tsx",
|
|
"packages/app/src/components/context-window-meter.tsx",
|
|
"packages/app/src/components/dictation-controls.tsx",
|
|
"packages/app/src/components/download-toast.tsx",
|
|
"packages/app/src/components/draggable-list.native.tsx",
|
|
"packages/app/src/components/explorer-sidebar.tsx",
|
|
"packages/app/src/components/headers/back-header.tsx",
|
|
"packages/app/src/components/headers/menu-header.tsx",
|
|
"packages/app/src/components/headers/screen-header.tsx",
|
|
"packages/app/src/components/host-status-dot.tsx",
|
|
"packages/app/src/components/hosts/host-picker.tsx",
|
|
"packages/app/src/components/icons/paseo-logo.tsx",
|
|
"packages/app/src/components/left-sidebar.tsx",
|
|
"packages/app/src/components/pair-link-modal.tsx",
|
|
"packages/app/src/components/plan-card.tsx",
|
|
"packages/app/src/components/provider-diagnostic-sheet.tsx",
|
|
"packages/app/src/components/question-form-card.tsx",
|
|
"packages/app/src/components/quitting-overlay.tsx",
|
|
"packages/app/src/components/realtime-voice-overlay.tsx",
|
|
"packages/app/src/components/resize-handle.tsx",
|
|
"packages/app/src/components/rewind/rewind-menu.tsx",
|
|
"packages/app/src/components/settings-textarea.tsx",
|
|
"packages/app/src/components/sidebar-callout.tsx",
|
|
"packages/app/src/components/split-container.tsx",
|
|
"packages/app/src/components/split-drop-zone.tsx",
|
|
"packages/app/src/components/terminal-pane.tsx",
|
|
"packages/app/src/components/toast-host.tsx",
|
|
"packages/app/src/components/tool-call-sheet.tsx",
|
|
"packages/app/src/components/ui/alert.tsx",
|
|
"packages/app/src/components/ui/autocomplete.tsx",
|
|
"packages/app/src/components/ui/combobox.tsx",
|
|
"packages/app/src/components/ui/context-menu.tsx",
|
|
"packages/app/src/components/ui/dropdown-menu.tsx",
|
|
"packages/app/src/components/ui/external-link.tsx",
|
|
"packages/app/src/components/volume-meter.tsx",
|
|
"packages/app/src/components/web-desktop-scrollbar.tsx",
|
|
"packages/app/src/components/welcome-screen.tsx",
|
|
"packages/app/src/composer/agent-controls/index.tsx",
|
|
"packages/app/src/composer/agent-controls/mode-control.tsx",
|
|
"packages/app/src/constants/layout.ts",
|
|
"packages/app/src/desktop/components/desktop-permission-row.tsx",
|
|
"packages/app/src/desktop/components/desktop-permissions-section.tsx",
|
|
"packages/app/src/desktop/components/desktop-updates-section.tsx",
|
|
"packages/app/src/desktop/components/integrations-section.tsx",
|
|
"packages/app/src/desktop/updates/update-callout-source.tsx",
|
|
"packages/app/src/git/actions-split-button.tsx",
|
|
"packages/app/src/hooks/use-web-scrollbar-style.web.ts",
|
|
"packages/app/src/hosts/host-chooser.tsx",
|
|
"packages/app/src/screens/open-project-screen.tsx",
|
|
"packages/app/src/screens/projects-screen.tsx",
|
|
"packages/app/src/screens/sessions-screen.tsx",
|
|
"packages/app/src/screens/settings-screen.tsx",
|
|
"packages/app/src/screens/settings/host-page.tsx",
|
|
"packages/app/src/screens/settings/providers-section.tsx",
|
|
"packages/app/src/screens/settings/settings-group.tsx",
|
|
"packages/app/src/screens/startup-splash-screen.tsx",
|
|
"packages/app/src/screens/workspace/workspace-route-state-views.tsx"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "react-native",
|
|
"importNames": ["TextInput"],
|
|
"message": "Use EditingTextInput from @/components/ui/text-input. Raw TextInput bypasses editing-surface authority and IME safety."
|
|
},
|
|
{
|
|
"name": "@tanstack/react-query",
|
|
"importNames": ["useQuery", "useInfiniteQuery", "useQueries"],
|
|
"message": "App reads must go through useReplicaQuery/useFetchQuery from @/data/query. Grandfathered files may only leave the override burn-down list."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
// Both burn-downs: 6 overlapping files. They may only shrink out of this exemption.
|
|
{
|
|
"files": [
|
|
"packages/app/src/components/file-explorer-pane.tsx",
|
|
"packages/app/src/components/file-pane.tsx",
|
|
"packages/app/src/components/import-session-sheet.tsx",
|
|
"packages/app/src/components/project-picker-modal.tsx",
|
|
"packages/app/src/desktop/components/pair-device-section.tsx",
|
|
"packages/app/src/screens/new-workspace-screen.tsx"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "react-native",
|
|
"importNames": ["TextInput"],
|
|
"message": "Use EditingTextInput from @/components/ui/text-input. Raw TextInput bypasses editing-surface authority and IME safety."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"files": [
|
|
"packages/app/src/components/ui/text-input/**/*.{ts,tsx}",
|
|
"packages/app/src/agent-stream/scroll-keyboard-dismiss/use-scroll-keyboard-dismiss.ts"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": "off"
|
|
}
|
|
},
|
|
{
|
|
"files": ["**/e2e/**/fixtures.ts"],
|
|
"rules": {
|
|
"no-empty-pattern": "off"
|
|
}
|
|
}
|
|
]
|
|
}
|