@eclipse-docks/extension-ai-system 0.8.1 → 0.8.3

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 (44) hide show
  1. package/dist/api.d.ts +1 -1
  2. package/dist/api.d.ts.map +1 -1
  3. package/dist/api.js +87 -2
  4. package/dist/api.js.map +1 -0
  5. package/dist/{cognitive-extension-7_ZMUCGD.js → cognitive-extension-CvP05Bw_.js} +241 -36
  6. package/dist/cognitive-extension-CvP05Bw_.js.map +1 -0
  7. package/dist/cognitive-extension.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/runtime/cognitive-runtime.d.ts +5 -0
  10. package/dist/runtime/cognitive-runtime.d.ts.map +1 -1
  11. package/dist/runtime/context/usage.d.ts +3 -0
  12. package/dist/runtime/context/usage.d.ts.map +1 -1
  13. package/dist/runtime/index.d.ts +2 -0
  14. package/dist/runtime/index.d.ts.map +1 -1
  15. package/dist/runtime/models/openai-compatible.d.ts.map +1 -1
  16. package/dist/runtime/models/types.d.ts +6 -1
  17. package/dist/runtime/models/types.d.ts.map +1 -1
  18. package/dist/runtime/skills-commands.d.ts +3 -0
  19. package/dist/runtime/skills-commands.d.ts.map +1 -0
  20. package/dist/runtime/skills-parse.d.ts +14 -0
  21. package/dist/runtime/skills-parse.d.ts.map +1 -0
  22. package/dist/runtime/skills-resolve.d.ts +9 -0
  23. package/dist/runtime/skills-resolve.d.ts.map +1 -0
  24. package/dist/runtime/skills-select.d.ts +9 -0
  25. package/dist/runtime/skills-select.d.ts.map +1 -0
  26. package/dist/runtime/skills-types.d.ts +47 -0
  27. package/dist/runtime/skills-types.d.ts.map +1 -0
  28. package/dist/runtime/skills.d.ts +13 -0
  29. package/dist/runtime/skills.d.ts.map +1 -0
  30. package/dist/runtime/specialists/index.d.ts.map +1 -1
  31. package/dist/runtime/specialists/loop.d.ts.map +1 -1
  32. package/dist/runtime/tools/fetch-adapter.d.ts +4 -0
  33. package/dist/runtime/tools/fetch-adapter.d.ts.map +1 -0
  34. package/dist/runtime/tools/index.d.ts +1 -0
  35. package/dist/runtime/tools/index.d.ts.map +1 -1
  36. package/dist/runtime/types.d.ts +7 -0
  37. package/dist/runtime/types.d.ts.map +1 -1
  38. package/dist/{runtime-By5PP2BC.js → runtime-DVzLyx8h.js} +345 -16
  39. package/dist/runtime-DVzLyx8h.js.map +1 -0
  40. package/dist/view/cognitive-view.d.ts +5 -0
  41. package/dist/view/cognitive-view.d.ts.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/cognitive-extension-7_ZMUCGD.js.map +0 -1
  44. package/dist/runtime-By5PP2BC.js.map +0 -1
