@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
package/lib/members.js
CHANGED
|
@@ -318,44 +318,22 @@ export function interruptMember(ctx, captain, childId) {
|
|
|
318
318
|
ctx.logger.warn(`agent-teams: interrupt of member ${childId} failed: ${String(error)}`);
|
|
319
319
|
}
|
|
320
320
|
}
|
|
321
|
-
/** Resolve one live parent's workspace-scoped retirement index. */
|
|
322
|
-
async function retiredForParent(ctx, parentId, stateDir) {
|
|
323
|
-
const parent = ctx.agents.get(parentId);
|
|
324
|
-
return parent === undefined
|
|
325
|
-
? new Set()
|
|
326
|
-
: readRetiredMemberIds(join(parent.session.header.cwd ?? process.cwd(), stateDir));
|
|
327
|
-
}
|
|
328
321
|
/**
|
|
329
322
|
* Install the missing per-child retirement boundary above Harness rc.6.
|
|
330
323
|
*
|
|
331
324
|
* Upstream `interrupt()` deliberately preserves continuable sessions and the
|
|
332
325
|
* upstream seam exposes no targeted forget/retire method. The durable
|
|
333
|
-
* AgentTeams index therefore
|
|
334
|
-
* retired
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
*
|
|
326
|
+
* AgentTeams index therefore rejects `followup()` before it can cold-resume a
|
|
327
|
+
* retired member. Catalog rows deliberately remain discoverable: Harness rc.8
|
|
328
|
+
* uses the direct-child catalog to authorize historical transcript reads and
|
|
329
|
+
* `openSubagent()`, so filtering those rows would make an archived member's
|
|
330
|
+
* persisted conversation inaccessible. Exact ids keep unrelated subagents
|
|
331
|
+
* untouched while the followup boundary still prevents further model turns.
|
|
338
332
|
*/
|
|
339
333
|
export function installRetiredMemberGuard(ctx, stateDir) {
|
|
340
334
|
const runtime = ctx.subagents;
|
|
341
335
|
ctx.effect(() => {
|
|
342
|
-
const listChildren = runtime.listChildren;
|
|
343
|
-
const listDescendants = runtime.listDescendants;
|
|
344
336
|
const followup = runtime.followup;
|
|
345
|
-
const guardedChildren = async (parentId, signal) => {
|
|
346
|
-
const [entries, retired] = await Promise.all([
|
|
347
|
-
listChildren.call(runtime, parentId, signal),
|
|
348
|
-
retiredForParent(ctx, parentId, stateDir),
|
|
349
|
-
]);
|
|
350
|
-
return entries.filter(entry => !retired.has(entry.id));
|
|
351
|
-
};
|
|
352
|
-
const guardedDescendants = async (rootId, signal) => {
|
|
353
|
-
const [entries, retired] = await Promise.all([
|
|
354
|
-
listDescendants.call(runtime, rootId, signal),
|
|
355
|
-
retiredForParent(ctx, rootId, stateDir),
|
|
356
|
-
]);
|
|
357
|
-
return entries.filter(entry => !retired.has(entry.id));
|
|
358
|
-
};
|
|
359
337
|
const guardedFollowup = async (parent, childId, content, options) => {
|
|
360
338
|
const retired = await readRetiredMemberIds(join(parent.session.header.cwd ?? process.cwd(), stateDir));
|
|
361
339
|
if (retired.has(childId)) {
|
|
@@ -363,36 +341,32 @@ export function installRetiredMemberGuard(ctx, stateDir) {
|
|
|
363
341
|
}
|
|
364
342
|
return followup.call(runtime, parent, childId, content, options);
|
|
365
343
|
};
|
|
366
|
-
runtime.listChildren = guardedChildren;
|
|
367
|
-
runtime.listDescendants = guardedDescendants;
|
|
368
344
|
runtime.followup = guardedFollowup;
|
|
369
345
|
return () => {
|
|
370
|
-
if (runtime.listChildren === guardedChildren)
|
|
371
|
-
runtime.listChildren = listChildren;
|
|
372
|
-
if (runtime.listDescendants === guardedDescendants)
|
|
373
|
-
runtime.listDescendants = listDescendants;
|
|
374
346
|
if (runtime.followup === guardedFollowup)
|
|
375
347
|
runtime.followup = followup;
|
|
376
348
|
};
|
|
377
349
|
}, 'agent-teams: retired member guard');
|
|
378
350
|
}
|
|
379
351
|
/**
|
|
380
|
-
* Snapshot
|
|
381
|
-
*
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
386
|
-
*
|
|
352
|
+
* Snapshot the real driver activity for durable member ids.
|
|
353
|
+
*
|
|
354
|
+
* The team record is the membership authority, so this path intentionally no
|
|
355
|
+
* longer depends on `listChildren()`'s versioned projection shape. Harness
|
|
356
|
+
* rc.8 changed those rows to branded `SessionId` values plus residency-only
|
|
357
|
+
* `activity`; neither is needed to answer whether the live Agent driver is
|
|
358
|
+
* running, idle, or absent/ready.
|
|
359
|
+
* @param ctx - the plugin context (injects `agents`).
|
|
360
|
+
* @param memberIds - child ids restored from the durable team record.
|
|
361
|
+
* @returns child id → live activity.
|
|
387
362
|
*/
|
|
388
|
-
export
|
|
389
|
-
const entries = await ctx.subagents.listChildren(brandedSessionId(captainSessionId));
|
|
363
|
+
export function memberActivity(ctx, memberIds) {
|
|
390
364
|
const activity = new Map();
|
|
391
|
-
for (const
|
|
392
|
-
if (
|
|
365
|
+
for (const id of memberIds) {
|
|
366
|
+
if (id === '')
|
|
393
367
|
continue;
|
|
394
|
-
const live = ctx.agents.get(
|
|
395
|
-
activity.set(
|
|
368
|
+
const live = ctx.agents.get(brandedSessionId(id));
|
|
369
|
+
activity.set(id, live === undefined ? 'ready' : live.status);
|
|
396
370
|
}
|
|
397
371
|
return activity;
|
|
398
372
|
}
|
package/lib/snapshot.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { readdir } from 'node:fs/promises';
|
|
11
11
|
import { join } from 'node:path';
|
|
12
|
+
import { memberActivity } from "./members.js";
|
|
12
13
|
import { CAPTAIN_KEY, listArchivedTeamIds, readArchivedTeam, readUnreadMailbox, readTeam, taskDepthsById, taskVisualState, } from "./state.js";
|
|
13
14
|
/** The current task of a member: its first unfinished owned task. */
|
|
14
15
|
function currentTaskOf(memberName, tasks) {
|
|
@@ -32,21 +33,9 @@ export async function assembleTeamSnapshot(ctx, stateRoot, workspace, state, opt
|
|
|
32
33
|
const roster = options.includeRemoved === true
|
|
33
34
|
? state.members
|
|
34
35
|
: state.members.filter((member) => member.status !== 'removed');
|
|
35
|
-
const activity =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const children = await ctx.subagents.listChildren(state.captainSessionId);
|
|
39
|
-
for (const entry of children) {
|
|
40
|
-
if (entry.kind === 'child') {
|
|
41
|
-
const live = ctx.agents.get(entry.id);
|
|
42
|
-
activity.set(entry.id, live === undefined ? 'ready' : live.status);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
ctx.logger.warn(`agent-teams: activity listing failed for ${state.name}: ${String(error)}`);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
36
|
+
const activity = options.historic === true
|
|
37
|
+
? new Map()
|
|
38
|
+
: memberActivity(ctx, roster.map((member) => member.id));
|
|
50
39
|
const unreadByMember = new Map();
|
|
51
40
|
for (const member of roster) {
|
|
52
41
|
try {
|
package/lib/tools.js
CHANGED
|
@@ -871,7 +871,7 @@ export function registerAgentTeamsTools(ctx, config) {
|
|
|
871
871
|
await scheduler.kickTeam(workspace, located.id, caller);
|
|
872
872
|
}
|
|
873
873
|
const { team, identity } = await withTeamLock(teamLockKey(stateRoot, located.id), () => requireFreshParticipant(stateRoot, located.id, caller.id));
|
|
874
|
-
const activity =
|
|
874
|
+
const activity = memberActivity(ctx, team.members.map((member) => member.id));
|
|
875
875
|
const members = team.members
|
|
876
876
|
.filter((member) => member.status !== 'removed')
|
|
877
877
|
.map((member) => ({
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* AgentTeams activity panel: the top-right floater monitoring every team.
|
|
3
3
|
*
|
|
4
|
-
* Modeled on the Claude Code desktop SessionActivityPanel: a
|
|
5
|
-
* panel at the top-right
|
|
6
|
-
*
|
|
4
|
+
* Modeled on the Claude Code desktop SessionActivityPanel: a shell-overlay
|
|
5
|
+
* panel that docks at the conversation's top-right edge by default, can be
|
|
6
|
+
* dragged into a floating window, resized, and folded into an activity badge.
|
|
7
|
+
* On wide viewports the docked panel makes the conversation column yield
|
|
8
|
+
* space; narrow viewports keep a simple inset overlay. It
|
|
7
9
|
* polls the host `/plugins/dsh-agent-teams/state` route for
|
|
8
10
|
* server-side snapshots (durable files + live subagent activity), with a
|
|
9
11
|
* collapsed badge that auto-expands once when activity appears. Archived
|
|
10
12
|
* teams stay available for the owning conversation after live work ends.
|
|
11
13
|
*
|
|
12
|
-
* The floater mounts
|
|
13
|
-
*
|
|
14
|
-
*
|
|
14
|
+
* The floater mounts in ui-layout's additive `shell.overlay`; it is not a
|
|
15
|
+
* conversation node — the in-conversation panel was removed in favor of this
|
|
16
|
+
* always-available monitor.
|
|
15
17
|
* @module dsh-agent-teams/client/activity
|
|
16
18
|
*/
|
|
17
19
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
@@ -19,7 +21,7 @@ import type { ObservableSnapshot, SessionListState } from '@deepseek-ai/dsh-clie
|
|
|
19
21
|
/** The top-right activity floater. Teams follow the current session: live
|
|
20
22
|
* snapshots and historic card summaries are only shown while their captain
|
|
21
23
|
* session is the one currently open. */
|
|
22
|
-
export declare function ActivityPanel({ sessionsList,
|
|
24
|
+
export declare function ActivityPanel({ sessionsList, openMember }: {
|
|
23
25
|
readonly sessionsList: ObservableSnapshot<SessionListState>;
|
|
24
|
-
readonly
|
|
26
|
+
readonly openMember: (parentId: SessionId, childId: SessionId) => void;
|
|
25
27
|
}): import("react").JSX.Element | null;
|
|
@@ -15,9 +15,9 @@ import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
|
|
15
15
|
export declare const OPEN_PANEL_EVENT = "agent-teams:open-panel";
|
|
16
16
|
/** Navigation action injected from the plugin's own SessionsService access. */
|
|
17
17
|
export interface AgentTeamsCardInjected {
|
|
18
|
-
readonly
|
|
18
|
+
readonly openMember: (parentId: SessionId, childId: SessionId) => void;
|
|
19
19
|
}
|
|
20
20
|
/** Complete keyed Chat renderer props. */
|
|
21
21
|
export type AgentTeamsCardProps = PropsRuntime<'conversation.chat.node', 'agent-teams'> & PropsLocale<'agentTeams'> & AgentTeamsCardInjected;
|
|
22
22
|
/** Render one durable team as a compact conversation card. */
|
|
23
|
-
export declare function AgentTeamsCard({ node,
|
|
23
|
+
export declare function AgentTeamsCard({ node, openMember, sessionId }: AgentTeamsCardProps): import("react").JSX.Element;
|
|
@@ -39,10 +39,10 @@ export declare function usesParallelTaskGrid<T extends RelationshipTask>(tasks:
|
|
|
39
39
|
/**
|
|
40
40
|
* Whether an expanded activity panel still belongs to the current session.
|
|
41
41
|
*
|
|
42
|
-
* The panel is mounted
|
|
43
|
-
* when the conversation route changes. Ownership keeps an expanded
|
|
44
|
-
* from leaking onto the new-session screen (or another conversation)
|
|
45
|
-
* its local open state is being reset.
|
|
42
|
+
* The panel is mounted in the root-scoped shell overlay, so React does not
|
|
43
|
+
* remount it when the conversation route changes. Ownership keeps an expanded
|
|
44
|
+
* panel from leaking onto the new-session screen (or another conversation)
|
|
45
|
+
* while its local open state is being reset.
|
|
46
46
|
*/
|
|
47
47
|
export declare function activityPanelExpandedForSession(open: boolean, owner: string | undefined, current: string | undefined): boolean;
|
|
48
48
|
/**
|
|
@@ -79,6 +79,12 @@ interface ActivityFetchResponse {
|
|
|
79
79
|
}
|
|
80
80
|
/** Injectable browser primitives used by the poll controller and its tests. */
|
|
81
81
|
export interface ActivityPollingRuntime {
|
|
82
|
+
/**
|
|
83
|
+
* Current captain session to discover after a cold client/host restart.
|
|
84
|
+
* This one-time scope restores teams whose older conversation log has no
|
|
85
|
+
* AgentTeams card capable of registering an explicit monitor target.
|
|
86
|
+
*/
|
|
87
|
+
readonly discoverySessionId?: string;
|
|
82
88
|
readonly fetchState?: (url: string, init: {
|
|
83
89
|
readonly cache: 'no-store';
|
|
84
90
|
readonly signal: AbortSignal;
|
|
@@ -98,9 +104,13 @@ export interface ActivityPollingController {
|
|
|
98
104
|
/**
|
|
99
105
|
* Start the single polling loop for the current session's requested targets.
|
|
100
106
|
*
|
|
101
|
-
* With
|
|
102
|
-
*
|
|
103
|
-
*
|
|
107
|
+
* With neither targets nor a discovery session this is deliberately inert.
|
|
108
|
+
* A discovery session performs one live+archive pass after selection/restart;
|
|
109
|
+
* it keeps polling only while that captain still owns a live team. This
|
|
110
|
+
* restores legacy/cardless history without turning every ordinary session
|
|
111
|
+
* into a permanent one-second filesystem scan. Explicit card targets retain
|
|
112
|
+
* the normal cadence, and archive state is refreshed when a target or a
|
|
113
|
+
* previously discovered live team disappears.
|
|
104
114
|
*/
|
|
105
115
|
export declare function startActivityPolling(monitorTargets: readonly ActivityMonitorTarget[], runtime?: ActivityPollingRuntime): ActivityPollingController;
|
|
106
116
|
export {};
|
|
@@ -3,9 +3,8 @@ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
|
3
3
|
/** Required services: conversation nodes, slots, and sessions navigation. */
|
|
4
4
|
export declare const inject: string[];
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* for a closed floater or a re-opened session.
|
|
6
|
+
* Register the activity monitor in the shell's additive overlay and the
|
|
7
|
+
* in-conversation team card. The card's activity button re-opens a folded
|
|
8
|
+
* monitor via a window event — the recovery path for an old session.
|
|
10
9
|
*/
|
|
11
10
|
export declare function apply(ctx: ClientContext): void;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/** Pure persisted geometry rules for the AgentTeams shell-overlay panel. */
|
|
2
|
+
export type PanelMode = 'docked' | 'floating';
|
|
3
|
+
export type PanelHeightMode = 'auto' | 'manual';
|
|
4
|
+
export type PanelResizeEdge = 'left' | 'bottom' | 'corner';
|
|
5
|
+
/** User-owned panel state persisted between browser sessions. */
|
|
6
|
+
export interface PanelLayout {
|
|
7
|
+
readonly mode: PanelMode;
|
|
8
|
+
readonly x: number;
|
|
9
|
+
readonly y: number;
|
|
10
|
+
readonly width: number;
|
|
11
|
+
readonly height: number;
|
|
12
|
+
readonly heightMode: PanelHeightMode;
|
|
13
|
+
}
|
|
14
|
+
/** The shell-overlay box and the right edge of its current conversation. */
|
|
15
|
+
export interface PanelBounds {
|
|
16
|
+
readonly width: number;
|
|
17
|
+
readonly height: number;
|
|
18
|
+
readonly anchorRight: number;
|
|
19
|
+
}
|
|
20
|
+
export declare const PANEL_LAYOUT_STORAGE_KEY = "dsh-agent-teams:activity-panel:v1";
|
|
21
|
+
export declare const PANEL_COMPACT_BREAKPOINT = 960;
|
|
22
|
+
export declare const PANEL_DEFAULT_WIDTH = 388;
|
|
23
|
+
export declare const PANEL_DEFAULT_HEIGHT = 640;
|
|
24
|
+
export declare const PANEL_MIN_WIDTH = 320;
|
|
25
|
+
export declare const PANEL_MAX_WIDTH = 640;
|
|
26
|
+
export declare const PANEL_MIN_HEIGHT = 360;
|
|
27
|
+
export declare const PANEL_DOCK_TOP = 64;
|
|
28
|
+
export declare const PANEL_DOCK_RIGHT = 18;
|
|
29
|
+
export declare const PANEL_DOCK_BOTTOM = 48;
|
|
30
|
+
export declare const PANEL_FLOAT_MARGIN = 12;
|
|
31
|
+
export declare const DEFAULT_PANEL_LAYOUT: PanelLayout;
|
|
32
|
+
/** Decode one versioned localStorage value, rejecting partial/corrupt state. */
|
|
33
|
+
export declare function parsePanelLayout(value: string | null): PanelLayout;
|
|
34
|
+
/** Whether the panel should become a simple inset overlay with no gestures. */
|
|
35
|
+
export declare function compactPanelForBounds(bounds: PanelBounds): boolean;
|
|
36
|
+
/** Docked and compact panels always fit content; floating panels may be user-sized. */
|
|
37
|
+
export declare function panelUsesAutoHeight(layout: PanelLayout, bounds: PanelBounds): boolean;
|
|
38
|
+
/** CSS max-height ceiling that keeps an auto-height panel inside its shell. */
|
|
39
|
+
export declare function panelMaximumHeight(layout: PanelLayout, bounds: PanelBounds): number;
|
|
40
|
+
/** Resolve persisted state into a visible rectangle inside the current shell. */
|
|
41
|
+
export declare function resolvePanelGeometry(layout: PanelLayout, bounds: PanelBounds): PanelLayout;
|
|
42
|
+
/** Undock without a visual jump by adopting the panel's resolved rectangle. */
|
|
43
|
+
export declare function floatPanelLayout(geometry: PanelLayout, bounds: PanelBounds): PanelLayout;
|
|
44
|
+
/** Return to the right dock, preserving width and restoring content-fit height. */
|
|
45
|
+
export declare function dockPanelLayout(layout: PanelLayout, bounds: PanelBounds): PanelLayout;
|
|
46
|
+
/** Translate a floating panel and clamp it back into the visible shell. */
|
|
47
|
+
export declare function movePanelLayout(start: PanelLayout, dx: number, dy: number, bounds: PanelBounds): PanelLayout;
|
|
48
|
+
/** Resize while keeping the edge opposite the active handle stationary. */
|
|
49
|
+
export declare function resizePanelLayout(start: PanelLayout, edge: PanelResizeEdge, dx: number, dy: number, bounds: PanelBounds): PanelLayout;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Version-tolerant navigation into durable AgentTeams member transcripts. */
|
|
2
|
+
import type { SessionId, SubagentAddress } from '@deepseek-ai/dsh-client-runtime/client';
|
|
3
|
+
/** Narrow sessions-service face used by the activity panel and team card. */
|
|
4
|
+
export interface AgentTeamsSessionNavigator {
|
|
5
|
+
/** Legacy/ordinary session navigation. */
|
|
6
|
+
open(id: SessionId): void;
|
|
7
|
+
/** rc.8 addressed subagent navigation. */
|
|
8
|
+
openSubagent?(address: SubagentAddress): void;
|
|
9
|
+
/** Refresh the exact parent's durable direct-child catalog. */
|
|
10
|
+
refreshSubagents?(parentSessionId: SessionId): Promise<void>;
|
|
11
|
+
/** Reuse an address already retained by the client runtime when available. */
|
|
12
|
+
subagentAddress?(id: SessionId): SubagentAddress | undefined;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Open one member's persisted transcript.
|
|
16
|
+
*
|
|
17
|
+
* Harness rc.8 intentionally removed cold subagents from the ordinary session
|
|
18
|
+
* list. They must first be rediscovered in their parent's catalog, then opened
|
|
19
|
+
* with the exact parent/child/mode address. Older runtimes have only `open()`;
|
|
20
|
+
* the fallback preserves the plugin's rc.6 peer range.
|
|
21
|
+
*/
|
|
22
|
+
export declare function openAgentTeamMember(sessions: AgentTeamsSessionNavigator, parentSessionId: SessionId, childSessionId: SessionId): Promise<'subagent' | 'session'>;
|
package/lib/types/command.d.ts
CHANGED
|
@@ -8,18 +8,16 @@
|
|
|
8
8
|
* `/agent-teams` command. The web GUI's slash menu (the Harness
|
|
9
9
|
* `ui-commands` client) lists it from the host catalog with the input
|
|
10
10
|
* hint; the argued line is claimed client-side and executed through
|
|
11
|
-
* `command.execute
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* no "use AgentTeams" phrasing required.
|
|
11
|
+
* `command.execute`. The handler replays that exact line as an ordinary
|
|
12
|
+
* user follow-up (`agent.followup`) so it remains visible in the chat; the
|
|
13
|
+
* gesture boundary then adds the deterministic activation message.
|
|
15
14
|
* 2. **Gesture boundary** — a `agent/pre-step` listener recognizes a leading
|
|
16
15
|
* `/agent-teams` token in genuine user messages and injects the same
|
|
17
16
|
* activation message. This covers surfaces with no command adjudication
|
|
18
|
-
* (headless CLI, API, pasted text in plain composers) and
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* gesture.
|
|
17
|
+
* (headless CLI, API, pasted text in plain composers) and also handles the
|
|
18
|
+
* exact user line replayed by the host command. Mid-sentence mentions stay
|
|
19
|
+
* ordinary prose; only `source.kind === 'user'` messages are scanned, so
|
|
20
|
+
* injected or external text cannot forge the gesture.
|
|
23
21
|
*
|
|
24
22
|
* @module dsh-agent-teams/command
|
|
25
23
|
*/
|
|
@@ -30,8 +28,8 @@ export declare const AGENT_TEAMS_COMMAND = "agent-teams";
|
|
|
30
28
|
declare module '@deepseek-ai/dsh-llm' {
|
|
31
29
|
interface MessageSourceMap {
|
|
32
30
|
/**
|
|
33
|
-
* A deterministic `/agent-teams` activation
|
|
34
|
-
*
|
|
31
|
+
* A deterministic `/agent-teams` activation injected after the visible
|
|
32
|
+
* user-authored slash line.
|
|
35
33
|
*/
|
|
36
34
|
'agent-teams-command': {
|
|
37
35
|
readonly kind: 'agent-teams-command';
|
|
@@ -55,10 +53,11 @@ export declare function buildActivationDirective(goal: string): string;
|
|
|
55
53
|
export declare function invokedAgentTeamsGoal(messages: readonly UserMessage[]): string | undefined;
|
|
56
54
|
/**
|
|
57
55
|
* Register the closed-namespace `/agent-teams` host command. The handler
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* a disposed scope (HMR, plugin removal) unregisters the
|
|
56
|
+
* preserves the exact submitted slash line as an ordinary user follow-up;
|
|
57
|
+
* the pre-step gesture boundary injects the activation directive and wakes
|
|
58
|
+
* the captain deterministically. The registration rides the calling
|
|
59
|
+
* context's fiber, so a disposed scope (HMR, plugin removal) unregisters the
|
|
60
|
+
* command.
|
|
62
61
|
* @param ctx - host context providing the `commands` registry.
|
|
63
62
|
*/
|
|
64
63
|
export declare function registerAgentTeamsCommand(ctx: Context): void;
|
package/lib/types/members.d.ts
CHANGED
|
@@ -123,20 +123,24 @@ export declare function interruptMember(ctx: Context, captain: Agent, childId: s
|
|
|
123
123
|
*
|
|
124
124
|
* Upstream `interrupt()` deliberately preserves continuable sessions and the
|
|
125
125
|
* upstream seam exposes no targeted forget/retire method. The durable
|
|
126
|
-
* AgentTeams index therefore
|
|
127
|
-
* retired
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
*
|
|
126
|
+
* AgentTeams index therefore rejects `followup()` before it can cold-resume a
|
|
127
|
+
* retired member. Catalog rows deliberately remain discoverable: Harness rc.8
|
|
128
|
+
* uses the direct-child catalog to authorize historical transcript reads and
|
|
129
|
+
* `openSubagent()`, so filtering those rows would make an archived member's
|
|
130
|
+
* persisted conversation inaccessible. Exact ids keep unrelated subagents
|
|
131
|
+
* untouched while the followup boundary still prevents further model turns.
|
|
131
132
|
*/
|
|
132
133
|
export declare function installRetiredMemberGuard(ctx: Context, stateDir: string): void;
|
|
133
134
|
/**
|
|
134
|
-
* Snapshot
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
*
|
|
135
|
+
* Snapshot the real driver activity for durable member ids.
|
|
136
|
+
*
|
|
137
|
+
* The team record is the membership authority, so this path intentionally no
|
|
138
|
+
* longer depends on `listChildren()`'s versioned projection shape. Harness
|
|
139
|
+
* rc.8 changed those rows to branded `SessionId` values plus residency-only
|
|
140
|
+
* `activity`; neither is needed to answer whether the live Agent driver is
|
|
141
|
+
* running, idle, or absent/ready.
|
|
142
|
+
* @param ctx - the plugin context (injects `agents`).
|
|
143
|
+
* @param memberIds - child ids restored from the durable team record.
|
|
144
|
+
* @returns child id → live activity.
|
|
141
145
|
*/
|
|
142
|
-
export declare function memberActivity(ctx: Context,
|
|
146
|
+
export declare function memberActivity(ctx: Context, memberIds: readonly string[]): Map<string, 'running' | 'idle' | 'ready'>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nanmicoder/dsh-agent-teams",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"description": "AgentTeams for DeepSeek Harness: multi-agent team collaboration (captain, members, tasks with dependencies, messaging) driven by natural language, with a tree monitor in the web GUI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -21,7 +21,9 @@
|
|
|
21
21
|
"lib",
|
|
22
22
|
"assets/agent-teams",
|
|
23
23
|
"assets/readme",
|
|
24
|
+
"assets/ui.png",
|
|
24
25
|
"cordis.patch.yml",
|
|
26
|
+
"release-notes",
|
|
25
27
|
"README.md",
|
|
26
28
|
"README_ZH.md"
|
|
27
29
|
],
|
|
@@ -64,19 +66,12 @@
|
|
|
64
66
|
"inject": [
|
|
65
67
|
"@deepseek-ai/dsh-client-locale",
|
|
66
68
|
"@deepseek-ai/dsh-client-runtime",
|
|
67
|
-
"@deepseek-ai/dsh-client-ui-conversation"
|
|
69
|
+
"@deepseek-ai/dsh-client-ui-conversation",
|
|
70
|
+
"@deepseek-ai/dsh-client-ui-layout"
|
|
68
71
|
],
|
|
69
72
|
"platform": "web"
|
|
70
73
|
}
|
|
71
74
|
},
|
|
72
|
-
"dshClient": {
|
|
73
|
-
"inject": [
|
|
74
|
-
"@deepseek-ai/dsh-client-locale",
|
|
75
|
-
"@deepseek-ai/dsh-client-runtime",
|
|
76
|
-
"@deepseek-ai/dsh-client-ui-conversation"
|
|
77
|
-
],
|
|
78
|
-
"platform": "web"
|
|
79
|
-
},
|
|
80
75
|
"scripts": {
|
|
81
76
|
"build": "tsc -p tsconfig.json && tsc -p tsconfig.client.json && tsdown",
|
|
82
77
|
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
|
|
@@ -91,6 +86,7 @@
|
|
|
91
86
|
"@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
|
|
92
87
|
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.6",
|
|
93
88
|
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6",
|
|
89
|
+
"@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.6",
|
|
94
90
|
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
|
|
95
91
|
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6",
|
|
96
92
|
"@deepseek-ai/dsh-commands": "^0.1.0-rc.6",
|
|
@@ -118,6 +114,9 @@
|
|
|
118
114
|
"@deepseek-ai/dsh-client-ui-conversation": {
|
|
119
115
|
"optional": true
|
|
120
116
|
},
|
|
117
|
+
"@deepseek-ai/dsh-client-ui-layout": {
|
|
118
|
+
"optional": true
|
|
119
|
+
},
|
|
121
120
|
"@deepseek-ai/dsh-client-ui-primitives": {
|
|
122
121
|
"optional": true
|
|
123
122
|
},
|
|
@@ -151,19 +150,20 @@
|
|
|
151
150
|
},
|
|
152
151
|
"devDependencies": {
|
|
153
152
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
154
|
-
"@deepseek-ai/dsh-agent": "0.1.0-rc.
|
|
155
|
-
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.
|
|
156
|
-
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.
|
|
157
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.
|
|
158
|
-
"@deepseek-ai/dsh-client-ui-
|
|
159
|
-
"@deepseek-ai/dsh-client-ui-
|
|
160
|
-
"@deepseek-ai/dsh-
|
|
161
|
-
"@deepseek-ai/dsh-
|
|
162
|
-
"@deepseek-ai/dsh-
|
|
163
|
-
"@deepseek-ai/dsh-
|
|
164
|
-
"@deepseek-ai/dsh-
|
|
165
|
-
"@deepseek-ai/dsh-
|
|
166
|
-
"@deepseek-ai/dsh-
|
|
153
|
+
"@deepseek-ai/dsh-agent": "0.1.0-rc.8",
|
|
154
|
+
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.8",
|
|
155
|
+
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8",
|
|
156
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8",
|
|
157
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.1.0-rc.8",
|
|
158
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8",
|
|
159
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.0-rc.8",
|
|
160
|
+
"@deepseek-ai/dsh-commands": "0.1.0-rc.8",
|
|
161
|
+
"@deepseek-ai/dsh-llm": "0.1.0-rc.8",
|
|
162
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.8",
|
|
163
|
+
"@deepseek-ai/dsh-subagent": "0.1.0-rc.8",
|
|
164
|
+
"@deepseek-ai/dsh-system-prompt": "0.1.0-rc.8",
|
|
165
|
+
"@deepseek-ai/dsh-tools": "0.1.0-rc.8",
|
|
166
|
+
"@deepseek-ai/dsh-workspace": "0.1.0-rc.8",
|
|
167
167
|
"@deepseek-ai/schemastery": "^3.18.1",
|
|
168
168
|
"@types/node": "^24.13.3",
|
|
169
169
|
"@types/react": "~18.3.1",
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# AgentTeams v0.1.10
|
|
2
|
+
|
|
3
|
+
This release makes the AgentTeams activity panel easier to place and size, fixes the `/agent-teams` conversation history, and gives the whale roles a cleaner visual treatment. It is tested against DeepSeek Harness `0.1.0-rc.8`.
|
|
4
|
+
|
|
5
|
+
## New & Improved
|
|
6
|
+
|
|
7
|
+
- **Movable and resizable activity panel**: switch between docked and floating layouts, drag the floating panel by its header, and resize it from the supported edges and corner. Position, size, and dock mode persist across refreshes.
|
|
8
|
+
- **Content-aware height**: the panel grows with its content and only introduces internal scrolling after reaching the viewport safety limit, avoiding a large empty area for smaller teams.
|
|
9
|
+
- **Cleaner role portraits**: captain and member artwork now uses transparent, uncropped character silhouettes with clearer sizing, lighter state stickers, and a compact unread indicator.
|
|
10
|
+
|
|
11
|
+
## Fixes
|
|
12
|
+
|
|
13
|
+
- Preserved the exact `/agent-teams ...` input as the normal user message in the main conversation.
|
|
14
|
+
- Kept command context injections below the user message in chronological order.
|
|
15
|
+
- Removed the duplicate slash-command result row while retaining the durable command events.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
dsh plugin --profile web add @nanmicoder/dsh-agent-teams
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
<details>
|
|
24
|
+
<summary><b>中文版本 / Chinese Version</b></summary>
|
|
25
|
+
|
|
26
|
+
# AgentTeams v0.1.10
|
|
27
|
+
|
|
28
|
+
本次更新重点改善 AgentTeams 活动面板的摆放与尺寸体验,修复 `/agent-teams` 在主会话中的消息展示,并重新整理鲸鱼角色头像的视觉层级。已基于 DeepSeek Harness `0.1.0-rc.8` 完成验证。
|
|
29
|
+
|
|
30
|
+
## 新增与改进
|
|
31
|
+
|
|
32
|
+
- **活动面板支持移动和缩放**:可在停靠与浮动布局之间切换;浮动态可以拖动标题栏,并从支持的边缘和右下角调整尺寸。面板位置、尺寸和停靠模式会在刷新后恢复。
|
|
33
|
+
- **高度跟随内容**:面板先根据团队内容自然增长,达到视口安全上限后才启用内部滚动,小团队不再出现大块空白。
|
|
34
|
+
- **角色头像更清晰**:队长和成员改为透明、无裁切的完整角色剪影,统一头像尺寸,减轻状态贴纸,并使用更轻量的未读提示。
|
|
35
|
+
|
|
36
|
+
## 修复
|
|
37
|
+
|
|
38
|
+
- 将用户输入的完整 `/agent-teams ...` 原文保留为主会话中的普通用户消息。
|
|
39
|
+
- 上下文注入按时间顺序显示在用户消息下方。
|
|
40
|
+
- 移除重复的 slash command 结果行,同时保留持久化命令事件。
|
|
41
|
+
|
|
42
|
+
## 安装
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
dsh plugin --profile web add @nanmicoder/dsh-agent-teams
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
</details>
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# AgentTeams v0.1.11
|
|
2
|
+
|
|
3
|
+
This release restores AgentTeams activity and member history after a DeepSeek Harness client or host restart. It fixes the rc.8 compatibility regressions reported in [#60](https://github.com/NanmiCoder/dsh-agent-teams/issues/60) and [#61](https://github.com/NanmiCoder/dsh-agent-teams/issues/61).
|
|
4
|
+
|
|
5
|
+
## Fixes
|
|
6
|
+
|
|
7
|
+
- **Cold-start activity recovery**: selecting a captain session now performs a lightweight live and archived team discovery pass, so older sessions without an AgentTeams conversation card restore their activity panel after restart.
|
|
8
|
+
- **Reliable member activity**: live `running / idle / ready` state is resolved from the durable team roster and Agent registry instead of depending on the versioned `listChildren()` projection shape.
|
|
9
|
+
- **Persistent member history**: retired AgentTeams members remain discoverable in the Harness subagent catalog for transcript review while direct follow-up remains blocked.
|
|
10
|
+
- **rc.8 transcript navigation**: activity-panel and conversation-card member links refresh the parent catalog and use addressed `openSubagent()` navigation, with a fallback for older Harness runtimes.
|
|
11
|
+
|
|
12
|
+
## Verification
|
|
13
|
+
|
|
14
|
+
- Reproduced the full captain/member/task/archive lifecycle in a real `/tmp` workspace on the Harness web client.
|
|
15
|
+
- Verified cold restart recovery without opening the built-in subagent catalog first.
|
|
16
|
+
- Verified archived member navigation and complete persisted task history.
|
|
17
|
+
- Passed type checking, production build, offline verification, lifecycle verification, and the eight-member complex stress suite.
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
dsh plugin --profile web add @nanmicoder/dsh-agent-teams
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
<details>
|
|
26
|
+
<summary><b>中文版本 / Chinese Version</b></summary>
|
|
27
|
+
|
|
28
|
+
# AgentTeams v0.1.11
|
|
29
|
+
|
|
30
|
+
本次更新修复 DeepSeek Harness 客户端或 host 重启后 AgentTeams 活动面板与成员历史消失的问题,对应 [#60](https://github.com/NanmiCoder/dsh-agent-teams/issues/60) 和 [#61](https://github.com/NanmiCoder/dsh-agent-teams/issues/61) 中报告的 rc.8 兼容性回归。
|
|
31
|
+
|
|
32
|
+
## 修复
|
|
33
|
+
|
|
34
|
+
- **冷启动活动恢复**:选择队长会话时会执行一次轻量的活动团队与历史归档发现;即使旧会话没有 AgentTeams 对话卡片,重启后也能恢复活动面板。
|
|
35
|
+
- **可靠的成员活动状态**:从持久化团队成员表和 Agent registry 解析真实的 `running / idle / ready`,不再依赖容易变化的 `listChildren()` 投影结构。
|
|
36
|
+
- **成员历史持续可见**:已退休的 AgentTeams 成员继续保留在 Harness 子代理目录中供历史记录查看,但直接 follow-up 仍会被拒绝。
|
|
37
|
+
- **rc.8 历史会话导航**:活动面板和对话卡片会先刷新父级目录,再通过带父子地址的 `openSubagent()` 打开成员记录;旧版 Harness 继续使用兼容回退。
|
|
38
|
+
|
|
39
|
+
## 验证
|
|
40
|
+
|
|
41
|
+
- 在 Harness Web 客户端的真实 `/tmp` workspace 中完成队长、成员、任务和归档全流程复现。
|
|
42
|
+
- 验证未预先打开内置子代理目录时的冷重启恢复。
|
|
43
|
+
- 验证归档成员导航及完整持久化任务历史。
|
|
44
|
+
- 通过类型检查、生产构建、离线验证、生命周期验证及八成员复杂压力测试。
|
|
45
|
+
|
|
46
|
+
## 安装
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
dsh plugin --profile web add @nanmicoder/dsh-agent-teams
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
</details>
|