path-link 0.2.0__py3-none-any.whl → 0.3.0__py3-none-any.whl

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.
@@ -1,12 +1,12 @@
1
1
  """
2
- ptool-serena: Type-safe path configuration for Python projects
2
+ path-link: Type-safe path configuration for Python projects
3
3
 
4
4
  A powerful library for managing project paths with built-in validation,
5
5
  static model generation, and comprehensive security features.
6
6
 
7
7
  Quick Start
8
8
  -----------
9
- >>> from project_paths import ProjectPaths
9
+ >>> from path_link import ProjectPaths
10
10
  >>>
11
11
  >>> # Load paths from pyproject.toml
12
12
  >>> paths = ProjectPaths.from_pyproject()
@@ -28,7 +28,7 @@ Documentation Access (Offline)
28
28
  -------------------------------
29
29
  Access comprehensive documentation programmatically, even in airgapped environments:
30
30
 
31
- >>> from project_paths import get_ai_guidelines, get_developer_guide, get_metadata
31
+ >>> from path_link import get_ai_guidelines, get_developer_guide, get_metadata
32
32
  >>> import json
33
33
  >>>
34
34
  >>> # Get AI assistant usage patterns and best practices
@@ -45,7 +45,7 @@ Access comprehensive documentation programmatically, even in airgapped environme
45
45
 
46
46
  Validation Example
47
47
  ------------------
48
- >>> from project_paths import validate_or_raise, StrictPathValidator
48
+ >>> from path_link import validate_or_raise, StrictPathValidator
49
49
  >>>
50
50
  >>> paths = ProjectPaths.from_pyproject()
51
51
  >>> validator = StrictPathValidator(
@@ -75,14 +75,14 @@ See Also
75
75
  - AI guidelines: get_ai_guidelines()
76
76
  - Developer guide: get_developer_guide()
77
77
  - Package metadata: get_metadata()
78
- - GitHub: https://github.com/yourusername/ptool-serena
78
+ - GitHub: https://github.com/yourusername/path-link
79
79
  """
80
80
 
81
81
  from importlib.resources import files
82
82
 
