multi-forge 0.2.0__tar.gz → 0.3.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.2.0 → multi_forge-0.3.0}/PKG-INFO +18 -12
- {multi_forge-0.2.0 → multi_forge-0.3.0}/README.md +14 -8
- {multi_forge-0.2.0 → multi_forge-0.3.0}/pyproject.toml +14 -11
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/__init__.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/backend.py +22 -10
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/claude.py +9 -8
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/config_cmd.py +4 -4
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/extensions.py +25 -19
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/gc.py +2 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/guards.py +4 -3
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/handoff.py +13 -8
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/commands.py +14 -11
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/direct_commands.py +45 -44
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/policy.py +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/logs.py +35 -13
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/main.py +8 -2
- multi_forge-0.3.0/src/forge/cli/memory.py +1227 -0
- multi_forge-0.3.0/src/forge/cli/output.py +92 -0
- multi_forge-0.2.0/src/forge/cli/guard.py → multi_forge-0.3.0/src/forge/cli/policy.py +125 -139
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/proxy.py +120 -61
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/search.py +41 -15
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session.py +16 -24
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_fork.py +123 -25
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_handoff.py +9 -9
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_lifecycle.py +415 -81
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_manage.py +94 -30
- multi_forge-0.3.0/src/forge/cli/session_memory.py +36 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/workflow.py +13 -9
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/loader.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/schema.py +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/__init__.py +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/capabilities.py +4 -4
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/template_secrets.py +8 -8
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/model_catalog.yaml +2 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/__init__.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/litellm.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/openrouter.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/resolution.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/session_runner.py +9 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/tagger.py +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/throttle.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/__init__.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/__init__.py +3 -3
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/base.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/coding_standards.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/registry.py +5 -5
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/deterministic/tdd.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/engine.py +3 -3
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/protocols.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/queries.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/__init__.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/promotion.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/supervisor.py +49 -24
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/semantic/verdict.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/store.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/handlers.py +2 -2
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/branches.py +3 -3
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/divergence.py +1 -1
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/policy.py +4 -4
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/stages.py +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_orchestrator.py +92 -4
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/server.py +13 -7
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/utils.py +3 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/engine.py +4 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/effective.py +7 -3
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/exceptions.py +13 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/handoff_agent.py +120 -111
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/manager.py +36 -0
- multi_forge-0.3.0/src/forge/session/memory_inheritance.py +78 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/models.py +7 -15
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/overrides.py +1 -1
- multi_forge-0.3.0/src/forge/session/passport.py +758 -0
- multi_forge-0.3.0/src/forge/session/project_memory.py +317 -0
- multi_forge-0.3.0/src/forge/session/shadow_curation.py +320 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/store.py +32 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/validation.py +21 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/secrets.py +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/SKILL.md +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/12-search.md +3 -3
- multi_forge-0.2.0/src/skills/qa/resources/checklist/13-guard.md → multi_forge-0.3.0/src/skills/qa/resources/checklist/13-policy.md +31 -31
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/16-handoff.md +35 -47
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/9-direct-commands.md +21 -21
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist.md +10 -10
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/report-template.md +1 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/scripts/walkthrough-state.py +88 -35
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/skills-writing-guide.md +1 -1
- multi_forge-0.3.0/src/skills/review/resources/code.md +1 -0
- multi_forge-0.3.0/src/skills/review-docs/resources/docs.md +1 -0
- multi_forge-0.3.0/src/skills/understand/resources/code.md +163 -0
- multi_forge-0.3.0/src/skills/understand/resources/docs.md +177 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/SKILL.md +2 -2
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/resources/checklist.md +25 -22
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/walkthrough-state.py +88 -35
- multi_forge-0.2.0/src/forge/cli/session_memory.py +0 -201
- multi_forge-0.2.0/src/skills/review/resources/code-anthropic.md +0 -1
- multi_forge-0.2.0/src/skills/review-docs/resources/docs-anthropic.md +0 -1
- multi_forge-0.2.0/src/skills/understand/resources/code-anthropic.md +0 -1
- multi_forge-0.2.0/src/skills/understand/resources/docs-anthropic.md +0 -1
- {multi_forge-0.2.0 → multi_forge-0.3.0}/.gitignore +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/LICENSE +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/NOTICE +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/agents/.gitkeep +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/commands/.gitkeep +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/adapters/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/adapters/litellm.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/creation.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/backend/registry.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/auth.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/_group.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/_helpers.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/install.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/read_hygiene.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/hooks/verification.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/proxy_costs.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/session_addendum.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/cli/status_line.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/dataclass_utils.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/backends/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/backends/litellm.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-anthropic-local.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-anthropic.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-flash-local.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-local.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini-test.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-gemini.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai-codex-local.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai-local.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/litellm-openai.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-anthropic.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-deepseek.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-gemini-flash.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-gemini.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-glm.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-kimi.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-minimax.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-openai-codex.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-openai.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/config/defaults/templates/openrouter-qwen.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/credentials_file.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/protocols.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/auth/secrets.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/pricing.yaml +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/gemini.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/data/system_prompt_addendums/openai.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/base.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/clients/openai_compat.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/credentials.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/detection.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/errors.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/protocols.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/llm/types.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/logging.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/catalog.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/pricing.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/models/types.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/naming.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/context.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/gc.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/proxy.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/session.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/ops/session_context.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/paths.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/process.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/cost_tracking.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/env.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/proxy.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/routing.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/reactive/structured_output.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/exceptions.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/io.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/lock.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/state/timestamps.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/transcript.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/typing_helpers.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/queue.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/core/workqueue/types.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/cli.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/exceptions.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/hooks.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/installer.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/models.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/preset.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/settings_merge.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/tracking.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/install/version.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/__init__.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/config.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/team/prompts.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/types.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/__init__.py +0 -0
- {multi_forge-0.2.0/src/forge/guard → multi_forge-0.3.0/src/forge/policy}/workflow/config.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/base_client.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/client_adapter.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/client_factory.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/converters.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/cost_logger.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/cost_tracker.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/data_models.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/error_hints.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/metrics.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/model_spec.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxies.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_identity.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/proxy/proxy_startup.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/adversarial.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/consensus.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/models.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-performance.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-quick.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview-security.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/codereview.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/docreview-quick.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/docreview.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/resources/thinkdeep.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/routing.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/review/synthesis.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/runtime_config.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/bm25_store.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/content_store.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/engine.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/exceptions.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/extractor.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/index_state.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/store.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/search/tokenizer.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/active.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/artifacts.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/cleanup.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/invoke.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/claude/paths.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/cleanup.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/config.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/direct_model.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/handoff.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/models.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/hooks/session_start.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/identity.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/index.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/plan_resolution.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/prev_sessions.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/cleanup.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/config_copy.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/session/worktree/create.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/__init__.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/container.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/forge/sidecar/docker.py +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/analyze/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/challenge/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/code_consensus_evaluation.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/consensus_evaluation.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/consensus/resources/synthesis.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/resources/code_debate_evaluation.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/debate/resources/debate_evaluation.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/panel/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/panel/resources/synthesis.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/0-enable.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/1-preflight.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/10-resume.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/11-config.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/14-workflow.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/15-skills.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/17-info.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/18-disable.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/19-uninstall.md +0 -0
- /multi_forge-0.2.0/src/skills/qa/resources/checklist/2-extensions.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/2-extension.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/20-cleanup.md +0 -0
- /multi_forge-0.2.0/src/skills/qa/resources/checklist/3-auth.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/3-authentication.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/4-proxy.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/5-session.md +0 -0
- /multi_forge-0.2.0/src/skills/qa/resources/checklist/6-hooks.md → /multi_forge-0.3.0/src/skills/qa/resources/checklist/6-hook.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/7-costs.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/resources/checklist/8-status-line.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/qa/scripts/start-container.sh +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/claude-4.6.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/claude-4.7.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/gemini-3.1.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/references/gpt-5.5.md +0 -0
- /multi_forge-0.2.0/src/skills/review/resources/code.md → /multi_forge-0.3.0/src/skills/review/resources/code-anthropic.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/resources/code-gemini.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review/resources/code-openai.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/SKILL.md +0 -0
- /multi_forge-0.2.0/src/skills/review-docs/resources/docs.md → /multi_forge-0.3.0/src/skills/review-docs/resources/docs-anthropic.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/resources/docs-gemini.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/review-docs/resources/docs-openai.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/smoke-test/SKILL.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/smoke-test/scripts/smoke-test.sh +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/SKILL.md +0 -0
- /multi_forge-0.2.0/src/skills/understand/resources/code.md → /multi_forge-0.3.0/src/skills/understand/resources/code-anthropic.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/code-gemini.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/code-openai.md +0 -0
- /multi_forge-0.2.0/src/skills/understand/resources/docs.md → /multi_forge-0.3.0/src/skills/understand/resources/docs-anthropic.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/docs-gemini.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/understand/resources/docs-openai.md +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/run-in-repo.sh +0 -0
- {multi_forge-0.2.0 → multi_forge-0.3.0}/src/skills/walkthrough/scripts/setup-test-repo.sh +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: multi-forge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.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
|
|
@@ -24,15 +24,15 @@ Requires-Python: <3.14,>=3.11
|
|
|
24
24
|
Requires-Dist: click>=8.3.1
|
|
25
25
|
Requires-Dist: coolname<6,>=5.0.0
|
|
26
26
|
Requires-Dist: dacite>=1.8.0
|
|
27
|
-
Requires-Dist: fastapi>=0.115.
|
|
27
|
+
Requires-Dist: fastapi>=0.115.14
|
|
28
28
|
Requires-Dist: httpx>=0.25.0
|
|
29
|
-
Requires-Dist: litellm[proxy]>=1.
|
|
29
|
+
Requires-Dist: litellm[proxy]>=1.85.0
|
|
30
30
|
Requires-Dist: openai>=1.0.0
|
|
31
31
|
Requires-Dist: packaging>=21.0
|
|
32
32
|
Requires-Dist: pydantic>=2.0.0
|
|
33
33
|
Requires-Dist: python-dotenv>=1.2.2
|
|
34
34
|
Requires-Dist: pyyaml>=6.0.0
|
|
35
|
-
Requires-Dist: rich>=13.
|
|
35
|
+
Requires-Dist: rich>=13.9.0
|
|
36
36
|
Requires-Dist: ruamel-yaml>=0.18.0
|
|
37
37
|
Requires-Dist: tenacity>=8.0.0
|
|
38
38
|
Requires-Dist: uvicorn>=0.31.1
|
|
@@ -41,8 +41,13 @@ Description-Content-Type: text/markdown
|
|
|
41
41
|
|
|
42
42
|
# Multi-Forge
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
<p align="left">
|
|
45
|
+
<img src="assets/logo.jpg" alt="Dusk" width=320">
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
[](https://pypi.org/project/multi-forge/)
|
|
49
|
+
[](https://pypi.org/project/multi-forge/)
|
|
50
|
+
[](LICENSE)
|
|
46
51
|
|
|
47
52
|
> [!WARNING]
|
|
48
53
|
> **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
|
|
@@ -206,7 +211,7 @@ inside Claude Code for an interactive walkthrough.
|
|
|
206
211
|
| `forge session` | Named sessions, worktrees, resume, fork |
|
|
207
212
|
| `forge proxy` | Model routing, templates, tier mappings |
|
|
208
213
|
| `forge authentication` | Credential management (`credentials.yaml`) |
|
|
209
|
-
| `forge
|
|
214
|
+
| `forge policy` | Policy enforcement, plan supervision |
|
|
210
215
|
| `forge workflow` | Workflow runners (panel, analyze, debate) |
|
|
211
216
|
| `forge search` | Transcript search across sessions |
|
|
212
217
|
| `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
|
|
@@ -217,11 +222,12 @@ Run `forge <command> --help` for details on any command.
|
|
|
217
222
|
|
|
218
223
|
## Documentation
|
|
219
224
|
|
|
220
|
-
| Audience | Location | Contents
|
|
221
|
-
| ---------------- | ---------------------------------- |
|
|
222
|
-
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ...
|
|
223
|
-
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines
|
|
224
|
-
| **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants
|
|
225
|
+
| Audience | Location | Contents |
|
|
226
|
+
| ---------------- | ---------------------------------- | ---------------------------------------------------- |
|
|
227
|
+
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
|
|
228
|
+
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
|
|
229
|
+
| **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
|
|
230
|
+
| **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
|
|
225
231
|
|
|
226
232
|
## Contributing
|
|
227
233
|
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
# Multi-Forge
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
<p align="left">
|
|
4
|
+
<img src="assets/logo.jpg" alt="Dusk" width=320">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
[](https://pypi.org/project/multi-forge/)
|
|
8
|
+
[](https://pypi.org/project/multi-forge/)
|
|
9
|
+
[](LICENSE)
|
|
5
10
|
|
|
6
11
|
> [!WARNING]
|
|
7
12
|
> **Research Preview** -- Forge is under active development. APIs, commands, and file formats may change without notice
|
|
@@ -165,7 +170,7 @@ inside Claude Code for an interactive walkthrough.
|
|
|
165
170
|
| `forge session` | Named sessions, worktrees, resume, fork |
|
|
166
171
|
| `forge proxy` | Model routing, templates, tier mappings |
|
|
167
172
|
| `forge authentication` | Credential management (`credentials.yaml`) |
|
|
168
|
-
| `forge
|
|
173
|
+
| `forge policy` | Policy enforcement, plan supervision |
|
|
169
174
|
| `forge workflow` | Workflow runners (panel, analyze, debate) |
|
|
170
175
|
| `forge search` | Transcript search across sessions |
|
|
171
176
|
| `forge config` | Runtime preferences (`~/.forge/config.yaml`) |
|
|
@@ -176,11 +181,12 @@ Run `forge <command> --help` for details on any command.
|
|
|
176
181
|
|
|
177
182
|
## Documentation
|
|
178
183
|
|
|
179
|
-
| Audience | Location | Contents
|
|
180
|
-
| ---------------- | ---------------------------------- |
|
|
181
|
-
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ...
|
|
182
|
-
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines
|
|
183
|
-
| **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants
|
|
184
|
+
| Audience | Location | Contents |
|
|
185
|
+
| ---------------- | ---------------------------------- | ---------------------------------------------------- |
|
|
186
|
+
| **Users** | [docs/end-user/](docs/end-user/) | Tour, guides for sessions, proxies, policies, ... |
|
|
187
|
+
| **Developers** | [docs/developer/](docs/developer/) | Setup, coding standards, testing guidelines |
|
|
188
|
+
| **Architecture** | [docs/design.md](docs/design.md) | System narrative, data flow, invariants |
|
|
189
|
+
| **Work Board** | [docs/board/](docs/board/) | Cards, checklists, change log, implementation memory |
|
|
184
190
|
|
|
185
191
|
## Contributing
|
|
186
192
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "multi-forge"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Multi-runtime agent toolkit: proxy routing, cost control, session management, policy enforcement, and workflow orchestration"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -28,7 +28,7 @@ dependencies = [
|
|
|
28
28
|
"dacite>=1.8.0",
|
|
29
29
|
"click>=8.3.1",
|
|
30
30
|
"coolname>=5.0.0,<6",
|
|
31
|
-
"rich>=13.
|
|
31
|
+
"rich>=13.9.0",
|
|
32
32
|
"pydantic>=2.0.0",
|
|
33
33
|
"openai>=1.0.0",
|
|
34
34
|
"httpx>=0.25.0",
|
|
@@ -41,10 +41,10 @@ dependencies = [
|
|
|
41
41
|
# Plain `fastapi` (no `[standard]` extras): Forge uses none of websockets/
|
|
42
42
|
# uvloop/httptools/multipart/jinja2. `watchfiles` is declared explicitly
|
|
43
43
|
# because Forge owns `--reload` (`forge proxy server --reload`).
|
|
44
|
-
"fastapi>=0.115.
|
|
44
|
+
"fastapi>=0.115.14",
|
|
45
45
|
"uvicorn>=0.31.1",
|
|
46
46
|
"watchfiles>=0.20",
|
|
47
|
-
"litellm[proxy]>=1.
|
|
47
|
+
"litellm[proxy]>=1.85.0",
|
|
48
48
|
]
|
|
49
49
|
|
|
50
50
|
[project.scripts]
|
|
@@ -104,9 +104,11 @@ markers = [
|
|
|
104
104
|
asyncio_mode = "auto"
|
|
105
105
|
|
|
106
106
|
[tool.mypy]
|
|
107
|
-
#
|
|
107
|
+
# Same-named standalone scripts in separate skill directories collide in mypy's
|
|
108
|
+
# module map during broad scans. Keep this exclusion local to the duplicate
|
|
109
|
+
# script name; it is not a source-of-truth relationship between the skills.
|
|
108
110
|
exclude = [
|
|
109
|
-
|
|
111
|
+
'src/skills/qa/scripts/walkthrough-state\.py$',
|
|
110
112
|
]
|
|
111
113
|
ignore_missing_imports = true
|
|
112
114
|
|
|
@@ -137,18 +139,19 @@ dev = [
|
|
|
137
139
|
"pytest-cov>=4.1.0",
|
|
138
140
|
"pytest-asyncio>=0.23.0",
|
|
139
141
|
"pytest-mock>=3.15.1",
|
|
140
|
-
"ruff>=0.
|
|
142
|
+
"ruff>=0.15.0",
|
|
143
|
+
"black>=26.5.0",
|
|
141
144
|
"mypy>=1.13.0",
|
|
142
145
|
"pyright>=1.1.0",
|
|
143
146
|
"pytest-rerunfailures>=14.0",
|
|
144
|
-
"pre-commit>=4.
|
|
147
|
+
"pre-commit>=4.5.0",
|
|
145
148
|
"types-PyYAML>=6.0.0",
|
|
146
149
|
"types-requests>=2.31.0",
|
|
147
150
|
"python-dotenv>=1.2.1",
|
|
148
151
|
]
|
|
149
152
|
provider-check = [
|
|
150
|
-
"anthropic>=0.
|
|
151
|
-
"google-genai>=2.
|
|
152
|
-
"openai>=
|
|
153
|
+
"anthropic>=0.100.0",
|
|
154
|
+
"google-genai>=2.5.0",
|
|
155
|
+
"openai>=2.0.0",
|
|
153
156
|
"tiktoken>=0.12.0",
|
|
154
157
|
]
|
|
@@ -21,6 +21,7 @@ from forge.backend import BackendManager
|
|
|
21
21
|
from forge.backend.adapters import get_adapter
|
|
22
22
|
from forge.backend.creation import create_backend_config, get_backend_config_path
|
|
23
23
|
from forge.backend.registry import BackendRegistryStore, is_pid_alive
|
|
24
|
+
from forge.cli.output import print_error_with_tip, print_tip
|
|
24
25
|
from forge.core.paths import display_path, get_forge_home
|
|
25
26
|
|
|
26
27
|
|
|
@@ -64,7 +65,7 @@ def list_cmd(as_json: bool) -> None:
|
|
|
64
65
|
|
|
65
66
|
if not backends:
|
|
66
67
|
console.print("No backends found.")
|
|
67
|
-
|
|
68
|
+
print_tip("Run 'forge backend create litellm'.", console=console)
|
|
68
69
|
return
|
|
69
70
|
|
|
70
71
|
table = Table(title="Forge Backends")
|
|
@@ -146,7 +147,7 @@ def show_cmd(backend_id: str, raw: bool) -> None:
|
|
|
146
147
|
console.print(syntax)
|
|
147
148
|
else:
|
|
148
149
|
console.print(f"\n[dim]No config found for adapter '{adapter_type}'.[/dim]")
|
|
149
|
-
|
|
150
|
+
print_tip(f"Run 'forge backend create {adapter_type}'.", blank_before=False, console=console)
|
|
150
151
|
|
|
151
152
|
|
|
152
153
|
@backend.command("create")
|
|
@@ -166,10 +167,13 @@ def create_cmd(adapter: str, config: Path | None) -> None:
|
|
|
166
167
|
|
|
167
168
|
config_path = get_backend_config_path(adapter)
|
|
168
169
|
if config_path.exists():
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
print_error_with_tip(
|
|
171
|
+
f"Backend config already exists: {display_path(config_path)}",
|
|
172
|
+
"Start an instance with:",
|
|
173
|
+
commands=[f"forge backend start {adapter} --port 4000"],
|
|
174
|
+
console=console,
|
|
175
|
+
)
|
|
176
|
+
sys.exit(1)
|
|
173
177
|
|
|
174
178
|
try:
|
|
175
179
|
config_path = create_backend_config(
|
|
@@ -194,9 +198,12 @@ def start_cmd(adapter: str, port: int) -> None:
|
|
|
194
198
|
|
|
195
199
|
config_path = get_backend_config_path(adapter)
|
|
196
200
|
if not config_path.exists():
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
print_error_with_tip(
|
|
202
|
+
f"Backend config not found for '{adapter}'",
|
|
203
|
+
"Create it first:",
|
|
204
|
+
commands=[f"forge backend create {adapter}"],
|
|
205
|
+
console=console,
|
|
206
|
+
)
|
|
200
207
|
sys.exit(1)
|
|
201
208
|
|
|
202
209
|
backend_id = f"{adapter}-{port}"
|
|
@@ -271,7 +278,12 @@ def delete_cmd(adapter: str, port: int | None, yes: bool, force: bool) -> None:
|
|
|
271
278
|
else:
|
|
272
279
|
backend_dir = get_forge_home() / "backends" / adapter
|
|
273
280
|
if not backend_dir.exists():
|
|
274
|
-
|
|
281
|
+
print_error_with_tip(
|
|
282
|
+
f"Backend config not found for '{adapter}'",
|
|
283
|
+
"Create it first:",
|
|
284
|
+
commands=[f"forge backend create {adapter}"],
|
|
285
|
+
console=console,
|
|
286
|
+
)
|
|
275
287
|
sys.exit(1)
|
|
276
288
|
|
|
277
289
|
if not yes and not click.confirm(f"Delete backend config for '{adapter}' (stops all instances)?"):
|
|
@@ -20,10 +20,9 @@ from rich.console import Console
|
|
|
20
20
|
|
|
21
21
|
from forge.core.paths import display_path
|
|
22
22
|
from forge.proxy.proxies import (
|
|
23
|
+
ProxyNotFoundError,
|
|
23
24
|
ProxyRegistryCorruptedError,
|
|
24
|
-
ProxyRegistryStore,
|
|
25
25
|
ProxyResolutionError,
|
|
26
|
-
resolve_proxy,
|
|
27
26
|
)
|
|
28
27
|
from forge.session.direct_model import apply_direct_model_env
|
|
29
28
|
|
|
@@ -208,20 +207,22 @@ def start_cmd(
|
|
|
208
207
|
proxy_display: str | None = None
|
|
209
208
|
|
|
210
209
|
if proxy_id:
|
|
211
|
-
|
|
210
|
+
from forge.proxy.proxy_orchestrator import ProxyStartError, ensure_proxy
|
|
212
211
|
|
|
213
212
|
try:
|
|
214
|
-
|
|
213
|
+
entry, started = ensure_proxy(proxy_id)
|
|
215
214
|
except ProxyRegistryCorruptedError as e:
|
|
216
215
|
click.echo(f"Error: {e}")
|
|
217
216
|
sys.exit(1)
|
|
218
|
-
|
|
219
|
-
try:
|
|
220
|
-
entry = resolve_proxy(registry, proxy_id)
|
|
221
|
-
except ProxyResolutionError as e:
|
|
217
|
+
except (ProxyResolutionError, ProxyStartError) as e:
|
|
222
218
|
click.echo(f"Error: {e}")
|
|
219
|
+
if isinstance(e, ProxyNotFoundError):
|
|
220
|
+
click.echo("Tip: Run 'forge proxy template list' to see available templates.")
|
|
223
221
|
sys.exit(1)
|
|
224
222
|
|
|
223
|
+
if started:
|
|
224
|
+
console.print(f"[dim]Started proxy '{entry.proxy_id}' from template '{proxy_id}'.[/dim]")
|
|
225
|
+
|
|
225
226
|
try:
|
|
226
227
|
_healthcheck_proxy(
|
|
227
228
|
base_url=entry.base_url,
|
|
@@ -35,23 +35,23 @@ from forge.runtime_config import (
|
|
|
35
35
|
)
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
@click.group(invoke_without_command=True)
|
|
38
|
+
@click.group(invoke_without_command=True, subcommand_metavar="[COMMAND] [ARGS]...")
|
|
39
39
|
@click.pass_context
|
|
40
40
|
def config(ctx: click.Context) -> None:
|
|
41
41
|
"""Manage Forge global configuration.
|
|
42
42
|
|
|
43
43
|
\b
|
|
44
44
|
Configuration file: ~/.forge/config.yaml
|
|
45
|
-
Auto-created with documented defaults
|
|
45
|
+
Auto-created with documented defaults by `forge config show`.
|
|
46
46
|
|
|
47
47
|
\b
|
|
48
48
|
Examples:
|
|
49
|
-
forge config
|
|
49
|
+
forge config show # Show effective config
|
|
50
50
|
forge config set proxy_mode=sidecar
|
|
51
51
|
forge config edit # Open in $EDITOR
|
|
52
52
|
"""
|
|
53
53
|
if ctx.invoked_subcommand is None:
|
|
54
|
-
ctx.
|
|
54
|
+
click.echo(ctx.get_help())
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
@config.command("show")
|
|
@@ -17,6 +17,7 @@ import click
|
|
|
17
17
|
from rich.console import Console
|
|
18
18
|
from rich.table import Table
|
|
19
19
|
|
|
20
|
+
from forge.cli.output import print_tip
|
|
20
21
|
from forge.core.paths import display_path
|
|
21
22
|
from forge.install.exceptions import (
|
|
22
23
|
ForgeInstallError,
|
|
@@ -179,11 +180,17 @@ def _print_completion_message(
|
|
|
179
180
|
parts.append(f"{settings_actions} setting{'s' if settings_actions != 1 else ''}")
|
|
180
181
|
console.print(f"\n[green]Extensions enabled.[/green] ({', '.join(parts)} updated)")
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
print_tip(
|
|
184
|
+
"Run 'forge claude preset edit' to customize permissions and env vars.",
|
|
185
|
+
blank_before=False,
|
|
186
|
+
console=console,
|
|
187
|
+
)
|
|
183
188
|
|
|
184
189
|
if InstallModule.SKILLS.value in plan.modules:
|
|
185
|
-
|
|
186
|
-
"
|
|
190
|
+
print_tip(
|
|
191
|
+
"Multi-model skills require proxy credentials. Run 'forge auth status' to check.",
|
|
192
|
+
blank_before=False,
|
|
193
|
+
console=console,
|
|
187
194
|
)
|
|
188
195
|
|
|
189
196
|
profile = InstallProfile(plan.profile)
|
|
@@ -191,7 +198,7 @@ def _print_completion_message(
|
|
|
191
198
|
if gated:
|
|
192
199
|
skill_list = ", ".join(f"/forge:{name}" for name, _ in gated)
|
|
193
200
|
required = gated[0][1].value
|
|
194
|
-
|
|
201
|
+
print_tip(f"Additional skills available with --profile {required}: {skill_list}", console=console)
|
|
195
202
|
|
|
196
203
|
|
|
197
204
|
def _validate_anchor(anchor: Path) -> None:
|
|
@@ -321,7 +328,7 @@ def _print_plan(plan: InstallPlan, dry_run: bool = False) -> None:
|
|
|
321
328
|
console.print(f"\n{prefix}[bold red]Conflicts detected:[/bold red]")
|
|
322
329
|
for c in plan.conflicts:
|
|
323
330
|
console.print(f" [red]- {c}[/red]")
|
|
324
|
-
|
|
331
|
+
print_tip("Use --force to override, or resolve conflicts manually.", console=console)
|
|
325
332
|
|
|
326
333
|
|
|
327
334
|
def _uninstall_all_installations(tracking: TrackingStore, yes: bool) -> None:
|
|
@@ -507,7 +514,7 @@ def enable_cmd(
|
|
|
507
514
|
version_check = check_minimum_version()
|
|
508
515
|
if not version_check.ok:
|
|
509
516
|
console.print(f"[red]Error:[/red] {version_check.reason}")
|
|
510
|
-
|
|
517
|
+
print_tip("Run 'claude update' to upgrade.", console=console)
|
|
511
518
|
sys.exit(1)
|
|
512
519
|
|
|
513
520
|
anchor = Path(path) if path else None
|
|
@@ -597,14 +604,13 @@ def enable_cmd(
|
|
|
597
604
|
raise
|
|
598
605
|
except NoClaudeDirectoryError as e:
|
|
599
606
|
console.print(f"[red]Error:[/red] {e}")
|
|
600
|
-
|
|
601
|
-
"
|
|
602
|
-
"or '--root <dir>' to target a specific directory.[/dim]"
|
|
607
|
+
print_tip(
|
|
608
|
+
"Use --scope user to enable globally, or --root <dir> to target a specific directory.", console=console
|
|
603
609
|
)
|
|
604
610
|
sys.exit(1)
|
|
605
611
|
except SettingsConflictError as e:
|
|
606
612
|
console.print(f"[red]Settings conflict:[/red] {e}")
|
|
607
|
-
|
|
613
|
+
print_tip("Use --force to override.", console=console)
|
|
608
614
|
sys.exit(1)
|
|
609
615
|
except ForgeInstallError as e:
|
|
610
616
|
console.print(f"[red]Error:[/red] {e}")
|
|
@@ -647,7 +653,7 @@ def sync_cmd(scope: str | None, force: bool) -> None:
|
|
|
647
653
|
version_check = check_minimum_version()
|
|
648
654
|
if not version_check.ok:
|
|
649
655
|
console.print(f"[red]Error:[/red] {version_check.reason}")
|
|
650
|
-
|
|
656
|
+
print_tip("Run 'claude update' to upgrade.", console=console)
|
|
651
657
|
sys.exit(1)
|
|
652
658
|
|
|
653
659
|
if scope is None:
|
|
@@ -683,7 +689,7 @@ def sync_cmd(scope: str | None, force: bool) -> None:
|
|
|
683
689
|
sys.exit(1)
|
|
684
690
|
except NotInstalledError as e:
|
|
685
691
|
console.print(f"[red]Error:[/red] {e}")
|
|
686
|
-
|
|
692
|
+
print_tip("Run 'forge extension enable' first.", console=console)
|
|
687
693
|
sys.exit(1)
|
|
688
694
|
except ForgeInstallError as e:
|
|
689
695
|
console.print(f"[red]Error:[/red] {e}")
|
|
@@ -809,12 +815,12 @@ def disable_cmd(scope: str | None, uninstall_all: bool, yes: bool, force: bool)
|
|
|
809
815
|
except NoForgeInstallationError as e:
|
|
810
816
|
console.print(f"[red]Error:[/red] {e}")
|
|
811
817
|
sys.exit(1)
|
|
812
|
-
except ForgeInstallError as e:
|
|
813
|
-
console.print(f"[red]Error:[/red] {e}")
|
|
814
|
-
sys.exit(1)
|
|
815
818
|
except TrackingCorruptedError as e:
|
|
816
819
|
console.print(f"[bold red]Error:[/bold red] {e}")
|
|
817
820
|
sys.exit(1)
|
|
821
|
+
except ForgeInstallError as e:
|
|
822
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
823
|
+
sys.exit(1)
|
|
818
824
|
|
|
819
825
|
|
|
820
826
|
@extensions.command("status")
|
|
@@ -993,9 +999,9 @@ def status_cmd(scope: str | None, path: str | None, show_all: bool, as_json: boo
|
|
|
993
999
|
if not local_installed:
|
|
994
1000
|
all_installations = tracking.list_installations()
|
|
995
1001
|
if all_installations:
|
|
996
|
-
|
|
997
|
-
f"
|
|
998
|
-
|
|
1002
|
+
print_tip(
|
|
1003
|
+
f"{len(all_installations)} installation(s) exist elsewhere. Run 'forge info' to see all.",
|
|
1004
|
+
console=console,
|
|
999
1005
|
)
|
|
1000
1006
|
else:
|
|
1001
|
-
|
|
1007
|
+
print_tip("Run 'forge extension enable' to set up Forge.", console=console)
|
|
@@ -8,6 +8,7 @@ import sys
|
|
|
8
8
|
import click
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
|
|
11
|
+
from forge.cli.output import print_tip
|
|
11
12
|
from forge.core.ops.context import ExecutionContext
|
|
12
13
|
from forge.core.ops.gc import CleanError, CleanReport, collect_clean_report, run_clean
|
|
13
14
|
|
|
@@ -78,7 +79,7 @@ def _print_report(report: CleanReport, verbose: bool, console: Console) -> None:
|
|
|
78
79
|
console.print("[green]Nothing to clean.[/green]")
|
|
79
80
|
else:
|
|
80
81
|
console.print(f"Total: [cyan]{report.total_count}[/cyan] objects to clean\n")
|
|
81
|
-
|
|
82
|
+
print_tip("Use --yes to clean, or --verbose for details.", blank_before=False, console=console)
|
|
82
83
|
|
|
83
84
|
|
|
84
85
|
def _run_and_report(ctx: ExecutionContext, scope: str, report: CleanReport, console: Console) -> None:
|
|
@@ -12,6 +12,7 @@ from pathlib import Path
|
|
|
12
12
|
|
|
13
13
|
from rich.console import Console
|
|
14
14
|
|
|
15
|
+
from forge.cli.output import print_tip
|
|
15
16
|
from forge.core.paths import display_path
|
|
16
17
|
|
|
17
18
|
console = Console()
|
|
@@ -47,7 +48,7 @@ def require_repo_root() -> Path:
|
|
|
47
48
|
console.print(
|
|
48
49
|
f"[red]Error:[/red] Must run from the repository root ({display_path(repo_root)}), " f"not a subdirectory"
|
|
49
50
|
)
|
|
50
|
-
|
|
51
|
+
print_tip("Run from:", commands=[f"cd {display_path(hint)}"], console=console)
|
|
51
52
|
sys.exit(1)
|
|
52
53
|
|
|
53
54
|
return cwd
|
|
@@ -87,7 +88,7 @@ def require_main_repo_root() -> Path:
|
|
|
87
88
|
"[red]Error:[/red] Cannot create worktrees from inside a child worktree. "
|
|
88
89
|
f"Run from the main repository root ({display_path(main_root)})"
|
|
89
90
|
)
|
|
90
|
-
|
|
91
|
+
print_tip("Run from:", commands=[f"cd {display_path(main_root)}"], console=console)
|
|
91
92
|
sys.exit(1)
|
|
92
93
|
|
|
93
94
|
# Accept CWD at a Forge project root (nested or top-level)
|
|
@@ -100,7 +101,7 @@ def require_main_repo_root() -> Path:
|
|
|
100
101
|
console.print(
|
|
101
102
|
f"[red]Error:[/red] Must run from the repository root ({display_path(repo_root)}), " f"not a subdirectory"
|
|
102
103
|
)
|
|
103
|
-
|
|
104
|
+
print_tip("Run from:", commands=[f"cd {display_path(repo_root)}"], console=console)
|
|
104
105
|
sys.exit(1)
|
|
105
106
|
|
|
106
107
|
return cwd
|
|
@@ -71,16 +71,21 @@ def run_cmd(
|
|
|
71
71
|
logger.warning("Failed to read session manifest for %s: %s", session_name, e)
|
|
72
72
|
raise SystemExit(1)
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
logger.info("Handoff not configured for session %s", session_name)
|
|
76
|
-
return
|
|
74
|
+
import dataclasses
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
76
|
+
from forge.session.handoff_agent import resolve_handoff_base_url, run_handoff_agent
|
|
77
|
+
from forge.session.project_memory import (
|
|
78
|
+
DEFAULT_SCAN_ROOTS,
|
|
79
|
+
is_memory_enabled,
|
|
80
|
+
scan_passported_docs,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
if not is_memory_enabled(manifest, effective):
|
|
84
|
+
logger.info("Handoff not activated for session %s", session_name)
|
|
81
85
|
return
|
|
82
86
|
|
|
83
|
-
|
|
87
|
+
assert effective.memory is not None and effective.memory.auto_update is not None
|
|
88
|
+
config = dataclasses.replace(effective.memory.auto_update, enabled=True)
|
|
84
89
|
|
|
85
90
|
confirmed_proxy_url = None
|
|
86
91
|
if manifest.confirmed.started_with_proxy:
|
|
@@ -94,7 +99,7 @@ def run_cmd(
|
|
|
94
99
|
subprocess_proxy=subprocess_proxy or effective.subprocess_proxy,
|
|
95
100
|
)
|
|
96
101
|
|
|
97
|
-
designated_docs =
|
|
102
|
+
designated_docs = scan_passported_docs(effective_root, DEFAULT_SCAN_ROOTS, session_name)
|
|
98
103
|
|
|
99
104
|
success = run_handoff_agent(
|
|
100
105
|
session_name=session_name,
|
|
@@ -52,9 +52,9 @@ from .direct_commands import (
|
|
|
52
52
|
_handle_cmd_cancel_verification,
|
|
53
53
|
_handle_cmd_clean,
|
|
54
54
|
_handle_cmd_config,
|
|
55
|
-
_handle_cmd_guard,
|
|
56
55
|
_handle_cmd_help,
|
|
57
56
|
_handle_cmd_plan,
|
|
57
|
+
_handle_cmd_policy,
|
|
58
58
|
_handle_cmd_proxy,
|
|
59
59
|
_handle_cmd_session,
|
|
60
60
|
_parse_direct_command,
|
|
@@ -513,11 +513,14 @@ def stop() -> None:
|
|
|
513
513
|
is not None
|
|
514
514
|
)
|
|
515
515
|
|
|
516
|
-
# Enqueue handoff marker if
|
|
516
|
+
# Enqueue handoff marker if memory is enabled for this session (best-effort).
|
|
517
517
|
queued_handoff = False
|
|
518
518
|
try:
|
|
519
519
|
effective = compute_effective_intent(manifest)
|
|
520
|
-
|
|
520
|
+
|
|
521
|
+
from forge.session.project_memory import is_memory_enabled
|
|
522
|
+
|
|
523
|
+
if is_memory_enabled(manifest, effective):
|
|
521
524
|
queued_handoff = (
|
|
522
525
|
enqueue_handoff_marker(
|
|
523
526
|
session_id=session_id,
|
|
@@ -530,7 +533,7 @@ def stop() -> None:
|
|
|
530
533
|
is not None
|
|
531
534
|
)
|
|
532
535
|
except Exception:
|
|
533
|
-
|
|
536
|
+
logger.debug("Memory handoff enqueue failed for session %s", manifest.name, exc_info=True)
|
|
534
537
|
|
|
535
538
|
if not manifest_updated:
|
|
536
539
|
# Manifest failed but we still tried to enqueue
|
|
@@ -1117,8 +1120,8 @@ def policy_check() -> None:
|
|
|
1117
1120
|
print("[forge] Policy check: cannot build action context", file=sys.stderr)
|
|
1118
1121
|
sys.exit(0)
|
|
1119
1122
|
|
|
1120
|
-
from forge.
|
|
1121
|
-
from forge.
|
|
1123
|
+
from forge.policy.engine import build_engine
|
|
1124
|
+
from forge.policy.types import FailMode
|
|
1122
1125
|
|
|
1123
1126
|
fail_mode: FailMode = effective.policy.fail_mode or "open"
|
|
1124
1127
|
bundles = effective.policy.bundles or []
|
|
@@ -1140,7 +1143,7 @@ def policy_check() -> None:
|
|
|
1140
1143
|
|
|
1141
1144
|
# Register semantic supervisor before restore_state so cached state is restored with it.
|
|
1142
1145
|
if has_supervisor:
|
|
1143
|
-
from forge.
|
|
1146
|
+
from forge.policy.semantic.supervisor import SemanticSupervisorPolicy
|
|
1144
1147
|
|
|
1145
1148
|
supervisor_policy = SemanticSupervisorPolicy(config=effective.policy.supervisor)
|
|
1146
1149
|
engine.register(supervisor_policy)
|
|
@@ -1321,8 +1324,8 @@ def user_prompt_submit() -> None:
|
|
|
1321
1324
|
_handle_cmd_plan(args)
|
|
1322
1325
|
return
|
|
1323
1326
|
|
|
1324
|
-
if cmd == "
|
|
1325
|
-
|
|
1327
|
+
if cmd == "policy":
|
|
1328
|
+
_handle_cmd_policy(data, args)
|
|
1326
1329
|
return
|
|
1327
1330
|
|
|
1328
1331
|
if cmd == "config":
|
|
@@ -1541,7 +1544,7 @@ def teammate_idle() -> None:
|
|
|
1541
1544
|
if not config or not config.enabled:
|
|
1542
1545
|
sys.exit(0)
|
|
1543
1546
|
|
|
1544
|
-
from forge.
|
|
1547
|
+
from forge.policy.team.handlers import handle_teammate_idle
|
|
1545
1548
|
|
|
1546
1549
|
cache_key = _safe_cache_key(data.get("session_id"))
|
|
1547
1550
|
exit_code, feedback = _run_team_handler(cache_key, lambda cache: handle_teammate_idle(data, config, cache))
|
|
@@ -1576,7 +1579,7 @@ def task_completed() -> None:
|
|
|
1576
1579
|
if not config or not config.enabled:
|
|
1577
1580
|
sys.exit(0)
|
|
1578
1581
|
|
|
1579
|
-
from forge.
|
|
1582
|
+
from forge.policy.team.handlers import handle_task_completed
|
|
1580
1583
|
|
|
1581
1584
|
cache_key = _safe_cache_key(data.get("session_id"))
|
|
1582
1585
|
exit_code, feedback = _run_team_handler(cache_key, lambda cache: handle_task_completed(data, config, cache))
|