@agimon-ai/doompi-config 0.0.1-alpha.70 → 0.0.1-alpha.71

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.
@@ -1,2 +1,2 @@
1
- const e=require("../services/configPolicy/index.cjs"),t=require("../services/config/index.cjs"),n=require("../services/configWriter/index.cjs"),r=require("../services/imageSettings/index.cjs"),i=require("../services/piConfig/index.cjs"),a=require("../services/settings/index.cjs"),o={basePath:`config`,start(o){if(o.scope===`session`)throw Error(`Configuration settings require a global or workspace mount.`);let{homeDirectory:s}=o,c=()=>o.scope===`workspace`&&o.workspaceId&&o.workspaceRoot?{id:o.workspaceId,name:o.workspaceRoot.split(`/`).at(-1)??o.workspaceId,path:o.workspaceRoot,active:o.repositories?.().find(e=>e.id===o.workspaceId)?.active??!1}:void 0,l=()=>({...i.loadPiImageSettings(s),minDimension:256,maxAllowedDimension:r.DEFAULT_IMAGE_MAX_DIMENSION}),u=Promise.resolve(),d=!1,f=async r=>{if(d)return Response.json({error:`Configuration mount is closed.`},{status:503});let u=new URL(r.url),f=c();if(u.pathname===`/config`&&r.method===`GET`)return Response.json(a.configView(o,u.searchParams.getAll(`key`)));if(u.pathname===`/repositories`&&r.method===`GET`)return Response.json({repositories:o.repositories?.()??[]});if(u.pathname===`/repository`&&r.method===`GET`)return f?Response.json(a.repositorySettingsView(f,s)):Response.json({error:`Choose a workspace.`},{status:404});if(u.pathname===`/images`&&o.scope===`global`){if(r.method===`GET`)return Response.json(l());if(r.method===`PUT`){let e=await r.json();return!a.isRecord(e)||e.autoResize!==void 0&&typeof e.autoResize!=`boolean`||e.maxDimension!==void 0&&(typeof e.maxDimension!=`number`||!Number.isFinite(e.maxDimension))?Response.json({error:`Invalid image settings.`},{status:400}):(i.savePiImageSettings({...typeof e.autoResize==`boolean`?{autoResize:e.autoResize}:{},...typeof e.maxDimension==`number`?{maxDimension:e.maxDimension}:{}},s),o.configurationChanged?.(),Response.json(l()))}}if(u.pathname===`/repository/selection`&&r.method===`PUT`){let e=a.parseSelectionWrite(await r.json());if(!e)return Response.json({error:`A selection write needs typed changes and a file hash.`},{status:400});if(!f||e.repositoryId!==f.id)return Response.json({error:`Workspace not found in this mount.`},{status:404});let i=a.repositorySettingsView(f,s);if(i.hash!==e.expectedHash)return Response.json({error:`The repository config changed since it was read.`,hash:i.hash},{status:409});let c=a.validateSelectionChanges(i,e.changes);return c?Response.json({error:c},{status:422}):(await n.writeDoomConfigValues(t.repositoryDoomConfigPath(f.path),a.selectionEdits(e.changes),{scope:`repository`}),o.configurationChanged?.(),Response.json(a.repositorySettingsView(f,s)))}if(u.pathname===`/value`&&r.method===`PUT`){let t=a.parseWrite(await r.json());if(!t)return Response.json({error:`A save requires a scope, key, value and file hash.`},{status:400});let i=o.scope===`global`?`global`:`repository`;if(t.scope!==i||i===`repository`&&t.repoRoot!==f?.path)return Response.json({error:`The write targets a different mount.`},{status:403});if(t.edits.some(t=>{let n=e.configScopeOf(t.keyPath);return n!==`both`&&n!==i}))return Response.json({error:`This key cannot be set at this scope.`},{status:409});let c=a.configView(o,[]);if(c.hashes[i]!==t.expectedHash)return Response.json({error:`The config changed since it was read.`,hash:c.hashes[i]},{status:409});let l=a.pathFor(i,f?.path??``,s);return await n.writeDoomConfigValues(l,t.edits.map(({keyPath:e,value:t})=>({keyPath:e,...t===null?{}:{value:t}})),{scope:i}),o.configurationChanged?.(),Response.json(a.configView(o,t.edits.map(e=>e.keyPath.join(`.`))))}return Response.json({error:`Configuration route not found.`},{status:404})},p=async e=>{try{return await f(e)}catch(e){return Response.json({error:a.describe(e)},{status:e instanceof SyntaxError?400:422})}};return{fetch(e){if(e.method===`GET`||e.method===`HEAD`)return p(e);let t=u.then(()=>p(e));return u=t.catch(()=>void 0),t},close(){d=!0}}}};exports.settingsApi=o;
1
+ const e=require("../services/configPolicy/index.cjs"),t=require("../services/config/index.cjs"),n=require("../services/configWriter/index.cjs"),r=require("../services/imageSettings/index.cjs"),i=require("../services/piConfig/index.cjs"),a=require("../services/settings/index.cjs"),o={basePath:`settings`,start(o){if(o.scope===`session`)throw Error(`Configuration settings require a global or workspace mount.`);let{homeDirectory:s}=o,c=()=>o.scope===`workspace`&&o.workspaceId&&o.workspaceRoot?{id:o.workspaceId,name:o.workspaceRoot.split(`/`).at(-1)??o.workspaceId,path:o.workspaceRoot,active:o.repositories?.().find(e=>e.id===o.workspaceId)?.active??!1}:void 0,l=()=>({...i.loadPiImageSettings(s),minDimension:256,maxAllowedDimension:r.DEFAULT_IMAGE_MAX_DIMENSION}),u=Promise.resolve(),d=!1,f=async r=>{if(d)return Response.json({error:`Configuration mount is closed.`},{status:503});let u=new URL(r.url),f=c();if(u.pathname===`/`&&r.method===`GET`)return Response.json(a.configView(o,u.searchParams.getAll(`key`)));if(u.pathname===`/repositories`&&r.method===`GET`)return Response.json({repositories:o.repositories?.()??[]});if(u.pathname===`/repository`&&r.method===`GET`)return f?Response.json(a.repositorySettingsView(f,s)):Response.json({error:`Choose a workspace.`},{status:404});if(u.pathname===`/images`&&o.scope===`global`){if(r.method===`GET`)return Response.json(l());if(r.method===`PUT`){let e=await r.json();return!a.isRecord(e)||e.autoResize!==void 0&&typeof e.autoResize!=`boolean`||e.maxDimension!==void 0&&(typeof e.maxDimension!=`number`||!Number.isFinite(e.maxDimension))?Response.json({error:`Invalid image settings.`},{status:400}):(i.savePiImageSettings({...typeof e.autoResize==`boolean`?{autoResize:e.autoResize}:{},...typeof e.maxDimension==`number`?{maxDimension:e.maxDimension}:{}},s),o.configurationChanged?.(),Response.json(l()))}}if(u.pathname===`/repository/selection`&&r.method===`PUT`){let e=a.parseSelectionWrite(await r.json());if(!e)return Response.json({error:`A selection write needs typed changes and a file hash.`},{status:400});if(!f||e.repositoryId!==f.id)return Response.json({error:`Workspace not found in this mount.`},{status:404});let i=a.repositorySettingsView(f,s);if(i.hash!==e.expectedHash)return Response.json({error:`The repository config changed since it was read.`,hash:i.hash},{status:409});let c=a.validateSelectionChanges(i,e.changes);return c?Response.json({error:c},{status:422}):(await n.writeDoomConfigValues(t.repositoryDoomConfigPath(f.path),a.selectionEdits(e.changes),{scope:`repository`}),o.configurationChanged?.(),Response.json(a.repositorySettingsView(f,s)))}if(u.pathname===`/value`&&r.method===`PUT`){let t=a.parseWrite(await r.json());if(!t)return Response.json({error:`A save requires a scope, key, value and file hash.`},{status:400});let i=o.scope===`global`?`global`:`repository`;if(t.scope!==i||i===`repository`&&t.repoRoot!==f?.path)return Response.json({error:`The write targets a different mount.`},{status:403});if(t.edits.some(t=>{let n=e.configScopeOf(t.keyPath);return n!==`both`&&n!==i}))return Response.json({error:`This key cannot be set at this scope.`},{status:409});let c=a.configView(o,[]);if(c.hashes[i]!==t.expectedHash)return Response.json({error:`The config changed since it was read.`,hash:c.hashes[i]},{status:409});let l=a.pathFor(i,f?.path??``,s);return await n.writeDoomConfigValues(l,t.edits.map(({keyPath:e,value:t})=>({keyPath:e,...t===null?{}:{value:t}})),{scope:i}),o.configurationChanged?.(),Response.json(a.configView(o,t.edits.map(e=>e.keyPath.join(`.`))))}return Response.json({error:`Configuration route not found.`},{status:404})},p=async e=>{try{return await f(e)}catch(e){return Response.json({error:a.describe(e)},{status:e instanceof SyntaxError?400:422})}};return{fetch(e){if(e.method===`GET`||e.method===`HEAD`)return p(e);let t=u.then(()=>p(e));return u=t.catch(()=>void 0),t},close(){d=!0}}}};exports.settingsApi=o;
2
2
  //# sourceMappingURL=settingsApi.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"settingsApi.cjs","names":["loadPiImageSettings","DEFAULT_IMAGE_MAX_DIMENSION","configView","repositorySettingsView","isRecord","parseSelectionWrite","validateSelectionChanges","writeDoomConfigValues","repositoryDoomConfigPath","selectionEdits","parseWrite","configScopeOf","pathFor","describe"],"sources":["../../src/controllers/settingsApi.ts"],"sourcesContent":["import type { DoomApi } from '@agimon-ai/doompi-core/package-api';\n\nimport { KEY_SEPARATOR } from '../constants/settings';\nimport { repositoryDoomConfigPath } from '../services/config';\nimport { configScopeOf } from '../services/configPolicy';\nimport { writeDoomConfigValues } from '../services/configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../services/imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../services/piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../services/settings';\nimport type { SettingsRepository } from '../types/settings';\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'config',\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 const currentRepository = repository();\n if (url.pathname === '/config' && request.method === 'GET')\n return Response.json(configView(context, url.searchParams.getAll('key')));\n if (url.pathname === '/repositories' && request.method === 'GET')\n return Response.json({ repositories: context.repositories?.() ?? [] });\n if (url.pathname === '/repository' && request.method === 'GET') {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n if (url.pathname === '/images' && context.scope === 'global') {\n if (request.method === 'GET') return Response.json(imageView());\n if (request.method === 'PUT') {\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 (url.pathname === '/repository/selection' && request.method === 'PUT') {\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 (url.pathname === '/value' && request.method === 'PUT') {\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"],"mappings":"yRAsBa,EAAuB,CAClC,SAAU,SACV,MAAM,EAAS,CACb,GAAI,EAAQ,QAAU,UAAW,MAAU,MAAM,6DAA6D,EAC9G,GAAM,CAAE,iBAAkB,EACpB,MACJ,EAAQ,QAAU,aAAe,EAAQ,aAAe,EAAQ,cAC5D,CACE,GAAI,EAAQ,YACZ,KAAM,EAAQ,cAAc,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,GAAK,EAAQ,YACzD,KAAM,EAAQ,cACd,OAAQ,EAAQ,eAAe,CAAC,CAAC,KAAM,GAAU,EAAM,KAAO,EAAQ,WAAW,CAAC,EAAE,QAAU,EAChG,EACA,IAAA,GACA,OAAmB,CACvB,GAAGA,EAAAA,oBAAoB,CAAa,EACpC,aAAA,IACA,oBAAqBC,EAAAA,2BACvB,GACI,EAA2B,QAAQ,QAAQ,EAC3C,EAAS,GACP,EAAW,KAAO,IAAwC,CAC9D,GAAI,EAAQ,OAAO,SAAS,KAAK,CAAE,MAAO,gCAAiC,EAAG,CAAE,OAAQ,GAAI,CAAC,EAC7F,IAAM,EAAM,IAAI,IAAI,EAAQ,GAAG,EACzB,EAAoB,EAAW,EACrC,GAAI,EAAI,WAAa,WAAa,EAAQ,SAAW,MACnD,OAAO,SAAS,KAAKC,EAAAA,WAAW,EAAS,EAAI,aAAa,OAAO,KAAK,CAAC,CAAC,EAC1E,GAAI,EAAI,WAAa,iBAAmB,EAAQ,SAAW,MACzD,OAAO,SAAS,KAAK,CAAE,aAAc,EAAQ,eAAe,GAAK,CAAC,CAAE,CAAC,EACvE,GAAI,EAAI,WAAa,eAAiB,EAAQ,SAAW,MACvD,OAAO,EACH,SAAS,KAAKC,EAAAA,uBAAuB,EAAmB,CAAa,CAAC,EACtE,SAAS,KAAK,CAAE,MAAO,qBAAsB,EAAG,CAAE,OAAQ,GAAI,CAAC,EAErE,GAAI,EAAI,WAAa,WAAa,EAAQ,QAAU,SAAU,CAC5D,GAAI,EAAQ,SAAW,MAAO,OAAO,SAAS,KAAK,EAAU,CAAC,EAC9D,GAAI,EAAQ,SAAW,MAAO,CAC5B,IAAM,EAAgB,MAAM,EAAQ,KAAK,EAgBzC,MAdE,CAACC,EAAAA,SAAS,CAAI,GACb,EAAK,aAAe,IAAA,IAAa,OAAO,EAAK,YAAe,WAC5D,EAAK,eAAiB,IAAA,KACpB,OAAO,EAAK,cAAiB,UAAY,CAAC,OAAO,SAAS,EAAK,YAAY,GAEvE,SAAS,KAAK,CAAE,MAAO,yBAA0B,EAAG,CAAE,OAAQ,GAAI,CAAC,GAC5E,EAAA,oBACE,CACE,GAAI,OAAO,EAAK,YAAe,UAAY,CAAE,WAAY,EAAK,UAAW,EAAI,CAAC,EAC9E,GAAI,OAAO,EAAK,cAAiB,SAAW,CAAE,aAAc,EAAK,YAAa,EAAI,CAAC,CACrF,EACA,CACF,EACA,EAAQ,uBAAuB,EACxB,SAAS,KAAK,EAAU,CAAC,EAClC,CACF,CACA,GAAI,EAAI,WAAa,yBAA2B,EAAQ,SAAW,MAAO,CACxE,IAAM,EAAOC,EAAAA,oBAAoB,MAAM,EAAQ,KAAK,CAAC,EACrD,GAAI,CAAC,EACH,OAAO,SAAS,KAAK,CAAE,MAAO,wDAAyD,EAAG,CAAE,OAAQ,GAAI,CAAC,EAC3G,GAAI,CAAC,GAAqB,EAAK,eAAiB,EAAkB,GAChE,OAAO,SAAS,KAAK,CAAE,MAAO,oCAAqC,EAAG,CAAE,OAAQ,GAAI,CAAC,EACvF,IAAM,EAASF,EAAAA,uBAAuB,EAAmB,CAAa,EACtE,GAAI,EAAO,OAAS,EAAK,aACvB,OAAO,SAAS,KACd,CAAE,MAAO,mDAAoD,KAAM,EAAO,IAAK,EAC/E,CAAE,OAAQ,GAAI,CAChB,EACF,IAAM,EAAUG,EAAAA,yBAAyB,EAAQ,EAAK,OAAO,EAM7D,OALI,EAAgB,SAAS,KAAK,CAAE,MAAO,CAAQ,EAAG,CAAE,OAAQ,GAAI,CAAC,GACrE,MAAMC,EAAAA,sBAAsBC,EAAAA,yBAAyB,EAAkB,IAAI,EAAGC,EAAAA,eAAe,EAAK,OAAO,EAAG,CAC1G,MAAO,YACT,CAAC,EACD,EAAQ,uBAAuB,EACxB,SAAS,KAAKN,EAAAA,uBAAuB,EAAmB,CAAa,CAAC,EAC/E,CACA,GAAI,EAAI,WAAa,UAAY,EAAQ,SAAW,MAAO,CACzD,IAAM,EAAOO,EAAAA,WAAW,MAAM,EAAQ,KAAK,CAAC,EAC5C,GAAI,CAAC,EACH,OAAO,SAAS,KAAK,CAAE,MAAO,oDAAqD,EAAG,CAAE,OAAQ,GAAI,CAAC,EACvG,IAAM,EAAQ,EAAQ,QAAU,SAAW,SAAW,aACtD,GAAI,EAAK,QAAU,GAAU,IAAU,cAAgB,EAAK,WAAa,GAAmB,KAC1F,OAAO,SAAS,KAAK,CAAE,MAAO,sCAAuC,EAAG,CAAE,OAAQ,GAAI,CAAC,EACzF,GACE,EAAK,MAAM,KAAM,GAAS,CACxB,IAAM,EAAUC,EAAAA,cAAc,EAAK,OAAO,EAC1C,OAAO,IAAY,QAAU,IAAY,CAC3C,CAAC,EAED,OAAO,SAAS,KAAK,CAAE,MAAO,uCAAwC,EAAG,CAAE,OAAQ,GAAI,CAAC,EAC1F,IAAM,EAAST,EAAAA,WAAW,EAAS,CAAC,CAAC,EACrC,GAAI,EAAO,OAAO,KAAW,EAAK,aAChC,OAAO,SAAS,KACd,CAAE,MAAO,wCAAyC,KAAM,EAAO,OAAO,EAAO,EAC7E,CAAE,OAAQ,GAAI,CAChB,EACF,IAAM,EAASU,EAAAA,QAAQ,EAAO,GAAmB,MAAQ,GAAI,CAAa,EAO1E,OANA,MAAML,EAAAA,sBACJ,EACA,EAAK,MAAM,KAAK,CAAE,UAAS,YAAa,CAAE,UAAS,GAAI,IAAU,KAAO,CAAC,EAAI,CAAE,OAAM,CAAG,EAAE,EAC1F,CAAE,OAAM,CACV,EACA,EAAQ,uBAAuB,EACxB,SAAS,KACdL,EAAAA,WACE,EACA,EAAK,MAAM,IAAK,GAAS,EAAK,QAAQ,KAAA,GAAkB,CAAC,CAC3D,CACF,CACF,CACA,OAAO,SAAS,KAAK,CAAE,MAAO,gCAAiC,EAAG,CAAE,OAAQ,GAAI,CAAC,CACnF,EACM,EAAU,KAAO,IAAwC,CAC7D,GAAI,CACF,OAAO,MAAM,EAAS,CAAO,CAC/B,OAAS,EAAO,CACd,OAAO,SAAS,KAAK,CAAE,MAAOW,EAAAA,SAAS,CAAK,CAAE,EAAG,CAAE,OAAQ,aAAiB,YAAc,IAAM,GAAI,CAAC,CACvG,CACF,EACA,MAAO,CACL,MAAM,EAAS,CACb,GAAI,EAAQ,SAAW,OAAS,EAAQ,SAAW,OAAQ,OAAO,EAAQ,CAAO,EACjF,IAAM,EAAS,EAAO,SAAW,EAAQ,CAAO,CAAC,EAEjD,MADA,GAAS,EAAO,UAAY,IAAA,EAAS,EAC9B,CACT,EACA,OAAQ,CACN,EAAS,EACX,CACF,CACF,CACF"}
