@promptbook/cli 0.112.0-102 → 0.112.0-104

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 (54) hide show
  1. package/apps/agents-server/README.md +0 -6
  2. package/apps/agents-server/src/app/AddAgentButton.tsx +0 -5
  3. package/apps/agents-server/src/app/actions.ts +50 -0
  4. package/apps/agents-server/src/app/admin/image-generator-test/ImageAttachmentsEditor.tsx +11 -6
  5. package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +13 -15
  6. package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +13 -14
  7. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +3 -4
  8. package/apps/agents-server/src/app/api/health/route.ts +18 -0
  9. package/apps/agents-server/src/app/api/upload/route.ts +110 -383
  10. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +1 -4
  11. package/apps/agents-server/src/components/Header/Header.tsx +0 -11
  12. package/apps/agents-server/src/components/Header/useHeaderAgentMenus.tsx +0 -5
  13. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +39 -16
  14. package/apps/agents-server/src/constants/defaultAgentAvatarVisual.ts +1 -1
  15. package/apps/agents-server/src/database/migrations/2026-06-0200-default-agent-avatar-visual-octopus3d3.sql +16 -0
  16. package/apps/agents-server/src/middleware.ts +2 -1
  17. package/apps/agents-server/src/tools/$provideCdnForServer.ts +87 -49
  18. package/apps/agents-server/src/utils/agentRouting/resolveAgentRouteTarget.ts +27 -4
  19. package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +17 -49
  20. package/apps/agents-server/src/utils/cdn/classes/TrackedFilesStorage.ts +5 -2
  21. package/apps/agents-server/src/utils/cdn/interfaces/IFilesStorage.ts +5 -0
  22. package/apps/agents-server/src/utils/defaultAgents/defaultAgents.ts +168 -0
  23. package/apps/agents-server/src/utils/defaultAgents/installDefaultAgents.ts +139 -0
  24. package/apps/agents-server/src/utils/shareTargetPayloads.ts +15 -63
  25. package/apps/agents-server/src/utils/upload/createBookEditorUploadHandler.ts +23 -150
  26. package/apps/agents-server/src/utils/upload/uploadFileToServer.ts +113 -0
  27. package/esm/index.es.js +711 -41
  28. package/esm/index.es.js.map +1 -1
  29. package/esm/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
  30. package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
  31. package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
  32. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
  33. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  34. package/esm/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
  35. package/esm/src/version.d.ts +1 -1
  36. package/package.json +1 -1
  37. package/src/avatars/types/AvatarVisualDefinition.ts +1 -0
  38. package/src/avatars/visuals/avatarVisualRegistry.ts +2 -0
  39. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +903 -0
  40. package/src/book-components/Chat/MarkdownContent/MarkdownContent.tsx +1 -3
  41. package/src/other/templates/getTemplatesPipelineCollection.ts +799 -809
  42. package/src/utils/agents/resolveAgentAvatarImageUrl.ts +1 -1
  43. package/src/version.ts +2 -2
  44. package/src/versions.txt +1 -0
  45. package/umd/index.umd.js +711 -41
  46. package/umd/index.umd.js.map +1 -1
  47. package/umd/scripts/run-codex-prompts/common/waitForPause.d.ts +12 -0
  48. package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -1
  49. package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
  50. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -1
  51. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
  52. package/umd/src/avatars/visuals/octopus3d3AvatarVisual.d.ts +7 -0
  53. package/umd/src/version.d.ts +1 -1
  54. package/apps/agents-server/src/utils/cdn/resolveCdnStorageProvider.ts +0 -40
@@ -41,12 +41,6 @@ ptbk agents-server start --agent github-copilot --model gpt-5.4 --thinking-level
41
41
  <a id="agents-server-env-admin-password"></a>
42
42
  - `ADMIN_PASSWORD`: Password for the built-in `admin` login on a self-hosted Agents Server. Choose a private value before using the admin UI.
43
43
 
