dsh-edge 0.2.0-alpha.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +6 -6
- package/README.zh.md +6 -6
- package/THIRD_PARTY_NOTICES.md +387 -1131
- package/dist/assets/index-BNMwCG9c.css +1 -0
- package/dist/assets/index-CA9Bpko5.js +96 -0
- package/dist/assets/langs/{php-D-uCvoST.js → php-DDkx9sim.js} +2 -2
- package/dist/assets/langs/{ruby-DEItuUFs.js → ruby-DCxyoPen.js} +2 -2
- package/dist/assets/{vendor-Cjbwl5VI.js → vendor-D22_Mp1f.js} +2 -2
- package/dist/index.html +26 -5
- package/dist/plugins/@deepseek-ai/dsh-api-remotes/client.js +166 -27
- package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +136 -19
- package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +51 -12
- package/dist/plugins/@deepseek-ai/dsh-client-modules/client.js +188 -123
- package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +43 -8
- package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +54 -54
- package/dist/plugins/@deepseek-ai/dsh-client-ui-brand-official/client.js +50 -0
- package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +46 -17
- package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +805 -486
- package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +5 -5
- package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +82 -26
- package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +7 -7
- package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +2 -2
- package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +18 -18
- package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +96 -82
- package/dist/plugins/@deepseek-ai/dsh-client-ui-renderer/client.js +989 -0
- package/dist/plugins/@deepseek-ai/dsh-client-ui-settings/client.js +1177 -67
- package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +61 -65
- package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +51 -21
- package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +12 -12
- package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +18 -45
- package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +46 -3
- package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +102 -62
- package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +143 -142
- package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +25 -25
- package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +261 -86
- package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +72 -62
- package/package.json +22 -22
- package/scripts/legal-files.mjs +2 -1
- package/worker/direct/index.js +692 -688
- package/worker/isolated/index.js +469 -465
- package/dist/assets/index-C-1AiF3k.js +0 -112
- package/dist/assets/index-CSGf6Qzd.css +0 -1
|
@@ -5360,6 +5360,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5360
5360
|
maxImagesPerMessage: number().int().positive(),
|
|
5361
5361
|
maxMessageImageBytes: number().int().positive(),
|
|
5362
5362
|
maxImagePixels: number().int().positive(),
|
|
5363
|
+
maxImageDimension: number().int().positive(),
|
|
5363
5364
|
mediaTypes: array(string())
|
|
5364
5365
|
});
|
|
5365
5366
|
/** session.history response value (projections rides the tail page only). */
|
|
@@ -5707,6 +5708,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5707
5708
|
provider: string().optional(),
|
|
5708
5709
|
model: string().optional(),
|
|
5709
5710
|
attachedSessions: number().int().nonnegative(),
|
|
5711
|
+
home: string(),
|
|
5710
5712
|
canOpenPath: boolean()
|
|
5711
5713
|
});
|
|
5712
5714
|
object({});
|
|
@@ -7084,7 +7086,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7084
7086
|
toolTurn(67, "grep", "{\"pattern\":\"SEARCH_MAX_LINES\",\"path\":\"packages/client\"}", SEARCH_MATCHES_TEXT);
|
|
7085
7087
|
toolTurn(68, "glob", "{\"pattern\":\"**/SearchBlock*\",\"path\":\"packages/client\"}", SEARCH_PATHS_TEXT);
|
|
7086
7088
|
toolTurn(69, "read", `{"file_path":${JSON.stringify(READ_SAMPLE_PATH)},"offset":${READ_SAMPLE_FIRST_LINE}}`, READ_SAMPLE_TEXT);
|
|
7087
|
-
toolTurn(70, "web_search", "{\"
|
|
7089
|
+
toolTurn(70, "web_search", "{\"queries\":[\"deepseek harness architecture\"]}", "Search results for deepseek harness architecture.");
|
|
7088
7090
|
toolTurn(71, "web_fetch", "{\"url\":\"https://www.deepseek.com/blog/harness-architecture\"}", "# Harness architecture\n\nEverything is a plugin.");
|
|
7089
7091
|
push({
|
|
7090
7092
|
type: "turn/start",
|
|
@@ -7264,7 +7266,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7264
7266
|
};
|
|
7265
7267
|
case "web_search": return {
|
|
7266
7268
|
card: "generic",
|
|
7267
|
-
title: `Search ${
|
|
7269
|
+
title: `Search ${(Array.isArray(args.queries) ? args.queries.filter((query) => typeof query === "string" && query !== "") : []).join(", ")}`,
|
|
7268
7270
|
kind: "search",
|
|
7269
7271
|
rawInput: args
|
|
7270
7272
|
};
|
|
@@ -7357,29 +7359,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7357
7359
|
}
|
|
7358
7360
|
}
|
|
7359
7361
|
/**
|
|
7360
|
-
* Fixture parallel of the plan unit's
|
|
7361
|
-
*
|
|
7362
|
-
*
|
|
7363
|
-
*
|
|
7362
|
+
* Fixture parallel of the plan unit's lifecycle fold. The paired
|
|
7363
|
+
* `command/done` retains successful plan selections and drops failures;
|
|
7364
|
+
* `plan/mode` commits one. `wanted` is exposed for the prompt boundary (the
|
|
7365
|
+
* fixture's step/start parallel).
|
|
7364
7366
|
*/
|
|
7365
7367
|
function foldPlan(log) {
|
|
7366
7368
|
let active = false;
|
|
7367
7369
|
let wanted = null;
|
|
7370
|
+
let running = null;
|
|
7368
7371
|
for (const event of log) {
|
|
7369
7372
|
const item = event;
|
|
7370
7373
|
if (item.type === "command/run" && item.data?.["name"] === "plan") {
|
|
7371
7374
|
const args = item.data["args"];
|
|
7372
7375
|
if (typeof args !== "string") continue;
|
|
7373
|
-
|
|
7376
|
+
running = {
|
|
7377
|
+
commandId: item.data["commandId"],
|
|
7378
|
+
wanted: args.trim() !== "off"
|
|
7379
|
+
};
|
|
7380
|
+
} else if (item.type === "command/done" && item.data !== void 0 && running !== null && item.data["commandId"] === running.commandId) {
|
|
7381
|
+
wanted = item.data["kind"] === "success" && running.wanted !== active ? running.wanted : null;
|
|
7382
|
+
running = null;
|
|
7374
7383
|
} else if (item.type === "plan/mode") {
|
|
7375
7384
|
active = item.data?.["active"] === true;
|
|
7376
7385
|
wanted = null;
|
|
7377
7386
|
}
|
|
7378
7387
|
}
|
|
7388
|
+
const selected = running?.wanted ?? wanted;
|
|
7379
7389
|
return {
|
|
7380
7390
|
active,
|
|
7381
|
-
pending:
|
|
7382
|
-
wanted
|
|
7391
|
+
pending: selected !== null && selected !== active,
|
|
7392
|
+
wanted: selected
|
|
7383
7393
|
};
|
|
7384
7394
|
}
|
|
7385
7395
|
/** The plan projection's wire view over the full log. */
|
|
@@ -7619,6 +7629,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7619
7629
|
maxImagesPerMessage: 20,
|
|
7620
7630
|
maxMessageImageBytes: 100 * 1024 * 1024,
|
|
7621
7631
|
maxImagePixels: 4e7,
|
|
7632
|
+
maxImageDimension: 2e3,
|
|
7622
7633
|
mediaTypes: [
|
|
7623
7634
|
"image/png",
|
|
7624
7635
|
"image/jpeg",
|
|
@@ -7985,6 +7996,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7985
7996
|
let attachedSessions = options.empty ? 0 : 1;
|
|
7986
7997
|
const wid = (raw) => raw;
|
|
7987
7998
|
const fixtureEpoch = (/* @__PURE__ */ new Date(Date.now() - 3e5)).toISOString();
|
|
7999
|
+
const FIXTURE_HOME = "/home/fixture";
|
|
7988
8000
|
const workspaces = options.empty ? [] : [{
|
|
7989
8001
|
workspaceId: wid("fx-ws-fixture"),
|
|
7990
8002
|
path: "/tmp/fixture",
|
|
@@ -7996,10 +8008,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7996
8008
|
],
|
|
7997
8009
|
createdAt: fixtureEpoch,
|
|
7998
8010
|
updatedAt: fixtureEpoch
|
|
8011
|
+
}, {
|
|
8012
|
+
workspaceId: wid("fx-ws-home"),
|
|
8013
|
+
path: `${FIXTURE_HOME}/Documents/project`,
|
|
8014
|
+
title: "project",
|
|
8015
|
+
sessionIds: [],
|
|
8016
|
+
createdAt: fixtureEpoch,
|
|
8017
|
+
updatedAt: fixtureEpoch
|
|
7999
8018
|
}];
|
|
8000
8019
|
let nextWorkspace = 1;
|
|
8001
8020
|
const archivedSessionIds = [];
|
|
8002
|
-
const FIXTURE_HOME = "/home/fixture";
|
|
8003
8021
|
const directoryTree = new Map([
|
|
8004
8022
|
["/", ["home"]],
|
|
8005
8023
|
["/home", ["fixture"]],
|
|
@@ -8227,7 +8245,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8227
8245
|
{
|
|
8228
8246
|
name: "goal",
|
|
8229
8247
|
description: "set or view the goal for a long-running task",
|
|
8230
|
-
input: {
|
|
8248
|
+
input: {
|
|
8249
|
+
hint: "<objective>",
|
|
8250
|
+
images: true
|
|
8251
|
+
}
|
|
8231
8252
|
},
|
|
8232
8253
|
{
|
|
8233
8254
|
name: "permission",
|
|
@@ -8237,17 +8258,59 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8237
8258
|
{
|
|
8238
8259
|
name: "plan",
|
|
8239
8260
|
description: "Enter or leave plan mode",
|
|
8240
|
-
input: {
|
|
8261
|
+
input: {
|
|
8262
|
+
hint: "[off|message]",
|
|
8263
|
+
images: true
|
|
8264
|
+
}
|
|
8241
8265
|
}
|
|
8242
8266
|
]
|
|
8243
8267
|
};
|
|
8244
8268
|
},
|
|
8245
|
-
execute(id, line) {
|
|
8269
|
+
execute(id, line, images = []) {
|
|
8246
8270
|
const missing = requireGoalSession(id);
|
|
8247
8271
|
if (missing !== void 0) return missing;
|
|
8248
8272
|
const match = /^\/(\S+)((?:\s.*)?)$/.exec(line.trim());
|
|
8249
8273
|
const name = match?.[1];
|
|
8250
8274
|
const args = match?.[2] ?? "";
|
|
8275
|
+
if (images.length > 0 && name !== void 0 && [
|
|
8276
|
+
"permission",
|
|
8277
|
+
"goal",
|
|
8278
|
+
"compact",
|
|
8279
|
+
"echo",
|
|
8280
|
+
"plan"
|
|
8281
|
+
].includes(name)) {
|
|
8282
|
+
const rejection = name !== "goal" && name !== "plan" ? `/${name} does not accept image attachments` : name === "goal" && args.trim() === "" ? "Image attachments only accompany a goal objective: /goal <objective> or /goal edit <objective>." : name === "plan" && args.trim() === "off" ? "Image attachments cannot accompany /plan off." : void 0;
|
|
8283
|
+
if (rejection !== void 0) {
|
|
8284
|
+
const commandId = `fx-cmd-${logOf(id).length}`;
|
|
8285
|
+
append(id, {
|
|
8286
|
+
type: "command/run",
|
|
8287
|
+
data: {
|
|
8288
|
+
commandId,
|
|
8289
|
+
name,
|
|
8290
|
+
args,
|
|
8291
|
+
source: { kind: "user" }
|
|
8292
|
+
}
|
|
8293
|
+
});
|
|
8294
|
+
const result = {
|
|
8295
|
+
kind: "error",
|
|
8296
|
+
text: rejection
|
|
8297
|
+
};
|
|
8298
|
+
append(id, {
|
|
8299
|
+
type: "command/done",
|
|
8300
|
+
data: {
|
|
8301
|
+
commandId,
|
|
8302
|
+
...result
|
|
8303
|
+
}
|
|
8304
|
+
});
|
|
8305
|
+
return {
|
|
8306
|
+
ok: true,
|
|
8307
|
+
value: {
|
|
8308
|
+
commandId,
|
|
8309
|
+
result
|
|
8310
|
+
}
|
|
8311
|
+
};
|
|
8312
|
+
}
|
|
8313
|
+
}
|
|
8251
8314
|
if (name === "permission") {
|
|
8252
8315
|
const preset = args.trim();
|
|
8253
8316
|
const commandId = `fx-cmd-${logOf(id).length}`;
|
|
@@ -8409,6 +8472,50 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8409
8472
|
activation: projection.goal.phase === "active" ? "armed" : "disarmed"
|
|
8410
8473
|
});
|
|
8411
8474
|
/** Canonical fixture implementation of the generated Goal Remote contract. */
|
|
8475
|
+
/** Canonical fixture implementation of the generated reference-discovery Remote contracts. */
|
|
8476
|
+
const referenceRemotes = {
|
|
8477
|
+
files(id, query) {
|
|
8478
|
+
const missing = requireGoalSession(id);
|
|
8479
|
+
if (missing !== void 0) return missing;
|
|
8480
|
+
const needle = query.toLocaleLowerCase();
|
|
8481
|
+
return {
|
|
8482
|
+
ok: true,
|
|
8483
|
+
value: [
|
|
8484
|
+
{
|
|
8485
|
+
path: "notes",
|
|
8486
|
+
kind: "directory"
|
|
8487
|
+
},
|
|
8488
|
+
{
|
|
8489
|
+
path: "README.md",
|
|
8490
|
+
kind: "file"
|
|
8491
|
+
},
|
|
8492
|
+
{
|
|
8493
|
+
path: "notes/demo.txt",
|
|
8494
|
+
kind: "file"
|
|
8495
|
+
}
|
|
8496
|
+
].filter((item) => item.path.toLocaleLowerCase().includes(needle))
|
|
8497
|
+
};
|
|
8498
|
+
},
|
|
8499
|
+
sessions(id, query) {
|
|
8500
|
+
const missing = requireGoalSession(id);
|
|
8501
|
+
if (missing !== void 0) return missing;
|
|
8502
|
+
const needle = query.toLocaleLowerCase();
|
|
8503
|
+
return {
|
|
8504
|
+
ok: true,
|
|
8505
|
+
value: sessions.filter((item) => item.sessionId !== id).filter((item) => String(item.sessionId).toLocaleLowerCase().includes(needle) || item.cwd?.toLocaleLowerCase().includes(needle) === true).map((item) => {
|
|
8506
|
+
const label = item.sessionId === sid("fx-beta") ? "Fixture child session" : String(item.sessionId);
|
|
8507
|
+
const encoded = btoa(JSON.stringify(item.sessionId)).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
|
|
8508
|
+
return {
|
|
8509
|
+
sessionId: item.sessionId,
|
|
8510
|
+
label,
|
|
8511
|
+
...item.cwd === void 0 ? {} : { cwd: item.cwd },
|
|
8512
|
+
createdAt: item.updatedAt,
|
|
8513
|
+
mention: `@[${label}](dsh-session:${encoded})`
|
|
8514
|
+
};
|
|
8515
|
+
})
|
|
8516
|
+
};
|
|
8517
|
+
}
|
|
8518
|
+
};
|
|
8412
8519
|
const goalRemotes = {
|
|
8413
8520
|
create(id, request) {
|
|
8414
8521
|
const missing = requireGoalSession(id);
|
|
@@ -9204,11 +9311,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9204
9311
|
message: `no session ${id}`,
|
|
9205
9312
|
details: { sessionId: id }
|
|
9206
9313
|
});
|
|
9207
|
-
if (options.rejectPrompt)
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9314
|
+
if (options.rejectPrompt) {
|
|
9315
|
+
if (content.some((block) => block.type === "image")) return err(request, {
|
|
9316
|
+
code: "attachment-error",
|
|
9317
|
+
message: "fixture: image side exceeds the deployment limit",
|
|
9318
|
+
details: { reason: "IMAGE_DIMENSION_TOO_LARGE" }
|
|
9319
|
+
});
|
|
9320
|
+
return err(request, {
|
|
9321
|
+
code: "agent-busy",
|
|
9322
|
+
message: "fixture: prompt rejected before acceptance",
|
|
9323
|
+
details: { reason: "fixture-prompt-rejection" }
|
|
9324
|
+
});
|
|
9325
|
+
}
|
|
9212
9326
|
summary.updatedAt = Date.now();
|
|
9213
9327
|
summary.blank = false;
|
|
9214
9328
|
const userText = content.map((b) => b.type === "text" ? b.text : "").join("");
|
|
@@ -9319,6 +9433,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9319
9433
|
version: "0.0.0-fixture",
|
|
9320
9434
|
cwd: "/tmp/fixture",
|
|
9321
9435
|
attachedSessions,
|
|
9436
|
+
home: FIXTURE_HOME,
|
|
9322
9437
|
canOpenPath: true
|
|
9323
9438
|
}),
|
|
9324
9439
|
pickDirectory: (request) => ok(request, { path: `${FIXTURE_HOME}/Documents/project` }),
|
|
@@ -9831,7 +9946,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9831
9946
|
const sessionId = args.agentId;
|
|
9832
9947
|
switch (endpoint) {
|
|
9833
9948
|
case "commands/list": return Promise.resolve(commandRemotes.list(sessionId));
|
|
9834
|
-
case "commands/execute": return Promise.resolve(commandRemotes.execute(sessionId, args.line));
|
|
9949
|
+
case "commands/execute": return Promise.resolve(commandRemotes.execute(sessionId, args.line, args.images ?? []));
|
|
9950
|
+
case "fileReferences/list": return Promise.resolve(referenceRemotes.files(sessionId, args.query ?? ""));
|
|
9951
|
+
case "sessionReferenceResolver/candidates": return Promise.resolve(referenceRemotes.sessions(sessionId, args.query ?? ""));
|
|
9835
9952
|
case "goals/create": return Promise.resolve(goalRemotes.create(sessionId, {
|
|
9836
9953
|
objective: args.request?.objective,
|
|
9837
9954
|
...args.request?.maxGoalRounds === void 0 ? {} : { maxGoalRounds: args.request.maxGoalRounds }
|
|
@@ -886,11 +886,11 @@ window.__ModuleLoader__.load({
|
|
|
886
886
|
document.head.appendChild(tag);
|
|
887
887
|
}
|
|
888
888
|
var LanguageRow_module_css_default = {
|
|
889
|
-
"
|
|
890
|
-
"rowText": "hVGvvW_rowText",
|
|
891
|
-
"title": "hVGvvW_title",
|
|
889
|
+
"chevron": "hVGvvW_chevron",
|
|
892
890
|
"row": "hVGvvW_row",
|
|
893
|
-
"
|
|
891
|
+
"rowText": "hVGvvW_rowText",
|
|
892
|
+
"selector": "hVGvvW_selector",
|
|
893
|
+
"title": "hVGvvW_title"
|
|
894
894
|
};
|
|
895
895
|
//#endregion
|
|
896
896
|
//#region lib/types/client/LanguageRow.js
|
|
@@ -975,8 +975,16 @@ window.__ModuleLoader__.load({
|
|
|
975
975
|
}
|
|
976
976
|
//#endregion
|
|
977
977
|
//#region lib/types/client/index.js
|
|
978
|
-
/**
|
|
979
|
-
|
|
978
|
+
/**
|
|
979
|
+
* English is both the locale the UI opens in when the browser names no shipped
|
|
980
|
+
* language (and for non-browser runs), and the dictionary consulted after the
|
|
981
|
+
* active locale misses a key. One constant serves both because the shipped
|
|
982
|
+
* `zh`/`en` dictionaries carry identical key sets, so neither direction can
|
|
983
|
+
* leave a key unresolved; the residual case points at English rather than
|
|
984
|
+
* zh because a browser naming neither shipped language is the reader least
|
|
985
|
+
* likely to read Chinese.
|
|
986
|
+
*/
|
|
987
|
+
const FALLBACK_LOCALE = "en";
|
|
980
988
|
/** Shared namespace for shell-level texts. */
|
|
981
989
|
const COMMON_NS = "common";
|
|
982
990
|
/** Namespace owning this feature's settings-row copy. */
|
|
@@ -990,9 +998,31 @@ window.__ModuleLoader__.load({
|
|
|
990
998
|
label: "English"
|
|
991
999
|
}]);
|
|
992
1000
|
/**
|
|
1001
|
+
* `<html lang>` tag per shipped locale. The locale id is the app's own
|
|
1002
|
+
* vocabulary (primary subtag); the document attribute wants a BCP 47 tag,
|
|
1003
|
+
* which assistive technology and browser features (pronunciation rules,
|
|
1004
|
+
* translation offers, font fallback, spell check) read to pick their own
|
|
1005
|
+
* behavior. `zh` alone leaves the script ambiguous, so the shipped Chinese
|
|
1006
|
+
* copy names the variant it actually is.
|
|
1007
|
+
*/
|
|
1008
|
+
const DOCUMENT_LANGUAGE = {
|
|
1009
|
+
zh: "zh-CN",
|
|
1010
|
+
en: "en"
|
|
1011
|
+
};
|
|
1012
|
+
/**
|
|
1013
|
+
* Point `<html lang>` at the active locale. Called on every locale change,
|
|
1014
|
+
* so the attribute tracks the UI instead of standing at whatever the served
|
|
1015
|
+
* markup happened to declare.
|
|
1016
|
+
* @param active - the active locale id.
|
|
1017
|
+
*/
|
|
1018
|
+
function syncDocumentLanguage(active) {
|
|
1019
|
+
if (typeof document === "undefined") return;
|
|
1020
|
+
document.documentElement.lang = DOCUMENT_LANGUAGE[active];
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
993
1023
|
* Dictionary registry plus locale preference. Lookup chain per key: the
|
|
994
|
-
* entry's namespace in the active locale -> that namespace's
|
|
995
|
-
* the shared common namespace (active, then
|
|
1024
|
+
* entry's namespace in the active locale -> that namespace's en fallback ->
|
|
1025
|
+
* the shared common namespace (active, then en) -> the key itself (missing
|
|
996
1026
|
* text stays visible, fail loud in the UI rather than blank). Reads go
|
|
997
1027
|
* through {@link getLocale}; writes only through {@link setLocale};
|
|
998
1028
|
* continuous sync through the `locale/change` event, or through the
|
|
@@ -1060,13 +1090,20 @@ window.__ModuleLoader__.load({
|
|
|
1060
1090
|
}
|
|
1061
1091
|
/**
|
|
1062
1092
|
* Switch the active locale — the only user preference write entry.
|
|
1093
|
+
*
|
|
1094
|
+
* The durable write happens even when the id already matches the active
|
|
1095
|
+
* locale, because the active value may be a provisional browser-derived or
|
|
1096
|
+
* fallback resolution that nothing has stored yet. Picking the language
|
|
1097
|
+
* already on screen is still an explicit choice, and it must survive a
|
|
1098
|
+
* different browser sharing the same DSH home. Only the render notification
|
|
1099
|
+
* is conditional: republishing an unchanged locale would churn every
|
|
1100
|
+
* subscriber for nothing.
|
|
1063
1101
|
* @param id - a registered locale id; unknown ids throw.
|
|
1064
1102
|
*/
|
|
1065
1103
|
setLocale(id) {
|
|
1066
1104
|
const match = this.snapshot.locales.find((l) => l.id === id);
|
|
1067
1105
|
if (match === void 0) throw new Error(`locale "${id}" is not registered`);
|
|
1068
|
-
if (this.snapshot.active
|
|
1069
|
-
this.publish(match.id, true);
|
|
1106
|
+
if (this.snapshot.active !== match.id) this.publish(match.id, true);
|
|
1070
1107
|
this.host?.set(LOCALE_PREFERENCE_FIELD, match.id);
|
|
1071
1108
|
}
|
|
1072
1109
|
/**
|
|
@@ -1120,7 +1157,7 @@ window.__ModuleLoader__.load({
|
|
|
1120
1157
|
}
|
|
1121
1158
|
lookup(ns, key) {
|
|
1122
1159
|
const locales = this.dicts.get(ns);
|
|
1123
|
-
return locales?.get(this.snapshot.active)?.[key] ?? locales?.get("
|
|
1160
|
+
return locales?.get(this.snapshot.active)?.[key] ?? locales?.get("en")?.[key];
|
|
1124
1161
|
}
|
|
1125
1162
|
/**
|
|
1126
1163
|
* Advance the snapshot revision and notify LocaleFace subscribers (render
|
|
@@ -1148,7 +1185,7 @@ window.__ModuleLoader__.load({
|
|
|
1148
1185
|
* Host preference may replace this provisional value after plugin activation.
|
|
1149
1186
|
*/
|
|
1150
1187
|
function resolveInitialLocale() {
|
|
1151
|
-
return detectBrowserLocale() ?? "
|
|
1188
|
+
return detectBrowserLocale() ?? "en";
|
|
1152
1189
|
}
|
|
1153
1190
|
/**
|
|
1154
1191
|
* The first shipped locale the browser asks for, matched on the primary
|
|
@@ -1195,12 +1232,14 @@ window.__ModuleLoader__.load({
|
|
|
1195
1232
|
const store = createLanguageRowStore();
|
|
1196
1233
|
let bound;
|
|
1197
1234
|
const sync = (snapshot) => {
|
|
1235
|
+
syncDocumentLanguage(snapshot.active);
|
|
1198
1236
|
bound?.sync(snapshot.active, snapshot.locales.map((l) => ({
|
|
1199
1237
|
id: l.id,
|
|
1200
1238
|
label: l.label
|
|
1201
1239
|
})), snapshot.revision);
|
|
1202
1240
|
};
|
|
1203
1241
|
ctx.on("locale/change", sync);
|
|
1242
|
+
syncDocumentLanguage(locale.getLocale().active);
|
|
1204
1243
|
const injected = (actions) => {
|
|
1205
1244
|
bound = actions;
|
|
1206
1245
|
sync(locale.getLocale());
|