@ran-sh/dsh-crew 1.0.3 → 1.1.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/codex/AGENTS.md CHANGED
@@ -1,92 +1,101 @@
1
- # Global capability-aware delegation policy
2
-
3
- The main Codex agent owns the user's task from planning through final delivery.
4
- DSH Crew is an execution and review capability that Codex may use after
5
- discovering what the current environment actually supports.
6
-
7
- ## Discover capabilities before delegation
8
-
9
- - Before delegating substantial work, query DSH Crew's authoritative live
10
- configuration, capability, and readiness surfaces.
11
- - Discover capabilities dynamically from the returned contracts. Do not rely
12
- on a hard-coded list of roles, models, providers, tools, modes, or optional
13
- features; newly added capabilities should be considered automatically.
14
- - For every relevant capability, respect its reported availability, activation
15
- state, invocation mode, constraints, dependencies, and readiness evidence.
16
- - Treat installed, configured, enabled, and callable as different states. Use a
17
- capability only when the complete live execution path is ready.
18
- - Keep the capability snapshot for the current plan, and refresh it after a
19
- relevant configuration change or an availability, routing, credential,
20
- compatibility, or activation failure.
21
- - If discovery is unavailable or evidence is incomplete, fail closed: do not
22
- invent capabilities or repeatedly dispatch blind retries. If DSH Crew was
23
- selected for the task, apply the operator decision gate below.
24
-
25
- ## Operator decision gate when DSH Crew is unavailable
26
-
27
- - Once Codex has selected DSH Crew for any work unit, any condition that makes
28
- the required Crew capability unavailable or non-callable is a mandatory
29
- pause point, regardless of cause.
30
- - At this pause point, do not continue implementation, silently fall back,
31
- choose another execution path, or repair/reconfigure DSH Crew without new
32
- operator direction. Perform only the read-only diagnosis needed to report
33
- the blocker accurately.
34
- - Report the unavailable capability, bounded reason and evidence, and completed
35
- work. Then wait for the operator to choose one direction:
36
- 1. Repair or restore DSH Crew, then continue through DSH Crew.
37
- 2. Do not repair DSH Crew; continue with the main Codex agent.
38
- - Resume only after the operator gives a new instruction. If repair is chosen,
39
- verify live capability again before dispatch. If local execution is chosen,
40
- state that the affected work is no longer independently delegated.
41
- - This gate applies only after DSH Crew has been selected or explicitly
42
- requested. It does not force a pause when initial planning decides DSH Crew
43
- provides no benefit and the task should remain with the main agent.
44
-
45
- ## Decide what to delegate
46
-
47
- - Decompose the request into bounded work units before choosing an executor.
48
- - Match each unit against discovered capabilities. Use DSH Crew only where it
49
- provides a clear execution, isolation, parallelism, specialization, or
50
- independent-review benefit.
51
- - Delegate the smallest coherent unit that can be completed and verified
52
- independently. Do not delegate an entire request merely because it is large.
53
- - Keep ambiguity, dependency ordering, cross-cutting decisions, conflict
54
- resolution, external side effects, final integration, and user communication
55
- in the main Codex agent.
56
- - Respect reported concurrency and isolation limits. Parallelize only
57
- independent units with explicit, non-overlapping ownership.
58
- - Simple questions, explanations, small read-only inspections, and genuinely
59
- trivial edits should normally remain in the main agent.
60
- - Explicit user instructions override default routing, but never safety or
61
- capability boundaries.
62
-
63
- ## Execute and verify
64
-
65
- - Give each delegated unit a concrete objective, owned scope, workspace
66
- context, constraints, and required validation evidence.
67
- - Prefer isolated execution for code changes when supported. Review work must
68
- remain read-only.
69
- - Consume compact structured results and canonical events. Do not move
70
- unbounded transcripts, raw provider payloads, credentials, or unnecessary
71
- patch content between agents.
72
- - The main agent must validate results, tests, changed scope, unresolved risks,
73
- and completion state before accepting delegated work.
74
-
75
- ## Review policy
76
-
77
- - Use available independent review for non-trivial code changes when its live
78
- invocation policy permits automatic use or the user requests manual use.
79
- - Never bypass a manual, disabled, unavailable, or restricted review boundary.
80
- - Treat requested changes, incomplete structured results, or missing direct
81
- evidence as not approved.
82
- - If selected DSH Crew review cannot run, apply the operator decision gate. The
83
- main agent may review locally only after the operator selects that path.
84
-
85
- ## Authority and completion
86
-
87
- - Delegation does not broaden authority. Publishing, pushing, messaging,
88
- credential changes, account actions, destructive operations, and other
89
- external effects still require authority from the user's request.
90
- - Do not present delegated work as complete until validation passes, structured
91
- results are complete, integration is checked, and permitted review
92
- requirements are satisfied or transparently reported as unavailable.
1
+ # Global capability-aware delegation policy
2
+
3
+ The main Codex agent owns the user's task from planning through final delivery.
4
+ DSH Crew is an execution and review capability that Codex may use after
5
+ discovering what the current environment actually supports.
6
+
7
+ ## Discover capabilities before delegation
8
+
9
+ - Before delegating substantial work, query DSH Crew's authoritative live
10
+ configuration, capability, and readiness surfaces.
11
+ - Discover capabilities dynamically from the returned contracts. Do not rely
12
+ on a hard-coded list of roles, models, providers, tools, modes, or optional
13
+ features; newly added capabilities should be considered automatically.
14
+ - For every relevant capability, respect its reported availability, activation
15
+ state, invocation mode, constraints, dependencies, and readiness evidence.
16
+ - Treat installed, configured, enabled, and callable as different states. Use a
17
+ capability only when the complete live execution path is ready.
18
+ - Keep the capability snapshot for the current plan, and refresh it after a
19
+ relevant configuration change or an availability, routing, credential,
20
+ compatibility, or activation failure.
21
+ - If discovery is unavailable or evidence is incomplete, fail closed: do not
22
+ invent capabilities or repeatedly dispatch blind retries. If DSH Crew was
23
+ selected for the task, apply the operator decision gate below.
24
+
25
+ ## Operator decision gate when DSH Crew is unavailable
26
+
27
+ - Once Codex has selected DSH Crew for any work unit, any condition that makes
28
+ the required Crew capability unavailable or non-callable is a mandatory
29
+ pause point, regardless of cause.
30
+ - At this pause point, do not continue implementation, silently fall back,
31
+ choose another execution path, or repair/reconfigure DSH Crew without new
32
+ operator direction. Perform only the read-only diagnosis needed to report
33
+ the blocker accurately.
34
+ - Report the unavailable capability, bounded reason and evidence, and completed
35
+ work. Then wait for the operator to choose one direction:
36
+ 1. Repair or restore DSH Crew, then continue through DSH Crew.
37
+ 2. Do not repair DSH Crew; continue with the main Codex agent.
38
+ - Resume only after the operator gives a new instruction. If repair is chosen,
39
+ verify live capability again before dispatch. If local execution is chosen,
40
+ state that the affected work is no longer independently delegated.
41
+ - This gate applies only after DSH Crew has been selected or explicitly
42
+ requested. It does not force a pause when initial planning decides DSH Crew
43
+ provides no benefit and the task should remain with the main agent.
44
+
45
+ ## Decide what to delegate
46
+
47
+ - Decompose the request into bounded work units before choosing an executor.
48
+ - Match each unit against discovered capabilities. Use DSH Crew only where it
49
+ provides a clear execution, isolation, parallelism, specialization, or
50
+ independent-review benefit.
51
+ - Delegate the smallest coherent unit that can be completed and verified
52
+ independently. Do not delegate an entire request merely because it is large.
53
+ - Keep ambiguity, dependency ordering, cross-cutting decisions, conflict
54
+ resolution, external side effects, final integration, and user communication
55
+ in the main Codex agent.
56
+ - Respect reported concurrency and isolation limits. Parallelize only
57
+ independent units with explicit, non-overlapping ownership.
58
+ - Simple questions, explanations, small read-only inspections, and genuinely
59
+ trivial edits should normally remain in the main agent.
60
+ - Explicit user instructions override default routing, but never safety or
61
+ capability boundaries.
62
+
63
+ ## Execute and verify
64
+
65
+ - Give each delegated unit a concrete objective, owned scope, workspace
66
+ context, constraints, and required validation evidence.
67
+ - Prefer isolated execution for code changes when supported. Review work must
68
+ remain read-only.
69
+ - Consume compact structured results and canonical events. Do not move
70
+ unbounded transcripts, raw provider payloads, credentials, or unnecessary
71
+ patch content between agents.
72
+ - The main agent must validate results, tests, changed scope, unresolved risks,
73
+ and completion state before accepting delegated work.
74
+
75
+ ## Review policy
76
+
77
+ - Use available independent review for non-trivial code changes when its live
78
+ invocation policy permits automatic use or the user requests manual use.
79
+ - Never bypass a manual, disabled, unavailable, or restricted review boundary.
80
+ - Treat requested changes, incomplete structured results, or missing direct
81
+ evidence as not approved.
82
+ - If selected DSH Crew review cannot run, apply the operator decision gate. The
83
+ main agent may review locally only after the operator selects that path.
84
+
85
+ ## Authority and completion
86
+
87
+ - Delegation does not broaden authority. Publishing, pushing, messaging,
88
+ credential changes, account actions, destructive operations, and other
89
+ external effects still require authority from the user's request.
90
+ - Do not present delegated work as complete until validation passes, structured
91
+ results are complete, integration is checked, and permitted review
92
+ requirements are satisfied or transparently reported as unavailable.
93
+
94
+ ## Harness upgrade redlines
95
+
96
+ - Never install, update, register, unlink, repair, or mutate anything under ~/.dsh.
97
+ - DSH Crew runtime upgrades must go through the Crew-owned installer and DSH_HOME.
98
+ - Never use direct pnpm/npm/dsh plugin operations against the official web profile.
99
+ - Preparing a Harness upgrade must not restart 3080 or 3210.
100
+ - Standalone workers launch through the official DSH SDK profile contract; dsh-sdk-jsonrpc-demo is obsolete.
101
+ - Legacy 3080 bridge must never be used for 3210 lifecycle/restart/rollback.
@@ -1,46 +1,66 @@
1
- # 3080 and 3210 UI responsibilities
1
+ # 3210 and 3080 UI responsibilities
2
2
 
