odai-dsh-agent 0.2.37 → 0.2.38
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/README.md +32 -41
- package/build/bin/odai-dsh-agent.d.mts +11 -0
- package/build/bin/odai-dsh-agent.d.mts.map +1 -1
- package/build/bin/odai-dsh-agent.mjs +48 -108
- package/build/bin/odai-dsh-agent.mjs.map +1 -1
- package/build/src/control-center-installer.d.mts.map +1 -1
- package/build/src/control-center-installer.mjs +81 -4
- package/build/src/control-center-installer.mjs.map +1 -1
- package/build/src/installer.d.mts +55 -17
- package/build/src/installer.d.mts.map +1 -1
- package/build/src/installer.mjs +52 -227
- package/build/src/installer.mjs.map +1 -1
- package/package.json +9 -4
- package/preset/odai/runtime/lifecycle-runtime.d.mts.map +1 -1
- package/preset/odai/runtime/lifecycle-runtime.mjs +8 -1
- package/preset/odai/runtime/lifecycle-runtime.mjs.map +1 -1
- package/preset/odai/runtime/routing-context.d.mts +3 -0
- package/preset/odai/runtime/routing-context.d.mts.map +1 -1
- package/preset/odai/runtime/routing-context.mjs +11 -3
- package/preset/odai/runtime/routing-context.mjs.map +1 -1
- package/preset/odai/skills/odai/SKILL.md +41 -40
- package/preset/odai/skills/odai/manifest.json +1 -1
- package/preset/odai/skills/odai/references/craft.md +2 -2
- package/preset/odai/skills/odai/references/dao.md +15 -16
- package/preset/odai/skills/odai/references/planning.md +2 -2
- package/preset/odai/skills/odai/references/verification.md +4 -4
- package/preset.cordis.patch.yml +282 -0
- package/build/src/control-center-prompt.d.mts +0 -4
- package/build/src/control-center-prompt.d.mts.map +0 -1
- package/build/src/control-center-prompt.mjs +0 -27
- package/build/src/control-center-prompt.mjs.map +0 -1
- package/preset/odai/agent.cordis.yml +0 -261
- package/preset/odai/preset.yml +0 -3
package/README.md
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
1
|
# odai dsh agent
|
|
2
2
|
|
|
3
|
-
`odai-dsh-agent` installs a selectable, session-scoped Odai Agent preset for DeepSeek Harness (`dsh`). It is independent from the profile-wide `odai-dsh-plugin`: the preset
|
|
3
|
+
`odai-dsh-agent` installs a selectable, session-scoped Odai Agent preset for DeepSeek Harness (`dsh`). It is independent from the profile-wide `odai-dsh-plugin`: the preset does not activate global governance.
|
|
4
4
|
|
|
5
|
-
The
|
|
5
|
+
DSH `0.1.7` registers agent presets only from profile bundle declarations; it no longer scans `$DSH_HOME/.agent-presets`. The package is therefore a DSH bundle. Installing it into a profile (default `web`) through DSH's plugin manager applies two patches:
|
|
6
6
|
|
|
7
7
|
```text
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
odai-governance.mjs
|
|
12
|
-
runtime/*.mjs
|
|
13
|
-
skills/odai/**
|
|
14
|
-
.odai-agent.json
|
|
8
|
+
odai-dsh-agent/
|
|
9
|
+
preset.cordis.patch.yml declares the `odai` preset (`@deepseek-ai/dsh-agent-preset`)
|
|
10
|
+
control-center.cordis.patch.yml adds the Control Center
|
|
11
|
+
preset/odai/odai-governance.mjs scoped Odai runtime entry (exported as odai-dsh-agent/governance)
|
|
12
|
+
preset/odai/runtime/*.mjs
|
|
13
|
+
preset/odai/skills/{odai,odai-orchestration}/**
|
|
15
14
|
```
|
|
16
15
|
|
|
17
|
-
|
|
16
|
+
The preset id stays `odai`, so sessions saved with it keep resolving after an upgrade. In DSH's Plugins page the whole bundle and its Control Center row can be switched on and off; the preset declaration and the rows inside the preset are read-only there, because DSH does not let its plugin manager edit a preset's composition.
|
|
17
|
+
|
|
18
|
+
Odai owns its composition and capability set, with a scoped runtime in default `auto` mode. The `0.2.38` candidate admits DSH `>=0.1.7-rc.1`, including later prereleases; its npm peer is `*` to avoid a package-manager prerelease allow-list. Only `0.1.7-rc.1` is currently verified. A newer version alone is not a refusal, but the host still must provide the bundle registry, workflow engine and runtime services. It follows three Standard changes in that release: the workflow engine is `@deepseek-ai/dsh-workflow-ptc` (the worker-thread engine was removed), `ralph` is disabled by default, and the plugin-manager tool row is present but disabled. Standard is an upstream reference, not a required composition: release checks load Odai against the real host and verify scoped tool/prompt behavior rather than requiring text equality with Standard.
|
|
18
19
|
|
|
19
20
|
Host-owned persistence, sandbox, approval, registries, and base controller selection remain in the selected DSH profile. Ordinary requests stay on that controller. Responsibility words are optional signals rather than commands: evidence-grounded task-state gaps route at any step, the gap tool records rather than claims a route start, terminal decisions consume the proposal, an incomplete reviewer proposal waits for changed native evidence, and an identical planner/controller model remains inline without another model call. After planner handback, the controller resumes implementation only when the current user task authorizes it; plan-only, new-task, expanded-scope, and unknown authorization remain non-implementing. Reviewer children require a current hash-addressed schema 3 evidence packet whose diff is newer than the last write and whose latest successful test or read-only check follows the last write; viewing a diff does not itself invalidate an earlier successful check. The packet binds to the authenticated direct-user task when available, excludes all prior-task session events, records its boundary in route evidence, and fails closed if an explicit task binding cannot be resolved uniquely. An incomplete packet keeps the current controller route, reports why native evidence was excluded, suppresses unchanged repeat notices, and reassesses the pending proposal after decisive evidence changes without claiming independent acceptance or terminating the authorized task. Every route is resolved before provider I/O; deterministic invalid persisted mappings are backed up and exact-match removed, while recoverable provider failures preserve them. Frontend route failure becomes an explicit local controller fallback without a routed receipt. `execute` remains an explicit comparison mode and `observe` changes no model or child while retaining fail-closed high-impact protection. Configured compaction streams are buffered so partial failed output cannot contaminate the inherited-route retry or replace original history.
|
|
20
21
|
|
|
21
22
|
DSH `0.1.5-rc.1` provides native bidirectional `send_message` between adjacent continuable parent/child Agents. Odai retains the controller's native collaboration tools; its read-only children expose only their allowed tools and return bounded results through the responsibility mechanism. DSH owns durable child identity, cold resume, admission, and explicit invalid/unavailable-target failures; Odai does not replace an invalid id or treat delivery as responsibility acceptance.
|
|
22
23
|
|
|
23
|
-
The preset includes the same local long-term semantic memory runtime as the Plugin. Default `auto` mode performs no hidden model call: it automatically captures only high-confidence durable statements from the direct-human message authenticated by the latest open-turn session event, keeps ambiguous or conflicting candidates inert, and recalls only bounded active global/project records as untrusted historical context. Matching direct intent, or the compact capability gateway on a later step, exposes the controller-only `odai_memory` tool for inspection, search, confirmation, correction, physical forgetting, exact-phrase clearing, and `auto`/`off` mode changes. Recognized secrets, contact identifiers, health/crisis content, temporary instructions, hypotheses, quotes, and code are rejected; the current user and project authority always override memory. State lives at `$DSH_HOME/odai/memory/store.json`, outside
|
|
24
|
+
The preset includes the same local long-term semantic memory runtime as the Plugin. Default `auto` mode performs no hidden model call: it automatically captures only high-confidence durable statements from the direct-human message authenticated by the latest open-turn session event, keeps ambiguous or conflicting candidates inert, and recalls only bounded active global/project records as untrusted historical context. Matching direct intent, or the compact capability gateway on a later step, exposes the controller-only `odai_memory` tool for inspection, search, confirmation, correction, physical forgetting, exact-phrase clearing, and `auto`/`off` mode changes. Recognized secrets, contact identifiers, health/crisis content, temporary instructions, hypotheses, quotes, and code are rejected; the current user and project authority always override memory. State lives at `$DSH_HOME/odai/memory/store.json`, outside the package, so install, update, and uninstall preserve it. An invalid or symlinked store fails closed. The matcher is not a replacement for protecting the underlying DSH session history from sensitive input.
|
|
24
25
|
|
|
25
26
|
Non-crisis care and crisis safety are separate. `references/care.md` owns fatigue, anxiety, self-doubt, rumination, shame, fear of mistakes, negativity, reduced agency, and user-controlled 阿岱/欧黛 styles without diagnosis, scoring, persistence, or model routing. `references/human-safety.md` owns sustained or worsening low mood, hopelessness, burden, self-harm, suicide, and immediate danger; any credible current inclination triggers timely care and a direct safety check even without a plan, while plan, means, and action determine urgency.
|
|
26
27
|
|
|
@@ -30,39 +31,27 @@ Ordinary requests retain the complete canonical governance plus compact responsi
|
|
|
30
31
|
|
|
31
32
|
## Install
|
|
32
33
|
|
|
33
|
-
With DSH
|
|
34
|
+
With DSH `0.1.7-rc.1` installed, run:
|
|
34
35
|
|
|
35
36
|
```sh
|
|
36
|
-
npx odai-dsh-agent install
|
|
37
|
+
npx odai-dsh-agent install [--profile web] [--dsh-home /path/to/dsh-home]
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
The installer checks `dsh -V
|
|
40
|
+
The installer checks `dsh -V` (the `0.2.38` candidate accepts `>=0.1.7-rc.1`, including later prereleases, without an upper version cap; published `0.2.37` targets `0.1.5-rc.2` and keeps its copied-preset installer), then runs `dsh plugin --profile <profile> add odai-dsh-agent@<version> --save-exact`. DSH's plugin manager checks the package's DSH peer before downloading anything. The package already contains the canonical skills and runtime; it does not require the Plugin. Restart the DSH Web process after a profile change, open a new session, and select `odai 治理模式` in the preset picker. Existing sessions keep the composition they started with.
|
|
40
41
|
|
|
41
|
-
`
|
|
42
|
+
DSH `0.1.7` does not carry the earlier `agent-presets.default` setting forward. To make odai the default preset again, choose it as the default in DSH; the choice is saved in the profile's own `cordis.patch.yml`.
|
|
42
43
|
|
|
43
|
-
|
|
44
|
-
npx odai-dsh-agent install --dsh-home /path/to/dsh-home
|
|
45
|
-
```
|
|
44
|
+
Uninstall reads the host's non-booting `--dump-config` output, including bundle, profile and home layers. It follows `modeSelectionEnabled`, `selectedDefault` and `default` precedence, refusing removal when Odai is the effective default or the relevant configuration cannot be determined without evaluating code.
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
The preset's `package.json` must contain the `#odai-contracts` import map and its orchestration entry must exist; missing or invalid metadata is `partial-drift` and requires repair. Status is `current` only when the profile dependency is this installer's exact registry version, the resolved package reports that version, the bundle entry occurs exactly once, and the preset patch, governance entry, runtime, skills, Control Center host and client exist. Other states are `absent`, `registry-upgrade`, `local-link`, `partial-drift`, `newer`, and `unknown-source`; install repairs or upgrades them and refuses a silent downgrade. Profile operations serialize through an owner-token lock. If a plugin-manager command fails without changing profile bytes, the installer reports the unchanged state; if bytes changed, it does not run a destructive inverse command. It preserves the current state and retains before/after recovery evidence under `$DSH_HOME/odai/control-center-backups/`.
|
|
48
47
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
DSH classifies this as a `trust: user` preset. User presets have the same privileges as shell access, so install only reviewed package versions; the installer repeats this trust notice in both plain and JSON output.
|
|
48
|
+
DSH bundles run in-process with the host's privileges, so install only reviewed package versions. Normal install, update, and uninstall do not scan, rewrite, or migrate historical session logs.
|
|
52
49
|
|
|
53
50
|
## Control Center
|
|
54
51
|
|
|
55
|
-
The
|
|
52
|
+
The Control Center ships inside the same bundle. It adds one Chinese launcher to DSH Web with a current-turn responsibility graph, session evidence timeline, structured event inspector, and routing controls for the four optional responsibilities. The controller remains host-managed and read-only. Routing writes use the same validated, locked, atomic routing action as the conversation tool and apply on the next user turn. Configured models alone are never displayed as execution evidence. A native-collaboration summary shows observed `subagent`/`subagent_fork` tool receipts; these are not named-role model verification or child completion evidence.
|
|
56
53
|
|
|
57
|
-
The
|
|
58
|
-
|
|
59
|
-
```sh
|
|
60
|
-
npx odai-dsh-agent control-center install [--profile web]
|
|
61
|
-
npx odai-dsh-agent control-center status [--profile web]
|
|
62
|
-
npx odai-dsh-agent control-center uninstall [--profile web]
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
A Control Center profile change requires one normal DSH Web process restart. Removing it does not remove the Agent preset, routing configuration, or session evidence. Status is current only when the dependency is the installer package's exact registry version, the resolved package reports that same version, the bundle entry occurs exactly once, and the shipped bundle patch plus host/runtime/client artifacts exist. Standalone Control Center install checks the supported DSH version before running the package manager; status and removal remain available for recovery. A stale `file:` or `link:` dependency is reported with its concrete source and can be replaced only after explicit consent. Profile operations serialize through an owner-token lock. If a DSH package-manager command fails without changing profile bytes, the installer reports the unchanged state; if bytes changed, it does not run a destructive inverse command or overwrite a possible concurrent successor. It preserves the current state and retains before/after recovery evidence under `$DSH_HOME/odai/control-center-backups/` for explicit repair.
|
|
54
|
+
The earlier `control-center install|status|uninstall` commands remain as aliases for `install|status|uninstall`. `--with-control-center` and `--without-control-center` are accepted and ignored; disable the Control Center row in the Plugins page instead.
|
|
66
55
|
|
|
67
56
|
## Responsibility models
|
|
68
57
|
|
|
@@ -77,7 +66,7 @@ The Agent ships no researcher, planner, reviewer, or frontend model mapping. It
|
|
|
77
66
|
研究和验收职责改成 same-turn。
|
|
78
67
|
```
|
|
79
68
|
|
|
80
|
-
The controller calls `odai_routing_config` to persist that explicit choice. Researcher, planner, reviewer, and frontend each accept an explicit `same-turn` or `child` dispatch override; the controller owns integration, validation, and final delivery. Children remain read-only; explicitly delegated patch preparation returns unapplied proposals, while research, planning, and review keep their narrower contracts. The tool uses separate `set-dispatch`/`reset-dispatch` actions, so changing a dispatch override does not remove its model mapping. Researcher activation is task-gated but not price-aware: its mapping enables the narrow trigger and does not guarantee lower cost. The tool repeats that warning whenever a researcher mapping is shown; Odai must use authoritative provider prices and measured usage instead of inventing either. The user does not edit Agent files, YAML, or JSON and does not add trigger terms to later tasks. Mappings live in `$DSH_HOME/odai/routing.json`, outside the
|
|
69
|
+
The controller calls `odai_routing_config` to persist that explicit choice. Researcher, planner, reviewer, and frontend each accept an explicit `same-turn` or `child` dispatch override; the controller owns integration, validation, and final delivery. Children remain read-only; explicitly delegated patch preparation returns unapplied proposals, while research, planning, and review keep their narrower contracts. The tool uses separate `set-dispatch`/`reset-dispatch` actions, so changing a dispatch override does not remove its model mapping. Researcher activation is task-gated but not price-aware: its mapping enables the narrow trigger and does not guarantee lower cost. The tool repeats that warning whenever a researcher mapping is shown; Odai must use authoritative provider prices and measured usage instead of inventing either. The user does not edit Agent files, YAML, or JSON and does not add trigger terms to later tasks. Mappings live in `$DSH_HOME/odai/routing.json`, outside the package, so updates never replace them. A legacy Executor mapping is ignored without invalidating current responsibilities and is removed on the next configuration write. Audit evidence likewise lives under `$DSH_HOME/odai/session-evidence/` instead of using private DSH session-event types, so changing or removing the preset cannot make a session unreadable. Changes apply from the next user turn. Whenever routing or explicit mapping management needs it, runtime resolves a fresh merged effective-mapping snapshot, with persisted mappings preferred over deployment mappings; the full snapshot enters the model prompt only for mapping-management intent and remains authoritative over stale compaction text. The tool also exposes the latest current-session actual route receipt; configured targets alone never prove that a responsibility ran. If reasoning effort is omitted, the target provider/model uses its own default rather than inheriting the source controller's setting. Plugin and Agent read the same stores when both are deliberately present.
|
|
81
70
|
|
|
82
71
|
Researcher and frontend are optional evidence/production upgrades whose missing mappings keep the original route without claiming success. A researcher child is limited to a bounded multi-source repository question; technical facts available through controller tools are investigated directly instead of manufacturing a role call. Planner and reviewer are independent optional responsibilities; if a needed one has no mapping, high-impact work fails closed and remains read-only, while lower-impact work continues only where it does not depend on the missing responsibility. Same-turn routes and child outputs require actual request-header evidence. Same-turn researcher, planner, and reviewer are read-only and must return through `odai_responsibility_return` to the controller, which resumes any authorized implementation. Missing handback restores and continues the controller instead of treating the read-only text as final delivery. Deterministic invalid persisted mappings are backed up and exact-match removed; credentials, quota, rate-limit, server, timeout, and transport failures preserve configuration and fall back only for the current call. Matching responsibilities use `odai_responsibility_gap` to honor configured models, dispatch, and evidence gates. A generic subagent is not a responsibility route. Exceptional manual planner/frontend children use the native tool's `description` prefix `odai-planner:` or `odai-frontend:` and require a matching actual-route receipt; researcher/reviewer require managed evidence validation. Local child routing receipts reach the parent's Control Center under the corresponding role, without claiming task completion. Odai never chooses a model or price on the user's behalf.
|
|
83
72
|
|
|
@@ -107,7 +96,7 @@ The target applies only to future `compaction` summary requests. It does not cha
|
|
|
107
96
|
|
|
108
97
|
## Skill sources
|
|
109
98
|
|
|
110
|
-
The Agent keeps the
|
|
99
|
+
The Agent keeps the bundle's complete skill copy as its `bundled` default, so existing installations do not change behavior. When the user explicitly asks to show, set, or reset the Odai skill source, the controller uses `odai_skill_source_config` and stores the choice in `$DSH_HOME/odai/source.json`, outside the package:
|
|
111
100
|
|
|
112
101
|
- `bundled`: use the skill shipped with this Agent release.
|
|
113
102
|
- `auto`: allow a compatible current-project `.dsh/skills/odai` or `.agents/skills/odai` bundle, then DSH custom roots and newer user installs under `$DSH_HOME/skills/odai` or `$DSH_AGENTS_HOME/skills/odai` (default `~/.agents/skills/odai`), with bundled fallback.
|
|
@@ -117,25 +106,27 @@ The Agent keeps the managed preset's complete skill copy as its `bundled` defaul
|
|
|
117
106
|
|
|
118
107
|
An independent install must be a complete directory bundle containing `SKILL.md`, `manifest.json`, and every manifest-declared file. The runtime checks SemVer 2.0.0 `skillVersion`, an exact supported `runtimeContract`, complete-file SHA-256 integrity, and same-version content conflicts. Prompt governance and routing role contracts are selected atomically for one agent turn; project sources are scoped by that session's cwd, and changes are reconsidered on the next user turn. Explicit deployment `skillPath` or `ODAI_SKILL_PATH` remains highest priority and requires a DSH restart.
|
|
119
108
|
|
|
120
|
-
|
|
109
|
+
The `0.2.38` source candidate bundles governance `0.7.1` (schema `5`, runtime contract `9`) and `odai-orchestration` `0.2.0` (schema `1`). Published `0.2.37` bundles governance `0.7.0` with the same schemas, runtime contract, and orchestration version. Governance has no role or orchestration dependency. The bundle carries both skills and its own trusted compiler, combining separate source digests into one immutable turn snapshot; it never executes external scripts or discovers neighboring orchestration. Incompatible older sources fall back visibly without rewriting their files; an incompatible explicit `skillPath` fails fast.
|
|
121
110
|
|
|
122
111
|
## Retired skill evolution
|
|
123
112
|
|
|
124
|
-
|
|
113
|
+
Releases before `0.2.37` could refine both governance and orchestration Markdown in `$DSH_HOME/odai/skill-evolution`. Published `0.2.37` retired that overlay together with `odai_skill_evolution`, `ODAI_DISABLE_EVOLUTION`, and `governance.evolutionRoot`; the `0.2.38` candidate preserves that retirement. Previously active refinements stop taking effect after upgrading and restarting DSH. The runtime no longer reads the store, no package install, update, repair, or removal deletes it, and a leftover `evolutionRoot` is ignored.
|
|
125
114
|
|
|
126
|
-
To retain governance customizations, start with a complete schema `5` / contract `9` user-level bundle, review and apply the desired rules, assign a distinct valid SemVer `skillVersion`, then ask Odai to set the source to `user`. Modified content retaining bundled version `0.7.
|
|
115
|
+
To retain governance customizations, start with a complete schema `5` / contract `9` user-level bundle, review and apply the desired rules, assign a distinct valid SemVer `skillVersion`, then ask Odai to set the source to `user`. Modified content retaining this candidate's bundled version `0.7.1` falls back with `same-version-content-conflict`; changing only build metadata is insufficient. On the next turn verify the actual canonical source, version and governance digest, not just the saved setting. Explicit deployment paths take precedence.
|
|
127
116
|
|
|
128
117
|
External selection cannot restore orchestration refinements or generation activation, rebase and rollback. DSH retains its packaged orchestration; the old store has no automatic migration or export. Keep it unchanged and follow the [governance migration and recovery steps](https://github.com/orziz/odai/blob/main/dsh/README.md#migrating-retired-skill-evolution).
|
|
129
118
|
|
|
130
|
-
## Status and
|
|
119
|
+
## Status, uninstall, and the old preset directory
|
|
131
120
|
|
|
132
121
|
```sh
|
|
133
|
-
npx odai-dsh-agent status
|
|
134
|
-
npx odai-dsh-agent status --json
|
|
122
|
+
npx odai-dsh-agent status [--json]
|
|
135
123
|
npx odai-dsh-agent uninstall
|
|
124
|
+
npx odai-dsh-agent cleanup-legacy
|
|
136
125
|
```
|
|
137
126
|
|
|
138
|
-
`status` reports
|
|
127
|
+
`status` reports the bundle state and, separately, whether a preset directory copied by an earlier release still exists at `$DSH_HOME/.agent-presets/odai`. DSH `0.1.7` no longer reads that directory; the installer leaves it untouched. `cleanup-legacy` moves it into `$DSH_HOME/odai/legacy-preset-backups/<timestamp>/` instead of deleting it, so local edits survive; it touches no sessions, memory, routing, or other Odai data.
|
|
128
|
+
|
|
129
|
+
`uninstall` removes the bundle through DSH's plugin manager. It refuses while the profile still selects `odai` as the default preset; choose another default first so new sessions cannot fail on a missing preset. Removing the bundle does not delete routing configuration, memory, or session evidence.
|
|
139
130
|
|
|
140
131
|
## Plugin versus Agent
|
|
141
132
|
|
|
@@ -1,3 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
type Command = "install" | "status" | "uninstall" | "cleanup-legacy";
|
|
3
|
+
interface CliArguments {
|
|
4
|
+
command?: Command;
|
|
5
|
+
legacyControlCenter: boolean;
|
|
6
|
+
deprecatedFlag?: string;
|
|
7
|
+
dshHome?: string;
|
|
8
|
+
profile?: string;
|
|
9
|
+
json: boolean;
|
|
10
|
+
help: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function parseArgs(argv: readonly string[]): CliArguments;
|
|
2
13
|
export {};
|
|
3
14
|
//# sourceMappingURL=odai-dsh-agent.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odai-dsh-agent.d.mts","sourceRoot":"","sources":["../../bin/odai-dsh-agent.mts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"odai-dsh-agent.d.mts","sourceRoot":"","sources":["../../bin/odai-dsh-agent.mts"],"names":[],"mappings":";AAYA,KAAK,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAErE,UAAU,YAAY;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAmFD,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,YAAY,CAkB/D"}
|
|
@@ -1,76 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { promptForControlCenterInstall } from "../src/control-center-prompt.mjs";
|
|
3
|
-
import { inspectAgentControlCenter, installAgentControlCenter, uninstallAgentControlCenter, } from "../src/control-center-installer.mjs";
|
|
4
2
|
import { readDshVersion } from "../src/dsh-version.mjs";
|
|
5
|
-
import { inspectAgentInstallation, installAgentPreset, supportsDshVersion, SUPPORTED_DSH_RANGE, uninstallAgentPreset, } from "../src/installer.mjs";
|
|
3
|
+
import { inspectAgentInstallation, installAgentPreset, moveLegacyAgentPreset, supportsDshVersion, SUPPORTED_DSH_RANGE, uninstallAgentPreset, } from "../src/installer.mjs";
|
|
6
4
|
const HELP = `Usage: odai-dsh-agent <command> [options]
|
|
7
5
|
|
|
6
|
+
Installs the Odai agent preset for DSH ${SUPPORTED_DSH_RANGE} as a profile bundle. The
|
|
7
|
+
bundle declares the \`odai\` preset and the Control Center; the Control Center row can
|
|
8
|
+
be switched off in DSH's Plugins page, while the preset's own rows are read-only there.
|
|
9
|
+
|
|
8
10
|
Commands:
|
|
9
|
-
install
|
|
10
|
-
status
|
|
11
|
-
uninstall
|
|
12
|
-
|
|
13
|
-
control-center status Inspect the Agent Control Center profile state
|
|
14
|
-
control-center uninstall Remove only the Agent Control Center profile state
|
|
11
|
+
install Install or update the Odai bundle in a DSH profile
|
|
12
|
+
status Inspect the bundle and any preset directory left by older releases
|
|
13
|
+
uninstall Remove the bundle (refused while odai is the default preset)
|
|
14
|
+
cleanup-legacy Move the old $DSH_HOME/.agent-presets/odai directory into a backup
|
|
15
15
|
|
|
16
16
|
Options:
|
|
17
17
|
--dsh-home <path> Override DSH_HOME
|
|
18
|
-
--profile <name>
|
|
19
|
-
--
|
|
20
|
-
|
|
21
|
-
--json Print JSON; never prompts
|
|
22
|
-
-h, --help Show this help
|
|
18
|
+
--profile <name> DSH profile (default: web)
|
|
19
|
+
--json Print JSON
|
|
20
|
+
-h, --help Show this help
|
|
23
21
|
`;
|
|
24
22
|
try {
|
|
25
23
|
const args = parseArgs(process.argv.slice(2));
|
|
24
|
+
if (args.legacyControlCenter) {
|
|
25
|
+
process.stderr.write("odai-dsh-agent: `control-center` commands now manage the whole Odai bundle; the Control Center is part of it.\n");
|
|
26
|
+
}
|
|
27
|
+
if (args.deprecatedFlag) {
|
|
28
|
+
process.stderr.write(`odai-dsh-agent: ${args.deprecatedFlag} is ignored; the Control Center is part of the bundle and can be disabled in DSH's Plugins page.\n`);
|
|
29
|
+
}
|
|
26
30
|
if (args.help) {
|
|
27
31
|
process.stdout.write(HELP);
|
|
28
32
|
}
|
|
29
33
|
else if (args.command === "install") {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
dshHome: args.dshHome,
|
|
33
|
-
dshVersion,
|
|
34
|
-
});
|
|
35
|
-
if (args.json) {
|
|
36
|
-
const controlCenter = args.controlCenter === true
|
|
37
|
-
? await installAgentControlCenter({ dshHome: args.dshHome, profile: args.profile })
|
|
38
|
-
: undefined;
|
|
39
|
-
process.stdout.write(`${JSON.stringify({
|
|
40
|
-
...preset,
|
|
41
|
-
...(controlCenter ? { controlCenter } : {}),
|
|
42
|
-
}, null, 2)}\n`);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
print(preset, false);
|
|
46
|
-
const installControlCenter = await shouldInstallControlCenter(args);
|
|
47
|
-
if (installControlCenter) {
|
|
48
|
-
print(await installAgentControlCenter({ dshHome: args.dshHome, profile: args.profile }), false);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
34
|
+
assertDshVersion();
|
|
35
|
+
print(await installAgentPreset({ dshHome: args.dshHome, profile: args.profile }), args.json);
|
|
51
36
|
}
|
|
52
37
|
else if (args.command === "status") {
|
|
53
|
-
const result = await inspectAgentInstallation({ dshHome: args.dshHome });
|
|
38
|
+
const result = await inspectAgentInstallation({ dshHome: args.dshHome, profile: args.profile });
|
|
54
39
|
print(result, args.json);
|
|
55
|
-
if (result.status
|
|
40
|
+
if (result.status !== "absent" && result.status !== "current")
|
|
56
41
|
process.exitCode = 2;
|
|
57
42
|
}
|
|
58
43
|
else if (args.command === "uninstall") {
|
|
59
|
-
print(await uninstallAgentPreset({
|
|
60
|
-
dshHome: args.dshHome,
|
|
61
|
-
}), args.json);
|
|
62
|
-
}
|
|
63
|
-
else if (args.command === "control-center" && args.controlCenterCommand === "install") {
|
|
64
|
-
print(await installAgentControlCenter({ dshHome: args.dshHome, profile: args.profile }), args.json);
|
|
44
|
+
print(await uninstallAgentPreset({ dshHome: args.dshHome, profile: args.profile }), args.json);
|
|
65
45
|
}
|
|
66
|
-
else if (args.command === "
|
|
67
|
-
|
|
68
|
-
print(result, args.json);
|
|
69
|
-
if (result.status !== "absent" && result.status !== "current")
|
|
70
|
-
process.exitCode = 2;
|
|
71
|
-
}
|
|
72
|
-
else if (args.command === "control-center" && args.controlCenterCommand === "uninstall") {
|
|
73
|
-
print(await uninstallAgentControlCenter({ dshHome: args.dshHome, profile: args.profile }), args.json);
|
|
46
|
+
else if (args.command === "cleanup-legacy") {
|
|
47
|
+
print(await moveLegacyAgentPreset({ dshHome: args.dshHome }), args.json);
|
|
74
48
|
}
|
|
75
49
|
else {
|
|
76
50
|
throw new Error("a command is required\n\n" + HELP);
|
|
@@ -80,41 +54,13 @@ catch (error) {
|
|
|
80
54
|
process.stderr.write(`odai-dsh-agent: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
81
55
|
process.exitCode = 1;
|
|
82
56
|
}
|
|
83
|
-
async function shouldInstallControlCenter(args) {
|
|
84
|
-
if (args.controlCenter !== undefined)
|
|
85
|
-
return args.controlCenter;
|
|
86
|
-
const current = await inspectAgentControlCenter({ dshHome: args.dshHome, profile: args.profile });
|
|
87
|
-
if (current.status === "current") {
|
|
88
|
-
process.stdout.write(`Control Center registry ${current.installedVersion} 已准确安装,未修改:${current.target}\n`);
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
if (current.status === "newer") {
|
|
92
|
-
process.stdout.write(`Control Center ${current.installedVersion ?? current.dependency ?? "<unknown>"} 高于当前安装器 ${current.targetVersion},禁止静默降级:${current.target}\n`);
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
if (args.json || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
96
|
-
process.stdout.write(`Control Center 状态为 ${current.status},非交互安装未修改 Web profile;需要时显式传 --with-control-center。\n`);
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
const action = current.status === "absent"
|
|
100
|
-
? `把 Odai Control Center registry ${current.targetVersion} 安装到 DSH profile “${current.profile}”`
|
|
101
|
-
: current.status === "registry-upgrade"
|
|
102
|
-
? `把 DSH profile “${current.profile}” 的 Control Center 从 registry ${current.installedVersion ?? current.dependency ?? "<unknown>"} 升级到 ${current.targetVersion}`
|
|
103
|
-
: current.status === "local-link"
|
|
104
|
-
? `把 DSH profile “${current.profile}” 的本地 Control Center 来源 ${current.dependency ?? current.resolvedRoot ?? "<unknown>"} 替换为 registry ${current.targetVersion}`
|
|
105
|
-
: `修复 DSH profile “${current.profile}” 的 Control Center ${current.status} 状态并固定到 registry ${current.targetVersion}(${current.issues.join(";") || "来源无法确认"})`;
|
|
106
|
-
const accepted = await promptForControlCenterInstall(process.stdin, process.stdout, current.profile, action);
|
|
107
|
-
if (!accepted)
|
|
108
|
-
process.stdout.write("已跳过 Control Center,Web profile 未修改;稍后可运行 odai-dsh-agent control-center install。\n");
|
|
109
|
-
return accepted;
|
|
110
|
-
}
|
|
111
57
|
function assertDshVersion() {
|
|
112
58
|
const dsh = process.env.DSH_BIN ?? "dsh";
|
|
113
59
|
let actual;
|
|
114
60
|
try {
|
|
115
61
|
actual = readDshVersion({ dsh });
|
|
116
62
|
}
|
|
117
|
-
catch
|
|
63
|
+
catch {
|
|
118
64
|
throw new Error(`cannot run ${dsh} -V; install DSH ${SUPPORTED_DSH_RANGE} before installing the preset`);
|
|
119
65
|
}
|
|
120
66
|
if (!supportsDshVersion(actual)) {
|
|
@@ -129,48 +75,31 @@ function requiredOptionValue(argv, index, option, label) {
|
|
|
129
75
|
}
|
|
130
76
|
return value;
|
|
131
77
|
}
|
|
132
|
-
function parseArgs(argv) {
|
|
133
|
-
const parsed = { json: false, help: false };
|
|
78
|
+
export function parseArgs(argv) {
|
|
79
|
+
const parsed = { json: false, help: false, legacyControlCenter: false };
|
|
134
80
|
for (let index = 0; index < argv.length; index += 1) {
|
|
135
81
|
const arg = argv[index];
|
|
136
82
|
if (arg === "-h" || arg === "--help")
|
|
137
83
|
parsed.help = true;
|
|
138
84
|
else if (arg === "--json")
|
|
139
85
|
parsed.json = true;
|
|
140
|
-
else if (arg === "--with-control-center")
|
|
141
|
-
|
|
142
|
-
throw new Error("--with-control-center conflicts with --without-control-center");
|
|
143
|
-
parsed.controlCenter = true;
|
|
144
|
-
}
|
|
145
|
-
else if (arg === "--without-control-center") {
|
|
146
|
-
if (parsed.controlCenter === true)
|
|
147
|
-
throw new Error("--without-control-center conflicts with --with-control-center");
|
|
148
|
-
parsed.controlCenter = false;
|
|
149
|
-
}
|
|
86
|
+
else if (arg === "--with-control-center" || arg === "--without-control-center")
|
|
87
|
+
parsed.deprecatedFlag = arg;
|
|
150
88
|
else if (arg === "--dsh-home")
|
|
151
89
|
parsed.dshHome = requiredOptionValue(argv, ++index, "--dsh-home", "path");
|
|
152
90
|
else if (arg === "--profile")
|
|
153
91
|
parsed.profile = requiredOptionValue(argv, ++index, "--profile", "name");
|
|
154
|
-
else if (!parsed.command &&
|
|
92
|
+
else if (!parsed.command && !parsed.legacyControlCenter && arg === "control-center")
|
|
93
|
+
parsed.legacyControlCenter = true;
|
|
94
|
+
else if (!parsed.command && (arg === "install" || arg === "status" || arg === "uninstall"
|
|
95
|
+
|| (arg === "cleanup-legacy" && !parsed.legacyControlCenter)))
|
|
155
96
|
parsed.command = arg;
|
|
156
|
-
else if (parsed.command === "control-center" && !parsed.controlCenterCommand
|
|
157
|
-
&& (arg === "install" || arg === "status" || arg === "uninstall"))
|
|
158
|
-
parsed.controlCenterCommand = arg;
|
|
159
97
|
else
|
|
160
98
|
throw new Error(`unknown argument: ${arg}`);
|
|
161
99
|
}
|
|
162
|
-
if (parsed.
|
|
163
|
-
throw new Error("--dsh-home requires a non-empty path");
|
|
164
|
-
}
|
|
165
|
-
if (parsed.profile !== undefined && parsed.profile.trim() === "") {
|
|
166
|
-
throw new Error("--profile requires a non-empty name");
|
|
167
|
-
}
|
|
168
|
-
if (parsed.command === "control-center" && !parsed.controlCenterCommand && !parsed.help) {
|
|
100
|
+
if (parsed.legacyControlCenter && !parsed.command && !parsed.help) {
|
|
169
101
|
throw new Error("control-center requires install, status, or uninstall");
|
|
170
102
|
}
|
|
171
|
-
if (parsed.controlCenter !== undefined && parsed.command !== "install" && !parsed.help) {
|
|
172
|
-
throw new Error("--with-control-center and --without-control-center are valid only with install");
|
|
173
|
-
}
|
|
174
103
|
return parsed;
|
|
175
104
|
}
|
|
176
105
|
function print(result, json) {
|
|
@@ -182,9 +111,20 @@ function print(result, json) {
|
|
|
182
111
|
process.stdout.write(`${result.status}: ${result.target}\n`);
|
|
183
112
|
for (const issue of result.issues ?? [])
|
|
184
113
|
process.stdout.write(`- ${issue}\n`);
|
|
185
|
-
return;
|
|
186
114
|
}
|
|
187
|
-
|
|
115
|
+
else {
|
|
116
|
+
process.stdout.write(`${result.operation}: ${result.target}\n`);
|
|
117
|
+
if (result.backup)
|
|
118
|
+
process.stdout.write(`backup: ${result.backup}\n`);
|
|
119
|
+
for (const issue of result.issues ?? [])
|
|
120
|
+
process.stdout.write(`- ${issue}\n`);
|
|
121
|
+
}
|
|
122
|
+
if (result.legacy && result.legacy.status !== "absent") {
|
|
123
|
+
process.stdout.write(`legacy preset directory (${result.legacy.status}, no longer read by DSH): ${result.legacy.target}\n`);
|
|
124
|
+
process.stdout.write("run `odai-dsh-agent cleanup-legacy` to move it into a backup\n");
|
|
125
|
+
}
|
|
126
|
+
if (result.notice)
|
|
127
|
+
process.stdout.write(`notice: ${result.notice}\n`);
|
|
188
128
|
if (result.security)
|
|
189
129
|
process.stdout.write(`security: ${result.security}\n`);
|
|
190
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odai-dsh-agent.mjs","sourceRoot":"","sources":["../../bin/odai-dsh-agent.mts"],"names":[],"mappings":";AAEA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"odai-dsh-agent.mjs","sourceRoot":"","sources":["../../bin/odai-dsh-agent.mts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center-installer.d.mts","sourceRoot":"","sources":["../../src/control-center-installer.mts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,oBAAoB,CAAC;AA8BhF,KAAK,eAAe,GAAG,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qCAAqC,KAC3C,MAAM,CAAC;AAEZ,MAAM,MAAM,wBAAwB,GAChC,QAAQ,GACR,SAAS,GACT,kBAAkB,GAClB,YAAY,GACZ,eAAe,GACf,OAAO,GACP,gBAAgB,CAAC;AAErB,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;
|
|
1
|
+
{"version":3,"file":"control-center-installer.d.mts","sourceRoot":"","sources":["../../src/control-center-installer.mts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,oBAAoB,CAAC;AA8BhF,KAAK,eAAe,GAAG,CACrB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,EAAE,qCAAqC,KAC3C,MAAM,CAAC;AAEZ,MAAM,MAAM,wBAAwB,GAChC,QAAQ,GACR,SAAS,GACT,kBAAkB,GAClB,YAAY,GACZ,eAAe,GACf,OAAO,GACP,gBAAgB,CAAC;AAErB,MAAM,WAAW,yBAAyB;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,OAAO,CAAC,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AA2KD,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,4BAA4B,CAAC,CAqDvC;AAgID,wBAAsB,yBAAyB,CAC7C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,QAAQ,CAAC;IAChB,SAAS,EAAE,WAAW,GAAG,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAC9D,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,wBAAwB,CAAC;CAC1C,CAAC,CAAC,CAUJ;AA2DD,wBAAsB,2BAA2B,CAC/C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,QAAQ,CAAC;IAAE,SAAS,EAAE,aAAa,GAAG,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CA6B7F"}
|
|
@@ -16,6 +16,7 @@ if (!isRecord(parsedMetadata) || typeof parsedMetadata.name !== "string" || type
|
|
|
16
16
|
}
|
|
17
17
|
const packageMetadata = { name: parsedMetadata.name, version: parsedMetadata.version };
|
|
18
18
|
const PROFILE_STATE_FILES = Object.freeze(["package.json", "pnpm-lock.yaml", "pnpm-workspace.yaml"]);
|
|
19
|
+
const ODAI_PRESET_ID = "odai";
|
|
19
20
|
function isRecord(value) {
|
|
20
21
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21
22
|
}
|
|
@@ -105,7 +106,13 @@ function exactRegistryVersion(dependency) {
|
|
|
105
106
|
}
|
|
106
107
|
async function resolvedPackage(target) {
|
|
107
108
|
const manifestPath = resolve(target, "node_modules", packageMetadata.name, "package.json");
|
|
108
|
-
|
|
109
|
+
let source;
|
|
110
|
+
try {
|
|
111
|
+
source = await optionalFile(manifestPath);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
return { complete: false, issues: [`resolved package metadata is unreadable: ${errorMessage(error)}`] };
|
|
115
|
+
}
|
|
109
116
|
if (!source)
|
|
110
117
|
return undefined;
|
|
111
118
|
const issues = [];
|
|
@@ -127,15 +134,38 @@ async function resolvedPackage(target) {
|
|
|
127
134
|
issues.push(`cannot resolve installed package root: ${errorMessage(error)}`);
|
|
128
135
|
}
|
|
129
136
|
for (const relativePath of [
|
|
137
|
+
"preset.cordis.patch.yml",
|
|
138
|
+
"preset/odai/odai-governance.mjs",
|
|
139
|
+
"preset/odai/package.json",
|
|
140
|
+
"preset/odai/skills/odai/manifest.json",
|
|
141
|
+
"preset/odai/skills/odai-orchestration/manifest.json",
|
|
142
|
+
"preset/odai/skills/odai-orchestration/scripts/compose-contracts.mjs",
|
|
143
|
+
"preset/odai/runtime/index.mjs",
|
|
144
|
+
"preset/odai/skills/odai/SKILL.md",
|
|
130
145
|
"control-center.cordis.patch.yml",
|
|
131
146
|
"build/src/installer.mjs",
|
|
132
147
|
"preset/odai/runtime/control-center-host.mjs",
|
|
133
148
|
"preset/odai/runtime/control-center-runtime.mjs",
|
|
134
149
|
"client/client.js",
|
|
135
150
|
]) {
|
|
136
|
-
|
|
137
|
-
|
|
151
|
+
try {
|
|
152
|
+
if (!await optionalFile(resolve(dirname(manifestPath), relativePath))) {
|
|
153
|
+
issues.push(`resolved package is missing ${relativePath}`);
|
|
154
|
+
}
|
|
138
155
|
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
issues.push(`resolved package cannot read ${relativePath}: ${errorMessage(error)}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
const presetMetadata = JSON.parse(await readFile(resolve(dirname(manifestPath), "preset/odai/package.json"), "utf8"));
|
|
162
|
+
if (!isRecord(presetMetadata) || presetMetadata.type !== "module" || !isRecord(presetMetadata.imports)
|
|
163
|
+
|| presetMetadata.imports["#odai-contracts"] !== "./skills/odai-orchestration/scripts/compose-contracts.mjs") {
|
|
164
|
+
issues.push("resolved preset package has an invalid #odai-contracts import map");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
issues.push(`resolved preset package metadata is unavailable: ${errorMessage(error)}`);
|
|
139
169
|
}
|
|
140
170
|
return {
|
|
141
171
|
...(root ? { root } : {}),
|
|
@@ -263,6 +293,52 @@ async function changedProfileFailure(dshHome, before, after, detail, cause) {
|
|
|
263
293
|
return new AggregateError([cause, evidenceError], `${detail}\ncurrent profile state was preserved, but recovery evidence could not be retained`);
|
|
264
294
|
}
|
|
265
295
|
}
|
|
296
|
+
// Ask the host to compose bundle, profile and home layers without booting or
|
|
297
|
+
// evaluating !!js. Reading only the profile patch misses deployment defaults.
|
|
298
|
+
async function assertOdaiIsNotProfileDefault(options) {
|
|
299
|
+
const dsh = options.dshBin ?? process.env.DSH_BIN ?? "dsh";
|
|
300
|
+
const platform = options.platform ?? process.platform;
|
|
301
|
+
const execute = options.execute ?? execFileSync;
|
|
302
|
+
const source = execute(platform === "win32" && dsh === "dsh" ? "dsh.cmd" : dsh, ["--profile", assertProfile(options.profile ?? "web"), "--dump-config"], {
|
|
303
|
+
encoding: "utf8",
|
|
304
|
+
env: { ...process.env, DSH_HOME: resolveDshHome(options.dshHome) },
|
|
305
|
+
...(platform === "win32" ? { shell: true } : {}),
|
|
306
|
+
});
|
|
307
|
+
let entries;
|
|
308
|
+
try {
|
|
309
|
+
entries = parseYaml(source, { customTags: [{ tag: "tag:yaml.org,2002:js", resolve: (value) => ({ expression: value }) }] });
|
|
310
|
+
}
|
|
311
|
+
catch (error) {
|
|
312
|
+
throw new Error(`cannot verify the composed default agent preset: ${errorMessage(error)}`);
|
|
313
|
+
}
|
|
314
|
+
const registries = [];
|
|
315
|
+
const visit = (rows) => {
|
|
316
|
+
if (!Array.isArray(rows))
|
|
317
|
+
return;
|
|
318
|
+
for (const row of rows) {
|
|
319
|
+
if (!isRecord(row))
|
|
320
|
+
continue;
|
|
321
|
+
if (row.name === "@deepseek-ai/dsh-agent-preset-registry")
|
|
322
|
+
registries.push(row);
|
|
323
|
+
if (row.group === true)
|
|
324
|
+
visit(row.config);
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
visit(entries);
|
|
328
|
+
const row = registries.length === 1 ? registries[0] : undefined;
|
|
329
|
+
const config = row && isRecord(row.config) ? row.config : undefined;
|
|
330
|
+
if (!row || (row.disabled !== undefined && row.disabled !== false) || !config
|
|
331
|
+
|| typeof config.default !== "string"
|
|
332
|
+
|| (config.selectedDefault != null && typeof config.selectedDefault !== "string")
|
|
333
|
+
|| (config.modeSelectionEnabled !== undefined && typeof config.modeSelectionEnabled !== "boolean")) {
|
|
334
|
+
throw new Error("cannot determine the effective default agent preset; resolve the registry configuration before uninstalling");
|
|
335
|
+
}
|
|
336
|
+
const selected = config.modeSelectionEnabled === false
|
|
337
|
+
? config.default : config.selectedDefault ?? config.default;
|
|
338
|
+
if (selected === ODAI_PRESET_ID) {
|
|
339
|
+
throw new Error(`refusing to remove the default agent preset ${ODAI_PRESET_ID}; choose another default preset in DSH first`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
266
342
|
async function acquireControlCenterOperation(dshHome, profile) {
|
|
267
343
|
await assertNoSymlinkDescendants(dshHome, "odai/locks");
|
|
268
344
|
const lockRoot = resolve(dshHome, "odai", "locks");
|
|
@@ -306,7 +382,7 @@ async function installAgentControlCenterUnderLock(options) {
|
|
|
306
382
|
runPluginCommand("add", packageSpec, options);
|
|
307
383
|
const installed = await inspectAgentControlCenter(options);
|
|
308
384
|
if (installed.status !== "current" || !installed.dependency) {
|
|
309
|
-
throw new Error(`DSH plugin manager did not install the exact Agent
|
|
385
|
+
throw new Error(`DSH plugin manager did not install the exact Odai Agent bundle: ${installed.issues.join("; ") || installed.status}`);
|
|
310
386
|
}
|
|
311
387
|
const operation = current.status === "absent"
|
|
312
388
|
? "installed"
|
|
@@ -343,6 +419,7 @@ export async function uninstallAgentControlCenter(options = {}) {
|
|
|
343
419
|
if (current.status === "partial-drift") {
|
|
344
420
|
throw new Error(`refusing to remove partially owned Control Center profile state at ${current.target}: ${current.issues.join("; ")}`);
|
|
345
421
|
}
|
|
422
|
+
await assertOdaiIsNotProfileDefault(operationOptions);
|
|
346
423
|
const before = await captureProfile(current.target);
|
|
347
424
|
try {
|
|
348
425
|
runPluginCommand("remove", packageMetadata.name, operationOptions);
|