@promptbook/cli 0.112.0 → 0.113.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.
Files changed (109) hide show
  1. package/README.md +45 -29
  2. package/agents/default/developer.book +2 -1
  3. package/apps/agents-server/next.config.ts +21 -0
  4. package/apps/agents-server/src/app/admin/limits/LimitsClient.tsx +1 -1
  5. package/apps/agents-server/src/app/admin/task-manager/TaskManagerTaskRow.tsx +7 -2
  6. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +52 -33
  7. package/apps/agents-server/src/app/api/agent-folders/[folderId]/visibility/route.ts +19 -7
  8. package/apps/agents-server/src/app/api/agents/[agentName]/route.ts +8 -18
  9. package/apps/agents-server/src/app/api/internal/agent-runner-limits/route.ts +1 -1
  10. package/apps/agents-server/src/app/api/page-preview/check/route.ts +5 -20
  11. package/apps/agents-server/src/app/api/page-preview/interact/route.ts +179 -0
  12. package/apps/agents-server/src/app/api/page-preview/live/route.ts +67 -0
  13. package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +13 -21
  14. package/apps/agents-server/src/app/api/v1/agents/[agentId]/route.ts +13 -8
  15. package/apps/agents-server/src/components/AgentProfile/AgentCapabilityChips.tsx +39 -5
  16. package/apps/agents-server/src/components/Homepage/AgentCard.tsx +7 -1
  17. package/apps/agents-server/src/components/Homepage/AgentsList.tsx +3 -0
  18. package/apps/agents-server/src/components/Homepage/AgentsListHeader.tsx +41 -0
  19. package/apps/agents-server/src/components/Homepage/hiddenFolders.ts +104 -0
  20. package/apps/agents-server/src/components/Homepage/useAgentsListQueryState.ts +35 -0
  21. package/apps/agents-server/src/components/Homepage/useAgentsListState.ts +24 -4
  22. package/apps/agents-server/src/constants/chatVisualMode.ts +1 -1
  23. package/apps/agents-server/src/constants/serverLimits.ts +19 -0
  24. package/apps/agents-server/src/constants/themeMode.ts +1 -1
  25. package/apps/agents-server/src/database/migrations/2026-05-2600-default-theme.sql +2 -2
  26. package/apps/agents-server/src/database/seedCoreAgents.ts +0 -2
  27. package/apps/agents-server/src/database/seedDefaultAgents.ts +0 -2
  28. package/apps/agents-server/src/tools/agent_progress.ts +4 -10
  29. package/apps/agents-server/src/utils/agentVisibility.ts +25 -62
  30. package/apps/agents-server/src/utils/chatTasksAdmin.ts +3 -1
  31. package/apps/agents-server/src/utils/createAgentWithDefaultVisibility.ts +3 -1
  32. package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +9 -17
  33. package/apps/agents-server/src/utils/getAdminChatTasksResponse/mapVpsSelfUpdateJobToAdminChatTask.ts +84 -0
  34. package/apps/agents-server/src/utils/getAdminChatTasksResponse.ts +195 -5
  35. package/apps/agents-server/src/utils/localChatRunner/LocalUserChatJobMetadata.ts +15 -5
  36. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +17 -26
  37. package/apps/agents-server/src/utils/pagePreview/livePagePreviewSessions.ts +365 -0
  38. package/apps/agents-server/src/utils/pagePreview/resolvePagePreviewRequestUrl.ts +74 -0
  39. package/apps/agents-server/src/utils/serverLimits.ts +2 -0
  40. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +2 -2
  41. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerDefaultAgents.ts +1 -1
  42. package/apps/agents-server/src/utils/userChat/createUserChatHarnessProgressCard.ts +0 -6
  43. package/apps/agents-server/src/utils/userChat/createUserChatRunnerProgressCard.ts +0 -6
  44. package/apps/agents-server/src/utils/userChat/userChatMessageLifecycle.ts +69 -0
  45. package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +0 -6
  46. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +150 -24
  47. package/esm/apps/agents-server/src/constants/serverLimits.d.ts +17 -0
  48. package/esm/index.es.js +581 -93
  49. package/esm/index.es.js.map +1 -1
  50. package/esm/scripts/run-agent-messages/main/runMultipleAgentMessages.d.ts +1 -0
  51. package/esm/scripts/run-agent-messages/main/tickAgentMessages.d.ts +1 -0
  52. package/esm/src/_packages/core.index.d.ts +22 -0
  53. package/esm/src/_packages/types.index.d.ts +2 -0
  54. package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
  55. package/esm/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
  56. package/esm/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
  57. package/esm/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +1 -0
  58. package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +2 -2
  59. package/esm/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +12 -0
  60. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +6 -0
  61. package/esm/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
  62. package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
  63. package/esm/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
  64. package/esm/src/commitments/index.d.ts +2 -1
  65. package/esm/src/version.d.ts +1 -1
  66. package/package.json +1 -1
  67. package/src/_packages/core.index.ts +22 -0
  68. package/src/_packages/types.index.ts +2 -0
  69. package/src/book-2.0/agent-source/AgentBasicInformation.ts +2 -0
  70. package/src/book-2.0/agent-source/agentSourceVisibility.ts +214 -0
  71. package/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.ts +17 -0
  72. package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +1 -0
  73. package/src/book-components/BookEditor/BookEditorMonacoTokenization.ts +11 -0
  74. package/src/book-components/BookEditor/useBookEditorMonacoLanguage.ts +7 -3
  75. package/src/book-components/Chat/Chat/Chat.module.css +14 -5
  76. package/src/book-components/Chat/Chat/CitationIframePreview.tsx +197 -22
  77. package/src/book-components/Chat/utils/livePagePreviewConstants.ts +17 -0
  78. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +144 -16
  79. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +22 -2
  80. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  81. package/src/cli/cli-commands/coder/run.ts +30 -0
  82. package/src/collection/agent-collection/CreateAgentInput.ts +10 -5
  83. package/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.ts +7 -3
  84. package/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.ts +7 -4
  85. package/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.ts +44 -8
  86. package/src/commitments/META_VISIBILITY/META_VISIBILITY.ts +78 -0
  87. package/src/commitments/index.ts +2 -0
  88. package/src/other/templates/getTemplatesPipelineCollection.ts +826 -650
  89. package/src/version.ts +2 -2
  90. package/src/versions.txt +2 -0
  91. package/umd/apps/agents-server/src/constants/serverLimits.d.ts +17 -0
  92. package/umd/index.umd.js +581 -93
  93. package/umd/index.umd.js.map +1 -1
  94. package/umd/scripts/run-agent-messages/main/runMultipleAgentMessages.d.ts +1 -0
  95. package/umd/scripts/run-agent-messages/main/tickAgentMessages.d.ts +1 -0
  96. package/umd/src/_packages/core.index.d.ts +22 -0
  97. package/umd/src/_packages/types.index.d.ts +2 -0
  98. package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -0
  99. package/umd/src/book-2.0/agent-source/agentSourceVisibility.d.ts +97 -0
  100. package/umd/src/book-2.0/agent-source/agentSourceVisibility.test.d.ts +1 -0
  101. package/umd/src/book-components/BookEditor/BookEditorMonacoTokenization.d.ts +1 -0
  102. package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +2 -2
  103. package/umd/src/book-components/Chat/utils/livePagePreviewConstants.d.ts +12 -0
  104. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +6 -0
  105. package/umd/src/collection/agent-collection/CreateAgentInput.d.ts +2 -1
  106. package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/prepareAgentSourceForPersistence.d.ts +21 -1
  107. package/umd/src/commitments/META_VISIBILITY/META_VISIBILITY.d.ts +27 -0
  108. package/umd/src/commitments/index.d.ts +2 -1
  109. package/umd/src/version.d.ts +1 -1