3
- DSH Crew deliberately presents two different user experiences from one shared
4
- client build.
3
+ DSH Crew presents two different user experiences from two independently built
4
+ client bundles. The native 3210 page is the canonical full control plane;
5
+ the official 3080 page is an optional narrow quick-controls panel.
5
6
 
6
- ## 3080: daily Crew control plane
7
+ ## 3210: canonical full control plane
7
8
 
8
- The official Harness `web` profile on `127.0.0.1:3080` owns day-to-day Crew
9
- management:
9
+ The Crew-owned `dsh-crew` profile on `127.0.0.1:3210` owns day-to-day Crew
10
+ management AND model execution:
10
11
 
11
12
  - Crew workflow and global enablement
12
13
  - Worker and Reviewer policy
13
14
  - model priority, fallback, review, and adaptive routing
14
- - runtime and activation-boundary information
15
- - Codex, Claude, and ZCode installation actions and structured readiness
15
+ - multimodal (vision/imagegen) capability switches
16
+ - providers lifecycle (migrate/delete/rollback/quarantine)
17
+ - credential references lifecycle
18
+ - workspaces, presets, jobs
19
+ - installation integrations (Codex, Claude, ZCode)
16
20
  - task status and bounded model-invocation summaries
17
- - the link to the underlying 3210 Crew Harness
18
21
 
19
- The lightweight official-web bridge keeps these requests same-origin and
20
- proxies only the `/_dsh/dsh-crew/*` contract to the isolated backend.
22
+ Bundle: `lib/client.js` (module `@ran-sh/dsh-crew`), built from
23
+ `src/client/entry.tsx`.
21
24
 
22
- ## 3210: isolated native Harness
25
+ ## 3080: optional quick-controls surface
23
26
 
24
- The Crew-owned `dsh-crew` profile on `127.0.0.1:3210` owns model execution and
25
- low-level Harness configuration. Its native Harness menus remain the place for
26
- Providers, Harness Models, Agent presets, and native runtime settings.
27
+ The official Harness `web` profile on `127.0.0.1:3080` may host a NARROW
28
+ quick-controls card — and nothing else:
27
29
 
28
- The DSH Crew settings entry on this surface is intentionally diagnostics-only:
29
- it shows bounded runtime identity and a link back to 3080. It does not duplicate
30
- Worker/Reviewer policy, host integrations, tasks, or orchestration controls.
30
+ - master switch (`subagents_enabled`)
31
+ - Flash / Pro model priority lists (add/remove/reorder only)
32
+ - vision / imagegen toggles + providers (restart-pending flow)
33
+ - deep link to the 3210 full control plane (`http://127.0.0.1:3210/`)
34
+
35
+ Bundle: `official-web-bridge/lib/client.js` (module
36
+ `@ran-sh/dsh-crew-web-bridge`), built from `src/client/quick-entry.tsx`.
37
+ It physically contains none of the full control-plane code (no credential
38
+ purge, no provider delete/migration, no install integration).
39
+
40
+ The 3080 bridge proxies ONLY four exact endpoints to 3210:
41
+ `quick-config`, `quick-status`, `runtime/restart-request`,
42
+ `runtime/restart-status`. Everything else on the Crew namespace is 404 on
43
+ 3080, and `/supervisor/restart` returns 410 Gone pointing at 3210.
44
+
45
+ The official `~/.dsh` tree is strictly read-only for Crew; the 3080 quick
46
+ surface itself is optional — Crew works fully with 3080 closed.
47
+
48
+ ## UNKNOWN: diagnostics only
49
+
50
+ Unknown surfaces render diagnostics and never gain write authority.
31
51
 
32
52
  ## Surface detection and failure behavior
33
53
 
34
54
  The client does not infer responsibility from a hard-coded browser port. It
35
55
  uses two same-origin, structured signals:
36
56
 
37
- 1. `/_dsh/dsh-crew/bridge-status` identifies the official bridge control plane.
57
+ 1. `/_dsh/dsh-crew/bridge-status` identifies the official quick bridge.
38
58
  2. `/_dsh/dsh-crew/runtime` identifies the native Crew-owned runtime.
39
59
 
40
60
  The bridge signal wins on 3080 because the proxied runtime response correctly
41
61
  describes the 3210 backend. If neither contract can be verified, the client
42
- fails closed to the minimal diagnostics view. Missing evidence never enables
43
- the full control plane and never becomes `READY`.
62
+ fails closed to the diagnostics view. Missing evidence never enables the
63
+ full control plane and never becomes `READY`.
44
64
 
45
65
  The split changes presentation only. Crew state, credentials, routing policy,
46
66
  and model execution remain isolated under the Crew-owned home and profile.
@@ -63,3 +83,10 @@ they do not authenticate local users. If a deployment ever needs to separate
63
83
  local principals, add a per-install random token to state-changing calls and
64
84
  inject it server-side in the bridge — do not use browser `Origin` as
65
85
  authentication.
86
+
87
+ ## Process ownership
88
+
89
+ The Windows launcher supervisor (`windows/start-dsh-crew.ps1` watch mode) is
90
+ the ONLY process authority for 3210. The 3080 bridge never spawns, owns, or
91
+ kills 3210. Restart and maintenance go through durable request files the hub
92
+ writes and the launcher executes (`supervisor/restart-request.mjs`).
package/lib/client.js CHANGED
@@ -195,7 +195,7 @@ function runtimeState(runtime, readinessSnapshot) {
195
195
  }
196
196
  function bridgeState(surface) {
197
197
  if (surface === "official-bridge") return READINESS_STATES.READY;
198
- if (surface === "native-crew-harness") return READINESS_STATES.UNAVAILABLE;
198
+ if (surface === "native-crew-harness") return READINESS_STATES.UNKNOWN;
199
199
  return READINESS_STATES.UNKNOWN;
200
200
  }
201
201
  /** Project only structured, non-secret installer/runtime evidence. */
@@ -265,12 +265,31 @@ function classifyCrewSurface({ bridgeStatus, runtime } = {}) {
265
265
  if (runtime?.ok === true && runtime.service === "dsh-crew-hub" && (runtime.surface === CREW_UI_SURFACES.NATIVE || runtime.surface === void 0)) return CREW_UI_SURFACES.NATIVE;
266
266
  return CREW_UI_SURFACES.UNKNOWN;
267
267
  }
268
+ /**
269
+ * Surface capability model. The NATIVE 3210 Crew harness is the single full
270
+ * control plane; the OFFICIAL 3080 surface is a narrow quick-controls panel
271
+ * (total switch, flash/pro model priority, vision/imagegen toggles) plus a
272
+ * deep link back to 3210. Unknown surfaces get diagnostics only — never write
273
+ * authority. This replaces the old binary full-vs-minimal assumption.
274
+ */
268
275
  function surfaceResponsibilities(surface) {
269
- const fullControlPlane = surface === CREW_UI_SURFACES.OFFICIAL;
270
- return {
271
- fullControlPlane,
272
- minimalDiagnostics: !fullControlPlane
273
- };
276
+ switch (surface) {
277
+ case CREW_UI_SURFACES.NATIVE: return {
278
+ fullControlPlane: true,
279
+ quickControlPlane: true,
280
+ diagnostics: true
281
+ };
282
+ case CREW_UI_SURFACES.OFFICIAL: return {
283
+ fullControlPlane: false,
284
+ quickControlPlane: true,
285
+ diagnostics: true
286
+ };
287
+ default: return {
288
+ fullControlPlane: false,
289
+ quickControlPlane: false,
290
+ diagnostics: true
291
+ };
292
+ }
274
293
  }