package/dist/api.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { cognitiveRuntime, CognitiveRuntime, TOPIC, AI_VIEW_NAME, AI_SETTINGS_KEY, AI_SETTINGS_EDITOR_ID, OPEN_AI_SETTINGS_COMMAND, defaultProvidersSettings, fetchOpenAICompatibleModels, listConfiguredModelIds, loadModelsCatalog, parseModelIds, OpenAICompatibleProvider, type ChatMessage, type MessagePart, type PromptAttachment, type SessionAttachment, type CognitiveSession, type Checkpoint, type ModelPolicy, type EffortLevel, type OptimizeFor, type SpecialistRole, type PermissionAction, type ToolApprovalMode, type EmotionalState, type ProviderConfig, type ProvidersSettings, type RemoteModelInfo, type ModelProvider, type StreamParams, type StreamChunk, type ProviderChatMessage, type SystemPromptEnhancer, } from './runtime';
1
+ export { cognitiveRuntime, CognitiveRuntime, TOPIC, AI_VIEW_NAME, AI_SETTINGS_KEY, AI_SETTINGS_EDITOR_ID, OPEN_AI_SETTINGS_COMMAND, defaultProvidersSettings, fetchOpenAICompatibleModels, listConfiguredModelIds, loadModelsCatalog, parseModelIds, OpenAICompatibleProvider, type ChatMessage, type MessagePart, type PromptAttachment, type SessionAttachment, type CognitiveSession, type Checkpoint, type ModelPolicy, type EffortLevel, type OptimizeFor, type SpecialistRole, type PermissionAction, type ToolApprovalMode, type TokenUsage, type EmotionalState, type ProviderConfig, type ProvidersSettings, type RemoteModelInfo, type ModelProvider, type StreamParams, type StreamChunk, type ProviderChatMessage, type SystemPromptEnhancer, type AgentSkill, type ResolvedSkill, type SkillContribution, type SkillLoadResult, type SkillRelevanceContext, SYSTEM_SKILLS, parseSkillMarkdown, formatSkillForPrompt, formatSkillsPromptSection, registerSkillMarkdown, registerSkillCommands, listSkillContributions, resolveSkill, resolveSkillBody, selectRelevantSkills, isSkillContribution, } from './runtime';
2
2
  //# sourceMappingURL=api.d.ts.map
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,KAAK,EACL,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,sBAAsB,EACtB,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,yBAAyB,EACzB,qBAAqB,EACrB,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,WAAW,CAAC"}
package/dist/api.js CHANGED
@@ -1,2 +1,87 @@
1
- import { _ as AI_SETTINGS_KEY, b as TOPIC, d as defaultProvidersSettings, f as listConfiguredModelIds, g as AI_SETTINGS_EDITOR_ID, h as loadModelsCatalog, l as OpenAICompatibleProvider, n as cognitiveRuntime, p as parseModelIds, t as CognitiveRuntime, u as fetchOpenAICompatibleModels, v as AI_VIEW_NAME, y as OPEN_AI_SETTINGS_COMMAND } from "./runtime-By5PP2BC.js";
2
- export { AI_SETTINGS_EDITOR_ID, AI_SETTINGS_KEY, AI_VIEW_NAME, CognitiveRuntime, OPEN_AI_SETTINGS_COMMAND, OpenAICompatibleProvider, TOPIC, cognitiveRuntime, defaultProvidersSettings, fetchOpenAICompatibleModels, listConfiguredModelIds, loadModelsCatalog, parseModelIds };
1
+ import { 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, a as listSkillContributions, b as defaultProvidersSettings, c as resolveSkillBody, d as parseSkillMarkdown, i as SYSTEM_SKILLS, k as TOPIC, l as isSkillContribution, n as CognitiveRuntime, o as registerSkillMarkdown, r as cognitiveRuntime, s as resolveSkill, t as registerSkillCommands, u as formatSkillForPrompt, v as OpenAICompatibleProvider, w as loadModelsCatalog, x as listConfiguredModelIds, y as fetchOpenAICompatibleModels } from "./runtime-DVzLyx8h.js";
2
+ //#region src/runtime/skills-select.ts
3
+ /**
4
+ * Catalog-only prompt section. The model loads full skill bodies via skills.load.
5
+ */
6
+ function formatSkillsPromptSection(skills) {
7
+ if (!skills.length) return "";
8
+ return ["Available skills (call skills.load with the skill name to load full instructions before relying on them):", skills.map((skill) => `- ${skill.name}: ${(skill.description ?? "").trim() || skill.label}`).join("\n")].join("\n");
9
+ }
10
+ /** @deprecated Prefer skills.load; kept for tests/helpers that still filter by goal. */
11
+ function selectRelevantSkills(skills, ctx) {
12
+ return skills.filter((skill) => {
13
+ if (skill.relevant) return skill.relevant(ctx);
14
+ return skillMatchesGoal(skill, ctx.goal);
15
+ });
16
+ }
17
+ var STOP_WORDS = /* @__PURE__ */ new Set([
18
+ "that",
19
+ "this",
20
+ "with",
21
+ "from",
22
+ "your",
23
+ "have",
24
+ "when",
25
+ "into",
26
+ "call",
27
+ "file",
28
+ "files",
29
+ "default",
30
+ "export",
31
+ "write",
32
+ "using",
33
+ "such",
34
+ "does",
35
+ "send",
36
+ "open",
37
+ "name",
38
+ "they",
39
+ "them",
40
+ "then",
41
+ "than",
42
+ "also",
43
+ "only",
44
+ "over",
45
+ "under",
46
+ "about",
47
+ "after",
48
+ "before",
49
+ "other",
50
+ "which",
51
+ "where",
52
+ "whose",
53
+ "their",
54
+ "there",
55
+ "these",
56
+ "those",
57
+ "and",
58
+ "for",
59
+ "the",
60
+ "a",
61
+ "an",
62
+ "to",
63
+ "of",
64
+ "in",
65
+ "on",
66
+ "or",
67
+ "by",
68
+ "is",
69
+ "are",
70
+ "be",
71
+ "as",
72
+ "at",
73
+ "it",
74
+ "do",
75
+ "not"
76
+ ]);
77
+ function skillMatchesGoal(skill, goal) {
78
+ const hay = goal.toLowerCase();
79
+ if (!hay.trim()) return false;
80
+ const tokens = `${skill.name} ${skill.label ?? ""} ${skill.description ?? ""}`.toLowerCase().split(/[^a-z0-9._-]+/).filter((token) => token.length >= 4 && !STOP_WORDS.has(token));
81
+ if (!tokens.length) return false;
82
+ return tokens.some((token) => hay.includes(token));
83
+ }
84
+ //#endregion
85
+ export { AI_SETTINGS_EDITOR_ID, AI_SETTINGS_KEY, AI_VIEW_NAME, CognitiveRuntime, OPEN_AI_SETTINGS_COMMAND, OpenAICompatibleProvider, SYSTEM_SKILLS, TOPIC, cognitiveRuntime, defaultProvidersSettings, fetchOpenAICompatibleModels, formatSkillForPrompt, formatSkillsPromptSection, isSkillContribution, listConfiguredModelIds, listSkillContributions, loadModelsCatalog, parseModelIds, parseSkillMarkdown, registerSkillCommands, registerSkillMarkdown, resolveSkill, resolveSkillBody, selectRelevantSkills };
86
+
87
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","names":[],"sources":["../src/runtime/skills-select.ts"],"sourcesContent":["import type { SkillContribution, SkillRelevanceContext } from './skills-types';\n\nexport type { SkillContribution, SkillRelevanceContext } from './skills-types';\n\n/**\n * Catalog-only prompt section. The model loads full skill bodies via skills.load.\n */\nexport function formatSkillsPromptSection(skills: SkillContribution[]): string {\n if (!skills.length) return '';\n const catalog = skills\n .map((skill) => `- ${skill.name}: ${(skill.description ?? '').trim() || skill.label}`)\n .join('\\n');\n return [\n 'Available skills (call skills.load with the skill name to load full instructions before relying on them):',\n catalog,\n ].join('\\n');\n}\n\n/** @deprecated Prefer skills.load; kept for tests/helpers that still filter by goal. */\nexport function selectRelevantSkills(\n skills: SkillContribution[],\n ctx: SkillRelevanceContext,\n): SkillContribution[] {\n return skills.filter((skill) => {\n if (skill.relevant) return skill.relevant(ctx);\n return skillMatchesGoal(skill, ctx.goal);\n });\n}\n\nconst STOP_WORDS = new Set([\n 'that',\n 'this',\n 'with',\n 'from',\n 'your',\n 'have',\n 'when',\n 'into',\n 'call',\n 'file',\n 'files',\n 'default',\n 'export',\n 'write',\n 'using',\n 'such',\n 'does',\n 'send',\n 'open',\n 'name',\n 'they',\n 'them',\n 'then',\n 'than',\n 'also',\n 'only',\n 'over',\n 'under',\n 'about',\n 'after',\n 'before',\n 'other',\n 'which',\n 'where',\n 'whose',\n 'their',\n 'there',\n 'these',\n 'those',\n 'and',\n 'for',\n 'the',\n 'a',\n 'an',\n 'to',\n 'of',\n 'in',\n 'on',\n 'or',\n 'by',\n 'is',\n 'are',\n 'be',\n 'as',\n 'at',\n 'it',\n 'do',\n 'not',\n]);\n\nfunction skillMatchesGoal(skill: SkillContribution, goal: string): boolean {\n const hay = goal.toLowerCase();\n if (!hay.trim()) return false;\n const tokens = `${skill.name} ${skill.label ?? ''} ${skill.description ?? ''}`\n .toLowerCase()\n .split(/[^a-z0-9._-]+/)\n .filter((token) => token.length >= 4 && !STOP_WORDS.has(token));\n if (!tokens.length) return false;\n return tokens.some((token) => hay.includes(token));\n}\n"],"mappings":";;;;;AAOA,SAAgB,0BAA0B,QAAqC;CAC7E,IAAI,CAAC,OAAO,QAAQ,OAAO;CAI3B,OAAO,CACL,6GAJc,OACb,KAAK,UAAU,KAAK,MAAM,KAAK,KAAK,MAAM,eAAe,GAAA,CAAI,KAAK,KAAK,MAAM,OAAO,CAAC,CACrF,KAAK,IAGN,CACF,CAAC,CAAC,KAAK,IAAI;AACb;;AAGA,SAAgB,qBACd,QACA,KACqB;CACrB,OAAO,OAAO,QAAQ,UAAU;EAC9B,IAAI,MAAM,UAAU,OAAO,MAAM,SAAS,GAAG;EAC7C,OAAO,iBAAiB,OAAO,IAAI,IAAI;CACzC,CAAC;AACH;AAEA,IAAM,6BAAa,IAAI,IAAI;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAED,SAAS,iBAAiB,OAA0B,MAAuB;CACzE,MAAM,MAAM,KAAK,YAAY;CAC7B,IAAI,CAAC,IAAI,KAAK,GAAG,OAAO;CACxB,MAAM,SAAS,GAAG,MAAM,KAAK,GAAG,MAAM,SAAS,GAAG,GAAG,MAAM,eAAe,KACvE,YAAY,CAAC,CACb,MAAM,eAAe,CAAC,CACtB,QAAQ,UAAU,MAAM,UAAU,KAAK,CAAC,WAAW,IAAI,KAAK,CAAC;CAChE,IAAI,CAAC,OAAO,QAAQ,OAAO;CAC3B,OAAO,OAAO,MAAM,UAAU,IAAI,SAAS,KAAK,CAAC;AACnD"}
@@ -1,6 +1,6 @@
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-By5PP2BC.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-DVzLyx8h.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
6
  //#region src/view/busy-status.ts
