@eclipse-docks/extension-ai-system 0.8.0 → 0.8.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.
Files changed (66) hide show
  1. package/README.md +2 -2
  2. package/dist/api.d.ts +1 -1
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +87 -2
  5. package/dist/api.js.map +1 -0
  6. package/dist/{cognitive-extension-CG_d39K5.js → cognitive-extension-BKGxwLYj.js} +524 -102
  7. package/dist/cognitive-extension-BKGxwLYj.js.map +1 -0
  8. package/dist/cognitive-extension.d.ts.map +1 -1
  9. package/dist/index.js +1 -1
  10. package/dist/runtime/abort.d.ts +5 -0
  11. package/dist/runtime/abort.d.ts.map +1 -0
  12. package/dist/runtime/attachment-paths.d.ts +17 -0
  13. package/dist/runtime/attachment-paths.d.ts.map +1 -0
  14. package/dist/runtime/attachments.d.ts +5 -5
  15. package/dist/runtime/attachments.d.ts.map +1 -1
  16. package/dist/runtime/cognitive-runtime.d.ts +12 -3
  17. package/dist/runtime/cognitive-runtime.d.ts.map +1 -1
  18. package/dist/runtime/context/usage.d.ts +3 -0
  19. package/dist/runtime/context/usage.d.ts.map +1 -1
  20. package/dist/runtime/index.d.ts +4 -0
  21. package/dist/runtime/index.d.ts.map +1 -1
  22. package/dist/runtime/models/openai-compatible.d.ts.map +1 -1
  23. package/dist/runtime/models/types.d.ts +6 -1
  24. package/dist/runtime/models/types.d.ts.map +1 -1
  25. package/dist/runtime/session-workspace.d.ts +20 -0
  26. package/dist/runtime/session-workspace.d.ts.map +1 -0
  27. package/dist/runtime/skills-commands.d.ts +3 -0
  28. package/dist/runtime/skills-commands.d.ts.map +1 -0
  29. package/dist/runtime/skills-parse.d.ts +14 -0
  30. package/dist/runtime/skills-parse.d.ts.map +1 -0
  31. package/dist/runtime/skills-resolve.d.ts +9 -0
  32. package/dist/runtime/skills-resolve.d.ts.map +1 -0
  33. package/dist/runtime/skills-select.d.ts +9 -0
  34. package/dist/runtime/skills-select.d.ts.map +1 -0
  35. package/dist/runtime/skills-types.d.ts +47 -0
  36. package/dist/runtime/skills-types.d.ts.map +1 -0
  37. package/dist/runtime/skills.d.ts +13 -0
  38. package/dist/runtime/skills.d.ts.map +1 -0
  39. package/dist/runtime/specialists/index.d.ts.map +1 -1
  40. package/dist/runtime/specialists/loop.d.ts.map +1 -1
  41. package/dist/runtime/tools/command-adapter.d.ts.map +1 -1
  42. package/dist/runtime/tools/fetch-adapter.d.ts +4 -0
  43. package/dist/runtime/tools/fetch-adapter.d.ts.map +1 -0
  44. package/dist/runtime/tools/index.d.ts +1 -1
  45. package/dist/runtime/tools/index.d.ts.map +1 -1
  46. package/dist/runtime/tools/workspace-adapter.d.ts +1 -1
  47. package/dist/runtime/tools/workspace-adapter.d.ts.map +1 -1
  48. package/dist/runtime/tools/workspace-path-qualify.d.ts +22 -0
  49. package/dist/runtime/tools/workspace-path-qualify.d.ts.map +1 -0
  50. package/dist/runtime/tools/workspace-path.d.ts +17 -0
  51. package/dist/runtime/tools/workspace-path.d.ts.map +1 -0
  52. package/dist/runtime/types.d.ts +7 -0
  53. package/dist/runtime/types.d.ts.map +1 -1
  54. package/dist/{runtime-DfNGzEjU.js → runtime-B0IHjzQO.js} +1042 -401
  55. package/dist/runtime-B0IHjzQO.js.map +1 -0
  56. package/dist/view/busy-status.d.ts +12 -0
  57. package/dist/view/busy-status.d.ts.map +1 -0
  58. package/dist/view/cognitive-settings-editor.d.ts +0 -1
  59. package/dist/view/cognitive-settings-editor.d.ts.map +1 -1
  60. package/dist/view/cognitive-view.d.ts +22 -0
  61. package/dist/view/cognitive-view.d.ts.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/cognitive-extension-CG_d39K5.js.map +0 -1
  64. package/dist/runtime/tools/attachment-adapter.d.ts +0 -6
  65. package/dist/runtime/tools/attachment-adapter.d.ts.map +0 -1
  66. package/dist/runtime-DfNGzEjU.js.map +0 -1
@@ -1,20 +1,69 @@
1
- import { _ as AI_SETTINGS_KEY, a as formatContextPercent, b as TOPIC, c as readPromptAttachmentFromFile, d as defaultProvidersSettings, g as AI_SETTINGS_EDITOR_ID, i as formatBucketDetail, m as detectEffortCapability, n as cognitiveRuntime, o as formatTokenCount, p as parseModelIds, r as estimateSessionContextUsage, s as ATTACHMENT_FILE_ACCEPT, u as fetchOpenAICompatibleModels, v as AI_VIEW_NAME, y as OPEN_AI_SETTINGS_COMMAND } from "./runtime-DfNGzEjU.js";
2
- import { DocksPart, SIDEBAR_AUXILIARY, confirmDialog, contributionRegistry, editorRegistry, registerAll, rootContext, toastError, toastInfo } from "@eclipse-docks/core";
3
- import { css, customElement, html, nothing, property, query, state } from "@eclipse-docks/core/externals/lit";
1
+ import { C as detectEffortCapability, D as AI_VIEW_NAME, E as AI_SETTINGS_KEY, O as OPEN_AI_SETTINGS_COMMAND, S as parseModelIds, T as AI_SETTINGS_EDITOR_ID, _ as readPromptAttachmentFromFile, b as defaultProvidersSettings, f as estimateSessionContextUsage, g as ATTACHMENT_FILE_ACCEPT, h as formatTokenCount, k as TOPIC, m as formatContextPercent, p as formatBucketDetail, r as cognitiveRuntime, t as registerSkillCommands, y as fetchOpenAICompatibleModels } from "./runtime-B0IHjzQO.js";
2
+ import { DocksPart, File as File$1, FileContentType, SIDEBAR_AUXILIARY, confirmDialog, contributionRegistry, editorRegistry, filebrowserDialog, parseMarkdownHtml, registerAll, rootContext, toastError, toastInfo, workspaceService } from "@eclipse-docks/core";
3
+ import { css, customElement, html, nothing, property, query, state, unsafeHTML } from "@eclipse-docks/core/externals/lit";
4
4
  import "@eclipse-docks/core/externals/webawesome";
