codex-autorunner 0.1.1__py3-none-any.whl → 1.0.0__py3-none-any.whl
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.
- codex_autorunner/__main__.py +4 -0
- codex_autorunner/agents/__init__.py +20 -0
- codex_autorunner/agents/base.py +2 -2
- codex_autorunner/agents/codex/harness.py +1 -1
- codex_autorunner/agents/opencode/__init__.py +4 -0
- codex_autorunner/agents/opencode/agent_config.py +104 -0
- codex_autorunner/agents/opencode/client.py +305 -28
- codex_autorunner/agents/opencode/harness.py +71 -20
- codex_autorunner/agents/opencode/logging.py +225 -0
- codex_autorunner/agents/opencode/run_prompt.py +261 -0
- codex_autorunner/agents/opencode/runtime.py +1202 -132
- codex_autorunner/agents/opencode/supervisor.py +194 -68
- codex_autorunner/agents/registry.py +258 -0
- codex_autorunner/agents/types.py +2 -2
- codex_autorunner/api.py +25 -0
- codex_autorunner/bootstrap.py +19 -40
- codex_autorunner/cli.py +234 -151
- codex_autorunner/core/about_car.py +44 -32
- codex_autorunner/core/adapter_utils.py +21 -0
- codex_autorunner/core/app_server_events.py +15 -6
- codex_autorunner/core/app_server_logging.py +55 -15
- codex_autorunner/core/app_server_prompts.py +28 -259
- codex_autorunner/core/app_server_threads.py +15 -26
- codex_autorunner/core/circuit_breaker.py +183 -0
- codex_autorunner/core/codex_runner.py +6 -0
- codex_autorunner/core/config.py +555 -133
- codex_autorunner/core/docs.py +54 -9
- codex_autorunner/core/drafts.py +82 -0
- codex_autorunner/core/engine.py +828 -274
- codex_autorunner/core/exceptions.py +60 -0
- codex_autorunner/core/flows/__init__.py +25 -0
- codex_autorunner/core/flows/controller.py +178 -0
- codex_autorunner/core/flows/definition.py +82 -0
- codex_autorunner/core/flows/models.py +75 -0
- codex_autorunner/core/flows/runtime.py +351 -0
- codex_autorunner/core/flows/store.py +485 -0
- codex_autorunner/core/flows/transition.py +133 -0
- codex_autorunner/core/flows/worker_process.py +242 -0
- codex_autorunner/core/hub.py +21 -13
- codex_autorunner/core/locks.py +118 -1
- codex_autorunner/core/logging_utils.py +9 -6
- codex_autorunner/core/path_utils.py +123 -0
- codex_autorunner/core/prompt.py +15 -7
- codex_autorunner/core/redaction.py +29 -0
- codex_autorunner/core/retry.py +61 -0
- codex_autorunner/core/review.py +888 -0
- codex_autorunner/core/review_context.py +161 -0
- codex_autorunner/core/run_index.py +223 -0
- codex_autorunner/core/runner_controller.py +44 -1
- codex_autorunner/core/runner_process.py +30 -1
- codex_autorunner/core/sqlite_utils.py +32 -0
- codex_autorunner/core/state.py +273 -44
- codex_autorunner/core/static_assets.py +55 -0
- codex_autorunner/core/supervisor_utils.py +67 -0
- codex_autorunner/core/text_delta_coalescer.py +43 -0
- codex_autorunner/core/update.py +20 -11
- codex_autorunner/core/update_runner.py +2 -0
- codex_autorunner/core/usage.py +107 -75
- codex_autorunner/core/utils.py +167 -3
- codex_autorunner/discovery.py +3 -3
- codex_autorunner/flows/ticket_flow/__init__.py +3 -0
- codex_autorunner/flows/ticket_flow/definition.py +91 -0
- codex_autorunner/integrations/agents/__init__.py +27 -0
- codex_autorunner/integrations/agents/agent_backend.py +142 -0
- codex_autorunner/integrations/agents/codex_backend.py +307 -0
- codex_autorunner/integrations/agents/opencode_backend.py +325 -0
- codex_autorunner/integrations/agents/run_event.py +71 -0
- codex_autorunner/integrations/app_server/client.py +708 -153
- codex_autorunner/integrations/app_server/supervisor.py +59 -33
- codex_autorunner/integrations/telegram/adapter.py +474 -185
- codex_autorunner/integrations/telegram/api_schemas.py +120 -0
- codex_autorunner/integrations/telegram/config.py +239 -1
- codex_autorunner/integrations/telegram/constants.py +19 -1
- codex_autorunner/integrations/telegram/dispatch.py +44 -8
- codex_autorunner/integrations/telegram/doctor.py +47 -0
- codex_autorunner/integrations/telegram/handlers/approvals.py +12 -10
- codex_autorunner/integrations/telegram/handlers/callbacks.py +15 -1
- codex_autorunner/integrations/telegram/handlers/commands/__init__.py +29 -0
- codex_autorunner/integrations/telegram/handlers/commands/approvals.py +173 -0
- codex_autorunner/integrations/telegram/handlers/commands/execution.py +2595 -0
- codex_autorunner/integrations/telegram/handlers/commands/files.py +1408 -0
- codex_autorunner/integrations/telegram/handlers/commands/flows.py +227 -0
- codex_autorunner/integrations/telegram/handlers/commands/formatting.py +81 -0
- codex_autorunner/integrations/telegram/handlers/commands/github.py +1688 -0
- codex_autorunner/integrations/telegram/handlers/commands/shared.py +190 -0
- codex_autorunner/integrations/telegram/handlers/commands/voice.py +112 -0
- codex_autorunner/integrations/telegram/handlers/commands/workspace.py +2043 -0
- codex_autorunner/integrations/telegram/handlers/commands_runtime.py +954 -5689
- codex_autorunner/integrations/telegram/handlers/{commands.py → commands_spec.py} +11 -4
- codex_autorunner/integrations/telegram/handlers/messages.py +374 -49
- codex_autorunner/integrations/telegram/handlers/questions.py +389 -0
- codex_autorunner/integrations/telegram/handlers/selections.py +6 -4
- codex_autorunner/integrations/telegram/handlers/utils.py +171 -0
- codex_autorunner/integrations/telegram/helpers.py +90 -18
- codex_autorunner/integrations/telegram/notifications.py +126 -35
- codex_autorunner/integrations/telegram/outbox.py +214 -43
- codex_autorunner/integrations/telegram/progress_stream.py +42 -19
- codex_autorunner/integrations/telegram/runtime.py +24 -13
- codex_autorunner/integrations/telegram/service.py +500 -129
- codex_autorunner/integrations/telegram/state.py +1278 -330
- codex_autorunner/integrations/telegram/ticket_flow_bridge.py +322 -0
- codex_autorunner/integrations/telegram/transport.py +37 -4
- codex_autorunner/integrations/telegram/trigger_mode.py +53 -0
- codex_autorunner/integrations/telegram/types.py +22 -2
- codex_autorunner/integrations/telegram/voice.py +14 -15
- codex_autorunner/manifest.py +2 -0
- codex_autorunner/plugin_api.py +22 -0
- codex_autorunner/routes/__init__.py +25 -14
- codex_autorunner/routes/agents.py +18 -78
- codex_autorunner/routes/analytics.py +239 -0
- codex_autorunner/routes/base.py +142 -113
- codex_autorunner/routes/file_chat.py +836 -0
- codex_autorunner/routes/flows.py +980 -0
- codex_autorunner/routes/messages.py +459 -0
- codex_autorunner/routes/repos.py +17 -0
- codex_autorunner/routes/review.py +148 -0
- codex_autorunner/routes/sessions.py +16 -8
- codex_autorunner/routes/settings.py +22 -0
- codex_autorunner/routes/shared.py +33 -3
- codex_autorunner/routes/system.py +22 -1
- codex_autorunner/routes/usage.py +87 -0
- codex_autorunner/routes/voice.py +5 -13
- codex_autorunner/routes/workspace.py +271 -0
- codex_autorunner/server.py +2 -1
- codex_autorunner/static/agentControls.js +9 -1
- codex_autorunner/static/agentEvents.js +248 -0
- codex_autorunner/static/app.js +27 -22
- codex_autorunner/static/autoRefresh.js +29 -1
- codex_autorunner/static/bootstrap.js +1 -0
- codex_autorunner/static/bus.js +1 -0
- codex_autorunner/static/cache.js +1 -0
- codex_autorunner/static/constants.js +20 -4
- codex_autorunner/static/dashboard.js +162 -150
- codex_autorunner/static/diffRenderer.js +37 -0
- codex_autorunner/static/docChatCore.js +324 -0
- codex_autorunner/static/docChatStorage.js +65 -0
- codex_autorunner/static/docChatVoice.js +65 -0
- codex_autorunner/static/docEditor.js +133 -0
- codex_autorunner/static/env.js +1 -0
- codex_autorunner/static/eventSummarizer.js +166 -0
- codex_autorunner/static/fileChat.js +182 -0
- codex_autorunner/static/health.js +155 -0
- codex_autorunner/static/hub.js +67 -126
- codex_autorunner/static/index.html +788 -807
- codex_autorunner/static/liveUpdates.js +59 -0
- codex_autorunner/static/loader.js +1 -0
- codex_autorunner/static/messages.js +470 -0
- codex_autorunner/static/mobileCompact.js +2 -1
- codex_autorunner/static/settings.js +24 -205
- codex_autorunner/static/styles.css +7577 -3758
- codex_autorunner/static/tabs.js +28 -5
- codex_autorunner/static/terminal.js +14 -0
- codex_autorunner/static/terminalManager.js +53 -59
- codex_autorunner/static/ticketChatActions.js +333 -0
- codex_autorunner/static/ticketChatEvents.js +16 -0
- codex_autorunner/static/ticketChatStorage.js +16 -0
- codex_autorunner/static/ticketChatStream.js +264 -0
- codex_autorunner/static/ticketEditor.js +750 -0
- codex_autorunner/static/ticketVoice.js +9 -0
- codex_autorunner/static/tickets.js +1315 -0
- codex_autorunner/static/utils.js +32 -3
- codex_autorunner/static/voice.js +21 -7
- codex_autorunner/static/workspace.js +672 -0
- codex_autorunner/static/workspaceApi.js +53 -0
- codex_autorunner/static/workspaceFileBrowser.js +504 -0
- codex_autorunner/tickets/__init__.py +20 -0
- codex_autorunner/tickets/agent_pool.py +377 -0
- codex_autorunner/tickets/files.py +85 -0
- codex_autorunner/tickets/frontmatter.py +55 -0
- codex_autorunner/tickets/lint.py +102 -0
- codex_autorunner/tickets/models.py +95 -0
- codex_autorunner/tickets/outbox.py +232 -0
- codex_autorunner/tickets/replies.py +179 -0
- codex_autorunner/tickets/runner.py +823 -0
- codex_autorunner/tickets/spec_ingest.py +77 -0
- codex_autorunner/voice/capture.py +7 -7
- codex_autorunner/voice/service.py +51 -9
- codex_autorunner/web/app.py +419 -199
- codex_autorunner/web/hub_jobs.py +13 -2
- codex_autorunner/web/middleware.py +47 -13
- codex_autorunner/web/pty_session.py +26 -13
- codex_autorunner/web/schemas.py +114 -109
- codex_autorunner/web/static_assets.py +55 -42
- codex_autorunner/web/static_refresh.py +86 -0
- codex_autorunner/workspace/__init__.py +40 -0
- codex_autorunner/workspace/paths.py +319 -0
- {codex_autorunner-0.1.1.dist-info → codex_autorunner-1.0.0.dist-info}/METADATA +20 -21
- codex_autorunner-1.0.0.dist-info/RECORD +251 -0
- {codex_autorunner-0.1.1.dist-info → codex_autorunner-1.0.0.dist-info}/WHEEL +1 -1
- codex_autorunner/core/doc_chat.py +0 -1415
- codex_autorunner/core/snapshot.py +0 -580
- codex_autorunner/integrations/github/chatops.py +0 -268
- codex_autorunner/integrations/github/pr_flow.py +0 -1314
- codex_autorunner/routes/docs.py +0 -381
- codex_autorunner/routes/github.py +0 -327
- codex_autorunner/routes/runs.py +0 -118
- codex_autorunner/spec_ingest.py +0 -788
- codex_autorunner/static/docChatActions.js +0 -279
- codex_autorunner/static/docChatEvents.js +0 -300
- codex_autorunner/static/docChatRender.js +0 -205
- codex_autorunner/static/docChatStream.js +0 -361
- codex_autorunner/static/docs.js +0 -20
- codex_autorunner/static/docsClipboard.js +0 -69
- codex_autorunner/static/docsCrud.js +0 -257
- codex_autorunner/static/docsDocUpdates.js +0 -62
- codex_autorunner/static/docsDrafts.js +0 -16
- codex_autorunner/static/docsElements.js +0 -69
- codex_autorunner/static/docsInit.js +0 -274
- codex_autorunner/static/docsParse.js +0 -160
- codex_autorunner/static/docsSnapshot.js +0 -87
- codex_autorunner/static/docsSpecIngest.js +0 -263
- codex_autorunner/static/docsState.js +0 -127
- codex_autorunner/static/docsThreadRegistry.js +0 -44
- codex_autorunner/static/docsUi.js +0 -153
- codex_autorunner/static/docsVoice.js +0 -56
- codex_autorunner/static/github.js +0 -442
- codex_autorunner/static/logs.js +0 -640
- codex_autorunner/static/runs.js +0 -409
- codex_autorunner/static/snapshot.js +0 -124
- codex_autorunner/static/state.js +0 -86
- codex_autorunner/static/todoPreview.js +0 -27
- codex_autorunner/workspace.py +0 -16
- codex_autorunner-0.1.1.dist-info/RECORD +0 -191
- {codex_autorunner-0.1.1.dist-info → codex_autorunner-1.0.0.dist-info}/entry_points.txt +0 -0
- {codex_autorunner-0.1.1.dist-info → codex_autorunner-1.0.0.dist-info}/licenses/LICENSE +0 -0
- {codex_autorunner-0.1.1.dist-info → codex_autorunner-1.0.0.dist-info}/top_level.txt +0 -0
codex_autorunner/static/hub.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
// GENERATED FILE - do not edit directly. Source: static_src/
|
|
1
2
|
import { api, flash, statusPill, resolvePath, escapeHtml, confirmModal, inputModal, openModal, } from "./utils.js";
|
|
2
3
|
import { registerAutoRefresh } from "./autoRefresh.js";
|
|
3
|
-
import { CONSTANTS } from "./constants.js";
|
|
4
4
|
import { HUB_BASE } from "./env.js";
|
|
5
5
|
let hubData = { repos: [], last_scan_at: null };
|
|
6
|
-
const repoPrCache = new Map();
|
|
7
|
-
const repoPrFetches = new Set();
|
|
8
6
|
const prefetchedUrls = new Set();
|
|
9
7
|
const HUB_CACHE_TTL_MS = 30000;
|
|
10
8
|
const HUB_CACHE_KEY = `car:hub:${HUB_BASE || "/"}`;
|
|
11
9
|
const HUB_USAGE_CACHE_KEY = `car:hub-usage:${HUB_BASE || "/"}`;
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
const PR_PREFETCH_MARGIN = "200px";
|
|
10
|
+
const HUB_REFRESH_ACTIVE_MS = 5000;
|
|
11
|
+
const HUB_REFRESH_IDLE_MS = 30000;
|
|
12
|
+
let lastHubAutoRefreshAt = 0;
|
|
16
13
|
const repoListEl = document.getElementById("hub-repo-list");
|
|
17
14
|
const lastScanEl = document.getElementById("hub-last-scan");
|
|
18
15
|
const totalEl = document.getElementById("hub-count-total");
|
|
@@ -25,6 +22,8 @@ const hubUsageChartCanvas = document.getElementById("hub-usage-chart-canvas");
|
|
|
25
22
|
const hubUsageChartRange = document.getElementById("hub-usage-chart-range");
|
|
26
23
|
const hubUsageChartSegment = document.getElementById("hub-usage-chart-segment");
|
|
27
24
|
const hubVersionEl = document.getElementById("hub-version");
|
|
25
|
+
const hubInboxList = document.getElementById("hub-inbox-list");
|
|
26
|
+
const hubInboxRefresh = document.getElementById("hub-inbox-refresh");
|
|
28
27
|
const UPDATE_STATUS_SEEN_KEY = "car_update_status_seen";
|
|
29
28
|
const HUB_JOB_POLL_INTERVAL_MS = 1200;
|
|
30
29
|
const HUB_JOB_TIMEOUT_MS = 180000;
|
|
@@ -35,10 +34,6 @@ const hubUsageChartState = {
|
|
|
35
34
|
};
|
|
36
35
|
let hubUsageSeriesRetryTimer = null;
|
|
37
36
|
let hubUsageSummaryRetryTimer = null;
|
|
38
|
-
const repoPrPending = new Set();
|
|
39
|
-
const repoPrQueue = [];
|
|
40
|
-
let repoPrActive = 0;
|
|
41
|
-
let repoPrObserver = null;
|
|
42
37
|
function saveSessionCache(key, value) {
|
|
43
38
|
try {
|
|
44
39
|
const payload = { at: Date.now(), value };
|
|
@@ -65,7 +60,7 @@ function loadSessionCache(key, maxAgeMs) {
|
|
|
65
60
|
}
|
|
66
61
|
}
|
|
67
62
|
function formatRunSummary(repo) {
|
|
68
|
-
if (!repo.
|
|
63
|
+
if (!repo.initialized)
|
|
69
64
|
return "Not initialized";
|
|
70
65
|
if (!repo.exists_on_disk)
|
|
71
66
|
return "Missing on disk";
|
|
@@ -77,7 +72,7 @@ function formatRunSummary(repo) {
|
|
|
77
72
|
return `#${repo.last_run_id}${exit}`;
|
|
78
73
|
}
|
|
79
74
|
function formatLastActivity(repo) {
|
|
80
|
-
if (!repo.
|
|
75
|
+
if (!repo.initialized)
|
|
81
76
|
return "";
|
|
82
77
|
const time = repo.last_run_finished_at || repo.last_run_started_at;
|
|
83
78
|
if (!time)
|
|
@@ -683,11 +678,11 @@ function buildActions(repo) {
|
|
|
683
678
|
else if (!missing && repo.init_error) {
|
|
684
679
|
actions.push({
|
|
685
680
|
key: "init",
|
|
686
|
-
label: repo.
|
|
681
|
+
label: repo.initialized ? "Re-init" : "Init",
|
|
687
682
|
kind: "primary",
|
|
688
683
|
});
|
|
689
684
|
}
|
|
690
|
-
else if (!missing && !repo.
|
|
685
|
+
else if (!missing && !repo.initialized) {
|
|
691
686
|
actions.push({ key: "init", label: "Init", kind: "primary" });
|
|
692
687
|
}
|
|
693
688
|
if (!missing && kind === "base") {
|
|
@@ -756,76 +751,9 @@ function inferBaseId(repo) {
|
|
|
756
751
|
}
|
|
757
752
|
return null;
|
|
758
753
|
}
|
|
759
|
-
function initRepoPrObserver() {
|
|
760
|
-
if (!("IntersectionObserver" in window))
|
|
761
|
-
return null;
|
|
762
|
-
if (repoPrObserver)
|
|
763
|
-
return repoPrObserver;
|
|
764
|
-
repoPrObserver = new IntersectionObserver((entries) => {
|
|
765
|
-
entries.forEach((entry) => {
|
|
766
|
-
if (!entry.isIntersecting)
|
|
767
|
-
return;
|
|
768
|
-
const target = entry.target;
|
|
769
|
-
const repoId = target?.dataset?.repoId;
|
|
770
|
-
if (repoId) {
|
|
771
|
-
const repo = (hubData.repos || []).find((item) => item.id === repoId);
|
|
772
|
-
if (repo)
|
|
773
|
-
scheduleRepoPrFetch(repo);
|
|
774
|
-
}
|
|
775
|
-
if (target)
|
|
776
|
-
repoPrObserver?.unobserve(target);
|
|
777
|
-
});
|
|
778
|
-
}, { rootMargin: PR_PREFETCH_MARGIN });
|
|
779
|
-
return repoPrObserver;
|
|
780
|
-
}
|
|
781
|
-
function scheduleRepoPrFetch(repo) {
|
|
782
|
-
if (!repo || repo.mounted !== true)
|
|
783
|
-
return;
|
|
784
|
-
const cached = repoPrCache.get(repo.id);
|
|
785
|
-
if (cached &&
|
|
786
|
-
typeof cached.fetchedAt === "number" &&
|
|
787
|
-
Date.now() - cached.fetchedAt <
|
|
788
|
-
(cached.failed ? PR_FAILURE_TTL_MS : PR_CACHE_TTL_MS)) {
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
791
|
-
if (repoPrFetches.has(repo.id) || repoPrPending.has(repo.id))
|
|
792
|
-
return;
|
|
793
|
-
repoPrPending.add(repo.id);
|
|
794
|
-
repoPrQueue.push(repo);
|
|
795
|
-
pumpRepoPrQueue();
|
|
796
|
-
}
|
|
797
|
-
function pumpRepoPrQueue() {
|
|
798
|
-
while (repoPrActive < PR_FETCH_CONCURRENCY && repoPrQueue.length) {
|
|
799
|
-
const repo = repoPrQueue.shift();
|
|
800
|
-
if (!repo || repoPrFetches.has(repo.id))
|
|
801
|
-
continue;
|
|
802
|
-
repoPrPending.delete(repo.id);
|
|
803
|
-
repoPrActive += 1;
|
|
804
|
-
repoPrFetches.add(repo.id);
|
|
805
|
-
api(`/repos/${repo.id}/api/github/pr`, { method: "GET" })
|
|
806
|
-
.then((pr) => {
|
|
807
|
-
repoPrCache.set(repo.id, { data: pr, fetchedAt: Date.now() });
|
|
808
|
-
})
|
|
809
|
-
.catch(() => {
|
|
810
|
-
repoPrCache.set(repo.id, {
|
|
811
|
-
data: null,
|
|
812
|
-
fetchedAt: Date.now(),
|
|
813
|
-
failed: true,
|
|
814
|
-
});
|
|
815
|
-
})
|
|
816
|
-
.finally(() => {
|
|
817
|
-
repoPrFetches.delete(repo.id);
|
|
818
|
-
repoPrActive -= 1;
|
|
819
|
-
pumpRepoPrQueue();
|
|
820
|
-
renderRepos(hubData.repos || []);
|
|
821
|
-
});
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
754
|
function renderRepos(repos) {
|
|
825
755
|
if (!repoListEl)
|
|
826
756
|
return;
|
|
827
|
-
if (repoPrObserver)
|
|
828
|
-
repoPrObserver.disconnect();
|
|
829
757
|
repoListEl.innerHTML = "";
|
|
830
758
|
if (!repos.length) {
|
|
831
759
|
repoListEl.innerHTML =
|
|
@@ -867,7 +795,7 @@ function renderRepos(repos) {
|
|
|
867
795
|
const lockBadge = repo.lock_status && repo.lock_status !== "unlocked"
|
|
868
796
|
? `<span class="pill pill-small pill-warn">${escapeHtml(repo.lock_status.replace("_", " "))}</span>`
|
|
869
797
|
: "";
|
|
870
|
-
const initBadge = !repo.
|
|
798
|
+
const initBadge = !repo.initialized
|
|
871
799
|
? '<span class="pill pill-small pill-warn">uninit</span>'
|
|
872
800
|
: "";
|
|
873
801
|
let noteText = "";
|
|
@@ -900,12 +828,6 @@ function renderRepos(repos) {
|
|
|
900
828
|
const infoLine = infoItems.length > 0
|
|
901
829
|
? `<span class="hub-repo-info-line">${escapeHtml(infoItems.join(" · "))}</span>`
|
|
902
830
|
: "";
|
|
903
|
-
const prInfo = repoPrCache.get(repo.id)?.data;
|
|
904
|
-
const prPill = prInfo?.links?.files
|
|
905
|
-
? `<a class="pill pill-small hub-pr-pill" href="${escapeHtml(prInfo.links.files)}" target="_blank" rel="noopener noreferrer" title="${escapeHtml(prInfo.pr?.title || "Open PR files")}">PR${prInfo.pr?.number
|
|
906
|
-
? ` #${escapeHtml(prInfo.pr.number)}`
|
|
907
|
-
: ""}</a>`
|
|
908
|
-
: "";
|
|
909
831
|
card.innerHTML = `
|
|
910
832
|
<div class="hub-repo-row">
|
|
911
833
|
<div class="hub-repo-left">
|
|
@@ -918,7 +840,6 @@ function renderRepos(repos) {
|
|
|
918
840
|
<span class="hub-repo-title">${escapeHtml(repo.display_name)}</span>
|
|
919
841
|
<div class="hub-repo-subline">
|
|
920
842
|
${infoLine}
|
|
921
|
-
${prPill}
|
|
922
843
|
</div>
|
|
923
844
|
</div>
|
|
924
845
|
<div class="hub-repo-right">
|
|
@@ -933,15 +854,6 @@ function renderRepos(repos) {
|
|
|
933
854
|
statusPill(statusEl, repo.status);
|
|
934
855
|
}
|
|
935
856
|
repoListEl.appendChild(card);
|
|
936
|
-
if (repo.mounted === true) {
|
|
937
|
-
const observer = initRepoPrObserver();
|
|
938
|
-
if (observer) {
|
|
939
|
-
observer.observe(card);
|
|
940
|
-
}
|
|
941
|
-
else {
|
|
942
|
-
scheduleRepoPrFetch(repo);
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
857
|
};
|
|
946
858
|
orderedGroups.forEach((group) => {
|
|
947
859
|
const repo = group.base;
|
|
@@ -978,34 +890,16 @@ function renderRepos(repos) {
|
|
|
978
890
|
.forEach((wt) => renderRepoCard(wt, { isWorktreeRow: true }));
|
|
979
891
|
}
|
|
980
892
|
}
|
|
981
|
-
async function refreshRepoPrCache(repos) {
|
|
982
|
-
const mounted = repos.filter((r) => r && r.mounted === true);
|
|
983
|
-
if (!mounted.length)
|
|
984
|
-
return;
|
|
985
|
-
const observer = initRepoPrObserver();
|
|
986
|
-
if (observer && repoListEl) {
|
|
987
|
-
mounted.forEach((repo) => {
|
|
988
|
-
const card = repoListEl.querySelector(`[data-repo-id="${repo.id}"]`);
|
|
989
|
-
if (card) {
|
|
990
|
-
observer.observe(card);
|
|
991
|
-
}
|
|
992
|
-
else {
|
|
993
|
-
scheduleRepoPrFetch(repo);
|
|
994
|
-
}
|
|
995
|
-
});
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
mounted.forEach((repo) => scheduleRepoPrFetch(repo));
|
|
999
|
-
}
|
|
1000
893
|
async function refreshHub() {
|
|
1001
894
|
setButtonLoading(true);
|
|
1002
895
|
try {
|
|
1003
896
|
const data = await api("/hub/repos", { method: "GET" });
|
|
1004
897
|
hubData = data;
|
|
898
|
+
markHubRefreshed();
|
|
1005
899
|
saveSessionCache(HUB_CACHE_KEY, hubData);
|
|
1006
900
|
renderSummary(data.repos || []);
|
|
1007
901
|
renderRepos(data.repos || []);
|
|
1008
|
-
await
|
|
902
|
+
await loadHubInbox().catch(() => { });
|
|
1009
903
|
await loadHubUsage().catch(() => { });
|
|
1010
904
|
}
|
|
1011
905
|
catch (err) {
|
|
@@ -1015,6 +909,40 @@ async function refreshHub() {
|
|
|
1015
909
|
setButtonLoading(false);
|
|
1016
910
|
}
|
|
1017
911
|
}
|
|
912
|
+
async function loadHubInbox() {
|
|
913
|
+
if (!hubInboxList)
|
|
914
|
+
return;
|
|
915
|
+
hubInboxList.innerHTML = "Loading…";
|
|
916
|
+
try {
|
|
917
|
+
const payload = (await api("/hub/messages", { method: "GET" }));
|
|
918
|
+
const items = payload?.items || [];
|
|
919
|
+
if (!items.length) {
|
|
920
|
+
hubInboxList.innerHTML = '<div class="muted">No paused runs</div>';
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
hubInboxList.innerHTML = items
|
|
924
|
+
.map((item) => {
|
|
925
|
+
const title = item.message?.title || item.message?.mode || "Message";
|
|
926
|
+
const excerpt = item.message?.body ? item.message.body.slice(0, 160) : "";
|
|
927
|
+
const repoLabel = item.repo_display_name || item.repo_id;
|
|
928
|
+
const href = item.open_url || `/repos/${item.repo_id}/?tab=messages&run_id=${item.run_id}`;
|
|
929
|
+
return `
|
|
930
|
+
<a class="hub-inbox-item" href="${escapeHtml(resolvePath(href))}">
|
|
931
|
+
<div class="hub-inbox-item-header">
|
|
932
|
+
<span class="hub-inbox-repo">${escapeHtml(repoLabel)}</span>
|
|
933
|
+
<span class="pill pill-small pill-warn">paused</span>
|
|
934
|
+
</div>
|
|
935
|
+
<div class="hub-inbox-title">${escapeHtml(title)}</div>
|
|
936
|
+
<div class="hub-inbox-excerpt muted small">${escapeHtml(excerpt)}</div>
|
|
937
|
+
</a>
|
|
938
|
+
`;
|
|
939
|
+
})
|
|
940
|
+
.join("");
|
|
941
|
+
}
|
|
942
|
+
catch (_err) {
|
|
943
|
+
hubInboxList.innerHTML = '';
|
|
944
|
+
}
|
|
945
|
+
}
|
|
1018
946
|
async function triggerHubScan() {
|
|
1019
947
|
setButtonLoading(true);
|
|
1020
948
|
try {
|
|
@@ -1263,11 +1191,6 @@ function attachHubHandlers() {
|
|
|
1263
1191
|
if (repoListEl) {
|
|
1264
1192
|
repoListEl.addEventListener("click", (event) => {
|
|
1265
1193
|
const target = event.target;
|
|
1266
|
-
const prLink = target instanceof HTMLElement && target.closest("a.hub-pr-pill");
|
|
1267
|
-
if (prLink) {
|
|
1268
|
-
event.stopPropagation();
|
|
1269
|
-
return;
|
|
1270
|
-
}
|
|
1271
1194
|
const btn = target instanceof HTMLElement && target.closest("button[data-action]");
|
|
1272
1195
|
if (btn) {
|
|
1273
1196
|
event.stopPropagation();
|
|
@@ -1319,6 +1242,7 @@ async function silentRefreshHub() {
|
|
|
1319
1242
|
try {
|
|
1320
1243
|
const data = await api("/hub/repos", { method: "GET" });
|
|
1321
1244
|
hubData = data;
|
|
1245
|
+
markHubRefreshed();
|
|
1322
1246
|
saveSessionCache(HUB_CACHE_KEY, hubData);
|
|
1323
1247
|
renderSummary(data.repos || []);
|
|
1324
1248
|
renderRepos(data.repos || []);
|
|
@@ -1328,6 +1252,20 @@ async function silentRefreshHub() {
|
|
|
1328
1252
|
console.error("Auto-refresh hub failed:", err);
|
|
1329
1253
|
}
|
|
1330
1254
|
}
|
|
1255
|
+
function markHubRefreshed() {
|
|
1256
|
+
lastHubAutoRefreshAt = Date.now();
|
|
1257
|
+
}
|
|
1258
|
+
function hasActiveRuns(repos) {
|
|
1259
|
+
return repos.some((repo) => repo.status === "running");
|
|
1260
|
+
}
|
|
1261
|
+
async function dynamicRefreshHub() {
|
|
1262
|
+
const now = Date.now();
|
|
1263
|
+
const running = hasActiveRuns(hubData.repos || []);
|
|
1264
|
+
const minInterval = running ? HUB_REFRESH_ACTIVE_MS : HUB_REFRESH_IDLE_MS;
|
|
1265
|
+
if (now - lastHubAutoRefreshAt < minInterval)
|
|
1266
|
+
return;
|
|
1267
|
+
await silentRefreshHub();
|
|
1268
|
+
}
|
|
1331
1269
|
async function loadHubVersion() {
|
|
1332
1270
|
if (!hubVersionEl)
|
|
1333
1271
|
return;
|
|
@@ -1369,6 +1307,9 @@ export function initHub() {
|
|
|
1369
1307
|
return;
|
|
1370
1308
|
attachHubHandlers();
|
|
1371
1309
|
initHubUsageChartControls();
|
|
1310
|
+
hubInboxRefresh?.addEventListener("click", () => {
|
|
1311
|
+
void loadHubInbox();
|
|
1312
|
+
});
|
|
1372
1313
|
const cachedHub = loadSessionCache(HUB_CACHE_KEY, HUB_CACHE_TTL_MS);
|
|
1373
1314
|
if (cachedHub) {
|
|
1374
1315
|
hubData = cachedHub;
|
|
@@ -1384,9 +1325,9 @@ export function initHub() {
|
|
|
1384
1325
|
loadHubVersion();
|
|
1385
1326
|
checkUpdateStatus();
|
|
1386
1327
|
registerAutoRefresh("hub-repos", {
|
|
1387
|
-
callback: async () => { await
|
|
1328
|
+
callback: async () => { await dynamicRefreshHub(); },
|
|
1388
1329
|
tabId: null,
|
|
1389
|
-
interval:
|
|
1330
|
+
interval: HUB_REFRESH_ACTIVE_MS,
|
|
1390
1331
|
refreshOnActivation: true,
|
|
1391
1332
|
immediate: false,
|
|
1392
1333
|
});
|