Feat v0.3.7 package audit

- Fix 6 chat-extension manifests: "name" → "title" (was blocking install)
- Add "type": "surface" to hello-dashboard, icd-test-runner, sdk-test-runner
- Add dormant status to packages schema (SQLite + Postgres)
- Installer auto-detects requires: ["chat"] → sets dormant + disabled
- Enable endpoint returns 409 for dormant packages
- Relax dependency check: pending_review libraries allowed
- Admin UI: dormant badge, disabled Enable button, Dormant stat card
- 4 new handler tests (143 total passing)
- Docker audit: all 16 packages install correctly

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-28 20:18:18 +00:00
parent d68451fe8e
commit 6fec66bcc1
16 changed files with 307 additions and 20 deletions

View File

@@ -27,6 +27,11 @@ function sourceBadge(source) {
return html`<span class="badge ${cls}">${source}</span>`;
}
function statusBadge(status) {
if (status === 'dormant') return html`<span class="badge" style="opacity:0.6;">dormant</span>`;
return null;
}
export default function PackagesSection() {
const [packages, setPackages] = useState([]);
const [loading, setLoading] = useState(true);
@@ -56,6 +61,10 @@ export default function PackagesSection() {
// ── Actions ─────────────────────────────────
async function toggleEnabled(pkg) {
if (CORE_IDS.has(pkg.id)) return;
if (pkg.status === 'dormant') {
sw.toast('This package requires chat — it cannot be enabled yet', 'error');
return;
}
try {
if (pkg.enabled) {
await sw.api.admin.packages.disable(pkg.id);
@@ -154,6 +163,7 @@ export default function PackagesSection() {
if (loading) return html`<div class="settings-placeholder">Loading\u2026</div>`;
const enabled = packages.filter(p => p.enabled).length;
const dormant = packages.filter(p => p.status === 'dormant').length;
const hasManifestSettings = (pkg) =>
pkg.manifest?.settings || pkg.package_settings;
@@ -163,6 +173,7 @@ export default function PackagesSection() {
<div class="stat-cards-grid" style="margin-bottom:16px;">
<div class="stat-card"><div class="stat-value">${packages.length}</div><div class="stat-label">Total</div></div>
<div class="stat-card"><div class="stat-value">${enabled}</div><div class="stat-label">Enabled</div></div>
${dormant > 0 && html`<div class="stat-card"><div class="stat-value">${dormant}</div><div class="stat-label">Dormant</div></div>`}
</div>
${/* ── Action bar ─────────────── */``}
@@ -194,12 +205,14 @@ export default function PackagesSection() {
${' '}${typeBadge(pkg.type)}
${' '}${tierBadge(pkg.tier)}
${sourceBadge(pkg.source)}
${statusBadge(pkg.status)}
${pkg.is_system && html`<span class="badge" style="margin-left:4px;">system</span>`}
</div>
<div class="admin-actions-cell">
<button class="btn-small"
onClick=${() => toggleEnabled(pkg)}
disabled=${CORE_IDS.has(pkg.id)}>
disabled=${CORE_IDS.has(pkg.id) || pkg.status === 'dormant'}
title=${pkg.status === 'dormant' ? 'Requires chat' : ''}>
${pkg.enabled ? 'Disable' : 'Enable'}
</button>
${hasManifestSettings(pkg) && html`