specsmith 0.10.1.dev292__tar.gz → 0.10.1.dev294__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.
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/PKG-INFO +1 -1
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/pyproject.toml +1 -1
- specsmith-0.10.1.dev294/src/specsmith/esdb/__init__.py +20 -0
- specsmith-0.10.1.dev294/src/specsmith/esdb/bridge.py +137 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/governance_logic.py +18 -0
- specsmith-0.10.1.dev294/src/specsmith/mcp_generator.py +210 -0
- specsmith-0.10.1.dev294/src/specsmith/skills_builder.py +193 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/PKG-INFO +1 -1
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/SOURCES.txt +5 -0
- specsmith-0.10.1.dev294/tests/test_skills_mcp.py +109 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/LICENSE +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/README.md +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/setup.cfg +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/py.typed +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/session.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/epistemic/trace.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/__main__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/architect.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/auditor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/auth.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/block_export.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/cli.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/compliance.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/compressor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/config.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/context_window.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/credits.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/differ.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/doctor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/drive.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/editor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/executor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/exporter.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/history_search.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/importer.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/instinct.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/languages.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/ledger.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/patent.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/paths.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/phase.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/plugins.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/profiles.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/releaser.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/requirements.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/serve.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/session.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/session_init.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/skills.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/sync.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/tools.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/trace.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/updater.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/validator.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith/workspace.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_CMD_001.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_auditor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_cli.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_compliance.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_compressor.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_epistemic.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_importer.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_integrations.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_intelligence.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_mcp_client.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_new_modules.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_nexus.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_permissions.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_rate_limits.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_scaffolder.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_smoke.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_suggester.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_tools.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_validator.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_vcs.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_warp_parity.py +0 -0
- {specsmith-0.10.1.dev292 → specsmith-0.10.1.dev294}/tests/test_warp_parity_followup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.10.1.
|
|
3
|
+
Version: 0.10.1.dev294
|
|
4
4
|
Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
|
|
5
5
|
Author: BitConcepts
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.10.1.
|
|
7
|
+
version = "0.10.1.dev294"
|
|
8
8
|
description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""ChronoMemory ESDB Python bridge.
|
|
4
|
+
|
|
5
|
+
Provides a pure-Python adapter for the Rust ESDB engine.
|
|
6
|
+
Until PyO3 bindings are compiled, this module exposes the ESDB
|
|
7
|
+
data model as Python dataclasses that mirror the Rust types.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
__all__ = ["EsdbBridge", "is_esdb_available"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def is_esdb_available(project_dir: str = ".") -> bool:
|
|
16
|
+
"""Check if an ESDB exists for the given project."""
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
esdb_dir = Path(project_dir).resolve() / ".chronomemory"
|
|
20
|
+
return (esdb_dir / "events.wal").is_file()
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""ESDB bridge — adapter between .specsmith/ JSON and ESDB concepts.
|
|
4
|
+
|
|
5
|
+
This module provides read-only access to the current .specsmith/ flat JSON
|
|
6
|
+
state through ESDB-compatible query interfaces. It allows specsmith's
|
|
7
|
+
governance logic to work with either backend transparently.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
from typing import Any
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class EsdbRecord:
|
|
20
|
+
"""Python mirror of the Rust Record type."""
|
|
21
|
+
|
|
22
|
+
id: str
|
|
23
|
+
kind: str
|
|
24
|
+
status: str = "active"
|
|
25
|
+
confidence: float = 0.7
|
|
26
|
+
label: str = ""
|
|
27
|
+
data: dict[str, Any] = field(default_factory=dict)
|
|
28
|
+
source_ids: list[str] = field(default_factory=list)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class EsdbStatus:
|
|
33
|
+
"""ESDB health status for the REST API."""
|
|
34
|
+
|
|
35
|
+
available: bool
|
|
36
|
+
backend: str # "esdb" or "json-fallback"
|
|
37
|
+
record_count: int = 0
|
|
38
|
+
wal_seq: int = 0
|
|
39
|
+
epoch: int = 0
|
|
40
|
+
chain_valid: bool = True
|
|
41
|
+
|
|
42
|
+
def to_dict(self) -> dict[str, Any]:
|
|
43
|
+
return {
|
|
44
|
+
"available": self.available,
|
|
45
|
+
"backend": self.backend,
|
|
46
|
+
"record_count": self.record_count,
|
|
47
|
+
"wal_seq": self.wal_seq,
|
|
48
|
+
"epoch": self.epoch,
|
|
49
|
+
"chain_valid": self.chain_valid,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class EsdbBridge:
|
|
54
|
+
"""Read-only bridge to .specsmith/ JSON files using ESDB semantics.
|
|
55
|
+
|
|
56
|
+
When the Rust ESDB engine is available (via PyO3 bindings), this
|
|
57
|
+
class delegates to it. Otherwise, it reads the flat JSON files
|
|
58
|
+
directly and presents them through an ESDB-compatible interface.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(self, project_dir: str = ".") -> None:
|
|
62
|
+
self.root = Path(project_dir).resolve()
|
|
63
|
+
self._requirements: list[EsdbRecord] | None = None
|
|
64
|
+
self._testcases: list[EsdbRecord] | None = None
|
|
65
|
+
|
|
66
|
+
def status(self) -> EsdbStatus:
|
|
67
|
+
"""Return ESDB status."""
|
|
68
|
+
reqs = self._load_requirements()
|
|
69
|
+
tests = self._load_testcases()
|
|
70
|
+
return EsdbStatus(
|
|
71
|
+
available=True,
|
|
72
|
+
backend="json-fallback",
|
|
73
|
+
record_count=len(reqs) + len(tests),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
def requirements(self) -> list[EsdbRecord]:
|
|
77
|
+
"""Load requirements as ESDB records."""
|
|
78
|
+
return self._load_requirements()
|
|
79
|
+
|
|
80
|
+
def testcases(self) -> list[EsdbRecord]:
|
|
81
|
+
"""Load test cases as ESDB records."""
|
|
82
|
+
return self._load_testcases()
|
|
83
|
+
|
|
84
|
+
def record_counts(self) -> dict[str, int]:
|
|
85
|
+
"""Record counts by kind (for dashboard)."""
|
|
86
|
+
return {
|
|
87
|
+
"requirements": len(self._load_requirements()),
|
|
88
|
+
"testcases": len(self._load_testcases()),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
def _load_requirements(self) -> list[EsdbRecord]:
|
|
92
|
+
if self._requirements is not None:
|
|
93
|
+
return self._requirements
|
|
94
|
+
path = self.root / ".specsmith" / "requirements.json"
|
|
95
|
+
if not path.is_file():
|
|
96
|
+
self._requirements = []
|
|
97
|
+
return []
|
|
98
|
+
try:
|
|
99
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
100
|
+
self._requirements = [
|
|
101
|
+
EsdbRecord(
|
|
102
|
+
id=r.get("id", ""),
|
|
103
|
+
kind="requirement",
|
|
104
|
+
label=r.get("title", ""),
|
|
105
|
+
confidence=float(r.get("confidence", 0.7)),
|
|
106
|
+
data=r,
|
|
107
|
+
)
|
|
108
|
+
for r in raw
|
|
109
|
+
if isinstance(r, dict)
|
|
110
|
+
]
|
|
111
|
+
except (OSError, ValueError):
|
|
112
|
+
self._requirements = []
|
|
113
|
+
return self._requirements
|
|
114
|
+
|
|
115
|
+
def _load_testcases(self) -> list[EsdbRecord]:
|
|
116
|
+
if self._testcases is not None:
|
|
117
|
+
return self._testcases
|
|
118
|
+
path = self.root / ".specsmith" / "testcases.json"
|
|
119
|
+
if not path.is_file():
|
|
120
|
+
self._testcases = []
|
|
121
|
+
return []
|
|
122
|
+
try:
|
|
123
|
+
raw = json.loads(path.read_text(encoding="utf-8"))
|
|
124
|
+
self._testcases = [
|
|
125
|
+
EsdbRecord(
|
|
126
|
+
id=r.get("id", ""),
|
|
127
|
+
kind="testcase",
|
|
128
|
+
label=r.get("title", ""),
|
|
129
|
+
confidence=float(r.get("confidence", 1.0)),
|
|
130
|
+
data=r,
|
|
131
|
+
)
|
|
132
|
+
for r in raw
|
|
133
|
+
if isinstance(r, dict)
|
|
134
|
+
]
|
|
135
|
+
except (OSError, ValueError):
|
|
136
|
+
self._testcases = []
|
|
137
|
+
return self._testcases
|
|
@@ -614,6 +614,24 @@ class GovernanceHTTPServer:
|
|
|
614
614
|
except Exception as exc: # noqa: BLE001
|
|
615
615
|
self._json_err(str(exc), code=500)
|
|
616
616
|
|
|
617
|
+
# ── ESDB ──────────────────────────────────────────────
|
|
618
|
+
elif self.path == "/api/esdb/status":
|
|
619
|
+
try:
|
|
620
|
+
from specsmith.esdb.bridge import EsdbBridge
|
|
621
|
+
|
|
622
|
+
bridge = EsdbBridge(project_dir)
|
|
623
|
+
self._json_ok(bridge.status().to_dict())
|
|
624
|
+
except Exception as exc: # noqa: BLE001
|
|
625
|
+
self._json_err(str(exc), code=500)
|
|
626
|
+
elif self.path == "/api/esdb/counts":
|
|
627
|
+
try:
|
|
628
|
+
from specsmith.esdb.bridge import EsdbBridge
|
|
629
|
+
|
|
630
|
+
bridge = EsdbBridge(project_dir)
|
|
631
|
+
self._json_ok(bridge.record_counts())
|
|
632
|
+
except Exception as exc: # noqa: BLE001
|
|
633
|
+
self._json_err(str(exc), code=500)
|
|
634
|
+
|
|
617
635
|
# ── Datasources ────────────────────────────────────────
|
|
618
636
|
elif self.path == "/api/datasources":
|
|
619
637
|
try:
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""MCP Server Generator — auto-scaffold Model Context Protocol servers.
|
|
4
|
+
|
|
5
|
+
Generates Python MCP servers from natural-language tool descriptions using
|
|
6
|
+
the FastMCP pattern. Each generated server includes a `server.py`,
|
|
7
|
+
`tool_schema.json`, and `README.md`.
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from specsmith.mcp_generator import generate_mcp_server, list_mcp_servers
|
|
11
|
+
server = generate_mcp_server("Search USPTO patents by keyword")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class MCPServerSpec:
|
|
26
|
+
"""Specification for a generated MCP server."""
|
|
27
|
+
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
description: str
|
|
31
|
+
tools: list[MCPToolSpec] = field(default_factory=list)
|
|
32
|
+
transport: str = "stdio" # "stdio" or "http"
|
|
33
|
+
port: int = 8100
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> dict[str, Any]:
|
|
36
|
+
return {
|
|
37
|
+
"id": self.id,
|
|
38
|
+
"name": self.name,
|
|
39
|
+
"description": self.description,
|
|
40
|
+
"tools": [t.to_dict() for t in self.tools],
|
|
41
|
+
"transport": self.transport,
|
|
42
|
+
"port": self.port,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@dataclass
|
|
47
|
+
class MCPToolSpec:
|
|
48
|
+
"""Specification for a single MCP tool."""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
description: str
|
|
52
|
+
input_params: dict[str, str] = field(default_factory=dict)
|
|
53
|
+
output_type: str = "text"
|
|
54
|
+
|
|
55
|
+
def to_dict(self) -> dict[str, Any]:
|
|
56
|
+
return {
|
|
57
|
+
"name": self.name,
|
|
58
|
+
"description": self.description,
|
|
59
|
+
"input_params": self.input_params,
|
|
60
|
+
"output_type": self.output_type,
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _generate_server_id(name: str) -> str:
|
|
65
|
+
slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
|
|
66
|
+
return f"mcp-{slug}-{uuid.uuid4().hex[:6]}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _generate_server_py(spec: MCPServerSpec) -> str:
|
|
70
|
+
"""Generate a Python MCP server file."""
|
|
71
|
+
tool_funcs = []
|
|
72
|
+
for tool in spec.tools:
|
|
73
|
+
params = ", ".join(f"{k}: str" for k in tool.input_params)
|
|
74
|
+
func = f'''
|
|
75
|
+
@mcp.tool()
|
|
76
|
+
def {tool.name}({params}) -> dict:
|
|
77
|
+
"""{tool.description}"""
|
|
78
|
+
# TODO: implement actual logic
|
|
79
|
+
return {{"result": "stub response", "tool": "{tool.name}"}}
|
|
80
|
+
'''
|
|
81
|
+
tool_funcs.append(func)
|
|
82
|
+
|
|
83
|
+
transport_line = (
|
|
84
|
+
f' mcp.run(transport="streamable-http", host="127.0.0.1", port={spec.port})'
|
|
85
|
+
if spec.transport == "http"
|
|
86
|
+
else ' mcp.run(transport="stdio")'
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
return f'''#!/usr/bin/env python3
|
|
90
|
+
# Auto-generated MCP server: {spec.name}
|
|
91
|
+
# Generated by specsmith mcp generate
|
|
92
|
+
|
|
93
|
+
from mcp.server.fastmcp import FastMCP
|
|
94
|
+
|
|
95
|
+
mcp = FastMCP("{spec.name}")
|
|
96
|
+
{"".join(tool_funcs)}
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
{transport_line}
|
|
100
|
+
'''
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _generate_readme(spec: MCPServerSpec) -> str:
|
|
104
|
+
"""Generate README.md for the MCP server."""
|
|
105
|
+
tool_list = "\n".join(f"- **{t.name}**: {t.description}" for t in spec.tools)
|
|
106
|
+
return f"""# {spec.name}
|
|
107
|
+
|
|
108
|
+
{spec.description}
|
|
109
|
+
|
|
110
|
+
## Tools
|
|
111
|
+
|
|
112
|
+
{tool_list}
|
|
113
|
+
|
|
114
|
+
## Usage
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# stdio mode
|
|
118
|
+
python server.py
|
|
119
|
+
|
|
120
|
+
# HTTP mode (if configured)
|
|
121
|
+
python server.py
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
Add to your MCP client config:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{{
|
|
130
|
+
"mcpServers": {{
|
|
131
|
+
"{spec.id}": {{
|
|
132
|
+
"command": "python",
|
|
133
|
+
"args": ["server.py"]
|
|
134
|
+
}}
|
|
135
|
+
}}
|
|
136
|
+
}}
|
|
137
|
+
```
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def generate_mcp_server(
|
|
142
|
+
tool_description: str,
|
|
143
|
+
project_dir: str = ".",
|
|
144
|
+
transport: str = "stdio",
|
|
145
|
+
port: int = 8100,
|
|
146
|
+
) -> MCPServerSpec:
|
|
147
|
+
"""Generate an MCP server from a natural-language tool description.
|
|
148
|
+
|
|
149
|
+
Creates a server directory with `server.py`, `tool_schema.json`, and `README.md`.
|
|
150
|
+
"""
|
|
151
|
+
# Parse description into server + tool spec
|
|
152
|
+
name = tool_description.strip()[:50]
|
|
153
|
+
server_id = _generate_server_id(name)
|
|
154
|
+
tool_name = re.sub(r"[^a-z0-9_]+", "_", name.lower().strip())[:40]
|
|
155
|
+
|
|
156
|
+
tool = MCPToolSpec(
|
|
157
|
+
name=tool_name,
|
|
158
|
+
description=tool_description.strip(),
|
|
159
|
+
input_params={"query": "Search query or input"},
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
spec = MCPServerSpec(
|
|
163
|
+
id=server_id,
|
|
164
|
+
name=name,
|
|
165
|
+
description=tool_description.strip(),
|
|
166
|
+
tools=[tool],
|
|
167
|
+
transport=transport,
|
|
168
|
+
port=port,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
# Create server directory
|
|
172
|
+
server_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers" / server_id
|
|
173
|
+
server_dir.mkdir(parents=True, exist_ok=True)
|
|
174
|
+
|
|
175
|
+
# Write files
|
|
176
|
+
(server_dir / "server.py").write_text(_generate_server_py(spec), encoding="utf-8")
|
|
177
|
+
(server_dir / "tool_schema.json").write_text(
|
|
178
|
+
json.dumps(spec.to_dict(), indent=2, ensure_ascii=False), encoding="utf-8"
|
|
179
|
+
)
|
|
180
|
+
(server_dir / "README.md").write_text(_generate_readme(spec), encoding="utf-8")
|
|
181
|
+
|
|
182
|
+
return spec
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def list_mcp_servers(project_dir: str = ".") -> list[MCPServerSpec]:
|
|
186
|
+
"""List all generated MCP servers."""
|
|
187
|
+
servers_dir = Path(project_dir).resolve() / ".specsmith" / "mcp-servers"
|
|
188
|
+
if not servers_dir.is_dir():
|
|
189
|
+
return []
|
|
190
|
+
servers: list[MCPServerSpec] = []
|
|
191
|
+
for server_dir in sorted(servers_dir.iterdir()):
|
|
192
|
+
schema_path = server_dir / "tool_schema.json"
|
|
193
|
+
if schema_path.is_file():
|
|
194
|
+
try:
|
|
195
|
+
raw = json.loads(schema_path.read_text(encoding="utf-8"))
|
|
196
|
+
servers.append(
|
|
197
|
+
MCPServerSpec(
|
|
198
|
+
id=raw.get("id", ""),
|
|
199
|
+
name=raw.get("name", ""),
|
|
200
|
+
description=raw.get("description", ""),
|
|
201
|
+
transport=raw.get("transport", "stdio"),
|
|
202
|
+
port=raw.get("port", 8100),
|
|
203
|
+
)
|
|
204
|
+
)
|
|
205
|
+
except (OSError, ValueError):
|
|
206
|
+
continue
|
|
207
|
+
return servers
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
__all__ = ["MCPServerSpec", "MCPToolSpec", "generate_mcp_server", "list_mcp_servers"]
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs / BitConcepts, LLC.
|
|
3
|
+
"""AI-powered Skills Builder — generate agent skills from natural-language descriptions.
|
|
4
|
+
|
|
5
|
+
Skills follow the SkillNet-style ontology: each skill is a folder containing
|
|
6
|
+
a SKILL.md file with structured metadata (name, purpose, activation rules,
|
|
7
|
+
input/output schema, epistemic contract, tools used, tests required).
|
|
8
|
+
|
|
9
|
+
Usage:
|
|
10
|
+
from specsmith.skills_builder import build_skill, list_skills
|
|
11
|
+
skill = build_skill("Summarize a Python file into bullet points")
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import json
|
|
17
|
+
import re
|
|
18
|
+
import uuid
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class SkillSpec:
|
|
26
|
+
"""Structured specification for an agent skill."""
|
|
27
|
+
|
|
28
|
+
id: str
|
|
29
|
+
name: str
|
|
30
|
+
purpose: str
|
|
31
|
+
activation_rules: list[str] = field(default_factory=list)
|
|
32
|
+
input_schema: dict[str, str] = field(default_factory=dict)
|
|
33
|
+
output_schema: dict[str, str] = field(default_factory=dict)
|
|
34
|
+
epistemic_contract: str = ""
|
|
35
|
+
tools_used: list[str] = field(default_factory=list)
|
|
36
|
+
tests_required: list[str] = field(default_factory=list)
|
|
37
|
+
stop_conditions: list[str] = field(default_factory=list)
|
|
38
|
+
tags: list[str] = field(default_factory=list)
|
|
39
|
+
active: bool = False
|
|
40
|
+
|
|
41
|
+
def to_dict(self) -> dict[str, Any]:
|
|
42
|
+
return {
|
|
43
|
+
"id": self.id,
|
|
44
|
+
"name": self.name,
|
|
45
|
+
"purpose": self.purpose,
|
|
46
|
+
"activation_rules": self.activation_rules,
|
|
47
|
+
"input_schema": self.input_schema,
|
|
48
|
+
"output_schema": self.output_schema,
|
|
49
|
+
"epistemic_contract": self.epistemic_contract,
|
|
50
|
+
"tools_used": self.tools_used,
|
|
51
|
+
"tests_required": self.tests_required,
|
|
52
|
+
"stop_conditions": self.stop_conditions,
|
|
53
|
+
"tags": self.tags,
|
|
54
|
+
"active": self.active,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def to_markdown(self) -> str:
|
|
58
|
+
"""Generate SKILL.md content."""
|
|
59
|
+
lines = [
|
|
60
|
+
f"# {self.name}",
|
|
61
|
+
"",
|
|
62
|
+
f"**ID:** {self.id}",
|
|
63
|
+
f"**Purpose:** {self.purpose}",
|
|
64
|
+
"",
|
|
65
|
+
"## Activation Rules",
|
|
66
|
+
"",
|
|
67
|
+
]
|
|
68
|
+
for rule in self.activation_rules:
|
|
69
|
+
lines.append(f"- {rule}")
|
|
70
|
+
lines.extend(
|
|
71
|
+
[
|
|
72
|
+
"",
|
|
73
|
+
"## Input Schema",
|
|
74
|
+
"",
|
|
75
|
+
"```json",
|
|
76
|
+
json.dumps(self.input_schema, indent=2),
|
|
77
|
+
"```",
|
|
78
|
+
"",
|
|
79
|
+
"## Output Schema",
|
|
80
|
+
"",
|
|
81
|
+
"```json",
|
|
82
|
+
json.dumps(self.output_schema, indent=2),
|
|
83
|
+
"```",
|
|
84
|
+
"",
|
|
85
|
+
"## Epistemic Contract",
|
|
86
|
+
"",
|
|
87
|
+
self.epistemic_contract or "No epistemic contract defined.",
|
|
88
|
+
"",
|
|
89
|
+
"## Tools Used",
|
|
90
|
+
"",
|
|
91
|
+
]
|
|
92
|
+
)
|
|
93
|
+
for tool in self.tools_used:
|
|
94
|
+
lines.append(f"- {tool}")
|
|
95
|
+
lines.extend(["", "## Tests Required", ""])
|
|
96
|
+
for test in self.tests_required:
|
|
97
|
+
lines.append(f"- {test}")
|
|
98
|
+
lines.extend(["", "## Stop Conditions", ""])
|
|
99
|
+
for cond in self.stop_conditions:
|
|
100
|
+
lines.append(f"- {cond}")
|
|
101
|
+
return "\n".join(lines)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def _generate_skill_id(name: str) -> str:
|
|
105
|
+
slug = re.sub(r"[^a-z0-9]+", "-", name.lower().strip())[:30]
|
|
106
|
+
return f"skill-{slug}-{uuid.uuid4().hex[:6]}"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def build_skill(
|
|
110
|
+
description: str,
|
|
111
|
+
project_dir: str = ".",
|
|
112
|
+
tags: list[str] | None = None,
|
|
113
|
+
) -> SkillSpec:
|
|
114
|
+
"""Build a skill from a natural-language description.
|
|
115
|
+
|
|
116
|
+
Currently generates a deterministic skill spec from the description.
|
|
117
|
+
When an AI provider is configured, this will use the LLM to generate
|
|
118
|
+
richer skill content.
|
|
119
|
+
"""
|
|
120
|
+
# Deterministic generation (no LLM required)
|
|
121
|
+
name = description.strip()[:60]
|
|
122
|
+
skill_id = _generate_skill_id(name)
|
|
123
|
+
|
|
124
|
+
spec = SkillSpec(
|
|
125
|
+
id=skill_id,
|
|
126
|
+
name=name,
|
|
127
|
+
purpose=description.strip(),
|
|
128
|
+
activation_rules=[f"User requests: {description[:80]}"],
|
|
129
|
+
input_schema={"task": "string", "context": "string (optional)"},
|
|
130
|
+
output_schema={"result": "string", "confidence": "number"},
|
|
131
|
+
epistemic_contract="Output must be verifiable against the input task.",
|
|
132
|
+
tools_used=["read_file", "run_shell"],
|
|
133
|
+
tests_required=[f"Verify {name} produces correct output"],
|
|
134
|
+
stop_conditions=["Confidence below 0.3", "Timeout exceeded"],
|
|
135
|
+
tags=tags or [],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Save to disk
|
|
139
|
+
skill_dir = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id
|
|
140
|
+
skill_dir.mkdir(parents=True, exist_ok=True)
|
|
141
|
+
(skill_dir / "SKILL.md").write_text(spec.to_markdown(), encoding="utf-8")
|
|
142
|
+
|
|
143
|
+
# Save JSON metadata
|
|
144
|
+
(skill_dir / "skill.json").write_text(
|
|
145
|
+
json.dumps(spec.to_dict(), indent=2, ensure_ascii=False),
|
|
146
|
+
encoding="utf-8",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
return spec
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def list_skills(project_dir: str = ".") -> list[SkillSpec]:
|
|
153
|
+
"""List all available skills in the project."""
|
|
154
|
+
skills_dir = Path(project_dir).resolve() / ".specsmith" / "skills"
|
|
155
|
+
if not skills_dir.is_dir():
|
|
156
|
+
return []
|
|
157
|
+
skills: list[SkillSpec] = []
|
|
158
|
+
for skill_dir in sorted(skills_dir.iterdir()):
|
|
159
|
+
meta_path = skill_dir / "skill.json"
|
|
160
|
+
if meta_path.is_file():
|
|
161
|
+
try:
|
|
162
|
+
raw = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
163
|
+
skills.append(
|
|
164
|
+
SkillSpec(
|
|
165
|
+
id=raw.get("id", ""),
|
|
166
|
+
name=raw.get("name", ""),
|
|
167
|
+
purpose=raw.get("purpose", ""),
|
|
168
|
+
activation_rules=raw.get("activation_rules", []),
|
|
169
|
+
tools_used=raw.get("tools_used", []),
|
|
170
|
+
tags=raw.get("tags", []),
|
|
171
|
+
active=raw.get("active", False),
|
|
172
|
+
)
|
|
173
|
+
)
|
|
174
|
+
except (OSError, ValueError):
|
|
175
|
+
continue
|
|
176
|
+
return skills
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def activate_skill(skill_id: str, project_dir: str = ".") -> bool:
|
|
180
|
+
"""Activate a skill by ID."""
|
|
181
|
+
meta_path = Path(project_dir).resolve() / ".specsmith" / "skills" / skill_id / "skill.json"
|
|
182
|
+
if not meta_path.is_file():
|
|
183
|
+
return False
|
|
184
|
+
try:
|
|
185
|
+
raw = json.loads(meta_path.read_text(encoding="utf-8"))
|
|
186
|
+
raw["active"] = True
|
|
187
|
+
meta_path.write_text(json.dumps(raw, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
188
|
+
return True
|
|
189
|
+
except (OSError, ValueError):
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
__all__ = ["SkillSpec", "activate_skill", "build_skill", "list_skills"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.10.1.
|
|
3
|
+
Version: 0.10.1.dev294
|
|
4
4
|
Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
|
|
5
5
|
Author: BitConcepts
|
|
6
6
|
License-Expression: MIT
|
|
@@ -36,6 +36,7 @@ src/specsmith/importer.py
|
|
|
36
36
|
src/specsmith/instinct.py
|
|
37
37
|
src/specsmith/languages.py
|
|
38
38
|
src/specsmith/ledger.py
|
|
39
|
+
src/specsmith/mcp_generator.py
|
|
39
40
|
src/specsmith/patent.py
|
|
40
41
|
src/specsmith/paths.py
|
|
41
42
|
src/specsmith/phase.py
|
|
@@ -52,6 +53,7 @@ src/specsmith/serve.py
|
|
|
52
53
|
src/specsmith/session.py
|
|
53
54
|
src/specsmith/session_init.py
|
|
54
55
|
src/specsmith/skills.py
|
|
56
|
+
src/specsmith/skills_builder.py
|
|
55
57
|
src/specsmith/sync.py
|
|
56
58
|
src/specsmith/tool_installer.py
|
|
57
59
|
src/specsmith/toolrules.py
|
|
@@ -115,6 +117,8 @@ src/specsmith/epistemic/certainty.py
|
|
|
115
117
|
src/specsmith/epistemic/failure_graph.py
|
|
116
118
|
src/specsmith/epistemic/recovery.py
|
|
117
119
|
src/specsmith/epistemic/stress_tester.py
|
|
120
|
+
src/specsmith/esdb/__init__.py
|
|
121
|
+
src/specsmith/esdb/bridge.py
|
|
118
122
|
src/specsmith/eval/__init__.py
|
|
119
123
|
src/specsmith/eval/builtins.py
|
|
120
124
|
src/specsmith/eval/runner.py
|
|
@@ -218,6 +222,7 @@ tests/test_phase34_completion.py
|
|
|
218
222
|
tests/test_rate_limits.py
|
|
219
223
|
tests/test_scaffolder.py
|
|
220
224
|
tests/test_skill_marketplace.py
|
|
225
|
+
tests/test_skills_mcp.py
|
|
221
226
|
tests/test_smoke.py
|
|
222
227
|
tests/test_suggester.py
|
|
223
228
|
tests/test_tools.py
|