webarchiver 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. webarchiver-1.2.0/.bumpversion.cfg +16 -0
  2. webarchiver-1.2.0/.config/spec-dashboard.json +4 -0
  3. webarchiver-1.2.0/.github/workflows/pages.yml +25 -0
  4. webarchiver-1.2.0/.github/workflows/pipeline.yml +27 -0
  5. webarchiver-1.2.0/.github/workflows/scanners.yml +42 -0
  6. webarchiver-1.2.0/.github/workflows/windows-ci.yml +78 -0
  7. webarchiver-1.2.0/.pipeline-theme/provenance.json +21 -0
  8. webarchiver-1.2.0/.pipeline-theme/scripts/sync_mkdocs_theme.py +204 -0
  9. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/README.md +27 -0
  10. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/agent-connector-sdk-logo-v1.png +0 -0
  11. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/agent-terminal-ui-logo-v1.png +0 -0
  12. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/agent-utilities-logo-v1.png +0 -0
  13. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/agent-webui-logo-v1.png +0 -0
  14. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/arbora-logo-v1.png +0 -0
  15. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/epistemic-graph-logo-v1.png +0 -0
  16. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/brands/geniusbot-logo-v1.png +0 -0
  17. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/favicon.svg +13 -0
  18. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/assets/graph-mark.svg +13 -0
  19. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/base.mkdocs.yml +105 -0
  20. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/extra.css +249 -0
  21. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/glossary.md +57 -0
  22. webarchiver-1.2.0/.pipeline-theme/templates/mkdocs-theme/overrides/main.html +57 -0
  23. webarchiver-1.2.0/.pre-commit-config.yaml +79 -0
  24. webarchiver-1.2.0/LICENSE +21 -0
  25. webarchiver-1.2.0/MANIFEST.in +19 -0
  26. webarchiver-1.2.0/PKG-INFO +207 -0
  27. webarchiver-1.2.0/README.md +175 -0
  28. webarchiver-1.2.0/docker/Dockerfile +31 -0
  29. webarchiver-1.2.0/docker/debug.Dockerfile +31 -0
  30. webarchiver-1.2.0/docker/mcp.compose.yml +35 -0
  31. webarchiver-1.2.0/docker/starship.toml +70 -0
  32. webarchiver-1.2.0/docs/agent-readiness.json +31 -0
  33. webarchiver-1.2.0/docs/agent-readiness.schema.json +331 -0
  34. webarchiver-1.2.0/docs/architecture.md +34 -0
  35. webarchiver-1.2.0/docs/assets/brands/agent-connector-sdk-logo-v1.png +0 -0
  36. webarchiver-1.2.0/docs/assets/brands/agent-terminal-ui-logo-v1.png +0 -0
  37. webarchiver-1.2.0/docs/assets/brands/agent-utilities-logo-v1.png +0 -0
  38. webarchiver-1.2.0/docs/assets/brands/agent-webui-logo-v1.png +0 -0
  39. webarchiver-1.2.0/docs/assets/brands/arbora-logo-v1.png +0 -0
  40. webarchiver-1.2.0/docs/assets/brands/epistemic-graph-logo-v1.png +0 -0
  41. webarchiver-1.2.0/docs/assets/brands/geniusbot-logo-v1.png +0 -0
  42. webarchiver-1.2.0/docs/assets/favicon.svg +13 -0
  43. webarchiver-1.2.0/docs/assets/graph-mark.svg +13 -0
  44. webarchiver-1.2.0/docs/capabilities/api.json +1 -0
  45. webarchiver-1.2.0/docs/capabilities/mcp.json +1 -0
  46. webarchiver-1.2.0/docs/concepts.md +12 -0
  47. webarchiver-1.2.0/docs/deployment.md +139 -0
  48. webarchiver-1.2.0/docs/glossary.md +57 -0
  49. webarchiver-1.2.0/docs/index.md +33 -0
  50. webarchiver-1.2.0/docs/installation.md +36 -0
  51. webarchiver-1.2.0/docs/overview.md +21 -0
  52. webarchiver-1.2.0/docs/platform.md +22 -0
  53. webarchiver-1.2.0/docs/spec-delivery.md +18 -0
  54. webarchiver-1.2.0/docs/stylesheets/extra.css +249 -0
  55. webarchiver-1.2.0/docs/usage.md +36 -0
  56. webarchiver-1.2.0/mkdocs.yml +27 -0
  57. webarchiver-1.2.0/pyproject.toml +85 -0
  58. webarchiver-1.2.0/pytest.ini +11 -0
  59. webarchiver-1.2.0/scripts/agent_readiness_tck.py +1138 -0
  60. webarchiver-1.2.0/scripts/bootstrap_environment.py +235 -0
  61. webarchiver-1.2.0/scripts/bootstrap_sources.py +129 -0
  62. webarchiver-1.2.0/scripts/check_connector_contract.py +115 -0
  63. webarchiver-1.2.0/scripts/check_import_safety.py +308 -0
  64. webarchiver-1.2.0/scripts/check_workspace_source_drift.py +98 -0
  65. webarchiver-1.2.0/scripts/generate_agent_readiness.py +1531 -0
  66. webarchiver-1.2.0/scripts/generate_tool_schemas.py +100 -0
  67. webarchiver-1.2.0/scripts/security_sanitizer.py +279 -0
  68. webarchiver-1.2.0/scripts/select_python.py +85 -0
  69. webarchiver-1.2.0/scripts/verify_api_integration.py +78 -0
  70. webarchiver-1.2.0/scripts/workspace_sources.py +250 -0
  71. webarchiver-1.2.0/setup.cfg +4 -0
  72. webarchiver-1.2.0/specs/README.md +11 -0
  73. webarchiver-1.2.0/specs/web-source/plan.md +29 -0
  74. webarchiver-1.2.0/specs/web-source/requirements.md +18 -0
  75. webarchiver-1.2.0/specs/web-source/spec.md +26 -0
  76. webarchiver-1.2.0/specs/web-source/status.json +143 -0
  77. webarchiver-1.2.0/specs/web-source/tasks.md +14 -0
  78. webarchiver-1.2.0/specs/web-source/test-spec.md +16 -0
  79. webarchiver-1.2.0/tests/__init__.py +0 -0
  80. webarchiver-1.2.0/tests/conftest.py +76 -0
  81. webarchiver-1.2.0/tests/fixtures/article.html +31 -0
  82. webarchiver-1.2.0/tests/test_concept_parity.py +17 -0
  83. webarchiver-1.2.0/tests/test_conformance.py +39 -0
  84. webarchiver-1.2.0/tests/test_crawl.py +67 -0
  85. webarchiver-1.2.0/tests/test_error_authority.py +68 -0
  86. webarchiver-1.2.0/tests/test_extract.py +157 -0
  87. webarchiver-1.2.0/tests/test_init_dynamics.py +10 -0
  88. webarchiver-1.2.0/tests/test_kg_ingest.py +55 -0
  89. webarchiver-1.2.0/tests/test_served.py +83 -0
  90. webarchiver-1.2.0/tests/test_startup.py +68 -0
  91. webarchiver-1.2.0/tests/test_webarchiver_mcp_validation.py +14 -0
  92. webarchiver-1.2.0/webarchiver/__init__.py +54 -0
  93. webarchiver-1.2.0/webarchiver/__main__.py +4 -0
  94. webarchiver-1.2.0/webarchiver/_version.py +3 -0
  95. webarchiver-1.2.0/webarchiver/api/__init__.py +11 -0
  96. webarchiver-1.2.0/webarchiver/api/_support.py +19 -0
  97. webarchiver-1.2.0/webarchiver/api/api_client_system.py +120 -0
  98. webarchiver-1.2.0/webarchiver/api/browser.py +247 -0
  99. webarchiver-1.2.0/webarchiver/api/crawl.py +166 -0
  100. webarchiver-1.2.0/webarchiver/api/extraction.py +130 -0
  101. webarchiver-1.2.0/webarchiver/api/fetcher.py +186 -0
  102. webarchiver-1.2.0/webarchiver/api/policy.py +170 -0
  103. webarchiver-1.2.0/webarchiver/api/web_source.py +87 -0
  104. webarchiver-1.2.0/webarchiver/auth.py +47 -0
  105. webarchiver-1.2.0/webarchiver/connector_manifest.yml +89 -0
  106. webarchiver-1.2.0/webarchiver/connectors/__init__.py +0 -0
  107. webarchiver-1.2.0/webarchiver/connectors/mcp_source_presets.json +1 -0
  108. webarchiver-1.2.0/webarchiver/connectors/tool_schema_fingerprints.json +1 -0
  109. webarchiver-1.2.0/webarchiver/error_authority.py +248 -0
  110. webarchiver-1.2.0/webarchiver/error_rendering.py +105 -0
  111. webarchiver-1.2.0/webarchiver/kg_ingest.py +93 -0
  112. webarchiver-1.2.0/webarchiver/mcp/__init__.py +3 -0
  113. webarchiver-1.2.0/webarchiver/mcp/mcp_system.py +11 -0
  114. webarchiver-1.2.0/webarchiver/mcp_config.json +3 -0
  115. webarchiver-1.2.0/webarchiver/mcp_server.py +62 -0
  116. webarchiver-1.2.0/webarchiver/ontology/__init__.py +6 -0
  117. webarchiver-1.2.0/webarchiver/ontology/pack.ttl +48 -0
  118. webarchiver-1.2.0/webarchiver/ontology/webarchiver.ttl +29 -0
  119. webarchiver-1.2.0/webarchiver/prompts/__init__.py +0 -0
  120. webarchiver-1.2.0/webarchiver/prompts/webarchiver_specialist.json +30 -0
  121. webarchiver-1.2.0/webarchiver/skills/__init__.py +0 -0
  122. webarchiver-1.2.0/webarchiver/skills/webarchiver-starter/SKILL.md +25 -0
  123. webarchiver-1.2.0/webarchiver/webarchiver_input_models.py +12 -0
  124. webarchiver-1.2.0/webarchiver/webarchiver_response_models.py +15 -0
  125. webarchiver-1.2.0/webarchiver.egg-info/PKG-INFO +207 -0
  126. webarchiver-1.2.0/webarchiver.egg-info/SOURCES.txt +128 -0
  127. webarchiver-1.2.0/webarchiver.egg-info/dependency_links.txt +1 -0
  128. webarchiver-1.2.0/webarchiver.egg-info/entry_points.txt +2 -0
  129. webarchiver-1.2.0/webarchiver.egg-info/requires.txt +16 -0
  130. webarchiver-1.2.0/webarchiver.egg-info/top_level.txt +1 -0
