specsmith 0.15.3.dev568__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.dev568/src/specsmith.egg-info → specsmith-0.15.3.dev572}/PKG-INFO +8 -1
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/README.md +7 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/pyproject.toml +1 -1
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/auditor.py +11 -4
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/cli.py +80 -23
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/esdb/sqlite_store.py +16 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/codity.py +15 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/governance.py +15 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/sync.py +84 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/gitignore.j2 +35 -2
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572/src/specsmith.egg-info}/PKG-INFO +8 -1
- {specsmith-0.15.3.dev568 → 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.dev568 → specsmith-0.15.3.dev572}/tests/test_scaffolder.py +13 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/LICENSE +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/setup.cfg +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/belief.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/certainty.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/py.typed +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/recovery.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/session.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/epistemic/trace.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/__main__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/architect.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/auth.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/block_export.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/channel.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/compressor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/config.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/context_window.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/credits.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/differ.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/doctor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/drive.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/editor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/executor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/exporter.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/history_search.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/importer.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/instinct.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/languages.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/ledger.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/mcp_server.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/patent.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/paths.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/phase.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/plugins.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/profiles.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/releaser.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/requirements.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/serve.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/session.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/session_init.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/session_store.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/tools.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/trace.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/updater.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/validator.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/wi_store.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith/workspace.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_CMD_001.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_ai_client.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_auditor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_channel.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_cli.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_compliance.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_compliance_governance.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_compressor.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_dispatch.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_epistemic.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_esdb_license.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_importer.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_integrations.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_intelligence.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_mcp_client.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_mcp_server.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_new_modules.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_nexus.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_permissions.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_rate_limits.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_req_248_262.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_req_358_359.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_smoke.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_suggester.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_tools.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_validator.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_vcs.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_warp_parity.py +0 -0
- {specsmith-0.15.3.dev568 → specsmith-0.15.3.dev572}/tests/test_warp_parity_followup.py +0 -0
- {specsmith-0.15.3.dev568 → 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
|
|
@@ -231,6 +231,11 @@ No additional packages, no license key, no configuration — it works out of the
|
|
|
231
231
|
specsmith esdb status # shows: SQLite (free, MIT) — active by default
|
|
232
232
|
```
|
|
233
233
|
|
|
234
|
+
**ESDB version-control policy (this repository):**
|
|
235
|
+
- Commit canonical SQLite state file: `.specsmith/esdb.sqlite3`.
|
|
236
|
+
- Commit canonical ChronoMemory state files: `.chronomemory/events.wal` and `.chronomemory/snapshot.json`.
|
|
237
|
+
- Do not commit ChronoMemory timestamped backup copies under `.chronomemory/backup/` (regenerated by `specsmith save` / `specsmith esdb backup`).
|
|
238
|
+
|
|
234
239
|
**Upgrading to chronomemory ChronoStore (commercial):**
|
|
235
240
|
|
|
236
241
|
If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
@@ -1048,6 +1053,8 @@ This generates:
|
|
|
1048
1053
|
- `docs/codity-setup.md` — one-time setup checklist
|
|
1049
1054
|
- Appends a TODO checklist to `LEDGER.md`
|
|
1050
1055
|
|
|
1056
|
+
**Windows note:** Codity's `install.sh` is Linux/macOS only. For native PowerShell use, install `codity.exe` from the official `codity-ai/codity-cli` GitHub release zip and place it on PATH (for example `~/.local/bin`).
|
|
1057
|
+
|
|
1051
1058
|
**AGENTS.md rule (REQ-355):** Projects with Codity configured SHOULD run `codity review --staged` before any commit touching production code. HIGH-severity findings are blocking; MEDIUM findings require inline acknowledgement.
|
|
1052
1059
|
|
|
1053
1060
|
See the `codity-ai-review` governance skill (`specsmith skill install codity-ai-review`) for the full CLI workflow reference.
|
|
@@ -153,6 +153,11 @@ No additional packages, no license key, no configuration — it works out of the
|
|
|
153
153
|
specsmith esdb status # shows: SQLite (free, MIT) — active by default
|
|
154
154
|
```
|
|
155
155
|
|
|
156
|
+
**ESDB version-control policy (this repository):**
|
|
157
|
+
- Commit canonical SQLite state file: `.specsmith/esdb.sqlite3`.
|
|
158
|
+
- Commit canonical ChronoMemory state files: `.chronomemory/events.wal` and `.chronomemory/snapshot.json`.
|
|
159
|
+
- Do not commit ChronoMemory timestamped backup copies under `.chronomemory/backup/` (regenerated by `specsmith save` / `specsmith esdb backup`).
|
|
160
|
+
|
|
156
161
|
**Upgrading to chronomemory ChronoStore (commercial):**
|
|
157
162
|
|
|
158
163
|
If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
@@ -970,6 +975,8 @@ This generates:
|
|
|
970
975
|
- `docs/codity-setup.md` — one-time setup checklist
|
|
971
976
|
- Appends a TODO checklist to `LEDGER.md`
|
|
972
977
|
|
|
978
|
+
**Windows note:** Codity's `install.sh` is Linux/macOS only. For native PowerShell use, install `codity.exe` from the official `codity-ai/codity-cli` GitHub release zip and place it on PATH (for example `~/.local/bin`).
|
|
979
|
+
|
|
973
980
|
**AGENTS.md rule (REQ-355):** Projects with Codity configured SHOULD run `codity review --staged` before any commit touching production code. HIGH-severity findings are blocking; MEDIUM findings require inline acknowledgement.
|
|
974
981
|
|
|
975
982
|
See the `codity-ai-review` governance skill (`specsmith skill install codity-ai-review`) for the full CLI workflow reference.
|
|
@@ -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
|
|
@@ -229,6 +229,21 @@ steps:
|
|
|
229
229
|
```bash
|
|
230
230
|
curl -fsSL https://cli.codity.ai/install.sh | sh
|
|
231
231
|
```
|
|
232
|
+
Native Windows (PowerShell) is also supported via GitHub Releases
|
|
233
|
+
(`codity-ai/codity-cli`), because the shell installer is Linux/macOS only:
|
|
234
|
+
```powershell
|
|
235
|
+
# No official winget/scoop/choco package currently.
|
|
236
|
+
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/codity-ai/codity-cli/releases/latest"
|
|
237
|
+
$version = $release.tag_name.TrimStart("v")
|
|
238
|
+
$assetName = "codity_" + $version + "_windows_amd64.zip"
|
|
239
|
+
$asset = $release.assets | Where-Object {{ $_.name -eq $assetName }} | Select-Object -First 1
|
|
240
|
+
$zip = Join-Path $env:TEMP $asset.name
|
|
241
|
+
$tmp = Join-Path $env:TEMP ("codity-install-" + [guid]::NewGuid().ToString())
|
|
242
|
+
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip
|
|
243
|
+
Expand-Archive -Path $zip -DestinationPath $tmp -Force
|
|
244
|
+
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.local\\bin" | Out-Null
|
|
245
|
+
Copy-Item (Join-Path $tmp "codity.exe") "$env:USERPROFILE\\.local\\bin\\codity.exe" -Force
|
|
246
|
+
```
|
|
232
247
|
|
|
233
248
|
2. Authenticate:
|
|
234
249
|
```bash
|
|
@@ -1127,9 +1127,24 @@ generation that runs against staged changes (`--staged`) before every commit
|
|
|
1127
1127
|
that touches production code.
|
|
1128
1128
|
|
|
1129
1129
|
## Installation
|
|
1130
|
+
Linux/macOS:
|
|
1130
1131
|
```bash
|
|
1131
1132
|
curl -fsSL https://cli.codity.ai/install.sh | sh
|
|
1132
1133
|
```
|
|
1134
|
+
Native Windows (PowerShell):
|
|
1135
|
+
```powershell
|
|
1136
|
+
# No official winget/scoop/choco package currently.
|
|
1137
|
+
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/codity-ai/codity-cli/releases/latest"
|
|
1138
|
+
$version = $release.tag_name.TrimStart("v")
|
|
1139
|
+
$asset = $release.assets | Where-Object { $_.name -eq "codity_${version}_windows_amd64.zip" } | Select-Object -First 1
|
|
1140
|
+
$zip = Join-Path $env:TEMP $asset.name
|
|
1141
|
+
$tmp = Join-Path $env:TEMP ("codity-install-" + [guid]::NewGuid().ToString())
|
|
1142
|
+
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip
|
|
1143
|
+
Expand-Archive -Path $zip -DestinationPath $tmp -Force
|
|
1144
|
+
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\\.local\\bin" | Out-Null
|
|
1145
|
+
Copy-Item (Join-Path $tmp "codity.exe") "$env:USERPROFILE\\.local\\bin\\codity.exe" -Force
|
|
1146
|
+
```
|
|
1147
|
+
Verify with `codity doctor`.
|
|
1133
1148
|
|
|
1134
1149
|
## Authentication
|
|
1135
1150
|
```bash
|
|
@@ -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 ─────────────────────────────────────────────────
|
|
@@ -37,8 +37,41 @@ htmlcov/
|
|
|
37
37
|
.work/
|
|
38
38
|
*.log
|
|
39
39
|
|
|
40
|
-
# specsmith
|
|
41
|
-
|
|
40
|
+
# specsmith governance data policy
|
|
41
|
+
# Keep committed:
|
|
42
|
+
# - .specsmith/config.yml
|
|
43
|
+
# - .specsmith/requirements.json
|
|
44
|
+
# - .specsmith/testcases.json
|
|
45
|
+
# - .specsmith/esdb.sqlite3
|
|
46
|
+
# - .chronomemory/events.wal
|
|
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
|
|
55
|
+
#
|
|
56
|
+
# Ignore runtime-only / regeneratable artifacts:
|
|
57
|
+
.chronomemory/backup/
|
|
58
|
+
.specsmith/workitems.json
|
|
59
|
+
.specsmith/runs/
|
|
60
|
+
.specsmith/chat/
|
|
61
|
+
.specsmith/perf/
|
|
62
|
+
.specsmith/recovery/
|
|
63
|
+
.specsmith/ledger.jsonl
|
|
64
|
+
.specsmith/ledger-chain.txt
|
|
65
|
+
.specsmith/trace.jsonl
|
|
66
|
+
.specsmith/credit-budget.json
|
|
67
|
+
.specsmith/credits.json
|
|
68
|
+
.specsmith/model-rate-limits.json
|
|
69
|
+
.specsmith/pids/
|
|
70
|
+
.specsmith/logs/
|
|
71
|
+
.specsmith/sessions/
|
|
72
|
+
.specsmith/agent-reports/
|
|
73
|
+
.specsmith/dispatch/
|
|
74
|
+
.specsmith/esdb_migration_manifest.json
|
|
42
75
|
{% if project.type in ('cli-rust', 'library-rust') %}
|
|
43
76
|
|
|
44
77
|
# Rust
|
|
@@ -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
|
|
@@ -231,6 +231,11 @@ No additional packages, no license key, no configuration — it works out of the
|
|
|
231
231
|
specsmith esdb status # shows: SQLite (free, MIT) — active by default
|
|
232
232
|
```
|
|
233
233
|
|
|
234
|
+
**ESDB version-control policy (this repository):**
|
|
235
|
+
- Commit canonical SQLite state file: `.specsmith/esdb.sqlite3`.
|
|
236
|
+
- Commit canonical ChronoMemory state files: `.chronomemory/events.wal` and `.chronomemory/snapshot.json`.
|
|
237
|
+
- Do not commit ChronoMemory timestamped backup copies under `.chronomemory/backup/` (regenerated by `specsmith save` / `specsmith esdb backup`).
|
|
238
|
+
|
|
234
239
|
**Upgrading to chronomemory ChronoStore (commercial):**
|
|
235
240
|
|
|
236
241
|
If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
@@ -1048,6 +1053,8 @@ This generates:
|
|
|
1048
1053
|
- `docs/codity-setup.md` — one-time setup checklist
|
|
1049
1054
|
- Appends a TODO checklist to `LEDGER.md`
|
|
1050
1055
|
|
|
1056
|
+
**Windows note:** Codity's `install.sh` is Linux/macOS only. For native PowerShell use, install `codity.exe` from the official `codity-ai/codity-cli` GitHub release zip and place it on PATH (for example `~/.local/bin`).
|
|
1057
|
+
|
|
1051
1058
|
**AGENTS.md rule (REQ-355):** Projects with Codity configured SHOULD run `codity review --staged` before any commit touching production code. HIGH-severity findings are blocking; MEDIUM findings require inline acknowledgement.
|
|
1052
1059
|
|
|
1053
1060
|
See the `codity-ai-review` governance skill (`specsmith skill install codity-ai-review`) for the full CLI workflow reference.
|
|
@@ -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"
|
|
@@ -86,6 +86,19 @@ class TestScaffoldCLIPython:
|
|
|
86
86
|
files = scaffold_project(cfg, tmp_target)
|
|
87
87
|
assert len(files) >= 25 # baseline for cli-python type
|
|
88
88
|
|
|
89
|
+
def test_gitignore_tracks_canonical_esdb_files(self, tmp_target: Path) -> None:
|
|
90
|
+
cfg = _make_config(ProjectType.CLI_PYTHON)
|
|
91
|
+
scaffold_project(cfg, tmp_target)
|
|
92
|
+
content = (tmp_target / ".gitignore").read_text(encoding="utf-8")
|
|
93
|
+
assert ".chronomemory/backup/" in content
|
|
94
|
+
assert ".specsmith/workitems.json" in content
|
|
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
|
|
99
|
+
assert "\n.specsmith/\n" not in content
|
|
100
|
+
assert "\n.chronomemory/\n" not in content
|
|
101
|
+
|
|
89
102
|
|
|
90
103
|
class TestScaffoldFPGA:
|
|
91
104
|
"""Tests for FPGA/RTL project type."""
|
|
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.dev568 → specsmith-0.15.3.dev572}/src/specsmith/agent/dispatch/__init__.py
RENAMED
|
File without changes
|