5
5
  import _decorate from "@oxc-project/runtime/helpers/decorate";
6
+ //#region src/view/busy-status.ts
7
+ /** Shown immediately when waiting on a model turn. */
8
+ var INITIAL_BUSY_STATUS = "Thinking…";
9
+ /**
10
+ * Rotating wait copy (Cursor / Copilot style). Picked at random after the initial message.
11
+ * Keep these light and short — they appear in the composer while busy.
12
+ */
13
+ var BUSY_STATUS_MESSAGES = [
14
+ "Bribing the hamster…",
15
+ "Consulting the rubber duck…",
16
+ "Untangling the spaghetti…",
17
+ "Herding tokens…",
18
+ "Warming up the crystals…",
19
+ "Counting electric sheep…",
20
+ "Negotiating with the compiler…",
21
+ "Teaching frogs to code…",
22
+ "Aligning the bits…",
23
+ "Feeding the GPU snacks…",
24
+ "Looking under the couch…",
25
+ "Summoning a specialist…",
26
+ "Checking the manual twice…",
27
+ "Reticulating splines…",
28
+ "Sharpening pencils…",
29
+ "Pedaling harder…",
30
+ "Buffering brilliance…",
31
+ "Reversing the polarity…",
32
+ "Convincing the bits to cooperate…",
33
+ "Dusting off the playbook…",
34
+ "Whispering to the model…",
35
+ "Calibrating optimism…",
36
+ "Unfolding the roadmap…",
37
+ "Polishing ones and zeros…",
38
+ "Asking politely…"
39
+ ];
40
+ var ROTATE_MS_MIN = 3e3;
41
+ /** Random delay until the next busy-status line (3–12s). */
42
+ function busyStatusRotateMs() {
43
+ return ROTATE_MS_MIN + Math.floor(Math.random() * 9001);
44
+ }
45
+ /** Next status, avoiding an immediate repeat of `current`. */
46
+ function nextBusyStatus(current) {
47
+ const pool = BUSY_STATUS_MESSAGES.filter((m) => m !== current);
48
+ if (!pool.length) return INITIAL_BUSY_STATUS;
49
+ return pool[Math.floor(Math.random() * pool.length)];
50
+ }
51
+ //#endregion
6
52
  //#region src/view/cognitive-view.ts
7
53
  var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
8
54
  constructor(..._args) {
9
55
  super(..._args);
10
56
  this.scrollMode = "none";
57
+ this.composerPasteBound = false;
11
58
  this.sessions = [];
12
59
  this.focusedId = null;
13
60
  this.draft = "";
14
61
  this.pendingAttachmentIds = [];
15
62
  this.dragOver = false;
16
63
  this.previewAttachmentId = null;
64
+ this.toolDetail = null;
17
65
  this.busy = false;
66
+ this.busyStatus = INITIAL_BUSY_STATUS;
18
67
  this.pendingPermission = null;
19
68
  this.policyMode = "auto";
20
69
  this.optimizeFor = "balance";
@@ -26,6 +75,13 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
26
75
  this.historyOpen = false;
27
76
  this.historyQuery = "";
28
77
  this.unsubs = [];
78
+ this.promptController = null;
79
+ this.nativePasteHandler = (e) => void this.onComposerPaste(e);
80
+ this.cancelKeyHandler = (e) => {
81
+ if (!this.busy || e.key !== "Escape") return;
82
+ e.preventDefault();
83
+ this.cancelTurn();
84
+ };
29
85
  }
30
86
  static {
31
87
  this.styles = css`
@@ -124,11 +180,21 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
124
180
  display: flex;
125
181
  flex-direction: column;
126
182
  gap: var(--wa-space-2xs);
127
- max-width: 100%;
183
+ width: 90%;
184
+ min-width: 90%;
185
+ max-width: 90%;
186
+ align-self: flex-start;
187
+ align-items: stretch;
128
188
  }
129
189
 
130
190
  .msg.user {
131
- align-items: flex-end;
191
+ align-self: flex-end;
192
+ }
193
+
194
+ .msg .bubble,
195
+ .msg wa-details.msg-details {
196
+ width: 100%;
197
+ box-sizing: border-box;
132
198
  }
133
199
 
134
200
  .msg-meta {
@@ -166,6 +232,39 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
166
232
  white-space: pre-wrap;
167
233
  line-height: var(--wa-line-height-normal);
168
234
  max-width: 100%;
235
+ overflow-wrap: anywhere;
236
+ }
237
+
238
+ .bubble.markdown {
239
+ white-space: normal;
240
+ }
241
+
242
+ .bubble.markdown > :first-child {
243
+ margin-block-start: 0;
244
+ }
245
+
246
+ .bubble.markdown > :last-child {
247
+ margin-block-end: 0;
248
+ }
249
+
250
+ .bubble.markdown pre {
251
+ overflow-x: auto;
252
+ padding: var(--wa-space-s);
253
+ border-radius: var(--wa-border-radius-m);
254
+ background: color-mix(in srgb, var(--wa-color-neutral-fill-quiet) 55%, transparent);
255
+ }
256
+
257
+ .bubble.markdown code {
258
+ font-family: var(--wa-font-family-code, ui-monospace, monospace);
259
+ font-size: 0.92em;
260
+ }
261
+
262
+ .bubble.markdown pre code {
263
+ font-size: inherit;
264
+ }
265
+
266
+ .bubble.markdown a {
267
+ color: var(--wa-color-brand-on-normal);
169
268
  }
170
269
 
171
270
  .msg.user .bubble {
@@ -262,6 +361,34 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
262
361
  background: var(--bucket-color, var(--wa-color-brand-fill-normal));
263
362
  }
264
363
 
364
+ .context-io {
365
+ display: grid;
366
+ grid-template-columns: 1fr 1fr;
367
+ gap: var(--wa-space-2xs);
368
+ padding-top: var(--wa-space-s);
369
+ border-top: var(--wa-border-width-s) solid var(--wa-color-border-normal);
370
+ font-size: var(--wa-font-size-xs);
371
+ }
372
+
373
+ .context-io-heading {
374
+ grid-column: 1 / -1;
375
+ font-weight: var(--wa-font-weight-semibold, 600);
376
+ }
377
+
378
+ .context-io-item {
379
+ display: flex;
380
+ flex-direction: column;
381
+ gap: 0.1rem;
382
+ }
383
+
384
+ .context-io-item span {
385
+ color: var(--wa-color-text-quiet);
386
+ }
387
+
388
+ .context-io-item strong {
389
+ font-variant-numeric: tabular-nums;
390
+ }
391
+
265
392
  .context-footer {
266
393
  display: flex;
267
394
  flex-direction: column;
@@ -490,8 +617,44 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
490
617
  color: var(--wa-color-text-quiet);
491
618
  margin-bottom: var(--wa-space-2xs);
492
619
  }
620
+
621
+ .tool-row {
622
+ display: flex;
623
+ align-items: center;
624
+ gap: var(--wa-space-2xs);
625
+ flex-wrap: wrap;
626
+ }
627
+
628
+ .tool-row .tool-heading {
629
+ margin-bottom: 0;
630
+ flex: 1;
631
+ min-width: 0;
632
+ }
633
+
634
+ .tool-detail-body {
635
+ max-height: min(70vh, 36rem);
636
+ overflow: auto;
637
+ }
638
+
639
+ .tool-detail-body pre {
640
+ margin: 0;
641
+ font-family: var(--wa-font-family-code, var(--wa-font-mono));
642
+ font-size: var(--wa-font-size-xs);
643
+ white-space: pre-wrap;
644
+ word-break: break-word;
645
+ }
493
646
  `;
494
647
  }
