devstuff 1.14.1__tar.gz → 1.15.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.
Files changed (54) hide show
  1. {devstuff-1.14.1 → devstuff-1.15.0}/.github/workflows/test-installs.yml +1 -0
  2. {devstuff-1.14.1 → devstuff-1.15.0}/CHANGELOG.md +12 -0
  3. {devstuff-1.14.1 → devstuff-1.15.0}/PKG-INFO +2 -1
  4. {devstuff-1.14.1 → devstuff-1.15.0}/README.md +1 -0
  5. {devstuff-1.14.1 → devstuff-1.15.0}/pyproject.toml +1 -1
  6. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/help_cmd.py +1 -1
  7. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/install_cmd.py +2 -3
  8. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/skills_cmd.py +1 -4
  9. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/update_cmd.py +2 -3
  10. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/tools.yaml +1 -0
  11. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/ui.py +20 -5
  12. {devstuff-1.14.1 → devstuff-1.15.0}/uv.lock +1 -1
  13. {devstuff-1.14.1 → devstuff-1.15.0}/.claude/skills/run-stuff/SKILL.md +0 -0
  14. {devstuff-1.14.1 → devstuff-1.15.0}/.claude/skills/run-stuff/smoke.sh +0 -0
  15. {devstuff-1.14.1 → devstuff-1.15.0}/.github/workflows/bump.yml +0 -0
  16. {devstuff-1.14.1 → devstuff-1.15.0}/.github/workflows/ci.yml +0 -0
  17. {devstuff-1.14.1 → devstuff-1.15.0}/.github/workflows/publish.yml +0 -0
  18. {devstuff-1.14.1 → devstuff-1.15.0}/.gitignore +0 -0
  19. {devstuff-1.14.1 → devstuff-1.15.0}/CLAUDE.md +0 -0
  20. {devstuff-1.14.1 → devstuff-1.15.0}/dev/Dockerfile +0 -0
  21. {devstuff-1.14.1 → devstuff-1.15.0}/dev/Dockerfile.ci +0 -0
  22. {devstuff-1.14.1 → devstuff-1.15.0}/dev/Makefile +0 -0
  23. {devstuff-1.14.1 → devstuff-1.15.0}/dev/docker-compose.yml +0 -0
  24. {devstuff-1.14.1 → devstuff-1.15.0}/dev-setup +0 -0
  25. {devstuff-1.14.1 → devstuff-1.15.0}/install.sh +0 -0
  26. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/__init__.py +0 -0
  27. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/__main__.py +0 -0
  28. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/base.py +0 -0
  29. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/catalog.py +0 -0
  30. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/cli.py +0 -0
  31. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/__init__.py +0 -0
  32. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/add_cmd.py +0 -0
  33. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/catalog_cmd.py +0 -0
  34. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/delete_cmd.py +0 -0
  35. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/docs_cmd.py +0 -0
  36. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/functions_cmd.py +0 -0
  37. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/list_cmd.py +0 -0
  38. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/remove_cmd.py +0 -0
  39. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/commands/run_cmd.py +0 -0
  40. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/function_runner.py +0 -0
  41. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/functions.schema.json +0 -0
  42. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/functions.yaml +0 -0
  43. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/functions_catalog.py +0 -0
  44. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/functions_registry.py +0 -0
  45. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/generic.py +0 -0
  46. {devstuff-1.14.1 → devstuff-1.15.0}/src/dev_setup/registry.py +0 -0
  47. {devstuff-1.14.1 → devstuff-1.15.0}/tests/__init__.py +0 -0
  48. {devstuff-1.14.1 → devstuff-1.15.0}/tests/integration/__init__.py +0 -0
  49. {devstuff-1.14.1 → devstuff-1.15.0}/tests/integration/conftest.py +0 -0
  50. {devstuff-1.14.1 → devstuff-1.15.0}/tests/integration/test_tools.py +0 -0
  51. {devstuff-1.14.1 → devstuff-1.15.0}/tests/test_catalog.py +0 -0
  52. {devstuff-1.14.1 → devstuff-1.15.0}/tests/test_functions.py +0 -0
  53. {devstuff-1.14.1 → devstuff-1.15.0}/tests/test_generic.py +0 -0
  54. {devstuff-1.14.1 → devstuff-1.15.0}/tests/test_registry.py +0 -0