@@ -0,0 +1,16 @@
1
+ [bumpversion]
2
+ current_version = 1.2.0
3
+ commit = True
4
+ tag = True
5
+
6
+ [bumpversion:file:pyproject.toml]
7
+ search = version = "{current_version}"
8
+ replace = version = "{new_version}"
9
+
10
+ [bumpversion:file:webarchiver/_version.py]
11
+ search = __version__ = "{current_version}"
12
+ replace = __version__ = "{new_version}"
13
+
14
+ [bumpversion:file(dockerpin):docker/Dockerfile]
15
+ search = webarchiver[mcp]=={current_version}
16
+ replace = webarchiver[mcp]=={new_version}
@@ -0,0 +1,4 @@
1
+ {
2
+ "version": 1,
3
+ "sources": [{"glob": "specs/*/status.json", "kind": "spec"}]
4
+ }
@@ -0,0 +1,25 @@
1
+ name: Deploy GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish-pages:
13
+ uses: Knuckles-Team/pipelines/.github/workflows/pages_pipeline.yml@main
14
+ with:
15
+ content_source: docs
16
+ shared_theme_enabled: true
17
+ agent_readiness_enabled: true
18
+ readiness_input: docs/agent-readiness.json
19
+ readiness_schema: docs/agent-readiness.schema.json
20
+ spec_dashboard_enabled: true
21
+ spec_dashboard_config: .config/spec-dashboard.json
22
+ permissions:
23
+ contents: read
24
+ pages: write
25
+ id-token: write
@@ -0,0 +1,27 @@
1
+ name: Build|Upload|Release Python Package
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - 'main'
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish-pypi:
13
+ uses: Knuckles-Team/pipelines/.github/workflows/python_pipeline.yml@main
14
+ permissions:
15
+ contents: write
16
+ secrets:
17
+ PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
18
+ publish-docker:
19
+ needs: publish-pypi
20
+ uses: Knuckles-Team/pipelines/.github/workflows/container_pipeline.yml@main
21
+ permissions:
22
+ contents: read
23
+ secrets:
24
+ DOCKER_REGISTRY: ${{ secrets.DOCKER_REGISTRY }}
25
+ DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
26
+ DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
27
+ DOCKER_REPOSITORY: ${{ secrets.DOCKER_REPOSITORY }}
@@ -0,0 +1,42 @@
1
+ name: Connector quality
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ checks:
14
+ # The runner supplies bootstrap Python, uv, pre-commit and approved scanners.
15
+ # Prepare project dependencies separately; never build scanners here.
16
+ runs-on: self-hosted
17
+ env:
18
+ MCP_FLEET_REGISTRATION: 'false'
19
+ steps:
20
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
21
+ with:
22
+ fetch-depth: 0
23
+ persist-credentials: false
24
+ - name: Capture provisioned hook runner
25
+ shell: bash
26
+ run: |
27
+ hook_runner="$(realpath "$(command -v pre-commit)")"
28
+ test -x "$hook_runner"
29
+ echo "CONNECTOR_PRE_COMMIT=$hook_runner" >> "$GITHUB_ENV"
30
+ - name: Select provisioned Python baseline
31
+ run: python scripts/select_python.py
32
+ - name: Prepare frozen project test environment
33
+ run: '"$CONNECTOR_BOOTSTRAP_PYTHON" scripts/bootstrap_environment.py --github'
34
+ - name: Validate hooks
35
+ run: '"$CONNECTOR_PRE_COMMIT" validate-config'
36
+ - name: Commit checks
37
+ run: '"$CONNECTOR_PRE_COMMIT" run --all-files --show-diff-on-failure'
38
+ - name: Push checks and generated connector tests
39
+ env:
40
+ PRE_COMMIT_FROM_REF: ${{ github.event.pull_request.base.sha || github.event.before }}
41
+ PRE_COMMIT_TO_REF: ${{ github.event.pull_request.head.sha || github.sha }}
42
+ run: '"$CONNECTOR_PRE_COMMIT" run --all-files --hook-stage pre-push --show-diff-on-failure'
@@ -0,0 +1,78 @@
1
+ name: Cross-platform coverage
2
+
3
+ # Report-only (continue-on-error on every step) -- does not touch
4
+ # pipeline.yml/pages.yml. scripts/check_import_safety.py auto-detects this
5
+ # package's import name from pyproject.toml's [project].name, so this file
6
+ # needs no per-package templating. See that script's own docstring for
7
+ # exactly what --simulate-windows does and does not model, and its
8
+ # sys.platform-guard false-positive limitation -- if this package
9
+ # legitimately guards a POSIX-only import behind
10
+ # `sys.platform == "win32"`, add `--exclude <dotted.module.name>` to BOTH
11
+ # this file's windows job below and .pre-commit-config.yaml's
12
+ # check-import-safety hook.
13
+
14
+ on:
15
+ pull_request:
16
+ paths:
17
+ - 'webarchiver/**'
18
+ - 'scripts/**'
19
+ - 'tests/**'
20
+ - 'pyproject.toml'
21
+ - 'uv.lock'
22
+ - '.github/workflows/windows-ci.yml'
23
+ push:
24
+ branches:
25
+ - 'main'
26
+
27
+ permissions:
28
+ contents: read
29
+
30
+ jobs:
31
+ windows:
32
+ name: Windows coverage (report only, never blocks)
33
+ runs-on: windows-latest
34
+ permissions:
35
+ contents: read
36
+ defaults:
37
+ run:
38
+ shell: bash
39
+ steps:
40
+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
41
+ with:
42
+ persist-credentials: false
43
+
44
+ - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
45
+ with:
46
+ python-version: '3.14'
47
+
48
+ - uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6
49
+ with:
50
+ version: '0.11.7'
51
+ enable-cache: true
52
+ cache-dependency-glob: uv.lock
53
+
54
+ - name: Sync test environment
55
+ id: sync
56
+ continue-on-error: true
57
+ run: |
58
+ uv sync --extra test
59
+ echo "$PWD/.venv/Scripts" >> "$GITHUB_PATH"
60
+ echo "$PWD/.venv/bin" >> "$GITHUB_PATH"
61
+
62
+ - name: Cross-platform import safety (real Windows interpreter)
63
+ if: steps.sync.outcome == 'success'
64
+ continue-on-error: true
65
+ run: python3 scripts/check_import_safety.py
66
+
67
+ - name: Unit tests
68
+ if: steps.sync.outcome == 'success'
69
+ continue-on-error: true
70
+ run: python3 -m pytest tests -q --tb=short --timeout=120
71
+
72
+ - name: Windows coverage summary
73
+ if: always()
74
+ run: |
75
+ echo "## Windows coverage ran in report-only mode" >> "$GITHUB_STEP_SUMMARY"
76
+ echo "Both steps above use continue-on-error: true -- a red step" >> "$GITHUB_STEP_SUMMARY"
77
+ echo "here is a real Windows regression and never blocks the" >> "$GITHUB_STEP_SUMMARY"
78
+ echo "publish pipeline." >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,21 @@
1
+ {
2
+ "files": {
3
+ "scripts/sync_mkdocs_theme.py": "bec06ab81fcf5df697b37419324535d2385be2675d34dd093f60190c12c2e390",
4
+ "templates/mkdocs-theme/README.md": "e5484fae67ffa597e6f40747f52b2e321b9b1b31612b6d5a141a2dcf6029f180",
5
+ "templates/mkdocs-theme/assets/brands/agent-connector-sdk-logo-v1.png": "6688810468a77118ee1960ac3872816c6ace4f750a849688d306d7a63132e1b1",
6
+ "templates/mkdocs-theme/assets/brands/agent-terminal-ui-logo-v1.png": "d5e3c011066e2241c09c885f65d9a07c6ff32f4244b00dbe8e7550a3bab20dc8",
7
+ "templates/mkdocs-theme/assets/brands/agent-utilities-logo-v1.png": "923319a3b89fa1fbd14ca14c27cf49d2e2d9f85bc45456e05b788692700f0103",
8
+ "templates/mkdocs-theme/assets/brands/agent-webui-logo-v1.png": "3939a7324f134c520fd544aadd2a37c99abba9db78dd2bf3fd5003ffd62502ff",
9
+ "templates/mkdocs-theme/assets/brands/arbora-logo-v1.png": "bba183368e42927edea91013639311a5d64f5a9910ec2f1bdcc7f4cd32f9d230",
10
+ "templates/mkdocs-theme/assets/brands/epistemic-graph-logo-v1.png": "26671aef2c3b78ecdcca2ad13adfd266cebf8d7e666e614c2d83d166b853d272",
11
+ "templates/mkdocs-theme/assets/brands/geniusbot-logo-v1.png": "c4a17404f234f677496197ac202ca8fb30b136c5a69243811bbfa6e5d5352b28",
12
+ "templates/mkdocs-theme/assets/favicon.svg": "aa606f9668a363bfe533f7d835700c246efaed0b8895cce5fe4398f36c35e7ba",
13
+ "templates/mkdocs-theme/assets/graph-mark.svg": "d0c69cdc06aa51439b6ce04b4c6df4dbf02283329f01122a78e08f286186e25d",
14
+ "templates/mkdocs-theme/base.mkdocs.yml": "5424438de987d1ea222f8ce4467e830f286784d14e35b71c623616c9a6ce87d9",
15
+ "templates/mkdocs-theme/extra.css": "2cc17b7610b67c82895312e7e61cf84587a6fe291bbc154d3c83c59fba2ee843",
16
+ "templates/mkdocs-theme/glossary.md": "f35f337fd8175dfdd274442795558772ae3138bb95fc31d84937f5047bff1f64",
17
+ "templates/mkdocs-theme/overrides/main.html": "766234b5045a5815805bb2ce5223ddd93729f7854abc4b6cdf4fba9c7e0dab3b"
18
+ },
19
+ "repository": "https://github.com/Knuckles-Team/pipelines",
20
+ "revision": "58e9bbc62557f2d4a07438070b1ceebb5864a81f"
21
+ }
@@ -0,0 +1,204 @@
1
+ """Synchronize generated ecosystem MkDocs theme files into a consumer repo."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import re
7
+ import sys
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+ from typing import Literal
11
+
12
+
13
+ @dataclass(frozen=True)
14
+ class ThemeFile:
15
+ """A canonical source file and its generated consumer-relative path."""
16
+
17
+ source: str
18
+ destination: str
19
+ content_relative: bool = True
20
+
21
+
22
+ THEME_FILES = (
23
+ ThemeFile("extra.css", "stylesheets/extra.css"),
24
+ ThemeFile("assets/graph-mark.svg", "assets/graph-mark.svg"),
25
+ ThemeFile("assets/favicon.svg", "assets/favicon.svg"),
26
+ ThemeFile(
27
+ "assets/brands/epistemic-graph-logo-v1.png",
28
+ "assets/brands/epistemic-graph-logo-v1.png",
29
+ ),
30
+ ThemeFile(
31
+ "assets/brands/agent-utilities-logo-v1.png",
32
+ "assets/brands/agent-utilities-logo-v1.png",
33
+ ),
34
+ ThemeFile("assets/brands/arbora-logo-v1.png", "assets/brands/arbora-logo-v1.png"),
35
+ ThemeFile(
36
+ "assets/brands/agent-connector-sdk-logo-v1.png",
37
+ "assets/brands/agent-connector-sdk-logo-v1.png",
38
+ ),
39
+ ThemeFile(
40
+ "assets/brands/agent-webui-logo-v1.png",
41
+ "assets/brands/agent-webui-logo-v1.png",
42
+ ),
43
+ ThemeFile(
44
+ "assets/brands/geniusbot-logo-v1.png", "assets/brands/geniusbot-logo-v1.png"
45
+ ),
46
+ ThemeFile(
47
+ "assets/brands/agent-terminal-ui-logo-v1.png",
48
+ "assets/brands/agent-terminal-ui-logo-v1.png",
49
+ ),
50
+ ThemeFile("glossary.md", "glossary.md"),
51
+ )
52
+
53
+
54
+ RUNTIME_DIAGRAM_URL = (
55
+ "https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/"
56
+ "docs/assets/runtime-architecture.svg"
57
+ )
58
+ # Any reference to the diagram file; the only accepted target is RUNTIME_DIAGRAM_URL.
59
+ RUNTIME_DIAGRAM_REFERENCE = re.compile(r"[^\s\"'()<>]*runtime-architecture\.svg")
60
+ PAGE_SUFFIXES = {".md", ".html", ".yml", ".yaml"}
61
+
62
+
63
+ class ThemeSyncError(Exception):
64
+ """The source, destination, or content-source contract is invalid."""
65
+
66
+
67
+ def _safe_relative_path(value: str, label: str) -> Path:
68
+ path = Path(value)
69
+ if (
70
+ path.is_absolute()
71
+ or not path.parts
72
+ or any(part in {".", ".."} for part in path.parts)
73
+ ):
74
+ raise ThemeSyncError(f"{label} must be a contained relative path")
75
+ return path
76
+
77
+
78
+ def _contained(root: Path, relative: Path, label: str) -> Path:
79
+ base = root.resolve()
80
+ result = (base / relative).resolve()
81
+ if not result.is_relative_to(base):
82
+ raise ThemeSyncError(f"{label} escapes the repository root")
83
+ return result
84
+
85
+
86
+ def _check_file(destination: Path, expected: bytes, repository: Path) -> str | None:
87
+ """Describe how ``destination`` diverges from ``expected``, or ``None`` when it matches."""
88
+ try:
89
+ actual = destination.read_bytes()
90
+ except OSError:
91
+ return f"missing generated file: {destination.relative_to(repository)}"
92
+ if actual != expected:
93
+ return f"generated file differs: {destination.relative_to(repository)}"
94
+ return None
95
+
96
+
97
+ def _runtime_reference_mismatches(content_root: Path, repository: Path) -> list[str]:
98
+ """Pages may show the runtime diagram only through the single canonical URL."""
99
+ mismatches: list[str] = []
100
+ if not content_root.is_dir():
101
+ return mismatches
102
+ for page in sorted(content_root.rglob("*")):
103
+ if page.suffix not in PAGE_SUFFIXES or not page.is_file():
104
+ continue
105
+ text = page.read_text(encoding="utf-8", errors="replace")
106
+ if any(
107
+ match.group(0) != RUNTIME_DIAGRAM_URL
108
+ for match in RUNTIME_DIAGRAM_REFERENCE.finditer(text)
109
+ ):
110
+ mismatches.append(
111
+ f"runtime diagram must be referenced as {RUNTIME_DIAGRAM_URL}: "
112
+ f"{page.relative_to(repository)}"
113
+ )
114
+ return mismatches
115
+
116
+
117
+ def sync_theme(
118
+ *,
119
+ source_root: Path,
120
+ repository_root: Path,
121
+ content_source: str,
122
+ mode: Literal["sync", "check"],
123
+ ) -> list[str]:
124
+ """Copy canonical files in ``sync`` mode or return mismatches in ``check`` mode."""
125
+ content_relative = _safe_relative_path(content_source, "content-source")
126
+ repository = repository_root.resolve()
127
+ content_root = _contained(repository, content_relative, "content-source")
128
+ source = (source_root / "templates" / "mkdocs-theme").resolve()
129
+ if not source.is_dir():
130
+ raise ThemeSyncError(f"canonical theme directory does not exist: {source}")
131
+
132
+ mismatches = _sync_files(source, content_root, repository, mode=mode)
133
+ if mode == "check":
134
+ mismatches.extend(_runtime_reference_mismatches(content_root, repository))
135
+ return mismatches
136
+
137
+
138
+ def _sync_files(
139
+ source: Path,
140
+ content_root: Path,
141
+ repository: Path,
142
+ *,
143
+ mode: Literal["sync", "check"],
144
+ ) -> list[str]:
145
+ """Write or compare every theme file and describe each divergence."""
146
+ mismatches: list[str] = []
147
+ for item in THEME_FILES:
148
+ source_file = source / item.source
149
+ if not source_file.is_file():
150
+ raise ThemeSyncError(f"canonical theme file does not exist: {source_file}")
151
+ destination_root = content_root if item.content_relative else repository
152
+ destination = _contained(
153
+ destination_root, Path(item.destination), item.destination
154
+ )
155
+ expected = source_file.read_bytes()
156
+ if mode == "check":
157
+ mismatch = _check_file(destination, expected, repository)
158
+ if mismatch:
159
+ mismatches.append(mismatch)
160
+ continue
161
+ destination.parent.mkdir(parents=True, exist_ok=True)
162
+ destination.write_bytes(expected)
163
+ return mismatches
164
+
165
+
166
+ def main(argv: list[str] | None = None) -> int:
167
+ parser = argparse.ArgumentParser(description=__doc__)
168
+ parser.add_argument("mode", choices=("sync", "check"))
169
+ parser.add_argument(
170
+ "--root", type=Path, default=Path.cwd(), help="consumer repository root"
171
+ )
172
+ parser.add_argument(
173
+ "--content-source",
174
+ default="docs",
175
+ help="consumer MkDocs content directory (normally docs or pages)",
176
+ )
177
+ parser.add_argument(
178
+ "--source-root",
179
+ type=Path,
180
+ default=Path(__file__).resolve().parents[1],
181
+ help="pipelines checkout containing templates/mkdocs-theme",
182
+ )
183
+ args = parser.parse_args(argv)
184
+ try:
185
+ mismatches = sync_theme(
186
+ source_root=args.source_root,
187
+ repository_root=args.root,
188
+ content_source=args.content_source,
189
+ mode=args.mode,
190
+ )
191
+ except (OSError, ThemeSyncError) as exc:
192
+ print(f"shared MkDocs theme: CANNOT RUN: {exc}", file=sys.stderr)
193
+ return 2
194
+ if mismatches:
195
+ print("shared MkDocs theme: generated files are out of sync:", file=sys.stderr)
196
+ for mismatch in mismatches:
197
+ print(f" - {mismatch}", file=sys.stderr)
198
+ return 1
199
+ print(f"shared MkDocs theme: {args.mode} complete")
200
+ return 0
201
+
202
+
203
+ if __name__ == "__main__":
204
+ raise SystemExit(main())
@@ -0,0 +1,27 @@
1
+ # Shared MkDocs theme
2
+
3
+ This folder is the canonical source for the five ecosystem documentation sites. `scripts/sync_mkdocs_theme.py` copies its generated files into a consuming repository and checks that committed copies are byte-identical.
4
+
5
+ ## Generated files
6
+
7
+ | Source | Consumer path |
8
+ | --- | --- |
9
+ | `extra.css` | `<content-source>/stylesheets/extra.css` |
10
+ | `overrides/main.html` | not synced: `custom_dir` serves it from the theme checkout (`.pipeline-theme/templates/mkdocs-theme/overrides`) |
11
+ | `assets/*` | `<content-source>/assets/*` |
12
+ | `glossary.md` | `<content-source>/glossary.md` |
13
+ | `base.mkdocs.yml` | inherited directly from the pinned pipelines checkout |
14
+
15
+ `<content-source>` is the explicitly declared `docs` or `pages` directory. Run `python scripts/sync_mkdocs_theme.py sync --root REPOSITORY --content-source docs` to update files, and the same command with `check` to check exact equality without writing. The Pages workflow checks the committed assets against its immutable workflow checkout before building.
16
+
17
+ ## Runtime architecture diagram
18
+
19
+ The runtime architecture diagram is not a theme asset and is never copied into a consumer. There is exactly one file, `docs/assets/runtime-architecture.svg` in Knuckles-Team/epistemic-graph, and every page that shows it references the URL `https://raw.githubusercontent.com/Knuckles-Team/epistemic-graph/main/docs/assets/runtime-architecture.svg`. The `check` mode fails when a page under the content source references `runtime-architecture.svg` by any other path.
20
+
21
+ ## MkDocs configuration
22
+
23
+ The repository's `mkdocs.yml` inherits `templates/mkdocs-theme/base.mkdocs.yml` and supplies `extra.ecosystem.current` with its own slug (`agent-webui`, `arbora`, `agent-utilities`, `epistemic-graph`, or `agent-connector-sdk`). It continues to own its site name, URL, content directory, and navigation. For local builds, check out the exact pinned `pipelines` revision into `.pipeline-theme`, run the `sync` command above, then run `mkdocs build --strict`.
24
+
25
+ Use `.site-hero`, `.site-card-grid` / `.site-card`, `.site-ownership__grid` / `.site-ownership__item`, and the ordered `.site-flow` components for landing-page structure. Prefer semantic HTML and retain visible keyboard focus. The common theme uses native `<details>` for the site switcher and does not require custom JavaScript.
26
+
27
+ The root `README.md` remains the short entry point. It keeps its exact ordered headings: Overview, Key capabilities, Documentation, Architecture, Quick start, Contributing, License. Deep reference material belongs in Pages. Public home pages describe the current bundled ecosystem in present tense. They contain no planning, migration, worktree, or future-release status.
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect width="64" height="64" rx="14" fill="#f1f5fb"/>
3
+ <g fill="none" stroke="#2a5ca8" stroke-linecap="round" stroke-width="5">
4
+ <path d="M16 18 32 10l16 9v26l-16 9-16-9z"/>
5
+ <path d="m16 18 16 9 16-8M32 27v27M16 45l16-18 16 18"/>
6
+ </g>
7
+ <g fill="#e6a23a" stroke="#f1f5fb" stroke-width="2">
8
+ <circle cx="16" cy="18" r="6"/><circle cx="32" cy="10" r="6"/>
9
+ <circle cx="48" cy="19" r="6"/><circle cx="16" cy="45" r="6"/>
10
+ <circle cx="32" cy="54" r="6"/><circle cx="48" cy="45" r="6"/>
11
+ <circle cx="32" cy="27" r="6"/>
12
+ </g>
13
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-labelledby="title">
2
+ <title id="title">Knuckles-Team graph mark</title>
3
+ <g fill="none" stroke="#2a5ca8" stroke-linecap="round" stroke-width="5">
4
+ <path d="M16 18 32 10l16 9v26l-16 9-16-9z"/>
5
+ <path d="m16 18 16 9 16-8M32 27v27M16 45l16-18 16 18"/>
6
+ </g>
7
+ <g fill="#e6a23a" stroke="#fff" stroke-width="2">
8
+ <circle cx="16" cy="18" r="6"/><circle cx="32" cy="10" r="6"/>
9
+ <circle cx="48" cy="19" r="6"/><circle cx="16" cy="45" r="6"/>
10
+ <circle cx="32" cy="54" r="6"/><circle cx="48" cy="45" r="6"/>
11
+ <circle cx="32" cy="27" r="6"/>
12
+ </g>
13
+ </svg>
@@ -0,0 +1,105 @@
1
+ # Shared GitHub Pages theme for the Knuckles-Team agent ecosystem.
2
+ #
3
+ # A consuming repository's own `mkdocs.yml` inherits this file via mkdocs's
4
+ # native `INHERIT:` key (a recursive dict merge, lists replaced only where the
5
+ # child repository re-declares them -- see `mkdocs.utils.yaml.yaml_load`).
6
+ # The `pages_pipeline.yml` reusable workflow wires the `INHERIT:` line in for
7
+ # every caller that sets `shared_theme_enabled: true`. The repository's own
8
+ # `mkdocs.yml` remains the content manifest; this file supplies the common
9
+ # presentation, while `scripts/sync_mkdocs_theme.py` materializes its generated
10
+ # assets into the caller's docs tree.
11
+
12
+ theme:
13
+ name: material
14
+ custom_dir: .pipeline-theme/templates/mkdocs-theme/overrides
15
+ logo: assets/graph-mark.svg
16
+ favicon: assets/favicon.svg
17
+ icon:
18
+ repo: fontawesome/brands/github
19
+ features:
20
+ - navigation.tabs
21
+ - navigation.tabs.sticky
22
+ - navigation.sections
23
+ - navigation.top
24
+ - navigation.tracking
25
+ - navigation.instant
26
+ - navigation.instant.progress
27
+ - navigation.footer
28
+ - toc.follow
29
+ - search.suggest
30
+ - search.highlight
31
+ - search.share
32
+ - content.code.copy
33
+ - content.code.annotate
34
+ - content.tabs.link
35
+ palette:
36
+ - media: "(prefers-color-scheme: light)"
37
+ scheme: default
38
+ primary: indigo
39
+ accent: indigo
40
+ toggle:
41
+ icon: material/weather-sunny
42
+ name: Switch to dark mode
43
+ - media: "(prefers-color-scheme: dark)"
44
+ scheme: slate
45
+ primary: indigo
46
+ accent: indigo
47
+ toggle:
48
+ icon: material/weather-night
49
+ name: Switch to light mode
50
+
51
+ extra_css:
52
+ - stylesheets/extra.css
53
+
54
+ extra:
55
+ spec_delivery: !ENV [SPEC_DELIVERY_ENABLED, false]
56
+ ecosystem:
57
+ current: ""
58
+ sites:
59
+ - slug: agent-webui
60
+ name: Agent Web UI
61
+ role: operator experience
62
+ url: https://knuckles-team.github.io/agent-webui/
63
+ repository: https://github.com/Knuckles-Team/agent-webui
64
+ - slug: arbora
65
+ name: Arbora
66
+ role: public runtime gateway
67
+ url: https://knuckles-team.github.io/arbora/
68
+ repository: https://github.com/Knuckles-Team/arbora
69
+ - slug: agent-utilities
70
+ name: Agent Utilities
71
+ role: agent control plane
72
+ url: https://knuckles-team.github.io/agent-utilities/
73
+ repository: https://github.com/Knuckles-Team/agent-utilities
74
+ - slug: epistemic-graph
75
+ name: Epistemic Graph
76
+ role: durable multimodal knowledge and reasoning engine
77
+ url: https://knuckles-team.github.io/epistemic-graph/
78
+ repository: https://github.com/Knuckles-Team/epistemic-graph
79
+ - slug: agent-connector-sdk
80
+ name: Agent Connector SDK
81
+ role: governed source integration boundary
82
+ url: https://knuckles-team.github.io/agent-connector-sdk/
83
+ repository: https://github.com/Knuckles-Team/agent-connector-sdk
84
+ - slug: pipelines
85
+ name: Skill Graph
86
+ role: cross-repo concept, component and man-page corpus
87
+ url: https://knuckles-team.github.io/pipelines/
88
+ repository: https://github.com/Knuckles-Team/pipelines
89
+ spec_delivery: false
90
+
91
+ markdown_extensions:
92
+ - admonition
93
+ - attr_list
94
+ - md_in_html
95
+ - tables
96
+ - toc:
97
+ permalink: true
98
+ - pymdownx.details
99
+ - pymdownx.superfences
100
+ - pymdownx.tabbed:
101
+ alternate_style: true
102
+ - pymdownx.highlight:
103
+ anchor_linenums: true
104
+ - pymdownx.inlinehilite
105
+ - pymdownx.snippets