648
+ updated() {
649
+ this.bindComposerPaste();
650
+ }
651
+ bindComposerPaste() {
652
+ if (this.composerPasteBound) return;
653
+ const native = this.textarea?.shadowRoot?.querySelector("textarea");
654
+ if (!native) return;
655
+ native.addEventListener("paste", this.nativePasteHandler);
656
+ this.composerPasteBound = true;
657
+ }
495
658
  doBeforeUI() {
496
659
  cognitiveRuntime.start();
497
660
  this.syncSessions();
@@ -499,14 +662,13 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
499
662
  this.approvalMode = cognitiveRuntime.getApprovalMode();
500
663
  cognitiveRuntime.whenReady().then(() => {
501
664
  this.syncSessions();
502
- this.syncModels();
503
- this.approvalMode = cognitiveRuntime.getApprovalMode();
665
+ this.restoreRoutingFromRuntime();
504
666
  this.scheduleScrollToBottom();
505
667
  });
506
668
  this.unsubs.push(cognitiveRuntime.events.subscribe(TOPIC.sessionChanged, () => {
507
669
  this.syncSessions();
508
670
  this.scheduleScrollToBottom();
509
- }), cognitiveRuntime.events.subscribe(TOPIC.providersChanged, () => this.syncModels()), cognitiveRuntime.events.subscribe(TOPIC.approvalModeChanged, (mode) => {
671
+ }), cognitiveRuntime.events.subscribe(TOPIC.providersChanged, () => this.onProvidersChanged()), cognitiveRuntime.events.subscribe(TOPIC.approvalModeChanged, (mode) => {
510
672
  this.approvalMode = mode;
511
673
  }), cognitiveRuntime.events.subscribe(TOPIC.permissionAsked, (payload) => {
512
674
  this.pendingPermission = payload;
@@ -525,9 +687,33 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
525
687
  doClose() {
526
688
  if (this.scrollDebounceTimer) clearTimeout(this.scrollDebounceTimer);
527
689
  this.scrollDebounceTimer = void 0;
690
+ this.cancelTurn();
691
+ this.stopBusyStatus();
692
+ (this.textarea?.shadowRoot?.querySelector("textarea"))?.removeEventListener("paste", this.nativePasteHandler);
693
+ this.composerPasteBound = false;
528
694
  for (const u of this.unsubs) u();
529
695
  this.unsubs = [];
530
696
  }
697
+ startBusyStatus() {
698
+ this.stopBusyStatus();
699
+ this.busyStatus = INITIAL_BUSY_STATUS;
700
+ this.setComposerText(this.busyStatus);
701
+ window.addEventListener("keydown", this.cancelKeyHandler);
702
+ const schedule = () => {
703
+ this.busyStatusTimer = setTimeout(() => {
704
+ this.busyStatus = nextBusyStatus(this.busyStatus);
705
+ this.setComposerText(this.busyStatus);
706
+ schedule();
707
+ }, busyStatusRotateMs());
708
+ };
709
+ schedule();
710
+ }
711
+ stopBusyStatus() {
712
+ if (this.busyStatusTimer) clearTimeout(this.busyStatusTimer);
713
+ this.busyStatusTimer = void 0;
714
+ this.busyStatus = INITIAL_BUSY_STATUS;
715
+ window.removeEventListener("keydown", this.cancelKeyHandler);
716
+ }
531
717
  syncSessions() {
532
718
  const byRecency = cognitiveRuntime.sessions.list();
533
719
  this.sessions = [...byRecency].sort((a, b) => a.createdAt - b.createdAt);
@@ -558,11 +744,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
558
744
  deleteSession(sessionId) {
559
745
  if (this.sessions.length <= 1) {
560
746
  cognitiveRuntime.sessions.createSession({ title: "Chat" });
561
- cognitiveRuntime.sessions.remove(sessionId);
562
- } else cognitiveRuntime.sessions.remove(sessionId);
747
+ cognitiveRuntime.removeSession(sessionId);
748
+ } else cognitiveRuntime.removeSession(sessionId);
563
749
  this.streamingParts = [];
564
750
  this.syncSessions();
565
- cognitiveRuntime.commitSessions();
566
751
  }
567
752
  openSession(sessionId) {
568
753
  if (!cognitiveRuntime.sessions.focus(sessionId)) return;
@@ -598,6 +783,31 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
598
783
  this.modelIds = cognitiveRuntime.listConfiguredModels();
599
784
  if (!this.manualModel || !this.modelIds.includes(this.manualModel)) this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();
600
785
  }
786
+ /** Mirror persisted runtime policy into the gear menu after hydrate. */
787
+ restoreRoutingFromRuntime() {
788
+ this.syncModels();
789
+ const policy = cognitiveRuntime.getModelPolicy();
790
+ if (policy.mode === "auto") {
791
+ this.policyMode = "auto";
792
+ this.optimizeFor = policy.optimizeFor;
793
+ } else {
794
+ this.policyMode = "manual";
795
+ this.manualModel = policy.model;
796
+ this.manualEffort = policy.effort ?? "auto";
797
+ if (!this.manualModel || !this.modelIds.includes(this.manualModel)) {
798
+ this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();
799
+ this.applyPolicy();
800
+ }
801
+ }
802
+ this.approvalMode = cognitiveRuntime.getApprovalMode();
803
+ }
804
+ onProvidersChanged() {
805
+ this.syncModels();
806
+ if (this.policyMode !== "manual") return;
807
+ if (this.manualModel && this.modelIds.includes(this.manualModel)) return;
808
+ this.manualModel = this.modelIds[0] ?? cognitiveRuntime.defaultModelId();
809
+ this.applyPolicy();
810
+ }
601
811
  effortChoices() {
602
812
  const cap = detectEffortCapability(this.manualModel || cognitiveRuntime.defaultModelId());
603
813
  if (!cap.supported) return ["auto", "none"];
@@ -631,6 +841,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
631
841
  if (optimize === "cost" || optimize === "balance" || optimize === "intelligence") {
632
842
  this.policyMode = "auto";
633
843
  this.optimizeFor = optimize;
844
+ this.applyPolicy();
634
845
  }
635
846
  return;
636
847
  }
@@ -639,6 +850,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
639
850
  if (!model) return;
640
851
  this.policyMode = "manual";
641
852
  this.manualModel = model;
853
+ this.applyPolicy();
642
854
  }
643
855
  }
644
856
  applyPolicy() {
@@ -652,12 +864,15 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
652
864
  };
653
865
  cognitiveRuntime.setModelPolicy(policy);
654
866
  }
867
+ async setComposerText(value) {
868
+ this.draft = value;
869
+ await this.updateComplete;
870
+ if (this.textarea) this.textarea.value = value;
871
+ }
655
872
  async clearComposer() {
656
- this.draft = "";
657
873
  this.pendingAttachmentIds = [];
658
- await this.updateComplete;
659
- if (this.textarea) this.textarea.value = "";
660
874
  if (this.fileInput) this.fileInput.value = "";
875
+ await this.setComposerText("");
661
876
  }
662
877
  sessionAttachments() {
663
878
  return this.focusedSession()?.attachments ?? [];
@@ -679,6 +894,40 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
679
894
  if (this.previewAttachmentId === attachmentId) this.previewAttachmentId = null;
680
895
  this.syncSessions();
681
896
  }
897
+ async saveAttachmentToWorkspace(attachmentId) {
898
+ const attachment = this.sessionAttachments().find((a) => a.id === attachmentId);
899
+ if (!attachment) return;
900
+ const preferredName = attachmentSaveFileName(attachment);
901
+ const parent = await filebrowserDialog("directory");
902
+ if (!parent) return;
903
+ try {
904
+ const workspace = await workspaceService.getWorkspace();
905
+ if (!workspace) {
906
+ toastError("No workspace connected");
907
+ return;
908
+ }
909
+ const parentPath = parent.replace(/\/$/, "");
910
+ const fileName = await uniqueWorkspaceFileName(workspace, parentPath, preferredName);
911
+ const path = `${parentPath}/${fileName}`;
912
+ const resource = await workspace.getResource(path, { create: true });
913
+ if (!(resource instanceof File$1)) {
914
+ toastError("Could not create file in the selected folder");
915
+ return;
916
+ }
917
+ if (attachment.dataUrl) {
918
+ const blob = await (await fetch(attachment.dataUrl)).blob();
919
+ const named = new globalThis.File([blob], fileName, { type: blob.type || attachment.mime || "" });
920
+ await resource.saveContents(named, { contentType: FileContentType.BINARY });
921
+ } else if (attachment.text != null) await resource.saveContents(attachment.text);
922
+ else {
923
+ toastError("Attachment has no payload to save");
924
+ return;
925
+ }
926
+ toastInfo(`Saved ${fileName}`);
927
+ } catch (err) {
928
+ toastError(err instanceof Error ? err.message : String(err));
929
+ }
930
+ }
682
931
  async addFiles(fileList) {
683
932
  const files = [...fileList];
684
933
  if (!files.length) return;
@@ -699,7 +948,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
699
948
  }
700
949
  accepted.push(result.attachment);
701
950
  }
