napoln 0.2.2__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.
- napoln-0.2.2/.github/workflows/ci.yml +37 -0
- napoln-0.2.2/.github/workflows/pr-title.yml +15 -0
- napoln-0.2.2/.github/workflows/release-please.yml +27 -0
- napoln-0.2.2/.github/workflows/release.yml +54 -0
- napoln-0.2.2/.gitignore +26 -0
- napoln-0.2.2/.release-please-manifest.json +3 -0
- napoln-0.2.2/AGENTS.md +107 -0
- napoln-0.2.2/ARCHITECTURE.md +440 -0
- napoln-0.2.2/CHANGELOG.md +66 -0
- napoln-0.2.2/CLI-REDESIGN.md +895 -0
- napoln-0.2.2/CONTRIBUTING.md +165 -0
- napoln-0.2.2/LICENSE +21 -0
- napoln-0.2.2/PKG-INFO +141 -0
- napoln-0.2.2/PROMPT.md +67 -0
- napoln-0.2.2/README.md +121 -0
- napoln-0.2.2/SPEC.md +1933 -0
- napoln-0.2.2/STORIES.md +701 -0
- napoln-0.2.2/justfile +40 -0
- napoln-0.2.2/pyproject.toml +41 -0
- napoln-0.2.2/release-please-config.json +12 -0
- napoln-0.2.2/skills-lock.json +10 -0
- napoln-0.2.2/src/napoln/__init__.py +3 -0
- napoln-0.2.2/src/napoln/cli.py +300 -0
- napoln-0.2.2/src/napoln/commands/__init__.py +0 -0
- napoln-0.2.2/src/napoln/commands/add.py +392 -0
- napoln-0.2.2/src/napoln/commands/config.py +310 -0
- napoln-0.2.2/src/napoln/commands/init.py +54 -0
- napoln-0.2.2/src/napoln/commands/install.py +140 -0
- napoln-0.2.2/src/napoln/commands/list_cmd.py +246 -0
- napoln-0.2.2/src/napoln/commands/remove.py +72 -0
- napoln-0.2.2/src/napoln/commands/upgrade.py +217 -0
- napoln-0.2.2/src/napoln/core/__init__.py +0 -0
- napoln-0.2.2/src/napoln/core/agents.py +190 -0
- napoln-0.2.2/src/napoln/core/hasher.py +64 -0
- napoln-0.2.2/src/napoln/core/linker.py +95 -0
- napoln-0.2.2/src/napoln/core/manifest.py +230 -0
- napoln-0.2.2/src/napoln/core/merger.py +231 -0
- napoln-0.2.2/src/napoln/core/resolver.py +545 -0
- napoln-0.2.2/src/napoln/core/store.py +127 -0
- napoln-0.2.2/src/napoln/core/validator.py +168 -0
- napoln-0.2.2/src/napoln/errors.py +64 -0
- napoln-0.2.2/src/napoln/output.py +89 -0
- napoln-0.2.2/src/napoln/prompts.py +96 -0
- napoln-0.2.2/src/napoln/skills/napoln-manage/SKILL.md +78 -0
- napoln-0.2.2/tests/__init__.py +0 -0
- napoln-0.2.2/tests/conftest.py +72 -0
- napoln-0.2.2/tests/features/config.feature +32 -0
- napoln-0.2.2/tests/features/first_run.feature +20 -0
- napoln-0.2.2/tests/features/init.feature +16 -0
- napoln-0.2.2/tests/features/install.feature +22 -0
- napoln-0.2.2/tests/features/list.feature +24 -0
- napoln-0.2.2/tests/features/upgrade.feature +59 -0
- napoln-0.2.2/tests/fixtures/invalid-skill/SKILL.md +7 -0
- napoln-0.2.2/tests/fixtures/multi-skill-repo/README.md +3 -0
- napoln-0.2.2/tests/fixtures/multi-skill-repo/skills/skill-a/SKILL.md +10 -0
- napoln-0.2.2/tests/fixtures/multi-skill-repo/skills/skill-b/SKILL.md +10 -0
- napoln-0.2.2/tests/fixtures/valid-skill/SKILL.md +16 -0
- napoln-0.2.2/tests/integration/test_cli.py +306 -0
- napoln-0.2.2/tests/steps/__init__.py +0 -0
- napoln-0.2.2/tests/steps/conftest.py +83 -0
- napoln-0.2.2/tests/steps/test_config.py +96 -0
- napoln-0.2.2/tests/steps/test_first_run.py +93 -0
- napoln-0.2.2/tests/steps/test_init.py +78 -0
- napoln-0.2.2/tests/steps/test_install.py +103 -0
- napoln-0.2.2/tests/steps/test_list.py +90 -0
- napoln-0.2.2/tests/steps/test_upgrade.py +239 -0
- napoln-0.2.2/tests/unit/test_agents.py +130 -0
- napoln-0.2.2/tests/unit/test_hasher.py +108 -0
- napoln-0.2.2/tests/unit/test_linker.py +100 -0
- napoln-0.2.2/tests/unit/test_manifest.py +159 -0
- napoln-0.2.2/tests/unit/test_merger.py +160 -0
- napoln-0.2.2/tests/unit/test_resolver.py +131 -0
- napoln-0.2.2/tests/unit/test_store.py +112 -0
- napoln-0.2.2/tests/unit/test_validator.py +132 -0
- napoln-0.2.2/uv.lock +782 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- "src/**"
|
|
8
|
+
- "tests/**"
|
|
9
|
+
- "pyproject.toml"
|
|
10
|
+
- "justfile"
|
|
11
|
+
- ".github/workflows/ci.yml"
|
|
12
|
+
pull_request:
|
|
13
|
+
branches: [main]
|
|
14
|
+
paths:
|
|
15
|
+
- "src/**"
|
|
16
|
+
- "tests/**"
|
|
17
|
+
- "pyproject.toml"
|
|
18
|
+
- "justfile"
|
|
19
|
+
- ".github/workflows/ci.yml"
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
check:
|
|
23
|
+
name: Check, Lint & Test
|
|
24
|
+
runs-on: ubuntu-latest
|
|
25
|
+
strategy:
|
|
26
|
+
matrix:
|
|
27
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: astral-sh/setup-uv@v6
|
|
31
|
+
- uses: extractions/setup-just@v2
|
|
32
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
33
|
+
run: uv python install ${{ matrix.python-version }}
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --extra dev
|
|
36
|
+
- name: Run checks
|
|
37
|
+
run: just check
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
name: PR Title
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
types: [opened, edited, synchronize, reopened]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
validate:
|
|
9
|
+
permissions:
|
|
10
|
+
pull-requests: read
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5
|
|
14
|
+
env:
|
|
15
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Release Please
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
actions: write
|
|
10
|
+
contents: write
|
|
11
|
+
pull-requests: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release-please:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: googleapis/release-please-action@v4
|
|
18
|
+
id: release-please
|
|
19
|
+
with:
|
|
20
|
+
config-file: release-please-config.json
|
|
21
|
+
manifest-file: .release-please-manifest.json
|
|
22
|
+
|
|
23
|
+
- name: Dispatch release build
|
|
24
|
+
if: ${{ steps.release-please.outputs.releases_created == 'true' }}
|
|
25
|
+
env:
|
|
26
|
+
GH_TOKEN: ${{ github.token }}
|
|
27
|
+
run: gh workflow run release.yml --repo ${{ github.repository }} -f tag=${{ steps.release-please.outputs.tag_name }}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
tag:
|
|
7
|
+
description: "Git tag to build and release (e.g. v0.1.0)"
|
|
8
|
+
required: true
|
|
9
|
+
type: string
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
build:
|
|
17
|
+
name: Build & Publish
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
with:
|
|
22
|
+
ref: ${{ inputs.tag }}
|
|
23
|
+
- uses: astral-sh/setup-uv@v6
|
|
24
|
+
- uses: extractions/setup-just@v2
|
|
25
|
+
|
|
26
|
+
- name: Build
|
|
27
|
+
run: just build
|
|
28
|
+
|
|
29
|
+
- name: Upload artifacts
|
|
30
|
+
uses: actions/upload-artifact@v4
|
|
31
|
+
with:
|
|
32
|
+
name: dist
|
|
33
|
+
path: dist/
|
|
34
|
+
|
|
35
|
+
- name: Publish to PyPI
|
|
36
|
+
run: uv publish
|
|
37
|
+
env:
|
|
38
|
+
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
|
|
39
|
+
|
|
40
|
+
release:
|
|
41
|
+
name: GitHub Release
|
|
42
|
+
needs: build
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/download-artifact@v4
|
|
46
|
+
with:
|
|
47
|
+
name: dist
|
|
48
|
+
path: dist/
|
|
49
|
+
|
|
50
|
+
- name: Upload to GitHub Release
|
|
51
|
+
uses: softprops/action-gh-release@v2
|
|
52
|
+
with:
|
|
53
|
+
tag_name: ${{ inputs.tag }}
|
|
54
|
+
files: dist/*
|
napoln-0.2.2/.gitignore
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
.venv/
|
|
8
|
+
|
|
9
|
+
# IDE
|
|
10
|
+
.idea/
|
|
11
|
+
.vscode/
|
|
12
|
+
*.swp
|
|
13
|
+
*.swo
|
|
14
|
+
|
|
15
|
+
# OS
|
|
16
|
+
.DS_Store
|
|
17
|
+
Thumbs.db
|
|
18
|
+
|
|
19
|
+
# napoln placements (commit manifest, not placements)
|
|
20
|
+
.claude/skills/
|
|
21
|
+
.gemini/skills/
|
|
22
|
+
.agents/skills/
|
|
23
|
+
.pi/skills/
|
|
24
|
+
.coverage
|
|
25
|
+
.pytest_cache/
|
|
26
|
+
.napoln/
|
napoln-0.2.2/AGENTS.md
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Development Rules
|
|
2
|
+
|
|
3
|
+
## First Message
|
|
4
|
+
|
|
5
|
+
If no concrete task is given, read README.md and ARCHITECTURE.md, then ask what to work on.
|
|
6
|
+
|
|
7
|
+
## Project Overview
|
|
8
|
+
|
|
9
|
+
napoln is a package manager for agent skills. Python 3.11+, built with uv and hatchling. CLI uses typer. Tests use pytest + pytest-bdd.
|
|
10
|
+
|
|
11
|
+
Key directories:
|
|
12
|
+
- `src/napoln/core/` — Core logic (no CLI dependency)
|
|
13
|
+
- `src/napoln/commands/` — One module per CLI command
|
|
14
|
+
- `src/napoln/cli.py` — Typer entry point (7 commands)
|
|
15
|
+
- `tests/unit/` — Parametrized unit tests per core module
|
|
16
|
+
- `tests/integration/` — CLI tests via typer.testing.CliRunner
|
|
17
|
+
- `tests/steps/` — BDD step definitions
|
|
18
|
+
- `tests/features/` — BDD .feature files
|
|
19
|
+
|
|
20
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) for full project layout, test organization, and how to add commands or agents.
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
- After code changes: `just check` (runs format check + lint + tests). Fix all errors before committing.
|
|
25
|
+
- `just check` is the single source of truth. CI runs the same command.
|
|
26
|
+
- `just fmt` to auto-fix formatting and lint issues.
|
|
27
|
+
- `just test` to run tests only. Supports args: `just test -k "test_merge" -x -v`
|
|
28
|
+
- `just coverage` for coverage report.
|
|
29
|
+
- Run the CLI locally: `uv run napoln <command>`
|
|
30
|
+
- NEVER run `uv run napoln add` or `uv run napoln remove` against the real `~/.napoln/` during development without explicit user instruction. Tests use isolated `$HOME` and `$NAPOLN_HOME`.
|
|
31
|
+
|
|
32
|
+
## Code Quality
|
|
33
|
+
|
|
34
|
+
- Keep `core/` independent. Commands import from core, never the reverse.
|
|
35
|
+
- One command per file in `commands/`. Each exports a `run_<command>()` function.
|
|
36
|
+
- Use `from __future__ import annotations` in every module.
|
|
37
|
+
- Line length: 100 (configured in pyproject.toml).
|
|
38
|
+
- Linter/formatter: ruff.
|
|
39
|
+
- Type hints on all function signatures.
|
|
40
|
+
- No unused imports or variables (ruff enforces this).
|
|
41
|
+
|
|
42
|
+
## Architecture
|
|
43
|
+
|
|
44
|
+
Read [ARCHITECTURE.md](ARCHITECTURE.md) for design decisions. Key points:
|
|
45
|
+
|
|
46
|
+
- **7 CLI commands**: `add`, `remove`, `upgrade`, `list`, `install`, `init`, `config`
|
|
47
|
+
- **Reflink-first placement.** Copy-on-write where supported, full copy fallback. No hardlinks (skills are mutable).
|
|
48
|
+
- **Content-addressed store** at `~/.napoln/store/{name}/{version}-{hash}/`. Immutable after write.
|
|
49
|
+
- **Three-way merge on upgrade** using `git merge-file` with `difflib` fallback.
|
|
50
|
+
- **Agent path deduplication.** Gemini CLI, pi, and Codex share `~/.agents/skills/` — one placement serves all three.
|
|
51
|
+
- **Dual-scope manifests.** Global (`~/.napoln/manifest.toml`) and project (`.napoln/manifest.toml`). `napoln install` syncs both.
|
|
52
|
+
- **No registry in v0.x.** Git-only sources. Registry identifiers are parsed but return "not yet available".
|
|
53
|
+
- **No telemetry.** Cut until there's a real backend.
|
|
54
|
+
|
|
55
|
+
## Testing
|
|
56
|
+
|
|
57
|
+
- Write tests first when adding behavior.
|
|
58
|
+
- Unit tests for core logic, BDD for user-facing workflows.
|
|
59
|
+
- Tests run in isolated environments with `$HOME` and `$NAPOLN_HOME` set to tmp dirs.
|
|
60
|
+
- The `NapolnTestEnv` class in `tests/steps/conftest.py` manages isolated BDD environments.
|
|
61
|
+
- The `skill_builder` factory in `tests/conftest.py` creates test skills for unit tests.
|
|
62
|
+
- Use `--agents claude-code` in tests that use `--project` to avoid relying on agent detection.
|
|
63
|
+
- BDD tests that check `napoln list` must `chdir` to the isolated home to avoid picking up the real project manifest.
|
|
64
|
+
- Reflink may not be available (Linux ext4, CI). The linker falls back to copy. Tests pass on both.
|
|
65
|
+
|
|
66
|
+
## CLI Design
|
|
67
|
+
|
|
68
|
+
The CLI has 7 top-level commands. No completion flags in help output. Common short flags:
|
|
69
|
+
|
|
70
|
+
| Flag | Meaning | Available on |
|
|
71
|
+
|------|---------|-------------|
|
|
72
|
+
| `-p` | Project scope | add, remove, upgrade, list, install, config doctor |
|
|
73
|
+
| `-g` | Global only | list, install |
|
|
74
|
+
| `-a` | Install all skills | add |
|
|
75
|
+
| `-s` | Select specific skill | add |
|
|
76
|
+
| `-v` | Verbose (show paths) | list |
|
|
77
|
+
|
|
78
|
+
`config` has subcommands: `set`, `doctor`, `gc`.
|
|
79
|
+
|
|
80
|
+
All mutating commands support `--dry-run`.
|
|
81
|
+
|
|
82
|
+
## Commit Messages
|
|
83
|
+
|
|
84
|
+
Use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
feat: add napoln init command
|
|
88
|
+
fix: catch ReflinkImpossibleError on Linux
|
|
89
|
+
test: BDD coverage for three-way merge cases
|
|
90
|
+
refactor: reduce CLI from 13 commands to 7
|
|
91
|
+
docs: update ARCHITECTURE.md for new command set
|
|
92
|
+
chore: trigger release-please
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Breaking changes bump minor while pre-v1 (configured via release-please `bump-minor-pre-major`).
|
|
96
|
+
|
|
97
|
+
## Style
|
|
98
|
+
|
|
99
|
+
- Concise answers, no filler.
|
|
100
|
+
- Neutral technical voice in documentation (no "This is exactly what we want", no first-person plural editorializing).
|
|
101
|
+
- No emojis in commits, docs, or code. Terminal output uses unicode symbols (✓, ✗, ⚠, ℹ).
|
|
102
|
+
|
|
103
|
+
## File Reading
|
|
104
|
+
|
|
105
|
+
- Use the read tool to examine files, not cat or sed.
|
|
106
|
+
- Read files fully before editing.
|
|
107
|
+
- When editing, keep `oldText` as small as possible while being unique.
|