@rizom/brain 0.2.0-alpha.223 → 0.2.0-alpha.225

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.
Files changed (62) hide show
  1. package/dist/brain.js +1007 -1001
  2. package/dist/chunks/blog-post-adapter-tk0z5tgh.js +5 -0
  3. package/dist/chunks/{index-ps0mn8y9.js → index-18d0wj5t.js} +4 -4
  4. package/dist/chunks/{index-ps0mn8y9.js.map → index-18d0wj5t.js.map} +1 -1
  5. package/dist/chunks/{index-px8fmtx1.js → index-1qz89akh.js} +4 -4
  6. package/dist/chunks/{index-px8fmtx1.js.map → index-1qz89akh.js.map} +1 -1
  7. package/dist/chunks/{index-vtwspye3.js → index-48mg443r.js} +3 -3
  8. package/dist/chunks/{index-vtwspye3.js.map → index-48mg443r.js.map} +1 -1
  9. package/dist/chunks/{index-0bjkx8vb.js → index-4xzx30t8.js} +4 -4
  10. package/dist/chunks/{index-0bjkx8vb.js.map → index-4xzx30t8.js.map} +2 -2
  11. package/dist/chunks/{index-gca7xnrh.js → index-e933mq3w.js} +3 -3
  12. package/dist/chunks/{index-gca7xnrh.js.map → index-e933mq3w.js.map} +1 -1
  13. package/dist/chunks/{index-nqjbkf5n.js → index-gaa2742w.js} +3 -3
  14. package/dist/chunks/{index-nqjbkf5n.js.map → index-gaa2742w.js.map} +1 -1
  15. package/dist/chunks/index-gfewwta6.js +6 -0
  16. package/dist/chunks/{index-59y15khc.js.map → index-gfewwta6.js.map} +2 -2
  17. package/dist/chunks/{index-57d1xga4.js → index-h1zmmtbw.js} +4 -4
  18. package/dist/chunks/{index-57d1xga4.js.map → index-h1zmmtbw.js.map} +1 -1
  19. package/dist/chunks/index-jm9vaxsh.js +10 -0
  20. package/dist/chunks/{index-836tm28j.js.map → index-jm9vaxsh.js.map} +8 -8
  21. package/dist/chunks/{index-c93wmj0d.js → index-q53nehd5.js} +4 -4
  22. package/dist/chunks/{index-c93wmj0d.js.map → index-q53nehd5.js.map} +3 -3
  23. package/dist/chunks/index-rng6ka15.js +6 -0
  24. package/dist/chunks/{index-t7hbrpyx.js.map → index-rng6ka15.js.map} +12 -12
  25. package/dist/chunks/{rss-datasource-c67ta2xa.js → rss-datasource-v805vq9d.js} +3 -3
  26. package/dist/chunks/{rss-datasource-c67ta2xa.js.map → rss-datasource-v805vq9d.js.map} +1 -1
  27. package/dist/deploy.js +1 -1
  28. package/dist/entities.js +2 -2
  29. package/dist/entities.js.map +1 -1
  30. package/dist/index.js +2 -2
  31. package/dist/index.js.map +1 -1
  32. package/dist/interfaces.js +2 -2
  33. package/dist/interfaces.js.map +1 -1
  34. package/dist/plugins.d.ts +17 -5
  35. package/dist/plugins.js +3 -3
  36. package/dist/plugins.js.map +3 -3
  37. package/dist/seed-content/ranger/anchor-profile/anchor-profile.md +1 -1
  38. package/dist/seed-content/ranger/site-info/site-info.md +1 -0
  39. package/dist/seed-content/relay/site-info/site-info.md +1 -0
  40. package/dist/seed-content/rover-seed-content-core/anchor-profile/anchor-profile.md +1 -1
  41. package/dist/seed-content/rover-seed-content-core/style-guide/style-guide.md +48 -0
  42. package/dist/seed-content/rover-seed-content-default/anchor-profile/anchor-profile.md +1 -1
  43. package/dist/seed-content/rover-seed-content-default/site-info/site-info.md +1 -0
  44. package/dist/seed-content/rover-seed-content-default/style-guide/style-guide.md +48 -0
  45. package/dist/seed-content/rover-seed-content-full/anchor-profile/anchor-profile.md +1 -1
  46. package/dist/seed-content/rover-seed-content-full/site-info/site-info.md +1 -0
  47. package/dist/seed-content/rover-seed-content-full/style-guide/style-guide.md +48 -0
  48. package/dist/services.js +2 -2
  49. package/dist/services.js.map +1 -1
  50. package/dist/site.js +155 -160
  51. package/dist/site.js.map +33 -25
  52. package/dist/templates.js +2 -2
  53. package/dist/templates.js.map +1 -1
  54. package/dist/themes.js +1 -1
  55. package/dist/ui/cms-app.js +121 -121
  56. package/dist/ui/cms-app.js.map +6 -6
  57. package/package.json +1 -1
  58. package/dist/chunks/blog-post-adapter-gny02sy3.js +0 -5
  59. package/dist/chunks/index-59y15khc.js +0 -6
  60. package/dist/chunks/index-836tm28j.js +0 -10
  61. package/dist/chunks/index-t7hbrpyx.js +0 -6
  62. /package/dist/chunks/{blog-post-adapter-gny02sy3.js.map → blog-post-adapter-tk0z5tgh.js.map} +0 -0
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../shell/plugins/src/system-channels.ts", "../../../shell/plugins/src/service/upload-registry.ts", "../../../shell/plugins/src/service/base-generation-job-handler.ts", "../../../shell/plugins/src/message-interface/stored-message-metadata.ts", "../../../shell/plugins/src/message-interface/confirmation-result.ts", "../../../shell/plugins/src/message-interface/artifact-display.ts", "../../../shell/plugins/src/message-interface/upload-policy.ts", "../../../shell/plugins/src/service/create-entity-with-unique-title.ts", "../../../shell/identity-service/src/brain-character-schema.ts", "../../../shell/identity-service/src/brain-character-adapter.ts", "../../../shell/identity-service/src/brain-character-service.ts", "../../../shell/identity-service/src/anchor-profile-schema.ts", "../../../shell/identity-service/src/anchor-profile-adapter.ts", "../../../shell/identity-service/src/profile-helpers.ts", "../../../shell/identity-service/src/anchor-profile-service.ts", "../../../shell/plugins/src/a2a/agent-card-schema.ts", "../../../shell/plugins/src/a2a/skill-data-schema.ts", "../../../shell/plugins/src/manager/pluginManager.ts", "../../../shell/plugins/src/manager/types.ts", "../../../shell/plugins/src/errors.ts", "../../../shell/plugins/src/manager/plugin-resource-scope.ts", "../../../shell/plugins/src/manager/plugin-lifecycle.ts", "../../../shell/plugins/src/manager/dependency-resolver.ts", "../../../shell/plugins/src/manager/capability-registrar.ts", "../../../entities/blog/src/schemas/blog-post.ts"],
3
+ "sources": ["../../../shell/plugins/src/system-channels.ts", "../../../shell/plugins/src/service/upload-registry.ts", "../../../shell/plugins/src/service/base-generation-job-handler.ts", "../../../shell/plugins/src/message-interface/stored-message-metadata.ts", "../../../shell/plugins/src/message-interface/confirmation-result.ts", "../../../shell/plugins/src/message-interface/artifact-display.ts", "../../../shell/plugins/src/message-interface/upload-policy.ts", "../../../shell/plugins/src/service/create-entity-with-unique-title.ts", "../../../shell/identity-service/src/brain-character-schema.ts", "../../../shell/identity-service/src/brain-character-adapter.ts", "../../../shell/identity-service/src/brain-character-service.ts", "../../../shell/identity-service/src/anchor-profile-schema.ts", "../../../shell/identity-service/src/anchor-profile-adapter.ts", "../../../shell/identity-service/src/anchor-profile-service.ts", "../../../shell/identity-service/src/profile-kind-registry.ts", "../../../shell/plugins/src/a2a/agent-card-schema.ts", "../../../shell/plugins/src/a2a/skill-data-schema.ts", "../../../shell/plugins/src/manager/pluginManager.ts", "../../../shell/plugins/src/manager/types.ts", "../../../shell/plugins/src/errors.ts", "../../../shell/plugins/src/manager/plugin-resource-scope.ts", "../../../shell/plugins/src/manager/plugin-lifecycle.ts", "../../../shell/plugins/src/manager/dependency-resolver.ts", "../../../shell/plugins/src/manager/capability-registrar.ts", "../../../entities/blog/src/schemas/blog-post.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Internal shell coordination channel names.\n *\n * Keep names aligned with their lifecycle timing: registration coordination is\n * not the same as ready-state preparation.\n */\nexport const SYSTEM_CHANNELS = {\n /** Emitted after every plugin has completed registration. */\n pluginsRegistered: \"system:plugins:registered\",\n /** Emitted by directory-sync after startup import has completed. */\n initialSyncCompleted: \"sync:initial:completed\",\n} as const;\n\nexport type SystemChannelName =\n (typeof SYSTEM_CHANNELS)[keyof typeof SYSTEM_CHANNELS];\n",
5
+ "/**\n * Internal shell coordination channel names.\n *\n * Keep names aligned with their lifecycle timing: registration coordination is\n * not the same as ready-state preparation.\n */\nexport const SYSTEM_CHANNELS = {\n /** Emitted after every plugin has completed registration. */\n pluginsRegistered: \"system:plugins:registered\",\n /** Emitted by directory-sync after startup import has completed. */\n initialSyncCompleted: \"sync:initial:completed\",\n /** Emitted after shell boot completes and guarded shell APIs are available. */\n shellReady: \"system:shell:ready\",\n} as const;\n\nexport type SystemChannelName =\n (typeof SYSTEM_CHANNELS)[keyof typeof SYSTEM_CHANNELS];\n",
6
6
  "import { mkdir, readdir, readFile, rm, stat, writeFile } from \"fs/promises\";\nimport { basename, dirname, join } from \"path\";\nimport { z } from \"@brains/utils/zod\";\n\nexport const runtimeUploadIdPattern: RegExp =\n /^upload-[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nexport const defaultRuntimeUploadRetentionMs: number = 24 * 60 * 60 * 1000;\nexport const defaultRuntimeUploadMaxCount: number = 200;\n\nexport interface RuntimeUploadRef {\n kind: string;\n id: string;\n}\n\nexport interface RuntimeUploadRecord {\n id: string;\n ref: RuntimeUploadRef;\n filename: string;\n mediaType: string;\n sizeBytes: number;\n createdAt: string;\n metadata?: Record<string, unknown> | undefined;\n}\n\nexport interface RuntimeUploadResponseBody extends RuntimeUploadRecord {\n url: string;\n downloadUrl: string;\n}\n\nexport interface RuntimeUploadScopeOptions {\n /** Filesystem namespace below the runtime data directory, e.g. \"upload\". */\n namespace: string;\n /** Ref discriminator exposed to clients, e.g. \"upload\". */\n refKind: string;\n /** HTTP route used to resolve stored uploads, e.g. \"/api/chat/uploads\". */\n routePath: string;\n retentionMs?: number | undefined;\n maxCount?: number | undefined;\n createId?: (() => string) | undefined;\n now?: (() => Date) | undefined;\n}\n\nexport interface RuntimeUploadRegistryOptions {\n dataDir: string;\n}\n\nexport interface SaveRuntimeUploadInput {\n filename: string;\n mediaType: string;\n content: Buffer;\n metadata?: Record<string, unknown> | undefined;\n}\n\nexport interface ResolvedRuntimeUpload {\n record: RuntimeUploadRecord;\n content: Buffer;\n}\n\nexport type RuntimeUploadStoreErrorCode =\n \"invalid_ref\" | \"not_found\" | \"invalid_metadata\";\n\nexport class RuntimeUploadStoreError extends Error {\n public readonly code: RuntimeUploadStoreErrorCode;\n constructor(code: RuntimeUploadStoreErrorCode, message: string) {\n super(message);\n this.code = code;\n this.name = \"RuntimeUploadStoreError\";\n }\n}\n\nconst runtimeUploadRecordSchema = z.object({\n id: z.string().regex(runtimeUploadIdPattern),\n ref: z.object({\n kind: z.string().min(1),\n id: z.string().regex(runtimeUploadIdPattern),\n }),\n filename: z.string().min(1),\n mediaType: z.string().min(1),\n sizeBytes: z.number().nonnegative(),\n createdAt: z.string().datetime(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport interface IRuntimeUploadsNamespace {\n /** Create a scoped runtime upload store for an interface/plugin namespace. */\n scoped(options: RuntimeUploadScopeOptions): RuntimeUploadStore;\n}\n\nexport function createRuntimeUploadsNamespace(\n registry: RuntimeUploadRegistry,\n): IRuntimeUploadsNamespace {\n return {\n scoped: (options: RuntimeUploadScopeOptions): RuntimeUploadStore =>\n registry.scoped(options),\n };\n}\n\nexport function normalizeRuntimeUploadDataDir(contentDataDir: string): string {\n return basename(contentDataDir) === \"brain-data\"\n ? join(dirname(contentDataDir), \"data\")\n : contentDataDir;\n}\n\nexport class RuntimeUploadRegistry {\n private readonly dataDir: string;\n\n constructor(options: RuntimeUploadRegistryOptions) {\n this.dataDir = normalizeRuntimeUploadDataDir(options.dataDir);\n }\n\n static createFresh(\n options: RuntimeUploadRegistryOptions,\n ): RuntimeUploadRegistry {\n return new RuntimeUploadRegistry(options);\n }\n\n scoped(options: RuntimeUploadScopeOptions): RuntimeUploadStore {\n return new RuntimeUploadStore({ ...options, dataDir: this.dataDir });\n }\n}\n\nexport interface RuntimeUploadStoreOptions extends RuntimeUploadScopeOptions {\n dataDir: string;\n}\n\nexport class RuntimeUploadStore {\n private readonly options: RuntimeUploadStoreOptions;\n private readonly retentionMs: number;\n private readonly maxCount: number;\n private readonly createUploadId: () => string;\n private readonly getNow: () => Date;\n\n constructor(options: RuntimeUploadStoreOptions) {\n this.options = options;\n this.retentionMs = options.retentionMs ?? defaultRuntimeUploadRetentionMs;\n this.maxCount = options.maxCount ?? defaultRuntimeUploadMaxCount;\n this.createUploadId =\n options.createId ?? ((): string => `upload-${crypto.randomUUID()}`);\n this.getNow = options.now ?? ((): Date => new Date());\n }\n\n async save(input: SaveRuntimeUploadInput): Promise<RuntimeUploadRecord> {\n const uploadId = this.createUploadId();\n this.assertValidUploadId(uploadId);\n\n const record: RuntimeUploadRecord = {\n id: uploadId,\n ref: { kind: this.options.refKind, id: uploadId },\n filename: input.filename,\n mediaType: input.mediaType,\n sizeBytes: input.content.byteLength,\n createdAt: this.getNow().toISOString(),\n ...(input.metadata !== undefined && { metadata: input.metadata }),\n };\n\n const uploadDir = this.getUploadDir(uploadId);\n await mkdir(uploadDir, { recursive: true });\n await writeFile(join(uploadDir, \"content\"), input.content);\n await writeFile(\n join(uploadDir, \"metadata.json\"),\n `${JSON.stringify(record, null, 2)}\\n`,\n \"utf8\",\n );\n await this.prune();\n\n return record;\n }\n\n async read(uploadId: string): Promise<ResolvedRuntimeUpload> {\n const record = await this.readRecord(uploadId);\n try {\n const content = await readFile(\n join(this.getUploadDir(uploadId), \"content\"),\n );\n return { record, content };\n } catch {\n throw new RuntimeUploadStoreError(\"not_found\", \"Upload not found\");\n }\n }\n\n async readRecord(uploadId: string): Promise<RuntimeUploadRecord> {\n this.assertValidUploadId(uploadId);\n\n try {\n const raw = await readFile(\n join(this.getUploadDir(uploadId), \"metadata.json\"),\n \"utf8\",\n );\n const parsed = runtimeUploadRecordSchema.safeParse(JSON.parse(raw));\n if (\n !parsed.success ||\n parsed.data.id !== uploadId ||\n parsed.data.ref.id !== uploadId ||\n parsed.data.ref.kind !== this.options.refKind\n ) {\n throw new RuntimeUploadStoreError(\n \"invalid_metadata\",\n \"Invalid upload metadata\",\n );\n }\n return parsed.data;\n } catch (error) {\n if (error instanceof RuntimeUploadStoreError) throw error;\n throw new RuntimeUploadStoreError(\"not_found\", \"Upload not found\");\n }\n }\n\n toResponseBody(record: RuntimeUploadRecord): RuntimeUploadResponseBody {\n return {\n ...record,\n url: this.getUploadUrl(record.id),\n downloadUrl: this.getUploadUrl(record.id, true),\n };\n }\n\n async prune(): Promise<void> {\n const root = this.getUploadsRoot();\n try {\n const entries = await readdir(root);\n const stats = await Promise.all(\n entries.map(async (entry) => {\n try {\n const info = await stat(join(root, entry));\n return info.isDirectory() ? { entry, mtimeMs: info.mtimeMs } : null;\n } catch {\n return null;\n }\n }),\n );\n const dirs = stats\n .filter(\n (value): value is { entry: string; mtimeMs: number } =>\n value !== null,\n )\n .sort((a, b) => b.mtimeMs - a.mtimeMs);\n const cutoff = this.getNow().getTime() - this.retentionMs;\n const stale = dirs.filter(\n (dir, index) => index >= this.maxCount || dir.mtimeMs < cutoff,\n );\n await Promise.all(\n stale.map((dir) =>\n rm(join(root, dir.entry), { recursive: true, force: true }),\n ),\n );\n } catch {\n /* uploads dir missing or unreadable — nothing to prune */\n }\n }\n\n getUploadDir(uploadId: string): string {\n this.assertValidUploadId(uploadId);\n return join(this.getUploadsRoot(), uploadId);\n }\n\n private getUploadsRoot(): string {\n return join(this.options.dataDir, this.options.namespace, \"uploads\");\n }\n\n private getUploadUrl(uploadId: string, download = false): string {\n this.assertValidUploadId(uploadId);\n const encodedId = encodeURIComponent(uploadId);\n return `${this.options.routePath}?id=${encodedId}${download ? \"&download=1\" : \"\"}`;\n }\n\n private assertValidUploadId(uploadId: string): void {\n if (!runtimeUploadIdPattern.test(uploadId)) {\n throw new RuntimeUploadStoreError(\"invalid_ref\", \"Invalid upload ref\");\n }\n }\n}\n",
7
7
  "import { IMAGE_CHANNELS } from \"@brains/contracts\";\nimport { BaseJobHandler } from \"@brains/job-queue\";\nimport type { JobDataSchema } from \"@brains/job-queue\";\nimport type { BaseEntity } from \"@brains/entity-service\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { ProgressReporter } from \"@brains/utils/progress\";\nimport { getErrorMessage } from \"@brains/utils/error\";\nimport {\n generateMarkdown,\n parseMarkdown,\n updateFrontmatterField,\n} from \"@brains/utils/markdown\";\nimport {\n PROGRESS_STEPS,\n JobResult,\n type GenerationResult,\n} from \"@brains/contracts\";\nimport type { EntityPluginContext } from \"../entity/context\";\n\n/**\n * Configuration for BaseGenerationJobHandler\n */\nexport interface GenerationJobHandlerConfig<TInput> {\n /** Zod schema for validating job input */\n schema: JobDataSchema<TInput>;\n /** Job type name for logging */\n jobTypeName: string;\n /** Entity type being generated (e.g., \"post\", \"note\", \"deck\") */\n entityType: string;\n}\n\n/**\n * Result of the generate step — the resolved content before entity creation.\n *\n * Subclasses return this from `generate()`. The base class handles\n * progress reporting, error wrapping, and entity creation.\n */\nexport interface GenericCoverImageRequest {\n generate?: boolean;\n prompt?: string;\n}\n\ninterface NormalizedGenericCoverImageRequest {\n generate: true;\n prompt?: string;\n}\n\nfunction getPreallocatedEntityId(data: unknown): string | undefined {\n if (typeof data !== \"object\" || data === null || !(\"entityId\" in data)) {\n return undefined;\n }\n const entityId = data.entityId;\n return typeof entityId === \"string\" && entityId.trim().length > 0\n ? entityId.trim()\n : undefined;\n}\n\nfunction normalizeGenericCoverImageRequest(\n data: unknown,\n): NormalizedGenericCoverImageRequest | undefined {\n if (typeof data !== \"object\" || data === null || !(\"coverImage\" in data)) {\n return undefined;\n }\n\n const coverImage = (data as { coverImage?: unknown }).coverImage;\n if (coverImage === undefined || coverImage === false) return undefined;\n if (coverImage === true) return { generate: true };\n if (typeof coverImage !== \"object\" || coverImage === null) return undefined;\n\n const request = coverImage as GenericCoverImageRequest;\n if (request.generate === false) return undefined;\n const prompt = request.prompt?.trim();\n return {\n generate: true,\n ...(prompt && { prompt }),\n };\n}\n\nexport interface GeneratedContent {\n /** Entity ID (often derived from title) */\n id: string;\n /** Markdown body, optionally with frontmatter */\n content: string;\n /** Entity metadata */\n metadata: Record<string, unknown>;\n /** Title for result reporting */\n title?: string;\n /** Extra fields merged into the success result (e.g., slug) */\n resultExtras?: Record<string, unknown>;\n /** Options passed to createEntity */\n createOptions?: { deduplicateId?: boolean };\n}\n\nfunction withoutUndefined(\n input: Record<string, unknown>,\n): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(input).filter(([, value]) => value !== undefined),\n );\n}\n\nfunction withoutStubLifecycleFields(\n input: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...input };\n // Stub lifecycle fields are owned by the generation lifecycle, not by\n // durable user edits made while the stub is generating.\n delete result[\"status\"];\n delete result[\"error\"];\n return withoutUndefined(result);\n}\n\n/**\n * Abstract base class for content generation job handlers.\n *\n * Encapsulates the common flow shared by note, blog, deck, portfolio,\n * newsletter, and social-media generation handlers:\n *\n * 1. Report start\n * 2. Generate/resolve content (subclass)\n * 3. Create entity\n * 4. Post-creation hook (optional)\n * 5. Report done\n *\n * Subclasses implement `generate()` — the plugin-specific logic for\n * resolving content (AI generation, direct input, source entities, etc.).\n *\n * The base class owns:\n * - The try/catch + error result boilerplate\n * - Progress reporting at standard steps\n * - Entity creation via entityService\n * - Success/failure result construction\n *\n * @example\n * ```typescript\n * export class NoteGenerationHandler extends BaseGenerationJobHandler<NoteJobData> {\n * constructor(logger: Logger, context: ServicePluginContext) {\n * super(logger, context, {\n * schema: noteJobSchema,\n * jobTypeName: \"note-generation\",\n * entityType: \"note\",\n * });\n * }\n *\n * protected async generate(data: NoteJobData): Promise<GeneratedContent> {\n * const generated = await this.context.ai.generate<{ title: string; body: string }>({\n * prompt: data.prompt,\n * templateName: \"note:generation\",\n * });\n * const title = data.title ?? generated.title;\n * return {\n * id: title,\n * content: noteAdapter.createNoteContent(title, generated.body),\n * metadata: { title },\n * title,\n * };\n * }\n * }\n * ```\n */\nexport abstract class BaseGenerationJobHandler<\n TInput = unknown,\n TResult extends GenerationResult = GenerationResult,\n> extends BaseJobHandler<string, TInput, TResult> {\n protected readonly context: EntityPluginContext;\n protected readonly entityType: string;\n\n constructor(\n logger: Logger,\n context: EntityPluginContext,\n config: GenerationJobHandlerConfig<TInput>,\n ) {\n super(logger, {\n schema: config.schema,\n jobTypeName: config.jobTypeName,\n });\n this.context = context;\n this.entityType = config.entityType;\n }\n\n /**\n * Generate or resolve content for entity creation.\n *\n * This is the only method subclasses must implement. It receives\n * the validated job data and a progress reporter, and returns\n * the content ready for entity creation.\n *\n * Progress reporting within generate() is optional — the base class\n * reports START before and SAVE/COMPLETE after.\n *\n * Throw via `this.failEarly(message)` for clean early returns.\n */\n protected abstract generate(\n data: TInput,\n progressReporter: ProgressReporter,\n ): Promise<GeneratedContent>;\n\n /**\n * Hook called after successful entity creation.\n * Override for post-creation actions (e.g., queue image generation,\n * send messaging events).\n */\n protected async afterCreate(\n _data: TInput,\n _entityId: string,\n _progressReporter: ProgressReporter,\n _generated: GeneratedContent,\n ): Promise<void> {\n // Default: no-op\n }\n\n /**\n * Hook called when generation fails (either from failEarly or exceptions).\n * Override for failure notifications (e.g., messaging events).\n */\n protected async onGenerationFailure(\n _data: TInput,\n _error: string,\n ): Promise<void> {\n // Default: no-op\n }\n\n override validateAndParse(data: unknown): TInput | null {\n const parsed = super.validateAndParse(data);\n if (!parsed) return null;\n\n const coverImage = normalizeGenericCoverImageRequest(data);\n if (typeof parsed !== \"object\") {\n return parsed;\n }\n\n const entityId = getPreallocatedEntityId(data);\n if (!coverImage && !entityId) {\n return parsed;\n }\n\n Object.assign(parsed, {\n ...(coverImage && { coverImage }),\n ...(entityId && { entityId }),\n });\n return parsed;\n }\n\n async process(\n data: TInput,\n jobId: string,\n progressReporter: ProgressReporter,\n ): Promise<TResult> {\n try {\n await this.reportProgress(progressReporter, {\n progress: PROGRESS_STEPS.START,\n message: `Starting ${this.jobTypeName}`,\n });\n\n // Step 1: Generate content (subclass logic)\n const generated = await this.generate(data, progressReporter);\n const preallocatedEntityId = getPreallocatedEntityId(data);\n const generatedForSave = preallocatedEntityId\n ? this.applyPreallocatedEntityId(preallocatedEntityId, generated)\n : generated;\n\n // Step 2: Create entity\n await this.reportProgress(progressReporter, {\n progress: PROGRESS_STEPS.SAVE,\n message: `Saving ${this.entityType} to database`,\n });\n\n const result = preallocatedEntityId\n ? await this.updatePreallocatedStub(\n preallocatedEntityId,\n generatedForSave,\n )\n : await this.context.entityService.createEntity({\n entity: {\n id: generatedForSave.id,\n entityType: this.entityType,\n content: generatedForSave.content,\n metadata: generatedForSave.metadata,\n },\n options: generatedForSave.createOptions,\n });\n\n // Step 3: Post-creation hook\n await this.afterCreate(\n data,\n result.entityId,\n progressReporter,\n generatedForSave,\n );\n await this.enqueueGenericCoverImageIfRequested(\n data,\n result.entityId,\n progressReporter,\n generatedForSave,\n );\n\n // Step 4: Done\n await this.reportProgress(progressReporter, {\n progress: PROGRESS_STEPS.COMPLETE,\n message: `${generatedForSave.title ?? this.entityType} created successfully`,\n });\n\n return {\n success: true,\n entityId: result.entityId,\n ...generatedForSave.resultExtras,\n } as TResult;\n } catch (error) {\n if (error instanceof GenerationFailure) {\n await this.markPreallocatedStubFailed(data, error.message);\n await this.onGenerationFailure(data, error.message);\n return { success: false, error: error.message } as TResult;\n }\n\n const errorMessage = getErrorMessage(error);\n this.logger.error(`${this.jobTypeName} job failed`, {\n error,\n jobId,\n data: this.summarizeDataForLog(data),\n });\n\n await this.markPreallocatedStubFailed(data, errorMessage);\n await this.onGenerationFailure(data, errorMessage);\n return JobResult.failure(error) as TResult;\n }\n }\n\n private applyPreallocatedEntityId(\n entityId: string,\n generated: GeneratedContent,\n ): GeneratedContent {\n const metadata = { ...generated.metadata };\n let content = generated.content;\n let resultExtras = generated.resultExtras;\n\n if (typeof metadata[\"slug\"] === \"string\") {\n metadata[\"slug\"] = entityId;\n content = updateFrontmatterField(content, \"slug\", entityId);\n resultExtras = { ...resultExtras, slug: entityId };\n }\n\n return {\n ...generated,\n id: entityId,\n content,\n metadata,\n ...(resultExtras && { resultExtras }),\n };\n }\n\n private async updatePreallocatedStub(\n entityId: string,\n generated: GeneratedContent,\n ): Promise<{ entityId: string; jobId: string; skipped?: boolean }> {\n const existing = await this.context.entityService.getEntity({\n entityType: this.entityType,\n id: entityId,\n visibilityScope: \"restricted\",\n });\n if (!existing) {\n throw new Error(\n `Pre-allocated entity stub not found: ${this.entityType}/${entityId}`,\n );\n }\n\n const merged = this.mergeStubWithGenerated(existing, generated);\n\n return this.context.entityService.updateEntity({\n entity: {\n ...existing,\n id: entityId,\n entityType: this.entityType,\n content: merged.content,\n metadata: merged.metadata,\n },\n });\n }\n\n private mergeStubWithGenerated(\n existing: BaseEntity,\n generated: GeneratedContent,\n ): Pick<BaseEntity, \"content\" | \"metadata\"> {\n const existingFrontmatter = withoutStubLifecycleFields(\n parseMarkdown(existing.content).frontmatter,\n );\n const existingMetadata = withoutStubLifecycleFields(existing.metadata);\n const generatedMetadata = withoutUndefined(generated.metadata);\n const generatedParsed = parseMarkdown(generated.content);\n const generatedFrontmatter = withoutUndefined(generatedParsed.frontmatter);\n\n const mergedFrontmatter = withoutUndefined({\n ...existingFrontmatter,\n ...generatedMetadata,\n ...generatedFrontmatter,\n });\n const frontmatterSchema =\n this.context.entities.getEffectiveFrontmatterSchema(this.entityType);\n // Validate only — do NOT serialize the parsed result. A default z.object\n // strips unknown keys, which would drop the preserved attachment fields\n // (coverImageId, documents, future user-attached fields) that this merge\n // exists to keep. Serialize the un-parsed mergedFrontmatter below.\n frontmatterSchema?.parse(mergedFrontmatter);\n\n return {\n content: generateMarkdown(mergedFrontmatter, generatedParsed.content),\n metadata: {\n ...existingMetadata,\n ...generatedMetadata,\n },\n };\n }\n\n private async markPreallocatedStubFailed(\n data: TInput,\n error: string,\n ): Promise<void> {\n const entityId = getPreallocatedEntityId(data);\n if (!entityId) return;\n\n try {\n const existing = await this.context.entityService.getEntity({\n entityType: this.entityType,\n id: entityId,\n visibilityScope: \"restricted\",\n });\n if (!existing) return;\n\n await this.context.entityService.updateEntity({\n entity: {\n ...existing,\n content: updateFrontmatterField(\n updateFrontmatterField(existing.content, \"status\", \"failed\"),\n \"error\",\n error,\n ),\n metadata: {\n ...existing.metadata,\n status: \"failed\",\n error,\n },\n },\n });\n } catch (failure) {\n this.logger.warn(\"Failed to mark generation stub as failed\", {\n error: failure,\n entityId,\n entityType: this.entityType,\n });\n }\n }\n\n private async enqueueGenericCoverImageIfRequested(\n data: TInput,\n entityId: string,\n progressReporter: ProgressReporter,\n generated: GeneratedContent,\n ): Promise<void> {\n const coverImage = normalizeGenericCoverImageRequest(data);\n if (!coverImage) return;\n\n await this.reportProgress(progressReporter, {\n progress: 90,\n message: \"Queueing cover image generation\",\n });\n\n const title = generated.title ?? entityId;\n await this.context.jobs.enqueue({\n type: IMAGE_CHANNELS.generate,\n data: {\n prompt: coverImage.prompt ?? `Editorial cover image for: ${title}. `,\n title: `${title} Cover`,\n aspectRatio: \"16:9\",\n targetEntityType: this.entityType,\n targetEntityId: entityId,\n entityTitle: title,\n entityContent: generated.content,\n },\n toolContext: { interfaceType: \"job\", userId: \"system\" },\n });\n }\n\n /**\n * Signal an early failure from within `generate()`.\n * Produces a clean `{ success: false, error }` result without logging an error.\n */\n protected failEarly(message: string): never {\n throw new GenerationFailure(message);\n }\n}\n\n/**\n * Internal error type for clean early failures (not logged as errors).\n */\nclass GenerationFailure extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GenerationFailure\";\n }\n}\n",
8
8
  "import { z } from \"@brains/utils/zod\";\nimport {\n AttachmentCardSchema,\n StructuredChatCardSchema,\n ToolApprovalCardSchema,\n type AttachmentCard,\n type StructuredChatCard,\n} from \"../contracts/agent\";\n\nconst storedAttachmentSourceSchema: z.ZodObject<{\n kind: z.ZodString;\n id: z.ZodString;\n}> = z.object({\n kind: z.string().min(1),\n id: z.string().min(1),\n});\n\nconst storedMessageAttachmentSchema: z.ZodObject<{\n kind: z.ZodString;\n filename: z.ZodString;\n mediaType: z.ZodString;\n sizeBytes: z.ZodOptional<z.ZodNumber>;\n source: z.ZodOptional<typeof storedAttachmentSourceSchema>;\n}> = z.object({\n kind: z.string().min(1),\n filename: z.string().min(1),\n mediaType: z.string().min(1),\n sizeBytes: z.number().nonnegative().optional(),\n source: storedAttachmentSourceSchema.optional(),\n});\n\nconst storedMessageAttachmentsSchema: z.ZodArray<\n typeof storedMessageAttachmentSchema\n> = z.array(storedMessageAttachmentSchema);\nconst storedAttachmentCardsSchema = z.array(AttachmentCardSchema);\nconst storedToolApprovalCardsSchema = z.array(ToolApprovalCardSchema);\nconst storedMessageMetadataRecordSchema = z.record(z.string(), z.unknown());\n\nexport type StoredMessageAttachment = z.infer<\n typeof storedMessageAttachmentSchema\n>;\n\nexport function parseStoredMessageMetadata(\n metadata: unknown,\n): Record<string, unknown> | null {\n if (typeof metadata === \"string\") {\n try {\n return parseMetadataRecord(JSON.parse(metadata));\n } catch {\n return null;\n }\n }\n return parseMetadataRecord(metadata);\n}\n\nexport function getStoredMessageAttachments(\n metadata: unknown,\n): StoredMessageAttachment[] {\n const parsedMetadata = parseStoredMessageMetadata(metadata);\n const parsedAttachments = storedMessageAttachmentsSchema.safeParse(\n parsedMetadata?.[\"attachments\"],\n );\n return parsedAttachments.success ? parsedAttachments.data : [];\n}\n\nexport function getStoredAttachmentCards(metadata: unknown): AttachmentCard[] {\n const attachmentCards = getStoredMessageCards(metadata).filter(\n (card): card is AttachmentCard => card.kind === \"attachment\",\n );\n const parsedCards = storedAttachmentCardsSchema.safeParse(attachmentCards);\n return parsedCards.success ? parsedCards.data : [];\n}\n\nexport function getStoredMessageCards(metadata: unknown): StructuredChatCard[] {\n const parsedMetadata = parseStoredMessageMetadata(metadata);\n const cards = parsedMetadata?.[\"cards\"];\n if (!Array.isArray(cards)) return [];\n\n return cards\n .map((card) => StructuredChatCardSchema.safeParse(card))\n .filter((result) => result.success)\n .map((result) => result.data);\n}\n\nexport function collectUploadIdsFromStoredMessages(\n messages: readonly unknown[],\n options: { sourceKind: string; role?: string | undefined },\n): string[] {\n const ids: string[] = [];\n const seen = new Set<string>();\n for (const message of messages) {\n const parsedMessage = parseMetadataRecord(message);\n if (!parsedMessage) continue;\n if (options.role && parsedMessage[\"role\"] !== options.role) continue;\n for (const attachment of getStoredMessageAttachments(\n parsedMessage[\"metadata\"],\n )) {\n if (attachment.source?.kind !== options.sourceKind) continue;\n if (seen.has(attachment.source.id)) continue;\n seen.add(attachment.source.id);\n ids.push(attachment.source.id);\n }\n }\n return ids;\n}\n\nexport function collectPendingApprovalIdsFromStoredMessages(\n messages: readonly unknown[],\n): Set<string> {\n const pending = new Set<string>();\n for (const message of messages) {\n const parsedMessage = parseMetadataRecord(message);\n if (!parsedMessage) continue;\n const parsedMetadata = parseStoredMessageMetadata(\n parsedMessage[\"metadata\"],\n );\n const cards = parsedMetadata?.[\"cards\"];\n if (!Array.isArray(cards)) continue;\n\n const approvalCandidates = cards.filter(\n (card) => parseMetadataRecord(card)?.[\"kind\"] === \"tool-approval\",\n );\n const parsedCards =\n storedToolApprovalCardsSchema.safeParse(approvalCandidates);\n if (!parsedCards.success) continue;\n\n for (const card of parsedCards.data) {\n if (card.state === \"approval-requested\") {\n pending.add(card.id);\n } else {\n pending.delete(card.id);\n }\n }\n }\n return pending;\n}\n\nfunction parseMetadataRecord(value: unknown): Record<string, unknown> | null {\n const parsed = storedMessageMetadataRecordSchema.safeParse(value);\n return parsed.success ? parsed.data : null;\n}\n",
@@ -13,22 +13,22 @@
13
13
  "import { z } from \"@brains/utils/zod\";\nimport { baseEntitySchema } from \"@brains/entity-service\";\n\n/**\n * Brain character entity schema\n * Character data (role, purpose, values) is stored in content field as structured markdown\n */\nexport const brainCharacterSchema: ReturnType<\n typeof baseEntitySchema.extend<{\n id: z.ZodLiteral<\"brain-character\">;\n entityType: z.ZodLiteral<\"brain-character\">;\n }>\n> = baseEntitySchema.extend({\n id: z.literal(\"brain-character\"),\n entityType: z.literal(\"brain-character\"),\n});\n\n/**\n * Brain character entity type derived from schema\n */\nexport type BrainCharacterEntity = z.infer<typeof brainCharacterSchema>;\n\nexport interface BrainCharacter {\n name: string;\n role: string;\n purpose: string;\n values: string[];\n}\n\nexport type BrainCharacterBodySchema = z.ZodObject<{\n name: z.ZodString;\n role: z.ZodString;\n purpose: z.ZodString;\n values: z.ZodArray<z.ZodString>;\n}>;\n\n/**\n * Brain character body schema - structure of content within the markdown\n * (Not stored as separate entity fields - parsed from content)\n */\nexport const brainCharacterBodySchema: BrainCharacterBodySchema = z.object({\n name: z.string().describe(\"The brain's friendly display name\"),\n role: z.string().describe(\"The brain's primary role\"),\n purpose: z.string().describe(\"The brain's purpose and goals\"),\n values: z.array(z.string()).describe(\"Core values that guide behavior\"),\n});\n\n/**\n * Brain character body type\n */\nexport type BrainCharacterFrontmatterSchema = BrainCharacterBodySchema;\n\n/**\n * Brain character frontmatter schema for CMS editing\n * Same shape as body schema — all character data is structured fields\n */\nexport const brainCharacterFrontmatterSchema: BrainCharacterFrontmatterSchema =\n brainCharacterBodySchema;\n",
14
14
  "import { BaseEntityAdapter } from \"@brains/entity-service\";\nimport { z } from \"@brains/utils/zod\";\nimport {\n brainCharacterSchema,\n brainCharacterBodySchema,\n type BrainCharacterEntity,\n type BrainCharacter,\n} from \"./brain-character-schema\";\n\nconst frontmatterRecordSchema = z.record(z.string(), z.unknown());\n\n/**\n * Entity adapter for Brain Character entities\n * Uses frontmatter format for CMS compatibility\n */\nexport class BrainCharacterAdapter extends BaseEntityAdapter<\n BrainCharacterEntity,\n Record<string, unknown>,\n BrainCharacter\n> {\n constructor() {\n super({\n entityType: \"brain-character\",\n purpose: \"The brain's own identity, character, and purpose (singleton).\",\n schema: brainCharacterSchema,\n frontmatterSchema: brainCharacterBodySchema,\n isSingleton: true,\n hasBody: false,\n });\n }\n\n /**\n * Create character content in frontmatter format\n */\n public createCharacterContent(params: {\n name: string;\n role: string;\n purpose: string;\n values: string[];\n }): string {\n return this.buildMarkdown(\"\", params);\n }\n\n /**\n * Parse character body from content\n */\n public parseCharacterBody(content: string): BrainCharacter {\n return this.parseFrontmatter(content);\n }\n\n /**\n * Convert character entity to frontmatter markdown\n */\n public override toMarkdown(entity: BrainCharacterEntity): string {\n const data = this.parseFrontmatter(entity.content);\n return this.buildMarkdown(\"\", frontmatterRecordSchema.parse(data));\n }\n\n /**\n * Create partial entity from markdown content\n */\n public fromMarkdown(markdown: string): Partial<BrainCharacterEntity> {\n return {\n content: markdown,\n entityType: \"brain-character\",\n };\n }\n\n /**\n * Extract metadata for search/filtering\n */\n public override extractMetadata(\n entity: BrainCharacterEntity,\n ): Record<string, unknown> {\n const data = this.parseFrontmatter(entity.content);\n return {\n role: data.role,\n values: data.values,\n };\n }\n\n /**\n * Generate frontmatter for the entity\n */\n public override generateFrontMatter(entity: BrainCharacterEntity): string {\n const data = this.parseFrontmatter(entity.content);\n return this.buildMarkdown(\"\", frontmatterRecordSchema.parse(data));\n }\n}\n",
15
15
  "import type { IEntityService } from \"@brains/entity-service\";\nimport {\n internalFullScope,\n SingletonEntityService,\n} from \"@brains/entity-service\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { BrainCharacter } from \"./brain-character-schema\";\nimport { BrainCharacterAdapter } from \"./brain-character-adapter\";\n\n/**\n * Interface for consuming the brain's character data\n * Use this in consumers instead of the concrete class\n */\nexport interface IBrainCharacterService {\n getCharacter(): BrainCharacter;\n}\n\n/**\n * Brain Character Service\n * Caches and provides the brain's character (role, purpose, values)\n */\nexport class BrainCharacterService\n extends SingletonEntityService<BrainCharacter>\n implements IBrainCharacterService\n{\n private static instance: BrainCharacterService | null = null;\n private adapter = new BrainCharacterAdapter();\n\n /**\n * Get the default character for a new brain\n */\n public static getDefaultCharacter(): BrainCharacter {\n return {\n name: \"Brain\",\n role: \"Knowledge assistant\",\n purpose:\n \"Help organize, understand, and retrieve information from your knowledge base\",\n values: [\"clarity\", \"accuracy\", \"helpfulness\"],\n };\n }\n\n /**\n * Get the singleton instance\n */\n public static getInstance(\n entityService: IEntityService,\n logger: Logger,\n defaultCharacter?: BrainCharacter,\n ): BrainCharacterService {\n BrainCharacterService.instance ??= new BrainCharacterService(\n entityService,\n logger,\n defaultCharacter,\n );\n return BrainCharacterService.instance;\n }\n\n /**\n * Reset the singleton instance (for testing)\n */\n public static resetInstance(): void {\n BrainCharacterService.instance = null;\n }\n\n /**\n * Create a fresh instance without affecting singleton\n */\n public static createFresh(\n entityService: IEntityService,\n logger: Logger,\n defaultCharacter?: BrainCharacter,\n ): BrainCharacterService {\n return new BrainCharacterService(entityService, logger, defaultCharacter);\n }\n\n /**\n * Private constructor to enforce factory methods\n */\n private constructor(\n entityService: IEntityService,\n logger: Logger,\n defaultCharacter?: BrainCharacter,\n ) {\n super(\n entityService,\n logger,\n \"brain-character\",\n defaultCharacter ?? BrainCharacterService.getDefaultCharacter(),\n internalFullScope(\n \"brain character is loaded at bootstrap before any user is in scope\",\n ),\n );\n }\n\n protected parseBody(content: string): BrainCharacter {\n return this.adapter.parseCharacterBody(content);\n }\n\n protected createContent(body: BrainCharacter): string {\n return this.adapter.createCharacterContent(body);\n }\n\n /**\n * Get the character data (from cache or default)\n */\n public getCharacter(): BrainCharacter {\n return this.get();\n }\n\n /**\n * Get the raw character content (markdown)\n */\n public getCharacterContent(): string {\n return this.getContent();\n }\n}\n",
16
- "import { z } from \"@brains/utils/zod\";\nimport { baseEntitySchema } from \"@brains/entity-service\";\n\n/**\n * Anchor profile entity schema\n * Profile data (name, description, socialLinks) is stored in content field as structured markdown\n */\nexport const anchorProfileSchema: ReturnType<\n typeof baseEntitySchema.extend<{\n id: z.ZodLiteral<\"anchor-profile\">;\n entityType: z.ZodLiteral<\"anchor-profile\">;\n }>\n> = baseEntitySchema.extend({\n id: z.literal(\"anchor-profile\"),\n entityType: z.literal(\"anchor-profile\"),\n});\n\n/**\n * Anchor profile entity type derived from schema\n */\nexport type AnchorProfileEntity = z.infer<typeof anchorProfileSchema>;\n\nexport interface AnchorProfileSocialLink {\n platform: \"github\" | \"instagram\" | \"linkedin\" | \"email\" | \"website\";\n url: string;\n label?: string | undefined;\n}\n\nexport interface AnchorProfile {\n name: string;\n kind: \"professional\" | \"team\" | \"collective\";\n organization?: string | undefined;\n description?: string | undefined;\n avatar?: string | undefined;\n website?: string | undefined;\n email?: string | undefined;\n socialLinks?: AnchorProfileSocialLink[] | undefined;\n}\n\ntype SocialLinkSchema = z.ZodObject<{\n platform: z.ZodEnum<{\n github: \"github\";\n instagram: \"instagram\";\n linkedin: \"linkedin\";\n email: \"email\";\n website: \"website\";\n }>;\n url: z.ZodString;\n label: z.ZodOptional<z.ZodString>;\n}>;\n\nexport type AnchorProfileBodySchema = z.ZodObject<{\n name: z.ZodString;\n kind: z.ZodEnum<{\n professional: \"professional\";\n team: \"team\";\n collective: \"collective\";\n }>;\n organization: z.ZodOptional<z.ZodString>;\n description: z.ZodOptional<z.ZodString>;\n avatar: z.ZodOptional<z.ZodString>;\n website: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n socialLinks: z.ZodOptional<z.ZodArray<SocialLinkSchema>>;\n}>;\n\n/**\n * Anchor profile body schema - structure of content within the markdown\n * (Not stored as separate entity fields - parsed from content)\n */\nexport const anchorProfileBodySchema: AnchorProfileBodySchema = z.object({\n name: z.string().describe(\"Name (person or organization)\"),\n kind: z\n .enum([\"professional\", \"team\", \"collective\"])\n .describe(\"Type of anchor: professional (individual), team, or collective\"),\n organization: z\n .string()\n .optional()\n .describe(\"Organization the anchor belongs to\"),\n description: z.string().optional().describe(\"Short description or biography\"),\n avatar: z.string().optional().describe(\"URL or asset path to avatar/logo\"),\n website: z.string().optional().describe(\"Primary website URL\"),\n email: z.string().optional().describe(\"Contact email\"),\n socialLinks: z\n .array(\n z.object({\n platform: z\n .enum([\"github\", \"instagram\", \"linkedin\", \"email\", \"website\"])\n .describe(\"Social media platform\"),\n url: z.string().describe(\"Profile or contact URL\"),\n label: z.string().optional().describe(\"Optional display label\"),\n }),\n )\n .optional()\n .describe(\"Social media and contact links\"),\n});\n",
16
+ "import { z } from \"@brains/utils/zod\";\nimport { baseEntitySchema } from \"@brains/entity-service\";\n\n/**\n * Anchor profile entity schema\n * Profile data (name, description, socialLinks) is stored in content field as structured markdown\n */\nexport const anchorProfileSchema: ReturnType<\n typeof baseEntitySchema.extend<{\n id: z.ZodLiteral<\"anchor-profile\">;\n entityType: z.ZodLiteral<\"anchor-profile\">;\n }>\n> = baseEntitySchema.extend({\n id: z.literal(\"anchor-profile\"),\n entityType: z.literal(\"anchor-profile\"),\n});\n\n/**\n * Anchor profile entity type derived from schema\n */\nexport type AnchorProfileEntity = z.infer<typeof anchorProfileSchema>;\n\nexport interface AnchorProfileSocialLink {\n platform: \"github\" | \"instagram\" | \"linkedin\" | \"email\" | \"website\";\n url: string;\n label?: string | undefined;\n}\n\nexport type AnchorProfileKindSchema = z.ZodEnum<{\n person: \"person\";\n team: \"team\";\n organization: \"organization\";\n}>;\n\nexport const anchorProfileKindSchema: AnchorProfileKindSchema = z.enum([\n \"person\",\n \"team\",\n \"organization\",\n]);\n\nexport type AnchorProfileKind = z.infer<typeof anchorProfileKindSchema>;\n\nexport interface AnchorProfile {\n name: string;\n organization?: string | undefined;\n description?: string | undefined;\n avatar?: string | undefined;\n website?: string | undefined;\n email?: string | undefined;\n socialLinks?: AnchorProfileSocialLink[] | undefined;\n}\n\ntype SocialLinkSchema = z.ZodObject<{\n platform: z.ZodEnum<{\n github: \"github\";\n instagram: \"instagram\";\n linkedin: \"linkedin\";\n email: \"email\";\n website: \"website\";\n }>;\n url: z.ZodString;\n label: z.ZodOptional<z.ZodString>;\n}>;\n\nexport type AnchorProfileBodySchema = z.ZodObject<{\n name: z.ZodString;\n organization: z.ZodOptional<z.ZodString>;\n description: z.ZodOptional<z.ZodString>;\n avatar: z.ZodOptional<z.ZodString>;\n website: z.ZodOptional<z.ZodString>;\n email: z.ZodOptional<z.ZodString>;\n socialLinks: z.ZodOptional<z.ZodArray<SocialLinkSchema>>;\n}>;\n\n/**\n * Anchor profile body schema - structure of content within the markdown\n * (Not stored as separate entity fields - parsed from content)\n */\nexport const anchorProfileBodySchema: AnchorProfileBodySchema = z.object({\n name: z.string().describe(\"Name of the anchor\"),\n organization: z\n .string()\n .optional()\n .describe(\"Organization the anchor belongs to\"),\n description: z.string().optional().describe(\"Short description or biography\"),\n avatar: z.string().optional().describe(\"URL or asset path to avatar/logo\"),\n website: z.string().optional().describe(\"Primary website URL\"),\n email: z.string().optional().describe(\"Contact email\"),\n socialLinks: z\n .array(\n z.object({\n platform: z\n .enum([\"github\", \"instagram\", \"linkedin\", \"email\", \"website\"])\n .describe(\"Social media platform\"),\n url: z.string().describe(\"Profile or contact URL\"),\n label: z.string().optional().describe(\"Optional display label\"),\n }),\n )\n .optional()\n .describe(\"Social media and contact links\"),\n});\n",
17
17
  "import {\n BaseEntityAdapter,\n parseMarkdownWithFrontmatter,\n} from \"@brains/entity-service\";\nimport { z } from \"@brains/utils/zod\";\nimport {\n anchorProfileSchema,\n anchorProfileBodySchema,\n type AnchorProfileEntity,\n type AnchorProfile,\n} from \"./anchor-profile-schema\";\n\nconst frontmatterRecordSchema = z.record(z.string(), z.unknown());\n\ninterface ProfileBodyParser<T> {\n parse(data: unknown): T;\n}\n\n/**\n * Entity adapter for Anchor Profile entities\n * Uses frontmatter format for CMS compatibility\n */\nexport class AnchorProfileAdapter extends BaseEntityAdapter<\n AnchorProfileEntity,\n Record<string, unknown>,\n AnchorProfile\n> {\n constructor() {\n super({\n entityType: \"anchor-profile\",\n purpose: \"The profile of the brain's anchor owner (singleton).\",\n schema: anchorProfileSchema,\n frontmatterSchema: anchorProfileBodySchema,\n isSingleton: true,\n hasBody: true,\n });\n }\n\n /**\n * Create profile content in frontmatter format\n * Validates input data through Zod schema\n */\n public createProfileContent(params: AnchorProfile): string {\n const validatedData = anchorProfileBodySchema.parse(params);\n return this.buildMarkdown(\"\", validatedData);\n }\n\n /**\n * Parse profile body from content.\n * When called with an extended schema, parses against that schema\n * and maps the markdown body to the `story` field.\n */\n public parseProfileBody(content: string): AnchorProfile;\n public parseProfileBody<T extends Record<string, unknown>>(\n content: string,\n schema: ProfileBodyParser<T>,\n ): T;\n public parseProfileBody<T extends Record<string, unknown>>(\n content: string,\n schema?: ProfileBodyParser<T>,\n ): AnchorProfile | T {\n if (schema) {\n const { metadata: parsed, content: body } = parseMarkdownWithFrontmatter(\n content,\n schema,\n );\n return body ? { ...parsed, story: body } : parsed;\n }\n return this.parseFrontmatter(content);\n }\n\n /**\n * Create partial entity from markdown content\n * Preserves frontmatter as-is to avoid stripping extension fields (e.g., tagline, expertise)\n */\n public fromMarkdown(markdown: string): Partial<AnchorProfileEntity> {\n return {\n content: markdown,\n entityType: \"anchor-profile\",\n };\n }\n\n /**\n * Extract metadata for search/filtering\n */\n public override extractMetadata(\n entity: AnchorProfileEntity,\n ): Record<string, unknown> {\n const data = this.parseFrontmatter(entity.content);\n return {\n name: data.name,\n email: data.email,\n website: data.website,\n };\n }\n\n /**\n * Generate frontmatter for the entity\n */\n public override generateFrontMatter(entity: AnchorProfileEntity): string {\n const data = this.parseFrontmatter(entity.content);\n return this.buildMarkdown(\"\", frontmatterRecordSchema.parse(data));\n }\n}\n",
18
- "import { z } from \"@brains/utils/zod\";\nimport type { ICoreEntityService } from \"@brains/entity-service\";\nimport { AnchorProfileAdapter } from \"./anchor-profile-adapter\";\n\nexport interface BaseProfileExtension {\n tagline?: string | undefined;\n intro?: string | undefined;\n story?: string | undefined;\n}\n\nexport type BaseProfileExtensionSchema = z.ZodObject<{\n tagline: z.ZodOptional<z.ZodString>;\n intro: z.ZodOptional<z.ZodString>;\n story: z.ZodOptional<z.ZodString>;\n}>;\n\n/**\n * Shared profile fields used by all layout packages.\n * Layout-specific extensions (e.g. expertise, availability) extend this.\n */\nexport const baseProfileExtension: BaseProfileExtensionSchema = z.object({\n tagline: z\n .string()\n .optional()\n .describe(\"Short, punchy one-liner for homepage\"),\n intro: z\n .string()\n .optional()\n .describe(\"Optional longer introduction for homepage\"),\n story: z\n .string()\n .optional()\n .describe(\"Extended bio/narrative (multi-paragraph markdown)\"),\n});\n\nexport interface ProfessionalProfileExtension extends BaseProfileExtension {\n role?: string | undefined;\n audience?: string | undefined;\n expertise?: string[] | undefined;\n currentFocus?: string | undefined;\n availability?: string | undefined;\n desiredTone?: string | undefined;\n}\n\nexport type ProfessionalProfileExtensionSchema = ReturnType<\n typeof baseProfileExtension.extend<{\n role: z.ZodOptional<z.ZodString>;\n audience: z.ZodOptional<z.ZodString>;\n expertise: z.ZodOptional<z.ZodArray<z.ZodString>>;\n currentFocus: z.ZodOptional<z.ZodString>;\n availability: z.ZodOptional<z.ZodString>;\n desiredTone: z.ZodOptional<z.ZodString>;\n }>\n>;\n\n/**\n * Shared professional profile fields.\n *\n * The base anchor-profile schema remains brain-model agnostic. Brain models\n * and site compositions that operate on professional profiles can opt into\n * this extension explicitly.\n */\nexport const professionalProfileExtension: ProfessionalProfileExtensionSchema =\n baseProfileExtension.extend({\n role: z\n .string()\n .optional()\n .describe(\"Professional role or working identity\"),\n audience: z\n .string()\n .optional()\n .describe(\"Primary audience or community served\"),\n expertise: z\n .array(z.string())\n .optional()\n .describe(\"Skills, domains, areas of focus\"),\n currentFocus: z\n .string()\n .optional()\n .describe(\"What you're currently working on\"),\n availability: z\n .string()\n .optional()\n .describe(\"What you're open to (consulting, speaking, etc.)\"),\n desiredTone: z\n .string()\n .optional()\n .describe(\"Preferred tone for profile-shaped outputs\"),\n });\n\n/**\n * Fetch the anchor-profile entity content.\n * Returns the raw markdown string — caller parses with their own schema\n * via AnchorProfileAdapter.parseProfileBody(content, schema).\n */\nexport async function fetchAnchorProfile(\n entityService: ICoreEntityService,\n): Promise<string> {\n const entities = await entityService.listEntities({\n entityType: \"anchor-profile\",\n options: {\n limit: 1,\n },\n });\n const entity = entities[0];\n if (!entity) {\n throw new Error(\"Profile not found — create an anchor-profile entity\");\n }\n return entity.content;\n}\n\n/**\n * Fetch the anchor-profile entity and parse its body with the given schema.\n * Combines {@link fetchAnchorProfile} with the adapter parse step that every\n * profile consumer otherwise repeats.\n */\nexport async function fetchAnchorProfileData<T extends Record<string, unknown>>(\n entityService: ICoreEntityService,\n schema: z.ZodSchema<T>,\n): Promise<T> {\n const content = await fetchAnchorProfile(entityService);\n return new AnchorProfileAdapter().parseProfileBody(content, schema);\n}\n",
19
- "import type { IEntityService } from \"@brains/entity-service\";\nimport {\n internalFullScope,\n SingletonEntityService,\n} from \"@brains/entity-service\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { AnchorProfile } from \"./anchor-profile-schema\";\nimport { AnchorProfileAdapter } from \"./anchor-profile-adapter\";\n\n/**\n * Interface for consuming the anchor's profile data\n * Use this in consumers instead of the concrete class\n */\nexport interface IAnchorProfileService {\n getProfile(): AnchorProfile;\n}\n\n/**\n * Anchor Profile Service\n * Provides the person/organization's public profile (name, bio, socialLinks)\n */\nexport class AnchorProfileService\n extends SingletonEntityService<AnchorProfile>\n implements IAnchorProfileService\n{\n private static instance: AnchorProfileService | null = null;\n private adapter = new AnchorProfileAdapter();\n\n /**\n * Get the default profile for a new brain\n */\n public static getDefaultProfile(): AnchorProfile {\n return {\n name: \"Unknown\",\n kind: \"professional\" as const,\n };\n }\n\n /**\n * Get the singleton instance\n */\n public static getInstance(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ): AnchorProfileService {\n AnchorProfileService.instance ??= new AnchorProfileService(\n entityService,\n logger,\n defaultProfile,\n );\n return AnchorProfileService.instance;\n }\n\n /**\n * Reset the singleton instance (for testing)\n */\n public static resetInstance(): void {\n AnchorProfileService.instance = null;\n }\n\n /**\n * Create a fresh instance without affecting singleton\n */\n public static createFresh(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ): AnchorProfileService {\n return new AnchorProfileService(entityService, logger, defaultProfile);\n }\n\n /**\n * Private constructor to enforce factory methods\n */\n private constructor(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ) {\n super(\n entityService,\n logger,\n \"anchor-profile\",\n defaultProfile ?? AnchorProfileService.getDefaultProfile(),\n internalFullScope(\n \"anchor profile is loaded at bootstrap before any user is in scope\",\n ),\n );\n }\n\n protected parseBody(content: string): AnchorProfile {\n return this.adapter.parseProfileBody(content);\n }\n\n protected createContent(body: AnchorProfile): string {\n return this.adapter.createProfileContent(body);\n }\n\n /**\n * Get the profile data (from cache or default)\n */\n public getProfile(): AnchorProfile {\n return this.get();\n }\n\n /**\n * Get the raw profile content (markdown)\n */\n public getProfileContent(): string {\n return this.getContent();\n }\n}\n",
20
- "import { z } from \"@brains/utils/zod\";\nimport {\n type AnchorProfile,\n anchorProfileBodySchema,\n} from \"@brains/identity-service\";\n\n/**\n * URI for the anchor-profile A2A Agent Card extension.\n */\nexport const ANCHOR_EXTENSION_URI = \"https://rizom.ai/ext/anchor-profile/v1\";\n\n/**\n * Shared Zod schemas for parsing A2A Agent Cards.\n * Used by the A2A interface (client) and the agent directory plugin.\n */\n\nexport const agentCardSkillSchema: z.ZodObject<{\n id: z.ZodString;\n description: z.ZodString;\n name: z.ZodOptional<z.ZodString>;\n tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;\n}> = z.looseObject({\n id: z.string(),\n description: z.string(),\n name: z.string().optional(),\n tags: z.array(z.string()).optional().default([]),\n});\n\nexport const anchorExtensionParamsSchema: z.ZodType<AnchorProfile> =\n anchorProfileBodySchema;\n\nconst extensionSchema: z.ZodObject<{\n uri: z.ZodString;\n params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n}> = z.looseObject({\n uri: z.string(),\n params: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const agentCardSchema: z.ZodObject<{\n name: z.ZodString;\n url: z.ZodString;\n description: z.ZodOptional<z.ZodString>;\n skills: z.ZodDefault<z.ZodOptional<z.ZodArray<typeof agentCardSkillSchema>>>;\n capabilities: z.ZodOptional<\n z.ZodObject<{\n extensions: z.ZodDefault<\n z.ZodOptional<z.ZodArray<typeof extensionSchema>>\n >;\n }>\n >;\n}> = z.looseObject({\n name: z.string(),\n url: z.string(),\n description: z.string().optional(),\n skills: z.array(agentCardSkillSchema).optional().default([]),\n capabilities: z\n .looseObject({\n extensions: z.array(extensionSchema).optional().default([]),\n })\n .optional(),\n});\n\n/**\n * Parsed Agent Card with anchor extension data extracted.\n */\nexport interface ParsedAgentCard {\n brainName: string;\n url: string;\n description: string;\n skills: Array<{\n id: string;\n name: string;\n description: string;\n tags: string[];\n }>;\n anchor: AnchorProfile | null;\n}\n\n/**\n * Parse raw Agent Card JSON into a ParsedAgentCard.\n * Extracts the anchor-profile extension if present.\n * Returns null if the data doesn't match the schema.\n */\nexport function parseAgentCard(data: unknown): ParsedAgentCard | null {\n const parsed = agentCardSchema.safeParse(data);\n if (!parsed.success) return null;\n\n const card = parsed.data;\n\n const extensions = card.capabilities?.extensions ?? [];\n const anchorExt = extensions.find((e) => e.uri === ANCHOR_EXTENSION_URI);\n\n let anchor: ParsedAgentCard[\"anchor\"] = null;\n if (anchorExt?.params) {\n const anchorParsed = anchorExtensionParamsSchema.safeParse(\n anchorExt.params,\n );\n if (anchorParsed.success) {\n anchor = anchorParsed.data;\n }\n }\n\n return {\n brainName: card.name,\n url: card.url,\n description: card.description ?? \"\",\n skills: card.skills.map((s) => ({\n id: s.id,\n name: s.name ?? s.id,\n description: s.description,\n tags: s.tags,\n })),\n anchor,\n };\n}\n",
18
+ "import type { IEntityService } from \"@brains/entity-service\";\nimport {\n internalFullScope,\n SingletonEntityService,\n} from \"@brains/entity-service\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { AnchorProfile } from \"./anchor-profile-schema\";\nimport { AnchorProfileAdapter } from \"./anchor-profile-adapter\";\n\n/**\n * Interface for consuming the anchor's profile data\n * Use this in consumers instead of the concrete class\n */\nexport interface IAnchorProfileService {\n getProfile(): AnchorProfile;\n}\n\n/**\n * Anchor Profile Service\n * Provides the person/organization's public profile (name, bio, socialLinks)\n */\nexport class AnchorProfileService\n extends SingletonEntityService<AnchorProfile>\n implements IAnchorProfileService\n{\n private static instance: AnchorProfileService | null = null;\n private adapter = new AnchorProfileAdapter();\n\n /**\n * Get the default profile for a new brain\n */\n public static getDefaultProfile(): AnchorProfile {\n return { name: \"Unknown\" };\n }\n\n /**\n * Get the singleton instance\n */\n public static getInstance(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ): AnchorProfileService {\n AnchorProfileService.instance ??= new AnchorProfileService(\n entityService,\n logger,\n defaultProfile,\n );\n return AnchorProfileService.instance;\n }\n\n /**\n * Reset the singleton instance (for testing)\n */\n public static resetInstance(): void {\n AnchorProfileService.instance = null;\n }\n\n /**\n * Create a fresh instance without affecting singleton\n */\n public static createFresh(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ): AnchorProfileService {\n return new AnchorProfileService(entityService, logger, defaultProfile);\n }\n\n /**\n * Private constructor to enforce factory methods\n */\n private constructor(\n entityService: IEntityService,\n logger: Logger,\n defaultProfile?: AnchorProfile,\n ) {\n super(\n entityService,\n logger,\n \"anchor-profile\",\n defaultProfile ?? AnchorProfileService.getDefaultProfile(),\n internalFullScope(\n \"anchor profile is loaded at bootstrap before any user is in scope\",\n ),\n );\n }\n\n protected parseBody(content: string): AnchorProfile {\n return this.adapter.parseProfileBody(content);\n }\n\n protected createContent(body: AnchorProfile): string {\n return this.adapter.createProfileContent(body);\n }\n\n /**\n * Get the profile data (from cache or default)\n */\n public getProfile(): AnchorProfile {\n return this.get();\n }\n\n /**\n * Get the raw profile content (markdown)\n */\n public getProfileContent(): string {\n return this.getContent();\n }\n}\n",
19
+ "import type { FrontmatterSchema } from \"@brains/entity-service\";\nimport { z } from \"@brains/utils/zod\";\n\nexport const profileCategorySchema: z.ZodEnum<{\n person: \"person\";\n team: \"team\";\n organization: \"organization\";\n}> = z.enum([\"person\", \"team\", \"organization\"]);\n\nexport type ProfileCategory = z.infer<typeof profileCategorySchema>;\n\nexport interface ProfileKindLabels {\n singular: string;\n plural: string;\n}\n\nexport interface ProfileKindDefinition {\n kind: string;\n category: ProfileCategory;\n fields: FrontmatterSchema;\n labels: ProfileKindLabels;\n}\n\nexport interface ResolvedProfileKind {\n kind: string;\n category: ProfileCategory;\n labels: ProfileKindLabels;\n}\n\nexport type ResolvedProfileSelection = ResolvedProfileKind | null;\n\ninterface RegisteredProfileKind {\n pluginId: string;\n definition: ProfileKindDefinition;\n}\n\nconst profileKindMetadataSchema = z.object({\n kind: z.string().trim().min(1),\n category: profileCategorySchema,\n labels: z.object({\n singular: z.string().trim().min(1),\n plural: z.string().trim().min(1),\n }),\n});\n\nfunction validateFields(fields: unknown): asserts fields is FrontmatterSchema {\n if (\n typeof fields !== \"object\" ||\n fields === null ||\n !(\"shape\" in fields) ||\n !(\"safeParse\" in fields) ||\n typeof fields.safeParse !== \"function\"\n ) {\n throw new Error(\"Profile kind fields must be a Zod object schema\");\n }\n}\n\nexport interface IProfileKindRegistry {\n register(pluginId: string, definition: ProfileKindDefinition): void;\n unregisterPlugin(pluginId: string): void;\n finalize(): ResolvedProfileSelection;\n getResolved(): ResolvedProfileSelection;\n getSelectedDefinition(): ProfileKindDefinition | undefined;\n isFinalized(): boolean;\n}\n\n/** App-scoped catalog and immutable selected profile-kind resolution. */\nexport class ProfileKindRegistry implements IProfileKindRegistry {\n private readonly selectedKind: string | undefined;\n private readonly registrations = new Map<string, RegisteredProfileKind[]>();\n private finalized = false;\n private resolved: ResolvedProfileSelection = null;\n private selectedDefinition: ProfileKindDefinition | undefined;\n\n public constructor(selectedKind?: string) {\n const normalized = selectedKind?.trim();\n this.selectedKind = normalized === \"\" ? undefined : normalized;\n }\n\n public register(pluginId: string, definition: ProfileKindDefinition): void {\n if (this.finalized) {\n throw new Error(\"Profile kind registration is closed\");\n }\n\n const metadata = profileKindMetadataSchema.parse(definition);\n validateFields(definition.fields);\n const normalizedDefinition: ProfileKindDefinition = Object.freeze({\n ...definition,\n kind: metadata.kind,\n category: metadata.category,\n labels: Object.freeze({ ...metadata.labels }),\n });\n const registrations = this.registrations.get(metadata.kind) ?? [];\n registrations.push({ pluginId, definition: normalizedDefinition });\n this.registrations.set(metadata.kind, registrations);\n }\n\n public unregisterPlugin(pluginId: string): void {\n for (const [kind, registrations] of this.registrations) {\n const remaining = registrations.filter(\n (registration) => registration.pluginId !== pluginId,\n );\n if (remaining.length === 0) {\n this.registrations.delete(kind);\n } else {\n this.registrations.set(kind, remaining);\n }\n }\n }\n\n public finalize(): ResolvedProfileSelection {\n if (this.finalized) return this.resolved;\n\n const collisions = [...this.registrations.entries()]\n .filter(([, registrations]) => registrations.length > 1)\n .sort(([left], [right]) => left.localeCompare(right));\n const collision = collisions[0];\n if (collision) {\n const [kind, registrations] = collision;\n const pluginIds = registrations\n .map((registration) => registration.pluginId)\n .sort()\n .join(\", \");\n throw new Error(\n `Profile kind \"${kind}\" is registered by multiple plugins: ${pluginIds}`,\n );\n }\n\n if (!this.selectedKind) {\n this.finalized = true;\n this.resolved = null;\n return null;\n }\n\n const selected = this.registrations.get(this.selectedKind)?.[0];\n if (!selected) {\n throw new Error(\n `Selected profile kind \"${this.selectedKind}\" is not registered`,\n );\n }\n\n this.selectedDefinition = selected.definition;\n this.resolved = Object.freeze({\n kind: selected.definition.kind,\n category: selected.definition.category,\n labels: Object.freeze({ ...selected.definition.labels }),\n });\n this.finalized = true;\n return this.resolved;\n }\n\n public getResolved(): ResolvedProfileSelection {\n this.assertFinalized();\n return this.resolved;\n }\n\n public getSelectedDefinition(): ProfileKindDefinition | undefined {\n this.assertFinalized();\n return this.selectedDefinition;\n }\n\n public isFinalized(): boolean {\n return this.finalized;\n }\n\n private assertFinalized(): void {\n if (!this.finalized) {\n throw new Error(\"Profile kind selection has not been finalized\");\n }\n }\n}\n",
20
+ "import { z } from \"@brains/utils/zod\";\nimport {\n type AnchorProfile,\n type ProfileCategory,\n anchorProfileBodySchema,\n profileCategorySchema,\n} from \"@brains/identity-service\";\n\n/**\n * URI for the anchor-profile A2A Agent Card extension.\n */\nexport const ANCHOR_EXTENSION_URI = \"https://rizom.ai/ext/anchor-profile/v1\";\n\n/**\n * Shared Zod schemas for parsing A2A Agent Cards.\n * Used by the A2A interface (client) and the agent directory plugin.\n */\n\nexport const agentCardSkillSchema: z.ZodObject<{\n id: z.ZodString;\n description: z.ZodString;\n name: z.ZodOptional<z.ZodString>;\n tags: z.ZodDefault<z.ZodOptional<z.ZodArray<z.ZodString>>>;\n}> = z.looseObject({\n id: z.string(),\n description: z.string(),\n name: z.string().optional(),\n tags: z.array(z.string()).optional().default([]),\n});\n\nexport interface AnchorExtensionProfile extends AnchorProfile {\n kind?: string | undefined;\n category?: ProfileCategory | undefined;\n}\n\nexport const anchorExtensionParamsSchema: z.ZodType<AnchorExtensionProfile> =\n anchorProfileBodySchema\n .extend({\n kind: z.string().trim().min(1).optional(),\n category: profileCategorySchema.optional(),\n })\n .superRefine((value, ctx) => {\n if ((value.kind === undefined) !== (value.category === undefined)) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Anchor kind and category must be provided together\",\n });\n }\n });\n\nconst extensionSchema: z.ZodObject<{\n uri: z.ZodString;\n params: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;\n}> = z.looseObject({\n uri: z.string(),\n params: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport const agentCardSchema: z.ZodObject<{\n name: z.ZodString;\n url: z.ZodString;\n description: z.ZodOptional<z.ZodString>;\n skills: z.ZodDefault<z.ZodOptional<z.ZodArray<typeof agentCardSkillSchema>>>;\n capabilities: z.ZodOptional<\n z.ZodObject<{\n extensions: z.ZodDefault<\n z.ZodOptional<z.ZodArray<typeof extensionSchema>>\n >;\n }>\n >;\n}> = z.looseObject({\n name: z.string(),\n url: z.string(),\n description: z.string().optional(),\n skills: z.array(agentCardSkillSchema).optional().default([]),\n capabilities: z\n .looseObject({\n extensions: z.array(extensionSchema).optional().default([]),\n })\n .optional(),\n});\n\n/**\n * Parsed Agent Card with anchor extension data extracted.\n */\nexport interface ParsedAgentCard {\n brainName: string;\n url: string;\n description: string;\n skills: Array<{\n id: string;\n name: string;\n description: string;\n tags: string[];\n }>;\n anchor: AnchorExtensionProfile | null;\n}\n\n/**\n * Parse raw Agent Card JSON into a ParsedAgentCard.\n * Extracts the anchor-profile extension if present.\n * Returns null if the data doesn't match the schema.\n */\nexport function parseAgentCard(data: unknown): ParsedAgentCard | null {\n const parsed = agentCardSchema.safeParse(data);\n if (!parsed.success) return null;\n\n const card = parsed.data;\n\n const extensions = card.capabilities?.extensions ?? [];\n const anchorExt = extensions.find(\n (extension) => extension.uri === ANCHOR_EXTENSION_URI,\n );\n\n let anchor: ParsedAgentCard[\"anchor\"] = null;\n if (anchorExt?.params) {\n const anchorParsed = anchorExtensionParamsSchema.safeParse(\n anchorExt.params,\n );\n if (anchorParsed.success) {\n anchor = anchorParsed.data;\n }\n }\n\n return {\n brainName: card.name,\n url: card.url,\n description: card.description ?? \"\",\n skills: card.skills.map((s) => ({\n id: s.id,\n name: s.name ?? s.id,\n description: s.description,\n tags: s.tags,\n })),\n anchor,\n };\n}\n",
21
21
  "import { z } from \"@brains/utils/zod\";\n\n/**\n * Skill data for Agent Card integration.\n * Defined here as the shared Zod 4 contract used by agent-card parsing and\n * durable skill entity/frontmatter schemas.\n */\nexport const skillDataSchema: z.ZodObject<{\n name: z.ZodString;\n description: z.ZodString;\n tags: z.ZodArray<z.ZodString>;\n examples: z.ZodArray<z.ZodString>;\n}> = z.object({\n name: z.string(),\n description: z.string(),\n tags: z.array(z.string()),\n examples: z.array(z.string()),\n});\n\nexport type SkillData = z.output<typeof skillDataSchema>;\n",
22
- "import type { Logger } from \"@brains/utils/logger\";\nimport type { IShell } from \"../interfaces\";\nimport { EventEmitter } from \"events\";\nimport type { Plugin, PluginRegistrationContext } from \"../interfaces\";\nimport type { IDaemonRegistry } from \"./daemon-types\";\nimport type {\n PluginManager as IPluginManager,\n PluginInfo,\n PluginManagerEventMap,\n} from \"./types\";\nimport { PluginStatus, PluginEvent } from \"./types\";\nimport { PluginError } from \"../errors\";\nimport { PluginLifecycle } from \"./plugin-lifecycle\";\nimport { DependencyResolver } from \"./dependency-resolver\";\nimport { CapabilityRegistrar } from \"./capability-registrar\";\nimport { Effect, Either } from \"@brains/utils/effect\";\n\nasync function runConcurrentPhase(\n operations: Array<() => Promise<void>>,\n): Promise<void> {\n const results = await Effect.runPromise(\n Effect.all(\n operations.map((operation) =>\n Effect.either(\n Effect.tryPromise({\n try: operation,\n catch: (error) => error,\n }),\n ),\n ),\n { concurrency: \"unbounded\" },\n ),\n );\n const firstFailure = results.find(Either.isLeft);\n if (firstFailure) throw firstFailure.left;\n}\n\n// Re-export enums for convenience\nexport { PluginEvent, PluginStatus } from \"./types\";\n\n/**\n * Plugin manager that handles plugin registration, initialization, and lifecycle\n * Implements Component Interface Standardization pattern\n */\nexport class PluginManager implements IPluginManager {\n private static instance: PluginManager | null = null;\n\n private plugins: Map<string, PluginInfo> = new Map();\n private logger: Logger;\n private events = new EventEmitter();\n private daemonRegistry: IDaemonRegistry;\n private shell: IShell | null = null;\n private initializedPluginIds: string[] = [];\n private pluginLifecycle: PluginLifecycle;\n private dependencyResolver: DependencyResolver;\n private capabilityRegistrar: CapabilityRegistrar;\n\n /**\n * Get the singleton instance of PluginManager\n */\n public static getInstance(\n logger: Logger,\n daemonRegistry: IDaemonRegistry,\n ): PluginManager {\n PluginManager.instance ??= new PluginManager(logger, daemonRegistry);\n return PluginManager.instance;\n }\n\n /**\n * Reset the singleton instance (primarily for testing)\n */\n public static resetInstance(): void {\n PluginManager.instance = null;\n }\n\n /**\n * Create a fresh instance without affecting the singleton\n */\n public static createFresh(\n logger: Logger,\n daemonRegistry: IDaemonRegistry,\n ): PluginManager {\n return new PluginManager(logger, daemonRegistry);\n }\n\n /**\n * Set the shell instance after it's created\n */\n public setShell(shell: IShell): void {\n this.shell = shell;\n }\n\n /**\n * Private constructor to enforce singleton pattern\n */\n private constructor(logger: Logger, daemonRegistry: IDaemonRegistry) {\n this.logger = logger.child(\"PluginManager\");\n this.events = new EventEmitter();\n this.daemonRegistry = daemonRegistry;\n\n // Initialize helper classes\n this.pluginLifecycle = new PluginLifecycle(\n this.plugins,\n this.events,\n this.daemonRegistry,\n logger,\n );\n this.dependencyResolver = new DependencyResolver(\n this.plugins,\n this.events,\n logger,\n );\n this.capabilityRegistrar = new CapabilityRegistrar(logger);\n }\n\n /**\n * Register a plugin with the system\n * This only registers the plugin but doesn't initialize it\n */\n public registerPlugin(plugin: Plugin): void {\n if (!plugin.id) {\n throw new PluginError(\n \"unknown\",\n \"Registration failed: Plugin must have an id\",\n );\n }\n\n this.logger.debug(`Registering plugin: ${plugin.id} (${plugin.version})`);\n\n // Check if plugin is already registered\n if (this.plugins.has(plugin.id)) {\n const existingInfo = this.plugins.get(plugin.id);\n const existingVersion = existingInfo?.plugin.version;\n\n throw new PluginError(\n plugin.id,\n `Registration failed: Plugin is already registered with version ${existingVersion}`,\n );\n }\n\n // Get dependencies or use empty array\n const dependencies = plugin.dependencies ?? [];\n\n // Store plugin info\n const pluginInfo: PluginInfo = {\n plugin,\n status: PluginStatus.REGISTERED,\n dependencies,\n };\n\n this.plugins.set(plugin.id, pluginInfo);\n this.logger.debug(`Registered plugin: ${plugin.id} (${plugin.version})`);\n\n // Emit registered event\n this.events.emit(PluginEvent.REGISTERED, plugin.id, plugin);\n }\n\n /**\n * Initialize all registered plugins in dependency order\n * Plugins with no dependencies are initialized first\n */\n public async initializePlugins(\n registrationContext?: PluginRegistrationContext,\n ): Promise<void> {\n this.logger.debug(\"Initializing plugins...\");\n\n this.initializedPluginIds = [];\n\n // Use dependency resolver to handle initialization order\n const result = await this.dependencyResolver.resolveInitializationOrder(\n async (pluginId) => {\n await this.initializePlugin(pluginId, registrationContext);\n },\n );\n\n this.logger.debug(\n `Initialized ${result.initialized.size} of ${this.plugins.size} plugins`,\n );\n }\n\n /**\n * Initialize a specific plugin\n */\n private async initializePlugin(\n pluginId: string,\n registrationContext?: PluginRegistrationContext,\n ): Promise<void> {\n if (!this.shell) {\n throw new PluginError(\n pluginId,\n \"Cannot initialize plugin: Shell not set. Call setShell() first.\",\n );\n }\n const shell = this.shell;\n\n try {\n const capabilities = await this.pluginLifecycle.initializePlugin(\n pluginId,\n shell,\n registrationContext,\n );\n\n await this.capabilityRegistrar.registerCapabilities(\n shell,\n pluginId,\n capabilities,\n );\n\n this.initializedPluginIds.push(pluginId);\n } catch (error) {\n await this.pluginLifecycle.failPluginInitialization(pluginId, error);\n throw error;\n }\n }\n\n /**\n * Dispatch ready hooks for all initialized plugins.\n *\n * Hooks run concurrently — no ordering guarantees between plugins in this\n * phase. Plugins that need cross-plugin coordination must use the message\n * bus.\n */\n public async readyPlugins(): Promise<void> {\n this.logger.debug(\"Dispatching plugin ready hooks...\");\n\n try {\n await runConcurrentPhase(\n this.initializedPluginIds.map(\n (id) => (): Promise<void> => this.pluginLifecycle.readyPlugin(id),\n ),\n );\n } catch (error) {\n for (const id of this.initializedPluginIds) {\n const pluginInfo = this.plugins.get(id);\n if (pluginInfo?.status === PluginStatus.ERROR) {\n await this.pluginLifecycle.failPluginInitialization(\n id,\n pluginInfo.error ?? error,\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Start daemons for all initialized plugins concurrently.\n */\n public async startPluginDaemons(): Promise<void> {\n this.logger.debug(\"Starting plugin daemons...\");\n\n await runConcurrentPhase(\n this.initializedPluginIds.map(\n (id) => (): Promise<void> =>\n this.pluginLifecycle.startPluginDaemons(id),\n ),\n );\n }\n\n /**\n * Get a registered plugin by ID\n */\n public getPlugin(id: string): Plugin | undefined {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.plugin;\n }\n\n /**\n * Get plugin status by ID\n */\n public getPluginStatus(id: string): PluginStatus | undefined {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.status;\n }\n\n /**\n * Check if a plugin is registered\n */\n public hasPlugin(id: string): boolean {\n return this.plugins.has(id);\n }\n\n /**\n * Check if a plugin is initialized\n */\n public isPluginInitialized(id: string): boolean {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.status === PluginStatus.INITIALIZED;\n }\n\n /**\n * Get all registered plugin IDs\n */\n public getAllPluginIds(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /**\n * Get all plugins with their status\n */\n public getAllPlugins(): Map<string, PluginInfo> {\n return new Map(this.plugins);\n }\n\n /**\n * Get plugins that failed to initialize\n */\n public getFailedPlugins(): Array<{ id: string; error: Error }> {\n return Array.from(this.plugins.entries())\n .filter(\n (entry): entry is [string, PluginInfo & { error: Error }] =>\n entry[1].status === PluginStatus.ERROR &&\n entry[1].error !== undefined,\n )\n .map(([id, info]) => ({ id, error: info.error }));\n }\n\n /**\n * Get plugin package name by ID\n */\n public getPluginPackageName(pluginId: string): string | undefined {\n const pluginInfo = this.plugins.get(pluginId);\n return pluginInfo?.plugin.packageName;\n }\n\n /** Terminally release a plugin and its runtime resources. */\n public async disablePlugin(id: string): Promise<void> {\n await this.pluginLifecycle.disablePlugin(id);\n }\n\n /** Release plugins in reverse initialization order. */\n public async shutdownPlugins(): Promise<void> {\n const released = new Set<string>();\n for (const id of [...this.initializedPluginIds].reverse()) {\n await this.disablePlugin(id);\n released.add(id);\n }\n for (const id of [...this.plugins.keys()].reverse()) {\n if (!released.has(id)) await this.disablePlugin(id);\n }\n }\n\n /**\n * Subscribe to plugin events\n */\n public on<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.on(event, listener);\n }\n\n /**\n * Subscribe to plugin events once\n */\n public once<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.once(event, listener);\n }\n\n /**\n * Unsubscribe from plugin events\n */\n public off<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.off(event, listener);\n }\n\n /**\n * Get the event emitter for external subscribers\n */\n public getEventEmitter(): EventEmitter {\n return this.events;\n }\n}\n",
23
- "import type { Plugin, PluginRegistrationContext } from \"../interfaces\";\n\n/**\n * Plugin Manager interface for managing plugin lifecycle\n */\nexport interface PluginManager {\n registerPlugin(plugin: Plugin): void;\n\n initializePlugins(context?: PluginRegistrationContext): Promise<void>;\n\n readyPlugins(): Promise<void>;\n\n startPluginDaemons(): Promise<void>;\n\n getPlugin(id: string): Plugin | undefined;\n\n getPluginStatus(id: string): PluginStatus | undefined;\n\n hasPlugin(id: string): boolean;\n\n isPluginInitialized(id: string): boolean;\n\n getAllPluginIds(): string[];\n\n getAllPlugins(): Map<string, PluginInfo>;\n\n getFailedPlugins(): Array<{ id: string; error: Error }>;\n\n disablePlugin(id: string): Promise<void>;\n\n shutdownPlugins(): Promise<void>;\n\n on<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n\n once<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n\n off<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n}\n\n/**\n * Plugin status types\n */\nexport const PluginStatus = {\n REGISTERED: \"registered\",\n INITIALIZED: \"initialized\",\n ERROR: \"error\",\n DISABLED: \"disabled\",\n} as const;\nexport type PluginStatus = (typeof PluginStatus)[keyof typeof PluginStatus];\n\n/**\n * Plugin metadata with status\n */\nexport interface PluginInfo {\n plugin: Plugin;\n status: PluginStatus;\n error?: Error;\n dependencies: string[];\n}\n\n/**\n * Plugin lifecycle event types\n */\nexport const PluginEvent = {\n REGISTERED: \"plugin:registered\",\n BEFORE_INITIALIZE: \"plugin:before_initialize\",\n INITIALIZED: \"plugin:initialized\",\n ERROR: \"plugin:error\",\n DISABLED: \"plugin:disabled\",\n} as const;\nexport type PluginEvent = (typeof PluginEvent)[keyof typeof PluginEvent];\n\n/**\n * Typed event map for PluginManager events\n */\nexport interface PluginManagerEventMap {\n [PluginEvent.REGISTERED]: [pluginId: string, plugin: Plugin];\n [PluginEvent.BEFORE_INITIALIZE]: [pluginId: string, plugin: Plugin];\n [PluginEvent.INITIALIZED]: [pluginId: string, plugin: Plugin];\n [PluginEvent.ERROR]: [pluginId: string, error: Error];\n [PluginEvent.DISABLED]: [pluginId: string];\n}\n",
22
+ "import type { Logger } from \"@brains/utils/logger\";\nimport type { IShell } from \"../interfaces\";\nimport { EventEmitter } from \"events\";\nimport type { Plugin, PluginRegistrationContext } from \"../interfaces\";\nimport type { IDaemonRegistry } from \"./daemon-types\";\nimport type {\n PluginManager as IPluginManager,\n PluginInfo,\n PluginManagerEventMap,\n} from \"./types\";\nimport { PluginStatus, PluginEvent } from \"./types\";\nimport { PluginError } from \"../errors\";\nimport { PluginLifecycle } from \"./plugin-lifecycle\";\nimport { DependencyResolver } from \"./dependency-resolver\";\nimport { CapabilityRegistrar } from \"./capability-registrar\";\nimport { Effect, Either } from \"@brains/utils/effect\";\n\nasync function runConcurrentPhase(\n operations: Array<() => Promise<void>>,\n): Promise<void> {\n const results = await Effect.runPromise(\n Effect.all(\n operations.map((operation) =>\n Effect.either(\n Effect.tryPromise({\n try: operation,\n catch: (error) => error,\n }),\n ),\n ),\n { concurrency: \"unbounded\" },\n ),\n );\n const firstFailure = results.find(Either.isLeft);\n if (firstFailure) throw firstFailure.left;\n}\n\n// Re-export enums for convenience\nexport { PluginEvent, PluginStatus } from \"./types\";\n\n/**\n * Plugin manager that handles plugin registration, initialization, and lifecycle\n * Implements Component Interface Standardization pattern\n */\nexport class PluginManager implements IPluginManager {\n private static instance: PluginManager | null = null;\n\n private plugins: Map<string, PluginInfo> = new Map();\n private logger: Logger;\n private events = new EventEmitter();\n private daemonRegistry: IDaemonRegistry;\n private shell: IShell | null = null;\n private initializedPluginIds: string[] = [];\n private pluginLifecycle: PluginLifecycle;\n private dependencyResolver: DependencyResolver;\n private capabilityRegistrar: CapabilityRegistrar;\n\n /**\n * Get the singleton instance of PluginManager\n */\n public static getInstance(\n logger: Logger,\n daemonRegistry: IDaemonRegistry,\n ): PluginManager {\n PluginManager.instance ??= new PluginManager(logger, daemonRegistry);\n return PluginManager.instance;\n }\n\n /**\n * Reset the singleton instance (primarily for testing)\n */\n public static resetInstance(): void {\n PluginManager.instance = null;\n }\n\n /**\n * Create a fresh instance without affecting the singleton\n */\n public static createFresh(\n logger: Logger,\n daemonRegistry: IDaemonRegistry,\n ): PluginManager {\n return new PluginManager(logger, daemonRegistry);\n }\n\n /**\n * Set the shell instance after it's created\n */\n public setShell(shell: IShell): void {\n this.shell = shell;\n }\n\n /**\n * Private constructor to enforce singleton pattern\n */\n private constructor(logger: Logger, daemonRegistry: IDaemonRegistry) {\n this.logger = logger.child(\"PluginManager\");\n this.events = new EventEmitter();\n this.daemonRegistry = daemonRegistry;\n\n // Initialize helper classes\n this.pluginLifecycle = new PluginLifecycle(\n this.plugins,\n this.events,\n this.daemonRegistry,\n logger,\n );\n this.dependencyResolver = new DependencyResolver(\n this.plugins,\n this.events,\n logger,\n );\n this.capabilityRegistrar = new CapabilityRegistrar(logger);\n }\n\n /**\n * Register a plugin with the system\n * This only registers the plugin but doesn't initialize it\n */\n public registerPlugin(plugin: Plugin): void {\n if (!plugin.id) {\n throw new PluginError(\n \"unknown\",\n \"Registration failed: Plugin must have an id\",\n );\n }\n\n this.logger.debug(`Registering plugin: ${plugin.id} (${plugin.version})`);\n\n // Check if plugin is already registered\n if (this.plugins.has(plugin.id)) {\n const existingInfo = this.plugins.get(plugin.id);\n const existingVersion = existingInfo?.plugin.version;\n\n throw new PluginError(\n plugin.id,\n `Registration failed: Plugin is already registered with version ${existingVersion}`,\n );\n }\n\n // Get dependencies or use empty array\n const dependencies = plugin.dependencies ?? [];\n\n // Store plugin info\n const pluginInfo: PluginInfo = {\n plugin,\n status: PluginStatus.REGISTERED,\n dependencies,\n };\n\n this.plugins.set(plugin.id, pluginInfo);\n this.logger.debug(`Registered plugin: ${plugin.id} (${plugin.version})`);\n\n // Emit registered event\n this.events.emit(PluginEvent.REGISTERED, plugin.id, plugin);\n }\n\n /**\n * Initialize all registered plugins in dependency order\n * Plugins with no dependencies are initialized first\n */\n public async initializePlugins(\n registrationContext?: PluginRegistrationContext,\n ): Promise<void> {\n this.logger.debug(\"Initializing plugins...\");\n\n this.initializedPluginIds = [];\n\n // Use dependency resolver to handle initialization order\n const result = await this.dependencyResolver.resolveInitializationOrder(\n async (pluginId) => {\n await this.initializePlugin(pluginId, registrationContext);\n },\n );\n\n this.logger.debug(\n `Initialized ${result.initialized.size} of ${this.plugins.size} plugins`,\n );\n }\n\n /**\n * Initialize a specific plugin\n */\n private async initializePlugin(\n pluginId: string,\n registrationContext?: PluginRegistrationContext,\n ): Promise<void> {\n if (!this.shell) {\n throw new PluginError(\n pluginId,\n \"Cannot initialize plugin: Shell not set. Call setShell() first.\",\n );\n }\n const shell = this.shell;\n\n try {\n const capabilities = await this.pluginLifecycle.initializePlugin(\n pluginId,\n shell,\n registrationContext,\n );\n\n await this.capabilityRegistrar.registerCapabilities(\n shell,\n pluginId,\n capabilities,\n );\n\n this.initializedPluginIds.push(pluginId);\n } catch (error) {\n await this.pluginLifecycle.failPluginInitialization(pluginId, error);\n throw error;\n }\n }\n\n /**\n * Finalize composition after all registrations and before content discovery.\n * Run in dependency order so dependent plugins observe finalized providers.\n */\n public async finalizePluginRegistrations(): Promise<void> {\n this.logger.debug(\"Finalizing plugin registrations...\");\n for (const id of this.initializedPluginIds) {\n await this.pluginLifecycle.finalizePluginRegistration(id);\n }\n }\n\n /**\n * Dispatch ready hooks for all initialized plugins.\n *\n * Hooks run concurrently — no ordering guarantees between plugins in this\n * phase. Plugins that need cross-plugin coordination must use the message\n * bus.\n */\n public async readyPlugins(): Promise<void> {\n this.logger.debug(\"Dispatching plugin ready hooks...\");\n\n try {\n await runConcurrentPhase(\n this.initializedPluginIds.map(\n (id) => (): Promise<void> => this.pluginLifecycle.readyPlugin(id),\n ),\n );\n } catch (error) {\n for (const id of this.initializedPluginIds) {\n const pluginInfo = this.plugins.get(id);\n if (pluginInfo?.status === PluginStatus.ERROR) {\n await this.pluginLifecycle.failPluginInitialization(\n id,\n pluginInfo.error ?? error,\n );\n }\n }\n throw error;\n }\n }\n\n /**\n * Start daemons for all initialized plugins concurrently.\n */\n public async startPluginDaemons(): Promise<void> {\n this.logger.debug(\"Starting plugin daemons...\");\n\n await runConcurrentPhase(\n this.initializedPluginIds.map(\n (id) => (): Promise<void> =>\n this.pluginLifecycle.startPluginDaemons(id),\n ),\n );\n }\n\n /**\n * Get a registered plugin by ID\n */\n public getPlugin(id: string): Plugin | undefined {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.plugin;\n }\n\n /**\n * Get plugin status by ID\n */\n public getPluginStatus(id: string): PluginStatus | undefined {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.status;\n }\n\n /**\n * Check if a plugin is registered\n */\n public hasPlugin(id: string): boolean {\n return this.plugins.has(id);\n }\n\n /**\n * Check if a plugin is initialized\n */\n public isPluginInitialized(id: string): boolean {\n const pluginInfo = this.plugins.get(id);\n return pluginInfo?.status === PluginStatus.INITIALIZED;\n }\n\n /**\n * Get all registered plugin IDs\n */\n public getAllPluginIds(): string[] {\n return Array.from(this.plugins.keys());\n }\n\n /**\n * Get all plugins with their status\n */\n public getAllPlugins(): Map<string, PluginInfo> {\n return new Map(this.plugins);\n }\n\n /**\n * Get plugins that failed to initialize\n */\n public getFailedPlugins(): Array<{ id: string; error: Error }> {\n return Array.from(this.plugins.entries())\n .filter(\n (entry): entry is [string, PluginInfo & { error: Error }] =>\n entry[1].status === PluginStatus.ERROR &&\n entry[1].error !== undefined,\n )\n .map(([id, info]) => ({ id, error: info.error }));\n }\n\n /**\n * Get plugin package name by ID\n */\n public getPluginPackageName(pluginId: string): string | undefined {\n const pluginInfo = this.plugins.get(pluginId);\n return pluginInfo?.plugin.packageName;\n }\n\n /** Terminally release a plugin and its runtime resources. */\n public async disablePlugin(id: string): Promise<void> {\n await this.pluginLifecycle.disablePlugin(id);\n }\n\n /** Release plugins in reverse initialization order. */\n public async shutdownPlugins(): Promise<void> {\n const released = new Set<string>();\n for (const id of [...this.initializedPluginIds].reverse()) {\n await this.disablePlugin(id);\n released.add(id);\n }\n for (const id of [...this.plugins.keys()].reverse()) {\n if (!released.has(id)) await this.disablePlugin(id);\n }\n }\n\n /**\n * Subscribe to plugin events\n */\n public on<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.on(event, listener);\n }\n\n /**\n * Subscribe to plugin events once\n */\n public once<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.once(event, listener);\n }\n\n /**\n * Unsubscribe from plugin events\n */\n public off<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void {\n this.events.off(event, listener);\n }\n\n /**\n * Get the event emitter for external subscribers\n */\n public getEventEmitter(): EventEmitter {\n return this.events;\n }\n}\n",
23
+ "import type { Plugin, PluginRegistrationContext } from \"../interfaces\";\n\n/**\n * Plugin Manager interface for managing plugin lifecycle\n */\nexport interface PluginManager {\n registerPlugin(plugin: Plugin): void;\n\n initializePlugins(context?: PluginRegistrationContext): Promise<void>;\n\n finalizePluginRegistrations(): Promise<void>;\n\n readyPlugins(): Promise<void>;\n\n startPluginDaemons(): Promise<void>;\n\n getPlugin(id: string): Plugin | undefined;\n\n getPluginStatus(id: string): PluginStatus | undefined;\n\n hasPlugin(id: string): boolean;\n\n isPluginInitialized(id: string): boolean;\n\n getAllPluginIds(): string[];\n\n getAllPlugins(): Map<string, PluginInfo>;\n\n getFailedPlugins(): Array<{ id: string; error: Error }>;\n\n disablePlugin(id: string): Promise<void>;\n\n shutdownPlugins(): Promise<void>;\n\n on<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n\n once<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n\n off<E extends PluginEvent>(\n event: E,\n listener: (...args: PluginManagerEventMap[E]) => void,\n ): void;\n}\n\n/**\n * Plugin status types\n */\nexport const PluginStatus = {\n REGISTERED: \"registered\",\n INITIALIZED: \"initialized\",\n ERROR: \"error\",\n DISABLED: \"disabled\",\n} as const;\nexport type PluginStatus = (typeof PluginStatus)[keyof typeof PluginStatus];\n\n/**\n * Plugin metadata with status\n */\nexport interface PluginInfo {\n plugin: Plugin;\n status: PluginStatus;\n error?: Error;\n dependencies: string[];\n}\n\n/**\n * Plugin lifecycle event types\n */\nexport const PluginEvent = {\n REGISTERED: \"plugin:registered\",\n BEFORE_INITIALIZE: \"plugin:before_initialize\",\n INITIALIZED: \"plugin:initialized\",\n ERROR: \"plugin:error\",\n DISABLED: \"plugin:disabled\",\n} as const;\nexport type PluginEvent = (typeof PluginEvent)[keyof typeof PluginEvent];\n\n/**\n * Typed event map for PluginManager events\n */\nexport interface PluginManagerEventMap {\n [PluginEvent.REGISTERED]: [pluginId: string, plugin: Plugin];\n [PluginEvent.BEFORE_INITIALIZE]: [pluginId: string, plugin: Plugin];\n [PluginEvent.INITIALIZED]: [pluginId: string, plugin: Plugin];\n [PluginEvent.ERROR]: [pluginId: string, error: Error];\n [PluginEvent.DISABLED]: [pluginId: string];\n}\n",
24
24
  "/**\n * Plugin error class with plugin ID tracking\n */\nexport class PluginError extends Error {\n public readonly pluginId: string;\n\n constructor(pluginId: string, message: string) {\n super(`Plugin ${pluginId}: ${message}`);\n this.name = \"PluginError\";\n this.pluginId = pluginId;\n }\n}\n",
25
- "import type { IMessageBus, MessageHandler } from \"@brains/messaging-service\";\nimport type { IAttachmentsNamespace } from \"../service/attachment-registry\";\nimport { Cause, Effect, Exit, Scope } from \"@brains/utils/effect\";\nimport type { IShell } from \"../interfaces\";\n\ninterface PluginIngress {\n stopAdmission(): void;\n drain(): Promise<void>;\n}\n\n/** Internal resource scope for one plugin registration. */\nexport class PluginResourceScope {\n private readonly scope: Scope.CloseableScope;\n private readonly ingress = new Set<PluginIngress>();\n private closePromise: Promise<void> | null = null;\n private closed = false;\n\n public constructor() {\n this.scope = Effect.runSync(Scope.make());\n }\n\n public addFinalizer(finalizer: () => void | Promise<void>): void {\n if (this.closed) {\n throw new Error(\"Cannot register a resource after plugin teardown\");\n }\n Effect.runSync(\n Scope.addFinalizer(\n this.scope,\n Effect.promise(async () => {\n await finalizer();\n }),\n ),\n );\n }\n\n /** Register Promise-based ingress that must stop admission and drain on close. */\n public addIngress(ingress: PluginIngress): void {\n if (this.closed) {\n throw new Error(\"Cannot register ingress after plugin teardown\");\n }\n this.ingress.add(ingress);\n }\n\n public close(exit: Exit.Exit<unknown, unknown> = Exit.void): Promise<void> {\n this.closed = true;\n this.closePromise ??= this.closeScope(exit);\n return this.closePromise;\n }\n\n private async closeScope(exit: Exit.Exit<unknown, unknown>): Promise<void> {\n let firstFailure: unknown;\n let failed = false;\n const ingress = [...this.ingress].reverse();\n for (const entry of ingress) {\n try {\n entry.stopAdmission();\n } catch (error) {\n if (!failed) firstFailure = error;\n failed = true;\n }\n }\n\n const drainResults = await Promise.allSettled(\n ingress.map((entry) => Promise.resolve().then(() => entry.drain())),\n );\n this.ingress.clear();\n const drainFailure = drainResults.find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (!failed && drainFailure) {\n firstFailure = drainFailure.reason;\n failed = true;\n }\n\n const scopeResult = await Effect.runPromiseExit(\n Scope.close(this.scope, exit),\n );\n if (!failed && Exit.isFailure(scopeResult)) {\n firstFailure = Cause.squash(scopeResult.cause);\n failed = true;\n }\n if (failed) throw firstFailure;\n }\n}\n\n/**\n * Restrict plugin-visible resource acquisition to the plugin scope. The proxy\n * preserves the existing IShell API while owning every message subscription.\n */\nexport function createPluginScopedShell(\n shell: IShell,\n resources: PluginResourceScope,\n): IShell {\n const messageBus = shell.getMessageBus();\n const messageSubscriptions = new Set<{\n type: string;\n originalHandler: unknown;\n stopAdmission(): void;\n }>();\n const scopedMessageBus: IMessageBus = {\n send: (request) => messageBus.send(request),\n subscribe: <T = unknown, R = unknown>(\n type: string,\n handler: MessageHandler<T, R>,\n filter?: Parameters<IMessageBus[\"subscribe\"]>[2],\n ): (() => void) => {\n let accepting = true;\n const inFlight = new Set<Promise<void>>();\n const scopedHandler: MessageHandler<T, R> = (message) => {\n if (!accepting) return { noop: true };\n\n // Message handlers have no cancellation contract. Track the admitted\n // Promise so plugin teardown drains it instead of interrupting work\n // that may already be mutating plugin-owned state.\n let settleAdmitted!: () => void;\n const admitted = new Promise<void>((resolve) => {\n settleAdmitted = resolve;\n });\n inFlight.add(admitted);\n const settle = (): void => {\n inFlight.delete(admitted);\n settleAdmitted();\n };\n\n let operation: Promise<Awaited<ReturnType<typeof handler>>>;\n try {\n operation = Promise.resolve(handler(message));\n } catch (error) {\n settle();\n throw error;\n }\n return operation.then(\n (result) => {\n settle();\n return result;\n },\n (error: unknown) => {\n settle();\n throw error;\n },\n );\n };\n const unsubscribe = messageBus.subscribe(type, scopedHandler, filter);\n const subscription = {\n type,\n originalHandler: handler,\n stopAdmission: (): void => {\n if (!accepting) return;\n accepting = false;\n unsubscribe();\n messageSubscriptions.delete(subscription);\n },\n };\n messageSubscriptions.add(subscription);\n try {\n resources.addIngress({\n stopAdmission: subscription.stopAdmission,\n drain: async (): Promise<void> => {\n await Promise.all(inFlight);\n },\n });\n } catch (error) {\n subscription.stopAdmission();\n throw error;\n }\n return subscription.stopAdmission;\n },\n unsubscribe: (type, handler): void => {\n const subscriptions = [...messageSubscriptions].filter(\n (subscription) =>\n subscription.type === type &&\n subscription.originalHandler === handler,\n );\n if (subscriptions.length === 0) {\n messageBus.unsubscribe(type, handler);\n return;\n }\n for (const subscription of subscriptions) {\n subscription.stopAdmission();\n }\n },\n };\n\n const attachments = shell.getAttachmentRegistry();\n const scopedAttachments: IAttachmentsNamespace = {\n ...attachments,\n register: (sourceEntityType, attachmentType, provider): (() => void) => {\n let active = true;\n const unregister = attachments.register(\n sourceEntityType,\n attachmentType,\n provider,\n );\n const release = (): void => {\n if (!active) return;\n active = false;\n unregister();\n };\n resources.addFinalizer(release);\n return release;\n },\n };\n\n const entityRegistry = shell.getEntityRegistry();\n const scopedEntityRegistry = new Proxy(entityRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"registerEntityType\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const entityType = args[0];\n if (typeof entityType === \"string\") {\n resources.addFinalizer(() =>\n target.unregisterEntityType(entityType),\n );\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n const dataSourceRegistry = shell.getDataSourceRegistry();\n const scopedDataSourceRegistry = new Proxy(dataSourceRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"register\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const dataSource = args[0];\n if (\n typeof dataSource === \"object\" &&\n dataSource !== null &&\n \"id\" in dataSource &&\n typeof dataSource.id === \"string\"\n ) {\n const id = dataSource.id.includes(\":\")\n ? dataSource.id\n : `shell:${dataSource.id}`;\n resources.addFinalizer(() => target.unregister(id));\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n const insightsRegistry = shell.getInsightsRegistry();\n const scopedInsightsRegistry = new Proxy(insightsRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"register\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const insightType = args[0];\n if (typeof insightType === \"string\") {\n resources.addFinalizer(() => target.unregister(insightType));\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n return new Proxy(shell, {\n get(target, property): unknown {\n if (property === \"getMessageBus\") {\n return (): IMessageBus => scopedMessageBus;\n }\n if (property === \"getAttachmentRegistry\") {\n return (): IAttachmentsNamespace => scopedAttachments;\n }\n if (property === \"getEntityRegistry\") {\n return () => scopedEntityRegistry;\n }\n if (property === \"getDataSourceRegistry\") {\n return () => scopedDataSourceRegistry;\n }\n if (property === \"getInsightsRegistry\") {\n return () => scopedInsightsRegistry;\n }\n const value = Reflect.get(target, property, target) as unknown;\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n}\n",
26
- "import { getErrorMessage, toError } from \"@brains/utils/error\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { IShell, PluginRegistrationContext } from \"../interfaces\";\nimport type { EventEmitter } from \"events\";\nimport type { PluginCapabilities } from \"../interfaces\";\nimport type { IDaemonRegistry } from \"./daemon-types\";\nimport type { PluginInfo } from \"./types\";\nimport { PluginStatus, PluginEvent } from \"./types\";\nimport { PluginError } from \"../errors\";\nimport { Exit } from \"@brains/utils/effect\";\nimport {\n createPluginScopedShell,\n PluginResourceScope,\n} from \"./plugin-resource-scope\";\n\n/**\n * Handles plugin initialization and terminal resource teardown.\n * Extracted from PluginManager for single responsibility.\n */\nexport class PluginLifecycle {\n private plugins: Map<string, PluginInfo>;\n private events: EventEmitter;\n private daemonRegistry: IDaemonRegistry;\n private logger: Logger;\n private readonly resourceScopes = new Map<string, PluginResourceScope>();\n private readonly releasePromises = new Map<string, Promise<void>>();\n\n constructor(\n plugins: Map<string, PluginInfo>,\n events: EventEmitter,\n daemonRegistry: IDaemonRegistry,\n logger: Logger,\n ) {\n this.plugins = plugins;\n this.events = events;\n this.daemonRegistry = daemonRegistry;\n this.logger = logger.child(\"PluginLifecycle\");\n }\n\n /**\n * Initialize a specific plugin\n */\n public async initializePlugin(\n pluginId: string,\n shell: IShell,\n registrationContext?: PluginRegistrationContext,\n ): Promise<PluginCapabilities> {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n throw new PluginError(\n pluginId,\n \"Registration failed: Plugin is not registered\",\n );\n }\n\n const plugin = pluginInfo.plugin;\n const resources = new PluginResourceScope();\n resources.addFinalizer(() =>\n shell.unregisterPluginCapabilities?.(pluginId),\n );\n resources.addFinalizer(() =>\n shell.getJobQueueService().unregisterPluginHandlers(pluginId),\n );\n this.resourceScopes.set(pluginId, resources);\n this.releasePromises.delete(pluginId);\n\n this.logger.debug(`Initializing plugin: ${pluginId}`);\n\n try {\n this.events.emit(PluginEvent.BEFORE_INITIALIZE, pluginId, plugin);\n const capabilities = await plugin.register(\n createPluginScopedShell(shell, resources),\n registrationContext,\n );\n\n pluginInfo.status = PluginStatus.INITIALIZED;\n this.logger.debug(`Initialized plugin: ${pluginId}`);\n\n // Daemons start in a later shell phase after all plugins have registered\n // and ready hooks have run.\n this.events.emit(PluginEvent.INITIALIZED, pluginId, plugin);\n\n return capabilities;\n } catch (error) {\n this.logger.error(\n `Error initializing plugin ${pluginId}: ${getErrorMessage(error)}`,\n );\n await this.failPluginInitialization(pluginId, error);\n throw error;\n }\n }\n\n /**\n * Dispatch ready hook for a plugin.\n */\n public async readyPlugin(pluginId: string): Promise<void> {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n throw new PluginError(pluginId, \"Ready failed: Plugin is not registered\");\n }\n\n if (pluginInfo.status !== PluginStatus.INITIALIZED) {\n this.logger.debug(\n `Skipping ready hook for non-initialized plugin: ${pluginId}`,\n );\n return;\n }\n\n try {\n await pluginInfo.plugin.ready?.();\n this.logger.debug(`Ready hook completed for plugin: ${pluginId}`);\n } catch (error) {\n const readyError = toError(error);\n pluginInfo.status = PluginStatus.ERROR;\n pluginInfo.error = readyError;\n try {\n this.events.emit(PluginEvent.ERROR, pluginId, readyError);\n } catch (eventError) {\n this.logger.error(\n `Plugin error listener failed for ${pluginId}`,\n eventError,\n );\n }\n throw readyError;\n }\n }\n\n /**\n * Start any daemons registered by a plugin.\n */\n public async startPluginDaemons(pluginId: string): Promise<void> {\n const pluginInfo = this.plugins.get(pluginId);\n if (pluginInfo?.status !== PluginStatus.INITIALIZED) {\n return;\n }\n\n try {\n await this.daemonRegistry.startPlugin(pluginId);\n this.logger.debug(`Started daemons for plugin: ${pluginId}`);\n } catch (error) {\n if (pluginInfo.plugin.requiresDaemonStartup?.()) {\n throw error;\n }\n this.logger.warn(\n `Daemon ${pluginId} failed to start: ${getErrorMessage(error)}`,\n );\n }\n }\n\n /** Mark a failed registration phase and release everything acquired so far. */\n public async failPluginInitialization(\n id: string,\n error: unknown,\n ): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) return;\n\n const shouldEmit = pluginInfo.status !== PluginStatus.ERROR;\n const failure = toError(error);\n pluginInfo.status = PluginStatus.ERROR;\n pluginInfo.error = failure;\n await this.releasePluginResources(id, Exit.fail(error));\n\n if (shouldEmit) {\n try {\n this.events.emit(PluginEvent.ERROR, id, failure);\n } catch (eventError) {\n this.logger.error(`Plugin error listener failed for ${id}`, eventError);\n }\n }\n }\n\n /** Terminally release one plugin. Plugin instances are not re-enabled. */\n public async disablePlugin(id: string): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) {\n this.logger.warn(`Cannot disable plugin ${id}: not registered`);\n return;\n }\n if (pluginInfo.status === PluginStatus.DISABLED) return;\n\n this.logger.debug(`Disabling plugin: ${id}`);\n const failed = pluginInfo.status === PluginStatus.ERROR;\n await this.releasePluginResources(id, Exit.void);\n\n const releasedPluginInfo = this.plugins.get(id);\n if (\n !failed &&\n releasedPluginInfo &&\n releasedPluginInfo.status !== PluginStatus.DISABLED\n ) {\n releasedPluginInfo.status = PluginStatus.DISABLED;\n this.events.emit(PluginEvent.DISABLED, id, releasedPluginInfo.plugin);\n }\n this.logger.debug(`Disabled plugin: ${id}`);\n }\n\n private releasePluginResources(\n id: string,\n exit: Exit.Exit<unknown, unknown>,\n ): Promise<void> {\n const existing = this.releasePromises.get(id);\n if (existing) return existing;\n\n const release = this.releasePluginResourcesOnce(id, exit);\n this.releasePromises.set(id, release);\n return release;\n }\n\n private async releasePluginResourcesOnce(\n id: string,\n exit: Exit.Exit<unknown, unknown>,\n ): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) return;\n\n try {\n await this.daemonRegistry.stopPlugin(id);\n this.logger.debug(`Stopped daemons for plugin: ${id}`);\n } catch (error) {\n this.logger.error(`Failed to stop daemons for plugin: ${id}`, error);\n }\n\n // Remove shell-owned ingress and drain scoped resources before invoking\n // plugin shutdown, so no admitted callback can enter torn-down plugin code.\n const resources = this.resourceScopes.get(id);\n this.resourceScopes.delete(id);\n if (resources) {\n try {\n await resources.close(exit);\n } catch (error) {\n this.logger.error(`Failed to close resources for plugin ${id}`, error);\n }\n }\n\n if (pluginInfo.plugin.shutdown) {\n try {\n await pluginInfo.plugin.shutdown();\n this.logger.debug(`Shutdown completed for plugin: ${id}`);\n } catch (error) {\n this.logger.error(`Plugin shutdown failed for ${id}:`, error);\n }\n }\n\n for (const daemon of this.daemonRegistry.getByPlugin(id)) {\n try {\n await this.daemonRegistry.unregister(daemon.name);\n } catch (error) {\n this.logger.error(\n `Failed to unregister daemon ${daemon.name} for plugin ${id}`,\n error,\n );\n }\n }\n }\n}\n",
25
+ "import type { IMessageBus, MessageHandler } from \"@brains/messaging-service\";\nimport type { IAttachmentsNamespace } from \"../service/attachment-registry\";\nimport { Cause, Effect, Exit, Scope } from \"@brains/utils/effect\";\nimport type { IShell } from \"../interfaces\";\n\ninterface PluginIngress {\n stopAdmission(): void;\n drain(): Promise<void>;\n}\n\n/** Internal resource scope for one plugin registration. */\nexport class PluginResourceScope {\n private readonly scope: Scope.CloseableScope;\n private readonly ingress = new Set<PluginIngress>();\n private closePromise: Promise<void> | null = null;\n private closed = false;\n\n public constructor() {\n this.scope = Effect.runSync(Scope.make());\n }\n\n public addFinalizer(finalizer: () => void | Promise<void>): void {\n if (this.closed) {\n throw new Error(\"Cannot register a resource after plugin teardown\");\n }\n Effect.runSync(\n Scope.addFinalizer(\n this.scope,\n Effect.promise(async () => {\n await finalizer();\n }),\n ),\n );\n }\n\n /** Register Promise-based ingress that must stop admission and drain on close. */\n public addIngress(ingress: PluginIngress): void {\n if (this.closed) {\n throw new Error(\"Cannot register ingress after plugin teardown\");\n }\n this.ingress.add(ingress);\n }\n\n public close(exit: Exit.Exit<unknown, unknown> = Exit.void): Promise<void> {\n this.closed = true;\n this.closePromise ??= this.closeScope(exit);\n return this.closePromise;\n }\n\n private async closeScope(exit: Exit.Exit<unknown, unknown>): Promise<void> {\n let firstFailure: unknown;\n let failed = false;\n const ingress = [...this.ingress].reverse();\n for (const entry of ingress) {\n try {\n entry.stopAdmission();\n } catch (error) {\n if (!failed) firstFailure = error;\n failed = true;\n }\n }\n\n const drainResults = await Promise.allSettled(\n ingress.map((entry) => Promise.resolve().then(() => entry.drain())),\n );\n this.ingress.clear();\n const drainFailure = drainResults.find(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (!failed && drainFailure) {\n firstFailure = drainFailure.reason;\n failed = true;\n }\n\n const scopeResult = await Effect.runPromiseExit(\n Scope.close(this.scope, exit),\n );\n if (!failed && Exit.isFailure(scopeResult)) {\n firstFailure = Cause.squash(scopeResult.cause);\n failed = true;\n }\n if (failed) throw firstFailure;\n }\n}\n\n/**\n * Restrict plugin-visible resource acquisition to the plugin scope. The proxy\n * preserves the existing IShell API while owning every message subscription.\n */\nexport function createPluginScopedShell(\n shell: IShell,\n resources: PluginResourceScope,\n): IShell {\n const messageBus = shell.getMessageBus();\n const messageSubscriptions = new Set<{\n type: string;\n originalHandler: unknown;\n stopAdmission(): void;\n }>();\n const scopedMessageBus: IMessageBus = {\n send: (request) => messageBus.send(request),\n subscribe: <T = unknown, R = unknown>(\n type: string,\n handler: MessageHandler<T, R>,\n filter?: Parameters<IMessageBus[\"subscribe\"]>[2],\n ): (() => void) => {\n let accepting = true;\n const inFlight = new Set<Promise<void>>();\n const scopedHandler: MessageHandler<T, R> = (message) => {\n if (!accepting) return { noop: true };\n\n // Message handlers have no cancellation contract. Track the admitted\n // Promise so plugin teardown drains it instead of interrupting work\n // that may already be mutating plugin-owned state.\n let settleAdmitted!: () => void;\n const admitted = new Promise<void>((resolve) => {\n settleAdmitted = resolve;\n });\n inFlight.add(admitted);\n const settle = (): void => {\n inFlight.delete(admitted);\n settleAdmitted();\n };\n\n let operation: Promise<Awaited<ReturnType<typeof handler>>>;\n try {\n operation = Promise.resolve(handler(message));\n } catch (error) {\n settle();\n throw error;\n }\n return operation.then(\n (result) => {\n settle();\n return result;\n },\n (error: unknown) => {\n settle();\n throw error;\n },\n );\n };\n const unsubscribe = messageBus.subscribe(type, scopedHandler, filter);\n const subscription = {\n type,\n originalHandler: handler,\n stopAdmission: (): void => {\n if (!accepting) return;\n accepting = false;\n unsubscribe();\n messageSubscriptions.delete(subscription);\n },\n };\n messageSubscriptions.add(subscription);\n try {\n resources.addIngress({\n stopAdmission: subscription.stopAdmission,\n drain: async (): Promise<void> => {\n await Promise.all(inFlight);\n },\n });\n } catch (error) {\n subscription.stopAdmission();\n throw error;\n }\n return subscription.stopAdmission;\n },\n unsubscribe: (type, handler): void => {\n const subscriptions = [...messageSubscriptions].filter(\n (subscription) =>\n subscription.type === type &&\n subscription.originalHandler === handler,\n );\n if (subscriptions.length === 0) {\n messageBus.unsubscribe(type, handler);\n return;\n }\n for (const subscription of subscriptions) {\n subscription.stopAdmission();\n }\n },\n };\n\n const attachments = shell.getAttachmentRegistry();\n const scopedAttachments: IAttachmentsNamespace = {\n ...attachments,\n register: (sourceEntityType, attachmentType, provider): (() => void) => {\n let active = true;\n const unregister = attachments.register(\n sourceEntityType,\n attachmentType,\n provider,\n );\n const release = (): void => {\n if (!active) return;\n active = false;\n unregister();\n };\n resources.addFinalizer(release);\n return release;\n },\n };\n\n const entityRegistry = shell.getEntityRegistry();\n const scopedEntityRegistry = new Proxy(entityRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"registerEntityType\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const entityType = args[0];\n if (typeof entityType === \"string\") {\n resources.addFinalizer(() =>\n target.unregisterEntityType(entityType),\n );\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n const profileKindRegistry = shell.getProfileKindRegistry();\n const scopedProfileKindRegistry = new Proxy(profileKindRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"register\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const pluginId = args[0];\n if (typeof pluginId === \"string\") {\n resources.addFinalizer(() => target.unregisterPlugin(pluginId));\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n const dataSourceRegistry = shell.getDataSourceRegistry();\n const scopedDataSourceRegistry = new Proxy(dataSourceRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"register\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const dataSource = args[0];\n if (\n typeof dataSource === \"object\" &&\n dataSource !== null &&\n \"id\" in dataSource &&\n typeof dataSource.id === \"string\"\n ) {\n const id = dataSource.id.includes(\":\")\n ? dataSource.id\n : `shell:${dataSource.id}`;\n resources.addFinalizer(() => target.unregister(id));\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n const insightsRegistry = shell.getInsightsRegistry();\n const scopedInsightsRegistry = new Proxy(insightsRegistry, {\n get(target, property): unknown {\n const value = Reflect.get(target, property, target) as unknown;\n if (property === \"register\" && typeof value === \"function\") {\n return (...args: unknown[]): unknown => {\n const result = Reflect.apply(value, target, args);\n const insightType = args[0];\n if (typeof insightType === \"string\") {\n resources.addFinalizer(() => target.unregister(insightType));\n }\n return result;\n };\n }\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n\n return new Proxy(shell, {\n get(target, property): unknown {\n if (property === \"getMessageBus\") {\n return (): IMessageBus => scopedMessageBus;\n }\n if (property === \"getAttachmentRegistry\") {\n return (): IAttachmentsNamespace => scopedAttachments;\n }\n if (property === \"getEntityRegistry\") {\n return () => scopedEntityRegistry;\n }\n if (property === \"getDataSourceRegistry\") {\n return () => scopedDataSourceRegistry;\n }\n if (property === \"getProfileKindRegistry\") {\n return () => scopedProfileKindRegistry;\n }\n if (property === \"getInsightsRegistry\") {\n return () => scopedInsightsRegistry;\n }\n const value = Reflect.get(target, property, target) as unknown;\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n}\n",
26
+ "import { getErrorMessage, toError } from \"@brains/utils/error\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { IShell, PluginRegistrationContext } from \"../interfaces\";\nimport type { EventEmitter } from \"events\";\nimport type { PluginCapabilities } from \"../interfaces\";\nimport type { IDaemonRegistry } from \"./daemon-types\";\nimport type { PluginInfo } from \"./types\";\nimport { PluginStatus, PluginEvent } from \"./types\";\nimport { PluginError } from \"../errors\";\nimport { Exit } from \"@brains/utils/effect\";\nimport {\n createPluginScopedShell,\n PluginResourceScope,\n} from \"./plugin-resource-scope\";\n\n/**\n * Handles plugin initialization and terminal resource teardown.\n * Extracted from PluginManager for single responsibility.\n */\nexport class PluginLifecycle {\n private plugins: Map<string, PluginInfo>;\n private events: EventEmitter;\n private daemonRegistry: IDaemonRegistry;\n private logger: Logger;\n private readonly resourceScopes = new Map<string, PluginResourceScope>();\n private readonly releasePromises = new Map<string, Promise<void>>();\n\n constructor(\n plugins: Map<string, PluginInfo>,\n events: EventEmitter,\n daemonRegistry: IDaemonRegistry,\n logger: Logger,\n ) {\n this.plugins = plugins;\n this.events = events;\n this.daemonRegistry = daemonRegistry;\n this.logger = logger.child(\"PluginLifecycle\");\n }\n\n /**\n * Initialize a specific plugin\n */\n public async initializePlugin(\n pluginId: string,\n shell: IShell,\n registrationContext?: PluginRegistrationContext,\n ): Promise<PluginCapabilities> {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n throw new PluginError(\n pluginId,\n \"Registration failed: Plugin is not registered\",\n );\n }\n\n const plugin = pluginInfo.plugin;\n const resources = new PluginResourceScope();\n resources.addFinalizer(() =>\n shell.unregisterPluginCapabilities?.(pluginId),\n );\n resources.addFinalizer(() =>\n shell.getJobQueueService().unregisterPluginHandlers(pluginId),\n );\n this.resourceScopes.set(pluginId, resources);\n this.releasePromises.delete(pluginId);\n\n this.logger.debug(`Initializing plugin: ${pluginId}`);\n\n try {\n this.events.emit(PluginEvent.BEFORE_INITIALIZE, pluginId, plugin);\n const capabilities = await plugin.register(\n createPluginScopedShell(shell, resources),\n registrationContext,\n );\n\n pluginInfo.status = PluginStatus.INITIALIZED;\n this.logger.debug(`Initialized plugin: ${pluginId}`);\n\n // Daemons start in a later shell phase after all plugins have registered\n // and ready hooks have run.\n this.events.emit(PluginEvent.INITIALIZED, pluginId, plugin);\n\n return capabilities;\n } catch (error) {\n this.logger.error(\n `Error initializing plugin ${pluginId}: ${getErrorMessage(error)}`,\n );\n await this.failPluginInitialization(pluginId, error);\n throw error;\n }\n }\n\n /** Dispatch post-registration finalization for one initialized plugin. */\n public async finalizePluginRegistration(pluginId: string): Promise<void> {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n throw new PluginError(\n pluginId,\n \"Registration finalization failed: Plugin is not registered\",\n );\n }\n if (pluginInfo.status !== PluginStatus.INITIALIZED) return;\n\n try {\n await pluginInfo.plugin.finalizeRegistration?.();\n this.logger.debug(`Registration finalized for plugin: ${pluginId}`);\n } catch (error) {\n await this.failPluginInitialization(pluginId, error);\n throw error;\n }\n }\n\n /**\n * Dispatch ready hook for a plugin.\n */\n public async readyPlugin(pluginId: string): Promise<void> {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n throw new PluginError(pluginId, \"Ready failed: Plugin is not registered\");\n }\n\n if (pluginInfo.status !== PluginStatus.INITIALIZED) {\n this.logger.debug(\n `Skipping ready hook for non-initialized plugin: ${pluginId}`,\n );\n return;\n }\n\n try {\n await pluginInfo.plugin.ready?.();\n this.logger.debug(`Ready hook completed for plugin: ${pluginId}`);\n } catch (error) {\n const readyError = toError(error);\n pluginInfo.status = PluginStatus.ERROR;\n pluginInfo.error = readyError;\n try {\n this.events.emit(PluginEvent.ERROR, pluginId, readyError);\n } catch (eventError) {\n this.logger.error(\n `Plugin error listener failed for ${pluginId}`,\n eventError,\n );\n }\n throw readyError;\n }\n }\n\n /**\n * Start any daemons registered by a plugin.\n */\n public async startPluginDaemons(pluginId: string): Promise<void> {\n const pluginInfo = this.plugins.get(pluginId);\n if (pluginInfo?.status !== PluginStatus.INITIALIZED) {\n return;\n }\n\n try {\n await this.daemonRegistry.startPlugin(pluginId);\n this.logger.debug(`Started daemons for plugin: ${pluginId}`);\n } catch (error) {\n if (pluginInfo.plugin.requiresDaemonStartup?.()) {\n throw error;\n }\n this.logger.warn(\n `Daemon ${pluginId} failed to start: ${getErrorMessage(error)}`,\n );\n }\n }\n\n /** Mark a failed registration phase and release everything acquired so far. */\n public async failPluginInitialization(\n id: string,\n error: unknown,\n ): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) return;\n\n const shouldEmit = pluginInfo.status !== PluginStatus.ERROR;\n const failure = toError(error);\n pluginInfo.status = PluginStatus.ERROR;\n pluginInfo.error = failure;\n await this.releasePluginResources(id, Exit.fail(error));\n\n if (shouldEmit) {\n try {\n this.events.emit(PluginEvent.ERROR, id, failure);\n } catch (eventError) {\n this.logger.error(`Plugin error listener failed for ${id}`, eventError);\n }\n }\n }\n\n /** Terminally release one plugin. Plugin instances are not re-enabled. */\n public async disablePlugin(id: string): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) {\n this.logger.warn(`Cannot disable plugin ${id}: not registered`);\n return;\n }\n if (pluginInfo.status === PluginStatus.DISABLED) return;\n\n this.logger.debug(`Disabling plugin: ${id}`);\n const failed = pluginInfo.status === PluginStatus.ERROR;\n await this.releasePluginResources(id, Exit.void);\n\n const releasedPluginInfo = this.plugins.get(id);\n if (\n !failed &&\n releasedPluginInfo &&\n releasedPluginInfo.status !== PluginStatus.DISABLED\n ) {\n releasedPluginInfo.status = PluginStatus.DISABLED;\n this.events.emit(PluginEvent.DISABLED, id, releasedPluginInfo.plugin);\n }\n this.logger.debug(`Disabled plugin: ${id}`);\n }\n\n private releasePluginResources(\n id: string,\n exit: Exit.Exit<unknown, unknown>,\n ): Promise<void> {\n const existing = this.releasePromises.get(id);\n if (existing) return existing;\n\n const release = this.releasePluginResourcesOnce(id, exit);\n this.releasePromises.set(id, release);\n return release;\n }\n\n private async releasePluginResourcesOnce(\n id: string,\n exit: Exit.Exit<unknown, unknown>,\n ): Promise<void> {\n const pluginInfo = this.plugins.get(id);\n if (!pluginInfo) return;\n\n try {\n await this.daemonRegistry.stopPlugin(id);\n this.logger.debug(`Stopped daemons for plugin: ${id}`);\n } catch (error) {\n this.logger.error(`Failed to stop daemons for plugin: ${id}`, error);\n }\n\n // Remove shell-owned ingress and drain scoped resources before invoking\n // plugin shutdown, so no admitted callback can enter torn-down plugin code.\n const resources = this.resourceScopes.get(id);\n this.resourceScopes.delete(id);\n if (resources) {\n try {\n await resources.close(exit);\n } catch (error) {\n this.logger.error(`Failed to close resources for plugin ${id}`, error);\n }\n }\n\n if (pluginInfo.plugin.shutdown) {\n try {\n await pluginInfo.plugin.shutdown();\n this.logger.debug(`Shutdown completed for plugin: ${id}`);\n } catch (error) {\n this.logger.error(`Plugin shutdown failed for ${id}:`, error);\n }\n }\n\n for (const daemon of this.daemonRegistry.getByPlugin(id)) {\n try {\n await this.daemonRegistry.unregister(daemon.name);\n } catch (error) {\n this.logger.error(\n `Failed to unregister daemon ${daemon.name} for plugin ${id}`,\n error,\n );\n }\n }\n }\n}\n",
27
27
  "import { getErrorMessage } from \"@brains/utils/error\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport type { EventEmitter } from \"events\";\nimport type { PluginInfo } from \"./types\";\nimport { PluginStatus, PluginEvent } from \"./types\";\nimport { PluginError } from \"../errors\";\n\n/**\n * Handles plugin dependency resolution and initialization order\n * Extracted from PluginManager for single responsibility\n */\nexport class DependencyResolver {\n private plugins: Map<string, PluginInfo>;\n private events: EventEmitter;\n private logger: Logger;\n\n constructor(\n plugins: Map<string, PluginInfo>,\n events: EventEmitter,\n logger: Logger,\n ) {\n this.plugins = plugins;\n this.events = events;\n this.logger = logger.child(\"DependencyResolver\");\n }\n\n /**\n * Get plugin IDs in dependency order for initialization\n * Returns array of plugin IDs that can be initialized, considering dependencies\n */\n public async resolveInitializationOrder(\n initializeCallback: (pluginId: string) => Promise<void>,\n ): Promise<{\n initialized: Set<string>;\n failed: string[];\n }> {\n this.logger.debug(\"Resolving plugin initialization order...\");\n\n // Get all plugin IDs\n const allPluginIds = Array.from(this.plugins.keys());\n\n // Track attempted plugins (to prevent infinite loops)\n const attempted = new Set<string>();\n\n // Try to initialize all plugins\n let progress = true;\n\n // Continue until all plugins are attempted or no progress can be made\n while (progress && attempted.size < allPluginIds.length) {\n progress = false;\n\n // Iterate through all plugins\n for (const pluginId of allPluginIds) {\n // Skip already attempted plugins\n if (attempted.has(pluginId)) {\n continue;\n }\n\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n continue;\n }\n\n // Check if all dependencies are initialized (check actual status, not attempted)\n const unmetDependencies = this.getUnmetDependencies(pluginId);\n\n if (unmetDependencies.length === 0) {\n // All dependencies are satisfied, initialize this plugin\n try {\n await initializeCallback(pluginId);\n attempted.add(pluginId);\n progress = true;\n } catch (error) {\n // Mark as error and continue with others\n const errorMessage = getErrorMessage(error);\n this.logger.error(\n `Failed to initialize plugin ${pluginId}: ${errorMessage}`,\n );\n\n // Plugin status and error event are already set in initializePlugin\n // Consider this \"handled\" for dependency resolution\n attempted.add(pluginId);\n progress = true;\n }\n }\n }\n }\n\n // Check for plugins that couldn't be initialized due to dependency issues\n const uninitializedPlugins = allPluginIds.filter(\n (id) => !attempted.has(id),\n );\n\n if (uninitializedPlugins.length > 0) {\n const pluginList = uninitializedPlugins.join(\", \");\n this.logger.error(\n `Failed to initialize plugins due to dependency issues: ${pluginList}`,\n );\n\n // Report specific issues for each plugin\n for (const pluginId of uninitializedPlugins) {\n const unmetDependencies = this.getUnmetDependencies(pluginId);\n this.logger.error(\n `Plugin ${pluginId} has unmet dependencies: ${unmetDependencies.join(\", \")}`,\n );\n\n // Update plugin status\n const pluginInfo = this.plugins.get(pluginId);\n if (pluginInfo) {\n pluginInfo.status = PluginStatus.ERROR;\n pluginInfo.error = new PluginError(\n pluginId,\n `Unmet dependencies: ${unmetDependencies.join(\", \")}`,\n );\n }\n\n // Emit error event\n this.events.emit(PluginEvent.ERROR, pluginId, pluginInfo?.error);\n }\n }\n\n // Get successfully initialized plugins (those with INITIALIZED status)\n const initialized = new Set<string>();\n for (const [pluginId, pluginInfo] of this.plugins) {\n if (pluginInfo.status === PluginStatus.INITIALIZED) {\n initialized.add(pluginId);\n }\n }\n\n this.logger.debug(\n `Resolved ${initialized.size} of ${allPluginIds.length} plugins`,\n );\n\n return {\n initialized,\n failed: uninitializedPlugins,\n };\n }\n\n /**\n * Check if all dependencies of a plugin are met\n */\n public getUnmetDependencies(pluginId: string): string[] {\n const pluginInfo = this.plugins.get(pluginId);\n if (!pluginInfo) {\n return [];\n }\n\n const { dependencies } = pluginInfo;\n const unmetDependencies: string[] = [];\n\n for (const depId of dependencies) {\n // Check if dependency exists\n const dependency = this.plugins.get(depId);\n\n if (!dependency) {\n unmetDependencies.push(depId);\n continue;\n }\n\n // Check if dependency is initialized (not just registered)\n if (dependency.status !== PluginStatus.INITIALIZED) {\n unmetDependencies.push(depId);\n }\n }\n\n return unmetDependencies;\n }\n}\n",
28
28
  "import type { Logger } from \"@brains/utils/logger\";\nimport type { IShell } from \"../interfaces\";\nimport type { PluginCapabilities } from \"../interfaces\";\n\n/**\n * Handles registration of plugin capabilities (tools, resources)\n * Extracted from PluginManager for single responsibility\n */\nexport class CapabilityRegistrar {\n private logger: Logger;\n\n constructor(logger: Logger) {\n this.logger = logger.child(\"CapabilityRegistrar\");\n }\n\n /**\n * Register plugin capabilities using Shell convenience methods\n */\n public async registerCapabilities(\n shell: IShell,\n pluginId: string,\n capabilities: PluginCapabilities,\n ): Promise<void> {\n // Register tools\n if (capabilities.tools.length > 0) {\n shell.registerTools(pluginId, capabilities.tools);\n this.logger.debug(\n `Registered ${capabilities.tools.length} tools from ${pluginId}`,\n );\n }\n\n // Register resources\n if (capabilities.resources.length > 0) {\n shell.registerResources(pluginId, capabilities.resources);\n this.logger.debug(\n `Registered ${capabilities.resources.length} resources from ${pluginId}`,\n );\n }\n\n // Register instructions\n if (capabilities.instructions) {\n shell.registerInstructions(pluginId, capabilities.instructions);\n this.logger.debug(`Registered instructions from ${pluginId}`);\n }\n }\n}\n",
29
29
  "import { z } from \"@brains/utils/zod\";\nimport { baseEntityParserSchema } from \"@brains/plugins\";\n\n/**\n * Blog post status\n */\nexport type BlogPostStatus =\n \"generating\" | \"draft\" | \"queued\" | \"published\" | \"failed\";\n\nexport const blogPostStatusSchema: z.ZodType<BlogPostStatus, BlogPostStatus> =\n z.enum([\"generating\", \"draft\", \"queued\", \"published\", \"failed\"]);\n\nconst blogPostStatusParserSchema: z.ZodType<BlogPostStatus, BlogPostStatus> =\n z.enum([\"generating\", \"draft\", \"queued\", \"published\", \"failed\"]);\n\n/**\n * Blog post frontmatter schema (stored in content as YAML frontmatter)\n * Contains all blog post data for human editing\n */\nexport interface BlogPostFrontmatter {\n [key: string]: unknown;\n title: string;\n slug?: string | undefined;\n status: BlogPostStatus;\n publishedAt?: string | undefined;\n excerpt: string;\n author: string;\n coverImageId?: string | undefined;\n ogImageId?: string | undefined;\n seriesName?: string | undefined;\n seriesIndex?: number | undefined;\n ogImage?: string | undefined;\n ogDescription?: string | undefined;\n twitterCard?: \"summary\" | \"summary_large_image\" | undefined;\n canonicalUrl?: string | undefined;\n atprotoUri?: string | undefined;\n}\n\ntype TwitterCardSchema = z.ZodOptional<\n z.ZodEnum<{ summary: \"summary\"; summary_large_image: \"summary_large_image\" }>\n>;\n\ntype BlogPostFrontmatterSchema = z.ZodObject<{\n title: z.ZodString;\n slug: z.ZodOptional<z.ZodString>;\n status: z.ZodType<BlogPostStatus, BlogPostStatus>;\n publishedAt: z.ZodOptional<z.ZodString>;\n excerpt: z.ZodString;\n author: z.ZodString;\n coverImageId: z.ZodOptional<z.ZodString>;\n ogImageId: z.ZodOptional<z.ZodString>;\n seriesName: z.ZodOptional<z.ZodString>;\n seriesIndex: z.ZodOptional<z.ZodNumber>;\n ogImage: z.ZodOptional<z.ZodString>;\n ogDescription: z.ZodOptional<z.ZodString>;\n twitterCard: TwitterCardSchema;\n canonicalUrl: z.ZodOptional<z.ZodString>;\n atprotoUri: z.ZodOptional<z.ZodString>;\n}>;\n\nexport const blogPostFrontmatterSchema: BlogPostFrontmatterSchema = z.object({\n title: z.string(),\n slug: z.string().optional(), // Auto-generated from title if not provided\n status: blogPostStatusSchema,\n publishedAt: z.string().datetime().optional(),\n excerpt: z.string(),\n author: z.string(),\n coverImageId: z.string().optional(), // References an image entity by ID\n ogImageId: z.string().optional(), // References an image entity for social/OG metadata\n seriesName: z.string().optional(),\n seriesIndex: z.number().optional(),\n // SEO metadata (optional, with smart fallbacks)\n ogImage: z.string().url().optional(),\n ogDescription: z.string().optional(),\n twitterCard: z.enum([\"summary\", \"summary_large_image\"]).optional(),\n canonicalUrl: z.string().url().optional(),\n atprotoUri: z.string().optional(),\n});\n\n/**\n * Blog post metadata schema - derived from frontmatter\n * Only includes fields needed for fast DB queries/filtering\n * Using .pick() ensures metadata stays in sync with frontmatter\n */\nexport interface BlogPostMetadata {\n [key: string]: unknown;\n title: string;\n status: BlogPostStatus;\n publishedAt?: string | undefined;\n seriesName?: string | undefined;\n seriesIndex?: number | undefined;\n slug: string;\n error?: string | undefined;\n}\n\ntype BlogPostMetadataSchema = z.ZodObject<{\n title: z.ZodString;\n status: z.ZodType<BlogPostStatus, BlogPostStatus>;\n publishedAt: z.ZodOptional<z.ZodString>;\n seriesName: z.ZodOptional<z.ZodString>;\n seriesIndex: z.ZodOptional<z.ZodNumber>;\n slug: z.ZodString;\n error: z.ZodOptional<z.ZodString>;\n}>;\n\nexport const blogPostMetadataSchema: BlogPostMetadataSchema =\n blogPostFrontmatterSchema\n .pick({\n title: true,\n status: true,\n publishedAt: true,\n seriesName: true,\n seriesIndex: true,\n })\n .extend({\n // slug is required in metadata (auto-generated from title if not in frontmatter)\n slug: z.string(),\n error: z.string().optional(),\n });\n\nconst blogPostEntityMetadataParserSchema: BlogPostMetadataSchema = z.object({\n title: z.string(),\n status: blogPostStatusParserSchema,\n publishedAt: z.string().datetime().optional(),\n seriesName: z.string().optional(),\n seriesIndex: z.number().optional(),\n slug: z.string(),\n error: z.string().optional(),\n});\n\nconst blogPostFrontmatterParserSchema: BlogPostFrontmatterSchema = z.object({\n title: z.string(),\n slug: z.string().optional(),\n status: blogPostStatusParserSchema,\n publishedAt: z.string().datetime().optional(),\n excerpt: z.string(),\n author: z.string(),\n coverImageId: z.string().optional(),\n ogImageId: z.string().optional(),\n seriesName: z.string().optional(),\n seriesIndex: z.number().optional(),\n ogImage: z.string().url().optional(),\n ogDescription: z.string().optional(),\n twitterCard: z.enum([\"summary\", \"summary_large_image\"]).optional(),\n canonicalUrl: z.string().url().optional(),\n atprotoUri: z.string().optional(),\n});\n\n/**\n * Blog post entity schema (extends BaseEntity)\n * Content field contains markdown with frontmatter + blog post body\n * Metadata field duplicates key fields from frontmatter for fast queries\n */\nexport const blogPostSchema: ReturnType<\n typeof baseEntityParserSchema.extend<{\n entityType: z.ZodLiteral<\"post\">;\n metadata: BlogPostMetadataSchema;\n }>\n> = baseEntityParserSchema.extend({\n entityType: z.literal(\"post\"),\n metadata: blogPostEntityMetadataParserSchema,\n});\n\n/**\n * Blog post entity type\n */\nexport type BlogPost = z.output<typeof blogPostSchema>;\n\n/**\n * Blog post with parsed frontmatter data (returned by datasource)\n * Extends BlogPost with parsed frontmatter and body (markdown without frontmatter)\n * coverImageUrl is resolved from coverImageId and contains the actual image data URL\n */\nexport const blogPostWithDataSchema: ReturnType<\n typeof blogPostSchema.extend<{\n frontmatter: BlogPostFrontmatterSchema;\n body: z.ZodString;\n coverImageUrl: z.ZodOptional<z.ZodString>;\n }>\n> = blogPostSchema.extend({\n frontmatter: blogPostFrontmatterParserSchema,\n body: z.string(),\n coverImageUrl: z.string().optional(), // Resolved data URL from coverImageId\n});\n\nexport type BlogPostWithData = z.output<typeof blogPostWithDataSchema>;\n\n/**\n * Enriched blog post schema (used for validation)\n * url, typeLabel, listUrl, listLabel are optional to allow validation before enrichment\n * seriesUrl is optional and only present for posts that belong to a series\n */\nexport const enrichedBlogPostSchema: ReturnType<\n typeof blogPostWithDataSchema.extend<{\n url: z.ZodOptional<z.ZodString>;\n typeLabel: z.ZodOptional<z.ZodString>;\n listUrl: z.ZodOptional<z.ZodString>;\n listLabel: z.ZodOptional<z.ZodString>;\n seriesUrl: z.ZodOptional<z.ZodString>;\n coverImageUrl: z.ZodOptional<z.ZodString>;\n ogImageUrl: z.ZodOptional<z.ZodString>;\n coverImageWidth: z.ZodOptional<z.ZodNumber>;\n coverImageHeight: z.ZodOptional<z.ZodNumber>;\n coverImageSrcset: z.ZodOptional<z.ZodString>;\n coverImageSizes: z.ZodOptional<z.ZodString>;\n }>\n> = blogPostWithDataSchema.extend({\n url: z.string().optional(),\n typeLabel: z.string().optional(),\n listUrl: z.string().optional(),\n listLabel: z.string().optional(),\n seriesUrl: z.string().optional(),\n coverImageUrl: z.string().optional(),\n ogImageUrl: z.string().optional(),\n coverImageWidth: z.number().optional(),\n coverImageHeight: z.number().optional(),\n coverImageSrcset: z.string().optional(),\n coverImageSizes: z.string().optional(),\n});\n\n/**\n * Template blog post schema (used for template validation)\n * All enrichment fields are required - always present after enrichment\n */\nexport const templateBlogPostSchema: ReturnType<\n typeof blogPostWithDataSchema.extend<{\n url: z.ZodString;\n typeLabel: z.ZodString;\n listUrl: z.ZodString;\n listLabel: z.ZodString;\n seriesUrl: z.ZodOptional<z.ZodString>;\n coverImageUrl: z.ZodOptional<z.ZodString>;\n ogImageUrl: z.ZodOptional<z.ZodString>;\n coverImageWidth: z.ZodOptional<z.ZodNumber>;\n coverImageHeight: z.ZodOptional<z.ZodNumber>;\n coverImageSrcset: z.ZodOptional<z.ZodString>;\n coverImageSizes: z.ZodOptional<z.ZodString>;\n }>\n> = blogPostWithDataSchema.extend({\n url: z.string(),\n typeLabel: z.string(),\n listUrl: z.string(),\n listLabel: z.string(),\n seriesUrl: z.string().optional(), // URL to series detail page (if post is in a series)\n coverImageUrl: z.string().optional(),\n ogImageUrl: z.string().optional(),\n coverImageWidth: z.number().optional(),\n coverImageHeight: z.number().optional(),\n coverImageSrcset: z.string().optional(),\n coverImageSizes: z.string().optional(),\n});\n\n/**\n * Enriched blog post type (used by components)\n * All enrichment fields (url, typeLabel, listUrl, listLabel) are required\n */\nexport type EnrichedBlogPost = z.output<typeof templateBlogPostSchema>;\n"
30
30
  ],
31
- "mappings": "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",
32
- "debugId": "36DB131612A5B36664756E2164756E21",
31
+ "mappings": "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",
32
+ "debugId": "5D5C2DB1F819D68664756E2164756E21",
33
33
  "names": []
34
34
  }
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{c as K}from"./index-d5r8p459.js";import{k as J}from"./index-t7hbrpyx.js";import"./index-836tm28j.js";import"./index-px8fmtx1.js";import{Z as I}from"./index-0bjkx8vb.js";import"./index-c93wmj0d.js";import"./index-ps0mn8y9.js";import"./index-gca7xnrh.js";import{Za as j}from"./index-57d1xga4.js";import"./index-vtwspye3.js";var V=j.object({siteUrl:j.url(),title:j.string(),description:j.string(),language:j.string().optional(),copyright:j.string().optional()});class Y{logger;id="blog:rss";name="Blog RSS Feed DataSource";description="Generates RSS 2.0 feed XML from published blog posts";constructor(D){this.logger=D,this.logger.debug("RSSDataSource initialized")}async fetch(D,N,O){let v=V.parse(D),E=(await O.entityService.listEntities({entityType:"post",options:{limit:1000}})).filter((A)=>A.metadata.status==="published"&&A.metadata.publishedAt).map((A)=>{let H=I(A.content,J);return{...A,frontmatter:H.metadata,body:H.content}});this.logger.debug(`Generating RSS feed with ${E.length} posts`);let T={title:v.title,description:v.description,link:v.siteUrl,language:v.language??"en-us",...v.copyright&&{copyright:v.copyright}},U={xml:K(E,T)};return N.parse(U)}}export{Y as RSSDataSource};
2
+ import{c as K}from"./index-d5r8p459.js";import{h as J}from"./index-rng6ka15.js";import"./index-jm9vaxsh.js";import"./index-1qz89akh.js";import{W as I}from"./index-4xzx30t8.js";import"./index-q53nehd5.js";import"./index-18d0wj5t.js";import"./index-e933mq3w.js";import{Wa as j}from"./index-h1zmmtbw.js";import"./index-48mg443r.js";var V=j.object({siteUrl:j.url(),title:j.string(),description:j.string(),language:j.string().optional(),copyright:j.string().optional()});class Y{logger;id="blog:rss";name="Blog RSS Feed DataSource";description="Generates RSS 2.0 feed XML from published blog posts";constructor(D){this.logger=D,this.logger.debug("RSSDataSource initialized")}async fetch(D,N,O){let v=V.parse(D),E=(await O.entityService.listEntities({entityType:"post",options:{limit:1000}})).filter((A)=>A.metadata.status==="published"&&A.metadata.publishedAt).map((A)=>{let H=I(A.content,J);return{...A,frontmatter:H.metadata,body:H.content}});this.logger.debug(`Generating RSS feed with ${E.length} posts`);let T={title:v.title,description:v.description,link:v.siteUrl,language:v.language??"en-us",...v.copyright&&{copyright:v.copyright}},U={xml:K(E,T)};return N.parse(U)}}export{Y as RSSDataSource};
3
3
 
4
- //# debugId=E9878465D75A294364756E2164756E21
5
- //# sourceMappingURL=rss-datasource-c67ta2xa.js.map
4
+ //# debugId=AC1C0EA354A69B2664756E2164756E21
5
+ //# sourceMappingURL=rss-datasource-v805vq9d.js.map
@@ -5,6 +5,6 @@
5
5
  "import type {\n BaseDataSourceContext,\n DataSource,\n DataSourceSchema,\n} from \"@brains/plugins\";\nimport type { Logger } from \"@brains/utils/logger\";\nimport { z } from \"@brains/utils/zod\";\nimport type { BlogPost } from \"../schemas/blog-post\";\nimport { parseMarkdownWithFrontmatter } from \"@brains/plugins\";\nimport { blogPostFrontmatterSchema } from \"../schemas/blog-post\";\nimport type { BlogPostWithData } from \"./blog-datasource\";\nimport { generateRSSFeed, type RSSFeedConfig } from \"../rss/feed-generator\";\n\n/**\n * RSS feed query schema\n */\nconst rssFeedQuerySchema = z.object({\n siteUrl: z.url(),\n title: z.string(),\n description: z.string(),\n language: z.string().optional(),\n copyright: z.string().optional(),\n});\n\ntype RSSFeedQuery = z.output<typeof rssFeedQuerySchema>;\n\n/**\n * DataSource for generating RSS feed from blog posts\n */\nexport class RSSDataSource implements DataSource {\n private readonly logger: Logger;\n public readonly id = \"blog:rss\";\n public readonly name = \"Blog RSS Feed DataSource\";\n public readonly description =\n \"Generates RSS 2.0 feed XML from published blog posts\";\n\n constructor(logger: Logger) {\n this.logger = logger;\n this.logger.debug(\"RSSDataSource initialized\");\n }\n\n /**\n * Fetch and generate RSS feed XML\n * @param context - Optional context (environment, etc.)\n */\n async fetch<T>(\n query: unknown,\n outputSchema: DataSourceSchema<T>,\n context: BaseDataSourceContext,\n ): Promise<T> {\n // Parse query parameters\n const params: RSSFeedQuery = rssFeedQuerySchema.parse(query);\n // Use context.entityService for automatic publishedOnly filtering\n const entityService = context.entityService;\n\n // Fetch all published posts\n const allPosts: BlogPost[] = await entityService.listEntities({\n entityType: \"post\",\n options: {\n limit: 1000,\n },\n });\n\n // Filter only published posts and parse frontmatter\n const publishedPosts: BlogPostWithData[] = allPosts\n .filter(\n (p) => p.metadata.status === \"published\" && p.metadata.publishedAt,\n )\n .map((entity) => {\n const parsed = parseMarkdownWithFrontmatter(\n entity.content,\n blogPostFrontmatterSchema,\n );\n return {\n ...entity,\n frontmatter: parsed.metadata,\n body: parsed.content,\n };\n });\n\n this.logger.debug(\n `Generating RSS feed with ${publishedPosts.length} posts`,\n );\n\n // Build RSS config\n const rssConfig: RSSFeedConfig = {\n title: params.title,\n description: params.description,\n link: params.siteUrl,\n language: params.language ?? \"en-us\",\n ...(params.copyright && { copyright: params.copyright }),\n };\n\n // Generate RSS XML\n const xml = generateRSSFeed(publishedPosts, rssConfig);\n\n const result = {\n xml,\n };\n\n return outputSchema.parse(result);\n }\n}\n"
6
6
  ],
7
7
  "mappings": ";+XAgBA,FAAM,JAAqB,JAAE,CAAO,LAClC,EAAS,JAAE,FAAI,JACf,MAAO,EAAE,OAAO,EAChB,YAAa,EAAE,OAAO,EACtB,SAAU,EAAE,OAAO,EAAE,SAAS,EAC9B,UAAW,EAAE,OAAO,EAAE,SAAS,CACjC,CAAC,EAOM,MAAM,CAAoC,CAC9B,OACD,GAAK,WACL,KAAO,2BACP,YACd,uDAEF,WAAW,CAAC,EAAgB,CAC1B,KAAK,OAAS,EACd,KAAK,OAAO,MAAM,2BAA2B,OAOzC,MAAQ,CACZ,EACA,EACA,EACY,CAEZ,IAAM,EAAuB,EAAmB,MAAM,CAAK,EAarD,GARuB,MAHP,EAAQ,cAGmB,aAAa,CAC5D,WAAY,OACZ,QAAS,CACP,MAAO,IACT,CACF,CAAC,GAIE,OACC,CAAC,IAAM,EAAE,SAAS,SAAW,aAAe,EAAE,SAAS,WACzD,EACC,IAAI,CAAC,IAAW,CACf,IAAM,EAAS,EACb,EAAO,QACP,CACF,EACA,MAAO,IACF,EACH,YAAa,EAAO,SACpB,KAAM,EAAO,OACf,EACD,EAEH,KAAK,OAAO,MACV,4BAA4B,EAAe,cAC7C,EAGA,IAAM,EAA2B,CAC/B,MAAO,EAAO,MACd,YAAa,EAAO,YACpB,KAAM,EAAO,QACb,SAAU,EAAO,UAAY,WACzB,EAAO,WAAa,CAAE,UAAW,EAAO,SAAU,CACxD,EAKM,EAAS,CACb,IAHU,EAAgB,EAAgB,CAAS,CAIrD,EAEA,OAAO,EAAa,MAAM,CAAM,EAEpC",
8
- "debugId": "E9878465D75A294364756E2164756E21",
8
+ "debugId": "AC1C0EA354A69B2664756E2164756E21",
9
9
  "names": []
10
10
  }