Feat v0.6.12 extension css isolation
Some checks failed
CI/CD / detect-changes (pull_request) Successful in 4s
CI/CD / build-and-deploy (pull_request) Has been cancelled
CI/CD / test-sqlite (pull_request) Has been cancelled
CI/CD / test-go-pg (pull_request) Has been cancelled
CI/CD / test-frontend (pull_request) Has been cancelled

Prefix enforcement prevents extension CSS from leaking into the kernel
or sibling extensions. All 12 in-tree packages migrated to .ext-{slug}-*
naming convention.

- Add data-ext attribute to extension mount container
- Add CSS linter (scripts/lint-package-css.sh) enforcing .ext-{slug} prefix
- Add kernel CSS contract doc (docs/EXTENSION-CSS.md)
- Migrate 12 packages: chat, dashboard, editor, git-board, hello-dashboard,
  icd-test-runner, notes, schedules, sdk-test-runner, tasks,
  team-activity-log, workflow-demo (CSS + JS in lockstep)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 11:54:51 +00:00
parent 786bc92768
commit abf71162b1
33 changed files with 1385 additions and 1074 deletions

View File

@@ -2,16 +2,16 @@
Uses CSS custom properties from the platform theme system (variables.css).
See EXTENSION-SURFACES.md for the full property reference. */
.hello-dashboard { max-width: 720px; margin: 0 auto; padding: 40px 24px; }
.hello-header { margin-bottom: 32px; }
.hello-header h1 { font-size: 28px; font-weight: 700; color: var(--text); margin: 0 0 8px 0; }
.hello-subtitle { font-size: 14px; color: var(--text-2); margin: 0; }
.hello-subtitle code,
.hello-card-value code { background: var(--bg-raised); padding: 2px 6px; border-radius: 4px; font-size: 13px; }
.hello-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
.hello-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 16px; }
.hello-card-title { font-size: 12px; font-weight: 600; color: var(--text-2); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; }
.hello-card-value { font-size: 20px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.hello-card-detail { font-size: 12px; color: var(--text-3); }
.hello-actions { display: flex; gap: 12px; margin-bottom: 24px; }
.hello-manifest { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-size: 12px; color: var(--text-2); overflow-x: auto; white-space: pre-wrap; font-family: var(--mono); line-height: 1.5; }
.ext-hello-dashboard { max-width: 720px; margin: 0 auto; padding: 40px 24px; }
.ext-hello-dashboard-header { margin-bottom: 32px; }
.ext-hello-dashboard-header h1 { font-size: 28px; font-weight: 700; color: var(--text); margin: 0 0 8px 0; }
.ext-hello-dashboard-subtitle { font-size: 14px; color: var(--text-2); margin: 0; }
.ext-hello-dashboard-subtitle code,
.ext-hello-dashboard-card-value code { background: var(--bg-raised); padding: 2px 6px; border-radius: 4px; font-size: 13px; }
.ext-hello-dashboard-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin-bottom: 24px; }
.ext-hello-dashboard-card { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 16px; }
.ext-hello-dashboard-card-title { font-size: 12px; font-weight: 600; color: var(--text-2); text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px; }
.ext-hello-dashboard-card-value { font-size: 20px; font-weight: 600; color: var(--text); margin-bottom: 4px; }
.ext-hello-dashboard-card-detail { font-size: 12px; color: var(--text-3); }
.ext-hello-dashboard-actions { display: flex; gap: 12px; margin-bottom: 24px; }
.ext-hello-dashboard-manifest { background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 16px; font-size: 12px; color: var(--text-2); overflow-x: auto; white-space: pre-wrap; font-family: var(--mono); line-height: 1.5; }

View File

@@ -20,12 +20,12 @@
var name = user.display_name || user.username || 'World';
mount.innerHTML =
'<div class="hello-dashboard">' +
'<div class="hello-header">' +
'<div class="ext-hello-dashboard">' +
'<div class="ext-hello-dashboard-header">' +
'<h1>Hello, ' + esc(name) + '!</h1>' +
'<p class="hello-subtitle">Extension surface <code>' + esc(manifest.id || 'unknown') + '</code> loaded successfully.</p>' +
'<p class="ext-hello-dashboard-subtitle">Extension surface <code>' + esc(manifest.id || 'unknown') + '</code> loaded successfully.</p>' +
'</div>' +
'<div class="hello-cards">' +
'<div class="ext-hello-dashboard-cards">' +
card('Platform Access', (typeof UI !== 'undefined' ? '\u2713 Connected' : '\u2717 Unavailable'),
'API, Theme, UI primitives available', 'var(--accent)') +
card('Theme', isDark ? '\uD83C\uDF19 Dark' : '\u2600\uFE0F Light',
@@ -33,11 +33,11 @@
card('Route', '<code>' + esc(manifest.route || '/s/hello-dashboard') + '</code>',
'Registered via surface manifest', '') +
'</div>' +
'<div class="hello-actions">' +
'<div class="ext-hello-dashboard-actions">' +
'<button class="sw-btn sw-btn--primary sw-btn--md" id="helloToast">Show Toast</button>' +
'<button class="sw-btn sw-btn--secondary sw-btn--md" id="helloApi">Test API</button>' +
'</div>' +
'<pre class="hello-manifest">' + esc(JSON.stringify(manifest, null, 2)) + '</pre>' +
'<pre class="ext-hello-dashboard-manifest">' + esc(JSON.stringify(manifest, null, 2)) + '</pre>' +
'</div>';
// Wire toast button
@@ -69,10 +69,10 @@
function card(title, value, detail, color) {
var style = color ? ' style="color:' + color + ';"' : '';
return '<div class="hello-card">' +
'<div class="hello-card-title">' + esc(title) + '</div>' +
'<div class="hello-card-value"' + style + '>' + value + '</div>' +
'<div class="hello-card-detail">' + esc(detail) + '</div>' +
return '<div class="ext-hello-dashboard-card">' +
'<div class="ext-hello-dashboard-card-title">' + esc(title) + '</div>' +
'<div class="ext-hello-dashboard-card-value"' + style + '>' + value + '</div>' +
'<div class="ext-hello-dashboard-card-detail">' + esc(detail) + '</div>' +
'</div>';
}