44
- <a id="agents-server-env-next-public-cdn-storage-provider"></a>
45
- - `NEXT_PUBLIC_CDN_STORAGE_PROVIDER`: File storage provider for uploads. Use `s3` for S3-compatible storage such as the VPS installer's self-contained MinIO service or external S3, and `vercel` for Vercel Blob.
46
-
47
- <a id="agents-server-env-s3-cdn"></a>
48
- - `CDN_BUCKET`, `CDN_ENDPOINT`, `CDN_ACCESS_KEY_ID`, `CDN_SECRET_ACCESS_KEY`, `NEXT_PUBLIC_CDN_PUBLIC_URL`, and `NEXT_PUBLIC_CDN_PATH_PREFIX`: S3-compatible upload configuration used when `NEXT_PUBLIC_CDN_STORAGE_PROVIDER=s3`.
49
-
50
44
  ## Creating servers
51
45
 
52
46
  When creating new Agents server, search across the repository for [☁]
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { useRouter } from 'next/navigation';
4
3
  import { FileCard } from '../components/Homepage/FileCard';
5
4
  import { useAgentNaming } from '../components/AgentNaming/AgentNamingContext';
6
5
  import { showAlert } from '../components/AsyncDialogs/asyncDialogs';
@@ -21,15 +20,11 @@ type AddAgentButtonProps = {
21
20
  * Renders the add-agent card and creation dialog workflow.
22
21
  */
23
22
  export function AddAgentButton({ currentFolderId }: AddAgentButtonProps) {
24
- const router = useRouter();
25
23
  const { formatText } = useAgentNaming();
26
24
  const { t } = useServerLanguage();
27
25
  const addButtonLabel = formatText(t('agentCreation.addButtonLabel'));
28
26
 
29
27
  const { isPreparingDialog, openNewAgentDialog, dialog } = useNewAgentDialog({
30
- onCreated: ({ targetPath }) => {
31
- router.push(targetPath);
32
- },
33
28
  onCreateFailed: async (error) => {
34
29
  console.error('Failed to create agent:', error);
35
30
  await showAlert({
@@ -8,6 +8,9 @@ import { DEFAULT_NAME_POOL, NAME_POOL_METADATA_KEY, parseNamePool } from '../con
8
8
  import { NEW_AGENT_WIZZARD_METADATA_KEY, parseNewAgentWizardMode } from '../constants/newAgentWizard';
9
9
  import { getMetadata } from '../database/getMetadata';
10
10
  import { $provideAgentCollectionForServer } from '../tools/$provideAgentCollectionForServer';
11
+ import { invalidateCachedActiveOrganizationSnapshots } from '../utils/agentOrganization/loadAgentOrganizationState';
12
+ import { resolveAgentRouteTarget } from '../utils/agentRouting/resolveAgentRouteTarget';
13
+ import { buildAgentChatHref, buildAgentProfileHref } from '../utils/agentRouting/agentRouteHrefs';
11
14
  import { type AgentVisibility, parseAgentVisibility } from '../utils/agentVisibility';
12
15
  import { authenticateUser } from '../utils/authenticateUser';
13
16
  import { createAgentWithDefaultVisibility } from '../utils/createAgentWithDefaultVisibility';
@@ -15,6 +18,16 @@ import { resolveCurrentUserIdentity } from '../utils/currentUserIdentity';
15
18
  import { isUserAdmin } from '../utils/isUserAdmin';
16
19
  import { clearSession, setSession } from '../utils/session';
17
20
 
21
+ /**
22
+ * Maximum attempts used to confirm a freshly created agent route resolves before navigation starts.
23
+ */
24
+ const CREATED_AGENT_ROUTE_READY_ATTEMPTS = 20;
25
+
26
+ /**
27
+ * Delay between created-agent route-resolution retries.
28
+ */
29
+ const CREATED_AGENT_ROUTE_READY_DELAY_MS = 100;
30
+
18
31
  /**
19
32
  * Creates a new agent from the generated boilerplate template.
20
33
  *
@@ -34,6 +47,8 @@ export async function $createAgentAction(): Promise<{ agentName: string_agent_na
34
47
  const { agentName, permanentId } = await createAgentWithDefaultVisibility(collection, agentSource, {
35
48
  userId: currentUserIdentity?.userId,
36
49
  });
50
+ revalidateCreatedAgentPaths(permanentId);
51
+ await waitForCreatedAgentRoute(permanentId);
37
52
 
38
53
  return { agentName, permanentId };
39
54
  }
@@ -63,6 +78,39 @@ export async function $getNewAgentCreationSettingsAction(): Promise<{
63
78
  };
64
79
  }
65
80
 
81
+ /**
82
+ * Clears cached organization snapshots and route payloads after a new agent is created.
83
+ *
84
+ * @param permanentId - Canonical identifier of the newly created agent.
85
+ */
86
+ function revalidateCreatedAgentPaths(permanentId: string_agent_permanent_id): void {
87
+ invalidateCachedActiveOrganizationSnapshots();
88
+ revalidatePath('/', 'layout');
89
+ revalidatePath('/');
90
+ revalidatePath('/agents');
91
+ revalidatePath('/dashboard');
92
+ revalidatePath(buildAgentProfileHref(permanentId));
93
+ revalidatePath(buildAgentChatHref(permanentId));
94
+ }
95
+
96
+ /**
97
+ * Waits until the new agent can be resolved by the same routing helper the chat page uses.
98
+ *
99
+ * @param permanentId - Canonical identifier of the newly created agent.
100
+ */
101
+ async function waitForCreatedAgentRoute(permanentId: string_agent_permanent_id): Promise<void> {
102
+ for (let attempt = 0; attempt < CREATED_AGENT_ROUTE_READY_ATTEMPTS; attempt++) {
103
+ const routeTarget = await resolveAgentRouteTarget(permanentId, { forceRefresh: true });
104
+ if (routeTarget?.kind === 'local' && routeTarget.canonicalAgentId === permanentId) {
105
+ return;
106
+ }
107
+
108
+ await new Promise((resolve) => setTimeout(resolve, CREATED_AGENT_ROUTE_READY_DELAY_MS));
109
+ }
110
+
111
+ throw new Error(`Created agent "${permanentId}" could not be resolved for routing immediately after creation.`);
112
+ }
113
+
66
114
  /**
67
115
  * Creates a new agent using provided book content.
68
116
  *
@@ -89,6 +137,8 @@ export async function $createAgentFromBookAction(
89
137
  visibility: visibility ?? undefined,
90
138
  userId: currentUserIdentity?.userId,
91
139
  });
140
+ revalidateCreatedAgentPaths(permanentId);
141
+ await waitForCreatedAgentRoute(permanentId);
92
142
 
93
143
  return { agentName, permanentId };
94
144
  }
@@ -1,8 +1,8 @@
1
- import { upload } from '@vercel/blob/client';
2
1
  import { useCallback, useRef, useState, type ChangeEvent } from 'react';
3
2
  import { showAlert } from '../../../components/AsyncDialogs/asyncDialogs';
4
3
  import { getSafeCdnPath } from '../../../utils/cdn/utils/getSafeCdnPath';
5
4
  import { normalizeUploadFilename } from '../../../utils/normalization/normalizeUploadFilename';
5
+ import { uploadFileToServer } from '../../../utils/upload/uploadFileToServer';
6
6
  import type { UseImageGeneratorTestState } from './useImageGeneratorTestState';
7
7
 
8
8
  /**
@@ -36,17 +36,22 @@ async function uploadImageAttachment(
36
36
  file: File,
37
37
  ): Promise<UseImageGeneratorTestState['prompts'][number]['attachments'][number]> {
38
38
  const normalizedFilename = normalizeUploadFilename(file.name);
39
- const uploadPath = getSafeCdnPath({ pathname: normalizedFilename });
40
- const blob = await upload(uploadPath, file, {
41
- access: 'public',
42
- handleUploadUrl: '/api/upload',
39
+ const uploadPath = getSafeCdnPath({
40
+ pathname: normalizedFilename,
41
+ pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX,
42
+ });
43
+ const uploadResult = await uploadFileToServer({
44
+ file,
45
+ pathname: uploadPath,
46
+ purpose: 'IMAGE_GENERATOR_TEST_ATTACHMENT',
47
+ contentType: file.type,
43
48
  });
44
49
 
45
50
  return {
46
51
  id: createAttachmentIdentifier(),
47
52
  name: file.name,
48
53
  type: file.type,
49
- url: blob.url,
54
+ url: uploadResult.url,
50
55
  };
51
56
  }
52
57
 
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { upload } from '@vercel/blob/client';
4
3
  import { FileTextIcon, HashIcon, ImageIcon, ListIcon, ShieldIcon, ToggleLeftIcon, TypeIcon, Upload } from 'lucide-react';
5
4
  import Link from 'next/link';
6
5
  import { Fragment, useEffect, useRef, useState } from 'react';
@@ -8,6 +7,7 @@ import { showConfirm } from '../../../components/AsyncDialogs/asyncDialogs';
8
7
  import { getMetadataDefinition, metadataDefaults, type MetadataDefinition } from '../../../database/metadataDefaults';
9
8
  import { getSafeCdnPath } from '../../../utils/cdn/utils/getSafeCdnPath';
10
9
  import { normalizeUploadFilename } from '../../../utils/normalization/normalizeUploadFilename';
10
+ import { buildDefaultUserFileUploadPath, uploadFileToServer } from '../../../utils/upload/uploadFileToServer';
11
11
  import { getDeprecatedLimitMetadataDefinition, type DeprecatedLimitMetadataDefinition } from '../../../constants/serverLimits';
12
12
 
13
13
  /**
@@ -502,23 +502,21 @@ export function MetadataClient() {
502
502
  try {
503
503
  setUploading(true);
504
504
 
505
- const pathPrefix = process.env.NEXT_PUBLIC_CDN_PATH_PREFIX || '';
506
505
  const normalizedFilename = normalizeUploadFilename(file.name);
507
- const uploadPath = pathPrefix
508
- ? `${pathPrefix}/user/files/${normalizedFilename}`
509
- : `user/files/${normalizedFilename}`;
510
- const safeUploadPath = getSafeCdnPath({ pathname: uploadPath });
511
-
512
- const blob = await upload(safeUploadPath, file, {
513
- access: 'public',
514
- handleUploadUrl: '/api/upload',
515
- clientPayload: JSON.stringify({
516
- purpose: formState.key || 'METADATA_IMAGE',
517
- contentType: file.type,
518
- }),
506
+ const uploadPath = buildDefaultUserFileUploadPath(normalizedFilename);
507
+ const safeUploadPath = getSafeCdnPath({
508
+ pathname: uploadPath,
509
+ pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX,
519
510
  });
520
511
 
521
- const fileUrl = blob.url;
512
+ const uploadResult = await uploadFileToServer({
513
+ file,
514
+ pathname: safeUploadPath,
515
+ purpose: formState.key || 'METADATA_IMAGE',
516
+ contentType: file.type,
517
+ });
518
+
519
+ const fileUrl = uploadResult.url;
522
520
 
523
521
  const LONG_URL = `${process.env.NEXT_PUBLIC_CDN_PUBLIC_URL!}/${process.env
524
522
  .NEXT_PUBLIC_CDN_PATH_PREFIX!}/user/files/`;
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
 
3
- import { upload } from '@vercel/blob/client';
4
3
  import { useCallback, useMemo, useRef, useState, type ChangeEvent, type RefObject } from 'react';
5
4
  import { showAlert } from '../../../components/AsyncDialogs/asyncDialogs';
6
5
  import { useDirtyModalGuard } from '../../../components/utils/useDirtyModalGuard';
@@ -8,6 +7,7 @@ import { buildServerTablePrefix } from '../../../utils/buildServerTablePrefix';
8
7
  import type { ChatFeedbackMode } from '../../../utils/chatFeedbackMode';
9
8
  import { getSafeCdnPath } from '../../../utils/cdn/utils/getSafeCdnPath';
10
9
  import { normalizeUploadFilename } from '../../../utils/normalization/normalizeUploadFilename';
10
+ import { buildDefaultUserFileUploadPath, uploadFileToServer } from '../../../utils/upload/uploadFileToServer';
11
11
  import type { ManagedServerEnvironment } from './useServersRegistryState';
12
12
 
13
13
  /**
@@ -425,22 +425,21 @@ export function useCreateServerWizard(options: UseCreateServerWizardOptions): Us
425
425
  setIsUploadingIcon(true);
426
426
  setWizardError(null);
427
427
 
428
- const pathPrefix = process.env.NEXT_PUBLIC_CDN_PATH_PREFIX || '';
429
428
  const normalizedFilename = normalizeUploadFilename(file.name);
430
- const uploadPath = pathPrefix
431
- ? `${pathPrefix}/user/files/${normalizedFilename}`
432
- : `user/files/${normalizedFilename}`;
433
-
434
- const blob = await upload(getSafeCdnPath({ pathname: uploadPath }), file, {
435
- access: 'public',
436
- handleUploadUrl: '/api/upload',
437
- clientPayload: JSON.stringify({
438
- purpose: 'SERVER_ICON',
439
- contentType: file.type,
440
- }),
429
+ const uploadPath = buildDefaultUserFileUploadPath(normalizedFilename);
430
+ const safeUploadPath = getSafeCdnPath({
431
+ pathname: uploadPath,
432
+ pathPrefix: process.env.NEXT_PUBLIC_CDN_PATH_PREFIX,
441
433
  });
442
434
 
443
- updateWizardField('iconUrl', blob.url);
435
+ const uploadResult = await uploadFileToServer({
436
+ file,
437
+ pathname: safeUploadPath,
438
+ purpose: 'SERVER_ICON',
439
+ contentType: file.type,
440
+ });
441
+
442
+ updateWizardField('iconUrl', uploadResult.url);
444
443
  } catch (uploadError) {
445
444
  setWizardError({
446
445
  message: uploadError instanceof Error ? uploadError.message : 'Failed to upload the server icon.',
@@ -4,7 +4,6 @@ import { usePromise } from '@common/hooks/usePromise';
4
4
  import { Chat } from '@promptbook-local/components';
5
5
  import { RemoteAgent } from '@promptbook-local/core';
6
6
  import { string_book, type ChatMessage } from '@promptbook-local/types';
7
- import { useRouter } from 'next/navigation';
8
7
  import { useCallback, useMemo, useState, type MouseEvent as ReactMouseEvent } from 'react';
9
8
  import { spaceTrim } from 'spacetrim';
10
9
  import { string_agent_url, string_color } from '../../../../../../src/types/typeAliases';
@@ -24,6 +23,7 @@ import { useServerLanguage } from '../../../components/ServerLanguage/ServerLang
24
23
  import { ChatThreadLoadingSkeleton } from '../../../components/Skeleton/ChatThreadLoadingSkeleton';
25
24
  import { usePromptbookTheme } from '../../../components/ThemeMode/usePromptbookTheme';
26
25
  import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
26
+ import { buildFreshAgentChatHref } from '../../../utils/agentRouting/agentRouteHrefs';
27
27
  import { executeQuickActionButton } from '../../../utils/chat/executeQuickActionButton';
28
28
  import { resolveChatMessageValidationIssue } from '../../../utils/chat/validateChatMessageContent';
29
29
  import { createServerLanguageMoment } from '../../../utils/localization/createServerLanguageMoment';
@@ -277,7 +277,6 @@ export function AgentProfileChat({
277
277
  isHistoryEnabled = false,
278
278
  areFileAttachmentsEnabled = true,
279
279
  }: AgentProfileChatProps) {
280
- const router = useRouter();
281
280
  const [isCreatingAgent, setIsCreatingAgent] = useState(false);
282
281
  const [optimisticNavigationState, setOptimisticNavigationState] = useState<OptimisticChatNavigationState | null>(null);
283
282
  const { formatText } = useAgentNaming();
@@ -409,7 +408,7 @@ export function AgentProfileChat({
409
408
  try {
410
409
  const { permanentId } = await $createAgentFromBookAction(bookContent as string_book);
411
410
  if (permanentId) {
412
- router.push(`/agents/${permanentId}`);
411
+ window.location.assign(buildFreshAgentChatHref(permanentId));
413
412
  }
414
413
  } catch (error) {
415
414
  console.error('Failed to create agent:', error);
@@ -421,7 +420,7 @@ export function AgentProfileChat({
421
420
  setIsCreatingAgent(false);
422
421
  }
423
422
  },
424
- [formatText, router],
423
+ [formatText],
425
424
  );
426
425
  const handleFileUpload = useCallback(async (file: File) => chatFileUploadHandler(file), []);
427
426
  const fallbackInitialMessage = useMemo(() => {
@@ -0,0 +1,18 @@
1
+ import { NextResponse } from 'next/server';
2
+
3
+ /**
4
+ * Ensures the readiness route runs in the same runtime as the standalone server.
5
+ */
6
+ export const runtime = 'nodejs';
7
+
8
+ /**
9
+ * Prevents a cached response from hiding readiness failures during deployment handoff.
10
+ */
11
+ export const dynamic = 'force-dynamic';
12
+
13
+ /**
14
+ * Lightweight readiness endpoint used by standalone VPS pm2/nginx handoffs.
15
+ */
16
+ export async function GET() {
17
+ return NextResponse.json({ status: 'ok' });
18
+ }