@chenkai114/dsh-team-admin 0.1.4 → 0.1.5
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/package.json +1 -1
- package/src/api.mjs +16 -0
- package/src/client.js +74 -1
- package/src/index.js +1 -1
package/package.json
CHANGED
package/src/api.mjs
CHANGED
|
@@ -92,6 +92,22 @@ export function createApi({ ctx, getStore, version, logSystem, services }) {
|
|
|
92
92
|
return
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
if (path === '/api/team-admin/dismissed') {
|
|
96
|
+
if (method !== 'GET') { sendJson(res, 405, { error: '请求方法不支持' }); return }
|
|
97
|
+
const store = await getStore()
|
|
98
|
+
const state = await store.readAll()
|
|
99
|
+
const buckets = state !== null && typeof state === 'object' && typeof state.dismissed === 'object' && state.dismissed !== null
|
|
100
|
+
? state.dismissed
|
|
101
|
+
: {}
|
|
102
|
+
const ids = []
|
|
103
|
+
for (const bucket of Object.values(buckets)) {
|
|
104
|
+
if (bucket === null || typeof bucket !== 'object') continue
|
|
105
|
+
for (const memberId of Object.keys(bucket)) ids.push(memberId)
|
|
106
|
+
}
|
|
107
|
+
sendJson(res, 200, { ids })
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
95
111
|
if (path === '/api/team-admin/team') {
|
|
96
112
|
if (method !== 'GET') { sendJson(res, 405, { error: '请求方法不支持' }); return }
|
|
97
113
|
const sessionId = queryValue(url, 'sessionId')
|
package/src/client.js
CHANGED
|
@@ -170,11 +170,77 @@
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
const DISMISS_URL = API_BASE + '/dismiss'
|
|
173
|
+
const DISMISSED_URL = API_BASE + '/dismissed'
|
|
174
|
+
const LIST_FILTER_FLAG = '__dshTeamAdminSessionListFilter__'
|
|
173
175
|
|
|
174
176
|
function dismissPayload(sessionId, name) {
|
|
175
177
|
return { sessionId: sessionId, name: name, deleteSession: true }
|
|
176
178
|
}
|
|
177
179
|
|
|
180
|
+
// —— 宿主会话列表过滤:把已删除成员从 subagentCatalog 投影里摘掉 ——
|
|
181
|
+
// 宿主 catalog 与 roster 都是 append-only,删会话不会撤销 catalog 事件;
|
|
182
|
+
// 这里在本插件内拦截 /api/session/list 的响应,按墓碑把失效条目过滤掉,
|
|
183
|
+
// 不修改宿主源码,也不需要重编译。
|
|
184
|
+
let dismissedIds = new Set()
|
|
185
|
+
let dismissedReady = null
|
|
186
|
+
|
|
187
|
+
function stripDismissedCatalogs(payload, dismissed) {
|
|
188
|
+
if (payload === null || typeof payload !== 'object' || dismissed === undefined || dismissed.size === 0) return payload
|
|
189
|
+
const visit = (node, depth) => {
|
|
190
|
+
if (node === null || typeof node !== 'object' || depth > 6) return
|
|
191
|
+
if (Array.isArray(node.subagentCatalog)) {
|
|
192
|
+
node.subagentCatalog = node.subagentCatalog.filter((entry) => !(entry !== null && typeof entry === 'object' && typeof entry.id === 'string' && dismissed.has(entry.id)))
|
|
193
|
+
}
|
|
194
|
+
for (const key of Object.keys(node)) {
|
|
195
|
+
if (key === 'subagentCatalog') continue
|
|
196
|
+
visit(node[key], depth + 1)
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
visit(payload, 0)
|
|
200
|
+
return payload
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async function refreshDismissedIds() {
|
|
204
|
+
try {
|
|
205
|
+
const response = await fetch(DISMISSED_URL, { headers: { accept: 'application/json' } })
|
|
206
|
+
if (response.ok !== true) return dismissedIds
|
|
207
|
+
const payload = await response.json()
|
|
208
|
+
const ids = isRecord(payload) && Array.isArray(payload.ids) ? payload.ids : []
|
|
209
|
+
dismissedIds = new Set(ids.filter((id) => typeof id === 'string' && id !== ''))
|
|
210
|
+
} catch (error) {
|
|
211
|
+
// 墓碑拿不到就放行原始列表:过滤是增强,不是前置条件。
|
|
212
|
+
}
|
|
213
|
+
return dismissedIds
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function installSessionListFilter(win) {
|
|
217
|
+
const scope = win !== undefined ? win : (typeof window === 'undefined' ? null : window)
|
|
218
|
+
if (scope === null || scope === undefined) return false
|
|
219
|
+
if (scope[LIST_FILTER_FLAG] === true) {
|
|
220
|
+
dismissedReady = refreshDismissedIds()
|
|
221
|
+
return false
|
|
222
|
+
}
|
|
223
|
+
const original = scope.fetch
|
|
224
|
+
if (typeof original !== 'function') return false
|
|
225
|
+
scope[LIST_FILTER_FLAG] = true
|
|
226
|
+
dismissedReady = refreshDismissedIds()
|
|
227
|
+
scope.fetch = async function teamAdminAwareFetch(input, init) {
|
|
228
|
+
const url = typeof input === 'string' ? input : (isRecord(input) && typeof input.url === 'string' ? input.url : '')
|
|
229
|
+
if (url.indexOf('/api/session/list') < 0) return await original(input, init)
|
|
230
|
+
if (dismissedReady !== null) await dismissedReady
|
|
231
|
+
const response = await original(input, init)
|
|
232
|
+
if (dismissedIds.size === 0 || response.ok !== true) return response
|
|
233
|
+
try {
|
|
234
|
+
const body = await response.clone().json()
|
|
235
|
+
stripDismissedCatalogs(body, dismissedIds)
|
|
236
|
+
return new Response(JSON.stringify(body), { status: response.status, statusText: response.statusText, headers: response.headers })
|
|
237
|
+
} catch (error) {
|
|
238
|
+
return response
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return true
|
|
242
|
+
}
|
|
243
|
+
|
|
178
244
|
// —— 响应校验:缺字段回退默认值,形态不对返回可展示的错误 ——
|
|
179
245
|
function normalizeSessionRow(raw) {
|
|
180
246
|
const row = isRecord(raw) ? raw : {}
|
|
@@ -788,6 +854,7 @@
|
|
|
788
854
|
return
|
|
789
855
|
}
|
|
790
856
|
state.confirm = null
|
|
857
|
+
dismissedReady = refreshDismissedIds()
|
|
791
858
|
state.notice = { text: dismissResultText(readDismissResult(outcome.data, target)) }
|
|
792
859
|
render()
|
|
793
860
|
await loadTeam(state.selectedId)
|
|
@@ -847,6 +914,7 @@
|
|
|
847
914
|
throw new Error('mount(container) 需要一个可挂载的 DOM 元素')
|
|
848
915
|
}
|
|
849
916
|
ensureStyle(typeof document === 'undefined' ? null : document)
|
|
917
|
+
installSessionListFilter()
|
|
850
918
|
const controller = createPanelController()
|
|
851
919
|
container.appendChild(controller.root)
|
|
852
920
|
controller.start()
|
|
@@ -922,6 +990,7 @@
|
|
|
922
990
|
return {
|
|
923
991
|
inject: ['slots'],
|
|
924
992
|
apply(ctx) {
|
|
993
|
+
installSessionListFilter()
|
|
925
994
|
const slots = ctx !== null && ctx !== undefined && ctx.slots !== undefined ? ctx.slots : null
|
|
926
995
|
if (slots === null || typeof slots.inject !== 'function' || typeof slots.register !== 'function') {
|
|
927
996
|
console.warn('[team-admin] 宿主未提供 slots 服务,配置卡片未注册')
|
|
@@ -979,6 +1048,10 @@
|
|
|
979
1048
|
PANEL_LABEL: PANEL_LABEL,
|
|
980
1049
|
PANEL_ORDER: PANEL_ORDER,
|
|
981
1050
|
API_BASE: API_BASE,
|
|
1051
|
+
DISMISSED_URL: DISMISSED_URL,
|
|
1052
|
+
stripDismissedCatalogs: stripDismissedCatalogs,
|
|
1053
|
+
installSessionListFilter: installSessionListFilter,
|
|
1054
|
+
refreshDismissedIds: refreshDismissedIds,
|
|
982
1055
|
DEBOUNCE_MS: DEBOUNCE_MS,
|
|
983
1056
|
CARD_TITLE: CARD_TITLE,
|
|
984
1057
|
CARD_SUMMARY: CARD_SUMMARY,
|
|
@@ -1011,4 +1084,4 @@
|
|
|
1011
1084
|
&& typeof window.__ModuleLoader__.load === 'function') {
|
|
1012
1085
|
window.__ModuleLoader__.load({ id: PKG_ID, factory: factory })
|
|
1013
1086
|
}
|
|
1014
|
-
})()
|
|
1087
|
+
})()
|
package/src/index.js
CHANGED
|
@@ -17,7 +17,7 @@ const DATA_DIR_ENV = 'DSH_TEAM_ADMIN_DATA_DIR'
|
|
|
17
17
|
/** 路由前缀:webServer 只支持 exact/prefix 注册。 */
|
|
18
18
|
const ROUTE_PREFIX = '/api/team-admin'
|
|
19
19
|
/** 与 package.json 版本保持一致(发布前由测试校验)。 */
|
|
20
|
-
const PLUGIN_VERSION = '0.1.
|
|
20
|
+
const PLUGIN_VERSION = '0.1.5'
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* 解析插件数据目录。
|