harness-bujang 0.5.4 → 0.5.6
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.
package/dist/index.js
CHANGED
|
@@ -1198,8 +1198,9 @@ const ROLES = {
|
|
|
1198
1198
|
};
|
|
1199
1199
|
|
|
1200
1200
|
const ROOMS = [
|
|
1201
|
-
// Top-level
|
|
1202
|
-
|
|
1201
|
+
// Top-level \u2014 kept narrow on purpose so the "smallest matching room wins"
|
|
1202
|
+
// filter routes director\u2192principal reports to \uB300\uD45C \uBCF4\uACE0 (not \uACF5\uB3D9\uB300\uD45C).
|
|
1203
|
+
{ id: '\uB300\uD45C\uB2D8', name: '\uB300\uD45C \uBCF4\uACE0', icon: '\u{1F454}', members: ['\uB300\uD45C\uB2D8', '\uBD80\uC7A5'] },
|
|
1203
1204
|
{ id: '\uACF5\uB3D9\uB300\uD45C', name: '\uACF5\uB3D9\uB300\uD45C', icon: '\u2B50', members: ['\uB300\uD45C\uB2D8', '\uACF5\uB3D9\uB300\uD45C', '\uBD80\uC7A5'] },
|
|
1204
1205
|
{ id: 'consultant', name: '\uCEE8\uC124\uD134\uD2B8', icon: '\u{1F91D}', members: ['consultant', '\uBD80\uC7A5'] },
|
|
1205
1206
|
// Engineering teams
|
|
@@ -1344,7 +1345,7 @@ function render() {
|
|
|
1344
1345
|
html += '</div>';
|
|
1345
1346
|
html += '</div>';
|
|
1346
1347
|
|
|
1347
|
-
html += '<div class="flex-1 overflow-y-auto">';
|
|
1348
|
+
html += '<div id="room-list" class="flex-1 overflow-y-auto">';
|
|
1348
1349
|
// When 'unread' filter is active, only show rooms with unread > 0.
|
|
1349
1350
|
const visibleRooms = state.filter === 'unread'
|
|
1350
1351
|
? ROOMS.filter((r) => unreadByRoom[r.id] > 0)
|
|
@@ -1431,8 +1432,27 @@ function render() {
|
|
|
1431
1432
|
}
|
|
1432
1433
|
html += '</div>';
|
|
1433
1434
|
|
|
1435
|
+
// Save scroll positions BEFORE replacing innerHTML \u2014 otherwise every 2s poll
|
|
1436
|
+
// resets the sidebar room-list scroll to top, and the conversation re-snaps
|
|
1437
|
+
// to the bottom even if the user was reading older messages.
|
|
1438
|
+
const oldRoomList = document.getElementById('room-list');
|
|
1439
|
+
const oldConv = document.getElementById('conversation');
|
|
1440
|
+
const savedRoomScroll = oldRoomList ? oldRoomList.scrollTop : 0;
|
|
1441
|
+
let savedConvScroll = null;
|
|
1442
|
+
let convWasAtBottom = true;
|
|
1443
|
+
if (oldConv) {
|
|
1444
|
+
savedConvScroll = oldConv.scrollTop;
|
|
1445
|
+
// "At bottom" within ~80px \u2014 if user was at bottom we keep them at bottom
|
|
1446
|
+
// (so new messages stay visible). If they scrolled up, preserve position.
|
|
1447
|
+
convWasAtBottom = (oldConv.scrollHeight - oldConv.scrollTop - oldConv.clientHeight) < 80;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1434
1450
|
root.innerHTML = html;
|
|
1435
1451
|
|
|
1452
|
+
// Restore scroll positions.
|
|
1453
|
+
const newRoomList = document.getElementById('room-list');
|
|
1454
|
+
if (newRoomList) newRoomList.scrollTop = savedRoomScroll;
|
|
1455
|
+
|
|
1436
1456
|
// Re-bind filter buttons (\uC804\uCCB4 / \uC548\uC77D\uC74C).
|
|
1437
1457
|
document.querySelectorAll('[data-filter]').forEach((el) => {
|
|
1438
1458
|
el.addEventListener('click', () => {
|
|
@@ -1455,11 +1475,20 @@ function render() {
|
|
|
1455
1475
|
});
|
|
1456
1476
|
});
|
|
1457
1477
|
|
|
1458
|
-
//
|
|
1478
|
+
// Conversation scroll handling:
|
|
1479
|
+
// - First render of a room \u2192 scroll to bottom (latest msg visible)
|
|
1480
|
+
// - User was at bottom \u2192 keep at new bottom (so new msgs auto-show)
|
|
1481
|
+
// - User scrolled up to read history \u2192 preserve their position
|
|
1459
1482
|
const conv = document.getElementById('conversation');
|
|
1460
|
-
if (conv
|
|
1461
|
-
conv.
|
|
1462
|
-
|
|
1483
|
+
if (conv) {
|
|
1484
|
+
if (conv.dataset.scrolled !== state.selectedRoom) {
|
|
1485
|
+
conv.scrollTop = conv.scrollHeight;
|
|
1486
|
+
conv.dataset.scrolled = state.selectedRoom;
|
|
1487
|
+
} else if (convWasAtBottom) {
|
|
1488
|
+
conv.scrollTop = conv.scrollHeight;
|
|
1489
|
+
} else if (savedConvScroll !== null) {
|
|
1490
|
+
conv.scrollTop = savedConvScroll;
|
|
1491
|
+
}
|
|
1463
1492
|
}
|
|
1464
1493
|
}
|
|
1465
1494
|
|
|
@@ -2171,7 +2200,7 @@ async function main() {
|
|
|
2171
2200
|
break;
|
|
2172
2201
|
case "--version":
|
|
2173
2202
|
case "-v":
|
|
2174
|
-
console.log("0.5.
|
|
2203
|
+
console.log("0.5.6");
|
|
2175
2204
|
break;
|
|
2176
2205
|
case "--help":
|
|
2177
2206
|
case "-h":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harness-bujang",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
4
|
"description": "Install the Harness-Bujang multi-agent harness into any project — Director, 7 specialist teams, real-time chat-room UI. Korean and English personas. Works with Claude Code, Cursor, Cline, Aider, or any tool that reads .claude/agents/.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|
|
@@ -51,8 +51,10 @@ const ROLES: Record<string, { icon: string; color: string; bg: string; label?: s
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
const ROOMS = [
|
|
54
|
-
// Top
|
|
55
|
-
|
|
54
|
+
// Top — kept narrow on purpose so director→principal reports route to 대표 보고
|
|
55
|
+
// (not 공동대표). The "smallest matching room wins" filter would otherwise
|
|
56
|
+
// funnel them to 공동대표 because that room also includes both 부장 and 대표님.
|
|
57
|
+
{ id: '대표님', name: '대표 보고', icon: '👔', members: ['대표님', '부장'] },
|
|
56
58
|
{ id: '공동대표', name: '공동대표', icon: '⭐', members: ['대표님', '공동대표', '부장'] },
|
|
57
59
|
{ id: 'consultant', name: '컨설턴트', icon: '🤝', members: ['consultant', '부장'] },
|
|
58
60
|
// Engineering
|