1
+ {"version":3,"file":"settingsApi.cjs","names":["loadPiImageSettings","DEFAULT_IMAGE_MAX_DIMENSION","configView","repositorySettingsView","isRecord","parseSelectionWrite","validateSelectionChanges","writeDoomConfigValues","repositoryDoomConfigPath","selectionEdits","parseWrite","configScopeOf","pathFor","describe"],"sources":["../../src/controllers/settingsApi.ts"],"sourcesContent":["import type { DoomApi } from '@agimon-ai/doompi-core/package-api';\n\nimport { KEY_SEPARATOR } from '../constants/settings';\nimport { repositoryDoomConfigPath } from '../services/config';\nimport { configScopeOf } from '../services/configPolicy';\nimport { writeDoomConfigValues } from '../services/configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../services/imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../services/piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../services/settings';\nimport type { SettingsRepository } from '../types/settings';\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 const currentRepository = repository();\n if (url.pathname === '/' && request.method === 'GET')\n return Response.json(configView(context, url.searchParams.getAll('key')));\n if (url.pathname === '/repositories' && request.method === 'GET')\n return Response.json({ repositories: context.repositories?.() ?? [] });\n if (url.pathname === '/repository' && request.method === 'GET') {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n if (url.pathname === '/images' && context.scope === 'global') {\n if (request.method === 'GET') return Response.json(imageView());\n if (request.method === 'PUT') {\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 (url.pathname === '/repository/selection' && request.method === 'PUT') {\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 (url.pathname === '/value' && request.method === 'PUT') {\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"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{configScopeOf as e}from"../services/configPolicy/index.mjs";import{repositoryDoomConfigPath as t}from"../services/config/index.mjs";import{writeDoomConfigValues as n}from"../services/configWriter/index.mjs";import{DEFAULT_IMAGE_MAX_DIMENSION as r}from"../services/imageSettings/index.mjs";import{loadPiImageSettings as i,savePiImageSettings as a}from"../services/piConfig/index.mjs";import{configView as o,describe as s,isRecord as c,parseSelectionWrite as l,parseWrite as u,pathFor as d,repositorySettingsView as f,selectionEdits as p,validateSelectionChanges as m}from"../services/settings/index.mjs";const h={basePath:`config`,start(h){if(h.scope===`session`)throw Error(`Configuration settings require a global or workspace mount.`);let{homeDirectory:g}=h,_=()=>h.scope===`workspace`&&h.workspaceId&&h.workspaceRoot?{id:h.workspaceId,name:h.workspaceRoot.split(`/`).at(-1)??h.workspaceId,path:h.workspaceRoot,active:h.repositories?.().find(e=>e.id===h.workspaceId)?.active??!1}:void 0,v=()=>({...i(g),minDimension:256,maxAllowedDimension:r}),y=Promise.resolve(),b=!1,x=async r=>{if(b)return Response.json({error:`Configuration mount is closed.`},{status:503});let i=new URL(r.url),s=_();if(i.pathname===`/config`&&r.method===`GET`)return Response.json(o(h,i.searchParams.getAll(`key`)));if(i.pathname===`/repositories`&&r.method===`GET`)return Response.json({repositories:h.repositories?.()??[]});if(i.pathname===`/repository`&&r.method===`GET`)return s?Response.json(f(s,g)):Response.json({error:`Choose a workspace.`},{status:404});if(i.pathname===`/images`&&h.scope===`global`){if(r.method===`GET`)return Response.json(v());if(r.method===`PUT`){let e=await r.json();return!c(e)||e.autoResize!==void 0&&typeof e.autoResize!=`boolean`||e.maxDimension!==void 0&&(typeof e.maxDimension!=`number`||!Number.isFinite(e.maxDimension))?Response.json({error:`Invalid image settings.`},{status:400}):(a({...typeof e.autoResize==`boolean`?{autoResize:e.autoResize}:{},...typeof e.maxDimension==`number`?{maxDimension:e.maxDimension}:{}},g),h.configurationChanged?.(),Response.json(v()))}}if(i.pathname===`/repository/selection`&&r.method===`PUT`){let e=l(await r.json());if(!e)return Response.json({error:`A selection write needs typed changes and a file hash.`},{status:400});if(!s||e.repositoryId!==s.id)return Response.json({error:`Workspace not found in this mount.`},{status:404});let i=f(s,g);if(i.hash!==e.expectedHash)return Response.json({error:`The repository config changed since it was read.`,hash:i.hash},{status:409});let a=m(i,e.changes);return a?Response.json({error:a},{status:422}):(await n(t(s.path),p(e.changes),{scope:`repository`}),h.configurationChanged?.(),Response.json(f(s,g)))}if(i.pathname===`/value`&&r.method===`PUT`){let t=u(await r.json());if(!t)return Response.json({error:`A save requires a scope, key, value and file hash.`},{status:400});let i=h.scope===`global`?`global`:`repository`;if(t.scope!==i||i===`repository`&&t.repoRoot!==s?.path)return Response.json({error:`The write targets a different mount.`},{status:403});if(t.edits.some(t=>{let n=e(t.keyPath);return n!==`both`&&n!==i}))return Response.json({error:`This key cannot be set at this scope.`},{status:409});let a=o(h,[]);if(a.hashes[i]!==t.expectedHash)return Response.json({error:`The config changed since it was read.`,hash:a.hashes[i]},{status:409});let c=d(i,s?.path??``,g);return await n(c,t.edits.map(({keyPath:e,value:t})=>({keyPath:e,...t===null?{}:{value:t}})),{scope:i}),h.configurationChanged?.(),Response.json(o(h,t.edits.map(e=>e.keyPath.join(`.`))))}return Response.json({error:`Configuration route not found.`},{status:404})},S=async e=>{try{return await x(e)}catch(e){return Response.json({error:s(e)},{status:e instanceof SyntaxError?400:422})}};return{fetch(e){if(e.method===`GET`||e.method===`HEAD`)return S(e);let t=y.then(()=>S(e));return y=t.catch(()=>void 0),t},close(){b=!0}}}};export{h as settingsApi};
1
+ import{configScopeOf as e}from"../services/configPolicy/index.mjs";import{repositoryDoomConfigPath as t}from"../services/config/index.mjs";import{writeDoomConfigValues as n}from"../services/configWriter/index.mjs";import{DEFAULT_IMAGE_MAX_DIMENSION as r}from"../services/imageSettings/index.mjs";import{loadPiImageSettings as i,savePiImageSettings as a}from"../services/piConfig/index.mjs";import{configView as o,describe as s,isRecord as c,parseSelectionWrite as l,parseWrite as u,pathFor as d,repositorySettingsView as f,selectionEdits as p,validateSelectionChanges as m}from"../services/settings/index.mjs";const h={basePath:`settings`,start(h){if(h.scope===`session`)throw Error(`Configuration settings require a global or workspace mount.`);let{homeDirectory:g}=h,_=()=>h.scope===`workspace`&&h.workspaceId&&h.workspaceRoot?{id:h.workspaceId,name:h.workspaceRoot.split(`/`).at(-1)??h.workspaceId,path:h.workspaceRoot,active:h.repositories?.().find(e=>e.id===h.workspaceId)?.active??!1}:void 0,v=()=>({...i(g),minDimension:256,maxAllowedDimension:r}),y=Promise.resolve(),b=!1,x=async r=>{if(b)return Response.json({error:`Configuration mount is closed.`},{status:503});let i=new URL(r.url),s=_();if(i.pathname===`/`&&r.method===`GET`)return Response.json(o(h,i.searchParams.getAll(`key`)));if(i.pathname===`/repositories`&&r.method===`GET`)return Response.json({repositories:h.repositories?.()??[]});if(i.pathname===`/repository`&&r.method===`GET`)return s?Response.json(f(s,g)):Response.json({error:`Choose a workspace.`},{status:404});if(i.pathname===`/images`&&h.scope===`global`){if(r.method===`GET`)return Response.json(v());if(r.method===`PUT`){let e=await r.json();return!c(e)||e.autoResize!==void 0&&typeof e.autoResize!=`boolean`||e.maxDimension!==void 0&&(typeof e.maxDimension!=`number`||!Number.isFinite(e.maxDimension))?Response.json({error:`Invalid image settings.`},{status:400}):(a({...typeof e.autoResize==`boolean`?{autoResize:e.autoResize}:{},...typeof e.maxDimension==`number`?{maxDimension:e.maxDimension}:{}},g),h.configurationChanged?.(),Response.json(v()))}}if(i.pathname===`/repository/selection`&&r.method===`PUT`){let e=l(await r.json());if(!e)return Response.json({error:`A selection write needs typed changes and a file hash.`},{status:400});if(!s||e.repositoryId!==s.id)return Response.json({error:`Workspace not found in this mount.`},{status:404});let i=f(s,g);if(i.hash!==e.expectedHash)return Response.json({error:`The repository config changed since it was read.`,hash:i.hash},{status:409});let a=m(i,e.changes);return a?Response.json({error:a},{status:422}):(await n(t(s.path),p(e.changes),{scope:`repository`}),h.configurationChanged?.(),Response.json(f(s,g)))}if(i.pathname===`/value`&&r.method===`PUT`){let t=u(await r.json());if(!t)return Response.json({error:`A save requires a scope, key, value and file hash.`},{status:400});let i=h.scope===`global`?`global`:`repository`;if(t.scope!==i||i===`repository`&&t.repoRoot!==s?.path)return Response.json({error:`The write targets a different mount.`},{status:403});if(t.edits.some(t=>{let n=e(t.keyPath);return n!==`both`&&n!==i}))return Response.json({error:`This key cannot be set at this scope.`},{status:409});let a=o(h,[]);if(a.hashes[i]!==t.expectedHash)return Response.json({error:`The config changed since it was read.`,hash:a.hashes[i]},{status:409});let c=d(i,s?.path??``,g);return await n(c,t.edits.map(({keyPath:e,value:t})=>({keyPath:e,...t===null?{}:{value:t}})),{scope:i}),h.configurationChanged?.(),Response.json(o(h,t.edits.map(e=>e.keyPath.join(`.`))))}return Response.json({error:`Configuration route not found.`},{status:404})},S=async e=>{try{return await x(e)}catch(e){return Response.json({error:s(e)},{status:e instanceof SyntaxError?400:422})}};return{fetch(e){if(e.method===`GET`||e.method===`HEAD`)return S(e);let t=y.then(()=>S(e));return y=t.catch(()=>void 0),t},close(){b=!0}}}};export{h as settingsApi};
2
2
  //# sourceMappingURL=settingsApi.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"settingsApi.mjs","names":[],"sources":["../../src/controllers/settingsApi.ts"],"sourcesContent":["import type { DoomApi } from '@agimon-ai/doompi-core/package-api';\n\nimport { KEY_SEPARATOR } from '../constants/settings';\nimport { repositoryDoomConfigPath } from '../services/config';\nimport { configScopeOf } from '../services/configPolicy';\nimport { writeDoomConfigValues } from '../services/configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../services/imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../services/piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../services/settings';\nimport type { SettingsRepository } from '../types/settings';\n\n/** Config handlers are bound to their mount. Request paths cannot choose a different repository. */\nexport const settingsApi: DoomApi = {\n basePath: 'config',\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 const currentRepository = repository();\n if (url.pathname === '/config' && request.method === 'GET')\n return Response.json(configView(context, url.searchParams.getAll('key')));\n if (url.pathname === '/repositories' && request.method === 'GET')\n return Response.json({ repositories: context.repositories?.() ?? [] });\n if (url.pathname === '/repository' && request.method === 'GET') {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n if (url.pathname === '/images' && context.scope === 'global') {\n if (request.method === 'GET') return Response.json(imageView());\n if (request.method === 'PUT') {\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 (url.pathname === '/repository/selection' && request.method === 'PUT') {\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 (url.pathname === '/value' && request.method === 'PUT') {\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"],"mappings":"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"}
1
+ {"version":3,"file":"settingsApi.mjs","names":[],"sources":["../../src/controllers/settingsApi.ts"],"sourcesContent":["import type { DoomApi } from '@agimon-ai/doompi-core/package-api';\n\nimport { KEY_SEPARATOR } from '../constants/settings';\nimport { repositoryDoomConfigPath } from '../services/config';\nimport { configScopeOf } from '../services/configPolicy';\nimport { writeDoomConfigValues } from '../services/configWriter';\nimport { DEFAULT_IMAGE_MAX_DIMENSION, MIN_IMAGE_MAX_DIMENSION } from '../services/imageSettings';\nimport { loadPiImageSettings, savePiImageSettings } from '../services/piConfig';\nimport {\n configView,\n describe,\n isRecord,\n parseSelectionWrite,\n parseWrite,\n pathFor,\n repositorySettingsView,\n selectionEdits,\n validateSelectionChanges,\n} from '../services/settings';\nimport type { SettingsRepository } from '../types/settings';\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 const currentRepository = repository();\n if (url.pathname === '/' && request.method === 'GET')\n return Response.json(configView(context, url.searchParams.getAll('key')));\n if (url.pathname === '/repositories' && request.method === 'GET')\n return Response.json({ repositories: context.repositories?.() ?? [] });\n if (url.pathname === '/repository' && request.method === 'GET') {\n return currentRepository\n ? Response.json(repositorySettingsView(currentRepository, homeDirectory))\n : Response.json({ error: 'Choose a workspace.' }, { status: 404 });\n }\n if (url.pathname === '/images' && context.scope === 'global') {\n if (request.method === 'GET') return Response.json(imageView());\n if (request.method === 'PUT') {\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 (url.pathname === '/repository/selection' && request.method === 'PUT') {\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 (url.pathname === '/value' && request.method === 'PUT') {\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"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- let e=require("@agimon-ai/doompi-core/api-contracts"),t=require("typebox");const n=t.Type.String(),r=t.Type.Optional,i=t.Type.Array(n),a=t.Type.Union([n,t.Type.Null()]),o=t.Type.Union([t.Type.Literal(`global`),t.Type.Literal(`repository`)]),s=t.Type.Union([t.Type.Literal(`global`),t.Type.Literal(`repository`),t.Type.Literal(`default`)]),c=t.Type.Object({repoRoot:n,hashes:t.Type.Object({global:n,repository:n}),values:t.Type.Record(n,t.Type.Object({value:r(n),origin:s,scope:t.Type.Union([o,t.Type.Literal(`both`)])}))}),l=t.Type.Object({keyPath:i,value:t.Type.Union([n,t.Type.Number(),t.Type.Null()])}),u=t.Type.Union([t.Type.Object({repoRoot:n,scope:o,...l.properties,expectedHash:n}),t.Type.Object({repoRoot:n,scope:o,edits:t.Type.Array(l,{minItems:1,maxItems:100}),expectedHash:n})]),d=t.Type.Object({id:n,name:n,path:n,active:t.Type.Boolean()}),f=t.Type.Array(t.Type.Object({name:n,description:r(n),expandsTo:r(i),layers:r(i)})),p=t.Type.Object({effective:r(n),repository:r(n),origin:s}),m=t.Type.Object({effective:r(i),repository:r(i),origin:s}),h=t.Type.Object({repository:d,hash:n,catalogs:t.Type.Object({majorModes:f,domains:f,profiles:f}),selection:t.Type.Object({majorMode:p,domains:m,profile:p})}),g=t.Type.Object({repositoryId:n,expectedHash:n,changes:t.Type.Object({majorMode:r(a),domains:r(t.Type.Union([i,t.Type.Null()])),profile:r(a)})}),_=t.Type.Object({autoResize:t.Type.Boolean(),maxDimension:t.Type.Number(),minDimension:t.Type.Number(),maxAllowedDimension:t.Type.Number()}),v=[`global`,`workspace`].flatMap(n=>{let a={scope:n,basePath:`config`,authentication:`owner`};return[{...a,id:`config`,path:`/config`,method:`GET`,description:`Read selected settings keys and file hashes.`,parameters:[{name:`key`,in:`query`,required:!1,schema:i}],responses:(0,e.jsonApiResponses)(c)},{...a,id:`value`,path:`/value`,method:`PUT`,description:`Write a setting with an optimistic file hash.`,body:{contentType:`application/json`,required:!0,schema:u},responses:(0,e.jsonApiResponses)(c)},{...a,id:`repositories`,path:`/repositories`,method:`GET`,description:`List admitted repositories.`,responses:(0,e.jsonApiResponses)(t.Type.Object({repositories:t.Type.Array(d)}))},{...a,id:`repository`,path:`/repository`,method:`GET`,description:`Read the mounted workspace catalog and selection.`,availability:`Requires a workspace mount; global returns 404.`,responses:(0,e.jsonApiResponses)(h)},{...a,id:`selection`,path:`/repository/selection`,method:`PUT`,description:`Update the mounted workspace selection.`,availability:`Requires a workspace mount; global returns 404.`,body:{contentType:`application/json`,required:!0,schema:g},responses:(0,e.jsonApiResponses)(h)},...n===`global`?[{...a,id:`images.get`,path:`/images`,method:`GET`,description:`Read image resizing limits.`,responses:(0,e.jsonApiResponses)(_)},{...a,id:`images.put`,path:`/images`,method:`PUT`,description:`Update image resizing settings; dimensions are clamped.`,body:{contentType:`application/json`,required:!0,schema:t.Type.Object({autoResize:r(t.Type.Boolean()),maxDimension:r(t.Type.Number())})},responses:(0,e.jsonApiResponses)(_)}]:[]]}),y=(0,e.defineApiContract)({version:1,http:v,sockets:[],dynamic:[]});exports.RepositorySelectionWriteSchema=g,exports.RepositorySettingsSchema=h,exports.SettingsConfigSchema=c,exports.SettingsWriteSchema=u,exports.apiContracts=y,exports.default=y;
1
+ let e=require("@agimon-ai/doompi-core/api-contracts"),t=require("typebox");const n=t.Type.String(),r=t.Type.Optional,i=t.Type.Array(n),a=t.Type.Union([n,t.Type.Null()]),o=t.Type.Union([t.Type.Literal(`global`),t.Type.Literal(`repository`)]),s=t.Type.Union([t.Type.Literal(`global`),t.Type.Literal(`repository`),t.Type.Literal(`default`)]),c=t.Type.Object({repoRoot:n,hashes:t.Type.Object({global:n,repository:n}),values:t.Type.Record(n,t.Type.Object({value:r(n),origin:s,scope:t.Type.Union([o,t.Type.Literal(`both`)])}))}),l=t.Type.Object({keyPath:i,value:t.Type.Union([n,t.Type.Number(),t.Type.Null()])}),u=t.Type.Union([t.Type.Object({repoRoot:n,scope:o,...l.properties,expectedHash:n}),t.Type.Object({repoRoot:n,scope:o,edits:t.Type.Array(l,{minItems:1,maxItems:100}),expectedHash:n})]),d=t.Type.Object({id:n,name:n,path:n,active:t.Type.Boolean()}),f=t.Type.Array(t.Type.Object({name:n,description:r(n),expandsTo:r(i),layers:r(i)})),p=t.Type.Object({effective:r(n),repository:r(n),origin:s}),m=t.Type.Object({effective:r(i),repository:r(i),origin:s}),h=t.Type.Object({repository:d,hash:n,catalogs:t.Type.Object({majorModes:f,domains:f,profiles:f}),selection:t.Type.Object({majorMode:p,domains:m,profile:p})}),g=t.Type.Object({repositoryId:n,expectedHash:n,changes:t.Type.Object({majorMode:r(a),domains:r(t.Type.Union([i,t.Type.Null()])),profile:r(a)})}),_=t.Type.Object({autoResize:t.Type.Boolean(),maxDimension:t.Type.Number(),minDimension:t.Type.Number(),maxAllowedDimension:t.Type.Number()}),v=[`global`,`workspace`].flatMap(n=>{let a={scope:n,basePath:`settings`,authentication:`owner`};return[{...a,id:`config`,path:`/`,method:`GET`,description:`Read selected settings keys and file hashes.`,parameters:[{name:`key`,in:`query`,required:!1,schema:i}],responses:(0,e.jsonApiResponses)(c)},{...a,id:`value`,path:`/value`,method:`PUT`,description:`Write a setting with an optimistic file hash.`,body:{contentType:`application/json`,required:!0,schema:u},responses:(0,e.jsonApiResponses)(c)},{...a,id:`repositories`,path:`/repositories`,method:`GET`,description:`List admitted repositories.`,responses:(0,e.jsonApiResponses)(t.Type.Object({repositories:t.Type.Array(d)}))},{...a,id:`repository`,path:`/repository`,method:`GET`,description:`Read the mounted workspace catalog and selection.`,availability:`Requires a workspace mount; global returns 404.`,responses:(0,e.jsonApiResponses)(h)},{...a,id:`selection`,path:`/repository/selection`,method:`PUT`,description:`Update the mounted workspace selection.`,availability:`Requires a workspace mount; global returns 404.`,body:{contentType:`application/json`,required:!0,schema:g},responses:(0,e.jsonApiResponses)(h)},...n===`global`?[{...a,id:`images.get`,path:`/images`,method:`GET`,description:`Read image resizing limits.`,responses:(0,e.jsonApiResponses)(_)},{...a,id:`images.put`,path:`/images`,method:`PUT`,description:`Update image resizing settings; dimensions are clamped.`,body:{contentType:`application/json`,required:!0,schema:t.Type.Object({autoResize:r(t.Type.Boolean()),maxDimension:r(t.Type.Number())})},responses:(0,e.jsonApiResponses)(_)}]:[]]}),y=(0,e.defineApiContract)({version:1,http:v,sockets:[],dynamic:[]});exports.RepositorySelectionWriteSchema=g,exports.RepositorySettingsSchema=h,exports.SettingsConfigSchema=c,exports.SettingsWriteSchema=u,exports.apiContracts=y,exports.default=y;
2
2
  //# sourceMappingURL=apiContracts.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.cjs","names":["Type","jsonApiResponses","defineApiContract"],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\nconst Text = Type.String();\nconst Optional = Type.Optional;\nconst Strings = Type.Array(Text);\nconst NullableText = Type.Union([Text, Type.Null()]);\nconst Scope = Type.Union([Type.Literal('global'), Type.Literal('repository')]);\nconst Origin = Type.Union([Type.Literal('global'), Type.Literal('repository'), Type.Literal('default')]);\nexport const SettingsConfigSchema = Type.Object({\n repoRoot: Text,\n hashes: Type.Object({ global: Text, repository: Text }),\n values: Type.Record(\n Text,\n Type.Object({\n value: Optional(Text),\n origin: Origin,\n scope: Type.Union([Scope, Type.Literal('both')]),\n }),\n ),\n});\nconst SettingsEditSchema = Type.Object({ keyPath: Strings, value: Type.Union([Text, Type.Number(), Type.Null()]) });\nexport const SettingsWriteSchema = Type.Union([\n Type.Object({ repoRoot: Text, scope: Scope, ...SettingsEditSchema.properties, expectedHash: Text }),\n Type.Object({\n repoRoot: Text,\n scope: Scope,\n edits: Type.Array(SettingsEditSchema, { minItems: 1, maxItems: 100 }),\n expectedHash: Text,\n }),\n]);\n\nconst Repository = Type.Object({ id: Text, name: Text, path: Text, active: Type.Boolean() });\nconst Catalog = Type.Array(\n Type.Object({ name: Text, description: Optional(Text), expandsTo: Optional(Strings), layers: Optional(Strings) }),\n);\nconst SelectionText = Type.Object({ effective: Optional(Text), repository: Optional(Text), origin: Origin });\nconst SelectionStrings = Type.Object({ effective: Optional(Strings), repository: Optional(Strings), origin: Origin });\nexport const RepositorySettingsSchema = Type.Object({\n repository: Repository,\n hash: Text,\n catalogs: Type.Object({ majorModes: Catalog, domains: Catalog, profiles: Catalog }),\n selection: Type.Object({ majorMode: SelectionText, domains: SelectionStrings, profile: SelectionText }),\n});\nexport const RepositorySelectionWriteSchema = Type.Object({\n repositoryId: Text,\n expectedHash: Text,\n changes: Type.Object({\n majorMode: Optional(NullableText),\n domains: Optional(Type.Union([Strings, Type.Null()])),\n profile: Optional(NullableText),\n }),\n});\nconst Images = Type.Object({\n autoResize: Type.Boolean(),\n maxDimension: Type.Number(),\n minDimension: Type.Number(),\n maxAllowedDimension: Type.Number(),\n});\nconst http: DoomHttpContract[] = (['global', 'workspace'] as const).flatMap((scope) => {\n const common = { scope, basePath: 'config', authentication: 'owner' as const };\n return [\n {\n ...common,\n id: 'config',\n path: '/config',\n method: 'GET',\n description: 'Read selected settings keys and file hashes.',\n parameters: [{ name: 'key', in: 'query', required: false, schema: Strings }],\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'value',\n path: '/value',\n method: 'PUT',\n description: 'Write a setting with an optimistic file hash.',\n body: { contentType: 'application/json', required: true, schema: SettingsWriteSchema },\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'repositories',\n path: '/repositories',\n method: 'GET',\n description: 'List admitted repositories.',\n responses: jsonApiResponses(Type.Object({ repositories: Type.Array(Repository) })),\n },\n {\n ...common,\n id: 'repository',\n path: '/repository',\n method: 'GET',\n description: 'Read the mounted workspace catalog and selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n {\n ...common,\n id: 'selection',\n path: '/repository/selection',\n method: 'PUT',\n description: 'Update the mounted workspace selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n body: { contentType: 'application/json', required: true, schema: RepositorySelectionWriteSchema },\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n ...(scope === 'global'\n ? [\n {\n ...common,\n id: 'images.get',\n path: '/images',\n method: 'GET' as const,\n description: 'Read image resizing limits.',\n responses: jsonApiResponses(Images),\n },\n {\n ...common,\n id: 'images.put',\n path: '/images',\n method: 'PUT' as const,\n description: 'Update image resizing settings; dimensions are clamped.',\n body: {\n contentType: 'application/json',\n required: true,\n schema: Type.Object({ autoResize: Optional(Type.Boolean()), maxDimension: Optional(Type.Number()) }),\n },\n responses: jsonApiResponses(Images),\n },\n ]\n : []),\n ] satisfies DoomHttpContract[];\n});\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"2EAGA,MAAM,EAAOA,EAAAA,KAAK,OAAO,EACnB,EAAWA,EAAAA,KAAK,SAChB,EAAUA,EAAAA,KAAK,MAAM,CAAI,EACzB,EAAeA,EAAAA,KAAK,MAAM,CAAC,EAAMA,EAAAA,KAAK,KAAK,CAAC,CAAC,EAC7C,EAAQA,EAAAA,KAAK,MAAM,CAACA,EAAAA,KAAK,QAAQ,QAAQ,EAAGA,EAAAA,KAAK,QAAQ,YAAY,CAAC,CAAC,EACvE,EAASA,EAAAA,KAAK,MAAM,CAACA,EAAAA,KAAK,QAAQ,QAAQ,EAAGA,EAAAA,KAAK,QAAQ,YAAY,EAAGA,EAAAA,KAAK,QAAQ,SAAS,CAAC,CAAC,EAC1F,EAAuBA,EAAAA,KAAK,OAAO,CAC9C,SAAU,EACV,OAAQA,EAAAA,KAAK,OAAO,CAAE,OAAQ,EAAM,WAAY,CAAK,CAAC,EACtD,OAAQA,EAAAA,KAAK,OACX,EACAA,EAAAA,KAAK,OAAO,CACV,MAAO,EAAS,CAAI,EACpB,OAAQ,EACR,MAAOA,EAAAA,KAAK,MAAM,CAAC,EAAOA,EAAAA,KAAK,QAAQ,MAAM,CAAC,CAAC,CACjD,CAAC,CACH,CACF,CAAC,EACK,EAAqBA,EAAAA,KAAK,OAAO,CAAE,QAAS,EAAS,MAAOA,EAAAA,KAAK,MAAM,CAAC,EAAMA,EAAAA,KAAK,OAAO,EAAGA,EAAAA,KAAK,KAAK,CAAC,CAAC,CAAE,CAAC,EACrG,EAAsBA,EAAAA,KAAK,MAAM,CAC5CA,EAAAA,KAAK,OAAO,CAAE,SAAU,EAAM,MAAO,EAAO,GAAG,EAAmB,WAAY,aAAc,CAAK,CAAC,EAClGA,EAAAA,KAAK,OAAO,CACV,SAAU,EACV,MAAO,EACP,MAAOA,EAAAA,KAAK,MAAM,EAAoB,CAAE,SAAU,EAAG,SAAU,GAAI,CAAC,EACpE,aAAc,CAChB,CAAC,CACH,CAAC,EAEK,EAAaA,EAAAA,KAAK,OAAO,CAAE,GAAI,EAAM,KAAM,EAAM,KAAM,EAAM,OAAQA,EAAAA,KAAK,QAAQ,CAAE,CAAC,EACrF,EAAUA,EAAAA,KAAK,MACnBA,EAAAA,KAAK,OAAO,CAAE,KAAM,EAAM,YAAa,EAAS,CAAI,EAAG,UAAW,EAAS,CAAO,EAAG,OAAQ,EAAS,CAAO,CAAE,CAAC,CAClH,EACM,EAAgBA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAS,CAAI,EAAG,WAAY,EAAS,CAAI,EAAG,OAAQ,CAAO,CAAC,EACrG,EAAmBA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAS,CAAO,EAAG,WAAY,EAAS,CAAO,EAAG,OAAQ,CAAO,CAAC,EACvG,EAA2BA,EAAAA,KAAK,OAAO,CAClD,WAAY,EACZ,KAAM,EACN,SAAUA,EAAAA,KAAK,OAAO,CAAE,WAAY,EAAS,QAAS,EAAS,SAAU,CAAQ,CAAC,EAClF,UAAWA,EAAAA,KAAK,OAAO,CAAE,UAAW,EAAe,QAAS,EAAkB,QAAS,CAAc,CAAC,CACxG,CAAC,EACY,EAAiCA,EAAAA,KAAK,OAAO,CACxD,aAAc,EACd,aAAc,EACd,QAASA,EAAAA,KAAK,OAAO,CACnB,UAAW,EAAS,CAAY,EAChC,QAAS,EAASA,EAAAA,KAAK,MAAM,CAAC,EAASA,EAAAA,KAAK,KAAK,CAAC,CAAC,CAAC,EACpD,QAAS,EAAS,CAAY,CAChC,CAAC,CACH,CAAC,EACK,EAASA,EAAAA,KAAK,OAAO,CACzB,WAAYA,EAAAA,KAAK,QAAQ,EACzB,aAAcA,EAAAA,KAAK,OAAO,EAC1B,aAAcA,EAAAA,KAAK,OAAO,EAC1B,oBAAqBA,EAAAA,KAAK,OAAO,CACnC,CAAC,EACK,EAA4B,CAAC,SAAU,WAAW,CAAC,CAAW,QAAS,GAAU,CACrF,IAAM,EAAS,CAAE,QAAO,SAAU,SAAU,eAAgB,OAAiB,EAC7E,MAAO,CACL,CACE,GAAG,EACH,GAAI,SACJ,KAAM,UACN,OAAQ,MACR,YAAa,+CACb,WAAY,CAAC,CAAE,KAAM,MAAO,GAAI,QAAS,SAAU,GAAO,OAAQ,CAAQ,CAAC,EAC3E,WAAA,EAAWC,EAAAA,iBAAAA,CAAiB,CAAoB,CAClD,EACA,CACE,GAAG,EACH,GAAI,QACJ,KAAM,SACN,OAAQ,MACR,YAAa,gDACb,KAAM,CAAE,YAAa,mBAAoB,SAAU,GAAM,OAAQ,CAAoB,EACrF,WAAA,EAAWA,EAAAA,iBAAAA,CAAiB,CAAoB,CAClD,EACA,CACE,GAAG,EACH,GAAI,eACJ,KAAM,gBACN,OAAQ,MACR,YAAa,8BACb,WAAA,EAAWA,EAAAA,iBAAAA,CAAiBD,EAAAA,KAAK,OAAO,CAAE,aAAcA,EAAAA,KAAK,MAAM,CAAU,CAAE,CAAC,CAAC,CACnF,EACA,CACE,GAAG,EACH,GAAI,aACJ,KAAM,cACN,OAAQ,MACR,YAAa,oDACb,aAAc,kDACd,WAAA,EAAWC,EAAAA,iBAAAA,CAAiB,CAAwB,CACtD,EACA,CACE,GAAG,EACH,GAAI,YACJ,KAAM,wBACN,OAAQ,MACR,YAAa,0CACb,aAAc,kDACd,KAAM,CAAE,YAAa,mBAAoB,SAAU,GAAM,OAAQ,CAA+B,EAChG,WAAA,EAAWA,EAAAA,iBAAAA,CAAiB,CAAwB,CACtD,EACA,GAAI,IAAU,SACV,CACE,CACE,GAAG,EACH,GAAI,aACJ,KAAM,UACN,OAAQ,MACR,YAAa,8BACb,WAAA,EAAWA,EAAAA,iBAAAA,CAAiB,CAAM,CACpC,EACA,CACE,GAAG,EACH,GAAI,aACJ,KAAM,UACN,OAAQ,MACR,YAAa,0DACb,KAAM,CACJ,YAAa,mBACb,SAAU,GACV,OAAQD,EAAAA,KAAK,OAAO,CAAE,WAAY,EAASA,EAAAA,KAAK,QAAQ,CAAC,EAAG,aAAc,EAASA,EAAAA,KAAK,OAAO,CAAC,CAAE,CAAC,CACrG,EACA,WAAA,EAAWC,EAAAA,iBAAAA,CAAiB,CAAM,CACpC,CACF,EACA,CAAC,CACP,CACF,CAAC,EACY,GAAA,EAAeC,EAAAA,kBAAAA,CAAkB,CAAE,QAAS,EAAG,OAAM,QAAS,CAAC,EAAG,QAAS,CAAC,CAAE,CAAC"}
1
+ {"version":3,"file":"apiContracts.cjs","names":["Type","jsonApiResponses","defineApiContract"],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\nconst Text = Type.String();\nconst Optional = Type.Optional;\nconst Strings = Type.Array(Text);\nconst NullableText = Type.Union([Text, Type.Null()]);\nconst Scope = Type.Union([Type.Literal('global'), Type.Literal('repository')]);\nconst Origin = Type.Union([Type.Literal('global'), Type.Literal('repository'), Type.Literal('default')]);\nexport const SettingsConfigSchema = Type.Object({\n repoRoot: Text,\n hashes: Type.Object({ global: Text, repository: Text }),\n values: Type.Record(\n Text,\n Type.Object({\n value: Optional(Text),\n origin: Origin,\n scope: Type.Union([Scope, Type.Literal('both')]),\n }),\n ),\n});\nconst SettingsEditSchema = Type.Object({ keyPath: Strings, value: Type.Union([Text, Type.Number(), Type.Null()]) });\nexport const SettingsWriteSchema = Type.Union([\n Type.Object({ repoRoot: Text, scope: Scope, ...SettingsEditSchema.properties, expectedHash: Text }),\n Type.Object({\n repoRoot: Text,\n scope: Scope,\n edits: Type.Array(SettingsEditSchema, { minItems: 1, maxItems: 100 }),\n expectedHash: Text,\n }),\n]);\n\nconst Repository = Type.Object({ id: Text, name: Text, path: Text, active: Type.Boolean() });\nconst Catalog = Type.Array(\n Type.Object({ name: Text, description: Optional(Text), expandsTo: Optional(Strings), layers: Optional(Strings) }),\n);\nconst SelectionText = Type.Object({ effective: Optional(Text), repository: Optional(Text), origin: Origin });\nconst SelectionStrings = Type.Object({ effective: Optional(Strings), repository: Optional(Strings), origin: Origin });\nexport const RepositorySettingsSchema = Type.Object({\n repository: Repository,\n hash: Text,\n catalogs: Type.Object({ majorModes: Catalog, domains: Catalog, profiles: Catalog }),\n selection: Type.Object({ majorMode: SelectionText, domains: SelectionStrings, profile: SelectionText }),\n});\nexport const RepositorySelectionWriteSchema = Type.Object({\n repositoryId: Text,\n expectedHash: Text,\n changes: Type.Object({\n majorMode: Optional(NullableText),\n domains: Optional(Type.Union([Strings, Type.Null()])),\n profile: Optional(NullableText),\n }),\n});\nconst Images = Type.Object({\n autoResize: Type.Boolean(),\n maxDimension: Type.Number(),\n minDimension: Type.Number(),\n maxAllowedDimension: Type.Number(),\n});\nconst http: DoomHttpContract[] = (['global', 'workspace'] as const).flatMap((scope) => {\n const common = { scope, basePath: 'settings', authentication: 'owner' as const };\n return [\n {\n ...common,\n id: 'config',\n path: '/',\n method: 'GET',\n description: 'Read selected settings keys and file hashes.',\n parameters: [{ name: 'key', in: 'query', required: false, schema: Strings }],\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'value',\n path: '/value',\n method: 'PUT',\n description: 'Write a setting with an optimistic file hash.',\n body: { contentType: 'application/json', required: true, schema: SettingsWriteSchema },\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'repositories',\n path: '/repositories',\n method: 'GET',\n description: 'List admitted repositories.',\n responses: jsonApiResponses(Type.Object({ repositories: Type.Array(Repository) })),\n },\n {\n ...common,\n id: 'repository',\n path: '/repository',\n method: 'GET',\n description: 'Read the mounted workspace catalog and selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n {\n ...common,\n id: 'selection',\n path: '/repository/selection',\n method: 'PUT',\n description: 'Update the mounted workspace selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n body: { contentType: 'application/json', required: true, schema: RepositorySelectionWriteSchema },\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n ...(scope === 'global'\n ? [\n {\n ...common,\n id: 'images.get',\n path: '/images',\n method: 'GET' as const,\n description: 'Read image resizing limits.',\n responses: jsonApiResponses(Images),\n },\n {\n ...common,\n id: 'images.put',\n path: '/images',\n method: 'PUT' as const,\n description: 'Update image resizing settings; dimensions are clamped.',\n body: {\n contentType: 'application/json',\n required: true,\n schema: Type.Object({ autoResize: Optional(Type.Boolean()), maxDimension: Optional(Type.Number()) }),\n },\n responses: jsonApiResponses(Images),\n },\n ]\n : []),\n ] satisfies DoomHttpContract[];\n});\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{defineApiContract as e,jsonApiResponses as t}from"@agimon-ai/doompi-core/api-contracts";import{Type as n}from"typebox";const r=n.String(),i=n.Optional,a=n.Array(r),o=n.Union([r,n.Null()]),s=n.Union([n.Literal(`global`),n.Literal(`repository`)]),c=n.Union([n.Literal(`global`),n.Literal(`repository`),n.Literal(`default`)]),l=n.Object({repoRoot:r,hashes:n.Object({global:r,repository:r}),values:n.Record(r,n.Object({value:i(r),origin:c,scope:n.Union([s,n.Literal(`both`)])}))}),u=n.Object({keyPath:a,value:n.Union([r,n.Number(),n.Null()])}),d=n.Union([n.Object({repoRoot:r,scope:s,...u.properties,expectedHash:r}),n.Object({repoRoot:r,scope:s,edits:n.Array(u,{minItems:1,maxItems:100}),expectedHash:r})]),f=n.Object({id:r,name:r,path:r,active:n.Boolean()}),p=n.Array(n.Object({name:r,description:i(r),expandsTo:i(a),layers:i(a)})),m=n.Object({effective:i(r),repository:i(r),origin:c}),h=n.Object({effective:i(a),repository:i(a),origin:c}),g=n.Object({repository:f,hash:r,catalogs:n.Object({majorModes:p,domains:p,profiles:p}),selection:n.Object({majorMode:m,domains:h,profile:m})}),_=n.Object({repositoryId:r,expectedHash:r,changes:n.Object({majorMode:i(o),domains:i(n.Union([a,n.Null()])),profile:i(o)})}),v=n.Object({autoResize:n.Boolean(),maxDimension:n.Number(),minDimension:n.Number(),maxAllowedDimension:n.Number()}),y=[`global`,`workspace`].flatMap(e=>{let r={scope:e,basePath:`config`,authentication:`owner`};return[{...r,id:`config`,path:`/config`,method:`GET`,description:`Read selected settings keys and file hashes.`,parameters:[{name:`key`,in:`query`,required:!1,schema:a}],responses:t(l)},{...r,id:`value`,path:`/value`,method:`PUT`,description:`Write a setting with an optimistic file hash.`,body:{contentType:`application/json`,required:!0,schema:d},responses:t(l)},{...r,id:`repositories`,path:`/repositories`,method:`GET`,description:`List admitted repositories.`,responses:t(n.Object({repositories:n.Array(f)}))},{...r,id:`repository`,path:`/repository`,method:`GET`,description:`Read the mounted workspace catalog and selection.`,availability:`Requires a workspace mount; global returns 404.`,responses:t(g)},{...r,id:`selection`,path:`/repository/selection`,method:`PUT`,description:`Update the mounted workspace selection.`,availability:`Requires a workspace mount; global returns 404.`,body:{contentType:`application/json`,required:!0,schema:_},responses:t(g)},...e===`global`?[{...r,id:`images.get`,path:`/images`,method:`GET`,description:`Read image resizing limits.`,responses:t(v)},{...r,id:`images.put`,path:`/images`,method:`PUT`,description:`Update image resizing settings; dimensions are clamped.`,body:{contentType:`application/json`,required:!0,schema:n.Object({autoResize:i(n.Boolean()),maxDimension:i(n.Number())})},responses:t(v)}]:[]]}),b=e({version:1,http:y,sockets:[],dynamic:[]});export{_ as RepositorySelectionWriteSchema,g as RepositorySettingsSchema,l as SettingsConfigSchema,d as SettingsWriteSchema,b as apiContracts,b as default};
1
+ import{defineApiContract as e,jsonApiResponses as t}from"@agimon-ai/doompi-core/api-contracts";import{Type as n}from"typebox";const r=n.String(),i=n.Optional,a=n.Array(r),o=n.Union([r,n.Null()]),s=n.Union([n.Literal(`global`),n.Literal(`repository`)]),c=n.Union([n.Literal(`global`),n.Literal(`repository`),n.Literal(`default`)]),l=n.Object({repoRoot:r,hashes:n.Object({global:r,repository:r}),values:n.Record(r,n.Object({value:i(r),origin:c,scope:n.Union([s,n.Literal(`both`)])}))}),u=n.Object({keyPath:a,value:n.Union([r,n.Number(),n.Null()])}),d=n.Union([n.Object({repoRoot:r,scope:s,...u.properties,expectedHash:r}),n.Object({repoRoot:r,scope:s,edits:n.Array(u,{minItems:1,maxItems:100}),expectedHash:r})]),f=n.Object({id:r,name:r,path:r,active:n.Boolean()}),p=n.Array(n.Object({name:r,description:i(r),expandsTo:i(a),layers:i(a)})),m=n.Object({effective:i(r),repository:i(r),origin:c}),h=n.Object({effective:i(a),repository:i(a),origin:c}),g=n.Object({repository:f,hash:r,catalogs:n.Object({majorModes:p,domains:p,profiles:p}),selection:n.Object({majorMode:m,domains:h,profile:m})}),_=n.Object({repositoryId:r,expectedHash:r,changes:n.Object({majorMode:i(o),domains:i(n.Union([a,n.Null()])),profile:i(o)})}),v=n.Object({autoResize:n.Boolean(),maxDimension:n.Number(),minDimension:n.Number(),maxAllowedDimension:n.Number()}),y=[`global`,`workspace`].flatMap(e=>{let r={scope:e,basePath:`settings`,authentication:`owner`};return[{...r,id:`config`,path:`/`,method:`GET`,description:`Read selected settings keys and file hashes.`,parameters:[{name:`key`,in:`query`,required:!1,schema:a}],responses:t(l)},{...r,id:`value`,path:`/value`,method:`PUT`,description:`Write a setting with an optimistic file hash.`,body:{contentType:`application/json`,required:!0,schema:d},responses:t(l)},{...r,id:`repositories`,path:`/repositories`,method:`GET`,description:`List admitted repositories.`,responses:t(n.Object({repositories:n.Array(f)}))},{...r,id:`repository`,path:`/repository`,method:`GET`,description:`Read the mounted workspace catalog and selection.`,availability:`Requires a workspace mount; global returns 404.`,responses:t(g)},{...r,id:`selection`,path:`/repository/selection`,method:`PUT`,description:`Update the mounted workspace selection.`,availability:`Requires a workspace mount; global returns 404.`,body:{contentType:`application/json`,required:!0,schema:_},responses:t(g)},...e===`global`?[{...r,id:`images.get`,path:`/images`,method:`GET`,description:`Read image resizing limits.`,responses:t(v)},{...r,id:`images.put`,path:`/images`,method:`PUT`,description:`Update image resizing settings; dimensions are clamped.`,body:{contentType:`application/json`,required:!0,schema:n.Object({autoResize:i(n.Boolean()),maxDimension:i(n.Number())})},responses:t(v)}]:[]]}),b=e({version:1,http:y,sockets:[],dynamic:[]});export{_ as RepositorySelectionWriteSchema,g as RepositorySettingsSchema,l as SettingsConfigSchema,d as SettingsWriteSchema,b as apiContracts,b as default};
2
2
  //# sourceMappingURL=apiContracts.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\nconst Text = Type.String();\nconst Optional = Type.Optional;\nconst Strings = Type.Array(Text);\nconst NullableText = Type.Union([Text, Type.Null()]);\nconst Scope = Type.Union([Type.Literal('global'), Type.Literal('repository')]);\nconst Origin = Type.Union([Type.Literal('global'), Type.Literal('repository'), Type.Literal('default')]);\nexport const SettingsConfigSchema = Type.Object({\n repoRoot: Text,\n hashes: Type.Object({ global: Text, repository: Text }),\n values: Type.Record(\n Text,\n Type.Object({\n value: Optional(Text),\n origin: Origin,\n scope: Type.Union([Scope, Type.Literal('both')]),\n }),\n ),\n});\nconst SettingsEditSchema = Type.Object({ keyPath: Strings, value: Type.Union([Text, Type.Number(), Type.Null()]) });\nexport const SettingsWriteSchema = Type.Union([\n Type.Object({ repoRoot: Text, scope: Scope, ...SettingsEditSchema.properties, expectedHash: Text }),\n Type.Object({\n repoRoot: Text,\n scope: Scope,\n edits: Type.Array(SettingsEditSchema, { minItems: 1, maxItems: 100 }),\n expectedHash: Text,\n }),\n]);\n\nconst Repository = Type.Object({ id: Text, name: Text, path: Text, active: Type.Boolean() });\nconst Catalog = Type.Array(\n Type.Object({ name: Text, description: Optional(Text), expandsTo: Optional(Strings), layers: Optional(Strings) }),\n);\nconst SelectionText = Type.Object({ effective: Optional(Text), repository: Optional(Text), origin: Origin });\nconst SelectionStrings = Type.Object({ effective: Optional(Strings), repository: Optional(Strings), origin: Origin });\nexport const RepositorySettingsSchema = Type.Object({\n repository: Repository,\n hash: Text,\n catalogs: Type.Object({ majorModes: Catalog, domains: Catalog, profiles: Catalog }),\n selection: Type.Object({ majorMode: SelectionText, domains: SelectionStrings, profile: SelectionText }),\n});\nexport const RepositorySelectionWriteSchema = Type.Object({\n repositoryId: Text,\n expectedHash: Text,\n changes: Type.Object({\n majorMode: Optional(NullableText),\n domains: Optional(Type.Union([Strings, Type.Null()])),\n profile: Optional(NullableText),\n }),\n});\nconst Images = Type.Object({\n autoResize: Type.Boolean(),\n maxDimension: Type.Number(),\n minDimension: Type.Number(),\n maxAllowedDimension: Type.Number(),\n});\nconst http: DoomHttpContract[] = (['global', 'workspace'] as const).flatMap((scope) => {\n const common = { scope, basePath: 'config', authentication: 'owner' as const };\n return [\n {\n ...common,\n id: 'config',\n path: '/config',\n method: 'GET',\n description: 'Read selected settings keys and file hashes.',\n parameters: [{ name: 'key', in: 'query', required: false, schema: Strings }],\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'value',\n path: '/value',\n method: 'PUT',\n description: 'Write a setting with an optimistic file hash.',\n body: { contentType: 'application/json', required: true, schema: SettingsWriteSchema },\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'repositories',\n path: '/repositories',\n method: 'GET',\n description: 'List admitted repositories.',\n responses: jsonApiResponses(Type.Object({ repositories: Type.Array(Repository) })),\n },\n {\n ...common,\n id: 'repository',\n path: '/repository',\n method: 'GET',\n description: 'Read the mounted workspace catalog and selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n {\n ...common,\n id: 'selection',\n path: '/repository/selection',\n method: 'PUT',\n description: 'Update the mounted workspace selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n body: { contentType: 'application/json', required: true, schema: RepositorySelectionWriteSchema },\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n ...(scope === 'global'\n ? [\n {\n ...common,\n id: 'images.get',\n path: '/images',\n method: 'GET' as const,\n description: 'Read image resizing limits.',\n responses: jsonApiResponses(Images),\n },\n {\n ...common,\n id: 'images.put',\n path: '/images',\n method: 'PUT' as const,\n description: 'Update image resizing settings; dimensions are clamped.',\n body: {\n contentType: 'application/json',\n required: true,\n schema: Type.Object({ autoResize: Optional(Type.Boolean()), maxDimension: Optional(Type.Number()) }),\n },\n responses: jsonApiResponses(Images),\n },\n ]\n : []),\n ] satisfies DoomHttpContract[];\n});\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\n"],"mappings":"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"}
1
+ {"version":3,"file":"apiContracts.mjs","names":[],"sources":["../../src/schemas/apiContracts.ts"],"sourcesContent":["import { defineApiContract, jsonApiResponses, type DoomHttpContract } from '@agimon-ai/doompi-core/api-contracts';\nimport { Type } from 'typebox';\n\nconst Text = Type.String();\nconst Optional = Type.Optional;\nconst Strings = Type.Array(Text);\nconst NullableText = Type.Union([Text, Type.Null()]);\nconst Scope = Type.Union([Type.Literal('global'), Type.Literal('repository')]);\nconst Origin = Type.Union([Type.Literal('global'), Type.Literal('repository'), Type.Literal('default')]);\nexport const SettingsConfigSchema = Type.Object({\n repoRoot: Text,\n hashes: Type.Object({ global: Text, repository: Text }),\n values: Type.Record(\n Text,\n Type.Object({\n value: Optional(Text),\n origin: Origin,\n scope: Type.Union([Scope, Type.Literal('both')]),\n }),\n ),\n});\nconst SettingsEditSchema = Type.Object({ keyPath: Strings, value: Type.Union([Text, Type.Number(), Type.Null()]) });\nexport const SettingsWriteSchema = Type.Union([\n Type.Object({ repoRoot: Text, scope: Scope, ...SettingsEditSchema.properties, expectedHash: Text }),\n Type.Object({\n repoRoot: Text,\n scope: Scope,\n edits: Type.Array(SettingsEditSchema, { minItems: 1, maxItems: 100 }),\n expectedHash: Text,\n }),\n]);\n\nconst Repository = Type.Object({ id: Text, name: Text, path: Text, active: Type.Boolean() });\nconst Catalog = Type.Array(\n Type.Object({ name: Text, description: Optional(Text), expandsTo: Optional(Strings), layers: Optional(Strings) }),\n);\nconst SelectionText = Type.Object({ effective: Optional(Text), repository: Optional(Text), origin: Origin });\nconst SelectionStrings = Type.Object({ effective: Optional(Strings), repository: Optional(Strings), origin: Origin });\nexport const RepositorySettingsSchema = Type.Object({\n repository: Repository,\n hash: Text,\n catalogs: Type.Object({ majorModes: Catalog, domains: Catalog, profiles: Catalog }),\n selection: Type.Object({ majorMode: SelectionText, domains: SelectionStrings, profile: SelectionText }),\n});\nexport const RepositorySelectionWriteSchema = Type.Object({\n repositoryId: Text,\n expectedHash: Text,\n changes: Type.Object({\n majorMode: Optional(NullableText),\n domains: Optional(Type.Union([Strings, Type.Null()])),\n profile: Optional(NullableText),\n }),\n});\nconst Images = Type.Object({\n autoResize: Type.Boolean(),\n maxDimension: Type.Number(),\n minDimension: Type.Number(),\n maxAllowedDimension: Type.Number(),\n});\nconst http: DoomHttpContract[] = (['global', 'workspace'] as const).flatMap((scope) => {\n const common = { scope, basePath: 'settings', authentication: 'owner' as const };\n return [\n {\n ...common,\n id: 'config',\n path: '/',\n method: 'GET',\n description: 'Read selected settings keys and file hashes.',\n parameters: [{ name: 'key', in: 'query', required: false, schema: Strings }],\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'value',\n path: '/value',\n method: 'PUT',\n description: 'Write a setting with an optimistic file hash.',\n body: { contentType: 'application/json', required: true, schema: SettingsWriteSchema },\n responses: jsonApiResponses(SettingsConfigSchema),\n },\n {\n ...common,\n id: 'repositories',\n path: '/repositories',\n method: 'GET',\n description: 'List admitted repositories.',\n responses: jsonApiResponses(Type.Object({ repositories: Type.Array(Repository) })),\n },\n {\n ...common,\n id: 'repository',\n path: '/repository',\n method: 'GET',\n description: 'Read the mounted workspace catalog and selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n {\n ...common,\n id: 'selection',\n path: '/repository/selection',\n method: 'PUT',\n description: 'Update the mounted workspace selection.',\n availability: 'Requires a workspace mount; global returns 404.',\n body: { contentType: 'application/json', required: true, schema: RepositorySelectionWriteSchema },\n responses: jsonApiResponses(RepositorySettingsSchema),\n },\n ...(scope === 'global'\n ? [\n {\n ...common,\n id: 'images.get',\n path: '/images',\n method: 'GET' as const,\n description: 'Read image resizing limits.',\n responses: jsonApiResponses(Images),\n },\n {\n ...common,\n id: 'images.put',\n path: '/images',\n method: 'PUT' as const,\n description: 'Update image resizing settings; dimensions are clamped.',\n body: {\n contentType: 'application/json',\n required: true,\n schema: Type.Object({ autoResize: Optional(Type.Boolean()), maxDimension: Optional(Type.Number()) }),\n },\n responses: jsonApiResponses(Images),\n },\n ]\n : []),\n ] satisfies DoomHttpContract[];\n});\nexport const apiContracts = defineApiContract({ version: 1, http, sockets: [], dynamic: [] });\nexport default apiContracts;\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.70",
3
+ "version": "0.0.1-alpha.71",
4
4
  "description": "Typed configuration loading, validation, and host services for composing DoomPi sessions.",
5
5
  "keywords": [
6
6
  "agent-configuration",
@@ -144,15 +144,15 @@
144
144
  "registry": "https://registry.npmjs.org/"
145
145
  },
146
146
  "dependencies": {
147
+ "@agimon-ai/doompi-core": "0.0.1-alpha.72",
148
+ "@agimon-ai/doompi-telemetry": "0.0.1-alpha.69",
147
149
  "@deepseek-ai/cordis": "4.0.2",
148
- "typebox": "1.3.25",
149
- "yaml": "2.9.0",
150
- "@agimon-ai/doompi-core": "0.0.1-alpha.71",
151
- "@agimon-ai/doompi-telemetry": "0.0.1-alpha.68"
150
+ "typebox": "1.3.30",
151
+ "yaml": "2.9.0"
152
152
  },
153
153
  "devDependencies": {
154
154
  "@earendil-works/pi-coding-agent": "0.85.1",
155
- "@types/node": "26.4.1",
155
+ "@types/node": "26.5.1",
156
156
  "@vitest/coverage-v8": "5.0.0",
157
157
  "tsdown": "0.23.0",
158
158
  "typescript": "7.0.2",