@@ -64,6 +64,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
64
64
  this.toolDetail = null;
65
65
  this.busy = false;
66
66
  this.busyStatus = INITIAL_BUSY_STATUS;
67
+ this.queuedPrompt = null;
67
68
  this.pendingPermission = null;
68
69
  this.policyMode = "auto";
69
70
  this.optimizeFor = "balance";
@@ -180,11 +181,21 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
180
181
  display: flex;
181
182
  flex-direction: column;
182
183
  gap: var(--wa-space-2xs);
183
- max-width: 100%;
184
+ width: 90%;
185
+ min-width: 90%;
186
+ max-width: 90%;
187
+ align-self: flex-start;
188
+ align-items: stretch;
184
189
  }
185
190
 
186
191
  .msg.user {
187
- align-items: flex-end;
192
+ align-self: flex-end;
193
+ }
194
+
195
+ .msg .bubble,
196
+ .msg wa-details.msg-details {
197
+ width: 100%;
198
+ box-sizing: border-box;
188
199
  }
189
200
 
190
201
  .msg-meta {
@@ -222,6 +233,39 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
222
233
  white-space: pre-wrap;
223
234
  line-height: var(--wa-line-height-normal);
224
235
  max-width: 100%;
236
+ overflow-wrap: anywhere;
237
+ }
238
+
239
+ .bubble.markdown {
240
+ white-space: normal;
241
+ }
242
+
243
+ .bubble.markdown > :first-child {
244
+ margin-block-start: 0;
245
+ }
246
+
247
+ .bubble.markdown > :last-child {
248
+ margin-block-end: 0;
249
+ }
250
+
251
+ .bubble.markdown pre {
252
+ overflow-x: auto;
253
+ padding: var(--wa-space-s);
254
+ border-radius: var(--wa-border-radius-m);
255
+ background: color-mix(in srgb, var(--wa-color-neutral-fill-quiet) 55%, transparent);
256
+ }
257
+
258
+ .bubble.markdown code {
259
+ font-family: var(--wa-font-family-code, ui-monospace, monospace);
260
+ font-size: 0.92em;
261
+ }
262
+
263
+ .bubble.markdown pre code {
264
+ font-size: inherit;
265
+ }
266
+
267
+ .bubble.markdown a {
268
+ color: var(--wa-color-brand-on-normal);
225
269
  }
