collavre 0.24.0 → 0.25.0
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.
- checksums.yaml +4 -4
- data/README.md +0 -1
- data/app/assets/stylesheets/collavre/comments_popup.css +165 -99
- data/app/assets/stylesheets/collavre/creatives.css +346 -37
- data/app/assets/stylesheets/collavre/desktop_setup.css +246 -0
- data/app/assets/stylesheets/collavre/gnb.css +64 -3
- data/app/assets/stylesheets/collavre/landing.css +108 -3
- data/app/assets/stylesheets/collavre/mention_menu.css +32 -0
- data/app/assets/stylesheets/collavre/popup.css +14 -0
- data/app/assets/stylesheets/collavre/print.css +0 -1
- data/app/assets/stylesheets/collavre/search_popup.css +1 -1
- data/app/assets/stylesheets/collavre/secret_fields.css +3 -0
- data/app/assets/stylesheets/collavre/workspace.css +307 -0
- data/app/channels/collavre/agent_channel.rb +14 -21
- data/app/channels/collavre/comments_presence_channel.rb +181 -21
- data/app/channels/collavre/inbox_badge_channel.rb +7 -1
- data/app/components/collavre/inbox/badge_component.rb +6 -13
- data/app/components/collavre/progress_filter_component.html.erb +2 -2
- data/app/components/collavre/progress_filter_component.rb +20 -0
- data/app/controllers/collavre/admin/settings_controller.rb +4 -1
- data/app/controllers/collavre/agent_connections_controller.rb +165 -0
- data/app/controllers/collavre/agent_gateways_controller.rb +132 -0
- data/app/controllers/collavre/agent_provisioning_controller.rb +79 -0
- data/app/controllers/collavre/api/v1/agents_controller.rb +45 -97
- data/app/controllers/collavre/application_controller.rb +13 -2
- data/app/controllers/collavre/comment_read_pointers_controller.rb +69 -40
- data/app/controllers/collavre/comments_controller.rb +45 -131
- data/app/controllers/collavre/concerns/shareable.rb +9 -3
- data/app/controllers/collavre/creatives_controller.rb +144 -11
- data/app/controllers/collavre/desktop_gateway_registrations_controller.rb +173 -0
- data/app/controllers/collavre/desktop_setup_controller.rb +119 -0
- data/app/controllers/collavre/desktop_sidecar_health_controller.rb +35 -0
- data/app/controllers/collavre/features_controller.rb +57 -0
- data/app/controllers/collavre/invites_controller.rb +12 -1
- data/app/controllers/collavre/llm_models_controller.rb +8 -0
- data/app/controllers/collavre/notices_controller.rb +20 -0
- data/app/controllers/collavre/tasks_controller.rb +40 -6
- data/app/controllers/collavre/topics_controller.rb +130 -53
- data/app/controllers/collavre/user_creative_preferences_controller.rb +214 -30
- data/app/controllers/concerns/collavre/comments/batch_operations.rb +15 -3
- data/app/controllers/concerns/collavre/comments/conversion.rb +1 -1
- data/app/controllers/concerns/collavre/users_controller/ai_user_management.rb +118 -8
- data/app/controllers/concerns/collavre/users_controller/profile_and_settings.rb +1 -15
- data/app/controllers/concerns/collavre/users_controller/registration.rb +2 -2
- data/app/errors/collavre/turn_deadline_error.rb +20 -0
- data/app/helpers/collavre/application_helper.rb +38 -0
- data/app/helpers/collavre/creatives_helper.rb +56 -22
- data/app/helpers/collavre/navigation_helper.rb +12 -0
- data/app/javascript/collavre.js +1 -2
- data/app/javascript/components/InlineLexicalEditor.jsx +30 -21
- data/app/javascript/components/__tests__/creative_tree_row_parent_id.test.js +32 -2
- data/app/javascript/components/__tests__/creative_tree_row_progress_toggle.test.js +185 -0
- data/app/javascript/components/creative_tree_row.js +62 -22
- data/app/javascript/controllers/__tests__/agent_connection_controller.test.js +195 -0
- data/app/javascript/controllers/__tests__/desktop_proxy_setup_controller.test.js +96 -0
- data/app/javascript/controllers/__tests__/index.test.js +42 -0
- data/app/javascript/controllers/__tests__/last_visited_creative_controller.test.js +103 -0
- data/app/javascript/controllers/__tests__/link_creative_controller.test.js +253 -2
- data/app/javascript/controllers/__tests__/progress_filter_controller.test.js +134 -0
- data/app/javascript/controllers/__tests__/search_popup_controller.test.js +310 -0
- data/app/javascript/controllers/__tests__/topic_list_controller.test.js +111 -0
- data/app/javascript/controllers/__tests__/workspace_tree_controller.test.js +1011 -0
- data/app/javascript/controllers/agent_connection_controller.js +357 -0
- data/app/javascript/controllers/agent_vendor_controller.js +23 -0
- data/app/javascript/controllers/comment_controller.js +3 -1
- data/app/javascript/controllers/comments/__tests__/feature_cards_controller.test.js +223 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_default_placeholder.test.js +83 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_draft.test.js +2069 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_ime_send.test.js +324 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_review.test.js +28 -2
- data/app/javascript/controllers/comments/__tests__/form_controller_search_submit.test.js +106 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_stashed_draft.test.js +134 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_stashed_draft_creative_switch.test.js +166 -0
- data/app/javascript/controllers/comments/__tests__/form_controller_stashed_draft_failure.test.js +183 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_deep_link_topic.test.js +467 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_docked.test.js +115 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_prev_message.test.js +245 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_read_pointer.test.js +276 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_stream_archived.test.js +221 -0
- data/app/javascript/controllers/comments/__tests__/list_controller_stream_search.test.js +104 -0
- data/app/javascript/controllers/comments/__tests__/placeholder_controller.test.js +79 -0
- data/app/javascript/controllers/comments/__tests__/popup_controller.test.js +754 -1
- data/app/javascript/controllers/comments/__tests__/presence_controller.test.js +717 -15
- data/app/javascript/controllers/comments/__tests__/prev_message_navigator.test.js +129 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_action_errors.test.js +184 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_archived.test.js +879 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_creation_container.test.js +154 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_creation_scroll.test.js +92 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_delete.test.js +130 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_docked.test.js +32 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_last_topic_echo.test.js +1938 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_primary_agent.test.js +256 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_scroll.test.js +182 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_selection_race.test.js +981 -0
- data/app/javascript/controllers/comments/__tests__/topics_controller_topic_list.test.js +313 -0
- data/app/javascript/controllers/comments/feature_cards_controller.js +83 -0
- data/app/javascript/controllers/comments/form_controller.js +795 -14
- data/app/javascript/controllers/comments/list_controller.js +338 -52
- data/app/javascript/controllers/comments/placeholder_controller.js +30 -0
- data/app/javascript/controllers/comments/popup_controller.js +425 -83
- data/app/javascript/controllers/comments/presence_controller.js +317 -55
- data/app/javascript/controllers/comments/prev_message_navigator.js +94 -0
- data/app/javascript/controllers/comments/topics_controller.js +1772 -100
- data/app/javascript/controllers/common_popup_controller.js +2 -2
- data/app/javascript/controllers/creatives/__tests__/select_mode_controller.test.js +139 -0
- data/app/javascript/controllers/creatives/__tests__/tree_controller.test.js +605 -0
- data/app/javascript/controllers/creatives/__tests__/write_access_request_controller.test.js +125 -0
- data/app/javascript/controllers/creatives/select_mode_controller.js +7 -2
- data/app/javascript/controllers/creatives/tree_controller.js +140 -31
- data/app/javascript/controllers/creatives/write_access_request_controller.js +58 -0
- data/app/javascript/controllers/desktop_proxy_setup_controller.js +51 -0
- data/app/javascript/controllers/gateway_check_controller.js +36 -0
- data/app/javascript/controllers/index.js +25 -1
- data/app/javascript/controllers/last_visited_creative_controller.js +58 -0
- data/app/javascript/controllers/link_creative_controller.js +89 -18
- data/app/javascript/controllers/progress_filter_controller.js +12 -22
- data/app/javascript/controllers/search_popup_controller.js +64 -46
- data/app/javascript/controllers/share_user_search_controller.js +2 -2
- data/app/javascript/controllers/topic_list_controller.js +44 -7
- data/app/javascript/controllers/workspace_tree_controller.js +662 -0
- data/app/javascript/creatives/__tests__/tree_renderer.test.js +80 -0
- data/app/javascript/creatives/drag_drop/__tests__/drop_completion_empty_state.test.js +98 -0
- data/app/javascript/creatives/drag_drop/__tests__/topic_move_released_agent.test.js +125 -0
- data/app/javascript/creatives/drag_drop/event_handlers.js +12 -0
- data/app/javascript/creatives/tree_renderer.js +65 -22
- data/app/javascript/lib/__tests__/chat_drafts.test.js +1458 -0
- data/app/javascript/lib/__tests__/common_popup_bounds.test.js +8 -3
- data/app/javascript/lib/__tests__/common_popup_placement.test.js +374 -0
- data/app/javascript/lib/__tests__/common_popup_reshow.test.js +131 -0
- data/app/javascript/lib/__tests__/creative_link_prefetch.test.js +46 -0
- data/app/javascript/lib/__tests__/last_visited_creative.test.js +87 -0
- data/app/javascript/lib/__tests__/skill_html_entities.test.js +23 -0
- data/app/javascript/lib/__tests__/turbo_stream_actions.test.js +190 -0
- data/app/javascript/lib/api/__tests__/creatives.test.js +68 -0
- data/app/javascript/lib/api/__tests__/csrf_fetch.test.js +27 -0
- data/app/javascript/lib/api/__tests__/topics_save_last_topic.test.js +112 -0
- data/app/javascript/lib/api/creatives.js +32 -13
- data/app/javascript/lib/api/csrf_fetch.js +6 -4
- data/app/javascript/lib/api/topics.js +63 -5
- data/app/javascript/lib/chat_drafts.js +786 -0
- data/app/javascript/lib/common_popup.js +164 -25
- data/app/javascript/lib/creative_link_prefetch.js +27 -0
- data/app/javascript/lib/last_visited_creative.js +97 -0
- data/app/javascript/lib/lexical/__tests__/creative_link_node.test.js +162 -0
- data/app/javascript/lib/lexical/__tests__/creative_link_trigger.test.js +133 -0
- data/app/javascript/lib/lexical/__tests__/link_toolbar.test.js +62 -0
- data/app/javascript/lib/lexical/creative_link_node.js +101 -0
- data/app/javascript/lib/lexical/creative_link_trigger.js +98 -0
- data/app/javascript/lib/lexical/link_toolbar.js +23 -0
- data/app/javascript/lib/turbo_stream_actions.js +23 -16
- data/app/javascript/lib/utils/__tests__/filter_navigation.test.js +210 -0
- data/app/javascript/lib/utils/__tests__/markdown.test.js +44 -0
- data/app/javascript/lib/utils/filter_navigation.js +100 -0
- data/app/javascript/modules/__tests__/command_menu_creative_picker.test.js +62 -0
- data/app/javascript/modules/__tests__/command_menu_typeahead.test.js +267 -0
- data/app/javascript/modules/__tests__/creative_link_picker.test.js +85 -0
- data/app/javascript/modules/__tests__/creative_row_editor_archive.test.js +391 -0
- data/app/javascript/modules/__tests__/creative_row_editor_delegated_clicks.test.js +158 -0
- data/app/javascript/modules/__tests__/creative_row_editor_empty_state_recovery.test.js +519 -0
- data/app/javascript/modules/__tests__/creative_row_editor_empty_state_removal.test.js +346 -0
- data/app/javascript/modules/__tests__/creative_row_editor_session.test.js +144 -0
- data/app/javascript/modules/__tests__/creative_tree_dom.test.js +30 -0
- data/app/javascript/modules/__tests__/creative_tree_empty_state.test.js +186 -0
- data/app/javascript/modules/__tests__/dom_listener_registry.test.js +67 -0
- data/app/javascript/modules/__tests__/support/inline_editor_dom.js +159 -0
- data/app/javascript/modules/command_args_form.js +0 -12
- data/app/javascript/modules/command_menu.js +80 -38
- data/app/javascript/modules/creative_link_picker.js +56 -0
- data/app/javascript/modules/creative_row_editor.js +446 -243
- data/app/javascript/modules/creative_row_editor_delegated_clicks.js +87 -0
- data/app/javascript/modules/creative_tree_dom.js +4 -0
- data/app/javascript/modules/creative_tree_empty_state.js +80 -0
- data/app/javascript/modules/dom_listener_registry.js +23 -0
- data/app/javascript/modules/mention_menu.js +2 -3
- data/app/javascript/utils/__tests__/caret_anchor.test.js +75 -0
- data/app/javascript/utils/__tests__/chevron_icons.test.js +15 -0
- data/app/javascript/utils/caret_position.js +10 -0
- data/app/javascript/utils/chevron_icons.js +7 -0
- data/app/jobs/collavre/ai_agent_job.rb +262 -72
- data/app/jobs/collavre/cancel_offline_delegated_tasks_job.rb +11 -36
- data/app/jobs/collavre/comment_badges_broadcast_job.rb +28 -0
- data/app/jobs/collavre/comment_link_preview_job.rb +33 -0
- data/app/jobs/collavre/comment_notification_job.rb +14 -0
- data/app/jobs/collavre/comment_push_delivery_sweep_job.rb +17 -0
- data/app/jobs/collavre/compress_job.rb +33 -22
- data/app/jobs/collavre/creative_broadcast_job.rb +161 -48
- data/app/jobs/collavre/cron_action_job.rb +36 -18
- data/app/jobs/collavre/drop_trigger_job.rb +23 -9
- data/app/jobs/collavre/merge_comments_job.rb +33 -16
- data/app/jobs/collavre/push_notification_job.rb +62 -18
- data/app/jobs/collavre/restore_dropped_dispatches_job.rb +17 -0
- data/app/jobs/collavre/stuck_detector_job.rb +1 -1
- data/app/jobs/collavre/touch_creative_subtree_job.rb +14 -0
- data/app/models/collavre/agent_gateway.rb +200 -0
- data/app/models/collavre/agent_subscription.rb +4 -4
- data/app/models/collavre/agent_workspace.rb +210 -0
- data/app/models/collavre/comment/broadcastable.rb +22 -52
- data/app/models/collavre/comment/notifiable.rb +154 -77
- data/app/models/collavre/comment/topic_membership.rb +41 -0
- data/app/models/collavre/comment.rb +336 -31
- data/app/models/collavre/comment_notification_delivery.rb +61 -0
- data/app/models/collavre/comment_presence_store/cache_batches.rb +64 -0
- data/app/models/collavre/comment_presence_store.rb +272 -12
- data/app/models/collavre/comment_read_pointer.rb +9 -15
- data/app/models/collavre/creative/describable.rb +8 -2
- data/app/models/collavre/creative/permissible.rb +11 -0
- data/app/models/collavre/creative.rb +29 -4
- data/app/models/collavre/creative_share.rb +109 -4
- data/app/models/collavre/current.rb +1 -0
- data/app/models/collavre/llm_model.rb +62 -0
- data/app/models/collavre/system_setting.rb +12 -1
- data/app/models/collavre/task.rb +121 -2
- data/app/models/collavre/topic.rb +51 -0
- data/app/models/collavre/user.rb +101 -41
- data/app/models/collavre/user_creative_preference.rb +3 -1
- data/app/services/collavre/agent_provisioning/archive.rb +108 -0
- data/app/services/collavre/ai_agent/a2a_dispatcher.rb +16 -3
- data/app/services/collavre/ai_agent/agent_lifecycle_manager.rb +63 -6
- data/app/services/collavre/ai_agent/approval_handler.rb +12 -4
- data/app/services/collavre/ai_agent/claude_channel_adapter.rb +10 -5
- data/app/services/collavre/ai_agent/merged_trigger_comments.rb +164 -0
- data/app/services/collavre/ai_agent/message_builder.rb +103 -16
- data/app/services/collavre/ai_agent/session_provisioner.rb +3 -7
- data/app/services/collavre/ai_agent/task_claim_service.rb +29 -15
- data/app/services/collavre/ai_agent/task_reply_service.rb +67 -0
- data/app/services/collavre/ai_agent_service.rb +108 -20
- data/app/services/collavre/ai_client.rb +211 -21
- data/app/services/collavre/cli_proxy/client.rb +147 -0
- data/app/services/collavre/cli_proxy/endpoint_policy.rb +81 -0
- data/app/services/collavre/cli_proxy/identity.rb +47 -0
- data/app/services/collavre/cli_proxy/safe_net_http_adapter.rb +19 -0
- data/app/services/collavre/command_menu_service.rb +0 -10
- data/app/services/collavre/comment_move_service.rb +96 -7
- data/app/services/collavre/comment_snapshot_restore_service.rb +11 -5
- data/app/services/collavre/comments/action_executor.rb +48 -20
- data/app/services/collavre/comments/command_processor.rb +0 -1
- data/app/services/collavre/comments/list_response.rb +133 -0
- data/app/services/collavre/comments/read_pointer_writer.rb +210 -0
- data/app/services/collavre/comments/read_receipt_broadcaster.rb +157 -0
- data/app/services/collavre/comments/read_receipt_index.rb +152 -0
- data/app/services/collavre/comments/topic_command.rb +72 -1
- data/app/services/collavre/comments/topic_mutation.rb +20 -0
- data/app/services/collavre/creatives/breadcrumb_resolver.rb +1 -1
- data/app/services/collavre/creatives/comment_badge_index.rb +299 -27
- data/app/services/collavre/creatives/reorderer.rb +15 -3
- data/app/services/collavre/creatives/tree_builder.rb +1 -1
- data/app/services/collavre/creatives/tree_formatter.rb +5 -6
- data/app/services/collavre/creatives/workspace_path_resolver.rb +50 -0
- data/app/services/collavre/creatives/workspace_tree_builder.rb +92 -0
- data/app/services/collavre/crons/recurring_topic_tasks.rb +23 -0
- data/app/services/collavre/home_page_path.rb +55 -0
- data/app/services/collavre/html_text.rb +64 -0
- data/app/services/collavre/http_client.rb +11 -2
- data/app/services/collavre/inbox_reply_service.rb +1 -1
- data/app/services/collavre/markdown_converter.rb +13 -1
- data/app/services/collavre/orchestration/agent_orchestrator.rb +776 -81
- data/app/services/collavre/orchestration/arbiter.rb +48 -5
- data/app/services/collavre/orchestration/deferred_trigger_scope.rb +53 -0
- data/app/services/collavre/orchestration/delivery_record.rb +792 -0
- data/app/services/collavre/orchestration/loop_breaker.rb +10 -4
- data/app/services/collavre/orchestration/matcher.rb +132 -17
- data/app/services/collavre/orchestration/policy_resolver.rb +58 -10
- data/app/services/collavre/orchestration/scheduler.rb +10 -4
- data/app/services/collavre/orchestration/scheduling_hooks.rb +10 -0
- data/app/services/collavre/orchestration/selection.rb +43 -0
- data/app/services/collavre/orchestration/stuck_detector.rb +25 -112
- data/app/services/collavre/orchestration/task_coalescer.rb +355 -0
- data/app/services/collavre/orchestration/topic_slot.rb +73 -0
- data/app/services/collavre/system_events/context_builder.rb +60 -11
- data/app/services/collavre/system_events/dispatcher.rb +58 -12
- data/app/services/collavre/system_events/envelope.rb +73 -0
- data/app/services/collavre/system_events/vocabulary.rb +45 -0
- data/app/services/collavre/tools/creative_retrieval_service.rb +1 -1
- data/app/services/collavre/tools/cron_create_service.rb +32 -18
- data/app/services/collavre/tools/id_list.rb +38 -0
- data/app/services/collavre/tools/topic_authorizer.rb +61 -7
- data/app/services/collavre/tools/topic_branch_service.rb +85 -0
- data/app/services/collavre/tools/topic_create_service.rb +117 -0
- data/app/services/collavre/tools/topic_list_service.rb +101 -0
- data/app/services/collavre/tools/topic_message_create_service.rb +192 -0
- data/app/services/collavre/tools/topic_messages_service.rb +346 -0
- data/app/services/collavre/tools/topic_move_service.rb +108 -0
- data/app/services/collavre/tools/topic_selection.rb +59 -0
- data/app/services/collavre/tools/topic_update_service.rb +165 -0
- data/app/services/collavre/topic_branch_service.rb +39 -10
- data/app/services/collavre/topics/agent_resolver.rb +87 -0
- data/app/services/collavre/topics/char_budget.rb +70 -0
- data/app/services/collavre/topics/last_topic_preference_payload.rb +18 -0
- data/app/services/collavre/topics/message_page.rb +380 -0
- data/app/services/collavre/topics/message_page_markdown.rb +102 -0
- data/app/services/collavre/topics/message_scope.rb +61 -0
- data/app/services/collavre/topics/message_stats.rb +92 -0
- data/app/services/collavre/topics/move_blocker.rb +47 -0
- data/app/services/collavre/topics/next_name.rb +35 -0
- data/app/services/collavre/topics/pin_rejection.rb +25 -0
- data/app/services/collavre/topics/read_pointer_relocator.rb +71 -0
- data/app/services/collavre/topics/reserved_name.rb +18 -0
- data/app/services/collavre/topics/serializer.rb +92 -0
- data/app/services/collavre/topics/topic_destroy.rb +30 -0
- data/app/services/collavre/topics/topic_move.rb +80 -0
- data/app/services/collavre/topics/topic_move_effects.rb +35 -0
- data/app/services/collavre/topics/topic_mutation.rb +27 -0
- data/app/views/collavre/admin/integrations/_setting_row.html.erb +5 -8
- data/app/views/collavre/admin/settings/_system_tab.html.erb +7 -0
- data/app/views/collavre/agent_connections/show.html.erb +77 -0
- data/app/views/collavre/agent_gateways/_form.html.erb +71 -0
- data/app/views/collavre/agent_gateways/edit.html.erb +2 -0
- data/app/views/collavre/agent_gateways/index.html.erb +54 -0
- data/app/views/collavre/agent_gateways/new.html.erb +2 -0
- data/app/views/collavre/comments/_comments_popup.html.erb +32 -17
- data/app/views/collavre/comments/_empty_state.html.erb +33 -0
- data/app/views/collavre/comments/_empty_state_minimal.html.erb +7 -0
- data/app/views/collavre/comments/_feature_card.html.erb +35 -0
- data/app/views/collavre/comments/_list.html.erb +3 -2
- data/app/views/collavre/comments/_no_search_results.html.erb +3 -0
- data/app/views/collavre/creatives/_add_button.html.erb +17 -19
- data/app/views/collavre/creatives/_empty_state.html.erb +109 -0
- data/app/views/collavre/creatives/_inline_edit_form.html.erb +5 -5
- data/app/views/collavre/creatives/_tree_loading_placeholder.html.erb +16 -0
- data/app/views/collavre/creatives/_workspace_tree.html.erb +33 -0
- data/app/views/collavre/creatives/index.html.erb +79 -18
- data/app/views/collavre/desktop_setup/show.html.erb +114 -0
- data/app/views/collavre/features/index.html.erb +42 -0
- data/app/views/collavre/features/show.html.erb +52 -0
- data/app/views/collavre/invitation_mailer/invite.html.erb +1 -1
- data/app/views/collavre/invitation_mailer/invite.text.erb +1 -1
- data/app/views/collavre/invites/show.html.erb +14 -1
- data/app/views/collavre/landing/show.html.erb +5 -1
- data/app/views/collavre/shared/_link_creative_modal.html.erb +4 -1
- data/app/views/collavre/shared/navigation/_help_button.html.erb +3 -1
- data/app/views/collavre/shared/navigation/_panels.html.erb +1 -8
- data/app/views/collavre/shared/navigation/_search_form.html.erb +13 -2
- data/app/views/collavre/user_themes/index.html.erb +1 -1
- data/app/views/collavre/users/_llm_fields.html.erb +65 -0
- data/app/views/collavre/users/_org_chart_node.html.erb +1 -1
- data/app/views/collavre/users/edit_ai.html.erb +33 -31
- data/app/views/collavre/users/new.html.erb +4 -2
- data/app/views/collavre/users/new_ai.html.erb +14 -32
- data/app/views/collavre/users/show.html.erb +13 -1
- data/app/views/layouts/collavre/landing.html.erb +9 -4
- data/config/initializers/ruby_llm_openai_reasoning_content.rb +77 -0
- data/config/locales/admin.en.yml +3 -1
- data/config/locales/admin.ko.yml +3 -1
- data/config/locales/agent_gateway.en.yml +217 -0
- data/config/locales/agent_gateway.ko.yml +217 -0
- data/config/locales/ai_agent.en.yml +0 -1
- data/config/locales/ai_agent.ko.yml +0 -1
- data/config/locales/comments.en.yml +72 -30
- data/config/locales/comments.ko.yml +72 -30
- data/config/locales/creatives.en.yml +32 -1
- data/config/locales/creatives.ko.yml +32 -1
- data/config/locales/features.en.yml +140 -0
- data/config/locales/features.ko.yml +140 -0
- data/config/locales/invites.en.yml +3 -0
- data/config/locales/invites.ko.yml +3 -0
- data/config/locales/landing.en.yml +2 -1
- data/config/locales/landing.ko.yml +2 -1
- data/config/locales/tools.en.yml +20 -0
- data/config/locales/tools.ko.yml +20 -0
- data/config/locales/users.en.yml +15 -14
- data/config/locales/users.ko.yml +14 -14
- data/config/routes.rb +45 -19
- data/db/migrate/20250911084338_backfill_creative_in_comment_inbox_items.rb +9 -1
- data/db/migrate/20260724000000_add_creative_id_index_to_comments.rb +34 -0
- data/db/migrate/20260724000001_add_creative_private_id_index_to_comments.rb +50 -0
- data/db/migrate/20260724090000_add_async_comment_notification_state.rb +64 -0
- data/db/migrate/20260727000000_add_waiting_notice_scope_to_comments.rb +30 -0
- data/db/migrate/20260727010000_add_waiting_notice_scope_to_tasks.rb +26 -0
- data/db/migrate/20260805000000_add_creative_workspace_enabled_to_users.rb +5 -0
- data/db/migrate/20260807050000_add_dismissed_notices_to_users.rb +5 -0
- data/db/migrate/20260809000000_change_creative_workspace_enabled_default_to_true.rb +18 -0
- data/db/migrate/20260809000001_create_llm_models.rb +64 -0
- data/db/migrate/20260809000002_create_agent_gateways_and_workspaces.rb +35 -0
- data/db/migrate/20260809000003_hash_agent_workspace_callback_tokens.rb +44 -0
- data/db/migrate/20260809000004_encrypt_agent_workspace_manifest_tokens.rb +59 -0
- data/db/migrate/20260810000000_split_agent_workspace_identity_axes.rb +58 -0
- data/db/migrate/20260810000001_seed_codex_custom_proxy_llm_models.rb +28 -0
- data/db/migrate/20260810010000_add_last_visited_creative_to_users.rb +8 -0
- data/db/migrate/20260810020000_add_last_visited_creative_at_to_users.rb +5 -0
- data/db/migrate/20260810030000_add_last_visited_creative_navigation_order_to_users.rb +6 -0
- data/db/migrate/20260810060000_add_last_visited_creative_issued_sequence_to_users.rb +5 -0
- data/db/migrate/20260810100000_add_desktop_managed_to_agent_gateways.rb +40 -0
- data/db/migrate/20260810100001_add_desktop_preset_adapter_to_users.rb +38 -0
- data/db/migrate/20260811000000_make_agent_gateway_completion_key_nullable.rb +7 -0
- data/db/migrate/20260812000000_remove_workflow_columns_from_tasks.rb +101 -0
- data/db/migrate/20260812000001_remove_android_devices.rb +24 -0
- data/db/migrate/20260812010000_drop_inbox_items.rb +22 -0
- data/db/migrate/20260813000000_clear_claude_channel_presence_routing_expressions.rb +16 -0
- data/db/migrate/20260813000001_add_last_topic_revision_to_user_creative_preferences.rb +5 -0
- data/db/migrate/20260813000002_add_last_topic_save_order_to_user_creative_preferences.rb +6 -0
- data/db/migrate/20260813000003_add_last_topic_save_sequences_to_user_creative_preferences.rb +5 -0
- data/db/migrate/20260813000004_add_last_topic_save_fences_to_user_creative_preferences.rb +6 -0
- data/db/migrate/20260814000000_add_topic_to_comment_read_pointers.rb +79 -0
- data/db/migrate/20260814000001_add_creative_topic_private_id_index_to_comments.rb +37 -0
- data/db/migrate/20260816000000_add_watermark_index_to_comment_read_pointers.rb +27 -0
- data/db/migrate/20260816000001_add_private_recipient_topic_index_to_comments.rb +48 -0
- data/db/migrate/20260820000000_add_topic_assigned_at_to_comments.rb +13 -0
- data/db/seeds.rb +1 -51
- data/lib/collavre/engine.rb +108 -1
- data/lib/collavre/feature_card_registry.rb +168 -0
- data/lib/collavre/hashed_access_token_lookup.rb +22 -0
- data/lib/collavre/sensitive_request_silencer.rb +23 -0
- data/lib/collavre/user_extensions.rb +0 -2
- data/lib/collavre/version.rb +1 -1
- data/lib/collavre.rb +1 -0
- data/skills/collavre/SKILL.md +165 -0
- data/skills/collavre/package.json +8 -0
- data/skills/collavre/references/tool-reference.md +347 -0
- data/skills/collavre/scripts/collavre +634 -0
- data/skills/collavre/scripts/html_entities.js +24 -0
- metadata +228 -30
- data/app/controllers/collavre/api/v1/mobile/agent_events_controller.rb +0 -224
- data/app/controllers/collavre/api/v1/mobile/base_controller.rb +0 -95
- data/app/controllers/collavre/api/v1/mobile/devices_controller.rb +0 -31
- data/app/controllers/collavre/api/v1/mobile/voice_commands_controller.rb +0 -25
- data/app/controllers/collavre/inbox_items_controller.rb +0 -70
- data/app/controllers/collavre/typo_corrections_controller.rb +0 -39
- data/app/javascript/lib/__tests__/typo_correction.test.js +0 -192
- data/app/javascript/lib/typo_correction.js +0 -146
- data/app/javascript/modules/__tests__/typo_corrector.test.js +0 -365
- data/app/javascript/modules/creative_guide.js +0 -67
- data/app/javascript/modules/typo_corrector.js +0 -534
- data/app/jobs/collavre/inbox_summary_job.rb +0 -24
- data/app/mailers/collavre/inbox_mailer.rb +0 -19
- data/app/models/collavre/inbox_item.rb +0 -89
- data/app/services/collavre/comments/concerns/workflow_support.rb +0 -115
- data/app/services/collavre/comments/work_command.rb +0 -161
- data/app/services/collavre/comments/workflow_executor.rb +0 -276
- data/app/services/collavre/gemini_parent_recommender.rb +0 -77
- data/app/services/collavre/mobile/event_summarizer.rb +0 -40
- data/app/services/collavre/typo_corrector.rb +0 -188
- data/app/views/collavre/inbox_items/_item.html.erb +0 -18
- data/app/views/collavre/inbox_items/_items.html.erb +0 -3
- data/app/views/collavre/inbox_items/_list.html.erb +0 -7
- data/app/views/collavre/inbox_items/index.html.erb +0 -1
- data/app/views/collavre/inbox_mailer/daily_summary.html.erb +0 -11
- data/app/views/collavre/inbox_mailer/daily_summary.text.erb +0 -8
- data/app/views/collavre/users/typo_correction.html.erb +0 -50
- data/config/locales/mobile.en.yml +0 -16
- data/config/locales/mobile.ko.yml +0 -16
data/lib/collavre/engine.rb
CHANGED
|
@@ -1,11 +1,41 @@
|
|
|
1
|
+
require "collavre/sensitive_request_silencer"
|
|
2
|
+
require "collavre/hashed_access_token_lookup"
|
|
3
|
+
|
|
1
4
|
module Collavre
|
|
2
5
|
class Engine < ::Rails::Engine
|
|
6
|
+
PROVISIONING_CAPABILITY_PATH = %r{
|
|
7
|
+
\A(?:/[^/]+)*/agents/\d+/workspaces/[^/]+(?:/.*)?\z
|
|
8
|
+
}x
|
|
9
|
+
|
|
3
10
|
isolate_namespace Collavre
|
|
4
11
|
|
|
5
12
|
config.generators do |g|
|
|
6
13
|
g.test_framework :minitest
|
|
7
14
|
end
|
|
8
15
|
|
|
16
|
+
# Manifest capabilities grant access to workspace callback credentials and
|
|
17
|
+
# therefore must not appear in Rails request logs. This middleware wraps the
|
|
18
|
+
# request logger as well as controller instrumentation while leaving public,
|
|
19
|
+
# content-addressed skill archive requests observable.
|
|
20
|
+
initializer "collavre.silence_provisioning_capability_paths" do |app|
|
|
21
|
+
app.middleware.insert_before(
|
|
22
|
+
Rails::Rack::Logger,
|
|
23
|
+
Collavre::SensitiveRequestSilencer,
|
|
24
|
+
path: PROVISIONING_CAPABILITY_PATH
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Workspace callback credentials retain their plaintext only in the
|
|
29
|
+
# encrypted AgentWorkspace column. Doorkeeper stores a one-way digest and
|
|
30
|
+
# resolves presented bearer values through this mixed plain/hashed lookup,
|
|
31
|
+
# preserving existing OAuth tokens without making stored digests usable.
|
|
32
|
+
initializer "collavre.hashed_workspace_callback_tokens" do
|
|
33
|
+
Rails.application.config.to_prepare do
|
|
34
|
+
token_class = Doorkeeper::AccessToken.singleton_class
|
|
35
|
+
token_class.prepend(Collavre::HashedAccessTokenLookup) unless token_class < Collavre::HashedAccessTokenLookup
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
9
39
|
# Path to engine's JavaScript sources for jsbundling-rails integration
|
|
10
40
|
def self.javascript_path
|
|
11
41
|
root.join("app/javascript")
|
|
@@ -148,6 +178,83 @@ module Collavre
|
|
|
148
178
|
ActiveSupport::Reloader.to_prepare(prepend: true) do
|
|
149
179
|
Navigation::Registry.instance.reset!
|
|
150
180
|
Collavre::ViewExtensions.reset!
|
|
181
|
+
Collavre::FeatureCardRegistry.reset!
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Register the empty-chat feature discovery cards. Vendor engines may
|
|
186
|
+
# register additional cards from their own initializers (after this one)
|
|
187
|
+
# the same way they register integrations.
|
|
188
|
+
initializer "collavre.feature_cards", after: "collavre.navigation_reset" do
|
|
189
|
+
Rails.application.config.to_prepare do
|
|
190
|
+
Collavre::FeatureCardRegistry.register(:mention_agent, {
|
|
191
|
+
icon: "🤖",
|
|
192
|
+
title_key: "collavre.comments.empty_state.cards.mention_agent.title",
|
|
193
|
+
description_key: "collavre.comments.empty_state.cards.mention_agent.description",
|
|
194
|
+
guide: true
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
Collavre::FeatureCardRegistry.register(:slash_command, {
|
|
198
|
+
icon: "⚡",
|
|
199
|
+
title_key: "collavre.comments.empty_state.cards.slash_command.title",
|
|
200
|
+
description_key: "collavre.comments.empty_state.cards.slash_command.description",
|
|
201
|
+
action: { type: :command_menu, label_key: "collavre.comments.empty_state.cards.slash_command.action" },
|
|
202
|
+
guide: true
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
Collavre::FeatureCardRegistry.register(:chat_context, {
|
|
206
|
+
icon: "🔗",
|
|
207
|
+
title_key: "collavre.comments.empty_state.cards.chat_context.title",
|
|
208
|
+
description_key: "collavre.comments.empty_state.cards.chat_context.description",
|
|
209
|
+
guide: true
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
Collavre::FeatureCardRegistry.register(:automation_trigger, {
|
|
213
|
+
icon: "⚙️",
|
|
214
|
+
title_key: "collavre.comments.empty_state.cards.automation_trigger.title",
|
|
215
|
+
description_key: "collavre.comments.empty_state.cards.automation_trigger.description",
|
|
216
|
+
guide: true
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
Collavre::FeatureCardRegistry.register(:topic_management, {
|
|
220
|
+
icon: "🗂️",
|
|
221
|
+
title_key: "collavre.comments.empty_state.cards.topic_management.title",
|
|
222
|
+
description_key: "collavre.comments.empty_state.cards.topic_management.description",
|
|
223
|
+
action: { type: :topic_list, label_key: "collavre.comments.empty_state.cards.topic_management.action" },
|
|
224
|
+
guide: true
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
Collavre::FeatureCardRegistry.register(:add_user, {
|
|
228
|
+
icon: "👥",
|
|
229
|
+
title_key: "collavre.comments.empty_state.cards.add_user.title",
|
|
230
|
+
description_key: "collavre.comments.empty_state.cards.add_user.description",
|
|
231
|
+
action: { type: :share_modal, label_key: "collavre.comments.empty_state.cards.add_user.action" },
|
|
232
|
+
guide: true
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
Collavre::FeatureCardRegistry.register(:inbox_notifications, {
|
|
236
|
+
icon: "🔔",
|
|
237
|
+
title_key: "collavre.comments.empty_state.cards.inbox_notifications.title",
|
|
238
|
+
description_key: "collavre.comments.empty_state.cards.inbox_notifications.description",
|
|
239
|
+
surfaces: [ :inbox_system ],
|
|
240
|
+
guide: true
|
|
241
|
+
})
|
|
242
|
+
|
|
243
|
+
Collavre::FeatureCardRegistry.register(:inbox_reply, {
|
|
244
|
+
icon: "↩️",
|
|
245
|
+
title_key: "collavre.comments.empty_state.cards.inbox_reply.title",
|
|
246
|
+
description_key: "collavre.comments.empty_state.cards.inbox_reply.description",
|
|
247
|
+
surfaces: [ :inbox_system ],
|
|
248
|
+
guide: true
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
Collavre::FeatureCardRegistry.register(:inbox_source, {
|
|
252
|
+
icon: "🔗",
|
|
253
|
+
title_key: "collavre.comments.empty_state.cards.inbox_source.title",
|
|
254
|
+
description_key: "collavre.comments.empty_state.cards.inbox_source.description",
|
|
255
|
+
surfaces: [ :inbox_system ],
|
|
256
|
+
guide: true
|
|
257
|
+
})
|
|
151
258
|
end
|
|
152
259
|
end
|
|
153
260
|
|
|
@@ -178,7 +285,7 @@ module Collavre
|
|
|
178
285
|
key: :home,
|
|
179
286
|
label: "app.home",
|
|
180
287
|
type: :button,
|
|
181
|
-
path: -> {
|
|
288
|
+
path: -> { home_navigation_path }, html_class: "home-nav-button",
|
|
182
289
|
priority: 110
|
|
183
290
|
)
|
|
184
291
|
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Collavre
|
|
4
|
+
# Registry for the empty-chat "feature discovery" cards shown when a
|
|
5
|
+
# Creative's comment thread has no comments yet. Mirrors the
|
|
6
|
+
# Collavre::IntegrationRegistry pattern so vendor engines can register
|
|
7
|
+
# their own cards later without touching the core empty-state view.
|
|
8
|
+
#
|
|
9
|
+
# @example Registering a card
|
|
10
|
+
# Collavre::FeatureCardRegistry.register(:add_user, {
|
|
11
|
+
# icon: "user-plus",
|
|
12
|
+
# title_key: "collavre.comments.empty_state.cards.add_user.title",
|
|
13
|
+
# description_key: "collavre.comments.empty_state.cards.add_user.description",
|
|
14
|
+
# action: { type: :share_modal },
|
|
15
|
+
# guide: true
|
|
16
|
+
# })
|
|
17
|
+
class FeatureCardRegistry
|
|
18
|
+
include Singleton
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
@cards = {}
|
|
22
|
+
@mutex = Mutex.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Register a new feature card
|
|
26
|
+
# @param key [Symbol] Unique identifier for the card
|
|
27
|
+
# @param config [Hash] Configuration options
|
|
28
|
+
# @option config [String] :icon Icon identifier (optional)
|
|
29
|
+
# @option config [String] :title_key i18n key for the card title
|
|
30
|
+
# @option config [String] :description_key i18n key for the card description
|
|
31
|
+
# @option config [Array<Symbol>] :surfaces Empty-state surfaces where the card appears
|
|
32
|
+
# (defaults to [:default])
|
|
33
|
+
# @option config [Hash] :action Optional { type:, label_key: } describing a call-to-action button
|
|
34
|
+
# @option config [Boolean] :guide Opt in to the engine-provided public guide page at
|
|
35
|
+
# collavre.feature_path(key). Only set this once the page's copy exists under
|
|
36
|
+
# collavre.features.pages.<key> — FeaturesController#show 404s for cards without it.
|
|
37
|
+
# @option config [String] :guide_url Optional URL overriding the engine guide page, for
|
|
38
|
+
# vendor engines that host their own documentation.
|
|
39
|
+
def register(key, config)
|
|
40
|
+
card = FeatureCard.new(key, config)
|
|
41
|
+
@mutex.synchronize do
|
|
42
|
+
@cards[key.to_sym] = card
|
|
43
|
+
end
|
|
44
|
+
card
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def unregister(key)
|
|
48
|
+
@mutex.synchronize do
|
|
49
|
+
@cards.delete(key.to_sym)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def find(key)
|
|
54
|
+
@mutex.synchronize do
|
|
55
|
+
@cards[key.to_sym]
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def all
|
|
60
|
+
@mutex.synchronize do
|
|
61
|
+
@cards.values
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def for(creative:, topic:)
|
|
66
|
+
surface = if creative.inbox? && topic&.name == Creative::SYSTEM_TOPIC_NAME
|
|
67
|
+
:inbox_system
|
|
68
|
+
else
|
|
69
|
+
:default
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
all.select { |card| card.visible_on?(surface) }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Cards that render on the public /features hub — only those opting into the
|
|
76
|
+
# engine-provided guide page, since a vendor card pointing at its own
|
|
77
|
+
# :guide_url has no page here to link to.
|
|
78
|
+
def with_builtin_guide
|
|
79
|
+
all.select(&:builtin_guide?)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def each(&block)
|
|
83
|
+
all.each(&block)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def any?
|
|
87
|
+
@mutex.synchronize do
|
|
88
|
+
@cards.any?
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Clear all cards (useful for testing)
|
|
93
|
+
def reset!
|
|
94
|
+
@mutex.synchronize do
|
|
95
|
+
@cards = {}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
class << self
|
|
100
|
+
delegate :register, :unregister, :find, :all, :for, :with_builtin_guide, :each, :any?, :reset!, to: :instance
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# Represents a registered feature card
|
|
105
|
+
class FeatureCard
|
|
106
|
+
# A card with a built-in guide has its key placed in a URL by
|
|
107
|
+
# collavre.feature_path, so it has to satisfy the :key constraint on the
|
|
108
|
+
# features route. config/routes.rb uses this verbatim; Rails rejects anchors
|
|
109
|
+
# in a routing requirement and anchors the segment itself, so the anchored
|
|
110
|
+
# form below is what validation compares against.
|
|
111
|
+
GUIDE_KEY_FORMAT = /[a-z0-9_]+/
|
|
112
|
+
GUIDE_KEY_FORMAT_ANCHORED = /\A#{GUIDE_KEY_FORMAT.source}\z/
|
|
113
|
+
|
|
114
|
+
attr_reader :key, :icon, :title_key, :description_key, :action, :guide_url, :surfaces
|
|
115
|
+
|
|
116
|
+
def initialize(key, config)
|
|
117
|
+
@key = key.to_sym
|
|
118
|
+
@icon = config[:icon]
|
|
119
|
+
@title_key = config[:title_key]
|
|
120
|
+
@description_key = config[:description_key]
|
|
121
|
+
@action = config[:action]
|
|
122
|
+
@guide = config.fetch(:guide, false)
|
|
123
|
+
@guide_url = config[:guide_url]
|
|
124
|
+
@surfaces = Array(config.fetch(:surfaces, :default)).map(&:to_sym).uniq.freeze
|
|
125
|
+
|
|
126
|
+
validate!
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def guide_url?
|
|
130
|
+
@guide_url.present?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# True when this card is served by the engine's own /features/:key page.
|
|
134
|
+
# A card carrying its own :guide_url is documented elsewhere, so the engine
|
|
135
|
+
# neither renders nor routes a page for it.
|
|
136
|
+
def builtin_guide?
|
|
137
|
+
@guide && !guide_url?
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# True when the empty-state card should render a "learn more" link at all.
|
|
141
|
+
def guide_link?
|
|
142
|
+
builtin_guide? || guide_url?
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def visible_on?(surface)
|
|
146
|
+
@surfaces.include?(surface.to_sym)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
private
|
|
150
|
+
|
|
151
|
+
def validate!
|
|
152
|
+
raise ArgumentError, "FeatureCard must have a :title_key" unless @title_key.present?
|
|
153
|
+
raise ArgumentError, "FeatureCard must have a :description_key" unless @description_key.present?
|
|
154
|
+
raise ArgumentError, "FeatureCard must have at least one :surface" if @surfaces.empty?
|
|
155
|
+
|
|
156
|
+
# Reject an unroutable key at registration rather than at render. A key the
|
|
157
|
+
# features route cannot accept would otherwise raise UrlGenerationError from
|
|
158
|
+
# feature_path, turning an extension's typo into a 500 on a user's empty
|
|
159
|
+
# chat and on the public hub. Fail loudly at boot, where the author sees it.
|
|
160
|
+
return unless @guide && !guide_url?
|
|
161
|
+
return if @key.to_s.match?(GUIDE_KEY_FORMAT_ANCHORED)
|
|
162
|
+
|
|
163
|
+
raise ArgumentError,
|
|
164
|
+
"FeatureCard key #{@key.inspect} cannot use the built-in guide page: " \
|
|
165
|
+
"keys must match #{GUIDE_KEY_FORMAT_ANCHORED.inspect}. Supply a :guide_url instead."
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
module Collavre
|
|
6
|
+
module HashedAccessTokenLookup
|
|
7
|
+
PREFIX = "sha256$"
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def encode(plaintext)
|
|
11
|
+
"#{PREFIX}#{Digest::SHA256.hexdigest(plaintext.to_s)}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def by_token(plaintext)
|
|
16
|
+
value = plaintext.to_s
|
|
17
|
+
return if value.start_with?(PREFIX)
|
|
18
|
+
|
|
19
|
+
super || find_by(token: HashedAccessTokenLookup.encode(value))
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/logger_silence"
|
|
4
|
+
|
|
5
|
+
module Collavre
|
|
6
|
+
# Prevents capability-bearing request paths from reaching any Rails log level.
|
|
7
|
+
# Logger::UNKNOWN + 1 is intentional: the built-in SilenceRequest defaults to
|
|
8
|
+
# ERROR, which still permits exception logs containing the original path.
|
|
9
|
+
class SensitiveRequestSilencer
|
|
10
|
+
SILENCE_LEVEL = ::Logger::UNKNOWN + 1
|
|
11
|
+
|
|
12
|
+
def initialize(app, path:)
|
|
13
|
+
@app = app
|
|
14
|
+
@path = path
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call(env)
|
|
18
|
+
return @app.call(env) unless @path === env["PATH_INFO"]
|
|
19
|
+
|
|
20
|
+
Rails.logger.silence(SILENCE_LEVEL) { @app.call(env) }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -10,8 +10,6 @@ module Collavre
|
|
|
10
10
|
has_many :collavre_shared_creative_shares, class_name: "Collavre::CreativeShare",
|
|
11
11
|
foreign_key: :shared_by_id, dependent: :nullify, inverse_of: :shared_by
|
|
12
12
|
has_many :collavre_topics, class_name: "Collavre::Topic", dependent: :destroy
|
|
13
|
-
has_many :collavre_inbox_items, class_name: "Collavre::InboxItem",
|
|
14
|
-
foreign_key: :owner_id, dependent: :destroy, inverse_of: :owner
|
|
15
13
|
has_many :collavre_invitations, class_name: "Collavre::Invitation",
|
|
16
14
|
foreign_key: :inviter_id, dependent: :destroy, inverse_of: :inviter
|
|
17
15
|
has_many :collavre_contacts, class_name: "Collavre::Contact", dependent: :destroy
|
data/lib/collavre/version.rb
CHANGED
data/lib/collavre.rb
CHANGED
|
@@ -3,6 +3,7 @@ require "collavre/configuration"
|
|
|
3
3
|
require "collavre/engine"
|
|
4
4
|
require "collavre/user_extensions"
|
|
5
5
|
require "collavre/integration_registry"
|
|
6
|
+
require "collavre/feature_card_registry"
|
|
6
7
|
require "collavre/integration_settings"
|
|
7
8
|
require "collavre/aws_credentials"
|
|
8
9
|
require "collavre/ses_settings_interceptor"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: collavre
|
|
3
|
+
description: Manage Collavre Creatives (hierarchical tasks/content blocks) via CLI. Use when creating, retrieving, updating, importing, or batch-operating on Creatives. Creatives are tree-structured items with automatic progress rollup — like a smart to-do list that doubles as a structured document.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Collavre
|
|
7
|
+
|
|
8
|
+
CLI for managing Collavre Creatives via MCP protocol.
|
|
9
|
+
|
|
10
|
+
## Setup
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# Configure (once)
|
|
14
|
+
collavre auth --url https://collavre.example.com --token <oauth_token>
|
|
15
|
+
|
|
16
|
+
# Verify
|
|
17
|
+
collavre list
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The `collavre` script lives in `scripts/collavre`. Config is stored at `~/.config/collavre/config.json`.
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
### List root creatives
|
|
25
|
+
```bash
|
|
26
|
+
collavre list
|
|
27
|
+
collavre list --level 5 # deeper tree
|
|
28
|
+
collavre list --format json # structured output
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Get a creative subtree
|
|
32
|
+
```bash
|
|
33
|
+
collavre get 123
|
|
34
|
+
collavre get 123 --level 5 --comments
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Search
|
|
38
|
+
```bash
|
|
39
|
+
collavre search "project name"
|
|
40
|
+
collavre search "urgent" --tags "v2"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Create
|
|
44
|
+
```bash
|
|
45
|
+
collavre create --parent 123 --desc "New task"
|
|
46
|
+
collavre create --parent 123 --desc "# Rich content\n\n- point one\n- point two"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Update
|
|
50
|
+
```bash
|
|
51
|
+
collavre update 456 --desc "Updated title"
|
|
52
|
+
collavre update 456 --progress 1.0 # mark complete (leaf only)
|
|
53
|
+
collavre update 456 --parent 789 # move
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Import markdown
|
|
57
|
+
```bash
|
|
58
|
+
collavre import --parent 123 --file plan.md
|
|
59
|
+
collavre import --parent 123 --stdin < plan.md
|
|
60
|
+
echo "# Quick\n## Plan" | collavre import --parent 123 --stdin
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Attach a file
|
|
64
|
+
```bash
|
|
65
|
+
collavre attach --creative 123 --file ./hero.png # png/mp4/pdf/svg
|
|
66
|
+
```
|
|
67
|
+
Uploads the raw bytes over a bearer multipart endpoint, embeds the matching
|
|
68
|
+
node (`<img>`/`<video>`/`<a>`) into the creative's description, and attaches the
|
|
69
|
+
blob to `creative.files`. Use this for binary files on disk. For inline
|
|
70
|
+
agent-generated text (markdown/html/svg source), use the
|
|
71
|
+
`creative_attach_files_service` tool with `files: [{ filename, content }]`.
|
|
72
|
+
|
|
73
|
+
### Batch operations
|
|
74
|
+
```bash
|
|
75
|
+
collavre batch --file ops.json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
ops.json format:
|
|
79
|
+
```json
|
|
80
|
+
[
|
|
81
|
+
{ "action": "create", "parent_id": 100, "description": "Task A" },
|
|
82
|
+
{ "action": "update", "id": 200, "progress": 1.0 },
|
|
83
|
+
{ "action": "delete", "id": 300 }
|
|
84
|
+
]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Topics and messages
|
|
88
|
+
|
|
89
|
+
Topics are conversation threads on a Creative — and the unit of agent
|
|
90
|
+
concurrency. Tasks in the same topic are serialized (one runs, the rest queue);
|
|
91
|
+
tasks in different topics run in parallel. There is no dedicated CLI verb yet;
|
|
92
|
+
drive them through `collavre tool run`:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# See what topics exist and how much conversation each holds
|
|
96
|
+
collavre tool run topic_list --json '{"creative_id": 8849}'
|
|
97
|
+
|
|
98
|
+
# Summarize three topics at once — first page only; offset/limit apply per topic
|
|
99
|
+
collavre tool run topic_messages --json '{"topic_ids": "12,45,78", "limit": 100}'
|
|
100
|
+
|
|
101
|
+
# Continue each topic separately with its own cursor and snapshot id
|
|
102
|
+
collavre tool run topic_messages --json '{"topic_ids": 12, "offset": 100, "cursor": "1770000000000000:989:1770000001000000:1770000002000000", "max_message_id": 9931}'
|
|
103
|
+
|
|
104
|
+
# Continue inside one clipped message, preserving its row cursor
|
|
105
|
+
collavre tool run topic_messages --json '{"topic_ids": 12, "offset": 100, "cursor": "1770000000000000:989:1770000001000000:1770000002000000", "content_offset": 28400, "max_message_id": 9931}'
|
|
106
|
+
|
|
107
|
+
# Fan work out: one topic per unit of work, with an agent pinned to each;
|
|
108
|
+
# keep each returned topic id for the initial-message calls
|
|
109
|
+
collavre tool run topic_create --json '{"creative_id": 8849, "name": "Research", "primary_agent": "Dev1Claude"}'
|
|
110
|
+
collavre tool run topic_create --json '{"creative_id": 8849, "name": "Delivery", "primary_agent": "Dev1Claude"}'
|
|
111
|
+
|
|
112
|
+
# Start the pinned agent independently in both topics
|
|
113
|
+
collavre tool run topic_message_create --json '{"topic_id": 12, "content": "Research the API options and report your recommendation."}'
|
|
114
|
+
collavre tool run topic_message_create --json '{"topic_id": 13, "content": "Build the selected approach and verify it."}'
|
|
115
|
+
|
|
116
|
+
# Put a finished thread away (messages are kept and stay readable by id)
|
|
117
|
+
collavre tool run topic_update --json '{"topic_id": 12, "archived": true}'
|
|
118
|
+
|
|
119
|
+
# Move a complete thread, including its messages and read cursors
|
|
120
|
+
collavre tool run topic_move --json '{"topic_id": 13, "creative_id": 9023}'
|
|
121
|
+
|
|
122
|
+
# Carry the messages that still matter into a fresh topic
|
|
123
|
+
collavre tool run topic_branch --json '{"source_topic_id": 12, "comment_ids": "991,994"}'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`topic_messages` includes each comment image as a URL-bearing marker in the
|
|
127
|
+
message content. Image-only comments are not blank, and a long attachment list
|
|
128
|
+
uses the same `content_offset` continuation as long prose.
|
|
129
|
+
|
|
130
|
+
### Discover & run tools (meta)
|
|
131
|
+
```bash
|
|
132
|
+
collavre tool list # list available tools
|
|
133
|
+
collavre tool list --full # list with full details
|
|
134
|
+
collavre tool search "github" # search by name/description
|
|
135
|
+
collavre tool info <tool_name> # show tool parameters
|
|
136
|
+
collavre tool run <tool_name> --json '{"k":"v"}' # run with JSON args
|
|
137
|
+
collavre tool run <tool_name> --key value # run with flag args
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Key Concepts
|
|
141
|
+
|
|
142
|
+
- **Tree structure**: Creatives nest via `parent_id`. Use `--level` to control depth.
|
|
143
|
+
- **Topics**: conversation threads on a Creative, and the concurrency unit — same
|
|
144
|
+
topic serializes, different topics run in parallel. One topic = one thread
|
|
145
|
+
reaching one conclusion; archive it when it gets there rather than reusing it.
|
|
146
|
+
- **Primary agent**: pinning an agent to a topic is exclusive — that agent alone
|
|
147
|
+
answers there. Use it for a dedicated 1:1 channel; leave it unset for a thread
|
|
148
|
+
several participants should hear.
|
|
149
|
+
- **Starting topic work**: after creating and pinning a topic, call
|
|
150
|
+
`topic_message_create` with its initial instruction. Agent-authored messages
|
|
151
|
+
dispatch as A2A work, so one coordinating agent can start independent work in
|
|
152
|
+
several topics without impersonating a human. Do not call it on the topic the
|
|
153
|
+
caller is currently handling; continue that work in the current turn instead.
|
|
154
|
+
- **Moving topics**: `topic_move` keeps the thread and its messages together,
|
|
155
|
+
but Creative permissions stay with each Creative. Verify that participants
|
|
156
|
+
can access the destination after moving. Wait for or cancel active agent work
|
|
157
|
+
in the topic before moving it, and wait for dropped-message restoration to
|
|
158
|
+
settle. Cancel recurring cron jobs that target the topic and recreate them
|
|
159
|
+
after the move. Topics referenced by a Drop Trigger loop cannot move.
|
|
160
|
+
- **Progress**: Leaf = manual (0.0 or 1.0). Parent = auto-calculated from children.
|
|
161
|
+
- **Import**: Markdown headings/bullets become nested Creatives.
|
|
162
|
+
- **Batch**: All-or-nothing transaction. Requires approval.
|
|
163
|
+
- **Description format**: Written as Markdown (GitHub-Flavored: headings, bold/italic, lists, links, tables, code blocks, task lists). A single newline is a line break. Plain text is stored as-is.
|
|
164
|
+
|
|
165
|
+
For detailed MCP tool parameters, see [references/tool-reference.md](references/tool-reference.md).
|