Skip to content

Commit 5ead140

Browse files
authored
Merge pull request #12763 from gitbutlerapp/lite-prep
Various tooling changes for Lite
2 parents 61e85a6 + a4d62b9 commit 5ead140

File tree

22 files changed

+1047
-114
lines changed

22 files changed

+1047
-114
lines changed

.vscode/extensions.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"dbaeumer.vscode-eslint",
44
"svelte.svelte-vscode",
55
"rust-lang.rust-analyzer",
6-
"esbenp.prettier-vscode"
6+
"esbenp.prettier-vscode",
7+
"oxc.oxc-vscode"
78
]
89
}

.vscode/settings.json

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
{
22
"eslint.useFlatConfig": true,
3-
"eslint.validate": ["typescript", "javascript", "svelte"],
3+
"eslint.validate": ["typescript", "typescriptreact", "javascript", "svelte"],
44
"eslint.workingDirectories": [{ "directory": "./", "changeProcessCWD": true }],
55
"svelte.enable-ts-plugin": true,
66
"prettier.configPath": ".prettierrc.mjs",
77
"prettier.useEditorConfig": false,
88
"editor.defaultFormatter": null,
9+
"oxc.typeAware": true,
10+
"oxc.unusedDisableDirectives": "warn",
11+
"files.associations": {
12+
"*.cts": "typescript"
13+
},
914
"rust-analyzer.check.command": "clippy",
1015
"rust-analyzer.check.allTargets": true,
1116
"rust-analyzer.check.features": "all",
@@ -19,6 +24,9 @@
1924
"[typescript]": {
2025
"editor.defaultFormatter": "esbenp.prettier-vscode"
2126
},
27+
"[typescriptreact]": {
28+
"editor.defaultFormatter": "esbenp.prettier-vscode"
29+
},
2230
"[javascript]": {
2331
"editor.defaultFormatter": "esbenp.prettier-vscode"
2432
},
@@ -38,6 +46,5 @@
3846
"editor.defaultFormatter": "esbenp.prettier-vscode"
3947
},
4048
"svelte.plugin.css.globals": "packages/ui/src/**/*.css",
41-
"typescript.preferences.importModuleSpecifier": "non-relative",
42-
"javascript.preferences.importModuleSpecifier": "non-relative"
49+
"js/ts.preferences.importModuleSpecifier": "non-relative"
4350
}

