@promptbook/cli 0.103.0 → 0.104.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,10 @@ Turn your company's scattered knowledge into AI ready Books
27
27
 
28
28
 
29
29
 
30
+ <blockquote style="color: #ff8811">
31
+ <b>⚠ Warning:</b> This is a pre-release version of the library. It is not yet ready for production use. Please look at <a href="https://www.npmjs.com/package/@promptbook/core?activeTab=versions">latest stable release</a>.
32
+ </blockquote>
33
+
30
34
  ## 📦 Package `@promptbook/cli`
31
35
 
32
36
  - Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+
3
+ import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
4
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../../../_common/components/Tabs/Tabs';
5
+
6
+ type WebsiteIntegrationTabsProps = {
7
+ reactCode: string;
8
+ htmlCode: string;
9
+ };
10
+
11
+ export function WebsiteIntegrationTabs({ reactCode, htmlCode }: WebsiteIntegrationTabsProps) {
12
+ return (
13
+ <Tabs defaultValue="react" className="w-full">
14
+ <TabsList>
15
+ <TabsTrigger value="react">React</TabsTrigger>
16
+ <TabsTrigger value="html">HTML</TabsTrigger>
17
+ </TabsList>
18
+ <TabsContent value="react">
19
+ <CodePreview code={reactCode} language="typescript" />
20
+ </TabsContent>
21
+ <TabsContent value="html">
22
+ <CodePreview code={htmlCode} language="xml" />
23
+ </TabsContent>
24
+ </Tabs>
25
+ );
26
+ }
@@ -14,11 +14,12 @@ import { Color } from '../../../../../../../src/utils/color/Color';
14
14
  import { withAlpha } from '../../../../../../../src/utils/color/operators/withAlpha';
15
15
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
16
16
  import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
17
+ import { getAgentName, getAgentProfile } from '../_utils';
17
18
  import { getAgentLinks } from '../agentLinks';
18
19
  import { CopyField } from '../CopyField';
19
- import { getAgentName, getAgentProfile } from '../_utils';
20
20
  import { generateAgentMetadata } from '../generateAgentMetadata';
21
21
  import { SdkCodeTabs } from './SdkCodeTabs';
22
+ import { WebsiteIntegrationTabs } from './WebsiteIntegrationTabs';
22
23
 
23
24
  export const generateMetadata = generateAgentMetadata;
24
25
 
