specsmith 0.14.1.dev546__tar.gz → 0.15.0.dev553__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.14.1.dev546/src/specsmith.egg-info → specsmith-0.15.0.dev553}/PKG-INFO +57 -3
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/README.md +56 -2
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/pyproject.toml +2 -1
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/__init__.py +1 -1
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/cli.py +426 -8
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/__init__.py +7 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/reporter.py +33 -8
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/config.py +1 -1
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_logic.py +25 -0
- specsmith-0.15.0.dev553/src/specsmith/wi_store.py +362 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553/src/specsmith.egg-info}/PKG-INFO +57 -3
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/SOURCES.txt +4 -1
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_cli.py +2 -2
- specsmith-0.15.0.dev553/tests/test_compliance_governance.py +1001 -0
- specsmith-0.15.0.dev553/tests/test_wi_lifecycle.py +937 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/LICENSE +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/setup.cfg +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/belief.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/certainty.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/py.typed +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/recovery.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/session.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/epistemic/trace.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/__main__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/architect.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/auditor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/auth.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/block_export.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/channel.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/compressor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/context_window.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/credits.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/differ.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/doctor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/drive.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/editor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/_license.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/esdb/sqlite_store.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/executor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/exporter.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/history_search.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/importer.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/instinct.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/codity.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/languages.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ledger.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/mcp_server.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/m006_session_governance.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/patent.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/paths.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/phase.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/plugins.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/profiles.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/releaser.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/requirements.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/serve.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session_init.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/session_store.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/ai_agents.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/cross_platform.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/data_engineering.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/devops.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/governance.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/platform_engineering.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/software_engineering.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/specsmith_skills.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills/web_backend.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/sync.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/tools.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/trace.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/updater.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/validator.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/vcs_commands.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith/workspace.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_CMD_001.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_run_feedback.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_ai_client.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_auditor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_channel.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_compliance.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_compressor.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_dispatch.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_epistemic.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_esdb_license.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_esdb_sqlite.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_importer.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_integrations.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_integrations_codity.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_intelligence.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_mcp_client.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_mcp_server.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_new_modules.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_nexus.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_permissions.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_rate_limits.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_req_248_262.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_req_358_359.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_scaffolder.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_smoke.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_suggester.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_tools.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_validator.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_vcs.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_warp_parity.py +0 -0
- {specsmith-0.14.1.dev546 → specsmith-0.15.0.dev553}/tests/test_warp_parity_followup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: specsmith
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.0.dev553
|
|
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
|
|
@@ -363,6 +363,14 @@ agent:
|
|
|
363
363
|
|
|
364
364
|
## AI Compliance & Governance
|
|
365
365
|
|
|
366
|
+
> **DISCLAIMER — Best-effort only.** specsmith is designed to *help* teams build
|
|
367
|
+
> auditable, explainable AI systems, but **it does not guarantee compliance** with
|
|
368
|
+
> any law or regulation. Regulations change frequently; final compliance determination
|
|
369
|
+
> is solely the responsibility of the end user. Layer1Labs makes no legal warranty.
|
|
370
|
+
> Found outdated coverage or a missing regulation?
|
|
371
|
+
> [Open a ticket](https://github.com/layer1labs/specsmith/issues) — we actively
|
|
372
|
+
> maintain the regulation database and welcome compliance PRs.
|
|
373
|
+
|
|
366
374
|
specsmith is designed from the ground up for **auditable, explainable, and human-overseen AI**.
|
|
367
375
|
It implements concrete compliance mechanisms mapped to the two major regulatory frameworks
|
|
368
376
|
that govern AI systems in production today.
|
|
@@ -501,8 +509,8 @@ specsmith export --format markdown > compliance-report.md
|
|
|
501
509
|
specsmith export --format json > compliance-report.json
|
|
502
510
|
```
|
|
503
511
|
|
|
504
|
-
This report is suitable
|
|
505
|
-
|
|
512
|
+
This report is suitable as a starting point for audit evidence, but is **not a legal
|
|
513
|
+
certification**. Always verify with qualified counsel before regulatory submission.
|
|
506
514
|
|
|
507
515
|
### Compliance per Session and per Project
|
|
508
516
|
|
|
@@ -594,6 +602,52 @@ specsmith run
|
|
|
594
602
|
|
|
595
603
|
---
|
|
596
604
|
|
|
605
|
+
## Work Item (WI) Lifecycle
|
|
606
|
+
|
|
607
|
+
Every accepted `specsmith preflight` mints a **Work Item** — a unique ID such as
|
|
608
|
+
`WI-3A9F1C02` that tracks user intent through the full governance lifecycle.
|
|
609
|
+
WIs are persisted to `.specsmith/workitems.json` and evolve through defined states:
|
|
610
|
+
|
|
611
|
+
| State | Meaning |
|
|
612
|
+
|---|---|
|
|
613
|
+
| `open` | Minted by preflight; work in progress |
|
|
614
|
+
| `implemented` | `specsmith verify` reached equilibrium (auto-set) |
|
|
615
|
+
| `promoted` | Elevated to a formal REQ-NNN via `specsmith wi promote` |
|
|
616
|
+
| `closed` | Done; maps to an existing requirement |
|
|
617
|
+
| `archived` | Deferred; may be re-opened |
|
|
618
|
+
| `rejected` | Explicitly rejected |
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
# See all open work items
|
|
622
|
+
specsmith wi list --status open
|
|
623
|
+
|
|
624
|
+
# View full details of a WI
|
|
625
|
+
specsmith wi show WI-3A9F1C02
|
|
626
|
+
|
|
627
|
+
# Close a WI (change covered by an existing REQ)
|
|
628
|
+
specsmith wi close WI-3A9F1C02 --reason "covered by REQ-042"
|
|
629
|
+
|
|
630
|
+
# Promote a WI to a new requirement (new behaviour, no existing REQ)
|
|
631
|
+
specsmith wi promote WI-3A9F1C02 \
|
|
632
|
+
--title "System must retry on transient HTTP 5xx failures" \
|
|
633
|
+
--domain governance
|
|
634
|
+
specsmith sync # regenerate REQUIREMENTS.md
|
|
635
|
+
|
|
636
|
+
# Set kind label
|
|
637
|
+
specsmith wi tag WI-3A9F1C02 --kind bug
|
|
638
|
+
|
|
639
|
+
# Import historical WIs from LEDGER.md
|
|
640
|
+
specsmith wi import --from-ledger
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**When to promote vs close:** Promote (`wi promote`) when the change introduces new
|
|
644
|
+
behaviour not covered by any existing REQ and the pattern is expected to recur.
|
|
645
|
+
Close (`wi close`) for bug fixes, refactors, and chores that already have a matching REQ.
|
|
646
|
+
|
|
647
|
+
Full documentation: [`docs/site/wi-lifecycle.md`](docs/site/wi-lifecycle.md)
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
597
651
|
## Nexus
|
|
598
652
|
|
|
599
653
|
The Nexus runtime is specsmith's local-first agentic REPL — a
|
|
@@ -285,6 +285,14 @@ agent:
|
|
|
285
285
|
|
|
286
286
|
## AI Compliance & Governance
|
|
287
287
|
|
|
288
|
+
> **DISCLAIMER — Best-effort only.** specsmith is designed to *help* teams build
|
|
289
|
+
> auditable, explainable AI systems, but **it does not guarantee compliance** with
|
|
290
|
+
> any law or regulation. Regulations change frequently; final compliance determination
|
|
291
|
+
> is solely the responsibility of the end user. Layer1Labs makes no legal warranty.
|
|
292
|
+
> Found outdated coverage or a missing regulation?
|
|
293
|
+
> [Open a ticket](https://github.com/layer1labs/specsmith/issues) — we actively
|
|
294
|
+
> maintain the regulation database and welcome compliance PRs.
|
|
295
|
+
|
|
288
296
|
specsmith is designed from the ground up for **auditable, explainable, and human-overseen AI**.
|
|
289
297
|
It implements concrete compliance mechanisms mapped to the two major regulatory frameworks
|
|
290
298
|
that govern AI systems in production today.
|
|
@@ -423,8 +431,8 @@ specsmith export --format markdown > compliance-report.md
|
|
|
423
431
|
specsmith export --format json > compliance-report.json
|
|
424
432
|
```
|
|
425
433
|
|
|
426
|
-
This report is suitable
|
|
427
|
-
|
|
434
|
+
This report is suitable as a starting point for audit evidence, but is **not a legal
|
|
435
|
+
certification**. Always verify with qualified counsel before regulatory submission.
|
|
428
436
|
|
|
429
437
|
### Compliance per Session and per Project
|
|
430
438
|
|
|
@@ -516,6 +524,52 @@ specsmith run
|
|
|
516
524
|
|
|
517
525
|
---
|
|
518
526
|
|
|
527
|
+
## Work Item (WI) Lifecycle
|
|
528
|
+
|
|
529
|
+
Every accepted `specsmith preflight` mints a **Work Item** — a unique ID such as
|
|
530
|
+
`WI-3A9F1C02` that tracks user intent through the full governance lifecycle.
|
|
531
|
+
WIs are persisted to `.specsmith/workitems.json` and evolve through defined states:
|
|
532
|
+
|
|
533
|
+
| State | Meaning |
|
|
534
|
+
|---|---|
|
|
535
|
+
| `open` | Minted by preflight; work in progress |
|
|
536
|
+
| `implemented` | `specsmith verify` reached equilibrium (auto-set) |
|
|
537
|
+
| `promoted` | Elevated to a formal REQ-NNN via `specsmith wi promote` |
|
|
538
|
+
| `closed` | Done; maps to an existing requirement |
|
|
539
|
+
| `archived` | Deferred; may be re-opened |
|
|
540
|
+
| `rejected` | Explicitly rejected |
|
|
541
|
+
|
|
542
|
+
```bash
|
|
543
|
+
# See all open work items
|
|
544
|
+
specsmith wi list --status open
|
|
545
|
+
|
|
546
|
+
# View full details of a WI
|
|
547
|
+
specsmith wi show WI-3A9F1C02
|
|
548
|
+
|
|
549
|
+
# Close a WI (change covered by an existing REQ)
|
|
550
|
+
specsmith wi close WI-3A9F1C02 --reason "covered by REQ-042"
|
|
551
|
+
|
|
552
|
+
# Promote a WI to a new requirement (new behaviour, no existing REQ)
|
|
553
|
+
specsmith wi promote WI-3A9F1C02 \
|
|
554
|
+
--title "System must retry on transient HTTP 5xx failures" \
|
|
555
|
+
--domain governance
|
|
556
|
+
specsmith sync # regenerate REQUIREMENTS.md
|
|
557
|
+
|
|
558
|
+
# Set kind label
|
|
559
|
+
specsmith wi tag WI-3A9F1C02 --kind bug
|
|
560
|
+
|
|
561
|
+
# Import historical WIs from LEDGER.md
|
|
562
|
+
specsmith wi import --from-ledger
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**When to promote vs close:** Promote (`wi promote`) when the change introduces new
|
|
566
|
+
behaviour not covered by any existing REQ and the pattern is expected to recur.
|
|
567
|
+
Close (`wi close`) for bug fixes, refactors, and chores that already have a matching REQ.
|
|
568
|
+
|
|
569
|
+
Full documentation: [`docs/site/wi-lifecycle.md`](docs/site/wi-lifecycle.md)
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
519
573
|
## Nexus
|
|
520
574
|
|
|
521
575
|
The Nexus runtime is specsmith's local-first agentic REPL — a
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.15.0.dev553"
|
|
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"
|
|
@@ -248,3 +248,4 @@ ignore_errors = true
|
|
|
248
248
|
|
|
249
249
|
[tool.pytest.ini_options]
|
|
250
250
|
testpaths = ["tests"]
|
|
251
|
+
pythonpath = ["src"]
|
|
@@ -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.
|
|
11
|
+
__version__ = "0.15.0" # fallback: keep in sync with pyproject.toml
|
|
@@ -2430,11 +2430,12 @@ def verify_release() -> None:
|
|
|
2430
2430
|
|
|
2431
2431
|
# GitHub release
|
|
2432
2432
|
try:
|
|
2433
|
-
result = subprocess.run(
|
|
2433
|
+
result = subprocess.run( # noqa: S603, S607 — argv is a fixed, trusted CLI invocation
|
|
2434
2434
|
["gh", "release", "view", f"v{__version__}", "--json", "tagName"],
|
|
2435
2435
|
capture_output=True,
|
|
2436
2436
|
text=True,
|
|
2437
2437
|
timeout=10,
|
|
2438
|
+
check=False,
|
|
2438
2439
|
)
|
|
2439
2440
|
if result.returncode == 0:
|
|
2440
2441
|
console.print(f" [green]\u2713[/green] GitHub Release: v{__version__}")
|
|
@@ -3183,7 +3184,10 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
3183
3184
|
wal = root / ".chronomemory" / "events.wal"
|
|
3184
3185
|
if wal.exists():
|
|
3185
3186
|
with ChronoStore(root) as store:
|
|
3186
|
-
|
|
3187
|
+
# Issue #202: chain_valid() may return non-bool (e.g. None or 0)
|
|
3188
|
+
# in some chronomemory versions for an intact chain. Treat any
|
|
3189
|
+
# value that is not the literal False as valid.
|
|
3190
|
+
esdb_ok = store.chain_valid() is not False
|
|
3187
3191
|
esdb_records = store.record_count()
|
|
3188
3192
|
except Exception: # noqa: BLE001
|
|
3189
3193
|
pass
|
|
@@ -3260,8 +3264,10 @@ def checkpoint_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
3260
3264
|
r2_plain = f" Project : {project_name}"
|
|
3261
3265
|
console.print(_arow(f" Project : [bold]{project_name}[/bold]", r2_plain))
|
|
3262
3266
|
|
|
3263
|
-
|
|
3264
|
-
|
|
3267
|
+
# Emoji omitted from the anchor box: full-width glyphs vary by terminal
|
|
3268
|
+
# and break the fixed-width box alignment unpredictably (GH #align).
|
|
3269
|
+
r3_plain = f" Phase : {phase_label} ({phase_pct}%)"
|
|
3270
|
+
console.print(_arow(r3_plain, r3_plain))
|
|
3265
3271
|
|
|
3266
3272
|
r4_plain = (
|
|
3267
3273
|
f" Health : {health_icon} clean"
|
|
@@ -7278,8 +7284,12 @@ def tools_scan_cmd(project_dir: str, as_json: bool, fpga: bool) -> None:
|
|
|
7278
7284
|
version = ""
|
|
7279
7285
|
if path_found:
|
|
7280
7286
|
try:
|
|
7281
|
-
r = subprocess.run(
|
|
7282
|
-
[exe, "--version"],
|
|
7287
|
+
r = subprocess.run( # noqa: S603, S607 — exe comes from a trusted hardcoded map
|
|
7288
|
+
[exe, "--version"],
|
|
7289
|
+
capture_output=True,
|
|
7290
|
+
text=True,
|
|
7291
|
+
timeout=5,
|
|
7292
|
+
check=False,
|
|
7283
7293
|
)
|
|
7284
7294
|
ver_out = (r.stdout + r.stderr).strip().splitlines()
|
|
7285
7295
|
if ver_out:
|
|
@@ -8117,6 +8127,395 @@ def notebook_replay(slug: str, project_dir: str) -> None:
|
|
|
8117
8127
|
main.add_command(notebook_group)
|
|
8118
8128
|
|
|
8119
8129
|
|
|
8130
|
+
# ---------------------------------------------------------------------------
|
|
8131
|
+
# specsmith wi — Work Item lifecycle management
|
|
8132
|
+
# ---------------------------------------------------------------------------
|
|
8133
|
+
|
|
8134
|
+
|
|
8135
|
+
@main.group(name="wi")
|
|
8136
|
+
def wi_group() -> None:
|
|
8137
|
+
"""Manage the lifecycle of Work Items (WIs).
|
|
8138
|
+
|
|
8139
|
+
Work Items are governance breadcrumbs minted by ``specsmith preflight``.
|
|
8140
|
+
Every accepted preflight produces a WI such as ``WI-3A9F1C02``. WIs
|
|
8141
|
+
evolve through the following states:
|
|
8142
|
+
|
|
8143
|
+
\b
|
|
8144
|
+
open created by preflight; work in progress
|
|
8145
|
+
implemented verify reached equilibrium (auto-set by specsmith verify)
|
|
8146
|
+
promoted WI elevated to a formal REQ-NNN (new requirement)
|
|
8147
|
+
closed done; maps to an existing REQ; no new requirement needed
|
|
8148
|
+
archived abandoned or deferred; may be re-opened
|
|
8149
|
+
rejected explicitly rejected
|
|
8150
|
+
|
|
8151
|
+
State machine:
|
|
8152
|
+
|
|
8153
|
+
\b
|
|
8154
|
+
open → implemented → promoted
|
|
8155
|
+
→ closed
|
|
8156
|
+
→ archived
|
|
8157
|
+
→ archived
|
|
8158
|
+
→ rejected
|
|
8159
|
+
archived → open (un-defer)
|
|
8160
|
+
|
|
8161
|
+
When to promote a WI to a REQ:
|
|
8162
|
+
|
|
8163
|
+
\b
|
|
8164
|
+
- The change introduced new behavior not covered by any existing requirement.
|
|
8165
|
+
- The pattern is expected to recur and needs permanent test coverage.
|
|
8166
|
+
- The WI's ``requirement_ids`` list was empty at preflight time.
|
|
8167
|
+
|
|
8168
|
+
When to close (not promote):
|
|
8169
|
+
|
|
8170
|
+
\b
|
|
8171
|
+
- Bug fix against an existing REQ.
|
|
8172
|
+
- Refactoring or performance work within existing requirements.
|
|
8173
|
+
- Docs / chore work with no new functionality.
|
|
8174
|
+
"""
|
|
8175
|
+
|
|
8176
|
+
|
|
8177
|
+
@wi_group.command(name="list")
|
|
8178
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8179
|
+
@click.option(
|
|
8180
|
+
"--status",
|
|
8181
|
+
"filter_status",
|
|
8182
|
+
default="",
|
|
8183
|
+
help="Filter by status: open|implemented|promoted|closed|archived|rejected.",
|
|
8184
|
+
)
|
|
8185
|
+
@click.option("--json", "as_json", is_flag=True, default=False)
|
|
8186
|
+
def wi_list_cmd(project_dir: str, filter_status: str, as_json: bool) -> None:
|
|
8187
|
+
"""List work items, optionally filtered by status."""
|
|
8188
|
+
import json as _json
|
|
8189
|
+
|
|
8190
|
+
from specsmith.wi_store import WorkItemStore
|
|
8191
|
+
|
|
8192
|
+
root = Path(project_dir).resolve()
|
|
8193
|
+
store = WorkItemStore(root)
|
|
8194
|
+
items = store.list_by_status(filter_status or None)
|
|
8195
|
+
|
|
8196
|
+
if as_json:
|
|
8197
|
+
click.echo(_json.dumps([i.to_dict() for i in items], indent=2))
|
|
8198
|
+
return
|
|
8199
|
+
|
|
8200
|
+
if not items:
|
|
8201
|
+
console.print("[dim]No work items found.[/dim]")
|
|
8202
|
+
return
|
|
8203
|
+
|
|
8204
|
+
_STATUS_COLOR = {
|
|
8205
|
+
"open": "cyan",
|
|
8206
|
+
"implemented": "green",
|
|
8207
|
+
"promoted": "bold green",
|
|
8208
|
+
"closed": "dim",
|
|
8209
|
+
"archived": "yellow",
|
|
8210
|
+
"rejected": "red",
|
|
8211
|
+
}
|
|
8212
|
+
console.print(f"[bold]Work Items[/bold] ({root.name})\n")
|
|
8213
|
+
for item in items:
|
|
8214
|
+
color = _STATUS_COLOR.get(item.status, "white")
|
|
8215
|
+
req_tag = f" [{', '.join(item.requirement_ids)}]" if item.requirement_ids else ""
|
|
8216
|
+
promoted_tag = f" → {item.promoted_to_req}" if item.promoted_to_req else ""
|
|
8217
|
+
console.print(
|
|
8218
|
+
f" [{color}]{item.id}[/{color}] "
|
|
8219
|
+
f"[{color}]{item.status:12s}[/{color}] "
|
|
8220
|
+
f"[dim]{item.kind:9s}[/dim] "
|
|
8221
|
+
f"{item.intent[:60]}"
|
|
8222
|
+
f"[dim]{req_tag}{promoted_tag}[/dim]"
|
|
8223
|
+
)
|
|
8224
|
+
|
|
8225
|
+
|
|
8226
|
+
@wi_group.command(name="show")
|
|
8227
|
+
@click.argument("wi_id")
|
|
8228
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8229
|
+
@click.option("--json", "as_json", is_flag=True, default=False)
|
|
8230
|
+
def wi_show_cmd(wi_id: str, project_dir: str, as_json: bool) -> None:
|
|
8231
|
+
"""Show full details for a work item."""
|
|
8232
|
+
import json as _json
|
|
8233
|
+
|
|
8234
|
+
from specsmith.wi_store import WorkItemStore
|
|
8235
|
+
|
|
8236
|
+
root = Path(project_dir).resolve()
|
|
8237
|
+
store = WorkItemStore(root)
|
|
8238
|
+
item = store.get(wi_id.upper())
|
|
8239
|
+
if item is None:
|
|
8240
|
+
console.print(f"[red]Work item {wi_id!r} not found.[/red]")
|
|
8241
|
+
raise SystemExit(1)
|
|
8242
|
+
|
|
8243
|
+
if as_json:
|
|
8244
|
+
click.echo(_json.dumps(item.to_dict(), indent=2))
|
|
8245
|
+
return
|
|
8246
|
+
|
|
8247
|
+
console.print(f"\n[bold cyan]{item.id}[/bold cyan]")
|
|
8248
|
+
console.print(f" Status : {item.status}")
|
|
8249
|
+
console.print(f" Kind : {item.kind}")
|
|
8250
|
+
console.print(f" Intent : {item.intent}")
|
|
8251
|
+
console.print(f" Created : {item.created_at}")
|
|
8252
|
+
console.print(f" Updated : {item.updated_at}")
|
|
8253
|
+
console.print(f" Verified : {item.verified}")
|
|
8254
|
+
console.print(f" Req IDs : {', '.join(item.requirement_ids) or '(none)'}")
|
|
8255
|
+
console.print(f" Test IDs : {', '.join(item.test_case_ids) or '(none)'}")
|
|
8256
|
+
if item.promoted_to_req:
|
|
8257
|
+
console.print(f" Promoted : [green]{item.promoted_to_req}[/green]")
|
|
8258
|
+
if item.closed_at:
|
|
8259
|
+
console.print(f" Closed : {item.closed_at}")
|
|
8260
|
+
if item.closed_reason:
|
|
8261
|
+
console.print(f" Reason : {item.closed_reason}")
|
|
8262
|
+
|
|
8263
|
+
|
|
8264
|
+
@wi_group.command(name="close")
|
|
8265
|
+
@click.argument("wi_id")
|
|
8266
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8267
|
+
@click.option("--reason", default="", help="Reason for closing (optional).")
|
|
8268
|
+
def wi_close_cmd(wi_id: str, project_dir: str, reason: str) -> None:
|
|
8269
|
+
"""Close a work item (done; maps to an existing requirement)."""
|
|
8270
|
+
from specsmith.wi_store import WorkItemError, WorkItemStore
|
|
8271
|
+
|
|
8272
|
+
root = Path(project_dir).resolve()
|
|
8273
|
+
store = WorkItemStore(root)
|
|
8274
|
+
try:
|
|
8275
|
+
item = store.set_status(wi_id.upper(), "closed", reason=reason)
|
|
8276
|
+
except WorkItemError as exc:
|
|
8277
|
+
console.print(f"[red]{exc}[/red]")
|
|
8278
|
+
raise SystemExit(1) from exc
|
|
8279
|
+
console.print(f"[green]\u2713[/green] {item.id} → closed")
|
|
8280
|
+
try:
|
|
8281
|
+
from specsmith.ledger import add_entry
|
|
8282
|
+
|
|
8283
|
+
add_entry(
|
|
8284
|
+
root,
|
|
8285
|
+
description=f"wi_close {item.id}: {reason or 'done'}",
|
|
8286
|
+
entry_type="wi_close",
|
|
8287
|
+
author="specsmith",
|
|
8288
|
+
)
|
|
8289
|
+
except Exception: # noqa: BLE001
|
|
8290
|
+
pass
|
|
8291
|
+
|
|
8292
|
+
|
|
8293
|
+
@wi_group.command(name="archive")
|
|
8294
|
+
@click.argument("wi_id")
|
|
8295
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8296
|
+
@click.option("--reason", default="", help="Reason for archiving (optional).")
|
|
8297
|
+
def wi_archive_cmd(wi_id: str, project_dir: str, reason: str) -> None:
|
|
8298
|
+
"""Archive a work item (abandoned or deferred).
|
|
8299
|
+
|
|
8300
|
+
Archived WIs may be re-opened with ``specsmith wi tag --kind <kind>`` or
|
|
8301
|
+
by using ``specsmith preflight`` for the same intent again.
|
|
8302
|
+
"""
|
|
8303
|
+
from specsmith.wi_store import WorkItemError, WorkItemStore
|
|
8304
|
+
|
|
8305
|
+
root = Path(project_dir).resolve()
|
|
8306
|
+
store = WorkItemStore(root)
|
|
8307
|
+
try:
|
|
8308
|
+
item = store.set_status(wi_id.upper(), "archived", reason=reason)
|
|
8309
|
+
except WorkItemError as exc:
|
|
8310
|
+
console.print(f"[red]{exc}[/red]")
|
|
8311
|
+
raise SystemExit(1) from exc
|
|
8312
|
+
console.print(f"[yellow]\u2714[/yellow] {item.id} → archived")
|
|
8313
|
+
try:
|
|
8314
|
+
from specsmith.ledger import add_entry
|
|
8315
|
+
|
|
8316
|
+
add_entry(
|
|
8317
|
+
root,
|
|
8318
|
+
description=f"wi_archive {item.id}: {reason or 'deferred'}",
|
|
8319
|
+
entry_type="wi_archive",
|
|
8320
|
+
author="specsmith",
|
|
8321
|
+
)
|
|
8322
|
+
except Exception: # noqa: BLE001
|
|
8323
|
+
pass
|
|
8324
|
+
|
|
8325
|
+
|
|
8326
|
+
@wi_group.command(name="promote")
|
|
8327
|
+
@click.argument("wi_id")
|
|
8328
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8329
|
+
@click.option("--title", default="", help="REQ title (defaults to WI intent).")
|
|
8330
|
+
@click.option(
|
|
8331
|
+
"--domain",
|
|
8332
|
+
default="overflow",
|
|
8333
|
+
help="Requirements domain YAML to append to (default: overflow).",
|
|
8334
|
+
)
|
|
8335
|
+
@click.option("--json", "as_json", is_flag=True, default=False)
|
|
8336
|
+
def wi_promote_cmd(wi_id: str, project_dir: str, title: str, domain: str, as_json: bool) -> None:
|
|
8337
|
+
"""Promote a work item to a formal requirement (REQ-NNN).
|
|
8338
|
+
|
|
8339
|
+
Creates a new requirement entry in ``docs/requirements/<domain>.yml``,
|
|
8340
|
+
writes the REQ-NNN back to the WI record, and runs ``specsmith sync``
|
|
8341
|
+
to regenerate REQUIREMENTS.md.
|
|
8342
|
+
|
|
8343
|
+
Example:
|
|
8344
|
+
|
|
8345
|
+
\b
|
|
8346
|
+
# WI introduced new retry logic not covered by any existing REQ
|
|
8347
|
+
specsmith wi promote WI-3A9F1C02 \\
|
|
8348
|
+
--title "Exporter must retry on transient HTTP failures" \\
|
|
8349
|
+
--domain overflow
|
|
8350
|
+
"""
|
|
8351
|
+
import json as _json
|
|
8352
|
+
|
|
8353
|
+
from specsmith.wi_store import WorkItemError, WorkItemStore
|
|
8354
|
+
|
|
8355
|
+
root = Path(project_dir).resolve()
|
|
8356
|
+
store = WorkItemStore(root)
|
|
8357
|
+
|
|
8358
|
+
item = store.get(wi_id.upper())
|
|
8359
|
+
if item is None:
|
|
8360
|
+
console.print(f"[red]Work item {wi_id!r} not found.[/red]")
|
|
8361
|
+
raise SystemExit(1)
|
|
8362
|
+
if item.is_terminal() and item.status != "implemented":
|
|
8363
|
+
console.print(
|
|
8364
|
+
f"[red]Cannot promote {wi_id}: already in terminal state {item.status!r}.[/red]"
|
|
8365
|
+
)
|
|
8366
|
+
raise SystemExit(1)
|
|
8367
|
+
|
|
8368
|
+
# ── Find the domain YAML file ──────────────────────────────────────────
|
|
8369
|
+
req_dir = root / "docs" / "requirements"
|
|
8370
|
+
yaml_path = req_dir / f"{domain}.yml"
|
|
8371
|
+
if not yaml_path.is_file():
|
|
8372
|
+
# Fall back to overflow.yml; create if missing
|
|
8373
|
+
yaml_path = req_dir / "overflow.yml"
|
|
8374
|
+
|
|
8375
|
+
# ── Determine next REQ-NNN ────────────────────────────────────────────
|
|
8376
|
+
import re
|
|
8377
|
+
|
|
8378
|
+
import yaml # type: ignore[import-untyped]
|
|
8379
|
+
|
|
8380
|
+
all_req_ids: list[int] = []
|
|
8381
|
+
for yf in req_dir.glob("*.yml"):
|
|
8382
|
+
try:
|
|
8383
|
+
entries = yaml.safe_load(yf.read_text(encoding="utf-8")) or []
|
|
8384
|
+
for entry in entries:
|
|
8385
|
+
if isinstance(entry, dict):
|
|
8386
|
+
m = re.match(r"REQ-(\d+)", str(entry.get("id", "")))
|
|
8387
|
+
if m:
|
|
8388
|
+
all_req_ids.append(int(m.group(1)))
|
|
8389
|
+
except Exception: # noqa: BLE001
|
|
8390
|
+
pass
|
|
8391
|
+
next_num = (max(all_req_ids) + 1) if all_req_ids else 400
|
|
8392
|
+
new_req_id = f"REQ-{next_num}"
|
|
8393
|
+
|
|
8394
|
+
# ── Build REQ entry ───────────────────────────────────────────────────
|
|
8395
|
+
req_title = title.strip() or item.intent[:120] or f"Work item {item.id}"
|
|
8396
|
+
|
|
8397
|
+
# ── Append to domain YAML ─────────────────────────────────────────────
|
|
8398
|
+
yaml_path.parent.mkdir(parents=True, exist_ok=True)
|
|
8399
|
+
existing_text = yaml_path.read_text(encoding="utf-8") if yaml_path.is_file() else ""
|
|
8400
|
+
entry_yaml = (
|
|
8401
|
+
f"- id: {new_req_id}\n"
|
|
8402
|
+
f" title: {req_title}\n"
|
|
8403
|
+
f" description: >-\n"
|
|
8404
|
+
f" Promoted from {item.id}. {item.intent}\n"
|
|
8405
|
+
f" source: {item.id}\n"
|
|
8406
|
+
f" status: planned\n"
|
|
8407
|
+
)
|
|
8408
|
+
yaml_path.write_text(
|
|
8409
|
+
(existing_text.rstrip() + "\n" + entry_yaml) if existing_text.strip() else entry_yaml,
|
|
8410
|
+
encoding="utf-8",
|
|
8411
|
+
)
|
|
8412
|
+
|
|
8413
|
+
# ── Update WI record ──────────────────────────────────────────────────
|
|
8414
|
+
try:
|
|
8415
|
+
store.promote_to_req(item.id, new_req_id)
|
|
8416
|
+
except WorkItemError as exc:
|
|
8417
|
+
console.print(f"[red]{exc}[/red]")
|
|
8418
|
+
raise SystemExit(1) from exc
|
|
8419
|
+
|
|
8420
|
+
# ── Ledger entry ──────────────────────────────────────────────────────
|
|
8421
|
+
try:
|
|
8422
|
+
from specsmith.ledger import add_entry
|
|
8423
|
+
|
|
8424
|
+
add_entry(
|
|
8425
|
+
root,
|
|
8426
|
+
description=f"wi_promote {item.id} → {new_req_id}: {req_title}",
|
|
8427
|
+
entry_type="wi_promote",
|
|
8428
|
+
author="specsmith",
|
|
8429
|
+
)
|
|
8430
|
+
except Exception: # noqa: BLE001
|
|
8431
|
+
pass
|
|
8432
|
+
|
|
8433
|
+
if as_json:
|
|
8434
|
+
click.echo(
|
|
8435
|
+
_json.dumps(
|
|
8436
|
+
{
|
|
8437
|
+
"wi_id": item.id,
|
|
8438
|
+
"promoted_to": new_req_id,
|
|
8439
|
+
"req_file": str(yaml_path.relative_to(root)),
|
|
8440
|
+
},
|
|
8441
|
+
indent=2,
|
|
8442
|
+
)
|
|
8443
|
+
)
|
|
8444
|
+
return
|
|
8445
|
+
|
|
8446
|
+
console.print(
|
|
8447
|
+
f"[green]\u2713[/green] {item.id} → [bold green]{new_req_id}[/bold green]\n"
|
|
8448
|
+
f" Title : {req_title}\n"
|
|
8449
|
+
f" File : {yaml_path.relative_to(root)}\n"
|
|
8450
|
+
f" Next : run [bold]specsmith sync[/bold] to regenerate REQUIREMENTS.md"
|
|
8451
|
+
)
|
|
8452
|
+
|
|
8453
|
+
|
|
8454
|
+
@wi_group.command(name="tag")
|
|
8455
|
+
@click.argument("wi_id")
|
|
8456
|
+
@click.option(
|
|
8457
|
+
"--kind",
|
|
8458
|
+
required=True,
|
|
8459
|
+
type=click.Choice(["feature", "bug", "chore", "spike", "refactor", "docs"]),
|
|
8460
|
+
help="WI kind / classification label.",
|
|
8461
|
+
)
|
|
8462
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8463
|
+
def wi_tag_cmd(wi_id: str, kind: str, project_dir: str) -> None:
|
|
8464
|
+
"""Set the kind / classification label on a work item."""
|
|
8465
|
+
from specsmith.wi_store import WorkItemError, WorkItemStore
|
|
8466
|
+
|
|
8467
|
+
root = Path(project_dir).resolve()
|
|
8468
|
+
store = WorkItemStore(root)
|
|
8469
|
+
try:
|
|
8470
|
+
item = store.tag(wi_id.upper(), kind)
|
|
8471
|
+
except WorkItemError as exc:
|
|
8472
|
+
console.print(f"[red]{exc}[/red]")
|
|
8473
|
+
raise SystemExit(1) from exc
|
|
8474
|
+
console.print(f"[green]\u2713[/green] {item.id} → kind={item.kind}")
|
|
8475
|
+
|
|
8476
|
+
|
|
8477
|
+
@wi_group.command(name="import")
|
|
8478
|
+
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
8479
|
+
@click.option(
|
|
8480
|
+
"--from-ledger",
|
|
8481
|
+
"from_ledger",
|
|
8482
|
+
is_flag=True,
|
|
8483
|
+
default=True,
|
|
8484
|
+
help="Import WIs from LEDGER.md work_proposal entries (default: on).",
|
|
8485
|
+
)
|
|
8486
|
+
def wi_import_cmd(project_dir: str, from_ledger: bool) -> None:
|
|
8487
|
+
"""Import work items from LEDGER.md into .specsmith/workitems.json.
|
|
8488
|
+
|
|
8489
|
+
Useful for projects that already have WIs in their ledger but haven't
|
|
8490
|
+
yet run the ``wi`` command group. Existing WIs are never overwritten.
|
|
8491
|
+
"""
|
|
8492
|
+
from specsmith.wi_store import WorkItemStore
|
|
8493
|
+
|
|
8494
|
+
root = Path(project_dir).resolve()
|
|
8495
|
+
store = WorkItemStore(root)
|
|
8496
|
+
imported = 0
|
|
8497
|
+
if from_ledger:
|
|
8498
|
+
for cand in ["docs/LEDGER.md", "LEDGER.md"]:
|
|
8499
|
+
lp = root / cand
|
|
8500
|
+
if lp.is_file():
|
|
8501
|
+
imported += store.import_from_ledger(lp)
|
|
8502
|
+
break
|
|
8503
|
+
if imported:
|
|
8504
|
+
console.print(f"[green]\u2713[/green] Imported {imported} work item(s) from LEDGER.md")
|
|
8505
|
+
else:
|
|
8506
|
+
console.print("[dim]No new work items found to import.[/dim]")
|
|
8507
|
+
|
|
8508
|
+
|
|
8509
|
+
def _now_ts() -> str:
|
|
8510
|
+
"""Return current UTC timestamp as ISO-8601 string."""
|
|
8511
|
+
import time
|
|
8512
|
+
|
|
8513
|
+
return time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
|
8514
|
+
|
|
8515
|
+
|
|
8516
|
+
main.add_command(wi_group)
|
|
8517
|
+
|
|
8518
|
+
|
|
8120
8519
|
# ---------------------------------------------------------------------------
|
|
8121
8520
|
# Workflow — parameterised command snippets (Warp-style Workflows)
|
|
8122
8521
|
# ---------------------------------------------------------------------------
|
|
@@ -10044,7 +10443,9 @@ def esdb_status_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
10044
10443
|
try:
|
|
10045
10444
|
with store as s: # type: ignore[attr-defined]
|
|
10046
10445
|
record_count = s.record_count()
|
|
10047
|
-
|
|
10446
|
+
# Issue #202: chain_valid() may return non-bool in some chronomemory
|
|
10447
|
+
# versions for an intact chain. Only treat literal False as invalid.
|
|
10448
|
+
chain_ok = s.chain_valid() is not False
|
|
10048
10449
|
if ESDB_BACKEND == "sqlite":
|
|
10049
10450
|
sqlite_db = root / ".specsmith" / "esdb.sqlite3"
|
|
10050
10451
|
backend_label = f"SQLite (free, MIT) — {sqlite_db}"
|
|
@@ -11477,6 +11878,13 @@ main.add_command(context_group)
|
|
|
11477
11878
|
def compliance_group() -> None:
|
|
11478
11879
|
"""EU and North American AI regulation compliance checking and reporting.
|
|
11479
11880
|
|
|
11881
|
+
DISCLAIMER: specsmith compliance checks are provided on a best-effort basis.
|
|
11882
|
+
Results are NOT a guarantee of legal compliance. Laws and regulations change
|
|
11883
|
+
frequently; the user is solely responsible for determining and maintaining
|
|
11884
|
+
actual compliance. Layer1Labs makes no warranty of fitness for regulatory
|
|
11885
|
+
submission. File tickets for outdated or missing regulation coverage at
|
|
11886
|
+
https://github.com/layer1labs/specsmith/issues
|
|
11887
|
+
|
|
11480
11888
|
Supported regulations (May 2026):\n
|
|
11481
11889
|
eu-ai-act EU AI Act 2024/1689\n
|
|
11482
11890
|
nist-rmf NIST AI RMF 1.0 + AI 600-1 GenAI Profile\n
|
|
@@ -11538,10 +11946,20 @@ def compliance_check_cmd(project_dir: str, regulation: str, as_json: bool) -> No
|
|
|
11538
11946
|
output = {
|
|
11539
11947
|
"results": [r.to_dict() for r in results],
|
|
11540
11948
|
"checked": len(results),
|
|
11949
|
+
"disclaimer": (
|
|
11950
|
+
"specsmith compliance checks are best-effort only and do NOT constitute "
|
|
11951
|
+
"legal advice or guarantee of compliance. Verify with qualified counsel."
|
|
11952
|
+
),
|
|
11541
11953
|
}
|
|
11542
11954
|
click.echo(_json.dumps(output, indent=2))
|
|
11543
11955
|
return
|
|
11544
11956
|
|
|
11957
|
+
console.print(
|
|
11958
|
+
"[dim]\u26a0 DISCLAIMER: Results are best-effort only. specsmith does not guarantee "
|
|
11959
|
+
"compliance. Laws change \u2014 verify with qualified counsel. "
|
|
11960
|
+
"File issues at https://github.com/layer1labs/specsmith/issues[/dim]\n"
|
|
11961
|
+
)
|
|
11962
|
+
|
|
11545
11963
|
_STATUS_ICON = {
|
|
11546
11964
|
"compliant": "[green]\u2714[/green]",
|
|
11547
11965
|
"partial": "[yellow]\u26a0[/yellow]",
|
|
@@ -11644,7 +12062,7 @@ def compliance_audit_cmd(project_dir: str, as_json: bool) -> None:
|
|
|
11644
12062
|
written = checker.store_results_to_esdb(results)
|
|
11645
12063
|
|
|
11646
12064
|
reporter = ComplianceReporter(results)
|
|
11647
|
-
summary = reporter.
|
|
12065
|
+
summary = reporter.summary_dict() # public API — use summary_dict, not _summary_dict
|
|
11648
12066
|
summary["esdb_records_written"] = written
|
|
11649
12067
|
|
|
11650
12068
|
if as_json:
|