multi-forge 0.8.1__tar.gz → 0.9.0__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.
- {multi_forge-0.8.1 → multi_forge-0.9.0}/PKG-INFO +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/pyproject.toml +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/extensions.py +289 -64
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/memory.py +100 -83
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/memory_report.py +3 -3
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/runtime.py +3 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_lifecycle.py +4 -4
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_memory.py +3 -3
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/workflow.py +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/backends/litellm.yaml +22 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/codex-responses-local.yaml +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-openai.yaml +3 -3
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +4 -4
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/schema.py +4 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/data/model_catalog.yaml +82 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime/codex_preflight.py +8 -8
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime/registry.py +25 -15
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/lock.py +7 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/__init__.py +6 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/hook_dispatcher.py +8 -4
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/hook_migration.py +1 -0
- multi_forge-0.9.0/src/forge/install/installer.py +2412 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/models.py +57 -1
- multi_forge-0.9.0/src/forge/install/skill_cache.py +174 -0
- multi_forge-0.9.0/src/forge/install/skill_compiler.py +1660 -0
- multi_forge-0.9.0/src/forge/install/skill_planning.py +424 -0
- multi_forge-0.9.0/src/forge/install/skill_validation.py +1140 -0
- multi_forge-0.9.0/src/forge/install/tracking.py +394 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/models.py +6 -3
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/claude/cleanup.py +2 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/hooks/session_start.py +4 -4
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/launch_confirmation.py +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/memory_inheritance.py +1 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/models.py +13 -11
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/passport.py +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/project_memory.py +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/transfer.py +1 -1
- multi_forge-0.8.1/src/skills/challenge/SKILL.md → multi_forge-0.9.0/src/skills/challenge/content.md +10 -20
- multi_forge-0.9.0/src/skills/challenge/forge-skill.yaml +9 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/consensus/SKILL.md +3 -3
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/debate/SKILL.md +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/panel/SKILL.md +7 -7
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/panel/resources/synthesis.md +4 -4
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/0-enable.md +8 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/15-skills.md +50 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/17-info.md +30 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/18-disable.md +31 -5
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/19-uninstall.md +11 -6
- multi_forge-0.9.0/src/skills/qa/resources/checklist/2-extension.md +473 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/4-proxy.md +2 -2
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/6-hook.md +10 -1
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist.md +15 -11
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/scripts/start-container.sh +2 -2
- multi_forge-0.9.0/src/skills/review/content.md +96 -0
- multi_forge-0.9.0/src/skills/review/forge-skill.yaml +21 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/references/skills-writing-guide.md +58 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/resources/code-anthropic.md +7 -15
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/resources/code-gemini.md +7 -15
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/resources/code-openai.md +8 -16
- multi_forge-0.9.0/src/skills/review-docs/content.md +93 -0
- multi_forge-0.9.0/src/skills/review-docs/forge-skill.yaml +14 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-anthropic.md +6 -14
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-gemini.md +6 -14
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs-openai.md +7 -15
- multi_forge-0.9.0/src/skills/smoke-test/content.md +18 -0
- multi_forge-0.9.0/src/skills/smoke-test/forge-skill.yaml +8 -0
- multi_forge-0.9.0/src/skills/smoke-test/scripts/smoke-test.sh +157 -0
- multi_forge-0.8.1/src/skills/understand/SKILL.md → multi_forge-0.9.0/src/skills/understand/content.md +27 -51
- multi_forge-0.9.0/src/skills/understand/forge-skill.yaml +18 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/code-anthropic.md +11 -24
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/code-gemini.md +12 -25
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/code-openai.md +12 -25
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/code.md +11 -24
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/docs-anthropic.md +13 -28
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/docs-gemini.md +14 -29
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/docs-openai.md +14 -29
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/understand/resources/docs.md +13 -28
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/walkthrough/SKILL.md +13 -10
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/walkthrough/resources/checklist.md +179 -35
- multi_forge-0.8.1/src/forge/install/installer.py +0 -1259
- multi_forge-0.8.1/src/forge/install/tracking.py +0 -230
- multi_forge-0.8.1/src/skills/qa/resources/checklist/2-extension.md +0 -265
- multi_forge-0.8.1/src/skills/review/SKILL.md +0 -125
- multi_forge-0.8.1/src/skills/review-docs/SKILL.md +0 -121
- multi_forge-0.8.1/src/skills/smoke-test/SKILL.md +0 -27
- multi_forge-0.8.1/src/skills/smoke-test/scripts/smoke-test.sh +0 -118
- {multi_forge-0.8.1 → multi_forge-0.9.0}/.gitignore +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/LICENSE +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/NOTICE +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/README.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/agents/.gitkeep +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/commands/.gitkeep +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/adapters/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/adapters/litellm.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/creation.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/registry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/remote/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/remote/base.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/remote/openrouter.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/backend/sources.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/activity.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/auth.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/backend.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/claude.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/codex.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/config_cmd.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/consumer_lane_freeze.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/editor.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/gc.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/guards.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/_group.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/_helpers.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_patch.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_policy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/codex_transfer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/commands.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/direct_commands.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/policy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/protocols.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/hooks/verification.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/logs.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/main.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/memory_writer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/model.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/output.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/policy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/proxy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/proxy_audit.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/proxy_costs.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/search.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_codex.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_fork.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_lane.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_manage.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_model_pin.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_resume_modes.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_rewind.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_routing.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/session_supervisor_options.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/status_line.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/context.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/names.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/palette.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/registry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/statusline/throttle.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/telemetry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/trace.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/cli/transfer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/dataclass_utils.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/backends/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/anthropic-passthrough.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/config/loader.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/capabilities.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/credentials_file.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/protocols.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/secrets.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/auth/template_secrets.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/backend_dependency.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/credential_registry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/data/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/effort.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/_lifecycle.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/claude.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/codex.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/codex_stream.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/invoker/types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/lanes.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/clients/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/clients/base.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/clients/litellm.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/clients/openai_compat.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/clients/openrouter.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/credentials.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/detection.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/errors.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/protocols.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/llm/types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/logging.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/models/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/models/catalog.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/models/direct_model.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/models/types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/naming.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/backend_reconcile.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/claude_session.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/codex_bridge.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/codex_enrollment.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/codex_interactive.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/codex_session.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/context.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/gc.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/policy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/provider_trace.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/proxy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/resolution.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/session.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/session_context.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/transfer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/ops/usage_summary.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/paths.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/process.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/provider_types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/cost_tracking.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/env.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/headless_json.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/proxy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/routing.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/session_runner.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/structured_output.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/tagger.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/reactive/throttle.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/run_id.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime/codex_preflight_cache.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime/codex_rollouts.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/runtime_vocab.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/exceptions.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/io.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/retention.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/timestamps.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/state/versioned_store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/caps.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/downstream.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/jsonl_io.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/upstream.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/telemetry/vocabulary.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/tiers.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/transcript.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/typing_helpers.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/billing.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/correlation.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/emit.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/ledger.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/measurement.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/usage/vocabulary.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/workqueue/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/workqueue/queue.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/core/workqueue/types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/cli.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/codex_hooks.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/doctor.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/exceptions.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/hooks.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/preset.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/project_compat.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/project_registry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/settings_merge.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/install/version.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/deterministic/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/deterministic/base.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/deterministic/coding_standards.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/deterministic/registry.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/deterministic/tdd.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/engine.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/protocols.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/queries.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/plan_check.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/shadow.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/shadow_runner.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/supervisor.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/semantic/verdict.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/supervisor_lane_degrade.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/team/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/team/config.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/team/handlers.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/team/prompts.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/types.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/branches.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/config.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/divergence.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/policy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/policy/workflow/stages.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/audit_logger.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/base_client.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/client_adapter.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/client_factory.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/converters.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/cost_logger.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/cost_tracker.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/data_models.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/error_hints.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/intercept.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/metrics.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/model_spec.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/passthrough.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/ports.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/provider_trace_logger.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/proxies.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/proxy_identity.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/proxy_orchestrator.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/proxy_startup.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/responses_ingress.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/responses_passthrough.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/server.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/stream_relay.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/proxy/utils.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/adversarial.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/consensus.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/engine.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/code_consensus_evaluation.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/code_debate_evaluation.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/codereview-performance.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/codereview-quick.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/codereview-security.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/codereview.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/consensus_evaluation.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/debate_evaluation.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/docreview-quick.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/docreview.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/resources/thinkdeep.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/routing.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/review/synthesis.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/runtime_config.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/bm25_store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/content_store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/engine.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/exceptions.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/extractor.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/index_state.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/search/tokenizer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/active.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/addendum.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/artifacts.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/claude/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/claude/invoke.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/claude/paths.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/claude/relocate.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/cleanup.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/codex_handoff.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/codex_invoke.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/config.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/consumer_lanes.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/context_limit.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/effective.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/exceptions.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/hooks/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/hooks/models.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/identity.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/index.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/launch.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/manager.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/memory_writer.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/model_pin.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/overrides.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/plan_resolution.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/prev_sessions.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/rewind.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/shadow_curation.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/store.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/validation.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/worktree/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/worktree/cleanup.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/worktree/config_copy.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/session/worktree/create.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/sidecar/__init__.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/sidecar/container.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/forge/sidecar/docker.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/analyze/SKILL.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/consensus/resources/synthesis.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/SKILL.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/10-resume.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/12-search.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/13-policy.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/16-memory.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/20-cleanup.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/3-authentication.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/5-session.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/7-costs.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/8-status-line.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/checklist/9-direct-commands.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/resources/report-template.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/qa/scripts/walkthrough-state.py +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/references/claude-4.6.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/references/claude-4.8.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/references/gemini-3.1.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/references/gpt-5.5.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review/resources/code.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/review-docs/resources/docs.md +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
- {multi_forge-0.8.1 → multi_forge-0.9.0}/src/skills/walkthrough/scripts/walkthrough-state.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multi-forge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.9.0
|
|
4
4
|
Summary: Multi-runtime agent toolkit: proxy routing, cost control, session management, policy enforcement, and workflow orchestration
|
|
5
5
|
Project-URL: Homepage, https://github.com/hapa1i/multi-forge
|
|
6
6
|
Project-URL: Repository, https://github.com/hapa1i/multi-forge
|
|
@@ -39,7 +39,12 @@ from forge.install.hook_migration import (
|
|
|
39
39
|
plan_project_hook_migration,
|
|
40
40
|
)
|
|
41
41
|
from forge.install.hooks import diagnose_forge_hook_runtime
|
|
42
|
-
from forge.install.installer import
|
|
42
|
+
from forge.install.installer import (
|
|
43
|
+
Installer,
|
|
44
|
+
find_claude_root,
|
|
45
|
+
find_forge_installation,
|
|
46
|
+
inspect_skill_package_status,
|
|
47
|
+
)
|
|
43
48
|
from forge.install.models import (
|
|
44
49
|
FILE_MODULES,
|
|
45
50
|
PROFILE_RANK,
|
|
@@ -61,6 +66,13 @@ from forge.install.tracking import TrackingStore
|
|
|
61
66
|
console = Console()
|
|
62
67
|
_log = logging.getLogger(__name__)
|
|
63
68
|
_INSTALL_SCOPE_HELP = "Installation scope: local (gitignored), project (committed), user (global)"
|
|
69
|
+
_SKILL_RUNTIME_IDS = {"claude": "claude_code", "codex": "codex"}
|
|
70
|
+
_NON_FORCEABLE_SKILL_CONFLICT_REASONS = {
|
|
71
|
+
"duplicate_scan_chain",
|
|
72
|
+
"forge_managed_scope_duplicate",
|
|
73
|
+
"runtime_unavailable",
|
|
74
|
+
"scope_unsupported",
|
|
75
|
+
}
|
|
64
76
|
|
|
65
77
|
|
|
66
78
|
def _detect_git_project_root(start: Path | None = None) -> Path | None:
|
|
@@ -103,6 +115,51 @@ def _parse_modules(modules_str: str | None) -> set[InstallModule] | None:
|
|
|
103
115
|
return {InstallModule(m.strip()) for m in modules_str.split(",")}
|
|
104
116
|
|
|
105
117
|
|
|
118
|
+
def _parse_skill_runtimes(values: tuple[str, ...]) -> tuple[str, ...] | None:
|
|
119
|
+
"""Map repeatable CLI runtime names to stable runtime registry ids."""
|
|
120
|
+
|
|
121
|
+
if not values:
|
|
122
|
+
return None
|
|
123
|
+
selected: set[str] = set()
|
|
124
|
+
for value in values:
|
|
125
|
+
if value == "all":
|
|
126
|
+
selected.update(_SKILL_RUNTIME_IDS.values())
|
|
127
|
+
else:
|
|
128
|
+
selected.add(_SKILL_RUNTIME_IDS[value])
|
|
129
|
+
return tuple(runtime for runtime in _SKILL_RUNTIME_IDS.values() if runtime in selected)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _enforce_claude_version_if_required(plan: InstallPlan, project_root: Path | None = None) -> None:
|
|
133
|
+
"""Apply the Claude CLI gate only when the plan mutates Claude surfaces."""
|
|
134
|
+
|
|
135
|
+
if not plan.requires_claude_version:
|
|
136
|
+
return
|
|
137
|
+
from forge.install.version import check_minimum_version
|
|
138
|
+
|
|
139
|
+
version_check = check_minimum_version()
|
|
140
|
+
if not version_check.ok:
|
|
141
|
+
print_error(f"{version_check.reason}")
|
|
142
|
+
codex_packages_selected = any(
|
|
143
|
+
package.runtime == _SKILL_RUNTIME_IDS["codex"] and package.action in {"install", "update"}
|
|
144
|
+
for package in plan.skill_packages
|
|
145
|
+
)
|
|
146
|
+
if version_check.version is None and codex_packages_selected:
|
|
147
|
+
root_option = f" --root {shlex.quote(str(project_root))}" if project_root is not None else ""
|
|
148
|
+
command = (
|
|
149
|
+
f"forge extension enable --scope {plan.scope}{root_option} --profile minimal "
|
|
150
|
+
"--with skills --without commands --runtime codex"
|
|
151
|
+
)
|
|
152
|
+
print_tip(
|
|
153
|
+
f"Install Claude Code, or install only Codex skills with '{command}'.",
|
|
154
|
+
console=console,
|
|
155
|
+
)
|
|
156
|
+
elif version_check.version is None:
|
|
157
|
+
print_tip("Install Claude Code, then retry.", console=console)
|
|
158
|
+
else:
|
|
159
|
+
print_tip("Run 'claude update' to upgrade.", console=console)
|
|
160
|
+
raise click.exceptions.Exit(1)
|
|
161
|
+
|
|
162
|
+
|
|
106
163
|
def _count_actions(plan: InstallPlan) -> tuple[int, int, int]:
|
|
107
164
|
"""Count non-skip actions in a plan.
|
|
108
165
|
|
|
@@ -218,11 +275,12 @@ def _print_completion_message(
|
|
|
218
275
|
parts.append("Codex hooks")
|
|
219
276
|
console.print(f"\n[green]Extensions enabled.[/green] ({', '.join(parts)} updated)")
|
|
220
277
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
278
|
+
if InstallModule.PERMISSIONS.value in plan.modules:
|
|
279
|
+
print_tip(
|
|
280
|
+
"Run 'forge claude preset edit' to customize permissions and env vars.",
|
|
281
|
+
blank_before=False,
|
|
282
|
+
console=console,
|
|
283
|
+
)
|
|
226
284
|
|
|
227
285
|
if InstallModule.SKILLS.value in plan.modules:
|
|
228
286
|
print_tip(
|
|
@@ -355,7 +413,10 @@ def _print_hook_migration_plan(plan: ProjectHookMigrationPlan) -> None:
|
|
|
355
413
|
for settings_plan in (plan.user.settings, plan.user.legacy_settings):
|
|
356
414
|
if settings_plan.changed:
|
|
357
415
|
console.print(f" - {display_path(settings_plan.path)}: update user runtime hooks; backup first")
|
|
358
|
-
if plan.user.codex is not None and plan.user.codex.action in {
|
|
416
|
+
if plan.user.codex is not None and plan.user.codex.action in {
|
|
417
|
+
"install",
|
|
418
|
+
"update",
|
|
419
|
+
}:
|
|
359
420
|
console.print(f" - {display_path(plan.user.codex.config_path)}: install/update user Codex hooks")
|
|
360
421
|
if plan.user.settings.added_path is not None:
|
|
361
422
|
console.print(
|
|
@@ -472,6 +533,35 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
|
|
|
472
533
|
console.print(f" Profile: {plan.profile}")
|
|
473
534
|
console.print(f" Modules: {', '.join(plan.modules)}")
|
|
474
535
|
|
|
536
|
+
if plan.skill_packages:
|
|
537
|
+
console.print(f"\n{prefix}[bold]Skill packages:[/bold]")
|
|
538
|
+
table = Table(show_header=True, header_style="bold", box=None)
|
|
539
|
+
table.add_column("ACTION", style="dim")
|
|
540
|
+
table.add_column("RUNTIME")
|
|
541
|
+
table.add_column("SKILL")
|
|
542
|
+
table.add_column("TARGET")
|
|
543
|
+
table.add_column("REASON", style="dim")
|
|
544
|
+
for package in plan.skill_packages:
|
|
545
|
+
style = {
|
|
546
|
+
"install": "green",
|
|
547
|
+
"update": "yellow",
|
|
548
|
+
"skip": "dim",
|
|
549
|
+
"conflict": "red",
|
|
550
|
+
}.get(package.action, "")
|
|
551
|
+
reason = package.reason or ""
|
|
552
|
+
if package.duplicate_dirs:
|
|
553
|
+
duplicates = ", ".join(display_path(path) for path in package.duplicate_dirs)
|
|
554
|
+
reason = f"{reason}; duplicates: {duplicates}" if reason else f"duplicates: {duplicates}"
|
|
555
|
+
table.add_row(
|
|
556
|
+
package.action,
|
|
557
|
+
package.runtime,
|
|
558
|
+
package.skill,
|
|
559
|
+
display_path(package.target_dir) if package.target_dir else "",
|
|
560
|
+
reason,
|
|
561
|
+
style=style,
|
|
562
|
+
)
|
|
563
|
+
console.print(table)
|
|
564
|
+
|
|
475
565
|
if plan.files:
|
|
476
566
|
console.print(f"\n{prefix}[bold]Files:[/bold]")
|
|
477
567
|
table = Table(show_header=True, header_style="bold", box=None)
|
|
@@ -527,7 +617,26 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
|
|
|
527
617
|
console.print(f"\n{prefix}[bold red]Conflicts detected:[/bold red]")
|
|
528
618
|
for c in plan.conflicts:
|
|
529
619
|
console.print(f" [red]- {c}[/red]")
|
|
530
|
-
|
|
620
|
+
has_policy_conflicts = any(
|
|
621
|
+
package.action == "conflict" and package.reason in _NON_FORCEABLE_SKILL_CONFLICT_REASONS
|
|
622
|
+
for package in plan.skill_packages
|
|
623
|
+
)
|
|
624
|
+
has_forceable_conflicts = any(file.action == "conflict" for file in plan.files) or any(
|
|
625
|
+
setting.action == "conflict" for setting in plan.settings
|
|
626
|
+
)
|
|
627
|
+
if has_policy_conflicts and has_forceable_conflicts:
|
|
628
|
+
print_tip(
|
|
629
|
+
"Use --force only for file or settings conflicts; resolve runtime, scope, "
|
|
630
|
+
"and duplicate-scan conflicts manually.",
|
|
631
|
+
console=console,
|
|
632
|
+
)
|
|
633
|
+
elif has_policy_conflicts:
|
|
634
|
+
print_tip(
|
|
635
|
+
"Resolve runtime, scope, or duplicate-scan conflicts manually; --force does not override them.",
|
|
636
|
+
console=console,
|
|
637
|
+
)
|
|
638
|
+
else:
|
|
639
|
+
print_tip("Use --force to override, or resolve conflicts manually.", console=console)
|
|
531
640
|
|
|
532
641
|
|
|
533
642
|
def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
@@ -550,6 +659,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
|
550
659
|
table.add_column("PROJECT PATH")
|
|
551
660
|
table.add_column("PROFILE")
|
|
552
661
|
table.add_column("FILES")
|
|
662
|
+
table.add_column("SKILL PACKAGES")
|
|
553
663
|
|
|
554
664
|
for scope, project_path, installation in installations:
|
|
555
665
|
scope_display = scope
|
|
@@ -561,6 +671,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
|
561
671
|
path_display,
|
|
562
672
|
installation.profile,
|
|
563
673
|
str(len(installation.files)),
|
|
674
|
+
str(len(installation.skill_packages)),
|
|
564
675
|
)
|
|
565
676
|
|
|
566
677
|
console.print(table)
|
|
@@ -589,7 +700,10 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
|
589
700
|
installer.uninstall()
|
|
590
701
|
console.print(" [green]✓ Done[/green]")
|
|
591
702
|
|
|
592
|
-
except
|
|
703
|
+
except Exception as e:
|
|
704
|
+
# ``--all`` is a batch boundary: one filesystem, settings, or
|
|
705
|
+
# tracking failure must not prevent later installations from being
|
|
706
|
+
# attempted. KeyboardInterrupt/SystemExit remain uncaught.
|
|
593
707
|
console.print(f" [red]✗ Failed: {e}[/red]")
|
|
594
708
|
errors.append((scope, project_path, str(e)))
|
|
595
709
|
|
|
@@ -598,6 +712,7 @@ def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
|
598
712
|
console.print(f"[yellow]Completed with {len(errors)} error(s).[/yellow]")
|
|
599
713
|
for scope, path, err in errors:
|
|
600
714
|
console.print(f" [red]- {scope} ({display_path(path) if path else 'global'}): {err}[/red]")
|
|
715
|
+
raise click.exceptions.Exit(1)
|
|
601
716
|
else:
|
|
602
717
|
console.print(f"[green]All {len(installations)} installation(s) disabled.[/green]")
|
|
603
718
|
|
|
@@ -611,6 +726,19 @@ def _can_resolve_project_root(scope: InstallScope, *, anchor: Path | None = None
|
|
|
611
726
|
return False
|
|
612
727
|
|
|
613
728
|
|
|
729
|
+
def _resolve_status_project_root(scope: InstallScope, anchor: Path | None) -> Path | None:
|
|
730
|
+
"""Resolve a status lookup root, including tracked installs without ``.claude``."""
|
|
731
|
+
|
|
732
|
+
try:
|
|
733
|
+
return _resolve_project_root(scope, anchor=anchor)
|
|
734
|
+
except NoClaudeDirectoryError:
|
|
735
|
+
try:
|
|
736
|
+
detected_scope, detected_root = find_forge_installation(start=anchor)
|
|
737
|
+
except NoForgeInstallationError:
|
|
738
|
+
return None
|
|
739
|
+
return detected_root if detected_scope == scope else None
|
|
740
|
+
|
|
741
|
+
|
|
614
742
|
# --- Commands ---
|
|
615
743
|
|
|
616
744
|
|
|
@@ -676,6 +804,13 @@ def extensions() -> None:
|
|
|
676
804
|
"without_modules",
|
|
677
805
|
help="Remove modules (comma-separated)",
|
|
678
806
|
)
|
|
807
|
+
@click.option(
|
|
808
|
+
"--runtime",
|
|
809
|
+
"runtimes",
|
|
810
|
+
type=click.Choice(["claude", "codex", "all"]),
|
|
811
|
+
multiple=True,
|
|
812
|
+
help="Skill runtime target; repeat for multiple targets (default: Claude plus detected Codex)",
|
|
813
|
+
)
|
|
679
814
|
@click.option("--force", "-f", is_flag=True, help="Override conflicts")
|
|
680
815
|
@click.option("--dry-run", "-n", is_flag=True, help="Show plan without executing")
|
|
681
816
|
def enable_cmd(
|
|
@@ -685,6 +820,7 @@ def enable_cmd(
|
|
|
685
820
|
mode: str,
|
|
686
821
|
with_modules: str | None,
|
|
687
822
|
without_modules: str | None,
|
|
823
|
+
runtimes: tuple[str, ...],
|
|
688
824
|
force: bool,
|
|
689
825
|
dry_run: bool,
|
|
690
826
|
) -> None:
|
|
@@ -706,18 +842,11 @@ def enable_cmd(
|
|
|
706
842
|
forge extension enable --root /repo/api # Same (defaults to local)
|
|
707
843
|
forge extension enable --scope user # Global ~/.claude
|
|
708
844
|
forge extension enable --profile minimal # Commands only
|
|
845
|
+
forge extension enable --runtime codex # Target skill packages at Codex
|
|
846
|
+
forge extension enable --runtime claude --runtime codex
|
|
709
847
|
forge extension enable --dry-run # Preview changes
|
|
710
848
|
"""
|
|
711
849
|
try:
|
|
712
|
-
# Check Claude Code minimum version (hard-block: reject over warn)
|
|
713
|
-
from forge.install.version import check_minimum_version
|
|
714
|
-
|
|
715
|
-
version_check = check_minimum_version()
|
|
716
|
-
if not version_check.ok:
|
|
717
|
-
print_error(f"{version_check.reason}")
|
|
718
|
-
print_tip("Run 'claude update' to upgrade.", console=console)
|
|
719
|
-
sys.exit(1)
|
|
720
|
-
|
|
721
850
|
anchor = Path(path) if path else None
|
|
722
851
|
|
|
723
852
|
# Validate: --scope user + --root is contradictory
|
|
@@ -762,13 +891,6 @@ def enable_cmd(
|
|
|
762
891
|
|
|
763
892
|
_enforce_project_compatibility(project_root)
|
|
764
893
|
|
|
765
|
-
# Create .claude/ only when not dry-run
|
|
766
|
-
if needs_create and project_root is not None:
|
|
767
|
-
if dry_run:
|
|
768
|
-
console.print(f"[dim]Would create {display_path(project_root / '.claude')}[/dim]")
|
|
769
|
-
else:
|
|
770
|
-
_create_claude_dir(project_root)
|
|
771
|
-
|
|
772
894
|
# Rule 1 anchor: .forge/ is required for session start.
|
|
773
895
|
# Preview in dry-run; actual creation deferred until installer succeeds.
|
|
774
896
|
needs_forge = project_root is not None and not (project_root / ".forge").is_dir()
|
|
@@ -777,29 +899,41 @@ def enable_cmd(
|
|
|
777
899
|
|
|
778
900
|
install_profile = InstallProfile(profile)
|
|
779
901
|
install_mode = InstallMode(mode)
|
|
902
|
+
selected_runtimes = _parse_skill_runtimes(runtimes)
|
|
780
903
|
|
|
781
904
|
installer = Installer(scope=install_scope, project_root=project_root)
|
|
905
|
+
plan = installer.plan(
|
|
906
|
+
profile=install_profile,
|
|
907
|
+
mode=install_mode,
|
|
908
|
+
with_modules=_parse_modules(with_modules),
|
|
909
|
+
without_modules=_parse_modules(without_modules),
|
|
910
|
+
force=force,
|
|
911
|
+
skill_runtimes=selected_runtimes,
|
|
912
|
+
)
|
|
782
913
|
|
|
783
914
|
if dry_run:
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
mode=install_mode,
|
|
787
|
-
with_modules=_parse_modules(with_modules),
|
|
788
|
-
without_modules=_parse_modules(without_modules),
|
|
789
|
-
force=force,
|
|
790
|
-
)
|
|
915
|
+
if needs_create and project_root is not None and plan.requires_claude_version:
|
|
916
|
+
console.print(f"[dim]Would create {display_path(project_root / '.claude')}[/dim]")
|
|
791
917
|
_print_plan(plan, dry_run=True)
|
|
792
918
|
if plan.has_conflicts:
|
|
793
919
|
sys.exit(1)
|
|
794
920
|
if install_scope == InstallScope.USER:
|
|
795
921
|
_print_hook_migration_candidates()
|
|
796
922
|
else:
|
|
923
|
+
if plan.has_conflicts:
|
|
924
|
+
_print_plan(plan)
|
|
925
|
+
console.print("\n[red]Enable failed due to conflicts.[/red]")
|
|
926
|
+
sys.exit(1)
|
|
927
|
+
_enforce_claude_version_if_required(plan, project_root)
|
|
928
|
+
if needs_create and project_root is not None and plan.requires_claude_version:
|
|
929
|
+
_create_claude_dir(project_root)
|
|
797
930
|
plan = installer.init(
|
|
798
931
|
profile=install_profile,
|
|
799
932
|
mode=install_mode,
|
|
800
933
|
with_modules=_parse_modules(with_modules),
|
|
801
934
|
without_modules=_parse_modules(without_modules),
|
|
802
935
|
force=force,
|
|
936
|
+
skill_runtimes=selected_runtimes,
|
|
803
937
|
)
|
|
804
938
|
_print_plan(plan)
|
|
805
939
|
if plan.has_conflicts:
|
|
@@ -856,8 +990,9 @@ def sync_cmd(scope: str | None, force: bool) -> None:
|
|
|
856
990
|
|
|
857
991
|
\b
|
|
858
992
|
Scope Detection (when no --scope specified):
|
|
859
|
-
Walks up from current directory looking for existing Forge extensions
|
|
860
|
-
|
|
993
|
+
Walks up from current directory looking for existing Forge extensions,
|
|
994
|
+
using .claude/ ownership sidecars and exact scope/path tracking rows in
|
|
995
|
+
~/.forge/installed.json.
|
|
861
996
|
- Checks LOCAL first, then PROJECT, then USER
|
|
862
997
|
- Fails if no extensions found
|
|
863
998
|
|
|
@@ -868,26 +1003,28 @@ def sync_cmd(scope: str | None, force: bool) -> None:
|
|
|
868
1003
|
forge extension sync --force # Force re-sync
|
|
869
1004
|
"""
|
|
870
1005
|
try:
|
|
871
|
-
# Check Claude Code minimum version (same gate as enable)
|
|
872
|
-
from forge.install.version import check_minimum_version
|
|
873
|
-
|
|
874
|
-
version_check = check_minimum_version()
|
|
875
|
-
if not version_check.ok:
|
|
876
|
-
print_error(f"{version_check.reason}")
|
|
877
|
-
print_tip("Run 'claude update' to upgrade.", console=console)
|
|
878
|
-
sys.exit(1)
|
|
879
|
-
|
|
880
1006
|
if scope is None:
|
|
881
1007
|
install_scope, project_root = find_forge_installation()
|
|
882
1008
|
console.print(f"[dim]Auto-detected scope: {install_scope.value}[/dim]")
|
|
883
1009
|
else:
|
|
884
1010
|
install_scope = InstallScope(scope)
|
|
885
|
-
|
|
886
|
-
|
|
1011
|
+
try:
|
|
1012
|
+
project_root = _resolve_project_root(install_scope)
|
|
1013
|
+
except NoClaudeDirectoryError:
|
|
1014
|
+
detected_scope, detected_root = find_forge_installation()
|
|
1015
|
+
if detected_scope != install_scope:
|
|
1016
|
+
raise NotInstalledError(install_scope.value) from None
|
|
1017
|
+
project_root = detected_root
|
|
887
1018
|
|
|
888
1019
|
_enforce_project_compatibility(project_root)
|
|
889
1020
|
|
|
890
1021
|
installer = Installer(scope=install_scope, project_root=project_root)
|
|
1022
|
+
preview = installer.plan_update(force=force)
|
|
1023
|
+
if preview.has_conflicts:
|
|
1024
|
+
_print_plan(preview)
|
|
1025
|
+
console.print("\n[red]Sync failed due to conflicts.[/red]")
|
|
1026
|
+
sys.exit(1)
|
|
1027
|
+
_enforce_claude_version_if_required(preview, project_root)
|
|
891
1028
|
plan = installer.update(force=force)
|
|
892
1029
|
|
|
893
1030
|
_print_plan(plan)
|
|
@@ -1028,8 +1165,9 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
|
|
|
1028
1165
|
|
|
1029
1166
|
\b
|
|
1030
1167
|
Scope Detection (when no --scope/--all specified):
|
|
1031
|
-
Walks up from current directory looking for existing Forge extensions
|
|
1032
|
-
|
|
1168
|
+
Walks up from current directory looking for existing Forge extensions,
|
|
1169
|
+
using .claude/ ownership sidecars and exact scope/path tracking rows in
|
|
1170
|
+
~/.forge/installed.json.
|
|
1033
1171
|
- Checks LOCAL first, then PROJECT, then USER
|
|
1034
1172
|
- Fails if no extensions found
|
|
1035
1173
|
|
|
@@ -1058,8 +1196,13 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
|
|
|
1058
1196
|
console.print(f"[dim]Auto-detected scope: {install_scope.value}[/dim]")
|
|
1059
1197
|
else:
|
|
1060
1198
|
install_scope = InstallScope(scope)
|
|
1061
|
-
|
|
1062
|
-
|
|
1199
|
+
try:
|
|
1200
|
+
project_root = _resolve_project_root(install_scope)
|
|
1201
|
+
except NoClaudeDirectoryError:
|
|
1202
|
+
detected_scope, detected_root = find_forge_installation()
|
|
1203
|
+
if detected_scope != install_scope:
|
|
1204
|
+
raise NoForgeInstallationError(str(Path.cwd())) from None
|
|
1205
|
+
project_root = detected_root
|
|
1063
1206
|
|
|
1064
1207
|
_enforce_project_compatibility(project_root)
|
|
1065
1208
|
|
|
@@ -1075,6 +1218,23 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool) -> None:
|
|
|
1075
1218
|
console.print(f" Mode: {existing.mode}")
|
|
1076
1219
|
console.print()
|
|
1077
1220
|
|
|
1221
|
+
if existing.skill_packages:
|
|
1222
|
+
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
|
|
1223
|
+
table.add_column("ACTION", style="red")
|
|
1224
|
+
table.add_column("RUNTIME")
|
|
1225
|
+
table.add_column("SKILL")
|
|
1226
|
+
table.add_column("TARGET")
|
|
1227
|
+
for package in existing.skill_packages:
|
|
1228
|
+
table.add_row(
|
|
1229
|
+
"remove",
|
|
1230
|
+
package.runtime,
|
|
1231
|
+
package.skill,
|
|
1232
|
+
display_path(package.target_dir),
|
|
1233
|
+
)
|
|
1234
|
+
console.print("[bold]Skill packages:[/bold]")
|
|
1235
|
+
console.print(table)
|
|
1236
|
+
console.print()
|
|
1237
|
+
|
|
1078
1238
|
if existing.files:
|
|
1079
1239
|
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
|
|
1080
1240
|
table.add_column("ACTION", style="red")
|
|
@@ -1159,8 +1319,9 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1159
1319
|
|
|
1160
1320
|
\b
|
|
1161
1321
|
Scope Detection (when no --scope/--all specified):
|
|
1162
|
-
Walks up from current directory looking for existing Forge installations
|
|
1163
|
-
|
|
1322
|
+
Walks up from current directory looking for existing Forge installations,
|
|
1323
|
+
using .claude/ ownership sidecars and exact scope/path tracking rows in
|
|
1324
|
+
~/.forge/installed.json.
|
|
1164
1325
|
- Checks LOCAL first, then PROJECT, then USER
|
|
1165
1326
|
- If no installation found, shows all scopes for informational purposes
|
|
1166
1327
|
|
|
@@ -1185,7 +1346,11 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1185
1346
|
# A corrupt installed.json raises TrackingCorruptedError (a StateCorruptedError);
|
|
1186
1347
|
# it propagates to the top-level handler for the uniform reset tip.
|
|
1187
1348
|
tracking = TrackingStore()
|
|
1188
|
-
tracking.
|
|
1349
|
+
tracked_installations = tracking.list_installations()
|
|
1350
|
+
installations_by_target = {
|
|
1351
|
+
(tracked_scope, project_path): installation
|
|
1352
|
+
for tracked_scope, project_path, installation in tracked_installations
|
|
1353
|
+
}
|
|
1189
1354
|
|
|
1190
1355
|
cwd = os.getcwd()
|
|
1191
1356
|
|
|
@@ -1222,15 +1387,18 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1222
1387
|
|
|
1223
1388
|
data = []
|
|
1224
1389
|
for s in scopes:
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
project_path_str = str(project_root) if project_root else None
|
|
1228
|
-
except NoClaudeDirectoryError:
|
|
1229
|
-
project_path_str = None
|
|
1390
|
+
project_root = _resolve_status_project_root(s, effective_anchor)
|
|
1391
|
+
project_path_str = str(project_root) if project_root else None
|
|
1230
1392
|
|
|
1231
|
-
inst =
|
|
1393
|
+
inst = installations_by_target.get((s.value, project_path_str))
|
|
1232
1394
|
if inst is None:
|
|
1233
1395
|
continue
|
|
1396
|
+
package_statuses = inspect_skill_package_status(
|
|
1397
|
+
inst,
|
|
1398
|
+
s,
|
|
1399
|
+
project_root,
|
|
1400
|
+
tracked_installations=tracked_installations,
|
|
1401
|
+
)
|
|
1234
1402
|
data.append(
|
|
1235
1403
|
{
|
|
1236
1404
|
"scope": s.value,
|
|
@@ -1238,6 +1406,20 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1238
1406
|
"mode": inst.mode,
|
|
1239
1407
|
"modules": list(inst.modules_enabled),
|
|
1240
1408
|
"files_count": len(inst.files),
|
|
1409
|
+
"skill_packages": [
|
|
1410
|
+
{
|
|
1411
|
+
"runtime": package_status.runtime,
|
|
1412
|
+
"skill": package_status.skill,
|
|
1413
|
+
"target_dir": package_status.target_dir,
|
|
1414
|
+
"file_paths": list(package_status.file_paths),
|
|
1415
|
+
"state": package_status.state,
|
|
1416
|
+
"target_present": package_status.target_present,
|
|
1417
|
+
"missing_file_paths": list(package_status.missing_file_paths),
|
|
1418
|
+
"duplicate_dirs": list(package_status.duplicate_dirs),
|
|
1419
|
+
"recovery": package_status.recovery,
|
|
1420
|
+
}
|
|
1421
|
+
for package_status in package_statuses
|
|
1422
|
+
],
|
|
1241
1423
|
"settings_count": len(inst.settings_entries),
|
|
1242
1424
|
"codex_config_path": inst.codex_config_path,
|
|
1243
1425
|
"codex_commands": list(inst.codex_commands),
|
|
@@ -1256,13 +1438,10 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1256
1438
|
console.print("[dim]Showing all scopes for this location:[/dim]")
|
|
1257
1439
|
|
|
1258
1440
|
for s in scopes:
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
project_path_str = str(project_root) if project_root else None
|
|
1262
|
-
except NoClaudeDirectoryError:
|
|
1263
|
-
project_path_str = None
|
|
1441
|
+
project_root = _resolve_status_project_root(s, effective_anchor)
|
|
1442
|
+
project_path_str = str(project_root) if project_root else None
|
|
1264
1443
|
|
|
1265
|
-
installation =
|
|
1444
|
+
installation = installations_by_target.get((s.value, project_path_str))
|
|
1266
1445
|
|
|
1267
1446
|
console.print(f"\n[bold]Scope: {s.value}[/bold]")
|
|
1268
1447
|
|
|
@@ -1280,12 +1459,58 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
1280
1459
|
console.print(f" Mode: {installation.mode}")
|
|
1281
1460
|
console.print(f" Modules: {', '.join(installation.modules_enabled)}")
|
|
1282
1461
|
console.print(f" Files: {len(installation.files)}")
|
|
1462
|
+
console.print(f" Skills: {len(installation.skill_packages)} runtime package(s)")
|
|
1283
1463
|
console.print(f" Settings: {len(installation.settings_entries)} entries")
|
|
1284
1464
|
if installation.codex_config_path:
|
|
1285
1465
|
console.print(f" Codex: hooks registered in {display_path(installation.codex_config_path)}")
|
|
1286
1466
|
console.print(f" Installed: {installation.installed_at}")
|
|
1287
1467
|
console.print(f" Updated: {installation.updated_at}")
|
|
1288
1468
|
|
|
1469
|
+
if installation.skill_packages:
|
|
1470
|
+
package_statuses = inspect_skill_package_status(
|
|
1471
|
+
installation,
|
|
1472
|
+
s,
|
|
1473
|
+
project_root,
|
|
1474
|
+
tracked_installations=tracked_installations,
|
|
1475
|
+
)
|
|
1476
|
+
table = Table(show_header=True, header_style="bold", box=None, padding=(0, 1))
|
|
1477
|
+
table.add_column("STATE")
|
|
1478
|
+
table.add_column("RUNTIME")
|
|
1479
|
+
table.add_column("SKILL")
|
|
1480
|
+
table.add_column("TARGET")
|
|
1481
|
+
for package_status in package_statuses:
|
|
1482
|
+
style = {
|
|
1483
|
+
"present": "green",
|
|
1484
|
+
"missing": "yellow",
|
|
1485
|
+
"duplicate": "red",
|
|
1486
|
+
"invalid-target": "red",
|
|
1487
|
+
}.get(package_status.state, "")
|
|
1488
|
+
table.add_row(
|
|
1489
|
+
package_status.state,
|
|
1490
|
+
package_status.runtime,
|
|
1491
|
+
package_status.skill,
|
|
1492
|
+
display_path(package_status.target_dir),
|
|
1493
|
+
style=style,
|
|
1494
|
+
)
|
|
1495
|
+
console.print("\n [dim]Skill packages:[/dim]")
|
|
1496
|
+
console.print(table)
|
|
1497
|
+
for package_status in package_statuses:
|
|
1498
|
+
if package_status.duplicate_dirs:
|
|
1499
|
+
console.print(
|
|
1500
|
+
f" [red]{package_status.runtime}/{package_status.skill} duplicates:[/red] "
|
|
1501
|
+
+ ", ".join(display_path(path) for path in package_status.duplicate_dirs)
|
|
1502
|
+
)
|
|
1503
|
+
if package_status.missing_file_paths:
|
|
1504
|
+
console.print(
|
|
1505
|
+
f" [yellow]{package_status.runtime}/{package_status.skill} missing files:[/yellow] "
|
|
1506
|
+
+ ", ".join(display_path(path) for path in package_status.missing_file_paths)
|
|
1507
|
+
)
|
|
1508
|
+
if package_status.recovery:
|
|
1509
|
+
console.print(
|
|
1510
|
+
f" [yellow]{package_status.runtime}/{package_status.skill}:[/yellow] "
|
|
1511
|
+
f"{package_status.recovery}"
|
|
1512
|
+
)
|
|
1513
|
+
|
|
1289
1514
|
try:
|
|
1290
1515
|
inst_profile = InstallProfile(installation.profile)
|
|
1291
1516
|
gated = get_gated_skills(inst_profile)
|