cligr 1.0.7 → 1.0.8
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/.claude/worktrees/agent-ac25cfb2/.claude/settings.local.json +30 -0
- package/.claude/worktrees/agent-ac25cfb2/README.md +65 -0
- package/.claude/worktrees/agent-ac25cfb2/docs/plans/2026-02-13-named-params-support.md +391 -0
- package/.claude/worktrees/agent-ac25cfb2/docs/plans/2026-02-25-named-items-design.md +164 -0
- package/.claude/worktrees/agent-ac25cfb2/docs/plans/2026-02-25-named-items-implementation.md +460 -0
- package/.claude/worktrees/agent-ac25cfb2/package-lock.json +554 -0
- package/.claude/worktrees/agent-ac25cfb2/package.json +27 -0
- package/.claude/worktrees/agent-ac25cfb2/scripts/build.js +20 -0
- package/.claude/worktrees/agent-ac25cfb2/scripts/test.js +168 -0
- package/.claude/worktrees/agent-ac25cfb2/src/commands/config.ts +121 -0
- package/.claude/worktrees/agent-ac25cfb2/src/commands/groups.ts +68 -0
- package/.claude/worktrees/agent-ac25cfb2/src/commands/ls.ts +25 -0
- package/.claude/worktrees/agent-ac25cfb2/src/commands/up.ts +49 -0
- package/.claude/worktrees/agent-ac25cfb2/src/config/loader.ts +148 -0
- package/.claude/worktrees/agent-ac25cfb2/src/config/types.ts +26 -0
- package/.claude/worktrees/agent-ac25cfb2/src/index.ts +97 -0
- package/.claude/worktrees/agent-ac25cfb2/src/process/manager.ts +270 -0
- package/.claude/worktrees/agent-ac25cfb2/src/process/pid-store.ts +203 -0
- package/.claude/worktrees/agent-ac25cfb2/src/process/template.ts +87 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/blocking-processes-fixed.test.ts +255 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/blocking-processes.test.ts +497 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/commands.test.ts +648 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/config-loader.test.ts +426 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/process-manager.test.ts +394 -0
- package/.claude/worktrees/agent-ac25cfb2/tests/integration/template-expander.test.ts +454 -0
- package/.claude/worktrees/agent-ac25cfb2/tsconfig.json +15 -0
- package/.claude/worktrees/agent-ac25cfb2/usage.md +9 -0
- package/dist/index.js +82 -25
- package/docs/superpowers/plans/2026-04-13-improve-web-ui-console.md +256 -0
- package/docs/superpowers/specs/2026-04-13-improve-web-ui-console-design.md +38 -0
- package/package.json +1 -1
- package/src/commands/serve.ts +64 -7
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Improve Web UI Console Logging Implementation Plan
|
|
2
|
+
|
|
3
|
+
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
+
|
|
5
|
+
**Goal:** Enhance the web UI console panel in `cligr serve` with timestamps, system event logging, color-coded output, and a clear button.
|
|
6
|
+
|
|
7
|
+
**Architecture:** Modify the embedded HTML/CSS/JS inside `src/commands/serve.ts`'s `serveHtml()` function. All changes are client-side: timestamps are generated in `appendLog`, system events are rendered when `status` SSE events arrive, and a clear button empties the log container.
|
|
8
|
+
|
|
9
|
+
**Tech Stack:** TypeScript, vanilla HTML/CSS/JS embedded in a string.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
### Task 1: Add console header layout and clear button
|
|
14
|
+
|
|
15
|
+
**Files:**
|
|
16
|
+
- Modify: `src/commands/serve.ts:232-234`
|
|
17
|
+
|
|
18
|
+
- [ ] **Step 1: Update `.main h2` CSS to support a flex header with button**
|
|
19
|
+
|
|
20
|
+
Replace:
|
|
21
|
+
```css
|
|
22
|
+
.main h2 { font-size: 1rem; margin: 0; padding: 0.5rem 1rem; border-bottom: 1px solid #ccc; background: #f0f0f0; }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
With:
|
|
26
|
+
```css
|
|
27
|
+
.main-header { display: flex; align-items: center; justify-content: space-between; font-size: 1rem; margin: 0; padding: 0.5rem 1rem; border-bottom: 1px solid #ccc; background: #f0f0f0; }
|
|
28
|
+
.main-header h2 { font-size: 1rem; margin: 0; }
|
|
29
|
+
.clear-btn { font-size: 0.8rem; padding: 0.25rem 0.6rem; cursor: pointer; }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- [ ] **Step 2: Replace the `<h2>Console</h2>` markup with the new header**
|
|
33
|
+
|
|
34
|
+
Replace:
|
|
35
|
+
```html
|
|
36
|
+
<h2>Console</h2>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
With:
|
|
40
|
+
```html
|
|
41
|
+
<div class="main-header">
|
|
42
|
+
<h2>Console</h2>
|
|
43
|
+
<button class="clear-btn" id="clearBtn">Clear</button>
|
|
44
|
+
</div>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- [ ] **Step 3: Add clear button click handler in the script section**
|
|
48
|
+
|
|
49
|
+
Add after:
|
|
50
|
+
```javascript
|
|
51
|
+
const groupsEl = document.getElementById('groups');
|
|
52
|
+
const logsEl = document.getElementById('logs');
|
|
53
|
+
const resizer = document.getElementById('resizer');
|
|
54
|
+
let autoScroll = true;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const clearBtn = document.getElementById('clearBtn');
|
|
59
|
+
clearBtn.addEventListener('click', () => {
|
|
60
|
+
logsEl.innerHTML = '';
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
- [ ] **Step 4: Typecheck**
|
|
65
|
+
|
|
66
|
+
Run: `npm run typecheck`
|
|
67
|
+
Expected: No errors.
|
|
68
|
+
|
|
69
|
+
- [ ] **Step 5: Commit**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git add src/commands/serve.ts
|
|
73
|
+
git commit -m "feat(serve): add clear button to console header"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
### Task 2: Add timestamp and color-coded log styling
|
|
79
|
+
|
|
80
|
+
**Files:**
|
|
81
|
+
- Modify: `src/commands/serve.ts:238-239` and `src/commands/serve.ts:336-342`
|
|
82
|
+
|
|
83
|
+
- [ ] **Step 1: Add CSS classes for log styling**
|
|
84
|
+
|
|
85
|
+
Replace:
|
|
86
|
+
```css
|
|
87
|
+
.logs { flex: 1; background: #111; color: #0f0; font-family: monospace; font-size: 0.85rem; overflow-y: auto; padding: 0.75rem; white-space: pre-wrap; }
|
|
88
|
+
.error { color: #f55; }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
With:
|
|
92
|
+
```css
|
|
93
|
+
.logs { flex: 1; background: #111; color: #0f0; font-family: monospace; font-size: 0.85rem; overflow-y: auto; padding: 0.75rem; white-space: pre-wrap; }
|
|
94
|
+
.log-line { margin: 0.1rem 0; }
|
|
95
|
+
.log-time { color: #888; }
|
|
96
|
+
.log-system { color: #6cf; }
|
|
97
|
+
.log-error { color: #f55; }
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- [ ] **Step 2: Rewrite `appendLog` to include timestamps and structured styling**
|
|
101
|
+
|
|
102
|
+
Replace:
|
|
103
|
+
```javascript
|
|
104
|
+
function appendLog(line, isError) {
|
|
105
|
+
const span = document.createElement('div');
|
|
106
|
+
span.textContent = line;
|
|
107
|
+
if (isError) span.className = 'error';
|
|
108
|
+
logsEl.appendChild(span);
|
|
109
|
+
if (autoScroll) logsEl.scrollTop = logsEl.scrollHeight;
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
With:
|
|
114
|
+
```javascript
|
|
115
|
+
function appendLog(line, isError) {
|
|
116
|
+
const div = document.createElement('div');
|
|
117
|
+
div.className = 'log-line';
|
|
118
|
+
|
|
119
|
+
const time = document.createElement('span');
|
|
120
|
+
time.className = 'log-time';
|
|
121
|
+
const now = new Date();
|
|
122
|
+
const hh = String(now.getHours()).padStart(2, '0');
|
|
123
|
+
const mm = String(now.getMinutes()).padStart(2, '0');
|
|
124
|
+
const ss = String(now.getSeconds()).padStart(2, '0');
|
|
125
|
+
time.textContent = `[${hh}:${mm}:${ss}] `;
|
|
126
|
+
div.appendChild(time);
|
|
127
|
+
|
|
128
|
+
const content = document.createElement('span');
|
|
129
|
+
content.textContent = line;
|
|
130
|
+
if (isError) content.className = 'log-error';
|
|
131
|
+
div.appendChild(content);
|
|
132
|
+
|
|
133
|
+
logsEl.appendChild(div);
|
|
134
|
+
if (autoScroll) logsEl.scrollTop = logsEl.scrollHeight;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
- [ ] **Step 3: Typecheck**
|
|
139
|
+
|
|
140
|
+
Run: `npm run typecheck`
|
|
141
|
+
Expected: No errors.
|
|
142
|
+
|
|
143
|
+
- [ ] **Step 4: Commit**
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
git add src/commands/serve.ts
|
|
147
|
+
git commit -m "feat(serve): add timestamps and color-coded log styling"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### Task 3: Log system events to the console
|
|
153
|
+
|
|
154
|
+
**Files:**
|
|
155
|
+
- Modify: `src/commands/serve.ts:344-354`
|
|
156
|
+
|
|
157
|
+
- [ ] **Step 1: Update the `status` SSE handler to append system messages**
|
|
158
|
+
|
|
159
|
+
Replace:
|
|
160
|
+
```javascript
|
|
161
|
+
evtSource.addEventListener('status', (e) => {
|
|
162
|
+
fetchGroups();
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
With:
|
|
167
|
+
```javascript
|
|
168
|
+
evtSource.addEventListener('status', (e) => {
|
|
169
|
+
const data = JSON.parse(e.data);
|
|
170
|
+
if (data.type === 'group-started') {
|
|
171
|
+
appendLog(`[system] Group "${data.groupName}" started`, false);
|
|
172
|
+
const groupTime = document.querySelector('.log-line:last-child span:last-child');
|
|
173
|
+
if (groupTime) groupTime.className = 'log-system';
|
|
174
|
+
} else if (data.type === 'group-stopped') {
|
|
175
|
+
appendLog(`[system] Group "${data.groupName}" stopped`, false);
|
|
176
|
+
const groupTime = document.querySelector('.log-line:last-child span:last-child');
|
|
177
|
+
if (groupTime) groupTime.className = 'log-system';
|
|
178
|
+
} else if (data.type === 'item-restarted') {
|
|
179
|
+
appendLog(`[system] Item "${data.groupName}/${data.itemName}" restarted`, false);
|
|
180
|
+
const groupTime = document.querySelector('.log-line:last-child span:last-child');
|
|
181
|
+
if (groupTime) groupTime.className = 'log-system';
|
|
182
|
+
}
|
|
183
|
+
fetchGroups();
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Wait — the above uses `querySelector` hackily. Better: introduce an `appendSystemLog(message)` helper.
|
|
188
|
+
|
|
189
|
+
Instead, replace the whole block with:
|
|
190
|
+
|
|
191
|
+
```javascript
|
|
192
|
+
function appendSystemLog(message) {
|
|
193
|
+
const div = document.createElement('div');
|
|
194
|
+
div.className = 'log-line';
|
|
195
|
+
|
|
196
|
+
const time = document.createElement('span');
|
|
197
|
+
time.className = 'log-time';
|
|
198
|
+
const now = new Date();
|
|
199
|
+
const hh = String(now.getHours()).padStart(2, '0');
|
|
200
|
+
const mm = String(now.getMinutes()).padStart(2, '0');
|
|
201
|
+
const ss = String(now.getSeconds()).padStart(2, '0');
|
|
202
|
+
time.textContent = `[${hh}:${mm}:${ss}] `;
|
|
203
|
+
div.appendChild(time);
|
|
204
|
+
|
|
205
|
+
const content = document.createElement('span');
|
|
206
|
+
content.className = 'log-system';
|
|
207
|
+
content.textContent = message;
|
|
208
|
+
div.appendChild(content);
|
|
209
|
+
|
|
210
|
+
logsEl.appendChild(div);
|
|
211
|
+
if (autoScroll) logsEl.scrollTop = logsEl.scrollHeight;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
evtSource.addEventListener('status', (e) => {
|
|
215
|
+
const data = JSON.parse(e.data);
|
|
216
|
+
if (data.type === 'group-started') {
|
|
217
|
+
appendSystemLog(`[system] Group "${data.groupName}" started`);
|
|
218
|
+
} else if (data.type === 'group-stopped') {
|
|
219
|
+
appendSystemLog(`[system] Group "${data.groupName}" stopped`);
|
|
220
|
+
} else if (data.type === 'item-restarted') {
|
|
221
|
+
appendSystemLog(`[system] Item "${data.groupName}/${data.itemName}" restarted`);
|
|
222
|
+
}
|
|
223
|
+
fetchGroups();
|
|
224
|
+
});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
- [ ] **Step 2: Typecheck**
|
|
228
|
+
|
|
229
|
+
Run: `npm run typecheck`
|
|
230
|
+
Expected: No errors.
|
|
231
|
+
|
|
232
|
+
- [ ] **Step 3: Build**
|
|
233
|
+
|
|
234
|
+
Run: `npm run build`
|
|
235
|
+
Expected: Build completes successfully.
|
|
236
|
+
|
|
237
|
+
- [ ] **Step 4: Commit**
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
git add src/commands/serve.ts
|
|
241
|
+
git commit -m "feat(serve): log system events in web UI console"
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Self-Review
|
|
247
|
+
|
|
248
|
+
**Spec coverage:**
|
|
249
|
+
- Timestamps: Task 2 (`appendLog` adds `[HH:MM:SS]`).
|
|
250
|
+
- System events in console: Task 3 (`appendSystemLog` for `group-started`, `group-stopped`, `item-restarted`).
|
|
251
|
+
- Color coding: Task 2 (`.log-time`, `.log-system`, `.log-error`) and Task 3 (uses `.log-system`).
|
|
252
|
+
- Clear button: Task 1 (Clear button + click handler).
|
|
253
|
+
|
|
254
|
+
**Placeholder scan:** None found. Every step has exact code, file paths, and commands.
|
|
255
|
+
|
|
256
|
+
**Type consistency:** `appendLog` signature unchanged (`line, isError`). `appendSystemLog` is a new helper. All DOM APIs are standard.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Improve Web UI Console Logging
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Enhance the web UI console panel in `cligr serve` with timestamps, system event logging, color-coded output, and a clear button.
|
|
5
|
+
|
|
6
|
+
## Changes
|
|
7
|
+
|
|
8
|
+
### 1. Timestamps
|
|
9
|
+
- Every log line in the console gets an `[HH:MM:SS]` prefix.
|
|
10
|
+
- Generated client-side in the `appendLog` function using `new Date().toLocaleTimeString()`.
|
|
11
|
+
|
|
12
|
+
### 2. System Events in Console
|
|
13
|
+
- When the `status` SSE event fires, log human-readable messages to the console:
|
|
14
|
+
- `group-started` → `[system] Group "<name>" started`
|
|
15
|
+
- `group-stopped` → `[system] Group "<name>" stopped`
|
|
16
|
+
- `item-restarted` → `[system] Item "<group/item>" restarted`
|
|
17
|
+
|
|
18
|
+
### 3. Color Coding (CSS Classes)
|
|
19
|
+
- `.log-time` — muted gray timestamp
|
|
20
|
+
- `.log-system` — blue/purple for system events
|
|
21
|
+
- `.log-error` — red for stderr lines
|
|
22
|
+
- Process stdout stays default green (existing `#0f0` on `#111`)
|
|
23
|
+
|
|
24
|
+
### 4. Clear Button
|
|
25
|
+
- A "Clear" button is added to the console header next to the "Console" title.
|
|
26
|
+
- Clicking it empties the `#logs` element.
|
|
27
|
+
|
|
28
|
+
## Scope
|
|
29
|
+
- Only `src/commands/serve.ts` is modified (specifically the `serveHtml()` function).
|
|
30
|
+
- No backend or SSE protocol changes.
|
|
31
|
+
- No new dependencies.
|
|
32
|
+
|
|
33
|
+
## Success Criteria
|
|
34
|
+
- Console lines show `[HH:MM:SS]` prefix.
|
|
35
|
+
- Toggling a group on/off logs a system message in the console.
|
|
36
|
+
- Restarting an item logs a system message in the console.
|
|
37
|
+
- The Clear button removes all visible log lines.
|
|
38
|
+
- Existing process output behavior remains unchanged.
|
package/package.json
CHANGED
package/src/commands/serve.ts
CHANGED
|
@@ -230,13 +230,18 @@ function serveHtml(): string {
|
|
|
230
230
|
.resizer { width: 6px; background: #e0e0e0; cursor: col-resize; flex-shrink: 0; }
|
|
231
231
|
.resizer:hover { background: #bbb; }
|
|
232
232
|
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
|
|
233
|
-
.main
|
|
233
|
+
.main-header { display: flex; align-items: center; justify-content: space-between; font-size: 1rem; padding: 0.5rem 1rem; border-bottom: 1px solid #ccc; background: #f0f0f0; }
|
|
234
|
+
.main-header h2 { font-size: 1rem; margin: 0; }
|
|
235
|
+
.clear-btn { font-size: 0.8rem; padding: 0.25rem 0.6rem; cursor: pointer; }
|
|
234
236
|
.group { border: 1px solid #ccc; border-radius: 6px; padding: 0.75rem; margin: 0 0 0.75rem 0; background: #fff; }
|
|
235
237
|
.group-header { display: flex; align-items: center; gap: 0.5rem; font-weight: bold; font-size: 1rem; }
|
|
236
238
|
.items { margin: 0.5rem 0 0 1.25rem; }
|
|
237
239
|
.item { display: flex; align-items: center; gap: 0.4rem; margin: 0.2rem 0; font-size: 0.9rem; }
|
|
238
240
|
.logs { flex: 1; background: #111; color: #0f0; font-family: monospace; font-size: 0.85rem; overflow-y: auto; padding: 0.75rem; white-space: pre-wrap; }
|
|
239
|
-
.
|
|
241
|
+
.log-line { margin: 0.1rem 0; }
|
|
242
|
+
.log-time { color: #888; }
|
|
243
|
+
.log-system { color: #6cf; }
|
|
244
|
+
.log-error { color: #f55; }
|
|
240
245
|
</style>
|
|
241
246
|
</head>
|
|
242
247
|
<body>
|
|
@@ -245,7 +250,10 @@ function serveHtml(): string {
|
|
|
245
250
|
<div class="sidebar" id="groups"></div>
|
|
246
251
|
<div class="resizer" id="resizer"></div>
|
|
247
252
|
<div class="main">
|
|
248
|
-
<
|
|
253
|
+
<div class="main-header">
|
|
254
|
+
<h2>Console</h2>
|
|
255
|
+
<button class="clear-btn" id="clearBtn">Clear</button>
|
|
256
|
+
</div>
|
|
249
257
|
<div class="logs" id="logs"></div>
|
|
250
258
|
</div>
|
|
251
259
|
</div>
|
|
@@ -256,6 +264,11 @@ function serveHtml(): string {
|
|
|
256
264
|
const resizer = document.getElementById('resizer');
|
|
257
265
|
let autoScroll = true;
|
|
258
266
|
|
|
267
|
+
const clearBtn = document.getElementById('clearBtn');
|
|
268
|
+
clearBtn.addEventListener('click', () => {
|
|
269
|
+
logsEl.innerHTML = '';
|
|
270
|
+
});
|
|
271
|
+
|
|
259
272
|
resizer.addEventListener('mousedown', (e) => {
|
|
260
273
|
e.preventDefault();
|
|
261
274
|
document.body.style.cursor = 'col-resize';
|
|
@@ -333,16 +346,60 @@ function serveHtml(): string {
|
|
|
333
346
|
autoScroll = logsEl.scrollTop + logsEl.clientHeight >= logsEl.scrollHeight - 10;
|
|
334
347
|
});
|
|
335
348
|
|
|
349
|
+
function formatTime() {
|
|
350
|
+
const now = new Date();
|
|
351
|
+
const hh = String(now.getHours()).padStart(2, '0');
|
|
352
|
+
const mm = String(now.getMinutes()).padStart(2, '0');
|
|
353
|
+
const ss = String(now.getSeconds()).padStart(2, '0');
|
|
354
|
+
return \`[\${hh}:\${mm}:\${ss}] \`;
|
|
355
|
+
}
|
|
356
|
+
|
|
336
357
|
function appendLog(line, isError) {
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
358
|
+
const div = document.createElement('div');
|
|
359
|
+
div.className = 'log-line';
|
|
360
|
+
|
|
361
|
+
const time = document.createElement('span');
|
|
362
|
+
time.className = 'log-time';
|
|
363
|
+
time.textContent = formatTime();
|
|
364
|
+
div.appendChild(time);
|
|
365
|
+
|
|
366
|
+
const content = document.createElement('span');
|
|
367
|
+
content.textContent = line;
|
|
368
|
+
if (isError) content.className = 'log-error';
|
|
369
|
+
div.appendChild(content);
|
|
370
|
+
|
|
371
|
+
logsEl.appendChild(div);
|
|
372
|
+
if (autoScroll) logsEl.scrollTop = logsEl.scrollHeight;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function appendSystemLog(message) {
|
|
376
|
+
const div = document.createElement('div');
|
|
377
|
+
div.className = 'log-line';
|
|
378
|
+
|
|
379
|
+
const time = document.createElement('span');
|
|
380
|
+
time.className = 'log-time';
|
|
381
|
+
time.textContent = formatTime();
|
|
382
|
+
div.appendChild(time);
|
|
383
|
+
|
|
384
|
+
const content = document.createElement('span');
|
|
385
|
+
content.className = 'log-system';
|
|
386
|
+
content.textContent = message;
|
|
387
|
+
div.appendChild(content);
|
|
388
|
+
|
|
389
|
+
logsEl.appendChild(div);
|
|
341
390
|
if (autoScroll) logsEl.scrollTop = logsEl.scrollHeight;
|
|
342
391
|
}
|
|
343
392
|
|
|
344
393
|
const evtSource = new EventSource('/api/events');
|
|
345
394
|
evtSource.addEventListener('status', (e) => {
|
|
395
|
+
const data = JSON.parse(e.data);
|
|
396
|
+
if (data.type === 'group-started') {
|
|
397
|
+
appendSystemLog(\`[system] Group "\${data.groupName}" started\`);
|
|
398
|
+
} else if (data.type === 'group-stopped') {
|
|
399
|
+
appendSystemLog(\`[system] Group "\${data.groupName}" stopped\`);
|
|
400
|
+
} else if (data.type === 'item-restarted') {
|
|
401
|
+
appendSystemLog(\`[system] Item "\${data.groupName}/\${data.itemName}" restarted\`);
|
|
402
|
+
}
|
|
346
403
|
fetchGroups();
|
|
347
404
|
});
|
|
348
405
|
evtSource.addEventListener('log', (e) => {
|