apps/lite/.oxlintrc.json

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"jsPlugins": [
4+
// The builtin plugin isn't 1:1 at time of writing.
5+
{ "name": "react-hooks-js", "specifier": "eslint-plugin-react-hooks" },
6+
{ "name": "react-query-js", "specifier": "@tanstack/eslint-plugin-query" }
7+
],
8+
"plugins": ["eslint", "jsx-a11y", "oxc", "react", "typescript", "unicorn"],
9+
"rules": {
10+
"arrow-body-style": ["error", "as-needed"],
11+
"default-param-last": "error",
12+
"no-cond-assign": ["warn", "always"],
13+
"curly": ["warn", "multi"],
14+
"no-console": "warn",
15+
"no-fallthrough": "error",
16+
"no-param-reassign": "error",
17+
"prefer-template": "warn",
18+
"oxc/no-barrel-file": ["warn", { "threshold": 0 }],
19+
"unicorn/no-document-cookie": "warn",
20+
"unicorn/prefer-number-properties": "error",
21+
"react/button-has-type": "error",
22+
"react/jsx-boolean-value": "warn",
23+
"react/jsx-fragments": "warn",
24+
"react/jsx-no-useless-fragment": "warn",
25+
"react/no-array-index-key": "warn",
26+
"react/no-danger": "error",
27+
// Temporarily disabled during the POC phase
28+
// "react/only-export-components": "error",
29+
"react/self-closing-comp": "warn",
30+
"typescript/array-type": ["warn", { "default": "generic" }],
31+
"typescript/ban-ts-comment": "warn",
32+
"typescript/parameter-properties": "error",
33+
"typescript/no-explicit-any": "error",
34+
"typescript/no-inferrable-types": "warn",
35+
"typescript/no-non-null-assertion": "warn",
36+
"typescript/no-unnecessary-condition": "warn",
37+
"typescript/no-unnecessary-template-expression": "warn",
38+
"typescript/restrict-template-expressions": [
39+
"warn",
40+
{
41+
"allowAny": false,
42+
"allowNullish": false,
43+
"allowRegExp": false
44+
}
45+
],
46+
"typescript/restrict-plus-operands": [
47+
"error",
48+
{
49+
"allowAny": false,
50+
"allowBoolean": false,
51+
"allowNullish": false,
52+
"allowNumberAndString": false,
53+
"allowRegExp": false
54+
}
55+
],
56+
// "always" flags for lack of await outside of async functions, unlike ESLint:
57+
// https://github.com/oxc-project/oxc/issues/18452
58+
"typescript/return-await": ["error", "error-handling-correctness-only"],
59+
"typescript/strict-boolean-expressions": [
60+
"warn",
61+
{
62+
"allowString": false,
63+
"allowNumber": false,
64+
"allowNullableBoolean": true
65+
}
66+
],
67+
"typescript/await-thenable": "error",
68+
"typescript/no-misused-promises": "error",
69+
"typescript/no-floating-promises": "error",
70+
"typescript/no-misused-spread": "error",
71+
"typescript/no-unsafe-argument": "error",
72+
"typescript/no-unsafe-assignment": "error",
73+
"typescript/no-unsafe-call": "error",
74+
"typescript/no-unsafe-member-access": "error",
75+
"typescript/no-unsafe-return": "error",
76+
"typescript/unbound-method": "error",
77+
78+
// Default config has catch violations.
79+
"no-unused-vars": [
80+
"warn",
81+
{
82+
"caughtErrorsIgnorePattern": "^_",
83+
// These are the defaults that are unset by diverging our config at all.
84+
"argsIgnorePattern": "^_",
85+
"varsIgnorePattern": "^_"
86+
}
87+
],
88+
89+
// Lots of false positives on sums.
90+
"react/jsx-key": "off",
91+
92+
// Enable the recommended rules in the JS plugin as per:
93+
// https://react.dev/reference/eslint-plugin-react-hooks#recommended
94+
"react-hooks-js/exhaustive-deps": "error",
95+
"react-hooks-js/rules-of-hooks": "error",
96+
"react-hooks-js/component-hook-factories": "error",
97+
"react-hooks-js/config": "error",
98+
"react-hooks-js/error-boundaries": "error",
99+
"react-hooks-js/gating": "error",
100+
"react-hooks-js/globals": "error",
101+
"react-hooks-js/immutability": "error",
102+
"react-hooks-js/incompatible-library": "error",
103+
"react-hooks-js/preserve-manual-memoization": "error",
104+
"react-hooks-js/purity": "error",
105+
"react-hooks-js/refs": "error",
106+
"react-hooks-js/set-state-in-effect": "error",
107+
"react-hooks-js/set-state-in-render": "error",
108+
"react-hooks-js/static-components": "error",
109+
"react-hooks-js/unsupported-syntax": "error",
110+
"react-hooks-js/use-memo": "error",
111+
112+
// Enable the recommended rules in the JS plugin.
113+
"react-query-js/exhaustive-deps": "error",
114+
"react-query-js/no-rest-destructuring": "warn",
115+
"react-query-js/stable-query-client": "error",
116+
"react-query-js/no-unstable-deps": "error",
117+
"react-query-js/infinite-query-property-order": "error"
118+
}
119+
}

apps/lite/AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## Typechecking
2+
3+
Typechecking is the fastest way to validate that everything is okay. Always run this **exact** command to typecheck:
4+
5+
```console
6+
$ pnpm -F @gitbutler/lite check
7+
```

apps/lite/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Electron + React (Vite) + TanStack Router scaffold.
7676

7777
## ESLint
7878