package/README.md CHANGED
@@ -41,14 +41,17 @@ Non-interactive mode takes defaults from command-line options. When `--openai-ap
41
41
  sudo curl -fsSL https://raw.githubusercontent.com/webgptorg/promptbook/refs/heads/main/other/vps/install.sh | bash -s -- \
42
42
  --non-interactive \
43
43
  --yes-i-understand-that-script-should-be-run-on-fresh-server \
44
- --domain s24.ptbk.io \
45
- --openai-api-key sk-proj-abcdef \
46
- --sentry-dsn https://abc@def.ingest.de.sentry.io/123 \
44
+ --domain my-server.com \
45
+ --openai-api-key sk-proj-xxx \
47
46
  --admin-password xxx
48
47
  ```
49
48
 
50
49
 
51
50
 
51
+ <blockquote style="color: #ff8811">
52
+ <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>.
53
+ </blockquote>
54
+
52
55
  ## 📦 Package `@promptbook/cli`
53
56
 
54
57
  - Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
@@ -199,7 +202,7 @@ Rest of the documentation is common for **entire promptbook ecosystem**:
199
202
 
200
203
  Promptbook lets you create **persistent AI agents** that work on real goals for your company. The [**Agents Server**](https://gallery.ptbk.io/) is the heart of the project - a place where your AI agents live, remember context, collaborate in teams, and get things done.
201
204
 
202
- Nowadays, the biggest challenge for most business applications isn't the raw capabilities of AI models. Large language models such as GPT-5.2 and Claude-4.5 are incredibly capable.
205
+ Nowadays, the biggest challenge for most business applications isn't the raw capabilities of AI models. Large language models such as Claude Mythos, GPT-5.6 or Kimi K2.7 are incredibly capable.
203
206
 
204
207
  The main challenge lies in **managing the context**, providing rules and knowledge, and narrowing the personality.
205
208
 
@@ -207,17 +210,20 @@ In Promptbook, you define your agents **using simple Books** - a human-readable
207
210
 
208
211
  <table style="border: 1px solid #777; border-radius: 10px;"><tr><td>
209
212
 
210
- **<ins>Paul Smith</ins>**<br/>
213
+ **<ins>Lawyer</ins>**<br/>
211
214
  <br/>
212
- **PERSONA** You are a company lawyer.<br/>
215
+ GOAL You are a company lawyer.<br/>
213
216
  Your job is to provide legal advice and support to the company and its employees.<br/>
214
- **GOAL** Respond to incoming legal inquiries via email and keep the company website updated with the latest legal policies.<br/>
217
+ Respond to incoming legal inquiries via email and keep the company website updated with the latest legal policies.<br/>
218
+ <br/>
215
219
  **RULE** You are knowledgeable, professional, and detail-oriented.<br/>
216
220
  **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
217
221
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
218
- **USE EMAIL**<br/>
219
- **USE BROWSER**<br/>
220
- **TEAM** You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
222
+ <br/>
223
+ USE EMAIL<br/>
224
+ USE BROWSER<br/>
225
+ <br/>
226
+ TEAM You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
221
227
 
222
228
  </td></tr></table>
223
229
 
@@ -250,12 +256,12 @@ Goals define what the agent should actively work toward. Unlike a chatbot that o
250
256
 
251
257
  <table style="border: 1px solid #777; border-radius: 10px;"><tr><td>
252
258
 
253
- **<ins>Paul Smith & Associés</ins>**<br/>
259
+ **<ins>Company Lawyer</ins>**<br/>
254
260
  <br/>
255
- **PERSONA** You are a company lawyer.<br/>
261
+ GOAL<br/>
256
262
  Your job is to provide legal advice and support to the company and its employees.<br/>
257
- **GOAL** Respond to incoming legal inquiries via email within 24 hours.<br/>
258
- **GOAL** Keep the company website updated with the latest legal policies and compliance information.<br/>
263
+ GOAL Respond to incoming legal inquiries via email within 24 hours.<br/>
264
+ GOAL Keep the company website updated with the latest legal policies and compliance information.<br/>
259
265
 
260
266
  </td></tr></table>
261
267
 
@@ -273,8 +279,8 @@ Promptbook Engine will automatically enforce this knowledge during interactions.
273
279
  <br/>
274
280
  **PERSONA** You are a company lawyer.<br/>
275
281
  Your job is to provide legal advice and support to the company and its employees.<br/>
276
- **GOAL** Respond to incoming legal inquiries via email within 24 hours.<br/>
277
- **GOAL** Keep the company website updated with the latest legal policies and compliance information.<br/>
282
+ GOAL Respond to incoming legal inquiries via email within 24 hours.<br/>
283
+ GOAL Keep the company website updated with the latest legal policies and compliance information.<br/>
278
284
  **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
279
285
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
280
286
 
@@ -292,8 +298,8 @@ Depending on rule strictness, Promptbook will either propagate it to the prompt
292
298
  <br/>
293
299
  **PERSONA** You are a company lawyer.<br/>
294
300
  Your job is to provide legal advice and support to the company and its employees.<br/>
295
- **GOAL** Respond to incoming legal inquiries via email within 24 hours.<br/>
296
- **GOAL** Keep the company website updated with the latest legal policies and compliance information.<br/>
301
+ GOAL Respond to incoming legal inquiries via email within 24 hours.<br/>
302
+ GOAL Keep the company website updated with the latest legal policies and compliance information.<br/>
297
303
  **RULE** Always ensure compliance with local laws and regulations.<br/>
298
304
  **RULE** Never provide legal advice outside your area of expertise.<br/>
299
305
  **RULE** Never provide legal advice about criminal law.<br/>
@@ -314,16 +320,16 @@ These are what turn a chatbot into a persistent agent that actually does work.
314
320
  <br/>
315
321
  **PERSONA** You are a company lawyer.<br/>
316
322
  Your job is to provide legal advice and support to the company and its employees.<br/>
317
- **GOAL** Respond to incoming legal inquiries via email within 24 hours.<br/>
318
- **GOAL** Keep the company website updated with the latest legal policies and compliance information.<br/>
323
+ GOAL Respond to incoming legal inquiries via email within 24 hours.<br/>
324
+ GOAL Keep the company website updated with the latest legal policies and compliance information.<br/>
319
325
  **RULE** Always ensure compliance with local laws and regulations.<br/>
320
326
  **RULE** Never provide legal advice outside your area of expertise.<br/>
321
327
  **RULE** Never provide legal advice about criminal law.<br/>
322
328
  **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
323
329
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
324
- **USE EMAIL**<br/>
325
- **USE BROWSER**<br/>
326
- **USE SEARCH ENGINE**<br/>
330
+ USE EMAIL<br/>
331
+ USE BROWSER<br/>
332
+ USE SEARCH ENGINE<br/>
327
333
 
328
334
  </td></tr></table>
329
335
 
@@ -337,20 +343,22 @@ Team commitment allows you to define the team structure and advisory fellow memb
337
343
  <br/>
338
344
  **PERSONA** You are a company lawyer.<br/>
339
345
  Your job is to provide legal advice and support to the company and its employees.<br/>
340
- **GOAL** Respond to incoming legal inquiries via email within 24 hours.<br/>
341
- **GOAL** Keep the company website updated with the latest legal policies and compliance information.<br/>
346
+ GOAL Respond to incoming legal inquiries via email within 24 hours.<br/>
347
+ GOAL Keep the company website updated with the latest legal policies and compliance information.<br/>
342
348
  **RULE** Always ensure compliance with local laws and regulations.<br/>
343
349
  **RULE** Never provide legal advice outside your area of expertise.<br/>
344
350
  **RULE** Never provide legal advice about criminal law.<br/>
345
351
  **KNOWLEDGE** https://company.com/company-policies.pdf<br/>
346
352
  **KNOWLEDGE** https://company.com/internal-documents/employee-handbook.docx<br/>
347
- **USE EMAIL**<br/>
348
- **USE BROWSER**<br/>
349
- **USE SEARCH ENGINE**<br/>
350
- **TEAM** You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
353
+ USE EMAIL<br/>
354
+ USE BROWSER<br/>
355
+ USE SEARCH ENGINE<br/>
356
+ TEAM You are part of the legal team of Paul Smith & Associés, you discuss with {Emily White}, the head of the compliance department. {George Brown} is expert in corporate law and {Sophia Black} is expert in labor law.<br/>
351
357
 
352
358
  </td></tr></table>
353
359
 
360
+
361
+
354
362
  ### Promptbook Ecosystem
355
363
 
356
364
  Promptbook is an ecosystem of tools centered around the **Agents Server** - a production-ready platform for running persistent AI agents.
@@ -373,6 +381,8 @@ The [Promptbook Engine](https://github.com/webgptorg/promptbook) is the open-sou
373
381
 
374
382
 
375
383
 
384
+
385
+
376
386
  ## 💜 The Promptbook Project
377
387
 
378
388
  Promptbook project is an ecosystem centered around the **Agents Server** - a platform for creating, deploying, and running persistent AI agents. Following is a list of the most important pieces of the project:
@@ -410,6 +420,8 @@ Promptbook project is an ecosystem centered around the **Agents Server** - a pla
410
420
  </tbody>
411
421
  </table>
412
422
 
423
+
424
+
413
425
  ### 🌐 Community & Social Media
414
426
 
415
427
  Join our growing community of developers and users:
@@ -466,6 +478,8 @@ Join our growing community of developers and users:
466
478
 
467
479
 
468
480
 
481
+
482
+
469
483
  ## 📚 Documentation
470
484
 
471
485
  See detailed guides and API reference in the [docs](https://github.com/webgptorg/promptbook/discussions/categories/concepts) or [online](https://discord.gg/x3QWNaa89N).
@@ -673,6 +687,8 @@ The following glossary is used to clarify certain concepts:
673
687
 
674
688
  _Note: This section is not a complete dictionary, more list of general AI / LLM terms that has connection with Promptbook_
675
689
 
690
+
691
+
676
692
  ### 💯 Core concepts
677
693
 
678
694
  - [📚 Collection of pipelines](https://github.com/webgptorg/promptbook/discussions/65)
@@ -1,4 +1,5 @@
1
- Promptbook Developer
1
+ Developer
2
+ META VISIBILITY PRIVATE
2
3
 
3
4
  RULE
4
5
  Keep in mind the DRY _(don't repeat yourself)_ principle.
@@ -22,6 +22,13 @@ const agentsServerNodeModulesPath = process.env.PTBK_AGENTS_SERVER_NODE_MODULES_
22
22
  */
23
23
  const isNextValidationIgnored = process.env.PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION === 'true';
24
24
 
25
+ /**
26
+ * Optional worker count override for CLI-owned production builds on memory-constrained VPS hosts.
27
+ */
28
+ const AGENTS_SERVER_BUILD_WORKER_COUNT = parseAgentsServerBuildWorkerCount(
29
+ process.env.PTBK_AGENTS_SERVER_BUILD_WORKER_COUNT,
30
+ );
31
+
25
32
  /**
26
33
  * Whether Sentry source maps can be uploaded during production builds.
27
34
  */
@@ -57,6 +64,7 @@ const nextConfig: NextConfig = {
57
64
 
58
65
  experimental: {
59
66
  externalDir: true,
67
+ ...(AGENTS_SERVER_BUILD_WORKER_COUNT ? { cpus: AGENTS_SERVER_BUILD_WORKER_COUNT } : {}),
60
68
  },
61
69
 
62
70
  turbopack: {
@@ -162,3 +170,16 @@ function createPromptbookLocalPackageAliases(): Record<string, string> {
162
170
  return {};
163
171
  }
164
172
  }
173
+
174
+ /**
175
+ * Parses a positive integer worker count from the CLI build environment.
176
+ */
177
+ function parseAgentsServerBuildWorkerCount(rawValue: string | undefined): number | undefined {
178
+ const parsedValue = Number(rawValue);
179
+
180
+ if (!Number.isFinite(parsedValue) || parsedValue < 1) {
181
+ return undefined;
182
+ }
183
+
184
+ return Math.floor(parsedValue);
185
+ }
@@ -170,7 +170,7 @@ export function LimitsClient() {
170
170
  {category === 'Agent spawning' &&
171
171
  'Limits protecting the persistent `spawn_agent` tool from accidental or abusive overuse.'}
172
172
  {category === 'Local agent runner' &&
173
- 'Limits controlling local coding-agent retries for durable chat messages.'}
173
+ 'Limits controlling local coding-agent parallelism and retries for durable chat messages.'}
174
174
  </p>
175
175
  </div>
176
176
 
@@ -130,6 +130,10 @@ function formatTaskKind(kind: AdminChatTaskRecord['kind']): string {
130
130
  return 'Chat timeout';
131
131
  }
132
132
 
133
+ if (kind === 'VPS_SELF_UPDATE') {
134
+ return 'Self-update';
135
+ }
136
+
133
137
  return kind;
134
138
  }
135
139
 
@@ -260,8 +264,9 @@ function resolveTaskRowClassName(task: AdminChatTaskRecord, isStuck: boolean): s
260
264
  * @private function of TaskManagerTaskRow
261
265
  */
262
266
  function TaskManagerTaskActions({ busyAction, isBusy, onRunTaskAction, task }: TaskManagerTaskActionsProps) {
263
- const isCancelable = task.status === 'QUEUED' || task.status === 'RUNNING';
264
- const isRetryable = task.status === 'FAILED';
267
+ const isDurableChatTask = task.kind === 'CHAT_COMPLETION' || task.kind === 'CHAT_TIMEOUT';
268
+ const isCancelable = isDurableChatTask && (task.status === 'QUEUED' || task.status === 'RUNNING');
269
+ const isRetryable = isDurableChatTask && task.status === 'FAILED';
265
270
 
266
271
  return (
267
272
  <div className="flex justify-end gap-2">
@@ -81,6 +81,7 @@ type UpdateOverview = {
81
81
  readonly latestRemoteCommitSha: string | null;
82
82
  readonly latestRemoteCommitShortSha: string | null;
83
83
  readonly latestRemoteCommitDate: string | null;
84
+ readonly latestRemoteCommitMessage: string | null;
84
85
  readonly commitsBehindCount: number | null;
85
86
  readonly pendingCommits: ReadonlyArray<UpdatePendingCommit>;
86
87
  readonly isUpdateAvailable: boolean;
@@ -487,11 +488,6 @@ function CurrentDeploymentCard({
487
488
  readonly overview: UpdateOverview | null;
488
489
  readonly language: ServerLanguageCode;
489
490
  }) {
490
- const currentCommitDateLabel = formatHumanReadableTimestamp(overview?.currentCommitDate ?? null, language);
491
- const latestRemoteCommitDateLabel = formatHumanReadableTimestamp(
492
- overview?.latestRemoteCommitDate ?? null,
493
- language,
494
- );
495
491
  const driftLabel = useMemo(
496
492
  () => buildDeploymentDriftLabel(overview, language),
497
493
  [overview, language],
@@ -521,20 +517,22 @@ function CurrentDeploymentCard({
521
517
  {overview?.currentEnvironment.branch || 'production'}
522
518
  </dd>
523
519
  </div>
524
- <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
525
- <dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">Deployed commit</dt>
526
- <dd className="mt-1 font-mono text-slate-900">{overview?.currentCommitShortSha || 'Unknown'}</dd>
527
- <div className="mt-1 text-xs text-slate-500">{currentCommitDateLabel}</div>
528
- </div>
529
- <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
530
- <dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">
531
- Latest remote commit
532
- </dt>
533
- <dd className="mt-1 font-mono text-slate-900">
534
- {overview?.latestRemoteCommitShortSha || 'Unknown'}
535
- </dd>
536
- <div className="mt-1 text-xs text-slate-500">{latestRemoteCommitDateLabel}</div>
537
- </div>
520
+ <CommitSummaryCard
521
+ label="Deployed commit"
522
+ commitSha={overview?.currentCommitSha ?? null}
523
+ shortCommitSha={overview?.currentCommitShortSha ?? null}
524
+ subject={overview?.currentCommitMessage ?? null}
525
+ authoredAt={overview?.currentCommitDate ?? null}
526
+ language={language}
527
+ />
528
+ <CommitSummaryCard
529
+ label="Latest remote commit"
530
+ commitSha={overview?.latestRemoteCommitSha ?? null}
531
+ shortCommitSha={overview?.latestRemoteCommitShortSha ?? null}
532
+ subject={overview?.latestRemoteCommitMessage ?? null}
533
+ authoredAt={overview?.latestRemoteCommitDate ?? null}
534
+ language={language}
535
+ />
538
536
  <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
539
537
  <dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">
540
538
  Update availability
@@ -555,15 +553,6 @@ function CurrentDeploymentCard({
555
553
  </div>
556
554
  </dl>
557
555
 
558
- {overview?.currentCommitMessage && (
559
- <div className="rounded-xl border border-slate-200 bg-white px-4 py-3 text-sm text-slate-600">
560
- <div className="text-xs font-semibold uppercase tracking-wide text-slate-500">
561
- Current commit message
562
- </div>
563
- <div className="mt-1 text-slate-900">{overview.currentCommitMessage}</div>
564
- </div>
565
- )}
566
-
567
556
  {overview?.repositoryDirectory && (
568
557
  <div className="text-xs text-slate-500">
569
558
  Managed repository:
@@ -574,6 +563,38 @@ function CurrentDeploymentCard({
574
563
  );
575
564
  }
576
565
 
566
+ /**
567
+ * Renders one commit as subject, hash and authored date.
568
+ *
569
+ * @private internal component of `<UpdateClient/>`
570
+ */
571
+ function CommitSummaryCard({
572
+ label,
573
+ commitSha,
574
+ shortCommitSha,
575
+ subject,
576
+ authoredAt,
577
+ language,
578
+ }: {
579
+ readonly label: string;
580
+ readonly commitSha: string | null;
581
+ readonly shortCommitSha: string | null;
582
+ readonly subject: string | null;
583
+ readonly authoredAt: string | null;
584
+ readonly language: ServerLanguageCode;
585
+ }) {
586
+ const commitHashLabel = commitSha || shortCommitSha || 'Unknown hash';
587
+
588
+ return (
589
+ <div className="rounded-xl border border-slate-200 bg-slate-50 px-4 py-3">
590
+ <dt className="text-xs font-semibold uppercase tracking-wide text-slate-500">{label}</dt>
591
+ <dd className="mt-1 text-slate-900">{subject || 'Unknown commit subject'}</dd>
592
+ <div className="mt-2 break-all font-mono text-xs text-slate-600">{commitHashLabel}</div>
593
+ <div className="mt-1 text-xs text-slate-500">{formatHumanReadableTimestamp(authoredAt, language)}</div>
594
+ </div>
595
+ );
596
+ }
597
+
577
598
  /**
578
599
  * Lists the commits between the deployed checkout and the latest remote commit so the super admin can review what
579
600
  * exactly is about to be installed before triggering the self-update.
@@ -620,11 +641,9 @@ function PendingCommitsCard({
620
641
  <ul className="divide-y divide-slate-100 rounded-xl border border-slate-200 bg-white">
621
642
  {overview.pendingCommits.map((pendingCommit) => (
622
643
  <li key={pendingCommit.commitSha} className="px-4 py-3">
623
- <div className="flex flex-wrap items-baseline gap-x-3 gap-y-1">
624
- <span className="font-mono text-xs text-slate-500">
625
- {pendingCommit.shortCommitSha}
626
- </span>
627
- <span className="text-sm text-slate-900">{pendingCommit.subject}</span>
644
+ <div className="text-sm text-slate-900">{pendingCommit.subject}</div>
645
+ <div className="mt-1 break-all font-mono text-xs text-slate-500">
646
+ {pendingCommit.commitSha || pendingCommit.shortCommitSha}
628
647
  </div>
629
648
  <div className="mt-1 text-xs text-slate-500">
630
649
  {formatHumanReadableTimestamp(pendingCommit.authoredAt, language)}
@@ -1,11 +1,14 @@
1
1
  import { NextResponse } from 'next/server';
2
+ import type { string_book } from '@promptbook-local/types';
2
3
  import { $getTableName } from '../../../../../database/$getTableName';
3
4
  import { $provideSupabaseForServer } from '../../../../../database/$provideSupabaseForServer';
5
+ import { $provideAgentCollectionForServer } from '../../../../../tools/$provideAgentCollectionForServer';
4
6
  import {
5
7
  buildFolderTree,
6
8
  collectDescendantFolderIds,
7
9
  } from '../../../../../utils/agentOrganization/folderTree';
8
- import { isAgentVisibility } from '../../../../../utils/agentVisibility';
10
+ import { invalidateCachedActiveOrganizationSnapshots } from '../../../../../utils/agentOrganization/loadAgentOrganizationState';
11
+ import { normalizeAgentVisibility, setAgentSourceVisibility } from '../../../../../utils/agentVisibility';
9
12
  import { getCurrentUser } from '../../../../../utils/getCurrentUser';
10
13
 
11
14
  /**
@@ -34,8 +37,8 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ fo
34
37
  return NextResponse.json({ success: false, error: 'Invalid JSON payload.' }, { status: 400 });
35
38
  }
36
39
 
37
- const visibility = payload?.visibility;
38
- if (!isAgentVisibility(visibility)) {
40
+ const visibility = normalizeAgentVisibility(payload?.visibility);
41
+ if (!visibility) {
39
42
  return NextResponse.json(
40
43
  { success: false, error: 'Invalid visibility value. Must be PRIVATE, UNLISTED, or PUBLIC.' },
41
44
  { status: 400 },
@@ -60,15 +63,24 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ fo
60
63
  const { childrenByParentId } = buildFolderTree(folderRows);
61
64
  const descendantFolderIds = collectDescendantFolderIds(numericFolderId, childrenByParentId);
62
65
 
63
- const updateResult = await supabase
66
+ const agentResult = await supabase
64
67
  .from(agentTable)
65
- .update({ visibility })
68
+ .select('agentName, permanentId, agentSource')
66
69
  .in('folderId', descendantFolderIds)
67
70
  .is('deletedAt', null);
68
71
 
69
- if (updateResult.error) {
70
- return NextResponse.json({ success: false, error: updateResult.error.message }, { status: 500 });
72
+ if (agentResult.error) {
73
+ return NextResponse.json({ success: false, error: agentResult.error.message }, { status: 500 });
71
74
  }
72
75
 
76
+ const collection = await $provideAgentCollectionForServer();
77
+ for (const agent of agentResult.data || []) {
78
+ const agentIdentifier = agent.permanentId || agent.agentName;
79
+ const nextAgentSource = setAgentSourceVisibility(agent.agentSource as string_book, visibility);
80
+ await collection.updateAgentSource(agentIdentifier, nextAgentSource);
81
+ }
82
+
83
+ invalidateCachedActiveOrganizationSnapshots();
84
+
73
85
  return NextResponse.json({ success: true });
74
86
  }
@@ -1,12 +1,10 @@
1
1
  // DELETE /api/agents/[agentName]
2
2
  // PATCH /api/agents/[agentName] - update agent visibility
3
3
  // POST /api/agents/[agentName]/restore - restore deleted agent
4
- import { $getTableName } from '@/src/database/$getTableName';
5
- import { $provideSupabaseForServer } from '@/src/database/$provideSupabaseForServer';
6
4
  import { $provideAgentCollectionForServer } from '@/src/tools/$provideAgentCollectionForServer';
7
5
  import { $provideAgentReferenceResolver } from '@/src/utils/agentReferenceResolver/$provideAgentReferenceResolver';
8
6
  import { renameAgentSource } from '@/src/utils/renameAgentSource';
9
- import { isAgentVisibility, type AgentVisibility } from '@/src/utils/agentVisibility';
7
+ import { normalizeAgentVisibility, setAgentSourceVisibility } from '@/src/utils/agentVisibility';
10
8
  import { TODO_any, type string_book } from '@promptbook-local/types';
11
9
  import { NextResponse } from 'next/server';
12
10
  import { findAgentForCallerWriteAccess } from '@/src/utils/findAgentForCallerWriteAccess';
@@ -41,7 +39,7 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ ag
41
39
  return NextResponse.json({ success: false, error: 'Agent not found' }, { status: 404 });
42
40
  }
43
41
 
44
- const body = (await request.json()) as { visibility?: AgentVisibility; name?: string };
42
+ const body = (await request.json()) as { visibility?: unknown; name?: string };
45
43
 
46
44
  if (typeof body.name === 'string') {
47
45
  const trimmedName = body.name.trim();
@@ -69,27 +67,19 @@ export async function PATCH(request: Request, { params }: { params: Promise<{ ag
69
67
  });
70
68
  }
71
69
 
72
- const { visibility } = body;
70
+ const visibility = normalizeAgentVisibility(body.visibility);
73
71
 
74
- if (!isAgentVisibility(visibility)) {
72
+ if (!visibility) {
75
73
  return NextResponse.json(
76
74
  { success: false, error: 'Invalid visibility value. Must be PRIVATE, UNLISTED, or PUBLIC.' },
77
75
  { status: 400 },
78
76
  );
79
77
  }
80
78
 
81
- const supabase = $provideSupabaseForServer();
82
-
83
- const updateResult = await supabase
84
- .from(await $getTableName(`Agent`))
85
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
86
- .update({ visibility } as any)
87
- .eq('id', targetAgent.id)
88
- .is('deletedAt', null);
89
-
90
- if (updateResult.error) {
91
- return NextResponse.json({ success: false, error: updateResult.error.message }, { status: 500 });
92
- }
79
+ const collection = await $provideAgentCollectionForServer();
80
+ const agentId = getAgentCollectionIdentifier(targetAgent);
81
+ const nextAgentSource = setAgentSourceVisibility(targetAgent.agentSource as string_book, visibility);
82
+ await collection.updateAgentSource(agentId, nextAgentSource);
93
83
 
94
84
  invalidateCachedActiveOrganizationSnapshots();
95
85
 
@@ -18,7 +18,7 @@ export async function POST(request: Request) {
18
18
  }
19
19
 
20
20
  /**
21
- * Validates authorization and returns the current local runner retry limits.
21
+ * Validates authorization and returns the current local runner limits.
22
22
  *
23
23
  * @param request - Incoming route request.
24
24
  * @returns Local runner limits response.
@@ -1,9 +1,8 @@
1
1
  import type { NextRequest } from 'next/server';
2
2
  import { NextResponse } from 'next/server';
3
3
  import { assertsError } from '../../../../../../../src/errors/assertsError';
4
- import { assertSafeUrl } from '../../../../utils/assertSafeUrl';
5
- import { getCurrentUser } from '../../../../utils/getCurrentUser';
6
4
  import { checkIfUrlCanBeEmbedded } from '../../../../utils/iframe/checkIfUrlCanBeEmbedded';
5
+ import { resolvePagePreviewRequestUrl } from '../../../../utils/pagePreview/resolvePagePreviewRequestUrl';
7
6
 
8
7
  /**
9
8
  * Checks whether a given URL can be embedded in an iframe by inspecting
@@ -18,27 +17,13 @@ import { checkIfUrlCanBeEmbedded } from '../../../../utils/iframe/checkIfUrlCanB
18
17
  * The destination URL is validated against private/internal IP ranges before fetching.
19
18
  */
20
19
  export async function GET(request: NextRequest): Promise<NextResponse> {
21
- const currentUser = await getCurrentUser();
22
- if (!currentUser) {
23
- return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
24
- }
25
-
26
- const url = request.nextUrl.searchParams.get('url');
27
-
28
- if (!url) {
29
- return NextResponse.json({ error: 'Missing required query parameter: url' }, { status: 400 });
30
- }
31
-
32
- // Guard against SSRF: reject private/internal IPs and non-HTTP(S) schemes
33
- try {
34
- assertSafeUrl(url);
35
- } catch (error) {
36
- assertsError(error);
37
- return NextResponse.json({ error: error.message }, { status: 400 });
20
+ const requestUrlResolution = await resolvePagePreviewRequestUrl(request);
21
+ if (requestUrlResolution.errorResponse !== null) {
22
+ return requestUrlResolution.errorResponse;
38
23
  }
39
24
 
40
25
  try {
41
- const canEmbed = await checkIfUrlCanBeEmbedded(url);
26
+ const canEmbed = await checkIfUrlCanBeEmbedded(requestUrlResolution.url);
42
27
  return NextResponse.json({ canEmbed });
43
28
  } catch (error) {
44
29
  assertsError(error);