pi-python-helper 0.1.0

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,60 @@
1
+ # Changelog
2
+
3
+ All notable changes are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project follows
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html); the `0.y.z` series
6
+ does not guarantee a stable public tool schema.
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0] - 2026-09-21
11
+
12
+ ### Added
13
+
14
+ - `py_project_inspect` reports environment conformance: the declared, locked, and actually-installed versions are compared in one place.
15
+ - `src/project/installed.ts` reads installed distributions from `.venv` without running Python, using only the bounded `METADATA` header block (~3 ms for 22 packages).
16
+ - `src/project/conformance.ts` classifies lock-versus-installed drift as version mismatch, missing required package, absent or non-editable project, untracked package, or an environment no lockfile describes.
17
+ - `py_validation_bundle` gained a conformance check: a passing test run against versions the lockfile does not describe fails the gate, and an unverifiable environment fails it too.
18
+ - `py_environment` reports the resolved interpreter, virtual-environment state, project root, and uv/tool availability.
19
+ - `py_project_inspect` analyses `pyproject.toml` and `uv.lock`, including layout, dependency groups, tool configuration, and lockfile drift.
20
+ - `py_dependency_plan` compares `ast`-scanned imports with declared dependencies, dev groups, extras, and `uv.lock`.
21
+ - `py_test_select` selects focused pytest targets from changed files using pytest naming conventions.
22
+ - `py_test` previews or runs `uv run --frozen pytest` and summarises counts, failing node ids, and the first project frame.
23
+ - `py_failure_diagnose` classifies the first actionable cause in Python, pytest, or uv output by position in the output.
24
+ - `py_sync` previews or runs `uv lock --check` and `uv sync --frozen`.
25
+ - `py_validation_bundle` chains lock check, sync, pytest, environment conformance, and a stale-artifact check into one evidence-oriented gate.
26
+ - `py_tdd_checkpoint` and `py_completion_evidence` provide conservative development and completion gates.
27
+ - `/py-status` reports a concise interpreter and project status.
28
+ - `helpers/scan_project.py` provides read-only `ast` import scanning and `tomllib` manifest parsing.
29
+ - Risk classification for shell commands, including compound-command segment inheritance and pipe-to-shell detection.
30
+ - `npm run test:e2e` verifies the scanner, pytest parser, failure diagnoser, and uv command builders against a real uv project.
31
+ - `docs/tools.md`, a generated tool reference, and `docs/api-surface.json`, a structure-only snapshot of every tool's parameters and return payload.
32
+ - `test/api-surface.test.ts` guards the public surface: the exact tool set, the parameter schemas, the captured return shapes, and the freshness of the reference document.
33
+ - `CONTRIBUTING.md` and a release workflow that publishes to npm with provenance after verifying the tag matches `package.json`.
34
+ - Tests for the environment probe (`test/environment.test.ts`) and the scanner CLI contract (`test/helper-cli.test.ts`), and a Python 3.10–3.13 CI matrix.
35
+
36
+ ### Changed
37
+
38
+ - `py_environment` resolves tool availability from the project environment, PATH, and `uv.lock` instead of running `--version` for every tool. It went from ~210 ms to ~64 ms and now reports the *project's* version from the lockfile instead of the host's.
39
+ - `helpers/scan_project.py` accepts `--mode`, `--root`, `--max-files`, `--help`, and `--version`, validates the requested sections, and separates diagnostics (stderr) from results (stdout). Exit codes are now documented and stable: 0 success, 1 failure, 2 invalid input.
40
+ - The scanner emits `scannerVersion` and the extension refuses to interpret a document from an unknown protocol version.
41
+ - `mode` accepts a comma-separated section list, so a caller can request `environment,manifest` without running the import scan.
42
+ - `tsconfig.json` enables `noUnusedLocals`, `noUnusedParameters`, `noImplicitOverride`, and `noFallthroughCasesInSwitch`.
43
+
44
+ ### Fixed
45
+
46
+ - A directory under `src/` is only reported as an importable module when it actually contains Python code. A TypeScript tree under `src/` was previously listed as a Python package's modules.
47
+ - Removed dead declarations in `src/build/failure.ts` and an unused import in `src/project/paths.ts`, both surfaced by the stricter compiler settings.
48
+ - `helpers/scan_project.py` no longer aborts the whole scan when a directory cannot be stat-ed. Layout detection, legacy manifest probing, and requirement discovery now degrade to "absent" instead of raising `PermissionError` (reproduced against `/tmp`, which contains a root-owned sibling).
49
+ - An unexpected scanner exception is now reported as structured JSON instead of a bare traceback on stderr.
50
+ - `py_failure_diagnose` now recognises pytest `--tb=short` frames (`path:line: in func`) and `E `-prefixed exception lines, which previously left real failures unclassified with no project frame.
51
+ - Failure diagnosis now selects the cause that appears first in the output instead of using a fixed pattern priority.
52
+ - `curl ... | sh` is classified as irreversible; it was previously masked by pipe-based segment splitting.
53
+
54
+ ### Notes
55
+
56
+ - Package manager support is intentionally limited to uv; lint and type diagnostics are delegated to other extensions.
57
+ - `TYPE_CHECKING`-guarded imports are excluded from runtime dependency checks to avoid false positives.
58
+ - Unused-dependency reporting is opt-in because runtime plugins and console tools are not imported.
59
+ - Conformance compares only names that are provably required: declarations and lock edges with no marker, reached from the root project or from an installed package. Marker-guarded entries (`colorama` on Linux, `tomli` before 3.11) are counted as conditional instead of reported as missing, and interpreter-seeded distributions such as pip are excluded.
60
+ - The stale-installed-package mtime heuristic was replaced by the structural `PROJECT_INSTALLED_NOT_EDITABLE` check; coverage staleness remains the only mtime-based artifact check.
@@ -0,0 +1,77 @@
1
+ # 기여 가이드 (Contributing)
2
+
3
+ ## 시작하기 (Getting started)
4
+
5
+ ```bash
6
+ npm install
7
+ npm test
8
+ npm run typecheck
9
+ npm run check # 테스트 + 타입 + 포맷 + 패키지 내용 검사
10
+ ```
11
+
12
+ 네트워크와 uv가 있는 환경에서는 실제 uv 프로젝트를 만들어 전 경로를 검증할 수 있습니다.
13
+
14
+ ```bash
15
+ npm run test:e2e
16
+ ```
17
+
18
+ 확장이 실제로 로드되는지 확인:
19
+
20
+ ```bash
21
+ pi -e ./extensions/index.ts --list-models
22
+ ```
23
+
24
+ ## 개발 규칙 (Development rules)
25
+
26
+ 자세한 구현 규칙은 `AGENTS.md`를 참고하세요. 요약:
27
+
28
+ - `extensions/`는 도구 **등록**만 담당하고, 로직은 `src/`의 순수 함수로 두세요. `extensions/index.ts`를 단일 대형 파일로 키우지 마세요.
29
+ - 사용자 입력을 쉘 문자열로 보간하지 말고 항상 인자 배열로 전달하세요. 모든 서브프로세스는 타임아웃, `AbortSignal`, 출력 크기 제한을 적용해야 합니다.
30
+ - 이 패키지의 도구는 프로젝트 파일을 쓰지 않습니다. 상태를 바꾸는 명령(`uv sync`/`uv lock`)은 `execute: true` 옵트인을 요구하세요.
31
+ - `helpers/scan_project.py`는 읽기 전용을 유지하세요. 파일시스템 접근은 `safe_is_file`/`safe_is_dir`/`safe_iterdir`를 통해서만 하고, 한 디렉터리의 `PermissionError`가 전체 스캔을 중단시켜서는 안 됩니다.
32
+ - 도구 판정을 느슨하게 만들지 말고 **증명 범위를 좁히세요**. 불확실한 항목은 `counts`에 별도 집계하고 `notes`로 공개하는 편이 경고를 삭제하는 것보다 낫습니다.
33
+ - 새 도구를 추가하기 전에 기존 도구에 파라미터로 흡수할 수 있는지 먼저 검토하세요. 도구 표면적은 의도적으로 작게 유지합니다.
34
+
35
+ ## 테스트 요구사항 (Testing requirements)
36
+
37
+ - 모든 파서, 정규화기, 안전 규칙, 순수 생성기 변경에 단위 테스트를 작성하세요.
38
+ - `helpers/scan_project.py`의 계약(요청/결과 문서, 종료 코드)을 바꾸면 `test/helper-cli.test.ts`와 `test/scanner-integration.test.ts`를 함께 갱신하세요. 스캐너 프로토콜을 깨는 변경은 `SCANNER_VERSION`과 `SUPPORTED_SCANNER_VERSION`을 함께 올려야 합니다.
39
+ - 환경 정합성 로직을 바꾸면 `test/conformance.test.ts`(순수 비교)와 `test/installed.test.ts`(파일시스템 리더)를 모두 갱신하고, 마커 조건부 항목에 대한 회귀 테스트를 남기세요.
40
+ - 커밋 전 `npm test`, `npm run typecheck`, `npm run check`를 실행하세요. Python이 없는 환경이라는 이유로 검증 강도를 약화하지 말고 해당 테스트를 `t.skip()`으로 건너뛰세요.
41
+
42
+ ## 도구 레퍼런스 (Tool reference)
43
+
44
+ `docs/tools.md`는 생성 파일입니다. 도구의 이름, 설명, `promptSnippet`, `promptGuidelines`, 파라미터 스키마를 변경하면 반드시 다시 생성하세요.
45
+
46
+ ```bash
47
+ npm run docs
48
+ ```
49
+
50
+ - `docs/api-surface.json` — 반환 형태 스냅샷. 구조만 기록하고 값·경로·버전·소요시간은 제외하므로 머신과 릴리스 간에 안정적입니다.
51
+ - `docs/tools.md` — 위 스냅샷과 실시간 등록 정보로 렌더링한 사람이 읽는 레퍼런스.
52
+ - 스냅샷 캡처는 python3와 uv가 필요합니다. 둘 중 하나라도 없으면 스냅샷은 도구 목록과 파라미터만 담고 반환 형태는 비워둡니다(경고 출력). CI의 `python-scanner` job이 두 가지를 모두 갖춘 상태에서 반환 형태를 검증합니다.
53
+
54
+ `test/api-surface.test.ts`가 다음을 강제합니다.
55
+
56
+ 1. 등록된 도구 집합이 명시적 목록과 일치
57
+ 2. 파라미터 스키마가 스냅샷과 일치
58
+ 3. `docs/tools.md`가 최신
59
+ 4. 캡처한 반환 형태가 스냅샷과 일치
60
+
61
+ 도구를 추가·이름 변경·제거하는 것은 에이전트 프롬프트와 레퍼런스에 대한 파괴적 변경이므로, 테스트의 `EXPECTED_TOOLS` 목록도 함께 수정해야 합니다.
62
+
63
+ ## 커밋과 릴리스 (Commits and releases)
64
+
65
+ `feat:`, `fix:`, `test:`, `docs:`, `chore:` 등 Conventional Commits를 사용하세요.
66
+
67
+ 릴리스 순서:
68
+
69
+ 1. `package.json`의 `version`을 올립니다.
70
+ 2. `CHANGELOG.md`의 `[Unreleased]` 항목을 새 버전 섹션으로 옮기고 날짜를 기록합니다.
71
+ 3. `v<version>` 태그를 푸시합니다. `.github/workflows/publish.yml`이 태그와 `package.json` 버전이 일치하는지 확인한 뒤 npm provenance와 함께 배포합니다.
72
+
73
+ `node_modules`, `.venv`, `__pycache__`, `*.pyc`, `.coverage`, 로그, 비밀 정보는 커밋하지 마세요.
74
+
75
+ ## 보안 (Security)
76
+
77
+ 취약점은 공개 이슈가 아니라 `SECURITY.md`에 안내된 비공개 채널로 제보해 주세요.
package/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ Copyright 2026 wkqco
6
+
7
+ Licensed under the Apache License, Version 2.0 (the "License");
8
+ you may not use this file except in compliance with the License.
9
+ You may obtain a copy of the License at
10
+
11
+ http://www.apache.org/licenses/LICENSE-2.0
12
+
13
+ Unless required by applicable law or agreed to in writing, software
14
+ distributed under the License is distributed on an "AS IS" BASIS,
15
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ See the License for the specific language governing permissions and
17
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # pi-python-helper
2
+
3
+ [pi 코딩 에이전트](https://github.com/badlogic/pi-mono)를 위한 uv 기반 Python 개발 도구 확장 패키지입니다.
4
+
5
+ 패키지 관리자는 **uv 단일 지원**이며, 린트/타입 진단(LSP)은 의도적으로 다루지 않습니다. 해당 영역은 `@narumitw/pi-python-lsp` 같은 별도 확장에 위임합니다.
6
+
7
+ ## 현재 지원 현황
8
+
9
+ 버전 `0.1.0`은 `python-development` 스킬에 정의된 범위 제한(bounded) 검사, 품질 게이트, 명시적 옵트인 기반 명령 실행 도구를 제공합니다.
10
+
11
+ ### 환경 및 프로젝트 검사 (Environment & Project Inspection)
12
+
13
+ - `py_environment` — 활성 인터프리터(`python3`/`python`), 버전, 실행 파일 경로, `sys.prefix` vs `base_prefix`, `VIRTUAL_ENV`/`CONDA_PREFIX`, 프로젝트 루트, `.venv` 존재 여부, `uv`/`ruff`/`mypy`/`ty`/`pyright`/`pytest`/`pre-commit` 가용성
14
+ - `py_project_inspect` — `pyproject.toml`과 `uv.lock` 파싱, src/flat 레이아웃, importable 모듈, 의존성 그룹, 엔트리포인트, 빌드 백엔드, `[tool.*]` 설정, **lockfile 드리프트**(requires-python 불일치, lock에 없는 선언, 스펙 미충족 버전, `.gitignore` 누락, 레거시 `setup.py`/`requirements*.txt` 중복), 그리고 **환경 정합성**(선언 ↔ uv.lock ↔ `.venv` 실제 설치본)
15
+
16
+ ### 의존성 분석 (Dependency Analysis)
17
+
18
+ - `py_dependency_plan` — Python `ast`로 실제 import를 스캔하여 선언된 의존성과 비교합니다. `sys.stdlib_module_names`로 표준 라이브러리를 제외하고, import 이름과 배포 이름의 차이(`PIL`↔`pillow`, `yaml`↔`PyYAML`)를 정적 별칭 테이블과 `importlib.metadata.packages_distributions()`로 해석합니다. 판정 항목:
19
+ - 선언되지 않은 import (`UNDECLARED_IMPORT`)
20
+ - `[project] dependencies`가 아니라 dev 그룹/extra에만 선언되었는데 프로덕션 코드가 import (`RUNTIME_DEPENDENCY_IN_DEV_GROUP`)
21
+ - `TYPE_CHECKING` 블록 전용 import (`UNDECLARED_TYPE_ONLY_IMPORT` — 런타임 의존성으로 오탐하지 않음)
22
+ - `uv.lock` 드리프트 (`LOCKFILE_DRIFT`)
23
+ - `includeUnused=true`일 때만, 콘솔 전용 도구를 제외한 미사용 선언 보고
24
+
25
+ ### 테스트 실행 및 선별 (Test Selection & Execution)
26
+
27
+ - `py_test_select` — pytest 규약(`tests/`, `test_*.py`, `*_test.py`, `conftest.py`)과 토큰 중복으로 변경 파일과 연관된 테스트 파일을 선별합니다. 매칭 실패 시 전체 스위트를 범위로 되돌리고 그 사실을 명시합니다.
28
+ - `py_test` — `uv run --frozen pytest` 미리보기 또는 실행. `--lf`(직전 실패만), `-k`, `--maxfail` 지원. pytest 요약 라인을 파싱하여 passed/failed/errors/skipped/xfailed/deselected/warning 카운트와 실패 노드 ID를 반환하고, 요약이 없는 실행은 통과로 간주하지 않습니다.
29
+ - `py_failure_diagnose` — 제한된 출력에서 **출력상 가장 먼저 등장하는** 원인을 선택합니다. `traceback` 프레임을 `site-packages`/표준 라이브러리와 프로젝트 코드로 분리하여 마지막 프로젝트 프레임을 지목합니다.
30
+
31
+ ### 게이트 및 검증 (Gates & Validation)
32
+
33
+ - `py_sync` — `uv lock --check` 또는 `uv sync --frozen` 미리보기/실행. 실행은 명시적 `execute: true` 필요
34
+ - `py_validation_bundle` — `uv lock --check` → `uv sync --frozen` → `pytest` → 환경 정합성 → 오래된 아티팩트 검사를 하나의 증거 지향 시퀀스로 미리보기/실행
35
+ - `py_tdd_checkpoint` — 프로덕션 `.py` 변경에 대응하는 테스트 변경이 있는지 확인
36
+ - `py_completion_evidence` — 환경 동기화와 테스트가 실제로 실행·성공했는지에 대한 보수적 완료 판정
37
+
38
+ ### 대화형 명령어 (Interactive Commands)
39
+
40
+ - `/py-status` — 간결한 인터프리터/uv/프로젝트 상태 알림
41
+
42
+ ## 안전 모델 (Safety model)
43
+
44
+ ROS 2와 달리 Python에는 위험을 결정론적으로 알려주는 토픽 이름이 없습니다. 따라서 위험은 **명령 텍스트 자체**에서 분류하며, 복합 명령(`&&`, `||`, `;`, `|`)은 각 세그먼트 중 가장 높은 위험을 상속합니다.
45
+
46
+ - **되돌릴 수 없음(irreversible)**: `uv publish`/`twine upload`, `git push --force`, `git reset --hard`/`git clean -fd`, `alembic downgrade`, `rm -rf`, `conda env remove`, `curl ... | sh`
47
+ - **상태 변경(mutating)**: `uv add/remove/sync/lock`, `pip install/uninstall`, `git commit/push`, 마이그레이션 적용
48
+ - **읽기 전용(read)**: `uv lock --check`, `uv sync --dry-run`, `pytest`, `ruff check --diff`, `git diff/status/log`, `python -c`
49
+
50
+ `py_sync`와 `py_validation_bundle`은 `execute: true`가 명시적으로 전달되기 전까지 명령을 실행하지 않고 미리보기만 반환합니다. 이 패키지의 어떤 도구도 소스 파일을 쓰지 않습니다.
51
+
52
+ ## 오래된 아티팩트 탐지 (Stale artifact detection)
53
+
54
+ Python은 바이트코드를 자동 무효화하고 pytest는 아무것도 설치하지 않으므로 남는 위험은 하나입니다.
55
+
56
+ - `STALE_COVERAGE_DATA` — `.coverage`/`coverage.xml`이 현재 소스보다 오래됨 → 커버리지 수치를 근거로 쓸 수 없음
57
+
58
+ 프로젝트 자체가 오래된 복사본으로 설치되었는지는 mtime 비교가 아니라 `PROJECT_INSTALLED_NOT_EDITABLE` 구조적 검사가 담당합니다.
59
+
60
+ ## 환경 정합성 검사 (Environment conformance)
61
+
62
+ 세 개의 진실 원천을 비교합니다: `pyproject.toml`의 선언, `uv.lock`의 해석 결과, `.venv`에 실제로 설치된 배포판.
63
+
64
+ 설치 버전은 Python을 실행하지 않고 `site-packages/<name>-<version>.dist-info/METADATA`의 헤더 블록(최대 8KB)만 읽어 얻습니다. 22개 패키지 기준 **약 3ms**이며 서브프로세스를 띄우지 않습니다.
65
+
66
+ | 코드 | 의미 |
67
+ |---|---|
68
+ | `INSTALLED_VERSION_MISMATCH` | lock의 버전과 설치된 버전이 다름 — `uv add`/`uv lock` 후 `uv sync`를 잊은 상태. `uv lock --check`는 이걸 **잡지 못합니다**(락은 최신) |
69
+ | `INSTALLED_PACKAGE_MISSING` | 무조건 필요한 패키지가 `.venv`에 없음 |
70
+ | `PROJECT_NOT_INSTALLED` | lock이 editable 설치를 기대하는데 프로젝트가 `.venv`에 없음(빌드 실패 포함). 테스트가 프로젝트를 import할 수 없음 |
71
+ | `PROJECT_INSTALLED_NOT_EDITABLE` | 프로젝트가 live link가 아니라 **복사본**으로 설치됨 → 테스트가 오래된 스냅샷을 import |
72
+ | `INSTALLED_PACKAGE_UNTRACKED` | `.venv`에 있지만 lock에 없는 패키지 (예: `uv pip install` 잔여물) |
73
+ | `INSTALLED_ENVIRONMENT_INDEPENDENT` | 설치본 대부분이 lock에 없음 — 이 `.venv`는 uv가 이 프로젝트용으로 만든 것이 아님 |
74
+
75
+ ### 오탐 억제 (False-positive control)
76
+
77
+ - **조건부 항목**: `colorama`(`sys_platform == 'win32'`), `tomli`(`python_version < '3.11'`) 같은 항목은 lock에 있어도 해당 플랫폼에 설치되지 않는 것이 정상입니다. `uv.lock`의 각 의존성 엣지에 기록된 마커를 읽어 **무조건 필요하다고 증명된 이름만** 누락으로 보고합니다. 나머지는 `counts.conditional`과 `CONDITIONAL_PACKAGES_ABSENT` 노트로 집계합니다.
78
+ - **설치되지 않은 패키지의 의존성**은 required로 승격하지 않습니다(win32 전용 브랜치 등).
79
+ - **부트스트랩 배포판**(pip/setuptools/wheel 등)은 비교에서 제외합니다.
80
+ - **선택적 extra**는 `uv sync`가 설치하지 않으므로 required 집합에 넣지 않습니다. `[project] dependencies`와 기본 `dev` 그룹만 포함합니다.
81
+ - 검증 불가 상태(venv 없음, lock 없음, 스캔 잘림)는 `verdict: 'unverifiable'`로 반환하며 **일치한다고 주장하지 않습니다**.
82
+
83
+ `py_validation_bundle`은 정합성이 `consistent`일 때만 통과합니다. `drifted`와 `unverifiable`은 모두 게이트 실패입니다 — lock이 기술하지 않는 버전으로 통과한 테스트는 증거가 아니기 때문입니다.
84
+
85
+ ## 개발용 설치 (Install for development)
86
+
87
+ ```bash
88
+ pi -e /absolute/path/to/pi-python-helper
89
+ ```
90
+
91
+ 프로젝트 로컬 패키지로 사용하려면 `.pi/settings.json`에 경로를 추가하거나 npm 패키지를 설치합니다.
92
+
93
+ ```bash
94
+ pi install npm:pi-python-helper@latest
95
+ ```
96
+
97
+ ## 개발 및 기여 (Development)
98
+
99
+ ```bash
100
+ npm install
101
+ npm test
102
+ npm run typecheck
103
+ # 또는 전체 검사 실행
104
+ npm run check
105
+ ```
106
+
107
+ 네트워크와 uv가 있는 환경에서는 실제 uv 프로젝트를 생성해 전 경로를 검증하는 e2e 테스트를 실행할 수 있습니다:
108
+
109
+ ```bash
110
+ npm run test:e2e
111
+ ```
112
+
113
+ 도구의 공개 표면(이름·파라미터·반환 형태)을 변경하면 레퍼런스 문서를 다시 생성해야 합니다:
114
+
115
+ ```bash
116
+ npm run docs # docs/tools.md + docs/api-surface.json 재생성
117
+ npm run docs:check # 문서가 최신인지만 확인
118
+ ```
119
+
120
+ `docs/tools.md`는 생성 파일이므로 직접 편집하지 마세요. `npm test`가 도구 집합·파라미터 스키마·반환 형태·문서 최신성을 모두 검증하며, 문서가 오래되면 테스트가 실패합니다.
121
+
122
+ 이 확장은 로드 시 Python이나 uv가 설치되어 있을 필요가 없습니다. Python 도구는 해석기나 uv를 사용할 수 없을 때 예외를 던지지 않고 구조화된 진단 오류를 반환합니다.
123
+
124
+ 분석은 `helpers/scan_project.py`에 위임합니다. 이 스크립트는 stdin으로 JSON 요청을 받아 stdout으로 JSON을 출력하며 프로젝트를 수정하지 않습니다. import 스캔에는 `ast`, 매니페스트 파싱에는 `tomllib`(Python 3.11+) 또는 `tomli`가 필요하고, 둘 다 없으면 매니페스트 분석이 저하된 상태로 동작함을 명시적으로 경고합니다. 선언된 버전 제약과 `uv.lock`의 버전을 비교하는 기능은 분석 인터프리터의 `packaging`을 사용하며, 없으면 `SPECIFIER_CHECK_UNAVAILABLE` 노트를 남기고 이름 대조만 수행합니다.
125
+
126
+ 스캐너는 독립 실행도 가능합니다:
127
+
128
+ ```bash
129
+ python3 helpers/scan_project.py --help
130
+ python3 helpers/scan_project.py --mode environment,manifest --root . </dev/null
131
+ ```
132
+
133
+ 종료 코드는 `0` 성공, `1` 예상외 실패, `2` 잘못된 입력입니다. 결과는 stdout(JSON 문서 하나), 진단 메시지는 stderr로 분리됩니다.
134
+
135
+ ## 성능 특성 (Measured cost)
136
+
137
+ 측정 환경: Linux, Python 3.12, uv 0.12.
138
+
139
+ | 작업 | 비용 |
140
+ |---|---|
141
+ | `py_environment` 전체 | ~64 ms (스캐너 1회 + `uv --version` 1회) |
142
+ | 도구 가용성 판정 | ~2.3 ms (프로세스 실행 없음) |
143
+ | `py_project_inspect` 매니페스트 스캔 | ~31 ms |
144
+ | import 스캔 (`ast`) | ~76 ms (`py_dependency_plan`에만 사용) |
145
+ | 설치본 스캔 | ~3 ms / 22개 패키지 (`METADATA` 헤더만 읽음) |
146
+
147
+ 도구 존재 여부는 `--version`을 실행해서 확인하지 않습니다. 그 방식은 도구당 프로세스 1회(pytest만 154 ms)를 썼고 호스트 버전을 프로젝트 버전으로 잘못 보고했습니다. 대신 `.venv/bin`과 PATH를 파일시스템으로 탐색하고 버전은 `uv.lock`에서 가져옵니다.
148
+
149
+ ## 지원 및 호환성 (Support and compatibility)
150
+
151
+ - Node.js 20 이상
152
+ - Python 3.10 / 3.11 / 3.12 / 3.13 (CI 매트릭스에서 검증, 3.11+ 권장)
153
+ - uv 0.5+ 우선 지원, `uv.lock`(revision 2/3) 기준
154
+ - 정적 프로젝트/의존성 분석 도구는 uv나 `.venv` 없이도 작동합니다.
155
+ - 라이선스: Apache-2.0
156
+
157
+ 릴리스 이력은 `CHANGELOG.md`, 도구 레퍼런스는 `docs/tools.md`, 개발 규칙은 `AGENTS.md`와 `CONTRIBUTING.md`, 지원 런타임 및 성능 정보는 `docs/compatibility.md`, 취약점 보고는 `SECURITY.md`를 참고하세요.
158
+
159
+ 릴리스는 `v<version>` 태그를 푸시하면 `.github/workflows/publish.yml`이 태그와 `package.json` 버전을 검증한 뒤 npm provenance와 함께 배포합니다.
160
+
161
+ ## 설계 원칙 (Design principles)
162
+
163
+ - 모호한 쉘 텍스트 대신 구조화된 결과(`PyToolResult`) 반환
164
+ - 타임아웃, 작업 취소, 출력 크기 제한을 통한 프로세스 경계 유지
165
+ - 사용자 입력 경로/패키지명의 쉘 문자열 보간 금지 (항상 인자 배열)
166
+ - 기본적으로 읽기 전용 진단 수행, 상태를 바꾸는 명령은 명시적 opt-in 요구
167
+ - 근거가 약한 판정은 경고하지 않고 `info` 노트로 내리거나 옵트인으로 제공
168
+ - 도구 수를 의도적으로 작게 유지하고, 린트/타입 진단은 다른 확장에 위임
169
+
170
+ ## 출처 (Attribution)
171
+
172
+ 이 패키지의 공통 코어(결과 규격, 범위 제한 실행기, 검증 게이트 골격)는 Apache-2.0 라이선스의 [pi-ros-helper](https://github.com/wkqco33/pi-ros-helper) 구조를 참고하여 작성되었습니다. ROS 2 전용 도메인 로직은 포함하지 않습니다.
package/SECURITY.md ADDED
@@ -0,0 +1,24 @@
1
+ # Security Policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes target the latest released version and the `main` branch.
6
+
7
+ ## Reporting a vulnerability
8
+
9
+ Please do not open a public issue for a suspected vulnerability. Use GitHub's private security advisory flow for `wkqco33/pi-python-helper` when available. Include reproduction steps, affected version, and impact. Do not include credentials, virtual environments, or private source trees.
10
+
11
+ ## Safety model
12
+
13
+ This extension inspects Python projects and can run environment-modifying commands. The following guarantees hold:
14
+
15
+ - No tool in this package writes, moves, or deletes project files.
16
+ - `py_sync` and `py_validation_bundle` return a preview and execute nothing unless `execute: true` is explicitly passed.
17
+ - Every subprocess is bounded by a timeout, an abort signal, and an output size cap.
18
+ - User-supplied paths and package names are passed as argument arrays, never interpolated into a shell string.
19
+ - `uv --frozen` is used for test runs so a test invocation cannot silently rewrite `uv.lock`.
20
+ - `helpers/scan_project.py` is read-only: it never imports project code and never writes to disk.
21
+
22
+ `execute: true` on `py_sync` or `py_validation_bundle` creates or refreshes `.venv`. Do not bypass that gate in automation unless the deployment environment has an independently reviewed authorization layer.
23
+
24
+ Irreversible operations (publishing to an index, force pushing, hard resetting, recursive deletion, reversing migrations) are classified and reported with a reason. This extension never runs them on your behalf.
@@ -0,0 +1,64 @@
1
+ # 호환성 매트릭스 (Compatibility matrix)
2
+
3
+ | 구성 요소 | 지원 버전 | CI 테스트 여부 |
4
+ |---|---|---|
5
+ | Node.js | 20, 22, 24 | 지원 (Yes) |
6
+ | pi coding agent | 0.86+ / 피어 의존성 범위 | 확장 패키지 스모크 테스트 |
7
+ | Python | 3.10, 3.11, 3.12, 3.13 | 4개 버전 매트릭스 |
8
+ | uv | 0.5+ (`uv.lock` revision 2/3) | CI 설치 후 스모크 테스트 |
9
+ | Ubuntu | `ubuntu-latest` (24.04) | CI 실행 환경 (22.04 미검증) |
10
+
11
+ ## 지원 종료 일정 (End of life)
12
+
13
+ | 런타임 | 지원 상태 | 비고 |
14
+ |---|---|---|
15
+ | Python 3.9 | **미지원** | 2025-10 EOL. `sys.stdlib_module_names` 부재로 표준 라이브러리 판별 정확도가 떨어짐 |
16
+ | Python 3.10 | 지원 | `tomllib`이 없어 `tomli` 설치가 필요 |
17
+ | Python 3.11+ | 지원 | `tomllib` 내장, 모든 분석 기능 사용 가능 |
18
+ | Python 3.14 | 미검증 | CI 매트릭스 추가 전까지 best-effort |
19
+
20
+ 매니페스트/락파일 분석은 Python 3.11+에서 가장 정확합니다. 3.10에서는 분석에 사용되는 인터프리터에 `tomli`가 설치되어 있어야 하며, 없으면 `TOML_PARSER_UNAVAILABLE` 경고 후 분석이 생략됩니다. 선언된 버전 제약과 `uv.lock`의 버전 비교에는 `packaging`이 필요하며, 없으면 `SPECIFIER_CHECK_UNAVAILABLE` 노트와 `python3 -m pip install packaging` 제안을 반환하고 이름 대조만 수행합니다.
21
+
22
+ ## 성능 특성 (Measured cost)
23
+
24
+ 측정 환경: Linux, Python 3.12, `uv` 0.12, 이 저장소 기준.
25
+
26
+ | 작업 | 비용 | 비고 |
27
+ |---|---|---|
28
+ | `py_environment` 전체 | ~64 ms | 스캐너 1회 + `uv --version` 1회. 도구 가용성은 프로세스 실행 없이 판정 |
29
+ | 도구 가용성 판정 | ~2.3 ms | `.venv/bin` + PATH 파일시스템 탐색 + lock 버전 |
30
+ | `py_project_inspect` 매니페스트 스캔 | ~31 ms | `pyproject.toml` + `uv.lock` 파싱 |
31
+ | import 스캔 (`ast`) | ~76 ms | `py_dependency_plan`에만 사용 |
32
+ | 설치본 스캔 | ~3 ms / 22개 패키지 | `dist-info/METADATA` 헤더만 읽음 |
33
+
34
+ `py_environment`는 `--version` 실행을 도구마다 수행하지 않습니다. 과거 이 방식은 도구당 프로세스 1회(pytest만 154 ms)를 썼고 호스트 버전을 프로젝트 버전으로 잘못 보고했습니다.
35
+
36
+ ## 저하 동작 (Degraded behaviour)
37
+
38
+ | 상황 | 동작 |
39
+ |---|---|
40
+ | Python 3 해석기 없음 | `PYTHON_NOT_FOUND` 구조화 오류 반환, 모든 도구가 예외 없이 종료 |
41
+ | `tomllib`/`tomli` 없음 | `TOML_PARSER_UNAVAILABLE` 경고 후 매니페스트 분석 생략 |
42
+ | `sys.stdlib_module_names` 없음 | `STDLIB_LIST_HEURISTIC` 노트와 함께 축소된 표준 라이브러리 목록 사용, 과다 보고 가능성 명시 |
43
+ | uv 미설치 | `UV_NOT_AVAILABLE` 경고, 커맨드 미리보기는 계속 생성 |
44
+ | `uv.lock` 없음 | `LOCKFILE_MISSING` 노트와 `uv lock` 제안, 드리프트 검사 불가 명시, 정합성은 `unverifiable` |
45
+ | `.venv` 없음 | `VENV_MISSING` 노트, 정합성은 `unverifiable` (일치로 간주하지 않음) |
46
+ | site-packages 스캔 잘림 | `truncated: true` 표시 후 정합성을 `unverifiable`로 반환 |
47
+ | `METADATA` 손상/부재 | dist-info 디렉터리 이름에서 버전 복구, `VERSION_FROM_DIRECTORY_NAME` 노트 |
48
+ | 마커 조건부 lock 항목 | `counts.conditional`과 `CONDITIONAL_PACKAGES_ABSENT` 노트로 집계, 누락으로 보고하지 않음 |
49
+ | 부트스트랩 배포판(pip 등) | 비교 대상에서 제외 |
50
+ | `packaging` 미설치 | `SPECIFIER_CHECK_UNAVAILABLE` 노트, 이름 대조만 수행 |
51
+ | import 스캔 중 구문 오류 파일 | `UNPARSABLE_FILE` 노트로 보고하고 나머지 스캔은 계속 |
52
+ | 스캔 파일 수 초과 | `truncated: true` 표시 |
53
+ | 스캐너 프로토콜 불일치 | `SCANNER_VERSION_MISMATCH` 오류 반환 (문서를 해석하지 않음) |
54
+ | 읽을 수 없는 디렉터리 | 해당 항목만 "없음"으로 처리, 전체 스캔은 계속 |
55
+
56
+ ## 릴리스 호환성 (Release compatibility)
57
+
58
+ 본 패키지는 유의적 버전(Semantic Versioning)을 준수합니다. `0.y.z` 시리즈에서는 공개 도구 스키마가 변경될 수 있으며, 하위 호환성을 깨뜨리는 변경사항은 `CHANGELOG.md`에 명시됩니다. 릴리스 태그는 `package.json`에 명시된 버전과 반드시 일치해야 하며(예: `v0.1.0`), 배포는 `.github/workflows/publish.yml`이 태그를 검증한 뒤 npm provenance와 함께 수행합니다.
59
+
60
+ ### Deprecation 정책
61
+
62
+ - 도구 이름이나 필수 파라미터를 제거할 때는 최소 1개 마이너 버전 동안 유지하면서 `CHANGELOG.md`에 `Deprecated` 항목과 마이그레이션 안내를 남깁니다.
63
+ - 파라미터는 additive하게 추가하고, 기존 이름은 `prepareArguments`로 흡수하는 방식을 우선합니다.
64
+ - `1.0.0` 이전에는 위 정책을 권고 사항으로 운영하며, 예외는 `CHANGELOG.md`에 사유와 함께 기록합니다.