@stofone/dsh-agent-roster 0.12.0 → 0.13.0
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/CHANGELOG.md +35 -0
- package/README.md +18 -10
- package/README.zh.md +16 -9
- package/client.js +334 -165
- package/examples/dist/core-review-1.0.0.json +9 -0
- package/examples/dist/research-0.1.0.json +7 -0
- package/examples-orchestration/dist/core-review-1.0.0.json +9 -0
- package/index.js +104 -66
- package/lib/compile2.js +13 -4
- package/locale/en.json +11 -8
- package/locale/zh.json +11 -8
- package/orgs/agent-roster-collective/dist/api-design-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/content-ops-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/contract-review-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/data-quality-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/db-migration-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/docs-writer-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/finance-recon-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/frontend-ui-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/i18n-l10n-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/incident-response-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/literature-review-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/market-research-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/ml-eval-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/performance-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/product-discovery-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/qa-regression-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/recruiting-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/release-manager-1.0.0.json +9 -0
- package/orgs/agent-roster-collective/dist/security-audit-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/sre-oncall-1.0.0.json +10 -0
- package/orgs/agent-roster-collective/dist/support-triage-1.0.0.json +9 -0
- package/package.json +1 -1
- package/schema/compiled.v1.schema.json +30 -0
package/index.js
CHANGED
|
@@ -174,8 +174,107 @@ export function apply(ctx, config) {
|
|
|
174
174
|
"collection route",
|
|
175
175
|
);
|
|
176
176
|
|
|
177
|
-
//
|
|
178
|
-
//
|
|
177
|
+
// 「档案库」与「搜索」共用同一次摊平动作:本机 + 所有订阅来源。
|
|
178
|
+
// 两条路由各写一遍,缓存口径、并发上限与诊断文案迟早会分叉。
|
|
179
|
+
const gatherEntries = async ({ refresh = false } = {}) => {
|
|
180
|
+
const library = collectLibrary(ctx, settings, { name: pkg.name, version: pkg.version });
|
|
181
|
+
const entries = [];
|
|
182
|
+
let localCount = 0;
|
|
183
|
+
for (const workspace of library.workspaces) {
|
|
184
|
+
for (const roster of workspace.rosters) {
|
|
185
|
+
entries.push({ scope: "local", roster, libraryId: workspace.rootDir ?? null, file: roster.file ?? null });
|
|
186
|
+
localCount += 1;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const diagnostics = [];
|
|
191
|
+
const collections = [];
|
|
192
|
+
try {
|
|
193
|
+
const remote = await loadRemotePanel(settings, { refresh });
|
|
194
|
+
for (const item of remote.diagnostics ?? []) if (item.severity !== "info") diagnostics.push(item);
|
|
195
|
+
for (const collection of remote.collections ?? []) collections.push(collection);
|
|
196
|
+
} catch (error) {
|
|
197
|
+
diagnostics.push({
|
|
198
|
+
severity: "warn",
|
|
199
|
+
code: "index-unavailable",
|
|
200
|
+
message: `订阅索引拉不到,这次只显示本机档案:${error instanceof Error ? error.message : String(error)}`,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// 来源两两并发:一个慢集合不该把所有来源都拖住,也不该一次打三十个请求。
|
|
205
|
+
const sourceConcurrency = 2;
|
|
206
|
+
let cursor = 0;
|
|
207
|
+
const fetchNext = async () => {
|
|
208
|
+
while (cursor < collections.length) {
|
|
209
|
+
const collection = collections[cursor];
|
|
210
|
+
cursor += 1;
|
|
211
|
+
const key = `${collection.source ?? ""}::${collection.id}`;
|
|
212
|
+
try {
|
|
213
|
+
const cached = collectionCache.get(key);
|
|
214
|
+
const fetched = cached ?? collectionCache.set(key, await fetchCollection(collection));
|
|
215
|
+
for (const roster of fetched.rosters ?? []) {
|
|
216
|
+
entries.push({
|
|
217
|
+
scope: "remote",
|
|
218
|
+
roster,
|
|
219
|
+
collectionId: collection.id,
|
|
220
|
+
collectionTitle: collection.title ?? null,
|
|
221
|
+
file: roster.file ?? null,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
for (const item of fetched.diagnostics ?? []) if (item.severity === "error") diagnostics.push(item);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
diagnostics.push({
|
|
227
|
+
severity: "warn",
|
|
228
|
+
code: "source-failed",
|
|
229
|
+
message: `${collection.id} 拉取失败:${error instanceof Error ? error.message : String(error)}`,
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
await Promise.all(Array.from({ length: Math.min(sourceConcurrency, collections.length) }, fetchNext));
|
|
235
|
+
|
|
236
|
+
return { entries, diagnostics: diagnostics.slice(0, 20), counts: { local: localCount, remote: entries.length - localCount } };
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const catalogEntry = (entry) => {
|
|
240
|
+
const roster = entry.roster;
|
|
241
|
+
return {
|
|
242
|
+
scope: entry.scope,
|
|
243
|
+
rosterId: typeof roster.id === "string" ? roster.id : "",
|
|
244
|
+
title: typeof roster.title === "string" ? roster.title : "",
|
|
245
|
+
description: typeof roster.description === "string" ? roster.description : "",
|
|
246
|
+
tags: Array.isArray(roster.tags) ? roster.tags : [],
|
|
247
|
+
members: Array.isArray(roster.members) ? roster.members.length : 0,
|
|
248
|
+
memberRoles: (Array.isArray(roster.members) ? roster.members : [])
|
|
249
|
+
.map((member) => (typeof member?.role === "string" ? member.role : ""))
|
|
250
|
+
.filter((role) => role !== "")
|
|
251
|
+
.slice(0, 4),
|
|
252
|
+
libraryId: entry.libraryId ?? null,
|
|
253
|
+
collectionId: entry.collectionId ?? null,
|
|
254
|
+
collectionTitle: entry.collectionTitle ?? null,
|
|
255
|
+
file: entry.file ?? null,
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// 档案库:像插件市场那样「全部摊开」,供浏览、按标签筛选、按来源聚合。
|
|
260
|
+
register(
|
|
261
|
+
"/plugins/dsh-agent-roster/catalog",
|
|
262
|
+
async (req, res) => {
|
|
263
|
+
if (guard(req, res)) return;
|
|
264
|
+
if (!requireMethod(req, res, "GET")) return;
|
|
265
|
+
const query = new URL(req.url ?? "/", "http://localhost").searchParams;
|
|
266
|
+
const gathered = await gatherEntries({ refresh: query.get("refresh") === "1" });
|
|
267
|
+
sendJson(res, 200, {
|
|
268
|
+
ok: true,
|
|
269
|
+
entries: gathered.entries.map(catalogEntry),
|
|
270
|
+
counts: gathered.counts,
|
|
271
|
+
diagnostics: gathered.diagnostics,
|
|
272
|
+
});
|
|
273
|
+
},
|
|
274
|
+
"catalog route",
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
// 搜索:同一个「摊平」结果上做排序,回车即可打开。空查询不做无谓的摊平。
|
|
179
278
|
register(
|
|
180
279
|
"/plugins/dsh-agent-roster/search",
|
|
181
280
|
async (req, res) => {
|
|
@@ -187,70 +286,9 @@ export function apply(ctx, config) {
|
|
|
187
286
|
sendJson(res, 200, { ok: true, q: "", tokens: [], total: 0, matches: [], counts: { local: 0, remote: 0 }, diagnostics: [] });
|
|
188
287
|
return;
|
|
189
288
|
}
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
let localCount = 0;
|
|
194
|
-
for (const workspace of library.workspaces) {
|
|
195
|
-
for (const roster of workspace.rosters) {
|
|
196
|
-
entries.push({ scope: "local", roster, libraryId: workspace.rootDir ?? null, file: roster.file ?? null });
|
|
197
|
-
localCount += 1;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const diagnostics = [];
|
|
202
|
-
const collections = [];
|
|
203
|
-
try {
|
|
204
|
-
const remote = await loadRemotePanel(settings, {});
|
|
205
|
-
for (const item of remote.diagnostics ?? []) if (item.severity !== "info") diagnostics.push(item);
|
|
206
|
-
for (const collection of remote.collections ?? []) collections.push(collection);
|
|
207
|
-
} catch (error) {
|
|
208
|
-
diagnostics.push({
|
|
209
|
-
severity: "warn",
|
|
210
|
-
code: "search-index-unavailable",
|
|
211
|
-
message: `订阅索引拉不到,本次只搜索本机档案:${error instanceof Error ? error.message : String(error)}`,
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// 来源两两并发:一个慢集合不该把所有来源都拖住,也不该一次打三十个请求。
|
|
216
|
-
const sourceConcurrency = 2;
|
|
217
|
-
let cursor = 0;
|
|
218
|
-
const fetchNext = async () => {
|
|
219
|
-
while (cursor < collections.length) {
|
|
220
|
-
const collection = collections[cursor];
|
|
221
|
-
cursor += 1;
|
|
222
|
-
const key = `${collection.source ?? ""}::${collection.id}`;
|
|
223
|
-
try {
|
|
224
|
-
const cached = collectionCache.get(key);
|
|
225
|
-
const fetched = cached ?? collectionCache.set(key, await fetchCollection(collection));
|
|
226
|
-
for (const roster of fetched.rosters ?? []) {
|
|
227
|
-
entries.push({
|
|
228
|
-
scope: "remote",
|
|
229
|
-
roster,
|
|
230
|
-
collectionId: collection.id,
|
|
231
|
-
collectionTitle: collection.title ?? null,
|
|
232
|
-
file: roster.file ?? null,
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
for (const item of fetched.diagnostics ?? []) if (item.severity === "error") diagnostics.push(item);
|
|
236
|
-
} catch (error) {
|
|
237
|
-
diagnostics.push({
|
|
238
|
-
severity: "warn",
|
|
239
|
-
code: "search-source-failed",
|
|
240
|
-
message: `${collection.id} 拉取失败:${error instanceof Error ? error.message : String(error)}`,
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
await Promise.all(Array.from({ length: Math.min(sourceConcurrency, collections.length) }, fetchNext));
|
|
246
|
-
|
|
247
|
-
const result = searchRosters(q, entries);
|
|
248
|
-
const remoteCount = entries.length - localCount;
|
|
249
|
-
sendJson(res, 200, {
|
|
250
|
-
...result,
|
|
251
|
-
counts: { local: localCount, remote: remoteCount },
|
|
252
|
-
diagnostics: diagnostics.slice(0, 20),
|
|
253
|
-
});
|
|
289
|
+
const gathered = await gatherEntries();
|
|
290
|
+
const result = searchRosters(q, gathered.entries);
|
|
291
|
+
sendJson(res, 200, { ...result, counts: gathered.counts, diagnostics: gathered.diagnostics });
|
|
254
292
|
},
|
|
255
293
|
"search route",
|
|
256
294
|
);
|
package/lib/compile2.js
CHANGED
|
@@ -231,7 +231,13 @@ export function compileRoster(options) {
|
|
|
231
231
|
source: {
|
|
232
232
|
roster: roster.id,
|
|
233
233
|
version: roster.version,
|
|
234
|
+
// 产物是唯一被分发的形态:发现它所需的一切(标题、标签、许可、维护者)必须自带,
|
|
235
|
+
// 否则"从远处找一份档案"就只剩一个 id。
|
|
234
236
|
title: roster.title ?? null,
|
|
237
|
+
description: roster.description ?? null,
|
|
238
|
+
tags: Array.isArray(roster.tags) ? roster.tags : [],
|
|
239
|
+
license: roster.license ?? null,
|
|
240
|
+
maintainers: Array.isArray(roster.maintainers) ? roster.maintainers : [],
|
|
235
241
|
repo: options.source?.repo ?? null,
|
|
236
242
|
ref: options.source?.ref ?? null,
|
|
237
243
|
lock: options.source?.lock ?? null,
|
|
@@ -510,10 +516,10 @@ export function rosterViewOf(compiled, roster2, options = {}) {
|
|
|
510
516
|
version: compiled.source.version,
|
|
511
517
|
file: compiled.source.file ?? null,
|
|
512
518
|
title: roster2?.title ?? compiled.source.title ?? "",
|
|
513
|
-
description: roster2?.description ?? "",
|
|
514
|
-
license: roster2?.license ?? "",
|
|
515
|
-
maintainers: roster2?.maintainers ?? [],
|
|
516
|
-
tags: roster2?.tags ?? [],
|
|
519
|
+
description: roster2?.description ?? compiled.source.description ?? "",
|
|
520
|
+
license: roster2?.license ?? compiled.source.license ?? "",
|
|
521
|
+
maintainers: roster2?.maintainers ?? compiled.source.maintainers ?? [],
|
|
522
|
+
tags: roster2?.tags ?? compiled.source.tags ?? [],
|
|
517
523
|
notes: roster2?.notes ?? null,
|
|
518
524
|
members,
|
|
519
525
|
captain,
|
|
@@ -618,6 +624,9 @@ export function flattenCompiledToRoster(compiled) {
|
|
|
618
624
|
};
|
|
619
625
|
if (source.title) roster.title = source.title;
|
|
620
626
|
if (source.description) roster.description = source.description;
|
|
627
|
+
if (source.license) roster.license = source.license;
|
|
628
|
+
if (Array.isArray(source.maintainers) && source.maintainers.length > 0) roster.maintainers = source.maintainers;
|
|
629
|
+
if (Array.isArray(source.tags) && source.tags.length > 0) roster.tags = source.tags;
|
|
621
630
|
if (compiled.captain) {
|
|
622
631
|
const captain = { name: String(compiled.captain.role ?? "").replace(/@[^@]*$/, "") };
|
|
623
632
|
if (compiled.captain.provider) captain.provider = compiled.captain.provider;
|
package/locale/en.json
CHANGED
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"metaRosters": "rosters",
|
|
65
65
|
"metaMembers": "members",
|
|
66
66
|
"metaTeams": "teams",
|
|
67
|
-
"metaOrganization": "Organization {name}"
|
|
67
|
+
"metaOrganization": "Organization {name}",
|
|
68
|
+
"tabsCatalog": "Library"
|
|
68
69
|
},
|
|
69
70
|
"roster": {
|
|
70
71
|
"members": "{count} members",
|
|
@@ -302,18 +303,20 @@
|
|
|
302
303
|
"source.filter": "Filter this collection",
|
|
303
304
|
"source.filterPlaceholder": "Filter by id, title or member",
|
|
304
305
|
"source.filterCount": "{shown} of {total}",
|
|
305
|
-
"
|
|
306
|
+
"catalog": {
|
|
306
307
|
"placeholder": "What should it do? e.g. data quality, release, review",
|
|
307
|
-
"hint": "Searches this machine and every subscribed source",
|
|
308
|
-
"clear": "Clear",
|
|
309
308
|
"searching": "Searching…",
|
|
310
|
-
"counts": "{total}
|
|
311
|
-
"empty": "Nothing
|
|
312
|
-
"failed": "
|
|
309
|
+
"counts": "{shown} / {total} · {local} local · {remote} remote",
|
|
310
|
+
"empty": "Nothing matches. Try another wording, or check Sources for a subscription.",
|
|
311
|
+
"failed": "The library did not load: the host did not answer.",
|
|
313
312
|
"members": "{count} members",
|
|
314
313
|
"local": "local",
|
|
315
314
|
"remoteFrom": "from {collection}",
|
|
316
315
|
"open": "Open",
|
|
317
|
-
"pull": "Pull"
|
|
316
|
+
"pull": "Pull",
|
|
317
|
+
"mode": "Layout",
|
|
318
|
+
"modeSource": "By source",
|
|
319
|
+
"modeFlat": "Flat",
|
|
320
|
+
"refresh": "Refresh"
|
|
318
321
|
}
|
|
319
322
|
}
|
package/locale/zh.json
CHANGED
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"metaRosters": "份档案",
|
|
65
65
|
"metaMembers": "名成员",
|
|
66
66
|
"metaTeams": "支团队",
|
|
67
|
-
"metaOrganization": "组织 {name}"
|
|
67
|
+
"metaOrganization": "组织 {name}",
|
|
68
|
+
"tabsCatalog": "档案库"
|
|
68
69
|
},
|
|
69
70
|
"roster": {
|
|
70
71
|
"members": "{count} 名成员",
|
|
@@ -302,18 +303,20 @@
|
|
|
302
303
|
"source.filter": "在这份集合里查找",
|
|
303
304
|
"source.filterPlaceholder": "按 id、标题或成员名过滤",
|
|
304
305
|
"source.filterCount": "{shown} / {total}",
|
|
305
|
-
"
|
|
306
|
+
"catalog": {
|
|
306
307
|
"placeholder": "要找什么能力?例:数据质量、发版、代码评审",
|
|
307
|
-
"hint": "同时搜本机与已订阅的来源",
|
|
308
|
-
"clear": "清除",
|
|
309
308
|
"searching": "正在搜索…",
|
|
310
|
-
"counts": "
|
|
311
|
-
"empty": "
|
|
312
|
-
"failed": "
|
|
309
|
+
"counts": "{shown} / {total} 份 · 本机 {local} · 远端 {remote}",
|
|
310
|
+
"empty": "没有符合条件的档案。换个词,或去「档案源」看看订阅。",
|
|
311
|
+
"failed": "档案库加载失败:宿主没有响应。",
|
|
313
312
|
"members": "{count} 名成员",
|
|
314
313
|
"local": "本机",
|
|
315
314
|
"remoteFrom": "来自 {collection}",
|
|
316
315
|
"open": "打开",
|
|
317
|
-
"pull": "拉取"
|
|
316
|
+
"pull": "拉取",
|
|
317
|
+
"mode": "显示方式",
|
|
318
|
+
"modeSource": "按来源",
|
|
319
|
+
"modeFlat": "平铺",
|
|
320
|
+
"refresh": "刷新"
|
|
318
321
|
}
|
|
319
322
|
}
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "api-design",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "API 设计评审组",
|
|
7
|
+
"description": "在写第一行实现之前,把接口的形状、演进与失败语义定下来。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"api",
|
|
10
|
+
"design",
|
|
11
|
+
"review"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "content-ops",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "内容运营组",
|
|
7
|
+
"description": "一次发布:选题、成稿、分发,三件事各有验收。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"content",
|
|
10
|
+
"publishing"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "contract-review",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "合同审阅组",
|
|
7
|
+
"description": "找到会让你赔钱、被锁定或无法退出的条款。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"legal",
|
|
10
|
+
"contract"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "data-quality",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "数据质量组",
|
|
7
|
+
"description": "为一份数据表定“什么算合格”,并把不合格变成可复现的判据。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"data",
|
|
10
|
+
"quality",
|
|
11
|
+
"checks"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "db-migration",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "数据库迁移组",
|
|
7
|
+
"description": "把一次 schema 变更做到可回滚:先证明能回,再动手。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"database",
|
|
10
|
+
"migration",
|
|
11
|
+
"reliability"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "docs-writer",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "文档组",
|
|
7
|
+
"description": "让文档里的每条命令都真的能跑,每个读数都带时间。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"docs",
|
|
10
|
+
"writing"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "finance-recon",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "财务对账组",
|
|
7
|
+
"description": "让两套账的差异落到具体行,而不是“大概对得上”。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"finance",
|
|
10
|
+
"reconciliation"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "frontend-ui",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "前端实现组",
|
|
7
|
+
"description": "把设计做成能用、能读、能被键盘与读屏器操作的东西。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"frontend",
|
|
10
|
+
"ui",
|
|
11
|
+
"a11y"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "i18n-l10n",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "本地化组",
|
|
7
|
+
"description": "把一份文案做成两种语言,且两种语言说同一件事。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"i18n",
|
|
10
|
+
"docs",
|
|
11
|
+
"review"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "incident-response",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "事故响应组",
|
|
7
|
+
"description": "线上出事时的三个人:指挥、定位、记录;先止损再找根因。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"incident",
|
|
10
|
+
"oncall",
|
|
11
|
+
"reliability"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "literature-review",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "文献综述组",
|
|
7
|
+
"description": "把一堆论文读成一张能追到出处的证据表。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"research",
|
|
10
|
+
"literature"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "market-research",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "市场研究组",
|
|
7
|
+
"description": "把“听说”变成“有出处的数”,并说清它什么时候会失效。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"research",
|
|
10
|
+
"market"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "ml-eval",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "模型评测组",
|
|
7
|
+
"description": "跑分之前先问:这套题能不能区分好坏。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"ml",
|
|
10
|
+
"evaluation"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "performance",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "性能优化组",
|
|
7
|
+
"description": "先量再改:没有基线就没有优化。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"performance",
|
|
10
|
+
"profiling"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "product-discovery",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "产品发现组",
|
|
7
|
+
"description": "在写需求之前,先证明这个需求真的存在。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"product",
|
|
10
|
+
"discovery"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "qa-regression",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "回归测试组",
|
|
7
|
+
"description": "每次改动都问:哪些旧行为可能被碰坏。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"qa",
|
|
10
|
+
"regression",
|
|
11
|
+
"testing"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "recruiting",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "招聘筛选组",
|
|
7
|
+
"description": "按岗位要求筛人,只报证据,不做印象判断。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"hiring",
|
|
10
|
+
"screening"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "release-manager",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "发布管理组",
|
|
7
|
+
"description": "每一次发布都可复现、可回滚、可解释。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"release",
|
|
10
|
+
"versioning"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "security-audit",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "安全审计组",
|
|
7
|
+
"description": "在代码里找“能被利用”的东西,而不是“看着不安全”的东西。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"security",
|
|
10
|
+
"audit",
|
|
11
|
+
"review"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,16 @@
|
|
|
4
4
|
"roster": "sre-oncall",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "SRE 值守组",
|
|
7
|
+
"description": "值守不是盯屏:定告警阈值、写手册、算容量。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"sre",
|
|
10
|
+
"oncall",
|
|
11
|
+
"capacity"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"maintainers": [
|
|
15
|
+
"STofone"
|
|
16
|
+
],
|
|
7
17
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
18
|
"ref": "main",
|
|
9
19
|
"lock": null,
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
"roster": "support-triage",
|
|
5
5
|
"version": "1.0.0",
|
|
6
6
|
"title": "客服分诊组",
|
|
7
|
+
"description": "把每条来信分到“能自助、要人接、是缺陷”三条路之一。",
|
|
8
|
+
"tags": [
|
|
9
|
+
"support",
|
|
10
|
+
"triage"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"maintainers": [
|
|
14
|
+
"STofone"
|
|
15
|
+
],
|
|
7
16
|
"repo": "dsh-agent-roster/dsh-agent-roster",
|
|
8
17
|
"ref": "main",
|
|
9
18
|
"lock": null,
|