mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-28 20:22:45 +00:00
The subagent track rows were as dense on a phone as in the desktop popover, and the archive and detach actions were hand-rolled pressables that only recoloured the glyph, so a tap or hover never showed the rounded highlight every other icon action has. Rows now take the compact menu-row height and padding below the `md` breakpoint, decided once in the track row style; the desktop popover keeps its density. The actions are `ToolbarButton`, which owns the hitbox, the rounded highlight on hover and press, the compact size, and the tooltip. A repo oxlint rule, `paseo/no-raw-pressable`, reports `Pressable` and `Touchable*` imports outside `components/ui/` so the next tap target reaches for a primitive. Existing importers are on a burn-down list they can only leave. The rule is its own name rather than another `no-restricted-imports` entry so its override cannot interact with the existing burn-downs. Its test runs the real oxlint binary and is wired into the CI quality job.
479 lines
21 KiB
JSON
479 lines
21 KiB
JSON
{
|
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
|
"options": {
|
|
"typeAware": false
|
|
},
|
|
"ignorePatterns": [".dev/**"],
|
|
"plugins": ["react", "react-perf", "unicorn", "typescript", "oxc", "import", "promise"],
|
|
"jsPlugins": ["./scripts/oxlint/paseo-plugin.mjs"],
|
|
"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": [
|
|
"plugins/*-provider/server/**/*.ts",
|
|
"packages/plugin/src/server/acp-internal/**/*.ts"
|
|
],
|
|
"rules": {
|
|
"no-restricted-imports": [
|
|
"error",
|
|
{
|
|
"paths": [
|
|
{
|
|
"name": "node:child_process",
|
|
"importNames": [
|
|
"spawn",
|
|
"exec",
|
|
"execFile",
|
|
"spawnSync",
|
|
"execSync",
|
|
"execFileSync"
|
|
],
|
|
"message": "Use the plugin server process helpers so Windows command scripts and argv are handled consistently."
|
|
},
|
|
{
|
|
"name": "child_process",
|
|
"importNames": [
|
|
"spawn",
|
|
"exec",
|
|
"execFile",
|
|
"spawnSync",
|
|
"execSync",
|
|
"execFileSync"
|
|
],
|
|
"message": "Use the plugin server process helpers so Windows command scripts and argv are handled consistently."
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"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/compact-explorer-sidebar.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/headers/back-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": ["packages/app/src/**/*.{ts,tsx}"],
|
|
"rules": {
|
|
"paseo/no-raw-pressable": "error"
|
|
}
|
|
},
|
|
// Press feedback is owned by the primitives in components/ui. Raw pressable burn-down:
|
|
// 94 files. They may only leave this list.
|
|
{
|
|
"files": [
|
|
"packages/app/src/components/ui/**/*.{ts,tsx}",
|
|
"packages/app/src/**/*.{test,spec}.{ts,tsx}",
|
|
"packages/app/src/agent-profiles/settings/agent-profile-appearance-field.tsx",
|
|
"packages/app/src/agent-skills/selection-sheet.tsx",
|
|
"packages/app/src/agent-stream/chat-outline/rail.web.tsx",
|
|
"packages/app/src/agent-stream/view.tsx",
|
|
"packages/app/src/app/pair-scan.tsx",
|
|
"packages/app/src/changelog/internal/changelog-sheet.tsx",
|
|
"packages/app/src/command-center/command-center.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/add-project-flow.tsx",
|
|
"packages/app/src/components/add-remote-ssh-host-modal.tsx",
|
|
"packages/app/src/components/agent-list.tsx",
|
|
"packages/app/src/components/app-diagnostic-sheet.tsx",
|
|
"packages/app/src/components/attachment-lightbox.tsx",
|
|
"packages/app/src/components/attachment-pill.tsx",
|
|
"packages/app/src/components/combined-model-selector.tsx",
|
|
"packages/app/src/components/compact-explorer-sidebar.tsx",
|
|
"packages/app/src/components/context-window-meter.tsx",
|
|
"packages/app/src/components/desktop/window-controls.tsx",
|
|
"packages/app/src/components/dictation-controls.tsx",
|
|
"packages/app/src/components/download-toast.tsx",
|
|
"packages/app/src/components/file-explorer-pane.tsx",
|
|
"packages/app/src/components/headers/back-header.tsx",
|
|
"packages/app/src/components/highlighted-code-block.tsx",
|
|
"packages/app/src/components/hosts/host-filter.tsx",
|
|
"packages/app/src/components/hosts/host-picker.tsx",
|
|
"packages/app/src/components/import-session-sheet.tsx",
|
|
"packages/app/src/components/left-sidebar.tsx",
|
|
"packages/app/src/components/markdown/fence/mermaid/host.native.tsx",
|
|
"packages/app/src/components/markdown/fence/mermaid/host.web.tsx",
|
|
"packages/app/src/components/message.tsx",
|
|
"packages/app/src/components/model-browser.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/realtime-voice-overlay.tsx",
|
|
"packages/app/src/components/schedules/schedule-row.tsx",
|
|
"packages/app/src/components/settings/collapsible-row.tsx",
|
|
"packages/app/src/components/settings/headings/settings-info-tip.tsx",
|
|
"packages/app/src/components/sidebar-callout.tsx",
|
|
"packages/app/src/components/sidebar-resize-handle.tsx",
|
|
"packages/app/src/components/sidebar-workspace-list.tsx",
|
|
"packages/app/src/components/sidebar/sidebar-group-toggle-row.tsx",
|
|
"packages/app/src/components/sidebar/sidebar-header-row.tsx",
|
|
"packages/app/src/components/sidebar/sidebar-section-header.tsx",
|
|
"packages/app/src/components/sidebar/sidebar-status-list.tsx",
|
|
"packages/app/src/components/sidebar/workspace-meta-row/index.tsx",
|
|
"packages/app/src/components/terminal-copy-paste-actions.tsx",
|
|
"packages/app/src/components/terminal-emulator-native-grid.native.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/welcome-screen.tsx",
|
|
"packages/app/src/components/workspace-hover-card.tsx",
|
|
"packages/app/src/components/zoomable-viewport/toolbar.tsx",
|
|
"packages/app/src/composer/agent-controls/index.tsx",
|
|
"packages/app/src/composer/diff-stat-pill.tsx",
|
|
"packages/app/src/composer/dock/internal/background.native.tsx",
|
|
"packages/app/src/composer/draft/import-pill.tsx",
|
|
"packages/app/src/composer/index.tsx",
|
|
"packages/app/src/composer/tracks.tsx",
|
|
"packages/app/src/desktop/browser/pane/index.electron.tsx",
|
|
"packages/app/src/git/actions-split-button.tsx",
|
|
"packages/app/src/git/commits-section/commit-row.tsx",
|
|
"packages/app/src/git/commits-section/commits-section.tsx",
|
|
"packages/app/src/git/diff-pane.tsx",
|
|
"packages/app/src/git/forges/gitlab.view.tsx",
|
|
"packages/app/src/git/pull-request-panel/checks-section.tsx",
|
|
"packages/app/src/git/pull-request-panel/pane.tsx",
|
|
"packages/app/src/git/pull-request-panel/section-kit.tsx",
|
|
"packages/app/src/hosts/host-chooser.tsx",
|
|
"packages/app/src/mobile-panels/presentation.tsx",
|
|
"packages/app/src/panels/new-tab-panel.tsx",
|
|
"packages/app/src/panels/setup-panel.tsx",
|
|
"packages/app/src/plugins/buttons/view.tsx",
|
|
"packages/app/src/review/surface.tsx",
|
|
"packages/app/src/screens/open-project-screen.tsx",
|
|
"packages/app/src/screens/project-settings-screen.tsx",
|
|
"packages/app/src/screens/projects-screen.tsx",
|
|
"packages/app/src/screens/settings-screen.tsx",
|
|
"packages/app/src/screens/settings/host-appearance-section.tsx",
|
|
"packages/app/src/screens/settings/host-page.tsx",
|
|
"packages/app/src/screens/settings/providers-section.tsx",
|
|
"packages/app/src/screens/workspace/compact-workspace-header/tab-switcher.tsx",
|
|
"packages/app/src/screens/workspace/scripts/workspace-scripts-button.tsx",
|
|
"packages/app/src/screens/workspace/workspace-desktop-tabs-row.tsx",
|
|
"packages/app/src/screens/workspace/workspace-tab-presentation.tsx",
|
|
"packages/app/src/tool-calls/detail-level/overview/sheet.tsx",
|
|
"packages/app/src/usage/sidebar-item.tsx",
|
|
"packages/app/src/usage/window-bar.tsx",
|
|
"packages/app/src/workspace-labels/manager-modal.tsx",
|
|
"packages/app/src/workspace-labels/swatch.tsx",
|
|
"packages/app/src/workspace/open-in-editor/button.tsx"
|
|
],
|
|
"rules": {
|
|
"paseo/no-raw-pressable": "off"
|
|
}
|
|
},
|
|
{
|
|
"files": ["**/e2e/**/fixtures.ts"],
|
|
"rules": {
|
|
"no-empty-pattern": "off"
|
|
}
|
|
}
|
|
]
|
|
}
|