@agimon-ai/doompi-config 0.0.1-alpha.91 → 0.0.1-alpha.92

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.
@@ -349,23 +349,6 @@ const settingsApi = {
349
349
  //#region src/extensions/(backend)/api/settings/route.server.ts
350
350
  var route_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineRoutedContribution)(({ host }) => host.scope === "session" ? void 0 : settingsApi, { cardinality: "optional" });
351
351
  //#endregion
352
- //#region src/services/configResources/index.ts
353
- function selectionMetadata(execution) {
354
- return JSON.stringify({
355
- profile: execution.selection.profile ?? null,
356
- domains: execution.selection.domains,
357
- majorMode: execution.selection.majorMode,
358
- activeLayers: execution.selection.activeLayers
359
- });
360
- }
361
- //#endregion
362
- //#region src/extensions/workspaces/sessions/(backend)/resource/config.server.ts
363
- var config_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)({
364
- name: "doompi/config",
365
- kind: "context",
366
- read: selectionMetadata
367
- });
368
- //#endregion
369
352
  //#region src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts
370
353
  var doompi_author_config_server_default = (0, _agimon_ai_doompi_core_extensionFile.defineResource)({
371
354
  ...require_config$1.CONFIG_HELP_SKILL,
@@ -398,7 +381,7 @@ const facet = (0, _agimon_ai_doompi_core_serverFacet.defineServerPlugin)({
398
381
  return defined([at(route_server_default, context)]);
399
382
  },
400
383
  get resources() {
401
- return [at(config_server_default, context), at(doompi_author_config_server_default, context)];
384
+ return [at(doompi_author_config_server_default, context)];
402
385
  }
403
386
  })
404
387
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["defineApiRoutes","apiResponse","repositoryDoomConfigPath","globalDoomConfigPath","loadDoomConfigLayers","loadMajorModesConfig","loadDomains","loadProfiles","defaultDomainsForMajorMode","configScopeOf","loadPiImageSettings","DEFAULT_IMAGE_MAX_DIMENSION","routes","writeDoomConfigValues","repositoryDoomConfigPath","configScopeOf","defineRoutedContribution","defineResource","defineResource","CONFIG_HELP_SKILL","packageResourcePath","readPackageResource","defineServerPlugin","apiRoute","resourceConfig","resourceDoompiAuthorConfig"],"sources":["../../src/constants/settings.ts","../../src/types/apiRoutes.ts","../../src/services/settings/index.ts","../../src/services/settingsApi/index.ts","../../src/extensions/(backend)/api/settings/route.server.ts","../../src/services/configResources/index.ts","../../src/extensions/workspaces/sessions/(backend)/resource/config.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts","../../generated/server.ts"],"sourcesContent":["export const KEY_SEPARATOR = '.';\n\n/** The repeatable query parameter naming which keys a read is about. */\nexport const KEY_QUERY_PARAM = 'key';\n\nexport const SELECTION_KEYS = {\n majorMode: ['selection', 'majorMode'],\n domains: ['selection', 'domains'],\n profile: ['selection', 'profile'],\n} as const;\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport { KEY_QUERY_PARAM } from '../constants/settings';\nimport type { RepositorySettingsView, SettingsConfigView, SettingsImagesView, SettingsRepository } from './settings';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/settings/`, so the mount is stated once, by the\n * folder that creates it. `settings` is the host's own API: it answers at\n * `/api/settings` and `/api/workspaces/<id>/settings`, beside `/plugins` rather\n * than under it, and the client knows that from the base path alone.\n *\n * This is the one file the mount's dispatcher and, once the client crosses the\n * package boundary, the cockpit both read, so a path cannot move on one side\n * alone.\n */\nexport default defineApiRoutes({\n /** The mount itself: the selected keys and the hash of each file they came from. */\n config: {\n method: 'GET',\n path: '/',\n /** Repeatable. The page also sends `repoRoot`, which the mount ignores: it serves one repository. */\n query: [KEY_QUERY_PARAM],\n response: apiResponse<SettingsConfigView>(),\n },\n value: {\n method: 'PUT',\n path: '/value',\n response: apiResponse<SettingsConfigView>(),\n },\n repositories: {\n method: 'GET',\n path: '/repositories',\n response: apiResponse<{ repositories: readonly SettingsRepository[] }>(),\n },\n /** The workspace this mount was bound to; a global mount has none and answers 404. */\n repository: {\n method: 'GET',\n path: '/repository',\n response: apiResponse<RepositorySettingsView>(),\n },\n selection: {\n method: 'PUT',\n path: '/repository/selection',\n response: apiResponse<RepositorySettingsView>(),\n },\n /** Pi's own image limits, served by the global mount only. */\n images: {\n method: 'GET',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n /** The same path as `images`; the method is the whole of the difference. */\n saveImages: {\n method: 'PUT',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n});\n","import type { DoomApiContext } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_SEPARATOR, SELECTION_KEYS } from '../../constants/settings';\nimport type {\n RepositoryCatalogOption,\n RepositorySelectionChanges,\n RepositorySelectionWriteRequest,\n RepositorySettingsView,\n SettingsConfigView,\n SettingsRepository,\n SettingsScope,\n SettingsValueView,\n SettingsBatchWriteRequest,\n} from '../../types/settings';\nimport { globalDoomConfigPath, loadDoomConfigLayers, repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { defaultDomainsForMajorMode, loadDomains } from '../domains';\nimport { loadMajorModesConfig } from '../majorModes';\nimport { loadProfiles } from '../profiles';\n\ntype SelectionKey = keyof typeof SELECTION_KEYS;\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The display form of a config value; a record has no single-line form, so it has none. */\nexport function displayValue(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map((entry) => displayValue(entry) ?? '').join(', ');\n return undefined;\n}\n\nexport function pathFor(scope: SettingsScope, repoRoot: string, homeDirectory: string | undefined): string {\n return scope === 'repository' ? repositoryDoomConfigPath(repoRoot) : globalDoomConfigPath(homeDirectory);\n}\n\nexport function parseWrite(body: unknown): SettingsBatchWriteRequest | undefined {\n if (!isRecord(body)) return undefined;\n const { repoRoot, scope, expectedHash } = body;\n if (typeof repoRoot !== 'string' || (scope !== 'global' && scope !== 'repository')) return undefined;\n if (scope === 'repository' && repoRoot === '') return undefined;\n if (typeof expectedHash !== 'string') return undefined;\n const edits = body.edits === undefined ? [{ keyPath: body.keyPath, value: body.value }] : body.edits;\n if (!Array.isArray(edits) || edits.length === 0 || edits.length > 100) return undefined;\n const validated: Array<SettingsBatchWriteRequest['edits'][number]> = [];\n for (const edit of edits) {\n if (!isRecord(edit)) return undefined;\n const { keyPath, value } = edit;\n if (!Array.isArray(keyPath) || keyPath.length === 0 || keyPath.some((part) => typeof part !== 'string'))\n return undefined;\n if (value !== null && typeof value !== 'string' && (typeof value !== 'number' || !Number.isFinite(value)))\n return undefined;\n validated.push({ keyPath: keyPath as string[], value });\n }\n return { repoRoot, scope, expectedHash, edits: validated };\n}\n\nexport function configuredSelectionValue<T>(\n layers: ReturnType<typeof loadDoomConfigLayers>,\n key: SelectionKey,\n effective: T | undefined,\n): { effective?: T; repository?: T; origin: 'global' | 'repository' | 'default' } {\n const origin = layers.originOf(SELECTION_KEYS[key]);\n return {\n ...(effective === undefined ? {} : { effective }),\n ...(origin === 'repository' && effective !== undefined ? { repository: effective } : {}),\n origin,\n };\n}\n\nexport function repositorySettingsView(\n repository: SettingsRepository,\n homeDirectory: string | undefined,\n): RepositorySettingsView {\n const repoRoot = repository.path;\n const layers = loadDoomConfigLayers(repoRoot, homeDirectory);\n const modes = loadMajorModesConfig(repoRoot, homeDirectory);\n const domains = loadDomains(repoRoot, homeDirectory);\n const profiles = loadProfiles(repoRoot, homeDirectory);\n const configured = layers.effective.selection;\n const effectiveMajorMode = configured?.majorMode ?? modes.defaultMajorMode;\n const effectiveDomains =\n configured?.domains ?? defaultDomainsForMajorMode(effectiveMajorMode, {}, domains.defaultDomains);\n const majorModes: RepositoryCatalogOption[] = Object.entries(modes.majorMode)\n .map(([name, definition]) => ({ name, description: definition.description, layers: definition.layers }))\n .sort((left, right) => left.name.localeCompare(right.name));\n const domainOptions: RepositoryCatalogOption[] = [\n ...Object.entries(domains.domains).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n })),\n ...Object.entries(domains.aliases).map(([name, expandsTo]) => ({\n name,\n description: `Alias for ${expandsTo.join(', ') || 'no domains'}.`,\n expandsTo,\n })),\n ].sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n repository,\n hash: layers.repositoryFile.hash,\n catalogs: {\n majorModes,\n domains: domainOptions,\n profiles: profiles.map((profile) => ({ name: profile.name })),\n },\n selection: {\n majorMode: configuredSelectionValue(layers, 'majorMode', effectiveMajorMode),\n domains: configuredSelectionValue(layers, 'domains', effectiveDomains),\n profile: configuredSelectionValue(layers, 'profile', configured?.profile),\n },\n };\n}\n\nexport function parseSelectionChanges(value: unknown): RepositorySelectionChanges | undefined {\n if (!isRecord(value)) return undefined;\n const keys = Object.keys(value);\n if (keys.length === 0 || keys.some((key) => !Object.hasOwn(SELECTION_KEYS, key))) return undefined;\n const changes: RepositorySelectionChanges = {};\n if (Object.hasOwn(value, 'majorMode')) {\n if (value.majorMode !== null && (typeof value.majorMode !== 'string' || value.majorMode.trim() === ''))\n return undefined;\n changes.majorMode = value.majorMode === null ? null : value.majorMode.trim();\n }\n if (Object.hasOwn(value, 'domains')) {\n if (\n value.domains !== null &&\n (!Array.isArray(value.domains) || value.domains.some((name) => typeof name !== 'string' || name.trim() === ''))\n ) {\n return undefined;\n }\n changes.domains =\n value.domains === null ? null : [...new Set((value.domains as string[]).map((name) => name.trim()))];\n }\n if (Object.hasOwn(value, 'profile')) {\n if (value.profile !== null && (typeof value.profile !== 'string' || value.profile.trim() === '')) return undefined;\n changes.profile = value.profile === null ? null : value.profile.trim();\n }\n return changes;\n}\n\nexport function parseSelectionWrite(value: unknown): RepositorySelectionWriteRequest | undefined {\n if (!isRecord(value) || typeof value.repositoryId !== 'string' || typeof value.expectedHash !== 'string')\n return undefined;\n const changes = parseSelectionChanges(value.changes);\n return changes === undefined\n ? undefined\n : { repositoryId: value.repositoryId, expectedHash: value.expectedHash, changes };\n}\n\nexport function validateSelectionChanges(\n view: RepositorySettingsView,\n changes: RepositorySelectionChanges,\n): string | undefined {\n if (changes.majorMode !== undefined && changes.majorMode !== null) {\n if (!view.catalogs.majorModes.some((mode) => mode.name === changes.majorMode)) {\n return `Unknown major mode '${changes.majorMode}'.`;\n }\n }\n if (changes.domains !== undefined && changes.domains !== null) {\n const known = new Set(view.catalogs.domains.map((domain) => domain.name));\n const unknown = changes.domains.find((domain) => !known.has(domain));\n if (unknown !== undefined) return `Unknown domain '${unknown}'.`;\n }\n if (changes.profile !== undefined && changes.profile !== null) {\n if (!view.catalogs.profiles.some((profile) => profile.name === changes.profile)) {\n return `Unknown profile '${changes.profile}'.`;\n }\n }\n return undefined;\n}\n\nexport function selectionEdits(changes: RepositorySelectionChanges) {\n return (Object.entries(changes) as Array<[SelectionKey, string | readonly string[] | null]>).map(([key, value]) => ({\n keyPath: SELECTION_KEYS[key],\n ...(value === null ? {} : { value }),\n }));\n}\n\nexport function configView(context: DoomApiContext, keys: readonly string[]): SettingsConfigView {\n const root = context.scope === 'workspace' ? context.workspaceRoot : undefined;\n const layers = loadDoomConfigLayers(root, context.homeDirectory);\n const values: Record<string, SettingsValueView> = {};\n for (const key of keys) {\n const keyPath = key.split(KEY_SEPARATOR);\n const value = displayValue(layers.valueAt(keyPath));\n values[key] = {\n ...(value === undefined ? {} : { value }),\n origin: layers.originOf(keyPath),\n scope: configScopeOf(keyPath),\n };\n }\n return {\n repoRoot: root ?? '',\n values,\n hashes: { global: layers.globalFile.hash, repository: layers.repositoryFile.hash },\n };\n}\n","import type { DoomApi } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_QUERY_PARAM, KEY_SEPARATOR } from '../../constants/settings';\nimport routes from '../../types/apiRoutes';\nimport type { SettingsRepository } from '../../types/settings';\nimport { repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { writeDoomConfigValues } from '../configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../settings';\n\n/** One declared route, as much of it as a comparison needs. */\ntype RouteSpec = { readonly method: string; readonly path: string };\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'settings',\n start(context) {\n if (context.scope === 'session') throw new Error('Configuration settings require a global or workspace mount.');\n const { homeDirectory } = context;\n const repository = (): SettingsRepository | undefined =>\n context.scope === 'workspace' && context.workspaceId && context.workspaceRoot\n ? {\n id: context.workspaceId,\n name: context.workspaceRoot.split('/').at(-1) ?? context.workspaceId,\n path: context.workspaceRoot,\n active: context.repositories?.().find((entry) => entry.id === context.workspaceId)?.active ?? false,\n }\n : undefined;\n const imageView = () => ({\n ...loadPiImageSettings(homeDirectory),\n minDimension: MIN_IMAGE_MAX_DIMENSION,\n maxAllowedDimension: DEFAULT_IMAGE_MAX_DIMENSION,\n });\n let writes: Promise<unknown> = Promise.resolve();\n let closed = false;\n const dispatch = async (request: Request): Promise<Response> => {\n if (closed) return Response.json({ error: 'Configuration mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n /**\n * Whether this request addresses one declared route.\n *\n * The table owns both halves of the comparison, so the path this mount\n * answers and the path the client asks for cannot drift apart: there is\n * one spelling of each, in `src/types/apiRoutes`.\n */\n const addresses = (route: RouteSpec): boolean => url.pathname === route.path && request.method === route.method;\n const currentRepository = repository();\n if (addresses(routes.config)) return Response.json(configView(context, url.searchParams.getAll(KEY_QUERY_PARAM)));\n if (addresses(routes.repositories)) return Response.json({ repositories: context.repositories?.() ?? [] });\n if (addresses(routes.repository)) {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n // One path, two methods, so the branch is on the path the pair share.\n if (url.pathname === routes.images.path && context.scope === 'global') {\n if (request.method === routes.images.method) return Response.json(imageView());\n if (request.method === routes.saveImages.method) {\n const body: unknown = await request.json();\n if (\n !isRecord(body) ||\n (body.autoResize !== undefined && typeof body.autoResize !== 'boolean') ||\n (body.maxDimension !== undefined &&\n (typeof body.maxDimension !== 'number' || !Number.isFinite(body.maxDimension)))\n )\n return Response.json({ error: 'Invalid image settings.' }, { status: 400 });\n savePiImageSettings(\n {\n ...(typeof body.autoResize === 'boolean' ? { autoResize: body.autoResize } : {}),\n ...(typeof body.maxDimension === 'number' ? { maxDimension: body.maxDimension } : {}),\n },\n homeDirectory,\n );\n context.configurationChanged?.();\n return Response.json(imageView());\n }\n }\n if (addresses(routes.selection)) {\n const body = parseSelectionWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A selection write needs typed changes and a file hash.' }, { status: 400 });\n if (!currentRepository || body.repositoryId !== currentRepository.id)\n return Response.json({ error: 'Workspace not found in this mount.' }, { status: 404 });\n const before = repositorySettingsView(currentRepository, homeDirectory);\n if (before.hash !== body.expectedHash)\n return Response.json(\n { error: 'The repository config changed since it was read.', hash: before.hash },\n { status: 409 },\n );\n const invalid = validateSelectionChanges(before, body.changes);\n if (invalid) return Response.json({ error: invalid }, { status: 422 });\n await writeDoomConfigValues(repositoryDoomConfigPath(currentRepository.path), selectionEdits(body.changes), {\n scope: 'repository',\n });\n context.configurationChanged?.();\n return Response.json(repositorySettingsView(currentRepository, homeDirectory));\n }\n if (addresses(routes.value)) {\n const body = parseWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A save requires a scope, key, value and file hash.' }, { status: 400 });\n const scope = context.scope === 'global' ? 'global' : 'repository';\n if (body.scope !== scope || (scope === 'repository' && body.repoRoot !== currentRepository?.path))\n return Response.json({ error: 'The write targets a different mount.' }, { status: 403 });\n if (\n body.edits.some((edit) => {\n const allowed = configScopeOf(edit.keyPath);\n return allowed !== 'both' && allowed !== scope;\n })\n )\n return Response.json({ error: 'This key cannot be set at this scope.' }, { status: 409 });\n const before = configView(context, []);\n if (before.hashes[scope] !== body.expectedHash)\n return Response.json(\n { error: 'The config changed since it was read.', hash: before.hashes[scope] },\n { status: 409 },\n );\n const target = pathFor(scope, currentRepository?.path ?? '', homeDirectory);\n await writeDoomConfigValues(\n target,\n body.edits.map(({ keyPath, value }) => ({ keyPath, ...(value === null ? {} : { value }) })),\n { scope },\n );\n context.configurationChanged?.();\n return Response.json(\n configView(\n context,\n body.edits.map((edit) => edit.keyPath.join(KEY_SEPARATOR)),\n ),\n );\n }\n return Response.json({ error: 'Configuration route not found.' }, { status: 404 });\n };\n const guarded = async (request: Request): Promise<Response> => {\n try {\n return await dispatch(request);\n } catch (error) {\n return Response.json({ error: describe(error) }, { status: error instanceof SyntaxError ? 400 : 422 });\n }\n };\n return {\n fetch(request) {\n if (request.method === 'GET' || request.method === 'HEAD') return guarded(request);\n const result = writes.then(() => guarded(request));\n writes = result.catch(() => undefined);\n return result;\n },\n close() {\n closed = true;\n },\n };\n },\n};\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { settingsApi } from '../../../../services/settingsApi';\n\nexport default defineRoutedContribution(\n ({ host }: DoomServerPluginContext) => (host.scope === 'session' ? undefined : settingsApi),\n { cardinality: 'optional' },\n);\n","export function selectionMetadata(execution: {\n readonly selection: {\n readonly profile?: string;\n readonly domains: readonly string[];\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n };\n}): string {\n return JSON.stringify({\n profile: execution.selection.profile ?? null,\n domains: execution.selection.domains,\n majorMode: execution.selection.majorMode,\n activeLayers: execution.selection.activeLayers,\n });\n}\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { selectionMetadata } from '../../../../../services/configResources';\nexport default defineResource({ name: 'doompi/config', kind: 'context' as const, read: selectionMetadata });\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { CONFIG_HELP_SKILL } from '../../../../../constants/config';\n\nexport default defineResource({\n ...CONFIG_HELP_SKILL,\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor' as const, mode: 'help' } },\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport apiRoute from '../src/extensions/(backend)/api/settings/route.server';\nimport resourceConfig from '../src/extensions/workspaces/sessions/(backend)/resource/config.server';\nimport resourceDoompiAuthorConfig from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-config',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceConfig, context), at(resourceDoompiAuthorConfig, context)]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["defineApiRoutes","apiResponse","repositoryDoomConfigPath","globalDoomConfigPath","loadDoomConfigLayers","loadMajorModesConfig","loadDomains","loadProfiles","defaultDomainsForMajorMode","configScopeOf","loadPiImageSettings","DEFAULT_IMAGE_MAX_DIMENSION","routes","writeDoomConfigValues","repositoryDoomConfigPath","configScopeOf","defineRoutedContribution","defineResource","CONFIG_HELP_SKILL","packageResourcePath","readPackageResource","defineServerPlugin","apiRoute","resourceDoompiAuthorConfig"],"sources":["../../src/constants/settings.ts","../../src/types/apiRoutes.ts","../../src/services/settings/index.ts","../../src/services/settingsApi/index.ts","../../src/extensions/(backend)/api/settings/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts","../../generated/server.ts"],"sourcesContent":["export const KEY_SEPARATOR = '.';\n\n/** The repeatable query parameter naming which keys a read is about. */\nexport const KEY_QUERY_PARAM = 'key';\n\nexport const SELECTION_KEYS = {\n majorMode: ['selection', 'majorMode'],\n domains: ['selection', 'domains'],\n profile: ['selection', 'profile'],\n} as const;\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport { KEY_QUERY_PARAM } from '../constants/settings';\nimport type { RepositorySettingsView, SettingsConfigView, SettingsImagesView, SettingsRepository } from './settings';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/settings/`, so the mount is stated once, by the\n * folder that creates it. `settings` is the host's own API: it answers at\n * `/api/settings` and `/api/workspaces/<id>/settings`, beside `/plugins` rather\n * than under it, and the client knows that from the base path alone.\n *\n * This is the one file the mount's dispatcher and, once the client crosses the\n * package boundary, the cockpit both read, so a path cannot move on one side\n * alone.\n */\nexport default defineApiRoutes({\n /** The mount itself: the selected keys and the hash of each file they came from. */\n config: {\n method: 'GET',\n path: '/',\n /** Repeatable. The page also sends `repoRoot`, which the mount ignores: it serves one repository. */\n query: [KEY_QUERY_PARAM],\n response: apiResponse<SettingsConfigView>(),\n },\n value: {\n method: 'PUT',\n path: '/value',\n response: apiResponse<SettingsConfigView>(),\n },\n repositories: {\n method: 'GET',\n path: '/repositories',\n response: apiResponse<{ repositories: readonly SettingsRepository[] }>(),\n },\n /** The workspace this mount was bound to; a global mount has none and answers 404. */\n repository: {\n method: 'GET',\n path: '/repository',\n response: apiResponse<RepositorySettingsView>(),\n },\n selection: {\n method: 'PUT',\n path: '/repository/selection',\n response: apiResponse<RepositorySettingsView>(),\n },\n /** Pi's own image limits, served by the global mount only. */\n images: {\n method: 'GET',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n /** The same path as `images`; the method is the whole of the difference. */\n saveImages: {\n method: 'PUT',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n});\n","import type { DoomApiContext } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_SEPARATOR, SELECTION_KEYS } from '../../constants/settings';\nimport type {\n RepositoryCatalogOption,\n RepositorySelectionChanges,\n RepositorySelectionWriteRequest,\n RepositorySettingsView,\n SettingsConfigView,\n SettingsRepository,\n SettingsScope,\n SettingsValueView,\n SettingsBatchWriteRequest,\n} from '../../types/settings';\nimport { globalDoomConfigPath, loadDoomConfigLayers, repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { defaultDomainsForMajorMode, loadDomains } from '../domains';\nimport { loadMajorModesConfig } from '../majorModes';\nimport { loadProfiles } from '../profiles';\n\ntype SelectionKey = keyof typeof SELECTION_KEYS;\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The display form of a config value; a record has no single-line form, so it has none. */\nexport function displayValue(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map((entry) => displayValue(entry) ?? '').join(', ');\n return undefined;\n}\n\nexport function pathFor(scope: SettingsScope, repoRoot: string, homeDirectory: string | undefined): string {\n return scope === 'repository' ? repositoryDoomConfigPath(repoRoot) : globalDoomConfigPath(homeDirectory);\n}\n\nexport function parseWrite(body: unknown): SettingsBatchWriteRequest | undefined {\n if (!isRecord(body)) return undefined;\n const { repoRoot, scope, expectedHash } = body;\n if (typeof repoRoot !== 'string' || (scope !== 'global' && scope !== 'repository')) return undefined;\n if (scope === 'repository' && repoRoot === '') return undefined;\n if (typeof expectedHash !== 'string') return undefined;\n const edits = body.edits === undefined ? [{ keyPath: body.keyPath, value: body.value }] : body.edits;\n if (!Array.isArray(edits) || edits.length === 0 || edits.length > 100) return undefined;\n const validated: Array<SettingsBatchWriteRequest['edits'][number]> = [];\n for (const edit of edits) {\n if (!isRecord(edit)) return undefined;\n const { keyPath, value } = edit;\n if (!Array.isArray(keyPath) || keyPath.length === 0 || keyPath.some((part) => typeof part !== 'string'))\n return undefined;\n if (value !== null && typeof value !== 'string' && (typeof value !== 'number' || !Number.isFinite(value)))\n return undefined;\n validated.push({ keyPath: keyPath as string[], value });\n }\n return { repoRoot, scope, expectedHash, edits: validated };\n}\n\nexport function configuredSelectionValue<T>(\n layers: ReturnType<typeof loadDoomConfigLayers>,\n key: SelectionKey,\n effective: T | undefined,\n): { effective?: T; repository?: T; origin: 'global' | 'repository' | 'default' } {\n const origin = layers.originOf(SELECTION_KEYS[key]);\n return {\n ...(effective === undefined ? {} : { effective }),\n ...(origin === 'repository' && effective !== undefined ? { repository: effective } : {}),\n origin,\n };\n}\n\nexport function repositorySettingsView(\n repository: SettingsRepository,\n homeDirectory: string | undefined,\n): RepositorySettingsView {\n const repoRoot = repository.path;\n const layers = loadDoomConfigLayers(repoRoot, homeDirectory);\n const modes = loadMajorModesConfig(repoRoot, homeDirectory);\n const domains = loadDomains(repoRoot, homeDirectory);\n const profiles = loadProfiles(repoRoot, homeDirectory);\n const configured = layers.effective.selection;\n const effectiveMajorMode = configured?.majorMode ?? modes.defaultMajorMode;\n const effectiveDomains =\n configured?.domains ?? defaultDomainsForMajorMode(effectiveMajorMode, {}, domains.defaultDomains);\n const majorModes: RepositoryCatalogOption[] = Object.entries(modes.majorMode)\n .map(([name, definition]) => ({ name, description: definition.description, layers: definition.layers }))\n .sort((left, right) => left.name.localeCompare(right.name));\n const domainOptions: RepositoryCatalogOption[] = [\n ...Object.entries(domains.domains).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n })),\n ...Object.entries(domains.aliases).map(([name, expandsTo]) => ({\n name,\n description: `Alias for ${expandsTo.join(', ') || 'no domains'}.`,\n expandsTo,\n })),\n ].sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n repository,\n hash: layers.repositoryFile.hash,\n catalogs: {\n majorModes,\n domains: domainOptions,\n profiles: profiles.map((profile) => ({ name: profile.name })),\n },\n selection: {\n majorMode: configuredSelectionValue(layers, 'majorMode', effectiveMajorMode),\n domains: configuredSelectionValue(layers, 'domains', effectiveDomains),\n profile: configuredSelectionValue(layers, 'profile', configured?.profile),\n },\n };\n}\n\nexport function parseSelectionChanges(value: unknown): RepositorySelectionChanges | undefined {\n if (!isRecord(value)) return undefined;\n const keys = Object.keys(value);\n if (keys.length === 0 || keys.some((key) => !Object.hasOwn(SELECTION_KEYS, key))) return undefined;\n const changes: RepositorySelectionChanges = {};\n if (Object.hasOwn(value, 'majorMode')) {\n if (value.majorMode !== null && (typeof value.majorMode !== 'string' || value.majorMode.trim() === ''))\n return undefined;\n changes.majorMode = value.majorMode === null ? null : value.majorMode.trim();\n }\n if (Object.hasOwn(value, 'domains')) {\n if (\n value.domains !== null &&\n (!Array.isArray(value.domains) || value.domains.some((name) => typeof name !== 'string' || name.trim() === ''))\n ) {\n return undefined;\n }\n changes.domains =\n value.domains === null ? null : [...new Set((value.domains as string[]).map((name) => name.trim()))];\n }\n if (Object.hasOwn(value, 'profile')) {\n if (value.profile !== null && (typeof value.profile !== 'string' || value.profile.trim() === '')) return undefined;\n changes.profile = value.profile === null ? null : value.profile.trim();\n }\n return changes;\n}\n\nexport function parseSelectionWrite(value: unknown): RepositorySelectionWriteRequest | undefined {\n if (!isRecord(value) || typeof value.repositoryId !== 'string' || typeof value.expectedHash !== 'string')\n return undefined;\n const changes = parseSelectionChanges(value.changes);\n return changes === undefined\n ? undefined\n : { repositoryId: value.repositoryId, expectedHash: value.expectedHash, changes };\n}\n\nexport function validateSelectionChanges(\n view: RepositorySettingsView,\n changes: RepositorySelectionChanges,\n): string | undefined {\n if (changes.majorMode !== undefined && changes.majorMode !== null) {\n if (!view.catalogs.majorModes.some((mode) => mode.name === changes.majorMode)) {\n return `Unknown major mode '${changes.majorMode}'.`;\n }\n }\n if (changes.domains !== undefined && changes.domains !== null) {\n const known = new Set(view.catalogs.domains.map((domain) => domain.name));\n const unknown = changes.domains.find((domain) => !known.has(domain));\n if (unknown !== undefined) return `Unknown domain '${unknown}'.`;\n }\n if (changes.profile !== undefined && changes.profile !== null) {\n if (!view.catalogs.profiles.some((profile) => profile.name === changes.profile)) {\n return `Unknown profile '${changes.profile}'.`;\n }\n }\n return undefined;\n}\n\nexport function selectionEdits(changes: RepositorySelectionChanges) {\n return (Object.entries(changes) as Array<[SelectionKey, string | readonly string[] | null]>).map(([key, value]) => ({\n keyPath: SELECTION_KEYS[key],\n ...(value === null ? {} : { value }),\n }));\n}\n\nexport function configView(context: DoomApiContext, keys: readonly string[]): SettingsConfigView {\n const root = context.scope === 'workspace' ? context.workspaceRoot : undefined;\n const layers = loadDoomConfigLayers(root, context.homeDirectory);\n const values: Record<string, SettingsValueView> = {};\n for (const key of keys) {\n const keyPath = key.split(KEY_SEPARATOR);\n const value = displayValue(layers.valueAt(keyPath));\n values[key] = {\n ...(value === undefined ? {} : { value }),\n origin: layers.originOf(keyPath),\n scope: configScopeOf(keyPath),\n };\n }\n return {\n repoRoot: root ?? '',\n values,\n hashes: { global: layers.globalFile.hash, repository: layers.repositoryFile.hash },\n };\n}\n","import type { DoomApi } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_QUERY_PARAM, KEY_SEPARATOR } from '../../constants/settings';\nimport routes from '../../types/apiRoutes';\nimport type { SettingsRepository } from '../../types/settings';\nimport { repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { writeDoomConfigValues } from '../configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../settings';\n\n/** One declared route, as much of it as a comparison needs. */\ntype RouteSpec = { readonly method: string; readonly path: string };\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'settings',\n start(context) {\n if (context.scope === 'session') throw new Error('Configuration settings require a global or workspace mount.');\n const { homeDirectory } = context;\n const repository = (): SettingsRepository | undefined =>\n context.scope === 'workspace' && context.workspaceId && context.workspaceRoot\n ? {\n id: context.workspaceId,\n name: context.workspaceRoot.split('/').at(-1) ?? context.workspaceId,\n path: context.workspaceRoot,\n active: context.repositories?.().find((entry) => entry.id === context.workspaceId)?.active ?? false,\n }\n : undefined;\n const imageView = () => ({\n ...loadPiImageSettings(homeDirectory),\n minDimension: MIN_IMAGE_MAX_DIMENSION,\n maxAllowedDimension: DEFAULT_IMAGE_MAX_DIMENSION,\n });\n let writes: Promise<unknown> = Promise.resolve();\n let closed = false;\n const dispatch = async (request: Request): Promise<Response> => {\n if (closed) return Response.json({ error: 'Configuration mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n /**\n * Whether this request addresses one declared route.\n *\n * The table owns both halves of the comparison, so the path this mount\n * answers and the path the client asks for cannot drift apart: there is\n * one spelling of each, in `src/types/apiRoutes`.\n */\n const addresses = (route: RouteSpec): boolean => url.pathname === route.path && request.method === route.method;\n const currentRepository = repository();\n if (addresses(routes.config)) return Response.json(configView(context, url.searchParams.getAll(KEY_QUERY_PARAM)));\n if (addresses(routes.repositories)) return Response.json({ repositories: context.repositories?.() ?? [] });\n if (addresses(routes.repository)) {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n // One path, two methods, so the branch is on the path the pair share.\n if (url.pathname === routes.images.path && context.scope === 'global') {\n if (request.method === routes.images.method) return Response.json(imageView());\n if (request.method === routes.saveImages.method) {\n const body: unknown = await request.json();\n if (\n !isRecord(body) ||\n (body.autoResize !== undefined && typeof body.autoResize !== 'boolean') ||\n (body.maxDimension !== undefined &&\n (typeof body.maxDimension !== 'number' || !Number.isFinite(body.maxDimension)))\n )\n return Response.json({ error: 'Invalid image settings.' }, { status: 400 });\n savePiImageSettings(\n {\n ...(typeof body.autoResize === 'boolean' ? { autoResize: body.autoResize } : {}),\n ...(typeof body.maxDimension === 'number' ? { maxDimension: body.maxDimension } : {}),\n },\n homeDirectory,\n );\n context.configurationChanged?.();\n return Response.json(imageView());\n }\n }\n if (addresses(routes.selection)) {\n const body = parseSelectionWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A selection write needs typed changes and a file hash.' }, { status: 400 });\n if (!currentRepository || body.repositoryId !== currentRepository.id)\n return Response.json({ error: 'Workspace not found in this mount.' }, { status: 404 });\n const before = repositorySettingsView(currentRepository, homeDirectory);\n if (before.hash !== body.expectedHash)\n return Response.json(\n { error: 'The repository config changed since it was read.', hash: before.hash },\n { status: 409 },\n );\n const invalid = validateSelectionChanges(before, body.changes);\n if (invalid) return Response.json({ error: invalid }, { status: 422 });\n await writeDoomConfigValues(repositoryDoomConfigPath(currentRepository.path), selectionEdits(body.changes), {\n scope: 'repository',\n });\n context.configurationChanged?.();\n return Response.json(repositorySettingsView(currentRepository, homeDirectory));\n }\n if (addresses(routes.value)) {\n const body = parseWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A save requires a scope, key, value and file hash.' }, { status: 400 });\n const scope = context.scope === 'global' ? 'global' : 'repository';\n if (body.scope !== scope || (scope === 'repository' && body.repoRoot !== currentRepository?.path))\n return Response.json({ error: 'The write targets a different mount.' }, { status: 403 });\n if (\n body.edits.some((edit) => {\n const allowed = configScopeOf(edit.keyPath);\n return allowed !== 'both' && allowed !== scope;\n })\n )\n return Response.json({ error: 'This key cannot be set at this scope.' }, { status: 409 });\n const before = configView(context, []);\n if (before.hashes[scope] !== body.expectedHash)\n return Response.json(\n { error: 'The config changed since it was read.', hash: before.hashes[scope] },\n { status: 409 },\n );\n const target = pathFor(scope, currentRepository?.path ?? '', homeDirectory);\n await writeDoomConfigValues(\n target,\n body.edits.map(({ keyPath, value }) => ({ keyPath, ...(value === null ? {} : { value }) })),\n { scope },\n );\n context.configurationChanged?.();\n return Response.json(\n configView(\n context,\n body.edits.map((edit) => edit.keyPath.join(KEY_SEPARATOR)),\n ),\n );\n }\n return Response.json({ error: 'Configuration route not found.' }, { status: 404 });\n };\n const guarded = async (request: Request): Promise<Response> => {\n try {\n return await dispatch(request);\n } catch (error) {\n return Response.json({ error: describe(error) }, { status: error instanceof SyntaxError ? 400 : 422 });\n }\n };\n return {\n fetch(request) {\n if (request.method === 'GET' || request.method === 'HEAD') return guarded(request);\n const result = writes.then(() => guarded(request));\n writes = result.catch(() => undefined);\n return result;\n },\n close() {\n closed = true;\n },\n };\n },\n};\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { settingsApi } from '../../../../services/settingsApi';\n\nexport default defineRoutedContribution(\n ({ host }: DoomServerPluginContext) => (host.scope === 'session' ? undefined : settingsApi),\n { cardinality: 'optional' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { CONFIG_HELP_SKILL } from '../../../../../constants/config';\n\nexport default defineResource({\n ...CONFIG_HELP_SKILL,\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor' as const, mode: 'help' } },\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport apiRoute from '../src/extensions/(backend)/api/settings/route.server';\nimport resourceDoompiAuthorConfig from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-config',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiAuthorConfig, context)]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAca,oDAAK"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../../generated/server.ts"],"mappings":";qBAaa,oDAAK"}
@@ -345,23 +345,6 @@ const settingsApi = {
345
345
  //#region src/extensions/(backend)/api/settings/route.server.ts
346
346
  var route_server_default = defineRoutedContribution(({ host }) => host.scope === "session" ? void 0 : settingsApi, { cardinality: "optional" });
347
347
  //#endregion
348
- //#region src/services/configResources/index.ts
349
- function selectionMetadata(execution) {
350
- return JSON.stringify({
351
- profile: execution.selection.profile ?? null,
352
- domains: execution.selection.domains,
353
- majorMode: execution.selection.majorMode,
354
- activeLayers: execution.selection.activeLayers
355
- });
356
- }
357
- //#endregion
358
- //#region src/extensions/workspaces/sessions/(backend)/resource/config.server.ts
359
- var config_server_default = defineResource({
360
- name: "doompi/config",
361
- kind: "context",
362
- read: selectionMetadata
363
- });
364
- //#endregion
365
348
  //#region src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts
366
349
  var doompi_author_config_server_default = defineResource({
367
350
  ...CONFIG_HELP_SKILL,
@@ -394,7 +377,7 @@ const facet = defineServerPlugin({
394
377
  return defined([at(route_server_default, context)]);
395
378
  },
396
379
  get resources() {
397
- return [at(config_server_default, context), at(doompi_author_config_server_default, context)];
380
+ return [at(doompi_author_config_server_default, context)];
398
381
  }
399
382
  })
400
383
  });
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["routes","apiRoute","resourceConfig","resourceDoompiAuthorConfig"],"sources":["../../src/constants/settings.ts","../../src/types/apiRoutes.ts","../../src/services/settings/index.ts","../../src/services/settingsApi/index.ts","../../src/extensions/(backend)/api/settings/route.server.ts","../../src/services/configResources/index.ts","../../src/extensions/workspaces/sessions/(backend)/resource/config.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts","../../generated/server.ts"],"sourcesContent":["export const KEY_SEPARATOR = '.';\n\n/** The repeatable query parameter naming which keys a read is about. */\nexport const KEY_QUERY_PARAM = 'key';\n\nexport const SELECTION_KEYS = {\n majorMode: ['selection', 'majorMode'],\n domains: ['selection', 'domains'],\n profile: ['selection', 'profile'],\n} as const;\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport { KEY_QUERY_PARAM } from '../constants/settings';\nimport type { RepositorySettingsView, SettingsConfigView, SettingsImagesView, SettingsRepository } from './settings';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/settings/`, so the mount is stated once, by the\n * folder that creates it. `settings` is the host's own API: it answers at\n * `/api/settings` and `/api/workspaces/<id>/settings`, beside `/plugins` rather\n * than under it, and the client knows that from the base path alone.\n *\n * This is the one file the mount's dispatcher and, once the client crosses the\n * package boundary, the cockpit both read, so a path cannot move on one side\n * alone.\n */\nexport default defineApiRoutes({\n /** The mount itself: the selected keys and the hash of each file they came from. */\n config: {\n method: 'GET',\n path: '/',\n /** Repeatable. The page also sends `repoRoot`, which the mount ignores: it serves one repository. */\n query: [KEY_QUERY_PARAM],\n response: apiResponse<SettingsConfigView>(),\n },\n value: {\n method: 'PUT',\n path: '/value',\n response: apiResponse<SettingsConfigView>(),\n },\n repositories: {\n method: 'GET',\n path: '/repositories',\n response: apiResponse<{ repositories: readonly SettingsRepository[] }>(),\n },\n /** The workspace this mount was bound to; a global mount has none and answers 404. */\n repository: {\n method: 'GET',\n path: '/repository',\n response: apiResponse<RepositorySettingsView>(),\n },\n selection: {\n method: 'PUT',\n path: '/repository/selection',\n response: apiResponse<RepositorySettingsView>(),\n },\n /** Pi's own image limits, served by the global mount only. */\n images: {\n method: 'GET',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n /** The same path as `images`; the method is the whole of the difference. */\n saveImages: {\n method: 'PUT',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n});\n","import type { DoomApiContext } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_SEPARATOR, SELECTION_KEYS } from '../../constants/settings';\nimport type {\n RepositoryCatalogOption,\n RepositorySelectionChanges,\n RepositorySelectionWriteRequest,\n RepositorySettingsView,\n SettingsConfigView,\n SettingsRepository,\n SettingsScope,\n SettingsValueView,\n SettingsBatchWriteRequest,\n} from '../../types/settings';\nimport { globalDoomConfigPath, loadDoomConfigLayers, repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { defaultDomainsForMajorMode, loadDomains } from '../domains';\nimport { loadMajorModesConfig } from '../majorModes';\nimport { loadProfiles } from '../profiles';\n\ntype SelectionKey = keyof typeof SELECTION_KEYS;\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The display form of a config value; a record has no single-line form, so it has none. */\nexport function displayValue(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map((entry) => displayValue(entry) ?? '').join(', ');\n return undefined;\n}\n\nexport function pathFor(scope: SettingsScope, repoRoot: string, homeDirectory: string | undefined): string {\n return scope === 'repository' ? repositoryDoomConfigPath(repoRoot) : globalDoomConfigPath(homeDirectory);\n}\n\nexport function parseWrite(body: unknown): SettingsBatchWriteRequest | undefined {\n if (!isRecord(body)) return undefined;\n const { repoRoot, scope, expectedHash } = body;\n if (typeof repoRoot !== 'string' || (scope !== 'global' && scope !== 'repository')) return undefined;\n if (scope === 'repository' && repoRoot === '') return undefined;\n if (typeof expectedHash !== 'string') return undefined;\n const edits = body.edits === undefined ? [{ keyPath: body.keyPath, value: body.value }] : body.edits;\n if (!Array.isArray(edits) || edits.length === 0 || edits.length > 100) return undefined;\n const validated: Array<SettingsBatchWriteRequest['edits'][number]> = [];\n for (const edit of edits) {\n if (!isRecord(edit)) return undefined;\n const { keyPath, value } = edit;\n if (!Array.isArray(keyPath) || keyPath.length === 0 || keyPath.some((part) => typeof part !== 'string'))\n return undefined;\n if (value !== null && typeof value !== 'string' && (typeof value !== 'number' || !Number.isFinite(value)))\n return undefined;\n validated.push({ keyPath: keyPath as string[], value });\n }\n return { repoRoot, scope, expectedHash, edits: validated };\n}\n\nexport function configuredSelectionValue<T>(\n layers: ReturnType<typeof loadDoomConfigLayers>,\n key: SelectionKey,\n effective: T | undefined,\n): { effective?: T; repository?: T; origin: 'global' | 'repository' | 'default' } {\n const origin = layers.originOf(SELECTION_KEYS[key]);\n return {\n ...(effective === undefined ? {} : { effective }),\n ...(origin === 'repository' && effective !== undefined ? { repository: effective } : {}),\n origin,\n };\n}\n\nexport function repositorySettingsView(\n repository: SettingsRepository,\n homeDirectory: string | undefined,\n): RepositorySettingsView {\n const repoRoot = repository.path;\n const layers = loadDoomConfigLayers(repoRoot, homeDirectory);\n const modes = loadMajorModesConfig(repoRoot, homeDirectory);\n const domains = loadDomains(repoRoot, homeDirectory);\n const profiles = loadProfiles(repoRoot, homeDirectory);\n const configured = layers.effective.selection;\n const effectiveMajorMode = configured?.majorMode ?? modes.defaultMajorMode;\n const effectiveDomains =\n configured?.domains ?? defaultDomainsForMajorMode(effectiveMajorMode, {}, domains.defaultDomains);\n const majorModes: RepositoryCatalogOption[] = Object.entries(modes.majorMode)\n .map(([name, definition]) => ({ name, description: definition.description, layers: definition.layers }))\n .sort((left, right) => left.name.localeCompare(right.name));\n const domainOptions: RepositoryCatalogOption[] = [\n ...Object.entries(domains.domains).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n })),\n ...Object.entries(domains.aliases).map(([name, expandsTo]) => ({\n name,\n description: `Alias for ${expandsTo.join(', ') || 'no domains'}.`,\n expandsTo,\n })),\n ].sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n repository,\n hash: layers.repositoryFile.hash,\n catalogs: {\n majorModes,\n domains: domainOptions,\n profiles: profiles.map((profile) => ({ name: profile.name })),\n },\n selection: {\n majorMode: configuredSelectionValue(layers, 'majorMode', effectiveMajorMode),\n domains: configuredSelectionValue(layers, 'domains', effectiveDomains),\n profile: configuredSelectionValue(layers, 'profile', configured?.profile),\n },\n };\n}\n\nexport function parseSelectionChanges(value: unknown): RepositorySelectionChanges | undefined {\n if (!isRecord(value)) return undefined;\n const keys = Object.keys(value);\n if (keys.length === 0 || keys.some((key) => !Object.hasOwn(SELECTION_KEYS, key))) return undefined;\n const changes: RepositorySelectionChanges = {};\n if (Object.hasOwn(value, 'majorMode')) {\n if (value.majorMode !== null && (typeof value.majorMode !== 'string' || value.majorMode.trim() === ''))\n return undefined;\n changes.majorMode = value.majorMode === null ? null : value.majorMode.trim();\n }\n if (Object.hasOwn(value, 'domains')) {\n if (\n value.domains !== null &&\n (!Array.isArray(value.domains) || value.domains.some((name) => typeof name !== 'string' || name.trim() === ''))\n ) {\n return undefined;\n }\n changes.domains =\n value.domains === null ? null : [...new Set((value.domains as string[]).map((name) => name.trim()))];\n }\n if (Object.hasOwn(value, 'profile')) {\n if (value.profile !== null && (typeof value.profile !== 'string' || value.profile.trim() === '')) return undefined;\n changes.profile = value.profile === null ? null : value.profile.trim();\n }\n return changes;\n}\n\nexport function parseSelectionWrite(value: unknown): RepositorySelectionWriteRequest | undefined {\n if (!isRecord(value) || typeof value.repositoryId !== 'string' || typeof value.expectedHash !== 'string')\n return undefined;\n const changes = parseSelectionChanges(value.changes);\n return changes === undefined\n ? undefined\n : { repositoryId: value.repositoryId, expectedHash: value.expectedHash, changes };\n}\n\nexport function validateSelectionChanges(\n view: RepositorySettingsView,\n changes: RepositorySelectionChanges,\n): string | undefined {\n if (changes.majorMode !== undefined && changes.majorMode !== null) {\n if (!view.catalogs.majorModes.some((mode) => mode.name === changes.majorMode)) {\n return `Unknown major mode '${changes.majorMode}'.`;\n }\n }\n if (changes.domains !== undefined && changes.domains !== null) {\n const known = new Set(view.catalogs.domains.map((domain) => domain.name));\n const unknown = changes.domains.find((domain) => !known.has(domain));\n if (unknown !== undefined) return `Unknown domain '${unknown}'.`;\n }\n if (changes.profile !== undefined && changes.profile !== null) {\n if (!view.catalogs.profiles.some((profile) => profile.name === changes.profile)) {\n return `Unknown profile '${changes.profile}'.`;\n }\n }\n return undefined;\n}\n\nexport function selectionEdits(changes: RepositorySelectionChanges) {\n return (Object.entries(changes) as Array<[SelectionKey, string | readonly string[] | null]>).map(([key, value]) => ({\n keyPath: SELECTION_KEYS[key],\n ...(value === null ? {} : { value }),\n }));\n}\n\nexport function configView(context: DoomApiContext, keys: readonly string[]): SettingsConfigView {\n const root = context.scope === 'workspace' ? context.workspaceRoot : undefined;\n const layers = loadDoomConfigLayers(root, context.homeDirectory);\n const values: Record<string, SettingsValueView> = {};\n for (const key of keys) {\n const keyPath = key.split(KEY_SEPARATOR);\n const value = displayValue(layers.valueAt(keyPath));\n values[key] = {\n ...(value === undefined ? {} : { value }),\n origin: layers.originOf(keyPath),\n scope: configScopeOf(keyPath),\n };\n }\n return {\n repoRoot: root ?? '',\n values,\n hashes: { global: layers.globalFile.hash, repository: layers.repositoryFile.hash },\n };\n}\n","import type { DoomApi } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_QUERY_PARAM, KEY_SEPARATOR } from '../../constants/settings';\nimport routes from '../../types/apiRoutes';\nimport type { SettingsRepository } from '../../types/settings';\nimport { repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { writeDoomConfigValues } from '../configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../settings';\n\n/** One declared route, as much of it as a comparison needs. */\ntype RouteSpec = { readonly method: string; readonly path: string };\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'settings',\n start(context) {\n if (context.scope === 'session') throw new Error('Configuration settings require a global or workspace mount.');\n const { homeDirectory } = context;\n const repository = (): SettingsRepository | undefined =>\n context.scope === 'workspace' && context.workspaceId && context.workspaceRoot\n ? {\n id: context.workspaceId,\n name: context.workspaceRoot.split('/').at(-1) ?? context.workspaceId,\n path: context.workspaceRoot,\n active: context.repositories?.().find((entry) => entry.id === context.workspaceId)?.active ?? false,\n }\n : undefined;\n const imageView = () => ({\n ...loadPiImageSettings(homeDirectory),\n minDimension: MIN_IMAGE_MAX_DIMENSION,\n maxAllowedDimension: DEFAULT_IMAGE_MAX_DIMENSION,\n });\n let writes: Promise<unknown> = Promise.resolve();\n let closed = false;\n const dispatch = async (request: Request): Promise<Response> => {\n if (closed) return Response.json({ error: 'Configuration mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n /**\n * Whether this request addresses one declared route.\n *\n * The table owns both halves of the comparison, so the path this mount\n * answers and the path the client asks for cannot drift apart: there is\n * one spelling of each, in `src/types/apiRoutes`.\n */\n const addresses = (route: RouteSpec): boolean => url.pathname === route.path && request.method === route.method;\n const currentRepository = repository();\n if (addresses(routes.config)) return Response.json(configView(context, url.searchParams.getAll(KEY_QUERY_PARAM)));\n if (addresses(routes.repositories)) return Response.json({ repositories: context.repositories?.() ?? [] });\n if (addresses(routes.repository)) {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n // One path, two methods, so the branch is on the path the pair share.\n if (url.pathname === routes.images.path && context.scope === 'global') {\n if (request.method === routes.images.method) return Response.json(imageView());\n if (request.method === routes.saveImages.method) {\n const body: unknown = await request.json();\n if (\n !isRecord(body) ||\n (body.autoResize !== undefined && typeof body.autoResize !== 'boolean') ||\n (body.maxDimension !== undefined &&\n (typeof body.maxDimension !== 'number' || !Number.isFinite(body.maxDimension)))\n )\n return Response.json({ error: 'Invalid image settings.' }, { status: 400 });\n savePiImageSettings(\n {\n ...(typeof body.autoResize === 'boolean' ? { autoResize: body.autoResize } : {}),\n ...(typeof body.maxDimension === 'number' ? { maxDimension: body.maxDimension } : {}),\n },\n homeDirectory,\n );\n context.configurationChanged?.();\n return Response.json(imageView());\n }\n }\n if (addresses(routes.selection)) {\n const body = parseSelectionWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A selection write needs typed changes and a file hash.' }, { status: 400 });\n if (!currentRepository || body.repositoryId !== currentRepository.id)\n return Response.json({ error: 'Workspace not found in this mount.' }, { status: 404 });\n const before = repositorySettingsView(currentRepository, homeDirectory);\n if (before.hash !== body.expectedHash)\n return Response.json(\n { error: 'The repository config changed since it was read.', hash: before.hash },\n { status: 409 },\n );\n const invalid = validateSelectionChanges(before, body.changes);\n if (invalid) return Response.json({ error: invalid }, { status: 422 });\n await writeDoomConfigValues(repositoryDoomConfigPath(currentRepository.path), selectionEdits(body.changes), {\n scope: 'repository',\n });\n context.configurationChanged?.();\n return Response.json(repositorySettingsView(currentRepository, homeDirectory));\n }\n if (addresses(routes.value)) {\n const body = parseWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A save requires a scope, key, value and file hash.' }, { status: 400 });\n const scope = context.scope === 'global' ? 'global' : 'repository';\n if (body.scope !== scope || (scope === 'repository' && body.repoRoot !== currentRepository?.path))\n return Response.json({ error: 'The write targets a different mount.' }, { status: 403 });\n if (\n body.edits.some((edit) => {\n const allowed = configScopeOf(edit.keyPath);\n return allowed !== 'both' && allowed !== scope;\n })\n )\n return Response.json({ error: 'This key cannot be set at this scope.' }, { status: 409 });\n const before = configView(context, []);\n if (before.hashes[scope] !== body.expectedHash)\n return Response.json(\n { error: 'The config changed since it was read.', hash: before.hashes[scope] },\n { status: 409 },\n );\n const target = pathFor(scope, currentRepository?.path ?? '', homeDirectory);\n await writeDoomConfigValues(\n target,\n body.edits.map(({ keyPath, value }) => ({ keyPath, ...(value === null ? {} : { value }) })),\n { scope },\n );\n context.configurationChanged?.();\n return Response.json(\n configView(\n context,\n body.edits.map((edit) => edit.keyPath.join(KEY_SEPARATOR)),\n ),\n );\n }\n return Response.json({ error: 'Configuration route not found.' }, { status: 404 });\n };\n const guarded = async (request: Request): Promise<Response> => {\n try {\n return await dispatch(request);\n } catch (error) {\n return Response.json({ error: describe(error) }, { status: error instanceof SyntaxError ? 400 : 422 });\n }\n };\n return {\n fetch(request) {\n if (request.method === 'GET' || request.method === 'HEAD') return guarded(request);\n const result = writes.then(() => guarded(request));\n writes = result.catch(() => undefined);\n return result;\n },\n close() {\n closed = true;\n },\n };\n },\n};\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { settingsApi } from '../../../../services/settingsApi';\n\nexport default defineRoutedContribution(\n ({ host }: DoomServerPluginContext) => (host.scope === 'session' ? undefined : settingsApi),\n { cardinality: 'optional' },\n);\n","export function selectionMetadata(execution: {\n readonly selection: {\n readonly profile?: string;\n readonly domains: readonly string[];\n readonly majorMode: string;\n readonly activeLayers: readonly string[];\n };\n}): string {\n return JSON.stringify({\n profile: execution.selection.profile ?? null,\n domains: execution.selection.domains,\n majorMode: execution.selection.majorMode,\n activeLayers: execution.selection.activeLayers,\n });\n}\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\n\nimport { selectionMetadata } from '../../../../../services/configResources';\nexport default defineResource({ name: 'doompi/config', kind: 'context' as const, read: selectionMetadata });\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { CONFIG_HELP_SKILL } from '../../../../../constants/config';\n\nexport default defineResource({\n ...CONFIG_HELP_SKILL,\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor' as const, mode: 'help' } },\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport apiRoute from '../src/extensions/(backend)/api/settings/route.server';\nimport resourceConfig from '../src/extensions/workspaces/sessions/(backend)/resource/config.server';\nimport resourceDoompiAuthorConfig from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-config',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceConfig, context), at(resourceDoompiAuthorConfig, context)]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":["routes","apiRoute","resourceDoompiAuthorConfig"],"sources":["../../src/constants/settings.ts","../../src/types/apiRoutes.ts","../../src/services/settings/index.ts","../../src/services/settingsApi/index.ts","../../src/extensions/(backend)/api/settings/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server.ts","../../generated/server.ts"],"sourcesContent":["export const KEY_SEPARATOR = '.';\n\n/** The repeatable query parameter naming which keys a read is about. */\nexport const KEY_QUERY_PARAM = 'key';\n\nexport const SELECTION_KEYS = {\n majorMode: ['selection', 'majorMode'],\n domains: ['selection', 'domains'],\n profile: ['selection', 'profile'],\n} as const;\n","import { apiResponse, defineApiRoutes } from '@agimon-ai/doompi-core/web';\n\nimport { KEY_QUERY_PARAM } from '../constants/settings';\nimport type { RepositorySettingsView, SettingsConfigView, SettingsImagesView, SettingsRepository } from './settings';\n\n/**\n * This package's routes, as data.\n *\n * No scope and no base path. The build reads both off\n * `src/extensions/(backend)/api/settings/`, so the mount is stated once, by the\n * folder that creates it. `settings` is the host's own API: it answers at\n * `/api/settings` and `/api/workspaces/<id>/settings`, beside `/plugins` rather\n * than under it, and the client knows that from the base path alone.\n *\n * This is the one file the mount's dispatcher and, once the client crosses the\n * package boundary, the cockpit both read, so a path cannot move on one side\n * alone.\n */\nexport default defineApiRoutes({\n /** The mount itself: the selected keys and the hash of each file they came from. */\n config: {\n method: 'GET',\n path: '/',\n /** Repeatable. The page also sends `repoRoot`, which the mount ignores: it serves one repository. */\n query: [KEY_QUERY_PARAM],\n response: apiResponse<SettingsConfigView>(),\n },\n value: {\n method: 'PUT',\n path: '/value',\n response: apiResponse<SettingsConfigView>(),\n },\n repositories: {\n method: 'GET',\n path: '/repositories',\n response: apiResponse<{ repositories: readonly SettingsRepository[] }>(),\n },\n /** The workspace this mount was bound to; a global mount has none and answers 404. */\n repository: {\n method: 'GET',\n path: '/repository',\n response: apiResponse<RepositorySettingsView>(),\n },\n selection: {\n method: 'PUT',\n path: '/repository/selection',\n response: apiResponse<RepositorySettingsView>(),\n },\n /** Pi's own image limits, served by the global mount only. */\n images: {\n method: 'GET',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n /** The same path as `images`; the method is the whole of the difference. */\n saveImages: {\n method: 'PUT',\n path: '/images',\n response: apiResponse<SettingsImagesView>(),\n },\n});\n","import type { DoomApiContext } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_SEPARATOR, SELECTION_KEYS } from '../../constants/settings';\nimport type {\n RepositoryCatalogOption,\n RepositorySelectionChanges,\n RepositorySelectionWriteRequest,\n RepositorySettingsView,\n SettingsConfigView,\n SettingsRepository,\n SettingsScope,\n SettingsValueView,\n SettingsBatchWriteRequest,\n} from '../../types/settings';\nimport { globalDoomConfigPath, loadDoomConfigLayers, repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { defaultDomainsForMajorMode, loadDomains } from '../domains';\nimport { loadMajorModesConfig } from '../majorModes';\nimport { loadProfiles } from '../profiles';\n\ntype SelectionKey = keyof typeof SELECTION_KEYS;\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nexport function describe(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/** The display form of a config value; a record has no single-line form, so it has none. */\nexport function displayValue(value: unknown): string | undefined {\n if (typeof value === 'string') return value;\n if (typeof value === 'number' || typeof value === 'boolean') return String(value);\n if (Array.isArray(value)) return value.map((entry) => displayValue(entry) ?? '').join(', ');\n return undefined;\n}\n\nexport function pathFor(scope: SettingsScope, repoRoot: string, homeDirectory: string | undefined): string {\n return scope === 'repository' ? repositoryDoomConfigPath(repoRoot) : globalDoomConfigPath(homeDirectory);\n}\n\nexport function parseWrite(body: unknown): SettingsBatchWriteRequest | undefined {\n if (!isRecord(body)) return undefined;\n const { repoRoot, scope, expectedHash } = body;\n if (typeof repoRoot !== 'string' || (scope !== 'global' && scope !== 'repository')) return undefined;\n if (scope === 'repository' && repoRoot === '') return undefined;\n if (typeof expectedHash !== 'string') return undefined;\n const edits = body.edits === undefined ? [{ keyPath: body.keyPath, value: body.value }] : body.edits;\n if (!Array.isArray(edits) || edits.length === 0 || edits.length > 100) return undefined;\n const validated: Array<SettingsBatchWriteRequest['edits'][number]> = [];\n for (const edit of edits) {\n if (!isRecord(edit)) return undefined;\n const { keyPath, value } = edit;\n if (!Array.isArray(keyPath) || keyPath.length === 0 || keyPath.some((part) => typeof part !== 'string'))\n return undefined;\n if (value !== null && typeof value !== 'string' && (typeof value !== 'number' || !Number.isFinite(value)))\n return undefined;\n validated.push({ keyPath: keyPath as string[], value });\n }\n return { repoRoot, scope, expectedHash, edits: validated };\n}\n\nexport function configuredSelectionValue<T>(\n layers: ReturnType<typeof loadDoomConfigLayers>,\n key: SelectionKey,\n effective: T | undefined,\n): { effective?: T; repository?: T; origin: 'global' | 'repository' | 'default' } {\n const origin = layers.originOf(SELECTION_KEYS[key]);\n return {\n ...(effective === undefined ? {} : { effective }),\n ...(origin === 'repository' && effective !== undefined ? { repository: effective } : {}),\n origin,\n };\n}\n\nexport function repositorySettingsView(\n repository: SettingsRepository,\n homeDirectory: string | undefined,\n): RepositorySettingsView {\n const repoRoot = repository.path;\n const layers = loadDoomConfigLayers(repoRoot, homeDirectory);\n const modes = loadMajorModesConfig(repoRoot, homeDirectory);\n const domains = loadDomains(repoRoot, homeDirectory);\n const profiles = loadProfiles(repoRoot, homeDirectory);\n const configured = layers.effective.selection;\n const effectiveMajorMode = configured?.majorMode ?? modes.defaultMajorMode;\n const effectiveDomains =\n configured?.domains ?? defaultDomainsForMajorMode(effectiveMajorMode, {}, domains.defaultDomains);\n const majorModes: RepositoryCatalogOption[] = Object.entries(modes.majorMode)\n .map(([name, definition]) => ({ name, description: definition.description, layers: definition.layers }))\n .sort((left, right) => left.name.localeCompare(right.name));\n const domainOptions: RepositoryCatalogOption[] = [\n ...Object.entries(domains.domains).map(([name, definition]) => ({\n name,\n ...(definition.description ? { description: definition.description } : {}),\n })),\n ...Object.entries(domains.aliases).map(([name, expandsTo]) => ({\n name,\n description: `Alias for ${expandsTo.join(', ') || 'no domains'}.`,\n expandsTo,\n })),\n ].sort((left, right) => left.name.localeCompare(right.name));\n\n return {\n repository,\n hash: layers.repositoryFile.hash,\n catalogs: {\n majorModes,\n domains: domainOptions,\n profiles: profiles.map((profile) => ({ name: profile.name })),\n },\n selection: {\n majorMode: configuredSelectionValue(layers, 'majorMode', effectiveMajorMode),\n domains: configuredSelectionValue(layers, 'domains', effectiveDomains),\n profile: configuredSelectionValue(layers, 'profile', configured?.profile),\n },\n };\n}\n\nexport function parseSelectionChanges(value: unknown): RepositorySelectionChanges | undefined {\n if (!isRecord(value)) return undefined;\n const keys = Object.keys(value);\n if (keys.length === 0 || keys.some((key) => !Object.hasOwn(SELECTION_KEYS, key))) return undefined;\n const changes: RepositorySelectionChanges = {};\n if (Object.hasOwn(value, 'majorMode')) {\n if (value.majorMode !== null && (typeof value.majorMode !== 'string' || value.majorMode.trim() === ''))\n return undefined;\n changes.majorMode = value.majorMode === null ? null : value.majorMode.trim();\n }\n if (Object.hasOwn(value, 'domains')) {\n if (\n value.domains !== null &&\n (!Array.isArray(value.domains) || value.domains.some((name) => typeof name !== 'string' || name.trim() === ''))\n ) {\n return undefined;\n }\n changes.domains =\n value.domains === null ? null : [...new Set((value.domains as string[]).map((name) => name.trim()))];\n }\n if (Object.hasOwn(value, 'profile')) {\n if (value.profile !== null && (typeof value.profile !== 'string' || value.profile.trim() === '')) return undefined;\n changes.profile = value.profile === null ? null : value.profile.trim();\n }\n return changes;\n}\n\nexport function parseSelectionWrite(value: unknown): RepositorySelectionWriteRequest | undefined {\n if (!isRecord(value) || typeof value.repositoryId !== 'string' || typeof value.expectedHash !== 'string')\n return undefined;\n const changes = parseSelectionChanges(value.changes);\n return changes === undefined\n ? undefined\n : { repositoryId: value.repositoryId, expectedHash: value.expectedHash, changes };\n}\n\nexport function validateSelectionChanges(\n view: RepositorySettingsView,\n changes: RepositorySelectionChanges,\n): string | undefined {\n if (changes.majorMode !== undefined && changes.majorMode !== null) {\n if (!view.catalogs.majorModes.some((mode) => mode.name === changes.majorMode)) {\n return `Unknown major mode '${changes.majorMode}'.`;\n }\n }\n if (changes.domains !== undefined && changes.domains !== null) {\n const known = new Set(view.catalogs.domains.map((domain) => domain.name));\n const unknown = changes.domains.find((domain) => !known.has(domain));\n if (unknown !== undefined) return `Unknown domain '${unknown}'.`;\n }\n if (changes.profile !== undefined && changes.profile !== null) {\n if (!view.catalogs.profiles.some((profile) => profile.name === changes.profile)) {\n return `Unknown profile '${changes.profile}'.`;\n }\n }\n return undefined;\n}\n\nexport function selectionEdits(changes: RepositorySelectionChanges) {\n return (Object.entries(changes) as Array<[SelectionKey, string | readonly string[] | null]>).map(([key, value]) => ({\n keyPath: SELECTION_KEYS[key],\n ...(value === null ? {} : { value }),\n }));\n}\n\nexport function configView(context: DoomApiContext, keys: readonly string[]): SettingsConfigView {\n const root = context.scope === 'workspace' ? context.workspaceRoot : undefined;\n const layers = loadDoomConfigLayers(root, context.homeDirectory);\n const values: Record<string, SettingsValueView> = {};\n for (const key of keys) {\n const keyPath = key.split(KEY_SEPARATOR);\n const value = displayValue(layers.valueAt(keyPath));\n values[key] = {\n ...(value === undefined ? {} : { value }),\n origin: layers.originOf(keyPath),\n scope: configScopeOf(keyPath),\n };\n }\n return {\n repoRoot: root ?? '',\n values,\n hashes: { global: layers.globalFile.hash, repository: layers.repositoryFile.hash },\n };\n}\n","import type { DoomApi } from '@agimon-ai/doompi-core/packageApi';\n\nimport { KEY_QUERY_PARAM, KEY_SEPARATOR } from '../../constants/settings';\nimport routes from '../../types/apiRoutes';\nimport type { SettingsRepository } from '../../types/settings';\nimport { repositoryDoomConfigPath } from '../config';\nimport { configScopeOf } from '../configPolicy';\nimport { writeDoomConfigValues } from '../configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../settings';\n\n/** One declared route, as much of it as a comparison needs. */\ntype RouteSpec = { readonly method: string; readonly path: string };\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'settings',\n start(context) {\n if (context.scope === 'session') throw new Error('Configuration settings require a global or workspace mount.');\n const { homeDirectory } = context;\n const repository = (): SettingsRepository | undefined =>\n context.scope === 'workspace' && context.workspaceId && context.workspaceRoot\n ? {\n id: context.workspaceId,\n name: context.workspaceRoot.split('/').at(-1) ?? context.workspaceId,\n path: context.workspaceRoot,\n active: context.repositories?.().find((entry) => entry.id === context.workspaceId)?.active ?? false,\n }\n : undefined;\n const imageView = () => ({\n ...loadPiImageSettings(homeDirectory),\n minDimension: MIN_IMAGE_MAX_DIMENSION,\n maxAllowedDimension: DEFAULT_IMAGE_MAX_DIMENSION,\n });\n let writes: Promise<unknown> = Promise.resolve();\n let closed = false;\n const dispatch = async (request: Request): Promise<Response> => {\n if (closed) return Response.json({ error: 'Configuration mount is closed.' }, { status: 503 });\n const url = new URL(request.url);\n /**\n * Whether this request addresses one declared route.\n *\n * The table owns both halves of the comparison, so the path this mount\n * answers and the path the client asks for cannot drift apart: there is\n * one spelling of each, in `src/types/apiRoutes`.\n */\n const addresses = (route: RouteSpec): boolean => url.pathname === route.path && request.method === route.method;\n const currentRepository = repository();\n if (addresses(routes.config)) return Response.json(configView(context, url.searchParams.getAll(KEY_QUERY_PARAM)));\n if (addresses(routes.repositories)) return Response.json({ repositories: context.repositories?.() ?? [] });\n if (addresses(routes.repository)) {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n // One path, two methods, so the branch is on the path the pair share.\n if (url.pathname === routes.images.path && context.scope === 'global') {\n if (request.method === routes.images.method) return Response.json(imageView());\n if (request.method === routes.saveImages.method) {\n const body: unknown = await request.json();\n if (\n !isRecord(body) ||\n (body.autoResize !== undefined && typeof body.autoResize !== 'boolean') ||\n (body.maxDimension !== undefined &&\n (typeof body.maxDimension !== 'number' || !Number.isFinite(body.maxDimension)))\n )\n return Response.json({ error: 'Invalid image settings.' }, { status: 400 });\n savePiImageSettings(\n {\n ...(typeof body.autoResize === 'boolean' ? { autoResize: body.autoResize } : {}),\n ...(typeof body.maxDimension === 'number' ? { maxDimension: body.maxDimension } : {}),\n },\n homeDirectory,\n );\n context.configurationChanged?.();\n return Response.json(imageView());\n }\n }\n if (addresses(routes.selection)) {\n const body = parseSelectionWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A selection write needs typed changes and a file hash.' }, { status: 400 });\n if (!currentRepository || body.repositoryId !== currentRepository.id)\n return Response.json({ error: 'Workspace not found in this mount.' }, { status: 404 });\n const before = repositorySettingsView(currentRepository, homeDirectory);\n if (before.hash !== body.expectedHash)\n return Response.json(\n { error: 'The repository config changed since it was read.', hash: before.hash },\n { status: 409 },\n );\n const invalid = validateSelectionChanges(before, body.changes);\n if (invalid) return Response.json({ error: invalid }, { status: 422 });\n await writeDoomConfigValues(repositoryDoomConfigPath(currentRepository.path), selectionEdits(body.changes), {\n scope: 'repository',\n });\n context.configurationChanged?.();\n return Response.json(repositorySettingsView(currentRepository, homeDirectory));\n }\n if (addresses(routes.value)) {\n const body = parseWrite(await request.json());\n if (!body)\n return Response.json({ error: 'A save requires a scope, key, value and file hash.' }, { status: 400 });\n const scope = context.scope === 'global' ? 'global' : 'repository';\n if (body.scope !== scope || (scope === 'repository' && body.repoRoot !== currentRepository?.path))\n return Response.json({ error: 'The write targets a different mount.' }, { status: 403 });\n if (\n body.edits.some((edit) => {\n const allowed = configScopeOf(edit.keyPath);\n return allowed !== 'both' && allowed !== scope;\n })\n )\n return Response.json({ error: 'This key cannot be set at this scope.' }, { status: 409 });\n const before = configView(context, []);\n if (before.hashes[scope] !== body.expectedHash)\n return Response.json(\n { error: 'The config changed since it was read.', hash: before.hashes[scope] },\n { status: 409 },\n );\n const target = pathFor(scope, currentRepository?.path ?? '', homeDirectory);\n await writeDoomConfigValues(\n target,\n body.edits.map(({ keyPath, value }) => ({ keyPath, ...(value === null ? {} : { value }) })),\n { scope },\n );\n context.configurationChanged?.();\n return Response.json(\n configView(\n context,\n body.edits.map((edit) => edit.keyPath.join(KEY_SEPARATOR)),\n ),\n );\n }\n return Response.json({ error: 'Configuration route not found.' }, { status: 404 });\n };\n const guarded = async (request: Request): Promise<Response> => {\n try {\n return await dispatch(request);\n } catch (error) {\n return Response.json({ error: describe(error) }, { status: error instanceof SyntaxError ? 400 : 422 });\n }\n };\n return {\n fetch(request) {\n if (request.method === 'GET' || request.method === 'HEAD') return guarded(request);\n const result = writes.then(() => guarded(request));\n writes = result.catch(() => undefined);\n return result;\n },\n close() {\n closed = true;\n },\n };\n },\n};\n","import { defineRoutedContribution } from '@agimon-ai/doompi-core/extensionFile';\nimport type { DoomServerPluginContext } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { settingsApi } from '../../../../services/settingsApi';\n\nexport default defineRoutedContribution(\n ({ host }: DoomServerPluginContext) => (host.scope === 'session' ? undefined : settingsApi),\n { cardinality: 'optional' },\n);\n","import { defineResource } from '@agimon-ai/doompi-core/extensionFile';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/doompi-core/serverFacet';\n\nimport { CONFIG_HELP_SKILL } from '../../../../../constants/config';\n\nexport default defineResource({\n ...CONFIG_HELP_SKILL,\n when: { state: { 'minor-mode': 'help' }, attribution: { kind: 'minor' as const, mode: 'help' } },\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/doompi-author-config/SKILL.md'),\n});\n","// Generated by @agimon-ai/doompi-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/doompi-core/serverFacet';\n\nimport apiRoute from '../src/extensions/(backend)/api/settings/route.server';\nimport resourceDoompiAuthorConfig from '../src/extensions/workspaces/sessions/(backend)/resource/doompi-author-config.server';\n\ntype Factory<T, C> = (context: C) => T;\nconst at = <T, C>(value: T | Factory<T, C>, context: C): T =>\n typeof value === 'function' ? (value as Factory<T, C>)(context) : value;\n/* v8 ignore next -- generated normalization branch */\nconst defined = <T>(values: readonly (T | undefined)[]): T[] =>\n values.filter((value): value is T => value !== undefined);\n\nexport const facet = defineServerPlugin({\n name: '@agimon-ai/doompi-config',\n global: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n workspace: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n }),\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return defined([at(apiRoute, context)]); },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourceDoompiAuthorConfig, context)]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/doompi-config",
3
- "version": "0.0.1-alpha.91",
3
+ "version": "0.0.1-alpha.92",
4
4
  "description": "Typed configuration loading, validation, and host services for composing DoomPi sessions.",
5
5
  "keywords": [
6
6
  "agent-configuration",
@@ -144,18 +144,18 @@
144
144
  "registry": "https://registry.npmjs.org/"
145
145
  },
146
146
  "dependencies": {
147
- "@agimon-ai/doompi-core": "0.0.1-alpha.92",
148
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.83",
149
- "@agimon-ai/doompi-web-components": "0.0.1-alpha.50",
147
+ "@agimon-ai/doompi-core": "0.0.1-alpha.93",
148
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.84",
149
+ "@agimon-ai/doompi-web-components": "0.0.1-alpha.51",
150
150
  "@deepseek-ai/cordis": "4.0.2",
151
151
  "typebox": "1.3.34",
152
152
  "yaml": "2.9.1"
153
153
  },
154
154
  "devDependencies": {
155
- "@agimon-ai/doompi-build": "0.0.1-alpha.15",
155
+ "@agimon-ai/doompi-build": "0.0.1-alpha.16",
156
156
  "@earendil-works/pi-coding-agent": "0.87.1",
157
- "@modelcontextprotocol/ext-apps": "1.5.0",
158
- "@modelcontextprotocol/sdk": "1.30.0",
157
+ "@modelcontextprotocol/ext-apps": "2.0.0",
158
+ "@modelcontextprotocol/server": "2.1.0",
159
159
  "@playwright/test": "1.63.0",
160
160
  "@types/node": "26.6.1",
161
161
  "@types/react": "19.3.0",