plain.dev 0.36.0__tar.gz → 0.38.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 (33) hide show
  1. {plain_dev-0.36.0 → plain_dev-0.38.0}/PKG-INFO +1 -1
  2. plain_dev-0.38.0/plain/dev/AGENTS.md +3 -0
  3. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/CHANGELOG.md +20 -0
  4. plain_dev-0.38.0/plain/dev/alias.py +152 -0
  5. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/cli.py +4 -1
  6. {plain_dev-0.36.0 → plain_dev-0.38.0}/pyproject.toml +1 -1
  7. {plain_dev-0.36.0 → plain_dev-0.38.0}/.gitignore +0 -0
  8. {plain_dev-0.36.0 → plain_dev-0.38.0}/LICENSE +0 -0
  9. {plain_dev-0.36.0 → plain_dev-0.38.0}/README.md +0 -0
  10. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/README.md +0 -0
  11. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/__init__.py +0 -0
  12. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/contribute/README.md +0 -0
  13. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/contribute/__init__.py +0 -0
  14. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/contribute/cli.py +0 -0
  15. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/core.py +0 -0
  16. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/debug.py +0 -0
  17. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/default_settings.py +0 -0
  18. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/entrypoints.py +0 -0
  19. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/gunicorn_logging.json +0 -0
  20. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/mkcert.py +0 -0
  21. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/pdb.py +0 -0
  22. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/__init__.py +0 -0
  23. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/color.py +0 -0
  24. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/compat.py +0 -0
  25. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/manager.py +0 -0
  26. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/printer.py +0 -0
  27. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/poncho/process.py +0 -0
  28. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/precommit/__init__.py +0 -0
  29. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/precommit/cli.py +0 -0
  30. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/process.py +0 -0
  31. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/services.py +0 -0
  32. {plain_dev-0.36.0 → plain_dev-0.38.0}/plain/dev/utils.py +0 -0
  33. {plain_dev-0.36.0 → plain_dev-0.38.0}/tests/settings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plain.dev
3
- Version: 0.36.0
3
+ Version: 0.38.0
4
4
  Summary: A single command that runs everything you need for local development.
5
5
  Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
6
6
  License-Expression: BSD-3-Clause
@@ -0,0 +1,3 @@
1
+ # Plain Dev AGENTS.md
2
+
3
+ - `plain dev logs`: Show the log output for the running `plain dev` processes
@@ -1,5 +1,25 @@
1
1
  # plain-dev changelog
2
2
 