702
- const stored = cognitiveRuntime.addAttachments(sessionId, accepted);
951
+ const stored = await cognitiveRuntime.addAttachments(sessionId, accepted);
703
952
  if (stored.length) this.pendingAttachmentIds = [...this.pendingAttachmentIds, ...stored.map((a) => a.id).filter((id) => !this.pendingAttachmentIds.includes(id))];
704
953
  this.syncSessions();
705
954
  }
@@ -724,22 +973,47 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
724
973
  this.dragOver = false;
725
974
  if (e.dataTransfer?.files?.length) await this.addFiles(e.dataTransfer.files);
726
975
  }
976
+ /** Attach clipboard files/images (e.g. Ctrl+V screenshot) when focused in the prompt. */
977
+ async onComposerPaste(e) {
978
+ if (this.busy) {
979
+ e.preventDefault();
980
+ return;
981
+ }
982
+ const files = filesFromClipboard(e.clipboardData);
983
+ if (!files.length) return;
984
+ e.preventDefault();
985
+ await this.addFiles(files);
986
+ }
987
+ cancelTurn() {
988
+ if (!this.busy && !this.promptController) return;
989
+ this.promptController?.abort();
990
+ if (this.pendingPermission) this.resolvePermission("deny");
991
+ }
727
992
  async send() {
728
993
  const text = this.draft.trim();
729
994
  const attachmentIds = [...this.pendingAttachmentIds];
730
995
  if (!text && !attachmentIds.length || this.busy) return;
731
996
  this.applyPolicy();
732
- await this.clearComposer();
997
+ this.pendingAttachmentIds = [];
998
+ if (this.fileInput) this.fileInput.value = "";
999
+ const controller = new AbortController();
1000
+ this.promptController = controller;
733
1001
  this.busy = true;
734
1002
  this.streamingParts = [];
1003
+ this.startBusyStatus();
735
1004
  try {
736
1005
  await cognitiveRuntime.prompt({
737
1006
  sessionId: this.focusedId ?? void 0,
738
1007
  text,
739
- attachmentIds
1008
+ attachmentIds,
1009
+ signal: controller.signal
740
1010
  });
741
1011
  } finally {
1012
+ if (this.promptController === controller) this.promptController = null;
1013
+ this.stopBusyStatus();
742
1014
  this.busy = false;
1015
+ this.streamingParts = [];
1016
+ await this.clearComposer();
743
1017
  this.syncSessions();
744
1018
  this.scheduleScrollToBottom();
745
1019
  this.textarea?.focus();
@@ -786,6 +1060,15 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
786
1060
  `}
787
1061
  <span class="attach-name">${file.name}</span>
788
1062
  </button>
1063
+ <wa-button
1064
+ size="s"
1065
+ appearance="plain"
1066
+ title=${`Save ${file.name} to workspace folder`}
1067
+ ?disabled=${this.busy}
1068
+ @click=${() => void this.saveAttachmentToWorkspace(file.id)}
1069
+ >
1070
+ <wa-icon name="floppy-disk" label=${`Save ${file.name}`}></wa-icon>
1071
+ </wa-button>
789
1072
  <wa-button
790
1073
  size="s"
791
1074
  appearance="plain"
@@ -839,6 +1122,38 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
839
1122
  <wa-button variant="brand" @click=${() => this.closeAttachmentPreview()}>Close</wa-button>
840
1123
  </div>
841
1124
  </wa-dialog>
1125
+ `;
1126
+ }
1127
+ openToolDetail(part) {
1128
+ this.toolDetail = part;
1129
+ }
1130
+ closeToolDetail() {
1131
+ this.toolDetail = null;
1132
+ }
1133
+ renderToolDetailDialog() {
1134
+ const tool = this.toolDetail;
1135
+ if (!tool) return nothing;
1136
+ const label = `${tool.name} · ${tool.status}${tool.durationMs != null ? ` · ${tool.durationMs}ms` : ""}`;
1137
+ const body = JSON.stringify({
1138
+ args: tool.args ?? {},
1139
+ result: tool.result ?? null
1140
+ }, null, 2);
1141
+ return html`
1142
+ <wa-dialog
1143
+ label=${label}
1144
+ open
1145
+ light-dismiss
1146
+ with-footer
1147
+ style="--width: min(44rem, 96vw)"
1148
+ @wa-after-hide=${() => this.closeToolDetail()}
1149
+ >
1150
+ <div class="tool-detail-body">
1151
+ <pre>${body}</pre>
1152
+ </div>
1153
+ <div slot="footer">
1154
+ <wa-button variant="brand" @click=${() => this.closeToolDetail()}>Close</wa-button>
1155
+ </div>
1156
+ </wa-dialog>
842
1157
  `;
843
1158
  }
844
1159
  resolvePermission(action) {
@@ -878,7 +1193,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
878
1193
  const usage = this.contextUsage();
879
1194
  const canCompact = (this.focusedSession()?.history.length ?? 0) > 12;
880
1195
  const percentLabel = formatContextPercent(usage.percent);
881
- const title = `Context ${percentLabel} · ${formatTokenCount(usage.used)} / ${formatTokenCount(usage.limit)} tokens`;
1196
+ const title = `Context window ${percentLabel} · ~${formatTokenCount(usage.used)} / ${formatTokenCount(usage.limit)}`;
882
1197
  const ringValue = Math.min(100, Math.max(usage.percent, usage.used > 0 ? 1 : 0));
883
1198
  return html`
884
1199
  <wa-dropdown
@@ -907,7 +1222,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
907
1222
  @keydown=${(e) => e.stopPropagation()}
908
1223
  >
909
1224
  <div class="context-header">
910
- <strong>Context tokens</strong>
1225
+ <strong>Context window</strong>
911
1226
  <span>${percentLabel}</span>
912
1227
  </div>
913
1228
  <div class="context-bars">
@@ -928,10 +1243,26 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
928
1243
  </div>
929
1244
  <div class="context-footer">
930
1245
  <span class="context-remaining">
931
- ~${formatTokenCount(usage.used)} used · ${formatTokenCount(usage.remaining)} free of
1246
+ ~${formatTokenCount(usage.used)} in window · ${formatTokenCount(usage.remaining)} free of
932
1247
  ${formatTokenCount(usage.limit)}
933
1248
  · ${shortModelLabel(usage.modelRef)}
934
1249
  </span>
1250
+ </div>
1251
+ <div
1252
+ class="context-io"
1253
+ title="Sum of provider-reported tokens across every model request in this chat. Each tool-loop call re-sends the prompt, so API input grows much faster than the context window fill."
1254
+ >
1255
+ <div class="context-io-heading">API usage (this chat)</div>
1256
+ <div class="context-io-item">
1257
+ <span>Input</span>
1258
+ <strong>${usage.inputTokens ? formatTokenCount(usage.inputTokens) : "—"}</strong>
1259
+ </div>
1260
+ <div class="context-io-item">
1261
+ <span>Output</span>
1262
+ <strong>${usage.outputTokens ? formatTokenCount(usage.outputTokens) : "—"}</strong>
1263
+ </div>
1264
+ </div>
1265
+ <div class="context-footer">
935
1266
  <wa-button
936
1267
  size="s"
937
1268
  variant=${usage.level === "critical" ? "danger" : "neutral"}
@@ -975,16 +1306,27 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
975
1306
  <div class="composer">
976
1307
  <div class="composer-row">
977
1308
  <wa-textarea
978
- placeholder="Enter your message here..."
1309
+ placeholder=${this.busy ? this.busyStatus : "Enter your message here…"}
979
1310
  size="s"
980
1311
  resize="auto"
981
1312
  rows="1"
982
- .value=${this.draft}
1313
+ .value=${this.busy ? this.busyStatus : this.draft}
983
1314
  ?disabled=${this.busy}
1315
+ ?readonly=${this.busy}
984
1316
  @input=${(e) => {
1317
+ if (this.busy) return;
985
1318
  this.draft = e.target.value;
986
1319
  }}
987
1320
  @keydown=${(e) => {
1321
+ if (this.busy) {
1322
+ if (e.key === "Escape") {
1323
+ e.preventDefault();
1324
+ this.cancelTurn();
1325
+ return;
1326
+ }
1327
+ e.preventDefault();
1328
+ return;
1329
+ }
988
1330
  if (e.key === "Enter" && !e.shiftKey) {
989
1331
  e.preventDefault();
990
1332
  this.send();
@@ -992,6 +1334,17 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
992
1334
  }}
993
1335
  ></wa-textarea>
994
1336
  <div class="composer-actions">
1337
+ ${this.busy ? html`
1338
+ <wa-button
1339
+ size="s"
1340
+ appearance="plain"
1341
+ variant="danger"
1342
+ title="Stop (Esc)"
1343
+ @click=${() => this.cancelTurn()}
1344
+ >
1345
+ <wa-icon name="stop" label="Stop"></wa-icon>
1346
+ </wa-button>
1347
+ ` : nothing}
995
1348
  ${this.renderAttachmentDropdown()}
996
1349
  ${this.renderContextDropdown()}
997
1350
  </div>
@@ -999,6 +1352,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
999
1352
  </div>
1000
1353
  </div>
1001
1354
  ${this.renderAttachmentDialog()}
1355
+ ${this.renderToolDetailDialog()}
1002
1356
  </div>
1003
1357
  `;
1004
1358
  }
@@ -1130,6 +1484,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1130
1484
  }
