netizen-cli 0.11.4__tar.gz → 0.11.5__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.
- {netizen_cli-0.11.4/netizen_cli.egg-info → netizen_cli-0.11.5}/PKG-INFO +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/__init__.py +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/callbacks.py +4 -4
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/chat_target.py +30 -7
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/fork.py +7 -5
- netizen_cli-0.11.5/netizen_cli/cards/status.py +239 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel_app.py +151 -51
- {netizen_cli-0.11.4 → netizen_cli-0.11.5/netizen_cli.egg-info}/PKG-INFO +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli.egg-info/SOURCES.txt +3 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/pyproject.toml +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/skills/netizen-user-guide/references/user-guide.md +22 -2
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cards.py +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_channel_app.py +130 -68
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_chat_target_cards.py +17 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_fork_cards.py +61 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_persistent_fork_channel.py +25 -3
- netizen_cli-0.11.5/tests/test_status_cards.py +170 -0
- netizen_cli-0.11.5/tests/test_status_commands.py +308 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_thread_naming.py +5 -3
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/MANIFEST.in +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/README.md +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/_build.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/config.example.yaml +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/__main__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/account_rate_limits.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/auth.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/credentials.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/errors.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/feishu.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/login.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/port_config.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/presentation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/queries.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/admin.css +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/admin.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/chat-picker.css +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/chat-picker.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/identity.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/index.html +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/login.html +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/static/login.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/transport.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/users.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/admin/web.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/bindings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/builtin_skills.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/controls.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/defaults.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/model_info.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/questions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/reply.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/scheduled.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cards/usage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/completion_mentions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/input_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/ports.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/question_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/reactions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/reply_presenter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/channel/topics.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/chat_avatars.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/chat_targets.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_data.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_packages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_services.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_setup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_update.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_update_restore.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/cli_update_worker.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/codex_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/completion_mention.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/database_migrations.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/defaults/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/defaults/models.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/defaults/service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/defaults/store.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/deployment/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/deployment/restart_worker.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/deployment/update_executor.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/deployment/update_protocol.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/domain.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/error_messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/experience.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/feishu_app_onboarding.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/feishu_app_permissions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/feishu_links.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/git_status.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/image_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/instance.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/lark_app.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/main.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/blocking_io.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/chat_directory.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/chat_labels.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/coordination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/management/updates.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/markdown_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/message_content.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/message_history.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/message_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/message_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/migrations/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/migrations/schema.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/migrations/v14.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/model_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/package_resources.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/projects.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/prompt_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/quoted_context.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/result_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/runtime/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/runtime/contracts.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/runtime/name_writes.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/runtime/thread_naming.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/mcp.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/models.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/scheduler.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/schedules/store.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/sdk_gap_adapter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/service_launcher.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/session_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/skill_references.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/task_text.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/terminal_cleanup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/turn_activity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/turn_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/turn_patch_children.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/turn_plan_observer.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli/user_questions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli.egg-info/dependency_links.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli.egg-info/entry_points.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli.egg-info/requires.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/netizen_cli.egg-info/top_level.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/setup.cfg +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/skills/netizen-lark/SKILL.md +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/skills/netizen-user-guide/SKILL.md +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_account_rate_limits.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_admin_update_executor_probe.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_binding_scheduled_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_bindings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_channel_fixtures.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_channel_input_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_chat_avatars.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_check_sdk.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_data.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_distribution.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_integration.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_packages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_packaging.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_services.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_setup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cli_update.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_codex_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_codex_sdk_capabilities.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_codex_sdk_upgrade_0161.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_completion_mention_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_completion_mentions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_completion_topic_delivery.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_cron_chat_targets.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_database_migrations.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_defaults_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_defaults_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_defaults_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_deployment.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_documentation_links.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_domain_experience.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_error_messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_feishu_app_onboarding.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_feishu_app_permissions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_file_pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_git_status.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_image_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_lark_app.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_lark_sdk_contract.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_main.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_markdown_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_message_content.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_message_history.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_message_material_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_message_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_migration_schema_validation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_model_info_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_model_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_name_writes.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_partial_answer_delivery.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_persistent_fork_bindings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_persistent_fork_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_child_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_feishu_completion_mention.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_feishu_partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_feishu_turn_file_card.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_persistent_fork.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_python_sdk.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_scheduled_tasks.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_sdk_completion_race.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_skill_execution.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_probe_thread_naming.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_project_delete_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_project_delete_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_project_deletion_storage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_prompt_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_question_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_question_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_question_target_parity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_quoted_context.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_release_script.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_repository_hygiene.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_result_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_resume_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_retired_deployment.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_runtime_resume_activation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_runtime_thread_naming.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_card_retry.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_mcp.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_run_now.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_scope_matrix.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedule_service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_scheduled_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_scheduled_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_scheduler.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_scheduler_presenter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_schedules_storage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_sdk_gap_adapter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_service_launcher.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_session_defaults.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_session_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_settings_projects.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_task_text.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_terminal_cleanup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_turn_activity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_turn_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_turn_patch_children.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_turn_patch_statistics.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_turn_plan_observer.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_update_executor.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_usage_card.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_usage_control.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_user_guide_skill.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.11.5}/tests/test_user_questions.py +0 -0
|
@@ -76,7 +76,7 @@ _REPEATABLE_CARD_CONTROL_NAMES = frozenset(
|
|
|
76
76
|
# one updated message. Revision-bearing and one-shot actions stay excluded.
|
|
77
77
|
_REPEATABLE_CALLBACK_INTENTS = frozenset(
|
|
78
78
|
name.value for name in _REPEATABLE_CARD_CONTROL_NAMES
|
|
79
|
-
) | {TurnFileActionName.PAGE.value}
|
|
79
|
+
) | {TurnFileActionName.PAGE.value, "status.command"}
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
class CardActionError(ValueError):
|
|
@@ -453,15 +453,15 @@ def _builder(title: str, subtitle: str, *, template: str = "blue"):
|
|
|
453
453
|
)
|
|
454
454
|
|
|
455
455
|
|
|
456
|
-
def _button_row(*buttons: dict[str, Any]) -> dict[str, Any]:
|
|
456
|
+
def _button_row(*buttons: dict[str, Any], equal_width: bool = True) -> dict[str, Any]:
|
|
457
457
|
return {
|
|
458
458
|
"tag": "column_set",
|
|
459
459
|
"flex_mode": "none",
|
|
460
460
|
"columns": [
|
|
461
461
|
{
|
|
462
462
|
"tag": "column",
|
|
463
|
-
"width": "weighted",
|
|
464
|
-
"weight": 1,
|
|
463
|
+
"width": "weighted" if equal_width else "auto",
|
|
464
|
+
**({"weight": 1} if equal_width else {}),
|
|
465
465
|
"elements": [button],
|
|
466
466
|
}
|
|
467
467
|
for button in buttons
|
|
@@ -221,7 +221,8 @@ def snapshot_capacity_selections(snapshot: ChatSearchSnapshot, page: int) -> tup
|
|
|
221
221
|
|
|
222
222
|
def chat_target_elements(*, mode_field: str, choice_field: str, id_field: str,
|
|
223
223
|
draft: ChatTargetDraft, options: Sequence[dict[str, Any]],
|
|
224
|
-
search: ChatSearchView | None = None
|
|
224
|
+
search: ChatSearchView | None = None,
|
|
225
|
+
group_details: bool = False) -> list[dict[str, Any]]:
|
|
225
226
|
"""Both inputs remain editable; the mode alone determines the saved value."""
|
|
226
227
|
if draft.mode not in {"current", "group", "id"}:
|
|
227
228
|
raise CardActionError("请选择有效的飞书聊天指定方式。")
|
|
@@ -246,11 +247,13 @@ def chat_target_elements(*, mode_field: str, choice_field: str, id_field: str,
|
|
|
246
247
|
{"text": _plain_text("填写聊天 ID"), "value": "id"},
|
|
247
248
|
], "initial_option": draft.mode},
|
|
248
249
|
]
|
|
249
|
-
|
|
250
|
+
if not group_details or search is None:
|
|
251
|
+
elements.append(_plain("选择群聊" if group_details else "群聊选择(仅选择群聊时生效)"))
|
|
250
252
|
if search is not None:
|
|
251
253
|
elements.extend([
|
|
252
254
|
{"tag": "input", "name": search.query_field, "required": False,
|
|
253
|
-
"width": "fill", "max_length": 50,
|
|
255
|
+
"width": "fill", "max_length": 50,
|
|
256
|
+
"label": _plain_text("群聊 · 群名关键词" if group_details else "查找群聊 · 群名关键词"),
|
|
254
257
|
"default_value": search.query, "placeholder": _plain_text("留空查找全部可选群")},
|
|
255
258
|
search.search_button,
|
|
256
259
|
])
|
|
@@ -261,7 +264,7 @@ def chat_target_elements(*, mode_field: str, choice_field: str, id_field: str,
|
|
|
261
264
|
elements.append(_plain(f"查找结果 · {query_label}{page_label}。修改关键词后请重新点击查找群聊。"))
|
|
262
265
|
elif choices:
|
|
263
266
|
elements.append(_plain("当前选择;如需其他群,请先查找群聊。"))
|
|
264
|
-
|
|
267
|
+
elif not group_details:
|
|
265
268
|
elements.append(_plain("请先查找群聊,再从查找结果中选择。"))
|
|
266
269
|
if choices or search is None:
|
|
267
270
|
if search is not None and draft.choice and "initial_option" in choice:
|
|
@@ -272,11 +275,31 @@ def chat_target_elements(*, mode_field: str, choice_field: str, id_field: str,
|
|
|
272
275
|
elements.append(_plain("没有找到可选群聊,请修改关键词重新查找。"))
|
|
273
276
|
if search is not None and search.navigation is not None:
|
|
274
277
|
elements.append(search.navigation)
|
|
275
|
-
elements.
|
|
278
|
+
elements.append(
|
|
276
279
|
{"tag": "input", "name": id_field, "required": False, "width": "fill",
|
|
277
|
-
"label": _plain_text("聊天 ID(仅填写 ID 时生效)"),
|
|
280
|
+
"label": _plain_text("聊天 ID" if group_details else "聊天 ID(仅填写 ID 时生效)"),
|
|
278
281
|
"default_value": draft.chat_id, "max_length": 192,
|
|
279
|
-
"placeholder": _plain_text("请输入聊天 ID(oc_…),不能为空")},
|
|
282
|
+
"placeholder": _plain_text("oc_…" if group_details else "请输入聊天 ID(oc_…),不能为空")},
|
|
283
|
+
)
|
|
284
|
+
if group_details:
|
|
285
|
+
elements.append({
|
|
286
|
+
"tag": "markdown", "text_size": "notation",
|
|
287
|
+
"content": "<font color='grey'>请使用聊天 ID,非用户 ID;单聊限与本机器人的聊天。</font>"
|
|
288
|
+
f"[获取 ID]({CHAT_ID_HELP_URL})",
|
|
289
|
+
})
|
|
290
|
+
mode, *details = elements
|
|
291
|
+
return [mode, {
|
|
292
|
+
"tag": "column_set", "flex_mode": "none", "background_style": "grey-50",
|
|
293
|
+
"columns": [{
|
|
294
|
+
"tag": "column", "width": "weighted", "weight": 1,
|
|
295
|
+
"padding": "12px", "vertical_spacing": "8px",
|
|
296
|
+
"elements": [{
|
|
297
|
+
"tag": "markdown", "text_size": "notation",
|
|
298
|
+
"content": "<font color='grey'>当前聊天无需填写;其他方式只需填写对应项。</font>",
|
|
299
|
+
}, *details],
|
|
300
|
+
}],
|
|
301
|
+
}]
|
|
302
|
+
elements.extend([
|
|
280
303
|
_plain("仅指定方式对应的输入生效;填写 ID 时不能为空。聊天 ID 不是用户 ID;单聊请选择与本机器人的聊天。"),
|
|
281
304
|
{"tag": "markdown", "content": f"[如何获取聊天 ID]({CHAT_ID_HELP_URL})"},
|
|
282
305
|
])
|
|
@@ -293,11 +293,11 @@ def fork_form_card(scope: FeishuScope, source: ForkSource, *, source_title: str,
|
|
|
293
293
|
{"tag": "input", "name": _NAME_FIELD, "width": "fill",
|
|
294
294
|
"label": _plain_text("分支名称"), "default_value": draft_name,
|
|
295
295
|
"max_length": MAX_THREAD_NAME_CHARS},
|
|
296
|
-
|
|
296
|
+
{"tag": "markdown", "content": "**分支位置**\n<font color='grey'>在所选聊天中新建分支话题</font>"},
|
|
297
297
|
*chat_target_elements(
|
|
298
298
|
mode_field=_MODE_FIELD, choice_field=_TARGET_FIELD, id_field=_ID_FIELD,
|
|
299
299
|
draft=ChatTargetDraft(target.mode, selection, target.chat_id), options=page_options,
|
|
300
|
-
search=search,
|
|
300
|
+
search=search, group_details=True,
|
|
301
301
|
),
|
|
302
302
|
_button(scope, source, "创建分支", "create"),
|
|
303
303
|
]
|
|
@@ -327,14 +327,16 @@ def fork_status_card(*, name: str, source_title: str, project_alias: str,
|
|
|
327
327
|
topic_url: str | None = None, detail: str | None = None,
|
|
328
328
|
native_thread_id: str | None = None,
|
|
329
329
|
binding_saved: bool = False) -> OutboundCard:
|
|
330
|
-
"""
|
|
330
|
+
"""Status pages cannot resubmit; only the source receipt gets a topic URL."""
|
|
331
331
|
titles = {"creating": "会话分支创建中", "success": "会话分支已创建", "failed": "会话分支创建未完成"}
|
|
332
|
-
|
|
332
|
+
title, subtitle = (name, titles[status]) if status == "success" else (titles[status], name)
|
|
333
|
+
builder = _builder(title, subtitle, template="red" if status == "failed" else "blue")
|
|
333
334
|
builder.raw(_plain(f"来源:{source_title}\nProject:{project_alias}"))
|
|
334
335
|
if status == "creating":
|
|
335
336
|
builder.raw(_notice("请等待创建完成后再发送消息。"))
|
|
336
337
|
elif status == "success":
|
|
337
|
-
|
|
338
|
+
location = "新话题" if topic_url else "本话题"
|
|
339
|
+
builder.raw(_plain(f"在{location}中发送消息即可继续。两个会话独立管理,共享项目文件;来源会话保持不变。"))
|
|
338
340
|
if topic_url:
|
|
339
341
|
builder.raw({"tag": "button", "text": _plain_text("进入新话题"), "type": "primary_filled",
|
|
340
342
|
"behaviors": [{"type": "open_url", "default_url": topic_url}]})
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""Session snapshots with a closed set of session-bound command aliases."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from collections.abc import Mapping
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from lark_channel import OutboundCard
|
|
11
|
+
|
|
12
|
+
from ..domain import ControlIntent, ControlName, FeishuScope
|
|
13
|
+
from .callbacks import (
|
|
14
|
+
CardActionError, _builder, _button_row, _repeatable_callback_button, _plain,
|
|
15
|
+
_plain_text, _required_string,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_STATUS_COMMAND = "status.command"
|
|
20
|
+
_STATUS_CARD_MAX_BYTES = 55_000
|
|
21
|
+
_BINDING_COMMANDS = (
|
|
22
|
+
("查看状态", ControlName.STATUS, ()),
|
|
23
|
+
("停止", ControlName.STOP, ()),
|
|
24
|
+
("会话配置", ControlName.CONFIG, ()),
|
|
25
|
+
("会话列表", ControlName.SESSIONS, ()),
|
|
26
|
+
)
|
|
27
|
+
_SIDE_COMMANDS = (
|
|
28
|
+
("查看状态", ControlName.STATUS, ()),
|
|
29
|
+
("停止", ControlName.STOP, ()),
|
|
30
|
+
("结束临时会话", ControlName.SIDE, ("close",)),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass(frozen=True, slots=True)
|
|
35
|
+
class StatusCommandAction:
|
|
36
|
+
target_kind: str
|
|
37
|
+
target_id: str
|
|
38
|
+
command: ControlIntent
|
|
39
|
+
snapshot: dict[str, Any]
|
|
40
|
+
|
|
41
|
+
def card(self) -> OutboundCard:
|
|
42
|
+
"""Renew transport nonces while preserving the original display snapshot."""
|
|
43
|
+
if self.target_kind == "side":
|
|
44
|
+
return side_status_card(scope=self.command.scope, side_id=self.target_id, **self.snapshot)
|
|
45
|
+
return session_status_card(scope=self.command.scope, binding_id=self.target_id, **self.snapshot)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def is_status_command(value: Any) -> bool:
|
|
49
|
+
return isinstance(value, Mapping) and value.get("intent") == _STATUS_COMMAND
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def decode_status_command(
|
|
53
|
+
*, scope: FeishuScope, message_id: str, sender_id: str, value: Any,
|
|
54
|
+
) -> StatusCommandAction:
|
|
55
|
+
fields = {"v", "intent", "scope", "target_kind", "target_id", "command", "snapshot"}
|
|
56
|
+
if isinstance(value, Mapping):
|
|
57
|
+
value = {key: item for key, item in value.items() if key != "nonce"}
|
|
58
|
+
if not isinstance(value, Mapping) or set(value) != fields:
|
|
59
|
+
raise CardActionError("状态卡操作无效,请重新发送 /status。")
|
|
60
|
+
if type(value["v"]) is not int or value["v"] != 1 or not is_status_command(value):
|
|
61
|
+
raise CardActionError("状态卡版本已过期,请重新发送 /status。")
|
|
62
|
+
if value["scope"] != scope.key:
|
|
63
|
+
raise CardActionError("状态卡与当前聊天或话题不一致,本次未执行。")
|
|
64
|
+
target_kind = value["target_kind"]
|
|
65
|
+
if target_kind not in ("binding", "side"):
|
|
66
|
+
raise CardActionError("状态卡会话类型无效,请重新发送 /status。")
|
|
67
|
+
commands = _SIDE_COMMANDS if target_kind == "side" else _BINDING_COMMANDS
|
|
68
|
+
selected = next((item for item in commands if item[1].value == value["command"]), None)
|
|
69
|
+
if selected is None:
|
|
70
|
+
raise CardActionError("状态卡不支持这个命令,请重新发送 /status。")
|
|
71
|
+
return StatusCommandAction(
|
|
72
|
+
target_kind=target_kind,
|
|
73
|
+
target_id=_required_string(value["target_id"], "target_id"),
|
|
74
|
+
command=ControlIntent(
|
|
75
|
+
scope=scope, source_id=_required_string(message_id, "message_id"),
|
|
76
|
+
sender_id=_required_string(sender_id, "sender_id"),
|
|
77
|
+
name=selected[1], arguments=selected[2],
|
|
78
|
+
),
|
|
79
|
+
snapshot=_decode_snapshot(target_kind, value["snapshot"]),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _decode_snapshot(target_kind: str, value: Any) -> dict[str, Any]:
|
|
84
|
+
# Only inert display strings cross the callback. Never accept raw card JSON,
|
|
85
|
+
# and never use these historical labels as command admission or identity.
|
|
86
|
+
if target_kind == "side":
|
|
87
|
+
strings = {"short_id", "parent_short_id", "state", "turn_state"}
|
|
88
|
+
lines = {"git_branch_lines": 1}
|
|
89
|
+
else:
|
|
90
|
+
strings = {"short_id", "project_alias", "native_thread_id", "state", "context_window_line", "subscription_line"}
|
|
91
|
+
lines = {"metadata_lines": 2, "git_branch_lines": 1, "context_mode_lines": 4, "model_lines": 4, "progress_lines": 32}
|
|
92
|
+
if not isinstance(value, Mapping) or set(value) != strings | lines.keys():
|
|
93
|
+
raise CardActionError("状态卡展示快照无效,请重新发送 /status。")
|
|
94
|
+
if any(not isinstance(value[key], str) for key in strings):
|
|
95
|
+
raise CardActionError("状态卡展示文字无效,请重新发送 /status。")
|
|
96
|
+
for key, limit in lines.items():
|
|
97
|
+
items = value[key]
|
|
98
|
+
if (not isinstance(items, (list, tuple)) or len(items) > limit
|
|
99
|
+
or any(not isinstance(item, str) for item in items)):
|
|
100
|
+
raise CardActionError("状态卡展示字段无效,请重新发送 /status。")
|
|
101
|
+
if target_kind == "binding" and (len(value["metadata_lines"]) != 2 or len(value["model_lines"]) != 4):
|
|
102
|
+
raise CardActionError("状态卡展示字段缺失,请重新发送 /status。")
|
|
103
|
+
return dict(value)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _command_buttons(
|
|
107
|
+
scope: FeishuScope, target_kind: str, target_id: str, snapshot: dict[str, Any],
|
|
108
|
+
) -> dict[str, Any]:
|
|
109
|
+
commands = _SIDE_COMMANDS if target_kind == "side" else _BINDING_COMMANDS
|
|
110
|
+
return _button_row(*(
|
|
111
|
+
_repeatable_callback_button(label=label, value={
|
|
112
|
+
"v": 1, "intent": _STATUS_COMMAND, "scope": scope.key,
|
|
113
|
+
"target_kind": target_kind, "target_id": target_id,
|
|
114
|
+
"command": command.value,
|
|
115
|
+
"snapshot": snapshot,
|
|
116
|
+
})
|
|
117
|
+
for label, command, _arguments in commands
|
|
118
|
+
), equal_width=False)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _status_card(card: dict[str, Any]) -> OutboundCard:
|
|
122
|
+
# The snapshot appears in each button. Check the complete transport payload,
|
|
123
|
+
# including non-ASCII text, rather than just the visible body or one action.
|
|
124
|
+
if len(json.dumps(card, ensure_ascii=False).encode("utf-8")) > _STATUS_CARD_MAX_BYTES:
|
|
125
|
+
raise CardActionError("状态卡内容过长,暂不能展示;可直接使用 /stop、/config 或 /sessions。")
|
|
126
|
+
return OutboundCard(card=card)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def session_status_card(
|
|
130
|
+
*,
|
|
131
|
+
scope: FeishuScope,
|
|
132
|
+
binding_id: str,
|
|
133
|
+
short_id: str,
|
|
134
|
+
project_alias: str,
|
|
135
|
+
native_thread_id: str,
|
|
136
|
+
state: str,
|
|
137
|
+
metadata_lines: tuple[str, str],
|
|
138
|
+
git_branch_lines: tuple[str, ...],
|
|
139
|
+
context_window_line: str,
|
|
140
|
+
context_mode_lines: tuple[str, ...],
|
|
141
|
+
model_lines: tuple[str, str, str, str],
|
|
142
|
+
progress_lines: tuple[str, ...],
|
|
143
|
+
subscription_line: str,
|
|
144
|
+
) -> OutboundCard:
|
|
145
|
+
builder = _builder("当前会话", metadata_lines[0], template=_state_template(state))
|
|
146
|
+
builder.raw(_columns(f"Project:{project_alias}", f"状态:{state}"))
|
|
147
|
+
builder.raw(_plain(metadata_lines[1]))
|
|
148
|
+
for line in git_branch_lines:
|
|
149
|
+
builder.raw(_plain(line))
|
|
150
|
+
|
|
151
|
+
builder.raw({"tag": "hr"})
|
|
152
|
+
builder.markdown("**模型配置**")
|
|
153
|
+
builder.raw(_plain(model_lines[0]))
|
|
154
|
+
builder.raw(_columns(model_lines[1], model_lines[2]))
|
|
155
|
+
builder.raw(_plain(model_lines[3]))
|
|
156
|
+
|
|
157
|
+
builder.raw({"tag": "hr"})
|
|
158
|
+
builder.raw(_plain(context_window_line))
|
|
159
|
+
for line in context_mode_lines:
|
|
160
|
+
builder.raw(_plain(line))
|
|
161
|
+
if progress_lines:
|
|
162
|
+
builder.raw({"tag": "hr"})
|
|
163
|
+
builder.markdown("**任务进展**")
|
|
164
|
+
builder.raw(_plain("\n".join(progress_lines[1:])))
|
|
165
|
+
|
|
166
|
+
builder.raw({
|
|
167
|
+
"tag": "collapsible_panel",
|
|
168
|
+
"expanded": False,
|
|
169
|
+
"header": {"title": _plain_text("会话详情与订阅")},
|
|
170
|
+
"elements": [_plain("\n".join((
|
|
171
|
+
f"会话:{short_id}",
|
|
172
|
+
f"Native Thread:{native_thread_id}",
|
|
173
|
+
subscription_line,
|
|
174
|
+
)))],
|
|
175
|
+
})
|
|
176
|
+
builder.raw(_command_buttons(scope, "binding", binding_id, {
|
|
177
|
+
"short_id": short_id, "project_alias": project_alias,
|
|
178
|
+
"native_thread_id": native_thread_id, "state": state,
|
|
179
|
+
"metadata_lines": metadata_lines, "git_branch_lines": git_branch_lines,
|
|
180
|
+
"context_window_line": context_window_line, "context_mode_lines": context_mode_lines,
|
|
181
|
+
"model_lines": model_lines, "progress_lines": progress_lines,
|
|
182
|
+
"subscription_line": subscription_line,
|
|
183
|
+
}))
|
|
184
|
+
builder.markdown("<font color='grey'>本次查询快照 · 按钮与对应命令的处理方式相同</font>")
|
|
185
|
+
return _status_card(builder.to_dict())
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def side_status_card(
|
|
189
|
+
*,
|
|
190
|
+
scope: FeishuScope,
|
|
191
|
+
side_id: str,
|
|
192
|
+
short_id: str,
|
|
193
|
+
parent_short_id: str,
|
|
194
|
+
state: str,
|
|
195
|
+
turn_state: str,
|
|
196
|
+
git_branch_lines: tuple[str, ...],
|
|
197
|
+
) -> OutboundCard:
|
|
198
|
+
# A Side's lifecycle and current Turn are distinct observations.
|
|
199
|
+
template_state = turn_state if state == "open" else state
|
|
200
|
+
builder = _builder("当前 Side", f"Side:{short_id}", template=_state_template(template_state))
|
|
201
|
+
builder.raw(_columns(f"状态:{state}", f"当前 Turn:{turn_state}"))
|
|
202
|
+
builder.raw(_plain(f"Parent 会话:{parent_short_id}"))
|
|
203
|
+
for line in git_branch_lines:
|
|
204
|
+
builder.raw(_plain(line))
|
|
205
|
+
builder.raw({"tag": "hr"})
|
|
206
|
+
builder.raw(_plain("空闲 2 小时后自动结束;运行中的 Turn 不计入空闲时间。"))
|
|
207
|
+
builder.raw(_command_buttons(scope, "side", side_id, {
|
|
208
|
+
"short_id": short_id, "parent_short_id": parent_short_id,
|
|
209
|
+
"state": state, "turn_state": turn_state, "git_branch_lines": git_branch_lines,
|
|
210
|
+
}))
|
|
211
|
+
builder.markdown("<font color='grey'>本次查询快照 · 按钮与对应命令的处理方式相同</font>")
|
|
212
|
+
return _status_card(builder.to_dict())
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _columns(*values: str) -> dict[str, Any]:
|
|
216
|
+
return {
|
|
217
|
+
"tag": "column_set",
|
|
218
|
+
"flex_mode": "none",
|
|
219
|
+
"background_style": "grey-50",
|
|
220
|
+
"columns": [
|
|
221
|
+
{
|
|
222
|
+
"tag": "column", "width": "weighted", "weight": 1,
|
|
223
|
+
"padding": "8px", "elements": [_plain(value)],
|
|
224
|
+
}
|
|
225
|
+
for value in values
|
|
226
|
+
],
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _state_template(state: str) -> str:
|
|
231
|
+
if state in {"idle", "open", "goal-complete"}:
|
|
232
|
+
return "green"
|
|
233
|
+
if state in {"running", "goal-starting", "goal-running", "compacting", "creating"}:
|
|
234
|
+
return "blue"
|
|
235
|
+
if state == "failed":
|
|
236
|
+
return "red"
|
|
237
|
+
if state in {"closed", "expired"}:
|
|
238
|
+
return "grey"
|
|
239
|
+
return "orange"
|