3
+ ## [0.38.0](https://github.com/dropseed/plain/releases/plain-dev@0.38.0) (2025-09-30)
4
+
5
+ ### What's changed
6
+
7
+ - Added an `AGENTS.md` file with package-specific agent instructions for the `plain dev logs` command ([5841a3f](https://github.com/dropseed/plain/commit/5841a3fb0b))
8
+
9
+ ### Upgrade instructions
10
+
11
+ - No changes required
12
+
13
+ ## [0.37.0](https://github.com/dropseed/plain/releases/plain-dev@0.37.0) (2025-09-29)
14
+
15
+ ### What's changed
16
+
17
+ - Added a `p` alias prompt that suggests setting up a shell alias for `uv run plain` to make command execution faster ([d913b44](https://github.com/dropseed/plain/commit/d913b44fab), [6632529](https://github.com/dropseed/plain/commit/663252925b))
18
+
19
+ ### Upgrade instructions
20
+
21
+ - No changes required
22
+
3
23
  ## [0.36.0](https://github.com/dropseed/plain/releases/plain-dev@0.36.0) (2025-09-25)
4
24
 
5
25
  ### What's changed
@@ -0,0 +1,152 @@
1
+ import os
2
+ import subprocess
3
+ import sys
4
+ from functools import cached_property
5
+ from pathlib import Path
6
+
7
+ import click
8
+
9
+
10
+ class AliasManager:
11
+ """Manages the 'p' alias for 'uv run plain'."""
12
+
13
+ MARKER_FILE = Path.home() / ".plain" / "dev" / ".alias_prompted"
14
+ ALIAS_COMMAND = "uv run plain"
15
+ ALIAS_NAME = "p"
16
+
17
+ @cached_property
18
+ def shell(self):
19
+ """Detect the current shell."""
20
+ shell = os.environ.get("SHELL", "")
21
+ if "zsh" in shell:
22
+ return "zsh"
23
+ elif "bash" in shell:
24
+ return "bash"
25
+ elif "fish" in shell:
26
+ return "fish"
27
+ return None
28
+
29
+ @cached_property
30
+ def shell_config_file(self):
31
+ """Get the appropriate shell configuration file."""
32
+ home = Path.home()
33
+
34
+ if self.shell == "zsh":
35
+ return home / ".zshrc"
36
+ elif self.shell == "bash":
37
+ # Check for .bash_aliases first (Ubuntu/Debian convention)
38
+ if (home / ".bash_aliases").exists():
39
+ return home / ".bash_aliases"
40
+ return home / ".bashrc"
41
+ elif self.shell == "fish":
42
+ return home / ".config" / "fish" / "config.fish"
43
+
44
+ return None
45
+
46
+ def _command_exists(self, command):
47
+ """Check if a command exists in the system."""
48
+ try:
49
+ result = subprocess.run(
50
+ ["which", command], capture_output=True, text=True, check=False
51
+ )
52
+ return result.returncode == 0
53
+ except Exception:
54
+ return False
55
+
56
+ def _alias_exists(self):
57
+ """Check if the 'p' alias already exists."""
58
+ # First check if 'p' is already a command
59
+ if self._command_exists(self.ALIAS_NAME):
60
+ return True
61
+
62
+ # Check if alias is defined in shell
63
+ try:
64
+ # Try to run the alias to see if it exists
65
+ result = subprocess.run(
66
+ [self.shell, "-i", "-c", f"alias {self.ALIAS_NAME}"],
67
+ capture_output=True,
68
+ text=True,
69
+ check=False,
70
+ timeout=2,
71
+ )
72
+ return result.returncode == 0
73
+ except (subprocess.TimeoutExpired, Exception):
74
+ return False
75
+
76
+ def _add_alias_to_shell(self):
77
+ """Add the alias to the shell configuration file."""
78
+ if not self.shell_config_file or not self.shell_config_file.exists():
79
+ return False
80
+
81
+ alias_line = f'alias {self.ALIAS_NAME}="{self.ALIAS_COMMAND}"'
82
+ comment = "# Added by Plain"
83
+
84
+ # Check if alias already in file
85
+ try:
86
+ with open(self.shell_config_file) as f:
87
+ content = f.read()
88
+ if alias_line in content:
89
+ return True
90
+ except Exception:
91
+ return False
92
+
93
+ # Add alias to file
94
+ try:
95
+ with open(self.shell_config_file, "a") as f:
96
+ f.write(f"\n{comment}\n{alias_line}\n")
97
+
98
+ click.secho(
99
+ f"✓ Added '{self.ALIAS_NAME}' alias to {self.shell_config_file.name}. Restart your shell!",
100
+ fg="green",
101
+ )
102
+ return True
103
+ except Exception as e:
104
+ click.secho(
105
+ f"Failed to add alias to {self.shell_config_file.name}: {e}", fg="red"
106
+ )
107
+ return False
108
+
109
+ def check_and_prompt(self):
110
+ """Check if alias exists and prompt user to set it up if needed."""
111
+ # Only suggest if project uses uv (has uv.lock file)
112
+ if not Path("uv.lock").exists():
113
+ return
114
+
115
+ # Don't prompt if already configured
116
+ if self._alias_exists():
117
+ return
118
+
119
+ # Don't prompt if we've asked before
120
+ if self.MARKER_FILE.exists():
121
+ return
122
+
123
+ # Don't prompt for certain commands
124
+ if "--help" in sys.argv or "-h" in sys.argv:
125
+ return
126
+
127
+ # Mark that we've asked (do this first so we don't ask again even if they Ctrl+C)
128
+ self.MARKER_FILE.parent.mkdir(parents=True, exist_ok=True)
129
+ self.MARKER_FILE.touch()
130
+
131
+ click.echo()
132
+ click.secho("💡 Tip: ", fg="yellow", bold=True, nl=False)
133
+ click.echo(
134
+ f"Set up `{self.ALIAS_NAME}` as an alias to run commands faster (e.g., `{self.ALIAS_NAME} dev` instead of `uv run plain dev`)."
135
+ )
136
+ click.echo()
137
+
138
+ # Check if shell is supported
139
+ if not self.shell or not self.shell_config_file:
140
+ click.echo("To set this up manually, add to your shell config:")
141
+ click.echo(f' alias {self.ALIAS_NAME}="{self.ALIAS_COMMAND}"')
142
+ click.echo()
143
+ return
144
+
145
+ # Offer to set it up
146
+ prompt_text = f"Would you like to add this to {self.shell_config_file.name}?"
147
+ if click.confirm(prompt_text, default=False):
148
+ click.echo()
149
+ if self._add_alias_to_shell():
150
+ sys.exit(0) # Completely exit
151
+
152
+ click.echo()
@@ -9,6 +9,7 @@ import click
9
9
  from plain.cli import register_cli
10
10
  from plain.runtime import APP_PATH, PLAIN_TEMP_PATH
11
11
 
12
+ from .alias import AliasManager
12
13
  from .core import ENTRYPOINT_GROUP, DevProcess
13
14
  from .services import ServicesProcess
14
15
 
@@ -119,7 +120,6 @@ class DevGroup(click.Group):
119
120
  )
120
121
  def cli(ctx, port, hostname, log_level, start, stop):
121
122
  """Start local development"""
122
-
123
123
  if ctx.invoked_subcommand:
124
124
  return
125
125
 
@@ -170,6 +170,9 @@ def cli(ctx, port, hostname, log_level, start, stop):
170
170
  )
171
171
  return
172
172
 
173
+ # Check and prompt for alias setup
174
+ AliasManager().check_and_prompt()
175
+
173
176
  dev.setup(port=port, hostname=hostname, log_level=log_level)
174
177
  returncode = dev.run()
175
178
  if returncode:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "plain.dev"
3
- version = "0.36.0"
3
+ version = "0.38.0"
4
4
  description = "A single command that runs everything you need for local development."
5
5
  authors = [{name = "Dave Gaeddert", email = "dave.gaeddert@dropseed.dev"}]
6
6
  license = "BSD-3-Clause"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes