@ran-sh/dsh-crew 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +16 -16
- package/.claude-plugin/plugin.json +14 -14
- package/LICENSE +21 -21
- package/README.de.md +359 -359
- package/README.es.md +359 -359
- package/README.fr.md +359 -359
- package/README.hi.md +359 -359
- package/README.id.md +359 -359
- package/README.ja.md +359 -359
- package/README.ko.md +359 -359
- package/README.md +126 -126
- package/README.pt.md +359 -359
- package/README.ru.md +359 -359
- package/README.th.md +359 -359
- package/README.tr.md +359 -359
- package/README.vi.md +359 -359
- package/README.zh-TW.md +359 -359
- package/README.zh.md +116 -116
- package/agents/ds-flash.md +24 -24
- package/agents/ds-pro.md +24 -24
- package/agents/ds-reviewer.md +23 -23
- package/agents/ds-worker.md +23 -23
- package/bin/dsh-crew.mjs +16 -16
- package/codex/agents/ds-flash.toml +34 -34
- package/codex/agents/ds-pro.toml +34 -34
- package/codex/agents/ds-reviewer.toml +32 -32
- package/codex/agents/ds-worker.toml +32 -32
- package/codex/prompts/dsh-config.md +19 -19
- package/codex/prompts/dsh-status.md +5 -5
- package/commands/config.md +23 -23
- package/commands/off.md +5 -5
- package/commands/on.md +5 -5
- package/commands/status.md +9 -9
- package/cordis.patch.yml +4 -4
- package/docs/gpt-relay-extension.md +103 -103
- package/docs/installation.md +138 -138
- package/docs/job-contracts.md +103 -103
- package/docs/readiness-matrix.md +85 -85
- package/docs/ui-surfaces.md +107 -107
- package/official-web-bridge/cordis.patch.yml +4 -4
- package/official-web-bridge/entry.mjs +1 -1
- package/official-web-bridge/overlay-entry.mjs +59 -59
- package/official-web-bridge/package.json +25 -25
- package/package.json +3 -2
- package/scripts/build-client.mjs +49 -49
- package/scripts/live-crew-smoke.mjs +39 -39
- package/scripts/live-policy-matrix.mjs +177 -177
- package/scripts/policy-probe.mjs +101 -101
- package/scripts/remove-legacy-official-bridge.ps1 +89 -89
- package/scripts/setup.mjs +393 -393
- package/scripts/smoke-real.mjs +110 -110
- package/scripts/smoke.mjs +78 -78
- package/scripts/verify-crew-ui-polish.mjs +145 -145
- package/scripts/verify-history-ui.mjs +97 -97
- package/scripts/verify-installer-fix.mjs +26 -26
- package/scripts/verify-npm-install.mjs +311 -311
- package/scripts/verify-official-bridge-e2e.mjs +192 -192
- package/src/adaptive-routing.mjs +260 -260
- package/src/client/activation-summary.tsx +64 -64
- package/src/client/collapsible-sections.mjs +55 -55
- package/src/client/history-panel.tsx +108 -108
- package/src/client/host-readiness.mjs +71 -71
- package/src/client/index.tsx +1711 -1711
- package/src/client/model-callability-view.mjs +17 -17
- package/src/client/panel-chrome.tsx +40 -40
- package/src/client/quick-entry.tsx +10 -10
- package/src/client/quick-panel.tsx +275 -275
- package/src/client/readiness-envelope.mjs +34 -34
- package/src/client/surface-detection.mjs +43 -43
- package/src/config-readiness.mjs +226 -226
- package/src/credential-reference.mjs +38 -38
- package/src/delivery.mjs +205 -205
- package/src/dsh-cli-runtime.mjs +1021 -1021
- package/src/dsh-cohort.mjs +20 -20
- package/src/extension-contract.mjs +104 -104
- package/src/failure-classification.mjs +201 -201
- package/src/history/admission-gate.mjs +67 -67
- package/src/history/archive-store.mjs +272 -272
- package/src/history/cleanup-plan.mjs +89 -89
- package/src/history/http.mjs +32 -32
- package/src/history/operation.mjs +86 -86
- package/src/history/runner-detach.mjs +34 -34
- package/src/history/runner.mjs +52 -52
- package/src/history/runtime.mjs +36 -36
- package/src/history/service.mjs +177 -177
- package/src/history/state.mjs +27 -27
- package/src/hub/entry.mjs +104 -104
- package/src/hub/index.mjs +2694 -2694
- package/src/hub-client.mjs +154 -154
- package/src/hub-compatibility.mjs +42 -42
- package/src/i18n.mjs +19 -19
- package/src/information-flow.mjs +67 -67
- package/src/install/cli.mjs +28 -28
- package/src/install/install-legacy.mjs +711 -711
- package/src/install/install.mjs +483 -483
- package/src/install/npx-lifecycle.mjs +3456 -3456
- package/src/install/official-frontend-assets.mjs +78 -78
- package/src/install/official-web.mjs +95 -95
- package/src/install/payload-content.mjs +88 -88
- package/src/install/windows-startup.mjs +236 -236
- package/src/install/windows-supervisor-adapter.mjs +443 -443
- package/src/install/windows-supervisor-lifecycle.mjs +782 -782
- package/src/install/zcode.mjs +397 -397
- package/src/job-contracts.mjs +255 -255
- package/src/local-request-guard.mjs +60 -60
- package/src/mcp-runtime.mjs +340 -340
- package/src/model-callability-contract.mjs +79 -79
- package/src/model-catalog.mjs +180 -180
- package/src/model-routing.mjs +586 -586
- package/src/model-schedule.mjs +207 -207
- package/src/official-web-bridge.mjs +447 -447
- package/src/policy.mjs +235 -235
- package/src/provider-delete-adapters.mjs +1934 -1934
- package/src/provider-health.mjs +130 -130
- package/src/provider-inventory.mjs +182 -182
- package/src/provider-layer-migration-adapters.mjs +759 -759
- package/src/provider-layer-migration.mjs +198 -198
- package/src/provider-lifecycle-state.mjs +103 -103
- package/src/provider-lifecycle.mjs +252 -252
- package/src/provider-profile-store.mjs +390 -390
- package/src/provider-settings-store.mjs +633 -633
- package/src/provider-store-lock.mjs +67 -67
- package/src/readiness-matrix.mjs +181 -181
- package/src/removable-waiter.mjs +29 -29
- package/src/role-profiles.mjs +107 -107
- package/src/runtime-controls.mjs +84 -84
- package/src/runtime-identity-contract.mjs +34 -34
- package/src/runtime-identity.mjs +235 -235
- package/src/runtime-readiness-snapshot.mjs +285 -285
- package/src/server.mjs +581 -581
- package/src/session-origins.mjs +60 -60
- package/src/standalone-sdk.mjs +23 -23
- package/src/status-shard.mjs +63 -63
- package/src/structured-error-code.mjs +38 -38
- package/src/supervisor/restart-request.mjs +256 -256
- package/src/workflow-runtime.mjs +739 -739
- package/src/workflow.mjs +155 -155
- package/src/workspace-audit.mjs +231 -231
- package/src/workspace-context.mjs +146 -146
- package/src/workspace-isolation.mjs +463 -455
- package/src/workspace-readiness.mjs +32 -32
- package/statusline/statusline.sh +14 -14
- package/statusline/worker-segment.sh +35 -35
- package/windows/start-dsh-crew.cmd +57 -57
- package/windows/start-dsh-crew.ps1 +1302 -1302
- package/windows/supervisor-control.ps1 +467 -467
- package/worker.cordis.yml +67 -67
- package/zcode/agents/ds-reviewer.md +31 -31
- package/zcode/agents/ds-worker.md +31 -31
- package/zcode/commands/dsh-config.md +17 -17
- package/zcode/commands/dsh-status.md +5 -5
package/docs/readiness-matrix.md
CHANGED
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
# DSH Crew Readiness Matrix
|
|
2
|
-
|
|
3
|
-
The readiness matrix is a conservative diagnostic surface for release and environment confidence. Its primary rule is simple:
|
|
4
|
-
|
|
5
|
-
> Missing evidence is never PASS.
|
|
6
|
-
|
|
7
|
-
The matrix is emitted by `hubStatus()` and is therefore visible inside the existing `dsh_worker_config` response under `hub_compatibility.readiness_matrix`.
|
|
8
|
-
|
|
9
|
-
## Statuses
|
|
10
|
-
|
|
11
|
-
- `PASS` — direct evidence confirms the row.
|
|
12
|
-
- `FAIL` — a check actually ran and produced an incompatible or failed result.
|
|
13
|
-
- `BLOCKED` — the check could not run because required infrastructure or authorization was unavailable.
|
|
14
|
-
- `SKIP` — the row is intentionally not applicable for the active policy/path.
|
|
15
|
-
- `NOT_RUN` — no trusted evidence has been supplied for the row.
|
|
16
|
-
|
|
17
|
-
`BLOCKED` and `SKIP` are not failures. `NOT_RUN` is not success.
|
|
18
|
-
|
|
19
|
-
## Evidence classes
|
|
20
|
-
|
|
21
|
-
The matrix separates three kinds of evidence:
|
|
22
|
-
|
|
23
|
-
1. `live-runtime` — facts the current process can directly observe, such as Hub reachability and protocol compatibility.
|
|
24
|
-
2. `ci` — platform validation such as Linux deterministic, Windows regressions, and future macOS smoke.
|
|
25
|
-
3. `real-execution` — provider/model and workflow behavior that requires a genuine DSH execution.
|
|
26
|
-
|
|
27
|
-
Live checks are populated automatically. The config report also consumes the
|
|
28
|
-
compatible Hub's bounded job registry, so a completed Worker or Reviewer can
|
|
29
|
-
promote the corresponding generic real-execution row. Other CI and execution
|
|
30
|
-
rows remain `NOT_RUN` until a trusted higher layer supplies explicit evidence.
|
|
31
|
-
|
|
32
|
-
## Target rows
|
|
33
|
-
|
|
34
|
-
- `linux_deterministic`
|
|
35
|
-
- `windows_regressions`
|
|
36
|
-
- `macos_smoke`
|
|
37
|
-
- `hub_compatibility`
|
|
38
|
-
- `provider_catalog`
|
|
39
|
-
- `provider_health`
|
|
40
|
-
- `reviewer_health`
|
|
41
|
-
- `model_execution`
|
|
42
|
-
- `deepseek_flash`
|
|
43
|
-
- `deepseek_pro`
|
|
44
|
-
- `opencode_go_mimo_qwen`
|
|
45
|
-
- `reviewer_pipeline`
|
|
46
|
-
- `cancellation_timeout_escalation`
|
|
47
|
-
- `standalone_official`
|
|
48
|
-
|
|
49
|
-
`provider_health` and `reviewer_health` describe only the currently resolved
|
|
50
|
-
Worker and Reviewer routes. A fresh negative observation overrides historical
|
|
51
|
-
success; unrelated providers and stale observations do not. Historical jobs
|
|
52
|
-
count only when their provider/model matches the corresponding current route,
|
|
53
|
-
with escalation evidence matched against the current escalation route.
|
|
54
|
-
|
|
55
|
-
## Provider/catalog rule
|
|
56
|
-
|
|
57
|
-
The Hub client does not know the active worker provider mode, so its embedded matrix leaves `provider_catalog` as `NOT_RUN` with `PROVIDER_MODE_UNKNOWN` rather than guessing.
|
|
58
|
-
|
|
59
|
-
When a higher layer knows the provider mode and has actually read the Harness catalog, it may build a more specific matrix:
|
|
60
|
-
|
|
61
|
-
- DeepSeek Official strict mode: catalog row may be `SKIP` / `PROVIDER_CATALOG_NOT_REQUIRED`.
|
|
62
|
-
- Follow-DSH with successful catalog read: `PASS` / `PROVIDER_CATALOG_RESOLVED`.
|
|
63
|
-
- Follow-DSH with an attempted but failed catalog read: `FAIL` / `PROVIDER_CATALOG_UNAVAILABLE`.
|
|
64
|
-
- Hub unavailable/incompatible before catalog access: `BLOCKED`, not `FAIL`.
|
|
65
|
-
|
|
66
|
-
## Credential safety
|
|
67
|
-
|
|
68
|
-
The matrix never reads or returns credential values, provider configuration payloads, quota data, pricing, cookies, tokens, or raw exception dumps. The standalone row defaults to `NOT_RUN` / `CREDENTIAL_STATUS_NOT_PROBED` unless an authorized real-environment validation explicitly reports evidence.
|
|
69
|
-
|
|
70
|
-
## Trusted evidence
|
|
71
|
-
|
|
72
|
-
`buildReadinessMatrix()` accepts an optional evidence map so CI/report aggregation can be added later without changing row semantics. Evidence can set only the existing status vocabulary. Invalid statuses are ignored rather than broadening the contract.
|
|
73
|
-
|
|
74
|
-
An evidence record may contain:
|
|
75
|
-
|
|
76
|
-
```json
|
|
77
|
-
{
|
|
78
|
-
"status": "PASS",
|
|
79
|
-
"reason_code": "CI_GREEN",
|
|
80
|
-
"evidence_source": "github-actions",
|
|
81
|
-
"evidence_ref": "run-123"
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
The matrix does not fetch or trust arbitrary remote data by itself. Loading and authenticating an evidence source is the responsibility of the higher layer that calls the builder.
|
|
1
|
+
# DSH Crew Readiness Matrix
|
|
2
|
+
|
|
3
|
+
The readiness matrix is a conservative diagnostic surface for release and environment confidence. Its primary rule is simple:
|
|
4
|
+
|
|
5
|
+
> Missing evidence is never PASS.
|
|
6
|
+
|
|
7
|
+
The matrix is emitted by `hubStatus()` and is therefore visible inside the existing `dsh_worker_config` response under `hub_compatibility.readiness_matrix`.
|
|
8
|
+
|
|
9
|
+
## Statuses
|
|
10
|
+
|
|
11
|
+
- `PASS` — direct evidence confirms the row.
|
|
12
|
+
- `FAIL` — a check actually ran and produced an incompatible or failed result.
|
|
13
|
+
- `BLOCKED` — the check could not run because required infrastructure or authorization was unavailable.
|
|
14
|
+
- `SKIP` — the row is intentionally not applicable for the active policy/path.
|
|
15
|
+
- `NOT_RUN` — no trusted evidence has been supplied for the row.
|
|
16
|
+
|
|
17
|
+
`BLOCKED` and `SKIP` are not failures. `NOT_RUN` is not success.
|
|
18
|
+
|
|
19
|
+
## Evidence classes
|
|
20
|
+
|
|
21
|
+
The matrix separates three kinds of evidence:
|
|
22
|
+
|
|
23
|
+
1. `live-runtime` — facts the current process can directly observe, such as Hub reachability and protocol compatibility.
|
|
24
|
+
2. `ci` — platform validation such as Linux deterministic, Windows regressions, and future macOS smoke.
|
|
25
|
+
3. `real-execution` — provider/model and workflow behavior that requires a genuine DSH execution.
|
|
26
|
+
|
|
27
|
+
Live checks are populated automatically. The config report also consumes the
|
|
28
|
+
compatible Hub's bounded job registry, so a completed Worker or Reviewer can
|
|
29
|
+
promote the corresponding generic real-execution row. Other CI and execution
|
|
30
|
+
rows remain `NOT_RUN` until a trusted higher layer supplies explicit evidence.
|
|
31
|
+
|
|
32
|
+
## Target rows
|
|
33
|
+
|
|
34
|
+
- `linux_deterministic`
|
|
35
|
+
- `windows_regressions`
|
|
36
|
+
- `macos_smoke`
|
|
37
|
+
- `hub_compatibility`
|
|
38
|
+
- `provider_catalog`
|
|
39
|
+
- `provider_health`
|
|
40
|
+
- `reviewer_health`
|
|
41
|
+
- `model_execution`
|
|
42
|
+
- `deepseek_flash`
|
|
43
|
+
- `deepseek_pro`
|
|
44
|
+
- `opencode_go_mimo_qwen`
|
|
45
|
+
- `reviewer_pipeline`
|
|
46
|
+
- `cancellation_timeout_escalation`
|
|
47
|
+
- `standalone_official`
|
|
48
|
+
|
|
49
|
+
`provider_health` and `reviewer_health` describe only the currently resolved
|
|
50
|
+
Worker and Reviewer routes. A fresh negative observation overrides historical
|
|
51
|
+
success; unrelated providers and stale observations do not. Historical jobs
|
|
52
|
+
count only when their provider/model matches the corresponding current route,
|
|
53
|
+
with escalation evidence matched against the current escalation route.
|
|
54
|
+
|
|
55
|
+
## Provider/catalog rule
|
|
56
|
+
|
|
57
|
+
The Hub client does not know the active worker provider mode, so its embedded matrix leaves `provider_catalog` as `NOT_RUN` with `PROVIDER_MODE_UNKNOWN` rather than guessing.
|
|
58
|
+
|
|
59
|
+
When a higher layer knows the provider mode and has actually read the Harness catalog, it may build a more specific matrix:
|
|
60
|
+
|
|
61
|
+
- DeepSeek Official strict mode: catalog row may be `SKIP` / `PROVIDER_CATALOG_NOT_REQUIRED`.
|
|
62
|
+
- Follow-DSH with successful catalog read: `PASS` / `PROVIDER_CATALOG_RESOLVED`.
|
|
63
|
+
- Follow-DSH with an attempted but failed catalog read: `FAIL` / `PROVIDER_CATALOG_UNAVAILABLE`.
|
|
64
|
+
- Hub unavailable/incompatible before catalog access: `BLOCKED`, not `FAIL`.
|
|
65
|
+
|
|
66
|
+
## Credential safety
|
|
67
|
+
|
|
68
|
+
The matrix never reads or returns credential values, provider configuration payloads, quota data, pricing, cookies, tokens, or raw exception dumps. The standalone row defaults to `NOT_RUN` / `CREDENTIAL_STATUS_NOT_PROBED` unless an authorized real-environment validation explicitly reports evidence.
|
|
69
|
+
|
|
70
|
+
## Trusted evidence
|
|
71
|
+
|
|
72
|
+
`buildReadinessMatrix()` accepts an optional evidence map so CI/report aggregation can be added later without changing row semantics. Evidence can set only the existing status vocabulary. Invalid statuses are ignored rather than broadening the contract.
|
|
73
|
+
|
|
74
|
+
An evidence record may contain:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"status": "PASS",
|
|
79
|
+
"reason_code": "CI_GREEN",
|
|
80
|
+
"evidence_source": "github-actions",
|
|
81
|
+
"evidence_ref": "run-123"
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The matrix does not fetch or trust arbitrary remote data by itself. Loading and authenticating an evidence source is the responsibility of the higher layer that calls the builder.
|
package/docs/ui-surfaces.md
CHANGED
|
@@ -1,107 +1,107 @@
|
|
|
1
|
-
# 3210 and 3080 UI responsibilities
|
|
2
|
-
|
|
3
|
-
The desktop entry opens the official frontend with a simple Crew panel on 3080. Crew runs hidden on 3210;
|
|
4
|
-
its web page is an explicit advanced-settings entry, not the default browser tab.
|
|
5
|
-
The background watcher manages only 3210. Desktop launch may start the official
|
|
6
|
-
program but never uses it as authority to restart, update or roll back Crew.
|
|
7
|
-
The simple panel is mounted through a `--patch` file under the Crew-owned home,
|
|
8
|
-
with immutable frontend revisions kept independently of backend release cleanup.
|
|
9
|
-
The 3080 button opens 3210; the 3210 button opens 3080.
|
|
10
|
-
|
|
11
|
-
DSH Crew is a plugin attached to the official DeepSeek Harness. Current installs
|
|
12
|
-
register it in a dedicated official Harness `dsh-crew` profile whose native 3210
|
|
13
|
-
page is the canonical full Crew control and execution surface. An older
|
|
14
|
-
installation may still expose a narrow 3080 quick-controls bundle, but that
|
|
15
|
-
legacy surface is external to Crew ownership, optional, and deprecated. Crew
|
|
16
|
-
treats the official profile as read-only. The legacy surface
|
|
17
|
-
never starts, owns, or supervises 3210.
|
|
18
|
-
|
|
19
|
-
## 3210: official Harness profile with the Crew plugin
|
|
20
|
-
|
|
21
|
-
The Crew-owned official Harness `dsh-crew` profile on `127.0.0.1:3210` loads the
|
|
22
|
-
DSH Crew plugin and owns day-to-day Crew management and model execution:
|
|
23
|
-
|
|
24
|
-
- Crew workflow and global enablement
|
|
25
|
-
- Worker and Reviewer policy
|
|
26
|
-
- model priority, fallback, review, and adaptive routing
|
|
27
|
-
- multimodal (vision/imagegen) capability switches
|
|
28
|
-
- providers lifecycle (migrate/delete/rollback/quarantine)
|
|
29
|
-
- credential references lifecycle
|
|
30
|
-
- workspaces, presets, jobs
|
|
31
|
-
- installation integrations (Codex, Claude, ZCode)
|
|
32
|
-
- task status and bounded model-invocation summaries
|
|
33
|
-
|
|
34
|
-
Bundle: `lib/client.js` (module `@ran-sh/dsh-crew`), built from
|
|
35
|
-
`src/client/entry.tsx`.
|
|
36
|
-
|
|
37
|
-
## 3080: official frontend; optional legacy Crew controls
|
|
38
|
-
|
|
39
|
-
An older official Harness `web` profile on `127.0.0.1:3080` may still host a
|
|
40
|
-
NARROW quick-controls card — and nothing else:
|
|
41
|
-
|
|
42
|
-
- master switch (`subagents_enabled`)
|
|
43
|
-
- Flash / Pro model priority lists (add/remove/reorder only)
|
|
44
|
-
- vision / imagegen toggles + providers (restart-pending flow)
|
|
45
|
-
- deep link to the 3210 full control plane (`http://127.0.0.1:3210/`)
|
|
46
|
-
|
|
47
|
-
Bundle: `official-web-bridge/lib/client.js` (module
|
|
48
|
-
`@ran-sh/dsh-crew-web-bridge`), built from `src/client/quick-entry.tsx`.
|
|
49
|
-
It physically contains none of the full control-plane code (no credential
|
|
50
|
-
purge, no provider delete/migration, no install integration).
|
|
51
|
-
|
|
52
|
-
The 3080 bridge proxies ONLY two exact endpoints to 3210:
|
|
53
|
-
`quick-config` and `quick-status`. Restart and rollback belong to 3210;
|
|
54
|
-
the quick panel links there when needed. Everything else on the Crew namespace is 404 on
|
|
55
|
-
3080, and `/supervisor/restart` returns 410 Gone pointing at 3210.
|
|
56
|
-
|
|
57
|
-
The official `~/.dsh` tree is strictly read-only for Crew; the 3080 quick
|
|
58
|
-
surface itself is optional — Crew works fully with 3080 closed.
|
|
59
|
-
|
|
60
|
-
## UNKNOWN: diagnostics only
|
|
61
|
-
|
|
62
|
-
Unknown surfaces render diagnostics and never gain write authority.
|
|
63
|
-
|
|
64
|
-
## Surface detection and failure behavior
|
|
65
|
-
|
|
66
|
-
The client does not infer responsibility from a hard-coded browser port. It
|
|
67
|
-
uses two same-origin, structured signals:
|
|
68
|
-
|
|
69
|
-
1. `/_dsh/dsh-crew/bridge-status` identifies the official quick bridge.
|
|
70
|
-
2. `/_dsh/dsh-crew/runtime` identifies the native Crew-owned runtime.
|
|
71
|
-
|
|
72
|
-
The bridge signal wins on 3080 because the proxied runtime response correctly
|
|
73
|
-
describes the 3210 backend. If neither contract can be verified, the client
|
|
74
|
-
fails closed to the diagnostics view. Missing evidence never enables the
|
|
75
|
-
full control plane and never becomes `READY`.
|
|
76
|
-
|
|
77
|
-
The split changes presentation only. Crew state, credentials, routing policy,
|
|
78
|
-
and model execution remain isolated under the Crew-owned home and profile.
|
|
79
|
-
|
|
80
|
-
## Local trust model
|
|
81
|
-
|
|
82
|
-
Both surfaces listen on loopback only and share one request guard
|
|
83
|
-
(`src/local-request-guard.mjs`). A request is trusted when it proves, in
|
|
84
|
-
order: (1) the TCP peer is a loopback address, (2) the `Host` header names a
|
|
85
|
-
loopback host, (3) browser fetch-metadata (`Sec-Fetch-Site`) is `same-origin`
|
|
86
|
-
or absent/`none`, and (4) when an `Origin` header is present it names a
|
|
87
|
-
loopback host — on the 3080 bridge the `Origin` authority must additionally
|
|
88
|
-
equal the request authority, while the 3210 hub accepts any loopback origin
|
|
89
|
-
because the 3080 panel calls it cross-port.
|
|
90
|
-
|
|
91
|
-
There is deliberately no bearer token: every process running as the local
|
|
92
|
-
user is inside the trust boundary and may control Crew. The guards keep
|
|
93
|
-
off-machine browsers, DNS-rebinding pages, and cross-machine proxies out;
|
|
94
|
-
they do not authenticate local users. If a deployment ever needs to separate
|
|
95
|
-
local principals, add a per-install random token to state-changing calls and
|
|
96
|
-
inject it server-side in the bridge — do not use browser `Origin` as
|
|
97
|
-
authentication.
|
|
98
|
-
|
|
99
|
-
## Process ownership
|
|
100
|
-
|
|
101
|
-
The Windows launcher supervisor (`windows/start-dsh-crew.ps1` watch mode) is
|
|
102
|
-
the ONLY process authority for the Crew-owned 3210 service. The official 3080
|
|
103
|
-
surface never starts, owns, or supervises 3210. Restart and maintenance go
|
|
104
|
-
through durable request files the hub writes and the launcher executes
|
|
105
|
-
(`supervisor/restart-request.mjs`). Ordinary backend startup does not probe the
|
|
106
|
-
legacy bridge. Desktop opening uses the official process and root HTTP response,
|
|
107
|
-
independently of whether that process has any Crew plugin installed.
|
|
1
|
+
# 3210 and 3080 UI responsibilities
|
|
2
|
+
|
|
3
|
+
The desktop entry opens the official frontend with a simple Crew panel on 3080. Crew runs hidden on 3210;
|
|
4
|
+
its web page is an explicit advanced-settings entry, not the default browser tab.
|
|
5
|
+
The background watcher manages only 3210. Desktop launch may start the official
|
|
6
|
+
program but never uses it as authority to restart, update or roll back Crew.
|
|
7
|
+
The simple panel is mounted through a `--patch` file under the Crew-owned home,
|
|
8
|
+
with immutable frontend revisions kept independently of backend release cleanup.
|
|
9
|
+
The 3080 button opens 3210; the 3210 button opens 3080.
|
|
10
|
+
|
|
11
|
+
DSH Crew is a plugin attached to the official DeepSeek Harness. Current installs
|
|
12
|
+
register it in a dedicated official Harness `dsh-crew` profile whose native 3210
|
|
13
|
+
page is the canonical full Crew control and execution surface. An older
|
|
14
|
+
installation may still expose a narrow 3080 quick-controls bundle, but that
|
|
15
|
+
legacy surface is external to Crew ownership, optional, and deprecated. Crew
|
|
16
|
+
treats the official profile as read-only. The legacy surface
|
|
17
|
+
never starts, owns, or supervises 3210.
|
|
18
|
+
|
|
19
|
+
## 3210: official Harness profile with the Crew plugin
|
|
20
|
+
|
|
21
|
+
The Crew-owned official Harness `dsh-crew` profile on `127.0.0.1:3210` loads the
|
|
22
|
+
DSH Crew plugin and owns day-to-day Crew management and model execution:
|
|
23
|
+
|
|
24
|
+
- Crew workflow and global enablement
|
|
25
|
+
- Worker and Reviewer policy
|
|
26
|
+
- model priority, fallback, review, and adaptive routing
|
|
27
|
+
- multimodal (vision/imagegen) capability switches
|
|
28
|
+
- providers lifecycle (migrate/delete/rollback/quarantine)
|
|
29
|
+
- credential references lifecycle
|
|
30
|
+
- workspaces, presets, jobs
|
|
31
|
+
- installation integrations (Codex, Claude, ZCode)
|
|
32
|
+
- task status and bounded model-invocation summaries
|
|
33
|
+
|
|
34
|
+
Bundle: `lib/client.js` (module `@ran-sh/dsh-crew`), built from
|
|
35
|
+
`src/client/entry.tsx`.
|
|
36
|
+
|
|
37
|
+
## 3080: official frontend; optional legacy Crew controls
|
|
38
|
+
|
|
39
|
+
An older official Harness `web` profile on `127.0.0.1:3080` may still host a
|
|
40
|
+
NARROW quick-controls card — and nothing else:
|
|
41
|
+
|
|
42
|
+
- master switch (`subagents_enabled`)
|
|
43
|
+
- Flash / Pro model priority lists (add/remove/reorder only)
|
|
44
|
+
- vision / imagegen toggles + providers (restart-pending flow)
|
|
45
|
+
- deep link to the 3210 full control plane (`http://127.0.0.1:3210/`)
|
|
46
|
+
|
|
47
|
+
Bundle: `official-web-bridge/lib/client.js` (module
|
|
48
|
+
`@ran-sh/dsh-crew-web-bridge`), built from `src/client/quick-entry.tsx`.
|
|
49
|
+
It physically contains none of the full control-plane code (no credential
|
|
50
|
+
purge, no provider delete/migration, no install integration).
|
|
51
|
+
|
|
52
|
+
The 3080 bridge proxies ONLY two exact endpoints to 3210:
|
|
53
|
+
`quick-config` and `quick-status`. Restart and rollback belong to 3210;
|
|
54
|
+
the quick panel links there when needed. Everything else on the Crew namespace is 404 on
|
|
55
|
+
3080, and `/supervisor/restart` returns 410 Gone pointing at 3210.
|
|
56
|
+
|
|
57
|
+
The official `~/.dsh` tree is strictly read-only for Crew; the 3080 quick
|
|
58
|
+
surface itself is optional — Crew works fully with 3080 closed.
|
|
59
|
+
|
|
60
|
+
## UNKNOWN: diagnostics only
|
|
61
|
+
|
|
62
|
+
Unknown surfaces render diagnostics and never gain write authority.
|
|
63
|
+
|
|
64
|
+
## Surface detection and failure behavior
|
|
65
|
+
|
|
66
|
+
The client does not infer responsibility from a hard-coded browser port. It
|
|
67
|
+
uses two same-origin, structured signals:
|
|
68
|
+
|
|
69
|
+
1. `/_dsh/dsh-crew/bridge-status` identifies the official quick bridge.
|
|
70
|
+
2. `/_dsh/dsh-crew/runtime` identifies the native Crew-owned runtime.
|
|
71
|
+
|
|
72
|
+
The bridge signal wins on 3080 because the proxied runtime response correctly
|
|
73
|
+
describes the 3210 backend. If neither contract can be verified, the client
|
|
74
|
+
fails closed to the diagnostics view. Missing evidence never enables the
|
|
75
|
+
full control plane and never becomes `READY`.
|
|
76
|
+
|
|
77
|
+
The split changes presentation only. Crew state, credentials, routing policy,
|
|
78
|
+
and model execution remain isolated under the Crew-owned home and profile.
|
|
79
|
+
|
|
80
|
+
## Local trust model
|
|
81
|
+
|
|
82
|
+
Both surfaces listen on loopback only and share one request guard
|
|
83
|
+
(`src/local-request-guard.mjs`). A request is trusted when it proves, in
|
|
84
|
+
order: (1) the TCP peer is a loopback address, (2) the `Host` header names a
|
|
85
|
+
loopback host, (3) browser fetch-metadata (`Sec-Fetch-Site`) is `same-origin`
|
|
86
|
+
or absent/`none`, and (4) when an `Origin` header is present it names a
|
|
87
|
+
loopback host — on the 3080 bridge the `Origin` authority must additionally
|
|
88
|
+
equal the request authority, while the 3210 hub accepts any loopback origin
|
|
89
|
+
because the 3080 panel calls it cross-port.
|
|
90
|
+
|
|
91
|
+
There is deliberately no bearer token: every process running as the local
|
|
92
|
+
user is inside the trust boundary and may control Crew. The guards keep
|
|
93
|
+
off-machine browsers, DNS-rebinding pages, and cross-machine proxies out;
|
|
94
|
+
they do not authenticate local users. If a deployment ever needs to separate
|
|
95
|
+
local principals, add a per-install random token to state-changing calls and
|
|
96
|
+
inject it server-side in the bridge — do not use browser `Origin` as
|
|
97
|
+
authentication.
|
|
98
|
+
|
|
99
|
+
## Process ownership
|
|
100
|
+
|
|
101
|
+
The Windows launcher supervisor (`windows/start-dsh-crew.ps1` watch mode) is
|
|
102
|
+
the ONLY process authority for the Crew-owned 3210 service. The official 3080
|
|
103
|
+
surface never starts, owns, or supervises 3210. Restart and maintenance go
|
|
104
|
+
through durable request files the hub writes and the launcher executes
|
|
105
|
+
(`supervisor/restart-request.mjs`). Ordinary backend startup does not probe the
|
|
106
|
+
legacy bridge. Desktop opening uses the official process and root HTTP response,
|
|
107
|
+
independently of whether that process has any Crew plugin installed.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Lightweight official-web bridge. The full Crew Hub remains isolated on 3210.
|
|
2
|
-
- insert:
|
|
3
|
-
- id: dsh-crew-official-web-bridge
|
|
4
|
-
name: '@ran-sh/dsh-crew-web-bridge'
|
|
1
|
+
# Lightweight official-web bridge. The full Crew Hub remains isolated on 3210.
|
|
2
|
+
- insert:
|
|
3
|
+
- id: dsh-crew-official-web-bridge
|
|
4
|
+
name: '@ran-sh/dsh-crew-web-bridge'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { apply, registerOfficialWebBridge } from '../src/official-web-bridge.mjs';
|
|
1
|
+
export { apply, registerOfficialWebBridge } from '../src/official-web-bridge.mjs';
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
// UI-only overlay host. No process lifecycle, installer or profile mutations.
|
|
2
|
-
import { localRequestCore, originAuthorityMatches } from '../src/local-request-guard.mjs';
|
|
3
|
-
import { readFileSync } from 'node:fs';
|
|
4
|
-
|
|
5
|
-
const PREFIX = '/_dsh/dsh-crew';
|
|
6
|
-
const BACKEND = 'http://127.0.0.1:3210';
|
|
7
|
-
const REVISION = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).dshCrewFrontendRevision ?? null;
|
|
8
|
-
|
|
9
|
-
function trusted(req) {
|
|
10
|
-
return localRequestCore(req) && (req.headers.origin === undefined
|
|
11
|
-
|| originAuthorityMatches(req.headers.origin, req.headers.host));
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function send(res, status, body) {
|
|
15
|
-
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
|
|
16
|
-
res.end(JSON.stringify(body));
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export function registerFrontend(ctx, { fetchImpl = globalThis.fetch } = {}) {
|
|
20
|
-
return ctx.inject(['webServer'], ({ webServer }) => {
|
|
21
|
-
const disposers = [];
|
|
22
|
-
disposers.push(webServer.register({ kind: 'exact', path: `${PREFIX}/bridge-status`, handler(req, res) {
|
|
23
|
-
if (!trusted(req)) return send(res, 403, { ok: false, code: 'LOCAL_SAME_ORIGIN_ONLY' });
|
|
24
|
-
send(res, 200, { ok: true, surface: 'official-bridge', ui_role: 'quick-controls', frontend_revision: REVISION, full_control_plane_url: `${BACKEND}/` });
|
|
25
|
-
} }));
|
|
26
|
-
for (const suffix of ['/quick-config', '/quick-status']) {
|
|
27
|
-
disposers.push(webServer.register({ kind: 'exact', path: `${PREFIX}${suffix}`, async handler(req, res) {
|
|
28
|
-
if (!trusted(req)) return send(res, 403, { ok: false, code: 'LOCAL_SAME_ORIGIN_ONLY' });
|
|
29
|
-
const method = req.method ?? 'GET';
|
|
30
|
-
if (method !== 'GET' && !(suffix === '/quick-config' && method === 'POST')) return send(res, 405, { ok: false, code: 'METHOD_NOT_ALLOWED' });
|
|
31
|
-
try {
|
|
32
|
-
const identityResponse = await fetchImpl(`${BACKEND}${PREFIX}/runtime`, { signal: AbortSignal.timeout(2500) });
|
|
33
|
-
const identity = await identityResponse.json();
|
|
34
|
-
if (!identityResponse.ok || identity.ok !== true || identity.service !== 'dsh-crew-hub'
|
|
35
|
-
|| identity.profile !== 'dsh-crew' || identity.execution_plane !== 'hub-3210'
|
|
36
|
-
|| identity.listen_port !== 3210 || identity.protocol_version !== 1) throw new Error('incompatible backend');
|
|
37
|
-
const chunks = [];
|
|
38
|
-
let size = 0;
|
|
39
|
-
if (method === 'POST') for await (const chunk of req) {
|
|
40
|
-
size += chunk.length;
|
|
41
|
-
if (size > 64 * 1024) return send(res, 413, { ok: false, code: 'BODY_TOO_LARGE' });
|
|
42
|
-
chunks.push(Buffer.from(chunk));
|
|
43
|
-
}
|
|
44
|
-
const response = await fetchImpl(`${BACKEND}${PREFIX}${suffix}`, {
|
|
45
|
-
method, headers: { 'content-type': 'application/json' },
|
|
46
|
-
...(method === 'POST' ? { body: Buffer.concat(chunks) } : {}),
|
|
47
|
-
signal: AbortSignal.timeout(5000),
|
|
48
|
-
});
|
|
49
|
-
send(res, response.status, await response.json());
|
|
50
|
-
} catch {
|
|
51
|
-
send(res, 503, { ok: false, ready: false, code: 'CREW_BACKEND_UNAVAILABLE' });
|
|
52
|
-
}
|
|
53
|
-
} }));
|
|
54
|
-
}
|
|
55
|
-
return () => { for (const dispose of disposers) dispose?.(); };
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function apply(ctx) { registerFrontend(ctx); }
|
|
1
|
+
// UI-only overlay host. No process lifecycle, installer or profile mutations.
|
|
2
|
+
import { localRequestCore, originAuthorityMatches } from '../src/local-request-guard.mjs';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
const PREFIX = '/_dsh/dsh-crew';
|
|
6
|
+
const BACKEND = 'http://127.0.0.1:3210';
|
|
7
|
+
const REVISION = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).dshCrewFrontendRevision ?? null;
|
|
8
|
+
|
|
9
|
+
function trusted(req) {
|
|
10
|
+
return localRequestCore(req) && (req.headers.origin === undefined
|
|
11
|
+
|| originAuthorityMatches(req.headers.origin, req.headers.host));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function send(res, status, body) {
|
|
15
|
+
res.writeHead(status, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' });
|
|
16
|
+
res.end(JSON.stringify(body));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function registerFrontend(ctx, { fetchImpl = globalThis.fetch } = {}) {
|
|
20
|
+
return ctx.inject(['webServer'], ({ webServer }) => {
|
|
21
|
+
const disposers = [];
|
|
22
|
+
disposers.push(webServer.register({ kind: 'exact', path: `${PREFIX}/bridge-status`, handler(req, res) {
|
|
23
|
+
if (!trusted(req)) return send(res, 403, { ok: false, code: 'LOCAL_SAME_ORIGIN_ONLY' });
|
|
24
|
+
send(res, 200, { ok: true, surface: 'official-bridge', ui_role: 'quick-controls', frontend_revision: REVISION, full_control_plane_url: `${BACKEND}/` });
|
|
25
|
+
} }));
|
|
26
|
+
for (const suffix of ['/quick-config', '/quick-status']) {
|
|
27
|
+
disposers.push(webServer.register({ kind: 'exact', path: `${PREFIX}${suffix}`, async handler(req, res) {
|
|
28
|
+
if (!trusted(req)) return send(res, 403, { ok: false, code: 'LOCAL_SAME_ORIGIN_ONLY' });
|
|
29
|
+
const method = req.method ?? 'GET';
|
|
30
|
+
if (method !== 'GET' && !(suffix === '/quick-config' && method === 'POST')) return send(res, 405, { ok: false, code: 'METHOD_NOT_ALLOWED' });
|
|
31
|
+
try {
|
|
32
|
+
const identityResponse = await fetchImpl(`${BACKEND}${PREFIX}/runtime`, { signal: AbortSignal.timeout(2500) });
|
|
33
|
+
const identity = await identityResponse.json();
|
|
34
|
+
if (!identityResponse.ok || identity.ok !== true || identity.service !== 'dsh-crew-hub'
|
|
35
|
+
|| identity.profile !== 'dsh-crew' || identity.execution_plane !== 'hub-3210'
|
|
36
|
+
|| identity.listen_port !== 3210 || identity.protocol_version !== 1) throw new Error('incompatible backend');
|
|
37
|
+
const chunks = [];
|
|
38
|
+
let size = 0;
|
|
39
|
+
if (method === 'POST') for await (const chunk of req) {
|
|
40
|
+
size += chunk.length;
|
|
41
|
+
if (size > 64 * 1024) return send(res, 413, { ok: false, code: 'BODY_TOO_LARGE' });
|
|
42
|
+
chunks.push(Buffer.from(chunk));
|
|
43
|
+
}
|
|
44
|
+
const response = await fetchImpl(`${BACKEND}${PREFIX}${suffix}`, {
|
|
45
|
+
method, headers: { 'content-type': 'application/json' },
|
|
46
|
+
...(method === 'POST' ? { body: Buffer.concat(chunks) } : {}),
|
|
47
|
+
signal: AbortSignal.timeout(5000),
|
|
48
|
+
});
|
|
49
|
+
send(res, response.status, await response.json());
|
|
50
|
+
} catch {
|
|
51
|
+
send(res, 503, { ok: false, ready: false, code: 'CREW_BACKEND_UNAVAILABLE' });
|
|
52
|
+
}
|
|
53
|
+
} }));
|
|
54
|
+
}
|
|
55
|
+
return () => { for (const dispose of disposers) dispose?.(); };
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function apply(ctx) { registerFrontend(ctx); }
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ran-sh/dsh-crew-web-bridge",
|
|
3
|
-
"version": "0.3.8",
|
|
4
|
-
"private": true,
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./entry.mjs",
|
|
7
|
-
"exports": {
|
|
8
|
-
".": "./entry.mjs",
|
|
9
|
-
"./client": "./lib/client.js",
|
|
10
|
-
"./package.json": "./package.json"
|
|
11
|
-
},
|
|
12
|
-
"dsh": {
|
|
13
|
-
"bundle": {
|
|
14
|
-
"patch": "./cordis.patch.yml"
|
|
15
|
-
},
|
|
16
|
-
"client": {
|
|
17
|
-
"inject": [
|
|
18
|
-
"@deepseek-ai/dsh-client-ui-renderer",
|
|
19
|
-
"@deepseek-ai/dsh-client-locale",
|
|
20
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
21
|
-
],
|
|
22
|
-
"platform": "web"
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@ran-sh/dsh-crew-web-bridge",
|
|
3
|
+
"version": "0.3.8",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./entry.mjs",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./entry.mjs",
|
|
9
|
+
"./client": "./lib/client.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"dsh": {
|
|
13
|
+
"bundle": {
|
|
14
|
+
"patch": "./cordis.patch.yml"
|
|
15
|
+
},
|
|
16
|
+
"client": {
|
|
17
|
+
"inject": [
|
|
18
|
+
"@deepseek-ai/dsh-client-ui-renderer",
|
|
19
|
+
"@deepseek-ai/dsh-client-locale",
|
|
20
|
+
"@deepseek-ai/dsh-client-ui-settings"
|
|
21
|
+
],
|
|
22
|
+
"platform": "web"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ran-sh/dsh-crew",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./src/hub/entry.mjs",
|
|
6
6
|
"bin": {
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"build:client": "tsdown src/client/entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --clean --logLevel warn && tsdown src/client/quick-entry.tsx --format cjs --platform browser --target es2022 --tsconfig tsconfig.client.json --deps.never-bundle react --deps.never-bundle react/jsx-runtime --deps.never-bundle react-dom --deps.never-bundle react-dom/client --out-dir .client-build --no-clean --logLevel warn && node scripts/build-client.mjs",
|
|
30
30
|
"verify:npm-install": "node scripts/verify-npm-install.mjs",
|
|
31
31
|
"verify:npm-install:official": "node scripts/verify-npm-install.mjs --with-official-dsh",
|
|
32
|
-
"verify:official-bridge": "node scripts/verify-official-bridge-e2e.mjs --diagnostic-only"
|
|
32
|
+
"verify:official-bridge": "node scripts/verify-official-bridge-e2e.mjs --diagnostic-only",
|
|
33
|
+
"test": "node --test \"test/*.test.mjs\""
|
|
33
34
|
},
|
|
34
35
|
"dependencies": {
|
|
35
36
|
"@modelcontextprotocol/sdk": "^1.25.4",
|