@codemem/server 0.31.0 → 0.31.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/dist/index.js +202 -68
- package/dist/index.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +3 -3
- package/static/app.js +298 -39
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAGX,WAAW,EAIX,MAAM,eAAe,CAAC;AA8EvB,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAoBF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAGX,WAAW,EAIX,MAAM,eAAe,CAAC;AA8EvB,OAAO,EAAgB,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAE3E,KAAK,YAAY,GAAG,MAAM,WAAW,CAAC;AACtC,KAAK,iBAAiB,GAAG;IACxB,KAAK,EACF,UAAU,GACV,SAAS,GACT,UAAU,GACV,OAAO,GACP,UAAU,GACV,iBAAiB,GACjB,iBAAiB,GACjB,IAAI,CAAC;IACR,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAoBF,UAAU,wBAAwB;IACjC,cAAc,CAAC,EAAE;QAChB,OAAO,EAAE,0BAA0B,CAAC;QACpC,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,wBAAwB,EAAE,MAAM,CAAC;QACjC,4BAA4B,EAAE,MAAM,CAAC;KACrC,CAAC;CACF;AA6mDD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,8EA2W7F;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,YAAY,EACtB,oBAAoB,CAAC,EAAE,MAAM,iBAAiB,GAAG,IAAI,8EAwkErD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemem/server",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -17,9 +17,9 @@
|
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@hono/node-server": "^2.0.1",
|
|
19
19
|
"drizzle-orm": "^0.45.2",
|
|
20
|
-
"hono": "^4.12.
|
|
20
|
+
"hono": "^4.12.21",
|
|
21
21
|
"limiter": "^3.0.0",
|
|
22
|
-
"@codemem/core": "^0.31.
|
|
22
|
+
"@codemem/core": "^0.31.2"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/better-sqlite3": "^7.6.13",
|
package/static/app.js
CHANGED
|
@@ -3268,6 +3268,14 @@
|
|
|
3268
3268
|
if (!resp.ok) throw new Error(detail || payloadError(payload) || text || "request failed");
|
|
3269
3269
|
return payload;
|
|
3270
3270
|
}
|
|
3271
|
+
var ProjectForgetConfirmationError = class extends Error {
|
|
3272
|
+
preview;
|
|
3273
|
+
constructor(preview) {
|
|
3274
|
+
super("Project forget confirmation required");
|
|
3275
|
+
this.name = "ProjectForgetConfirmationError";
|
|
3276
|
+
this.preview = preview;
|
|
3277
|
+
}
|
|
3278
|
+
};
|
|
3271
3279
|
var SharingDomainGuardrailConfirmationError = class extends Error {
|
|
3272
3280
|
requiredGuardrails;
|
|
3273
3281
|
requiredGuardrailTokens;
|
|
@@ -3318,6 +3326,20 @@
|
|
|
3318
3326
|
guardrail_warnings: payload.guardrail_warnings ?? mapping.guardrail_warnings
|
|
3319
3327
|
};
|
|
3320
3328
|
}
|
|
3329
|
+
async function saveSharingDomainProjectMappings(input) {
|
|
3330
|
+
const resp = await fetch("/api/sync/sharing-domains/project-mappings/bulk", {
|
|
3331
|
+
method: "PUT",
|
|
3332
|
+
headers: { "Content-Type": "application/json" },
|
|
3333
|
+
body: JSON.stringify(input)
|
|
3334
|
+
});
|
|
3335
|
+
const { text, payload } = await readJsonPayload(resp);
|
|
3336
|
+
if (!resp.ok) {
|
|
3337
|
+
if (payload?.error === "guardrail_confirmation_required") throw new SharingDomainGuardrailConfirmationError(payload);
|
|
3338
|
+
throw new Error(payloadError(payload) || text || "request failed");
|
|
3339
|
+
}
|
|
3340
|
+
if (!Array.isArray(payload?.mappings)) throw new Error("response missing mappings");
|
|
3341
|
+
return payload.mappings;
|
|
3342
|
+
}
|
|
3321
3343
|
async function deleteSharingDomainProjectMapping(id) {
|
|
3322
3344
|
const resp = await fetch(`/api/sync/sharing-domains/project-mappings/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
3323
3345
|
const { text, payload } = await readJsonPayload(resp);
|
|
@@ -3335,6 +3357,20 @@
|
|
|
3335
3357
|
if (!payload?.workspace_identity) throw new Error("response missing project reassignment");
|
|
3336
3358
|
return payload;
|
|
3337
3359
|
}
|
|
3360
|
+
async function forgetProjectInventoryMemories(input) {
|
|
3361
|
+
const resp = await fetch("/api/sync/projects/forget", {
|
|
3362
|
+
method: "POST",
|
|
3363
|
+
headers: { "Content-Type": "application/json" },
|
|
3364
|
+
body: JSON.stringify(input)
|
|
3365
|
+
});
|
|
3366
|
+
const { text, payload } = await readJsonPayload(resp);
|
|
3367
|
+
if (!resp.ok) {
|
|
3368
|
+
if (payload?.error === "project_forget_confirmation_required" && payload.preview) throw new ProjectForgetConfirmationError(payload.preview);
|
|
3369
|
+
throw new Error(payloadError(payload) || text || "request failed");
|
|
3370
|
+
}
|
|
3371
|
+
if (!payload?.workspace_identity) throw new Error("response missing project forget result");
|
|
3372
|
+
return payload;
|
|
3373
|
+
}
|
|
3338
3374
|
async function reassignLegacySharedReviewGroup$1(input) {
|
|
3339
3375
|
const resp = await fetch("/api/sync/legacy-shared-review/reassign", {
|
|
3340
3376
|
method: "POST",
|
|
@@ -13508,7 +13544,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
13508
13544
|
}) : null, _$3(Tooltip, {
|
|
13509
13545
|
label: formatDate(createdAtRaw),
|
|
13510
13546
|
side: "left"
|
|
13511
|
-
}, _$3("div", { className: "small feed-age" }, relative)),
|
|
13547
|
+
}, _$3("div", { className: "small feed-age" }, relative)), item.owned_by_self && memoryId > 0 ? _$3(FeedItemMenu, {
|
|
13512
13548
|
assignProjectDisabled: movingProject,
|
|
13513
13549
|
disabled: deletingMemory,
|
|
13514
13550
|
onAssignProject: () => void moveProject(),
|
|
@@ -13523,7 +13559,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
13523
13559
|
})), _$3("div", { className: "feed-meta" }, metaText || "No tags, files, or provenance details attached."), bodyContent, _$3("div", { className: "feed-footer" }, _$3("div", { className: "feed-footer-left" }, tags.length ? _$3("div", { className: "feed-tags" }, tags.map((tag, index) => _$3(TagChip, {
|
|
13524
13560
|
key: `${String(tag)}-${index}`,
|
|
13525
13561
|
tag
|
|
13526
|
-
}))) : null,
|
|
13562
|
+
}))) : null, item.owned_by_self && memoryId > 0 ? _$3("div", { className: "feed-visibility-controls" }, _$3("select", {
|
|
13527
13563
|
"aria-label": `Visibility for ${String(item.title || "memory")}`,
|
|
13528
13564
|
className: "feed-visibility-select",
|
|
13529
13565
|
disabled: savingVisibility,
|
|
@@ -14399,11 +14435,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14399
14435
|
];
|
|
14400
14436
|
var refreshProjects = null;
|
|
14401
14437
|
var currentOffset = 0;
|
|
14402
|
-
var lastLimit =
|
|
14438
|
+
var lastLimit = 250;
|
|
14403
14439
|
var scopes = [];
|
|
14404
14440
|
var openProjectDetails = /* @__PURE__ */ new Set();
|
|
14441
|
+
var openProjectClusters = /* @__PURE__ */ new Set();
|
|
14405
14442
|
var draftDomainSelections = /* @__PURE__ */ new Map();
|
|
14406
14443
|
var pendingConfirmations = /* @__PURE__ */ new Map();
|
|
14444
|
+
var pendingForgetConfirmations = /* @__PURE__ */ new Map();
|
|
14407
14445
|
function el(id) {
|
|
14408
14446
|
return document.getElementById(id);
|
|
14409
14447
|
}
|
|
@@ -14429,6 +14467,14 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14429
14467
|
if (project.cwd) return project.cwd;
|
|
14430
14468
|
return project.workspace_identity;
|
|
14431
14469
|
}
|
|
14470
|
+
function projectClusterKey(project) {
|
|
14471
|
+
if (project.git_remote) return `git:${project.git_remote}`;
|
|
14472
|
+
if (project.project) return `project:${project.project}`;
|
|
14473
|
+
return `identity:${project.workspace_identity}`;
|
|
14474
|
+
}
|
|
14475
|
+
function projectClusterLabel(project) {
|
|
14476
|
+
return project.project || project.display_project || strongestSignal(project);
|
|
14477
|
+
}
|
|
14432
14478
|
function scopeLabel(scopeId) {
|
|
14433
14479
|
if (!scopeId) return "—";
|
|
14434
14480
|
const scope = scopes.find((item) => item.scope_id === scopeId);
|
|
@@ -14473,6 +14519,22 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14473
14519
|
showGlobalNotice(error instanceof Error ? error.message : "Unable to update project Sharing domain.", "warning");
|
|
14474
14520
|
}
|
|
14475
14521
|
}
|
|
14522
|
+
async function saveProjectClusterMapping(projects, scopeId) {
|
|
14523
|
+
const assignable = projects.filter((project) => project.identity_source !== "unmapped");
|
|
14524
|
+
if (assignable.length === 0) return;
|
|
14525
|
+
try {
|
|
14526
|
+
await saveSharingDomainProjectMappings({ mappings: assignable.map((project) => ({
|
|
14527
|
+
...project.mapping_id && project.resolution_reason === "exact_mapping" ? { id: project.mapping_id } : {},
|
|
14528
|
+
project_pattern: project.display_project,
|
|
14529
|
+
scope_id: scopeId,
|
|
14530
|
+
workspace_identity: project.workspace_identity
|
|
14531
|
+
})) });
|
|
14532
|
+
showGlobalNotice(`Updated ${assignable.length} project identit${assignable.length === 1 ? "y" : "ies"}. Device access grants are unchanged.`);
|
|
14533
|
+
refreshProjects?.();
|
|
14534
|
+
} catch (error) {
|
|
14535
|
+
showGlobalNotice(error instanceof SharingDomainGuardrailConfirmationError ? "One or more identities in this group need review before bulk assignment. Expand the group and save those identities directly." : error instanceof Error ? error.message : "Unable to update project Sharing domains.", "warning");
|
|
14536
|
+
}
|
|
14537
|
+
}
|
|
14476
14538
|
async function removeProjectMapping(project) {
|
|
14477
14539
|
if (project.mapping_id == null) return;
|
|
14478
14540
|
try {
|
|
@@ -14485,6 +14547,30 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14485
14547
|
showGlobalNotice(error instanceof Error ? error.message : "Unable to remove project Sharing domain mapping.", "warning");
|
|
14486
14548
|
}
|
|
14487
14549
|
}
|
|
14550
|
+
async function forgetProjectMemories(project, confirmed = false) {
|
|
14551
|
+
try {
|
|
14552
|
+
const pending = pendingForgetConfirmations.get(project.workspace_identity);
|
|
14553
|
+
const result = await forgetProjectInventoryMemories({
|
|
14554
|
+
...confirmed && pending ? { confirmation_token: pending.confirmationToken } : {},
|
|
14555
|
+
confirmed,
|
|
14556
|
+
workspace_identity: project.workspace_identity
|
|
14557
|
+
});
|
|
14558
|
+
pendingForgetConfirmations.delete(project.workspace_identity);
|
|
14559
|
+
showGlobalNotice(`Forgot ${result.forgotten_memory_count.toLocaleString()} local memor${result.forgotten_memory_count === 1 ? "y" : "ies"}. ${result.peer_owned_memory_count.toLocaleString()} peer-owned memor${result.peer_owned_memory_count === 1 ? "y was" : "ies were"} left unchanged.`);
|
|
14560
|
+
refreshProjects?.();
|
|
14561
|
+
} catch (error) {
|
|
14562
|
+
if (error instanceof ProjectForgetConfirmationError) {
|
|
14563
|
+
pendingForgetConfirmations.set(project.workspace_identity, {
|
|
14564
|
+
confirmationToken: error.preview.confirmation_token,
|
|
14565
|
+
localOwnedMemoryCount: error.preview.local_owned_memory_count,
|
|
14566
|
+
peerOwnedMemoryCount: error.preview.peer_owned_memory_count
|
|
14567
|
+
});
|
|
14568
|
+
refreshProjects?.();
|
|
14569
|
+
return;
|
|
14570
|
+
}
|
|
14571
|
+
showGlobalNotice(error instanceof Error ? error.message : "Unable to forget project memories.", "warning");
|
|
14572
|
+
}
|
|
14573
|
+
}
|
|
14488
14574
|
async function reassignProject(project) {
|
|
14489
14575
|
if (project.identity_source === "unmapped") return;
|
|
14490
14576
|
const currentProject = String(project.project || project.display_project || "").trim();
|
|
@@ -14583,7 +14669,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14583
14669
|
changeProject.disabled = project.session_count === 0;
|
|
14584
14670
|
if (changeProject.disabled) changeProject.title = "No sessions are available to reassign for this saved mapping.";
|
|
14585
14671
|
changeProject.addEventListener("click", () => void reassignProject(project));
|
|
14586
|
-
|
|
14672
|
+
const forget = document.createElement("button");
|
|
14673
|
+
forget.className = "settings-button danger";
|
|
14674
|
+
forget.type = "button";
|
|
14675
|
+
forget.textContent = "Forget local memories…";
|
|
14676
|
+
forget.disabled = (project.memory_count ?? 0) === 0;
|
|
14677
|
+
forget.addEventListener("click", () => void forgetProjectMemories(project));
|
|
14678
|
+
actions.append(label, select, save, keepLocal, remove, changeProject, forget);
|
|
14587
14679
|
const pending = pendingConfirmations.get(project.workspace_identity);
|
|
14588
14680
|
if (pending) {
|
|
14589
14681
|
const warningBox = document.createElement("div");
|
|
@@ -14623,6 +14715,33 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14623
14715
|
warningBox.append(title, intro, list, confirm, cancel);
|
|
14624
14716
|
actions.appendChild(warningBox);
|
|
14625
14717
|
}
|
|
14718
|
+
const pendingForget = pendingForgetConfirmations.get(project.workspace_identity);
|
|
14719
|
+
if (pendingForget) {
|
|
14720
|
+
const warningBox = document.createElement("div");
|
|
14721
|
+
warningBox.className = "settings-note project-guardrail-confirmation";
|
|
14722
|
+
warningBox.setAttribute("role", "alert");
|
|
14723
|
+
const title = document.createElement("strong");
|
|
14724
|
+
title.textContent = "Confirm project memory cleanup.";
|
|
14725
|
+
const intro = document.createElement("p");
|
|
14726
|
+
intro.textContent = `${pendingForget.localOwnedMemoryCount.toLocaleString()} locally owned memor${pendingForget.localOwnedMemoryCount === 1 ? "y" : "ies"} will be forgotten. ${pendingForget.peerOwnedMemoryCount.toLocaleString()} peer-owned memor${pendingForget.peerOwnedMemoryCount === 1 ? "y" : "ies"} will be left unchanged.`;
|
|
14727
|
+
const detail = document.createElement("p");
|
|
14728
|
+
detail.textContent = "Use this only to clean up wrongly attributed local project inventory; it forgets actual local memories on this device.";
|
|
14729
|
+
const confirm = document.createElement("button");
|
|
14730
|
+
confirm.className = "settings-button danger";
|
|
14731
|
+
confirm.type = "button";
|
|
14732
|
+
confirm.textContent = "I understand, forget local memories";
|
|
14733
|
+
confirm.addEventListener("click", () => void forgetProjectMemories(project, true));
|
|
14734
|
+
const cancel = document.createElement("button");
|
|
14735
|
+
cancel.className = "settings-button";
|
|
14736
|
+
cancel.type = "button";
|
|
14737
|
+
cancel.textContent = "Cancel";
|
|
14738
|
+
cancel.addEventListener("click", () => {
|
|
14739
|
+
pendingForgetConfirmations.delete(project.workspace_identity);
|
|
14740
|
+
refreshProjects?.();
|
|
14741
|
+
});
|
|
14742
|
+
warningBox.append(title, intro, detail, confirm, cancel);
|
|
14743
|
+
actions.appendChild(warningBox);
|
|
14744
|
+
}
|
|
14626
14745
|
return actions;
|
|
14627
14746
|
}
|
|
14628
14747
|
function renderProjectRow(project) {
|
|
@@ -14706,6 +14825,90 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14706
14825
|
row.appendChild(detail);
|
|
14707
14826
|
return row;
|
|
14708
14827
|
}
|
|
14828
|
+
function clusterDomainLabel(projects) {
|
|
14829
|
+
const uniqueScopes = [...new Set(projects.map((project) => project.resolved_scope_id))];
|
|
14830
|
+
return uniqueScopes.length === 1 ? scopeLabel(uniqueScopes[0]) : "Mixed Sharing domains";
|
|
14831
|
+
}
|
|
14832
|
+
function renderProjectCluster(projects) {
|
|
14833
|
+
if (projects.length === 1) return renderProjectRow(projects[0]);
|
|
14834
|
+
const clusterKey = projectClusterKey(projects[0]);
|
|
14835
|
+
const row = document.createElement("article");
|
|
14836
|
+
row.className = "project-inventory-row project-inventory-cluster";
|
|
14837
|
+
const header = document.createElement("div");
|
|
14838
|
+
header.className = "project-inventory-row-header";
|
|
14839
|
+
const title = document.createElement("div");
|
|
14840
|
+
title.className = "project-inventory-title";
|
|
14841
|
+
title.textContent = projectClusterLabel(projects[0]);
|
|
14842
|
+
header.appendChild(title);
|
|
14843
|
+
const domain = document.createElement("div");
|
|
14844
|
+
domain.className = "project-inventory-domain";
|
|
14845
|
+
domain.textContent = clusterDomainLabel(projects);
|
|
14846
|
+
header.appendChild(domain);
|
|
14847
|
+
row.appendChild(header);
|
|
14848
|
+
const memoryCount = projects.reduce((total, project) => total + (project.memory_count ?? 0), 0);
|
|
14849
|
+
const sessionCount = projects.reduce((total, project) => total + project.session_count, 0);
|
|
14850
|
+
const meta = document.createElement("div");
|
|
14851
|
+
meta.className = "project-inventory-meta";
|
|
14852
|
+
meta.textContent = `${projects.length} identities · ${sessionCount.toLocaleString()} sessions · ${memoryCount.toLocaleString()} memories`;
|
|
14853
|
+
row.appendChild(meta);
|
|
14854
|
+
const actions = document.createElement("div");
|
|
14855
|
+
actions.className = "project-inventory-actions";
|
|
14856
|
+
const hasGuardrailWarnings = projects.some((project) => project.guardrail_warnings.length > 0);
|
|
14857
|
+
const suggestedScopes = new Set(projects.map((project) => project.suggested_scope_id).filter((scopeId) => Boolean(scopeId)));
|
|
14858
|
+
const resolvedScopes = new Set(projects.map((project) => project.resolved_scope_id));
|
|
14859
|
+
const select = document.createElement("select");
|
|
14860
|
+
select.className = "project-domain-select";
|
|
14861
|
+
select.setAttribute("aria-label", `Sharing domain for ${projectClusterLabel(projects[0])} group`);
|
|
14862
|
+
const placeholder = document.createElement("option");
|
|
14863
|
+
placeholder.value = "";
|
|
14864
|
+
placeholder.textContent = "Choose domain…";
|
|
14865
|
+
select.appendChild(placeholder);
|
|
14866
|
+
for (const scope of assignableScopes()) {
|
|
14867
|
+
const option = document.createElement("option");
|
|
14868
|
+
option.value = scope.scope_id;
|
|
14869
|
+
option.textContent = scope.label ? `${scope.label} · ${scope.scope_id}` : scope.scope_id;
|
|
14870
|
+
select.appendChild(option);
|
|
14871
|
+
}
|
|
14872
|
+
select.value = "";
|
|
14873
|
+
const save = document.createElement("button");
|
|
14874
|
+
save.className = "settings-button";
|
|
14875
|
+
save.type = "button";
|
|
14876
|
+
save.textContent = `Save domain for ${projects.length} identities`;
|
|
14877
|
+
save.disabled = true;
|
|
14878
|
+
save.addEventListener("click", () => void saveProjectClusterMapping(projects, select.value));
|
|
14879
|
+
select.addEventListener("change", () => {
|
|
14880
|
+
save.disabled = !select.value || hasGuardrailWarnings;
|
|
14881
|
+
});
|
|
14882
|
+
actions.append(select, save);
|
|
14883
|
+
if (suggestedScopes.size > 1 || resolvedScopes.size > 1 || hasGuardrailWarnings) {
|
|
14884
|
+
const note = document.createElement("div");
|
|
14885
|
+
note.className = "settings-note project-attention-note";
|
|
14886
|
+
note.textContent = hasGuardrailWarnings ? "One or more identities in this group need individual review before bulk assignment." : "This group has mixed suggestions or current domains. Choose a domain explicitly before bulk assignment.";
|
|
14887
|
+
actions.appendChild(note);
|
|
14888
|
+
}
|
|
14889
|
+
row.appendChild(actions);
|
|
14890
|
+
const details = document.createElement("details");
|
|
14891
|
+
details.className = "project-inventory-details";
|
|
14892
|
+
details.open = openProjectClusters.has(clusterKey);
|
|
14893
|
+
details.addEventListener("toggle", () => {
|
|
14894
|
+
if (details.open) openProjectClusters.add(clusterKey);
|
|
14895
|
+
else openProjectClusters.delete(clusterKey);
|
|
14896
|
+
});
|
|
14897
|
+
const summary = document.createElement("summary");
|
|
14898
|
+
summary.textContent = "Show identities in this project";
|
|
14899
|
+
details.appendChild(summary);
|
|
14900
|
+
for (const project of projects) details.appendChild(renderProjectRow(project));
|
|
14901
|
+
row.appendChild(details);
|
|
14902
|
+
return row;
|
|
14903
|
+
}
|
|
14904
|
+
function projectClusters(projects) {
|
|
14905
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
14906
|
+
for (const project of projects) {
|
|
14907
|
+
const key = projectClusterKey(project);
|
|
14908
|
+
byKey.set(key, [...byKey.get(key) ?? [], project]);
|
|
14909
|
+
}
|
|
14910
|
+
return [...byKey.values()];
|
|
14911
|
+
}
|
|
14709
14912
|
function renderEmpty(message) {
|
|
14710
14913
|
const list = el("projectsInventoryList");
|
|
14711
14914
|
if (!list) return;
|
|
@@ -14730,8 +14933,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
14730
14933
|
scopes = settings.scopes;
|
|
14731
14934
|
list.textContent = "";
|
|
14732
14935
|
if (result.projects.length === 0) renderEmpty("No projects match those filters.");
|
|
14733
|
-
else for (const
|
|
14734
|
-
meta.textContent = result.total === 0 ? "0
|
|
14936
|
+
else for (const cluster of projectClusters(result.projects)) list.appendChild(renderProjectCluster(cluster));
|
|
14937
|
+
meta.textContent = result.total === 0 ? "0 project identities found" : `${result.total} project identit${result.total === 1 ? "y" : "ies"} found · showing ${result.offset + 1}-${Math.min(result.offset + result.projects.length, result.total)}`;
|
|
14735
14938
|
const prev = el("projectsPrevPage");
|
|
14736
14939
|
const next = el("projectsNextPage");
|
|
14737
14940
|
if (prev) prev.disabled = result.offset === 0;
|
|
@@ -21058,6 +21261,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21058
21261
|
const label = group.displayProject.toLowerCase();
|
|
21059
21262
|
return label.includes("fatal:") || label.includes("not a git repository") || label === "unknown project" || group.identitySource === "unmapped";
|
|
21060
21263
|
}
|
|
21264
|
+
function canReassignLegacyGroup(group) {
|
|
21265
|
+
return (group.reassignableMemoryCount ?? group.memoryCount) > 0;
|
|
21266
|
+
}
|
|
21061
21267
|
function groupSearchText(group) {
|
|
21062
21268
|
return [
|
|
21063
21269
|
group.displayProject,
|
|
@@ -21103,9 +21309,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21103
21309
|
function LegacySharedReviewRow({ item, onReassign, onReview }) {
|
|
21104
21310
|
const groups = item.groups ?? [];
|
|
21105
21311
|
const targetScopes = item.targetScopes ?? [];
|
|
21106
|
-
const
|
|
21107
|
-
const initialSelections = Object.fromEntries(groups.map((group) => [group.workspaceIdentity, group.suggestedScopeId ?? firstTargetScopeId ?? ""]));
|
|
21312
|
+
const initialSelections = Object.fromEntries(groups.map((group) => [group.workspaceIdentity, group.suggestedScopeId ?? ""]));
|
|
21108
21313
|
const [pending, setPending] = d$2({});
|
|
21314
|
+
const [errors, setErrors] = d$2({});
|
|
21109
21315
|
const [selectedScopes, setSelectedScopes] = d$2(initialSelections);
|
|
21110
21316
|
const [selectedGroups, setSelectedGroups] = d$2({});
|
|
21111
21317
|
const [filter, setFilter] = d$2("all");
|
|
@@ -21114,8 +21320,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21114
21320
|
const shownGroupCount = groups.length;
|
|
21115
21321
|
const groupCount = item.totalGroupCount ?? shownGroupCount;
|
|
21116
21322
|
const cleanupCount = groups.filter(needsProjectCleanup).length;
|
|
21117
|
-
const suggestedCount = groups.filter((group) => group.suggestedScopeId && !needsProjectCleanup(group)).length;
|
|
21118
|
-
const
|
|
21323
|
+
const suggestedCount = groups.filter((group) => group.suggestedScopeId && !needsProjectCleanup(group) && canReassignLegacyGroup(group)).length;
|
|
21324
|
+
const selectedReassignableCount = groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group)).length;
|
|
21325
|
+
const selectedCount = groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity])).length;
|
|
21119
21326
|
const visibleGroups = groups.filter((group) => {
|
|
21120
21327
|
const cleanup = needsProjectCleanup(group);
|
|
21121
21328
|
if (filter === "suggested" && (!group.suggestedScopeId || cleanup)) return false;
|
|
@@ -21128,8 +21335,13 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21128
21335
|
const selectedScopeId = selectedScopes[group.workspaceIdentity] || group.suggestedScopeId || "";
|
|
21129
21336
|
if (!selectedScopeId || !onReassign || busyIdentity) return;
|
|
21130
21337
|
setBusyIdentity(group.workspaceIdentity);
|
|
21338
|
+
setErrors((current) => {
|
|
21339
|
+
const next = { ...current };
|
|
21340
|
+
delete next[group.workspaceIdentity];
|
|
21341
|
+
return next;
|
|
21342
|
+
});
|
|
21131
21343
|
try {
|
|
21132
|
-
const preview = await onReassign(group, selectedScopeId, Boolean(pending[group.workspaceIdentity]));
|
|
21344
|
+
const preview = await onReassign(group, selectedScopeId, Boolean(pending[group.workspaceIdentity]), pending[group.workspaceIdentity]?.confirmation_token);
|
|
21133
21345
|
if (preview) setPending((current) => ({
|
|
21134
21346
|
...current,
|
|
21135
21347
|
[group.workspaceIdentity]: preview
|
|
@@ -21139,6 +21351,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21139
21351
|
delete next[group.workspaceIdentity];
|
|
21140
21352
|
return next;
|
|
21141
21353
|
});
|
|
21354
|
+
} catch (error) {
|
|
21355
|
+
setErrors((current) => ({
|
|
21356
|
+
...current,
|
|
21357
|
+
[group.workspaceIdentity]: error instanceof Error ? error.message : "Unable to reassign legacy review memories."
|
|
21358
|
+
}));
|
|
21142
21359
|
} finally {
|
|
21143
21360
|
setBusyIdentity(null);
|
|
21144
21361
|
}
|
|
@@ -21153,6 +21370,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21153
21370
|
delete next[group.workspaceIdentity];
|
|
21154
21371
|
return next;
|
|
21155
21372
|
});
|
|
21373
|
+
setErrors((current) => {
|
|
21374
|
+
const next = { ...current };
|
|
21375
|
+
delete next[group.workspaceIdentity];
|
|
21376
|
+
return next;
|
|
21377
|
+
});
|
|
21156
21378
|
}
|
|
21157
21379
|
function toggleGroup(group, checked) {
|
|
21158
21380
|
setSelectedGroups((current) => ({
|
|
@@ -21163,38 +21385,40 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21163
21385
|
function setVisibleSelected(checked) {
|
|
21164
21386
|
setSelectedGroups((current) => ({
|
|
21165
21387
|
...current,
|
|
21166
|
-
...Object.fromEntries(visibleGroups.map((group) => [group.workspaceIdentity, checked]))
|
|
21388
|
+
...Object.fromEntries(visibleGroups.filter(canReassignLegacyGroup).map((group) => [group.workspaceIdentity, checked]))
|
|
21167
21389
|
}));
|
|
21168
21390
|
}
|
|
21169
21391
|
function selectSuggestedGroups() {
|
|
21170
21392
|
setSelectedGroups((current) => ({
|
|
21171
21393
|
...current,
|
|
21172
|
-
...Object.fromEntries(groups.filter((group) => group.suggestedScopeId && !needsProjectCleanup(group)).map((group) => [group.workspaceIdentity, true]))
|
|
21394
|
+
...Object.fromEntries(groups.filter((group) => group.suggestedScopeId && !needsProjectCleanup(group) && canReassignLegacyGroup(group)).map((group) => [group.workspaceIdentity, true]))
|
|
21173
21395
|
}));
|
|
21174
21396
|
}
|
|
21175
21397
|
async function applySelectedGroups() {
|
|
21176
21398
|
if (!onReassign || busyIdentity || selectedCount === 0) return;
|
|
21177
|
-
const selected = groups.filter((group) => selectedGroups[group.workspaceIdentity]);
|
|
21178
|
-
|
|
21399
|
+
const selected = groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity]));
|
|
21400
|
+
if (selected.every((group) => pending[group.workspaceIdentity])) return;
|
|
21179
21401
|
setBusyIdentity("bulk");
|
|
21180
21402
|
try {
|
|
21181
21403
|
for (const group of selected) {
|
|
21404
|
+
if (pending[group.workspaceIdentity]) continue;
|
|
21182
21405
|
const selectedScopeId = selectedScopes[group.workspaceIdentity] || group.suggestedScopeId || "";
|
|
21183
21406
|
if (!selectedScopeId) continue;
|
|
21184
|
-
|
|
21185
|
-
|
|
21186
|
-
|
|
21187
|
-
[group.workspaceIdentity]: preview
|
|
21188
|
-
}));
|
|
21189
|
-
else if (allPreviewed) {
|
|
21190
|
-
setPending((current) => {
|
|
21407
|
+
try {
|
|
21408
|
+
const preview = await onReassign(group, selectedScopeId, false);
|
|
21409
|
+
setErrors((current) => {
|
|
21191
21410
|
const next = { ...current };
|
|
21192
21411
|
delete next[group.workspaceIdentity];
|
|
21193
21412
|
return next;
|
|
21194
21413
|
});
|
|
21195
|
-
|
|
21414
|
+
if (preview) setPending((current) => ({
|
|
21415
|
+
...current,
|
|
21416
|
+
[group.workspaceIdentity]: preview
|
|
21417
|
+
}));
|
|
21418
|
+
} catch (error) {
|
|
21419
|
+
setErrors((current) => ({
|
|
21196
21420
|
...current,
|
|
21197
|
-
[group.workspaceIdentity]:
|
|
21421
|
+
[group.workspaceIdentity]: error instanceof Error ? error.message : "Unable to reassign legacy review memories."
|
|
21198
21422
|
}));
|
|
21199
21423
|
}
|
|
21200
21424
|
}
|
|
@@ -21226,7 +21450,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21226
21450
|
" ",
|
|
21227
21451
|
item.memoryCount.toLocaleString(),
|
|
21228
21452
|
" older shared memories total; review the projects, not individual memories.",
|
|
21229
|
-
shownGroupCount < groupCount ? ` Showing
|
|
21453
|
+
shownGroupCount < groupCount ? ` Showing ${shownGroupCount.toLocaleString()} projects; open Projects to review the rest.` : ""
|
|
21230
21454
|
]
|
|
21231
21455
|
}),
|
|
21232
21456
|
/* @__PURE__ */ u("div", {
|
|
@@ -21289,13 +21513,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21289
21513
|
}),
|
|
21290
21514
|
onReassign && targetScopes.length > 0 ? /* @__PURE__ */ u("button", {
|
|
21291
21515
|
className: "settings-save",
|
|
21292
|
-
disabled: busyIdentity != null || selectedCount === 0,
|
|
21516
|
+
disabled: busyIdentity != null || selectedCount === 0 || groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity])).every((group) => pending[group.workspaceIdentity]),
|
|
21293
21517
|
onClick: () => void applySelectedGroups(),
|
|
21294
21518
|
type: "button",
|
|
21295
|
-
children: busyIdentity === "bulk" ? "
|
|
21296
|
-
}) : onReassign &&
|
|
21519
|
+
children: busyIdentity === "bulk" ? "Previewing…" : `Preview ${selectedCount.toLocaleString()} selected`
|
|
21520
|
+
}) : onReassign && selectedReassignableCount > 0 ? /* @__PURE__ */ u("span", {
|
|
21297
21521
|
className: "legacy-review-cleanup-note",
|
|
21298
21522
|
children: "Add or join a Sharing domain before bulk reassignment."
|
|
21523
|
+
}) : null,
|
|
21524
|
+
selectedCount > 0 && groups.filter((group) => selectedGroups[group.workspaceIdentity] && canReassignLegacyGroup(group) && Boolean(selectedScopes[group.workspaceIdentity])).every((group) => pending[group.workspaceIdentity]) ? /* @__PURE__ */ u("span", {
|
|
21525
|
+
className: "legacy-review-cleanup-note",
|
|
21526
|
+
children: "Bulk actions only preview. Confirm each project individually to avoid partial reassignment."
|
|
21299
21527
|
}) : null
|
|
21300
21528
|
]
|
|
21301
21529
|
})]
|
|
@@ -21314,6 +21542,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21314
21542
|
"aria-label": `Select ${group.displayProject}`,
|
|
21315
21543
|
checked: Boolean(selectedGroups[group.workspaceIdentity]),
|
|
21316
21544
|
className: "cm-checkbox",
|
|
21545
|
+
disabled: !canReassignLegacyGroup(group),
|
|
21317
21546
|
onChange: (event) => toggleGroup(group, event.currentTarget.checked),
|
|
21318
21547
|
type: "checkbox"
|
|
21319
21548
|
}), /* @__PURE__ */ u("div", { children: [
|
|
@@ -21325,6 +21554,24 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21325
21554
|
className: "legacy-review-group-meta",
|
|
21326
21555
|
children: [formatIdentitySource(group.identitySource), group.suggestedScopeId ? ` · suggested ${group.suggestedScopeId}` : ""]
|
|
21327
21556
|
}),
|
|
21557
|
+
!canReassignLegacyGroup(group) ? /* @__PURE__ */ u("div", {
|
|
21558
|
+
className: "legacy-review-cleanup-note",
|
|
21559
|
+
children: "Peer-owned only. These older memories were received from another device, so this device cannot reassign them to a Sharing domain."
|
|
21560
|
+
}) : group.peerOwnedMemoryCount ? /* @__PURE__ */ u("div", {
|
|
21561
|
+
className: "legacy-review-cleanup-note",
|
|
21562
|
+
children: [
|
|
21563
|
+
(group.reassignableMemoryCount ?? group.memoryCount).toLocaleString(),
|
|
21564
|
+
" ",
|
|
21565
|
+
"local memor",
|
|
21566
|
+
(group.reassignableMemoryCount ?? group.memoryCount) === 1 ? "y" : "ies",
|
|
21567
|
+
" ",
|
|
21568
|
+
"can be reassigned; ",
|
|
21569
|
+
group.peerOwnedMemoryCount.toLocaleString(),
|
|
21570
|
+
" peer-owned memor",
|
|
21571
|
+
group.peerOwnedMemoryCount === 1 ? "y" : "ies",
|
|
21572
|
+
" will stay in review."
|
|
21573
|
+
]
|
|
21574
|
+
}) : null,
|
|
21328
21575
|
needsProjectCleanup(group) ? /* @__PURE__ */ u("div", {
|
|
21329
21576
|
className: "legacy-review-cleanup-note",
|
|
21330
21577
|
children: "Unclear project identity. Inspect or correct the project before trusting a domain."
|
|
@@ -21343,6 +21590,11 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21343
21590
|
className: "legacy-review-reason",
|
|
21344
21591
|
children: group.suggestionReason
|
|
21345
21592
|
}) : null,
|
|
21593
|
+
errors[group.workspaceIdentity] ? /* @__PURE__ */ u("div", {
|
|
21594
|
+
className: "legacy-review-confirmation",
|
|
21595
|
+
role: "alert",
|
|
21596
|
+
children: errors[group.workspaceIdentity]
|
|
21597
|
+
}) : null,
|
|
21346
21598
|
pending[group.workspaceIdentity] ? /* @__PURE__ */ u("div", {
|
|
21347
21599
|
className: "legacy-review-confirmation",
|
|
21348
21600
|
role: "alert",
|
|
@@ -21359,14 +21611,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21359
21611
|
"."
|
|
21360
21612
|
]
|
|
21361
21613
|
}) : null,
|
|
21362
|
-
targetScopes.length > 0 && onReassign ? /* @__PURE__ */ u("label", {
|
|
21614
|
+
targetScopes.length > 0 && onReassign && canReassignLegacyGroup(group) ? /* @__PURE__ */ u("label", {
|
|
21363
21615
|
className: "legacy-review-target",
|
|
21364
21616
|
children: [/* @__PURE__ */ u("span", { children: "Destination Sharing domain" }), /* @__PURE__ */ u("select", {
|
|
21365
21617
|
className: "peer-scope-input",
|
|
21366
21618
|
disabled: busyIdentity != null,
|
|
21367
21619
|
onChange: (event) => updateSelectedScope(group, event.currentTarget.value),
|
|
21368
|
-
value: selectedScopes[group.workspaceIdentity] ||
|
|
21369
|
-
children:
|
|
21620
|
+
value: selectedScopes[group.workspaceIdentity] || "",
|
|
21621
|
+
children: [/* @__PURE__ */ u("option", {
|
|
21622
|
+
value: "",
|
|
21623
|
+
children: "Choose domain…"
|
|
21624
|
+
}), targetScopes.map((scope) => /* @__PURE__ */ u("option", {
|
|
21370
21625
|
value: scope.scopeId,
|
|
21371
21626
|
children: [
|
|
21372
21627
|
scope.label,
|
|
@@ -21374,17 +21629,17 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21374
21629
|
scope.authorityType,
|
|
21375
21630
|
scope.scopeId === group.suggestedScopeId ? " · suggested" : ""
|
|
21376
21631
|
]
|
|
21377
|
-
}, scope.scopeId))
|
|
21632
|
+
}, scope.scopeId))]
|
|
21378
21633
|
})]
|
|
21379
21634
|
}) : null,
|
|
21380
|
-
targetScopes.length > 0 && onReassign ? /* @__PURE__ */ u("div", {
|
|
21635
|
+
targetScopes.length > 0 && onReassign && canReassignLegacyGroup(group) ? /* @__PURE__ */ u("div", {
|
|
21381
21636
|
className: "legacy-review-actions",
|
|
21382
21637
|
children: /* @__PURE__ */ u("button", {
|
|
21383
21638
|
type: "button",
|
|
21384
21639
|
className: "settings-button",
|
|
21385
|
-
disabled: busyIdentity != null,
|
|
21640
|
+
disabled: busyIdentity != null || !selectedScopes[group.workspaceIdentity],
|
|
21386
21641
|
onClick: () => void applyGroup(group),
|
|
21387
|
-
children: busyIdentity === group.workspaceIdentity ? "Reassigning…" : pending[group.workspaceIdentity] ? "I understand, reassign memories" : "Preview reassignment"
|
|
21642
|
+
children: busyIdentity === group.workspaceIdentity ? pending[group.workspaceIdentity] ? "Reassigning…" : "Previewing…" : pending[group.workspaceIdentity] ? "I understand, reassign memories" : "Preview reassignment"
|
|
21388
21643
|
})
|
|
21389
21644
|
}) : null
|
|
21390
21645
|
]
|
|
@@ -21413,9 +21668,10 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21413
21668
|
function openProjectsReview() {
|
|
21414
21669
|
window.location.hash = "projects";
|
|
21415
21670
|
}
|
|
21416
|
-
async function reassignLegacySharedReviewGroup(group, scopeId, confirmedOldCopies) {
|
|
21671
|
+
async function reassignLegacySharedReviewGroup(group, scopeId, confirmedOldCopies, confirmationToken) {
|
|
21417
21672
|
try {
|
|
21418
21673
|
const result = await reassignLegacySharedReviewGroup$1({
|
|
21674
|
+
...confirmationToken ? { confirmation_token: confirmationToken } : {},
|
|
21419
21675
|
confirmed_old_copies: confirmedOldCopies,
|
|
21420
21676
|
scope_id: scopeId,
|
|
21421
21677
|
workspace_identity: group.workspaceIdentity
|
|
@@ -21426,8 +21682,9 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21426
21682
|
return null;
|
|
21427
21683
|
} catch (error) {
|
|
21428
21684
|
if (error instanceof LegacySharedReviewConfirmationError) return error.preview;
|
|
21429
|
-
|
|
21430
|
-
|
|
21685
|
+
const message = error instanceof Error ? error.message : "Unable to reassign legacy review memories.";
|
|
21686
|
+
showGlobalNotice(message, "warning");
|
|
21687
|
+
throw new Error(message);
|
|
21431
21688
|
}
|
|
21432
21689
|
}
|
|
21433
21690
|
function renderSyncSharingReview() {
|
|
@@ -21447,6 +21704,8 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21447
21704
|
identitySource: String(raw.identity_source || "unknown"),
|
|
21448
21705
|
lastUpdatedAt: typeof raw.last_updated_at === "string" ? raw.last_updated_at : null,
|
|
21449
21706
|
memoryCount: Number(raw.memory_count || 0),
|
|
21707
|
+
peerOwnedMemoryCount: Number(raw.peer_owned_memory_count || 0),
|
|
21708
|
+
reassignableMemoryCount: Number(raw.reassignable_memory_count || 0),
|
|
21450
21709
|
suggestedScopeId: typeof raw.suggested_scope_id === "string" ? raw.suggested_scope_id : null,
|
|
21451
21710
|
suggestionReason: typeof raw.suggestion_reason === "string" ? raw.suggestion_reason : null,
|
|
21452
21711
|
workspaceIdentity: String(raw.workspace_identity || raw.display_project || "unknown")
|
|
@@ -21670,7 +21929,7 @@ For more information, see https://radix-ui.com/primitives/docs/components/${titl
|
|
|
21670
21929
|
try {
|
|
21671
21930
|
const runtime = await loadRuntimeInfo();
|
|
21672
21931
|
if (!runtime?.version) return;
|
|
21673
|
-
setRuntimeLabel(runtime.version, "
|
|
21932
|
+
setRuntimeLabel(runtime.version, "52dbd3c");
|
|
21674
21933
|
} catch {}
|
|
21675
21934
|
}
|
|
21676
21935
|
var lastAnnouncedRefreshState = null;
|