netizen-cli 0.13.1__tar.gz → 0.13.2__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.13.1/netizen_cli.egg-info → netizen_cli-0.13.2}/PKG-INFO +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/__init__.py +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/admin.css +27 -10
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/admin.js +100 -7
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/index.html +6 -0
- netizen_cli-0.13.2/netizen_cli/admin/static/login.html +41 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/web.py +4 -4
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/bindings.py +2 -2
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/controls.py +94 -72
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/defaults.py +166 -14
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel_app.py +51 -7
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/database_migrations.py +5 -1
- netizen_cli-0.13.2/netizen_cli/defaults/models.py +85 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/defaults/service.py +76 -9
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/defaults/store.py +32 -4
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/service.py +68 -1
- netizen_cli-0.13.2/netizen_cli/migrations/v16.py +104 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2/netizen_cli.egg-info}/PKG-INFO +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli.egg-info/SOURCES.txt +3 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/pyproject.toml +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/sessions.md +25 -7
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/user-guide.md +2 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cards.py +41 -5
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_channel_app.py +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_data.py +8 -6
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_database_migrations.py +4 -4
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_defaults_cards.py +163 -5
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_defaults_channel.py +120 -0
- netizen_cli-0.13.2/tests/test_defaults_worktree_channel.py +374 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_migration_schema_validation.py +1 -1
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_defaults.py +153 -0
- netizen_cli-0.13.2/tests/test_session_defaults_migration.py +106 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_storage.py +1 -1
- netizen_cli-0.13.1/netizen_cli/admin/static/login.html +0 -30
- netizen_cli-0.13.1/netizen_cli/defaults/models.py +0 -35
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/MANIFEST.in +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/README.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/_build.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/config.example.yaml +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/__main__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/account_rate_limits.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/auth.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/credentials.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/errors.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/feishu.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/login.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/port_config.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/presentation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/queries.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/chat-picker.css +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/chat-picker.js +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/identity.js +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/login.js +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/session-access.js +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/static/worktrees.js +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/transport.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/admin/users.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/builtin_skills.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/callbacks.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/chat_target.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/fork.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/model_info.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/pagination.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/questions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/reply.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/scheduled.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/session_ids.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/status.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cards/usage.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/completion_mentions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/input_preparation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/messages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/ports.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/question_inputs.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/reactions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/reply_presenter.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/session_pages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/channel/topics.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/chat_avatars.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/chat_targets.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_data.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_packages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_services.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_setup.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_update.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_update_restore.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/cli_update_worker.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/codex_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/completion_mention.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/defaults/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/deployment/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/deployment/restart_worker.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/deployment/update_executor.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/deployment/update_protocol.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/domain.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/error_messages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/experience.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/feishu_app_onboarding.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/feishu_app_permissions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/feishu_links.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/git_status.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/image_inputs.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/instance.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/lark_app.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/main.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/blocking_io.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/chat_directory.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/chat_labels.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/coordination.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/management/updates.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/markdown_images.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/mcp_transport.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/message_content.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/message_history.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/message_preparation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/message_projection.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/migrations/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/migrations/schema.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/migrations/v14.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/migrations/v15.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/model_settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/package_resources.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/pagination.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/partial_answers.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/projects.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/prompt_projection.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/quoted_context.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/result_images.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/runtime/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/runtime/contracts.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/runtime/name_writes.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/runtime/thread_naming.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/mcp.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/models.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/scheduler.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/service.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/schedules/store.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sdk_gap_adapter.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/service_launcher.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/session_inventory.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/session_settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/__init__.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/delegation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/errors.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/mcp.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/policy.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/presentation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/schema.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/sessions/service.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/skill_references.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/task_text.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/terminal_cleanup.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/thread_history.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/turn_activity.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/turn_files.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/turn_patch_children.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/turn_plan_observer.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/user_questions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/errors.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/git.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/models.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/service.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli/worktrees/store.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli.egg-info/dependency_links.txt +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli.egg-info/entry_points.txt +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli.egg-info/requires.txt +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/netizen_cli.egg-info/top_level.txt +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/setup.cfg +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-lark/SKILL.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/SKILL.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/admin.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/commands.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/concepts.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/faq.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/feedback-and-files.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/fork-side-goal.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/messages.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/native-capabilities.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/scheduled-tasks.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/session-collaboration.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/skills/netizen-user-guide/references/status-and-control.md +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_account_rate_limits.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_admin_update_executor_probe.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_binding_scheduled_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_bindings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_channel_fixtures.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_channel_input_preparation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_chat_avatars.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_chat_target_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_check_sdk.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_distribution.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_integration.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_packages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_packaging.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_services.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_setup.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cli_update.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_codex_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_codex_sdk_capabilities.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_codex_sdk_upgrade_0161.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_codex_sdk_upgrade_0163.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_completion_mention_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_completion_mentions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_completion_topic_delivery.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_cron_chat_targets.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_defaults_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_deployment.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_documentation_links.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_domain_experience.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_error_messages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_feishu_app_onboarding.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_feishu_app_permissions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_file_pagination.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_fork_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_git_status.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_goal_reply_separation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_image_inputs.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_lark_app.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_lark_sdk_contract.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_main.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_markdown_images.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_message_content.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_message_history.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_message_material_inputs.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_message_preparation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_model_info_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_model_settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_name_writes.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_pagination.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_partial_answer_delivery.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_partial_answers.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_persistent_fork_bindings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_persistent_fork_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_persistent_fork_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_child_files.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_feishu_completion_mention.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_feishu_partial_answers.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_feishu_turn_file_card.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_persistent_fork.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_python_sdk.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_scheduled_tasks.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_sdk_completion_race.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_sdk_response_recovery.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_skill_execution.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_probe_thread_naming.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_project_delete_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_project_delete_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_project_deletion_storage.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_prompt_projection.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_question_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_question_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_question_target_parity.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_quoted_context.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_release_script.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_repository_hygiene.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_result_images.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_resume_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_retired_deployment.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_runtime_resume_activation.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_runtime_thread_naming.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_card_retry.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_mcp.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_run_now.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_scope_matrix.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedule_service.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_scheduled_channel.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_scheduled_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_scheduler.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_scheduler_presenter.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_schedules_storage.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_sdk_gap_adapter.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_service_launcher.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_card_pages.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_collaboration_app.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_external_runtime.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_id_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_policy.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_session_tools.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_settings_projects.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_status_cards.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_status_commands.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_task_text.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_terminal_cleanup.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_thread_history.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_thread_naming.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_turn_activity.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_turn_files.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_turn_patch_children.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_turn_patch_statistics.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_turn_plan_observer.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_update_executor.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_usage_card.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_usage_control.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_user_guide_skill.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_user_questions.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_channel_cwd.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_git.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_new.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_runtime_cwd.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_service.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_settings.py +0 -0
- {netizen_cli-0.13.1 → netizen_cli-0.13.2}/tests/test_worktree_tools_integration.py +0 -0
|
@@ -200,11 +200,32 @@ button:disabled { cursor: default; opacity: .48; }
|
|
|
200
200
|
.service-restart p { line-height: 1.6; }
|
|
201
201
|
#updates a { color: var(--blue); }
|
|
202
202
|
button:focus-visible, input:focus-visible, select:focus-visible { outline: 3px solid #8cb4ff; outline-offset: 2px; }
|
|
203
|
-
.login-body { min-height: 100vh; display: grid; place-items: center; padding:
|
|
204
|
-
.login-card { width: min(420px, 100%);
|
|
205
|
-
.login-
|
|
206
|
-
.login-
|
|
207
|
-
.login-
|
|
203
|
+
.login-body { min-height: 100vh; min-height: 100svh; display: grid; place-items: center; padding: clamp(12px, 3vw, 24px); }
|
|
204
|
+
.login-card { width: min(420px, 100%); min-width: 0; margin: 0; padding: clamp(20px, 5vw, 28px); border: 1px solid var(--line); border-radius: 14px; background: var(--paper); box-shadow: 0 8px 28px rgb(23 39 68 / 6%); font-size: 14px; line-height: 1.6; }
|
|
205
|
+
.login-heading h1 { font-size: 28px; line-height: 1.2; }
|
|
206
|
+
.login-heading p { margin: 8px 0 0; color: var(--muted); font-size: 13px; }
|
|
207
|
+
.login-instance { margin: 20px 0; padding: 10px 12px; border-radius: 8px; background: var(--wash); }
|
|
208
|
+
.login-instance > span { color: var(--muted); font-size: 12px; }
|
|
209
|
+
.login-instance .instance-root { margin: 3px 0 0; line-height: 1.5; }
|
|
210
|
+
.login-card .login-button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 44px; border: 1px solid var(--line); border-radius: 8px; padding: 10px 14px; background: var(--paper); color: var(--ink); font-size: 14px; line-height: 22px; font-weight: 500; text-align: center; text-decoration: none; }
|
|
211
|
+
.login-card .login-primary { width: 100%; border-color: var(--blue); background: var(--blue); color: white; }
|
|
212
|
+
.login-card .login-cancel { border-color: transparent; background: transparent; color: var(--muted); }
|
|
213
|
+
.login-card .login-secondary:hover:not(:disabled), .login-card .login-cancel:hover:not(:disabled) { background: var(--wash); }
|
|
214
|
+
.login-card .login-button:focus-visible { outline: 3px solid #8cb4ff; outline-offset: 2px; }
|
|
215
|
+
.login-scan { margin-top: 20px; }
|
|
216
|
+
.login-scan:has(.login-qr[hidden]) { display: none; }
|
|
217
|
+
.login-divider { display: flex; align-items: center; gap: 12px; margin: 0; color: var(--muted); font-size: 12px; }
|
|
218
|
+
.login-divider::before, .login-divider::after { content: ""; flex: 1; border-top: 1px solid var(--line); }
|
|
219
|
+
.login-qr { display: block; width: min(208px, 100%); height: auto; margin: 12px auto 0; }
|
|
220
|
+
.login-user-code { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; color: var(--muted); font-size: 12px; }
|
|
221
|
+
#login-code { min-width: 0; border-radius: 6px; padding: 4px 8px; background: var(--wash); color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 16px; letter-spacing: .04em; overflow-wrap: anywhere; }
|
|
222
|
+
.login-deadline { margin: 6px 0 0; color: var(--muted); font-size: 12px; text-align: center; }
|
|
223
|
+
.login-deadline:empty { display: none; }
|
|
224
|
+
.login-card .status { margin: 16px 0 0; font-size: 13px; text-align: center; overflow-wrap: anywhere; }
|
|
225
|
+
.login-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
|
|
226
|
+
.login-actions:not(:has(> :not([hidden]))) { display: none; }
|
|
227
|
+
#login-retry { margin-top: 16px; }
|
|
228
|
+
.login-safety { margin: 20px 0 0; border-top: 1px solid var(--line); padding-top: 14px; color: var(--muted); font-size: 12px; }
|
|
208
229
|
@media (max-width: 650px) {
|
|
209
230
|
.topbar { padding: 12px 18px; }
|
|
210
231
|
.tabs { overflow-x: auto; padding: 10px 14px; }
|
|
@@ -428,13 +449,9 @@ body.schedule-detail-open { overflow: hidden; }
|
|
|
428
449
|
.identity-panel { max-width: 480px; border: 1px solid var(--line); border-radius: 14px; margin-bottom: 24px; padding: 20px; color: var(--ink); }
|
|
429
450
|
.identity-panel h3 { margin: 0; }
|
|
430
451
|
.identity-panel > p { margin: 20px 0; }
|
|
431
|
-
.identity-panel-actions
|
|
452
|
+
.identity-panel-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 10px; }
|
|
432
453
|
#admin-selector { min-height: 48px; margin: 18px 0; }
|
|
433
454
|
#admin-user-selection { margin-top: 20px; }
|
|
434
|
-
.login-qr { display: block; width: min(240px, 100%); height: auto; margin: 18px auto; }
|
|
435
|
-
.login-link { display: inline-block; margin-bottom: 14px; }
|
|
436
|
-
.login-actions { justify-content: flex-start; margin: 18px 0; }
|
|
437
|
-
#login-code { overflow-wrap: anywhere; }
|
|
438
455
|
@media (max-width: 600px) {
|
|
439
456
|
.topbar { align-items: flex-start; gap: 12px; flex-wrap: wrap; }
|
|
440
457
|
.topbar-brand { flex-basis: 100%; }
|
|
@@ -2565,12 +2565,13 @@ function renderDefaultSettings() {
|
|
|
2565
2565
|
const model = renderSessionSettingsFields(defaultsInput, settings, editor.models, editor.contextAvailable);
|
|
2566
2566
|
defaultsInput("context-field").hidden = editor.kind === "chat"
|
|
2567
2567
|
&& chatTarget("defaults").kind() === "p2p" && settings.message_context_mode === "current-only";
|
|
2568
|
+
renderDefaultWorkspace();
|
|
2568
2569
|
const notes = [editor.loading ? "正在读取配置…" : "", editor.sourceNote, editor.error, editor.catalogError];
|
|
2569
2570
|
if (turn && !model) notes.push("已保存的模型当前不可用,选择保持不变;可显式选择其他模型。");
|
|
2570
2571
|
if (editor.contextAvailable === false) notes.push("单聊不支持补齐未读上下文,请使用当前消息。");
|
|
2571
2572
|
defaultsInput("note").textContent = notes.filter(Boolean).join(" ");
|
|
2572
2573
|
defaultsInput("note").classList.toggle("error", Boolean(editor.error));
|
|
2573
|
-
defaultsInput("save").disabled = defaultsBusy || editor.loading || !editor.action;
|
|
2574
|
+
defaultsInput("save").disabled = defaultsBusy || editor.loading || !editor.action || !defaultWorkspaceAvailable();
|
|
2574
2575
|
defaultsInput("save").textContent = defaultsBusy ? "保存中…" : "保存";
|
|
2575
2576
|
defaultsInput("editor").setAttribute("aria-busy", String(defaultsBusy || editor.loading));
|
|
2576
2577
|
}
|
|
@@ -2595,6 +2596,77 @@ function renderDefaultProject(project) {
|
|
|
2595
2596
|
])], project);
|
|
2596
2597
|
}
|
|
2597
2598
|
|
|
2599
|
+
function defaultWorkspaceAvailable() {
|
|
2600
|
+
const editor = defaultsEditor;
|
|
2601
|
+
if (!editor || editor.workspace.mode === "project") return true;
|
|
2602
|
+
const options = editor.workspaceOptions;
|
|
2603
|
+
if (!options?.isGit || options.projectAlias !== defaultsInput("project").value) return false;
|
|
2604
|
+
return editor.workspace.mode === "new"
|
|
2605
|
+
|| options.items.some((item) => item.id === editor.workspace.worktree_id);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
function renderDefaultWorkspace() {
|
|
2609
|
+
const editor = defaultsEditor;
|
|
2610
|
+
const workspace = editor.workspace;
|
|
2611
|
+
const options = editor.workspaceOptions;
|
|
2612
|
+
const available = options?.isGit && options.projectAlias === defaultsInput("project").value;
|
|
2613
|
+
defaultsInput("workspace").value = workspace.mode;
|
|
2614
|
+
for (const option of defaultsInput("workspace").querySelectorAll("option")) {
|
|
2615
|
+
option.disabled = option.value !== "project" && (!available || option.value === "existing" && !options.items.length);
|
|
2616
|
+
}
|
|
2617
|
+
defaultsInput("worktree-field").hidden = workspace.mode !== "existing";
|
|
2618
|
+
defaultsInput("workspace-ref-field").hidden = workspace.mode !== "new";
|
|
2619
|
+
scheduleSelectOptions(defaultsInput("worktree"), [["", "选择受管 Worktree"],
|
|
2620
|
+
...(available ? options.items : []).map((item) => [item.id, `${item.cwd} · ${item.branch || "detached"} · ${item.id}`])],
|
|
2621
|
+
workspace.worktree_id || "");
|
|
2622
|
+
defaultsInput("worktree").required = workspace.mode === "existing";
|
|
2623
|
+
defaultsInput("workspace-ref").value = workspace.ref || "";
|
|
2624
|
+
defaultsInput("workspace-refs").replaceChildren();
|
|
2625
|
+
for (const branch of options?.branches || []) {
|
|
2626
|
+
const option = document.createElement("option");
|
|
2627
|
+
option.value = branch.ref;
|
|
2628
|
+
option.textContent = branch.name;
|
|
2629
|
+
defaultsInput("workspace-refs").append(option);
|
|
2630
|
+
}
|
|
2631
|
+
const notes = [];
|
|
2632
|
+
if (editor.workspaceError) notes.push(editor.workspaceError);
|
|
2633
|
+
else if (options?.isGit === false) notes.push("该 Project 不是 Git 仓库,只支持项目目录。");
|
|
2634
|
+
else if (!defaultsInput("project").value) notes.push("先选择 Project,再选择工作区策略。");
|
|
2635
|
+
if (workspace.mode === "existing") {
|
|
2636
|
+
notes.push("新会话共享所选 Worktree 的文件和分支;删除或失效后保留此配置,自动创建会话时明确报错。");
|
|
2637
|
+
if (!editor.loading && !defaultWorkspaceAvailable()) notes.push("所选 Worktree 当前不可用,请重新选择;不会切回项目目录。");
|
|
2638
|
+
} else if (workspace.mode === "new") {
|
|
2639
|
+
notes.push("每次自动创建新会话时创建一次 detached Worktree;后续消息复用。留空使用创建时 Project 的 HEAD,保存配置不创建目录。");
|
|
2640
|
+
if (!editor.loading && !available) notes.push("当前无法使用新建 Worktree 策略,请检查 Project。");
|
|
2641
|
+
} else notes.push("新会话使用 Project 的项目目录。");
|
|
2642
|
+
defaultsInput("workspace-help").textContent = notes.join(" ");
|
|
2643
|
+
defaultsInput("workspace-help").classList.toggle("error", !editor.loading && !defaultWorkspaceAvailable());
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
async function changeDefaultProject() {
|
|
2647
|
+
const editor = defaultsEditor;
|
|
2648
|
+
if (!editor || defaultsBusy) return;
|
|
2649
|
+
editor.workspace = { mode: "project" };
|
|
2650
|
+
editor.workspaceOptions = null;
|
|
2651
|
+
editor.workspaceError = "";
|
|
2652
|
+
await loadDefaultOptions();
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
function changeDefaultWorkspace(field) {
|
|
2656
|
+
const editor = defaultsEditor;
|
|
2657
|
+
if (!editor || editor.loading || defaultsBusy) return;
|
|
2658
|
+
if (field === "workspace") {
|
|
2659
|
+
const mode = defaultsInput("workspace").value;
|
|
2660
|
+
editor.workspace = mode === "existing" ? { mode, worktree_id: "" } : { mode };
|
|
2661
|
+
} else if (field === "worktree") {
|
|
2662
|
+
editor.workspace = { mode: "existing", worktree_id: defaultsInput(field).value };
|
|
2663
|
+
} else {
|
|
2664
|
+
const ref = defaultsInput(field).value.trim();
|
|
2665
|
+
editor.workspace = { mode: "new", ...(ref ? { ref } : {}) };
|
|
2666
|
+
}
|
|
2667
|
+
renderDefaultSettings();
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2598
2670
|
async function loadDefaultOptions(resolveChat = false) {
|
|
2599
2671
|
const editor = defaultsEditor;
|
|
2600
2672
|
if (!editor) return;
|
|
@@ -2603,6 +2675,8 @@ async function loadDefaultOptions(resolveChat = false) {
|
|
|
2603
2675
|
const chatId = editor.kind === "chat" ? defaultsInput("chat").value.trim() : "";
|
|
2604
2676
|
editor.loading = true;
|
|
2605
2677
|
editor.error = "";
|
|
2678
|
+
editor.workspaceOptions = null;
|
|
2679
|
+
editor.workspaceError = "";
|
|
2606
2680
|
renderDefaultSettings();
|
|
2607
2681
|
try {
|
|
2608
2682
|
let view = null;
|
|
@@ -2614,10 +2688,12 @@ async function loadDefaultOptions(resolveChat = false) {
|
|
|
2614
2688
|
const effective = view.exact || view.effective;
|
|
2615
2689
|
if (effective) {
|
|
2616
2690
|
editor.settings = structuredClone(effective.session_settings);
|
|
2691
|
+
editor.workspace = structuredClone(effective.workspace);
|
|
2617
2692
|
renderDefaultProject(effective.project);
|
|
2618
2693
|
editor.touched = true;
|
|
2619
2694
|
} else {
|
|
2620
2695
|
editor.settings = defaultScheduleSessionSettings();
|
|
2696
|
+
editor.workspace = { mode: "project" };
|
|
2621
2697
|
renderDefaultProject("");
|
|
2622
2698
|
editor.touched = false;
|
|
2623
2699
|
}
|
|
@@ -2627,10 +2703,14 @@ async function loadDefaultOptions(resolveChat = false) {
|
|
|
2627
2703
|
}
|
|
2628
2704
|
const query = new URLSearchParams({ mode: "options" });
|
|
2629
2705
|
if (chatId) query.set("chat_id", chatId);
|
|
2706
|
+
const project = defaultsInput("project").value;
|
|
2707
|
+
if (project) query.set("project", project);
|
|
2630
2708
|
const data = await api(`/api/v1/defaults?${query}`);
|
|
2631
2709
|
if (defaultsEditor !== editor || serial !== editor.serial) return;
|
|
2632
2710
|
editor.models = data.models;
|
|
2633
2711
|
editor.contextAvailable = data.context_mode_available;
|
|
2712
|
+
editor.workspaceOptions = data.workspace_options || null;
|
|
2713
|
+
editor.workspaceError = data.workspace_options_error || "";
|
|
2634
2714
|
if (editor.kind === "chat") chatTarget("defaults").resolveKind(editor.contextAvailable);
|
|
2635
2715
|
editor.catalogError = typeof data.model_catalog_error === "string"
|
|
2636
2716
|
? data.model_catalog_error : data.model_catalog_error?.message || "";
|
|
@@ -2657,6 +2737,7 @@ function openDefaultEditor(kind, record = null) {
|
|
|
2657
2737
|
returnFocus: document.activeElement,
|
|
2658
2738
|
settings: structuredClone(record?.session_settings || defaultScheduleSessionSettings()),
|
|
2659
2739
|
models: [], serial: 0, loading: true, touched: false, contextAvailable: null,
|
|
2740
|
+
workspace: structuredClone(record ? record.workspace : { mode: "project" }), workspaceOptions: null, workspaceError: "",
|
|
2660
2741
|
sourceNote: record ? "修改已保存的配置,只影响之后创建的会话。" : "保存后,在没有当前会话的位置收到消息时生效。",
|
|
2661
2742
|
error: "", catalogError: "", lockedTarget: Boolean(record) };
|
|
2662
2743
|
defaultsInput("editor").hidden = false;
|
|
@@ -2701,7 +2782,7 @@ function defaultEditorValues() {
|
|
|
2701
2782
|
if (!editor) return null;
|
|
2702
2783
|
return { kind: editor.kind, project: defaultsInput("project").value,
|
|
2703
2784
|
target: defaultsInput(editor.kind === "chat" ? "chat" : "keyword").value,
|
|
2704
|
-
settings: sessionSettingsFingerprint(editor.settings) };
|
|
2785
|
+
settings: sessionSettingsFingerprint(editor.settings), workspace: structuredClone(editor.workspace) };
|
|
2705
2786
|
}
|
|
2706
2787
|
|
|
2707
2788
|
function defaultEditorHasChanges() {
|
|
@@ -2752,7 +2833,7 @@ async function defaultMutation(mode, action, extra = {}) {
|
|
|
2752
2833
|
async function saveDefault(event) {
|
|
2753
2834
|
event.preventDefault();
|
|
2754
2835
|
const editor = defaultsEditor;
|
|
2755
|
-
if (!editor || editor.loading || !editor.action || defaultsBusy) return;
|
|
2836
|
+
if (!editor || editor.loading || !editor.action || defaultsBusy || !defaultWorkspaceAvailable()) return;
|
|
2756
2837
|
if (editor.kind === "chat") {
|
|
2757
2838
|
editor.loading = true;
|
|
2758
2839
|
renderDefaultSettings();
|
|
@@ -2765,7 +2846,10 @@ async function saveDefault(event) {
|
|
|
2765
2846
|
if (defaultsEditor !== editor) return;
|
|
2766
2847
|
}
|
|
2767
2848
|
const definition = { kind: editor.kind, project: defaultsInput("project").value,
|
|
2768
|
-
session_settings: structuredClone(editor.settings) };
|
|
2849
|
+
session_settings: structuredClone(editor.settings), workspace: structuredClone(editor.workspace) };
|
|
2850
|
+
if (editor.workspaceOptions?.projectAlias === definition.project) {
|
|
2851
|
+
definition.expected_project_revision = editor.workspaceOptions.projectRevision;
|
|
2852
|
+
}
|
|
2769
2853
|
if (editor.kind === "chat") definition.chat_id = defaultsInput("chat").value.trim();
|
|
2770
2854
|
else definition.keyword = defaultsInput("keyword").value.trim();
|
|
2771
2855
|
const action = editor.action;
|
|
@@ -2828,7 +2912,7 @@ function defaultChatCell(row, rule) {
|
|
|
2828
2912
|
row.append(td);
|
|
2829
2913
|
}
|
|
2830
2914
|
|
|
2831
|
-
function defaultSettingsCell(row, settings) {
|
|
2915
|
+
function defaultSettingsCell(row, settings, workspace) {
|
|
2832
2916
|
const td = document.createElement("td");
|
|
2833
2917
|
const model = settings.turn_settings;
|
|
2834
2918
|
const title = document.createElement("div");
|
|
@@ -2836,7 +2920,11 @@ function defaultSettingsCell(row, settings) {
|
|
|
2836
2920
|
const detail = document.createElement("div");
|
|
2837
2921
|
detail.className = "default-settings-detail";
|
|
2838
2922
|
detail.textContent = scheduleSessionSummary(settings).split(" · ").slice(1).join(" · ");
|
|
2839
|
-
|
|
2923
|
+
const location = document.createElement("div");
|
|
2924
|
+
location.className = "default-settings-detail";
|
|
2925
|
+
location.textContent = workspace.mode === "existing" ? `指定 Worktree:${workspace.worktree_id}`
|
|
2926
|
+
: workspace.mode === "new" ? `每个新会话创建 Worktree · ${workspace.ref || "创建时 Project HEAD"}` : "项目目录";
|
|
2927
|
+
td.append(title, detail, location);
|
|
2840
2928
|
row.append(td);
|
|
2841
2929
|
}
|
|
2842
2930
|
|
|
@@ -2863,7 +2951,7 @@ async function loadDefaults(offset = defaultsOffset, returnFocus = null) {
|
|
|
2863
2951
|
cell(row, rule.keyword);
|
|
2864
2952
|
} else defaultChatCell(row, rule);
|
|
2865
2953
|
cell(row, rule.project);
|
|
2866
|
-
defaultSettingsCell(row, rule.session_settings);
|
|
2954
|
+
defaultSettingsCell(row, rule.session_settings, rule.workspace);
|
|
2867
2955
|
const actions = document.createElement("td");
|
|
2868
2956
|
const buttons = document.createElement("div");
|
|
2869
2957
|
buttons.className = "actions";
|
|
@@ -4418,6 +4506,11 @@ defaultsInput("drawer").addEventListener("cancel", (event) => {
|
|
|
4418
4506
|
});
|
|
4419
4507
|
defaultsInput("editor").addEventListener("submit", saveDefault);
|
|
4420
4508
|
defaultsInput("chat").addEventListener("change", () => changeDefaultChat());
|
|
4509
|
+
defaultsInput("project").addEventListener("change", changeDefaultProject);
|
|
4510
|
+
for (const field of ["workspace", "worktree"]) {
|
|
4511
|
+
defaultsInput(field).addEventListener("change", () => changeDefaultWorkspace(field));
|
|
4512
|
+
}
|
|
4513
|
+
defaultsInput("workspace-ref").addEventListener("input", () => changeDefaultWorkspace("workspace-ref"));
|
|
4421
4514
|
for (const field of ["model", "effort", "tier", "context", "reactions", "progress", "completion-mention"]) {
|
|
4422
4515
|
defaultsInput(field).addEventListener("change", () => changeDefaultSettings(field));
|
|
4423
4516
|
}
|
|
@@ -271,6 +271,12 @@
|
|
|
271
271
|
<h4>会话配置</h4>
|
|
272
272
|
<div class="schedule-form-grid">
|
|
273
273
|
<label>Project<select id="defaults-project" required><option value="">选择 Project</option></select></label>
|
|
274
|
+
<label>工作区策略<select id="defaults-workspace"><option value="project">项目目录</option><option value="existing">指定已有 Worktree</option><option value="new">每个新会话创建 Worktree</option></select></label>
|
|
275
|
+
<label id="defaults-worktree-field" hidden>受管 Worktree<select id="defaults-worktree"></select></label>
|
|
276
|
+
<label id="defaults-workspace-ref-field" hidden>起点提交 / 分支<input id="defaults-workspace-ref" list="defaults-workspace-refs" maxlength="256" placeholder="留空使用创建时 Project 的 HEAD"><datalist id="defaults-workspace-refs"></datalist></label>
|
|
277
|
+
</div>
|
|
278
|
+
<p id="defaults-workspace-help" class="defaults-field-help" role="status"></p>
|
|
279
|
+
<div class="schedule-form-grid">
|
|
274
280
|
<label>模型<select id="defaults-model"><option value="">继承 Codex</option></select></label>
|
|
275
281
|
<label>推理强度<select id="defaults-effort" disabled></select></label>
|
|
276
282
|
<label>速度<select id="defaults-tier" disabled></select></label>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Netizen Admin 登录</title>
|
|
7
|
+
<link rel="stylesheet" href="/static/admin.css">
|
|
8
|
+
<script src="/static/login.js" defer></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body class="login-body">
|
|
11
|
+
<main class="login-card">
|
|
12
|
+
<header class="login-heading">
|
|
13
|
+
<h1>Netizen Admin</h1>
|
|
14
|
+
<p>使用已获授权的飞书管理员账号登录</p>
|
|
15
|
+
</header>
|
|
16
|
+
<div class="login-instance">
|
|
17
|
+
<span>当前实例</span>
|
|
18
|
+
<p class="instance-root">__NETIZEN_INSTANCE_ROOT__</p>
|
|
19
|
+
</div>
|
|
20
|
+
<input id="login-nonce" type="hidden" value="__NETIZEN_LOGIN_NONCE__">
|
|
21
|
+
<input id="login-next" type="hidden" value="__NETIZEN_LOGIN_NEXT__">
|
|
22
|
+
<div id="login-authorization" hidden>
|
|
23
|
+
<a id="login-link" class="login-button login-primary" target="_blank" rel="noopener noreferrer">打开飞书授权页<span aria-hidden="true">↗</span></a>
|
|
24
|
+
<div class="login-scan">
|
|
25
|
+
<p class="login-divider">或使用飞书扫码</p>
|
|
26
|
+
<img id="login-qr" class="login-qr" alt="使用飞书扫描二维码完成本次登录" hidden>
|
|
27
|
+
</div>
|
|
28
|
+
<p class="login-user-code"><span>核对用户码</span><strong id="login-code"></strong></p>
|
|
29
|
+
<p id="login-deadline" class="login-deadline"></p>
|
|
30
|
+
</div>
|
|
31
|
+
<p id="login-status" class="status" role="status" aria-live="polite">正在检查登录状态…</p>
|
|
32
|
+
<div class="login-actions">
|
|
33
|
+
<button id="login-start" class="login-button login-primary" disabled>使用飞书登录</button>
|
|
34
|
+
<button id="login-check" class="login-button login-secondary" hidden>检查登录结果</button>
|
|
35
|
+
<button id="login-cancel" class="login-button login-cancel" hidden>取消登录</button>
|
|
36
|
+
</div>
|
|
37
|
+
<a id="login-retry" class="login-button login-primary" href="/login" hidden>重新开始登录</a>
|
|
38
|
+
<p class="login-safety">只确认你为上述实例主动发起的登录,不要替他人确认登录请求。</p>
|
|
39
|
+
</main>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
|
@@ -764,7 +764,7 @@ class AdminWebApplication:
|
|
|
764
764
|
allowed = {
|
|
765
765
|
"list": {"mode", "kind", "offset", "limit"},
|
|
766
766
|
"view": {"mode", "chat_id"},
|
|
767
|
-
"options": {"mode", "chat_id"},
|
|
767
|
+
"options": {"mode", "chat_id", "project", "expected_project_revision"},
|
|
768
768
|
}
|
|
769
769
|
if mode not in allowed:
|
|
770
770
|
raise AdminWebError(400, "invalid_query", "默认配置查询类型无效。")
|
|
@@ -773,9 +773,9 @@ class AdminWebApplication:
|
|
|
773
773
|
for key in allowed[mode] - {"mode"}:
|
|
774
774
|
value = _optional_text_query(context.query, key)
|
|
775
775
|
if value is not None:
|
|
776
|
-
if key in {"offset", "limit"}:
|
|
776
|
+
if key in {"offset", "limit", "expected_project_revision"}:
|
|
777
777
|
if not value.isascii() or not value.isdigit():
|
|
778
|
-
raise AdminWebError(400, "invalid_query", "
|
|
778
|
+
raise AdminWebError(400, "invalid_query", "分页或 Project 版本参数无效。")
|
|
779
779
|
request[key] = int(value)
|
|
780
780
|
else:
|
|
781
781
|
request[key] = value
|
|
@@ -817,7 +817,7 @@ class AdminWebApplication:
|
|
|
817
817
|
grant = self._redeem_parsed(context, payload, "defaults.save", target, expected_resource=target.resource)
|
|
818
818
|
definition = payload.get("definition")
|
|
819
819
|
if not isinstance(definition, dict) or set(definition) - {
|
|
820
|
-
"kind", "chat_id", "keyword", "project", "session_settings",
|
|
820
|
+
"kind", "chat_id", "keyword", "project", "expected_project_revision", "workspace", "session_settings",
|
|
821
821
|
}:
|
|
822
822
|
raise AdminWebError(400, "invalid_input", "默认配置字段无效。")
|
|
823
823
|
request: dict[str, object] = {**definition, "mode": "save", "expected_revision": None}
|
|
@@ -39,7 +39,7 @@ from .worktrees.models import WorktreeRecord
|
|
|
39
39
|
from .worktrees.store import WorktreeStore, create_schema as create_worktree_schema
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
SCHEMA_VERSION =
|
|
42
|
+
SCHEMA_VERSION = 16
|
|
43
43
|
|
|
44
44
|
# Includes the running query and all submitted queries waiting for the reader.
|
|
45
45
|
_ADMIN_QUERY_CAPACITY = 32
|
|
@@ -466,7 +466,7 @@ def _require_current_schema(connection: sqlite3.Connection) -> None:
|
|
|
466
466
|
_require_project_metadata_schema(connection)
|
|
467
467
|
require_schema(connection)
|
|
468
468
|
require_defaults_schema(connection)
|
|
469
|
-
from .migrations.
|
|
469
|
+
from .migrations.v16 import validate
|
|
470
470
|
validate(connection)
|
|
471
471
|
|
|
472
472
|
|
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
-
from collections.abc import Callable, Mapping
|
|
7
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
from datetime import datetime
|
|
10
10
|
from typing import Any
|
|
@@ -350,7 +350,7 @@ def _new_binding_form(
|
|
|
350
350
|
),
|
|
351
351
|
None,
|
|
352
352
|
)
|
|
353
|
-
elements = [
|
|
353
|
+
elements = [_form_section("项目", [
|
|
354
354
|
_static_select(
|
|
355
355
|
name="new_project",
|
|
356
356
|
placeholder="选择项目",
|
|
@@ -393,31 +393,15 @@ def _new_binding_form(
|
|
|
393
393
|
model_value_encoder=_new_model_reference,
|
|
394
394
|
inherit_initial_when_unset=False,
|
|
395
395
|
)
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
model_elements.append(_new_form_columns(
|
|
400
|
-
(1, model_fields[2:4]), (1, model_fields[4:6]),
|
|
401
|
-
))
|
|
402
|
-
elements.append(_new_form_section("模型配置", model_elements))
|
|
403
|
-
if allow_context_mode:
|
|
404
|
-
context = _context_mode_form_elements(prefix="new", initial_mode=message_context_mode)
|
|
405
|
-
context[-1] = _form_hint(
|
|
406
|
-
"机器人始终只响应 @。选择“自动带上”会把两次 @ 之间未 @ 机器人的群聊消息交给 Codex。"
|
|
407
|
-
)
|
|
408
|
-
_restore_new_settings_draft(context, settings_draft)
|
|
409
|
-
elements.append(_new_form_section("消息上下文", context))
|
|
410
|
-
feedback = _task_feedback_form_elements(prefix="new", initial=task_feedback)
|
|
411
|
-
_restore_new_settings_draft(feedback, settings_draft)
|
|
412
|
-
feedback_hints = (
|
|
413
|
-
"执行时闪烁;关闭仍保留状态表情。部分移动端会显示为消息。",
|
|
414
|
-
"展示执行状态与清单,结束后自动折叠。",
|
|
415
|
-
"完成或失败时 @ 发起人;主动停止、定时自动首轮不提醒。",
|
|
396
|
+
context = (
|
|
397
|
+
_context_mode_form_elements(prefix="new", initial_mode=message_context_mode)
|
|
398
|
+
if allow_context_mode else []
|
|
416
399
|
)
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
400
|
+
feedback = _task_feedback_form_elements(prefix="new", initial=task_feedback)
|
|
401
|
+
_restore_settings_draft([*model_fields, *context, *feedback], settings_draft)
|
|
402
|
+
elements.extend(_session_settings_sections(
|
|
403
|
+
model_fields=model_fields, context_fields=context, feedback_fields=feedback,
|
|
404
|
+
))
|
|
421
405
|
if allow_workspace_selection:
|
|
422
406
|
workspace_elements = [
|
|
423
407
|
_form_hint("使用上方选择的项目加载目录选项;不会创建会话。切换项目后请重新加载。"),
|
|
@@ -434,7 +418,7 @@ def _new_binding_form(
|
|
|
434
418
|
))
|
|
435
419
|
if workspace_options is not None and workspace_options.get("isGit") is True:
|
|
436
420
|
workspace_elements.extend(_new_workspace_elements(workspace_options))
|
|
437
|
-
elements.append(
|
|
421
|
+
elements.append(_form_section("工作区", workspace_elements))
|
|
438
422
|
elements.append(
|
|
439
423
|
_form_submit_button(name="new_binding_submit_v6", label="新建会话")
|
|
440
424
|
)
|
|
@@ -446,7 +430,7 @@ def _new_binding_form(
|
|
|
446
430
|
}
|
|
447
431
|
|
|
448
432
|
|
|
449
|
-
def
|
|
433
|
+
def _restore_settings_draft(
|
|
450
434
|
elements: list[dict[str, Any]], draft: Mapping[str, str] | None,
|
|
451
435
|
) -> None:
|
|
452
436
|
"""Retain this form submission only; never silently replace an unavailable choice."""
|
|
@@ -461,8 +445,8 @@ def _restore_new_settings_draft(
|
|
|
461
445
|
element["initial_option"] = value
|
|
462
446
|
|
|
463
447
|
|
|
464
|
-
def
|
|
465
|
-
"""Arrange existing
|
|
448
|
+
def _form_columns(*columns: tuple[int, list[dict[str, Any]]]) -> dict[str, Any]:
|
|
449
|
+
"""Arrange existing controls without changing their submitted values."""
|
|
466
450
|
rendered = []
|
|
467
451
|
for weight, elements in columns:
|
|
468
452
|
styled = []
|
|
@@ -482,8 +466,41 @@ def _new_form_columns(*columns: tuple[int, list[dict[str, Any]]]) -> dict[str, A
|
|
|
482
466
|
}
|
|
483
467
|
|
|
484
468
|
|
|
485
|
-
def
|
|
486
|
-
return
|
|
469
|
+
def _form_section(title: str, elements: list[dict[str, Any]]) -> dict[str, Any]:
|
|
470
|
+
return _form_columns((1, [{"tag": "markdown", "content": f"**{title}**"}, *elements]))
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
def _session_settings_sections(
|
|
474
|
+
*,
|
|
475
|
+
model_fields: list[dict[str, Any]],
|
|
476
|
+
context_fields: list[dict[str, Any]],
|
|
477
|
+
feedback_fields: list[dict[str, Any]],
|
|
478
|
+
model_notices: Sequence[dict[str, Any]] = (),
|
|
479
|
+
) -> list[dict[str, Any]]:
|
|
480
|
+
"""Share presentation while each caller owns field values and validation."""
|
|
481
|
+
model_elements = [*model_notices, model_fields[1]]
|
|
482
|
+
if len(model_fields) > 2:
|
|
483
|
+
model_elements.append(_form_columns(
|
|
484
|
+
(1, model_fields[2:4]), (1, model_fields[4:6]),
|
|
485
|
+
))
|
|
486
|
+
sections = [_form_section("模型配置", model_elements)]
|
|
487
|
+
if context_fields:
|
|
488
|
+
sections.append(_form_section("消息上下文", [
|
|
489
|
+
*context_fields[:-1],
|
|
490
|
+
_form_hint("机器人始终只响应 @。选择“自动带上”会把两次 @ 之间未 @ 机器人的群聊消息交给 Codex。"),
|
|
491
|
+
]))
|
|
492
|
+
feedback_hints = (
|
|
493
|
+
"执行时闪烁;关闭仍保留状态表情。部分移动端会显示为消息。",
|
|
494
|
+
"展示执行状态与清单,结束后自动折叠。",
|
|
495
|
+
"完成或失败时 @ 发起人;主动停止、定时自动首轮不提醒。",
|
|
496
|
+
)
|
|
497
|
+
sections.append(_form_section("任务反馈", [
|
|
498
|
+
_form_columns((3, [label, _form_hint(hint)]), (1, [select]))
|
|
499
|
+
for label, select, hint in zip(
|
|
500
|
+
feedback_fields[::3], feedback_fields[1::3], feedback_hints, strict=True,
|
|
501
|
+
)
|
|
502
|
+
]))
|
|
503
|
+
return sections
|
|
487
504
|
|
|
488
505
|
|
|
489
506
|
def _workspace_reference(options: Mapping[str, Any], choice: str) -> str:
|
|
@@ -567,38 +584,31 @@ def _binding_config_form(
|
|
|
567
584
|
model_id=model_id,
|
|
568
585
|
)
|
|
569
586
|
|
|
570
|
-
elements: list[dict[str, Any]] = []
|
|
571
587
|
if catalog is None:
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
]
|
|
582
|
-
)
|
|
588
|
+
model_fields = [
|
|
589
|
+
_form_label("Model"),
|
|
590
|
+
_static_select(
|
|
591
|
+
name="config_model",
|
|
592
|
+
placeholder="选择 Model 来源",
|
|
593
|
+
options=(("继承 Codex", model_reference(None)),),
|
|
594
|
+
initial_option=model_reference(None),
|
|
595
|
+
),
|
|
596
|
+
]
|
|
583
597
|
else:
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
inherit_initial_when_unset=True,
|
|
591
|
-
)
|
|
592
|
-
)
|
|
593
|
-
if allow_context_mode:
|
|
594
|
-
elements.extend(
|
|
595
|
-
_context_mode_form_elements(
|
|
596
|
-
prefix="config",
|
|
597
|
-
initial_mode=message_context_mode,
|
|
598
|
-
)
|
|
598
|
+
model_fields = _model_settings_form_elements(
|
|
599
|
+
prefix="config",
|
|
600
|
+
catalog=catalog,
|
|
601
|
+
turn_settings=turn_settings,
|
|
602
|
+
model_value_encoder=model_reference,
|
|
603
|
+
inherit_initial_when_unset=True,
|
|
599
604
|
)
|
|
600
|
-
elements
|
|
601
|
-
|
|
605
|
+
elements = _session_settings_sections(
|
|
606
|
+
model_fields=model_fields,
|
|
607
|
+
context_fields=(
|
|
608
|
+
_context_mode_form_elements(prefix="config", initial_mode=message_context_mode)
|
|
609
|
+
if allow_context_mode else []
|
|
610
|
+
),
|
|
611
|
+
feedback_fields=_task_feedback_form_elements(prefix="config", initial=task_feedback),
|
|
602
612
|
)
|
|
603
613
|
elements.append(
|
|
604
614
|
_form_submit_button(
|
|
@@ -609,6 +619,7 @@ def _binding_config_form(
|
|
|
609
619
|
return {
|
|
610
620
|
"tag": "form",
|
|
611
621
|
"name": "binding_config_v6",
|
|
622
|
+
"vertical_spacing": "12px",
|
|
612
623
|
"elements": elements,
|
|
613
624
|
}
|
|
614
625
|
|
|
@@ -778,6 +789,8 @@ def session_settings_form_elements(
|
|
|
778
789
|
catalog: ModelCatalog | None,
|
|
779
790
|
catalog_error: str | None = None,
|
|
780
791
|
allow_context_mode: bool,
|
|
792
|
+
grouped: bool = False,
|
|
793
|
+
settings_draft: Mapping[str, str] | None = None,
|
|
781
794
|
) -> list[dict[str, Any]]:
|
|
782
795
|
"""Use ordinary controls while preserving unavailable explicit intent."""
|
|
783
796
|
usable_catalog = catalog
|
|
@@ -787,34 +800,43 @@ def session_settings_form_elements(
|
|
|
787
800
|
except ValueError:
|
|
788
801
|
usable_catalog = None
|
|
789
802
|
catalog_error = "已有 Model / Effort / Speed 暂不可用,当前选择完整保留。"
|
|
790
|
-
|
|
803
|
+
model_notices: list[dict[str, Any]] = []
|
|
791
804
|
if usable_catalog is not None:
|
|
792
|
-
|
|
805
|
+
model_fields = _model_settings_form_elements(
|
|
793
806
|
prefix=prefix, catalog=usable_catalog, turn_settings=settings.turn_settings,
|
|
794
807
|
model_value_encoder=_new_model_reference, inherit_initial_when_unset=True,
|
|
795
|
-
)
|
|
808
|
+
)
|
|
796
809
|
else:
|
|
797
|
-
|
|
810
|
+
model_notices.append(_notice(catalog_error or "模型目录暂不可用;可以保留原配置或明确选择继承 Codex。"))
|
|
798
811
|
options = [("继承 Codex", _new_model_reference(None))]
|
|
799
812
|
turn = settings.turn_settings
|
|
800
813
|
if turn is not None:
|
|
801
814
|
options.append(("保留已有显式配置", _new_model_reference(turn.model_id)))
|
|
802
|
-
|
|
815
|
+
model_fields = [
|
|
803
816
|
_form_label("Model"),
|
|
804
817
|
_static_select(name=f"{prefix}_model", placeholder="选择 Model 来源", options=tuple(options),
|
|
805
818
|
initial_option=_new_model_reference(turn.model_id if turn else None)),
|
|
806
|
-
]
|
|
819
|
+
]
|
|
807
820
|
if turn is not None:
|
|
808
821
|
for field, label, value in (("effort", "Effort", turn.effort_id), ("speed", "Speed", turn.service_tier_id)):
|
|
809
|
-
|
|
822
|
+
model_fields.extend([
|
|
810
823
|
_form_label(label),
|
|
811
824
|
_static_select(name=f"{prefix}_{field}", placeholder=label,
|
|
812
825
|
options=((value, value),), initial_option=value),
|
|
813
826
|
])
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
827
|
+
context = (
|
|
828
|
+
_context_mode_form_elements(prefix=prefix, initial_mode=settings.message_context_mode)
|
|
829
|
+
if allow_context_mode else []
|
|
830
|
+
)
|
|
831
|
+
feedback = _task_feedback_form_elements(prefix=prefix, initial=settings.task_feedback)
|
|
832
|
+
fields = [*model_fields, *context, *feedback]
|
|
833
|
+
_restore_settings_draft(fields, settings_draft)
|
|
834
|
+
if grouped:
|
|
835
|
+
return _session_settings_sections(
|
|
836
|
+
model_fields=model_fields, context_fields=context, feedback_fields=feedback,
|
|
837
|
+
model_notices=model_notices,
|
|
838
|
+
)
|
|
839
|
+
return [*model_notices, *fields]
|
|
818
840
|
|
|
819
841
|
|
|
820
842
|
def session_settings_summary(settings: SessionSettings, *, allow_context_mode: bool = True) -> str:
|