dsh-plugin-t-expert 0.3.88 → 0.3.89
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 +29 -56
- package/THIRD-PARTY-NOTICES +6 -31
- package/lib/bootstrap.js +11 -33
- package/lib/catalog.js +1 -1
- package/lib/client.js +20707 -21863
- package/lib/i18n.js +0 -4
- package/lib/index.js +171 -858
- package/lib/remote-schemas.js +5 -104
- package/lib/remote.js +7 -174
- package/lib/schedule.js +93 -23
- package/lib/skill.js +1 -1
- package/package.json +3 -10
- package/vendor/third-party-licenses/README.md +0 -1
- package/data/t-team.config.json +0 -1558
- package/data/team-profiles.py +0 -367
- package/data/teams.json +0 -791
- package/data/teams.resolved.json +0 -1594
- package/lib/command.js +0 -251
- package/lib/plan-check.js +0 -166
- package/lib/squads.js +0 -446
- package/lib/teams/assignee-contract.js +0 -47
- package/lib/teams/capabilities.js +0 -106
- package/lib/teams/command.js +0 -147
- package/lib/teams/event-types.js +0 -12
- package/lib/teams/events.js +0 -60
- package/lib/teams/harness-compat.js +0 -561
- package/lib/teams/index.js +0 -463
- package/lib/teams/members.js +0 -619
- package/lib/teams/profiles.js +0 -572
- package/lib/teams/quality-gates.js +0 -905
- package/lib/teams/scheduler.js +0 -642
- package/lib/teams/snapshot.js +0 -184
- package/lib/teams/state.js +0 -946
- package/lib/teams/tool-names.js +0 -11
- package/lib/teams/tools.js +0 -2346
- package/lib/teams/types.js +0 -22
- package/lib/teams/web-routes.js +0 -86
- package/vendor/dsh-agent-teams/LICENSE +0 -21
package/lib/teams/snapshot.js
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Team activity snapshot assembly for the activity panel.
|
|
3
|
-
*
|
|
4
|
-
* Server-side assembly mirrors the Claude Code desktop teamWatcher: read the
|
|
5
|
-
* durable team files (the truth source) and enrich with live subagent
|
|
6
|
-
* activity, so the panel always reflects the on-disk state even when a model
|
|
7
|
-
* skipped a tool "ritual" (e.g. not calling update_task on completion).
|
|
8
|
-
* @module t-team/snapshot
|
|
9
|
-
*/
|
|
10
|
-
import { readdir } from 'node:fs/promises';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
|
-
import { memberActivity } from "./members.js";
|
|
13
|
-
import { CAPTAIN_KEY, listArchivedTeamIds, readArchivedTeam, readUnreadMailbox, readTeam, taskDepthsById, taskVisualState, } from "./state.js";
|
|
14
|
-
/** The current task of a member: its first unfinished owned task. */
|
|
15
|
-
function currentTaskOf(memberName, tasks) {
|
|
16
|
-
for (const task of tasks) {
|
|
17
|
-
if (task.status === 'in_progress' && task.assignee === memberName)
|
|
18
|
-
return task.id;
|
|
19
|
-
}
|
|
20
|
-
return '';
|
|
21
|
-
}
|
|
22
|
-
/** Compact `provider/model` route for the activity panel, or just the model. */
|
|
23
|
-
export function memberModelRoute(member) {
|
|
24
|
-
if (member === undefined)
|
|
25
|
-
return '';
|
|
26
|
-
const provider = member.provider?.trim() ?? '';
|
|
27
|
-
const model = member.model?.trim() ?? '';
|
|
28
|
-
if (provider !== '' && model !== '')
|
|
29
|
-
return `${provider}/${model}`;
|
|
30
|
-
return model;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Assemble one team snapshot from its durable files plus live activity.
|
|
34
|
-
* @param ctx - the plugin context (injects `subagents`, used for activity).
|
|
35
|
-
* @param stateRoot - resolved absolute state root of the owning workspace.
|
|
36
|
-
* @param workspace - display name of the owning workspace.
|
|
37
|
-
* @param state - the durable team record.
|
|
38
|
-
* @returns the panel snapshot.
|
|
39
|
-
*/
|
|
40
|
-
export async function assembleTeamSnapshot(ctx, stateRoot, workspace, state, options = {}) {
|
|
41
|
-
const tasks = state.tasks;
|
|
42
|
-
const depths = taskDepthsById(tasks);
|
|
43
|
-
const roster = options.includeRemoved === true
|
|
44
|
-
? state.members
|
|
45
|
-
: state.members.filter((member) => member.status !== 'removed');
|
|
46
|
-
const activity = options.historic === true
|
|
47
|
-
? new Map()
|
|
48
|
-
: memberActivity(ctx, roster.map((member) => member.id));
|
|
49
|
-
const unreadByMember = new Map();
|
|
50
|
-
for (const member of roster) {
|
|
51
|
-
try {
|
|
52
|
-
unreadByMember.set(member.name, (await readUnreadMailbox(stateRoot, state.id, member.name)).length);
|
|
53
|
-
}
|
|
54
|
-
catch (error) {
|
|
55
|
-
ctx.logger.warn(`t-team: mailbox read failed for ${member.name}: ${String(error)}`);
|
|
56
|
-
unreadByMember.set(member.name, 0);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const members = roster.map((member) => {
|
|
60
|
-
const owned = tasks.filter((task) => task.assignee === member.name);
|
|
61
|
-
const done = owned.filter((task) => task.status === 'completed').length;
|
|
62
|
-
return {
|
|
63
|
-
id: member.id,
|
|
64
|
-
name: member.name,
|
|
65
|
-
role: member.role ?? '',
|
|
66
|
-
provider: member.provider?.trim() ?? '',
|
|
67
|
-
model: member.model?.trim() ?? '',
|
|
68
|
-
reasoningEffort: member.reasoningEffort?.trim() ?? '',
|
|
69
|
-
executionPrompt: member.executionPrompt ?? '',
|
|
70
|
-
status: member.status,
|
|
71
|
-
activity: options.historic === true
|
|
72
|
-
? 'idle'
|
|
73
|
-
: member.id !== ''
|
|
74
|
-
? (activity.get(member.id) === 'running'
|
|
75
|
-
? 'working'
|
|
76
|
-
: activity.get(member.id) === 'idle' || activity.get(member.id) === 'ready'
|
|
77
|
-
? 'idle'
|
|
78
|
-
: 'unknown')
|
|
79
|
-
: state.phase === 'staged' ? 'idle' : 'unknown',
|
|
80
|
-
progress: owned.length === 0 ? 0 : Math.round((done / owned.length) * 100),
|
|
81
|
-
done,
|
|
82
|
-
total: owned.length,
|
|
83
|
-
currentTask: currentTaskOf(member.name, tasks),
|
|
84
|
-
unread: unreadByMember.get(member.name) ?? 0,
|
|
85
|
-
};
|
|
86
|
-
});
|
|
87
|
-
const captainInbox = await readUnreadMailbox(stateRoot, state.id, CAPTAIN_KEY);
|
|
88
|
-
return {
|
|
89
|
-
workspace,
|
|
90
|
-
teamId: state.id,
|
|
91
|
-
name: state.name,
|
|
92
|
-
...state.description !== undefined ? { description: state.description } : {},
|
|
93
|
-
captainSessionId: state.captainSessionId,
|
|
94
|
-
phase: state.phase ?? 'running',
|
|
95
|
-
...state.phase === 'staged'
|
|
96
|
-
? { planReviewState: state.planReviewState ?? 'awaiting_review' }
|
|
97
|
-
: {},
|
|
98
|
-
...state.halted === true ? { halted: true } : {},
|
|
99
|
-
members,
|
|
100
|
-
tasks: tasks.map((task) => ({
|
|
101
|
-
id: task.id,
|
|
102
|
-
subject: task.subject,
|
|
103
|
-
description: task.description ?? '',
|
|
104
|
-
status: task.status,
|
|
105
|
-
state: taskVisualState(task.status, task.dependencies, tasks),
|
|
106
|
-
assignee: task.assignee ?? '',
|
|
107
|
-
model: memberModelRoute(roster.find((member) => member.name === task.assignee)),
|
|
108
|
-
dependencies: task.dependencies,
|
|
109
|
-
depth: depths.get(task.id) ?? 0,
|
|
110
|
-
...task.kind === undefined ? {} : { kind: task.kind },
|
|
111
|
-
...task.round === undefined ? {} : { round: task.round },
|
|
112
|
-
...task.verdict === undefined ? {} : { verdict: task.verdict },
|
|
113
|
-
})),
|
|
114
|
-
messageCount: captainInbox.length
|
|
115
|
-
+ members.reduce((count, member) => count + member.unread, 0),
|
|
116
|
-
captainInbox: captainInbox.slice(-5).map((message) => ({
|
|
117
|
-
from: message.from,
|
|
118
|
-
content: message.content,
|
|
119
|
-
})),
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Collect every team under the given workspace state roots.
|
|
124
|
-
* @param ctx - the plugin context.
|
|
125
|
-
* @param roots - `{ workspace, stateRoot }` pairs (resolved absolute roots).
|
|
126
|
-
* @returns the snapshots in stable order (workspace, then team id).
|
|
127
|
-
*/
|
|
128
|
-
export async function collectTeamsActivity(ctx, roots) {
|
|
129
|
-
const snapshots = [];
|
|
130
|
-
for (const root of roots) {
|
|
131
|
-
let entries;
|
|
132
|
-
try {
|
|
133
|
-
entries = await readdir(root.stateRoot, { withFileTypes: true });
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
throw error;
|
|
140
|
-
}
|
|
141
|
-
for (const entry of entries) {
|
|
142
|
-
if (!entry.isDirectory())
|
|
143
|
-
continue;
|
|
144
|
-
try {
|
|
145
|
-
const state = await readTeam(root.stateRoot, entry.name);
|
|
146
|
-
if (state === undefined)
|
|
147
|
-
continue;
|
|
148
|
-
snapshots.push(await assembleTeamSnapshot(ctx, root.stateRoot, root.workspace, state));
|
|
149
|
-
}
|
|
150
|
-
catch (error) {
|
|
151
|
-
// 必须带上根因:裸 `catch {` 只留一句「unreadable」,解析失败、权限、服务缺失、
|
|
152
|
-
// 并发读全都会变成同一句无法诊断的告警(2026-09-13 在真实宿主日志里就撞上一条
|
|
153
|
-
// 谁也没法解释的 "skipped unreadable team state",根因正是被这里吞掉的)。
|
|
154
|
-
ctx.logger.warn(`t-team: skipped unreadable team state "${entry.name}" in workspace "${root.workspace}": ${String(error)}`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
return snapshots;
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Collect every archived team under the given workspace state roots (the
|
|
162
|
-
* `archive/` subdirectory of each state root). Used by the historic panel
|
|
163
|
-
* path to restore full team detail after deletion.
|
|
164
|
-
* @param ctx - the plugin context.
|
|
165
|
-
* @param roots - `{ workspace, stateRoot }` pairs.
|
|
166
|
-
* @returns the archived snapshots in stable order.
|
|
167
|
-
*/
|
|
168
|
-
export async function collectArchivedTeamsActivity(ctx, roots) {
|
|
169
|
-
const snapshots = [];
|
|
170
|
-
for (const root of roots) {
|
|
171
|
-
for (const teamId of await listArchivedTeamIds(root.stateRoot)) {
|
|
172
|
-
try {
|
|
173
|
-
const state = await readArchivedTeam(root.stateRoot, teamId);
|
|
174
|
-
if (state === undefined)
|
|
175
|
-
continue;
|
|
176
|
-
snapshots.push(await assembleTeamSnapshot(ctx, join(root.stateRoot, 'archive'), root.workspace, state, { includeRemoved: true, historic: true }));
|
|
177
|
-
}
|
|
178
|
-
catch (error) {
|
|
179
|
-
ctx.logger.warn(`t-team: skipped unreadable archived team "${teamId}" in workspace "${root.workspace}": ${String(error)}`);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return snapshots;
|
|
184
|
-
}
|