1131
1485
  if (value.startsWith("effort:")) {
1132
1486
  this.manualEffort = value.slice(7) || "auto";
1487
+ this.applyPolicy();
1133
1488
  return;
1134
1489
  }
1135
1490
  this.onRouterSelect(value);
@@ -1177,7 +1532,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1177
1532
  <wa-dropdown-item
1178
1533
  value=${option.value}
1179
1534
  type="checkbox"
1180
- ?checked=${option.value === selected}
1535
+ .checked=${option.value === selected}
1181
1536
  >
1182
1537
  ${option.label}
1183
1538
  </wa-dropdown-item>
@@ -1189,7 +1544,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1189
1544
  <wa-dropdown-item
1190
1545
  value=${`model:${id}`}
1191
1546
  type="checkbox"
1192
- ?checked=${selected === `model:${id}`}
1547
+ .checked=${selected === `model:${id}`}
1193
1548
  >
1194
1549
  ${id}
1195
1550
  </wa-dropdown-item>
@@ -1202,7 +1557,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1202
1557
  <wa-dropdown-item
1203
1558
  value=${`effort:${level}`}
1204
1559
  type="checkbox"
1205
- ?checked=${this.manualEffort === level}
1560
+ .checked=${this.manualEffort === level}
1206
1561
  >
