relay-dsh-plugin-manager 0.1.0-rc.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/CHANGELOG.md +17 -0
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/SPEC.md +85 -0
- package/cordis.patch.yml +5 -0
- package/docs/acceptance/live-codex-2026-08-26.md +67 -0
- package/docs/acceptance/release-candidate-2026-08-26.md +51 -0
- package/docs/acceptance.md +81 -0
- package/docs/releasing.md +46 -0
- package/docs/technical-design.md +153 -0
- package/lib/errors-BGx4K2uq.js +18 -0
- package/lib/errors-BGx4K2uq.js.map +1 -0
- package/lib/index.d.ts +269 -0
- package/lib/index.js +1621 -0
- package/lib/index.js.map +1 -0
- package/lib/search-runtime-Be3SS1k2.d.ts +72 -0
- package/lib/search-runtime.d.ts +2 -0
- package/lib/search-runtime.js +30 -0
- package/lib/search-runtime.js.map +1 -0
- package/package.json +110 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
## [0.1.0-rc.1] - 2026-08-26
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Conversation-first DSH plugin discovery and lifecycle management.
|
|
10
|
+
- One `/plugins` command and two model tools.
|
|
11
|
+
- npm and GitHub discovery with immutable install-source resolution.
|
|
12
|
+
- Confirmed install, remove, update, enable, disable, and restart operations.
|
|
13
|
+
- Loader HMR verification, restart fallbacks, rollback, and operation tracking.
|
|
14
|
+
- Versioned search-provider extension registry.
|
|
15
|
+
- Unit, integration, package E2E, and opt-in live Codex acceptance coverage.
|
|
16
|
+
|
|
17
|
+
[0.1.0-rc.1]: https://github.com/yangbobo2021/relay-dsh-plugin-manager/releases/tag/v0.1.0-rc.1
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 yangbobo2021 and Relay contributors
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Relay DSH Plugin Manager
|
|
2
|
+
|
|
3
|
+
Conversation-first plugin discovery and lifecycle management for the DeepSeek
|
|
4
|
+
Harness `web` profile. The package has no settings UI and registers no public
|
|
5
|
+
management HTTP routes.
|
|
6
|
+
|
|
7
|
+
## Conversation Surface
|
|
8
|
+
|
|
9
|
+
The bundle contributes one human command and two model tools:
|
|
10
|
+
|
|
11
|
+
- `/plugins [request]` sends the request to the current Agent;
|
|
12
|
+
- `plugin_discover` lists, searches, inspects, and reports status;
|
|
13
|
+
- `plugin_manage` plans, executes, polls, and cancels mutations.
|
|
14
|
+
|
|
15
|
+
Ordinary natural-language requests use the same tools. Every install, update,
|
|
16
|
+
remove, enable, disable, or restart is a two-stage operation: the Agent first
|
|
17
|
+
shows a plan, then uses its one-use token only after a later explicit user
|
|
18
|
+
confirmation. The token is bound to that DSH conversation, and same-turn or
|
|
19
|
+
cross-conversation execution is rejected in code.
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
|
|
23
|
+
```text
|
|
24
|
+
/plugins 找一个能连接飞书的插件
|
|
25
|
+
/plugins 安装 example-dsh-plugin
|
|
26
|
+
卸载 example-dsh-plugin
|
|
27
|
+
列出当前插件以及是否需要重启
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Install with the DSH instance that will run the profile:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
dsh plugin --profile web add --save-exact relay-dsh-plugin-manager@0.1.0-rc.1
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The official DSH command adds the package to profile dependencies and mounts
|
|
39
|
+
both bundle rows. Restart DSH after the manager itself is first installed.
|
|
40
|
+
|
|
41
|
+
## Behavior
|
|
42
|
+
|
|
43
|
+
- npm sources resolve to an exact version and SHA-512 registry integrity.
|
|
44
|
+
- GitHub sources resolve to a full commit before execution.
|
|
45
|
+
- Package mutations call the current official DSH CLI with argv arrays.
|
|
46
|
+
- New simple insert-only bundles may activate without restart; complex bundles
|
|
47
|
+
and updates report `restartRequired`.
|
|
48
|
+
- Enable/disable owns only exact Loader override rows written by this manager.
|
|
49
|
+
- Disabling a plugin used by the current conversation can interrupt that turn;
|
|
50
|
+
use another backend or Session when continuity matters.
|
|
51
|
+
- Mutations are serialized, cancellable, and retain pollable terminal status.
|
|
52
|
+
- Automatic restart is a separate confirmed operation and is disabled for a
|
|
53
|
+
detected systemd main process unless explicitly configured.
|
|
54
|
+
|
|
55
|
+
Set `allowRestart: false` on the `relay-plugin-manager-host` bundle row to
|
|
56
|
+
disable automatic restart in other deployments as well.
|
|
57
|
+
|
|
58
|
+
## Search Extensions
|
|
59
|
+
|
|
60
|
+
Installed Host plugins can inject `pluginSearch`, require `apiVersion === 1`,
|
|
61
|
+
and register a provider:
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
export const inject = ['pluginSearch']
|
|
65
|
+
|
|
66
|
+
export function apply(ctx) {
|
|
67
|
+
ctx.pluginSearch.register({
|
|
68
|
+
id: 'internal-catalog',
|
|
69
|
+
async search({ query, maxResults, signal }) {
|
|
70
|
+
return lookupCatalog(query, { maxResults, signal })
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Providers return npm/GitHub candidates only. Core inspection, immutable source
|
|
77
|
+
resolution, confirmation, installation, rollback, and activation are not
|
|
78
|
+
extension points.
|
|
79
|
+
|
|
80
|
+
## Verification
|
|
81
|
+
|
|
82
|
+
```sh
|
|
83
|
+
npm ci --ignore-scripts
|
|
84
|
+
npm run verify
|
|
85
|
+
npm run acceptance:live:codex
|
|
86
|
+
npm run release:dry-run
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`verify` runs type checking, unit/integration tests, the production build, and
|
|
90
|
+
a local package E2E that installs the tarball through the immutable official
|
|
91
|
+
DSH checkout. The live command additionally uses the public npm/GitHub services
|
|
92
|
+
and the real `relay-dsh-plugin-codex` package. The RC dry run uses npm's
|
|
93
|
+
`next` dist-tag. See [SPEC.md](./SPEC.md) and
|
|
94
|
+
[docs/acceptance.md](./docs/acceptance.md) for the release contract and
|
|
95
|
+
traceability matrix. The current real-session release record is
|
|
96
|
+
[docs/acceptance/release-candidate-2026-08-26.md](./docs/acceptance/release-candidate-2026-08-26.md).
|
|
97
|
+
Tag-triggered npm publication is defined in
|
|
98
|
+
[docs/releasing.md](./docs/releasing.md).
|
|
99
|
+
|
|
100
|
+
## Repository Boundary
|
|
101
|
+
|
|
102
|
+
This is an independently installable package. It imports no Relay parent or
|
|
103
|
+
KeySync implementation code. The local KeySync prototype handoff was used as
|
|
104
|
+
reference material and is intentionally excluded from both git and the npm
|
|
105
|
+
package.
|
package/SPEC.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Relay DSH Plugin Manager Specification
|
|
2
|
+
|
|
3
|
+
Status: implementation contract
|
|
4
|
+
Target package: `relay-dsh-plugin-manager`
|
|
5
|
+
Target profile: the running `web` profile
|
|
6
|
+
|
|
7
|
+
## Product Contract
|
|
8
|
+
|
|
9
|
+
Relay DSH Plugin Manager is a conversation-first, independently installable
|
|
10
|
+
DeepSeek Harness bundle. It discovers and manages DSH profile plugins without a
|
|
11
|
+
management UI or public management HTTP routes.
|
|
12
|
+
|
|
13
|
+
The user may enter `/plugins <request>` or describe the same request in ordinary
|
|
14
|
+
conversation. Both paths use the same model-facing tools and Host management
|
|
15
|
+
service.
|
|
16
|
+
|
|
17
|
+
## Requirements
|
|
18
|
+
|
|
19
|
+
| ID | Requirement |
|
|
20
|
+
|---|---|
|
|
21
|
+
| PM-001 | Register exactly one human command, `/plugins [request]`. It submits the request to the receiving Agent; it does not implement a second command-only management path. |
|
|
22
|
+
| PM-002 | Keep the model surface compact: one discovery tool and one management tool. Natural-language and slash-command requests use these tools. |
|
|
23
|
+
| PM-003 | List profile dependencies with installed source, bundle membership, package-level enablement, runtime phase, and pending-restart state. |
|
|
24
|
+
| PM-004 | Provide a versioned `ctx.pluginSearch` registry. Other installed plugins may register abortable search providers. Providers discover candidates only and cannot install or mutate the profile. |
|
|
25
|
+
| PM-005 | Search all registered providers concurrently with bounded results, timeout/cancellation, provenance, provider-error isolation, and repository/package-identity deduplication. |
|
|
26
|
+
| PM-006 | Ship npm and GitHub search providers. Preserve a syntactically valid exact npm package-name query even when npm search ranking omits it. Search results are inspected before being reported as installable DSH plugins. |
|
|
27
|
+
| PM-007 | Accept only core-owned npm and GitHub install-source types. Resolve npm to an exact semantic version with registry integrity and GitHub to a full 40-character commit. |
|
|
28
|
+
| PM-008 | Inspect the resolved package manifest and require a valid package name plus a DSH surface (`dsh.bundle.patch` or `dsh.client`). Search providers cannot bypass this validation. |
|
|
29
|
+
| PM-009 | Every install, remove, update, enable, disable, or restart starts with an immutable plan. A later execute call requires the unexpired, one-use confirmation token returned by that plan. The token is bound to the planning DSH Session and cannot execute until that Session contains a newer user message; the original request is mechanically not confirmation. Execution also refuses a stale plan when the target profile dependency changed after planning. |
|
|
30
|
+
| PM-010 | Install and update through argv-only invocation of the currently running DSH CLI: `dsh plugin --profile web add --save-exact <immutable-source>`. Never build a shell command string. |
|
|
31
|
+
| PM-011 | Remove through argv-only `dsh plugin --profile web remove <package>`. Verify dependency and bundle postconditions and reconcile a half-removed profile conservatively. |
|
|
32
|
+
| PM-012 | Enable and disable are package-level projections over owned Cordis Loader entries. Persist manager-owned `disabled` overrides in the profile patch, report `mixed` or `unknown` when ownership is not safely reducible, and never disable the manager itself or protected DSH infrastructure. A disable plan warns that conversations using the target plugin may be interrupted. |
|
|
33
|
+
| PM-013 | Attempt restart-free activation for newly installed client-only packages and bundles whose patches contain only plain insert rows. Attempt live disposal for removals. Otherwise report `restartRequired` with a concrete reason. |
|
|
34
|
+
| PM-014 | Enable/disable changes use Loader HMR and normally require no restart. A failed or unverifiable live transition reports pending restart rather than claiming success. |
|
|
35
|
+
| PM-015 | Mutations run as tracked operations with stable ids, progress snapshots, terminal exit state, cooperative cancellation, and one active mutation at a time. |
|
|
36
|
+
| PM-016 | Restart is a separately planned operation. When allowed, relaunch the exact current DSH entry/argv/environment through a detached helper, then stop the old process. Refuse automatic restart under a detected service supervisor or explicit disable setting. |
|
|
37
|
+
| PM-017 | Snapshot the profile manifest before package mutations. Restore failed install/update manifest residue; detect and reconcile a remove that deleted package files before pnpm failed. Never report success before dependency source, installed package identity/version, DSH surface, and bundle-membership postconditions pass. |
|
|
38
|
+
| PM-018 | Reject unsafe source tokens, flags, whitespace/control characters, shell metacharacters, unsupported URL hosts, ambiguous package names, and mutable execution sources. Build scripts remain governed by pnpm/DSH and are never silently authorized. |
|
|
39
|
+
| PM-019 | Expose no public plugin-management HTTP routes and impose no client-address, Origin, CORS, or loopback policy. The callable surface is the in-process DSH command/tool plane. |
|
|
40
|
+
| PM-020 | Remain independently installable. Do not import Relay parent implementation code or KeySync implementation code. Runtime interactions use DSH/Cordis public services and the official CLI. |
|
|
41
|
+
|
|
42
|
+
## Command Grammar
|
|
43
|
+
|
|
44
|
+
Only `/plugins` is registered.
|
|
45
|
+
|
|
46
|
+
- `/plugins` submits a request to list installed plugins.
|
|
47
|
+
- `/plugins <text>` submits `<text>` as a plugin-management request.
|
|
48
|
+
- The command does not parse install/remove synonyms. The Agent interprets the
|
|
49
|
+
same natural language that it would receive without the slash command.
|
|
50
|
+
|
|
51
|
+
This keeps command discovery and persistent prompt cost small while avoiding
|
|
52
|
+
behavior drift between direct commands and conversation.
|
|
53
|
+
|
|
54
|
+
## Model Tool Contract
|
|
55
|
+
|
|
56
|
+
### `plugin_discover`
|
|
57
|
+
|
|
58
|
+
Read-only actions: `list`, `search`, `inspect`, `status`.
|
|
59
|
+
|
|
60
|
+
### `plugin_manage`
|
|
61
|
+
|
|
62
|
+
State-changing workflow actions: `plan`, `execute`, `status`, `cancel`.
|
|
63
|
+
`plan` carries one operation from `install`, `remove`, `update`, `enable`,
|
|
64
|
+
`disable`, or `restart`. `execute` accepts only a confirmation token.
|
|
65
|
+
|
|
66
|
+
## Search Extension Contract
|
|
67
|
+
|
|
68
|
+
A search provider registers a stable id and an abortable `search()` function.
|
|
69
|
+
It returns typed npm/GitHub candidates with provenance and optional local score.
|
|
70
|
+
The manager owns inspection, immutable resolution, deduplication, ranking,
|
|
71
|
+
confirmation, installation, rollback, activation, and restart.
|
|
72
|
+
|
|
73
|
+
Provider scores are not globally comparable. The manager uses them only within
|
|
74
|
+
one provider before deterministic cross-provider ordering.
|
|
75
|
+
|
|
76
|
+
## Explicit Non-Goals
|
|
77
|
+
|
|
78
|
+
- Settings page, dashboard, or any other management UI.
|
|
79
|
+
- Public management REST/HTTP endpoints.
|
|
80
|
+
- Provider-defined installers, shell commands, or arbitrary pnpm arguments.
|
|
81
|
+
- Arbitrary tarball, filesystem, SSH Git, or non-GitHub Git installation in the
|
|
82
|
+
first release.
|
|
83
|
+
- Automatic mutation based only on a search query.
|
|
84
|
+
- Automatic restart as part of install/update/remove.
|
|
85
|
+
- Managing profiles other than the running `web` profile in the first release.
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Live Codex Plugin Acceptance - 2026-08-26
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
Opt-in live-network acceptance of `relay-dsh-plugin-codex` through the plugin
|
|
6
|
+
manager implementation. The run used two fresh temporary `DSH_HOME` roots and
|
|
7
|
+
the immutable official DSH checkout. Both temporary roots were removed after
|
|
8
|
+
the run.
|
|
9
|
+
|
|
10
|
+
Command:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npm run acceptance:live:codex
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Environment
|
|
17
|
+
|
|
18
|
+
| Item | Value |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Date/time zone | 2026-08-26, Asia/Shanghai |
|
|
21
|
+
| Node | `v25.5.0` |
|
|
22
|
+
| npm | `11.8.0` |
|
|
23
|
+
| pnpm | `11.19.0` |
|
|
24
|
+
| Official DSH commit | `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e` |
|
|
25
|
+
| Codex plugin repository commit | `56324ecd9f2df4c172af2967fb347517d0770270` |
|
|
26
|
+
|
|
27
|
+
The Codex plugin checkout was clean after acceptance. The official DSH checkout
|
|
28
|
+
retained its pre-existing untracked development symlink
|
|
29
|
+
`packages/core/tools/dsh-tools` (created 2026-08-25); the acceptance did not
|
|
30
|
+
create or modify it.
|
|
31
|
+
|
|
32
|
+
## Source Evidence
|
|
33
|
+
|
|
34
|
+
| Source | Resolved immutable value |
|
|
35
|
+
|---|---|
|
|
36
|
+
| npm | `relay-dsh-plugin-codex@0.1.2` |
|
|
37
|
+
| npm integrity | `sha512-UD3Ud3zTsxRY/0ZlLsAqbAopXb7fPY5zXjefMRWsAqG+wBaZMNSrYd5XpI453xBe8M/KdNFdae+Ha3HNI+aQ4w==` |
|
|
38
|
+
| GitHub | `github:yangbobo2021/relay-dsh-plugin-codex#56324ecd9f2df4c172af2967fb347517d0770270` |
|
|
39
|
+
|
|
40
|
+
The real search result merged npm and GitHub provenance into one candidate and
|
|
41
|
+
recommended the exact npm source. Initial execution exposed that npm Registry
|
|
42
|
+
ranking omitted the exact package from the bounded keyword result; PM-006 was
|
|
43
|
+
fixed so an exact valid npm package-name query remains a candidate and still
|
|
44
|
+
passes full core inspection.
|
|
45
|
+
|
|
46
|
+
## Lifecycle Evidence
|
|
47
|
+
|
|
48
|
+
| Scenario | Result |
|
|
49
|
+
|---|---|
|
|
50
|
+
| npm search and inspection | Passed; exact semver, SHA-512 integrity, repository, bundle patch |
|
|
51
|
+
| GitHub search and inspection | Passed; full 40-character commit and bundle patch |
|
|
52
|
+
| npm install through official DSH CLI | Passed; dependency, installed identity/version, DSH surface, and one bundle verified |
|
|
53
|
+
| Installed status | Passed; bundle enabled and restart required outside the booted process |
|
|
54
|
+
| `--dump-config` | Passed; `relay-codex-host` present |
|
|
55
|
+
| Real `dsh web --no-open --port 0` boot | Passed; readiness URL returned HTTP 200 |
|
|
56
|
+
| Disable | Passed; manager-owned `relay-codex-host` override persisted |
|
|
57
|
+
| Enable | Passed; only manager-owned override removed |
|
|
58
|
+
| Update | Passed; exact official add path and restart boundary verified |
|
|
59
|
+
| npm remove | Passed; dependency and bundle absent |
|
|
60
|
+
| Immutable GitHub install | Passed; exact commit dependency and bundle verified |
|
|
61
|
+
| GitHub remove | Passed; dependency and bundle absent |
|
|
62
|
+
|
|
63
|
+
The final successful RC boot URL used a random ephemeral port
|
|
64
|
+
(`http://127.0.0.1:52149`) and the process was terminated cleanly. No model
|
|
65
|
+
request, Codex conversation, or automatic DSH restart was performed in this
|
|
66
|
+
script; real conversation and Loader HMR evidence is recorded separately in
|
|
67
|
+
[`release-candidate-2026-08-26.md`](./release-candidate-2026-08-26.md).
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Release Candidate Acceptance - 2026-08-26
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
Release acceptance for `relay-dsh-plugin-manager@0.1.0-rc.1` in an isolated
|
|
6
|
+
real DSH Web profile. The manager was installed from its packed tarball and
|
|
7
|
+
`relay-dsh-plugin-codex@0.1.2` was installed from npm through the official
|
|
8
|
+
DSH CLI.
|
|
9
|
+
|
|
10
|
+
## Environment
|
|
11
|
+
|
|
12
|
+
| Item | Value |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Official DSH commit | `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e` |
|
|
15
|
+
| Codex plugin | `relay-dsh-plugin-codex@0.1.2` |
|
|
16
|
+
| Codex CLI | `0.149.0-alpha.4.3` |
|
|
17
|
+
| Codex model route | `relay-codex/gpt-5.4-mini` |
|
|
18
|
+
| Profile | fresh temporary `web` profile |
|
|
19
|
+
|
|
20
|
+
No production DSH profile or repository checkout was modified.
|
|
21
|
+
|
|
22
|
+
## Conversation Evidence
|
|
23
|
+
|
|
24
|
+
| Scenario | Result |
|
|
25
|
+
|---|---|
|
|
26
|
+
| Real Web boot | Passed; DSH returned a readiness URL and HTTP 200 |
|
|
27
|
+
| Agent preset roster | Passed; `relay-codex` was available |
|
|
28
|
+
| Compact model surface | Passed; request header contained exactly `plugin_discover` and `plugin_manage` |
|
|
29
|
+
| Slash command | Passed; `/plugins 搜索 Codex 插件` produced merged live search results |
|
|
30
|
+
| Natural language | Passed; a Chinese discovery request ran on the real Codex backend and returned inspected DSH candidates |
|
|
31
|
+
| No mutation on search | Passed |
|
|
32
|
+
| Same-turn confirmation | Passed; “disable and confirm now” produced a plan, execution was rejected, and `cordis.patch.yml` stayed byte-identical |
|
|
33
|
+
| Later confirmation | Passed; a later `确认禁用` message wrote the owned `relay-codex-host` disabled row |
|
|
34
|
+
| Loader hot unload | Passed; the Codex provider was disposed without restarting DSH |
|
|
35
|
+
| Loader hot reload | Passed; removing the temporary acceptance override restored the Codex provider without restarting DSH; a new real Codex Session replied `CODEX_HMR_OK` |
|
|
36
|
+
|
|
37
|
+
## Review Finding
|
|
38
|
+
|
|
39
|
+
Disabling the backend serving the executing conversation interrupts that turn
|
|
40
|
+
when Loader HMR disposes the provider. The profile mutation is successful and
|
|
41
|
+
DSH itself does not restart, but the conversation cannot deliver a final
|
|
42
|
+
success message from the disabled backend.
|
|
43
|
+
|
|
44
|
+
The release contract, plan output, README, technical design, and integration
|
|
45
|
+
test now warn about this behavior. Continuity-sensitive disable operations
|
|
46
|
+
should be confirmed from another backend or Session.
|
|
47
|
+
|
|
48
|
+
## Cleanup
|
|
49
|
+
|
|
50
|
+
The temporary override was removed, the Codex provider was verified live again,
|
|
51
|
+
and the temporary DSH process and profile were deleted after the release run.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Delivery Acceptance
|
|
2
|
+
|
|
3
|
+
This matrix is the release contract. Tests name the relevant `PM-*` ids.
|
|
4
|
+
|
|
5
|
+
## Scenario Matrix
|
|
6
|
+
|
|
7
|
+
| Scenario | Requirement coverage | Automated evidence |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| A-001 `/plugins` without arguments submits one list request to the receiving Agent | PM-001, PM-002 | command unit/integration |
|
|
10
|
+
| A-002 `/plugins install X` and ordinary `install X` expose the same two model tools and management workflow | PM-001, PM-002 | command/tool integration |
|
|
11
|
+
| A-003 list an empty and populated profile with bundle, enablement, runtime, and restart fields | PM-003 | profile unit + manager integration |
|
|
12
|
+
| A-004 external search provider registers, returns results, disposes, times out, fails, and cancels without breaking siblings | PM-004, PM-005 | search-registry unit |
|
|
13
|
+
| A-005 npm and GitHub search results are inspected, exact npm package names survive ranking omission, invalid bundles are dropped, aliases deduplicated, and provenance retained | PM-005, PM-006, PM-008 | provider/search integration with fake network + live Codex acceptance |
|
|
14
|
+
| A-006 npm bare name resolves to exact semver/integrity; mutable or malformed npm specs cannot execute | PM-007, PM-008, PM-018 | source unit |
|
|
15
|
+
| A-007 GitHub URL/slug resolves to a full commit; non-GitHub URLs and unsafe refs are rejected | PM-007, PM-008, PM-018 | source unit |
|
|
16
|
+
| A-008 install plan performs no mutation, returns digest/token/expiry, binds the token to its Session, and rejects same-turn/cross-session execution so the original request is not confirmation | PM-009 | plan unit + tool integration |
|
|
17
|
+
| A-009 token is one-use, expires, cannot substitute another operation, rejects stale profile state, and execution creates one tracked operation | PM-009, PM-015 | plan/operation unit + manager integration |
|
|
18
|
+
| A-010 install invokes exact official argv, verifies dependency source, installed identity/version, DSH surface, and one bundle membership, then reports hot or restart-required activation | PM-010, PM-013, PM-017 | fake-CLI integration |
|
|
19
|
+
| A-011 failed install restores manifest residue and never reports installed | PM-017 | fake-CLI integration |
|
|
20
|
+
| A-012 update resolves an immutable newer source, invokes exact add argv, verifies installed spec, and supports rollback reporting | PM-009, PM-010, PM-017 | fake-CLI integration |
|
|
21
|
+
| A-013 remove invokes exact official argv, verifies absence, live-disposes when possible, and reconciles half-removal | PM-011, PM-013, PM-017 | fake-CLI integration |
|
|
22
|
+
| A-014 disable warns about active-conversation interruption, writes only manager-owned patch rows, HMR-verifies state, survives reload, and enable removes only owned rows | PM-012, PM-014 | plan + profile/loader integration + real DSH walkthrough |
|
|
23
|
+
| A-015 mixed, unknown, user-patch conflict, self-disable, and protected-infrastructure disable are refused or reported accurately | PM-012, PM-014 | enablement unit/integration |
|
|
24
|
+
| A-016 simple insert bundle hot-mounts; complex/config patch, unavailable Include, timeout, and thrown activation require restart | PM-013 | hot-runtime unit/integration |
|
|
25
|
+
| A-017 operation progress is bounded, a concurrent mutation is refused, cancellation reaches the runner, and terminal status is retained | PM-015 | operation integration |
|
|
26
|
+
| A-018 restart requires a separate plan, is refused under supervisor/disabled config, and schedules exact invocation otherwise | PM-016 | restart unit |
|
|
27
|
+
| A-019 package exposes no client entry or management HTTP route and registers exactly one command/two tools | PM-001, PM-002, PM-019 | package/loader integration |
|
|
28
|
+
| A-020 packed tarball installs through official DSH CLI into a clean profile and contributes both Host rows without modifying DSH | PM-020 | local checkout E2E + CI against the locked published DSH runtime fixture |
|
|
29
|
+
| A-021 optional live-network acceptance discovers the real Codex plugin through npm/GitHub, installs npm and immutable GitHub sources in isolated DSH homes, boots the npm-installed Web profile, exercises enable/disable/update, and removes both | PM-003-PM-017 | `npm run acceptance:live:codex` |
|
|
30
|
+
| A-022 a real DSH Web Session exposes both tools, serves slash-command and natural-language search, rejects same-turn confirmation, executes later confirmation, and observes Loader HMR without restarting DSH | PM-001, PM-002, PM-009, PM-012, PM-014 | release-candidate walkthrough with real Codex backend |
|
|
31
|
+
|
|
32
|
+
## Test Layers
|
|
33
|
+
|
|
34
|
+
### Unit
|
|
35
|
+
|
|
36
|
+
Pure parsing, source resolution, search registry, deduplication, plans, profile
|
|
37
|
+
projection, patch ownership, hot-patch classification, operation state, and
|
|
38
|
+
restart policy. Network, clock, random values, process spawning, and Loader
|
|
39
|
+
entries are injected fakes.
|
|
40
|
+
|
|
41
|
+
### Integration
|
|
42
|
+
|
|
43
|
+
Use temporary profiles and an in-process fake official CLI runner that performs
|
|
44
|
+
the same manifest/bundle changes DSH owns. Exercise real manager orchestration,
|
|
45
|
+
postconditions, rollback, operation polling, cancellation, Loader state, actual
|
|
46
|
+
DSH command/tool registries, and model-tool execution.
|
|
47
|
+
|
|
48
|
+
### E2E
|
|
49
|
+
|
|
50
|
+
Build and pack the package, install the tarball through an official DSH CLI
|
|
51
|
+
into a new temporary `web` profile, and run `--dump-config`. Local acceptance
|
|
52
|
+
uses the immutable official checkout; CI and release acceptance use the
|
|
53
|
+
published DSH version locked under `test/fixtures/dsh-runtime`. Assert package
|
|
54
|
+
dependency, bundle membership, search-service row, manager row, and an
|
|
55
|
+
unchanged upstream Git status when a checkout is present.
|
|
56
|
+
|
|
57
|
+
### Optional release acceptance
|
|
58
|
+
|
|
59
|
+
Real npm/GitHub requests are opt-in because they are network-dependent. They
|
|
60
|
+
use isolated temporary DSH homes and pinned public fixtures. The release record
|
|
61
|
+
must capture DSH version/commit, Node, pnpm, exact npm version, exact GitHub
|
|
62
|
+
commit, and sanitized output.
|
|
63
|
+
|
|
64
|
+
The current evidence record is
|
|
65
|
+
[`live-codex-2026-08-26.md`](./live-codex-2026-08-26.md). The real
|
|
66
|
+
conversation and Loader record is
|
|
67
|
+
[`release-candidate-2026-08-26.md`](./release-candidate-2026-08-26.md).
|
|
68
|
+
|
|
69
|
+
## Review Gates
|
|
70
|
+
|
|
71
|
+
After each implementation slice:
|
|
72
|
+
|
|
73
|
+
1. Compare changed behavior to every affected `PM-*` row.
|
|
74
|
+
2. Confirm each positive path has mutation/postcondition assertions.
|
|
75
|
+
3. Confirm rejection, cancellation, partial failure, and retry behavior.
|
|
76
|
+
4. Run the smallest affected suite and inspect that it actually reaches the
|
|
77
|
+
intended boundary rather than only testing a mock's return value.
|
|
78
|
+
5. Update this matrix before accepting behavior that was not previously named.
|
|
79
|
+
|
|
80
|
+
Release requires typecheck/build, all unit/integration tests, local package E2E,
|
|
81
|
+
and a final SPEC-code-test traceability review.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Release Contract
|
|
2
|
+
|
|
3
|
+
## Version And Tag
|
|
4
|
+
|
|
5
|
+
- Commit the intended version in both `package.json` and
|
|
6
|
+
`package-lock.json`.
|
|
7
|
+
- A release tag must be exactly `v<package version>`.
|
|
8
|
+
- Stable versions publish to npm's `latest` dist-tag.
|
|
9
|
+
- SemVer prereleases publish to `next`.
|
|
10
|
+
- The tagged commit must be reachable from `main`.
|
|
11
|
+
|
|
12
|
+
`scripts/release-metadata.mjs` is the executable source of truth.
|
|
13
|
+
|
|
14
|
+
## Publication Gates
|
|
15
|
+
|
|
16
|
+
The tag workflow installs dependencies without dependency lifecycle scripts,
|
|
17
|
+
validates the tag, verifies against the official published DSH CLI locked in
|
|
18
|
+
`test/fixtures/dsh-runtime`, runs the complete test/build/package acceptance
|
|
19
|
+
chain, audits production dependencies, inspects the tarball, refuses to
|
|
20
|
+
republish an existing version, and verifies the resulting npm dist-tag.
|
|
21
|
+
|
|
22
|
+
## First Publication
|
|
23
|
+
|
|
24
|
+
The first publication uses a short-lived granular npm token stored as the
|
|
25
|
+
repository's `NPM_TOKEN` Actions secret. The token must allow publishing this
|
|
26
|
+
public package and satisfy the npm account's 2FA policy.
|
|
27
|
+
|
|
28
|
+
After the first version exists, configure its npm Trusted Publisher:
|
|
29
|
+
|
|
30
|
+
- provider: GitHub Actions
|
|
31
|
+
- organization or user: `yangbobo2021`
|
|
32
|
+
- repository: `relay-dsh-plugin-manager`
|
|
33
|
+
- workflow filename: `release.yml`
|
|
34
|
+
- allowed action: `npm publish`
|
|
35
|
+
|
|
36
|
+
Then remove the `NPM_TOKEN` repository secret. The workflow already grants
|
|
37
|
+
`id-token: write` and uses an OIDC-capable npm CLI.
|
|
38
|
+
|
|
39
|
+
## Release
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
git push origin main
|
|
43
|
+
git push origin v<version>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Do not move or reuse a published version tag. npm versions are immutable.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Technical Design
|
|
2
|
+
|
|
3
|
+
## Boundaries
|
|
4
|
+
|
|
5
|
+
The bundle mounts two Host entries:
|
|
6
|
+
|
|
7
|
+
1. `PluginSearchRuntime`, the provider registry (`ctx.pluginSearch`).
|
|
8
|
+
2. The manager Host plugin, which owns built-in providers, profile operations,
|
|
9
|
+
model tools, and `/plugins`.
|
|
10
|
+
|
|
11
|
+
There is no browser client entry and no management HTTP route.
|
|
12
|
+
|
|
13
|
+
## Request Flow
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
natural language --------------------------+
|
|
17
|
+
v
|
|
18
|
+
/plugins request -> Agent steering -> plugin_discover / plugin_manage
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
PluginManager core
|
|
22
|
+
+-----------------+------------------+
|
|
23
|
+
| |
|
|
24
|
+
PluginSearchRuntime Operation runtime
|
|
25
|
+
| |
|
|
26
|
+
built-in / external providers official DSH CLI
|
|
27
|
+
|
|
|
28
|
+
postcondition -> hot activation
|
|
29
|
+
|
|
|
30
|
+
restart fallback
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Compact Conversation Surface
|
|
34
|
+
|
|
35
|
+
`/plugins` deliberately forwards its unstructured text to the Agent. A direct
|
|
36
|
+
command parser would duplicate the model's language understanding and create a
|
|
37
|
+
second confirmation implementation.
|
|
38
|
+
|
|
39
|
+
Two model tools are sufficient:
|
|
40
|
+
|
|
41
|
+
- discovery is read-only and may run without confirmation;
|
|
42
|
+
- management separates planning from execution and also owns operation status
|
|
43
|
+
and cancellation.
|
|
44
|
+
|
|
45
|
+
The tool descriptions instruct the model to show a plan and wait for a later
|
|
46
|
+
affirmative user message before calling `execute`. The conversation adapter
|
|
47
|
+
also binds each token to the Agent Session and its latest `user/message` seq at
|
|
48
|
+
planning time. Same-turn and cross-session execution fail before the manager
|
|
49
|
+
can consume the token.
|
|
50
|
+
|
|
51
|
+
## Source Resolution
|
|
52
|
+
|
|
53
|
+
The core recognizes only this closed union:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
type PluginSource =
|
|
57
|
+
| { kind: 'npm'; package: string; version?: string }
|
|
58
|
+
| { kind: 'github'; owner: string; repo: string; ref?: string }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
npm metadata provides the exact version, integrity, manifest, and repository
|
|
62
|
+
identity. GitHub's API resolves a ref/default branch to a full commit; the raw
|
|
63
|
+
manifest at that commit is then validated. Execution receives only the
|
|
64
|
+
immutable normalized spec.
|
|
65
|
+
|
|
66
|
+
## Search Providers
|
|
67
|
+
|
|
68
|
+
Providers are trusted installed code but their result data remains untrusted.
|
|
69
|
+
Registration validates provider identity. Search:
|
|
70
|
+
|
|
71
|
+
- calls providers concurrently;
|
|
72
|
+
- passes one AbortSignal;
|
|
73
|
+
- isolates provider failures;
|
|
74
|
+
- normalizes typed sources;
|
|
75
|
+
- inspects candidates through the core source resolver;
|
|
76
|
+
- merges npm/GitHub aliases by canonical repository identity;
|
|
77
|
+
- returns provenance and rejected-provider diagnostics.
|
|
78
|
+
|
|
79
|
+
For an exact npm package-name query, the npm provider inserts that name as a
|
|
80
|
+
candidate when the registry search ranking omits it. This is not trusted as an
|
|
81
|
+
installation result: the same core registry metadata, integrity, manifest, and
|
|
82
|
+
DSH-surface inspection still runs before it can be returned.
|
|
83
|
+
|
|
84
|
+
No provider callback participates after discovery.
|
|
85
|
+
|
|
86
|
+
## Confirmation Plans
|
|
87
|
+
|
|
88
|
+
Plans live in memory for ten minutes. Each carries:
|
|
89
|
+
|
|
90
|
+
- operation and profile;
|
|
91
|
+
- package/source and immutable target where applicable;
|
|
92
|
+
- impact/restart expectations;
|
|
93
|
+
- creation/expiry timestamps;
|
|
94
|
+
- SHA-256 digest and a random one-use confirmation token.
|
|
95
|
+
|
|
96
|
+
Execution atomically consumes the token before starting an operation. Retrying
|
|
97
|
+
requires a new plan. Immediately before operation creation, the manager also
|
|
98
|
+
compares the planned dependency source with the current profile and refuses a
|
|
99
|
+
stale plan. This prevents confirmation replay, plan substitution, and mutation
|
|
100
|
+
after an out-of-band profile change.
|
|
101
|
+
|
|
102
|
+
## Package Mutations
|
|
103
|
+
|
|
104
|
+
The runner reuses the current DSH installation. When the current Node entry is
|
|
105
|
+
an existing file, it invokes `process.execPath <current-entry> plugin ...`;
|
|
106
|
+
otherwise it uses explicit `DSH_EXECUTABLE` or the `dsh` command. Arguments are
|
|
107
|
+
always an array. Windows shell fallback is limited to a bare `.cmd` executable.
|
|
108
|
+
|
|
109
|
+
Only one mutation runs at once. Output is bounded and exposed as progress.
|
|
110
|
+
Cancellation sends SIGTERM and later SIGKILL if needed.
|
|
111
|
+
|
|
112
|
+
After add succeeds, the manager verifies the saved immutable dependency, the
|
|
113
|
+
installed package name and exact npm version, a declared DSH surface, and exact
|
|
114
|
+
bundle membership before reporting success. A failed check restores the saved
|
|
115
|
+
profile manifest and reports a failed operation.
|
|
116
|
+
|
|
117
|
+
## Enablement
|
|
118
|
+
|
|
119
|
+
DSH has Loader-entry enablement, not a native package-level boolean. The manager
|
|
120
|
+
derives package ownership from the package's bundle patch insert rows.
|
|
121
|
+
|
|
122
|
+
Disable appends manager-owned `{ id, disabled: true }` overrides to the profile
|
|
123
|
+
patch and records ownership under `.relay-plugin-manager/state.json`. Enable
|
|
124
|
+
removes only exact overrides still owned by that state. Existing user-authored
|
|
125
|
+
rows are never overwritten. HMR verification reads current Loader entries.
|
|
126
|
+
|
|
127
|
+
Disabling a plugin that supplies the backend or another capability used by the
|
|
128
|
+
executing conversation can interrupt that turn when Loader HMR disposes it.
|
|
129
|
+
Disable plans state this explicitly so continuity-sensitive operations can be
|
|
130
|
+
confirmed from another backend or Session.
|
|
131
|
+
|
|
132
|
+
Self and protected infrastructure ids/names cannot be disabled.
|
|
133
|
+
|
|
134
|
+
## Restart-Free Activation
|
|
135
|
+
|
|
136
|
+
For a new bundle, the manager may create a process-local Include subtree when
|
|
137
|
+
the bundle patch consists only of insert rows containing `id` and `name`.
|
|
138
|
+
Client-only packages receive a no-op Host shim so the client module can be
|
|
139
|
+
served. Complex patches, activation timeout, missing Include support, and
|
|
140
|
+
runtime failure produce a restart-required result.
|
|
141
|
+
|
|
142
|
+
Temporary hot inputs are deleted at manager startup. Durable bundle membership
|
|
143
|
+
remains owned by the profile manifest and becomes authoritative at next boot.
|
|
144
|
+
|
|
145
|
+
## Restart
|
|
146
|
+
|
|
147
|
+
Restart is never chained automatically after another operation. A confirmed
|
|
148
|
+
restart starts a detached helper which waits for the old process to exit,
|
|
149
|
+
replays the exact DSH invocation, and then terminates the old process.
|
|
150
|
+
|
|
151
|
+
Automatic restart is unavailable when explicitly disabled or when the running
|
|
152
|
+
process is detected as a systemd-owned main process. The user must then use the
|
|
153
|
+
deployment supervisor.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/errors.ts
|
|
2
|
+
var PluginManagerError = class extends Error {
|
|
3
|
+
code;
|
|
4
|
+
details;
|
|
5
|
+
constructor(code, message, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "PluginManagerError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.details = details;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function fail(code, message, details) {
|
|
13
|
+
throw new PluginManagerError(code, message, details);
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { fail as t };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=errors-BGx4K2uq.js.map
|