@kodaris/krubble-app-components 1.0.77 → 1.0.79
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/dist/chatbot.d.ts +73 -9
- package/dist/chatbot.d.ts.map +1 -1
- package/dist/chatbot.js +323 -36
- package/dist/chatbot.js.map +1 -1
- package/dist/krubble-app.bundled.js +323 -36
- package/dist/krubble-app.bundled.js.map +1 -1
- package/dist/krubble-app.bundled.min.js +122 -37
- package/dist/krubble-app.bundled.min.js.map +1 -1
- package/dist/krubble-app.umd.js +323 -36
- package/dist/krubble-app.umd.js.map +1 -1
- package/dist/krubble-app.umd.min.js +107 -22
- package/dist/krubble-app.umd.min.js.map +1 -1
- package/package.json +1 -1
|
@@ -5617,10 +5617,18 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5617
5617
|
/** Monotonic id source for pending attachments. */
|
|
5618
5618
|
this._pendingSeq = 0;
|
|
5619
5619
|
/**
|
|
5620
|
-
* Request-id
|
|
5621
|
-
* responses are dropped (mirrors the kr-combo-box `_requestId` pattern).
|
|
5620
|
+
* Request-id guards for skill searches — bumped on each search so out-of-order
|
|
5621
|
+
* responses are dropped (mirrors the kr-combo-box `_requestId` pattern). Org and
|
|
5622
|
+
* global searches run concurrently into separate buffers, so each has its own.
|
|
5622
5623
|
*/
|
|
5623
5624
|
this._skillRequestId = 0;
|
|
5625
|
+
this._globalSkillRequestId = 0;
|
|
5626
|
+
/**
|
|
5627
|
+
* Codes of global skills with an in-flight enable/disable request. The `+`
|
|
5628
|
+
* button reads this to show a pending state and ignore repeat clicks. Mutated
|
|
5629
|
+
* in place; call requestUpdate() after changing it to re-render.
|
|
5630
|
+
*/
|
|
5631
|
+
this._globalSkillPending = new Set();
|
|
5624
5632
|
// --- @property (public API) ---
|
|
5625
5633
|
/**
|
|
5626
5634
|
* Callback function for sending messages. Receives the user's message and
|
|
@@ -5726,10 +5734,24 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5726
5734
|
/** Current `/` query (text after the slash), sent to `_searchSkills`. */
|
|
5727
5735
|
this._skillQuery = '';
|
|
5728
5736
|
/**
|
|
5729
|
-
* Latest skill search results
|
|
5730
|
-
*
|
|
5737
|
+
* Latest org skill search results (this instance's own skills). Backs the `/`
|
|
5738
|
+
* menu and the browse dialog's "Your Org" tab.
|
|
5731
5739
|
*/
|
|
5732
5740
|
this._skillResults = [];
|
|
5741
|
+
/**
|
|
5742
|
+
* Latest shared-Kodaris (global) skill results, for the browse dialog's
|
|
5743
|
+
* "Kodaris" tab. Kept separate from `_skillResults` so switching tabs shows
|
|
5744
|
+
* fresh results immediately instead of the other tab's stale list — the browse
|
|
5745
|
+
* search fills both buffers at once.
|
|
5746
|
+
*/
|
|
5747
|
+
this._globalSkillResults = [];
|
|
5748
|
+
/**
|
|
5749
|
+
* AI framework UI config flags fetched from `aiFrameworkConfig` on connect.
|
|
5750
|
+
* `debugTelemetryEnabled` (same server-side gate as TOKEN_USAGE emission) turns
|
|
5751
|
+
* on the debug drawer toggle and the `/test-warning` / `/test-limit` composer
|
|
5752
|
+
* options — known up front, before any message.
|
|
5753
|
+
*/
|
|
5754
|
+
this._aiFrameworkConfig = {};
|
|
5733
5755
|
/** Highlighted item in the skill menu for keyboard navigation (-1 = none). */
|
|
5734
5756
|
this._skillHighlighted = 0;
|
|
5735
5757
|
/** Index of the message whose copy button just flashed "Copied" (-1 = none). */
|
|
@@ -5737,11 +5759,11 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5737
5759
|
/** Whether the "Browse all skills" dialog is open. */
|
|
5738
5760
|
this._skillBrowseOpened = false;
|
|
5739
5761
|
/**
|
|
5740
|
-
* Active tab in the browse dialog. `org`
|
|
5741
|
-
*
|
|
5762
|
+
* Active tab in the browse dialog. `org` shows `_skillResults` (this instance's
|
|
5763
|
+
* skills); `kodaris` shows `_globalSkillResults` (the shared global catalog).
|
|
5742
5764
|
*/
|
|
5743
5765
|
this._skillBrowseSource = 'org';
|
|
5744
|
-
/** Search text in the browse dialog,
|
|
5766
|
+
/** Search text in the browse dialog, routed to the active tab's search. */
|
|
5745
5767
|
this._skillBrowseQuery = '';
|
|
5746
5768
|
this._handleMouseMove = (e) => {
|
|
5747
5769
|
if (this._isDragging) {
|
|
@@ -5839,6 +5861,17 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
5839
5861
|
this.messages = messages;
|
|
5840
5862
|
}
|
|
5841
5863
|
}).catch(() => { });
|
|
5864
|
+
// Fetch the framework config on load (debugTelemetryEnabled, v2ChatEnabled,
|
|
5865
|
+
// registryServer). debugTelemetryEnabled gates the debug affordances and is
|
|
5866
|
+
// known before any message.
|
|
5867
|
+
KRHttp.fetch({
|
|
5868
|
+
url: '/api/system/integration/aws/bedrock/aiFrameworkConfig',
|
|
5869
|
+
})
|
|
5870
|
+
.then((r) => r.json())
|
|
5871
|
+
.then((res) => {
|
|
5872
|
+
this._aiFrameworkConfig = res?.data || {};
|
|
5873
|
+
})
|
|
5874
|
+
.catch(() => { });
|
|
5842
5875
|
// Inline mode fills its container and is always open — the floating widget's
|
|
5843
5876
|
// toggle/drag/resize state doesn't apply, but the composer message and debug
|
|
5844
5877
|
// drawer state (restored inside _restoreState) do.
|
|
@@ -6133,11 +6166,16 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6133
6166
|
}
|
|
6134
6167
|
}
|
|
6135
6168
|
_handleKeyDown(e) {
|
|
6136
|
-
// When the skill menu is open, arrow keys / Enter / Escape drive it. The
|
|
6137
|
-
//
|
|
6138
|
-
// filtered skills
|
|
6169
|
+
// When the skill menu is open, arrow keys / Enter / Escape drive it. The top
|
|
6170
|
+
// actions (Attach Files, Browse All Skills, plus the two debug test triggers
|
|
6171
|
+
// when enabled) come first, then the filtered skills — all one navigable list.
|
|
6139
6172
|
if (this._skillMenuOpened) {
|
|
6140
|
-
const
|
|
6173
|
+
const debugActions = this.variant === 'inline' && this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
6174
|
+
let actionCount = 2;
|
|
6175
|
+
if (debugActions) {
|
|
6176
|
+
actionCount = 4;
|
|
6177
|
+
}
|
|
6178
|
+
const count = actionCount + this._skillResults.length;
|
|
6141
6179
|
if (e.key === 'ArrowDown') {
|
|
6142
6180
|
e.preventDefault();
|
|
6143
6181
|
this._skillHighlighted = (this._skillHighlighted + 1) % count;
|
|
@@ -6164,8 +6202,13 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6164
6202
|
this._handleSubmit();
|
|
6165
6203
|
}
|
|
6166
6204
|
}
|
|
6167
|
-
/** Run the skill-menu item at the given flat index (
|
|
6205
|
+
/** Run the skill-menu item at the given flat index (actions first, then skills). */
|
|
6168
6206
|
_activateSkillMenuItem(index) {
|
|
6207
|
+
const debugActions = this.variant === 'inline' && this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
6208
|
+
let actionCount = 2;
|
|
6209
|
+
if (debugActions) {
|
|
6210
|
+
actionCount = 4;
|
|
6211
|
+
}
|
|
6169
6212
|
if (index === 0) {
|
|
6170
6213
|
this._openFilePicker();
|
|
6171
6214
|
return;
|
|
@@ -6174,7 +6217,23 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6174
6217
|
this._handleSkillBrowseOpen();
|
|
6175
6218
|
return;
|
|
6176
6219
|
}
|
|
6177
|
-
|
|
6220
|
+
if (debugActions && index === 2) {
|
|
6221
|
+
this._skillMenuOpened = false;
|
|
6222
|
+
this._send({
|
|
6223
|
+
message: '/test-warning',
|
|
6224
|
+
internalFiles: [],
|
|
6225
|
+
});
|
|
6226
|
+
return;
|
|
6227
|
+
}
|
|
6228
|
+
if (debugActions && index === 3) {
|
|
6229
|
+
this._skillMenuOpened = false;
|
|
6230
|
+
this._send({
|
|
6231
|
+
message: '/test-limit',
|
|
6232
|
+
internalFiles: [],
|
|
6233
|
+
});
|
|
6234
|
+
return;
|
|
6235
|
+
}
|
|
6236
|
+
const skill = this._skillResults[index - actionCount];
|
|
6178
6237
|
if (skill) {
|
|
6179
6238
|
this._handleSkillSelect(skill);
|
|
6180
6239
|
}
|
|
@@ -6203,17 +6262,33 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6203
6262
|
// specials so user input is treated literally, then wrap with `*...*`.
|
|
6204
6263
|
let must = { match_all: {} };
|
|
6205
6264
|
if (trimmed) {
|
|
6206
|
-
const pattern = `*${trimmed.replace(/([*?\\])/g, '\\$1')}*`;
|
|
6207
|
-
const value = {
|
|
6208
|
-
value: pattern,
|
|
6209
|
-
case_insensitive: true,
|
|
6210
|
-
};
|
|
6211
6265
|
must = {
|
|
6212
6266
|
bool: {
|
|
6213
6267
|
should: [
|
|
6214
|
-
{
|
|
6215
|
-
|
|
6216
|
-
|
|
6268
|
+
{
|
|
6269
|
+
wildcard: {
|
|
6270
|
+
'name.raw': {
|
|
6271
|
+
value: `*${trimmed.replace(/([*?\\])/g, '\\$1')}*`,
|
|
6272
|
+
case_insensitive: true,
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6275
|
+
},
|
|
6276
|
+
{
|
|
6277
|
+
wildcard: {
|
|
6278
|
+
'code.raw': {
|
|
6279
|
+
value: `*${trimmed.replace(/([*?\\])/g, '\\$1')}*`,
|
|
6280
|
+
case_insensitive: true,
|
|
6281
|
+
}
|
|
6282
|
+
}
|
|
6283
|
+
},
|
|
6284
|
+
{
|
|
6285
|
+
wildcard: {
|
|
6286
|
+
'description.raw': {
|
|
6287
|
+
value: `*${trimmed.replace(/([*?\\])/g, '\\$1')}*`,
|
|
6288
|
+
case_insensitive: true,
|
|
6289
|
+
}
|
|
6290
|
+
}
|
|
6291
|
+
},
|
|
6217
6292
|
],
|
|
6218
6293
|
minimum_should_match: 1,
|
|
6219
6294
|
},
|
|
@@ -6244,6 +6319,66 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6244
6319
|
console.error('kr-chatbot: skill search failed', error);
|
|
6245
6320
|
});
|
|
6246
6321
|
}
|
|
6322
|
+
/**
|
|
6323
|
+
* Search the shared Kodaris global-skill registry into `_globalSkillResults`
|
|
6324
|
+
* (the browse dialog's "Kodaris" tab). Unlike `/aiskills/search`,
|
|
6325
|
+
* `/aiskills/global/search` returns a digested list
|
|
6326
|
+
* (`data: [{ code, name, description, enabled }]`) already in `KRChatbotSkill`
|
|
6327
|
+
* shape, so no `_source` lifting is needed. Only the browse dialog calls this
|
|
6328
|
+
* (the `/` menu is org-only), so it isn't run per slash keystroke.
|
|
6329
|
+
*/
|
|
6330
|
+
_searchGlobalSkills(query) {
|
|
6331
|
+
this._globalSkillRequestId++;
|
|
6332
|
+
const requestId = this._globalSkillRequestId;
|
|
6333
|
+
KRHttp.fetch({
|
|
6334
|
+
url: '/api/system/opensearch/aiskills/global/search',
|
|
6335
|
+
method: 'POST',
|
|
6336
|
+
body: { query: query.trim() },
|
|
6337
|
+
})
|
|
6338
|
+
.then((r) => r.json())
|
|
6339
|
+
.then((res) => {
|
|
6340
|
+
// Ignore a stale response superseded by a newer search.
|
|
6341
|
+
if (requestId !== this._globalSkillRequestId) {
|
|
6342
|
+
return;
|
|
6343
|
+
}
|
|
6344
|
+
this._globalSkillResults = (res?.data || []);
|
|
6345
|
+
})
|
|
6346
|
+
.catch((error) => {
|
|
6347
|
+
console.error('kr-chatbot: global skill search failed', error);
|
|
6348
|
+
});
|
|
6349
|
+
}
|
|
6350
|
+
/**
|
|
6351
|
+
* Enable or disable a global skill on this instance via
|
|
6352
|
+
* `/aiskills/global/{code}/enabled`, then reflect the server's result on the
|
|
6353
|
+
* matching card. Ignores clicks while a request for the same code is pending.
|
|
6354
|
+
*/
|
|
6355
|
+
_handleGlobalSkillEnable(skill, e) {
|
|
6356
|
+
// The card body inserts the skill; the `+` button must not also do that.
|
|
6357
|
+
e.stopPropagation();
|
|
6358
|
+
if (this._globalSkillPending.has(skill.code)) {
|
|
6359
|
+
return;
|
|
6360
|
+
}
|
|
6361
|
+
this._globalSkillPending.add(skill.code);
|
|
6362
|
+
this.requestUpdate();
|
|
6363
|
+
KRHttp.fetch({
|
|
6364
|
+
url: `/api/system/opensearch/aiskills/global/${encodeURIComponent(skill.code)}/enabled`,
|
|
6365
|
+
method: 'POST',
|
|
6366
|
+
body: { enabled: !skill.enabled },
|
|
6367
|
+
})
|
|
6368
|
+
.then((r) => r.json())
|
|
6369
|
+
.then((res) => {
|
|
6370
|
+
// Reflect the server's returned flag on the card.
|
|
6371
|
+
skill.enabled = res?.data?.enabled;
|
|
6372
|
+
this.requestUpdate();
|
|
6373
|
+
})
|
|
6374
|
+
.catch((error) => {
|
|
6375
|
+
console.error('kr-chatbot: global skill enable failed', error);
|
|
6376
|
+
})
|
|
6377
|
+
.finally(() => {
|
|
6378
|
+
this._globalSkillPending.delete(skill.code);
|
|
6379
|
+
this.requestUpdate();
|
|
6380
|
+
});
|
|
6381
|
+
}
|
|
6247
6382
|
/** The `+` button toggles the skill/attachment menu open (showing all skills). */
|
|
6248
6383
|
_handlePlusClick() {
|
|
6249
6384
|
if (this._skillMenuOpened) {
|
|
@@ -6263,6 +6398,13 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6263
6398
|
this._skillBrowseOpened = false;
|
|
6264
6399
|
this._inputEl?.focus();
|
|
6265
6400
|
}
|
|
6401
|
+
/** Activate a skill card via keyboard (Enter/Space), since it's a div role=button. */
|
|
6402
|
+
_handleSkillCardKeydown(e, skill) {
|
|
6403
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
6404
|
+
e.preventDefault();
|
|
6405
|
+
this._handleSkillSelect(skill);
|
|
6406
|
+
}
|
|
6407
|
+
}
|
|
6266
6408
|
/** Copy a message's text to the clipboard and briefly flash "Copied". */
|
|
6267
6409
|
_handleCopyMessage(content, index) {
|
|
6268
6410
|
navigator.clipboard.writeText(content).then(() => {
|
|
@@ -6278,16 +6420,22 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6278
6420
|
this._skillMenuOpened = false;
|
|
6279
6421
|
this._skillBrowseQuery = '';
|
|
6280
6422
|
this._skillBrowseOpened = true;
|
|
6423
|
+
// Fill both tabs up front so switching between them is instant, not stale.
|
|
6281
6424
|
this._searchSkills('');
|
|
6425
|
+
this._searchGlobalSkills('');
|
|
6282
6426
|
}
|
|
6283
6427
|
_handleSkillBrowseClose() {
|
|
6284
6428
|
this._skillBrowseOpened = false;
|
|
6285
6429
|
}
|
|
6286
6430
|
_handleSkillBrowseSearch(e) {
|
|
6287
6431
|
this._skillBrowseQuery = e.target.value;
|
|
6432
|
+
// Filter both catalogs so whichever tab the user switches to is already current.
|
|
6288
6433
|
this._searchSkills(this._skillBrowseQuery);
|
|
6434
|
+
this._searchGlobalSkills(this._skillBrowseQuery);
|
|
6289
6435
|
}
|
|
6290
6436
|
_handleSkillBrowseTabChange(e) {
|
|
6437
|
+
// Both buffers are kept current by open/search, so switching just swaps which
|
|
6438
|
+
// one is shown — no re-search needed.
|
|
6291
6439
|
this._skillBrowseSource = e.detail.activeTabId;
|
|
6292
6440
|
}
|
|
6293
6441
|
// --- Attachments ---
|
|
@@ -6425,9 +6573,21 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6425
6573
|
if (submitEvent.defaultPrevented) {
|
|
6426
6574
|
return;
|
|
6427
6575
|
}
|
|
6576
|
+
this._send({
|
|
6577
|
+
message: messageText,
|
|
6578
|
+
internalFiles
|
|
6579
|
+
});
|
|
6580
|
+
}
|
|
6581
|
+
/**
|
|
6582
|
+
* Append the user message and stream the response. Split out of `_handleSubmit`
|
|
6583
|
+
* so debug test triggers can send a specific message without going through the
|
|
6584
|
+
* composer input. `_handleSubmit` owns reading/validating the composer and
|
|
6585
|
+
* firing the cancelable `message-submit` event; this owns the send + stream.
|
|
6586
|
+
*/
|
|
6587
|
+
_send(params) {
|
|
6428
6588
|
const userMessage = {
|
|
6429
6589
|
type: 'user',
|
|
6430
|
-
content:
|
|
6590
|
+
content: params.message,
|
|
6431
6591
|
};
|
|
6432
6592
|
this.messages = [...this.messages, userMessage];
|
|
6433
6593
|
this._inputValue = '';
|
|
@@ -6493,9 +6653,9 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6493
6653
|
};
|
|
6494
6654
|
}
|
|
6495
6655
|
this.send({
|
|
6496
|
-
message:
|
|
6656
|
+
message: params.message,
|
|
6497
6657
|
messages: this.messages.slice(0, -1),
|
|
6498
|
-
internalFiles,
|
|
6658
|
+
internalFiles: params.internalFiles,
|
|
6499
6659
|
}).then((response) => {
|
|
6500
6660
|
if (!response.ok) {
|
|
6501
6661
|
this._handleStreamError('Request failed: ' + response.status);
|
|
@@ -6716,6 +6876,14 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6716
6876
|
/** The `/` skill menu shown above the composer while typing a slash command. */
|
|
6717
6877
|
_renderSkillMenu() {
|
|
6718
6878
|
const skills = this._skillResults;
|
|
6879
|
+
// Debug test triggers are extra actions after Attach Files / Browse. The
|
|
6880
|
+
// flat keyboard index counts actions first, then skills, so the skills'
|
|
6881
|
+
// index offset is the number of actions shown.
|
|
6882
|
+
const debugActions = this.variant === 'inline' && this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
6883
|
+
let actionCount = 2;
|
|
6884
|
+
if (debugActions) {
|
|
6885
|
+
actionCount = 4;
|
|
6886
|
+
}
|
|
6719
6887
|
return b `
|
|
6720
6888
|
<div class="skill-menu">
|
|
6721
6889
|
<div class="skill-menu__actions">
|
|
@@ -6737,6 +6905,26 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6737
6905
|
>
|
|
6738
6906
|
Browse All Skills
|
|
6739
6907
|
</button>
|
|
6908
|
+
${debugActions ? b `
|
|
6909
|
+
<button
|
|
6910
|
+
class=${e({
|
|
6911
|
+
'skill-menu__action': true,
|
|
6912
|
+
'skill-menu__item--highlighted': this._skillHighlighted === 2,
|
|
6913
|
+
})}
|
|
6914
|
+
@click=${() => this._activateSkillMenuItem(2)}
|
|
6915
|
+
>
|
|
6916
|
+
Test: context warning
|
|
6917
|
+
</button>
|
|
6918
|
+
<button
|
|
6919
|
+
class=${e({
|
|
6920
|
+
'skill-menu__action': true,
|
|
6921
|
+
'skill-menu__item--highlighted': this._skillHighlighted === 3,
|
|
6922
|
+
})}
|
|
6923
|
+
@click=${() => this._activateSkillMenuItem(3)}
|
|
6924
|
+
>
|
|
6925
|
+
Test: context limit
|
|
6926
|
+
</button>
|
|
6927
|
+
` : A}
|
|
6740
6928
|
</div>
|
|
6741
6929
|
${skills.length ? b `
|
|
6742
6930
|
<ul class="skill-menu__list">
|
|
@@ -6745,7 +6933,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6745
6933
|
<button
|
|
6746
6934
|
class=${e({
|
|
6747
6935
|
'skill-menu__item': true,
|
|
6748
|
-
'skill-menu__item--highlighted': index +
|
|
6936
|
+
'skill-menu__item--highlighted': index + actionCount === this._skillHighlighted,
|
|
6749
6937
|
})}
|
|
6750
6938
|
@click=${() => this._handleSkillSelect(skill)}
|
|
6751
6939
|
>
|
|
@@ -6784,37 +6972,81 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6784
6972
|
${this._renderSkillGrid()}
|
|
6785
6973
|
</kr-tab>
|
|
6786
6974
|
<kr-tab id="kodaris" label="Kodaris">
|
|
6787
|
-
|
|
6788
|
-
Shared Kodaris skills are coming soon.
|
|
6789
|
-
</div>
|
|
6975
|
+
${this._renderSkillGrid(true)}
|
|
6790
6976
|
</kr-tab>
|
|
6791
6977
|
</kr-tab-group>
|
|
6792
6978
|
</div>
|
|
6793
6979
|
</kr-dialog>
|
|
6794
6980
|
`;
|
|
6795
6981
|
}
|
|
6796
|
-
/**
|
|
6797
|
-
|
|
6798
|
-
|
|
6982
|
+
/**
|
|
6983
|
+
* The card grid of skill search results for the browse dialog. Clicking a card
|
|
6984
|
+
* inserts `/code ` into the composer. In the shared-Kodaris (`global`) tab each
|
|
6985
|
+
* card also gets a `+` install button that enables the skill on this instance
|
|
6986
|
+
* (turning into a ✓ once installed).
|
|
6987
|
+
*/
|
|
6988
|
+
_renderSkillGrid(global = false) {
|
|
6989
|
+
let skills = this._skillResults;
|
|
6990
|
+
if (global) {
|
|
6991
|
+
skills = this._globalSkillResults;
|
|
6992
|
+
}
|
|
6799
6993
|
if (!skills.length) {
|
|
6800
6994
|
return A;
|
|
6801
6995
|
}
|
|
6802
6996
|
return b `
|
|
6803
6997
|
<div class="skill-browse__grid">
|
|
6804
6998
|
${skills.map((skill) => b `
|
|
6805
|
-
<
|
|
6999
|
+
<div
|
|
6806
7000
|
class="skill-card"
|
|
7001
|
+
role="button"
|
|
7002
|
+
tabindex="0"
|
|
6807
7003
|
@click=${() => this._handleSkillSelect(skill)}
|
|
7004
|
+
@keydown=${(e) => this._handleSkillCardKeydown(e, skill)}
|
|
6808
7005
|
>
|
|
6809
7006
|
<span class="skill-card__name">${skill.name}</span>
|
|
6810
7007
|
${skill.description ? b `
|
|
6811
7008
|
<span class="skill-card__desc">${skill.description}</span>
|
|
6812
7009
|
` : A}
|
|
6813
|
-
|
|
7010
|
+
${global ? this._renderSkillInstall(skill) : A}
|
|
7011
|
+
</div>
|
|
6814
7012
|
`)}
|
|
6815
7013
|
</div>
|
|
6816
7014
|
`;
|
|
6817
7015
|
}
|
|
7016
|
+
/**
|
|
7017
|
+
* The install affordance on a global skill card: a `+` button that enables the
|
|
7018
|
+
* skill on this instance, showing a ✓ once installed and a disabled state
|
|
7019
|
+
* while the enable/disable request is in flight.
|
|
7020
|
+
*/
|
|
7021
|
+
_renderSkillInstall(skill) {
|
|
7022
|
+
return b `
|
|
7023
|
+
<button
|
|
7024
|
+
class=${e({
|
|
7025
|
+
'skill-card__install': true,
|
|
7026
|
+
'skill-card__install--installed': !!skill.enabled,
|
|
7027
|
+
})}
|
|
7028
|
+
?disabled=${this._globalSkillPending.has(skill.code)}
|
|
7029
|
+
title=${!!skill.enabled ? 'Installed — click to remove' : 'Install this skill'}
|
|
7030
|
+
aria-label=${!!skill.enabled ? 'Remove skill' : 'Install skill'}
|
|
7031
|
+
@click=${(e) => this._handleGlobalSkillEnable(skill, e)}
|
|
7032
|
+
>
|
|
7033
|
+
<svg
|
|
7034
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
7035
|
+
fill="none"
|
|
7036
|
+
viewBox="0 0 24 24"
|
|
7037
|
+
stroke-width="2"
|
|
7038
|
+
stroke="currentColor"
|
|
7039
|
+
class="skill-card__install-icon"
|
|
7040
|
+
>
|
|
7041
|
+
<path
|
|
7042
|
+
stroke-linecap="round"
|
|
7043
|
+
stroke-linejoin="round"
|
|
7044
|
+
d=${!!skill.enabled ? 'm4.5 12.75 6 6 9-13.5' : 'M12 4.5v15m7.5-7.5h-15'}
|
|
7045
|
+
/>
|
|
7046
|
+
</svg>
|
|
7047
|
+
</button>
|
|
7048
|
+
`;
|
|
7049
|
+
}
|
|
6818
7050
|
/**
|
|
6819
7051
|
* Render a user message, highlighting a leading `/skill-code` token (like the
|
|
6820
7052
|
* way Claude highlights slash commands). The composer only inserts valid skill
|
|
@@ -6980,6 +7212,9 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
6980
7212
|
`;
|
|
6981
7213
|
}
|
|
6982
7214
|
render() {
|
|
7215
|
+
// Debug affordances (drawer toggle, drawer, /test-* options) require the
|
|
7216
|
+
// inline variant AND the server-side debug flag from aiFrameworkConfig.
|
|
7217
|
+
const isDebugEnabled = this.variant === 'inline' && this._aiFrameworkConfig.debugTelemetryEnabled === true;
|
|
6983
7218
|
return b `
|
|
6984
7219
|
${(this.hideToggle || this.variant === 'inline') ? A : b `
|
|
6985
7220
|
<button
|
|
@@ -7010,7 +7245,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7010
7245
|
'panel--opened': this.opened,
|
|
7011
7246
|
'panel--resizing-debug': this._isDebugResizing,
|
|
7012
7247
|
})}
|
|
7013
|
-
style=${o(
|
|
7248
|
+
style=${o(isDebugEnabled && this._debugPanelOpen ? { paddingRight: `${this._debugDrawerWidth}px` } : {})}
|
|
7014
7249
|
@dragenter=${this._handleDragEnter}
|
|
7015
7250
|
@dragover=${this._handleDragOver}
|
|
7016
7251
|
@dragleave=${this._handleDragLeave}
|
|
@@ -7083,7 +7318,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7083
7318
|
</div>
|
|
7084
7319
|
</div>
|
|
7085
7320
|
<div class="header-actions">
|
|
7086
|
-
${
|
|
7321
|
+
${isDebugEnabled ? b `
|
|
7087
7322
|
<button
|
|
7088
7323
|
class=${e({
|
|
7089
7324
|
'header-action': true,
|
|
@@ -7402,7 +7637,7 @@ let KRChatbot = class KRChatbot extends i$3 {
|
|
|
7402
7637
|
</div>
|
|
7403
7638
|
</div>
|
|
7404
7639
|
${this._skillBrowseOpened ? this._renderSkillBrowse() : A}
|
|
7405
|
-
${
|
|
7640
|
+
${isDebugEnabled ? this._renderDebugPanel() : A}
|
|
7406
7641
|
</div>
|
|
7407
7642
|
`;
|
|
7408
7643
|
}
|
|
@@ -8427,6 +8662,7 @@ KRChatbot.styles = i$6 `
|
|
|
8427
8662
|
}
|
|
8428
8663
|
|
|
8429
8664
|
.skill-card {
|
|
8665
|
+
position: relative;
|
|
8430
8666
|
display: flex;
|
|
8431
8667
|
flex-direction: column;
|
|
8432
8668
|
gap: 6px;
|
|
@@ -8446,8 +8682,53 @@ KRChatbot.styles = i$6 `
|
|
|
8446
8682
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
8447
8683
|
}
|
|
8448
8684
|
|
|
8685
|
+
/* Install button on global skill cards. Absolutely positioned in the corner
|
|
8686
|
+
so it sits above the card's own click target; leave room via the name's
|
|
8687
|
+
padding-right below. */
|
|
8688
|
+
.skill-card__install {
|
|
8689
|
+
position: absolute;
|
|
8690
|
+
top: 10px;
|
|
8691
|
+
right: 10px;
|
|
8692
|
+
display: inline-flex;
|
|
8693
|
+
align-items: center;
|
|
8694
|
+
justify-content: center;
|
|
8695
|
+
width: 24px;
|
|
8696
|
+
height: 24px;
|
|
8697
|
+
padding: 0;
|
|
8698
|
+
border: 1px solid #d1d5db;
|
|
8699
|
+
border-radius: 6px;
|
|
8700
|
+
background: white;
|
|
8701
|
+
color: #374151;
|
|
8702
|
+
cursor: pointer;
|
|
8703
|
+
transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
|
|
8704
|
+
}
|
|
8705
|
+
|
|
8706
|
+
.skill-card__install:hover:not(:disabled) {
|
|
8707
|
+
border-color: var(--kr-chatbot-primary);
|
|
8708
|
+
color: var(--kr-chatbot-primary);
|
|
8709
|
+
}
|
|
8710
|
+
|
|
8711
|
+
.skill-card__install:disabled {
|
|
8712
|
+
opacity: 0.5;
|
|
8713
|
+
cursor: default;
|
|
8714
|
+
}
|
|
8715
|
+
|
|
8716
|
+
/* Installed state: filled check. */
|
|
8717
|
+
.skill-card__install--installed {
|
|
8718
|
+
background: var(--kr-chatbot-primary);
|
|
8719
|
+
border-color: var(--kr-chatbot-primary);
|
|
8720
|
+
color: white;
|
|
8721
|
+
}
|
|
8722
|
+
|
|
8723
|
+
.skill-card__install-icon {
|
|
8724
|
+
width: 15px;
|
|
8725
|
+
height: 15px;
|
|
8726
|
+
}
|
|
8727
|
+
|
|
8449
8728
|
.skill-card__name {
|
|
8450
8729
|
font-weight: 600;
|
|
8730
|
+
/* Leave room for the corner install button on global cards. */
|
|
8731
|
+
padding-right: 28px;
|
|
8451
8732
|
}
|
|
8452
8733
|
|
|
8453
8734
|
.skill-card__desc {
|
|
@@ -8637,6 +8918,12 @@ __decorate([
|
|
|
8637
8918
|
__decorate([
|
|
8638
8919
|
r()
|
|
8639
8920
|
], KRChatbot.prototype, "_skillResults", void 0);
|
|
8921
|
+
__decorate([
|
|
8922
|
+
r()
|
|
8923
|
+
], KRChatbot.prototype, "_globalSkillResults", void 0);
|
|
8924
|
+
__decorate([
|
|
8925
|
+
r()
|
|
8926
|
+
], KRChatbot.prototype, "_aiFrameworkConfig", void 0);
|
|
8640
8927
|
__decorate([
|
|
8641
8928
|
r()
|
|
8642
8929
|
], KRChatbot.prototype, "_skillHighlighted", void 0);
|