@promptbook/cli 0.103.0-50 → 0.103.0-52

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 (36) hide show
  1. package/apps/agents-server/package.json +1 -0
  2. package/apps/agents-server/src/app/AddAgentButton.tsx +7 -6
  3. package/apps/agents-server/src/app/{metadata → admin/metadata}/MetadataClient.tsx +5 -13
  4. package/apps/agents-server/src/app/{metadata → admin/metadata}/page.tsx +2 -2
  5. package/apps/agents-server/src/app/agents/[agentName]/AgentQrCode.tsx +3 -3
  6. package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +1 -1
  7. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +5 -2
  8. package/apps/agents-server/src/app/api/embed.js/route.ts +93 -0
  9. package/apps/agents-server/src/app/embed/page.tsx +24 -0
  10. package/apps/agents-server/src/app/page.tsx +48 -101
  11. package/apps/agents-server/src/components/Header/Header.tsx +28 -8
  12. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +28 -0
  13. package/apps/agents-server/src/components/Homepage/Card.tsx +18 -0
  14. package/apps/agents-server/src/components/Homepage/ModelCard.tsx +29 -0
  15. package/apps/agents-server/src/components/Homepage/Section.tsx +17 -0
  16. package/apps/agents-server/src/components/Homepage/TechInfoCard.tsx +20 -0
  17. package/apps/agents-server/src/components/UsersList/UsersList.tsx +6 -6
  18. package/apps/agents-server/src/components/VercelDeploymentCard/VercelDeploymentCard.tsx +3 -8
  19. package/apps/agents-server/src/database/migrate.ts +131 -0
  20. package/apps/agents-server/src/database/{schema.sql → migrations/2025-11-0001-initial-schema.sql} +1 -17
  21. package/apps/agents-server/src/database/migrations/2025-11-0002-metadata-table.sql +16 -0
  22. package/apps/agents-server/src/middleware.ts +1 -1
  23. package/esm/index.es.js +192 -10
  24. package/esm/index.es.js.map +1 -1
  25. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +1 -0
  26. package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +2 -2
  27. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
  28. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgent.d.ts +10 -1
  29. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +38 -0
  30. package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +2 -1
  31. package/esm/typings/src/commitments/index.d.ts +3 -1
  32. package/esm/typings/src/llm-providers/agent/Agent.d.ts +1 -0
  33. package/esm/typings/src/version.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/umd/index.umd.js +192 -10
  36. package/umd/index.umd.js.map +1 -1
@@ -1,6 +1,8 @@
1
1
  'use client';
2
2
 
3
3
  import { useState, useEffect } from 'react';
4
+ import { Card } from '../Homepage/Card';
5
+ import { Section } from '../Homepage/Section';
4
6
 
