@nanmicoder/dsh-agent-teams 0.1.10 → 0.1.12

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/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 guards all three public continuation boundaries:
334
- * retired rows disappear from `list_agents` (children and descendants), and a
335
- * direct `followup()` is rejected before it can cold-resume the member. Exact
336
- * ids keep unrelated subagents untouched; transcripts remain in persistence
337
- * for archived-team review.
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 each direct continuable child's real driver activity under the
381
- * captain's session. `listChildren().activity` is only session residency, so
382
- * live children are refined through the Agent registry exactly like Harness's
383
- * shipped `list_agents` tool.
384
- * @param ctx - the plugin context (injects `subagents`).
385
- * @param captainSessionId - the captain's session id.
386
- * @returns child id → activity, missing entries are unknown children.
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 async function memberActivity(ctx, captainSessionId) {
389
- const entries = await ctx.subagents.listChildren(brandedSessionId(captainSessionId));
363
+ export function memberActivity(ctx, memberIds) {
390
364
  const activity = new Map();
391
- for (const entry of entries) {
392
- if (entry.kind !== 'child')
365
+ for (const id of memberIds) {
366
+ if (id === '')
393
367
  continue;
394
- const live = ctx.agents.get(entry.id);
395
- activity.set(entry.id, live === undefined ? 'ready' : live.status);
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 = new Map();
36
- if (options.historic !== true) {
37
- try {
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 = await memberActivity(ctx, team.captainSessionId);
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) => ({
@@ -16,12 +16,14 @@
16
16
  * always-available monitor.
17
17
  * @module dsh-agent-teams/client/activity
18
18
  */
19
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots';
19
20
  import type { SessionId } from '@deepseek-ai/dsh-session/types';
20
21
  import type { ObservableSnapshot, SessionListState } from '@deepseek-ai/dsh-client-runtime/client';
21
22
  /** The top-right activity floater. Teams follow the current session: live
22
23
  * snapshots and historic card summaries are only shown while their captain
23
24
  * session is the one currently open. */
24
- export declare function ActivityPanel({ sessionsList, openSession }: {
25
+ export type ActivityPanelProps = {
25
26
  readonly sessionsList: ObservableSnapshot<SessionListState>;
26
- readonly openSession: (id: SessionId) => void;
27
- }): import("react").JSX.Element | null;
27
+ readonly openMember: (parentId: SessionId, childId: SessionId) => void;
28
+ } & PropsLocale<'agentTeams'>;
29
+ export declare function ActivityPanel({ sessionsList, openMember, t }: ActivityPanelProps): 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 openSession: (id: SessionId) => void;
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, openSession, sessionId }: AgentTeamsCardProps): import("react").JSX.Element;
23
+ export declare function AgentTeamsCard({ node, openMember, sessionId, t }: AgentTeamsCardProps): import("react").JSX.Element;
@@ -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 no targets this is deliberately inert: installing the plugin must not
102
- * touch the state route. Live state is polled at the normal cadence; archive
103
- * state is fetched only as a one-time fallback for targets no longer live.
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 {};
@@ -1,6 +1,13 @@
1
1
  /** Browser plugin for the AgentTeams activity floater and conversation card. */
2
2
  import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
3
- /** Required services: conversation nodes, slots, and sessions navigation. */
3
+ import { type AgentTeamsLocaleKey } from './locales.ts';
4
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
5
+ interface LocaleNamespaceMap {
6
+ /** AgentTeams conversation card and activity monitor copy. */
7
+ agentTeams: AgentTeamsLocaleKey;
8
+ }
9
+ }
10
+ /** Required services: conversation nodes, slots, sessions navigation, and locale. */
4
11
  export declare const inject: string[];
5
12
  /**
6
13
  * Register the activity monitor in the shell's additive overlay and the
@@ -0,0 +1,169 @@
1
+ /** `agentTeams` namespace dictionaries for every plugin-owned Web surface. */
2
+ /** Dictionary namespace owned by the AgentTeams client plugin. */
3
+ export declare const AGENT_TEAMS_LOCALE_NAMESPACE = "agentTeams";
4
+ /** Simplified Chinese dictionary (the key-set source of truth). */
5
+ export declare const zh: {
6
+ 'card.memberCount': string;
7
+ 'action.openActivityPanel': string;
8
+ 'activity.panelButton': string;
9
+ 'activity.badgeAria': string;
10
+ 'activity.panelAria': string;
11
+ 'activity.title': string;
12
+ 'activity.float': string;
13
+ 'activity.dockRight': string;
14
+ 'activity.collapse': string;
15
+ 'activity.empty': string;
16
+ 'format.listSeparator': string;
17
+ 'task.status.pending': string;
18
+ 'task.status.claimed': string;
19
+ 'task.status.inProgress': string;
20
+ 'task.status.completed': string;
21
+ 'task.status.failed': string;
22
+ 'task.status.cancelled': string;
23
+ 'member.state.working': string;
24
+ 'member.state.failed': string;
25
+ 'member.state.waiting': string;
26
+ 'member.state.delivered': string;
27
+ 'member.state.left': string;
28
+ 'member.state.removed': string;
29
+ 'member.state.pending': string;
30
+ 'member.state.unassigned': string;
31
+ 'member.status.executing': string;
32
+ 'member.status.working': string;
33
+ 'member.status.waitingOn': string;
34
+ 'member.status.waitingPrerequisite': string;
35
+ 'member.status.waitingAssignment': string;
36
+ 'member.status.delivered': string;
37
+ 'member.status.idle': string;
38
+ 'member.status.unknown': string;
39
+ 'task.assignee.unclaimed': string;
40
+ 'task.summary.waitingBreakdown': string;
41
+ 'task.summary.allDelivered': string;
42
+ 'task.summary.blockedAndRunning': string;
43
+ 'task.summary.more': string;
44
+ 'task.summary.running': string;
45
+ 'task.summary.ready': string;
46
+ 'task.summary.blocked': string;
47
+ 'task.summary.waitingSchedule': string;
48
+ 'progress.aria': string;
49
+ 'progress.title': string;
50
+ 'progress.running': string;
51
+ 'progress.blocked': string;
52
+ 'progress.delivered': string;
53
+ 'dependency.aria': string;
54
+ 'dependency.parallel': string;
55
+ 'dependency.title': string;
56
+ 'dependency.hint.parallel': string;
57
+ 'dependency.hint.chain': string;
58
+ 'dependency.hint.pinned': string;
59
+ 'task.runningAria': string;
60
+ 'task.detail.completed': string;
61
+ 'task.detail.noPrerequisite': string;
62
+ 'task.detail.ready': string;
63
+ 'task.detail.waitingOn': string;
64
+ 'task.detail.noDownstream': string;
65
+ 'task.detail.unlocks': string;
66
+ 'team.ended': string;
67
+ 'team.stats.members': string;
68
+ 'team.stats.completed': string;
69
+ 'team.stats.messages': string;
70
+ 'delegation.aria': string;
71
+ 'captain.name': string;
72
+ 'captain.role': string;
73
+ 'captain.summary': string;
74
+ 'captain.state.working': string;
75
+ 'captain.state.collected': string;
76
+ 'captain.state.waiting': string;
77
+ 'members.toggle': string;
78
+ 'members.collapse': string;
79
+ 'members.expand': string;
80
+ 'members.empty': string;
81
+ 'assignment.label': string;
82
+ 'assignment.empty': string;
83
+ 'archive.label': string;
84
+ };
85
+ /** AgentTeams namespace key union. */
86
+ export type AgentTeamsLocaleKey = keyof typeof zh;
87
+ /** English dictionary, checked complete against the Chinese source key set. */
88
+ export declare const en: {
89
+ 'card.memberCount': string;
90
+ 'action.openActivityPanel': string;
91
+ 'activity.panelButton': string;
92
+ 'activity.badgeAria': string;
93
+ 'activity.panelAria': string;
94
+ 'activity.title': string;
95
+ 'activity.float': string;
96
+ 'activity.dockRight': string;
97
+ 'activity.collapse': string;
98
+ 'activity.empty': string;
99
+ 'format.listSeparator': string;
100
+ 'task.status.pending': string;
101
+ 'task.status.claimed': string;
102
+ 'task.status.inProgress': string;
103
+ 'task.status.completed': string;
104
+ 'task.status.failed': string;
105
+ 'task.status.cancelled': string;
106
+ 'member.state.working': string;
107
+ 'member.state.failed': string;
108
+ 'member.state.waiting': string;
109
+ 'member.state.delivered': string;
110
+ 'member.state.left': string;
111
+ 'member.state.removed': string;
112
+ 'member.state.pending': string;
113
+ 'member.state.unassigned': string;
114
+ 'member.status.executing': string;
115
+ 'member.status.working': string;
116
+ 'member.status.waitingOn': string;
117
+ 'member.status.waitingPrerequisite': string;
118
+ 'member.status.waitingAssignment': string;
119
+ 'member.status.delivered': string;
120
+ 'member.status.idle': string;
121
+ 'member.status.unknown': string;
122
+ 'task.assignee.unclaimed': string;
123
+ 'task.summary.waitingBreakdown': string;
124
+ 'task.summary.allDelivered': string;
125
+ 'task.summary.blockedAndRunning': string;
126
+ 'task.summary.more': string;
127
+ 'task.summary.running': string;
128
+ 'task.summary.ready': string;
129
+ 'task.summary.blocked': string;
130
+ 'task.summary.waitingSchedule': string;
131
+ 'progress.aria': string;
132
+ 'progress.title': string;
133
+ 'progress.running': string;
134
+ 'progress.blocked': string;
135
+ 'progress.delivered': string;
136
+ 'dependency.aria': string;
137
+ 'dependency.parallel': string;
138
+ 'dependency.title': string;
139
+ 'dependency.hint.parallel': string;
140
+ 'dependency.hint.chain': string;
141
+ 'dependency.hint.pinned': string;
142
+ 'task.runningAria': string;
143
+ 'task.detail.completed': string;
144
+ 'task.detail.noPrerequisite': string;
145
+ 'task.detail.ready': string;
146
+ 'task.detail.waitingOn': string;
147
+ 'task.detail.noDownstream': string;
148
+ 'task.detail.unlocks': string;
149
+ 'team.ended': string;
150
+ 'team.stats.members': string;
151
+ 'team.stats.completed': string;
152
+ 'team.stats.messages': string;
153
+ 'delegation.aria': string;
154
+ 'captain.name': string;
155
+ 'captain.role': string;
156
+ 'captain.summary': string;
157
+ 'captain.state.working': string;
158
+ 'captain.state.collected': string;
159
+ 'captain.state.waiting': string;
160
+ 'members.toggle': string;
161
+ 'members.collapse': string;
162
+ 'members.expand': string;
163
+ 'members.empty': string;
164
+ 'assignment.label': string;
165
+ 'assignment.empty': string;
166
+ 'archive.label': string;
167
+ };
168
+ /** Translation function consumed by pure view helpers. */
169
+ export type AgentTeamsTranslate = (key: AgentTeamsLocaleKey, params?: Record<string, unknown>) => string;
@@ -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'>;
@@ -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 guards all three public continuation boundaries:
127
- * retired rows disappear from `list_agents` (children and descendants), and a
128
- * direct `followup()` is rejected before it can cold-resume the member. Exact
129
- * ids keep unrelated subagents untouched; transcripts remain in persistence
130
- * for archived-team review.
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 each direct continuable child's real driver activity under the
135
- * captain's session. `listChildren().activity` is only session residency, so
136
- * live children are refined through the Agent registry exactly like Harness's
137
- * shipped `list_agents` tool.
138
- * @param ctx - the plugin context (injects `subagents`).
139
- * @param captainSessionId - the captain's session id.
140
- * @returns child id → activity, missing entries are unknown children.
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, captainSessionId: string): Promise<Map<string, 'running' | 'idle' | 'ready'>>;
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.10",
3
+ "version": "0.1.12",
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",
@@ -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>
@@ -0,0 +1,54 @@
1
+ # AgentTeams v0.1.12
2
+
3
+ This release adds host-native English and Simplified Chinese localization to the AgentTeams Web UI.
4
+
5
+ ## New & Improved
6
+
7
+ - **Official Harness locale integration**: the plugin registers its own `agentTeams` namespace with the Harness locale service instead of inspecting or rewriting host DOM.
8
+ - **Complete localized Web surfaces**: the conversation card and activity panel now translate task and member states, dynamic summaries, progress labels, dependency guidance, archive markers, controls, and accessibility text.
9
+ - **Live language switching**: changing the Harness language updates the active AgentTeams card and panel immediately without a page reload or a separate plugin setting.
10
+ - **Consistent fallback behavior**: English remains the fallback for missing locale entries, and dictionary keys and placeholders are verified as a release contract.
11
+
12
+ The `/agent-teams` slash-command description and input hint remain stable English metadata because the current Harness command protocol does not expose a locale namespace.
13
+
14
+ ## Verification
15
+
16
+ - Ran a real DeepSeek API workflow in an isolated `/tmp` Git project with one captain, two members, two dependent tasks, durable messaging, generated artifacts, and a successful project verification command.
17
+ - Verified English → Chinese → English live switching in the real Harness Web UI, including panel folding, dock/floating mode, task dependencies, and member transcript navigation.
18
+ - Passed type checking, production build, offline verification, lifecycle verification, the eight-member complex stress suite, and the Skill mirror check.
19
+
20
+ ## Installation
21
+
22
+ ```sh
23
+ dsh plugin --profile web add @nanmicoder/dsh-agent-teams
24
+ ```
25
+
26
+ <details>
27
+ <summary><b>中文版本 / Chinese Version</b></summary>
28
+
29
+ # AgentTeams v0.1.12
30
+
31
+ 本次更新为 AgentTeams Web UI 增加基于宿主官方能力的简体中文与英文多语言支持。
32
+
33
+ ## 新增与改进
34
+
35
+ - **接入 Harness 官方多语言服务**:插件注册独立的 `agentTeams` 命名空间,不读取或改写宿主 DOM。
36
+ - **完整覆盖 Web 界面**:对话卡片与活动面板中的任务/成员状态、动态摘要、进度、依赖提示、归档标识、操作按钮及无障碍文案均已适配。
37
+ - **语言实时切换**:修改 Harness 语言后,当前 AgentTeams 卡片和面板无需刷新即可同步更新,也不需要插件自己的语言设置。
38
+ - **稳定回退与发布校验**:缺失文案按官方机制回退到英文,发布验证会检查中英文字典的键和模板参数保持一致。
39
+
40
+ 由于当前 Harness 命令协议尚未提供 locale namespace,`/agent-teams` 在 slash 菜单中的描述和输入提示暂时保留稳定的英文元数据。
41
+
42
+ ## 验证
43
+
44
+ - 在隔离的 `/tmp` Git 项目中使用真实 DeepSeek API 完成队长、两名成员、两个依赖任务、持久消息、真实产物及项目校验的完整链路。
45
+ - 在真实 Harness Web UI 中验证英文 → 中文 → 英文实时切换,以及面板收起、停靠/浮动、任务依赖和成员记录跳转。
46
+ - 通过类型检查、生产构建、离线验证、生命周期验证、八成员复杂压力测试及 Skill 镜像检查。
47
+
48
+ ## 安装
49
+
50
+ ```sh
51
+ dsh plugin --profile web add @nanmicoder/dsh-agent-teams
52
+ ```
53
+
54
+ </details>