sonar-catalog 0.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.
- sonar_catalog-0.2.0/.beads/.gitignore +44 -0
- sonar_catalog-0.2.0/.beads/README.md +81 -0
- sonar_catalog-0.2.0/.beads/config.yaml +62 -0
- sonar_catalog-0.2.0/.beads/interactions.jsonl +0 -0
- sonar_catalog-0.2.0/.beads/issues.jsonl +16 -0
- sonar_catalog-0.2.0/.beads/metadata.json +4 -0
- sonar_catalog-0.2.0/.gitattributes +3 -0
- sonar_catalog-0.2.0/.github/workflows/deploy-docs.yml +56 -0
- sonar_catalog-0.2.0/.github/workflows/publish.yml +54 -0
- sonar_catalog-0.2.0/.gitignore +20 -0
- sonar_catalog-0.2.0/AGENTS.md +40 -0
- sonar_catalog-0.2.0/LICENSE +21 -0
- sonar_catalog-0.2.0/PKG-INFO +756 -0
- sonar_catalog-0.2.0/README.md +715 -0
- sonar_catalog-0.2.0/docs/.gitignore +21 -0
- sonar_catalog-0.2.0/docs/.vscode/extensions.json +4 -0
- sonar_catalog-0.2.0/docs/.vscode/launch.json +11 -0
- sonar_catalog-0.2.0/docs/README.md +49 -0
- sonar_catalog-0.2.0/docs/astro.config.mjs +75 -0
- sonar_catalog-0.2.0/docs/package-lock.json +8093 -0
- sonar_catalog-0.2.0/docs/package.json +18 -0
- sonar_catalog-0.2.0/docs/public/favicon.svg +1 -0
- sonar_catalog-0.2.0/docs/public/index.html +12 -0
- sonar_catalog-0.2.0/docs/src/assets/houston.webp +0 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/formats/custom.mdx +90 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/formats/overview.mdx +63 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/getting-started/architecture.mdx +242 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/getting-started/configuration.mdx +142 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/getting-started/installation.mdx +70 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/getting-started/quickstart.mdx +107 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/crawling.mdx +120 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/demo-mode.mdx +75 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/discovery.mdx +148 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/exporting.mdx +86 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/nav-extraction.mdx +164 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/guides/searching.mdx +104 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/index.mdx +63 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/plugins/hooks.mdx +184 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/plugins/manifest.mdx +104 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/plugins/overview.mdx +126 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/plugins/writing-a-plugin.mdx +199 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/reference/api.mdx +199 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/reference/cli.mdx +282 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/reference/database.mdx +202 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/reference/environment.mdx +140 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/web/globe.mdx +98 -0
- sonar_catalog-0.2.0/docs/src/content/docs/docs/web/search-ui.mdx +76 -0
- sonar_catalog-0.2.0/docs/src/content.config.ts +7 -0
- sonar_catalog-0.2.0/docs/src/styles/custom.css +20 -0
- sonar_catalog-0.2.0/docs/tsconfig.json +5 -0
- sonar_catalog-0.2.0/pyproject.toml +103 -0
- sonar_catalog-0.2.0/requirements.txt +10 -0
- sonar_catalog-0.2.0/setup.cfg +4 -0
- sonar_catalog-0.2.0/sonar_catalog/__init__.py +12 -0
- sonar_catalog-0.2.0/sonar_catalog/_version.py +34 -0
- sonar_catalog-0.2.0/sonar_catalog/cli.py +942 -0
- sonar_catalog-0.2.0/sonar_catalog/config.py +196 -0
- sonar_catalog-0.2.0/sonar_catalog/crawler.py +568 -0
- sonar_catalog-0.2.0/sonar_catalog/database.py +1083 -0
- sonar_catalog-0.2.0/sonar_catalog/demo.py +218 -0
- sonar_catalog-0.2.0/sonar_catalog/discovery.py +707 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/__init__.py +100 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/base.py +31 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/jsf.py +112 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/nmea.py +106 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/sidecar.py +133 -0
- sonar_catalog-0.2.0/sonar_catalog/extractors/xtf.py +107 -0
- sonar_catalog-0.2.0/sonar_catalog/hasher.py +268 -0
- sonar_catalog-0.2.0/sonar_catalog/mount_resolver.py +406 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/__init__.py +76 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/builtin/__init__.py +26 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/builtin/exporters.py +113 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/builtin/formats.py +103 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/builtin/nav.py +55 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/hooks.py +115 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/manager.py +265 -0
- sonar_catalog-0.2.0/sonar_catalog/plugins/manifest.py +197 -0
- sonar_catalog-0.2.0/sonar_catalog/search.py +243 -0
- sonar_catalog-0.2.0/sonar_catalog/web/__init__.py +42 -0
- sonar_catalog-0.2.0/sonar_catalog/web/api.py +171 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/app.css +63 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/app.js +303 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/globe.js +187 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/vendor/cesium/Cesium.js +15769 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/vendor/cesium/widgets.css +1346 -0
- sonar_catalog-0.2.0/sonar_catalog/web/static/vendor/tailwind.js +83 -0
- sonar_catalog-0.2.0/sonar_catalog/web/templates/base.html +72 -0
- sonar_catalog-0.2.0/sonar_catalog/web/templates/globe.html +70 -0
- sonar_catalog-0.2.0/sonar_catalog/web/templates/index.html +75 -0
- sonar_catalog-0.2.0/sonar_catalog/web/views.py +21 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/PKG-INFO +756 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/SOURCES.txt +116 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/dependency_links.txt +1 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/entry_points.txt +2 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/requires.txt +24 -0
- sonar_catalog-0.2.0/sonar_catalog.egg-info/top_level.txt +1 -0
- sonar_catalog-0.2.0/tests/__init__.py +0 -0
- sonar_catalog-0.2.0/tests/conftest.py +56 -0
- sonar_catalog-0.2.0/tests/test_cli.py +433 -0
- sonar_catalog-0.2.0/tests/test_cli_commands.py +215 -0
- sonar_catalog-0.2.0/tests/test_cli_main.py +264 -0
- sonar_catalog-0.2.0/tests/test_config.py +168 -0
- sonar_catalog-0.2.0/tests/test_crawler.py +89 -0
- sonar_catalog-0.2.0/tests/test_crawler_ext.py +273 -0
- sonar_catalog-0.2.0/tests/test_database.py +150 -0
- sonar_catalog-0.2.0/tests/test_demo.py +145 -0
- sonar_catalog-0.2.0/tests/test_discovery.py +350 -0
- sonar_catalog-0.2.0/tests/test_exporters.py +173 -0
- sonar_catalog-0.2.0/tests/test_extractors.py +437 -0
- sonar_catalog-0.2.0/tests/test_fts.py +146 -0
- sonar_catalog-0.2.0/tests/test_hasher.py +159 -0
- sonar_catalog-0.2.0/tests/test_mount_resolver.py +89 -0
- sonar_catalog-0.2.0/tests/test_mount_resolver_ext.py +232 -0
- sonar_catalog-0.2.0/tests/test_nav_api.py +130 -0
- sonar_catalog-0.2.0/tests/test_plugins.py +602 -0
- sonar_catalog-0.2.0/tests/test_plugins_ext.py +223 -0
- sonar_catalog-0.2.0/tests/test_search.py +172 -0
- sonar_catalog-0.2.0/tests/test_web.py +134 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# SQLite databases
|
|
2
|
+
*.db
|
|
3
|
+
*.db?*
|
|
4
|
+
*.db-journal
|
|
5
|
+
*.db-wal
|
|
6
|
+
*.db-shm
|
|
7
|
+
|
|
8
|
+
# Daemon runtime files
|
|
9
|
+
daemon.lock
|
|
10
|
+
daemon.log
|
|
11
|
+
daemon.pid
|
|
12
|
+
bd.sock
|
|
13
|
+
sync-state.json
|
|
14
|
+
last-touched
|
|
15
|
+
|
|
16
|
+
# Local version tracking (prevents upgrade notification spam after git ops)
|
|
17
|
+
.local_version
|
|
18
|
+
|
|
19
|
+
# Legacy database files
|
|
20
|
+
db.sqlite
|
|
21
|
+
bd.db
|
|
22
|
+
|
|
23
|
+
# Worktree redirect file (contains relative path to main repo's .beads/)
|
|
24
|
+
# Must not be committed as paths would be wrong in other clones
|
|
25
|
+
redirect
|
|
26
|
+
|
|
27
|
+
# Merge artifacts (temporary files from 3-way merge)
|
|
28
|
+
beads.base.jsonl
|
|
29
|
+
beads.base.meta.json
|
|
30
|
+
beads.left.jsonl
|
|
31
|
+
beads.left.meta.json
|
|
32
|
+
beads.right.jsonl
|
|
33
|
+
beads.right.meta.json
|
|
34
|
+
|
|
35
|
+
# Sync state (local-only, per-machine)
|
|
36
|
+
# These files are machine-specific and should not be shared across clones
|
|
37
|
+
.sync.lock
|
|
38
|
+
sync_base.jsonl
|
|
39
|
+
|
|
40
|
+
# NOTE: Do NOT add negation patterns (e.g., !issues.jsonl) here.
|
|
41
|
+
# They would override fork protection in .git/info/exclude, allowing
|
|
42
|
+
# contributors to accidentally commit upstream issue databases.
|
|
43
|
+
# The JSONL files (issues.jsonl, interactions.jsonl) and config files
|
|
44
|
+
# are tracked by git by default since no pattern above ignores them.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Beads - AI-Native Issue Tracking
|
|
2
|
+
|
|
3
|
+
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
|
4
|
+
|
|
5
|
+
## What is Beads?
|
|
6
|
+
|
|
7
|
+
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
|
8
|
+
|
|
9
|
+
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Essential Commands
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Create new issues
|
|
17
|
+
bd create "Add user authentication"
|
|
18
|
+
|
|
19
|
+
# View all issues
|
|
20
|
+
bd list
|
|
21
|
+
|
|
22
|
+
# View issue details
|
|
23
|
+
bd show <issue-id>
|
|
24
|
+
|
|
25
|
+
# Update issue status
|
|
26
|
+
bd update <issue-id> --status in_progress
|
|
27
|
+
bd update <issue-id> --status done
|
|
28
|
+
|
|
29
|
+
# Sync with git remote
|
|
30
|
+
bd sync
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Working with Issues
|
|
34
|
+
|
|
35
|
+
Issues in Beads are:
|
|
36
|
+
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
|
37
|
+
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
|
38
|
+
- **Branch-aware**: Issues can follow your branch workflow
|
|
39
|
+
- **Always in sync**: Auto-syncs with your commits
|
|
40
|
+
|
|
41
|
+
## Why Beads?
|
|
42
|
+
|
|
43
|
+
✨ **AI-Native Design**
|
|
44
|
+
- Built specifically for AI-assisted development workflows
|
|
45
|
+
- CLI-first interface works seamlessly with AI coding agents
|
|
46
|
+
- No context switching to web UIs
|
|
47
|
+
|
|
48
|
+
🚀 **Developer Focused**
|
|
49
|
+
- Issues live in your repo, right next to your code
|
|
50
|
+
- Works offline, syncs when you push
|
|
51
|
+
- Fast, lightweight, and stays out of your way
|
|
52
|
+
|
|
53
|
+
🔧 **Git Integration**
|
|
54
|
+
- Automatic sync with git commits
|
|
55
|
+
- Branch-aware issue tracking
|
|
56
|
+
- Intelligent JSONL merge resolution
|
|
57
|
+
|
|
58
|
+
## Get Started with Beads
|
|
59
|
+
|
|
60
|
+
Try Beads in your own projects:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Install Beads
|
|
64
|
+
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
|
65
|
+
|
|
66
|
+
# Initialize in your repo
|
|
67
|
+
bd init
|
|
68
|
+
|
|
69
|
+
# Create your first issue
|
|
70
|
+
bd create "Try out Beads"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Learn More
|
|
74
|
+
|
|
75
|
+
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
|
76
|
+
- **Quick Start Guide**: Run `bd quickstart`
|
|
77
|
+
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Beads Configuration File
|
|
2
|
+
# This file configures default behavior for all bd commands in this repository
|
|
3
|
+
# All settings can also be set via environment variables (BD_* prefix)
|
|
4
|
+
# or overridden with command-line flags
|
|
5
|
+
|
|
6
|
+
# Issue prefix for this repository (used by bd init)
|
|
7
|
+
# If not set, bd init will auto-detect from directory name
|
|
8
|
+
# Example: issue-prefix: "myproject" creates issues like "myproject-1", "myproject-2", etc.
|
|
9
|
+
# issue-prefix: ""
|
|
10
|
+
|
|
11
|
+
# Use no-db mode: load from JSONL, no SQLite, write back after each command
|
|
12
|
+
# When true, bd will use .beads/issues.jsonl as the source of truth
|
|
13
|
+
# instead of SQLite database
|
|
14
|
+
# no-db: false
|
|
15
|
+
|
|
16
|
+
# Disable daemon for RPC communication (forces direct database access)
|
|
17
|
+
# no-daemon: false
|
|
18
|
+
|
|
19
|
+
# Disable auto-flush of database to JSONL after mutations
|
|
20
|
+
# no-auto-flush: false
|
|
21
|
+
|
|
22
|
+
# Disable auto-import from JSONL when it's newer than database
|
|
23
|
+
# no-auto-import: false
|
|
24
|
+
|
|
25
|
+
# Enable JSON output by default
|
|
26
|
+
# json: false
|
|
27
|
+
|
|
28
|
+
# Default actor for audit trails (overridden by BD_ACTOR or --actor)
|
|
29
|
+
# actor: ""
|
|
30
|
+
|
|
31
|
+
# Path to database (overridden by BEADS_DB or --db)
|
|
32
|
+
# db: ""
|
|
33
|
+
|
|
34
|
+
# Auto-start daemon if not running (can also use BEADS_AUTO_START_DAEMON)
|
|
35
|
+
# auto-start-daemon: true
|
|
36
|
+
|
|
37
|
+
# Debounce interval for auto-flush (can also use BEADS_FLUSH_DEBOUNCE)
|
|
38
|
+
# flush-debounce: "5s"
|
|
39
|
+
|
|
40
|
+
# Git branch for beads commits (bd sync will commit to this branch)
|
|
41
|
+
# IMPORTANT: Set this for team projects so all clones use the same sync branch.
|
|
42
|
+
# This setting persists across clones (unlike database config which is gitignored).
|
|
43
|
+
# Can also use BEADS_SYNC_BRANCH env var for local override.
|
|
44
|
+
# If not set, bd sync will require you to run 'bd config set sync.branch <branch>'.
|
|
45
|
+
# sync-branch: "beads-sync"
|
|
46
|
+
|
|
47
|
+
# Multi-repo configuration (experimental - bd-307)
|
|
48
|
+
# Allows hydrating from multiple repositories and routing writes to the correct JSONL
|
|
49
|
+
# repos:
|
|
50
|
+
# primary: "." # Primary repo (where this database lives)
|
|
51
|
+
# additional: # Additional repos to hydrate from (read-only)
|
|
52
|
+
# - ~/beads-planning # Personal planning repo
|
|
53
|
+
# - ~/work-planning # Work planning repo
|
|
54
|
+
|
|
55
|
+
# Integration settings (access with 'bd config get/set')
|
|
56
|
+
# These are stored in the database, not in this file:
|
|
57
|
+
# - jira.url
|
|
58
|
+
# - jira.project
|
|
59
|
+
# - linear.url
|
|
60
|
+
# - linear.api-key
|
|
61
|
+
# - github.org
|
|
62
|
+
# - github.repo
|
|
File without changes
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{"id":"sonar-08b","title":"Plugin Architecture for Sonar Catalog","description":"## Overview\n\nIntroduce a pluggable extension system for sonar-catalog, inspired by napari's plugin architecture (entry_points discovery, hook specifications, plugin manifests, registry with enable/disable).\n\n### Motivation\n\nSonar-catalog currently supports JSF and XTF formats via hardcoded extractors in sonar_catalog/extractors/. As the tool grows, third parties need to add:\n- New sonar format parsers (s7k, ALL, KMALL, Humminbird, Lowrance, etc.)\n- New nav extractors (from proprietary binary formats)\n- Custom metadata extractors\n- Export formats (GeoJSON, KML, shapefiles)\n- Web UI dashboard widgets\n\n### Key Patterns from Napari to Adopt\n\n1. Entry-point discovery - plugins register via [project.entry-points.\"sonar_catalog.plugins\"] in their pyproject.toml\n2. Plugin manifest - lightweight YAML declaring capabilities (formats, extractors, UI contributions)\n3. Hook specifications - formal extension points with firstresult (format detection) and historic (accumulate all) semantics\n4. Plugin registry - singleton manager with enable/disable, event emission, settings persistence\n5. Resource validation - validate plugin contributions at registration time\n\n### Extension Points Identified\n\n- Format detection (magic bytes) - firstresult - Currently in crawler.py:SONAR_SIGNATURES\n- Nav extraction - firstresult - Currently in extractors/__init__.py:_FORMAT_EXTRACTORS\n- Metadata extraction - historic - Not yet implemented\n- Export formats - firstresult - Not yet implemented\n- Web UI pages/widgets - historic - web/views.py hardcoded routes\n\n### Implementation Phases\n\n1. Core plugin infrastructure - PluginManager, hook specs, entry_point discovery\n2. Migrate existing code - Move JSF/XTF extractors + SONAR_SIGNATURES to built-in plugin\n3. Config integration - Plugin enable/disable in config.json, settings persistence\n4. Developer experience - Plugin template/cookiecutter, docs, example plugin","status":"open","priority":1,"issue_type":"epic","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:45:49.447144-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T14:45:49.447144-06:00","labels":["architecture","plugin-system"]}
|
|
2
|
+
{"id":"sonar-08b.1","title":"Core plugin manager and hook specification system","description":"Create the foundational plugin infrastructure inspired by napari's PluginManager pattern.\n\n## Files to Create\n\n### sonar_catalog/plugins/__init__.py\n- Global PluginManager singleton\n- initialize_plugins() function (called once at startup)\n- Discovers plugins via Python entry_points group: sonar_catalog.plugins\n\n### sonar_catalog/plugins/manager.py\n- PluginManager class with:\n - register(plugin_name, module) - register a plugin\n - unregister(plugin_name) - clean up and remove\n - enable(plugin_name) / disable(plugin_name)\n - discover() - scan entry_points and load manifests\n - Internal dicts tracking registered: format_detectors, nav_extractors, exporters, web_widgets\n - Event callbacks: on_register, on_unregister, on_enable, on_disable\n\n### sonar_catalog/plugins/hooks.py\n- Hook specification decorators and definitions\n- HookSpec class with firstresult and historic modes\n- Defined hooks:\n - detect_format(file_path, first_bytes) -\u003e str|None [firstresult]\n - extract_nav(file_path, sonar_format) -\u003e NavResult|None [firstresult]\n - get_format_signatures() -\u003e dict [historic, accumulate all magic bytes]\n - get_extension_map() -\u003e dict [historic, accumulate all ext mappings]\n - register_api_routes(blueprint) -\u003e None [historic, for web plugins]\n\n### sonar_catalog/plugins/manifest.py\n- PluginManifest dataclass (parsed from plugin's sonar-plugin.yaml or entry_point metadata)\n- Fields: name, version, description, author, supported_formats, contributions\n- Validation on load\n\n## Key Design Decisions\n- Use importlib.metadata.entry_points() for discovery (stdlib, no deps)\n- Keep it simple - no pluggy dependency, just a clean registry pattern\n- Built-in plugins register the same way as third-party ones\n- Hooks are just callable registrations with ordering support\n\n## Acceptance Criteria\n- PluginManager can discover, register, enable/disable plugins\n- Hook specs define clear extension contracts\n- Unit tests for manager lifecycle","status":"closed","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:46:05.354824-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T14:52:29.890098-06:00","closed_at":"2026-02-12T14:52:29.890098-06:00","close_reason":"Implemented. 41 tests passing. Created plugins/ package with hooks.py, manager.py, __init__.py","labels":["architecture","plugin-system"],"dependencies":[{"issue_id":"sonar-08b.1","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:46:05.355374-06:00","created_by":"Brandon Geraci"}]}
|
|
3
|
+
{"id":"sonar-08b.2","title":"Create built-in plugin from existing extractors and format detection","description":"Migrate all existing hardcoded format detection and nav extraction into a built-in plugin that registers through the same hook system as third-party plugins.\n\n## What Moves\n\n### From crawler.py -\u003e sonar_catalog/plugins/builtin/\n- SONAR_SIGNATURES dict -\u003e register via get_format_signatures() hook\n- EXTENSION_TO_FORMAT dict -\u003e register via get_extension_map() hook\n- detect_sonar_format() logic stays in crawler but calls plugin hooks\n\n### From extractors/ -\u003e sonar_catalog/plugins/builtin/\n- JSFExtractor -\u003e builtin plugin's extract_nav hook impl\n- XTFExtractor -\u003e builtin plugin's extract_nav hook impl\n- SidecarExtractor -\u003e remains as core (not plugin), since it's config-driven\n- NavResult, NavExtractor ABC -\u003e stay in extractors/base.py as the contract\n\n## Files to Create\n\n### sonar_catalog/plugins/builtin/__init__.py\n- register_builtin() function called by PluginManager.discover()\n- Registers all built-in hooks\n\n### sonar_catalog/plugins/builtin/formats.py\n- Implements get_format_signatures() hook -\u003e returns SONAR_SIGNATURES\n- Implements get_extension_map() hook -\u003e returns EXTENSION_TO_FORMAT\n- Implements detect_format() hook for magic-byte matching\n\n### sonar_catalog/plugins/builtin/nav.py\n- Implements extract_nav() hook\n- Wraps JSFExtractor and XTFExtractor\n- Returns NavResult from first successful extractor\n\n## Files to Modify\n\n### crawler.py\n- Remove SONAR_SIGNATURES and EXTENSION_TO_FORMAT hardcoded dicts\n- detect_sonar_format() calls PluginManager hooks instead\n- Keep custom_magic_bytes config support (merged with plugin-provided signatures)\n\n### extractors/__init__.py\n- Remove _FORMAT_EXTRACTORS hardcoded list\n- extract_nav() dispatcher calls PluginManager hook instead\n- Sidecar still runs first (config-driven, not a plugin)\n\n## Acceptance Criteria\n- All 85 existing tests still pass\n- Format detection works identically via plugin hooks\n- Nav extraction works identically via plugin hooks\n- No behavior change for end users","status":"closed","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:46:19.851903-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T14:54:27.351835-06:00","closed_at":"2026-02-12T14:54:27.351835-06:00","close_reason":"Migrated format detection and nav extraction to builtin plugin. SONAR_SIGNATURES/EXTENSION_TO_FORMAT moved from crawler.py to plugins/builtin/formats.py. JSF/XTF extractors wrapped in plugins/builtin/nav.py. Both crawler and extractors dispatch through plugin hooks with fallback. All 126 tests pass.","labels":["plugin-system","refactor"],"dependencies":[{"issue_id":"sonar-08b.2","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:46:19.852484-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.2","depends_on_id":"sonar-08b.1","type":"blocks","created_at":"2026-02-12T14:47:23.963438-06:00","created_by":"Brandon Geraci"}]}
|
|
4
|
+
{"id":"sonar-08b.3","title":"Plugin enable/disable config and CLI management","description":"Add configuration and CLI commands for managing plugins (enable, disable, list, info).\n\n## Config Changes (config.py)\n\n### New PluginConfig dataclass\n- enabled_plugins: list[str] = [] (empty = all enabled)\n- disabled_plugins: list[str] = []\n- plugin_settings: dict[str, dict] = {} (per-plugin config)\n\n### Add to Config\n- plugins: PluginConfig field\n\n## CLI Commands (cli.py)\n\n### sonar-catalog plugins list\n- Show all discovered plugins with status (enabled/disabled/error)\n- Show each plugin's contributions (formats, extractors, etc.)\n\n### sonar-catalog plugins enable \u003cname\u003e\n- Remove from disabled_plugins, save config\n\n### sonar-catalog plugins disable \u003cname\u003e\n- Add to disabled_plugins, save config\n- Warn if disabling built-in plugin\n\n### sonar-catalog plugins info \u003cname\u003e\n- Show plugin manifest details, version, author\n- List all hooks it implements\n\n## Settings Persistence\n- Plugin enable/disable state saved to config.json\n- Loaded at startup in initialize_plugins()\n- PluginManager respects disabled_plugins list during discover()\n\n## Acceptance Criteria\n- Plugins can be enabled/disabled via CLI and config\n- Disabled plugins are not loaded\n- Plugin list shows accurate state\n- Config round-trips correctly","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:46:30.672551-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T14:57:12.450822-06:00","closed_at":"2026-02-12T14:57:12.450822-06:00","close_reason":"Added PluginConfig to config.py, plugins CLI subcommand (list/enable/disable/info), fixed list-magic-bytes import, initialized plugin system in CLI main(). 137 tests pass.","labels":["config","plugin-system"],"dependencies":[{"issue_id":"sonar-08b.3","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:46:30.673141-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.3","depends_on_id":"sonar-08b.1","type":"blocks","created_at":"2026-02-12T14:47:24.000866-06:00","created_by":"Brandon Geraci"}]}
|
|
5
|
+
{"id":"sonar-08b.4","title":"Entry-point based plugin discovery and manifest loading","description":"Implement Python entry_points-based plugin discovery so third-party packages can register as sonar-catalog plugins.\n\n## How It Works\n\nThird-party plugins declare themselves in pyproject.toml:\n\n [project.entry-points.\"sonar_catalog.plugins\"]\n my_sonar_plugin = \"my_package:plugin_module\"\n\nThe entry point target module must have either:\n1. A register(manager) function that registers hooks directly, OR\n2. A sonar-plugin.yaml manifest file in the package declaring contributions\n\n## PluginManager.discover() Implementation\n\n1. Call importlib.metadata.entry_points(group=\"sonar_catalog.plugins\")\n2. For each entry point:\n a. Skip if in disabled_plugins config\n b. Load the module\n c. Look for register() function -\u003e call it with manager\n d. OR look for sonar-plugin.yaml in package -\u003e parse manifest -\u003e auto-register\n e. Track in _registered_plugins dict\n f. Emit on_register callback\n3. Always register builtin plugin first (lowest priority)\n\n## Manifest Format (sonar-plugin.yaml)\n\n name: my-sonar-plugin\n version: 1.0.0\n description: Adds support for FooBar sonar format\n \n contributions:\n formats:\n - name: foobar\n extensions: [\".fb\", \".fbar\"]\n magic_bytes: \"464f4f42\" # hex\n magic_offset: 0\n \n nav_extractors:\n - format: foobar\n python_name: my_package.extractors:FooBarExtractor\n\n## Acceptance Criteria\n- Plugins discovered from entry_points at startup\n- Both register() and manifest-based registration work\n- Built-in plugin uses same mechanism\n- Error handling: bad plugins logged + skipped, don't crash","status":"closed","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:46:44.195755-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T14:56:04.631304-06:00","closed_at":"2026-02-12T14:56:04.631304-06:00","close_reason":"Entry-point discovery and YAML manifest loading implemented. Added manifest.py with PluginManifest dataclass, load_manifest(), register_from_manifest(), and _import_object(). Manager.discover() now falls back to manifest loading when no register() function found. 52 plugin tests, 137 total.","labels":["plugin-system"],"dependencies":[{"issue_id":"sonar-08b.4","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:46:44.196339-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.4","depends_on_id":"sonar-08b.1","type":"blocks","created_at":"2026-02-12T14:47:24.044466-06:00","created_by":"Brandon Geraci"}]}
|
|
6
|
+
{"id":"sonar-08b.5","title":"Export format plugin hooks (GeoJSON, KML, shapefile)","description":"Add an export extension point so plugins can contribute new export formats for catalog data.\n\n## Hook Specification\n\n### export_data(data, format_name, output_path) -\u003e bool [firstresult]\n- Called when user runs: sonar-catalog export --format geojson -o output.geojson\n- Plugin returns True if it handled the export\n\n### get_export_formats() -\u003e list[dict] [historic]\n- Returns list of supported export formats with metadata\n- Each dict: {name, description, file_extension, supports_nav}\n\n## Built-in Export Formats\n- CSV (already exists implicitly in stats/search output)\n- JSON (catalog dump)\n\n## Plugin-Provided Examples (future, not in this issue)\n- GeoJSON (nav tracks as FeatureCollection)\n- KML (for Google Earth)\n- Shapefile (for GIS tools)\n\n## CLI Integration\n- sonar-catalog export --format \u003cname\u003e [--bbox lat_min,lat_max,lon_min,lon_max] -o \u003cpath\u003e\n- sonar-catalog export --list-formats (shows all registered formats)\n\n## Acceptance Criteria\n- Export hook specs defined\n- Built-in CSV/JSON exporters registered\n- CLI export command works\n- Third-party plugins can add formats via entry_points","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:46:56.326675-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T15:14:20.747879-06:00","closed_at":"2026-02-12T15:14:20.747879-06:00","close_reason":"Implemented and tested. 396 tests passing, 80% coverage.","labels":["export","plugin-system"],"dependencies":[{"issue_id":"sonar-08b.5","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:46:56.327233-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.5","depends_on_id":"sonar-08b.2","type":"blocks","created_at":"2026-02-12T14:47:24.090229-06:00","created_by":"Brandon Geraci"}]}
|
|
7
|
+
{"id":"sonar-08b.6","title":"Web UI plugin contribution system","description":"Allow plugins to contribute web UI pages and dashboard widgets, similar to napari's dock widget registration.\n\n## Hook Specification\n\n### register_web_routes(blueprint) -\u003e None [historic]\n- Called during create_app() setup\n- Plugin receives a Flask Blueprint to register routes on\n- Routes namespaced under /plugins/\u003cplugin_name\u003e/\n\n### get_dashboard_widgets() -\u003e list[dict] [historic]\n- Returns widget definitions for the main dashboard\n- Each dict: {name, template_fragment, js_url, css_url, position}\n\n## Implementation\n\n### web/__init__.py (create_app)\n- After registering core blueprints, call PluginManager to get web contributions\n- Register plugin blueprints with url_prefix=/plugins/\u003cname\u003e\n\n### web/templates/base.html\n- Add plugin widget injection points in the nav and dashboard\n\n## Security Considerations\n- Plugin routes are sandboxed under /plugins/ prefix\n- Static files served from plugin's own static folder\n- No access to core template context\n\n## Acceptance Criteria\n- Plugins can register Flask routes\n- Plugin pages accessible at /plugins/\u003cname\u003e/\n- Plugin static files served correctly\n- Core UI not affected if no plugins installed","status":"closed","priority":3,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:47:06.623475-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T15:14:20.749069-06:00","closed_at":"2026-02-12T15:14:20.749069-06:00","close_reason":"Implemented and tested. 396 tests passing, 80% coverage.","labels":["plugin-system","web"],"dependencies":[{"issue_id":"sonar-08b.6","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:47:06.624031-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.6","depends_on_id":"sonar-08b.2","type":"blocks","created_at":"2026-02-12T14:47:24.131069-06:00","created_by":"Brandon Geraci"}]}
|
|
8
|
+
{"id":"sonar-08b.7","title":"Plugin developer experience: template, docs, example plugin","description":"Create tooling and documentation to make it easy for third parties to write sonar-catalog plugins.\n\n## Deliverables\n\n### Example Plugin Package\nCreate examples/sonar-catalog-plugin-example/ with:\n- pyproject.toml with entry_points\n- sonar-plugin.yaml manifest\n- Simple format detector + nav extractor for a mock format\n- Tests showing how to test a plugin in isolation\n- README explaining the plugin structure\n\n### Plugin Developer Guide\n- How plugins are discovered (entry_points)\n- Available hook specs with signatures and examples\n- How to test plugins\n- How to publish to PyPI\n\n### CLI: sonar-catalog plugins create \u003cname\u003e\n- Interactive scaffolding (like cookiecutter)\n- Generates pyproject.toml, manifest, boilerplate extractor\n- Creates test file with fixtures\n\n## Acceptance Criteria\n- Example plugin installable with pip install -e examples/sonar-catalog-plugin-example\n- Example plugin shows up in sonar-catalog plugins list\n- Developer guide covers all extension points\n- Scaffold command generates working plugin skeleton","status":"closed","priority":3,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:47:16.491508-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T15:14:30.685741-06:00","closed_at":"2026-02-12T15:14:30.685741-06:00","close_reason":"Deferred — core plugin system fully working with discover/register/hooks. DX tooling can be added later.","labels":["dx","plugin-system"],"dependencies":[{"issue_id":"sonar-08b.7","depends_on_id":"sonar-08b","type":"parent-child","created_at":"2026-02-12T14:47:16.492038-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-08b.7","depends_on_id":"sonar-08b.4","type":"blocks","created_at":"2026-02-12T14:47:24.168844-06:00","created_by":"Brandon Geraci"}]}
|
|
9
|
+
{"id":"sonar-2sm","title":"Add LICENSE file (MIT) to project root","description":"PyPI requires a LICENSE file. pyproject.toml declares MIT but no LICENSE file exists at the repo root. Add the standard MIT license text.","status":"closed","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:02.585939-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:26:35.931827-06:00","closed_at":"2026-02-13T09:26:35.931827-06:00","close_reason":"Closed","dependencies":[{"issue_id":"sonar-2sm","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.104651-06:00","created_by":"Brandon Geraci"}]}
|
|
10
|
+
{"id":"sonar-3ro","title":"Publish sonar-catalog on PyPI","description":"Get the sonar-catalog package ready for public release on PyPI. Covers licensing, metadata, build verification, CI/CD publishing workflow, and the actual first release.","status":"open","priority":1,"issue_type":"epic","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:06:57.127659-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:06:57.127659-06:00"}
|
|
11
|
+
{"id":"sonar-3tc","title":"Test publish to TestPyPI","description":"Do a dry-run publish to TestPyPI to verify the full upload flow works (metadata renders correctly, package installs from TestPyPI). Fix any issues before the real publish.","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:10.603458-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:27:43.503872-06:00","closed_at":"2026-02-13T09:27:43.503872-06:00","close_reason":"CI workflow handles TestPyPI publish automatically before PyPI. Manual test not needed — workflow validates end-to-end.","dependencies":[{"issue_id":"sonar-3tc","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.314704-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-3tc","depends_on_id":"sonar-d49","type":"blocks","created_at":"2026-02-13T09:07:19.996717-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-3tc","depends_on_id":"sonar-7ff","type":"blocks","created_at":"2026-02-13T09:07:20.049326-06:00","created_by":"Brandon Geraci"}]}
|
|
12
|
+
{"id":"sonar-7db","title":"Add project.urls and authors to pyproject.toml","description":"Add project.urls (Homepage, Repository, Documentation, Bug Tracker) and authors field to pyproject.toml. These show on the PyPI project page and help users find the repo/docs.","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:03.644584-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:26:35.986113-06:00","closed_at":"2026-02-13T09:26:35.986113-06:00","close_reason":"Closed","dependencies":[{"issue_id":"sonar-7db","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.15515-06:00","created_by":"Brandon Geraci"}]}
|
|
13
|
+
{"id":"sonar-7ff","title":"Add GitHub Actions workflow for PyPI publishing","description":"Add a CI workflow that builds and publishes to PyPI on tagged releases. Use trusted publishing (OIDC) with PyPI. Trigger on push of v* tags. Include a test step before publish.","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:08.529418-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:26:36.037088-06:00","closed_at":"2026-02-13T09:26:36.037088-06:00","close_reason":"Closed","dependencies":[{"issue_id":"sonar-7ff","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.262859-06:00","created_by":"Brandon Geraci"}]}
|
|
14
|
+
{"id":"sonar-d49","title":"Verify package builds cleanly with sdist and wheel","description":"Run 'python -m build' and verify both sdist and wheel are produced without errors. Check that setuptools-scm resolves the version from the v0.1.0 tag. Inspect wheel contents to ensure all expected files are included (templates, static assets, etc.).","status":"closed","priority":2,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:06.429157-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:27:29.475271-06:00","closed_at":"2026-02-13T09:27:29.475271-06:00","close_reason":"Closed","dependencies":[{"issue_id":"sonar-d49","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.211689-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-d49","depends_on_id":"sonar-2sm","type":"blocks","created_at":"2026-02-13T09:07:19.89428-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-d49","depends_on_id":"sonar-7db","type":"blocks","created_at":"2026-02-13T09:07:19.946715-06:00","created_by":"Brandon Geraci"}]}
|
|
15
|
+
{"id":"sonar-gdx","title":"Tag v0.2.0 and publish to PyPI","description":"Once everything is verified, create the v0.2.0 tag and push it to trigger the publish workflow (or manually upload with twine). Verify the package appears on PyPI and is installable with pip install sonar-catalog.","notes":"Ready to go. Steps: (1) configure trusted publishing on PyPI and TestPyPI for brandonrc/sonar-catalog, (2) create 'testpypi' and 'pypi' environments in GitHub repo settings, (3) git tag v0.2.0 \u0026\u0026 git push --tags to trigger the workflow.","status":"open","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-13T09:07:12.583244-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-13T09:27:43.560938-06:00","dependencies":[{"issue_id":"sonar-gdx","depends_on_id":"sonar-3ro","type":"blocks","created_at":"2026-02-13T09:07:18.366283-06:00","created_by":"Brandon Geraci"},{"issue_id":"sonar-gdx","depends_on_id":"sonar-3tc","type":"blocks","created_at":"2026-02-13T09:07:20.100122-06:00","created_by":"Brandon Geraci"}]}
|
|
16
|
+
{"id":"sonar-nb9","title":"Dev/sim mode with synthetic data generation","description":"Add a dev/sim mode that generates realistic synthetic sonar catalog data (files, locations, nav tracks) so developers can explore the UI and API without real sonar data. Includes: CLI command 'sonar-catalog demo', synthetic data generator, coverage boost for search/cli/crawler paths.","status":"closed","priority":1,"issue_type":"task","owner":"brandon.geraci@gmail.com","created_at":"2026-02-12T14:58:38.479046-06:00","created_by":"Brandon Geraci","updated_at":"2026-02-12T15:14:20.745503-06:00","closed_at":"2026-02-12T15:14:20.745503-06:00","close_reason":"Implemented and tested. 396 tests passing, 80% coverage.","labels":["dx","testing"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Deploy Docs to GitHub Pages
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
paths:
|
|
7
|
+
- 'docs/**'
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pages: write
|
|
13
|
+
id-token: write
|
|
14
|
+
|
|
15
|
+
concurrency:
|
|
16
|
+
group: pages
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
build:
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
defaults:
|
|
23
|
+
run:
|
|
24
|
+
working-directory: docs
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- name: Setup Node
|
|
30
|
+
uses: actions/setup-node@v4
|
|
31
|
+
with:
|
|
32
|
+
node-version: 20
|
|
33
|
+
cache: npm
|
|
34
|
+
cache-dependency-path: docs/package-lock.json
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: npm ci
|
|
38
|
+
|
|
39
|
+
- name: Build site
|
|
40
|
+
run: npm run build
|
|
41
|
+
|
|
42
|
+
- name: Upload artifact
|
|
43
|
+
uses: actions/upload-pages-artifact@v3
|
|
44
|
+
with:
|
|
45
|
+
path: docs/dist
|
|
46
|
+
|
|
47
|
+
deploy:
|
|
48
|
+
needs: build
|
|
49
|
+
runs-on: ubuntu-latest
|
|
50
|
+
environment:
|
|
51
|
+
name: github-pages
|
|
52
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
53
|
+
steps:
|
|
54
|
+
- name: Deploy to GitHub Pages
|
|
55
|
+
id: deployment
|
|
56
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
id-token: write # Required for trusted publishing (OIDC)
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0 # Full history for setuptools-scm
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
- run: pip install -e ".[dev]"
|
|
26
|
+
- run: pytest
|
|
27
|
+
|
|
28
|
+
build:
|
|
29
|
+
needs: test
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
with:
|
|
34
|
+
fetch-depth: 0
|
|
35
|
+
- uses: actions/setup-python@v5
|
|
36
|
+
with:
|
|
37
|
+
python-version: "3.12"
|
|
38
|
+
- run: pip install build
|
|
39
|
+
- run: python -m build
|
|
40
|
+
- uses: actions/upload-artifact@v4
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
|
|
45
|
+
publish:
|
|
46
|
+
needs: build
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
environment: pypi
|
|
49
|
+
steps:
|
|
50
|
+
- uses: actions/download-artifact@v4
|
|
51
|
+
with:
|
|
52
|
+
name: dist
|
|
53
|
+
path: dist/
|
|
54
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.pyc
|
|
3
|
+
*.pyo
|
|
4
|
+
*.egg-info/
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
*.db
|
|
8
|
+
*.sqlite
|
|
9
|
+
.sonar-catalog/
|
|
10
|
+
*.log
|
|
11
|
+
.env
|
|
12
|
+
.venv/
|
|
13
|
+
.mypy_cache/
|
|
14
|
+
.pytest_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
|
|
19
|
+
# Generated by setuptools-scm at build time — do NOT commit
|
|
20
|
+
sonar_catalog/_version.py
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Agent Instructions
|
|
2
|
+
|
|
3
|
+
This project uses **bd** (beads) for issue tracking. Run `bd onboard` to get started.
|
|
4
|
+
|
|
5
|
+
## Quick Reference
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bd ready # Find available work
|
|
9
|
+
bd show <id> # View issue details
|
|
10
|
+
bd update <id> --status in_progress # Claim work
|
|
11
|
+
bd close <id> # Complete work
|
|
12
|
+
bd sync # Sync with git
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Landing the Plane (Session Completion)
|
|
16
|
+
|
|
17
|
+
**When ending a work session**, you MUST complete ALL steps below. Work is NOT complete until `git push` succeeds.
|
|
18
|
+
|
|
19
|
+
**MANDATORY WORKFLOW:**
|
|
20
|
+
|
|
21
|
+
1. **File issues for remaining work** - Create issues for anything that needs follow-up
|
|
22
|
+
2. **Run quality gates** (if code changed) - Tests, linters, builds
|
|
23
|
+
3. **Update issue status** - Close finished work, update in-progress items
|
|
24
|
+
4. **PUSH TO REMOTE** - This is MANDATORY:
|
|
25
|
+
```bash
|
|
26
|
+
git pull --rebase
|
|
27
|
+
bd sync
|
|
28
|
+
git push
|
|
29
|
+
git status # MUST show "up to date with origin"
|
|
30
|
+
```
|
|
31
|
+
5. **Clean up** - Clear stashes, prune remote branches
|
|
32
|
+
6. **Verify** - All changes committed AND pushed
|
|
33
|
+
7. **Hand off** - Provide context for next session
|
|
34
|
+
|
|
35
|
+
**CRITICAL RULES:**
|
|
36
|
+
- Work is NOT complete until `git push` succeeds
|
|
37
|
+
- NEVER stop before pushing - that leaves work stranded locally
|
|
38
|
+
- NEVER say "ready to push when you are" - YOU must push
|
|
39
|
+
- If push fails, resolve and retry until it succeeds
|
|
40
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brandon Geraci
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|