@nanmicoder/dsh-agent-teams 0.1.9 → 0.1.11
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/README.md +9 -4
- package/README_ZH.md +5 -1
- package/assets/ui.png +0 -0
- package/lib/client/ActivityPanel.js +240 -33
- package/lib/client/AgentTeamsCard.js +5 -3
- package/lib/client/activity-model.js +4 -4
- package/lib/client/activity-monitor.js +32 -7
- package/lib/client/index.js +28 -15
- package/lib/client/panel-geometry.js +143 -0
- package/lib/client/session-navigation.js +21 -0
- package/lib/client.js +551 -100
- package/lib/client.js.map +1 -1
- package/lib/command.js +14 -15
- package/lib/members.js +21 -47
- package/lib/snapshot.js +4 -15
- package/lib/tools.js +1 -1
- package/lib/types/client/ActivityPanel.d.ts +10 -8
- package/lib/types/client/AgentTeamsCard.d.ts +2 -2
- package/lib/types/client/activity-model.d.ts +4 -4
- package/lib/types/client/activity-monitor.d.ts +13 -3
- package/lib/types/client/index.d.ts +3 -4
- package/lib/types/client/panel-geometry.d.ts +49 -0
- package/lib/types/client/session-navigation.d.ts +22 -0
- package/lib/types/command.d.ts +14 -15
- package/lib/types/members.d.ts +17 -13
- package/package.json +23 -23
- package/release-notes/v0.1.10.md +48 -0
- package/release-notes/v0.1.11.md +52 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/** Pure persisted geometry rules for the AgentTeams shell-overlay panel. */
|
|
2
|
+
export const PANEL_LAYOUT_STORAGE_KEY = 'dsh-agent-teams:activity-panel:v1';
|
|
3
|
+
export const PANEL_COMPACT_BREAKPOINT = 960;
|
|
4
|
+
export const PANEL_DEFAULT_WIDTH = 388;
|
|
5
|
+
export const PANEL_DEFAULT_HEIGHT = 640;
|
|
6
|
+
export const PANEL_MIN_WIDTH = 320;
|
|
7
|
+
export const PANEL_MAX_WIDTH = 640;
|
|
8
|
+
export const PANEL_MIN_HEIGHT = 360;
|
|
9
|
+
export const PANEL_DOCK_TOP = 64;
|
|
10
|
+
export const PANEL_DOCK_RIGHT = 18;
|
|
11
|
+
export const PANEL_DOCK_BOTTOM = 48;
|
|
12
|
+
export const PANEL_FLOAT_MARGIN = 12;
|
|
13
|
+
export const DEFAULT_PANEL_LAYOUT = Object.freeze({
|
|
14
|
+
mode: 'docked',
|
|
15
|
+
x: 0,
|
|
16
|
+
y: PANEL_DOCK_TOP,
|
|
17
|
+
width: PANEL_DEFAULT_WIDTH,
|
|
18
|
+
height: PANEL_DEFAULT_HEIGHT,
|
|
19
|
+
heightMode: 'auto',
|
|
20
|
+
});
|
|
21
|
+
function clamp(value, minimum, maximum) {
|
|
22
|
+
return Math.min(Math.max(value, minimum), maximum);
|
|
23
|
+
}
|
|
24
|
+
function finite(value) {
|
|
25
|
+
return typeof value === 'number' && Number.isFinite(value);
|
|
26
|
+
}
|
|
27
|
+
/** Decode one versioned localStorage value, rejecting partial/corrupt state. */
|
|
28
|
+
export function parsePanelLayout(value) {
|
|
29
|
+
if (value === null)
|
|
30
|
+
return DEFAULT_PANEL_LAYOUT;
|
|
31
|
+
try {
|
|
32
|
+
const parsed = JSON.parse(value);
|
|
33
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
34
|
+
return DEFAULT_PANEL_LAYOUT;
|
|
35
|
+
const record = parsed;
|
|
36
|
+
if ((record.mode !== 'docked' && record.mode !== 'floating')
|
|
37
|
+
|| !finite(record.x) || !finite(record.y)
|
|
38
|
+
|| !finite(record.width) || !finite(record.height)) {
|
|
39
|
+
return DEFAULT_PANEL_LAYOUT;
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
mode: record.mode,
|
|
43
|
+
x: record.x,
|
|
44
|
+
y: record.y,
|
|
45
|
+
width: record.width,
|
|
46
|
+
height: record.height,
|
|
47
|
+
// v1 values written before content-fit height existed have no mode.
|
|
48
|
+
// Treat them as automatic so the upgrade removes legacy blank space.
|
|
49
|
+
heightMode: record.mode === 'floating' && record.heightMode === 'manual' ? 'manual' : 'auto',
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return DEFAULT_PANEL_LAYOUT;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Whether the panel should become a simple inset overlay with no gestures. */
|
|
57
|
+
export function compactPanelForBounds(bounds) {
|
|
58
|
+
return bounds.width <= PANEL_COMPACT_BREAKPOINT;
|
|
59
|
+
}
|
|
60
|
+
/** Docked and compact panels always fit content; floating panels may be user-sized. */
|
|
61
|
+
export function panelUsesAutoHeight(layout, bounds) {
|
|
62
|
+
return compactPanelForBounds(bounds) || layout.mode === 'docked' || layout.heightMode === 'auto';
|
|
63
|
+
}
|
|
64
|
+
/** CSS max-height ceiling that keeps an auto-height panel inside its shell. */
|
|
65
|
+
export function panelMaximumHeight(layout, bounds) {
|
|
66
|
+
const bottomInset = compactPanelForBounds(bounds) || layout.mode === 'floating'
|
|
67
|
+
? PANEL_FLOAT_MARGIN
|
|
68
|
+
: PANEL_DOCK_BOTTOM;
|
|
69
|
+
return Math.max(1, bounds.height - layout.y - bottomInset);
|
|
70
|
+
}
|
|
71
|
+
/** Resolve persisted state into a visible rectangle inside the current shell. */
|
|
72
|
+
export function resolvePanelGeometry(layout, bounds) {
|
|
73
|
+
const boundsWidth = Math.max(1, bounds.width);
|
|
74
|
+
const boundsHeight = Math.max(1, bounds.height);
|
|
75
|
+
if (compactPanelForBounds(bounds)) {
|
|
76
|
+
return {
|
|
77
|
+
...layout,
|
|
78
|
+
x: PANEL_FLOAT_MARGIN,
|
|
79
|
+
y: PANEL_FLOAT_MARGIN,
|
|
80
|
+
width: Math.max(1, boundsWidth - PANEL_FLOAT_MARGIN * 2),
|
|
81
|
+
height: Math.max(1, boundsHeight - PANEL_FLOAT_MARGIN * 2),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const maximumWidth = Math.max(1, Math.min(PANEL_MAX_WIDTH, boundsWidth - PANEL_FLOAT_MARGIN * 2));
|
|
85
|
+
const minimumWidth = Math.min(PANEL_MIN_WIDTH, maximumWidth);
|
|
86
|
+
const width = clamp(layout.width, minimumWidth, maximumWidth);
|
|
87
|
+
const maximumHeight = Math.max(1, boundsHeight - PANEL_FLOAT_MARGIN * 2);
|
|
88
|
+
const minimumHeight = Math.min(PANEL_MIN_HEIGHT, maximumHeight);
|
|
89
|
+
if (layout.mode === 'docked') {
|
|
90
|
+
const y = clamp(PANEL_DOCK_TOP, PANEL_FLOAT_MARGIN, Math.max(PANEL_FLOAT_MARGIN, boundsHeight - minimumHeight - PANEL_FLOAT_MARGIN));
|
|
91
|
+
const availableHeight = Math.max(1, boundsHeight - y - PANEL_DOCK_BOTTOM);
|
|
92
|
+
const height = clamp(availableHeight, Math.min(minimumHeight, availableHeight), maximumHeight);
|
|
93
|
+
const anchorRight = clamp(bounds.anchorRight, 0, boundsWidth);
|
|
94
|
+
const maximumX = Math.max(PANEL_FLOAT_MARGIN, boundsWidth - width - PANEL_FLOAT_MARGIN);
|
|
95
|
+
const x = clamp(anchorRight - PANEL_DOCK_RIGHT - width, PANEL_FLOAT_MARGIN, maximumX);
|
|
96
|
+
return { mode: 'docked', x, y, width, height, heightMode: layout.heightMode };
|
|
97
|
+
}
|
|
98
|
+
const height = clamp(layout.height, minimumHeight, maximumHeight);
|
|
99
|
+
return {
|
|
100
|
+
mode: 'floating',
|
|
101
|
+
x: clamp(layout.x, PANEL_FLOAT_MARGIN, Math.max(PANEL_FLOAT_MARGIN, boundsWidth - width - PANEL_FLOAT_MARGIN)),
|
|
102
|
+
y: clamp(layout.y, PANEL_FLOAT_MARGIN, Math.max(PANEL_FLOAT_MARGIN, boundsHeight - height - PANEL_FLOAT_MARGIN)),
|
|
103
|
+
width,
|
|
104
|
+
height,
|
|
105
|
+
heightMode: layout.heightMode,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/** Undock without a visual jump by adopting the panel's resolved rectangle. */
|
|
109
|
+
export function floatPanelLayout(geometry, bounds) {
|
|
110
|
+
return resolvePanelGeometry({ ...geometry, mode: 'floating' }, bounds);
|
|
111
|
+
}
|
|
112
|
+
/** Return to the right dock, preserving width and restoring content-fit height. */
|
|
113
|
+
export function dockPanelLayout(layout, bounds) {
|
|
114
|
+
return resolvePanelGeometry({ ...layout, mode: 'docked', heightMode: 'auto' }, bounds);
|
|
115
|
+
}
|
|
116
|
+
/** Translate a floating panel and clamp it back into the visible shell. */
|
|
117
|
+
export function movePanelLayout(start, dx, dy, bounds) {
|
|
118
|
+
return resolvePanelGeometry({ ...start, mode: 'floating', x: start.x + dx, y: start.y + dy }, bounds);
|
|
119
|
+
}
|
|
120
|
+
/** Resize while keeping the edge opposite the active handle stationary. */
|
|
121
|
+
export function resizePanelLayout(start, edge, dx, dy, bounds) {
|
|
122
|
+
if (start.mode === 'docked') {
|
|
123
|
+
if (edge !== 'left')
|
|
124
|
+
return resolvePanelGeometry(start, bounds);
|
|
125
|
+
return resolvePanelGeometry({ ...start, width: start.width - dx }, bounds);
|
|
126
|
+
}
|
|
127
|
+
const resolved = resolvePanelGeometry(start, bounds);
|
|
128
|
+
const minimumWidth = Math.min(PANEL_MIN_WIDTH, resolved.x + resolved.width - PANEL_FLOAT_MARGIN);
|
|
129
|
+
const minimumHeight = Math.min(PANEL_MIN_HEIGHT, bounds.height - resolved.y - PANEL_FLOAT_MARGIN);
|
|
130
|
+
if (edge === 'left') {
|
|
131
|
+
const right = resolved.x + resolved.width;
|
|
132
|
+
const maximumWidth = Math.max(1, Math.min(PANEL_MAX_WIDTH, right - PANEL_FLOAT_MARGIN));
|
|
133
|
+
const width = clamp(resolved.width - dx, Math.min(minimumWidth, maximumWidth), maximumWidth);
|
|
134
|
+
return { ...resolved, x: right - width, width };
|
|
135
|
+
}
|
|
136
|
+
const maximumHeight = Math.max(1, bounds.height - resolved.y - PANEL_FLOAT_MARGIN);
|
|
137
|
+
const height = clamp(resolved.height + dy, Math.min(minimumHeight, maximumHeight), maximumHeight);
|
|
138
|
+
if (edge === 'bottom')
|
|
139
|
+
return { ...resolved, height, heightMode: 'manual' };
|
|
140
|
+
const maximumWidth = Math.max(1, Math.min(PANEL_MAX_WIDTH, bounds.width - resolved.x - PANEL_FLOAT_MARGIN));
|
|
141
|
+
const width = clamp(resolved.width + dx, Math.min(minimumWidth, maximumWidth), maximumWidth);
|
|
142
|
+
return { ...resolved, width, height, heightMode: 'manual' };
|
|
143
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Version-tolerant navigation into durable AgentTeams member transcripts. */
|
|
2
|
+
/**
|
|
3
|
+
* Open one member's persisted transcript.
|
|
4
|
+
*
|
|
5
|
+
* Harness rc.8 intentionally removed cold subagents from the ordinary session
|
|
6
|
+
* list. They must first be rediscovered in their parent's catalog, then opened
|
|
7
|
+
* with the exact parent/child/mode address. Older runtimes have only `open()`;
|
|
8
|
+
* the fallback preserves the plugin's rc.6 peer range.
|
|
9
|
+
*/
|
|
10
|
+
export async function openAgentTeamMember(sessions, parentSessionId, childSessionId) {
|
|
11
|
+
if (sessions.openSubagent === undefined || sessions.refreshSubagents === undefined) {
|
|
12
|
+
sessions.open(childSessionId);
|
|
13
|
+
return 'session';
|
|
14
|
+
}
|
|
15
|
+
await sessions.refreshSubagents(parentSessionId);
|
|
16
|
+
const retained = sessions.subagentAddress?.(childSessionId);
|
|
17
|
+
sessions.openSubagent(retained?.parentSessionId === parentSessionId
|
|
18
|
+
? retained
|
|
19
|
+
: { parentSessionId, childSessionId, mode: 'continuable' });
|
|
20
|
+
return 'subagent';
|
|
21
|
+
}
|