@@ -71,13 +72,13 @@ export default async function AgentIntegrationPage({ params }: { params: Promise
71
72
 
72
73
  // Website Integration Code
73
74
  const { fullname, color, image, ...restMeta } = agentProfile.meta;
74
- const websiteIntegrationCode = spaceTrim(
75
+ const websiteIntegrationReactCode = spaceTrim(
75
76
  (block) => `
76
- import { PromptbookAgent } from '@promptbook/components';
77
+ import { PromptbookAgentIntegration } from '@promptbook/components';
77
78
 
78
79
  export function YourComponent() {
79
80
  return(
80
- <PromptbookAgent
81
+ <PromptbookAgentIntegration
81
82
  agentUrl="${baseUrl}"
82
83
  meta={${block(JSON.stringify({ fullname, color, image, ...restMeta }, null, 4))}}
83
84
  />
@@ -86,6 +87,19 @@ export default async function AgentIntegrationPage({ params }: { params: Promise
86
87
  `,
87
88
  );
88
89
 
90
+ // HTML Integration Code - use single quotes for meta attribute to allow JSON with double quotes inside
91
+ const metaJsonString = JSON.stringify({ fullname, color, image, ...restMeta }, null, 4);
92
+ const websiteIntegrationHtmlCode = spaceTrim(
93
+ (block) => `
94
+ <script src="${publicUrl.href}api/embed.js" async defer></script>
95
+
96
+ <promptbook-agent-integration
97
+ agent-url="${baseUrl}"
98
+ meta='${block(metaJsonString)}'
99
+ />
100
+ `,
101
+ );
102
+
89
103
  // OpenAI Compatible Curl
90
104
  const curlCode = spaceTrim(`
91
105
  curl ${agentApiBase}/api/openai/v1/chat/completions \\
@@ -214,7 +228,10 @@ export default async function AgentIntegrationPage({ params }: { params: Promise
214
228
  </p>
215
229
  </div>
216
230
  </div>
217
- <CodePreview code={websiteIntegrationCode} language="typescript" />
231
+ <WebsiteIntegrationTabs
232
+ reactCode={websiteIntegrationReactCode}
233
+ htmlCode={websiteIntegrationHtmlCode}
234
+ />
218
235
  </div>
219
236
 
220
237
  {/* OpenAI API Compatible Endpoint */}
@@ -7,8 +7,9 @@ import { parseAgentSource } from '@promptbook-local/core';
7
7
  import { headers } from 'next/headers';
8
8
  import spaceTrim from 'spacetrim';
9
9
  import { $sideEffect } from '../../../../../../../src/utils/organization/$sideEffect';
10
- import { CodePreview } from '../../../../../../_common/components/CodePreview/CodePreview';
10
+ import { just } from '../../../../../../../src/utils/organization/just';
11
11
  import { generateAgentMetadata } from '../generateAgentMetadata';
12
+ import { WebsiteIntegrationTabs } from '../integration/WebsiteIntegrationTabs';
12
13
 
13
14
  export const generateMetadata = generateAgentMetadata;
14
15
 
@@ -24,20 +25,31 @@ export default async function WebsiteIntegrationAgentPage({ params }: { params:
24
25
  const { publicUrl } = await $provideServer();
25
26
  const agentUrl = `${publicUrl.href}agents/${encodeURIComponent(agentName)}`;
26
27
 
27
- const code = spaceTrim(
28
+ const reactCode = spaceTrim(
28
29
  (block) => `
29
-
30
- import { PromptbookAgent } from '@promptbook/components';
30
+ import { PromptbookAgentIntegration } from '@promptbook/components';
31
31
 
32
32
  export function YourComponent() {
33
33
  return(
34
- <PromptbookAgent
34
+ <PromptbookAgentIntegration
35
35
  agentUrl="${agentUrl}"
36
36
  meta={${block(JSON.stringify({ fullname, color, image, ...restMeta }, null, 4))}}
37
37
  />
38
38
  );
39
39
  }
40
-
40
+ `,
41
+ );
42
+
43
+ // HTML Integration Code - use single quotes for meta attribute to allow JSON with double quotes inside
44
+ const metaJsonString = JSON.stringify({ fullname, color, image, ...restMeta }, null, 4);
45
+ const htmlCode = spaceTrim(
46
+ (block) => `
47
+ <script src="${publicUrl.href}api/embed.js" async defer></script>
48
+
49
+ <promptbook-agent-integration
50
+ agent-url="${agentUrl}"
51
+ meta='${block(metaJsonString)}'
52
+ />
41
53
  `,
42
54
  );
43
55
 
@@ -49,17 +61,24 @@ export default async function WebsiteIntegrationAgentPage({ params }: { params:
49
61
  React application using the <code>{'<PromptbookAgent />'}</code> component.
50
62
  </p>
51
63
 
52
- <CodePreview code={code} />
53
- <PromptbookAgentIntegration
54
- formfactor="profile"
55
- agentUrl={agentUrl}
56
- meta={meta}
57
- style={{
58
- width: '400px',
59
- height: '600px',
60
- // outline: `2px solid red`
61
- }}
62
- />
64
+ <WebsiteIntegrationTabs reactCode={reactCode} htmlCode={htmlCode} />
65
+ {just(false) && (
66
+ <PromptbookAgentIntegration
67
+ // formfactor="profile"
68
+ agentUrl={agentUrl}
69
+ meta={meta}
70
+ style={
71
+ {
72
+ // width: '400px',
73
+ // height: '600px',
74
+ // outline: `2px solid red`
75
+ }
76
+ }
77
+ />
78
+ )}
79
+ {htmlCode}
80
+ {just(true) && <div dangerouslySetInnerHTML={{ __html: htmlCode }} />}
81
+ {just(true) && <div dangerouslySetInnerHTML={{ __html: `<h1>Test</h1>` }} />}
63
82
  </main>
64
83
  );
65
84
  }
@@ -1,3 +1,4 @@
1
+ import { spaceTrim } from '@promptbook-local/utils';
1
2
  import { NextRequest, NextResponse } from 'next/server';
2
3
 
3
4
  export async function GET(request: NextRequest) {
@@ -5,84 +6,103 @@ export async function GET(request: NextRequest) {
5
6
  const host = request.nextUrl.host;
6
7
  const baseUrl = `${protocol}//${host}`;
7
8
 
8
- const script = `
9
- (function() {
10
- if (customElements.get('promptbook-agent')) {
11
- return;
12
- }
9
+ const script = spaceTrim(`
10
+ console.info('[🔌] Promptbook integration script from ${baseUrl}');
13
11
 
14
- class PromptbookAgentElement extends HTMLElement {
15
- constructor() {
16
- super();
17
- this.iframe = null;
18
- }
12
+ (function() {
13
+ if (customElements.get('promptbook-agent-integration')) {
14
+ return;
15
+ }
19
16
 
20
- static get observedAttributes() {
21
- return ['agent-url'];
22
- }
17
+ class PromptbookAgentIntegrationElement extends HTMLElement {
18
+ constructor() {
19
+ super();
20
+ console.info('[🔌] Initializing <promptbook-agent-integration/>',this);
21
+ this.iframe = null;
22
+ }
23
23
 
24
- connectedCallback() {
25
- this.render();
26
- window.addEventListener('message', this.handleMessage.bind(this));
27
- }
24
+ static get observedAttributes() {
25
+ return ['agent-url', 'meta'];
26
+ }
28
27
 
29
- disconnectedCallback() {
30
- window.removeEventListener('message', this.handleMessage.bind(this));
31
- }
28
+ connectedCallback() {
29
+ this.render();
30
+ window.addEventListener('message', this.handleMessage.bind(this));
31
+ }
32
32
 
33
- attributeChangedCallback(name, oldValue, newValue) {
34
- if (name === 'agent-url' && oldValue !== newValue) {
35
- this.render();
36
- }
37
- }
33
+ disconnectedCallback() {
34
+ window.removeEventListener('message', this.handleMessage.bind(this));
35
+ }
38
36
 
39
- handleMessage(event) {
40
- if (event.data && event.data.type === 'PROMPTBOOK_AGENT_RESIZE') {
41
- if (event.data.isOpen) {
42
- this.iframe.style.width = '450px';
43
- this.iframe.style.height = '650px';
44
- this.iframe.style.maxHeight = '90vh';
45
- this.iframe.style.maxWidth = '90vw';
46
- this.iframe.style.boxShadow = '0 4px 12px rgba(0,0,0,0.15)';
47
- this.iframe.style.borderRadius = '12px';
48
- } else {
49
- this.iframe.style.width = '60px';
50
- this.iframe.style.height = '60px';
51
- this.iframe.style.boxShadow = 'none';
52
- this.iframe.style.borderRadius = '0';
37
+ attributeChangedCallback(name, oldValue, newValue) {
38
+ if ((name === 'agent-url' || name === 'meta') && oldValue !== newValue) {
39
+ this.render();
40
+ }
53
41
  }
54
- }
55
- }
56
42
 
57
- render() {
58
- const agentUrl = this.getAttribute('agent-url');
59
- if (!agentUrl) return;
43
+ handleMessage(event) {
44
+ if (event.data && event.data.type === 'PROMPTBOOK_AGENT_RESIZE') {
45
+ if (event.data.isOpen) {
46
+ // Match PromptbookAgentSeamlessIntegration.module.css dimensions
47
+ // Window is 380x600 + 20px padding on each side
48
+ this.iframe.style.width = '420px';
49
+ this.iframe.style.height = '640px';
50
+ this.iframe.style.maxHeight = 'calc(80vh + 40px)';
51
+ this.iframe.style.maxWidth = 'calc(100vw - 20px)';
52
+ } else {
53
+ // Closed state - button area with padding and shadow space
54
+ // Button is ~140px wide + 20px right margin + shadow space
55
+ this.iframe.style.width = '180px';
56
+ this.iframe.style.height = '100px';
57
+ this.iframe.style.maxHeight = 'none';
58
+ this.iframe.style.maxWidth = 'none';
59
+ }
60
+ }
61
+ }
60
62
 
61
- if (!this.iframe) {
62
- this.attachShadow({ mode: 'open' });
63
- this.iframe = document.createElement('iframe');
64
- this.iframe.style.border = 'none';
65
- this.iframe.style.position = 'fixed';
66
- this.iframe.style.bottom = '20px';
67
- this.iframe.style.right = '20px';
68
- this.iframe.style.width = '60px';
69
- this.iframe.style.height = '60px';
70
- this.iframe.style.zIndex = '2147483647'; // Max z-index
71
- this.iframe.style.transition = 'width 0.3s ease, height 0.3s ease';
72
- this.iframe.style.backgroundColor = 'transparent';
73
- this.iframe.setAttribute('allow', 'microphone'); // Allow microphone if needed for voice
74
- this.shadowRoot.appendChild(this.iframe);
75
- }
63
+ render() {
64
+ const agentUrl = this.getAttribute('agent-url');
65
+ if (!agentUrl) return;
76
66
 
77
- // Construct embed URL pointing to the Next.js page we created
78
- const embedUrl = '${baseUrl}/embed?agentUrl=' + encodeURIComponent(agentUrl);
79
- this.iframe.src = embedUrl;
80
- }
81
- }
67
+ if (!this.iframe) {
68
+ this.attachShadow({ mode: 'open' });
69
+ this.iframe = document.createElement('iframe');
70
+ this.iframe.style.border = 'none';
71
+ this.iframe.style.position = 'fixed';
72
+ this.iframe.style.bottom = '0';
73
+ this.iframe.style.right = '0';
74
+ // Initial size for the closed button state (with padding and shadow space)
75
+ this.iframe.style.width = '180px';
76
+ this.iframe.style.height = '100px';
77
+ this.iframe.style.zIndex = '2147483647'; // Max z-index
78
+ this.iframe.style.transition = 'width 0.3s ease, height 0.3s ease';
79
+ this.iframe.style.backgroundColor = 'transparent';
80
+ this.iframe.setAttribute('allow', 'microphone'); // Allow microphone if needed for voice
81
+ this.shadowRoot.appendChild(this.iframe);
82
+ }
83
+
84
+ // Construct embed URL pointing to the Next.js page we created
85
+ let embedUrl = '${baseUrl}/embed?agentUrl=' + encodeURIComponent(agentUrl);
86
+
87
+ // Add meta parameter if provided
88
+ const metaAttr = this.getAttribute('meta');
89
+ if (metaAttr) {
90
+ try {
91
+ // Validate that it's valid JSON
92
+ JSON.parse(metaAttr);
93
+ embedUrl += '&meta=' + encodeURIComponent(metaAttr);
94
+ } catch (e) {
95
+ console.error('[🔌] Invalid meta JSON:', e);
96
+ }
97
+ }
98
+
99
+ this.iframe.src = embedUrl;
100
+ }
101
+ }
82
102
 
83
- customElements.define('promptbook-agent', PromptbookAgentElement);
84
- })();
85
- `;
103
+ customElements.define('promptbook-agent-integration', PromptbookAgentIntegrationElement);
104
+ })();
105
+ `);
86
106
 
87
107
  return new NextResponse(script, {
88
108
  headers: {
@@ -0,0 +1,31 @@
1
+ import type { Metadata } from 'next';
2
+
3
+ export const metadata: Metadata = {
4
+ title: 'Promptbook Agent Embed',
5
+ description: 'Embedded agent chat widget',
6
+ };
7
+
8
+ /**
9
+ * Minimal layout for the embed page - no header, footer, or other UI elements
10
+ * This layout is completely transparent and only renders the chat widget
11
+ */
12
+ export default function EmbedLayout({
13
+ children,
14
+ }: Readonly<{
15
+ children: React.ReactNode;
16
+ }>) {
17
+ return (
18
+ <html lang="en">
19
+ <body
20
+ style={{
21
+ margin: 0,
22
+ padding: 0,
23
+ background: 'transparent',
24
+ overflow: 'hidden',
25
+ }}
26
+ >
27
+ {children}
28
+ </body>
29
+ </html>
30
+ );
31
+ }
@@ -2,23 +2,36 @@
2
2
 
3
3
  import { PromptbookAgentIntegration } from '@promptbook-local/components';
4
4
  import { useSearchParams } from 'next/navigation';
5
+ import { useMemo } from 'react';
5
6
 
6
7
  export default function EmbedPage() {
7
8
  const searchParams = useSearchParams();
8
9
  const agentUrl = searchParams.get('agentUrl');
10
+ const metaParam = searchParams.get('meta');
11
+
12
+ const meta = useMemo(() => {
13
+ if (!metaParam) {
14
+ return undefined;
15
+ }
16
+ try {
17
+ return JSON.parse(metaParam);
18
+ } catch (e) {
19
+ console.error('[🔌] Failed to parse meta parameter:', e);
20
+ return undefined;
21
+ }
22
+ }, [metaParam]);
9
23
 
10
24
  if (!agentUrl) {
11
- return <div className="text-red-500">Missing agentUrl parameter</div>;
25
+ return <div style={{ color: 'red' }}>Missing agentUrl parameter</div>;
12
26
  }
13
27
 
14
28
  return (
15
- <div className="w-full h-full bg-transparent">
16
- <PromptbookAgentIntegration
17
- agentUrl={agentUrl}
18
- onOpenChange={(isOpen) => {
19
- window.parent.postMessage({ type: 'PROMPTBOOK_AGENT_RESIZE', isOpen }, '*');
20
- }}
21
- />
22
- </div>
29
+ <PromptbookAgentIntegration
30
+ agentUrl={agentUrl}
31
+ meta={meta}
32
+ onOpenChange={(isOpen) => {
33
+ window.parent.postMessage({ type: 'PROMPTBOOK_AGENT_RESIZE', isOpen }, '*');
34
+ }}
35
+ />
23
36
  );
24
37
  }
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
+ const PROMPTBOOK_ENGINE_VERSION = '0.104.0-1';
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