1207
1562
  ${level}
1208
1563
  </wa-dropdown-item>
@@ -1215,7 +1570,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1215
1570
  <wa-dropdown-item
1216
1571
  value=${`approval:${option.value}`}
1217
1572
  type="checkbox"
1218
- ?checked=${this.approvalMode === option.value}
1573
+ .checked=${this.approvalMode === option.value}
1219
1574
  >
1220
1575
  ${option.label}
1221
1576
  </wa-dropdown-item>
@@ -1268,18 +1623,18 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1268
1623
  return this.renderAssistantMessage(message);
1269
1624
  }
1270
1625
  renderAssistantMessage(message, opts = {}) {
1271
- const textParts = message.parts.filter((p) => p.type === "text");
1272
- const techParts = message.parts.filter((p) => p.type !== "text");
1626
+ const { summaryText, techParts } = splitAssistantPresentation(message.parts);
1273
1627
  const open = opts.streaming === true || techParts.some((p) => (p.type === "reasoning" || p.type === "tool") && p.status === "streaming");
1628
+ const summaryBubble = summaryText.length ? summaryText.map((p) => this.renderTextPart(p, { markdown: true })) : opts.streaming ? nothing : html`<div class="bubble">${technicalSummary(techParts)}</div>`;
1274
1629
  const summary = html`
1275
1630
  <div slot="summary" class="msg-summary">
1276
1631
  ${opts.streaming ? html`
1277
1632
  <div class="streaming-meta">
1278
1633
  <wa-spinner style="font-size: 0.85rem"></wa-spinner>
1279
- <span>streaming…</span>
1634
+ <span>${this.busy ? this.busyStatus : "streaming…"}</span>
1280
1635
  </div>
1281
1636
  ` : nothing}
1282
- ${textParts.length ? textParts.map((p) => this.renderTextPart(p)) : html`<div class="bubble">${technicalSummary(techParts)}</div>`}
1637
+ ${summaryBubble}
1283
1638
  </div>
1284
1639
  `;
1285
1640
  if (!techParts.length) return html`
@@ -1287,10 +1642,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1287
1642
  ${opts.streaming ? html`
1288
1643
  <div class="streaming-meta">
1289
1644
  <wa-spinner style="font-size: 0.85rem"></wa-spinner>
1290
- <span>streaming…</span>
1645
+ <span>${this.busy ? this.busyStatus : "streaming…"}</span>
1291
1646
  </div>
1292
1647
  ` : nothing}
1293
- ${textParts.map((p) => this.renderTextPart(p))}
1648
+ ${summaryBubble}
1294
1649
  ${message.id !== "streaming" ? this.renderMessageMeta(message) : nothing}
1295
1650
  </div>
1296
1651
  `;
@@ -1316,9 +1671,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1316
1671
  </div>
1317
1672
  `;
1318
1673
  }
1319
- renderTextPart(part) {
1320
- if (part.type === "text") return html`<div class="bubble">${part.text}</div>`;
1321
- return nothing;
1674
+ renderTextPart(part, opts = {}) {
1675
+ if (part.type !== "text") return nothing;
1676
+ if (opts.markdown) return html`<div class="bubble markdown">${unsafeHTML(parseMarkdownHtml(part.text))}</div>`;
1677
+ return html`<div class="bubble">${part.text}</div>`;
1322
1678
  }
1323
1679
  renderTechnicalPart(part) {
1324
1680
  if (part.type === "reasoning") return html`
@@ -1329,13 +1685,20 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1329
1685
  `;
1330
1686
  if (part.type === "tool") {
1331
1687
  const heading = `${part.name} · ${part.status}${part.durationMs != null ? ` · ${part.durationMs}ms` : ""}`;
1688
+ const hasDetail = part.args != null || part.result != null || part.status === "error";
1332
1689
  return html`
1333
- <div>
1690
+ <div class="tool-row">
1334
1691
  <div class="tool-heading">${heading}</div>
1335
- <pre class="args">${JSON.stringify({
1336
- args: part.args,
1337
- result: part.result
1338
- }, null, 2)}</pre>
1692
+ ${hasDetail ? html`
1693
+ <wa-button
1694
+ size="s"
1695
+ appearance="plain"
1696
+ variant="neutral"
1697
+ @click=${() => this.openToolDetail(part)}
1698
+ >
1699
+ Details
1700
+ </wa-button>
1701
+ ` : nothing}
1339
1702
  </div>
1340
1703
  `;
1341
1704
  }
@@ -1351,7 +1714,9 @@ _decorate([state()], DocksCognitiveView.prototype, "draft", void 0);
1351
1714
  _decorate([state()], DocksCognitiveView.prototype, "pendingAttachmentIds", void 0);
1352
1715
  _decorate([state()], DocksCognitiveView.prototype, "dragOver", void 0);
1353
1716
  _decorate([state()], DocksCognitiveView.prototype, "previewAttachmentId", void 0);
1717
+ _decorate([state()], DocksCognitiveView.prototype, "toolDetail", void 0);
1354
1718
  _decorate([state()], DocksCognitiveView.prototype, "busy", void 0);
1719
+ _decorate([state()], DocksCognitiveView.prototype, "busyStatus", void 0);
1355
1720
  _decorate([state()], DocksCognitiveView.prototype, "pendingPermission", void 0);
1356
1721
  _decorate([state()], DocksCognitiveView.prototype, "policyMode", void 0);
1357
1722
  _decorate([state()], DocksCognitiveView.prototype, "optimizeFor", void 0);
@@ -1364,14 +1729,14 @@ _decorate([state()], DocksCognitiveView.prototype, "historyOpen", void 0);
1364
1729
  _decorate([state()], DocksCognitiveView.prototype, "historyQuery", void 0);
1365
1730
  DocksCognitiveView = _decorate([customElement("docks-cognitive-view")], DocksCognitiveView);
1366
1731
  var APPROVAL_OPTIONS$1 = [
1367
- {
1368
- value: "manual",
1369
- label: "Manual"
1370
- },
1371
1732
  {
1372
1733
  value: "auto_safe",
1373
1734
  label: "Auto-approve non-critical"
1374
1735
  },
1736
+ {
1737
+ value: "manual",
1738
+ label: "Manual"
1739
+ },
1375
1740
  {
1376
1741
  value: "auto_all",
1377
1742
  label: "Approve all"
@@ -1380,15 +1745,64 @@ var APPROVAL_OPTIONS$1 = [
1380
1745
  function capitalize(value) {
1381
1746
  return value ? value[0].toUpperCase() + value.slice(1) : value;
1382
1747
  }
1748
+ /** Basename used when saving an attachment into a workspace folder. */
1749
+ function attachmentSaveFileName(attachment) {
1750
+ const fromName = attachment.name.trim().split(/[/\\]/).pop()?.trim();
1751
+ if (fromName) return fromName;
1752
+ const fromPath = attachment.path?.split(/[/\\]/).pop()?.trim();
1753
+ if (fromPath) return fromPath;
1754
+ if (attachment.kind === "image") return attachment.mime === "image/jpeg" ? "attachment.jpg" : "attachment.png";
1755
+ return "attachment.txt";
1756
+ }
1757
+ /** `photo.png` → `photo (1).png`, `photo (2).png`, … when the path is taken. */
1758
+ function withNumericSuffix(fileName, n) {
1759
+ const dot = fileName.lastIndexOf(".");
1760
+ if (dot > 0) return `${fileName.slice(0, dot)} (${n})${fileName.slice(dot)}`;
1761
+ return `${fileName} (${n})`;
1762
+ }
1763
+ async function uniqueWorkspaceFileName(workspace, parentPath, fileName) {
1764
+ const candidatePath = (name) => `${parentPath}/${name}`;
1765
+ if (!await workspace.getResource(candidatePath(fileName))) return fileName;
1766
+ for (let n = 1; n < 1e4; n++) {
1767
+ const next = withNumericSuffix(fileName, n);
1768
+ if (!await workspace.getResource(candidatePath(next))) return next;
1769
+ }
1770
+ return withNumericSuffix(fileName, Date.now());
1771
+ }
1772
+ /**
1773
+ * Prefer text after the last tool/reasoning as the visible reply.
1774
+ * Interim narration stays out of the bubble — tool details cover the execution trail.
1775
+ */
1776
+ function splitAssistantPresentation(parts) {
1777
+ const techParts = parts.filter((p) => p.type !== "text");
1778
+ let lastTechIndex = -1;
1779
+ for (let i = 0; i < parts.length; i++) if (parts[i].type !== "text") lastTechIndex = i;
1780
+ if (lastTechIndex < 0) return {
1781
+ summaryText: parts.filter((p) => p.type === "text"),
1782
+ techParts
1783
+ };
1784
+ const afterTools = parts.slice(lastTechIndex + 1).filter((p) => p.type === "text").filter((p) => p.text.trim());
1785
+ if (afterTools.length) return {
1786
+ summaryText: afterTools,
1787
+ techParts
1788
+ };
1789
+ return {
1790
+ summaryText: [],
1791
+ techParts
1792
+ };
1793
+ }
1383
1794
  function technicalSummary(parts) {
1384
1795
  const tools = parts.filter((p) => p.type === "tool");
1385
- const reasoning = parts.some((p) => p.type === "reasoning");
1386
- const steps = parts.filter((p) => p.type === "step");
1387
- const bits = [];
1388
- if (tools.length) bits.push(tools.map((t) => `${t.name} · ${t.status}${t.durationMs != null ? ` · ${t.durationMs}ms` : ""}`).join(", "));
1389
- if (reasoning) bits.push("Thinking");
1390
- if (steps.length) bits.push(`${steps.length} step${steps.length === 1 ? "" : "s"}`);
1391
- return bits.join(" · ") || "Details";
1796
+ const done = tools.filter((t) => t.status === "done").length;
1797
+ const errors = tools.filter((t) => t.status === "error").length;
1798
+ if (!tools.length) {
1799
+ if (parts.some((p) => p.type === "reasoning")) return "Thinking…";
1800
+ return "Details";
1801
+ }
1802
+ if (errors && done) return `Finished with ${errors} issue${errors === 1 ? "" : "s"} (${done} ok).`;
1803
+ if (errors) return `Couldn't complete ${errors} step${errors === 1 ? "" : "s"}.`;
1804
+ if (tools.some((t) => t.status === "running" || t.status === "preparing")) return "Working…";
1805
+ return done === 1 ? "Done." : `Done · ${done} steps.`;
1392
1806
  }
