@beastmode-develeap/beastmode 0.1.164 → 0.1.166

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.
@@ -15,7 +15,7 @@
15
15
  }
16
16
  </script>
17
17
  <!--BOARD_DATA-->
18
- <script>window.__BUILD_STAMP__ = "20260503-204626-f038641";</script>
18
+ <script>window.__BUILD_STAMP__ = "20260505-061944-bb36100";</script>
19
19
  <link rel="preconnect" href="https://fonts.googleapis.com">
20
20
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
21
21
  <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
@@ -442,11 +442,12 @@ body {
442
442
  .kanban {
443
443
  display: flex;
444
444
  gap: 12px;
445
- overflow-x: scroll;
445
+ overflow-x: auto;
446
446
  overflow-y: visible;
447
447
  scroll-behavior: auto;
448
448
  cursor: grab;
449
449
  -webkit-overflow-scrolling: touch;
450
+ min-width: 0;
450
451
  }
451
452
  .kanban::-webkit-scrollbar-corner { background: var(--bg-card); }
452
453
 
@@ -1015,7 +1016,7 @@ input[type="range"]::-webkit-slider-thumb {
1015
1016
  .kanban-column {
1016
1017
  min-width: 230px;
1017
1018
  max-width: 270px;
1018
- flex: 1;
1019
+ flex: 1 0 230px;
1019
1020
  background: var(--bg-card);
1020
1021
  border: 1px solid var(--border);
1021
1022
  border-radius: var(--radius-lg);
@@ -1076,7 +1077,7 @@ input[type="range"]::-webkit-slider-thumb {
1076
1077
  max-height: calc(100vh - 300px);
1077
1078
  overflow-y: auto;
1078
1079
  scrollbar-width: thin;
1079
- scrollbar-color: rgba(255, 255, 255, 0.15) transparent;
1080
+ scrollbar-color: rgba(255, 255, 255, 0.25) rgba(255, 255, 255, 0.05);
1080
1081
  }
1081
1082
 
1082
1083
  .kanban-items::-webkit-scrollbar {
@@ -1084,29 +1085,34 @@ input[type="range"]::-webkit-slider-thumb {
1084
1085
  }
1085
1086
 
1086
1087
  .kanban-items::-webkit-scrollbar-track {
1087
- background: transparent;
1088
+ background: rgba(255, 255, 255, 0.03);
1089
+ border-radius: 5px;
1088
1090
  }
1089
1091
 
1090
1092
  .kanban-items::-webkit-scrollbar-thumb {
1091
- background: rgba(255, 255, 255, 0.15);
1093
+ background: rgba(255, 255, 255, 0.25);
1092
1094
  border-radius: 5px;
1093
1095
  }
1094
1096
 
1095
1097
  .kanban-items::-webkit-scrollbar-thumb:hover {
1096
- background: rgba(255, 255, 255, 0.25);
1098
+ background: rgba(255, 255, 255, 0.35);
1097
1099
  }
1098
1100
 
1099
1101
  [data-theme="light"] .kanban-items {
1100
- scrollbar-color: rgba(0, 0, 0, 0.15) transparent;
1102
+ scrollbar-color: rgba(0, 0, 0, 0.25) rgba(0, 0, 0, 0.05);
1103
+ }
1104
+
1105
+ [data-theme="light"] .kanban-items::-webkit-scrollbar-track {
1106
+ background: rgba(0, 0, 0, 0.03);
1101
1107
  }
1102
1108
 
1103
1109
  [data-theme="light"] .kanban-items::-webkit-scrollbar-thumb {
1104
- background: rgba(0, 0, 0, 0.15);
1110
+ background: rgba(0, 0, 0, 0.25);
1105
1111
  border-radius: 5px;
1106
1112
  }
1107
1113
 
1108
1114
  [data-theme="light"] .kanban-items::-webkit-scrollbar-thumb:hover {
1109
- background: rgba(0, 0, 0, 0.25);
1115
+ background: rgba(0, 0, 0, 0.35);
1110
1116
  }
1111
1117
 
1112
1118
  .kanban-card {
@@ -1194,18 +1200,28 @@ input[type="range"]::-webkit-slider-thumb {
1194
1200
  font-size: 11px;
1195
1201
  color: var(--text-muted);
1196
1202
  margin-bottom: 4px;
1203
+ overflow: hidden;
1204
+ text-overflow: ellipsis;
1205
+ white-space: nowrap;
1197
1206
  }
1198
1207
  .kanban-card .card-title {
1199
1208
  font-weight: 500;
1200
1209
  font-size: 13px;
1201
1210
  line-height: 1.4;
1202
1211
  margin-bottom: 8px;
1212
+ overflow: hidden;
1213
+ text-overflow: ellipsis;
1214
+ display: -webkit-box;
1215
+ -webkit-line-clamp: 2;
1216
+ -webkit-box-orient: vertical;
1217
+ word-break: break-word;
1203
1218
  }
1204
1219
  .kanban-card .card-footer {
1205
1220
  display: flex;
1206
1221
  flex-wrap: wrap;
1207
1222
  align-items: center;
1208
1223
  gap: 6px;
1224
+ overflow: hidden;
1209
1225
  }
1210
1226
  .kanban-card .card-time {
1211
1227
  margin-left: auto;
@@ -1237,6 +1253,10 @@ input[type="range"]::-webkit-slider-thumb {
1237
1253
  font-size: 11px;
1238
1254
  font-weight: 500;
1239
1255
  line-height: 1.4;
1256
+ max-width: 120px;
1257
+ overflow: hidden;
1258
+ text-overflow: ellipsis;
1259
+ white-space: nowrap;
1240
1260
  }
1241
1261
  .badge-epic { background: var(--accent-subtle); color: var(--accent); }
1242
1262
  .badge-priority-critical { background: rgba(239, 68, 68, 0.15); color: #f87171; }
@@ -1722,6 +1742,7 @@ input[type="range"]::-webkit-slider-thumb {
1722
1742
  gap: 0;
1723
1743
  overflow-x: auto;
1724
1744
  padding: 0;
1745
+ min-width: 0;
1725
1746
  }
1726
1747
 
1727
1748
  .pipeline-swimlane-body::-webkit-scrollbar { height: 6px; }
@@ -1732,7 +1753,7 @@ input[type="range"]::-webkit-slider-thumb {
1732
1753
  .pipeline-column {
1733
1754
  min-width: 200px;
1734
1755
  max-width: 240px;
1735
- flex: 1;
1756
+ flex: 1 0 200px;
1736
1757
  border-right: 1px solid var(--border-subtle);
1737
1758
  display: flex;
1738
1759
  flex-direction: column;
@@ -1770,6 +1791,8 @@ input[type="range"]::-webkit-slider-thumb {
1770
1791
  cursor: pointer;
1771
1792
  user-select: none;
1772
1793
  white-space: nowrap;
1794
+ overflow: hidden;
1795
+ text-overflow: ellipsis;
1773
1796
  }
1774
1797
 
1775
1798
  .pipeline-column-items {
@@ -1778,6 +1801,8 @@ input[type="range"]::-webkit-slider-thumb {
1778
1801
  min-height: 40px;
1779
1802
  max-height: 400px;
1780
1803
  overflow-y: auto;
1804
+ scrollbar-width: thin;
1805
+ scrollbar-color: rgba(255, 255, 255, 0.25) rgba(255, 255, 255, 0.05);
1781
1806
  }
1782
1807
 
1783
1808
  @media (max-width: 900px) {
@@ -4127,12 +4152,19 @@ function getEffectivePipelineColumn(item) {
4127
4152
  return stages.find(s => s !== 'New' && s !== 'Ready') || item.status;
4128
4153
  }
4129
4154
 
4155
+ function getTargetSwimlaneKey(element) {
4156
+ if (!element || typeof element.closest !== 'function') return null;
4157
+ const swimlaneEl = element.closest('[data-swimlane]');
4158
+ return swimlaneEl ? swimlaneEl.dataset.swimlane : null;
4159
+ }
4160
+
4130
4161
  window.isOverlayStatus = isOverlayStatus;
4131
4162
  window.overlayBadgeClass = overlayBadgeClass;
4132
4163
  window.overlayBadgeLabel = overlayBadgeLabel;
4133
4164
  window.overlayKey = overlayKey;
4134
4165
  window.overlayTooltip = overlayTooltip;
4135
4166
  window.getEffectivePipelineColumn = getEffectivePipelineColumn;
4167
+ window.getTargetSwimlaneKey = getTargetSwimlaneKey;
4136
4168
 
4137
4169
  function swimlaneColor(colorKey) {
4138
4170
  const map = {
@@ -5259,7 +5291,7 @@ function PipelineView({
5259
5291
  <${Icon} name="trash" size=${12} />
5260
5292
  </button>
5261
5293
  <div class="card-id">#${item.id}</div>
5262
- <div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)}>${item.name || item.title}</div>
5294
+ <div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)} title=${item.name || item.title}>${item.name || item.title}</div>
5263
5295
  <div class="card-footer">
5264
5296
  ${isOverlayStatus(item.status) && html`<span class=${'card-badge badge-overlay ' + overlayBadgeClass(item.status)} title=${overlayTooltip(item.status)}>${overlayBadgeLabel(item.status)}</span>`}
5265
5297
  ${!isParentEpic && item.parent_epic && html`<span class="card-badge badge-epic">epic:${item.parent_epic}</span>`}
@@ -5896,8 +5928,11 @@ function BoardPage({ selectedProject }) {
5896
5928
  const onDragStart = (e, id) => {
5897
5929
  const item = items.find(i => String(i.id) === String(id));
5898
5930
  const taskType = (item && item.task_type) ? item.task_type : 'code';
5899
- setDragInfo({ id, taskType });
5900
- dragInfoRef.current = { id, taskType };
5931
+ const lane = (typeof getSwimlaneForType === 'function')
5932
+ ? getSwimlaneForType(taskType) : null;
5933
+ const swimlaneKey = lane ? lane.key : null;
5934
+ setDragInfo({ id, taskType, swimlaneKey });
5935
+ dragInfoRef.current = { id, taskType, swimlaneKey };
5901
5936
  e.dataTransfer.effectAllowed = 'move';
5902
5937
  try { e.dataTransfer.setData('text/plain', String(id)); } catch {}
5903
5938
  e.target.classList.add('dragging');
@@ -5909,6 +5944,7 @@ function BoardPage({ selectedProject }) {
5909
5944
  dragInfoRef.current = null;
5910
5945
  document.querySelectorAll('.drag-over, .drag-over-invalid').forEach(el => {
5911
5946
  el.classList.remove('drag-over', 'drag-over-invalid');
5947
+ el.removeAttribute('title');
5912
5948
  });
5913
5949
  };
5914
5950
 
@@ -5919,31 +5955,48 @@ function BoardPage({ selectedProject }) {
5919
5955
  const validStages = (typeof getStagesForType === 'function')
5920
5956
  ? getStagesForType(di.taskType)
5921
5957
  : [];
5922
- const isValid = validStages.indexOf(targetColumnId) !== -1;
5958
+ const stageValid = validStages.indexOf(targetColumnId) !== -1;
5959
+ // Pipeline view: enforce swimlane boundary. Kanban columns have no
5960
+ // [data-swimlane] ancestor so getTargetSwimlaneKey returns null and
5961
+ // the swimlane gate falls open — kanban DnD remains unchanged.
5962
+ const targetSwimlane = (typeof getTargetSwimlaneKey === 'function')
5963
+ ? getTargetSwimlaneKey(e.currentTarget) : null;
5964
+ const swimlaneValid = !targetSwimlane || !di.swimlaneKey || targetSwimlane === di.swimlaneKey;
5965
+ const isValid = stageValid && swimlaneValid;
5923
5966
  if (isValid) {
5924
5967
  e.dataTransfer.dropEffect = 'move';
5925
5968
  e.currentTarget.classList.remove('drag-over-invalid');
5926
5969
  e.currentTarget.classList.add('drag-over');
5970
+ e.currentTarget.removeAttribute('title');
5927
5971
  } else {
5928
5972
  e.dataTransfer.dropEffect = 'none';
5929
5973
  e.currentTarget.classList.remove('drag-over');
5930
5974
  e.currentTarget.classList.add('drag-over-invalid');
5975
+ if (stageValid && !swimlaneValid) {
5976
+ e.currentTarget.setAttribute('title', 'Cannot move items between swimlanes');
5977
+ }
5931
5978
  }
5932
5979
  };
5933
5980
 
5934
5981
  const onDragLeave = (e) => {
5935
5982
  e.currentTarget.classList.remove('drag-over', 'drag-over-invalid');
5983
+ e.currentTarget.removeAttribute('title');
5936
5984
  };
5937
5985
 
5938
5986
  const onDrop = async (e, status) => {
5939
5987
  e.preventDefault();
5940
5988
  e.currentTarget.classList.remove('drag-over', 'drag-over-invalid');
5989
+ e.currentTarget.removeAttribute('title');
5941
5990
  const di = dragInfoRef.current;
5942
5991
  if (!di) return;
5943
5992
  const validStages = (typeof getStagesForType === 'function')
5944
5993
  ? getStagesForType(di.taskType)
5945
5994
  : [];
5946
5995
  if (validStages.indexOf(status) === -1) return;
5996
+ // Swimlane boundary gate — same falls-open semantics as onDragOver.
5997
+ const targetSwimlane = (typeof getTargetSwimlaneKey === 'function')
5998
+ ? getTargetSwimlaneKey(e.currentTarget) : null;
5999
+ if (targetSwimlane && di.swimlaneKey && targetSwimlane !== di.swimlaneKey) return;
5947
6000
  const current = items.find(i => String(i.id) === String(di.id));
5948
6001
  if (current && current.status === status) return;
5949
6002
  try {
@@ -6345,7 +6398,7 @@ function BoardPage({ selectedProject }) {
6345
6398
  <${Icon} name="trash" size=${12} />
6346
6399
  </button>
6347
6400
  <div class="card-id">#${item.id}</div>
6348
- <div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)}>${item.name || item.title}</div>
6401
+ <div class="card-title" style="cursor:pointer;" onClick=${() => setSelectedItem(item)} title=${item.name || item.title}>${item.name || item.title}</div>
6349
6402
  <div class="card-footer">
6350
6403
  ${isOverlayStatus(item.status) && html`<span class=${'card-badge badge-overlay ' + overlayBadgeClass(item.status)} title=${overlayTooltip(item.status)}>${overlayBadgeLabel(item.status)}</span>`}
6351
6404
  ${!isParentEpic && item.parent_epic && html`<span class="card-badge badge-epic">epic:${item.parent_epic}</span>`}
@@ -9951,7 +10004,7 @@ function App() {
9951
10004
 
9952
10005
  render(html`<${App} />`, document.getElementById('app'));
9953
10006
  </script>
9954
- <div id="build-stamp-footer" style="position:fixed;bottom:4px;right:8px;font-size:10px;color:rgba(255,255,255,0.2);font-family:'JetBrains Mono',monospace;pointer-events:none;z-index:1;user-select:all;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></div>
10007
+ <div id="build-stamp-footer" style="position:fixed;bottom:4px;right:8px;font-size:10px;color:rgba(255,255,255,0.15);font-family:'JetBrains Mono',monospace;pointer-events:none;z-index:0;user-select:all;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"></div>
9955
10008
  <script>if(window.__BUILD_STAMP__){document.getElementById('build-stamp-footer').textContent=window.__BUILD_STAMP__}</script>
9956
10009
  </body>
9957
10010
  </html>
@@ -1 +1 @@
1
- f0386412b5fbca9297035dae7115884809b7a8ef
1
+ bb361001d983cfbd200675f52e1bbdd2620632a4
@@ -1 +1 @@
1
- 20260503-204626-f038641
1
+ 20260505-061944-bb36100
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beastmode-develeap/beastmode",
3
- "version": "0.1.164",
3
+ "version": "0.1.166",
4
4
  "description": "BeastMode Dark Factory — turn intent into verified software",
5
5
  "type": "module",
6
6
  "bin": {