275
294
  //#endregion
276
295
  //#region src/client/task-telemetry.mjs
@@ -1591,7 +1610,7 @@ function WorkersPanel({ ctx }) {
1591
1610
  } catch {}
1592
1611
  }, [get]);
1593
1612
  (0, react.useEffect)(() => {
1594
- if (surface !== CREW_UI_SURFACES.OFFICIAL) return void 0;
1613
+ if (!surfaceResponsibilities(surface).fullControlPlane) return void 0;
1595
1614
  refreshAll();
1596
1615
  const timer = setInterval(() => {
1597
1616
  Promise.all([get("/jobs"), get("/provider-health").catch(() => null)]).then(([j, health]) => {
@@ -1675,10 +1694,10 @@ function WorkersPanel({ ctx }) {
1675
1694
  withLang
1676
1695
  ]);
1677
1696
  (0, react.useEffect)(() => {
1678
- if (surface === CREW_UI_SURFACES.OFFICIAL) refreshHarnessModels();
1697
+ if (surfaceResponsibilities(surface).fullControlPlane) refreshHarnessModels();
1679
1698
  }, [surface, refreshHarnessModels]);
1680
1699
  (0, react.useEffect)(() => {
1681
- if (surface === CREW_UI_SURFACES.OFFICIAL) refreshProviderInventory();
1700
+ if (surfaceResponsibilities(surface).fullControlPlane) refreshProviderInventory();
1682
1701
  }, [surface, refreshProviderInventory]);
1683
1702
  const act = (0, react.useCallback)(async (target, confirmName) => {
1684
1703
  if (confirmName && !window.confirm(copy.confirmRestore(confirmName))) return;
@@ -1721,6 +1740,34 @@ function WorkersPanel({ ctx }) {
1721
1740
  get,
1722
1741
  copy
1723
1742
  ]);
1743
+ /** Request a Crew 3210 restart through the durable supervisor channel
1744
+ * (hub writes the request; the Windows watcher executes it). Polls until
1745
+ * VERIFIED or a terminal failure. Same-origin against the 3210 API — the
1746
+ * legacy 3080 supervisor endpoint is retired. */
1747
+ const requestRestart = (0, react.useCallback)(async (reason) => {
1748
+ const created = await post("/runtime/restart-request", {
1749
+ confirm: true,
1750
+ reason: reason ?? "configuration change"
1751
+ });
1752
+ if (!created.ok) throw new Error(created.code ?? created.error ?? copy.providerLifecycleError);
1753
+ const requestId = created.request_id;
1754
+ const deadline = Date.now() + 9e4;
1755
+ for (;;) {
1756
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
1757
+ if (Date.now() > deadline) throw new Error("Crew restart timed out");
1758
+ const status = await get(`/runtime/restart-status?id=${encodeURIComponent(requestId)}`);
1759
+ if (!status.ok) continue;
1760
+ if (status.state === "VERIFIED") return {
1761
+ ok: true,
1762
+ ...status
1763
+ };
1764
+ if (status.state !== "RESTART_REQUESTED") throw new Error(status.state ?? "Crew restart failed");
1765
+ }
1766
+ }, [
1767
+ post,
1768
+ get,
1769
+ copy
1770
+ ]);
1724
1771
  /** Selects & checkboxes: apply immediately. */
1725
1772
  const field = (key, value) => {
1726
1773
  setConfig((c) => ({
@@ -2020,13 +2067,7 @@ function WorkersPanel({ ctx }) {
2020
2067
  }), path);
2021
2068
  if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
2022
2069
  if (result.restart_required === true && result.result?.state === "RESTART_PENDING") {
2023
- const restartPath = "http://127.0.0.1:3080/_dsh/dsh-crew/supervisor/restart";
2024
- const restarted = await readJson(await fetch(restartPath, {
2025
- method: "POST",
2026
- headers: { "content-type": "application/json" },
2027
- body: JSON.stringify({ confirm: true })
2028
- }), restartPath);
2029
- if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
2070
+ await requestRestart("provider delete");
2030
2071
  const verified = await post(`/providers/${encoded}/verify-delete`, {
2031
2072
  transaction_id: planned.plan.plan_id,
2032
2073
  confirm: true
@@ -2065,13 +2106,7 @@ function WorkersPanel({ ctx }) {
2065
2106
  });
2066
2107
  if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
2067
2108
  if (result.restart_required === true && result.result?.state === "RESTART_PENDING") {
2068
- const restartPath = "http://127.0.0.1:3080/_dsh/dsh-crew/supervisor/restart";
2069
- const restarted = await readJson(await fetch(restartPath, {
2070
- method: "POST",
2071
- headers: { "content-type": "application/json" },
2072
- body: JSON.stringify({ confirm: true })
2073
- }), restartPath);
2074
- if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
2109
+ await requestRestart("provider migrate");
2075
2110
  const verified = await post(`/providers/${encoded}/verify-migration`, {
2076
2111
  transaction_id: planned.plan.plan_id,
2077
2112
  confirm: true
@@ -2100,15 +2135,7 @@ function WorkersPanel({ ctx }) {
2100
2135
  confirm: true
2101
2136
  });
2102
2137
  if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
2103
- if (result.restart_required === true) {
2104
- const restartPath = "http://127.0.0.1:3080/_dsh/dsh-crew/supervisor/restart";
2105
- const restarted = await readJson(await fetch(restartPath, {
2106
- method: "POST",
2107
- headers: { "content-type": "application/json" },
2108
- body: JSON.stringify({ confirm: true })
2109
- }), restartPath);
2110
- if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
2111
- }
2138
+ if (result.restart_required === true) await requestRestart("provider migrate");
2112
2139
  setNotice(copy.saved);
2113
2140
  await refreshProviderInventory();
2114
2141
  } catch (error) {
@@ -2153,13 +2180,7 @@ function WorkersPanel({ ctx }) {
2153
2180
  });
2154
2181
  if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
2155
2182
  if (result.restart_required === true && result.state === "ROLLBACK_PENDING") {
2156
- const restartPath = "http://127.0.0.1:3080/_dsh/dsh-crew/supervisor/restart";
2157
- const restarted = await readJson(await fetch(restartPath, {
2158
- method: "POST",
2159
- headers: { "content-type": "application/json" },
2160
- body: JSON.stringify({ confirm: true })
2161
- }), restartPath);
2162
- if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
2183
+ await requestRestart("provider migrate");
2163
2184
  const verified = await post(`/providers/${encoded}/verify-rollback`, {
2164
2185
  transaction_id: transactionId,
2165
2186
  confirm: true
@@ -4754,7 +4775,7 @@ function WorkersPanel({ ctx }) {
4754
4775
  }
4755
4776
  function apply$1(ctx) {
4756
4777
  let runningCount = 0;
4757
- let officialSurface = null;
4778
+ let badgeSurface = null;
4758
4779
  ctx.slots.inject("settings.section", () => {
4759
4780
  let dispose = register();
4760
4781
  function register() {
@@ -4783,11 +4804,14 @@ function apply$1(ctx) {
4783
4804
  const poll = async () => {
4784
4805
  if (document.visibilityState !== "visible") return;
4785
4806
  try {
4786
- if (officialSurface === null) {
4787
- const response = await fetch(`${API}/bridge-status`, { cache: "no-store" });
4788
- officialSurface = classifyCrewSurface({ bridgeStatus: response.ok ? await response.json() : null }) === CREW_UI_SURFACES.OFFICIAL;
4807
+ if (badgeSurface === null) {
4808
+ const [bridgeStatus, runtime] = await Promise.all([fetch(`${API}/bridge-status`, { cache: "no-store" }).then((r) => r.ok ? r.json() : null).catch(() => null), fetch(`${API}/runtime`, { cache: "no-store" }).then((r) => r.ok ? r.json() : null).catch(() => null)]);
4809
+ badgeSurface = surfaceResponsibilities(classifyCrewSurface({
4810
+ bridgeStatus,
4811
+ runtime
4812
+ })).fullControlPlane;
4789
4813
  }
4790
- if (!officialSurface) return;
4814
+ if (!badgeSurface) return;
4791
4815
  const r = await (await fetch(`${API}/jobs`, { cache: "no-store" })).json();
4792
4816
  const n = r.ok ? (r.jobs ?? []).filter((j) => j.status === "running").length : 0;
4793
4817
  if (n !== runningCount) {