specsmith 0.15.3.dev570__tar.gz → 0.15.3.dev572__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.15.3.dev570/src/specsmith.egg-info → specsmith-0.15.3.dev572}/PKG-INFO +1 -1
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/pyproject.toml +1 -1
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/auditor.py +11 -4
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/cli.py +80 -23
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/esdb/sqlite_store.py +16 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/sync.py +84 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/gitignore.j2 +7 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572/src/specsmith.egg-info}/PKG-INFO +1 -1
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/SOURCES.txt +1 -0
- specsmith-0.15.3.dev572/tests/test_esdb_enforcement.py +81 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_scaffolder.py +3 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/LICENSE +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/README.md +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/setup.cfg +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/belief.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/certainty.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/py.typed +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/recovery.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/session.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/epistemic/trace.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/__main__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/architect.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/auth.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/block_export.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/channel.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/compressor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/config.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/context_window.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/credits.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/differ.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/doctor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/drive.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/editor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/executor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/exporter.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/history_search.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/importer.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/instinct.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/codity.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/languages.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/ledger.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/mcp_server.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/patent.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/paths.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/phase.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/plugins.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/profiles.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/releaser.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/requirements.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/serve.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/session.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/session_init.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/session_store.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/governance.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/tools.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/trace.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/updater.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/validator.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/wi_store.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/workspace.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_CMD_001.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_ai_client.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_auditor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_channel.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_cli.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_compliance.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_compliance_governance.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_compressor.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_dispatch.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_epistemic.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_esdb_license.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_importer.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_integrations.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_intelligence.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_mcp_client.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_mcp_server.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_new_modules.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_nexus.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_permissions.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_rate_limits.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_req_248_262.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_req_358_359.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_smoke.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_suggester.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_tools.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_validator.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_vcs.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_warp_parity.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_warp_parity_followup.py +0 -0
- {specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/tests/test_wi_lifecycle.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.15.3.
|
|
3
|
+
Version: 0.15.3.dev572
|
|
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.15.3.
|
|
7
|
+
version = "0.15.3.dev572"
|
|
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"
|
|
@@ -1130,7 +1130,11 @@ def check_industrial_artifacts(root: Path) -> list[AuditResult]:
|
|
|
1130
1130
|
raw = _read_scaffold_raw(root)
|
|
1131
1131
|
declared: dict[str, Any] = raw.get("industrial_artifacts", {}) or {}
|
|
1132
1132
|
declared_eds = declared.get("canopen_eds", []) or []
|
|
1133
|
-
|
|
1133
|
+
# Normalise declared paths to forward slashes and lowercase so they match
|
|
1134
|
+
# on Windows where YAML uses '/' but Path.relative_to() returns '\\' (#251).
|
|
1135
|
+
declared_paths = {
|
|
1136
|
+
e.get("path", "").replace("\\", "/").lower() for e in declared_eds if isinstance(e, dict)
|
|
1137
|
+
}
|
|
1134
1138
|
|
|
1135
1139
|
# Scan for .eds and .xdd files — respect scan_exclude_dirs and
|
|
1136
1140
|
# scan_exclude_patterns from scaffold.yml (#175).
|
|
@@ -1158,9 +1162,12 @@ def check_industrial_artifacts(root: Path) -> list[AuditResult]:
|
|
|
1158
1162
|
if not found_eds:
|
|
1159
1163
|
return results # No industrial artifacts found
|
|
1160
1164
|
|
|
1161
|
-
# Use as_posix() for cross-platform comparison — avoids
|
|
1162
|
-
# mismatch on Windows where str(Path) uses '\' but
|
|
1163
|
-
|
|
1165
|
+
# Use as_posix().lower() for cross-platform comparison — avoids backslash
|
|
1166
|
+
# mismatch on Windows where str(Path) uses '\' but YAML paths use '/' (#173,
|
|
1167
|
+
# #251). Both sides are lowercased so Windows case-insensitive FS is handled.
|
|
1168
|
+
undeclared = [
|
|
1169
|
+
f for f in found_eds if f.relative_to(root).as_posix().lower() not in declared_paths
|
|
1170
|
+
]
|
|
1164
1171
|
|
|
1165
1172
|
if undeclared:
|
|
1166
1173
|
results.append(
|
|
@@ -2577,30 +2577,47 @@ def save_cmd(project_dir: str, message: str, no_push: bool, force: bool, as_json
|
|
|
2577
2577
|
"""
|
|
2578
2578
|
import json as _json
|
|
2579
2579
|
|
|
2580
|
-
from specsmith
|
|
2580
|
+
from specsmith import esdb as esdb_mod
|
|
2581
|
+
from specsmith.sync import normalize_esdb_gitignore_policy
|
|
2581
2582
|
from specsmith.vcs_commands import has_uncommitted_changes, run_commit, run_push
|
|
2582
2583
|
|
|
2583
2584
|
root = Path(project_dir).resolve()
|
|
2584
2585
|
steps: list[dict[str, Any]] = []
|
|
2586
|
+
# 0. Normalize ESDB policy for legacy projects
|
|
2587
|
+
try:
|
|
2588
|
+
changed = normalize_esdb_gitignore_policy(root)
|
|
2589
|
+
steps.append(
|
|
2590
|
+
{
|
|
2591
|
+
"step": "gitignore_policy",
|
|
2592
|
+
"ok": True,
|
|
2593
|
+
"note": "normalized legacy ESDB policy" if changed else "already compliant",
|
|
2594
|
+
}
|
|
2595
|
+
)
|
|
2596
|
+
except Exception as exc: # noqa: BLE001
|
|
2597
|
+
steps.append({"step": "gitignore_policy", "ok": False, "error": str(exc)})
|
|
2585
2598
|
|
|
2586
2599
|
# 1. ESDB backup
|
|
2587
2600
|
try:
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2601
|
+
with esdb_mod.open_default_store(root, warn=False) as store: # type: ignore[attr-defined]
|
|
2602
|
+
backup_fn = getattr(store, "backup", None)
|
|
2603
|
+
if callable(backup_fn):
|
|
2604
|
+
backup_path = backup_fn()
|
|
2605
|
+
steps.append(
|
|
2606
|
+
{
|
|
2607
|
+
"step": "esdb_backup",
|
|
2608
|
+
"ok": True,
|
|
2609
|
+
"path": str(backup_path),
|
|
2610
|
+
"backend": esdb_mod.ESDB_BACKEND,
|
|
2611
|
+
}
|
|
2612
|
+
)
|
|
2613
|
+
else:
|
|
2614
|
+
steps.append(
|
|
2615
|
+
{
|
|
2616
|
+
"step": "esdb_backup",
|
|
2617
|
+
"ok": True,
|
|
2618
|
+
"note": f"{esdb_mod.ESDB_BACKEND} backend has no native backup method",
|
|
2619
|
+
}
|
|
2620
|
+
)
|
|
2604
2621
|
except Exception as exc: # noqa: BLE001
|
|
2605
2622
|
steps.append({"step": "esdb_backup", "ok": False, "error": str(exc)})
|
|
2606
2623
|
|
|
@@ -5653,7 +5670,8 @@ def phase_next(project_dir: str, force: bool) -> None:
|
|
|
5653
5670
|
"""Advance to the next AEE workflow phase.
|
|
5654
5671
|
|
|
5655
5672
|
Performs readiness checks on the current phase first.
|
|
5656
|
-
Use --force to skip checks.
|
|
5673
|
+
Use --force to skip checks. Phases listed in ``suppressed_phases`` in the
|
|
5674
|
+
scaffold config (docs/SPECSMITH.yml) are automatically skipped (#254).
|
|
5657
5675
|
"""
|
|
5658
5676
|
from specsmith.phase import PHASE_MAP, evaluate_phase, read_phase, write_phase
|
|
5659
5677
|
|
|
@@ -5679,12 +5697,45 @@ def phase_next(project_dir: str, force: bool) -> None:
|
|
|
5679
5697
|
)
|
|
5680
5698
|
return
|
|
5681
5699
|
|
|
5682
|
-
|
|
5683
|
-
|
|
5700
|
+
# Read suppressed_phases from the scaffold config (#254).
|
|
5701
|
+
suppressed: list[str] = []
|
|
5702
|
+
try:
|
|
5703
|
+
import yaml as _yaml
|
|
5704
|
+
|
|
5705
|
+
from specsmith.paths import find_scaffold
|
|
5706
|
+
|
|
5707
|
+
sp = find_scaffold(root)
|
|
5708
|
+
if sp:
|
|
5709
|
+
_raw = _yaml.safe_load(sp.read_text(encoding="utf-8")) or {}
|
|
5710
|
+
suppressed = [str(p) for p in (_raw.get("suppressed_phases") or [])]
|
|
5711
|
+
except Exception: # noqa: BLE001
|
|
5712
|
+
pass # Never block phase advance on config parse errors
|
|
5713
|
+
|
|
5714
|
+
# Walk the phase chain until we find a non-suppressed next phase.
|
|
5715
|
+
target_key: str | None = phase.next_phase
|
|
5716
|
+
skipped: list[str] = []
|
|
5717
|
+
while target_key and target_key in suppressed:
|
|
5718
|
+
skipped.append(target_key)
|
|
5719
|
+
target_phase = PHASE_MAP.get(target_key)
|
|
5720
|
+
target_key = target_phase.next_phase if target_phase else None
|
|
5721
|
+
|
|
5722
|
+
if not target_key:
|
|
5723
|
+
console.print(
|
|
5724
|
+
f"[bold]{phase.emoji} {phase.label}[/bold] is the effective final phase "
|
|
5725
|
+
"(all remaining phases are suppressed)."
|
|
5726
|
+
)
|
|
5727
|
+
if skipped:
|
|
5728
|
+
console.print(f" [dim]Suppressed: {', '.join(skipped)}[/dim]")
|
|
5729
|
+
return
|
|
5730
|
+
|
|
5731
|
+
write_phase(root, target_key)
|
|
5732
|
+
next_phase = PHASE_MAP[target_key]
|
|
5684
5733
|
console.print(
|
|
5685
5734
|
f"[green]\u2713[/green] Advanced from [bold]{phase.label}[/bold] "
|
|
5686
5735
|
f"to [bold]{next_phase.emoji} {next_phase.label}[/bold]."
|
|
5687
5736
|
)
|
|
5737
|
+
if skipped:
|
|
5738
|
+
console.print(f" [dim]Skipped suppressed phase(s): {', '.join(skipped)}[/dim]")
|
|
5688
5739
|
console.print(f" {next_phase.description}")
|
|
5689
5740
|
if next_phase.commands:
|
|
5690
5741
|
console.print("\n [bold]Next steps:[/bold]")
|
|
@@ -5693,14 +5744,14 @@ def phase_next(project_dir: str, force: bool) -> None:
|
|
|
5693
5744
|
|
|
5694
5745
|
# G3: keep the agents routing table aligned with the active phase.
|
|
5695
5746
|
# We pin a synthetic ``phase:active`` route so the runner can flip the
|
|
5696
|
-
# whole session to the new phase
|
|
5747
|
+
# whole session to the new phase's preferred profile without the user
|
|
5697
5748
|
# having to run `specsmith agents route set` themselves.
|
|
5698
5749
|
try:
|
|
5699
5750
|
from specsmith.agent.profiles import ProfileStore
|
|
5700
5751
|
|
|
5701
5752
|
agents_store = ProfileStore.load()
|
|
5702
5753
|
if agents_store.profiles:
|
|
5703
|
-
phase_key_target = f"phase:{
|
|
5754
|
+
phase_key_target = f"phase:{target_key}"
|
|
5704
5755
|
target_id = agents_store.routes.get(phase_key_target) or (
|
|
5705
5756
|
agents_store.default_profile_id
|
|
5706
5757
|
)
|
|
@@ -10554,9 +10605,15 @@ def esdb_enable_cmd(key_file: str, as_json: bool) -> None:
|
|
|
10554
10605
|
console.print("[dim]Contact licensing@layer1labs.com to obtain a valid license.[/dim]")
|
|
10555
10606
|
raise SystemExit(1)
|
|
10556
10607
|
|
|
10608
|
+
import os
|
|
10609
|
+
|
|
10557
10610
|
dest = Path.home() / ".specsmith" / "esdb.key"
|
|
10558
10611
|
dest.parent.mkdir(parents=True, exist_ok=True)
|
|
10559
|
-
|
|
10612
|
+
# Skip the copy when source and destination are the same file (#249).
|
|
10613
|
+
# On Windows, shutil.copy2(src, dst) raises PermissionError / WinError 32
|
|
10614
|
+
# when src == dst (file is already at the expected location).
|
|
10615
|
+
if os.path.realpath(str(key_file)) != os.path.realpath(str(dest)):
|
|
10616
|
+
shutil.copy2(key_file, dest)
|
|
10560
10617
|
|
|
10561
10618
|
if as_json:
|
|
10562
10619
|
click.echo(
|
|
@@ -289,6 +289,22 @@ class SqliteStore:
|
|
|
289
289
|
row = conn.execute("SELECT MAX(rowid) FROM records").fetchone()
|
|
290
290
|
return int(row[0]) if row and row[0] is not None else 0
|
|
291
291
|
|
|
292
|
+
def backup(self, backup_dir: str | Path | None = None) -> Path:
|
|
293
|
+
"""Create a timestamped SQLite snapshot and return its path."""
|
|
294
|
+
conn = self._require_open()
|
|
295
|
+
ts = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
|
|
296
|
+
dest_dir = Path(backup_dir) if backup_dir else self._db_path.parent / "backups"
|
|
297
|
+
dest_dir.mkdir(parents=True, exist_ok=True)
|
|
298
|
+
dest = dest_dir / f"esdb_sqlite_backup_{ts}.sqlite3"
|
|
299
|
+
|
|
300
|
+
backup_conn = sqlite3.connect(str(dest))
|
|
301
|
+
try:
|
|
302
|
+
conn.backup(backup_conn)
|
|
303
|
+
finally:
|
|
304
|
+
backup_conn.close()
|
|
305
|
+
|
|
306
|
+
return dest
|
|
307
|
+
|
|
292
308
|
def chain_valid(self) -> bool:
|
|
293
309
|
"""Always True — SQLite ACID guarantees integrity (no SHA-256 WAL chain)."""
|
|
294
310
|
return True
|
|
@@ -207,6 +207,88 @@ class SyncResult:
|
|
|
207
207
|
return "Machine state already in sync."
|
|
208
208
|
|
|
209
209
|
|
|
210
|
+
# ---------------------------------------------------------------------------
|
|
211
|
+
# ESDB legacy policy normalization (.gitignore)
|
|
212
|
+
# ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
_ESDB_GITIGNORE_FORBIDDEN = frozenset(
|
|
215
|
+
{
|
|
216
|
+
".specsmith/",
|
|
217
|
+
".chronomemory/",
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
_ESDB_GITIGNORE_REQUIRED = (
|
|
222
|
+
"!.specsmith/config.yml",
|
|
223
|
+
"!.specsmith/requirements.json",
|
|
224
|
+
"!.specsmith/testcases.json",
|
|
225
|
+
"!.specsmith/esdb.sqlite3",
|
|
226
|
+
"!.chronomemory/events.wal",
|
|
227
|
+
"!.chronomemory/snapshot.json",
|
|
228
|
+
".chronomemory/backup/",
|
|
229
|
+
".specsmith/workitems.json",
|
|
230
|
+
".specsmith/runs/",
|
|
231
|
+
".specsmith/chat/",
|
|
232
|
+
".specsmith/perf/",
|
|
233
|
+
".specsmith/recovery/",
|
|
234
|
+
".specsmith/ledger.jsonl",
|
|
235
|
+
".specsmith/ledger-chain.txt",
|
|
236
|
+
".specsmith/trace.jsonl",
|
|
237
|
+
".specsmith/credit-budget.json",
|
|
238
|
+
".specsmith/credits.json",
|
|
239
|
+
".specsmith/model-rate-limits.json",
|
|
240
|
+
".specsmith/pids/",
|
|
241
|
+
".specsmith/logs/",
|
|
242
|
+
".specsmith/sessions/",
|
|
243
|
+
".specsmith/agent-reports/",
|
|
244
|
+
".specsmith/dispatch/",
|
|
245
|
+
".specsmith/esdb_migration_manifest.json",
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def normalize_esdb_gitignore_policy(root: Path, *, dry_run: bool = False) -> bool:
|
|
250
|
+
"""Normalize ESDB gitignore policy for legacy projects.
|
|
251
|
+
|
|
252
|
+
Ensures broad ignores that hide canonical ESDB state are removed and that
|
|
253
|
+
explicit policy lines are present so SQLite/Chrono canonical artifacts are
|
|
254
|
+
always tracked while runtime files stay ignored.
|
|
255
|
+
"""
|
|
256
|
+
gitignore_path = root / ".gitignore"
|
|
257
|
+
if gitignore_path.exists():
|
|
258
|
+
original_lines = gitignore_path.read_text(encoding="utf-8").splitlines()
|
|
259
|
+
else:
|
|
260
|
+
original_lines = []
|
|
261
|
+
|
|
262
|
+
normalized_lines: list[str] = []
|
|
263
|
+
removed_forbidden = False
|
|
264
|
+
for line in original_lines:
|
|
265
|
+
if line.strip() in _ESDB_GITIGNORE_FORBIDDEN:
|
|
266
|
+
removed_forbidden = True
|
|
267
|
+
continue
|
|
268
|
+
normalized_lines.append(line)
|
|
269
|
+
|
|
270
|
+
existing = {line.strip() for line in normalized_lines if line.strip()}
|
|
271
|
+
missing = [entry for entry in _ESDB_GITIGNORE_REQUIRED if entry not in existing]
|
|
272
|
+
changed = removed_forbidden or bool(missing)
|
|
273
|
+
|
|
274
|
+
if not changed:
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
if normalized_lines and normalized_lines[-1].strip():
|
|
278
|
+
normalized_lines.append("")
|
|
279
|
+
if missing:
|
|
280
|
+
normalized_lines.append("# specsmith ESDB policy (auto-normalized)")
|
|
281
|
+
normalized_lines.extend(missing)
|
|
282
|
+
|
|
283
|
+
if not dry_run:
|
|
284
|
+
rendered = "\n".join(normalized_lines)
|
|
285
|
+
if rendered and not rendered.endswith("\n"):
|
|
286
|
+
rendered += "\n"
|
|
287
|
+
gitignore_path.write_text(rendered, encoding="utf-8")
|
|
288
|
+
|
|
289
|
+
return True
|
|
290
|
+
|
|
291
|
+
|
|
210
292
|
# ---------------------------------------------------------------------------
|
|
211
293
|
# Core sync
|
|
212
294
|
# ---------------------------------------------------------------------------
|
|
@@ -244,6 +326,8 @@ def run_sync(root: Path, *, dry_run: bool = False) -> SyncResult:
|
|
|
244
326
|
tests_md_path = root / "docs" / "TESTS.md"
|
|
245
327
|
reqs_json_path = state_dir / "requirements.json"
|
|
246
328
|
tests_json_path = state_dir / "testcases.json"
|
|
329
|
+
if not dry_run:
|
|
330
|
+
normalize_esdb_gitignore_policy(root)
|
|
247
331
|
|
|
248
332
|
if is_yaml_mode(root):
|
|
249
333
|
# ── YAML-first mode ─────────────────────────────────────────────────
|
|
@@ -45,6 +45,13 @@ htmlcov/
|
|
|
45
45
|
# - .specsmith/esdb.sqlite3
|
|
46
46
|
# - .chronomemory/events.wal
|
|
47
47
|
# - .chronomemory/snapshot.json
|
|
48
|
+
# Always track these even if broader ignore rules are added later:
|
|
49
|
+
!.specsmith/config.yml
|
|
50
|
+
!.specsmith/requirements.json
|
|
51
|
+
!.specsmith/testcases.json
|
|
52
|
+
!.specsmith/esdb.sqlite3
|
|
53
|
+
!.chronomemory/events.wal
|
|
54
|
+
!.chronomemory/snapshot.json
|
|
48
55
|
#
|
|
49
56
|
# Ignore runtime-only / regeneratable artifacts:
|
|
50
57
|
.chronomemory/backup/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.15.3.
|
|
3
|
+
Version: 0.15.3.dev572
|
|
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
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright (c) 2026 Layer1Labs Silicon, Inc. All rights reserved.
|
|
3
|
+
"""Regression tests for ESDB fallback and legacy policy enforcement."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import json
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
import pytest
|
|
11
|
+
from click.testing import CliRunner
|
|
12
|
+
|
|
13
|
+
from specsmith.cli import main
|
|
14
|
+
from specsmith.esdb.sqlite_store import SqliteRecord, SqliteStore
|
|
15
|
+
from specsmith.sync import run_sync
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _run(args: list[str]): # type: ignore[return] # noqa: ANN201
|
|
19
|
+
runner = CliRunner()
|
|
20
|
+
return runner.invoke(
|
|
21
|
+
main,
|
|
22
|
+
args,
|
|
23
|
+
env={
|
|
24
|
+
"SPECSMITH_NO_AUTO_UPDATE": "1",
|
|
25
|
+
"SPECSMITH_PYPI_CHECKED": "1",
|
|
26
|
+
"SPECSMITH_ALLOW_NON_PIPX": "1",
|
|
27
|
+
},
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_run_sync_normalizes_legacy_esdb_gitignore(tmp_path: Path) -> None:
|
|
32
|
+
"""Legacy broad ignores are removed and canonical ESDB policy is injected."""
|
|
33
|
+
(tmp_path / ".gitignore").write_text(
|
|
34
|
+
"\n".join(
|
|
35
|
+
[
|
|
36
|
+
".specsmith/",
|
|
37
|
+
".chronomemory/",
|
|
38
|
+
]
|
|
39
|
+
)
|
|
40
|
+
+ "\n",
|
|
41
|
+
encoding="utf-8",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
run_sync(tmp_path)
|
|
45
|
+
|
|
46
|
+
lines = {
|
|
47
|
+
line.strip()
|
|
48
|
+
for line in (tmp_path / ".gitignore").read_text(encoding="utf-8").splitlines()
|
|
49
|
+
if line.strip()
|
|
50
|
+
}
|
|
51
|
+
assert ".specsmith/" not in lines
|
|
52
|
+
assert ".chronomemory/" not in lines
|
|
53
|
+
assert ".chronomemory/backup/" in lines
|
|
54
|
+
assert ".specsmith/workitems.json" in lines
|
|
55
|
+
assert "!.specsmith/esdb.sqlite3" in lines
|
|
56
|
+
assert "!.chronomemory/events.wal" in lines
|
|
57
|
+
assert "!.chronomemory/snapshot.json" in lines
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_save_uses_sqlite_store_backup(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
61
|
+
"""specsmith save should create a SQLite backup when ChronoStore is unavailable."""
|
|
62
|
+
monkeypatch.setenv("SPECSMITH_ESDB_BACKEND", "sqlite")
|
|
63
|
+
with SqliteStore(tmp_path) as store:
|
|
64
|
+
store.upsert(
|
|
65
|
+
SqliteRecord(
|
|
66
|
+
id="REQ-001",
|
|
67
|
+
kind="requirement",
|
|
68
|
+
label="SQLite fallback requirement",
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
result = _run(["save", "--project-dir", str(tmp_path), "--no-push", "--json"])
|
|
73
|
+
assert result.exit_code == 0, result.output
|
|
74
|
+
payload = json.loads(result.output)
|
|
75
|
+
backup_step = next(step for step in payload["steps"] if step["step"] == "esdb_backup")
|
|
76
|
+
assert backup_step["ok"] is True
|
|
77
|
+
assert backup_step["backend"] == "sqlite"
|
|
78
|
+
|
|
79
|
+
backup_path = Path(backup_step["path"])
|
|
80
|
+
assert backup_path.is_file()
|
|
81
|
+
assert backup_path.suffix == ".sqlite3"
|
|
@@ -93,6 +93,9 @@ class TestScaffoldCLIPython:
|
|
|
93
93
|
assert ".chronomemory/backup/" in content
|
|
94
94
|
assert ".specsmith/workitems.json" in content
|
|
95
95
|
assert ".specsmith/esdb_migration_manifest.json" in content
|
|
96
|
+
assert "!.specsmith/esdb.sqlite3" in content
|
|
97
|
+
assert "!.chronomemory/events.wal" in content
|
|
98
|
+
assert "!.chronomemory/snapshot.json" in content
|
|
96
99
|
assert "\n.specsmith/\n" not in content
|
|
97
100
|
assert "\n.chronomemory/\n" not in content
|
|
98
101
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/dispatcher.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/execution_profiles.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/model_intelligence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{specsmith-0.15.3.dev570 → specsmith-0.15.3.dev572}/src/specsmith/agent/provider_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|