226
270
 
227
271
  .msg.user .bubble {
@@ -318,6 +362,34 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
318
362
  background: var(--bucket-color, var(--wa-color-brand-fill-normal));
319
363
  }
320
364
 
365
+ .context-io {
366
+ display: grid;
367
+ grid-template-columns: 1fr 1fr;
368
+ gap: var(--wa-space-2xs);
369
+ padding-top: var(--wa-space-s);
370
+ border-top: var(--wa-border-width-s) solid var(--wa-color-border-normal);
371
+ font-size: var(--wa-font-size-xs);
372
+ }
373
+
374
+ .context-io-heading {
375
+ grid-column: 1 / -1;
376
+ font-weight: var(--wa-font-weight-semibold, 600);
377
+ }
378
+
379
+ .context-io-item {
380
+ display: flex;
381
+ flex-direction: column;
382
+ gap: 0.1rem;
383
+ }
384
+
385
+ .context-io-item span {
386
+ color: var(--wa-color-text-quiet);
387
+ }
388
+
389
+ .context-io-item strong {
390
+ font-variant-numeric: tabular-nums;
391
+ }
392
+
321
393
  .context-footer {
322
394
  display: flex;
323
395
  flex-direction: column;
@@ -337,6 +409,27 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
337
409
  min-width: 0;
338
410
  }
