dsh-atlassian-plugin 0.0.0-stage → 0.3.2

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,1684 @@
1
+ window.__ModuleLoader__.load({ id: "dsh-atlassian-plugin", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/client/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ apply: () => apply,
25
+ inject: () => inject
26
+ });
27
+ module.exports = __toCommonJS(index_exports);
28
+
29
+ // ../integration-ui/src/card/definition.ts
30
+ var resultCallId = (match) => {
31
+ if (match.event.type !== "tool/result") return void 0;
32
+ const source = match.event.data.message.source;
33
+ return typeof source.callId === "string" ? source.callId : void 0;
34
+ };
35
+ var createPresentationType = (spec) => {
36
+ const select = (owner) => {
37
+ const data = owner.turn.data.get(spec.turnDataKey);
38
+ if (data === void 0) return null;
39
+ const bound = owner.turn.end?.seq ?? owner.seq;
40
+ const presentations2 = data.presentations.filter(
41
+ (presentation2) => presentation2.seq <= bound
42
+ );
43
+ return presentations2.length === 0 ? null : { presentations: presentations2 };
44
+ };
45
+ const definition = {
46
+ kind: spec.turnDataKey,
47
+ match: (event) => {
48
+ if (event.type === "turn/start")
49
+ return { id: String(event.data.turn), role: "start" };
50
+ if (event.type === "tool/call" || event.type === "tool/result")
51
+ return { id: String(event.data.turn), role: "update" };
52
+ return null;
53
+ },
54
+ start: (_context, match) => {
55
+ if (match.event.type !== "turn/start")
56
+ throw new Error(`${spec.turnDataKey} start requires turn/start`);
57
+ return {
58
+ turn: match.event.data.turn,
59
+ calls: /* @__PURE__ */ new Map(),
60
+ presentations: []
61
+ };
62
+ },
63
+ update: (context, match) => {
64
+ if (match.event.type === "tool/call") {
65
+ const calls = new Map(context.state.calls);
66
+ calls.set(String(match.event.data.callId), {
67
+ name: match.event.data.name
68
+ });
69
+ return { ...context.state, calls };
70
+ }
71
+ if (match.event.type !== "tool/result") return context.state;
72
+ if (match.event.data.message.isError === true) return context.state;
73
+ const callId = resultCallId(match);
74
+ if (callId === void 0) return context.state;
75
+ if (context.state.calls.get(callId)?.name !== spec.toolName)
76
+ return context.state;
77
+ const card2 = spec.parse(match.event.data.meta);
78
+ if (card2 === void 0) return context.state;
79
+ const present = { card: card2, seq: match.event.seq };
80
+ return {
81
+ ...context.state,
82
+ presentations: spec.keep === "last" ? [present] : [...context.state.presentations, present]
83
+ };
84
+ },
85
+ buildLocationData: (context, scope, previous) => {
86
+ if (scope !== "turn" || context.state === void 0) return null;
87
+ const prior = previous;
88
+ if (prior?.kind === "turn" && prior.turn === context.state.turn && prior.key === spec.turnDataKey && prior.value.presentations === context.state.presentations)
89
+ return previous;
90
+ return {
91
+ kind: "turn",
92
+ turn: context.state.turn,
93
+ key: spec.turnDataKey,
94
+ value: { presentations: context.state.presentations }
95
+ };
96
+ }
97
+ };
98
+ return { definition, select, card: spec.card };
99
+ };
100
+
101
+ // ../integration-ui/src/styles/styles.css.ts
102
+ var actions = "_9d1h6n8";
103
+ var caption = "_9d1h6n7";
104
+ var card = "_9d1h6n1";
105
+ var code = "_9d1h6no";
106
+ var error = "_9d1h6np";
107
+ var factInline = "_9d1h6nf";
108
+ var factInlineLabel = "_9d1h6ng";
109
+ var factLabel = "_9d1h6nc";
110
+ var factValue = "_9d1h6nd";
111
+ var facts = "_9d1h6nb";
112
+ var factsInline = "_9d1h6ne";
113
+ var field = "_9d1h6na";
114
+ var head = "_9d1h6n2";
115
+ var link = "_9d1h6nn";
116
+ var list = "_9d1h6nh";
117
+ var panel = "_9d1h6nz";
118
+ var panelLoading = "_9d1h6n11";
119
+ var panelScroll = "_9d1h6n10";
120
+ var presentation = "_9d1h6nr";
121
+ var presentationCount = "_9d1h6nu";
122
+ var presentationHead = "_9d1h6ns";
123
+ var presentationTitle = "_9d1h6nt";
124
+ var presentations = "_9d1h6nq";
125
+ var row = "_9d1h6n9";
126
+ var section = "_9d1h6n0";
127
+ var state = "_9d1h6n4";
128
+ var stateWord = "_9d1h6n5";
129
+ var title = "_9d1h6n3";
130
+ var toolLabel = "_9d1h6ny";
131
+ var toolRow = "_9d1h6nx";
132
+
133
+ // ../integration-ui/src/card/tail.tsx
134
+ var import_jsx_runtime = require("react/jsx-runtime");
135
+ var SCROLL_AFTER = 4;
136
+ var createPresentationTail = (type) => {
137
+ const Tail = (props) => {
138
+ const matched = type.select(props);
139
+ if (matched === null) return null;
140
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: presentations, children: matched.presentations.map((presentation2) => {
141
+ const card2 = presentation2.card;
142
+ const callId = type.card.callId(card2);
143
+ const title2 = type.card.title(card2);
144
+ const meta = type.card.meta?.(card2, props);
145
+ const footer = type.card.footer?.(card2, props);
146
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
147
+ "section",
148
+ {
149
+ className: presentation,
150
+ "data-integration-card": callId,
151
+ children: [
152
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: presentationHead, children: [
153
+ title2 === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: presentationTitle, children: title2 }),
154
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: presentationCount, children: type.card.count(card2) })
155
+ ] }),
156
+ meta,
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
158
+ "ul",
159
+ {
160
+ className: list,
161
+ "data-layout": type.card.layout(card2),
162
+ "data-scrollable": type.card.length(card2) > SCROLL_AFTER ? "true" : void 0,
163
+ children: type.card.items(card2, props)
164
+ }
165
+ ),
166
+ footer
167
+ ]
168
+ },
169
+ callId
170
+ );
171
+ }) });
172
+ };
173
+ return Tail;
174
+ };
175
+
176
+ // ../integration-ui/src/fact.tsx
177
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
178
+ var import_react = require("react");
179
+ var import_jsx_runtime2 = require("react/jsx-runtime");
180
+ var hasValue = (item2) => item2.value !== void 0 && item2.value !== null && item2.value !== "" && // React collapses a fragment of nulls to nothing; an empty array is the same
181
+ // answer from a provider that built its rows conditionally.
182
+ !(Array.isArray(item2.value) && item2.value.length === 0);
183
+ var Facts = ({
184
+ items,
185
+ layout = "rows"
186
+ }) => {
187
+ const shown = items.filter(hasValue);
188
+ if (shown.length === 0) return null;
189
+ if (layout === "inline") {
190
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: factsInline, children: shown.map((item2) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: factInline, children: [
191
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: factInlineLabel, children: item2.label }),
192
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: factValue, children: item2.value })
193
+ ] }, item2.label)) });
194
+ }
195
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dl", { className: facts, children: shown.map((item2) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react.Fragment, { children: [
196
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dt", { className: factLabel, children: item2.label }),
197
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("dd", { className: factValue, children: item2.value })
198
+ ] }, item2.label)) });
199
+ };
200
+ var Chip = ({ label, value, tone = "outline" }) => {
201
+ if (value === void 0 || value === "") return null;
202
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives.Tag, { tone, children: label === void 0 ? value : `${label}: ${value}` });
203
+ };
204
+
205
+ // ../integration-ui/src/host-api.ts
206
+ var createHostRequest = (basePath) => {
207
+ const failureOf = async (response) => {
208
+ try {
209
+ const body = await response.json();
210
+ if (body !== null && typeof body === "object" && typeof body.error === "string")
211
+ return body.error;
212
+ } catch {
213
+ }
214
+ return `host answered ${response.status} ${response.statusText}`;
215
+ };
216
+ return async (path, method, body, signal) => {
217
+ const response = await fetch(`${basePath}${path}`, {
218
+ method,
219
+ headers: body === void 0 ? { accept: "application/json" } : { accept: "application/json", "content-type": "application/json" },
220
+ ...body === void 0 ? {} : { body: JSON.stringify(body) },
221
+ ...signal === void 0 ? {} : { signal }
222
+ });
223
+ if (!response.ok) throw new Error(await failureOf(response));
224
+ return await response.json();
225
+ };
226
+ };
227
+
228
+ // ../integration-ui/src/panel/body.tsx
229
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
230
+ var import_react2 = require("react");
231
+ var import_jsx_runtime3 = require("react/jsx-runtime");
232
+ var messageOf = (error2) => error2 instanceof Error ? error2.message : String(error2);
233
+ var createPanelBody = (provider2) => {
234
+ const Panel = (props) => {
235
+ const { tab } = props.useTabInfo();
236
+ const params = provider2.parseParams(tab.navigation.params);
237
+ const revision = tab.navigation.revision;
238
+ const identity = params === void 0 ? "" : provider2.identity(params);
239
+ const [load, setLoad] = (0, import_react2.useState)({
240
+ status: "loading"
241
+ });
242
+ const [failure, setFailure] = (0, import_react2.useState)(void 0);
243
+ const [busy, setBusy] = (0, import_react2.useState)(false);
244
+ const current = (0, import_react2.useRef)(params);
245
+ current.current = params;
246
+ const fetchPanel = (0, import_react2.useCallback)(
247
+ async (signal) => {
248
+ const wanted = current.current;
249
+ if (wanted === void 0) {
250
+ setLoad({ status: "error", message: provider2.emptyMessage });
251
+ return;
252
+ }
253
+ setLoad({ status: "loading" });
254
+ try {
255
+ const data = provider2.parse(await provider2.fetch(wanted, signal));
256
+ if (data === void 0)
257
+ throw new Error(
258
+ "the host answered with a document this version cannot draw"
259
+ );
260
+ if (signal?.aborted !== true)
261
+ setLoad({ status: "ready", data, params: wanted });
262
+ } catch (error2) {
263
+ if (signal?.aborted !== true)
264
+ setLoad({ status: "error", message: messageOf(error2) });
265
+ }
266
+ },
267
+ []
268
+ );
269
+ (0, import_react2.useEffect)(() => {
270
+ const controller = new AbortController();
271
+ setFailure(void 0);
272
+ void fetchPanel(controller.signal);
273
+ return () => {
274
+ controller.abort();
275
+ };
276
+ }, [identity, revision, fetchPanel]);
277
+ const run = (0, import_react2.useCallback)(
278
+ (write) => {
279
+ const wanted = current.current;
280
+ if (wanted === void 0) return;
281
+ setBusy(true);
282
+ setFailure(void 0);
283
+ write(wanted).then((answer) => {
284
+ const data = provider2.parse(answer);
285
+ if (data === void 0)
286
+ throw new Error(
287
+ "the host answered with a document this version cannot draw"
288
+ );
289
+ setLoad({ status: "ready", data, params: wanted });
290
+ }).catch((error2) => {
291
+ setFailure(messageOf(error2));
292
+ void fetchPanel();
293
+ }).finally(() => {
294
+ setBusy(false);
295
+ });
296
+ },
297
+ [fetchPanel]
298
+ );
299
+ const actions3 = { busy, run };
300
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: panel, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: panelScroll, children: [
301
+ load.status === "loading" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
302
+ "div",
303
+ {
304
+ className: panelLoading,
305
+ role: "status",
306
+ "aria-live": "polite",
307
+ children: [
308
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives2.StateDot, { state: "ongoing", size: 20 }),
309
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives2.TextShimmer, { active: true, children: "Loading\u2026" })
310
+ ]
311
+ }
312
+ ) : null,
313
+ load.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
314
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: error, children: load.message }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: actions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives2.Button, { size: "sm", onClick: () => void fetchPanel(), children: "Try again" }) })
316
+ ] }) : null,
317
+ failure === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: error, children: failure }),
318
+ load.status === "ready" ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
319
+ import_dsh_client_ui_primitives2.MarkdownDelegateProvider,
320
+ {
321
+ openExternalLink: (href) => {
322
+ window.open(href, "_blank", "noopener,noreferrer");
323
+ },
324
+ children: provider2.view({
325
+ data: load.data,
326
+ params: load.params,
327
+ actions: actions3
328
+ })
329
+ }
330
+ ) : null
331
+ ] }) });
332
+ };
333
+ return Panel;
334
+ };
335
+
336
+ // ../integration-ui/src/panel/definition.ts
337
+ var createPanelDefinition = (spec) => {
338
+ return {
339
+ id: spec.id,
340
+ kind: spec.kind,
341
+ // A type from outside the product outranks the shipped ones, which is the
342
+ // band the Sidebar's own documentation reserves for exactly this.
343
+ priority: "extension",
344
+ title: () => spec.title
345
+ };
346
+ };
347
+
348
+ // ../integration-ui/src/panel/open.ts
349
+ var createPanelOpener = (ctx, kind) => {
350
+ return {
351
+ open: (params) => {
352
+ const sidebar = ctx.get("sidebarRight");
353
+ if (sidebar === void 0) return false;
354
+ try {
355
+ sidebar.openTab(kind, { params });
356
+ return true;
357
+ } catch {
358
+ return false;
359
+ }
360
+ }
361
+ };
362
+ };
363
+ var wantsBrowser = (event) => {
364
+ return event.metaKey || event.ctrlKey || event.shiftKey || event.altKey || event.button !== 0;
365
+ };
366
+
367
+ // ../integration-ui/src/panel/title.tsx
368
+ var createPanelTitle = (provider2) => {
369
+ const Title = (props) => {
370
+ const { tab } = props.useTabInfo();
371
+ const params = provider2.parseParams(tab.navigation.params);
372
+ return (params === void 0 ? void 0 : provider2.title(params)) ?? tab.title;
373
+ };
374
+ return Title;
375
+ };
376
+
377
+ // ../integration-ui/src/settings/section.tsx
378
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
379
+ var import_react3 = require("react");
380
+ var import_jsx_runtime4 = require("react/jsx-runtime");
381
+ var POLL_MS = 1500;
382
+ var connectionState = (status) => {
383
+ if (status?.inFlight === true) return "ongoing";
384
+ return status?.connected === true ? "done" : "idle";
385
+ };
386
+ var stateText = (status, credentials) => {
387
+ if (status.inFlight === true) return "Connecting";
388
+ if (credentials === "none")
389
+ return status.connected === true ? "Connected" : "Not connected";
390
+ return status.signedIn === true ? "Signed in" : "Not signed in";
391
+ };
392
+ var createSettingsSection = (spec) => {
393
+ const Section2 = () => {
394
+ const mounted = (0, import_react3.useRef)(true);
395
+ const [status, setStatus] = (0, import_react3.useState)(null);
396
+ const [failure, setFailure] = (0, import_react3.useState)(null);
397
+ const [pending, setPending] = (0, import_react3.useState)(null);
398
+ const [typed, setTyped] = (0, import_react3.useState)("");
399
+ const [replacing, setReplacing] = (0, import_react3.useState)(false);
400
+ const refresh = (0, import_react3.useCallback)(async () => {
401
+ try {
402
+ const next = await spec.api.status();
403
+ if (!mounted.current) return;
404
+ setStatus(next);
405
+ setFailure(null);
406
+ } catch (error2) {
407
+ if (!mounted.current) return;
408
+ setStatus(null);
409
+ setFailure(error2 instanceof Error ? error2.message : String(error2));
410
+ }
411
+ }, []);
412
+ (0, import_react3.useEffect)(() => {
413
+ mounted.current = true;
414
+ void refresh();
415
+ return () => {
416
+ mounted.current = false;
417
+ };
418
+ }, [refresh]);
419
+ (0, import_react3.useEffect)(() => {
420
+ if (status?.inFlight !== true) return;
421
+ const timer = setInterval(refresh, POLL_MS);
422
+ return () => clearInterval(timer);
423
+ }, [status?.inFlight, refresh]);
424
+ const act = (0, import_react3.useCallback)(
425
+ async (key, action) => {
426
+ setPending(key);
427
+ try {
428
+ const next = await action();
429
+ if (!mounted.current) return;
430
+ setStatus(next);
431
+ setFailure(null);
432
+ } catch (error2) {
433
+ if (!mounted.current) return;
434
+ setFailure(error2 instanceof Error ? error2.message : String(error2));
435
+ } finally {
436
+ if (mounted.current) setPending(null);
437
+ }
438
+ },
439
+ []
440
+ );
441
+ const tokenField = spec.token;
442
+ if (status === null) {
443
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: section, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: card, children: [
444
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: head, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: title, children: spec.title }) }),
445
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: caption, children: failure === null ? spec.checking : spec.unreachable }),
446
+ failure === null ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: code, children: failure }),
447
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: actions, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.Button, { variant: "outline", onClick: refresh, children: "Try again" }) })
448
+ ] }) });
449
+ }
450
+ const signedIn = status.signedIn === true;
451
+ const waiting = status.inFlight === true;
452
+ const toolCount = status.tools.length;
453
+ const expiry = signedIn && spec.credentials !== "none" ? status.expiresAt : null;
454
+ const showField = tokenField !== void 0 && (!signedIn || replacing);
455
+ const field2 = spec.token;
456
+ const label = (key, text) => pending === key ? "Working\u2026" : text;
457
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("section", { className: section, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: card, children: [
458
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: head, children: [
459
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: title, children: spec.title }),
460
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: state, children: [
461
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: connectionState(status) }),
462
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: stateWord, children: stateText(status, spec.credentials) }),
463
+ toolCount === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: `\xB7 ${toolCount} tool${toolCount === 1 ? "" : "s"}` })
464
+ ] })
465
+ ] }),
466
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: caption, children: spec.blurb }),
467
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
468
+ Facts,
469
+ {
470
+ items: [
471
+ ...spec.details?.(status) ?? [],
472
+ ...expiry === null ? [] : [
473
+ {
474
+ label: "Token",
475
+ value: `valid until ${new Date(expiry).toLocaleString()}`
476
+ }
477
+ ]
478
+ ]
479
+ }
480
+ ),
481
+ waiting ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: row, children: [
482
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "ongoing" }),
483
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: caption, children: "Waiting for you to approve the sign-in in your browser\u2026" })
484
+ ] }) : null,
485
+ status.notice?.url !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: row, children: [
486
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: caption, children: status.notice.message }),
487
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
488
+ "a",
489
+ {
490
+ className: link,
491
+ href: status.notice.url,
492
+ target: "_blank",
493
+ rel: "noreferrer",
494
+ children: "Open the sign-in page"
495
+ }
496
+ )
497
+ ] }) : null,
498
+ status.error != null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: row, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: error, children: status.error }) }) : null,
499
+ showField && field2 !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
500
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: field, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
501
+ import_dsh_client_ui_primitives3.Input,
502
+ {
503
+ type: "password",
504
+ value: typed,
505
+ placeholder: field2.placeholder,
506
+ "aria-label": field2.label,
507
+ disabled: pending !== null,
508
+ onChange: (event) => {
509
+ setTyped(event.target.value);
510
+ }
511
+ }
512
+ ) }),
513
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: caption, children: field2.hint })
514
+ ] }) : null,
515
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: actions, children: [
516
+ spec.credentials === "browser" ? signedIn ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
517
+ import_dsh_client_ui_primitives3.Button,
518
+ {
519
+ variant: "outline",
520
+ disabled: pending !== null,
521
+ onClick: () => void act("logout", spec.api.logout),
522
+ children: label("logout", "Sign out")
523
+ }
524
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
525
+ import_dsh_client_ui_primitives3.Button,
526
+ {
527
+ variant: "primary",
528
+ disabled: pending !== null || waiting,
529
+ onClick: () => void act("login", spec.api.login),
530
+ children: label("login", waiting ? "Waiting\u2026" : spec.signInLabel)
531
+ }
532
+ ) : null,
533
+ spec.credentials === "typed" && field2 !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
534
+ showField ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
535
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
536
+ import_dsh_client_ui_primitives3.Button,
537
+ {
538
+ variant: "primary",
539
+ disabled: pending !== null || typed.trim() === "",
540
+ onClick: () => {
541
+ void act("save", async () => {
542
+ const next = await field2.save(typed);
543
+ setTyped("");
544
+ setReplacing(false);
545
+ return next;
546
+ });
547
+ },
548
+ children: label("save", field2.saveLabel)
549
+ }
550
+ ),
551
+ signedIn ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
552
+ import_dsh_client_ui_primitives3.Button,
553
+ {
554
+ variant: "ghost",
555
+ disabled: pending !== null,
556
+ onClick: () => {
557
+ setTyped("");
558
+ setReplacing(false);
559
+ },
560
+ children: "Cancel"
561
+ }
562
+ ) : null
563
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
564
+ import_dsh_client_ui_primitives3.Button,
565
+ {
566
+ variant: "outline",
567
+ disabled: pending !== null,
568
+ onClick: () => {
569
+ setReplacing(true);
570
+ },
571
+ children: field2.replaceLabel
572
+ }
573
+ ),
574
+ signedIn ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
575
+ import_dsh_client_ui_primitives3.Button,
576
+ {
577
+ variant: "ghost",
578
+ disabled: pending !== null,
579
+ onClick: () => void act("logout", spec.api.logout),
580
+ children: label("logout", field2.clearLabel)
581
+ }
582
+ ) : null
583
+ ] }) : null,
584
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
585
+ import_dsh_client_ui_primitives3.Button,
586
+ {
587
+ variant: "ghost",
588
+ disabled: pending !== null || waiting,
589
+ onClick: () => void act("sync", spec.api.sync),
590
+ children: label("sync", spec.syncLabel)
591
+ }
592
+ )
593
+ ] })
594
+ ] }) });
595
+ };
596
+ return Section2;
597
+ };
598
+
599
+ // ../integration-ui/src/settings/tab.ts
600
+ var registerIntegrationsTab = (ctx, spec, card2) => {
601
+ ctx.slots.inject(
602
+ "integrations.tab",
603
+ () => ctx.slots.register(
604
+ {
605
+ name: "integrations.tab",
606
+ id: spec.id,
607
+ order: spec.order,
608
+ label: spec.label
609
+ },
610
+ card2
611
+ )
612
+ );
613
+ };
614
+
615
+ // ../integration-ui/src/styles/runtime.ts
616
+ var installStyles = (pluginId, css) => {
617
+ const style = document.createElement("style");
618
+ style.setAttribute("data-plugin", pluginId);
619
+ style.textContent = css;
620
+ document.head.append(style);
621
+ return () => style.remove();
622
+ };
623
+
624
+ // ../integration-ui/src/tool/row.tsx
625
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
626
+ var import_jsx_runtime5 = require("react/jsx-runtime");
627
+ var resultText = (block) => (block?.content ?? []).filter((item2) => item2.type === "text" && typeof item2.text === "string").map((item2) => item2.text ?? "").join("\n").trim();
628
+ var createToolRow = (spec) => {
629
+ const Row = ({ phase, block, toolName }) => {
630
+ const name = spec.displayName(toolName);
631
+ if (phase !== "result") {
632
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: toolRow, "data-tool": toolName, title: toolName, children: [
633
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.StateDot, { state: "ongoing" }),
634
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: toolLabel, children: name }),
635
+ spec.asked === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: caption, children: spec.asked(block) ?? "\u2026" })
636
+ ] });
637
+ }
638
+ if (block?.isError === true) {
639
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: toolRow, "data-tool": toolName, title: toolName, children: [
640
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.StateDot, { state: "error" }),
641
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: toolLabel, children: name }),
642
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `${caption} ${error}`, children: resultText(block) || "failed" })
643
+ ] });
644
+ }
645
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: toolRow, "data-tool": toolName, title: toolName, children: [
646
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.StateDot, { state: spec.state?.(block) ?? "done" }),
647
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: toolLabel, children: name }),
648
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: caption, children: spec.summarize(block) })
649
+ ] });
650
+ };
651
+ return Row;
652
+ };
653
+
654
+ // ../mcp-oauth/src/tool-name.ts
655
+ var MAX_TOOL_NAME = 64;
656
+ function toolPrefix(namespace) {
657
+ return `mcp__${namespace}__`;
658
+ }
659
+ function publicToolName(serverTool, namespace) {
660
+ const cleaned = serverTool.replace(/[^A-Za-z0-9_-]/gu, "_") || "tool";
661
+ const full = `${toolPrefix(namespace)}${cleaned}`;
662
+ if (full.length <= MAX_TOOL_NAME) return full;
663
+ const digest = digestOf(serverTool);
664
+ return `${full.slice(0, MAX_TOOL_NAME - digest.length - 1)}_${digest}`;
665
+ }
666
+ function digestOf(input) {
667
+ let hash = 0xcbf29ce484222325n;
668
+ const prime = 0x100000001b3n;
669
+ const mask = 0xffffffffffffffffn;
670
+ for (let index = 0; index < input.length; index += 1) {
671
+ hash = (hash ^ BigInt(input.charCodeAt(index))) * prime & mask;
672
+ }
673
+ return hash.toString(16).padStart(16, "0").slice(0, 12);
674
+ }
675
+
676
+ // src/shared/tool-names.ts
677
+ var TOOL_NAMESPACE = "atlassian";
678
+ var TOOL_NAMES = [
679
+ // Shared and v2 gateway tools.
680
+ "atlassianUserInfo",
681
+ "getAccessibleAtlassianResources",
682
+ "discover",
683
+ "getContentFormatGuide",
684
+ "executeRead",
685
+ "executeWrite",
686
+ "executeDestructive",
687
+ // Jira, both generations.
688
+ "getJiraIssue",
689
+ "searchJiraIssuesUsingJql",
690
+ "createJiraIssue",
691
+ "editJiraIssue",
692
+ "transitionJiraIssue",
693
+ "addOrEditJiraIssueComment",
694
+ "addCommentToJiraIssue",
695
+ "getJiraProjectIssueTypesMetadata",
696
+ "listJiraProjects",
697
+ "listJiraIssueComments",
698
+ "listJiraIssueTransitions",
699
+ "listJiraStatuses",
700
+ "getJiraUser",
701
+ "getJiraCurrentUser",
702
+ "lookupJiraAccountId",
703
+ "listJiraIssueAssignableUsers",
704
+ "listJiraIssueWorklogs",
705
+ "listJiraIssueLinkTypes",
706
+ "listJiraIssueRemoteIssueLinks",
707
+ "listJiraIssueChangelogs",
708
+ "listJiraFilters",
709
+ "listJiraDashboards",
710
+ "listJiraBoards",
711
+ "getJiraBoardConfig",
712
+ "getJiraBoardIssueData",
713
+ "getJiraBoardSprintData",
714
+ "listJiraBoardSprints",
715
+ "listJiraProjectComponents",
716
+ "getJiraProjectVersions",
717
+ "getJiraEntityProperty",
718
+ "addOrEditJiraIssueWorklog",
719
+ "createJiraIssueLink",
720
+ "watchJiraIssue",
721
+ "manageJiraSprint",
722
+ "manageJiraProjectVersion",
723
+ "uploadAttachmentToJiraIssue",
724
+ "downloadJiraIssueAttachment",
725
+ // Confluence, both generations.
726
+ "getConfluencePage",
727
+ "getConfluenceContent",
728
+ "searchConfluenceUsingCql",
729
+ "searchConfluence",
730
+ "createConfluencePage",
731
+ "updateConfluencePage",
732
+ "createConfluenceContent",
733
+ "updateConfluenceContent",
734
+ "getConfluenceSpaces",
735
+ "listConfluenceSpaces",
736
+ "getConfluenceSpace",
737
+ "listConfluenceContent",
738
+ "listConfluenceComments",
739
+ "getConfluenceComment",
740
+ "listConfluenceAttachments",
741
+ "getConfluenceAttachment",
742
+ "listConfluenceContentVersions",
743
+ "getConfluenceContentVersion",
744
+ "exportConfluenceContent",
745
+ "listConfluenceTasks",
746
+ "getConfluenceTask",
747
+ "listConfluenceTemplates",
748
+ "getConfluenceTemplate",
749
+ "getConfluenceContentPermissions",
750
+ "getConfluenceSpaceInstructions",
751
+ "createConfluenceComment",
752
+ "updateConfluenceComment",
753
+ "createConfluenceAttachment",
754
+ // Rovo search, which often answers a Jira or Confluence question.
755
+ "search"
756
+ ];
757
+ var PUBLIC_TOOL_NAMES = TOOL_NAMES.map(
758
+ (name) => publicToolName(name, TOOL_NAMESPACE)
759
+ );
760
+
761
+ // src/shared/presentation.ts
762
+ function isRecord(value) {
763
+ return value !== null && typeof value === "object" && !Array.isArray(value);
764
+ }
765
+ function asItem(value) {
766
+ if (!isRecord(value)) return void 0;
767
+ if (value.kind === "issue" && isRecord(value.issue) && typeof value.issue.key === "string")
768
+ return { kind: "issue", issue: value.issue };
769
+ if (value.kind === "page" && isRecord(value.page) && typeof value.page.title === "string")
770
+ return { kind: "page", page: value.page };
771
+ return void 0;
772
+ }
773
+ function asPresentation(value) {
774
+ if (!isRecord(value)) return void 0;
775
+ if (typeof value.callId !== "string" || value.callId === "") return void 0;
776
+ if (!Array.isArray(value.items)) return void 0;
777
+ const layout = value.layout === "single" || value.layout === "compact" || value.layout === "list" ? value.layout : "list";
778
+ const items = [];
779
+ for (const candidate of value.items) {
780
+ const item2 = asItem(candidate);
781
+ if (item2 !== void 0) items.push(item2);
782
+ }
783
+ if (items.length === 0) return void 0;
784
+ return {
785
+ callId: value.callId,
786
+ ...typeof value.title === "string" && value.title !== "" ? { title: value.title } : {},
787
+ layout,
788
+ ...typeof value.total === "number" && Number.isFinite(value.total) && value.total > items.length ? { total: value.total } : {},
789
+ items
790
+ };
791
+ }
792
+
793
+ // src/shared/tone.ts
794
+ var TYPE_TONES = {
795
+ bug: "danger",
796
+ defect: "danger",
797
+ \u0431\u0430\u0433: "danger",
798
+ \u043E\u0448\u0438\u0431\u043A\u0430: "danger",
799
+ story: "success",
800
+ "user story": "success",
801
+ \u0438\u0441\u0442\u043E\u0440\u0438\u044F: "success",
802
+ feature: "success",
803
+ improvement: "success",
804
+ \u0443\u043B\u0443\u0447\u0448\u0435\u043D\u0438\u0435: "success",
805
+ task: "info",
806
+ \u0437\u0430\u0434\u0430\u0447\u0430: "info",
807
+ // An epic is the container the others hang from, so it gets the one loud
808
+ // palette: it should be recognizable at a glance in a mixed list.
809
+ epic: "solid",
810
+ \u044D\u043F\u0438\u043A: "solid",
811
+ question: "warning",
812
+ \u0432\u043E\u043F\u0440\u043E\u0441: "warning",
813
+ support: "warning",
814
+ "sub-task": "quiet",
815
+ subtask: "quiet",
816
+ \u043F\u043E\u0434\u0437\u0430\u0434\u0430\u0447\u0430: "quiet"
817
+ };
818
+ var PRIORITY_TONES = {
819
+ p0: "danger",
820
+ p1: "danger",
821
+ blocker: "danger",
822
+ blocking: "danger",
823
+ highest: "danger",
824
+ critical: "danger",
825
+ \u043A\u0440\u0438\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439: "danger",
826
+ p2: "warning",
827
+ high: "warning",
828
+ major: "warning",
829
+ \u0432\u044B\u0441\u043E\u043A\u0438\u0439: "warning",
830
+ \u0431\u043B\u043E\u043A\u0438\u0440\u0443\u044E\u0449\u0438\u0439: "warning",
831
+ // A low or medium priority is a quiet fact, not a status: text only.
832
+ p3: "quiet",
833
+ p4: "quiet",
834
+ p5: "quiet",
835
+ medium: "quiet",
836
+ average: "quiet",
837
+ normal: "quiet",
838
+ low: "quiet",
839
+ lowest: "quiet",
840
+ minor: "quiet",
841
+ trivial: "quiet",
842
+ \u0441\u0440\u0435\u0434\u043D\u0438\u0439: "quiet",
843
+ \u043D\u0438\u0437\u043A\u0438\u0439: "quiet"
844
+ };
845
+ var HOMOGLYPHS = {
846
+ \u0430: "a",
847
+ \u0432: "b",
848
+ \u0435: "e",
849
+ \u043A: "k",
850
+ \u043C: "m",
851
+ \u043D: "h",
852
+ \u043E: "o",
853
+ \u0440: "p",
854
+ \u0441: "c",
855
+ \u0442: "t",
856
+ \u0443: "y",
857
+ \u0445: "x"
858
+ };
859
+ function issueTypeTone(type) {
860
+ return lookup(TYPE_TONES, type);
861
+ }
862
+ function priorityTone(priority) {
863
+ return lookup(PRIORITY_TONES, priority);
864
+ }
865
+ function lookup(table, value) {
866
+ const name = (value ?? "").trim().toLowerCase();
867
+ if (name === "") return "neutral";
868
+ return table[name] ?? table[fold(name)] ?? "neutral";
869
+ }
870
+ function fold(name) {
871
+ return name.replace(
872
+ /[авекмнорстух]/gu,
873
+ (letter) => HOMOGLYPHS[letter] ?? letter
874
+ );
875
+ }
876
+
877
+ // src/client/sidebar/definition.ts
878
+ var PANEL_KIND = "atlassian";
879
+ var PANEL_ID = "dsh-atlassian";
880
+ var panelDefinition = () => createPanelDefinition({ id: PANEL_ID, kind: PANEL_KIND, title: "Atlassian" });
881
+
882
+ // src/client/sidebar/open.ts
883
+ var opener;
884
+ var installPanelOpener = (ctx) => {
885
+ opener = createPanelOpener(ctx, PANEL_KIND);
886
+ };
887
+ var openPanel = (target) => opener?.open(target) ?? false;
888
+
889
+ // src/client/styles/styles.css.ts
890
+ var actions2 = "_9d1h6n8";
891
+ var badges = "_9d1h6n6";
892
+ var caption2 = "_9d1h6n7";
893
+ var comment = "d9jrn16";
894
+ var commentAuthor = "d9jrn18";
895
+ var commentHead = "d9jrn17";
896
+ var comments = "d9jrn15";
897
+ var item = "_9d1h6ni";
898
+ var itemHead = "_9d1h6nj";
899
+ var itemLink = "_9d1h6nl";
900
+ var itemText = "d9jrn10";
901
+ var link2 = "_9d1h6nn";
902
+ var panelBody = "d9jrn11";
903
+ var panelHead = "_9d1h6n12";
904
+ var panelKey = "_9d1h6n15";
905
+ var panelSection = "_9d1h6n17";
906
+ var panelSectionTitle = "_9d1h6n18";
907
+ var panelSummary = "_9d1h6n16";
908
+ var panelTitleRow = "_9d1h6n14";
909
+ var people = "d9jrn12";
910
+ var person = "d9jrn14";
911
+ var personSearch = "d9jrn13";
912
+ var row2 = "_9d1h6n9";
913
+
914
+ // src/client/components/issue-item.tsx
915
+ var import_jsx_runtime6 = require("react/jsx-runtime");
916
+ var IssueItem = ({ issue }) => {
917
+ const title2 = [issue.key, issue.summary].filter((part) => part !== void 0 && part !== "").join(" \xB7 ");
918
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { className: item, children: [
919
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: itemHead, children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Chip, { value: issue.type, tone: issueTypeTone(issue.type) }),
921
+ issue.url === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: title2 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
922
+ "a",
923
+ {
924
+ className: `${link2} ${itemLink}`,
925
+ href: issue.url,
926
+ target: "_blank",
927
+ rel: "noreferrer",
928
+ onClick: (event) => {
929
+ if (wantsBrowser(event)) return;
930
+ if (openPanel({ kind: "issue", key: issue.key }))
931
+ event.preventDefault();
932
+ },
933
+ children: title2
934
+ }
935
+ )
936
+ ] }),
937
+ issue.description === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: itemText, children: issue.description }),
938
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
939
+ Facts,
940
+ {
941
+ layout: "inline",
942
+ items: [
943
+ { label: "Status", value: issue.status },
944
+ {
945
+ label: "Priority",
946
+ value: issue.priority === void 0 ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
947
+ Chip,
948
+ {
949
+ value: issue.priority,
950
+ tone: priorityTone(issue.priority)
951
+ }
952
+ )
953
+ },
954
+ { label: "Assignee", value: issue.assignee },
955
+ { label: "Estimate", value: issue.estimate }
956
+ ]
957
+ }
958
+ )
959
+ ] });
960
+ };
961
+
962
+ // src/client/components/page-item.tsx
963
+ var import_jsx_runtime7 = require("react/jsx-runtime");
964
+ var PageItem = ({ page }) => {
965
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("li", { className: item, children: [
966
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: itemHead, children: page.url === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: page.title }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
967
+ "a",
968
+ {
969
+ className: `${link2} ${itemLink}`,
970
+ href: page.url,
971
+ target: "_blank",
972
+ rel: "noreferrer",
973
+ onClick: (event) => {
974
+ if (wantsBrowser(event) || page.id === void 0) return;
975
+ if (openPanel({
976
+ kind: "page",
977
+ id: page.id,
978
+ title: page.title
979
+ }))
980
+ event.preventDefault();
981
+ },
982
+ children: page.title
983
+ }
984
+ ) }),
985
+ page.excerpt === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: itemText, children: page.excerpt }),
986
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Facts, { layout: "inline", items: [{ label: "Space", value: page.space }] })
987
+ ] });
988
+ };
989
+
990
+ // src/client/components/presentation-card.tsx
991
+ var import_jsx_runtime8 = require("react/jsx-runtime");
992
+ var countLabel = (presentation2) => {
993
+ const issues = presentation2.items.filter(
994
+ (item2) => item2.kind === "issue"
995
+ ).length;
996
+ const pages = presentation2.items.length - issues;
997
+ const total = presentation2.total;
998
+ if (total !== void 0 && (issues === 0 || pages === 0)) {
999
+ const noun = issues === 0 ? "page" : "issue";
1000
+ return `${presentation2.items.length} of ${total} ${noun}${total === 1 ? "" : "s"}`;
1001
+ }
1002
+ return [
1003
+ issues === 0 ? "" : `${issues} issue${issues === 1 ? "" : "s"}`,
1004
+ pages === 0 ? "" : `${pages} page${pages === 1 ? "" : "s"}`
1005
+ ].filter(Boolean).join(" \xB7 ");
1006
+ };
1007
+ var atlassianCard = {
1008
+ callId: (presentation2) => presentation2.callId,
1009
+ title: (presentation2) => presentation2.title,
1010
+ count: countLabel,
1011
+ length: (presentation2) => presentation2.items.length,
1012
+ layout: (presentation2) => presentation2.layout,
1013
+ items: (presentation2) => presentation2.items.map(
1014
+ (item2, index) => item2.kind === "issue" ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1015
+ IssueItem,
1016
+ {
1017
+ issue: item2.issue
1018
+ },
1019
+ item2.issue.key ?? `issue-${index}`
1020
+ ) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PageItem, { page: item2.page }, item2.page.id ?? `page-${index}`)
1021
+ )
1022
+ };
1023
+
1024
+ // src/client/conversation/presentation-definition.ts
1025
+ var PRESENT_TOOL_NAME = "atlassian_present";
1026
+ var PRESENTATION_TURN_DATA_KEY = "atlassian-presented";
1027
+ var atlassianPresentation = createPresentationType({
1028
+ turnDataKey: PRESENTATION_TURN_DATA_KEY,
1029
+ toolName: PRESENT_TOOL_NAME,
1030
+ parse: asPresentation,
1031
+ card: atlassianCard
1032
+ });
1033
+
1034
+ // src/client/components/presentation-tail.tsx
1035
+ var PresentationTail = createPresentationTail(atlassianPresentation);
1036
+
1037
+ // src/client/host-api.ts
1038
+ var request = createHostRequest("/dsh-atlassian");
1039
+ var hostApi = {
1040
+ /** Read the current sign-in and connection state. */
1041
+ status: async () => {
1042
+ return await request("/status", "GET");
1043
+ },
1044
+ /** Start a sign-in attempt; resolves as soon as the attempt is running. */
1045
+ login: async () => {
1046
+ return await request("/login", "POST");
1047
+ },
1048
+ /** Forget the stored sign-in and withdraw the published tools. */
1049
+ logout: async () => {
1050
+ return await request("/logout", "POST");
1051
+ },
1052
+ /** Reconnect and re-publish the Atlassian tools. */
1053
+ sync: async () => {
1054
+ return await request("/sync", "POST");
1055
+ },
1056
+ /** Everything one panel shows for its target. */
1057
+ getPanel: async (target, signal) => {
1058
+ return target.kind === "issue" ? await request(
1059
+ `/issue?key=${encodeURIComponent(target.key)}`,
1060
+ "GET",
1061
+ void 0,
1062
+ signal
1063
+ ) : await request(
1064
+ `/page?id=${encodeURIComponent(target.id)}`,
1065
+ "GET",
1066
+ void 0,
1067
+ signal
1068
+ );
1069
+ },
1070
+ /**
1071
+ * The signed-in user, as the site names them.
1072
+ * @returns the reader, or null when the site names no account for this token.
1073
+ */
1074
+ me: async () => {
1075
+ const answer = await request("/me", "GET");
1076
+ return answer.person;
1077
+ },
1078
+ /** People the site matches to a search string. */
1079
+ findPeople: async (query, signal) => {
1080
+ const found2 = await request(
1081
+ `/people?q=${encodeURIComponent(query)}`,
1082
+ "GET",
1083
+ void 0,
1084
+ signal
1085
+ );
1086
+ return Array.isArray(found2) ? found2 : [];
1087
+ },
1088
+ /** Move one issue through a workflow transition; answers with the fresh issue. */
1089
+ transitionIssue: async (key, transitionId) => {
1090
+ return await request("/issue/transition", "POST", {
1091
+ key,
1092
+ transitionId
1093
+ });
1094
+ },
1095
+ /** Set or clear one issue's assignee; answers with the fresh issue. */
1096
+ assignIssue: async (key, accountId) => {
1097
+ return await request("/issue/assignee", "POST", { key, accountId });
1098
+ }
1099
+ };
1100
+
1101
+ // src/client/components/settings-section.tsx
1102
+ var AtlassianSection = createSettingsSection({
1103
+ title: "Atlassian",
1104
+ blurb: "Jira and Confluence, through Atlassian\u2019s MCP server.",
1105
+ checking: "Checking the Atlassian sign-in\u2026",
1106
+ unreachable: "The Atlassian host half is not reachable.",
1107
+ credentials: "browser",
1108
+ signInLabel: "Sign in with Atlassian",
1109
+ syncLabel: "Re-check",
1110
+ api: hostApi
1111
+ });
1112
+
1113
+ // src/shared/meta.ts
1114
+ function asAtlassianMeta(value) {
1115
+ if (value === null || typeof value !== "object") return void 0;
1116
+ const candidate = value;
1117
+ if (typeof candidate.kind !== "string" || typeof candidate.tool !== "string")
1118
+ return void 0;
1119
+ const total = typeof candidate.total === "number" && Number.isFinite(candidate.total) ? candidate.total : void 0;
1120
+ return {
1121
+ kind: candidate.kind === "jira-issues" || candidate.kind === "confluence-pages" ? candidate.kind : "text",
1122
+ tool: candidate.tool,
1123
+ ...typeof candidate.query === "string" ? { query: candidate.query } : {},
1124
+ ...total === void 0 ? {} : { total },
1125
+ issues: Array.isArray(candidate.issues) ? candidate.issues : [],
1126
+ pages: Array.isArray(candidate.pages) ? candidate.pages : [],
1127
+ text: typeof candidate.text === "string" ? candidate.text : ""
1128
+ };
1129
+ }
1130
+
1131
+ // src/client/components/tool-row.tsx
1132
+ var TOOL_LABELS = {
1133
+ atlassianUserInfo: "Atlassian account",
1134
+ getJiraCurrentUser: "Atlassian account",
1135
+ getJiraUser: "Jira person",
1136
+ getAccessibleAtlassianResources: "Atlassian sites",
1137
+ discover: "Atlassian tools",
1138
+ getContentFormatGuide: "Content format",
1139
+ executeRead: "Atlassian read",
1140
+ executeWrite: "Atlassian write",
1141
+ executeDestructive: "Atlassian change",
1142
+ searchJiraIssuesUsingJql: "Jira search",
1143
+ getJiraIssue: "Jira issue",
1144
+ createJiraIssue: "New Jira issue",
1145
+ editJiraIssue: "Jira issue edit",
1146
+ transitionJiraIssue: "Jira transition",
1147
+ addCommentToJiraIssue: "Jira comment",
1148
+ addOrEditJiraIssueComment: "Jira comment",
1149
+ lookupJiraAccountId: "Jira people",
1150
+ listJiraIssueAssignableUsers: "Jira people",
1151
+ searchConfluenceUsingCql: "Confluence search",
1152
+ searchConfluence: "Confluence search",
1153
+ getConfluencePage: "Confluence page",
1154
+ getConfluenceContent: "Confluence content",
1155
+ createConfluencePage: "New Confluence page",
1156
+ updateConfluencePage: "Confluence page edit",
1157
+ createConfluenceComment: "Confluence comment",
1158
+ listConfluenceComments: "Confluence comments",
1159
+ search: "Atlassian search",
1160
+ fetch: "Atlassian resource"
1161
+ };
1162
+ var asWords = (name) => {
1163
+ const words = name.replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_-]+/gu, " ").trim();
1164
+ if (words === "") return "Atlassian";
1165
+ return `${words.slice(0, 1).toUpperCase()}${words.slice(1)}`;
1166
+ };
1167
+ var toolLabel2 = (toolName) => {
1168
+ const name = (toolName ?? "").replace(/^mcp__atlassian__/u, "");
1169
+ return TOOL_LABELS[name] ?? asWords(name);
1170
+ };
1171
+ var found = (count, noun, total) => {
1172
+ const plural = count === 1 ? "" : "s";
1173
+ return total === void 0 || total <= count ? `found ${count} ${noun}${plural}` : `found ${count} of ${total} ${noun}${plural}`;
1174
+ };
1175
+ var summarize = (block) => {
1176
+ const meta = asAtlassianMeta(block?.meta);
1177
+ if (meta === void 0) return "done";
1178
+ const parts = [];
1179
+ const total = meta.total;
1180
+ if (meta.issues.length > 0)
1181
+ parts.push(found(meta.issues.length, "issue", total));
1182
+ else if (meta.pages.length > 0)
1183
+ parts.push(found(meta.pages.length, "page", total));
1184
+ if (meta.query !== void 0) parts.push(meta.query);
1185
+ if (parts.length === 0) parts.push("done");
1186
+ return parts.join(" \xB7 ");
1187
+ };
1188
+ var AtlassianToolRow = createToolRow({
1189
+ displayName: toolLabel2,
1190
+ summarize
1191
+ });
1192
+
1193
+ // src/client/plugin-id.ts
1194
+ var PLUGIN_ID = "dsh-atlassian";
1195
+
1196
+ // src/client/sidebar/panel.tsx
1197
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
1198
+ var import_react4 = require("react");
1199
+
1200
+ // src/shared/panel.ts
1201
+ function isRecord2(value) {
1202
+ return value !== null && typeof value === "object" && !Array.isArray(value);
1203
+ }
1204
+ function asString(value) {
1205
+ return typeof value === "string" && value !== "" ? value : void 0;
1206
+ }
1207
+ function asComments(value) {
1208
+ if (!Array.isArray(value)) return [];
1209
+ const comments2 = [];
1210
+ for (const candidate of value) {
1211
+ if (!isRecord2(candidate)) continue;
1212
+ const body = asString(candidate.body);
1213
+ if (body === void 0) continue;
1214
+ comments2.push({
1215
+ body,
1216
+ ...asString(candidate.author) === void 0 ? {} : { author: asString(candidate.author) },
1217
+ ...asString(candidate.created) === void 0 ? {} : { created: asString(candidate.created) }
1218
+ });
1219
+ }
1220
+ return comments2;
1221
+ }
1222
+ function asTransitions(value) {
1223
+ if (!Array.isArray(value)) return [];
1224
+ const transitions = [];
1225
+ for (const candidate of value) {
1226
+ if (!isRecord2(candidate)) continue;
1227
+ const id = asString(candidate.id);
1228
+ const name = asString(candidate.name);
1229
+ if (id === void 0 || name === void 0) continue;
1230
+ transitions.push({
1231
+ id,
1232
+ name,
1233
+ ...asString(candidate.to) === void 0 ? {} : { to: asString(candidate.to) },
1234
+ available: candidate.available !== false,
1235
+ needsFields: candidate.needsFields === true
1236
+ });
1237
+ }
1238
+ return transitions;
1239
+ }
1240
+ function asPerson(value) {
1241
+ if (!isRecord2(value)) return void 0;
1242
+ const name = asString(value.name);
1243
+ const accountId = asString(value.accountId);
1244
+ if (name === void 0 || accountId === void 0) return void 0;
1245
+ return { name, accountId };
1246
+ }
1247
+ function asPanelTarget(value) {
1248
+ if (!isRecord2(value)) return void 0;
1249
+ if (value.kind === "issue") {
1250
+ const key = asString(value.key);
1251
+ return key === void 0 ? void 0 : { kind: "issue", key };
1252
+ }
1253
+ if (value.kind === "page") {
1254
+ const id = asString(value.id);
1255
+ if (id === void 0) return void 0;
1256
+ return {
1257
+ kind: "page",
1258
+ id,
1259
+ ...asString(value.title) === void 0 ? {} : { title: asString(value.title) }
1260
+ };
1261
+ }
1262
+ return void 0;
1263
+ }
1264
+ function asPanelData(value) {
1265
+ if (!isRecord2(value)) return void 0;
1266
+ if (value.kind === "issue") {
1267
+ const key = asString(value.key);
1268
+ if (key === void 0) return void 0;
1269
+ const assignee = asPerson(value.assignee);
1270
+ return {
1271
+ kind: "issue",
1272
+ key,
1273
+ ...asString(value.summary) === void 0 ? {} : { summary: asString(value.summary) },
1274
+ ...asString(value.type) === void 0 ? {} : { type: asString(value.type) },
1275
+ ...asString(value.status) === void 0 ? {} : { status: asString(value.status) },
1276
+ ...asString(value.priority) === void 0 ? {} : { priority: asString(value.priority) },
1277
+ ...assignee === void 0 ? {} : { assignee },
1278
+ ...asString(value.reporter) === void 0 ? {} : { reporter: asString(value.reporter) },
1279
+ ...asString(value.estimate) === void 0 ? {} : { estimate: asString(value.estimate) },
1280
+ ...asString(value.due) === void 0 ? {} : { due: asString(value.due) },
1281
+ labels: Array.isArray(value.labels) ? value.labels.filter(
1282
+ (item2) => typeof item2 === "string"
1283
+ ) : [],
1284
+ ...asString(value.created) === void 0 ? {} : { created: asString(value.created) },
1285
+ ...asString(value.updated) === void 0 ? {} : { updated: asString(value.updated) },
1286
+ ...asString(value.description) === void 0 ? {} : { description: asString(value.description) },
1287
+ ...asString(value.url) === void 0 ? {} : { url: asString(value.url) },
1288
+ comments: asComments(value.comments),
1289
+ transitions: asTransitions(value.transitions)
1290
+ };
1291
+ }
1292
+ if (value.kind === "page") {
1293
+ const id = asString(value.id);
1294
+ const title2 = asString(value.title);
1295
+ if (id === void 0 || title2 === void 0) return void 0;
1296
+ return {
1297
+ kind: "page",
1298
+ id,
1299
+ title: title2,
1300
+ ...asString(value.space) === void 0 ? {} : { space: asString(value.space) },
1301
+ ...asString(value.url) === void 0 ? {} : { url: asString(value.url) },
1302
+ ...asString(value.body) === void 0 ? {} : { body: asString(value.body) },
1303
+ comments: asComments(value.comments)
1304
+ };
1305
+ }
1306
+ return void 0;
1307
+ }
1308
+
1309
+ // src/client/sidebar/panel.tsx
1310
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1311
+ var MARKDOWN_LABELS = {
1312
+ code: { copyLabel: "Copy", copiedLabel: "Copied" },
1313
+ footnotes: "Footnotes"
1314
+ };
1315
+ function whenText(value) {
1316
+ const time = Date.parse(value);
1317
+ return Number.isNaN(time) ? value : new Date(time).toLocaleString(void 0, {
1318
+ dateStyle: "medium",
1319
+ timeStyle: "short"
1320
+ });
1321
+ }
1322
+ var Section = ({
1323
+ title: title2,
1324
+ children
1325
+ }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("section", { className: panelSection, children: [
1326
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: panelSectionTitle, children: title2 }),
1327
+ children
1328
+ ] });
1329
+ var Prose = ({ text }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: panelBody, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives5.MarkdownText, { text, labels: MARKDOWN_LABELS, variant: "compact" }) });
1330
+ var Comments = ({ comments: comments2 }) => {
1331
+ if (comments2.length === 0)
1332
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "No comments." });
1333
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: comments, children: comments2.map((comment2, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
1334
+ "li",
1335
+ {
1336
+ className: comment,
1337
+ children: [
1338
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: commentHead, children: [
1339
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: commentAuthor, children: comment2.author ?? "Someone" }),
1340
+ comment2.created === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: whenText(comment2.created) })
1341
+ ] }),
1342
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Prose, { text: comment2.body })
1343
+ ]
1344
+ },
1345
+ `${comment2.author ?? "comment"}-${comment2.created ?? index}`
1346
+ )) });
1347
+ };
1348
+ var runIssue = (actions3, write) => {
1349
+ actions3.run(async (target) => {
1350
+ if (target.kind !== "issue")
1351
+ throw new Error("this panel is not showing an issue");
1352
+ return await write(target.key);
1353
+ });
1354
+ };
1355
+ var Transitions = ({
1356
+ issue,
1357
+ actions: actions3
1358
+ }) => {
1359
+ if (issue.transitions.length === 0) return null;
1360
+ const blocked = issue.transitions.some(
1361
+ (transition) => transition.needsFields
1362
+ );
1363
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Section, { title: "Move to", children: [
1364
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: actions2, children: issue.transitions.map((transition) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1365
+ import_dsh_client_ui_primitives5.Button,
1366
+ {
1367
+ size: "sm",
1368
+ variant: "outline",
1369
+ disabled: actions3.busy || !transition.available || transition.needsFields,
1370
+ title: transition.needsFields ? `${transition.name} opens a screen with required fields` : transition.to === void 0 ? transition.name : `${transition.name} \u2192 ${transition.to}`,
1371
+ onClick: () => {
1372
+ runIssue(
1373
+ actions3,
1374
+ (key) => hostApi.transitionIssue(key, transition.id)
1375
+ );
1376
+ },
1377
+ children: transition.name
1378
+ },
1379
+ transition.id
1380
+ )) }),
1381
+ blocked ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "A transition that needs a form is left to the Atlassian site." }) : null
1382
+ ] });
1383
+ };
1384
+ var remembered = [];
1385
+ var REMEMBERED_LIMIT = 4;
1386
+ function remember(person2) {
1387
+ if (remembered.some((known) => known.accountId === person2.accountId)) return;
1388
+ remembered.unshift(person2);
1389
+ remembered.length = Math.min(remembered.length, REMEMBERED_LIMIT);
1390
+ }
1391
+ var Assignee = ({
1392
+ issue,
1393
+ actions: actions3
1394
+ }) => {
1395
+ const [open, setOpen] = (0, import_react4.useState)(false);
1396
+ const [searchOpen, setSearchOpen] = (0, import_react4.useState)(false);
1397
+ const [fetching, setFetching] = (0, import_react4.useState)(false);
1398
+ const [query, setQuery] = (0, import_react4.useState)("");
1399
+ const [people2, setPeople] = (0, import_react4.useState)([]);
1400
+ const [me, setMe] = (0, import_react4.useState)(null);
1401
+ const [known, setKnown] = (0, import_react4.useState)(remembered);
1402
+ (0, import_react4.useEffect)(() => {
1403
+ let live = true;
1404
+ hostApi.me().then((person2) => {
1405
+ if (live) setMe(person2);
1406
+ }).catch(() => void 0);
1407
+ return () => {
1408
+ live = false;
1409
+ };
1410
+ }, []);
1411
+ (0, import_react4.useEffect)(() => {
1412
+ const trimmed = query.trim();
1413
+ if (trimmed.length < 2) {
1414
+ setPeople([]);
1415
+ return;
1416
+ }
1417
+ const controller = new AbortController();
1418
+ const timer = setTimeout(() => {
1419
+ setFetching(true);
1420
+ hostApi.findPeople(trimmed, controller.signal).then((found2) => {
1421
+ if (!controller.signal.aborted) setPeople(found2);
1422
+ }).catch(() => void 0).finally(() => {
1423
+ if (!controller.signal.aborted) setFetching(false);
1424
+ });
1425
+ }, 300);
1426
+ return () => {
1427
+ clearTimeout(timer);
1428
+ controller.abort();
1429
+ };
1430
+ }, [query]);
1431
+ const assign = (person2) => {
1432
+ if (person2 !== null) {
1433
+ remember(person2);
1434
+ setKnown([...remembered]);
1435
+ }
1436
+ setQuery("");
1437
+ setSearchOpen(false);
1438
+ runIssue(
1439
+ actions3,
1440
+ (key) => hostApi.assignIssue(key, person2?.accountId ?? null)
1441
+ );
1442
+ };
1443
+ const entries = [
1444
+ ...me === null || me.accountId === issue.assignee?.accountId ? [] : [{ id: `person:${me.accountId}`, label: `Assign to me (${me.name})` }],
1445
+ ...known.filter((person2) => person2.accountId !== me?.accountId).map((person2) => ({
1446
+ id: `person:${person2.accountId}`,
1447
+ label: person2.name
1448
+ })),
1449
+ { id: "search", label: "Search people\u2026" }
1450
+ ];
1451
+ const personFor = (id) => {
1452
+ if (me !== null && id === `person:${me.accountId}`) return me;
1453
+ return known.find((person2) => id === `person:${person2.accountId}`) ?? null;
1454
+ };
1455
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Section, { title: "Assignee", children: [
1456
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: row2, children: [
1457
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: issue.assignee?.name ?? "Nobody is assigned." }),
1458
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1459
+ import_dsh_client_ui_primitives5.Menu,
1460
+ {
1461
+ open,
1462
+ onClose: () => {
1463
+ setOpen(false);
1464
+ },
1465
+ autoFocus: true,
1466
+ dense: true,
1467
+ items: entries,
1468
+ onSelect: (id) => {
1469
+ setOpen(false);
1470
+ if (id === "search") {
1471
+ setSearchOpen(true);
1472
+ return;
1473
+ }
1474
+ assign(personFor(id));
1475
+ },
1476
+ footer: issue.assignee === void 0 ? [] : [{ id: "unassign", label: "Unassign", danger: true }],
1477
+ anchor: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1478
+ import_dsh_client_ui_primitives5.Button,
1479
+ {
1480
+ size: "sm",
1481
+ variant: "ghost",
1482
+ disabled: actions3.busy,
1483
+ onClick: () => {
1484
+ if (open) {
1485
+ setOpen(false);
1486
+ return;
1487
+ }
1488
+ setSearchOpen(false);
1489
+ setOpen(true);
1490
+ },
1491
+ children: "Change"
1492
+ }
1493
+ )
1494
+ }
1495
+ )
1496
+ ] }),
1497
+ searchOpen ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1498
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: actions2, children: [
1499
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1500
+ import_dsh_client_ui_primitives5.Input,
1501
+ {
1502
+ className: personSearch,
1503
+ value: query,
1504
+ placeholder: "Search people\u2026",
1505
+ disabled: actions3.busy,
1506
+ onChange: (event) => {
1507
+ setQuery(event.target.value);
1508
+ }
1509
+ }
1510
+ ),
1511
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1512
+ import_dsh_client_ui_primitives5.Button,
1513
+ {
1514
+ size: "sm",
1515
+ variant: "ghost",
1516
+ disabled: actions3.busy,
1517
+ onClick: () => {
1518
+ setQuery("");
1519
+ setSearchOpen(false);
1520
+ },
1521
+ children: "Cancel"
1522
+ }
1523
+ )
1524
+ ] }),
1525
+ query.trim().length < 2 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "Two letters are enough to search the site." }) : null,
1526
+ fetching ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "Searching\u2026" }) : null,
1527
+ people2.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", { className: people, children: people2.map((person2) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1528
+ "button",
1529
+ {
1530
+ type: "button",
1531
+ className: person,
1532
+ disabled: actions3.busy,
1533
+ onClick: () => {
1534
+ assign(person2);
1535
+ },
1536
+ children: person2.name
1537
+ }
1538
+ ) }, person2.accountId)) })
1539
+ ] }) : null
1540
+ ] });
1541
+ };
1542
+ var IssueView = ({
1543
+ issue,
1544
+ actions: actions3
1545
+ }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1546
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: panelHead, children: [
1547
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: panelTitleRow, children: [
1548
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Chip, { value: issue.type, tone: issueTypeTone(issue.type) }),
1549
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1550
+ "a",
1551
+ {
1552
+ className: `${link2} ${panelKey}`,
1553
+ href: issue.url,
1554
+ target: "_blank",
1555
+ rel: "noreferrer",
1556
+ children: issue.key
1557
+ }
1558
+ )
1559
+ ] }),
1560
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: panelSummary, children: issue.summary ?? issue.key }),
1561
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1562
+ Facts,
1563
+ {
1564
+ items: [
1565
+ { label: "Status", value: issue.status },
1566
+ {
1567
+ label: "Priority",
1568
+ value: issue.priority === void 0 ? void 0 : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1569
+ Chip,
1570
+ {
1571
+ value: issue.priority,
1572
+ tone: priorityTone(issue.priority)
1573
+ }
1574
+ )
1575
+ },
1576
+ { label: "Reporter", value: issue.reporter },
1577
+ { label: "Estimate", value: issue.estimate },
1578
+ { label: "Due", value: issue.due }
1579
+ ]
1580
+ }
1581
+ ),
1582
+ issue.labels.length === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: badges, children: issue.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Chip, { value: label, tone: "neutral" }, label)) })
1583
+ ] }),
1584
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Transitions, { issue, actions: actions3 }),
1585
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Assignee, { issue, actions: actions3 }),
1586
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Section, { title: "Description", children: issue.description === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "No description." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Prose, { text: issue.description }) }),
1587
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Section, { title: `Comments (${issue.comments.length})`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Comments, { comments: issue.comments }) }),
1588
+ issue.updated === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("span", { className: caption2, children: [
1589
+ "Updated ",
1590
+ whenText(issue.updated)
1591
+ ] })
1592
+ ] });
1593
+ var PageView = ({ page }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
1594
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("header", { className: panelHead, children: [
1595
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: panelTitleRow, children: [
1596
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Chip, { value: "Page", tone: "neutral" }),
1597
+ page.space === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: panelKey, children: page.space })
1598
+ ] }),
1599
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", { className: panelSummary, children: page.title }),
1600
+ page.url === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1601
+ "a",
1602
+ {
1603
+ className: link2,
1604
+ href: page.url,
1605
+ target: "_blank",
1606
+ rel: "noreferrer",
1607
+ children: "Open in Confluence"
1608
+ }
1609
+ )
1610
+ ] }),
1611
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Section, { title: "Content", children: page.body === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: caption2, children: "No content." }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Prose, { text: page.body }) }),
1612
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Section, { title: `Comments (${page.comments.length})`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Comments, { comments: page.comments }) })
1613
+ ] });
1614
+ var provider = {
1615
+ emptyMessage: "This panel was opened without an issue or a page.",
1616
+ parseParams: (value) => asPanelTarget(value),
1617
+ identity: (target) => target.kind === "issue" ? `issue:${target.key}` : `page:${target.id}`,
1618
+ title: (target) => target.kind === "issue" ? target.key : target.title ?? "Page",
1619
+ fetch: async (target, signal) => await hostApi.getPanel(target, signal),
1620
+ parse: (value) => asPanelData(value),
1621
+ view: ({ data, actions: actions3 }) => data.kind === "issue" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(IssueView, { issue: data, actions: actions3 }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PageView, { page: data })
1622
+ };
1623
+ var AtlassianPanel = createPanelBody(provider);
1624
+ var AtlassianPanelTitle = createPanelTitle(provider);
1625
+
1626
+ // src/client/styles/styles-runtime.ts
1627
+ var installAtlassianStyles = () => installStyles(PLUGIN_ID, '/* vanilla-extract-css-ns:../integration-ui/src/styles/styles.css.ts.vanilla.css?source=#H4sIAAAAAAAAE81Z227jNhB9z1cQAQpsHhhIjuN1GOyXFEVBiSOZMUWqJBXbKfrvBan7xYqsTRd9CkyRM8O5nDmcPP75wsLDTgbo7zuEGDe5oBeCEgHn1zvk_2LGNcSWK0lQrESRSfclpTlB4S7323LKGJcpQfv8jAJ_UEmLDf8AgsKncpPgEvABeHqwBG025WKshNIEvVP9DWNmTpgKTg0WNAKBc80zqi8Pr3f_3D1Whobe0EZhuMnPjRmR0gw0QcHjc35GRgnORpINWMtlanBMNcPGanWEh_Yw1pTxwnQtKlfwWZTbaHxMtSokG1vdl51wIXqmb6Z9TAVPJeYWMkNQDNKCdstvhbE8ueBYSQvSEmRyGgOOwJ4AOiHY9EKAI2Wtyur1VvmTV94Ny7Y86JdOVVieg6B7aHuTxd6eXUdqpWgzEf9wvyD-FrTlZQIgdDpwC9g7gSCpTprmXVOfvamz4gzESrJhQu3W39EVh7ODoKE130fe_gontPL3txu9v2I0QhnVKZfYqnycNi__Sc5WDsy4bHyxDQZQsquhJFJn50S_WBVppHpGUm_k3DWi_jVSzZm3RnOGLWS5oBZwCW6GeLuqK6Aw0VWIikziXslpdSoXqt-lARUIol4hxR0LyRghf0mFsLEN7qInzuzhRpvUO-hEqFOVSFReTgfQsArQYabz9PO0l3QRNeBsa5LKN4JBJIJeRgXlfYzFxl6E95E735qSLEj2kd5tm8utK1uZ6QgJwinH7tYiwcHLH99q1gnjQmgQoiP5d0YtxYJeVGF_3DsV9394bS0IjnabWCshaCTgx73VBVQnMnpu7vq0CwZZdCGIFlbVa6UMHMGBvnPnDleLlHv8KL9FVOO0sNY1e2Odtm4L1BXF6BvIS-KgDC-pjAZBLX-H1xW8Z4r21Lm3hIRUMCY2i5hHxh5m4mK4TIXz8-CiDUPajhjSdVUinVNVpcAVRQ6ww2CZHpP19HByoOYbfSAHF38vdo5ncddvaOyih6MU-0MT8qLCWiW_TOjbGnS41nWXh_NtBCDPnxO3-cCNRT71a-VYbhBwJihEYVOd10BuXl0pra52gg6csZINWDhb3H4AIXhuuFnQzAQhNLFVWBu6cX__2qtxGhklCuvDwaUBS2pK0UtPLg-gue3Kz7xgmudANZVxB1br-m5-d3LKaipNTjVIW0eoI32IwnGhjYO3XPGSQLXq5Syb5fL4MJ0BlUsZxErT0gfDJic79TDaXEgGuk7gwde6vzBlLbBmQ3MEqyTxLh4kkySJiguD37nhkYBfp1j1CE_DyrrYGNR8oW1Pm2F7aptTLydzDbhmJielGY400CNB_g92K02IEppxcWkDiTurOFYM2mjOka_H58UQPg91GdVHpk7S68aRUPGxh3T5XPYZ67gyaK30JJ_7a90kocfcpkm8XiV5P-jVzcSgeQH_z8cGZvVbr_u-2mz7zrTTPWAAKrsSVG4m9UX3RSYgsW0R_fJ3z_vXvZVboac-93E5tZBieeqzpj5_FkxWzEbOXzpmmMnGy7Vs7A8Ng5VDw4_ryNEnONexpEnPIPhteJtbamQ-8lGKHYXsTzxnZrNLrb86dhn0wwYbN9v5N5pfO3e53LLgda4VLr3W0mHTIBOb5t65blin0IS1t7-9wysT3SUdqSPlafAyNZbHx4vnOa4N-hB9YC6Zd8zrxLC3bmS3ZtaK-e7n0Bg-t8W8Eqw6wnbzk7Opt1DVtCb-39CR-_1LQre_Nt2ZNAjcxMI3qvIR8BjsIGv4rH88JEpnBBV5Djqm5vOJ2nRevvx0BJaD7L-TgtXfQhoAAA */\n._9d1h6n0 {\n display: flex;\n flex-direction: column;\n gap: 16px;\n padding: 8px 0;\n font-size: 13px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n._9d1h6n1 {\n padding: 12px 16px;\n border: 0.5px solid var(--dsw-alias-settings-card-stroke);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-settings-card-fill);\n}\n._9d1h6n2 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding-bottom: 12px;\n}\n._9d1h6n3 {\n font-size: 14px;\n font-weight: 500;\n}\n._9d1h6n4 {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n}\n._9d1h6n5 {\n color: var(--dsw-alias-label-secondary);\n}\n._9d1h6n6 {\n display: flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n}\n._9d1h6n7 {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n._9d1h6n8 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n margin-top: 12px;\n}\n._9d1h6n9 {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n min-height: 40px;\n padding: 6px 0;\n box-sizing: border-box;\n}\n._9d1h6na {\n margin-top: 12px;\n}\n._9d1h6nb {\n display: grid;\n grid-template-columns: min-content 1fr;\n column-gap: 12px;\n row-gap: 2px;\n margin: 8px 0 0;\n}\n._9d1h6nc {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n}\n._9d1h6nd {\n margin: 0;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n overflow-wrap: anywhere;\n color: var(--dsw-alias-label-primary);\n}\n._9d1h6ne {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 2px 12px;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n._9d1h6nf {\n display: flex;\n align-items: baseline;\n gap: 4px;\n min-width: 0;\n}\n._9d1h6ng {\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-tertiary);\n}\n._9d1h6nh {\n list-style: none;\n margin: 0;\n padding: 0;\n display: grid;\n gap: 8px;\n}\n._9d1h6nh[data-layout=list] {\n gap: 6px;\n}\n._9d1h6nh[data-scrollable=true] {\n max-height: 360px;\n overflow-y: auto;\n overscroll-behavior: contain;\n scrollbar-gutter: stable;\n padding-right: 2px;\n}\n._9d1h6ni {\n position: relative;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 12px;\n border: 0.5px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n}\n._9d1h6nh[data-layout=single] ._9d1h6ni {\n padding: 14px 16px;\n border-radius: var(--dsw-radius-lg);\n}\n._9d1h6nh[data-layout=list] ._9d1h6ni {\n padding: 6px 10px;\n border-radius: var(--dsw-radius-sm);\n}\n._9d1h6ni:has(a):hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n._9d1h6ni:has(button):hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n._9d1h6nj {\n display: flex;\n align-items: baseline;\n gap: 8px;\n flex-wrap: wrap;\n}\n._9d1h6nh[data-layout=single] ._9d1h6nj {\n font-size: 15px;\n font-weight: 500;\n}\n._9d1h6nh[data-layout=list] ._9d1h6nj {\n font-size: 13px;\n}\n._9d1h6nk {\n flex: 1 1 auto;\n min-width: 0;\n}\n._9d1h6nh[data-layout=list] ._9d1h6nk {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n._9d1h6nl::after {\n content: "";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n}\n._9d1h6nm {\n appearance: none;\n border: none;\n background: transparent;\n font: inherit;\n padding: 0;\n cursor: pointer;\n}\n._9d1h6nn {\n color: var(--dsw-alias-link);\n font-weight: 500;\n text-decoration: none;\n}\n._9d1h6nn:hover {\n text-decoration: underline;\n text-decoration-style: dotted;\n text-underline-offset: 3px;\n}\n._9d1h6nn:focus-visible {\n text-decoration: underline;\n text-decoration-style: dotted;\n text-underline-offset: 3px;\n}\n._9d1h6no {\n margin: 8px 0 0;\n padding: 10px;\n max-height: 260px;\n overflow: auto;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n line-height: 1.5;\n border-radius: var(--dsw-radius-lg);\n background: var(--dsw-alias-markdown-code-block);\n}\n._9d1h6np {\n color: var(--dsw-alias-state-error-primary);\n}\n._9d1h6nq {\n display: flex;\n flex-direction: column;\n gap: 12px;\n margin-top: 12px;\n}\n._9d1h6nr {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 12px 16px 14px;\n border: 0.5px solid var(--dsw-alias-settings-card-stroke);\n border-radius: var(--dsw-radius-xl);\n background: var(--dsw-alias-settings-card-fill);\n}\n._9d1h6ns {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n}\n._9d1h6nt {\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n._9d1h6nu {\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n white-space: nowrap;\n}\n._9d1h6nv {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n._9d1h6nw {\n padding: 2px 6px;\n border-radius: var(--dsw-radius-sm);\n background: var(--dsw-alias-markdown-code-block);\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n._9d1h6nx {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n min-height: 24px;\n}\n._9d1h6ny {\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-primary);\n}\n._9d1h6nz {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-base);\n}\n._9d1h6n10 {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 16px;\n min-height: 0;\n padding: 12px 16px 24px;\n overflow-y: auto;\n overflow-x: hidden;\n font-size: 13px;\n line-height: 20px;\n}\n._9d1h6n11 {\n display: flex;\n flex: 1 1 auto;\n align-items: center;\n justify-content: center;\n gap: 10px;\n min-height: 120px;\n font-size: 13px;\n color: var(--dsw-alias-label-tertiary);\n}\n._9d1h6n12 {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n._9d1h6n13 {\n position: sticky;\n top: 0;\n z-index: 1;\n padding-bottom: 4px;\n background: var(--dsw-alias-bg-base);\n}\n._9d1h6n14 {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: wrap;\n}\n._9d1h6n15 {\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n}\n._9d1h6n16 {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n line-height: 22px;\n}\n._9d1h6n17 {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n._9d1h6n18 {\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.06em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-tertiary);\n}\n._9d1h6n19 {\n font-family: var(--ds-font-family-code);\n font-size: 12px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* vanilla-extract-css-ns:src/client/styles/styles.css.ts.vanilla.css?source=#H4sIAAAAAAAAE71Uy47bMAy85yuIPXUPCuI0TbMK2h8pioK2aJuNLBkSnUeL_nshOQns3aBoLz0ZoobDITny0rx8D65Ywc8FQIehYadhtV8A1N6JivyDNBTr_pxClh2plrhpRUOxG4OVtz5oOGJ4p5SJJ4WWMSqLJVklFIQxXJ4T0nDsLV40qBOVBxZV-swwOSofmJxoOKbECu30PpevLHa9hnW68EcKtfUnDS0bQ26_-LVYfnsxRbt17ReDgsrixQ_y6clylKevsJy2-4i3yBwjqoDPoGsOUVTVsjWTGSnxfZ7THGzxEbb0Ir6bw9cZkFSpKBdLGpx3tH-9hB6NYddcT_cB1pby5NJXGQ5UCXun0y6GzqWbBtOQ0obuJd_nkilFQwEF4CA-F2SnTmyknSvcZDj2PWFAV00Ulj4YCpMzVocm-MEZDRLQxR4DObmZSAO7lgLLn9zC7pA9InSWFGucBku1zIaw6c-wHV03alABDQ9xyjdGVOwyXTWEmOr1np1QmLan22Sf3OS0gdfKch5WwkdSZaNy0vOMx3DE0tK48r9_DTdphmocrEwoP_wPbxRzc2xzzX8l2YzLuCpRaWEaitVsRWNw3Z8hesvmzWhusPV0qh8fy8nGUCzURQ0lRkpP965mN-toN9r97V8sh07Xv9h2lTz_G50K8QwGBQAA */\n.d9jrn10 {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n overflow: hidden;\n}\n._9d1h6nh[data-layout=list] .d9jrn10 {\n -webkit-line-clamp: 1;\n}\n.d9jrn11 > :first-child {\n margin-top: 0;\n}\n.d9jrn11 > :last-child {\n margin-bottom: 0;\n}\n.d9jrn12 {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n.d9jrn13 {\n flex: 1 1 auto;\n min-width: 0;\n}\n.d9jrn14 {\n appearance: none;\n border: none;\n background: transparent;\n font: inherit;\n color: var(--dsw-alias-link);\n text-align: left;\n padding: 4px 6px;\n border-radius: var(--dsw-radius-sm);\n cursor: pointer;\n}\n.d9jrn14:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.d9jrn14:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.d9jrn15 {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.d9jrn16 {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-left: 10px;\n border-left: 2px solid var(--dsw-alias-border-l2);\n}\n.d9jrn17 {\n display: flex;\n align-items: baseline;\n gap: 8px;\n}\n.d9jrn18 {\n font-size: 12px;\n font-weight: 600;\n}\n');
1628
+
1629
+ // src/client/index.ts
1630
+ var inject = ["slots", "uiConversation"];
1631
+ var apply = (ctx) => {
1632
+ ctx.effect(() => installAtlassianStyles(), "atlassian: stylesheet");
1633
+ ctx.uiConversation.events.register(atlassianPresentation.definition);
1634
+ installPanelOpener(ctx);
1635
+ ctx.inject(["sidebarRightTabs"], (scoped) => {
1636
+ scoped.effect(
1637
+ () => scoped.sidebarRightTabs.register(panelDefinition()),
1638
+ "atlassian: panel type"
1639
+ );
1640
+ scoped.slots.inject(
1641
+ "sidebar.right.pane.tab",
1642
+ () => scoped.slots.register(
1643
+ { name: "sidebar.right.pane.tab", key: PANEL_ID },
1644
+ AtlassianPanel
1645
+ )
1646
+ );
1647
+ scoped.slots.inject(
1648
+ "sidebar.right.pane.tab.title",
1649
+ () => scoped.slots.register(
1650
+ { name: "sidebar.right.pane.tab.title", key: PANEL_ID },
1651
+ AtlassianPanelTitle
1652
+ )
1653
+ );
1654
+ });
1655
+ registerIntegrationsTab(
1656
+ ctx,
1657
+ { id: "atlassian", order: 10, label: "Atlassian" },
1658
+ AtlassianSection
1659
+ );
1660
+ ctx.slots.inject("tool.call.toolview", () => {
1661
+ const disposers = PUBLIC_TOOL_NAMES.map(
1662
+ (name) => ctx.slots.register(
1663
+ { name: "tool.call.toolview", key: name },
1664
+ AtlassianToolRow
1665
+ )
1666
+ );
1667
+ return () => {
1668
+ for (const dispose of disposers) dispose();
1669
+ };
1670
+ });
1671
+ ctx.slots.inject(
1672
+ "conversation.chat.turnTail",
1673
+ () => ctx.slots.register(
1674
+ {
1675
+ name: "conversation.chat.turnTail",
1676
+ id: PLUGIN_ID,
1677
+ order: 20
1678
+ },
1679
+ PresentationTail
1680
+ )
1681
+ );
1682
+ };
1683
+ return module.exports; } });
1684
+ //# sourceMappingURL=client.js.map