@hydraharness/harness-client-ui-cordis 0.1.1-rc.6

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/lib/client.js ADDED
@@ -0,0 +1,1399 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "@hydraharness/harness-client-ui-cordis",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react_jsx_runtime = require("react/jsx-runtime");
8
+ let _hydraharness_harness_client_ui_primitives = require("@hydraharness/harness-client-ui-primitives");
9
+ let react = require("react");
10
+ //#region lib/types/client/card-model.js
11
+ /** Replay-stable view models for Cordis lifecycle Tool calls. */
12
+ function firstLine(text) {
13
+ const newline = text.indexOf("\n");
14
+ return newline === -1 ? text : text.slice(0, newline);
15
+ }
16
+ function stringAt(source, key) {
17
+ const value = source[key];
18
+ return typeof value === "string" && value !== "" ? value : null;
19
+ }
20
+ function objectAt(source, key) {
21
+ const value = source[key];
22
+ return typeof value === "object" && value !== null ? value : null;
23
+ }
24
+ function parseArgs(argsRaw) {
25
+ try {
26
+ const parsed = JSON.parse(argsRaw);
27
+ return typeof parsed === "object" && parsed !== null ? parsed : null;
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+ function resultText(block) {
33
+ const text = block.content.map((item) => item.type === "text" ? item.text : JSON.stringify(item, null, 2)).join("\n");
34
+ if (text !== "") return text;
35
+ return block.error === void 0 ? null : `${block.error.name}: ${block.error.code}`;
36
+ }
37
+ function stateOf(block) {
38
+ if (!("kind" in block)) return "running";
39
+ if (block.error?.code === "interrupted") return "stopped";
40
+ return block.isError ? "error" : "ok";
41
+ }
42
+ function metaObject(block) {
43
+ if (!("kind" in block) || block.isError || typeof block.meta !== "object" || block.meta === null) return null;
44
+ return block.meta;
45
+ }
46
+ /**
47
+ * Derive one Define card from its frozen call/result slice.
48
+ * @param block - active or settled tool-call block.
49
+ * @returns normalized Define card fields.
50
+ */
51
+ function cordisDefineCard(block) {
52
+ const settled = "kind" in block;
53
+ const argsRaw = (settled ? block.call?.argsRaw : block.argsRaw) ?? "";
54
+ const args = parseArgs(argsRaw);
55
+ const code = args === null ? null : objectAt(args, "code");
56
+ const state = stateOf(block);
57
+ const output = settled ? resultText(block) : null;
58
+ const meta = metaObject(block);
59
+ const rawName = argsRaw === "" ? null : firstLine(argsRaw);
60
+ return {
61
+ pluginId: meta === null ? null : stringAt(meta, "pluginId"),
62
+ packageId: meta === null ? null : stringAt(meta, "packageId"),
63
+ name: args === null ? rawName : stringAt(args, "name") ?? rawName,
64
+ purpose: args === null ? null : stringAt(args, "purpose"),
65
+ hostCode: code === null ? null : stringAt(code, "host"),
66
+ clientCode: code === null ? null : stringAt(code, "client"),
67
+ output,
68
+ errorSummary: state === "error" && output !== null ? firstLine(output) : null,
69
+ state
70
+ };
71
+ }
72
+ /**
73
+ * Derive one Run card and its successful activation metadata.
74
+ * @param block - active or settled tool-call block.
75
+ * @returns normalized Run card fields.
76
+ */
77
+ function cordisRunCard(block) {
78
+ const settled = "kind" in block;
79
+ const args = parseArgs((settled ? block.call?.argsRaw : block.argsRaw) ?? "");
80
+ const meta = metaObject(block);
81
+ const state = stateOf(block);
82
+ const output = settled ? resultText(block) : null;
83
+ const rawMode = args === null ? null : stringAt(args, "mode");
84
+ const argsPluginId = args === null ? null : stringAt(args, "pluginId");
85
+ const argsPackageId = args === null ? null : stringAt(args, "packageId");
86
+ return {
87
+ pluginId: meta === null ? argsPluginId : stringAt(meta, "pluginId") ?? argsPluginId,
88
+ packageId: meta === null ? argsPackageId : stringAt(meta, "packageId") ?? argsPackageId,
89
+ pluginRunId: meta === null ? null : stringAt(meta, "pluginRunId"),
90
+ mode: rawMode === "run" || rawMode === "update" ? rawMode : null,
91
+ seq: settled ? block.seq : null,
92
+ output,
93
+ errorSummary: state === "error" && output !== null ? firstLine(output) : null,
94
+ state
95
+ };
96
+ }
97
+ /**
98
+ * Derive one Stop or Remove card from its frozen call/result slice.
99
+ * @param block - active or settled tool-call block.
100
+ * @returns normalized lifecycle-action card fields.
101
+ */
102
+ function cordisActionCard(block) {
103
+ const settled = "kind" in block;
104
+ const args = parseArgs((settled ? block.call?.argsRaw : block.argsRaw) ?? "");
105
+ const state = stateOf(block);
106
+ const output = settled ? resultText(block) : null;
107
+ return {
108
+ pluginId: args === null ? null : stringAt(args, "pluginId") ?? stringAt(args, "id"),
109
+ output,
110
+ errorSummary: state === "error" && output !== null ? firstLine(output) : null,
111
+ state
112
+ };
113
+ }
114
+ //#endregion
115
+ //#region \0hydra-css:/home/runner/work/Hydra-Harness/Hydra-Harness/packages/extensions/ui-cordis/src/client/CordisRunRow.module.css.mjs
116
+ const css$2 = ".KUgU6q_card{flex-direction:column;gap:8px;display:flex}.KUgU6q_row{align-items:center;min-height:32px;display:flex}.KUgU6q_icon{color:var(--dsw-alias-state-business-primary);flex:none;margin-right:8px;display:inline-flex}.KUgU6q_title{color:var(--dsw-alias-state-business-primary);flex:none;font-size:14px;font-weight:500;line-height:24px}.KUgU6q_separator{background:var(--dsw-alias-state-business-primary);border-radius:50%;flex:none;width:2px;height:2px;margin:0 8px}.KUgU6q_summary,.KUgU6q_error{min-width:0;color:var(--dsw-alias-label-secondary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;line-height:24px;overflow:hidden}.KUgU6q_error{color:var(--dsw-alias-state-error-primary)}.KUgU6q_status{color:var(--dsw-alias-label-caption);flex:none;margin-left:8px;font-size:12px;line-height:24px}.KUgU6q_card[data-cordis-status=awaiting-approval] .KUgU6q_status,.KUgU6q_card[data-cordis-status=client-pending] .KUgU6q_status{color:var(--dsw-alias-state-warn-label)}.KUgU6q_card[data-cordis-status=running] .KUgU6q_status{color:var(--dsw-alias-state-success-primary)}.KUgU6q_card[data-cordis-status=failed] .KUgU6q_status{color:var(--dsw-alias-state-error-primary)}.KUgU6q_inspect{width:24px;height:24px;color:var(--dsw-alias-label-tertiary);cursor:pointer;opacity:0;background:0 0;border:none;border-radius:999px;justify-content:center;align-items:center;margin-left:4px;padding:0;display:inline-flex}.KUgU6q_card:hover .KUgU6q_inspect,.KUgU6q_inspect:focus-visible{opacity:1}.KUgU6q_inspect:hover{background:var(--dsw-alias-interactive-bg-hover)}.KUgU6q_message{background:var(--dsw-alias-button-ghost-active-fill);color:var(--dsw-alias-label-tertiary);border-radius:8px;padding:8px 12px;font-size:12px;line-height:18px}.KUgU6q_business{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);border-radius:12px;min-width:0;overflow:hidden}.KUgU6q_output{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-secondary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px;margin:0;padding:10px 12px;overflow:auto}.KUgU6q_business .KUgU6q_output{border:none;border-radius:0}";
117
+ const tagId$2 = "@hydraharness/harness-client-ui-cordis/CordisRunRow.module.css";
118
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
119
+ const tag = document.createElement("style");
120
+ tag.dataset.plugin = "@hydraharness/harness-client-ui-cordis";
121
+ tag.dataset.pluginCss = tagId$2;
122
+ tag.textContent = css$2;
123
+ document.head.appendChild(tag);
124
+ }
125
+ var CordisRunRow_module_css_default = {
126
+ "business": "KUgU6q_business",
127
+ "card": "KUgU6q_card",
128
+ "error": "KUgU6q_error",
129
+ "icon": "KUgU6q_icon",
130
+ "inspect": "KUgU6q_inspect",
131
+ "message": "KUgU6q_message",
132
+ "output": "KUgU6q_output",
133
+ "row": "KUgU6q_row",
134
+ "separator": "KUgU6q_separator",
135
+ "status": "KUgU6q_status",
136
+ "summary": "KUgU6q_summary",
137
+ "title": "KUgU6q_title"
138
+ };
139
+ //#endregion
140
+ //#region lib/types/client/CordisActionRow.js
141
+ /** Localized cards for `cordis_stop` and `cordis_undefine`. */
142
+ /** Render one Stop or Remove call with Cordis-owned localized copy. */
143
+ function CordisActionRow({ callId, toolName, block, inspect, t }) {
144
+ const card = cordisActionCard(block);
145
+ const remove = toolName === "cordis_undefine";
146
+ const summary = card.errorSummary ?? card.pluginId ?? callId;
147
+ return (0, react_jsx_runtime.jsxs)("div", {
148
+ className: CordisRunRow_module_css_default.card,
149
+ "data-tool": toolName,
150
+ "data-state": card.state,
151
+ children: [(0, react_jsx_runtime.jsxs)("div", {
152
+ className: CordisRunRow_module_css_default.row,
153
+ children: [
154
+ (0, react_jsx_runtime.jsx)("span", {
155
+ className: CordisRunRow_module_css_default.icon,
156
+ children: card.state === "error" ? (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "error" }) : card.state === "stopped" ? (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "warning" }) : remove ? (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconTrashOutline16, { size: 14 }) : (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconStopFill16, { size: 14 })
157
+ }),
158
+ (0, react_jsx_runtime.jsx)("span", {
159
+ className: CordisRunRow_module_css_default.title,
160
+ children: t(remove ? "row.removeTitle" : "row.stopTitle")
161
+ }),
162
+ (0, react_jsx_runtime.jsx)("span", {
163
+ className: CordisRunRow_module_css_default.separator,
164
+ "aria-hidden": true
165
+ }),
166
+ (0, react_jsx_runtime.jsx)("span", {
167
+ className: card.errorSummary === null ? CordisRunRow_module_css_default.summary : CordisRunRow_module_css_default.error,
168
+ children: summary
169
+ }),
170
+ inspect !== void 0 && (0, react_jsx_runtime.jsx)("button", {
171
+ type: "button",
172
+ className: CordisRunRow_module_css_default.inspect,
173
+ "aria-label": "Inspect",
174
+ onClick: inspect,
175
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconInspectOutline12, {})
176
+ })
177
+ ]
178
+ }), card.output !== null && (0, react_jsx_runtime.jsx)("pre", {
179
+ className: CordisRunRow_module_css_default.output,
180
+ children: card.output
181
+ })]
182
+ });
183
+ }
184
+ //#endregion
185
+ //#region lib/types/client/status.js
186
+ /** Shared status derivation over Host inventory and this page's Client live set. */
187
+ /**
188
+ * Locate one immutable Package inside a Plugin row.
189
+ * @param row - owning Plugin inventory row.
190
+ * @param packageId - immutable Package identity to locate.
191
+ * @returns the matching Package metadata, or `undefined` when absent.
192
+ */
193
+ function packageOf(row, packageId) {
194
+ return row.packages.find((pkg) => pkg.packageId === packageId);
195
+ }
196
+ /**
197
+ * Derive the visible state of one Package.
198
+ * @param row - owning Plugin inventory row.
199
+ * @param packageId - Package being described.
200
+ * @param loaded - Client activations loaded in this page.
201
+ * @returns idle, Host-running/Client-pending, or fully running.
202
+ */
203
+ function cordisVisibleStatus(row, packageId, loaded) {
204
+ const run = row.activeRun;
205
+ if (run === void 0 || run.packageId !== packageId) return "idle";
206
+ if (packageOf(row, packageId)?.hasClientHalf !== true) return "running";
207
+ return loaded.some((live) => live.pluginId === row.pluginId && live.packageId === packageId && live.pluginRunId === run.pluginRunId) ? "running" : "client-pending";
208
+ }
209
+ //#endregion
210
+ //#region \0hydra-css:/home/runner/work/Hydra-Harness/Hydra-Harness/packages/extensions/ui-cordis/src/client/CordisDefineRow.module.css.mjs
211
+ const css$1 = ".G_Xl3q_card{flex-direction:column;display:flex}.G_Xl3q_card .G_Xl3q_title,.G_Xl3q_card .G_Xl3q_chevron{color:var(--dsw-alias-state-business-primary)}.G_Xl3q_title{flex:none;font-size:14px;font-weight:500;line-height:24px}.G_Xl3q_row{gap:0}.G_Xl3q_separator{background:var(--dsw-alias-state-business-primary);border-radius:1px;flex:none;width:2px;height:2px;margin:0 8px}.G_Xl3q_name{text-overflow:ellipsis;white-space:nowrap;max-width:40%;color:var(--dsw-alias-label-secondary);flex:none;font-size:14px;line-height:24px;overflow:hidden}.G_Xl3q_purpose{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-tertiary);flex:auto;margin-left:8px;font-size:13px;line-height:24px;overflow:hidden}.G_Xl3q_errorSummary{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-state-error-primary);flex:auto;font-size:14px;line-height:24px;overflow:hidden}.G_Xl3q_requestError{text-overflow:ellipsis;white-space:nowrap;max-width:40%;color:var(--dsw-alias-state-error-primary);flex:none;margin-left:8px;font-size:12px;line-height:24px;overflow:hidden}.G_Xl3q_readout{flex:none;align-items:center;margin-left:8px;display:inline-flex}.G_Xl3q_panelHint{color:var(--dsw-alias-label-caption);margin:4px 0 2px 4px;font-size:11px;line-height:16px}.G_Xl3q_statusLabel{color:var(--dsw-alias-label-caption);font-size:12px;line-height:24px}.G_Xl3q_approvalPrompt{text-overflow:ellipsis;white-space:nowrap;max-width:40%;color:var(--dsw-alias-label-secondary);flex:none;margin-left:8px;font-size:12px;line-height:24px;overflow:hidden}.G_Xl3q_notice{text-overflow:ellipsis;white-space:nowrap;max-width:40%;color:var(--dsw-alias-label-caption);flex:none;margin-left:8px;font-size:12px;line-height:24px;overflow:hidden}.G_Xl3q_switch{height:22px;padding:0 8px;font-size:12px}.G_Xl3q_card[data-terminal] .G_Xl3q_title,.G_Xl3q_card[data-terminal] .G_Xl3q_name,.G_Xl3q_card[data-terminal] .G_Xl3q_purpose,.G_Xl3q_card[data-terminal] .G_Xl3q_statusLabel{color:var(--dsw-alias-label-caption)}.G_Xl3q_card[data-terminal] .G_Xl3q_separator{background:var(--dsw-alias-label-caption)}.G_Xl3q_bodyWrap{flex-direction:column;display:flex}.G_Xl3q_sourceCard{flex-direction:column;margin:4px 0 4px 4px;display:flex}.G_Xl3q_sourceTabs{border-bottom:1px solid var(--dsw-alias-border-l2);height:32px;display:flex}.G_Xl3q_sourceTab{color:var(--dsw-alias-label-tertiary);cursor:pointer;font:var(--dsw-font-xs-13);background:0 0;border:0;padding:0 10px;position:relative}.G_Xl3q_sourceTab:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.G_Xl3q_sourceTab:disabled{cursor:default;opacity:.4}.G_Xl3q_sourceTabActive{color:var(--dsw-alias-state-business-primary)}.G_Xl3q_sourceTabActive:after{background:var(--dsw-alias-state-business-primary);content:\"\";border-radius:1px 1px 0 0;height:2px;position:absolute;bottom:0;left:10px;right:10px}.G_Xl3q_sourceTab:focus-visible{outline:1px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.G_Xl3q_sourcePanel{max-height:260px;overflow:auto}.G_Xl3q_sourceCode{margin:0}.G_Xl3q_codeSection{flex-direction:column;max-height:260px;margin:4px 0 4px 4px;display:flex;overflow:auto}.G_Xl3q_sectionLabel{color:var(--dsw-alias-label-caption);text-transform:uppercase;letter-spacing:.04em;flex:none;padding:2px 0;font-size:11px;font-weight:500;line-height:16px}.G_Xl3q_output{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-markdown-code-block);white-space:pre-wrap;overflow-wrap:anywhere;font:var(--dsw-font-markdown-code-block-small);color:var(--dsw-alias-label-secondary);border-radius:8px;margin:0;padding:8px 10px}.G_Xl3q_output[data-error]{color:var(--dsw-alias-state-error-primary)}.G_Xl3q_inspectButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-secondary);cursor:pointer;opacity:0;border-radius:999px;align-self:flex-start;align-items:center;gap:4px;margin:4px 0 2px 4px;padding:2px 8px;font-size:11px;line-height:16px;transition:opacity .1s;display:inline-flex}.G_Xl3q_card:hover .G_Xl3q_inspectButton,.G_Xl3q_inspectButton:focus-visible{opacity:1}.G_Xl3q_inspectButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.G_Xl3q_visuallyHidden{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.G_Xl3q_inspectButton{transition:none}}";
212
+ const tagId$1 = "@hydraharness/harness-client-ui-cordis/CordisDefineRow.module.css";
213
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
214
+ const tag = document.createElement("style");
215
+ tag.dataset.plugin = "@hydraharness/harness-client-ui-cordis";
216
+ tag.dataset.pluginCss = tagId$1;
217
+ tag.textContent = css$1;
218
+ document.head.appendChild(tag);
219
+ }
220
+ var CordisDefineRow_module_css_default = {
221
+ "approvalPrompt": "G_Xl3q_approvalPrompt",
222
+ "bodyWrap": "G_Xl3q_bodyWrap",
223
+ "card": "G_Xl3q_card",
224
+ "chevron": "G_Xl3q_chevron",
225
+ "codeSection": "G_Xl3q_codeSection",
226
+ "errorSummary": "G_Xl3q_errorSummary",
227
+ "inspectButton": "G_Xl3q_inspectButton",
228
+ "name": "G_Xl3q_name",
229
+ "notice": "G_Xl3q_notice",
230
+ "output": "G_Xl3q_output",
231
+ "panelHint": "G_Xl3q_panelHint",
232
+ "purpose": "G_Xl3q_purpose",
233
+ "readout": "G_Xl3q_readout",
234
+ "requestError": "G_Xl3q_requestError",
235
+ "row": "G_Xl3q_row",
236
+ "sectionLabel": "G_Xl3q_sectionLabel",
237
+ "separator": "G_Xl3q_separator",
238
+ "sourceCard": "G_Xl3q_sourceCard",
239
+ "sourceCode": "G_Xl3q_sourceCode",
240
+ "sourcePanel": "G_Xl3q_sourcePanel",
241
+ "sourceTab": "G_Xl3q_sourceTab",
242
+ "sourceTabActive": "G_Xl3q_sourceTabActive",
243
+ "sourceTabs": "G_Xl3q_sourceTabs",
244
+ "statusLabel": "G_Xl3q_statusLabel",
245
+ "switch": "G_Xl3q_switch",
246
+ "title": "G_Xl3q_title",
247
+ "visuallyHidden": "G_Xl3q_visuallyHidden"
248
+ };
249
+ //#endregion
250
+ //#region lib/types/client/CordisDefineRow.js
251
+ /** Read-only `cordis_define` card with Host and Client source tabs. */
252
+ const READING_LABELS$1 = {
253
+ idle: "status.idle",
254
+ "client-pending": "status.clientPending",
255
+ running: "status.running",
256
+ removed: "status.removed"
257
+ };
258
+ function stateStatus(state) {
259
+ switch (state) {
260
+ case "running": return "a11y.defining";
261
+ case "error": return "a11y.failed";
262
+ case "stopped": return "a11y.stopped";
263
+ default: return null;
264
+ }
265
+ }
266
+ function leadingFor(state) {
267
+ switch (state) {
268
+ case "error": return (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "error" });
269
+ case "stopped": return (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "warning" });
270
+ default: return (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCodeOutline16, { size: 14 });
271
+ }
272
+ }
273
+ /** Render one immutable Package definition. */
274
+ function CordisDefineRow({ callId, block, inspect, useInventory, useLoaded, t }) {
275
+ const card = cordisDefineCard(block);
276
+ const inventory = useInventory((snapshot) => snapshot);
277
+ const loaded = useLoaded((snapshot) => snapshot);
278
+ const [expanded, setExpanded] = (0, react.useState)(false);
279
+ const [selectedSource, setSelectedSource] = (0, react.useState)(card.clientCode !== null ? "client" : "host");
280
+ const sourcePanelId = (0, react.useId)();
281
+ const row = card.pluginId === null ? void 0 : inventory.rows.find((candidate) => candidate.pluginId === card.pluginId);
282
+ const reading = card.pluginId !== null && inventory.removed.has(card.pluginId) ? "removed" : row !== void 0 && card.packageId !== null ? cordisVisibleStatus(row, card.packageId, loaded) : "idle";
283
+ const name = card.name ?? callId;
284
+ const expandable = card.hostCode !== null || card.clientCode !== null || card.output !== null;
285
+ const open = expanded && expandable;
286
+ const a11yState = stateStatus(card.state);
287
+ const hasSource = card.clientCode !== null || card.hostCode !== null;
288
+ const activeSource = selectedSource === "client" && card.clientCode !== null ? "client" : selectedSource === "host" && card.hostCode !== null ? "host" : card.clientCode !== null ? "client" : "host";
289
+ const activeCode = activeSource === "client" ? card.clientCode : card.hostCode;
290
+ return (0, react_jsx_runtime.jsxs)("div", {
291
+ className: CordisDefineRow_module_css_default.card,
292
+ "data-tool": "cordis_define",
293
+ "data-state": card.state,
294
+ "data-terminal": reading === "removed" || void 0,
295
+ "data-cordis-plugin-id": card.pluginId ?? void 0,
296
+ "data-cordis-package-id": card.packageId ?? void 0,
297
+ "data-cordis-status": reading,
298
+ children: [a11yState !== null && (0, react_jsx_runtime.jsx)("span", {
299
+ className: CordisDefineRow_module_css_default.visuallyHidden,
300
+ children: t(a11yState)
301
+ }), (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.DisclosureRow, {
302
+ rowClassName: CordisDefineRow_module_css_default.row,
303
+ titleClassName: CordisDefineRow_module_css_default.title,
304
+ chevronClassName: CordisDefineRow_module_css_default.chevron,
305
+ icon: leadingFor(card.state),
306
+ title: t("row.defineTitle"),
307
+ open,
308
+ expandable,
309
+ expandOnRowClick: true,
310
+ keepContentWhenOpen: true,
311
+ onToggle: () => {
312
+ setExpanded((value) => !value);
313
+ },
314
+ collapsedContent: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
315
+ (0, react_jsx_runtime.jsx)("span", {
316
+ className: CordisDefineRow_module_css_default.separator,
317
+ "aria-hidden": true
318
+ }),
319
+ (0, react_jsx_runtime.jsx)("span", {
320
+ className: card.errorSummary === null ? CordisDefineRow_module_css_default.name : CordisDefineRow_module_css_default.errorSummary,
321
+ children: card.errorSummary ?? name
322
+ }),
323
+ card.errorSummary === null && (0, react_jsx_runtime.jsx)("span", {
324
+ className: CordisDefineRow_module_css_default.purpose,
325
+ children: card.purpose ?? t("purpose.missing")
326
+ }),
327
+ card.pluginId !== null && (0, react_jsx_runtime.jsx)("span", {
328
+ className: CordisDefineRow_module_css_default.readout,
329
+ children: (0, react_jsx_runtime.jsx)("span", {
330
+ className: CordisDefineRow_module_css_default.statusLabel,
331
+ children: t(READING_LABELS$1[reading])
332
+ })
333
+ })
334
+ ] }),
335
+ children: (0, react_jsx_runtime.jsxs)("div", {
336
+ className: CordisDefineRow_module_css_default.bodyWrap,
337
+ children: [
338
+ hasSource && activeCode !== null && (0, react_jsx_runtime.jsxs)("section", {
339
+ className: CordisDefineRow_module_css_default.sourceCard,
340
+ children: [(0, react_jsx_runtime.jsx)("div", {
341
+ className: CordisDefineRow_module_css_default.sourceTabs,
342
+ role: "tablist",
343
+ "aria-label": t("body.source"),
344
+ children: ["client", "host"].map((source) => {
345
+ const available = source === "client" ? card.clientCode !== null : card.hostCode !== null;
346
+ return (0, react_jsx_runtime.jsx)("button", {
347
+ id: `${sourcePanelId}-${source}`,
348
+ type: "button",
349
+ role: "tab",
350
+ "aria-controls": sourcePanelId,
351
+ "aria-selected": activeSource === source,
352
+ className: activeSource === source ? `${CordisDefineRow_module_css_default.sourceTab} ${CordisDefineRow_module_css_default.sourceTabActive}` : CordisDefineRow_module_css_default.sourceTab,
353
+ disabled: !available,
354
+ onClick: () => {
355
+ setSelectedSource(source);
356
+ },
357
+ children: t(source === "client" ? "body.clientCode" : "body.hostCode")
358
+ }, source);
359
+ })
360
+ }), (0, react_jsx_runtime.jsx)("div", {
361
+ id: sourcePanelId,
362
+ className: CordisDefineRow_module_css_default.sourcePanel,
363
+ role: "tabpanel",
364
+ "aria-labelledby": `${sourcePanelId}-${activeSource}`,
365
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.CodeBlock, {
366
+ code: activeCode,
367
+ lang: "javascript",
368
+ copyLabel: t("body.copy"),
369
+ copiedLabel: t("body.copied"),
370
+ className: CordisDefineRow_module_css_default.sourceCode
371
+ })
372
+ })]
373
+ }),
374
+ card.output !== null && (0, react_jsx_runtime.jsxs)("section", {
375
+ className: CordisDefineRow_module_css_default.codeSection,
376
+ children: [(0, react_jsx_runtime.jsx)("div", {
377
+ className: CordisDefineRow_module_css_default.sectionLabel,
378
+ children: t("body.output")
379
+ }), (0, react_jsx_runtime.jsx)("pre", {
380
+ className: CordisDefineRow_module_css_default.output,
381
+ "data-error": card.state === "error" || void 0,
382
+ children: card.output
383
+ })]
384
+ }),
385
+ card.pluginId !== null && (0, react_jsx_runtime.jsx)("div", {
386
+ className: CordisDefineRow_module_css_default.panelHint,
387
+ children: t("panel.hint")
388
+ }),
389
+ inspect !== void 0 && (0, react_jsx_runtime.jsxs)("button", {
390
+ type: "button",
391
+ className: CordisDefineRow_module_css_default.inspectButton,
392
+ onClick: inspect,
393
+ children: [(0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconInspectOutline12, {}), "Inspect"]
394
+ })
395
+ ]
396
+ })
397
+ })]
398
+ });
399
+ }
400
+ //#endregion
401
+ //#region lib/types/client/run-card-index.js
402
+ /** Session-local ownership index for Package business views on `cordis_run` cards. */
403
+ function createStore() {
404
+ const pointers = /* @__PURE__ */ new Map();
405
+ const listeners = /* @__PURE__ */ new Set();
406
+ let cache;
407
+ return {
408
+ getSnapshot: () => cache ??= new Map(pointers),
409
+ subscribe: (listener) => {
410
+ listeners.add(listener);
411
+ return () => {
412
+ listeners.delete(listener);
413
+ };
414
+ },
415
+ observe: (pointer) => {
416
+ const current = pointers.get(pointer.key);
417
+ if (current !== void 0 && current.seq >= pointer.seq) return;
418
+ pointers.set(pointer.key, pointer);
419
+ cache = void 0;
420
+ for (const listener of [...listeners]) listener();
421
+ }
422
+ };
423
+ }
424
+ /** Page-lifetime registry that gives all cards of one session the same Store. */
425
+ var CordisRunCardRegistry = class {
426
+ sessions = /* @__PURE__ */ new Map();
427
+ /**
428
+ * Return the persistent page-local Store for a session.
429
+ * @param sessionId - session whose cards share supersession state.
430
+ * @returns the page-local Store retained for that session.
431
+ */
432
+ forSession(sessionId) {
433
+ let store = this.sessions.get(sessionId);
434
+ if (store === void 0) {
435
+ store = createStore();
436
+ this.sessions.set(sessionId, store);
437
+ }
438
+ return store;
439
+ }
440
+ };
441
+ /**
442
+ * Build the Package business-view key shared by registrations and Run cards.
443
+ * @param pluginId - stable Plugin identity.
444
+ * @param packageId - immutable Package identity.
445
+ * @returns the shared business-view key.
446
+ */
447
+ function cordisToolViewKey(pluginId, packageId) {
448
+ return `${pluginId}.${packageId}`;
449
+ }
450
+ //#endregion
451
+ //#region lib/types/client/CordisRunRow.js
452
+ /** `cordis_run` card and the host seat for Package-owned interactive UI. */
453
+ const READING_LABELS = {
454
+ idle: "status.idle",
455
+ "awaiting-approval": "status.awaitingApproval",
456
+ failed: "status.failed",
457
+ "client-pending": "status.clientPending",
458
+ running: "status.running",
459
+ removed: "status.removed",
460
+ superseded: "status.superseded"
461
+ };
462
+ /** Render one activation result and, when eligible, its Package-owned view. */
463
+ function CordisRunRow({ callId, block, inspect, renderSlot, useInventory, useLoaded, useRunCards, useActiveRuns, onObserveRunCard, t }) {
464
+ const card = cordisRunCard(block);
465
+ const inventory = useInventory((snapshot) => snapshot);
466
+ const loaded = useLoaded((snapshot) => snapshot);
467
+ const latest = useRunCards((snapshot) => snapshot);
468
+ const activeRuns = useActiveRuns((snapshot) => snapshot);
469
+ const key = card.state === "ok" && card.pluginId !== null && card.packageId !== null && card.pluginRunId !== null && card.seq !== null ? cordisToolViewKey(card.pluginId, card.packageId) : null;
470
+ (0, react.useEffect)(() => {
471
+ if (key === null || card.seq === null || card.pluginRunId === null) return;
472
+ onObserveRunCard({
473
+ key,
474
+ callId,
475
+ seq: card.seq,
476
+ pluginRunId: card.pluginRunId
477
+ });
478
+ }, [
479
+ callId,
480
+ card.pluginRunId,
481
+ card.seq,
482
+ key,
483
+ onObserveRunCard
484
+ ]);
485
+ const row = card.pluginId === null ? void 0 : inventory.rows.find((candidate) => candidate.pluginId === card.pluginId);
486
+ const pointer = key === null ? void 0 : latest.get(key);
487
+ const superseded = pointer !== void 0 && pointer.callId !== callId && pointer.seq >= (card.seq ?? -1);
488
+ const activity = card.pluginId === null ? void 0 : activeRuns.get(card.pluginId);
489
+ const attempt = card.pluginRunId !== null && row?.latestRun?.pluginRunId === card.pluginRunId ? row.latestRun : void 0;
490
+ const awaitingApproval = attempt?.status === "awaiting-approval" || card.packageId !== null && activity?.phase === "awaiting-approval" && activity.packageId === card.packageId && (card.mode === null || activity.mode === card.mode);
491
+ const reading = card.pluginId !== null && inventory.removed.has(card.pluginId) ? "removed" : superseded ? "superseded" : awaitingApproval ? "awaiting-approval" : attempt?.status === "failed" ? "failed" : row !== void 0 && card.packageId !== null ? cordisVisibleStatus(row, card.packageId, loaded) : "idle";
492
+ const status = t(READING_LABELS[reading]);
493
+ const summary = card.errorSummary ?? (card.pluginId === null ? callId : `${card.pluginId}${card.packageId === null ? "" : ` · ${card.packageId}`}`);
494
+ const showBusiness = reading === "running" && key !== null;
495
+ return (0, react_jsx_runtime.jsxs)("div", {
496
+ className: CordisRunRow_module_css_default.card,
497
+ "data-tool": "cordis_run",
498
+ "data-state": card.state,
499
+ "data-cordis-plugin-id": card.pluginId ?? void 0,
500
+ "data-cordis-package-id": card.packageId ?? void 0,
501
+ "data-cordis-run-id": card.pluginRunId ?? void 0,
502
+ "data-cordis-status": reading,
503
+ children: [
504
+ (0, react_jsx_runtime.jsxs)("div", {
505
+ className: CordisRunRow_module_css_default.row,
506
+ children: [
507
+ (0, react_jsx_runtime.jsx)("span", {
508
+ className: CordisRunRow_module_css_default.icon,
509
+ children: card.state === "error" ? (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "error" }) : card.state === "stopped" ? (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.StateDot, { state: "warning" }) : (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCodeOutline16, { size: 14 })
510
+ }),
511
+ (0, react_jsx_runtime.jsx)("span", {
512
+ className: CordisRunRow_module_css_default.title,
513
+ children: t(card.mode === "update" ? "row.updateTitle" : "row.runTitle")
514
+ }),
515
+ (0, react_jsx_runtime.jsx)("span", {
516
+ className: CordisRunRow_module_css_default.separator,
517
+ "aria-hidden": true
518
+ }),
519
+ (0, react_jsx_runtime.jsx)("span", {
520
+ className: card.errorSummary === null ? CordisRunRow_module_css_default.summary : CordisRunRow_module_css_default.error,
521
+ children: summary
522
+ }),
523
+ (0, react_jsx_runtime.jsx)("span", {
524
+ className: CordisRunRow_module_css_default.status,
525
+ children: status
526
+ }),
527
+ inspect !== void 0 && (0, react_jsx_runtime.jsx)("button", {
528
+ type: "button",
529
+ className: CordisRunRow_module_css_default.inspect,
530
+ "aria-label": "Inspect",
531
+ onClick: inspect,
532
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconInspectOutline12, {})
533
+ })
534
+ ]
535
+ }),
536
+ reading === "removed" && (0, react_jsx_runtime.jsx)("div", {
537
+ className: CordisRunRow_module_css_default.message,
538
+ children: t("run.removed")
539
+ }),
540
+ reading === "superseded" && (0, react_jsx_runtime.jsx)("div", {
541
+ className: CordisRunRow_module_css_default.message,
542
+ children: t("run.superseded")
543
+ }),
544
+ reading === "failed" && attempt?.error !== void 0 && (0, react_jsx_runtime.jsx)("div", {
545
+ className: CordisRunRow_module_css_default.message,
546
+ children: attempt.error.message
547
+ }),
548
+ showBusiness && card.pluginId !== null && card.packageId !== null && card.pluginRunId !== null && (0, react_jsx_runtime.jsx)("div", {
549
+ className: CordisRunRow_module_css_default.business,
550
+ "data-cordis-business-view": key,
551
+ children: renderSlot("tool.view.cordis", {
552
+ pluginId: card.pluginId,
553
+ packageId: card.packageId,
554
+ pluginRunId: card.pluginRunId
555
+ }, {
556
+ entryKey: key,
557
+ fallback: card.output === null ? null : (0, react_jsx_runtime.jsx)("pre", {
558
+ className: CordisRunRow_module_css_default.output,
559
+ children: card.output
560
+ })
561
+ })
562
+ }),
563
+ !showBusiness && reading !== "removed" && reading !== "superseded" && card.output !== null && (0, react_jsx_runtime.jsx)("pre", {
564
+ className: CordisRunRow_module_css_default.output,
565
+ children: card.output
566
+ })
567
+ ]
568
+ });
569
+ }
570
+ //#endregion
571
+ //#region \0hydra-css:/home/runner/work/Hydra-Harness/Hydra-Harness/packages/extensions/ui-cordis/src/client/CordisPanel.module.css.mjs
572
+ const css = ".I97Aaq_layer{flex:none;align-items:center;width:100%;height:42px;margin:8px 0 0;display:flex;position:relative}.I97Aaq_footerButtons{align-items:center;width:100%;display:flex}.I97Aaq_badge{width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;margin:0 -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;display:inline-flex;overflow:hidden}.I97Aaq_badge:hover,.I97Aaq_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover)}.I97Aaq_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.I97Aaq_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.I97Aaq_layer.I97Aaq_rail{width:36px;height:36px;margin:0}.I97Aaq_rail .I97Aaq_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.I97Aaq_rail .I97Aaq_footerButtons{flex-direction:column;gap:2px}.I97Aaq_panel{z-index:30;border:1px solid var(--dsw-alias-border-inverted);background:var(--dsw-specific-menu);width:420px;max-width:calc(100vw - 24px);max-height:60vh;box-shadow:var(--dsw-shadow-lv3);--hydra-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--hydra-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;overflow:hidden}.I97Aaq_header{box-sizing:border-box;flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.I97Aaq_body{flex:1;min-height:0;padding:0 12px 12px;overflow-y:auto}.I97Aaq_title{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:20px}.I97Aaq_note,.I97Aaq_readError{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.I97Aaq_readError{color:var(--dsw-alias-state-error-primary)}.I97Aaq_group{color:var(--dsw-alias-label-caption);text-transform:uppercase;letter-spacing:.04em;margin:8px 0;font-size:11px;font-weight:500;line-height:16px}.I97Aaq_rows{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}.I97Aaq_row{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:8px;padding:14px 12px 10px;display:flex}.I97Aaq_row[data-cordis-awaiting]{border-color:var(--dsw-alias-state-business-primary)}.I97Aaq_rowHead{align-items:center;gap:8px;display:flex}.I97Aaq_rowId{color:var(--dsw-alias-label-tertiary);font-family:var(--hydra-font-mono,monospace);flex:none;font-size:11px;line-height:20px}.I97Aaq_rowName{min-width:0;color:var(--dsw-alias-label-primary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.I97Aaq_rowStatus{background:var(--dsw-alias-button-ghost-active-fill);height:20px;color:var(--dsw-alias-label-caption);border-radius:10px;flex:none;align-items:center;padding:0 6px;font-size:11px;line-height:20px;display:inline-flex}.I97Aaq_row[data-cordis-status=idle] .I97Aaq_rowStatus{background:var(--dsw-alias-button-ghost-active-fill);color:var(--dsw-alias-label-caption)}.I97Aaq_row[data-cordis-status=awaiting-approval] .I97Aaq_rowStatus,.I97Aaq_row[data-cordis-status=client-pending] .I97Aaq_rowStatus{background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-label)}.I97Aaq_row[data-cordis-status=failed] .I97Aaq_rowStatus{background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.I97Aaq_row[data-cordis-status=running] .I97Aaq_rowStatus{background:var(--dsw-alias-state-success-tertiary);color:var(--dsw-alias-state-success-primary)}.I97Aaq_rowDetail{align-items:center;gap:8px;min-height:28px;display:flex}.I97Aaq_versionPicker{color:var(--dsw-alias-label-caption);align-items:center;gap:8px;font-size:11px;line-height:18px;display:flex}.I97Aaq_versionPicker select{flex:1}.I97Aaq_rowPurpose{min-width:0;color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;flex:1;font-size:12px;line-height:18px;overflow:hidden}.I97Aaq_rowError{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}.I97Aaq_rowActions{flex:none;align-items:center;gap:10px;display:flex}.I97Aaq_transition{min-width:0;color:var(--dsw-alias-label-caption);align-items:center;gap:8px;font-size:11px;line-height:18px;display:flex}.I97Aaq_transitionActions{gap:6px;margin-left:auto;display:flex}.I97Aaq_transitionActions button{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px}.I97Aaq_transitionActions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.I97Aaq_transitionActions button:disabled{opacity:.4;cursor:default}.I97Aaq_activeVersion{color:var(--dsw-alias-label-caption);font-size:11px;line-height:16px}.I97Aaq_actionButton{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:999px;justify-content:center;align-items:center;padding:0;display:inline-flex}.I97Aaq_actionButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.I97Aaq_actionButton:disabled{opacity:.4;cursor:default}.I97Aaq_doubleCheck{width:17px;height:14px;display:inline-block;position:relative}.I97Aaq_doubleCheck svg{position:absolute;top:1px}.I97Aaq_doubleCheck svg:first-child{opacity:.7;left:0}.I97Aaq_doubleCheck svg:last-child{left:5px}";
573
+ const tagId = "@hydraharness/harness-client-ui-cordis/CordisPanel.module.css";
574
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
575
+ const tag = document.createElement("style");
576
+ tag.dataset.plugin = "@hydraharness/harness-client-ui-cordis";
577
+ tag.dataset.pluginCss = tagId;
578
+ tag.textContent = css;
579
+ document.head.appendChild(tag);
580
+ }
581
+ var CordisPanel_module_css_default = {
582
+ "actionButton": "I97Aaq_actionButton",
583
+ "activeVersion": "I97Aaq_activeVersion",
584
+ "badge": "I97Aaq_badge",
585
+ "badgeCount": "I97Aaq_badgeCount",
586
+ "badgeLabel": "I97Aaq_badgeLabel",
587
+ "body": "I97Aaq_body",
588
+ "doubleCheck": "I97Aaq_doubleCheck",
589
+ "footerButtons": "I97Aaq_footerButtons",
590
+ "group": "I97Aaq_group",
591
+ "header": "I97Aaq_header",
592
+ "layer": "I97Aaq_layer",
593
+ "note": "I97Aaq_note",
594
+ "panel": "I97Aaq_panel",
595
+ "rail": "I97Aaq_rail",
596
+ "readError": "I97Aaq_readError",
597
+ "row": "I97Aaq_row",
598
+ "rowActions": "I97Aaq_rowActions",
599
+ "rowDetail": "I97Aaq_rowDetail",
600
+ "rowError": "I97Aaq_rowError",
601
+ "rowHead": "I97Aaq_rowHead",
602
+ "rowId": "I97Aaq_rowId",
603
+ "rowName": "I97Aaq_rowName",
604
+ "rowPurpose": "I97Aaq_rowPurpose",
605
+ "rowStatus": "I97Aaq_rowStatus",
606
+ "rows": "I97Aaq_rows",
607
+ "title": "I97Aaq_title",
608
+ "transition": "I97Aaq_transition",
609
+ "transitionActions": "I97Aaq_transitionActions",
610
+ "versionPicker": "I97Aaq_versionPicker"
611
+ };
612
+ //#endregion
613
+ //#region lib/types/client/CordisPanel.js
614
+ /** Frame-wide dynamic Plugin inventory, approvals, versions, and lifecycle actions. */
615
+ const STATUS_LABELS = {
616
+ idle: "status.idle",
617
+ "awaiting-approval": "status.awaitingApproval",
618
+ "client-pending": "status.clientPending",
619
+ running: "status.running",
620
+ failed: "status.failed"
621
+ };
622
+ const RENDER_FAILURE_LABELS = {
623
+ abdicated: "render.failedAbdicated",
624
+ held: "render.failedHeld"
625
+ };
626
+ function selectedPackageIdOf({ pluginId, listed, activity }, selected) {
627
+ const selectedPackageId = selected[pluginId];
628
+ if (selectedPackageId !== void 0 && listed?.packages.some((pkg) => pkg.packageId === selectedPackageId)) return selectedPackageId;
629
+ return listed?.nextPackageId ?? listed?.currentPackageId ?? listed?.packages.at(-1)?.packageId ?? activity?.packageId;
630
+ }
631
+ function visiblePanelStatus(view, selectedPackageId, loaded) {
632
+ const { listed, activity } = view;
633
+ const latest = listed?.latestRun;
634
+ if (activity?.phase === "awaiting-approval" || latest?.status === "awaiting-approval") return "awaiting-approval";
635
+ if (latest?.status === "failed" && latest.packageId === selectedPackageId) return "failed";
636
+ if (listed?.activeRun === void 0) return "idle";
637
+ return cordisVisibleStatus(listed, listed.activeRun.packageId, loaded);
638
+ }
639
+ function blockingFirst(rows) {
640
+ return [...rows.filter((row) => row.activity?.phase === "awaiting-approval"), ...rows.filter((row) => row.activity?.phase !== "awaiting-approval")];
641
+ }
642
+ function RowAction({ label, children, ...props }) {
643
+ return (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.Tooltip, {
644
+ label,
645
+ side: "bottom",
646
+ delayMs: 500,
647
+ children: (0, react_jsx_runtime.jsx)("button", {
648
+ type: "button",
649
+ className: CordisPanel_module_css_default.actionButton,
650
+ "aria-label": label,
651
+ ...props,
652
+ children
653
+ })
654
+ });
655
+ }
656
+ function DoubleCheckIcon() {
657
+ return (0, react_jsx_runtime.jsxs)("span", {
658
+ className: CordisPanel_module_css_default.doubleCheck,
659
+ "aria-hidden": true,
660
+ children: [(0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCheckOutline16, { size: 12 }), (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCheckOutline16, { size: 12 })]
661
+ });
662
+ }
663
+ /** Render the inventory panel and its unified footer action. */
664
+ function CordisPanel({ wide, useSessions, useInventory, useActiveRuns, useRunErrors, useLoaded, useRenderFailures, onApprove, onDecline, onRun, onStop, onRemove, onRefresh, t }) {
665
+ const inventory = useInventory((snapshot) => snapshot);
666
+ const activeRuns = useActiveRuns((snapshot) => snapshot);
667
+ const errors = useRunErrors((snapshot) => snapshot);
668
+ const loaded = useLoaded((snapshot) => snapshot);
669
+ const renderFailures = useRenderFailures((snapshot) => snapshot);
670
+ const current = useSessions((state) => state.current);
671
+ const [open, setOpen] = (0, react.useState)(false);
672
+ const [selected, setSelected] = (0, react.useState)({});
673
+ const [pending, setPending] = (0, react.useState)(/* @__PURE__ */ new Set());
674
+ const [actionErrors, setActionErrors] = (0, react.useState)(/* @__PURE__ */ new Map());
675
+ const visibleRequests = (0, react.useRef)(/* @__PURE__ */ new Set());
676
+ const rootRef = (0, react.useRef)(null);
677
+ const [anchor, setAnchor] = (0, react.useState)();
678
+ (0, react.useLayoutEffect)(() => {
679
+ if (!open) return;
680
+ const place = () => {
681
+ const rect = rootRef.current?.getBoundingClientRect();
682
+ if (rect !== void 0) setAnchor({
683
+ left: rect.left,
684
+ bottom: window.innerHeight - rect.top + 8
685
+ });
686
+ };
687
+ place();
688
+ window.addEventListener("resize", place);
689
+ return () => {
690
+ window.removeEventListener("resize", place);
691
+ };
692
+ }, [open]);
693
+ (0, _hydraharness_harness_client_ui_primitives.useDismissOnOutsidePointer)(rootRef, open, setOpen);
694
+ (0, react.useEffect)(() => {
695
+ const now = /* @__PURE__ */ new Set();
696
+ for (const activity of activeRuns.values()) if (activity.phase === "awaiting-approval") now.add(activity.requestId);
697
+ const discovered = [...now].some((requestId) => !visibleRequests.current.has(requestId));
698
+ visibleRequests.current = now;
699
+ if (discovered) setOpen(true);
700
+ }, [activeRuns]);
701
+ (0, react.useEffect)(() => {
702
+ onRefresh();
703
+ }, [onRefresh]);
704
+ (0, react.useEffect)(() => {
705
+ if (open) onRefresh();
706
+ }, [onRefresh, open]);
707
+ const byPlugin = /* @__PURE__ */ new Map();
708
+ for (const listed of inventory.rows) {
709
+ const activity = activeRuns.get(listed.pluginId);
710
+ byPlugin.set(listed.pluginId, {
711
+ pluginId: listed.pluginId,
712
+ agentId: activity?.agentId ?? listed.agentId,
713
+ listed,
714
+ ...activity === void 0 ? {} : { activity }
715
+ });
716
+ }
717
+ for (const [pluginId, activity] of activeRuns) {
718
+ if (byPlugin.has(pluginId)) continue;
719
+ byPlugin.set(pluginId, {
720
+ pluginId,
721
+ agentId: activity.agentId,
722
+ activity
723
+ });
724
+ }
725
+ const all = [...byPlugin.values()];
726
+ const mine = blockingFirst(all.filter((row) => current !== void 0 && row.agentId === current));
727
+ const theirs = blockingFirst(all.filter((row) => current === void 0 || row.agentId !== current));
728
+ const approvals = [...activeRuns.values()].filter((activity) => activity.phase === "awaiting-approval").length;
729
+ const running = all.filter((view) => visiblePanelStatus(view, selectedPackageIdOf(view, selected), loaded) === "running").length;
730
+ if (all.length === 0) return null;
731
+ const runAction = async (pluginId, action) => {
732
+ if (pending.has(pluginId)) return;
733
+ setPending((currentPending) => new Set(currentPending).add(pluginId));
734
+ setActionErrors((currentErrors) => {
735
+ const next = new Map(currentErrors);
736
+ next.delete(pluginId);
737
+ return next;
738
+ });
739
+ try {
740
+ const result = await action();
741
+ if (result !== void 0 && !result.ok) setActionErrors((currentErrors) => new Map(currentErrors).set(pluginId, result.message ?? "operation failed"));
742
+ } catch (error) {
743
+ setActionErrors((currentErrors) => new Map(currentErrors).set(pluginId, error instanceof Error ? error.message : String(error)));
744
+ } finally {
745
+ setPending((currentPending) => {
746
+ const next = new Set(currentPending);
747
+ next.delete(pluginId);
748
+ return next;
749
+ });
750
+ onRefresh();
751
+ }
752
+ };
753
+ const renderRow = (view) => {
754
+ const { pluginId, listed, activity } = view;
755
+ const selectedPackageId = selectedPackageIdOf(view, selected);
756
+ const selectedPackage = listed !== void 0 && selectedPackageId !== void 0 ? packageOf(listed, selectedPackageId) : void 0;
757
+ const activePackage = listed?.activeRun === void 0 ? void 0 : packageOf(listed, listed.activeRun.packageId);
758
+ const name = selectedPackage?.name ?? (activity?.phase === "awaiting-approval" ? activity.name : pluginId);
759
+ const purpose = selectedPackage?.purpose ?? (activity?.phase === "awaiting-approval" ? activity.purpose : "");
760
+ const latest = listed?.latestRun;
761
+ const awaiting = activity?.phase === "awaiting-approval" ? activity.requestId : latest?.status === "awaiting-approval" ? latest.approvalRequestId : void 0;
762
+ const status = visiblePanelStatus(view, selectedPackageId, loaded);
763
+ const busy = pending.has(pluginId) || activity?.phase === "orchestrating";
764
+ const failure = errors.get(pluginId);
765
+ const hostFailure = latest?.status === "failed" ? latest.error : void 0;
766
+ const renderFailure = renderFailures.get(pluginId);
767
+ const actionError = actionErrors.get(pluginId);
768
+ const nextPackageId = listed?.nextPackageId !== void 0 && listed.nextPackageId !== listed.currentPackageId ? listed.nextPackageId : void 0;
769
+ const currentPackageId = listed?.currentPackageId;
770
+ const runMode = listed?.currentPackageId !== void 0 && selectedPackageId !== listed.currentPackageId ? "update" : "run";
771
+ return (0, react_jsx_runtime.jsxs)("li", {
772
+ className: CordisPanel_module_css_default.row,
773
+ "data-cordis-row": pluginId,
774
+ "data-cordis-status": status,
775
+ "data-cordis-awaiting": awaiting !== void 0 || void 0,
776
+ children: [
777
+ (0, react_jsx_runtime.jsxs)("div", {
778
+ className: CordisPanel_module_css_default.rowHead,
779
+ children: [
780
+ (0, react_jsx_runtime.jsx)("span", {
781
+ className: CordisPanel_module_css_default.rowId,
782
+ children: pluginId
783
+ }),
784
+ (0, react_jsx_runtime.jsx)("span", {
785
+ className: CordisPanel_module_css_default.rowName,
786
+ children: name
787
+ }),
788
+ (0, react_jsx_runtime.jsx)("span", {
789
+ className: CordisPanel_module_css_default.rowStatus,
790
+ children: t(STATUS_LABELS[status])
791
+ })
792
+ ]
793
+ }),
794
+ listed !== void 0 && listed.packages.length > 1 && selectedPackageId !== void 0 && (0, react_jsx_runtime.jsxs)("label", {
795
+ className: CordisPanel_module_css_default.versionPicker,
796
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("panel.version") }), (0, react_jsx_runtime.jsx)("select", {
797
+ "data-hydra-control": "compact",
798
+ value: selectedPackageId,
799
+ disabled: busy,
800
+ onChange: (event) => {
801
+ setSelected((currentSelected) => ({
802
+ ...currentSelected,
803
+ [pluginId]: event.target.value
804
+ }));
805
+ },
806
+ children: listed.packages.map((pkg) => (0, react_jsx_runtime.jsx)("option", {
807
+ value: pkg.packageId,
808
+ children: `${pkg.name} · ${pkg.packageId}`
809
+ }, pkg.packageId))
810
+ })]
811
+ }),
812
+ (0, react_jsx_runtime.jsxs)("div", {
813
+ className: CordisPanel_module_css_default.rowDetail,
814
+ children: [(0, react_jsx_runtime.jsx)("span", {
815
+ className: CordisPanel_module_css_default.rowPurpose,
816
+ children: purpose
817
+ }), (0, react_jsx_runtime.jsxs)("div", {
818
+ className: CordisPanel_module_css_default.rowActions,
819
+ children: [
820
+ awaiting !== void 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
821
+ (0, react_jsx_runtime.jsx)(RowAction, {
822
+ label: t("action.approveOnce"),
823
+ "data-cordis-approve": awaiting,
824
+ disabled: busy,
825
+ onClick: () => {
826
+ runAction(pluginId, async () => {
827
+ await onApprove(awaiting, false);
828
+ setOpen(false);
829
+ });
830
+ },
831
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCheckOutline16, { size: 14 })
832
+ }),
833
+ (0, react_jsx_runtime.jsx)(RowAction, {
834
+ label: t("action.approvePlugin"),
835
+ "data-cordis-approve-plugin": awaiting,
836
+ disabled: busy,
837
+ onClick: () => {
838
+ runAction(pluginId, async () => {
839
+ await onApprove(awaiting, true);
840
+ setOpen(false);
841
+ });
842
+ },
843
+ children: (0, react_jsx_runtime.jsx)(DoubleCheckIcon, {})
844
+ }),
845
+ (0, react_jsx_runtime.jsx)(RowAction, {
846
+ label: t("action.decline"),
847
+ "data-cordis-decline": awaiting,
848
+ disabled: busy,
849
+ onClick: () => {
850
+ runAction(pluginId, async () => {
851
+ await onDecline(awaiting);
852
+ setOpen(false);
853
+ });
854
+ },
855
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCloseOutline16, { size: 14 })
856
+ })
857
+ ] }),
858
+ awaiting === void 0 && listed !== void 0 && selectedPackageId !== void 0 && listed.activeRun === void 0 && (0, react_jsx_runtime.jsx)(RowAction, {
859
+ label: t("action.run"),
860
+ "data-cordis-switch": "run",
861
+ disabled: busy,
862
+ onClick: () => {
863
+ runAction(pluginId, () => onRun({
864
+ agentId: listed.agentId,
865
+ pluginId,
866
+ packageId: selectedPackageId,
867
+ mode: runMode,
868
+ hasClientHalf: selectedPackage?.hasClientHalf === true
869
+ }));
870
+ },
871
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconPlayOutline16, { size: 14 })
872
+ }),
873
+ awaiting === void 0 && listed !== void 0 && listed.activeRun !== void 0 && selectedPackageId !== listed.activeRun.packageId && selectedPackage !== void 0 && (0, react_jsx_runtime.jsx)(RowAction, {
874
+ label: t("action.run"),
875
+ "data-cordis-switch": "run",
876
+ disabled: busy,
877
+ onClick: () => {
878
+ runAction(pluginId, () => onRun({
879
+ agentId: listed.agentId,
880
+ pluginId,
881
+ packageId: selectedPackage.packageId,
882
+ mode: runMode,
883
+ hasClientHalf: selectedPackage.hasClientHalf
884
+ }));
885
+ },
886
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconPlayOutline16, { size: 14 })
887
+ }),
888
+ awaiting === void 0 && listed !== void 0 && listed.activeRun !== void 0 && status === "client-pending" && activePackage !== void 0 && selectedPackageId === listed.activeRun.packageId && (0, react_jsx_runtime.jsx)(RowAction, {
889
+ label: t("action.run"),
890
+ "data-cordis-switch": "run",
891
+ disabled: busy,
892
+ onClick: () => {
893
+ runAction(pluginId, () => onRun({
894
+ agentId: listed.agentId,
895
+ pluginId,
896
+ packageId: activePackage.packageId,
897
+ mode: "run",
898
+ hasClientHalf: true
899
+ }));
900
+ },
901
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconPlayOutline16, { size: 14 })
902
+ }),
903
+ awaiting === void 0 && listed !== void 0 && listed.activeRun !== void 0 && (0, react_jsx_runtime.jsx)(RowAction, {
904
+ label: t("action.stop"),
905
+ "data-cordis-switch": "stop",
906
+ disabled: busy,
907
+ onClick: () => {
908
+ runAction(pluginId, () => onStop(listed.agentId, pluginId));
909
+ },
910
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconStopFill16, { size: 14 })
911
+ }),
912
+ awaiting === void 0 && listed !== void 0 && (0, react_jsx_runtime.jsx)(RowAction, {
913
+ label: t("action.remove"),
914
+ "data-cordis-remove": pluginId,
915
+ disabled: busy,
916
+ onClick: () => {
917
+ runAction(pluginId, () => onRemove(listed.agentId, pluginId));
918
+ },
919
+ children: (0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconTrashOutline16, { size: 14 })
920
+ })
921
+ ]
922
+ })]
923
+ }),
924
+ awaiting === void 0 && nextPackageId !== void 0 && listed !== void 0 && (0, react_jsx_runtime.jsxs)("div", {
925
+ className: CordisPanel_module_css_default.transition,
926
+ children: [
927
+ (0, react_jsx_runtime.jsx)("span", { children: currentPackageId === void 0 ? "" : t("panel.current", { packageId: currentPackageId }) }),
928
+ (0, react_jsx_runtime.jsx)("span", { children: t("panel.next", { packageId: nextPackageId }) }),
929
+ (0, react_jsx_runtime.jsxs)("div", {
930
+ className: CordisPanel_module_css_default.transitionActions,
931
+ children: [(0, react_jsx_runtime.jsx)("button", {
932
+ type: "button",
933
+ disabled: busy,
934
+ onClick: () => {
935
+ runAction(pluginId, () => onRun({
936
+ agentId: listed.agentId,
937
+ pluginId,
938
+ packageId: nextPackageId,
939
+ mode: currentPackageId === void 0 ? "run" : "update",
940
+ hasClientHalf: packageOf(listed, nextPackageId)?.hasClientHalf === true
941
+ }));
942
+ },
943
+ children: t("action.retry")
944
+ }), currentPackageId !== void 0 && (0, react_jsx_runtime.jsx)("button", {
945
+ type: "button",
946
+ disabled: busy,
947
+ onClick: () => {
948
+ runAction(pluginId, () => onRun({
949
+ agentId: listed.agentId,
950
+ pluginId,
951
+ packageId: currentPackageId,
952
+ mode: "run",
953
+ hasClientHalf: packageOf(listed, currentPackageId)?.hasClientHalf === true
954
+ }));
955
+ },
956
+ children: t("action.rollback")
957
+ })]
958
+ })
959
+ ]
960
+ }),
961
+ failure !== void 0 && (0, react_jsx_runtime.jsx)("div", {
962
+ className: CordisPanel_module_css_default.rowError,
963
+ role: "alert",
964
+ children: `${failure.message} (${failure.reason})`
965
+ }),
966
+ failure === void 0 && hostFailure !== void 0 && (0, react_jsx_runtime.jsx)("div", {
967
+ className: CordisPanel_module_css_default.rowError,
968
+ role: "alert",
969
+ children: `${hostFailure.message} (${hostFailure.phase})`
970
+ }),
971
+ actionError !== void 0 && (0, react_jsx_runtime.jsx)("div", {
972
+ className: CordisPanel_module_css_default.rowError,
973
+ role: "alert",
974
+ children: actionError
975
+ }),
976
+ renderFailure !== void 0 && (0, react_jsx_runtime.jsx)("div", {
977
+ className: CordisPanel_module_css_default.rowError,
978
+ role: "alert",
979
+ "data-cordis-render-failure": renderFailure.slot,
980
+ "data-cordis-render-abdicated": renderFailure.abdicated || void 0,
981
+ children: `${t(RENDER_FAILURE_LABELS[renderFailure.abdicated ? "abdicated" : "held"], { slot: renderFailure.slot })} ${renderFailure.message}`
982
+ }),
983
+ activePackage !== void 0 && activePackage.packageId !== selectedPackageId && (0, react_jsx_runtime.jsx)("span", {
984
+ className: CordisPanel_module_css_default.activeVersion,
985
+ children: `${t("status.running")}: ${activePackage.name} · ${activePackage.packageId}`
986
+ })
987
+ ]
988
+ }, pluginId);
989
+ };
990
+ return (0, react_jsx_runtime.jsxs)("div", {
991
+ ref: rootRef,
992
+ className: wide ? CordisPanel_module_css_default.layer : `${CordisPanel_module_css_default.layer} ${CordisPanel_module_css_default.rail}`,
993
+ children: [open && anchor !== void 0 && (0, react_jsx_runtime.jsxs)("section", {
994
+ className: CordisPanel_module_css_default.panel,
995
+ style: anchor,
996
+ "data-cordis-panel": true,
997
+ "aria-label": t("panel.title"),
998
+ children: [(0, react_jsx_runtime.jsx)("header", {
999
+ className: CordisPanel_module_css_default.header,
1000
+ children: (0, react_jsx_runtime.jsx)("span", {
1001
+ className: CordisPanel_module_css_default.title,
1002
+ children: t("panel.title")
1003
+ })
1004
+ }), (0, react_jsx_runtime.jsxs)("div", {
1005
+ className: CordisPanel_module_css_default.body,
1006
+ children: [
1007
+ inventory.error !== void 0 && (0, react_jsx_runtime.jsx)("p", {
1008
+ className: CordisPanel_module_css_default.readError,
1009
+ role: "alert",
1010
+ children: t("panel.readFailed", { message: inventory.error })
1011
+ }),
1012
+ !inventory.read && inventory.error === void 0 && (0, react_jsx_runtime.jsx)("p", {
1013
+ className: CordisPanel_module_css_default.note,
1014
+ children: t("panel.loading")
1015
+ }),
1016
+ inventory.read && all.length === 0 && (0, react_jsx_runtime.jsx)("p", {
1017
+ className: CordisPanel_module_css_default.note,
1018
+ children: t("panel.empty")
1019
+ }),
1020
+ mine.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
1021
+ className: CordisPanel_module_css_default.group,
1022
+ children: t("panel.group.current")
1023
+ }), (0, react_jsx_runtime.jsx)("ul", {
1024
+ className: CordisPanel_module_css_default.rows,
1025
+ children: mine.map(renderRow)
1026
+ })] }),
1027
+ theirs.length > 0 && (0, react_jsx_runtime.jsxs)("section", { children: [(0, react_jsx_runtime.jsx)("h3", {
1028
+ className: CordisPanel_module_css_default.group,
1029
+ children: t("panel.group.others")
1030
+ }), (0, react_jsx_runtime.jsx)("ul", {
1031
+ className: CordisPanel_module_css_default.rows,
1032
+ children: theirs.map(renderRow)
1033
+ })] })
1034
+ ]
1035
+ })]
1036
+ }), (0, react_jsx_runtime.jsx)("div", {
1037
+ className: CordisPanel_module_css_default.footerButtons,
1038
+ children: (0, react_jsx_runtime.jsxs)("button", {
1039
+ type: "button",
1040
+ className: CordisPanel_module_css_default.badge,
1041
+ "data-cordis-badge": all.length,
1042
+ "data-cordis-approval-badge": approvals,
1043
+ "data-active": approvals > 0 || void 0,
1044
+ "aria-label": t("panel.plugins.aria"),
1045
+ "aria-expanded": open,
1046
+ onClick: () => {
1047
+ setOpen((value) => !value);
1048
+ },
1049
+ children: [(0, react_jsx_runtime.jsx)(_hydraharness_harness_client_ui_primitives.IconCordisPluginOutline14, { size: wide ? 16 : 18 }), wide && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("span", {
1050
+ className: CordisPanel_module_css_default.badgeLabel,
1051
+ children: t("panel.trigger")
1052
+ }), (0, react_jsx_runtime.jsx)("span", {
1053
+ className: CordisPanel_module_css_default.badgeCount,
1054
+ children: t("panel.runningCount", { count: running })
1055
+ })] })]
1056
+ })
1057
+ })]
1058
+ });
1059
+ }
1060
+ //#endregion
1061
+ //#region lib/types/client/inventory.js
1062
+ /**
1063
+ * The host's definition registry as this page last read it, owned by the
1064
+ * plugin's apply closure.
1065
+ *
1066
+ * The panel is a frame-wide surface, so it cannot derive this from any session:
1067
+ * the registry is global and the read is a single global call. The rows are
1068
+ * re-read rather than patched, because the wire announcements
1069
+ * (`cordis/dynamic-package` / `/retract`) carry no labels and a definition
1070
+ * can appear or disappear between them — a patch-in-place cache would drift into
1071
+ * showing definitions the host no longer holds.
1072
+ *
1073
+ * Reads are single-flight: several announcements settling at once, or a badge
1074
+ * opening while a reconnect re-reads, must not multiply the call. Single-flight
1075
+ * alone would be wrong across a reconnect, though — the in-flight read belongs to
1076
+ * the previous connection, so a reset both discards its answer and frees the slot
1077
+ * for a fresh one. Without that, a reconnect either loses its re-read to the old
1078
+ * call or has the old host's rows published on top of it.
1079
+ */
1080
+ /**
1081
+ * Create the inventory source.
1082
+ * @param port - the RPC seam the read goes through.
1083
+ * @param onError - reporter for a failed read (console in production, captured in specs).
1084
+ * @returns the inventory observable and its read trigger.
1085
+ */
1086
+ function createCordisInventory(port, onError) {
1087
+ const listeners = /* @__PURE__ */ new Set();
1088
+ let snapshot = {
1089
+ rows: [],
1090
+ removed: /* @__PURE__ */ new Set(),
1091
+ read: false
1092
+ };
1093
+ let inFlight;
1094
+ let generation = 0;
1095
+ const publish = (next) => {
1096
+ snapshot = next;
1097
+ for (const listener of [...listeners]) listener();
1098
+ };
1099
+ return {
1100
+ getSnapshot: () => snapshot,
1101
+ subscribe: (fn) => {
1102
+ listeners.add(fn);
1103
+ return () => {
1104
+ listeners.delete(fn);
1105
+ };
1106
+ },
1107
+ refresh: () => {
1108
+ if (inFlight !== void 0) return;
1109
+ const issued = generation;
1110
+ inFlight = port.inventory().then((rows) => {
1111
+ if (issued !== generation) return;
1112
+ const removed = new Set(snapshot.removed);
1113
+ const live = new Set(rows.map((row) => row.pluginId));
1114
+ for (const previous of snapshot.rows) if (!live.has(previous.pluginId)) removed.add(previous.pluginId);
1115
+ publish({
1116
+ rows,
1117
+ removed,
1118
+ read: true
1119
+ });
1120
+ }, (error) => {
1121
+ if (issued !== generation) return;
1122
+ onError(error);
1123
+ publish({
1124
+ rows: snapshot.rows,
1125
+ removed: snapshot.removed,
1126
+ read: snapshot.read,
1127
+ error: error instanceof Error ? error.message : "reading the cordis inventory failed"
1128
+ });
1129
+ }).then(() => {
1130
+ if (issued === generation) inFlight = void 0;
1131
+ });
1132
+ },
1133
+ retire: (pluginId) => {
1134
+ const removed = new Set(snapshot.removed);
1135
+ removed.add(pluginId);
1136
+ publish({
1137
+ ...snapshot,
1138
+ rows: snapshot.rows.filter((row) => row.pluginId !== pluginId),
1139
+ removed
1140
+ });
1141
+ },
1142
+ reset: () => {
1143
+ generation += 1;
1144
+ inFlight = void 0;
1145
+ publish({
1146
+ rows: [],
1147
+ removed: snapshot.removed,
1148
+ read: false
1149
+ });
1150
+ }
1151
+ };
1152
+ }
1153
+ //#endregion
1154
+ //#region lib/types/client/locales.js
1155
+ /** Cordis dynamic-plugin UI dictionaries. */
1156
+ const NS = "cordis";
1157
+ /** English Cordis UI messages (the key-set source of truth). */
1158
+ const en = {
1159
+ "row.defineTitle": "Register Cordis Plugin",
1160
+ "row.runTitle": "Run Cordis Plugin",
1161
+ "row.updateTitle": "Update Cordis Plugin",
1162
+ "row.stopTitle": "Stop Cordis Plugin",
1163
+ "row.removeTitle": "Remove Cordis Plugin",
1164
+ "purpose.missing": "(no purpose given)",
1165
+ "status.idle": "Ready",
1166
+ "status.awaitingApproval": "Awaiting approval",
1167
+ "status.failed": "Run failed",
1168
+ "status.clientPending": "Client ready to activate",
1169
+ "status.running": "Running",
1170
+ "status.removed": "Removed",
1171
+ "status.superseded": "Newer run available",
1172
+ "run.removed": "This package no longer exists",
1173
+ "run.superseded": "A newer run card is available below",
1174
+ "panel.hint": "Run controls live in the Cordis panel above Settings",
1175
+ "panel.plugins.aria": "Cordis plugins",
1176
+ "panel.approvals.aria": "Cordis approvals",
1177
+ "panel.trigger": "Cordis Plugin",
1178
+ "panel.runningCount": "{count} running",
1179
+ "panel.title": "Cordis plugins",
1180
+ "panel.empty": "No plugins defined yet",
1181
+ "panel.loading": "Reading…",
1182
+ "panel.readFailed": "Reading the plugin inventory failed: {message}",
1183
+ "panel.group.current": "This session",
1184
+ "panel.group.others": "Other sessions",
1185
+ "panel.version": "Version",
1186
+ "panel.current": "Current: {packageId}",
1187
+ "panel.next": "Next: {packageId}",
1188
+ "action.approve": "Allow",
1189
+ "action.approveOnce": "Allow this version only",
1190
+ "action.approvePlugin": "Allow future versions of this plugin",
1191
+ "action.decline": "Decline",
1192
+ "action.run": "Run",
1193
+ "action.stop": "Stop",
1194
+ "action.remove": "Remove",
1195
+ "action.retry": "Retry",
1196
+ "action.rollback": "Roll back",
1197
+ "render.failedAbdicated": "Rendering failed in {slot}; the default UI was restored:",
1198
+ "render.failedHeld": "Rendering failed in {slot}:",
1199
+ "a11y.defining": "Defining the plugin",
1200
+ "a11y.failed": "Definition failed",
1201
+ "a11y.stopped": "Definition interrupted",
1202
+ "body.source": "Plugin source",
1203
+ "body.hostCode": "Host",
1204
+ "body.clientCode": "Client",
1205
+ "body.output": "Result",
1206
+ "body.copy": "Copy",
1207
+ "body.copied": "Copied"
1208
+ };
1209
+ //#endregion
1210
+ //#region lib/types/client/index.js
1211
+ /** Cordis dynamic-plugin cards, inventory panel, business-view host, and `@pluginId` source. */
1212
+ /** Required services for the two Tool cards, panel, Remote lifecycle, and Slash source. */
1213
+ const inject = [
1214
+ "slots",
1215
+ "locale",
1216
+ "inputTriggers",
1217
+ "remote",
1218
+ "remote.dynamicCordisRunner",
1219
+ "dynamicCordisRunner"
1220
+ ];
1221
+ /** Mount every Cordis browser surface over the shared Host inventory. */
1222
+ function apply(ctx) {
1223
+ ctx.effect(() => ctx.locale.register(NS, { en }), "ui-cordis: dictionaries");
1224
+ const port = {
1225
+ stop: async (sessionId, pluginId) => {
1226
+ const answered = await ctx.remote.dynamicCordisRunner.stopFromPanel(sessionId, pluginId);
1227
+ if (!answered.ok) return {
1228
+ ok: false,
1229
+ message: `${answered.error.code}: ${answered.error.message}`
1230
+ };
1231
+ if (answered.value.ok || answered.value.reason === "not-running") return { ok: true };
1232
+ return {
1233
+ ok: false,
1234
+ message: answered.value.message
1235
+ };
1236
+ },
1237
+ remove: async (sessionId, pluginId) => {
1238
+ const answered = await ctx.remote.dynamicCordisRunner.undefineFromPanel(sessionId, pluginId);
1239
+ if (!answered.ok) return {
1240
+ ok: false,
1241
+ message: `${answered.error.code}: ${answered.error.message}`
1242
+ };
1243
+ return answered.value.ok ? { ok: true } : {
1244
+ ok: false,
1245
+ message: answered.value.message
1246
+ };
1247
+ },
1248
+ inventory: async () => {
1249
+ const answered = await ctx.remote.dynamicCordisRunner.inventory();
1250
+ if (!answered.ok) throw new Error(`${answered.error.code}: ${answered.error.message}`);
1251
+ return answered.value;
1252
+ }
1253
+ };
1254
+ const inventory = createCordisInventory(port, (error) => {
1255
+ console.error("[ui-cordis] reading the Cordis inventory failed:", error);
1256
+ });
1257
+ const runner = ctx.dynamicCordisRunner;
1258
+ const loaded = {
1259
+ getSnapshot: () => runner.getSnapshot(),
1260
+ subscribe: (fn) => runner.subscribe(fn)
1261
+ };
1262
+ const runCards = new CordisRunCardRegistry();
1263
+ ctx.effect(() => inventory.subscribe(() => {
1264
+ const snapshot = inventory.getSnapshot();
1265
+ if (snapshot.read) runner.reconcileApprovals(snapshot.rows);
1266
+ }), "ui-cordis: reconcile pending approvals");
1267
+ ctx.remote.$on("cordis/dynamic-package", () => {
1268
+ inventory.refresh();
1269
+ });
1270
+ ctx.remote.$on("cordis/dynamic-retract", () => {
1271
+ inventory.refresh();
1272
+ });
1273
+ ctx.remote.$on("cordis/request-run", (request) => {
1274
+ if (!inventory.getSnapshot().rows.some((row) => row.pluginId === request.pluginId)) inventory.refresh();
1275
+ });
1276
+ ctx.remote.$on("cordis/request-run-resolved", () => {
1277
+ inventory.refresh();
1278
+ });
1279
+ ctx.on("connection/reset", () => {
1280
+ inventory.reset();
1281
+ inventory.refresh();
1282
+ });
1283
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
1284
+ name: "sidebar.footer.action",
1285
+ id: "cordis-panel",
1286
+ locale: NS,
1287
+ inject: () => ({
1288
+ hooks: {
1289
+ inventory,
1290
+ activeRuns: runner.activeRuns,
1291
+ runErrors: runner.lastRunError,
1292
+ loaded,
1293
+ renderFailures: runner.renderFailures
1294
+ },
1295
+ onApprove: (requestId, approveFutureVersions) => runner.approve(requestId, approveFutureVersions),
1296
+ onDecline: (requestId) => runner.decline(requestId),
1297
+ onRun: (request) => runner.startUserRun(request),
1298
+ onStop: async (sessionId, pluginId) => {
1299
+ const result = await port.stop(sessionId, pluginId);
1300
+ inventory.refresh();
1301
+ return result;
1302
+ },
1303
+ onRemove: async (sessionId, pluginId) => {
1304
+ const result = await port.remove(sessionId, pluginId);
1305
+ if (result.ok) inventory.retire(pluginId);
1306
+ inventory.refresh();
1307
+ return result;
1308
+ },
1309
+ onRefresh: () => {
1310
+ inventory.refresh();
1311
+ }
1312
+ })
1313
+ }, CordisPanel));
1314
+ const cardFace = () => ({ hooks: {
1315
+ inventory,
1316
+ loaded
1317
+ } });
1318
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1319
+ name: "tool.call.toolview",
1320
+ key: "cordis_define",
1321
+ locale: NS,
1322
+ inject: cardFace
1323
+ }, CordisDefineRow));
1324
+ ctx.slots.inject("tool.call.toolview", () => ctx.slots.register({
1325
+ name: "tool.call.toolview",
1326
+ key: "cordis_run",
1327
+ locale: NS,
1328
+ children: { "tool.view.cordis": {
1329
+ kind: "keyed",
1330
+ scope: "session"
1331
+ } },
1332
+ inject: (sessionId) => {
1333
+ const store = runCards.forSession(sessionId);
1334
+ return {
1335
+ hooks: {
1336
+ inventory,
1337
+ loaded,
1338
+ runCards: store,
1339
+ activeRuns: runner.activeRuns
1340
+ },
1341
+ onObserveRunCard: (pointer) => {
1342
+ store.observe(pointer);
1343
+ }
1344
+ };
1345
+ }
1346
+ }, CordisRunRow));
1347
+ ctx.slots.inject("tool.call.toolview", function* () {
1348
+ yield ctx.slots.register({
1349
+ name: "tool.call.toolview",
1350
+ key: "cordis_stop",
1351
+ locale: NS
1352
+ }, CordisActionRow);
1353
+ yield ctx.slots.register({
1354
+ name: "tool.call.toolview",
1355
+ key: "cordis_undefine",
1356
+ locale: NS
1357
+ }, CordisActionRow);
1358
+ });
1359
+ const rowsOf = (sessionId, query) => inventory.getSnapshot().rows.filter((row) => row.agentId === sessionId && String(row.pluginId).includes(query));
1360
+ const source = {
1361
+ trigger: "@",
1362
+ name: "cordis",
1363
+ order: 1,
1364
+ candidates(session, { query }) {
1365
+ const rows = rowsOf(session.sessionId, query);
1366
+ return Promise.resolve(rows.map((row) => {
1367
+ const packageId = row.nextPackageId ?? row.currentPackageId ?? row.packages.at(-1)?.packageId;
1368
+ const pkg = packageId === void 0 ? void 0 : row.packages.find((candidate) => candidate.packageId === packageId);
1369
+ return {
1370
+ name: String(row.pluginId),
1371
+ ...pkg === void 0 ? {} : { description: pkg.purpose }
1372
+ };
1373
+ }));
1374
+ },
1375
+ warm() {
1376
+ inventory.refresh();
1377
+ },
1378
+ lexicon(session) {
1379
+ return rowsOf(session.sessionId, "").map((row) => String(row.pluginId));
1380
+ },
1381
+ subscribeLexicon(_session, listener) {
1382
+ return inventory.subscribe(listener);
1383
+ },
1384
+ onPick({ candidate }) {
1385
+ return { text: `@${candidate.name} ` };
1386
+ }
1387
+ };
1388
+ const slash = ctx.get("inputTriggers");
1389
+ ctx.effect(() => slash.registerSource(source), "ui-cordis: @pluginId source");
1390
+ inventory.refresh();
1391
+ }
1392
+ //#endregion
1393
+ exports.apply = apply;
1394
+ exports.inject = inject;
1395
+ return module.exports;
1396
+ }
1397
+ });
1398
+
1399
+ //# sourceMappingURL=client.js.map