339
411
 
412
+ .queued-prompt {
413
+ display: flex;
414
+ align-items: center;
415
+ gap: var(--wa-space-2xs);
416
+ padding: var(--wa-space-2xs) var(--wa-space-s);
417
+ border-radius: var(--wa-border-radius-m);
418
+ border: var(--wa-border-width-s) solid var(--wa-color-border-normal);
419
+ background: color-mix(in srgb, var(--wa-color-brand-fill-quiet) 40%, transparent);
420
+ color: var(--wa-color-text-quiet);
421
+ font-size: var(--wa-font-size-s);
422
+ min-width: 0;
423
+ }
424
+
425
+ .queued-prompt-text {
426
+ flex: 1;
427
+ min-width: 0;
428
+ overflow: hidden;
429
+ text-overflow: ellipsis;
430
+ white-space: nowrap;
431
+ }
432
+
340
433
  .composer-row {
341
434
  display: flex;
342
435
  gap: var(--wa-space-s);
@@ -626,12 +719,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
626
719
  startBusyStatus() {
627
720
  this.stopBusyStatus();
628
721
  this.busyStatus = INITIAL_BUSY_STATUS;
629
- this.setComposerText(this.busyStatus);
630
722
  window.addEventListener("keydown", this.cancelKeyHandler);
631
723
  const schedule = () => {
632
724
  this.busyStatusTimer = setTimeout(() => {
633
725
  this.busyStatus = nextBusyStatus(this.busyStatus);
634
- this.setComposerText(this.busyStatus);
635
726
  schedule();
636
727
  }, busyStatusRotateMs());
637
728
  };
@@ -823,6 +914,40 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
823
914
  if (this.previewAttachmentId === attachmentId) this.previewAttachmentId = null;
824
915
  this.syncSessions();
825
916
  }
917
+ async saveAttachmentToWorkspace(attachmentId) {
918
+ const attachment = this.sessionAttachments().find((a) => a.id === attachmentId);
919
+ if (!attachment) return;
920
+ const preferredName = attachmentSaveFileName(attachment);
921
+ const parent = await filebrowserDialog("directory");
922
+ if (!parent) return;
923
+ try {
924
+ const workspace = await workspaceService.getWorkspace();
925
+ if (!workspace) {
926
+ toastError("No workspace connected");
927
+ return;
928
+ }
929
+ const parentPath = parent.replace(/\/$/, "");
930
+ const fileName = await uniqueWorkspaceFileName(workspace, parentPath, preferredName);
931
+ const path = `${parentPath}/${fileName}`;
932
+ const resource = await workspace.getResource(path, { create: true });
933
+ if (!(resource instanceof File$1)) {
934
+ toastError("Could not create file in the selected folder");
935
+ return;
936
+ }
937
+ if (attachment.dataUrl) {
938
+ const blob = await (await fetch(attachment.dataUrl)).blob();
939
+ const named = new globalThis.File([blob], fileName, { type: blob.type || attachment.mime || "" });
940
+ await resource.saveContents(named, { contentType: FileContentType.BINARY });
941
+ } else if (attachment.text != null) await resource.saveContents(attachment.text);
942
+ else {
943
+ toastError("Attachment has no payload to save");
944
+ return;
945
+ }
946
+ toastInfo(`Saved ${fileName}`);
947
+ } catch (err) {
948
+ toastError(err instanceof Error ? err.message : String(err));
949
+ }
950
+ }
826
951
  async addFiles(fileList) {
827
952
  const files = [...fileList];
828
953
  if (!files.length) return;
@@ -870,10 +995,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
870
995
  }
871
996
  /** Attach clipboard files/images (e.g. Ctrl+V screenshot) when focused in the prompt. */
872
997
  async onComposerPaste(e) {
873
- if (this.busy) {
874
- e.preventDefault();
875
- return;
876
- }
877
998
  const files = filesFromClipboard(e.clipboardData);
878
999
  if (!files.length) return;
879
1000
  e.preventDefault();
@@ -884,13 +1005,30 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
884
1005
  this.promptController?.abort();
885
1006
  if (this.pendingPermission) this.resolvePermission("deny");
886
1007
  }
1008
+ clearQueuedPrompt() {
1009
+ this.queuedPrompt = null;
1010
+ }
1011
+ async queueFollowUp(text, attachmentIds) {
1012
+ this.queuedPrompt = {
1013
+ text,
1014
+ attachmentIds
1015
+ };
1016
+ this.pendingAttachmentIds = [];
1017
+ if (this.fileInput) this.fileInput.value = "";
1018
+ await this.setComposerText("");
1019
+ }
887
1020
  async send() {
888
1021
  const text = this.draft.trim();
889
1022
  const attachmentIds = [...this.pendingAttachmentIds];
890
- if (!text && !attachmentIds.length || this.busy) return;
1023
+ if (!text && !attachmentIds.length) return;
1024
+ if (this.busy) {
1025
+ await this.queueFollowUp(text, attachmentIds);
1026
+ return;
1027
+ }
891
1028
  this.applyPolicy();
892
1029
  this.pendingAttachmentIds = [];
893
1030
  if (this.fileInput) this.fileInput.value = "";
1031
+ await this.setComposerText("");
894
1032
  const controller = new AbortController();
895
1033
  this.promptController = controller;
896
1034
  this.busy = true;
@@ -908,9 +1046,18 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
908
1046
  this.stopBusyStatus();
909
1047
  this.busy = false;
910
1048
  this.streamingParts = [];
911
- await this.clearComposer();
912
1049
  this.syncSessions();
913
1050
  this.scheduleScrollToBottom();
1051
+ const next = this.queuedPrompt;
1052
+ this.queuedPrompt = null;
1053
+ if (next && (next.text.trim() || next.attachmentIds.length)) {
1054
+ this.draft = next.text;
1055
+ this.pendingAttachmentIds = next.attachmentIds;
1056
+ await this.updateComplete;
1057
+ if (this.textarea) this.textarea.value = next.text;
1058
+ await this.send();
1059
+ return;
1060
+ }
914
1061
  this.textarea?.focus();
915
1062
  }
916
1063
  }
