@ran-sh/dsh-crew 1.0.2 → 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/README.md +4 -0
- package/README.zh.md +4 -0
- package/codex/AGENTS.md +101 -92
- package/docs/ui-surfaces.md +48 -21
- package/lib/client.js +235 -34
- package/official-web-bridge/lib/client.js +368 -4532
- package/official-web-bridge/package.json +1 -2
- package/package.json +130 -67
- package/scripts/build-client.mjs +30 -15
- package/scripts/remove-legacy-official-bridge.ps1 +89 -0
- package/scripts/setup.mjs +152 -140
- package/scripts/verify-npm-install.mjs +311 -310
- package/scripts/verify-official-bridge-e2e.mjs +12 -1
- package/src/client/host-readiness.mjs +62 -59
- package/src/client/index.tsx +117 -24
- package/src/client/quick-entry.tsx +10 -0
- package/src/client/quick-panel.tsx +295 -0
- package/src/client/surface-detection.mjs +43 -30
- package/src/credential-reference.mjs +38 -0
- package/src/dsh-cli-runtime.mjs +500 -40
- package/src/dsh-cohort.mjs +20 -0
- package/src/hub/index.mjs +1602 -1016
- package/src/install/npx-lifecycle.mjs +1983 -468
- package/src/install/official-web.mjs +36 -73
- package/src/jobs.mjs +20 -24
- package/src/model-catalog.mjs +8 -1
- package/src/official-web-bridge.mjs +329 -249
- package/src/provider-delete-adapters.mjs +165 -17
- package/src/provider-inventory.mjs +17 -3
- package/src/provider-layer-migration-adapters.mjs +759 -0
- package/src/provider-layer-migration.mjs +198 -0
- package/src/provider-lifecycle-state.mjs +4 -1
- package/src/provider-profile-store.mjs +193 -4
- package/src/provider-settings-store.mjs +82 -6
- package/src/provider-store-lock.mjs +67 -0
- package/src/runtime-identity.mjs +24 -1
- package/src/supervisor/restart-request.mjs +202 -0
- package/windows/start-dsh-crew.ps1 +783 -370
- package/worker.cordis.yml +32 -46
- package/zcode/AGENTS.md +35 -26
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.
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
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
|
|
@@ -511,6 +530,13 @@ const COPY = {
|
|
|
511
530
|
providerJobs: (count) => `${count} 个运行任务`,
|
|
512
531
|
providerOfficialBuiltin: "· 官方内置(不可删除)",
|
|
513
532
|
providerSourceUnresolved: "· 来源未解析(安全锁定)",
|
|
533
|
+
providerLayerMigration: "检测到旧版 profile Provider",
|
|
534
|
+
providerLayerMigrationHint: "这些 Provider 仍在 Crew profile/base 层,所以 3210 原生页面不会显示删除。请先按迁移计划提升到 Harness 用户设置层;不会复制密钥。",
|
|
535
|
+
providerLayerMigrationPlan: "迁移计划",
|
|
536
|
+
providerLayerMigrate: "迁移到用户层",
|
|
537
|
+
providerLayerMigrating: "迁移中…",
|
|
538
|
+
providerLayerMigrationConfirm: "确认把这个 Provider 移到 Harness 用户设置层?会先保存可回滚快照,不会复制密钥值。",
|
|
539
|
+
providerLayerRollback: "回滚迁移",
|
|
514
540
|
providerDeletePlan: "生成删除计划",
|
|
515
541
|
providerDelete: "确认删除",
|
|
516
542
|
providerPlanReady: "计划已生成;再次确认后才会修改 3210 配置。",
|
|
@@ -537,8 +563,8 @@ const COPY = {
|
|
|
537
563
|
credentialPurging: "清理中…",
|
|
538
564
|
credentialPurgeUnavailable: "凭据清理不可用",
|
|
539
565
|
credentialPurgeUnverified: "已执行清理,但验证失败;引用仍保留用于恢复检查",
|
|
540
|
-
customProviders: "
|
|
541
|
-
addProvider: "+
|
|
566
|
+
customProviders: "多模态适配器",
|
|
567
|
+
addProvider: "+ 添加多模态适配器",
|
|
542
568
|
noCustomProviders: "暂无。添加后会出现在上方的视觉 / 生图 provider 选择里。",
|
|
543
569
|
providerName: "名称",
|
|
544
570
|
modelsField: "模型列表(逗号分隔)",
|
|
@@ -842,6 +868,13 @@ const COPY = {
|
|
|
842
868
|
providerJobs: (count) => `${count} running jobs`,
|
|
843
869
|
providerOfficialBuiltin: "· official built-in (immutable)",
|
|
844
870
|
providerSourceUnresolved: "· source unresolved (locked)",
|
|
871
|
+
providerLayerMigration: "Legacy profile Providers detected",
|
|
872
|
+
providerLayerMigrationHint: "These Providers still exist in the Crew profile/base layer, so the native 3210 page cannot show Delete. Promote them to Harness user settings with an explicit plan; keys are never copied.",
|
|
873
|
+
providerLayerMigrationPlan: "Migration plan",
|
|
874
|
+
providerLayerMigrate: "Migrate to user layer",
|
|
875
|
+
providerLayerMigrating: "Migrating…",
|
|
876
|
+
providerLayerMigrationConfirm: "Move this Provider into Harness user settings? A rollback snapshot is saved first; credential values are never copied.",
|
|
877
|
+
providerLayerRollback: "Rollback migration",
|
|
845
878
|
providerDeletePlan: "Plan deletion",
|
|
846
879
|
providerDelete: "Confirm delete",
|
|
847
880
|
providerPlanReady: "Plan ready; a second confirmation is required before changing 3210 config.",
|
|
@@ -868,8 +901,8 @@ const COPY = {
|
|
|
868
901
|
credentialPurging: "Purging…",
|
|
869
902
|
credentialPurgeUnavailable: "Credential purge unavailable",
|
|
870
903
|
credentialPurgeUnverified: "Purge ran but verification failed; the reference remains visible for recovery",
|
|
871
|
-
customProviders: "
|
|
872
|
-
addProvider: "+ Add
|
|
904
|
+
customProviders: "Multimodal adapters",
|
|
905
|
+
addProvider: "+ Add multimodal adapter",
|
|
873
906
|
noCustomProviders: "None yet. Added providers appear in the vision / image-gen selects above.",
|
|
874
907
|
providerName: "Name",
|
|
875
908
|
modelsField: "Models (comma-separated)",
|
|
@@ -1577,7 +1610,7 @@ function WorkersPanel({ ctx }) {
|
|
|
1577
1610
|
} catch {}
|
|
1578
1611
|
}, [get]);
|
|
1579
1612
|
(0, react.useEffect)(() => {
|
|
1580
|
-
if (surface
|
|
1613
|
+
if (!surfaceResponsibilities(surface).fullControlPlane) return void 0;
|
|
1581
1614
|
refreshAll();
|
|
1582
1615
|
const timer = setInterval(() => {
|
|
1583
1616
|
Promise.all([get("/jobs"), get("/provider-health").catch(() => null)]).then(([j, health]) => {
|
|
@@ -1661,10 +1694,10 @@ function WorkersPanel({ ctx }) {
|
|
|
1661
1694
|
withLang
|
|
1662
1695
|
]);
|
|
1663
1696
|
(0, react.useEffect)(() => {
|
|
1664
|
-
if (surface
|
|
1697
|
+
if (surfaceResponsibilities(surface).fullControlPlane) refreshHarnessModels();
|
|
1665
1698
|
}, [surface, refreshHarnessModels]);
|
|
1666
1699
|
(0, react.useEffect)(() => {
|
|
1667
|
-
if (surface
|
|
1700
|
+
if (surfaceResponsibilities(surface).fullControlPlane) refreshProviderInventory();
|
|
1668
1701
|
}, [surface, refreshProviderInventory]);
|
|
1669
1702
|
const act = (0, react.useCallback)(async (target, confirmName) => {
|
|
1670
1703
|
if (confirmName && !window.confirm(copy.confirmRestore(confirmName))) return;
|
|
@@ -1707,6 +1740,34 @@ function WorkersPanel({ ctx }) {
|
|
|
1707
1740
|
get,
|
|
1708
1741
|
copy
|
|
1709
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
|
+
]);
|
|
1710
1771
|
/** Selects & checkboxes: apply immediately. */
|
|
1711
1772
|
const field = (key, value) => {
|
|
1712
1773
|
setConfig((c) => ({
|
|
@@ -2006,13 +2067,7 @@ function WorkersPanel({ ctx }) {
|
|
|
2006
2067
|
}), path);
|
|
2007
2068
|
if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
|
|
2008
2069
|
if (result.restart_required === true && result.result?.state === "RESTART_PENDING") {
|
|
2009
|
-
|
|
2010
|
-
const restarted = await readJson(await fetch(restartPath, {
|
|
2011
|
-
method: "POST",
|
|
2012
|
-
headers: { "content-type": "application/json" },
|
|
2013
|
-
body: JSON.stringify({ confirm: true })
|
|
2014
|
-
}), restartPath);
|
|
2015
|
-
if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
|
|
2070
|
+
await requestRestart("provider delete");
|
|
2016
2071
|
const verified = await post(`/providers/${encoded}/verify-delete`, {
|
|
2017
2072
|
transaction_id: planned.plan.plan_id,
|
|
2018
2073
|
confirm: true
|
|
@@ -2030,6 +2085,68 @@ function WorkersPanel({ ctx }) {
|
|
|
2030
2085
|
setProviderLifecycleBusy(null);
|
|
2031
2086
|
}
|
|
2032
2087
|
};
|
|
2088
|
+
const migrateHarnessProvider = async (entry) => {
|
|
2089
|
+
if (!entry || !["promote-existing-user", "materialize-user"].includes(entry.action)) {
|
|
2090
|
+
setNotice(entry?.blocked_reason ?? copy.providerLayerMigrationHint);
|
|
2091
|
+
return;
|
|
2092
|
+
}
|
|
2093
|
+
if (!window.confirm(copy.providerLayerMigrationConfirm)) return;
|
|
2094
|
+
const id = String(entry.provider_id ?? "");
|
|
2095
|
+
if (!id) return;
|
|
2096
|
+
setProviderLifecycleBusy(`migrate:${id}`);
|
|
2097
|
+
setNotice(copy.providerLayerMigrating);
|
|
2098
|
+
try {
|
|
2099
|
+
const encoded = encodeURIComponent(id);
|
|
2100
|
+
const planned = await post(`/providers/${encoded}/migrate-plan`, {});
|
|
2101
|
+
if (!planned.ok || !planned.plan) throw new Error(planned.code ?? copy.providerLifecycleError);
|
|
2102
|
+
if (!window.confirm(`${copy.providerLayerMigrationConfirm}\n\n${id}`)) return;
|
|
2103
|
+
const result = await post(`/providers/${encoded}/migrate`, {
|
|
2104
|
+
plan_id: planned.plan.plan_id,
|
|
2105
|
+
confirm: true
|
|
2106
|
+
});
|
|
2107
|
+
if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
|
|
2108
|
+
if (result.restart_required === true && result.result?.state === "RESTART_PENDING") {
|
|
2109
|
+
await requestRestart("provider migrate");
|
|
2110
|
+
const verified = await post(`/providers/${encoded}/verify-migration`, {
|
|
2111
|
+
transaction_id: planned.plan.plan_id,
|
|
2112
|
+
confirm: true
|
|
2113
|
+
});
|
|
2114
|
+
if (!verified.ok || verified.state !== "VERIFIED") throw new Error(verified.code ?? verified.error ?? copy.providerLifecycleError);
|
|
2115
|
+
}
|
|
2116
|
+
setNotice(copy.saved);
|
|
2117
|
+
await refreshProviderInventory();
|
|
2118
|
+
} catch (error) {
|
|
2119
|
+
try {
|
|
2120
|
+
await refreshProviderInventory();
|
|
2121
|
+
} catch {}
|
|
2122
|
+
setNotice(String(error?.message ?? error));
|
|
2123
|
+
} finally {
|
|
2124
|
+
setProviderLifecycleBusy(null);
|
|
2125
|
+
}
|
|
2126
|
+
};
|
|
2127
|
+
const rollbackHarnessMigration = async (record, transactionId) => {
|
|
2128
|
+
if (!record?.id || !transactionId || !window.confirm(copy.providerRollbackConfirm)) return;
|
|
2129
|
+
setProviderLifecycleBusy(`rollback-migrate:${record.id}`);
|
|
2130
|
+
setNotice(copy.working);
|
|
2131
|
+
try {
|
|
2132
|
+
const encoded = encodeURIComponent(record.id);
|
|
2133
|
+
const result = await post(`/providers/${encoded}/rollback-migration`, {
|
|
2134
|
+
transaction_id: transactionId,
|
|
2135
|
+
confirm: true
|
|
2136
|
+
});
|
|
2137
|
+
if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
|
|
2138
|
+
if (result.restart_required === true) await requestRestart("provider migrate");
|
|
2139
|
+
setNotice(copy.saved);
|
|
2140
|
+
await refreshProviderInventory();
|
|
2141
|
+
} catch (error) {
|
|
2142
|
+
setNotice(String(error?.message ?? error));
|
|
2143
|
+
try {
|
|
2144
|
+
await refreshProviderInventory();
|
|
2145
|
+
} catch {}
|
|
2146
|
+
} finally {
|
|
2147
|
+
setProviderLifecycleBusy(null);
|
|
2148
|
+
}
|
|
2149
|
+
};
|
|
2033
2150
|
const rollbackHarnessProvider = async (record, transactionId, transactionState = "VERIFIED") => {
|
|
2034
2151
|
const continuing = ["ROLLBACK_PENDING", "ROLLBACK_RESTART_PENDING"].includes(transactionState);
|
|
2035
2152
|
const recoverable = [
|
|
@@ -2063,13 +2180,7 @@ function WorkersPanel({ ctx }) {
|
|
|
2063
2180
|
});
|
|
2064
2181
|
if (!result.ok) throw new Error(result.code ?? result.error ?? copy.providerLifecycleError);
|
|
2065
2182
|
if (result.restart_required === true && result.state === "ROLLBACK_PENDING") {
|
|
2066
|
-
|
|
2067
|
-
const restarted = await readJson(await fetch(restartPath, {
|
|
2068
|
-
method: "POST",
|
|
2069
|
-
headers: { "content-type": "application/json" },
|
|
2070
|
-
body: JSON.stringify({ confirm: true })
|
|
2071
|
-
}), restartPath);
|
|
2072
|
-
if (!restarted.ok) throw new Error(restarted.code ?? restarted.error ?? copy.providerLifecycleError);
|
|
2183
|
+
await requestRestart("provider migrate");
|
|
2073
2184
|
const verified = await post(`/providers/${encoded}/verify-rollback`, {
|
|
2074
2185
|
transaction_id: transactionId,
|
|
2075
2186
|
confirm: true
|
|
@@ -3642,6 +3753,78 @@ function WorkersPanel({ ctx }) {
|
|
|
3642
3753
|
},
|
|
3643
3754
|
children: providerInventoryError
|
|
3644
3755
|
}),
|
|
3756
|
+
!providerInventoryError && (providerInventory?.migration?.providers?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3757
|
+
style: {
|
|
3758
|
+
border: "1px solid rgba(201,135,53,0.45)",
|
|
3759
|
+
borderRadius: 7,
|
|
3760
|
+
padding: "8px 10px",
|
|
3761
|
+
marginBottom: 8
|
|
3762
|
+
},
|
|
3763
|
+
children: [
|
|
3764
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3765
|
+
style: {
|
|
3766
|
+
fontWeight: 650,
|
|
3767
|
+
fontSize: 12.5
|
|
3768
|
+
},
|
|
3769
|
+
children: copy.providerLayerMigration
|
|
3770
|
+
}),
|
|
3771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3772
|
+
style: {
|
|
3773
|
+
fontSize: 11.5,
|
|
3774
|
+
opacity: .7,
|
|
3775
|
+
marginTop: 3
|
|
3776
|
+
},
|
|
3777
|
+
children: copy.providerLayerMigrationHint
|
|
3778
|
+
}),
|
|
3779
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3780
|
+
style: {
|
|
3781
|
+
fontSize: 11,
|
|
3782
|
+
marginTop: 6,
|
|
3783
|
+
fontFamily: "monospace"
|
|
3784
|
+
},
|
|
3785
|
+
children: (providerInventory.migration.providers ?? []).map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3786
|
+
style: {
|
|
3787
|
+
display: "flex",
|
|
3788
|
+
alignItems: "center",
|
|
3789
|
+
gap: 6,
|
|
3790
|
+
marginTop: 3
|
|
3791
|
+
},
|
|
3792
|
+
children: [
|
|
3793
|
+
entry.provider_id,
|
|
3794
|
+
" · ",
|
|
3795
|
+
entry.action,
|
|
3796
|
+
entry.harness_default ? " · Harness Default" : "",
|
|
3797
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
|
|
3798
|
+
["promote-existing-user", "materialize-user"].includes(entry.action) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3799
|
+
type: "button",
|
|
3800
|
+
style: {
|
|
3801
|
+
...S.btn,
|
|
3802
|
+
padding: "2px 7px"
|
|
3803
|
+
},
|
|
3804
|
+
disabled: providerLifecycleBusy !== null,
|
|
3805
|
+
onClick: () => {
|
|
3806
|
+
migrateHarnessProvider(entry);
|
|
3807
|
+
},
|
|
3808
|
+
children: providerLifecycleBusy === `migrate:${entry.provider_id}` ? copy.providerLayerMigrating : copy.providerLayerMigrate
|
|
3809
|
+
})
|
|
3810
|
+
]
|
|
3811
|
+
}, entry.provider_id))
|
|
3812
|
+
}),
|
|
3813
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
3814
|
+
href: "http://127.0.0.1:3210/",
|
|
3815
|
+
target: "_blank",
|
|
3816
|
+
rel: "noopener noreferrer",
|
|
3817
|
+
style: {
|
|
3818
|
+
...S.btn,
|
|
3819
|
+
display: "inline-block",
|
|
3820
|
+
textDecoration: "none",
|
|
3821
|
+
marginTop: 7,
|
|
3822
|
+
padding: "3px 8px"
|
|
3823
|
+
},
|
|
3824
|
+
children: [copy.providerLayerMigrationPlan, " → 3210"]
|
|
3825
|
+
})
|
|
3826
|
+
]
|
|
3827
|
+
}),
|
|
3645
3828
|
!providerInventoryError && (providerInventory?.records?.length ?? 0) === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3646
3829
|
style: {
|
|
3647
3830
|
fontSize: 12,
|
|
@@ -3673,7 +3856,10 @@ function WorkersPanel({ ctx }) {
|
|
|
3673
3856
|
"DELETE_RESTART_PENDING",
|
|
3674
3857
|
"ROLLBACK_RESTART_PENDING",
|
|
3675
3858
|
"ROLLBACK_RESTORED",
|
|
3676
|
-
"ROLLBACK_APPLYING"
|
|
3859
|
+
"ROLLBACK_APPLYING",
|
|
3860
|
+
"PREPARED",
|
|
3861
|
+
"USER_MATERIALIZED",
|
|
3862
|
+
"BASE_REMOVED"
|
|
3677
3863
|
].includes(entry.state)).sort((a, b) => String(a.updated_at ?? "").localeCompare(String(b.updated_at ?? ""))).at(-1);
|
|
3678
3864
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3679
3865
|
style: {
|
|
@@ -3741,7 +3927,7 @@ function WorkersPanel({ ctx }) {
|
|
|
3741
3927
|
"ROLLBACK_RESTART_PENDING",
|
|
3742
3928
|
"ROLLBACK_RESTORED",
|
|
3743
3929
|
"ROLLBACK_APPLYING"
|
|
3744
|
-
].includes(rollbackTransaction?.state)) && rollbackTransaction && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3930
|
+
].includes(rollbackTransaction?.state)) && rollbackTransaction && rollbackTransaction.source !== "provider-layer-migration" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3745
3931
|
type: "button",
|
|
3746
3932
|
style: {
|
|
3747
3933
|
...S.btn,
|
|
@@ -3752,6 +3938,18 @@ function WorkersPanel({ ctx }) {
|
|
|
3752
3938
|
rollbackHarnessProvider(record, rollbackTransaction.transaction_id, rollbackTransaction.state);
|
|
3753
3939
|
},
|
|
3754
3940
|
children: providerLifecycleBusy === `rollback:${record.id}` ? copy.working : rollbackTransaction.state === "ROLLBACK_PENDING" ? copy.providerRollbackContinue : copy.providerRollback
|
|
3941
|
+
}),
|
|
3942
|
+
rollbackTransaction?.source === "provider-layer-migration" && rollbackTransaction.transaction_id && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3943
|
+
type: "button",
|
|
3944
|
+
style: {
|
|
3945
|
+
...S.btn,
|
|
3946
|
+
padding: "2px 8px"
|
|
3947
|
+
},
|
|
3948
|
+
disabled: providerLifecycleBusy !== null,
|
|
3949
|
+
onClick: () => {
|
|
3950
|
+
rollbackHarnessMigration(record, rollbackTransaction.transaction_id);
|
|
3951
|
+
},
|
|
3952
|
+
children: providerLifecycleBusy === `rollback-migrate:${record.id}` ? copy.working : copy.providerLayerRollback
|
|
3755
3953
|
})
|
|
3756
3954
|
]
|
|
3757
3955
|
}, record.id);
|
|
@@ -4577,7 +4775,7 @@ function WorkersPanel({ ctx }) {
|
|
|
4577
4775
|
}
|
|
4578
4776
|
function apply$1(ctx) {
|
|
4579
4777
|
let runningCount = 0;
|
|
4580
|
-
let
|
|
4778
|
+
let badgeSurface = null;
|
|
4581
4779
|
ctx.slots.inject("settings.section", () => {
|
|
4582
4780
|
let dispose = register();
|
|
4583
4781
|
function register() {
|
|
@@ -4606,11 +4804,14 @@ function apply$1(ctx) {
|
|
|
4606
4804
|
const poll = async () => {
|
|
4607
4805
|
if (document.visibilityState !== "visible") return;
|
|
4608
4806
|
try {
|
|
4609
|
-
if (
|
|
4610
|
-
const
|
|
4611
|
-
|
|
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;
|
|
4612
4813
|
}
|
|
4613
|
-
if (!
|
|
4814
|
+
if (!badgeSurface) return;
|
|
4614
4815
|
const r = await (await fetch(`${API}/jobs`, { cache: "no-store" })).json();
|
|
4615
4816
|
const n = r.ok ? (r.jobs ?? []).filter((j) => j.status === "running").length : 0;
|
|
4616
4817
|
if (n !== runningCount) {
|