@lmzhen/dsh-evolution-merge-ui 0.28.0 → 0.29.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/README.md +9 -10
- package/lib/client.js +116 -20
- package/lib/types/client/api.d.ts +27 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# @lmzhen/dsh-evolution-merge-ui
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
- 面板仅在 `evolution-merge` host 行与其 bundle 同时挂载时可用。
|
|
3
|
+
Browser-only sidebar panel for the merge queues. It reads the four host routes
|
|
4
|
+
and never writes skills: row actions are copyable `/evolution merge ...`
|
|
5
|
+
commands.
|
|
6
|
+
|
|
7
|
+
- Queues: pending / retry / skipped.
|
|
8
|
+
- Row facts: target, confidence, failure, attempts, origin, staging expiry.
|
|
9
|
+
- Run strip: latest run id/state/stage/progress.
|
|
10
|
+
- Four states: loading / ready / empty / failed; view schemaVersion guard.
|
|
11
|
+
- Mounted by the `all` bundle only.
|
package/lib/client.js
CHANGED
|
@@ -100,12 +100,16 @@ window.__ModuleLoader__.load({
|
|
|
100
100
|
ok: true,
|
|
101
101
|
data: record.data
|
|
102
102
|
};
|
|
103
|
-
|
|
103
|
+
const nested = record.error;
|
|
104
|
+
const errorRecord = typeof nested === "object" && nested !== null ? nested : void 0;
|
|
105
|
+
const code = typeof record.code === "string" && record.code !== "" ? record.code : typeof errorRecord?.code === "string" ? errorRecord.code : void 0;
|
|
106
|
+
const message = typeof record.message === "string" && record.message !== "" ? record.message : typeof errorRecord?.message === "string" ? errorRecord.message : void 0;
|
|
107
|
+
if (record.ok === false && code !== void 0 && message !== void 0 && message !== "") return {
|
|
104
108
|
ok: false,
|
|
105
109
|
failure: {
|
|
106
110
|
kind: "refused",
|
|
107
|
-
code
|
|
108
|
-
message
|
|
111
|
+
code,
|
|
112
|
+
message
|
|
109
113
|
}
|
|
110
114
|
};
|
|
111
115
|
}
|
|
@@ -162,11 +166,28 @@ window.__ModuleLoader__.load({
|
|
|
162
166
|
"empty.skipped": "没有标记为无需合并的对。",
|
|
163
167
|
"loading": "正在读取…",
|
|
164
168
|
"refresh": "刷新",
|
|
169
|
+
"loadMore": "加载更多",
|
|
170
|
+
"approval.on": "审批开:合并前需人工批准。",
|
|
171
|
+
"approval.off": "审批关:合并自动执行。",
|
|
165
172
|
"failed": "读取失败,保留上次结果。",
|
|
166
173
|
"stage.decide": "判定",
|
|
167
174
|
"stage.author": "合并",
|
|
168
175
|
"stage.validate": "检查",
|
|
169
|
-
"stage.commit": "提交"
|
|
176
|
+
"stage.commit": "提交",
|
|
177
|
+
"row.target": "目标",
|
|
178
|
+
"row.confidence": "置信度",
|
|
179
|
+
"row.attempts": "尝试",
|
|
180
|
+
"row.origin": "来源",
|
|
181
|
+
"row.expires": "暂存到期",
|
|
182
|
+
"row.failure": "失败",
|
|
183
|
+
"row.noRetry": "不可重试",
|
|
184
|
+
"row.copy": "复制命令",
|
|
185
|
+
"origin.agent": "自动",
|
|
186
|
+
"origin.human": "人工",
|
|
187
|
+
"state.verify": "待判定",
|
|
188
|
+
"state.pending": "待批准",
|
|
189
|
+
"state.fuse": "待融合",
|
|
190
|
+
"state.skipped": "已跳过"
|
|
170
191
|
};
|
|
171
192
|
const en = {
|
|
172
193
|
"entry.label": "Skill merge",
|
|
@@ -179,17 +200,35 @@ window.__ModuleLoader__.load({
|
|
|
179
200
|
"empty.skipped": "No pairs marked as not worth merging.",
|
|
180
201
|
"loading": "Loading…",
|
|
181
202
|
"refresh": "Refresh",
|
|
203
|
+
"loadMore": "Load more",
|
|
204
|
+
"approval.on": "Approval on: merges wait for a human.",
|
|
205
|
+
"approval.off": "Approval off: merges run automatically.",
|
|
182
206
|
"failed": "Read failed; keeping the last result.",
|
|
183
207
|
"stage.decide": "Decide",
|
|
184
208
|
"stage.author": "Author",
|
|
185
209
|
"stage.validate": "Validate",
|
|
186
|
-
"stage.commit": "Commit"
|
|
210
|
+
"stage.commit": "Commit",
|
|
211
|
+
"row.target": "Target",
|
|
212
|
+
"row.confidence": "Confidence",
|
|
213
|
+
"row.attempts": "Attempts",
|
|
214
|
+
"row.origin": "Origin",
|
|
215
|
+
"row.expires": "Staging expires",
|
|
216
|
+
"row.failure": "Failure",
|
|
217
|
+
"row.noRetry": "not retryable",
|
|
218
|
+
"row.copy": "Copy command",
|
|
219
|
+
"origin.agent": "auto",
|
|
220
|
+
"origin.human": "human",
|
|
221
|
+
"state.verify": "Unverified",
|
|
222
|
+
"state.pending": "Pending approval",
|
|
223
|
+
"state.fuse": "Ready to fuse",
|
|
224
|
+
"state.skipped": "Skipped"
|
|
187
225
|
};
|
|
188
226
|
//#endregion
|
|
189
227
|
//#region src/client/styles.ts
|
|
190
228
|
const CSS_TAG_ID = "evolution-merge-panel";
|
|
191
229
|
const CSS = [
|
|
192
|
-
".evolution-merge-panel {
|
|
230
|
+
":where(.evolution-merge-panel) { --evo-type-lg:calc(1em + 2px);--evo-type-body:1em;--evo-type-sm:calc(1em - 1px);--evo-type-xs:calc(1em - 2px);--evo-space-2:2px;--evo-space-4:4px;--evo-space-6:6px;--evo-space-8:8px;--evo-space-10:10px;--evo-space-12:12px;--evo-space-14:14px;--evo-space-16:16px;--evo-space-20:20px;--evo-radius-chip:4px;--evo-radius-control:8px;--evo-radius-surface:12px;--evo-radius-pill:999px;--evo-hairline-width:.5px;--evo-hairline-marker:2px;--evo-measure-read:80ch;--evo-leading-base:1.5;--evo-tone-quiet:var(--dsw-alias-label-secondary);--evo-tone-primary:var(--dsw-alias-brand-primary);--evo-tone-danger:var(--dsw-alias-state-error-primary);--evo-tone-success:var(--dsw-alias-state-success-primary);--evo-focus-ring:2px solid var(--dsw-alias-label-primary);--evo-focus-offset:-2px;--evo-cap-aside:280px;--evo-cap-block:260px }",
|
|
231
|
+
".evolution-merge-panel { display:flex; flex-direction:column; gap:var(--evo-space-12); padding:var(--evo-space-16); color:var(--dsw-alias-label-primary); font-size:var(--evo-type-sm); line-height:var(--evo-leading-base); }",
|
|
193
232
|
".evolution-merge-panel [data-role=\"hint\"] { margin:0; color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
194
233
|
".evolution-merge-panel [data-role=\"stats\"] { display:flex; gap:var(--evo-space-8); flex-wrap:wrap; }",
|
|
195
234
|
".evolution-merge-panel [data-role=\"stat\"] { border:var(--evo-hairline-width) solid var(--dsw-alias-border-l2); border-radius:var(--evo-radius-control); padding:var(--evo-space-6) var(--evo-space-10); min-width:calc(var(--evo-space-16) * 4); }",
|
|
@@ -274,15 +313,21 @@ window.__ModuleLoader__.load({
|
|
|
274
313
|
const [view, setView] = (0, react.useState)(face.view);
|
|
275
314
|
const [tab, setTab] = (0, react.useState)("pending");
|
|
276
315
|
const [rows, setRows] = (0, react.useState)(face.rows);
|
|
277
|
-
const [loading, setLoading] = (0, react.useState)(
|
|
316
|
+
const [loading, setLoading] = (0, react.useState)(face.loadRows !== void 0 || face.loadView !== void 0);
|
|
278
317
|
const [failed, setFailed] = (0, react.useState)(void 0);
|
|
279
|
-
const
|
|
318
|
+
const [nextCursor, setNextCursor] = (0, react.useState)(void 0);
|
|
319
|
+
const request = (0, react.useRef)(0);
|
|
320
|
+
const loadRows = (queue, cursor = 0) => {
|
|
280
321
|
const load = face.loadRows;
|
|
281
322
|
if (load === void 0) return;
|
|
323
|
+
const token = request.current + 1;
|
|
324
|
+
request.current = token;
|
|
282
325
|
setLoading(true);
|
|
283
|
-
load(queue).then((outcome) => {
|
|
326
|
+
load(queue, cursor).then((outcome) => {
|
|
327
|
+
if (token !== request.current) return;
|
|
284
328
|
if (outcome.ok) {
|
|
285
|
-
setRows(outcome.payload.items);
|
|
329
|
+
setRows((current) => [...cursor === 0 ? [] : current, ...outcome.payload.items].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)));
|
|
330
|
+
setNextCursor(outcome.payload.nextCursor);
|
|
286
331
|
setFailed(void 0);
|
|
287
332
|
} else setFailed(outcome.failure);
|
|
288
333
|
}).catch(() => {
|
|
@@ -298,15 +343,32 @@ window.__ModuleLoader__.load({
|
|
|
298
343
|
const load = face.loadView;
|
|
299
344
|
if (load === void 0) return;
|
|
300
345
|
load().then((outcome) => {
|
|
301
|
-
if (outcome.ok)
|
|
302
|
-
|
|
346
|
+
if (!outcome.ok) {
|
|
347
|
+
setFailed(outcome.failure);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (outcome.payload.schemaVersion !== void 0 && outcome.payload.schemaVersion !== 1) {
|
|
351
|
+
setFailed({
|
|
352
|
+
kind: "server",
|
|
353
|
+
status: 0
|
|
354
|
+
});
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
setView(outcome.payload);
|
|
358
|
+
}).catch(() => {
|
|
359
|
+
setFailed({
|
|
360
|
+
kind: "server",
|
|
361
|
+
status: 0
|
|
362
|
+
});
|
|
363
|
+
});
|
|
303
364
|
};
|
|
304
365
|
(0, react.useEffect)(() => {
|
|
305
366
|
loadView();
|
|
306
367
|
loadRows("pending");
|
|
307
368
|
}, [face]);
|
|
308
369
|
(0, react.useEffect)(() => {
|
|
309
|
-
|
|
370
|
+
setNextCursor(void 0);
|
|
371
|
+
loadRows(tab, 0);
|
|
310
372
|
}, [tab]);
|
|
311
373
|
const counts = view.counts;
|
|
312
374
|
const stats = (0, react.createElement)("div", { "data-role": "stats" }, QUEUES.map((queue) => (0, react.createElement)("div", {
|
|
@@ -314,25 +376,59 @@ window.__ModuleLoader__.load({
|
|
|
314
376
|
"data-role": "stat",
|
|
315
377
|
"data-queue": queue
|
|
316
378
|
}, (0, react.createElement)("div", { "data-role": "stat-value" }, String(counts[queue])), (0, react.createElement)("div", { "data-role": "stat-label" }, t("tab." + queue)))));
|
|
317
|
-
const
|
|
379
|
+
const latest = view.latestRun;
|
|
380
|
+
const runStrip = latest === void 0 ? null : (0, react.createElement)("div", { "data-role": "run-strip" }, (0, react.createElement)("span", { "data-role": "run-id" }, latest.id), (0, react.createElement)("span", { "data-role": "run-state" }, latest.state), latest.stage === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-stage" }, t("stage." + latest.stage)), latest.progress === void 0 ? null : (0, react.createElement)("span", { "data-role": "run-progress" }, String(latest.progress.done) + "/" + String(latest.progress.total)));
|
|
381
|
+
const tabs = (0, react.createElement)("div", {
|
|
382
|
+
"data-role": "tabs",
|
|
383
|
+
role: "tablist"
|
|
384
|
+
}, QUEUES.map((queue) => (0, react.createElement)("button", {
|
|
318
385
|
key: queue,
|
|
319
386
|
type: "button",
|
|
387
|
+
role: "tab",
|
|
388
|
+
"aria-selected": tab === queue ? "true" : "false",
|
|
320
389
|
"data-role": "tab",
|
|
321
390
|
"data-active": tab === queue ? "true" : "false",
|
|
322
391
|
onClick: () => {
|
|
323
392
|
setTab(queue);
|
|
324
393
|
}
|
|
325
394
|
}, t("tab." + queue) + " " + String(counts[queue]))));
|
|
326
|
-
const list = rows.length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("empty." + tab)) : (0, react.createElement)("div", { "data-role": "rows" }, rows.map((row) =>
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
395
|
+
const list = rows.length === 0 ? (0, react.createElement)("p", { "data-role": "note" }, t("empty." + tab)) : (0, react.createElement)("div", { "data-role": "rows" }, rows.map((row) => {
|
|
396
|
+
const facts = [
|
|
397
|
+
row.target === void 0 ? void 0 : t("row.target") + " " + row.target,
|
|
398
|
+
row.confidence === void 0 ? void 0 : t("row.confidence") + " " + row.confidence.toFixed(2),
|
|
399
|
+
row.attempts === void 0 ? void 0 : t("row.attempts") + " " + String(row.attempts),
|
|
400
|
+
row.origin === void 0 ? void 0 : t("row.origin") + " " + t("origin." + row.origin),
|
|
401
|
+
row.stagingExpiresAt === void 0 ? void 0 : t("row.expires") + " " + new Date(row.stagingExpiresAt).toLocaleString(),
|
|
402
|
+
row.failure === void 0 ? void 0 : t("row.failure") + " " + row.failure.message + (row.failure.retryable ? "" : " · " + t("row.noRetry"))
|
|
403
|
+
].filter((value) => value !== void 0).join(" · ");
|
|
404
|
+
return (0, react.createElement)("div", {
|
|
405
|
+
key: row.id,
|
|
406
|
+
"data-role": "row"
|
|
407
|
+
}, (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-label" }, row.label), (0, react.createElement)("div", { "data-role": "row-meta" }, t("state." + row.state) + (row.stage === null ? "" : " · " + t("stage." + row.stage))), facts === "" ? null : (0, react.createElement)("div", { "data-role": "row-facts" }, facts)), (0, react.createElement)("div", null, (0, react.createElement)("div", { "data-role": "row-meta" }, row.updatedAt), (0, react.createElement)("div", { "data-role": "row-actions" }, (row.actions ?? []).filter((action) => view.approval !== false || !action.includes("/evolution merge approve")).map((action) => (0, react.createElement)("button", {
|
|
408
|
+
key: action,
|
|
409
|
+
type: "button",
|
|
410
|
+
"data-role": "row-action",
|
|
411
|
+
title: action,
|
|
412
|
+
onClick: () => {
|
|
413
|
+
navigator.clipboard.writeText(action);
|
|
414
|
+
}
|
|
415
|
+
}, t("row.copy"))))));
|
|
416
|
+
}));
|
|
417
|
+
return (0, react.createElement)("section", {
|
|
418
|
+
className: CSS_TAG_ID,
|
|
419
|
+
"data-state": loading ? "loading" : failed !== void 0 ? "failed" : rows.length === 0 ? "empty" : "ready"
|
|
420
|
+
}, (0, react.createElement)("p", { "data-role": "hint" }, t("hint")), view.approval === void 0 ? null : (0, react.createElement)("p", { "data-role": "approval" }, t(view.approval ? "approval.on" : "approval.off")), runStrip, stats, tabs, loading ? (0, react.createElement)("p", { "data-role": "note" }, t("loading")) : null, failed === void 0 ? null : (0, react.createElement)("div", { "data-role": "note" }, failure(t, failed)), list, nextCursor === void 0 ? null : (0, react.createElement)("button", {
|
|
421
|
+
type: "button",
|
|
422
|
+
"data-role": "load-more",
|
|
423
|
+
onClick: () => {
|
|
424
|
+
loadRows(tab, Number(nextCursor));
|
|
425
|
+
}
|
|
426
|
+
}, t("loadMore")), (0, react.createElement)("button", {
|
|
331
427
|
type: "button",
|
|
332
428
|
"data-role": "refresh",
|
|
333
429
|
onClick: () => {
|
|
334
430
|
loadView();
|
|
335
|
-
loadRows(tab);
|
|
431
|
+
loadRows(tab, 0);
|
|
336
432
|
}
|
|
337
433
|
}, t("refresh")));
|
|
338
434
|
}
|
|
@@ -11,13 +11,27 @@ export interface MergeCounts {
|
|
|
11
11
|
retry: number;
|
|
12
12
|
skipped: number;
|
|
13
13
|
}
|
|
14
|
+
export interface MergeRunView {
|
|
15
|
+
id: string;
|
|
16
|
+
state: string;
|
|
17
|
+
command?: string;
|
|
18
|
+
stage?: string;
|
|
19
|
+
progress?: {
|
|
20
|
+
done: number;
|
|
21
|
+
total: number;
|
|
22
|
+
};
|
|
23
|
+
startedAt: number;
|
|
24
|
+
}
|
|
14
25
|
export interface MergeViewPayload {
|
|
26
|
+
schemaVersion?: number;
|
|
15
27
|
counts: MergeCounts;
|
|
16
28
|
tabs: {
|
|
17
29
|
queue: MergeQueue;
|
|
18
30
|
count: number;
|
|
19
31
|
}[];
|
|
20
32
|
commands: string[];
|
|
33
|
+
latestRun?: MergeRunView;
|
|
34
|
+
approval?: boolean;
|
|
21
35
|
}
|
|
22
36
|
export interface MergeRowView {
|
|
23
37
|
id: string;
|
|
@@ -29,6 +43,19 @@ export interface MergeRowView {
|
|
|
29
43
|
stage: string | null;
|
|
30
44
|
label: string;
|
|
31
45
|
updatedAt: string;
|
|
46
|
+
createdAt?: string;
|
|
47
|
+
target?: string;
|
|
48
|
+
confidence?: number;
|
|
49
|
+
failure?: {
|
|
50
|
+
stage: string;
|
|
51
|
+
code: string;
|
|
52
|
+
message: string;
|
|
53
|
+
retryable: boolean;
|
|
54
|
+
};
|
|
55
|
+
attempts?: number;
|
|
56
|
+
origin?: 'agent' | 'human';
|
|
57
|
+
stagingExpiresAt?: number;
|
|
58
|
+
actions?: string[];
|
|
32
59
|
}
|
|
33
60
|
export interface QueuePage {
|
|
34
61
|
queue: MergeQueue;
|