iac-code 0.3.0__tar.gz → 0.4.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.
- {iac_code-0.3.0 → iac_code-0.4.0}/PKG-INFO +15 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/README.md +14 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/pyproject.toml +3 -2
- iac_code-0.4.0/src/iac_code/__init__.py +2 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/client.py +45 -11
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/base.py +10 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/server.py +135 -28
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/session.py +7 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/slash_registry.py +42 -3
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/agent_loop.py +108 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/cli/headless.py +54 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/cli/main.py +38 -5
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/cli/output_formats.py +6 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/__init__.py +40 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/auth.py +240 -8
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/clear.py +12 -2
- iac_code-0.4.0/src/iac_code/commands/memory.py +85 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/registry.py +26 -4
- iac_code-0.4.0/src/iac_code/commands/rename.py +43 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/resume.py +25 -4
- iac_code-0.4.0/src/iac_code/commands/skills.py +29 -0
- iac_code-0.4.0/src/iac_code/commands/status.py +98 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/config.py +28 -9
- iac_code-0.4.0/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.po +1000 -324
- iac_code-0.4.0/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.po +999 -324
- iac_code-0.4.0/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.po +998 -324
- iac_code-0.4.0/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.po +978 -324
- iac_code-0.4.0/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.po +995 -324
- iac_code-0.4.0/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.mo +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.po +971 -324
- iac_code-0.4.0/src/iac_code/memory/memory_manager.py +182 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/memory/memory_tools.py +6 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/manager.py +22 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/registry.py +2 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/thinking.py +1 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/agent_factory.py +7 -3
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/permissions/loader.py +11 -5
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/providers/aliyun.py +107 -5
- iac_code-0.4.0/src/iac_code/services/providers/aliyun_oauth.py +583 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/session_index.py +48 -24
- iac_code-0.4.0/src/iac_code/services/session_metadata.py +78 -0
- iac_code-0.4.0/src/iac_code/services/session_resolver.py +73 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/session_storage.py +124 -9
- iac_code-0.4.0/src/iac_code/services/session_usage.py +176 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/client.py +1 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/config.py +9 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/fallback.py +4 -2
- iac_code-0.4.0/src/iac_code/services/update_checker.py +567 -0
- iac_code-0.4.0/src/iac_code/skills/auto_trigger.py +115 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/__init__.py +2 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/SKILL.md +13 -2
- iac_code-0.4.0/src/iac_code/skills/bundled/iac_aliyun/__init__.py +20 -0
- iac_code-0.4.0/src/iac_code/skills/bundled/iac_aliyun/auto_trigger.py +88 -0
- iac_code-0.4.0/src/iac_code/skills/bundled/iac_aliyun/references/template-parameter-recommendation.md +165 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/discovery.py +42 -26
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/frontmatter.py +4 -0
- iac_code-0.4.0/src/iac_code/skills/management.py +81 -0
- iac_code-0.4.0/src/iac_code/skills/settings.py +61 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/skill_definition.py +4 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/skill_tool.py +13 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/base.py +13 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/aliyun_api.py +23 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_client.py +14 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_stack_instances.py +3 -2
- iac_code-0.4.0/src/iac_code/tools/cloud/aliyun/user_agent.py +23 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/registry.py +10 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/edit_file.py +10 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/read_file.py +3 -0
- iac_code-0.4.0/src/iac_code/tools/result_storage.py +64 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/write_file.py +7 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/banner.py +52 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/input_history.py +36 -6
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/prompt_input.py +18 -7
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/raw_input.py +58 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/raw_input_win.py +51 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/resume_picker.py +25 -2
- iac_code-0.4.0/src/iac_code/ui/dialogs/skills_picker.py +297 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/renderer.py +13 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/repl.py +493 -84
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/spinner.py +0 -2
- iac_code-0.4.0/src/iac_code/ui/suggestions/command_provider.py +135 -0
- iac_code-0.4.0/src/iac_code/ui/suggestions/skill_provider.py +47 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/token_extractor.py +32 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/types.py +3 -3
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/file_security.py +14 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/store.py +4 -2
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/json_utils.py +38 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/log.py +6 -4
- iac_code-0.4.0/src/iac_code/utils/project_paths.py +176 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/PKG-INFO +15 -1
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/SOURCES.txt +17 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/requires.txt +3 -2
- iac_code-0.3.0/src/iac_code/__init__.py +0 -2
- iac_code-0.3.0/src/iac_code/i18n/locales/de/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/i18n/locales/es/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/i18n/locales/fr/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/i18n/locales/ja/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/i18n/locales/pt/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/i18n/locales/zh/LC_MESSAGES/messages.mo +0 -0
- iac_code-0.3.0/src/iac_code/memory/memory_manager.py +0 -92
- iac_code-0.3.0/src/iac_code/skills/bundled/iac_aliyun/__init__.py +0 -16
- iac_code-0.3.0/src/iac_code/tools/result_storage.py +0 -39
- iac_code-0.3.0/src/iac_code/ui/suggestions/command_provider.py +0 -43
- iac_code-0.3.0/src/iac_code/utils/project_paths.py +0 -109
- {iac_code-0.3.0 → iac_code-0.4.0}/LICENSE +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/MANIFEST.in +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/setup.cfg +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/setup.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/agent_card.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/app.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/artifacts.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/events.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/executor.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/exposure.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/metrics.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/parts.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/persistence.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/push.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/push_queue.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/push_secrets.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/push_worker.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/router.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/signing.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/task_store.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transport.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/dispatcher.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/grpc.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/grpc_jsonrpc.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/http.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/redis_streams.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/stdio.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/unix.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/transports/websocket.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/a2a/types.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/convert.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/http_sse.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/mcp.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/metrics.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/state.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/tools.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/types.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/acp/version.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/agent_tool.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/agent_types.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/message.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/agent/system_prompt.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/cli/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/cli/install_git_bash.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/compact.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/debug.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/effort.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/exit.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/help.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/model.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/commands/tasks.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/i18n/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/memory/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/anthropic_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/azure_openai_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/base.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/dashscope_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/deepseek_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/gemini_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/kimi_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/lmstudio_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/minimax_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/modelscope_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/ollama_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/openai_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/openrouter_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/retry.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/siliconflow_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/stream_watchdog.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/volcengine_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/providers/zhipu_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/capabilities/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/capabilities/auto_detect.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/capabilities/multimodal.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/cloud_credentials.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/context_manager.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/permissions/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/permissions/pipeline.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/permissions/storage.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/providers/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/qwenpaw_source.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/attributes.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/constants.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/content_serializer.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/events.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/identity.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/metrics.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/names.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/sanitize.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/sink.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/tracing.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/telemetry/types.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/token_budget.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/services/token_counter.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/ecs.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/oss.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/rds.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/redis.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/slb.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/cloud-products/vpc.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/ros-template.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/template-parameters.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/references/terraform-template.md +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/iac_aliyun/scripts/tf2ros.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/bundled/simplify.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/listing.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/loader.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/processor.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/skills/renderer.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/state/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/state/app_state.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tasks/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tasks/notification_queue.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tasks/task_state.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tasks/task_tools.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/bash_tool.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/command_parser.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/mode_validation.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/path_validation.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/permissions.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/readonly_commands.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/rule_matching.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/bash/safety_checks.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/aliyun_doc_search.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/api_hooks.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/endpoints.yml +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/ros_parameters.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/hooks/ros_validate.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_stack.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/aliyun/ros_yaml.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/base_api.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/base_stack.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/cloud/types.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/glob.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/grep.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/list_files.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/tool_executor.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/tools/web_fetch.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/types/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/types/permissions.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/types/skill_source.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/types/stream_events.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/dialog.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/divider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/fuzzy_picker.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/progress_bar.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/search_box.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/select.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/status_icon.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/components/tabs.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/in_place_render.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/key_event.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/core/screen.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/global_search.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/history_search.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/model_picker.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/dialogs/quick_open.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/keybindings/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/keybindings/manager.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/aggregator.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/directory_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/file_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/suggestions/shell_history_provider.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/ui/transcript_view.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/background_housekeeping.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/cleanup.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/console.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/__init__.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/clipboard.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/format_detect.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/pasted_content.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/processor.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/image/resizer.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/platform.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/signals.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/tool_input_parser.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code/utils/windows_paths.py +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/dependency_links.txt +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/entry_points.txt +0 -0
- {iac_code-0.3.0 → iac_code-0.4.0}/src/iac_code.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: iac_code
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Your AI-powered Infrastructure as Code assistant
|
|
5
5
|
Classifier: Programming Language :: Python :: 3
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -74,6 +74,20 @@ Reading from stdin is also supported:
|
|
|
74
74
|
echo "Create an OSS Bucket" | iac-code --prompt -
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
+
## Contributing
|
|
78
|
+
|
|
79
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
make install # install dependencies and pre-commit hooks
|
|
83
|
+
make dev # run in debug mode
|
|
84
|
+
make test # run tests
|
|
85
|
+
make lint # run linters
|
|
86
|
+
make format # format code
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
See the [Contributing Guide](https://aliyun.github.io/iac-code/getting-started/contributing) for details.
|
|
90
|
+
|
|
77
91
|
## Contact Us
|
|
78
92
|
|
|
79
93
|
| [DingTalk](https://qr.dingtalk.com/action/joingroup?code=v1,k1,ubm/77U7qRh/STFZUNBP26X4PNg2z6+uhiPcLGtDNfU=&_dt_no_comment=1&origin=11) | [Discord](https://discord.gg/qECFuFBwF) |
|
|
@@ -55,6 +55,20 @@ Reading from stdin is also supported:
|
|
|
55
55
|
echo "Create an OSS Bucket" | iac-code --prompt -
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
+
## Contributing
|
|
59
|
+
|
|
60
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
make install # install dependencies and pre-commit hooks
|
|
64
|
+
make dev # run in debug mode
|
|
65
|
+
make test # run tests
|
|
66
|
+
make lint # run linters
|
|
67
|
+
make format # format code
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
See the [Contributing Guide](https://aliyun.github.io/iac-code/getting-started/contributing) for details.
|
|
71
|
+
|
|
58
72
|
## Contact Us
|
|
59
73
|
|
|
60
74
|
| [DingTalk](https://qr.dingtalk.com/action/joingroup?code=v1,k1,ubm/77U7qRh/STFZUNBP26X4PNg2z6+uhiPcLGtDNfU=&_dt_no_comment=1&origin=11) | [Discord](https://discord.gg/qECFuFBwF) |
|
|
@@ -21,6 +21,7 @@ dependencies = [
|
|
|
21
21
|
"pyperclip>=1.8.0",
|
|
22
22
|
"openai>=1.50",
|
|
23
23
|
"httpx>=0.27.0",
|
|
24
|
+
"packaging>=24.0",
|
|
24
25
|
"tiktoken>=0.7.0",
|
|
25
26
|
"jsonschema>=4.20",
|
|
26
27
|
"alibabacloud-ros20190910>=3.0.0",
|
|
@@ -32,8 +33,8 @@ dependencies = [
|
|
|
32
33
|
"pillow==12.2.0",
|
|
33
34
|
"cryptography>=42.0",
|
|
34
35
|
"keyring>=25.0",
|
|
35
|
-
"tree-sitter>=0.
|
|
36
|
-
"tree-sitter-bash>=0.
|
|
36
|
+
"tree-sitter>=0.25,<0.26",
|
|
37
|
+
"tree-sitter-bash>=0.25,<0.26",
|
|
37
38
|
]
|
|
38
39
|
|
|
39
40
|
[project.optional-dependencies]
|
|
@@ -7,6 +7,7 @@ from time import monotonic
|
|
|
7
7
|
from typing import Any, AsyncIterator
|
|
8
8
|
|
|
9
9
|
import httpx
|
|
10
|
+
from a2a.types import Role
|
|
10
11
|
|
|
11
12
|
from iac_code.a2a.signing import AgentCardSignature, agent_card_signature_jwks_url, verify_agent_card_dict
|
|
12
13
|
from iac_code.a2a.transport import A2AAuthConfig, A2ATransportBinding, UnsupportedA2ATransportError, headers_for_auth
|
|
@@ -31,19 +32,52 @@ class A2AClientResponse:
|
|
|
31
32
|
if not isinstance(result, dict):
|
|
32
33
|
return ""
|
|
33
34
|
text = result.get("text")
|
|
34
|
-
if isinstance(text, str):
|
|
35
|
+
if isinstance(text, str) and text:
|
|
35
36
|
return text
|
|
36
37
|
status = result.get("status")
|
|
37
|
-
if
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
38
|
+
if isinstance(status, dict):
|
|
39
|
+
extracted = _extract_parts_text(status.get("message"))
|
|
40
|
+
if extracted:
|
|
41
|
+
return extracted
|
|
42
|
+
task = result.get("task")
|
|
43
|
+
if isinstance(task, dict):
|
|
44
|
+
task_status = task.get("status")
|
|
45
|
+
if isinstance(task_status, dict):
|
|
46
|
+
extracted = _extract_parts_text(task_status.get("message"))
|
|
47
|
+
if extracted:
|
|
48
|
+
return extracted
|
|
49
|
+
history = task.get("history")
|
|
50
|
+
if isinstance(history, list):
|
|
51
|
+
for entry in reversed(history):
|
|
52
|
+
extracted = _extract_agent_entry_text(entry)
|
|
53
|
+
if extracted:
|
|
54
|
+
return extracted
|
|
55
|
+
return ""
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
_AGENT_ROLE_NAME = Role.Name(Role.ROLE_AGENT)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _extract_agent_entry_text(entry: Any) -> str:
|
|
62
|
+
if not isinstance(entry, dict) or entry.get("role") != _AGENT_ROLE_NAME:
|
|
63
|
+
return ""
|
|
64
|
+
return _extract_parts_text(entry)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _extract_parts_text(message: Any) -> str:
|
|
68
|
+
if not isinstance(message, dict):
|
|
69
|
+
return ""
|
|
70
|
+
parts = message.get("parts")
|
|
71
|
+
if not isinstance(parts, list):
|
|
72
|
+
return ""
|
|
73
|
+
pieces: list[str] = []
|
|
74
|
+
for part in parts:
|
|
75
|
+
if not isinstance(part, dict):
|
|
76
|
+
continue
|
|
77
|
+
value = part.get("text")
|
|
78
|
+
if isinstance(value, str):
|
|
79
|
+
pieces.append(value)
|
|
80
|
+
return "".join(pieces)
|
|
47
81
|
|
|
48
82
|
|
|
49
83
|
class A2AClient:
|
|
@@ -9,7 +9,7 @@ from urllib.parse import urlparse
|
|
|
9
9
|
from iac_code.a2a.transport import A2ATransportBinding, UnsupportedA2ATransportError
|
|
10
10
|
from iac_code.i18n import _
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
SUPPORTED_TRANSPORTS = frozenset({"http", "stdio", "unix", "websocket", "grpc", "grpc-jsonrpc", "redis-streams"})
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class A2ATransportConfigError(ValueError):
|
|
@@ -159,8 +159,16 @@ def select_binding(bindings: Sequence[A2ATransportBinding]) -> A2ATransportBindi
|
|
|
159
159
|
raise UnsupportedA2ATransportError(f"No runnable A2A transport found. Candidate bindings: {names}")
|
|
160
160
|
|
|
161
161
|
|
|
162
|
+
def validate_transport_supported(transport: str) -> None:
|
|
163
|
+
"""Raise ValueError if the transport name is not recognised."""
|
|
164
|
+
if transport not in SUPPORTED_TRANSPORTS:
|
|
165
|
+
supported = ", ".join(sorted(SUPPORTED_TRANSPORTS))
|
|
166
|
+
raise ValueError(f"Unsupported transport '{transport}'. Supported values: {supported}")
|
|
167
|
+
|
|
168
|
+
|
|
162
169
|
def validate_transport_for_platform(transport: str) -> None:
|
|
163
|
-
"""Raise
|
|
170
|
+
"""Raise an error if the transport is unsupported or unavailable on the current platform."""
|
|
171
|
+
validate_transport_supported(transport)
|
|
164
172
|
if transport == "unix" and sys.platform == "win32":
|
|
165
173
|
raise RuntimeError(
|
|
166
174
|
_(
|
|
@@ -18,8 +18,12 @@ from iac_code.acp.types import ACPContentBlock, MCPServer
|
|
|
18
18
|
from iac_code.acp.version import negotiate_version
|
|
19
19
|
from iac_code.commands import LocalCommand, create_default_registry
|
|
20
20
|
from iac_code.config import DEFAULT_MODEL, get_active_provider_key, load_saved_model
|
|
21
|
+
from iac_code.i18n import _
|
|
21
22
|
from iac_code.services.agent_factory import AgentFactoryOptions, create_agent_runtime
|
|
23
|
+
from iac_code.services.session_index import SessionEntry, SessionIndex
|
|
24
|
+
from iac_code.services.session_resolver import ResolutionStatus, resolve_session_argument
|
|
22
25
|
from iac_code.services.session_storage import SessionStorage
|
|
26
|
+
from iac_code.utils.project_paths import format_resume_command, same_project_path
|
|
23
27
|
|
|
24
28
|
SESSION_IDLE_TIMEOUT = 3600 # 1 hour
|
|
25
29
|
CLEANUP_INTERVAL = 300 # 5 minutes
|
|
@@ -152,7 +156,12 @@ class ACPServer:
|
|
|
152
156
|
runtime.session_id,
|
|
153
157
|
)
|
|
154
158
|
session = ACPSession(
|
|
155
|
-
runtime.session_id,
|
|
159
|
+
runtime.session_id,
|
|
160
|
+
runtime.agent_loop,
|
|
161
|
+
self.conn,
|
|
162
|
+
mcp_configs=mcp_configs,
|
|
163
|
+
metrics=self.metrics,
|
|
164
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
156
165
|
)
|
|
157
166
|
self.sessions[session.id] = session
|
|
158
167
|
self.metrics.record_session_created()
|
|
@@ -228,25 +237,16 @@ class ACPServer:
|
|
|
228
237
|
cwd: str | None = None,
|
|
229
238
|
**kwargs: Any,
|
|
230
239
|
) -> acp.schema.ListSessionsResponse:
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
session_ids: list[str] = []
|
|
234
|
-
if cwd:
|
|
235
|
-
project_dir = get_project_dir(cwd)
|
|
236
|
-
if project_dir.exists():
|
|
237
|
-
session_ids = [p.stem for p in project_dir.glob("*.jsonl")]
|
|
238
|
-
else:
|
|
239
|
-
projects_root = get_projects_dir()
|
|
240
|
-
if projects_root.exists():
|
|
241
|
-
session_ids = [p.stem for p in projects_root.glob("*/*.jsonl")]
|
|
240
|
+
index = SessionIndex()
|
|
241
|
+
entries = index.list_for_cwd(cwd) if cwd else index.list_all_projects()
|
|
242
242
|
return acp.schema.ListSessionsResponse(
|
|
243
243
|
sessions=[
|
|
244
244
|
acp.schema.SessionInfo(
|
|
245
|
-
session_id=session_id,
|
|
246
|
-
cwd=cwd or "",
|
|
247
|
-
title=
|
|
245
|
+
session_id=entry.session_id,
|
|
246
|
+
cwd=entry.cwd or cwd or "",
|
|
247
|
+
title=entry.title,
|
|
248
248
|
)
|
|
249
|
-
for
|
|
249
|
+
for entry in entries
|
|
250
250
|
],
|
|
251
251
|
next_cursor=None,
|
|
252
252
|
)
|
|
@@ -297,7 +297,14 @@ class ACPServer:
|
|
|
297
297
|
runtime.agent_loop.context_manager.load_messages(history)
|
|
298
298
|
|
|
299
299
|
# 4. Register session
|
|
300
|
-
session = ACPSession(
|
|
300
|
+
session = ACPSession(
|
|
301
|
+
session_id,
|
|
302
|
+
runtime.agent_loop,
|
|
303
|
+
self.conn,
|
|
304
|
+
mcp_configs=mcp_configs,
|
|
305
|
+
metrics=self.metrics,
|
|
306
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
307
|
+
)
|
|
301
308
|
self.sessions[session_id] = session
|
|
302
309
|
self.metrics.record_session_created()
|
|
303
310
|
logger.info("Session loaded, session_id=%s, history_messages=%d", session_id, len(history))
|
|
@@ -360,7 +367,12 @@ class ACPServer:
|
|
|
360
367
|
|
|
361
368
|
# 4. Register the forked session
|
|
362
369
|
session = ACPSession(
|
|
363
|
-
new_session_id,
|
|
370
|
+
new_session_id,
|
|
371
|
+
runtime.agent_loop,
|
|
372
|
+
self.conn,
|
|
373
|
+
mcp_configs=mcp_configs,
|
|
374
|
+
metrics=self.metrics,
|
|
375
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
364
376
|
)
|
|
365
377
|
self.sessions[new_session_id] = session
|
|
366
378
|
self.metrics.record_session_created()
|
|
@@ -384,20 +396,66 @@ class ACPServer:
|
|
|
384
396
|
mcp_servers: list[MCPServer] | None = None,
|
|
385
397
|
**kwargs: Any,
|
|
386
398
|
) -> acp.schema.ResumeSessionResponse:
|
|
387
|
-
# 1. If session is still active in memory,
|
|
388
|
-
|
|
399
|
+
# 1. If session is still active in memory by exact id, enforce project ownership before returning.
|
|
400
|
+
active_session = self.sessions.get(session_id)
|
|
401
|
+
if active_session is not None:
|
|
402
|
+
error = _active_session_project_error(cwd, session_id, session_id, active_session)
|
|
403
|
+
if error is not None:
|
|
404
|
+
raise error
|
|
389
405
|
await self._push_available_commands(session_id)
|
|
390
406
|
return acp.schema.ResumeSessionResponse()
|
|
391
407
|
|
|
392
408
|
if self.conn is None:
|
|
393
409
|
raise acp.RequestError.internal_error({"error": "ACP client not connected"})
|
|
394
410
|
|
|
395
|
-
|
|
411
|
+
resolution = resolve_session_argument(SessionIndex(), cwd, session_id)
|
|
412
|
+
if resolution.status == ResolutionStatus.NOT_FOUND:
|
|
413
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
414
|
+
if resolution.status == ResolutionStatus.AMBIGUOUS_NAME:
|
|
415
|
+
candidate_ids = [entry.session_id for entry in resolution.candidates]
|
|
416
|
+
message = _("Session name is ambiguous. Candidates: {candidates}").format(
|
|
417
|
+
candidates=", ".join(candidate_ids)
|
|
418
|
+
)
|
|
419
|
+
raise _invalid_params(
|
|
420
|
+
message,
|
|
421
|
+
{
|
|
422
|
+
"session_id": session_id,
|
|
423
|
+
"candidates": [_resume_candidate_data(entry) for entry in resolution.candidates],
|
|
424
|
+
},
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
entry = resolution.entry
|
|
428
|
+
if entry is None: # pragma: no cover - defensive guard for inconsistent resolver output
|
|
429
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
430
|
+
|
|
431
|
+
resolved_session_id = entry.session_id
|
|
432
|
+
if entry.cwd and not same_project_path(entry.cwd, cwd):
|
|
433
|
+
hint = _resume_command(entry.cwd, resolved_session_id)
|
|
434
|
+
message = _("Session belongs to another project. Run: {hint}").format(hint=hint)
|
|
435
|
+
raise _invalid_params(
|
|
436
|
+
message,
|
|
437
|
+
{
|
|
438
|
+
"session_id": session_id,
|
|
439
|
+
"resolved_session_id": resolved_session_id,
|
|
440
|
+
"cwd": entry.cwd,
|
|
441
|
+
"hint": hint,
|
|
442
|
+
},
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
active_session = self.sessions.get(resolved_session_id)
|
|
446
|
+
if active_session is not None:
|
|
447
|
+
error = _active_session_project_error(cwd, session_id, resolved_session_id, active_session)
|
|
448
|
+
if error is not None:
|
|
449
|
+
raise error
|
|
450
|
+
await self._push_available_commands(resolved_session_id)
|
|
451
|
+
return acp.schema.ResumeSessionResponse()
|
|
452
|
+
|
|
453
|
+
# 2. Try to load persisted history from SessionStorage.
|
|
396
454
|
storage = SessionStorage()
|
|
397
|
-
if not storage.exists(cwd,
|
|
398
|
-
raise
|
|
455
|
+
if not storage.exists(cwd, resolved_session_id):
|
|
456
|
+
raise _invalid_params(_("Session not found"), {"session_id": session_id})
|
|
399
457
|
|
|
400
|
-
history = storage.load(cwd,
|
|
458
|
+
history = storage.load(cwd, resolved_session_id)
|
|
401
459
|
history = SessionStorage.repair_interrupted(history)
|
|
402
460
|
|
|
403
461
|
# Convert MCP server configs from ACP protocol types to internal dicts
|
|
@@ -405,7 +463,7 @@ class ACPServer:
|
|
|
405
463
|
|
|
406
464
|
# 3. Rebuild agent runtime with restored history
|
|
407
465
|
model = load_saved_model() or DEFAULT_MODEL
|
|
408
|
-
runtime = self._create_runtime_with_auth_check(model=model, session_id=
|
|
466
|
+
runtime = self._create_runtime_with_auth_check(model=model, session_id=resolved_session_id, cwd=cwd)
|
|
409
467
|
replace_bash_with_acp_terminal(
|
|
410
468
|
runtime.tool_registry,
|
|
411
469
|
self.client_capabilities,
|
|
@@ -418,10 +476,17 @@ class ACPServer:
|
|
|
418
476
|
runtime.agent_loop.context_manager.load_messages(history)
|
|
419
477
|
|
|
420
478
|
# 4. Register the resumed session
|
|
421
|
-
session = ACPSession(
|
|
422
|
-
|
|
479
|
+
session = ACPSession(
|
|
480
|
+
resolved_session_id,
|
|
481
|
+
runtime.agent_loop,
|
|
482
|
+
self.conn,
|
|
483
|
+
mcp_configs=mcp_configs,
|
|
484
|
+
metrics=self.metrics,
|
|
485
|
+
memory_manager=getattr(runtime, "memory_manager", None),
|
|
486
|
+
)
|
|
487
|
+
self.sessions[resolved_session_id] = session
|
|
423
488
|
self.metrics.record_session_created()
|
|
424
|
-
await self._push_available_commands(
|
|
489
|
+
await self._push_available_commands(resolved_session_id)
|
|
425
490
|
|
|
426
491
|
return acp.schema.ResumeSessionResponse()
|
|
427
492
|
|
|
@@ -619,6 +684,48 @@ def _convert_mcp_servers(mcp_servers: list[MCPServer] | None) -> list[dict[str,
|
|
|
619
684
|
return configs
|
|
620
685
|
|
|
621
686
|
|
|
687
|
+
def _invalid_params(message: str, data: dict[str, Any] | None = None) -> acp.RequestError:
|
|
688
|
+
"""Create an ACP invalid-params error with a useful message."""
|
|
689
|
+
return acp.RequestError(-32602, message, data)
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
def _resume_command(cwd: str, session_id: str) -> str:
|
|
693
|
+
return format_resume_command(cwd, session_id)
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
def _active_session_cwd(session: ACPSession) -> str | None:
|
|
697
|
+
cwd = getattr(session.agent_loop, "_cwd", None)
|
|
698
|
+
return cwd if isinstance(cwd, str) and cwd else None
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
def _active_session_project_error(
|
|
702
|
+
cwd: str, session_id: str, resolved_session_id: str, session: ACPSession
|
|
703
|
+
) -> acp.RequestError | None:
|
|
704
|
+
active_cwd = _active_session_cwd(session)
|
|
705
|
+
if not active_cwd or same_project_path(active_cwd, cwd):
|
|
706
|
+
return None
|
|
707
|
+
hint = _resume_command(active_cwd, resolved_session_id)
|
|
708
|
+
message = _("Session belongs to another project. Run: {hint}").format(hint=hint)
|
|
709
|
+
return _invalid_params(
|
|
710
|
+
message,
|
|
711
|
+
{
|
|
712
|
+
"session_id": session_id,
|
|
713
|
+
"resolved_session_id": resolved_session_id,
|
|
714
|
+
"cwd": active_cwd,
|
|
715
|
+
"hint": hint,
|
|
716
|
+
},
|
|
717
|
+
)
|
|
718
|
+
|
|
719
|
+
|
|
720
|
+
def _resume_candidate_data(entry: SessionEntry) -> dict[str, str | None]:
|
|
721
|
+
return {
|
|
722
|
+
"session_id": entry.session_id,
|
|
723
|
+
"name": entry.name,
|
|
724
|
+
"cwd": entry.cwd,
|
|
725
|
+
"command": _resume_command(entry.cwd, entry.session_id),
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
|
|
622
729
|
# ---------------------------------------------------------------------------
|
|
623
730
|
# Auth methods declaration
|
|
624
731
|
# ---------------------------------------------------------------------------
|
|
@@ -165,9 +165,11 @@ class ACPSession:
|
|
|
165
165
|
conn: acp.Client,
|
|
166
166
|
mcp_configs: list[dict] | None = None,
|
|
167
167
|
metrics: ACPMetrics | None = None,
|
|
168
|
+
memory_manager=None,
|
|
168
169
|
) -> None:
|
|
169
170
|
self.id = session_id
|
|
170
171
|
self.agent_loop = agent_loop
|
|
172
|
+
self.memory_manager = memory_manager
|
|
171
173
|
self._conn = conn
|
|
172
174
|
self._current_task: asyncio.Task | None = None
|
|
173
175
|
self._replay_task: asyncio.Task[None] | None = None
|
|
@@ -292,7 +294,11 @@ class ACPSession:
|
|
|
292
294
|
prompt_text = acp_blocks_to_prompt_text(prompt)
|
|
293
295
|
slash_registry = ACPSlashRegistry()
|
|
294
296
|
if slash_registry.is_slash_command(prompt_text):
|
|
295
|
-
result = await slash_registry.execute(
|
|
297
|
+
result = await slash_registry.execute(
|
|
298
|
+
prompt_text,
|
|
299
|
+
self.agent_loop,
|
|
300
|
+
memory_manager=self.memory_manager,
|
|
301
|
+
)
|
|
296
302
|
await self._conn.session_update(
|
|
297
303
|
session_id=self.id,
|
|
298
304
|
update=acp.schema.AgentMessageChunk(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""ACP slash command registry.
|
|
2
2
|
|
|
3
3
|
Manages commands supported over the ACP protocol.
|
|
4
|
-
Only /compact, /clear, and /
|
|
4
|
+
Only /compact, /clear, /debug, /memory, and /rename are allowed;
|
|
5
5
|
all other slash commands are rejected with a clear message.
|
|
6
6
|
"""
|
|
7
7
|
|
|
@@ -10,10 +10,12 @@ from __future__ import annotations
|
|
|
10
10
|
import logging
|
|
11
11
|
|
|
12
12
|
from iac_code.i18n import _
|
|
13
|
+
from iac_code.services.session_metadata import normalize_session_name
|
|
14
|
+
from iac_code.services.session_storage import SessionStorage
|
|
13
15
|
|
|
14
16
|
logger = logging.getLogger(__name__)
|
|
15
17
|
|
|
16
|
-
ACP_SUPPORTED_COMMANDS: frozenset[str] = frozenset({"compact", "clear", "debug"})
|
|
18
|
+
ACP_SUPPORTED_COMMANDS: frozenset[str] = frozenset({"compact", "clear", "debug", "memory", "rename"})
|
|
17
19
|
|
|
18
20
|
|
|
19
21
|
class ACPSlashRegistry:
|
|
@@ -51,6 +53,10 @@ class ACPSlashRegistry:
|
|
|
51
53
|
return await self._handle_clear(agent_loop)
|
|
52
54
|
if cmd_name == "debug":
|
|
53
55
|
return self._handle_debug(args_str)
|
|
56
|
+
if cmd_name == "memory":
|
|
57
|
+
return self._handle_memory(args_str, context.get("memory_manager"))
|
|
58
|
+
if cmd_name == "rename":
|
|
59
|
+
return self._handle_rename(args_str, agent_loop)
|
|
54
60
|
|
|
55
61
|
# Should not reach here
|
|
56
62
|
return _("Command '/{cmd_name}' handler not implemented.").format(cmd_name=cmd_name) # pragma: no cover
|
|
@@ -91,7 +97,7 @@ class ACPSlashRegistry:
|
|
|
91
97
|
async def _handle_clear(self, agent_loop) -> str:
|
|
92
98
|
"""Clear the agent_loop conversation history."""
|
|
93
99
|
try:
|
|
94
|
-
agent_loop.
|
|
100
|
+
agent_loop.reset()
|
|
95
101
|
except Exception as exc:
|
|
96
102
|
logger.warning("ACP /clear failed: %s", exc)
|
|
97
103
|
return _("Clear failed: {error}").format(error=exc)
|
|
@@ -123,3 +129,36 @@ class ACPSlashRegistry:
|
|
|
123
129
|
return _("Debug logging disabled.")
|
|
124
130
|
|
|
125
131
|
return _("Usage: /debug [on|off]")
|
|
132
|
+
|
|
133
|
+
def _handle_memory(self, args: str, memory_manager) -> str:
|
|
134
|
+
"""View and manage persistent memories."""
|
|
135
|
+
if memory_manager is None:
|
|
136
|
+
return _("Memory manager is unavailable.")
|
|
137
|
+
|
|
138
|
+
from iac_code.commands.memory import execute_memory_command
|
|
139
|
+
|
|
140
|
+
return execute_memory_command(memory_manager, args.split())
|
|
141
|
+
|
|
142
|
+
def _handle_rename(self, args: str, agent_loop) -> str:
|
|
143
|
+
"""Rename the current ACP session non-interactively."""
|
|
144
|
+
parts = args.split()
|
|
145
|
+
if len(parts) != 1:
|
|
146
|
+
return _("Usage: /rename <name>")
|
|
147
|
+
|
|
148
|
+
cwd = getattr(agent_loop, "_cwd", None)
|
|
149
|
+
session_id = getattr(agent_loop, "_session_id", None)
|
|
150
|
+
git_branch = getattr(agent_loop, "_current_git_branch", None)
|
|
151
|
+
if not isinstance(cwd, str) or not isinstance(session_id, str):
|
|
152
|
+
return _("Rename is only available after a session is created.")
|
|
153
|
+
if not isinstance(git_branch, str):
|
|
154
|
+
git_branch = None
|
|
155
|
+
|
|
156
|
+
try:
|
|
157
|
+
name = normalize_session_name(parts[0])
|
|
158
|
+
result = SessionStorage().rename_session(cwd, session_id, name, git_branch=git_branch)
|
|
159
|
+
except ValueError as exc:
|
|
160
|
+
return str(exc)
|
|
161
|
+
|
|
162
|
+
if result == "unchanged":
|
|
163
|
+
return _("Session is already named {name}").format(name=name)
|
|
164
|
+
return _("Renamed session to {name}").format(name=name)
|