diff --git a/apps/activities/_day.html b/apps/activities/_day.html
index c23ea53fc..55dd3a90d 100644
--- a/apps/activities/_day.html
+++ b/apps/activities/_day.html
@@ -504,10 +504,10 @@ button.activity-detail-back {
-
diff --git a/apps/settings/workspace.html b/apps/settings/workspace.html
index 82643bf1b..f6eb7ce3a 100644
--- a/apps/settings/workspace.html
+++ b/apps/settings/workspace.html
@@ -2964,6 +2964,7 @@ const saveTimeouts = new Map();
let logNextCursor = null;
let insightsData = null;
let keyValidationData = {};
+const escapeHtml = window.AppServices.escapeHtml;
// ========== MODAL ACCESSIBILITY ==========
function setupModalAccessibility(modalId) {
@@ -5754,11 +5755,6 @@ if (resetAgentBtn) {
});
}
-function escapeHtml(str) {
- if (!str) return '';
- return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
-}
-
// ========== STORAGE ==========
let storageData = null;
diff --git a/apps/sol/workspace.html b/apps/sol/workspace.html
index 67e0c37ff..ed6a972b4 100644
--- a/apps/sol/workspace.html
+++ b/apps/sol/workspace.html
@@ -1159,8 +1159,6 @@
-
-
@@ -2088,7 +2086,7 @@
if (data.format === 'md') {
const markdown = document.createElement('div');
markdown.className = 'rendered-markdown';
- markdown.innerHTML = renderMarkdown(data.content);
+ markdown.innerHTML = window.AppServices.renderMarkdown(data.content);
container.appendChild(markdown);
} else {
const pre = document.createElement('pre');
@@ -2121,16 +2119,7 @@
return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}
- // Escape HTML to prevent XSS
- function escapeHtml(text) {
- const div = document.createElement('div');
- div.textContent = text;
- return div.innerHTML;
- }
-
- function renderMarkdown(raw) {
- return DOMPurify.sanitize(marked.parse(raw || '', { breaks: true, gfm: true }));
- }
+ const escapeHtml = window.AppServices.escapeHtml;
// Render agent events as a rich interactive timeline
function renderEventTimeline(events) {
@@ -2314,7 +2303,7 @@
if (event.result && event.result.trim()) {
const resultDiv = document.createElement('div');
resultDiv.className = 'finish-result';
- resultDiv.innerHTML = renderMarkdown(event.result);
+ resultDiv.innerHTML = window.AppServices.renderMarkdown(event.result);
block.appendChild(resultDiv);
} else {
const empty = document.createElement('div');
diff --git a/apps/speakers/workspace.html b/apps/speakers/workspace.html
index 8d9ab6c84..00170fd1d 100644
--- a/apps/speakers/workspace.html
+++ b/apps/speakers/workspace.html
@@ -1098,6 +1098,7 @@
diff --git a/apps/todos/workspace.html b/apps/todos/workspace.html
index ba81f5528..c3bf9399d 100644
--- a/apps/todos/workspace.html
+++ b/apps/todos/workspace.html
@@ -1358,7 +1358,7 @@ document.addEventListener('DOMContentLoaded', function() {
window.addEventListener('todo.added', (e) => {
const todo = e.detail;
const facetName = todo.facet;
- const escape = window.AppServices._escapeHtml;
+ const escape = window.AppServices.escapeHtml;
// Find or create facet section
let facetSection = document.querySelector(`.facet-section[data-facet="${facetName}"]`);
diff --git a/apps/tokens/workspace.html b/apps/tokens/workspace.html
index 72dcbb11e..645a0280e 100644
--- a/apps/tokens/workspace.html
+++ b/apps/tokens/workspace.html
@@ -579,14 +579,7 @@ function formatSegmentKey(segment) {
}
// Escape HTML special characters for safe innerHTML interpolation
-function escapeHtml(val) {
- return String(val ?? '')
- .replace(/&/g, '&')
- .replace(//g, '>')
- .replace(/"/g, '"')
- .replace(/'/g, ''');
-}
+const escapeHtml = window.AppServices.escapeHtml;
// Create percent bar
function createPercentBar(percent, color) {
diff --git a/apps/transcripts/workspace.html b/apps/transcripts/workspace.html
index d03b0ee0b..c6b720c3a 100644
--- a/apps/transcripts/workspace.html
+++ b/apps/transcripts/workspace.html
@@ -1449,9 +1449,9 @@ body.has-app-bar.has-date-nav .workspace:has(.tr-wrap) {
-