specsmith 0.19.2.dev737__tar.gz → 0.19.2.dev739__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.19.2.dev737/src/specsmith.egg-info → specsmith-0.19.2.dev739}/PKG-INFO +1 -1
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/pyproject.toml +1 -1
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/runner.py +10 -0
- specsmith-0.19.2.dev739/src/specsmith/agent/terminal_env.py +43 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/cli.py +64 -40
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/__init__.py +7 -6
- specsmith-0.19.2.dev739/src/specsmith/integrations/warp.py +84 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/local_model.py +212 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/mcp_server.py +41 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739/src/specsmith.egg-info}/PKG-INFO +1 -1
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith.egg-info/SOURCES.txt +4 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_integrations.py +8 -5
- specsmith-0.19.2.dev739/tests/test_integrations_warp.py +88 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_local_model.py +176 -0
- specsmith-0.19.2.dev739/tests/test_terminal_env.py +58 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/LICENSE +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/README.md +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/setup.cfg +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/belief.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/certainty.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/py.typed +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/recovery.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/session.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/epistemic/trace.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/__main__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/model_router.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/token_pricing.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/approvals.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/architect.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/auditor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/auth.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/block_export.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/channel.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/commands/issues_policy.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/commands/reporting.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/compressor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/config.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/context_window.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/credits.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/dashboard.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/differ.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/doctor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/drive.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/editor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/efficiency.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb/sqlite_store.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb_sweep.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/esdb_writer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/executor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/exporter.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/governed_pr.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/history_search.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/importer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/instinct.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/codity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/languages.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/ledger.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m007_yaml_first.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m008_esdb_full_coverage.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m009_esdb_first.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/m010_post_esdb_cleanup.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/patent.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/paths.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/phase.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/plugins.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/policy.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/profiles.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/project_metrics.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/quality_report.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/recover.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/releaser.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/requirements.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/risk.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/serve.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/session.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/session_init.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/session_store.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/governance.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/sync.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/tools.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/trace.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/transcripts.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/updater.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/validator.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/wi_store.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith/workspace.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_CMD_001.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_ai_client.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_architect_interview.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_architect_v2.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_architecture.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_audit_governance.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_auditor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_benchmark_harness.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_broker_scope.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_channel.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_cleanup_cmd.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_cli.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_cli_regressions.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_compliance.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_compliance_governance.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_compressor.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_deprecation_registry.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_dispatch.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_dual_write.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_efficiency.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_epistemic.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_backend_switch.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_enforcement.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_integration.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_license.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_status_integrity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_status_output.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_sweep.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_verify_chain_cli.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_esdb_writer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_golden_path.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_importer.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_init_modes.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_intelligence.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_issue_policy_features.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_issues_263_264.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_markdown_deprecation.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_mcp_client.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_mcp_server.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_metrics_flush.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_migration_direction.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_model_router.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_new_modules.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_nexus.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_parallel_agents.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_permissions.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_project_metrics.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_quality_report.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_rate_limits.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_releaser.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_repl.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_repl_extended.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_reporting_commands.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_req_248_262.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_req_358_359.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_resume_command.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_scaffolder.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_schema_migrations.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_smoke.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_sqlite_parity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_suggester.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_sync_reconcile.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_token_cost.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_tools.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_trace_vault_esdb.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_typing_guardrails.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_validator.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_vcs.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_warp_parity.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_warp_parity_followup.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_wi_lifecycle.py +0 -0
- {specsmith-0.19.2.dev737 → specsmith-0.19.2.dev739}/tests/test_wi_lifecycle_extended.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.19.2.
|
|
3
|
+
Version: 0.19.2.dev739
|
|
4
4
|
Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
|
|
5
5
|
Author: Layer1Labs Silicon, Inc.
|
|
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.19.2.
|
|
7
|
+
version = "0.19.2.dev739"
|
|
8
8
|
description = "AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -304,6 +304,12 @@ class AgentRunner:
|
|
|
304
304
|
self.endpoint_id = (endpoint_id or "").strip() or None
|
|
305
305
|
self.profile_id = (profile_id or "").strip() or None
|
|
306
306
|
|
|
307
|
+
# Host-terminal detection (REQ-444): when running inside Warp the
|
|
308
|
+
# banner/ready frame advertises native integration. Read-only.
|
|
309
|
+
from specsmith.agent.terminal_env import detect_terminal
|
|
310
|
+
|
|
311
|
+
self.terminal = detect_terminal()
|
|
312
|
+
|
|
307
313
|
# Use a plain-text emitter in interactive mode so LLM tokens render
|
|
308
314
|
# as readable prose instead of raw JSONL frames on the terminal.
|
|
309
315
|
if emitter is not None:
|
|
@@ -374,6 +380,7 @@ class AgentRunner:
|
|
|
374
380
|
profile_id=self.profile_id or "",
|
|
375
381
|
capabilities=_capabilities(),
|
|
376
382
|
endpoint_id=self.endpoint_id or "",
|
|
383
|
+
terminal=self.terminal.as_dict(),
|
|
377
384
|
)
|
|
378
385
|
else:
|
|
379
386
|
statuses = check_providers()
|
|
@@ -385,6 +392,9 @@ class AgentRunner:
|
|
|
385
392
|
"",
|
|
386
393
|
" LLM providers:",
|
|
387
394
|
]
|
|
395
|
+
if self.terminal.is_warp:
|
|
396
|
+
ver = f" {self.terminal.version}" if self.terminal.version else ""
|
|
397
|
+
lines.insert(3, f" terminal: Warp{ver} \u2014 native integration active")
|
|
388
398
|
for s in statuses:
|
|
389
399
|
if s.available:
|
|
390
400
|
lines.append(
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved.
|
|
3
|
+
"""Terminal-environment detection for specsmith (REQ-444).
|
|
4
|
+
|
|
5
|
+
Lets the interactive REPL (``specsmith run``) detect when it is running
|
|
6
|
+
inside Warp so it can adapt its banner / ``ready`` frame. Detection is
|
|
7
|
+
based on the standard ``TERM_PROGRAM`` signal Warp sets, plus any
|
|
8
|
+
``WARP_*`` environment variables, and is purely read-only.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
from dataclasses import asdict, dataclass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class TerminalInfo:
|
|
19
|
+
"""Information about the host terminal."""
|
|
20
|
+
|
|
21
|
+
is_warp: bool
|
|
22
|
+
program: str
|
|
23
|
+
version: str
|
|
24
|
+
|
|
25
|
+
def as_dict(self) -> dict[str, object]:
|
|
26
|
+
"""Return a flat dict suitable for the ``ready`` event frame."""
|
|
27
|
+
return asdict(self)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def detect_terminal(env: dict[str, str] | None = None) -> TerminalInfo:
|
|
31
|
+
"""Detect the host terminal from environment variables.
|
|
32
|
+
|
|
33
|
+
Warp sets ``TERM_PROGRAM=WarpTerminal`` (and ``TERM_PROGRAM_VERSION``).
|
|
34
|
+
As a fallback we also treat the presence of any ``WARP_*`` variable as a
|
|
35
|
+
Warp signal. Pass *env* to override ``os.environ`` (used by tests).
|
|
36
|
+
"""
|
|
37
|
+
source = os.environ if env is None else env
|
|
38
|
+
program = (source.get("TERM_PROGRAM") or "").strip()
|
|
39
|
+
version = (source.get("TERM_PROGRAM_VERSION") or "").strip()
|
|
40
|
+
is_warp = program == "WarpTerminal" or any(k.startswith("WARP_") for k in source)
|
|
41
|
+
if is_warp and not program:
|
|
42
|
+
program = "WarpTerminal"
|
|
43
|
+
return TerminalInfo(is_warp=is_warp, program=program, version=version)
|
|
@@ -5625,12 +5625,14 @@ def integrate_cmd(tool_name: str, project_dir: str, dry_run: bool) -> None:
|
|
|
5625
5625
|
what belief artifacts this tool provides evidence for, what its
|
|
5626
5626
|
uncertainty bounds are, and what failure modes it might introduce.
|
|
5627
5627
|
"""
|
|
5628
|
+
from specsmith.paths import find_requirements, find_scaffold
|
|
5629
|
+
|
|
5628
5630
|
root = Path(project_dir).resolve()
|
|
5629
|
-
req_path = root
|
|
5631
|
+
req_path = find_requirements(root)
|
|
5630
5632
|
|
|
5631
5633
|
console.print(f"[bold]Epistemic Impact Analysis[/bold]: {tool_name}\n")
|
|
5632
5634
|
|
|
5633
|
-
if req_path
|
|
5635
|
+
if req_path is not None:
|
|
5634
5636
|
from specsmith.epistemic.belief import parse_requirements_as_beliefs
|
|
5635
5637
|
|
|
5636
5638
|
artifacts = parse_requirements_as_beliefs(req_path)
|
|
@@ -5669,19 +5671,23 @@ def integrate_cmd(tool_name: str, project_dir: str, dry_run: bool) -> None:
|
|
|
5669
5671
|
from specsmith.integrations import get_adapter
|
|
5670
5672
|
|
|
5671
5673
|
adapter = get_adapter(tool_name)
|
|
5672
|
-
|
|
5673
|
-
if
|
|
5674
|
+
scaffold_file = find_scaffold(root)
|
|
5675
|
+
if scaffold_file is not None:
|
|
5674
5676
|
import yaml
|
|
5675
5677
|
|
|
5676
|
-
|
|
5678
|
+
from specsmith.config import _normalize_scaffold_raw
|
|
5679
|
+
|
|
5680
|
+
with open(scaffold_file) as f:
|
|
5677
5681
|
raw = yaml.safe_load(f)
|
|
5678
|
-
config = ProjectConfig(**raw)
|
|
5682
|
+
config = ProjectConfig(**_normalize_scaffold_raw(raw or {}))
|
|
5679
5683
|
created = adapter.generate(config, root)
|
|
5680
5684
|
for path in created:
|
|
5681
5685
|
console.print(f" [green]✓[/green] {path.relative_to(root)}")
|
|
5682
5686
|
console.print(f"\n[bold green]{len(created)} adapter file(s) generated.[/bold green]")
|
|
5683
5687
|
else:
|
|
5684
|
-
console.print(
|
|
5688
|
+
console.print(
|
|
5689
|
+
"[yellow]No docs/SPECSMITH.yml found. Run specsmith import first.[/yellow]"
|
|
5690
|
+
)
|
|
5685
5691
|
except ValueError:
|
|
5686
5692
|
console.print(
|
|
5687
5693
|
f"[yellow]No built-in adapter for '{tool_name}'.[/yellow] "
|
|
@@ -10592,41 +10598,10 @@ def mcp_install_warp_cmd(as_json: bool) -> None:
|
|
|
10592
10598
|
to ``oz agent run --mcp '<json>'`` for a one-off cloud agent run.
|
|
10593
10599
|
"""
|
|
10594
10600
|
import json as _json
|
|
10595
|
-
import shutil
|
|
10596
|
-
import sys
|
|
10597
10601
|
|
|
10598
|
-
|
|
10599
|
-
# SPECSMITH_ALLOW_NON_PIPX=1 — prevents the pipx-enforcement gate from
|
|
10600
|
-
# exiting before the MCP handshake when Warp starts the server directly.
|
|
10601
|
-
# SPECSMITH_NO_AUTO_UPDATE / SPECSMITH_PYPI_CHECKED — suppress network
|
|
10602
|
-
# calls on startup so the server responds immediately.
|
|
10603
|
-
server_env = {
|
|
10604
|
-
"SPECSMITH_ALLOW_NON_PIPX": "1",
|
|
10605
|
-
"SPECSMITH_NO_AUTO_UPDATE": "1",
|
|
10606
|
-
"SPECSMITH_PYPI_CHECKED": "1",
|
|
10607
|
-
}
|
|
10602
|
+
from specsmith.mcp_server import build_warp_mcp_config
|
|
10608
10603
|
|
|
10609
|
-
|
|
10610
|
-
# 1. specsmith (or specsmith.exe) on PATH — covers pipx shims and system installs.
|
|
10611
|
-
# 2. python -m specsmith via the current interpreter — reliable fallback
|
|
10612
|
-
# for editable dev installs and venvs where the console script wrapper
|
|
10613
|
-
# is absent or resolves incorrectly (e.g. some Windows pipx setups).
|
|
10614
|
-
specsmith_exe = shutil.which("specsmith") or shutil.which("specsmith.exe")
|
|
10615
|
-
if specsmith_exe:
|
|
10616
|
-
cmd = specsmith_exe
|
|
10617
|
-
args: list[str] = ["mcp", "serve"]
|
|
10618
|
-
else:
|
|
10619
|
-
# Fall back to `python -m specsmith` using the current interpreter.
|
|
10620
|
-
cmd = sys.executable
|
|
10621
|
-
args = ["-m", "specsmith", "mcp", "serve"]
|
|
10622
|
-
|
|
10623
|
-
config = {
|
|
10624
|
-
"specsmith-governance": {
|
|
10625
|
-
"command": cmd,
|
|
10626
|
-
"args": args,
|
|
10627
|
-
"env": server_env,
|
|
10628
|
-
}
|
|
10629
|
-
}
|
|
10604
|
+
config = build_warp_mcp_config()
|
|
10630
10605
|
|
|
10631
10606
|
if as_json:
|
|
10632
10607
|
click.echo(_json.dumps(config, indent=2))
|
|
@@ -14152,6 +14127,55 @@ def local_model_detect_cmd(as_json: bool) -> None:
|
|
|
14152
14127
|
)
|
|
14153
14128
|
|
|
14154
14129
|
|
|
14130
|
+
@local_model_group.command(name="recommend")
|
|
14131
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Emit result as JSON.")
|
|
14132
|
+
def local_model_recommend_cmd(as_json: bool) -> None:
|
|
14133
|
+
"""Recommend a full local model lineup based on detected GPU VRAM (REQ-445).
|
|
14134
|
+
|
|
14135
|
+
Detects the host GPU and prints a VRAM-aware role lineup (default / fast /
|
|
14136
|
+
harder pass / general) with a per-model fit assessment so you can see which
|
|
14137
|
+
models run fully on the GPU and which would spill to system RAM.
|
|
14138
|
+
"""
|
|
14139
|
+
import json as _json
|
|
14140
|
+
|
|
14141
|
+
from specsmith.local_model import recommend_for_hardware
|
|
14142
|
+
|
|
14143
|
+
lineup = recommend_for_hardware()
|
|
14144
|
+
|
|
14145
|
+
if as_json:
|
|
14146
|
+
click.echo(
|
|
14147
|
+
_json.dumps(
|
|
14148
|
+
lineup.as_dict()
|
|
14149
|
+
if lineup is not None
|
|
14150
|
+
else {"hardware": None, "reason": "cpu-only or insufficient VRAM", "models": []}
|
|
14151
|
+
)
|
|
14152
|
+
)
|
|
14153
|
+
return
|
|
14154
|
+
|
|
14155
|
+
if lineup is None:
|
|
14156
|
+
console.print(
|
|
14157
|
+
"[yellow]\u2014[/yellow] No GPU / insufficient VRAM detected. "
|
|
14158
|
+
"Local model recommendations skipped (CPU-only would be too slow)."
|
|
14159
|
+
)
|
|
14160
|
+
return
|
|
14161
|
+
|
|
14162
|
+
console.print(
|
|
14163
|
+
f"[bold]Hardware:[/bold] {lineup.hardware} ([bold]{lineup.vram_gb:.1f} GB[/bold] VRAM)\n"
|
|
14164
|
+
)
|
|
14165
|
+
_fit_color = {"fits": "green", "tight": "yellow", "spills": "red"}
|
|
14166
|
+
for rec in lineup.models:
|
|
14167
|
+
color = _fit_color.get(rec.fit.value, "white")
|
|
14168
|
+
console.print(
|
|
14169
|
+
f" [bold]{rec.slot:<8}[/bold] [green]{rec.model:<22}[/green] "
|
|
14170
|
+
f"~{rec.footprint_gb:.1f} GB [{color}]{rec.fit_note}[/{color}]"
|
|
14171
|
+
)
|
|
14172
|
+
console.print(f" [dim]{rec.summary}[/dim]")
|
|
14173
|
+
console.print(
|
|
14174
|
+
"\n[dim]Pull all with [bold]specsmith local-model setup[/bold], or pull one with "
|
|
14175
|
+
"[bold]ollama pull <model>[/bold].[/dim]"
|
|
14176
|
+
)
|
|
14177
|
+
|
|
14178
|
+
|
|
14155
14179
|
@local_model_group.command(name="setup")
|
|
14156
14180
|
def local_model_setup_cmd() -> None:
|
|
14157
14181
|
"""Pull the recommended local model via Ollama (REQ-386).
|
|
@@ -15,12 +15,11 @@ ADAPTER_REGISTRY: dict[str, type[AgentAdapter]] = {}
|
|
|
15
15
|
# canonical name. Lookups for legacy keys still succeed (backward compat for
|
|
16
16
|
# existing scaffold.yml files) but only the canonical names are returned by
|
|
17
17
|
# ``list_adapters()``.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
18
|
+
#
|
|
19
|
+
# Note: ``warp`` is no longer an alias — it now resolves to the dedicated
|
|
20
|
+
# :class:`~specsmith.integrations.warp.WarpAdapter`, which still emits the
|
|
21
|
+
# governance skill (via ``AgentSkillAdapter``) plus Warp-native artifacts.
|
|
22
|
+
LEGACY_ALIASES: dict[str, str] = {}
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
def _load_adapters() -> None:
|
|
@@ -32,6 +31,7 @@ def _load_adapters() -> None:
|
|
|
32
31
|
from specsmith.integrations.copilot import CopilotAdapter
|
|
33
32
|
from specsmith.integrations.cursor import CursorAdapter
|
|
34
33
|
from specsmith.integrations.gemini import GeminiAdapter
|
|
34
|
+
from specsmith.integrations.warp import WarpAdapter
|
|
35
35
|
from specsmith.integrations.windsurf import WindsurfAdapter
|
|
36
36
|
|
|
37
37
|
for cls in (
|
|
@@ -43,6 +43,7 @@ def _load_adapters() -> None:
|
|
|
43
43
|
GeminiAdapter,
|
|
44
44
|
WindsurfAdapter,
|
|
45
45
|
AiderAdapter,
|
|
46
|
+
WarpAdapter,
|
|
46
47
|
):
|
|
47
48
|
ADAPTER_REGISTRY[cls().name] = cls
|
|
48
49
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved.
|
|
3
|
+
"""Warp integration adapter (REQ-444).
|
|
4
|
+
|
|
5
|
+
Generates Warp-native artifacts so Warp's agent is governed by specsmith:
|
|
6
|
+
|
|
7
|
+
* ``.warp/specsmith-mcp.json`` — governance MCP server config
|
|
8
|
+
* ``.warp/launch_configs/specsmith-governed.yaml`` — launch config for a governed session
|
|
9
|
+
* ``.agents/skills/SKILL.md`` — governance skill (shared with agent-skill)
|
|
10
|
+
|
|
11
|
+
``AGENTS.md`` is already the governance hub Warp reads as project Rules, so the
|
|
12
|
+
adapter does not duplicate it.
|
|
13
|
+
|
|
14
|
+
This adapter supersedes the pre-0.5.0 ``warp`` name that previously aliased to
|
|
15
|
+
the generic ``agent-skill`` adapter; the skill is still emitted here (by reusing
|
|
16
|
+
``AgentSkillAdapter``), so existing setups keep their ``.agents/skills/SKILL.md``.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
from specsmith.config import ProjectConfig
|
|
25
|
+
from specsmith.integrations.agent_skill import AgentSkillAdapter
|
|
26
|
+
from specsmith.integrations.base import AgentAdapter
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class WarpAdapter(AgentAdapter):
|
|
30
|
+
"""Generate Warp-native governance integration files."""
|
|
31
|
+
|
|
32
|
+
@property
|
|
33
|
+
def name(self) -> str:
|
|
34
|
+
return "warp"
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def description(self) -> str:
|
|
38
|
+
return "Warp native integration (MCP server config, launch config, governance skill)"
|
|
39
|
+
|
|
40
|
+
def generate(self, config: ProjectConfig, target: Path) -> list[Path]:
|
|
41
|
+
created: list[Path] = []
|
|
42
|
+
warp_dir = target / ".warp"
|
|
43
|
+
warp_dir.mkdir(parents=True, exist_ok=True)
|
|
44
|
+
|
|
45
|
+
# 1. MCP governance server config (shared builder with `mcp install-warp`).
|
|
46
|
+
from specsmith.mcp_server import build_warp_mcp_config
|
|
47
|
+
|
|
48
|
+
mcp_path = warp_dir / "specsmith-mcp.json"
|
|
49
|
+
mcp_path.write_text(
|
|
50
|
+
json.dumps(build_warp_mcp_config(), indent=2) + "\n",
|
|
51
|
+
encoding="utf-8",
|
|
52
|
+
)
|
|
53
|
+
created.append(mcp_path)
|
|
54
|
+
|
|
55
|
+
# 2. Launch config for a governed `specsmith run` session.
|
|
56
|
+
launch_dir = warp_dir / "launch_configs"
|
|
57
|
+
launch_dir.mkdir(parents=True, exist_ok=True)
|
|
58
|
+
launch_path = launch_dir / "specsmith-governed.yaml"
|
|
59
|
+
launch_path.write_text(self._render_launch_config(config, target), encoding="utf-8")
|
|
60
|
+
created.append(launch_path)
|
|
61
|
+
|
|
62
|
+
# 3. Governance skill (reuse the agent-skill adapter; .agents/skills/SKILL.md).
|
|
63
|
+
created.extend(AgentSkillAdapter().generate(config, target))
|
|
64
|
+
|
|
65
|
+
return created
|
|
66
|
+
|
|
67
|
+
def _render_launch_config(self, config: ProjectConfig, target: Path) -> str:
|
|
68
|
+
cwd = str(target).replace("\\", "/")
|
|
69
|
+
return f"""\
|
|
70
|
+
# specsmith governed session — Warp launch configuration.
|
|
71
|
+
# Copy to your Warp launch configurations directory to use it:
|
|
72
|
+
# macOS/Linux: ~/.warp/launch_configurations/
|
|
73
|
+
# Windows: %APPDATA%/warp/Warp/data/launch_configurations/
|
|
74
|
+
# The governance MCP server config lives in .warp/specsmith-mcp.json — add it
|
|
75
|
+
# under Warp Settings -> Agents -> MCP servers so Warp's agent is governed.
|
|
76
|
+
name: {config.name} — specsmith governed
|
|
77
|
+
windows:
|
|
78
|
+
- tabs:
|
|
79
|
+
- title: specsmith
|
|
80
|
+
layout:
|
|
81
|
+
cwd: "{cwd}"
|
|
82
|
+
commands:
|
|
83
|
+
- exec: specsmith run
|
|
84
|
+
"""
|
|
@@ -76,6 +76,9 @@ _REASON_14B = "deepseek-r1:14b"
|
|
|
76
76
|
_REASON_8B = "deepseek-r1:8b"
|
|
77
77
|
_REASON_7B = "deepseek-r1:7b"
|
|
78
78
|
|
|
79
|
+
# ── Heavier coder for the "harder pass" slot (deepseek-coder-v2, MoE) ───────
|
|
80
|
+
_DEEPSEEK_CODER_V2 = "deepseek-coder-v2:16b"
|
|
81
|
+
|
|
79
82
|
|
|
80
83
|
@dataclass
|
|
81
84
|
class LocalModelInfo:
|
|
@@ -394,6 +397,209 @@ def detect_local_model() -> LocalModelInfo | None:
|
|
|
394
397
|
return None
|
|
395
398
|
|
|
396
399
|
|
|
400
|
+
# ---------------------------------------------------------------------------
|
|
401
|
+
# VRAM-aware recommendation engine (REQ-445)
|
|
402
|
+
# ---------------------------------------------------------------------------
|
|
403
|
+
#
|
|
404
|
+
# ``recommend_models`` turns a detected VRAM figure into a complete, first-class
|
|
405
|
+
# role lineup with per-model fit assessment, so recommendations always follow
|
|
406
|
+
# the GPU that was actually detected. ``recommend_for_hardware`` is the
|
|
407
|
+
# top-level entry point: it detects the host GPU (Apple Silicon or NVIDIA) and
|
|
408
|
+
# applies the same VRAM tiering used by ``detect_local_models``.
|
|
409
|
+
|
|
410
|
+
# Approximate on-GPU footprint (GB) for each model at its default Ollama
|
|
411
|
+
# quantization (Q4_K_M for dense models; MoE active-params for deepseek-coder-v2).
|
|
412
|
+
# Used purely to assess fit against detected VRAM — not an exact figure.
|
|
413
|
+
_MODEL_FOOTPRINT_GB: dict[str, float] = {
|
|
414
|
+
_MODEL_7B: 4.7,
|
|
415
|
+
_MODEL_14B: 9.0,
|
|
416
|
+
_MODEL_32B: 20.0,
|
|
417
|
+
_GEN_7B: 4.7,
|
|
418
|
+
_GEN_14B: 9.0,
|
|
419
|
+
_GEN_32B: 20.0,
|
|
420
|
+
_REASON_7B: 4.7,
|
|
421
|
+
_REASON_8B: 5.2,
|
|
422
|
+
_REASON_14B: 9.0,
|
|
423
|
+
_DEEPSEEK_CODER_V2: 8.9,
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# Headroom (GB) reserved above a model's footprint for the KV cache / context.
|
|
427
|
+
_FIT_HEADROOM_GB = 2.0
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
class ModelFit(str, Enum):
|
|
431
|
+
"""How well a model fits the detected VRAM."""
|
|
432
|
+
|
|
433
|
+
fits = "fits" # footprint + headroom <= VRAM → fully on GPU
|
|
434
|
+
tight = "tight" # footprint <= VRAM < footprint + headroom
|
|
435
|
+
spills = "spills" # footprint > VRAM → partial CPU offload (slow)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
_FIT_NOTE: dict[ModelFit, str] = {
|
|
439
|
+
ModelFit.fits: "fits fully on GPU",
|
|
440
|
+
ModelFit.tight: "fits but tight — reduce context if slow",
|
|
441
|
+
ModelFit.spills: "exceeds VRAM — partial CPU offload, expect slowdown",
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def assess_fit(model: str, vram_gb: float) -> ModelFit:
|
|
446
|
+
"""Assess how *model* fits in *vram_gb* of VRAM (REQ-445).
|
|
447
|
+
|
|
448
|
+
Unknown models are treated optimistically as ``fits`` so a missing
|
|
449
|
+
footprint entry never blocks a recommendation.
|
|
450
|
+
"""
|
|
451
|
+
footprint = _MODEL_FOOTPRINT_GB.get(model)
|
|
452
|
+
if footprint is None:
|
|
453
|
+
return ModelFit.fits
|
|
454
|
+
if footprint + _FIT_HEADROOM_GB <= vram_gb:
|
|
455
|
+
return ModelFit.fits
|
|
456
|
+
if footprint <= vram_gb:
|
|
457
|
+
return ModelFit.tight
|
|
458
|
+
return ModelFit.spills
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
@dataclass
|
|
462
|
+
class RecommendedModel:
|
|
463
|
+
"""A single VRAM-aware model recommendation for one usage slot (REQ-445)."""
|
|
464
|
+
|
|
465
|
+
slot: str
|
|
466
|
+
"""Usage slot: ``default`` | ``fast`` | ``harder`` | ``general``."""
|
|
467
|
+
|
|
468
|
+
role: ModelRole
|
|
469
|
+
"""Router role this slot maps to (coding/general/reasoning)."""
|
|
470
|
+
|
|
471
|
+
model: str
|
|
472
|
+
"""Ollama model tag."""
|
|
473
|
+
|
|
474
|
+
footprint_gb: float
|
|
475
|
+
"""Approximate on-GPU footprint in GB."""
|
|
476
|
+
|
|
477
|
+
fit: ModelFit
|
|
478
|
+
"""Fit against the detected VRAM."""
|
|
479
|
+
|
|
480
|
+
summary: str
|
|
481
|
+
"""What this slot is for."""
|
|
482
|
+
|
|
483
|
+
@property
|
|
484
|
+
def pull_cmd(self) -> str:
|
|
485
|
+
return f"ollama pull {self.model}"
|
|
486
|
+
|
|
487
|
+
@property
|
|
488
|
+
def fit_note(self) -> str:
|
|
489
|
+
return _FIT_NOTE[self.fit]
|
|
490
|
+
|
|
491
|
+
def as_dict(self) -> dict[str, object]:
|
|
492
|
+
return {
|
|
493
|
+
"slot": self.slot,
|
|
494
|
+
"role": self.role.value,
|
|
495
|
+
"model": self.model,
|
|
496
|
+
"footprint_gb": self.footprint_gb,
|
|
497
|
+
"fit": self.fit.value,
|
|
498
|
+
"fit_note": self.fit_note,
|
|
499
|
+
"summary": self.summary,
|
|
500
|
+
"pull_cmd": self.pull_cmd,
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
@dataclass
|
|
505
|
+
class RecommendedLineup:
|
|
506
|
+
"""A complete VRAM-aware lineup recommendation (REQ-445)."""
|
|
507
|
+
|
|
508
|
+
hardware: str
|
|
509
|
+
vram_gb: float
|
|
510
|
+
models: list[RecommendedModel]
|
|
511
|
+
|
|
512
|
+
def role_config(self) -> dict[str, str]:
|
|
513
|
+
"""Return the role→tag mapping for ``.specsmith/local-models.yml``.
|
|
514
|
+
|
|
515
|
+
Maps the router's three roles to lineup slots:
|
|
516
|
+
``coding`` → default, ``general`` → general, ``reasoning`` → harder.
|
|
517
|
+
"""
|
|
518
|
+
by_role: dict[str, str] = {}
|
|
519
|
+
for rec in self.models:
|
|
520
|
+
# First write wins per role (slots are emitted in priority order).
|
|
521
|
+
by_role.setdefault(rec.role.value, rec.model)
|
|
522
|
+
return by_role
|
|
523
|
+
|
|
524
|
+
def as_dict(self) -> dict[str, object]:
|
|
525
|
+
return {
|
|
526
|
+
"hardware": self.hardware,
|
|
527
|
+
"vram_gb": self.vram_gb,
|
|
528
|
+
"models": [m.as_dict() for m in self.models],
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def _tiered_tag(vram_gb: float, *, tag_32b: str, tag_14b: str, tag_7b: str) -> str:
|
|
533
|
+
"""Select a dense-model tag for *vram_gb* using the NVIDIA VRAM tiers."""
|
|
534
|
+
if vram_gb >= _TIER_32B_GB:
|
|
535
|
+
return tag_32b
|
|
536
|
+
if vram_gb >= _TIER_14B_GB:
|
|
537
|
+
return tag_14b
|
|
538
|
+
return tag_7b
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
def recommend_models(vram_gb: float, hardware: str = "") -> RecommendedLineup | None:
|
|
542
|
+
"""Recommend a full role lineup for *vram_gb* of VRAM (REQ-445).
|
|
543
|
+
|
|
544
|
+
Returns ``None`` below the minimum tier (``< _TIER_7B_GB``), where local
|
|
545
|
+
inference would be unusably slow. The lineup always follows the supplied
|
|
546
|
+
VRAM: the default/general slots scale with the VRAM tier (7b/14b/32b) while
|
|
547
|
+
the ``fast`` and ``harder`` slots are fixed picks whose fit is reported
|
|
548
|
+
relative to *vram_gb* so the caller can warn about CPU spillover.
|
|
549
|
+
"""
|
|
550
|
+
if vram_gb < _TIER_7B_GB:
|
|
551
|
+
return None
|
|
552
|
+
|
|
553
|
+
default_tag = _tiered_tag(vram_gb, tag_32b=_MODEL_32B, tag_14b=_MODEL_14B, tag_7b=_MODEL_7B)
|
|
554
|
+
general_tag = _tiered_tag(vram_gb, tag_32b=_GEN_32B, tag_14b=_GEN_14B, tag_7b=_GEN_7B)
|
|
555
|
+
|
|
556
|
+
specs: list[tuple[str, ModelRole, str, str]] = [
|
|
557
|
+
("default", ModelRole.coding, default_tag, "Default daily driver — balanced coding model."),
|
|
558
|
+
(
|
|
559
|
+
"fast",
|
|
560
|
+
ModelRole.coding,
|
|
561
|
+
_MODEL_7B,
|
|
562
|
+
"Fast scratch model — quick edits, big context headroom.",
|
|
563
|
+
),
|
|
564
|
+
(
|
|
565
|
+
"harder",
|
|
566
|
+
ModelRole.reasoning,
|
|
567
|
+
_DEEPSEEK_CODER_V2,
|
|
568
|
+
"Harder C/Python pass — heavier reasoning-capable coder.",
|
|
569
|
+
),
|
|
570
|
+
("general", ModelRole.general, general_tag, "General chat / project management."),
|
|
571
|
+
]
|
|
572
|
+
|
|
573
|
+
models = [
|
|
574
|
+
RecommendedModel(
|
|
575
|
+
slot=slot,
|
|
576
|
+
role=role,
|
|
577
|
+
model=tag,
|
|
578
|
+
footprint_gb=_MODEL_FOOTPRINT_GB.get(tag, 0.0),
|
|
579
|
+
fit=assess_fit(tag, vram_gb),
|
|
580
|
+
summary=summary,
|
|
581
|
+
)
|
|
582
|
+
for slot, role, tag, summary in specs
|
|
583
|
+
]
|
|
584
|
+
return RecommendedLineup(hardware=hardware or "unknown", vram_gb=vram_gb, models=models)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def recommend_for_hardware() -> RecommendedLineup | None:
|
|
588
|
+
"""Detect the host GPU and recommend a VRAM-aware lineup (REQ-445).
|
|
589
|
+
|
|
590
|
+
Mirrors the detection order of :func:`detect_local_models` (Apple Silicon
|
|
591
|
+
first, then NVIDIA) and applies the same VRAM tiering. Returns ``None`` on
|
|
592
|
+
CPU-only machines or when the detected VRAM is below the minimum tier.
|
|
593
|
+
"""
|
|
594
|
+
as_gb = _detect_apple_silicon_gb()
|
|
595
|
+
if as_gb is not None:
|
|
596
|
+
return recommend_models(as_gb, hardware=f"apple-silicon-{int(as_gb)}gb")
|
|
597
|
+
nv_gb = _detect_nvidia_vram_gb()
|
|
598
|
+
if nv_gb is not None:
|
|
599
|
+
return recommend_models(nv_gb, hardware=f"nvidia-{int(nv_gb)}gb")
|
|
600
|
+
return None
|
|
601
|
+
|
|
602
|
+
|
|
397
603
|
def ensure_local_model(model_tag: str) -> bool:
|
|
398
604
|
"""Pull *model_tag* via Ollama if it is not already present.
|
|
399
605
|
|
|
@@ -426,10 +632,16 @@ def ensure_local_model(model_tag: str) -> bool:
|
|
|
426
632
|
|
|
427
633
|
__all__ = [
|
|
428
634
|
"LocalModelInfo",
|
|
635
|
+
"ModelFit",
|
|
429
636
|
"ModelRole",
|
|
637
|
+
"RecommendedLineup",
|
|
638
|
+
"RecommendedModel",
|
|
639
|
+
"assess_fit",
|
|
430
640
|
"detect_local_model",
|
|
431
641
|
"detect_local_models",
|
|
432
642
|
"ensure_local_model",
|
|
433
643
|
"load_local_models_config",
|
|
644
|
+
"recommend_for_hardware",
|
|
645
|
+
"recommend_models",
|
|
434
646
|
"save_local_models_config",
|
|
435
647
|
]
|
|
@@ -122,6 +122,47 @@ def unregister_project(path: str = ".") -> bool:
|
|
|
122
122
|
return True
|
|
123
123
|
|
|
124
124
|
|
|
125
|
+
def build_warp_mcp_config() -> dict[str, Any]:
|
|
126
|
+
"""Build the Warp MCP server config snippet for the governance server.
|
|
127
|
+
|
|
128
|
+
Shared by ``specsmith mcp install-warp`` and the ``warp`` integration
|
|
129
|
+
adapter (REQ-444) so both emit an identical, registry-aware config.
|
|
130
|
+
|
|
131
|
+
Executable detection (in priority order):
|
|
132
|
+
1. ``specsmith`` / ``specsmith.exe`` on PATH — covers pipx shims and
|
|
133
|
+
system installs.
|
|
134
|
+
2. ``python -m specsmith`` via the current interpreter — reliable
|
|
135
|
+
fallback for editable dev installs and venvs where the console-script
|
|
136
|
+
wrapper is absent or resolves incorrectly (e.g. some Windows pipx setups).
|
|
137
|
+
|
|
138
|
+
The env vars keep the server starting cleanly when Warp launches it directly:
|
|
139
|
+
``SPECSMITH_ALLOW_NON_PIPX`` prevents the pipx-enforcement gate from exiting
|
|
140
|
+
before the MCP handshake; ``SPECSMITH_NO_AUTO_UPDATE`` / ``SPECSMITH_PYPI_CHECKED``
|
|
141
|
+
suppress startup network calls so the server responds immediately.
|
|
142
|
+
"""
|
|
143
|
+
import shutil
|
|
144
|
+
|
|
145
|
+
server_env = {
|
|
146
|
+
"SPECSMITH_ALLOW_NON_PIPX": "1",
|
|
147
|
+
"SPECSMITH_NO_AUTO_UPDATE": "1",
|
|
148
|
+
"SPECSMITH_PYPI_CHECKED": "1",
|
|
149
|
+
}
|
|
150
|
+
specsmith_exe = shutil.which("specsmith") or shutil.which("specsmith.exe")
|
|
151
|
+
if specsmith_exe:
|
|
152
|
+
cmd = specsmith_exe
|
|
153
|
+
args: list[str] = ["mcp", "serve"]
|
|
154
|
+
else:
|
|
155
|
+
cmd = sys.executable
|
|
156
|
+
args = ["-m", "specsmith", "mcp", "serve"]
|
|
157
|
+
return {
|
|
158
|
+
"specsmith-governance": {
|
|
159
|
+
"command": cmd,
|
|
160
|
+
"args": args,
|
|
161
|
+
"env": server_env,
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
125
166
|
_TOOLS: list[dict[str, Any]] = [
|
|
126
167
|
{
|
|
127
168
|
"name": "governance_project_list",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.19.2.
|
|
3
|
+
Version: 0.19.2.dev739
|
|
4
4
|
Summary: AEE governance toolkit for AI-assisted development — session preflight gates, multi-agent dispatch, requirements↔test traceability, ESDB persistence, MCP server, and skills for Warp, Cursor, Claude Code, Copilot, Windsurf, and Aider.
|
|
5
5
|
Author: Layer1Labs Silicon, Inc.
|
|
6
6
|
License-Expression: MIT
|