79-
No app-local ESLint config is added. This app uses the monorepo root flat config in `eslint.config.js`.
79+
No app-local ESLint config is added. The monorepo root flat config in `eslint.config.js` ignores `apps/lite/**`, and Lite is linted via `oxlint` instead.
8080

8181
## IPC contract
8282

@@ -88,7 +88,7 @@ No app-local ESLint config is added. This app uses the monorepo root flat config
8888

8989
`apps/lite` consumes Rust bindings via `@gitbutler/but-sdk` using a strict process boundary:
9090

91-
1. **Electron main process** calls native bindings (for example `listProjectsNapi`) in `electron/src/model/projects.ts`.
91+
1. **Electron main process** defines IPC handlers in `electron/src/main.ts` that call native bindings (for example `listProjectsStatelessNapi`).
9292
2. **IPC layer** defines request/response contracts in `electron/src/ipc.ts` and carries SDK-generated types such as `ProjectForFrontend`.
9393
3. **Preload** forwards approved methods through `contextBridge` in `electron/src/preload.cts`.
9494
4. **Renderer** calls `window.lite.*` and never imports or calls native bindings directly.

apps/lite/electron/src/ipc.ts

Lines changed: 157 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,165 @@
1-
import type { ProjectForFrontend, RefInfo } from "@gitbutler/but-sdk";
1+
import type {
2+
ApplyOutcome,
3+
AssignmentRejection,
4+
BranchDetails,
5+
BranchListing,
6+
BranchListingFilter,
7+
HunkAssignmentRequest,
8+
CommitDetails,
9+
DiffSpec,
10+
InsertSide,
11+
ProjectForFrontend,
12+
RelativeTo,
13+
RefInfo,
14+
TreeChange,
15+
TreeChanges,
16+
UICommitCreateResult,
17+
UICommitInsertBlankResult,
18+
UICommitMoveResult,
19+
UICommitRewordResult,
20+
UIMoveChangesResult,
21+
UnifiedPatch,
22+
WorktreeChanges,
23+
} from "@gitbutler/but-sdk";
24+
25+
export interface AssignHunkParams {
26+
projectId: string;
27+
assignments: Array<HunkAssignmentRequest>;
28+
}
29+
30+
export interface ApplyParams {
31+
projectId: string;
32+
existingBranch: string;
33+
}
34+
35+
export interface BranchDetailsParams {
36+
projectId: string;
37+
branchName: string;
38+
remote: string | null;
39+
}
40+
41+
export interface BranchDiffParams {
42+
projectId: string;
43+
branch: string;
44+
}
45+
46+
export interface CommitAmendParams {
47+
projectId: string;
48+
commitId: string;
49+
changes: Array<DiffSpec>;
50+
}
51+
52+
export interface CommitDetailsWithLineStatsParams {
53+
projectId: string;
54+
commitId: string;
55+
}
56+
57+
export interface CommitCreateParams {
58+
projectId: string;
59+
relativeTo: RelativeTo;
60+
side: InsertSide;
61+
changes: Array<DiffSpec>;
62+
message: string;
63+
}
64+
65+
export interface CommitMoveChangesBetweenParams {
66+
projectId: string;
67+
sourceCommitId: string;
68+
destinationCommitId: string;
69+
changes: Array<DiffSpec>;
70+
}
71+
72+
export interface CommitMoveParams {
73+
projectId: string;
74+
subjectCommitId: string;
75+
anchorCommitId: string;
76+
side: InsertSide;
77+
}
78+
79+
export interface CommitMoveToBranchParams {
80+
projectId: string;
81+
subjectCommitId: string;
82+
anchorRef: string;
83+
}
84+
85+
export interface CommitInsertBlankParams {
86+
projectId: string;
87+
relativeTo: RelativeTo;
88+
side: InsertSide;
89+
}
90+
91+
export interface CommitRewordParams {
92+
projectId: string;
93+
commitId: string;
94+
message: string;
95+
}
96+
97+
export interface CommitUncommitChangesParams {
98+
projectId: string;
99+
commitId: string;
100+
changes: Array<DiffSpec>;
101+
assignTo: string | null;
102+
}
103+
104+
export interface TreeChangeDiffParams {
105+
projectId: string;
106+
change: TreeChange;
107+
}
108+
109+
export interface UnapplyStackParams {
110+
projectId: string;
111+
stackId: string;
112+
}
2113

