Skip to content

Commit 5a57ada

Browse files
committed
feat(git): support custom commit flags for app-run commits
1 parent 89ffcf4 commit 5a57ada

10 files changed

Lines changed: 75 additions & 5 deletions

File tree

apps/server/src/git/Layers/GitCore.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ const makeIsolatedGitCore = (gitService: GitServiceShape) =>
9898
status: (input) => core.status(input),
9999
statusDetails: (cwd) => core.statusDetails(cwd),
100100
prepareCommitContext: (cwd, filePaths?) => core.prepareCommitContext(cwd, filePaths),
101-
commit: (cwd, subject, body) => core.commit(cwd, subject, body),
101+
commit: (cwd, subject, body, extraArgs?) => core.commit(cwd, subject, body, extraArgs),
102102
pushCurrentBranch: (cwd, fallbackBranch) => core.pushCurrentBranch(cwd, fallbackBranch),
103103
pullCurrentBranch: (cwd) => core.pullCurrentBranch(cwd),
104104
readRangeContext: (cwd, baseBranch) => core.readRangeContext(cwd, baseBranch),

apps/server/src/git/Layers/GitCore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -804,9 +804,9 @@ const makeGitCore = Effect.gen(function* () {
804804
};
805805
});
806806

807-
const commit: GitCoreShape["commit"] = (cwd, subject, body) =>
807+
const commit: GitCoreShape["commit"] = (cwd, subject, body, extraArgs = []) =>
808808
Effect.gen(function* () {
809-
const args = ["commit", "-m", subject];
809+
const args = ["commit", ...extraArgs, "-m", subject];
810810
const trimmedBody = body.trim();
811811
if (trimmedBody.length > 0) {
812812
args.push("-m", trimmedBody);

apps/server/src/git/Layers/GitManager.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ interface CommitAndBranchSuggestion {
207207
commitMessage: string;
208208
}
209209

210+
function tokenizeCommitFlags(rawFlags?: string): string[] {
211+
return (rawFlags ?? "")
212+
.trim()
213+
.split(/\s+/g)
214+
.filter((value) => value.length > 0);
215+
}
216+
210217
function formatCommitMessage(subject: string, body: string): string {
211218
const trimmedBody = body.trim();
212219
if (trimmedBody.length === 0) {
@@ -680,6 +687,7 @@ export const makeGitManager = Effect.gen(function* () {
680687
cwd: string,
681688
branch: string | null,
682689
commitMessage?: string,
690+
commitFlags?: string,
683691
preResolvedSuggestion?: CommitAndBranchSuggestion,
684692
filePaths?: readonly string[],
685693
) =>
@@ -696,7 +704,12 @@ export const makeGitManager = Effect.gen(function* () {
696704
return { status: "skipped_no_changes" as const };
697705
}
698706

699-
const { commitSha } = yield* gitCore.commit(cwd, suggestion.subject, suggestion.body);
707+
const { commitSha } = yield* gitCore.commit(
708+
cwd,
709+
suggestion.subject,
710+
suggestion.body,
711+
tokenizeCommitFlags(commitFlags),
712+
);
700713
return {
701714
status: "created" as const,
702715
commitSha,
@@ -1042,6 +1055,7 @@ export const makeGitManager = Effect.gen(function* () {
10421055
input.cwd,
10431056
currentBranch,
10441057
commitMessageForStep,
1058+
input.commitFlags,
10451059
preResolvedCommitSuggestion,
10461060
input.filePaths,
10471061
);

apps/server/src/git/Services/GitCore.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export interface GitCoreShape {
111111
cwd: string,
112112
subject: string,
113113
body: string,
114+
extraArgs?: readonly string[],
114115
) => Effect.Effect<{ commitSha: string }, GitCommandError>;
115116

116117
/**

apps/web/public/mockServiceWorker.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* - Please do NOT modify this file.
88
*/
99

10-
const PACKAGE_VERSION = '2.12.9'
10+
const PACKAGE_VERSION = '2.12.10'
1111
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
1212
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
1313
const activeClientIds = new Set()

apps/web/src/appSettings.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ const AppSettingsSchema = Schema.Struct({
2121
codexHomePath: Schema.String.check(Schema.isMaxLength(4096)).pipe(
2222
Schema.withConstructorDefault(() => Option.some("")),
2323
),
24+
gitCommitFlags: Schema.String.check(Schema.isMaxLength(4096)).pipe(
25+
Schema.withConstructorDefault(() => Option.some("")),
26+
),
2427
defaultThreadEnvMode: Schema.Literals(["local", "worktree"]).pipe(
2528
Schema.withConstructorDefault(() => Option.some("local")),
2629
),

apps/web/src/components/GitActionsControl.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { Popover, PopoverPopup, PopoverTrigger } from "~/components/ui/popover";
3232
import { ScrollArea } from "~/components/ui/scroll-area";
3333
import { Textarea } from "~/components/ui/textarea";
3434
import { toastManager } from "~/components/ui/toast";
35+
import { useAppSettings } from "~/appSettings";
3536
import { openInPreferredEditor } from "~/editorPreferences";
3637
import {
3738
gitBranchesQueryOptions,
@@ -158,6 +159,7 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
158159
() => (activeThreadId ? { threadId: activeThreadId } : undefined),
159160
[activeThreadId],
160161
);
162+
const { settings } = useAppSettings();
161163
const queryClient = useQueryClient();
162164
const [isCommitDialogOpen, setIsCommitDialogOpen] = useState(false);
163165
const [dialogCommitMessage, setDialogCommitMessage] = useState("");
@@ -199,6 +201,7 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
199201
useIsMutating({ mutationKey: gitMutationKeys.runStackedAction(gitCwd) }) > 0;
200202
const isPullRunning = useIsMutating({ mutationKey: gitMutationKeys.pull(gitCwd) }) > 0;
201203
const isGitActionRunning = isRunStackedActionRunning || isPullRunning;
204+
const configuredCommitFlags = settings.gitCommitFlags.trim();
202205
const isDefaultBranch = useMemo(() => {
203206
const branchName = gitStatusForActions?.branch;
204207
if (!branchName) return false;
@@ -349,6 +352,7 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
349352
const promise = runImmediateGitActionMutation.mutateAsync({
350353
action,
351354
...(commitMessage ? { commitMessage } : {}),
355+
...(configuredCommitFlags ? { commitFlags: configuredCommitFlags } : {}),
352356
...(featureBranch ? { featureBranch } : {}),
353357
...(filePaths ? { filePaths } : {}),
354358
});
@@ -442,6 +446,7 @@ export default function GitActionsControl({ gitCwd, activeThreadId }: GitActions
442446
},
443447

444448
[
449+
configuredCommitFlags,
445450
isDefaultBranch,
446451
runImmediateGitActionMutation,
447452
setPendingDefaultBranchAction,

apps/web/src/lib/gitReactQuery.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,13 @@ export function gitRunStackedActionMutationOptions(input: {
118118
mutationFn: async ({
119119
action,
120120
commitMessage,
121+
commitFlags,
121122
featureBranch,
122123
filePaths,
123124
}: {
124125
action: GitStackedAction;
125126
commitMessage?: string;
127+
commitFlags?: string;
126128
featureBranch?: boolean;
127129
filePaths?: string[];
128130
}) => {
@@ -132,6 +134,7 @@ export function gitRunStackedActionMutationOptions(input: {
132134
cwd: input.cwd,
133135
action,
134136
...(commitMessage ? { commitMessage } : {}),
137+
...(commitFlags ? { commitFlags } : {}),
135138
...(featureBranch ? { featureBranch } : {}),
136139
...(filePaths ? { filePaths } : {}),
137140
});

apps/web/src/routes/_chat.settings.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ function SettingsRouteView() {
109109

110110
const codexBinaryPath = settings.codexBinaryPath;
111111
const codexHomePath = settings.codexHomePath;
112+
const gitCommitFlags = settings.gitCommitFlags;
112113
const keybindingsConfigPath = serverConfigQuery.data?.keybindingsConfigPath ?? null;
113114
const availableEditors = serverConfigQuery.data?.availableEditors;
114115

@@ -545,6 +546,48 @@ function SettingsRouteView() {
545546
) : null}
546547
</section>
547548

549+
<section className="rounded-2xl border border-border bg-card p-5">
550+
<div className="mb-4">
551+
<h2 className="text-sm font-medium text-foreground">Git</h2>
552+
<p className="mt-1 text-xs text-muted-foreground">
553+
Configure extra flags for app-run <code>git commit</code> commands.
554+
</p>
555+
</div>
556+
557+
<div className="space-y-4">
558+
<label htmlFor="git-commit-flags" className="block space-y-1">
559+
<span className="text-xs font-medium text-foreground">
560+
Extra git commit flags
561+
</span>
562+
<Input
563+
id="git-commit-flags"
564+
value={gitCommitFlags}
565+
onChange={(event) => updateSettings({ gitCommitFlags: event.target.value })}
566+
placeholder="--no-gpg-sign"
567+
spellCheck={false}
568+
/>
569+
<span className="text-xs text-muted-foreground">
570+
Applied to app-run git commit commands only. Example: <code>--no-gpg-sign</code>
571+
. Quoted arguments are not supported yet.
572+
</span>
573+
</label>
574+
575+
<div className="flex justify-end">
576+
<Button
577+
size="xs"
578+
variant="outline"
579+
onClick={() =>
580+
updateSettings({
581+
gitCommitFlags: defaults.gitCommitFlags,
582+
})
583+
}
584+
>
585+
Restore default
586+
</Button>
587+
</div>
588+
</div>
589+
</section>
590+
548591
<section className="rounded-2xl border border-border bg-card p-5">
549592
<div className="mb-4">
550593
<h2 className="text-sm font-medium text-foreground">Responses</h2>

packages/contracts/src/git.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const GitRunStackedActionInput = Schema.Struct({
6060
cwd: TrimmedNonEmptyStringSchema,
6161
action: GitStackedAction,
6262
commitMessage: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(10_000))),
63+
commitFlags: Schema.optional(TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(4_096))),
6364
featureBranch: Schema.optional(Schema.Boolean),
6465
filePaths: Schema.optional(
6566
Schema.Array(TrimmedNonEmptyStringSchema).check(Schema.isMinLength(1)),

0 commit comments

Comments
 (0)