oysterun 1.5.3-beta.2 → 1.5.3
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.
- package/README.md +144 -0
- package/dev/client/web/index.html +240 -13
- package/dev/client/web-chat/dist/assets/{ReactPrism-BGRmaJf7.js → ReactPrism-Bny_C7xD.js} +1 -1
- package/dev/client/web-chat/dist/assets/{ReactPrism-BGRmaJf7.js.map → ReactPrism-Bny_C7xD.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-CRrbvWg7.js → index-Bo9Y7lbT.js} +2 -2
- package/dev/client/web-chat/dist/assets/index-Bo9Y7lbT.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{index-W5ISbeWM.js → index-CIswQzBj.js} +1 -1
- package/dev/client/web-chat/dist/assets/{index-W5ISbeWM.js.map → index-CIswQzBj.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{index-Cuy-f6-d.js → index-CqfVnL4A.js} +74 -74
- package/dev/client/web-chat/dist/assets/index-CqfVnL4A.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{pdf-BFZzIBtl.js → pdf-0XtIzGl2.js} +3 -3
- package/dev/client/web-chat/dist/assets/pdf-0XtIzGl2.js.map +1 -0
- package/dev/client/web-chat/dist/assets/{web-B2-C3qO8.js → web-B5Lh8s9A.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-B2-C3qO8.js.map → web-B5Lh8s9A.js.map} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DUrVmksC.js → web-CZMJKFKu.js} +1 -1
- package/dev/client/web-chat/dist/assets/{web-DUrVmksC.js.map → web-CZMJKFKu.js.map} +1 -1
- package/dev/client/web-chat/dist/index.html +1 -1
- package/host-service/browser-root-project-index.mjs +30 -0
- package/host-service/matrix-transcript-read-adapter.mjs +80 -1
- package/host-service/package.json +1 -1
- package/host-service/routec-matrix-sqlite-store.mjs +49 -0
- package/host-service/routec-matrix-storage-adapter.mjs +36 -0
- package/host-service/scheduler-acp-provider-runner.mjs +480 -0
- package/host-service/scheduler-service.mjs +100 -33
- package/host-service/server.mjs +168 -132
- package/host-service/session-list-preview-service.mjs +124 -0
- package/host-service/session-manager.mjs +60 -19
- package/package.json +1 -1
- package/dev/client/web-chat/dist/assets/index-CRrbvWg7.js.map +0 -1
- package/dev/client/web-chat/dist/assets/index-Cuy-f6-d.js.map +0 -1
- package/dev/client/web-chat/dist/assets/pdf-BFZzIBtl.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,5 +1,149 @@
|
|
|
1
1
|
# Oysterun
|
|
2
2
|
|
|
3
|
+
## What Oysterun Is
|
|
4
|
+
|
|
5
|
+
Oysterun is a deployment and operations platform for working AI agents. It lets
|
|
6
|
+
people run Claude Code or Codex on their own Mac or Linux Host, then operate
|
|
7
|
+
those agents from an iPhone or web browser with persistent sessions,
|
|
8
|
+
scheduling, notifications, reports, websites, local files, and agent skills.
|
|
9
|
+
|
|
10
|
+
The core idea is that prompts and skills are not enough. A useful agent also
|
|
11
|
+
needs a runtime, tools, permissions, scheduled execution, a readable delivery
|
|
12
|
+
surface, and a reliable way for its user to intervene. Oysterun brings those
|
|
13
|
+
pieces together so an agent can move from "only its author can run it" toward a
|
|
14
|
+
complete AgentFolder that another user can install and operate.
|
|
15
|
+
|
|
16
|
+
## Build Week Scope
|
|
17
|
+
|
|
18
|
+
### Introduction
|
|
19
|
+
|
|
20
|
+
Oysterun is an existing platform that was created before OpenAI Build Week. The
|
|
21
|
+
submission does not claim that the complete Oysterun Host, client, session,
|
|
22
|
+
scheduling, Mail, Website, notification, or skill system was built during the
|
|
23
|
+
event.
|
|
24
|
+
|
|
25
|
+
For this submission, Build Week work is measured from July 14, 2026 at 00:00
|
|
26
|
+
Asia/Taipei, equivalent to July 13, 2026 at 09:00 Pacific Time. The final
|
|
27
|
+
repository commit before that cutoff is `cf9c8e11` (July 13 at 20:31
|
|
28
|
+
Asia/Taipei), and the submission snapshot is `711c0246` (July 20 at 23:39
|
|
29
|
+
Asia/Taipei). The range `cf9c8e11..711c0246` contains 39 commits including
|
|
30
|
+
merges and changes 159 distinct files.
|
|
31
|
+
|
|
32
|
+
The work in that measured range focuses on making complete agents easier to
|
|
33
|
+
distribute and use:
|
|
34
|
+
|
|
35
|
+
- **Stock Research Agent:** a cloneable AgentFolder that researches stocks,
|
|
36
|
+
generates readable HTML reports, publishes them through Oysterun Website, and
|
|
37
|
+
can deliver them through Oysterun Mail.
|
|
38
|
+
- **GitHub Tracker Agent:** a cloneable AgentFolder that monitors public GitHub
|
|
39
|
+
repositories, runs on a schedule, and publishes update reports.
|
|
40
|
+
- **Direct GitHub Agent Store:** a new Oysterun flow that accepts a public
|
|
41
|
+
GitHub repository URL, safely clones the AgentFolder into the Host, resolves
|
|
42
|
+
its configuration, starts a session, and opens the resulting chat.
|
|
43
|
+
|
|
44
|
+
This Build Week submission demonstrates these new agents and the Agent Store
|
|
45
|
+
workflow running on the existing Oysterun platform.
|
|
46
|
+
|
|
47
|
+
The dated Git history and the submitted Codex `/feedback` Session ID provide
|
|
48
|
+
evidence of the work completed during the submission period.
|
|
49
|
+
|
|
50
|
+
### Evidence
|
|
51
|
+
|
|
52
|
+
1. Important Commits:
|
|
53
|
+
- SQLite migration and tool-detail integration, July 14: `56690244` through `7a2e304e`
|
|
54
|
+
- Provider aggregation and Telegram delivery follow-ups, July 14:
|
|
55
|
+
`523c68d9` through `f6c66f58`
|
|
56
|
+
- Timeline and pagination recovery, July 16:
|
|
57
|
+
`212a9fd3` through `2caf0fa2`
|
|
58
|
+
- Browser Root AgentFolder registration, July 19: `87e6df47`
|
|
59
|
+
- Direct GitHub Agent Store clone/start demo, July 20: `ba6bbdfa`
|
|
60
|
+
2. Team Session:
|
|
61
|
+
1. PM: 019f5761-**1078**-7dc3-a130-64ac66435cc8
|
|
62
|
+
2. Team Lead: 019f5760-ee50-70e3-870e-1d16838305f2
|
|
63
|
+
3. Assistant1: 019f56e8-4c9f-71b2-8ad5-a0232b95686d
|
|
64
|
+
4. Assistant2: 019f552a-3830-7cf3-92ca-dd483fa63cf9
|
|
65
|
+
5. Engineer: 019f56fc-c4cd-7120-a2ff-d2c603ebafa7
|
|
66
|
+
6. Manual Session: 019f05d5-f491-7db3-8bf6-94eba3c89607
|
|
67
|
+
3. Other Repo (Agents):
|
|
68
|
+
1. https://github.com/GoatWang/oysterun-ccstock-workenv-en
|
|
69
|
+
2. https://github.com/GoatWang/oysterun-github-tracker
|
|
70
|
+
|
|
71
|
+
## How Codex And GPT-5.6 Were Used
|
|
72
|
+
|
|
73
|
+
The work measured from the July 14, 00:00 Asia/Taipei cutoff was developed with
|
|
74
|
+
Codex as the primary engineering environment and GPT-5.6 as the reasoning model
|
|
75
|
+
for planning, codebase investigation, implementation, verification design,
|
|
76
|
+
debugging, and review.
|
|
77
|
+
|
|
78
|
+
Rather than using Codex only for isolated code generation, Oysterun was
|
|
79
|
+
developed by a persistent AI engineering team running through Oysterun itself:
|
|
80
|
+
|
|
81
|
+
- two Assistants prepared requirements, verification plans, and progress
|
|
82
|
+
summaries;
|
|
83
|
+
- one Project Manager coordinated tasks and checked progress every two minutes;
|
|
84
|
+
- one Team Lead reviewed architecture, verification evidence, and priorities;
|
|
85
|
+
- three Engineers implemented and tested scoped changes;
|
|
86
|
+
- every 30 minutes, an Assistant summarized team progress for human review.
|
|
87
|
+
|
|
88
|
+
The human Owner made the product, security, UX, and release decisions. Codex
|
|
89
|
+
traced behavior across the Host, web client, Matrix facade, provider adapters,
|
|
90
|
+
skills, and operational scripts; implemented the approved phases; and produced
|
|
91
|
+
focused verification evidence. This workflow let the project continue making
|
|
92
|
+
measurable progress while the Owner worked full-time and while the Oysterun Host
|
|
93
|
+
ran remotely on a Mac mini in Taiwan.
|
|
94
|
+
|
|
95
|
+
## Judge Quickstart
|
|
96
|
+
|
|
97
|
+
### Hosted review environment (recommended)
|
|
98
|
+
|
|
99
|
+
A dedicated Oysterun Host URL and its login password are provided privately in
|
|
100
|
+
the project registration form. Judges should follow the access instructions in
|
|
101
|
+
that form; it is the authoritative source for the current Host address and
|
|
102
|
+
credentials. No local installation or rebuild is required for this path.
|
|
103
|
+
|
|
104
|
+
Available clients:
|
|
105
|
+
|
|
106
|
+
1. **iOS app**
|
|
107
|
+
- Install [Oysterun from the App Store](https://apps.apple.com/tw/app/oysterun/id6762069229).
|
|
108
|
+
- Add the Host URL supplied in the registration form.
|
|
109
|
+
- Sign in with the supplied Host password.
|
|
110
|
+
2. **Web browser**
|
|
111
|
+
- Open the Host `/app/` URL supplied in the registration form.
|
|
112
|
+
- Sign in with the supplied Host password.
|
|
113
|
+
|
|
114
|
+
Both clients connect to the same dedicated Host and expose the same sessions.
|
|
115
|
+
The password is intentionally not stored in this public repository.
|
|
116
|
+
|
|
117
|
+
## What Judges Should Test
|
|
118
|
+
|
|
119
|
+
1. Open the `oysterun-ccstock-workenv-en-da14e` session.
|
|
120
|
+
2. Ask any question, then ask the agent to generate a report.
|
|
121
|
+
3. Open the website URL returned by the agent.
|
|
122
|
+
4. Check the mail box
|
|
123
|
+
5. Ask the agent to create a schedule or send you a Mail item.
|
|
124
|
+
6. Open the Webiste in the external browser
|
|
125
|
+
|
|
126
|
+
## Oysterun Skills
|
|
127
|
+
|
|
128
|
+
The repository includes first-party skills that let Codex operate
|
|
129
|
+
Oysterun through its supported CLI rather than direct Host API calls:
|
|
130
|
+
|
|
131
|
+
- `skills/oysterun-sessions`
|
|
132
|
+
- `skills/oysterun-session-chat`
|
|
133
|
+
- `skills/oysterun-find-context`
|
|
134
|
+
- `skills/oysterun-scheduler`
|
|
135
|
+
- `skills/oysterun-notifications`
|
|
136
|
+
- `skills/oysterun-mail`
|
|
137
|
+
- `skills/oysterun-telegram`
|
|
138
|
+
- `skills/oysterun-website`
|
|
139
|
+
|
|
140
|
+
`skills/Oysterun` is the umbrella skill set used when Oysterun installs or
|
|
141
|
+
updates the product skills in an AgentFolder.
|
|
142
|
+
|
|
143
|
+
------------------------------------OpenAI Build Week------------------------------------
|
|
144
|
+
|
|
145
|
+
## Runtime Pieces
|
|
146
|
+
|
|
3
147
|
Oysterun currently has three main runtime pieces:
|
|
4
148
|
|
|
5
149
|
- `backend/`: the Cloud API written in FastAPI
|
|
@@ -12183,6 +12183,7 @@ Waiting for Claude login output…</pre
|
|
|
12183
12183
|
lastTestRunScheduleId: "",
|
|
12184
12184
|
lastTestRunRunId: "",
|
|
12185
12185
|
lastTestRunOutcome: "",
|
|
12186
|
+
lastTimezoneReconciliationGeneration: 0,
|
|
12186
12187
|
error: "",
|
|
12187
12188
|
status: "",
|
|
12188
12189
|
};
|
|
@@ -13191,6 +13192,8 @@ Waiting for Claude login output…</pre
|
|
|
13191
13192
|
let projectRegistrationIssues = [];
|
|
13192
13193
|
let liveSessions = [];
|
|
13193
13194
|
let sessionHistory = [];
|
|
13195
|
+
const sessionListPreviewBySessionId = new Map();
|
|
13196
|
+
let sessionListPreviewHydrationRequestId = 0;
|
|
13194
13197
|
let matrixTranscriptSessionIdsByAgent = {};
|
|
13195
13198
|
let matrixTranscriptMembershipLoadedAtByAgent = {};
|
|
13196
13199
|
const matrixTranscriptMembershipRequestsByAgent = new Map();
|
|
@@ -25009,6 +25012,7 @@ Waiting for Claude login output…</pre
|
|
|
25009
25012
|
catalog: createDashboardDataRequestSlot(),
|
|
25010
25013
|
sessions: createDashboardDataRequestSlot(),
|
|
25011
25014
|
history: createDashboardDataRequestSlot(),
|
|
25015
|
+
previews: createDashboardDataRequestSlot(),
|
|
25012
25016
|
providers: createDashboardDataRequestSlot(),
|
|
25013
25017
|
};
|
|
25014
25018
|
}
|
|
@@ -25039,13 +25043,28 @@ Waiting for Claude login output…</pre
|
|
|
25039
25043
|
}
|
|
25040
25044
|
|
|
25041
25045
|
function invalidateDashboardDataCaches(opts = {}) {
|
|
25042
|
-
const keys = [
|
|
25046
|
+
const keys = [
|
|
25047
|
+
"catalog",
|
|
25048
|
+
"sessions",
|
|
25049
|
+
"history",
|
|
25050
|
+
"previews",
|
|
25051
|
+
"providers",
|
|
25052
|
+
];
|
|
25043
25053
|
const resetAll = opts.all === true;
|
|
25044
25054
|
for (const key of keys) {
|
|
25045
|
-
if (
|
|
25055
|
+
if (
|
|
25056
|
+
resetAll ||
|
|
25057
|
+
opts[key] === true ||
|
|
25058
|
+
(key === "previews" &&
|
|
25059
|
+
(opts.sessions === true || opts.history === true))
|
|
25060
|
+
) {
|
|
25046
25061
|
resetDashboardDataRequestSlot(dashboardDataRequestState[key]);
|
|
25047
25062
|
}
|
|
25048
25063
|
}
|
|
25064
|
+
if (resetAll) {
|
|
25065
|
+
sessionListPreviewBySessionId.clear();
|
|
25066
|
+
sessionListPreviewHydrationRequestId += 1;
|
|
25067
|
+
}
|
|
25049
25068
|
if (
|
|
25050
25069
|
resetAll ||
|
|
25051
25070
|
opts.transcripts === true ||
|
|
@@ -25138,13 +25157,27 @@ Waiting for Claude login output…</pre
|
|
|
25138
25157
|
}
|
|
25139
25158
|
|
|
25140
25159
|
function readDashboardLiveSessions(opts = {}) {
|
|
25141
|
-
return readDashboardDataRequest(
|
|
25142
|
-
|
|
25143
|
-
|
|
25160
|
+
return readDashboardDataRequest(
|
|
25161
|
+
"sessions",
|
|
25162
|
+
"/sessions?include_previews=0",
|
|
25163
|
+
{
|
|
25164
|
+
force: opts.force === true,
|
|
25165
|
+
}
|
|
25166
|
+
);
|
|
25144
25167
|
}
|
|
25145
25168
|
|
|
25146
25169
|
function readDashboardSessionHistory(opts = {}) {
|
|
25147
|
-
return readDashboardDataRequest(
|
|
25170
|
+
return readDashboardDataRequest(
|
|
25171
|
+
"history",
|
|
25172
|
+
"/sessions/history?include_previews=0",
|
|
25173
|
+
{
|
|
25174
|
+
force: opts.force === true,
|
|
25175
|
+
}
|
|
25176
|
+
);
|
|
25177
|
+
}
|
|
25178
|
+
|
|
25179
|
+
function readDashboardSessionPreviews(opts = {}) {
|
|
25180
|
+
return readDashboardDataRequest("previews", "/sessions/previews", {
|
|
25148
25181
|
force: opts.force === true,
|
|
25149
25182
|
});
|
|
25150
25183
|
}
|
|
@@ -31242,6 +31275,7 @@ Waiting for Claude login output…</pre
|
|
|
31242
31275
|
),
|
|
31243
31276
|
}));
|
|
31244
31277
|
sessionHistory = historyData.sessions || [];
|
|
31278
|
+
pruneSessionListPreviewCache();
|
|
31245
31279
|
explorerState.roots = catalogData.roots || {};
|
|
31246
31280
|
pruneMatrixTranscriptMembershipCache();
|
|
31247
31281
|
const selectedLiveSession = getSelectedLiveSession();
|
|
@@ -31257,6 +31291,7 @@ Waiting for Claude login output…</pre
|
|
|
31257
31291
|
if (keepConnectedSelectedSession) {
|
|
31258
31292
|
renderExplorerRoots();
|
|
31259
31293
|
renderCatalog();
|
|
31294
|
+
void hydrateSessionListPreviews();
|
|
31260
31295
|
renderWebCatalog();
|
|
31261
31296
|
void refreshMailUnreadCount({ quiet: true });
|
|
31262
31297
|
updateComposerAvailability();
|
|
@@ -31270,6 +31305,7 @@ Waiting for Claude login output…</pre
|
|
|
31270
31305
|
}
|
|
31271
31306
|
renderExplorerRoots();
|
|
31272
31307
|
renderCatalog();
|
|
31308
|
+
void hydrateSessionListPreviews();
|
|
31273
31309
|
renderWebCatalog();
|
|
31274
31310
|
void refreshMailUnreadCount({ quiet: true });
|
|
31275
31311
|
const activeSelectedSession = selectedSessionId
|
|
@@ -31516,6 +31552,142 @@ Waiting for Claude login output…</pre
|
|
|
31516
31552
|
return `${providerLabel} · ${modelLabel} · ${folderName}`;
|
|
31517
31553
|
}
|
|
31518
31554
|
|
|
31555
|
+
function getSessionListPreviewState(sessionId) {
|
|
31556
|
+
const normalizedSessionId = sanitizeRouteText(sessionId);
|
|
31557
|
+
return normalizedSessionId
|
|
31558
|
+
? sessionListPreviewBySessionId.get(normalizedSessionId) || null
|
|
31559
|
+
: null;
|
|
31560
|
+
}
|
|
31561
|
+
|
|
31562
|
+
function getSessionListPreviewText({
|
|
31563
|
+
sessionId,
|
|
31564
|
+
lastMessagePreview,
|
|
31565
|
+
runtime,
|
|
31566
|
+
model,
|
|
31567
|
+
folder,
|
|
31568
|
+
}) {
|
|
31569
|
+
const state = getSessionListPreviewState(sessionId);
|
|
31570
|
+
const resolvedPreview =
|
|
31571
|
+
state?.loaded === true
|
|
31572
|
+
? state.lastMessagePreview
|
|
31573
|
+
: lastMessagePreview;
|
|
31574
|
+
if (state?.loaded !== true && !resolvedPreview) {
|
|
31575
|
+
return "Loading latest message...";
|
|
31576
|
+
}
|
|
31577
|
+
return getSessionPreviewText({
|
|
31578
|
+
lastMessagePreview: resolvedPreview,
|
|
31579
|
+
runtime,
|
|
31580
|
+
model,
|
|
31581
|
+
folder,
|
|
31582
|
+
});
|
|
31583
|
+
}
|
|
31584
|
+
|
|
31585
|
+
function updateSessionListPreviewDom() {
|
|
31586
|
+
for (const row of document.querySelectorAll(
|
|
31587
|
+
"[data-live-session-id], [data-history-session-id]"
|
|
31588
|
+
)) {
|
|
31589
|
+
const liveSessionId = sanitizeRouteText(
|
|
31590
|
+
row.getAttribute("data-live-session-id")
|
|
31591
|
+
);
|
|
31592
|
+
const historySessionId = sanitizeRouteText(
|
|
31593
|
+
row.getAttribute("data-history-session-id")
|
|
31594
|
+
);
|
|
31595
|
+
const sessionId = liveSessionId || historySessionId;
|
|
31596
|
+
if (!sessionId) continue;
|
|
31597
|
+
const liveSession = liveSessionId
|
|
31598
|
+
? liveSessions.find((entry) => entry.sessionId === sessionId)
|
|
31599
|
+
: null;
|
|
31600
|
+
const historyRecord = historySessionId
|
|
31601
|
+
? sessionHistory.find((entry) => entry.session_id === sessionId)
|
|
31602
|
+
: null;
|
|
31603
|
+
const source = liveSession || historyRecord;
|
|
31604
|
+
if (!source) continue;
|
|
31605
|
+
const state = getSessionListPreviewState(sessionId);
|
|
31606
|
+
row.dataset.sessionPreviewStatus = state?.status || "loading";
|
|
31607
|
+
const preview = row.querySelector(".session-row-preview");
|
|
31608
|
+
if (!preview) continue;
|
|
31609
|
+
preview.textContent = getSessionListPreviewText({
|
|
31610
|
+
sessionId,
|
|
31611
|
+
lastMessagePreview:
|
|
31612
|
+
liveSession?.lastMessagePreview ||
|
|
31613
|
+
historyRecord?.last_message_preview ||
|
|
31614
|
+
"",
|
|
31615
|
+
runtime: source.provider || source.runtime || "claude",
|
|
31616
|
+
model: source.model || "default model",
|
|
31617
|
+
folder: source.cwd || source.agent_folder || "",
|
|
31618
|
+
});
|
|
31619
|
+
}
|
|
31620
|
+
}
|
|
31621
|
+
|
|
31622
|
+
function pruneSessionListPreviewCache() {
|
|
31623
|
+
const activeSessionIds = new Set([
|
|
31624
|
+
...liveSessions.map((entry) => entry.sessionId),
|
|
31625
|
+
...sessionHistory.map((entry) => entry.session_id),
|
|
31626
|
+
]);
|
|
31627
|
+
for (const sessionId of sessionListPreviewBySessionId.keys()) {
|
|
31628
|
+
if (!activeSessionIds.has(sessionId)) {
|
|
31629
|
+
sessionListPreviewBySessionId.delete(sessionId);
|
|
31630
|
+
}
|
|
31631
|
+
}
|
|
31632
|
+
}
|
|
31633
|
+
|
|
31634
|
+
async function hydrateSessionListPreviews(opts = {}) {
|
|
31635
|
+
if (!liveSessions.length && !sessionHistory.length) return;
|
|
31636
|
+
const requestId = ++sessionListPreviewHydrationRequestId;
|
|
31637
|
+
try {
|
|
31638
|
+
const data = await readDashboardSessionPreviews({
|
|
31639
|
+
force: opts.force === true,
|
|
31640
|
+
});
|
|
31641
|
+
if (requestId !== sessionListPreviewHydrationRequestId) return;
|
|
31642
|
+
for (const entry of Array.isArray(data.previews)
|
|
31643
|
+
? data.previews
|
|
31644
|
+
: []) {
|
|
31645
|
+
const sessionId = sanitizeRouteText(entry.session_id);
|
|
31646
|
+
if (!sessionId) continue;
|
|
31647
|
+
sessionListPreviewBySessionId.set(sessionId, {
|
|
31648
|
+
loaded: true,
|
|
31649
|
+
status: sanitizeRouteText(entry.status) || "unavailable",
|
|
31650
|
+
lastMessagePreview:
|
|
31651
|
+
typeof entry.last_message_preview === "string"
|
|
31652
|
+
? entry.last_message_preview
|
|
31653
|
+
: "",
|
|
31654
|
+
latestCommittedSeq: Number(entry.latest_committed_seq) || 0,
|
|
31655
|
+
cacheStatus: sanitizeRouteText(entry.cache_status),
|
|
31656
|
+
errorCode: sanitizeRouteText(entry.error_code),
|
|
31657
|
+
});
|
|
31658
|
+
}
|
|
31659
|
+
updateSessionListPreviewDom();
|
|
31660
|
+
} catch (err) {
|
|
31661
|
+
if (requestId !== sessionListPreviewHydrationRequestId) return;
|
|
31662
|
+
for (const session of liveSessions) {
|
|
31663
|
+
if (!sessionListPreviewBySessionId.has(session.sessionId)) {
|
|
31664
|
+
sessionListPreviewBySessionId.set(session.sessionId, {
|
|
31665
|
+
loaded: true,
|
|
31666
|
+
status: "unavailable",
|
|
31667
|
+
lastMessagePreview: "",
|
|
31668
|
+
latestCommittedSeq: 0,
|
|
31669
|
+
cacheStatus: "request_failed",
|
|
31670
|
+
errorCode: "session_preview_request_failed",
|
|
31671
|
+
});
|
|
31672
|
+
}
|
|
31673
|
+
}
|
|
31674
|
+
for (const record of sessionHistory) {
|
|
31675
|
+
if (!sessionListPreviewBySessionId.has(record.session_id)) {
|
|
31676
|
+
sessionListPreviewBySessionId.set(record.session_id, {
|
|
31677
|
+
loaded: true,
|
|
31678
|
+
status: "unavailable",
|
|
31679
|
+
lastMessagePreview: "",
|
|
31680
|
+
latestCommittedSeq: 0,
|
|
31681
|
+
cacheStatus: "request_failed",
|
|
31682
|
+
errorCode: "session_preview_request_failed",
|
|
31683
|
+
});
|
|
31684
|
+
}
|
|
31685
|
+
}
|
|
31686
|
+
updateSessionListPreviewDom();
|
|
31687
|
+
console.warn("[oysterun-ui] Session preview hydration failed", err);
|
|
31688
|
+
}
|
|
31689
|
+
}
|
|
31690
|
+
|
|
31519
31691
|
function renderSessionAvatar(runtime, isActive = false) {
|
|
31520
31692
|
const key = getSessionRuntimeVisualKey(runtime);
|
|
31521
31693
|
return `
|
|
@@ -31883,7 +32055,9 @@ Waiting for Claude login output…</pre
|
|
|
31883
32055
|
const lastTouched = formatSessionRelativeTime(
|
|
31884
32056
|
session.lastActiveAt || session.startedAt
|
|
31885
32057
|
);
|
|
31886
|
-
const
|
|
32058
|
+
const previewState = getSessionListPreviewState(session.sessionId);
|
|
32059
|
+
const previewText = getSessionListPreviewText({
|
|
32060
|
+
sessionId: session.sessionId,
|
|
31887
32061
|
lastMessagePreview: session.lastMessagePreview,
|
|
31888
32062
|
runtime,
|
|
31889
32063
|
model,
|
|
@@ -31895,6 +32069,9 @@ Waiting for Claude login output…</pre
|
|
|
31895
32069
|
class="agent-entry-card session-list-row session-list-row-live"
|
|
31896
32070
|
data-live-session-id="${esc(session.sessionId)}"
|
|
31897
32071
|
data-agent-id="${esc(agentId)}"
|
|
32072
|
+
data-session-preview-status="${esc(
|
|
32073
|
+
previewState?.status || "loading"
|
|
32074
|
+
)}"
|
|
31898
32075
|
>
|
|
31899
32076
|
<button
|
|
31900
32077
|
class="session-row-main"
|
|
@@ -31926,7 +32103,9 @@ Waiting for Claude login output…</pre
|
|
|
31926
32103
|
const lastTouched = formatSessionRelativeTime(
|
|
31927
32104
|
record.last_active_at || record.created_at
|
|
31928
32105
|
);
|
|
31929
|
-
const
|
|
32106
|
+
const previewState = getSessionListPreviewState(record.session_id);
|
|
32107
|
+
const previewText = getSessionListPreviewText({
|
|
32108
|
+
sessionId: record.session_id,
|
|
31930
32109
|
lastMessagePreview: record.last_message_preview,
|
|
31931
32110
|
runtime,
|
|
31932
32111
|
model,
|
|
@@ -31937,6 +32116,9 @@ Waiting for Claude login output…</pre
|
|
|
31937
32116
|
class="agent-entry-card session-list-row session-list-row-history"
|
|
31938
32117
|
data-history-session-id="${esc(record.session_id)}"
|
|
31939
32118
|
data-agent-id="${esc(record.agent_id)}"
|
|
32119
|
+
data-session-preview-status="${esc(
|
|
32120
|
+
previewState?.status || "loading"
|
|
32121
|
+
)}"
|
|
31940
32122
|
>
|
|
31941
32123
|
<button
|
|
31942
32124
|
class="session-row-main"
|
|
@@ -41468,6 +41650,23 @@ Waiting for Claude login output…</pre
|
|
|
41468
41650
|
: "/scheduler/schedules";
|
|
41469
41651
|
const data = await api("GET", schedulerPath);
|
|
41470
41652
|
const rows = Array.isArray(data.schedules) ? data.schedules : [];
|
|
41653
|
+
const timezoneReconciliation =
|
|
41654
|
+
data.timezone_reconciliation &&
|
|
41655
|
+
typeof data.timezone_reconciliation === "object"
|
|
41656
|
+
? data.timezone_reconciliation
|
|
41657
|
+
: null;
|
|
41658
|
+
const timezoneReconciliationGeneration = Number(
|
|
41659
|
+
timezoneReconciliation?.project_index_generation || 0
|
|
41660
|
+
);
|
|
41661
|
+
const timezoneCorrectionCount = Number(
|
|
41662
|
+
timezoneReconciliation?.timezone_correction_count || 0
|
|
41663
|
+
);
|
|
41664
|
+
const showTimezoneCorrection =
|
|
41665
|
+
timezoneCorrectionCount > 0 &&
|
|
41666
|
+
Number.isInteger(timezoneReconciliationGeneration) &&
|
|
41667
|
+
timezoneReconciliationGeneration > 0 &&
|
|
41668
|
+
timezoneReconciliationGeneration !==
|
|
41669
|
+
hostSchedulerState.lastTimezoneReconciliationGeneration;
|
|
41471
41670
|
const requestedId = sanitizeRouteText(opts.scheduleId);
|
|
41472
41671
|
const shouldOpenSetup =
|
|
41473
41672
|
opts.newDraft === true ||
|
|
@@ -41487,6 +41686,10 @@ Waiting for Claude login output…</pre
|
|
|
41487
41686
|
: [],
|
|
41488
41687
|
loaded: true,
|
|
41489
41688
|
loading: false,
|
|
41689
|
+
lastTimezoneReconciliationGeneration:
|
|
41690
|
+
timezoneReconciliationGeneration > 0
|
|
41691
|
+
? timezoneReconciliationGeneration
|
|
41692
|
+
: hostSchedulerState.lastTimezoneReconciliationGeneration,
|
|
41490
41693
|
selectedId,
|
|
41491
41694
|
editingId: shouldOpenSetup
|
|
41492
41695
|
? opts.newDraft === true
|
|
@@ -41501,6 +41704,11 @@ Waiting for Claude login output…</pre
|
|
|
41501
41704
|
: hostSchedulerState.setupPageMode || "edit"
|
|
41502
41705
|
: "list",
|
|
41503
41706
|
error: "",
|
|
41707
|
+
status: showTimezoneCorrection
|
|
41708
|
+
? `Normalized ${timezoneCorrectionCount} portable schedule timezone${
|
|
41709
|
+
timezoneCorrectionCount === 1 ? "" : "s"
|
|
41710
|
+
} to this Host.`
|
|
41711
|
+
: "",
|
|
41504
41712
|
};
|
|
41505
41713
|
} catch (err) {
|
|
41506
41714
|
hostSchedulerState = {
|
|
@@ -41528,6 +41736,12 @@ Waiting for Claude login output…</pre
|
|
|
41528
41736
|
{}
|
|
41529
41737
|
);
|
|
41530
41738
|
const rows = Array.isArray(data.schedules) ? data.schedules : [];
|
|
41739
|
+
const timezoneCorrectionCount = Number(
|
|
41740
|
+
data.timezone_correction_count || 0
|
|
41741
|
+
);
|
|
41742
|
+
const timezoneReconciliationGeneration = Number(
|
|
41743
|
+
data.timezone_normalization?.project_index_generation || 0
|
|
41744
|
+
);
|
|
41531
41745
|
hostSchedulerState = {
|
|
41532
41746
|
...hostSchedulerState,
|
|
41533
41747
|
rows,
|
|
@@ -41539,12 +41753,25 @@ Waiting for Claude login output…</pre
|
|
|
41539
41753
|
loaded: true,
|
|
41540
41754
|
refreshing: false,
|
|
41541
41755
|
loading: false,
|
|
41756
|
+
lastTimezoneReconciliationGeneration:
|
|
41757
|
+
timezoneReconciliationGeneration > 0
|
|
41758
|
+
? timezoneReconciliationGeneration
|
|
41759
|
+
: hostSchedulerState.lastTimezoneReconciliationGeneration,
|
|
41542
41760
|
error: "",
|
|
41543
|
-
status:
|
|
41544
|
-
|
|
41545
|
-
|
|
41546
|
-
|
|
41547
|
-
|
|
41761
|
+
status:
|
|
41762
|
+
timezoneCorrectionCount > 0
|
|
41763
|
+
? `Refreshed ${Number(
|
|
41764
|
+
data.project_count || 0
|
|
41765
|
+
)} Browser Root project${
|
|
41766
|
+
Number(data.project_count || 0) === 1 ? "" : "s"
|
|
41767
|
+
}. Normalized ${timezoneCorrectionCount} portable schedule timezone${
|
|
41768
|
+
timezoneCorrectionCount === 1 ? "" : "s"
|
|
41769
|
+
} to this Host.`
|
|
41770
|
+
: `Refreshed ${Number(
|
|
41771
|
+
data.project_count || 0
|
|
41772
|
+
)} Browser Root project${
|
|
41773
|
+
Number(data.project_count || 0) === 1 ? "" : "s"
|
|
41774
|
+
}.`,
|
|
41548
41775
|
};
|
|
41549
41776
|
} catch (err) {
|
|
41550
41777
|
hostSchedulerState = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{g as ee,c as Y,r as K,j as Z}from"./index-
|
|
1
|
+
import{g as ee,c as Y,r as K,j as Z}from"./index-CqfVnL4A.js";var X={exports:{}};(function(e){var t=typeof window<"u"?window:typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?self:{};/**
|
|
2
2
|
* Prism: Lightweight, robust, elegant syntax highlighting
|
|
3
3
|
*
|
|
4
4
|
* @license MIT <https://opensource.org/licenses/MIT>
|