3114
export interface LiteElectronApi {
4-
ping(input: string): Promise<string>;
5-
getVersion(): Promise<string>;
6-
listProjects(): Promise<ProjectForFrontend[]>;
7-
headInfo(projectId: string): Promise<RefInfo>;
115+
apply: (params: ApplyParams) => Promise<ApplyOutcome>;
116+
assignHunk: (params: AssignHunkParams) => Promise<Array<AssignmentRejection>>;
117+
branchDetails: (params: BranchDetailsParams) => Promise<BranchDetails>;
118+
branch_diff: (params: BranchDiffParams) => Promise<TreeChanges>;
119+
changesInWorktree: (projectId: string) => Promise<WorktreeChanges>;
120+
commitAmend: (params: CommitAmendParams) => Promise<UICommitCreateResult>;
121+
commitCreate: (params: CommitCreateParams) => Promise<UICommitCreateResult>;
122+
commitDetailsWithLineStats: (params: CommitDetailsWithLineStatsParams) => Promise<CommitDetails>;
123+
commitInsertBlank: (params: CommitInsertBlankParams) => Promise<UICommitInsertBlankResult>;
124+
commitMove: (params: CommitMoveParams) => Promise<UICommitMoveResult>;
125+
commitMoveToBranch: (params: CommitMoveToBranchParams) => Promise<UICommitMoveResult>;
126+
commitReword: (params: CommitRewordParams) => Promise<UICommitRewordResult>;
127+
commitMoveChangesBetween: (
128+
params: CommitMoveChangesBetweenParams,
129+
) => Promise<UIMoveChangesResult>;
130+
commitUncommitChanges: (params: CommitUncommitChangesParams) => Promise<UIMoveChangesResult>;
131+
getVersion: () => Promise<string>;
132+
headInfo: (projectId: string) => Promise<RefInfo>;
133+
listBranches: (
134+
projectId: string,
135+
filter: BranchListingFilter | null,
136+
) => Promise<Array<BranchListing>>;
137+
listProjects: () => Promise<Array<ProjectForFrontend>>;
138+
ping: (input: string) => Promise<string>;
139+
treeChangeDiffs: (params: TreeChangeDiffParams) => Promise<UnifiedPatch | null>;
140+
unapplyStack: (params: UnapplyStackParams) => Promise<void>;
8141
}
9142

10143
export const liteIpcChannels = {
11-
ping: "lite:ping",
144+
apply: "workspace:apply",
145+
assignHunk: "workspace:assign-hunk",
146+
branchDetails: "workspace:branch-details",
147+
branchDiff: "workspace:branch-diff",
148+
changesInWorktree: "workspace:changes-in-worktree",
149+
commitAmend: "workspace:commit-amend",
150+
commitCreate: "workspace:commit-create",
151+
commitDetailsWithLineStats: "workspace:commit-details-with-line-stats",
152+
commitInsertBlank: "workspace:commit-insert-blank",
153+
commitMove: "workspace:commit-move",
154+
commitMoveToBranch: "workspace:commit-move-to-branch",
155+
commitReword: "workspace:commit-reword",
156+
commitMoveChangesBetween: "workspace:commit-move-changes-between",
157+
commitUncommitChanges: "workspace:commit-uncommit-changes",
12158
getVersion: "lite:get-version",
13-
listProjects: "projects:list",
14159
headInfo: "workspace:head-info",
160+
listBranches: "workspace:list-branches",
161+
listProjects: "projects:list",
162+
ping: "lite:ping",
163+
treeChangeDiffs: "workspace:tree-change-diffs",
164+
unapplyStack: "workspace:unapply-stack",
15165
} as const;

0 commit comments

Comments
 (0)