x-ipe 1.0.24__py3-none-any.whl → 1.0.25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. x_ipe/app.py +25 -3
  2. x_ipe/handlers/terminal_handlers.py +6 -0
  3. x_ipe/handlers/voice_handlers.py +5 -0
  4. x_ipe/resources/copilot-instructions.md +19 -6
  5. x_ipe/resources/skills/lesson-learned/SKILL.md +208 -0
  6. x_ipe/resources/skills/lesson-learned/references/examples.md +238 -0
  7. x_ipe/resources/skills/project-quality-board-management/SKILL.md +135 -298
  8. x_ipe/resources/skills/project-quality-board-management/references/evaluation-principles.md +213 -0
  9. x_ipe/resources/skills/project-quality-board-management/references/evaluation-procedures.md +214 -0
  10. x_ipe/resources/skills/project-quality-board-management/templates/quality-report.md +70 -18
  11. x_ipe/resources/skills/task-execution-guideline/SKILL.md +2 -2
  12. x_ipe/resources/skills/task-execution-guideline/templates/task-record.yaml +1 -1
  13. x_ipe/resources/skills/task-type-code-implementation/SKILL.md +72 -270
  14. x_ipe/resources/skills/task-type-code-implementation/references/implementation-guidelines.md +432 -0
  15. x_ipe/resources/skills/task-type-code-refactor-v2/SKILL.md +127 -353
  16. x_ipe/resources/skills/task-type-code-refactor-v2/references/refactoring-techniques.md +373 -0
  17. x_ipe/resources/skills/task-type-feature-breakdown/SKILL.md +31 -243
  18. x_ipe/resources/skills/task-type-feature-breakdown/references/breakdown-guidelines.md +330 -0
  19. x_ipe/resources/skills/task-type-feature-refinement/SKILL.md +27 -180
  20. x_ipe/resources/skills/task-type-feature-refinement/references/specification-writing-guide.md +267 -0
  21. x_ipe/resources/skills/task-type-idea-mockup/SKILL.md +38 -276
  22. x_ipe/resources/skills/task-type-idea-mockup/references/mockup-guidelines.md +299 -0
  23. x_ipe/resources/skills/task-type-idea-to-architecture/SKILL.md +20 -218
  24. x_ipe/resources/skills/task-type-idea-to-architecture/references/architecture-patterns.md +342 -0
  25. x_ipe/resources/skills/task-type-ideation/SKILL.md +10 -266
  26. x_ipe/resources/skills/task-type-ideation/references/folder-naming-guide.md +55 -0
  27. x_ipe/resources/skills/task-type-ideation/references/tool-usage-guide.md +236 -0
  28. x_ipe/resources/skills/task-type-ideation-v2/SKILL.md +488 -0
  29. x_ipe/resources/skills/task-type-ideation-v2/references/examples.md +377 -0
  30. x_ipe/resources/skills/task-type-ideation-v2/references/folder-naming-guide.md +74 -0
  31. x_ipe/resources/skills/task-type-ideation-v2/references/tool-usage-guide.md +145 -0
  32. x_ipe/resources/skills/task-type-ideation-v2/references/visualization-guide.md +160 -0
  33. x_ipe/resources/skills/task-type-ideation-v2/templates/idea-summary.md +86 -0
  34. x_ipe/resources/skills/task-type-refactoring-analysis/SKILL.md +83 -145
  35. x_ipe/resources/skills/task-type-refactoring-analysis/references/output-schema.md +172 -0
  36. x_ipe/resources/skills/task-type-technical-design/SKILL.md +28 -214
  37. x_ipe/resources/skills/task-type-technical-design/references/design-templates.md +422 -0
  38. x_ipe/resources/skills/task-type-test-generation/SKILL.md +47 -332
  39. x_ipe/resources/skills/task-type-test-generation/references/test-patterns.md +368 -0
  40. x_ipe/resources/skills/tool-tracing-creator/SKILL.md +312 -0
  41. x_ipe/resources/skills/tool-tracing-creator/references/examples.md +324 -0
  42. x_ipe/resources/skills/tool-tracing-instrumentation/SKILL.md +373 -0
  43. x_ipe/resources/skills/tool-tracing-instrumentation/references/examples.md +264 -0
  44. x_ipe/resources/skills/x-ipe-skill-creator-v3/SKILL.md +486 -0
  45. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/10. example-gate-conditions.md +73 -0
  46. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/11. reference-quality-standards.md +127 -0
  47. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/2. reference-section-order.md +127 -0
  48. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/3. example-step-based-code-review.md +84 -0
  49. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/4. example-step-based-feature-implementation.md +113 -0
  50. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/5. example-function-based-validation.md +73 -0
  51. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/6. example-function-based-analysis.md +94 -0
  52. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/7. example-task-io-code-implementation.md +36 -0
  53. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/8. example-structured-summary.md +43 -0
  54. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/9. example-dor-dod.md +77 -0
  55. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/examples.md +429 -0
  56. x_ipe/resources/skills/x-ipe-skill-creator-v3/references/skill-general-guidelines-v2.md +611 -0
  57. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-meta.md +153 -0
  58. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-based.md +324 -0
  59. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-task-category.md +109 -0
  60. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/skill-meta-x-ipe-tool.md +205 -0
  61. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-meta.md +334 -0
  62. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-task-based.md +279 -0
  63. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-tool.md +175 -0
  64. x_ipe/resources/skills/x-ipe-skill-creator-v3/templates/x-ipe-workflow-orchestration.md +329 -0
  65. x_ipe/resources/skills/x-ipe-task-based-ideation/SKILL.md +487 -0
  66. x_ipe/resources/skills/x-ipe-task-based-ideation/references/examples.md +377 -0
  67. x_ipe/resources/skills/x-ipe-task-based-ideation/references/folder-naming-guide.md +74 -0
  68. x_ipe/resources/skills/x-ipe-task-based-ideation/references/tool-usage-guide.md +145 -0
  69. x_ipe/resources/skills/x-ipe-task-based-ideation/references/visualization-guide.md +160 -0
  70. x_ipe/resources/skills/x-ipe-task-based-ideation/templates/idea-summary.md +86 -0
  71. x_ipe/routes/__init__.py +2 -0
  72. x_ipe/routes/ideas_routes.py +17 -0
  73. x_ipe/routes/kb_routes.py +80 -0
  74. x_ipe/routes/main_routes.py +18 -0
  75. x_ipe/routes/project_routes.py +7 -0
  76. x_ipe/routes/proxy_routes.py +2 -0
  77. x_ipe/routes/quality_evaluation_routes.py +193 -0
  78. x_ipe/routes/settings_routes.py +6 -0
  79. x_ipe/routes/tools_routes.py +6 -0
  80. x_ipe/routes/tracing_routes.py +232 -0
  81. x_ipe/routes/uiux_feedback_routes.py +30 -0
  82. x_ipe/services/__init__.py +5 -0
  83. x_ipe/services/config_service.py +6 -0
  84. x_ipe/services/file_service.py +20 -0
  85. x_ipe/services/homepage_service.py +160 -0
  86. x_ipe/services/ideas_service.py +19 -0
  87. x_ipe/services/kb_service.py +378 -0
  88. x_ipe/services/proxy_service.py +4 -0
  89. x_ipe/services/settings_service.py +13 -0
  90. x_ipe/services/skills_service.py +4 -0
  91. x_ipe/services/terminal_service.py +24 -0
  92. x_ipe/services/themes_service.py +4 -0
  93. x_ipe/services/tools_config_service.py +4 -0
  94. x_ipe/services/tracing_service.py +333 -0
  95. x_ipe/services/uiux_feedback_service.py +32 -0
  96. x_ipe/services/voice_input_service_v2.py +11 -0
  97. x_ipe/static/css/base.css +7 -0
  98. x_ipe/static/css/homepage-infinity.css +330 -0
  99. x_ipe/static/css/kb-core.css +301 -0
  100. x_ipe/static/css/quality-evaluation.css +345 -0
  101. x_ipe/static/css/sidebar.css +14 -4
  102. x_ipe/static/css/terminal.css +1 -0
  103. x_ipe/static/css/tracing-dashboard.css +796 -0
  104. x_ipe/static/css/workplace.css +20 -0
  105. x_ipe/static/img/homepage-infinity-loop.png +0 -0
  106. x_ipe/static/js/features/homepage-infinity.js +314 -0
  107. x_ipe/static/js/features/kb-core.js +371 -0
  108. x_ipe/static/js/features/quality-evaluation.js +387 -0
  109. x_ipe/static/js/features/sidebar.js +255 -12
  110. x_ipe/static/js/features/tracing-dashboard.js +855 -0
  111. x_ipe/static/js/features/tracing-graph.js +1031 -0
  112. x_ipe/static/js/features/tree-search.js +6 -2
  113. x_ipe/static/js/features/workplace.js +200 -6
  114. x_ipe/static/js/init.js +76 -0
  115. x_ipe/static/js/uiux-feedback.js +18 -2
  116. x_ipe/templates/base.html +19 -0
  117. x_ipe/templates/index.html +7 -1
  118. x_ipe/templates/knowledge-base.html +110 -0
  119. x_ipe/templates/workplace.html +4 -0
  120. x_ipe/tracing/__init__.py +37 -0
  121. x_ipe/tracing/buffer.py +135 -0
  122. x_ipe/tracing/context.py +125 -0
  123. x_ipe/tracing/decorator.py +288 -0
  124. x_ipe/tracing/middleware.py +197 -0
  125. x_ipe/tracing/parser.py +235 -0
  126. x_ipe/tracing/redactor.py +111 -0
  127. x_ipe/tracing/writer.py +122 -0
  128. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/METADATA +2 -2
  129. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/RECORD +132 -62
  130. x_ipe/resources/skills/x-ipe-skill-creator/SKILL.md +0 -329
  131. x_ipe/resources/skills/x-ipe-skill-creator/references/output-patterns.md +0 -169
  132. x_ipe/resources/skills/x-ipe-skill-creator/references/skill-structure.md +0 -162
  133. x_ipe/resources/skills/x-ipe-skill-creator/references/workflows.md +0 -110
  134. x_ipe/resources/skills/x-ipe-skill-creator/templates/references/examples.md +0 -113
  135. x_ipe/resources/skills/x-ipe-skill-creator/templates/skill-category-skill.md +0 -296
  136. x_ipe/resources/skills/x-ipe-skill-creator/templates/task-type-skill.md +0 -269
  137. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/WHEEL +0 -0
  138. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/entry_points.txt +0 -0
  139. {x_ipe-1.0.24.dist-info → x_ipe-1.0.25.dist-info}/licenses/LICENSE +0 -0
