@lmzhen/dsh-evolution-merge-ui 0.28.0 → 0.30.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 +209 -30
- package/lib/types/client/Panel.d.ts +5 -1
- package/lib/types/client/api.d.ts +52 -4
- package/lib/types/client/routes.generated.d.ts +2 -2
- 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
|
@@ -31,8 +31,8 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
merge: {
|
|
32
32
|
view: "/api/dsh-evolution/merge/view",
|
|
33
33
|
rows: "/api/dsh-evolution/merge/rows",
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
body: "/api/dsh-evolution/merge/body",
|
|
35
|
+
history: "/api/dsh-evolution/merge/history"
|
|
36
36
|
},
|
|
37
37
|
diagnostics: { view: "/api/dsh-evolution/diagnostics" }
|
|
38
38
|
};
|
|
@@ -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
|
}
|
|
@@ -154,42 +158,91 @@ window.__ModuleLoader__.load({
|
|
|
154
158
|
const zh = {
|
|
155
159
|
"entry.label": "技能合并",
|
|
156
160
|
"hint": "手动触发;后台逐对判定。这里只读,不写技能。",
|
|
161
|
+
"history": "历史",
|
|
162
|
+
"close": "关闭",
|
|
163
|
+
"tab.verify": "待判断",
|
|
157
164
|
"tab.pending": "待批准",
|
|
158
|
-
"tab.
|
|
165
|
+
"tab.fuse": "待合并",
|
|
159
166
|
"tab.skipped": "无需合并",
|
|
167
|
+
"empty.verify": "没有待判断的对。",
|
|
160
168
|
"empty.pending": "没有待批准的合并。",
|
|
161
|
-
"empty.
|
|
169
|
+
"empty.fuse": "没有待合并的对。",
|
|
162
170
|
"empty.skipped": "没有标记为无需合并的对。",
|
|
163
171
|
"loading": "正在读取…",
|
|
164
172
|
"refresh": "刷新",
|
|
173
|
+
"loadMore": "加载更多",
|
|
174
|
+
"approval.on": "审批开:合并前需人工批准。",
|
|
175
|
+
"approval.off": "审批关:合并自动执行。",
|
|
165
176
|
"failed": "读取失败,保留上次结果。",
|
|
166
177
|
"stage.decide": "判定",
|
|
167
178
|
"stage.author": "合并",
|
|
168
179
|
"stage.validate": "检查",
|
|
169
|
-
"stage.commit": "提交"
|
|
180
|
+
"stage.commit": "提交",
|
|
181
|
+
"row.target": "目标",
|
|
182
|
+
"row.confidence": "置信度",
|
|
183
|
+
"row.attempts": "尝试",
|
|
184
|
+
"row.origin": "来源",
|
|
185
|
+
"row.expires": "暂存到期",
|
|
186
|
+
"row.expired": "已过期",
|
|
187
|
+
"row.reason": "原因",
|
|
188
|
+
"row.failure": "失败",
|
|
189
|
+
"row.noRetry": "不可重试",
|
|
190
|
+
"row.copy": "复制命令",
|
|
191
|
+
"origin.agent": "自动",
|
|
192
|
+
"origin.human": "人工",
|
|
193
|
+
"state.verify": "待判定",
|
|
194
|
+
"state.pending": "待批准",
|
|
195
|
+
"state.approved": "已批准",
|
|
196
|
+
"state.fuse": "待合并",
|
|
197
|
+
"state.skipped": "已跳过"
|
|
170
198
|
};
|
|
171
199
|
const en = {
|
|
172
200
|
"entry.label": "Skill merge",
|
|
173
201
|
"hint": "Manual only; pairs are judged in the background. Read-only here.",
|
|
174
|
-
"
|
|
175
|
-
"
|
|
202
|
+
"history": "History",
|
|
203
|
+
"close": "Close",
|
|
204
|
+
"tab.verify": "To judge",
|
|
205
|
+
"tab.pending": "Pending approval",
|
|
206
|
+
"tab.fuse": "Ready to merge",
|
|
176
207
|
"tab.skipped": "Skipped",
|
|
208
|
+
"empty.verify": "No pairs to judge.",
|
|
177
209
|
"empty.pending": "No pending merges.",
|
|
178
|
-
"empty.
|
|
210
|
+
"empty.fuse": "No pairs ready to merge.",
|
|
179
211
|
"empty.skipped": "No pairs marked as not worth merging.",
|
|
180
212
|
"loading": "Loading…",
|
|
181
213
|
"refresh": "Refresh",
|
|
214
|
+
"loadMore": "Load more",
|
|
215
|
+
"approval.on": "Approval on: merges wait for a human.",
|
|
216
|
+
"approval.off": "Approval off: merges run automatically.",
|
|
182
217
|
"failed": "Read failed; keeping the last result.",
|
|
183
218
|
"stage.decide": "Decide",
|
|
184
219
|
"stage.author": "Author",
|
|
185
220
|
"stage.validate": "Validate",
|
|
186
|
-
"stage.commit": "Commit"
|
|
221
|
+
"stage.commit": "Commit",
|
|
222
|
+
"row.target": "Target",
|
|
223
|
+
"row.confidence": "Confidence",
|
|
224
|
+
"row.attempts": "Attempts",
|
|
225
|
+
"row.origin": "Origin",
|
|
226
|
+
"row.expires": "Staging expires",
|
|
227
|
+
"row.expired": "Expired",
|
|
228
|
+
"row.reason": "Reason",
|
|
229
|
+
"row.failure": "Failure",
|
|
230
|
+
"row.noRetry": "not retryable",
|
|
231
|
+
"row.copy": "Copy command",
|
|
232
|
+
"origin.agent": "auto",
|
|
233
|
+
"origin.human": "human",
|
|
234
|
+
"state.verify": "Unverified",
|
|
235
|
+
"state.pending": "Pending approval",
|
|
236
|
+
"state.approved": "Approved",
|
|
237
|
+
"state.fuse": "Ready to merge",
|
|
238
|
+
"state.skipped": "Skipped"
|
|
187
239
|
};
|
|
188
240
|
//#endregion
|
|
189
241
|
//#region src/client/styles.ts
|
|
190
242
|
const CSS_TAG_ID = "evolution-merge-panel";
|
|
191
243
|
const CSS = [
|
|
192
|
-
".evolution-merge-panel {
|
|
244
|
+
":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 }",
|
|
245
|
+
".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
246
|
".evolution-merge-panel [data-role=\"hint\"] { margin:0; color:var(--dsw-alias-label-tertiary); font-size:var(--evo-type-xs); }",
|
|
194
247
|
".evolution-merge-panel [data-role=\"stats\"] { display:flex; gap:var(--evo-space-8); flex-wrap:wrap; }",
|
|
195
248
|
".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); }",
|
|
@@ -258,8 +311,9 @@ window.__ModuleLoader__.load({
|
|
|
258
311
|
* intentionally copied commands, not buttons that write from the browser.
|
|
259
312
|
*/
|
|
260
313
|
const QUEUES = [
|
|
314
|
+
"verify",
|
|
261
315
|
"pending",
|
|
262
|
-
"
|
|
316
|
+
"fuse",
|
|
263
317
|
"skipped"
|
|
264
318
|
];
|
|
265
319
|
function failure(t, failure) {
|
|
@@ -274,15 +328,22 @@ window.__ModuleLoader__.load({
|
|
|
274
328
|
const [view, setView] = (0, react.useState)(face.view);
|
|
275
329
|
const [tab, setTab] = (0, react.useState)("pending");
|
|
276
330
|
const [rows, setRows] = (0, react.useState)(face.rows);
|
|
277
|
-
const [loading, setLoading] = (0, react.useState)(
|
|
331
|
+
const [loading, setLoading] = (0, react.useState)(face.loadRows !== void 0 || face.loadView !== void 0);
|
|
278
332
|
const [failed, setFailed] = (0, react.useState)(void 0);
|
|
279
|
-
const
|
|
333
|
+
const [nextCursor, setNextCursor] = (0, react.useState)(void 0);
|
|
334
|
+
const [overlay, setOverlay] = (0, react.useState)(void 0);
|
|
335
|
+
const request = (0, react.useRef)(0);
|
|
336
|
+
const loadRows = (queue, cursor = 0) => {
|
|
280
337
|
const load = face.loadRows;
|
|
281
338
|
if (load === void 0) return;
|
|
339
|
+
const token = request.current + 1;
|
|
340
|
+
request.current = token;
|
|
282
341
|
setLoading(true);
|
|
283
|
-
load(queue).then((outcome) => {
|
|
342
|
+
load(queue, cursor).then((outcome) => {
|
|
343
|
+
if (token !== request.current) return;
|
|
284
344
|
if (outcome.ok) {
|
|
285
|
-
setRows(outcome.payload.items);
|
|
345
|
+
setRows((current) => [...cursor === 0 ? [] : current, ...outcome.payload.items].sort((a, b) => b.updatedAt.localeCompare(a.updatedAt)));
|
|
346
|
+
setNextCursor(outcome.payload.nextCursor);
|
|
286
347
|
setFailed(void 0);
|
|
287
348
|
} else setFailed(outcome.failure);
|
|
288
349
|
}).catch(() => {
|
|
@@ -298,15 +359,65 @@ window.__ModuleLoader__.load({
|
|
|
298
359
|
const load = face.loadView;
|
|
299
360
|
if (load === void 0) return;
|
|
300
361
|
load().then((outcome) => {
|
|
301
|
-
if (outcome.ok)
|
|
302
|
-
|
|
362
|
+
if (!outcome.ok) {
|
|
363
|
+
setFailed(outcome.failure);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
if (outcome.payload.schemaVersion !== void 0 && outcome.payload.schemaVersion !== 2) {
|
|
367
|
+
setFailed({
|
|
368
|
+
kind: "server",
|
|
369
|
+
status: 0
|
|
370
|
+
});
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
setView(outcome.payload);
|
|
374
|
+
}).catch(() => {
|
|
375
|
+
setFailed({
|
|
376
|
+
kind: "server",
|
|
377
|
+
status: 0
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
};
|
|
381
|
+
const openBody = (id, side) => {
|
|
382
|
+
const load = face.loadBody;
|
|
383
|
+
if (load === void 0) return;
|
|
384
|
+
load(id, side).then((outcome) => {
|
|
385
|
+
if (outcome.ok) setOverlay({
|
|
386
|
+
kind: "body",
|
|
387
|
+
html: outcome.payload.html,
|
|
388
|
+
label: id + ":" + side
|
|
389
|
+
});
|
|
390
|
+
else setFailed(outcome.failure);
|
|
391
|
+
}).catch(() => {
|
|
392
|
+
setFailed({
|
|
393
|
+
kind: "server",
|
|
394
|
+
status: 0
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
};
|
|
398
|
+
const openHistory = () => {
|
|
399
|
+
const load = face.loadHistory;
|
|
400
|
+
if (load === void 0) return;
|
|
401
|
+
load().then((outcome) => {
|
|
402
|
+
if (outcome.ok) setOverlay({
|
|
403
|
+
kind: "history",
|
|
404
|
+
items: outcome.payload.items
|
|
405
|
+
});
|
|
406
|
+
else setFailed(outcome.failure);
|
|
407
|
+
}).catch(() => {
|
|
408
|
+
setFailed({
|
|
409
|
+
kind: "server",
|
|
410
|
+
status: 0
|
|
411
|
+
});
|
|
412
|
+
});
|
|
303
413
|
};
|
|
304
414
|
(0, react.useEffect)(() => {
|
|
305
415
|
loadView();
|
|
306
416
|
loadRows("pending");
|
|
307
417
|
}, [face]);
|
|
308
418
|
(0, react.useEffect)(() => {
|
|
309
|
-
|
|
419
|
+
setNextCursor(void 0);
|
|
420
|
+
loadRows(tab, 0);
|
|
310
421
|
}, [tab]);
|
|
311
422
|
const counts = view.counts;
|
|
312
423
|
const stats = (0, react.createElement)("div", { "data-role": "stats" }, QUEUES.map((queue) => (0, react.createElement)("div", {
|
|
@@ -314,25 +425,88 @@ window.__ModuleLoader__.load({
|
|
|
314
425
|
"data-role": "stat",
|
|
315
426
|
"data-queue": queue
|
|
316
427
|
}, (0, react.createElement)("div", { "data-role": "stat-value" }, String(counts[queue])), (0, react.createElement)("div", { "data-role": "stat-label" }, t("tab." + queue)))));
|
|
317
|
-
const
|
|
428
|
+
const latest = view.latestRun;
|
|
429
|
+
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)));
|
|
430
|
+
const tabs = (0, react.createElement)("div", {
|
|
431
|
+
"data-role": "tabs",
|
|
432
|
+
role: "tablist"
|
|
433
|
+
}, QUEUES.map((queue) => (0, react.createElement)("button", {
|
|
318
434
|
key: queue,
|
|
319
435
|
type: "button",
|
|
436
|
+
role: "tab",
|
|
437
|
+
"aria-selected": tab === queue ? "true" : "false",
|
|
320
438
|
"data-role": "tab",
|
|
321
439
|
"data-active": tab === queue ? "true" : "false",
|
|
322
440
|
onClick: () => {
|
|
323
441
|
setTab(queue);
|
|
324
442
|
}
|
|
325
443
|
}, 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
|
-
|
|
444
|
+
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) => {
|
|
445
|
+
const facts = [
|
|
446
|
+
row.target === void 0 ? void 0 : t("row.target") + " " + row.target,
|
|
447
|
+
row.confidence === void 0 ? void 0 : t("row.confidence") + " " + row.confidence.toFixed(2),
|
|
448
|
+
row.attempts === void 0 ? void 0 : t("row.attempts") + " " + String(row.attempts),
|
|
449
|
+
row.origin === void 0 ? void 0 : t("row.origin") + " " + t("origin." + row.origin),
|
|
450
|
+
row.stagingExpiresAt === void 0 ? void 0 : t("row.expires") + " " + new Date(row.stagingExpiresAt).toLocaleString(),
|
|
451
|
+
row.expired === void 0 ? void 0 : t("row.expired") + " " + row.expired,
|
|
452
|
+
row.reason === void 0 ? void 0 : t("row.reason") + " " + row.reason,
|
|
453
|
+
row.summary === void 0 ? void 0 : row.summary.filter(Boolean).join(" · "),
|
|
454
|
+
row.failure === void 0 ? void 0 : t("row.failure") + " " + row.failure.message + (row.failure.retryable ? "" : " · " + t("row.noRetry"))
|
|
455
|
+
].filter((value) => value !== void 0).join(" · ");
|
|
456
|
+
return (0, react.createElement)("div", {
|
|
457
|
+
key: row.id,
|
|
458
|
+
"data-role": "row"
|
|
459
|
+
}, (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" }, face.loadBody === void 0 ? null : (0, react.createElement)("button", {
|
|
460
|
+
type: "button",
|
|
461
|
+
"data-role": "body-a",
|
|
462
|
+
onClick: () => {
|
|
463
|
+
openBody(row.id, "a");
|
|
464
|
+
}
|
|
465
|
+
}, "A"), face.loadBody === void 0 ? null : (0, react.createElement)("button", {
|
|
466
|
+
type: "button",
|
|
467
|
+
"data-role": "body-b",
|
|
468
|
+
onClick: () => {
|
|
469
|
+
openBody(row.id, "b");
|
|
470
|
+
}
|
|
471
|
+
}, "B"), (row.actions ?? []).filter((action) => view.approval !== false || !action.includes("/evolution merge approve")).map((action) => (0, react.createElement)("button", {
|
|
472
|
+
key: action,
|
|
473
|
+
type: "button",
|
|
474
|
+
"data-role": "row-action",
|
|
475
|
+
title: action,
|
|
476
|
+
onClick: () => {
|
|
477
|
+
navigator.clipboard.writeText(action);
|
|
478
|
+
}
|
|
479
|
+
}, t("row.copy"))))));
|
|
480
|
+
}));
|
|
481
|
+
return (0, react.createElement)("section", {
|
|
482
|
+
className: CSS_TAG_ID,
|
|
483
|
+
"data-state": loading ? "loading" : failed !== void 0 ? "failed" : rows.length === 0 ? "empty" : "ready"
|
|
484
|
+
}, (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", {
|
|
485
|
+
type: "button",
|
|
486
|
+
"data-role": "load-more",
|
|
487
|
+
onClick: () => {
|
|
488
|
+
loadRows(tab, Number(nextCursor));
|
|
489
|
+
}
|
|
490
|
+
}, t("loadMore")), face.loadHistory === void 0 ? null : (0, react.createElement)("button", {
|
|
491
|
+
type: "button",
|
|
492
|
+
"data-role": "history",
|
|
493
|
+
onClick: openHistory
|
|
494
|
+
}, t("history")), overlay === void 0 ? null : (0, react.createElement)("section", { "data-role": "overlay" }, (0, react.createElement)("button", {
|
|
495
|
+
type: "button",
|
|
496
|
+
"data-role": "overlay-close",
|
|
497
|
+
onClick: () => {
|
|
498
|
+
setOverlay(void 0);
|
|
499
|
+
}
|
|
500
|
+
}, t("close")), overlay.kind === "body" ? (0, react.createElement)("div", {
|
|
501
|
+
"data-role": "body",
|
|
502
|
+
"data-label": overlay.label,
|
|
503
|
+
dangerouslySetInnerHTML: { __html: overlay.html }
|
|
504
|
+
}) : (0, react.createElement)("ul", { "data-role": "history-list" }, overlay.items.map((item) => (0, react.createElement)("li", { key: item.name }, item.name + " · " + item.kind + " · " + item.reason + " · v" + String(item.lastVersion))))), (0, react.createElement)("button", {
|
|
331
505
|
type: "button",
|
|
332
506
|
"data-role": "refresh",
|
|
333
507
|
onClick: () => {
|
|
334
508
|
loadView();
|
|
335
|
-
loadRows(tab);
|
|
509
|
+
loadRows(tab, 0);
|
|
336
510
|
}
|
|
337
511
|
}, t("refresh")));
|
|
338
512
|
}
|
|
@@ -356,17 +530,22 @@ window.__ModuleLoader__.load({
|
|
|
356
530
|
function seedView() {
|
|
357
531
|
return {
|
|
358
532
|
counts: {
|
|
533
|
+
verify: 0,
|
|
359
534
|
pending: 0,
|
|
360
|
-
|
|
535
|
+
fuse: 0,
|
|
361
536
|
skipped: 0
|
|
362
537
|
},
|
|
363
538
|
tabs: [
|
|
539
|
+
{
|
|
540
|
+
queue: "verify",
|
|
541
|
+
count: 0
|
|
542
|
+
},
|
|
364
543
|
{
|
|
365
544
|
queue: "pending",
|
|
366
545
|
count: 0
|
|
367
546
|
},
|
|
368
547
|
{
|
|
369
|
-
queue: "
|
|
548
|
+
queue: "fuse",
|
|
370
549
|
count: 0
|
|
371
550
|
},
|
|
372
551
|
{
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
* intentionally copied commands, not buttons that write from the browser.
|
|
4
4
|
*/
|
|
5
5
|
import { type ReactNode } from 'react';
|
|
6
|
-
import type { MergeOutcome, MergeQueue, MergeRowView, MergeViewPayload, QueuePage } from './api.ts';
|
|
6
|
+
import type { MergeBody, MergeHistoryItem, MergeOutcome, MergeQueue, MergeRowView, MergeViewPayload, QueuePage } from './api.ts';
|
|
7
7
|
export interface MergeFace {
|
|
8
8
|
view: MergeViewPayload;
|
|
9
9
|
rows: MergeRowView[];
|
|
10
10
|
loadView?: () => Promise<MergeOutcome<MergeViewPayload>>;
|
|
11
11
|
loadRows?: (queue: MergeQueue, cursor?: number) => Promise<MergeOutcome<QueuePage>>;
|
|
12
|
+
loadBody?: (id: string, side: 'a' | 'b') => Promise<MergeOutcome<MergeBody>>;
|
|
13
|
+
loadHistory?: () => Promise<MergeOutcome<{
|
|
14
|
+
items: MergeHistoryItem[];
|
|
15
|
+
}>>;
|
|
12
16
|
t: (key: string) => string;
|
|
13
17
|
}
|
|
14
18
|
export declare function MergePanel(face: MergeFace): ReactNode;
|
|
@@ -2,22 +2,37 @@ import { type RouteFailure } from './route-client.generated.ts';
|
|
|
2
2
|
export declare const HOST_ROUTES: {
|
|
3
3
|
readonly view: "/api/dsh-evolution/merge/view";
|
|
4
4
|
readonly rows: "/api/dsh-evolution/merge/rows";
|
|
5
|
-
readonly
|
|
6
|
-
readonly
|
|
5
|
+
readonly body: "/api/dsh-evolution/merge/body";
|
|
6
|
+
readonly history: "/api/dsh-evolution/merge/history";
|
|
7
7
|
};
|
|
8
|
-
export type MergeQueue = 'pending' | '
|
|
8
|
+
export type MergeQueue = 'verify' | 'pending' | 'fuse' | 'skipped';
|
|
9
9
|
export interface MergeCounts {
|
|
10
|
+
verify: number;
|
|
10
11
|
pending: number;
|
|
11
|
-
|
|
12
|
+
fuse: number;
|
|
12
13
|
skipped: number;
|
|
13
14
|
}
|
|
15
|
+
export interface MergeRunView {
|
|
16
|
+
id: string;
|
|
17
|
+
state: string;
|
|
18
|
+
command?: string;
|
|
19
|
+
stage?: string;
|
|
20
|
+
progress?: {
|
|
21
|
+
done: number;
|
|
22
|
+
total: number;
|
|
23
|
+
};
|
|
24
|
+
startedAt: number;
|
|
25
|
+
}
|
|
14
26
|
export interface MergeViewPayload {
|
|
27
|
+
schemaVersion?: number;
|
|
15
28
|
counts: MergeCounts;
|
|
16
29
|
tabs: {
|
|
17
30
|
queue: MergeQueue;
|
|
18
31
|
count: number;
|
|
19
32
|
}[];
|
|
20
33
|
commands: string[];
|
|
34
|
+
latestRun?: MergeRunView;
|
|
35
|
+
approval?: boolean;
|
|
21
36
|
}
|
|
22
37
|
export interface MergeRowView {
|
|
23
38
|
id: string;
|
|
@@ -29,12 +44,41 @@ export interface MergeRowView {
|
|
|
29
44
|
stage: string | null;
|
|
30
45
|
label: string;
|
|
31
46
|
updatedAt: string;
|
|
47
|
+
createdAt?: string;
|
|
48
|
+
target?: string;
|
|
49
|
+
confidence?: number;
|
|
50
|
+
failure?: {
|
|
51
|
+
stage: string;
|
|
52
|
+
code: string;
|
|
53
|
+
message: string;
|
|
54
|
+
retryable: boolean;
|
|
55
|
+
};
|
|
56
|
+
attempts?: number;
|
|
57
|
+
origin?: 'agent' | 'human';
|
|
58
|
+
stagingExpiresAt?: number;
|
|
59
|
+
expired?: 'target-taken' | 'source-changed';
|
|
60
|
+
reason?: string;
|
|
61
|
+
summary?: string[];
|
|
62
|
+
actions?: string[];
|
|
32
63
|
}
|
|
33
64
|
export interface QueuePage {
|
|
34
65
|
queue: MergeQueue;
|
|
35
66
|
items: MergeRowView[];
|
|
36
67
|
nextCursor?: string;
|
|
37
68
|
}
|
|
69
|
+
export interface MergeBody {
|
|
70
|
+
content: string;
|
|
71
|
+
markdown: boolean;
|
|
72
|
+
html: string;
|
|
73
|
+
}
|
|
74
|
+
export interface MergeHistoryItem {
|
|
75
|
+
name: string;
|
|
76
|
+
kind: 'merged' | 'deleted' | 'split' | 'other';
|
|
77
|
+
reason: string;
|
|
78
|
+
lastVersion: number;
|
|
79
|
+
archivedAt: string;
|
|
80
|
+
sourceRunId?: string;
|
|
81
|
+
}
|
|
38
82
|
export type MergeOutcome<T> = {
|
|
39
83
|
ok: true;
|
|
40
84
|
payload: T;
|
|
@@ -44,4 +88,8 @@ export type MergeOutcome<T> = {
|
|
|
44
88
|
};
|
|
45
89
|
export declare function view(): Promise<MergeOutcome<MergeViewPayload>>;
|
|
46
90
|
export declare function rows(queue: MergeQueue, cursor?: number): Promise<MergeOutcome<QueuePage>>;
|
|
91
|
+
export declare function body(id: string, side: 'a' | 'b'): Promise<MergeOutcome<MergeBody>>;
|
|
92
|
+
export declare function history(): Promise<MergeOutcome<{
|
|
93
|
+
items: MergeHistoryItem[];
|
|
94
|
+
}>>;
|
|
47
95
|
//# sourceMappingURL=api.d.ts.map
|
|
@@ -27,8 +27,8 @@ export declare const ROUTES: {
|
|
|
27
27
|
readonly merge: {
|
|
28
28
|
readonly view: "/api/dsh-evolution/merge/view";
|
|
29
29
|
readonly rows: "/api/dsh-evolution/merge/rows";
|
|
30
|
-
readonly
|
|
31
|
-
readonly
|
|
30
|
+
readonly body: "/api/dsh-evolution/merge/body";
|
|
31
|
+
readonly history: "/api/dsh-evolution/merge/history";
|
|
32
32
|
};
|
|
33
33
|
readonly diagnostics: {
|
|
34
34
|
readonly view: "/api/dsh-evolution/diagnostics";
|