@stofone/dsh-agent-roster 0.5.1 → 0.6.1

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/service.js CHANGED
@@ -13,6 +13,7 @@
13
13
  import nodePath from "node:path";
14
14
 
15
15
  import { globalRosterRoot } from "./home.js";
16
+ import { readDeployedCaptains, verifyCaptain } from "./captain.js";
16
17
  import { collectLibrary, listWorkspaces } from "./library.js";
17
18
  import { CACHE_DIR_NAME, fetchCollection, loadRegistryIndex } from "./remote.js";
18
19
  import { rosterDocumentText } from "./serialize.js";
@@ -74,6 +75,7 @@ export function buildPanelSnapshot(ctx, config, meta, options = {}) {
74
75
 
75
76
  const hints = buildHints({ library, roots, rosters, teams, config });
76
77
  const deployments = countDeployments(rosters, teams.teams);
78
+ const captain = buildCaptainSection(rosters, options);
77
79
 
78
80
  return {
79
81
  plugin: meta.name,
@@ -85,10 +87,13 @@ export function buildPanelSnapshot(ctx, config, meta, options = {}) {
85
87
  defaultRoot: globalRosterRoot(),
86
88
  knownToolPolicies: Array.isArray(config.knownToolPolicies) ? config.knownToolPolicies : [],
87
89
  stateDirSpec: config.agentTeamsStateDir,
90
+ region: config.region,
91
+ registryMirror: config.registryMirror ?? "",
88
92
  },
89
93
  workspaces: library.workspaces,
90
94
  teams,
91
95
  deployments,
96
+ captain,
92
97
  hints,
93
98
  summary: {
94
99
  rosters: rosters.length,
@@ -241,6 +246,53 @@ export function countDeployments(rosters, teams) {
241
246
  return result;
242
247
  }
243
248
 
249
+ /**
250
+ * 队长段:部署里的实际值 + 每份档案的核对结果。
251
+ *
252
+ * 部署值读不到不算错(核对待核字段会给 `unknown`),但一定如实标出来——不假装通过。
253
+ *
254
+ * @param {object[]} rosters
255
+ * @param {{ readDeployed?: () => object }} [options] 测试注入
256
+ * @returns {{ deployed: object, reports: object[] }}
257
+ */
258
+ export function buildCaptainSection(rosters, options = {}) {
259
+ const readDeployed = options.readDeployed ?? (() => readDeployedCaptains());
260
+ let deployed;
261
+ try {
262
+ deployed = readDeployed();
263
+ } catch (error) {
264
+ deployed = {
265
+ home: "",
266
+ displayed: "",
267
+ profiles: [],
268
+ diagnostics: [{ severity: "warn", code: "captain-unreadable", reason: String(error?.message ?? error) }],
269
+ };
270
+ }
271
+
272
+ const reports = rosters
273
+ .filter((roster) => roster.captain !== undefined && roster.captain !== null)
274
+ .map((roster) => {
275
+ const verified = verifyCaptain(roster.captain, deployed);
276
+ return { rosterId: roster.id, rootDir: roster.rootDir ?? "", checks: verified.checks, ok: verified.ok };
277
+ });
278
+
279
+ return {
280
+ deployed: {
281
+ home: deployed.home ?? "",
282
+ displayed: deployed.displayed ?? "",
283
+ profiles: (deployed.profiles ?? []).map((profile) => ({
284
+ profile: profile.profile,
285
+ provider: profile.provider,
286
+ model: profile.model,
287
+ reasoningEffort: profile.reasoningEffort,
288
+ personas: (profile.personas ?? []).length,
289
+ })),
290
+ diagnostics: deployed.diagnostics ?? [],
291
+ },
292
+ reports,
293
+ };
294
+ }
295
+
244
296
  /**
245
297
  * 配置与环境体检:只产出 code + params,客户端负责措辞。
246
298
  *
package/lib/tools.js CHANGED
@@ -1,5 +1,6 @@
1
1
  /**
2
- * 四个模型可见工具:列档案、看成员、生成桥接调用、核对运行时。
2
+ * 五个模型可见工具:列档案、看成员、生成桥接调用、核对运行时、读公共档案源。
3
+ * (roster_list / roster_show / roster_create / roster_verify / roster_index)
3
4
  *
4
5
  * 只读优先:`roster_list` / `roster_show` / `roster_verify` 只读文件系统;
5
6
  * `roster_create` 也不写任何东西——它输出的是**参数**,真正的成员创建仍由队长调用
@@ -14,7 +15,8 @@ import { LIMITS } from "./format.js";
14
15
  import { resolveDirSpec } from "./home.js";
15
16
  import { lossless } from "./json.js";
16
17
  import { scanRosterLibrary, findRoster } from "./registry.js";
17
- import { renderBridgePlan, renderRosterDetail, renderRosterList, renderVerifyReport } from "./render.js";
18
+ import { renderBridgePlan, renderCaptainVerification, renderRosterDetail, renderRosterList, renderVerifyReport } from "./render.js";
19
+ import { readDeployedCaptains, verifyCaptain } from "./captain.js";
18
20
  import { readTeamStates, resolveStateDir } from "./teams-state.js";
19
21
  import { filterChecks, verifyBindings } from "./verify.js";
20
22
 
@@ -349,6 +351,11 @@ export function registerRosterTools(ctx, config, meta) {
349
351
  // 技能是声明层:只有宿主真的能列出技能目录时才核对,否则如实记成"无法核对"。
350
352
  const knownSkills = await readKnownSkills(ctx, workspace);
351
353
  let report = verifyBindings(rosters, state.teams, { knownSkills });
354
+ // 队长不是成员行:只能拿实际的部署配置去比档案里的声明,读不到就记成“无法核对”。
355
+ const deployedCaptains = readDeployedCaptains();
356
+ const captainReports = rosters
357
+ .filter((roster) => roster.captain !== undefined && roster.captain !== null)
358
+ .map((roster) => ({ roster, verified: verifyCaptain(roster.captain, deployedCaptains) }));
352
359
  if (Array.isArray(args.members) && args.members.length > 0) {
353
360
  report = filterChecks(report, args.members);
354
361
  }
@@ -364,8 +371,16 @@ export function registerRosterTools(ctx, config, meta) {
364
371
  missing: report.summary.missing,
365
372
  unmanaged: report.summary.unmanaged,
366
373
  skills: `${report.summary.skillsMissing}/${report.summary.skillsDeclared}`,
374
+ captain: captainReports.length,
367
375
  }),
368
376
  renderVerifyReport(report, { rosterIds: refRosterIds }),
377
+ ...(captainReports.length === 0
378
+ ? []
379
+ : [
380
+ captainReports
381
+ .map(({ verified }) => renderCaptainVerification(verified, { displayed: deployedCaptains.displayed }))
382
+ .join("\n\n"),
383
+ ]),
369
384
  ].join("\n\n");
370
385
  return lossless({
371
386
  ok,
@@ -382,6 +397,11 @@ export function registerRosterTools(ctx, config, meta) {
382
397
  fields: check.binding === null ? [] : check.binding.fields,
383
398
  })),
384
399
  unmanaged: report.unmanaged,
400
+ captain: captainReports.map(({ roster, verified }) => ({
401
+ rosterId: roster.id,
402
+ ok: verified.ok,
403
+ checks: verified.checks,
404
+ })),
385
405
  skills: report.skills,
386
406
  diagnostics: [...scan.diagnostics, ...state.diagnostics],
387
407
  text,
package/locale/en.json CHANGED
@@ -20,7 +20,17 @@
20
20
  "policiesNone": "Not configured — policy ids in rosters stay declarations only.",
21
21
  "policiesCount": "{count} declared",
22
22
  "version": "Version",
23
- "openPanel": "Open panel"
23
+ "openPanel": "Open panel",
24
+ "region": "Download region",
25
+ "regionAuto": "Follow default",
26
+ "regionGlobal": "Global",
27
+ "regionChina": "China mirror",
28
+ "save": "Save",
29
+ "saved": "Saved",
30
+ "saveFailed": "Could not save — the settings form is unavailable.",
31
+ "mirror": "Custom registry mirror",
32
+ "mirrorPlaceholder": "https://registry.npmmirror.com",
33
+ "mirrorHint": "When set, this replaces the region preset for index sources published as npm packages. Company mirrors with a sub-path (e.g. /repository/npm) work too; leave empty to use the region preset."
24
34
  },
25
35
  "panel": {
26
36
  "title": "Agent Roster",
@@ -46,7 +56,11 @@
46
56
  "bannerMany": "{count} things need attention",
47
57
  "bannerCta": "Open health",
48
58
  "workspaceFallback": "No workspace is registered yet; reading the process directory instead.",
49
- "tabsSources": "Sources"
59
+ "tabsSources": "Sources",
60
+ "tagPool": "Tags",
61
+ "tagPoolEmpty": "No tags yet — add `tags:` to an archive.",
62
+ "tagClear": "Clear tags",
63
+ "settings": "Settings"
50
64
  },
51
65
  "roster": {
52
66
  "members": "{count} members",
@@ -240,6 +254,40 @@
240
254
  "hide": "Hide rosters",
241
255
  "loading": "Loading rosters…",
242
256
  "repo": "Repository",
243
- "conflictHint": "Local versions differ; nothing was overwritten."
257
+ "conflictHint": "Local versions differ; nothing was overwritten.",
258
+ "refresh": "Refresh sources",
259
+ "refreshHint": "No index has been read yet — refresh to fetch the public index."
260
+ },
261
+ "captain": {
262
+ "title": "Captain",
263
+ "hint": "The captain is the session that creates the team — it has no member row. Its model comes from the deployment (agent-default-model) and its persona from the agent preset, so a roster can only declare them and compare.",
264
+ "declared": "Declared",
265
+ "effortDefault": "default",
266
+ "noPersona": "no persona prefix declared",
267
+ "hasPersona": "persona prefix declared",
268
+ "noChecks": "No deployment config read yet — nothing to compare.",
269
+ "applyTo": "Apply to a session",
270
+ "modeExisting": "Existing session",
271
+ "modeNew": "New session",
272
+ "noSessions": "No sessions available",
273
+ "cwdPlaceholder": "Working directory (optional)",
274
+ "apply": "Apply & create team",
275
+ "applying": "Applying…",
276
+ "applyFailed": "Apply failed",
277
+ "applyFailedCode": "Failed: {code}",
278
+ "applied": "Applied — the team prompt is queued in that session",
279
+ "appliedTo": "Queued in {session}",
280
+ "check": {
281
+ "provider": "Provider",
282
+ "model": "Model",
283
+ "reasoningEffort": "Reasoning effort",
284
+ "personaPrefix": "Persona prefix"
285
+ },
286
+ "status": {
287
+ "match": "matches deployment ({declared})",
288
+ "differ": "declared {declared}, deployment has {actual}",
289
+ "undeclared": "not declared, runtime uses {actual}",
290
+ "unknown": "deployment unreadable"
291
+ }
244
292
  }
245
293
  }
package/locale/zh.json CHANGED
@@ -20,7 +20,17 @@
20
20
  "policiesNone": "未配置——档案里写的策略 id 只是声明,运行时不生效。",
21
21
  "policiesCount": "已声明 {count} 个",
22
22
  "version": "版本",
23
- "openPanel": "打开面板"
23
+ "openPanel": "打开面板",
24
+ "region": "下载区",
25
+ "regionAuto": "跟随默认",
26
+ "regionGlobal": "海外",
27
+ "regionChina": "国内镜像",
28
+ "save": "保存",
29
+ "saved": "已保存",
30
+ "saveFailed": "保存失败——设置表单当前不可用。",
31
+ "mirror": "自定义镜像地址",
32
+ "mirrorPlaceholder": "https://registry.npmmirror.com",
33
+ "mirrorHint": "填了就用它代替下载区:按 npm 包形式发布的公共档案源从这里取。支持带子路径的公司镜像(如 /repository/npm);留空用下载区的预置。"
24
34
  },
25
35
  "panel": {
26
36
  "title": "Agent 档案",
@@ -46,7 +56,11 @@
46
56
  "bannerMany": "有 {count} 项待处理",
47
57
  "bannerCta": "查看体检",
48
58
  "workspaceFallback": "还没有注册工作区,暂时按进程所在目录读取。",
49
- "tabsSources": "档案源"
59
+ "tabsSources": "档案源",
60
+ "tagPool": "标签",
61
+ "tagPoolEmpty": "还没有标签——给档案加 `tags:`。",
62
+ "tagClear": "清除标签",
63
+ "settings": "设置"
50
64
  },
51
65
  "roster": {
52
66
  "members": "{count} 名成员",
@@ -240,6 +254,40 @@
240
254
  "hide": "收起",
241
255
  "loading": "正在读取档案…",
242
256
  "repo": "仓库",
243
- "conflictHint": "本地版本与远端不同,未覆盖。"
257
+ "conflictHint": "本地版本与远端不同,未覆盖。",
258
+ "refresh": "刷新档案源",
259
+ "refreshHint": "还没有读到任何索引——点刷新去拉公共索引。"
260
+ },
261
+ "captain": {
262
+ "title": "队长",
263
+ "hint": "队长就是创建团队的那个会话,没有成员行。它的模型来自部署(agent-default-model),人格来自 agent preset,所以档案只能声明并核对。",
264
+ "declared": "声明",
265
+ "effortDefault": "默认",
266
+ "noPersona": "未声明人格前缀",
267
+ "hasPersona": "已声明人格前缀",
268
+ "noChecks": "还没读到部署配置,没有可比对的项。",
269
+ "applyTo": "应用到会话",
270
+ "modeExisting": "已有会话",
271
+ "modeNew": "新建会话",
272
+ "noSessions": "没有可用会话",
273
+ "cwdPlaceholder": "工作目录(可留空)",
274
+ "apply": "应用并创建团队",
275
+ "applying": "应用中…",
276
+ "applyFailed": "应用失败",
277
+ "applyFailedCode": "失败:{code}",
278
+ "applied": "已应用,建团队提示词已排入该会话",
279
+ "appliedTo": "已排入 {session}",
280
+ "check": {
281
+ "provider": "Provider",
282
+ "model": "模型",
283
+ "reasoningEffort": "推理强度",
284
+ "personaPrefix": "人格前缀"
285
+ },
286
+ "status": {
287
+ "match": "与部署一致({declared})",
288
+ "differ": "声明 {declared},部署是 {actual}",
289
+ "undeclared": "未声明,运行时用 {actual}",
290
+ "unknown": "读不到部署配置"
291
+ }
244
292
  }
245
293
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stofone/dsh-agent-roster",
3
- "version": "0.5.1",
3
+ "version": "0.6.1",
4
4
  "description": "多 Agent 团队的静态成员档案定义与校验层:档案库在面板里看得见、改得动,团队成员的人设、模型与工具边界固化成可校验、可版本化的文件,并在 dsh-agent-teams 创建成员时把档案桥接给运行时。",
5
5
  "type": "module",
6
6
  "main": "index.js",