Adds first-class tracking for API and interface mutations across the
agent ecosystem. Breaking changes are documented, affected repos are
notified via inbox, and agents discover pending changes at session
start via the dispatch endpoint.
- Migration q4l5m6n7o8p9: interface_changes table
- Model/schema: InterfaceChange with draft→published→resolved lifecycle
- Router: POST/GET/PATCH /interface-changes/, /publish, /resolve actions
(auto-notify affected repo agents on publish; progress event on origin)
- Dispatch: GET /repos/{slug}/dispatch now returns pending_interface_changes
- MCP tools: register_interface_change, list_interface_changes,
publish_interface_change, resolve_interface_change
- Dashboard: /interface-changes page with type badges, planned calendar,
published cards, and draft table
- EP-CUST-ICR-001 registered: webhook subscriptions (deliberately deferred)
First record: trailing-slash normalisation (2026-04-26), published,
affecting repo-registry — visible in repo-registry dispatch immediately.
223 tests passing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
120 lines
6.3 KiB
JavaScript
120 lines
6.3 KiB
JavaScript
import {readFileSync} from "node:fs";
|
|
import {fileURLToPath} from "node:url";
|
|
import {dirname, join} from "node:path";
|
|
|
|
// Read improvement-modal.js at config load time and inject as a plain <script>.
|
|
// Observable Framework proxies all src/*.js files through its own module
|
|
// bundler — they cannot be imported via a raw <script type="module"> in <head>.
|
|
// Reading the file here and stripping the ES module export is the reliable path.
|
|
const _configDir = dirname(fileURLToPath(import.meta.url));
|
|
const _modalScript = readFileSync(
|
|
join(_configDir, "src/components/improvement-modal.js"), "utf-8"
|
|
)
|
|
.replace(/^export function /gm, "function ") // strip ES module export
|
|
+ "\ninitImprovementModal();\n"; // auto-initialise
|
|
|
|
export default {
|
|
root: "src",
|
|
title: "Custodian State Hub",
|
|
pages: [
|
|
// ── Pages (Overview first, then alphabetical) ────────────────────────────
|
|
{ name: "Overview", path: "/" },
|
|
{ name: "Capabilities", path: "/capability-requests" },
|
|
{ name: "Contributions", path: "/contributions" },
|
|
{ name: "Domains", path: "/domains" },
|
|
{ name: "Goals", path: "/goals" },
|
|
{ name: "Inbox", path: "/inbox" },
|
|
{ name: "Progress", path: "/progress" },
|
|
{ name: "Token Cost", path: "/token-cost" },
|
|
{ name: "Services (TPSC)", path: "/tpsc" },
|
|
{ name: "Todo", path: "/todo" },
|
|
{ name: "Tools & Apps", path: "/tools" },
|
|
// ── Sections (alphabetical) ───────────────────────────────────────────────
|
|
{
|
|
name: "Policies",
|
|
collapsible: true,
|
|
open: false,
|
|
pages: [
|
|
{ name: "Repository DoI", path: "/policy/repo-doi" },
|
|
{ name: "Workstream DoD", path: "/policy/workstream-dod" },
|
|
],
|
|
},
|
|
{
|
|
name: "Repositories",
|
|
path: "/repos",
|
|
collapsible: true,
|
|
open: false,
|
|
pages: [
|
|
{ name: "Debt", path: "/techdept" },
|
|
{ name: "Repo Sync", path: "/repo-sync" },
|
|
{ name: "SBOM", path: "/sbom" },
|
|
],
|
|
},
|
|
{
|
|
name: "Workstreams",
|
|
path: "/workstreams",
|
|
collapsible: true,
|
|
open: false,
|
|
pages: [
|
|
{ name: "Decisions", path: "/decisions" },
|
|
{ name: "Dependencies", path: "/dependencies" },
|
|
{ name: "Extends", path: "/extensions" },
|
|
{ name: "Interface Changes", path: "/interface-changes" },
|
|
{ name: "Interventions", path: "/interventions" },
|
|
{ name: "Tasks", path: "/tasks" },
|
|
{ name: "UI Feedback", path: "/ui-feedback" },
|
|
],
|
|
},
|
|
// ── Reference (always last) ───────────────────────────────────────────────
|
|
{
|
|
name: "Reference",
|
|
path: "/reference",
|
|
collapsible: true,
|
|
open: false,
|
|
pages: [
|
|
{ name: "Capabilities", path: "/docs/capabilities" },
|
|
{ name: "Connecting to the Hub", path: "/docs/connecting" },
|
|
{ name: "Dashboard", path: "/docs/dashboard" },
|
|
{ name: "Contributions", path: "/docs/contributions" },
|
|
{ name: "Decision Health", path: "/docs/decisions-kpi" },
|
|
{ name: "Decisions", path: "/docs/decisions" },
|
|
{ name: "Dependencies", path: "/docs/dependencies" },
|
|
{ name: "Domains", path: "/docs/domains" },
|
|
{ name: "Goals", path: "/docs/goals" },
|
|
{ name: "Extension Points", path: "/docs/extensions" },
|
|
{ name: "Inter-Repo Communication", path: "/docs/inter-repo-communication" },
|
|
{ name: "Interventions", path: "/docs/interventions" },
|
|
{ name: "Live Data", path: "/docs/live-data" },
|
|
{ name: "Overview", path: "/docs/overview" },
|
|
{ name: "Progress Log", path: "/docs/progress-log" },
|
|
{ name: "Ralph Workplan", path: "/docs/ralph-workplan" },
|
|
{ name: "Reference & Context Help", path: "/docs/reference" },
|
|
{ name: "Repo Integration", path: "/docs/repo-integration" },
|
|
{ name: "State Hub", path: "/docs/state-hub" },
|
|
{ name: "Repos", path: "/docs/repos" },
|
|
{ name: "SBOM", path: "/docs/sbom" },
|
|
{ name: "SCOPE.md", path: "/docs/scope" },
|
|
{ name: "Tasks", path: "/docs/tasks" },
|
|
{ name: "TPSC", path: "/docs/tpsc" },
|
|
{ name: "TPSC — GDPR Maturity", path: "/docs/gdpr-maturity" },
|
|
{ name: "Technical Debt", path: "/docs/debt" },
|
|
{ name: "Todo", path: "/docs/todo" },
|
|
{ name: "Workstream Health", path: "/docs/workstream-health-index" },
|
|
{ name: "Workstream Lifecycle", path: "/docs/workstream-lifecycle" },
|
|
{ name: "Workstreams", path: "/docs/workstreams" },
|
|
],
|
|
},
|
|
],
|
|
theme: ["air", "near-midnight"],
|
|
head: `<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🗄️</text></svg>">
|
|
<script>${_modalScript}</script>
|
|
<style>
|
|
.kpi-infobox { background: var(--theme-background-alt, #f9f9f9); border: 1px solid var(--theme-foreground-faint, #e0e0e0); border-radius: 10px; padding: 0.75rem 1rem; position: relative; box-shadow: 0 1px 6px rgba(0,0,0,0.07); margin-bottom: 1.25rem; }
|
|
.kpi-infobox-title { font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; color: var(--theme-foreground-muted, #888); margin-bottom: 0.55rem; padding-right: 1.6rem; }
|
|
.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 1rem; }
|
|
.filter-text-input { display: flex; align-items: center; }
|
|
.filter-text-input input { height: 30px; font-size: 0.85rem; padding: 0.25rem 0.5rem; border-radius: 6px; border: 1px solid var(--theme-foreground-faint, #ccc); background: var(--theme-background, #fff); font-family: inherit; color: inherit; }
|
|
</style>`,
|
|
footer: "Custodian State Hub — local-first, append-only, sovereignty-preserving.",
|
|
};
|