collavre 0.2.5 → 0.3.1
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/app/channels/collavre/comments_presence_channel.rb +6 -3
- data/app/controllers/collavre/admin/orchestration_controller.rb +177 -0
- data/app/controllers/collavre/comments_controller.rb +10 -1
- data/app/javascript/controllers/comments/presence_controller.js +5 -1
- data/app/jobs/collavre/ai_agent_job.rb +55 -4
- data/app/jobs/collavre/cron_action_job.rb +53 -0
- data/app/jobs/collavre/stuck_detector_job.rb +34 -0
- data/app/models/collavre/comment.rb +15 -15
- data/app/models/collavre/creative.rb +1 -1
- data/app/models/collavre/orchestrator_policy.rb +124 -0
- data/app/models/collavre/task.rb +3 -0
- data/app/models/collavre/user.rb +1 -1
- data/app/services/collavre/ai_agent_service.rb +32 -1
- data/app/services/collavre/ai_client.rb +4 -3
- data/app/services/collavre/comments/command_processor.rb +4 -1
- data/app/services/collavre/comments/topic_command.rb +101 -0
- data/app/services/collavre/orchestration/agent_context_builder.rb +201 -0
- data/app/services/collavre/orchestration/agent_orchestrator.rb +142 -0
- data/app/services/collavre/orchestration/arbiter.rb +257 -0
- data/app/services/collavre/orchestration/loop_breaker.rb +294 -0
- data/app/services/collavre/orchestration/matcher.rb +98 -0
- data/app/services/collavre/orchestration/policy_resolver.rb +170 -0
- data/app/services/collavre/orchestration/resource_tracker.rb +135 -0
- data/app/services/collavre/orchestration/scheduler.rb +145 -0
- data/app/services/collavre/orchestration/self_reflection_evaluator.rb +231 -0
- data/app/services/collavre/orchestration/stuck_detector.rb +303 -0
- data/app/services/collavre/system_events/context_builder.rb +34 -7
- data/app/services/collavre/system_events/dispatcher.rb +2 -7
- data/app/services/collavre/tools/cron_cancel_service.rb +49 -0
- data/app/services/collavre/tools/cron_create_service.rb +73 -0
- data/app/services/collavre/tools/cron_list_service.rb +65 -0
- data/app/services/collavre/tools/cron_update_service.rb +82 -0
- data/app/views/admin/shared/_tabs.html.erb +1 -0
- data/app/views/collavre/admin/orchestration/show.html.erb +66 -0
- data/app/views/collavre/creatives/index.html.erb +1 -1
- data/config/locales/ai_agent.en.yml +21 -0
- data/config/locales/ai_agent.ko.yml +21 -0
- data/config/locales/comments.en.yml +8 -0
- data/config/locales/comments.ko.yml +8 -0
- data/config/routes.rb +5 -1
- data/db/migrate/20260206005035_create_orchestrator_policies.rb +32 -0
- data/db/migrate/20260206094509_add_retry_count_to_tasks.rb +5 -0
- data/db/migrate/20260206100000_add_topic_id_to_tasks.rb +6 -0
- data/lib/collavre/version.rb +1 -1
- metadata +24 -13
- data/app/controllers/collavre/github_auth_controller.rb +0 -25
- data/app/models/collavre/github_account.rb +0 -10
- data/app/models/collavre/github_repository_link.rb +0 -19
- data/app/services/collavre/github/client.rb +0 -112
- data/app/services/collavre/github/pull_request_analyzer.rb +0 -280
- data/app/services/collavre/github/pull_request_processor.rb +0 -181
- data/app/services/collavre/github/webhook_provisioner.rb +0 -130
- data/app/services/collavre/system_events/router.rb +0 -96
- data/app/views/collavre/creatives/_github_integration_modal.html.erb +0 -77
- data/db/migrate/20250925000000_create_github_integrations.rb +0 -26
- data/db/migrate/20250927000000_add_webhook_secret_to_github_repository_links.rb +0 -29
- data/db/migrate/20250928105957_add_github_gemini_prompt_to_creatives.rb +0 -5
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<h1 class="no-top-margin"><%= t('admin.title') %></h1>
|
|
2
|
+
|
|
3
|
+
<%= render "admin/shared/tabs" %>
|
|
4
|
+
|
|
5
|
+
<div class="tab-panels">
|
|
6
|
+
<section class="tab-panel active">
|
|
7
|
+
<%= tag.div(flash[:alert], class: "flash-alert") if flash[:alert] %>
|
|
8
|
+
<%= tag.div(flash[:notice], class: "flash-notice") if flash[:notice] %>
|
|
9
|
+
|
|
10
|
+
<div style="margin-bottom: 1.5em;">
|
|
11
|
+
<h2 style="font-size: 1.2em; margin-bottom: 0.5em;"><%= t('admin.orchestration.title') %></h2>
|
|
12
|
+
<p style="color: var(--color-text-muted); font-size: 0.9em;">
|
|
13
|
+
<%= t('admin.orchestration.description') %>
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
|
|
17
|
+
<%= form_with url: admin_orchestration_path, method: :patch, local: true, html: { class: 'profile-form' } do |f| %>
|
|
18
|
+
<div>
|
|
19
|
+
<label for="policies_yaml" style="font-weight: 600; display: block; margin-bottom: 0.5em;">
|
|
20
|
+
<%= t('admin.orchestration.policies_yaml') %>
|
|
21
|
+
</label>
|
|
22
|
+
<%= f.text_area :policies_yaml,
|
|
23
|
+
value: @policies_yaml,
|
|
24
|
+
rows: 30,
|
|
25
|
+
style: "width: 100%; font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace; font-size: 0.9em; padding: 1em; border: 1px solid var(--color-border); border-radius: 4px; background: var(--color-surface); line-height: 1.5;" %>
|
|
26
|
+
<div class="help-text" style="font-size: 0.85em; color: var(--color-text-muted); margin-top: 0.5em;">
|
|
27
|
+
<%= t('admin.orchestration.yaml_hint') %>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div style="margin-top: 1.5em; padding-top: 1.5em; border-top: 1px solid var(--color-border);">
|
|
32
|
+
<h3 style="font-size: 1em; margin-bottom: 0.75em;"><%= t('admin.orchestration.reference') %></h3>
|
|
33
|
+
|
|
34
|
+
<div style="background: var(--color-surface-alt); padding: 1em; border-radius: 4px; font-size: 0.85em;">
|
|
35
|
+
<p style="margin-bottom: 0.75em;"><strong><%= t('admin.orchestration.arbitration_strategies') %></strong></p>
|
|
36
|
+
<ul style="margin-left: 1.5em; margin-bottom: 1em;">
|
|
37
|
+
<li><code>all</code> — <%= t('admin.orchestration.strategy_all') %></li>
|
|
38
|
+
<li><code>primary_first</code> — <%= t('admin.orchestration.strategy_primary_first') %></li>
|
|
39
|
+
<li><code>round_robin</code> — <%= t('admin.orchestration.strategy_round_robin') %></li>
|
|
40
|
+
<li><code>bid</code> — <%= t('admin.orchestration.strategy_bid') %></li>
|
|
41
|
+
</ul>
|
|
42
|
+
|
|
43
|
+
<p style="margin-bottom: 0.75em;"><strong><%= t('admin.orchestration.scheduling_options') %></strong></p>
|
|
44
|
+
<ul style="margin-left: 1.5em; margin-bottom: 1em;">
|
|
45
|
+
<li><code>max_concurrent_jobs</code> — <%= t('admin.orchestration.opt_max_concurrent') %></li>
|
|
46
|
+
<li><code>daily_token_limit</code> — <%= t('admin.orchestration.opt_daily_token') %></li>
|
|
47
|
+
<li><code>rate_limit_per_minute</code> — <%= t('admin.orchestration.opt_rate_limit') %></li>
|
|
48
|
+
<li><code>backoff_strategy</code> — <%= t('admin.orchestration.opt_backoff') %></li>
|
|
49
|
+
<li><code>topic_max_concurrent_jobs</code> — <%= t('admin.orchestration.opt_topic_max_concurrent') %></li>
|
|
50
|
+
</ul>
|
|
51
|
+
|
|
52
|
+
<p style="margin-bottom: 0.75em;"><strong><%= t('admin.orchestration.scope_types') %></strong></p>
|
|
53
|
+
<ul style="margin-left: 1.5em;">
|
|
54
|
+
<li><code>Creative</code> — <%= t('admin.orchestration.scope_creative') %></li>
|
|
55
|
+
<li><code>Topic</code> — <%= t('admin.orchestration.scope_topic') %></li>
|
|
56
|
+
<li><code>User</code> — <%= t('admin.orchestration.scope_user') %></li>
|
|
57
|
+
</ul>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div style="margin-top: 2em;">
|
|
62
|
+
<%= f.submit t('admin.orchestration.save'), class: 'btn-primary' %>
|
|
63
|
+
</div>
|
|
64
|
+
<% end %>
|
|
65
|
+
</section>
|
|
66
|
+
</div>
|
|
@@ -203,7 +203,7 @@
|
|
|
203
203
|
<%= render 'set_plan_modal' %>
|
|
204
204
|
<% if can_manage_integrations %>
|
|
205
205
|
<%# Legacy hardcoded integration modals %>
|
|
206
|
-
<%= render '
|
|
206
|
+
<%= render 'collavre_github/integrations/modal', creative: current_creative %>
|
|
207
207
|
<%# Dynamically registered integration modals %>
|
|
208
208
|
<%= render 'integration_modals', creative: current_creative %>
|
|
209
209
|
<% end %>
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
en:
|
|
2
2
|
collavre:
|
|
3
|
+
stuck_detection:
|
|
4
|
+
task_stuck: "⚠️ Task '%{task_name}' assigned to %{agent_name} has been stuck for %{minutes} minutes."
|
|
5
|
+
creative_stalled: "⚠️ Creative '%{creative_title}' has stalled at %{progress}%% for %{hours} hours."
|
|
6
|
+
system_comment: "[System] Task '%{task_name}' by %{agent_name} appears stuck. Admin attention required."
|
|
3
7
|
ai_agent:
|
|
4
8
|
approval:
|
|
5
9
|
message: |
|
|
@@ -13,3 +17,20 @@ en:
|
|
|
13
17
|
|
|
14
18
|
Please approve or reject this action.
|
|
15
19
|
no_arguments: "(no arguments)"
|
|
20
|
+
a2a:
|
|
21
|
+
request_header: "## ⚡ Agent Request"
|
|
22
|
+
request_description: "This message is a request from another AI Agent (@%{sender_name}, %{sender_type})."
|
|
23
|
+
focus_instruction: "- Focus on answering the request"
|
|
24
|
+
completion_instruction: "- Clearly communicate results when done"
|
|
25
|
+
followup_instruction: "- If you need more information, ask the requester via @mention"
|
|
26
|
+
collaboration:
|
|
27
|
+
header: "## Available Agents for Collaboration"
|
|
28
|
+
escalation_header: "### Escalation Targets (when stuck)"
|
|
29
|
+
collaborator_header: "### Collaborators (work together)"
|
|
30
|
+
reviewer_header: "### Reviewers (request review)"
|
|
31
|
+
reference_header: "### References (information only)"
|
|
32
|
+
rules_header: "## Collaboration Rules"
|
|
33
|
+
mention_rule: "- Call other agents: @name: request"
|
|
34
|
+
confidence_rule: "- Re-evaluate before responding if uncertain"
|
|
35
|
+
escalation_rule: "- Ask escalation targets for help when stuck"
|
|
36
|
+
review_rule: "- Request review from reviewers when code review is needed"
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
ko:
|
|
2
2
|
collavre:
|
|
3
|
+
stuck_detection:
|
|
4
|
+
task_stuck: "⚠️ '%{task_name}' 작업이 %{agent_name}에게 할당된 후 %{minutes}분 동안 진행되지 않고 있습니다."
|
|
5
|
+
creative_stalled: "⚠️ '%{creative_title}' Creative가 %{progress}%%에서 %{hours}시간 동안 정체되어 있습니다."
|
|
6
|
+
system_comment: "[시스템] %{agent_name}의 '%{task_name}' 작업이 막힌 것 같습니다. 관리자 확인이 필요합니다."
|
|
3
7
|
ai_agent:
|
|
4
8
|
approval:
|
|
5
9
|
message: |
|
|
@@ -13,3 +17,20 @@ ko:
|
|
|
13
17
|
|
|
14
18
|
승인 또는 거부해 주세요.
|
|
15
19
|
no_arguments: "(인자 없음)"
|
|
20
|
+
a2a:
|
|
21
|
+
request_header: "## ⚡ Agent 요청"
|
|
22
|
+
request_description: "이 메시지는 다른 AI Agent(@%{sender_name}, %{sender_type})가 보낸 요청입니다."
|
|
23
|
+
focus_instruction: "- 요청에 집중해서 답변하세요"
|
|
24
|
+
completion_instruction: "- 완료되면 결과를 명확히 전달하세요"
|
|
25
|
+
followup_instruction: "- 추가 정보가 필요하면 요청자에게 @멘션으로 물어보세요"
|
|
26
|
+
collaboration:
|
|
27
|
+
header: "## 협업 가능한 Agent"
|
|
28
|
+
escalation_header: "### 에스컬레이션 대상 (문제 해결 불가 시)"
|
|
29
|
+
collaborator_header: "### 협업 가능 (함께 작업)"
|
|
30
|
+
reviewer_header: "### 리뷰어 (검토 요청)"
|
|
31
|
+
reference_header: "### 참조 (정보 요청만)"
|
|
32
|
+
rules_header: "## 협업 규칙"
|
|
33
|
+
mention_rule: "- 다른 Agent 호출: @이름: 요청내용"
|
|
34
|
+
confidence_rule: "- 확신이 낮으면 재검토 후 발화"
|
|
35
|
+
escalation_rule: "- 막히면 에스컬레이션 대상에게 도움 요청"
|
|
36
|
+
review_rule: "- 코드 리뷰가 필요하면 리뷰어에게 요청"
|
|
@@ -81,10 +81,18 @@ en:
|
|
|
81
81
|
command_menu:
|
|
82
82
|
calendar_description: "Create a Google Calendar event."
|
|
83
83
|
calendar_args: "YYYY-MM-DD@HH:MM memo (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon)"
|
|
84
|
+
topic_description: "Create a new topic with optional primary agent."
|
|
85
|
+
topic_args: '"topic name" @agent_name'
|
|
84
86
|
calendar_command:
|
|
85
87
|
event_created: 'event created: [Google Calendar event](%{url})'
|
|
86
88
|
event_created_local: 'event created (local only - connect Google Calendar to sync)'
|
|
87
89
|
event_created_sync_failed: 'event created (Google Calendar sync failed - please reconnect your Google account)'
|
|
90
|
+
topic_command:
|
|
91
|
+
missing_name: 'Please specify a topic name in quotes: /topic "topic name"'
|
|
92
|
+
created: 'Topic "%{name}" created.'
|
|
93
|
+
created_with_agent: 'Topic "%{name}" created with @%{agent} as primary agent.'
|
|
94
|
+
updated_agent: 'Topic "%{name}" primary agent updated to @%{agent}.'
|
|
95
|
+
already_exists: 'Topic "%{name}" already exists.'
|
|
88
96
|
read_by: Read by %{name}
|
|
89
97
|
activity_logs_summary: Activity Logs
|
|
90
98
|
calendar_events:
|
|
@@ -78,10 +78,18 @@ ko:
|
|
|
78
78
|
command_menu:
|
|
79
79
|
calendar_description: 구글 캘린더 이벤트를 생성합니다.
|
|
80
80
|
calendar_args: "YYYY-MM-DD@HH:MM 메모 (today/tomorrow, +3days, +2weeks, +1months, +1years, +mon/+월)"
|
|
81
|
+
topic_description: "새 토픽을 생성합니다. Primary Agent를 지정할 수 있습니다."
|
|
82
|
+
topic_args: '"토픽 이름" @에이전트이름'
|
|
81
83
|
calendar_command:
|
|
82
84
|
event_created: '이벤트가 생성되었습니다: [구글 캘린더 이벤트](%{url})'
|
|
83
85
|
event_created_local: '이벤트가 생성되었습니다 (로컬 전용 - 구글 캘린더 연동 시 동기화됩니다)'
|
|
84
86
|
event_created_sync_failed: '이벤트가 생성되었습니다 (구글 캘린더 동기화 실패 - 구글 계정을 다시 연동해주세요)'
|
|
87
|
+
topic_command:
|
|
88
|
+
missing_name: '토픽 이름을 따옴표로 지정하세요: /topic "토픽 이름"'
|
|
89
|
+
created: '토픽 "%{name}"이(가) 생성되었습니다.'
|
|
90
|
+
created_with_agent: '토픽 "%{name}"이(가) 생성되었습니다. @%{agent}이(가) Primary Agent로 설정되었습니다.'
|
|
91
|
+
updated_agent: '토픽 "%{name}"의 Primary Agent가 @%{agent}(으)로 변경되었습니다.'
|
|
92
|
+
already_exists: '토픽 "%{name}"이(가) 이미 존재합니다.'
|
|
85
93
|
read_by: "%{name} 님이 읽음"
|
|
86
94
|
activity_logs_summary: 활동 기록
|
|
87
95
|
calendar_events:
|
data/config/routes.rb
CHANGED
|
@@ -24,7 +24,6 @@ Collavre::Engine.routes.draw do
|
|
|
24
24
|
|
|
25
25
|
# OAuth callback routes (paths match OmniAuth provider names)
|
|
26
26
|
match "/auth/google_oauth2/callback", to: "google_auth#callback", via: [ :get, :post ]
|
|
27
|
-
match "/auth/github/callback", to: "github_auth#callback", via: [ :get, :post ]
|
|
28
27
|
|
|
29
28
|
delete "/attachments/:signed_id", to: "attachments#destroy", as: :attachment
|
|
30
29
|
|
|
@@ -94,4 +93,9 @@ Collavre::Engine.routes.draw do
|
|
|
94
93
|
|
|
95
94
|
post "/creative_expanded_states/toggle", to: "creative_expanded_states#toggle"
|
|
96
95
|
post "/comment_read_pointers/update", to: "comment_read_pointers#update"
|
|
96
|
+
|
|
97
|
+
# Admin orchestration
|
|
98
|
+
scope "/admin", as: :admin do
|
|
99
|
+
resource :orchestration, only: [ :show, :update ], controller: "admin/orchestration"
|
|
100
|
+
end
|
|
97
101
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateOrchestratorPolicies < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :orchestrator_policies do |t|
|
|
6
|
+
# Scope determines where this policy applies
|
|
7
|
+
# - global: applies everywhere (scope_type/scope_id null)
|
|
8
|
+
# - creative: applies to a specific creative
|
|
9
|
+
# - topic: applies to a specific topic
|
|
10
|
+
# - agent: applies to a specific agent
|
|
11
|
+
t.string :scope_type, null: true
|
|
12
|
+
t.bigint :scope_id, null: true
|
|
13
|
+
|
|
14
|
+
# Policy type: matching, arbitration, scheduling
|
|
15
|
+
t.string :policy_type, null: false
|
|
16
|
+
|
|
17
|
+
# Configuration stored as JSON
|
|
18
|
+
t.json :config, null: false, default: {}
|
|
19
|
+
|
|
20
|
+
# Priority: lower number = higher priority (evaluated first)
|
|
21
|
+
t.integer :priority, null: false, default: 100
|
|
22
|
+
|
|
23
|
+
t.boolean :enabled, null: false, default: true
|
|
24
|
+
|
|
25
|
+
t.timestamps
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
add_index :orchestrator_policies, [ :scope_type, :scope_id ]
|
|
29
|
+
add_index :orchestrator_policies, [ :policy_type, :enabled ]
|
|
30
|
+
add_index :orchestrator_policies, :priority
|
|
31
|
+
end
|
|
32
|
+
end
|
data/lib/collavre/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: collavre
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Collavre
|
|
@@ -186,6 +186,7 @@ files:
|
|
|
186
186
|
- app/components/collavre/progress_filter_component.html.erb
|
|
187
187
|
- app/components/collavre/progress_filter_component.rb
|
|
188
188
|
- app/components/collavre/user_mention_menu_component.rb
|
|
189
|
+
- app/controllers/collavre/admin/orchestration_controller.rb
|
|
189
190
|
- app/controllers/collavre/application_controller.rb
|
|
190
191
|
- app/controllers/collavre/attachments_controller.rb
|
|
191
192
|
- app/controllers/collavre/calendar_events_controller.rb
|
|
@@ -202,7 +203,6 @@ files:
|
|
|
202
203
|
- app/controllers/collavre/devices_controller.rb
|
|
203
204
|
- app/controllers/collavre/email_verifications_controller.rb
|
|
204
205
|
- app/controllers/collavre/emails_controller.rb
|
|
205
|
-
- app/controllers/collavre/github_auth_controller.rb
|
|
206
206
|
- app/controllers/collavre/google_auth_controller.rb
|
|
207
207
|
- app/controllers/collavre/inbox_items_controller.rb
|
|
208
208
|
- app/controllers/collavre/invites_controller.rb
|
|
@@ -295,10 +295,12 @@ files:
|
|
|
295
295
|
- app/javascript/utils/caret_position.js
|
|
296
296
|
- app/javascript/utils/clipboard.js
|
|
297
297
|
- app/jobs/collavre/ai_agent_job.rb
|
|
298
|
+
- app/jobs/collavre/cron_action_job.rb
|
|
298
299
|
- app/jobs/collavre/inbox_summary_job.rb
|
|
299
300
|
- app/jobs/collavre/permission_cache_cleanup_job.rb
|
|
300
301
|
- app/jobs/collavre/permission_cache_job.rb
|
|
301
302
|
- app/jobs/collavre/push_notification_job.rb
|
|
303
|
+
- app/jobs/collavre/stuck_detector_job.rb
|
|
302
304
|
- app/mailers/collavre/application_mailer.rb
|
|
303
305
|
- app/mailers/collavre/creative_mailer.rb
|
|
304
306
|
- app/mailers/collavre/email_verification_mailer.rb
|
|
@@ -320,12 +322,11 @@ files:
|
|
|
320
322
|
- app/models/collavre/current.rb
|
|
321
323
|
- app/models/collavre/device.rb
|
|
322
324
|
- app/models/collavre/email.rb
|
|
323
|
-
- app/models/collavre/github_account.rb
|
|
324
|
-
- app/models/collavre/github_repository_link.rb
|
|
325
325
|
- app/models/collavre/inbox_item.rb
|
|
326
326
|
- app/models/collavre/invitation.rb
|
|
327
327
|
- app/models/collavre/label.rb
|
|
328
328
|
- app/models/collavre/mcp_tool.rb
|
|
329
|
+
- app/models/collavre/orchestrator_policy.rb
|
|
329
330
|
- app/models/collavre/plan.rb
|
|
330
331
|
- app/models/collavre/session.rb
|
|
331
332
|
- app/models/collavre/system_setting.rb
|
|
@@ -348,6 +349,7 @@ files:
|
|
|
348
349
|
- app/services/collavre/comments/command_processor.rb
|
|
349
350
|
- app/services/collavre/comments/mcp_command.rb
|
|
350
351
|
- app/services/collavre/comments/mcp_command_builder.rb
|
|
352
|
+
- app/services/collavre/comments/topic_command.rb
|
|
351
353
|
- app/services/collavre/creatives/filter_pipeline.rb
|
|
352
354
|
- app/services/collavre/creatives/filters/assignee_filter.rb
|
|
353
355
|
- app/services/collavre/creatives/filters/base_filter.rb
|
|
@@ -367,23 +369,33 @@ files:
|
|
|
367
369
|
- app/services/collavre/creatives/tree_builder.rb
|
|
368
370
|
- app/services/collavre/creatives/tree_formatter.rb
|
|
369
371
|
- app/services/collavre/gemini_parent_recommender.rb
|
|
370
|
-
- app/services/collavre/github/client.rb
|
|
371
|
-
- app/services/collavre/github/pull_request_analyzer.rb
|
|
372
|
-
- app/services/collavre/github/pull_request_processor.rb
|
|
373
|
-
- app/services/collavre/github/webhook_provisioner.rb
|
|
374
372
|
- app/services/collavre/google_calendar_service.rb
|
|
375
373
|
- app/services/collavre/link_preview_fetcher.rb
|
|
376
374
|
- app/services/collavre/markdown_importer.rb
|
|
377
375
|
- app/services/collavre/mcp_service.rb
|
|
376
|
+
- app/services/collavre/orchestration/agent_context_builder.rb
|
|
377
|
+
- app/services/collavre/orchestration/agent_orchestrator.rb
|
|
378
|
+
- app/services/collavre/orchestration/arbiter.rb
|
|
379
|
+
- app/services/collavre/orchestration/loop_breaker.rb
|
|
380
|
+
- app/services/collavre/orchestration/matcher.rb
|
|
381
|
+
- app/services/collavre/orchestration/policy_resolver.rb
|
|
382
|
+
- app/services/collavre/orchestration/resource_tracker.rb
|
|
383
|
+
- app/services/collavre/orchestration/scheduler.rb
|
|
384
|
+
- app/services/collavre/orchestration/self_reflection_evaluator.rb
|
|
385
|
+
- app/services/collavre/orchestration/stuck_detector.rb
|
|
378
386
|
- app/services/collavre/ppt_importer.rb
|
|
379
387
|
- app/services/collavre/ruby_llm_interaction_logger.rb
|
|
380
388
|
- app/services/collavre/system_events/context_builder.rb
|
|
381
389
|
- app/services/collavre/system_events/dispatcher.rb
|
|
382
|
-
- app/services/collavre/system_events/router.rb
|
|
383
390
|
- app/services/collavre/tools/creative_create_service.rb
|
|
384
391
|
- app/services/collavre/tools/creative_retrieval_service.rb
|
|
385
392
|
- app/services/collavre/tools/creative_update_service.rb
|
|
393
|
+
- app/services/collavre/tools/cron_cancel_service.rb
|
|
394
|
+
- app/services/collavre/tools/cron_create_service.rb
|
|
395
|
+
- app/services/collavre/tools/cron_list_service.rb
|
|
396
|
+
- app/services/collavre/tools/cron_update_service.rb
|
|
386
397
|
- app/views/admin/shared/_tabs.html.erb
|
|
398
|
+
- app/views/collavre/admin/orchestration/show.html.erb
|
|
387
399
|
- app/views/collavre/comments/_activity_log_details.html.erb
|
|
388
400
|
- app/views/collavre/comments/_comment.html.erb
|
|
389
401
|
- app/views/collavre/comments/_comments_popup.html.erb
|
|
@@ -393,7 +405,6 @@ files:
|
|
|
393
405
|
- app/views/collavre/comments/_read_receipts.html.erb
|
|
394
406
|
- app/views/collavre/creatives/_add_button.html.erb
|
|
395
407
|
- app/views/collavre/creatives/_delete_button.html.erb
|
|
396
|
-
- app/views/collavre/creatives/_github_integration_modal.html.erb
|
|
397
408
|
- app/views/collavre/creatives/_import_upload_zone.html.erb
|
|
398
409
|
- app/views/collavre/creatives/_inline_edit_form.html.erb
|
|
399
410
|
- app/views/collavre/creatives/_integration_modals.html.erb
|
|
@@ -516,11 +527,8 @@ files:
|
|
|
516
527
|
- db/migrate/20250911084338_backfill_creative_in_comment_inbox_items.rb
|
|
517
528
|
- db/migrate/20250923002959_deduplicate_device_fcm_tokens.rb
|
|
518
529
|
- db/migrate/20250924000000_add_system_admin_to_users.rb
|
|
519
|
-
- db/migrate/20250925000000_create_github_integrations.rb
|
|
520
|
-
- db/migrate/20250927000000_add_webhook_secret_to_github_repository_links.rb
|
|
521
530
|
- db/migrate/20250928000000_add_action_and_approver_to_comments.rb
|
|
522
531
|
- db/migrate/20250928010000_add_action_execution_tracking_to_comments.rb
|
|
523
|
-
- db/migrate/20250928105957_add_github_gemini_prompt_to_creatives.rb
|
|
524
532
|
- db/migrate/20250929000000_add_comment_and_creative_refs_to_inbox_items.rb
|
|
525
533
|
- db/migrate/20251001000001_create_contacts.rb
|
|
526
534
|
- db/migrate/20251002000000_add_shared_by_to_creative_shares.rb
|
|
@@ -564,6 +572,9 @@ files:
|
|
|
564
572
|
- db/migrate/20260203002637_add_requires_approval_to_mcp_tools.rb
|
|
565
573
|
- db/migrate/20260203002643_add_pending_tool_call_to_tasks.rb
|
|
566
574
|
- db/migrate/20260203083302_add_position_to_topics.rb
|
|
575
|
+
- db/migrate/20260206005035_create_orchestrator_policies.rb
|
|
576
|
+
- db/migrate/20260206094509_add_retry_count_to_tasks.rb
|
|
577
|
+
- db/migrate/20260206100000_add_topic_id_to_tasks.rb
|
|
567
578
|
- lib/collavre.rb
|
|
568
579
|
- lib/collavre/configuration.rb
|
|
569
580
|
- lib/collavre/engine.rb
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
module Collavre
|
|
2
|
-
class GithubAuthController < ApplicationController
|
|
3
|
-
allow_unauthenticated_access only: :callback
|
|
4
|
-
before_action -> { enforce_auth_provider!(:github) }, only: :callback
|
|
5
|
-
|
|
6
|
-
def callback
|
|
7
|
-
auth = request.env["omniauth.auth"]
|
|
8
|
-
gh = Collavre::GithubAccount.find_or_initialize_by(github_uid: auth.uid)
|
|
9
|
-
|
|
10
|
-
if gh.new_record?
|
|
11
|
-
unless Current.user
|
|
12
|
-
redirect_to collavre.new_session_path, alert: I18n.t("collavre.github_auth.login_first")
|
|
13
|
-
return
|
|
14
|
-
end
|
|
15
|
-
gh.user = Current.user
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
gh.token = auth.credentials.token
|
|
19
|
-
gh.login = auth.info.nickname
|
|
20
|
-
gh.save!
|
|
21
|
-
|
|
22
|
-
redirect_to creatives_path, notice: I18n.t("collavre.github_auth.connected")
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module Collavre
|
|
2
|
-
class GithubAccount < ApplicationRecord
|
|
3
|
-
self.table_name = "github_accounts"
|
|
4
|
-
|
|
5
|
-
belongs_to :user, class_name: "Collavre::User"
|
|
6
|
-
has_many :github_repository_links, class_name: "Collavre::GithubRepositoryLink", dependent: :destroy
|
|
7
|
-
|
|
8
|
-
encrypts :token, deterministic: false
|
|
9
|
-
end
|
|
10
|
-
end
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
module Collavre
|
|
2
|
-
class GithubRepositoryLink < ApplicationRecord
|
|
3
|
-
self.table_name = "github_repository_links"
|
|
4
|
-
|
|
5
|
-
belongs_to :creative, class_name: "Collavre::Creative"
|
|
6
|
-
belongs_to :github_account, class_name: "Collavre::GithubAccount"
|
|
7
|
-
|
|
8
|
-
validates :repository_full_name, presence: true
|
|
9
|
-
validates :webhook_secret, presence: true
|
|
10
|
-
|
|
11
|
-
before_validation :ensure_webhook_secret
|
|
12
|
-
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
def ensure_webhook_secret
|
|
16
|
-
self.webhook_secret ||= SecureRandom.hex(20)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
module Collavre
|
|
2
|
-
module Github
|
|
3
|
-
class Client
|
|
4
|
-
def initialize(account)
|
|
5
|
-
@client = Octokit::Client.new(access_token: account.token)
|
|
6
|
-
@client.auto_paginate = true
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def organizations
|
|
10
|
-
client.organizations
|
|
11
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
12
|
-
Rails.logger.warn("GitHub organizations fetch failed: #{e.message}")
|
|
13
|
-
[]
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def repositories_for_authenticated_user
|
|
17
|
-
client.repos(nil, type: "all")
|
|
18
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
19
|
-
Rails.logger.warn("GitHub user repos fetch failed: #{e.message}")
|
|
20
|
-
[]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def repositories_for_organization(org)
|
|
24
|
-
client.org_repos(org, type: "all")
|
|
25
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
26
|
-
Rails.logger.warn("GitHub org repos fetch failed: #{e.message}")
|
|
27
|
-
[]
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def pull_request_details(repo_full_name, number)
|
|
31
|
-
client.pull_request(repo_full_name, number)
|
|
32
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
33
|
-
Rails.logger.warn("GitHub PR fetch failed: #{e.message}")
|
|
34
|
-
nil
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def pull_request_commit_messages(repo_full_name, number)
|
|
38
|
-
client
|
|
39
|
-
.pull_request_commits(repo_full_name, number)
|
|
40
|
-
.map { |commit| commit.commit&.message }
|
|
41
|
-
.compact
|
|
42
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
43
|
-
Rails.logger.warn("GitHub PR commits fetch failed: #{e.message}")
|
|
44
|
-
[]
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def pull_request_diff(repo_full_name, number)
|
|
48
|
-
files = client.pull_request_files(repo_full_name, number)
|
|
49
|
-
formatted = files.filter_map do |file|
|
|
50
|
-
next unless file.patch.present?
|
|
51
|
-
|
|
52
|
-
<<~DIFF.strip
|
|
53
|
-
diff --git a/#{file.filename} b/#{file.filename}
|
|
54
|
-
#{file.patch}
|
|
55
|
-
DIFF
|
|
56
|
-
end
|
|
57
|
-
formatted.join("\n\n").presence
|
|
58
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
59
|
-
Rails.logger.warn("GitHub PR files fetch failed: #{e.message}")
|
|
60
|
-
nil
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
def repository_hooks(repo_full_name)
|
|
64
|
-
client.hooks(repo_full_name)
|
|
65
|
-
rescue Octokit::Error, Faraday::Error => e
|
|
66
|
-
Rails.logger.warn("GitHub hooks fetch failed for #{repo_full_name}: #{e.message}")
|
|
67
|
-
[]
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def create_repository_webhook(repo_full_name, url:, secret:, events:, content_type: "json")
|
|
71
|
-
client.create_hook(
|
|
72
|
-
repo_full_name,
|
|
73
|
-
"web",
|
|
74
|
-
{
|
|
75
|
-
url: url,
|
|
76
|
-
content_type: content_type,
|
|
77
|
-
secret: secret
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
events: events,
|
|
81
|
-
active: true
|
|
82
|
-
}
|
|
83
|
-
)
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
def update_repository_webhook(repo_full_name, hook_id, url:, secret:, events:, content_type: "json")
|
|
87
|
-
client.edit_hook(
|
|
88
|
-
repo_full_name,
|
|
89
|
-
hook_id,
|
|
90
|
-
"web",
|
|
91
|
-
{
|
|
92
|
-
url: url,
|
|
93
|
-
content_type: content_type,
|
|
94
|
-
secret: secret
|
|
95
|
-
},
|
|
96
|
-
{
|
|
97
|
-
events: events,
|
|
98
|
-
active: true
|
|
99
|
-
}
|
|
100
|
-
)
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
def delete_repository_webhook(repo_full_name, hook_id)
|
|
104
|
-
client.remove_hook(repo_full_name, hook_id)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
private
|
|
108
|
-
|
|
109
|
-
attr_reader :client
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|