netizen-cli 0.11.4__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {netizen_cli-0.11.4/netizen_cli.egg-info → netizen_cli-0.12.0}/PKG-INFO +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/README.md +14 -14
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/config.example.yaml +11 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/__init__.py +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/port_config.py +6 -4
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/admin.css +6 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/admin.js +24 -25
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/index.html +30 -0
- netizen_cli-0.12.0/netizen_cli/admin/static/session-access.js +127 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/web.py +67 -70
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/bindings.py +20 -52
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/callbacks.py +4 -4
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/chat_target.py +30 -7
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/controls.py +21 -21
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/fork.py +7 -5
- netizen_cli-0.12.0/netizen_cli/cards/session_ids.py +17 -0
- netizen_cli-0.12.0/netizen_cli/cards/status.py +245 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/topics.py +33 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel_app.py +454 -77
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/codex_runtime.py +236 -30
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/domain.py +25 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/main.py +47 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/chat_labels.py +49 -9
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/service.py +0 -42
- netizen_cli-0.12.0/netizen_cli/mcp_transport.py +231 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/runtime/contracts.py +1 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/runtime/thread_naming.py +35 -5
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/mcp.py +11 -214
- netizen_cli-0.12.0/netizen_cli/sessions/__init__.py +1 -0
- netizen_cli-0.12.0/netizen_cli/sessions/errors.py +14 -0
- netizen_cli-0.12.0/netizen_cli/sessions/mcp.py +80 -0
- netizen_cli-0.12.0/netizen_cli/sessions/policy.py +128 -0
- netizen_cli-0.12.0/netizen_cli/sessions/presentation.py +227 -0
- netizen_cli-0.12.0/netizen_cli/sessions/schema.py +94 -0
- netizen_cli-0.12.0/netizen_cli/sessions/service.py +330 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/settings.py +7 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0/netizen_cli.egg-info}/PKG-INFO +1 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli.egg-info/SOURCES.txt +30 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/pyproject.toml +1 -1
- netizen_cli-0.12.0/skills/netizen-user-guide/SKILL.md +46 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/admin.md +198 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/commands.md +41 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/concepts.md +50 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/faq.md +131 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/feedback-and-files.md +119 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/fork-side-goal.md +96 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/messages.md +122 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/native-capabilities.md +64 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/scheduled-tasks.md +140 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/session-collaboration.md +58 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/sessions.md +149 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/status-and-control.md +84 -0
- netizen_cli-0.12.0/skills/netizen-user-guide/references/user-guide.md +60 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_bindings.py +6 -22
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cards.py +3 -3
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_channel_app.py +143 -77
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_chat_target_cards.py +17 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_codex_runtime.py +3 -2
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_deployment.py +7 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_fork_cards.py +61 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_main.py +52 -2
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_persistent_fork_channel.py +25 -3
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_repository_hygiene.py +1 -2
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_runtime_thread_naming.py +79 -1
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_service_launcher.py +3 -1
- netizen_cli-0.12.0/tests/test_session_collaboration_app.py +531 -0
- netizen_cli-0.12.0/tests/test_session_external_runtime.py +384 -0
- netizen_cli-0.12.0/tests/test_session_id_cards.py +137 -0
- netizen_cli-0.12.0/tests/test_session_policy.py +128 -0
- netizen_cli-0.12.0/tests/test_session_tools.py +500 -0
- netizen_cli-0.12.0/tests/test_status_cards.py +186 -0
- netizen_cli-0.12.0/tests/test_status_commands.py +308 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_thread_naming.py +51 -4
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_user_guide_skill.py +4 -1
- netizen_cli-0.11.4/skills/netizen-user-guide/SKILL.md +0 -41
- netizen_cli-0.11.4/skills/netizen-user-guide/references/user-guide.md +0 -1057
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/MANIFEST.in +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/_build.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/__main__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/account_rate_limits.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/auth.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/credentials.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/errors.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/feishu.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/login.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/presentation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/queries.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/chat-picker.css +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/chat-picker.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/identity.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/login.html +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/static/login.js +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/transport.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/admin/users.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/builtin_skills.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/defaults.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/model_info.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/questions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/reply.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/scheduled.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cards/usage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/completion_mentions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/input_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/ports.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/question_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/reactions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/channel/reply_presenter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/chat_avatars.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/chat_targets.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_data.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_packages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_services.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_setup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_update.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_update_restore.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/cli_update_worker.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/completion_mention.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/database_migrations.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/defaults/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/defaults/models.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/defaults/service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/defaults/store.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/deployment/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/deployment/restart_worker.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/deployment/update_executor.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/deployment/update_protocol.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/error_messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/experience.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/feishu_app_onboarding.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/feishu_app_permissions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/feishu_links.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/git_status.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/image_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/instance.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/lark_app.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/blocking_io.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/chat_directory.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/coordination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/management/updates.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/markdown_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/message_content.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/message_history.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/message_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/message_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/migrations/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/migrations/schema.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/migrations/v14.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/model_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/package_resources.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/projects.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/prompt_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/quoted_context.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/result_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/runtime/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/runtime/name_writes.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/__init__.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/models.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/scheduler.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/schedules/store.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/sdk_gap_adapter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/service_launcher.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/session_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/skill_references.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/task_text.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/terminal_cleanup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/turn_activity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/turn_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/turn_patch_children.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/turn_plan_observer.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli/user_questions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli.egg-info/dependency_links.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli.egg-info/entry_points.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli.egg-info/requires.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/netizen_cli.egg-info/top_level.txt +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/setup.cfg +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/skills/netizen-lark/SKILL.md +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_account_rate_limits.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_admin_update_executor_probe.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_binding_scheduled_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_channel_fixtures.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_channel_input_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_chat_avatars.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_check_sdk.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_data.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_distribution.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_integration.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_packages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_packaging.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_services.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_setup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cli_update.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_codex_sdk_capabilities.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_codex_sdk_upgrade_0161.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_completion_mention_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_completion_mentions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_completion_topic_delivery.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_cron_chat_targets.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_database_migrations.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_defaults_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_defaults_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_defaults_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_documentation_links.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_domain_experience.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_error_messages.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_feishu_app_onboarding.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_feishu_app_permissions.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_file_pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_git_status.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_image_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_lark_app.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_lark_sdk_contract.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_markdown_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_message_content.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_message_history.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_message_material_inputs.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_message_preparation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_migration_schema_validation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_model_info_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_model_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_name_writes.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_pagination.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_partial_answer_delivery.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_persistent_fork_bindings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_persistent_fork_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_child_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_feishu_completion_mention.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_feishu_partial_answers.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_feishu_turn_file_card.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_persistent_fork.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_python_sdk.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_scheduled_tasks.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_sdk_completion_race.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_skill_execution.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_probe_thread_naming.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_project_delete_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_project_delete_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_project_deletion_storage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_prompt_projection.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_question_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_question_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_question_target_parity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_quoted_context.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_release_script.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_result_images.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_resume_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_retired_deployment.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_runtime_resume_activation.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_card_retry.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_cards.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_mcp.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_run_now.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_scope_matrix.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedule_service.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_scheduled_channel.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_scheduled_runtime.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_scheduler.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_scheduler_presenter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_schedules_storage.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_sdk_gap_adapter.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_session_defaults.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_session_settings.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_settings_projects.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_task_text.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_terminal_cleanup.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_turn_activity.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_turn_files.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_turn_patch_children.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_turn_patch_statistics.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_turn_plan_observer.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_update_executor.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_usage_card.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_usage_control.py +0 -0
- {netizen_cli-0.11.4 → netizen_cli-0.12.0}/tests/test_user_questions.py +0 -0
|
@@ -36,19 +36,19 @@
|
|
|
36
36
|
- **把任务交给 Codex。** 在飞书中阅读代码、修改项目、整理资料;任务由官方 Codex SDK
|
|
37
37
|
管理的原生会话执行,沿用运行主机上的工具和工作目录。
|
|
38
38
|
- **边做边沟通。** 普通任务执行时继续发消息,可以补充条件或调整方向;也可以开启
|
|
39
|
-
[过程卡](skills/netizen-user-guide/references/
|
|
39
|
+
[过程卡](skills/netizen-user-guide/references/feedback-and-files.md#飞书中的运行反馈)查看进展。
|
|
40
40
|
- **带上图片与讨论背景。** 支持图片、逐条引用,以及可选的
|
|
41
|
-
[群聊上下文](skills/netizen-user-guide/references/
|
|
41
|
+
[群聊上下文](skills/netizen-user-guide/references/messages.md#发送消息引用与图片)。
|
|
42
42
|
- **取回本轮文件。** 完成后从回复卡片中按需发送有原生执行记录的文件;发送的是点击时
|
|
43
|
-
的当前内容,详见[文件说明](skills/netizen-user-guide/references/
|
|
43
|
+
的当前内容,详见[文件说明](skills/netizen-user-guide/references/feedback-and-files.md#查看和发送本轮文件)。
|
|
44
44
|
- **保留上下文,另开一条讨论。** 用
|
|
45
|
-
[持久分支](skills/netizen-user-guide/references/
|
|
45
|
+
[持久分支](skills/netizen-user-guide/references/fork-side-goal.md#fork-持久分支)在当前聊天或其他群
|
|
46
46
|
创建普通话题,之后独立继续。
|
|
47
47
|
- **展开临时讨论,推进持续目标。** 用
|
|
48
|
-
[Side](skills/netizen-user-guide/references/
|
|
49
|
-
[Goal](skills/netizen-user-guide/references/
|
|
48
|
+
[Side](skills/netizen-user-guide/references/fork-side-goal.md#side-临时话题)另开临时话题,或用
|
|
49
|
+
[Goal](skills/netizen-user-guide/references/fork-side-goal.md#goal)让 Codex 围绕目标持续推进。
|
|
50
50
|
- **让任务按时开始。** 用自然语言或 `/cron` 创建
|
|
51
|
-
[定时任务](skills/netizen-user-guide/references/
|
|
51
|
+
[定时任务](skills/netizen-user-guide/references/scheduled-tasks.md#定时任务),可每次在独立话题执行,也可在原会话定时继续。
|
|
52
52
|
|
|
53
53
|
普通会话的历史由 Codex 保存,可在 Codex App/CLI 中继续使用;App/CLI 中新增的消息不会
|
|
54
54
|
自动回填飞书。多个会话可以并行,同一项目的文件目录共享,修改会相互可见。
|
|
@@ -109,7 +109,7 @@ Agent/脚本使用 `netizen update --json`:stdout 只输出最终 JSON,进
|
|
|
109
109
|
5. 收到回复后继续交流;如果出现“本轮文件”,点击“发送”取回需要的文件。
|
|
110
110
|
|
|
111
111
|
不确定下一步时发送 `/help` 查看快速开始。通过 `/defaults` 或 Admin 配好
|
|
112
|
-
[会话默认配置](skills/netizen-user-guide/references/
|
|
112
|
+
[会话默认配置](skills/netizen-user-guide/references/sessions.md#默认会话配置与自动创建)后,
|
|
113
113
|
没有当前会话时也可直接发送任务:机器人会在消息所在主线或话题创建会话并执行。
|
|
114
114
|
没有可用默认配置时,机器人仍会提示准备步骤;被拦下的任务需在准备好后重新发送。
|
|
115
115
|
|
|
@@ -117,7 +117,7 @@ Agent/脚本使用 `netizen update --json`:stdout 只输出最终 JSON,进
|
|
|
117
117
|
不接受参数。普通任务执行中发来的新消息用于调整当前任务,不会排队成下一个任务。
|
|
118
118
|
|
|
119
119
|
安装遇到问题可从[部署文档](docs/deployment.md)继续;已能对话时,常见疑问见
|
|
120
|
-
[使用 FAQ](skills/netizen-user-guide/references/
|
|
120
|
+
[使用 FAQ](skills/netizen-user-guide/references/faq.md#常见问题)。
|
|
121
121
|
|
|
122
122
|
## 命令
|
|
123
123
|
|
|
@@ -133,12 +133,12 @@ Agent/脚本使用 `netizen update --json`:stdout 只输出最终 JSON,进
|
|
|
133
133
|
| 调整模型、思考强度和过程卡 | `/config`,当前会话空闲时使用 |
|
|
134
134
|
| 查看当前任务和上下文用量 | `/status` |
|
|
135
135
|
| 查看共享 Codex 账号额度和重置时间 | `/usage` |
|
|
136
|
-
| 中断当前任务 | `/stop`;不保证前台工具进程退出,见[停止说明](skills/netizen-user-guide/references/
|
|
136
|
+
| 中断当前任务 | `/stop`;不保证前台工具进程退出,见[停止说明](skills/netizen-user-guide/references/status-and-control.md#stop) |
|
|
137
137
|
| 查找当前机器人的管理入口 | `/admin`;返回实际管理 URL 和实例根目录,不返回登录凭据 |
|
|
138
138
|
| 管理定时任务 | `/cron`,也可以直接用自然语言描述计划 |
|
|
139
139
|
| 查看当前实例提供的命令 | `/help` |
|
|
140
140
|
|
|
141
|
-
重命名、归档、恢复、删除等完整用法见[命令索引](skills/netizen-user-guide/references/
|
|
141
|
+
重命名、归档、恢复、删除等完整用法见[命令索引](skills/netizen-user-guide/references/commands.md#完整命令索引)。
|
|
142
142
|
当前实例的命令开放情况以 `/help` 为准,任务状态以 `/status` 和卡片提示为准。
|
|
143
143
|
|
|
144
144
|
### 两个常见场景
|
|
@@ -159,7 +159,7 @@ Side 会在同一聊天中新建话题,可继续多轮讨论。它与原会话
|
|
|
159
159
|
```
|
|
160
160
|
|
|
161
161
|
计划每次创建独立执行话题;暂停计划不会停止已经触发的任务。
|
|
162
|
-
[定时任务用法](skills/netizen-user-guide/references/
|
|
162
|
+
[定时任务用法](skills/netizen-user-guide/references/scheduled-tasks.md#定时任务)
|
|
163
163
|
|
|
164
164
|
<a id="admin-web"></a>
|
|
165
165
|
|
|
@@ -183,12 +183,12 @@ Admin 是实例必备能力;管理员可在“系统管理 → 权限管理
|
|
|
183
183
|
- **共享环境。** 飞书应用的可用范围和群成员关系控制谁能访问;同一实例复用服务账号,
|
|
184
184
|
不提供按用户或项目隔离的权限体系。Admin Web 面向受信内网,名单中的管理员权限相同。
|
|
185
185
|
- **输入与输出。** 支持文本、普通图片和富文本图片,也可提供飞书 2.0 卡片、合并转发与转发话题作为
|
|
186
|
-
[背景材料](skills/netizen-user-guide/references/
|
|
186
|
+
[背景材料](skills/netizen-user-guide/references/messages.md#卡片合并转发与转发话题)。材料内部的媒体只提供未读附件描述;直接文件和音视频仍不支持。
|
|
187
187
|
飞书 1.0 卡片明确不支持。
|
|
188
188
|
输出文件按本轮原生记录发现,不扫描工作区补齐,也不自动上传。
|
|
189
189
|
- **Codex 能力有宿主差异。** 飞书复用原生会话和工具,但并非每个 App/CLI 控件都可用;
|
|
190
190
|
全新会话采用 `auto_review`,持久分支沿用原生继承权限;不提供 App 的 Ask/Custom 选择器。
|
|
191
|
-
[完整差异与当前限制](skills/netizen-user-guide/references/
|
|
191
|
+
[完整差异与当前限制](skills/netizen-user-guide/references/native-capabilities.md#与-codex-appcli-的差异)
|
|
192
192
|
|
|
193
193
|
<a id="用户指南-skill"></a>
|
|
194
194
|
|
|
@@ -15,6 +15,17 @@ projects:
|
|
|
15
15
|
channel:
|
|
16
16
|
securityMode: audit
|
|
17
17
|
|
|
18
|
+
# Optional collaboration-tool ranges; both default to all when omitted.
|
|
19
|
+
# Admin can update these at runtime. These rules do not restrict ordinary chat input.
|
|
20
|
+
# Each mode is all, only, exclude, or disabled; only/exclude use exact chat IDs.
|
|
21
|
+
sessionTools:
|
|
22
|
+
discovery:
|
|
23
|
+
mode: all
|
|
24
|
+
chatIds: []
|
|
25
|
+
readSend:
|
|
26
|
+
mode: all
|
|
27
|
+
chatIds: []
|
|
28
|
+
|
|
18
29
|
# Required management UI, using this app's Feishu administrator identities.
|
|
19
30
|
# It listens on all interfaces for direct access inside the trusted private network.
|
|
20
31
|
adminWeb:
|
|
@@ -52,7 +52,7 @@ def _identity(metadata: os.stat_result) -> tuple[int, ...]:
|
|
|
52
52
|
)
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def persist_admin_port(snapshot: ConfigFileSnapshot, port: int) ->
|
|
55
|
+
def persist_admin_port(snapshot: ConfigFileSnapshot, port: int) -> ConfigFileSnapshot:
|
|
56
56
|
"""Preserve all YAML values and refuse a detected concurrent human edit.
|
|
57
57
|
|
|
58
58
|
The caller retains its listening socket and instance lifetime lock. This
|
|
@@ -72,7 +72,7 @@ def persist_admin_port(snapshot: ConfigFileSnapshot, port: int) -> None:
|
|
|
72
72
|
values = dict(values)
|
|
73
73
|
loaded["adminWeb"] = values
|
|
74
74
|
values["port"] = port
|
|
75
|
-
|
|
75
|
+
return write_configuration(snapshot, loaded)
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
def _validate_port(port: int) -> None:
|
|
@@ -80,10 +80,11 @@ def _validate_port(port: int) -> None:
|
|
|
80
80
|
raise AdminPortConfigurationError("Admin port must be from 1 to 65535")
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
def
|
|
83
|
+
def write_configuration(snapshot: ConfigFileSnapshot, loaded: dict) -> ConfigFileSnapshot:
|
|
84
|
+
"""Replace the existing instance YAML after checking its exact snapshot."""
|
|
84
85
|
content = yaml.safe_dump(loaded, allow_unicode=True, sort_keys=False).encode("utf-8")
|
|
85
86
|
snapshot.require_unchanged()
|
|
86
|
-
descriptor, temporary_name = tempfile.mkstemp(prefix=".
|
|
87
|
+
descriptor, temporary_name = tempfile.mkstemp(prefix=".netizen-config-", dir=snapshot.path.parent)
|
|
87
88
|
temporary = Path(temporary_name)
|
|
88
89
|
try:
|
|
89
90
|
with os.fdopen(descriptor, "wb") as output:
|
|
@@ -96,3 +97,4 @@ def _write_configuration(snapshot: ConfigFileSnapshot, loaded: dict) -> None:
|
|
|
96
97
|
finally:
|
|
97
98
|
with contextlib.suppress(FileNotFoundError):
|
|
98
99
|
temporary.unlink()
|
|
100
|
+
return ConfigFileSnapshot.read(snapshot.path)
|
|
@@ -378,6 +378,12 @@ body.schedule-detail-open { overflow: hidden; }
|
|
|
378
378
|
.system-tabs { width: fit-content; margin: 22px 0; }
|
|
379
379
|
.admin-users { padding: 0; margin: 0; list-style: none; }
|
|
380
380
|
.admin-users > li { display: flex; justify-content: space-between; align-items: center; gap: 16px; border-top: 1px solid var(--line); padding: 16px 0; }
|
|
381
|
+
.session-access { margin-top: 32px; padding-top: 18px; border-top: 1px solid var(--line); }
|
|
382
|
+
.session-access-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 24px; }
|
|
383
|
+
.session-access-grid h4 { margin: 0 0 8px; }
|
|
384
|
+
.session-access-grid p { min-height: 48px; color: var(--muted); line-height: 1.6; }
|
|
385
|
+
.session-access-grid textarea { width: 100%; resize: vertical; font-family: monospace; }
|
|
386
|
+
.session-access-grid [hidden] { display: none; }
|
|
381
387
|
.identity-panel { max-width: 480px; border: 1px solid var(--line); border-radius: 14px; margin-bottom: 24px; padding: 20px; color: var(--ink); }
|
|
382
388
|
.identity-panel h3 { margin: 0; }
|
|
383
389
|
.identity-panel > p { margin: 20px 0; }
|
|
@@ -61,6 +61,7 @@ function expireAdminSession() {
|
|
|
61
61
|
const notice = document.querySelector("#auth-expired");
|
|
62
62
|
if (notice) notice.hidden = false;
|
|
63
63
|
window.NetizenIdentity?.expire();
|
|
64
|
+
window.NetizenSessionAccess?.expire();
|
|
64
65
|
setStatus("登录已过期,请重新登录。", true);
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -404,7 +405,7 @@ function actionsCell(row) {
|
|
|
404
405
|
function confirmMaterializedDelete(session) {
|
|
405
406
|
const name = session.nativeTitle || "未命名 Session";
|
|
406
407
|
return window.confirm(
|
|
407
|
-
`确认永久删除这个会话?\n\n会话:${name}\nScope:${session.scopeKey}\
|
|
408
|
+
`确认永久删除这个会话?\n\n会话:${name}\nScope:${session.scopeKey}\nNetizen 会话编号:${session.shortId}`
|
|
408
409
|
+ "\n\n原生 Thread、spawned descendants、Codex App/CLI 历史和本地 Binding 都会永久消失,无法恢复。",
|
|
409
410
|
);
|
|
410
411
|
}
|
|
@@ -1608,15 +1609,16 @@ function sessionIdentityCell(row, session) {
|
|
|
1608
1609
|
}
|
|
1609
1610
|
const bindingId = document.createElement("div");
|
|
1610
1611
|
bindingId.className = "id";
|
|
1611
|
-
bindingId.textContent = `
|
|
1612
|
+
bindingId.textContent = `Netizen 会话编号:${session.shortId}`;
|
|
1612
1613
|
td.append(bindingId);
|
|
1613
1614
|
const details = document.createElement("details");
|
|
1614
1615
|
details.className = "session-identities";
|
|
1615
1616
|
const summary = document.createElement("summary");
|
|
1616
1617
|
summary.textContent = "会话标识";
|
|
1617
1618
|
details.append(summary);
|
|
1618
|
-
for (const [label, value] of [["
|
|
1619
|
-
["Binding", session.bindingId],
|
|
1619
|
+
for (const [label, value] of [["飞书聊天 ID(位置)", session.chatId], ["飞书话题 ID(位置)", session.topicId],
|
|
1620
|
+
["Netizen 会话编号(Binding ID,管理与切换)", session.bindingId],
|
|
1621
|
+
["Codex 会话 ID(Thread ID,跨会话工具)", session.nativeThreadId]]) {
|
|
1620
1622
|
if (!value) continue;
|
|
1621
1623
|
const field = document.createElement("label");
|
|
1622
1624
|
field.textContent = label;
|
|
@@ -1624,15 +1626,21 @@ function sessionIdentityCell(row, session) {
|
|
|
1624
1626
|
input.type = "text";
|
|
1625
1627
|
input.readOnly = true;
|
|
1626
1628
|
input.value = value;
|
|
1627
|
-
input.setAttribute("aria-label", `${label}
|
|
1629
|
+
input.setAttribute("aria-label", `${label},完整值,选中后可复制`);
|
|
1628
1630
|
input.addEventListener("focus", () => input.select());
|
|
1629
1631
|
input.addEventListener("click", () => input.select());
|
|
1630
1632
|
field.append(input);
|
|
1631
1633
|
details.append(field);
|
|
1632
1634
|
}
|
|
1633
1635
|
const hint = document.createElement("small");
|
|
1634
|
-
hint.textContent = "点击标识全选,再按 Ctrl/Cmd+C
|
|
1636
|
+
hint.textContent = "点击标识全选,再按 Ctrl/Cmd+C 复制。跨会话工具使用完整 Codex 会话 ID;现有管理与 /resume 使用 Netizen 编号。";
|
|
1635
1637
|
details.append(hint);
|
|
1638
|
+
if (!session.nativeThreadId) {
|
|
1639
|
+
const pending = document.createElement("p");
|
|
1640
|
+
pending.className = "meta-line";
|
|
1641
|
+
pending.textContent = "Codex 会话 ID 尚未生成,首条消息后创建。";
|
|
1642
|
+
details.append(pending);
|
|
1643
|
+
}
|
|
1636
1644
|
td.append(details);
|
|
1637
1645
|
row.append(td);
|
|
1638
1646
|
}
|
|
@@ -1862,20 +1870,6 @@ function wireSessionActions(actions, session) {
|
|
|
1862
1870
|
});
|
|
1863
1871
|
const schedule = actionButton("创建定时任务", () => openScheduleForSession(session, schedule));
|
|
1864
1872
|
secondary.append(schedule);
|
|
1865
|
-
if (a.createLazy) secondary.append(actionButton("新建 Lazy", async () => {
|
|
1866
|
-
if (!state.projects) await loadProjects();
|
|
1867
|
-
const alias = window.prompt("Project alias");
|
|
1868
|
-
if (!alias) return;
|
|
1869
|
-
const project = state.projects.items.find((item) => item.alias === alias && item.enabled);
|
|
1870
|
-
if (!project) return setStatus("未找到当前页中已启用的 Project,请先刷新 Projects。", true);
|
|
1871
|
-
const activate = window.confirm("是否立即设为当前会话?");
|
|
1872
|
-
await mutate("/api/v1/sessions/create-lazy", a.createLazy, {
|
|
1873
|
-
projectAlias: alias,
|
|
1874
|
-
projectRevision: project.revision,
|
|
1875
|
-
activate,
|
|
1876
|
-
turnSettings: null,
|
|
1877
|
-
});
|
|
1878
|
-
}));
|
|
1879
1873
|
if (a.configure) {
|
|
1880
1874
|
const button = actionButton("配置", () => openSessionSettingsEditor(session, button));
|
|
1881
1875
|
actions.append(button);
|
|
@@ -2047,7 +2041,7 @@ function openSessionSettingsEditor(session, returnFocus) {
|
|
|
2047
2041
|
privateChat, contextAvailable: !privateChat && base.message_context_mode === "catch-up",
|
|
2048
2042
|
loading: true, saving: false, optionsSerial: 0 };
|
|
2049
2043
|
sessionSettingsInput("editor").hidden = false;
|
|
2050
|
-
sessionSettingsInput("identity").textContent = `${session.nativeTitle || "未命名 Session"} ·
|
|
2044
|
+
sessionSettingsInput("identity").textContent = `${session.nativeTitle || "未命名 Session"} · Netizen 会话编号:${session.shortId} · ${session.projectAlias}`;
|
|
2051
2045
|
renderSessionSettingsEditor();
|
|
2052
2046
|
if (!sessionSettingsInput("drawer").open) sessionSettingsInput("drawer").showModal();
|
|
2053
2047
|
document.body.classList.toggle("session-settings-drawer-open", true);
|
|
@@ -2647,18 +2641,20 @@ function confirmDiscardChanges(changed) {
|
|
|
2647
2641
|
|
|
2648
2642
|
function hasUnsavedEditors() {
|
|
2649
2643
|
return sessionSettingsHasChanges() || defaultEditorHasChanges() || scheduleEditorHasChanges()
|
|
2650
|
-
|| Boolean(pendingScheduleDraft?.dirty);
|
|
2644
|
+
|| Boolean(pendingScheduleDraft?.dirty) || Boolean(window.NetizenSessionAccess?.dirty());
|
|
2651
2645
|
}
|
|
2652
2646
|
|
|
2653
2647
|
// Navigation asks once before closing any editor. Busy submissions retain the
|
|
2654
2648
|
// existing fail-closed boundary; this helper never cancels or repeats a POST.
|
|
2655
2649
|
function confirmDiscardEditors() {
|
|
2656
|
-
if (sessionSettingsEditor?.saving || defaultsBusy || (scheduleEditor && scheduleInput("fields").disabled)
|
|
2650
|
+
if (sessionSettingsEditor?.saving || defaultsBusy || (scheduleEditor && scheduleInput("fields").disabled)
|
|
2651
|
+
|| window.NetizenSessionAccess?.busy()) return false;
|
|
2657
2652
|
if (!confirmDiscardChanges(hasUnsavedEditors())) return false;
|
|
2658
2653
|
closeSessionSettingsEditor({ confirmed: true });
|
|
2659
2654
|
closeDefaultEditor({ confirmed: true });
|
|
2660
2655
|
if (scheduleEditor) closeScheduleEditor({ confirmed: true });
|
|
2661
2656
|
cancelScheduleSelection({ confirmed: true });
|
|
2657
|
+
window.NetizenSessionAccess?.discard();
|
|
2662
2658
|
return true;
|
|
2663
2659
|
}
|
|
2664
2660
|
|
|
@@ -2891,7 +2887,7 @@ function renderScheduleTarget() {
|
|
|
2891
2887
|
scheduleInput("binding").value = selected;
|
|
2892
2888
|
scheduleInput("select-session").hidden = Boolean(selected);
|
|
2893
2889
|
scheduleInput("binding-summary").textContent = target
|
|
2894
|
-
? `${target.nativeTitle || target.shortId || "未命名会话"}\n${target.chatLabel || target.chatId} · ${target.projectAlias}\
|
|
2890
|
+
? `${target.nativeTitle || target.shortId || "未命名会话"}\n${target.chatLabel || target.chatId} · ${target.projectAlias}\nNetizen 会话编号:${target.shortId || target.bindingId.slice(0, 8)}${target.topicId ? ` · 话题 ${target.topicId}` : ""}`
|
|
2895
2891
|
+ (target.pointerState !== "current" || target.catalogState === "archived" ? "\n目标当前不是可执行的当前会话,计划将自动暂停;不会自动切换或恢复会话。" : "")
|
|
2896
2892
|
: selected ? `${editor.plan.target_label || selected}\n${editor.plan.chat?.chatLabel || editor.plan.chat_id} · ${editor.plan.project_alias}`
|
|
2897
2893
|
: "请前往 Sessions 找到具体会话,再点击该行的“创建定时任务”。已填写内容会在当前页面保留。";
|
|
@@ -3927,7 +3923,10 @@ async function refresh(tab, cursor = undefined) {
|
|
|
3927
3923
|
if (tab === "updates") await loadUpdates();
|
|
3928
3924
|
if (tab === "schedules" && await loadSchedules(cursor) === false) return false;
|
|
3929
3925
|
if (tab === "defaults") await loadDefaults();
|
|
3930
|
-
if (tab === "system")
|
|
3926
|
+
if (tab === "system") {
|
|
3927
|
+
const results = await Promise.all([window.NetizenIdentity.loadUsers(), window.NetizenSessionAccess?.load()]);
|
|
3928
|
+
if (results[1] === false) return false;
|
|
3929
|
+
}
|
|
3931
3930
|
if (state.authExpired) return false;
|
|
3932
3931
|
if (isCurrentView()) setStatus("已更新。");
|
|
3933
3932
|
return true;
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
<link rel="stylesheet" href="/static/chat-picker.css">
|
|
9
9
|
<script src="/static/chat-picker.js" defer></script>
|
|
10
10
|
<script src="/static/identity.js" defer></script>
|
|
11
|
+
<script src="/static/session-access.js" defer></script>
|
|
11
12
|
<script src="/static/admin.js" defer></script>
|
|
12
13
|
</head>
|
|
13
14
|
<body>
|
|
@@ -389,6 +390,35 @@
|
|
|
389
390
|
<div class="identity-panel-actions"><button id="admin-selector-retry" class="refresh" hidden>重试加载</button><button id="admin-selector-reload" class="refresh" hidden>重新加载页面</button><button id="admin-user-confirm" class="action" disabled>确认添加</button></div>
|
|
390
391
|
</section>
|
|
391
392
|
<ul id="admin-users" class="admin-users" aria-label="管理员名单"></ul>
|
|
393
|
+
<section class="session-access" aria-labelledby="session-access-heading">
|
|
394
|
+
<h3 id="session-access-heading">跨会话工具权限</h3>
|
|
395
|
+
<p class="defaults-help">仅控制 Agent 对本实例普通会话的跨会话访问。所有来源聊天共用规则,范围按目标聊天匹配,包含其中的主会话与话题。两组权限互不依赖。</p>
|
|
396
|
+
<form id="session-access-form" class="card-form">
|
|
397
|
+
<fieldset id="session-access-fields" disabled>
|
|
398
|
+
<div class="session-access-grid">
|
|
399
|
+
<section>
|
|
400
|
+
<h4>发现</h4><p>允许列出、搜索会话标识及位置;不能单独授权读取消息正文。</p>
|
|
401
|
+
<label>目标范围<select id="session-access-discovery-mode"><option value="all">全部</option><option value="only">仅指定聊天</option><option value="exclude">排除指定聊天(黑名单)</option><option value="disabled">关闭</option></select></label>
|
|
402
|
+
<div id="session-access-discovery-targets" hidden>
|
|
403
|
+
<div id="session-access-discovery-picker"></div>
|
|
404
|
+
<label>聊天 ID,每行一个<textarea id="session-access-discovery-chats" rows="5" maxlength="257000" placeholder="oc_…" aria-describedby="session-access-chat-help"></textarea></label>
|
|
405
|
+
</div>
|
|
406
|
+
</section>
|
|
407
|
+
<section>
|
|
408
|
+
<h4>读取与发送</h4><p>允许读取、发送和等待结果;在当前聊天创建话题并启动任务也检查此范围。关闭发现后仍可凭完整 Codex 会话 ID 操作。</p>
|
|
409
|
+
<label>目标范围<select id="session-access-readSend-mode"><option value="all">全部</option><option value="only">仅指定聊天</option><option value="exclude">排除指定聊天(黑名单)</option><option value="disabled">关闭</option></select></label>
|
|
410
|
+
<div id="session-access-readSend-targets" hidden>
|
|
411
|
+
<div id="session-access-readSend-picker"></div>
|
|
412
|
+
<label>聊天 ID,每行一个<textarea id="session-access-readSend-chats" rows="5" maxlength="257000" placeholder="oc_…" aria-describedby="session-access-chat-help"></textarea></label>
|
|
413
|
+
</div>
|
|
414
|
+
</section>
|
|
415
|
+
</div>
|
|
416
|
+
<p id="session-access-chat-help" class="defaults-field-help">可选择群聊加入名单,或填写聊天 ID(单聊也用聊天 ID,不是用户 ID)。聊天 ID 可在会话列表的“会话标识”中复制。名单为空时,“仅指定聊天”不允许任何目标,“排除指定聊天”允许全部目标。</p>
|
|
417
|
+
</fieldset>
|
|
418
|
+
<p id="session-access-note" class="defaults-field-help" role="status"></p>
|
|
419
|
+
<div class="actions"><button id="session-access-cancel" class="refresh" type="button" disabled>放弃修改</button><button id="session-access-save" class="action" type="submit" disabled>保存权限</button></div>
|
|
420
|
+
</form>
|
|
421
|
+
</section>
|
|
392
422
|
</div>
|
|
393
423
|
</section>
|
|
394
424
|
<section id="updates" class="panel" aria-labelledby="updates-heading" hidden>
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
window.NetizenSessionAccess = (() => {
|
|
4
|
+
const node = (id) => document.querySelector(`#session-access-${id}`);
|
|
5
|
+
const groups = ["discovery", "readSend"];
|
|
6
|
+
const pickers = new Map();
|
|
7
|
+
let snapshot = null;
|
|
8
|
+
let baseline = "";
|
|
9
|
+
let pending = false;
|
|
10
|
+
let expired = false;
|
|
11
|
+
let generation = 0;
|
|
12
|
+
|
|
13
|
+
function rule(group) {
|
|
14
|
+
const mode = node(`${group}-mode`).value;
|
|
15
|
+
return { mode, chatIds: ["only", "exclude"].includes(mode)
|
|
16
|
+
? [...new Set(node(`${group}-chats`).value.split(/\s+/).filter(Boolean))].sort() : [] };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function definition() {
|
|
20
|
+
return Object.fromEntries(groups.map((group) => [group, rule(group)]));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function dirty() {
|
|
24
|
+
return Boolean(snapshot) && JSON.stringify(definition()) !== baseline;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function renderControls() {
|
|
28
|
+
node("fields").disabled = expired || pending || !snapshot;
|
|
29
|
+
for (const group of groups) {
|
|
30
|
+
const listed = ["only", "exclude"].includes(node(`${group}-mode`).value);
|
|
31
|
+
node(`${group}-targets`).hidden = !listed;
|
|
32
|
+
node(`${group}-chats`).disabled = expired || pending || !snapshot || !listed;
|
|
33
|
+
pickers.get(group)?.setDisabled(expired || pending || !snapshot || !listed);
|
|
34
|
+
}
|
|
35
|
+
node("save").disabled = expired || pending || !snapshot?.saveAction || !dirty();
|
|
36
|
+
node("cancel").disabled = expired || pending || !dirty();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function discard() {
|
|
40
|
+
generation += 1;
|
|
41
|
+
for (const group of groups) {
|
|
42
|
+
if (snapshot) {
|
|
43
|
+
node(`${group}-mode`).value = snapshot[group].mode;
|
|
44
|
+
node(`${group}-chats`).value = snapshot[group].chatIds.join("\n");
|
|
45
|
+
}
|
|
46
|
+
pickers.get(group)?.close();
|
|
47
|
+
}
|
|
48
|
+
baseline = JSON.stringify(definition());
|
|
49
|
+
renderControls();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function initializePickers() {
|
|
53
|
+
for (const group of groups) {
|
|
54
|
+
if (pickers.has(group)) continue;
|
|
55
|
+
pickers.set(group, window.createChatPicker(node(`${group}-picker`), {
|
|
56
|
+
id: `session-access-${group}-group`, label: "添加群聊", fetchPage: fetchChatPage,
|
|
57
|
+
onChange(chat) {
|
|
58
|
+
if (chat && !pending && !expired) {
|
|
59
|
+
generation += 1;
|
|
60
|
+
const ids = new Set(node(`${group}-chats`).value.split(/\s+/).filter(Boolean));
|
|
61
|
+
ids.add(chat.chatId);
|
|
62
|
+
node(`${group}-chats`).value = [...ids].join("\n");
|
|
63
|
+
pickers.get(group).reset();
|
|
64
|
+
renderControls();
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function load() {
|
|
72
|
+
if (expired || pending || !confirmDiscardChanges(dirty())) return false;
|
|
73
|
+
initializePickers();
|
|
74
|
+
const version = ++generation;
|
|
75
|
+
const value = await api("/api/v1/session-tool-access");
|
|
76
|
+
// A late refresh must not overwrite edits made while the GET was pending.
|
|
77
|
+
if (expired || version !== generation) return false;
|
|
78
|
+
snapshot = value;
|
|
79
|
+
discard();
|
|
80
|
+
node("note").textContent = value.saveAction ? "保存后立即应用于新的工具访问。" : "实例配置不可编辑。";
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function save(event) {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
if (expired || pending || !snapshot?.saveAction || !dirty()) return;
|
|
87
|
+
const body = actionPayload(snapshot.saveAction, definition());
|
|
88
|
+
pending = true;
|
|
89
|
+
generation += 1;
|
|
90
|
+
renderControls();
|
|
91
|
+
try {
|
|
92
|
+
const value = await api("/api/v1/session-tool-access/save", {
|
|
93
|
+
method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body),
|
|
94
|
+
});
|
|
95
|
+
if (expired) return;
|
|
96
|
+
snapshot = value;
|
|
97
|
+
discard();
|
|
98
|
+
node("note").textContent = "跨会话工具权限已保存并生效。";
|
|
99
|
+
setStatus("跨会话工具权限已保存。");
|
|
100
|
+
} catch (error) {
|
|
101
|
+
if (!expired) {
|
|
102
|
+
// A consumed grant or unknown result is never silently replayed.
|
|
103
|
+
snapshot.saveAction = null;
|
|
104
|
+
node("note").textContent = "请刷新核对当前权限后再保存;本次修改未自动重试。";
|
|
105
|
+
setStatus(error.message, true);
|
|
106
|
+
}
|
|
107
|
+
} finally {
|
|
108
|
+
pending = false;
|
|
109
|
+
renderControls();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
for (const group of groups) {
|
|
114
|
+
for (const field of ["mode", "chats"]) {
|
|
115
|
+
node(`${group}-${field}`).addEventListener(field === "mode" ? "change" : "input", () => {
|
|
116
|
+
generation += 1;
|
|
117
|
+
renderControls();
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
node("form").addEventListener("submit", save);
|
|
122
|
+
node("cancel").addEventListener("click", discard);
|
|
123
|
+
return {
|
|
124
|
+
load, dirty, discard, busy: () => pending,
|
|
125
|
+
expire() { expired = true; generation += 1; renderControls(); },
|
|
126
|
+
};
|
|
127
|
+
})();
|