@@ -64,6 +64,7 @@ jobs:
64
64
  - nvm
65
65
  - php
66
66
  - pi # installs nvm first via its declared `requires`
67
+ - pre-commit # uvx tool, requires uv
67
68
  - ruby # compiles from source — this job takes ~15 minutes
68
69
  - saml2aws
69
70
  - starship
@@ -1,3 +1,15 @@
1
+ ## v1.15.0 (2026-07-18)
2
+
3
+ ### Feat
4
+
5
+ - complete pre-commit tool integration
6
+
7
+ ## v1.14.2 (2026-07-12)
8
+
9
+ ### Fix
10
+
11
+ - make interactive prompts abortable with Ctrl+C/Ctrl+D
12
+
1
13
  ## v1.14.1 (2026-07-12)
2
14
 
3
15
  ### Fix
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devstuff
3
- Version: 1.14.1
3
+ Version: 1.15.0
4
4
  Summary: Development environment setup CLI for Linux
5
5
  Project-URL: Repository, https://github.com/thesawdawg/dev-setup-py
6
6
  Author-email: Sawyer <sawyerksu@gmail.com>
@@ -439,6 +439,7 @@ Optional utilities you may want on some machines.
439
439
  | `ollama` | Ollama | Run large language models locally | `ollama --help` |
440
440
  | `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
441
441
  | `pi` | Pi Coding Agent | AI coding agent npm package | `pi --help` |
442
+ | `pre-commit` | pre-commit | Git hook manager for automated code quality checks | `pre-commit --help` |
442
443
  | `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
