@agimon-ai/po-image-gen 0.0.0-alpha.39 → 0.0.0-alpha.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/extensions/server.cjs +25 -7
- package/dist/extensions/server.cjs.map +1 -1
- package/dist/extensions/server.mjs +25 -7
- package/dist/extensions/server.mjs.map +1 -1
- package/dist/extensions/web.mjs +19 -225
- package/dist/extensions/web.mjs.map +1 -1
- package/dist/{imagegenTool-DeLz7kv4.mjs → imagegenTool-CUwr0FTZ.mjs} +6 -2
- package/dist/{imagegenTool-DeLz7kv4.mjs.map → imagegenTool-CUwr0FTZ.mjs.map} +1 -1
- package/dist/{imagegenTool-BTWVD9aZ.cjs → imagegenTool-p4LqaZ9G.cjs} +6 -2
- package/dist/{imagegenTool-BTWVD9aZ.cjs.map → imagegenTool-p4LqaZ9G.cjs.map} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +9 -9
|
@@ -2,7 +2,7 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_imagegenTool = require("../imagegenTool-
|
|
5
|
+
const require_imagegenTool = require("../imagegenTool-p4LqaZ9G.cjs");
|
|
6
6
|
let node_crypto = require("node:crypto");
|
|
7
7
|
let node_path = require("node:path");
|
|
8
8
|
let _agimon_ai_po_core_serverPlugin = require("@agimon-ai/po-core/serverPlugin");
|
|
@@ -278,16 +278,34 @@ var help_how_to_image_gen_server_default = (0, _agimon_ai_po_core_extensionFile.
|
|
|
278
278
|
});
|
|
279
279
|
//#endregion
|
|
280
280
|
//#region src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts
|
|
281
|
-
var imagegen_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)(({ host, context }) => {
|
|
281
|
+
var imagegen_server_default = (0, _agimon_ai_po_core_extensionFile.defineServerTool)(({ host, context, signal }) => {
|
|
282
282
|
if (!host.context.homeDirectory) throw new Error("Image generation requires the configured server home.");
|
|
283
|
-
const
|
|
284
|
-
const
|
|
283
|
+
const environment = host.context.environment ?? {};
|
|
284
|
+
const home = (0, _agimon_ai_po_core_piSettings.poHomeDirectory)(host.context.homeDirectory, environment);
|
|
285
|
+
const temporaryDirectory = environment.PO_SESSION_TEMP_DIR;
|
|
286
|
+
const sessionId = host.context.sessionId;
|
|
285
287
|
const fileAccess = (0, _agimon_ai_po_core_platform.readPoFileAccess)(context);
|
|
286
|
-
if (fileAccess !== void 0 &&
|
|
287
|
-
const close = fileAccess.register(require_imagegenTool.imageArtifactDirectory(home,
|
|
288
|
+
if (fileAccess !== void 0 && sessionId !== void 0) {
|
|
289
|
+
const close = fileAccess.register(require_imagegenTool.imageArtifactDirectory(home, sessionId, temporaryDirectory));
|
|
288
290
|
context.effect(() => close, "image generation file access");
|
|
289
291
|
}
|
|
290
|
-
return require_imagegenTool.createImagegenTool(home, temporaryDirectory);
|
|
292
|
+
if (sessionId === void 0) return require_imagegenTool.createImagegenTool(home, temporaryDirectory);
|
|
293
|
+
let promotion;
|
|
294
|
+
context.inject([_agimon_ai_po_core_platform.PO_FS_SERVICE, "po/artifacts"], (child) => {
|
|
295
|
+
const controller = new AbortController();
|
|
296
|
+
const binding = {
|
|
297
|
+
fs: (0, _agimon_ai_po_core_platform.requirePoFs)(child),
|
|
298
|
+
storage: child.get("po/artifacts"),
|
|
299
|
+
signal: AbortSignal.any([signal, controller.signal])
|
|
300
|
+
};
|
|
301
|
+
promotion = binding;
|
|
302
|
+
return () => {
|
|
303
|
+
controller.abort();
|
|
304
|
+
if (promotion === binding) promotion = void 0;
|
|
305
|
+
};
|
|
306
|
+
});
|
|
307
|
+
const promote = createImagePromotion(home, sessionId, environment, () => promotion, signal);
|
|
308
|
+
return require_imagegenTool.createImagegenTool(home, temporaryDirectory, promote);
|
|
291
309
|
});
|
|
292
310
|
//#endregion
|
|
293
311
|
//#region generated/server.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.cjs","names":["withAbortSignal","BACKGROUND_CONTEXT","resolve","getOrThrow","join","createHash","randomUUID","listImageArtifacts","readImageArtifact","imageArtifactIdForCall","ImageArtifactError","defineRoute","PO_FS_SERVICE","requirePoFs","poHomeDirectory","defineResource","PO_HELP_WHEN","packageResourcePath","readPackageResource","defineServerTool","poHomeDirectory","readPoFileAccess","imageArtifactDirectory","createImagegenTool","defineServerPlugin","apiRoute","resourceHelpHowToImageGen","toolImagegen"],"sources":["../../src/services/imagePromotion/index.ts","../../src/types/apiRoutes.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/_lib/imageApi.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { join, resolve } from 'node:path';\n\nimport { BACKGROUND_CONTEXT, getOrThrow, withAbortSignal, type FileSystem } from '@agimon-ai/po-core/platform';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImagePromotionBinding } from './type';\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\n/** One queue per mounted owner. HTTP callers can select an image identity, never a filesystem location. */\nexport function createImagePromotion(\n home: string,\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n binding: () => ImagePromotionBinding | undefined,\n mountSignal: AbortSignal,\n) {\n let pending: Promise<unknown> = Promise.resolve();\n return (id: string, requestSignal: AbortSignal): Promise<{ sessionId: string; path: string }> => {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id) || !/^[A-Za-z0-9_-]+$/u.test(sessionId))\n return Promise.reject(new Error('Invalid image identity.'));\n const run = pending\n .catch(() => undefined)\n .then(async () => {\n const active = binding();\n if (!active) throw new Error('Image artifact storage is unavailable.');\n const signal = AbortSignal.any([requestSignal, mountSignal, active.signal]);\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n const { fs, storage } = active;\n const check = () => {\n signal.throwIfAborted();\n if (binding() !== active) throw new Error('Image artifact storage changed. Retry the image copy.');\n };\n check();\n const root = await storage.rootForSession(sessionId, environment);\n check();\n if (!root) throw new Error('Session artifacts are unavailable.');\n const safeDirectory = async (path: string) => {\n const absolute = resolve(path);\n const info = getOrThrow(await fs.fileInfo(absolute, context));\n if (info.kind !== 'directory' || getOrThrow(await fs.canonicalPath(absolute, context)) !== absolute)\n throw new Error('Unsafe image directory.');\n return absolute;\n };\n await safeDirectory(root);\n const candidates = environment.PO_SESSION_TEMP_DIR\n ? [join(environment.PO_SESSION_TEMP_DIR, 'images'), join(home, 'generated_images', sessionId)]\n : [join(home, 'generated_images', sessionId)];\n let bytes: Uint8Array | undefined;\n for (const candidate of candidates) {\n const info = await fs.fileInfo(candidate, context);\n if (!info.ok && info.error.code === 'not_found') continue;\n getOrThrow(info);\n await safeDirectory(candidate);\n const path = join(candidate, `${id}.png`);\n const leaf = await fs.fileInfo(path, context);\n if (!leaf.ok && leaf.error.code === 'not_found') continue;\n getOrThrow(leaf);\n bytes = await readPng(fs, path, context);\n break;\n }\n if (!bytes) throw new Error('Image not found.');\n const name = `${id}-${createHash('sha256').update(bytes).digest('hex')}.png`;\n const directory = join(root, 'generated-images');\n check();\n await safeDirectory(root);\n const directoryInfo = await fs.fileInfo(directory, context);\n if (!directoryInfo.ok && directoryInfo.error.code === 'not_found')\n getOrThrow(await fs.createDir(directory, undefined, context));\n else getOrThrow(directoryInfo);\n await safeDirectory(directory);\n const target = join(directory, name);\n const matchingTarget = async () => {\n const info = await fs.fileInfo(target, context);\n if (!info.ok && info.error.code === 'not_found') return false;\n getOrThrow(info);\n const existing = await readPng(fs, target, context);\n if (!Buffer.from(existing).equals(Buffer.from(bytes)))\n throw new Error('Artifact filename is already in use.');\n return true;\n };\n const result = { sessionId, path: `artifact:generated-images/${name}` };\n if (await matchingTarget()) {\n check();\n return result;\n }\n // ponytail: the port has no no-replace rename; the queue and checks protect HTTP callers, not hostile\n // concurrent host filesystem writers. Upgrade to a no-replace FileSystem capability when available.\n const temporary = join(directory, `.image-promotion-${randomUUID()}.tmp`);\n if (getOrThrow(await fs.exists(temporary, context))) throw new Error('Image copy temporary name is in use.');\n try {\n check();\n getOrThrow(await fs.writeFile(temporary, bytes, context));\n await safeDirectory(root);\n await safeDirectory(directory);\n check();\n if (!(await matchingTarget())) {\n check();\n getOrThrow(await fs.renameFile(temporary, target, context));\n }\n check();\n return result;\n } finally {\n getOrThrow(await fs.remove(temporary, { force: true }, BACKGROUND_CONTEXT));\n }\n });\n pending = run;\n return run;\n };\n}\n\nasync function readPng(\n fs: FileSystem,\n path: string,\n context: Parameters<FileSystem['fileInfo']>[1],\n): Promise<Uint8Array> {\n const info = getOrThrow(await fs.fileInfo(path, context));\n if (info.kind !== 'file' || getOrThrow(await fs.canonicalPath(path, context)) !== resolve(path))\n throw new Error('Unsafe image file.');\n const reader = getOrThrow(await fs.openBinaryReader(path, { noFollow: true }, context));\n try {\n const before = getOrThrow(await reader.info(context));\n if (before.size < PNG_SIGNATURE.length || before.size > MAX_REFERENCE_BYTES)\n throw new Error('Image exceeds the size limit or is empty.');\n const data = getOrThrow(await reader.read(0, before.size, context));\n const after = getOrThrow(await reader.info(context));\n if (data.length !== before.size || before.size !== after.size || before.mtimeMs !== after.mtimeMs)\n throw new Error('Image changed during access.');\n if (!Buffer.from(data.subarray(0, PNG_SIGNATURE.length)).equals(PNG_SIGNATURE))\n throw new Error('Image is not a PNG.');\n return data;\n } finally {\n await reader.close(BACKGROUND_CONTEXT);\n }\n}\n","// Type-only imports: the native bundle loads this file and may not import po-core/web at runtime.\nimport type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = {\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: undefined as unknown as ApiResponseOf<ImageArtifactList>,\n },\n promoteImage: {\n method: 'POST',\n path: '/promote',\n response: undefined as unknown as ApiResponseOf<{ sessionId: string; path: string }>,\n },\n readImage: {\n method: 'GET',\n path: '/artifact',\n query: ['id', 'toolCallId', 'offset', 'count', 'sourceSha256'],\n response: undefined as unknown as ApiResponseOf<ImageArtifact>,\n },\n} as const satisfies ApiRoutes;\nexport default routes;\n","import type { PoApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport { createImagePromotion } from '../../../../../../../services/imagePromotion';\nimport type { ImagePromotionBinding } from '../../../../../../../services/imagePromotion/type';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(\n home: string,\n binding: () => ImagePromotionBinding | undefined = () => undefined,\n lifetime?: AbortSignal,\n): PoApi {\n return {\n basePath: 'images',\n start(context) {\n if (context.scope !== 'session' || !context.sessionId) throw new Error('Images require a session mount.');\n const sessionId = context.sessionId;\n const controller = new AbortController();\n const signal = lifetime ? AbortSignal.any([lifetime, controller.signal]) : controller.signal;\n const promote = createImagePromotion(home, sessionId, context.environment ?? {}, binding, signal);\n return {\n close() {\n controller.abort();\n },\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' && !(request.method === 'POST' && url.pathname === routes.promoteImage.path))\n return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n if (url.pathname === routes.promoteImage.path) {\n if (request.method !== 'POST') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n // Small ID-only body. No path, directory, root or session selectors are admitted.\n const reader = request.body?.getReader();\n if (!reader) return Response.json({ error: 'Provide an image identity.' }, { status: 400 });\n let text = '';\n let size = 0;\n try {\n const decoder = new TextDecoder();\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.byteLength;\n if (size > 1024) return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n text += decoder.decode(chunk.value, { stream: true });\n }\n text += decoder.decode();\n } finally {\n await reader.cancel();\n }\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n }\n if (\n typeof body !== 'object' ||\n body === null ||\n Array.isArray(body) ||\n Object.keys(body).length !== 1 ||\n !('id' in body) ||\n typeof body.id !== 'string' ||\n !/^[A-Za-z0-9_-]{1,128}$/u.test(body.id) ||\n url.search\n ) {\n return Response.json({ error: 'Provide only an image identity.' }, { status: 400 });\n }\n try {\n result = await promote(body.id, request.signal);\n } catch (error) {\n request.signal.throwIfAborted();\n return Response.json(\n { error: error instanceof Error ? error.message : 'Image could not be copied.' },\n { status: 409 },\n );\n }\n } else if (url.pathname === routes.listImages.path) {\n const limit = url.searchParams.get('limit');\n const cursor = url.searchParams.get('cursor');\n if ((limit !== null && !/^\\d+$/u.test(limit)) || (cursor !== null && !/^\\d+$/u.test(cursor)))\n return Response.json({ error: 'Invalid image page.' }, { status: 400 });\n result = await listImageArtifacts(\n home,\n sessionId,\n limit === null ? 6 : Number(limit),\n cursor === null ? 0 : Number(cursor),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n );\n } else if (url.pathname === routes.readImage.path) {\n const id = url.searchParams.get('id');\n const call = url.searchParams.get('toolCallId');\n if ((id === null) === (call === null) || (call !== null && (!call || call.length > 16384)))\n return Response.json({ error: 'Provide exactly one image identity.' }, { status: 400 });\n const offset = url.searchParams.get('offset');\n const count = url.searchParams.get('count');\n const sourceSha256 = url.searchParams.get('sourceSha256');\n const chunked = offset !== null || count !== null || sourceSha256 !== null;\n if (chunked && (offset === null || count === null || !/^\\d+$/u.test(offset) || !/^\\d+$/u.test(count)))\n return Response.json({ error: 'Invalid image chunk.' }, { status: 400 });\n result = await readImageArtifact(\n home,\n sessionId,\n id ?? imageArtifactIdForCall(call!),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n chunked\n ? { offset: Number(offset), count: Number(count), ...(sourceSha256 !== null ? { sourceSha256 } : {}) }\n : undefined,\n );\n } else return Response.json({ error: 'Not found.' }, { status: 404 });\n return Response.json(result, {\n headers: { 'cache-control': 'no-store', 'x-content-type-options': 'nosniff' },\n });\n } catch (error) {\n request.signal.throwIfAborted();\n if (error instanceof ImageArtifactError)\n return Response.json(\n { error: error.message },\n { status: error.message.startsWith('Invalid') ? 400 : 404 },\n );\n if (\n error instanceof Error &&\n 'code' in error &&\n ['ENOENT', 'ELOOP', 'ENOTDIR'].includes(String(error.code))\n )\n return Response.json({ error: 'Image not found.' }, { status: 404 });\n throw error;\n }\n },\n };\n },\n };\n}\n","import { defineRoute } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../../services/imagePromotion/type';\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n return createImageApi(\n poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {}),\n () => promotion,\n signal,\n );\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { PO_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineResource({\n name: 'help-how-to-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: PO_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { readPoFileAccess } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { imageArtifactDirectory } from '../../../../../services/imageArtifacts';\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host, context }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n const home = poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {});\n const temporaryDirectory = host.context.environment?.PO_SESSION_TEMP_DIR;\n // A paired client opens the images this tool writes, wherever the host put them; closes with the tool.\n const fileAccess = readPoFileAccess(context);\n if (fileAccess !== undefined && host.context.sessionId !== undefined) {\n const close = fileAccess.register(imageArtifactDirectory(home, host.context.sessionId, temporaryDirectory));\n context.effect(() => close, 'image generation file access');\n }\n return createImagegenTool(home, temporaryDirectory);\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourceHelpHowToImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(backend)/tool/imagegen.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;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): PoServerSessionPlugin['resources'] { return [at(resourceHelpHowToImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.cjs","names":["withAbortSignal","BACKGROUND_CONTEXT","resolve","getOrThrow","join","createHash","randomUUID","listImageArtifacts","readImageArtifact","imageArtifactIdForCall","ImageArtifactError","defineRoute","PO_FS_SERVICE","requirePoFs","poHomeDirectory","defineResource","PO_HELP_WHEN","packageResourcePath","readPackageResource","defineServerTool","poHomeDirectory","readPoFileAccess","imageArtifactDirectory","createImagegenTool","PO_FS_SERVICE","requirePoFs","defineServerPlugin","apiRoute","resourceHelpHowToImageGen","toolImagegen"],"sources":["../../src/services/imagePromotion/index.ts","../../src/types/apiRoutes.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/_lib/imageApi.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { join, resolve } from 'node:path';\n\nimport { BACKGROUND_CONTEXT, getOrThrow, withAbortSignal, type FileSystem } from '@agimon-ai/po-core/platform';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImagePromotionBinding } from './type';\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\n/** One queue per mounted owner. HTTP callers can select an image identity, never a filesystem location. */\nexport function createImagePromotion(\n home: string,\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n binding: () => ImagePromotionBinding | undefined,\n mountSignal: AbortSignal,\n) {\n let pending: Promise<unknown> = Promise.resolve();\n return (id: string, requestSignal: AbortSignal): Promise<{ sessionId: string; path: string }> => {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id) || !/^[A-Za-z0-9_-]+$/u.test(sessionId))\n return Promise.reject(new Error('Invalid image identity.'));\n const run = pending\n .catch(() => undefined)\n .then(async () => {\n const active = binding();\n if (!active) throw new Error('Image artifact storage is unavailable.');\n const signal = AbortSignal.any([requestSignal, mountSignal, active.signal]);\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n const { fs, storage } = active;\n const check = () => {\n signal.throwIfAborted();\n if (binding() !== active) throw new Error('Image artifact storage changed. Retry the image copy.');\n };\n check();\n const root = await storage.rootForSession(sessionId, environment);\n check();\n if (!root) throw new Error('Session artifacts are unavailable.');\n const safeDirectory = async (path: string) => {\n const absolute = resolve(path);\n const info = getOrThrow(await fs.fileInfo(absolute, context));\n if (info.kind !== 'directory' || getOrThrow(await fs.canonicalPath(absolute, context)) !== absolute)\n throw new Error('Unsafe image directory.');\n return absolute;\n };\n await safeDirectory(root);\n const candidates = environment.PO_SESSION_TEMP_DIR\n ? [join(environment.PO_SESSION_TEMP_DIR, 'images'), join(home, 'generated_images', sessionId)]\n : [join(home, 'generated_images', sessionId)];\n let bytes: Uint8Array | undefined;\n for (const candidate of candidates) {\n const info = await fs.fileInfo(candidate, context);\n if (!info.ok && info.error.code === 'not_found') continue;\n getOrThrow(info);\n await safeDirectory(candidate);\n const path = join(candidate, `${id}.png`);\n const leaf = await fs.fileInfo(path, context);\n if (!leaf.ok && leaf.error.code === 'not_found') continue;\n getOrThrow(leaf);\n bytes = await readPng(fs, path, context);\n break;\n }\n if (!bytes) throw new Error('Image not found.');\n const name = `${id}-${createHash('sha256').update(bytes).digest('hex')}.png`;\n const directory = join(root, 'generated-images');\n check();\n await safeDirectory(root);\n const directoryInfo = await fs.fileInfo(directory, context);\n if (!directoryInfo.ok && directoryInfo.error.code === 'not_found')\n getOrThrow(await fs.createDir(directory, undefined, context));\n else getOrThrow(directoryInfo);\n await safeDirectory(directory);\n const target = join(directory, name);\n const matchingTarget = async () => {\n const info = await fs.fileInfo(target, context);\n if (!info.ok && info.error.code === 'not_found') return false;\n getOrThrow(info);\n const existing = await readPng(fs, target, context);\n if (!Buffer.from(existing).equals(Buffer.from(bytes)))\n throw new Error('Artifact filename is already in use.');\n return true;\n };\n const result = { sessionId, path: `artifact:generated-images/${name}` };\n if (await matchingTarget()) {\n check();\n return result;\n }\n // ponytail: the port has no no-replace rename; the queue and checks protect HTTP callers, not hostile\n // concurrent host filesystem writers. Upgrade to a no-replace FileSystem capability when available.\n const temporary = join(directory, `.image-promotion-${randomUUID()}.tmp`);\n if (getOrThrow(await fs.exists(temporary, context))) throw new Error('Image copy temporary name is in use.');\n try {\n check();\n getOrThrow(await fs.writeFile(temporary, bytes, context));\n await safeDirectory(root);\n await safeDirectory(directory);\n check();\n if (!(await matchingTarget())) {\n check();\n getOrThrow(await fs.renameFile(temporary, target, context));\n }\n check();\n return result;\n } finally {\n getOrThrow(await fs.remove(temporary, { force: true }, BACKGROUND_CONTEXT));\n }\n });\n pending = run;\n return run;\n };\n}\n\nasync function readPng(\n fs: FileSystem,\n path: string,\n context: Parameters<FileSystem['fileInfo']>[1],\n): Promise<Uint8Array> {\n const info = getOrThrow(await fs.fileInfo(path, context));\n if (info.kind !== 'file' || getOrThrow(await fs.canonicalPath(path, context)) !== resolve(path))\n throw new Error('Unsafe image file.');\n const reader = getOrThrow(await fs.openBinaryReader(path, { noFollow: true }, context));\n try {\n const before = getOrThrow(await reader.info(context));\n if (before.size < PNG_SIGNATURE.length || before.size > MAX_REFERENCE_BYTES)\n throw new Error('Image exceeds the size limit or is empty.');\n const data = getOrThrow(await reader.read(0, before.size, context));\n const after = getOrThrow(await reader.info(context));\n if (data.length !== before.size || before.size !== after.size || before.mtimeMs !== after.mtimeMs)\n throw new Error('Image changed during access.');\n if (!Buffer.from(data.subarray(0, PNG_SIGNATURE.length)).equals(PNG_SIGNATURE))\n throw new Error('Image is not a PNG.');\n return data;\n } finally {\n await reader.close(BACKGROUND_CONTEXT);\n }\n}\n","// Type-only imports: the native bundle loads this file and may not import po-core/web at runtime.\nimport type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = {\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: undefined as unknown as ApiResponseOf<ImageArtifactList>,\n },\n promoteImage: {\n method: 'POST',\n path: '/promote',\n response: undefined as unknown as ApiResponseOf<{ sessionId: string; path: string }>,\n },\n readImage: {\n method: 'GET',\n path: '/artifact',\n query: ['id', 'toolCallId', 'offset', 'count', 'sourceSha256'],\n response: undefined as unknown as ApiResponseOf<ImageArtifact>,\n },\n} as const satisfies ApiRoutes;\nexport default routes;\n","import type { PoApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport { createImagePromotion } from '../../../../../../../services/imagePromotion';\nimport type { ImagePromotionBinding } from '../../../../../../../services/imagePromotion/type';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(\n home: string,\n binding: () => ImagePromotionBinding | undefined = () => undefined,\n lifetime?: AbortSignal,\n): PoApi {\n return {\n basePath: 'images',\n start(context) {\n if (context.scope !== 'session' || !context.sessionId) throw new Error('Images require a session mount.');\n const sessionId = context.sessionId;\n const controller = new AbortController();\n const signal = lifetime ? AbortSignal.any([lifetime, controller.signal]) : controller.signal;\n const promote = createImagePromotion(home, sessionId, context.environment ?? {}, binding, signal);\n return {\n close() {\n controller.abort();\n },\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' && !(request.method === 'POST' && url.pathname === routes.promoteImage.path))\n return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n if (url.pathname === routes.promoteImage.path) {\n if (request.method !== 'POST') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n // Small ID-only body. No path, directory, root or session selectors are admitted.\n const reader = request.body?.getReader();\n if (!reader) return Response.json({ error: 'Provide an image identity.' }, { status: 400 });\n let text = '';\n let size = 0;\n try {\n const decoder = new TextDecoder();\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.byteLength;\n if (size > 1024) return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n text += decoder.decode(chunk.value, { stream: true });\n }\n text += decoder.decode();\n } finally {\n await reader.cancel();\n }\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n }\n if (\n typeof body !== 'object' ||\n body === null ||\n Array.isArray(body) ||\n Object.keys(body).length !== 1 ||\n !('id' in body) ||\n typeof body.id !== 'string' ||\n !/^[A-Za-z0-9_-]{1,128}$/u.test(body.id) ||\n url.search\n ) {\n return Response.json({ error: 'Provide only an image identity.' }, { status: 400 });\n }\n try {\n result = await promote(body.id, request.signal);\n } catch (error) {\n request.signal.throwIfAborted();\n return Response.json(\n { error: error instanceof Error ? error.message : 'Image could not be copied.' },\n { status: 409 },\n );\n }\n } else if (url.pathname === routes.listImages.path) {\n const limit = url.searchParams.get('limit');\n const cursor = url.searchParams.get('cursor');\n if ((limit !== null && !/^\\d+$/u.test(limit)) || (cursor !== null && !/^\\d+$/u.test(cursor)))\n return Response.json({ error: 'Invalid image page.' }, { status: 400 });\n result = await listImageArtifacts(\n home,\n sessionId,\n limit === null ? 6 : Number(limit),\n cursor === null ? 0 : Number(cursor),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n );\n } else if (url.pathname === routes.readImage.path) {\n const id = url.searchParams.get('id');\n const call = url.searchParams.get('toolCallId');\n if ((id === null) === (call === null) || (call !== null && (!call || call.length > 16384)))\n return Response.json({ error: 'Provide exactly one image identity.' }, { status: 400 });\n const offset = url.searchParams.get('offset');\n const count = url.searchParams.get('count');\n const sourceSha256 = url.searchParams.get('sourceSha256');\n const chunked = offset !== null || count !== null || sourceSha256 !== null;\n if (chunked && (offset === null || count === null || !/^\\d+$/u.test(offset) || !/^\\d+$/u.test(count)))\n return Response.json({ error: 'Invalid image chunk.' }, { status: 400 });\n result = await readImageArtifact(\n home,\n sessionId,\n id ?? imageArtifactIdForCall(call!),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n chunked\n ? { offset: Number(offset), count: Number(count), ...(sourceSha256 !== null ? { sourceSha256 } : {}) }\n : undefined,\n );\n } else return Response.json({ error: 'Not found.' }, { status: 404 });\n return Response.json(result, {\n headers: { 'cache-control': 'no-store', 'x-content-type-options': 'nosniff' },\n });\n } catch (error) {\n request.signal.throwIfAborted();\n if (error instanceof ImageArtifactError)\n return Response.json(\n { error: error.message },\n { status: error.message.startsWith('Invalid') ? 400 : 404 },\n );\n if (\n error instanceof Error &&\n 'code' in error &&\n ['ENOENT', 'ELOOP', 'ENOTDIR'].includes(String(error.code))\n )\n return Response.json({ error: 'Image not found.' }, { status: 404 });\n throw error;\n }\n },\n };\n },\n };\n}\n","import { defineRoute } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../../services/imagePromotion/type';\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n return createImageApi(\n poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {}),\n () => promotion,\n signal,\n );\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { PO_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineResource({\n name: 'help-how-to-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: PO_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, readPoFileAccess, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { imageArtifactDirectory } from '../../../../../services/imageArtifacts';\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\nimport { createImagePromotion } from '../../../../../services/imagePromotion';\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../services/imagePromotion/type';\n\nexport default defineServerTool(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n const environment = host.context.environment ?? {};\n const home = poHomeDirectory(host.context.homeDirectory, environment);\n const temporaryDirectory = environment.PO_SESSION_TEMP_DIR;\n const sessionId = host.context.sessionId;\n // A paired client opens the images this tool writes, wherever the host put them; closes with the tool.\n const fileAccess = readPoFileAccess(context);\n if (fileAccess !== undefined && sessionId !== undefined) {\n const close = fileAccess.register(imageArtifactDirectory(home, sessionId, temporaryDirectory));\n context.effect(() => close, 'image generation file access');\n }\n if (sessionId === undefined) return createImagegenTool(home, temporaryDirectory);\n // Every generated image also lands in the session's artifacts, so it is listed with the files Po made.\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n const promote = createImagePromotion(home, sessionId, environment, () => promotion, signal);\n return createImagegenTool(home, temporaryDirectory, promote);\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourceHelpHowToImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(backend)/tool/imagegen.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;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): PoServerSessionPlugin['resources'] { return [at(resourceHelpHowToImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as listImageArtifacts, i as imageArtifactIdForCall, n as ImageArtifactError, o as readImageArtifact, r as imageArtifactDirectory, t as createImagegenTool } from "../imagegenTool-
|
|
1
|
+
import { a as listImageArtifacts, i as imageArtifactIdForCall, n as ImageArtifactError, o as readImageArtifact, r as imageArtifactDirectory, t as createImagegenTool } from "../imagegenTool-CUwr0FTZ.mjs";
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
3
|
import { join, resolve } from "node:path";
|
|
4
4
|
import { defineServerPlugin, packageResourcePath, readPackageResource } from "@agimon-ai/po-core/serverPlugin";
|
|
@@ -274,16 +274,34 @@ var help_how_to_image_gen_server_default = defineResource({
|
|
|
274
274
|
});
|
|
275
275
|
//#endregion
|
|
276
276
|
//#region src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts
|
|
277
|
-
var imagegen_server_default = defineServerTool(({ host, context }) => {
|
|
277
|
+
var imagegen_server_default = defineServerTool(({ host, context, signal }) => {
|
|
278
278
|
if (!host.context.homeDirectory) throw new Error("Image generation requires the configured server home.");
|
|
279
|
-
const
|
|
280
|
-
const
|
|
279
|
+
const environment = host.context.environment ?? {};
|
|
280
|
+
const home = poHomeDirectory(host.context.homeDirectory, environment);
|
|
281
|
+
const temporaryDirectory = environment.PO_SESSION_TEMP_DIR;
|
|
282
|
+
const sessionId = host.context.sessionId;
|
|
281
283
|
const fileAccess = readPoFileAccess(context);
|
|
282
|
-
if (fileAccess !== void 0 &&
|
|
283
|
-
const close = fileAccess.register(imageArtifactDirectory(home,
|
|
284
|
+
if (fileAccess !== void 0 && sessionId !== void 0) {
|
|
285
|
+
const close = fileAccess.register(imageArtifactDirectory(home, sessionId, temporaryDirectory));
|
|
284
286
|
context.effect(() => close, "image generation file access");
|
|
285
287
|
}
|
|
286
|
-
return createImagegenTool(home, temporaryDirectory);
|
|
288
|
+
if (sessionId === void 0) return createImagegenTool(home, temporaryDirectory);
|
|
289
|
+
let promotion;
|
|
290
|
+
context.inject([PO_FS_SERVICE, "po/artifacts"], (child) => {
|
|
291
|
+
const controller = new AbortController();
|
|
292
|
+
const binding = {
|
|
293
|
+
fs: requirePoFs(child),
|
|
294
|
+
storage: child.get("po/artifacts"),
|
|
295
|
+
signal: AbortSignal.any([signal, controller.signal])
|
|
296
|
+
};
|
|
297
|
+
promotion = binding;
|
|
298
|
+
return () => {
|
|
299
|
+
controller.abort();
|
|
300
|
+
if (promotion === binding) promotion = void 0;
|
|
301
|
+
};
|
|
302
|
+
});
|
|
303
|
+
const promote = createImagePromotion(home, sessionId, environment, () => promotion, signal);
|
|
304
|
+
return createImagegenTool(home, temporaryDirectory, promote);
|
|
287
305
|
});
|
|
288
306
|
//#endregion
|
|
289
307
|
//#region generated/server.ts
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.mjs","names":["apiRoute","resourceHelpHowToImageGen","toolImagegen"],"sources":["../../src/services/imagePromotion/index.ts","../../src/types/apiRoutes.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/_lib/imageApi.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { join, resolve } from 'node:path';\n\nimport { BACKGROUND_CONTEXT, getOrThrow, withAbortSignal, type FileSystem } from '@agimon-ai/po-core/platform';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImagePromotionBinding } from './type';\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\n/** One queue per mounted owner. HTTP callers can select an image identity, never a filesystem location. */\nexport function createImagePromotion(\n home: string,\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n binding: () => ImagePromotionBinding | undefined,\n mountSignal: AbortSignal,\n) {\n let pending: Promise<unknown> = Promise.resolve();\n return (id: string, requestSignal: AbortSignal): Promise<{ sessionId: string; path: string }> => {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id) || !/^[A-Za-z0-9_-]+$/u.test(sessionId))\n return Promise.reject(new Error('Invalid image identity.'));\n const run = pending\n .catch(() => undefined)\n .then(async () => {\n const active = binding();\n if (!active) throw new Error('Image artifact storage is unavailable.');\n const signal = AbortSignal.any([requestSignal, mountSignal, active.signal]);\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n const { fs, storage } = active;\n const check = () => {\n signal.throwIfAborted();\n if (binding() !== active) throw new Error('Image artifact storage changed. Retry the image copy.');\n };\n check();\n const root = await storage.rootForSession(sessionId, environment);\n check();\n if (!root) throw new Error('Session artifacts are unavailable.');\n const safeDirectory = async (path: string) => {\n const absolute = resolve(path);\n const info = getOrThrow(await fs.fileInfo(absolute, context));\n if (info.kind !== 'directory' || getOrThrow(await fs.canonicalPath(absolute, context)) !== absolute)\n throw new Error('Unsafe image directory.');\n return absolute;\n };\n await safeDirectory(root);\n const candidates = environment.PO_SESSION_TEMP_DIR\n ? [join(environment.PO_SESSION_TEMP_DIR, 'images'), join(home, 'generated_images', sessionId)]\n : [join(home, 'generated_images', sessionId)];\n let bytes: Uint8Array | undefined;\n for (const candidate of candidates) {\n const info = await fs.fileInfo(candidate, context);\n if (!info.ok && info.error.code === 'not_found') continue;\n getOrThrow(info);\n await safeDirectory(candidate);\n const path = join(candidate, `${id}.png`);\n const leaf = await fs.fileInfo(path, context);\n if (!leaf.ok && leaf.error.code === 'not_found') continue;\n getOrThrow(leaf);\n bytes = await readPng(fs, path, context);\n break;\n }\n if (!bytes) throw new Error('Image not found.');\n const name = `${id}-${createHash('sha256').update(bytes).digest('hex')}.png`;\n const directory = join(root, 'generated-images');\n check();\n await safeDirectory(root);\n const directoryInfo = await fs.fileInfo(directory, context);\n if (!directoryInfo.ok && directoryInfo.error.code === 'not_found')\n getOrThrow(await fs.createDir(directory, undefined, context));\n else getOrThrow(directoryInfo);\n await safeDirectory(directory);\n const target = join(directory, name);\n const matchingTarget = async () => {\n const info = await fs.fileInfo(target, context);\n if (!info.ok && info.error.code === 'not_found') return false;\n getOrThrow(info);\n const existing = await readPng(fs, target, context);\n if (!Buffer.from(existing).equals(Buffer.from(bytes)))\n throw new Error('Artifact filename is already in use.');\n return true;\n };\n const result = { sessionId, path: `artifact:generated-images/${name}` };\n if (await matchingTarget()) {\n check();\n return result;\n }\n // ponytail: the port has no no-replace rename; the queue and checks protect HTTP callers, not hostile\n // concurrent host filesystem writers. Upgrade to a no-replace FileSystem capability when available.\n const temporary = join(directory, `.image-promotion-${randomUUID()}.tmp`);\n if (getOrThrow(await fs.exists(temporary, context))) throw new Error('Image copy temporary name is in use.');\n try {\n check();\n getOrThrow(await fs.writeFile(temporary, bytes, context));\n await safeDirectory(root);\n await safeDirectory(directory);\n check();\n if (!(await matchingTarget())) {\n check();\n getOrThrow(await fs.renameFile(temporary, target, context));\n }\n check();\n return result;\n } finally {\n getOrThrow(await fs.remove(temporary, { force: true }, BACKGROUND_CONTEXT));\n }\n });\n pending = run;\n return run;\n };\n}\n\nasync function readPng(\n fs: FileSystem,\n path: string,\n context: Parameters<FileSystem['fileInfo']>[1],\n): Promise<Uint8Array> {\n const info = getOrThrow(await fs.fileInfo(path, context));\n if (info.kind !== 'file' || getOrThrow(await fs.canonicalPath(path, context)) !== resolve(path))\n throw new Error('Unsafe image file.');\n const reader = getOrThrow(await fs.openBinaryReader(path, { noFollow: true }, context));\n try {\n const before = getOrThrow(await reader.info(context));\n if (before.size < PNG_SIGNATURE.length || before.size > MAX_REFERENCE_BYTES)\n throw new Error('Image exceeds the size limit or is empty.');\n const data = getOrThrow(await reader.read(0, before.size, context));\n const after = getOrThrow(await reader.info(context));\n if (data.length !== before.size || before.size !== after.size || before.mtimeMs !== after.mtimeMs)\n throw new Error('Image changed during access.');\n if (!Buffer.from(data.subarray(0, PNG_SIGNATURE.length)).equals(PNG_SIGNATURE))\n throw new Error('Image is not a PNG.');\n return data;\n } finally {\n await reader.close(BACKGROUND_CONTEXT);\n }\n}\n","// Type-only imports: the native bundle loads this file and may not import po-core/web at runtime.\nimport type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = {\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: undefined as unknown as ApiResponseOf<ImageArtifactList>,\n },\n promoteImage: {\n method: 'POST',\n path: '/promote',\n response: undefined as unknown as ApiResponseOf<{ sessionId: string; path: string }>,\n },\n readImage: {\n method: 'GET',\n path: '/artifact',\n query: ['id', 'toolCallId', 'offset', 'count', 'sourceSha256'],\n response: undefined as unknown as ApiResponseOf<ImageArtifact>,\n },\n} as const satisfies ApiRoutes;\nexport default routes;\n","import type { PoApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport { createImagePromotion } from '../../../../../../../services/imagePromotion';\nimport type { ImagePromotionBinding } from '../../../../../../../services/imagePromotion/type';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(\n home: string,\n binding: () => ImagePromotionBinding | undefined = () => undefined,\n lifetime?: AbortSignal,\n): PoApi {\n return {\n basePath: 'images',\n start(context) {\n if (context.scope !== 'session' || !context.sessionId) throw new Error('Images require a session mount.');\n const sessionId = context.sessionId;\n const controller = new AbortController();\n const signal = lifetime ? AbortSignal.any([lifetime, controller.signal]) : controller.signal;\n const promote = createImagePromotion(home, sessionId, context.environment ?? {}, binding, signal);\n return {\n close() {\n controller.abort();\n },\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' && !(request.method === 'POST' && url.pathname === routes.promoteImage.path))\n return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n if (url.pathname === routes.promoteImage.path) {\n if (request.method !== 'POST') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n // Small ID-only body. No path, directory, root or session selectors are admitted.\n const reader = request.body?.getReader();\n if (!reader) return Response.json({ error: 'Provide an image identity.' }, { status: 400 });\n let text = '';\n let size = 0;\n try {\n const decoder = new TextDecoder();\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.byteLength;\n if (size > 1024) return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n text += decoder.decode(chunk.value, { stream: true });\n }\n text += decoder.decode();\n } finally {\n await reader.cancel();\n }\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n }\n if (\n typeof body !== 'object' ||\n body === null ||\n Array.isArray(body) ||\n Object.keys(body).length !== 1 ||\n !('id' in body) ||\n typeof body.id !== 'string' ||\n !/^[A-Za-z0-9_-]{1,128}$/u.test(body.id) ||\n url.search\n ) {\n return Response.json({ error: 'Provide only an image identity.' }, { status: 400 });\n }\n try {\n result = await promote(body.id, request.signal);\n } catch (error) {\n request.signal.throwIfAborted();\n return Response.json(\n { error: error instanceof Error ? error.message : 'Image could not be copied.' },\n { status: 409 },\n );\n }\n } else if (url.pathname === routes.listImages.path) {\n const limit = url.searchParams.get('limit');\n const cursor = url.searchParams.get('cursor');\n if ((limit !== null && !/^\\d+$/u.test(limit)) || (cursor !== null && !/^\\d+$/u.test(cursor)))\n return Response.json({ error: 'Invalid image page.' }, { status: 400 });\n result = await listImageArtifacts(\n home,\n sessionId,\n limit === null ? 6 : Number(limit),\n cursor === null ? 0 : Number(cursor),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n );\n } else if (url.pathname === routes.readImage.path) {\n const id = url.searchParams.get('id');\n const call = url.searchParams.get('toolCallId');\n if ((id === null) === (call === null) || (call !== null && (!call || call.length > 16384)))\n return Response.json({ error: 'Provide exactly one image identity.' }, { status: 400 });\n const offset = url.searchParams.get('offset');\n const count = url.searchParams.get('count');\n const sourceSha256 = url.searchParams.get('sourceSha256');\n const chunked = offset !== null || count !== null || sourceSha256 !== null;\n if (chunked && (offset === null || count === null || !/^\\d+$/u.test(offset) || !/^\\d+$/u.test(count)))\n return Response.json({ error: 'Invalid image chunk.' }, { status: 400 });\n result = await readImageArtifact(\n home,\n sessionId,\n id ?? imageArtifactIdForCall(call!),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n chunked\n ? { offset: Number(offset), count: Number(count), ...(sourceSha256 !== null ? { sourceSha256 } : {}) }\n : undefined,\n );\n } else return Response.json({ error: 'Not found.' }, { status: 404 });\n return Response.json(result, {\n headers: { 'cache-control': 'no-store', 'x-content-type-options': 'nosniff' },\n });\n } catch (error) {\n request.signal.throwIfAborted();\n if (error instanceof ImageArtifactError)\n return Response.json(\n { error: error.message },\n { status: error.message.startsWith('Invalid') ? 400 : 404 },\n );\n if (\n error instanceof Error &&\n 'code' in error &&\n ['ENOENT', 'ELOOP', 'ENOTDIR'].includes(String(error.code))\n )\n return Response.json({ error: 'Image not found.' }, { status: 404 });\n throw error;\n }\n },\n };\n },\n };\n}\n","import { defineRoute } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../../services/imagePromotion/type';\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n return createImageApi(\n poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {}),\n () => promotion,\n signal,\n );\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { PO_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineResource({\n name: 'help-how-to-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: PO_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { readPoFileAccess } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { imageArtifactDirectory } from '../../../../../services/imageArtifacts';\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host, context }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n const home = poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {});\n const temporaryDirectory = host.context.environment?.PO_SESSION_TEMP_DIR;\n // A paired client opens the images this tool writes, wherever the host put them; closes with the tool.\n const fileAccess = readPoFileAccess(context);\n if (fileAccess !== undefined && host.context.sessionId !== undefined) {\n const close = fileAccess.register(imageArtifactDirectory(home, host.context.sessionId, temporaryDirectory));\n context.effect(() => close, 'image generation file access');\n }\n return createImagegenTool(home, temporaryDirectory);\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourceHelpHowToImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(backend)/tool/imagegen.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;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): PoServerSessionPlugin['resources'] { return [at(resourceHelpHowToImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"server.mjs","names":["apiRoute","resourceHelpHowToImageGen","toolImagegen"],"sources":["../../src/services/imagePromotion/index.ts","../../src/types/apiRoutes.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/_lib/imageApi.ts","../../src/extensions/workspaces/sessions/(backend)/api/images/route.server.ts","../../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { join, resolve } from 'node:path';\n\nimport { BACKGROUND_CONTEXT, getOrThrow, withAbortSignal, type FileSystem } from '@agimon-ai/po-core/platform';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImagePromotionBinding } from './type';\n\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\n\n/** One queue per mounted owner. HTTP callers can select an image identity, never a filesystem location. */\nexport function createImagePromotion(\n home: string,\n sessionId: string,\n environment: Readonly<Record<string, string | undefined>>,\n binding: () => ImagePromotionBinding | undefined,\n mountSignal: AbortSignal,\n) {\n let pending: Promise<unknown> = Promise.resolve();\n return (id: string, requestSignal: AbortSignal): Promise<{ sessionId: string; path: string }> => {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id) || !/^[A-Za-z0-9_-]+$/u.test(sessionId))\n return Promise.reject(new Error('Invalid image identity.'));\n const run = pending\n .catch(() => undefined)\n .then(async () => {\n const active = binding();\n if (!active) throw new Error('Image artifact storage is unavailable.');\n const signal = AbortSignal.any([requestSignal, mountSignal, active.signal]);\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n const { fs, storage } = active;\n const check = () => {\n signal.throwIfAborted();\n if (binding() !== active) throw new Error('Image artifact storage changed. Retry the image copy.');\n };\n check();\n const root = await storage.rootForSession(sessionId, environment);\n check();\n if (!root) throw new Error('Session artifacts are unavailable.');\n const safeDirectory = async (path: string) => {\n const absolute = resolve(path);\n const info = getOrThrow(await fs.fileInfo(absolute, context));\n if (info.kind !== 'directory' || getOrThrow(await fs.canonicalPath(absolute, context)) !== absolute)\n throw new Error('Unsafe image directory.');\n return absolute;\n };\n await safeDirectory(root);\n const candidates = environment.PO_SESSION_TEMP_DIR\n ? [join(environment.PO_SESSION_TEMP_DIR, 'images'), join(home, 'generated_images', sessionId)]\n : [join(home, 'generated_images', sessionId)];\n let bytes: Uint8Array | undefined;\n for (const candidate of candidates) {\n const info = await fs.fileInfo(candidate, context);\n if (!info.ok && info.error.code === 'not_found') continue;\n getOrThrow(info);\n await safeDirectory(candidate);\n const path = join(candidate, `${id}.png`);\n const leaf = await fs.fileInfo(path, context);\n if (!leaf.ok && leaf.error.code === 'not_found') continue;\n getOrThrow(leaf);\n bytes = await readPng(fs, path, context);\n break;\n }\n if (!bytes) throw new Error('Image not found.');\n const name = `${id}-${createHash('sha256').update(bytes).digest('hex')}.png`;\n const directory = join(root, 'generated-images');\n check();\n await safeDirectory(root);\n const directoryInfo = await fs.fileInfo(directory, context);\n if (!directoryInfo.ok && directoryInfo.error.code === 'not_found')\n getOrThrow(await fs.createDir(directory, undefined, context));\n else getOrThrow(directoryInfo);\n await safeDirectory(directory);\n const target = join(directory, name);\n const matchingTarget = async () => {\n const info = await fs.fileInfo(target, context);\n if (!info.ok && info.error.code === 'not_found') return false;\n getOrThrow(info);\n const existing = await readPng(fs, target, context);\n if (!Buffer.from(existing).equals(Buffer.from(bytes)))\n throw new Error('Artifact filename is already in use.');\n return true;\n };\n const result = { sessionId, path: `artifact:generated-images/${name}` };\n if (await matchingTarget()) {\n check();\n return result;\n }\n // ponytail: the port has no no-replace rename; the queue and checks protect HTTP callers, not hostile\n // concurrent host filesystem writers. Upgrade to a no-replace FileSystem capability when available.\n const temporary = join(directory, `.image-promotion-${randomUUID()}.tmp`);\n if (getOrThrow(await fs.exists(temporary, context))) throw new Error('Image copy temporary name is in use.');\n try {\n check();\n getOrThrow(await fs.writeFile(temporary, bytes, context));\n await safeDirectory(root);\n await safeDirectory(directory);\n check();\n if (!(await matchingTarget())) {\n check();\n getOrThrow(await fs.renameFile(temporary, target, context));\n }\n check();\n return result;\n } finally {\n getOrThrow(await fs.remove(temporary, { force: true }, BACKGROUND_CONTEXT));\n }\n });\n pending = run;\n return run;\n };\n}\n\nasync function readPng(\n fs: FileSystem,\n path: string,\n context: Parameters<FileSystem['fileInfo']>[1],\n): Promise<Uint8Array> {\n const info = getOrThrow(await fs.fileInfo(path, context));\n if (info.kind !== 'file' || getOrThrow(await fs.canonicalPath(path, context)) !== resolve(path))\n throw new Error('Unsafe image file.');\n const reader = getOrThrow(await fs.openBinaryReader(path, { noFollow: true }, context));\n try {\n const before = getOrThrow(await reader.info(context));\n if (before.size < PNG_SIGNATURE.length || before.size > MAX_REFERENCE_BYTES)\n throw new Error('Image exceeds the size limit or is empty.');\n const data = getOrThrow(await reader.read(0, before.size, context));\n const after = getOrThrow(await reader.info(context));\n if (data.length !== before.size || before.size !== after.size || before.mtimeMs !== after.mtimeMs)\n throw new Error('Image changed during access.');\n if (!Buffer.from(data.subarray(0, PNG_SIGNATURE.length)).equals(PNG_SIGNATURE))\n throw new Error('Image is not a PNG.');\n return data;\n } finally {\n await reader.close(BACKGROUND_CONTEXT);\n }\n}\n","// Type-only imports: the native bundle loads this file and may not import po-core/web at runtime.\nimport type { ApiResponseOf, ApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = {\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: undefined as unknown as ApiResponseOf<ImageArtifactList>,\n },\n promoteImage: {\n method: 'POST',\n path: '/promote',\n response: undefined as unknown as ApiResponseOf<{ sessionId: string; path: string }>,\n },\n readImage: {\n method: 'GET',\n path: '/artifact',\n query: ['id', 'toolCallId', 'offset', 'count', 'sourceSha256'],\n response: undefined as unknown as ApiResponseOf<ImageArtifact>,\n },\n} as const satisfies ApiRoutes;\nexport default routes;\n","import type { PoApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport { createImagePromotion } from '../../../../../../../services/imagePromotion';\nimport type { ImagePromotionBinding } from '../../../../../../../services/imagePromotion/type';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(\n home: string,\n binding: () => ImagePromotionBinding | undefined = () => undefined,\n lifetime?: AbortSignal,\n): PoApi {\n return {\n basePath: 'images',\n start(context) {\n if (context.scope !== 'session' || !context.sessionId) throw new Error('Images require a session mount.');\n const sessionId = context.sessionId;\n const controller = new AbortController();\n const signal = lifetime ? AbortSignal.any([lifetime, controller.signal]) : controller.signal;\n const promote = createImagePromotion(home, sessionId, context.environment ?? {}, binding, signal);\n return {\n close() {\n controller.abort();\n },\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET' && !(request.method === 'POST' && url.pathname === routes.promoteImage.path))\n return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n if (url.pathname === routes.promoteImage.path) {\n if (request.method !== 'POST') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n // Small ID-only body. No path, directory, root or session selectors are admitted.\n const reader = request.body?.getReader();\n if (!reader) return Response.json({ error: 'Provide an image identity.' }, { status: 400 });\n let text = '';\n let size = 0;\n try {\n const decoder = new TextDecoder();\n while (true) {\n const chunk = await reader.read();\n if (chunk.done) break;\n size += chunk.value.byteLength;\n if (size > 1024) return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n text += decoder.decode(chunk.value, { stream: true });\n }\n text += decoder.decode();\n } finally {\n await reader.cancel();\n }\n let body: unknown;\n try {\n body = JSON.parse(text);\n } catch {\n return Response.json({ error: 'Invalid image identity.' }, { status: 400 });\n }\n if (\n typeof body !== 'object' ||\n body === null ||\n Array.isArray(body) ||\n Object.keys(body).length !== 1 ||\n !('id' in body) ||\n typeof body.id !== 'string' ||\n !/^[A-Za-z0-9_-]{1,128}$/u.test(body.id) ||\n url.search\n ) {\n return Response.json({ error: 'Provide only an image identity.' }, { status: 400 });\n }\n try {\n result = await promote(body.id, request.signal);\n } catch (error) {\n request.signal.throwIfAborted();\n return Response.json(\n { error: error instanceof Error ? error.message : 'Image could not be copied.' },\n { status: 409 },\n );\n }\n } else if (url.pathname === routes.listImages.path) {\n const limit = url.searchParams.get('limit');\n const cursor = url.searchParams.get('cursor');\n if ((limit !== null && !/^\\d+$/u.test(limit)) || (cursor !== null && !/^\\d+$/u.test(cursor)))\n return Response.json({ error: 'Invalid image page.' }, { status: 400 });\n result = await listImageArtifacts(\n home,\n sessionId,\n limit === null ? 6 : Number(limit),\n cursor === null ? 0 : Number(cursor),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n );\n } else if (url.pathname === routes.readImage.path) {\n const id = url.searchParams.get('id');\n const call = url.searchParams.get('toolCallId');\n if ((id === null) === (call === null) || (call !== null && (!call || call.length > 16384)))\n return Response.json({ error: 'Provide exactly one image identity.' }, { status: 400 });\n const offset = url.searchParams.get('offset');\n const count = url.searchParams.get('count');\n const sourceSha256 = url.searchParams.get('sourceSha256');\n const chunked = offset !== null || count !== null || sourceSha256 !== null;\n if (chunked && (offset === null || count === null || !/^\\d+$/u.test(offset) || !/^\\d+$/u.test(count)))\n return Response.json({ error: 'Invalid image chunk.' }, { status: 400 });\n result = await readImageArtifact(\n home,\n sessionId,\n id ?? imageArtifactIdForCall(call!),\n request.signal,\n context.environment?.PO_SESSION_TEMP_DIR,\n chunked\n ? { offset: Number(offset), count: Number(count), ...(sourceSha256 !== null ? { sourceSha256 } : {}) }\n : undefined,\n );\n } else return Response.json({ error: 'Not found.' }, { status: 404 });\n return Response.json(result, {\n headers: { 'cache-control': 'no-store', 'x-content-type-options': 'nosniff' },\n });\n } catch (error) {\n request.signal.throwIfAborted();\n if (error instanceof ImageArtifactError)\n return Response.json(\n { error: error.message },\n { status: error.message.startsWith('Invalid') ? 400 : 404 },\n );\n if (\n error instanceof Error &&\n 'code' in error &&\n ['ENOENT', 'ELOOP', 'ENOTDIR'].includes(String(error.code))\n )\n return Response.json({ error: 'Image not found.' }, { status: 404 });\n throw error;\n }\n },\n };\n },\n };\n}\n","import { defineRoute } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../../services/imagePromotion/type';\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n return createImageApi(\n poHomeDirectory(host.context.homeDirectory, host.context.environment ?? {}),\n () => promotion,\n signal,\n );\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { PO_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverPlugin';\n\nexport default defineResource({\n name: 'help-how-to-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: PO_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/help-how-to-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport { PO_FS_SERVICE, readPoFileAccess, requirePoFs } from '@agimon-ai/po-core/platform';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverPlugin';\n\nimport { imageArtifactDirectory } from '../../../../../services/imageArtifacts';\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\nimport { createImagePromotion } from '../../../../../services/imagePromotion';\nimport type { ImageArtifactStorage, ImagePromotionBinding } from '../../../../../services/imagePromotion/type';\n\nexport default defineServerTool(({ host, context, signal }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n const environment = host.context.environment ?? {};\n const home = poHomeDirectory(host.context.homeDirectory, environment);\n const temporaryDirectory = environment.PO_SESSION_TEMP_DIR;\n const sessionId = host.context.sessionId;\n // A paired client opens the images this tool writes, wherever the host put them; closes with the tool.\n const fileAccess = readPoFileAccess(context);\n if (fileAccess !== undefined && sessionId !== undefined) {\n const close = fileAccess.register(imageArtifactDirectory(home, sessionId, temporaryDirectory));\n context.effect(() => close, 'image generation file access');\n }\n if (sessionId === undefined) return createImagegenTool(home, temporaryDirectory);\n // Every generated image also lands in the session's artifacts, so it is listed with the files Po made.\n let promotion: ImagePromotionBinding | undefined;\n context.inject([PO_FS_SERVICE, 'po/artifacts'], (child) => {\n const controller = new AbortController();\n const binding: ImagePromotionBinding = {\n fs: requirePoFs(child),\n storage: child.get('po/artifacts') as ImageArtifactStorage,\n signal: AbortSignal.any([signal, controller.signal]),\n };\n promotion = binding;\n return () => {\n controller.abort();\n if (promotion === binding) promotion = undefined;\n };\n });\n const promote = createImagePromotion(home, sessionId, environment, () => promotion, signal);\n return createImagegenTool(home, temporaryDirectory, promote);\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverPlugin';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourceHelpHowToImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/help-how-to-image-gen.server';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(backend)/tool/imagegen.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;\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const serverPlugin = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): PoServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): PoServerSessionPlugin['resources'] { return [at(resourceHelpHowToImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default serverPlugin;\n"],"mappings":"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"}
|