@@ -924,7 +1071,6 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
924
1071
  size="s"
925
1072
  appearance="plain"
926
1073
  title=${count ? `${count} attachment${count === 1 ? "" : "s"}` : "Attachments"}
927
- ?disabled=${this.busy}
928
1074
  >
929
1075
  <wa-icon name="paperclip" label="Attachments"></wa-icon>
930
1076
  ${count > 0 ? html`<wa-badge pill>${count}</wa-badge>` : nothing}
@@ -955,11 +1101,18 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
955
1101
  `}
956
1102
  <span class="attach-name">${file.name}</span>
957
1103
  </button>
1104
+ <wa-button
1105
+ size="s"
1106
+ appearance="plain"
1107
+ title=${`Save ${file.name} to workspace folder`}
1108
+ @click=${() => void this.saveAttachmentToWorkspace(file.id)}
1109
+ >
1110
+ <wa-icon name="floppy-disk" label=${`Save ${file.name}`}></wa-icon>
1111
+ </wa-button>
958
1112
  <wa-button
959
1113
  size="s"
960
1114
  appearance="plain"
961
1115
  title="Remove from session"
962
- ?disabled=${this.busy}
963
1116
  @click=${() => this.removeSessionAttachment(file.id)}
964
1117
  >
965
1118
  <wa-icon name="xmark" label="Remove"></wa-icon>
@@ -971,7 +1124,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
971
1124
  <wa-button
972
1125
  size="s"
973
1126
  appearance="outlined"
974
- ?disabled=${this.busy || count >= 8}
1127
+ ?disabled=${count >= 8}
975
1128
  @click=${() => this.openFilePicker()}
976
1129
  >
977
1130
  <wa-icon slot="start" name="plus"></wa-icon>
@@ -1079,7 +1232,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1079
1232
  const usage = this.contextUsage();
1080
1233
  const canCompact = (this.focusedSession()?.history.length ?? 0) > 12;
1081
1234
  const percentLabel = formatContextPercent(usage.percent);
1082
- const title = `Context ${percentLabel} · ${formatTokenCount(usage.used)} / ${formatTokenCount(usage.limit)} tokens`;
1235
+ const title = `Context window ${percentLabel} · ~${formatTokenCount(usage.used)} / ${formatTokenCount(usage.limit)}`;
1083
1236
  const ringValue = Math.min(100, Math.max(usage.percent, usage.used > 0 ? 1 : 0));
1084
1237
  return html`
1085
1238
  <wa-dropdown
@@ -1108,7 +1261,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1108
1261
  @keydown=${(e) => e.stopPropagation()}
1109
1262
  >
1110
1263
  <div class="context-header">
1111
- <strong>Context tokens</strong>
1264
+ <strong>Context window</strong>
1112
1265
  <span>${percentLabel}</span>
1113
1266
  </div>
1114
1267
  <div class="context-bars">
@@ -1129,10 +1282,26 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1129
1282
  </div>
1130
1283
  <div class="context-footer">
1131
1284
  <span class="context-remaining">
