@zq-silk/yui 2.0.0 → 2.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/README.md +4 -0
- package/dist/cli/commandCatalog.js +318 -289
- package/dist/cli/commandDiscovery.js +72 -0
- package/dist/cli/completion.js +22 -227
- package/dist/cli/dynamicCompletion.js +12 -6
- package/dist/cli/invocationAuthority.js +2 -2
- package/dist/cli/invocationRouter.js +18 -7
- package/dist/cli.js +23 -3030
- package/dist/commands/capabilityCommands.js +5 -5
- package/dist/commands/globalRoleCommands.js +2 -1
- package/dist/commands/taskCommands.js +90 -21
- package/dist/commands/taskIntegrationCommands.js +3 -1
- package/dist/commands/taskUpstreamCommands.js +3 -1
- package/dist/context/runContextPack.js +132 -5
- package/dist/context/sourceRunContext.js +4 -2
- package/dist/context/taskContext.js +12 -3
- package/dist/controlPlaneCli.js +3092 -0
- package/dist/controller/fileSchedulerStoreAdapter.js +19 -6
- package/dist/controller/jobControl.js +21 -0
- package/dist/executor/agentExecutor.js +1 -1
- package/dist/executor/effectiveLaunch.js +18 -5
- package/dist/executor/fileRoleLaunchPlanner.js +15 -19
- package/dist/integration/gitIntegrationService.js +50 -15
- package/dist/kernel/accessAssessment.js +1 -0
- package/dist/kernel/builtinCapabilities.js +28 -1
- package/dist/kernel/capabilityRegistry.js +64 -19
- package/dist/message/messageContinuation.js +7 -2
- package/dist/nativeAgent/agent.js +275 -0
- package/dist/nativeAgent/cliDemo.js +37 -0
- package/dist/nativeAgent/codingTools.js +11 -0
- package/dist/nativeAgent/commandTool.js +215 -0
- package/dist/nativeAgent/compactionDemo.js +158 -0
- package/dist/nativeAgent/composition.js +71 -0
- package/dist/nativeAgent/context/budget.js +44 -0
- package/dist/nativeAgent/context/index.js +339 -0
- package/dist/nativeAgent/context/providerCompressor.js +103 -0
- package/dist/nativeAgent/contracts.js +1 -0
- package/dist/nativeAgent/demo.js +40 -0
- package/dist/nativeAgent/evaluation/cases.js +38 -0
- package/dist/nativeAgent/evaluation/checks.js +91 -0
- package/dist/nativeAgent/evaluation/demo.js +19 -0
- package/dist/nativeAgent/evaluation/files.js +54 -0
- package/dist/nativeAgent/evaluation/fixture.js +36 -0
- package/dist/nativeAgent/evaluation/index.js +239 -0
- package/dist/nativeAgent/executionOwner.js +209 -0
- package/dist/nativeAgent/filePatterns.js +170 -0
- package/dist/nativeAgent/fileToolsSupport.js +202 -0
- package/dist/nativeAgent/index.js +16 -0
- package/dist/nativeAgent/interaction/cli.js +358 -0
- package/dist/nativeAgent/interaction/contracts.js +1 -0
- package/dist/nativeAgent/interaction/index.js +3 -0
- package/dist/nativeAgent/interaction/memoryDemo.js +115 -0
- package/dist/nativeAgent/interaction/renderer.js +34 -0
- package/dist/nativeAgent/localSafety.js +258 -0
- package/dist/nativeAgent/mockProvider.js +43 -0
- package/dist/nativeAgent/model/anthropicMessages.js +204 -0
- package/dist/nativeAgent/model/chatCompletions.js +210 -0
- package/dist/nativeAgent/model/errors.js +47 -0
- package/dist/nativeAgent/model/gateway.js +423 -0
- package/dist/nativeAgent/model/index.js +7 -0
- package/dist/nativeAgent/model/observationAdapter.js +21 -0
- package/dist/nativeAgent/model/protocols.js +19 -0
- package/dist/nativeAgent/model/responses.js +263 -0
- package/dist/nativeAgent/model/types.js +1 -0
- package/dist/nativeAgent/model/wire.js +73 -0
- package/dist/nativeAgent/observability/index.js +220 -0
- package/dist/nativeAgent/product/catalog.js +82 -0
- package/dist/nativeAgent/product/config.js +295 -0
- package/dist/nativeAgent/product/facts.js +30 -0
- package/dist/nativeAgent/product/index.js +62 -0
- package/dist/nativeAgent/product/location.js +44 -0
- package/dist/nativeAgent/product/runtime.js +276 -0
- package/dist/nativeAgent/product/storage.js +49 -0
- package/dist/nativeAgent/product/tools.js +47 -0
- package/dist/nativeAgent/product/transport.js +54 -0
- package/dist/nativeAgent/projectGuidance/index.js +425 -0
- package/dist/nativeAgent/searchTools.js +305 -0
- package/dist/nativeAgent/session/backends.js +293 -0
- package/dist/nativeAgent/session/catalog.js +97 -0
- package/dist/nativeAgent/session/catalogDemo.js +87 -0
- package/dist/nativeAgent/session/contracts.js +1 -0
- package/dist/nativeAgent/session/format.js +269 -0
- package/dist/nativeAgent/session/index.js +5 -0
- package/dist/nativeAgent/session/location.js +36 -0
- package/dist/nativeAgent/session/sqliteFormat.js +134 -0
- package/dist/nativeAgent/session/store.js +248 -0
- package/dist/nativeAgent/textTools.js +293 -0
- package/dist/nativeAgent/toolManager/executor.js +290 -0
- package/dist/nativeAgent/toolManager/index.js +4 -0
- package/dist/nativeAgent/validation.js +95 -0
- package/dist/plugins/pluginService.js +98 -8
- package/dist/resources/projectResourceService.js +23 -1
- package/dist/runtime/managedIdentity.js +6 -0
- package/dist/surface/surfaceContributions.js +3 -0
- package/dist/task/taskAuthority.js +61 -10
- package/dist/web/assets/assetManifest.js +38 -22
- package/dist/web/assets/client/api.js +115 -0
- package/dist/web/assets/client/app.js +615 -862
- package/dist/web/assets/client/components.js +323 -897
- package/dist/web/assets/client/detail.js +333 -0
- package/dist/web/assets/client/dock.js +225 -0
- package/dist/web/assets/client/dom.js +55 -3
- package/dist/web/assets/client/evidence.js +172 -0
- package/dist/web/assets/client/format.js +25 -14
- package/dist/web/assets/client/forms.js +230 -0
- package/dist/web/assets/client/i18n.js +1024 -791
- package/dist/web/assets/client/overview.js +118 -0
- package/dist/web/assets/client/records.js +63 -0
- package/dist/web/assets/client/sections.js +313 -0
- package/dist/web/assets/client/sidebar.js +146 -0
- package/dist/web/assets/client/theme.js +61 -22
- package/dist/web/assets/icons.js +39 -0
- package/dist/web/assets/shell.js +125 -118
- package/dist/web/assets/styles/base.js +41 -0
- package/dist/web/assets/styles/components.js +169 -0
- package/dist/web/assets/styles/layout.js +56 -77
- package/dist/web/assets/styles/markdown.js +16 -24
- package/dist/web/assets/styles/responsive.js +41 -44
- package/dist/web/assets/styles/tokens.js +65 -89
- package/dist/web/assets/styles/views.js +292 -0
- package/dist/web/webServer.js +2 -1
- package/docs/agent-result-consumption.md +16 -0
- package/docs/agent-result-consumption.zh-CN.md +13 -0
- package/docs/examples/agent-offline.mjs +194 -0
- package/docs/native-agent.md +283 -0
- package/docs/release-workflow.md +61 -0
- package/docs/release-workflow.zh-CN.md +46 -0
- package/docs/roles-and-configuration.md +32 -0
- package/docs/roles-and-configuration.zh-CN.md +26 -0
- package/package.json +1 -1
- package/skills/yui-leader/SKILL.md +9 -0
- package/skills/yui-reviewer/SKILL.md +5 -0
- package/skills/yui-runtime/SKILL.md +33 -0
- package/dist/web/assets/client/taskSummary.js +0 -350
- package/dist/web/assets/client/taskSurface.js +0 -616
- package/dist/web/assets/client/view.js +0 -608
- package/dist/web/assets/styles/cards.js +0 -247
- package/dist/web/assets/styles/widgets.js +0 -168
|
@@ -1,992 +1,418 @@
|
|
|
1
1
|
import { AGENT_ADAPTER_CATALOG } from "../../../agent/adapterCatalog.js";
|
|
2
2
|
import { AGENT_EXECUTION_COMPONENT_CATALOG } from "../../../agent/executionComponents.js";
|
|
3
|
-
export const COMPONENTS_SCRIPT = `
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
import { node } from "/assets/js/dom.js";
|
|
3
|
+
export const COMPONENTS_SCRIPT = String.raw `
|
|
4
|
+
// Pure builders: data + translator in, DOM out. Views compose these; nothing
|
|
5
|
+
// here reads application state or performs a request.
|
|
6
|
+
import { h, icon, node } from "/assets/js/dom.js";
|
|
7
7
|
import { formatDateTime, relativeTime } from "/assets/js/format.js";
|
|
8
|
-
import {
|
|
8
|
+
import { renderMarkdown } from "/assets/js/markdown.js";
|
|
9
9
|
|
|
10
10
|
// Generated from the server catalogs, not a second product registry.
|
|
11
11
|
const adapterLabels = ${JSON.stringify(Object.fromEntries(AGENT_ADAPTER_CATALOG.map(({ id, label }) => [id, label])))};
|
|
12
12
|
const componentLabels = ${JSON.stringify(Object.fromEntries(AGENT_EXECUTION_COMPONENT_CATALOG.map(({ id, label }) => [id, label])))};
|
|
13
|
-
function
|
|
14
|
-
return adapterLabels[adapterId] || adapterId;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
export function agentLabel(component, adapterId) {
|
|
14
|
+
return component ? componentLabels[component] || component : adapterLabels[adapterId] || adapterId;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// --- Vocabulary ----------------------------------------------------------------
|
|
18
|
+
// A translated label for a domain value; unknown values stay visible verbatim
|
|
19
|
+
// instead of being hidden or guessed.
|
|
20
|
+
export function label(t, prefix, value) {
|
|
21
|
+
if (value === undefined || value === null || value === "") return "—";
|
|
22
|
+
return t(prefix + "." + value, String(value).replace(/[-_]/g, " "));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TONES = {
|
|
26
|
+
task: { draft: "warn", active: "info", completed: "ok", cancelled: "idle", archived: "idle" },
|
|
27
|
+
exec: {
|
|
28
|
+
"needs-leader-action": "accent", "waiting-on-agents": "info", "waiting-user": "warn",
|
|
29
|
+
recovering: "warn", attention: "bad", "progressing-with-attention": "warn", blocked: "bad",
|
|
30
|
+
conflicted: "warn", working: "info", completed: "ok", retired: "idle", cancelled: "idle",
|
|
31
|
+
accepted: "ok", open: "info", archived: "idle"
|
|
32
|
+
},
|
|
33
|
+
run: { active: "info", completed: "ok", failed: "bad" },
|
|
34
|
+
work: { open: "info", accepted: "ok", retired: "idle" },
|
|
35
|
+
review: { pending: "idle", running: "info", completed: "ok", failed: "bad" },
|
|
36
|
+
job: { queued: "idle", running: "info", succeeded: "ok", failed: "bad", "timed-out": "bad",
|
|
37
|
+
cancelled: "idle", "unknown-needs-attention": "warn" },
|
|
38
|
+
session: { active: "ok", waiting: "warn", quiet: "idle", diagnostic: "bad", unknown: "idle",
|
|
39
|
+
stopped: "bad", idle: "idle", background: "warn" },
|
|
40
|
+
role: { running: "ok", waiting: "warn", idle: "idle", unknown: "idle", failed: "bad", exited: "idle", detached: "idle" },
|
|
41
|
+
decision: { active: "ok", superseded: "idle" },
|
|
42
|
+
input: { open: "warn", answered: "ok", cancelled: "idle", "auto-resolved": "ok" }
|
|
43
|
+
};
|
|
44
|
+
export function tone(kind, value) {
|
|
45
|
+
return (TONES[kind] && TONES[kind][value]) || "idle";
|
|
18
46
|
}
|
|
19
47
|
|
|
20
|
-
export function
|
|
21
|
-
|
|
48
|
+
export function badge(text, toneName, options) {
|
|
49
|
+
const element = h("span.badge.tone-" + (toneName || "idle"), null,
|
|
50
|
+
options && options.dot ? h("i.badge-dot", { "aria-hidden": "true" }) : null, text);
|
|
51
|
+
if (options && options.title) element.title = options.title;
|
|
52
|
+
return element;
|
|
22
53
|
}
|
|
23
54
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return item;
|
|
55
|
+
export function statusBadge(t, kind, prefix, value) {
|
|
56
|
+
const element = badge(label(t, prefix, value), tone(kind, value), { dot: true });
|
|
57
|
+
element.dataset.status = value;
|
|
58
|
+
return element;
|
|
29
59
|
}
|
|
30
60
|
|
|
31
|
-
export function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
item.append(node("small", "", label), path);
|
|
36
|
-
return item;
|
|
61
|
+
export function dot(toneName, title) {
|
|
62
|
+
const element = h("span.dot.tone-" + (toneName || "idle"), { "aria-hidden": title ? null : "true" });
|
|
63
|
+
if (title) { element.title = title; element.setAttribute("role", "img"); element.setAttribute("aria-label", title); }
|
|
64
|
+
return element;
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
export function chip(text, extraClass) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export function agentBadge(agent) {
|
|
44
|
-
if (!agent) return null;
|
|
45
|
-
const badge = node("span", "agent-badge");
|
|
46
|
-
if (agent.adapterId || agent.component) {
|
|
47
|
-
badge.append(chip(componentLabel(agent.component, agent.adapterId), "is-adapter"));
|
|
48
|
-
}
|
|
49
|
-
if (agent.model) badge.append(chip(agent.model));
|
|
50
|
-
if (agent.effort) badge.append(chip(agent.effort));
|
|
51
|
-
return badge.childNodes.length ? badge : null;
|
|
68
|
+
return h("span.chip" + (extraClass ? "." + extraClass : ""), null, text);
|
|
52
69
|
}
|
|
53
70
|
|
|
54
|
-
export function
|
|
55
|
-
|
|
56
|
-
if (!list.length) return null;
|
|
57
|
-
const block = node("div", "record-block");
|
|
58
|
-
block.append(node("small", "", label));
|
|
59
|
-
const row = node("div", "chip-row");
|
|
60
|
-
list.forEach(function (value) {
|
|
61
|
-
row.append(chip(String(value), activeValue !== undefined && value === activeValue ? "is-active" : ""));
|
|
62
|
-
});
|
|
63
|
-
block.append(row);
|
|
64
|
-
return block;
|
|
71
|
+
export function mono(text, extraClass) {
|
|
72
|
+
return h("code.id" + (extraClass ? "." + extraClass : ""), null, text);
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
export function
|
|
68
|
-
|
|
69
|
-
element
|
|
75
|
+
export function timeTag(iso, locale, t, options) {
|
|
76
|
+
if (!iso) return null;
|
|
77
|
+
const element = h("time.when", { dateTime: iso }, options && options.absolute
|
|
78
|
+
? formatDateTime(iso, locale) : relativeTime(iso, locale, t));
|
|
79
|
+
element.title = formatDateTime(iso, locale);
|
|
70
80
|
return element;
|
|
71
81
|
}
|
|
72
82
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export function anchorSection(id, head, body) {
|
|
93
|
-
const section = node("section", "detail-section anchor");
|
|
94
|
-
section.id = id;
|
|
95
|
-
if (head) section.append(head);
|
|
96
|
-
section.append(body);
|
|
97
|
-
return section;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// --- Task-first execution status -------------------------------------------
|
|
101
|
-
// The projection is the current read-model vocabulary: one derived status,
|
|
102
|
-
// owner, next action, and the attention/blocker facts behind it.
|
|
103
|
-
const EXEC_STATUS_TONE = {
|
|
104
|
-
"needs-leader-action": "is-accent",
|
|
105
|
-
"waiting-on-agents": "is-active",
|
|
106
|
-
"waiting-user": "is-warning",
|
|
107
|
-
"recovering": "is-warning",
|
|
108
|
-
"attention": "is-danger",
|
|
109
|
-
"progressing-with-attention": "is-warning",
|
|
110
|
-
"blocked": "is-danger",
|
|
111
|
-
"conflicted": "is-warning",
|
|
112
|
-
"working": "is-active",
|
|
113
|
-
"completed": "is-muted",
|
|
114
|
-
"retired": "is-muted",
|
|
115
|
-
"cancelled": "is-muted",
|
|
116
|
-
"accepted": "is-muted",
|
|
117
|
-
"open": "is-active",
|
|
118
|
-
"archived": "is-muted"
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
export function executionBand(projection, t, locale) {
|
|
122
|
-
if (!projection) return null;
|
|
123
|
-
const tone = EXEC_STATUS_TONE[projection.status] || "";
|
|
124
|
-
const band = node("div", "exec-band " + tone);
|
|
125
|
-
|
|
126
|
-
const head = node("div", "exec-band-head");
|
|
127
|
-
head.append(pill(t, "exec.status", projection.status));
|
|
128
|
-
head.append(node("span", "exec-band-owner",
|
|
129
|
-
t("exec.owner." + projection.owner) + " · " + t("exec.action." + projection.action)));
|
|
130
|
-
if (projection.activeRuns && projection.activeRuns.length > 0) {
|
|
131
|
-
head.append(node("span", "exec-band-executors",
|
|
132
|
-
projection.activeRuns.length + " " + t("exec.executors")));
|
|
133
|
-
}
|
|
134
|
-
if (projection.monitoring === "stopped") {
|
|
135
|
-
head.append(node("span", "exec-band-stopped", t("exec.monitoring.stopped")));
|
|
136
|
-
}
|
|
137
|
-
if (projection.failClosed) {
|
|
138
|
-
head.append(node("span", "exec-band-failclosed", t("exec.failClosed")));
|
|
139
|
-
}
|
|
140
|
-
band.append(head);
|
|
141
|
-
|
|
142
|
-
if (projection.summary) {
|
|
143
|
-
band.append(node("p", "exec-band-summary", projection.summary));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (projection.attention && projection.attention.length) {
|
|
147
|
-
const list = node("div", "exec-signal-list");
|
|
148
|
-
projection.attention.forEach(function (item) {
|
|
149
|
-
const row = node("div", "exec-signal is-attention");
|
|
150
|
-
row.append(node("span", "exec-signal-kind", t("exec.attention." + item.kind)));
|
|
151
|
-
row.append(node("span", "exec-signal-text", item.summary));
|
|
152
|
-
list.append(row);
|
|
153
|
-
});
|
|
154
|
-
band.append(list);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (projection.blockers && projection.blockers.length) {
|
|
158
|
-
const list = node("div", "exec-signal-list");
|
|
159
|
-
projection.blockers.forEach(function (blocker) {
|
|
160
|
-
const row = node("div", "exec-signal is-blocker");
|
|
161
|
-
row.append(node("span", "exec-signal-kind",
|
|
162
|
-
t("exec.blocker." + blocker.kind) + " · " + t("exec.owner." + blocker.owner)));
|
|
163
|
-
row.append(node("span", "exec-signal-text", blocker.summary));
|
|
164
|
-
list.append(row);
|
|
165
|
-
});
|
|
166
|
-
band.append(list);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
return band;
|
|
83
|
+
// --- Containers -------------------------------------------------------------------
|
|
84
|
+
export function card(options) {
|
|
85
|
+
const opts = options || {};
|
|
86
|
+
const element = h("section.card" + (opts.className ? "." + opts.className.split(" ").join(".") : ""));
|
|
87
|
+
if (opts.id) element.id = opts.id;
|
|
88
|
+
if (opts.title || opts.actions) {
|
|
89
|
+
const head = h("header.card-head", null,
|
|
90
|
+
h("h3.card-title", null, opts.icon ? icon(opts.icon) : null, h("span", null, opts.title),
|
|
91
|
+
opts.count !== undefined && opts.count !== null ? h("span.count", null, String(opts.count)) : null),
|
|
92
|
+
opts.actions ? h("div.card-actions", null, opts.actions) : null);
|
|
93
|
+
if (opts.hint) head.append(h("p.card-hint", null, opts.hint));
|
|
94
|
+
element.append(head);
|
|
95
|
+
}
|
|
96
|
+
const body = h("div.card-body");
|
|
97
|
+
element.append(body);
|
|
98
|
+
element.body = body;
|
|
99
|
+
return element;
|
|
170
100
|
}
|
|
171
101
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
card.append(head);
|
|
184
|
-
|
|
185
|
-
if (projection.lanes && projection.lanes.length) {
|
|
186
|
-
const lanes = node("div", "lane-list");
|
|
187
|
-
projection.lanes.forEach(function (lane) {
|
|
188
|
-
const row = node("div", "lane-row");
|
|
189
|
-
row.append(statusDot(lane.status));
|
|
190
|
-
row.append(node("span", "lane-role", lane.roleName));
|
|
191
|
-
row.append(node("span", "lane-status", t("workExec.lane." + lane.status)));
|
|
192
|
-
if (lane.delivery) row.append(chip(t("run.delivery." + lane.delivery)));
|
|
193
|
-
row.append(node("span", "mono", lane.currentRunId || t("detail.unobserved")));
|
|
194
|
-
if (lane.retryRunId) row.append(chip(t("workExec.retry") + " · " + lane.retryRunId, "is-danger"));
|
|
195
|
-
if (lane.settleRunId) row.append(chip(t("workExec.settle") + " · " + lane.settleRunId));
|
|
196
|
-
if (lane.session === "unobserved") row.append(chip(t("detail.unobserved")));
|
|
197
|
-
lanes.append(row);
|
|
198
|
-
});
|
|
199
|
-
card.append(lanes);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
const facts = node("div", "record-meta execution-resource-meta");
|
|
203
|
-
facts.append(node("span", "", t("workExec.main") + " · "
|
|
204
|
-
+ (projection.mainRun.runId || t("detail.unobserved"))
|
|
205
|
-
+ " [" + t("workExec.mainStatus." + projection.mainRun.status) + "]"));
|
|
206
|
-
facts.append(node("span", "", t("workExec.candidate") + " · "
|
|
207
|
-
+ (projection.candidate.candidateId || t("workExec.none"))
|
|
208
|
-
+ " [" + t("workExec.candidateStatus." + projection.candidate.status) + "]"));
|
|
209
|
-
card.append(facts);
|
|
210
|
-
|
|
211
|
-
if (projection.candidate.sourceExecutionGroupId) {
|
|
212
|
-
const provenance = projection.candidate.successfulLaneRuns.map(function (lane) {
|
|
213
|
-
return lane.laneId + " → " + lane.successfulRunId;
|
|
214
|
-
}).join(", ") || t("detail.unobserved");
|
|
215
|
-
card.append(node("p", "muted mono", (projection.candidate.mainRunId || t("detail.unobserved"))
|
|
216
|
-
+ " → " + projection.candidate.sourceExecutionGroupId + " → " + provenance));
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
const next = node("div", "exec-resolution");
|
|
220
|
-
next.append(node("span", "exec-resolution-decision", t("workExec.next")));
|
|
221
|
-
next.append(node("span", "exec-resolution-summary",
|
|
222
|
-
t("workExec.action." + projection.nextAction.kind)
|
|
223
|
-
+ " · " + t("workExec.owner") + " "
|
|
224
|
-
+ (projection.nextAction.owners.join(", ") || t("workExec.none"))));
|
|
225
|
-
if (projection.nextAction.targetIds.length) {
|
|
226
|
-
next.append(node("span", "mono", projection.nextAction.targetIds.join(", ")));
|
|
227
|
-
}
|
|
228
|
-
card.append(next);
|
|
229
|
-
return card;
|
|
102
|
+
export function disclosure(title, viewKey, options) {
|
|
103
|
+
const opts = options || {};
|
|
104
|
+
const element = h("details.disclosure" + (opts.className ? "." + opts.className : ""));
|
|
105
|
+
if (viewKey) element.dataset.viewKey = viewKey;
|
|
106
|
+
const summary = h("summary", null, icon("chevron", "disclosure-chevron"), h("span.disclosure-title", null, title));
|
|
107
|
+
if (opts.meta) summary.append(h("span.disclosure-meta", null, opts.meta));
|
|
108
|
+
element.append(summary);
|
|
109
|
+
const body = h("div.disclosure-body");
|
|
110
|
+
element.append(body);
|
|
111
|
+
element.body = body;
|
|
112
|
+
return element;
|
|
230
113
|
}
|
|
231
114
|
|
|
232
|
-
export function
|
|
233
|
-
|
|
234
|
-
|
|
115
|
+
export function sectionTitle(text, count, actions) {
|
|
116
|
+
return h("div.section-title", null, h("h2", null, text,
|
|
117
|
+
count !== undefined && count !== null ? h("span.count", null, String(count)) : null),
|
|
118
|
+
actions ? h("div.section-actions", null, actions) : null);
|
|
235
119
|
}
|
|
236
120
|
|
|
237
|
-
function
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return tile;
|
|
121
|
+
export function kv(rows) {
|
|
122
|
+
const list = h("dl.kv");
|
|
123
|
+
rows.forEach(function (row) {
|
|
124
|
+
if (!row || row[1] === undefined || row[1] === null || row[1] === "") return;
|
|
125
|
+
list.append(h("dt", null, row[0]), h("dd", null, row[1]));
|
|
126
|
+
});
|
|
127
|
+
return list;
|
|
245
128
|
}
|
|
246
129
|
|
|
247
|
-
export function
|
|
248
|
-
|
|
249
|
-
const card = node("div", "observability-metrics");
|
|
250
|
-
const cost = observability.cost || {};
|
|
251
|
-
const context = observability.context || {};
|
|
252
|
-
card.append(usageTile(t("detail.tokens"), cost.tokens, t));
|
|
253
|
-
card.append(usageTile(t("detail.toolCalls"), cost.toolCalls, t));
|
|
254
|
-
card.append(usageTile(t("detail.elapsed"), cost.elapsedSeconds, t, "s"));
|
|
255
|
-
card.append(usageTile(t("detail.executionSum"), cost.executionSeconds, t, "s"));
|
|
256
|
-
card.append(metricTile(t("detail.ready"), (observability.dag?.readyIds || []).length, { hot: true }));
|
|
257
|
-
card.append(metricTile(t("detail.contextSnapshots"), context.snapshotCount));
|
|
258
|
-
const contextMeta = node("div", "record-meta observability-context-meta");
|
|
259
|
-
contextMeta.append(node("span", "", t("detail.usageScope")));
|
|
260
|
-
contextMeta.append(node("span", "", t("detail.observedThrough") + " · "
|
|
261
|
-
+ (cost.observedThrough ? formatDateTime(cost.observedThrough) : t("detail.unobserved"))));
|
|
262
|
-
contextMeta.append(node("span", "", t("detail.contextBytes") + " · "
|
|
263
|
-
+ (context.totalBytes === null ? t("detail.partial") : context.totalBytes + " B")));
|
|
264
|
-
contextMeta.append(node("span", "", t("detail.compression") + " · " + t("detail.unavailable")));
|
|
265
|
-
contextMeta.append(node("span", "", t("detail.marginalValue") + " · " + t("detail.unavailable")));
|
|
266
|
-
card.append(contextMeta);
|
|
267
|
-
return card;
|
|
130
|
+
export function emptyState(text, iconName, extra) {
|
|
131
|
+
return h("div.empty", null, iconName ? icon(iconName) : null, h("p", null, text), extra || null);
|
|
268
132
|
}
|
|
269
133
|
|
|
270
|
-
export function
|
|
271
|
-
|
|
272
|
-
const graph = node("div", "dag-graph");
|
|
273
|
-
const edgeByTarget = {};
|
|
274
|
-
(dag.edges || []).forEach(function (edge) {
|
|
275
|
-
if (!edgeByTarget[edge.to]) edgeByTarget[edge.to] = [];
|
|
276
|
-
edgeByTarget[edge.to].push(edge);
|
|
277
|
-
});
|
|
278
|
-
dag.nodes.forEach(function (item) {
|
|
279
|
-
const row = node("div", "dag-node is-" + item.projectedStatus);
|
|
280
|
-
const top = node("div", "dag-node-head");
|
|
281
|
-
top.append(statusDot(item.projectedStatus), node("strong", "dag-node-title", item.title));
|
|
282
|
-
top.append(pill(t, "dag", item.projectedStatus));
|
|
283
|
-
if ((dag.readyIds || []).indexOf(item.id) >= 0) top.append(chip(t("dag.ready"), "is-active"));
|
|
284
|
-
row.append(top);
|
|
285
|
-
const edges = edgeByTarget[item.id] || [];
|
|
286
|
-
if (edges.length) {
|
|
287
|
-
const deps = node("div", "dag-node-deps");
|
|
288
|
-
deps.append(node("small", "", t("dag.dependsOn")));
|
|
289
|
-
edges.forEach(function (edge) {
|
|
290
|
-
deps.append(chip(edge.from + " · " + t("dag.edge." + edge.status), "is-" + edge.status));
|
|
291
|
-
});
|
|
292
|
-
row.append(deps);
|
|
293
|
-
}
|
|
294
|
-
if (item.rootCauseIds && item.rootCauseIds.length) {
|
|
295
|
-
row.append(node("small", "dag-root-cause", t("dag.rootCause") + " · " + item.rootCauseIds.join(" ← ")));
|
|
296
|
-
}
|
|
297
|
-
graph.append(row);
|
|
298
|
-
});
|
|
299
|
-
return graph;
|
|
134
|
+
export function note(text, toneName) {
|
|
135
|
+
return h("p.note" + (toneName ? ".tone-" + toneName : ""), null, text);
|
|
300
136
|
}
|
|
301
137
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
.forEach(function (candidate) {
|
|
310
|
-
const row = node("div", "candidate-row");
|
|
311
|
-
row.append(node("span", "candidate-seq", "#" + candidate.sequence));
|
|
312
|
-
row.append(node("span", "candidate-summary", candidate.summary));
|
|
313
|
-
const source = candidate.source.type === "direct"
|
|
314
|
-
? t("candidate.source.direct")
|
|
315
|
-
: t("candidate.source.run") + " " + candidate.source.runId;
|
|
316
|
-
row.append(node("span", "candidate-source", source));
|
|
317
|
-
row.append(node("time", "", formatDateTime(candidate.createdAt, locale)));
|
|
318
|
-
list.append(row);
|
|
319
|
-
});
|
|
320
|
-
block.append(list);
|
|
321
|
-
return block;
|
|
138
|
+
export function button(text, options) {
|
|
139
|
+
const opts = options || {};
|
|
140
|
+
const element = h("button.btn" + (opts.variant ? ".btn-" + opts.variant : ""), {
|
|
141
|
+
type: opts.type || "button", onclick: opts.onClick, disabled: !!opts.disabled, title: opts.title
|
|
142
|
+
}, opts.icon ? icon(opts.icon) : null, text ? h("span", null, text) : null);
|
|
143
|
+
if (opts.dataset) Object.assign(element.dataset, opts.dataset);
|
|
144
|
+
return element;
|
|
322
145
|
}
|
|
323
146
|
|
|
324
|
-
// ---
|
|
325
|
-
// Re-render is cheap and happens whenever the underlying data changes, so all
|
|
326
|
-
// disclosure state (collapsed blocks, visible pages) is deliberately
|
|
327
|
-
// deterministic per render: long content starts collapsed and expanding is a
|
|
328
|
-
// pure local toggle.
|
|
147
|
+
// --- Rich text ---------------------------------------------------------------------
|
|
329
148
|
function shouldCollapse(text, threshold) {
|
|
330
|
-
const limit = threshold || 700;
|
|
331
149
|
const value = String(text);
|
|
332
|
-
if (value.length >
|
|
150
|
+
if (value.length > (threshold || 700)) return true;
|
|
333
151
|
let lines = 0;
|
|
334
|
-
for (let
|
|
335
|
-
if (value[i] === "\\n") lines += 1;
|
|
336
|
-
}
|
|
152
|
+
for (let index = 0; index < value.length; index += 1) if (value[index] === "\n") lines += 1;
|
|
337
153
|
return lines > 12;
|
|
338
154
|
}
|
|
339
155
|
|
|
340
|
-
function
|
|
341
|
-
block.classList.add("is-collapsible", "is-collapsed");
|
|
342
|
-
const toggle = node("button", "md-toggle", t("actions.showMore"));
|
|
343
|
-
toggle.type = "button";
|
|
344
|
-
toggle.addEventListener("click", function () {
|
|
345
|
-
const collapsed = block.classList.toggle("is-collapsed");
|
|
346
|
-
toggle.textContent = collapsed ? t("actions.showMore") : t("actions.showLess");
|
|
347
|
-
});
|
|
348
|
-
block.append(toggle);
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Rich text block: small label + Markdown body, auto-collapsed when long.
|
|
352
|
-
export function richText(label, text, t, options) {
|
|
156
|
+
export function richText(title, text, t, options) {
|
|
353
157
|
if (!text) return null;
|
|
354
|
-
const
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const body = node("div", "md" + (options && options.muted ? " muted" : ""));
|
|
158
|
+
const opts = options || {};
|
|
159
|
+
const block = h("div.prose-block" + (opts.className ? "." + opts.className : ""));
|
|
160
|
+
if (title) block.append(h("h4.prose-label", null, title));
|
|
161
|
+
const body = h("div.md" + (opts.muted ? ".muted" : ""));
|
|
359
162
|
body.innerHTML = renderMarkdown(text);
|
|
360
163
|
block.append(body);
|
|
361
|
-
if (shouldCollapse(text,
|
|
164
|
+
if (shouldCollapse(text, opts.threshold)) {
|
|
165
|
+
block.classList.add("is-collapsed");
|
|
166
|
+
const toggle = h("button.link-btn", { type: "button" }, t("actions.showMore"));
|
|
167
|
+
toggle.addEventListener("click", function () {
|
|
168
|
+
const collapsed = block.classList.toggle("is-collapsed");
|
|
169
|
+
toggle.textContent = t(collapsed ? "actions.showMore" : "actions.showLess");
|
|
170
|
+
});
|
|
171
|
+
block.append(toggle);
|
|
172
|
+
}
|
|
362
173
|
return block;
|
|
363
174
|
}
|
|
364
175
|
|
|
365
|
-
|
|
366
|
-
|
|
176
|
+
export function bulletList(items, className) {
|
|
177
|
+
const list = (items || []).filter(Boolean);
|
|
178
|
+
if (!list.length) return null;
|
|
179
|
+
return h("ul.bullets" + (className ? "." + className : ""), null, list.map(function (item) { return h("li", null, item); }));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// First page of a long list plus an in-place "show more".
|
|
367
183
|
export function pagedList(container, items, pageSize, renderItem, t) {
|
|
368
184
|
let shown = 0;
|
|
369
185
|
let more = null;
|
|
370
186
|
function renderChunk() {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const remaining = items.length - shown;
|
|
378
|
-
if (remaining <= 0) {
|
|
379
|
-
more.remove();
|
|
380
|
-
more = null;
|
|
381
|
-
} else {
|
|
382
|
-
more.textContent = t("actions.showRemaining").replace("{count}", String(remaining));
|
|
383
|
-
}
|
|
384
|
-
}
|
|
187
|
+
items.slice(shown, shown + pageSize).forEach(function (item) { container.insertBefore(renderItem(item), more); });
|
|
188
|
+
shown = Math.min(items.length, shown + pageSize);
|
|
189
|
+
if (!more) return;
|
|
190
|
+
const remaining = items.length - shown;
|
|
191
|
+
if (remaining <= 0) { more.remove(); more = null; }
|
|
192
|
+
else more.textContent = t("actions.showRemaining").replace("{count}", String(remaining));
|
|
385
193
|
}
|
|
386
194
|
if (items.length > pageSize) {
|
|
387
|
-
more =
|
|
388
|
-
more.type = "button";
|
|
389
|
-
more.addEventListener("click", renderChunk);
|
|
195
|
+
more = h("button.show-more", { type: "button", onclick: renderChunk });
|
|
390
196
|
container.append(more);
|
|
391
197
|
}
|
|
392
198
|
renderChunk();
|
|
393
199
|
}
|
|
394
200
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
list.forEach(function (item) {
|
|
402
|
-
const li = node("li", "");
|
|
403
|
-
li.innerHTML = inlineMarkdown(escapeHtml(item));
|
|
404
|
-
listElement.append(li);
|
|
405
|
-
});
|
|
406
|
-
block.append(listElement);
|
|
407
|
-
if (list.length > 6) collapseToggle(block, t);
|
|
408
|
-
return block;
|
|
201
|
+
// --- Metrics (DOM built with node() only; executed by the usage test) -------------
|
|
202
|
+
export function metricTile(labelText, value, options) {
|
|
203
|
+
const variant = options && options.tone ? " tone-" + options.tone : "";
|
|
204
|
+
const tile = node("div", "metric" + variant);
|
|
205
|
+
tile.append(node("span", "metric-label", labelText), node("strong", "metric-value", String(value)));
|
|
206
|
+
return tile;
|
|
409
207
|
}
|
|
410
208
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return
|
|
414
|
-
? message.author.roleName
|
|
415
|
-
: t("author." + message.author.type);
|
|
209
|
+
export function usageMetricText(metric, t, suffix) {
|
|
210
|
+
if (!metric || metric.value == null) return t("detail.unobserved");
|
|
211
|
+
return metric.value + (suffix || "") + (metric.status === "partial" ? " · " + t("detail.partial") : "");
|
|
416
212
|
}
|
|
417
213
|
|
|
418
|
-
function
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
214
|
+
function usageTile(labelText, metric, t, suffix) {
|
|
215
|
+
const tile = metricTile(labelText, usageMetricText(metric, t, suffix));
|
|
216
|
+
if (metric && metric.reasons && metric.reasons.length) {
|
|
217
|
+
tile.append(node("small", "metric-note", metric.reasons.map(function (reason) {
|
|
218
|
+
return t("usage.reason." + reason);
|
|
219
|
+
}).join("; ")));
|
|
220
|
+
}
|
|
221
|
+
return tile;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function observabilityMetricCard(observability, t) {
|
|
225
|
+
if (!observability) return null;
|
|
226
|
+
const wrap = node("div", "usage");
|
|
227
|
+
const grid = node("div", "metric-grid");
|
|
228
|
+
const cost = observability.cost || {};
|
|
229
|
+
const context = observability.context || {};
|
|
230
|
+
grid.append(usageTile(t("usage.tokens"), cost.tokens, t));
|
|
231
|
+
grid.append(usageTile(t("usage.toolCalls"), cost.toolCalls, t));
|
|
232
|
+
grid.append(usageTile(t("usage.elapsed"), cost.elapsedSeconds, t, "s"));
|
|
233
|
+
grid.append(usageTile(t("usage.executionSum"), cost.executionSeconds, t, "s"));
|
|
234
|
+
grid.append(metricTile(t("usage.ready"), ((observability.dag && observability.dag.readyIds) || []).length));
|
|
235
|
+
grid.append(metricTile(t("usage.contextSnapshots"), context.snapshotCount == null ? t("detail.unobserved") : context.snapshotCount));
|
|
236
|
+
wrap.append(grid);
|
|
237
|
+
const meta = node("p", "usage-meta");
|
|
238
|
+
meta.append(node("span", "", t("usage.scope")));
|
|
239
|
+
meta.append(node("span", "", t("usage.observedThrough") + " "
|
|
240
|
+
+ (cost.observedThrough ? formatDateTime(cost.observedThrough) : t("detail.unobserved"))));
|
|
241
|
+
meta.append(node("span", "", t("usage.contextBytes") + " "
|
|
242
|
+
+ (context.totalBytes == null ? t("detail.partial") : context.totalBytes + " B")));
|
|
243
|
+
wrap.append(meta);
|
|
244
|
+
return wrap;
|
|
422
245
|
}
|
|
423
246
|
|
|
424
|
-
// ---
|
|
425
|
-
function
|
|
426
|
-
|
|
247
|
+
// --- Agent identity ------------------------------------------------------------------
|
|
248
|
+
export function agentChips(agent) {
|
|
249
|
+
if (!agent) return null;
|
|
250
|
+
const chips = [];
|
|
251
|
+
if (agent.adapterId || agent.component) chips.push(chip(agentLabel(agent.component, agent.adapterId), "chip-strong"));
|
|
252
|
+
if (agent.model) chips.push(chip(agent.model));
|
|
253
|
+
if (agent.effort) chips.push(chip(agent.effort));
|
|
254
|
+
return chips.length ? h("span.chip-row", null, chips) : null;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- Input requests ----------------------------------------------------------------
|
|
258
|
+
export function inputCard(input, t, locale, onAnswer) {
|
|
259
|
+
const policy = input.policy && input.policy.kind;
|
|
260
|
+
const element = h("article.input-card");
|
|
261
|
+
element.append(h("div.input-head", null,
|
|
262
|
+
h("span.input-kicker", null, icon("inbox", "icon-sm"), t("input.kicker")),
|
|
263
|
+
policy ? badge(label(t, "input", policy), policy === "required" ? "bad" : "warn") : null,
|
|
264
|
+
input.policy && input.policy.timeoutAt
|
|
265
|
+
? h("span.input-timeout", null, icon("clock", "icon-sm"),
|
|
266
|
+
t("input.timeoutAt") + " " + relativeTime(input.policy.timeoutAt, locale, t)) : null,
|
|
267
|
+
timeTag(input.createdAt, locale, t)));
|
|
268
|
+
element.append(h("p.input-question", null, input.question));
|
|
269
|
+
const facts = [];
|
|
270
|
+
if (input.requester) facts.push(t("input.from") + " " + input.requester.roleName
|
|
271
|
+
+ " · " + (input.requester.runId || input.requester.nativeSessionId || ""));
|
|
272
|
+
if (input.blockedRefs && input.blockedRefs.length) facts.push(t("input.blocks") + " "
|
|
273
|
+
+ input.blockedRefs.map(function (ref) { return ref.type + " " + ref.id; }).join(", "));
|
|
274
|
+
if (facts.length) element.append(h("p.input-facts", null, facts.join(" · ")));
|
|
275
|
+
const recommended = input.policy && input.policy.recommendedChoiceKey;
|
|
427
276
|
if (input.choices && input.choices.length) {
|
|
428
|
-
input.choices.
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
answers.append(button);
|
|
435
|
-
});
|
|
277
|
+
element.append(h("div.input-choices", null, input.choices.map(function (choice) {
|
|
278
|
+
return h("button.choice" + (choice.key === recommended ? ".is-recommended" : ""), {
|
|
279
|
+
type: "button",
|
|
280
|
+
onclick: function (event) { onAnswer(input, { choiceKey: choice.key }, event.currentTarget); }
|
|
281
|
+
}, h("span", null, choice.label), choice.key === recommended ? badge(t("input.recommended"), "accent") : null);
|
|
282
|
+
})));
|
|
436
283
|
} else {
|
|
437
|
-
const
|
|
438
|
-
const
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
field.placeholder = t("input.freeText");
|
|
442
|
-
const submit = node("button", "input-answer", t("actions.answer"));
|
|
443
|
-
submit.type = "submit";
|
|
444
|
-
form.append(field, submit);
|
|
284
|
+
const field = h("input", { type: "text", required: true, placeholder: t("input.freeText"), maxLength: 8000 });
|
|
285
|
+
const form = h("form.input-form", null, field,
|
|
286
|
+
h("button.btn.btn-primary", { type: "submit" }, icon("send"), h("span", null, t("actions.answer"))));
|
|
287
|
+
form.addEventListener("input", function () { form.dataset.unsent = field.value ? "true" : "false"; });
|
|
445
288
|
form.addEventListener("submit", function (event) {
|
|
446
289
|
event.preventDefault();
|
|
447
290
|
const text = field.value.trim();
|
|
448
|
-
if (text
|
|
291
|
+
if (text) onAnswer(input, { text: text }, form.querySelector("button"));
|
|
449
292
|
});
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
return answers;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
export function inputCard(input, _options, t, locale, actions) {
|
|
456
|
-
const card = node("article", "input-card");
|
|
457
|
-
const top = node("div", "input-card-top");
|
|
458
|
-
top.append(node("small", "", t("detail.openInput")));
|
|
459
|
-
const question = node("p", "input-question", input.question);
|
|
460
|
-
top.append(question);
|
|
461
|
-
const context = node("div", "input-context");
|
|
462
|
-
if (input.policy) {
|
|
463
|
-
if (input.policy.kind === "recommended") {
|
|
464
|
-
context.append(pill(t, "input", "recommended"));
|
|
465
|
-
if (input.policy.timeoutAt) {
|
|
466
|
-
context.append(node("span", "", t("input.timeoutAt") + " · " + relativeTime(input.policy.timeoutAt, locale, t)));
|
|
467
|
-
}
|
|
468
|
-
} else {
|
|
469
|
-
context.append(pill(t, "input", "required"));
|
|
470
|
-
}
|
|
293
|
+
element.append(form);
|
|
471
294
|
}
|
|
472
|
-
|
|
473
|
-
top.append(context);
|
|
474
|
-
if (input.blockedRefs && input.blockedRefs.length) {
|
|
475
|
-
const blocked = input.blockedRefs.map(function (ref) { return ref.type + "·" + ref.id; }).join(" ");
|
|
476
|
-
top.append(node("span", "input-blocked", blocked));
|
|
477
|
-
}
|
|
478
|
-
if (input.requester) {
|
|
479
|
-
top.append(node("span", "input-requester",
|
|
480
|
-
t("detail.requester") + " · " + input.requester.roleName + " / " + (input.requester.runId ?? input.requester.nativeSessionId)));
|
|
481
|
-
}
|
|
482
|
-
card.append(top);
|
|
483
|
-
card.append(answerActions(input, actions, t));
|
|
484
|
-
return card;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// --- Conclusion band ------------------------------------------------------------
|
|
488
|
-
export function conclusionMeta(task, t, locale, kind) {
|
|
489
|
-
const meta = node("div", "conclusion-meta");
|
|
490
|
-
const actor = kind === "archived" ? task.archivedBy
|
|
491
|
-
: kind === "cancelled" ? task.retiredBy
|
|
492
|
-
: task.completedBy;
|
|
493
|
-
const at = kind === "archived" ? task.archivedAt
|
|
494
|
-
: kind === "cancelled" ? task.retiredAt
|
|
495
|
-
: task.completedAt;
|
|
496
|
-
const label = kind === "archived" ? t("detail.archivedBy")
|
|
497
|
-
: kind === "cancelled" ? t("detail.cancelledBy")
|
|
498
|
-
: t("detail.completedBy");
|
|
499
|
-
if (actor) meta.append(node("span", "", label + " · " + authorName(t, actor)));
|
|
500
|
-
if (at) meta.append(node("time", "", formatDateTime(at, locale)));
|
|
501
|
-
return meta;
|
|
295
|
+
return element;
|
|
502
296
|
}
|
|
503
297
|
|
|
504
|
-
// ---
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
const body = node("div", "work-item-body");
|
|
522
|
-
const meta = node("div", "record-meta");
|
|
523
|
-
if (item.assignee) meta.append(node("span", "meta-name", item.assignee));
|
|
524
|
-
meta.append(node("span", "mono", item.id));
|
|
525
|
-
meta.append(node("time", "", formatDateTime(item.updatedAt, locale)));
|
|
526
|
-
if (item.endedAt) {
|
|
527
|
-
meta.append(node("span", "", t("detail.endedAt") + " · " + formatDateTime(item.endedAt, locale)));
|
|
528
|
-
}
|
|
529
|
-
body.append(meta);
|
|
530
|
-
|
|
531
|
-
if (item.objective && item.objective !== item.title) {
|
|
532
|
-
body.append(richText(t("detail.objective"), item.objective, t));
|
|
533
|
-
}
|
|
298
|
+
// --- Records -----------------------------------------------------------------------
|
|
299
|
+
export function workItemCard(item, t, locale, titles) {
|
|
300
|
+
const settled = item.status !== "open";
|
|
301
|
+
const element = h(settled ? "details.work-card.is-settled" : "article.work-card");
|
|
302
|
+
element.dataset.viewKey = "work:" + item.id;
|
|
303
|
+
const head = h(settled ? "summary.work-head" : "header.work-head", null,
|
|
304
|
+
settled ? icon("chevron", "disclosure-chevron") : null,
|
|
305
|
+
dot(tone("work", item.status)),
|
|
306
|
+
h("span.work-title", null, item.title),
|
|
307
|
+
statusBadge(t, "work", "work", item.status));
|
|
308
|
+
element.append(head);
|
|
309
|
+
const body = h("div.work-body");
|
|
310
|
+
body.append(h("div.meta-line", null,
|
|
311
|
+
item.assignee ? h("span.meta-strong", null, icon("user", "icon-sm"), item.assignee) : null,
|
|
312
|
+
mono(item.id), timeTag(item.updatedAt, locale, t)));
|
|
313
|
+
if (item.objective && item.objective !== item.title) body.append(richText(t("work.objective"), item.objective, t));
|
|
534
314
|
if (item.acceptance && item.acceptance.length) {
|
|
535
|
-
body.append(
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
// text blocks above and below stay full-width so the card reads top-to-bottom
|
|
540
|
-
// like an issue rather than a mismatched column grid.
|
|
541
|
-
const chipCols = node("div", "work-item-chips");
|
|
542
|
-
if (item.dependsOn && item.dependsOn.length) {
|
|
543
|
-
chipCols.append(chipRow(t("detail.dependsOn"), item.dependsOn.map(function (id) { return titles[id] || id; })));
|
|
315
|
+
body.append(h("div.prose-block", null, h("h4.prose-label", null, t("work.acceptance")),
|
|
316
|
+
h("ul.checklist", null, item.acceptance.map(function (entry) {
|
|
317
|
+
return h("li" + (item.status === "accepted" ? ".is-done" : ""), null, icon(item.status === "accepted" ? "check" : "target", "icon-sm"), h("span", null, entry));
|
|
318
|
+
}))));
|
|
544
319
|
}
|
|
320
|
+
const deps = (item.dependsOn || []).map(function (id) { return (titles && titles[id]) || id; });
|
|
321
|
+
if (deps.length) body.append(h("div.meta-line", null, h("span.meta-label", null, t("work.dependsOn")), deps.map(function (d) { return chip(d); })));
|
|
545
322
|
if (item.writeProjectIds && item.writeProjectIds.length) {
|
|
546
|
-
|
|
323
|
+
body.append(h("div.meta-line", null, h("span.meta-label", null, t("work.writeProjects")), item.writeProjectIds.map(function (d) { return chip(d); })));
|
|
547
324
|
}
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
const observability = item.observability;
|
|
556
|
-
const metrics = node("div", "record-meta work-item-observability");
|
|
557
|
-
metrics.append(usageTile(t("detail.tokens"), observability.cost.tokens, t));
|
|
558
|
-
metrics.append(usageTile(t("detail.toolCalls"), observability.cost.toolCalls, t));
|
|
559
|
-
metrics.append(usageTile(t("detail.executionSum"), observability.cost.executionSeconds, t, "s"));
|
|
560
|
-
metrics.append(node("span", "", t("detail.contextSnapshots") + " · "
|
|
561
|
-
+ observability.context.snapshotCount));
|
|
562
|
-
metrics.append(node("span", "", t("detail.results") + " · "
|
|
563
|
-
+ (observability.resultCount == null
|
|
564
|
-
? t("detail.unobserved")
|
|
565
|
-
: observability.resultCount)));
|
|
566
|
-
body.append(metrics);
|
|
325
|
+
if (item.candidates && item.candidates.length) {
|
|
326
|
+
body.append(h("div.prose-block", null, h("h4.prose-label", null, t("work.candidates")),
|
|
327
|
+
h("ol.candidates", null, item.candidates.slice().sort(function (a, b) { return b.sequence - a.sequence; }).map(function (candidate) {
|
|
328
|
+
return h("li", null, h("span.candidate-seq", null, "#" + candidate.sequence), h("span", null, candidate.summary),
|
|
329
|
+
h("span.faint", null, candidate.source && candidate.source.type === "run" ? candidate.source.runId : t("work.direct")),
|
|
330
|
+
timeTag(candidate.createdAt, locale, t));
|
|
331
|
+
}))));
|
|
567
332
|
}
|
|
568
|
-
|
|
569
|
-
// Review candidates submitted for this WorkItem, newest first.
|
|
570
|
-
const candidates = candidateList(item.candidates, t, locale);
|
|
571
|
-
if (candidates) body.append(candidates);
|
|
572
|
-
|
|
573
|
-
// Explicit Leader retirement disposition.
|
|
574
333
|
if (item.disposition) {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
const text = item.disposition.summary
|
|
578
|
-
+ (item.disposition.replacementWorkItemId
|
|
579
|
-
? " · " + t("detail.replacementWorkItem") + " " + item.disposition.replacementWorkItemId
|
|
580
|
-
: "");
|
|
581
|
-
disposition.append(node("p", "muted", text));
|
|
582
|
-
body.append(disposition);
|
|
334
|
+
body.append(note(t("work.disposition") + ": " + item.disposition.summary
|
|
335
|
+
+ (item.disposition.replacementWorkItemId ? " → " + item.disposition.replacementWorkItemId : "")));
|
|
583
336
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
}
|
|
588
|
-
card.append(body);
|
|
589
|
-
return card;
|
|
337
|
+
if (item.outcome) body.append(richText(t("work.outcome"), item.outcome, t, { className: "callout" }));
|
|
338
|
+
element.append(body);
|
|
339
|
+
return element;
|
|
590
340
|
}
|
|
591
341
|
|
|
592
342
|
export function runCard(run, t, locale) {
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
if (run.result
|
|
613
|
-
card.append(richText(t("detail.outcome"), run.result.output, t, { className: "execute-io outcome", threshold: 320 }));
|
|
614
|
-
}
|
|
615
|
-
if (run.result?.diagnostic) {
|
|
616
|
-
card.append(richText(t("detail.failure"), run.result.diagnostic, t, { className: "execute-io outcome", threshold: 320 }));
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
const foot = node("div", "execute-foot");
|
|
620
|
-
const tags = node("div", "execute-tags");
|
|
621
|
-
tags.append(chip(t("mode." + run.mode)));
|
|
343
|
+
const element = h("article.run-card");
|
|
344
|
+
element.dataset.status = run.status;
|
|
345
|
+
const input = run.inputs && run.inputs.length ? run.inputs[0].input : null;
|
|
346
|
+
element.append(h("header.run-head", null,
|
|
347
|
+
dot(tone("run", run.status)),
|
|
348
|
+
h("span.run-role", null, run.roleName),
|
|
349
|
+
mono(run.id),
|
|
350
|
+
run.purpose ? chip(label(t, "run.purpose", run.purpose)) : null,
|
|
351
|
+
run.workItemId ? chip(run.workItemId) : null,
|
|
352
|
+
h("span.spacer"),
|
|
353
|
+
statusBadge(t, "run", "run", run.status)));
|
|
354
|
+
element.append(h("div.meta-line", null,
|
|
355
|
+
h("span", null, t("run.delivery") + ": " + label(t, "run.delivery", (run.execution && run.execution.delivery) || "unobserved")),
|
|
356
|
+
run.mode ? h("span", null, label(t, "mode", run.mode)) : null,
|
|
357
|
+
timeTag((run.result && run.result.completedAt) || run.updatedAt, locale, t),
|
|
358
|
+
agentChips(run.effective || (run.agentId ? run : null))));
|
|
359
|
+
const directive = input && (input.directive || input.action);
|
|
360
|
+
if (directive) element.append(richText(t("run.instruction"), directive, t, { threshold: 320 }));
|
|
361
|
+
if (run.result && run.result.output) element.append(richText(t("run.output"), run.result.output, t, { threshold: 320, className: "callout" }));
|
|
362
|
+
if (run.result && run.result.diagnostic) element.append(richText(t("run.failure"), run.result.diagnostic, t, { threshold: 320, className: "callout.tone-bad" }));
|
|
622
363
|
if (run.executionGroupId) {
|
|
623
|
-
|
|
624
|
-
+ (run.executionLaneId ? "/" + run.executionLaneId : "")));
|
|
625
|
-
}
|
|
626
|
-
const badge = run.effective ? agentBadge(run.effective) : (run.agentId ? agentBadge(run) : null);
|
|
627
|
-
if (badge) tags.append(badge);
|
|
628
|
-
foot.append(tags);
|
|
629
|
-
foot.append(pill(t, "run", run.status));
|
|
630
|
-
card.append(foot);
|
|
631
|
-
|
|
632
|
-
if (run.effective) {
|
|
633
|
-
const eff = node("div", "record-meta");
|
|
634
|
-
eff.append(node("span", "", t("detail.effective") + " · r" + run.effective.sourceDesiredRevision));
|
|
635
|
-
eff.append(node("span", "", t("detail.profileIntent") + " · " + run.effective.profileAccess));
|
|
636
|
-
eff.append(node("span", "", t("detail.permission") + " · " + run.effective.permission.strategy));
|
|
637
|
-
card.append(eff);
|
|
364
|
+
element.append(h("p.faint.mono-line", null, t("run.lineage") + " " + run.executionGroupId + (run.executionLaneId ? "/" + run.executionLaneId : "")));
|
|
638
365
|
}
|
|
639
|
-
|
|
640
|
-
return card;
|
|
366
|
+
return element;
|
|
641
367
|
}
|
|
642
368
|
|
|
643
369
|
export function reviewCard(round, t, locale) {
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (round.workItemId && round.candidateId) {
|
|
660
|
-
meta.append(node("span", "mono", round.workItemId + " · " + round.candidateId));
|
|
661
|
-
}
|
|
662
|
-
if (round.createdAt) meta.append(node("time", "", formatDateTime(round.createdAt, locale)));
|
|
663
|
-
meta.append(node("span", "", t("detail.reviewBase") + " · " + round.reviewBaseCommit));
|
|
664
|
-
if (round.workspace && round.workspace.root) {
|
|
665
|
-
meta.append(pathMetaItem(t("detail.workspace"), round.workspace.root));
|
|
666
|
-
}
|
|
667
|
-
if (round.reviewerRunId) {
|
|
668
|
-
meta.append(node("span", "mono", t("detail.reviewerRun") + " · " + round.reviewerRunId));
|
|
669
|
-
}
|
|
670
|
-
if (round.workspaceDisposition) {
|
|
671
|
-
meta.append(node("span", "", t("detail.workspaceDisposition") + " · "
|
|
672
|
-
+ t("disposition." + round.workspaceDisposition.kind)));
|
|
673
|
-
}
|
|
674
|
-
card.append(meta);
|
|
675
|
-
if (round.executionGroup) {
|
|
676
|
-
const group = round.executionGroup;
|
|
677
|
-
const execution = node("div", "record-block exec-group");
|
|
678
|
-
const groupMeta = node("div", "record-meta execution-resource-meta");
|
|
679
|
-
groupMeta.append(node("span", "mono", group.id));
|
|
680
|
-
groupMeta.append(node("span", "", t("reviewExec.assignment") + " · "
|
|
681
|
-
+ group.assignment.contextSnapshotRef.id));
|
|
682
|
-
groupMeta.append(node("span", "", t("reviewExec.main") + " · "
|
|
683
|
-
+ (round.reviewerRunId || t("detail.unobserved"))));
|
|
684
|
-
execution.append(groupMeta);
|
|
685
|
-
const lanes = node("div", "lane-list");
|
|
686
|
-
group.lanes.forEach(function (lane) {
|
|
687
|
-
const row = node("div", "lane-row");
|
|
688
|
-
row.append(statusDot(lane.disposition === "open" ? "running" : lane.disposition));
|
|
689
|
-
row.append(node("span", "lane-role", t("reviewExec.producer") + " " + lane.ordinal
|
|
690
|
-
+ " · " + lane.roleName));
|
|
691
|
-
row.append(node("span", "lane-status", t("reviewExec.status." + lane.disposition)));
|
|
692
|
-
row.append(node("span", "mono", lane.currentRunId || t("detail.unobserved")));
|
|
693
|
-
lanes.append(row);
|
|
694
|
-
});
|
|
695
|
-
execution.append(lanes);
|
|
696
|
-
card.append(execution);
|
|
697
|
-
}
|
|
698
|
-
if (round.failure) {
|
|
699
|
-
card.append(richText(
|
|
700
|
-
t("detail.failure"),
|
|
701
|
-
round.failure.kind + ": " + round.failure.message,
|
|
702
|
-
t
|
|
703
|
-
));
|
|
704
|
-
}
|
|
705
|
-
return card;
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
export function roleCard(role, task, t, locale, actions) {
|
|
709
|
-
const card = node("article", "record-card");
|
|
710
|
-
const head = node("div", "record-head");
|
|
711
|
-
head.append(node("strong", "record-title", role.name));
|
|
712
|
-
const headRight = node("div", "record-pills");
|
|
713
|
-
headRight.append(pill(t, "role", role.status));
|
|
714
|
-
const open = node("button", "record-open", "");
|
|
715
|
-
open.type = "button";
|
|
716
|
-
open.append(node("span", "", t("actions.openSession")), node("span", "arrow", "→"));
|
|
717
|
-
open.addEventListener("click", function () {
|
|
718
|
-
if (actions.openTerminal) actions.openTerminal({ scope: "task", taskId: task.id, roleName: role.name });
|
|
719
|
-
});
|
|
720
|
-
headRight.append(open);
|
|
721
|
-
head.append(headRight);
|
|
722
|
-
card.append(head);
|
|
723
|
-
|
|
724
|
-
const meta = node("div", "record-meta");
|
|
725
|
-
meta.append(node("span", "meta-name", role.activeAgentId));
|
|
726
|
-
const activeBinding = role.agentBindings && role.agentBindings[role.activeAgentId];
|
|
727
|
-
if (activeBinding) {
|
|
728
|
-
const badge = agentBadge({
|
|
729
|
-
adapterId: activeBinding.adapterId,
|
|
730
|
-
component: activeBinding.component,
|
|
731
|
-
model: activeBinding.config && activeBinding.config.model,
|
|
732
|
-
effort: activeBinding.config && activeBinding.config.effort
|
|
733
|
-
});
|
|
734
|
-
if (badge) meta.append(badge);
|
|
735
|
-
}
|
|
736
|
-
if (role.launchRevision !== undefined) {
|
|
737
|
-
meta.append(node("span", "", t("detail.desired") + " · r" + role.launchRevision));
|
|
738
|
-
}
|
|
739
|
-
if (role.defaultAccess !== undefined) {
|
|
740
|
-
meta.append(node("span", "", t("detail.profileIntent") + " · " + role.defaultAccess));
|
|
741
|
-
}
|
|
742
|
-
if (role.updatedAt) meta.append(node("time", "", formatDateTime(role.updatedAt, locale)));
|
|
743
|
-
card.append(meta);
|
|
744
|
-
|
|
745
|
-
if (role.effectiveLaunch) {
|
|
746
|
-
const eff = node("div", "record-meta");
|
|
747
|
-
eff.append(node("span", "", t("detail.effectiveAgent") + " · " + role.effectiveLaunch.agentId));
|
|
748
|
-
const effBadge = agentBadge(role.effectiveLaunch);
|
|
749
|
-
if (effBadge) eff.append(effBadge);
|
|
750
|
-
if (role.effectiveLaunch.sourceDesiredRevision !== undefined) {
|
|
751
|
-
eff.append(node("span", "", t("detail.effective") + " · r" + role.effectiveLaunch.sourceDesiredRevision));
|
|
752
|
-
}
|
|
753
|
-
if (role.effectiveLaunch.profileAccess !== undefined) {
|
|
754
|
-
eff.append(node("span", "", t("detail.profileIntent") + " · " + role.effectiveLaunch.profileAccess));
|
|
755
|
-
}
|
|
756
|
-
if (role.effectiveLaunch.permission && role.effectiveLaunch.permission.strategy !== undefined) {
|
|
757
|
-
eff.append(node("span", "", t("detail.permission") + " · " + role.effectiveLaunch.permission.strategy));
|
|
758
|
-
}
|
|
759
|
-
eff.append(node("span", "", role.launchDrift ? t("launch.drift") : t("launch.current")));
|
|
760
|
-
card.append(eff);
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (role.providerRetry) {
|
|
764
|
-
const retry = role.providerRetry;
|
|
765
|
-
const retryMeta = node("p", "record-meta");
|
|
766
|
-
const zh = locale.startsWith("zh");
|
|
767
|
-
const labels = zh ? {
|
|
768
|
-
waiting: "等待 Provider 重试", "in-flight": "Provider 重试已提交",
|
|
769
|
-
recovered: "Provider 已恢复", cancelled: "自动重试已取消",
|
|
770
|
-
exhausted: "自动重试预算耗尽", "needs-attention": "需要检查 Provider",
|
|
771
|
-
"delivery-unknown": "投递结果未知,禁止重放"
|
|
772
|
-
} : {
|
|
773
|
-
waiting: "Waiting for Provider retry", "in-flight": "Provider retry submitted",
|
|
774
|
-
recovered: "Provider recovered", cancelled: "Automatic retry cancelled",
|
|
775
|
-
exhausted: "Automatic retry budget exhausted", "needs-attention": "Provider needs attention",
|
|
776
|
-
"delivery-unknown": "Delivery unknown; no replay"
|
|
777
|
-
};
|
|
778
|
-
retryMeta.textContent = (labels[retry.status] || retry.status) + " · "
|
|
779
|
-
+ (zh && retry.category === "rate-limit" ? "临时限流" : retry.category) + " · "
|
|
780
|
-
+ retry.attempts + "/" + retry.limit
|
|
781
|
-
+ (retry.status === "waiting" ? " · " + new Date(retry.nextEligibleAt).toLocaleString(locale) : "")
|
|
782
|
-
+ " · " + (zh ? "原成果保留" : "Existing work preserved")
|
|
783
|
-
+ (retry.reason ? " · " + retry.reason : "");
|
|
784
|
-
card.append(retryMeta);
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
if (role.sessionTokens) {
|
|
788
|
-
const tokenMeta = node("div", "record-meta");
|
|
789
|
-
const cumulative = role.sessionTokens.cumulativeTotal || {};
|
|
790
|
-
const maximum = role.sessionTokens.maximumRequestInput || {};
|
|
791
|
-
tokenMeta.append(node("span", "", t("detail.sessionTotalTokens") + " · "
|
|
792
|
-
+ (cumulative.status === "observed" ? cumulative.totalTokens : t("detail.unobserved"))));
|
|
793
|
-
tokenMeta.append(node("span", "", t("detail.maximumRequestInputTokens") + " · "
|
|
794
|
-
+ (maximum.status === "observed" ? maximum.inputTokens : t("detail.unobserved"))));
|
|
795
|
-
card.append(tokenMeta);
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
if (role.description) card.append(richText(null, role.description, t, { muted: true }));
|
|
799
|
-
|
|
800
|
-
const cols = node("div", "record-cols");
|
|
801
|
-
const bindingIds = role.agentBindings ? Object.keys(role.agentBindings) : [];
|
|
802
|
-
if (bindingIds.length > 1) {
|
|
803
|
-
const bindings = bindingIds.map(function (id) {
|
|
804
|
-
const binding = role.agentBindings[id];
|
|
805
|
-
const model = binding.config && binding.config.model;
|
|
806
|
-
return componentLabel(binding.component, binding.adapterId) + (model ? " · " + model : "");
|
|
807
|
-
});
|
|
808
|
-
const activeBindingLabel = activeBinding
|
|
809
|
-
? componentLabel(activeBinding.component, activeBinding.adapterId) + (activeBinding.config && activeBinding.config.model ? " · " + activeBinding.config.model : "")
|
|
810
|
-
: undefined;
|
|
811
|
-
cols.append(chipRow(t("detail.agents"), bindings, activeBindingLabel));
|
|
812
|
-
}
|
|
813
|
-
if (role.skills && role.skills.length) cols.append(chipRow(t("detail.skills"), role.skills));
|
|
814
|
-
if (role.responsibilities && role.responsibilities.length) cols.append(criteriaList(t("detail.responsibilities"), role.responsibilities, t));
|
|
815
|
-
if (role.constraints && role.constraints.length) cols.append(criteriaList(t("detail.constraints"), role.constraints, t));
|
|
816
|
-
if (role.expectedOutput) cols.append(richText(t("detail.expectedOutput"), role.expectedOutput, t, { muted: true }));
|
|
817
|
-
if (cols.childNodes.length) card.append(cols);
|
|
818
|
-
|
|
819
|
-
if (role.workspace) {
|
|
820
|
-
const workspaceMeta = node("div", "record-meta");
|
|
821
|
-
workspaceMeta.append(pathMetaItem(t("detail.workspace"), role.workspace));
|
|
822
|
-
card.append(workspaceMeta);
|
|
823
|
-
}
|
|
824
|
-
return card;
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
export function historyEventRow(event, t, locale) {
|
|
828
|
-
if (event.kind === "milestone") {
|
|
829
|
-
const milestone = event.item;
|
|
830
|
-
const card = node("article", "record-card");
|
|
831
|
-
const head = node("div", "record-head");
|
|
832
|
-
const titleRow = node("div", "record-title-row");
|
|
833
|
-
titleRow.append(node("strong", "record-title", milestone.title));
|
|
834
|
-
head.append(titleRow);
|
|
835
|
-
head.append(pill(t, "history", "milestone"));
|
|
836
|
-
card.append(head);
|
|
837
|
-
const meta = node("div", "record-meta");
|
|
838
|
-
meta.append(node("span", "mono", milestone.id));
|
|
839
|
-
meta.append(node("time", "", formatDateTime(milestone.createdAt, locale)));
|
|
840
|
-
card.append(meta);
|
|
841
|
-
if (milestone.summary) card.append(richText(null, milestone.summary, t, { muted: true }));
|
|
842
|
-
return card;
|
|
843
|
-
}
|
|
844
|
-
const decision = event.item;
|
|
845
|
-
const card = node("article", "record-card");
|
|
846
|
-
const head = node("div", "record-head");
|
|
847
|
-
const titleRow = node("div", "record-title-row");
|
|
848
|
-
titleRow.append(node("strong", "record-title", decision.title));
|
|
849
|
-
head.append(titleRow);
|
|
850
|
-
head.append(pill(t, "history", "decision"));
|
|
851
|
-
card.append(head);
|
|
852
|
-
const meta = node("div", "record-meta");
|
|
853
|
-
meta.append(node("span", "mono", decision.id));
|
|
854
|
-
if (decision.createdAt) meta.append(node("time", "", formatDateTime(decision.createdAt, locale)));
|
|
855
|
-
if (decision.status) meta.append(pill(t, "decision", decision.status));
|
|
856
|
-
card.append(meta);
|
|
857
|
-
if (decision.rationale) card.append(richText(null, decision.rationale, t, { muted: true }));
|
|
858
|
-
if (decision.supersededReason) card.append(richText(null, decision.supersededReason, t, { muted: true }));
|
|
859
|
-
return card;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
export function messageCard(message, t, locale, result) {
|
|
863
|
-
const card = node("article", "record-card");
|
|
864
|
-
const head = node("div", "record-head");
|
|
865
|
-
const titleRow = node("div", "record-title-row");
|
|
866
|
-
titleRow.append(node("strong", "record-title", messageAuthor(message, t)));
|
|
867
|
-
head.append(titleRow);
|
|
868
|
-
if (message.kind) head.append(pill(t, "messageKind", message.kind));
|
|
869
|
-
if (message.status) head.append(pill(t, "status", message.status));
|
|
870
|
-
card.append(head);
|
|
871
|
-
|
|
872
|
-
const meta = node("div", "record-meta");
|
|
873
|
-
meta.append(node("span", "mono", message.id));
|
|
874
|
-
meta.append(node("time", "", formatDateTime(message.createdAt, locale)));
|
|
875
|
-
if (message.runId) meta.append(node("span", "mono", message.runId + (message.workItemId ? " · " + message.workItemId : "")));
|
|
876
|
-
if (message.recipient) {
|
|
877
|
-
meta.append(node("span", "mono", "→ " + message.recipient.roleName + " · "
|
|
878
|
-
+ (message.recipient.reviewRoundId || message.recipient.workItemId)));
|
|
879
|
-
meta.append(node("span", "mono", !message.recipient.ownerRunId ? t("messageDelivery.notification") : message.continuation?.runId
|
|
880
|
-
? t("messageDelivery.run") + " " + message.continuation.runId
|
|
881
|
-
: message.continuation?.notDeliveredReason
|
|
882
|
-
? t("messageDelivery.blocked") + " " + message.continuation.notDeliveredReason
|
|
883
|
-
: t("messageDelivery.pending")));
|
|
884
|
-
}
|
|
885
|
-
card.append(meta);
|
|
886
|
-
|
|
887
|
-
card.append(richText(null, message.body, t));
|
|
888
|
-
if (message.resultRef) {
|
|
889
|
-
card.append(node("small", "mono", message.resultRef.runId));
|
|
890
|
-
if (result?.output) card.append(richText(t("detail.outcome"), result.output, t));
|
|
891
|
-
if (result?.diagnostic) card.append(richText(t("detail.failure"), result.diagnostic, t));
|
|
892
|
-
if (!result) card.append(node("p", "muted", t("detail.unobserved")));
|
|
893
|
-
}
|
|
894
|
-
return card;
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// --- Overview + sidebar rows --------------------------------------------------
|
|
898
|
-
export function metricTile(label, value, options) {
|
|
899
|
-
const variant = options && options.hot ? " is-hot" : options && options.warning ? " is-warning" : "";
|
|
900
|
-
const tile = node("article", "metric" + variant);
|
|
901
|
-
tile.append(node("span", "metric-label", label), node("strong", "metric-value", String(value)));
|
|
902
|
-
return tile;
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
export function attentionRow(item, t, locale, onSelect) {
|
|
906
|
-
const row = node("button", "inbox-row");
|
|
907
|
-
row.type = "button";
|
|
908
|
-
const request = item.request || {};
|
|
909
|
-
const kind = request.policy && request.policy.kind === "required" ? "required"
|
|
910
|
-
: request.policy && request.policy.kind === "recommended" ? "recommended"
|
|
911
|
-
: null;
|
|
912
|
-
|
|
913
|
-
const lead = node("span", "inbox-lead");
|
|
914
|
-
lead.append(node("span", "inbox-dot"));
|
|
915
|
-
const head = node("span", "inbox-head");
|
|
916
|
-
head.append(node("span", "inbox-task", item.taskTitle));
|
|
917
|
-
if (kind) head.append(pill(t, "input", kind));
|
|
918
|
-
lead.append(head);
|
|
919
|
-
row.append(lead);
|
|
920
|
-
|
|
921
|
-
if (request.question) {
|
|
922
|
-
const question = node("span", "inbox-question", request.question);
|
|
923
|
-
question.title = request.question;
|
|
924
|
-
row.append(question);
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
const foot = node("span", "inbox-foot");
|
|
928
|
-
if (request.createdAt) foot.append(node("time", "", relativeTime(request.createdAt, locale, t)));
|
|
929
|
-
foot.append(node("span", "inbox-go", t("actions.answer") + " →"));
|
|
930
|
-
row.append(foot);
|
|
931
|
-
|
|
932
|
-
row.addEventListener("click", function () { onSelect(item.taskId); });
|
|
933
|
-
return row;
|
|
370
|
+
const element = h("article.review-card");
|
|
371
|
+
element.append(h("header.run-head", null,
|
|
372
|
+
dot(tone("review", round.status)),
|
|
373
|
+
h("span.run-role", null, round.reviewerRoleName || t("review.reviewer")),
|
|
374
|
+
mono(round.id),
|
|
375
|
+
round.scope ? chip(label(t, "review.scope", round.scope)) : null,
|
|
376
|
+
h("span.spacer"),
|
|
377
|
+
statusBadge(t, "review", "review", round.status)));
|
|
378
|
+
element.append(h("div.meta-line", null,
|
|
379
|
+
round.workItemId ? mono(round.workItemId + (round.candidateId ? " · " + round.candidateId : "")) : null,
|
|
380
|
+
round.reviewBaseCommit ? h("span", null, t("review.base") + " ", mono(String(round.reviewBaseCommit).slice(0, 12))) : null,
|
|
381
|
+
round.reviewerRunId ? h("span", null, t("review.run") + " ", mono(round.reviewerRunId)) : null,
|
|
382
|
+
timeTag(round.createdAt, locale, t)));
|
|
383
|
+
if (round.failure) element.append(note(round.failure.kind + ": " + round.failure.message, "bad"));
|
|
384
|
+
return element;
|
|
934
385
|
}
|
|
935
386
|
|
|
936
|
-
export function
|
|
937
|
-
const
|
|
938
|
-
const
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
387
|
+
export function roleCard(role, t, locale, options) {
|
|
388
|
+
const opts = options || {};
|
|
389
|
+
const session = opts.runtimeRole && opts.runtimeRole.runtimeSession;
|
|
390
|
+
const element = h("article.role-card");
|
|
391
|
+
const binding = role.agentBindings && role.agentBindings[role.activeAgentId];
|
|
392
|
+
element.append(h("header.role-head", null,
|
|
393
|
+
h("span.avatar", { "aria-hidden": "true" }, String(role.name || "?").slice(0, 1).toUpperCase()),
|
|
394
|
+
h("div.role-title", null, h("strong", null, role.name),
|
|
395
|
+
h("span.faint", null, role.activeAgentId || "")),
|
|
396
|
+
opts.status ? statusBadge(t, "role", "role", opts.status) : null));
|
|
397
|
+
if (binding) element.append(agentChips({
|
|
398
|
+
adapterId: binding.adapterId, component: binding.component,
|
|
399
|
+
model: binding.config && binding.config.model, effort: binding.config && binding.config.effort
|
|
400
|
+
}));
|
|
401
|
+
if (role.description) element.append(richText(null, role.description, t, { muted: true, threshold: 280 }));
|
|
402
|
+
const rows = [];
|
|
403
|
+
rows.push([t("role.session"), session && session.nativeSessionId ? mono(session.nativeSessionId) : t("role.noSession")]);
|
|
404
|
+
if (role.launchRevision !== undefined) rows.push([t("role.desired"), "r" + role.launchRevision + (opts.launchDrift ? " · " + t("role.drift") : "")]);
|
|
405
|
+
if (role.defaultAccess !== undefined) rows.push([t("role.access"), role.defaultAccess]);
|
|
406
|
+
if (opts.retry) rows.push([t("role.providerRetry"), label(t, "retry", opts.retry.status) + " · "
|
|
407
|
+
+ opts.retry.attempts + "/" + opts.retry.limit
|
|
408
|
+
+ (opts.retry.status === "waiting" && opts.retry.nextEligibleAt ? " · " + formatDateTime(opts.retry.nextEligibleAt, locale) : "")]);
|
|
409
|
+
if (role.skills && role.skills.length) rows.push([t("role.skills"), h("span.chip-row", null, role.skills.map(function (s) { return chip(s); }))]);
|
|
410
|
+
element.append(kv(rows));
|
|
411
|
+
if (opts.onOpen) {
|
|
412
|
+
element.append(h("div.role-actions", null, button(t("role.openSession"), {
|
|
413
|
+
icon: "terminal", variant: "ghost", onClick: function () { opts.onOpen(role.name); }
|
|
414
|
+
})));
|
|
947
415
|
}
|
|
948
|
-
|
|
949
|
-
row.addEventListener("click", function () { onSelect(task.id); });
|
|
950
|
-
return row;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
export function taskCard(task, hasAttention, state, t, locale, onSelect) {
|
|
954
|
-
const button = node("button", "task");
|
|
955
|
-
button.type = "button";
|
|
956
|
-
button.dataset.id = task.id;
|
|
957
|
-
button.setAttribute("aria-current", String(state.selected === task.id));
|
|
958
|
-
|
|
959
|
-
button.append(statusDot(task.status));
|
|
960
|
-
|
|
961
|
-
const main = node("span", "task-main");
|
|
962
|
-
main.append(node("strong", "task-title", task.title));
|
|
963
|
-
main.append(node("span", "task-meta", relativeTime(task.updatedAt, locale, t)));
|
|
964
|
-
button.append(main);
|
|
965
|
-
|
|
966
|
-
// Derived Task-first execution status for active tasks (blocked, waiting on
|
|
967
|
-
// agents, recovering, etc.) — a richer signal than the raw lifecycle status.
|
|
968
|
-
if (task.executionStatus && task.status === "active") {
|
|
969
|
-
const exec = node("span", "task-exec is-" + task.executionStatus,
|
|
970
|
-
t("exec.status." + task.executionStatus));
|
|
971
|
-
button.append(exec);
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
// One signal only: an open input (needs the user) outranks a running count.
|
|
975
|
-
if (hasAttention || (task.attention && task.attention.openInputs > 0)) {
|
|
976
|
-
const badge = node("span", "task-signal is-input", String(task.attention ? task.attention.openInputs : task.openInputCount || 1));
|
|
977
|
-
badge.title = t("stats.inputs");
|
|
978
|
-
button.append(badge);
|
|
979
|
-
} else if (task.attention && task.attention.executionSignals > 0) {
|
|
980
|
-
const badge = node("span", "task-signal", String(task.attention.executionSignals));
|
|
981
|
-
badge.title = t("catalog.executionSignals");
|
|
982
|
-
button.append(badge);
|
|
983
|
-
} else if (task.workItems && task.workItems.running > 0) {
|
|
984
|
-
const badge = node("span", "task-signal is-running", String(task.workItems.running));
|
|
985
|
-
badge.title = t("stats.running");
|
|
986
|
-
button.append(badge);
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
button.addEventListener("click", function () { onSelect(task.id); });
|
|
990
|
-
return button;
|
|
416
|
+
return element;
|
|
991
417
|
}
|
|
992
418
|
`;
|