443
444
  | `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
444
445
  | `yq` | yq | Portable command-line YAML/JSON/XML processor | `yq --help` |
@@ -412,6 +412,7 @@ Optional utilities you may want on some machines.
412
412
  | `ollama` | Ollama | Run large language models locally | `ollama --help` |
413
413
  | `php` | PHP 8.4 | PHP 8.4 + common extensions via ondrej/php PPA | `php --help` |
414
414
  | `pi` | Pi Coding Agent | AI coding agent npm package | `pi --help` |
415
+ | `pre-commit` | pre-commit | Git hook manager for automated code quality checks | `pre-commit --help` |
415
416
  | `saml2aws` | saml2aws | SAML → AWS STS credentials CLI (Versent) | `saml2aws --help` |
416
417
  | `starship` | Starship | Fast, cross-shell customizable prompt | `starship --help` |
417
418
  | `yq` | yq | Portable command-line YAML/JSON/XML processor | `yq --help` |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "devstuff"
3
- version = "1.14.1"
3
+ version = "1.15.0"
4
4
  description = "Development environment setup CLI for Linux"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -19,7 +19,7 @@ def print_help() -> None:
19
19
  ("docs", "<package>", "Open documentation in browser"),
20
20
  ("run", "<function> [args...]", "Run a function/script"),
21
21
  ("functions", "<list|enable|disable|path>", "Manage functions/scripts"),
22
- ("skills", "add", "Append skills from a GitHub repo to claude/codex/pi"),
22
+ ("skills", "add", "Append GitHub skills to claude/codex/pi"),
23
23
  ("version", "", "Show version"),
24
24
  ]
25
25
  for cmd, args, desc in rows:
@@ -102,12 +102,11 @@ def _install_interactive() -> None:
102
102
  disabled=disabled,
103
103
  ))
104
104
 
105
- selected = questionary.checkbox(
105
+ selected = ui.checkbox(
106
106
  "Select packages to install:",
107
107
  choices=choices,
108
108
  instruction="(Space toggle · Enter confirm · installed items are skipped)",
109
- style=ui._STYLE,
110
- ).ask()
109
+ )
111
110
 
112
111
  if not selected:
113
112
  ui.info("No packages selected.")
@@ -112,10 +112,7 @@ def _clone_repo(repo: str, dest: Path) -> str | None:
112
112
  return ssh_url
113
113
 
114
114
  if auth_method == "Personal access token":
115
- token = questionary.password("GitHub personal access token:").ask()
116
- if not token:
117
- ui.warn("No token provided — aborted.")
118
- return None
115
+ token = ui.password("GitHub personal access token:")
119
116
  owner_repo = _owner_repo(repo)
120
117
  token_url = f"https://x-access-token:{token}@github.com/{owner_repo}.git"
121
118
  with ui.spinner("Cloning with token..."):
@@ -124,12 +124,11 @@ def _update_interactive() -> None:
124
124
  ]
125
125
  choices.append(questionary.Choice(title=title, value=t.key, checked=status.available is True))
126
126
 
127
- selected = questionary.checkbox(
127
+ selected = ui.checkbox(
128
128
  "Select packages to update:",
129
129
  choices=choices,
130
130
  instruction="(Space toggle · Enter confirm · pre-checked items have a known update)",
131
- style=ui._STYLE,
132
- ).ask()
131
+ )
133
132
 
134
133
  if not selected:
135
134
  ui.info("No packages selected.")
@@ -465,6 +465,7 @@ tools:
465
465
  category: tools
466
466
  type: uvx
467
467
  pip_name: pre-commit
468
+ check_cmd: pre-commit
468
469
  help_cmd: pre-commit --help
469
470
  docs_url: https://pre-commit.com/
470
471
  requires:
@@ -75,14 +75,24 @@ def spinner(label: str) -> Generator[None, None, None]:
75
75
  yield
76
76
 
77
77
 
78
+ def _ask(question) -> object:
79
+ """Run a questionary prompt via unsafe_ask() so Ctrl+C/Ctrl+D raise
80
+ KeyboardInterrupt/EOFError instead of being swallowed into a None return
81
+ (questionary's default .ask() catches KeyboardInterrupt and retries
82
+ silently, which makes required prompts impossible to cancel). Click's
83
+ top-level command dispatch already catches both and exits cleanly with
84
+ "Aborted!", so letting them propagate is enough."""
85
+ return question.unsafe_ask()
86
+
87
+
78
88
  def confirm(prompt: str, default: bool = False) -> bool:
79
- result = questionary.confirm(prompt, default=default, style=_STYLE).ask()
89
+ result = _ask(questionary.confirm(prompt, default=default, style=_STYLE))
80
90
  return bool(result)
81
91
 
82
92
 
83
93
  def text_input(prompt: str, default: str = "", required: bool = False) -> str:
84
94
  while True:
85
- result = questionary.text(prompt, default=default, style=_STYLE).ask()
95
+ result = _ask(questionary.text(prompt, default=default, style=_STYLE))
86
96
  val = (result or "").strip()
87
97
  if val or not required:
88
98
  return val
@@ -90,15 +100,20 @@ def text_input(prompt: str, default: str = "", required: bool = False) -> str:
90
100
 
91
101
 
92
102
  def select(prompt: str, choices: list[str]) -> str:
93
- result = questionary.select(prompt, choices=choices, style=_STYLE).ask()
103
+ result = _ask(questionary.select(prompt, choices=choices, style=_STYLE))
94
104
  return result or ""
95
105
 
96
106
 
97
- def checkbox(prompt: str, choices: list) -> list:
98
- result = questionary.checkbox(prompt, choices=choices, style=_STYLE).ask()
107
+ def checkbox(prompt: str, choices: list, **kwargs) -> list:
108
+ result = _ask(questionary.checkbox(prompt, choices=choices, style=_STYLE, **kwargs))
99
109
  return result or []
100
110
 
101
111
 
112
+ def password(prompt: str) -> str:
113
+ result = _ask(questionary.password(prompt, style=_STYLE))
114
+ return result or ""
115
+
116
+
102
117
  def code_block(code: str, language: str = "bash") -> None:
103
118
  """Print a syntax-highlighted code panel."""
104
119
  from rich.syntax import Syntax
@@ -167,7 +167,7 @@ wheels = [
167
167
 
168
168
  [[package]]
169
169
  name = "devstuff"
170
- version = "1.14.1"
170
+ version = "1.15.0"
171
171
  source = { editable = "." }
172
172
  dependencies = [
173
173
  { name = "click" },
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes