specsmith 0.11.3.dev428__tar.gz → 0.11.3.dev432__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.11.3.dev428/src/specsmith.egg-info → specsmith-0.11.3.dev432}/PKG-INFO +1 -1
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/pyproject.toml +3 -1
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/cli.py +29 -6
- specsmith-0.11.3.dev432/src/specsmith/skills/cross_platform.py +570 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/devops.py +170 -0
- specsmith-0.11.3.dev432/src/specsmith/skills/governance.py +418 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs_commands.py +35 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432/src/specsmith.egg-info}/PKG-INFO +1 -1
- specsmith-0.11.3.dev428/src/specsmith/skills/cross_platform.py +0 -291
- specsmith-0.11.3.dev428/src/specsmith/skills/governance.py +0 -168
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/LICENSE +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/README.md +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/setup.cfg +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/belief.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/certainty.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/failure_graph.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/py.typed +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/recovery.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/session.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/stress_tester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/epistemic/trace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/__main__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/broker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/chat_runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/cleanup.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/context_seed.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/core.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/_status.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/dag.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/dispatcher.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/events.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/dispatch/result.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/endpoints.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/events.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/execution_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/fallback.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/hf_leaderboard.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/hf_sync.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/indexer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/llm_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/mcp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/memory.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/model_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/model_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/orchestrator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/permissions.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/provider_registry.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/repl.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/router.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/rules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/safety.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/spawner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/suggester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/teams.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/verifier.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/agent/voice.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/architect.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/auditor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/auth.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/block_export.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/channel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/ci_manager.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/commands/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/commands/intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/_compat.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/checker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/evidence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/regulations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compliance/reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/compressor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/config.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/console_utils.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/context_orchestrator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/context_window.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/credit_analyzer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/credits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/citations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/fpd.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/odp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/patentsview.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/pfw.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/ppubs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/datasources/ptab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/differ.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/doctor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/drive.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/editor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/belief.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/certainty.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/failure_graph.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/recovery.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/epistemic/stress_tester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/esdb/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/esdb/bridge.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/eval/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/eval/builtins.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/eval/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/executor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/exporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/governance_logic.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/governance_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/governance_yaml.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/app.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/main_window.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/session_tab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/theme.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/chat_view.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/input_bar.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/provider_bar.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/token_meter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/tool_panel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/widgets/update_checker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/gui/worker.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/history_search.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/importer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/instinct.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/agent_skill.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/aider.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/claude_code.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/copilot.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/cursor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/gemini.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/integrations/windsurf.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/issue_reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/languages.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/ledger.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/mcp_generator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/m001_governance_yaml.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/m002_agents_slim.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/m003_compliance_init.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/m004_ledger_esdb.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/m005_agent_run_tool.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/migrations/runner.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/ollama_cmds.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/patent.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/paths.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/phase.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/plugins.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/rate_limits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/releaser.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/requirements.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/requirements_parser.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/retrieval.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/safe_write.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/scaffolder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/serve.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/session.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/session_init.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/session_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/cloud.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/corporate.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/docs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/embedded.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/hardware.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/mobile.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/productivity.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills/ssh.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/skills_builder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/sync.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/agents.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/bug_report.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/code_of_conduct.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/contributing.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/feature_request.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/license-Apache-2.0.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/license-MIT.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/pull_request_template.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/community/security.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/docs/architecture.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/docs/mkdocs.yml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/docs/readthedocs.yaml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/docs/requirements.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/docs/test-spec.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/editorconfig.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/gitattributes.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/gitignore.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/go/go.mod.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/go/main.go.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/belief-registry.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/context-budget.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/drift-metrics.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/epistemic-axioms.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/failure-modes.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/lifecycle.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/roles.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/rules.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/session-protocol.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/uncertainty-map.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/governance/verification.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/js/package.json.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/ledger.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/python/cli.py.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/python/init.py.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/python/pyproject.toml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/readme.md.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/rust/Cargo.toml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/rust/main.rs.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/exec.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/exec.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/run.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/run.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/setup.cmd.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/scripts/setup.sh.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/templates/workflows/release.yml.j2 +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/tool_installer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/toolrules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/trace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/updater.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/upgrader.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/validator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs/__init__.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs/base.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs/bitbucket.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs/github.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/vcs/gitlab.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/wireframes.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith/workspace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith.egg-info/SOURCES.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith.egg-info/dependency_links.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith.egg-info/entry_points.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith.egg-info/requires.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/src/specsmith.egg-info/top_level.txt +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_CMD_001.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_agent_profiles.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_agent_runner_ready.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_ai_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_ai_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_auditor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_channel.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_chat_diff_decision.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_chat_runner_openai_compat.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_chat_stdin_protocol.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_cli.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_cli_workflows_history_drive.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_compliance.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_compressor.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_dispatch.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_e2e_nexus.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_endpoints_cli.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_endpoints_store.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_epistemic.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_fallback_chain.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_importer.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_integrations.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_intelligence.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_issue_reporter.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_mcp_client.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_new_modules.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_nexus.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_permissions.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_phase1_4_new.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_phase34_completion.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_rate_limits.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_req_248_262.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_scaffolder.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_skill_marketplace.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_skills_mcp.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_smoke.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_suggester.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_tools.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_validator.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_vcs.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/tests/test_warp_parity.py +0 -0
- {specsmith-0.11.3.dev428 → specsmith-0.11.3.dev432}/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.11.3.
|
|
3
|
+
Version: 0.11.3.dev432
|
|
4
4
|
Summary: Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands.
|
|
5
5
|
Author: BitConcepts
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "specsmith"
|
|
7
|
-
version = "0.11.3.
|
|
7
|
+
version = "0.11.3.dev432"
|
|
8
8
|
description = "Applied Epistemic Engineering toolkit — AEE agent sessions, execution profiles, FPGA/HDL governance, tool installer, 50+ CLI commands."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -127,6 +127,8 @@ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
|
|
|
127
127
|
"src/specsmith/ci_manager.py" = ["E501"]
|
|
128
128
|
# Context orchestrator: tier descriptions are intentionally descriptive
|
|
129
129
|
"src/specsmith/context_orchestrator.py" = ["E501"]
|
|
130
|
+
# Skills module: skill body strings contain markdown content with long lines
|
|
131
|
+
"src/specsmith/skills/*.py" = ["E501"]
|
|
130
132
|
# Migration files: rule description strings and template content
|
|
131
133
|
"src/specsmith/migrations/m001_governance_yaml.py" = ["E501"]
|
|
132
134
|
"src/specsmith/migrations/m004_ledger_esdb.py" = ["E501"]
|
|
@@ -2471,8 +2471,14 @@ def push_cmd(project_dir: str, force: bool) -> None:
|
|
|
2471
2471
|
default=False,
|
|
2472
2472
|
help="Commit only; skip push.",
|
|
2473
2473
|
)
|
|
2474
|
+
@click.option(
|
|
2475
|
+
"--force",
|
|
2476
|
+
is_flag=True,
|
|
2477
|
+
default=False,
|
|
2478
|
+
help="Override push safety checks (e.g. direct-to-main guard).",
|
|
2479
|
+
)
|
|
2474
2480
|
@click.option("--json", "as_json", is_flag=True, default=False)
|
|
2475
|
-
def save_cmd(project_dir: str, message: str, no_push: bool, as_json: bool) -> None:
|
|
2481
|
+
def save_cmd(project_dir: str, message: str, no_push: bool, force: bool, as_json: bool) -> None:
|
|
2476
2482
|
"""Save governance state: ESDB backup, commit, and push.
|
|
2477
2483
|
|
|
2478
2484
|
Combines ``specsmith esdb backup`` + ``specsmith commit`` + ``specsmith push``
|
|
@@ -2511,7 +2517,7 @@ def save_cmd(project_dir: str, message: str, no_push: bool, as_json: bool) -> No
|
|
|
2511
2517
|
|
|
2512
2518
|
# 3. Push
|
|
2513
2519
|
if not no_push:
|
|
2514
|
-
push_result = run_push(root)
|
|
2520
|
+
push_result = run_push(root, force=force)
|
|
2515
2521
|
steps.append({"step": "push", "ok": push_result.success, "message": push_result.message})
|
|
2516
2522
|
|
|
2517
2523
|
ok = all(s["ok"] for s in steps)
|
|
@@ -2688,11 +2694,28 @@ def pr_cmd(project_dir: str, title: str, draft: bool) -> None:
|
|
|
2688
2694
|
|
|
2689
2695
|
@main.command(name="pull")
|
|
2690
2696
|
@click.option("--project-dir", type=click.Path(exists=True), default=".")
|
|
2691
|
-
|
|
2692
|
-
""
|
|
2693
|
-
|
|
2697
|
+
@click.option(
|
|
2698
|
+
"--discard",
|
|
2699
|
+
is_flag=True,
|
|
2700
|
+
default=False,
|
|
2701
|
+
help="Hard-reset to remote and pull, discarding all local changes.",
|
|
2702
|
+
)
|
|
2703
|
+
@click.option(
|
|
2704
|
+
"--clean",
|
|
2705
|
+
is_flag=True,
|
|
2706
|
+
default=False,
|
|
2707
|
+
help="Like --discard but also removes untracked files (git clean -fd).",
|
|
2708
|
+
)
|
|
2709
|
+
def pull_cmd(project_dir: str, discard: bool, clean: bool) -> None:
|
|
2710
|
+
"""Pull latest changes and check for governance conflicts.
|
|
2711
|
+
|
|
2712
|
+
Use --discard to hard-reset to the remote branch, discarding local
|
|
2713
|
+
changes. Add --clean to also remove untracked files.
|
|
2714
|
+
"""
|
|
2715
|
+
from specsmith.vcs_commands import run_discard, run_sync
|
|
2694
2716
|
|
|
2695
|
-
|
|
2717
|
+
root = Path(project_dir).resolve()
|
|
2718
|
+
result = run_discard(root, clean=clean) if discard or clean else run_sync(root)
|
|
2696
2719
|
if result.success:
|
|
2697
2720
|
console.print(f"[green]\u2713[/green] {result.message}")
|
|
2698
2721
|
else:
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
"""Cross-platform build and tooling skills — CMake, vcpkg, package managers."""
|
|
3
|
+
|
|
4
|
+
from specsmith.skills import SkillDomain, SkillEntry
|
|
5
|
+
|
|
6
|
+
SKILLS: list[SkillEntry] = [
|
|
7
|
+
SkillEntry(
|
|
8
|
+
slug="terminal-awareness",
|
|
9
|
+
name="Terminal Awareness — PowerShell 5/7, cmd.exe, bash/zsh/fish, spawn+PID, cleanup",
|
|
10
|
+
description=(
|
|
11
|
+
"Full cross-platform shell guide: detect the active shell, use correct syntax "
|
|
12
|
+
"per shell, spawn subprocesses with PID tracking, prevent hanging processes, "
|
|
13
|
+
"and clean up reliably on Windows, Linux, and macOS."
|
|
14
|
+
),
|
|
15
|
+
domain=SkillDomain.CROSS_PLATFORM,
|
|
16
|
+
tags=[
|
|
17
|
+
"powershell",
|
|
18
|
+
"pwsh",
|
|
19
|
+
"cmd",
|
|
20
|
+
"bash",
|
|
21
|
+
"zsh",
|
|
22
|
+
"fish",
|
|
23
|
+
"shell",
|
|
24
|
+
"terminal",
|
|
25
|
+
"pid",
|
|
26
|
+
"subprocess",
|
|
27
|
+
"cleanup",
|
|
28
|
+
"cross-platform",
|
|
29
|
+
"windows",
|
|
30
|
+
"linux",
|
|
31
|
+
"macos",
|
|
32
|
+
],
|
|
33
|
+
platforms=["windows", "linux", "macos"],
|
|
34
|
+
prerequisites=[],
|
|
35
|
+
body="""\
|
|
36
|
+
# Terminal Awareness Skill
|
|
37
|
+
|
|
38
|
+
## Rule: Always match syntax to the active shell
|
|
39
|
+
Never run PowerShell cmdlets in bash. Never run bash-isms in cmd.exe.
|
|
40
|
+
Detect first, then adapt.
|
|
41
|
+
|
|
42
|
+
## Shell detection
|
|
43
|
+
|
|
44
|
+
### From Python (most reliable in agent code)
|
|
45
|
+
```python
|
|
46
|
+
import os, sys
|
|
47
|
+
|
|
48
|
+
def detect_shell() -> str:
|
|
49
|
+
# Explicit override
|
|
50
|
+
shell = os.environ.get("SHELL", "") # /bin/bash, /bin/zsh, /usr/bin/fish
|
|
51
|
+
comspec = os.environ.get("ComSpec", "") # C:\\Windows\\System32\\cmd.exe
|
|
52
|
+
psver = os.environ.get("PSVersionTable", "") # set by PowerShell
|
|
53
|
+
if os.environ.get("__CFBundleIdentifier", ""): # macOS Terminal.app
|
|
54
|
+
pass
|
|
55
|
+
if shell.endswith("fish"): return "fish"
|
|
56
|
+
if shell.endswith("zsh"): return "zsh"
|
|
57
|
+
if shell.endswith("bash"): return "bash"
|
|
58
|
+
if comspec: return "cmd"
|
|
59
|
+
if os.environ.get("PSModulePath"): return "powershell" # pwsh or ps5
|
|
60
|
+
return "unknown"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### From the shell itself
|
|
64
|
+
```bash
|
|
65
|
+
echo $0 # bash: bash or -bash; zsh: -zsh; fish: fish
|
|
66
|
+
ps -p $$ # Linux/macOS: show parent process
|
|
67
|
+
```
|
|
68
|
+
```pwsh
|
|
69
|
+
$PSVersionTable.PSVersion # PowerShell version (5.x or 7.x)
|
|
70
|
+
$PSVersionTable.PSEdition # Desktop (PS5) vs Core (PS7)
|
|
71
|
+
```
|
|
72
|
+
```bat
|
|
73
|
+
echo %ComSpec% # cmd.exe: C:\\Windows\\System32\\cmd.exe
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## PowerShell 5 (Desktop) vs PowerShell 7 (Core) — critical differences
|
|
77
|
+
|
|
78
|
+
| Feature | PS5 (Windows only) | PS7 (cross-platform) |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Invoke | `powershell.exe` | `pwsh.exe` / `pwsh` |
|
|
81
|
+
| Edition | `Desktop` | `Core` |
|
|
82
|
+
| Null coalescing | NOT available | `$a ??= $b` |
|
|
83
|
+
| Ternary | NOT available | `$a ? $b : $c` |
|
|
84
|
+
| Pipelines | `ForEach-Object` | `ForEach-Object -Parallel` |
|
|
85
|
+
| Import-Module | Single-threaded | Thread-safe |
|
|
86
|
+
| `-ErrorAction` | Limited | Full `Stop`/`SilentlyContinue` |
|
|
87
|
+
| Encoding default | UTF-16 LE | UTF-8 |
|
|
88
|
+
| `&&` / `\\|\\|` | NOT available | Available (PS7.1+) |
|
|
89
|
+
| Out-File encoding | UTF-16 | UTF-8 (use `-Encoding utf8NoBOM`) |
|
|
90
|
+
| `$env:PATH` sep | `;` | `;` (Windows) / `:` (Linux/macOS) |
|
|
91
|
+
|
|
92
|
+
```pwsh
|
|
93
|
+
# Safe version guard
|
|
94
|
+
if ($PSVersionTable.PSVersion.Major -lt 7) {
|
|
95
|
+
Write-Error "This script requires PowerShell 7+"; exit 1
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# PS7-only: parallel foreach
|
|
99
|
+
1..10 | ForEach-Object -Parallel { Start-Process "task$_" } -ThrottleLimit 4
|
|
100
|
+
|
|
101
|
+
# Both: null coalescing the safe way
|
|
102
|
+
$val = if ($null -ne $x) { $x } else { "default" } # PS5+PS7
|
|
103
|
+
$val = $x ?? "default" # PS7 only
|
|
104
|
+
|
|
105
|
+
# Encoding — always explicit
|
|
106
|
+
"content" | Out-File -FilePath file.txt -Encoding utf8NoBOM # PS7
|
|
107
|
+
[System.IO.File]::WriteAllText("file.txt", "content") # PS5 safe UTF-8
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## cmd.exe rules
|
|
111
|
+
```bat
|
|
112
|
+
:: Variables: %VAR% not $VAR
|
|
113
|
+
set MYVAR=hello
|
|
114
|
+
echo %MYVAR%
|
|
115
|
+
|
|
116
|
+
:: No pipelines to non-exe targets
|
|
117
|
+
:: WRONG: dir | Select-String <-- Select-String is PowerShell
|
|
118
|
+
:: RIGHT: dir | findstr pattern
|
|
119
|
+
|
|
120
|
+
:: Conditionals
|
|
121
|
+
if exist file.txt (echo found) else (echo missing)
|
|
122
|
+
if %ERRORLEVEL% NEQ 0 (echo failed)
|
|
123
|
+
|
|
124
|
+
:: Multiline — use ^ for continuation
|
|
125
|
+
copy /Y src\file.txt ^\n dest\file.txt
|
|
126
|
+
|
|
127
|
+
:: Spawn and wait
|
|
128
|
+
start /wait myprogram.exe arg1
|
|
129
|
+
call script.bat :: blocks until done
|
|
130
|
+
|
|
131
|
+
:: Get PID of last background process — cmd has no native $!
|
|
132
|
+
:: Use wmic or PowerShell from within cmd:
|
|
133
|
+
powershell -Command "$proc = Start-Process myapp -PassThru; $proc.Id"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## bash / zsh / fish
|
|
137
|
+
```bash
|
|
138
|
+
# bash/zsh: spawn in background, capture PID
|
|
139
|
+
myprogram &
|
|
140
|
+
BG_PID=$!
|
|
141
|
+
wait $BG_PID # blocks until done
|
|
142
|
+
echo "Exit: $?"
|
|
143
|
+
|
|
144
|
+
# With timeout (bash 4+)
|
|
145
|
+
timeout 30s myprogram || echo "timed out or failed"
|
|
146
|
+
|
|
147
|
+
# fish: no $!, use fish_pid
|
|
148
|
+
set bg_pid (myprogram &; echo $last_pid)
|
|
149
|
+
|
|
150
|
+
# Trap for cleanup on exit (bash/zsh)
|
|
151
|
+
trap 'kill $BG_PID 2>/dev/null' EXIT INT TERM
|
|
152
|
+
|
|
153
|
+
# Check if process is still running
|
|
154
|
+
kill -0 $BG_PID 2>/dev/null && echo "running" || echo "dead"
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Subprocess spawn with PID tracking
|
|
158
|
+
|
|
159
|
+
### Python (cross-platform, preferred in agent tooling)
|
|
160
|
+
```python
|
|
161
|
+
import subprocess, signal, os, sys
|
|
162
|
+
|
|
163
|
+
# Spawn and track
|
|
164
|
+
proc = subprocess.Popen(
|
|
165
|
+
["myprogram", "--arg"],
|
|
166
|
+
stdout=subprocess.PIPE,
|
|
167
|
+
stderr=subprocess.PIPE,
|
|
168
|
+
# Windows: CREATE_NEW_PROCESS_GROUP for clean Ctrl+C forwarding
|
|
169
|
+
**({"creationflags": subprocess.CREATE_NEW_PROCESS_GROUP}
|
|
170
|
+
if sys.platform == "win32" else {}),
|
|
171
|
+
)
|
|
172
|
+
pid = proc.pid
|
|
173
|
+
|
|
174
|
+
# Wait with timeout
|
|
175
|
+
try:
|
|
176
|
+
stdout, stderr = proc.communicate(timeout=60)
|
|
177
|
+
except subprocess.TimeoutExpired:
|
|
178
|
+
proc.kill() # force-kill on timeout
|
|
179
|
+
stdout, stderr = proc.communicate() # drain pipes
|
|
180
|
+
raise
|
|
181
|
+
|
|
182
|
+
# Ensure cleanup
|
|
183
|
+
def kill_proc(p: subprocess.Popen) -> None:
|
|
184
|
+
if p.poll() is None: # still running
|
|
185
|
+
if sys.platform == "win32":
|
|
186
|
+
p.send_signal(signal.CTRL_BREAK_EVENT) # Windows
|
|
187
|
+
else:
|
|
188
|
+
p.terminate() # SIGTERM
|
|
189
|
+
try:
|
|
190
|
+
p.wait(timeout=5)
|
|
191
|
+
except subprocess.TimeoutExpired:
|
|
192
|
+
p.kill() # SIGKILL fallback
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### PowerShell spawn + PID
|
|
196
|
+
```pwsh
|
|
197
|
+
# Start-Process returns a System.Diagnostics.Process object
|
|
198
|
+
$proc = Start-Process -FilePath "myprogram" -ArgumentList "--arg" -PassThru -NoNewWindow
|
|
199
|
+
$pid = $proc.Id
|
|
200
|
+
|
|
201
|
+
# Wait with timeout (ms)
|
|
202
|
+
$done = $proc.WaitForExit(30000) # 30 s
|
|
203
|
+
if (-not $done) {
|
|
204
|
+
Stop-Process -Id $pid -Force
|
|
205
|
+
throw "Timed out"
|
|
206
|
+
}
|
|
207
|
+
Write-Host "Exit code: $($proc.ExitCode)"
|
|
208
|
+
|
|
209
|
+
# Cleanup on script exit
|
|
210
|
+
try {
|
|
211
|
+
# ... do work ...
|
|
212
|
+
} finally {
|
|
213
|
+
if ($proc -and -not $proc.HasExited) { Stop-Process -Id $pid -Force }
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Preventing hanging processes
|
|
218
|
+
|
|
219
|
+
### Root causes and fixes
|
|
220
|
+
| Cause | Fix |
|
|
221
|
+
|---|---|
|
|
222
|
+
| stdout/stderr pipe full | Always use `communicate()` or `DEVNULL` — never `Popen.wait()` with pipes |
|
|
223
|
+
| stdin waiting for input | Pass `stdin=subprocess.DEVNULL` or `input=b""` |
|
|
224
|
+
| Zombie child (POSIX) | Call `proc.wait()` after `proc.kill()` |
|
|
225
|
+
| Windows job object leak | Use `CREATE_NEW_PROCESS_GROUP` + `GenerateConsoleCtrlEvent` |
|
|
226
|
+
| Timeout not enforced | Always set `timeout=` in `communicate()` — never bare `wait()` |
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
# Safe subprocess runner (Python, all platforms)
|
|
230
|
+
def run_safe(cmd: list[str], timeout: int = 60) -> tuple[int, str, str]:
|
|
231
|
+
proc = subprocess.Popen(
|
|
232
|
+
cmd,
|
|
233
|
+
stdout=subprocess.PIPE,
|
|
234
|
+
stderr=subprocess.PIPE,
|
|
235
|
+
stdin=subprocess.DEVNULL, # never hang waiting for input
|
|
236
|
+
)
|
|
237
|
+
try:
|
|
238
|
+
out, err = proc.communicate(timeout=timeout)
|
|
239
|
+
return proc.returncode, out.decode(errors="replace"), err.decode(errors="replace")
|
|
240
|
+
except subprocess.TimeoutExpired:
|
|
241
|
+
proc.kill()
|
|
242
|
+
proc.communicate() # drain to avoid zombie
|
|
243
|
+
return -1, "", f"Timed out after {timeout}s"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Cross-platform command equivalents
|
|
247
|
+
|
|
248
|
+
| Intent | bash/zsh | PowerShell | cmd.exe |
|
|
249
|
+
|---|---|---|---|
|
|
250
|
+
| Print text | `echo text` | `Write-Host text` | `echo text` |
|
|
251
|
+
| Set variable | `VAR=val` | `$var = 'val'` | `set VAR=val` |
|
|
252
|
+
| Read variable | `$VAR` | `$var` | `%VAR%` |
|
|
253
|
+
| Check exit code | `echo $?` | `$LASTEXITCODE` | `echo %ERRORLEVEL%` |
|
|
254
|
+
| List directory | `ls` / `dir` | `Get-ChildItem` / `dir` | `dir` |
|
|
255
|
+
| Copy file | `cp src dst` | `Copy-Item src dst` | `copy src dst` |
|
|
256
|
+
| Move file | `mv src dst` | `Move-Item src dst` | `move src dst` |
|
|
257
|
+
| Delete file | `rm file` | `Remove-Item file` | `del file` |
|
|
258
|
+
| Make dir | `mkdir dir` | `New-Item -Type Directory` | `mkdir dir` |
|
|
259
|
+
| Current dir | `pwd` | `$PWD` / `Get-Location` | `cd` |
|
|
260
|
+
| Change dir | `cd path` | `Set-Location path` | `cd path` |
|
|
261
|
+
| Environment var | `export K=V` | `$env:K = 'V'` | `set K=V` |
|
|
262
|
+
| Command exists | `which cmd` | `Get-Command cmd -EA SilentlyContinue` | `where cmd` |
|
|
263
|
+
| Kill process | `kill -9 PID` | `Stop-Process -Id PID -Force` | `taskkill /F /PID PID` |
|
|
264
|
+
| List processes | `ps aux` | `Get-Process` | `tasklist` |
|
|
265
|
+
| Sleep | `sleep 5` | `Start-Sleep 5` | `timeout /t 5` |
|
|
266
|
+
| Null device | `/dev/null` | `$null` / `NUL` | `NUL` |
|
|
267
|
+
| Script exit | `exit 1` | `exit 1` | `exit /b 1` |
|
|
268
|
+
| And-chain | `cmd1 && cmd2` | `cmd1; if ($?) { cmd2 }` (PS5) / `cmd1 && cmd2` (PS7) | `cmd1 && cmd2` |
|
|
269
|
+
| Or-fallback | `cmd1 \\|\\| cmd2` | `cmd1; if (-not $?) { cmd2 }` (PS5) / `cmd1 \\|\\| cmd2` (PS7) | `cmd1 \\|\\| cmd2` |
|
|
270
|
+
|
|
271
|
+
## macOS-specific notes
|
|
272
|
+
- Default shell since Catalina (10.15): **zsh** (`/bin/zsh`)
|
|
273
|
+
- bash is `/bin/bash` (3.2 — ancient; install brew bash for 5.x)
|
|
274
|
+
- `brew install coreutils` for GNU equivalents (`gls`, `gcp`, etc.)
|
|
275
|
+
- `launchctl list` replaces `systemctl` for service management
|
|
276
|
+
- Gatekeeper: new binaries need `xattr -d com.apple.quarantine <bin>`
|
|
277
|
+
|
|
278
|
+
## Cleanup checklist (before ending any session that spawned processes)
|
|
279
|
+
1. `kill $BG_PID` (bash) / `Stop-Process $proc.Id` (pwsh) — signal first
|
|
280
|
+
2. `wait $BG_PID` / `$proc.WaitForExit(5000)` — confirm termination
|
|
281
|
+
3. `kill -9 $BG_PID` / `Stop-Process -Force` — force if still alive
|
|
282
|
+
4. Remove `.specsmith/pids/<pid>.json` via `specsmith abort --all`
|
|
283
|
+
5. Verify: `specsmith ps` / `ps aux | grep myprogram` / `tasklist | findstr myprogram`
|
|
284
|
+
""",
|
|
285
|
+
),
|
|
286
|
+
SkillEntry(
|
|
287
|
+
slug="cmake-cross-platform",
|
|
288
|
+
name="CMake — cross-platform builds, vcpkg, conan, presets",
|
|
289
|
+
description=(
|
|
290
|
+
"CMake cross-platform build system: modern target-based configuration, "
|
|
291
|
+
"vcpkg/conan dependency management, CMake presets, and CI integration."
|
|
292
|
+
),
|
|
293
|
+
domain=SkillDomain.CROSS_PLATFORM,
|
|
294
|
+
tags=[
|
|
295
|
+
"cmake",
|
|
296
|
+
"vcpkg",
|
|
297
|
+
"conan",
|
|
298
|
+
"cross-platform",
|
|
299
|
+
"c",
|
|
300
|
+
"cpp",
|
|
301
|
+
"build",
|
|
302
|
+
"ninja",
|
|
303
|
+
"presets",
|
|
304
|
+
"windows",
|
|
305
|
+
"linux",
|
|
306
|
+
"macos",
|
|
307
|
+
],
|
|
308
|
+
platforms=["windows", "linux", "macos"],
|
|
309
|
+
prerequisites=["cmake", "ninja"],
|
|
310
|
+
body="""\
|
|
311
|
+
# CMake Cross-Platform Skill
|
|
312
|
+
|
|
313
|
+
## Modern CMakeLists.txt (target-based)
|
|
314
|
+
```cmake
|
|
315
|
+
cmake_minimum_required(VERSION 3.25)
|
|
316
|
+
project(myapp VERSION 1.0.0 LANGUAGES CXX)
|
|
317
|
+
|
|
318
|
+
set(CMAKE_CXX_STANDARD 20)
|
|
319
|
+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
|
320
|
+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # for clangd / clang-tidy
|
|
321
|
+
|
|
322
|
+
add_executable(myapp
|
|
323
|
+
src/main.cpp
|
|
324
|
+
src/engine.cpp)
|
|
325
|
+
|
|
326
|
+
target_include_directories(myapp
|
|
327
|
+
PRIVATE src/include
|
|
328
|
+
PUBLIC include)
|
|
329
|
+
|
|
330
|
+
target_compile_options(myapp PRIVATE
|
|
331
|
+
$<$<CXX_COMPILER_ID:MSVC>:/W4 /WX>
|
|
332
|
+
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall -Wextra -Werror>)
|
|
333
|
+
|
|
334
|
+
target_link_libraries(myapp
|
|
335
|
+
PRIVATE fmt::fmt spdlog::spdlog)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## CMake Presets (CMakePresets.json)
|
|
339
|
+
```json
|
|
340
|
+
{
|
|
341
|
+
"version": 6,
|
|
342
|
+
"configurePresets": [
|
|
343
|
+
{
|
|
344
|
+
"name": "linux-release",
|
|
345
|
+
"generator": "Ninja",
|
|
346
|
+
"binaryDir": "build/linux-release",
|
|
347
|
+
"cacheVariables": {
|
|
348
|
+
"CMAKE_BUILD_TYPE": "Release",
|
|
349
|
+
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
|
350
|
+
}
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"name": "windows-msvc",
|
|
354
|
+
"generator": "Visual Studio 17 2022",
|
|
355
|
+
"binaryDir": "build/windows-msvc",
|
|
356
|
+
"architecture": {"value": "x64", "strategy": "set"},
|
|
357
|
+
"cacheVariables": {
|
|
358
|
+
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
],
|
|
362
|
+
"buildPresets": [
|
|
363
|
+
{"name": "linux-release", "configurePreset": "linux-release"},
|
|
364
|
+
{"name": "windows-release", "configurePreset": "windows-msvc", "configuration": "Release"}
|
|
365
|
+
]
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
```bash
|
|
369
|
+
cmake --preset linux-release
|
|
370
|
+
cmake --build --preset linux-release
|
|
371
|
+
cmake --list-presets # list all presets
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## vcpkg dependency management
|
|
375
|
+
```bash
|
|
376
|
+
# Bootstrap vcpkg
|
|
377
|
+
git clone https://github.com/microsoft/vcpkg $HOME/vcpkg
|
|
378
|
+
$HOME/vcpkg/bootstrap-vcpkg.sh # Linux/macOS
|
|
379
|
+
%USERPROFILE%\\vcpkg\\bootstrap-vcpkg.bat # Windows
|
|
380
|
+
|
|
381
|
+
# Install packages (manifest mode — recommended)
|
|
382
|
+
# vcpkg.json in project root:
|
|
383
|
+
{
|
|
384
|
+
"name": "myapp",
|
|
385
|
+
"version": "1.0.0",
|
|
386
|
+
"dependencies": [
|
|
387
|
+
"fmt", "spdlog",
|
|
388
|
+
{"name": "boost-filesystem", "version>=": "1.83.0"}
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
# Set VCPKG_ROOT and use CMAKE_TOOLCHAIN_FILE=.../vcpkg.cmake
|
|
392
|
+
cmake --preset linux-release # auto-installs from vcpkg.json
|
|
393
|
+
|
|
394
|
+
vcpkg search boost # search packages
|
|
395
|
+
vcpkg list # show installed
|
|
396
|
+
vcpkg install fmt:x64-windows # manual install (classic mode)
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
## Conan 2 dependency management
|
|
400
|
+
```bash
|
|
401
|
+
pip install conan
|
|
402
|
+
conan profile detect # auto-detect host profile
|
|
403
|
+
# conanfile.txt:
|
|
404
|
+
[requires]
|
|
405
|
+
fmt/10.2.1
|
|
406
|
+
spdlog/1.13.0
|
|
407
|
+
[generators]
|
|
408
|
+
CMakeDeps
|
|
409
|
+
CMakeToolchain
|
|
410
|
+
|
|
411
|
+
conan install . --build=missing # install + generate CMake files
|
|
412
|
+
cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake
|
|
413
|
+
cmake --build build
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Cross-compilation with CMake toolchain
|
|
417
|
+
```cmake
|
|
418
|
+
# toolchain-aarch64-linux.cmake
|
|
419
|
+
set(CMAKE_SYSTEM_NAME Linux)
|
|
420
|
+
set(CMAKE_SYSTEM_PROCESSOR aarch64)
|
|
421
|
+
set(CMAKE_C_COMPILER aarch64-linux-gnu-gcc)
|
|
422
|
+
set(CMAKE_CXX_COMPILER aarch64-linux-gnu-g++)
|
|
423
|
+
set(CMAKE_FIND_ROOT_PATH /opt/sysroot-aarch64)
|
|
424
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
|
425
|
+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
|
426
|
+
```
|
|
427
|
+
```bash
|
|
428
|
+
cmake -B build-arm -DCMAKE_TOOLCHAIN_FILE=toolchain-aarch64-linux.cmake
|
|
429
|
+
cmake --build build-arm
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## Common pitfalls
|
|
433
|
+
- CMake 3.25+: use `cmake --preset`; older: pass `-G Ninja -B build`.
|
|
434
|
+
- MSVC: open "Developer Command Prompt" or use `vcvarsall.bat x64`.
|
|
435
|
+
- vcpkg: set `VCPKG_ROOT` env var system-wide; don't hardcode paths.
|
|
436
|
+
- `compile_commands.json`: generated by Ninja/Make, not MSVC
|
|
437
|
+
(use `CMAKE_EXPORT_COMPILE_COMMANDS=ON`).
|
|
438
|
+
""",
|
|
439
|
+
),
|
|
440
|
+
SkillEntry(
|
|
441
|
+
slug="package-managers",
|
|
442
|
+
name="Package Managers — brew, winget, scoop, apt, nix (cross-platform)",
|
|
443
|
+
description=(
|
|
444
|
+
"Cross-platform package manager workflows: Homebrew (macOS/Linux), "
|
|
445
|
+
"winget/scoop/choco (Windows), apt/dnf (Linux), and Nix for reproducibility."
|
|
446
|
+
),
|
|
447
|
+
domain=SkillDomain.CROSS_PLATFORM,
|
|
448
|
+
tags=[
|
|
449
|
+
"homebrew",
|
|
450
|
+
"brew",
|
|
451
|
+
"winget",
|
|
452
|
+
"scoop",
|
|
453
|
+
"chocolatey",
|
|
454
|
+
"apt",
|
|
455
|
+
"dnf",
|
|
456
|
+
"nix",
|
|
457
|
+
"package-manager",
|
|
458
|
+
"cross-platform",
|
|
459
|
+
],
|
|
460
|
+
platforms=["windows", "linux", "macos"],
|
|
461
|
+
prerequisites=[],
|
|
462
|
+
body="""\
|
|
463
|
+
# Cross-Platform Package Managers Skill
|
|
464
|
+
|
|
465
|
+
## macOS — Homebrew
|
|
466
|
+
```bash
|
|
467
|
+
# Install
|
|
468
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
469
|
+
|
|
470
|
+
brew install git cmake ninja python@3.12 node
|
|
471
|
+
brew install --cask visual-studio-code docker
|
|
472
|
+
brew upgrade # upgrade all packages
|
|
473
|
+
brew outdated # list outdatable packages
|
|
474
|
+
brew cleanup # remove old versions
|
|
475
|
+
brew leaves # show top-level installed packages
|
|
476
|
+
brew bundle dump # export Brewfile
|
|
477
|
+
brew bundle install # install from Brewfile
|
|
478
|
+
|
|
479
|
+
# Brewfile (commit to repo for team consistency)
|
|
480
|
+
tap "homebrew/cask"
|
|
481
|
+
brew "git"
|
|
482
|
+
brew "cmake"
|
|
483
|
+
brew "ninja"
|
|
484
|
+
cask "docker"
|
|
485
|
+
cask "visual-studio-code"
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
## Linux — apt (Debian/Ubuntu)
|
|
489
|
+
```bash
|
|
490
|
+
sudo apt update && sudo apt upgrade -y
|
|
491
|
+
sudo apt install -y git cmake ninja-build python3 python3-pip nodejs npm
|
|
492
|
+
sudo apt install -y build-essential gcc g++ clang clang-tidy clang-format
|
|
493
|
+
|
|
494
|
+
# Add third-party repo (example: GitHub CLI)
|
|
495
|
+
type -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
|
|
496
|
+
sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
|
497
|
+
echo "deb [arch=$(dpkg --print-architecture) \
|
|
498
|
+
signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] \
|
|
499
|
+
https://cli.github.com/packages stable main" \
|
|
500
|
+
| sudo tee /etc/apt/sources.list.d/github-cli.list
|
|
501
|
+
sudo apt update && sudo apt install gh
|
|
502
|
+
|
|
503
|
+
# List installed packages
|
|
504
|
+
dpkg -l | grep <pattern>
|
|
505
|
+
apt list --installed
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
## Linux — dnf (RHEL/Fedora/AlmaLinux)
|
|
509
|
+
```bash
|
|
510
|
+
sudo dnf update -y
|
|
511
|
+
sudo dnf install -y git cmake ninja-build python3 nodejs npm gcc gcc-c++ clang
|
|
512
|
+
sudo dnf groupinstall "Development Tools"
|
|
513
|
+
dnf list installed | grep <pattern>
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
## Windows — winget (built-in Windows Package Manager)
|
|
517
|
+
```powershell
|
|
518
|
+
winget search git
|
|
519
|
+
winget install Git.Git
|
|
520
|
+
winget install Kitware.CMake
|
|
521
|
+
winget install Python.Python.3.12
|
|
522
|
+
winget install Microsoft.VisualStudioCode
|
|
523
|
+
winget install Docker.DockerDesktop
|
|
524
|
+
winget upgrade --all # upgrade everything
|
|
525
|
+
winget export -o packages.json # export installed list
|
|
526
|
+
winget import -i packages.json # import and install
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## Windows — Scoop (developer-friendly, no admin needed)
|
|
530
|
+
```powershell
|
|
531
|
+
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
|
532
|
+
Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression
|
|
533
|
+
|
|
534
|
+
scoop install git cmake ninja python nodejs
|
|
535
|
+
scoop bucket add extras
|
|
536
|
+
scoop install vscode
|
|
537
|
+
scoop update * # update all
|
|
538
|
+
scoop status # show updatable
|
|
539
|
+
scoop export > scoop-packages.json # export
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
## Nix — reproducible, cross-platform
|
|
543
|
+
```bash
|
|
544
|
+
# Install Nix (Linux/macOS)
|
|
545
|
+
sh <(curl -L https://nixos.org/nix/install) --daemon
|
|
546
|
+
|
|
547
|
+
# nix shell — ephemeral env (no install)
|
|
548
|
+
nix shell nixpkgs#git nixpkgs#cmake nixpkgs#ninja
|
|
549
|
+
|
|
550
|
+
# flake.nix (project-level devShell)
|
|
551
|
+
{
|
|
552
|
+
outputs = { nixpkgs, ... }: {
|
|
553
|
+
devShell.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.mkShell {
|
|
554
|
+
packages = with nixpkgs.legacyPackages.x86_64-linux; [
|
|
555
|
+
git cmake ninja python3 nodejs
|
|
556
|
+
];
|
|
557
|
+
};
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
# Enter dev shell: nix develop
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
## Common pitfalls
|
|
564
|
+
- Homebrew on Apple Silicon: installs to `/opt/homebrew/`; Intel: `/usr/local/`.
|
|
565
|
+
- winget: requires Windows Package Manager app from Store on older Windows 10.
|
|
566
|
+
- Scoop: installs to `~/scoop/` — no admin rights needed, great for CI.
|
|
567
|
+
- Nix: steep learning curve but ultimate reproducibility; use nix-shell for experiments.
|
|
568
|
+
""",
|
|
569
|
+
),
|
|
570
|
+
]
|