docsgraph 0.1.0a2__tar.gz → 0.1.0a3__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.
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/ci.yml +1 -1
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/release.yml +56 -6
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CHANGELOG.md +10 -1
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/PKG-INFO +21 -5
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/README.md +20 -4
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/release-checklist.md +27 -10
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/pyproject.toml +6 -1
- docsgraph-0.1.0a3/scripts/verify_pypi_install.py +185 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/__init__.py +1 -1
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/app.py +199 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/repo_search.py +1 -1
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_cli.py +76 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.cairn/config.toml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.env.example +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/dependabot.yml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.github/workflows/repo-regression.yml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/.gitignore +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/ARCHITECTURE.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CLAUDE.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CODE_OF_CONDUCT.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/CONTRIBUTING.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/LICENSE +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/PRODUCT.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/ROADMAP.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/SECURITY.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/benchmarks/README.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/benchmarks/architecture.toml +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/assets/cairn-demo.svg +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/canvas.html +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/decisions/0000-template.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/decisions/0001-foundation.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/golden-docs-standard.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/inspector-principle.html +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/repo-lifecycle-canvas.html +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/docs/specs/mcp-tools.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/examples/hero-demo.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/examples/real-llm-doubao.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/scripts/eval_repos.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/scripts/smoke_many_repos.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/baseline.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/dataset.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/judge.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/metrics.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/report.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/bench/runner.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/cli/config.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/errors.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/core/types.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/doubao.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/embed/openai_compatible.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/indexer.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/engine/manifest.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/entity/heuristic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/entities.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/summaries.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/tree.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/vectors.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/index/xrefs.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/markdown.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/markitdown.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/ingest/pdf.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/inspection.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/schemas.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/mcp/server.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/providers.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/py.typed +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/repo.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/cache.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/openai_compatible.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/summarize/prompts.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/find_mentions.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/get_related.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/get_section.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/outline.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/read_range.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/search_keyword.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/tools/search_semantic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/base.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/src/cairn/xref/heuristic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/conftest.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/empty.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/nested.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/no_headings.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/simple.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/fixtures/with_frontmatter.md +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/__init__.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/conftest.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_baseline.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_dataset.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_judge.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_metrics.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_bench_runner.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_cli_config.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_doubao.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_embed_openai_compatible.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_engine_indexer.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_engine_manifest.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_entities_builder.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_entity_heuristic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_markdown_parser.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_markitdown_parser.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_mcp_server.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_pdf_parser.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_repo.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_repo_eval_gates.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summaries_builder.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summaries_reader.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_cache.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_fake.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_openai_compatible.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_summarize_prompts.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_document_index.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_find_mentions.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_get_related.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_get_section.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_outline.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_read_range.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_search_keyword.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tool_search_semantic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_tree_builder.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_types.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_vectors_builder.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_vectors_reader.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_xref_heuristic.py +0 -0
- {docsgraph-0.1.0a2 → docsgraph-0.1.0a3}/tests/unit/test_xrefs_builder.py +0 -0
|
@@ -6,9 +6,36 @@ on:
|
|
|
6
6
|
- "v*"
|
|
7
7
|
|
|
8
8
|
jobs:
|
|
9
|
+
verify:
|
|
10
|
+
name: lint + types + tests
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Set up Python
|
|
16
|
+
uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.13"
|
|
19
|
+
cache: pip
|
|
20
|
+
|
|
21
|
+
- name: Install package + dev extras
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
python -m pip install -e ".[dev]"
|
|
25
|
+
|
|
26
|
+
- name: ruff
|
|
27
|
+
run: ruff check .
|
|
28
|
+
|
|
29
|
+
- name: mypy --strict
|
|
30
|
+
run: mypy --python-version "3.13" src tests
|
|
31
|
+
|
|
32
|
+
- name: pytest
|
|
33
|
+
run: pytest
|
|
34
|
+
|
|
9
35
|
build:
|
|
10
36
|
name: Build wheel + sdist for ${{ github.ref_name }}
|
|
11
37
|
runs-on: ubuntu-latest
|
|
38
|
+
needs: verify
|
|
12
39
|
steps:
|
|
13
40
|
- uses: actions/checkout@v4
|
|
14
41
|
|
|
@@ -36,13 +63,11 @@ jobs:
|
|
|
36
63
|
name: Publish to PyPI
|
|
37
64
|
runs-on: ubuntu-latest
|
|
38
65
|
needs: build
|
|
39
|
-
# Trusted publishing
|
|
40
|
-
# GitHub
|
|
41
|
-
# Until then, leave this job disabled by editing the `if`.
|
|
42
|
-
if: ${{ false }}
|
|
66
|
+
# Trusted publishing requires the PyPI `docsgraph` project to trust this
|
|
67
|
+
# GitHub workflow/environment under Settings → Publishing.
|
|
43
68
|
environment:
|
|
44
69
|
name: pypi
|
|
45
|
-
url: https://pypi.org/p/
|
|
70
|
+
url: https://pypi.org/p/docsgraph
|
|
46
71
|
permissions:
|
|
47
72
|
id-token: write
|
|
48
73
|
steps:
|
|
@@ -55,10 +80,35 @@ jobs:
|
|
|
55
80
|
- name: Publish to PyPI
|
|
56
81
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
57
82
|
|
|
83
|
+
verify-pypi-install:
|
|
84
|
+
name: Verify install from PyPI
|
|
85
|
+
runs-on: ubuntu-latest
|
|
86
|
+
needs: publish-pypi
|
|
87
|
+
steps:
|
|
88
|
+
- uses: actions/checkout@v4
|
|
89
|
+
|
|
90
|
+
- name: Set up Python
|
|
91
|
+
uses: actions/setup-python@v5
|
|
92
|
+
with:
|
|
93
|
+
python-version: "3.12"
|
|
94
|
+
cache: pip
|
|
95
|
+
|
|
96
|
+
- name: Verify published package from official index
|
|
97
|
+
run: |
|
|
98
|
+
version="${GITHUB_REF_NAME#v}"
|
|
99
|
+
for attempt in 1 2 3 4 5; do
|
|
100
|
+
if python scripts/verify_pypi_install.py --version "$version" --repo . --sync-repo; then
|
|
101
|
+
exit 0
|
|
102
|
+
fi
|
|
103
|
+
echo "PyPI install verification failed on attempt $attempt; retrying..."
|
|
104
|
+
sleep 30
|
|
105
|
+
done
|
|
106
|
+
python scripts/verify_pypi_install.py --version "$version" --repo . --sync-repo
|
|
107
|
+
|
|
58
108
|
github-release:
|
|
59
109
|
name: Attach artifacts to GitHub release
|
|
60
110
|
runs-on: ubuntu-latest
|
|
61
|
-
needs: build
|
|
111
|
+
needs: [build, publish-pypi, verify-pypi-install]
|
|
62
112
|
permissions:
|
|
63
113
|
contents: write
|
|
64
114
|
steps:
|
|
@@ -41,6 +41,10 @@ All notable changes to Cairn. Format follows
|
|
|
41
41
|
freshness; `cairn mcp config` prints MCP snippets for Claude, Cursor, Codex,
|
|
42
42
|
and Goose. `cairn serve --repo <path>` makes generated configs independent
|
|
43
43
|
from the client's working directory.
|
|
44
|
+
- **Agent self-install command.** `docsgraph install` writes the Cairn MCP
|
|
45
|
+
server config for Codex, Claude, Cursor, or Goose, while
|
|
46
|
+
`docsgraph install --dry-run` prints the target path and config without
|
|
47
|
+
touching disk.
|
|
44
48
|
- **Public repo smoke evaluator.** `scripts/eval_repos.py` reproduces the
|
|
45
49
|
uv / MCP Python SDK / FastAPI template repo-document smoke tests used for
|
|
46
50
|
release readiness.
|
|
@@ -50,7 +54,10 @@ All notable changes to Cairn. Format follows
|
|
|
50
54
|
- **Golden documentation standard.** `docs/golden-docs-standard.md` publishes
|
|
51
55
|
the repo-doc shapes Cairn rewards and the tuning policy maintainers must
|
|
52
56
|
follow when mature-repository smoke runs expose quality gaps.
|
|
53
|
-
- **
|
|
57
|
+
- **PyPI installation verifier.** `scripts/verify_pypi_install.py` installs a
|
|
58
|
+
released `docsgraph` wheel from the official Python index into a clean
|
|
59
|
+
temporary environment and checks both `docsgraph` and `cairn` console scripts.
|
|
60
|
+
- **Optional MarkItDown ingestion.** Installing `docsgraph[markitdown]` lets Cairn
|
|
54
61
|
convert local DOCX, PPTX, XLSX, HTML, CSV, JSON, XML, EPUB, and related files
|
|
55
62
|
to Markdown before indexing them through the canonical Markdown pipeline.
|
|
56
63
|
|
|
@@ -98,6 +105,8 @@ All notable changes to Cairn. Format follows
|
|
|
98
105
|
Cairn product name while making the installed tool obvious and avoiding the
|
|
99
106
|
unrelated package that already occupies `cairn`.
|
|
100
107
|
- Strict mypy now passes across both `src` and `tests`.
|
|
108
|
+
- The release workflow now runs lint, type checks, tests, build validation, and
|
|
109
|
+
PyPI Trusted Publishing from the `pypi` GitHub environment on version tags.
|
|
101
110
|
|
|
102
111
|
## [0.1.0a2] — 2026-06-11
|
|
103
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docsgraph
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.0a3
|
|
4
4
|
Summary: Local-first documentation graph for AI agents. CodeGraph for docs, exposed through MCP.
|
|
5
5
|
Project-URL: Homepage, https://github.com/jokeuncle/cairn
|
|
6
6
|
Project-URL: Documentation, https://github.com/jokeuncle/cairn/tree/main/docs
|
|
@@ -260,7 +260,7 @@ Description-Content-Type: text/markdown
|
|
|
260
260
|
|
|
261
261
|
[](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml)
|
|
262
262
|
[](LICENSE)
|
|
263
|
-
[](CHANGELOG.md)
|
|
264
264
|
[](https://www.python.org/)
|
|
265
265
|
[](https://modelcontextprotocol.io/)
|
|
266
266
|
|
|
@@ -282,7 +282,7 @@ The result: better retrieval accuracy, lower token spend, and a practical MCP
|
|
|
282
282
|
tool layer between your project documentation and every AI coding agent you
|
|
283
283
|
use. Local-first. Vendor-neutral. Designed for open-source repos.
|
|
284
284
|
|
|
285
|
-
> 🚀 **Alpha — `0.1.
|
|
285
|
+
> 🚀 **Alpha — `0.1.0a3`.** Markdown + PDF ingest, all eight MCP tools,
|
|
286
286
|
> the full structure-aware index (tree + summaries + entities + xrefs +
|
|
287
287
|
> vectors), repo-level `init/sync/status`, repo-scoped MCP with
|
|
288
288
|
> `list_documents`, `search_documents`, `repo_context`, `repo_graph`, and
|
|
@@ -352,6 +352,22 @@ Or run it without installing:
|
|
|
352
352
|
uvx docsgraph --help
|
|
353
353
|
```
|
|
354
354
|
|
|
355
|
+
AI agents that can run shell commands can install and wire Cairn into their own
|
|
356
|
+
MCP config. Start with a dry run, then write the config once the target path
|
|
357
|
+
looks right:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
uvx docsgraph init -y
|
|
361
|
+
uvx docsgraph sync --fake
|
|
362
|
+
uvx docsgraph install --client codex --dry-run --fake
|
|
363
|
+
uvx docsgraph install --client codex --yes --fake
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Use `--client claude`, `--client cursor`, or `--client goose` for other MCP
|
|
367
|
+
clients. `docsgraph install` writes the same server config that
|
|
368
|
+
`docsgraph mcp config` prints, with `command = "docsgraph"` and
|
|
369
|
+
`args = ["serve", "--repo", "..."]`.
|
|
370
|
+
|
|
355
371
|
### Repository Workflow
|
|
356
372
|
|
|
357
373
|
Inside any repository:
|
|
@@ -442,7 +458,7 @@ Markdown parser. This expands coverage to formats such as DOCX, PPTX, XLSX,
|
|
|
442
458
|
HTML, CSV, JSON, XML, and EPUB without making the base install heavy:
|
|
443
459
|
|
|
444
460
|
```bash
|
|
445
|
-
|
|
461
|
+
pip install "docsgraph[markitdown]"
|
|
446
462
|
.venv/bin/docsgraph init -y --force --markitdown
|
|
447
463
|
.venv/bin/docsgraph sync --fake
|
|
448
464
|
```
|
|
@@ -657,7 +673,7 @@ choices we adopted, modified, or declined.
|
|
|
657
673
|
| 4 — v0.4 polish for production | ☐ | DOCX/RTF/EPUB, VSCode extension, security review |
|
|
658
674
|
| v1.0 GA | ☐ | All `PRODUCT.md` §7 success criteria met |
|
|
659
675
|
|
|
660
|
-
Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **
|
|
676
|
+
Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **440 passing**,
|
|
661
677
|
mypy strict clean, ruff clean.
|
|
662
678
|
|
|
663
679
|
Maintainer release gate: [`docs/release-checklist.md`](docs/release-checklist.md).
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/jokeuncle/cairn/actions/workflows/ci.yml)
|
|
8
8
|
[](LICENSE)
|
|
9
|
-
[](CHANGELOG.md)
|
|
10
10
|
[](https://www.python.org/)
|
|
11
11
|
[](https://modelcontextprotocol.io/)
|
|
12
12
|
|
|
@@ -28,7 +28,7 @@ The result: better retrieval accuracy, lower token spend, and a practical MCP
|
|
|
28
28
|
tool layer between your project documentation and every AI coding agent you
|
|
29
29
|
use. Local-first. Vendor-neutral. Designed for open-source repos.
|
|
30
30
|
|
|
31
|
-
> 🚀 **Alpha — `0.1.
|
|
31
|
+
> 🚀 **Alpha — `0.1.0a3`.** Markdown + PDF ingest, all eight MCP tools,
|
|
32
32
|
> the full structure-aware index (tree + summaries + entities + xrefs +
|
|
33
33
|
> vectors), repo-level `init/sync/status`, repo-scoped MCP with
|
|
34
34
|
> `list_documents`, `search_documents`, `repo_context`, `repo_graph`, and
|
|
@@ -98,6 +98,22 @@ Or run it without installing:
|
|
|
98
98
|
uvx docsgraph --help
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
+
AI agents that can run shell commands can install and wire Cairn into their own
|
|
102
|
+
MCP config. Start with a dry run, then write the config once the target path
|
|
103
|
+
looks right:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uvx docsgraph init -y
|
|
107
|
+
uvx docsgraph sync --fake
|
|
108
|
+
uvx docsgraph install --client codex --dry-run --fake
|
|
109
|
+
uvx docsgraph install --client codex --yes --fake
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Use `--client claude`, `--client cursor`, or `--client goose` for other MCP
|
|
113
|
+
clients. `docsgraph install` writes the same server config that
|
|
114
|
+
`docsgraph mcp config` prints, with `command = "docsgraph"` and
|
|
115
|
+
`args = ["serve", "--repo", "..."]`.
|
|
116
|
+
|
|
101
117
|
### Repository Workflow
|
|
102
118
|
|
|
103
119
|
Inside any repository:
|
|
@@ -188,7 +204,7 @@ Markdown parser. This expands coverage to formats such as DOCX, PPTX, XLSX,
|
|
|
188
204
|
HTML, CSV, JSON, XML, and EPUB without making the base install heavy:
|
|
189
205
|
|
|
190
206
|
```bash
|
|
191
|
-
|
|
207
|
+
pip install "docsgraph[markitdown]"
|
|
192
208
|
.venv/bin/docsgraph init -y --force --markitdown
|
|
193
209
|
.venv/bin/docsgraph sync --fake
|
|
194
210
|
```
|
|
@@ -403,7 +419,7 @@ choices we adopted, modified, or declined.
|
|
|
403
419
|
| 4 — v0.4 polish for production | ☐ | DOCX/RTF/EPUB, VSCode extension, security review |
|
|
404
420
|
| v1.0 GA | ☐ | All `PRODUCT.md` §7 success criteria met |
|
|
405
421
|
|
|
406
|
-
Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **
|
|
422
|
+
Full plan: [`ROADMAP.md`](ROADMAP.md). Current test suite: **440 passing**,
|
|
407
423
|
mypy strict clean, ruff clean.
|
|
408
424
|
|
|
409
425
|
Maintainer release gate: [`docs/release-checklist.md`](docs/release-checklist.md).
|
|
@@ -37,20 +37,16 @@ UV_PROJECT_ENVIRONMENT=/tmp/cairn-test-venv-py313 uv run --python 3.13 --extra d
|
|
|
37
37
|
UV_PROJECT_ENVIRONMENT=/tmp/cairn-test-venv-py313 uv run --python 3.13 --extra dev pytest
|
|
38
38
|
|
|
39
39
|
rm -rf /tmp/cairn-dist
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
python -m build --outdir /tmp/cairn-dist
|
|
43
|
-
UV_PROJECT_ENVIRONMENT=/tmp/cairn-build-venv-py313 \
|
|
44
|
-
uv run --python 3.13 --with build --with twine \
|
|
45
|
-
python -m twine check /tmp/cairn-dist/*
|
|
40
|
+
uv build --out-dir /tmp/cairn-dist
|
|
41
|
+
uv publish --dry-run /tmp/cairn-dist/*
|
|
46
42
|
```
|
|
47
43
|
|
|
48
44
|
Expected current gate:
|
|
49
45
|
|
|
50
46
|
- `ruff check .`: pass
|
|
51
47
|
- `mypy src tests`: pass
|
|
52
|
-
- `pytest`:
|
|
53
|
-
- `
|
|
48
|
+
- `pytest`: 440 passing
|
|
49
|
+
- `uv publish --dry-run`: wheel and sdist pass upload validation
|
|
54
50
|
|
|
55
51
|
## Dogfood Checks
|
|
56
52
|
|
|
@@ -121,6 +117,27 @@ export CAIRN_EMBED_MODEL=doubao-embedding-vision-251215
|
|
|
121
117
|
The corresponding API key variables must be set locally, but real values must
|
|
122
118
|
never appear in git, shell history snippets, benchmark reports, or CI logs.
|
|
123
119
|
|
|
120
|
+
## Trusted Publishing
|
|
121
|
+
|
|
122
|
+
Public PyPI publishing must use GitHub OIDC Trusted Publishing, not a long-lived
|
|
123
|
+
API token in a local shell. Configure PyPI before pushing a release tag:
|
|
124
|
+
|
|
125
|
+
- Project: `docsgraph`
|
|
126
|
+
- Owner / repository: `jokeuncle/cairn`
|
|
127
|
+
- Workflow: `.github/workflows/release.yml`
|
|
128
|
+
- Environment: `pypi`
|
|
129
|
+
|
|
130
|
+
In GitHub, create the `pypi` environment and require maintainer approval if the
|
|
131
|
+
repository is not fully locked down. Revoke any account-wide PyPI token used for
|
|
132
|
+
manual bootstrapping after the first project-scoped setup is in place.
|
|
133
|
+
|
|
134
|
+
After the tag workflow publishes, verify the official source install from a
|
|
135
|
+
clean temporary environment:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
python scripts/verify_pypi_install.py --version "$(uv run docsgraph version)" --repo . --sync-repo
|
|
139
|
+
```
|
|
140
|
+
|
|
124
141
|
## Secret And Generated-File Audit
|
|
125
142
|
|
|
126
143
|
```bash
|
|
@@ -144,5 +161,5 @@ git push origin main --tags
|
|
|
144
161
|
```
|
|
145
162
|
|
|
146
163
|
The release workflow builds wheel/sdist and attaches them to the GitHub
|
|
147
|
-
release.
|
|
148
|
-
|
|
164
|
+
release. It also publishes to PyPI through Trusted Publishing when the `pypi`
|
|
165
|
+
environment is approved and the PyPI project trusts this workflow.
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "docsgraph"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.0a3"
|
|
8
8
|
description = "Local-first documentation graph for AI agents. CodeGraph for docs, exposed through MCP."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -116,6 +116,11 @@ ignore_missing_imports = true
|
|
|
116
116
|
module = ["markitdown", "markitdown.*"]
|
|
117
117
|
ignore_missing_imports = true
|
|
118
118
|
|
|
119
|
+
[[tool.mypy.overrides]]
|
|
120
|
+
module = ["numpy", "numpy.*"]
|
|
121
|
+
follow_imports = "skip"
|
|
122
|
+
ignore_missing_imports = true
|
|
123
|
+
|
|
119
124
|
[tool.pytest.ini_options]
|
|
120
125
|
testpaths = ["tests"]
|
|
121
126
|
addopts = "-ra --strict-markers"
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"""Verify a published docsgraph package from the public Python index."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
import tempfile
|
|
10
|
+
import tomllib
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main() -> int:
|
|
15
|
+
parser = argparse.ArgumentParser()
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"--version",
|
|
18
|
+
default=None,
|
|
19
|
+
help="Version to install. Defaults to the current pyproject version.",
|
|
20
|
+
)
|
|
21
|
+
parser.add_argument(
|
|
22
|
+
"--index-url",
|
|
23
|
+
default="https://pypi.org/simple",
|
|
24
|
+
help="Python package index URL to install from.",
|
|
25
|
+
)
|
|
26
|
+
parser.add_argument(
|
|
27
|
+
"--repo",
|
|
28
|
+
type=Path,
|
|
29
|
+
default=None,
|
|
30
|
+
help="Optional initialized repo to smoke-test MCP config against.",
|
|
31
|
+
)
|
|
32
|
+
parser.add_argument(
|
|
33
|
+
"--sync-repo",
|
|
34
|
+
action="store_true",
|
|
35
|
+
help="Run docsgraph sync/status/query in --repo after installing.",
|
|
36
|
+
)
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
|
|
39
|
+
root = Path(__file__).resolve().parents[1]
|
|
40
|
+
version = args.version or _project_version(root / "pyproject.toml")
|
|
41
|
+
requirement = f"docsgraph=={version}"
|
|
42
|
+
|
|
43
|
+
with tempfile.TemporaryDirectory(prefix="docsgraph-pypi-") as tmp:
|
|
44
|
+
venv = Path(tmp) / "venv"
|
|
45
|
+
python = _create_venv(venv)
|
|
46
|
+
_install(python, args.index_url, requirement)
|
|
47
|
+
|
|
48
|
+
docsgraph = _script_path(venv, "docsgraph")
|
|
49
|
+
cairn = _script_path(venv, "cairn")
|
|
50
|
+
_run([str(docsgraph), "--help"])
|
|
51
|
+
_run([str(cairn), "--help"])
|
|
52
|
+
_run([str(docsgraph), "version"], expected=version)
|
|
53
|
+
|
|
54
|
+
_run(
|
|
55
|
+
[
|
|
56
|
+
str(python),
|
|
57
|
+
"-c",
|
|
58
|
+
(
|
|
59
|
+
"from importlib.metadata import metadata, version; "
|
|
60
|
+
"m=metadata('docsgraph'); "
|
|
61
|
+
"print(m['Name']); print(version('docsgraph'))"
|
|
62
|
+
),
|
|
63
|
+
],
|
|
64
|
+
expected=f"docsgraph\n{version}",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if args.repo is not None:
|
|
68
|
+
repo = args.repo.resolve()
|
|
69
|
+
_run(
|
|
70
|
+
[
|
|
71
|
+
str(docsgraph),
|
|
72
|
+
"mcp",
|
|
73
|
+
"config",
|
|
74
|
+
"--client",
|
|
75
|
+
"codex",
|
|
76
|
+
"--repo",
|
|
77
|
+
str(repo),
|
|
78
|
+
"--fake",
|
|
79
|
+
],
|
|
80
|
+
cwd=repo,
|
|
81
|
+
expected='command = "docsgraph"',
|
|
82
|
+
)
|
|
83
|
+
if args.sync_repo:
|
|
84
|
+
_run([str(docsgraph), "sync", "--fake"], cwd=repo)
|
|
85
|
+
_run([str(docsgraph), "status"], cwd=repo, expected="documents:")
|
|
86
|
+
_run(
|
|
87
|
+
[
|
|
88
|
+
str(docsgraph),
|
|
89
|
+
"query",
|
|
90
|
+
"repo",
|
|
91
|
+
"what is this project?",
|
|
92
|
+
"--fake",
|
|
93
|
+
],
|
|
94
|
+
cwd=repo,
|
|
95
|
+
expected='"hits"',
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
print(f"verified {requirement} from {args.index_url}")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _project_version(pyproject: Path) -> str:
|
|
103
|
+
data = tomllib.loads(pyproject.read_text(encoding="utf-8"))
|
|
104
|
+
return str(data["project"]["version"])
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _create_venv(venv: Path) -> Path:
|
|
108
|
+
uv = shutil.which("uv")
|
|
109
|
+
if uv:
|
|
110
|
+
_run([uv, "venv", str(venv)])
|
|
111
|
+
return _venv_python(venv)
|
|
112
|
+
|
|
113
|
+
_run([sys.executable, "-m", "venv", str(venv)])
|
|
114
|
+
python = _venv_python(venv)
|
|
115
|
+
_run([str(python), "-m", "ensurepip", "--upgrade"])
|
|
116
|
+
return python
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _install(python: Path, index_url: str, requirement: str) -> None:
|
|
120
|
+
uv = shutil.which("uv")
|
|
121
|
+
if uv:
|
|
122
|
+
_run(
|
|
123
|
+
[
|
|
124
|
+
uv,
|
|
125
|
+
"pip",
|
|
126
|
+
"install",
|
|
127
|
+
"--python",
|
|
128
|
+
str(python),
|
|
129
|
+
"--index-url",
|
|
130
|
+
index_url,
|
|
131
|
+
requirement,
|
|
132
|
+
]
|
|
133
|
+
)
|
|
134
|
+
return
|
|
135
|
+
_run(
|
|
136
|
+
[
|
|
137
|
+
str(python),
|
|
138
|
+
"-m",
|
|
139
|
+
"pip",
|
|
140
|
+
"install",
|
|
141
|
+
"--index-url",
|
|
142
|
+
index_url,
|
|
143
|
+
requirement,
|
|
144
|
+
]
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _venv_python(venv: Path) -> Path:
|
|
149
|
+
if sys.platform == "win32":
|
|
150
|
+
return venv / "Scripts" / "python.exe"
|
|
151
|
+
return venv / "bin" / "python"
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _script_path(venv: Path, name: str) -> Path:
|
|
155
|
+
suffix = ".exe" if sys.platform == "win32" else ""
|
|
156
|
+
directory = "Scripts" if sys.platform == "win32" else "bin"
|
|
157
|
+
return venv / directory / f"{name}{suffix}"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _run(
|
|
161
|
+
cmd: list[str],
|
|
162
|
+
*,
|
|
163
|
+
cwd: Path | None = None,
|
|
164
|
+
expected: str | None = None,
|
|
165
|
+
) -> str:
|
|
166
|
+
result = subprocess.run(
|
|
167
|
+
cmd,
|
|
168
|
+
cwd=cwd,
|
|
169
|
+
text=True,
|
|
170
|
+
stdout=subprocess.PIPE,
|
|
171
|
+
stderr=subprocess.STDOUT,
|
|
172
|
+
check=False,
|
|
173
|
+
)
|
|
174
|
+
if result.returncode != 0:
|
|
175
|
+
print(result.stdout, file=sys.stderr)
|
|
176
|
+
raise SystemExit(result.returncode)
|
|
177
|
+
if expected is not None and expected not in result.stdout:
|
|
178
|
+
print(result.stdout, file=sys.stderr)
|
|
179
|
+
msg = f"expected output to contain: {expected!r}"
|
|
180
|
+
raise SystemExit(msg)
|
|
181
|
+
return result.stdout
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
if __name__ == "__main__":
|
|
185
|
+
raise SystemExit(main())
|