@@ -16,6 +16,12 @@ class ProjectSidebar {
16
16
  this.changedPaths = new Set();
17
17
  this.previousPathMtimes = new Map(); // Map<path, mtime> for content change detection
18
18
 
19
+ // Track expanded/pinned state to preserve across re-renders
20
+ this.pinnedSections = new Set(); // Set of section IDs
21
+ this.pinnedFolders = new Set(); // Set of folder paths
22
+ this.expandedSections = new Set(); // Set of section IDs
23
+ this.expandedFolders = new Set(); // Set of folder paths
24
+
19
25
  this._startPolling();
20
26
  }
21
27
 
@@ -225,6 +231,9 @@ class ProjectSidebar {
225
231
  return;
226
232
  }
227
233
 
234
+ // Save current expanded/pinned state before re-rendering
235
+ this._saveExpandedState();
236
+
228
237
  let html = '';
229
238
 
230
239
  for (const section of this.sections) {
@@ -233,6 +242,95 @@ class ProjectSidebar {
233
242
 
234
243
  this.container.innerHTML = html;
235
244
  this.bindEvents();
245
+
246
+ // Restore expanded/pinned state after re-rendering
247
+ this._restoreExpandedState();
248
+ }
249
+
250
+ /**
251
+ * Save current expanded and pinned state from DOM
252
+ */
253
+ _saveExpandedState() {
254
+ // Save expanded sections
255
+ this.container.querySelectorAll('.nav-section-content.show').forEach(content => {
256
+ const sectionId = content.id.replace('section-', '');
257
+ this.expandedSections.add(sectionId);
258
+ });
259
+
260
+ // Save pinned sections
261
+ this.container.querySelectorAll('.nav-section-header.pinned').forEach(header => {
262
+ const target = header.dataset.bsTarget;
263
+ if (target) {
264
+ const sectionId = target.replace('#section-', '');
265
+ this.pinnedSections.add(sectionId);
266
+ }
267
+ });
268
+
269
+ // Save expanded folders
270
+ this.container.querySelectorAll('.nav-folder-content.show').forEach(content => {
271
+ const folderHeader = this.container.querySelector(`[data-bs-target="#${content.id}"]`);
272
+ if (folderHeader && folderHeader.dataset.path) {
273
+ this.expandedFolders.add(folderHeader.dataset.path);
274
+ }
275
+ });
276
+
277
+ // Save pinned folders
278
+ this.container.querySelectorAll('.nav-folder.pinned').forEach(folder => {
279
+ if (folder.dataset.path) {
280
+ this.pinnedFolders.add(folder.dataset.path);
281
+ }
282
+ });
283
+ }
284
+
285
+ /**
286
+ * Restore expanded and pinned state after render
287
+ */
288
+ _restoreExpandedState() {
289
+ // Restore expanded sections
290
+ this.expandedSections.forEach(sectionId => {
291
+ const content = document.getElementById(`section-${sectionId}`);
292
+ const header = this.container.querySelector(`[data-bs-target="#section-${sectionId}"]`);
293
+ if (content && header) {
294
+ content.classList.add('show');
295
+ header.classList.remove('collapsed');
296
+ }
297
+ });
298
+
299
+ // Restore pinned sections (also expand them)
300
+ this.pinnedSections.forEach(sectionId => {
301
+ const content = document.getElementById(`section-${sectionId}`);
302
+ const header = this.container.querySelector(`[data-bs-target="#section-${sectionId}"]`);
303
+ if (content && header) {
304
+ content.classList.add('show');
305
+ header.classList.remove('collapsed');
306
+ header.classList.add('pinned');
307
+ }
308
+ });
309
+
310
+ // Restore expanded folders
311
+ this.expandedFolders.forEach(folderPath => {
312
+ const folder = this.container.querySelector(`.nav-folder[data-path="${folderPath}"]`);
313
+ if (folder) {
314
+ const targetSelector = folder.dataset.bsTarget;
315
+ const content = document.querySelector(targetSelector);
316
+ if (content) {
317
+ content.classList.add('show');
318
+ }
319
+ }
320
+ });
321
+
322
+ // Restore pinned folders (also expand them)
323
+ this.pinnedFolders.forEach(folderPath => {
324
+ const folder = this.container.querySelector(`.nav-folder[data-path="${folderPath}"]`);
325
+ if (folder) {
326
+ folder.classList.add('pinned');
327
+ const targetSelector = folder.dataset.bsTarget;
328
+ const content = document.querySelector(targetSelector);
329
+ if (content) {
330
+ content.classList.add('show');
331
+ }
332
+ }
333
+ });
236
334
  }
237
335
 
238
336
  /**
@@ -243,6 +341,8 @@ class ProjectSidebar {
243
341
  const hasChildren = section.children && section.children.length > 0;
244
342
 
245
343
  // CR-004: Special handling for Workplace section - show submenu with Ideation and UIUX Feedbacks
344
+ // FEATURE-023-B: Added Tracing submenu item
345
+ // FEATURE-024: Added Quality Evaluation submenu item
246
346
  if (section.id === 'workplace') {
247
347
  return `
248
348
  <div class="nav-section" data-section-id="${section.id}">
@@ -260,6 +360,14 @@ class ProjectSidebar {
260
360
  <i class="bi bi-chat-square-text"></i>
261
361
  <span>UIUX Feedbacks</span>
262
362
  </div>
363
+ <div class="nav-section-header sidebar-child nav-tracing" data-section-id="tracing">
364
+ <i class="bi bi-graph-up"></i>
365
+ <span>Application Tracing</span>
366
+ </div>
367
+ <div class="nav-section-header sidebar-child nav-quality-evaluation" data-section-id="quality-evaluation">
368
+ <i class="bi bi-clipboard-check"></i>
369
+ <span>Quality Evaluation</span>
370
+ </div>
263
371
  </div>
264
372
  </div>
265
373
  `;
@@ -267,7 +375,7 @@ class ProjectSidebar {
267
375
 
268
376
  let html = `
269
377
  <div class="nav-section" data-section-id="${section.id}">
270
- <div class="nav-section-header collapsed" data-bs-toggle="collapse" data-bs-target="#section-${section.id}">
378
+ <div class="nav-section-header collapsed" data-bs-target="#section-${section.id}">
271
379
  <i class="bi ${icon}"></i>
272
380
  <span>${section.label}</span>
273
381
  <i class="bi bi-chevron-down chevron"></i>
@@ -328,7 +436,6 @@ class ProjectSidebar {
328
436
  let html = `
329
437
  <div class="nav-item nav-folder${isChanged ? ' has-changes' : ''}"
330
438
  style="padding-left: ${paddingLeft}rem"
331
- data-bs-toggle="collapse"
332
439
  data-bs-target="#folder-${folderId}"
333
440
  data-path="${folder.path}">
334
441
  ${isChanged ? '<span class="change-indicator"></span>' : ''}
@@ -505,6 +612,88 @@ class ProjectSidebar {
505
612
  });
506
613
  }
507
614
 
615
+ // FEATURE-023-B: Tracing click handler - render Tracing Dashboard in content area
616
+ const tracingHeader = this.container.querySelector('.nav-tracing');
617
+ if (tracingHeader) {
618
+ tracingHeader.addEventListener('click', () => {
619
+ // Clear file selection
620
+ fileItems.forEach(f => f.classList.remove('active'));
621
+ this.selectedFile = null;
622
+
623
+ // Update sidebar-child active state
624
+ const sidebarChildren = this.container.querySelectorAll('.sidebar-child');
625
+ sidebarChildren.forEach(child => child.classList.remove('active'));
626
+ tracingHeader.classList.add('active');
627
+
628
+ // Clear contentRenderer.currentPath to prevent auto-refresh
629
+ if (window.contentRenderer) {
630
+ window.contentRenderer.currentPath = null;
631
+ }
632
+
633
+ // Hide Create Idea button
634
+ const createIdeaBtn = document.getElementById('btn-create-idea');
635
+ if (createIdeaBtn) {
636
+ createIdeaBtn.classList.add('d-none');
637
+ }
638
+
639
+ // Update breadcrumb
640
+ const breadcrumb = document.getElementById('breadcrumb');
641
+ breadcrumb.innerHTML = '<li class="breadcrumb-item active">Application Tracing</li>';
642
+
643
+ // Render Tracing Dashboard in content area
644
+ const container = document.getElementById('content-body');
645
+ if (window.TracingDashboard) {
646
+ // Clean up any existing dashboard
647
+ if (window._tracingDashboardInstance) {
648
+ window._tracingDashboardInstance.destroy();
649
+ }
650
+ window._tracingDashboardInstance = new window.TracingDashboard(container);
651
+ window._tracingDashboardInstance.init();
652
+ }
653
+ });
654
+ }
655
+
656
+ // FEATURE-024: Quality Evaluation submenu click handler
657
+ const qualityEvalHeader = this.container.querySelector('.nav-quality-evaluation');
658
+ if (qualityEvalHeader) {
659
+ qualityEvalHeader.addEventListener('click', () => {
660
+ // Clear file selection
661
+ fileItems.forEach(f => f.classList.remove('active'));
662
+ this.selectedFile = null;
663
+
664
+ // Update sidebar-child active state
665
+ const sidebarChildren = this.container.querySelectorAll('.sidebar-child');
666
+ sidebarChildren.forEach(child => child.classList.remove('active'));
667
+ qualityEvalHeader.classList.add('active');
668
+
669
+ // Clear contentRenderer.currentPath to prevent auto-refresh
670
+ if (window.contentRenderer) {
671
+ window.contentRenderer.currentPath = null;
672
+ }
673
+
674
+ // Hide Create Idea button
675
+ const createIdeaBtn = document.getElementById('btn-create-idea');
676
+ if (createIdeaBtn) {
677
+ createIdeaBtn.classList.add('d-none');
678
+ }
679
+
680
+ // Update breadcrumb
681
+ const breadcrumb = document.getElementById('breadcrumb');
682
+ breadcrumb.innerHTML = '<li class="breadcrumb-item active">Quality Evaluation</li>';
683
+
684
+ // Render Quality Evaluation view in content area
685
+ const container = document.getElementById('content-body');
686
+ if (window.QualityEvaluationView) {
687
+ // Clean up any existing view
688
+ if (window._qualityEvaluationInstance) {
689
+ window._qualityEvaluationInstance.destroy();
690
+ }
691
+ window._qualityEvaluationInstance = new window.QualityEvaluationView(container);
692
+ window._qualityEvaluationInstance.init();
693
+ }
694
+ });
695
+ }
696
+
508
697
  // CR-004: Prevent parent item click action
509
698
  const parentItems = this.container.querySelectorAll('.sidebar-parent[data-no-action="true"]');
510
699
  parentItems.forEach(item => {
@@ -548,7 +737,9 @@ class ProjectSidebar {
548
737
 
549
738
  let collapseTimeout = null;
550
739
  let expandTimeout = null;
551
- let isPinned = false;
740
+ // Initialize isPinned from persisted state
741
+ const sectionId = targetSelector.replace('#section-', '');
742
+ let isPinned = this.pinnedSections.has(sectionId);
552
743
  const section = header.closest('.nav-section');
553
744
 
554
745
  // Click to pin/unpin
@@ -568,15 +759,17 @@ class ProjectSidebar {
568
759
  if (isPinned) {
569
760
  // Unpin and collapse
570
761
  isPinned = false;
762
+ this.pinnedSections.delete(sectionId);
763
+ this.expandedSections.delete(sectionId);
571
764
  header.classList.remove('pinned');
572
765
  bootstrap.Collapse.getOrCreateInstance(target).hide();
573
766
  } else {
574
- // Pin and expand
767
+ // Pin and expand - always show to ensure it stays open
575
768
  isPinned = true;
769
+ this.pinnedSections.add(sectionId);
770
+ this.expandedSections.add(sectionId);
576
771
  header.classList.add('pinned');
577
- if (!target.classList.contains('show')) {
578
- bootstrap.Collapse.getOrCreateInstance(target).show();
579
- }
772
+ bootstrap.Collapse.getOrCreateInstance(target).show();
580
773
  }
581
774
  });
582
775
 
@@ -633,7 +826,9 @@ class ProjectSidebar {
633
826
 
634
827
  let collapseTimeout = null;
635
828
  let expandTimeout = null;
636
- let isPinned = false;
829
+ // Initialize isPinned from persisted state
830
+ const folderPath = folder.dataset.path;
831
+ let isPinned = this.pinnedFolders.has(folderPath);
637
832
 
638
833
  // Click to pin/unpin
639
834
  folder.addEventListener('click', (e) => {
@@ -652,15 +847,17 @@ class ProjectSidebar {
652
847
  if (isPinned) {
653
848
  // Unpin and collapse
654
849
  isPinned = false;
850
+ this.pinnedFolders.delete(folderPath);
851
+ this.expandedFolders.delete(folderPath);
655
852
  folder.classList.remove('pinned');
656
853
  bootstrap.Collapse.getOrCreateInstance(target).hide();
657
854
  } else {
658
- // Pin and expand
855
+ // Pin and expand - always show to ensure it stays open
659
856
  isPinned = true;
857
+ this.pinnedFolders.add(folderPath);
858
+ this.expandedFolders.add(folderPath);
660
859
  folder.classList.add('pinned');
661
- if (!target.classList.contains('show')) {
662
- bootstrap.Collapse.getOrCreateInstance(target).show();
663
- }
860
+ bootstrap.Collapse.getOrCreateInstance(target).show();
664
861
  }
665
862
  });
666
863
 
@@ -773,6 +970,52 @@ class ProjectSidebar {
773
970
  document.dispatchEvent(event);
774
971
  }
775
972
 
973
+ /**
974
+ * FEATURE-026: Expand a sidebar section by ID
975
+ * @param {string} sectionId - Section ID to expand
976
+ */
977
+ expandSection(sectionId) {
978
+ const sectionHeader = document.querySelector(`[data-section="${sectionId}"] .section-header`);
979
+ if (sectionHeader) {
980
+ const section = sectionHeader.closest('.sidebar-section');
981
+ if (section && !section.classList.contains('expanded')) {
982
+ sectionHeader.click();
983
+ }
984
+ }
985
+ }
986
+
987
+ /**
988
+ * FEATURE-026: Highlight a sidebar item
989
+ * @param {string} selector - CSS selector for target item
990
+ * @param {Object} options - Highlight options
991
+ * @param {number} options.duration - Highlight duration in ms (default 3000)
992
+ */
993
+ highlightItem(selector, options = {}) {
994
+ const duration = options.duration || 3000;
995
+ const item = document.querySelector(selector);
996
+
997
+ if (!item) {
998
+ console.warn(`Sidebar item not found: ${selector}`);
999
+ return;
1000
+ }
1001
+
1002
+ // Remove any existing highlights
1003
+ document.querySelectorAll('.homepage-highlight').forEach(el => {
1004
+ el.classList.remove('homepage-highlight');
1005
+ });
1006
+
1007
+ // Add highlight class
1008
+ item.classList.add('homepage-highlight');
1009
+
1010
+ // Scroll into view
1011
+ item.scrollIntoView({ behavior: 'smooth', block: 'center' });
1012
+
1013
+ // Remove highlight after delay
1014
+ setTimeout(() => {
1015
+ item.classList.remove('homepage-highlight');
1016
+ }, duration);
1017
+ }
1018
+
776
1019
  /**
777
1020
  * Show toast notification
778
1021
  */