deepagents-cli 0.0.44__tar.gz → 0.0.45__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.
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/CHANGELOG.md +7 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/PKG-INFO +2 -2
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_version.py +1 -1
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/project_utils.py +62 -10
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/chat_input.py +6 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/loading.py +1 -1
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/pyproject.toml +2 -2
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_chat_input.py +50 -1
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_config.py +139 -6
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/uv.lock +2 -2
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/.gitignore +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/DEV.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/Makefile +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/README.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/THREAT_MODEL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/__main__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_ask_user_types.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_cli_context.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_debug.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_env_vars.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_git.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_server_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_session_stats.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_testing_models.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/_textual_patches.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/agent.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/app.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/app.tcss +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/ask_user.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/remember/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/clipboard.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/command_registry.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/configurable_model.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/default_agent_prompt.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/bundler.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/commands.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/anonymous-B9UzAXQd.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/clerk-5xHgyQyG.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/highlighted-body-OFNGDK62-rX-7qT8o.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/index-DM3gptpu.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/index-Ddy7F6KI.css +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/assets/supabase-S6NACDgm.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/index.html +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/logo-dark.svg +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/logo-light.svg +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/templates.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/editor.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/extras_info.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/file_ops.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/formatting.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/hooks.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/input.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/integrations/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/integrations/sandbox_factory.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/integrations/sandbox_provider.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/local_context.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/main.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/mcp_tools.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/mcp_trust.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/media_utils.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/model_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/non_interactive.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/notifications.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/offload.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/output.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/py.typed +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/remote_client.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/server.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/server_graph.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/server_manager.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/sessions.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/skills/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/skills/commands.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/skills/invocation.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/skills/load.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/subagents.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/system_prompt.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/textual_adapter.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/theme.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/token_state.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/tool_display.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/tools.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/ui.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/unicode_security.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/update_check.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/_links.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/agent_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/approval.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/ask_user.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/autocomplete.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/diff.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/history.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/mcp_viewer.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/message_store.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/messages.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/model_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/notification_center.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/notification_detail.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/notification_settings.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/status.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/theme_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/thread_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/tool_renderers.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/tool_widgets.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/update_available.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/widgets/welcome.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/deploy-content-writer/.env.example +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/deploy-content-writer/skills/blog-post/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/deploy-content-writer/skills/social-media/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/deploy-content-writer/user/context.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/deploy-content-writer/user/preferences.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/arxiv-search/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/arxiv-search/arxiv_search.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/langgraph-docs/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/skill-creator/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/skill-creator/scripts/init_skill.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/skill-creator/scripts/quick_validate.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/examples/skills/web-research/SKILL.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/.nvmrc +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/index.html +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/package-lock.json +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/package.json +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/postcss.config.js +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/public/logo-dark.svg +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/public/logo-light.svg +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/App.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/ThemeProvider.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/auth/anonymous.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/auth/clerk.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/auth/loader.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/auth/supabase.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/auth/types.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/AppHeader.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/FilePanels.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/MessageList.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/SubagentActivity.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/ThreadPicker.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/TodosPanel.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/ToolCallCard.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/toolcalls/FileToolCard.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/toolcalls/SearchCard.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/toolcalls/ThinkCard.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/toolcalls/TodosCard.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/components/toolcalls/index.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/constants.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/index.css +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/main.tsx +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/runtimeConfig.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/types.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/src/vite-env.d.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/tsconfig.json +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/frontend/vite.config.ts +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/images/cli.png +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/scripts/check_imports.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/scripts/debug_server.sh +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/scripts/install.sh +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/README.md +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/benchmarks/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/benchmarks/test_codspeed_import_benchmarks.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/benchmarks/test_startup_benchmarks.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/conftest.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/test_acp_mode.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/test_compact_resume.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/integration_tests/test_sandbox_operations.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/conftest.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/test_bundler.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/test_commands.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/test_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/test_frontend_bundle.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/deploy/test_frontend_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/skills/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/skills/test_commands.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/skills/test_load.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/skills/test_skills_json.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_agent.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_agent_friendly.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_agent_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_app.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_approval.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_args.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_ask_user.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_ask_user_middleware.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_autocomplete.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_charset.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_command_registry.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_compact_tool.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_configurable_model.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_debug.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_editor.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_end_to_end.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_env_vars.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_exception_handling.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_extras_info.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_file_ops.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_formatting.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_git.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_history.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_hooks.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_imports.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_input_parsing.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_links.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_loading.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_local_context.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_main.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_main_acp_mode.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_main_args.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_mcp_tools.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_mcp_trust.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_mcp_viewer.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_media_utils.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_message_store.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_messages.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_model_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_model_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_model_switch.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_non_interactive.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_notification_center.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_notification_detail.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_notifications.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_offload.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_offload_dict_messages.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_output.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_reload.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_remote_client.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_sandbox_factory.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_server.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_server_config.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_server_graph.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_server_helpers.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_server_manager.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_session_stats.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_sessions.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_shell_allow_list.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_skill_invocation.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_status.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_subagents.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_terminal_capabilities.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_textual_adapter.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_textual_patches.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_theme.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_thread_selector.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_token_tracker.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_tool_display.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_ui.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_unicode_security.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_update_available.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_update_check.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_version.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/test_welcome.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/tools/__init__.py +0 -0
- {deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/tests/unit_tests/tools/test_fetch_url.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.45](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.44...deepagents-cli==0.0.45) (2026-04-30)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Reject out-of-tree symlinked project `AGENTS.md` ([#3039](https://github.com/langchain-ai/deepagents/issues/3039)) ([4618098](https://github.com/langchain-ai/deepagents/commit/4618098e59c8c8d1d3f91354e4f4163a9582f710))
|
|
8
|
+
* Support modified backspace word deletion ([#3037](https://github.com/langchain-ai/deepagents/issues/3037)) ([bc3d019](https://github.com/langchain-ai/deepagents/commit/bc3d01916d2ba34be07d56c9eb9b813008c1584c))
|
|
9
|
+
|
|
3
10
|
## [0.0.44](https://github.com/langchain-ai/deepagents/compare/deepagents-cli==0.0.43...deepagents-cli==0.0.44) (2026-04-29)
|
|
4
11
|
|
|
5
12
|
### Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: deepagents-cli
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.45
|
|
4
4
|
Summary: Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities.
|
|
5
5
|
Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
|
|
6
6
|
Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
|
|
@@ -27,7 +27,7 @@ Classifier: Topic :: Terminals
|
|
|
27
27
|
Requires-Python: <4.0,>=3.11
|
|
28
28
|
Requires-Dist: aiosqlite<1.0.0,>=0.19.0
|
|
29
29
|
Requires-Dist: deepagents-acp>=0.0.4
|
|
30
|
-
Requires-Dist: deepagents==0.5.
|
|
30
|
+
Requires-Dist: deepagents==0.5.5
|
|
31
31
|
Requires-Dist: httpx<1.0.0,>=0.28.1
|
|
32
32
|
Requires-Dist: langchain-anthropic<2.0.0,>=1.4.2
|
|
33
33
|
Requires-Dist: langchain-google-genai<5.0.0,>=4.2.2
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Version information and lightweight constants for `deepagents-cli`."""
|
|
2
2
|
|
|
3
|
-
__version__ = "0.0.
|
|
3
|
+
__version__ = "0.0.45" # x-release-please-version
|
|
4
4
|
|
|
5
5
|
DOCS_URL = "https://docs.langchain.com/oss/python/deepagents/cli"
|
|
6
6
|
"""URL for `deepagents-cli` documentation."""
|
|
@@ -156,24 +156,76 @@ def find_project_agent_md(project_root: Path) -> list[Path]:
|
|
|
156
156
|
|
|
157
157
|
Both files will be loaded and combined if both exist.
|
|
158
158
|
|
|
159
|
+
Candidates with symlinked path components are followed only when the
|
|
160
|
+
resolved target stays inside `project_root`. The returned `Path` is the
|
|
161
|
+
resolved target when any symlink component was traversed, so
|
|
162
|
+
`FilesystemBackend.download_files` opens a regular file rather than
|
|
163
|
+
tripping `O_NOFOLLOW` on the link itself. Symlinks pointing outside the
|
|
164
|
+
project root, symlink loops, and unreadable parents are skipped with a
|
|
165
|
+
warning. Broken symlinks are treated as missing files (no warning),
|
|
166
|
+
matching the pre-existing behavior for absent candidates.
|
|
167
|
+
|
|
168
|
+
Why: project AGENTS.md is auto-discovered and loaded into the system
|
|
169
|
+
prompt before the first model call. Without the in-tree check, a
|
|
170
|
+
malicious clone could ship `AGENTS.md -> ~/.ssh/config` (or any other
|
|
171
|
+
locally-readable file) and have its contents injected as agent
|
|
172
|
+
instructions on first run.
|
|
173
|
+
|
|
159
174
|
Args:
|
|
160
175
|
project_root: Path to the project root directory.
|
|
161
176
|
|
|
162
177
|
Returns:
|
|
163
|
-
Existing AGENTS.md paths
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
178
|
+
Existing AGENTS.md paths, with in-tree symlinked path components
|
|
179
|
+
pre-resolved to their targets. Empty if neither file exists, one
|
|
180
|
+
entry if only one is present, or two entries if both locations
|
|
181
|
+
have the file.
|
|
167
182
|
"""
|
|
183
|
+
# Resolve the root once so the candidate-equality check below works even
|
|
184
|
+
# when the caller passes a non-canonical `project_root` (e.g., macOS
|
|
185
|
+
# `/var` -> `/private/var`, or a path with symlinked ancestors).
|
|
186
|
+
project_root_resolved = project_root.resolve()
|
|
168
187
|
candidates = [
|
|
169
|
-
|
|
170
|
-
|
|
188
|
+
project_root_resolved / ".deepagents" / "AGENTS.md",
|
|
189
|
+
project_root_resolved / "AGENTS.md",
|
|
171
190
|
]
|
|
172
191
|
paths: list[Path] = []
|
|
173
192
|
for candidate in candidates:
|
|
174
193
|
try:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
194
|
+
# Single syscall handles existence, broken symlinks, loops, and
|
|
195
|
+
# canonicalization. `strict=True` raises rather than returning
|
|
196
|
+
# the unresolved path.
|
|
197
|
+
resolved = candidate.resolve(strict=True)
|
|
198
|
+
except FileNotFoundError:
|
|
199
|
+
# Absent file or broken symlink — matches the pre-existing
|
|
200
|
+
# silent-skip behavior for missing candidates. `Path.exists()`
|
|
201
|
+
# also returns False for symlink loops on some Python versions,
|
|
202
|
+
# so loops do NOT come through here; see the OSError branch.
|
|
203
|
+
continue
|
|
204
|
+
except (OSError, RuntimeError) as exc:
|
|
205
|
+
# `OSError(ELOOP)` on Python 3.13+, `RuntimeError("Symlink loop
|
|
206
|
+
# ...")` on 3.11-3.12; bare `OSError` for permission/unreadable
|
|
207
|
+
# parent. Security-relevant — warn and skip.
|
|
208
|
+
logger.warning(
|
|
209
|
+
"Skipping AGENTS.md candidate %s: %s",
|
|
210
|
+
candidate,
|
|
211
|
+
exc,
|
|
212
|
+
)
|
|
213
|
+
continue
|
|
214
|
+
|
|
215
|
+
try:
|
|
216
|
+
resolved.relative_to(project_root_resolved)
|
|
217
|
+
except ValueError:
|
|
218
|
+
logger.warning(
|
|
219
|
+
"Skipping AGENTS.md symlink %s: target %s is outside "
|
|
220
|
+
"the project root %s",
|
|
221
|
+
candidate,
|
|
222
|
+
resolved,
|
|
223
|
+
project_root_resolved,
|
|
224
|
+
)
|
|
225
|
+
continue
|
|
226
|
+
|
|
227
|
+
if candidate.absolute() == resolved:
|
|
228
|
+
paths.append(candidate)
|
|
229
|
+
else:
|
|
230
|
+
paths.append(resolved)
|
|
179
231
|
return paths
|
|
@@ -332,6 +332,12 @@ class ChatTextArea(TextArea):
|
|
|
332
332
|
show=False,
|
|
333
333
|
priority=True,
|
|
334
334
|
),
|
|
335
|
+
Binding(
|
|
336
|
+
"ctrl+backspace,alt+backspace",
|
|
337
|
+
"delete_word_left",
|
|
338
|
+
"Delete left to start of word",
|
|
339
|
+
show=False,
|
|
340
|
+
),
|
|
335
341
|
]
|
|
336
342
|
"""Key bindings for the chat text area.
|
|
337
343
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "deepagents-cli"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.45"
|
|
8
8
|
description = "Terminal interface for Deep Agents - interactive AI agent with file operations, shell access, and sub-agent capabilities."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -26,7 +26,7 @@ classifiers = [
|
|
|
26
26
|
]
|
|
27
27
|
dependencies = [
|
|
28
28
|
# Framework
|
|
29
|
-
"deepagents==0.5.
|
|
29
|
+
"deepagents==0.5.5",
|
|
30
30
|
"langchain>=1.2.15,<2.0.0",
|
|
31
31
|
"langgraph>=1.1.6,<2.0.0",
|
|
32
32
|
"langgraph-checkpoint-sqlite>=3.0.0,<4.0.0",
|
|
@@ -25,7 +25,6 @@ from deepagents_cli.widgets.chat_input import (
|
|
|
25
25
|
if TYPE_CHECKING:
|
|
26
26
|
from pathlib import Path
|
|
27
27
|
|
|
28
|
-
import pytest
|
|
29
28
|
from textual.pilot import Pilot
|
|
30
29
|
|
|
31
30
|
|
|
@@ -225,6 +224,34 @@ class _RecordingApp(App[None]):
|
|
|
225
224
|
self.submitted.append(event)
|
|
226
225
|
|
|
227
226
|
|
|
227
|
+
class TestChatTextAreaKeybindings:
|
|
228
|
+
"""Regression tests for terminal key aliases in the chat input."""
|
|
229
|
+
|
|
230
|
+
def test_newline_bindings_do_not_shadow_enter_alias(self) -> None:
|
|
231
|
+
"""`ctrl+m` is carriage return in terminals, so it must remain plain Enter."""
|
|
232
|
+
newline_keys = {
|
|
233
|
+
key.strip()
|
|
234
|
+
for binding in ChatTextArea.BINDINGS
|
|
235
|
+
if binding.action == "insert_newline"
|
|
236
|
+
for key in binding.key.split(",")
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
assert "ctrl+m" not in newline_keys
|
|
240
|
+
assert "ctrl+m" not in ChatTextArea._NEWLINE_KEYS
|
|
241
|
+
|
|
242
|
+
def test_modified_backspace_deletes_word_left(self) -> None:
|
|
243
|
+
"""Modified Backspace aliases should delete the previous word."""
|
|
244
|
+
word_delete_keys = {
|
|
245
|
+
key.strip()
|
|
246
|
+
for binding in ChatTextArea.BINDINGS
|
|
247
|
+
if binding.action == "delete_word_left"
|
|
248
|
+
for key in binding.key.split(",")
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
assert "ctrl+backspace" in word_delete_keys
|
|
252
|
+
assert "alt+backspace" in word_delete_keys
|
|
253
|
+
|
|
254
|
+
|
|
228
255
|
class _ImagePasteApp(App[None]):
|
|
229
256
|
"""App that wires a shared tracker into ChatInput for paste tests."""
|
|
230
257
|
|
|
@@ -2206,6 +2233,28 @@ class TestCtrlUDeleteToLineStart:
|
|
|
2206
2233
|
assert ta.cursor_location == (1, 0)
|
|
2207
2234
|
|
|
2208
2235
|
|
|
2236
|
+
class TestModifiedBackspaceDeleteWordLeft:
|
|
2237
|
+
"""Test modified Backspace aliases for word deletion."""
|
|
2238
|
+
|
|
2239
|
+
@pytest.mark.parametrize("key", ["ctrl+backspace", "alt+backspace"])
|
|
2240
|
+
async def test_modified_backspace_deletes_previous_word(self, key: str) -> None:
|
|
2241
|
+
"""Modified Backspace should delete the word before the cursor."""
|
|
2242
|
+
app = _ChatInputTestApp()
|
|
2243
|
+
async with app.run_test() as pilot:
|
|
2244
|
+
chat = app.query_one(ChatInput)
|
|
2245
|
+
ta = chat._text_area
|
|
2246
|
+
assert ta is not None
|
|
2247
|
+
|
|
2248
|
+
ta.insert("hello world")
|
|
2249
|
+
await pilot.pause()
|
|
2250
|
+
|
|
2251
|
+
await pilot.press(key)
|
|
2252
|
+
await pilot.pause()
|
|
2253
|
+
|
|
2254
|
+
assert ta.text == "hello "
|
|
2255
|
+
assert ta.cursor_location == (0, 6)
|
|
2256
|
+
|
|
2257
|
+
|
|
2209
2258
|
class _TextAreaTypingApp(App[None]):
|
|
2210
2259
|
"""Minimal app that captures ChatTextArea.Typing and ChatInput.Typing events."""
|
|
2211
2260
|
|
|
@@ -222,26 +222,159 @@ class TestProjectAgentMdFinding:
|
|
|
222
222
|
assert result == []
|
|
223
223
|
|
|
224
224
|
def test_skips_paths_with_permission_errors(self, tmp_path: Path) -> None:
|
|
225
|
-
"""
|
|
225
|
+
"""`OSError` from `Path.resolve()` is caught and the candidate is skipped."""
|
|
226
226
|
project_root = tmp_path / "project"
|
|
227
227
|
project_root.mkdir()
|
|
228
228
|
|
|
229
229
|
real_md = project_root / "AGENTS.md"
|
|
230
230
|
real_md.write_text("root instructions")
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
original_resolve = Path.resolve
|
|
233
233
|
|
|
234
|
-
def
|
|
234
|
+
def patched_resolve(self: Path, *args: object, **kwargs: object) -> Path:
|
|
235
235
|
if self.name == "AGENTS.md" and ".deepagents" in str(self):
|
|
236
236
|
msg = "Permission denied"
|
|
237
237
|
raise PermissionError(msg)
|
|
238
|
-
return
|
|
238
|
+
return original_resolve(self, *args, **kwargs) # type: ignore[arg-type]
|
|
239
239
|
|
|
240
|
-
with patch.object(Path, "
|
|
240
|
+
with patch.object(Path, "resolve", patched_resolve):
|
|
241
241
|
result = _find_project_agent_md(project_root)
|
|
242
242
|
|
|
243
243
|
assert len(result) == 1
|
|
244
|
-
assert result[0]
|
|
244
|
+
assert result[0].samefile(real_md)
|
|
245
|
+
assert not result[0].is_symlink()
|
|
246
|
+
|
|
247
|
+
def test_in_tree_symlink_resolves_to_target(self, tmp_path: Path) -> None:
|
|
248
|
+
"""`AGENTS.md -> CLAUDE.md` returns a non-symlink path same-file as target."""
|
|
249
|
+
project_root = tmp_path / "project"
|
|
250
|
+
project_root.mkdir()
|
|
251
|
+
|
|
252
|
+
target = project_root / "CLAUDE.md"
|
|
253
|
+
target.write_text("real instructions")
|
|
254
|
+
|
|
255
|
+
link = project_root / "AGENTS.md"
|
|
256
|
+
link.symlink_to(target)
|
|
257
|
+
|
|
258
|
+
result = _find_project_agent_md(project_root)
|
|
259
|
+
|
|
260
|
+
assert len(result) == 1
|
|
261
|
+
# Returned path must be the resolved target — not the symlink — so
|
|
262
|
+
# `FilesystemBackend.download_files` opens the regular file rather
|
|
263
|
+
# than tripping `O_NOFOLLOW` on the link itself.
|
|
264
|
+
assert not result[0].is_symlink()
|
|
265
|
+
assert result[0].samefile(target)
|
|
266
|
+
assert result[0].is_relative_to(project_root.resolve())
|
|
267
|
+
|
|
268
|
+
def test_out_of_tree_symlink_skipped(
|
|
269
|
+
self, tmp_path: Path, caplog: pytest.LogCaptureFixture
|
|
270
|
+
) -> None:
|
|
271
|
+
"""Symlink pointing outside project root is skipped with a warning."""
|
|
272
|
+
project_root = tmp_path / "project"
|
|
273
|
+
project_root.mkdir()
|
|
274
|
+
outside_target = tmp_path / "outside.md"
|
|
275
|
+
outside_target.write_text("attacker-controlled")
|
|
276
|
+
|
|
277
|
+
link = project_root / "AGENTS.md"
|
|
278
|
+
link.symlink_to(outside_target)
|
|
279
|
+
|
|
280
|
+
with caplog.at_level(logging.WARNING, logger="deepagents_cli.project_utils"):
|
|
281
|
+
result = _find_project_agent_md(project_root)
|
|
282
|
+
|
|
283
|
+
assert result == []
|
|
284
|
+
assert any("outside the project root" in r.getMessage() for r in caplog.records)
|
|
285
|
+
|
|
286
|
+
def test_out_of_tree_parent_symlink_skipped(
|
|
287
|
+
self, tmp_path: Path, caplog: pytest.LogCaptureFixture
|
|
288
|
+
) -> None:
|
|
289
|
+
"""Parent directory symlink cannot bypass project-root containment."""
|
|
290
|
+
project_root = tmp_path / "project"
|
|
291
|
+
project_root.mkdir()
|
|
292
|
+
outside = tmp_path / "outside"
|
|
293
|
+
outside.mkdir()
|
|
294
|
+
outside_agent_md = outside / "AGENTS.md"
|
|
295
|
+
outside_agent_md.write_text("attacker-controlled")
|
|
296
|
+
|
|
297
|
+
(project_root / ".deepagents").symlink_to(outside, target_is_directory=True)
|
|
298
|
+
|
|
299
|
+
with caplog.at_level(logging.WARNING, logger="deepagents_cli.project_utils"):
|
|
300
|
+
result = _find_project_agent_md(project_root)
|
|
301
|
+
|
|
302
|
+
assert result == []
|
|
303
|
+
assert any("outside the project root" in r.getMessage() for r in caplog.records)
|
|
304
|
+
|
|
305
|
+
def test_broken_symlink_skipped(self, tmp_path: Path) -> None:
|
|
306
|
+
"""Symlink whose target does not exist is skipped without crashing."""
|
|
307
|
+
project_root = tmp_path / "project"
|
|
308
|
+
project_root.mkdir()
|
|
309
|
+
|
|
310
|
+
link = project_root / "AGENTS.md"
|
|
311
|
+
link.symlink_to(project_root / "missing.md")
|
|
312
|
+
|
|
313
|
+
result = _find_project_agent_md(project_root)
|
|
314
|
+
|
|
315
|
+
# `Path.exists()` returns False for broken symlinks, so the candidate
|
|
316
|
+
# is silently skipped — matches pre-existing behavior for absent files.
|
|
317
|
+
assert result == []
|
|
318
|
+
|
|
319
|
+
def test_symlink_loop_skipped(
|
|
320
|
+
self, tmp_path: Path, caplog: pytest.LogCaptureFixture
|
|
321
|
+
) -> None:
|
|
322
|
+
"""Symlink loop is skipped with a warning instead of crashing the agent."""
|
|
323
|
+
project_root = tmp_path / "project"
|
|
324
|
+
project_root.mkdir()
|
|
325
|
+
|
|
326
|
+
a = project_root / "AGENTS.md"
|
|
327
|
+
b = project_root / "loop.md"
|
|
328
|
+
a.symlink_to(b)
|
|
329
|
+
b.symlink_to(a)
|
|
330
|
+
|
|
331
|
+
with caplog.at_level(logging.WARNING, logger="deepagents_cli.project_utils"):
|
|
332
|
+
result = _find_project_agent_md(project_root)
|
|
333
|
+
|
|
334
|
+
assert result == []
|
|
335
|
+
assert any(
|
|
336
|
+
"Skipping AGENTS.md candidate" in r.getMessage() for r in caplog.records
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
def test_regular_file_unchanged_by_resolution(self, tmp_path: Path) -> None:
|
|
340
|
+
"""Regular (non-symlink) AGENTS.md returns a non-symlink, in-tree path."""
|
|
341
|
+
project_root = tmp_path / "project"
|
|
342
|
+
project_root.mkdir()
|
|
343
|
+
|
|
344
|
+
agent_md = project_root / "AGENTS.md"
|
|
345
|
+
agent_md.write_text("plain file")
|
|
346
|
+
|
|
347
|
+
result = _find_project_agent_md(project_root)
|
|
348
|
+
|
|
349
|
+
assert len(result) == 1
|
|
350
|
+
assert not result[0].is_symlink()
|
|
351
|
+
assert result[0].samefile(agent_md)
|
|
352
|
+
assert result[0].is_relative_to(project_root.resolve())
|
|
353
|
+
|
|
354
|
+
def test_non_canonical_project_root_handled(self, tmp_path: Path) -> None:
|
|
355
|
+
"""Non-canonical `project_root` (symlinked ancestor) still locates AGENTS.md.
|
|
356
|
+
|
|
357
|
+
Regression test: a symlinked `project_root` previously caused the
|
|
358
|
+
regular-file candidate to fail the absolute-vs-resolved equality check
|
|
359
|
+
and be returned as the canonical target rather than reported as missing.
|
|
360
|
+
Pin behavior so that callers passing an uncanonicalized root (common
|
|
361
|
+
when `Settings.project_root` originates from an unresolved cwd) still
|
|
362
|
+
find a regular AGENTS.md.
|
|
363
|
+
"""
|
|
364
|
+
real_root = tmp_path / "real"
|
|
365
|
+
real_root.mkdir()
|
|
366
|
+
agent_md = real_root / "AGENTS.md"
|
|
367
|
+
agent_md.write_text("instructions")
|
|
368
|
+
|
|
369
|
+
link_root = tmp_path / "link"
|
|
370
|
+
link_root.symlink_to(real_root, target_is_directory=True)
|
|
371
|
+
|
|
372
|
+
result = _find_project_agent_md(link_root)
|
|
373
|
+
|
|
374
|
+
assert len(result) == 1
|
|
375
|
+
assert not result[0].is_symlink()
|
|
376
|
+
assert result[0].samefile(agent_md)
|
|
377
|
+
assert result[0].is_relative_to(link_root.resolve())
|
|
245
378
|
|
|
246
379
|
|
|
247
380
|
class TestSettingsGetProjectAgentMdPath:
|
|
@@ -967,7 +967,7 @@ wheels = [
|
|
|
967
967
|
|
|
968
968
|
[[package]]
|
|
969
969
|
name = "deepagents"
|
|
970
|
-
version = "0.5.
|
|
970
|
+
version = "0.5.5"
|
|
971
971
|
source = { editable = "../deepagents" }
|
|
972
972
|
dependencies = [
|
|
973
973
|
{ name = "langchain" },
|
|
@@ -1023,7 +1023,7 @@ wheels = [
|
|
|
1023
1023
|
|
|
1024
1024
|
[[package]]
|
|
1025
1025
|
name = "deepagents-cli"
|
|
1026
|
-
version = "0.0.
|
|
1026
|
+
version = "0.0.45"
|
|
1027
1027
|
source = { editable = "." }
|
|
1028
1028
|
dependencies = [
|
|
1029
1029
|
{ name = "aiosqlite" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/built_in_skills/remember/SKILL.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/index.html
RENAMED
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/logo-dark.svg
RENAMED
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/deploy/frontend_dist/logo-light.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/integrations/sandbox_factory.py
RENAMED
|
File without changes
|
{deepagents_cli-0.0.44 → deepagents_cli-0.0.45}/deepagents_cli/integrations/sandbox_provider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|