1393
1807
  function startOfDay(ts) {
1394
1808
  const d = new Date(ts);
@@ -1463,6 +1877,29 @@ function shortModelLabel(modelRef) {
1463
1877
  const slash = modelRef.indexOf("/");
1464
1878
  return slash === -1 ? modelRef : modelRef.slice(slash + 1);
1465
1879
  }
1880
+ function filesFromClipboard(data) {
1881
+ if (!data) return [];
1882
+ const fromFiles = [...data.files ?? []].filter((f) => f && f.size > 0);
1883
+ if (fromFiles.length) return fromFiles;
1884
+ const fromItems = [];
1885
+ for (const item of data.items ?? []) {
1886
+ if (item.kind !== "file") continue;
1887
+ const file = item.getAsFile();
1888
+ if (!file || file.size <= 0) continue;
1889
+ fromItems.push(nameClipboardFile(file, item.type));
1890
+ }
1891
+ return fromItems;
1892
+ }
1893
+ function nameClipboardFile(file, mimeHint) {
1894
+ const mime = (file.type || mimeHint || "application/octet-stream").toLowerCase();
1895
+ if (file.name && file.name !== "image.png" && file.name !== "blob") return file;
1896
+ const ext = mime === "image/jpeg" || mime === "image/jpg" ? "jpg" : mime === "image/png" ? "png" : mime === "image/gif" ? "gif" : mime === "image/webp" ? "webp" : mime === "image/svg+xml" ? "svg" : mime.startsWith("image/") ? "png" : "bin";
1897
+ const name = `clipboard-${Date.now()}.${ext}`;
1898
+ return new File([file], name, {
1899
+ type: mime || file.type,
1900
+ lastModified: file.lastModified
1901
+ });
1902
+ }
1466
1903
  function mergePart(parts, part) {
1467
1904
  const next = [...parts];
1468
1905
  const last = next[next.length - 1];
@@ -1491,16 +1928,16 @@ function mergePart(parts, part) {
1491
1928
  //#endregion
1492
1929
  //#region src/view/cognitive-settings-editor.ts
1493
1930
  var APPROVAL_OPTIONS = [
1494
- {
1495
- value: "manual",
1496
- label: "Manual",
1497
- hint: "Confirm every tool before it runs"
1498
- },
1499
1931
  {
1500
1932
  value: "auto_safe",
1501
1933
  label: "Auto-approve non-critical",
1502
1934
  hint: "The agent classifies each tool as safe or critical; only critical ones ask for approval"
1503
1935
  },
1936
+ {
1937
+ value: "manual",
1938
+ label: "Manual",
1939
+ hint: "Confirm every tool before it runs"
1940
+ },
1504
1941
  {
1505
1942
  value: "auto_all",
1506
1943
  label: "Approve all",
@@ -1711,59 +2148,15 @@ var DocksCognitiveSettingsEditor = class DocksCognitiveSettingsEditor extends Do
1711
2148
  toastError(err instanceof Error ? err.message : String(err));
1712
2149
  }
1713
2150
  }
1714
- renderToolbar() {
1715
- return html`
1716
- <wa-button size="s" appearance="plain" title="Add provider" @click=${() => this.addProvider()}>
1717
- <wa-icon name="plus" label="Add provider"></wa-icon>
1718
- </wa-button>
1719
- <wa-button
1720
- size="s"
1721
- variant="brand"
1722
- ?disabled=${!this.isDirty()}
1723
- @click=${() => void this.save()}
1724
- >
1725
- <wa-icon slot="start" name="floppy-disk"></wa-icon>
1726
- Save
1727
- </wa-button>
1728
- `;
1729
- }
1730
2151
  renderContent() {
1731
2152
  const rows = this.settings.providers;
1732
2153
  return html`
1733
2154
  <div class="editor">
1734
- <section class="section">
1735
- <header class="header">
1736
- <div>
1737
- <h2>Tool approvals</h2>
1738
- <p class="hint">How the agent handles tool confirmation — same options as GitHub Copilot.</p>
1739
- </div>
1740
- </header>
1741
- <wa-radio-group
1742
- name="approval-mode"
1743
- label="Approval mode"
1744
- orientation="vertical"
1745
- .value=${this.approvalMode}
1746
- @change=${(e) => {
1747
- const value = e.target.value;
1748
- if (value === "manual" || value === "auto_safe" || value === "auto_all") this.setApprovalMode(value);
1749
- }}
1750
- >
1751
- ${APPROVAL_OPTIONS.map((option) => html`
1752
- <wa-radio value=${option.value}>
1753
- <span class="approval-option">
1754
- <span class="approval-label">${option.label}</span>
1755
- <span class="approval-hint">${option.hint}</span>
1756
- </span>
1757
- </wa-radio>
1758
- `)}
1759
- </wa-radio-group>
1760
- </section>
1761
-
1762
2155
  <section class="section">
1763
2156
  <header class="header">
1764
2157
  <div>
1765
2158
  <h2>AI Providers</h2>
1766
- <p class="hint">OpenAI-compatible endpoints. Edit cells in place, then Save.</p>
2159
+ <p class="hint">OpenAI-compatible endpoints. Edit cells in place, then save from the toolbar.</p>
1767
2160
  </div>
1768
2161
  <wa-button size="s" variant="brand" appearance="filled" @click=${() => this.addProvider()}>
1769
2162
  <wa-icon slot="start" name="plus"></wa-icon>
@@ -1798,6 +2191,34 @@ var DocksCognitiveSettingsEditor = class DocksCognitiveSettingsEditor extends Do
1798
2191
  <code>providerId/modelId</code> for Auto routing.
1799
2192
  </wa-callout>
1800
2193
  </section>
2194
+
2195
+ <section class="section">
2196
+ <header class="header">
2197
+ <div>
2198
+ <h2>Tool approvals</h2>
2199
+ <p class="hint">How the agent handles tool confirmation — same options as GitHub Copilot.</p>
2200
+ </div>
2201
+ </header>
2202
+ <wa-radio-group
2203
+ name="approval-mode"
2204
+ label="Approval mode"
2205
+ orientation="vertical"
2206
+ .value=${this.approvalMode}
2207
+ @change=${(e) => {
2208
+ const value = e.target.value;
2209
+ if (value === "manual" || value === "auto_safe" || value === "auto_all") this.setApprovalMode(value);
2210
+ }}
2211
+ >
2212
+ ${APPROVAL_OPTIONS.map((option) => html`
2213
+ <wa-radio value=${option.value}>
2214
+ <span class="approval-option">
2215
+ <span class="approval-label">${option.label}</span>
2216
+ <span class="approval-hint">${option.hint}</span>
2217
+ </span>
2218
+ </wa-radio>
2219
+ `)}
2220
+ </wa-radio-group>
2221
+ </section>
1801
2222
  </div>
1802
2223
  `;
1803
2224
  }
@@ -2088,6 +2509,7 @@ function uniqueProviderId(existing) {
2088
2509
  //#endregion
2089
2510
  //#region src/cognitive-extension.ts
2090
2511
  cognitiveRuntime.start();
2512
+ registerSkillCommands();
2091
2513
  rootContext.put("cognitiveRuntime", cognitiveRuntime);
2092
2514
  contributionRegistry.registerContribution(SIDEBAR_AUXILIARY, {
2093
2515
  name: AI_VIEW_NAME,
@@ -2126,4 +2548,4 @@ registerAll({
2126
2548
  });
2127
2549
  //#endregion
2128
2550
 
2129
- //# sourceMappingURL=cognitive-extension-CG_d39K5.js.map
2551
+ //# sourceMappingURL=cognitive-extension-BKGxwLYj.js.map