@agimon-ai/po-image-gen 0.0.0-alpha.2 → 0.0.0-alpha.3

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.
@@ -80,7 +80,7 @@ var route_server_default = (0, _agimon_ai_po_core_extensionFile.defineRoute)(({
80
80
  var po_use_image_gen_server_default = (0, _agimon_ai_po_core_extensionFile.defineResource)({
81
81
  name: "po-use-image-gen",
82
82
  description: "Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.",
83
- when: _agimon_ai_po_core_help.DOOM_HELP_WHEN,
83
+ when: _agimon_ai_po_core_help.PO_HELP_WHEN,
84
84
  kind: "skill",
85
85
  path: (0, _agimon_ai_po_core_serverFacet.packageResourcePath)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-image-gen/SKILL.md"),
86
86
  read: () => (0, _agimon_ai_po_core_serverFacet.readPackageResource)(require("url").pathToFileURL(__filename).href, "src/prompts/po-use-image-gen/SKILL.md")
@@ -1 +1 @@
1
- {"version":3,"file":"server.cjs","names":["defineApiRoutes","apiResponse","listImageArtifacts","readImageArtifact","imageArtifactIdForCall","ImageArtifactError","defineRoute","poHomeDirectory","defineResource","DOOM_HELP_WHEN","packageResourcePath","readPackageResource","defineServerTool","createImagegenTool","poHomeDirectory","defineServerPlugin","apiRoute","resourcePoUseImageGen","toolImagegen"],"sources":["../../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/po-use-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\nexport default routes;\n","import type { DoomApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(home: string): DoomApi {\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 return {\n close() {},\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n 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 );\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 result = await readImageArtifact(home, sessionId, id ?? imageArtifactIdForCall(call!), request.signal);\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 type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host }: DoomServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n return createImageApi(poHomeDirectory(host.context.homeDirectory));\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { DOOM_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineResource({\n name: 'po-use-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: DOOM_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host }: DoomServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n return createImagegenTool(poHomeDirectory(host.context.homeDirectory));\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourcePoUseImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/po-use-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 facet = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourcePoUseImageGen, context)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.cjs","names":["defineApiRoutes","apiResponse","listImageArtifacts","readImageArtifact","imageArtifactIdForCall","ImageArtifactError","defineRoute","poHomeDirectory","defineResource","PO_HELP_WHEN","packageResourcePath","readPackageResource","defineServerTool","createImagegenTool","poHomeDirectory","defineServerPlugin","apiRoute","resourcePoUseImageGen","toolImagegen"],"sources":["../../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/po-use-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\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 routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(home: string): 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 return {\n close() {},\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n 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 );\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 result = await readImageArtifact(home, sessionId, id ?? imageArtifactIdForCall(call!), request.signal);\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 type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n return createImageApi(poHomeDirectory(host.context.homeDirectory));\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/serverFacet';\n\nexport default defineResource({\n name: 'po-use-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/po-use-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n return createImagegenTool(poHomeDirectory(host.context.homeDirectory));\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourcePoUseImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/po-use-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 facet = 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(resourcePoUseImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  //#region generated/server.d.ts
2
- export declare const facet: import("@agimon-ai/po-core/serverFacet").DoomServerFacet;
2
+ export declare const facet: import("@agimon-ai/po-core/serverFacet").PoServerFacet;
3
3
  //#endregion
4
4
  export { facet as default };
5
5
  //# sourceMappingURL=server.d.mts.map
@@ -3,7 +3,7 @@ import { defineServerPlugin, packageResourcePath, readPackageResource } from "@a
3
3
  import { defineResource, defineRoute, defineServerTool } from "@agimon-ai/po-core/extensionFile";
4
4
  import { poHomeDirectory } from "@agimon-ai/po-core/piSettings";
5
5
  import { apiResponse, defineApiRoutes } from "@agimon-ai/po-core/web";
6
- import { DOOM_HELP_WHEN } from "@agimon-ai/po-core/help";
6
+ import { PO_HELP_WHEN } from "@agimon-ai/po-core/help";
7
7
  //#region src/types/apiRoutes.ts
8
8
  const routes = defineApiRoutes({
9
9
  listImages: {
@@ -76,7 +76,7 @@ var route_server_default = defineRoute(({ host }) => {
76
76
  var po_use_image_gen_server_default = defineResource({
77
77
  name: "po-use-image-gen",
78
78
  description: "Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.",
79
- when: DOOM_HELP_WHEN,
79
+ when: PO_HELP_WHEN,
80
80
  kind: "skill",
81
81
  path: packageResourcePath(import.meta.url, "src/prompts/po-use-image-gen/SKILL.md"),
82
82
  read: () => readPackageResource(import.meta.url, "src/prompts/po-use-image-gen/SKILL.md")
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":["apiRoute","resourcePoUseImageGen","toolImagegen"],"sources":["../../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/po-use-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\nexport default routes;\n","import type { DoomApi } from '@agimon-ai/po-core/packageApi';\n\nimport {\n ImageArtifactError,\n imageArtifactIdForCall,\n listImageArtifacts,\n readImageArtifact,\n} from '../../../../../../../services/imageArtifacts';\nimport routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(home: string): DoomApi {\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 return {\n close() {},\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n 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 );\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 result = await readImageArtifact(home, sessionId, id ?? imageArtifactIdForCall(call!), request.signal);\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 type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host }: DoomServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n return createImageApi(poHomeDirectory(host.context.homeDirectory));\n});\n","// @scaffold-generated\nimport { defineResource } from '@agimon-ai/po-core/extensionFile';\nimport { DOOM_HELP_WHEN } from '@agimon-ai/po-core/help';\nimport { packageResourcePath, readPackageResource } from '@agimon-ai/po-core/serverFacet';\n\nexport default defineResource({\n name: 'po-use-image-gen',\n description: 'Use @agimon-ai/po-image-gen: Generate and edit images using a ChatGPT subscription.',\n when: DOOM_HELP_WHEN,\n kind: 'skill' as const,\n path: packageResourcePath(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport type { DoomServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host }: DoomServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n return createImagegenTool(poHomeDirectory(host.context.homeDirectory));\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type DoomServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourcePoUseImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/po-use-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 facet = defineServerPlugin({\n name: '@agimon-ai/po-image-gen',\n session: (context) => ({\n get api(): DoomServerSessionPlugin['api'] { return [at(apiRoute, context)]; },\n get resources(): DoomServerSessionPlugin['resources'] { return [at(resourcePoUseImageGen, context)]; },\n get tools(): DoomServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":["apiRoute","resourcePoUseImageGen","toolImagegen"],"sources":["../../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/po-use-image-gen.server.ts","../../src/extensions/workspaces/sessions/(backend)/tool/imagegen.server.ts","../../generated/server.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\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 routes from '../../../../../../../types/apiRoutes';\n\n/** Owner authentication and session admission are enforced by the host mount. */\nexport function createImageApi(home: string): 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 return {\n close() {},\n async fetch(request) {\n const url = new URL(request.url);\n if (request.method !== 'GET') return Response.json({ error: 'Method not allowed.' }, { status: 405 });\n try {\n let result;\n 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 );\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 result = await readImageArtifact(home, sessionId, id ?? imageArtifactIdForCall(call!), request.signal);\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 type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImageApi } from './_lib/imageApi';\n\nexport default defineRoute(({ host }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Images require the configured server home.');\n return createImageApi(poHomeDirectory(host.context.homeDirectory));\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/serverFacet';\n\nexport default defineResource({\n name: 'po-use-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/po-use-image-gen/SKILL.md'),\n read: () => readPackageResource(import.meta.url, 'src/prompts/po-use-image-gen/SKILL.md'),\n});\n","import { defineServerTool } from '@agimon-ai/po-core/extensionFile';\nimport { poHomeDirectory } from '@agimon-ai/po-core/piSettings';\nimport type { PoServerPluginContext } from '@agimon-ai/po-core/serverFacet';\n\nimport { createImagegenTool } from '../../../../../services/imagegenTool';\n\nexport default defineServerTool(({ host }: PoServerPluginContext) => {\n if (!host.context.homeDirectory) throw new Error('Image generation requires the configured server home.');\n return createImagegenTool(poHomeDirectory(host.context.homeDirectory));\n});\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineServerPlugin, type PoServerSessionPlugin } from '@agimon-ai/po-core/serverFacet';\n\nimport apiRoute from '../src/extensions/workspaces/sessions/(backend)/api/images/route.server';\nimport resourcePoUseImageGen from '../src/extensions/workspaces/sessions/(backend)/resource/po-use-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 facet = 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(resourcePoUseImageGen, context)]; },\n get tools(): PoServerSessionPlugin['tools'] { return [via({ name: 'imagegen' }, at(toolImagegen, context))]; },\n }),\n});\n\nexport default facet;\n"],"mappings":";;;;;;;AAIA,MAAa,SAAS,gBAAgB;CACpC,YAAY;EACV,QAAQ;EACR,MAAM;EACN,OAAO,CAAC,SAAS,QAAQ;EACzB,UAAU,YAA+B;CAC3C;CACA,WAAW;EAAE,QAAQ;EAAO,MAAM;EAAa,OAAO,CAAC,MAAM,YAAY;EAAG,UAAU,YAA2B;CAAE;AACrH,CAAC;;;;ACDD,SAAgB,eAAe,MAAqB;CAClD,OAAO;EACL,UAAU;EACV,MAAM,SAAS;GACb,IAAI,QAAQ,UAAU,aAAa,CAAC,QAAQ,WAAW,MAAM,IAAI,MAAM,iCAAiC;GACxG,MAAM,YAAY,QAAQ;GAC1B,OAAO;IACL,QAAQ,CAAC;IACT,MAAM,MAAM,SAAS;KACnB,MAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;KAC/B,IAAI,QAAQ,WAAW,OAAO,OAAO,SAAS,KAAK,EAAE,OAAO,sBAAsB,GAAG,EAAE,QAAQ,IAAI,CAAC;KACpG,IAAI;MACF,IAAI;MACJ,IAAI,IAAI,aAAa,OAAO,WAAW,MAAM;OAC3C,MAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;OAC1C,MAAM,SAAS,IAAI,aAAa,IAAI,QAAQ;OAC5C,IAAK,UAAU,QAAQ,CAAC,SAAS,KAAK,KAAK,KAAO,WAAW,QAAQ,CAAC,SAAS,KAAK,MAAM,GACxF,OAAO,SAAS,KAAK,EAAE,OAAO,sBAAsB,GAAG,EAAE,QAAQ,IAAI,CAAC;OACxE,SAAS,MAAM,mBACb,MACA,WACA,UAAU,OAAO,IAAI,OAAO,KAAK,GACjC,WAAW,OAAO,IAAI,OAAO,MAAM,GACnC,QAAQ,MACV;MACF,OAAO,IAAI,IAAI,aAAa,OAAO,UAAU,MAAM;OACjD,MAAM,KAAK,IAAI,aAAa,IAAI,IAAI;OACpC,MAAM,OAAO,IAAI,aAAa,IAAI,YAAY;OAC9C,IAAK,OAAO,UAAW,SAAS,SAAU,SAAS,SAAS,CAAC,QAAQ,KAAK,SAAS,QACjF,OAAO,SAAS,KAAK,EAAE,OAAO,sCAAsC,GAAG,EAAE,QAAQ,IAAI,CAAC;OACxF,SAAS,MAAM,kBAAkB,MAAM,WAAW,MAAM,uBAAuB,IAAK,GAAG,QAAQ,MAAM;MACvG,OAAO,OAAO,SAAS,KAAK,EAAE,OAAO,aAAa,GAAG,EAAE,QAAQ,IAAI,CAAC;MACpE,OAAO,SAAS,KAAK,QAAQ,EAC3B,SAAS;OAAE,iBAAiB;OAAY,0BAA0B;MAAU,EAC9E,CAAC;KACH,SAAS,OAAO;MACd,QAAQ,OAAO,eAAe;MAC9B,IAAI,iBAAiB,oBACnB,OAAO,SAAS,KACd,EAAE,OAAO,MAAM,QAAQ,GACvB,EAAE,QAAQ,MAAM,QAAQ,WAAW,SAAS,IAAI,MAAM,IAAI,CAC5D;MACF,IACE,iBAAiB,SACjB,UAAU,SACV;OAAC;OAAU;OAAS;MAAS,CAAC,CAAC,SAAS,OAAO,MAAM,IAAI,CAAC,GAE1D,OAAO,SAAS,KAAK,EAAE,OAAO,mBAAmB,GAAG,EAAE,QAAQ,IAAI,CAAC;MACrE,MAAM;KACR;IACF;GACF;EACF;CACF;AACF;;;AC3DA,IAAA,uBAAe,aAAa,EAAE,WAAkC;CAC9D,IAAI,CAAC,KAAK,QAAQ,eAAe,MAAM,IAAI,MAAM,4CAA4C;CAC7F,OAAO,eAAe,gBAAgB,KAAK,QAAQ,aAAa,CAAC;AACnE,CAAC;;;ACJD,IAAA,kCAAe,eAAe;CAC5B,MAAM;CACN,aAAa;CACb,MAAM;CACN,MAAM;CACN,MAAM,oBAAoB,YAAY,KAAK,uCAAuC;CAClF,YAAY,oBAAoB,YAAY,KAAK,uCAAuC;AAC1F,CAAC;;;ACND,IAAA,0BAAe,kBAAkB,EAAE,WAAkC;CACnE,IAAI,CAAC,KAAK,QAAQ,eAAe,MAAM,IAAI,MAAM,uDAAuD;CACxG,OAAO,mBAAmB,gBAAgB,KAAK,QAAQ,aAAa,CAAC;AACvE,CAAC;;;ACDD,MAAM,MAAY,OAA0B,YAC1C,OAAO,UAAU,aAAc,MAAwB,OAAO,IAAI;AACpE,MAAM,OAAU,UAAmC,UAChD,UAAU,KAAA,IAAY,KAAA,IAAY;CAAE,GAAG;CAAU,GAAI;AAAiB;AAEzE,MAAa,QAAQ,mBAAmB;CACtC,MAAM;CACN,UAAU,aAAa;EACrB,IAAI,MAAoC;GAAE,OAAO,CAAC,GAAGA,sBAAU,OAAO,CAAC;EAAG;EAC1E,IAAI,YAAgD;GAAE,OAAO,CAAC,GAAGC,iCAAuB,OAAO,CAAC;EAAG;EACnG,IAAI,QAAwC;GAAE,OAAO,CAAC,IAAI,EAAE,MAAM,WAAW,GAAG,GAAGC,yBAAc,OAAO,CAAC,CAAC;EAAG;CAC/G;AACF,CAAC"}
@@ -85,11 +85,11 @@ async function resolveTranscriptImage(sessionId, toolCallId, src, signal, inline
85
85
  function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore }) {
86
86
  if (state === "error") return /* @__PURE__ */ jsx("p", {
87
87
  role: "alert",
88
- className: "p-3 text-sm text-doom-red",
88
+ className: "p-3 text-sm text-po-red",
89
89
  children: error ?? "Images could not be loaded."
90
90
  });
91
91
  if (state === "ready" && images.length === 0) return /* @__PURE__ */ jsx("p", {
92
- className: "p-3 text-sm text-doom-dim",
92
+ className: "p-3 text-sm text-po-dim",
93
93
  children: "Images generated in this session will appear here."
94
94
  });
95
95
  const visible = variant === "activity" ? images.slice(0, 6) : images;
@@ -103,13 +103,13 @@ function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore
103
103
  onClick: () => onOpen(image.id),
104
104
  title: image.label,
105
105
  "aria-label": `Open ${image.label}`,
106
- className: "group min-w-0 overflow-hidden rounded-md border border-doom-border bg-doom-deep focus-visible:outline-2 focus-visible:outline-doom-selected",
106
+ className: "group min-w-0 overflow-hidden rounded-md border border-po-border bg-po-deep focus-visible:outline-2 focus-visible:outline-po-selected",
107
107
  children: [image.src ? /* @__PURE__ */ jsx("img", {
108
108
  src: image.src,
109
109
  alt: image.label,
110
110
  className: "aspect-square w-full object-cover transition-opacity group-hover:opacity-80"
111
111
  }) : /* @__PURE__ */ jsx(Skeleton, { className: "aspect-square w-full" }), variant === "gallery" ? /* @__PURE__ */ jsx("span", {
112
- className: "block truncate px-2 py-2 text-sm text-doom-text",
112
+ className: "block truncate px-2 py-2 text-sm text-po-text",
113
113
  children: image.label
114
114
  }) : null]
115
115
  }, image.id))
@@ -126,13 +126,13 @@ function ImageViewerView({ image, state, error, feedback }) {
126
126
  className: "flex h-full min-h-0 flex-col gap-3 overflow-y-auto p-4",
127
127
  children: [
128
128
  /* @__PURE__ */ jsx("h2", {
129
- className: "truncate text-lg font-semibold text-doom-hi",
129
+ className: "truncate text-lg font-semibold text-po-hi",
130
130
  title: image.label,
131
131
  children: image.label
132
132
  }),
133
133
  feedback ? feedback : state === "error" ? /* @__PURE__ */ jsx("p", {
134
134
  role: "alert",
135
- className: "text-sm text-doom-red",
135
+ className: "text-sm text-po-red",
136
136
  children: error ?? "This image could not be loaded."
137
137
  }) : state === "loading" || !image.src ? /* @__PURE__ */ jsx(Skeleton, { className: "h-64 w-full rounded-md" }) : /* @__PURE__ */ jsx(MediaPreview, {
138
138
  src: image.src,
@@ -142,7 +142,7 @@ function ImageViewerView({ image, state, error, feedback }) {
142
142
  className: "min-h-0 flex-1 object-contain"
143
143
  }),
144
144
  !feedback ? /* @__PURE__ */ jsx("p", {
145
- className: "text-sm text-doom-dim",
145
+ className: "text-sm text-po-dim",
146
146
  children: "Original image, read only."
147
147
  }) : null
148
148
  ]
@@ -194,11 +194,11 @@ function ImagesGallery(props) {
194
194
  "aria-label": "Session image gallery",
195
195
  children: [
196
196
  /* @__PURE__ */ jsx("h2", {
197
- className: "text-lg font-semibold text-doom-hi",
197
+ className: "text-lg font-semibold text-po-hi",
198
198
  children: "Images"
199
199
  }),
200
200
  /* @__PURE__ */ jsx("p", {
201
- className: "text-sm text-doom-dim",
201
+ className: "text-sm text-po-dim",
202
202
  children: "Generated in this session, newest first."
203
203
  }),
204
204
  /* @__PURE__ */ jsx(SessionImages, {
@@ -348,7 +348,7 @@ function SessionImageViewer(props) {
348
348
  }) : void 0
349
349
  })
350
350
  }), props.image.inlineData ? /* @__PURE__ */ jsx("p", {
351
- className: "px-4 pb-4 text-sm text-doom-dim",
351
+ className: "px-4 pb-4 text-sm text-po-dim",
352
352
  children: "This inline image was not saved. Original-path refinement is unavailable."
353
353
  }) : null]
354
354
  });
@@ -411,10 +411,10 @@ function ImagegenToolMessage(props) {
411
411
  title: "imagegen",
412
412
  children: [/* @__PURE__ */ jsx("span", {
413
413
  "data-testid": "tool-call-imagegen",
414
- className: "min-w-0 flex-1 truncate text-doom-text",
414
+ className: "min-w-0 flex-1 truncate text-po-text",
415
415
  children: view.prompt
416
416
  }), /* @__PURE__ */ jsx("span", {
417
- className: "shrink-0 text-doom-faint",
417
+ className: "shrink-0 text-po-faint",
418
418
  children: view.editing ? "edit" : "generate"
419
419
  })]
420
420
  }), expanded ? /* @__PURE__ */ jsxs(MessageItemBody, {
@@ -433,7 +433,7 @@ function ImagegenToolMessage(props) {
433
433
  type: "button",
434
434
  "aria-label": `Open ${view.prompt || "generated image"}`,
435
435
  disabled: opening || props.sessionId === null,
436
- className: "max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-doom-selected",
436
+ className: "max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-po-selected",
437
437
  onClick: async () => {
438
438
  if (props.sessionId === null || !view.src || opening) return;
439
439
  const controller = new AbortController();
@@ -458,11 +458,11 @@ function ImagegenToolMessage(props) {
458
458
  }) : null,
459
459
  openError ? /* @__PURE__ */ jsx("p", {
460
460
  role: "alert",
461
- className: "text-sm text-doom-red",
461
+ className: "text-sm text-po-red",
462
462
  children: openError
463
463
  }) : null,
464
464
  resultTextLines(result, output).map((line, index) => /* @__PURE__ */ jsx("span", {
465
- className: `whitespace-pre-wrap break-words ${isError ? "text-doom-red" : "text-doom-dim"}`,
465
+ className: `whitespace-pre-wrap break-words ${isError ? "text-po-red" : "text-po-dim"}`,
466
466
  children: line
467
467
  }, `${String(index)}-${line}`))
468
468
  ]
@@ -1 +1 @@
1
- {"version":3,"file":"web.mjs","names":["activityGroupImages","fillImages","toolImagegen"],"sources":["../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/constants/imagegen.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imageFeedback.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/sessionImagesApi.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImagesView.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImages.tsx","../../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imagegenToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ImagegenToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web.tsx","../../generated/web.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/po-core/web';\nimport { sealedTransport } from '@agimon-ai/po-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'images' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'images',\n transport: (input, init) => sealedTransport.fetch(input, init),\n sessionAddress: sessionApiAddress,\n});\n","export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import type { SlotDeclaration, WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport type { ComponentType } from 'react';\n\nimport { MAX_REFERENCE_BYTES } from '../../../../../../constants/imagegen';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\n\ninterface ImageFeedbackContribution {\n version: 1;\n panel: ComponentType<WebPluginSlotProps & { target: ImageArtifact }>;\n}\n\nexport const imageFeedbackSlot = {\n slot: 'author.image-feedback',\n parse(input) {\n if (input === null || typeof input !== 'object') return null;\n const value = input as Partial<ImageFeedbackContribution>;\n return value.version === 1 && typeof value.panel === 'function' ? (value as ImageFeedbackContribution) : null;\n },\n} satisfies SlotDeclaration<ImageFeedbackContribution>;\n\n/** Inline save failures are preview bytes, never filesystem authority. */\nexport function inlineImageData(src: string | undefined): string | undefined {\n const prefix = 'data:image/png;base64,';\n if (src === undefined || !src.startsWith(prefix)) return undefined;\n const data = src.slice(prefix.length);\n if (\n data.length === 0 ||\n data.length > Math.ceil(MAX_REFERENCE_BYTES / 3) * 4 ||\n !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)\n )\n return undefined;\n try {\n const bytes = atob(data);\n return bytes.length <= MAX_REFERENCE_BYTES && bytes.startsWith('\\x89PNG\\r\\n\\x1a\\n') ? data : undefined;\n } catch {\n return undefined;\n }\n}\n","import { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { inlineImageData } from './imageFeedback';\n\n/** Resolve transcript identity at the session boundary, not from result metadata paths. */\nexport async function resolveTranscriptImage(\n sessionId: string,\n toolCallId: string,\n src: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<{ id: string; artifact?: ImageArtifact; inlineData?: string }> {\n if (inlineOnly) {\n signal.throwIfAborted();\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n }\n const response = await api.session(sessionId).readImage({ query: { toolCallId }, signal });\n signal.throwIfAborted();\n if (response.ok) {\n if (response.data.sessionId !== sessionId) throw new Error('Image belongs to another session.');\n return { id: response.data.id, artifact: response.data };\n }\n if (response.status !== 404) throw new Error(response.error || 'This image could not be loaded.');\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n}\n","import { Button, MediaPreview, Skeleton } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nexport interface ImageTile {\n id: string;\n label: string;\n src?: string;\n}\n\nexport interface ImagesGridViewProps {\n images: readonly ImageTile[];\n state: 'ready' | 'loading' | 'error';\n error?: string;\n onOpen: (id: string) => void;\n variant: 'activity' | 'gallery';\n hasMore?: boolean;\n onMore?: () => void;\n}\n\n/** Presentation only. The session container owns metadata and verified image URLs. */\nexport function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore }: ImagesGridViewProps) {\n if (state === 'error')\n return (\n <p role=\"alert\" className=\"p-3 text-sm text-doom-red\">\n {error ?? 'Images could not be loaded.'}\n </p>\n );\n if (state === 'ready' && images.length === 0)\n return <p className=\"p-3 text-sm text-doom-dim\">Images generated in this session will appear here.</p>;\n const visible = variant === 'activity' ? images.slice(0, 6) : images;\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"grid grid-cols-3 gap-2\">\n {state === 'loading' && visible.length === 0\n ? Array.from({ length: 6 }, (_, index) => <Skeleton key={index} className=\"aspect-square rounded-md\" />)\n : visible.map((image) => (\n <button\n key={image.id}\n data-testid={`image-thumbnail-${image.id}`}\n type=\"button\"\n onClick={() => onOpen(image.id)}\n title={image.label}\n aria-label={`Open ${image.label}`}\n className=\"group min-w-0 overflow-hidden rounded-md border border-doom-border bg-doom-deep focus-visible:outline-2 focus-visible:outline-doom-selected\"\n >\n {image.src ? (\n <img\n src={image.src}\n alt={image.label}\n className=\"aspect-square w-full object-cover transition-opacity group-hover:opacity-80\"\n />\n ) : (\n <Skeleton className=\"aspect-square w-full\" />\n )}\n {variant === 'gallery' ? (\n <span className=\"block truncate px-2 py-2 text-sm text-doom-text\">{image.label}</span>\n ) : null}\n </button>\n ))}\n </div>\n {hasMore ? (\n <Button variant=\"outline\" onClick={onMore} disabled={state === 'loading'}>\n Load more images\n </Button>\n ) : null}\n </div>\n );\n}\n\nexport interface ImageViewerViewProps {\n image: ImageTile;\n state: 'ready' | 'loading' | 'error';\n error?: string;\n feedback?: ReactNode;\n}\n\nexport function ImageViewerView({ image, state, error, feedback }: ImageViewerViewProps) {\n return (\n <section className=\"flex h-full min-h-0 flex-col gap-3 overflow-y-auto p-4\">\n <h2 className=\"truncate text-lg font-semibold text-doom-hi\" title={image.label}>\n {image.label}\n </h2>\n {feedback ? (\n feedback\n ) : state === 'error' ? (\n <p role=\"alert\" className=\"text-sm text-doom-red\">\n {error ?? 'This image could not be loaded.'}\n </p>\n ) : state === 'loading' || !image.src ? (\n <Skeleton className=\"h-64 w-full rounded-md\" />\n ) : (\n <MediaPreview\n src={image.src}\n path={`${image.label}.png`}\n kind=\"image\"\n contentType=\"image/png\"\n className=\"min-h-0 flex-1 object-contain\"\n />\n )}\n {!feedback ? <p className=\"text-sm text-doom-dim\">Original image, read only.</p> : null}\n </section>\n );\n}\n","import { type TransientTab, type WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { imageFeedbackSlot } from '../_lib/imageFeedback';\nimport { resolveTranscriptImage } from '../_lib/sessionImagesApi';\nimport { ImagesGridView, ImageViewerView, type ImageTile } from './SessionImagesView';\n\nexport function imagesGalleryTab(): TransientTab {\n return { id: 'image-gen-gallery', label: 'Images', panel: ImagesGallery };\n}\n\nfunction pngUrl(data: string): string {\n const bytes = Uint8Array.from(atob(data), (character) => character.charCodeAt(0));\n return URL.createObjectURL(new Blob([bytes], { type: 'image/png' }));\n}\n\nexport function imageViewerTab(\n sessionId: string,\n image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string },\n): TransientTab {\n return {\n id: `${image.inlineData === undefined ? 'image-gen-image' : 'image-gen-inline'}-${encodeURIComponent(image.id)}`,\n label: image.label ?? `Image ${image.id}`,\n panel: (props) => (props.sessionId === sessionId ? <SessionImageViewer {...props} image={image} /> : null),\n };\n}\n\n/** Inline bytes are a fallback only when no durable artifact exists. */\nexport async function transcriptImageTab(\n sessionId: string,\n toolCallId: string,\n src: string,\n label: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<TransientTab> {\n const image = await resolveTranscriptImage(sessionId, toolCallId, src, signal, inlineOnly);\n return imageViewerTab(sessionId, { ...image, label });\n}\n\nexport function ImagesActivity(props: WebPluginSlotProps) {\n return (\n <div data-testid=\"session-images-activity\">\n <SessionImages {...props} variant=\"activity\" />\n </div>\n );\n}\n\nfunction ImagesGallery(props: WebPluginSlotProps) {\n return (\n <section\n data-testid=\"session-images-gallery\"\n className=\"h-full min-h-0 overflow-y-auto p-4\"\n aria-label=\"Session image gallery\"\n >\n <h2 className=\"text-lg font-semibold text-doom-hi\">Images</h2>\n <p className=\"text-sm text-doom-dim\">Generated in this session, newest first.</p>\n <SessionImages {...props} variant=\"gallery\" />\n </section>\n );\n}\n\nfunction SessionImages(props: WebPluginSlotProps & { variant: 'activity' | 'gallery' }) {\n if (props.sessionId === null) return null;\n return (\n <ImagesPage\n key={`${props.sessionId}:${props.statuses['image-gen.images'] ?? ''}`}\n {...props}\n sessionId={props.sessionId}\n />\n );\n}\n\nfunction ImagesPage(props: WebPluginSlotProps & { sessionId: string; variant: 'activity' | 'gallery' }) {\n const [images, setImages] = useState<ImageTile[]>([]);\n const [cursor, setCursor] = useState('0');\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n const [error, setError] = useState('');\n const urls = useRef<string[]>([]);\n useEffect(\n () => () => {\n for (const url of urls.current) URL.revokeObjectURL(url);\n },\n [],\n );\n useEffect(() => {\n const controller = new AbortController();\n setState('loading');\n void (async () => {\n const response = await api\n .session(props.sessionId)\n .listImages({ query: { limit: '6', cursor }, signal: controller.signal });\n if (!response.ok) throw new Error(response.error || 'Images could not be loaded.');\n if (response.data.sessionId !== props.sessionId) throw new Error('Image history belongs to another session.');\n const artifacts = await Promise.all(\n response.data.items.map(async ({ id }) => {\n const result = await api.session(props.sessionId).readImage({ query: { id }, signal: controller.signal });\n if (!result.ok) {\n if (result.status === 404) return null;\n throw new Error(result.error || 'An image could not be loaded.');\n }\n if (result.data.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n return result.data;\n }),\n );\n controller.signal.throwIfAborted();\n const tiles = artifacts.flatMap((artifact) => {\n if (!artifact) return [];\n const src = pngUrl(artifact.data);\n urls.current.push(src);\n return [{ id: artifact.id, label: `Image ${artifact.id}`, src }];\n });\n setImages((previous) =>\n cursor === '0' ? tiles : [...previous, ...tiles.filter((tile) => !previous.some(({ id }) => id === tile.id))],\n );\n setNextCursor(response.data.nextCursor);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'Images could not be loaded.');\n setState('error');\n });\n return () => controller.abort();\n }, [props.sessionId, cursor]);\n return (\n <ImagesGridView\n images={images}\n state={state}\n error={error}\n variant={props.variant}\n onOpen={(id) => props.openTransientTab(imageViewerTab(props.sessionId, { id }))}\n hasMore={props.variant === 'gallery' && nextCursor !== null}\n onMore={() => {\n if (nextCursor !== null && state !== 'loading') setCursor(nextCursor);\n }}\n />\n );\n}\n\nfunction SessionImageViewer(\n props: WebPluginSlotProps & { image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string } },\n) {\n const [artifact, setArtifact] = useState<ImageArtifact>();\n const [src, setSrc] = useState<string>();\n const [error, setError] = useState('');\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n useEffect(() => {\n const controller = new AbortController();\n let objectUrl: string | undefined;\n setArtifact(undefined);\n setSrc(undefined);\n setError('');\n setState('loading');\n void (async () => {\n if (props.sessionId === null) return;\n let data = props.image.inlineData;\n if (!data) {\n let target = props.image.artifact;\n if (!target) {\n const result = await api\n .session(props.sessionId)\n .readImage({ query: { id: props.image.id }, signal: controller.signal });\n if (!result.ok) throw new Error(result.error || 'This image could not be loaded.');\n target = result.data;\n }\n if (target.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n controller.signal.throwIfAborted();\n setArtifact(target);\n data = target.data;\n }\n controller.signal.throwIfAborted();\n objectUrl = pngUrl(data);\n setSrc(objectUrl);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'This image could not be loaded.');\n setState('error');\n });\n return () => {\n controller.abort();\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n };\n }, [props.sessionId, props.image]);\n const Panel =\n artifact && props.activeMinorModes?.includes('author')\n ? props.slotData(imageFeedbackSlot)[0]?.data.panel\n : undefined;\n return (\n <section data-testid=\"session-image-viewer\" data-image-id={props.image.id} className=\"flex h-full min-h-0 flex-col\">\n <div className=\"min-h-0 flex-1\">\n <ImageViewerView\n image={{ id: props.image.id, label: props.image.label ?? `Image ${props.image.id}`, src }}\n state={state}\n error={error}\n feedback={Panel && artifact ? <Panel {...props} target={artifact} /> : undefined}\n />\n </div>\n {props.image.inlineData ? (\n <p className=\"px-4 pb-4 text-sm text-doom-dim\">\n This inline image was not saved. Original-path refinement is unavailable.\n </p>\n ) : null}\n </section>\n );\n}\n","import { defineActivityGroup } from '@agimon-ai/po-core/web';\n\nimport { imagesGalleryTab } from '../tool/_components/SessionImages';\n\nexport default defineActivityGroup({\n name: 'Images',\n keys: '',\n activeSource: { subscribe: () => () => undefined, isActive: () => false },\n marksBackgroundWork: false,\n transientTab: imagesGalleryTab,\n order: 35,\n});\n","import { defineFill } from '@agimon-ai/po-core/web';\n\nimport { ImagesActivity } from '../tool/_components/SessionImages';\n\nexport default defineFill({ slot: 'activity.Images', component: ImagesActivity });\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\n\nexport function imagegenToolView({ args, result }: Pick<ToolMessageRenderProps, 'args' | 'result'>) {\n const prompt = typeof args.prompt === 'string' ? args.prompt : '';\n const editing = Array.isArray(args.referenced_image_paths) && args.referenced_image_paths.length > 0;\n // Only inline PNG results from this tool, never a URL supplied in details.\n const image = result?.content.find(\n (block): block is { type: 'image'; data: string; mimeType: 'image/png' } =>\n block !== null &&\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'image' &&\n 'mimeType' in block &&\n block.mimeType === 'image/png' &&\n 'data' in block &&\n typeof block.data === 'string',\n );\n const src = image ? `data:image/png;base64,${image.data}` : undefined;\n const details = result?.details;\n const inlineOnly =\n details !== null &&\n typeof details === 'object' &&\n 'saveWarning' in details &&\n typeof details.saveWarning === 'string';\n return { prompt, editing, src, inlineOnly };\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\nimport {\n MessageItem,\n MessageItemBody,\n MessageItemHeader,\n MessageItemStatus,\n resultTextLines,\n toolTone,\n} from '@agimon-ai/po-web-components';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { imagegenToolView } from '../_lib/imagegenToolView';\nimport { transcriptImageTab } from './SessionImages';\n\nexport function ImagegenToolMessage(props: ToolMessageRenderProps) {\n const { result, output, running, isError } = props;\n const view = imagegenToolView(props);\n const [opening, setOpening] = useState(false);\n const [openError, setOpenError] = useState('');\n const request = useRef<AbortController | undefined>(undefined);\n useEffect(() => {\n setOpening(false);\n setOpenError('');\n return () => request.current?.abort();\n }, [props.sessionId, props.toolCallId]);\n return (\n <MessageItem tone={toolTone({ running, isError })} expandable defaultExpanded>\n {({ expanded }) => (\n <>\n <MessageItemHeader title=\"imagegen\">\n <span data-testid=\"tool-call-imagegen\" className=\"min-w-0 flex-1 truncate text-doom-text\">\n {view.prompt}\n </span>\n <span className=\"shrink-0 text-doom-faint\">{view.editing ? 'edit' : 'generate'}</span>\n </MessageItemHeader>\n {expanded ? (\n <MessageItemBody data-testid=\"tool-result-imagegen\" className=\"flex flex-col gap-2\">\n {running ? <MessageItemStatus tone=\"running\">creating image</MessageItemStatus> : null}\n {isError ? <MessageItemStatus tone=\"error\">failed</MessageItemStatus> : null}\n {!isError && view.src ? (\n <button\n type=\"button\"\n aria-label={`Open ${view.prompt || 'generated image'}`}\n disabled={opening || props.sessionId === null}\n className=\"max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-doom-selected\"\n onClick={async () => {\n if (props.sessionId === null || !view.src || opening) return;\n const controller = new AbortController();\n request.current?.abort();\n request.current = controller;\n setOpening(true);\n setOpenError('');\n try {\n const tab = await transcriptImageTab(\n props.sessionId,\n props.toolCallId,\n view.src,\n view.prompt || 'Generated image',\n controller.signal,\n view.inlineOnly,\n );\n if (!controller.signal.aborted) props.openTransientTab(tab);\n } catch (reason) {\n if (!controller.signal.aborted)\n setOpenError(reason instanceof Error ? reason.message : 'This image could not be opened.');\n } finally {\n if (!controller.signal.aborted) setOpening(false);\n }\n }}\n >\n <img\n src={view.src}\n alt={view.prompt || 'Generated image'}\n className=\"max-h-96 max-w-full rounded-md object-contain\"\n />\n </button>\n ) : null}\n {openError ? (\n <p role=\"alert\" className=\"text-sm text-doom-red\">\n {openError}\n </p>\n ) : null}\n {resultTextLines(result, output).map((line, index) => (\n <span\n key={`${String(index)}-${line}`}\n className={`whitespace-pre-wrap break-words ${isError ? 'text-doom-red' : 'text-doom-dim'}`}\n >\n {line}\n </span>\n ))}\n </MessageItemBody>\n ) : null}\n </>\n )}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/po-core/web';\n\nimport { ImagegenToolMessage } from './_components/ImagegenToolMessage';\n\nexport default defineToolRenderer({ message: ImagegenToolMessage });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport activityGroupImages from '../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web';\nimport fillImages from '../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'image-gen',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'images' }, activityGroupImages)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.Images', id: 'images' }, fillImages)]; },\n get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['imagegen'] }, toolImagegen)]; },\n },\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"web.mjs","names":["activityGroupImages","fillImages","toolImagegen"],"sources":["../../src/types/apiRoutes.ts","../../generated/client.ts","../../src/constants/imagegen.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imageFeedback.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/sessionImagesApi.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImagesView.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/SessionImages.tsx","../../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web.ts","../../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/_lib/imagegenToolView.ts","../../src/extensions/workspaces/sessions/(frontend)/tool/_components/ImagegenToolMessage.tsx","../../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web.tsx","../../generated/web.ts"],"sourcesContent":["import { apiResponse, defineApiRoutes } from '@agimon-ai/po-core/web';\n\nimport type { ImageArtifact, ImageArtifactList } from './imageArtifacts';\n\nexport const routes = defineApiRoutes({\n listImages: {\n method: 'GET',\n path: '/artifacts',\n query: ['limit', 'cursor'],\n response: apiResponse<ImageArtifactList>(),\n },\n readImage: { method: 'GET', path: '/artifact', query: ['id', 'toolCallId'], response: apiResponse<ImageArtifact>() },\n});\nexport default routes;\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { createApiClient, sessionApiAddress } from '@agimon-ai/po-core/web';\nimport { sealedTransport } from '@agimon-ai/po-web-security/browser';\n\nimport routes from '../src/types/apiRoutes';\n\n/** Scopes the tree mounts 'images' at. */\nexport const apiScopes = ['session'] as const;\n\nexport const api = createApiClient(routes, {\n scopes: apiScopes,\n basePath: 'images',\n transport: (input, init) => sealedTransport.fetch(input, init),\n sessionAddress: sessionApiAddress,\n});\n","export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import type { SlotDeclaration, WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport type { ComponentType } from 'react';\n\nimport { MAX_REFERENCE_BYTES } from '../../../../../../constants/imagegen';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\n\ninterface ImageFeedbackContribution {\n version: 1;\n panel: ComponentType<WebPluginSlotProps & { target: ImageArtifact }>;\n}\n\nexport const imageFeedbackSlot = {\n slot: 'author.image-feedback',\n parse(input) {\n if (input === null || typeof input !== 'object') return null;\n const value = input as Partial<ImageFeedbackContribution>;\n return value.version === 1 && typeof value.panel === 'function' ? (value as ImageFeedbackContribution) : null;\n },\n} satisfies SlotDeclaration<ImageFeedbackContribution>;\n\n/** Inline save failures are preview bytes, never filesystem authority. */\nexport function inlineImageData(src: string | undefined): string | undefined {\n const prefix = 'data:image/png;base64,';\n if (src === undefined || !src.startsWith(prefix)) return undefined;\n const data = src.slice(prefix.length);\n if (\n data.length === 0 ||\n data.length > Math.ceil(MAX_REFERENCE_BYTES / 3) * 4 ||\n !/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(data)\n )\n return undefined;\n try {\n const bytes = atob(data);\n return bytes.length <= MAX_REFERENCE_BYTES && bytes.startsWith('\\x89PNG\\r\\n\\x1a\\n') ? data : undefined;\n } catch {\n return undefined;\n }\n}\n","import { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { inlineImageData } from './imageFeedback';\n\n/** Resolve transcript identity at the session boundary, not from result metadata paths. */\nexport async function resolveTranscriptImage(\n sessionId: string,\n toolCallId: string,\n src: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<{ id: string; artifact?: ImageArtifact; inlineData?: string }> {\n if (inlineOnly) {\n signal.throwIfAborted();\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n }\n const response = await api.session(sessionId).readImage({ query: { toolCallId }, signal });\n signal.throwIfAborted();\n if (response.ok) {\n if (response.data.sessionId !== sessionId) throw new Error('Image belongs to another session.');\n return { id: response.data.id, artifact: response.data };\n }\n if (response.status !== 404) throw new Error(response.error || 'This image could not be loaded.');\n const inlineData = inlineImageData(src);\n if (!inlineData) throw new Error('The inline image is not a valid bounded PNG.');\n return { id: `inline-${toolCallId}`, inlineData };\n}\n","import { Button, MediaPreview, Skeleton } from '@agimon-ai/po-web-components';\nimport type { ReactNode } from 'react';\n\nexport interface ImageTile {\n id: string;\n label: string;\n src?: string;\n}\n\nexport interface ImagesGridViewProps {\n images: readonly ImageTile[];\n state: 'ready' | 'loading' | 'error';\n error?: string;\n onOpen: (id: string) => void;\n variant: 'activity' | 'gallery';\n hasMore?: boolean;\n onMore?: () => void;\n}\n\n/** Presentation only. The session container owns metadata and verified image URLs. */\nexport function ImagesGridView({ images, state, error, onOpen, variant, hasMore, onMore }: ImagesGridViewProps) {\n if (state === 'error')\n return (\n <p role=\"alert\" className=\"p-3 text-sm text-po-red\">\n {error ?? 'Images could not be loaded.'}\n </p>\n );\n if (state === 'ready' && images.length === 0)\n return <p className=\"p-3 text-sm text-po-dim\">Images generated in this session will appear here.</p>;\n const visible = variant === 'activity' ? images.slice(0, 6) : images;\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"grid grid-cols-3 gap-2\">\n {state === 'loading' && visible.length === 0\n ? Array.from({ length: 6 }, (_, index) => <Skeleton key={index} className=\"aspect-square rounded-md\" />)\n : visible.map((image) => (\n <button\n key={image.id}\n data-testid={`image-thumbnail-${image.id}`}\n type=\"button\"\n onClick={() => onOpen(image.id)}\n title={image.label}\n aria-label={`Open ${image.label}`}\n className=\"group min-w-0 overflow-hidden rounded-md border border-po-border bg-po-deep focus-visible:outline-2 focus-visible:outline-po-selected\"\n >\n {image.src ? (\n <img\n src={image.src}\n alt={image.label}\n className=\"aspect-square w-full object-cover transition-opacity group-hover:opacity-80\"\n />\n ) : (\n <Skeleton className=\"aspect-square w-full\" />\n )}\n {variant === 'gallery' ? (\n <span className=\"block truncate px-2 py-2 text-sm text-po-text\">{image.label}</span>\n ) : null}\n </button>\n ))}\n </div>\n {hasMore ? (\n <Button variant=\"outline\" onClick={onMore} disabled={state === 'loading'}>\n Load more images\n </Button>\n ) : null}\n </div>\n );\n}\n\nexport interface ImageViewerViewProps {\n image: ImageTile;\n state: 'ready' | 'loading' | 'error';\n error?: string;\n feedback?: ReactNode;\n}\n\nexport function ImageViewerView({ image, state, error, feedback }: ImageViewerViewProps) {\n return (\n <section className=\"flex h-full min-h-0 flex-col gap-3 overflow-y-auto p-4\">\n <h2 className=\"truncate text-lg font-semibold text-po-hi\" title={image.label}>\n {image.label}\n </h2>\n {feedback ? (\n feedback\n ) : state === 'error' ? (\n <p role=\"alert\" className=\"text-sm text-po-red\">\n {error ?? 'This image could not be loaded.'}\n </p>\n ) : state === 'loading' || !image.src ? (\n <Skeleton className=\"h-64 w-full rounded-md\" />\n ) : (\n <MediaPreview\n src={image.src}\n path={`${image.label}.png`}\n kind=\"image\"\n contentType=\"image/png\"\n className=\"min-h-0 flex-1 object-contain\"\n />\n )}\n {!feedback ? <p className=\"text-sm text-po-dim\">Original image, read only.</p> : null}\n </section>\n );\n}\n","import { type TransientTab, type WebPluginSlotProps } from '@agimon-ai/po-core/web';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { api } from '../../../../../../../generated/client';\nimport type { ImageArtifact } from '../../../../../../types/imageArtifacts';\nimport { imageFeedbackSlot } from '../_lib/imageFeedback';\nimport { resolveTranscriptImage } from '../_lib/sessionImagesApi';\nimport { ImagesGridView, ImageViewerView, type ImageTile } from './SessionImagesView';\n\nexport function imagesGalleryTab(): TransientTab {\n return { id: 'image-gen-gallery', label: 'Images', panel: ImagesGallery };\n}\n\nfunction pngUrl(data: string): string {\n const bytes = Uint8Array.from(atob(data), (character) => character.charCodeAt(0));\n return URL.createObjectURL(new Blob([bytes], { type: 'image/png' }));\n}\n\nexport function imageViewerTab(\n sessionId: string,\n image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string },\n): TransientTab {\n return {\n id: `${image.inlineData === undefined ? 'image-gen-image' : 'image-gen-inline'}-${encodeURIComponent(image.id)}`,\n label: image.label ?? `Image ${image.id}`,\n panel: (props) => (props.sessionId === sessionId ? <SessionImageViewer {...props} image={image} /> : null),\n };\n}\n\n/** Inline bytes are a fallback only when no durable artifact exists. */\nexport async function transcriptImageTab(\n sessionId: string,\n toolCallId: string,\n src: string,\n label: string,\n signal: AbortSignal,\n inlineOnly = false,\n): Promise<TransientTab> {\n const image = await resolveTranscriptImage(sessionId, toolCallId, src, signal, inlineOnly);\n return imageViewerTab(sessionId, { ...image, label });\n}\n\nexport function ImagesActivity(props: WebPluginSlotProps) {\n return (\n <div data-testid=\"session-images-activity\">\n <SessionImages {...props} variant=\"activity\" />\n </div>\n );\n}\n\nfunction ImagesGallery(props: WebPluginSlotProps) {\n return (\n <section\n data-testid=\"session-images-gallery\"\n className=\"h-full min-h-0 overflow-y-auto p-4\"\n aria-label=\"Session image gallery\"\n >\n <h2 className=\"text-lg font-semibold text-po-hi\">Images</h2>\n <p className=\"text-sm text-po-dim\">Generated in this session, newest first.</p>\n <SessionImages {...props} variant=\"gallery\" />\n </section>\n );\n}\n\nfunction SessionImages(props: WebPluginSlotProps & { variant: 'activity' | 'gallery' }) {\n if (props.sessionId === null) return null;\n return (\n <ImagesPage\n key={`${props.sessionId}:${props.statuses['image-gen.images'] ?? ''}`}\n {...props}\n sessionId={props.sessionId}\n />\n );\n}\n\nfunction ImagesPage(props: WebPluginSlotProps & { sessionId: string; variant: 'activity' | 'gallery' }) {\n const [images, setImages] = useState<ImageTile[]>([]);\n const [cursor, setCursor] = useState('0');\n const [nextCursor, setNextCursor] = useState<string | null>(null);\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n const [error, setError] = useState('');\n const urls = useRef<string[]>([]);\n useEffect(\n () => () => {\n for (const url of urls.current) URL.revokeObjectURL(url);\n },\n [],\n );\n useEffect(() => {\n const controller = new AbortController();\n setState('loading');\n void (async () => {\n const response = await api\n .session(props.sessionId)\n .listImages({ query: { limit: '6', cursor }, signal: controller.signal });\n if (!response.ok) throw new Error(response.error || 'Images could not be loaded.');\n if (response.data.sessionId !== props.sessionId) throw new Error('Image history belongs to another session.');\n const artifacts = await Promise.all(\n response.data.items.map(async ({ id }) => {\n const result = await api.session(props.sessionId).readImage({ query: { id }, signal: controller.signal });\n if (!result.ok) {\n if (result.status === 404) return null;\n throw new Error(result.error || 'An image could not be loaded.');\n }\n if (result.data.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n return result.data;\n }),\n );\n controller.signal.throwIfAborted();\n const tiles = artifacts.flatMap((artifact) => {\n if (!artifact) return [];\n const src = pngUrl(artifact.data);\n urls.current.push(src);\n return [{ id: artifact.id, label: `Image ${artifact.id}`, src }];\n });\n setImages((previous) =>\n cursor === '0' ? tiles : [...previous, ...tiles.filter((tile) => !previous.some(({ id }) => id === tile.id))],\n );\n setNextCursor(response.data.nextCursor);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'Images could not be loaded.');\n setState('error');\n });\n return () => controller.abort();\n }, [props.sessionId, cursor]);\n return (\n <ImagesGridView\n images={images}\n state={state}\n error={error}\n variant={props.variant}\n onOpen={(id) => props.openTransientTab(imageViewerTab(props.sessionId, { id }))}\n hasMore={props.variant === 'gallery' && nextCursor !== null}\n onMore={() => {\n if (nextCursor !== null && state !== 'loading') setCursor(nextCursor);\n }}\n />\n );\n}\n\nfunction SessionImageViewer(\n props: WebPluginSlotProps & { image: { id: string; artifact?: ImageArtifact; inlineData?: string; label?: string } },\n) {\n const [artifact, setArtifact] = useState<ImageArtifact>();\n const [src, setSrc] = useState<string>();\n const [error, setError] = useState('');\n const [state, setState] = useState<'ready' | 'loading' | 'error'>('loading');\n useEffect(() => {\n const controller = new AbortController();\n let objectUrl: string | undefined;\n setArtifact(undefined);\n setSrc(undefined);\n setError('');\n setState('loading');\n void (async () => {\n if (props.sessionId === null) return;\n let data = props.image.inlineData;\n if (!data) {\n let target = props.image.artifact;\n if (!target) {\n const result = await api\n .session(props.sessionId)\n .readImage({ query: { id: props.image.id }, signal: controller.signal });\n if (!result.ok) throw new Error(result.error || 'This image could not be loaded.');\n target = result.data;\n }\n if (target.sessionId !== props.sessionId) throw new Error('Image belongs to another session.');\n controller.signal.throwIfAborted();\n setArtifact(target);\n data = target.data;\n }\n controller.signal.throwIfAborted();\n objectUrl = pngUrl(data);\n setSrc(objectUrl);\n setState('ready');\n })().catch((reason: unknown) => {\n if (controller.signal.aborted) return;\n setError(reason instanceof Error ? reason.message : 'This image could not be loaded.');\n setState('error');\n });\n return () => {\n controller.abort();\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n };\n }, [props.sessionId, props.image]);\n const Panel =\n artifact && props.activeMinorModes?.includes('author')\n ? props.slotData(imageFeedbackSlot)[0]?.data.panel\n : undefined;\n return (\n <section data-testid=\"session-image-viewer\" data-image-id={props.image.id} className=\"flex h-full min-h-0 flex-col\">\n <div className=\"min-h-0 flex-1\">\n <ImageViewerView\n image={{ id: props.image.id, label: props.image.label ?? `Image ${props.image.id}`, src }}\n state={state}\n error={error}\n feedback={Panel && artifact ? <Panel {...props} target={artifact} /> : undefined}\n />\n </div>\n {props.image.inlineData ? (\n <p className=\"px-4 pb-4 text-sm text-po-dim\">\n This inline image was not saved. Original-path refinement is unavailable.\n </p>\n ) : null}\n </section>\n );\n}\n","import { defineActivityGroup } from '@agimon-ai/po-core/web';\n\nimport { imagesGalleryTab } from '../tool/_components/SessionImages';\n\nexport default defineActivityGroup({\n name: 'Images',\n keys: '',\n activeSource: { subscribe: () => () => undefined, isActive: () => false },\n marksBackgroundWork: false,\n transientTab: imagesGalleryTab,\n order: 35,\n});\n","import { defineFill } from '@agimon-ai/po-core/web';\n\nimport { ImagesActivity } from '../tool/_components/SessionImages';\n\nexport default defineFill({ slot: 'activity.Images', component: ImagesActivity });\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\n\nexport function imagegenToolView({ args, result }: Pick<ToolMessageRenderProps, 'args' | 'result'>) {\n const prompt = typeof args.prompt === 'string' ? args.prompt : '';\n const editing = Array.isArray(args.referenced_image_paths) && args.referenced_image_paths.length > 0;\n // Only inline PNG results from this tool, never a URL supplied in details.\n const image = result?.content.find(\n (block): block is { type: 'image'; data: string; mimeType: 'image/png' } =>\n block !== null &&\n typeof block === 'object' &&\n 'type' in block &&\n block.type === 'image' &&\n 'mimeType' in block &&\n block.mimeType === 'image/png' &&\n 'data' in block &&\n typeof block.data === 'string',\n );\n const src = image ? `data:image/png;base64,${image.data}` : undefined;\n const details = result?.details;\n const inlineOnly =\n details !== null &&\n typeof details === 'object' &&\n 'saveWarning' in details &&\n typeof details.saveWarning === 'string';\n return { prompt, editing, src, inlineOnly };\n}\n","import type { ToolMessageRenderProps } from '@agimon-ai/po-core/web';\nimport {\n MessageItem,\n MessageItemBody,\n MessageItemHeader,\n MessageItemStatus,\n resultTextLines,\n toolTone,\n} from '@agimon-ai/po-web-components';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { imagegenToolView } from '../_lib/imagegenToolView';\nimport { transcriptImageTab } from './SessionImages';\n\nexport function ImagegenToolMessage(props: ToolMessageRenderProps) {\n const { result, output, running, isError } = props;\n const view = imagegenToolView(props);\n const [opening, setOpening] = useState(false);\n const [openError, setOpenError] = useState('');\n const request = useRef<AbortController | undefined>(undefined);\n useEffect(() => {\n setOpening(false);\n setOpenError('');\n return () => request.current?.abort();\n }, [props.sessionId, props.toolCallId]);\n return (\n <MessageItem tone={toolTone({ running, isError })} expandable defaultExpanded>\n {({ expanded }) => (\n <>\n <MessageItemHeader title=\"imagegen\">\n <span data-testid=\"tool-call-imagegen\" className=\"min-w-0 flex-1 truncate text-po-text\">\n {view.prompt}\n </span>\n <span className=\"shrink-0 text-po-faint\">{view.editing ? 'edit' : 'generate'}</span>\n </MessageItemHeader>\n {expanded ? (\n <MessageItemBody data-testid=\"tool-result-imagegen\" className=\"flex flex-col gap-2\">\n {running ? <MessageItemStatus tone=\"running\">creating image</MessageItemStatus> : null}\n {isError ? <MessageItemStatus tone=\"error\">failed</MessageItemStatus> : null}\n {!isError && view.src ? (\n <button\n type=\"button\"\n aria-label={`Open ${view.prompt || 'generated image'}`}\n disabled={opening || props.sessionId === null}\n className=\"max-w-full self-start rounded-md focus-visible:outline-2 focus-visible:outline-po-selected\"\n onClick={async () => {\n if (props.sessionId === null || !view.src || opening) return;\n const controller = new AbortController();\n request.current?.abort();\n request.current = controller;\n setOpening(true);\n setOpenError('');\n try {\n const tab = await transcriptImageTab(\n props.sessionId,\n props.toolCallId,\n view.src,\n view.prompt || 'Generated image',\n controller.signal,\n view.inlineOnly,\n );\n if (!controller.signal.aborted) props.openTransientTab(tab);\n } catch (reason) {\n if (!controller.signal.aborted)\n setOpenError(reason instanceof Error ? reason.message : 'This image could not be opened.');\n } finally {\n if (!controller.signal.aborted) setOpening(false);\n }\n }}\n >\n <img\n src={view.src}\n alt={view.prompt || 'Generated image'}\n className=\"max-h-96 max-w-full rounded-md object-contain\"\n />\n </button>\n ) : null}\n {openError ? (\n <p role=\"alert\" className=\"text-sm text-po-red\">\n {openError}\n </p>\n ) : null}\n {resultTextLines(result, output).map((line, index) => (\n <span\n key={`${String(index)}-${line}`}\n className={`whitespace-pre-wrap break-words ${isError ? 'text-po-red' : 'text-po-dim'}`}\n >\n {line}\n </span>\n ))}\n </MessageItemBody>\n ) : null}\n </>\n )}\n </MessageItem>\n );\n}\n","import { defineToolRenderer } from '@agimon-ai/po-core/web';\n\nimport { ImagegenToolMessage } from './_components/ImagegenToolMessage';\n\nexport default defineToolRenderer({ message: ImagegenToolMessage });\n","// Generated by @agimon-ai/po-build. Do not edit by hand.\nimport { defineWebPlugin, type WebPluginContributions } from '@agimon-ai/po-core/web';\n\nimport activityGroupImages from '../src/extensions/workspaces/sessions/(frontend)/activity-group/images.web';\nimport fillImages from '../src/extensions/workspaces/sessions/(frontend)/fill/Images.activity.Images.web';\nimport toolImagegen from '../src/extensions/workspaces/sessions/(frontend)/tool/imagegen.web';\n\nconst via = <T>(identity: Record<string, unknown>, value: unknown): T =>\n (value === undefined ? undefined : { ...identity, ...(value as object) }) as T;\n\nexport const webPlugin = defineWebPlugin({\n id: 'image-gen',\n session: {\n get activityGroups(): WebPluginContributions['activityGroups'] { return [via({ name: 'images' }, activityGroupImages)]; },\n get fills(): WebPluginContributions['fills'] { return [via({ slot: 'activity.Images', id: 'images' }, fillImages)]; },\n get toolRenderers(): WebPluginContributions['toolRenderers'] { return [via({ tools: ['imagegen'] }, toolImagegen)]; },\n },\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"imagegenTool-DDb0F5QH.cjs","names":["Type","createHash","resolve","realpath","join","lstat","open","constants","opendir","mkdir","unlink","isAbsolute","open","constants","randomUUID"],"sources":["../src/constants/imagegen.ts","../src/schemas/imagegen.ts","../src/services/imageArtifacts/index.ts","../src/services/imageReferences/index.ts","../src/services/imagegenTool/index.ts"],"sourcesContent":["export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import { type Static, Type } from 'typebox';\n\nexport const ImagegenParamsSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, description: 'Describe the image to generate or changes to make.' }),\n transparent_background: Type.Optional(Type.Boolean({ description: 'Use a transparent background.' })),\n referenced_image_paths: Type.Optional(\n Type.Array(Type.String({ minLength: 1 }), {\n maxItems: 5,\n description: 'Absolute paths of local PNG, JPEG or WebP images to edit.',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\nexport type ImagegenParams = Static<typeof ImagegenParamsSchema>;\n","import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { lstat, mkdir, open, opendir, realpath, unlink } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImageArtifact, ImageArtifactList, ImageArtifactMetadata } from '../../types/imageArtifacts';\n\nconst sanitize = (value: string) => {\n const safe = value.replace(/[^A-Za-z0-9_-]/gu, '_') || 'generated_image';\n return safe.length <= 128\n ? safe\n : `${safe.slice(0, 96)}_${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;\n};\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\nconst MAX_DIRECTORY_ENTRIES = 10000;\n\nexport class ImageArtifactError extends Error {}\n\nexport function imageArtifactIdForCall(toolCallId: string): string {\n return sanitize(toolCallId);\n}\n\nasync function sessionDirectory(home: string, sessionId: string): Promise<string | null> {\n if (!/^[A-Za-z0-9_-]+$/u.test(sessionId)) throw new ImageArtifactError('Invalid session identity.');\n const root = resolve(await realpath(home), 'generated_images');\n const directory = join(root, sanitize(sessionId));\n try {\n for (const path of [root, directory]) {\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink() || (await realpath(path)) !== path)\n throw new ImageArtifactError('Unsafe image directory.');\n }\n return directory;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return null;\n throw error;\n }\n}\n\nfunction artifactPath(directory: string, id: string): string {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new ImageArtifactError('Invalid image identity.');\n return join(directory, `${id}.png`);\n}\n\nasync function inspectArtifact(directory: string, id: string, includeData: boolean, signal?: AbortSignal) {\n signal?.throwIfAborted();\n const path = artifactPath(directory, id);\n const info = await lstat(path);\n if (!info.isFile() || info.isSymbolicLink()) throw new ImageArtifactError('Image is not a regular file.');\n const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n try {\n const stat = await file.stat();\n if (!stat.isFile() || stat.dev !== info.dev || stat.ino !== info.ino || (await realpath(path)) !== path)\n throw new ImageArtifactError('Image changed during access.');\n if (stat.size < PNG_SIGNATURE.length || stat.size > MAX_REFERENCE_BYTES)\n throw new ImageArtifactError('Image exceeds the size limit or is empty.');\n const signature = Buffer.alloc(PNG_SIGNATURE.length);\n await file.read(signature, 0, signature.length, 0);\n if (!signature.equals(PNG_SIGNATURE)) throw new ImageArtifactError('Image is not a PNG.');\n const metadata: ImageArtifactMetadata = { id, createdAt: stat.mtime.toISOString(), byteLength: stat.size };\n if (!includeData) return { metadata, path, data: undefined };\n // Read only the admitted length, even if another process grows the file.\n const data = Buffer.alloc(stat.size);\n let offset = 0;\n while (offset < data.length) {\n signal?.throwIfAborted();\n const read = await file.read(data, offset, data.length - offset, offset);\n if (!read.bytesRead) throw new ImageArtifactError('Image changed during access.');\n offset += read.bytesRead;\n }\n const after = await file.stat();\n if (after.size !== stat.size || after.mtimeMs !== stat.mtimeMs || !data.subarray(0, 8).equals(PNG_SIGNATURE))\n throw new ImageArtifactError('Image changed during access.');\n return { metadata, path, data };\n } finally {\n await file.close();\n }\n}\n\nexport async function listImageArtifacts(\n home: string,\n sessionId: string,\n limit = 6,\n cursor = 0,\n signal?: AbortSignal,\n): Promise<ImageArtifactList> {\n if (\n !Number.isInteger(limit) ||\n limit < 1 ||\n limit > 24 ||\n !Number.isInteger(cursor) ||\n cursor < 0 ||\n cursor > MAX_DIRECTORY_ENTRIES\n )\n throw new ImageArtifactError('Invalid image page.');\n const directory = await sessionDirectory(home, sessionId);\n const items: ImageArtifactMetadata[] = [];\n if (directory) {\n const entries = await opendir(directory);\n let count = 0;\n for await (const entry of entries) {\n signal?.throwIfAborted();\n if (++count > MAX_DIRECTORY_ENTRIES) throw new ImageArtifactError('Image directory exceeds the listing limit.');\n if (!entry.isFile() || !/^[A-Za-z0-9_-]{1,128}\\.png$/u.test(entry.name)) continue;\n try {\n items.push((await inspectArtifact(directory, entry.name.slice(0, -4), false, signal)).metadata);\n } catch (error) {\n signal?.throwIfAborted();\n // Unsafe, oversized or concurrently removed artifacts are not advertised.\n if (\n !(error instanceof ImageArtifactError) &&\n !(error instanceof Error && 'code' in error && error.code === 'ENOENT')\n )\n throw error;\n }\n }\n }\n items.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b.id));\n return {\n sessionId,\n items: items.slice(cursor, cursor + limit),\n nextCursor: cursor + limit < items.length ? String(cursor + limit) : null,\n };\n}\n\nexport async function readImageArtifact(\n home: string,\n sessionId: string,\n id: string,\n signal?: AbortSignal,\n): Promise<ImageArtifact> {\n const directory = await sessionDirectory(home, sessionId);\n if (!directory) throw new ImageArtifactError('Image not found.');\n const { metadata, path, data } = await inspectArtifact(directory, id, true, signal);\n if (!data) throw new ImageArtifactError('Image data unavailable.');\n return {\n ...metadata,\n sessionId,\n originalPath: path,\n sourceSha256: createHash('sha256').update(data).digest('hex'),\n data: data.toString('base64'),\n mimeType: 'image/png',\n };\n}\n\nexport async function saveImageArtifact(\n home: string,\n sessionId: string,\n callId: string,\n data: string,\n signal?: AbortSignal,\n): Promise<string> {\n signal?.throwIfAborted();\n const directory = join(home, 'generated_images', sanitize(sessionId));\n const path = join(directory, `${sanitize(callId)}.png`);\n await mkdir(directory, { recursive: true });\n signal?.throwIfAborted();\n const file = await open(path, 'wx', 0o600);\n try {\n await file.writeFile(Buffer.from(data, 'base64'));\n } catch (error) {\n await file.close();\n await unlink(path).catch(() => undefined);\n throw error;\n }\n await file.close();\n return path;\n}\n","import { constants } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { isAbsolute } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES, MAX_TOTAL_REFERENCE_BYTES } from '../../constants/imagegen';\n\nexport async function readImageReferences(\n paths: readonly string[],\n signal?: AbortSignal,\n): Promise<{ data: string; mimeType: string }[]> {\n if (paths.length > 5) throw new Error('At most five reference images are supported.');\n const images: { data: string; mimeType: string }[] = [];\n let total = 0;\n for (const path of paths) {\n signal?.throwIfAborted();\n if (!isAbsolute(path)) throw new Error('Reference image paths must be absolute.');\n const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);\n try {\n const stats = await file.stat();\n if (!stats.isFile()) throw new Error('Reference images must be regular files.');\n if (stats.size > MAX_REFERENCE_BYTES || total + stats.size > MAX_TOTAL_REFERENCE_BYTES)\n throw new Error('Reference image size limit exceeded.');\n // Bound reads even if another process grows the file after stat.\n const bytes = Buffer.alloc(Math.min(stats.size + 1, MAX_REFERENCE_BYTES + 1));\n let length = 0;\n while (length < bytes.length) {\n signal?.throwIfAborted();\n const result = await file.read(bytes, length, bytes.length - length, null);\n if (!result.bytesRead) break;\n length += result.bytesRead;\n }\n if (length > stats.size) throw new Error('Reference image changed while reading.');\n const image = bytes.subarray(0, length);\n const mimeType = image.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ? 'image/png'\n : image[0] === 255 && image[1] === 216 && image[2] === 255\n ? 'image/jpeg'\n : image.toString('ascii', 0, 4) === 'RIFF' && image.toString('ascii', 8, 12) === 'WEBP'\n ? 'image/webp'\n : undefined;\n if (!mimeType) throw new Error('Reference images must be PNG, JPEG or WebP.');\n total += length;\n images.push({ data: image.toString('base64'), mimeType });\n } finally {\n await file.close();\n }\n }\n return images;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport type { DoomHeadlessTool } from '@agimon-ai/po-core/headless';\n\nimport { IMAGEGEN_DESCRIPTION, IMAGEGEN_NAME } from '../../constants/imagegen';\nimport { ImagegenParamsSchema } from '../../schemas/imagegen';\nimport { saveImageArtifact } from '../imageArtifacts';\nimport { readImageReferences } from '../imageReferences';\nimport type { ImagegenDetails } from './type';\n\nexport function createImagegenTool(home: string): DoomHeadlessTool<typeof ImagegenParamsSchema> {\n return {\n name: IMAGEGEN_NAME,\n label: IMAGEGEN_NAME,\n description: IMAGEGEN_DESCRIPTION,\n parameters: ImagegenParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n if (!params.prompt.trim()) throw new Error('Image prompts must not be blank.');\n const capability = context.imageGeneration;\n if (!capability?.available())\n throw new Error(\n 'Image generation needs a ChatGPT sign-in. Sign in to ChatGPT for Po features under Settings > Providers, or with /login.',\n );\n const images = await readImageReferences(params.referenced_image_paths ?? [], signal);\n const result = await capability.generate({\n prompt: params.prompt,\n transparentBackground: params.transparent_background,\n images,\n correlationId: toolCallId,\n signal,\n });\n signal?.throwIfAborted();\n const details: ImagegenDetails = { requestId: result.requestId, generationId: result.generationId };\n try {\n details.savedPath = await saveImageArtifact(home, context.sessionId, toolCallId, result.data, signal);\n } catch {\n signal?.throwIfAborted();\n details.saveWarning = 'Image generated, but could not be saved. The inline image is still available.';\n }\n if (details.savedPath) context.client?.setStatus('image-gen.images', randomUUID());\n return {\n content: [\n { type: 'image', data: result.data, mimeType: result.mimeType },\n {\n type: 'text',\n text: details.savedPath\n ? `Generated image saved to ${details.savedPath}. Copy it when using another destination and preserve the original.`\n : details.saveWarning!,\n },\n ],\n details,\n };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"imagegenTool-DDb0F5QH.cjs","names":["Type","createHash","resolve","realpath","join","lstat","open","constants","opendir","mkdir","unlink","isAbsolute","open","constants","randomUUID"],"sources":["../src/constants/imagegen.ts","../src/schemas/imagegen.ts","../src/services/imageArtifacts/index.ts","../src/services/imageReferences/index.ts","../src/services/imagegenTool/index.ts"],"sourcesContent":["export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import { type Static, Type } from 'typebox';\n\nexport const ImagegenParamsSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, description: 'Describe the image to generate or changes to make.' }),\n transparent_background: Type.Optional(Type.Boolean({ description: 'Use a transparent background.' })),\n referenced_image_paths: Type.Optional(\n Type.Array(Type.String({ minLength: 1 }), {\n maxItems: 5,\n description: 'Absolute paths of local PNG, JPEG or WebP images to edit.',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\nexport type ImagegenParams = Static<typeof ImagegenParamsSchema>;\n","import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { lstat, mkdir, open, opendir, realpath, unlink } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImageArtifact, ImageArtifactList, ImageArtifactMetadata } from '../../types/imageArtifacts';\n\nconst sanitize = (value: string) => {\n const safe = value.replace(/[^A-Za-z0-9_-]/gu, '_') || 'generated_image';\n return safe.length <= 128\n ? safe\n : `${safe.slice(0, 96)}_${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;\n};\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\nconst MAX_DIRECTORY_ENTRIES = 10000;\n\nexport class ImageArtifactError extends Error {}\n\nexport function imageArtifactIdForCall(toolCallId: string): string {\n return sanitize(toolCallId);\n}\n\nasync function sessionDirectory(home: string, sessionId: string): Promise<string | null> {\n if (!/^[A-Za-z0-9_-]+$/u.test(sessionId)) throw new ImageArtifactError('Invalid session identity.');\n const root = resolve(await realpath(home), 'generated_images');\n const directory = join(root, sanitize(sessionId));\n try {\n for (const path of [root, directory]) {\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink() || (await realpath(path)) !== path)\n throw new ImageArtifactError('Unsafe image directory.');\n }\n return directory;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return null;\n throw error;\n }\n}\n\nfunction artifactPath(directory: string, id: string): string {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new ImageArtifactError('Invalid image identity.');\n return join(directory, `${id}.png`);\n}\n\nasync function inspectArtifact(directory: string, id: string, includeData: boolean, signal?: AbortSignal) {\n signal?.throwIfAborted();\n const path = artifactPath(directory, id);\n const info = await lstat(path);\n if (!info.isFile() || info.isSymbolicLink()) throw new ImageArtifactError('Image is not a regular file.');\n const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n try {\n const stat = await file.stat();\n if (!stat.isFile() || stat.dev !== info.dev || stat.ino !== info.ino || (await realpath(path)) !== path)\n throw new ImageArtifactError('Image changed during access.');\n if (stat.size < PNG_SIGNATURE.length || stat.size > MAX_REFERENCE_BYTES)\n throw new ImageArtifactError('Image exceeds the size limit or is empty.');\n const signature = Buffer.alloc(PNG_SIGNATURE.length);\n await file.read(signature, 0, signature.length, 0);\n if (!signature.equals(PNG_SIGNATURE)) throw new ImageArtifactError('Image is not a PNG.');\n const metadata: ImageArtifactMetadata = { id, createdAt: stat.mtime.toISOString(), byteLength: stat.size };\n if (!includeData) return { metadata, path, data: undefined };\n // Read only the admitted length, even if another process grows the file.\n const data = Buffer.alloc(stat.size);\n let offset = 0;\n while (offset < data.length) {\n signal?.throwIfAborted();\n const read = await file.read(data, offset, data.length - offset, offset);\n if (!read.bytesRead) throw new ImageArtifactError('Image changed during access.');\n offset += read.bytesRead;\n }\n const after = await file.stat();\n if (after.size !== stat.size || after.mtimeMs !== stat.mtimeMs || !data.subarray(0, 8).equals(PNG_SIGNATURE))\n throw new ImageArtifactError('Image changed during access.');\n return { metadata, path, data };\n } finally {\n await file.close();\n }\n}\n\nexport async function listImageArtifacts(\n home: string,\n sessionId: string,\n limit = 6,\n cursor = 0,\n signal?: AbortSignal,\n): Promise<ImageArtifactList> {\n if (\n !Number.isInteger(limit) ||\n limit < 1 ||\n limit > 24 ||\n !Number.isInteger(cursor) ||\n cursor < 0 ||\n cursor > MAX_DIRECTORY_ENTRIES\n )\n throw new ImageArtifactError('Invalid image page.');\n const directory = await sessionDirectory(home, sessionId);\n const items: ImageArtifactMetadata[] = [];\n if (directory) {\n const entries = await opendir(directory);\n let count = 0;\n for await (const entry of entries) {\n signal?.throwIfAborted();\n if (++count > MAX_DIRECTORY_ENTRIES) throw new ImageArtifactError('Image directory exceeds the listing limit.');\n if (!entry.isFile() || !/^[A-Za-z0-9_-]{1,128}\\.png$/u.test(entry.name)) continue;\n try {\n items.push((await inspectArtifact(directory, entry.name.slice(0, -4), false, signal)).metadata);\n } catch (error) {\n signal?.throwIfAborted();\n // Unsafe, oversized or concurrently removed artifacts are not advertised.\n if (\n !(error instanceof ImageArtifactError) &&\n !(error instanceof Error && 'code' in error && error.code === 'ENOENT')\n )\n throw error;\n }\n }\n }\n items.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b.id));\n return {\n sessionId,\n items: items.slice(cursor, cursor + limit),\n nextCursor: cursor + limit < items.length ? String(cursor + limit) : null,\n };\n}\n\nexport async function readImageArtifact(\n home: string,\n sessionId: string,\n id: string,\n signal?: AbortSignal,\n): Promise<ImageArtifact> {\n const directory = await sessionDirectory(home, sessionId);\n if (!directory) throw new ImageArtifactError('Image not found.');\n const { metadata, path, data } = await inspectArtifact(directory, id, true, signal);\n if (!data) throw new ImageArtifactError('Image data unavailable.');\n return {\n ...metadata,\n sessionId,\n originalPath: path,\n sourceSha256: createHash('sha256').update(data).digest('hex'),\n data: data.toString('base64'),\n mimeType: 'image/png',\n };\n}\n\nexport async function saveImageArtifact(\n home: string,\n sessionId: string,\n callId: string,\n data: string,\n signal?: AbortSignal,\n): Promise<string> {\n signal?.throwIfAborted();\n const directory = join(home, 'generated_images', sanitize(sessionId));\n const path = join(directory, `${sanitize(callId)}.png`);\n await mkdir(directory, { recursive: true });\n signal?.throwIfAborted();\n const file = await open(path, 'wx', 0o600);\n try {\n await file.writeFile(Buffer.from(data, 'base64'));\n } catch (error) {\n await file.close();\n await unlink(path).catch(() => undefined);\n throw error;\n }\n await file.close();\n return path;\n}\n","import { constants } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { isAbsolute } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES, MAX_TOTAL_REFERENCE_BYTES } from '../../constants/imagegen';\n\nexport async function readImageReferences(\n paths: readonly string[],\n signal?: AbortSignal,\n): Promise<{ data: string; mimeType: string }[]> {\n if (paths.length > 5) throw new Error('At most five reference images are supported.');\n const images: { data: string; mimeType: string }[] = [];\n let total = 0;\n for (const path of paths) {\n signal?.throwIfAborted();\n if (!isAbsolute(path)) throw new Error('Reference image paths must be absolute.');\n const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);\n try {\n const stats = await file.stat();\n if (!stats.isFile()) throw new Error('Reference images must be regular files.');\n if (stats.size > MAX_REFERENCE_BYTES || total + stats.size > MAX_TOTAL_REFERENCE_BYTES)\n throw new Error('Reference image size limit exceeded.');\n // Bound reads even if another process grows the file after stat.\n const bytes = Buffer.alloc(Math.min(stats.size + 1, MAX_REFERENCE_BYTES + 1));\n let length = 0;\n while (length < bytes.length) {\n signal?.throwIfAborted();\n const result = await file.read(bytes, length, bytes.length - length, null);\n if (!result.bytesRead) break;\n length += result.bytesRead;\n }\n if (length > stats.size) throw new Error('Reference image changed while reading.');\n const image = bytes.subarray(0, length);\n const mimeType = image.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ? 'image/png'\n : image[0] === 255 && image[1] === 216 && image[2] === 255\n ? 'image/jpeg'\n : image.toString('ascii', 0, 4) === 'RIFF' && image.toString('ascii', 8, 12) === 'WEBP'\n ? 'image/webp'\n : undefined;\n if (!mimeType) throw new Error('Reference images must be PNG, JPEG or WebP.');\n total += length;\n images.push({ data: image.toString('base64'), mimeType });\n } finally {\n await file.close();\n }\n }\n return images;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\n\nimport { IMAGEGEN_DESCRIPTION, IMAGEGEN_NAME } from '../../constants/imagegen';\nimport { ImagegenParamsSchema } from '../../schemas/imagegen';\nimport { saveImageArtifact } from '../imageArtifacts';\nimport { readImageReferences } from '../imageReferences';\nimport type { ImagegenDetails } from './type';\n\nexport function createImagegenTool(home: string): PoHeadlessTool<typeof ImagegenParamsSchema> {\n return {\n name: IMAGEGEN_NAME,\n label: IMAGEGEN_NAME,\n description: IMAGEGEN_DESCRIPTION,\n parameters: ImagegenParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n if (!params.prompt.trim()) throw new Error('Image prompts must not be blank.');\n const capability = context.imageGeneration;\n if (!capability?.available())\n throw new Error(\n 'Image generation needs a ChatGPT sign-in. Sign in to ChatGPT for Po features under Settings > Providers, or with /login.',\n );\n const images = await readImageReferences(params.referenced_image_paths ?? [], signal);\n const result = await capability.generate({\n prompt: params.prompt,\n transparentBackground: params.transparent_background,\n images,\n correlationId: toolCallId,\n signal,\n });\n signal?.throwIfAborted();\n const details: ImagegenDetails = { requestId: result.requestId, generationId: result.generationId };\n try {\n details.savedPath = await saveImageArtifact(home, context.sessionId, toolCallId, result.data, signal);\n } catch {\n signal?.throwIfAborted();\n details.saveWarning = 'Image generated, but could not be saved. The inline image is still available.';\n }\n if (details.savedPath) context.client?.setStatus('image-gen.images', randomUUID());\n return {\n content: [\n { type: 'image', data: result.data, mimeType: result.mimeType },\n {\n type: 'text',\n text: details.savedPath\n ? `Generated image saved to ${details.savedPath}. Copy it when using another destination and preserve the original.`\n : details.saveWarning!,\n },\n ],\n details,\n };\n },\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"imagegenTool-DMrMZjfO.mjs","names":[],"sources":["../src/constants/imagegen.ts","../src/schemas/imagegen.ts","../src/services/imageArtifacts/index.ts","../src/services/imageReferences/index.ts","../src/services/imagegenTool/index.ts"],"sourcesContent":["export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import { type Static, Type } from 'typebox';\n\nexport const ImagegenParamsSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, description: 'Describe the image to generate or changes to make.' }),\n transparent_background: Type.Optional(Type.Boolean({ description: 'Use a transparent background.' })),\n referenced_image_paths: Type.Optional(\n Type.Array(Type.String({ minLength: 1 }), {\n maxItems: 5,\n description: 'Absolute paths of local PNG, JPEG or WebP images to edit.',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\nexport type ImagegenParams = Static<typeof ImagegenParamsSchema>;\n","import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { lstat, mkdir, open, opendir, realpath, unlink } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImageArtifact, ImageArtifactList, ImageArtifactMetadata } from '../../types/imageArtifacts';\n\nconst sanitize = (value: string) => {\n const safe = value.replace(/[^A-Za-z0-9_-]/gu, '_') || 'generated_image';\n return safe.length <= 128\n ? safe\n : `${safe.slice(0, 96)}_${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;\n};\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\nconst MAX_DIRECTORY_ENTRIES = 10000;\n\nexport class ImageArtifactError extends Error {}\n\nexport function imageArtifactIdForCall(toolCallId: string): string {\n return sanitize(toolCallId);\n}\n\nasync function sessionDirectory(home: string, sessionId: string): Promise<string | null> {\n if (!/^[A-Za-z0-9_-]+$/u.test(sessionId)) throw new ImageArtifactError('Invalid session identity.');\n const root = resolve(await realpath(home), 'generated_images');\n const directory = join(root, sanitize(sessionId));\n try {\n for (const path of [root, directory]) {\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink() || (await realpath(path)) !== path)\n throw new ImageArtifactError('Unsafe image directory.');\n }\n return directory;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return null;\n throw error;\n }\n}\n\nfunction artifactPath(directory: string, id: string): string {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new ImageArtifactError('Invalid image identity.');\n return join(directory, `${id}.png`);\n}\n\nasync function inspectArtifact(directory: string, id: string, includeData: boolean, signal?: AbortSignal) {\n signal?.throwIfAborted();\n const path = artifactPath(directory, id);\n const info = await lstat(path);\n if (!info.isFile() || info.isSymbolicLink()) throw new ImageArtifactError('Image is not a regular file.');\n const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n try {\n const stat = await file.stat();\n if (!stat.isFile() || stat.dev !== info.dev || stat.ino !== info.ino || (await realpath(path)) !== path)\n throw new ImageArtifactError('Image changed during access.');\n if (stat.size < PNG_SIGNATURE.length || stat.size > MAX_REFERENCE_BYTES)\n throw new ImageArtifactError('Image exceeds the size limit or is empty.');\n const signature = Buffer.alloc(PNG_SIGNATURE.length);\n await file.read(signature, 0, signature.length, 0);\n if (!signature.equals(PNG_SIGNATURE)) throw new ImageArtifactError('Image is not a PNG.');\n const metadata: ImageArtifactMetadata = { id, createdAt: stat.mtime.toISOString(), byteLength: stat.size };\n if (!includeData) return { metadata, path, data: undefined };\n // Read only the admitted length, even if another process grows the file.\n const data = Buffer.alloc(stat.size);\n let offset = 0;\n while (offset < data.length) {\n signal?.throwIfAborted();\n const read = await file.read(data, offset, data.length - offset, offset);\n if (!read.bytesRead) throw new ImageArtifactError('Image changed during access.');\n offset += read.bytesRead;\n }\n const after = await file.stat();\n if (after.size !== stat.size || after.mtimeMs !== stat.mtimeMs || !data.subarray(0, 8).equals(PNG_SIGNATURE))\n throw new ImageArtifactError('Image changed during access.');\n return { metadata, path, data };\n } finally {\n await file.close();\n }\n}\n\nexport async function listImageArtifacts(\n home: string,\n sessionId: string,\n limit = 6,\n cursor = 0,\n signal?: AbortSignal,\n): Promise<ImageArtifactList> {\n if (\n !Number.isInteger(limit) ||\n limit < 1 ||\n limit > 24 ||\n !Number.isInteger(cursor) ||\n cursor < 0 ||\n cursor > MAX_DIRECTORY_ENTRIES\n )\n throw new ImageArtifactError('Invalid image page.');\n const directory = await sessionDirectory(home, sessionId);\n const items: ImageArtifactMetadata[] = [];\n if (directory) {\n const entries = await opendir(directory);\n let count = 0;\n for await (const entry of entries) {\n signal?.throwIfAborted();\n if (++count > MAX_DIRECTORY_ENTRIES) throw new ImageArtifactError('Image directory exceeds the listing limit.');\n if (!entry.isFile() || !/^[A-Za-z0-9_-]{1,128}\\.png$/u.test(entry.name)) continue;\n try {\n items.push((await inspectArtifact(directory, entry.name.slice(0, -4), false, signal)).metadata);\n } catch (error) {\n signal?.throwIfAborted();\n // Unsafe, oversized or concurrently removed artifacts are not advertised.\n if (\n !(error instanceof ImageArtifactError) &&\n !(error instanceof Error && 'code' in error && error.code === 'ENOENT')\n )\n throw error;\n }\n }\n }\n items.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b.id));\n return {\n sessionId,\n items: items.slice(cursor, cursor + limit),\n nextCursor: cursor + limit < items.length ? String(cursor + limit) : null,\n };\n}\n\nexport async function readImageArtifact(\n home: string,\n sessionId: string,\n id: string,\n signal?: AbortSignal,\n): Promise<ImageArtifact> {\n const directory = await sessionDirectory(home, sessionId);\n if (!directory) throw new ImageArtifactError('Image not found.');\n const { metadata, path, data } = await inspectArtifact(directory, id, true, signal);\n if (!data) throw new ImageArtifactError('Image data unavailable.');\n return {\n ...metadata,\n sessionId,\n originalPath: path,\n sourceSha256: createHash('sha256').update(data).digest('hex'),\n data: data.toString('base64'),\n mimeType: 'image/png',\n };\n}\n\nexport async function saveImageArtifact(\n home: string,\n sessionId: string,\n callId: string,\n data: string,\n signal?: AbortSignal,\n): Promise<string> {\n signal?.throwIfAborted();\n const directory = join(home, 'generated_images', sanitize(sessionId));\n const path = join(directory, `${sanitize(callId)}.png`);\n await mkdir(directory, { recursive: true });\n signal?.throwIfAborted();\n const file = await open(path, 'wx', 0o600);\n try {\n await file.writeFile(Buffer.from(data, 'base64'));\n } catch (error) {\n await file.close();\n await unlink(path).catch(() => undefined);\n throw error;\n }\n await file.close();\n return path;\n}\n","import { constants } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { isAbsolute } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES, MAX_TOTAL_REFERENCE_BYTES } from '../../constants/imagegen';\n\nexport async function readImageReferences(\n paths: readonly string[],\n signal?: AbortSignal,\n): Promise<{ data: string; mimeType: string }[]> {\n if (paths.length > 5) throw new Error('At most five reference images are supported.');\n const images: { data: string; mimeType: string }[] = [];\n let total = 0;\n for (const path of paths) {\n signal?.throwIfAborted();\n if (!isAbsolute(path)) throw new Error('Reference image paths must be absolute.');\n const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);\n try {\n const stats = await file.stat();\n if (!stats.isFile()) throw new Error('Reference images must be regular files.');\n if (stats.size > MAX_REFERENCE_BYTES || total + stats.size > MAX_TOTAL_REFERENCE_BYTES)\n throw new Error('Reference image size limit exceeded.');\n // Bound reads even if another process grows the file after stat.\n const bytes = Buffer.alloc(Math.min(stats.size + 1, MAX_REFERENCE_BYTES + 1));\n let length = 0;\n while (length < bytes.length) {\n signal?.throwIfAborted();\n const result = await file.read(bytes, length, bytes.length - length, null);\n if (!result.bytesRead) break;\n length += result.bytesRead;\n }\n if (length > stats.size) throw new Error('Reference image changed while reading.');\n const image = bytes.subarray(0, length);\n const mimeType = image.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ? 'image/png'\n : image[0] === 255 && image[1] === 216 && image[2] === 255\n ? 'image/jpeg'\n : image.toString('ascii', 0, 4) === 'RIFF' && image.toString('ascii', 8, 12) === 'WEBP'\n ? 'image/webp'\n : undefined;\n if (!mimeType) throw new Error('Reference images must be PNG, JPEG or WebP.');\n total += length;\n images.push({ data: image.toString('base64'), mimeType });\n } finally {\n await file.close();\n }\n }\n return images;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport type { DoomHeadlessTool } from '@agimon-ai/po-core/headless';\n\nimport { IMAGEGEN_DESCRIPTION, IMAGEGEN_NAME } from '../../constants/imagegen';\nimport { ImagegenParamsSchema } from '../../schemas/imagegen';\nimport { saveImageArtifact } from '../imageArtifacts';\nimport { readImageReferences } from '../imageReferences';\nimport type { ImagegenDetails } from './type';\n\nexport function createImagegenTool(home: string): DoomHeadlessTool<typeof ImagegenParamsSchema> {\n return {\n name: IMAGEGEN_NAME,\n label: IMAGEGEN_NAME,\n description: IMAGEGEN_DESCRIPTION,\n parameters: ImagegenParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n if (!params.prompt.trim()) throw new Error('Image prompts must not be blank.');\n const capability = context.imageGeneration;\n if (!capability?.available())\n throw new Error(\n 'Image generation needs a ChatGPT sign-in. Sign in to ChatGPT for Po features under Settings > Providers, or with /login.',\n );\n const images = await readImageReferences(params.referenced_image_paths ?? [], signal);\n const result = await capability.generate({\n prompt: params.prompt,\n transparentBackground: params.transparent_background,\n images,\n correlationId: toolCallId,\n signal,\n });\n signal?.throwIfAborted();\n const details: ImagegenDetails = { requestId: result.requestId, generationId: result.generationId };\n try {\n details.savedPath = await saveImageArtifact(home, context.sessionId, toolCallId, result.data, signal);\n } catch {\n signal?.throwIfAborted();\n details.saveWarning = 'Image generated, but could not be saved. The inline image is still available.';\n }\n if (details.savedPath) context.client?.setStatus('image-gen.images', randomUUID());\n return {\n content: [\n { type: 'image', data: result.data, mimeType: result.mimeType },\n {\n type: 'text',\n text: details.savedPath\n ? `Generated image saved to ${details.savedPath}. Copy it when using another destination and preserve the original.`\n : details.saveWarning!,\n },\n ],\n details,\n };\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"imagegenTool-DMrMZjfO.mjs","names":[],"sources":["../src/constants/imagegen.ts","../src/schemas/imagegen.ts","../src/services/imageArtifacts/index.ts","../src/services/imageReferences/index.ts","../src/services/imagegenTool/index.ts"],"sourcesContent":["export const IMAGEGEN_NAME = 'imagegen';\nexport const IMAGEGEN_DESCRIPTION =\n 'Generate images from descriptions or edit up to five local images using ChatGPT. Omit referenced_image_paths for a new image. Inspect reference images before editing. Image generation can take a few minutes. Originals are preserved; copy saved images when using another destination.';\nexport const MAX_REFERENCE_BYTES = 20 * 1024 * 1024;\nexport const MAX_TOTAL_REFERENCE_BYTES = 50 * 1024 * 1024;\n","import { type Static, Type } from 'typebox';\n\nexport const ImagegenParamsSchema = Type.Object(\n {\n prompt: Type.String({ minLength: 1, description: 'Describe the image to generate or changes to make.' }),\n transparent_background: Type.Optional(Type.Boolean({ description: 'Use a transparent background.' })),\n referenced_image_paths: Type.Optional(\n Type.Array(Type.String({ minLength: 1 }), {\n maxItems: 5,\n description: 'Absolute paths of local PNG, JPEG or WebP images to edit.',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\nexport type ImagegenParams = Static<typeof ImagegenParamsSchema>;\n","import { createHash } from 'node:crypto';\nimport { constants } from 'node:fs';\nimport { lstat, mkdir, open, opendir, realpath, unlink } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES } from '../../constants/imagegen';\nimport type { ImageArtifact, ImageArtifactList, ImageArtifactMetadata } from '../../types/imageArtifacts';\n\nconst sanitize = (value: string) => {\n const safe = value.replace(/[^A-Za-z0-9_-]/gu, '_') || 'generated_image';\n return safe.length <= 128\n ? safe\n : `${safe.slice(0, 96)}_${createHash('sha256').update(value).digest('hex').slice(0, 24)}`;\n};\nconst PNG_SIGNATURE = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);\nconst MAX_DIRECTORY_ENTRIES = 10000;\n\nexport class ImageArtifactError extends Error {}\n\nexport function imageArtifactIdForCall(toolCallId: string): string {\n return sanitize(toolCallId);\n}\n\nasync function sessionDirectory(home: string, sessionId: string): Promise<string | null> {\n if (!/^[A-Za-z0-9_-]+$/u.test(sessionId)) throw new ImageArtifactError('Invalid session identity.');\n const root = resolve(await realpath(home), 'generated_images');\n const directory = join(root, sanitize(sessionId));\n try {\n for (const path of [root, directory]) {\n const info = await lstat(path);\n if (!info.isDirectory() || info.isSymbolicLink() || (await realpath(path)) !== path)\n throw new ImageArtifactError('Unsafe image directory.');\n }\n return directory;\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') return null;\n throw error;\n }\n}\n\nfunction artifactPath(directory: string, id: string): string {\n if (!/^[A-Za-z0-9_-]{1,128}$/u.test(id)) throw new ImageArtifactError('Invalid image identity.');\n return join(directory, `${id}.png`);\n}\n\nasync function inspectArtifact(directory: string, id: string, includeData: boolean, signal?: AbortSignal) {\n signal?.throwIfAborted();\n const path = artifactPath(directory, id);\n const info = await lstat(path);\n if (!info.isFile() || info.isSymbolicLink()) throw new ImageArtifactError('Image is not a regular file.');\n const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);\n try {\n const stat = await file.stat();\n if (!stat.isFile() || stat.dev !== info.dev || stat.ino !== info.ino || (await realpath(path)) !== path)\n throw new ImageArtifactError('Image changed during access.');\n if (stat.size < PNG_SIGNATURE.length || stat.size > MAX_REFERENCE_BYTES)\n throw new ImageArtifactError('Image exceeds the size limit or is empty.');\n const signature = Buffer.alloc(PNG_SIGNATURE.length);\n await file.read(signature, 0, signature.length, 0);\n if (!signature.equals(PNG_SIGNATURE)) throw new ImageArtifactError('Image is not a PNG.');\n const metadata: ImageArtifactMetadata = { id, createdAt: stat.mtime.toISOString(), byteLength: stat.size };\n if (!includeData) return { metadata, path, data: undefined };\n // Read only the admitted length, even if another process grows the file.\n const data = Buffer.alloc(stat.size);\n let offset = 0;\n while (offset < data.length) {\n signal?.throwIfAborted();\n const read = await file.read(data, offset, data.length - offset, offset);\n if (!read.bytesRead) throw new ImageArtifactError('Image changed during access.');\n offset += read.bytesRead;\n }\n const after = await file.stat();\n if (after.size !== stat.size || after.mtimeMs !== stat.mtimeMs || !data.subarray(0, 8).equals(PNG_SIGNATURE))\n throw new ImageArtifactError('Image changed during access.');\n return { metadata, path, data };\n } finally {\n await file.close();\n }\n}\n\nexport async function listImageArtifacts(\n home: string,\n sessionId: string,\n limit = 6,\n cursor = 0,\n signal?: AbortSignal,\n): Promise<ImageArtifactList> {\n if (\n !Number.isInteger(limit) ||\n limit < 1 ||\n limit > 24 ||\n !Number.isInteger(cursor) ||\n cursor < 0 ||\n cursor > MAX_DIRECTORY_ENTRIES\n )\n throw new ImageArtifactError('Invalid image page.');\n const directory = await sessionDirectory(home, sessionId);\n const items: ImageArtifactMetadata[] = [];\n if (directory) {\n const entries = await opendir(directory);\n let count = 0;\n for await (const entry of entries) {\n signal?.throwIfAborted();\n if (++count > MAX_DIRECTORY_ENTRIES) throw new ImageArtifactError('Image directory exceeds the listing limit.');\n if (!entry.isFile() || !/^[A-Za-z0-9_-]{1,128}\\.png$/u.test(entry.name)) continue;\n try {\n items.push((await inspectArtifact(directory, entry.name.slice(0, -4), false, signal)).metadata);\n } catch (error) {\n signal?.throwIfAborted();\n // Unsafe, oversized or concurrently removed artifacts are not advertised.\n if (\n !(error instanceof ImageArtifactError) &&\n !(error instanceof Error && 'code' in error && error.code === 'ENOENT')\n )\n throw error;\n }\n }\n }\n items.sort((a, b) => b.createdAt.localeCompare(a.createdAt) || a.id.localeCompare(b.id));\n return {\n sessionId,\n items: items.slice(cursor, cursor + limit),\n nextCursor: cursor + limit < items.length ? String(cursor + limit) : null,\n };\n}\n\nexport async function readImageArtifact(\n home: string,\n sessionId: string,\n id: string,\n signal?: AbortSignal,\n): Promise<ImageArtifact> {\n const directory = await sessionDirectory(home, sessionId);\n if (!directory) throw new ImageArtifactError('Image not found.');\n const { metadata, path, data } = await inspectArtifact(directory, id, true, signal);\n if (!data) throw new ImageArtifactError('Image data unavailable.');\n return {\n ...metadata,\n sessionId,\n originalPath: path,\n sourceSha256: createHash('sha256').update(data).digest('hex'),\n data: data.toString('base64'),\n mimeType: 'image/png',\n };\n}\n\nexport async function saveImageArtifact(\n home: string,\n sessionId: string,\n callId: string,\n data: string,\n signal?: AbortSignal,\n): Promise<string> {\n signal?.throwIfAborted();\n const directory = join(home, 'generated_images', sanitize(sessionId));\n const path = join(directory, `${sanitize(callId)}.png`);\n await mkdir(directory, { recursive: true });\n signal?.throwIfAborted();\n const file = await open(path, 'wx', 0o600);\n try {\n await file.writeFile(Buffer.from(data, 'base64'));\n } catch (error) {\n await file.close();\n await unlink(path).catch(() => undefined);\n throw error;\n }\n await file.close();\n return path;\n}\n","import { constants } from 'node:fs';\nimport { open } from 'node:fs/promises';\nimport { isAbsolute } from 'node:path';\n\nimport { MAX_REFERENCE_BYTES, MAX_TOTAL_REFERENCE_BYTES } from '../../constants/imagegen';\n\nexport async function readImageReferences(\n paths: readonly string[],\n signal?: AbortSignal,\n): Promise<{ data: string; mimeType: string }[]> {\n if (paths.length > 5) throw new Error('At most five reference images are supported.');\n const images: { data: string; mimeType: string }[] = [];\n let total = 0;\n for (const path of paths) {\n signal?.throwIfAborted();\n if (!isAbsolute(path)) throw new Error('Reference image paths must be absolute.');\n const file = await open(path, constants.O_RDONLY | constants.O_NONBLOCK);\n try {\n const stats = await file.stat();\n if (!stats.isFile()) throw new Error('Reference images must be regular files.');\n if (stats.size > MAX_REFERENCE_BYTES || total + stats.size > MAX_TOTAL_REFERENCE_BYTES)\n throw new Error('Reference image size limit exceeded.');\n // Bound reads even if another process grows the file after stat.\n const bytes = Buffer.alloc(Math.min(stats.size + 1, MAX_REFERENCE_BYTES + 1));\n let length = 0;\n while (length < bytes.length) {\n signal?.throwIfAborted();\n const result = await file.read(bytes, length, bytes.length - length, null);\n if (!result.bytesRead) break;\n length += result.bytesRead;\n }\n if (length > stats.size) throw new Error('Reference image changed while reading.');\n const image = bytes.subarray(0, length);\n const mimeType = image.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))\n ? 'image/png'\n : image[0] === 255 && image[1] === 216 && image[2] === 255\n ? 'image/jpeg'\n : image.toString('ascii', 0, 4) === 'RIFF' && image.toString('ascii', 8, 12) === 'WEBP'\n ? 'image/webp'\n : undefined;\n if (!mimeType) throw new Error('Reference images must be PNG, JPEG or WebP.');\n total += length;\n images.push({ data: image.toString('base64'), mimeType });\n } finally {\n await file.close();\n }\n }\n return images;\n}\n","import { randomUUID } from 'node:crypto';\n\nimport type { PoHeadlessTool } from '@agimon-ai/po-core/headless';\n\nimport { IMAGEGEN_DESCRIPTION, IMAGEGEN_NAME } from '../../constants/imagegen';\nimport { ImagegenParamsSchema } from '../../schemas/imagegen';\nimport { saveImageArtifact } from '../imageArtifacts';\nimport { readImageReferences } from '../imageReferences';\nimport type { ImagegenDetails } from './type';\n\nexport function createImagegenTool(home: string): PoHeadlessTool<typeof ImagegenParamsSchema> {\n return {\n name: IMAGEGEN_NAME,\n label: IMAGEGEN_NAME,\n description: IMAGEGEN_DESCRIPTION,\n parameters: ImagegenParamsSchema,\n executionMode: 'parallel',\n async execute(toolCallId, params, signal, _onUpdate, context) {\n signal?.throwIfAborted();\n if (!params.prompt.trim()) throw new Error('Image prompts must not be blank.');\n const capability = context.imageGeneration;\n if (!capability?.available())\n throw new Error(\n 'Image generation needs a ChatGPT sign-in. Sign in to ChatGPT for Po features under Settings > Providers, or with /login.',\n );\n const images = await readImageReferences(params.referenced_image_paths ?? [], signal);\n const result = await capability.generate({\n prompt: params.prompt,\n transparentBackground: params.transparent_background,\n images,\n correlationId: toolCallId,\n signal,\n });\n signal?.throwIfAborted();\n const details: ImagegenDetails = { requestId: result.requestId, generationId: result.generationId };\n try {\n details.savedPath = await saveImageArtifact(home, context.sessionId, toolCallId, result.data, signal);\n } catch {\n signal?.throwIfAborted();\n details.saveWarning = 'Image generated, but could not be saved. The inline image is still available.';\n }\n if (details.savedPath) context.client?.setStatus('image-gen.images', randomUUID());\n return {\n content: [\n { type: 'image', data: result.data, mimeType: result.mimeType },\n {\n type: 'text',\n text: details.savedPath\n ? `Generated image saved to ${details.savedPath}. Copy it when using another destination and preserve the original.`\n : details.saveWarning!,\n },\n ],\n details,\n };\n },\n };\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Type } from "typebox";
2
- import { DoomHeadlessTool } from "@agimon-ai/po-core/headless";
2
+ import { PoHeadlessTool } from "@agimon-ai/po-core/headless";
3
3
  //#region src/schemas/imagegen.d.ts
4
4
  declare const ImagegenParamsSchema: Type.TObject<{
5
5
  prompt: Type.TString;
@@ -8,7 +8,7 @@ declare const ImagegenParamsSchema: Type.TObject<{
8
8
  }>;
9
9
  //#endregion
10
10
  //#region src/services/imagegenTool/index.d.ts
11
- export declare function createImagegenTool(home: string): DoomHeadlessTool<typeof ImagegenParamsSchema>;
11
+ export declare function createImagegenTool(home: string): PoHeadlessTool<typeof ImagegenParamsSchema>;
12
12
  //#endregion
13
13
  //#region src/services/imagegenTool/type.d.ts
14
14
  interface ImagegenDetails {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/schemas/imagegen.ts","../src/services/imagegenTool/index.ts","../src/services/imagegenTool/type.ts"],"mappings":";;;cAEa,sBAAoB,KAAA;;;;;;;wBCQjB,mBAAmB,eAAe,wBAAwB;;;UCVzD;EACf;EACA;EACA;EACA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/schemas/imagegen.ts","../src/services/imagegenTool/index.ts","../src/services/imagegenTool/type.ts"],"mappings":";;;cAEa,sBAAoB,KAAA;;;;;;;wBCQjB,mBAAmB,eAAe,sBAAsB;;;UCVvD;EACf;EACA;EACA;EACA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-image-gen",
3
- "version": "0.0.0-alpha.2",
3
+ "version": "0.0.0-alpha.3",
4
4
  "description": "Generate and edit images using a ChatGPT subscription.",
5
5
  "keywords": [
6
6
  "coding-agent",
@@ -58,25 +58,25 @@
58
58
  "access": "public"
59
59
  },
60
60
  "dependencies": {
61
- "@agimon-ai/po-core": "0.0.0-alpha.3",
62
- "@agimon-ai/po-web-components": "0.0.0-alpha.3",
63
- "@agimon-ai/po-web-security": "0.0.0-alpha.3",
61
+ "@agimon-ai/po-core": "0.0.0-alpha.4",
62
+ "@agimon-ai/po-web-components": "0.0.0-alpha.4",
63
+ "@agimon-ai/po-web-security": "0.0.0-alpha.4",
64
64
  "@deepseek-ai/cordis": "4.0.4",
65
65
  "react": "19.3.0",
66
- "typebox": "1.3.36"
66
+ "typebox": "1.3.37"
67
67
  },
68
68
  "devDependencies": {
69
- "@agimon-ai/po-build": "0.0.0-alpha.3",
70
- "@agimon-ai/vibe-lint-plugin-doom-extension": "0.0.0-alpha.3",
71
- "@agimon-ai/vibe-lint-plugin-doom-web": "0.0.0-alpha.3",
69
+ "@agimon-ai/po-build": "0.0.0-alpha.4",
70
+ "@agimon-ai/vibe-lint-plugin-po-extension": "0.0.0-alpha.4",
71
+ "@agimon-ai/vibe-lint-plugin-po-web": "0.0.0-alpha.4",
72
72
  "@earendil-works/pi-coding-agent": "1.2.0",
73
- "@types/node": "25.9.9",
73
+ "@types/node": "26.6.5",
74
74
  "@types/react": "19.3.0",
75
- "@vitest/coverage-v8": "5.0.3",
75
+ "@vitest/coverage-v8": "5.0.4",
76
76
  "react-dom": "19.3.0",
77
77
  "tsdown": "0.23.1",
78
78
  "typescript": "7.0.2",
79
- "vitest": "5.0.3"
79
+ "vitest": "5.0.4"
80
80
  },
81
81
  "peerDependencies": {
82
82
  "@earendil-works/pi-coding-agent": "1.2.0"