1132
- ~${formatTokenCount(usage.used)} used · ${formatTokenCount(usage.remaining)} free of
1285
+ ~${formatTokenCount(usage.used)} in window · ${formatTokenCount(usage.remaining)} free of
1133
1286
  ${formatTokenCount(usage.limit)}
1134
1287
  · ${shortModelLabel(usage.modelRef)}
1135
1288
  </span>
1289
+ </div>
1290
+ <div
1291
+ class="context-io"
1292
+ 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."
1293
+ >
1294
+ <div class="context-io-heading">API usage (this chat)</div>
1295
+ <div class="context-io-item">
1296
+ <span>Input</span>
1297
+ <strong>${usage.inputTokens ? formatTokenCount(usage.inputTokens) : "—"}</strong>
1298
+ </div>
1299
+ <div class="context-io-item">
1300
+ <span>Output</span>
1301
+ <strong>${usage.outputTokens ? formatTokenCount(usage.outputTokens) : "—"}</strong>
1302
+ </div>
1303
+ </div>
1304
+ <div class="context-footer">
1136
1305
  <wa-button
1137
1306
  size="s"
1138
1307
  variant=${usage.level === "critical" ? "danger" : "neutral"}
@@ -1174,27 +1343,36 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1174
1343
  @change=${(e) => void this.onFileInputChange(e)}
1175
1344
  />
1176
1345
  <div class="composer">
1346
+ ${this.queuedPrompt ? html`
1347
+ <div class="queued-prompt" title="Sends automatically when the current turn finishes">
1348
+ <wa-icon name="clock"></wa-icon>
1349
+ <span class="queued-prompt-text">
1350
+ Queued: ${this.queuedPrompt.text.trim() || `(${this.queuedPrompt.attachmentIds.length} attachment${this.queuedPrompt.attachmentIds.length === 1 ? "" : "s"})`}
1351
+ </span>
1352
+ <wa-button
1353
+ size="s"
1354
+ appearance="plain"
1355
+ title="Remove queued follow-up"
1356
+ @click=${() => this.clearQueuedPrompt()}
1357
+ >
1358
+ <wa-icon name="xmark" label="Remove queue"></wa-icon>
1359
+ </wa-button>
1360
+ </div>
1361
+ ` : nothing}
1177
1362
  <div class="composer-row">
1178
1363
  <wa-textarea
1179
- placeholder=${this.busy ? this.busyStatus : "Enter your message here…"}
1364
+ placeholder=${this.busy ? "Add a follow-up…" : "Enter your message here…"}
1180
1365
  size="s"
1181
1366
  resize="auto"
1182
1367
  rows="1"
1183
- .value=${this.busy ? this.busyStatus : this.draft}
1184
- ?disabled=${this.busy}
1185
- ?readonly=${this.busy}
1368
+ .value=${this.draft}
1186
1369
  @input=${(e) => {
1187
- if (this.busy) return;
1188
1370
  this.draft = e.target.value;
1189
1371
  }}
