@eclipse-docks/extension-howto-system 0.8.12 → 0.8.14

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.
@@ -1,11 +1,9 @@
1
1
  import { DocksWidget, File, TOOLBAR_BOTTOM_END, TOPIC_CONTRIBUTEIONS_CHANGED, TOPIC_WORKSPACE_CHANGED, TOPIC_WORKSPACE_CONNECTED, activeEditorSignal, appLoaderService, appSettings, commandRegistry, contributionRegistry, createLogger, partDirtySignal, publish, registerAll, rootContext, subscribe, toastError, unsubscribe, watchSignal, workspaceService } from "@eclipse-docks/core";
2
2
  import { AI_SETTINGS_KEY, OPEN_AI_SETTINGS_COMMAND, TOPIC, cognitiveRuntime } from "@eclipse-docks/extension-ai-system/api";
3
3
  import { css, html, nothing } from "lit";
4
- import { customElement, state } from "lit/decorators.js";
5
- import { styleMap } from "lit/directives/style-map.js";
6
- import { createRef, ref } from "lit/directives/ref.js";
4
+ import { customElement, query, state } from "lit/decorators.js";
7
5
  import _decorate from "@oxc-project/runtime/helpers/decorate";
8
- //#region src/howto-service.ts
6
+ // src/howto-service.ts
9
7
  var logger$1 = createLogger("HowToService");
10
8
  var HOWTO_CONTRIBUTION_TARGET = "system.howtos";
11
9
  /**
@@ -89,8 +87,7 @@ var HowToService = class {
89
87
  }
90
88
  };
91
89
  var howToService = new HowToService();
92
- //#endregion
93
- //#region src/contributions/onboarding-howto-contributions.ts
90
+ // src/contributions/onboarding-howto-contributions.ts
94
91
  var ONBOARDING_FILE_NAME = "welcome.txt";
95
92
  async function getOnboardingFilePath() {
96
93
  if (!await workspaceService.getWorkspace()) return null;
@@ -237,8 +234,7 @@ contributionRegistry.registerContribution(HOWTO_CONTRIBUTION_TARGET, {
237
234
  }
238
235
  ]
239
236
  });
240
- //#endregion
241
- //#region src/contributions/ai-setup-howto-contributions.ts
237
+ // src/contributions/ai-setup-howto-contributions.ts
242
238
  function isAIConfigEditorOpen() {
243
239
  const activeEditor = activeEditorSignal.get();
244
240
  if (!activeEditor) return false;
@@ -336,76 +332,17 @@ var aiSetupContribution = {
336
332
  ]
337
333
  };
338
334
  contributionRegistry.registerContribution(HOWTO_CONTRIBUTION_TARGET, aiSetupContribution);
339
- //#endregion
340
- //#region src/howto-panel.ts
335
+ // src/howto-panel.ts
341
336
  var TOPIC_SHOW_HOWTO_PANEL = "howto/show-panel";
342
337
  var TOPIC_TOGGLE_HOWTO_PANEL = "howto/toggle-panel";
343
338
  var SETTINGS_KEY = "howto-panel";
344
- var DEFAULT_POSITION = {
345
- x: 100,
346
- y: 100
347
- };
348
- var DEFAULT_PANEL_SIZE = {
349
- width: 400,
350
- height: 300
351
- };
352
339
  var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
353
340
  constructor(..._args) {
354
341
  super(..._args);
355
342
  this.contributions = [];
356
343
  this.activeContributionId = null;
357
344
  this.stepStates = /* @__PURE__ */ new Map();
358
- this.isMinimized = false;
359
345
  this.isVisible = false;
360
- this.positionX = DEFAULT_POSITION.x;
361
- this.positionY = DEFAULT_POSITION.y;
362
- this.isDragging = false;
363
- this.dragPreviewPosition = null;
364
- this.dragStartPosition = {
365
- x: 0,
366
- y: 0
367
- };
368
- this.panelRef = createRef();
369
- this.handleDragStart = (e) => {
370
- const target = e.target;
371
- if (this.isDragTarget(target) || !this.panelRef.value) return;
372
- const rect = this.panelRef.value.getBoundingClientRect();
373
- this.dragStartPosition = {
374
- x: e.clientX - rect.left,
375
- y: e.clientY - rect.top
376
- };
377
- this.isDragging = true;
378
- this.dragPreviewPosition = {
379
- x: this.positionX,
380
- y: this.positionY
381
- };
382
- this.requestUpdate();
383
- e.preventDefault();
384
- e.stopPropagation();
385
- };
386
- this.handleDragMove = (e) => {
387
- if (!this.isDragging || !this.dragPreviewPosition) return;
388
- const bounds = this.getViewportBounds();
389
- const newX = Math.max(0, Math.min(e.clientX - this.dragStartPosition.x, bounds.maxX));
390
- const newY = Math.max(0, Math.min(e.clientY - this.dragStartPosition.y, bounds.maxY));
391
- if (this.dragPreviewPosition.x !== newX || this.dragPreviewPosition.y !== newY) {
392
- this.dragPreviewPosition = {
393
- x: newX,
394
- y: newY
395
- };
396
- this.requestUpdate();
397
- }
398
- };
399
- this.handleDragEnd = async () => {
400
- if (!this.isDragging || !this.dragPreviewPosition) return;
401
- this.isDragging = false;
402
- const previewPos = this.dragPreviewPosition;
403
- this.dragPreviewPosition = null;
404
- this.positionX = previewPos.x;
405
- this.positionY = previewPos.y;
406
- await this.saveSettings();
407
- this.requestUpdate();
408
- };
409
346
  }
410
347
  async doBeforeUI() {
411
348
  this.loadContributions();
@@ -433,47 +370,24 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
433
370
  checkAutoHide();
434
371
  });
435
372
  }
436
- doInitUI() {
437
- this.boundHandleDragMove = this.handleDragMove.bind(this);
438
- this.boundHandleDragEnd = this.handleDragEnd.bind(this);
439
- document.addEventListener("mousemove", this.boundHandleDragMove);
440
- document.addEventListener("mouseup", this.boundHandleDragEnd);
441
- }
442
- firstUpdated(_changedProperties) {
443
- super.firstUpdated(_changedProperties);
444
- }
445
373
  loadContributions() {
446
374
  this.contributions = howToService.getAllContributions();
447
375
  }
448
376
  async loadSettings() {
449
377
  const settings = await appSettings.getDialogSetting(SETTINGS_KEY);
450
- if (settings) {
451
- if (settings.position) {
452
- this.positionX = settings.position.x || DEFAULT_POSITION.x;
453
- this.positionY = settings.position.y || DEFAULT_POSITION.y;
454
- }
455
- if (settings.visible !== void 0) this.isVisible = settings.visible;
456
- }
378
+ if (settings && settings.visible !== void 0) this.isVisible = settings.visible;
457
379
  }
458
380
  async saveSettings() {
381
+ const current = await appSettings.getDialogSetting(SETTINGS_KEY);
382
+ const base = current !== null && typeof current === "object" ? current : {};
459
383
  await appSettings.setDialogSetting(SETTINGS_KEY, {
460
- position: {
461
- x: this.positionX,
462
- y: this.positionY
463
- },
384
+ ...base,
464
385
  visible: this.isVisible
465
386
  });
466
387
  }
