@jingyi0605/codingns4dsh 0.2.2-beta.1 → 0.2.2-beta.2
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.en.md +4 -4
- package/README.md +4 -4
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts +1 -1
- package/data/build/dist/bootstrap/dsh-connection-adapter.d.ts.map +1 -1
- package/data/build/dist/bootstrap/index.d.ts +1 -1
- package/data/build/dist/bootstrap/index.d.ts.map +1 -1
- package/data/build/dist/client/bundle.js +1720 -1933
- package/data/build/dist/client/bundle.js.map +1 -1
- package/data/build/dist/client/cli-slots.d.ts.map +1 -1
- package/data/build/dist/client/cli-slots.js +24 -13
- package/data/build/dist/client/cli-slots.js.map +1 -1
- package/data/build/dist/client/client.magpie-model-tag.js +4 -0
- package/data/build/dist/client/client.magpie-model-tag.js.map +1 -1
- package/data/build/dist/client/features/file-management.d.ts.map +1 -1
- package/data/build/dist/client/features/file-management.js +17 -2
- package/data/build/dist/client/features/file-management.js.map +1 -1
- package/data/build/dist/client/features/magpie-management-page.d.ts +17 -4
- package/data/build/dist/client/features/magpie-management-page.d.ts.map +1 -1
- package/data/build/dist/client/features/magpie-management-page.js +52 -16
- package/data/build/dist/client/features/magpie-management-page.js.map +1 -1
- package/data/build/dist/client/features/mobile-access-panel.d.ts.map +1 -1
- package/data/build/dist/client/features/mobile-access-panel.js +1 -11
- package/data/build/dist/client/features/mobile-access-panel.js.map +1 -1
- package/data/build/dist/client/features/mobile-access.d.ts +3 -6
- package/data/build/dist/client/features/mobile-access.d.ts.map +1 -1
- package/data/build/dist/client/features/mobile-access.js +18 -47
- package/data/build/dist/client/features/mobile-access.js.map +1 -1
- package/data/build/dist/client/features/types.d.ts +3 -0
- package/data/build/dist/client/features/types.d.ts.map +1 -1
- package/data/build/dist/client/features/workspace-session-enhancement.d.ts.map +1 -1
- package/data/build/dist/client/features/workspace-session-enhancement.js +2 -0
- package/data/build/dist/client/features/workspace-session-enhancement.js.map +1 -1
- package/data/build/dist/client/file-management-context-menu.d.ts +10 -0
- package/data/build/dist/client/file-management-context-menu.d.ts.map +1 -0
- package/data/build/dist/client/file-management-context-menu.js +182 -0
- package/data/build/dist/client/file-management-context-menu.js.map +1 -0
- package/data/build/dist/client/file-management-dom.d.ts +2 -0
- package/data/build/dist/client/file-management-dom.d.ts.map +1 -1
- package/data/build/dist/client/file-management-dom.js +10 -6
- package/data/build/dist/client/file-management-dom.js.map +1 -1
- package/data/build/dist/client/index.d.ts.map +1 -1
- package/data/build/dist/client/index.js +3 -0
- package/data/build/dist/client/index.js.map +1 -1
- package/data/build/dist/client/locale.d.ts.map +1 -1
- package/data/build/dist/client/locale.js +2 -0
- package/data/build/dist/client/locale.js.map +1 -1
- package/data/build/dist/client/locales/magpie.d.ts.map +1 -1
- package/data/build/dist/client/locales/magpie.js +2 -0
- package/data/build/dist/client/locales/magpie.js.map +1 -1
- package/data/build/dist/client/workspace-session-visibility-dom.d.ts +3 -0
- package/data/build/dist/client/workspace-session-visibility-dom.d.ts.map +1 -1
- package/data/build/dist/client/workspace-session-visibility-dom.js +29 -11
- package/data/build/dist/client/workspace-session-visibility-dom.js.map +1 -1
- package/data/build/dist/dsh-capabilities/client/context-menu-adapter.d.ts +22 -0
- package/data/build/dist/dsh-capabilities/client/context-menu-adapter.d.ts.map +1 -0
- package/data/build/dist/dsh-capabilities/client/context-menu-adapter.js +33 -0
- package/data/build/dist/dsh-capabilities/client/context-menu-adapter.js.map +1 -0
- package/data/build/dist/dsh-capabilities/client/primitives-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/client/session-performance-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js +10 -1
- package/data/build/dist/dsh-capabilities/client/session-performance-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/host/llm-text-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/host/llm-text-adapter.js +1 -0
- package/data/build/dist/dsh-capabilities/host/llm-text-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.d.ts +1 -0
- package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.js +15 -7
- package/data/build/dist/dsh-capabilities/host/plugin-update-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js +10 -1
- package/data/build/dist/dsh-capabilities/host/session-model-selection-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/host/session-performance-adapter.d.ts +1 -1
- package/data/build/dist/dsh-capabilities/host/session-performance-adapter.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/host/session-performance-adapter.js +10 -1
- package/data/build/dist/dsh-capabilities/host/session-performance-adapter.js.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/matrix.js +1 -0
- package/data/build/dist/dsh-capabilities/matrix.js.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/routes.js +3 -0
- package/data/build/dist/dsh-capabilities/routes.js.map +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts +1 -1
- package/data/build/dist/dsh-capabilities/types.d.ts.map +1 -1
- package/data/build/dist/dsh-capabilities/types.js.map +1 -1
- package/data/build/dist/host/cli-adapters/antigravity-driver.d.ts +5 -0
- package/data/build/dist/host/cli-adapters/antigravity-driver.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/antigravity-driver.js +54 -2
- package/data/build/dist/host/cli-adapters/antigravity-driver.js.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.d.ts.map +1 -1
- package/data/build/dist/host/cli-adapters/feature.js +70 -3
- package/data/build/dist/host/cli-adapters/feature.js.map +1 -1
- package/data/build/dist/host/cli-adapters/magpie-usage.js +6 -2
- package/data/build/dist/host/cli-adapters/magpie-usage.js.map +1 -1
- package/data/build/dist/host/features/session-translation-recovery.js +2 -2
- package/data/build/dist/host/features/session-translation-recovery.js.map +1 -1
- package/data/build/dist/host/features/session-translation-service.d.ts +2 -2
- package/data/build/dist/host/features/session-translation-service.d.ts.map +1 -1
- package/data/build/dist/host/features/session-translation-service.js +11 -9
- package/data/build/dist/host/features/session-translation-service.js.map +1 -1
- package/data/build/dist/host/index.d.ts.map +1 -1
- package/data/build/dist/host/index.js +4 -1
- package/data/build/dist/host/index.js.map +1 -1
- package/data/build/dist/host/settings.d.ts.map +1 -1
- package/data/build/dist/host/settings.js +5 -4
- package/data/build/dist/host/settings.js.map +1 -1
- package/data/build/dist/shared/contracts/config.d.ts +2 -2
- package/data/build/dist/shared/contracts/config.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/config.js +5 -10
- package/data/build/dist/shared/contracts/config.js.map +1 -1
- package/data/build/dist/shared/contracts/errors.d.ts +1 -1
- package/data/build/dist/shared/contracts/errors.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/version.d.ts +3 -3
- package/data/build/dist/shared/contracts/version.d.ts.map +1 -1
- package/data/build/dist/shared/contracts/version.js +2 -2
- package/data/build/dist/shared/contracts/version.js.map +1 -1
- package/package.json +34 -32
- package/profile/README.md +2 -2
- package/profile/package.json +2 -2
- package/profile/version.json +2 -2
- package/version.json +2 -2
|
@@ -2289,6 +2289,7 @@ window.__ModuleLoader__.load({
|
|
|
2289
2289
|
"magpie.statLatency": "First text",
|
|
2290
2290
|
"magpie.statLatencyNote": "Average first-text latency",
|
|
2291
2291
|
"magpie.topSessions": "Top sessions",
|
|
2292
|
+
"magpie.sortMetric": "Sort by",
|
|
2292
2293
|
"magpie.dailyTrend": "Daily trend",
|
|
2293
2294
|
"magpie.ncolTime": "Time",
|
|
2294
2295
|
"magpie.ncolRequested": "Requested model",
|
|
@@ -2646,6 +2647,7 @@ window.__ModuleLoader__.load({
|
|
|
2646
2647
|
"magpie.statLatency": "首字耗时",
|
|
2647
2648
|
"magpie.statLatencyNote": "首字平均耗时",
|
|
2648
2649
|
"magpie.topSessions": "最耗会话",
|
|
2650
|
+
"magpie.sortMetric": "排序指标",
|
|
2649
2651
|
"magpie.dailyTrend": "每日趋势",
|
|
2650
2652
|
"magpie.ncolTime": "时间",
|
|
2651
2653
|
"magpie.ncolRequested": "请求模型",
|
|
@@ -3532,6 +3534,7 @@ window.__ModuleLoader__.load({
|
|
|
3532
3534
|
"cli.notDetectedCommand": "Command not detected",
|
|
3533
3535
|
"cli.undeclared": "Undeclared",
|
|
3534
3536
|
"cli.defaultEffort": "Default",
|
|
3537
|
+
"cli.antigravityNativeModel": "{name} · Antigravity",
|
|
3535
3538
|
"cli.thinkingLevel": "Thinking level: {value}",
|
|
3536
3539
|
"cli.agentSelector": "Agent selector",
|
|
3537
3540
|
"cli.modelSelector": "Model and thinking level selector",
|
|
@@ -4009,6 +4012,7 @@ window.__ModuleLoader__.load({
|
|
|
4009
4012
|
"cli.notDetectedCommand": "未检测到命令",
|
|
4010
4013
|
"cli.undeclared": "未声明",
|
|
4011
4014
|
"cli.defaultEffort": "默认",
|
|
4015
|
+
"cli.antigravityNativeModel": "{name} · Antigravity",
|
|
4012
4016
|
"cli.thinkingLevel": "思考等级:{value}",
|
|
4013
4017
|
"cli.agentSelector": "Agent 选择器",
|
|
4014
4018
|
"cli.modelSelector": "模型与思考强度选择器",
|
|
@@ -5677,7 +5681,7 @@ window.__ModuleLoader__.load({
|
|
|
5677
5681
|
_deepseek_ai_dsh_client_ui_primitives = require_rolldown_runtime.__toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
5678
5682
|
let react = require("react");
|
|
5679
5683
|
/** DSH 测试版本别名,供新代码表达语义,保留 DSH_VERSION 兼容旧调用方。 */
|
|
5680
|
-
const DSH_TESTED_VERSION = "0.2.2-
|
|
5684
|
+
const DSH_TESTED_VERSION = "0.2.2-rc.1";
|
|
5681
5685
|
/**
|
|
5682
5686
|
* Only the minimum version blocks installation and activation.
|
|
5683
5687
|
* Hosts newer than DSH_TESTED_VERSION receive an advisory warning.
|
|
@@ -5691,7 +5695,7 @@ window.__ModuleLoader__.load({
|
|
|
5691
5695
|
* “不支持的 DSH 版本”,把仅仅缺少启动页注入的页面误判为宿主不兼容。
|
|
5692
5696
|
*/
|
|
5693
5697
|
function minimumSupportedDshVersion() {
|
|
5694
|
-
return /^>=([^ ]+)/u.exec(">=0.2.1-alpha.2")?.[1] ?? "0.2.2-
|
|
5698
|
+
return /^>=([^ ]+)/u.exec(">=0.2.1-alpha.2")?.[1] ?? "0.2.2-rc.1";
|
|
5695
5699
|
}
|
|
5696
5700
|
/** Host 注入到浏览器页面的真实 DSH 版本全局字段。 */
|
|
5697
5701
|
const CODINGNS_DSH_VERSION_GLOBAL = "__CODINGNS_DSH_VERSION__";
|
|
@@ -5700,7 +5704,7 @@ window.__ModuleLoader__.load({
|
|
|
5700
5704
|
return /^0\.1\.5(?:-|$)/u.test(version);
|
|
5701
5705
|
}
|
|
5702
5706
|
/** Codingns4DSH 插件自身的 npm 版本。 */
|
|
5703
|
-
const CODINGNS_VERSION = "0.2.2-beta.
|
|
5707
|
+
const CODINGNS_VERSION = "0.2.2-beta.2";
|
|
5704
5708
|
/** Accept any valid host version at or above the supported minimum. */
|
|
5705
5709
|
function isDshVersionCompatible(version) {
|
|
5706
5710
|
return isDshVersionAtLeast(version, minimumSupportedDshVersion());
|
|
@@ -5947,7 +5951,7 @@ window.__ModuleLoader__.load({
|
|
|
5947
5951
|
try {
|
|
5948
5952
|
await record.module.drain?.(record.context);
|
|
5949
5953
|
} catch (error) {
|
|
5950
|
-
record.reason = errorMessage$
|
|
5954
|
+
record.reason = errorMessage$4(error);
|
|
5951
5955
|
throw new FeatureRegistryError("FEATURE_DISPOSE_FAILED", `Failed to drain feature ${name}`, name, { cause: error });
|
|
5952
5956
|
}
|
|
5953
5957
|
});
|
|
@@ -5976,7 +5980,7 @@ window.__ModuleLoader__.load({
|
|
|
5976
5980
|
errors.push(error);
|
|
5977
5981
|
}
|
|
5978
5982
|
record.state = "disabled";
|
|
5979
|
-
record.reason = errors.length > 0 ? errors.map(errorMessage$
|
|
5983
|
+
record.reason = errors.length > 0 ? errors.map(errorMessage$4).join("; ") : null;
|
|
5980
5984
|
if (errors.length > 0) throw new FeatureRegistryError("FEATURE_DISPOSE_FAILED", `Failed to dispose feature ${name}`, name, { cause: new AggregateError(errors) });
|
|
5981
5985
|
});
|
|
5982
5986
|
}
|
|
@@ -6077,7 +6081,7 @@ window.__ModuleLoader__.load({
|
|
|
6077
6081
|
error = new AggregateError([error, disposeError], "Feature start and cleanup failed");
|
|
6078
6082
|
}
|
|
6079
6083
|
record.state = "failed";
|
|
6080
|
-
record.reason = errorMessage$
|
|
6084
|
+
record.reason = errorMessage$4(error);
|
|
6081
6085
|
traceFeature("start.failed", {
|
|
6082
6086
|
feature: name,
|
|
6083
6087
|
reason: record.reason,
|
|
@@ -6220,7 +6224,7 @@ window.__ModuleLoader__.load({
|
|
|
6220
6224
|
capabilities: [...record.capabilities]
|
|
6221
6225
|
};
|
|
6222
6226
|
}
|
|
6223
|
-
function errorMessage$
|
|
6227
|
+
function errorMessage$4(error) {
|
|
6224
6228
|
return error instanceof Error ? error.message : String(error);
|
|
6225
6229
|
}
|
|
6226
6230
|
// src/shared/contracts/session-translation.ts
|
|
@@ -6493,8 +6497,8 @@ window.__ModuleLoader__.load({
|
|
|
6493
6497
|
max: 1280
|
|
6494
6498
|
};
|
|
6495
6499
|
const DEFAULT_MOBILE_ACCESS_SETTINGS = {
|
|
6496
|
-
hideSidebarOnMobile:
|
|
6497
|
-
optimizeSettingsOnMobile:
|
|
6500
|
+
hideSidebarOnMobile: false,
|
|
6501
|
+
optimizeSettingsOnMobile: false,
|
|
6498
6502
|
mobileViewportMaxPx: 1024,
|
|
6499
6503
|
...DEFAULT_SIDEBAR_GESTURE_SETTINGS
|
|
6500
6504
|
};
|
|
@@ -6518,8 +6522,8 @@ window.__ModuleLoader__.load({
|
|
|
6518
6522
|
if (sidebarGestureDistancePercent !== void 0) gesture.sidebarGestureDistancePercent = sidebarGestureDistancePercent;
|
|
6519
6523
|
if (sidebarGestureDistancePercent === void 0 && sidebarGestureThresholdPx !== void 0) gesture.sidebarGestureThresholdPx = sidebarGestureThresholdPx;
|
|
6520
6524
|
return {
|
|
6521
|
-
hideSidebarOnMobile:
|
|
6522
|
-
optimizeSettingsOnMobile:
|
|
6525
|
+
hideSidebarOnMobile: false,
|
|
6526
|
+
optimizeSettingsOnMobile: false,
|
|
6523
6527
|
mobileViewportMaxPx: clampSettingsInteger(record.mobileViewportMaxPx, MOBILE_VIEWPORT_MAX_PX_LIMITS, DEFAULT_MOBILE_ACCESS_SETTINGS.mobileViewportMaxPx),
|
|
6524
6528
|
...normalizeSidebarGestureSettings(gesture)
|
|
6525
6529
|
};
|
|
@@ -9194,12 +9198,12 @@ window.__ModuleLoader__.load({
|
|
|
9194
9198
|
if (typeof fields.status === "number" && fields.status >= 400) return true;
|
|
9195
9199
|
if (typeof fields.state === "string" && /^(failed|disconnected|closed|degraded)$/iu.test(fields.state)) return true;
|
|
9196
9200
|
if (typeof fields.event === "string" && fields.event !== event) {
|
|
9197
|
-
const nestedFields = isRecord$
|
|
9201
|
+
const nestedFields = isRecord$16(fields.fields) ? fields.fields : {};
|
|
9198
9202
|
return isDshTransportWarningEvent(fields.event, nestedFields);
|
|
9199
9203
|
}
|
|
9200
9204
|
return false;
|
|
9201
9205
|
}
|
|
9202
|
-
function isRecord$
|
|
9206
|
+
function isRecord$16(value) {
|
|
9203
9207
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9204
9208
|
}
|
|
9205
9209
|
/**
|
|
@@ -10013,15 +10017,15 @@ window.__ModuleLoader__.load({
|
|
|
10013
10017
|
sendHello() {
|
|
10014
10018
|
this.send(this.createEnvelope("session.hello", "session", {
|
|
10015
10019
|
protocol: this.options.protocol ?? "dsh-transport-v1",
|
|
10016
|
-
dshVersion: this.options.dshVersion ?? "0.2.2-
|
|
10020
|
+
dshVersion: this.options.dshVersion ?? "0.2.2-rc.1",
|
|
10017
10021
|
capabilities: [...this.options.capabilities ?? []]
|
|
10018
10022
|
}));
|
|
10019
10023
|
}
|
|
10020
10024
|
sendReady(capabilities, peerDshVersion) {
|
|
10021
10025
|
this.send(this.createEnvelope("session.ready", "session", {
|
|
10022
10026
|
protocol: this.options.protocol ?? "dsh-transport-v1",
|
|
10023
|
-
dshVersion: peerDshVersion ?? this.options.dshVersion ?? "0.2.2-
|
|
10024
|
-
hostDshVersion: this.options.dshVersion ?? "0.2.2-
|
|
10027
|
+
dshVersion: peerDshVersion ?? this.options.dshVersion ?? "0.2.2-rc.1",
|
|
10028
|
+
hostDshVersion: this.options.dshVersion ?? "0.2.2-rc.1",
|
|
10025
10029
|
capabilities: [...capabilities],
|
|
10026
10030
|
byteCredit: 65536,
|
|
10027
10031
|
messageCredit: 32
|
|
@@ -11231,7 +11235,7 @@ window.__ModuleLoader__.load({
|
|
|
11231
11235
|
async onMessage(event) {
|
|
11232
11236
|
const sourceWindow = event.source;
|
|
11233
11237
|
if (this.disposed || sourceWindow === null || !this.iframeWindows.has(sourceWindow)) return;
|
|
11234
|
-
if (!isRecord$
|
|
11238
|
+
if (!isRecord$15(event.data) || typeof event.data.kind !== "string") return;
|
|
11235
11239
|
const message = event.data;
|
|
11236
11240
|
if (message.kind !== "dsh-web-debug" && typeof message.id !== "string") return;
|
|
11237
11241
|
if (typeof message.id === "string") this.messageWindows.set(message.id, sourceWindow);
|
|
@@ -11242,7 +11246,7 @@ window.__ModuleLoader__.load({
|
|
|
11242
11246
|
try {
|
|
11243
11247
|
if (message.kind === "dsh-web-debug") {
|
|
11244
11248
|
const eventName = typeof message.event === "string" ? message.event : "unknown";
|
|
11245
|
-
const fields = isRecord$
|
|
11249
|
+
const fields = isRecord$15(message.fields) ? message.fields : {};
|
|
11246
11250
|
this.debug.log(`iframe.${eventName}`, fields);
|
|
11247
11251
|
if (/^(bridge\.ws\.|client\.connection\.)/u.test(eventName)) await this.options.transport.webRequest("web.debug", {
|
|
11248
11252
|
event: eventName,
|
|
@@ -11251,7 +11255,7 @@ window.__ModuleLoader__.load({
|
|
|
11251
11255
|
return;
|
|
11252
11256
|
}
|
|
11253
11257
|
if (message.kind === "fetch") {
|
|
11254
|
-
const input = isRecord$
|
|
11258
|
+
const input = isRecord$15(message.input) ? message.input : {};
|
|
11255
11259
|
const path = resolveRemotePath(typeof input.path === "string" ? input.path : "/");
|
|
11256
11260
|
const body = typeof message.body === "string" ? message.body : typeof input.body === "string" ? input.body : void 0;
|
|
11257
11261
|
const response = path.startsWith("/assets/") || path.startsWith("/plugins/") ? {
|
|
@@ -11277,7 +11281,7 @@ window.__ModuleLoader__.load({
|
|
|
11277
11281
|
return;
|
|
11278
11282
|
}
|
|
11279
11283
|
if (message.kind === "script") {
|
|
11280
|
-
const input = isRecord$
|
|
11284
|
+
const input = isRecord$15(message.input) ? message.input : {};
|
|
11281
11285
|
const path = resolveRemotePath(typeof input.path === "string" ? input.path : "/");
|
|
11282
11286
|
const url = await this.loadScript(path, void 0);
|
|
11283
11287
|
this.postResponse(message.id, {
|
|
@@ -11287,7 +11291,7 @@ window.__ModuleLoader__.load({
|
|
|
11287
11291
|
return;
|
|
11288
11292
|
}
|
|
11289
11293
|
if (message.kind === "image") {
|
|
11290
|
-
const input = isRecord$
|
|
11294
|
+
const input = isRecord$15(message.input) ? message.input : {};
|
|
11291
11295
|
const path = resolveRemotePath(typeof input.path === "string" ? input.path : "/");
|
|
11292
11296
|
const url = await this.loadImage(path);
|
|
11293
11297
|
this.postResponse(message.id, {
|
|
@@ -11297,7 +11301,7 @@ window.__ModuleLoader__.load({
|
|
|
11297
11301
|
return;
|
|
11298
11302
|
}
|
|
11299
11303
|
if (message.kind === "style") {
|
|
11300
|
-
const input = isRecord$
|
|
11304
|
+
const input = isRecord$15(message.input) ? message.input : {};
|
|
11301
11305
|
const path = resolveRemotePath(typeof input.path === "string" ? input.path : "/");
|
|
11302
11306
|
const url = await this.loadStyle(path, void 0);
|
|
11303
11307
|
this.postResponse(message.id, {
|
|
@@ -11307,7 +11311,7 @@ window.__ModuleLoader__.load({
|
|
|
11307
11311
|
return;
|
|
11308
11312
|
}
|
|
11309
11313
|
if (message.kind === "ws.open") {
|
|
11310
|
-
const input = isRecord$
|
|
11314
|
+
const input = isRecord$15(message.input) ? message.input : {};
|
|
11311
11315
|
const opened = this.options.transport.openWebStreamWithId("web.ws.open", {
|
|
11312
11316
|
sessionId: this.sessionIdValue,
|
|
11313
11317
|
path: resolveRemotePath(typeof input.path === "string" ? input.path : "/")
|
|
@@ -11399,7 +11403,7 @@ window.__ModuleLoader__.load({
|
|
|
11399
11403
|
for await (const value of stream) {
|
|
11400
11404
|
if (!opened) {
|
|
11401
11405
|
opened = true;
|
|
11402
|
-
if (isRecord$
|
|
11406
|
+
if (isRecord$15(value) && value.opened === true) {
|
|
11403
11407
|
this.socketReady.get(id)?.resolve();
|
|
11404
11408
|
this.socketReady.delete(id);
|
|
11405
11409
|
continue;
|
|
@@ -12053,7 +12057,7 @@ window.__ModuleLoader__.load({
|
|
|
12053
12057
|
const policy = "default-src 'self' blob: data:; script-src 'self' blob: data: 'unsafe-inline' 'unsafe-eval'; style-src 'self' blob: data: 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self' blob: data:; media-src 'self' blob: data:; worker-src 'self' blob:; connect-src 'none'; frame-src 'self' blob: data:";
|
|
12054
12058
|
for (const node of documentValue.querySelectorAll("meta[http-equiv]")) if ((node.getAttribute("http-equiv") ?? "").toLowerCase() === "content-security-policy") node.setAttribute("content", policy);
|
|
12055
12059
|
}
|
|
12056
|
-
function isRecord$
|
|
12060
|
+
function isRecord$15(value) {
|
|
12057
12061
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12058
12062
|
}
|
|
12059
12063
|
function toBytes(value) {
|
|
@@ -20276,11 +20280,11 @@ window.__ModuleLoader__.load({
|
|
|
20276
20280
|
};
|
|
20277
20281
|
}
|
|
20278
20282
|
function readMarker(event) {
|
|
20279
|
-
if (!isRecord$
|
|
20283
|
+
if (!isRecord$14(event)) return null;
|
|
20280
20284
|
const data = event.data;
|
|
20281
|
-
if (!isRecord$
|
|
20282
|
-
const candidate = event.type === "assistant/live-chunk" ? isRecord$
|
|
20283
|
-
if (!isRecord$
|
|
20285
|
+
if (!isRecord$14(data)) return null;
|
|
20286
|
+
const candidate = event.type === "assistant/live-chunk" ? isRecord$14(data.chunk) ? data.chunk.codingnsExternalTool : void 0 : event.type === "assistant/attempt" ? data.codingnsExternalTool : void 0;
|
|
20287
|
+
if (!isRecord$14(candidate) || candidate.source !== "codingns-external-tool") return null;
|
|
20284
20288
|
if (typeof candidate.callId !== "string" || candidate.callId === "") return null;
|
|
20285
20289
|
if (typeof candidate.name !== "string" || typeof candidate.arguments !== "string") return null;
|
|
20286
20290
|
if (candidate.phase !== "start" && candidate.phase !== "update") return null;
|
|
@@ -20296,7 +20300,7 @@ window.__ModuleLoader__.load({
|
|
|
20296
20300
|
...typeof candidate.error === "string" ? { error: candidate.error } : {}
|
|
20297
20301
|
};
|
|
20298
20302
|
}
|
|
20299
|
-
function isRecord$
|
|
20303
|
+
function isRecord$14(value) {
|
|
20300
20304
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20301
20305
|
}
|
|
20302
20306
|
// src/client/native-translation-default.ts
|
|
@@ -20632,7 +20636,7 @@ window.__ModuleLoader__.load({
|
|
|
20632
20636
|
capability,
|
|
20633
20637
|
routeId: route.id,
|
|
20634
20638
|
dshVersion: this.dshVersion,
|
|
20635
|
-
message: `${route.id} 探测失败: ${errorMessage$
|
|
20639
|
+
message: `${route.id} 探测失败: ${errorMessage$3(error)}`,
|
|
20636
20640
|
...route.replacement === void 0 ? {} : { replacement: route.replacement }
|
|
20637
20641
|
});
|
|
20638
20642
|
}
|
|
@@ -20667,7 +20671,7 @@ window.__ModuleLoader__.load({
|
|
|
20667
20671
|
...selected.replacement === void 0 ? {} : { replacement: selected.replacement }
|
|
20668
20672
|
});
|
|
20669
20673
|
} catch (error) {
|
|
20670
|
-
const reason = `${selected.id} 创建失败: ${errorMessage$
|
|
20674
|
+
const reason = `${selected.id} 创建失败: ${errorMessage$3(error)}`;
|
|
20671
20675
|
resolutions.set(capability, unavailable(capability, this.dshVersion, reason));
|
|
20672
20676
|
diagnostics.push({
|
|
20673
20677
|
code: "CAPABILITY_CREATE_FAILED",
|
|
@@ -20751,7 +20755,7 @@ window.__ModuleLoader__.load({
|
|
|
20751
20755
|
}
|
|
20752
20756
|
return 0;
|
|
20753
20757
|
}
|
|
20754
|
-
function errorMessage$
|
|
20758
|
+
function errorMessage$3(error) {
|
|
20755
20759
|
return error instanceof Error ? error.message : String(error);
|
|
20756
20760
|
}
|
|
20757
20761
|
// src/dsh-capabilities/client/terminal-sharing-adapter.ts
|
|
@@ -21315,8 +21319,12 @@ window.__ModuleLoader__.load({
|
|
|
21315
21319
|
const owner = controller?.agents;
|
|
21316
21320
|
return typeof owner?.selectionFor === "function" ? owner : void 0;
|
|
21317
21321
|
}
|
|
21322
|
+
function agentRegistry(controller) {
|
|
21323
|
+
const agents = controller?.agents;
|
|
21324
|
+
return typeof agents?.get === "function" ? agents : void 0;
|
|
21325
|
+
}
|
|
21318
21326
|
function supportsSessionModelSelection(controller) {
|
|
21319
|
-
return selectionOwner(controller) !== void 0;
|
|
21327
|
+
return selectionOwner(controller) !== void 0 || agentRegistry(controller) !== void 0;
|
|
21320
21328
|
}
|
|
21321
21329
|
/**
|
|
21322
21330
|
* DSH's prompt admission reads selectionFor().current before agent/request.
|
|
@@ -21326,6 +21334,7 @@ window.__ModuleLoader__.load({
|
|
|
21326
21334
|
*/
|
|
21327
21335
|
function createSessionModelSelectionAdapter(controller) {
|
|
21328
21336
|
const owner = selectionOwner(controller);
|
|
21337
|
+
if (owner === void 0) return { install: () => () => void 0 };
|
|
21329
21338
|
return { install(resolve) {
|
|
21330
21339
|
const original = owner.selectionFor;
|
|
21331
21340
|
const ownDescriptor = Object.getOwnPropertyDescriptor(owner, "selectionFor");
|
|
@@ -21833,7 +21842,16 @@ window.__ModuleLoader__.load({
|
|
|
21833
21842
|
/** Registration owns schema admission, cold replay, checkpoints, and live projection delivery. */
|
|
21834
21843
|
function createSessionPerformanceAdapter(context) {
|
|
21835
21844
|
const service = projections(context);
|
|
21836
|
-
return { install
|
|
21845
|
+
return { async install(definition) {
|
|
21846
|
+
const registered = service.register(definition);
|
|
21847
|
+
if (typeof registered === "function") return async () => {
|
|
21848
|
+
registered();
|
|
21849
|
+
};
|
|
21850
|
+
const handle = await registered;
|
|
21851
|
+
return async () => {
|
|
21852
|
+
await handle.dispose?.();
|
|
21853
|
+
};
|
|
21854
|
+
} };
|
|
21837
21855
|
}
|
|
21838
21856
|
// src/shared/codex-performance.ts
|
|
21839
21857
|
const CODEX_PERFORMANCE_PROJECTION = "codingnsCodexStats";
|
|
@@ -21927,6 +21945,19 @@ window.__ModuleLoader__.load({
|
|
|
21927
21945
|
"subscribe"
|
|
21928
21946
|
].every((key) => typeof slots[key] === "function");
|
|
21929
21947
|
}
|
|
21948
|
+
function hasProviderTiming(adapter) {
|
|
21949
|
+
return adapter === "codex" || adapter === "grok";
|
|
21950
|
+
}
|
|
21951
|
+
/** Native DSH timing for translated Claude messages measures delivery, not model decoding. */
|
|
21952
|
+
function withoutUnverifiedProviderTiming(stats) {
|
|
21953
|
+
return {
|
|
21954
|
+
...stats,
|
|
21955
|
+
ttftMs: 0,
|
|
21956
|
+
ttftSteps: 0,
|
|
21957
|
+
decodeTokens: 0,
|
|
21958
|
+
decodeMs: 0
|
|
21959
|
+
};
|
|
21960
|
+
}
|
|
21930
21961
|
/** Reuse the native activity pill, dialog, localization, settings, and session binding. */
|
|
21931
21962
|
function createSessionPerformancePresentation(context) {
|
|
21932
21963
|
const slots = context.slots;
|
|
@@ -21942,7 +21973,8 @@ window.__ModuleLoader__.load({
|
|
|
21942
21973
|
const original = props.useProjection(key, ...args);
|
|
21943
21974
|
if (key !== "sessionStats") return original;
|
|
21944
21975
|
const value = props.useProjection(adapter === "grok" ? GROK_PERFORMANCE_PROJECTION : CODEX_PERFORMANCE_PROJECTION, ...args);
|
|
21945
|
-
if (adapter
|
|
21976
|
+
if (adapter === "claude-code") return withoutUnverifiedProviderTiming(original);
|
|
21977
|
+
if (!hasProviderTiming(adapter)) return original;
|
|
21946
21978
|
return value ?? {
|
|
21947
21979
|
turns: 0,
|
|
21948
21980
|
steps: 0,
|
|
@@ -22265,6 +22297,35 @@ window.__ModuleLoader__.load({
|
|
|
22265
22297
|
return false;
|
|
22266
22298
|
}
|
|
22267
22299
|
}
|
|
22300
|
+
// src/dsh-capabilities/client/context-menu-adapter.ts
|
|
22301
|
+
function readContextMenus(context) {
|
|
22302
|
+
const native = readService$2(context, "contextMenus");
|
|
22303
|
+
if (!isNativeContextMenus(native)) return void 0;
|
|
22304
|
+
return {
|
|
22305
|
+
register(input) {
|
|
22306
|
+
return native.register(input);
|
|
22307
|
+
},
|
|
22308
|
+
notify(text, success = false) {
|
|
22309
|
+
native.notify(text, success);
|
|
22310
|
+
}
|
|
22311
|
+
};
|
|
22312
|
+
}
|
|
22313
|
+
function supportsContextMenus(context) {
|
|
22314
|
+
return isNativeContextMenus(readService$2(context, "contextMenus"));
|
|
22315
|
+
}
|
|
22316
|
+
function isNativeContextMenus(value) {
|
|
22317
|
+
return typeof value?.register === "function" && typeof value.notify === "function";
|
|
22318
|
+
}
|
|
22319
|
+
function readService$2(context, name) {
|
|
22320
|
+
if (typeof context !== "object" || context === null) return void 0;
|
|
22321
|
+
try {
|
|
22322
|
+
const getter = Reflect.get(context, "get");
|
|
22323
|
+
if (typeof getter === "function") return getter.call(context, name);
|
|
22324
|
+
return Reflect.get(context, name);
|
|
22325
|
+
} catch {
|
|
22326
|
+
return;
|
|
22327
|
+
}
|
|
22328
|
+
}
|
|
22268
22329
|
// src/shared/contracts/plugin-update.ts
|
|
22269
22330
|
const CODINGNS_PACKAGE_NAME = "@jingyi0605/codingns4dsh";
|
|
22270
22331
|
const CODINGNS_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -22361,25 +22422,31 @@ window.__ModuleLoader__.load({
|
|
|
22361
22422
|
};
|
|
22362
22423
|
}
|
|
22363
22424
|
function normalizePluginManagerOutcome(value, version) {
|
|
22364
|
-
const
|
|
22425
|
+
const outer = isRecord$13(value) ? value : {};
|
|
22426
|
+
const result = isRecord$13(outer.result) ? outer.result : outer;
|
|
22427
|
+
const restore = isRecord$13(outer.restore) ? outer.restore : void 0;
|
|
22365
22428
|
const application = [
|
|
22366
22429
|
"applied",
|
|
22367
22430
|
"restart-required",
|
|
22368
22431
|
"overridden",
|
|
22369
22432
|
"failed",
|
|
22370
22433
|
"cancelled"
|
|
22371
|
-
].includes(String(result
|
|
22372
|
-
const accepted = result
|
|
22373
|
-
const error = result
|
|
22434
|
+
].includes(String(result.application)) ? result.application : "unknown";
|
|
22435
|
+
const accepted = result.bundle === "@jingyi0605/codingns4dsh" && result.version === version || result.target === `@jingyi0605/codingns4dsh@${version}`;
|
|
22436
|
+
const error = isRecord$13(result.error) ? result.error : void 0;
|
|
22374
22437
|
const code = typeof error?.code === "string" && /^[a-z-]{1,64}$/u.test(error.code) ? `UPDATE_MANAGER_${error.code.toUpperCase().replaceAll("-", "_")}` : void 0;
|
|
22375
22438
|
return {
|
|
22376
22439
|
application,
|
|
22377
22440
|
installedVersion: accepted ? version : null,
|
|
22378
22441
|
packageAccepted: accepted,
|
|
22379
|
-
restored: result
|
|
22442
|
+
restored: restore?.application === "applied" || restore?.application === "restart-required" || result.stage === "install" && result.changed === false && result.packageResult !== void 0 && (application === "cancelled" || application === "failed" && error?.code === "incompatible-version"),
|
|
22443
|
+
...typeof result.restartReason === "string" ? { restartReason: result.restartReason } : {},
|
|
22380
22444
|
...code === void 0 ? {} : { errorCode: code }
|
|
22381
22445
|
};
|
|
22382
22446
|
}
|
|
22447
|
+
function isRecord$13(value) {
|
|
22448
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
22449
|
+
}
|
|
22383
22450
|
// src/dsh-capabilities/routes.ts
|
|
22384
22451
|
/**
|
|
22385
22452
|
* 注册 Codingns4DSH 当前实际消费的 DSH 服务能力。
|
|
@@ -22650,6 +22717,17 @@ window.__ModuleLoader__.load({
|
|
|
22650
22717
|
detect: supportsGlobalPanel,
|
|
22651
22718
|
create: createGlobalPanelAdapter
|
|
22652
22719
|
});
|
|
22720
|
+
add({
|
|
22721
|
+
id: "ui-context-menu-022",
|
|
22722
|
+
capability: "ui.context-menu",
|
|
22723
|
+
supportedDsh: ">=0.2.2-alpha.3",
|
|
22724
|
+
runtime,
|
|
22725
|
+
priority: 20,
|
|
22726
|
+
status: "supported",
|
|
22727
|
+
introducedIn: "0.2.2-alpha.3",
|
|
22728
|
+
detect: supportsContextMenus,
|
|
22729
|
+
create: readContextMenus
|
|
22730
|
+
});
|
|
22653
22731
|
add({
|
|
22654
22732
|
id: "session-performance-presentation-021",
|
|
22655
22733
|
capability: "session.external-performance",
|
|
@@ -27505,6 +27583,7 @@ window.__ModuleLoader__.load({
|
|
|
27505
27583
|
const [quotaResetResult, setQuotaResetResult] = (0, react.useState)(null);
|
|
27506
27584
|
const [quotaResetFailed, setQuotaResetFailed] = (0, react.useState)(false);
|
|
27507
27585
|
const [chartMetric, setChartMetric] = (0, react.useState)("calls");
|
|
27586
|
+
const [usageSortMetric, setUsageSortMetric] = (0, react.useState)("cost");
|
|
27508
27587
|
const [sessionSearch, setSessionSearch] = (0, react.useState)("");
|
|
27509
27588
|
const [selectedSession, setSelectedSession] = (0, react.useState)(null);
|
|
27510
27589
|
const [requestPage, setRequestPage] = (0, react.useState)(null);
|
|
@@ -27875,12 +27954,16 @@ window.__ModuleLoader__.load({
|
|
|
27875
27954
|
className: `codingns-magpie-usage-tab${usageTab === entry.id ? " is-active" : ""}`,
|
|
27876
27955
|
"aria-pressed": usageTab === entry.id,
|
|
27877
27956
|
onClick: () => selectUsageTab(entry.id)
|
|
27878
|
-
}, t(entry.label))))), section === "quotas" && (0, react.createElement)("div", { className: "codingns-magpie-toolbar-right" }, (0, react.createElement)(QuotaViewSwitch, {
|
|
27957
|
+
}, t(entry.label))))), (section === "quotas" || section === "sessions") && (0, react.createElement)("div", { className: "codingns-magpie-toolbar-right" }, section === "quotas" && (0, react.createElement)(QuotaViewSwitch, {
|
|
27879
27958
|
value: quotaView,
|
|
27880
27959
|
disabled: settings === void 0 ? false : !quotaViewWritable,
|
|
27881
27960
|
failed: quotaViewSaveFailed,
|
|
27882
27961
|
onChange: selectQuotaView,
|
|
27883
27962
|
t
|
|
27963
|
+
}), section === "sessions" && (0, react.createElement)(UsageMetricSwitch, {
|
|
27964
|
+
value: usageSortMetric,
|
|
27965
|
+
onChange: setUsageSortMetric,
|
|
27966
|
+
t
|
|
27884
27967
|
}))), (0, react.createElement)("main", { className: "codingns-magpie-main" }, section === "providers" || section === "groups" ? managementIssue !== null && management === null ? (0, react.createElement)(EmptyState, { message: t(managementIssueLocaleKey(managementIssue)) }) : managementLoading && management === null ? (0, react.createElement)(EmptyState, {
|
|
27885
27968
|
message: t("magpie.management.loading"),
|
|
27886
27969
|
loading: true
|
|
@@ -27903,6 +27986,8 @@ window.__ModuleLoader__.load({
|
|
|
27903
27986
|
error: dashboardError,
|
|
27904
27987
|
chartMetric,
|
|
27905
27988
|
onChartMetricChange: setChartMetric,
|
|
27989
|
+
usageSortMetric,
|
|
27990
|
+
onUsageSortMetricChange: setUsageSortMetric,
|
|
27906
27991
|
t,
|
|
27907
27992
|
onOpenSession: openSession
|
|
27908
27993
|
}) : section === "sessions" ? (0, react.createElement)(SessionsPage, {
|
|
@@ -27910,6 +27995,7 @@ window.__ModuleLoader__.load({
|
|
|
27910
27995
|
sessions: filteredSessions,
|
|
27911
27996
|
search: sessionSearch,
|
|
27912
27997
|
onSearch: setSessionSearch,
|
|
27998
|
+
usageSortMetric,
|
|
27913
27999
|
onOpenSession: openSession,
|
|
27914
28000
|
t
|
|
27915
28001
|
}) : section === "requests" ? (0, react.createElement)(RequestsPage, {
|
|
@@ -27950,7 +28036,7 @@ window.__ModuleLoader__.load({
|
|
|
27950
28036
|
onClose: closeQuotaReset
|
|
27951
28037
|
}));
|
|
27952
28038
|
}
|
|
27953
|
-
function OverviewPage({ dashboard, loading, error, chartMetric, onChartMetricChange, t, onOpenSession }) {
|
|
28039
|
+
function OverviewPage({ dashboard, loading, error, chartMetric, onChartMetricChange, usageSortMetric = "cost", onUsageSortMetricChange = () => void 0, t, onOpenSession }) {
|
|
27954
28040
|
const [modelBreakdownMode, setModelBreakdownMode] = (0, react.useState)("aggregate");
|
|
27955
28041
|
const metrics = dashboard?.aggregate;
|
|
27956
28042
|
if (dashboard === null || dashboard.usageStatus === "unavailable" || metrics == null) return (0, react.createElement)(EmptyState, {
|
|
@@ -27998,17 +28084,24 @@ window.__ModuleLoader__.load({
|
|
|
27998
28084
|
points: dashboard.series,
|
|
27999
28085
|
metric: chartMetric,
|
|
28000
28086
|
label: t(`magpie.chart.${chartMetric}`)
|
|
28087
|
+
})), (0, react.createElement)("div", { className: "codingns-magpie-usage-sortbar" }, (0, react.createElement)(UsageMetricSwitch, {
|
|
28088
|
+
value: usageSortMetric,
|
|
28089
|
+
onChange: onUsageSortMetricChange,
|
|
28090
|
+
t
|
|
28001
28091
|
})), (0, react.createElement)(ProgressSection, {
|
|
28002
28092
|
title: t("magpie.byAgent"),
|
|
28003
28093
|
rows: dashboard.agents,
|
|
28094
|
+
metric: usageSortMetric,
|
|
28004
28095
|
t
|
|
28005
28096
|
}), (0, react.createElement)(ModelProgressSection, {
|
|
28006
28097
|
rows: dashboard.models,
|
|
28007
28098
|
mode: modelBreakdownMode,
|
|
28008
28099
|
onModeChange: setModelBreakdownMode,
|
|
28100
|
+
metric: usageSortMetric,
|
|
28009
28101
|
t
|
|
28010
28102
|
}), dashboard.sessions.length > 0 && (0, react.createElement)(ProgressSection, {
|
|
28011
28103
|
title: t("magpie.topSessions"),
|
|
28104
|
+
metric: usageSortMetric,
|
|
28012
28105
|
rows: dashboard.sessions.map((session) => ({
|
|
28013
28106
|
...session,
|
|
28014
28107
|
id: `${session.agent}:${session.id}`,
|
|
@@ -28101,7 +28194,8 @@ window.__ModuleLoader__.load({
|
|
|
28101
28194
|
onClick: onCheck
|
|
28102
28195
|
}, loading ? t("magpie.refreshing") : t("magpie.update.check")))));
|
|
28103
28196
|
}
|
|
28104
|
-
function ModelProgressSection({ rows, mode, onModeChange, t }) {
|
|
28197
|
+
function ModelProgressSection({ rows, mode, onModeChange, metric, t }) {
|
|
28198
|
+
const sortMetric = metric ?? "cost";
|
|
28105
28199
|
const controls = (0, react.createElement)("div", {
|
|
28106
28200
|
className: "codingns-magpie-chart-switch",
|
|
28107
28201
|
role: "group",
|
|
@@ -28118,15 +28212,17 @@ window.__ModuleLoader__.load({
|
|
|
28118
28212
|
key: `model-breakdown-${mode}`,
|
|
28119
28213
|
title: t("magpie.byModel"),
|
|
28120
28214
|
rows: displayRows,
|
|
28215
|
+
metric: sortMetric,
|
|
28121
28216
|
t,
|
|
28122
28217
|
header: controls,
|
|
28123
28218
|
...mode === "aggregate" ? { limit: 8 } : {}
|
|
28124
28219
|
});
|
|
28125
28220
|
}
|
|
28126
|
-
function SessionsPage({ dashboard, sessions, search, onSearch, onOpenSession, t }) {
|
|
28221
|
+
function SessionsPage({ dashboard, sessions, search, onSearch, usageSortMetric = "cost", onOpenSession, t }) {
|
|
28127
28222
|
const [agentFilter, setAgentFilter] = (0, react.useState)("");
|
|
28128
28223
|
const agentNames = (0, react.useMemo)(() => [...new Set(sessions.map((session) => session.agent))].sort(), [sessions]);
|
|
28129
28224
|
const visible = agentFilter === "" ? sessions : sessions.filter((session) => session.agent === agentFilter);
|
|
28225
|
+
const sortedVisible = (0, react.useMemo)(() => sortUsageRows(visible, usageSortMetric), [usageSortMetric, visible]);
|
|
28130
28226
|
const aggregate = sumSessions(visible);
|
|
28131
28227
|
const metrics = dashboard?.aggregate;
|
|
28132
28228
|
const stats = [
|
|
@@ -28184,7 +28280,7 @@ window.__ModuleLoader__.load({
|
|
|
28184
28280
|
points: dashboard.series,
|
|
28185
28281
|
metric: "tokens",
|
|
28186
28282
|
label: t("magpie.chart.tokens")
|
|
28187
|
-
})), visible.length === 0 ? (0, react.createElement)(EmptyState, { message: t(search === "" && agentFilter === "" ? "magpie.noSessions" : "magpie.noRequests") }) : (0, react.createElement)("section", { className: "codingns-magpie-panel codingns-magpie-toplist-panel" }, (0, react.createElement)("div", { className: "codingns-magpie-panel-head" }, (0, react.createElement)("h2", void 0, t("magpie.topSessions"))), ...
|
|
28283
|
+
})), visible.length === 0 ? (0, react.createElement)(EmptyState, { message: t(search === "" && agentFilter === "" ? "magpie.noSessions" : "magpie.noRequests") }) : (0, react.createElement)("section", { className: "codingns-magpie-panel codingns-magpie-toplist-panel" }, (0, react.createElement)("div", { className: "codingns-magpie-panel-head" }, (0, react.createElement)("h2", void 0, t("magpie.topSessions"))), ...sortedVisible.slice(0, 40).map((session) => (0, react.createElement)("button", {
|
|
28188
28284
|
key: `${session.agent}:${session.id}`,
|
|
28189
28285
|
type: "button",
|
|
28190
28286
|
className: "codingns-magpie-toprow",
|
|
@@ -28438,6 +28534,19 @@ window.__ModuleLoader__.load({
|
|
|
28438
28534
|
}
|
|
28439
28535
|
}, t(entry.label)))));
|
|
28440
28536
|
}
|
|
28537
|
+
function UsageMetricSwitch({ value, onChange, t }) {
|
|
28538
|
+
return (0, react.createElement)("div", {
|
|
28539
|
+
className: "codingns-magpie-usage-metric",
|
|
28540
|
+
role: "group",
|
|
28541
|
+
"aria-label": t("magpie.sortMetric")
|
|
28542
|
+
}, (0, react.createElement)("span", { className: "codingns-magpie-usage-metric-label" }, t("magpie.sortMetric")), (0, react.createElement)("div", { className: "codingns-magpie-chart-switch" }, ...["cost", "tokens"].map((metric) => (0, react.createElement)("button", {
|
|
28543
|
+
key: metric,
|
|
28544
|
+
type: "button",
|
|
28545
|
+
className: value === metric ? "is-active" : "",
|
|
28546
|
+
"aria-pressed": value === metric,
|
|
28547
|
+
onClick: () => onChange(metric)
|
|
28548
|
+
}, metric === "cost" ? t("magpie.metricCost") : t("magpie.tokens")))));
|
|
28549
|
+
}
|
|
28441
28550
|
/** 口径控件左侧的圆形图标:半实心圆表示"部分已用",与进度条的语义一致。 */
|
|
28442
28551
|
function QuotaViewIcon() {
|
|
28443
28552
|
return (0, react.createElement)("svg", {
|
|
@@ -28512,14 +28621,26 @@ window.__ModuleLoader__.load({
|
|
|
28512
28621
|
className: "codingns-magpie-barchart-tick"
|
|
28513
28622
|
}, point.label ?? "")] : [])), (0, react.createElement)("div", { className: "codingns-magpie-barchart-peak" }, formatValue(Math.max(...known))));
|
|
28514
28623
|
}
|
|
28515
|
-
function
|
|
28516
|
-
|
|
28624
|
+
function usageMetricValue(row, metric) {
|
|
28625
|
+
return metric === "cost" ? row.cost : sumNullable(row.inputTokens, row.outputTokens);
|
|
28626
|
+
}
|
|
28627
|
+
function sortUsageRows(rows, metric) {
|
|
28628
|
+
return [...rows].sort((left, right) => compareNullableDescending(usageMetricValue(left, metric), usageMetricValue(right, metric)) || compareNullableDescending(left.calls, right.calls));
|
|
28629
|
+
}
|
|
28630
|
+
function compareNullableDescending(left, right) {
|
|
28631
|
+
if (left === null && right === null) return 0;
|
|
28632
|
+
if (left === null) return 1;
|
|
28633
|
+
if (right === null) return -1;
|
|
28634
|
+
return right - left;
|
|
28635
|
+
}
|
|
28636
|
+
function ProgressSection({ title, rows, metric, t, onOpen, header, limit = 8 }) {
|
|
28637
|
+
const sorted = sortUsageRows(rows, metric);
|
|
28517
28638
|
const display = limit === void 0 ? sorted : sorted.slice(0, limit);
|
|
28518
|
-
const
|
|
28519
|
-
const max = Math.max(1, ...display.map((row) =>
|
|
28639
|
+
const displayMetric = metric === "cost" && display.some((row) => row.cost !== null) ? "cost" : "tokens";
|
|
28640
|
+
const max = Math.max(1, ...display.map((row) => usageMetricValue(row, displayMetric) ?? 0));
|
|
28520
28641
|
return (0, react.createElement)("section", { className: "codingns-magpie-panel codingns-magpie-progress-panel" }, (0, react.createElement)("div", { className: "codingns-magpie-panel-head" }, (0, react.createElement)("h2", void 0, title), header), display.length === 0 ? (0, react.createElement)("div", { className: "codingns-magpie-inline-empty" }, "—") : (0, react.createElement)("div", { className: "codingns-magpie-progress-list" }, ...display.map((row) => {
|
|
28521
28642
|
const label = row.label ?? row.name ?? row.model ?? row.account ?? row.provider ?? row.agent ?? row.id;
|
|
28522
|
-
const weight = Math.max(0,
|
|
28643
|
+
const weight = Math.max(0, usageMetricValue(row, displayMetric) ?? 0);
|
|
28523
28644
|
const body = (0, react.createElement)("div", { className: "codingns-magpie-progress-row" }, (0, react.createElement)("div", { className: "codingns-magpie-progress-head" }, (0, react.createElement)("span", { className: "codingns-magpie-provider-inline" }, (0, react.createElement)(MagpieProviderLogo, {
|
|
28524
28645
|
identities: [
|
|
28525
28646
|
row.agent,
|
|
@@ -28536,7 +28657,7 @@ window.__ModuleLoader__.load({
|
|
|
28536
28657
|
}, label), (row.account ?? row.provider) !== null && (0, react.createElement)("small", {
|
|
28537
28658
|
className: "codingns-magpie-progress-context",
|
|
28538
28659
|
title: row.account ?? row.provider ?? ""
|
|
28539
|
-
}, row.account ?? row.provider))), (0, react.createElement)("strong", { className: "codingns-magpie-progress-value" },
|
|
28660
|
+
}, row.account ?? row.provider))), (0, react.createElement)("strong", { className: "codingns-magpie-progress-value" }, displayMetric === "cost" ? formatValue(row.cost) : formatCompact(sumNullable(row.inputTokens, row.outputTokens)))), (0, react.createElement)("div", { className: "codingns-magpie-progress-track" }, (0, react.createElement)("span", { style: { width: `${Math.max(2, weight / max * 100)}%` } })), (0, react.createElement)("small", { className: "codingns-magpie-progress-meta" }, `${formatInteger$1(row.calls)} ${t("magpie.metricCalls")} · ${formatCompact(sumNullable(row.inputTokens, row.outputTokens))} token · ${formatValue(row.cost)}`));
|
|
28540
28661
|
return onOpen === void 0 ? (0, react.createElement)("div", {
|
|
28541
28662
|
key: row.id,
|
|
28542
28663
|
className: "codingns-magpie-progress-item"
|
|
@@ -29038,6 +29159,8 @@ window.__ModuleLoader__.load({
|
|
|
29038
29159
|
/* Pin the usage-view switch to the toolbar's right edge so the icon and the
|
|
29039
29160
|
segmented control stay together instead of wrapping with the left tabs. */
|
|
29040
29161
|
.codingns-magpie-toolbar-right{display:flex;align-items:center;justify-content:flex-end;gap:10px;flex:0 0 auto;margin-left:auto;min-width:0}
|
|
29162
|
+
.codingns-magpie-usage-metric{display:flex;align-items:center;gap:8px;flex:0 0 auto;min-width:0;color:var(--mp-muted);font-size:${uiFontSize(13)}}
|
|
29163
|
+
.codingns-magpie-usage-sortbar{display:flex;justify-content:flex-end;margin:14px 0 12px}
|
|
29041
29164
|
.codingns-magpie-quota-view{display:flex;align-items:center;gap:8px;flex:0 0 auto;min-width:0;color:var(--mp-muted);font-size:${uiFontSize(13)}}
|
|
29042
29165
|
.codingns-magpie-quota-view-icon{display:grid;place-items:center;flex:0 0 auto;width:22px;height:22px;color:var(--mp-muted)}
|
|
29043
29166
|
.codingns-magpie-quota-view-icon-svg{display:block}
|
|
@@ -30797,6 +30920,22 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
30797
30920
|
scheduleScan();
|
|
30798
30921
|
});
|
|
30799
30922
|
};
|
|
30923
|
+
const contextMenuDispose = options.contextMenus?.register({
|
|
30924
|
+
id: "codingns.workspace-visibility.hide",
|
|
30925
|
+
target: "workspace",
|
|
30926
|
+
order: 400,
|
|
30927
|
+
resolve: (value) => {
|
|
30928
|
+
const workspaceId = typeof value?.workspaceId === "string" ? value.workspaceId : "";
|
|
30929
|
+
if (workspaceId === "") return [];
|
|
30930
|
+
return [{
|
|
30931
|
+
id: "hide",
|
|
30932
|
+
label: t("workspaceVisibility.hide"),
|
|
30933
|
+
run: () => {
|
|
30934
|
+
updateVisibility(workspaceId, true);
|
|
30935
|
+
}
|
|
30936
|
+
}];
|
|
30937
|
+
}
|
|
30938
|
+
});
|
|
30800
30939
|
const refreshData = async () => {
|
|
30801
30940
|
if (disposed || options.readNativeWorkspaceSnapshot?.() !== void 0) return;
|
|
30802
30941
|
if (loading !== void 0) {
|
|
@@ -30825,7 +30964,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
30825
30964
|
const workspaceId = resolveWorkspaceId(header);
|
|
30826
30965
|
if (workspaceId === void 0) continue;
|
|
30827
30966
|
workspaceIds.add(workspaceId);
|
|
30828
|
-
bindWorkspaceMenuTriggers(header, workspaceId, () => {
|
|
30967
|
+
if (options.contextMenus === void 0) bindWorkspaceMenuTriggers(header, workspaceId, () => {
|
|
30829
30968
|
activeMenuWorkspaceId = workspaceId;
|
|
30830
30969
|
activeFilterTrigger = void 0;
|
|
30831
30970
|
activeMenuKind = "workspace";
|
|
@@ -30863,7 +31002,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
30863
31002
|
suppressFilterTrigger = false;
|
|
30864
31003
|
};
|
|
30865
31004
|
}), t);
|
|
30866
|
-
else injectWorkspaceMenuActions(selectWorkspaceMenus(menus, menuContextFresh, menuWorkspaceIds), dom, menuContextFresh ? activeMenuWorkspaceId : void 0, workspaceIds, menuWorkspaceIds, (workspaceId) => updateVisibility(workspaceId, true), t);
|
|
31005
|
+
else if (options.contextMenus === void 0) injectWorkspaceMenuActions(selectWorkspaceMenus(menus, menuContextFresh, menuWorkspaceIds), dom, menuContextFresh ? activeMenuWorkspaceId : void 0, workspaceIds, menuWorkspaceIds, (workspaceId) => updateVisibility(workspaceId, true), t);
|
|
30867
31006
|
if (menus.length === 0 && !menuContextPending) {
|
|
30868
31007
|
activeMenuWorkspaceId = void 0;
|
|
30869
31008
|
activeMenuKind = void 0;
|
|
@@ -30925,6 +31064,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
30925
31064
|
removeVisibilityEntries(dom);
|
|
30926
31065
|
removeMenuEntries(dom);
|
|
30927
31066
|
}
|
|
31067
|
+
contextMenuDispose?.();
|
|
30928
31068
|
}
|
|
30929
31069
|
};
|
|
30930
31070
|
}
|
|
@@ -35647,13 +35787,20 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
35647
35787
|
sensitivity: "base",
|
|
35648
35788
|
ignorePunctuation: true
|
|
35649
35789
|
});
|
|
35790
|
+
function compareModelProviderAndName(left, right) {
|
|
35791
|
+
const baseName = (model) => model.name.replace(/\[1m\]/gu, "").split(" · ")[0].trim();
|
|
35792
|
+
return claudeModelCollator.compare(left.magpieProviderId ?? "", right.magpieProviderId ?? "") || claudeModelCollator.compare(baseName(left), baseName(right)) || Number(left.id.endsWith("[1m]")) - Number(right.id.endsWith("[1m]")) || left.id.localeCompare(right.id, "en");
|
|
35793
|
+
}
|
|
35650
35794
|
function compareClaudeModelOptions(left, right) {
|
|
35651
35795
|
const aliasRank = (id) => {
|
|
35652
35796
|
const index = claudeModelAliases.indexOf(id);
|
|
35653
35797
|
return index < 0 ? claudeModelAliases.length : index;
|
|
35654
35798
|
};
|
|
35655
|
-
|
|
35656
|
-
|
|
35799
|
+
return aliasRank(left.id) - aliasRank(right.id) || compareModelProviderAndName(left, right);
|
|
35800
|
+
}
|
|
35801
|
+
function compareAntigravityModelOptions(left, right) {
|
|
35802
|
+
const aliasRank = (id) => id === "provider-default" ? 0 : 1;
|
|
35803
|
+
return aliasRank(left.id) - aliasRank(right.id) || compareModelProviderAndName(left, right);
|
|
35657
35804
|
}
|
|
35658
35805
|
const CLI_STYLE_ID = "codingns4dsh-cli-composer-style";
|
|
35659
35806
|
const CIRCULAR_PROVIDER_ICON_IDS = /* @__PURE__ */ new Set(["gemini", "grok"]);
|
|
@@ -36422,7 +36569,8 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
36422
36569
|
const efforts = model?.efforts ?? [];
|
|
36423
36570
|
const storedEffort = selection.effortId;
|
|
36424
36571
|
const effortValue = storedEffort !== void 0 && (model === void 0 || efforts.includes(storedEffort)) ? storedEffort : defaultEffort(efforts) ?? "default";
|
|
36425
|
-
const
|
|
36572
|
+
const modelDisplayName = (item) => selection.adapterId === "antigravity" && item.id !== "provider-default" && !item.id.startsWith("magpie/") && item.source !== "magpie" ? t("cli.antigravityNativeModel", { name: item.name }) : item.name;
|
|
36573
|
+
const modelLabel = model === void 0 ? loading ? t("cli.loadingModel") : t("cli.noModelsAvailable") : modelDisplayName(model);
|
|
36426
36574
|
const effortLabel = effortDisplayName(model, effortValue, t("cli.defaultEffort"));
|
|
36427
36575
|
const modelUnavailable = model === void 0;
|
|
36428
36576
|
const triggerDisabled = !loading && modelUnavailable;
|
|
@@ -36478,10 +36626,11 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
36478
36626
|
translationEnabled: next
|
|
36479
36627
|
});
|
|
36480
36628
|
};
|
|
36481
|
-
const
|
|
36629
|
+
const modelComparator = selection.adapterId === "claude-code" ? compareClaudeModelOptions : selection.adapterId === "antigravity" ? compareAntigravityModelOptions : void 0;
|
|
36630
|
+
const modelGroups = modelComparator === void 0 ? catalog?.groups ?? [] : (catalog?.groups ?? []).map((group) => ({
|
|
36482
36631
|
...group,
|
|
36483
|
-
models: [...group.models].sort(
|
|
36484
|
-
}))
|
|
36632
|
+
models: [...group.models].sort(modelComparator)
|
|
36633
|
+
}));
|
|
36485
36634
|
const modelQueryText = showModelSearch ? modelQuery.trim() : "";
|
|
36486
36635
|
const visibleModelGroups = modelQueryText === "" ? modelGroups : modelGroups.map((group) => ({
|
|
36487
36636
|
...group,
|
|
@@ -36611,7 +36760,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
36611
36760
|
"data-highlighted": showModelSearch && index === activeModelIndex ? "true" : void 0,
|
|
36612
36761
|
tabIndex: showModelSearch ? -1 : void 0,
|
|
36613
36762
|
className: "codingns4dsh-model-option",
|
|
36614
|
-
title: item
|
|
36763
|
+
title: modelDisplayName(item),
|
|
36615
36764
|
onMouseMove: () => {
|
|
36616
36765
|
if (showModelSearch && index !== activeModelIndex) setHighlightedModelIndex(index);
|
|
36617
36766
|
},
|
|
@@ -36623,7 +36772,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
36623
36772
|
overflow: "hidden",
|
|
36624
36773
|
textOverflow: "ellipsis",
|
|
36625
36774
|
whiteSpace: "nowrap"
|
|
36626
|
-
} }, item
|
|
36775
|
+
} }, modelDisplayName(item)), item.id === model?.id && (0, react.createElement)("span", { "aria-hidden": true }, "✓"), item.source === "magpie" && (0, react.createElement)(require_magpie_model_tag.MagpieModelTag, { providerId: item.magpieProviderId }));
|
|
36627
36776
|
}))), visibleModelGroups.length === 0 && (0, react.createElement)("div", {
|
|
36628
36777
|
key: "model-empty",
|
|
36629
36778
|
role: "status",
|
|
@@ -37309,6 +37458,11 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
37309
37458
|
enabledByDefault: false,
|
|
37310
37459
|
dependencies: ["cliAdapters"],
|
|
37311
37460
|
runtime: "client",
|
|
37461
|
+
requires: [{
|
|
37462
|
+
capability: "ui.context-menu",
|
|
37463
|
+
required: false,
|
|
37464
|
+
fallback: "degrade"
|
|
37465
|
+
}],
|
|
37312
37466
|
nativeReplacement: {
|
|
37313
37467
|
dshFeature: "DSH native session list, session search, plugin icons, and working-directory presentation",
|
|
37314
37468
|
since: "0.2.2-alpha.2",
|
|
@@ -37364,6 +37518,7 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
37364
37518
|
remote: context.services.remote,
|
|
37365
37519
|
readNativeWorkspaceSnapshot: () => readNativeWorkspaceSnapshot(context.services.uiContext),
|
|
37366
37520
|
hiddenWorkspaceIds,
|
|
37521
|
+
...context.services.contextMenus === void 0 ? {} : { contextMenus: context.services.contextMenus },
|
|
37367
37522
|
locale: context.services.locale,
|
|
37368
37523
|
onHiddenWorkspaceIdsChange: async (ids) => {
|
|
37369
37524
|
await context.services.settings.mutate([{
|
|
@@ -37513,379 +37668,6 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
37513
37668
|
},
|
|
37514
37669
|
settingsPanel: WorkspaceSessionEnhancementPanel
|
|
37515
37670
|
};
|
|
37516
|
-
// src/client/mobile-sidebar-logo.ts
|
|
37517
|
-
/**
|
|
37518
|
-
* DSH 官方品牌鲸鱼图形的几何数据。
|
|
37519
|
-
*
|
|
37520
|
-
* 取值自 `@deepseek-ai/dsh-client-ui-primitives` 的 `FISH_LOGO_PATH` /
|
|
37521
|
-
* `FISH_LOGO_VIEWBOX`(DSH 0.2.0-rc.1)。折叠态侧栏轨道里的 mark 用的就是同一个
|
|
37522
|
-
* 图形,这里内联同一份路径以保证插件浮起的入口与原生外观完全一致。
|
|
37523
|
-
*
|
|
37524
|
-
* 之所以不 import primitives:本模块是纯 DOM 控制器,要在没有 React 与浏览器
|
|
37525
|
-
* 依赖的 Node 测试里直接运行;同时功能模块不应直接依赖 DSH 版本专属类型。
|
|
37526
|
-
*/
|
|
37527
|
-
/** 鲸鱼轮廓的 SVG path 数据(与上游 `FISH_LOGO_PATH` 相同)。 */
|
|
37528
|
-
const FISH_LOGO_PATH = "M22.9168 1.43018C22.6713 1.31018 22.5658 1.53918 22.4223 1.65519C22.3733 1.69269 22.3318 1.74169 22.2903 1.78669C21.9317 2.1697 21.5127 2.42121 20.9657 2.39121C20.1657 2.34621 19.4827 2.59771 18.8787 3.20973C18.7502 2.45521 18.3236 2.0047 17.6746 1.71569C17.3351 1.56568 16.9916 1.41518 16.7536 1.08867C16.5876 0.856163 16.5421 0.597155 16.4591 0.341647C16.4061 0.187643 16.3536 0.0301382 16.1761 0.00363739C15.9836 -0.0263635 15.9081 0.135141 15.8326 0.270145C15.5306 0.822162 15.4136 1.43018 15.4251 2.0462C15.4516 3.43174 16.0366 4.53527 17.1991 5.3203C17.3311 5.4103 17.3651 5.5003 17.3236 5.63181C17.2441 5.90231 17.1501 6.16482 17.0671 6.43533C17.0141 6.60784 16.9351 6.64584 16.7501 6.57033C16.1121 6.30383 15.5611 5.90931 15.074 5.4328C14.2475 4.63328 13.5 3.75075 12.568 3.05973C12.349 2.89822 12.13 2.74822 11.9034 2.60522C10.9524 1.68169 12.028 0.923165 12.277 0.833162C12.5375 0.739159 12.3675 0.41615 11.5259 0.42015C10.6844 0.42365 9.91439 0.705658 8.93286 1.08117C8.78935 1.13767 8.63835 1.17867 8.48384 1.21267C7.59332 1.04367 6.66829 1.00617 5.70226 1.11517C3.88321 1.31768 2.43016 2.1777 1.36213 3.64575C0.0790928 5.4103 -0.222916 7.41536 0.146595 9.50642C0.535106 11.7105 1.66014 13.535 3.38869 14.9616C5.18125 16.4406 7.24581 17.1657 9.60138 17.0266C11.0319 16.9441 12.6245 16.7526 14.421 15.2321C14.874 15.4576 15.3496 15.5476 16.1381 15.6151C16.7456 15.6716 17.3306 15.5851 17.7836 15.4911C18.4931 15.3411 18.4441 14.6841 18.1876 14.5636C16.1081 13.595 16.5646 13.9891 16.1496 13.67C17.2061 12.42 18.8202 10.1979 19.3182 7.17235C19.3672 6.83834 19.4297 6.36783 19.4222 6.09732C19.4182 5.93231 19.4562 5.86831 19.6447 5.84931C20.1657 5.78931 20.6712 5.64681 21.1357 5.3913C22.4833 4.65528 23.0268 3.44624 23.1548 1.9972C23.1738 1.77569 23.1508 1.54668 22.9168 1.43018ZM11.1749 14.4736C9.15936 12.889 8.18184 12.3675 7.77832 12.39C7.40081 12.4125 7.46881 12.8445 7.55182 13.126C7.63882 13.404 7.75182 13.5955 7.91033 13.8396C8.01983 14.0011 8.09533 14.2411 7.80083 14.4216C7.15181 14.8231 6.02327 14.2866 5.97027 14.2601C4.65673 13.4865 3.5587 12.4655 2.78467 11.069C2.03715 9.72493 1.60314 8.28289 1.53164 6.74384C1.51264 6.37233 1.62214 6.24082 1.99215 6.17332C2.47916 6.08332 2.98118 6.06432 3.46769 6.13582C5.52476 6.43633 7.27581 7.35586 8.74385 8.8129C9.58188 9.64243 10.2159 10.634 10.8689 11.6025C11.5634 12.631 12.3105 13.611 13.262 14.4146C13.598 14.6961 13.866 14.9101 14.1225 15.0681C13.349 15.1546 12.058 15.1731 11.1749 14.4746L11.1749 14.4736ZM12.141 8.25988C12.141 8.09488 12.273 7.96338 12.439 7.96338C12.4765 7.96338 12.5105 7.97088 12.541 7.98188C12.5825 7.99688 12.6205 8.01938 12.6505 8.05338C12.7035 8.10588 12.7335 8.18088 12.7335 8.25988C12.7335 8.42489 12.6015 8.55639 12.4355 8.55639C12.2695 8.55639 12.141 8.42489 12.141 8.25988ZM15.1415 9.79893C14.949 9.87793 14.7565 9.94544 14.5715 9.95294C14.2845 9.96794 13.9715 9.85143 13.8015 9.70893C13.5375 9.48742 13.3485 9.36342 13.2695 8.97691C13.2355 8.8119 13.2545 8.55639 13.2845 8.40989C13.3525 8.09438 13.277 7.89187 13.0545 7.70787C12.8735 7.55786 12.643 7.51636 12.39 7.51636C12.2955 7.51636 12.209 7.47486 12.1445 7.44136C12.039 7.38886 11.9519 7.25735 12.035 7.09585C12.0615 7.04335 12.19 6.91584 12.22 6.89334C12.5635 6.69784 12.9595 6.76184 13.326 6.90834C13.6655 7.04735 13.9225 7.30236 14.292 7.66287C14.6695 8.09838 14.7375 8.21838 14.9525 8.54539C15.1225 8.8009 15.277 9.06341 15.3831 9.36392C15.4471 9.55142 15.3641 9.70493 15.1415 9.79893Z";
|
|
37529
|
-
/** `FISH_LOGO_PATH` 的原生 viewBox 尺寸。 */
|
|
37530
|
-
const FISH_LOGO_VIEWBOX = {
|
|
37531
|
-
width: 23.16,
|
|
37532
|
-
height: 17.04
|
|
37533
|
-
};
|
|
37534
|
-
// src/client/mobile-sidebar-rail-dom.ts
|
|
37535
|
-
/**
|
|
37536
|
-
* 移动端左侧边栏彻底隐藏器。
|
|
37537
|
-
*
|
|
37538
|
-
* DSH 在窄屏(< 1024px)下把左侧边栏收起成 56px 的图标轨道,而不是 0 宽:
|
|
37539
|
-
* 轨道本身始终占用横向空间,手机上等于白扔一条竖直区域。DSH 没有公开“折叠宽度”
|
|
37540
|
-
* 配置(`collapsedWidth` 只在 macOS 桌面与 Windows 标题栏两种形态下为 0),因此这里
|
|
37541
|
-
* 在浏览器侧做三件事,且只改界面、不改 DSH 状态:
|
|
37542
|
-
*
|
|
37543
|
-
* 1. 把应用框架(`AppFrame`)内联的 `grid-template-columns` 第一条轨道改写成 `0px`,
|
|
37544
|
-
* 其余轨道原样保留;React 重绘后由 MutationObserver 立即补写,恢复时写回基线值。
|
|
37545
|
-
* 2. 把左侧栏列整列隐藏,避免它作为 0 宽列仍渲染子树。
|
|
37546
|
-
* 3. 在 `document.body` 上挂一个**插件自有**的固定定位 logo 按钮作为再次唤起入口,
|
|
37547
|
-
* 点击调用 DSH 官方 `ctx.layout.toggleSidebar()`。
|
|
37548
|
-
*
|
|
37549
|
-
* 第 3 点是踩坑后的结论。最初的实现复用 DSH 折叠态侧栏里那一行原生 logo 行,
|
|
37550
|
-
* 把它 `position:fixed` 浮起来;但那一行位于**已被收成 0 宽、且带
|
|
37551
|
-
* `overflow:hidden`** 的侧栏列内部,只要任意祖先形成固定定位包含块(transform /
|
|
37552
|
-
* filter / contain / will-change),`position:fixed` 就会被改写成相对该祖先定位,
|
|
37553
|
-
* 随即被裁掉——表现为“侧栏确实收起了,但看不到 logo”。自建按钮挂在 body 上,
|
|
37554
|
-
* 不再受侧栏列的裁剪与包含块影响;图形仍使用与上游完全相同的鲸鱼路径,外观一致。
|
|
37555
|
-
*
|
|
37556
|
-
* 依赖的 DSH 0.2.0-rc.1 DOM 契约(任何一条不成立都只是不生效,不会误改宿主界面):
|
|
37557
|
-
* - 应用框架是文档里包含 `[data-shell-overlay]` 且带内联 `grid-template-columns` 的元素;
|
|
37558
|
-
* - 框架的第一个非遮罩层子元素是左侧栏列;
|
|
37559
|
-
* - 折叠状态由框架上的 `data-sidebar-collapsed` 表达。
|
|
37560
|
-
*/
|
|
37561
|
-
/** 加在 `documentElement` 上的开关:`on` 表示移动端隐藏模式正在生效。 */
|
|
37562
|
-
const MOBILE_SIDEBAR_MODE_ATTRIBUTE = "data-codingns-mobile-sidebar";
|
|
37563
|
-
/** 加在应用框架元素上的标记。 */
|
|
37564
|
-
const MOBILE_SIDEBAR_FRAME_ATTRIBUTE = "data-codingns-mobile-sidebar-frame";
|
|
37565
|
-
/** 加在左侧栏列上的标记。 */
|
|
37566
|
-
const MOBILE_SIDEBAR_COLUMN_ATTRIBUTE = "data-codingns-mobile-sidebar-column";
|
|
37567
|
-
/** 加在插件自有唤起按钮上的标记。 */
|
|
37568
|
-
const MOBILE_SIDEBAR_BUTTON_ATTRIBUTE = "data-codingns-mobile-sidebar-toggle";
|
|
37569
|
-
/** 插件样式标签的幂等键。 */
|
|
37570
|
-
const MOBILE_SIDEBAR_STYLE_ID = "codingns4dsh-mobile-sidebar-style";
|
|
37571
|
-
/** 框架上承载“已应用隐藏”的标记,供样式与诊断读取。 */
|
|
37572
|
-
const MOBILE_SIDEBAR_GRID_STATE_ATTRIBUTE = "data-codingns-mobile-sidebar-grid";
|
|
37573
|
-
require_magpie_model_tag.resolveCodingNsTranslator()("mobileRail.openSidebar");
|
|
37574
|
-
/** 结构不匹配:找不到应用框架或左侧栏列。 */
|
|
37575
|
-
const MOBILE_SIDEBAR_DIAGNOSTIC_STRUCTURE_MISSING = "CODINGNS_MOBILE_SIDEBAR_STRUCTURE_MISSING";
|
|
37576
|
-
/** 找不到布局服务:按钮仍会出现,但点击无法开合。 */
|
|
37577
|
-
const MOBILE_SIDEBAR_DIAGNOSTIC_TOGGLE_MISSING = "CODINGNS_MOBILE_SIDEBAR_TOGGLE_MISSING";
|
|
37578
|
-
/**
|
|
37579
|
-
* 纯函数:视口宽度是否按“移动端/窄屏”处理。
|
|
37580
|
-
*/
|
|
37581
|
-
function isMobileSidebarViewport(width, maxPx) {
|
|
37582
|
-
if (!Number.isFinite(width) || width <= 0) return false;
|
|
37583
|
-
if (!Number.isFinite(maxPx) || maxPx <= 0) return false;
|
|
37584
|
-
return width <= maxPx;
|
|
37585
|
-
}
|
|
37586
|
-
/**
|
|
37587
|
-
* 纯函数:宿主是否已经在框架的 `shell.leading` 座位里提供了自己的开合按钮。
|
|
37588
|
-
*
|
|
37589
|
-
* DSH 只在两种形态下把折叠宽度做成 0 并在 `[data-shell-leading]` 座位补上按钮:
|
|
37590
|
-
* macOS 桌面与 Windows 标题栏。此时插件不该再放一个重复入口。这里做**结构探测**
|
|
37591
|
-
* 而不是按平台判断:只要宿主已经渲染了那个座位且里面有按钮,就认为入口已存在。
|
|
37592
|
-
*/
|
|
37593
|
-
function hasHostLeadingToggle(container) {
|
|
37594
|
-
const seat = container.querySelector("[data-shell-leading]");
|
|
37595
|
-
if (seat === null) return false;
|
|
37596
|
-
return seat.querySelector("button") !== null;
|
|
37597
|
-
}
|
|
37598
|
-
/**
|
|
37599
|
-
* 纯函数:右栏当前是否占用了界面空间(普通停靠或全屏)。
|
|
37600
|
-
*
|
|
37601
|
-
* DSH 在框架上写 `data-rightbar-collapsed`(右栏不占轨道时存在)与
|
|
37602
|
-
* `data-rightbar-fullscreen`。右栏打开时它自己的标签栏就在左上角,插件再叠一个
|
|
37603
|
-
* logo 会把标签盖住,因此这两种情况都必须让位。
|
|
37604
|
-
*/
|
|
37605
|
-
function isRightbarOccupied(frame) {
|
|
37606
|
-
if (frame === void 0) return false;
|
|
37607
|
-
if (frame.hasAttribute("data-rightbar-fullscreen")) return true;
|
|
37608
|
-
return !frame.hasAttribute("data-rightbar-collapsed");
|
|
37609
|
-
}
|
|
37610
|
-
/**
|
|
37611
|
-
* 纯函数:把 `grid-template-columns` 的第一条轨道改写为 `0px`,其余原样保留。
|
|
37612
|
-
*
|
|
37613
|
-
* 只接受以显式 px 轨道开头的值(DSH 的框架写法);其它形式返回 `undefined`,
|
|
37614
|
-
* 调用方保持原样,避免把不认识的网格改坏。
|
|
37615
|
-
*/
|
|
37616
|
-
function hideLeadingGridTrack(value) {
|
|
37617
|
-
const match = /^\s*([0-9.]+)px\s+(\S[\s\S]*)$/u.exec(value);
|
|
37618
|
-
if (match === null) return void 0;
|
|
37619
|
-
const rest = (match[2] ?? "").trim();
|
|
37620
|
-
if (rest === "") return void 0;
|
|
37621
|
-
return `0px ${rest}`;
|
|
37622
|
-
}
|
|
37623
|
-
/**
|
|
37624
|
-
* 启动移动端侧栏隐藏器;未启用或不在窄屏时保证零副作用(不写任何属性、不加样式、不建按钮)。
|
|
37625
|
-
*/
|
|
37626
|
-
function startMobileSidebarRailDom(options) {
|
|
37627
|
-
const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
37628
|
-
const win = options.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
37629
|
-
const Observer = options.MutationObserver ?? (typeof MutationObserver === "undefined" ? void 0 : MutationObserver);
|
|
37630
|
-
const t = require_magpie_model_tag.resolveCodingNsTranslator(options.locale);
|
|
37631
|
-
let disposed = false;
|
|
37632
|
-
let frame;
|
|
37633
|
-
let column;
|
|
37634
|
-
/** React 自己写下的网格值;恢复时写回它,而不是插件改写后的值。 */
|
|
37635
|
-
let gridBaseline;
|
|
37636
|
-
/** 插件最后一次写入的网格值,用于区分“宿主重绘”与“自己的写入”。 */
|
|
37637
|
-
let gridApplied;
|
|
37638
|
-
let button;
|
|
37639
|
-
let queued = false;
|
|
37640
|
-
let warnedStructure = false;
|
|
37641
|
-
let warnedToggle = false;
|
|
37642
|
-
const scheduleSync = () => {
|
|
37643
|
-
if (disposed || queued) return;
|
|
37644
|
-
queued = true;
|
|
37645
|
-
queueMicrotask(() => {
|
|
37646
|
-
queued = false;
|
|
37647
|
-
sync();
|
|
37648
|
-
});
|
|
37649
|
-
};
|
|
37650
|
-
const sync = () => {
|
|
37651
|
-
if (disposed || dom === void 0) return false;
|
|
37652
|
-
const settings = options.settings();
|
|
37653
|
-
if (!(settings.hideSidebarOnMobile === true && isMobileSidebarViewport(readViewportWidth$1(win), settings.mobileViewportMaxPx))) {
|
|
37654
|
-
restore();
|
|
37655
|
-
return false;
|
|
37656
|
-
}
|
|
37657
|
-
const resolved = resolveStructure();
|
|
37658
|
-
if (resolved === void 0) {
|
|
37659
|
-
if (!warnedStructure) {
|
|
37660
|
-
warnedStructure = true;
|
|
37661
|
-
options.onDiagnostic?.(MOBILE_SIDEBAR_DIAGNOSTIC_STRUCTURE_MISSING);
|
|
37662
|
-
}
|
|
37663
|
-
return false;
|
|
37664
|
-
}
|
|
37665
|
-
installStyles();
|
|
37666
|
-
dom.documentElement?.setAttribute(MOBILE_SIDEBAR_MODE_ATTRIBUTE, "on");
|
|
37667
|
-
if (!resolved.frame.hasAttribute("data-sidebar-collapsed")) {
|
|
37668
|
-
restoreGrid();
|
|
37669
|
-
resolved.frame.style.removeProperty("--dsh-frame-leading-clearance");
|
|
37670
|
-
hideButton();
|
|
37671
|
-
return true;
|
|
37672
|
-
}
|
|
37673
|
-
applyGrid(resolved.frame);
|
|
37674
|
-
if (hasHostLeadingToggle(dom) || isRightbarOccupied(resolved.frame)) {
|
|
37675
|
-
hideButton();
|
|
37676
|
-
resolved.frame.style.removeProperty("--dsh-frame-leading-clearance");
|
|
37677
|
-
} else {
|
|
37678
|
-
resolved.frame.style.setProperty("--dsh-frame-leading-clearance", `72px`);
|
|
37679
|
-
showButton();
|
|
37680
|
-
}
|
|
37681
|
-
return true;
|
|
37682
|
-
};
|
|
37683
|
-
const applyGrid = (target) => {
|
|
37684
|
-
const current = target.style.gridTemplateColumns;
|
|
37685
|
-
if (current === gridApplied) return;
|
|
37686
|
-
if (current !== "") gridBaseline = current;
|
|
37687
|
-
const hidden = hideLeadingGridTrack(current === "" ? gridBaseline ?? "" : current);
|
|
37688
|
-
if (hidden === void 0) return;
|
|
37689
|
-
target.style.gridTemplateColumns = hidden;
|
|
37690
|
-
gridApplied = hidden;
|
|
37691
|
-
target.setAttribute(MOBILE_SIDEBAR_GRID_STATE_ATTRIBUTE, "on");
|
|
37692
|
-
};
|
|
37693
|
-
const restoreGrid = () => {
|
|
37694
|
-
if (frame !== void 0) {
|
|
37695
|
-
if (gridApplied !== void 0 && gridBaseline !== void 0 && frame.style.gridTemplateColumns === gridApplied) frame.style.gridTemplateColumns = gridBaseline;
|
|
37696
|
-
frame.removeAttribute(MOBILE_SIDEBAR_GRID_STATE_ATTRIBUTE);
|
|
37697
|
-
}
|
|
37698
|
-
gridApplied = void 0;
|
|
37699
|
-
};
|
|
37700
|
-
const restore = () => {
|
|
37701
|
-
restoreGrid();
|
|
37702
|
-
frame?.style.removeProperty("--dsh-frame-leading-clearance");
|
|
37703
|
-
dom?.documentElement?.removeAttribute(MOBILE_SIDEBAR_MODE_ATTRIBUTE);
|
|
37704
|
-
removeStyles();
|
|
37705
|
-
column?.removeAttribute(MOBILE_SIDEBAR_COLUMN_ATTRIBUTE);
|
|
37706
|
-
frame?.removeAttribute(MOBILE_SIDEBAR_FRAME_ATTRIBUTE);
|
|
37707
|
-
hideButton();
|
|
37708
|
-
};
|
|
37709
|
-
const showButton = () => {
|
|
37710
|
-
if (button === void 0) {
|
|
37711
|
-
button = createToggleButton(dom, t);
|
|
37712
|
-
if (button === void 0) return;
|
|
37713
|
-
button.addEventListener("click", () => {
|
|
37714
|
-
try {
|
|
37715
|
-
options.toggleSidebar?.();
|
|
37716
|
-
} catch {}
|
|
37717
|
-
});
|
|
37718
|
-
dom?.body?.appendChild(button);
|
|
37719
|
-
}
|
|
37720
|
-
if (!warnedToggle && options.toggleSidebar === void 0) {
|
|
37721
|
-
warnedToggle = true;
|
|
37722
|
-
options.onDiagnostic?.(MOBILE_SIDEBAR_DIAGNOSTIC_TOGGLE_MISSING);
|
|
37723
|
-
}
|
|
37724
|
-
};
|
|
37725
|
-
const hideButton = () => {
|
|
37726
|
-
if (button === void 0) return;
|
|
37727
|
-
button.remove();
|
|
37728
|
-
button = void 0;
|
|
37729
|
-
};
|
|
37730
|
-
const resolveStructure = () => {
|
|
37731
|
-
if (dom === void 0) return void 0;
|
|
37732
|
-
if (frame !== void 0 && !structureDrifted()) return { frame };
|
|
37733
|
-
const previousFrame = frame;
|
|
37734
|
-
column?.removeAttribute(MOBILE_SIDEBAR_COLUMN_ATTRIBUTE);
|
|
37735
|
-
frame?.removeAttribute(MOBILE_SIDEBAR_FRAME_ATTRIBUTE);
|
|
37736
|
-
frame = void 0;
|
|
37737
|
-
column = void 0;
|
|
37738
|
-
const found = findAppFrame(dom);
|
|
37739
|
-
if (found === void 0) return void 0;
|
|
37740
|
-
if (found !== previousFrame) {
|
|
37741
|
-
gridBaseline = void 0;
|
|
37742
|
-
gridApplied = void 0;
|
|
37743
|
-
}
|
|
37744
|
-
const foundColumn = findSidebarColumn(found);
|
|
37745
|
-
if (foundColumn === void 0) return void 0;
|
|
37746
|
-
frame = found;
|
|
37747
|
-
column = foundColumn;
|
|
37748
|
-
found.setAttribute(MOBILE_SIDEBAR_FRAME_ATTRIBUTE, "");
|
|
37749
|
-
foundColumn.setAttribute(MOBILE_SIDEBAR_COLUMN_ATTRIBUTE, "");
|
|
37750
|
-
return { frame: found };
|
|
37751
|
-
};
|
|
37752
|
-
const installStyles = () => {
|
|
37753
|
-
if (dom?.head === void 0 || dom.head === null) return;
|
|
37754
|
-
if (Array.from(dom.head.children).some((child) => child.tagName === "STYLE" && child.dataset.pluginCss === "codingns4dsh-mobile-sidebar-style")) return;
|
|
37755
|
-
const style = dom.createElement("style");
|
|
37756
|
-
style.dataset.plugin = "codingns4dsh";
|
|
37757
|
-
style.dataset.pluginCss = MOBILE_SIDEBAR_STYLE_ID;
|
|
37758
|
-
style.textContent = MOBILE_SIDEBAR_STYLE_TEXT;
|
|
37759
|
-
dom.head.appendChild(style);
|
|
37760
|
-
};
|
|
37761
|
-
const removeStyles = () => {
|
|
37762
|
-
if (dom?.head === void 0 || dom.head === null) return;
|
|
37763
|
-
for (const child of Array.from(dom.head.children)) {
|
|
37764
|
-
if (child.tagName !== "STYLE") continue;
|
|
37765
|
-
if (child.dataset.pluginCss !== "codingns4dsh-mobile-sidebar-style") continue;
|
|
37766
|
-
child.remove();
|
|
37767
|
-
}
|
|
37768
|
-
};
|
|
37769
|
-
const onMutations = (records) => {
|
|
37770
|
-
if (disposed) return;
|
|
37771
|
-
if (records.some(isRelevantMutation) || structureDrifted()) scheduleSync();
|
|
37772
|
-
};
|
|
37773
|
-
const isRelevantMutation = (record) => {
|
|
37774
|
-
if (frame === void 0 || !isAttached(frame, dom)) return true;
|
|
37775
|
-
if (record.target === frame || isInsideSidebar(record.target)) return true;
|
|
37776
|
-
for (const node of [...Array.from(record.addedNodes), ...Array.from(record.removedNodes)]) {
|
|
37777
|
-
if (node === frame || node === button) return true;
|
|
37778
|
-
if (isInsideSidebar(node)) return true;
|
|
37779
|
-
if (typeof node.contains === "function" && node.contains(frame)) return true;
|
|
37780
|
-
}
|
|
37781
|
-
return false;
|
|
37782
|
-
};
|
|
37783
|
-
/** 已解析出的侧栏节点是否仍然带着插件标记并挂在文档上。 */
|
|
37784
|
-
const structureDrifted = () => {
|
|
37785
|
-
if (frame === void 0) return false;
|
|
37786
|
-
if (!isAttached(frame, dom)) return true;
|
|
37787
|
-
if (!frame.hasAttribute("data-codingns-mobile-sidebar-frame")) return true;
|
|
37788
|
-
if (column === void 0 || !isAttached(column, dom) || !column.hasAttribute("data-codingns-mobile-sidebar-column")) return true;
|
|
37789
|
-
return false;
|
|
37790
|
-
};
|
|
37791
|
-
const isInsideSidebar = (node) => {
|
|
37792
|
-
if (column === void 0 || typeof node.contains !== "function") return false;
|
|
37793
|
-
return node === column || column.contains(node);
|
|
37794
|
-
};
|
|
37795
|
-
const onResize = () => {
|
|
37796
|
-
scheduleSync();
|
|
37797
|
-
};
|
|
37798
|
-
installStyles();
|
|
37799
|
-
const observer = dom === void 0 || Observer === void 0 || dom.documentElement === void 0 ? void 0 : new Observer(onMutations);
|
|
37800
|
-
if (observer !== void 0 && dom?.documentElement !== void 0) observer.observe(dom.documentElement, {
|
|
37801
|
-
childList: true,
|
|
37802
|
-
subtree: true,
|
|
37803
|
-
attributes: true,
|
|
37804
|
-
attributeFilter: [
|
|
37805
|
-
"style",
|
|
37806
|
-
"data-sidebar-collapsed",
|
|
37807
|
-
"data-rightbar-collapsed",
|
|
37808
|
-
"data-rightbar-fullscreen"
|
|
37809
|
-
]
|
|
37810
|
-
});
|
|
37811
|
-
win?.addEventListener?.("resize", onResize);
|
|
37812
|
-
sync();
|
|
37813
|
-
return {
|
|
37814
|
-
refresh: sync,
|
|
37815
|
-
dispose() {
|
|
37816
|
-
if (disposed) return;
|
|
37817
|
-
disposed = true;
|
|
37818
|
-
observer?.disconnect();
|
|
37819
|
-
win?.removeEventListener?.("resize", onResize);
|
|
37820
|
-
restore();
|
|
37821
|
-
}
|
|
37822
|
-
};
|
|
37823
|
-
}
|
|
37824
|
-
const MOBILE_SIDEBAR_STYLE_TEXT = [
|
|
37825
|
-
`html[${MOBILE_SIDEBAR_MODE_ATTRIBUTE}="on"] [${MOBILE_SIDEBAR_FRAME_ATTRIBUTE}][data-sidebar-collapsed] [${MOBILE_SIDEBAR_COLUMN_ATTRIBUTE}]{visibility:hidden!important;border-right:0!important;background:transparent!important}`,
|
|
37826
|
-
`[${MOBILE_SIDEBAR_BUTTON_ATTRIBUTE}]{position:fixed;top:calc(6px + env(safe-area-inset-top, 0px));left:calc(6px + env(safe-area-inset-left, 0px));z-index:60;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:0;border-radius:10px;background:transparent;color:var(--dsw-alias-label-primary, CanvasText);cursor:pointer;-webkit-tap-highlight-color:transparent}`,
|
|
37827
|
-
`[${MOBILE_SIDEBAR_BUTTON_ATTRIBUTE}]:hover{background:var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.14))}`,
|
|
37828
|
-
`[${MOBILE_SIDEBAR_BUTTON_ATTRIBUTE}]:focus-visible{outline:var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));outline-offset:2px}`,
|
|
37829
|
-
`[${MOBILE_SIDEBAR_BUTTON_ATTRIBUTE}] svg{display:block;pointer-events:none}`
|
|
37830
|
-
].join("");
|
|
37831
|
-
/** 插件自有的唤起按钮:与 DSH 折叠轨道使用同一个鲸鱼图形。 */
|
|
37832
|
-
function createToggleButton(dom, t) {
|
|
37833
|
-
if (dom?.body === void 0 || dom.body === null) return void 0;
|
|
37834
|
-
const element = dom.createElement("button");
|
|
37835
|
-
element.setAttribute(MOBILE_SIDEBAR_BUTTON_ATTRIBUTE, "");
|
|
37836
|
-
element.setAttribute("type", "button");
|
|
37837
|
-
const label = t("mobileRail.openSidebar");
|
|
37838
|
-
element.setAttribute("aria-label", label);
|
|
37839
|
-
element.setAttribute("title", label);
|
|
37840
|
-
const icon = createFishLogo(dom);
|
|
37841
|
-
if (icon !== void 0) element.appendChild(icon);
|
|
37842
|
-
else element.textContent = "≡";
|
|
37843
|
-
return element;
|
|
37844
|
-
}
|
|
37845
|
-
/** 内联鲸鱼 SVG;与 `FishLogo` 的 viewBox 和路径一致,24px 高。 */
|
|
37846
|
-
function createFishLogo(dom) {
|
|
37847
|
-
if (typeof dom.createElementNS !== "function") return void 0;
|
|
37848
|
-
const size = 24;
|
|
37849
|
-
const height = Math.round(size * FISH_LOGO_VIEWBOX.height / FISH_LOGO_VIEWBOX.width * 100) / 100;
|
|
37850
|
-
const svg = dom.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
37851
|
-
svg.setAttribute("width", String(size));
|
|
37852
|
-
svg.setAttribute("height", String(height));
|
|
37853
|
-
svg.setAttribute("viewBox", `0 0 ${FISH_LOGO_VIEWBOX.width} ${FISH_LOGO_VIEWBOX.height}`);
|
|
37854
|
-
svg.setAttribute("fill", "none");
|
|
37855
|
-
svg.setAttribute("aria-hidden", "true");
|
|
37856
|
-
const path = dom.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
37857
|
-
path.setAttribute("d", FISH_LOGO_PATH);
|
|
37858
|
-
path.setAttribute("fill", "currentColor");
|
|
37859
|
-
svg.appendChild(path);
|
|
37860
|
-
return svg;
|
|
37861
|
-
}
|
|
37862
|
-
/** 应用框架:从遮罩层向上找第一个带内联网格的祖先。 */
|
|
37863
|
-
function findAppFrame(dom) {
|
|
37864
|
-
const overlay = dom.querySelector("[data-shell-overlay]");
|
|
37865
|
-
if (overlay === null) return void 0;
|
|
37866
|
-
let current = overlay;
|
|
37867
|
-
for (let depth = 0; depth < 8 && current !== null; depth += 1, current = current.parentElement) if (current.style.gridTemplateColumns !== "") return current;
|
|
37868
|
-
}
|
|
37869
|
-
/** 左侧栏列:框架里第一个不是遮罩层的直接子元素。 */
|
|
37870
|
-
function findSidebarColumn(frame) {
|
|
37871
|
-
for (const child of Array.from(frame.children)) {
|
|
37872
|
-
if (child.hasAttribute("data-shell-overlay")) continue;
|
|
37873
|
-
return child;
|
|
37874
|
-
}
|
|
37875
|
-
}
|
|
37876
|
-
function readViewportWidth$1(win) {
|
|
37877
|
-
const width = win?.innerWidth;
|
|
37878
|
-
if (typeof width === "number" && Number.isFinite(width) && width > 0) return width;
|
|
37879
|
-
const fallback = globalThis.innerWidth;
|
|
37880
|
-
return typeof fallback === "number" && Number.isFinite(fallback) ? fallback : 0;
|
|
37881
|
-
}
|
|
37882
|
-
/** 元素是否仍在当前文档里;测试用的伪 DOM 没有 `isConnected`,退化为属性判断。 */
|
|
37883
|
-
function isAttached(element, dom) {
|
|
37884
|
-
if (dom?.documentElement === void 0 || dom.documentElement === null) return true;
|
|
37885
|
-
if (element.isConnected === true) return true;
|
|
37886
|
-
if (typeof dom.documentElement.contains !== "function") return true;
|
|
37887
|
-
return dom.documentElement.contains(element);
|
|
37888
|
-
}
|
|
37889
37671
|
// src/client/mobile-vibration.ts
|
|
37890
37672
|
/** 尝试触发一次振动;返回 true 表示浏览器接受了调用。 */
|
|
37891
37673
|
function vibrateMobile(pattern = 10, globalLike = globalThis) {
|
|
@@ -38408,375 +38190,6 @@ html[data-codingns-mobile-sidebar="on"] .codingns-magpie-page{padding-left:0;--m
|
|
|
38408
38190
|
}
|
|
38409
38191
|
return now();
|
|
38410
38192
|
}
|
|
38411
|
-
// src/client/mobile-rightbar-tabs-dom.ts
|
|
38412
|
-
/**
|
|
38413
|
-
* 移动端右栏标签条优先使用浏览器原生横向滚动。
|
|
38414
|
-
*
|
|
38415
|
-
* 上游标签条、标签容器及标签的 touch-action 均为 none,且标签 pointerdown
|
|
38416
|
-
* 会捕获指针并启动拖拽。这里只在窄屏触摸视口放开 pan-x,并在捕获阶段拦截
|
|
38417
|
-
* 标签容器内的触摸 pointerdown;不取消默认动作,原生滚动、惯性和点击仍可用。
|
|
38418
|
-
*/
|
|
38419
|
-
const MOBILE_RIGHTBAR_TABS_ATTRIBUTE = "data-codingns-mobile-rightbar-tabs";
|
|
38420
|
-
const MOBILE_RIGHTBAR_TABS_STYLE_ID = "codingns4dsh-mobile-rightbar-tabs";
|
|
38421
|
-
const TAB_RUN_SELECTOR = "[data-sidebar-right-panel] [data-dockkit-strip-tabs]";
|
|
38422
|
-
/** 全局选择器与事件委派自动覆盖宿主重建的标签条,无需逐个绑定或观察 DOM。 */
|
|
38423
|
-
function startMobileRightbarTabsDom(options = {}) {
|
|
38424
|
-
const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
38425
|
-
const win = options.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
38426
|
-
let active = false;
|
|
38427
|
-
let disposed = false;
|
|
38428
|
-
let style;
|
|
38429
|
-
const onPointerDown = (event) => {
|
|
38430
|
-
if (!active || event.pointerType !== "touch") return;
|
|
38431
|
-
if (!event.target?.closest?.(TAB_RUN_SELECTOR)) return;
|
|
38432
|
-
event.stopPropagation();
|
|
38433
|
-
};
|
|
38434
|
-
const deactivate = () => {
|
|
38435
|
-
if (!active) return;
|
|
38436
|
-
active = false;
|
|
38437
|
-
dom?.removeEventListener("pointerdown", onPointerDown, true);
|
|
38438
|
-
dom?.documentElement.removeAttribute(MOBILE_RIGHTBAR_TABS_ATTRIBUTE);
|
|
38439
|
-
style?.remove();
|
|
38440
|
-
style = void 0;
|
|
38441
|
-
};
|
|
38442
|
-
const refresh = () => {
|
|
38443
|
-
if (disposed) return false;
|
|
38444
|
-
const width = win?.innerWidth ?? 0;
|
|
38445
|
-
const maxPx = typeof options.mobileViewportMaxPx === "function" ? options.mobileViewportMaxPx() : options.mobileViewportMaxPx ?? 1024;
|
|
38446
|
-
const touchPoints = win?.navigator?.maxTouchPoints;
|
|
38447
|
-
if (!(dom?.documentElement !== void 0 && Number.isFinite(width) && width > 0 && width <= maxPx && (typeof touchPoints !== "number" || touchPoints > 0))) {
|
|
38448
|
-
deactivate();
|
|
38449
|
-
return false;
|
|
38450
|
-
}
|
|
38451
|
-
if (active) return true;
|
|
38452
|
-
active = true;
|
|
38453
|
-
style = dom.createElement("style");
|
|
38454
|
-
style.id = MOBILE_RIGHTBAR_TABS_STYLE_ID;
|
|
38455
|
-
style.textContent = mobileTabStyles();
|
|
38456
|
-
dom.head.appendChild(style);
|
|
38457
|
-
dom.documentElement.setAttribute(MOBILE_RIGHTBAR_TABS_ATTRIBUTE, "on");
|
|
38458
|
-
dom.addEventListener("pointerdown", onPointerDown, {
|
|
38459
|
-
capture: true,
|
|
38460
|
-
passive: true
|
|
38461
|
-
});
|
|
38462
|
-
return true;
|
|
38463
|
-
};
|
|
38464
|
-
const onResize = () => {
|
|
38465
|
-
refresh();
|
|
38466
|
-
};
|
|
38467
|
-
win?.addEventListener?.("resize", onResize);
|
|
38468
|
-
refresh();
|
|
38469
|
-
return {
|
|
38470
|
-
refresh,
|
|
38471
|
-
dispose() {
|
|
38472
|
-
if (disposed) return;
|
|
38473
|
-
disposed = true;
|
|
38474
|
-
deactivate();
|
|
38475
|
-
win?.removeEventListener?.("resize", onResize);
|
|
38476
|
-
}
|
|
38477
|
-
};
|
|
38478
|
-
}
|
|
38479
|
-
function mobileTabStyles() {
|
|
38480
|
-
const scope = `html[${MOBILE_RIGHTBAR_TABS_ATTRIBUTE}="on"] [data-sidebar-right-panel]`;
|
|
38481
|
-
return `
|
|
38482
|
-
${scope} [data-dockkit-strip],
|
|
38483
|
-
${scope} [data-dockkit-strip-tabs],
|
|
38484
|
-
${scope} [data-dockkit-tab] {
|
|
38485
|
-
touch-action: pan-x !important;
|
|
38486
|
-
}
|
|
38487
|
-
${scope} [data-dockkit-strip-tabs] {
|
|
38488
|
-
overflow-x: auto !important;
|
|
38489
|
-
overflow-y: hidden !important;
|
|
38490
|
-
overscroll-behavior-x: contain;
|
|
38491
|
-
-webkit-overflow-scrolling: touch;
|
|
38492
|
-
}
|
|
38493
|
-
`;
|
|
38494
|
-
}
|
|
38495
|
-
// src/client/mobile-settings-modal-dom.ts
|
|
38496
|
-
/**
|
|
38497
|
-
* DSH 设置弹窗的移动端布局适配。
|
|
38498
|
-
*
|
|
38499
|
-
* 设置弹窗由 DSH 通过 portal 直接挂到 body,插件不能把样式写进自己的 React
|
|
38500
|
-
* 树。这里依赖唯一稳定的 `[data-shortcut-modal="settings"]` 钩子,再按设置根节点
|
|
38501
|
-
* 的稳定语义结构(`nav` 与内容列)注入一份可撤销的样式:窄屏时导航变成只显示
|
|
38502
|
-
* 图标的窄轨道,弹窗内容占满整个视口。桌面端不写属性、不注入样式,避免影响
|
|
38503
|
-
* DSH 原生布局。
|
|
38504
|
-
*/
|
|
38505
|
-
/** DSH 设置弹窗的稳定选择器。 */
|
|
38506
|
-
const MOBILE_SETTINGS_MODAL_SELECTOR = "[data-shortcut-modal=\"settings\"]";
|
|
38507
|
-
/** 插件在设置弹窗上挂载的移动端标记。 */
|
|
38508
|
-
const MOBILE_SETTINGS_MODAL_ATTRIBUTE = "data-codingns-mobile-settings";
|
|
38509
|
-
/** 插件样式标签的幂等键。 */
|
|
38510
|
-
const MOBILE_SETTINGS_MODAL_STYLE_ID = "codingns4dsh-mobile-settings-style";
|
|
38511
|
-
/** 默认按移动端处理的最大视口宽度。 */
|
|
38512
|
-
const MOBILE_SETTINGS_MODAL_DEFAULT_MAX_PX = 1024;
|
|
38513
|
-
/** 纯函数:判断一个视口是否按移动端设置布局处理。 */
|
|
38514
|
-
function isMobileSettingsViewport(width, maxPx = MOBILE_SETTINGS_MODAL_DEFAULT_MAX_PX) {
|
|
38515
|
-
return Number.isFinite(width) && width > 0 && Number.isFinite(maxPx) && maxPx > 0 && width <= maxPx;
|
|
38516
|
-
}
|
|
38517
|
-
/**
|
|
38518
|
-
* 启动设置弹窗移动端适配。
|
|
38519
|
-
*
|
|
38520
|
-
* React 每次打开设置都会重新创建 portal,因此同时监听 documentElement 的子树变更
|
|
38521
|
-
* 与窗口 resize。样式使用强制规则覆盖 DSH 的固定 800px/188px 布局,但只在插件
|
|
38522
|
-
* 自己标记的弹窗上生效;dispose 后完全移除标记和 style 标签。
|
|
38523
|
-
*/
|
|
38524
|
-
function startMobileSettingsModalDom(options = {}) {
|
|
38525
|
-
const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
38526
|
-
const win = options.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
38527
|
-
const Observer = options.MutationObserver ?? (typeof MutationObserver === "undefined" ? void 0 : MutationObserver);
|
|
38528
|
-
const enabled = options.enabled ?? (() => true);
|
|
38529
|
-
const maxPx = () => {
|
|
38530
|
-
return (typeof options.mobileViewportMaxPx === "function" ? options.mobileViewportMaxPx() : options.mobileViewportMaxPx) ?? 1024;
|
|
38531
|
-
};
|
|
38532
|
-
let disposed = false;
|
|
38533
|
-
let queued = false;
|
|
38534
|
-
let marked = /* @__PURE__ */ new Set();
|
|
38535
|
-
const schedule = () => {
|
|
38536
|
-
if (disposed || queued) return;
|
|
38537
|
-
queued = true;
|
|
38538
|
-
queueMicrotask(() => {
|
|
38539
|
-
queued = false;
|
|
38540
|
-
sync();
|
|
38541
|
-
});
|
|
38542
|
-
};
|
|
38543
|
-
const sync = () => {
|
|
38544
|
-
if (disposed || dom === void 0) return;
|
|
38545
|
-
const active = enabled() && isMobileSettingsViewport(readViewportWidth(win), maxPx());
|
|
38546
|
-
const panels = active ? findSettingsPanels(dom) : [];
|
|
38547
|
-
const next = new Set(panels);
|
|
38548
|
-
for (const panel of marked) if (!next.has(panel)) panel.removeAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE);
|
|
38549
|
-
if (active && panels.length > 0) {
|
|
38550
|
-
installStyles$1(dom);
|
|
38551
|
-
for (const panel of panels) panel.setAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE, "on");
|
|
38552
|
-
} else removeStyles(dom);
|
|
38553
|
-
marked = next;
|
|
38554
|
-
};
|
|
38555
|
-
const observer = dom === void 0 || Observer === void 0 || dom.documentElement === void 0 ? void 0 : new Observer(() => schedule());
|
|
38556
|
-
if (observer !== void 0 && dom?.documentElement !== void 0) observer.observe(dom.documentElement, {
|
|
38557
|
-
childList: true,
|
|
38558
|
-
subtree: true,
|
|
38559
|
-
attributes: true,
|
|
38560
|
-
attributeFilter: ["data-shortcut-modal"]
|
|
38561
|
-
});
|
|
38562
|
-
const onResize = () => schedule();
|
|
38563
|
-
win?.addEventListener?.("resize", onResize);
|
|
38564
|
-
sync();
|
|
38565
|
-
return {
|
|
38566
|
-
refresh: sync,
|
|
38567
|
-
dispose() {
|
|
38568
|
-
if (disposed) return;
|
|
38569
|
-
disposed = true;
|
|
38570
|
-
observer?.disconnect();
|
|
38571
|
-
win?.removeEventListener?.("resize", onResize);
|
|
38572
|
-
for (const panel of marked) panel.removeAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE);
|
|
38573
|
-
marked = /* @__PURE__ */ new Set();
|
|
38574
|
-
removeStyles(dom);
|
|
38575
|
-
}
|
|
38576
|
-
};
|
|
38577
|
-
}
|
|
38578
|
-
/** 读取窗口宽度;没有浏览器窗口时返回 0,确保适配默认不生效。 */
|
|
38579
|
-
function readViewportWidth(win) {
|
|
38580
|
-
const width = win?.innerWidth;
|
|
38581
|
-
if (typeof width === "number" && Number.isFinite(width) && width > 0) return width;
|
|
38582
|
-
const fallback = globalThis.innerWidth;
|
|
38583
|
-
return typeof fallback === "number" && Number.isFinite(fallback) && fallback > 0 ? fallback : 0;
|
|
38584
|
-
}
|
|
38585
|
-
function findSettingsPanels(dom) {
|
|
38586
|
-
return Array.from(dom.querySelectorAll(MOBILE_SETTINGS_MODAL_SELECTOR));
|
|
38587
|
-
}
|
|
38588
|
-
function installStyles$1(dom) {
|
|
38589
|
-
if (dom.head === void 0 || dom.head === null) return;
|
|
38590
|
-
if (Array.from(dom.head.children).some((child) => child.tagName === "STYLE" && child.dataset.pluginCss === "codingns4dsh-mobile-settings-style")) return;
|
|
38591
|
-
const style = dom.createElement("style");
|
|
38592
|
-
style.dataset.plugin = "codingns4dsh";
|
|
38593
|
-
style.dataset.pluginCss = MOBILE_SETTINGS_MODAL_STYLE_ID;
|
|
38594
|
-
style.textContent = MOBILE_SETTINGS_MODAL_STYLE_TEXT;
|
|
38595
|
-
dom.head.appendChild(style);
|
|
38596
|
-
}
|
|
38597
|
-
function removeStyles(dom) {
|
|
38598
|
-
if (dom?.head === void 0 || dom.head === null) return;
|
|
38599
|
-
for (const child of Array.from(dom.head.children)) {
|
|
38600
|
-
if (child.tagName !== "STYLE") continue;
|
|
38601
|
-
if (child.dataset.pluginCss !== "codingns4dsh-mobile-settings-style") continue;
|
|
38602
|
-
child.remove();
|
|
38603
|
-
}
|
|
38604
|
-
}
|
|
38605
|
-
/**
|
|
38606
|
-
* 只依赖设置根节点的语义结构,不依赖 DSH 的 CSS module 哈希类名。
|
|
38607
|
-
* `nav` 第一列保留按钮和图标,文字使用视觉隐藏保留可访问名称;右侧内容列
|
|
38608
|
-
* 继续由 DSH 自己的 flex 规则伸展到剩余空间。
|
|
38609
|
-
*/
|
|
38610
|
-
const MOBILE_SETTINGS_MODAL_STYLE_TEXT = [
|
|
38611
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]{box-sizing:border-box!important;width:100vw!important;max-width:none!important;height:100%!important;max-height:none!important;border-radius:0!important}`,
|
|
38612
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav{box-sizing:border-box!important;flex:0 0 60px!important;width:60px!important;min-width:60px!important;gap:12px!important;padding:16px 8px 0!important}`,
|
|
38613
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:first-child{box-sizing:border-box!important;width:44px!important;height:24px!important;padding:0!important;overflow:hidden!important;font-size:0!important;line-height:0!important;text-indent:-9999px!important}`,
|
|
38614
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child{box-sizing:border-box!important;align-items:center!important;gap:4px!important}`,
|
|
38615
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child>button{box-sizing:border-box!important;justify-content:center!important;width:44px!important;height:44px!important;padding:9px!important;gap:0!important}`,
|
|
38616
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child>button>span{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}`,
|
|
38617
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>div{box-sizing:border-box!important;min-width:0!important;flex:1 1 auto!important;width:auto!important}`,
|
|
38618
|
-
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>div>div:last-child{box-sizing:border-box!important;min-width:0!important;width:100%!important;padding-left:8px!important;padding-right:8px!important}`
|
|
38619
|
-
].join("");
|
|
38620
|
-
// src/client/mobile-team-panel-dom.ts
|
|
38621
|
-
const PANEL = "[data-team-panel][role=\"dialog\"]";
|
|
38622
|
-
const MOBILE = "data-codingns-mobile-team";
|
|
38623
|
-
const HEADER = "data-codingns-team-header";
|
|
38624
|
-
/** Adapt the native portal while DSH retains roster, task, and dismissal ownership. */
|
|
38625
|
-
function startMobileTeamPanelDom(options = {}) {
|
|
38626
|
-
const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
38627
|
-
const win = options.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
38628
|
-
const Observer = options.MutationObserver ?? (typeof MutationObserver === "undefined" ? void 0 : MutationObserver);
|
|
38629
|
-
const t = require_magpie_model_tag.resolveCodingNsTranslator(options.locale);
|
|
38630
|
-
const headers = /* @__PURE__ */ new Map();
|
|
38631
|
-
let style;
|
|
38632
|
-
let queued = false;
|
|
38633
|
-
let disposed = false;
|
|
38634
|
-
const remove = (panel, header) => {
|
|
38635
|
-
header.remove();
|
|
38636
|
-
panel.removeAttribute(MOBILE);
|
|
38637
|
-
headers.delete(panel);
|
|
38638
|
-
};
|
|
38639
|
-
const refresh = () => {
|
|
38640
|
-
if (disposed || !dom) return;
|
|
38641
|
-
const max = typeof options.mobileViewportMaxPx === "function" ? options.mobileViewportMaxPx() : options.mobileViewportMaxPx ?? 1024;
|
|
38642
|
-
const width = win?.innerWidth ?? 0;
|
|
38643
|
-
const panels = new Set(Number.isFinite(width) && width > 0 && Number.isFinite(max) && width <= max ? dom.querySelectorAll(PANEL) : []);
|
|
38644
|
-
for (const [panel, header] of headers) if (!panels.has(panel)) remove(panel, header);
|
|
38645
|
-
if (!panels.size) {
|
|
38646
|
-
style?.remove();
|
|
38647
|
-
style = void 0;
|
|
38648
|
-
return;
|
|
38649
|
-
}
|
|
38650
|
-
if (!style) {
|
|
38651
|
-
style = dom.createElement("style");
|
|
38652
|
-
style.dataset.plugin = "codingns4dsh";
|
|
38653
|
-
style.dataset.pluginCss = "codingns4dsh-mobile-team-panel";
|
|
38654
|
-
style.textContent = MOBILE_TEAM_PANEL_STYLES;
|
|
38655
|
-
dom.head.appendChild(style);
|
|
38656
|
-
}
|
|
38657
|
-
for (const panel of panels) {
|
|
38658
|
-
panel.setAttribute(MOBILE, "on");
|
|
38659
|
-
let header = headers.get(panel);
|
|
38660
|
-
if (!header) {
|
|
38661
|
-
header = createHeader(dom, panel);
|
|
38662
|
-
panel.insertBefore(header, panel.firstChild);
|
|
38663
|
-
headers.set(panel, header);
|
|
38664
|
-
}
|
|
38665
|
-
const title = panel.getAttribute("aria-label") || t("mobile.team.title");
|
|
38666
|
-
const heading = header.firstElementChild;
|
|
38667
|
-
if (heading.textContent !== title) heading.textContent = title;
|
|
38668
|
-
const button = header.lastElementChild;
|
|
38669
|
-
const label = t("mobile.team.close");
|
|
38670
|
-
if (button.getAttribute("aria-label") !== label) button.setAttribute("aria-label", label);
|
|
38671
|
-
if (button.getAttribute("title") !== label) button.setAttribute("title", label);
|
|
38672
|
-
}
|
|
38673
|
-
};
|
|
38674
|
-
const schedule = () => {
|
|
38675
|
-
if (disposed || queued) return;
|
|
38676
|
-
queued = true;
|
|
38677
|
-
queueMicrotask(() => {
|
|
38678
|
-
queued = false;
|
|
38679
|
-
refresh();
|
|
38680
|
-
});
|
|
38681
|
-
};
|
|
38682
|
-
const observer = dom && Observer ? new Observer(schedule) : void 0;
|
|
38683
|
-
if (dom?.documentElement) observer?.observe(dom.documentElement, {
|
|
38684
|
-
childList: true,
|
|
38685
|
-
subtree: true,
|
|
38686
|
-
attributes: true,
|
|
38687
|
-
attributeFilter: ["data-team-panel", "aria-label"]
|
|
38688
|
-
});
|
|
38689
|
-
win?.addEventListener("resize", schedule);
|
|
38690
|
-
const unsubscribeLocale = options.locale?.subscribe(schedule);
|
|
38691
|
-
refresh();
|
|
38692
|
-
return {
|
|
38693
|
-
refresh,
|
|
38694
|
-
dispose() {
|
|
38695
|
-
if (disposed) return;
|
|
38696
|
-
disposed = true;
|
|
38697
|
-
observer?.disconnect();
|
|
38698
|
-
win?.removeEventListener("resize", schedule);
|
|
38699
|
-
unsubscribeLocale?.();
|
|
38700
|
-
for (const [panel, header] of headers) remove(panel, header);
|
|
38701
|
-
style?.remove();
|
|
38702
|
-
style = void 0;
|
|
38703
|
-
}
|
|
38704
|
-
};
|
|
38705
|
-
}
|
|
38706
|
-
function createHeader(dom, panel) {
|
|
38707
|
-
const header = dom.createElement("div");
|
|
38708
|
-
header.setAttribute(HEADER, "");
|
|
38709
|
-
const button = dom.createElement("button");
|
|
38710
|
-
button.type = "button";
|
|
38711
|
-
const svg = dom.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
38712
|
-
svg.setAttribute("viewBox", "0 0 24 24");
|
|
38713
|
-
svg.setAttribute("width", "20");
|
|
38714
|
-
svg.setAttribute("height", "20");
|
|
38715
|
-
svg.setAttribute("aria-hidden", "true");
|
|
38716
|
-
const close = dom.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
38717
|
-
close.setAttribute("d", "M6 6l12 12m0-12L6 18");
|
|
38718
|
-
close.setAttribute("fill", "none");
|
|
38719
|
-
close.setAttribute("stroke", "currentColor");
|
|
38720
|
-
close.setAttribute("stroke-width", "2");
|
|
38721
|
-
close.setAttribute("stroke-linecap", "round");
|
|
38722
|
-
svg.appendChild(close);
|
|
38723
|
-
button.appendChild(svg);
|
|
38724
|
-
button.addEventListener("click", (event) => {
|
|
38725
|
-
event.stopPropagation();
|
|
38726
|
-
const Keyboard = dom.defaultView?.KeyboardEvent;
|
|
38727
|
-
if (!Keyboard) return;
|
|
38728
|
-
button.focus({ preventScroll: true });
|
|
38729
|
-
panel.dispatchEvent(new Keyboard("keydown", {
|
|
38730
|
-
key: "Escape",
|
|
38731
|
-
bubbles: true,
|
|
38732
|
-
cancelable: true
|
|
38733
|
-
}));
|
|
38734
|
-
});
|
|
38735
|
-
header.append(dom.createElement("strong"), button);
|
|
38736
|
-
return header;
|
|
38737
|
-
}
|
|
38738
|
-
const SCOPE = `[${MOBILE}="on"]`;
|
|
38739
|
-
const MOBILE_TEAM_PANEL_STYLES = `
|
|
38740
|
-
${SCOPE} {
|
|
38741
|
-
box-sizing:border-box!important;
|
|
38742
|
-
top:max(8px, env(safe-area-inset-top, 0px))!important;
|
|
38743
|
-
left:max(8px, env(safe-area-inset-left, 0px))!important;
|
|
38744
|
-
right:max(8px, env(safe-area-inset-right, 0px))!important;
|
|
38745
|
-
bottom:auto!important; width:auto!important; max-width:none!important;
|
|
38746
|
-
height:calc(100vh - 16px)!important;
|
|
38747
|
-
height:calc(100dvh - max(8px, env(safe-area-inset-top, 0px)) - max(8px, env(safe-area-inset-bottom, 0px)))!important;
|
|
38748
|
-
max-height:none!important; padding:0!important; visibility:visible!important; overflow:hidden!important;
|
|
38749
|
-
}
|
|
38750
|
-
${SCOPE}>[${HEADER}] {
|
|
38751
|
-
flex:0 0 auto; display:flex; align-items:center; justify-content:space-between; gap:12px; padding:6px 8px 6px 16px;
|
|
38752
|
-
border-bottom:1px solid var(--dsw-alias-border-l2, #ddd); color:var(--dsw-alias-label-primary, CanvasText);
|
|
38753
|
-
}
|
|
38754
|
-
${SCOPE}>[${HEADER}] strong { min-width:0; font-size:15px; overflow-wrap:anywhere; }
|
|
38755
|
-
${SCOPE}>[${HEADER}] button {
|
|
38756
|
-
display:inline-flex; align-items:center; justify-content:center; flex:0 0 44px; width:44px; height:44px;
|
|
38757
|
-
padding:0; border:0; border-radius:10px; color:var(--dsw-alias-label-primary, CanvasText); background:transparent;
|
|
38758
|
-
cursor:pointer; touch-action:manipulation; -webkit-tap-highlight-color:transparent;
|
|
38759
|
-
}
|
|
38760
|
-
${SCOPE}>[${HEADER}] button:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(127,127,127,.1)); }
|
|
38761
|
-
${SCOPE}>[${HEADER}] button:focus-visible { outline:2px solid var(--dsw-focus-ring-color, #1677ff); outline-offset:-2px; }
|
|
38762
|
-
${SCOPE}>[${HEADER}] svg { display:block; pointer-events:none; }
|
|
38763
|
-
${SCOPE}>div:not([${HEADER}]) {
|
|
38764
|
-
flex:1 1 auto!important; min-height:0!important; min-width:0; padding:0 12px 12px!important;
|
|
38765
|
-
overflow-y:auto!important; overscroll-behavior:contain; scrollbar-gutter:auto!important; -webkit-overflow-scrolling:touch;
|
|
38766
|
-
}
|
|
38767
|
-
${SCOPE} section:first-of-type>div { grid-template-columns:repeat(auto-fit, minmax(min(150px, 100%), 1fr))!important; }
|
|
38768
|
-
${SCOPE} section:first-of-type button { min-height:64px; padding:10px!important; touch-action:manipulation; }
|
|
38769
|
-
${SCOPE} section:first-of-type button>span:last-child>span { flex-wrap:wrap; }
|
|
38770
|
-
${SCOPE} section:first-of-type button>span:last-child>span>span:first-child { white-space:normal!important; overflow-wrap:anywhere; }
|
|
38771
|
-
${SCOPE} article { min-width:0; padding:12px!important; }
|
|
38772
|
-
${SCOPE} article>div:first-child { align-items:flex-start!important; }
|
|
38773
|
-
${SCOPE} article>div:first-child strong { flex:1; min-width:0; font-size:14px!important; line-height:1.45; overflow-wrap:anywhere; }
|
|
38774
|
-
${SCOPE} article>div:first-child>span { flex:0 0 auto; white-space:nowrap; }
|
|
38775
|
-
${SCOPE} article p { font-size:13px!important; line-height:1.55!important; overflow-wrap:anywhere; }
|
|
38776
|
-
${SCOPE} article>div:last-child { display:flex; flex-wrap:wrap; align-items:center; gap:4px 10px; }
|
|
38777
|
-
${SCOPE} article>div:last-child>span { min-width:0; max-width:100%; margin-right:0!important; overflow-wrap:anywhere; }
|
|
38778
|
-
${SCOPE} article>div:last-child>button { float:none!important; order:1; min-height:36px; margin-left:auto!important; padding:6px!important; touch-action:manipulation; }
|
|
38779
|
-
`;
|
|
38780
38193
|
// src/client/features/mobile-access-panel.ts
|
|
38781
38194
|
/**
|
|
38782
38195
|
* 移动端访问增强的单列设置面板。
|
|
@@ -38984,33 +38397,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
38984
38397
|
opacity: disabled ? .5 : 1,
|
|
38985
38398
|
pointerEvents: disabled ? "none" : "auto"
|
|
38986
38399
|
}
|
|
38987
|
-
}, (0, react.createElement)("label", { style:
|
|
38988
|
-
display: "block",
|
|
38989
|
-
fontSize: uiFontSize(13),
|
|
38990
|
-
lineHeight: 1.4
|
|
38991
|
-
} }, t("mobile.hideSidebarOnMobile")), (0, react.createElement)("span", { style: {
|
|
38992
|
-
display: "block",
|
|
38993
|
-
marginTop: 3,
|
|
38994
|
-
...dshSettingsHelpStyle
|
|
38995
|
-
} }, t("mobile.hideSidebarOnMobileDescription"))), (0, react.createElement)(SettingsSwitch, {
|
|
38996
|
-
"aria-label": t("mobile.hideSidebarOnMobile"),
|
|
38997
|
-
checked: value.hideSidebarOnMobile,
|
|
38998
|
-
disabled: controlsDisabled,
|
|
38999
|
-
onChange: (event) => updateField("hideSidebarOnMobile", event.currentTarget.checked, t("mobile.saved"))
|
|
39000
|
-
})), (0, react.createElement)("label", { style: dshSettingsListRowStyle }, (0, react.createElement)("span", { style: { minWidth: 0 } }, (0, react.createElement)("strong", { style: {
|
|
39001
|
-
display: "block",
|
|
39002
|
-
fontSize: uiFontSize(13),
|
|
39003
|
-
lineHeight: 1.4
|
|
39004
|
-
} }, t("mobile.optimizeSettingsOnMobile")), (0, react.createElement)("span", { style: {
|
|
39005
|
-
display: "block",
|
|
39006
|
-
marginTop: 3,
|
|
39007
|
-
...dshSettingsHelpStyle
|
|
39008
|
-
} }, t("mobile.optimizeSettingsOnMobileDescription"))), (0, react.createElement)(SettingsSwitch, {
|
|
39009
|
-
"aria-label": t("mobile.optimizeSettingsOnMobile"),
|
|
39010
|
-
checked: value.optimizeSettingsOnMobile,
|
|
39011
|
-
disabled: controlsDisabled,
|
|
39012
|
-
onChange: (event) => updateField("optimizeSettingsOnMobile", event.currentTarget.checked, t("mobile.saved"))
|
|
39013
|
-
})), (0, react.createElement)("label", { style: {
|
|
38400
|
+
}, (0, react.createElement)("label", { style: {
|
|
39014
38401
|
display: "flex",
|
|
39015
38402
|
flexDirection: "column",
|
|
39016
38403
|
gap: 6,
|
|
@@ -39196,12 +38583,9 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
39196
38583
|
/**
|
|
39197
38584
|
* 移动端访问增强。
|
|
39198
38585
|
*
|
|
39199
|
-
*
|
|
39200
|
-
*
|
|
39201
|
-
*
|
|
39202
|
-
*
|
|
39203
|
-
* 依赖 `layout.columns`:该能力对应的正是 0.2.0 起的三栏布局世代,插件改写的
|
|
39204
|
-
* 内联网格与 `data-sidebar-collapsed` 都来自同一代实现;能力不可用时整块禁用。
|
|
38586
|
+
* 保留移动端横滑手势,并把侧栏开合交给 DSH 原生布局服务。移动端布局、设置弹窗、右栏
|
|
38587
|
+
* 标签和团队面板都由当前 DSH 自己负责,插件不再改写宿主 DOM,避免与 0.2.2 的原生
|
|
38588
|
+
* 移动端布局冲突。
|
|
39205
38589
|
*/
|
|
39206
38590
|
const mobileAccessFeature = {
|
|
39207
38591
|
descriptor: {
|
|
@@ -39225,14 +38609,6 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
39225
38609
|
}
|
|
39226
38610
|
},
|
|
39227
38611
|
start(context) {
|
|
39228
|
-
const controller = startMobileSidebarRailDom({
|
|
39229
|
-
settings: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess),
|
|
39230
|
-
toggleSidebar: () => {
|
|
39231
|
-
context.services.layout?.toggleSidebar();
|
|
39232
|
-
},
|
|
39233
|
-
onDiagnostic: (code) => require_magpie_model_tag.debugWarn("codingns4dsh: 移动端侧栏隐藏不可用", { code }),
|
|
39234
|
-
locale: context.services.locale
|
|
39235
|
-
});
|
|
39236
38612
|
const gestures = startMobileSidebarGestures({
|
|
39237
38613
|
ports: {
|
|
39238
38614
|
layout: context.services.layout,
|
|
@@ -39240,39 +38616,25 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
39240
38616
|
},
|
|
39241
38617
|
onRightbarOpen: () => notifyMobileRightbarManualOpen(typeof document === "undefined" ? void 0 : document),
|
|
39242
38618
|
onRightbarClose: () => notifyMobileRightbarManualClose(typeof document === "undefined" ? void 0 : document),
|
|
39243
|
-
readLeftCollapsed:
|
|
39244
|
-
if (typeof document === "undefined") return void 0;
|
|
39245
|
-
return document.querySelector("[data-codingns-mobile-sidebar-frame]")?.hasAttribute("data-sidebar-collapsed");
|
|
39246
|
-
},
|
|
38619
|
+
readLeftCollapsed: readNativeLeftCollapsed,
|
|
39247
38620
|
settings: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess, context.services.settings.getSnapshot().value?.workspaceSessionEnhancement),
|
|
39248
38621
|
onDiagnostic: (code) => require_magpie_model_tag.debugWarn("codingns4dsh: 侧栏手势不可用", { code })
|
|
39249
38622
|
});
|
|
39250
|
-
const settingsModal = startMobileSettingsModalDom({
|
|
39251
|
-
enabled: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess, context.services.settings.getSnapshot().value?.workspaceSessionEnhancement).optimizeSettingsOnMobile,
|
|
39252
|
-
mobileViewportMaxPx: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess).mobileViewportMaxPx
|
|
39253
|
-
});
|
|
39254
|
-
const rightbarTabs = startMobileRightbarTabsDom({ mobileViewportMaxPx: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess).mobileViewportMaxPx });
|
|
39255
|
-
const teamPanel = startMobileTeamPanelDom({
|
|
39256
|
-
locale: context.services.locale,
|
|
39257
|
-
mobileViewportMaxPx: () => normalizeMobileAccessSettings(context.services.settings.getSnapshot().value?.mobileAccess).mobileViewportMaxPx
|
|
39258
|
-
});
|
|
39259
38623
|
context.resources.add(context.services.settings.subscribe(() => {
|
|
39260
|
-
controller.refresh();
|
|
39261
38624
|
gestures.refresh();
|
|
39262
|
-
settingsModal.refresh();
|
|
39263
|
-
rightbarTabs.refresh();
|
|
39264
|
-
teamPanel.refresh();
|
|
39265
38625
|
}));
|
|
39266
38626
|
context.resources.add(() => {
|
|
39267
|
-
controller.dispose();
|
|
39268
38627
|
gestures.dispose();
|
|
39269
|
-
settingsModal.dispose();
|
|
39270
|
-
rightbarTabs.dispose();
|
|
39271
|
-
teamPanel.dispose();
|
|
39272
38628
|
});
|
|
39273
38629
|
},
|
|
39274
38630
|
settingsPanel: MobileAccessPanel
|
|
39275
38631
|
};
|
|
38632
|
+
/** Read the host frame's native collapsed state without adding a plugin marker or style. */
|
|
38633
|
+
function readNativeLeftCollapsed() {
|
|
38634
|
+
if (typeof document === "undefined") return void 0;
|
|
38635
|
+
let current = document.querySelector("[data-shell-overlay]");
|
|
38636
|
+
for (let depth = 0; depth < 8 && current !== null; depth += 1, current = current.parentElement) if (current.style.gridTemplateColumns !== "") return current.hasAttribute("data-sidebar-collapsed");
|
|
38637
|
+
}
|
|
39276
38638
|
// src/client/debug/ui.ts
|
|
39277
38639
|
const DEBUG_KIND = "debug";
|
|
39278
38640
|
const DEBUG_PROVIDER_ID = "codingns4dsh/debug";
|
|
@@ -43709,9 +43071,11 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43709
43071
|
const onKeyDown = (event) => {
|
|
43710
43072
|
if (event.key === "Escape") closeMenu();
|
|
43711
43073
|
};
|
|
43712
|
-
|
|
43713
|
-
|
|
43714
|
-
|
|
43074
|
+
if (initialOptions.nativeContextMenus !== true) {
|
|
43075
|
+
document.addEventListener("contextmenu", onContextMenu, true);
|
|
43076
|
+
document.addEventListener("pointerdown", onDocumentPointerDown, true);
|
|
43077
|
+
document.addEventListener("keydown", onKeyDown, true);
|
|
43078
|
+
}
|
|
43715
43079
|
if (options.fileEditor) {
|
|
43716
43080
|
observer?.observe(document.body, {
|
|
43717
43081
|
childList: true,
|
|
@@ -43725,9 +43089,11 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43725
43089
|
clearEditorEnhancements();
|
|
43726
43090
|
editor = void 0;
|
|
43727
43091
|
observer?.disconnect();
|
|
43728
|
-
|
|
43729
|
-
|
|
43730
|
-
|
|
43092
|
+
if (initialOptions.nativeContextMenus !== true) {
|
|
43093
|
+
document.removeEventListener("contextmenu", onContextMenu, true);
|
|
43094
|
+
document.removeEventListener("pointerdown", onDocumentPointerDown, true);
|
|
43095
|
+
document.removeEventListener("keydown", onKeyDown, true);
|
|
43096
|
+
}
|
|
43731
43097
|
};
|
|
43732
43098
|
return {
|
|
43733
43099
|
setOptions(nextOptions) {
|
|
@@ -43759,7 +43125,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43759
43125
|
path,
|
|
43760
43126
|
...sessionId === void 0 ? {} : { sessionId }
|
|
43761
43127
|
};
|
|
43762
|
-
const base = kind === "directory" ? path : parentPath(path);
|
|
43128
|
+
const base = kind === "directory" ? path : parentPath$1(path);
|
|
43763
43129
|
const destination = {
|
|
43764
43130
|
...target,
|
|
43765
43131
|
path: base
|
|
@@ -43807,7 +43173,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43807
43173
|
},
|
|
43808
43174
|
{
|
|
43809
43175
|
label: t("fileMenu.paste"),
|
|
43810
|
-
disabled: clipboard === void 0 || !sameFileHost(clipboard.target.sessionId, sessionId),
|
|
43176
|
+
disabled: clipboard === void 0 || !sameFileHost$1(clipboard.target.sessionId, sessionId),
|
|
43811
43177
|
action: () => void pasteEntry(destination, panel)
|
|
43812
43178
|
},
|
|
43813
43179
|
{
|
|
@@ -43892,14 +43258,14 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43892
43258
|
if (!name) return;
|
|
43893
43259
|
await runMutation(directory ? "create-directory" : "create-file", {
|
|
43894
43260
|
...target,
|
|
43895
|
-
path: joinPath(target.path, name)
|
|
43261
|
+
path: joinPath$1(target.path, name)
|
|
43896
43262
|
}, panel);
|
|
43897
43263
|
}
|
|
43898
43264
|
async function renameEntry(target, panel) {
|
|
43899
43265
|
const { path } = target;
|
|
43900
|
-
const next = window.prompt(t("fileMenu.promptRename"), leaf(path))?.trim();
|
|
43901
|
-
if (!next || next === leaf(path)) return;
|
|
43902
|
-
const destination = isAbsoluteLike(next) ? next : joinPath(parentPath(path), next);
|
|
43266
|
+
const next = window.prompt(t("fileMenu.promptRename"), leaf$1(path))?.trim();
|
|
43267
|
+
if (!next || next === leaf$1(path)) return;
|
|
43268
|
+
const destination = isAbsoluteLike$1(next) ? next : joinPath$1(parentPath$1(path), next);
|
|
43903
43269
|
await runMutation("rename", {
|
|
43904
43270
|
...target,
|
|
43905
43271
|
destination
|
|
@@ -43908,7 +43274,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43908
43274
|
async function pasteEntry(target, panel) {
|
|
43909
43275
|
const source = clipboard;
|
|
43910
43276
|
if (source === void 0) return;
|
|
43911
|
-
if (!sameFileHost(source.target.sessionId, target.sessionId)) return;
|
|
43277
|
+
if (!sameFileHost$1(source.target.sessionId, target.sessionId)) return;
|
|
43912
43278
|
await runMutation(source.mode === "copy" ? "copy" : "move", {
|
|
43913
43279
|
...target,
|
|
43914
43280
|
paths: [source.target.path],
|
|
@@ -43917,7 +43283,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43917
43283
|
if (source.mode === "cut" && clipboard === source) clipboard = void 0;
|
|
43918
43284
|
}
|
|
43919
43285
|
async function deleteEntry(target, panel) {
|
|
43920
|
-
if (!window.confirm(t("fileMenu.confirmDelete", { name: leaf(target.path) }))) return;
|
|
43286
|
+
if (!window.confirm(t("fileMenu.confirmDelete", { name: leaf$1(target.path) }))) return;
|
|
43921
43287
|
await runMutation("delete", {
|
|
43922
43288
|
...target,
|
|
43923
43289
|
paths: [target.path]
|
|
@@ -43926,16 +43292,16 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43926
43292
|
async function downloadFile(target) {
|
|
43927
43293
|
try {
|
|
43928
43294
|
const result = await call("download", target);
|
|
43929
|
-
const blob = new Blob([decodeBase64$
|
|
43295
|
+
const blob = new Blob([decodeBase64$3(result.contentBase64)], { type: result.mimeType ?? "application/octet-stream" });
|
|
43930
43296
|
const link = document.createElement("a");
|
|
43931
43297
|
link.href = URL.createObjectURL(blob);
|
|
43932
|
-
link.download = result.fileName ?? leaf(target.path);
|
|
43298
|
+
link.download = result.fileName ?? leaf$1(target.path);
|
|
43933
43299
|
document.body.append(link);
|
|
43934
43300
|
link.click();
|
|
43935
43301
|
link.remove();
|
|
43936
43302
|
globalThis.setTimeout(() => URL.revokeObjectURL(link.href), 3e4);
|
|
43937
43303
|
} catch (error) {
|
|
43938
|
-
showNotice(errorMessage$
|
|
43304
|
+
showNotice(errorMessage$2(error));
|
|
43939
43305
|
}
|
|
43940
43306
|
}
|
|
43941
43307
|
async function copyPath(item, absolute) {
|
|
@@ -43956,7 +43322,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
43956
43322
|
refreshPanel(panel);
|
|
43957
43323
|
showNotice(t("fileMenu.operationDone"));
|
|
43958
43324
|
} catch (error) {
|
|
43959
|
-
showNotice(errorMessage$
|
|
43325
|
+
showNotice(errorMessage$2(error));
|
|
43960
43326
|
}
|
|
43961
43327
|
}
|
|
43962
43328
|
function refreshPanel(panel) {
|
|
@@ -44029,7 +43395,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44029
43395
|
const notice = document.createElement("div");
|
|
44030
43396
|
notice.setAttribute("data-file-management-load-error", "true");
|
|
44031
43397
|
notice.setAttribute("role", "alert");
|
|
44032
|
-
notice.textContent = errorMessage$
|
|
43398
|
+
notice.textContent = errorMessage$2(error);
|
|
44033
43399
|
const retry = document.createElement("button");
|
|
44034
43400
|
retry.type = "button";
|
|
44035
43401
|
retry.textContent = t("fileEditor.edit");
|
|
@@ -44053,7 +43419,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44053
43419
|
reload?.click();
|
|
44054
43420
|
showNotice(t("fileEditor.saved"));
|
|
44055
43421
|
} catch (error) {
|
|
44056
|
-
showNotice(errorMessage$
|
|
43422
|
+
showNotice(errorMessage$2(error));
|
|
44057
43423
|
}
|
|
44058
43424
|
}
|
|
44059
43425
|
function cancelEdit(reenhance = true) {
|
|
@@ -44204,7 +43570,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44204
43570
|
path: decodeURIComponent(match[2] ?? "")
|
|
44205
43571
|
};
|
|
44206
43572
|
}
|
|
44207
|
-
function sameFileHost(left, right) {
|
|
43573
|
+
function sameFileHost$1(left, right) {
|
|
44208
43574
|
return (left === void 0 ? void 0 : require_magpie_model_tag.parseVirtualSessionId(left)?.hostId) === (right === void 0 ? void 0 : require_magpie_model_tag.parseVirtualSessionId(right)?.hostId);
|
|
44209
43575
|
}
|
|
44210
43576
|
function filesRootForEntry(item) {
|
|
@@ -44223,23 +43589,23 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44223
43589
|
const dot = fileName.lastIndexOf(".");
|
|
44224
43590
|
return dot > 0 && TEXT_EXTENSIONS.has(fileName.slice(dot));
|
|
44225
43591
|
}
|
|
44226
|
-
function parentPath(path) {
|
|
43592
|
+
function parentPath$1(path) {
|
|
44227
43593
|
const index = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
44228
43594
|
return index <= 0 ? path.slice(0, Math.max(index, 1)) : path.slice(0, index);
|
|
44229
43595
|
}
|
|
44230
|
-
function leaf(path) {
|
|
43596
|
+
function leaf$1(path) {
|
|
44231
43597
|
return path.split(/[\\/]/u).filter(Boolean).pop() ?? path;
|
|
44232
43598
|
}
|
|
44233
|
-
function isAbsoluteLike(path) {
|
|
43599
|
+
function isAbsoluteLike$1(path) {
|
|
44234
43600
|
return path.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(path);
|
|
44235
43601
|
}
|
|
44236
|
-
function joinPath(base, child) {
|
|
43602
|
+
function joinPath$1(base, child) {
|
|
44237
43603
|
const separator = base.includes("\\") && !base.includes("/") ? "\\" : "/";
|
|
44238
43604
|
return `${base.replace(/[\\/]$/u, "")}${separator}${child.replace(/^[\\/]+/u, "")}`;
|
|
44239
43605
|
}
|
|
44240
43606
|
function absolutePath(path, root) {
|
|
44241
|
-
if (isAbsoluteLike(path) || root === void 0) return path;
|
|
44242
|
-
return joinPath(root, path);
|
|
43607
|
+
if (isAbsoluteLike$1(path) || root === void 0) return path;
|
|
43608
|
+
return joinPath$1(root, path);
|
|
44243
43609
|
}
|
|
44244
43610
|
function relativePath(path, root) {
|
|
44245
43611
|
const workspaceRoot = root ?? document.querySelector("[data-files-root]")?.getAttribute("data-files-root") ?? void 0;
|
|
@@ -44257,8 +43623,8 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44257
43623
|
const resourceAbsolutePath = input.resourceAbsolutePath?.trim() ?? "";
|
|
44258
43624
|
const workspaceRoot = input.workspaceRoot?.trim() || void 0;
|
|
44259
43625
|
if ((resourcePath || displayPath || resourceAbsolutePath) === "") return void 0;
|
|
44260
|
-
const absolute = resourceAbsolutePath || (isAbsoluteLike(displayPath) ? displayPath : "") || absolutePath(resourcePath || displayPath, workspaceRoot);
|
|
44261
|
-
const relative = relativePath(resourcePath || (isAbsoluteLike(displayPath) ? displayPath : resourcePath) || absolute, workspaceRoot);
|
|
43626
|
+
const absolute = resourceAbsolutePath || (isAbsoluteLike$1(displayPath) ? displayPath : "") || absolutePath(resourcePath || displayPath, workspaceRoot);
|
|
43627
|
+
const relative = relativePath(resourcePath || (isAbsoluteLike$1(displayPath) ? displayPath : resourcePath) || absolute, workspaceRoot);
|
|
44262
43628
|
if (absolute === "" && relative === "") return void 0;
|
|
44263
43629
|
return {
|
|
44264
43630
|
relative,
|
|
@@ -44301,13 +43667,13 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
44301
43667
|
textarea.remove();
|
|
44302
43668
|
}
|
|
44303
43669
|
}
|
|
44304
|
-
function decodeBase64$
|
|
43670
|
+
function decodeBase64$3(value) {
|
|
44305
43671
|
const binary = atob(value);
|
|
44306
43672
|
const bytes = new Uint8Array(binary.length);
|
|
44307
43673
|
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
44308
43674
|
return bytes.buffer;
|
|
44309
43675
|
}
|
|
44310
|
-
function errorMessage$
|
|
43676
|
+
function errorMessage$2(error) {
|
|
44311
43677
|
return error instanceof Error ? error.message : String(error);
|
|
44312
43678
|
}
|
|
44313
43679
|
function showNotice(message) {
|
|
@@ -45284,7 +44650,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45284
44650
|
const address = (props.tab.contentId ?? "").split(/[?#]/u)[0] ?? "";
|
|
45285
44651
|
const parsed = parseFileTarget(address);
|
|
45286
44652
|
if (parsed === void 0) return void 0;
|
|
45287
|
-
const workspaceRoot = workspaceRootForSession(props.sessionId);
|
|
44653
|
+
const workspaceRoot = workspaceRootForSession$1(props.sessionId);
|
|
45288
44654
|
const resourceAbsolutePath = props.useResource?.(address)?.value?.absolutePath;
|
|
45289
44655
|
return resolveFileCopyPaths({
|
|
45290
44656
|
resourcePath: parsed.path,
|
|
@@ -45307,7 +44673,7 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45307
44673
|
onClick: onSelect
|
|
45308
44674
|
}, t(key));
|
|
45309
44675
|
}
|
|
45310
|
-
function workspaceRootForSession(sessionId) {
|
|
44676
|
+
function workspaceRootForSession$1(sessionId) {
|
|
45311
44677
|
if (typeof document === "undefined") return void 0;
|
|
45312
44678
|
if (sessionId !== void 0 && sessionId !== "") {
|
|
45313
44679
|
const scoped = document.querySelector(`[data-sidebar-right-session="${cssAttribute(sessionId)}"] [data-files-root]`)?.getAttribute("data-files-root")?.trim();
|
|
@@ -45463,6 +44829,233 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45463
44829
|
window.removeEventListener("message", onMessage);
|
|
45464
44830
|
};
|
|
45465
44831
|
}
|
|
44832
|
+
// src/client/file-management-context-menu.ts
|
|
44833
|
+
/** Registers alpha.3 file actions while leaving the DOM menu as the old-host fallback. */
|
|
44834
|
+
function registerFileManagementContextMenus(rpc, contextMenus, locale) {
|
|
44835
|
+
if (contextMenus === void 0) return {
|
|
44836
|
+
setEnabled: () => void 0,
|
|
44837
|
+
dispose: () => void 0
|
|
44838
|
+
};
|
|
44839
|
+
const menuService = contextMenus;
|
|
44840
|
+
const t = require_magpie_model_tag.resolveCodingNsTranslator(locale);
|
|
44841
|
+
let enabled = false;
|
|
44842
|
+
let clipboard;
|
|
44843
|
+
const disposers = [menuService.register({
|
|
44844
|
+
id: "codingns.file-management.file",
|
|
44845
|
+
target: "file",
|
|
44846
|
+
order: 400,
|
|
44847
|
+
resolve: (value, signal) => resolveFileActions(value, false, signal)
|
|
44848
|
+
}), menuService.register({
|
|
44849
|
+
id: "codingns.file-management.directory",
|
|
44850
|
+
target: "directory",
|
|
44851
|
+
order: 400,
|
|
44852
|
+
resolve: (value, signal) => resolveFileActions(value, true, signal)
|
|
44853
|
+
})];
|
|
44854
|
+
return {
|
|
44855
|
+
setEnabled(value) {
|
|
44856
|
+
enabled = value;
|
|
44857
|
+
},
|
|
44858
|
+
dispose() {
|
|
44859
|
+
for (const dispose of disposers) dispose();
|
|
44860
|
+
}
|
|
44861
|
+
};
|
|
44862
|
+
function resolveFileActions(value, directory, signal) {
|
|
44863
|
+
if (!enabled || signal.aborted) return [];
|
|
44864
|
+
const target = readTarget(value);
|
|
44865
|
+
if (target === void 0) return [];
|
|
44866
|
+
const destination = directory ? target : {
|
|
44867
|
+
...target,
|
|
44868
|
+
path: parentPath(target.path)
|
|
44869
|
+
};
|
|
44870
|
+
const workspaceRoot = workspaceRootForSession(target.sessionId);
|
|
44871
|
+
const paths = resolveFileCopyPaths({
|
|
44872
|
+
resourcePath: target.path,
|
|
44873
|
+
...workspaceRoot === void 0 ? {} : { workspaceRoot }
|
|
44874
|
+
});
|
|
44875
|
+
const absoluteAvailable = paths?.absolute !== void 0 && paths.absolute !== "";
|
|
44876
|
+
return [
|
|
44877
|
+
{
|
|
44878
|
+
id: "download",
|
|
44879
|
+
label: t("fileMenu.download"),
|
|
44880
|
+
disabled: directory,
|
|
44881
|
+
run: () => directory ? void 0 : downloadFile(target)
|
|
44882
|
+
},
|
|
44883
|
+
{
|
|
44884
|
+
id: "newFile",
|
|
44885
|
+
label: t("fileMenu.newFile"),
|
|
44886
|
+
run: () => createEntry(destination, false)
|
|
44887
|
+
},
|
|
44888
|
+
{
|
|
44889
|
+
id: "newDirectory",
|
|
44890
|
+
label: t("fileMenu.newDirectory"),
|
|
44891
|
+
run: () => createEntry(destination, true)
|
|
44892
|
+
},
|
|
44893
|
+
{
|
|
44894
|
+
id: "rename",
|
|
44895
|
+
label: t("fileMenu.rename"),
|
|
44896
|
+
run: () => renameEntry(target)
|
|
44897
|
+
},
|
|
44898
|
+
{
|
|
44899
|
+
id: "copy",
|
|
44900
|
+
label: t("fileMenu.copy"),
|
|
44901
|
+
run: () => {
|
|
44902
|
+
clipboard = {
|
|
44903
|
+
mode: "copy",
|
|
44904
|
+
target
|
|
44905
|
+
};
|
|
44906
|
+
}
|
|
44907
|
+
},
|
|
44908
|
+
{
|
|
44909
|
+
id: "cut",
|
|
44910
|
+
label: t("fileMenu.cut"),
|
|
44911
|
+
run: () => {
|
|
44912
|
+
clipboard = {
|
|
44913
|
+
mode: "cut",
|
|
44914
|
+
target
|
|
44915
|
+
};
|
|
44916
|
+
}
|
|
44917
|
+
},
|
|
44918
|
+
{
|
|
44919
|
+
id: "paste",
|
|
44920
|
+
label: t("fileMenu.paste"),
|
|
44921
|
+
disabled: clipboard === void 0 || !sameFileHost(clipboard.target.sessionId, target.sessionId),
|
|
44922
|
+
run: () => pasteEntry(destination)
|
|
44923
|
+
},
|
|
44924
|
+
{
|
|
44925
|
+
id: "copyRelativePath",
|
|
44926
|
+
label: t("fileMenu.copyRelativePath"),
|
|
44927
|
+
run: () => paths === void 0 ? notify(t("fileMenu.unresolvedPath")) : copyResolvedFilePath(paths.relative, false, t)
|
|
44928
|
+
},
|
|
44929
|
+
{
|
|
44930
|
+
id: "copyAbsolutePath",
|
|
44931
|
+
label: t("fileMenu.copyAbsolutePath"),
|
|
44932
|
+
disabled: !absoluteAvailable,
|
|
44933
|
+
run: () => paths === void 0 ? notify(t("fileMenu.unresolvedPath")) : copyResolvedFilePath(paths.absolute, true, t)
|
|
44934
|
+
},
|
|
44935
|
+
{
|
|
44936
|
+
id: "gitIgnore",
|
|
44937
|
+
label: t("fileMenu.gitIgnore"),
|
|
44938
|
+
run: () => runMutation("git-ignore", {
|
|
44939
|
+
...target,
|
|
44940
|
+
paths: [target.path]
|
|
44941
|
+
})
|
|
44942
|
+
},
|
|
44943
|
+
{
|
|
44944
|
+
id: "delete",
|
|
44945
|
+
label: t("fileMenu.delete"),
|
|
44946
|
+
danger: true,
|
|
44947
|
+
separatorBefore: true,
|
|
44948
|
+
run: () => deleteEntry(target)
|
|
44949
|
+
}
|
|
44950
|
+
];
|
|
44951
|
+
}
|
|
44952
|
+
async function createEntry(target, directory) {
|
|
44953
|
+
const name = window.prompt(t(directory ? "fileMenu.promptNewDirectory" : "fileMenu.promptNewFile"), "")?.trim();
|
|
44954
|
+
if (!name) return;
|
|
44955
|
+
await runMutation(directory ? "create-directory" : "create-file", {
|
|
44956
|
+
...target,
|
|
44957
|
+
path: joinPath(target.path, name)
|
|
44958
|
+
});
|
|
44959
|
+
}
|
|
44960
|
+
async function renameEntry(target) {
|
|
44961
|
+
const next = window.prompt(t("fileMenu.promptRename"), leaf(target.path))?.trim();
|
|
44962
|
+
if (!next || next === leaf(target.path)) return;
|
|
44963
|
+
const destination = isAbsoluteLike(next) ? next : joinPath(parentPath(target.path), next);
|
|
44964
|
+
await runMutation("rename", {
|
|
44965
|
+
...target,
|
|
44966
|
+
destination
|
|
44967
|
+
});
|
|
44968
|
+
}
|
|
44969
|
+
async function pasteEntry(target) {
|
|
44970
|
+
const source = clipboard;
|
|
44971
|
+
if (source === void 0 || !sameFileHost(source.target.sessionId, target.sessionId)) return;
|
|
44972
|
+
await runMutation(source.mode === "copy" ? "copy" : "move", {
|
|
44973
|
+
...target,
|
|
44974
|
+
paths: [source.target.path],
|
|
44975
|
+
destination: target.path
|
|
44976
|
+
});
|
|
44977
|
+
if (source.mode === "cut" && clipboard === source) clipboard = void 0;
|
|
44978
|
+
}
|
|
44979
|
+
async function deleteEntry(target) {
|
|
44980
|
+
if (!window.confirm(t("fileMenu.confirmDelete", { name: leaf(target.path) }))) return;
|
|
44981
|
+
await runMutation("delete", {
|
|
44982
|
+
...target,
|
|
44983
|
+
paths: [target.path]
|
|
44984
|
+
});
|
|
44985
|
+
}
|
|
44986
|
+
async function downloadFile(target) {
|
|
44987
|
+
try {
|
|
44988
|
+
const result = await call("download", target);
|
|
44989
|
+
const blob = new Blob([decodeBase64$2(result.contentBase64)], { type: result.mimeType ?? "application/octet-stream" });
|
|
44990
|
+
const link = document.createElement("a");
|
|
44991
|
+
link.href = URL.createObjectURL(blob);
|
|
44992
|
+
link.download = result.fileName ?? leaf(target.path);
|
|
44993
|
+
document.body.append(link);
|
|
44994
|
+
link.click();
|
|
44995
|
+
link.remove();
|
|
44996
|
+
globalThis.setTimeout(() => URL.revokeObjectURL(link.href), 3e4);
|
|
44997
|
+
} catch (error) {
|
|
44998
|
+
notify(errorMessage$1(error));
|
|
44999
|
+
}
|
|
45000
|
+
}
|
|
45001
|
+
async function runMutation(action, payload) {
|
|
45002
|
+
try {
|
|
45003
|
+
await call(action, payload);
|
|
45004
|
+
refreshPanel(payload.sessionId);
|
|
45005
|
+
notify(t("fileMenu.operationDone"), true);
|
|
45006
|
+
} catch (error) {
|
|
45007
|
+
notify(errorMessage$1(error));
|
|
45008
|
+
}
|
|
45009
|
+
}
|
|
45010
|
+
async function call(action, payload) {
|
|
45011
|
+
return callCodingNsRpc(rpc, `fileManagement/${action}`, payload);
|
|
45012
|
+
}
|
|
45013
|
+
function notify(message, success = false) {
|
|
45014
|
+
menuService.notify(message, success);
|
|
45015
|
+
}
|
|
45016
|
+
}
|
|
45017
|
+
function readTarget(value) {
|
|
45018
|
+
if (typeof value !== "object" || value === null) return void 0;
|
|
45019
|
+
const target = value;
|
|
45020
|
+
return typeof target.sessionId === "string" && typeof target.path === "string" && target.path !== "" ? {
|
|
45021
|
+
sessionId: target.sessionId,
|
|
45022
|
+
path: target.path
|
|
45023
|
+
} : void 0;
|
|
45024
|
+
}
|
|
45025
|
+
function refreshPanel(sessionId) {
|
|
45026
|
+
if (typeof document === "undefined" || typeof sessionId !== "string") return;
|
|
45027
|
+
([...document.querySelectorAll("[data-sidebar-right-session]")].find((item) => item.getAttribute("data-sidebar-right-session") === sessionId)?.querySelector("[data-files-reload]"))?.click();
|
|
45028
|
+
}
|
|
45029
|
+
function workspaceRootForSession(sessionId) {
|
|
45030
|
+
if (typeof document === "undefined") return void 0;
|
|
45031
|
+
return [...document.querySelectorAll("[data-sidebar-right-session]")].find((item) => item.getAttribute("data-sidebar-right-session") === sessionId)?.querySelector("[data-files-root]")?.getAttribute("data-files-root")?.trim() || document.querySelector("[data-files-root]")?.getAttribute("data-files-root")?.trim() || void 0;
|
|
45032
|
+
}
|
|
45033
|
+
function sameFileHost(left, right) {
|
|
45034
|
+
return require_magpie_model_tag.parseVirtualSessionId(left)?.hostId === require_magpie_model_tag.parseVirtualSessionId(right)?.hostId;
|
|
45035
|
+
}
|
|
45036
|
+
function parentPath(path) {
|
|
45037
|
+
const index = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
45038
|
+
return index <= 0 ? path.slice(0, Math.max(index, 1)) : path.slice(0, index);
|
|
45039
|
+
}
|
|
45040
|
+
function leaf(path) {
|
|
45041
|
+
return path.split(/[\\/]/u).filter(Boolean).pop() ?? path;
|
|
45042
|
+
}
|
|
45043
|
+
function isAbsoluteLike(path) {
|
|
45044
|
+
return path.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(path);
|
|
45045
|
+
}
|
|
45046
|
+
function joinPath(base, child) {
|
|
45047
|
+
const separator = base.includes("\\") && !base.includes("/") ? "\\" : "/";
|
|
45048
|
+
return `${base.replace(/[\\/]$/u, "")}${separator}${child.replace(/^[\\/]+/u, "")}`;
|
|
45049
|
+
}
|
|
45050
|
+
function decodeBase64$2(value) {
|
|
45051
|
+
const binary = atob(value);
|
|
45052
|
+
const bytes = new Uint8Array(binary.length);
|
|
45053
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
45054
|
+
return bytes.buffer;
|
|
45055
|
+
}
|
|
45056
|
+
function errorMessage$1(error) {
|
|
45057
|
+
return error instanceof Error ? error.message : String(error);
|
|
45058
|
+
}
|
|
45466
45059
|
// src/client/features/file-management.ts
|
|
45467
45060
|
/** descriptor 的 label/description 只是词典缺失时的兜底,取内置中文词典。 */
|
|
45468
45061
|
const fallbackT$2 = require_magpie_model_tag.resolveCodingNsTranslator();
|
|
@@ -45474,6 +45067,11 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45474
45067
|
enabledByDefault: false,
|
|
45475
45068
|
dependencies: [],
|
|
45476
45069
|
runtime: "client",
|
|
45070
|
+
requires: [{
|
|
45071
|
+
capability: "ui.context-menu",
|
|
45072
|
+
required: false,
|
|
45073
|
+
fallback: "degrade"
|
|
45074
|
+
}],
|
|
45477
45075
|
nativeReplacement: {
|
|
45478
45076
|
dshFeature: "DSH native file delivery, image upload, and drag-and-drop",
|
|
45479
45077
|
since: "0.2.2-alpha.2",
|
|
@@ -45498,10 +45096,12 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45498
45096
|
return {
|
|
45499
45097
|
menuEnhancement: value.menuEnhancement,
|
|
45500
45098
|
fileEditor: value.fileEditor,
|
|
45501
|
-
locale: context.services.locale
|
|
45099
|
+
locale: context.services.locale,
|
|
45100
|
+
nativeContextMenus: context.services.contextMenus !== void 0
|
|
45502
45101
|
};
|
|
45503
45102
|
};
|
|
45504
45103
|
const dom = startFileManagementDom(context.services.rpc, readOptions());
|
|
45104
|
+
const contextMenu = registerFileManagementContextMenus(context.services.rpc, context.services.contextMenus, context.services.locale);
|
|
45505
45105
|
context.resources.add(startHtmlWorkspaceFiles(context.services.rpc, context.services.locale));
|
|
45506
45106
|
let disposeSessionView;
|
|
45507
45107
|
let disposeCopyPathMenu;
|
|
@@ -45522,23 +45122,33 @@ ${SCOPE} article>div:last-child>button { float:none!important; order:1; min-heig
|
|
|
45522
45122
|
...DEFAULT_FILE_MANAGEMENT_SETTINGS,
|
|
45523
45123
|
...context.services.settings.getSnapshot().value?.fileManagement
|
|
45524
45124
|
};
|
|
45525
|
-
if (value.menuEnhancement && disposeCopyPathMenu === void 0) disposeCopyPathMenu = registerFileViewerCopyPathMenu(slots, context.services.locale);
|
|
45125
|
+
if (value.menuEnhancement && context.services.contextMenus === void 0 && disposeCopyPathMenu === void 0) disposeCopyPathMenu = registerFileViewerCopyPathMenu(slots, context.services.locale);
|
|
45526
45126
|
else if (!value.menuEnhancement && disposeCopyPathMenu !== void 0) {
|
|
45527
45127
|
disposeCopyPathMenu();
|
|
45528
45128
|
disposeCopyPathMenu = void 0;
|
|
45529
45129
|
}
|
|
45530
45130
|
};
|
|
45131
|
+
const syncContextMenu = () => {
|
|
45132
|
+
const value = {
|
|
45133
|
+
...DEFAULT_FILE_MANAGEMENT_SETTINGS,
|
|
45134
|
+
...context.services.settings.getSnapshot().value?.fileManagement
|
|
45135
|
+
};
|
|
45136
|
+
contextMenu.setEnabled(value.menuEnhancement);
|
|
45137
|
+
};
|
|
45531
45138
|
syncSessionView();
|
|
45532
45139
|
syncCopyPathMenu();
|
|
45140
|
+
syncContextMenu();
|
|
45533
45141
|
const unsubscribe = context.services.settings.subscribe(() => {
|
|
45534
45142
|
dom.setOptions(readOptions());
|
|
45535
45143
|
syncSessionView();
|
|
45536
45144
|
syncCopyPathMenu();
|
|
45145
|
+
syncContextMenu();
|
|
45537
45146
|
});
|
|
45538
45147
|
context.resources.add(unsubscribe);
|
|
45539
45148
|
context.resources.add(dom.dispose);
|
|
45540
45149
|
context.resources.add(() => disposeSessionView?.());
|
|
45541
45150
|
context.resources.add(() => disposeCopyPathMenu?.());
|
|
45151
|
+
context.resources.add(contextMenu.dispose);
|
|
45542
45152
|
},
|
|
45543
45153
|
settingsPanel: FileManagementPanel
|
|
45544
45154
|
};
|
|
@@ -67221,7 +66831,7 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${dshThemeColor.lab
|
|
|
67221
66831
|
});
|
|
67222
66832
|
});
|
|
67223
66833
|
dom.addEventListener("focusin", onFocusIn, true);
|
|
67224
|
-
installStyles(dom);
|
|
66834
|
+
installStyles$1(dom);
|
|
67225
66835
|
observer.observe(dom.documentElement, {
|
|
67226
66836
|
childList: true,
|
|
67227
66837
|
subtree: true,
|
|
@@ -67331,7 +66941,7 @@ button[${ACCOUNT_ATTRIBUTE}]:focus-visible{outline:2px solid ${dshThemeColor.lab
|
|
|
67331
66941
|
if (proxy.getAttribute("aria-selected") !== "true") proxy.setAttribute("aria-selected", "true");
|
|
67332
66942
|
} else if (proxy.hasAttribute("aria-selected")) proxy.removeAttribute("aria-selected");
|
|
67333
66943
|
}
|
|
67334
|
-
function installStyles(dom) {
|
|
66944
|
+
function installStyles$1(dom) {
|
|
67335
66945
|
if (dom.querySelector("style[data-codingns-credential-ui]") !== null) return;
|
|
67336
66946
|
const style = dom.createElement("style");
|
|
67337
66947
|
style.setAttribute("data-codingns-credential-ui", "");
|
|
@@ -67801,7 +67411,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
67801
67411
|
return (0, react.createElement)("aside", {
|
|
67802
67412
|
className: settingsPromoClass.root,
|
|
67803
67413
|
"aria-label": t("settings.promo.sectionLabel")
|
|
67804
|
-
}, (0, react.createElement)("div", { className: settingsPromoClass.row }, (0, react.createElement)("div", { className: settingsPromoClass.brand }, (0, react.createElement)("div", { className: settingsPromoClass.headline }, (0, react.createElement)(StarBurstIcon, { className: settingsPromoClass.logo }), (0, react.createElement)("h3", { className: settingsPromoClass.title }, t("common.brand"))), versionControl ?? (0, react.createElement)("span", { className: settingsPromoClass.version }, t("settings.promo.version", { version: "0.2.2-beta.
|
|
67414
|
+
}, (0, react.createElement)("div", { className: settingsPromoClass.row }, (0, react.createElement)("div", { className: settingsPromoClass.brand }, (0, react.createElement)("div", { className: settingsPromoClass.headline }, (0, react.createElement)(StarBurstIcon, { className: settingsPromoClass.logo }), (0, react.createElement)("h3", { className: settingsPromoClass.title }, t("common.brand"))), versionControl ?? (0, react.createElement)("span", { className: settingsPromoClass.version }, t("settings.promo.version", { version: "0.2.2-beta.2" }))), (0, react.createElement)("p", { className: settingsPromoClass.text }, t("settings.promo.starHint"), (0, react.createElement)("span", {
|
|
67805
67415
|
className: settingsPromoClass.hand,
|
|
67806
67416
|
"aria-hidden": true
|
|
67807
67417
|
}, "👉")), (0, react.createElement)("a", {
|
|
@@ -67858,7 +67468,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
67858
67468
|
};
|
|
67859
67469
|
}
|
|
67860
67470
|
// src/client/update-store.ts
|
|
67861
|
-
const DEFAULT_PLUGIN_UPDATE_CHANNEL = "0.2.2-beta.
|
|
67471
|
+
const DEFAULT_PLUGIN_UPDATE_CHANNEL = "0.2.2-beta.2".includes("-") ? "next" : "latest";
|
|
67862
67472
|
var PluginUpdateStore = class {
|
|
67863
67473
|
rpc;
|
|
67864
67474
|
snapshot = {
|
|
@@ -69235,7 +68845,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69235
68845
|
function toClientValue(value) {
|
|
69236
68846
|
return value === void 0 ? void 0 : (({ cliSessions: _cliSessions, ...clientValue }) => clientValue)(value);
|
|
69237
68847
|
}
|
|
69238
|
-
// node_modules/.pnpm/@deepseek-ai+cosmokit@1.
|
|
68848
|
+
// node_modules/.pnpm/@deepseek-ai+cosmokit@1.9.0/node_modules/@deepseek-ai/cosmokit/lib/index.js
|
|
69239
68849
|
/** Return true when a value is `null` or `undefined`. */
|
|
69240
68850
|
function isNullable(value) {
|
|
69241
68851
|
return value === null || value === void 0;
|
|
@@ -69403,7 +69013,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69403
69013
|
}
|
|
69404
69014
|
Time.template = template;
|
|
69405
69015
|
})(Time || (Time = {}));
|
|
69406
|
-
// node_modules/.pnpm/@deepseek-ai+cordis@4.
|
|
69016
|
+
// node_modules/.pnpm/@deepseek-ai+cordis@4.1.0_@deepseek-ai+cordis-plugin-include@1.1.0_@deepseek-ai+cordis-plugin-loader@1.1.0/node_modules/@deepseek-ai/cordis/lib/index.js
|
|
69407
69017
|
/** Ordered collection of disposable values with O(1) deletion by value. */
|
|
69408
69018
|
var DisposableList = class {
|
|
69409
69019
|
sn = 0;
|
|
@@ -69438,6 +69048,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69438
69048
|
/** Shared symbols used to avoid public property-name collisions. */
|
|
69439
69049
|
const symbols = {
|
|
69440
69050
|
shadow: Symbol.for("cordis.shadow"),
|
|
69051
|
+
caller: Symbol.for("cordis.caller"),
|
|
69441
69052
|
receiver: Symbol.for("cordis.receiver"),
|
|
69442
69053
|
original: Symbol.for("cordis.original"),
|
|
69443
69054
|
metadata: Symbol.for("cordis.metadata"),
|
|
@@ -69512,11 +69123,12 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69512
69123
|
writable: false
|
|
69513
69124
|
}));
|
|
69514
69125
|
}
|
|
69515
|
-
function createShadow(
|
|
69126
|
+
function createShadow(useSite, target, property, receiver) {
|
|
69516
69127
|
if (!property) return receiver;
|
|
69517
|
-
const
|
|
69518
|
-
if (!
|
|
69519
|
-
|
|
69128
|
+
const value = getPropertyDescriptor(target, property)?.value;
|
|
69129
|
+
if (!value) return receiver;
|
|
69130
|
+
const defSite = value[symbols.shadow] ?? value;
|
|
69131
|
+
return withProp(receiver, property, useSite.extend({ [symbols.shadow]: defSite }));
|
|
69520
69132
|
}
|
|
69521
69133
|
function createShadowMethod(ctx, value, outer, shadow) {
|
|
69522
69134
|
return new Proxy(value, { apply: (target, thisArg, args) => {
|
|
@@ -69525,37 +69137,40 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69525
69137
|
} });
|
|
69526
69138
|
}
|
|
69527
69139
|
function createTraceable(ctx, value, tracker) {
|
|
69528
|
-
|
|
69140
|
+
const defSite = ctx[symbols.shadow] ?? ctx;
|
|
69141
|
+
const useSite = ctx[symbols.shadow] ? Object.getPrototypeOf(ctx) : ctx;
|
|
69529
69142
|
const proxy = new Proxy(value, {
|
|
69530
69143
|
get: (target, prop, receiver) => {
|
|
69531
69144
|
if (prop === symbols.original) return target;
|
|
69532
|
-
if (prop ===
|
|
69145
|
+
if (prop === symbols.caller) return defSite;
|
|
69146
|
+
if (prop === tracker.property) return useSite;
|
|
69533
69147
|
if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
|
|
69534
|
-
if (tracker.associate &&
|
|
69148
|
+
if (tracker.associate && useSite.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.get(ctx, `${tracker.associate}.${prop}`, withProp(ctx, symbols.receiver, receiver));
|
|
69535
69149
|
let shadow, innerValue;
|
|
69536
69150
|
const desc = getPropertyDescriptor(target, prop);
|
|
69537
69151
|
if (desc && "value" in desc) innerValue = desc.value;
|
|
69538
69152
|
else {
|
|
69539
|
-
shadow = createShadow(
|
|
69153
|
+
shadow = createShadow(useSite, target, tracker.property, receiver);
|
|
69540
69154
|
innerValue = Reflect.get(target, prop, shadow);
|
|
69541
69155
|
}
|
|
69542
69156
|
const innerTracker = innerValue?.[symbols.tracker];
|
|
69543
|
-
if (innerTracker) return createTraceable(
|
|
69157
|
+
if (innerTracker) return createTraceable(useSite, innerValue, innerTracker);
|
|
69544
69158
|
else if (!tracker.noShadow && typeof innerValue === "function") {
|
|
69545
|
-
shadow ??= createShadow(
|
|
69546
|
-
return createShadowMethod(
|
|
69159
|
+
shadow ??= createShadow(useSite, target, tracker.property, receiver);
|
|
69160
|
+
return createShadowMethod(useSite, innerValue, receiver, shadow);
|
|
69547
69161
|
} else return innerValue;
|
|
69548
69162
|
},
|
|
69549
69163
|
set: (target, prop, value, receiver) => {
|
|
69550
69164
|
if (prop === symbols.original) return false;
|
|
69165
|
+
if (prop === symbols.caller) return false;
|
|
69551
69166
|
if (prop === tracker.property) return false;
|
|
69552
69167
|
if (typeof prop === "symbol") return Reflect.set(target, prop, value, receiver);
|
|
69553
|
-
if (tracker.associate &&
|
|
69554
|
-
const shadow = createShadow(
|
|
69168
|
+
if (tracker.associate && useSite.reflect.props[`${tracker.associate}.${prop}`]) return Reflect.set(ctx, `${tracker.associate}.${prop}`, value, withProp(ctx, symbols.receiver, receiver));
|
|
69169
|
+
const shadow = createShadow(useSite, target, tracker.property, receiver);
|
|
69555
69170
|
return Reflect.set(target, prop, value, shadow);
|
|
69556
69171
|
},
|
|
69557
69172
|
apply: (target, thisArg, args) => {
|
|
69558
|
-
return applyTraceable(proxy, target, thisArg, args);
|
|
69173
|
+
return applyTraceable(tracker.noShadow ? proxy : createShadow(useSite, target, tracker.property, proxy), target, thisArg, args);
|
|
69559
69174
|
}
|
|
69560
69175
|
});
|
|
69561
69176
|
return proxy;
|
|
@@ -69567,7 +69182,8 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69567
69182
|
/** Create a callable service object that dispatches through `symbols.invoke`. */
|
|
69568
69183
|
function createCallable(name, proto, tracker) {
|
|
69569
69184
|
const self = function(...args) {
|
|
69570
|
-
|
|
69185
|
+
const proxy = createTraceable(self["ctx"], self, tracker);
|
|
69186
|
+
return Reflect.apply(proxy, this, args);
|
|
69571
69187
|
};
|
|
69572
69188
|
defineProperty(self, "name", name);
|
|
69573
69189
|
return Object.setPrototypeOf(self, proto);
|
|
@@ -69612,204 +69228,775 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69612
69228
|
const outerError = /* @__PURE__ */ new Error();
|
|
69613
69229
|
return () => outerError.stack.split("\n").slice(3 + offset);
|
|
69614
69230
|
}
|
|
69615
|
-
|
|
69616
|
-
|
|
69617
|
-
|
|
69618
|
-
|
|
69619
|
-
* @returns `true` unless `value` is `null`, `false`, or `undefined`.
|
|
69620
|
-
*/
|
|
69621
|
-
function isBailed(value) {
|
|
69622
|
-
return value !== null && value !== false && value !== void 0;
|
|
69623
|
-
}
|
|
69624
|
-
/**
|
|
69625
|
-
* Event bus installed as `ctx.events` and mixed into every context.
|
|
69626
|
-
*
|
|
69627
|
-
* The service supports concurrent, synchronous, serial, bail, and waterfall
|
|
69628
|
-
* dispatch and automatically disposes listeners with their owning fiber.
|
|
69629
|
-
*/
|
|
69630
|
-
var EventsService = class {
|
|
69631
|
-
ctx;
|
|
69632
|
-
_hooks = {};
|
|
69633
|
-
constructor(ctx) {
|
|
69634
|
-
this.ctx = ctx;
|
|
69635
|
-
defineProperty(this, symbols.tracker, {
|
|
69636
|
-
property: "ctx",
|
|
69637
|
-
noShadow: true
|
|
69638
|
-
});
|
|
69639
|
-
this.on("internal/listener", function(name, listener, options) {
|
|
69640
|
-
if (name === "internal/update" && !options.global) return (this.fiber._hooks["internal/update"] ??= new DisposableList())[options.prepend ? "unshift" : "push"](listener);
|
|
69641
|
-
});
|
|
69642
|
-
this.on("internal/update", function(config, noSave, next) {
|
|
69643
|
-
const cbs = [...this._hooks["internal/update"] || []];
|
|
69644
|
-
const _next = () => {
|
|
69645
|
-
return (cbs.shift() ?? next).call(this, config, noSave, _next);
|
|
69646
|
-
};
|
|
69647
|
-
return _next();
|
|
69648
|
-
}, {
|
|
69649
|
-
global: true,
|
|
69650
|
-
prepend: true
|
|
69651
|
-
});
|
|
69652
|
-
}
|
|
69653
|
-
/**
|
|
69654
|
-
* Resolve listeners for one dispatch and apply context filtering.
|
|
69655
|
-
*
|
|
69656
|
-
* @param type — the dispatch mode, reported on `internal/dispatch`.
|
|
69657
|
-
* @param args — the raw dispatch arguments; consumed up to the event name.
|
|
69658
|
-
* @returns the matching listener callbacks, bound to the dispatch `this`.
|
|
69659
|
-
*/
|
|
69660
|
-
dispatch(type, args) {
|
|
69661
|
-
const thisArg = typeof args[0] === "object" || typeof args[0] === "function" ? args.shift() : null;
|
|
69662
|
-
const name = args.shift();
|
|
69663
|
-
if (!name.startsWith("internal/")) this.emit("internal/dispatch", type, name, args, thisArg);
|
|
69664
|
-
const filter = thisArg?.[Context.filter];
|
|
69665
|
-
return (this._hooks[name] || []).filter((hook) => hook.global || !filter || filter.call(thisArg, hook.ctx)).map((hook) => hook.callback.bind(thisArg));
|
|
69666
|
-
}
|
|
69231
|
+
const kValidationError = Symbol.for("ValidationError");
|
|
69232
|
+
/** Error raised when plugin configuration fails standard-schema validation. */
|
|
69233
|
+
var ValidationError = class extends TypeError {
|
|
69234
|
+
name = "ValidationError";
|
|
69667
69235
|
/**
|
|
69668
|
-
*
|
|
69236
|
+
* Build the aggregated message from schema issues.
|
|
69669
69237
|
*
|
|
69670
|
-
* @param
|
|
69671
|
-
* @returns a promise resolving once every listener has settled.
|
|
69238
|
+
* @param issues — the standard-schema issues, one message line each.
|
|
69672
69239
|
*/
|
|
69673
|
-
|
|
69674
|
-
|
|
69675
|
-
|
|
69240
|
+
constructor(issues) {
|
|
69241
|
+
super(`invalid config:\n` + issues.map((issue) => {
|
|
69242
|
+
if (issue.path) return ` - ${issue.message} (at ${issue.path.join(".")})`;
|
|
69243
|
+
else return ` - ${issue.message}`;
|
|
69244
|
+
}).join("\n"));
|
|
69676
69245
|
}
|
|
69677
|
-
|
|
69678
|
-
|
|
69679
|
-
|
|
69680
|
-
|
|
69681
|
-
|
|
69682
|
-
|
|
69683
|
-
|
|
69246
|
+
};
|
|
69247
|
+
Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
|
|
69248
|
+
/**
|
|
69249
|
+
* Validate and normalize config for a plugin runtime before it starts.
|
|
69250
|
+
*
|
|
69251
|
+
* @param runtime — the plugin runtime whose `Config` schema to apply.
|
|
69252
|
+
* @param config — the raw user config.
|
|
69253
|
+
* @returns the validated config, or `config` unchanged if the runtime has no schema.
|
|
69254
|
+
* @throws {ValidationError} when validation reports issues.
|
|
69255
|
+
*/
|
|
69256
|
+
function resolveConfig(runtime, config) {
|
|
69257
|
+
if (!runtime.Config) return config;
|
|
69258
|
+
const result = runtime.Config["~standard"].validate(config);
|
|
69259
|
+
if ("then" in result) throw new TypeError("Async config validation is not supported");
|
|
69260
|
+
if (result.issues) throw new ValidationError(result.issues);
|
|
69261
|
+
else return result.value;
|
|
69262
|
+
}
|
|
69263
|
+
const effectInertia = /* @__PURE__ */ new WeakMap();
|
|
69264
|
+
function runDisposable(dispose) {
|
|
69265
|
+
const result = dispose();
|
|
69266
|
+
return effectInertia.get(dispose)?.() ?? result;
|
|
69267
|
+
}
|
|
69268
|
+
/** Notify plugin teardown without allowing one observer to break ownership cleanup. */
|
|
69269
|
+
function emitPluginDisposed(context, fiber) {
|
|
69270
|
+
const args = ["internal/plugin", fiber];
|
|
69271
|
+
let callbacks;
|
|
69272
|
+
try {
|
|
69273
|
+
callbacks = context.events.dispatch("emit", args);
|
|
69274
|
+
} catch (error) {
|
|
69275
|
+
context.logger.error(error);
|
|
69276
|
+
return;
|
|
69684
69277
|
}
|
|
69685
|
-
|
|
69686
|
-
|
|
69687
|
-
|
|
69688
|
-
|
|
69689
|
-
|
|
69690
|
-
*/
|
|
69691
|
-
async serial(...args) {
|
|
69692
|
-
for (const cb of this.dispatch("serial", args)) {
|
|
69693
|
-
const result = await cb(...args);
|
|
69694
|
-
if (isBailed(result)) return result;
|
|
69695
|
-
}
|
|
69278
|
+
for (const callback of callbacks) try {
|
|
69279
|
+
const returned = callback(...args);
|
|
69280
|
+
Promise.resolve(returned).catch((error) => context.logger.error(error));
|
|
69281
|
+
} catch (error) {
|
|
69282
|
+
context.logger.error(error);
|
|
69696
69283
|
}
|
|
69284
|
+
}
|
|
69285
|
+
/** Framework error with a stable machine-readable code. */
|
|
69286
|
+
var CordisError = class CordisError extends Error {
|
|
69287
|
+
code;
|
|
69697
69288
|
/**
|
|
69698
|
-
*
|
|
69699
|
-
*
|
|
69700
|
-
* @param args — optional `this`, the event name, then listener arguments.
|
|
69701
|
-
* @returns the first bail value (see {@link isBailed}), if any.
|
|
69289
|
+
* @param code — the stable error code; also the default message.
|
|
69290
|
+
* @param message — optional human-readable override.
|
|
69702
69291
|
*/
|
|
69703
|
-
|
|
69704
|
-
|
|
69705
|
-
|
|
69706
|
-
if (isBailed(result)) return result;
|
|
69707
|
-
}
|
|
69292
|
+
constructor(code, message) {
|
|
69293
|
+
super(message ?? CordisError.Code[code]);
|
|
69294
|
+
this.code = code;
|
|
69708
69295
|
}
|
|
69296
|
+
};
|
|
69297
|
+
/** Cordis error code definitions. */
|
|
69298
|
+
(function(CordisError) {
|
|
69299
|
+
CordisError.Code = { INACTIVE_EFFECT: "cannot create effect on inactive context" };
|
|
69300
|
+
})(CordisError || (CordisError = {}));
|
|
69301
|
+
const INACTIVE = "__INACTIVE__";
|
|
69302
|
+
/**
|
|
69303
|
+
* Runtime instance of one plugin application.
|
|
69304
|
+
*
|
|
69305
|
+
* A fiber tracks dependency state, raw and effective config, lifecycle effects, and
|
|
69306
|
+
* cleanup for the plugin context returned by `ctx.plugin()`.
|
|
69307
|
+
*/
|
|
69308
|
+
var Fiber = class {
|
|
69309
|
+
parent;
|
|
69310
|
+
inject;
|
|
69311
|
+
runtime;
|
|
69312
|
+
/** Unique id within the registry; 0 for the root fiber, `null` once disposed. */
|
|
69313
|
+
uid;
|
|
69314
|
+
/** The context this fiber's plugin runs in (extends the parent context). */
|
|
69315
|
+
ctx;
|
|
69316
|
+
/** Raw plugin input retained for the next activation. */
|
|
69317
|
+
config;
|
|
69318
|
+
/** Current lifecycle state; transitions emit `internal/status`. */
|
|
69319
|
+
state = 0;
|
|
69320
|
+
/** Dispose this fiber: unload the plugin, then settle once cleanup finished. */
|
|
69321
|
+
dispose;
|
|
69322
|
+
/** Required implementations retained through dependent teardown. */
|
|
69323
|
+
committed;
|
|
69324
|
+
/** Service implementations owned by this fiber, including isolated provisions. */
|
|
69325
|
+
provisions = /* @__PURE__ */ new Set();
|
|
69326
|
+
/** The in-flight load/unload transition, if one is currently running. */
|
|
69327
|
+
inertia;
|
|
69328
|
+
_hooks = Object.create(null);
|
|
69329
|
+
_disposables = new DisposableList();
|
|
69330
|
+
context;
|
|
69331
|
+
_error;
|
|
69332
|
+
_revision = 0;
|
|
69333
|
+
_configRevision = 0;
|
|
69334
|
+
_effectiveConfig;
|
|
69335
|
+
_runner;
|
|
69336
|
+
_store = Object.create(null);
|
|
69337
|
+
_release;
|
|
69709
69338
|
/**
|
|
69710
|
-
*
|
|
69711
|
-
*
|
|
69712
|
-
* The last dispatch argument is treated as the innermost `next`. Listeners
|
|
69713
|
-
* run outermost-first; a listener that does not call `next()` vetoes the
|
|
69714
|
-
* rest of the chain, including the built-in behavior.
|
|
69339
|
+
* Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()`
|
|
69340
|
+
* rather than constructing them directly.
|
|
69715
69341
|
*
|
|
69716
|
-
* @param
|
|
69717
|
-
* @
|
|
69342
|
+
* @param parent — the context the plugin was loaded from.
|
|
69343
|
+
* @param config — raw config, validated against the runtime's schema.
|
|
69344
|
+
* @param inject — resolved dependency map (service name → intercept config).
|
|
69345
|
+
* @param runtime — the shared plugin runtime, or `null` for the root fiber.
|
|
69346
|
+
* @param getOuterStack — captures the caller stack for effect diagnostics.
|
|
69718
69347
|
*/
|
|
69719
|
-
|
|
69720
|
-
|
|
69721
|
-
|
|
69722
|
-
|
|
69723
|
-
|
|
69348
|
+
constructor(parent, config, inject, runtime, getOuterStack) {
|
|
69349
|
+
this.parent = parent;
|
|
69350
|
+
this.inject = inject;
|
|
69351
|
+
this.runtime = runtime;
|
|
69352
|
+
this.config = config;
|
|
69353
|
+
const collect = (dispose) => {
|
|
69354
|
+
this._disposables.push(dispose);
|
|
69724
69355
|
};
|
|
69725
|
-
|
|
69726
|
-
|
|
69727
|
-
|
|
69728
|
-
|
|
69729
|
-
|
|
69730
|
-
|
|
69731
|
-
|
|
69732
|
-
|
|
69733
|
-
|
|
69734
|
-
|
|
69735
|
-
|
|
69736
|
-
|
|
69737
|
-
|
|
69738
|
-
|
|
69739
|
-
|
|
69740
|
-
|
|
69741
|
-
|
|
69742
|
-
|
|
69743
|
-
|
|
69744
|
-
|
|
69745
|
-
|
|
69746
|
-
|
|
69747
|
-
|
|
69748
|
-
|
|
69749
|
-
|
|
69750
|
-
|
|
69751
|
-
|
|
69752
|
-
|
|
69753
|
-
|
|
69754
|
-
|
|
69755
|
-
|
|
69756
|
-
|
|
69757
|
-
|
|
69758
|
-
|
|
69759
|
-
|
|
69356
|
+
if (runtime) {
|
|
69357
|
+
this.uid = parent.registry.counter;
|
|
69358
|
+
this.ctx = this.context = parent.extend({ fiber: this });
|
|
69359
|
+
const injectEntries = Object.entries(this.inject);
|
|
69360
|
+
if (injectEntries.length) {
|
|
69361
|
+
this.ctx[Context.intercept] = Object.create(parent[Context.intercept]);
|
|
69362
|
+
for (const [name, config] of injectEntries) {
|
|
69363
|
+
if (isNullable(config)) continue;
|
|
69364
|
+
this.ctx[Context.intercept][name] = config;
|
|
69365
|
+
}
|
|
69366
|
+
}
|
|
69367
|
+
this._runner = {
|
|
69368
|
+
epoch: INACTIVE,
|
|
69369
|
+
getOuterStack,
|
|
69370
|
+
execute: function() {
|
|
69371
|
+
const config = this.resolveConfig(this.config);
|
|
69372
|
+
this._effectiveConfig = config;
|
|
69373
|
+
if (isConstructor(runtime.callback)) {
|
|
69374
|
+
const instance = new runtime.callback(this.ctx, config);
|
|
69375
|
+
for (const hook of instance?.[symbols.initHooks] ?? []) hook();
|
|
69376
|
+
return instance?.[symbols.init]?.();
|
|
69377
|
+
} else return runtime.callback(this.ctx, config);
|
|
69378
|
+
},
|
|
69379
|
+
collect
|
|
69380
|
+
};
|
|
69381
|
+
this.dispose = parent.fiber.effect(() => {
|
|
69382
|
+
const remove = runtime.fibers.push(this);
|
|
69383
|
+
return async () => {
|
|
69384
|
+
this.uid = null;
|
|
69385
|
+
emitPluginDisposed(this.context, this);
|
|
69386
|
+
if (this.ctx.registry.has(runtime.callback)) {
|
|
69387
|
+
remove();
|
|
69388
|
+
if (!runtime.fibers.length) this.ctx.registry.delete(runtime.callback);
|
|
69389
|
+
}
|
|
69390
|
+
this._setEpoch(INACTIVE);
|
|
69391
|
+
if (!this.inertia) this._updateState(() => {
|
|
69392
|
+
this.inertia = this._unload();
|
|
69393
|
+
return 5;
|
|
69394
|
+
});
|
|
69395
|
+
while (this.inertia) await this.inertia;
|
|
69396
|
+
};
|
|
69397
|
+
}, "ctx.plugin()");
|
|
69398
|
+
try {
|
|
69399
|
+
this.context.emit("internal/plugin", this);
|
|
69400
|
+
} catch (error) {
|
|
69401
|
+
Promise.resolve(this.dispose()).catch((reason) => this.ctx.logger.error(reason));
|
|
69402
|
+
throw error;
|
|
69403
|
+
}
|
|
69404
|
+
if (this.uid !== null && parent.fiber.state !== 5) {
|
|
69405
|
+
for (const name of Object.keys(this.inject)) this._checkImpl(name);
|
|
69406
|
+
this._refresh();
|
|
69407
|
+
}
|
|
69408
|
+
} else {
|
|
69409
|
+
this.uid = 0;
|
|
69410
|
+
this.ctx = this.context = parent;
|
|
69411
|
+
this.state = 2;
|
|
69412
|
+
this.committed = Object.create(null);
|
|
69413
|
+
this._runner = {
|
|
69414
|
+
epoch: "0",
|
|
69415
|
+
getOuterStack,
|
|
69416
|
+
execute: () => {},
|
|
69417
|
+
collect
|
|
69418
|
+
};
|
|
69419
|
+
this.dispose = () => this.restart();
|
|
69760
69420
|
}
|
|
69761
69421
|
}
|
|
69762
|
-
/**
|
|
69763
|
-
|
|
69764
|
-
|
|
69765
|
-
|
|
69766
|
-
|
|
69767
|
-
|
|
69768
|
-
|
|
69769
|
-
|
|
69770
|
-
* @param options — listener options; a boolean is shorthand for `prepend`.
|
|
69771
|
-
* @returns a disposer removing the listener; `true` if it was still registered.
|
|
69772
|
-
*/
|
|
69773
|
-
on(name, listener, options) {
|
|
69774
|
-
if (typeof options !== "object") options = { prepend: options };
|
|
69775
|
-
this.ctx.fiber.assertActive();
|
|
69776
|
-
listener = this.ctx.reflect.bind(listener);
|
|
69777
|
-
const result = this.bail(this.ctx, "internal/listener", name, listener, options);
|
|
69778
|
-
if (result) return result;
|
|
69779
|
-
const hooks = this._hooks[name] ||= [];
|
|
69780
|
-
const label = `ctx.on(${typeof name === "string" ? JSON.stringify(name) : name.toString()})`;
|
|
69781
|
-
return this.register(label, hooks, listener, options);
|
|
69422
|
+
/** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */
|
|
69423
|
+
get name() {
|
|
69424
|
+
let fiber = this;
|
|
69425
|
+
do {
|
|
69426
|
+
if (fiber.runtime?.name) return fiber.runtime.name;
|
|
69427
|
+
fiber = fiber.parent.fiber;
|
|
69428
|
+
} while (fiber !== fiber.parent.fiber);
|
|
69429
|
+
return "root";
|
|
69782
69430
|
}
|
|
69783
69431
|
/**
|
|
69784
|
-
*
|
|
69432
|
+
* Throw if the fiber has already been disposed.
|
|
69785
69433
|
*
|
|
69786
|
-
* @
|
|
69787
|
-
* @
|
|
69788
|
-
* @param options — listener options; a boolean is shorthand for `prepend`.
|
|
69789
|
-
* @returns a disposer removing the listener; `true` if it was still registered.
|
|
69434
|
+
* @returns nothing when the fiber is still active.
|
|
69435
|
+
* @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared.
|
|
69790
69436
|
*/
|
|
69791
|
-
|
|
69792
|
-
|
|
69793
|
-
|
|
69794
|
-
return listener.apply(this, args);
|
|
69795
|
-
}, options);
|
|
69796
|
-
return dispose;
|
|
69797
|
-
}
|
|
69798
|
-
};
|
|
69799
|
-
/** Built-in placeholder formatters used by `Logger.format()`. */
|
|
69800
|
-
const defaultFormatters = {
|
|
69801
|
-
s: (value) => String(value),
|
|
69802
|
-
d: (value) => Math.trunc(Number(value)),
|
|
69803
|
-
i: (value) => Math.trunc(Number(value)),
|
|
69804
|
-
f: (value) => Number(value),
|
|
69805
|
-
o: (value) => JSON.stringify(value),
|
|
69806
|
-
O: (value) => JSON.stringify(value),
|
|
69807
|
-
c: () => "",
|
|
69808
|
-
C: (value, exporter, message) => {
|
|
69809
|
-
return Logger.color(exporter, Logger.code(message.name, exporter.colors), value);
|
|
69437
|
+
assertActive() {
|
|
69438
|
+
if (this.uid !== null) return;
|
|
69439
|
+
throw new CordisError("INACTIVE_EFFECT");
|
|
69810
69440
|
}
|
|
69811
|
-
|
|
69812
|
-
|
|
69441
|
+
_execute(runner) {
|
|
69442
|
+
const oldEpoch = runner.epoch;
|
|
69443
|
+
return composeError((info) => {
|
|
69444
|
+
const safeCollect = (dispose) => {
|
|
69445
|
+
if (typeof dispose === "function") runner.collect(dispose);
|
|
69446
|
+
else if (!isNullable(dispose)) throw new TypeError("Invalid effect");
|
|
69447
|
+
};
|
|
69448
|
+
const effect = runner.execute.call(this);
|
|
69449
|
+
if (typeof effect === "function") return runner.collect(effect);
|
|
69450
|
+
else if (isNullable(effect)) {} else if (!isObject$1(effect)) throw new TypeError("Invalid effect");
|
|
69451
|
+
else if ("then" in effect) return effect.then(safeCollect);
|
|
69452
|
+
else if (Symbol.iterator in effect) {
|
|
69453
|
+
info.error = /* @__PURE__ */ new Error();
|
|
69454
|
+
const iter = effect[Symbol.iterator]();
|
|
69455
|
+
while (true) {
|
|
69456
|
+
const result = iter.next();
|
|
69457
|
+
safeCollect(result.value);
|
|
69458
|
+
if (result.done) return;
|
|
69459
|
+
}
|
|
69460
|
+
} else if (Symbol.asyncIterator in effect) {
|
|
69461
|
+
const iter = effect[Symbol.asyncIterator]();
|
|
69462
|
+
return (async () => {
|
|
69463
|
+
await Promise.resolve();
|
|
69464
|
+
info.error = /* @__PURE__ */ new Error();
|
|
69465
|
+
while (true) {
|
|
69466
|
+
if (runner.epoch !== oldEpoch) return;
|
|
69467
|
+
const result = await iter.next();
|
|
69468
|
+
safeCollect(result.value);
|
|
69469
|
+
if (result.done) return;
|
|
69470
|
+
}
|
|
69471
|
+
})();
|
|
69472
|
+
} else throw new TypeError("Invalid effect");
|
|
69473
|
+
}, runner.getOuterStack);
|
|
69474
|
+
}
|
|
69475
|
+
effect(execute, label = "anonymous") {
|
|
69476
|
+
this.assertActive();
|
|
69477
|
+
if (this.state === 5) throw new CordisError("INACTIVE_EFFECT");
|
|
69478
|
+
const disposables = [];
|
|
69479
|
+
let disposing = false;
|
|
69480
|
+
let disposalTask;
|
|
69481
|
+
const dispose = () => {
|
|
69482
|
+
if (disposing) return disposalTask;
|
|
69483
|
+
disposing = true;
|
|
69484
|
+
let task;
|
|
69485
|
+
for (const disposable of disposables.splice(0).reverse()) if (task) task = task.then(() => runDisposable(disposable));
|
|
69486
|
+
else {
|
|
69487
|
+
const result = runDisposable(disposable);
|
|
69488
|
+
if (isObject$1(result) && "then" in result) task = result;
|
|
69489
|
+
}
|
|
69490
|
+
return disposalTask = task;
|
|
69491
|
+
};
|
|
69492
|
+
const meta = {
|
|
69493
|
+
label,
|
|
69494
|
+
children: []
|
|
69495
|
+
};
|
|
69496
|
+
const runner = {
|
|
69497
|
+
execute,
|
|
69498
|
+
epoch: true,
|
|
69499
|
+
collect: (dispose) => {
|
|
69500
|
+
disposables.push(dispose);
|
|
69501
|
+
this._disposables.delete(dispose);
|
|
69502
|
+
if (dispose[symbols.effect]) meta.children.push(dispose[symbols.effect]);
|
|
69503
|
+
},
|
|
69504
|
+
getOuterStack: buildOuterStack()
|
|
69505
|
+
};
|
|
69506
|
+
let task;
|
|
69507
|
+
let executing = true;
|
|
69508
|
+
let resolveSetup;
|
|
69509
|
+
let rejectSetup;
|
|
69510
|
+
let setupBarrier;
|
|
69511
|
+
let setupFailed = false;
|
|
69512
|
+
let inFlight;
|
|
69513
|
+
let removeWrapper = () => false;
|
|
69514
|
+
const waitForSetup = () => {
|
|
69515
|
+
setupBarrier ??= new Promise((resolve, reject) => {
|
|
69516
|
+
resolveSetup = resolve;
|
|
69517
|
+
rejectSetup = reject;
|
|
69518
|
+
});
|
|
69519
|
+
return setupBarrier;
|
|
69520
|
+
};
|
|
69521
|
+
const disposeAfter = (setup) => {
|
|
69522
|
+
return Promise.resolve(setup).then(() => dispose(), async (reason) => {
|
|
69523
|
+
await dispose();
|
|
69524
|
+
throw reason;
|
|
69525
|
+
});
|
|
69526
|
+
};
|
|
69527
|
+
const finalizeDisposal = (callback) => {
|
|
69528
|
+
let result;
|
|
69529
|
+
try {
|
|
69530
|
+
result = callback();
|
|
69531
|
+
} catch (error) {
|
|
69532
|
+
removeWrapper();
|
|
69533
|
+
throw error;
|
|
69534
|
+
}
|
|
69535
|
+
if (isObject$1(result) && "then" in result) {
|
|
69536
|
+
const pending = Promise.resolve(result).finally(() => {
|
|
69537
|
+
removeWrapper();
|
|
69538
|
+
if (inFlight === pending) inFlight = void 0;
|
|
69539
|
+
});
|
|
69540
|
+
return inFlight = pending;
|
|
69541
|
+
}
|
|
69542
|
+
removeWrapper();
|
|
69543
|
+
return result;
|
|
69544
|
+
};
|
|
69545
|
+
const wrapper = defineProperty(() => {
|
|
69546
|
+
if (!runner.epoch) return setupFailed ? inFlight : void 0;
|
|
69547
|
+
runner.epoch = false;
|
|
69548
|
+
return finalizeDisposal(() => {
|
|
69549
|
+
if (executing) return disposeAfter(waitForSetup());
|
|
69550
|
+
return task ? disposeAfter(task) : dispose();
|
|
69551
|
+
});
|
|
69552
|
+
}, symbols.effect, meta);
|
|
69553
|
+
effectInertia.set(wrapper, () => inFlight);
|
|
69554
|
+
removeWrapper = this._disposables.push(wrapper);
|
|
69555
|
+
try {
|
|
69556
|
+
task = this._execute(runner);
|
|
69557
|
+
} catch (reason) {
|
|
69558
|
+
executing = false;
|
|
69559
|
+
setupFailed = true;
|
|
69560
|
+
runner.epoch = false;
|
|
69561
|
+
let cleanup;
|
|
69562
|
+
try {
|
|
69563
|
+
cleanup = finalizeDisposal(dispose);
|
|
69564
|
+
} finally {
|
|
69565
|
+
rejectSetup?.(reason);
|
|
69566
|
+
}
|
|
69567
|
+
if (isObject$1(cleanup) && "then" in cleanup) cleanup.catch((error) => this.ctx.logger.error(error));
|
|
69568
|
+
throw reason;
|
|
69569
|
+
}
|
|
69570
|
+
executing = false;
|
|
69571
|
+
if (setupBarrier) Promise.resolve(task).then(resolveSetup, rejectSetup);
|
|
69572
|
+
task?.catch(() => {
|
|
69573
|
+
if (!runner.epoch) return dispose();
|
|
69574
|
+
return finalizeDisposal(dispose);
|
|
69575
|
+
}).catch((error) => this.ctx.logger.error(error));
|
|
69576
|
+
const disposeAsync = () => {
|
|
69577
|
+
if (!runner.epoch) return;
|
|
69578
|
+
runner.epoch = false;
|
|
69579
|
+
return finalizeDisposal(dispose);
|
|
69580
|
+
};
|
|
69581
|
+
wrapper.then = async (onFulfilled, onRejected) => {
|
|
69582
|
+
return Promise.resolve(task).then(() => disposeAsync).then(onFulfilled, onRejected);
|
|
69583
|
+
};
|
|
69584
|
+
return wrapper;
|
|
69585
|
+
}
|
|
69586
|
+
/**
|
|
69587
|
+
* Return metadata for currently registered effects.
|
|
69588
|
+
*
|
|
69589
|
+
* @returns one {@link EffectMeta} tree per labeled live effect.
|
|
69590
|
+
*/
|
|
69591
|
+
getEffects() {
|
|
69592
|
+
return [...this._disposables].map((dispose) => dispose[symbols.effect]).filter(Boolean);
|
|
69593
|
+
}
|
|
69594
|
+
_getState() {
|
|
69595
|
+
if (this.uid === null) return 4;
|
|
69596
|
+
if (this._error) return 3;
|
|
69597
|
+
if (this._runner.epoch !== INACTIVE) return 2;
|
|
69598
|
+
return 0;
|
|
69599
|
+
}
|
|
69600
|
+
_updateState(callback) {
|
|
69601
|
+
const oldState = this.state;
|
|
69602
|
+
this.state = callback() ?? this._getState();
|
|
69603
|
+
if (oldState === this.state) return;
|
|
69604
|
+
this.context.emit("internal/status", this, oldState);
|
|
69605
|
+
if (oldState !== 2 && this.state !== 2) return;
|
|
69606
|
+
for (const key of Reflect.ownKeys(this.ctx.reflect.store)) {
|
|
69607
|
+
const impl = this.ctx.reflect.store[key];
|
|
69608
|
+
if (impl.ctx.fiber !== this) continue;
|
|
69609
|
+
this.ctx.isolate(impl.name, impl.isolate).reflect.notify([impl.name]);
|
|
69610
|
+
}
|
|
69611
|
+
}
|
|
69612
|
+
_checkImpl(name) {
|
|
69613
|
+
const impl = this.ctx.reflect._getImpl(name, true);
|
|
69614
|
+
if (!impl) return delete this._store[name];
|
|
69615
|
+
try {
|
|
69616
|
+
if (impl.check && !impl.check.call(getTraceable(this.ctx, impl.value))) return delete this._store[name];
|
|
69617
|
+
} catch (error) {
|
|
69618
|
+
impl.ctx.logger.error(error);
|
|
69619
|
+
return delete this._store[name];
|
|
69620
|
+
}
|
|
69621
|
+
this._store[name] = impl;
|
|
69622
|
+
}
|
|
69623
|
+
_refresh() {
|
|
69624
|
+
let epoch = `${this._revision}`;
|
|
69625
|
+
for (const name of Object.keys(this.inject)) {
|
|
69626
|
+
const impl = this._store[name];
|
|
69627
|
+
if (!impl) {
|
|
69628
|
+
epoch = INACTIVE;
|
|
69629
|
+
break;
|
|
69630
|
+
}
|
|
69631
|
+
epoch += ":" + impl.uid;
|
|
69632
|
+
}
|
|
69633
|
+
this._setEpoch(epoch);
|
|
69634
|
+
}
|
|
69635
|
+
_setEpoch(epoch) {
|
|
69636
|
+
const oldEpoch = this._runner.epoch;
|
|
69637
|
+
if (epoch === oldEpoch) return;
|
|
69638
|
+
if (this._error) return;
|
|
69639
|
+
this._runner.epoch = epoch;
|
|
69640
|
+
if (this.inertia) return;
|
|
69641
|
+
this._updateState(() => {
|
|
69642
|
+
if (epoch !== INACTIVE && oldEpoch === INACTIVE) {
|
|
69643
|
+
this.inertia = this._reload();
|
|
69644
|
+
return 1;
|
|
69645
|
+
} else {
|
|
69646
|
+
this.inertia = this._unload();
|
|
69647
|
+
return 5;
|
|
69648
|
+
}
|
|
69649
|
+
});
|
|
69650
|
+
}
|
|
69651
|
+
/** Raw input retained for the next activation, without evaluating expressions or validating it. */
|
|
69652
|
+
get rawConfig() {
|
|
69653
|
+
return this.ctx.fiber.config;
|
|
69654
|
+
}
|
|
69655
|
+
/** Retain raw input without changing the running config or triggering an update. */
|
|
69656
|
+
set rawConfig(config) {
|
|
69657
|
+
this.ctx.fiber.config = config;
|
|
69658
|
+
this.ctx.fiber._configRevision++;
|
|
69659
|
+
}
|
|
69660
|
+
/**
|
|
69661
|
+
* The object passed to plugin activation or the latest successful update that retained the instance.
|
|
69662
|
+
* Candidate resolution does not publish it; volatile updates retain its references.
|
|
69663
|
+
* Undefined before activation and readable after unload; callers requiring a live instance check `state`.
|
|
69664
|
+
*/
|
|
69665
|
+
get effectiveConfig() {
|
|
69666
|
+
return this.ctx.fiber._effectiveConfig;
|
|
69667
|
+
}
|
|
69668
|
+
/**
|
|
69669
|
+
* Evaluate and validate a candidate using this fiber's `internal/config` hooks and runtime schema.
|
|
69670
|
+
* Does not publish the result, replace raw input, or commit running volatile references.
|
|
69671
|
+
* Required injections must be available when a hook uses them.
|
|
69672
|
+
* @param config Raw candidate input.
|
|
69673
|
+
* @returns The candidate's resolved config, retaining the schema's result identity.
|
|
69674
|
+
* @throws {ValidationError} when the runtime schema rejects the candidate; hook errors propagate.
|
|
69675
|
+
*/
|
|
69676
|
+
resolveConfig(config) {
|
|
69677
|
+
const fiber = this.ctx.fiber;
|
|
69678
|
+
return fiber.context.waterfall("internal/config", fiber, () => config);
|
|
69679
|
+
}
|
|
69680
|
+
async _reload() {
|
|
69681
|
+
this.committed = { ...this._store };
|
|
69682
|
+
for (const impl of Object.values(this.committed)) {
|
|
69683
|
+
if (impl.ctx.fiber === this) continue;
|
|
69684
|
+
impl.dependents.add(this);
|
|
69685
|
+
}
|
|
69686
|
+
const oldEpoch = this._runner.epoch;
|
|
69687
|
+
try {
|
|
69688
|
+
await Promise.resolve();
|
|
69689
|
+
if (this._runner.epoch === oldEpoch) await this._execute(this._runner);
|
|
69690
|
+
} catch (reason) {
|
|
69691
|
+
this.ctx.logger.error(reason);
|
|
69692
|
+
if (this._runner.epoch === oldEpoch) {
|
|
69693
|
+
this._error = reason;
|
|
69694
|
+
this._runner.epoch = INACTIVE;
|
|
69695
|
+
}
|
|
69696
|
+
}
|
|
69697
|
+
this._updateState(() => {
|
|
69698
|
+
if (this._runner.epoch === oldEpoch) this.inertia = void 0;
|
|
69699
|
+
else {
|
|
69700
|
+
this.inertia = this._unload();
|
|
69701
|
+
return 5;
|
|
69702
|
+
}
|
|
69703
|
+
});
|
|
69704
|
+
}
|
|
69705
|
+
async _unload() {
|
|
69706
|
+
while ([...this.provisions].some((impl) => impl.dependents.size)) await new Promise((resolve) => this._release = resolve);
|
|
69707
|
+
this._release = void 0;
|
|
69708
|
+
await Promise.all(this._disposables.clear().map(async (dispose) => {
|
|
69709
|
+
try {
|
|
69710
|
+
await composeError(async (info) => {
|
|
69711
|
+
await Promise.resolve();
|
|
69712
|
+
info.error = /* @__PURE__ */ new Error();
|
|
69713
|
+
await runDisposable(dispose);
|
|
69714
|
+
}, this._runner.getOuterStack);
|
|
69715
|
+
} catch (reason) {
|
|
69716
|
+
this.ctx.logger.error(reason);
|
|
69717
|
+
}
|
|
69718
|
+
}));
|
|
69719
|
+
for (const impl of Object.values(this.committed ?? {})) {
|
|
69720
|
+
if (!impl.dependents.delete(this) || impl.dependents.size) continue;
|
|
69721
|
+
impl.release?.();
|
|
69722
|
+
impl.ctx.fiber._release?.();
|
|
69723
|
+
}
|
|
69724
|
+
this.committed = void 0;
|
|
69725
|
+
this._updateState(() => {
|
|
69726
|
+
if (this._runner.epoch === INACTIVE) this.inertia = void 0;
|
|
69727
|
+
else {
|
|
69728
|
+
this.inertia = this._reload();
|
|
69729
|
+
return 1;
|
|
69730
|
+
}
|
|
69731
|
+
});
|
|
69732
|
+
}
|
|
69733
|
+
/**
|
|
69734
|
+
* Wait for current lifecycle work and rethrow startup errors.
|
|
69735
|
+
*
|
|
69736
|
+
* @returns this fiber, once it has settled into a stable state.
|
|
69737
|
+
* @throws the config-validation or plugin-startup error, if any.
|
|
69738
|
+
*/
|
|
69739
|
+
async await() {
|
|
69740
|
+
while (this.inertia) await this.inertia;
|
|
69741
|
+
if (this._error) throw this._error;
|
|
69742
|
+
return this;
|
|
69743
|
+
}
|
|
69744
|
+
/**
|
|
69745
|
+
* Dispose and immediately reload this plugin with its current config.
|
|
69746
|
+
*
|
|
69747
|
+
* @returns a promise resolving once the reload settled.
|
|
69748
|
+
* @throws {CordisError} `INACTIVE_EFFECT` when the fiber is already disposed.
|
|
69749
|
+
*/
|
|
69750
|
+
async restart() {
|
|
69751
|
+
const fiber = this.ctx.fiber;
|
|
69752
|
+
fiber.assertActive();
|
|
69753
|
+
fiber._revision++;
|
|
69754
|
+
fiber._refresh();
|
|
69755
|
+
await fiber.await();
|
|
69756
|
+
}
|
|
69757
|
+
/**
|
|
69758
|
+
* Resolve a candidate, retain its raw config and apply it through the update waterfall.
|
|
69759
|
+
* @param config Raw config; pending fibers defer resolution until activation.
|
|
69760
|
+
* @param noSave Suppress the persistence notification when true.
|
|
69761
|
+
* @returns The awaited update/restart result, or undefined when a synchronous listener handles it.
|
|
69762
|
+
* @throws {ValidationError} when an active fiber's candidate is invalid.
|
|
69763
|
+
*/
|
|
69764
|
+
update(config, noSave = false) {
|
|
69765
|
+
const fiber = this.ctx.fiber;
|
|
69766
|
+
fiber.assertActive();
|
|
69767
|
+
const loaded = fiber._runner.epoch !== INACTIVE;
|
|
69768
|
+
const resolved = loaded ? fiber.resolveConfig(config) : void 0;
|
|
69769
|
+
if (!noSave) fiber.context.emit("internal/commit", fiber, config);
|
|
69770
|
+
fiber.config = config;
|
|
69771
|
+
fiber._error = void 0;
|
|
69772
|
+
const configRevision = ++fiber._configRevision;
|
|
69773
|
+
const epoch = fiber._runner.epoch;
|
|
69774
|
+
const committed = fiber.committed;
|
|
69775
|
+
let restarted = false;
|
|
69776
|
+
const restart = () => {
|
|
69777
|
+
restarted = true;
|
|
69778
|
+
return fiber.restart();
|
|
69779
|
+
};
|
|
69780
|
+
const publish = () => {
|
|
69781
|
+
if (!restarted && fiber.uid !== null && fiber._configRevision === configRevision && fiber._runner.epoch === epoch && fiber.committed === committed) fiber._effectiveConfig = resolved;
|
|
69782
|
+
};
|
|
69783
|
+
const result = loaded ? fiber.context.waterfall(fiber, "internal/update", resolved, restart) : restart();
|
|
69784
|
+
if (result === void 0) {
|
|
69785
|
+
publish();
|
|
69786
|
+
return;
|
|
69787
|
+
}
|
|
69788
|
+
const task = Promise.resolve(result).then(publish);
|
|
69789
|
+
task.catch(() => {});
|
|
69790
|
+
return task;
|
|
69791
|
+
}
|
|
69792
|
+
};
|
|
69793
|
+
/**
|
|
69794
|
+
* Return whether an event result should stop a bail-style dispatch.
|
|
69795
|
+
*
|
|
69796
|
+
* @param value — a listener's return value.
|
|
69797
|
+
* @returns `true` unless `value` is `null`, `false`, or `undefined`.
|
|
69798
|
+
*/
|
|
69799
|
+
function isBailed(value) {
|
|
69800
|
+
return value !== null && value !== false && value !== void 0;
|
|
69801
|
+
}
|
|
69802
|
+
/**
|
|
69803
|
+
* Event bus installed as `ctx.events` and mixed into every context.
|
|
69804
|
+
*
|
|
69805
|
+
* The service supports concurrent, synchronous, serial, bail, and waterfall
|
|
69806
|
+
* dispatch and automatically disposes listeners with their owning fiber.
|
|
69807
|
+
*/
|
|
69808
|
+
var EventsService = class {
|
|
69809
|
+
ctx;
|
|
69810
|
+
_hooks = Object.create(null);
|
|
69811
|
+
constructor(ctx) {
|
|
69812
|
+
this.ctx = ctx;
|
|
69813
|
+
defineProperty(this, symbols.tracker, {
|
|
69814
|
+
property: "ctx",
|
|
69815
|
+
noShadow: true
|
|
69816
|
+
});
|
|
69817
|
+
this.on("internal/listener", function(name, listener, options) {
|
|
69818
|
+
if (name === "internal/update" && !options.global) {
|
|
69819
|
+
const hooks = this.fiber._hooks["internal/update"] ??= new DisposableList();
|
|
69820
|
+
const method = options.prepend ? "unshift" : "push";
|
|
69821
|
+
return this.fiber.effect(() => hooks[method](listener), "ctx.on(\"internal/update\")");
|
|
69822
|
+
}
|
|
69823
|
+
});
|
|
69824
|
+
this.on("internal/update", function(config, next) {
|
|
69825
|
+
const cbs = [...this._hooks["internal/update"] || []];
|
|
69826
|
+
const _next = () => {
|
|
69827
|
+
return (cbs.shift() ?? next).call(this, config, _next);
|
|
69828
|
+
};
|
|
69829
|
+
return _next();
|
|
69830
|
+
}, {
|
|
69831
|
+
global: true,
|
|
69832
|
+
prepend: true
|
|
69833
|
+
});
|
|
69834
|
+
this.on("internal/config", (fiber, next) => {
|
|
69835
|
+
const config = next();
|
|
69836
|
+
return fiber.runtime ? resolveConfig(fiber.runtime, config) : config;
|
|
69837
|
+
});
|
|
69838
|
+
}
|
|
69839
|
+
_resolve(type, args) {
|
|
69840
|
+
const thisArg = typeof args[0] === "object" || typeof args[0] === "function" ? args.shift() : null;
|
|
69841
|
+
const name = args.shift();
|
|
69842
|
+
if ((typeof name !== "string" || !name.startsWith("internal/")) && this._hooks["internal/dispatch"]?.length) this.emit("internal/dispatch", type, name, args, thisArg);
|
|
69843
|
+
const filter = thisArg?.[Context.filter];
|
|
69844
|
+
return [thisArg, (this._hooks[name] || []).filter((hook) => hook.global || !filter || filter.call(thisArg, hook.ctx)).map((hook) => hook.callback)];
|
|
69845
|
+
}
|
|
69846
|
+
/**
|
|
69847
|
+
* Resolve bound callbacks using the event's context filter.
|
|
69848
|
+
* @param type Dispatch mode reported to observers.
|
|
69849
|
+
* @param args Dispatch arguments, consumed through the event name.
|
|
69850
|
+
* @returns Matching callbacks bound to the dispatch receiver.
|
|
69851
|
+
* DSH retains callback enumeration for per-listener error containment.
|
|
69852
|
+
*/
|
|
69853
|
+
dispatch(type, args) {
|
|
69854
|
+
const [thisArg, callbacks] = this._resolve(type, args);
|
|
69855
|
+
return callbacks.map((callback) => callback.bind(thisArg));
|
|
69856
|
+
}
|
|
69857
|
+
/**
|
|
69858
|
+
* Run listeners concurrently and wait for all of them.
|
|
69859
|
+
*
|
|
69860
|
+
* @param args — optional `this`, the event name, then listener arguments.
|
|
69861
|
+
* @returns a promise resolving once every listener has settled.
|
|
69862
|
+
*/
|
|
69863
|
+
async parallel(...args) {
|
|
69864
|
+
const [thisArg, callbacks] = this._resolve("parallel", args);
|
|
69865
|
+
const errors = (await Promise.allSettled(callbacks.map(async (callback) => Reflect.apply(callback, thisArg, args)))).filter((result) => result.status === "rejected");
|
|
69866
|
+
if (errors.length) throw new AggregateError(errors.map((error) => error.reason));
|
|
69867
|
+
}
|
|
69868
|
+
/**
|
|
69869
|
+
* Run listeners synchronously without waiting for returned promises.
|
|
69870
|
+
*
|
|
69871
|
+
* @param args — optional `this`, the event name, then listener arguments.
|
|
69872
|
+
*/
|
|
69873
|
+
emit(...args) {
|
|
69874
|
+
const [thisArg, callbacks] = this._resolve("emit", args);
|
|
69875
|
+
for (const callback of callbacks) Reflect.apply(callback, thisArg, args);
|
|
69876
|
+
}
|
|
69877
|
+
/**
|
|
69878
|
+
* Run listeners in order, awaiting each, until one returns a bail value.
|
|
69879
|
+
*
|
|
69880
|
+
* @param args — optional `this`, the event name, then listener arguments.
|
|
69881
|
+
* @returns the first bail value (see {@link isBailed}), if any.
|
|
69882
|
+
*/
|
|
69883
|
+
async serial(...args) {
|
|
69884
|
+
const [thisArg, callbacks] = this._resolve("serial", args);
|
|
69885
|
+
for (const callback of callbacks) {
|
|
69886
|
+
const result = await Reflect.apply(callback, thisArg, args);
|
|
69887
|
+
if (isBailed(result)) return result;
|
|
69888
|
+
}
|
|
69889
|
+
}
|
|
69890
|
+
/**
|
|
69891
|
+
* Run listeners synchronously until one returns a bail value.
|
|
69892
|
+
*
|
|
69893
|
+
* @param args — optional `this`, the event name, then listener arguments.
|
|
69894
|
+
* @returns the first bail value (see {@link isBailed}), if any.
|
|
69895
|
+
*/
|
|
69896
|
+
bail(...args) {
|
|
69897
|
+
const [thisArg, callbacks] = this._resolve("bail", args);
|
|
69898
|
+
for (const callback of callbacks) {
|
|
69899
|
+
const result = Reflect.apply(callback, thisArg, args);
|
|
69900
|
+
if (isBailed(result)) return result;
|
|
69901
|
+
}
|
|
69902
|
+
}
|
|
69903
|
+
/**
|
|
69904
|
+
* Compose listeners around the final `next` callback.
|
|
69905
|
+
*
|
|
69906
|
+
* The last dispatch argument is treated as the innermost `next`. Listeners
|
|
69907
|
+
* run outermost-first; a listener that does not call `next()` vetoes the
|
|
69908
|
+
* rest of the chain, including the built-in behavior.
|
|
69909
|
+
*
|
|
69910
|
+
* @param args — optional `this`, the event name, listener arguments, then `next`.
|
|
69911
|
+
* @returns the outermost listener's return value.
|
|
69912
|
+
*/
|
|
69913
|
+
waterfall(...args) {
|
|
69914
|
+
const [thisArg, callbacks] = this._resolve("waterfall", args);
|
|
69915
|
+
const inner = args.pop();
|
|
69916
|
+
const dispatch = () => {
|
|
69917
|
+
const callback = callbacks.shift();
|
|
69918
|
+
if (!callback) return inner();
|
|
69919
|
+
let called = false;
|
|
69920
|
+
const next = () => {
|
|
69921
|
+
if (called) throw new Error("next() called multiple times");
|
|
69922
|
+
called = true;
|
|
69923
|
+
return dispatch();
|
|
69924
|
+
};
|
|
69925
|
+
return Reflect.apply(callback, thisArg, [...args, next]);
|
|
69926
|
+
};
|
|
69927
|
+
return dispatch();
|
|
69928
|
+
}
|
|
69929
|
+
register(label, name, callback, options) {
|
|
69930
|
+
const method = options.prepend ? "unshift" : "push";
|
|
69931
|
+
return this.ctx.fiber.effect(() => {
|
|
69932
|
+
(this._hooks[name] ??= [])[method]({
|
|
69933
|
+
ctx: this.ctx,
|
|
69934
|
+
callback,
|
|
69935
|
+
...options
|
|
69936
|
+
});
|
|
69937
|
+
return () => this.unregister(name, callback);
|
|
69938
|
+
}, label);
|
|
69939
|
+
}
|
|
69940
|
+
unregister(name, callback) {
|
|
69941
|
+
const hooks = this._hooks[name];
|
|
69942
|
+
if (!hooks) return;
|
|
69943
|
+
const index = hooks.findIndex((hook) => hook.callback === callback);
|
|
69944
|
+
if (index >= 0) {
|
|
69945
|
+
hooks.splice(index, 1);
|
|
69946
|
+
if (!hooks.length) delete this._hooks[name];
|
|
69947
|
+
return true;
|
|
69948
|
+
}
|
|
69949
|
+
}
|
|
69950
|
+
/**
|
|
69951
|
+
* Register an event listener owned by the current fiber.
|
|
69952
|
+
*
|
|
69953
|
+
* The listener is removed automatically when the fiber unloads. Throws
|
|
69954
|
+
* `CordisError('INACTIVE_EFFECT')` if the fiber is already disposed.
|
|
69955
|
+
*
|
|
69956
|
+
* @param name — the event name to listen for.
|
|
69957
|
+
* @param listener — called with the dispatch arguments.
|
|
69958
|
+
* @param options — listener options; a boolean is shorthand for `prepend`.
|
|
69959
|
+
* @returns a disposer removing the listener; `true` if it was still registered.
|
|
69960
|
+
*/
|
|
69961
|
+
on(name, listener, options) {
|
|
69962
|
+
if (typeof options !== "object") options = { prepend: options };
|
|
69963
|
+
this.ctx.fiber.assertActive();
|
|
69964
|
+
listener = this.ctx.reflect.bind(listener);
|
|
69965
|
+
const result = this.bail(this.ctx, "internal/listener", name, listener, options);
|
|
69966
|
+
if (result) return result;
|
|
69967
|
+
const label = `ctx.on(${typeof name === "string" ? JSON.stringify(name) : name.toString()})`;
|
|
69968
|
+
return this.register(label, name, listener, options);
|
|
69969
|
+
}
|
|
69970
|
+
/**
|
|
69971
|
+
* Register an event listener that disposes itself after the first call.
|
|
69972
|
+
*
|
|
69973
|
+
* @param name — the event name to listen for.
|
|
69974
|
+
* @param listener — called at most once with the dispatch arguments.
|
|
69975
|
+
* @param options — listener options; a boolean is shorthand for `prepend`.
|
|
69976
|
+
* @returns a disposer removing the listener; `true` if it was still registered.
|
|
69977
|
+
*/
|
|
69978
|
+
once(name, listener, options) {
|
|
69979
|
+
const dispose = this.on(name, function(...args) {
|
|
69980
|
+
dispose();
|
|
69981
|
+
return listener.apply(this, args);
|
|
69982
|
+
}, options);
|
|
69983
|
+
return dispose;
|
|
69984
|
+
}
|
|
69985
|
+
};
|
|
69986
|
+
/** Built-in placeholder formatters used by `Logger.format()`. */
|
|
69987
|
+
const defaultFormatters = {
|
|
69988
|
+
s: (value) => String(value),
|
|
69989
|
+
d: (value) => Math.trunc(Number(value)),
|
|
69990
|
+
i: (value) => Math.trunc(Number(value)),
|
|
69991
|
+
f: (value) => Number(value),
|
|
69992
|
+
o: (value) => JSON.stringify(value),
|
|
69993
|
+
O: (value) => JSON.stringify(value),
|
|
69994
|
+
c: () => "",
|
|
69995
|
+
C: (value, exporter, message) => {
|
|
69996
|
+
return Logger.color(exporter, Logger.code(message.name, exporter.colors), value);
|
|
69997
|
+
}
|
|
69998
|
+
};
|
|
69999
|
+
function isAggregateError(error) {
|
|
69813
70000
|
return error instanceof Error && Array.isArray(error["errors"]);
|
|
69814
70001
|
}
|
|
69815
70002
|
/** Logger facade for one named subsystem. */
|
|
@@ -69855,8 +70042,8 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69855
70042
|
this.service = service;
|
|
69856
70043
|
Object.assign(this, options);
|
|
69857
70044
|
this.error = this._method("error", 0);
|
|
69858
|
-
this.info = this._method("info",
|
|
69859
|
-
this.warn = this._method("warn",
|
|
70045
|
+
this.info = this._method("info", 2);
|
|
70046
|
+
this.warn = this._method("warn", 1);
|
|
69860
70047
|
this.debug = this._method("debug", 3);
|
|
69861
70048
|
}
|
|
69862
70049
|
_method(type, level) {
|
|
@@ -69871,7 +70058,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69871
70058
|
const sn = ++this.service._snMessage;
|
|
69872
70059
|
const ts = Date.now();
|
|
69873
70060
|
for (const exporter of this.service.exporters.values()) {
|
|
69874
|
-
if ((exporter.levels?.[this.name] ?? exporter.levels?.default ?? this.level ??
|
|
70061
|
+
if ((exporter.levels?.[this.name] ?? exporter.levels?.default ?? this.level ?? 2) < level) continue;
|
|
69875
70062
|
const message = {
|
|
69876
70063
|
sn,
|
|
69877
70064
|
ts,
|
|
@@ -69999,867 +70186,336 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
69999
70186
|
colors: 3,
|
|
70000
70187
|
export: (message) => {
|
|
70001
70188
|
self.buffer.push(message);
|
|
70002
|
-
|
|
70003
|
-
|
|
70004
|
-
|
|
70005
|
-
|
|
70006
|
-
|
|
70007
|
-
|
|
70008
|
-
* Register an exporter and dispose it with the current fiber.
|
|
70009
|
-
*
|
|
70010
|
-
* @param exporter — the sink that receives structured log messages.
|
|
70011
|
-
* @returns a disposer that removes the exporter.
|
|
70012
|
-
*/
|
|
70013
|
-
exporter(exporter) {
|
|
70014
|
-
return this.ctx.effect(() => {
|
|
70015
|
-
const id = ++this._snExporter;
|
|
70016
|
-
this.exporters.set(id, exporter);
|
|
70017
|
-
return () => this.exporters.delete(id);
|
|
70018
|
-
}, "ctx.logger.exporter()");
|
|
70019
|
-
}
|
|
70020
|
-
_resolveConfig() {
|
|
70021
|
-
let intercept = this.ctx[symbols.intercept];
|
|
70022
|
-
const configs = [];
|
|
70023
|
-
while ("logger" in intercept) {
|
|
70024
|
-
if (Object.hasOwn(intercept, "logger")) configs.unshift(intercept["logger"]);
|
|
70025
|
-
intercept = Object.getPrototypeOf(intercept);
|
|
70026
|
-
}
|
|
70027
|
-
return Object.assign({}, ...configs);
|
|
70028
|
-
}
|
|
70029
|
-
[symbols.invoke](name) {
|
|
70030
|
-
const config = this._resolveConfig();
|
|
70031
|
-
const fiber = (this.ctx[symbols.shadow] ?? this.ctx).fiber;
|
|
70032
|
-
name ??= config.name;
|
|
70033
|
-
name ??= hyphenate(fiber.name);
|
|
70034
|
-
return new Logger({
|
|
70035
|
-
name,
|
|
70036
|
-
level: config.level,
|
|
70037
|
-
meta: { fiber: new WeakRef(fiber) }
|
|
70038
|
-
}, this);
|
|
70039
|
-
}
|
|
70040
|
-
static {
|
|
70041
|
-
for (const type of [
|
|
70042
|
-
"error",
|
|
70043
|
-
"info",
|
|
70044
|
-
"warn",
|
|
70045
|
-
"debug"
|
|
70046
|
-
]) LoggerService.prototype[type] = function(...args) {
|
|
70047
|
-
return this()[type](...args);
|
|
70048
|
-
};
|
|
70049
|
-
}
|
|
70050
|
-
};
|
|
70051
|
-
function enhanceError(error) {
|
|
70052
|
-
const lines = error.stack.split("\n");
|
|
70053
|
-
lines.splice(0, 2, `Error: ${error.message}`);
|
|
70054
|
-
error.stack = lines.join("\n");
|
|
70055
|
-
return error;
|
|
70056
|
-
}
|
|
70057
|
-
const RESERVED_WORDS = ["prototype", "then"];
|
|
70058
|
-
function isSpecialProperty(prop) {
|
|
70059
|
-
return typeof prop === "symbol" || RESERVED_WORDS.includes(prop) || parseInt(prop).toString() === prop || prop.startsWith("_");
|
|
70060
|
-
}
|
|
70061
|
-
/**
|
|
70062
|
-
* Reflection and service-resolution layer installed as `ctx.reflect`.
|
|
70063
|
-
*
|
|
70064
|
-
* This service powers the context proxy, service registration, accessors, and
|
|
70065
|
-
* the mixins that expose core service methods directly on `ctx`.
|
|
70066
|
-
*/
|
|
70067
|
-
var ReflectService = class {
|
|
70068
|
-
ctx;
|
|
70069
|
-
/** Proxy traps implementing service resolution for every context object. */
|
|
70070
|
-
static handler = {
|
|
70071
|
-
get: (target, prop, ctx) => {
|
|
70072
|
-
if (isSpecialProperty(prop)) return Reflect.get(target, prop, ctx);
|
|
70073
|
-
if (Reflect.has(target, prop)) return getTraceable(ctx, Reflect.get(target, prop, ctx));
|
|
70074
|
-
const error = /* @__PURE__ */ new Error(`cannot get property "${prop}" without inject`);
|
|
70075
|
-
try {
|
|
70076
|
-
const def = target.reflect.props[prop];
|
|
70077
|
-
if (def?.type === "accessor") return def.get.call(ctx, ctx[symbols.receiver], error);
|
|
70078
|
-
if (!ctx.fiber.runtime) return ctx.reflect.get(prop, false);
|
|
70079
|
-
return ctx.events.waterfall("internal/get", ctx, prop, error, () => {
|
|
70080
|
-
const key = target[symbols.isolate][prop];
|
|
70081
|
-
let fiber = (ctx[symbols.shadow] ?? ctx).fiber;
|
|
70082
|
-
while (true) {
|
|
70083
|
-
const impl = fiber.store?.[prop];
|
|
70084
|
-
if (impl) return getTraceable(ctx, impl.value);
|
|
70085
|
-
if (prop in fiber.inject) {
|
|
70086
|
-
error.message = `cannot get required service "${prop}" in inactive context`;
|
|
70087
|
-
throw error;
|
|
70088
|
-
}
|
|
70089
|
-
if (!fiber.runtime) throw error;
|
|
70090
|
-
if (fiber.parent[symbols.isolate][prop] !== key) throw error;
|
|
70091
|
-
fiber = fiber.parent.fiber;
|
|
70092
|
-
}
|
|
70093
|
-
});
|
|
70094
|
-
} catch (e) {
|
|
70095
|
-
throw e === error ? enhanceError(e) : e;
|
|
70096
|
-
}
|
|
70097
|
-
},
|
|
70098
|
-
set: (target, prop, value, ctx) => {
|
|
70099
|
-
if (isSpecialProperty(prop)) return Reflect.set(target, prop, value, ctx);
|
|
70100
|
-
const error = /* @__PURE__ */ new Error(`cannot set property "${prop}" without provide`);
|
|
70101
|
-
const def = target.reflect.props[prop];
|
|
70102
|
-
if (!def) {
|
|
70103
|
-
if (!ctx.fiber.runtime) return Reflect.set(target, prop, value, ctx);
|
|
70104
|
-
throw enhanceError(error);
|
|
70105
|
-
}
|
|
70106
|
-
try {
|
|
70107
|
-
if (def.type === "accessor") {
|
|
70108
|
-
if (!def.set) return false;
|
|
70109
|
-
return def.set.call(ctx, value, ctx[symbols.receiver], error);
|
|
70110
|
-
}
|
|
70111
|
-
return ctx.events.waterfall("internal/set", ctx, prop, value, error, () => {
|
|
70112
|
-
return ctx.reflect.set(prop, value, error);
|
|
70113
|
-
});
|
|
70114
|
-
} catch (e) {
|
|
70115
|
-
throw e === error ? enhanceError(e) : e;
|
|
70116
|
-
}
|
|
70117
|
-
},
|
|
70118
|
-
has: (target, prop) => {
|
|
70119
|
-
if (isSpecialProperty(prop)) return Reflect.has(target, prop);
|
|
70120
|
-
if (Reflect.has(target, prop)) return true;
|
|
70121
|
-
return !!target.reflect.props[prop];
|
|
70122
|
-
}
|
|
70123
|
-
};
|
|
70124
|
-
/** Service implementations, keyed by isolation label. */
|
|
70125
|
-
store = Object.create(null);
|
|
70126
|
-
/** Declared context properties (services and accessors), by name. */
|
|
70127
|
-
props = Object.create(null);
|
|
70128
|
-
constructor(ctx) {
|
|
70129
|
-
this.ctx = ctx;
|
|
70130
|
-
defineProperty(this, symbols.tracker, {
|
|
70131
|
-
property: "ctx",
|
|
70132
|
-
noShadow: true
|
|
70133
|
-
});
|
|
70134
|
-
this.mixin("reflect", [
|
|
70135
|
-
"get",
|
|
70136
|
-
"set",
|
|
70137
|
-
"provide",
|
|
70138
|
-
"accessor",
|
|
70139
|
-
"mixin"
|
|
70140
|
-
]);
|
|
70141
|
-
this.mixin("fiber", ["runtime", "effect"]);
|
|
70142
|
-
this.mixin("registry", ["inject", "plugin"]);
|
|
70143
|
-
this.mixin("events", [
|
|
70144
|
-
"on",
|
|
70145
|
-
"once",
|
|
70146
|
-
"parallel",
|
|
70147
|
-
"emit",
|
|
70148
|
-
"serial",
|
|
70149
|
-
"bail",
|
|
70150
|
-
"waterfall"
|
|
70151
|
-
]);
|
|
70152
|
-
}
|
|
70153
|
-
/**
|
|
70154
|
-
* Read a service from the store without the inject requirement.
|
|
70155
|
-
*
|
|
70156
|
-
* @param name — the service name.
|
|
70157
|
-
* @param strict — when `true`, only return implementations whose providing
|
|
70158
|
-
* fiber is currently active.
|
|
70159
|
-
* @returns the service value, or `undefined` when not (yet) provided.
|
|
70160
|
-
*/
|
|
70161
|
-
get(name, strict = true) {
|
|
70162
|
-
return getTraceable(this.ctx, this._getImpl(name, strict)?.value);
|
|
70163
|
-
}
|
|
70164
|
-
_getImpl(name, strict = true) {
|
|
70165
|
-
const key = this.ctx[symbols.isolate][name];
|
|
70166
|
-
const impl = key && this.store[key];
|
|
70167
|
-
if (!impl) return;
|
|
70168
|
-
if (strict && impl.fiber.state !== 2) return;
|
|
70169
|
-
return impl;
|
|
70170
|
-
}
|
|
70171
|
-
/**
|
|
70172
|
-
* Overwrite a provided service's value.
|
|
70173
|
-
*
|
|
70174
|
-
* @param name — the service name.
|
|
70175
|
-
* @param value — the new service value.
|
|
70176
|
-
* @param error — carrier for the caller stack in diagnostics.
|
|
70177
|
-
* @returns `true` on success.
|
|
70178
|
-
* @throws when `name` was never provided, or was provided by another fiber.
|
|
70179
|
-
*/
|
|
70180
|
-
set(name, value, error) {
|
|
70181
|
-
const key = this.ctx[symbols.isolate][name];
|
|
70182
|
-
const impl = this.store[key];
|
|
70183
|
-
if (!impl) throw new Error(`cannot set property "${name}" without provide`);
|
|
70184
|
-
if (impl.fiber !== this.ctx.fiber) throw new Error(`cannot set property "${name}" in multiple fibers`);
|
|
70185
|
-
impl.value = value;
|
|
70186
|
-
return true;
|
|
70187
|
-
}
|
|
70188
|
-
/**
|
|
70189
|
-
* Register a service implementation owned by the current fiber.
|
|
70190
|
-
*
|
|
70191
|
-
* See the `ctx.provide()` overload above for the full contract.
|
|
70192
|
-
*
|
|
70193
|
-
* @param name — the service name.
|
|
70194
|
-
* @param value — the service value.
|
|
70195
|
-
* @param check — optional availability predicate for dependents.
|
|
70196
|
-
* @returns a disposer that unregisters the service.
|
|
70197
|
-
*/
|
|
70198
|
-
provide(name, value, check) {
|
|
70199
|
-
return this.ctx.fiber.effect(() => {
|
|
70200
|
-
if (!this.props[name]) this.props[name] ??= { type: "service" };
|
|
70201
|
-
else if (this.props[name].type !== "service") throw new Error(`property "${name}" is already declared as ${this.props[name].type}`);
|
|
70202
|
-
this.props[name] = { type: "service" };
|
|
70203
|
-
this.ctx.root[symbols.isolate][name] ??= Symbol(name);
|
|
70204
|
-
const key = this.ctx[symbols.isolate][name];
|
|
70205
|
-
const impl = {
|
|
70206
|
-
name,
|
|
70207
|
-
value,
|
|
70208
|
-
fiber: this.ctx.fiber,
|
|
70209
|
-
check
|
|
70210
|
-
};
|
|
70211
|
-
if (this.store[key]) throw new Error(`service "${name}" has been registered at <${this.store[key].fiber.name}>`);
|
|
70212
|
-
this.store[key] = impl;
|
|
70213
|
-
this.ctx.fiber.store[name] = impl;
|
|
70214
|
-
if (this.ctx.fiber.state === 2) this.notify([name]);
|
|
70215
|
-
return async () => {
|
|
70216
|
-
delete this.store[key];
|
|
70217
|
-
const fibers = this.notify([name]);
|
|
70218
|
-
await Promise.allSettled(fibers.map((fiber) => fiber.await()));
|
|
70219
|
-
delete this.ctx.fiber.store[name];
|
|
70220
|
-
};
|
|
70221
|
-
}, `ctx.provide(${JSON.stringify(name)})`);
|
|
70222
|
-
}
|
|
70223
|
-
/**
|
|
70224
|
-
* Re-evaluate every fiber that requires one of the given services.
|
|
70225
|
-
*
|
|
70226
|
-
* @param names — the service names that changed.
|
|
70227
|
-
* @param filter — restricts notification to matching isolation scopes.
|
|
70228
|
-
* @returns the fibers whose dependency state was refreshed.
|
|
70229
|
-
*/
|
|
70230
|
-
notify(names, filter = (ctx, name) => ctx[symbols.isolate][name] === this.ctx[symbols.isolate][name]) {
|
|
70231
|
-
const fibers = [];
|
|
70232
|
-
for (const runtime of this.ctx.registry.values()) for (const fiber of runtime.fibers) {
|
|
70233
|
-
let hasUpdate = false;
|
|
70234
|
-
for (const name of names) {
|
|
70235
|
-
if (!(name in fiber.inject)) continue;
|
|
70236
|
-
if (!filter(fiber.ctx, name)) continue;
|
|
70237
|
-
hasUpdate = true;
|
|
70238
|
-
fiber._checkImpl(name);
|
|
70239
|
-
}
|
|
70240
|
-
if (!hasUpdate) continue;
|
|
70241
|
-
fiber._refresh();
|
|
70242
|
-
fibers.push(fiber);
|
|
70243
|
-
}
|
|
70244
|
-
for (const name of names) {
|
|
70245
|
-
const self = Object.create(this.ctx);
|
|
70246
|
-
self[symbols.filter] = (target) => filter(target, name);
|
|
70247
|
-
this.ctx.events.emit(self, "internal/service", name, this._getImpl(name, false)?.value);
|
|
70248
|
-
}
|
|
70249
|
-
return fibers;
|
|
70250
|
-
}
|
|
70251
|
-
/**
|
|
70252
|
-
* Define a computed context property backed by get/set hooks.
|
|
70253
|
-
*
|
|
70254
|
-
* @param name — the context property name.
|
|
70255
|
-
* @param options — the `get` hook and optional `set` hook.
|
|
70256
|
-
* @returns a disposer that removes the accessor.
|
|
70257
|
-
*/
|
|
70258
|
-
accessor(name, options) {
|
|
70259
|
-
return this.ctx.fiber.effect(() => {
|
|
70260
|
-
if (name in this.props) throw new Error(`property "${name}" is already declared as ${this.props[name].type}`);
|
|
70261
|
-
this.props[name] = {
|
|
70262
|
-
type: "accessor",
|
|
70263
|
-
...options
|
|
70264
|
-
};
|
|
70265
|
-
return () => delete this.props[name];
|
|
70266
|
-
}, `ctx.accessor(${JSON.stringify(name)})`);
|
|
70267
|
-
}
|
|
70268
|
-
/**
|
|
70269
|
-
* Expose selected members of a service directly on `ctx`.
|
|
70270
|
-
*
|
|
70271
|
-
* See the `ctx.mixin()` overload above for the full contract.
|
|
70272
|
-
*
|
|
70273
|
-
* @param source — a context property name or a source object.
|
|
70274
|
-
* @param mixins — keys to forward, or a source-key → ctx-key map.
|
|
70275
|
-
* @returns a disposer that removes all created accessors.
|
|
70276
|
-
*/
|
|
70277
|
-
mixin(source, mixins) {
|
|
70278
|
-
const self = this;
|
|
70279
|
-
return this.ctx.fiber.effect(function* () {
|
|
70280
|
-
const entries = Array.isArray(mixins) ? mixins.map((key) => [key, key]) : Object.entries(mixins);
|
|
70281
|
-
const getTarget = (ctx, error) => {
|
|
70282
|
-
return ctx[source];
|
|
70283
|
-
};
|
|
70284
|
-
for (const [key, value] of entries) yield self.accessor(value, {
|
|
70285
|
-
get(receiver, error) {
|
|
70286
|
-
const service = getTarget(this, error);
|
|
70287
|
-
if (isNullable(service)) return service;
|
|
70288
|
-
const mixin = receiver ? withProps(receiver, service) : service;
|
|
70289
|
-
const value = Reflect.get(service, key, mixin);
|
|
70290
|
-
if (typeof value !== "function") return value;
|
|
70291
|
-
return value.bind(mixin ?? service);
|
|
70292
|
-
},
|
|
70293
|
-
set(value, receiver, error) {
|
|
70294
|
-
const service = getTarget(this, error);
|
|
70295
|
-
const mixin = receiver ? withProps(receiver, service) : service;
|
|
70296
|
-
return Reflect.set(service, key, value, mixin);
|
|
70297
|
-
}
|
|
70298
|
-
});
|
|
70299
|
-
}, `ctx.mixin(${JSON.stringify(source)})`);
|
|
70300
|
-
}
|
|
70301
|
-
/**
|
|
70302
|
-
* Attach this context's tracing wrapper to a value.
|
|
70303
|
-
*
|
|
70304
|
-
* @param value — the value to wrap.
|
|
70305
|
-
* @returns the traceable wrapper (or the value itself when not applicable).
|
|
70306
|
-
*/
|
|
70307
|
-
trace(value) {
|
|
70308
|
-
return getTraceable(this.ctx, value);
|
|
70309
|
-
}
|
|
70310
|
-
/**
|
|
70311
|
-
* Wrap a callback so calls trace `this` and arguments to this context.
|
|
70312
|
-
*
|
|
70313
|
-
* @param callback — the function to wrap.
|
|
70314
|
-
* @returns a proxy delegating to `callback` with traced values.
|
|
70315
|
-
*/
|
|
70316
|
-
bind(callback) {
|
|
70317
|
-
return new Proxy(callback, {
|
|
70318
|
-
apply: (target, thisArg, args) => {
|
|
70319
|
-
return Reflect.apply(target, this.trace(thisArg), args.map((arg) => this.trace(arg)));
|
|
70320
|
-
},
|
|
70321
|
-
construct: (target, args, newTarget) => {
|
|
70322
|
-
return Reflect.construct(target, args.map((arg) => this.trace(arg)), newTarget);
|
|
70323
|
-
}
|
|
70324
|
-
});
|
|
70325
|
-
}
|
|
70326
|
-
};
|
|
70327
|
-
const kValidationError = Symbol.for("ValidationError");
|
|
70328
|
-
/** Error raised when plugin configuration fails standard-schema validation. */
|
|
70329
|
-
var ValidationError = class extends TypeError {
|
|
70330
|
-
name = "ValidationError";
|
|
70331
|
-
/**
|
|
70332
|
-
* Build the aggregated message from schema issues.
|
|
70333
|
-
*
|
|
70334
|
-
* @param issues — the standard-schema issues, one message line each.
|
|
70335
|
-
*/
|
|
70336
|
-
constructor(issues) {
|
|
70337
|
-
super(`invalid config:\n` + issues.map((issue) => {
|
|
70338
|
-
if (issue.path) return ` - ${issue.message} (at ${issue.path.join(".")})`;
|
|
70339
|
-
else return ` - ${issue.message}`;
|
|
70340
|
-
}).join("\n"));
|
|
70341
|
-
}
|
|
70342
|
-
};
|
|
70343
|
-
Object.defineProperty(ValidationError.prototype, kValidationError, { value: true });
|
|
70344
|
-
/**
|
|
70345
|
-
* Validate and normalize config for a plugin runtime before it starts.
|
|
70346
|
-
*
|
|
70347
|
-
* @param runtime — the plugin runtime whose `Config` schema to apply.
|
|
70348
|
-
* @param config — the raw user config.
|
|
70349
|
-
* @returns the validated config, or `config` unchanged if the runtime has no schema.
|
|
70350
|
-
* @throws {ValidationError} when validation reports issues.
|
|
70351
|
-
*/
|
|
70352
|
-
function resolveConfig(runtime, config) {
|
|
70353
|
-
if (!runtime.Config) return config;
|
|
70354
|
-
const result = runtime.Config["~standard"].validate(config);
|
|
70355
|
-
if ("then" in result) throw new TypeError("Async config validation is not supported");
|
|
70356
|
-
if (result.issues) throw new ValidationError(result.issues);
|
|
70357
|
-
else return result.value;
|
|
70358
|
-
}
|
|
70359
|
-
const effectInertia = /* @__PURE__ */ new WeakMap();
|
|
70360
|
-
function runDisposable(dispose) {
|
|
70361
|
-
const result = dispose();
|
|
70362
|
-
return effectInertia.get(dispose)?.() ?? result;
|
|
70363
|
-
}
|
|
70364
|
-
/** Notify plugin teardown without allowing one observer to break ownership cleanup. */
|
|
70365
|
-
function emitPluginDisposed(context, fiber) {
|
|
70366
|
-
const args = ["internal/plugin", fiber];
|
|
70367
|
-
let callbacks;
|
|
70368
|
-
try {
|
|
70369
|
-
callbacks = context.events.dispatch("emit", args);
|
|
70370
|
-
} catch (error) {
|
|
70371
|
-
context.logger.error(error);
|
|
70372
|
-
return;
|
|
70373
|
-
}
|
|
70374
|
-
for (const callback of callbacks) try {
|
|
70375
|
-
const returned = callback(...args);
|
|
70376
|
-
Promise.resolve(returned).catch((error) => context.logger.error(error));
|
|
70377
|
-
} catch (error) {
|
|
70378
|
-
context.logger.error(error);
|
|
70379
|
-
}
|
|
70380
|
-
}
|
|
70381
|
-
/** Framework error with a stable machine-readable code. */
|
|
70382
|
-
var CordisError = class CordisError extends Error {
|
|
70383
|
-
code;
|
|
70384
|
-
/**
|
|
70385
|
-
* @param code — the stable error code; also the default message.
|
|
70386
|
-
* @param message — optional human-readable override.
|
|
70387
|
-
*/
|
|
70388
|
-
constructor(code, message) {
|
|
70389
|
-
super(message ?? CordisError.Code[code]);
|
|
70390
|
-
this.code = code;
|
|
70391
|
-
}
|
|
70392
|
-
};
|
|
70393
|
-
/** Cordis error code definitions. */
|
|
70394
|
-
(function(CordisError) {
|
|
70395
|
-
CordisError.Code = { INACTIVE_EFFECT: "cannot create effect on inactive context" };
|
|
70396
|
-
})(CordisError || (CordisError = {}));
|
|
70397
|
-
const INACTIVE = "__INACTIVE__";
|
|
70398
|
-
/**
|
|
70399
|
-
* Runtime instance of one plugin application.
|
|
70400
|
-
*
|
|
70401
|
-
* A fiber tracks dependency state, validated config, lifecycle effects, and
|
|
70402
|
-
* cleanup for the plugin context returned by `ctx.plugin()`.
|
|
70403
|
-
*/
|
|
70404
|
-
var Fiber = class {
|
|
70405
|
-
parent;
|
|
70406
|
-
inject;
|
|
70407
|
-
runtime;
|
|
70408
|
-
/** Unique id within the registry; 0 for the root fiber, `null` once disposed. */
|
|
70409
|
-
uid;
|
|
70410
|
-
/** The context this fiber's plugin runs in (extends the parent context). */
|
|
70411
|
-
ctx;
|
|
70412
|
-
/** The validated plugin config (updated by `update()`); read through {@link effectiveConfig}. */
|
|
70413
|
-
config;
|
|
70414
|
-
/** The raw plugin config, re-resolved before activation; use {@link rawConfig} to read or retain it. */
|
|
70415
|
-
_config;
|
|
70416
|
-
/** Current lifecycle state; transitions emit `internal/status`. */
|
|
70417
|
-
state = 0;
|
|
70418
|
-
/** Dispose this fiber: unload the plugin, then settle once cleanup finished. */
|
|
70419
|
-
dispose;
|
|
70420
|
-
/** Snapshot of required service implementations while loaded; `undefined` otherwise. */
|
|
70421
|
-
store;
|
|
70422
|
-
/** The in-flight load/unload transition, if one is currently running. */
|
|
70423
|
-
inertia;
|
|
70424
|
-
_hooks = Object.create(null);
|
|
70425
|
-
_disposables = new DisposableList();
|
|
70426
|
-
context;
|
|
70427
|
-
_error;
|
|
70428
|
-
_runner;
|
|
70429
|
-
_store = Object.create(null);
|
|
70430
|
-
/**
|
|
70431
|
-
* Create a fiber. Plugin authors normally obtain fibers from `ctx.plugin()`
|
|
70432
|
-
* rather than constructing them directly.
|
|
70433
|
-
*
|
|
70434
|
-
* @param parent — the context the plugin was loaded from.
|
|
70435
|
-
* @param config — raw config, validated against the runtime's schema.
|
|
70436
|
-
* @param inject — resolved dependency map (service name → intercept config).
|
|
70437
|
-
* @param runtime — the shared plugin runtime, or `null` for the root fiber.
|
|
70438
|
-
* @param getOuterStack — captures the caller stack for effect diagnostics.
|
|
70439
|
-
*/
|
|
70440
|
-
constructor(parent, config, inject, runtime, getOuterStack) {
|
|
70441
|
-
this.parent = parent;
|
|
70442
|
-
this.inject = inject;
|
|
70443
|
-
this.runtime = runtime;
|
|
70444
|
-
this._config = config;
|
|
70445
|
-
const collect = (dispose) => {
|
|
70446
|
-
this._disposables.push(dispose);
|
|
70447
|
-
};
|
|
70448
|
-
if (runtime) {
|
|
70449
|
-
this.uid = parent.registry.counter;
|
|
70450
|
-
this.ctx = this.context = parent.extend({ fiber: this });
|
|
70451
|
-
const injectEntries = Object.entries(this.inject);
|
|
70452
|
-
if (injectEntries.length) {
|
|
70453
|
-
this.ctx[Context.intercept] = Object.create(parent[Context.intercept]);
|
|
70454
|
-
for (const [name, config] of injectEntries) {
|
|
70455
|
-
if (isNullable(config)) continue;
|
|
70456
|
-
this.ctx[Context.intercept][name] = config;
|
|
70457
|
-
}
|
|
70458
|
-
}
|
|
70459
|
-
this._runner = {
|
|
70460
|
-
epoch: INACTIVE,
|
|
70461
|
-
getOuterStack,
|
|
70462
|
-
execute: function() {
|
|
70463
|
-
if (isConstructor(runtime.callback)) {
|
|
70464
|
-
const instance = new runtime.callback(this.ctx, this.config);
|
|
70465
|
-
for (const hook of instance?.[symbols.initHooks] ?? []) hook();
|
|
70466
|
-
return instance?.[symbols.init]?.();
|
|
70467
|
-
} else return runtime.callback(this.ctx, this.config);
|
|
70468
|
-
},
|
|
70469
|
-
collect
|
|
70470
|
-
};
|
|
70471
|
-
this.dispose = parent.fiber.effect(() => {
|
|
70472
|
-
const remove = runtime.fibers.push(this);
|
|
70473
|
-
return async () => {
|
|
70474
|
-
this.uid = null;
|
|
70475
|
-
emitPluginDisposed(this.context, this);
|
|
70476
|
-
if (this.ctx.registry.has(runtime.callback)) {
|
|
70477
|
-
remove();
|
|
70478
|
-
if (!runtime.fibers.length) this.ctx.registry.delete(runtime.callback);
|
|
70479
|
-
}
|
|
70480
|
-
this._setEpoch(INACTIVE);
|
|
70481
|
-
if (!this.inertia) this._updateState(() => {
|
|
70482
|
-
this.inertia = this._unload();
|
|
70483
|
-
return 5;
|
|
70484
|
-
});
|
|
70485
|
-
while (this.inertia) await this.inertia;
|
|
70486
|
-
};
|
|
70487
|
-
}, "ctx.plugin()");
|
|
70488
|
-
try {
|
|
70489
|
-
this.context.emit("internal/plugin", this);
|
|
70490
|
-
} catch (error) {
|
|
70491
|
-
Promise.resolve(this.dispose()).catch((reason) => this.ctx.logger.error(reason));
|
|
70492
|
-
throw error;
|
|
70493
|
-
}
|
|
70494
|
-
if (this.uid !== null && parent.fiber.state !== 5) {
|
|
70495
|
-
for (const name of Object.keys(this.inject)) this._checkImpl(name);
|
|
70496
|
-
this._refresh();
|
|
70497
|
-
}
|
|
70498
|
-
} else {
|
|
70499
|
-
this.uid = 0;
|
|
70500
|
-
this.ctx = this.context = parent;
|
|
70501
|
-
this.state = 2;
|
|
70502
|
-
this.store = Object.create(null);
|
|
70503
|
-
this._runner = {
|
|
70504
|
-
epoch: "",
|
|
70505
|
-
getOuterStack,
|
|
70506
|
-
execute: () => {},
|
|
70507
|
-
collect
|
|
70508
|
-
};
|
|
70509
|
-
this.dispose = () => this.restart();
|
|
70510
|
-
}
|
|
70511
|
-
}
|
|
70512
|
-
/** The plugin's display name, inherited from the nearest named ancestor, else `'root'`. */
|
|
70513
|
-
get name() {
|
|
70514
|
-
let fiber = this;
|
|
70515
|
-
do {
|
|
70516
|
-
if (fiber.runtime?.name) return fiber.runtime.name;
|
|
70517
|
-
fiber = fiber.parent.fiber;
|
|
70518
|
-
} while (fiber !== fiber.parent.fiber);
|
|
70519
|
-
return "root";
|
|
70520
|
-
}
|
|
70521
|
-
/**
|
|
70522
|
-
* Throw if the fiber has already been disposed.
|
|
70523
|
-
*
|
|
70524
|
-
* @returns nothing when the fiber is still active.
|
|
70525
|
-
* @throws {CordisError} `INACTIVE_EFFECT` when the fiber's uid has been cleared.
|
|
70526
|
-
*/
|
|
70527
|
-
assertActive() {
|
|
70528
|
-
if (this.uid !== null) return;
|
|
70529
|
-
throw new CordisError("INACTIVE_EFFECT");
|
|
70530
|
-
}
|
|
70531
|
-
_execute(runner) {
|
|
70532
|
-
const oldEpoch = runner.epoch;
|
|
70533
|
-
return composeError((info) => {
|
|
70534
|
-
const safeCollect = (dispose) => {
|
|
70535
|
-
if (typeof dispose === "function") runner.collect(dispose);
|
|
70536
|
-
else if (!isNullable(dispose)) throw new TypeError("Invalid effect");
|
|
70537
|
-
};
|
|
70538
|
-
const effect = runner.execute.call(this);
|
|
70539
|
-
if (typeof effect === "function") return runner.collect(effect);
|
|
70540
|
-
else if (isNullable(effect)) {} else if (!isObject$1(effect)) throw new TypeError("Invalid effect");
|
|
70541
|
-
else if ("then" in effect) return effect.then(safeCollect);
|
|
70542
|
-
else if (Symbol.iterator in effect) {
|
|
70543
|
-
info.error = /* @__PURE__ */ new Error();
|
|
70544
|
-
const iter = effect[Symbol.iterator]();
|
|
70545
|
-
while (true) {
|
|
70546
|
-
const result = iter.next();
|
|
70547
|
-
safeCollect(result.value);
|
|
70548
|
-
if (result.done) return;
|
|
70549
|
-
}
|
|
70550
|
-
} else if (Symbol.asyncIterator in effect) {
|
|
70551
|
-
const iter = effect[Symbol.asyncIterator]();
|
|
70552
|
-
return (async () => {
|
|
70553
|
-
await Promise.resolve();
|
|
70554
|
-
info.error = /* @__PURE__ */ new Error();
|
|
70555
|
-
while (true) {
|
|
70556
|
-
if (runner.epoch !== oldEpoch) return;
|
|
70557
|
-
const result = await iter.next();
|
|
70558
|
-
safeCollect(result.value);
|
|
70559
|
-
if (result.done) return;
|
|
70560
|
-
}
|
|
70561
|
-
})();
|
|
70562
|
-
} else throw new TypeError("Invalid effect");
|
|
70563
|
-
}, runner.getOuterStack);
|
|
70564
|
-
}
|
|
70565
|
-
effect(execute, label = "anonymous") {
|
|
70566
|
-
this.assertActive();
|
|
70567
|
-
if (this.state === 5) throw new CordisError("INACTIVE_EFFECT");
|
|
70568
|
-
const disposables = [];
|
|
70569
|
-
let disposing = false;
|
|
70570
|
-
let disposalTask;
|
|
70571
|
-
const dispose = () => {
|
|
70572
|
-
if (disposing) return disposalTask;
|
|
70573
|
-
disposing = true;
|
|
70574
|
-
let task;
|
|
70575
|
-
for (const disposable of disposables.splice(0).reverse()) if (task) task = task.then(() => runDisposable(disposable));
|
|
70576
|
-
else {
|
|
70577
|
-
const result = runDisposable(disposable);
|
|
70578
|
-
if (isObject$1(result) && "then" in result) task = result;
|
|
70579
|
-
}
|
|
70580
|
-
return disposalTask = task;
|
|
70581
|
-
};
|
|
70582
|
-
const meta = {
|
|
70583
|
-
label,
|
|
70584
|
-
children: []
|
|
70585
|
-
};
|
|
70586
|
-
const runner = {
|
|
70587
|
-
execute,
|
|
70588
|
-
epoch: true,
|
|
70589
|
-
collect: (dispose) => {
|
|
70590
|
-
disposables.push(dispose);
|
|
70591
|
-
this._disposables.delete(dispose);
|
|
70592
|
-
if (dispose[symbols.effect]) meta.children.push(dispose[symbols.effect]);
|
|
70593
|
-
},
|
|
70594
|
-
getOuterStack: buildOuterStack()
|
|
70595
|
-
};
|
|
70596
|
-
let task;
|
|
70597
|
-
let executing = true;
|
|
70598
|
-
let resolveSetup;
|
|
70599
|
-
let rejectSetup;
|
|
70600
|
-
let setupBarrier;
|
|
70601
|
-
let setupFailed = false;
|
|
70602
|
-
let inFlight;
|
|
70603
|
-
let removeWrapper = () => false;
|
|
70604
|
-
const waitForSetup = () => {
|
|
70605
|
-
setupBarrier ??= new Promise((resolve, reject) => {
|
|
70606
|
-
resolveSetup = resolve;
|
|
70607
|
-
rejectSetup = reject;
|
|
70608
|
-
});
|
|
70609
|
-
return setupBarrier;
|
|
70610
|
-
};
|
|
70611
|
-
const disposeAfter = (setup) => {
|
|
70612
|
-
return Promise.resolve(setup).then(() => dispose(), async (reason) => {
|
|
70613
|
-
await dispose();
|
|
70614
|
-
throw reason;
|
|
70615
|
-
});
|
|
70616
|
-
};
|
|
70617
|
-
const finalizeDisposal = (callback) => {
|
|
70618
|
-
let result;
|
|
70619
|
-
try {
|
|
70620
|
-
result = callback();
|
|
70621
|
-
} catch (error) {
|
|
70622
|
-
removeWrapper();
|
|
70623
|
-
throw error;
|
|
70624
|
-
}
|
|
70625
|
-
if (isObject$1(result) && "then" in result) {
|
|
70626
|
-
const pending = Promise.resolve(result).finally(() => {
|
|
70627
|
-
removeWrapper();
|
|
70628
|
-
if (inFlight === pending) inFlight = void 0;
|
|
70629
|
-
});
|
|
70630
|
-
return inFlight = pending;
|
|
70631
|
-
}
|
|
70632
|
-
removeWrapper();
|
|
70633
|
-
return result;
|
|
70634
|
-
};
|
|
70635
|
-
const wrapper = defineProperty(() => {
|
|
70636
|
-
if (!runner.epoch) return setupFailed ? inFlight : void 0;
|
|
70637
|
-
runner.epoch = false;
|
|
70638
|
-
return finalizeDisposal(() => {
|
|
70639
|
-
if (executing) return disposeAfter(waitForSetup());
|
|
70640
|
-
return task ? disposeAfter(task) : dispose();
|
|
70641
|
-
});
|
|
70642
|
-
}, symbols.effect, meta);
|
|
70643
|
-
effectInertia.set(wrapper, () => inFlight);
|
|
70644
|
-
removeWrapper = this._disposables.push(wrapper);
|
|
70645
|
-
try {
|
|
70646
|
-
task = this._execute(runner);
|
|
70647
|
-
} catch (reason) {
|
|
70648
|
-
executing = false;
|
|
70649
|
-
setupFailed = true;
|
|
70650
|
-
runner.epoch = false;
|
|
70651
|
-
let cleanup;
|
|
70652
|
-
try {
|
|
70653
|
-
cleanup = finalizeDisposal(dispose);
|
|
70654
|
-
} finally {
|
|
70655
|
-
rejectSetup?.(reason);
|
|
70656
|
-
}
|
|
70657
|
-
if (isObject$1(cleanup) && "then" in cleanup) cleanup.catch((error) => this.ctx.logger.error(error));
|
|
70658
|
-
throw reason;
|
|
70659
|
-
}
|
|
70660
|
-
executing = false;
|
|
70661
|
-
if (setupBarrier) Promise.resolve(task).then(resolveSetup, rejectSetup);
|
|
70662
|
-
task?.catch(() => {
|
|
70663
|
-
if (!runner.epoch) return dispose();
|
|
70664
|
-
return finalizeDisposal(dispose);
|
|
70665
|
-
}).catch((error) => this.ctx.logger.error(error));
|
|
70666
|
-
const disposeAsync = () => {
|
|
70667
|
-
if (!runner.epoch) return;
|
|
70668
|
-
runner.epoch = false;
|
|
70669
|
-
return finalizeDisposal(dispose);
|
|
70670
|
-
};
|
|
70671
|
-
wrapper.then = async (onFulfilled, onRejected) => {
|
|
70672
|
-
return Promise.resolve(task).then(() => disposeAsync).then(onFulfilled, onRejected);
|
|
70673
|
-
};
|
|
70674
|
-
return wrapper;
|
|
70189
|
+
const overflow = self.buffer.length - self.bufferSize;
|
|
70190
|
+
if (overflow === 1) self.buffer.shift();
|
|
70191
|
+
else if (overflow > 1) self.buffer.splice(0, overflow);
|
|
70192
|
+
}
|
|
70193
|
+
});
|
|
70194
|
+
return self;
|
|
70675
70195
|
}
|
|
70676
70196
|
/**
|
|
70677
|
-
*
|
|
70197
|
+
* Register an exporter and dispose it with the current fiber.
|
|
70678
70198
|
*
|
|
70679
|
-
* @
|
|
70199
|
+
* @param exporter — the sink that receives structured log messages.
|
|
70200
|
+
* @returns a disposer that removes the exporter.
|
|
70680
70201
|
*/
|
|
70681
|
-
|
|
70682
|
-
return
|
|
70683
|
-
|
|
70684
|
-
|
|
70685
|
-
|
|
70686
|
-
|
|
70687
|
-
if (this._runner.epoch !== INACTIVE) return 2;
|
|
70688
|
-
return 0;
|
|
70202
|
+
exporter(exporter) {
|
|
70203
|
+
return this.ctx.effect(() => {
|
|
70204
|
+
const id = ++this._snExporter;
|
|
70205
|
+
this.exporters.set(id, exporter);
|
|
70206
|
+
return () => this.exporters.delete(id);
|
|
70207
|
+
}, "ctx.logger.exporter()");
|
|
70689
70208
|
}
|
|
70690
|
-
|
|
70691
|
-
|
|
70692
|
-
|
|
70693
|
-
|
|
70694
|
-
|
|
70695
|
-
|
|
70696
|
-
for (const key of Reflect.ownKeys(this.ctx.reflect.store)) {
|
|
70697
|
-
const impl = this.ctx.reflect.store[key];
|
|
70698
|
-
if (impl.fiber !== this) continue;
|
|
70699
|
-
this.ctx.reflect.notify([impl.name]);
|
|
70209
|
+
_resolveConfig() {
|
|
70210
|
+
let intercept = this.ctx[symbols.intercept];
|
|
70211
|
+
const configs = [];
|
|
70212
|
+
while ("logger" in intercept) {
|
|
70213
|
+
if (Object.hasOwn(intercept, "logger")) configs.unshift(intercept["logger"]);
|
|
70214
|
+
intercept = Object.getPrototypeOf(intercept);
|
|
70700
70215
|
}
|
|
70216
|
+
return Object.assign({}, ...configs);
|
|
70701
70217
|
}
|
|
70702
|
-
|
|
70703
|
-
const
|
|
70704
|
-
|
|
70705
|
-
|
|
70706
|
-
|
|
70707
|
-
|
|
70708
|
-
|
|
70709
|
-
|
|
70710
|
-
|
|
70711
|
-
this
|
|
70218
|
+
[symbols.invoke](name) {
|
|
70219
|
+
const config = this._resolveConfig();
|
|
70220
|
+
const fiber = (this[symbols.caller] ?? this.ctx).fiber;
|
|
70221
|
+
name ??= config.name;
|
|
70222
|
+
name ??= hyphenate(fiber.name);
|
|
70223
|
+
return new Logger({
|
|
70224
|
+
name,
|
|
70225
|
+
level: config.level,
|
|
70226
|
+
meta: { fiber: new WeakRef(fiber) }
|
|
70227
|
+
}, this);
|
|
70712
70228
|
}
|
|
70713
|
-
|
|
70714
|
-
|
|
70715
|
-
|
|
70716
|
-
|
|
70717
|
-
|
|
70718
|
-
|
|
70719
|
-
|
|
70720
|
-
|
|
70721
|
-
|
|
70722
|
-
epoch += ":" + impl.fiber.uid;
|
|
70723
|
-
}
|
|
70724
|
-
this._setEpoch(epoch);
|
|
70229
|
+
static {
|
|
70230
|
+
for (const type of [
|
|
70231
|
+
"error",
|
|
70232
|
+
"info",
|
|
70233
|
+
"warn",
|
|
70234
|
+
"debug"
|
|
70235
|
+
]) LoggerService.prototype[type] = function(...args) {
|
|
70236
|
+
return this()[type](...args);
|
|
70237
|
+
};
|
|
70725
70238
|
}
|
|
70726
|
-
|
|
70727
|
-
|
|
70728
|
-
|
|
70729
|
-
|
|
70730
|
-
|
|
70731
|
-
|
|
70732
|
-
|
|
70733
|
-
|
|
70734
|
-
|
|
70735
|
-
|
|
70736
|
-
|
|
70737
|
-
|
|
70239
|
+
};
|
|
70240
|
+
function enhanceError(error) {
|
|
70241
|
+
const lines = error.stack.split("\n");
|
|
70242
|
+
lines.splice(0, 2, `Error: ${error.message}`);
|
|
70243
|
+
error.stack = lines.join("\n");
|
|
70244
|
+
return error;
|
|
70245
|
+
}
|
|
70246
|
+
const RESERVED_WORDS = ["prototype", "then"];
|
|
70247
|
+
function isSpecialProperty(prop) {
|
|
70248
|
+
return typeof prop === "symbol" || RESERVED_WORDS.includes(prop) || parseInt(prop).toString() === prop || prop.startsWith("_");
|
|
70249
|
+
}
|
|
70250
|
+
/**
|
|
70251
|
+
* Reflection and service-resolution layer installed as `ctx.reflect`.
|
|
70252
|
+
*
|
|
70253
|
+
* This service powers the context proxy, service registration, accessors, and
|
|
70254
|
+
* the mixins that expose core service methods directly on `ctx`.
|
|
70255
|
+
*/
|
|
70256
|
+
var ReflectService = class {
|
|
70257
|
+
ctx;
|
|
70258
|
+
/** Proxy traps implementing service resolution for every context object. */
|
|
70259
|
+
static handler = {
|
|
70260
|
+
get: (target, prop, ctx) => {
|
|
70261
|
+
if (isSpecialProperty(prop)) return Reflect.get(target, prop, ctx);
|
|
70262
|
+
if (Reflect.has(target, prop)) return getTraceable(ctx, Reflect.get(target, prop, ctx));
|
|
70263
|
+
const error = /* @__PURE__ */ new Error(`cannot get property "${prop}" without inject`);
|
|
70264
|
+
try {
|
|
70265
|
+
const def = target.reflect.props[prop];
|
|
70266
|
+
if (def?.type === "accessor") return def.get.call(ctx, ctx[symbols.receiver], error);
|
|
70267
|
+
const defSite = ctx[symbols.shadow] ?? ctx;
|
|
70268
|
+
if (!defSite.fiber.runtime) return ctx.reflect.get(prop, false);
|
|
70269
|
+
return ctx.events.waterfall("internal/get", ctx, prop, error, () => {
|
|
70270
|
+
const key = defSite[symbols.isolate][prop];
|
|
70271
|
+
let fiber = defSite.fiber;
|
|
70272
|
+
while (true) {
|
|
70273
|
+
let impl = fiber.committed?.[prop];
|
|
70274
|
+
for (const provision of fiber.provisions) if (provision.name === prop && provision.ctx[symbols.isolate][prop] === key) impl = provision;
|
|
70275
|
+
if (impl) return getTraceable(ctx, impl.value);
|
|
70276
|
+
if (prop in fiber.inject) {
|
|
70277
|
+
error.message = `cannot get required service "${prop}" in inactive context`;
|
|
70278
|
+
throw error;
|
|
70279
|
+
}
|
|
70280
|
+
if (!fiber.runtime) throw error;
|
|
70281
|
+
if (fiber.parent[symbols.isolate][prop] !== key) throw error;
|
|
70282
|
+
fiber = fiber.parent.fiber;
|
|
70283
|
+
}
|
|
70284
|
+
});
|
|
70285
|
+
} catch (e) {
|
|
70286
|
+
throw e === error ? enhanceError(e) : e;
|
|
70287
|
+
}
|
|
70288
|
+
},
|
|
70289
|
+
set: (target, prop, value, ctx) => {
|
|
70290
|
+
if (isSpecialProperty(prop)) return Reflect.set(target, prop, value, ctx);
|
|
70291
|
+
const error = /* @__PURE__ */ new Error(`cannot set property "${prop}" without provide`);
|
|
70292
|
+
const def = target.reflect.props[prop];
|
|
70293
|
+
if (!def) {
|
|
70294
|
+
if (!ctx.fiber.runtime) return Reflect.set(target, prop, value, ctx);
|
|
70295
|
+
throw enhanceError(error);
|
|
70296
|
+
}
|
|
70297
|
+
try {
|
|
70298
|
+
if (def.type === "accessor") {
|
|
70299
|
+
if (!def.set) return false;
|
|
70300
|
+
return def.set.call(ctx, value, ctx[symbols.receiver], error);
|
|
70301
|
+
}
|
|
70302
|
+
return ctx.events.waterfall("internal/set", ctx, prop, value, error, () => {
|
|
70303
|
+
return ctx.reflect.set(prop, value, error);
|
|
70304
|
+
});
|
|
70305
|
+
} catch (e) {
|
|
70306
|
+
throw e === error ? enhanceError(e) : e;
|
|
70738
70307
|
}
|
|
70308
|
+
},
|
|
70309
|
+
has: (target, prop) => {
|
|
70310
|
+
if (isSpecialProperty(prop)) return Reflect.has(target, prop);
|
|
70311
|
+
if (Reflect.has(target, prop)) return true;
|
|
70312
|
+
return !!target.reflect.props[prop];
|
|
70313
|
+
}
|
|
70314
|
+
};
|
|
70315
|
+
/** Service implementations, keyed by isolation label. */
|
|
70316
|
+
store = Object.create(null);
|
|
70317
|
+
/** Declared context properties (services and accessors), by name. */
|
|
70318
|
+
props = Object.create(null);
|
|
70319
|
+
_implCounter = 0;
|
|
70320
|
+
constructor(ctx) {
|
|
70321
|
+
this.ctx = ctx;
|
|
70322
|
+
defineProperty(this, symbols.tracker, {
|
|
70323
|
+
property: "ctx",
|
|
70324
|
+
noShadow: true
|
|
70739
70325
|
});
|
|
70326
|
+
this.mixin("reflect", [
|
|
70327
|
+
"get",
|
|
70328
|
+
"set",
|
|
70329
|
+
"provide",
|
|
70330
|
+
"accessor",
|
|
70331
|
+
"mixin"
|
|
70332
|
+
]);
|
|
70333
|
+
this.mixin("fiber", ["runtime", "effect"]);
|
|
70334
|
+
this.mixin("registry", ["inject", "plugin"]);
|
|
70335
|
+
this.mixin("events", [
|
|
70336
|
+
"on",
|
|
70337
|
+
"once",
|
|
70338
|
+
"parallel",
|
|
70339
|
+
"emit",
|
|
70340
|
+
"serial",
|
|
70341
|
+
"bail",
|
|
70342
|
+
"waterfall"
|
|
70343
|
+
]);
|
|
70740
70344
|
}
|
|
70741
|
-
/**
|
|
70742
|
-
|
|
70743
|
-
|
|
70345
|
+
/**
|
|
70346
|
+
* Read a service from the store without the inject requirement.
|
|
70347
|
+
*
|
|
70348
|
+
* @param name — the service name.
|
|
70349
|
+
* @param strict — when `true`, only return implementations whose providing
|
|
70350
|
+
* fiber is currently active.
|
|
70351
|
+
* @returns the service value, or `undefined` when not (yet) provided.
|
|
70352
|
+
*/
|
|
70353
|
+
get(name, strict = true) {
|
|
70354
|
+
return getTraceable(this.ctx, this._getImpl(name, strict)?.value);
|
|
70744
70355
|
}
|
|
70745
|
-
|
|
70746
|
-
|
|
70747
|
-
|
|
70356
|
+
_getImpl(name, strict = true) {
|
|
70357
|
+
const key = this.ctx[symbols.isolate][name];
|
|
70358
|
+
const impl = key && this.store[key];
|
|
70359
|
+
if (!impl) return;
|
|
70360
|
+
if (strict && impl.ctx.fiber.state !== 2) return;
|
|
70361
|
+
return impl;
|
|
70748
70362
|
}
|
|
70749
70363
|
/**
|
|
70750
|
-
*
|
|
70751
|
-
*
|
|
70364
|
+
* Overwrite a provided service's value.
|
|
70365
|
+
*
|
|
70366
|
+
* @param name — the service name.
|
|
70367
|
+
* @param value — the new service value.
|
|
70368
|
+
* @param error — carrier for the caller stack in diagnostics.
|
|
70369
|
+
* @returns `true` on success.
|
|
70370
|
+
* @throws when `name` was never provided, or was provided by another fiber.
|
|
70752
70371
|
*/
|
|
70753
|
-
|
|
70754
|
-
|
|
70372
|
+
set(name, value, error) {
|
|
70373
|
+
const key = this.ctx[symbols.isolate][name];
|
|
70374
|
+
const impl = this.store[key];
|
|
70375
|
+
if (!impl) throw new Error(`cannot set property "${name}" without provide`);
|
|
70376
|
+
if (impl.ctx.fiber !== this.ctx.fiber) throw new Error(`cannot set property "${name}" in multiple fibers`);
|
|
70377
|
+
impl.value = value;
|
|
70378
|
+
return true;
|
|
70755
70379
|
}
|
|
70756
70380
|
/**
|
|
70757
|
-
*
|
|
70758
|
-
*
|
|
70759
|
-
*
|
|
70760
|
-
*
|
|
70761
|
-
* @
|
|
70762
|
-
* @
|
|
70381
|
+
* Register a service implementation owned by the current fiber.
|
|
70382
|
+
*
|
|
70383
|
+
* See the `ctx.provide()` overload above for the full contract.
|
|
70384
|
+
*
|
|
70385
|
+
* @param name — the service name.
|
|
70386
|
+
* @param value — the service value.
|
|
70387
|
+
* @param check — optional availability predicate for dependents.
|
|
70388
|
+
* @returns a disposer that unregisters the service.
|
|
70763
70389
|
*/
|
|
70764
|
-
|
|
70765
|
-
|
|
70766
|
-
|
|
70767
|
-
|
|
70390
|
+
provide(name, value, check) {
|
|
70391
|
+
return this.ctx.fiber.effect(() => {
|
|
70392
|
+
if (!this.props[name]) this.props[name] ??= { type: "service" };
|
|
70393
|
+
else if (this.props[name].type !== "service") throw new Error(`property "${name}" is already declared as ${this.props[name].type}`);
|
|
70394
|
+
this.props[name] = { type: "service" };
|
|
70395
|
+
this.ctx.root[symbols.isolate][name] ??= Symbol(name);
|
|
70396
|
+
const key = this.ctx[symbols.isolate][name];
|
|
70397
|
+
const impl = {
|
|
70398
|
+
uid: ++this._implCounter,
|
|
70399
|
+
name,
|
|
70400
|
+
value,
|
|
70401
|
+
ctx: this.ctx,
|
|
70402
|
+
check,
|
|
70403
|
+
isolate: key,
|
|
70404
|
+
dependents: /* @__PURE__ */ new Set()
|
|
70405
|
+
};
|
|
70406
|
+
if (this.store[key]) throw new Error(`service "${name}" has been registered at <${this.store[key].ctx.fiber.name}>`);
|
|
70407
|
+
this.store[key] = impl;
|
|
70408
|
+
this.ctx.fiber.provisions.add(impl);
|
|
70409
|
+
if (this.ctx.fiber.state === 2) this.notify([name]);
|
|
70410
|
+
return async () => {
|
|
70411
|
+
if (this.store[impl.isolate] === impl) delete this.store[impl.isolate];
|
|
70412
|
+
this.ctx.isolate(name, impl.isolate).reflect.notify([name]);
|
|
70413
|
+
await new Promise((resolve) => {
|
|
70414
|
+
impl.release = resolve;
|
|
70415
|
+
if (!impl.dependents.size) resolve();
|
|
70416
|
+
});
|
|
70417
|
+
impl.release = void 0;
|
|
70418
|
+
this.ctx.fiber.provisions.delete(impl);
|
|
70419
|
+
};
|
|
70420
|
+
}, `ctx.provide(${JSON.stringify(name)})`);
|
|
70768
70421
|
}
|
|
70769
|
-
|
|
70770
|
-
|
|
70771
|
-
|
|
70772
|
-
|
|
70773
|
-
|
|
70774
|
-
|
|
70775
|
-
|
|
70776
|
-
|
|
70777
|
-
|
|
70422
|
+
/**
|
|
70423
|
+
* Re-evaluate every fiber that requires one of the given services.
|
|
70424
|
+
*
|
|
70425
|
+
* @param names — the service names that changed.
|
|
70426
|
+
* @param filter — restricts notification to matching isolation scopes.
|
|
70427
|
+
*/
|
|
70428
|
+
notify(names, filter = (ctx, name) => ctx[symbols.isolate][name] === this.ctx[symbols.isolate][name]) {
|
|
70429
|
+
for (const runtime of this.ctx.registry.values()) for (const fiber of runtime.fibers) {
|
|
70430
|
+
let hasUpdate = false;
|
|
70431
|
+
for (const name of names) {
|
|
70432
|
+
if (!(name in fiber.inject)) continue;
|
|
70433
|
+
if (!filter(fiber.ctx, name)) continue;
|
|
70434
|
+
hasUpdate = true;
|
|
70435
|
+
fiber._checkImpl(name);
|
|
70778
70436
|
}
|
|
70779
|
-
|
|
70780
|
-
|
|
70781
|
-
|
|
70782
|
-
|
|
70437
|
+
if (!hasUpdate) continue;
|
|
70438
|
+
fiber._refresh();
|
|
70439
|
+
}
|
|
70440
|
+
for (const name of names) {
|
|
70441
|
+
const self = Object.create(this.ctx);
|
|
70442
|
+
self[symbols.filter] = (target) => filter(target, name);
|
|
70443
|
+
this.ctx.events.emit(self, "internal/service", name, this._getImpl(name, false)?.value);
|
|
70783
70444
|
}
|
|
70784
|
-
this._updateState(() => {
|
|
70785
|
-
if (this._runner.epoch === oldEpoch) this.inertia = void 0;
|
|
70786
|
-
else {
|
|
70787
|
-
this.inertia = this._unload();
|
|
70788
|
-
return 5;
|
|
70789
|
-
}
|
|
70790
|
-
});
|
|
70791
|
-
}
|
|
70792
|
-
async _unload() {
|
|
70793
|
-
await Promise.all(this._disposables.clear().map(async (dispose) => {
|
|
70794
|
-
try {
|
|
70795
|
-
await composeError(async (info) => {
|
|
70796
|
-
await Promise.resolve();
|
|
70797
|
-
info.error = /* @__PURE__ */ new Error();
|
|
70798
|
-
await runDisposable(dispose);
|
|
70799
|
-
}, this._runner.getOuterStack);
|
|
70800
|
-
} catch (reason) {
|
|
70801
|
-
this.ctx.logger.error(reason);
|
|
70802
|
-
}
|
|
70803
|
-
}));
|
|
70804
|
-
this.store = void 0;
|
|
70805
|
-
this._updateState(() => {
|
|
70806
|
-
if (this._runner.epoch === INACTIVE) this.inertia = void 0;
|
|
70807
|
-
else {
|
|
70808
|
-
this.inertia = this._reload();
|
|
70809
|
-
return 1;
|
|
70810
|
-
}
|
|
70811
|
-
});
|
|
70812
70445
|
}
|
|
70813
70446
|
/**
|
|
70814
|
-
*
|
|
70447
|
+
* Define a computed context property backed by get/set hooks.
|
|
70815
70448
|
*
|
|
70816
|
-
* @
|
|
70817
|
-
* @
|
|
70449
|
+
* @param name — the context property name.
|
|
70450
|
+
* @param options — the `get` hook and optional `set` hook.
|
|
70451
|
+
* @returns a disposer that removes the accessor.
|
|
70818
70452
|
*/
|
|
70819
|
-
|
|
70820
|
-
|
|
70821
|
-
|
|
70822
|
-
|
|
70453
|
+
accessor(name, options) {
|
|
70454
|
+
return this.ctx.fiber.effect(() => {
|
|
70455
|
+
if (name in this.props) throw new Error(`property "${name}" is already declared as ${this.props[name].type}`);
|
|
70456
|
+
this.props[name] = {
|
|
70457
|
+
type: "accessor",
|
|
70458
|
+
...options
|
|
70459
|
+
};
|
|
70460
|
+
return () => delete this.props[name];
|
|
70461
|
+
}, `ctx.accessor(${JSON.stringify(name)})`);
|
|
70823
70462
|
}
|
|
70824
70463
|
/**
|
|
70825
|
-
*
|
|
70464
|
+
* Expose selected members of a service directly on `ctx`.
|
|
70826
70465
|
*
|
|
70827
|
-
*
|
|
70828
|
-
*
|
|
70466
|
+
* See the `ctx.mixin()` overload above for the full contract.
|
|
70467
|
+
*
|
|
70468
|
+
* @param source — a context property name or a source object.
|
|
70469
|
+
* @param mixins — keys to forward, or a source-key → ctx-key map.
|
|
70470
|
+
* @returns a disposer that removes all created accessors.
|
|
70829
70471
|
*/
|
|
70830
|
-
|
|
70831
|
-
const
|
|
70832
|
-
fiber.
|
|
70833
|
-
|
|
70834
|
-
|
|
70835
|
-
|
|
70472
|
+
mixin(source, mixins) {
|
|
70473
|
+
const self = this;
|
|
70474
|
+
return this.ctx.fiber.effect(function* () {
|
|
70475
|
+
const entries = Array.isArray(mixins) ? mixins.map((key) => [key, key]) : Object.entries(mixins);
|
|
70476
|
+
const getTarget = (ctx, error) => {
|
|
70477
|
+
return ctx[source];
|
|
70478
|
+
};
|
|
70479
|
+
for (const [key, value] of entries) yield self.accessor(value, {
|
|
70480
|
+
get(receiver, error) {
|
|
70481
|
+
const service = getTarget(this, error);
|
|
70482
|
+
if (isNullable(service)) return service;
|
|
70483
|
+
const mixin = receiver ? withProps(receiver, service) : service;
|
|
70484
|
+
const value = Reflect.get(service, key, mixin);
|
|
70485
|
+
if (typeof value !== "function") return value;
|
|
70486
|
+
return value.bind(mixin ?? service);
|
|
70487
|
+
},
|
|
70488
|
+
set(value, receiver, error) {
|
|
70489
|
+
const service = getTarget(this, error);
|
|
70490
|
+
const mixin = receiver ? withProps(receiver, service) : service;
|
|
70491
|
+
return Reflect.set(service, key, value, mixin);
|
|
70492
|
+
}
|
|
70493
|
+
});
|
|
70494
|
+
}, `ctx.mixin(${JSON.stringify(source)})`);
|
|
70836
70495
|
}
|
|
70837
70496
|
/**
|
|
70838
|
-
*
|
|
70497
|
+
* Attach this context's tracing wrapper to a value.
|
|
70839
70498
|
*
|
|
70840
|
-
*
|
|
70841
|
-
*
|
|
70499
|
+
* @param value — the value to wrap.
|
|
70500
|
+
* @returns the traceable wrapper (or the value itself when not applicable).
|
|
70501
|
+
*/
|
|
70502
|
+
trace(value) {
|
|
70503
|
+
return getTraceable(this.ctx, value);
|
|
70504
|
+
}
|
|
70505
|
+
/**
|
|
70506
|
+
* Wrap a callback so calls trace `this` and arguments to this context.
|
|
70842
70507
|
*
|
|
70843
|
-
* @param
|
|
70844
|
-
* @
|
|
70845
|
-
* @returns nothing; the restart runs behind the `internal/update` waterfall.
|
|
70846
|
-
* @throws {ValidationError} when the new config fails validation.
|
|
70508
|
+
* @param callback — the function to wrap.
|
|
70509
|
+
* @returns a proxy delegating to `callback` with traced values.
|
|
70847
70510
|
*/
|
|
70848
|
-
|
|
70849
|
-
|
|
70850
|
-
|
|
70851
|
-
|
|
70852
|
-
|
|
70853
|
-
|
|
70854
|
-
|
|
70855
|
-
|
|
70856
|
-
return;
|
|
70857
|
-
}
|
|
70858
|
-
config = fiber.resolveConfig(config);
|
|
70859
|
-
fiber.context.waterfall(fiber, "internal/update", config, noSave, () => {
|
|
70860
|
-
fiber.config = config;
|
|
70861
|
-
fiber._error = void 0;
|
|
70862
|
-
return fiber.restart();
|
|
70511
|
+
bind(callback) {
|
|
70512
|
+
return new Proxy(callback, {
|
|
70513
|
+
apply: (target, thisArg, args) => {
|
|
70514
|
+
return Reflect.apply(target, this.trace(thisArg), args.map((arg) => this.trace(arg)));
|
|
70515
|
+
},
|
|
70516
|
+
construct: (target, args, newTarget) => {
|
|
70517
|
+
return Reflect.construct(target, args.map((arg) => this.trace(arg)), newTarget);
|
|
70518
|
+
}
|
|
70863
70519
|
});
|
|
70864
70520
|
}
|
|
70865
70521
|
};
|
|
@@ -74820,7 +74476,11 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
74820
74476
|
"dsh-capabilities/host/session-title-adapter.ts",
|
|
74821
74477
|
"host/features/session-title-optimization.ts",
|
|
74822
74478
|
"host/features/git-management.ts"
|
|
74823
|
-
]), route("settings.store", "legacy-settings-scope", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/settings.ts", "host/features/*"]), route("settings.store", "config-forms", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/settings.ts", "client/settings-bridge.ts"]), route("connection.rpc", "legacy-rpc-handler", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/rpc.ts"]), route("connection.rpc", "peer-aware-rpc-handler", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("connection.peer", "peer-scope", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("ui.icon.plus", "fixed-plus-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.plus", "regular-plus-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.chevron", "fixed-chevron-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/ui.ts"]), route("ui.icon.chevron", "regular-chevron-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("locale.runtime", "locale-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/locale.ts"]), route("theme.runtime", "theme-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/theme.ts"]), route("conversation.tool-call", "conversation-events", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/external-tool-stream.ts"]), route("sidebar.right", "sidebar-right-tabs", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("sidebar.global-panel", "sidebar-panellist-main-020", "client", DSH_COMPATIBILITY, "supported", ["dsh-capabilities/client/global-panel-adapter.ts", "client/features/magpie-management.ts"]), route("
|
|
74479
|
+
]), route("settings.store", "legacy-settings-scope", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/settings.ts", "host/features/*"]), route("settings.store", "config-forms", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/settings.ts", "client/settings-bridge.ts"]), route("connection.rpc", "legacy-rpc-handler", "host", ">=0.1.5-rc.3 <=0.1.6", "supported", ["host/rpc.ts"]), route("connection.rpc", "peer-aware-rpc-handler", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("connection.peer", "peer-scope", "host", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["host/rpc.ts"]), route("ui.icon.plus", "fixed-plus-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.plus", "regular-plus-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.chevron", "fixed-chevron-icon", "client", ">=0.1.5-rc.3 <=0.1.6", "supported", ["client/terminal/ui.ts"]), route("ui.icon.chevron", "regular-chevron-icon", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("locale.runtime", "locale-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/locale.ts"]), route("theme.runtime", "theme-runtime", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/theme.ts"]), route("conversation.tool-call", "conversation-events", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/external-tool-stream.ts"]), route("sidebar.right", "sidebar-right-tabs", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/terminal/ui.ts"]), route("sidebar.global-panel", "sidebar-panellist-main-020", "client", DSH_COMPATIBILITY, "supported", ["dsh-capabilities/client/global-panel-adapter.ts", "client/features/magpie-management.ts"]), route("ui.context-menu", "ui-context-menu-022", "client", ">=0.2.2-alpha.3", "supported", [
|
|
74480
|
+
"dsh-capabilities/client/context-menu-adapter.ts",
|
|
74481
|
+
"client/features/file-management.ts",
|
|
74482
|
+
"client/features/workspace-session-enhancement.ts"
|
|
74483
|
+
]), route("typert.remote", "remote-result", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/terminal/terminal-controller.ts", "client/terminal/model.ts"]), route("peer-host.store", "peer-host-store", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.handshake", "peer-host-handshake", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.http-proxy", "peer-host-http-proxy", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.ws-proxy", "peer-host-ws-proxy", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregate", "peer-host-aggregate", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.relay-route", "peer-host-relay-route", "host", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["host/features/peer-host.ts"]), route("peer-host.native-navigation", "peer-host-native-navigation-legacy", "client", ">=0.1.5-rc.3 <=0.1.6", "deprecated", ["client/features/peer-host.ts"]), route("peer-host.native-navigation", "peer-host-native-navigation-modern", "client", ">=0.1.7-rc.2 <=0.1.7-rc.2", "supported", ["client/features/peer-host.ts"]), route("peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback", "client", ">=0.1.5-rc.3 <=0.1.7-rc.2", "supported", ["client/features/peer-host.ts"]), route("settings.store", "settings-forms-020", "host", DSH_COMPATIBILITY, "supported", ["host/settings.ts", "host/rpc.ts"]), route("connection.rpc", "connection-rpc-020", "host", DSH_COMPATIBILITY, "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("connection.peer", "connection-peer-admission-020", "host", ">=0.2.1-alpha.2 <=0.2.1-alpha.2", "supported", ["host/rpc.ts"]), route("connection.attachment", "connection-rpc-attachment-020", "host", DSH_COMPATIBILITY, "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("connection.uplink", "connection-rpc-uplink-020", "host", ">=0.2.1-alpha.2 <=0.2.1-alpha.2", "supported", ["host/rpc.ts", "transport/dsh-transport.ts"]), route("typert.remote", "remote-context-stream-020", "host", DSH_COMPATIBILITY, "supported", ["host/terminal/terminal-controller.ts", "client/terminal/model.ts"]), route("typert.context", "typert-context-registry-020", "host", DSH_COMPATIBILITY, "supported", ["typert.host.ts", "host/terminal/terminal-controller.ts"]), route("typert.stream", "typert-remote-stream-020", "host", DSH_COMPATIBILITY, "supported", ["typert.host.ts", "typert.remote-client.ts"]), route("session.format-v4", "session-format-v4", "host", DSH_COMPATIBILITY, "supported", ["host/native-session-bridge.ts", "host/session-migration-repair.ts"]), route("subagent.continuable", "subagent-activation-021", "host", ">=0.2.1-alpha.2", "supported", ["host/cli-adapters/native-team-subagent.ts", "host/cli-adapters/native-subagent-dispatch.ts"]), route("agent-team.native", "agent-team-native-020", "host", DSH_COMPATIBILITY, "supported", ["host/cli-adapters/feature.ts", "host/cli-adapters/native-team-proxy.ts"]), route("agent-team.external-member", "agent-team-external-member-021", "host", ">=0.2.1-alpha.2", "supported", ["host/cli-adapters/feature.ts", "host/cli-bridge/team-dispatch.ts"]), route("agent-team.external-lead", "agent-team-external-lead-021", "host", ">=0.2.1-alpha.2", "supported", ["host/cli-adapters/feature.ts", "host/cli-bridge/team-dispatch.ts"]), route("ui.icon.plus", "regular-plus-icon-020", "client", DSH_COMPATIBILITY, "supported", ["client/terminal/xterm-view.ts"]), route("ui.icon.chevron", "regular-chevron-icon-020", "client", DSH_COMPATIBILITY, "supported", ["client/terminal/ui.ts"]), route("locale.runtime", "locale-runtime-020", "client", DSH_COMPATIBILITY, "supported", ["client/locale.ts"]), route("theme.runtime", "theme-runtime-020", "client", DSH_COMPATIBILITY, "supported", ["client/theme.ts"]), route("theme.font-scale", "theme-font-scale-021", "client", ">=0.2.1-alpha.2", "supported", ["client/font-scale.ts", "client/index.ts"]), route("conversation.tool-call", "conversation-events-020", "client", DSH_COMPATIBILITY, "supported", ["client/external-tool-stream.ts"]), route("conversation.draft-share", "conversation-draft-share-021", "client", ">=0.2.1-alpha.1", "supported", ["client/terminal/ui.ts", "client/terminal/sharing.ts"]), route("conversation.interaction-translation", "interaction-presentation-021", "client", DSH_COMPATIBILITY, "supported", ["client/session-translation-interactions.ts"]), route("sidebar.right", "sidebar-right-dock-020", "client", DSH_COMPATIBILITY, "supported", ["client/terminal/ui.ts"]), route("typert.remote", "remote-context-stream-020-client", "client", DSH_COMPATIBILITY, "supported", ["client/terminal/model.ts"]), route("typert.context", "typert-context-registry-020-client", "client", DSH_COMPATIBILITY, "supported", ["typert.remote-client.ts", "client/terminal/model.ts"]), route("typert.stream", "typert-remote-stream-020-client", "client", DSH_COMPATIBILITY, "supported", ["typert.remote-client.ts", "client/terminal/model.ts"]), route("client.boot-graph", "client-web-boot-graph-020", "client", DSH_COMPATIBILITY, "supported", ["client/index.ts", "package.json"]), route("peer-host.native-navigation", "peer-host-native-navigation-020", "client", DSH_COMPATIBILITY, "supported", ["client/features/peer-host.ts"]), route("peer-host.remote-web-context-fallback", "peer-host-remote-web-context-fallback-020", "client", DSH_COMPATIBILITY, "supported", ["client/features/peer-host.ts"]), route("peer-host.store", "peer-host-store-020", "host", DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.handshake", "peer-host-handshake-020", "host", DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.http-proxy", "peer-host-http-proxy-020", "host", DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts", "host/modules/peer-host/quick-app-gateway.ts"]), route("peer-host.ws-proxy", "peer-host-ws-proxy-020", "host", DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregate", "peer-host-aggregate-020", "host", DSH_COMPATIBILITY, "supported", ["host/features/peer-host.ts"]), route("peer-host.aggregated-transport", "peer-host-aggregated-transport-020", "host", DSH_COMPATIBILITY, "supported", ["host/modules/peer-host/aggregated-host-transport.ts"]), route("peer-host.client-preboot-transport", "peer-host-client-preboot-transport-020", "client", DSH_COMPATIBILITY, "supported", [
|
|
74824
74484
|
"bootstrap/index.ts",
|
|
74825
74485
|
"host/index-injection.ts",
|
|
74826
74486
|
"client/features/peer-host.ts"
|
|
@@ -74843,7 +74503,7 @@ button.${settingsPromoClass.version}:focus-visible{${focusRing}}
|
|
|
74843
74503
|
consumers
|
|
74844
74504
|
};
|
|
74845
74505
|
}
|
|
74846
|
-
// node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.2-
|
|
74506
|
+
// node_modules/.pnpm/@deepseek-ai+dsh-util-workspace-path@0.2.2-rc.1_@deepseek-ai+cordis@4.1.0/node_modules/@deepseek-ai/dsh-util-workspace-path/lib/index.js
|
|
74847
74507
|
/**
|
|
74848
74508
|
* The `dsh-resource://file/…` address grammar: how a file is named across the
|
|
74849
74509
|
* Sidebar and the resource model, built and parsed without touching a
|
|
@@ -80523,6 +80183,131 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
80523
80183
|
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
80524
80184
|
return bytes;
|
|
80525
80185
|
}
|
|
80186
|
+
// src/client/mobile-settings-modal-dom.ts
|
|
80187
|
+
/**
|
|
80188
|
+
* DSH 设置弹窗的移动端布局适配。
|
|
80189
|
+
*
|
|
80190
|
+
* 设置弹窗由 DSH 通过 portal 直接挂到 body,插件不能把样式写进自己的 React
|
|
80191
|
+
* 树。这里依赖唯一稳定的 `[data-shortcut-modal="settings"]` 钩子,再按设置根节点
|
|
80192
|
+
* 的稳定语义结构(`nav` 与内容列)注入一份可撤销的样式:窄屏时导航变成只显示
|
|
80193
|
+
* 图标的窄轨道,弹窗内容占满整个视口。桌面端不写属性、不注入样式,避免影响
|
|
80194
|
+
* DSH 原生布局。
|
|
80195
|
+
*/
|
|
80196
|
+
/** DSH 设置弹窗的稳定选择器。 */
|
|
80197
|
+
const MOBILE_SETTINGS_MODAL_SELECTOR = "[data-shortcut-modal=\"settings\"]";
|
|
80198
|
+
/** 插件在设置弹窗上挂载的移动端标记。 */
|
|
80199
|
+
const MOBILE_SETTINGS_MODAL_ATTRIBUTE = "data-codingns-mobile-settings";
|
|
80200
|
+
/** 插件样式标签的幂等键。 */
|
|
80201
|
+
const MOBILE_SETTINGS_MODAL_STYLE_ID = "codingns4dsh-mobile-settings-style";
|
|
80202
|
+
/** 默认按移动端处理的最大视口宽度。 */
|
|
80203
|
+
const MOBILE_SETTINGS_MODAL_DEFAULT_MAX_PX = 1024;
|
|
80204
|
+
/** 纯函数:判断一个视口是否按移动端设置布局处理。 */
|
|
80205
|
+
function isMobileSettingsViewport(width, maxPx = MOBILE_SETTINGS_MODAL_DEFAULT_MAX_PX) {
|
|
80206
|
+
return Number.isFinite(width) && width > 0 && Number.isFinite(maxPx) && maxPx > 0 && width <= maxPx;
|
|
80207
|
+
}
|
|
80208
|
+
/**
|
|
80209
|
+
* 启动设置弹窗移动端适配。
|
|
80210
|
+
*
|
|
80211
|
+
* React 每次打开设置都会重新创建 portal,因此同时监听 documentElement 的子树变更
|
|
80212
|
+
* 与窗口 resize。样式使用强制规则覆盖 DSH 的固定 800px/188px 布局,但只在插件
|
|
80213
|
+
* 自己标记的弹窗上生效;dispose 后完全移除标记和 style 标签。
|
|
80214
|
+
*/
|
|
80215
|
+
function startMobileSettingsModalDom(options = {}) {
|
|
80216
|
+
const dom = options.document ?? (typeof document === "undefined" ? void 0 : document);
|
|
80217
|
+
const win = options.window ?? (typeof window === "undefined" ? void 0 : window);
|
|
80218
|
+
const Observer = options.MutationObserver ?? (typeof MutationObserver === "undefined" ? void 0 : MutationObserver);
|
|
80219
|
+
const enabled = options.enabled ?? (() => true);
|
|
80220
|
+
const maxPx = () => {
|
|
80221
|
+
return (typeof options.mobileViewportMaxPx === "function" ? options.mobileViewportMaxPx() : options.mobileViewportMaxPx) ?? 1024;
|
|
80222
|
+
};
|
|
80223
|
+
let disposed = false;
|
|
80224
|
+
let queued = false;
|
|
80225
|
+
let marked = /* @__PURE__ */ new Set();
|
|
80226
|
+
const schedule = () => {
|
|
80227
|
+
if (disposed || queued) return;
|
|
80228
|
+
queued = true;
|
|
80229
|
+
queueMicrotask(() => {
|
|
80230
|
+
queued = false;
|
|
80231
|
+
sync();
|
|
80232
|
+
});
|
|
80233
|
+
};
|
|
80234
|
+
const sync = () => {
|
|
80235
|
+
if (disposed || dom === void 0) return;
|
|
80236
|
+
const active = enabled() && isMobileSettingsViewport(readViewportWidth(win), maxPx());
|
|
80237
|
+
const panels = active ? findSettingsPanels(dom) : [];
|
|
80238
|
+
const next = new Set(panels);
|
|
80239
|
+
for (const panel of marked) if (!next.has(panel)) panel.removeAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE);
|
|
80240
|
+
if (active && panels.length > 0) {
|
|
80241
|
+
installStyles(dom);
|
|
80242
|
+
for (const panel of panels) panel.setAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE, "on");
|
|
80243
|
+
} else removeStyles(dom);
|
|
80244
|
+
marked = next;
|
|
80245
|
+
};
|
|
80246
|
+
const observer = dom === void 0 || Observer === void 0 || dom.documentElement === void 0 ? void 0 : new Observer(() => schedule());
|
|
80247
|
+
if (observer !== void 0 && dom?.documentElement !== void 0) observer.observe(dom.documentElement, {
|
|
80248
|
+
childList: true,
|
|
80249
|
+
subtree: true,
|
|
80250
|
+
attributes: true,
|
|
80251
|
+
attributeFilter: ["data-shortcut-modal"]
|
|
80252
|
+
});
|
|
80253
|
+
const onResize = () => schedule();
|
|
80254
|
+
win?.addEventListener?.("resize", onResize);
|
|
80255
|
+
sync();
|
|
80256
|
+
return {
|
|
80257
|
+
refresh: sync,
|
|
80258
|
+
dispose() {
|
|
80259
|
+
if (disposed) return;
|
|
80260
|
+
disposed = true;
|
|
80261
|
+
observer?.disconnect();
|
|
80262
|
+
win?.removeEventListener?.("resize", onResize);
|
|
80263
|
+
for (const panel of marked) panel.removeAttribute(MOBILE_SETTINGS_MODAL_ATTRIBUTE);
|
|
80264
|
+
marked = /* @__PURE__ */ new Set();
|
|
80265
|
+
removeStyles(dom);
|
|
80266
|
+
}
|
|
80267
|
+
};
|
|
80268
|
+
}
|
|
80269
|
+
/** 读取窗口宽度;没有浏览器窗口时返回 0,确保适配默认不生效。 */
|
|
80270
|
+
function readViewportWidth(win) {
|
|
80271
|
+
const width = win?.innerWidth;
|
|
80272
|
+
if (typeof width === "number" && Number.isFinite(width) && width > 0) return width;
|
|
80273
|
+
const fallback = globalThis.innerWidth;
|
|
80274
|
+
return typeof fallback === "number" && Number.isFinite(fallback) && fallback > 0 ? fallback : 0;
|
|
80275
|
+
}
|
|
80276
|
+
function findSettingsPanels(dom) {
|
|
80277
|
+
return Array.from(dom.querySelectorAll(MOBILE_SETTINGS_MODAL_SELECTOR));
|
|
80278
|
+
}
|
|
80279
|
+
function installStyles(dom) {
|
|
80280
|
+
if (dom.head === void 0 || dom.head === null) return;
|
|
80281
|
+
if (Array.from(dom.head.children).some((child) => child.tagName === "STYLE" && child.dataset.pluginCss === "codingns4dsh-mobile-settings-style")) return;
|
|
80282
|
+
const style = dom.createElement("style");
|
|
80283
|
+
style.dataset.plugin = "codingns4dsh";
|
|
80284
|
+
style.dataset.pluginCss = MOBILE_SETTINGS_MODAL_STYLE_ID;
|
|
80285
|
+
style.textContent = MOBILE_SETTINGS_MODAL_STYLE_TEXT;
|
|
80286
|
+
dom.head.appendChild(style);
|
|
80287
|
+
}
|
|
80288
|
+
function removeStyles(dom) {
|
|
80289
|
+
if (dom?.head === void 0 || dom.head === null) return;
|
|
80290
|
+
for (const child of Array.from(dom.head.children)) {
|
|
80291
|
+
if (child.tagName !== "STYLE") continue;
|
|
80292
|
+
if (child.dataset.pluginCss !== "codingns4dsh-mobile-settings-style") continue;
|
|
80293
|
+
child.remove();
|
|
80294
|
+
}
|
|
80295
|
+
}
|
|
80296
|
+
/**
|
|
80297
|
+
* 只依赖设置根节点的语义结构,不依赖 DSH 的 CSS module 哈希类名。
|
|
80298
|
+
* `nav` 第一列保留按钮和图标,文字使用视觉隐藏保留可访问名称;右侧内容列
|
|
80299
|
+
* 继续由 DSH 自己的 flex 规则伸展到剩余空间。
|
|
80300
|
+
*/
|
|
80301
|
+
const MOBILE_SETTINGS_MODAL_STYLE_TEXT = [
|
|
80302
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]{box-sizing:border-box!important;width:100vw!important;max-width:none!important;height:100%!important;max-height:none!important;border-radius:0!important}`,
|
|
80303
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav{box-sizing:border-box!important;flex:0 0 60px!important;width:60px!important;min-width:60px!important;gap:12px!important;padding:16px 8px 0!important}`,
|
|
80304
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:first-child{box-sizing:border-box!important;width:44px!important;height:24px!important;padding:0!important;overflow:hidden!important;font-size:0!important;line-height:0!important;text-indent:-9999px!important}`,
|
|
80305
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child{box-sizing:border-box!important;align-items:center!important;gap:4px!important}`,
|
|
80306
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child>button{box-sizing:border-box!important;justify-content:center!important;width:44px!important;height:44px!important;padding:9px!important;gap:0!important}`,
|
|
80307
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>nav>:last-child>button>span{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}`,
|
|
80308
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>div{box-sizing:border-box!important;min-width:0!important;flex:1 1 auto!important;width:auto!important}`,
|
|
80309
|
+
`[${MOBILE_SETTINGS_MODAL_ATTRIBUTE}="on"]>div>div:last-child{box-sizing:border-box!important;min-width:0!important;width:100%!important;padding-left:8px!important;padding-right:8px!important}`
|
|
80310
|
+
].join("");
|
|
80526
80311
|
// src/client/index.ts
|
|
80527
80312
|
/** Client Runner 用于等待核心服务就绪的 Cordis 依赖声明。 */
|
|
80528
80313
|
const inject = [
|
|
@@ -80598,6 +80383,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
80598
80383
|
require_magpie_model_tag.debugInfo("codingns4dsh: client terminal UI registration ready");
|
|
80599
80384
|
const hostRouter = new HostRouter();
|
|
80600
80385
|
const peerHost = createPeerHostScopedClient(connection.rpc);
|
|
80386
|
+
const contextMenus = readContextMenus(settingsCtx);
|
|
80601
80387
|
const services = {
|
|
80602
80388
|
dshVersion,
|
|
80603
80389
|
stage0: isInjectedStage0Runtime(),
|
|
@@ -80616,7 +80402,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
80616
80402
|
layout: settingsCtx.layout,
|
|
80617
80403
|
sidebarRight: settingsCtx.sidebarRight,
|
|
80618
80404
|
notifications: createPwaNotificationClient(),
|
|
80619
|
-
uiContext: settingsCtx
|
|
80405
|
+
uiContext: settingsCtx,
|
|
80406
|
+
...contextMenus === void 0 ? {} : { contextMenus }
|
|
80620
80407
|
};
|
|
80621
80408
|
require_magpie_model_tag.debugInfo("codingns4dsh: client account bar registration begin");
|
|
80622
80409
|
const disposeAccountBar = startCodingNsAccountBar(connection.rpc, void 0, settings, settingsCtx.locale);
|
|
@@ -80802,5 +80589,5 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
80802
80589
|
});
|
|
80803
80590
|
|
|
80804
80591
|
})();
|
|
80805
|
-
// codingns-client-revision:
|
|
80592
|
+
// codingns-client-revision: 85e045cd1f9012d2f7c4dae9f20df83cafd33ea31f582881dc2f33b067d4af23
|
|
80806
80593
|
//# sourceMappingURL=bundle.js.map
|