1190
1372
  @keydown=${(e) => {
1191
- if (this.busy) {
1192
- if (e.key === "Escape") {
1193
- e.preventDefault();
1194
- this.cancelTurn();
1195
- return;
1196
- }
1373
+ if (e.key === "Escape" && this.busy) {
1197
1374
  e.preventDefault();
1375
+ this.cancelTurn();
1198
1376
  return;
1199
1377
  }
1200
1378
  if (e.key === "Enter" && !e.shiftKey) {
@@ -1227,7 +1405,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1227
1405
  `;
1228
1406
  }
1229
1407
  renderTranscript(session) {
1230
- const showStreaming = this.streamingParts.length > 0;
1408
+ const showStreaming = this.busy || this.streamingParts.length > 0;
1231
1409
  const showPermission = this.pendingPermission && this.pendingPermission.sessionId === session.id;
1232
1410
  return html`
1233
1411
  ${session.history.map((m) => this.renderMessage(m))}
@@ -1495,7 +1673,7 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1495
1673
  renderAssistantMessage(message, opts = {}) {
1496
1674
  const { summaryText, techParts } = splitAssistantPresentation(message.parts);
1497
1675
  const open = opts.streaming === true || techParts.some((p) => (p.type === "reasoning" || p.type === "tool") && p.status === "streaming");
1498
- const summaryBubble = summaryText.length ? summaryText.map((p) => this.renderTextPart(p)) : html`<div class="bubble">${technicalSummary(techParts)}</div>`;
1676
+ const summaryBubble = summaryText.length ? summaryText.map((p) => this.renderTextPart(p, { markdown: true })) : opts.streaming ? nothing : html`<div class="bubble">${technicalSummary(techParts)}</div>`;
1499
1677
  const summary = html`
1500
1678
  <div slot="summary" class="msg-summary">
1501
1679
  ${opts.streaming ? html`
@@ -1541,9 +1719,10 @@ var DocksCognitiveView = class DocksCognitiveView extends DocksPart {
1541
1719
  </div>
1542
1720
  `;
1543
1721
  }
1544
- renderTextPart(part) {
1545
- if (part.type === "text") return html`<div class="bubble">${part.text}</div>`;
1546
- return nothing;
1722
+ renderTextPart(part, opts = {}) {
1723
+ if (part.type !== "text") return nothing;
1724
+ if (opts.markdown) return html`<div class="bubble markdown">${unsafeHTML(parseMarkdownHtml(part.text))}</div>`;
1725
+ return html`<div class="bubble">${part.text}</div>`;
1547
1726
  }
1548
1727
  renderTechnicalPart(part) {
1549
1728
  if (part.type === "reasoning") return html`
@@ -1586,6 +1765,7 @@ _decorate([state()], DocksCognitiveView.prototype, "previewAttachmentId", void 0
1586
1765
  _decorate([state()], DocksCognitiveView.prototype, "toolDetail", void 0);
1587
1766
  _decorate([state()], DocksCognitiveView.prototype, "busy", void 0);
1588
1767
  _decorate([state()], DocksCognitiveView.prototype, "busyStatus", void 0);
1768
+ _decorate([state()], DocksCognitiveView.prototype, "queuedPrompt", void 0);
1589
1769
  _decorate([state()], DocksCognitiveView.prototype, "pendingPermission", void 0);
1590
1770
  _decorate([state()], DocksCognitiveView.prototype, "policyMode", void 0);
1591
1771
  _decorate([state()], DocksCognitiveView.prototype, "optimizeFor", void 0);
@@ -1614,6 +1794,30 @@ var APPROVAL_OPTIONS$1 = [
1614
1794
  function capitalize(value) {
1615
1795
  return value ? value[0].toUpperCase() + value.slice(1) : value;
1616
1796
  }
1797
+ /** Basename used when saving an attachment into a workspace folder. */
1798
+ function attachmentSaveFileName(attachment) {
1799
+ const fromName = attachment.name.trim().split(/[/\\]/).pop()?.trim();
1800
+ if (fromName) return fromName;
1801
+ const fromPath = attachment.path?.split(/[/\\]/).pop()?.trim();
1802
+ if (fromPath) return fromPath;
1803
+ if (attachment.kind === "image") return attachment.mime === "image/jpeg" ? "attachment.jpg" : "attachment.png";
1804
+ return "attachment.txt";
1805
+ }
1806
+ /** `photo.png` → `photo (1).png`, `photo (2).png`, … when the path is taken. */
1807
+ function withNumericSuffix(fileName, n) {
1808
+ const dot = fileName.lastIndexOf(".");
1809
+ if (dot > 0) return `${fileName.slice(0, dot)} (${n})${fileName.slice(dot)}`;
1810
+ return `${fileName} (${n})`;
1811
+ }
1812
+ async function uniqueWorkspaceFileName(workspace, parentPath, fileName) {
1813
+ const candidatePath = (name) => `${parentPath}/${name}`;
1814
+ if (!await workspace.getResource(candidatePath(fileName))) return fileName;
1815
+ for (let n = 1; n < 1e4; n++) {
1816
+ const next = withNumericSuffix(fileName, n);
1817
+ if (!await workspace.getResource(candidatePath(next))) return next;
1818
+ }
1819
+ return withNumericSuffix(fileName, Date.now());
1820
+ }
1617
1821
  /**
1618
1822
  * Prefer text after the last tool/reasoning as the visible reply.
1619
1823
  * Interim narration stays out of the bubble — tool details cover the execution trail.
@@ -2354,6 +2558,7 @@ function uniqueProviderId(existing) {
2354
2558
  //#endregion
2355
2559
  //#region src/cognitive-extension.ts
2356
2560
  cognitiveRuntime.start();
2561
+ registerSkillCommands();
2357
2562
  rootContext.put("cognitiveRuntime", cognitiveRuntime);
2358
2563
  contributionRegistry.registerContribution(SIDEBAR_AUXILIARY, {
2359
2564
  name: AI_VIEW_NAME,
@@ -2392,4 +2597,4 @@ registerAll({
2392
2597
  });
2393
2598
  //#endregion
2394
2599
 
2395
- //# sourceMappingURL=cognitive-extension-7_ZMUCGD.js.map
2600
+ //# sourceMappingURL=cognitive-extension-CvP05Bw_.js.map