467
- isDragTarget(target) {
468
- return !!(target.closest(".header-actions") || target.closest("wa-button"));
469
- }
470
- getViewportBounds() {
471
- const panelWidth = this.panelRef.value?.offsetWidth || DEFAULT_PANEL_SIZE.width;
472
- const panelHeight = this.panelRef.value?.offsetHeight || DEFAULT_PANEL_SIZE.height;
473
- return {
474
- maxX: window.innerWidth - panelWidth,
475
- maxY: window.innerHeight - panelHeight
476
- };
388
+ expandPanel() {
389
+ if (!this.floatingPanel) return;
390
+ this.floatingPanel.minimized = false;
477
391
  }
478
392
  async startHowTo(contributionId) {
479
393
  const contribution = howToService.getContribution(contributionId);
@@ -483,7 +397,7 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
483
397
  }
484
398
  this.cleanupHowTo();
485
399
  this.activeContributionId = contributionId;
486
- this.isMinimized = false;
400
+ this.expandPanel();
487
401
  const states = contribution.steps.map((step) => ({
488
402
  step,
489
403
  status: "pending"
@@ -642,15 +556,12 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
642
556
  this.stepStates.clear();
643
557
  this.requestUpdate();
644
558
  }
645
- toggleMinimize() {
646
- this.isMinimized = !this.isMinimized;
647
- this.requestUpdate();
648
- }
649
559
  async showPanel() {
650
560
  this.isVisible = true;
651
- this.isMinimized = false;
652
561
  await this.saveSettings();
653
562
  this.requestUpdate();
563
+ await this.updateComplete;
564
+ this.expandPanel();
654
565
  }
655
566
  async hidePanel() {
656
567
  this.isVisible = false;
@@ -723,54 +634,14 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
723
634
  const activeContribution = this.activeContributionId ? howToService.getContribution(this.activeContributionId) : null;
724
635
  const activeStepStates = this.activeContributionId ? this.stepStates.get(this.activeContributionId) || [] : [];
725
636
  return html`
726
- ${this.dragPreviewPosition ? html`
727
- <div
728
- class="howto-panel-drag-preview"
729
- style=${styleMap({
730
- left: `${this.dragPreviewPosition.x}px`,
731
- top: `${this.dragPreviewPosition.y}px`,
732
- width: `${this.panelRef.value?.offsetWidth || DEFAULT_PANEL_SIZE.width}px`,
733
- height: `${this.panelRef.value?.offsetHeight || DEFAULT_PANEL_SIZE.height}px`,
734
- display: "block",
735
- visibility: "visible"
736
- })}
737
- ></div>
738
- ` : nothing}
739
- <div
740
- class="howto-panel ${this.isMinimized ? "minimized" : ""} ${this.dragPreviewPosition ? "dragging" : ""}"
741
- style=${styleMap({
742
- left: `${this.positionX}px`,
743
- top: `${this.positionY}px`,
744
- transform: "translateZ(0)"
745
- })}
746
- ${ref(this.panelRef)}
637
+ <docks-floating-panel
638
+ label="HowTo Workflows"
639
+ icon="list-check"
640
+ .persistKey=${SETTINGS_KEY}
641
+ @floating-close=${() => {
642
+ this.hidePanel();
643
+ }}
747
644
  >
748
- <div class="panel-header" @mousedown=${this.handleDragStart}>
749
- <div class="header-title">
750
- <wa-icon name="list-check"></wa-icon>
751
- <span>HowTo Workflows</span>
752
- </div>
753
- <div class="header-actions" @mousedown=${(e) => e.stopPropagation()}>
754
- <wa-button
755
- size="s"
756
- appearance="plain"
757
- @click=${this.toggleMinimize}
758
- title="${this.isMinimized ? "Expand" : "Minimize"}"
759
- >
760
- <wa-icon name="${this.isMinimized ? "chevron-up" : "chevron-down"}"></wa-icon>
761
- </wa-button>
762
- <wa-button
763
- size="s"
764
- appearance="plain"
765
- @click=${this.hidePanel}
766
- title="Hide Panel"
767
- >
768
- <wa-icon name="xmark"></wa-icon>
769
- </wa-button>
770
- </div>
771
- </div>
772
-
773
- ${!this.isMinimized ? html`
774
645
  <div class="panel-content">
775
646
  ${activeContribution ? html`
776
647
  <div class="active-workflow">
@@ -826,102 +697,19 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
826
697
  </div>
827
698
  `}
828
699
  </div>
829
- ` : nothing}
830
- </div>
700
+ </docks-floating-panel>
831
701
  `;
832
702
  }
833
703
  static {
834
704
  this.styles = css`
835
705
  :host {
836
- display: block;
837
- position: fixed;
838
- z-index: 10000;
839
- pointer-events: none;
706
+ display: contents;
840
707
  }
841
708
 
842
- .howto-panel-drag-preview {
843
- position: fixed !important;
844
- border: 3px dashed var(--wa-color-primary-50, #0066cc) !important;
845
- background: var(--wa-color-primary-05, rgba(0, 102, 204, 0.05)) !important;
846
- border-radius: var(--wa-border-radius-medium, 8px);
847
- z-index: 10001 !important;
848
- pointer-events: none !important;
849
- opacity: 0.8 !important;
850
- box-sizing: border-box;
851
- display: block !important;
852
- visibility: visible !important;
853
- min-width: 100px;
854
- min-height: 100px;
855
- }
856
-
857
- :host-context(.wa-light) .howto-panel-drag-preview {
858
- background: var(--wa-color-primary-95);
859
- border-color: var(--wa-color-primary-50);
860
- }
861
-
862
- .howto-panel {
863
- position: fixed !important;
709
+ .panel-content {
864
710
  width: 400px;
865
711
  max-height: 600px;
866
- background: var(--wa-color-surface-raised, var(--wa-color-neutral-05));
867
- border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-loud, var(--wa-color-neutral-25));
868
- border-radius: var(--wa-border-radius-medium, 8px);
869
- box-shadow: var(--wa-shadow-large, 0 8px 24px rgba(0, 0, 0, 0.8));
870
- pointer-events: all;
871
- display: flex;
872
- flex-direction: column;
873
- overflow: hidden;
874
- }
875
-
876
- :host-context(.wa-light) .howto-panel {
877
- background: var(--wa-color-surface-raised, var(--wa-color-neutral-95));
878
- border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-75));
879
- box-shadow: var(--wa-shadow-large, 0 8px 24px rgba(0, 0, 0, 0.2));
880
- }
881
-
882
- .howto-panel.minimized {
883
- max-height: auto;
884
- }
885
-
886
- .howto-panel.dragging {
887
- opacity: 0.5;
888
- }
889
-
890
- .panel-header {
891
- display: flex;
892
- align-items: center;
893
- justify-content: space-between;
894
- padding: var(--wa-spacing-medium, 12px) var(--wa-spacing-large, 16px);
895
- background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));
896
- border-bottom: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-loud, var(--wa-color-neutral-25));
897
- cursor: move;
898
- user-select: none;
899
- }
900
-
901
- :host-context(.wa-light) .panel-header {
902
- background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));
903
- border-bottom-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-75));
904
- }
905
-
906
- .header-title {
907
- display: flex;
908
- align-items: center;
909
- gap: var(--wa-spacing-small, 8px);
910
- font-weight: 600;
911
- color: var(--wa-color-text-normal, var(--wa-color-neutral-90));
912
- }
913
-
914
- :host-context(.wa-light) .header-title {
915
- color: var(--wa-color-text-normal, var(--wa-color-neutral-10));
916
- }
917
-
918
- .header-actions {
919
- display: flex;
920
- gap: var(--wa-spacing-x-small, 4px);
921
- }
922
-
923
- .panel-content {
924
- flex: 1;
712
+ box-sizing: border-box;
925
713
  overflow-y: auto;
926
714
  padding: var(--wa-spacing-large, 16px);
927
715
  }
@@ -1222,14 +1010,10 @@ var DocksHowToPanel = class DocksHowToPanel extends DocksWidget {
1222
1010
  _decorate([state()], DocksHowToPanel.prototype, "contributions", void 0);
1223
1011
  _decorate([state()], DocksHowToPanel.prototype, "activeContributionId", void 0);
1224
1012
  _decorate([state()], DocksHowToPanel.prototype, "stepStates", void 0);
1225
- _decorate([state()], DocksHowToPanel.prototype, "isMinimized", void 0);
1226
1013
  _decorate([state()], DocksHowToPanel.prototype, "isVisible", void 0);
1227
- _decorate([state()], DocksHowToPanel.prototype, "positionX", void 0);
1228
- _decorate([state()], DocksHowToPanel.prototype, "positionY", void 0);
1229
- _decorate([state()], DocksHowToPanel.prototype, "dragPreviewPosition", void 0);
1014
+ _decorate([query("docks-floating-panel")], DocksHowToPanel.prototype, "floatingPanel", void 0);
1230
1015
  DocksHowToPanel = _decorate([customElement("docks-howto-panel")], DocksHowToPanel);
1231
- //#endregion
1232
- //#region src/howto-extension.ts
1016
+ // src/howto-extension.ts
1233
1017
  var logger = createLogger("HowToExtension");
1234
1018
  /**
1235
1019
  * HowTo System Extension
@@ -1295,7 +1079,6 @@ function howToExtension(context) {
1295
1079
  });
1296
1080
  logger.info("HowTo system extension initialized");
1297
1081
  }
1298
- //#endregion
1299
1082
  export { HOWTO_CONTRIBUTION_TARGET, howToExtension as default, howToService };
1300
1083
 
1301
- //# sourceMappingURL=howto-extension-fQQtPaor.js.map
1084
+ //# sourceMappingURL=howto-extension-BbJ7J894.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"howto-extension-BbJ7J894.js","names":["logger","getAppName"],"sources":["../src/howto-service.ts","../src/contributions/onboarding-howto-contributions.ts","../src/contributions/ai-setup-howto-contributions.ts","../src/howto-panel.ts","../src/howto-extension.ts"],"sourcesContent":["import { contributionRegistry, TOPIC_CONTRIBUTEIONS_CHANGED } from '@eclipse-docks/core';\nimport { HowToContribution, HowToStep } from './howto-contribution';\nimport { subscribe } from '@eclipse-docks/core';\nimport { createLogger } from '@eclipse-docks/core';\nimport { Signal } from '@lit-labs/signals';\n\nconst logger = createLogger('HowToService');\n\nexport const HOWTO_CONTRIBUTION_TARGET = 'system.howtos';\n\n/**\n * HowTo Service\n * \n * Manages HowTo contributions by reading from the contribution registry.\n * Provides methods to retrieve and manage workflows.\n */\nexport class HowToService {\n private contributions: Map<string, HowToContribution> = new Map();\n\n constructor() {\n // Load initial contributions\n this.loadContributions();\n\n // Subscribe to contribution changes\n subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {\n if (event.target === HOWTO_CONTRIBUTION_TARGET) {\n this.loadContributions();\n }\n });\n }\n\n /**\n * Load contributions from the contribution registry\n */\n private loadContributions(): void {\n const contributions = contributionRegistry.getContributions(HOWTO_CONTRIBUTION_TARGET) as HowToContribution[];\n \n this.contributions.clear();\n \n for (const contribution of contributions) {\n // Validate contribution\n if (!contribution.id) {\n logger.warn('HowTo contribution missing id, skipping');\n continue;\n }\n\n if (!contribution.label) {\n // Use title as label if label is not provided\n // Handle both string and function types\n const title = typeof contribution.title === 'function' \n ? contribution.title() \n : contribution.title;\n contribution.label = title;\n }\n\n if (!contribution.steps || contribution.steps.length === 0) {\n logger.warn(`HowTo contribution \"${contribution.id}\" has no steps, skipping`);\n continue;\n }\n\n // Validate step IDs are unique\n const stepIds = new Set<string>();\n for (const step of contribution.steps) {\n if (stepIds.has(step.id)) {\n logger.warn(`HowTo contribution \"${contribution.id}\" has duplicate step ID: \"${step.id}\"`);\n continue;\n }\n stepIds.add(step.id);\n }\n\n this.contributions.set(contribution.id, contribution);\n const title = typeof contribution.title === 'function' \n ? contribution.title() \n : contribution.title;\n logger.debug(`Loaded HowTo contribution: ${title} (${contribution.id})`);\n }\n\n logger.info(`Loaded ${this.contributions.size} HowTo contributions`);\n }\n\n /**\n * Get a HowTo Contribution by ID\n * \n * @param contributionId The ID of the contribution\n * @returns The contribution or undefined if not found\n */\n getContribution(contributionId: string): HowToContribution | undefined {\n return this.contributions.get(contributionId);\n }\n\n /**\n * Get all registered HowTo Contributions\n * \n * @returns Array of all contributions\n */\n getAllContributions(): HowToContribution[] {\n return Array.from(this.contributions.values());\n }\n\n /**\n * Get HowTo Contributions by category\n * \n * @param category The category to filter by\n * @returns Array of contributions in the category\n */\n getContributionsByCategory(category: string): HowToContribution[] {\n return Array.from(this.contributions.values())\n .filter(contrib => contrib.category === category);\n }\n\n /**\n * Check if a contribution exists\n * \n * @param contributionId The ID of the contribution\n * @returns True if the contribution exists\n */\n hasContribution(contributionId: string): boolean {\n return this.contributions.has(contributionId);\n }\n}\n\nexport const howToService = new HowToService();\n\n","import { contributionRegistry, workspaceService, File, TOPIC_WORKSPACE_CHANGED, TOPIC_WORKSPACE_CONNECTED, activeEditorSignal, partDirtySignal, subscribe, appLoaderService } from '@eclipse-docks/core';\nimport type { EditorContentProvider } from '@eclipse-docks/core';\nimport { watchSignal } from '@eclipse-docks/core';\nimport { HOWTO_CONTRIBUTION_TARGET } from '../howto-service';\nimport type { HowToContribution, HowToContext } from '../howto-contribution';\n\nconst ONBOARDING_FILE_NAME = 'welcome.txt';\n\nasync function getOnboardingFilePath(): Promise<string | null> {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) return null;\n const folders = await workspaceService.getFolders();\n if (folders.length === 0) return null;\n const firstFolderName = folders[0].name;\n return `${firstFolderName}/${ONBOARDING_FILE_NAME}`;\n}\n\n/**\n * Type guard to check if an editor implements EditorContentProvider\n */\nfunction isEditorContentProvider(editor: any): editor is EditorContentProvider {\n return editor &&\n typeof editor.getFilePath === 'function';\n}\n\n/**\n * Checks if a workspace is selected\n */\nasync function isWorkspaceSelected(): Promise<boolean> {\n return workspaceService.isConnected();\n}\n\n/**\n * Checks if the onboarding file exists\n */\nasync function onboardingFileExists(): Promise<boolean> {\n const path = await getOnboardingFilePath();\n if (!path) return false;\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) return false;\n try {\n const resource = await workspace.getResource(path);\n return resource instanceof File;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if the onboarding file is open in an editor\n */\nfunction isOnboardingFileOpen(): boolean {\n const activeEditor = activeEditorSignal.get();\n if (!activeEditor || !isEditorContentProvider(activeEditor)) {\n return false;\n }\n const filePath = activeEditor.getFilePath();\n return filePath === ONBOARDING_FILE_NAME || filePath?.endsWith('/' + ONBOARDING_FILE_NAME) === true;\n}\n\n/**\n * Checks if the active editor is dirty (has unsaved changes)\n * Returns true only if the onboarding file is open AND dirty\n */\nfunction isActiveEditorDirty(): boolean {\n if (!isOnboardingFileOpen()) return false;\n \n const activeEditor = activeEditorSignal.get();\n if (!activeEditor) return false;\n \n return activeEditor.isDirty() === true;\n}\n\n/**\n * Checks if the active editor is clean (no unsaved changes)\n * Returns true only if the onboarding file is open AND not dirty\n */\nfunction isActiveEditorClean(): boolean {\n if (!isOnboardingFileOpen()) return false;\n \n const activeEditor = activeEditorSignal.get();\n if (!activeEditor) return false;\n \n return activeEditor.isDirty() === false;\n}\n\n/**\n * Checks if the onboarding file is closed (not open in any editor)\n */\nfunction isOnboardingFileClosed(): boolean {\n return !isOnboardingFileOpen();\n}\n\n// Get current app name for the title\nfunction getAppName(): string {\n const currentApp = appLoaderService.getCurrentApp();\n return currentApp?.name || 'AppSpace';\n}\n\n// Create the onboarding HowTo contribution\n// Using callback functions so the app name is read when the HowTo is displayed\nconst onboardingContribution: HowToContribution = {\n id: 'docks.onboarding',\n title: () => `Welcome to ${getAppName()}`,\n description: () => `Get started with ${getAppName()} by learning the basics of workspace and file management`,\n icon: 'graduation-cap',\n // label will be set from title in howto-service.ts\n label: '',\n category: 'Getting Started',\n initialize: (context: HowToContext) => {\n // Set up subscriptions for workspace and editor changes\n const cleanups: (() => void)[] = [];\n\n // Subscribe to workspace events\n subscribe(TOPIC_WORKSPACE_CHANGED, () => {\n context.requestUpdate();\n });\n\n subscribe(TOPIC_WORKSPACE_CONNECTED, () => {\n context.requestUpdate();\n });\n\n // Watch editor signals\n cleanups.push(\n watchSignal(activeEditorSignal, () => {\n context.requestUpdate();\n })\n );\n\n cleanups.push(\n watchSignal(partDirtySignal, () => {\n context.requestUpdate();\n })\n );\n\n // Return cleanup function\n return () => {\n cleanups.forEach(cleanup => cleanup());\n };\n },\n steps: [\n {\n id: 'create-text-file',\n title: 'Create welcome.txt',\n description: 'Create a new text file called \"welcome.txt\" in your workspace. If you don\\'t have a workspace selected, choose one first.',\n preCondition: async () => {\n // Workspace must be selected\n return await isWorkspaceSelected();\n },\n postCondition: async () => {\n return await onboardingFileExists();\n },\n command: 'touch',\n commandParams: async () => {\n const path = await getOnboardingFilePath();\n return path ? {\n path,\n contents: 'Welcome to AppSpace!\\n\\nThis is your first file. You can edit it and save your changes.'\n } : {};\n }\n },\n {\n id: 'open-text-file',\n title: 'Open welcome.txt',\n description: 'Open the \"welcome.txt\" file in the editor.',\n preCondition: async () => {\n return await onboardingFileExists();\n },\n postCondition: () => {\n return isOnboardingFileOpen();\n },\n command: 'open_editor',\n commandParams: async () => {\n const path = await getOnboardingFilePath();\n return path ? { path } : {};\n }\n },\n {\n id: 'edit-and-save',\n title: 'Type something and save',\n description: 'Type some text in the editor to modify the file, then save it using Ctrl+S or the save button.',\n preCondition: () => {\n return isOnboardingFileOpen();\n },\n postCondition: () => {\n // File must be open, was dirty (edited), and is now clean (saved)\n // Check that file is open and clean (saved)\n return isActiveEditorClean();\n },\n // No command - user manually edits and saves\n },\n {\n id: 'close-text-file',\n title: 'Close the file',\n description: 'Close the editor tab by clicking the X button on the tab.',\n preCondition: () => {\n return isOnboardingFileOpen();\n },\n postCondition: () => {\n return isOnboardingFileClosed();\n },\n // No command - user manually closes the tab\n }\n ]\n};\n\n// Register the contribution\ncontributionRegistry.registerContribution<HowToContribution>(HOWTO_CONTRIBUTION_TARGET, onboardingContribution);\n\n","import {\n contributionRegistry,\n activeEditorSignal,\n appLoaderService,\n partDirtySignal,\n subscribe,\n unsubscribe,\n watchSignal,\n} from '@eclipse-docks/core';\nimport {\n AI_SETTINGS_KEY,\n OPEN_AI_SETTINGS_COMMAND,\n TOPIC,\n cognitiveRuntime,\n} from '@eclipse-docks/extension-ai-system/api';\nimport { HOWTO_CONTRIBUTION_TARGET } from '../howto-service';\nimport type { HowToContribution, HowToContext } from '../howto-contribution';\n\nfunction isAIConfigEditorOpen(): boolean {\n const activeEditor = activeEditorSignal.get() as {\n input?: { key?: string };\n tagName?: string;\n localName?: string;\n } | null;\n if (!activeEditor) return false;\n if (activeEditor.input?.key === AI_SETTINGS_KEY) return true;\n const tag = (activeEditor.tagName || activeEditor.localName || '').toLowerCase();\n return tag === 'docks-cognitive-settings-editor';\n}\n\nasync function isLLMProviderConfigured(): Promise<boolean> {\n try {\n await cognitiveRuntime.whenReady();\n const settings = cognitiveRuntime.getProvidersSettings();\n if (!settings.defaultProviderId) return false;\n const provider = settings.providers.find((p) => p.id === settings.defaultProviderId);\n if (!provider?.enabled) return false;\n // Local providers (ollama/webllm) may not need a key.\n if (!provider.apiKey.trim()) {\n return /ollama|webllm|localhost|127\\.0\\.0\\.1/i.test(`${provider.id} ${provider.baseUrl}`);\n }\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isAIConfigEditorDirty(): boolean {\n const activeEditor = activeEditorSignal.get() as { isDirty?: () => boolean } | null;\n if (!activeEditor || !isAIConfigEditorOpen()) return false;\n return activeEditor.isDirty?.() === true;\n}\n\nfunction isAIConfigEditorSaved(): boolean {\n return isAIConfigEditorOpen() && !isAIConfigEditorDirty();\n}\n\nfunction isAIConfigEditorClosed(): boolean {\n return !isAIConfigEditorOpen();\n}\n\nasync function hasTypedInChat(): Promise<boolean> {\n try {\n await cognitiveRuntime.whenReady();\n for (const session of cognitiveRuntime.sessions.list()) {\n const hasUserMessage = session.history.some(\n (msg) =>\n msg.role === 'user' &&\n msg.parts.some((part) => part.type === 'text' && part.text.trim() !== ''),\n );\n if (hasUserMessage) return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\nfunction getAppName(): string {\n const currentApp = appLoaderService.getCurrentApp();\n return currentApp?.name || 'AppSpace';\n}\n\nconst aiSetupContribution: HowToContribution = {\n id: 'docks.ai-setup',\n title: () => `Set up AI in ${getAppName()}`,\n description: () => `Configure an LLM provider to enable AI chat features in ${getAppName()}`,\n icon: 'robot',\n label: '',\n category: 'Getting Started',\n initialize: (context: HowToContext) => {\n const cleanups: Array<() => void> = [];\n\n cleanups.push(watchSignal(activeEditorSignal, () => context.requestUpdate()));\n cleanups.push(watchSignal(partDirtySignal, () => context.requestUpdate()));\n const providersToken = subscribe(TOPIC.providersChanged, () => context.requestUpdate());\n const sessionToken = subscribe(TOPIC.sessionChanged, () => context.requestUpdate());\n cleanups.push(() => unsubscribe(providersToken), () => unsubscribe(sessionToken));\n\n return () => {\n cleanups.forEach((cleanup) => cleanup());\n };\n },\n steps: [\n {\n id: 'open-ai-settings',\n title: 'Open AI Settings',\n description:\n 'Open the AI settings editor from the chat gear menu or the command palette.',\n preCondition: () => true,\n postCondition: () => isAIConfigEditorOpen(),\n command: OPEN_AI_SETTINGS_COMMAND,\n },\n {\n id: 'configure-llm-provider',\n title: 'Configure LLM Provider',\n description:\n 'Select a provider as default and enter an API key when required. Save your changes.',\n preCondition: () => isAIConfigEditorOpen(),\n postCondition: async () => {\n const configured = await isLLMProviderConfigured();\n const saved = isAIConfigEditorSaved();\n return configured && saved;\n },\n },\n {\n id: 'save-and-close',\n title: 'Save and Close',\n description: 'Save your changes (if not already saved) and close the AI settings editor tab.',\n preCondition: () => isAIConfigEditorOpen(),\n postCondition: () => isAIConfigEditorClosed(),\n },\n {\n id: 'type-in-chat',\n title: 'Type in Chat',\n description: 'Open the AI chat view and type a message to test your AI configuration.',\n preCondition: async () => await isLLMProviderConfigured(),\n postCondition: async () => await hasTypedInChat(),\n },\n ],\n};\n\ncontributionRegistry.registerContribution<HowToContribution>(HOWTO_CONTRIBUTION_TARGET, aiSetupContribution);\n","import { css, html, nothing } from 'lit';\nimport { customElement, query, state } from 'lit/decorators.js';\nimport { DocksWidget, type DocksFloatingPanel } from '@eclipse-docks/core';\nimport { howToService } from './howto-service';\nimport { HowToContribution, HowToStep } from './howto-contribution';\nimport { subscribe } from '@eclipse-docks/core';\nimport { commandRegistry } from '@eclipse-docks/core';\nimport { toastError } from '@eclipse-docks/core';\nimport { TOPIC_CONTRIBUTEIONS_CHANGED } from '@eclipse-docks/core';\nimport { HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nimport { appSettings } from '@eclipse-docks/core';\nimport { workspaceService, TOPIC_WORKSPACE_CONNECTED } from '@eclipse-docks/core';\n\n// Event topic for showing the HowTo panel\nexport const TOPIC_SHOW_HOWTO_PANEL = 'howto/show-panel';\nexport const TOPIC_TOGGLE_HOWTO_PANEL = 'howto/toggle-panel';\n\n// Constants\nconst SETTINGS_KEY = 'howto-panel';\n\ninterface StepState {\n step: HowToStep;\n status: 'pending' | 'active' | 'completed' | 'skipped' | 'failed';\n preConditionMet?: boolean;\n postConditionMet?: boolean;\n}\n\n@customElement('docks-howto-panel')\nexport class DocksHowToPanel extends DocksWidget {\n @state()\n private contributions: HowToContribution[] = [];\n\n @state()\n private activeContributionId: string | null = null;\n\n @state()\n private stepStates: Map<string, StepState[]> = new Map();\n\n @state()\n private isVisible: boolean = false;\n\n @query('docks-floating-panel')\n private floatingPanel?: DocksFloatingPanel;\n\n private howtoCleanup?: () => void;\n\n protected async doBeforeUI() {\n this.loadContributions();\n \n subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {\n if (event.target === HOWTO_CONTRIBUTION_TARGET) {\n this.loadContributions();\n this.requestUpdate();\n }\n });\n\n // Subscribe to show/toggle panel events\n subscribe(TOPIC_SHOW_HOWTO_PANEL, () => this.showPanel());\n subscribe(TOPIC_TOGGLE_HOWTO_PANEL, () => this.toggleVisibility());\n\n // Load position and visibility from dialogsettings\n await this.loadSettings();\n \n // If no workspace is selected and panel wasn't explicitly hidden, show it by default\n const hasWorkspace = workspaceService.isConnected();\n if (!hasWorkspace && this.isVisible === false) {\n // Check if user has explicitly hidden it (if settings exist and visible is false)\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (!settings || settings.visible === undefined) {\n // No explicit preference, show panel when no workspace\n this.isVisible = true;\n await this.saveSettings();\n }\n }\n \n // Subscribe to workspace connection to hide panel when workspace is connected (if it was auto-shown)\n subscribe(TOPIC_WORKSPACE_CONNECTED, () => {\n // Only auto-hide if it was auto-shown (no explicit visibility setting)\n const checkAutoHide = async () => {\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (!settings || settings.visible === undefined) {\n // Was auto-shown, can auto-hide when workspace connects\n // But let's keep it visible - user might want to see howtos even with workspace\n }\n };\n checkAutoHide();\n });\n }\n\n private loadContributions() {\n this.contributions = howToService.getAllContributions();\n }\n\n private async loadSettings() {\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (settings && settings.visible !== undefined) {\n this.isVisible = settings.visible;\n }\n }\n\n private async saveSettings() {\n const current = await appSettings.getDialogSetting(SETTINGS_KEY);\n const base = current !== null && typeof current === 'object' ? current : {};\n await appSettings.setDialogSetting(SETTINGS_KEY, {\n ...base,\n visible: this.isVisible,\n });\n }\n\n private expandPanel(): void {\n if (!this.floatingPanel) return;\n this.floatingPanel.minimized = false;\n }\n\n private async startHowTo(contributionId: string) {\n const contribution = howToService.getContribution(contributionId);\n if (!contribution) {\n toastError(`HowTo \"${contributionId}\" not found`);\n return;\n }\n\n // Clean up previous HowTo\n this.cleanupHowTo();\n\n this.activeContributionId = contributionId;\n this.expandPanel();\n\n // Initialize step states\n const states: StepState[] = contribution.steps.map(step => ({\n step,\n status: 'pending'\n }));\n\n this.stepStates.set(contributionId, states);\n \n // Call HowTo's initialize function if provided\n if (contribution.initialize) {\n const context = {\n requestUpdate: () => this.recheckActiveStepConditions(),\n contributionId: contributionId\n };\n this.howtoCleanup = contribution.initialize(context) || undefined;\n }\n \n this.requestUpdate();\n\n // Check initial pre-conditions\n await this.checkPreConditions(contributionId, 0);\n }\n\n private cleanupHowTo() {\n if (this.howtoCleanup) {\n this.howtoCleanup();\n this.howtoCleanup = undefined;\n }\n }\n\n private getStepState(contributionId: string, stepIndex: number): StepState | null {\n const states = this.stepStates.get(contributionId);\n return states && stepIndex < states.length ? states[stepIndex] : null;\n }\n\n private async checkPreConditions(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!state.step.preCondition) {\n state.preConditionMet = true;\n this.requestUpdate();\n return;\n }\n\n try {\n state.preConditionMet = await state.step.preCondition();\n this.requestUpdate();\n } catch (error) {\n console.error(`Pre-condition check failed for step ${state.step.id}:`, error);\n state.preConditionMet = false;\n this.requestUpdate();\n }\n }\n\n private async checkPostConditions(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!state.step.postCondition) {\n this.completeStep(contributionId, stepIndex);\n return;\n }\n\n try {\n const result = await state.step.postCondition();\n state.postConditionMet = result;\n state.status = result ? 'completed' : 'failed';\n \n if (result) {\n this.activateNextStep(contributionId, stepIndex);\n }\n this.requestUpdate();\n } catch (error) {\n console.error(`Post-condition check failed for step ${state.step.id}:`, error);\n state.postConditionMet = false;\n state.status = 'failed';\n this.requestUpdate();\n }\n }\n\n private completeStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n \n state.status = 'completed';\n this.activateNextStep(contributionId, stepIndex);\n this.requestUpdate();\n }\n\n private async activateNextStep(contributionId: string, stepIndex: number) {\n const states = this.stepStates.get(contributionId);\n if (!states || stepIndex + 1 >= states.length) return;\n \n const nextState = states[stepIndex + 1];\n nextState.status = 'active';\n await this.checkPreConditions(contributionId, stepIndex + 1);\n }\n\n /**\n * Re-checks conditions for active and pending steps when workspace or editor state changes\n */\n private async recheckActiveStepConditions() {\n if (!this.activeContributionId) return;\n\n const states = this.stepStates.get(this.activeContributionId);\n if (!states) return;\n\n // Find the active step\n const activeStepIndex = states.findIndex(state => state.status === 'active');\n \n if (activeStepIndex !== -1) {\n const activeState = states[activeStepIndex];\n const step = activeState.step;\n\n // Re-check post-condition if it exists and step is active\n if (step.postCondition) {\n try {\n const result = await step.postCondition();\n if (result && activeState.status === 'active') {\n // Post-condition is met, complete the step and move to next\n await this.checkPostConditions(this.activeContributionId, activeStepIndex);\n return; // Step completed, no need to check pre-conditions\n }\n } catch (error) {\n // Ignore errors in post-condition checks during re-evaluation\n }\n }\n }\n\n // Re-check pre-conditions for pending steps (they might become available)\n for (let i = 0; i < states.length; i++) {\n const state = states[i];\n if (state.status === 'pending' && state.step.preCondition) {\n // Re-check pre-condition for pending steps\n await this.checkPreConditions(this.activeContributionId, i);\n }\n }\n\n this.requestUpdate();\n }\n\n private async executeStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!await this.validatePreConditions(state, contributionId, stepIndex)) {\n return;\n }\n\n state.status = 'active';\n this.requestUpdate();\n\n if (state.step.command && !await this.executeStepCommand(state)) {\n return;\n }\n\n await this.checkPostConditions(contributionId, stepIndex);\n }\n\n private async validatePreConditions(state: StepState, contributionId: string, stepIndex: number): Promise<boolean> {\n if (!state.step.preCondition) {\n return true;\n }\n\n if (state.preConditionMet === undefined || state.preConditionMet === false) {\n await this.checkPreConditions(contributionId, stepIndex);\n }\n\n if (state.preConditionMet !== true) {\n toastError(`Pre-conditions not met for step: ${state.step.title}`);\n return false;\n }\n\n return true;\n }\n\n private async executeStepCommand(state: StepState): Promise<boolean> {\n if (!state.step.command) {\n return true;\n }\n\n try {\n const rawParams = state.step.commandParams;\n const params = typeof rawParams === 'function' ? await rawParams() : (rawParams || {});\n const execContext = commandRegistry.createExecutionContext(params);\n await commandRegistry.execute(state.step.command, execContext);\n return true;\n } catch (error) {\n console.error(`Failed to execute command for step ${state.step.id}:`, error);\n toastError(`Failed to execute step: ${state.step.title}`);\n state.status = 'failed';\n this.requestUpdate();\n return false;\n }\n }\n\n private async runStepCommand(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state || !state.step.command) {\n return;\n }\n\n // Check pre-conditions if they exist\n if (state.step.preCondition) {\n const preConditionMet = await state.step.preCondition();\n if (!preConditionMet) {\n toastError(`Pre-conditions not met for step: ${state.step.title}`);\n return;\n }\n }\n\n // Execute the command\n const success = await this.executeStepCommand(state);\n if (success) {\n // Check post-conditions after command execution\n await this.checkPostConditions(contributionId, stepIndex);\n }\n }\n\n private skipStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state || !state.step.optional) return;\n\n state.status = 'skipped';\n this.activateNextStep(contributionId, stepIndex);\n this.requestUpdate();\n }\n\n private closeHowTo() {\n this.cleanupHowTo();\n this.activeContributionId = null;\n this.stepStates.clear();\n this.requestUpdate();\n }\n\n private async showPanel() {\n this.isVisible = true;\n await this.saveSettings();\n this.requestUpdate();\n await this.updateComplete;\n this.expandPanel();\n }\n\n private async hidePanel() {\n this.isVisible = false;\n await this.saveSettings();\n this.requestUpdate();\n }\n\n private async toggleVisibility() {\n if (this.isVisible) {\n await this.hidePanel();\n } else {\n await this.showPanel();\n }\n }\n\n private renderStep(state: StepState, index: number, contributionId: string) {\n const { step, status, preConditionMet, postConditionMet } = state;\n const isActive = status === 'active';\n const isCompleted = status === 'completed';\n const isFailed = status === 'failed';\n const isPending = status === 'pending';\n const isSkipped = status === 'skipped';\n\n return html`\n <div class=\"step ${status}\" ?data-active=${isActive}>\n <div class=\"step-header\">\n <div class=\"step-number\">${index + 1}</div>\n <div class=\"step-title\">${step.title}</div>\n <div class=\"step-status\">\n ${step.command ? html`\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${(e: Event) => {\n e.stopPropagation();\n this.runStepCommand(contributionId, index);\n }}\n title=\"Run step command\"\n >\n <wa-icon name=\"play\"></wa-icon>\n </wa-button>\n ` : nothing}\n ${isCompleted ? html`<wa-icon name=\"check-circle\" class=\"status-icon completed\"></wa-icon>` : nothing}\n ${isFailed ? html`<wa-icon name=\"xmark-circle\" class=\"status-icon failed\"></wa-icon>` : nothing}\n ${isSkipped ? html`<wa-icon name=\"minus-circle\" class=\"status-icon skipped\"></wa-icon>` : nothing}\n ${isPending ? html`<wa-icon name=\"circle\" class=\"status-icon pending\"></wa-icon>` : nothing}\n ${isActive ? html`<wa-icon name=\"play-circle\" class=\"status-icon active\"></wa-icon>` : nothing}\n </div>\n </div>\n <div class=\"step-description\">${step.description}</div>\n ${step.preCondition && preConditionMet !== undefined ? html`\n <div class=\"condition pre-condition ${preConditionMet ? 'met' : 'not-met'}\">\n <wa-icon name=\"${preConditionMet ? 'check' : 'xmark'}\"></wa-icon>\n <span>Pre-condition: ${preConditionMet ? 'Met' : 'Not met'}</span>\n </div>\n ` : nothing}\n ${step.postCondition && postConditionMet !== undefined ? html`\n <div class=\"condition post-condition ${postConditionMet ? 'met' : 'not-met'}\">\n <wa-icon name=\"${postConditionMet ? 'check' : 'xmark'}\"></wa-icon>\n <span>Post-condition: ${postConditionMet ? 'Met' : 'Not met'}</span>\n </div>\n ` : nothing}\n ${isActive && step.optional ? html`\n <div class=\"step-actions\">\n <wa-button size=\"s\" appearance=\"outline\" @click=${() => this.skipStep(contributionId, index)}>\n <wa-icon name=\"forward\"></wa-icon>\n Skip\n </wa-button>\n </div>\n ` : nothing}\n </div>\n `;\n }\n\n render() {\n if (!this.isVisible) {\n return nothing;\n }\n\n const activeContribution = this.activeContributionId\n ? howToService.getContribution(this.activeContributionId)\n : null;\n\n const activeStepStates = this.activeContributionId\n ? this.stepStates.get(this.activeContributionId) || []\n : [];\n\n return html`\n <docks-floating-panel\n label=\"HowTo Workflows\"\n icon=\"list-check\"\n .persistKey=${SETTINGS_KEY}\n @floating-close=${() => { void this.hidePanel(); }}\n >\n <div class=\"panel-content\">\n ${activeContribution ? html`\n <div class=\"active-workflow\">\n <div class=\"workflow-header\">\n <div class=\"workflow-title-section\">\n <h3>${typeof activeContribution.title === 'function' \n ? activeContribution.title() \n : activeContribution.title}</h3>\n ${activeContribution.description ? html`\n <p class=\"workflow-description\">${typeof activeContribution.description === 'function'\n ? activeContribution.description()\n : activeContribution.description}</p>\n ` : nothing}\n </div>\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${this.closeHowTo}\n title=\"Close HowTo\"\n >\n <wa-icon name=\"xmark\"></wa-icon>\n </wa-button>\n </div>\n <div class=\"steps-list\">\n ${activeStepStates.map((state, index) => \n this.renderStep(state, index, this.activeContributionId!)\n )}\n </div>\n </div>\n ` : html`\n <div class=\"workflows-list\">\n <h3>Available Workflows</h3>\n ${this.contributions.length === 0 ? html`\n <div class=\"empty-state\">\n <wa-icon name=\"list-check\" style=\"font-size: 2em; opacity: 0.5; margin-bottom: 12px;\"></wa-icon>\n <p>No HowTo workflows available yet.</p>\n <p style=\"font-size: 0.9em; opacity: 0.7;\">Extensions can register workflows via the contribution registry.</p>\n </div>\n ` : this.contributions.map(contrib => {\n const title = typeof contrib.title === 'function' ? contrib.title() : contrib.title;\n const description = contrib.description \n ? (typeof contrib.description === 'function' ? contrib.description() : contrib.description)\n : null;\n return html`\n <div class=\"workflow-item\" @click=${() => this.startHowTo(contrib.id)}>\n ${contrib.icon ? html`\n <wa-icon name=\"${contrib.icon}\"></wa-icon>\n ` : html`\n <wa-icon name=\"list-check\"></wa-icon>\n `}\n <div class=\"workflow-info\">\n <div class=\"workflow-title\">${title}</div>\n ${description ? html`\n <div class=\"workflow-desc\">${description}</div>\n ` : nothing}\n <div class=\"workflow-meta\">${contrib.steps.length} step${contrib.steps.length !== 1 ? 's' : ''}</div>\n </div>\n </div>\n `})}\n </div>\n `}\n </div>\n </docks-floating-panel>\n `;\n }\n\n static styles = css`\n :host {\n display: contents;\n }\n\n .panel-content {\n width: 400px;\n max-height: 600px;\n box-sizing: border-box;\n overflow-y: auto;\n padding: var(--wa-spacing-large, 16px);\n }\n\n .workflows-list h3 {\n margin: 0 0 var(--wa-spacing-medium, 12px) 0;\n font-size: var(--wa-font-size-medium, 14px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-80));\n }\n\n :host-context(.wa-light) .workflows-list h3 {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-20));\n }\n\n .workflow-item {\n display: flex;\n align-items: flex-start;\n gap: var(--wa-spacing-medium, 12px);\n padding: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-small, 8px);\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));\n border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-20));\n border-radius: var(--wa-border-radius-small, 6px);\n cursor: pointer;\n transition: all var(--wa-transition-medium, 0.2s);\n }\n\n :host-context(.wa-light) .workflow-item {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));\n border-color: var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-80));\n }\n\n .workflow-item:hover {\n background: var(--wa-color-mix-hover, var(--wa-color-neutral-15));\n border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-30));\n }\n\n :host-context(.wa-light) .workflow-item:hover {\n background: var(--wa-color-mix-hover, var(--wa-color-neutral-85));\n border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-70));\n }\n\n .workflow-info {\n flex: 1;\n }\n\n .workflow-title {\n font-weight: 600;\n margin-bottom: var(--wa-spacing-x-small, 4px);\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .workflow-title {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .workflow-desc {\n font-size: var(--wa-font-size-small, 12px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n margin-bottom: var(--wa-spacing-x-small, 4px);\n }\n\n :host-context(.wa-light) .workflow-desc {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .workflow-meta {\n font-size: var(--wa-font-size-x-small, 11px);\n color: var(--wa-color-text-quiet, var(--wa-color-neutral-60));\n }\n\n :host-context(.wa-light) .workflow-meta {\n color: var(--wa-color-text-quiet, var(--wa-color-neutral-40));\n }\n\n .active-workflow {\n display: flex;\n flex-direction: column;\n gap: var(--wa-spacing-large, 16px);\n }\n\n .workflow-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-medium, 12px);\n }\n\n .workflow-title-section {\n flex: 1;\n }\n\n .workflow-header h3 {\n margin: 0 0 var(--wa-spacing-small, 8px) 0;\n font-size: var(--wa-font-size-large, 16px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .workflow-header h3 {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .workflow-description {\n margin: 0;\n font-size: var(--wa-font-size-medium, 13px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n }\n\n :host-context(.wa-light) .workflow-description {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .steps-list {\n display: flex;\n flex-direction: column;\n gap: var(--wa-spacing-medium, 12px);\n }\n\n .step {\n padding: var(--wa-spacing-medium, 12px);\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));\n border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-20));\n border-radius: var(--wa-border-radius-small, 6px);\n transition: all var(--wa-transition-medium, 0.2s);\n }\n\n :host-context(.wa-light) .step {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));\n border-color: var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-80));\n }\n\n .step[data-active=\"true\"] {\n border-color: var(--wa-color-primary-50);\n background: var(--wa-color-primary-05);\n }\n\n :host-context(.wa-light) .step[data-active=\"true\"] {\n background: var(--wa-color-primary-95);\n border-color: var(--wa-color-primary-50);\n }\n\n .step.completed {\n border-color: var(--wa-color-success-50);\n background: var(--wa-color-success-05);\n }\n\n :host-context(.wa-light) .step.completed {\n background: var(--wa-color-success-95);\n border-color: var(--wa-color-success-50);\n }\n\n .step.failed {\n border-color: var(--wa-color-danger-50);\n background: var(--wa-color-danger-05);\n }\n\n :host-context(.wa-light) .step.failed {\n background: var(--wa-color-danger-95);\n border-color: var(--wa-color-danger-50);\n }\n\n .step-header {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-small, 8px);\n }\n\n .step-number {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-20));\n border-radius: 50%;\n font-size: var(--wa-font-size-small, 12px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-80));\n }\n\n :host-context(.wa-light) .step-number {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-80));\n color: var(--wa-color-text-normal, var(--wa-color-neutral-20));\n }\n\n .step-title {\n flex: 1;\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .step-title {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .step-status {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-small, 8px);\n }\n\n .status-icon {\n width: 20px;\n height: 20px;\n }\n\n .status-icon.completed {\n color: var(--wa-color-success-50);\n }\n\n .status-icon.failed {\n color: var(--wa-color-danger-50);\n }\n\n .status-icon.skipped {\n color: var(--wa-color-neutral-50);\n }\n\n .status-icon.active {\n color: var(--wa-color-primary-50);\n }\n\n .status-icon.pending {\n color: var(--wa-color-neutral-50);\n }\n\n .step-description {\n font-size: var(--wa-font-size-medium, 13px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n margin-bottom: var(--wa-spacing-small, 8px);\n line-height: 1.4;\n }\n\n :host-context(.wa-light) .step-description {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .condition {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-x-small, 6px);\n font-size: var(--wa-font-size-small, 12px);\n padding: var(--wa-spacing-x-small, 6px) var(--wa-spacing-small, 8px);\n border-radius: var(--wa-border-radius-x-small, 4px);\n margin-bottom: var(--wa-spacing-small, 8px);\n }\n\n .condition.met {\n background: var(--wa-color-success-10);\n color: var(--wa-color-success-70);\n }\n\n :host-context(.wa-light) .condition.met {\n background: var(--wa-color-success-90);\n color: var(--wa-color-success-30);\n }\n\n .condition.not-met {\n background: var(--wa-color-danger-10);\n color: var(--wa-color-danger-70);\n }\n\n :host-context(.wa-light) .condition.not-met {\n background: var(--wa-color-danger-90);\n color: var(--wa-color-danger-30);\n }\n\n .step-actions {\n display: flex;\n gap: var(--wa-spacing-small, 8px);\n margin-top: var(--wa-spacing-small, 8px);\n }\n\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--wa-spacing-x-large, 40px) var(--wa-spacing-large, 20px);\n text-align: center;\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n }\n\n :host-context(.wa-light) .empty-state {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .empty-state p {\n margin: var(--wa-spacing-small, 8px) 0;\n }\n `;\n}\n\n","import { createLogger } from '@eclipse-docks/core';\nimport { rootContext } from '@eclipse-docks/core';\nimport { howToService } from './howto-service';\nimport { HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nimport './contributions/onboarding-howto-contributions';\nimport './contributions/ai-setup-howto-contributions';\nimport { TOPIC_SHOW_HOWTO_PANEL, TOPIC_TOGGLE_HOWTO_PANEL } from './howto-panel';\nimport { registerAll } from '@eclipse-docks/core';\nimport { publish } from '@eclipse-docks/core';\nimport { TOOLBAR_BOTTOM_END } from '@eclipse-docks/core';\nimport './howto-panel';\n\nconst logger = createLogger('HowToExtension');\n\n/**\n * HowTo System Extension\n * \n * Provides a system for registering and displaying step-by-step workflows\n * that guide users through specific processes with pre and post condition checks.\n * \n * Features:\n * - Register HowToContributions via contribution registry\n * - Floating, draggable UI panel\n * - Sequential step execution\n * - Pre and post condition validation\n * - Step status tracking\n */\nexport default function howToExtension(context: any) {\n logger.info('HowTo system extension loaded');\n\n // Register the HowTo service in the dependency injection context\n rootContext.put('howToService', howToService);\n\n // Ensure the panel is added to the DOM\n const ensurePanelInDOM = () => {\n // Check if panel already exists\n if (document.querySelector('docks-howto-panel')) {\n return;\n }\n\n // Create and append the panel\n const panel = document.createElement('docks-howto-panel');\n document.body.appendChild(panel);\n logger.info('HowTo panel added to DOM');\n };\n\n // Add panel to DOM - use requestAnimationFrame to ensure DOM is ready\n if (document.body) {\n requestAnimationFrame(() => {\n ensurePanelInDOM();\n });\n } else {\n // Wait for DOM to be ready\n const checkDOM = () => {\n if (document.body) {\n ensurePanelInDOM();\n } else {\n requestAnimationFrame(checkDOM);\n }\n };\n requestAnimationFrame(checkDOM);\n }\n\n // Register command to show/toggle the HowTo panel\n registerAll({\n command: {\n id: 'howto.show-panel',\n name: 'Show HowTo Panel',\n description: 'Shows the HowTo workflows panel',\n icon: 'list-check',\n parameters: []\n },\n handler: {\n execute: () => {\n publish(TOPIC_SHOW_HOWTO_PANEL, null);\n }\n }\n });\n\n registerAll({\n command: {\n id: 'howto.toggle-panel',\n name: 'Toggle HowTo Panel',\n description: 'Toggles the visibility of the HowTo workflows panel',\n icon: 'list-check',\n keyBinding: 'CTRL+SHIFT+H',\n parameters: []\n },\n handler: {\n execute: () => {\n publish(TOPIC_TOGGLE_HOWTO_PANEL, null);\n }\n },\n contribution: {\n target: TOOLBAR_BOTTOM_END,\n icon: 'list-check',\n label: 'HowTo',\n }\n });\n\n logger.info('HowTo system extension initialized');\n}\n\n// Export the service and types for direct imports\nexport { howToService, HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nexport type { HowToContribution, HowToStep, ConditionFunction } from './howto-contribution';\n\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { nothing, PropertyValues } from 'lit';
1
+ import { nothing } from 'lit';
2
2
  import { DocksWidget } from '@eclipse-docks/core';
3
3
  export declare const TOPIC_SHOW_HOWTO_PANEL = "howto/show-panel";
4
4
  export declare const TOPIC_TOGGLE_HOWTO_PANEL = "howto/toggle-panel";
@@ -6,28 +6,14 @@ export declare class DocksHowToPanel extends DocksWidget {
6
6
  private contributions;
7
7
  private activeContributionId;
8
8
  private stepStates;
9
- private isMinimized;
10
9
  private isVisible;
11
- private positionX;
12
- private positionY;
13
- private isDragging;
14
- private dragPreviewPosition;
15
- private dragStartPosition;
16
- private panelRef;
10
+ private floatingPanel?;
17
11
  private howtoCleanup?;
18
12
  protected doBeforeUI(): Promise<void>;
19
- private boundHandleDragMove?;
20
- private boundHandleDragEnd?;
21
- protected doInitUI(): void;
22
- protected firstUpdated(_changedProperties: PropertyValues): void;
23
13
  private loadContributions;
24
14
  private loadSettings;
25
15
  private saveSettings;
26
- private handleDragStart;
27
- private isDragTarget;
28
- private getViewportBounds;
29
- private handleDragMove;
30
- private handleDragEnd;
16
+ private expandPanel;
31
17
  private startHowTo;
32
18
  private cleanupHowTo;
33
19
  private getStepState;
@@ -45,7 +31,6 @@ export declare class DocksHowToPanel extends DocksWidget {
45
31
  private runStepCommand;
46
32
  private skipStep;
47
33
  private closeHowTo;
48
- private toggleMinimize;
49
34
  private showPanel;
50
35
  private hidePanel;
51
36
  private toggleVisibility;
@@ -1 +1 @@
1
- {"version":3,"file":"howto-panel.d.ts","sourceRoot":"","sources":["../src/howto-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,MAAM,KAAK,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AAErC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAalD,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAc7D,qBACa,eAAgB,SAAQ,WAAW;IAE5C,OAAO,CAAC,aAAa,CAA2B;IAGhD,OAAO,CAAC,oBAAoB,CAAuB;IAGnD,OAAO,CAAC,UAAU,CAAuC;IAGzD,OAAO,CAAC,WAAW,CAAkB;IAGrC,OAAO,CAAC,SAAS,CAAkB;IAGnC,OAAO,CAAC,SAAS,CAA8B;IAG/C,OAAO,CAAC,SAAS,CAA8B;IAE/C,OAAO,CAAC,UAAU,CAAkB;IAGpC,OAAO,CAAC,mBAAmB,CAAyC;IAEpE,OAAO,CAAC,iBAAiB,CAA4C;IAErE,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,YAAY,CAAC,CAAa;cAElB,UAAU;IA2C1B,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IACtD,OAAO,CAAC,kBAAkB,CAAC,CAAa;IAExC,SAAS,CAAC,QAAQ;IAQlB,SAAS,CAAC,YAAY,CAAC,kBAAkB,EAAE,cAAc;IAIzD,OAAO,CAAC,iBAAiB;YAIX,YAAY;YAaZ,YAAY;IAO1B,OAAO,CAAC,eAAe,CAgBtB;IAED,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,iBAAiB;IASzB,OAAO,CAAC,cAAc,CAarB;IAED,OAAO,CAAC,aAAa,CAcpB;YAEa,UAAU;IAoCxB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,YAAY;YAKN,kBAAkB;YAoBlB,mBAAmB;IA0BjC,OAAO,CAAC,YAAY;YASN,gBAAgB;IAS9B;;OAEG;YACW,2BAA2B;YAwC3B,WAAW;YAkBX,qBAAqB;YAiBrB,kBAAkB;YAoBlB,cAAc;IAuB5B,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,UAAU;IAOlB,OAAO,CAAC,cAAc;YAKR,SAAS;YAOT,SAAS;YAMT,gBAAgB;IAQ9B,OAAO,CAAC,UAAU;IA2DlB,MAAM;IAiIN,MAAM,CAAC,MAAM,0BAiYX;CACL"}
1
+ {"version":3,"file":"howto-panel.d.ts","sourceRoot":"","sources":["../src/howto-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,OAAO,EAAE,MAAM,KAAK,CAAC;AAEzC,OAAO,EAAE,WAAW,EAA2B,MAAM,qBAAqB,CAAC;AAY3E,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AACzD,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAY7D,qBACa,eAAgB,SAAQ,WAAW;IAE5C,OAAO,CAAC,aAAa,CAA2B;IAGhD,OAAO,CAAC,oBAAoB,CAAuB;IAGnD,OAAO,CAAC,UAAU,CAAuC;IAGzD,OAAO,CAAC,SAAS,CAAkB;IAGnC,OAAO,CAAC,aAAa,CAAC,CAAqB;IAE3C,OAAO,CAAC,YAAY,CAAC,CAAa;cAElB,UAAU;IA2C1B,OAAO,CAAC,iBAAiB;YAIX,YAAY;YAOZ,YAAY;IAS1B,OAAO,CAAC,WAAW;YAKL,UAAU;IAoCxB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,YAAY;YAKN,kBAAkB;YAoBlB,mBAAmB;IA0BjC,OAAO,CAAC,YAAY;YASN,gBAAgB;IAS9B;;OAEG;YACW,2BAA2B;YAwC3B,WAAW;YAkBX,qBAAqB;YAiBrB,kBAAkB;YAoBlB,cAAc;IAuB5B,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,UAAU;YAOJ,SAAS;YAQT,SAAS;YAMT,gBAAgB;IAQ9B,OAAO,CAAC,UAAU;IA2DlB,MAAM;IAsFN,MAAM,CAAC,MAAM,0BA+SX;CACL"}
@@ -1,11 +1,10 @@
1
- //#region src/i18n.de.json
1
+ // src/i18n.de.json
2
2
  var EXT_HOWTO_NAME = "HowTo-System";
3
3
  var EXT_HOWTO_DESC = "Schritt-für-Schritt-Workflow-System mit Vor- und Nachbedingungsprüfungen";
4
4
  var i18n_de_default = {
5
5
  EXT_HOWTO_NAME,
6
6
  EXT_HOWTO_DESC
7
7
  };
8
- //#endregion
9
8
  export { EXT_HOWTO_DESC, EXT_HOWTO_NAME, i18n_de_default as default };
10
9
 
11
- //# sourceMappingURL=i18n.de-6a7MkAVi.js.map
10
+ //# sourceMappingURL=i18n.de-CmqGh2TT.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.de-6a7MkAVi.js","names":[],"sources":["../src/i18n.de.json"],"sourcesContent":["{\n \"EXT_HOWTO_NAME\": \"HowTo-System\",\n \"EXT_HOWTO_DESC\": \"Schritt-für-Schritt-Workflow-System mit Vor- und Nachbedingungsprüfungen\"\n}\n"],"mappings":""}
1
+ {"version":3,"file":"i18n.de-CmqGh2TT.js","names":[],"sources":["../src/i18n.de.json"],"sourcesContent":["{\n \"EXT_HOWTO_NAME\": \"HowTo-System\",\n \"EXT_HOWTO_DESC\": \"Schritt-für-Schritt-Workflow-System mit Vor- und Nachbedingungsprüfungen\"\n}\n"],"mappings":""}
@@ -1,11 +1,10 @@
1
- //#region src/i18n.en.json
1
+ // src/i18n.en.json
2
2
  var EXT_HOWTO_NAME = "HowTo System";
3
3
  var EXT_HOWTO_DESC = "Step-by-step workflow system with pre and post condition checks";
4
4
  var i18n_en_default = {
5
5
  EXT_HOWTO_NAME,
6
6
  EXT_HOWTO_DESC
7
7
  };
8
- //#endregion
9
8
  export { EXT_HOWTO_DESC, EXT_HOWTO_NAME, i18n_en_default as default };
10
9
 
11
- //# sourceMappingURL=i18n.en-C6vlH27W.js.map
10
+ //# sourceMappingURL=i18n.en-DoB47dTB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.en-C6vlH27W.js","names":[],"sources":["../src/i18n.en.json"],"sourcesContent":["{\n \"EXT_HOWTO_NAME\": \"HowTo System\",\n \"EXT_HOWTO_DESC\": \"Step-by-step workflow system with pre and post condition checks\"\n}\n"],"mappings":""}
1
+ {"version":3,"file":"i18n.en-DoB47dTB.js","names":[],"sources":["../src/i18n.en.json"],"sourcesContent":["{\n \"EXT_HOWTO_NAME\": \"HowTo System\",\n \"EXT_HOWTO_DESC\": \"Step-by-step workflow system with pre and post condition checks\"\n}\n"],"mappings":""}
package/dist/index.js CHANGED
@@ -1,19 +1,18 @@
1
1
  import { extensionRegistry, i18n } from "@eclipse-docks/core";
2
2
  import pkg from "../package.json";
3
- //#region src/index.ts
3
+ // src/index.ts
4
4
  var t = await i18n(/* #__PURE__ */ Object.assign({
5
- "./i18n.de.json": () => import("./i18n.de-6a7MkAVi.js"),
6
- "./i18n.en.json": () => import("./i18n.en-C6vlH27W.js")
5
+ "./i18n.de.json": () => import("./i18n.de-CmqGh2TT.js"),
6
+ "./i18n.en.json": () => import("./i18n.en-DoB47dTB.js")
7
7
  }), true);
8
8
  extensionRegistry.registerExtension({
9
9
  id: pkg.name,
10
10
  name: t.EXT_HOWTO_NAME,
11
11
  description: t.EXT_HOWTO_DESC,
12
- loader: () => import("./howto-extension-fQQtPaor.js"),
12
+ loader: () => import("./howto-extension-BbJ7J894.js"),
13
13
  icon: "list-check",
14
14
  experimental: true,
15
15
  dependencies: ["@eclipse-docks/extension-ai-system"]
16
16
  });
17
- //#endregion
18
17
 
19
18
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-docks/extension-howto-system",
3
- "version": "0.8.12",
3
+ "version": "0.8.14",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "exports": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"howto-extension-fQQtPaor.js","names":["logger","getAppName"],"sources":["../src/howto-service.ts","../src/contributions/onboarding-howto-contributions.ts","../src/contributions/ai-setup-howto-contributions.ts","../src/howto-panel.ts","../src/howto-extension.ts"],"sourcesContent":["import { contributionRegistry, TOPIC_CONTRIBUTEIONS_CHANGED } from '@eclipse-docks/core';\nimport { HowToContribution, HowToStep } from './howto-contribution';\nimport { subscribe } from '@eclipse-docks/core';\nimport { createLogger } from '@eclipse-docks/core';\nimport { Signal } from '@lit-labs/signals';\n\nconst logger = createLogger('HowToService');\n\nexport const HOWTO_CONTRIBUTION_TARGET = 'system.howtos';\n\n/**\n * HowTo Service\n * \n * Manages HowTo contributions by reading from the contribution registry.\n * Provides methods to retrieve and manage workflows.\n */\nexport class HowToService {\n private contributions: Map<string, HowToContribution> = new Map();\n\n constructor() {\n // Load initial contributions\n this.loadContributions();\n\n // Subscribe to contribution changes\n subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {\n if (event.target === HOWTO_CONTRIBUTION_TARGET) {\n this.loadContributions();\n }\n });\n }\n\n /**\n * Load contributions from the contribution registry\n */\n private loadContributions(): void {\n const contributions = contributionRegistry.getContributions(HOWTO_CONTRIBUTION_TARGET) as HowToContribution[];\n \n this.contributions.clear();\n \n for (const contribution of contributions) {\n // Validate contribution\n if (!contribution.id) {\n logger.warn('HowTo contribution missing id, skipping');\n continue;\n }\n\n if (!contribution.label) {\n // Use title as label if label is not provided\n // Handle both string and function types\n const title = typeof contribution.title === 'function' \n ? contribution.title() \n : contribution.title;\n contribution.label = title;\n }\n\n if (!contribution.steps || contribution.steps.length === 0) {\n logger.warn(`HowTo contribution \"${contribution.id}\" has no steps, skipping`);\n continue;\n }\n\n // Validate step IDs are unique\n const stepIds = new Set<string>();\n for (const step of contribution.steps) {\n if (stepIds.has(step.id)) {\n logger.warn(`HowTo contribution \"${contribution.id}\" has duplicate step ID: \"${step.id}\"`);\n continue;\n }\n stepIds.add(step.id);\n }\n\n this.contributions.set(contribution.id, contribution);\n const title = typeof contribution.title === 'function' \n ? contribution.title() \n : contribution.title;\n logger.debug(`Loaded HowTo contribution: ${title} (${contribution.id})`);\n }\n\n logger.info(`Loaded ${this.contributions.size} HowTo contributions`);\n }\n\n /**\n * Get a HowTo Contribution by ID\n * \n * @param contributionId The ID of the contribution\n * @returns The contribution or undefined if not found\n */\n getContribution(contributionId: string): HowToContribution | undefined {\n return this.contributions.get(contributionId);\n }\n\n /**\n * Get all registered HowTo Contributions\n * \n * @returns Array of all contributions\n */\n getAllContributions(): HowToContribution[] {\n return Array.from(this.contributions.values());\n }\n\n /**\n * Get HowTo Contributions by category\n * \n * @param category The category to filter by\n * @returns Array of contributions in the category\n */\n getContributionsByCategory(category: string): HowToContribution[] {\n return Array.from(this.contributions.values())\n .filter(contrib => contrib.category === category);\n }\n\n /**\n * Check if a contribution exists\n * \n * @param contributionId The ID of the contribution\n * @returns True if the contribution exists\n */\n hasContribution(contributionId: string): boolean {\n return this.contributions.has(contributionId);\n }\n}\n\nexport const howToService = new HowToService();\n\n","import { contributionRegistry, workspaceService, File, TOPIC_WORKSPACE_CHANGED, TOPIC_WORKSPACE_CONNECTED, activeEditorSignal, partDirtySignal, subscribe, appLoaderService } from '@eclipse-docks/core';\nimport type { EditorContentProvider } from '@eclipse-docks/core';\nimport { watchSignal } from '@eclipse-docks/core';\nimport { HOWTO_CONTRIBUTION_TARGET } from '../howto-service';\nimport type { HowToContribution, HowToContext } from '../howto-contribution';\n\nconst ONBOARDING_FILE_NAME = 'welcome.txt';\n\nasync function getOnboardingFilePath(): Promise<string | null> {\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) return null;\n const folders = await workspaceService.getFolders();\n if (folders.length === 0) return null;\n const firstFolderName = folders[0].name;\n return `${firstFolderName}/${ONBOARDING_FILE_NAME}`;\n}\n\n/**\n * Type guard to check if an editor implements EditorContentProvider\n */\nfunction isEditorContentProvider(editor: any): editor is EditorContentProvider {\n return editor &&\n typeof editor.getFilePath === 'function';\n}\n\n/**\n * Checks if a workspace is selected\n */\nasync function isWorkspaceSelected(): Promise<boolean> {\n return workspaceService.isConnected();\n}\n\n/**\n * Checks if the onboarding file exists\n */\nasync function onboardingFileExists(): Promise<boolean> {\n const path = await getOnboardingFilePath();\n if (!path) return false;\n const workspace = await workspaceService.getWorkspace();\n if (!workspace) return false;\n try {\n const resource = await workspace.getResource(path);\n return resource instanceof File;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if the onboarding file is open in an editor\n */\nfunction isOnboardingFileOpen(): boolean {\n const activeEditor = activeEditorSignal.get();\n if (!activeEditor || !isEditorContentProvider(activeEditor)) {\n return false;\n }\n const filePath = activeEditor.getFilePath();\n return filePath === ONBOARDING_FILE_NAME || filePath?.endsWith('/' + ONBOARDING_FILE_NAME) === true;\n}\n\n/**\n * Checks if the active editor is dirty (has unsaved changes)\n * Returns true only if the onboarding file is open AND dirty\n */\nfunction isActiveEditorDirty(): boolean {\n if (!isOnboardingFileOpen()) return false;\n \n const activeEditor = activeEditorSignal.get();\n if (!activeEditor) return false;\n \n return activeEditor.isDirty() === true;\n}\n\n/**\n * Checks if the active editor is clean (no unsaved changes)\n * Returns true only if the onboarding file is open AND not dirty\n */\nfunction isActiveEditorClean(): boolean {\n if (!isOnboardingFileOpen()) return false;\n \n const activeEditor = activeEditorSignal.get();\n if (!activeEditor) return false;\n \n return activeEditor.isDirty() === false;\n}\n\n/**\n * Checks if the onboarding file is closed (not open in any editor)\n */\nfunction isOnboardingFileClosed(): boolean {\n return !isOnboardingFileOpen();\n}\n\n// Get current app name for the title\nfunction getAppName(): string {\n const currentApp = appLoaderService.getCurrentApp();\n return currentApp?.name || 'AppSpace';\n}\n\n// Create the onboarding HowTo contribution\n// Using callback functions so the app name is read when the HowTo is displayed\nconst onboardingContribution: HowToContribution = {\n id: 'docks.onboarding',\n title: () => `Welcome to ${getAppName()}`,\n description: () => `Get started with ${getAppName()} by learning the basics of workspace and file management`,\n icon: 'graduation-cap',\n // label will be set from title in howto-service.ts\n label: '',\n category: 'Getting Started',\n initialize: (context: HowToContext) => {\n // Set up subscriptions for workspace and editor changes\n const cleanups: (() => void)[] = [];\n\n // Subscribe to workspace events\n subscribe(TOPIC_WORKSPACE_CHANGED, () => {\n context.requestUpdate();\n });\n\n subscribe(TOPIC_WORKSPACE_CONNECTED, () => {\n context.requestUpdate();\n });\n\n // Watch editor signals\n cleanups.push(\n watchSignal(activeEditorSignal, () => {\n context.requestUpdate();\n })\n );\n\n cleanups.push(\n watchSignal(partDirtySignal, () => {\n context.requestUpdate();\n })\n );\n\n // Return cleanup function\n return () => {\n cleanups.forEach(cleanup => cleanup());\n };\n },\n steps: [\n {\n id: 'create-text-file',\n title: 'Create welcome.txt',\n description: 'Create a new text file called \"welcome.txt\" in your workspace. If you don\\'t have a workspace selected, choose one first.',\n preCondition: async () => {\n // Workspace must be selected\n return await isWorkspaceSelected();\n },\n postCondition: async () => {\n return await onboardingFileExists();\n },\n command: 'touch',\n commandParams: async () => {\n const path = await getOnboardingFilePath();\n return path ? {\n path,\n contents: 'Welcome to AppSpace!\\n\\nThis is your first file. You can edit it and save your changes.'\n } : {};\n }\n },\n {\n id: 'open-text-file',\n title: 'Open welcome.txt',\n description: 'Open the \"welcome.txt\" file in the editor.',\n preCondition: async () => {\n return await onboardingFileExists();\n },\n postCondition: () => {\n return isOnboardingFileOpen();\n },\n command: 'open_editor',\n commandParams: async () => {\n const path = await getOnboardingFilePath();\n return path ? { path } : {};\n }\n },\n {\n id: 'edit-and-save',\n title: 'Type something and save',\n description: 'Type some text in the editor to modify the file, then save it using Ctrl+S or the save button.',\n preCondition: () => {\n return isOnboardingFileOpen();\n },\n postCondition: () => {\n // File must be open, was dirty (edited), and is now clean (saved)\n // Check that file is open and clean (saved)\n return isActiveEditorClean();\n },\n // No command - user manually edits and saves\n },\n {\n id: 'close-text-file',\n title: 'Close the file',\n description: 'Close the editor tab by clicking the X button on the tab.',\n preCondition: () => {\n return isOnboardingFileOpen();\n },\n postCondition: () => {\n return isOnboardingFileClosed();\n },\n // No command - user manually closes the tab\n }\n ]\n};\n\n// Register the contribution\ncontributionRegistry.registerContribution<HowToContribution>(HOWTO_CONTRIBUTION_TARGET, onboardingContribution);\n\n","import {\n contributionRegistry,\n activeEditorSignal,\n appLoaderService,\n partDirtySignal,\n subscribe,\n unsubscribe,\n watchSignal,\n} from '@eclipse-docks/core';\nimport {\n AI_SETTINGS_KEY,\n OPEN_AI_SETTINGS_COMMAND,\n TOPIC,\n cognitiveRuntime,\n} from '@eclipse-docks/extension-ai-system/api';\nimport { HOWTO_CONTRIBUTION_TARGET } from '../howto-service';\nimport type { HowToContribution, HowToContext } from '../howto-contribution';\n\nfunction isAIConfigEditorOpen(): boolean {\n const activeEditor = activeEditorSignal.get() as {\n input?: { key?: string };\n tagName?: string;\n localName?: string;\n } | null;\n if (!activeEditor) return false;\n if (activeEditor.input?.key === AI_SETTINGS_KEY) return true;\n const tag = (activeEditor.tagName || activeEditor.localName || '').toLowerCase();\n return tag === 'docks-cognitive-settings-editor';\n}\n\nasync function isLLMProviderConfigured(): Promise<boolean> {\n try {\n await cognitiveRuntime.whenReady();\n const settings = cognitiveRuntime.getProvidersSettings();\n if (!settings.defaultProviderId) return false;\n const provider = settings.providers.find((p) => p.id === settings.defaultProviderId);\n if (!provider?.enabled) return false;\n // Local providers (ollama/webllm) may not need a key.\n if (!provider.apiKey.trim()) {\n return /ollama|webllm|localhost|127\\.0\\.0\\.1/i.test(`${provider.id} ${provider.baseUrl}`);\n }\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isAIConfigEditorDirty(): boolean {\n const activeEditor = activeEditorSignal.get() as { isDirty?: () => boolean } | null;\n if (!activeEditor || !isAIConfigEditorOpen()) return false;\n return activeEditor.isDirty?.() === true;\n}\n\nfunction isAIConfigEditorSaved(): boolean {\n return isAIConfigEditorOpen() && !isAIConfigEditorDirty();\n}\n\nfunction isAIConfigEditorClosed(): boolean {\n return !isAIConfigEditorOpen();\n}\n\nasync function hasTypedInChat(): Promise<boolean> {\n try {\n await cognitiveRuntime.whenReady();\n for (const session of cognitiveRuntime.sessions.list()) {\n const hasUserMessage = session.history.some(\n (msg) =>\n msg.role === 'user' &&\n msg.parts.some((part) => part.type === 'text' && part.text.trim() !== ''),\n );\n if (hasUserMessage) return true;\n }\n return false;\n } catch {\n return false;\n }\n}\n\nfunction getAppName(): string {\n const currentApp = appLoaderService.getCurrentApp();\n return currentApp?.name || 'AppSpace';\n}\n\nconst aiSetupContribution: HowToContribution = {\n id: 'docks.ai-setup',\n title: () => `Set up AI in ${getAppName()}`,\n description: () => `Configure an LLM provider to enable AI chat features in ${getAppName()}`,\n icon: 'robot',\n label: '',\n category: 'Getting Started',\n initialize: (context: HowToContext) => {\n const cleanups: Array<() => void> = [];\n\n cleanups.push(watchSignal(activeEditorSignal, () => context.requestUpdate()));\n cleanups.push(watchSignal(partDirtySignal, () => context.requestUpdate()));\n const providersToken = subscribe(TOPIC.providersChanged, () => context.requestUpdate());\n const sessionToken = subscribe(TOPIC.sessionChanged, () => context.requestUpdate());\n cleanups.push(() => unsubscribe(providersToken), () => unsubscribe(sessionToken));\n\n return () => {\n cleanups.forEach((cleanup) => cleanup());\n };\n },\n steps: [\n {\n id: 'open-ai-settings',\n title: 'Open AI Settings',\n description:\n 'Open the AI settings editor from the chat gear menu or the command palette.',\n preCondition: () => true,\n postCondition: () => isAIConfigEditorOpen(),\n command: OPEN_AI_SETTINGS_COMMAND,\n },\n {\n id: 'configure-llm-provider',\n title: 'Configure LLM Provider',\n description:\n 'Select a provider as default and enter an API key when required. Save your changes.',\n preCondition: () => isAIConfigEditorOpen(),\n postCondition: async () => {\n const configured = await isLLMProviderConfigured();\n const saved = isAIConfigEditorSaved();\n return configured && saved;\n },\n },\n {\n id: 'save-and-close',\n title: 'Save and Close',\n description: 'Save your changes (if not already saved) and close the AI settings editor tab.',\n preCondition: () => isAIConfigEditorOpen(),\n postCondition: () => isAIConfigEditorClosed(),\n },\n {\n id: 'type-in-chat',\n title: 'Type in Chat',\n description: 'Open the AI chat view and type a message to test your AI configuration.',\n preCondition: async () => await isLLMProviderConfigured(),\n postCondition: async () => await hasTypedInChat(),\n },\n ],\n};\n\ncontributionRegistry.registerContribution<HowToContribution>(HOWTO_CONTRIBUTION_TARGET, aiSetupContribution);\n","import { css, html, nothing } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { PropertyValues } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { DocksWidget } from '@eclipse-docks/core';\nimport { howToService } from './howto-service';\nimport { HowToContribution, HowToStep } from './howto-contribution';\nimport { subscribe } from '@eclipse-docks/core';\nimport { commandRegistry } from '@eclipse-docks/core';\nimport { toastError, toastInfo } from '@eclipse-docks/core';\nimport { createRef, ref, Ref } from 'lit/directives/ref.js';\nimport { TOPIC_CONTRIBUTEIONS_CHANGED } from '@eclipse-docks/core';\nimport { HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nimport { appSettings } from '@eclipse-docks/core';\nimport { workspaceService, TOPIC_WORKSPACE_CONNECTED } from '@eclipse-docks/core';\n\n// Event topic for showing the HowTo panel\nexport const TOPIC_SHOW_HOWTO_PANEL = 'howto/show-panel';\nexport const TOPIC_TOGGLE_HOWTO_PANEL = 'howto/toggle-panel';\n\n// Constants\nconst SETTINGS_KEY = 'howto-panel';\nconst DEFAULT_POSITION = { x: 100, y: 100 };\nconst DEFAULT_PANEL_SIZE = { width: 400, height: 300 };\n\ninterface StepState {\n step: HowToStep;\n status: 'pending' | 'active' | 'completed' | 'skipped' | 'failed';\n preConditionMet?: boolean;\n postConditionMet?: boolean;\n}\n\n@customElement('docks-howto-panel')\nexport class DocksHowToPanel extends DocksWidget {\n @state()\n private contributions: HowToContribution[] = [];\n\n @state()\n private activeContributionId: string | null = null;\n\n @state()\n private stepStates: Map<string, StepState[]> = new Map();\n\n @state()\n private isMinimized: boolean = false;\n\n @state()\n private isVisible: boolean = false;\n\n @state()\n private positionX: number = DEFAULT_POSITION.x;\n\n @state()\n private positionY: number = DEFAULT_POSITION.y;\n\n private isDragging: boolean = false;\n\n @state()\n private dragPreviewPosition: { x: number; y: number } | null = null;\n\n private dragStartPosition: { x: number; y: number } = { x: 0, y: 0 };\n\n private panelRef: Ref<HTMLElement> = createRef();\n private howtoCleanup?: () => void;\n\n protected async doBeforeUI() {\n this.loadContributions();\n \n subscribe(TOPIC_CONTRIBUTEIONS_CHANGED, (event: any) => {\n if (event.target === HOWTO_CONTRIBUTION_TARGET) {\n this.loadContributions();\n this.requestUpdate();\n }\n });\n\n // Subscribe to show/toggle panel events\n subscribe(TOPIC_SHOW_HOWTO_PANEL, () => this.showPanel());\n subscribe(TOPIC_TOGGLE_HOWTO_PANEL, () => this.toggleVisibility());\n\n // Load position and visibility from dialogsettings\n await this.loadSettings();\n \n // If no workspace is selected and panel wasn't explicitly hidden, show it by default\n const hasWorkspace = workspaceService.isConnected();\n if (!hasWorkspace && this.isVisible === false) {\n // Check if user has explicitly hidden it (if settings exist and visible is false)\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (!settings || settings.visible === undefined) {\n // No explicit preference, show panel when no workspace\n this.isVisible = true;\n await this.saveSettings();\n }\n }\n \n // Subscribe to workspace connection to hide panel when workspace is connected (if it was auto-shown)\n subscribe(TOPIC_WORKSPACE_CONNECTED, () => {\n // Only auto-hide if it was auto-shown (no explicit visibility setting)\n const checkAutoHide = async () => {\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (!settings || settings.visible === undefined) {\n // Was auto-shown, can auto-hide when workspace connects\n // But let's keep it visible - user might want to see howtos even with workspace\n }\n };\n checkAutoHide();\n });\n }\n\n private boundHandleDragMove?: (e: MouseEvent) => void;\n private boundHandleDragEnd?: () => void;\n\n protected doInitUI() {\n // Setup document-level drag handlers (these are always available)\n this.boundHandleDragMove = this.handleDragMove.bind(this);\n this.boundHandleDragEnd = this.handleDragEnd.bind(this);\n document.addEventListener('mousemove', this.boundHandleDragMove);\n document.addEventListener('mouseup', this.boundHandleDragEnd);\n }\n\n protected firstUpdated(_changedProperties: PropertyValues) {\n super.firstUpdated(_changedProperties);\n }\n\n private loadContributions() {\n this.contributions = howToService.getAllContributions();\n }\n\n private async loadSettings() {\n const settings = await appSettings.getDialogSetting(SETTINGS_KEY);\n if (settings) {\n if (settings.position) {\n this.positionX = settings.position.x || DEFAULT_POSITION.x;\n this.positionY = settings.position.y || DEFAULT_POSITION.y;\n }\n if (settings.visible !== undefined) {\n this.isVisible = settings.visible;\n }\n }\n }\n\n private async saveSettings() {\n await appSettings.setDialogSetting(SETTINGS_KEY, {\n position: { x: this.positionX, y: this.positionY },\n visible: this.isVisible\n });\n }\n\n private handleDragStart = (e: MouseEvent) => {\n const target = e.target as HTMLElement;\n if (this.isDragTarget(target) || !this.panelRef.value) {\n return;\n }\n \n const rect = this.panelRef.value.getBoundingClientRect();\n this.dragStartPosition = {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top\n };\n this.isDragging = true;\n this.dragPreviewPosition = { x: this.positionX, y: this.positionY };\n this.requestUpdate();\n e.preventDefault();\n e.stopPropagation();\n }\n\n private isDragTarget(target: HTMLElement): boolean {\n return !!(target.closest('.header-actions') || target.closest('wa-button'));\n }\n\n private getViewportBounds() {\n const panelWidth = this.panelRef.value?.offsetWidth || DEFAULT_PANEL_SIZE.width;\n const panelHeight = this.panelRef.value?.offsetHeight || DEFAULT_PANEL_SIZE.height;\n return {\n maxX: window.innerWidth - panelWidth,\n maxY: window.innerHeight - panelHeight\n };\n }\n\n private handleDragMove = (e: MouseEvent) => {\n if (!this.isDragging || !this.dragPreviewPosition) {\n return;\n }\n \n const bounds = this.getViewportBounds();\n const newX = Math.max(0, Math.min(e.clientX - this.dragStartPosition.x, bounds.maxX));\n const newY = Math.max(0, Math.min(e.clientY - this.dragStartPosition.y, bounds.maxY));\n \n if (this.dragPreviewPosition.x !== newX || this.dragPreviewPosition.y !== newY) {\n this.dragPreviewPosition = { x: newX, y: newY };\n this.requestUpdate();\n }\n }\n\n private handleDragEnd = async () => {\n if (!this.isDragging || !this.dragPreviewPosition) {\n return;\n }\n \n this.isDragging = false;\n const previewPos = this.dragPreviewPosition;\n this.dragPreviewPosition = null;\n \n this.positionX = previewPos.x;\n this.positionY = previewPos.y;\n \n await this.saveSettings();\n this.requestUpdate();\n }\n\n private async startHowTo(contributionId: string) {\n const contribution = howToService.getContribution(contributionId);\n if (!contribution) {\n toastError(`HowTo \"${contributionId}\" not found`);\n return;\n }\n\n // Clean up previous HowTo\n this.cleanupHowTo();\n\n this.activeContributionId = contributionId;\n this.isMinimized = false;\n\n // Initialize step states\n const states: StepState[] = contribution.steps.map(step => ({\n step,\n status: 'pending'\n }));\n\n this.stepStates.set(contributionId, states);\n \n // Call HowTo's initialize function if provided\n if (contribution.initialize) {\n const context = {\n requestUpdate: () => this.recheckActiveStepConditions(),\n contributionId: contributionId\n };\n this.howtoCleanup = contribution.initialize(context) || undefined;\n }\n \n this.requestUpdate();\n\n // Check initial pre-conditions\n await this.checkPreConditions(contributionId, 0);\n }\n\n private cleanupHowTo() {\n if (this.howtoCleanup) {\n this.howtoCleanup();\n this.howtoCleanup = undefined;\n }\n }\n\n private getStepState(contributionId: string, stepIndex: number): StepState | null {\n const states = this.stepStates.get(contributionId);\n return states && stepIndex < states.length ? states[stepIndex] : null;\n }\n\n private async checkPreConditions(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!state.step.preCondition) {\n state.preConditionMet = true;\n this.requestUpdate();\n return;\n }\n\n try {\n state.preConditionMet = await state.step.preCondition();\n this.requestUpdate();\n } catch (error) {\n console.error(`Pre-condition check failed for step ${state.step.id}:`, error);\n state.preConditionMet = false;\n this.requestUpdate();\n }\n }\n\n private async checkPostConditions(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!state.step.postCondition) {\n this.completeStep(contributionId, stepIndex);\n return;\n }\n\n try {\n const result = await state.step.postCondition();\n state.postConditionMet = result;\n state.status = result ? 'completed' : 'failed';\n \n if (result) {\n this.activateNextStep(contributionId, stepIndex);\n }\n this.requestUpdate();\n } catch (error) {\n console.error(`Post-condition check failed for step ${state.step.id}:`, error);\n state.postConditionMet = false;\n state.status = 'failed';\n this.requestUpdate();\n }\n }\n\n private completeStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n \n state.status = 'completed';\n this.activateNextStep(contributionId, stepIndex);\n this.requestUpdate();\n }\n\n private async activateNextStep(contributionId: string, stepIndex: number) {\n const states = this.stepStates.get(contributionId);\n if (!states || stepIndex + 1 >= states.length) return;\n \n const nextState = states[stepIndex + 1];\n nextState.status = 'active';\n await this.checkPreConditions(contributionId, stepIndex + 1);\n }\n\n /**\n * Re-checks conditions for active and pending steps when workspace or editor state changes\n */\n private async recheckActiveStepConditions() {\n if (!this.activeContributionId) return;\n\n const states = this.stepStates.get(this.activeContributionId);\n if (!states) return;\n\n // Find the active step\n const activeStepIndex = states.findIndex(state => state.status === 'active');\n \n if (activeStepIndex !== -1) {\n const activeState = states[activeStepIndex];\n const step = activeState.step;\n\n // Re-check post-condition if it exists and step is active\n if (step.postCondition) {\n try {\n const result = await step.postCondition();\n if (result && activeState.status === 'active') {\n // Post-condition is met, complete the step and move to next\n await this.checkPostConditions(this.activeContributionId, activeStepIndex);\n return; // Step completed, no need to check pre-conditions\n }\n } catch (error) {\n // Ignore errors in post-condition checks during re-evaluation\n }\n }\n }\n\n // Re-check pre-conditions for pending steps (they might become available)\n for (let i = 0; i < states.length; i++) {\n const state = states[i];\n if (state.status === 'pending' && state.step.preCondition) {\n // Re-check pre-condition for pending steps\n await this.checkPreConditions(this.activeContributionId, i);\n }\n }\n\n this.requestUpdate();\n }\n\n private async executeStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state) return;\n\n if (!await this.validatePreConditions(state, contributionId, stepIndex)) {\n return;\n }\n\n state.status = 'active';\n this.requestUpdate();\n\n if (state.step.command && !await this.executeStepCommand(state)) {\n return;\n }\n\n await this.checkPostConditions(contributionId, stepIndex);\n }\n\n private async validatePreConditions(state: StepState, contributionId: string, stepIndex: number): Promise<boolean> {\n if (!state.step.preCondition) {\n return true;\n }\n\n if (state.preConditionMet === undefined || state.preConditionMet === false) {\n await this.checkPreConditions(contributionId, stepIndex);\n }\n\n if (state.preConditionMet !== true) {\n toastError(`Pre-conditions not met for step: ${state.step.title}`);\n return false;\n }\n\n return true;\n }\n\n private async executeStepCommand(state: StepState): Promise<boolean> {\n if (!state.step.command) {\n return true;\n }\n\n try {\n const rawParams = state.step.commandParams;\n const params = typeof rawParams === 'function' ? await rawParams() : (rawParams || {});\n const execContext = commandRegistry.createExecutionContext(params);\n await commandRegistry.execute(state.step.command, execContext);\n return true;\n } catch (error) {\n console.error(`Failed to execute command for step ${state.step.id}:`, error);\n toastError(`Failed to execute step: ${state.step.title}`);\n state.status = 'failed';\n this.requestUpdate();\n return false;\n }\n }\n\n private async runStepCommand(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state || !state.step.command) {\n return;\n }\n\n // Check pre-conditions if they exist\n if (state.step.preCondition) {\n const preConditionMet = await state.step.preCondition();\n if (!preConditionMet) {\n toastError(`Pre-conditions not met for step: ${state.step.title}`);\n return;\n }\n }\n\n // Execute the command\n const success = await this.executeStepCommand(state);\n if (success) {\n // Check post-conditions after command execution\n await this.checkPostConditions(contributionId, stepIndex);\n }\n }\n\n private skipStep(contributionId: string, stepIndex: number) {\n const state = this.getStepState(contributionId, stepIndex);\n if (!state || !state.step.optional) return;\n\n state.status = 'skipped';\n this.activateNextStep(contributionId, stepIndex);\n this.requestUpdate();\n }\n\n private closeHowTo() {\n this.cleanupHowTo();\n this.activeContributionId = null;\n this.stepStates.clear();\n this.requestUpdate();\n }\n\n private toggleMinimize() {\n this.isMinimized = !this.isMinimized;\n this.requestUpdate();\n }\n\n private async showPanel() {\n this.isVisible = true;\n this.isMinimized = false;\n await this.saveSettings();\n this.requestUpdate();\n }\n\n private async hidePanel() {\n this.isVisible = false;\n await this.saveSettings();\n this.requestUpdate();\n }\n\n private async toggleVisibility() {\n if (this.isVisible) {\n await this.hidePanel();\n } else {\n await this.showPanel();\n }\n }\n\n private renderStep(state: StepState, index: number, contributionId: string) {\n const { step, status, preConditionMet, postConditionMet } = state;\n const isActive = status === 'active';\n const isCompleted = status === 'completed';\n const isFailed = status === 'failed';\n const isPending = status === 'pending';\n const isSkipped = status === 'skipped';\n\n return html`\n <div class=\"step ${status}\" ?data-active=${isActive}>\n <div class=\"step-header\">\n <div class=\"step-number\">${index + 1}</div>\n <div class=\"step-title\">${step.title}</div>\n <div class=\"step-status\">\n ${step.command ? html`\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${(e: Event) => {\n e.stopPropagation();\n this.runStepCommand(contributionId, index);\n }}\n title=\"Run step command\"\n >\n <wa-icon name=\"play\"></wa-icon>\n </wa-button>\n ` : nothing}\n ${isCompleted ? html`<wa-icon name=\"check-circle\" class=\"status-icon completed\"></wa-icon>` : nothing}\n ${isFailed ? html`<wa-icon name=\"xmark-circle\" class=\"status-icon failed\"></wa-icon>` : nothing}\n ${isSkipped ? html`<wa-icon name=\"minus-circle\" class=\"status-icon skipped\"></wa-icon>` : nothing}\n ${isPending ? html`<wa-icon name=\"circle\" class=\"status-icon pending\"></wa-icon>` : nothing}\n ${isActive ? html`<wa-icon name=\"play-circle\" class=\"status-icon active\"></wa-icon>` : nothing}\n </div>\n </div>\n <div class=\"step-description\">${step.description}</div>\n ${step.preCondition && preConditionMet !== undefined ? html`\n <div class=\"condition pre-condition ${preConditionMet ? 'met' : 'not-met'}\">\n <wa-icon name=\"${preConditionMet ? 'check' : 'xmark'}\"></wa-icon>\n <span>Pre-condition: ${preConditionMet ? 'Met' : 'Not met'}</span>\n </div>\n ` : nothing}\n ${step.postCondition && postConditionMet !== undefined ? html`\n <div class=\"condition post-condition ${postConditionMet ? 'met' : 'not-met'}\">\n <wa-icon name=\"${postConditionMet ? 'check' : 'xmark'}\"></wa-icon>\n <span>Post-condition: ${postConditionMet ? 'Met' : 'Not met'}</span>\n </div>\n ` : nothing}\n ${isActive && step.optional ? html`\n <div class=\"step-actions\">\n <wa-button size=\"s\" appearance=\"outline\" @click=${() => this.skipStep(contributionId, index)}>\n <wa-icon name=\"forward\"></wa-icon>\n Skip\n </wa-button>\n </div>\n ` : nothing}\n </div>\n `;\n }\n\n render() {\n if (!this.isVisible) {\n return nothing;\n }\n\n const activeContribution = this.activeContributionId\n ? howToService.getContribution(this.activeContributionId)\n : null;\n\n const activeStepStates = this.activeContributionId\n ? this.stepStates.get(this.activeContributionId) || []\n : [];\n\n return html`\n ${this.dragPreviewPosition ? html`\n <div \n class=\"howto-panel-drag-preview\"\n style=${styleMap({\n left: `${this.dragPreviewPosition.x}px`,\n top: `${this.dragPreviewPosition.y}px`,\n width: `${this.panelRef.value?.offsetWidth || DEFAULT_PANEL_SIZE.width}px`,\n height: `${this.panelRef.value?.offsetHeight || DEFAULT_PANEL_SIZE.height}px`,\n display: 'block',\n visibility: 'visible'\n })}\n ></div>\n ` : nothing}\n <div \n class=\"howto-panel ${this.isMinimized ? 'minimized' : ''} ${this.dragPreviewPosition ? 'dragging' : ''}\"\n style=${styleMap({\n left: `${this.positionX}px`,\n top: `${this.positionY}px`,\n transform: 'translateZ(0)'\n })}\n ${ref(this.panelRef)}\n >\n <div class=\"panel-header\" @mousedown=${this.handleDragStart}>\n <div class=\"header-title\">\n <wa-icon name=\"list-check\"></wa-icon>\n <span>HowTo Workflows</span>\n </div>\n <div class=\"header-actions\" @mousedown=${(e: MouseEvent) => e.stopPropagation()}>\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${this.toggleMinimize}\n title=\"${this.isMinimized ? 'Expand' : 'Minimize'}\"\n >\n <wa-icon name=\"${this.isMinimized ? 'chevron-up' : 'chevron-down'}\"></wa-icon>\n </wa-button>\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${this.hidePanel}\n title=\"Hide Panel\"\n >\n <wa-icon name=\"xmark\"></wa-icon>\n </wa-button>\n </div>\n </div>\n \n ${!this.isMinimized ? html`\n <div class=\"panel-content\">\n ${activeContribution ? html`\n <div class=\"active-workflow\">\n <div class=\"workflow-header\">\n <div class=\"workflow-title-section\">\n <h3>${typeof activeContribution.title === 'function' \n ? activeContribution.title() \n : activeContribution.title}</h3>\n ${activeContribution.description ? html`\n <p class=\"workflow-description\">${typeof activeContribution.description === 'function'\n ? activeContribution.description()\n : activeContribution.description}</p>\n ` : nothing}\n </div>\n <wa-button \n size=\"s\" \n appearance=\"plain\" \n @click=${this.closeHowTo}\n title=\"Close HowTo\"\n >\n <wa-icon name=\"xmark\"></wa-icon>\n </wa-button>\n </div>\n <div class=\"steps-list\">\n ${activeStepStates.map((state, index) => \n this.renderStep(state, index, this.activeContributionId!)\n )}\n </div>\n </div>\n ` : html`\n <div class=\"workflows-list\">\n <h3>Available Workflows</h3>\n ${this.contributions.length === 0 ? html`\n <div class=\"empty-state\">\n <wa-icon name=\"list-check\" style=\"font-size: 2em; opacity: 0.5; margin-bottom: 12px;\"></wa-icon>\n <p>No HowTo workflows available yet.</p>\n <p style=\"font-size: 0.9em; opacity: 0.7;\">Extensions can register workflows via the contribution registry.</p>\n </div>\n ` : this.contributions.map(contrib => {\n const title = typeof contrib.title === 'function' ? contrib.title() : contrib.title;\n const description = contrib.description \n ? (typeof contrib.description === 'function' ? contrib.description() : contrib.description)\n : null;\n return html`\n <div class=\"workflow-item\" @click=${() => this.startHowTo(contrib.id)}>\n ${contrib.icon ? html`\n <wa-icon name=\"${contrib.icon}\"></wa-icon>\n ` : html`\n <wa-icon name=\"list-check\"></wa-icon>\n `}\n <div class=\"workflow-info\">\n <div class=\"workflow-title\">${title}</div>\n ${description ? html`\n <div class=\"workflow-desc\">${description}</div>\n ` : nothing}\n <div class=\"workflow-meta\">${contrib.steps.length} step${contrib.steps.length !== 1 ? 's' : ''}</div>\n </div>\n </div>\n `})}\n </div>\n `}\n </div>\n ` : nothing}\n </div>\n `;\n }\n\n static styles = css`\n :host {\n display: block;\n position: fixed;\n z-index: 10000;\n pointer-events: none;\n }\n\n .howto-panel-drag-preview {\n position: fixed !important;\n border: 3px dashed var(--wa-color-primary-50, #0066cc) !important;\n background: var(--wa-color-primary-05, rgba(0, 102, 204, 0.05)) !important;\n border-radius: var(--wa-border-radius-medium, 8px);\n z-index: 10001 !important;\n pointer-events: none !important;\n opacity: 0.8 !important;\n box-sizing: border-box;\n display: block !important;\n visibility: visible !important;\n min-width: 100px;\n min-height: 100px;\n }\n\n :host-context(.wa-light) .howto-panel-drag-preview {\n background: var(--wa-color-primary-95);\n border-color: var(--wa-color-primary-50);\n }\n\n .howto-panel {\n position: fixed !important;\n width: 400px;\n max-height: 600px;\n background: var(--wa-color-surface-raised, var(--wa-color-neutral-05));\n border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-loud, var(--wa-color-neutral-25));\n border-radius: var(--wa-border-radius-medium, 8px);\n box-shadow: var(--wa-shadow-large, 0 8px 24px rgba(0, 0, 0, 0.8));\n pointer-events: all;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n }\n\n :host-context(.wa-light) .howto-panel {\n background: var(--wa-color-surface-raised, var(--wa-color-neutral-95));\n border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-75));\n box-shadow: var(--wa-shadow-large, 0 8px 24px rgba(0, 0, 0, 0.2));\n }\n\n .howto-panel.minimized {\n max-height: auto;\n }\n\n .howto-panel.dragging {\n opacity: 0.5;\n }\n\n .panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--wa-spacing-medium, 12px) var(--wa-spacing-large, 16px);\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));\n border-bottom: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-loud, var(--wa-color-neutral-25));\n cursor: move;\n user-select: none;\n }\n\n :host-context(.wa-light) .panel-header {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));\n border-bottom-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-75));\n }\n\n .header-title {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-small, 8px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .header-title {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .header-actions {\n display: flex;\n gap: var(--wa-spacing-x-small, 4px);\n }\n\n .panel-content {\n flex: 1;\n overflow-y: auto;\n padding: var(--wa-spacing-large, 16px);\n }\n\n .workflows-list h3 {\n margin: 0 0 var(--wa-spacing-medium, 12px) 0;\n font-size: var(--wa-font-size-medium, 14px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-80));\n }\n\n :host-context(.wa-light) .workflows-list h3 {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-20));\n }\n\n .workflow-item {\n display: flex;\n align-items: flex-start;\n gap: var(--wa-spacing-medium, 12px);\n padding: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-small, 8px);\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));\n border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-20));\n border-radius: var(--wa-border-radius-small, 6px);\n cursor: pointer;\n transition: all var(--wa-transition-medium, 0.2s);\n }\n\n :host-context(.wa-light) .workflow-item {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));\n border-color: var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-80));\n }\n\n .workflow-item:hover {\n background: var(--wa-color-mix-hover, var(--wa-color-neutral-15));\n border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-30));\n }\n\n :host-context(.wa-light) .workflow-item:hover {\n background: var(--wa-color-mix-hover, var(--wa-color-neutral-85));\n border-color: var(--wa-color-neutral-border-loud, var(--wa-color-neutral-70));\n }\n\n .workflow-info {\n flex: 1;\n }\n\n .workflow-title {\n font-weight: 600;\n margin-bottom: var(--wa-spacing-x-small, 4px);\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .workflow-title {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .workflow-desc {\n font-size: var(--wa-font-size-small, 12px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n margin-bottom: var(--wa-spacing-x-small, 4px);\n }\n\n :host-context(.wa-light) .workflow-desc {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .workflow-meta {\n font-size: var(--wa-font-size-x-small, 11px);\n color: var(--wa-color-text-quiet, var(--wa-color-neutral-60));\n }\n\n :host-context(.wa-light) .workflow-meta {\n color: var(--wa-color-text-quiet, var(--wa-color-neutral-40));\n }\n\n .active-workflow {\n display: flex;\n flex-direction: column;\n gap: var(--wa-spacing-large, 16px);\n }\n\n .workflow-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-medium, 12px);\n }\n\n .workflow-title-section {\n flex: 1;\n }\n\n .workflow-header h3 {\n margin: 0 0 var(--wa-spacing-small, 8px) 0;\n font-size: var(--wa-font-size-large, 16px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .workflow-header h3 {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .workflow-description {\n margin: 0;\n font-size: var(--wa-font-size-medium, 13px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n }\n\n :host-context(.wa-light) .workflow-description {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .steps-list {\n display: flex;\n flex-direction: column;\n gap: var(--wa-spacing-medium, 12px);\n }\n\n .step {\n padding: var(--wa-spacing-medium, 12px);\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-10));\n border: var(--wa-border-width-s, 1px) solid var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-20));\n border-radius: var(--wa-border-radius-small, 6px);\n transition: all var(--wa-transition-medium, 0.2s);\n }\n\n :host-context(.wa-light) .step {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-90));\n border-color: var(--wa-color-neutral-border-subtle, var(--wa-color-neutral-80));\n }\n\n .step[data-active=\"true\"] {\n border-color: var(--wa-color-primary-50);\n background: var(--wa-color-primary-05);\n }\n\n :host-context(.wa-light) .step[data-active=\"true\"] {\n background: var(--wa-color-primary-95);\n border-color: var(--wa-color-primary-50);\n }\n\n .step.completed {\n border-color: var(--wa-color-success-50);\n background: var(--wa-color-success-05);\n }\n\n :host-context(.wa-light) .step.completed {\n background: var(--wa-color-success-95);\n border-color: var(--wa-color-success-50);\n }\n\n .step.failed {\n border-color: var(--wa-color-danger-50);\n background: var(--wa-color-danger-05);\n }\n\n :host-context(.wa-light) .step.failed {\n background: var(--wa-color-danger-95);\n border-color: var(--wa-color-danger-50);\n }\n\n .step-header {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-medium, 12px);\n margin-bottom: var(--wa-spacing-small, 8px);\n }\n\n .step-number {\n width: 24px;\n height: 24px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-20));\n border-radius: 50%;\n font-size: var(--wa-font-size-small, 12px);\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-80));\n }\n\n :host-context(.wa-light) .step-number {\n background: var(--wa-color-surface-lowered, var(--wa-color-neutral-80));\n color: var(--wa-color-text-normal, var(--wa-color-neutral-20));\n }\n\n .step-title {\n flex: 1;\n font-weight: 600;\n color: var(--wa-color-text-normal, var(--wa-color-neutral-90));\n }\n\n :host-context(.wa-light) .step-title {\n color: var(--wa-color-text-normal, var(--wa-color-neutral-10));\n }\n\n .step-status {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-small, 8px);\n }\n\n .status-icon {\n width: 20px;\n height: 20px;\n }\n\n .status-icon.completed {\n color: var(--wa-color-success-50);\n }\n\n .status-icon.failed {\n color: var(--wa-color-danger-50);\n }\n\n .status-icon.skipped {\n color: var(--wa-color-neutral-50);\n }\n\n .status-icon.active {\n color: var(--wa-color-primary-50);\n }\n\n .status-icon.pending {\n color: var(--wa-color-neutral-50);\n }\n\n .step-description {\n font-size: var(--wa-font-size-medium, 13px);\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n margin-bottom: var(--wa-spacing-small, 8px);\n line-height: 1.4;\n }\n\n :host-context(.wa-light) .step-description {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .condition {\n display: flex;\n align-items: center;\n gap: var(--wa-spacing-x-small, 6px);\n font-size: var(--wa-font-size-small, 12px);\n padding: var(--wa-spacing-x-small, 6px) var(--wa-spacing-small, 8px);\n border-radius: var(--wa-border-radius-x-small, 4px);\n margin-bottom: var(--wa-spacing-small, 8px);\n }\n\n .condition.met {\n background: var(--wa-color-success-10);\n color: var(--wa-color-success-70);\n }\n\n :host-context(.wa-light) .condition.met {\n background: var(--wa-color-success-90);\n color: var(--wa-color-success-30);\n }\n\n .condition.not-met {\n background: var(--wa-color-danger-10);\n color: var(--wa-color-danger-70);\n }\n\n :host-context(.wa-light) .condition.not-met {\n background: var(--wa-color-danger-90);\n color: var(--wa-color-danger-30);\n }\n\n .step-actions {\n display: flex;\n gap: var(--wa-spacing-small, 8px);\n margin-top: var(--wa-spacing-small, 8px);\n }\n\n .empty-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: var(--wa-spacing-x-large, 40px) var(--wa-spacing-large, 20px);\n text-align: center;\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-70));\n }\n\n :host-context(.wa-light) .empty-state {\n color: var(--wa-color-text-subtle, var(--wa-color-neutral-30));\n }\n\n .empty-state p {\n margin: var(--wa-spacing-small, 8px) 0;\n }\n `;\n}\n\n","import { createLogger } from '@eclipse-docks/core';\nimport { rootContext } from '@eclipse-docks/core';\nimport { howToService } from './howto-service';\nimport { HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nimport './contributions/onboarding-howto-contributions';\nimport './contributions/ai-setup-howto-contributions';\nimport { TOPIC_SHOW_HOWTO_PANEL, TOPIC_TOGGLE_HOWTO_PANEL } from './howto-panel';\nimport { registerAll } from '@eclipse-docks/core';\nimport { publish } from '@eclipse-docks/core';\nimport { TOOLBAR_BOTTOM_END } from '@eclipse-docks/core';\nimport './howto-panel';\n\nconst logger = createLogger('HowToExtension');\n\n/**\n * HowTo System Extension\n * \n * Provides a system for registering and displaying step-by-step workflows\n * that guide users through specific processes with pre and post condition checks.\n * \n * Features:\n * - Register HowToContributions via contribution registry\n * - Floating, draggable UI panel\n * - Sequential step execution\n * - Pre and post condition validation\n * - Step status tracking\n */\nexport default function howToExtension(context: any) {\n logger.info('HowTo system extension loaded');\n\n // Register the HowTo service in the dependency injection context\n rootContext.put('howToService', howToService);\n\n // Ensure the panel is added to the DOM\n const ensurePanelInDOM = () => {\n // Check if panel already exists\n if (document.querySelector('docks-howto-panel')) {\n return;\n }\n\n // Create and append the panel\n const panel = document.createElement('docks-howto-panel');\n document.body.appendChild(panel);\n logger.info('HowTo panel added to DOM');\n };\n\n // Add panel to DOM - use requestAnimationFrame to ensure DOM is ready\n if (document.body) {\n requestAnimationFrame(() => {\n ensurePanelInDOM();\n });\n } else {\n // Wait for DOM to be ready\n const checkDOM = () => {\n if (document.body) {\n ensurePanelInDOM();\n } else {\n requestAnimationFrame(checkDOM);\n }\n };\n requestAnimationFrame(checkDOM);\n }\n\n // Register command to show/toggle the HowTo panel\n registerAll({\n command: {\n id: 'howto.show-panel',\n name: 'Show HowTo Panel',\n description: 'Shows the HowTo workflows panel',\n icon: 'list-check',\n parameters: []\n },\n handler: {\n execute: () => {\n publish(TOPIC_SHOW_HOWTO_PANEL, null);\n }\n }\n });\n\n registerAll({\n command: {\n id: 'howto.toggle-panel',\n name: 'Toggle HowTo Panel',\n description: 'Toggles the visibility of the HowTo workflows panel',\n icon: 'list-check',\n keyBinding: 'CTRL+SHIFT+H',\n parameters: []\n },\n handler: {\n execute: () => {\n publish(TOPIC_TOGGLE_HOWTO_PANEL, null);\n }\n },\n contribution: {\n target: TOOLBAR_BOTTOM_END,\n icon: 'list-check',\n label: 'HowTo',\n }\n });\n\n logger.info('HowTo system extension initialized');\n}\n\n// Export the service and types for direct imports\nexport { howToService, HOWTO_CONTRIBUTION_TARGET } from './howto-service';\nexport type { HowToContribution, HowToStep, ConditionFunction } from './howto-contribution';\n\n"],"mappings":"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"}