@stofone/dsh-agent-roster 0.10.5 → 0.10.7
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 +24 -1
- package/README.md +10 -4
- package/README.zh.md +9 -4
- package/lib/remote.js +22 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,27 @@
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.10.7] - 2026-11-03
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
|
|
11
|
+
- README (both languages) now describes the cache that knows its own version, the two remote-source
|
|
12
|
+
diagnostics added in 0.10.6, and a `lib/` listing that matches what is actually there — the previous one
|
|
13
|
+
still named only the v1-era modules and omitted `compile2`/`plan`/`migrate`/`run`/`role`/`roster2`.
|
|
14
|
+
- Test count corrected to 297/297.
|
|
15
|
+
|
|
16
|
+
## [0.10.6] - 2026-11-03
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **An index cached before an upgrade kept feeding the old shape.** The cache stored an index document
|
|
21
|
+
with no notion of what shape it had, so after upgrading to 0.10.3 — the release that added
|
|
22
|
+
`collection.files` — the panel kept reading a cached index without `files`, fell back to the v1 path, and
|
|
23
|
+
404'd. Caches now carry `CACHE_VERSION`; a mismatch refetches once.
|
|
24
|
+
- A failed fetch on the v1 fallback path now says *why* it is likely failing: if the collection has no
|
|
25
|
+
`files` mapping, the diagnostic points at a stale index (refresh, or delete `.index-cache`) instead of
|
|
26
|
+
leaving a bare `HTTP 404`.
|
|
27
|
+
|
|
7
28
|
## [0.10.5] - 2026-11-03
|
|
8
29
|
|
|
9
30
|
### Fixed
|
|
@@ -512,7 +533,9 @@
|
|
|
512
533
|
- 工具返回值含 `undefined` 键,运行时按 `value is not lossless JSON` 整次拒绝;缺失值统一写 `null`,
|
|
513
534
|
且所有返回值先过 `lib/json.js#lossless`。
|
|
514
535
|
|
|
515
|
-
[Unreleased]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.
|
|
536
|
+
[Unreleased]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.7...main
|
|
537
|
+
[0.10.7]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.6...v0.10.7
|
|
538
|
+
[0.10.6]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.5...v0.10.6
|
|
516
539
|
[0.10.5]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.4...v0.10.5
|
|
517
540
|
[0.10.4]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.3...v0.10.4
|
|
518
541
|
[0.10.3]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.10.2...v0.10.3
|
package/README.md
CHANGED
|
@@ -392,6 +392,9 @@ repository's `index/registry.json`, and anyone who subscribes can see them in th
|
|
|
392
392
|
- **How often it refreshes**: TTL **one hour** — that is the unauthenticated GitHub budget of 60 requests/hour.
|
|
393
393
|
`?refresh=1` (or the tools' `refresh`) bypasses the cache, throttled to one try per 60 seconds so the quota is not
|
|
394
394
|
burned. On failure the last cached index is reused and labelled "cached (fetch failed)" in the panel.
|
|
395
|
+
The cache records **which shape of index it holds** (`CACHE_VERSION`): a plugin upgrade that changes the
|
|
396
|
+
index shape invalidates old caches and refetches once, so "I upgraded but the panel still 404s" is not a
|
|
397
|
+
thing you have to debug by deleting a directory.
|
|
395
398
|
- **Pulling**: writes are idempotent and report one of `created`, `updated` (explicit overwrite), `unchanged`
|
|
396
399
|
(same content, nothing written) or `conflict` (the local copy differs and is **not** overwritten by default).
|
|
397
400
|
Conflicts are yours to resolve: merge in the editor, or pull again with `overwrite` in the request body.
|
|
@@ -441,7 +444,7 @@ Validation reports errors, warnings and infos with `file`, `path` and `reason`.
|
|
|
441
444
|
- safety: `reserved-character` (`^`, `$`, `|`, braces), `forbidden-content` (prompt-injection patterns), `single-line-required`
|
|
442
445
|
- limits: `string-too-long`, `too-many-members`, `too-many-values`
|
|
443
446
|
- library level: `library-missing`, `library-unusable`, `missing-roster-file`, `multiple-roster-files`, `unexpected-file`, `unreadable-file`, `unreadable-dir`, `duplicate-roster-id`, `tool-policy-cross-check-skipped`
|
|
444
|
-
- remote sources: `index-unreachable`, `index-invalid`, `index-refresh-throttled`, `index-source-invalid`, `collection-fetch-failed`, `collection-not-found`
|
|
447
|
+
- remote sources: `index-unreachable`, `index-invalid`, `index-refresh-throttled`, `index-source-invalid`, `collection-fetch-failed`, `collection-not-found`, `index-may-be-stale` (a v1-path fetch failed on a collection that has no `files` map — the index is probably older than the library), `collection-roster-needs-roles` (the entry points at a v2 assembly, which cannot travel as one file)
|
|
445
448
|
|
|
446
449
|
An empty library is not an error. A missing one is reported as info, not error. `tool-policy-cross-check-skipped` is emitted **once per library** (not once per roster) when no `knownToolPolicies` are configured — a per-roster warning would turn one fact into n lines of noise.
|
|
447
450
|
|
|
@@ -462,8 +465,11 @@ Layout:
|
|
|
462
465
|
|
|
463
466
|
```
|
|
464
467
|
index.js host plugin: Config, apply, six routes
|
|
465
|
-
lib/ format,
|
|
466
|
-
|
|
468
|
+
lib/ reading: format, format-v2, frontmatter, parse, validate, role, roster2,
|
|
469
|
+
capabilities, organization, registry, remote, library, home
|
|
470
|
+
compiling: compile2, plan, migrate, run
|
|
471
|
+
speaking to the runtime: bridge, verify, diff, digest, render, tools, service,
|
|
472
|
+
teams-state, captain, write, apply, serialize, config-view, json, http
|
|
467
473
|
client.js client plugin: sidebar entry, main panel (rosters/teams/health), settings section
|
|
468
474
|
locale/ panel + listing dictionaries (en/zh)
|
|
469
475
|
schema/ roster v1 / role v1 / roster v2 / compiled v1 / capabilities / organization / registry
|
|
@@ -480,7 +486,7 @@ test/ unit tests
|
|
|
480
486
|
|
|
481
487
|
Verified on this machine:
|
|
482
488
|
|
|
483
|
-
- `npm test` —
|
|
489
|
+
- `npm test` — 297/297 passing (format, parse, validate, registry, paths, bridge, verify buckets, digests and provenance, roster diff, capability requirements and the capability gate, library organization, registry schema, lossless JSON, write plan/apply, all routes, panel snapshot and hints, dictionary consistency, tool contracts, client loader contract, library snapshot, config view, package manifest, declared fields and captain block, schema/constant alignment, the v2 role/roster/compiled layers and their schema alignment, v1→v2 migration, run records feeding the plan, remote registry and one-click install).
|
|
484
490
|
- `npm run smoke` — `apply()` registers all six tools through a real `defineTool` from a DSH bundle; `roster_list` / `roster_show` / `roster_create` / `roster_verify` / `roster_diff` execute, every output survives `lossless` checks, `path` overrides are honored, effect disposal runs cleanly. The same command then loads `client.js` against a stubbed module table and asserts the three slot registrations, style injection and effect disposal.
|
|
485
491
|
- CLI: `validate --dir examples` returns exit 0 over both example libraries.
|
|
486
492
|
- Installed into a real profile with the plugin manager (`plugin_manager install_bundle` against this directory → `link:` dependency + bundle entry); the profile re-reads the linked files on restart.
|
package/README.zh.md
CHANGED
|
@@ -369,6 +369,8 @@ node bin/cli.mjs compile --roster examples-orchestration/rosters/core-review \
|
|
|
369
369
|
留空 = 只用官方源 `dsh-agent-roster/dsh-agent-roster` 的 `index/registry.json`;显式写 `false` 才彻底不连远端。
|
|
370
370
|
- **多久更新一次**:TTL **一小时**——等于未认证 GitHub 的 60 次/小时配额。`?refresh=1`(或工具的 `refresh`)
|
|
371
371
|
可绕过缓存,但 60 秒内最多一次,避免把配额烧光。拉取失败时沿用上次缓存并在页面上写明「缓存(拉取失败)」。
|
|
372
|
+
缓存里记着**它存的是哪一种形状的索引**(`CACHE_VERSION`):升级插件后如果索引形状变了,旧缓存自动失效、重取一次,
|
|
373
|
+
所以「我升级了,面板却还 404」不需要靠删目录来排查。
|
|
372
374
|
- **拉取到本机**:写入是幂等的,四种结果都会报给你——
|
|
373
375
|
`created`(新写入)、`updated`(显式覆盖)、`unchanged`(内容一致,不写盘)、`conflict`(本地不一样,**默认不覆盖**)。
|
|
374
376
|
冲突要你自己决定:要么在编辑器里合并,要么再点一次「拉取到本机」并在请求里带 `overwrite`。
|
|
@@ -417,7 +419,7 @@ node bin/cli.mjs compile --roster examples-orchestration/rosters/core-review \
|
|
|
417
419
|
- 安全:`reserved-character`(`^`、`$`、`|`、花括号)、`forbidden-content`(提示注入特征)、`single-line-required`
|
|
418
420
|
- 上限:`string-too-long`、`too-many-members`、`too-many-values`
|
|
419
421
|
- 档案库级:`library-missing`、`library-unusable`、`missing-roster-file`、`multiple-roster-files`、`unexpected-file`、`unreadable-file`、`unreadable-dir`、`duplicate-roster-id`、`tool-policy-cross-check-skipped`
|
|
420
|
-
- 远端源:`index-unreachable`、`index-invalid`、`index-refresh-throttled`、`index-source-invalid`、`collection-fetch-failed`、`collection-not-found`
|
|
422
|
+
- 远端源:`index-unreachable`、`index-invalid`、`index-refresh-throttled`、`index-source-invalid`、`collection-fetch-failed`、`collection-not-found`、`index-may-be-stale`(没有 `files` 映射却回退到 v1 路径并失败——索引多半比档案库旧)、`collection-roster-needs-roles`(条目指向 v2 组装,而组装不能以单文件旅行)
|
|
421
423
|
|
|
422
424
|
空档案库不是错误;目录不存在只算 info。`tool-policy-cross-check-skipped` **每座档案库只发一条**(不是每份档案一条)——没配 `knownToolPolicies` 是一件库级的事,按档案重复只会把一个事实放大成 n 行噪音。
|
|
423
425
|
|
|
@@ -436,8 +438,11 @@ node scripts/check-locale.mjs # client.js 里的静态 t() 键必须两本词
|
|
|
436
438
|
|
|
437
439
|
```
|
|
438
440
|
index.js 宿主半边:Config、apply、六条路由
|
|
439
|
-
lib/ format /
|
|
440
|
-
|
|
441
|
+
lib/ 读:format / format-v2 / frontmatter / parse / validate / role / roster2 /
|
|
442
|
+
capabilities / organization / registry / remote / library / home
|
|
443
|
+
编译:compile2 / plan / migrate / run
|
|
444
|
+
对运行时说话:bridge / verify / diff / digest / render / tools / service /
|
|
445
|
+
teams-state / captain / write / apply / serialize / config-view / json / http
|
|
441
446
|
client.js 客户端半边:左侧栏图标 + 主面板(档案/团队/体检)+ 设置页小节
|
|
442
447
|
locale/ 面板与列表词典(en/zh)
|
|
443
448
|
schema/ roster v1 / role v1 / roster v2 / compiled v1 / capabilities / organization / registry
|
|
@@ -454,7 +459,7 @@ test/ 单测
|
|
|
454
459
|
|
|
455
460
|
本机已验证:
|
|
456
461
|
|
|
457
|
-
- `npm test` ——
|
|
462
|
+
- `npm test` —— 297/297 通过(格式、解析、校验、扫描、路径、桥接、核对四桶、摘要与溯源、档案差异、能力要求与能力闸门、档案库组织、索引 schema、无损 JSON、写入计划与执行、六条路由、快照与提示、两本词典一致、工具契约、客户端加载器契约、包清单、配置视图、样式 token 约束、声明层字段与队长段、schema 与常量对齐、v2 角色/组装/编译三层及其 schema 对齐、v1→v2 迁移、执行回执并入施工图)。
|
|
458
463
|
- `npm run smoke` —— 用真实 DSH bundle 的 `defineTool` 注册六个工具,逐个调用:输出全部通过无损校验、`path` 覆盖生效、释放干净;同一条命令随后用桩模块表加载 `client.js`,断言三处槽位注册、样式只注入一次、effect 可回收。
|
|
459
464
|
- CLI:`validate --dir examples` 对两座示例库退出码 0。
|
|
460
465
|
- 用插件管理器真的装进了本机 profile(`plugin_manager install_bundle` 指向本仓库 → `link:` 依赖 + bundle 条目),重启后按链接读取本仓库文件。
|
package/lib/remote.js
CHANGED
|
@@ -49,6 +49,15 @@ export const DEFAULT_REGISTRY_URL =
|
|
|
49
49
|
/** 缓存目录名,放在档案库根下,跟着 `$DSH_HOME` 走。 */
|
|
50
50
|
export const CACHE_DIR_NAME = ".index-cache";
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* 索引缓存的语义版本。
|
|
54
|
+
*
|
|
55
|
+
* 缓存里存的是**索引的形状**,而形状会随插件版本变(0.10.3 给 collection 加了 `files`)。
|
|
56
|
+
* 不认版本号的缓存会在升级后继续提供旧形状,表现就是"面板明明装了新版,仍然 404"。
|
|
57
|
+
* 索引语义再变时把这里 +1,老缓存自动失效、重取一次。
|
|
58
|
+
*/
|
|
59
|
+
export const CACHE_VERSION = 2;
|
|
60
|
+
|
|
52
61
|
/** entry 文件所在的仓库前缀(只支持 GitHub raw,不引入 git 协议)。 */
|
|
53
62
|
export const GITHUB_RAW = "https://raw.githubusercontent.com";
|
|
54
63
|
|
|
@@ -266,6 +275,7 @@ export async function loadRegistry(source, options = {}) {
|
|
|
266
275
|
});
|
|
267
276
|
}
|
|
268
277
|
writeCache(cachePath, {
|
|
278
|
+
cacheVersion: CACHE_VERSION,
|
|
269
279
|
sourceId: source.id,
|
|
270
280
|
fetchedAt: current,
|
|
271
281
|
etag: fetched.etag,
|
|
@@ -567,6 +577,17 @@ export async function fetchCollection(collection, options = {}) {
|
|
|
567
577
|
}
|
|
568
578
|
if (loaded === null) {
|
|
569
579
|
diagnostics.push(diagnostic("warn", "collection-fetch-failed", `${collection.id}/${rosterId} 拉取失败:${lastError || "未知原因"}`));
|
|
580
|
+
// 没有 files 映射时退回的是 v1 路径;v2 库在那条路径上必然 404。
|
|
581
|
+
// 这时最可能的原因是"索引是升级前缓存的",提示一句比让用户猜有用。
|
|
582
|
+
if (listedPath === null) {
|
|
583
|
+
diagnostics.push(
|
|
584
|
+
diagnostic(
|
|
585
|
+
"info",
|
|
586
|
+
"index-may-be-stale",
|
|
587
|
+
`${collection.id} 的索引里没有 files 映射,回退到了 v1 路径;若刚升级过插件,先刷新索引(缓存按版本失效,也可删 .index-cache)`,
|
|
588
|
+
),
|
|
589
|
+
);
|
|
590
|
+
}
|
|
570
591
|
continue;
|
|
571
592
|
}
|
|
572
593
|
const parsed = parseDocumentText(loaded.text, { file: loaded.url });
|
|
@@ -669,6 +690,7 @@ export function cachePathFor(cacheDir, id) {
|
|
|
669
690
|
function readCache(file) {
|
|
670
691
|
try {
|
|
671
692
|
const parsed = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
693
|
+
if (parsed?.cacheVersion !== CACHE_VERSION) return null;
|
|
672
694
|
if (typeof parsed?.fetchedAt !== "number" || typeof parsed?.document !== "object" || parsed.document === null) return null;
|
|
673
695
|
return parsed;
|
|
674
696
|
} catch {
|
package/package.json
CHANGED