@mulmoclaude/core 0.24.0 → 0.25.0
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/assets/helps/google-calendar-collection.md +79 -0
- package/assets/helps/index.md +1 -0
- package/dist/collection/core/schemaZ.d.ts +29 -0
- package/dist/collection/index.cjs +15 -14
- package/dist/collection/index.cjs.map +1 -1
- package/dist/collection/index.js +2 -1
- package/dist/collection/index.js.map +1 -1
- package/dist/collection/paths.cjs +5 -55
- package/dist/collection/paths.js +1 -51
- package/dist/collection/registry/server/index.cjs +20 -19
- package/dist/collection/registry/server/index.cjs.map +1 -1
- package/dist/collection/registry/server/index.js +3 -2
- package/dist/collection/registry/server/index.js.map +1 -1
- package/dist/collection/server/index.cjs +41 -40
- package/dist/collection/server/index.js +4 -3
- package/dist/collection-watchers/index.cjs +12 -11
- package/dist/collection-watchers/index.cjs.map +1 -1
- package/dist/collection-watchers/index.js +3 -2
- package/dist/collection-watchers/index.js.map +1 -1
- package/dist/discovery-3K_Wtkvn.js +1636 -0
- package/dist/discovery-3K_Wtkvn.js.map +1 -0
- package/dist/discovery-BZ2ms1tE.cjs +1865 -0
- package/dist/discovery-BZ2ms1tE.cjs.map +1 -0
- package/dist/feeds/index.cjs +4 -4
- package/dist/feeds/index.js +2 -2
- package/dist/feeds/server/index.cjs +16 -15
- package/dist/feeds/server/index.cjs.map +1 -1
- package/dist/feeds/server/index.js +4 -3
- package/dist/feeds/server/index.js.map +1 -1
- package/dist/google/apiClient.d.ts +8 -1
- package/dist/google/calendar.d.ts +35 -0
- package/dist/google/calendarSyncStore.d.ts +7 -0
- package/dist/google/collectionSync.d.ts +70 -0
- package/dist/google/index.cjs +296 -4
- package/dist/google/index.cjs.map +1 -1
- package/dist/google/index.d.ts +4 -2
- package/dist/google/index.js +281 -5
- package/dist/google/index.js.map +1 -1
- package/dist/ids-BR4U1dJD.cjs +150 -0
- package/dist/ids-BR4U1dJD.cjs.map +1 -0
- package/dist/ids-D4e10971.js +85 -0
- package/dist/ids-D4e10971.js.map +1 -0
- package/dist/{ingestTypes-CFEgTItj.js → ingestTypes-BsGOjR2l.js} +2 -2
- package/dist/{ingestTypes-CFEgTItj.js.map → ingestTypes-BsGOjR2l.js.map} +1 -1
- package/dist/{ingestTypes-Stc7iQyA.cjs → ingestTypes-CygUXsjf.cjs} +3 -3
- package/dist/{ingestTypes-Stc7iQyA.cjs.map → ingestTypes-CygUXsjf.cjs.map} +1 -1
- package/dist/{promptSafety-BLUcImzd.js → promptSafety-Boz5qOs-.js} +2 -84
- package/dist/promptSafety-Boz5qOs-.js.map +1 -0
- package/dist/{promptSafety-DI_1Rvhk.cjs → promptSafety-Co4cYQ_Z.cjs} +1 -149
- package/dist/promptSafety-Co4cYQ_Z.cjs.map +1 -0
- package/dist/remote-host/server/index.cjs +6 -4
- package/dist/remote-host/server/index.cjs.map +1 -1
- package/dist/remote-host/server/index.js +6 -4
- package/dist/remote-host/server/index.js.map +1 -1
- package/dist/scheduler/index.cjs +3 -1
- package/dist/scheduler/index.cjs.map +1 -1
- package/dist/scheduler/index.js +3 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/{server-CkysfLh4.cjs → server-DLRz-U7F.cjs} +76 -1884
- package/dist/server-DLRz-U7F.cjs.map +1 -0
- package/dist/{server-BpEo0FOd.js → server-DZH7OjOD.js} +5 -1609
- package/dist/server-DZH7OjOD.js.map +1 -0
- package/dist/skill-bridge/index.cjs +2 -2
- package/dist/skill-bridge/index.cjs.map +1 -1
- package/dist/skill-bridge/index.js +1 -1
- package/dist/templatePath-27vUZowm.cjs +75 -0
- package/dist/templatePath-27vUZowm.cjs.map +1 -0
- package/dist/templatePath-k_WNbL_Q.js +52 -0
- package/dist/templatePath-k_WNbL_Q.js.map +1 -0
- package/package.json +1 -1
- package/dist/collection/paths.cjs.map +0 -1
- package/dist/collection/paths.js.map +0 -1
- package/dist/promptSafety-BLUcImzd.js.map +0 -1
- package/dist/promptSafety-DI_1Rvhk.cjs.map +0 -1
- package/dist/server-BpEo0FOd.js.map +0 -1
- package/dist/server-CkysfLh4.cjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/collection/registry/server/fetch.ts","../../../../src/collection/registry/server/registriesConfig.ts","../../../../src/collection/registry/server/client.ts","../../../../src/collection/registry/server/collectionFiles.ts","../../../../src/collection/registry/server/importCollection.ts","../../../../src/collection/registry/server/importWriter.ts","../../../../src/collection/registry/server/exportCollection.ts","../../../../src/collection/registry/server/skillDescription.ts","../../../../src/collection/registry/server/performExport.ts","../../../../src/collection/registry/server/index.ts"],"sourcesContent":["// `fetch` with a finite timeout, ported from the host (server/utils/fetch.ts)\n// so the registry engine carries no dependency on host utils.\n\nimport { ONE_SECOND_MS } from \"../../server/util.js\";\n\n// 10 s is long enough for a healthy registry round-trip but short enough that a\n// stuck upstream returns an error well before any client-side tool timeout.\nexport const DEFAULT_FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\n\n// `Parameters<typeof fetch>[1]` avoids referencing the ambient `RequestInit`\n// type, which ESLint's `no-undef` rule trips over in the server config. The\n// resulting type is identical to `RequestInit & { timeoutMs?: number }`.\nexport type FetchWithTimeoutInit = Parameters<typeof fetch>[1] & { timeoutMs?: number };\n\n/** `fetch` with a finite timeout. Rejects with a `TimeoutError` once `timeoutMs`\n * elapses. Composes with a caller-supplied `signal` so external cancellation\n * still works. */\nexport async function fetchWithTimeout(url: string | URL, init: FetchWithTimeoutInit = {}): Promise<Response> {\n const { timeoutMs = DEFAULT_FETCH_TIMEOUT_MS, signal: callerSignal, ...rest } = init;\n\n // Surface an already-aborted caller signal before we touch the network at all,\n // so callers get a deterministic rejection and no fetch side-effects.\n if (callerSignal?.aborted) {\n throw callerSignal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => {\n controller.abort(new DOMException(`fetch timed out after ${timeoutMs}ms`, \"TimeoutError\"));\n }, timeoutMs);\n\n const unsubscribeCaller = bridgeExternalSignal(callerSignal, controller);\n\n try {\n return await fetch(url, { ...rest, signal: controller.signal });\n } finally {\n clearTimeout(timer);\n unsubscribeCaller?.();\n }\n}\n\n// Propagate aborts from a caller-supplied signal into our internal controller.\n// Returns a disposer so the listener is removed on normal completion — otherwise\n// a long-lived caller signal would leak listeners across many fetches.\nfunction bridgeExternalSignal(external: AbortSignal | null | undefined, controller: AbortController): (() => void) | null {\n if (!external) return null;\n const onAbort = () => controller.abort(external.reason);\n external.addEventListener(\"abort\", onAbort, { once: true });\n return () => external.removeEventListener(\"abort\", onAbort);\n}\n","// User-supplied list of extra collection registries (`config/collections-registries.json`).\n// The official receptron/mulmoclaude-collections registry is always loaded; this\n// file adds more on top so a community / org / private registry shows up in the\n// same Discover catalog.\n//\n// Shape on disk:\n// [\n// { \"name\": \"myorg\", \"indexUrl\": \"https://...\", \"rawBaseUrl\": \"https://...\" }\n// ]\n//\n// Validation rules (a bad entry is dropped + logged; the rest still load):\n// - `name` matches `[A-Za-z0-9][A-Za-z0-9_-]{0,31}` and is NOT the reserved\n// `official` (which is always synthesized by client.ts)\n// - Both URLs are HTTPS, parseable, and have no userinfo/credentials\n// - Names are unique (later duplicates are dropped, first wins)\n//\n// Pure read + parse — no network. Caller invalidates by re-reading the file.\n\nimport { readFileSync } from \"node:fs\";\n\nimport { isRecord } from \"../guards.js\";\nimport { OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"../types.js\";\nimport { collectionsRegistriesConfigPath, log } from \"../../server/host.js\";\n\nexport { OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry };\n\nconst NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;\n\nfunction isValidHttpsUrl(value: unknown): value is string {\n if (typeof value !== \"string\" || value.length === 0) return false;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return false;\n }\n if (url.protocol !== \"https:\") return false;\n if (url.username !== \"\" || url.password !== \"\") return false;\n return true;\n}\n\nfunction parseEntry(value: unknown, index: number): RegistryConfigEntry | string {\n if (!isRecord(value)) return `entry[${index}] is not an object`;\n const { name, indexUrl, rawBaseUrl } = value;\n if (typeof name !== \"string\" || !NAME_RE.test(name)) {\n return `entry[${index}].name must match ${NAME_RE.source}`;\n }\n if (name === OFFICIAL_REGISTRY_NAME) {\n return `entry[${index}].name \"${OFFICIAL_REGISTRY_NAME}\" is reserved`;\n }\n if (!isValidHttpsUrl(indexUrl)) return `entry[${index}].indexUrl must be a valid HTTPS URL (no credentials)`;\n if (!isValidHttpsUrl(rawBaseUrl)) return `entry[${index}].rawBaseUrl must be a valid HTTPS URL (no credentials)`;\n // `rawBaseUrl` gets joined as `${rawBaseUrl}/<path>` downstream — a query or\n // fragment would land in the middle of the composed URL and break every\n // collection-file fetch on that registry (CodeRabbit review on #1837). The\n // index URL is fetched directly so a query is fine there; only rawBase\n // needs the constraint.\n if (rawBaseUrl.includes(\"?\") || rawBaseUrl.includes(\"#\")) {\n return `entry[${index}].rawBaseUrl must not contain a query (?) or fragment (#) — it's joined as a path prefix`;\n }\n // Strip trailing slashes so `${rawBaseUrl}/${path}` joins cleanly regardless\n // of what the user wrote. Plain-loop trim instead of a regex — the linter\n // flags any unanchored-quantifier regex as ReDoS-suspect even when it's\n // safe, and the loop is just as clear at this size.\n let normalizedRawBase = rawBaseUrl;\n while (normalizedRawBase.endsWith(\"/\")) normalizedRawBase = normalizedRawBase.slice(0, -1);\n return { name, indexUrl, rawBaseUrl: normalizedRawBase };\n}\n\n/** Parse the JSON text of `config/collections-registries.json`. Bad entries\n * drop with a warning; valid entries are returned in source order. Exported\n * for unit testing — the I/O wrapper `loadRegistriesConfig` below reads the\n * workspace file and delegates here. */\nexport function parseRegistriesConfig(raw: unknown): RegistryConfigEntry[] {\n if (!Array.isArray(raw)) {\n log.warn(\"collections-registry\", \"registries config is not an array — ignoring\");\n return [];\n }\n const seen = new Set<string>();\n const out: RegistryConfigEntry[] = [];\n for (let i = 0; i < raw.length; i++) {\n const parsed = parseEntry(raw[i], i);\n if (typeof parsed === \"string\") {\n log.warn(\"collections-registry\", \"registry config entry rejected\", { reason: parsed });\n continue;\n }\n if (seen.has(parsed.name)) {\n log.warn(\"collections-registry\", \"registry config duplicate name dropped\", { name: parsed.name });\n continue;\n }\n seen.add(parsed.name);\n out.push(parsed);\n }\n return out;\n}\n\n// Missing file ⇒ null (the most common case — most users only want the official\n// registry). Other read errors propagate, matching the host's prior behavior.\nfunction readConfigTextOrNull(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch (err) {\n if (isRecord(err) && err.code === \"ENOENT\") return null;\n throw err;\n }\n}\n\n/** Read `config/collections-registries.json` from the configured workspace.\n * Missing file ⇒ empty list. Malformed JSON or rejected entries log but never\n * throw. */\nexport function loadRegistriesConfig(): RegistryConfigEntry[] {\n const text = readConfigTextOrNull(collectionsRegistriesConfigPath());\n if (text === null) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n log.warn(\"collections-registry\", \"registries config is not valid JSON — ignoring\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return [];\n }\n return parseRegistriesConfig(parsed);\n}\n","// Server-side client for the curated collection registries' published index.json\n// files. The official registry (receptron/mulmoclaude-collections via GitHub Pages)\n// is always loaded; users can append more via `config/collections-registries.json`.\n// Each index is fetched over HTTPS with a timeout, validated against the index\n// contract, and memo-cached per-registry so the Discover tab doesn't hammer the\n// upstreams. On a transient upstream failure we serve that registry's last good\n// index rather than failing the whole Discover view.\n\nimport { fetchWithTimeout } from \"./fetch.js\";\nimport { errorMessage, ONE_SECOND_MS } from \"../../server/util.js\";\nimport { log } from \"../../server/host.js\";\nimport { parseRegistryIndex, type RegistryEntry, type RegistryIndex } from \"../registryIndex.js\";\nimport { loadRegistriesConfig, OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"./registriesConfig.js\";\n\nconst DEFAULT_OFFICIAL_INDEX_URL = \"https://receptron.github.io/mulmoclaude-collections/index.json\";\nconst DEFAULT_OFFICIAL_RAW_BASE = \"https://raw.githubusercontent.com/receptron/mulmoclaude-collections/main\";\nexport const CACHE_TTL_MS = 5 * 60 * ONE_SECOND_MS;\n// During an outage (cache past TTL + failing upstream) don't re-hit the network\n// more than once per this window — serve stale immediately in between, so a down\n// upstream can't add its full timeout to every request.\nexport const STALE_RETRY_BACKOFF_MS = 60 * ONE_SECOND_MS;\nconst FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\nconst STATUS_BAD_GATEWAY = 502;\nconst STATUS_UNAVAILABLE = 503;\n\n/** Per-registry fetch outcome. `ok: false` is reported per-registry — the\n * merged Discover response still succeeds when at least one registry is\n * reachable; failed registries just contribute zero entries. */\nexport type FetchIndexResult = { ok: true; index: RegistryIndex; stale: boolean } | { ok: false; status: number; error: string };\n\ninterface CacheEntry {\n index: RegistryIndex;\n atMs: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\nconst lastFailureMs = new Map<string, number>();\n\n/** Resolved descriptor for one registry the host should fetch — name + URLs.\n * `official` is always synthesized; further entries come from\n * `config/collections-registries.json`. Currently structurally identical to\n * `RegistryConfigEntry`; aliased so we can add server-only fields (e.g.\n * auth headers) without touching the on-disk config schema. */\nexport type RegistryDescriptor = RegistryConfigEntry;\n\nfunction officialDescriptor(): RegistryDescriptor {\n return {\n name: OFFICIAL_REGISTRY_NAME,\n indexUrl: process.env.COLLECTIONS_REGISTRY_URL ?? DEFAULT_OFFICIAL_INDEX_URL,\n rawBaseUrl: process.env.COLLECTIONS_REGISTRY_RAW_BASE ?? DEFAULT_OFFICIAL_RAW_BASE,\n };\n}\n\n/** The full ordered registry list: official first, then user-configured ones.\n * Re-reads the config file on every call so a Discover refresh picks up edits\n * without a server restart (the config is small + read-rarely). */\nexport function listRegistries(): RegistryDescriptor[] {\n return [officialDescriptor(), ...loadRegistriesConfig()];\n}\n\n/** Look up one registry descriptor by name. Used by the preview / import path,\n * which has the registry label from the entry and needs the rawBase. */\nexport function findRegistry(name: string): RegistryDescriptor | null {\n return listRegistries().find((reg) => reg.name === name) ?? null;\n}\n\nasync function loadFromNetwork(descriptor: RegistryDescriptor): Promise<FetchIndexResult> {\n let res: Response;\n try {\n res = await fetchWithTimeout(descriptor.indexUrl, { timeoutMs: FETCH_TIMEOUT_MS, headers: { accept: \"application/json\" } });\n } catch (err) {\n log.warn(\"collections-registry\", \"index fetch failed\", { registry: descriptor.name, url: descriptor.indexUrl, error: errorMessage(err) });\n return { ok: false, status: STATUS_UNAVAILABLE, error: \"registry unreachable\" };\n }\n if (!res.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry responded ${res.status}` };\n const json: unknown = await res.json().catch(() => null);\n const parsed = parseRegistryIndex(json, descriptor.name);\n if (!parsed.ok) {\n log.warn(\"collections-registry\", \"index invalid\", { registry: descriptor.name, url: descriptor.indexUrl, error: parsed.error });\n return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry index invalid: ${parsed.error}` };\n }\n return { ok: true, index: parsed.index, stale: false };\n}\n\nexport type IndexLoader = (descriptor: RegistryDescriptor) => Promise<FetchIndexResult>;\n\n/** Cache key incorporates BOTH URLs so editing `indexUrl` or `rawBaseUrl` for\n * an existing registry name invalidates the cached index automatically — same\n * refresh cycle as if the user had renamed it (CodeRabbit review on #1837).\n * Without this, the Discover catalog could keep serving the old upstream's\n * entries while preview / import resolved the new rawBase, drifting until TTL\n * expiry. Tab + key-content guarantees no collision between e.g. swapped\n * name/url pairs. */\nfunction descriptorCacheKey(descriptor: RegistryDescriptor): string {\n return `${descriptor.name}\\t${descriptor.indexUrl}\\t${descriptor.rawBaseUrl}`;\n}\n\n/** Fetch one registry's index. Same cache + stale-on-failure semantics as the\n * original single-registry implementation — just keyed by descriptor identity\n * (name + both URLs) so multiple registries don't fight over one slot AND a\n * reconfigured registry doesn't serve a stale index from the prior URL. */\nexport async function fetchRegistryIndex(\n descriptor: RegistryDescriptor,\n opts: { force?: boolean; nowMs?: number; loader?: IndexLoader } = {},\n): Promise<FetchIndexResult> {\n const nowMs = opts.nowMs ?? Date.now();\n const loader = opts.loader ?? loadFromNetwork;\n const key = descriptorCacheKey(descriptor);\n const cached = cache.get(key);\n if (!opts.force && cached && nowMs - cached.atMs < CACHE_TTL_MS) {\n return { ok: true, index: cached.index, stale: false };\n }\n const failedAt = lastFailureMs.get(key);\n if (!opts.force && cached && failedAt !== undefined && nowMs - failedAt < STALE_RETRY_BACKOFF_MS) {\n return { ok: true, index: cached.index, stale: true };\n }\n const fresh = await loader(descriptor);\n if (fresh.ok) {\n cache.set(key, { index: fresh.index, atMs: nowMs });\n lastFailureMs.delete(key);\n return { ok: true, index: fresh.index, stale: false };\n }\n lastFailureMs.set(key, nowMs);\n if (cached) return { ok: true, index: cached.index, stale: true };\n return fresh;\n}\n\n/** One registry's contribution to the merged Discover view. `failed` registries\n * surface in the response so the UI can show a per-registry error badge while\n * still rendering the entries from the registries that did work. */\nexport interface MergedRegistryResult {\n name: string;\n status: \"ok\" | \"stale\" | \"failed\";\n generatedAt: string | null;\n error: string | null;\n entries: RegistryEntry[];\n}\n\n/** Fetch every configured registry in parallel and return per-registry\n * outcomes. Callers (the Discover route) concatenate `entries` from each.\n * Failure of any single registry doesn't abort the others — that's the point\n * of supporting multiple registries. */\nexport async function fetchAllRegistries(opts: { force?: boolean; nowMs?: number; loader?: IndexLoader } = {}): Promise<MergedRegistryResult[]> {\n const descriptors = listRegistries();\n return await Promise.all(\n descriptors.map(async (descriptor): Promise<MergedRegistryResult> => {\n const result = await fetchRegistryIndex(descriptor, opts);\n if (!result.ok) {\n return { name: descriptor.name, status: \"failed\", generatedAt: null, error: result.error, entries: [] };\n }\n return {\n name: descriptor.name,\n status: result.stale ? \"stale\" : \"ok\",\n generatedAt: result.index.generatedAt,\n error: null,\n entries: result.index.collections,\n };\n }),\n );\n}\n\n/** Test seam: reset the module cache + failure backoff state (all registries). */\nexport function resetRegistryCache(): void {\n cache.clear();\n lastFailureMs.clear();\n}\n","// Fetch individual files of a registry collection (schema.json, meta.json, …)\n// from the registry repo's raw content. The collection's repo-relative dir comes\n// from a trusted index entry (never raw user input), so the host can only fetch\n// files of collections that actually appear in the published index.\n//\n// The index itself is served from GitHub Pages (see client.ts); per-collection\n// files are served from raw.githubusercontent. With multi-registry support the\n// rawBase is no longer a single module-level value — it comes from the entry's\n// source registry descriptor, so user-added registries can live anywhere.\n\nimport { fetchWithTimeout } from \"./fetch.js\";\nimport { errorMessage, ONE_SECOND_MS } from \"../../server/util.js\";\nimport { isRecord } from \"../guards.js\";\nimport { fetchAllRegistries, findRegistry } from \"./client.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\nconst STATUS_BAD_GATEWAY = 502;\nconst STATUS_UNAVAILABLE = 503;\nconst STATUS_NOT_FOUND = 404;\n\n/** Compose the raw URL for `<dirPath>/<relFile>` under a given registry's\n * rawBase. Empty and traversal (`.`/`..`) segments are dropped so the URL can\n * never escape the base, even if an upstream check is bypassed (the index\n * parser already rejects such identifiers — this is defense-in-depth). The\n * rawBase is trailing-slash-normalized: `parseRegistriesConfig` already trims\n * user-config trailing slashes, but the official descriptor and any test\n * bypass parse — repeating the trim here keeps the join `${base}/${path}`\n * from producing `//` even when the caller bypassed config validation\n * (CodeRabbit review on #1837). */\nexport function collectionFileUrl(rawBase: string, dirPath: string, relFile: string): string {\n let base = rawBase;\n while (base.endsWith(\"/\")) base = base.slice(0, -1);\n const segments = dirPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \".\" && segment !== \"..\");\n return `${base}/${segments.join(\"/\")}/${relFile}`;\n}\n\nexport type FileResult = { ok: true; text: string } | { ok: false; status: number; error: string };\n\n/** Fetch one file out of a registry collection. `rawBase` comes from the\n * entry's source registry (`findRegistry(entry.registryName).rawBaseUrl`),\n * not a module-level setting — that's what makes additional user-configured\n * registries reachable. */\nexport async function fetchCollectionFile(rawBase: string, dirPath: string, relFile: string): Promise<FileResult> {\n const url = collectionFileUrl(rawBase, dirPath, relFile);\n let res: Response;\n try {\n res = await fetchWithTimeout(url, { timeoutMs: FETCH_TIMEOUT_MS });\n } catch (err) {\n return { ok: false, status: STATUS_UNAVAILABLE, error: `fetch failed: ${errorMessage(err)}` };\n }\n if (!res.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: `${relFile} responded ${res.status}` };\n return { ok: true, text: await res.text() };\n}\n\nexport type JsonObjectResult = { ok: true; value: Record<string, unknown> } | { ok: false; error: string };\n\nexport function parseJsonObject(text: string, label: string): JsonObjectResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return { ok: false, error: `${label} is not valid JSON` };\n }\n if (!isRecord(parsed)) return { ok: false, error: `${label} is not an object` };\n return { ok: true, value: parsed };\n}\n\nasync function fetchJsonObject(\n rawBase: string,\n dirPath: string,\n relFile: string,\n label: string,\n): Promise<{ ok: true; value: Record<string, unknown> } | { ok: false; status: number; error: string }> {\n const file = await fetchCollectionFile(rawBase, dirPath, relFile);\n if (!file.ok) return { ok: false, status: file.status, error: `${label}: ${file.error}` };\n const parsed = parseJsonObject(file.text, label);\n if (!parsed.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: parsed.error };\n return { ok: true, value: parsed.value };\n}\n\n/** Resolve an entry's rawBase from its `registryName`. A missing match (the\n * user removed the registry from config while a cached index still references\n * it) returns null — the caller surfaces it as a 404 rather than crashing. */\nexport function rawBaseForEntry(entry: Pick<RegistryEntry, \"registryName\">): string | null {\n const registry = findRegistry(entry.registryName);\n return registry?.rawBaseUrl ?? null;\n}\n\nexport type PreviewResult =\n { ok: true; entry: RegistryEntry; schema: Record<string, unknown>; meta: Record<string, unknown> } | { ok: false; status: number; error: string };\n\n/** Resolve an entry by author+slug across every cached registry's entries.\n * When `registry` is passed we constrain to that registry — needed because\n * multiple registries can publish the same author/slug, and the UI should\n * follow the card it just clicked. */\nfunction findEntryInMergedView(\n merged: { name: string; entries: RegistryEntry[] }[],\n author: string,\n slug: string,\n registry: string | null,\n): RegistryEntry | null {\n for (const reg of merged) {\n if (registry !== null && reg.name !== registry) continue;\n const match = reg.entries.find((candidate) => candidate.author === author && candidate.slug === slug);\n if (match) return match;\n }\n return null;\n}\n\n/** Preview a registry collection: confirm it's in some registry's published\n * index, then fetch + parse its schema.json + meta.json so the Discover tab\n * can show fields/views before import. With multi-registry support the\n * `registry` arg disambiguates same-name collections from different sources. */\nexport async function previewCollection(author: string, slug: string, registry: string | null = null): Promise<PreviewResult> {\n const merged = await fetchAllRegistries();\n const entry = findEntryInMergedView(merged, author, slug, registry);\n if (!entry) return { ok: false, status: STATUS_NOT_FOUND, error: `unknown collection: ${author}/${slug}` };\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_NOT_FOUND, error: `registry \"${entry.registryName}\" is no longer configured` };\n const schema = await fetchJsonObject(rawBase, entry.path, \"schema.json\", \"schema.json\");\n if (!schema.ok) return schema;\n const meta = await fetchJsonObject(rawBase, entry.path, \"meta.json\", \"meta.json\");\n if (!meta.ok) return meta;\n return { ok: true, entry, schema: schema.value, meta: meta.value };\n}\n","// Import-side fetch + transform helpers for a registry collection. The writer\n// (writes into .claude/skills/, materializes seed, records provenance) builds on\n// these; kept separate so the pure, security-critical parts are unit-tested.\n//\n// Files to fetch come from the collection's manifest.json (published by the\n// registry's build-index). Every manifest path is re-checked for safety here —\n// the host must never write outside the target skill dir even if the manifest is\n// malformed/poisoned.\n\nimport { isRecord } from \"../guards.js\";\nimport { fetchCollectionFile, parseJsonObject, rawBaseForEntry } from \"./collectionFiles.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst MANIFEST_FILE = \"manifest.json\";\nconst STATUS_BAD_GATEWAY = 502;\n\n/** A manifest entry must be a relative path that stays inside the collection dir:\n * no absolute paths, no backslashes, no empty / `.` / `..` segments. */\nexport function isSafeBundlePath(rel: unknown): rel is string {\n if (typeof rel !== \"string\" || rel.length === 0) return false;\n if (rel.startsWith(\"/\") || rel.includes(\"\\\\\")) return false;\n return !rel.split(\"/\").some((segment) => segment === \"\" || segment === \".\" || segment === \"..\");\n}\n\nexport type ManifestResult = { ok: true; files: string[] } | { ok: false; error: string };\n\nexport function parseManifest(value: unknown): ManifestResult {\n if (!isRecord(value) || !Array.isArray(value.files)) return { ok: false, error: \"manifest is missing a files[] array\" };\n const unsafe = value.files.find((file) => !isSafeBundlePath(file));\n if (unsafe !== undefined) return { ok: false, error: `manifest contains an unsafe path: ${String(unsafe)}` };\n return { ok: true, files: value.files.filter(isSafeBundlePath) };\n}\n\n/** `data/collections/<localSlug>/items` — the host owns dataPath, never the\n * registry's authored value, so imported collections can't collide on disk. */\nexport function normalizedDataPath(localSlug: string): string {\n return `data/collections/${localSlug}/items`;\n}\n\nexport function withNormalizedDataPath(schema: Record<string, unknown>, localSlug: string): Record<string, unknown> {\n return { ...schema, dataPath: normalizedDataPath(localSlug) };\n}\n\nexport type ManifestFetch = { ok: true; files: string[] } | { ok: false; status: number; error: string };\n\nexport async function fetchManifest(entry: RegistryEntry): Promise<ManifestFetch> {\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry \"${entry.registryName}\" is no longer configured` };\n const file = await fetchCollectionFile(rawBase, entry.path, MANIFEST_FILE);\n if (!file.ok) return { ok: false, status: file.status, error: `manifest.json: ${file.error}` };\n const obj = parseJsonObject(file.text, \"manifest.json\");\n if (!obj.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: obj.error };\n const manifest = parseManifest(obj.value);\n if (!manifest.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: manifest.error };\n return { ok: true, files: manifest.files };\n}\n\nexport type BundleFetch = { ok: true; files: Map<string, string> } | { ok: false; status: number; error: string };\n\n/** Fetch every manifest file. Paths are already safety-checked by parseManifest. */\nexport async function fetchBundle(entry: RegistryEntry, fileList: readonly string[]): Promise<BundleFetch> {\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry \"${entry.registryName}\" is no longer configured` };\n const files = new Map<string, string>();\n for (const rel of fileList) {\n const file = await fetchCollectionFile(rawBase, entry.path, rel);\n if (!file.ok) return { ok: false, status: file.status, error: `${rel}: ${file.error}` };\n files.set(rel, file.text);\n }\n return { ok: true, files };\n}\n","// Import a registry collection into the active workspace. The writer fetches\n// the bundle, re-validates the schema with the host's own gates (R7 — the\n// index is not a trust boundary), writes the bundle into `data/skills/<localSlug>/`\n// with a host-owned dataPath (R3), materializes any seed records into that\n// dataPath when it's empty, and records provenance in `.origin.json` for\n// update detection (R5/R8). After the data-skills swap, the bundle's\n// allowlisted files (SKILL.md, schema.json, templates/<safe>) are mirrored\n// 1:1 into `.claude/skills/<localSlug>/` via the same skill-bridge rules an\n// agent-authored skill would go through — so an authored and an imported\n// collection live in EXACTLY the same place on disk, and the user can edit\n// either one identically.\n//\n// `.origin.json` lives ONLY in `data/skills/<slug>/.origin.json` and is NOT\n// mirrored — the skill-bridge allowlist deliberately excludes host\n// bookkeeping. Its presence is what distinguishes \"imported\" from\n// \"user-authored\" in every downstream tool.\n//\n// `writeImportedCollection` takes the already-fetched bundle + an explicit\n// workspaceRoot/clock so it is unit-testable against a temp workspace with\n// no network; `performImport` is the thin glue that fetches and calls it.\n\nimport { mkdir, readFile, readdir, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport type { Dirent } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { acceptParsedSchema, CollectionSchemaZ, isSafeActionTemplatePath, safeRecordId } from \"../../server/index.js\";\nimport type { CollectionSchema } from \"../../index.js\";\nimport { claudeSkillDir, dataSkillDir, mirrorSkillWrite } from \"../../../skill-bridge/index.js\";\n\nimport { log } from \"../../server/host.js\";\nimport { errorMessage } from \"../../server/util.js\";\nimport { writeFileAtomic } from \"../../server/atomic.js\";\nimport { isRecord } from \"../guards.js\";\nimport { fetchAllRegistries } from \"./client.js\";\nimport { fetchBundle, fetchManifest, normalizedDataPath } from \"./importCollection.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst ORIGIN_FILE = \".origin.json\";\nconst SEED_PREFIX = \"seed/items/\";\nconst SCHEMA_FILE = \"schema.json\";\nconst SKILL_FILE = \"SKILL.md\";\nconst STATUS_NOT_FOUND = 404;\nconst STATUS_CONFLICT = 409;\nconst STATUS_UNPROCESSABLE = 422;\n\nexport interface ImportOrigin {\n registry: string;\n author: string;\n slug: string;\n version: string;\n contentSha: string;\n importedAt: string;\n}\n\nexport type ImportResult =\n { ok: true; localSlug: string; updated: boolean; seedWritten: number; seedSkipped: boolean } | { ok: false; status: number; error: string };\n\nasync function statType(target: string): Promise<\"dir\" | \"other\" | \"absent\"> {\n try {\n return (await stat(target)).isDirectory() ? \"dir\" : \"other\";\n } catch (err) {\n // EACCES etc. are path-shape conflicts mkdir would later throw on → \"other\".\n // A file ancestor surfaces as ENOTDIR on POSIX but ENOENT on Windows (which\n // reports the whole path as missing), so ENOENT can't be trusted as \"absent\"\n // until we've confirmed no existing ancestor is a non-directory file.\n if (!(isRecord(err) && err.code === \"ENOENT\")) return \"other\";\n return (await hasNonDirAncestor(target)) ? \"other\" : \"absent\";\n }\n}\n\n// Walk up from `target` to the nearest ancestor that exists: a non-directory\n// file there means `target` can never be mkdir'd (a path-shape conflict → 409),\n// whichever errno the platform's `stat(target)` chose. An all-absent-or-directory\n// chain up to the filesystem root is a genuine \"absent\".\nasync function hasNonDirAncestor(target: string): Promise<boolean> {\n let current = path.dirname(target);\n while (current !== path.dirname(current)) {\n try {\n return !(await stat(current)).isDirectory();\n } catch (err) {\n if (isRecord(err) && err.code === \"ENOENT\") {\n current = path.dirname(current);\n continue;\n }\n return true;\n }\n }\n return false;\n}\n\nasync function isEmptyOrAbsentDir(target: string): Promise<boolean> {\n try {\n return (await readdir(target)).length === 0;\n } catch {\n return true;\n }\n}\n\nfunction originMatches(origin: unknown, registry: string, author: string, slug: string): boolean {\n return isRecord(origin) && origin.registry === registry && origin.author === author && origin.slug === slug;\n}\n\nasync function readOrigin(targetDir: string): Promise<unknown> {\n try {\n return JSON.parse(await readFile(path.join(targetDir, ORIGIN_FILE), \"utf-8\"));\n } catch {\n return null;\n }\n}\n\ntype TargetResolution = { targetDir: string; localSlug: string; updated: boolean } | { conflict: string };\n\n// Only bounds the fresh-slug search (a safety cap, far above any realistic\n// number of same-named collections — the first free slug is normally found in\n// 1–2 iterations). An EXISTING install is found via the directory scan below,\n// not this loop, so updates are never missed regardless of how high the rename\n// suffix is.\nconst MAX_SLUG_ATTEMPTS = 10000;\n\nconst renameCandidate = (slug: string, attempt: number): string => (attempt === 0 ? slug : `${slug}-${attempt + 1}`);\n\n// True when `name` is the registry slug or a `<slug>-<n>` rename of it.\nfunction isRenameOf(name: string, slug: string): boolean {\n if (name === slug) return true;\n if (!name.startsWith(`${slug}-`)) return false;\n const suffix = name.slice(slug.length + 1);\n return suffix.length > 0 && /^\\d+$/.test(suffix);\n}\n\n// Find an existing install of this registry collection at ANY rename suffix\n// by scanning `data/skills/` — independent of any candidate bound, so a\n// re-import always updates the existing install rather than duplicating it\n// (even if an earlier slug freed up). An authored skill without `.origin.json`\n// is invisible to this scan and so never collides with an update.\nasync function findMatchingInstall(skillsDir: string, registry: string, entry: RegistryEntry): Promise<string | null> {\n const names = await readdir(skillsDir).catch(() => [] as string[]);\n for (const name of names) {\n if (!isRenameOf(name, entry.slug)) continue;\n const dir = path.join(skillsDir, name);\n if ((await statType(dir)) === \"dir\" && originMatches(await readOrigin(dir), registry, entry.author, entry.slug)) return name;\n }\n return null;\n}\n\n// Pick the local install slug (rename-on-collision, R8). First reuse an\n// existing matching install (update). Otherwise install fresh at the first\n// free slug — the registry slug, else `<slug>-2`, `-3`, … — never clobbering\n// a user's own same-named collection.\n//\n// A slug is \"free\" only when BOTH `data/skills/<slug>/` AND\n// `.claude/skills/<slug>/` are absent. The mirror check matters because\n// `mirrorToClaudeSkills` overwrites the mirror dir's allowlisted files and\n// prunes anything else — if the user has a manually-installed Claude skill\n// at `.claude/skills/<slug>/` with no corresponding `data/skills/<slug>/`\n// (e.g. installed by the Claude CLI directly, or a legacy pre-refactor\n// import we never migrated), picking that slug would silently overwrite\n// their SKILL.md/schema.json and prune the rest of their files (CodeRabbit\n// review on #1839).\nasync function resolveTarget(workspaceRoot: string, registry: string, entry: RegistryEntry): Promise<TargetResolution> {\n const skillsDir = path.dirname(dataSkillDir(workspaceRoot, entry.slug));\n const existing = await findMatchingInstall(skillsDir, registry, entry);\n if (existing) return { targetDir: dataSkillDir(workspaceRoot, existing), localSlug: existing, updated: true };\n for (let attempt = 0; attempt < MAX_SLUG_ATTEMPTS; attempt += 1) {\n const localSlug = renameCandidate(entry.slug, attempt);\n const sourceAbsent = (await statType(dataSkillDir(workspaceRoot, localSlug))) === \"absent\";\n const mirrorAbsent = (await statType(claudeSkillDir(workspaceRoot, localSlug))) === \"absent\";\n if (sourceAbsent && mirrorAbsent) {\n return { targetDir: dataSkillDir(workspaceRoot, localSlug), localSlug, updated: false };\n }\n }\n return { conflict: `couldn't find an available slug for '${entry.slug}'` };\n}\n\ntype SchemaResolution = { schema: CollectionSchema } | { error: string };\n\nfunction validateAndNormalize(bundle: Map<string, string>, localSlug: string, workspaceRoot: string): SchemaResolution {\n // SKILL.md is required: `mirrorToClaudeSkills` calls\n // `mirrorSkillWrite({slug, relSegments: [SKILL_FILE]})` unconditionally\n // after the data-side swap, which throws if SKILL.md is missing. Caught\n // outside, that throw is logged but the data-side write still succeeds and\n // the function returns `ok: true` for an unusable import. Reject up front\n // so a missing SKILL.md surfaces as a clean 422 instead (CodeRabbit review\n // on #1839).\n if (bundle.get(SKILL_FILE) === undefined) return { error: \"bundle is missing SKILL.md\" };\n const schemaText = bundle.get(SCHEMA_FILE);\n if (schemaText === undefined) return { error: \"bundle is missing schema.json\" };\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(schemaText);\n } catch {\n return { error: \"schema.json is not valid JSON\" };\n }\n const parsed = CollectionSchemaZ.safeParse(parsedJson);\n if (!parsed.success) return { error: `schema.json failed validation: ${parsed.error.issues[0]?.message ?? \"invalid\"}` };\n // A `dataSource` collection can't be imported: its records are the rows of\n // a machine-local data file the bundle doesn't (and can't) carry — and the\n // R3 dataPath stamp below would collide with the exactly-one-of rule.\n if (parsed.data.dataSource !== undefined) {\n return { error: \"schema.json declares `dataSource` — external-data collections are machine-local and cannot be imported from a registry\" };\n }\n const schema: CollectionSchema = { ...parsed.data, dataPath: normalizedDataPath(localSlug) };\n const acceptance = acceptParsedSchema(schema, { source: \"project\", workspaceRoot, slug: localSlug });\n if (!acceptance.ok) return { error: `schema.json rejected: ${acceptance.reason}` };\n return { schema };\n}\n\nasync function writeBundleFiles(targetDir: string, bundle: Map<string, string>, schema: CollectionSchema): Promise<void> {\n for (const [rel, content] of bundle) {\n if (rel.startsWith(SEED_PREFIX)) continue; // seed goes to dataPath, not the skill dir\n const dest = path.join(targetDir, ...rel.split(\"/\"));\n if (dest !== targetDir && !dest.startsWith(targetDir + path.sep)) continue; // belt-and-suspenders (paths pre-validated)\n await mkdir(path.dirname(dest), { recursive: true });\n await writeFile(dest, rel === SCHEMA_FILE ? `${JSON.stringify(schema, null, 2)}\\n` : content, \"utf-8\");\n }\n}\n\nasync function materializeSeed(dataDir: string, bundle: Map<string, string>): Promise<{ written: number; skipped: boolean }> {\n const seedEntries = [...bundle].filter(([rel]) => rel.startsWith(SEED_PREFIX));\n if (seedEntries.length === 0) return { written: 0, skipped: false };\n if (!(await isEmptyOrAbsentDir(dataDir))) return { written: 0, skipped: true };\n await mkdir(dataDir, { recursive: true });\n let written = 0;\n for (const [rel, content] of seedEntries) {\n const fileName = rel.slice(SEED_PREFIX.length);\n if (fileName.includes(\"/\") || safeRecordId(fileName.replace(/\\.json$/, \"\")) === null) {\n log.warn(\"collections-registry\", \"skipped unsafe seed record\", { rel });\n continue;\n }\n await writeFile(path.join(dataDir, fileName), content, \"utf-8\");\n written += 1;\n }\n return { written, skipped: false };\n}\n\n/** Compute the set of bundle-relative paths that should land in `.claude/skills/<slug>/`.\n * Matches the bridge allowlist exactly — SKILL.md, schema.json,\n * `templates/<safe>` — so anything else (seed, meta.json, views, README,\n * assets) stays source-side. */\nfunction bridgeAllowlistFiles(bundle: Map<string, string>): Set<string> {\n const wanted = new Set<string>([SKILL_FILE, SCHEMA_FILE]);\n for (const rel of bundle.keys()) {\n if (rel === SKILL_FILE || rel === SCHEMA_FILE) continue;\n if (rel.startsWith(SEED_PREFIX)) continue;\n if (!isSafeActionTemplatePath(rel)) continue;\n wanted.add(rel);\n }\n return wanted;\n}\n\n/** Recursively list every file under `root`, returned as forward-slash paths\n * relative to `root`. Empty list when `root` doesn't exist. Used to spot\n * mirror files left over from a previous install so we can prune them after\n * writing the new ones. */\nasync function listFilesRecursive(root: string, prefix = \"\"): Promise<string[]> {\n const dir = prefix ? path.join(root, ...prefix.split(\"/\")) : root;\n const entries: Dirent[] = await readdir(dir, { withFileTypes: true }).catch(() => [] as Dirent[]);\n const out: string[] = [];\n for (const entry of entries) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isFile()) out.push(rel);\n else if (entry.isDirectory()) out.push(...(await listFilesRecursive(root, rel)));\n }\n return out;\n}\n\n// Mirror the just-written `data/skills/<slug>/` into `.claude/skills/<slug>/`\n// using the shared bridge package — exactly the set of files an\n// agent-authored skill would mirror, no more (SKILL.md, schema.json,\n// templates/<safe>). `.origin.json` is host bookkeeping and stays only on the\n// data side.\n//\n// **Write-then-prune ordering** (Codex review on #1839): write the new\n// bundle's allowlisted files FIRST (each is a per-file tmp+rename, atomic),\n// THEN prune mirror files that aren't in the new bundle. A transient mirror\n// failure during the writes leaves the previous mirror's files in place —\n// agent discovery keeps working with the prior state instead of finding an\n// empty `.claude/skills/<slug>/`. The prune step is best-effort: a failure\n// there leaves harmless stale leftovers but doesn't break the new install.\n// Compare with the old `mirrorSkillDelete`-first ordering, which could\n// silently leave an empty mirror if a subsequent write threw.\nasync function mirrorToClaudeSkills(workspaceRoot: string, localSlug: string, bundle: Map<string, string>): Promise<void> {\n const wanted = bridgeAllowlistFiles(bundle);\n // 1. Write the new set first (overwrites existing via tmp+rename).\n for (const rel of wanted) {\n mirrorSkillWrite(workspaceRoot, { slug: localSlug, relSegments: rel.split(\"/\") });\n }\n // 2. Prune files that exist in the mirror but aren't in the new bundle.\n const mirrorRoot = claudeSkillDir(workspaceRoot, localSlug);\n const existing = await listFilesRecursive(mirrorRoot);\n for (const rel of existing) {\n if (wanted.has(rel)) continue;\n await rm(path.join(mirrorRoot, ...rel.split(\"/\")), { force: true }).catch(() => undefined);\n }\n}\n\nexport async function writeImportedCollection(params: {\n registry: string;\n entry: RegistryEntry;\n bundle: Map<string, string>;\n workspaceRoot: string;\n nowIso: string;\n}): Promise<ImportResult> {\n const { registry, entry, bundle, workspaceRoot, nowIso } = params;\n const target = await resolveTarget(workspaceRoot, registry, entry);\n if (\"conflict\" in target) return { ok: false, status: STATUS_CONFLICT, error: target.conflict };\n\n const { localSlug } = target;\n\n // Pre-flight the data dir before schema validation: a non-directory at the dataPath\n // (or an ancestor that's a file → ENOTDIR) would otherwise surface as a generic 500\n // on mkdir. statType maps ENOTDIR/other to a deterministic 409 path-shape conflict.\n const dataDir = path.join(workspaceRoot, ...normalizedDataPath(localSlug).split(\"/\"));\n if ((await statType(dataDir)) === \"other\") {\n return { ok: false, status: STATUS_CONFLICT, error: `data path for slug '${localSlug}' exists and is not a directory` };\n }\n\n const validated = validateAndNormalize(bundle, localSlug, workspaceRoot);\n if (\"error\" in validated) return { ok: false, status: STATUS_UNPROCESSABLE, error: validated.error };\n\n // Build the replacement fully in a hidden sibling staging dir under\n // `data/skills/` (bundle + origin), so the prior install is untouched until\n // everything is durably written. Leftover staging/backup dirs from a\n // crashed import are cleaned first, keeping retries possible.\n const skillsParent = path.dirname(target.targetDir);\n await mkdir(skillsParent, { recursive: true }); // first-import case — data/skills/ may not exist\n const staging = path.join(skillsParent, `.importing-${localSlug}`);\n const backup = path.join(skillsParent, `.backup-${localSlug}`);\n await rm(staging, { recursive: true, force: true });\n await rm(backup, { recursive: true, force: true });\n await mkdir(staging, { recursive: true });\n await writeBundleFiles(staging, bundle, validated.schema);\n const origin: ImportOrigin = { registry, author: entry.author, slug: entry.slug, version: entry.version, contentSha: entry.contentSha, importedAt: nowIso };\n await writeFileAtomic(path.join(staging, ORIGIN_FILE), `${JSON.stringify(origin, null, 2)}\\n`);\n\n // Swap with rollback: move the old install aside (rename), move the new in\n // (rename), then discard the old. If the swap fails, restore the old so we\n // never end up with no installed collection. Records live in dataPath (a\n // separate dir) and are untouched.\n if (target.updated) await rename(target.targetDir, backup);\n try {\n await rename(staging, target.targetDir);\n } catch (err) {\n if (target.updated) await rename(backup, target.targetDir).catch(() => undefined);\n throw err;\n }\n await rm(backup, { recursive: true, force: true });\n\n // Replicate the new `data/skills/<slug>/` set into `.claude/skills/<slug>/`\n // via the shared bridge package — same allowlist + tmp+rename semantics the\n // hook uses for agent-authored writes. Write-then-prune ordering inside\n // mirrorToClaudeSkills means a transient failure here can't leave the mirror\n // empty (Codex review on #1839); the worst case is a half-written mirror\n // where the new install's SKILL.md/schema.json may not have updated, but the\n // prior install remains accessible to the agent until the next mirror\n // attempt. Logged-not-thrown matches the hook's posture for agent writes.\n try {\n await mirrorToClaudeSkills(workspaceRoot, localSlug, bundle);\n } catch (err) {\n log.warn(\"collections-registry\", \"mirror to .claude/skills/ failed (data/skills write succeeded; prior mirror left intact)\", {\n localSlug,\n error: errorMessage(err),\n });\n }\n\n const seed = await materializeSeed(dataDir, bundle);\n return { ok: true, localSlug, updated: target.updated, seedWritten: seed.written, seedSkipped: seed.skipped };\n}\n\nexport async function performImport(author: string, slug: string, workspaceRoot: string, registry: string | null = null): Promise<ImportResult> {\n const merged = await fetchAllRegistries();\n let entry: RegistryEntry | undefined;\n for (const reg of merged) {\n if (registry !== null && reg.name !== registry) continue;\n entry = reg.entries.find((candidate) => candidate.author === author && candidate.slug === slug);\n if (entry) break;\n }\n if (!entry) return { ok: false, status: STATUS_NOT_FOUND, error: `unknown collection: ${author}/${slug}` };\n const manifest = await fetchManifest(entry);\n if (!manifest.ok) return { ok: false, status: manifest.status, error: manifest.error };\n const bundle = await fetchBundle(entry, manifest.files);\n if (!bundle.ok) return { ok: false, status: bundle.status, error: bundle.error };\n try {\n return await writeImportedCollection({\n registry: entry.registryName,\n entry,\n bundle: bundle.files,\n workspaceRoot,\n nowIso: new Date().toISOString(),\n });\n } catch (err) {\n log.warn(\"collections-registry\", \"import write failed\", { author, slug, registry: entry.registryName, error: errorMessage(err) });\n return { ok: false, status: 500, error: `import failed: ${errorMessage(err)}` };\n }\n}\n\n// Exported for downstream code that wants the path conventions without\n// importing skill-bridge directly.\nexport { claudeSkillDir, dataSkillDir, hasNonDirAncestor };\n","// Export a workspace collection into the curated registry's contribution layout\n// (collections/<author>/<slug>/ + meta.json + optional seed/) under\n// data/registry-export/, so the user can open a PR to the registry. The producer\n// side of the registry loop.\n//\n// writeCollectionExport takes explicit dirs + a workspace root so it is unit-testable\n// against temp dirs with no discovery/network; performExport (separate file) is the\n// thin glue that resolves the collection from the live workspace.\n\nimport { cp, mkdir, readdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { log } from \"../../server/host.js\";\n\nexport const EXPORT_BASE = \"data/registry-export\";\nconst BUNDLE_FILES = [\"SKILL.md\", \"schema.json\"] as const;\nconst OPTIONAL_FILES = [\"screenshot.png\"] as const;\nconst BUNDLE_DIRS = [\"views\", \"templates\"] as const;\nconst AUTHOR_RE = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}$/;\nconst SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}$/;\nconst STATUS_BAD_REQUEST = 400;\n// Block obvious credentials from being published in seed data; PII is only warned.\nconst SECRET_PATTERNS = [\n /AKIA[0-9A-Z]{16}/,\n /gh[pousr]_[A-Za-z0-9]{20,}/,\n /-----BEGIN [A-Z ]*PRIVATE KEY-----/,\n /sk-[A-Za-z0-9]{20,}/,\n /xox[baprs]-[A-Za-z0-9-]{10,}/,\n];\nconst hasSecret = (text: string): boolean => SECRET_PATTERNS.some((pattern) => pattern.test(text));\n// Bounded + non-overlapping (no ReDoS): local@label.tld with single quantifier runs.\nconst EMAIL_RE = /[\\w.%+-]{1,64}@[\\w-]{1,255}\\.[a-z]{2,24}/i;\n\nexport interface ExportMeta {\n author: string;\n slug: string;\n version: string;\n title: string;\n description: string;\n tags: string[];\n license: string;\n}\n\nexport type ExportResult =\n | { ok: true; outputPath: string; fileCount: number; seedCount: number; seedSkipped: number; warnings: string[] }\n | { ok: false; status: number; error: string };\n\nasync function pathKind(target: string): Promise<\"dir\" | \"file\" | \"absent\"> {\n try {\n return (await stat(target)).isDirectory() ? \"dir\" : \"file\";\n } catch {\n return \"absent\";\n }\n}\n\nasync function copyBundle(skillDir: string, outDir: string): Promise<number> {\n let count = 0;\n for (const file of [...BUNDLE_FILES, ...OPTIONAL_FILES]) {\n const src = path.join(skillDir, file);\n if ((await pathKind(src)) !== \"file\") continue;\n await cp(src, path.join(outDir, file));\n count += 1;\n }\n for (const dir of BUNDLE_DIRS) {\n const src = path.join(skillDir, dir);\n if ((await pathKind(src)) !== \"dir\") continue;\n await cp(src, path.join(outDir, dir), { recursive: true });\n count += (await readdir(src)).filter((name) => !name.startsWith(\".\")).length;\n }\n return count;\n}\n\nasync function exportSeed(dataDir: string, outDir: string): Promise<{ count: number; skipped: number; warnings: string[] }> {\n let names: string[];\n try {\n names = (await readdir(dataDir)).filter((name) => name.endsWith(\".json\"));\n } catch {\n return { count: 0, skipped: 0, warnings: [] };\n }\n if (names.length === 0) return { count: 0, skipped: 0, warnings: [] };\n const seedDir = path.join(outDir, \"seed\", \"items\");\n await mkdir(seedDir, { recursive: true });\n const warnings: string[] = [];\n let count = 0;\n let skipped = 0;\n for (const name of names) {\n const base = path.basename(name);\n const text = await readFile(path.join(dataDir, base), \"utf-8\");\n if (hasSecret(text)) {\n warnings.push(`skipped ${base}: contains a possible credential`);\n skipped += 1;\n continue;\n }\n if (EMAIL_RE.test(text)) warnings.push(`${base}: contains a possible email/PII (kept — your responsibility)`);\n await writeFile(path.join(seedDir, base), text, \"utf-8\");\n count += 1;\n }\n return { count, skipped, warnings };\n}\n\n// Resolve `segments` under `root` and return the absolute path only when it stays\n// inside `root` — a containment barrier for the user-derived author/slug and the\n// collection dirs, on top of the AUTHOR_RE/SLUG_RE format checks. `..` or an\n// absolute escape resolves outside `root` and yields null (rejected upstream).\nfunction resolveWithin(root: string, ...segments: string[]): string | null {\n const resolvedRoot = path.resolve(root);\n const target = path.resolve(resolvedRoot, ...segments);\n return target === resolvedRoot || target.startsWith(resolvedRoot + path.sep) ? target : null;\n}\n\n// Required bundle files (SKILL.md, schema.json) must be present — exporting an\n// incomplete bundle would pass here but fail downstream registry curation.\n// Returns the first missing required file, or null when all are present.\nasync function findMissingRequired(skillDir: string): Promise<string | null> {\n for (const file of BUNDLE_FILES) {\n if ((await pathKind(path.join(skillDir, file))) !== \"file\") return file;\n }\n return null;\n}\n\nexport async function writeCollectionExport(params: {\n workspaceRoot: string;\n skillDir: string;\n dataDir: string;\n meta: ExportMeta;\n includeSeed: boolean;\n}): Promise<ExportResult> {\n const { workspaceRoot, skillDir, dataDir, meta, includeSeed } = params;\n if (!AUTHOR_RE.test(meta.author)) return { ok: false, status: STATUS_BAD_REQUEST, error: `author '${meta.author}' is not a valid GitHub login` };\n if (!SLUG_RE.test(meta.slug)) return { ok: false, status: STATUS_BAD_REQUEST, error: `slug '${meta.slug}' is invalid` };\n\n const wsRoot = path.resolve(workspaceRoot);\n const exportRoot = path.join(wsRoot, ...EXPORT_BASE.split(\"/\"));\n const outDir = resolveWithin(exportRoot, meta.author, meta.slug);\n const safeSkillDir = resolveWithin(wsRoot, skillDir);\n const safeDataDir = resolveWithin(wsRoot, dataDir);\n if (!outDir || !safeSkillDir || !safeDataDir) {\n return { ok: false, status: STATUS_BAD_REQUEST, error: \"resolved path escapes the workspace\" };\n }\n\n const missing = await findMissingRequired(safeSkillDir);\n if (missing) {\n return { ok: false, status: STATUS_BAD_REQUEST, error: `required bundle file missing: ${missing}` };\n }\n\n await rm(outDir, { recursive: true, force: true });\n await mkdir(outDir, { recursive: true });\n\n const bundleCount = await copyBundle(safeSkillDir, outDir);\n const seed = includeSeed ? await exportSeed(safeDataDir, outDir) : { count: 0, skipped: 0, warnings: [] };\n const metaOut = { ...meta, ...(seed.count > 0 ? { dataConsent: true } : {}) };\n await writeFile(path.join(outDir, \"meta.json\"), `${JSON.stringify(metaOut, null, 2)}\\n`, \"utf-8\");\n log.info(\"collections-registry\", \"exported collection\", { slug: meta.slug, author: meta.author, seedCount: seed.count });\n const outRel = path.relative(wsRoot, outDir).split(path.sep).join(\"/\");\n return { ok: true, outputPath: outRel, fileCount: bundleCount + 1, seedCount: seed.count, seedSkipped: seed.skipped, warnings: seed.warnings };\n}\n","// `description:` reader for a SKILL.md YAML frontmatter envelope.\n//\n// The host (MulmoClaude) parses SKILL.md frontmatter with js-yaml, but\n// @mulmoclaude/core deliberately carries no YAML dependency and export only needs\n// the single `description` scalar for the registry meta.json (best-effort — it\n// defaults to \"\" when absent). Rather than pull in a YAML parser we scan the\n// envelope for the first `description:` line and resolve the common YAML scalar\n// forms so exported descriptions match what the host produced:\n// - double-quoted (\"…\") → unescaped, trailing inline comment ignored\n// - single-quoted ('…') → '' → ', trailing inline comment ignored\n// - plain (unquoted) → trailing \" #comment\" stripped (YAML comment rule)\n// Block scalars (`description: |`) are NOT expanded — they yield \"\" (skill\n// descriptions are single-line in practice).\n\nconst FENCE = \"---\";\nconst KEY = \"description:\";\nconst BLOCK_SCALAR_INDICATORS = new Set([\"|\", \">\", \"|-\", \">-\", \"|+\", \">+\"]);\n\nconst isYamlSpace = (char: string | undefined): boolean => char === \" \" || char === \"\\t\";\n\n// After a closing quote, YAML allows only whitespace and an optional \"#\" comment.\n// Anything else (e.g. `\"foo\" bar`) is malformed — js-yaml would throw, so we\n// reject (→ null → \"\") rather than silently truncate.\nconst isOnlyTrailingComment = (rest: string): boolean => {\n const trimmed = rest.trimStart();\n return trimmed === \"\" || trimmed.startsWith(\"#\");\n};\n\n// Escapes a description realistically carries inside a double-quoted scalar;\n// any other `\\x` collapses to the literal `x`.\nconst DOUBLE_QUOTE_ESCAPES: Record<string, string> = { n: \"\\n\", t: \"\\t\" };\nconst unescapeDoubleQuote = (next: string): string => DOUBLE_QUOTE_ESCAPES[next] ?? next;\n\n// Double-quoted scalar: walk to the closing unescaped quote. Returns null for a\n// malformed scalar (no closing quote, or trailing non-comment text) so the caller\n// degrades to \"\" — matching the host's js-yaml behavior.\nfunction parseDoubleQuoted(value: string): string | null {\n const out: string[] = [];\n for (let i = 1; i < value.length; i += 1) {\n const char = value[i];\n if (char === \"\\\\\" && i + 1 < value.length) {\n out.push(unescapeDoubleQuote(value[i + 1]));\n i += 1;\n continue;\n }\n if (char === '\"') return isOnlyTrailingComment(value.slice(i + 1)) ? out.join(\"\") : null;\n out.push(char);\n }\n return null; // unterminated\n}\n\n// Single-quoted scalar: the only escape is a doubled quote (''). Same\n// malformed-rejection contract as parseDoubleQuoted.\nfunction parseSingleQuoted(value: string): string | null {\n const out: string[] = [];\n for (let i = 1; i < value.length; i += 1) {\n const char = value[i];\n if (char === \"'\") {\n if (value[i + 1] === \"'\") {\n out.push(\"'\");\n i += 1;\n continue;\n }\n return isOnlyTrailingComment(value.slice(i + 1)) ? out.join(\"\") : null;\n }\n out.push(char);\n }\n return null; // unterminated\n}\n\n// Plain scalar: a \"#\" preceded by whitespace (or at the start) begins a YAML\n// comment; \"#\" not preceded by whitespace (e.g. \"C#\") is literal.\nfunction stripPlainComment(value: string): string {\n for (let i = 0; i < value.length; i += 1) {\n if (value[i] === \"#\" && (i === 0 || isYamlSpace(value[i - 1]))) return value.slice(0, i);\n }\n return value;\n}\n\n/** Extract the frontmatter `description` from raw SKILL.md text. Returns \"\" when\n * there's no `---` envelope, no `description:` key, or the value is a block\n * scalar indicator. */\nexport function parseSkillDescription(raw: string): string {\n const lines = raw.split(/\\r?\\n/);\n if (lines[0]?.trim() !== FENCE) return \"\";\n for (let i = 1; i < lines.length; i += 1) {\n const line = lines[i];\n if (line.trim() === FENCE) return \"\"; // end of envelope, key not found\n if (!line.startsWith(KEY)) continue;\n const value = line.slice(KEY.length).trim();\n if (value === \"\" || BLOCK_SCALAR_INDICATORS.has(value)) return \"\";\n if (value.startsWith('\"')) return parseDoubleQuoted(value) ?? \"\";\n if (value.startsWith(\"'\")) return parseSingleQuoted(value) ?? \"\";\n return stripPlainComment(value).trim();\n }\n return \"\";\n}\n","// Thin glue for the collection export: resolve the collection from the live workspace\n// (its skill dir + data dir + schema), derive meta from SKILL.md front-matter / any\n// existing meta.json, then hand off to the testable writeCollectionExport. Kept\n// separate so the file-writing core stays import-light + unit-testable.\n\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { loadCollection } from \"../../server/index.js\";\nimport { isRecord } from \"../guards.js\";\nimport { parseSkillDescription } from \"./skillDescription.js\";\nimport { writeCollectionExport, type ExportMeta, type ExportResult } from \"./exportCollection.js\";\n\nconst STATUS_NOT_FOUND = 404;\nconst STATUS_UNPROCESSABLE = 422;\n\nasync function readJsonObject(file: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed: unknown = JSON.parse(await readFile(file, \"utf-8\"));\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport async function performExport(\n slug: string,\n opts: { author: string; license: string; includeSeed: boolean },\n workspaceRoot: string,\n): Promise<ExportResult> {\n const collection = await loadCollection(slug);\n if (!collection) return { ok: false, status: STATUS_NOT_FOUND, error: `collection not found: ${slug}` };\n // Mirrors the import-side refusal: a `dataSource` collection's records are\n // a machine-local data file a bundle can't carry.\n if (collection.schema.dataSource !== undefined) {\n return { ok: false, status: STATUS_UNPROCESSABLE, error: `collection '${slug}' is backed by an external dataSource and cannot be exported to a registry` };\n }\n const skillMd = await readFile(path.join(collection.skillDir, \"SKILL.md\"), \"utf-8\").catch(() => \"\");\n const existingMeta = await readJsonObject(path.join(collection.skillDir, \"meta.json\"));\n const meta: ExportMeta = {\n author: opts.author,\n slug,\n version: typeof existingMeta?.version === \"string\" ? existingMeta.version : \"1.0.0\",\n title: collection.schema.title,\n description: parseSkillDescription(skillMd),\n tags: [],\n license: opts.license,\n };\n return writeCollectionExport({ workspaceRoot, skillDir: collection.skillDir, dataDir: collection.dataDir, meta, includeSeed: opts.includeSeed });\n}\n","// @mulmoclaude/core/collection/registry/server — node-only collection registry\n// engine (Discover catalog fetch/cache, import writer, export writer). Shares the\n// `configureCollectionHost` binding with @mulmoclaude/core/collection/server, so a\n// host wires the workspace + logger + paths ONCE and both engines work. The\n// isomorphic contract types live on @mulmoclaude/core/collection/registry.\n\nimport { fetchAllRegistries } from \"./client.js\";\nimport { performImport } from \"./importWriter.js\";\nimport type { RegistryListResponse, RegistryImportResponse } from \"../types.js\";\n\nexport {\n CACHE_TTL_MS,\n STALE_RETRY_BACKOFF_MS,\n fetchAllRegistries,\n fetchRegistryIndex,\n findRegistry,\n listRegistries,\n resetRegistryCache,\n type FetchIndexResult,\n type IndexLoader,\n type MergedRegistryResult,\n type RegistryDescriptor,\n} from \"./client.js\";\nexport {\n collectionFileUrl,\n fetchCollectionFile,\n parseJsonObject,\n previewCollection,\n rawBaseForEntry,\n type FileResult,\n type JsonObjectResult,\n type PreviewResult,\n} from \"./collectionFiles.js\";\nexport {\n fetchBundle,\n fetchManifest,\n isSafeBundlePath,\n normalizedDataPath,\n parseManifest,\n withNormalizedDataPath,\n type BundleFetch,\n type ManifestFetch,\n type ManifestResult,\n} from \"./importCollection.js\";\nexport { claudeSkillDir, dataSkillDir, performImport, writeImportedCollection, type ImportOrigin, type ImportResult } from \"./importWriter.js\";\nexport { EXPORT_BASE, writeCollectionExport, type ExportMeta, type ExportResult } from \"./exportCollection.js\";\nexport { performExport } from \"./performExport.js\";\nexport { parseSkillDescription } from \"./skillDescription.js\";\nexport { loadRegistriesConfig, parseRegistriesConfig, OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"./registriesConfig.js\";\nexport type { RegistryEntry, RegistryIndex, ParseResult } from \"../registryIndex.js\";\nexport { parseRegistryIndex } from \"../registryIndex.js\";\nexport type { RegistrySummary, RegistryListResponse, RegistryImportResponse } from \"../types.js\";\n\n/** Build the merged Discover catalog response (`GET …collectionsRegistry.list`).\n * Wraps `fetchAllRegistries` with the per-registry summary + stale-flag shaping\n * every host needs, so a downstream host doesn't re-implement the mapping. */\nexport async function listRegistry(): Promise<RegistryListResponse> {\n const merged = await fetchAllRegistries();\n return {\n registries: merged.map((reg) => ({\n name: reg.name,\n status: reg.status,\n generatedAt: reg.generatedAt,\n error: reg.error,\n entryCount: reg.entries.length,\n })),\n stale: merged.some((reg) => reg.status === \"stale\"),\n collections: merged.flatMap((reg) => reg.entries),\n };\n}\n\nexport type RegistryImportOutcome = { ok: true; response: RegistryImportResponse } | { ok: false; status: number; error: string };\n\n/** Import a registry collection and return the host-facing response shape\n * (`POST …collectionsRegistry.import`). On failure carries the HTTP status so\n * the host route can pass it straight through. */\nexport async function importRegistry(author: string, slug: string, workspaceRoot: string, registry: string | null = null): Promise<RegistryImportOutcome> {\n const result = await performImport(author, slug, workspaceRoot, registry);\n if (!result.ok) return { ok: false, status: result.status, error: result.error };\n return {\n ok: true,\n response: { localSlug: result.localSlug, updated: result.updated, seedWritten: result.seedWritten, seedSkipped: result.seedSkipped },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../../src/collection/registry/server/fetch.ts","../../../../src/collection/registry/server/registriesConfig.ts","../../../../src/collection/registry/server/client.ts","../../../../src/collection/registry/server/collectionFiles.ts","../../../../src/collection/registry/server/importCollection.ts","../../../../src/collection/registry/server/importWriter.ts","../../../../src/collection/registry/server/exportCollection.ts","../../../../src/collection/registry/server/skillDescription.ts","../../../../src/collection/registry/server/performExport.ts","../../../../src/collection/registry/server/index.ts"],"sourcesContent":["// `fetch` with a finite timeout, ported from the host (server/utils/fetch.ts)\n// so the registry engine carries no dependency on host utils.\n\nimport { ONE_SECOND_MS } from \"../../server/util.js\";\n\n// 10 s is long enough for a healthy registry round-trip but short enough that a\n// stuck upstream returns an error well before any client-side tool timeout.\nexport const DEFAULT_FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\n\n// `Parameters<typeof fetch>[1]` avoids referencing the ambient `RequestInit`\n// type, which ESLint's `no-undef` rule trips over in the server config. The\n// resulting type is identical to `RequestInit & { timeoutMs?: number }`.\nexport type FetchWithTimeoutInit = Parameters<typeof fetch>[1] & { timeoutMs?: number };\n\n/** `fetch` with a finite timeout. Rejects with a `TimeoutError` once `timeoutMs`\n * elapses. Composes with a caller-supplied `signal` so external cancellation\n * still works. */\nexport async function fetchWithTimeout(url: string | URL, init: FetchWithTimeoutInit = {}): Promise<Response> {\n const { timeoutMs = DEFAULT_FETCH_TIMEOUT_MS, signal: callerSignal, ...rest } = init;\n\n // Surface an already-aborted caller signal before we touch the network at all,\n // so callers get a deterministic rejection and no fetch side-effects.\n if (callerSignal?.aborted) {\n throw callerSignal.reason ?? new DOMException(\"Aborted\", \"AbortError\");\n }\n\n const controller = new AbortController();\n const timer = setTimeout(() => {\n controller.abort(new DOMException(`fetch timed out after ${timeoutMs}ms`, \"TimeoutError\"));\n }, timeoutMs);\n\n const unsubscribeCaller = bridgeExternalSignal(callerSignal, controller);\n\n try {\n return await fetch(url, { ...rest, signal: controller.signal });\n } finally {\n clearTimeout(timer);\n unsubscribeCaller?.();\n }\n}\n\n// Propagate aborts from a caller-supplied signal into our internal controller.\n// Returns a disposer so the listener is removed on normal completion — otherwise\n// a long-lived caller signal would leak listeners across many fetches.\nfunction bridgeExternalSignal(external: AbortSignal | null | undefined, controller: AbortController): (() => void) | null {\n if (!external) return null;\n const onAbort = () => controller.abort(external.reason);\n external.addEventListener(\"abort\", onAbort, { once: true });\n return () => external.removeEventListener(\"abort\", onAbort);\n}\n","// User-supplied list of extra collection registries (`config/collections-registries.json`).\n// The official receptron/mulmoclaude-collections registry is always loaded; this\n// file adds more on top so a community / org / private registry shows up in the\n// same Discover catalog.\n//\n// Shape on disk:\n// [\n// { \"name\": \"myorg\", \"indexUrl\": \"https://...\", \"rawBaseUrl\": \"https://...\" }\n// ]\n//\n// Validation rules (a bad entry is dropped + logged; the rest still load):\n// - `name` matches `[A-Za-z0-9][A-Za-z0-9_-]{0,31}` and is NOT the reserved\n// `official` (which is always synthesized by client.ts)\n// - Both URLs are HTTPS, parseable, and have no userinfo/credentials\n// - Names are unique (later duplicates are dropped, first wins)\n//\n// Pure read + parse — no network. Caller invalidates by re-reading the file.\n\nimport { readFileSync } from \"node:fs\";\n\nimport { isRecord } from \"../guards.js\";\nimport { OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"../types.js\";\nimport { collectionsRegistriesConfigPath, log } from \"../../server/host.js\";\n\nexport { OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry };\n\nconst NAME_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,31}$/;\n\nfunction isValidHttpsUrl(value: unknown): value is string {\n if (typeof value !== \"string\" || value.length === 0) return false;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return false;\n }\n if (url.protocol !== \"https:\") return false;\n if (url.username !== \"\" || url.password !== \"\") return false;\n return true;\n}\n\nfunction parseEntry(value: unknown, index: number): RegistryConfigEntry | string {\n if (!isRecord(value)) return `entry[${index}] is not an object`;\n const { name, indexUrl, rawBaseUrl } = value;\n if (typeof name !== \"string\" || !NAME_RE.test(name)) {\n return `entry[${index}].name must match ${NAME_RE.source}`;\n }\n if (name === OFFICIAL_REGISTRY_NAME) {\n return `entry[${index}].name \"${OFFICIAL_REGISTRY_NAME}\" is reserved`;\n }\n if (!isValidHttpsUrl(indexUrl)) return `entry[${index}].indexUrl must be a valid HTTPS URL (no credentials)`;\n if (!isValidHttpsUrl(rawBaseUrl)) return `entry[${index}].rawBaseUrl must be a valid HTTPS URL (no credentials)`;\n // `rawBaseUrl` gets joined as `${rawBaseUrl}/<path>` downstream — a query or\n // fragment would land in the middle of the composed URL and break every\n // collection-file fetch on that registry (CodeRabbit review on #1837). The\n // index URL is fetched directly so a query is fine there; only rawBase\n // needs the constraint.\n if (rawBaseUrl.includes(\"?\") || rawBaseUrl.includes(\"#\")) {\n return `entry[${index}].rawBaseUrl must not contain a query (?) or fragment (#) — it's joined as a path prefix`;\n }\n // Strip trailing slashes so `${rawBaseUrl}/${path}` joins cleanly regardless\n // of what the user wrote. Plain-loop trim instead of a regex — the linter\n // flags any unanchored-quantifier regex as ReDoS-suspect even when it's\n // safe, and the loop is just as clear at this size.\n let normalizedRawBase = rawBaseUrl;\n while (normalizedRawBase.endsWith(\"/\")) normalizedRawBase = normalizedRawBase.slice(0, -1);\n return { name, indexUrl, rawBaseUrl: normalizedRawBase };\n}\n\n/** Parse the JSON text of `config/collections-registries.json`. Bad entries\n * drop with a warning; valid entries are returned in source order. Exported\n * for unit testing — the I/O wrapper `loadRegistriesConfig` below reads the\n * workspace file and delegates here. */\nexport function parseRegistriesConfig(raw: unknown): RegistryConfigEntry[] {\n if (!Array.isArray(raw)) {\n log.warn(\"collections-registry\", \"registries config is not an array — ignoring\");\n return [];\n }\n const seen = new Set<string>();\n const out: RegistryConfigEntry[] = [];\n for (let i = 0; i < raw.length; i++) {\n const parsed = parseEntry(raw[i], i);\n if (typeof parsed === \"string\") {\n log.warn(\"collections-registry\", \"registry config entry rejected\", { reason: parsed });\n continue;\n }\n if (seen.has(parsed.name)) {\n log.warn(\"collections-registry\", \"registry config duplicate name dropped\", { name: parsed.name });\n continue;\n }\n seen.add(parsed.name);\n out.push(parsed);\n }\n return out;\n}\n\n// Missing file ⇒ null (the most common case — most users only want the official\n// registry). Other read errors propagate, matching the host's prior behavior.\nfunction readConfigTextOrNull(filePath: string): string | null {\n try {\n return readFileSync(filePath, \"utf-8\");\n } catch (err) {\n if (isRecord(err) && err.code === \"ENOENT\") return null;\n throw err;\n }\n}\n\n/** Read `config/collections-registries.json` from the configured workspace.\n * Missing file ⇒ empty list. Malformed JSON or rejected entries log but never\n * throw. */\nexport function loadRegistriesConfig(): RegistryConfigEntry[] {\n const text = readConfigTextOrNull(collectionsRegistriesConfigPath());\n if (text === null) return [];\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n log.warn(\"collections-registry\", \"registries config is not valid JSON — ignoring\", {\n error: err instanceof Error ? err.message : String(err),\n });\n return [];\n }\n return parseRegistriesConfig(parsed);\n}\n","// Server-side client for the curated collection registries' published index.json\n// files. The official registry (receptron/mulmoclaude-collections via GitHub Pages)\n// is always loaded; users can append more via `config/collections-registries.json`.\n// Each index is fetched over HTTPS with a timeout, validated against the index\n// contract, and memo-cached per-registry so the Discover tab doesn't hammer the\n// upstreams. On a transient upstream failure we serve that registry's last good\n// index rather than failing the whole Discover view.\n\nimport { fetchWithTimeout } from \"./fetch.js\";\nimport { errorMessage, ONE_SECOND_MS } from \"../../server/util.js\";\nimport { log } from \"../../server/host.js\";\nimport { parseRegistryIndex, type RegistryEntry, type RegistryIndex } from \"../registryIndex.js\";\nimport { loadRegistriesConfig, OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"./registriesConfig.js\";\n\nconst DEFAULT_OFFICIAL_INDEX_URL = \"https://receptron.github.io/mulmoclaude-collections/index.json\";\nconst DEFAULT_OFFICIAL_RAW_BASE = \"https://raw.githubusercontent.com/receptron/mulmoclaude-collections/main\";\nexport const CACHE_TTL_MS = 5 * 60 * ONE_SECOND_MS;\n// During an outage (cache past TTL + failing upstream) don't re-hit the network\n// more than once per this window — serve stale immediately in between, so a down\n// upstream can't add its full timeout to every request.\nexport const STALE_RETRY_BACKOFF_MS = 60 * ONE_SECOND_MS;\nconst FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\nconst STATUS_BAD_GATEWAY = 502;\nconst STATUS_UNAVAILABLE = 503;\n\n/** Per-registry fetch outcome. `ok: false` is reported per-registry — the\n * merged Discover response still succeeds when at least one registry is\n * reachable; failed registries just contribute zero entries. */\nexport type FetchIndexResult = { ok: true; index: RegistryIndex; stale: boolean } | { ok: false; status: number; error: string };\n\ninterface CacheEntry {\n index: RegistryIndex;\n atMs: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\nconst lastFailureMs = new Map<string, number>();\n\n/** Resolved descriptor for one registry the host should fetch — name + URLs.\n * `official` is always synthesized; further entries come from\n * `config/collections-registries.json`. Currently structurally identical to\n * `RegistryConfigEntry`; aliased so we can add server-only fields (e.g.\n * auth headers) without touching the on-disk config schema. */\nexport type RegistryDescriptor = RegistryConfigEntry;\n\nfunction officialDescriptor(): RegistryDescriptor {\n return {\n name: OFFICIAL_REGISTRY_NAME,\n indexUrl: process.env.COLLECTIONS_REGISTRY_URL ?? DEFAULT_OFFICIAL_INDEX_URL,\n rawBaseUrl: process.env.COLLECTIONS_REGISTRY_RAW_BASE ?? DEFAULT_OFFICIAL_RAW_BASE,\n };\n}\n\n/** The full ordered registry list: official first, then user-configured ones.\n * Re-reads the config file on every call so a Discover refresh picks up edits\n * without a server restart (the config is small + read-rarely). */\nexport function listRegistries(): RegistryDescriptor[] {\n return [officialDescriptor(), ...loadRegistriesConfig()];\n}\n\n/** Look up one registry descriptor by name. Used by the preview / import path,\n * which has the registry label from the entry and needs the rawBase. */\nexport function findRegistry(name: string): RegistryDescriptor | null {\n return listRegistries().find((reg) => reg.name === name) ?? null;\n}\n\nasync function loadFromNetwork(descriptor: RegistryDescriptor): Promise<FetchIndexResult> {\n let res: Response;\n try {\n res = await fetchWithTimeout(descriptor.indexUrl, { timeoutMs: FETCH_TIMEOUT_MS, headers: { accept: \"application/json\" } });\n } catch (err) {\n log.warn(\"collections-registry\", \"index fetch failed\", { registry: descriptor.name, url: descriptor.indexUrl, error: errorMessage(err) });\n return { ok: false, status: STATUS_UNAVAILABLE, error: \"registry unreachable\" };\n }\n if (!res.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry responded ${res.status}` };\n const json: unknown = await res.json().catch(() => null);\n const parsed = parseRegistryIndex(json, descriptor.name);\n if (!parsed.ok) {\n log.warn(\"collections-registry\", \"index invalid\", { registry: descriptor.name, url: descriptor.indexUrl, error: parsed.error });\n return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry index invalid: ${parsed.error}` };\n }\n return { ok: true, index: parsed.index, stale: false };\n}\n\nexport type IndexLoader = (descriptor: RegistryDescriptor) => Promise<FetchIndexResult>;\n\n/** Cache key incorporates BOTH URLs so editing `indexUrl` or `rawBaseUrl` for\n * an existing registry name invalidates the cached index automatically — same\n * refresh cycle as if the user had renamed it (CodeRabbit review on #1837).\n * Without this, the Discover catalog could keep serving the old upstream's\n * entries while preview / import resolved the new rawBase, drifting until TTL\n * expiry. Tab + key-content guarantees no collision between e.g. swapped\n * name/url pairs. */\nfunction descriptorCacheKey(descriptor: RegistryDescriptor): string {\n return `${descriptor.name}\\t${descriptor.indexUrl}\\t${descriptor.rawBaseUrl}`;\n}\n\n/** Fetch one registry's index. Same cache + stale-on-failure semantics as the\n * original single-registry implementation — just keyed by descriptor identity\n * (name + both URLs) so multiple registries don't fight over one slot AND a\n * reconfigured registry doesn't serve a stale index from the prior URL. */\nexport async function fetchRegistryIndex(\n descriptor: RegistryDescriptor,\n opts: { force?: boolean; nowMs?: number; loader?: IndexLoader } = {},\n): Promise<FetchIndexResult> {\n const nowMs = opts.nowMs ?? Date.now();\n const loader = opts.loader ?? loadFromNetwork;\n const key = descriptorCacheKey(descriptor);\n const cached = cache.get(key);\n if (!opts.force && cached && nowMs - cached.atMs < CACHE_TTL_MS) {\n return { ok: true, index: cached.index, stale: false };\n }\n const failedAt = lastFailureMs.get(key);\n if (!opts.force && cached && failedAt !== undefined && nowMs - failedAt < STALE_RETRY_BACKOFF_MS) {\n return { ok: true, index: cached.index, stale: true };\n }\n const fresh = await loader(descriptor);\n if (fresh.ok) {\n cache.set(key, { index: fresh.index, atMs: nowMs });\n lastFailureMs.delete(key);\n return { ok: true, index: fresh.index, stale: false };\n }\n lastFailureMs.set(key, nowMs);\n if (cached) return { ok: true, index: cached.index, stale: true };\n return fresh;\n}\n\n/** One registry's contribution to the merged Discover view. `failed` registries\n * surface in the response so the UI can show a per-registry error badge while\n * still rendering the entries from the registries that did work. */\nexport interface MergedRegistryResult {\n name: string;\n status: \"ok\" | \"stale\" | \"failed\";\n generatedAt: string | null;\n error: string | null;\n entries: RegistryEntry[];\n}\n\n/** Fetch every configured registry in parallel and return per-registry\n * outcomes. Callers (the Discover route) concatenate `entries` from each.\n * Failure of any single registry doesn't abort the others — that's the point\n * of supporting multiple registries. */\nexport async function fetchAllRegistries(opts: { force?: boolean; nowMs?: number; loader?: IndexLoader } = {}): Promise<MergedRegistryResult[]> {\n const descriptors = listRegistries();\n return await Promise.all(\n descriptors.map(async (descriptor): Promise<MergedRegistryResult> => {\n const result = await fetchRegistryIndex(descriptor, opts);\n if (!result.ok) {\n return { name: descriptor.name, status: \"failed\", generatedAt: null, error: result.error, entries: [] };\n }\n return {\n name: descriptor.name,\n status: result.stale ? \"stale\" : \"ok\",\n generatedAt: result.index.generatedAt,\n error: null,\n entries: result.index.collections,\n };\n }),\n );\n}\n\n/** Test seam: reset the module cache + failure backoff state (all registries). */\nexport function resetRegistryCache(): void {\n cache.clear();\n lastFailureMs.clear();\n}\n","// Fetch individual files of a registry collection (schema.json, meta.json, …)\n// from the registry repo's raw content. The collection's repo-relative dir comes\n// from a trusted index entry (never raw user input), so the host can only fetch\n// files of collections that actually appear in the published index.\n//\n// The index itself is served from GitHub Pages (see client.ts); per-collection\n// files are served from raw.githubusercontent. With multi-registry support the\n// rawBase is no longer a single module-level value — it comes from the entry's\n// source registry descriptor, so user-added registries can live anywhere.\n\nimport { fetchWithTimeout } from \"./fetch.js\";\nimport { errorMessage, ONE_SECOND_MS } from \"../../server/util.js\";\nimport { isRecord } from \"../guards.js\";\nimport { fetchAllRegistries, findRegistry } from \"./client.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst FETCH_TIMEOUT_MS = 10 * ONE_SECOND_MS;\nconst STATUS_BAD_GATEWAY = 502;\nconst STATUS_UNAVAILABLE = 503;\nconst STATUS_NOT_FOUND = 404;\n\n/** Compose the raw URL for `<dirPath>/<relFile>` under a given registry's\n * rawBase. Empty and traversal (`.`/`..`) segments are dropped so the URL can\n * never escape the base, even if an upstream check is bypassed (the index\n * parser already rejects such identifiers — this is defense-in-depth). The\n * rawBase is trailing-slash-normalized: `parseRegistriesConfig` already trims\n * user-config trailing slashes, but the official descriptor and any test\n * bypass parse — repeating the trim here keeps the join `${base}/${path}`\n * from producing `//` even when the caller bypassed config validation\n * (CodeRabbit review on #1837). */\nexport function collectionFileUrl(rawBase: string, dirPath: string, relFile: string): string {\n let base = rawBase;\n while (base.endsWith(\"/\")) base = base.slice(0, -1);\n const segments = dirPath.split(\"/\").filter((segment) => segment.length > 0 && segment !== \".\" && segment !== \"..\");\n return `${base}/${segments.join(\"/\")}/${relFile}`;\n}\n\nexport type FileResult = { ok: true; text: string } | { ok: false; status: number; error: string };\n\n/** Fetch one file out of a registry collection. `rawBase` comes from the\n * entry's source registry (`findRegistry(entry.registryName).rawBaseUrl`),\n * not a module-level setting — that's what makes additional user-configured\n * registries reachable. */\nexport async function fetchCollectionFile(rawBase: string, dirPath: string, relFile: string): Promise<FileResult> {\n const url = collectionFileUrl(rawBase, dirPath, relFile);\n let res: Response;\n try {\n res = await fetchWithTimeout(url, { timeoutMs: FETCH_TIMEOUT_MS });\n } catch (err) {\n return { ok: false, status: STATUS_UNAVAILABLE, error: `fetch failed: ${errorMessage(err)}` };\n }\n if (!res.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: `${relFile} responded ${res.status}` };\n return { ok: true, text: await res.text() };\n}\n\nexport type JsonObjectResult = { ok: true; value: Record<string, unknown> } | { ok: false; error: string };\n\nexport function parseJsonObject(text: string, label: string): JsonObjectResult {\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return { ok: false, error: `${label} is not valid JSON` };\n }\n if (!isRecord(parsed)) return { ok: false, error: `${label} is not an object` };\n return { ok: true, value: parsed };\n}\n\nasync function fetchJsonObject(\n rawBase: string,\n dirPath: string,\n relFile: string,\n label: string,\n): Promise<{ ok: true; value: Record<string, unknown> } | { ok: false; status: number; error: string }> {\n const file = await fetchCollectionFile(rawBase, dirPath, relFile);\n if (!file.ok) return { ok: false, status: file.status, error: `${label}: ${file.error}` };\n const parsed = parseJsonObject(file.text, label);\n if (!parsed.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: parsed.error };\n return { ok: true, value: parsed.value };\n}\n\n/** Resolve an entry's rawBase from its `registryName`. A missing match (the\n * user removed the registry from config while a cached index still references\n * it) returns null — the caller surfaces it as a 404 rather than crashing. */\nexport function rawBaseForEntry(entry: Pick<RegistryEntry, \"registryName\">): string | null {\n const registry = findRegistry(entry.registryName);\n return registry?.rawBaseUrl ?? null;\n}\n\nexport type PreviewResult =\n { ok: true; entry: RegistryEntry; schema: Record<string, unknown>; meta: Record<string, unknown> } | { ok: false; status: number; error: string };\n\n/** Resolve an entry by author+slug across every cached registry's entries.\n * When `registry` is passed we constrain to that registry — needed because\n * multiple registries can publish the same author/slug, and the UI should\n * follow the card it just clicked. */\nfunction findEntryInMergedView(\n merged: { name: string; entries: RegistryEntry[] }[],\n author: string,\n slug: string,\n registry: string | null,\n): RegistryEntry | null {\n for (const reg of merged) {\n if (registry !== null && reg.name !== registry) continue;\n const match = reg.entries.find((candidate) => candidate.author === author && candidate.slug === slug);\n if (match) return match;\n }\n return null;\n}\n\n/** Preview a registry collection: confirm it's in some registry's published\n * index, then fetch + parse its schema.json + meta.json so the Discover tab\n * can show fields/views before import. With multi-registry support the\n * `registry` arg disambiguates same-name collections from different sources. */\nexport async function previewCollection(author: string, slug: string, registry: string | null = null): Promise<PreviewResult> {\n const merged = await fetchAllRegistries();\n const entry = findEntryInMergedView(merged, author, slug, registry);\n if (!entry) return { ok: false, status: STATUS_NOT_FOUND, error: `unknown collection: ${author}/${slug}` };\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_NOT_FOUND, error: `registry \"${entry.registryName}\" is no longer configured` };\n const schema = await fetchJsonObject(rawBase, entry.path, \"schema.json\", \"schema.json\");\n if (!schema.ok) return schema;\n const meta = await fetchJsonObject(rawBase, entry.path, \"meta.json\", \"meta.json\");\n if (!meta.ok) return meta;\n return { ok: true, entry, schema: schema.value, meta: meta.value };\n}\n","// Import-side fetch + transform helpers for a registry collection. The writer\n// (writes into .claude/skills/, materializes seed, records provenance) builds on\n// these; kept separate so the pure, security-critical parts are unit-tested.\n//\n// Files to fetch come from the collection's manifest.json (published by the\n// registry's build-index). Every manifest path is re-checked for safety here —\n// the host must never write outside the target skill dir even if the manifest is\n// malformed/poisoned.\n\nimport { isRecord } from \"../guards.js\";\nimport { fetchCollectionFile, parseJsonObject, rawBaseForEntry } from \"./collectionFiles.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst MANIFEST_FILE = \"manifest.json\";\nconst STATUS_BAD_GATEWAY = 502;\n\n/** A manifest entry must be a relative path that stays inside the collection dir:\n * no absolute paths, no backslashes, no empty / `.` / `..` segments. */\nexport function isSafeBundlePath(rel: unknown): rel is string {\n if (typeof rel !== \"string\" || rel.length === 0) return false;\n if (rel.startsWith(\"/\") || rel.includes(\"\\\\\")) return false;\n return !rel.split(\"/\").some((segment) => segment === \"\" || segment === \".\" || segment === \"..\");\n}\n\nexport type ManifestResult = { ok: true; files: string[] } | { ok: false; error: string };\n\nexport function parseManifest(value: unknown): ManifestResult {\n if (!isRecord(value) || !Array.isArray(value.files)) return { ok: false, error: \"manifest is missing a files[] array\" };\n const unsafe = value.files.find((file) => !isSafeBundlePath(file));\n if (unsafe !== undefined) return { ok: false, error: `manifest contains an unsafe path: ${String(unsafe)}` };\n return { ok: true, files: value.files.filter(isSafeBundlePath) };\n}\n\n/** `data/collections/<localSlug>/items` — the host owns dataPath, never the\n * registry's authored value, so imported collections can't collide on disk. */\nexport function normalizedDataPath(localSlug: string): string {\n return `data/collections/${localSlug}/items`;\n}\n\nexport function withNormalizedDataPath(schema: Record<string, unknown>, localSlug: string): Record<string, unknown> {\n return { ...schema, dataPath: normalizedDataPath(localSlug) };\n}\n\nexport type ManifestFetch = { ok: true; files: string[] } | { ok: false; status: number; error: string };\n\nexport async function fetchManifest(entry: RegistryEntry): Promise<ManifestFetch> {\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry \"${entry.registryName}\" is no longer configured` };\n const file = await fetchCollectionFile(rawBase, entry.path, MANIFEST_FILE);\n if (!file.ok) return { ok: false, status: file.status, error: `manifest.json: ${file.error}` };\n const obj = parseJsonObject(file.text, \"manifest.json\");\n if (!obj.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: obj.error };\n const manifest = parseManifest(obj.value);\n if (!manifest.ok) return { ok: false, status: STATUS_BAD_GATEWAY, error: manifest.error };\n return { ok: true, files: manifest.files };\n}\n\nexport type BundleFetch = { ok: true; files: Map<string, string> } | { ok: false; status: number; error: string };\n\n/** Fetch every manifest file. Paths are already safety-checked by parseManifest. */\nexport async function fetchBundle(entry: RegistryEntry, fileList: readonly string[]): Promise<BundleFetch> {\n const rawBase = rawBaseForEntry(entry);\n if (!rawBase) return { ok: false, status: STATUS_BAD_GATEWAY, error: `registry \"${entry.registryName}\" is no longer configured` };\n const files = new Map<string, string>();\n for (const rel of fileList) {\n const file = await fetchCollectionFile(rawBase, entry.path, rel);\n if (!file.ok) return { ok: false, status: file.status, error: `${rel}: ${file.error}` };\n files.set(rel, file.text);\n }\n return { ok: true, files };\n}\n","// Import a registry collection into the active workspace. The writer fetches\n// the bundle, re-validates the schema with the host's own gates (R7 — the\n// index is not a trust boundary), writes the bundle into `data/skills/<localSlug>/`\n// with a host-owned dataPath (R3), materializes any seed records into that\n// dataPath when it's empty, and records provenance in `.origin.json` for\n// update detection (R5/R8). After the data-skills swap, the bundle's\n// allowlisted files (SKILL.md, schema.json, templates/<safe>) are mirrored\n// 1:1 into `.claude/skills/<localSlug>/` via the same skill-bridge rules an\n// agent-authored skill would go through — so an authored and an imported\n// collection live in EXACTLY the same place on disk, and the user can edit\n// either one identically.\n//\n// `.origin.json` lives ONLY in `data/skills/<slug>/.origin.json` and is NOT\n// mirrored — the skill-bridge allowlist deliberately excludes host\n// bookkeeping. Its presence is what distinguishes \"imported\" from\n// \"user-authored\" in every downstream tool.\n//\n// `writeImportedCollection` takes the already-fetched bundle + an explicit\n// workspaceRoot/clock so it is unit-testable against a temp workspace with\n// no network; `performImport` is the thin glue that fetches and calls it.\n\nimport { mkdir, readFile, readdir, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport type { Dirent } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { acceptParsedSchema, CollectionSchemaZ, isSafeActionTemplatePath, safeRecordId } from \"../../server/index.js\";\nimport type { CollectionSchema } from \"../../index.js\";\nimport { claudeSkillDir, dataSkillDir, mirrorSkillWrite } from \"../../../skill-bridge/index.js\";\n\nimport { log } from \"../../server/host.js\";\nimport { errorMessage } from \"../../server/util.js\";\nimport { writeFileAtomic } from \"../../server/atomic.js\";\nimport { isRecord } from \"../guards.js\";\nimport { fetchAllRegistries } from \"./client.js\";\nimport { fetchBundle, fetchManifest, normalizedDataPath } from \"./importCollection.js\";\nimport type { RegistryEntry } from \"../registryIndex.js\";\n\nconst ORIGIN_FILE = \".origin.json\";\nconst SEED_PREFIX = \"seed/items/\";\nconst SCHEMA_FILE = \"schema.json\";\nconst SKILL_FILE = \"SKILL.md\";\nconst STATUS_NOT_FOUND = 404;\nconst STATUS_CONFLICT = 409;\nconst STATUS_UNPROCESSABLE = 422;\n\nexport interface ImportOrigin {\n registry: string;\n author: string;\n slug: string;\n version: string;\n contentSha: string;\n importedAt: string;\n}\n\nexport type ImportResult =\n { ok: true; localSlug: string; updated: boolean; seedWritten: number; seedSkipped: boolean } | { ok: false; status: number; error: string };\n\nasync function statType(target: string): Promise<\"dir\" | \"other\" | \"absent\"> {\n try {\n return (await stat(target)).isDirectory() ? \"dir\" : \"other\";\n } catch (err) {\n // EACCES etc. are path-shape conflicts mkdir would later throw on → \"other\".\n // A file ancestor surfaces as ENOTDIR on POSIX but ENOENT on Windows (which\n // reports the whole path as missing), so ENOENT can't be trusted as \"absent\"\n // until we've confirmed no existing ancestor is a non-directory file.\n if (!(isRecord(err) && err.code === \"ENOENT\")) return \"other\";\n return (await hasNonDirAncestor(target)) ? \"other\" : \"absent\";\n }\n}\n\n// Walk up from `target` to the nearest ancestor that exists: a non-directory\n// file there means `target` can never be mkdir'd (a path-shape conflict → 409),\n// whichever errno the platform's `stat(target)` chose. An all-absent-or-directory\n// chain up to the filesystem root is a genuine \"absent\".\nasync function hasNonDirAncestor(target: string): Promise<boolean> {\n let current = path.dirname(target);\n while (current !== path.dirname(current)) {\n try {\n return !(await stat(current)).isDirectory();\n } catch (err) {\n if (isRecord(err) && err.code === \"ENOENT\") {\n current = path.dirname(current);\n continue;\n }\n return true;\n }\n }\n return false;\n}\n\nasync function isEmptyOrAbsentDir(target: string): Promise<boolean> {\n try {\n return (await readdir(target)).length === 0;\n } catch {\n return true;\n }\n}\n\nfunction originMatches(origin: unknown, registry: string, author: string, slug: string): boolean {\n return isRecord(origin) && origin.registry === registry && origin.author === author && origin.slug === slug;\n}\n\nasync function readOrigin(targetDir: string): Promise<unknown> {\n try {\n return JSON.parse(await readFile(path.join(targetDir, ORIGIN_FILE), \"utf-8\"));\n } catch {\n return null;\n }\n}\n\ntype TargetResolution = { targetDir: string; localSlug: string; updated: boolean } | { conflict: string };\n\n// Only bounds the fresh-slug search (a safety cap, far above any realistic\n// number of same-named collections — the first free slug is normally found in\n// 1–2 iterations). An EXISTING install is found via the directory scan below,\n// not this loop, so updates are never missed regardless of how high the rename\n// suffix is.\nconst MAX_SLUG_ATTEMPTS = 10000;\n\nconst renameCandidate = (slug: string, attempt: number): string => (attempt === 0 ? slug : `${slug}-${attempt + 1}`);\n\n// True when `name` is the registry slug or a `<slug>-<n>` rename of it.\nfunction isRenameOf(name: string, slug: string): boolean {\n if (name === slug) return true;\n if (!name.startsWith(`${slug}-`)) return false;\n const suffix = name.slice(slug.length + 1);\n return suffix.length > 0 && /^\\d+$/.test(suffix);\n}\n\n// Find an existing install of this registry collection at ANY rename suffix\n// by scanning `data/skills/` — independent of any candidate bound, so a\n// re-import always updates the existing install rather than duplicating it\n// (even if an earlier slug freed up). An authored skill without `.origin.json`\n// is invisible to this scan and so never collides with an update.\nasync function findMatchingInstall(skillsDir: string, registry: string, entry: RegistryEntry): Promise<string | null> {\n const names = await readdir(skillsDir).catch(() => [] as string[]);\n for (const name of names) {\n if (!isRenameOf(name, entry.slug)) continue;\n const dir = path.join(skillsDir, name);\n if ((await statType(dir)) === \"dir\" && originMatches(await readOrigin(dir), registry, entry.author, entry.slug)) return name;\n }\n return null;\n}\n\n// Pick the local install slug (rename-on-collision, R8). First reuse an\n// existing matching install (update). Otherwise install fresh at the first\n// free slug — the registry slug, else `<slug>-2`, `-3`, … — never clobbering\n// a user's own same-named collection.\n//\n// A slug is \"free\" only when BOTH `data/skills/<slug>/` AND\n// `.claude/skills/<slug>/` are absent. The mirror check matters because\n// `mirrorToClaudeSkills` overwrites the mirror dir's allowlisted files and\n// prunes anything else — if the user has a manually-installed Claude skill\n// at `.claude/skills/<slug>/` with no corresponding `data/skills/<slug>/`\n// (e.g. installed by the Claude CLI directly, or a legacy pre-refactor\n// import we never migrated), picking that slug would silently overwrite\n// their SKILL.md/schema.json and prune the rest of their files (CodeRabbit\n// review on #1839).\nasync function resolveTarget(workspaceRoot: string, registry: string, entry: RegistryEntry): Promise<TargetResolution> {\n const skillsDir = path.dirname(dataSkillDir(workspaceRoot, entry.slug));\n const existing = await findMatchingInstall(skillsDir, registry, entry);\n if (existing) return { targetDir: dataSkillDir(workspaceRoot, existing), localSlug: existing, updated: true };\n for (let attempt = 0; attempt < MAX_SLUG_ATTEMPTS; attempt += 1) {\n const localSlug = renameCandidate(entry.slug, attempt);\n const sourceAbsent = (await statType(dataSkillDir(workspaceRoot, localSlug))) === \"absent\";\n const mirrorAbsent = (await statType(claudeSkillDir(workspaceRoot, localSlug))) === \"absent\";\n if (sourceAbsent && mirrorAbsent) {\n return { targetDir: dataSkillDir(workspaceRoot, localSlug), localSlug, updated: false };\n }\n }\n return { conflict: `couldn't find an available slug for '${entry.slug}'` };\n}\n\ntype SchemaResolution = { schema: CollectionSchema } | { error: string };\n\nfunction validateAndNormalize(bundle: Map<string, string>, localSlug: string, workspaceRoot: string): SchemaResolution {\n // SKILL.md is required: `mirrorToClaudeSkills` calls\n // `mirrorSkillWrite({slug, relSegments: [SKILL_FILE]})` unconditionally\n // after the data-side swap, which throws if SKILL.md is missing. Caught\n // outside, that throw is logged but the data-side write still succeeds and\n // the function returns `ok: true` for an unusable import. Reject up front\n // so a missing SKILL.md surfaces as a clean 422 instead (CodeRabbit review\n // on #1839).\n if (bundle.get(SKILL_FILE) === undefined) return { error: \"bundle is missing SKILL.md\" };\n const schemaText = bundle.get(SCHEMA_FILE);\n if (schemaText === undefined) return { error: \"bundle is missing schema.json\" };\n let parsedJson: unknown;\n try {\n parsedJson = JSON.parse(schemaText);\n } catch {\n return { error: \"schema.json is not valid JSON\" };\n }\n const parsed = CollectionSchemaZ.safeParse(parsedJson);\n if (!parsed.success) return { error: `schema.json failed validation: ${parsed.error.issues[0]?.message ?? \"invalid\"}` };\n // A `dataSource` collection can't be imported: its records are the rows of\n // a machine-local data file the bundle doesn't (and can't) carry — and the\n // R3 dataPath stamp below would collide with the exactly-one-of rule.\n if (parsed.data.dataSource !== undefined) {\n return { error: \"schema.json declares `dataSource` — external-data collections are machine-local and cannot be imported from a registry\" };\n }\n const schema: CollectionSchema = { ...parsed.data, dataPath: normalizedDataPath(localSlug) };\n const acceptance = acceptParsedSchema(schema, { source: \"project\", workspaceRoot, slug: localSlug });\n if (!acceptance.ok) return { error: `schema.json rejected: ${acceptance.reason}` };\n return { schema };\n}\n\nasync function writeBundleFiles(targetDir: string, bundle: Map<string, string>, schema: CollectionSchema): Promise<void> {\n for (const [rel, content] of bundle) {\n if (rel.startsWith(SEED_PREFIX)) continue; // seed goes to dataPath, not the skill dir\n const dest = path.join(targetDir, ...rel.split(\"/\"));\n if (dest !== targetDir && !dest.startsWith(targetDir + path.sep)) continue; // belt-and-suspenders (paths pre-validated)\n await mkdir(path.dirname(dest), { recursive: true });\n await writeFile(dest, rel === SCHEMA_FILE ? `${JSON.stringify(schema, null, 2)}\\n` : content, \"utf-8\");\n }\n}\n\nasync function materializeSeed(dataDir: string, bundle: Map<string, string>): Promise<{ written: number; skipped: boolean }> {\n const seedEntries = [...bundle].filter(([rel]) => rel.startsWith(SEED_PREFIX));\n if (seedEntries.length === 0) return { written: 0, skipped: false };\n if (!(await isEmptyOrAbsentDir(dataDir))) return { written: 0, skipped: true };\n await mkdir(dataDir, { recursive: true });\n let written = 0;\n for (const [rel, content] of seedEntries) {\n const fileName = rel.slice(SEED_PREFIX.length);\n if (fileName.includes(\"/\") || safeRecordId(fileName.replace(/\\.json$/, \"\")) === null) {\n log.warn(\"collections-registry\", \"skipped unsafe seed record\", { rel });\n continue;\n }\n await writeFile(path.join(dataDir, fileName), content, \"utf-8\");\n written += 1;\n }\n return { written, skipped: false };\n}\n\n/** Compute the set of bundle-relative paths that should land in `.claude/skills/<slug>/`.\n * Matches the bridge allowlist exactly — SKILL.md, schema.json,\n * `templates/<safe>` — so anything else (seed, meta.json, views, README,\n * assets) stays source-side. */\nfunction bridgeAllowlistFiles(bundle: Map<string, string>): Set<string> {\n const wanted = new Set<string>([SKILL_FILE, SCHEMA_FILE]);\n for (const rel of bundle.keys()) {\n if (rel === SKILL_FILE || rel === SCHEMA_FILE) continue;\n if (rel.startsWith(SEED_PREFIX)) continue;\n if (!isSafeActionTemplatePath(rel)) continue;\n wanted.add(rel);\n }\n return wanted;\n}\n\n/** Recursively list every file under `root`, returned as forward-slash paths\n * relative to `root`. Empty list when `root` doesn't exist. Used to spot\n * mirror files left over from a previous install so we can prune them after\n * writing the new ones. */\nasync function listFilesRecursive(root: string, prefix = \"\"): Promise<string[]> {\n const dir = prefix ? path.join(root, ...prefix.split(\"/\")) : root;\n const entries: Dirent[] = await readdir(dir, { withFileTypes: true }).catch(() => [] as Dirent[]);\n const out: string[] = [];\n for (const entry of entries) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isFile()) out.push(rel);\n else if (entry.isDirectory()) out.push(...(await listFilesRecursive(root, rel)));\n }\n return out;\n}\n\n// Mirror the just-written `data/skills/<slug>/` into `.claude/skills/<slug>/`\n// using the shared bridge package — exactly the set of files an\n// agent-authored skill would mirror, no more (SKILL.md, schema.json,\n// templates/<safe>). `.origin.json` is host bookkeeping and stays only on the\n// data side.\n//\n// **Write-then-prune ordering** (Codex review on #1839): write the new\n// bundle's allowlisted files FIRST (each is a per-file tmp+rename, atomic),\n// THEN prune mirror files that aren't in the new bundle. A transient mirror\n// failure during the writes leaves the previous mirror's files in place —\n// agent discovery keeps working with the prior state instead of finding an\n// empty `.claude/skills/<slug>/`. The prune step is best-effort: a failure\n// there leaves harmless stale leftovers but doesn't break the new install.\n// Compare with the old `mirrorSkillDelete`-first ordering, which could\n// silently leave an empty mirror if a subsequent write threw.\nasync function mirrorToClaudeSkills(workspaceRoot: string, localSlug: string, bundle: Map<string, string>): Promise<void> {\n const wanted = bridgeAllowlistFiles(bundle);\n // 1. Write the new set first (overwrites existing via tmp+rename).\n for (const rel of wanted) {\n mirrorSkillWrite(workspaceRoot, { slug: localSlug, relSegments: rel.split(\"/\") });\n }\n // 2. Prune files that exist in the mirror but aren't in the new bundle.\n const mirrorRoot = claudeSkillDir(workspaceRoot, localSlug);\n const existing = await listFilesRecursive(mirrorRoot);\n for (const rel of existing) {\n if (wanted.has(rel)) continue;\n await rm(path.join(mirrorRoot, ...rel.split(\"/\")), { force: true }).catch(() => undefined);\n }\n}\n\nexport async function writeImportedCollection(params: {\n registry: string;\n entry: RegistryEntry;\n bundle: Map<string, string>;\n workspaceRoot: string;\n nowIso: string;\n}): Promise<ImportResult> {\n const { registry, entry, bundle, workspaceRoot, nowIso } = params;\n const target = await resolveTarget(workspaceRoot, registry, entry);\n if (\"conflict\" in target) return { ok: false, status: STATUS_CONFLICT, error: target.conflict };\n\n const { localSlug } = target;\n\n // Pre-flight the data dir before schema validation: a non-directory at the dataPath\n // (or an ancestor that's a file → ENOTDIR) would otherwise surface as a generic 500\n // on mkdir. statType maps ENOTDIR/other to a deterministic 409 path-shape conflict.\n const dataDir = path.join(workspaceRoot, ...normalizedDataPath(localSlug).split(\"/\"));\n if ((await statType(dataDir)) === \"other\") {\n return { ok: false, status: STATUS_CONFLICT, error: `data path for slug '${localSlug}' exists and is not a directory` };\n }\n\n const validated = validateAndNormalize(bundle, localSlug, workspaceRoot);\n if (\"error\" in validated) return { ok: false, status: STATUS_UNPROCESSABLE, error: validated.error };\n\n // Build the replacement fully in a hidden sibling staging dir under\n // `data/skills/` (bundle + origin), so the prior install is untouched until\n // everything is durably written. Leftover staging/backup dirs from a\n // crashed import are cleaned first, keeping retries possible.\n const skillsParent = path.dirname(target.targetDir);\n await mkdir(skillsParent, { recursive: true }); // first-import case — data/skills/ may not exist\n const staging = path.join(skillsParent, `.importing-${localSlug}`);\n const backup = path.join(skillsParent, `.backup-${localSlug}`);\n await rm(staging, { recursive: true, force: true });\n await rm(backup, { recursive: true, force: true });\n await mkdir(staging, { recursive: true });\n await writeBundleFiles(staging, bundle, validated.schema);\n const origin: ImportOrigin = { registry, author: entry.author, slug: entry.slug, version: entry.version, contentSha: entry.contentSha, importedAt: nowIso };\n await writeFileAtomic(path.join(staging, ORIGIN_FILE), `${JSON.stringify(origin, null, 2)}\\n`);\n\n // Swap with rollback: move the old install aside (rename), move the new in\n // (rename), then discard the old. If the swap fails, restore the old so we\n // never end up with no installed collection. Records live in dataPath (a\n // separate dir) and are untouched.\n if (target.updated) await rename(target.targetDir, backup);\n try {\n await rename(staging, target.targetDir);\n } catch (err) {\n if (target.updated) await rename(backup, target.targetDir).catch(() => undefined);\n throw err;\n }\n await rm(backup, { recursive: true, force: true });\n\n // Replicate the new `data/skills/<slug>/` set into `.claude/skills/<slug>/`\n // via the shared bridge package — same allowlist + tmp+rename semantics the\n // hook uses for agent-authored writes. Write-then-prune ordering inside\n // mirrorToClaudeSkills means a transient failure here can't leave the mirror\n // empty (Codex review on #1839); the worst case is a half-written mirror\n // where the new install's SKILL.md/schema.json may not have updated, but the\n // prior install remains accessible to the agent until the next mirror\n // attempt. Logged-not-thrown matches the hook's posture for agent writes.\n try {\n await mirrorToClaudeSkills(workspaceRoot, localSlug, bundle);\n } catch (err) {\n log.warn(\"collections-registry\", \"mirror to .claude/skills/ failed (data/skills write succeeded; prior mirror left intact)\", {\n localSlug,\n error: errorMessage(err),\n });\n }\n\n const seed = await materializeSeed(dataDir, bundle);\n return { ok: true, localSlug, updated: target.updated, seedWritten: seed.written, seedSkipped: seed.skipped };\n}\n\nexport async function performImport(author: string, slug: string, workspaceRoot: string, registry: string | null = null): Promise<ImportResult> {\n const merged = await fetchAllRegistries();\n let entry: RegistryEntry | undefined;\n for (const reg of merged) {\n if (registry !== null && reg.name !== registry) continue;\n entry = reg.entries.find((candidate) => candidate.author === author && candidate.slug === slug);\n if (entry) break;\n }\n if (!entry) return { ok: false, status: STATUS_NOT_FOUND, error: `unknown collection: ${author}/${slug}` };\n const manifest = await fetchManifest(entry);\n if (!manifest.ok) return { ok: false, status: manifest.status, error: manifest.error };\n const bundle = await fetchBundle(entry, manifest.files);\n if (!bundle.ok) return { ok: false, status: bundle.status, error: bundle.error };\n try {\n return await writeImportedCollection({\n registry: entry.registryName,\n entry,\n bundle: bundle.files,\n workspaceRoot,\n nowIso: new Date().toISOString(),\n });\n } catch (err) {\n log.warn(\"collections-registry\", \"import write failed\", { author, slug, registry: entry.registryName, error: errorMessage(err) });\n return { ok: false, status: 500, error: `import failed: ${errorMessage(err)}` };\n }\n}\n\n// Exported for downstream code that wants the path conventions without\n// importing skill-bridge directly.\nexport { claudeSkillDir, dataSkillDir, hasNonDirAncestor };\n","// Export a workspace collection into the curated registry's contribution layout\n// (collections/<author>/<slug>/ + meta.json + optional seed/) under\n// data/registry-export/, so the user can open a PR to the registry. The producer\n// side of the registry loop.\n//\n// writeCollectionExport takes explicit dirs + a workspace root so it is unit-testable\n// against temp dirs with no discovery/network; performExport (separate file) is the\n// thin glue that resolves the collection from the live workspace.\n\nimport { cp, mkdir, readdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { log } from \"../../server/host.js\";\n\nexport const EXPORT_BASE = \"data/registry-export\";\nconst BUNDLE_FILES = [\"SKILL.md\", \"schema.json\"] as const;\nconst OPTIONAL_FILES = [\"screenshot.png\"] as const;\nconst BUNDLE_DIRS = [\"views\", \"templates\"] as const;\nconst AUTHOR_RE = /^[A-Za-z0-9][A-Za-z0-9-]{0,38}$/;\nconst SLUG_RE = /^[a-z0-9][a-z0-9-]{0,62}$/;\nconst STATUS_BAD_REQUEST = 400;\n// Block obvious credentials from being published in seed data; PII is only warned.\nconst SECRET_PATTERNS = [\n /AKIA[0-9A-Z]{16}/,\n /gh[pousr]_[A-Za-z0-9]{20,}/,\n /-----BEGIN [A-Z ]*PRIVATE KEY-----/,\n /sk-[A-Za-z0-9]{20,}/,\n /xox[baprs]-[A-Za-z0-9-]{10,}/,\n];\nconst hasSecret = (text: string): boolean => SECRET_PATTERNS.some((pattern) => pattern.test(text));\n// Bounded + non-overlapping (no ReDoS): local@label.tld with single quantifier runs.\nconst EMAIL_RE = /[\\w.%+-]{1,64}@[\\w-]{1,255}\\.[a-z]{2,24}/i;\n\nexport interface ExportMeta {\n author: string;\n slug: string;\n version: string;\n title: string;\n description: string;\n tags: string[];\n license: string;\n}\n\nexport type ExportResult =\n | { ok: true; outputPath: string; fileCount: number; seedCount: number; seedSkipped: number; warnings: string[] }\n | { ok: false; status: number; error: string };\n\nasync function pathKind(target: string): Promise<\"dir\" | \"file\" | \"absent\"> {\n try {\n return (await stat(target)).isDirectory() ? \"dir\" : \"file\";\n } catch {\n return \"absent\";\n }\n}\n\nasync function copyBundle(skillDir: string, outDir: string): Promise<number> {\n let count = 0;\n for (const file of [...BUNDLE_FILES, ...OPTIONAL_FILES]) {\n const src = path.join(skillDir, file);\n if ((await pathKind(src)) !== \"file\") continue;\n await cp(src, path.join(outDir, file));\n count += 1;\n }\n for (const dir of BUNDLE_DIRS) {\n const src = path.join(skillDir, dir);\n if ((await pathKind(src)) !== \"dir\") continue;\n await cp(src, path.join(outDir, dir), { recursive: true });\n count += (await readdir(src)).filter((name) => !name.startsWith(\".\")).length;\n }\n return count;\n}\n\nasync function exportSeed(dataDir: string, outDir: string): Promise<{ count: number; skipped: number; warnings: string[] }> {\n let names: string[];\n try {\n names = (await readdir(dataDir)).filter((name) => name.endsWith(\".json\"));\n } catch {\n return { count: 0, skipped: 0, warnings: [] };\n }\n if (names.length === 0) return { count: 0, skipped: 0, warnings: [] };\n const seedDir = path.join(outDir, \"seed\", \"items\");\n await mkdir(seedDir, { recursive: true });\n const warnings: string[] = [];\n let count = 0;\n let skipped = 0;\n for (const name of names) {\n const base = path.basename(name);\n const text = await readFile(path.join(dataDir, base), \"utf-8\");\n if (hasSecret(text)) {\n warnings.push(`skipped ${base}: contains a possible credential`);\n skipped += 1;\n continue;\n }\n if (EMAIL_RE.test(text)) warnings.push(`${base}: contains a possible email/PII (kept — your responsibility)`);\n await writeFile(path.join(seedDir, base), text, \"utf-8\");\n count += 1;\n }\n return { count, skipped, warnings };\n}\n\n// Resolve `segments` under `root` and return the absolute path only when it stays\n// inside `root` — a containment barrier for the user-derived author/slug and the\n// collection dirs, on top of the AUTHOR_RE/SLUG_RE format checks. `..` or an\n// absolute escape resolves outside `root` and yields null (rejected upstream).\nfunction resolveWithin(root: string, ...segments: string[]): string | null {\n const resolvedRoot = path.resolve(root);\n const target = path.resolve(resolvedRoot, ...segments);\n return target === resolvedRoot || target.startsWith(resolvedRoot + path.sep) ? target : null;\n}\n\n// Required bundle files (SKILL.md, schema.json) must be present — exporting an\n// incomplete bundle would pass here but fail downstream registry curation.\n// Returns the first missing required file, or null when all are present.\nasync function findMissingRequired(skillDir: string): Promise<string | null> {\n for (const file of BUNDLE_FILES) {\n if ((await pathKind(path.join(skillDir, file))) !== \"file\") return file;\n }\n return null;\n}\n\nexport async function writeCollectionExport(params: {\n workspaceRoot: string;\n skillDir: string;\n dataDir: string;\n meta: ExportMeta;\n includeSeed: boolean;\n}): Promise<ExportResult> {\n const { workspaceRoot, skillDir, dataDir, meta, includeSeed } = params;\n if (!AUTHOR_RE.test(meta.author)) return { ok: false, status: STATUS_BAD_REQUEST, error: `author '${meta.author}' is not a valid GitHub login` };\n if (!SLUG_RE.test(meta.slug)) return { ok: false, status: STATUS_BAD_REQUEST, error: `slug '${meta.slug}' is invalid` };\n\n const wsRoot = path.resolve(workspaceRoot);\n const exportRoot = path.join(wsRoot, ...EXPORT_BASE.split(\"/\"));\n const outDir = resolveWithin(exportRoot, meta.author, meta.slug);\n const safeSkillDir = resolveWithin(wsRoot, skillDir);\n const safeDataDir = resolveWithin(wsRoot, dataDir);\n if (!outDir || !safeSkillDir || !safeDataDir) {\n return { ok: false, status: STATUS_BAD_REQUEST, error: \"resolved path escapes the workspace\" };\n }\n\n const missing = await findMissingRequired(safeSkillDir);\n if (missing) {\n return { ok: false, status: STATUS_BAD_REQUEST, error: `required bundle file missing: ${missing}` };\n }\n\n await rm(outDir, { recursive: true, force: true });\n await mkdir(outDir, { recursive: true });\n\n const bundleCount = await copyBundle(safeSkillDir, outDir);\n const seed = includeSeed ? await exportSeed(safeDataDir, outDir) : { count: 0, skipped: 0, warnings: [] };\n const metaOut = { ...meta, ...(seed.count > 0 ? { dataConsent: true } : {}) };\n await writeFile(path.join(outDir, \"meta.json\"), `${JSON.stringify(metaOut, null, 2)}\\n`, \"utf-8\");\n log.info(\"collections-registry\", \"exported collection\", { slug: meta.slug, author: meta.author, seedCount: seed.count });\n const outRel = path.relative(wsRoot, outDir).split(path.sep).join(\"/\");\n return { ok: true, outputPath: outRel, fileCount: bundleCount + 1, seedCount: seed.count, seedSkipped: seed.skipped, warnings: seed.warnings };\n}\n","// `description:` reader for a SKILL.md YAML frontmatter envelope.\n//\n// The host (MulmoClaude) parses SKILL.md frontmatter with js-yaml, but\n// @mulmoclaude/core deliberately carries no YAML dependency and export only needs\n// the single `description` scalar for the registry meta.json (best-effort — it\n// defaults to \"\" when absent). Rather than pull in a YAML parser we scan the\n// envelope for the first `description:` line and resolve the common YAML scalar\n// forms so exported descriptions match what the host produced:\n// - double-quoted (\"…\") → unescaped, trailing inline comment ignored\n// - single-quoted ('…') → '' → ', trailing inline comment ignored\n// - plain (unquoted) → trailing \" #comment\" stripped (YAML comment rule)\n// Block scalars (`description: |`) are NOT expanded — they yield \"\" (skill\n// descriptions are single-line in practice).\n\nconst FENCE = \"---\";\nconst KEY = \"description:\";\nconst BLOCK_SCALAR_INDICATORS = new Set([\"|\", \">\", \"|-\", \">-\", \"|+\", \">+\"]);\n\nconst isYamlSpace = (char: string | undefined): boolean => char === \" \" || char === \"\\t\";\n\n// After a closing quote, YAML allows only whitespace and an optional \"#\" comment.\n// Anything else (e.g. `\"foo\" bar`) is malformed — js-yaml would throw, so we\n// reject (→ null → \"\") rather than silently truncate.\nconst isOnlyTrailingComment = (rest: string): boolean => {\n const trimmed = rest.trimStart();\n return trimmed === \"\" || trimmed.startsWith(\"#\");\n};\n\n// Escapes a description realistically carries inside a double-quoted scalar;\n// any other `\\x` collapses to the literal `x`.\nconst DOUBLE_QUOTE_ESCAPES: Record<string, string> = { n: \"\\n\", t: \"\\t\" };\nconst unescapeDoubleQuote = (next: string): string => DOUBLE_QUOTE_ESCAPES[next] ?? next;\n\n// Double-quoted scalar: walk to the closing unescaped quote. Returns null for a\n// malformed scalar (no closing quote, or trailing non-comment text) so the caller\n// degrades to \"\" — matching the host's js-yaml behavior.\nfunction parseDoubleQuoted(value: string): string | null {\n const out: string[] = [];\n for (let i = 1; i < value.length; i += 1) {\n const char = value[i];\n if (char === \"\\\\\" && i + 1 < value.length) {\n out.push(unescapeDoubleQuote(value[i + 1]));\n i += 1;\n continue;\n }\n if (char === '\"') return isOnlyTrailingComment(value.slice(i + 1)) ? out.join(\"\") : null;\n out.push(char);\n }\n return null; // unterminated\n}\n\n// Single-quoted scalar: the only escape is a doubled quote (''). Same\n// malformed-rejection contract as parseDoubleQuoted.\nfunction parseSingleQuoted(value: string): string | null {\n const out: string[] = [];\n for (let i = 1; i < value.length; i += 1) {\n const char = value[i];\n if (char === \"'\") {\n if (value[i + 1] === \"'\") {\n out.push(\"'\");\n i += 1;\n continue;\n }\n return isOnlyTrailingComment(value.slice(i + 1)) ? out.join(\"\") : null;\n }\n out.push(char);\n }\n return null; // unterminated\n}\n\n// Plain scalar: a \"#\" preceded by whitespace (or at the start) begins a YAML\n// comment; \"#\" not preceded by whitespace (e.g. \"C#\") is literal.\nfunction stripPlainComment(value: string): string {\n for (let i = 0; i < value.length; i += 1) {\n if (value[i] === \"#\" && (i === 0 || isYamlSpace(value[i - 1]))) return value.slice(0, i);\n }\n return value;\n}\n\n/** Extract the frontmatter `description` from raw SKILL.md text. Returns \"\" when\n * there's no `---` envelope, no `description:` key, or the value is a block\n * scalar indicator. */\nexport function parseSkillDescription(raw: string): string {\n const lines = raw.split(/\\r?\\n/);\n if (lines[0]?.trim() !== FENCE) return \"\";\n for (let i = 1; i < lines.length; i += 1) {\n const line = lines[i];\n if (line.trim() === FENCE) return \"\"; // end of envelope, key not found\n if (!line.startsWith(KEY)) continue;\n const value = line.slice(KEY.length).trim();\n if (value === \"\" || BLOCK_SCALAR_INDICATORS.has(value)) return \"\";\n if (value.startsWith('\"')) return parseDoubleQuoted(value) ?? \"\";\n if (value.startsWith(\"'\")) return parseSingleQuoted(value) ?? \"\";\n return stripPlainComment(value).trim();\n }\n return \"\";\n}\n","// Thin glue for the collection export: resolve the collection from the live workspace\n// (its skill dir + data dir + schema), derive meta from SKILL.md front-matter / any\n// existing meta.json, then hand off to the testable writeCollectionExport. Kept\n// separate so the file-writing core stays import-light + unit-testable.\n\nimport { readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nimport { loadCollection } from \"../../server/index.js\";\nimport { isRecord } from \"../guards.js\";\nimport { parseSkillDescription } from \"./skillDescription.js\";\nimport { writeCollectionExport, type ExportMeta, type ExportResult } from \"./exportCollection.js\";\n\nconst STATUS_NOT_FOUND = 404;\nconst STATUS_UNPROCESSABLE = 422;\n\nasync function readJsonObject(file: string): Promise<Record<string, unknown> | null> {\n try {\n const parsed: unknown = JSON.parse(await readFile(file, \"utf-8\"));\n return isRecord(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\nexport async function performExport(\n slug: string,\n opts: { author: string; license: string; includeSeed: boolean },\n workspaceRoot: string,\n): Promise<ExportResult> {\n const collection = await loadCollection(slug);\n if (!collection) return { ok: false, status: STATUS_NOT_FOUND, error: `collection not found: ${slug}` };\n // Mirrors the import-side refusal: a `dataSource` collection's records are\n // a machine-local data file a bundle can't carry.\n if (collection.schema.dataSource !== undefined) {\n return { ok: false, status: STATUS_UNPROCESSABLE, error: `collection '${slug}' is backed by an external dataSource and cannot be exported to a registry` };\n }\n const skillMd = await readFile(path.join(collection.skillDir, \"SKILL.md\"), \"utf-8\").catch(() => \"\");\n const existingMeta = await readJsonObject(path.join(collection.skillDir, \"meta.json\"));\n const meta: ExportMeta = {\n author: opts.author,\n slug,\n version: typeof existingMeta?.version === \"string\" ? existingMeta.version : \"1.0.0\",\n title: collection.schema.title,\n description: parseSkillDescription(skillMd),\n tags: [],\n license: opts.license,\n };\n return writeCollectionExport({ workspaceRoot, skillDir: collection.skillDir, dataDir: collection.dataDir, meta, includeSeed: opts.includeSeed });\n}\n","// @mulmoclaude/core/collection/registry/server — node-only collection registry\n// engine (Discover catalog fetch/cache, import writer, export writer). Shares the\n// `configureCollectionHost` binding with @mulmoclaude/core/collection/server, so a\n// host wires the workspace + logger + paths ONCE and both engines work. The\n// isomorphic contract types live on @mulmoclaude/core/collection/registry.\n\nimport { fetchAllRegistries } from \"./client.js\";\nimport { performImport } from \"./importWriter.js\";\nimport type { RegistryListResponse, RegistryImportResponse } from \"../types.js\";\n\nexport {\n CACHE_TTL_MS,\n STALE_RETRY_BACKOFF_MS,\n fetchAllRegistries,\n fetchRegistryIndex,\n findRegistry,\n listRegistries,\n resetRegistryCache,\n type FetchIndexResult,\n type IndexLoader,\n type MergedRegistryResult,\n type RegistryDescriptor,\n} from \"./client.js\";\nexport {\n collectionFileUrl,\n fetchCollectionFile,\n parseJsonObject,\n previewCollection,\n rawBaseForEntry,\n type FileResult,\n type JsonObjectResult,\n type PreviewResult,\n} from \"./collectionFiles.js\";\nexport {\n fetchBundle,\n fetchManifest,\n isSafeBundlePath,\n normalizedDataPath,\n parseManifest,\n withNormalizedDataPath,\n type BundleFetch,\n type ManifestFetch,\n type ManifestResult,\n} from \"./importCollection.js\";\nexport { claudeSkillDir, dataSkillDir, performImport, writeImportedCollection, type ImportOrigin, type ImportResult } from \"./importWriter.js\";\nexport { EXPORT_BASE, writeCollectionExport, type ExportMeta, type ExportResult } from \"./exportCollection.js\";\nexport { performExport } from \"./performExport.js\";\nexport { parseSkillDescription } from \"./skillDescription.js\";\nexport { loadRegistriesConfig, parseRegistriesConfig, OFFICIAL_REGISTRY_NAME, type RegistryConfigEntry } from \"./registriesConfig.js\";\nexport type { RegistryEntry, RegistryIndex, ParseResult } from \"../registryIndex.js\";\nexport { parseRegistryIndex } from \"../registryIndex.js\";\nexport type { RegistrySummary, RegistryListResponse, RegistryImportResponse } from \"../types.js\";\n\n/** Build the merged Discover catalog response (`GET …collectionsRegistry.list`).\n * Wraps `fetchAllRegistries` with the per-registry summary + stale-flag shaping\n * every host needs, so a downstream host doesn't re-implement the mapping. */\nexport async function listRegistry(): Promise<RegistryListResponse> {\n const merged = await fetchAllRegistries();\n return {\n registries: merged.map((reg) => ({\n name: reg.name,\n status: reg.status,\n generatedAt: reg.generatedAt,\n error: reg.error,\n entryCount: reg.entries.length,\n })),\n stale: merged.some((reg) => reg.status === \"stale\"),\n collections: merged.flatMap((reg) => reg.entries),\n };\n}\n\nexport type RegistryImportOutcome = { ok: true; response: RegistryImportResponse } | { ok: false; status: number; error: string };\n\n/** Import a registry collection and return the host-facing response shape\n * (`POST …collectionsRegistry.import`). On failure carries the HTTP status so\n * the host route can pass it straight through. */\nexport async function importRegistry(author: string, slug: string, workspaceRoot: string, registry: string | null = null): Promise<RegistryImportOutcome> {\n const result = await performImport(author, slug, workspaceRoot, registry);\n if (!result.ok) return { ok: false, status: result.status, error: result.error };\n return {\n ok: true,\n response: { localSlug: result.localSlug, updated: result.updated, seedWritten: result.seedWritten, seedSkipped: result.seedSkipped },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
|
|
2
|
+
const require_ids = require("../../ids-BR4U1dJD.cjs");
|
|
3
|
+
const require_discovery = require("../../discovery-BZ2ms1tE.cjs");
|
|
4
|
+
const require_templatePath = require("../../templatePath-27vUZowm.cjs");
|
|
5
|
+
const require_server = require("../../server-DLRz-U7F.cjs");
|
|
6
|
+
exports.COMPUTED_TYPES = require_ids.COMPUTED_TYPES;
|
|
6
7
|
exports.CollectionQueryZ = require_server.CollectionQueryZ;
|
|
7
|
-
exports.CollectionSchemaZ =
|
|
8
|
+
exports.CollectionSchemaZ = require_discovery.CollectionSchemaZ;
|
|
8
9
|
exports.DEFAULT_QUERY_ROWS = require_server.DEFAULT_QUERY_ROWS;
|
|
9
10
|
exports.MAX_CSV_ROWS = require_server.MAX_CSV_ROWS;
|
|
10
11
|
exports.MAX_QUERY_ROWS = require_server.MAX_QUERY_ROWS;
|
|
11
12
|
exports.MAX_SCHEMA_ISSUES = require_server.MAX_SCHEMA_ISSUES;
|
|
12
13
|
exports.MAX_UNSELECTIVE_ITEMS = require_server.MAX_UNSELECTIVE_ITEMS;
|
|
13
|
-
exports.SCHEMA_FILE =
|
|
14
|
-
exports.acceptParsedSchema =
|
|
14
|
+
exports.SCHEMA_FILE = require_discovery.SCHEMA_FILE;
|
|
15
|
+
exports.acceptParsedSchema = require_discovery.acceptParsedSchema;
|
|
15
16
|
exports.advanceTriggerDate = require_server.advanceTriggerDate;
|
|
16
17
|
exports.applyMutateAction = require_server.applyMutateAction;
|
|
17
|
-
exports.buildActionSeedPrompt =
|
|
18
|
-
exports.buildCollectionActionSeedPrompt =
|
|
18
|
+
exports.buildActionSeedPrompt = require_discovery.buildActionSeedPrompt;
|
|
19
|
+
exports.buildCollectionActionSeedPrompt = require_discovery.buildCollectionActionSeedPrompt;
|
|
19
20
|
exports.buildWorkspaceOntology = require_server.buildWorkspaceOntology;
|
|
20
21
|
exports.collectionWritable = require_server.collectionWritable;
|
|
21
22
|
exports.compileCsvQuery = require_server.compileCsvQuery;
|
|
@@ -23,7 +24,7 @@ exports.compileJsonlQuery = require_server.compileJsonlQuery;
|
|
|
23
24
|
exports.compileRecordZ = require_server.compileRecordZ;
|
|
24
25
|
exports.computeCollectionIcon = require_server.computeCollectionIcon;
|
|
25
26
|
exports.computeSuccessor = require_server.computeSuccessor;
|
|
26
|
-
exports.configureCollectionHost =
|
|
27
|
+
exports.configureCollectionHost = require_discovery.configureCollectionHost;
|
|
27
28
|
exports.csvRowToItem = require_server.csvRowToItem;
|
|
28
29
|
exports.daysInMonth = require_server.daysInMonth;
|
|
29
30
|
exports.decodeCsvRecordId = require_server.decodeCsvRecordId;
|
|
@@ -31,51 +32,51 @@ exports.dedupeByRecordId = require_server.dedupeByRecordId;
|
|
|
31
32
|
exports.deleteCollection = require_server.deleteCollection;
|
|
32
33
|
exports.deleteCollectionRefusalMessage = require_server.deleteCollectionRefusalMessage;
|
|
33
34
|
exports.deleteCustomView = require_server.deleteCustomView;
|
|
34
|
-
exports.deleteItem =
|
|
35
|
-
exports.discoverCollections =
|
|
35
|
+
exports.deleteItem = require_discovery.deleteItem;
|
|
36
|
+
exports.discoverCollections = require_discovery.discoverCollections;
|
|
36
37
|
exports.encodeCsvRecordId = require_server.encodeCsvRecordId;
|
|
37
38
|
exports.enrichItems = require_server.enrichItems;
|
|
38
39
|
exports.firstMutateParamProblem = require_server.firstMutateParamProblem;
|
|
39
40
|
exports.formatCivil = require_server.formatCivil;
|
|
40
|
-
exports.generateItemId =
|
|
41
|
-
exports.getWorkspaceRoot =
|
|
42
|
-
exports.isContainedInRoot =
|
|
43
|
-
exports.isContainedInWorkspace =
|
|
44
|
-
exports.isRegularFile =
|
|
45
|
-
exports.isSafeActionTemplatePath =
|
|
46
|
-
exports.isSafeCustomViewI18nPath =
|
|
47
|
-
exports.isSafeCustomViewPath =
|
|
48
|
-
exports.isSafeTemplatePath =
|
|
41
|
+
exports.generateItemId = require_discovery.generateItemId;
|
|
42
|
+
exports.getWorkspaceRoot = require_discovery.getWorkspaceRoot;
|
|
43
|
+
exports.isContainedInRoot = require_discovery.isContainedInRoot;
|
|
44
|
+
exports.isContainedInWorkspace = require_discovery.isContainedInWorkspace;
|
|
45
|
+
exports.isRegularFile = require_discovery.isRegularFile;
|
|
46
|
+
exports.isSafeActionTemplatePath = require_templatePath.isSafeActionTemplatePath;
|
|
47
|
+
exports.isSafeCustomViewI18nPath = require_templatePath.isSafeCustomViewI18nPath;
|
|
48
|
+
exports.isSafeCustomViewPath = require_templatePath.isSafeCustomViewPath;
|
|
49
|
+
exports.isSafeTemplatePath = require_templatePath.isSafeTemplatePath;
|
|
49
50
|
exports.isTriggerDue = require_server.isTriggerDue;
|
|
50
|
-
exports.itemFilePath =
|
|
51
|
-
exports.listItems =
|
|
52
|
-
exports.loadCollection =
|
|
53
|
-
exports.log =
|
|
51
|
+
exports.itemFilePath = require_discovery.itemFilePath;
|
|
52
|
+
exports.listItems = require_discovery.listItems;
|
|
53
|
+
exports.loadCollection = require_discovery.loadCollection;
|
|
54
|
+
exports.log = require_discovery.log;
|
|
54
55
|
exports.makeManageCollectionTool = require_server.makeManageCollectionTool;
|
|
55
56
|
exports.maybeSpawnSuccessor = require_server.maybeSpawnSuccessor;
|
|
56
57
|
exports.normalizeCsvValue = require_server.normalizeCsvValue;
|
|
57
58
|
exports.parseCivil = require_server.parseCivil;
|
|
58
|
-
exports.promptPathsFor =
|
|
59
|
-
exports.publishCollectionChange =
|
|
60
|
-
exports.readCustomViewHtml =
|
|
61
|
-
exports.readCustomViewI18n =
|
|
62
|
-
exports.readItem =
|
|
59
|
+
exports.promptPathsFor = require_discovery.promptPathsFor;
|
|
60
|
+
exports.publishCollectionChange = require_discovery.publishCollectionChange;
|
|
61
|
+
exports.readCustomViewHtml = require_discovery.readCustomViewHtml;
|
|
62
|
+
exports.readCustomViewI18n = require_discovery.readCustomViewI18n;
|
|
63
|
+
exports.readItem = require_discovery.readItem;
|
|
63
64
|
exports.readOnlyRefusal = require_server.readOnlyRefusal;
|
|
64
|
-
exports.readSkillTemplate =
|
|
65
|
+
exports.readSkillTemplate = require_discovery.readSkillTemplate;
|
|
65
66
|
exports.recordFieldProblem = require_server.recordFieldProblem;
|
|
66
|
-
exports.resolveCreateItemId =
|
|
67
|
-
exports.resolveDataDir =
|
|
67
|
+
exports.resolveCreateItemId = require_discovery.resolveCreateItemId;
|
|
68
|
+
exports.resolveDataDir = require_discovery.resolveDataDir;
|
|
68
69
|
exports.resolveEvery = require_server.resolveEvery;
|
|
69
|
-
exports.resolveTemplatePath =
|
|
70
|
+
exports.resolveTemplatePath = require_discovery.resolveTemplatePath;
|
|
70
71
|
exports.runQueryOverRows = require_server.runQueryOverRows;
|
|
71
|
-
exports.safeRecordId =
|
|
72
|
-
exports.safeSlugName =
|
|
72
|
+
exports.safeRecordId = require_discovery.safeRecordId;
|
|
73
|
+
exports.safeSlugName = require_discovery.safeSlugName;
|
|
73
74
|
exports.schemaRelations = require_server.schemaRelations;
|
|
74
|
-
exports.setCollectionChangePublisher =
|
|
75
|
+
exports.setCollectionChangePublisher = require_discovery.setCollectionChangePublisher;
|
|
75
76
|
exports.storeFor = require_server.storeFor;
|
|
76
77
|
exports.successorId = require_server.successorId;
|
|
77
|
-
exports.toDetail =
|
|
78
|
-
exports.toSummary =
|
|
78
|
+
exports.toDetail = require_discovery.toDetail;
|
|
79
|
+
exports.toSummary = require_discovery.toSummary;
|
|
79
80
|
exports.validateCollectionRecords = require_server.validateCollectionRecords;
|
|
80
81
|
exports.validateRecordObject = require_server.validateRecordObject;
|
|
81
|
-
exports.writeItem =
|
|
82
|
+
exports.writeItem = require_discovery.writeItem;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { o as COMPUTED_TYPES } from "../../ids-D4e10971.js";
|
|
2
|
+
import { C as isContainedInRoot, D as resolveTemplatePath, E as resolveDataDir, F as log, I as publishCollectionChange, L as setCollectionChangePublisher, M as configureCollectionHost, N as getWorkspaceRoot, O as safeRecordId, S as SCHEMA_FILE, T as itemFilePath, _ as readItem, a as toSummary, b as writeItem, c as buildActionSeedPrompt, d as generateItemId, f as isRegularFile, g as readCustomViewI18n, h as readCustomViewHtml, i as toDetail, k as safeSlugName, l as buildCollectionActionSeedPrompt, m as promptPathsFor, n as discoverCollections, o as CollectionSchemaZ, p as listItems, r as loadCollection, t as acceptParsedSchema, u as deleteItem, v as readSkillTemplate, w as isContainedInWorkspace, y as resolveCreateItemId } from "../../discovery-3K_Wtkvn.js";
|
|
3
|
+
import { i as isSafeTemplatePath, n as isSafeCustomViewI18nPath, r as isSafeCustomViewPath, t as isSafeActionTemplatePath } from "../../templatePath-k_WNbL_Q.js";
|
|
4
|
+
import { A as readOnlyRefusal, B as CollectionQueryZ, C as firstMutateParamProblem, D as recordFieldProblem, E as compileRecordZ, F as dedupeByRecordId, H as MAX_QUERY_ROWS, I as encodeCsvRecordId, L as normalizeCsvValue, M as MAX_CSV_ROWS, N as csvRowToItem, O as runQueryOverRows, P as decodeCsvRecordId, R as compileCsvQuery, S as applyMutateAction, T as validateRecordObject, V as DEFAULT_QUERY_ROWS, a as deleteCollection, b as buildWorkspaceOntology, c as computeSuccessor, d as isTriggerDue, f as maybeSpawnSuccessor, h as successorId, i as deleteCustomView, j as storeFor, k as collectionWritable, l as daysInMonth, m as resolveEvery, n as MAX_UNSELECTIVE_ITEMS, o as deleteCollectionRefusalMessage, p as parseCivil, r as makeManageCollectionTool, s as advanceTriggerDate, t as MAX_SCHEMA_ISSUES, u as formatCivil, v as computeCollectionIcon, w as validateCollectionRecords, x as schemaRelations, y as enrichItems, z as compileJsonlQuery } from "../../server-DZH7OjOD.js";
|
|
4
5
|
export { COMPUTED_TYPES, CollectionQueryZ, CollectionSchemaZ, DEFAULT_QUERY_ROWS, MAX_CSV_ROWS, MAX_QUERY_ROWS, MAX_SCHEMA_ISSUES, MAX_UNSELECTIVE_ITEMS, SCHEMA_FILE, acceptParsedSchema, advanceTriggerDate, applyMutateAction, buildActionSeedPrompt, buildCollectionActionSeedPrompt, buildWorkspaceOntology, collectionWritable, compileCsvQuery, compileJsonlQuery, compileRecordZ, computeCollectionIcon, computeSuccessor, configureCollectionHost, csvRowToItem, daysInMonth, decodeCsvRecordId, dedupeByRecordId, deleteCollection, deleteCollectionRefusalMessage, deleteCustomView, deleteItem, discoverCollections, encodeCsvRecordId, enrichItems, firstMutateParamProblem, formatCivil, generateItemId, getWorkspaceRoot, isContainedInRoot, isContainedInWorkspace, isRegularFile, isSafeActionTemplatePath, isSafeCustomViewI18nPath, isSafeCustomViewPath, isSafeTemplatePath, isTriggerDue, itemFilePath, listItems, loadCollection, log, makeManageCollectionTool, maybeSpawnSuccessor, normalizeCsvValue, parseCivil, promptPathsFor, publishCollectionChange, readCustomViewHtml, readCustomViewI18n, readItem, readOnlyRefusal, readSkillTemplate, recordFieldProblem, resolveCreateItemId, resolveDataDir, resolveEvery, resolveTemplatePath, runQueryOverRows, safeRecordId, safeSlugName, schemaRelations, setCollectionChangePublisher, storeFor, successorId, toDetail, toSummary, validateCollectionRecords, validateRecordObject, writeItem };
|