codex-agent-view 0.4.4 → 0.4.6
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/.codex-plugin/plugin.json +4 -4
- package/README.ko.md +15 -12
- package/README.md +16 -13
- package/package.json +2 -2
- package/public/app.js +265 -129
- package/public/index.html +14 -12
- package/public/styles.css +106 -1
- package/scripts/send-hook.mjs +10 -3
- package/skills/codex-agent-view/SKILL.md +46 -14
- package/skills/show-agents/SKILL.md +11 -1
- package/src/core/index.mjs +0 -1
- package/src/core/monitor-store.mjs +250 -18
- package/src/core/normalize-hook-payload.mjs +91 -0
package/public/app.js
CHANGED
|
@@ -4,87 +4,107 @@ const SESSION_TOKEN_KEY = "codex-agent-view-access-token";
|
|
|
4
4
|
const EXCLUDED_SESSION_KEY = "codex-agent-view-excluded-session";
|
|
5
5
|
const LANGUAGE_KEY = "codex-agent-view-language";
|
|
6
6
|
const SUPPORTED_LANGUAGES = new Set(["en", "ko", "es"]);
|
|
7
|
-
const KNOWN_STATUSES = new Set([
|
|
7
|
+
const KNOWN_STATUSES = new Set([
|
|
8
|
+
"running",
|
|
9
|
+
"waiting",
|
|
10
|
+
"completed",
|
|
11
|
+
"completion_not_observed",
|
|
12
|
+
"stale",
|
|
13
|
+
"interrupted",
|
|
14
|
+
"unknown",
|
|
15
|
+
]);
|
|
8
16
|
const VIEWER_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/;
|
|
9
17
|
const CANONICAL_SESSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
10
18
|
|
|
11
19
|
const MESSAGES = Object.freeze({
|
|
12
20
|
en: Object.freeze({
|
|
13
|
-
metaDescription: "
|
|
21
|
+
metaDescription: "A clear, live view of Codex work and the agents moving it forward.",
|
|
14
22
|
skipToContent: "Skip to content",
|
|
15
23
|
brandHome: "Codex Agent View home",
|
|
16
|
-
brandSubtitle: "
|
|
24
|
+
brandSubtitle: "Live work overview",
|
|
17
25
|
languageLabel: "Language",
|
|
18
26
|
connectionConnecting: "Connecting to local status",
|
|
19
27
|
connectionConnected: "Local monitor connected",
|
|
20
28
|
connectionRetrying: "Disconnected · retrying",
|
|
21
29
|
authenticationRequired: "Live view authentication required",
|
|
22
|
-
heroEyebrow: "
|
|
30
|
+
heroEyebrow: "LIVE CODEX WORK",
|
|
23
31
|
heroTitle: "See active work at a glance",
|
|
24
|
-
heroCopy: "
|
|
32
|
+
heroCopy: "See what Codex is working on, which agents are involved, and how each part is progressing—all in one place.",
|
|
25
33
|
freshnessAria: "Refresh information",
|
|
26
34
|
lastUpdatedLabel: "Last updated",
|
|
27
35
|
notYet: "Not yet",
|
|
28
36
|
refreshIntervalLabel: "Refresh interval",
|
|
29
37
|
twoSeconds: "2 seconds",
|
|
30
38
|
metricsAria: "Task status summary",
|
|
31
|
-
parentTasks: "
|
|
39
|
+
parentTasks: "Work items",
|
|
32
40
|
currentlyObserved: "Currently observed",
|
|
33
|
-
runningAgents: "
|
|
41
|
+
runningAgents: "Active agents",
|
|
34
42
|
workingNow: "Working now",
|
|
35
43
|
waitingStatus: "Waiting",
|
|
36
44
|
waitingExplanation: "Waiting for input or the next step",
|
|
37
|
-
completedAgents: "Completed
|
|
45
|
+
completedAgents: "Completed agents",
|
|
38
46
|
currentView: "In the current view",
|
|
39
47
|
liveWork: "LIVE WORK",
|
|
40
|
-
sessionsHeading: "
|
|
48
|
+
sessionsHeading: "Work and participating agents",
|
|
41
49
|
loadingState: "Loading status.",
|
|
42
|
-
toolbarAria: "Filter automatically observed
|
|
50
|
+
toolbarAria: "Filter automatically observed work and participating agents",
|
|
43
51
|
searchLabel: "Filter list (optional)",
|
|
44
|
-
searchPlaceholder: "Find
|
|
52
|
+
searchPlaceholder: "Find work or an agent",
|
|
45
53
|
statusFilterLabel: "Status filter (optional)",
|
|
46
54
|
statusAll: "All statuses",
|
|
47
55
|
statusRunning: "Running",
|
|
48
56
|
statusWaiting: "Waiting",
|
|
49
57
|
statusCompleted: "Completed",
|
|
58
|
+
statusCompletionNotObserved: "End not confirmed",
|
|
59
|
+
statusStale: "Stale · end not confirmed",
|
|
60
|
+
statusInterrupted: "Interrupted",
|
|
50
61
|
statusUnknown: "Unknown",
|
|
62
|
+
completionNotObservedExplanation: "No end signal was received for this item, so completion cannot be confirmed.",
|
|
63
|
+
staleExplanation: "This status is out of date and no end signal was received. Completion cannot be confirmed.",
|
|
64
|
+
interruptedExplanation: "This activity was still open when the work ended; its own completion signal was not observed.",
|
|
51
65
|
connectingCopy: "Connecting to the Codex app's local status.",
|
|
52
|
-
sessionListAria: "Codex
|
|
53
|
-
privacyPrompt: "This view
|
|
66
|
+
sessionListAria: "Codex work list",
|
|
67
|
+
privacyPrompt: "This view shows only a shortened request summary; it never displays the full request or tool inputs.",
|
|
54
68
|
privacyLocal: "Data is read only from the local monitor on this device.",
|
|
55
69
|
timeUnknown: "Time unavailable",
|
|
56
70
|
startedUnknown: "Start time unavailable",
|
|
57
71
|
noReceivedActivity: "No activity received",
|
|
58
|
-
parentTask: "
|
|
72
|
+
parentTask: "WORK",
|
|
59
73
|
projectUnknown: "Project unavailable",
|
|
74
|
+
taskSummary: "Request",
|
|
75
|
+
taskSummaryUnavailable: "A short request summary is not available yet.",
|
|
60
76
|
recentActivity: "Recent activity",
|
|
61
77
|
recent: "Recent",
|
|
62
|
-
subagentsCount: "
|
|
63
|
-
subagentName: "
|
|
78
|
+
subagentsCount: "Participating agents · {count}",
|
|
79
|
+
subagentName: "Agent {ordinal}",
|
|
64
80
|
agentProfile: "Role/profile · {profile}",
|
|
65
|
-
agentProfileNote: "
|
|
66
|
-
noSubagents: "No
|
|
81
|
+
agentProfileNote: "Codex currently provides each agent's role, but not its full assignment description.",
|
|
82
|
+
noSubagents: "No participating agents have been observed for this work item.",
|
|
67
83
|
noRecentActivity: "No recent activity to display.",
|
|
68
84
|
technicalInfo: "Technical information",
|
|
69
|
-
sessionId: "Session ID",
|
|
70
85
|
agentId: "Agent ID",
|
|
71
86
|
rawProfile: "Raw role/profile",
|
|
72
87
|
rawEvent: "Raw event",
|
|
73
88
|
rawTool: "Raw tool",
|
|
74
|
-
retry: "
|
|
89
|
+
retry: "Retry connection",
|
|
90
|
+
retryAuthentication: "Try this tab again",
|
|
91
|
+
checkAuthentication: "Check authentication again",
|
|
92
|
+
recoveryTitle: "Open a newly authenticated view",
|
|
93
|
+
recoveryStep: "In the Codex app, select @codex-agent-view in the composer, then choose the actual $show-agents skill from the skill picker.",
|
|
94
|
+
recoveryNote: "The skill opens a new live view with fresh authentication. No terminal command or external browser is needed.",
|
|
75
95
|
resultsFiltered: "Showing {visible} of {total}",
|
|
76
|
-
resultsTotal: "{count}
|
|
96
|
+
resultsTotal: "{count} work items",
|
|
77
97
|
searchEmptyTitle: "No matching results.",
|
|
78
98
|
searchEmptyCopy: "Try changing the search term or status filter.",
|
|
79
|
-
emptyWithDiagnosticsTitle: "No
|
|
80
|
-
emptyWithDiagnosticsCopy: "The local monitor received {count} activity records but could not apply them to displayable
|
|
99
|
+
emptyWithDiagnosticsTitle: "No work can be displayed.",
|
|
100
|
+
emptyWithDiagnosticsCopy: "The local monitor received {count} activity records but could not apply them to displayable work items.",
|
|
81
101
|
emptyTitle: "No task activity has been received in this observation window.",
|
|
82
|
-
emptyCopy: "The local monitor is connected. This result alone does not mean that Codex has no
|
|
102
|
+
emptyCopy: "The local monitor is connected. This result alone does not mean that Codex has no active work or participating agents.",
|
|
83
103
|
emptyGuidanceTitle: "If work does not appear",
|
|
84
104
|
automaticTracking: "You do not need to enter or register task IDs. Activity from trusted hooks is added automatically.",
|
|
85
105
|
emptyStep1: "After installing the plugin, fully restart the official Codex app.",
|
|
86
106
|
emptyStep2: "In a new task, review and explicitly trust the Codex Agent View hook command.",
|
|
87
|
-
emptyStep3: "After trusting it, start
|
|
107
|
+
emptyStep3: "After trusting it, start new work and run agents. New activity is added automatically.",
|
|
88
108
|
observationBoundary: "Observation starts with the first trusted hook event. Earlier activity and activity missed while local collection was stopped cannot be replayed; restarting collection opens a new observation window.",
|
|
89
109
|
diagnosticsCount: "Validation information · {count}",
|
|
90
110
|
diagnosticOccurrences: "{count} occurrences",
|
|
@@ -92,8 +112,8 @@ const MESSAGES = Object.freeze({
|
|
|
92
112
|
authTitle: "This live view cannot be authenticated.",
|
|
93
113
|
retryWithState: "Reconnecting automatically every 2 seconds while keeping the last good state visible.",
|
|
94
114
|
retryWithoutState: "Reconnecting automatically every 2 seconds. You can leave this view open in the Codex app.",
|
|
95
|
-
missingToken: "This tab
|
|
96
|
-
expiredToken: "This live
|
|
115
|
+
missingToken: "This tab does not have the authentication needed to display live work.",
|
|
116
|
+
expiredToken: "This tab's live-view authentication was rejected or is no longer valid.",
|
|
97
117
|
requestFailed: "Status request failed ({status})",
|
|
98
118
|
unknownConnectionError: "An unknown connection error occurred.",
|
|
99
119
|
offline: "This device is offline.",
|
|
@@ -107,25 +127,25 @@ const MESSAGES = Object.freeze({
|
|
|
107
127
|
nameUnknown: "Unknown name",
|
|
108
128
|
activityUnknown: "Unknown",
|
|
109
129
|
approvalRequest: "{tool} approval requested",
|
|
110
|
-
agentStarted: "
|
|
111
|
-
agentStopped: "
|
|
130
|
+
agentStarted: "Agent {ordinal} started",
|
|
131
|
+
agentStopped: "Agent {ordinal} completed",
|
|
112
132
|
activitySessionStarted: "Observation started",
|
|
113
133
|
activitySessionEnded: "Observation ended",
|
|
114
|
-
activityTurnStarted: "
|
|
115
|
-
activityTurnStopped: "
|
|
116
|
-
activitySubagentStarted: "
|
|
117
|
-
activitySubagentStopped: "
|
|
134
|
+
activityTurnStarted: "Work started",
|
|
135
|
+
activityTurnStopped: "Work response completed",
|
|
136
|
+
activitySubagentStarted: "Agent started",
|
|
137
|
+
activitySubagentStopped: "Agent completed",
|
|
118
138
|
activityToolStarted: "Tool activity",
|
|
119
139
|
activityToolCompleted: "Tool activity",
|
|
120
140
|
activityPermissionRequested: "User approval requested",
|
|
121
141
|
toolApplyPatch: "File edit",
|
|
122
142
|
toolBash: "Terminal activity",
|
|
123
|
-
toolFollowup: "
|
|
124
|
-
toolInterrupt: "
|
|
125
|
-
toolList: "
|
|
126
|
-
toolMessage: "Message sent to
|
|
127
|
-
toolSpawn: "
|
|
128
|
-
toolWaitAgent: "Waiting for
|
|
143
|
+
toolFollowup: "Agent follow-up requested",
|
|
144
|
+
toolInterrupt: "Agent interruption requested",
|
|
145
|
+
toolList: "Agent status checked",
|
|
146
|
+
toolMessage: "Message sent to agent",
|
|
147
|
+
toolSpawn: "Agent started",
|
|
148
|
+
toolWaitAgent: "Waiting for agent",
|
|
129
149
|
toolExec: "Terminal activity",
|
|
130
150
|
toolUserInput: "User input requested",
|
|
131
151
|
toolWait: "Waiting for completion",
|
|
@@ -137,25 +157,25 @@ const MESSAGES = Object.freeze({
|
|
|
137
157
|
roleUnknown: "Not reported",
|
|
138
158
|
}),
|
|
139
159
|
ko: Object.freeze({
|
|
140
|
-
metaDescription: "
|
|
160
|
+
metaDescription: "Codex가 수행 중인 작업과 참여 에이전트의 진행 상황을 한눈에 확인합니다.",
|
|
141
161
|
skipToContent: "본문으로 건너뛰기",
|
|
142
162
|
brandHome: "Codex Agent View 홈",
|
|
143
|
-
brandSubtitle: "
|
|
163
|
+
brandSubtitle: "실시간 작업 현황",
|
|
144
164
|
languageLabel: "언어",
|
|
145
165
|
connectionConnecting: "로컬 상태 연결 중",
|
|
146
166
|
connectionConnected: "로컬 모니터 연결됨",
|
|
147
167
|
connectionRetrying: "연결 끊김 · 재시도 중",
|
|
148
168
|
authenticationRequired: "실시간 화면 인증 필요",
|
|
149
|
-
heroEyebrow: "
|
|
169
|
+
heroEyebrow: "CODEX 작업 현황",
|
|
150
170
|
heroTitle: "작업 흐름을 한눈에",
|
|
151
|
-
heroCopy: "
|
|
171
|
+
heroCopy: "Codex가 어떤 요청을 처리하고 있는지, 어떤 에이전트가 참여하는지, 각 단계가 어디까지 왔는지 한 화면에서 확인하세요.",
|
|
152
172
|
freshnessAria: "상태 갱신 정보",
|
|
153
173
|
lastUpdatedLabel: "마지막 갱신",
|
|
154
174
|
notYet: "아직 없음",
|
|
155
175
|
refreshIntervalLabel: "갱신 주기",
|
|
156
176
|
twoSeconds: "2초",
|
|
157
177
|
metricsAria: "작업 상태 요약",
|
|
158
|
-
parentTasks: "
|
|
178
|
+
parentTasks: "작업",
|
|
159
179
|
currentlyObserved: "현재 관찰 중",
|
|
160
180
|
runningAgents: "실행 중 에이전트",
|
|
161
181
|
workingNow: "작업 수행 중",
|
|
@@ -164,54 +184,66 @@ const MESSAGES = Object.freeze({
|
|
|
164
184
|
completedAgents: "완료 에이전트",
|
|
165
185
|
currentView: "현재 화면 기준",
|
|
166
186
|
liveWork: "실시간 작업",
|
|
167
|
-
sessionsHeading: "
|
|
187
|
+
sessionsHeading: "작업과 참여 에이전트",
|
|
168
188
|
loadingState: "상태를 불러오는 중입니다.",
|
|
169
|
-
toolbarAria: "자동 수신된
|
|
189
|
+
toolbarAria: "자동 수신된 작업과 참여 에이전트 목록 필터",
|
|
170
190
|
searchLabel: "목록 필터 (선택)",
|
|
171
|
-
searchPlaceholder: "
|
|
191
|
+
searchPlaceholder: "작업 또는 에이전트 찾기",
|
|
172
192
|
statusFilterLabel: "상태 필터 (선택)",
|
|
173
193
|
statusAll: "모든 상태",
|
|
174
194
|
statusRunning: "실행 중",
|
|
175
195
|
statusWaiting: "대기",
|
|
176
196
|
statusCompleted: "완료",
|
|
197
|
+
statusCompletionNotObserved: "종료 확인 안 됨",
|
|
198
|
+
statusStale: "오래된 상태 · 종료 확인 안 됨",
|
|
199
|
+
statusInterrupted: "중단됨",
|
|
177
200
|
statusUnknown: "알 수 없음",
|
|
201
|
+
completionNotObservedExplanation: "이 항목의 종료 신호를 받지 못해 완료 여부를 확정할 수 없습니다.",
|
|
202
|
+
staleExplanation: "상태 정보가 오래되었고 종료 신호를 받지 못했습니다. 완료 여부를 확정할 수 없습니다.",
|
|
203
|
+
interruptedExplanation: "전체 작업이 끝날 때 이 활동이 열린 상태였습니다. 이 활동 자체의 완료 신호는 확인되지 않았습니다.",
|
|
178
204
|
connectingCopy: "Codex 앱의 로컬 상태에 연결하고 있습니다.",
|
|
179
|
-
sessionListAria: "Codex
|
|
180
|
-
privacyPrompt: "이 화면은
|
|
205
|
+
sessionListAria: "Codex 작업 목록",
|
|
206
|
+
privacyPrompt: "이 화면은 짧게 줄인 요청 요약만 표시하며, 전체 요청이나 도구 입력은 표시하지 않습니다.",
|
|
181
207
|
privacyLocal: "데이터는 이 기기의 로컬 모니터에서만 읽습니다.",
|
|
182
208
|
timeUnknown: "시간 정보 없음",
|
|
183
209
|
startedUnknown: "시작 시간 없음",
|
|
184
210
|
noReceivedActivity: "수신된 활동 없음",
|
|
185
|
-
parentTask: "
|
|
211
|
+
parentTask: "작업",
|
|
186
212
|
projectUnknown: "프로젝트 정보 없음",
|
|
213
|
+
taskSummary: "요청 내용",
|
|
214
|
+
taskSummaryUnavailable: "요청 내용을 요약할 수 있는 정보가 아직 없습니다.",
|
|
187
215
|
recentActivity: "최근 활동",
|
|
188
216
|
recent: "최근",
|
|
189
|
-
subagentsCount: "
|
|
190
|
-
subagentName: "
|
|
217
|
+
subagentsCount: "참여 에이전트 · {count}",
|
|
218
|
+
subagentName: "에이전트 {ordinal}",
|
|
191
219
|
agentProfile: "역할/프로필 · {profile}",
|
|
192
|
-
agentProfileNote: "
|
|
193
|
-
noSubagents: "이
|
|
220
|
+
agentProfileNote: "Codex는 현재 각 에이전트의 역할을 제공하지만, 구체적인 할당 내용 전체는 제공하지 않습니다.",
|
|
221
|
+
noSubagents: "이 작업에 참여한 에이전트가 아직 관찰되지 않았습니다.",
|
|
194
222
|
noRecentActivity: "표시할 최근 활동이 없습니다.",
|
|
195
223
|
technicalInfo: "기술 정보",
|
|
196
|
-
sessionId: "세션 ID",
|
|
197
224
|
agentId: "에이전트 ID",
|
|
198
225
|
rawProfile: "원본 역할/프로필",
|
|
199
226
|
rawEvent: "원본 이벤트",
|
|
200
227
|
rawTool: "원본 도구",
|
|
201
|
-
retry: "다시
|
|
228
|
+
retry: "연결 다시 시도",
|
|
229
|
+
retryAuthentication: "이 탭에서 다시 시도",
|
|
230
|
+
checkAuthentication: "인증 정보 다시 확인",
|
|
231
|
+
recoveryTitle: "새 인증 화면 열기",
|
|
232
|
+
recoveryStep: "Codex 앱 입력창에서 @codex-agent-view를 선택한 다음, 스킬 선택기에서 실제 $show-agents 스킬을 선택하세요.",
|
|
233
|
+
recoveryNote: "새 인증이 적용된 실시간 화면이 열립니다. 터미널 명령이나 외부 브라우저는 필요하지 않습니다.",
|
|
202
234
|
resultsFiltered: "전체 {total}개 중 {visible}개 표시",
|
|
203
|
-
resultsTotal: "{count}개
|
|
235
|
+
resultsTotal: "작업 {count}개",
|
|
204
236
|
searchEmptyTitle: "검색 결과가 없습니다.",
|
|
205
237
|
searchEmptyCopy: "검색어나 상태 필터를 바꿔 보세요.",
|
|
206
|
-
emptyWithDiagnosticsTitle: "표시 가능한
|
|
207
|
-
emptyWithDiagnosticsCopy: "로컬 모니터가 활동 정보 {count}건을 받았지만 표시 가능한
|
|
238
|
+
emptyWithDiagnosticsTitle: "표시 가능한 작업이 없습니다.",
|
|
239
|
+
emptyWithDiagnosticsCopy: "로컬 모니터가 활동 정보 {count}건을 받았지만 표시 가능한 작업으로 적용하지 못했습니다.",
|
|
208
240
|
emptyTitle: "이 관찰 화면에서 수신된 작업 활동이 없습니다.",
|
|
209
|
-
emptyCopy: "로컬 모니터 연결은 정상입니다. 이 결과만으로 Codex에
|
|
241
|
+
emptyCopy: "로컬 모니터 연결은 정상입니다. 이 결과만으로 Codex에 진행 중인 작업이나 참여 에이전트가 없다고 판단할 수 없습니다.",
|
|
210
242
|
emptyGuidanceTitle: "표시되지 않을 때 확인 순서",
|
|
211
243
|
automaticTracking: "작업 ID를 입력하거나 작업별로 등록할 필요가 없습니다. 신뢰한 hook의 작업 활동이 이 목록에 자동으로 추가됩니다.",
|
|
212
244
|
emptyStep1: "플러그인을 설치한 뒤 공식 Codex 앱을 완전히 재시작했는지 확인합니다.",
|
|
213
245
|
emptyStep2: "새 작업에서 표시되는 Codex Agent View hook 명령을 검토하고 직접 신뢰합니다.",
|
|
214
|
-
emptyStep3: "신뢰 설정 후 새 작업을 시작해
|
|
246
|
+
emptyStep3: "신뢰 설정 후 새 작업을 시작해 에이전트를 실행합니다. 새 활동은 이 목록에 자동으로 추가됩니다.",
|
|
215
247
|
observationBoundary: "관찰 화면은 첫 번째로 신뢰한 hook을 받은 시점부터 시작합니다. 그 전에 이미 지나간 활동과 로컬 상태 수집이 중단된 동안의 활동은 재생되지 않으며, 수집이 다시 시작되면 새 관찰 화면이 열립니다.",
|
|
216
248
|
diagnosticsCount: "검증 정보 · {count}건",
|
|
217
249
|
diagnosticOccurrences: "{count}건",
|
|
@@ -219,8 +251,8 @@ const MESSAGES = Object.freeze({
|
|
|
219
251
|
authTitle: "이 실시간 화면을 인증할 수 없습니다.",
|
|
220
252
|
retryWithState: "2초마다 자동으로 다시 연결합니다. 마지막 정상 상태를 계속 표시합니다.",
|
|
221
253
|
retryWithoutState: "2초마다 자동으로 다시 연결합니다. Codex 앱에서 이 화면을 그대로 두어도 됩니다.",
|
|
222
|
-
missingToken: "이 탭에는
|
|
223
|
-
expiredToken: "이 실시간
|
|
254
|
+
missingToken: "이 탭에는 실시간 작업을 표시하는 데 필요한 인증 정보가 없습니다.",
|
|
255
|
+
expiredToken: "이 탭의 실시간 화면 인증이 거부되었거나 더 이상 유효하지 않습니다.",
|
|
224
256
|
requestFailed: "상태 요청 실패 ({status})",
|
|
225
257
|
unknownConnectionError: "알 수 없는 연결 오류가 발생했습니다.",
|
|
226
258
|
offline: "이 기기가 오프라인입니다.",
|
|
@@ -234,14 +266,14 @@ const MESSAGES = Object.freeze({
|
|
|
234
266
|
nameUnknown: "이름 미상",
|
|
235
267
|
activityUnknown: "알 수 없음",
|
|
236
268
|
approvalRequest: "{tool} 승인 요청",
|
|
237
|
-
agentStarted: "
|
|
238
|
-
agentStopped: "
|
|
269
|
+
agentStarted: "에이전트 {ordinal} 시작",
|
|
270
|
+
agentStopped: "에이전트 {ordinal} 완료",
|
|
239
271
|
activitySessionStarted: "관찰 시작",
|
|
240
272
|
activitySessionEnded: "관찰 종료",
|
|
241
|
-
activityTurnStarted: "
|
|
242
|
-
activityTurnStopped: "
|
|
243
|
-
activitySubagentStarted: "
|
|
244
|
-
activitySubagentStopped: "
|
|
273
|
+
activityTurnStarted: "작업 시작",
|
|
274
|
+
activityTurnStopped: "작업 응답 완료",
|
|
275
|
+
activitySubagentStarted: "에이전트 시작",
|
|
276
|
+
activitySubagentStopped: "에이전트 완료",
|
|
245
277
|
activityToolStarted: "도구 작업",
|
|
246
278
|
activityToolCompleted: "도구 작업",
|
|
247
279
|
activityPermissionRequested: "사용자 승인 요청",
|
|
@@ -251,7 +283,7 @@ const MESSAGES = Object.freeze({
|
|
|
251
283
|
toolInterrupt: "에이전트 작업 중단 요청",
|
|
252
284
|
toolList: "에이전트 상태 확인",
|
|
253
285
|
toolMessage: "에이전트에게 메시지 전달",
|
|
254
|
-
toolSpawn: "
|
|
286
|
+
toolSpawn: "에이전트 시작",
|
|
255
287
|
toolWaitAgent: "에이전트 응답 대기",
|
|
256
288
|
toolExec: "터미널 작업",
|
|
257
289
|
toolUserInput: "사용자 입력 요청",
|
|
@@ -264,81 +296,93 @@ const MESSAGES = Object.freeze({
|
|
|
264
296
|
roleUnknown: "보고되지 않음",
|
|
265
297
|
}),
|
|
266
298
|
es: Object.freeze({
|
|
267
|
-
metaDescription: "
|
|
299
|
+
metaDescription: "Una vista clara del trabajo de Codex y de los agentes que lo hacen avanzar.",
|
|
268
300
|
skipToContent: "Saltar al contenido",
|
|
269
301
|
brandHome: "Inicio de Codex Agent View",
|
|
270
|
-
brandSubtitle: "
|
|
302
|
+
brandSubtitle: "Resumen del trabajo en vivo",
|
|
271
303
|
languageLabel: "Idioma",
|
|
272
304
|
connectionConnecting: "Conectando al estado local",
|
|
273
305
|
connectionConnected: "Monitor local conectado",
|
|
274
306
|
connectionRetrying: "Desconectado · reintentando",
|
|
275
307
|
authenticationRequired: "Se requiere autenticar la vista",
|
|
276
|
-
heroEyebrow: "
|
|
308
|
+
heroEyebrow: "TRABAJO ACTIVO EN CODEX",
|
|
277
309
|
heroTitle: "Observa el trabajo activo de un vistazo",
|
|
278
|
-
heroCopy: "
|
|
310
|
+
heroCopy: "Consulta qué está haciendo Codex, qué agentes participan y cómo avanza cada parte, todo en un solo lugar.",
|
|
279
311
|
freshnessAria: "Información de actualización",
|
|
280
312
|
lastUpdatedLabel: "Última actualización",
|
|
281
313
|
notYet: "Aún no",
|
|
282
314
|
refreshIntervalLabel: "Intervalo de actualización",
|
|
283
315
|
twoSeconds: "2 segundos",
|
|
284
316
|
metricsAria: "Resumen del estado de las tareas",
|
|
285
|
-
parentTasks: "
|
|
317
|
+
parentTasks: "Trabajos",
|
|
286
318
|
currentlyObserved: "En observación",
|
|
287
|
-
runningAgents: "
|
|
319
|
+
runningAgents: "Agentes activos",
|
|
288
320
|
workingNow: "Trabajando ahora",
|
|
289
321
|
waitingStatus: "En espera",
|
|
290
322
|
waitingExplanation: "Esperando una respuesta o el siguiente paso",
|
|
291
|
-
completedAgents: "
|
|
323
|
+
completedAgents: "Agentes que terminaron",
|
|
292
324
|
currentView: "En la vista actual",
|
|
293
325
|
liveWork: "TRABAJO EN VIVO",
|
|
294
|
-
sessionsHeading: "
|
|
326
|
+
sessionsHeading: "Trabajos y agentes participantes",
|
|
295
327
|
loadingState: "Cargando el estado.",
|
|
296
|
-
toolbarAria: "Filtrar
|
|
328
|
+
toolbarAria: "Filtrar trabajos y agentes participantes observados automáticamente",
|
|
297
329
|
searchLabel: "Filtrar lista (opcional)",
|
|
298
|
-
searchPlaceholder: "Buscar
|
|
330
|
+
searchPlaceholder: "Buscar un trabajo o agente",
|
|
299
331
|
statusFilterLabel: "Filtrar por estado (opcional)",
|
|
300
332
|
statusAll: "Todos los estados",
|
|
301
333
|
statusRunning: "En ejecución",
|
|
302
334
|
statusWaiting: "En espera",
|
|
303
335
|
statusCompleted: "Completado",
|
|
336
|
+
statusCompletionNotObserved: "Fin no confirmado",
|
|
337
|
+
statusStale: "Estado desactualizado · fin no confirmado",
|
|
338
|
+
statusInterrupted: "Interrumpido",
|
|
304
339
|
statusUnknown: "Desconocido",
|
|
340
|
+
completionNotObservedExplanation: "No se recibió una señal de fin para este elemento, por lo que no se puede confirmar que haya terminado.",
|
|
341
|
+
staleExplanation: "El estado está desactualizado y no se recibió una señal de fin. No se puede confirmar que haya terminado.",
|
|
342
|
+
interruptedExplanation: "Esta actividad seguía abierta cuando terminó el trabajo; no se observó su propia señal de finalización.",
|
|
305
343
|
connectingCopy: "Conectando al estado local de la aplicación Codex.",
|
|
306
|
-
sessionListAria: "Lista de
|
|
307
|
-
privacyPrompt: "Esta vista
|
|
344
|
+
sessionListAria: "Lista de trabajos de Codex",
|
|
345
|
+
privacyPrompt: "Esta vista solo muestra un resumen abreviado de la solicitud; nunca muestra la solicitud completa ni las entradas de herramientas.",
|
|
308
346
|
privacyLocal: "Los datos se leen únicamente del monitor local de este dispositivo.",
|
|
309
347
|
timeUnknown: "Hora no disponible",
|
|
310
348
|
startedUnknown: "Hora de inicio no disponible",
|
|
311
349
|
noReceivedActivity: "No se recibió actividad",
|
|
312
|
-
parentTask: "
|
|
350
|
+
parentTask: "TRABAJO",
|
|
313
351
|
projectUnknown: "Proyecto no disponible",
|
|
352
|
+
taskSummary: "Solicitud",
|
|
353
|
+
taskSummaryUnavailable: "Todavía no hay información para resumir esta solicitud.",
|
|
314
354
|
recentActivity: "Actividad reciente",
|
|
315
355
|
recent: "Reciente",
|
|
316
|
-
subagentsCount: "
|
|
317
|
-
subagentName: "
|
|
356
|
+
subagentsCount: "Agentes participantes · {count}",
|
|
357
|
+
subagentName: "Agente {ordinal}",
|
|
318
358
|
agentProfile: "Rol/perfil · {profile}",
|
|
319
|
-
agentProfileNote: "
|
|
320
|
-
noSubagents: "
|
|
359
|
+
agentProfileNote: "Codex proporciona el rol de cada agente, pero no la descripción completa de su asignación.",
|
|
360
|
+
noSubagents: "Todavía no se observaron agentes participantes en este trabajo.",
|
|
321
361
|
noRecentActivity: "No hay actividad reciente que mostrar.",
|
|
322
362
|
technicalInfo: "Información técnica",
|
|
323
|
-
sessionId: "ID de sesión",
|
|
324
363
|
agentId: "ID del agente",
|
|
325
364
|
rawProfile: "Rol/perfil original",
|
|
326
365
|
rawEvent: "Evento original",
|
|
327
366
|
rawTool: "Herramienta original",
|
|
328
|
-
retry: "
|
|
367
|
+
retry: "Reintentar conexión",
|
|
368
|
+
retryAuthentication: "Reintentar en esta pestaña",
|
|
369
|
+
checkAuthentication: "Volver a comprobar la autenticación",
|
|
370
|
+
recoveryTitle: "Abrir una vista con autenticación nueva",
|
|
371
|
+
recoveryStep: "En el cuadro de texto de Codex, selecciona @codex-agent-view y luego elige la skill real $show-agents en el selector de skills.",
|
|
372
|
+
recoveryNote: "La skill abre una vista en vivo nueva con autenticación actualizada. No necesitas la terminal ni un navegador externo.",
|
|
329
373
|
resultsFiltered: "Mostrando {visible} de {total}",
|
|
330
|
-
resultsTotal: "{count}
|
|
374
|
+
resultsTotal: "{count} trabajos",
|
|
331
375
|
searchEmptyTitle: "No hay resultados.",
|
|
332
376
|
searchEmptyCopy: "Prueba otra búsqueda o filtro de estado.",
|
|
333
|
-
emptyWithDiagnosticsTitle: "No hay
|
|
334
|
-
emptyWithDiagnosticsCopy: "El monitor local recibió {count} registros de actividad, pero no pudo aplicarlos a
|
|
377
|
+
emptyWithDiagnosticsTitle: "No hay trabajos que mostrar.",
|
|
378
|
+
emptyWithDiagnosticsCopy: "El monitor local recibió {count} registros de actividad, pero no pudo aplicarlos a trabajos visibles.",
|
|
335
379
|
emptyTitle: "No se recibió actividad en esta ventana de observación.",
|
|
336
|
-
emptyCopy: "El monitor local está conectado. Este resultado no implica por sí solo que Codex no tenga
|
|
380
|
+
emptyCopy: "El monitor local está conectado. Este resultado no implica por sí solo que Codex no tenga trabajos o agentes activos.",
|
|
337
381
|
emptyGuidanceTitle: "Si el trabajo no aparece",
|
|
338
382
|
automaticTracking: "No es necesario introducir ni registrar IDs de tareas. La actividad de hooks confiables se añade automáticamente.",
|
|
339
383
|
emptyStep1: "Tras instalar el plugin, reinicia por completo la aplicación oficial de Codex.",
|
|
340
384
|
emptyStep2: "En una tarea nueva, revisa y autoriza explícitamente el comando hook de Codex Agent View.",
|
|
341
|
-
emptyStep3: "Después, inicia
|
|
385
|
+
emptyStep3: "Después, inicia un trabajo nuevo y ejecuta agentes. La actividad se añadirá automáticamente.",
|
|
342
386
|
observationBoundary: "La observación comienza con el primer evento de un hook autorizado. La actividad anterior o perdida mientras la recopilación local estuvo detenida no se puede reproducir; al reiniciarla se abre una ventana nueva.",
|
|
343
387
|
diagnosticsCount: "Información de validación · {count}",
|
|
344
388
|
diagnosticOccurrences: "{count} apariciones",
|
|
@@ -346,8 +390,8 @@ const MESSAGES = Object.freeze({
|
|
|
346
390
|
authTitle: "No se puede autenticar esta vista en vivo.",
|
|
347
391
|
retryWithState: "Se reconecta automáticamente cada 2 segundos y mantiene visible el último estado válido.",
|
|
348
392
|
retryWithoutState: "Se reconecta automáticamente cada 2 segundos. Puedes dejar esta vista abierta en Codex.",
|
|
349
|
-
missingToken: "Esta pestaña no tiene
|
|
350
|
-
expiredToken: "La
|
|
393
|
+
missingToken: "Esta pestaña no tiene la autenticación necesaria para mostrar el trabajo en vivo.",
|
|
394
|
+
expiredToken: "La autenticación de esta pestaña fue rechazada o ya no es válida.",
|
|
351
395
|
requestFailed: "Falló la solicitud de estado ({status})",
|
|
352
396
|
unknownConnectionError: "Se produjo un error de conexión desconocido.",
|
|
353
397
|
offline: "Este dispositivo está sin conexión.",
|
|
@@ -361,25 +405,25 @@ const MESSAGES = Object.freeze({
|
|
|
361
405
|
nameUnknown: "Nombre desconocido",
|
|
362
406
|
activityUnknown: "Desconocida",
|
|
363
407
|
approvalRequest: "Se solicitó aprobación para {tool}",
|
|
364
|
-
agentStarted: "
|
|
365
|
-
agentStopped: "
|
|
408
|
+
agentStarted: "Agente {ordinal} iniciado",
|
|
409
|
+
agentStopped: "Agente {ordinal} completado",
|
|
366
410
|
activitySessionStarted: "Observación iniciada",
|
|
367
411
|
activitySessionEnded: "Observación finalizada",
|
|
368
|
-
activityTurnStarted: "
|
|
369
|
-
activityTurnStopped: "Respuesta
|
|
370
|
-
activitySubagentStarted: "
|
|
371
|
-
activitySubagentStopped: "
|
|
412
|
+
activityTurnStarted: "Trabajo iniciado",
|
|
413
|
+
activityTurnStopped: "Respuesta del trabajo completada",
|
|
414
|
+
activitySubagentStarted: "Agente iniciado",
|
|
415
|
+
activitySubagentStopped: "Agente completado",
|
|
372
416
|
activityToolStarted: "Actividad de herramienta",
|
|
373
417
|
activityToolCompleted: "Actividad de herramienta",
|
|
374
418
|
activityPermissionRequested: "Se solicitó aprobación",
|
|
375
419
|
toolApplyPatch: "Edición de archivo",
|
|
376
420
|
toolBash: "Actividad de terminal",
|
|
377
|
-
toolFollowup: "Seguimiento del
|
|
378
|
-
toolInterrupt: "Interrupción del
|
|
379
|
-
toolList: "Estado de
|
|
380
|
-
toolMessage: "Mensaje enviado al
|
|
381
|
-
toolSpawn: "
|
|
382
|
-
toolWaitAgent: "Esperando al
|
|
421
|
+
toolFollowup: "Seguimiento del agente solicitado",
|
|
422
|
+
toolInterrupt: "Interrupción del agente solicitada",
|
|
423
|
+
toolList: "Estado de agentes consultado",
|
|
424
|
+
toolMessage: "Mensaje enviado al agente",
|
|
425
|
+
toolSpawn: "Agente iniciado",
|
|
426
|
+
toolWaitAgent: "Esperando al agente",
|
|
383
427
|
toolExec: "Actividad de terminal",
|
|
384
428
|
toolUserInput: "Se solicitó entrada del usuario",
|
|
385
429
|
toolWait: "Esperando finalización",
|
|
@@ -396,14 +440,26 @@ const STATUS_KEYS = Object.freeze({
|
|
|
396
440
|
running: "statusRunning",
|
|
397
441
|
waiting: "statusWaiting",
|
|
398
442
|
completed: "statusCompleted",
|
|
443
|
+
completion_not_observed: "statusCompletionNotObserved",
|
|
444
|
+
stale: "statusStale",
|
|
445
|
+
interrupted: "statusInterrupted",
|
|
399
446
|
unknown: "statusUnknown",
|
|
400
447
|
});
|
|
401
448
|
|
|
402
449
|
const STATUS_ORDER = Object.freeze({
|
|
403
450
|
running: 0,
|
|
404
451
|
waiting: 1,
|
|
405
|
-
|
|
406
|
-
|
|
452
|
+
completion_not_observed: 2,
|
|
453
|
+
stale: 2,
|
|
454
|
+
interrupted: 3,
|
|
455
|
+
unknown: 4,
|
|
456
|
+
completed: 5,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const STATUS_EXPLANATION_KEYS = Object.freeze({
|
|
460
|
+
completion_not_observed: "completionNotObservedExplanation",
|
|
461
|
+
stale: "staleExplanation",
|
|
462
|
+
interrupted: "interruptedExplanation",
|
|
407
463
|
});
|
|
408
464
|
|
|
409
465
|
const ACTIVITY_KEYS = Object.freeze({
|
|
@@ -522,7 +578,7 @@ function consumeLiveContext() {
|
|
|
522
578
|
};
|
|
523
579
|
}
|
|
524
580
|
|
|
525
|
-
|
|
581
|
+
let { accessToken, excludedSessionId } = consumeLiveContext();
|
|
526
582
|
|
|
527
583
|
const elements = Object.freeze({
|
|
528
584
|
connectionStatus: document.querySelector("#connection-status"),
|
|
@@ -675,6 +731,9 @@ function normalizeCoreStatus(value) {
|
|
|
675
731
|
) {
|
|
676
732
|
return "completed";
|
|
677
733
|
}
|
|
734
|
+
if (value === "completion_not_observed" || value === "stale" || value === "interrupted") {
|
|
735
|
+
return value;
|
|
736
|
+
}
|
|
678
737
|
return normalizeStatus(value);
|
|
679
738
|
}
|
|
680
739
|
|
|
@@ -765,13 +824,13 @@ function normalizeDiagnostic(value) {
|
|
|
765
824
|
}
|
|
766
825
|
|
|
767
826
|
function deriveSessionStatus(session, agents, recentActivities) {
|
|
768
|
-
if (session.permission?.status === "waiting_for_user") {
|
|
769
|
-
return "waiting";
|
|
770
|
-
}
|
|
771
827
|
const reportedStatus = normalizeCoreStatus(session.status);
|
|
772
|
-
if (reportedStatus
|
|
828
|
+
if (reportedStatus !== "unknown") {
|
|
773
829
|
return reportedStatus;
|
|
774
830
|
}
|
|
831
|
+
if (session.permission?.status === "waiting_for_user") {
|
|
832
|
+
return "waiting";
|
|
833
|
+
}
|
|
775
834
|
if (
|
|
776
835
|
agents.some((agent) => agent.status === "running") ||
|
|
777
836
|
recentActivities[0]?.status === "running"
|
|
@@ -801,6 +860,7 @@ function normalizeSession(value, index) {
|
|
|
801
860
|
return {
|
|
802
861
|
sessionId: safeString(session.session_id, `unknown-session-${index + 1}`),
|
|
803
862
|
workspaceLabel: safeString(session.workspace_label, ""),
|
|
863
|
+
taskSummary: safeString(session.task_summary, ""),
|
|
804
864
|
status: deriveSessionStatus(session, agents, recentActivities),
|
|
805
865
|
lastActivityAtMs: safeTimestamp(session.last_seen_at_ms),
|
|
806
866
|
agents,
|
|
@@ -905,12 +965,24 @@ function createStatusBadge(status) {
|
|
|
905
965
|
dot.setAttribute("aria-hidden", "true");
|
|
906
966
|
|
|
907
967
|
const label = document.createElement("span");
|
|
908
|
-
label.textContent = t(STATUS_KEYS[status]);
|
|
968
|
+
label.textContent = t(STATUS_KEYS[status] ?? "statusUnknown");
|
|
909
969
|
|
|
910
970
|
badge.append(dot, label);
|
|
911
971
|
return badge;
|
|
912
972
|
}
|
|
913
973
|
|
|
974
|
+
function createStatusExplanation(status) {
|
|
975
|
+
const messageKey = STATUS_EXPLANATION_KEYS[status];
|
|
976
|
+
if (!messageKey) {
|
|
977
|
+
return null;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
const explanation = document.createElement("p");
|
|
981
|
+
explanation.className = "status-explanation";
|
|
982
|
+
explanation.textContent = t(messageKey);
|
|
983
|
+
return explanation;
|
|
984
|
+
}
|
|
985
|
+
|
|
914
986
|
function createTime(timestampMs, prefix) {
|
|
915
987
|
const wrapper = document.createElement("span");
|
|
916
988
|
wrapper.className = "time-label";
|
|
@@ -987,10 +1059,16 @@ function createAgentItem(agent) {
|
|
|
987
1059
|
document.createTextNode(` · ${formatDuration(agent.startedAtMs, agent.stoppedAtMs)}`),
|
|
988
1060
|
);
|
|
989
1061
|
|
|
1062
|
+
const statusExplanation = createStatusExplanation(agent.status);
|
|
1063
|
+
|
|
990
1064
|
const technicalRows = [[t("agentId"), agent.agentId]];
|
|
991
1065
|
technicalRows.push([t("rawProfile"), agent.agentType]);
|
|
992
1066
|
|
|
993
|
-
item.append(heading, metadata
|
|
1067
|
+
item.append(heading, metadata);
|
|
1068
|
+
if (statusExplanation) {
|
|
1069
|
+
item.append(statusExplanation);
|
|
1070
|
+
}
|
|
1071
|
+
item.append(createTechnicalInfo(technicalRows));
|
|
994
1072
|
return item;
|
|
995
1073
|
}
|
|
996
1074
|
|
|
@@ -1047,11 +1125,14 @@ function createSessionCard(session) {
|
|
|
1047
1125
|
eyebrow.textContent = t("parentTask");
|
|
1048
1126
|
const title = document.createElement("h3");
|
|
1049
1127
|
title.textContent = session.workspaceLabel || t("projectUnknown");
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
);
|
|
1128
|
+
const taskSummary = document.createElement("p");
|
|
1129
|
+
taskSummary.className = "task-summary";
|
|
1130
|
+
const taskSummaryLabel = document.createElement("strong");
|
|
1131
|
+
taskSummaryLabel.textContent = `${t("taskSummary")} · `;
|
|
1132
|
+
const taskSummaryCopy = document.createElement("span");
|
|
1133
|
+
taskSummaryCopy.textContent = session.taskSummary || t("taskSummaryUnavailable");
|
|
1134
|
+
taskSummary.append(taskSummaryLabel, taskSummaryCopy);
|
|
1135
|
+
identity.append(eyebrow, title, taskSummary);
|
|
1055
1136
|
|
|
1056
1137
|
const sessionState = document.createElement("div");
|
|
1057
1138
|
sessionState.className = "session-state";
|
|
@@ -1059,6 +1140,10 @@ function createSessionCard(session) {
|
|
|
1059
1140
|
createStatusBadge(session.status),
|
|
1060
1141
|
createTime(session.lastActivityAtMs, t("recentActivity")),
|
|
1061
1142
|
);
|
|
1143
|
+
const statusExplanation = createStatusExplanation(session.status);
|
|
1144
|
+
if (statusExplanation) {
|
|
1145
|
+
sessionState.append(statusExplanation);
|
|
1146
|
+
}
|
|
1062
1147
|
|
|
1063
1148
|
cardHeader.append(identity, sessionState);
|
|
1064
1149
|
|
|
@@ -1116,6 +1201,7 @@ function sessionMatchesQuery(session, query) {
|
|
|
1116
1201
|
const searchableValues = [
|
|
1117
1202
|
session.sessionId,
|
|
1118
1203
|
session.workspaceLabel,
|
|
1204
|
+
session.taskSummary,
|
|
1119
1205
|
session.status,
|
|
1120
1206
|
...session.agents.flatMap((agent) => [
|
|
1121
1207
|
agent.agentId,
|
|
@@ -1133,10 +1219,15 @@ function sessionMatchesQuery(session, query) {
|
|
|
1133
1219
|
}
|
|
1134
1220
|
|
|
1135
1221
|
function sessionMatchesStatus(session, status) {
|
|
1222
|
+
const matchesStatus = (candidate) => (
|
|
1223
|
+
candidate === status ||
|
|
1224
|
+
(status === "completion_not_observed" && candidate === "stale")
|
|
1225
|
+
);
|
|
1136
1226
|
return (
|
|
1137
1227
|
status === "all" ||
|
|
1138
|
-
session.status
|
|
1139
|
-
session.agents.some((agent) => agent.status
|
|
1228
|
+
matchesStatus(session.status) ||
|
|
1229
|
+
session.agents.some((agent) => matchesStatus(agent.status)) ||
|
|
1230
|
+
session.recentActivities.some((activity) => matchesStatus(activity.status))
|
|
1140
1231
|
);
|
|
1141
1232
|
}
|
|
1142
1233
|
|
|
@@ -1171,7 +1262,7 @@ function renderMetrics() {
|
|
|
1171
1262
|
: formatDateTime(viewState.updatedAtMs);
|
|
1172
1263
|
}
|
|
1173
1264
|
|
|
1174
|
-
function setStateMessage(kind, title, description,
|
|
1265
|
+
function setStateMessage(kind, title, description, retryMode = "") {
|
|
1175
1266
|
elements.stateMessage.className = `state-message state-${kind}`;
|
|
1176
1267
|
elements.stateMessage.replaceChildren();
|
|
1177
1268
|
|
|
@@ -1181,16 +1272,61 @@ function setStateMessage(kind, title, description, includeRetry = false) {
|
|
|
1181
1272
|
copy.textContent = description;
|
|
1182
1273
|
elements.stateMessage.append(heading, copy);
|
|
1183
1274
|
|
|
1184
|
-
if (
|
|
1275
|
+
if (retryMode === "authentication") {
|
|
1276
|
+
const recovery = document.createElement("div");
|
|
1277
|
+
recovery.className = "recovery-guidance";
|
|
1278
|
+
|
|
1279
|
+
const recoveryTitle = document.createElement("strong");
|
|
1280
|
+
recoveryTitle.textContent = t("recoveryTitle");
|
|
1281
|
+
const recoveryStep = document.createElement("p");
|
|
1282
|
+
recoveryStep.textContent = t("recoveryStep");
|
|
1283
|
+
const recoveryNote = document.createElement("p");
|
|
1284
|
+
recoveryNote.className = "recovery-note";
|
|
1285
|
+
recoveryNote.textContent = t("recoveryNote");
|
|
1286
|
+
recovery.append(recoveryTitle, recoveryStep, recoveryNote);
|
|
1287
|
+
elements.stateMessage.append(recovery);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
if (retryMode) {
|
|
1185
1291
|
const retry = document.createElement("button");
|
|
1186
1292
|
retry.type = "button";
|
|
1187
1293
|
retry.className = "retry-button";
|
|
1188
|
-
retry.textContent =
|
|
1189
|
-
|
|
1294
|
+
retry.textContent = retryMode === "authentication"
|
|
1295
|
+
? (accessToken ? t("retryAuthentication") : t("checkAuthentication"))
|
|
1296
|
+
: t("retry");
|
|
1297
|
+
retry.addEventListener(
|
|
1298
|
+
"click",
|
|
1299
|
+
retryMode === "authentication" ? retryAuthentication : refreshState,
|
|
1300
|
+
);
|
|
1190
1301
|
elements.stateMessage.append(retry);
|
|
1191
1302
|
}
|
|
1192
1303
|
}
|
|
1193
1304
|
|
|
1305
|
+
function retryAuthentication() {
|
|
1306
|
+
const refreshedContext = consumeLiveContext();
|
|
1307
|
+
accessToken = refreshedContext.accessToken;
|
|
1308
|
+
excludedSessionId = refreshedContext.excludedSessionId;
|
|
1309
|
+
|
|
1310
|
+
if (!accessToken) {
|
|
1311
|
+
viewState.hasLoaded = true;
|
|
1312
|
+
viewState.canRetry = false;
|
|
1313
|
+
viewState.authenticationFailed = true;
|
|
1314
|
+
viewState.errorKey = "missingToken";
|
|
1315
|
+
viewState.errorMessage = t(viewState.errorKey);
|
|
1316
|
+
setConnectionStatus("error", t("authenticationRequired"));
|
|
1317
|
+
render();
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
viewState.authenticationFailed = false;
|
|
1322
|
+
viewState.canRetry = true;
|
|
1323
|
+
viewState.errorKey = "";
|
|
1324
|
+
viewState.errorMessage = "";
|
|
1325
|
+
setConnectionStatus("connecting");
|
|
1326
|
+
render();
|
|
1327
|
+
void refreshState();
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1194
1330
|
function setEmptyObservationMessage() {
|
|
1195
1331
|
elements.stateMessage.className = "state-message state-empty state-empty-observation";
|
|
1196
1332
|
elements.stateMessage.replaceChildren();
|
|
@@ -1290,7 +1426,7 @@ function renderSessions() {
|
|
|
1290
1426
|
? t("disconnectedTitle")
|
|
1291
1427
|
: t("authTitle"),
|
|
1292
1428
|
description,
|
|
1293
|
-
viewState.canRetry,
|
|
1429
|
+
viewState.canRetry ? "connection" : "authentication",
|
|
1294
1430
|
);
|
|
1295
1431
|
return;
|
|
1296
1432
|
}
|