@gestaltrun/dsh-workspace-bundle 0.0.0-stage → 0.1.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.
Files changed (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +37 -0
  3. package/README.md +92 -2
  4. package/README.zh.md +93 -0
  5. package/lib/index.js +2868 -0
  6. package/lib/types/agent-config-contract/agent-configs.d.ts +621 -0
  7. package/lib/types/agent-config-contract/agent-configs.js +68 -0
  8. package/lib/types/agent-config-contract/cs-hosting.d.ts +1333 -0
  9. package/lib/types/agent-config-contract/cs-hosting.js +163 -0
  10. package/lib/types/agent-config-contract/errors.d.ts +224 -0
  11. package/lib/types/agent-config-contract/errors.js +202 -0
  12. package/lib/types/agent-config-contract/ids.d.ts +65 -0
  13. package/lib/types/agent-config-contract/ids.js +35 -0
  14. package/lib/types/agent-config-contract/route.d.ts +56 -0
  15. package/lib/types/agent-config-contract/route.js +1 -0
  16. package/lib/types/agent-config-contract/test-account-claim.d.ts +24 -0
  17. package/lib/types/agent-config-contract/test-account-claim.js +5 -0
  18. package/lib/types/agent-config-format.d.ts +86 -0
  19. package/lib/types/agent-config-format.js +119 -0
  20. package/lib/types/agent-config-observation.d.ts +64 -0
  21. package/lib/types/agent-config-observation.js +448 -0
  22. package/lib/types/agent-config-source.d.ts +78 -0
  23. package/lib/types/agent-config-source.js +411 -0
  24. package/lib/types/agent-config-types.d.ts +67 -0
  25. package/lib/types/agent-config-types.js +1 -0
  26. package/lib/types/bundled-agent-config.d.ts +29 -0
  27. package/lib/types/bundled-agent-config.js +47 -0
  28. package/lib/types/config.d.ts +34 -0
  29. package/lib/types/config.js +53 -0
  30. package/lib/types/definition.d.ts +82 -0
  31. package/lib/types/definition.js +20 -0
  32. package/lib/types/digest.d.ts +38 -0
  33. package/lib/types/digest.js +243 -0
  34. package/lib/types/errors.d.ts +22 -0
  35. package/lib/types/errors.js +26 -0
  36. package/lib/types/filesystem.d.ts +16 -0
  37. package/lib/types/filesystem.js +64 -0
  38. package/lib/types/index.d.ts +28 -0
  39. package/lib/types/index.js +19 -0
  40. package/lib/types/journal.d.ts +51 -0
  41. package/lib/types/journal.js +109 -0
  42. package/lib/types/local-host-identity.d.ts +65 -0
  43. package/lib/types/local-host-identity.js +87 -0
  44. package/lib/types/local-host-replacement.d.ts +49 -0
  45. package/lib/types/local-host-replacement.js +112 -0
  46. package/lib/types/paths.d.ts +26 -0
  47. package/lib/types/paths.js +48 -0
  48. package/lib/types/provider.d.ts +83 -0
  49. package/lib/types/provider.js +560 -0
  50. package/lib/types/session-events.d.ts +23 -0
  51. package/lib/types/session-events.js +14 -0
  52. package/lib/types/types.d.ts +126 -0
  53. package/lib/types/types.js +1 -0
  54. package/locale/en.json +6 -0
  55. package/locale/zh.json +6 -0
  56. package/package.json +69 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DeepSeek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,37 @@
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
+ # pnpm run verify-translation-pairing --write product/workspace-bundle/README.md
5
+ /:
6
+ en: 79fcf0fef0b0e5ab
7
+ zh: 013889272c7c75ed
8
+ /gestaltrun-dsh-workspace-bundle:
9
+ en: 32d9d61fe0c0c65a
10
+ zh: baf32db83ff0c674
11
+ /gestaltrun-dsh-workspace-bundle/summary:
12
+ en: 7e2c6d1fe1029327
13
+ zh: 80c8ac0e443ab679
14
+ /gestaltrun-dsh-workspace-bundle/table-of-contents:
15
+ en: 3f8824c773c2099e
16
+ zh: 3f8824c773c2099e
17
+ /gestaltrun-dsh-workspace-bundle/service-contract:
18
+ en: b4bc9ca5c553acf2
19
+ zh: e5660b60cc89953a
20
+ /gestaltrun-dsh-workspace-bundle/template-digest:
21
+ en: ace3ca12ffd26d60
22
+ zh: 6ef8270851901c24
23
+ /gestaltrun-dsh-workspace-bundle/upgrade-and-recovery:
24
+ en: 3aa7ca69d180616a
25
+ zh: cac74e4a9f989ae2
26
+ /gestaltrun-dsh-workspace-bundle/agent-configurations:
27
+ en: 68613875bf7392d0
28
+ zh: a78c427ba33c76d5
29
+ /gestaltrun-dsh-workspace-bundle/configuration:
30
+ en: 086761086e09adcb
31
+ zh: 1158f36ec547fcdd
32
+ /gestaltrun-dsh-workspace-bundle/model-experience:
33
+ en: 783dcce69a33b4eb
34
+ zh: 961497005b98fb7d
35
+ /gestaltrun-dsh-workspace-bundle/dev-note:
36
+ en: d87baca6542df62b
37
+ zh: 6faf785c5c2917cf
package/README.md CHANGED
@@ -1,3 +1,93 @@
1
- # Temporary Holding Version
1
+ ---
2
+ description: "WorkspaceBundles Service Definition and Provider: packaged templates, stable hidden Workspaces, and whole-tree upgrades."
3
+ kind: "package-plugin"
4
+ ---
2
5
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
6
+ # @gestaltrun/dsh-workspace-bundle
7
+
8
+ English | [中文](README.zh.md)
9
+
10
+ ## Summary
11
+
12
+ This package defines the Host-only `WorkspaceBundles` service (`ctx.workspaceBundles`). A product plugin registers a packaged template; `ensure` materializes a stable Workspace with bundle origin, and an upgrade replaces the tree as a whole. Ordinary Workspace views stay empty for that origin. Desktop lists it in `DESKTOP_PLATFORM_PACKAGE_SOURCES`. It publishes with `publishConfig.access` set to `public` and dist-tag `candidate`. It is not a profile bundle and has no cordis patch. The design is in the [customer-service hosting scheme](../../.agents/design/cs-hosting/scheme.zh.md).
13
+
14
+ ## Table of Contents
15
+
16
+ - [Service contract](#service-contract)
17
+ - [Template digest](#template-digest)
18
+ - [Upgrade and recovery](#upgrade-and-recovery)
19
+ - [Agent configurations](#agent-configurations)
20
+ - [Configuration](#configuration)
21
+ - [Model Experience](#model-experience)
22
+ - [Dev Note](#dev-note)
23
+
24
+ ## Service contract
25
+
26
+ `register(template)` is an effect: it returns a disposer that forbids later `ensure` and `acquire` for that identity. `ensure({ bundleId, workspaceKey })` verifies the template, writes a staging tree, and registers a Workspace whose `origin` is `{ kind: 'bundle', bundleId, workspaceKey }`. Repeated calls reuse the Workspace id and path. `acquire(workspaceId)` holds a lease that delays upgrade quiesce. `acquireAgentConfig(identity)` adopts and verifies content and acquires its lease in the same serialized operation. Its handle carries the Workspace id, verified source root, full version, archive SHA-256 (null for repository templates), and template digest. `retain()` synchronously extends that exact selection for another consumer; each handle is released once, after activity and persistence finish. Releasing a parent leaves retained consumers active. Provider unload waits for these handles and queued acquisitions. `record(identity)` returns the durable product record. `pathOf(identity)` is the absolute materialize directory from `materializeRoot` and the identity segments; it does not require `ensure`.
27
+
28
+ This is a capability package. It does not declare an installable bundle patch.
29
+
30
+ ## Template digest
31
+
32
+ The packaged `manifest.json` lists every file's SHA-256 digest and an overall digest of the ordered catalog. Materialize rejects symbolic links, parent-segment paths, missing assets, extra files, and digest mismatch. The immutable copy under `templateCacheRoot` is what recovery verifies when the package source directory is gone.
33
+
34
+ ## Upgrade and recovery
35
+
36
+ Replacement is staging → `updating` journal → quiesce leases → rename the live root to backup and staging to the stable root → verify → commit. A crash at a swap or commit point recovers a wholly old tree or a wholly new tree; the Workspace id and path do not change. Consumers are barred while the journal is `updating`.
37
+
38
+ Before replacing an existing tree, the Provider awaits the serial `workspace-bundle/quiesce` event under the durable `updating` barrier. Consumers cancel their activity, await its completion and release leases in that listener. A listener failure leaves the journal for recovery and prevents the swap.
39
+
40
+ ## Agent configurations
41
+
42
+ `BundledAgentConfigReceiptSchema` and `BundledAgentConfigReceipt` define the publication receipt beside a shipped template: `<template-directory>.agent-config.json`. It records format version 1, workspace kind, full release version, gzip SHA-256 and size, Host compatibility range, optional runtime range, and template digest. It contains no URL, credential or release notes. `loadBundledAgentConfigSync(template)` attaches the receipt and `agentConfigSha256` to an already verified template; an absent receipt returns the original template, while an unreadable, invalid or mismatched receipt throws `AGENT_CONFIG_INVALID`. The adjacent file stays outside the template catalog and model input.
43
+
44
+ Handles, Session version events and observations use the receipt SHA-256 for a bundled publication. Its journal package digest remains null, so replacing the installation selects the new bundled template on the next acquire. Bundled content never enters the remote version cache. A matching assignment creates no download or pending candidate. Downloaded content retains its actual journal digest and cache, including when its bytes match the registered template.
45
+
46
+ The optional module reporter exposes `replaced` after `409 LOCAL_HOST_REPLACED`. `WorkspaceBundles.localHostReplacement` owns the shared member fence in `journalRoot/local-host-replacement.json`; its key contains the server, member and shop, without an installation or module identity. Reporters, leases and checkpoints use that same state. A callable `hostId` supplies the current installation identity. Binding changes cancel and join the previous run but keep a replaced member stopped. Explicit activation registers every composed local module and confirms their reports before clearing the fence; an incomplete activation remains stopped. Legacy per-installation flags are imported into the member fence before the new identity can register. Stop writes use atomic replacement with bounded Windows retries. A failed write keeps the memory fence and module-file stop markers; subsequent marks retry persistence, and startup checks those markers even after an earlier migration. Other failure handling retains its retry or conflict behavior.
47
+
48
+ `WorkspaceBundles.localHostIdentity` keeps one local Host identity per server and member in `journalRoot/local-host-identity.json`, so every local module of one installation reports under the same identity. The module that owns the installation identity publishes it; `sharedLocalHostId(ctx, fallback)` gives another module's reporter that identity, or its own fallback before any identity is published. Publishes run in order, read the owner's identity when they commit, and become visible only after the atomic write succeeds. A confirmed identity is never replaced, so a reporter never returns to an identity the server already replaced. The file loads synchronously; an unreadable or invalid file fails plugin load.
49
+
50
+ `registerAgentConfigSource({ identity, revision, query, validate?, observation? })` adds an authenticated assignment query for a registered template and returns an async disposer that cancels and joins its work. Startup restores and validates this identity’s committed journal before starting the reporter or assignment query, including on an idle Host. Configured polling prepares candidates. When committed content is blocked and the Workspace has no activity leases, polling atomically adopts a validated candidate and checks execution permission again; valid committed content waits for the next acquire. `agentConfig(identity)` exposes the applied version, candidate and a fixed failure diagnostic; `refreshAgentConfig(identity)` joins one query and download. `ensure` and `acquire` apply a candidate only when the Workspace has no leases. Consumers must acquire before starting a turn and retain that lease through its end. The existing replacement journal keeps the Workspace id and path stable. This API does not cancel a running turn to apply remote content.
51
+
52
+ The archive is deterministic gzip JSON with `manifest` and `files`. The manifest has `formatVersion: 1`, `workspaceKind`, full SemVer `version`, `hostAgentConfigApiRange`, and sorted `files` containing `path`, `sizeBytes` and `sha256`. The parallel file array carries matching `path` and canonical `base64`. Gzip metadata contains no timestamp or host identity. Full versions including build metadata, such as `1.0.0+build.42`, identify different packages; build metadata does not change SemVer precedence. The Host Agent configuration API is `2.0.0`; compatible customer-service archives declare `^2.0.0`. All compressed bytes, file sizes and digests are verified before publishing the candidate tree. Links, traversal, case collisions, reserved names, duplicates and expansion beyond the configured bound are rejected.
53
+
54
+ An optional `validate(template, signal)` callback owns consumer checks; omission keeps generic archive validation. It must pass before a candidate is published, before adoption, and before restored content can execute. Physical swap recovery first restores a complete tree, then checks execution permission. An incompatible or damaged committed cache sets `blocked: true`; `current` is diagnostic only, new leases and customer-service CLI calls are refused, and default diagnostics name the blocked automatic service and compatible replacement. The old cache and Workspace identity are retained. A compatible candidate can atomically repair that same Workspace; `builtin` cannot bypass the block.
55
+
56
+ `agentConfig(identity).lastRejection` exposes the latest same-scope refusal as a fixed code and optional exact version and SHA-256, including build metadata. A query failure retains that refusal; `AGENT_CONFIG_QUERY_FAILED` and `AGENT_CONFIG_SCOPE_CHANGED` never create one. A different validated assignment, successful matching validation or commit, scope revision change, and disposal clear the applicable refusal. Late old-scope results cannot restore it. A blocked restored cache reports its committed version when known; `blocked` remains independent of candidate validation. This observation is process-local and is reconstructed by normal validation after restart.
57
+
58
+ Downloaded trees live under `templateCacheRoot/agent-config-versions/{bundleId}/{workspaceKey}/{sha256}/{version}` with read-only files and directories. The committed journal records the full version and package digest, so identical templates in distinct versions remain distinguishable after restart. The source revision changes with its authenticated assignment identity. A revision change cancels and joins the previous query/download, clears uncommitted candidates and queries the new identity; publication and replacement recheck it. The query callback owns credentials; this service sends none to the file server. Downloads require HTTPS, reject redirects, and share the query deadline. An explicit loopback HTTP setting exists only for local fixtures. A failed query, download, digest or compatibility check discards the candidate and keeps the current version. A `builtin` assignment retains an already installed remote version; a fresh installation uses the packaged template. Lower assigned versions are accepted for rollback.
59
+
60
+ The [manual workflow](../../.github/workflows/release-agent-config.yml) requires `candidate_sha`, `workspace_kind` and `version`, with default-true `dry_run`. Use the full lowercase 40-hex approved source commit for `candidate_sha`; branch and tag names are rejected. The workflow checks out that commit and requires actual HEAD equality and membership in master history before running candidate scripts. Select master as the workflow ref (`--ref master` for CLI dispatch); the candidate source is selected independently. The product registration [agent-configs.json](../agent-configs.json) lists each kind's sources. From the repository root, build the consumer assets, then pack:
61
+
62
+ ```sh
63
+ pnpm --dir product --filter @gestaltrun/dsh-cs-hosting run build:cli
64
+ node product/scripts/agent-config.mjs --kind cs-hosting --version 2.0.0+build.1 --out product/dist/agent-config
65
+ ```
66
+
67
+ The separate `source-receipt.json` artifact records `candidateSha`, actual `sourceCommit`, `workflowSha`, `workflowRef`, `runId` and `runAttempt` with `schemaVersion: 1`. The job summary repeats this receipt; job outputs expose `source_commit` and JSON `source_receipt`. It does not change `server-registration.json`.
68
+
69
+ The workflow uses the existing `desktop-release` environment, Alibaba OIDC role and `DESKTOP_RELEASE_*` OSS variables. It uploads an immutable object with a forbid-overwrite header, verifies metadata afterward and outputs `server-registration.json`: kind, version, SHA-256, size, compatibility range, OSS address and HTTPS download URL. Dry-run produces the same registration plan without accessing OSS. Add release notes and these fields to the server's reviewed agent-configage rules, merge that PR, then run its approved ops-job synchronization. Register a validated `^2.0.0` package before upgrading its Host consumer, and retain API 1 registrations for old clients. Assignment changes select the next permitted turn's version; assigning an older compatible API 2 version rolls back. The query does not send the Host API version, so mixed client generations need coordinated assignment groups; the range prevents adoption, not descriptor delivery or downloading. The server owns rule validation and rollout, as [R3a](https://github.com/gestaltrun/gestalt-travel-server/issues/86) specifies.
70
+
71
+ `recordWorkspaceAgentConfigVersion(session, version)` writes `workspace-bundle/agent-config-version` on the first step using a different version. Its data records kind, full version, previous version, template digest, package digest (null for repository templates) and Host Agent configuration API. The event contains no URL or credential. Model prompts remain logged as `system/message`; skills and CLI results remain logged tool results. This required-on-read event needs a Session core that registers its name. An older reader refuses it rather than reconstructing incomplete history.
72
+
73
+ Known limitations: version caches are retained and need operator-owned disk management; POSIX read-only modes are not a Windows ACL security policy. All affected turns must use leases, so one busy Session can delay a shared Workspace update. This interface updates content only; it does not hot-load Host authorization code or promise new Host commands. The [customer-service consumer](../cs-hosting/README.md#template) retains its released API 1 projection alongside the shared module source snapshot. The publication guard rejects CI pre-releases by default.
74
+
75
+ `sandboxAgentConfigHostObservation` requires an explicit `sandbox` identity for cloud-only registration; its named export prevents older packages from ignoring cloud settings. Before each cycle it verifies the configured sandbox and instance against the authenticated readback, then registers with the returned binding and exact CAS counters; conflicting runs stop. Cloud reporting ignores installation activation and replacement events. Its `blockingFailure` names the committed content and admission error independently of the latest candidate refusal; only successful execution validation clears it. Installation reports retain their existing fields.
76
+
77
+ A source may supply an `observation` factory bound to its actual committed state. The shared module reporter authenticates registration and periodic reports independently of task or customer-service leases. It persists the exact boot/request/sequence bodies under a cross-process file lock before transport, replays pending bodies after restart, and stops a conflicting run without guessing a generation. A generation conflict on a report from an earlier run, or from a run whose server-returned holder is a sandbox, discards that report and registers a new boot with the persisted generation under the same file lock. An unbound sandbox session keeps the exact pending request for the next cycle. Only the server response determines the holder. Reports include current/pending versions, blocked state and exact refused version/digest; they contain no source paths or credentials. Source disposal stops scheduling, aborts transport and awaits file and request completion. The paired module wire sources retain their CI source identity in `src/agent-config-contract/SNAPSHOT.json`; the released customer-service v1 projection remains separate.
78
+
79
+ ## Configuration
80
+
81
+ The row requires absolute `materializeRoot`, `templateCacheRoot`, and `journalRoot`. `quiesceTimeoutMs` (1000–600000, default 30000) and `recycleTimeoutMs` (0–600000, default 60000) are bounded. Content settings are `agentConfigPollIntervalMs` (1000–86400000, default 300000), `agentConfigRequestTimeoutMs` (100–600000, default 30000), `agentConfigMaxDownloadBytes` (1024–268435456, default 67108864), `agentConfigMaxExpandedBytes` (1024–536870912, default 134217728), and `allowLoopbackAgentConfigHttp` (default false). Missing or relative roots fail plugin load with `WorkspaceBundlesConfigError`.
82
+
83
+ ## Model Experience
84
+
85
+ The service is Host-only. It does not register model tools. Bundled Workspaces keep ordinary browse, search, and New Session from inheriting them through Workspace origin, not through this package's prompt text.
86
+
87
+ ## Dev Note
88
+
89
+ Historical customer-service compatibility acceptance uses [isolated API 1 components and real archives](tests/README.md).
90
+
91
+ Customer-service hosting is the first consumer. The template files live in [`product/cs-hosting/template`](../cs-hosting/template) and record teamwork commit `9e6c536f2`.
92
+
93
+ No runtime invariant companion is published: the package owns no relationship between independent observations.
package/README.zh.md ADDED
@@ -0,0 +1,93 @@
1
+ ---
2
+ description: "WorkspaceBundles 服务定义与 Provider:打包模板、稳定隐藏工作区与整树升级。"
3
+ kind: "package-plugin"
4
+ ---
5
+
6
+ # @gestaltrun/dsh-workspace-bundle
7
+
8
+ [English](README.md) | 中文
9
+
10
+ ## Summary
11
+
12
+ 本包定义 Host-only 的 `WorkspaceBundles` 服务(`ctx.workspaceBundles`)。产品插件注册打包模板;`ensure` 物化带 bundle origin 的稳定工作区,升级则整体替换目录树。普通工作区视图对该 origin 保持为空。Desktop 在 `DESKTOP_PLATFORM_PACKAGE_SOURCES` 中列出它。它以 `publishConfig.access` 为 `public`、dist-tag 为 `candidate` 发布。它不是 profile bundle,也没有 cordis patch。设计见[客服托管方案](../../.agents/design/cs-hosting/scheme.zh.md)。
13
+
14
+ ## Table of Contents
15
+
16
+ - [Service contract](#service-contract)
17
+ - [Template digest](#template-digest)
18
+ - [Upgrade and recovery](#upgrade-and-recovery)
19
+ - [Agent configurations](#agent-configurations)
20
+ - [Configuration](#configuration)
21
+ - [Model Experience](#model-experience)
22
+ - [Dev Note](#dev-note)
23
+
24
+ ## Service contract
25
+
26
+ `register(template)` 是 effect:返回的 disposer 禁止之后对该身份 `ensure` 和 `acquire`。`ensure({ bundleId, workspaceKey })` 校验模板、写入 staging 树,并注册 `origin` 为 `{ kind: 'bundle', bundleId, workspaceKey }` 的工作区。重复调用复用同一 Workspace id 与路径。`acquire(workspaceId)` 持有租约,推迟升级静止。`acquireAgentConfig(identity)` 在同一串行操作中采用、校验内容并取得租约。返回的句柄携带 Workspace id、已校验来源目录、完整版本、归档 SHA-256(仓库模板为 null)和模板摘要。`retain()` 同步延长同一选择供另一个消费者使用;每个句柄在活动和持久化完成后释放一次。释放父句柄不影响仍持有句柄的消费者。Provider 卸载等待这些句柄和排队的获取操作结束。`record(identity)` 返回持久产品记录。`pathOf(identity)` 是由 `materializeRoot` 与身份段得到的绝对物化目录,不要求先 `ensure`。
27
+
28
+ 这是能力包,不声明可安装 bundle patch。
29
+
30
+ ## Template digest
31
+
32
+ 打包的 `manifest.json` 列出每个文件的 SHA-256 以及按序目录的整体摘要。物化拒绝符号链接、越界路径、缺失资产、多余文件和摘要不匹配。`templateCacheRoot` 下的不可变副本供包源目录不可用时恢复校验。
33
+
34
+ ## Upgrade and recovery
35
+
36
+ 替换顺序为 staging → `updating` journal → 租约静止 → 将现根改名为 backup、将 staging 改名为稳定根 → 校验 → 提交。交换或提交点崩溃后恢复为完整旧树或完整新树;Workspace id 与路径不变。journal 为 `updating` 时消费者被屏障拦住。
37
+
38
+ 替换已有目录树前,Provider 在持久 `updating` 屏障下等待串行 `workspace-bundle/quiesce` 事件。消费方在监听器中取消活动、等待完成并释放租约。监听器失败时保留 journal 供恢复,并阻止目录替换。
39
+
40
+ ## Agent configurations
41
+
42
+ `BundledAgentConfigReceiptSchema` 和 `BundledAgentConfigReceipt` 定义随包模板旁的发布回执:`<template-directory>.agent-config.json`。它记录格式版本 1、工作区种类、完整发布版本、gzip SHA-256 与大小、Host 兼容范围、可选运行接口范围和模板摘要,不包含 URL、凭据或发布说明。`loadBundledAgentConfigSync(template)` 向已校验模板附加回执和 `agentConfigSha256`;回执不存在时返回原模板,回执不可读、无效或不匹配时抛出 `AGENT_CONFIG_INVALID`。旁置文件不进入模板清单或模型输入。
43
+
44
+ 随包发布配置的句柄、Session 版本事件和观测使用回执中的 SHA-256。其 journal 包摘要保持 null,因此换装后在下一次 acquire 选用新安装包的模板。随包内容不进入远端版本缓存;相同摘要的分配不触发下载或候选。已下载内容保留实际 journal 摘要及缓存,即使其字节与注册模板相同。
45
+
46
+ 可选模块上报器在收到 `409 LOCAL_HOST_REPLACED` 后公开 `replaced` 状态。`WorkspaceBundles.localHostReplacement` 在 `journalRoot/local-host-replacement.json` 中保存共享的成员停止标记;键包含服务端、成员与店铺,不含安装身份或模块身份。上报器、租约和检查点读取同一状态。函数形式的 `hostId` 提供当前安装身份。绑定变化会取消并等待旧运行结束,但不会解除该成员的停止状态。明确启用会先登记全部已组合的本地模块并确认它们的上报,再清除停止标记;未完成的启用保持停止。旧的按安装身份保存的标记会先导入成员状态,再允许新身份登记。停止状态使用原子替换写入,并对 Windows 临时失败有限重试。写入失败时,保留内存状态和模块文件中的停止标记;后续标记操作重试保存,重启时即使此前已迁移,也会检查模块停止标记。其他失败保留既有重试或冲突处理。
47
+
48
+ `WorkspaceBundles.localHostIdentity` 在 `journalRoot/local-host-identity.json` 中按服务端和成员保存一个本地 Host 身份,同一安装上的所有本地模块用这个身份上报。持有安装身份的模块发布该身份;`sharedLocalHostId(ctx, fallback)` 为其他模块的上报器提供这个身份,尚未发布时使用该模块自己的身份。发布按顺序执行,在提交时读取持有模块的当前身份,原子写入成功后才对读取方可见。已确认的身份不会被替换,所以上报器不会回到已被服务端替换的身份。该文件同步加载;文件无法读取或格式无效时,插件加载失败。
49
+
50
+ `registerAgentConfigSource({ identity, revision, query, validate?, observation? })` 为已注册模板添加鉴权分配查询,返回取消并等待工作结束的异步 disposer。启动时先恢复并验证该 identity 的已提交 journal,再启动 reporter 和分配查询,空闲 Host 也执行此恢复。配置间隔轮询准备候选。已提交配置被阻断且工作区没有活动租约时,轮询原子采用已验证候选并重新检查执行许可;有效的已提交配置等待下一次获取工作区。`agentConfig(identity)` 提供已应用版本、候选和固定失败诊断;`refreshAgentConfig(identity)` 等待一次查询和下载。`ensure` 和 `acquire` 只在工作区没有租约时应用候选。消费者必须在 turn 开始前获取租约,保持到 turn 结束。现有替换 journal 保持 Workspace id 和路径稳定。此接口不会为了远端Agent 配置更新取消正在运行的 turn。
51
+
52
+ 包格式为确定性 gzip JSON,包含 `manifest` 和 `files`。清单有 `formatVersion: 1`、`workspaceKind`、完整 SemVer `version`、`hostAgentConfigApiRange`,以及按路径排序、包含 `path`、`sizeBytes`、`sha256` 的 `files`。并行文件数组保存对应 `path` 和规范 `base64`。Gzip 元数据不含时间戳或主机身份。包含构建元数据的完整版本(如 `1.0.0+build.42`)区分不同包;构建元数据不参与 SemVer 优先级比较。Host Agent 配置接口为 `2.0.0`;兼容的客服归档声明 `^2.0.0`。完整压缩字节、文件大小和摘要都通过校验后,才发布候选目录。链接、路径越界、大小写冲突、保留名称、重复文件和解压超限均被拒绝。
53
+
54
+ 可选的 `validate(template, signal)` 回调负责 consumer 校验;省略时只执行通用归档校验。候选发布、采用和恢复后允许执行前均须通过。中断 swap 先恢复完整树,再判定执行许可。不兼容或损坏的已提交缓存设置 `blocked: true`;`current` 只供诊断,新租约与客服 CLI 调用被拒绝,默认诊断说明自动客服阻断及兼容替换。旧缓存和 Workspace 身份保留;兼容候选可原子修复同一 Workspace,`builtin` 不能绕过阻断。
55
+
56
+ `agentConfig(identity).lastRejection` 以固定码、可选的完整版本和 SHA-256 暴露最近一次同作用域拒绝,保留构建元数据。查询失败保留该拒绝;`AGENT_CONFIG_QUERY_FAILED` 和 `AGENT_CONFIG_SCOPE_CHANGED` 永不创建拒绝。选中不同的已验证分配、匹配校验或提交成功、作用域 revision 改变以及卸载时清除适用拒绝,旧作用域迟到结果不能恢复它。恢复时被阻断的缓存上报已知的已提交版本;`blocked` 与候选校验独立。该观测只在进程内保存,重启后由正常校验重建。
57
+
58
+ 下载目录为 `templateCacheRoot/agent-config-versions/{bundleId}/{workspaceKey}/{sha256}/{version}`,文件和版本目录只读。已提交 journal 保存完整版本和包摘要,因此模板字节相同的不同版本在重启后仍可区分。来源代次随鉴权分配身份改变;变更会取消并等待旧查询/下载、清除未提交候选并查询新身份,发布和替换时再次核对。查询回调持有凭据,本服务不向文件服务器发送凭据。下载要求 HTTPS、拒绝跳转,与查询共享超时;只有显式配置的本地 fixture 可用 loopback HTTP。查询、下载、摘要或兼容性失败都会丢弃候选并保留当前版本。`builtin` 分配保留已安装的远端版本;首次安装使用打包模板。允许分配低版本以回退。
59
+
60
+ [手动工作流](../../.github/workflows/release-agent-config.yml) 要求 `candidate_sha`、`workspace_kind`、`version`,`dry_run` 默认 true。`candidate_sha` 必须是已批准源码提交的完整 40 位小写十六进制 SHA,分支名和 tag 名会被拒绝。工作流 checkout 该提交,运行候选脚本前核对实际 HEAD 完全相等且提交位于 master 历史。工作流 ref 选择 master(CLI dispatch 使用 `--ref master`);候选源码单独选择。[agent-configs.json](../agent-configs.json) 登记各类来源。在仓库根目录先构建消费者资源,再打包:
61
+
62
+ ```sh
63
+ pnpm --dir product --filter @gestaltrun/dsh-cs-hosting run build:cli
64
+ node product/scripts/agent-config.mjs --kind cs-hosting --version 2.0.0+build.1 --out product/dist/agent-config
65
+ ```
66
+
67
+ 独立的 `source-receipt.json` artifact 记录 `candidateSha`、实际 `sourceCommit`、`workflowSha`、`workflowRef`、`runId`、`runAttempt` 和 `schemaVersion: 1`。job summary 同步展示回执;job outputs 提供 `source_commit` 和 JSON `source_receipt`。此回执不改变 `server-registration.json`。
68
+
69
+ 工作流沿用 `desktop-release` environment、阿里云 OIDC 角色和 `DESKTOP_RELEASE_*` OSS 变量。上传使用禁止覆盖标记,上传后回读元数据,输出 `server-registration.json`:种类、版本、SHA-256、大小、兼容范围、OSS 地址和 HTTPS 下载地址。Dry-run 生成同样的登记计划,不访问 OSS。将这些字段和发布说明写入 server 的 Agent 配置规则文件,经 PR 审阅合入后执行其经审批的 ops-job 同步任务。升级 Host consumer 前先登记已校验的 `^2.0.0` 包,并为旧客户端保留 API 1 登记。修改分配决定下一次允许采用的 turn 版本;分配较旧但兼容的 API 2 版本即可回退。查询不发送 Host API 版本,混合客户端代次需要协调分配组;范围检查保证不采用,不保证 server 不返回 descriptor 或不下载。规则校验和灰度由 server 持有,参见 [R3a](https://github.com/gestaltrun/gestalt-travel-server/issues/86)。
70
+
71
+ `recordWorkspaceAgentConfigVersion(session, version)` 在首次使用一个不同版本的 step 写入 `workspace-bundle/agent-config-version`。数据包含种类、完整版本、前一版本、模板摘要、包摘要(仓库模板为 null)和 Host Agent 配置接口。事件不含地址或凭据。模型提示词仍记录为 `system/message`,skills 和 CLI 结果仍记录为工具结果。这个必读事件需要 Session core 登记名称;旧 reader 会拒绝它,不会重建不完整历史。
72
+
73
+ 已知限制:版本缓存保留,需要操作员管理磁盘;POSIX 只读权限不是 Windows ACL 安全策略。所有涉及的 turn 都必须持有租约,因此忙碌的 Session 会延迟共享工作区更新。此接口只更新内容,不热加载 Host 授权代码,也不承诺新增 Host 命令。[客服托管消费者](../cs-hosting/README.zh.md#template) 在共享模块源码快照之外保留已发布的 API 1 投影。发布守卫默认拒绝 CI 预发行版本。
74
+
75
+ `sandboxAgentConfigHostObservation` 要求显式 `sandbox` 身份,专用于云端注册;独立命名导出使旧包不能忽略云端配置后继续运行。每轮先用鉴权读回核对配置中的沙箱与实例,再携带返回的绑定和精确 CAS 计数注册;冲突运行停止。云端报告不处理安装激活和 replacement 事件。`blockingFailure` 独立记录已提交内容及其准入错误,不受最新候选拒绝影响;只有执行校验成功后才清除。本机报告保留原有字段。
76
+
77
+ 来源可提供绑定实际已提交状态的 `observation` 工厂。共享模块 reporter 独立于任务或客服租约鉴权登记并定时上报,在跨进程文件锁内先持久化确切 boot/request/sequence 请求体,再发起传输;重启后重放 pending 请求体,冲突 run 停止且不猜测代次。早先 run 的报告,或服务端返回 holder 为 sandbox 的 run 的报告,遇到代次冲突时丢弃该报告,并在同一个文件锁内用新的 boot 和已持久化的代次重新登记。sandbox 会话尚未绑定时,保留确切的 pending 请求,到下一周期重试。holder 只取服务端响应。报告包含 current/pending 版本、blocked 状态及被拒绝版本和摘要,不含来源路径或凭据。来源卸载先停止调度、取消传输,再等待文件与请求完成。模块 wire 源码在 `src/agent-config-contract/SNAPSHOT.json` 保留其 CI 来源身份;已发布的客服 v1 投影独立保留。
78
+
79
+ ## Configuration
80
+
81
+ 该行要求绝对路径 `materializeRoot`、`templateCacheRoot` 和 `journalRoot`。`quiesceTimeoutMs`(1000–600000,默认 30000)和 `recycleTimeoutMs`(0–600000,默认 60000)有上下界。内容配置包括 `agentConfigPollIntervalMs`(1000–86400000,默认 300000)、`agentConfigRequestTimeoutMs`(100–600000,默认 30000)、`agentConfigMaxDownloadBytes`(1024–268435456,默认 67108864)、`agentConfigMaxExpandedBytes`(1024–536870912,默认 134217728)以及 `allowLoopbackAgentConfigHttp`(默认 false)。缺失或相对路径会以 `WorkspaceBundlesConfigError` 使插件加载失败。
82
+
83
+ ## Model Experience
84
+
85
+ 本服务仅 Host 使用,不注册模型工具。内置工作区通过 Workspace origin 从普通浏览、搜索和「新会话」继承中隐藏,而不是靠本包的提示词。
86
+
87
+ ## Dev Note
88
+
89
+ 历史客服兼容验收使用[隔离 API 1 组件与真实归档](tests/README.zh.md)。
90
+
91
+ 客服托管是第一个消费者。模板文件在 [`product/cs-hosting/template`](../cs-hosting/template),来源记录 teamwork 提交 `9e6c536f2`。
92
+
93
+ 不发布运行时不变量配套包:本包不持有独立观察之间的关系。