5
7
  type User = {
6
8
  id: number;
@@ -111,13 +113,11 @@ export function UsersList() {
111
113
 
112
114
  return (
113
115
  <div className="space-y-6">
114
- <h2 className="text-3xl text-gray-900 mt-16 mb-4">Users ({users.length})</h2>
115
-
116
116
  {error && <div className="bg-red-100 text-red-700 p-3 rounded">{error}</div>}
117
117
 
118
- <div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
118
+ <Section title={`Users (${users.length})`}>
119
119
  {users.map((user) => (
120
- <div key={user.id} className="block p-6 bg-white rounded-lg shadow-md border border-gray-200">
120
+ <Card key={user.id}>
121
121
  <div className="flex justify-between items-start">
122
122
  <div>
123
123
  <h3 className="text-xl font-semibold text-gray-900">{user.username}</h3>
@@ -139,7 +139,7 @@ export function UsersList() {
139
139
  </button>
140
140
  </div>
141
141
  </div>
142
- </div>
142
+ </Card>
143
143
  ))}
144
144
 
145
145
  {/* Create User Form */}
@@ -184,7 +184,7 @@ export function UsersList() {
184
184
  </button>
185
185
  </form>
186
186
  </div>
187
- </div>
187
+ </Section>
188
188
  </div>
189
189
  );
190
190
  }
@@ -16,19 +16,14 @@ import {
16
16
  NEXT_PUBLIC_VERCEL_TARGET_ENV,
17
17
  NEXT_PUBLIC_VERCEL_URL,
18
18
  } from '@/config';
19
- import Link from 'next/link';
19
+ import { TechInfoCard } from '../Homepage/TechInfoCard';
20
20
 
21
21
  /**
22
22
  * [♐️] Expose Vercel environment variables to indentify the deployment
23
23
  */
24
24
  export default function VercelDeploymentCard() {
25
25
  return (
26
- <Link
27
- href="#"
28
- className="block p-6 bg-white rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 border border-gray-200 hover:border-blue-400"
29
- >
30
- <h2 className="text-2xl font-semibold text-gray-900 mb-4">Vercel Deployment</h2>
31
-
26
+ <TechInfoCard title="Vercel Deployment">
32
27
  <p className="text-gray-600">NEXT_PUBLIC_VERCEL_ENV: {NEXT_PUBLIC_VERCEL_ENV}</p>
33
28
  <p className="text-gray-600">NEXT_PUBLIC_VERCEL_TARGET_ENV: {NEXT_PUBLIC_VERCEL_TARGET_ENV}</p>
34
29
  <p className="text-gray-600">NEXT_PUBLIC_VERCEL_URL: {NEXT_PUBLIC_VERCEL_URL}</p>
@@ -55,6 +50,6 @@ export default function VercelDeploymentCard() {
55
50
  <p className="text-gray-600">
56
51
  NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID: {NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID}
57
52
  </p>
58
- </Link>
53
+ </TechInfoCard>
59
54
  );
60
55
  }
@@ -0,0 +1,131 @@
1
+ import * as dotenv from 'dotenv';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { Client } from 'pg';
5
+
6
+ dotenv.config();
7
+
8
+ async function migrate() {
9
+ console.info('🚀 Starting database migration');
10
+
11
+ // 1. Get configuration
12
+ const prefixesEnv = process.env.SUPABASE_MIGRATION_PREFIXES;
13
+ if (!prefixesEnv) {
14
+ console.warn('⚠️ SUPABASE_MIGRATION_PREFIXES is not defined. Skipping migration.');
15
+ return;
16
+ }
17
+ const prefixes = prefixesEnv
18
+ .split(',')
19
+ .map((p) => p.trim())
20
+ .filter((p) => p !== '');
21
+
22
+ if (prefixes.length === 0) {
23
+ console.warn('⚠️ No prefixes found in SUPABASE_MIGRATION_PREFIXES. Skipping migration.');
24
+ return;
25
+ }
26
+
27
+ const connectionString = process.env.POSTGRES_URL || process.env.DATABASE_URL;
28
+ if (!connectionString) {
29
+ console.error('❌ POSTGRES_URL or DATABASE_URL is not defined.');
30
+ process.exit(1);
31
+ }
32
+
33
+ console.info(`📋 Found ${prefixes.length} prefixes to migrate: ${prefixes.join(', ')}`);
34
+
35
+ // 2. Connect to database
36
+ const client = new Client({
37
+ connectionString,
38
+ ssl: { rejectUnauthorized: false }, // Required for some Supabase/Heroku connections
39
+ });
40
+
41
+ try {
42
+ await client.connect();
43
+ console.info('🔌 Connected to database');
44
+
45
+ // 3. Read migration files
46
+ const migrationsDir = path.join(__dirname, 'migrations');
47
+ if (!fs.existsSync(migrationsDir)) {
48
+ console.error(`❌ Migrations directory not found at ${migrationsDir}`);
49
+ process.exit(1);
50
+ }
51
+
52
+ const migrationFiles = fs
53
+ .readdirSync(migrationsDir)
54
+ .filter((file) => file.endsWith('.sql'))
55
+ .sort(); // Ensure files are processed in order
56
+
57
+ console.info(`📂 Found ${migrationFiles.length} migration files`);
58
+
59
+ // 4. Iterate over prefixes and apply migrations
60
+ for (const prefix of prefixes) {
61
+ console.info(`\n🏗️ Migrating prefix: "${prefix}"`);
62
+ const migrationsTableName = `${prefix}Migrations`;
63
+
64
+ // 4.1 Create migrations table if not exists
65
+ const createMigrationsTableSql = `
66
+ CREATE TABLE IF NOT EXISTS "${migrationsTableName}" (
67
+ "filename" TEXT PRIMARY KEY,
68
+ "appliedAt" TIMESTAMP WITH TIME ZONE DEFAULT now()
69
+ );
70
+ `;
71
+ await client.query(createMigrationsTableSql);
72
+
73
+ // Enable RLS for migrations table
74
+ const enableRlsSql = `ALTER TABLE "${migrationsTableName}" ENABLE ROW LEVEL SECURITY;`;
75
+ await client.query(enableRlsSql);
76
+
77
+ // 4.2 Get applied migrations
78
+ const { rows: appliedMigrationsRows } = await client.query(
79
+ `SELECT "filename" FROM "${migrationsTableName}"`,
80
+ );
81
+ const appliedMigrations = new Set(appliedMigrationsRows.map((row) => row.filename));
82
+
83
+ // 4.3 Apply new migrations in one big transaction
84
+ let migrationError = null;
85
+ await client.query('BEGIN');
86
+ try {
87
+ for (const file of migrationFiles) {
88
+ if (appliedMigrations.has(file)) {
89
+ // console.info(` ⏭️ Skipping ${file} (already applied)`);
90
+ continue;
91
+ }
92
+
93
+ console.info(` 🚀 Applying ${file}...`);
94
+ const filePath = path.join(migrationsDir, file);
95
+ let sql = fs.readFileSync(filePath, 'utf-8');
96
+
97
+ // Replace prefix placeholder
98
+ sql = sql.replace(/prefix_/g, prefix);
99
+
100
+ try {
101
+ await client.query(sql);
102
+ await client.query(`INSERT INTO "${migrationsTableName}" ("filename") VALUES ($1)`, [file]);
103
+ console.info(` ✅ Applied ${file}`);
104
+ } catch (error) {
105
+ console.error(` ❌ Failed to apply ${file}:`, error);
106
+ migrationError = error;
107
+ break;
108
+ }
109
+ }
110
+ if (migrationError) {
111
+ await client.query('ROLLBACK');
112
+ throw migrationError;
113
+ } else {
114
+ await client.query('COMMIT');
115
+ }
116
+ } catch (error) {
117
+ await client.query('ROLLBACK');
118
+ throw error;
119
+ }
120
+ }
121
+
122
+ console.info('\n🎉 All migrations completed successfully');
123
+ } catch (error) {
124
+ console.error('\n❌ Migration failed:', error);
125
+ process.exit(1);
126
+ } finally {
127
+ await client.end();
128
+ }
129
+ }
130
+
131
+ migrate();
@@ -1,22 +1,8 @@
1
-
2
1
  -- Note: This is primary source of truth for the database schema
3
2
  -- In future we want to be compatible with more then Supabase so we keep SQL as main schema definition
4
3
  -- To update, search for [💽]
5
4
 
6
5
 
7
- CREATE TABLE IF NOT EXISTS "prefix_Metadata" (
8
- "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
9
- "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
10
- "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
11
- "key" TEXT NOT NULL,
12
- "value" TEXT NOT NULL,
13
- "note" TEXT NULL,
14
- CONSTRAINT prefix_Metadata_key_key UNIQUE ("key")
15
- );
16
-
17
- ALTER TABLE "prefix_Metadata" ENABLE ROW LEVEL SECURITY;
18
-
19
-
20
6
  CREATE TABLE IF NOT EXISTS "prefix_Agent" (
21
7
  "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
22
8
  "agentName" TEXT NOT NULL,
@@ -36,7 +22,7 @@ CREATE TABLE IF NOT EXISTS "prefix_Agent" (
36
22
  "preparedExternals" JSONB NULL
37
23
  );
38
24
  -- Ensure uniqueness of agentName even on repeated schema application without duplicate constraint creation
39
- CREATE UNIQUE INDEX IF NOT EXISTS prefix_agent_agentname_key ON "prefix_Agent" ("agentName");
25
+ CREATE UNIQUE INDEX IF NOT EXISTS "prefix_agent_agentname_key" ON "prefix_Agent" ("agentName");
40
26
  COMMENT ON COLUMN "prefix_Agent"."agentName" IS 'The unique name of the agent derived from the first line of the `agentSource`, automatically updated on `agentSource` change';
41
27
  COMMENT ON COLUMN "prefix_Agent"."agentHash" IS 'The hash of the `agentSource`, automatically updated on `agentSource` change';
42
28
  COMMENT ON COLUMN "prefix_Agent"."agentSource" IS 'The source code of the agent';
@@ -175,5 +161,3 @@ ALTER TABLE "prefix_ChatFeedback"
175
161
  FOREIGN KEY ("agentName")
176
162
  REFERENCES "prefix_Agent"("agentName")
177
163
  ON DELETE CASCADE;
178
-
179
- -- TODO: [🐱‍🚀] Create propper database migrations
@@ -0,0 +1,16 @@
1
+ -- Note: This is primary source of truth for the database schema
2
+ -- In future we want to be compatible with more then Supabase so we keep SQL as main schema definition
3
+ -- To update, search for [💽]
4
+
5
+
6
+ CREATE TABLE IF NOT EXISTS "prefix_Metadata" (
7
+ "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
8
+ "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
9
+ "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
10
+ "key" TEXT NOT NULL,
11
+ "value" TEXT NOT NULL,
12
+ "note" TEXT NULL,
13
+ CONSTRAINT "prefix_Metadata_key_key" UNIQUE ("key")
14
+ );
15
+
16
+ ALTER TABLE "prefix_Metadata" ENABLE ROW LEVEL SECURITY;
@@ -96,7 +96,7 @@ export async function middleware(req: NextRequest) {
96
96
 
97
97
  if (
98
98
  potentialAgentName &&
99
- !['agents', 'api', '_next', 'favicon.ico'].includes(potentialAgentName) &&
99
+ !['agents', 'api', 'admin', 'embed', '_next', 'favicon.ico'].includes(potentialAgentName) &&
100
100
  !potentialAgentName.startsWith('.') &&
101
101
  // Note: Other static files are excluded by the matcher configuration below
102
102
  true
package/esm/index.es.js CHANGED
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
47
47
  * @generated
48
48
  * @see https://github.com/webgptorg/promptbook
49
49
  */
50
- const PROMPTBOOK_ENGINE_VERSION = '0.103.0-50';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-52';
51
51
  /**
52
52
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
53
53
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -22395,9 +22395,13 @@ const _FormattedBookInMarkdownTranspilerRegistration = $bookTranspilersRegister.
22395
22395
  *
22396
22396
  * @private - TODO: [🧠] Maybe should be public?
22397
22397
  */
22398
- function createCommitmentRegex(commitment) {
22399
- const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22400
- const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
22398
+ function createCommitmentRegex(commitment, aliases = []) {
22399
+ const allCommitments = [commitment, ...aliases];
22400
+ const patterns = allCommitments.map((c) => {
22401
+ const escapedCommitment = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22402
+ return escapedCommitment.split(/\s+/).join('\\s+');
22403
+ });
22404
+ const keywordPattern = patterns.join('|');
22401
22405
  const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
22402
22406
  return regex;
22403
22407
  }
@@ -22410,9 +22414,13 @@ function createCommitmentRegex(commitment) {
22410
22414
  *
22411
22415
  * @private
22412
22416
  */
22413
- function createCommitmentTypeRegex(commitment) {
22414
- const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22415
- const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
22417
+ function createCommitmentTypeRegex(commitment, aliases = []) {
22418
+ const allCommitments = [commitment, ...aliases];
22419
+ const patterns = allCommitments.map((c) => {
22420
+ const escapedCommitment = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22421
+ return escapedCommitment.split(/\s+/).join('\\s+');
22422
+ });
22423
+ const keywordPattern = patterns.join('|');
22416
22424
  const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b`, 'gim');
22417
22425
  return regex;
22418
22426
  }
@@ -22424,22 +22432,23 @@ function createCommitmentTypeRegex(commitment) {
22424
22432
  * @private
22425
22433
  */
22426
22434
  class BaseCommitmentDefinition {
22427
- constructor(type) {
22435
+ constructor(type, aliases = []) {
22428
22436
  this.type = type;
22437
+ this.aliases = aliases;
22429
22438
  }
22430
22439
  /**
22431
22440
  * Creates a regex pattern to match this commitment in agent source
22432
22441
  * Uses the existing createCommitmentRegex function as internal helper
22433
22442
  */
22434
22443
  createRegex() {
22435
- return createCommitmentRegex(this.type);
22444
+ return createCommitmentRegex(this.type, this.aliases);
22436
22445
  }
22437
22446
  /**
22438
22447
  * Creates a regex pattern to match just the commitment type
22439
22448
  * Uses the existing createCommitmentTypeRegex function as internal helper
22440
22449
  */
22441
22450
  createTypeRegex() {
22442
- return createCommitmentTypeRegex(this.type);
22451
+ return createCommitmentTypeRegex(this.type, this.aliases);
22443
22452
  }
22444
22453
  /**
22445
22454
  * Helper method to create a new requirements object with updated system message
@@ -23351,6 +23360,165 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
23351
23360
  * Note: [💞] Ignore a discrepancy between file name and entity name
23352
23361
  */
23353
23362
 
23363
+ /**
23364
+ * META COLOR commitment definition
23365
+ *
23366
+ * The META COLOR commitment sets the agent's accent color.
23367
+ * This commitment is special because it doesn't affect the system message,
23368
+ * but is handled separately in the parsing logic.
23369
+ *
23370
+ * Example usage in agent source:
23371
+ *
23372
+ * ```book
23373
+ * META COLOR #ff0000
23374
+ * META COLOR #00ff00
23375
+ * ```
23376
+ *
23377
+ * @private [🪔] Maybe export the commitments through some package
23378
+ */
23379
+ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23380
+ constructor() {
23381
+ super('META COLOR', ['COLOR']);
23382
+ }
23383
+ /**
23384
+ * Short one-line description of META COLOR.
23385
+ */
23386
+ get description() {
23387
+ return "Set the agent's accent color.";
23388
+ }
23389
+ /**
23390
+ * Markdown documentation for META COLOR commitment.
23391
+ */
23392
+ get documentation() {
23393
+ return spaceTrim$1(`
23394
+ # META COLOR
23395
+
23396
+ Sets the agent's accent color.
23397
+
23398
+ ## Key aspects
23399
+
23400
+ - Does not modify the agent's behavior or responses.
23401
+ - Only one \`META COLOR\` should be used per agent.
23402
+ - If multiple are specified, the last one takes precedence.
23403
+ - Used for visual representation in user interfaces.
23404
+
23405
+ ## Examples
23406
+
23407
+ \`\`\`book
23408
+ Professional Assistant
23409
+
23410
+ META COLOR #3498db
23411
+ PERSONA You are a professional business assistant
23412
+ \`\`\`
23413
+
23414
+ \`\`\`book
23415
+ Creative Helper
23416
+
23417
+ META COLOR #e74c3c
23418
+ PERSONA You are a creative and inspiring assistant
23419
+ \`\`\`
23420
+ `);
23421
+ }
23422
+ applyToAgentModelRequirements(requirements, content) {
23423
+ // META COLOR doesn't modify the system message or model requirements
23424
+ // It's handled separately in the parsing logic for profile color extraction
23425
+ // This method exists for consistency with the CommitmentDefinition interface
23426
+ return requirements;
23427
+ }
23428
+ /**
23429
+ * Extracts the profile color from the content
23430
+ * This is used by the parsing logic
23431
+ */
23432
+ extractProfileColor(content) {
23433
+ const trimmedContent = content.trim();
23434
+ return trimmedContent || null;
23435
+ }
23436
+ }
23437
+ /**
23438
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23439
+ */
23440
+
23441
+ /**
23442
+ * META IMAGE commitment definition
23443
+ *
23444
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
23445
+ * This commitment is special because it doesn't affect the system message,
23446
+ * but is handled separately in the parsing logic.
23447
+ *
23448
+ * Example usage in agent source:
23449
+ *
23450
+ * ```book
23451
+ * META IMAGE https://example.com/avatar.jpg
23452
+ * META IMAGE /assets/agent-avatar.png
23453
+ * ```
23454
+ *
23455
+ * @private [🪔] Maybe export the commitments through some package
23456
+ */
23457
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
23458
+ constructor() {
23459
+ super('META IMAGE', ['IMAGE']);
23460
+ }
23461
+ /**
23462
+ * Short one-line description of META IMAGE.
23463
+ */
23464
+ get description() {
23465
+ return "Set the agent's profile image URL.";
23466
+ }
23467
+ /**
23468
+ * Markdown documentation for META IMAGE commitment.
23469
+ */
23470
+ get documentation() {
23471
+ return spaceTrim$1(`
23472
+ # META IMAGE
23473
+
23474
+ Sets the agent's avatar/profile image URL.
23475
+
23476
+ ## Key aspects
23477
+
23478
+ - Does not modify the agent's behavior or responses.
23479
+ - Only one \`META IMAGE\` should be used per agent.
23480
+ - If multiple are specified, the last one takes precedence.
23481
+ - Used for visual representation in user interfaces.
23482
+
23483
+ ## Examples
23484
+
23485
+ \`\`\`book
23486
+ Professional Assistant
23487
+
23488
+ META IMAGE https://example.com/professional-avatar.jpg
23489
+ PERSONA You are a professional business assistant
23490
+ STYLE Maintain a formal and courteous tone
23491
+ \`\`\`
23492
+
23493
+ \`\`\`book
23494
+ Creative Helper
23495
+
23496
+ META IMAGE /assets/creative-bot-avatar.png
23497
+ PERSONA You are a creative and inspiring assistant
23498
+ STYLE Be enthusiastic and encouraging
23499
+ ACTION Can help with brainstorming and ideation
23500
+ \`\`\`
23501
+ `);
23502
+ }
23503
+ applyToAgentModelRequirements(requirements, content) {
23504
+ // META IMAGE doesn't modify the system message or model requirements
23505
+ // It's handled separately in the parsing logic for profile image extraction
23506
+ // This method exists for consistency with the CommitmentDefinition interface
23507
+ return requirements;
23508
+ }
23509
+ /**
23510
+ * Extracts the profile image URL from the content
23511
+ * This is used by the parsing logic
23512
+ */
23513
+ extractProfileImageUrl(content) {
23514
+ const trimmedContent = content.trim();
23515
+ return trimmedContent || null;
23516
+ }
23517
+ }
23518
+ /**
23519
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23520
+ */
23521
+
23354
23522
  /**
23355
23523
  * MODEL commitment definition
23356
23524
  *
@@ -24258,6 +24426,8 @@ const COMMITMENT_REGISTRY = [
24258
24426
  new ModelCommitmentDefinition('MODELS'),
24259
24427
  new ActionCommitmentDefinition('ACTION'),
24260
24428
  new ActionCommitmentDefinition('ACTIONS'),
24429
+ new MetaImageCommitmentDefinition(),
24430
+ new MetaColorCommitmentDefinition(),
24261
24431
  new MetaCommitmentDefinition(),
24262
24432
  new NoteCommitmentDefinition('NOTE'),
24263
24433
  new NoteCommitmentDefinition('NOTES'),
@@ -24710,6 +24880,14 @@ function parseAgentSource(agentSource) {
24710
24880
  links.push(spaceTrim(commitment.content));
24711
24881
  continue;
24712
24882
  }
24883
+ if (commitment.type === 'META IMAGE') {
24884
+ meta.image = spaceTrim(commitment.content);
24885
+ continue;
24886
+ }
24887
+ if (commitment.type === 'META COLOR') {
24888
+ meta.color = spaceTrim(commitment.content);
24889
+ continue;
24890
+ }
24713
24891
  if (commitment.type !== 'META') {
24714
24892
  continue;
24715
24893
  }
@@ -24725,6 +24903,10 @@ function parseAgentSource(agentSource) {
24725
24903
  if (!meta.image) {
24726
24904
  meta.image = generatePlaceholderAgentProfileImageUrl(parseResult.agentName || '!!');
24727
24905
  }
24906
+ // Generate fullname fallback if no meta fullname specified
24907
+ if (!meta.fullname) {
24908
+ meta.fullname = parseResult.agentName || createDefaultAgentName(agentSource);
24909
+ }
24728
24910
  // Parse parameters using unified approach - both @Parameter and {parameter} notations
24729
24911
  // are treated as the same syntax feature with unified representation
24730
24912
  const parameters = parseParameters(agentSource);