noidea 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
noidea-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AccursedGalaxy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
noidea-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: noidea
3
+ Version: 0.1.0
4
+ Summary: AI powered commit suggestions
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Author: AccursedGalaxy
8
+ Author-email: robinbohrer7@gmail.com
9
+ Requires-Python: >=3.13
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Dist: anthropic (>=0.85.0,<0.86.0)
15
+ Requires-Dist: python-dotenv (>=1.2.2,<2.0.0)
16
+ Requires-Dist: typer (>=0.24.1,<0.25.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ # noidea
20
+
21
+ AI-powered commit message suggestions via git hooks. Stages a diff, sends it to Claude, and pre-fills your commit editor.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pipx install noidea
27
+ export ANTHROPIC_API_KEY=sk-ant-...
28
+ noidea init
29
+ ```
30
+
31
+ > Requires [pipx](https://pipx.pypa.io). Alternatively: `pip install noidea`
32
+
33
+ `noidea init` installs a `prepare-commit-msg` hook in your repo. From then on, every `git commit` opens your editor with a suggested message pre-filled.
34
+
35
+ ## Commands
36
+
37
+ ### `noidea init`
38
+ Installs the git hook. Backs up any existing `prepare-commit-msg` as `.bak`. Respects `core.hooksPath`.
39
+
40
+ ### `noidea update`
41
+ Updates noidea to the latest version via `pipx upgrade noidea` (falls back to `pip install --upgrade noidea`).
42
+
43
+ ### `noidea suggest`
44
+ Generates a commit message from the current staged diff and prints it.
45
+
46
+ ```
47
+ Options:
48
+ -F, --file TEXT Write message to file instead of stdout (used by the hook)
49
+ ```
50
+
51
+ ## Config
52
+
53
+ Optional config at `~/.noidea/noidea.toml`:
54
+
55
+ ```toml
56
+ [llm]
57
+ model = "claude-sonnet-4-6"
58
+ max_tokens = 1024
59
+ system_prompt = "Your custom prompt here"
60
+ ```
61
+
62
+ Falls back to built-in defaults if no config file exists.
63
+
64
+ ## Requirements
65
+
66
+ - Python 3.13+
67
+ - `ANTHROPIC_API_KEY` env var
68
+
noidea-0.1.0/README.md ADDED
@@ -0,0 +1,49 @@
1
+ # noidea
2
+
3
+ AI-powered commit message suggestions via git hooks. Stages a diff, sends it to Claude, and pre-fills your commit editor.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pipx install noidea
9
+ export ANTHROPIC_API_KEY=sk-ant-...
10
+ noidea init
11
+ ```
12
+
13
+ > Requires [pipx](https://pipx.pypa.io). Alternatively: `pip install noidea`
14
+
15
+ `noidea init` installs a `prepare-commit-msg` hook in your repo. From then on, every `git commit` opens your editor with a suggested message pre-filled.
16
+
17
+ ## Commands
18
+
19
+ ### `noidea init`
20
+ Installs the git hook. Backs up any existing `prepare-commit-msg` as `.bak`. Respects `core.hooksPath`.
21
+
22
+ ### `noidea update`
23
+ Updates noidea to the latest version via `pipx upgrade noidea` (falls back to `pip install --upgrade noidea`).
24
+
25
+ ### `noidea suggest`
26
+ Generates a commit message from the current staged diff and prints it.
27
+
28
+ ```
29
+ Options:
30
+ -F, --file TEXT Write message to file instead of stdout (used by the hook)
31
+ ```
32
+
33
+ ## Config
34
+
35
+ Optional config at `~/.noidea/noidea.toml`:
36
+
37
+ ```toml
38
+ [llm]
39
+ model = "claude-sonnet-4-6"
40
+ max_tokens = 1024
41
+ system_prompt = "Your custom prompt here"
42
+ ```
43
+
44
+ Falls back to built-in defaults if no config file exists.
45
+
46
+ ## Requirements
47
+
48
+ - Python 3.13+
49
+ - `ANTHROPIC_API_KEY` env var
@@ -0,0 +1,6 @@
1
+ from importlib.metadata import version, PackageNotFoundError
2
+
3
+ try:
4
+ __version__ = version("noidea")
5
+ except PackageNotFoundError:
6
+ __version__ = "0.0.0"
@@ -0,0 +1,73 @@
1
+ import subprocess
2
+ import sys
3
+ from typing import Optional
4
+
5
+ import typer
6
+
7
+ from noidea import __version__
8
+ from noidea.config import load_config
9
+ from noidea.git import get_diff, install_hook
10
+ from noidea.provider import get_commit_message
11
+
12
+ app = typer.Typer()
13
+
14
+
15
+ def version_callback(value: bool):
16
+ if value:
17
+ typer.echo(f"noidea {__version__}")
18
+ raise typer.Exit()
19
+
20
+
21
+ @app.callback()
22
+ def main(
23
+ version: Optional[bool] = typer.Option(
24
+ None, "--version", "-v", callback=version_callback, is_eager=True
25
+ ),
26
+ ):
27
+ pass
28
+
29
+
30
+ @app.command()
31
+ def init():
32
+ install_hook()
33
+ print("Git hook installed successfully.")
34
+
35
+
36
+ @app.command()
37
+ def suggest(file: str = typer.Option(None, "--file", "-F")):
38
+ diff = get_diff()
39
+ if diff == "none":
40
+ print("No Changes have been detected")
41
+ return
42
+ config = load_config()
43
+ commit_message = get_commit_message(
44
+ diff,
45
+ config["llm"]["system_prompt"],
46
+ config["llm"]["model"],
47
+ config["llm"]["max_tokens"],
48
+ )
49
+ if file:
50
+ with open(file, "w") as f:
51
+ f.write(commit_message)
52
+ else:
53
+ print(commit_message)
54
+
55
+
56
+ @app.command()
57
+ def update():
58
+ """Update noidea to the latest version."""
59
+ try:
60
+ result = subprocess.run(["pipx", "upgrade", "noidea"], check=True)
61
+ except FileNotFoundError:
62
+ # pipx not available, fall back to pip
63
+ result = subprocess.run(
64
+ [sys.executable, "-m", "pip", "install", "--upgrade", "noidea"],
65
+ check=True,
66
+ )
67
+ except subprocess.CalledProcessError as e:
68
+ typer.echo(f"Update failed: {e}", err=True)
69
+ raise typer.Exit(1)
70
+
71
+
72
+ if __name__ == "__main__":
73
+ app()
@@ -0,0 +1,29 @@
1
+ import os
2
+ import tomllib
3
+
4
+ config_path = os.path.expanduser("~/.noidea/noidea.toml")
5
+
6
+
7
+ def load_config() -> dict:
8
+ if os.path.exists(config_path):
9
+ with open(config_path, "rb") as f:
10
+ config = tomllib.load(f)
11
+ return config
12
+ else:
13
+ defaults = {
14
+ "llm": {
15
+ "max_tokens": 1024,
16
+ "model": "claude-sonnet-4-6",
17
+ "system_prompt": (
18
+ "Generate a concise git commit message from the provided diff.\n"
19
+ "Rules:\n"
20
+ "- First line: imperative mood, max 72 chars, no period\n"
21
+ "- If needed, blank line then body explaining *why*, not *what*\n"
22
+ "- Use conventional commits prefix if scope is clear (feat/fix/refactor/chore/docs/test)\n"
23
+ "- No filler, no praise, no explanation outside the commit message itself\n"
24
+ "Output only the commit message. No code block!"
25
+ ),
26
+ }
27
+ }
28
+
29
+ return defaults
@@ -0,0 +1,32 @@
1
+ import os
2
+ import subprocess
3
+
4
+
5
+ def get_diff():
6
+ diff = subprocess.run(["git", "diff", "--staged"], capture_output=True, text=True)
7
+ if not diff.stdout:
8
+ return "none"
9
+ return diff.stdout
10
+
11
+
12
+ def get_hooks_dir() -> str:
13
+ hooks_dir = subprocess.run(
14
+ ["git", "config", "core.hooksPath"], capture_output=True, text=True
15
+ )
16
+ if not hooks_dir.stdout:
17
+ return ".git/hooks"
18
+
19
+ return hooks_dir.stdout.strip()
20
+
21
+
22
+ def install_hook():
23
+ hooks_dir = get_hooks_dir()
24
+ hook_path = os.path.join(hooks_dir, "prepare-commit-msg")
25
+
26
+ if os.path.exists(hook_path):
27
+ os.rename(hook_path, hook_path + ".bak")
28
+
29
+ with open(hook_path, "w") as f:
30
+ f.write('#!/bin/bash\nnoidea suggest --file "$1"\n')
31
+
32
+ os.chmod(hook_path, mode=0o755)
@@ -0,0 +1,25 @@
1
+ import os
2
+
3
+ from anthropic import Anthropic
4
+ from anthropic.types import TextBlock
5
+ from dotenv import load_dotenv
6
+
7
+ load_dotenv()
8
+
9
+ client = Anthropic(
10
+ api_key=os.environ.get("ANTHROPIC_API_KEY"),
11
+ )
12
+
13
+
14
+ def get_commit_message(
15
+ diff: str, system_prompt: str, model: str, max_tokens: int
16
+ ) -> str:
17
+ message = client.messages.create(
18
+ model=model,
19
+ system=system_prompt,
20
+ messages=[{"role": "user", "content": diff}],
21
+ max_tokens=max_tokens,
22
+ )
23
+ block = message.content[0]
24
+ assert isinstance(block, TextBlock)
25
+ return block.text
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "noidea"
3
+ version = "0.1.0"
4
+ description = "AI powered commit suggestions"
5
+ authors = [
6
+ {name = "AccursedGalaxy",email = "robinbohrer7@gmail.com"}
7
+ ]
8
+ license = {text = "MIT"}
9
+ readme = "README.md"
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "anthropic (>=0.85.0,<0.86.0)",
13
+ "python-dotenv (>=1.2.2,<2.0.0)",
14
+ "typer (>=0.24.1,<0.25.0)"
15
+ ]
16
+
17
+ [project.scripts]
18
+ noidea = "noidea.cli:app"
19
+
20
+ [build-system]
21
+ requires = ["poetry-core>=2.0.0,<3.0.0"]
22
+ build-backend = "poetry.core.masonry.api"