Skip to content

Commit 38287ca

Browse files
authored
feat: add accept option (#59)
1 parent 17dcba8 commit 38287ca

File tree

8 files changed

+301
-165
lines changed

8 files changed

+301
-165
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* Concurrent edits. By default `git-draft` does not touch the working directory.
1010
* Customizable prompt templates.
1111
* Extensible bot API.
12+
* Local data collection for privacy-friendly analytics.
1213

1314

1415
## Installation
@@ -23,8 +24,14 @@ pipx install git-draft[openai]
2324
* Mechanism for reporting feedback from a bot, and possibly allowing user to
2425
interactively respond.
2526
* Add configuration option to auto sync and `--no-sync` flag. Similar to reset.
26-
* Add "amend" commit when finalizing. This could be useful training data,
27-
showing what the bot did not get right.
27+
Also rename both options to `sync` and `reset`, this will make it more natural
28+
to support a similar config option for `accept`.
29+
* Add `--sync` `finalize` option which creates a additional commit when
30+
finalizing if any changes were added to the bot's output. This could be useful
31+
training data, showing what the bot did not get right.
2832
* Convenience `--accept` functionality for simple cases: checkout option which
2933
applies the changes, and finalizes the draft if specified multiple times. For
3034
example `git draft -aa add-test symbol=foo`
35+
* Support file rename tool.
36+
* https://stackoverflow.com/q/49853177/1062617
37+
* https://stackoverflow.com/q/6658313/1062617

docs/git-draft.adoc

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,27 @@ IMPORTANT: `git-draft` is WIP.
1818
== Synopsis
1919

2020
[verse]
21-
git draft [options] [--generate] [--bot BOT] [--edit] [--reset | --no-reset] [--sync] [TEMPLATE [VARIABLE...]]
22-
git draft [options] --finalize [--delete]
21+
git draft [options] [--generate] [--accept... | no-accept] [--bot BOT] [--edit] [--reset | --no-reset] [--sync | --no-sync] [TEMPLATE [VARIABLE...]]
22+
git draft [options] --finalize [--delete] [--sync | --no-sync]
2323
git draft [options] --show-drafts [--json]
2424
git draft [options] --show-prompts [--json] [PROMPT]
2525
git draft [options] --show-templates [--json | [--edit] TEMPLATE]
2626

2727

2828
== Description
2929

30-
`git-draft` is a git-centric way to edit code using AI.
30+
`git-draft` is a git-centric way to develop using AI.
3131

3232

3333
== Options
3434

35+
-a::
36+
--accept::
37+
--no-accept::
38+
Check out generated changes automatically.
39+
Can be repeated.
40+
This may fail if you manually edit files that the bot updates during generation.
41+
3542
-b BOT::
3643
--bot=BOT::
3744
Bot name.
@@ -42,15 +49,17 @@ git draft [options] --show-templates [--json | [--edit] TEMPLATE]
4249

4350
-e::
4451
--edit::
45-
Edit.
52+
Enable interactive editing of prompts and templates.
53+
See `--generate` and `--show-templates` for details.
4654

4755
-F::
4856
--finalize::
49-
TODO
57+
Go back to the draft's origin branch with the current working directory.
5058

5159
-G::
5260
--generate::
53-
TODO
61+
Add an AI-generated commit.
62+
If the `--edit` option is set, an interactive editor will be open with the rendered prompt to allow modification before it is forwarded to the bot.
5463

5564
-h::
5665
--help::
@@ -65,22 +74,25 @@ git draft [options] --show-templates [--json | [--edit] TEMPLATE]
6574

6675
--reset::
6776
--no-reset::
68-
TODO
77+
Controls behavior when staged changes are present at the start of a generate command.
78+
If enabled, these changes are automatically reset and combined with other working directory changes.
79+
Otherwise an error is raised.
6980

7081
--root::
7182
Repository search root.
7283

7384
-D::
7485
--show-drafts::
75-
TODO
86+
List recently created drafts.
7687

7788
-P::
7889
--show-prompts::
79-
TODO
90+
Lists recently used prompts.
8091

8192
-T::
8293
--show-templates::
83-
TODO
94+
Lists available templates.
95+
With an template name argument, displays the corresponding template's contents or, if the `--edit` option is set, opens an interactive editor.
8496

8597
-s::
8698
--sync::

src/git_draft/__main__.py

Lines changed: 67 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
from .bots import load_bot
1313
from .common import PROGRAM, Config, UnreachableError, ensure_state_home
14-
from .drafter import Drafter
14+
from .drafter import Accept, Drafter
1515
from .editor import open_editor
1616
from .prompt import Template, TemplatedPrompt, find_template, templates_table
1717
from .store import Store
@@ -64,6 +64,12 @@ def callback(
6464
add_command("show-prompts", short="P", help="show prompt history")
6565
add_command("show-templates", short="T", help="show template information")
6666

67+
parser.add_option(
68+
"-a",
69+
"--accept",
70+
help="apply generated changes",
71+
action="count",
72+
)
6773
parser.add_option(
6874
"-b",
6975
"--bot",
@@ -171,67 +177,69 @@ def main() -> None: # noqa: PLR0912 PLR0915
171177
logging.basicConfig(level=config.log_level, filename=str(log_path))
172178

173179
drafter = Drafter.create(store=Store.persistent(), path=opts.root)
174-
command = getattr(opts, "command", "generate")
175-
if command == "generate":
176-
bot_config = None
177-
if opts.bot:
178-
bot_configs = [c for c in config.bots if c.name == opts.bot]
179-
if len(bot_configs) != 1:
180-
raise ValueError(f"Found {len(bot_configs)} matching bots")
181-
bot_config = bot_configs[0]
182-
elif config.bots:
183-
bot_config = config.bots[0]
184-
bot = load_bot(bot_config)
185-
186-
prompt: str | TemplatedPrompt
187-
editable = opts.edit
188-
if args:
189-
prompt = TemplatedPrompt.parse(args[0], *args[1:])
190-
elif opts.edit:
191-
editable = False
192-
prompt = edit(
193-
text=drafter.latest_draft_prompt() or _PROMPT_PLACEHOLDER
180+
match getattr(opts, "command", "generate"):
181+
case "generate":
182+
bot_config = None
183+
if opts.bot:
184+
bot_configs = [c for c in config.bots if c.name == opts.bot]
185+
if len(bot_configs) != 1:
186+
raise ValueError(f"Found {len(bot_configs)} matching bots")
187+
bot_config = bot_configs[0]
188+
elif config.bots:
189+
bot_config = config.bots[0]
190+
bot = load_bot(bot_config)
191+
192+
prompt: str | TemplatedPrompt
193+
editable = opts.edit
194+
if args:
195+
prompt = TemplatedPrompt.parse(args[0], *args[1:])
196+
elif opts.edit:
197+
editable = False
198+
prompt = edit(
199+
text=drafter.latest_draft_prompt() or _PROMPT_PLACEHOLDER
200+
)
201+
else:
202+
prompt = sys.stdin.read()
203+
204+
accept = Accept(opts.accept or 0)
205+
name = drafter.generate_draft(
206+
prompt,
207+
bot,
208+
accept=accept,
209+
bot_name=opts.bot,
210+
prompt_transform=open_editor if editable else None,
211+
tool_visitors=[ToolPrinter()],
212+
reset=config.auto_reset if opts.reset is None else opts.reset,
213+
sync=opts.sync,
194214
)
195-
else:
196-
prompt = sys.stdin.read()
197-
198-
name = drafter.generate_draft(
199-
prompt,
200-
bot,
201-
bot_name=opts.bot,
202-
prompt_transform=open_editor if editable else None,
203-
tool_visitors=[ToolPrinter()],
204-
reset=config.auto_reset if opts.reset is None else opts.reset,
205-
sync=opts.sync,
206-
)
207-
print(f"Refined {name}.")
208-
elif command == "finalize":
209-
name = drafter.finalize_draft(delete=opts.delete)
210-
print(f"Finalized {name}.")
211-
elif command == "show-drafts":
212-
table = drafter.history_table(args[0] if args else None)
213-
if table:
214-
print(table.to_json() if opts.json else table)
215-
elif command == "show-prompts":
216-
raise NotImplementedError() # TODO: Implement
217-
elif command == "show-templates":
218-
if args:
219-
name = args[0]
220-
tpl = find_template(name)
221-
if opts.edit:
222-
if tpl:
223-
edit(path=tpl.local_path(), text=tpl.source)
215+
print(f"Generated change in {name}.")
216+
case "finalize":
217+
name = drafter.finalize_draft(delete=opts.delete)
218+
print(f"Finalized {name}.")
219+
case "show-drafts":
220+
table = drafter.history_table(args[0] if args else None)
221+
if table:
222+
print(table.to_json() if opts.json else table)
223+
case "show-prompts":
224+
raise NotImplementedError() # TODO: Implement
225+
case "show-templates":
226+
if args:
227+
name = args[0]
228+
tpl = find_template(name)
229+
if opts.edit:
230+
if tpl:
231+
edit(path=tpl.local_path(), text=tpl.source)
232+
else:
233+
edit(path=Template.local_path_for(name))
224234
else:
225-
edit(path=Template.local_path_for(name))
235+
if not tpl:
236+
raise ValueError(f"No template named {name!r}")
237+
print(tpl.source)
226238
else:
227-
if not tpl:
228-
raise ValueError(f"No template named {name!r}")
229-
print(tpl.source)
230-
else:
231-
table = templates_table()
232-
print(table.to_json() if opts.json else table)
233-
else:
234-
raise UnreachableError()
239+
table = templates_table()
240+
print(table.to_json() if opts.json else table)
241+
case _:
242+
raise UnreachableError()
235243

236244

237245
if __name__ == "__main__":

0 commit comments

Comments
 (0)