83
- from .model import ProjectPaths
84
- from .get_paths import write_dataclass_file
85
- from .validation import (
83
+ from path_link.model import ProjectPaths
84
+ from path_link.get_paths import write_dataclass_file
85
+ from path_link.validation import (
86
86
  Severity,
87
87
  Finding,
88
88
  ValidationResult,
@@ -91,15 +91,18 @@ from .validation import (
91
91
  validate_or_raise,
92
92
  CompositeValidator,
93
93
  )
94
- from .builtin_validators.strict import StrictPathValidator
95
- from .builtin_validators.sandbox import SandboxPathValidator
94
+ from path_link.builtin_validators.strict import StrictPathValidator
95
+ from path_link.builtin_validators.sandbox import SandboxPathValidator
96
+ from path_link.url_factory import ProjectUrls
97
+ from path_link.url_model import ValidationMode
98
+ from path_link.url_static import write_url_dataclass_file
96
99
 
97
100
 
98
101
  def get_ai_guidelines() -> str:
99
102
  """
100
103
  Return AI assistant guidelines for working with this package.
101
104
 
102
- This provides comprehensive guidance for AI agents helping users with ptool-serena,
105
+ This provides comprehensive guidance for AI agents helping users with path-link,
103
106
  including usage patterns, critical rules, validation patterns, and troubleshooting.
104
107
 
105
108
  Returns:
@@ -109,7 +112,7 @@ def get_ai_guidelines() -> str:
109
112
  >>> guidelines = get_ai_guidelines()
110
113
  >>> print(guidelines[:100])
111
114
  """
112
- return files("project_paths.docs").joinpath("ai_guidelines.md").read_text()
115
+ return files("path_link.docs").joinpath("ai_guidelines.md").read_text()
113
116
 
114
117
 
115
118
  def get_developer_guide() -> str:
@@ -117,7 +120,7 @@ def get_developer_guide() -> str:
117
120
  Return developer guide for contributing to this package.
118
121
 
119
122
  This provides architecture details, development setup, testing patterns,
120
- and contribution guidelines for developers working on ptool-serena.
123
+ and contribution guidelines for developers working on path-link.
121
124
 
122
125
  Returns:
123
126
  str: Full content of developer guide (formerly CLAUDE.md)
@@ -126,7 +129,7 @@ def get_developer_guide() -> str:
126
129
  >>> guide = get_developer_guide()
127
130
  >>> print(guide[:100])
128
131
  """
129
- return files("project_paths.docs").joinpath("developer_guide.md").read_text()
132
+ return files("path_link.docs").joinpath("developer_guide.md").read_text()
130
133
 
131
134
 
132
135
  def get_metadata() -> str:
@@ -144,7 +147,7 @@ def get_metadata() -> str:
144
147
  >>> metadata = json.loads(get_metadata())
145
148
  >>> print(metadata['version'])
146
149
  """
147
- return files("project_paths.docs").joinpath("metadata.json").read_text()
150
+ return files("path_link.docs").joinpath("metadata.json").read_text()
148
151
 
149
152
 
150
153
  __all__ = [
@@ -159,6 +162,9 @@ __all__ = [
159
162
  "CompositeValidator",
160
163
  "StrictPathValidator",
161
164
  "SandboxPathValidator",
165
+ "ProjectUrls",
166
+ "ValidationMode",
167
+ "write_url_dataclass_file",
162
168
  "get_ai_guidelines",
163
169
  "get_developer_guide",
164
170
  "get_metadata",
@@ -17,7 +17,7 @@ def get_paths_from_pyproject() -> Dict[str, str]:
17
17
  with pyproject_path.open("rb") as f:
18
18
  pyproject_data = toml_load(f)
19
19
 
20
- tool_config = pyproject_data.get("tool", {}).get("project_paths", {})
20
+ tool_config = pyproject_data.get("tool", {}).get("path_link", {})
21
21
  if not tool_config:
22
22
  return {}
23
23
 
@@ -82,3 +82,65 @@ def build_field_definitions(
82
82
  )
83
83
 
84
84
  return fields
85
+
86
+
87
+ def get_urls_from_pyproject() -> Dict[str, str]:
88
+ """Load URL variables from pyproject.toml [tool.path_link.urls] section."""
89
+ pyproject_path = Path.cwd() / "pyproject.toml"
90
+ if not pyproject_path.is_file():
91
+ return {}
92
+
93
+ with pyproject_path.open("rb") as f:
94
+ pyproject_data = toml_load(f)
95
+
96
+ tool_config = pyproject_data.get("tool", {}).get("path_link", {})
97
+ if not tool_config:
98
+ return {}
99
+
100
+ urls = tool_config.get("urls", {})
101
+
102
+ if not isinstance(urls, dict):
103
+ raise TypeError("`urls` must be a table in pyproject.toml")
104
+
105
+ return urls
106
+
107
+
108
+ def get_urls_from_dot_urls(path_to_config: Path) -> Dict[str, str]:
109
+ """Load URL variables from a .urls file (dotenv format)."""
110
+ if not path_to_config.is_file():
111
+ raise FileNotFoundError(f"Configuration file not found: {path_to_config}")
112
+
113
+ values = dotenv_values(path_to_config)
114
+
115
+ # Filter out None values which can occur with empty lines
116
+ return {k: v for k, v in values.items() if v is not None}
117
+
118
+
119
+ def get_urls_merged(dotenv_path: Optional[Path] = None) -> Dict[str, str]:
120
+ """
121
+ Load URLs from both pyproject.toml and .urls file with defined precedence.
122
+
123
+ Precedence: pyproject.toml > .urls file
124
+ Missing keys are merged; duplicates resolved by pyproject.toml.
125
+
126
+ Args:
127
+ dotenv_path: Optional path to .urls file (default: ./.urls)
128
+
129
+ Returns:
130
+ Merged dictionary of URL key-value pairs
131
+ """
132
+ # Start with dotenv values (lower priority)
133
+ urls = {}
134
+
135
+ # Load from .urls file if it exists
136
+ if dotenv_path is None:
137
+ dotenv_path = Path.cwd() / ".urls"
138
+
139
+ if dotenv_path.is_file():
140
+ urls = get_urls_from_dot_urls(dotenv_path)
141
+
142
+ # Override with pyproject.toml values (higher priority)
143
+ pyproject_urls = get_urls_from_pyproject()
144
+ urls.update(pyproject_urls)
145
+
146
+ return urls
@@ -0,0 +1,6 @@
1
+ """Built-in validators for common validation scenarios."""
2
+
3
+ from path_link.builtin_validators.strict import StrictPathValidator
4
+ from path_link.builtin_validators.sandbox import SandboxPathValidator
5
+
6
+ __all__ = ["StrictPathValidator", "SandboxPathValidator"]
@@ -3,10 +3,10 @@ from dataclasses import dataclass
3
3
  from pathlib import Path
4
4
  from typing import Iterable, TYPE_CHECKING
5
5
 
6
- from ..validation import Finding, Severity, ValidationResult
6
+ from path_link.validation import Finding, Severity, ValidationResult
7
7
 
8
8
  if TYPE_CHECKING:
9
- from ..model import _ProjectPathsBase
9
+ from path_link.model import _ProjectPathsBase
10
10
 
11
11
 
12
12
  @dataclass
@@ -3,10 +3,10 @@ from dataclasses import dataclass
3
3
  from pathlib import Path
4
4
  from typing import Iterable, TYPE_CHECKING
5
5
 
6
- from ..validation import Finding, Severity, ValidationResult
6
+ from path_link.validation import Finding, Severity, ValidationResult
7
7
 
8
8
  if TYPE_CHECKING:
9
- from ..model import _ProjectPathsBase
9
+ from path_link.model import _ProjectPathsBase
10
10
 
11
11
 
12
12
  @dataclass
@@ -1,4 +1,4 @@
1
- """Command-line interface for ptool-serena.
1
+ """Command-line interface for path-link.
2
2
 
3
3
  Provides three commands:
4
4
  1. print - Print resolved paths as JSON
@@ -12,9 +12,12 @@ import sys
12
12
  from pathlib import Path
13
13
  from typing import NoReturn
14
14
 
15
- from project_paths import ProjectPaths, write_dataclass_file, validate_or_raise
16
- from project_paths.builtin_validators import StrictPathValidator
17
- from project_paths.validation import PathValidationError
15
+ from path_link import ProjectPaths, write_dataclass_file, validate_or_raise
16
+ from path_link.builtin_validators import StrictPathValidator
17
+ from path_link.validation import PathValidationError
18
+ from path_link.url_factory import ProjectUrls
19
+ from path_link.url_model import ValidationMode
20
+ from path_link.url_static import write_url_dataclass_file
18
21
 
19
22
 
20
23
  def cmd_print(args: argparse.Namespace) -> int:
@@ -126,10 +129,97 @@ def cmd_gen_static(args: argparse.Namespace) -> int:
126
129
  return 1
127
130
 
128
131
 
132
+ def cmd_print_urls(args: argparse.Namespace) -> int:
133
+ """Print resolved URLs as JSON."""
134
+ try:
135
+ # Determine validation mode
136
+ mode = ValidationMode(args.mode.lower()) if hasattr(args, "mode") and args.mode else ValidationMode.LENIENT
137
+
138
+ # Load URLs based on source
139
+ if args.src == "pyproject":
140
+ urls = ProjectUrls.from_pyproject(mode=mode)
141
+ elif args.src == "dotenv":
142
+ config_file = args.config if hasattr(args, "config") and args.config else ".urls"
143
+ urls = ProjectUrls.from_config(config_file, mode=mode)
144
+ elif args.src == "all":
145
+ urls = ProjectUrls.from_merged(mode=mode)
146
+ else:
147
+ print(f"Unknown source: {args.src}", file=sys.stderr)
148
+ return 1
149
+
150
+ # Convert URLs to dict
151
+ urls_dict = urls.to_dict()
152
+
153
+ # Output based on format
154
+ if args.format == "json":
155
+ print(json.dumps(urls_dict, indent=2))
156
+ else: # table format
157
+ print(f"URLs (mode: {mode.value}, source: {args.src}):")
158
+ for key, value in sorted(urls_dict.items()):
159
+ print(f" {key}: {value}")
160
+
161
+ return 0
162
+
163
+ except Exception as e:
164
+ print(f"Error loading URLs: {e}", file=sys.stderr)
165
+ return 1
166
+
167
+
168
+ def cmd_validate_urls(args: argparse.Namespace) -> int:
169
+ """Validate URLs and report results."""
170
+ try:
171
+ # Determine validation mode
172
+ mode = ValidationMode(args.mode.lower()) if hasattr(args, "mode") and args.mode else ValidationMode.LENIENT
173
+
174
+ # Load URLs based on source
175
+ if args.src == "pyproject":
176
+ urls = ProjectUrls.from_pyproject(mode=mode)
177
+ elif args.src == "dotenv":
178
+ config_file = args.config if hasattr(args, "config") and args.config else ".urls"
179
+ urls = ProjectUrls.from_config(config_file, mode=mode)
180
+ elif args.src == "all":
181
+ urls = ProjectUrls.from_merged(mode=mode)
182
+ else:
183
+ print(f"Unknown source: {args.src}", file=sys.stderr)
184
+ return 1
185
+
186
+ # If we got here, all URLs are valid
187
+ urls_dict = urls.to_dict()
188
+ print(f"✅ All {len(urls_dict)} URLs valid (mode: {mode.value})")
189
+ return 0
190
+
191
+ except Exception as e:
192
+ print(f"❌ URL validation failed: {e}", file=sys.stderr)
193
+ return 1
194
+
195
+
196
+ def cmd_gen_static_urls(args: argparse.Namespace) -> int:
197
+ """Generate static URL dataclass file."""
198
+ try:
199
+ # Determine validation mode
200
+ mode = ValidationMode(args.mode.lower()) if hasattr(args, "mode") and args.mode else ValidationMode.LENIENT
201
+
202
+ # Determine output path
203
+ output_path = Path(args.output) if hasattr(args, "output") and args.output else None
204
+
205
+ # Generate static model
206
+ if output_path:
207
+ print(f"Generating static URL model at: {output_path} (mode: {mode.value})")
208
+ else:
209
+ print(f"Generating static URL model at default location (mode: {mode.value})")
210
+
211
+ write_url_dataclass_file(output_path=output_path, mode=mode)
212
+ return 0
213
+
214
+ except Exception as e:
215
+ print(f"Error generating static URL model: {e}", file=sys.stderr)
216
+ return 1
217
+
218
+
129
219
  def main() -> NoReturn:
130
220
  """Main entry point for ptool CLI."""
131
221
  parser = argparse.ArgumentParser(
132
- prog="ptool", description="Type-safe project path management tool"
222
+ prog="pathlink", description="Type-safe project path management tool"
133
223
  )
134
224
 
135
225
  subparsers = parser.add_subparsers(dest="command", help="Available commands")
@@ -181,6 +271,66 @@ def main() -> NoReturn:
181
271
  help="Output path for static model (default: src/project_paths/project_paths_static.py)",
182
272
  )
183
273
 
274
+ # print-urls command
275
+ print_urls_parser = subparsers.add_parser("print-urls", help="Print resolved URLs")
276
+ print_urls_parser.add_argument(
277
+ "--mode",
278
+ choices=["lenient", "strict"],
279
+ default="lenient",
280
+ help="Validation mode (default: lenient)",
281
+ )
282
+ print_urls_parser.add_argument(
283
+ "--format",
284
+ choices=["json", "table"],
285
+ default="json",
286
+ help="Output format (default: json)",
287
+ )
288
+ print_urls_parser.add_argument(
289
+ "--src",
290
+ choices=["pyproject", "dotenv", "all"],
291
+ default="all",
292
+ help="URL source (default: all - merged from both sources)",
293
+ )
294
+ print_urls_parser.add_argument(
295
+ "--config", type=str, help="Path to .urls config file (default: .urls)"
296
+ )
297
+
298
+ # validate-urls command
299
+ validate_urls_parser = subparsers.add_parser(
300
+ "validate-urls", help="Validate URLs and report results"
301
+ )
302
+ validate_urls_parser.add_argument(
303
+ "--mode",
304
+ choices=["lenient", "strict"],
305
+ default="lenient",
306
+ help="Validation mode (default: lenient)",
307
+ )
308
+ validate_urls_parser.add_argument(
309
+ "--src",
310
+ choices=["pyproject", "dotenv", "all"],
311
+ default="all",
312
+ help="URL source (default: all - merged from both sources)",
313
+ )
314
+ validate_urls_parser.add_argument(
315
+ "--config", type=str, help="Path to .urls config file (default: .urls)"
316
+ )
317
+
318
+ # gen-static-urls command
319
+ gen_static_urls_parser = subparsers.add_parser(
320
+ "gen-static-urls", help="Generate static URL dataclass file"
321
+ )
322
+ gen_static_urls_parser.add_argument(
323
+ "--mode",
324
+ choices=["lenient", "strict"],
325
+ default="lenient",
326
+ help="Validation mode (default: lenient)",
327
+ )
328
+ gen_static_urls_parser.add_argument(
329
+ "--output",
330
+ type=str,
331
+ help="Output path for static model (default: src/project_paths/project_urls_static.py)",
332
+ )
333
+
184
334
  args = parser.parse_args()
185
335
 
186
336
  # Dispatch to appropriate command handler
@@ -190,6 +340,12 @@ def main() -> NoReturn:
190
340
  exit_code = cmd_validate(args)
191
341
  elif args.command == "gen-static":
192
342
  exit_code = cmd_gen_static(args)
343
+ elif args.command == "print-urls":
344
+ exit_code = cmd_print_urls(args)
345
+ elif args.command == "validate-urls":
346
+ exit_code = cmd_validate_urls(args)
347
+ elif args.command == "gen-static-urls":
348
+ exit_code = cmd_gen_static_urls(args)
193
349
  else:
194
350
  parser.print_help()
195
351
  exit_code = 1
@@ -1,4 +1,4 @@
1
- # Assistant Context — ptool-serena v0.2.0
1
+ # Assistant Context — path-link v0.2.0
2
2
 
3
3
  **Last Updated:** 2025-10-10
4
4
  **Status:** Active (Production)
@@ -8,10 +8,10 @@
8
8
 
9
9
  ## Overview
10
10
 
11
- `ptool-serena` is a Python library for type-safe project path management using Pydantic models.
11
+ `path-link` is a Python library for type-safe project path management using Pydantic models.
12
12
 
13
13
  **Key Facts:**
14
- - **Package:** `ptool-serena` → imports as `project_paths`
14
+ - **Package:** `path-link` → imports as `project_paths`
15
15
  - **Pattern:** Dynamic Pydantic model creation via factory methods (v2 API)
16
16
  - **Tool:** `uv` for dependency management
17
17
  - **Python:** 3.11+
@@ -33,13 +33,13 @@
33
33
  uv pip install -e ".[test]"
34
34
 
35
35
  # One-liner smoke test (verify installation)
36
- uv run python -c "from project_paths import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()), 'paths loaded')"
36
+ uv run python -c "from path_link import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()), 'paths loaded')"
37
37
  ```
38
38
 
39
39
  ### 2. Basic Usage
40
40
 
41
41
  ```python
42
- from project_paths import ProjectPaths
42
+ from path_link import ProjectPaths
43
43
 
44
44
  # ✅ CORRECT: Use factory methods
45
45
  paths = ProjectPaths.from_pyproject() # Load from pyproject.toml
@@ -69,17 +69,17 @@ uv run pytest tests/test_validators.py # Specific file
69
69
  | Purpose | Command |
70
70
  |---------|---------|
71
71
  | **Install** | `uv pip install -e ".[test]"` |
72
- | **Smoke test** | `uv run python -c "from project_paths import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()))"` |
72
+ | **Smoke test** | `uv run python -c "from path_link import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()))"` |
73
73
  | **Run all tests** | `uv run pytest` |
74
74
  | **Coverage check** | `uv run pytest --cov=src --cov-report=term-missing:skip-covered` |
75
75
  | **Type check** | `uv run mypy src/` |
76
76
  | **Lint** | `uv run ruff check .` |
77
77
  | **Format** | `uv run ruff format .` |
78
- | **Regenerate static model** | `uv run python -c "from project_paths import write_dataclass_file; write_dataclass_file()"` |
78
+ | **Regenerate static model** | `uv run python -c "from path_link import write_dataclass_file; write_dataclass_file()"` |
79
79
  | **Verify static sync** | `git diff --exit-code src/project_paths/project_paths_static.py` |
80
- | **Access AI guidelines** | `uv run python -c "from project_paths import get_ai_guidelines; print(get_ai_guidelines()[:200])"` |
81
- | **Access dev guide** | `uv run python -c "from project_paths import get_developer_guide; print(get_developer_guide()[:200])"` |
82
- | **Access metadata** | `uv run python -c "import json; from project_paths import get_metadata; print(json.loads(get_metadata())['version'])"` |
80
+ | **Access AI guidelines** | `uv run python -c "from path_link import get_ai_guidelines; print(get_ai_guidelines()[:200])"` |
81
+ | **Access dev guide** | `uv run python -c "from path_link import get_developer_guide; print(get_developer_guide()[:200])"` |
82
+ | **Access metadata** | `uv run python -c "import json; from path_link import get_metadata; print(json.loads(get_metadata())['version'])"` |
83
83
  | **Run example** | `uv run python examples/minimal_project/src/main.py` |
84
84
 
85
85
  ---
@@ -103,8 +103,8 @@ uv run pytest tests/test_validators.py # Specific file
103
103
 
104
104
  - **Validate paths:**
105
105
  ```python
106
- from project_paths import validate_or_raise
107
- from project_paths.builtin_validators import StrictPathValidator
106
+ from path_link import validate_or_raise
107
+ from path_link.builtin_validators import StrictPathValidator
108
108
 
109
109
  validator = StrictPathValidator(
110
110
  required=["config_dir", "data_dir"],
@@ -157,11 +157,11 @@ paths = ProjectPaths() # Raises NotImplementedError by design
157
157
 
158
158
  ## Static Model Sync
159
159
 
160
- **When to regenerate:** After any change to `[tool.project_paths]` in `pyproject.toml`
160
+ **When to regenerate:** After any change to `[tool.path_link]` in `pyproject.toml`
161
161
 
162
162
  ```bash
163
163
  # 1. Regenerate static model
164
- uv run python -c "from project_paths import write_dataclass_file; write_dataclass_file()"
164
+ uv run python -c "from path_link import write_dataclass_file; write_dataclass_file()"
165
165
 
166
166
  # 2. Verify no drift (CI check)
167
167
  git diff --exit-code src/project_paths/project_paths_static.py || \
@@ -212,7 +212,7 @@ except FileExistsError:
212
212
  **`StrictPathValidator(allow_symlinks=False)` blocks both live and dangling symlinks by default.**
213
213
 
214
214
  ```python
215
- from project_paths.builtin_validators import StrictPathValidator
215
+ from path_link.builtin_validators import StrictPathValidator
216
216
 
217
217
  # Blocks symlinks (default behavior)
218
218
  validator = StrictPathValidator(
@@ -239,14 +239,14 @@ validator_permissive = StrictPathValidator(
239
239
  ### Basic Validation
240
240
 
241
241
  ```python
242
- from project_paths import (
242
+ from path_link import (
243
243
  ProjectPaths,
244
244
  validate_or_raise,
245
245
  ValidationResult,
246
246
  Finding,
247
247
  Severity
248
248
  )
249
- from project_paths.builtin_validators import StrictPathValidator
249
+ from path_link.builtin_validators import StrictPathValidator
250
250
 
251
251
  # Load paths
252
252
  paths = ProjectPaths.from_pyproject()
@@ -289,7 +289,7 @@ else:
289
289
 
290
290
  ```python
291
291
  from dataclasses import dataclass
292
- from project_paths import ValidationResult, Finding, Severity
292
+ from path_link import ValidationResult, Finding, Severity
293
293
 
294
294
  @dataclass
295
295
  class MyValidator:
@@ -325,7 +325,7 @@ validate_or_raise(paths, validator)
325
325
  The package includes three functions to access documentation programmatically, even in airgapped or offline environments. This is especially useful for AI assistants helping users with the package.
326
326
 
327
327
  ```python
328
- from project_paths import get_ai_guidelines, get_developer_guide, get_metadata
328
+ from path_link import get_ai_guidelines, get_developer_guide, get_metadata
329
329
  import json
330
330
 
331
331
  # Get AI assistant guidelines (this file - comprehensive usage patterns)
@@ -363,13 +363,13 @@ print(f"CLI Commands: {len(metadata['cli_commands'])} available")
363
363
  uv run python -c "import sys; print(sys.version)"
364
364
 
365
365
  # 2. Verify editable install
366
- uv pip list | grep ptool-serena # Should show editable install
366
+ uv pip list | grep path-link # Should show editable install
367
367
 
368
368
  # 3. Reinstall if needed
369
369
  uv pip install -e ".[test]"
370
370
 
371
371
  # 4. Test import
372
- uv run python -c "import project_paths; print('✅ Import OK')"
372
+ uv run python -c "import path_link; print('✅ Import OK')"
373
373
  ```
374
374
 
375
375
  ### Test Failures
@@ -379,7 +379,7 @@ uv run python -c "import project_paths; print('✅ Import OK')"
379
379
  uv run pytest tests/test_static_model_equivalence.py -v
380
380
 
381
381
  # 2. If failing, regenerate static model
382
- uv run python -c "from project_paths import write_dataclass_file; write_dataclass_file()"
382
+ uv run python -c "from path_link import write_dataclass_file; write_dataclass_file()"
383
383
 
384
384
  # 3. Re-run all tests
385
385
  uv run pytest -v
@@ -406,7 +406,7 @@ paths = ProjectPaths.from_pyproject()
406
406
  **Fix:**
407
407
  ```bash
408
408
  # Regenerate in current environment
409
- uv run python -c "from project_paths import write_dataclass_file; write_dataclass_file()"
409
+ uv run python -c "from path_link import write_dataclass_file; write_dataclass_file()"
410
410
 
411
411
  # Verify fix
412
412
  uv run pytest tests/test_static_model_equivalence.py -v
@@ -465,7 +465,7 @@ When working with this codebase, AI assistants MUST:
465
465
 
466
466
  1. **Always use factory methods** — Never call `ProjectPaths()` directly
467
467
  2. **Keep static model in sync** — Regenerate after `pyproject.toml` changes
468
- 3. **Follow `src` layout** — Use absolute imports: `from project_paths.model import ...`
468
+ 3. **Follow `src` layout** — Use absolute imports: `from path_link.model import ...`
469
469
  4. **Refer to this document first** — Before any path-related task
470
470
  5. **Verify changes** — Run tests after modifications: `uv run pytest`
471
471
  6. **Use atomic operations** — Follow TOCTOU prevention patterns
@@ -474,8 +474,8 @@ When working with this codebase, AI assistants MUST:
474
474
  ### Example Pattern
475
475
 
476
476
  ```python
477
- from project_paths import ProjectPaths, validate_or_raise
478
- from project_paths.builtin_validators import StrictPathValidator
477
+ from path_link import ProjectPaths, validate_or_raise
478
+ from path_link.builtin_validators import StrictPathValidator
479
479
 
480
480
  # 1. Load paths
481
481
  paths = ProjectPaths.from_pyproject()
@@ -517,12 +517,12 @@ except FileExistsError:
517
517
  ### pyproject.toml
518
518
 
519
519
  ```toml
520
- [tool.project_paths.paths]
520
+ [tool.path_link.paths]
521
521
  config_dir = "config"
522
522
  data_dir = "data"
523
523
  logs_dir = "logs"
524
524
 
525
- [tool.project_paths.files]
525
+ [tool.path_link.files]
526
526
  settings_file = "config/settings.json"
527
527
  log_file = "logs/app.log"
528
528
  ```
@@ -569,7 +569,7 @@ user_data=~/projects/${PROJECT_NAME}/data
569
569
 
570
570
  **Example pyproject.toml:**
571
571
  ```toml
572
- [tool.project_paths.paths]
572
+ [tool.path_link.paths]
573
573
  data_dir = "${DATA_ROOT}/app_data"
574
574
  config_dir = "~/.config/myapp"
575
575
  ```
@@ -609,13 +609,13 @@ If you encounter issues, run these commands in order:
609
609
  uv run python -c "import sys; print('Python:', sys.version)" # Should be 3.11+
610
610
 
611
611
  # 2. Check editable install
612
- uv pip list | grep ptool-serena # Should show path with "(editable)"
612
+ uv pip list | grep path-link # Should show path with "(editable)"
613
613
 
614
614
  # 3. Test import
615
- uv run python -c "import project_paths; print('✅ Import OK')"
615
+ uv run python -c "import path_link; print('✅ Import OK')"
616
616
 
617
617
  # 4. Run smoke test
618
- uv run python -c "from project_paths import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()), 'paths loaded')"
618
+ uv run python -c "from path_link import ProjectPaths; p=ProjectPaths.from_pyproject(); print('✅ OK:', len(p.to_dict()), 'paths loaded')"
619
619
 
620
620
  # 5. Check config files
621
621
  ls -l pyproject.toml .paths 2>/dev/null
@@ -649,7 +649,7 @@ git diff src/project_paths/project_paths_static.py
649
649
 
650
650
  ## Summary
651
651
 
652
- **ptool-serena (v0.2.0)** provides type-safe, validated path management for Python projects.
652
+ **path-link (v0.2.0)** provides type-safe, validated path management for Python projects.
653
653
 
654
654
  **Core Principles:**
655
655
  - Factory methods only (v2 API)
@@ -661,7 +661,7 @@ git diff src/project_paths/project_paths_static.py
661
661
 
662
662
  ---
663
663
 
664
- **Project:** ptool-serena v0.2.0
664
+ **Project:** path-link v0.2.0
665
665
  **Python:** 3.11+
666
666
  **License:** MIT
667
667
  **Package Manager:** uv