specsmith 0.22.0__tar.gz → 0.22.2__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.22.0/src/specsmith.egg-info → specsmith-0.22.2}/PKG-INFO +7 -4
- {specsmith-0.22.0 → specsmith-0.22.2}/README.md +5 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/pyproject.toml +5 -5
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/__init__.py +1 -1
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/broker.py +11 -2
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/cli.py +81 -60
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/config.py +1 -1
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_logic.py +36 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs_commands.py +15 -3
- {specsmith-0.22.0 → specsmith-0.22.2/src/specsmith.egg-info}/PKG-INFO +7 -4
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/SOURCES.txt +4 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/requires.txt +1 -3
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli.py +62 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_license.py +12 -0
- specsmith-0.22.2/tests/test_esdb_migrate_wal_repair.py +79 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_nexus.py +42 -0
- specsmith-0.22.2/tests/test_release_version_contract.py +36 -0
- specsmith-0.22.2/tests/test_rtd_deploy_workflow.py +22 -0
- specsmith-0.22.2/tests/test_vcs_commands.py +57 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/LICENSE +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/setup.cfg +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/belief.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/certainty.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/py.typed +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/recovery.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/session.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/epistemic/trace.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/__main__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/advanced_code_analysis.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/model_router.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/terminal_env.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/token_pricing.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/approvals.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/architect.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/auditor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/auth.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/block_export.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/channel.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/chat_handoff.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/code_analysis.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/issues_policy.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/reporting.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/commands/zoo_code.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/compressor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/context_window.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/credits.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/dashboard.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/differ.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/doctor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/drive.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/editor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/efficiency.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb/sqlite_store.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb_sweep.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/esdb_writer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/executor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/exporter.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/governed_pr.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/history_search.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/importer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/improvement_tracker.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/instinct.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/codity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/warp.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/languages.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ledger.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/local_model.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/mcp_server.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m007_yaml_first.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m008_esdb_full_coverage.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m009_esdb_first.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m010_post_esdb_cleanup.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m011_windows_skill_shell.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/m012_normalize_skill_shell.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/model_optimizer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/model_registry.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/patent.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/paths.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/phase.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/plugins.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/policy.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/profiles.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/project_metrics.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/quality_report.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/recover.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/release_guard.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/releaser.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/requirements.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/risk.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/serve.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session_init.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/session_store.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/governance.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_core_commands.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_operations.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/sync.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/tools.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/trace.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/transcripts.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/updater.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/validator.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/wi_store.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith/workspace.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_CMD_001.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_ai_client.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architect_interview.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architect_v2.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_architecture.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_audit_governance.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_auditor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_benchmark_harness.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_branch_workflow.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_broker_scope.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_channel.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_handoff.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cleanup_cmd.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli_regressions.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compliance.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compliance_governance.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_compressor.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_deprecation_registry.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_dispatch.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_docs_artifacts.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_dual_write.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_efficiency.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_epistemic.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_backend_switch.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_enforcement.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_integration.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_status_integrity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_status_output.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_sweep.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_verify_chain_cli.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_esdb_writer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_golden_path.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_importer.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_improvement_tracker.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_init_modes.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_integrations_warp.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_intelligence.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issue_policy_features.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_issues_263_264.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_local_model.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_markdown_deprecation.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_mcp_client.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_mcp_server.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_metrics_flush.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_migration_direction.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_migrations_skill_shell.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_model_registry.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_model_router.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_new_modules.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_parallel_agents.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_permissions.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_project_metrics.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_quality_report.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_rate_limits.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_release_guard.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_releaser.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_repl.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_repl_extended.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_reporting_commands.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_req_248_262.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_req_358_359.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_resume_command.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_scaffolder.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_schema_migrations.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_session_events.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_smoke.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_sqlite_parity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_suggester.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_sync_reconcile.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_terminal_env.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_token_cost.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_tools.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_trace_vault_esdb.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_typing_guardrails.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_updater.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_validator.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_vcs.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_warp_parity.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_warp_parity_followup.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_wi_lifecycle.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_wi_lifecycle_extended.py +0 -0
- {specsmith-0.22.0 → specsmith-0.22.2}/tests/test_windows_launcher.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.2
|
|
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
|
|
@@ -27,6 +27,7 @@ Requires-Python: >=3.10
|
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: click>=8.1
|
|
30
|
+
Requires-Dist: cryptography>=42.0
|
|
30
31
|
Requires-Dist: jinja2>=3.1
|
|
31
32
|
Requires-Dist: pyyaml>=6.0
|
|
32
33
|
Requires-Dist: pydantic>=2.0
|
|
@@ -38,10 +39,8 @@ Requires-Dist: ruff>=0.4; extra == "dev"
|
|
|
38
39
|
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
39
40
|
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
40
41
|
Requires-Dist: types-pyyaml>=6.0; extra == "dev"
|
|
41
|
-
Requires-Dist: cryptography>=42.0; extra == "dev"
|
|
42
42
|
Provides-Extra: esdb
|
|
43
43
|
Requires-Dist: chronomemory>=0.2.7; extra == "esdb"
|
|
44
|
-
Requires-Dist: cryptography>=42.0; extra == "esdb"
|
|
45
44
|
Provides-Extra: docs
|
|
46
45
|
Requires-Dist: mkdocs>=1.6; extra == "docs"
|
|
47
46
|
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
@@ -73,7 +72,6 @@ Requires-Dist: pytest-cov>=4.0; extra == "all"
|
|
|
73
72
|
Requires-Dist: ruff>=0.4; extra == "all"
|
|
74
73
|
Requires-Dist: mypy>=1.10; extra == "all"
|
|
75
74
|
Provides-Extra: license-verify
|
|
76
|
-
Requires-Dist: cryptography>=42.0; extra == "license-verify"
|
|
77
75
|
Dynamic: license-file
|
|
78
76
|
|
|
79
77
|
# specsmith
|
|
@@ -317,6 +315,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
|
317
315
|
pip install "specsmith[esdb]" # installs chronomemory from PyPI
|
|
318
316
|
# or if using pipx:
|
|
319
317
|
pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
|
|
318
|
+
# The license verifier is included in base specsmith; no cryptography injection is needed.
|
|
320
319
|
|
|
321
320
|
# Step 2 — activate your license key
|
|
322
321
|
specsmith esdb enable --key-file /path/to/your.esdb.key
|
|
@@ -340,6 +339,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
|
|
|
340
339
|
specsmith self-update # alternative: self-update from within specsmith
|
|
341
340
|
```
|
|
342
341
|
|
|
342
|
+
An intent limited to maintaining the local pipx CLI is returned as the non-blocking
|
|
343
|
+
`environment_only` preflight decision. It exits successfully and creates no project
|
|
344
|
+
work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
|
|
345
|
+
|
|
343
346
|
---
|
|
344
347
|
|
|
345
348
|
## Quick Start
|
|
@@ -239,6 +239,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
|
239
239
|
pip install "specsmith[esdb]" # installs chronomemory from PyPI
|
|
240
240
|
# or if using pipx:
|
|
241
241
|
pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
|
|
242
|
+
# The license verifier is included in base specsmith; no cryptography injection is needed.
|
|
242
243
|
|
|
243
244
|
# Step 2 — activate your license key
|
|
244
245
|
specsmith esdb enable --key-file /path/to/your.esdb.key
|
|
@@ -262,6 +263,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
|
|
|
262
263
|
specsmith self-update # alternative: self-update from within specsmith
|
|
263
264
|
```
|
|
264
265
|
|
|
266
|
+
An intent limited to maintaining the local pipx CLI is returned as the non-blocking
|
|
267
|
+
`environment_only` preflight decision. It exits successfully and creates no project
|
|
268
|
+
work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
|
|
269
|
+
|
|
265
270
|
---
|
|
266
271
|
|
|
267
272
|
## Quick Start
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.22.
|
|
7
|
+
version = "0.22.2"
|
|
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"
|
|
@@ -37,6 +37,8 @@ classifiers = [
|
|
|
37
37
|
|
|
38
38
|
dependencies = [
|
|
39
39
|
"click>=8.1",
|
|
40
|
+
# `specsmith esdb enable` verifies Ed25519 license signatures in every install.
|
|
41
|
+
"cryptography>=42.0",
|
|
40
42
|
"jinja2>=3.1",
|
|
41
43
|
"pyyaml>=6.0",
|
|
42
44
|
"pydantic>=2.0",
|
|
@@ -54,7 +56,6 @@ dev = [
|
|
|
54
56
|
"mypy>=1.10",
|
|
55
57
|
"pre-commit>=3.0",
|
|
56
58
|
"types-pyyaml>=6.0",
|
|
57
|
-
"cryptography>=42.0", # needed for test_esdb_license.py signing helpers
|
|
58
59
|
]
|
|
59
60
|
# ESDB commercial backend — requires a valid license from licensing@layer1labs.ai
|
|
60
61
|
# Install: pip install specsmith[esdb]
|
|
@@ -62,7 +63,6 @@ dev = [
|
|
|
62
63
|
# Terms: https://github.com/layer1labs/specsmith/blob/develop/COMMERCIAL-LICENSE.md
|
|
63
64
|
esdb = [
|
|
64
65
|
"chronomemory>=0.2.7", # proprietary commercial — ChronoMemory terms only (not SQLite free tier)
|
|
65
|
-
"cryptography>=42.0",
|
|
66
66
|
]
|
|
67
67
|
docs = [
|
|
68
68
|
"mkdocs>=1.6",
|
|
@@ -95,8 +95,8 @@ all = [
|
|
|
95
95
|
"ruff>=0.4",
|
|
96
96
|
"mypy>=1.10",
|
|
97
97
|
]
|
|
98
|
-
# cryptography
|
|
99
|
-
license-verify = [
|
|
98
|
+
# Compatibility extra: cryptography is now part of every supported installation.
|
|
99
|
+
license-verify = []
|
|
100
100
|
|
|
101
101
|
[project.scripts]
|
|
102
102
|
specsmith = "specsmith.cli:main"
|
|
@@ -8,4 +8,4 @@ from importlib.metadata import version as _pkg_version
|
|
|
8
8
|
try:
|
|
9
9
|
__version__: str = _pkg_version("specsmith")
|
|
10
10
|
except PackageNotFoundError: # running from source without install
|
|
11
|
-
__version__ = "0.22.
|
|
11
|
+
__version__ = "0.22.2" # fallback: keep in sync with pyproject.toml
|
|
@@ -416,7 +416,12 @@ class PreflightDecision:
|
|
|
416
416
|
|
|
417
417
|
@property
|
|
418
418
|
def accepted(self) -> bool:
|
|
419
|
-
return self.decision.lower()
|
|
419
|
+
return self.decision.lower() in {"accepted", "environment_only"}
|
|
420
|
+
|
|
421
|
+
@property
|
|
422
|
+
def environment_only(self) -> bool:
|
|
423
|
+
"""Whether this decision permits local tool maintenance only."""
|
|
424
|
+
return self.decision.lower() == "environment_only"
|
|
420
425
|
|
|
421
426
|
|
|
422
427
|
def _resolve_specsmith_executable() -> str:
|
|
@@ -523,7 +528,11 @@ def narrate_plan(
|
|
|
523
528
|
else:
|
|
524
529
|
lines.append("No matching governance scope found; will ask before drafting anything new.")
|
|
525
530
|
|
|
526
|
-
if decision.
|
|
531
|
+
if decision.environment_only:
|
|
532
|
+
lines.append(
|
|
533
|
+
"Environment-only SpecSmith CLI maintenance may proceed; no project work is governed."
|
|
534
|
+
)
|
|
535
|
+
elif decision.accepted:
|
|
527
536
|
lines.append("Specsmith approved this work.")
|
|
528
537
|
elif decision.decision == "needs_clarification":
|
|
529
538
|
# Surface only one clarifying question (REQ-063 stop-and-align).
|
|
@@ -130,9 +130,11 @@ class _AutoUpdateGroup(click.Group):
|
|
|
130
130
|
warnings.simplefilter("ignore", DeprecationWarning)
|
|
131
131
|
protected = list(ctx.protected_args) # [subcommand] in 8.x, [] in 9.0
|
|
132
132
|
subcommand = protected[0] if protected else (ctx.args[0] if ctx.args else "")
|
|
133
|
+
help_requested = any(arg in {"--help", "-h"} for arg in (*protected, *ctx.args))
|
|
133
134
|
skip = (
|
|
134
135
|
os.environ.get("SPECSMITH_NO_AUTO_UPDATE", "").strip() in ("1", "true", "yes")
|
|
135
136
|
or subcommand in self._SKIP_COMMANDS
|
|
137
|
+
or help_requested
|
|
136
138
|
)
|
|
137
139
|
|
|
138
140
|
if not skip:
|
|
@@ -939,7 +941,7 @@ def preflight_cmd(
|
|
|
939
941
|
|
|
940
942
|
# REQ-092: decision-specific exit codes so CI / shell wrappers can branch
|
|
941
943
|
# on intent without parsing the JSON payload.
|
|
942
|
-
if decision_str
|
|
944
|
+
if decision_str in {"accepted", "environment_only"}:
|
|
943
945
|
return # exit 0
|
|
944
946
|
if decision_str == "needs_clarification":
|
|
945
947
|
raise SystemExit(2)
|
|
@@ -3853,7 +3855,7 @@ def channel_set_cmd(channel: str) -> None:
|
|
|
3853
3855
|
if channel == "stable" and is_prerelease_version(__version__):
|
|
3854
3856
|
raise click.UsageError(
|
|
3855
3857
|
"Cannot select stable while a prerelease is installed. "
|
|
3856
|
-
f"Install a stable build first: {version_mismatch_remediation('0.22.
|
|
3858
|
+
f"Install a stable build first: {version_mismatch_remediation('0.22.2')}"
|
|
3857
3859
|
)
|
|
3858
3860
|
|
|
3859
3861
|
set_persisted_channel(channel)
|
|
@@ -4100,7 +4102,7 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
4100
4102
|
pass
|
|
4101
4103
|
|
|
4102
4104
|
# ── Phase ─────────────────────────────────────────────────────────────────
|
|
4103
|
-
phase_key, phase_label,
|
|
4105
|
+
phase_key, phase_label, phase_pct = "unknown", "Unknown", 0
|
|
4104
4106
|
try:
|
|
4105
4107
|
from specsmith.phase import PHASE_MAP, phase_progress_pct, read_phase
|
|
4106
4108
|
|
|
@@ -4108,7 +4110,6 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
4108
4110
|
phase = PHASE_MAP.get(phase_key)
|
|
4109
4111
|
if phase:
|
|
4110
4112
|
phase_label = phase.label
|
|
4111
|
-
phase_emoji = phase.emoji
|
|
4112
4113
|
phase_pct = phase_progress_pct(phase, root)
|
|
4113
4114
|
except Exception: # noqa: BLE001
|
|
4114
4115
|
pass
|
|
@@ -4203,7 +4204,7 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
4203
4204
|
"ts": ts,
|
|
4204
4205
|
"project": project_name,
|
|
4205
4206
|
"phase": phase_key,
|
|
4206
|
-
"phase_label":
|
|
4207
|
+
"phase_label": phase_label,
|
|
4207
4208
|
"phase_pct": phase_pct,
|
|
4208
4209
|
"health": "clean" if health_ok else f"{audit_failed} issues",
|
|
4209
4210
|
"audit_failed": audit_failed,
|
|
@@ -4223,69 +4224,37 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
4223
4224
|
|
|
4224
4225
|
# ── Human-readable anchor block ───────────────────────────────────────────
|
|
4225
4226
|
# Designed to be compact and survive context summarization.
|
|
4226
|
-
_w =
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
health_icon = "\u2713" if health_ok else "\u2717"
|
|
4230
|
-
esdb_icon = "\u2713" if esdb_ok else "\u2717"
|
|
4227
|
+
_w = 72
|
|
4228
|
+
health_status = "OK" if health_ok else "FAIL"
|
|
4229
|
+
esdb_status = "OK" if esdb_ok else "FAIL"
|
|
4231
4230
|
if esdb_backend == "chronomemory":
|
|
4232
|
-
esdb_field = f"ESDB: {esdb_records} records
|
|
4231
|
+
esdb_field = f"ESDB: chronomemory {esdb_records} records chain={esdb_status}"
|
|
4233
4232
|
elif esdb_backend == "sqlite":
|
|
4234
|
-
|
|
4235
|
-
# " REQs : NNN TESTs: NNN " = 30 chars, leaving 27 for esdb_field.
|
|
4236
|
-
esdb_field = f"ESDB: SQLite {esdb_records} recs {esdb_icon}"
|
|
4233
|
+
esdb_field = f"ESDB: sqlite {esdb_records} records chain={esdb_status}"
|
|
4237
4234
|
else:
|
|
4238
4235
|
esdb_field = "ESDB: N/A"
|
|
4239
4236
|
wi_str = ", ".join(recent_wis) if recent_wis else "none seen"
|
|
4240
4237
|
|
|
4241
|
-
def _arow(
|
|
4242
|
-
"""
|
|
4238
|
+
def _arow(content: str) -> str:
|
|
4239
|
+
"""Return an ASCII-only row with a stable terminal-column width."""
|
|
4240
|
+
ascii_content = content.encode("ascii", "backslashreplace").decode("ascii")
|
|
4241
|
+
return f"|{ascii_content[:_w].ljust(_w)}|"
|
|
4243
4242
|
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
r1 = f" GOVERNANCE ANCHOR {ts}"
|
|
4254
|
-
console.print(_arow(r1, r1))
|
|
4255
|
-
|
|
4256
|
-
r2_plain = f" Project : {project_name}"
|
|
4257
|
-
console.print(_arow(f" Project : [bold]{project_name}[/bold]", r2_plain))
|
|
4258
|
-
|
|
4259
|
-
# Emoji omitted from the anchor box: full-width glyphs vary by terminal
|
|
4260
|
-
# and break the fixed-width box alignment unpredictably (GH #align).
|
|
4261
|
-
r3_plain = f" Phase : {phase_label} ({phase_pct}%)"
|
|
4262
|
-
console.print(_arow(r3_plain, r3_plain))
|
|
4263
|
-
|
|
4264
|
-
r4_plain = (
|
|
4265
|
-
f" Health : {health_icon} clean"
|
|
4266
|
-
if health_ok
|
|
4267
|
-
else f" Health : {health_icon} {audit_failed} issues"
|
|
4268
|
-
)
|
|
4269
|
-
r4_rich = (
|
|
4270
|
-
f" Health : [green]{health_icon} clean[/green]"
|
|
4271
|
-
if health_ok
|
|
4272
|
-
else f" Health : [red]{health_icon} {audit_failed} issues[/red]"
|
|
4273
|
-
)
|
|
4274
|
-
console.print(_arow(r4_rich, r4_plain))
|
|
4275
|
-
|
|
4276
|
-
r5 = f" REQs : {req_count} TESTs: {test_count} {esdb_field}"
|
|
4277
|
-
console.print(_arow(r5, r5))
|
|
4278
|
-
|
|
4279
|
-
r6 = f" WIs : {wi_str}"
|
|
4280
|
-
console.print(_arow(r6, r6))
|
|
4243
|
+
click.echo("+" + "-" * _w + "+")
|
|
4244
|
+
click.echo(_arow(f" GOVERNANCE ANCHOR {ts}"))
|
|
4245
|
+
click.echo(_arow(f" Project : {project_name}"))
|
|
4246
|
+
click.echo(_arow(f" Phase : {phase_label} ({phase_pct}%)"))
|
|
4247
|
+
health_field = "clean" if health_ok else f"{audit_failed} issues"
|
|
4248
|
+
click.echo(_arow(f" Health : {health_status} {health_field}"))
|
|
4249
|
+
click.echo(_arow(f" REQs : {req_count} TESTs: {test_count} {esdb_field}"))
|
|
4250
|
+
click.echo(_arow(f" WIs : {wi_str}"))
|
|
4281
4251
|
|
|
4282
4252
|
if last_preflight:
|
|
4283
|
-
_pf_max = _w - len(" Preflight: ")
|
|
4253
|
+
_pf_max = _w - len(" Preflight: ")
|
|
4284
4254
|
pf_short = last_preflight[:_pf_max]
|
|
4285
|
-
|
|
4286
|
-
console.print(_arow(r7, r7))
|
|
4255
|
+
click.echo(_arow(f" Preflight: {pf_short}"))
|
|
4287
4256
|
|
|
4288
|
-
|
|
4257
|
+
click.echo("+" + "-" * _w + "+")
|
|
4289
4258
|
console.print(
|
|
4290
4259
|
"[dim]Include this block verbatim in any context summary "
|
|
4291
4260
|
r"(\`specsmith checkpoint\` re-generates it).[/dim]",
|
|
@@ -11975,18 +11944,50 @@ def esdb_migrate_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
11975
11944
|
}
|
|
11976
11945
|
|
|
11977
11946
|
manifest_path = root / ".specsmith" / "esdb_migration_manifest.json"
|
|
11978
|
-
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
11979
|
-
manifest_path.write_text(_json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
11980
11947
|
|
|
11981
11948
|
# --- Phase 2: migrate into active ESDB backend (if validation passed) ---
|
|
11982
11949
|
migrate_counts: dict[str, int] = {}
|
|
11950
|
+
wal_repair: dict[str, Any] = {"attempted": False}
|
|
11983
11951
|
if ok:
|
|
11984
11952
|
try:
|
|
11985
11953
|
from specsmith.esdb import open_default_store
|
|
11986
11954
|
|
|
11987
11955
|
with open_default_store(root, warn=False) as store: # type: ignore[attr-defined]
|
|
11956
|
+
from specsmith.esdb import ESDB_BACKEND
|
|
11957
|
+
|
|
11958
|
+
chain_valid = getattr(store, "chain_valid", None)
|
|
11959
|
+
is_invalid_chrono_wal = (
|
|
11960
|
+
ESDB_BACKEND == "chronomemory"
|
|
11961
|
+
and callable(chain_valid)
|
|
11962
|
+
and chain_valid() is False
|
|
11963
|
+
)
|
|
11964
|
+
if is_invalid_chrono_wal:
|
|
11965
|
+
# ChronoMemory < 0.1.3 can retain readable records in a
|
|
11966
|
+
# WAL whose historical hash chain no longer validates.
|
|
11967
|
+
# Back up first, then compact to rebuild the chain safely.
|
|
11968
|
+
wal_repair = {
|
|
11969
|
+
"attempted": True,
|
|
11970
|
+
"detected_invalid": True,
|
|
11971
|
+
"method": "backup_then_compact",
|
|
11972
|
+
}
|
|
11973
|
+
backup = getattr(store, "backup", None)
|
|
11974
|
+
compact = getattr(store, "compact", None)
|
|
11975
|
+
if not callable(backup) or not callable(compact):
|
|
11976
|
+
raise RuntimeError(
|
|
11977
|
+
"ChronoStore cannot repair a legacy WAL because backup() or "
|
|
11978
|
+
"compact() is unavailable",
|
|
11979
|
+
)
|
|
11980
|
+
backup_path = backup()
|
|
11981
|
+
wal_repair["backup_path"] = str(backup_path)
|
|
11982
|
+
compact()
|
|
11983
|
+
wal_repair["chain_valid_after"] = chain_valid() is not False
|
|
11984
|
+
if not wal_repair["chain_valid_after"]:
|
|
11985
|
+
raise RuntimeError(
|
|
11986
|
+
"ChronoStore compact() did not restore WAL chain validity"
|
|
11987
|
+
)
|
|
11988
|
+
wal_repair["ok"] = True
|
|
11989
|
+
|
|
11988
11990
|
migrate_counts = store.migrate_from_json(root / ".specsmith")
|
|
11989
|
-
from specsmith.esdb import ESDB_BACKEND
|
|
11990
11991
|
|
|
11991
11992
|
manifest["migrated"] = migrate_counts
|
|
11992
11993
|
if ESDB_BACKEND == "chronomemory":
|
|
@@ -11994,7 +11995,27 @@ def esdb_migrate_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
11994
11995
|
else:
|
|
11995
11996
|
manifest["backend"] = "SQLite (.specsmith/esdb.sqlite3)"
|
|
11996
11997
|
except Exception as _me: # noqa: BLE001
|
|
11998
|
+
issue_kind = "legacy-wal-chain-repair" if wal_repair["attempted"] else "esdb-migration"
|
|
11999
|
+
migration_issue = {"kind": issue_kind, "detail": str(_me)}
|
|
12000
|
+
issues.append(migration_issue)
|
|
12001
|
+
errors.append(migration_issue)
|
|
12002
|
+
ok = False
|
|
11997
12003
|
manifest["chrono_error"] = str(_me)
|
|
12004
|
+
if wal_repair["attempted"]:
|
|
12005
|
+
wal_repair["ok"] = False
|
|
12006
|
+
|
|
12007
|
+
manifest["ok"] = ok
|
|
12008
|
+
manifest["issues"] = issues
|
|
12009
|
+
manifest["error_count"] = len(errors)
|
|
12010
|
+
manifest["warning_count"] = len(issues) - len(errors)
|
|
12011
|
+
manifest["wal_repair"] = wal_repair
|
|
12012
|
+
manifest["next_step"] = (
|
|
12013
|
+
"Ready for ChronoMemory native ingestion."
|
|
12014
|
+
if ok
|
|
12015
|
+
else "Fix errors above, then re-run to update the manifest."
|
|
12016
|
+
)
|
|
12017
|
+
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
12018
|
+
manifest_path.write_text(_json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
|
|
11998
12019
|
|
|
11999
12020
|
if as_json:
|
|
12000
12021
|
click.echo(_json.dumps(manifest, indent=2))
|
|
@@ -140,7 +140,7 @@ class ProjectConfig(BaseModel):
|
|
|
140
140
|
),
|
|
141
141
|
)
|
|
142
142
|
language: str = Field(default="python", description="Primary language/runtime")
|
|
143
|
-
spec_version: str = Field(default="0.22.
|
|
143
|
+
spec_version: str = Field(default="0.22.2", description="Spec version to scaffold from")
|
|
144
144
|
description: str = Field(default="", description="Short project description")
|
|
145
145
|
|
|
146
146
|
# Options
|
|
@@ -19,6 +19,16 @@ from pathlib import Path
|
|
|
19
19
|
from typing import Any, cast
|
|
20
20
|
|
|
21
21
|
|
|
22
|
+
def _is_environment_only_specsmith_upgrade(utterance: str) -> bool:
|
|
23
|
+
"""Return whether an utterance only maintains the local pipx CLI."""
|
|
24
|
+
text = utterance.casefold()
|
|
25
|
+
return (
|
|
26
|
+
"specsmith" in text
|
|
27
|
+
and "pipx" in text
|
|
28
|
+
and any(action in text for action in ("install", "update", "upgrade"))
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
22
32
|
def _safe_resolve(path: str | Path) -> Path:
|
|
23
33
|
"""Resolve a project directory path and reject traversal sequences.
|
|
24
34
|
|
|
@@ -88,6 +98,32 @@ def run_preflight(
|
|
|
88
98
|
_safe_root = os.path.realpath(_raw)
|
|
89
99
|
_root_str = _safe_root # alias used by helpers later in this function
|
|
90
100
|
intent = classify_intent(utterance)
|
|
101
|
+
|
|
102
|
+
# Local pipx maintenance is not a repository change. Return before scope
|
|
103
|
+
# inference and persistence so the command cannot dirty a governed project.
|
|
104
|
+
if _is_environment_only_specsmith_upgrade(utterance):
|
|
105
|
+
return {
|
|
106
|
+
"decision": "environment_only",
|
|
107
|
+
"scope": "environment_only",
|
|
108
|
+
"work_item_id": "",
|
|
109
|
+
"requirement_ids": [],
|
|
110
|
+
"test_case_ids": [],
|
|
111
|
+
"confidence_target": 1.0,
|
|
112
|
+
"instruction": (
|
|
113
|
+
"Pipx-managed local SpecSmith CLI maintenance is outside project governance. "
|
|
114
|
+
"Proceed with `pipx upgrade specsmith`; no project work item or "
|
|
115
|
+
"records were created."
|
|
116
|
+
),
|
|
117
|
+
"intent": intent.value,
|
|
118
|
+
"ai_disclosure": {
|
|
119
|
+
"governed_by": "specsmith",
|
|
120
|
+
"governance_gated": True,
|
|
121
|
+
"provider": os.environ.get("SPECSMITH_PROVIDER", "local/heuristic"),
|
|
122
|
+
"model": os.environ.get("SPECSMITH_MODEL", "deterministic-broker"),
|
|
123
|
+
"spec_version": __version__,
|
|
124
|
+
},
|
|
125
|
+
}
|
|
126
|
+
|
|
91
127
|
# Requirements scope source for keyword matching in infer_scope().
|
|
92
128
|
# Requirements are sourced from .specsmith/requirements.json (YAML-first mode);
|
|
93
129
|
# the REQUIREMENTS.md markdown is only a token-overlap fallback. The canonical
|
|
@@ -39,9 +39,16 @@ def _run_git(root: Path, args: list[str], *, timeout: int = 30) -> GitResult:
|
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
def get_current_branch(root: Path) -> str:
|
|
42
|
-
"""Get the current git branch name."""
|
|
42
|
+
"""Get the current git branch name for the supplied worktree."""
|
|
43
43
|
result = _run_git(root, ["branch", "--show-current"])
|
|
44
|
-
|
|
44
|
+
branch = result.output.strip() if result.success else ""
|
|
45
|
+
if branch:
|
|
46
|
+
return branch
|
|
47
|
+
|
|
48
|
+
# ``branch --show-current`` is empty in some shell/worktree combinations
|
|
49
|
+
# despite HEAD being attached. ``symbolic-ref`` is the authoritative fallback.
|
|
50
|
+
result = _run_git(root, ["symbolic-ref", "--quiet", "--short", "HEAD"])
|
|
51
|
+
return result.output.strip() if result.success else ""
|
|
45
52
|
|
|
46
53
|
|
|
47
54
|
def has_uncommitted_changes(root: Path) -> bool:
|
|
@@ -166,7 +173,12 @@ def run_push(root: Path, *, force: bool = False) -> GitResult:
|
|
|
166
173
|
|
|
167
174
|
branch = get_current_branch(root)
|
|
168
175
|
if not branch:
|
|
169
|
-
|
|
176
|
+
worktree = _run_git(root, ["rev-parse", "--show-toplevel"])
|
|
177
|
+
inspected = worktree.output.strip() if worktree.success else str(root.resolve())
|
|
178
|
+
return GitResult(
|
|
179
|
+
success=False,
|
|
180
|
+
message=f"Not on any branch in git worktree: {inspected}",
|
|
181
|
+
)
|
|
170
182
|
|
|
171
183
|
# Safety: check branching strategy
|
|
172
184
|
from specsmith.paths import find_scaffold
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.2
|
|
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
|
|
@@ -27,6 +27,7 @@ Requires-Python: >=3.10
|
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
License-File: LICENSE
|
|
29
29
|
Requires-Dist: click>=8.1
|
|
30
|
+
Requires-Dist: cryptography>=42.0
|
|
30
31
|
Requires-Dist: jinja2>=3.1
|
|
31
32
|
Requires-Dist: pyyaml>=6.0
|
|
32
33
|
Requires-Dist: pydantic>=2.0
|
|
@@ -38,10 +39,8 @@ Requires-Dist: ruff>=0.4; extra == "dev"
|
|
|
38
39
|
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
39
40
|
Requires-Dist: pre-commit>=3.0; extra == "dev"
|
|
40
41
|
Requires-Dist: types-pyyaml>=6.0; extra == "dev"
|
|
41
|
-
Requires-Dist: cryptography>=42.0; extra == "dev"
|
|
42
42
|
Provides-Extra: esdb
|
|
43
43
|
Requires-Dist: chronomemory>=0.2.7; extra == "esdb"
|
|
44
|
-
Requires-Dist: cryptography>=42.0; extra == "esdb"
|
|
45
44
|
Provides-Extra: docs
|
|
46
45
|
Requires-Dist: mkdocs>=1.6; extra == "docs"
|
|
47
46
|
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
@@ -73,7 +72,6 @@ Requires-Dist: pytest-cov>=4.0; extra == "all"
|
|
|
73
72
|
Requires-Dist: ruff>=0.4; extra == "all"
|
|
74
73
|
Requires-Dist: mypy>=1.10; extra == "all"
|
|
75
74
|
Provides-Extra: license-verify
|
|
76
|
-
Requires-Dist: cryptography>=42.0; extra == "license-verify"
|
|
77
75
|
Dynamic: license-file
|
|
78
76
|
|
|
79
77
|
# specsmith
|
|
@@ -317,6 +315,7 @@ If you hold a chronomemory ESDB license, activate the commercial backend:
|
|
|
317
315
|
pip install "specsmith[esdb]" # installs chronomemory from PyPI
|
|
318
316
|
# or if using pipx:
|
|
319
317
|
pipx inject specsmith "chronomemory>=0.2.0" # inject into the specsmith pipx venv
|
|
318
|
+
# The license verifier is included in base specsmith; no cryptography injection is needed.
|
|
320
319
|
|
|
321
320
|
# Step 2 — activate your license key
|
|
322
321
|
specsmith esdb enable --key-file /path/to/your.esdb.key
|
|
@@ -340,6 +339,10 @@ pipx upgrade specsmith # preferred — upgrades the pipx-isolated CLI
|
|
|
340
339
|
specsmith self-update # alternative: self-update from within specsmith
|
|
341
340
|
```
|
|
342
341
|
|
|
342
|
+
An intent limited to maintaining the local pipx CLI is returned as the non-blocking
|
|
343
|
+
`environment_only` preflight decision. It exits successfully and creates no project
|
|
344
|
+
work item, ledger entry, or ESDB record. All `--help` invocations are read-only.
|
|
345
|
+
|
|
343
346
|
---
|
|
344
347
|
|
|
345
348
|
## Quick Start
|
|
@@ -321,6 +321,7 @@ tests/test_esdb_backend_switch.py
|
|
|
321
321
|
tests/test_esdb_enforcement.py
|
|
322
322
|
tests/test_esdb_integration.py
|
|
323
323
|
tests/test_esdb_license.py
|
|
324
|
+
tests/test_esdb_migrate_wal_repair.py
|
|
324
325
|
tests/test_esdb_sqlite.py
|
|
325
326
|
tests/test_esdb_status_integrity.py
|
|
326
327
|
tests/test_esdb_status_output.py
|
|
@@ -358,6 +359,7 @@ tests/test_project_metrics.py
|
|
|
358
359
|
tests/test_quality_report.py
|
|
359
360
|
tests/test_rate_limits.py
|
|
360
361
|
tests/test_release_guard.py
|
|
362
|
+
tests/test_release_version_contract.py
|
|
361
363
|
tests/test_releaser.py
|
|
362
364
|
tests/test_repl.py
|
|
363
365
|
tests/test_repl_extended.py
|
|
@@ -365,6 +367,7 @@ tests/test_reporting_commands.py
|
|
|
365
367
|
tests/test_req_248_262.py
|
|
366
368
|
tests/test_req_358_359.py
|
|
367
369
|
tests/test_resume_command.py
|
|
370
|
+
tests/test_rtd_deploy_workflow.py
|
|
368
371
|
tests/test_scaffolder.py
|
|
369
372
|
tests/test_schema_migrations.py
|
|
370
373
|
tests/test_session_events.py
|
|
@@ -382,6 +385,7 @@ tests/test_typing_guardrails.py
|
|
|
382
385
|
tests/test_updater.py
|
|
383
386
|
tests/test_validator.py
|
|
384
387
|
tests/test_vcs.py
|
|
388
|
+
tests/test_vcs_commands.py
|
|
385
389
|
tests/test_warp_parity.py
|
|
386
390
|
tests/test_warp_parity_followup.py
|
|
387
391
|
tests/test_wi_lifecycle.py
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
click>=8.1
|
|
2
|
+
cryptography>=42.0
|
|
2
3
|
jinja2>=3.1
|
|
3
4
|
pyyaml>=6.0
|
|
4
5
|
pydantic>=2.0
|
|
@@ -29,7 +30,6 @@ ruff>=0.4
|
|
|
29
30
|
mypy>=1.10
|
|
30
31
|
pre-commit>=3.0
|
|
31
32
|
types-pyyaml>=6.0
|
|
32
|
-
cryptography>=42.0
|
|
33
33
|
|
|
34
34
|
[docs]
|
|
35
35
|
mkdocs>=1.6
|
|
@@ -37,7 +37,6 @@ mkdocs-material>=9.5
|
|
|
37
37
|
|
|
38
38
|
[esdb]
|
|
39
39
|
chronomemory>=0.2.7
|
|
40
|
-
cryptography>=42.0
|
|
41
40
|
|
|
42
41
|
[gemini]
|
|
43
42
|
google-genai>=1.0
|
|
@@ -50,7 +49,6 @@ sentence-transformers>=2.2
|
|
|
50
49
|
numpy>=1.24
|
|
51
50
|
|
|
52
51
|
[license-verify]
|
|
53
|
-
cryptography>=42.0
|
|
54
52
|
|
|
55
53
|
[mistral]
|
|
56
54
|
openai>=1.0
|
|
@@ -70,6 +70,68 @@ class TestCLIVersion:
|
|
|
70
70
|
assert __version__ in result.output
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
class TestCLIHelp:
|
|
74
|
+
def test_preflight_help_does_not_migrate_or_write_project_files(
|
|
75
|
+
self, tmp_path, monkeypatch
|
|
76
|
+
) -> None:
|
|
77
|
+
"""TEST-475: help must not mutate a project that needs migration."""
|
|
78
|
+
docs = tmp_path / "docs"
|
|
79
|
+
docs.mkdir()
|
|
80
|
+
(docs / "SPECSMITH.yml").write_text(
|
|
81
|
+
"name: temp-specsmith-repro\ntype: cli-python\nspec_version: 0.22.0\n",
|
|
82
|
+
encoding="utf-8",
|
|
83
|
+
)
|
|
84
|
+
(tmp_path / "LEDGER.md").write_text("# Ledger\n", encoding="utf-8")
|
|
85
|
+
before = {
|
|
86
|
+
path.relative_to(tmp_path): path.read_bytes()
|
|
87
|
+
for path in tmp_path.rglob("*")
|
|
88
|
+
if path.is_file()
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
monkeypatch.chdir(tmp_path)
|
|
92
|
+
result = CliRunner().invoke(
|
|
93
|
+
main,
|
|
94
|
+
["preflight", "--help"],
|
|
95
|
+
env={"SPECSMITH_NO_UPDATE_CHECK": "1"},
|
|
96
|
+
catch_exceptions=False,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
assert result.exit_code == 0, result.output
|
|
100
|
+
assert "Usage: " in result.output
|
|
101
|
+
assert "Auto-migrating" not in result.output
|
|
102
|
+
after = {
|
|
103
|
+
path.relative_to(tmp_path): path.read_bytes()
|
|
104
|
+
for path in tmp_path.rglob("*")
|
|
105
|
+
if path.is_file()
|
|
106
|
+
}
|
|
107
|
+
assert after == before
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
class TestCheckpointAnchor:
|
|
111
|
+
def test_checkpoint_anchor_is_ascii_and_fixed_width(self, tmp_path: Path) -> None:
|
|
112
|
+
"""TEST-479: anchor rows must render safely in proportional-font clients."""
|
|
113
|
+
result = CliRunner().invoke(
|
|
114
|
+
main,
|
|
115
|
+
["checkpoint", "--project-dir", str(tmp_path)],
|
|
116
|
+
env={"SPECSMITH_NO_AUTO_UPDATE": "1"},
|
|
117
|
+
catch_exceptions=False,
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
assert result.exit_code == 0, result.output
|
|
121
|
+
lines = result.output.splitlines()
|
|
122
|
+
top = next(index for index, line in enumerate(lines) if line.startswith("+---"))
|
|
123
|
+
bottom = next(
|
|
124
|
+
index for index, line in enumerate(lines[top + 1 :], top + 1) if line.startswith("+---")
|
|
125
|
+
)
|
|
126
|
+
anchor = lines[top : bottom + 1]
|
|
127
|
+
|
|
128
|
+
assert all(line.isascii() for line in anchor)
|
|
129
|
+
assert all(len(line) == len(anchor[0]) for line in anchor)
|
|
130
|
+
assert anchor[0] == anchor[-1]
|
|
131
|
+
assert all(line.startswith("|") and line.endswith("|") for line in anchor[1:-1])
|
|
132
|
+
assert "Health : " in "\n".join(anchor)
|
|
133
|
+
|
|
134
|
+
|
|
73
135
|
class TestCLIInit:
|
|
74
136
|
def test_init_from_config(self, tmp_path: Path) -> None:
|
|
75
137
|
config = {
|