@ai-setting/roy-plugin-task-show 1.0.0 → 1.2.0
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/dist/cli-tasks-adapter.d.ts +5 -0
- package/dist/cli-tasks-adapter.d.ts.map +1 -1
- package/dist/cli-tasks-adapter.js +5 -0
- package/dist/cli-tasks-adapter.js.map +1 -1
- package/dist/cli-tasks-tree-adapter.d.ts +5 -0
- package/dist/cli-tasks-tree-adapter.d.ts.map +1 -1
- package/dist/cli-tasks-tree-adapter.js +5 -0
- package/dist/cli-tasks-tree-adapter.js.map +1 -1
- package/dist/plugin.d.ts +2 -2
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +31 -11
- package/dist/plugin.js.map +1 -1
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +39 -9
- package/dist/server.js.map +1 -1
- package/dist/task-metadata.d.ts +21 -0
- package/dist/task-metadata.d.ts.map +1 -0
- package/dist/task-metadata.js +50 -0
- package/dist/task-metadata.js.map +1 -0
- package/dist/task-operations-html.d.ts +19 -0
- package/dist/task-operations-html.d.ts.map +1 -1
- package/dist/task-operations-html.js +32 -6
- package/dist/task-operations-html.js.map +1 -1
- package/dist/task-session-store.d.ts +2 -1
- package/dist/task-session-store.d.ts.map +1 -1
- package/dist/task-session-store.js +28 -4
- package/dist/task-session-store.js.map +1 -1
- package/dist/types.d.ts +31 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/plugin.json +2 -2
- package/public/style.css +105 -0
- package/public/task-operations.js +138 -3
package/public/style.css
CHANGED
|
@@ -598,6 +598,47 @@ details summary {
|
|
|
598
598
|
margin-left: 8px;
|
|
599
599
|
}
|
|
600
600
|
|
|
601
|
+
/* ---------- v1.1.0+ SSE state badge (5 states) ---------- */
|
|
602
|
+
/* All `.pipeline-badge` variants share the same shape so the header
|
|
603
|
+
* stays balanced; only the colour + animation differ. */
|
|
604
|
+
.pipeline-badge {
|
|
605
|
+
display: inline-block;
|
|
606
|
+
padding: 1px 8px;
|
|
607
|
+
border-radius: 8px;
|
|
608
|
+
font-size: 11px;
|
|
609
|
+
margin-left: 8px;
|
|
610
|
+
font-weight: 600;
|
|
611
|
+
letter-spacing: 0.02em;
|
|
612
|
+
}
|
|
613
|
+
.pipeline-stale {
|
|
614
|
+
/* legacy alias — same orange as the v0.9.x pill */
|
|
615
|
+
background: var(--warn);
|
|
616
|
+
color: #1f2937;
|
|
617
|
+
}
|
|
618
|
+
.pipeline-connecting {
|
|
619
|
+
background: #fde68a;
|
|
620
|
+
color: #78350f;
|
|
621
|
+
animation: badge-pulse 1.4s ease-in-out infinite;
|
|
622
|
+
}
|
|
623
|
+
.pipeline-live {
|
|
624
|
+
background: #22c55e;
|
|
625
|
+
color: #052e16;
|
|
626
|
+
animation: badge-pulse 1.8s ease-in-out infinite;
|
|
627
|
+
}
|
|
628
|
+
.pipeline-reconnecting {
|
|
629
|
+
background: #fde68a;
|
|
630
|
+
color: #78350f;
|
|
631
|
+
animation: badge-pulse 0.9s ease-in-out infinite;
|
|
632
|
+
}
|
|
633
|
+
.pipeline-error {
|
|
634
|
+
background: var(--bad);
|
|
635
|
+
color: #fff5f5;
|
|
636
|
+
}
|
|
637
|
+
@keyframes badge-pulse {
|
|
638
|
+
0%, 100% { opacity: 1; }
|
|
639
|
+
50% { opacity: 0.55; }
|
|
640
|
+
}
|
|
641
|
+
|
|
601
642
|
.pipeline-error {
|
|
602
643
|
background: rgba(239, 68, 68, 0.08);
|
|
603
644
|
border: 1px solid var(--bad);
|
|
@@ -1049,3 +1090,67 @@ details summary {
|
|
|
1049
1090
|
border: 1px solid rgba(148, 163, 184, 0.4);
|
|
1050
1091
|
}
|
|
1051
1092
|
|
|
1093
|
+
/* ---------- Session forest metadata ---------- */
|
|
1094
|
+
.session-forest > ul {
|
|
1095
|
+
list-style: none;
|
|
1096
|
+
margin: 0;
|
|
1097
|
+
padding: 0;
|
|
1098
|
+
}
|
|
1099
|
+
.session-row {
|
|
1100
|
+
min-width: 0;
|
|
1101
|
+
margin: 8px 0;
|
|
1102
|
+
padding: 10px 12px;
|
|
1103
|
+
border: 1px solid var(--border);
|
|
1104
|
+
border-radius: 8px;
|
|
1105
|
+
background: rgba(24, 36, 66, 0.45);
|
|
1106
|
+
}
|
|
1107
|
+
.session-row .session-title {
|
|
1108
|
+
display: inline-block;
|
|
1109
|
+
font-weight: 600;
|
|
1110
|
+
overflow-wrap: anywhere;
|
|
1111
|
+
}
|
|
1112
|
+
.session-toggle {
|
|
1113
|
+
margin-left: 10px;
|
|
1114
|
+
}
|
|
1115
|
+
.session-details {
|
|
1116
|
+
margin-top: 8px;
|
|
1117
|
+
}
|
|
1118
|
+
.session-details dl {
|
|
1119
|
+
display: grid;
|
|
1120
|
+
grid-template-columns: minmax(10rem, 15rem) minmax(0, 1fr);
|
|
1121
|
+
gap: 6px 12px;
|
|
1122
|
+
margin: 10px 0 0;
|
|
1123
|
+
}
|
|
1124
|
+
.session-details dt {
|
|
1125
|
+
color: var(--muted);
|
|
1126
|
+
font-weight: 600;
|
|
1127
|
+
overflow-wrap: anywhere;
|
|
1128
|
+
}
|
|
1129
|
+
.session-details dd {
|
|
1130
|
+
min-width: 0;
|
|
1131
|
+
margin: 0;
|
|
1132
|
+
overflow-wrap: anywhere;
|
|
1133
|
+
}
|
|
1134
|
+
.session-details pre.metadata-json,
|
|
1135
|
+
.session-details pre.metadata-text {
|
|
1136
|
+
max-height: 24rem;
|
|
1137
|
+
margin: 0;
|
|
1138
|
+
white-space: pre-wrap;
|
|
1139
|
+
overflow: auto;
|
|
1140
|
+
overflow-wrap: anywhere;
|
|
1141
|
+
word-break: break-word;
|
|
1142
|
+
}
|
|
1143
|
+
.session-operations {
|
|
1144
|
+
list-style: none;
|
|
1145
|
+
margin: 12px 0 0;
|
|
1146
|
+
padding: 0;
|
|
1147
|
+
}
|
|
1148
|
+
@media (max-width: 700px) {
|
|
1149
|
+
.session-details dl {
|
|
1150
|
+
grid-template-columns: 1fr;
|
|
1151
|
+
gap: 2px;
|
|
1152
|
+
}
|
|
1153
|
+
.session-details dd {
|
|
1154
|
+
margin-bottom: 8px;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
@@ -22,6 +22,12 @@
|
|
|
22
22
|
var TERMINAL_STATUSES = { completed: 1, failed: 1, cancelled: 1 };
|
|
23
23
|
var POLL_MS = 5000;
|
|
24
24
|
var MAX_BACKOFF_MS = 30000;
|
|
25
|
+
/** v1.1.0+ SSE state — drives the pipeline header badge. */
|
|
26
|
+
var currentSseState = "stale";
|
|
27
|
+
/** v1.1.0+ SSE instance, owned by the controller. */
|
|
28
|
+
var pipelineSse = null;
|
|
29
|
+
/** v1.1.0+ consecutive SSE error count (3+ → "error" state). */
|
|
30
|
+
var sseErrorCount = 0;
|
|
25
31
|
|
|
26
32
|
/** HTML escape — keep in sync with server-side `htmlEscape`. */
|
|
27
33
|
function esc(s) {
|
|
@@ -116,24 +122,50 @@
|
|
|
116
122
|
);
|
|
117
123
|
}).join("");
|
|
118
124
|
|
|
119
|
-
var
|
|
125
|
+
var badge = renderSseBadge(stale, currentSseState);
|
|
120
126
|
var idAttr = taskId ? ' data-task-id="' + esc(taskId) + '"' : "";
|
|
121
127
|
if (!ops || ops.length === 0) {
|
|
122
128
|
return (
|
|
123
129
|
'<section class="panel panel-pipeline"' + idAttr + ' data-pipeline-root>' +
|
|
124
|
-
'<h2>Task lifecycle pipeline' +
|
|
130
|
+
'<h2>Task lifecycle pipeline' + badge + '</h2>' +
|
|
125
131
|
'<p class="empty">No operations recorded yet.</p>' +
|
|
126
132
|
'</section>'
|
|
127
133
|
);
|
|
128
134
|
}
|
|
129
135
|
return (
|
|
130
136
|
'<section class="panel panel-pipeline"' + idAttr + ' data-pipeline-root>' +
|
|
131
|
-
'<h2>Task lifecycle pipeline' +
|
|
137
|
+
'<h2>Task lifecycle pipeline' + badge + '</h2>' +
|
|
132
138
|
'<ol class="op-timeline" role="list">' + nodes + '</ol>' +
|
|
133
139
|
'</section>'
|
|
134
140
|
);
|
|
135
141
|
}
|
|
136
142
|
|
|
143
|
+
/**
|
|
144
|
+
* v1.1.0+: render the SSE state badge (5-state) when SSE is wired,
|
|
145
|
+
* otherwise fall back to the legacy orange `pipeline-stale` pill for
|
|
146
|
+
* cache-TTL staleness.
|
|
147
|
+
*/
|
|
148
|
+
function renderSseBadge(stale, sseState) {
|
|
149
|
+
if (sseState) {
|
|
150
|
+
var labels = {
|
|
151
|
+
stale: "stale",
|
|
152
|
+
connecting: "connecting…",
|
|
153
|
+
live: "live",
|
|
154
|
+
reconnecting: "reconnecting…",
|
|
155
|
+
error: "error",
|
|
156
|
+
};
|
|
157
|
+
return (
|
|
158
|
+
' <span class="pipeline-badge pipeline-' + sseState + '" data-sse-state="' + sseState + '">' +
|
|
159
|
+
esc(labels[sseState] || sseState) +
|
|
160
|
+
'</span>'
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
if (stale) {
|
|
164
|
+
return ' <span class="pipeline-stale" data-pipeline-stale>stale</span>';
|
|
165
|
+
}
|
|
166
|
+
return "";
|
|
167
|
+
}
|
|
168
|
+
|
|
137
169
|
function renderErrorHtml(code, taskId) {
|
|
138
170
|
var idAttr = taskId ? ' data-task-id="' + esc(taskId) + '"' : "";
|
|
139
171
|
return (
|
|
@@ -250,6 +282,7 @@
|
|
|
250
282
|
notifyMermaidRebuild();
|
|
251
283
|
if (r.terminal) {
|
|
252
284
|
self.stopped = true;
|
|
285
|
+
self.teardownSse();
|
|
253
286
|
return;
|
|
254
287
|
}
|
|
255
288
|
self.scheduleNext();
|
|
@@ -257,6 +290,7 @@
|
|
|
257
290
|
swapIn(renderErrorHtml(r.code || "error", self.taskId));
|
|
258
291
|
if (r.terminal) {
|
|
259
292
|
self.stopped = true;
|
|
293
|
+
self.teardownSse();
|
|
260
294
|
return;
|
|
261
295
|
}
|
|
262
296
|
self.scheduleNext(true);
|
|
@@ -268,6 +302,103 @@
|
|
|
268
302
|
});
|
|
269
303
|
};
|
|
270
304
|
|
|
305
|
+
/**
|
|
306
|
+
* v1.1.0+: subscribe to /api/events and react to operation.updated /
|
|
307
|
+
* tool.called / task.* events for THIS task id. The handler updates
|
|
308
|
+
* `currentSseState` (drives the header badge) and patches the
|
|
309
|
+
* pipeline DOM in place — no full re-fetch needed.
|
|
310
|
+
*
|
|
311
|
+
* EventSource auto-reconnects; we just track the error count so
|
|
312
|
+
* 3+ consecutive failures flip the badge to `error`.
|
|
313
|
+
*/
|
|
314
|
+
PipelineController.prototype.attachSse = function () {
|
|
315
|
+
var self = this;
|
|
316
|
+
if (typeof EventSource === "undefined") return;
|
|
317
|
+
if (pipelineSse) return; // idempotent
|
|
318
|
+
setSseState("connecting");
|
|
319
|
+
try {
|
|
320
|
+
pipelineSse = new EventSource("/api/events");
|
|
321
|
+
} catch (_) {
|
|
322
|
+
setSseState("error");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
pipelineSse.addEventListener("open", function () {
|
|
326
|
+
setSseState("live");
|
|
327
|
+
sseErrorCount = 0;
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
pipelineSse.addEventListener("operation.updated", function (ev) {
|
|
331
|
+
var payload;
|
|
332
|
+
try { payload = JSON.parse(ev.data); } catch (_) { return; }
|
|
333
|
+
if (!payload || payload.taskId !== self.taskId) return;
|
|
334
|
+
var ops = (payload.data && payload.data.operations) || [];
|
|
335
|
+
var merged = mergeNodes(self.lastOps, ops);
|
|
336
|
+
self.lastOps = merged;
|
|
337
|
+
swapIn(renderPipelineHtml(merged, !!payload.data.stale, self.taskId));
|
|
338
|
+
window.__lifecycleOps = {
|
|
339
|
+
taskId: self.taskId,
|
|
340
|
+
operations: merged,
|
|
341
|
+
fetchedAt: Date.now(),
|
|
342
|
+
};
|
|
343
|
+
notifyMermaidRebuild();
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
["task.created", "task.updated", "task.completed"].forEach(function (type) {
|
|
347
|
+
pipelineSse.addEventListener(type, function (ev) {
|
|
348
|
+
// For task.completed, stop the controller — no more polling needed.
|
|
349
|
+
var payload;
|
|
350
|
+
try { payload = JSON.parse(ev.data); } catch (_) { return; }
|
|
351
|
+
if (!payload) return;
|
|
352
|
+
var sid = payload.data && payload.data.session && payload.data.session.taskId;
|
|
353
|
+
if (sid !== self.taskId) return;
|
|
354
|
+
if (type === "task.completed") {
|
|
355
|
+
self.stopped = true;
|
|
356
|
+
if (self.timer) { clearTimeout(self.timer); self.timer = null; }
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
pipelineSse.addEventListener("tool.called", function (ev) {
|
|
362
|
+
// tool.called doesn't change the pipeline timeline, but the
|
|
363
|
+
// Mermaid re-render hook listens for any data refresh — dispatch
|
|
364
|
+
// a synthetic ops-loaded event so the diagram reflects the new
|
|
365
|
+
// tool call. The timeline itself is patched via operation.updated.
|
|
366
|
+
notifyMermaidRebuild();
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
pipelineSse.addEventListener("error", function () {
|
|
370
|
+
sseErrorCount += 1;
|
|
371
|
+
if (sseErrorCount >= 3) {
|
|
372
|
+
setSseState("error");
|
|
373
|
+
} else {
|
|
374
|
+
setSseState("reconnecting");
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
PipelineController.prototype.teardownSse = function () {
|
|
380
|
+
if (pipelineSse) {
|
|
381
|
+
try { pipelineSse.close(); } catch (_) {}
|
|
382
|
+
pipelineSse = null;
|
|
383
|
+
}
|
|
384
|
+
setSseState("stale");
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* v1.1.0+ Update the SSE state and re-render the badge in place.
|
|
389
|
+
* Idempotent — safe to call multiple times for the same state.
|
|
390
|
+
*/
|
|
391
|
+
function setSseState(state) {
|
|
392
|
+
if (currentSseState === state) return;
|
|
393
|
+
currentSseState = state;
|
|
394
|
+
// Re-render the pipeline header with the new state.
|
|
395
|
+
var root = findRoot();
|
|
396
|
+
if (!root) return;
|
|
397
|
+
var pipeline = window.__pipelineController;
|
|
398
|
+
if (!pipeline) return;
|
|
399
|
+
swapIn(renderPipelineHtml(pipeline.lastOps, false, pipeline.taskId));
|
|
400
|
+
}
|
|
401
|
+
|
|
271
402
|
/**
|
|
272
403
|
* Fire a CustomEvent the app.js Mermaid re-renderer listens to.
|
|
273
404
|
* We don't import a global helper to keep this file standalone.
|
|
@@ -313,6 +444,10 @@
|
|
|
313
444
|
}
|
|
314
445
|
// Expose for tests
|
|
315
446
|
window.__pipelineController = new PipelineController(root);
|
|
447
|
+
// v1.1.0+: wire the SSE subscriber so operation.updated /
|
|
448
|
+
// tool.called events patch the pipeline DOM in place without
|
|
449
|
+
// waiting for the next polling tick.
|
|
450
|
+
window.__pipelineController.attachSse();
|
|
316
451
|
}
|
|
317
452
|
|
|
318
453
|
// v0.9.0: expose renderPipelineHtml to the global scope so other
|