@promptbook/cli 0.112.0-135 → 0.112.0-137

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 (64) hide show
  1. package/README.md +20 -0
  2. package/apps/agents-server/README.md +0 -1
  3. package/apps/agents-server/src/app/admin/metadata/MetadataClient.tsx +246 -15
  4. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +237 -4
  5. package/apps/agents-server/src/app/api/admin/update/log/route.ts +42 -0
  6. package/apps/agents-server/src/app/api/agents/export/route.ts +41 -0
  7. package/apps/agents-server/src/app/api/agents/import/route.ts +168 -0
  8. package/apps/agents-server/src/app/api/federated-agents/route.ts +1 -1
  9. package/apps/agents-server/src/app/api/internal/agent-runner-limits/route.ts +2 -1
  10. package/apps/agents-server/src/app/api/internal/user-chat-jobs/run/route.ts +2 -1
  11. package/apps/agents-server/src/app/api/metadata/export/route.ts +34 -0
  12. package/apps/agents-server/src/app/api/metadata/import/route.ts +46 -0
  13. package/apps/agents-server/src/app/layout.tsx +1 -1
  14. package/apps/agents-server/src/components/Homepage/AgentsList.tsx +31 -1
  15. package/apps/agents-server/src/components/Homepage/AgentsListHeader.tsx +60 -1
  16. package/apps/agents-server/src/components/Homepage/useAgentsListImportExportState.ts +523 -0
  17. package/apps/agents-server/src/components/Homepage/useAgentsListState.ts +16 -0
  18. package/apps/agents-server/src/database/metadataDefaults.ts +0 -21
  19. package/apps/agents-server/src/database/seedCoreAgents.ts +235 -0
  20. package/apps/agents-server/src/database/seedDefaultAgents.ts +32 -1
  21. package/apps/agents-server/src/search/createDefaultServerSearchProviders/createFederatedAgentsSearchProvider.ts +1 -1
  22. package/apps/agents-server/src/tools/$provideAgentCollectionForServer.ts +2 -9
  23. package/apps/agents-server/src/utils/agentsTransfer/createAgentsExportZipStream.ts +68 -0
  24. package/apps/agents-server/src/utils/agentsTransfer/importAgentsFromFiles.ts +852 -0
  25. package/apps/agents-server/src/utils/backup/createBooksBackupZipStream.ts +15 -2
  26. package/apps/agents-server/src/utils/defaultAgents/loadDefaultAgentBooks.ts +46 -4
  27. package/apps/agents-server/src/utils/getFederatedServers.ts +3 -74
  28. package/apps/agents-server/src/utils/getWellKnownAgentUrl.ts +10 -4
  29. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +1 -1
  30. package/apps/agents-server/src/utils/metadataConfigurationTransfer.ts +426 -0
  31. package/apps/agents-server/src/utils/serverManagement/createManagedServer/bootstrapManagedServer.ts +2 -5
  32. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +162 -0
  33. package/apps/agents-server/src/utils/session.ts +2 -1
  34. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +110 -0
  35. package/esm/index.es.js +1 -1
  36. package/esm/index.es.js.map +1 -1
  37. package/esm/src/_packages/core.index.d.ts +0 -2
  38. package/esm/src/utils/isTimingSafeEqualString.d.ts +25 -0
  39. package/esm/src/version.d.ts +1 -1
  40. package/package.json +1 -1
  41. package/servers.ts +1 -16
  42. package/src/_packages/core.index.ts +0 -2
  43. package/src/commitments/_common/teamInternalAgentAccess.ts +2 -1
  44. package/src/other/templates/getTemplatesPipelineCollection.ts +789 -716
  45. package/src/utils/isTimingSafeEqualString.ts +43 -0
  46. package/src/version.ts +2 -2
  47. package/src/versions.txt +2 -0
  48. package/umd/index.umd.js +1 -1
  49. package/umd/index.umd.js.map +1 -1
  50. package/umd/src/_packages/core.index.d.ts +0 -2
  51. package/umd/src/utils/isTimingSafeEqualString.d.ts +25 -0
  52. package/umd/src/version.d.ts +1 -1
  53. package/apps/agents-server/src/utils/defaultFederatedAgents/DefaultFederatedAgentsSyncOptions.ts +0 -9
  54. package/apps/agents-server/src/utils/defaultFederatedAgents/ensureDefaultFederatedAgentExists.ts +0 -277
  55. package/apps/agents-server/src/utils/defaultFederatedAgents/fetchCoreOrganizationPayload.ts +0 -39
  56. package/apps/agents-server/src/utils/defaultFederatedAgents/fetchFederatedAgentBook.ts +0 -43
  57. package/apps/agents-server/src/utils/defaultFederatedAgents/fetchWithDefaultFederatedAgentTimeout.ts +0 -28
  58. package/apps/agents-server/src/utils/defaultFederatedAgents/getDefaultFederatedAgentSyncPool.ts +0 -38
  59. package/apps/agents-server/src/utils/defaultFederatedAgents/loadActiveLocalAgentIdsByNormalizedName.ts +0 -41
  60. package/apps/agents-server/src/utils/defaultFederatedAgents/loadDefaultFederatedAgentSyncMetadata.ts +0 -76
  61. package/apps/agents-server/src/utils/defaultFederatedAgents/quoteIdentifier.ts +0 -11
  62. package/apps/agents-server/src/utils/defaultFederatedAgents/scheduleDefaultFederatedAgentsSync.ts +0 -88
  63. package/apps/agents-server/src/utils/defaultFederatedAgents/selectDefaultFederatedAgentsFromOrganizationPayload.ts +0 -181
  64. package/apps/agents-server/src/utils/defaultFederatedAgents/synchronizeDefaultFederatedAgents.ts +0 -77
@@ -0,0 +1,162 @@
1
+ import type { Client } from 'pg';
2
+ import { createAgentPersistenceRecords } from '../../../../../../src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords';
3
+ import { DEFAULT_AGENT_VISIBILITY } from '../../agentVisibility';
4
+ import { CORE_AGENT_DIRECTORY_NAME, loadCoreAgentBooks } from '../../defaultAgents/loadDefaultAgentBooks';
5
+ import { createInsertStatement, quoteIdentifier, type SqlRecorder } from './createSqlRecorder';
6
+ import type { NormalizedCreateServerInput } from './normalizeCreateServerInput';
7
+
8
+ /**
9
+ * Loads bundled `.core` agent books from the repository and persists them into the newly created server.
10
+ *
11
+ * Each `*.book` file in `agents/default/.core` becomes one persisted agent in the `.core` folder with its initial
12
+ * history snapshot.
13
+ *
14
+ * @param client - Connected PostgreSQL client inside the bootstrap transaction.
15
+ * @param input - Normalized create-server payload.
16
+ * @param sqlRecorder - Mutable SQL dump recorder.
17
+ *
18
+ * @private function of createManagedServer
19
+ */
20
+ export async function seedServerCoreAgents(
21
+ client: Client,
22
+ input: NormalizedCreateServerInput,
23
+ sqlRecorder: SqlRecorder,
24
+ ): Promise<void> {
25
+ const coreAgentBooks = await loadCoreAgentBooks();
26
+ if (coreAgentBooks.length === 0) {
27
+ return;
28
+ }
29
+
30
+ const coreFolderId = await insertCoreFolder(client, input, sqlRecorder);
31
+ const agentTableIdentifier = quoteIdentifier(`${input.tablePrefix}Agent`);
32
+ const agentHistoryTableIdentifier = quoteIdentifier(`${input.tablePrefix}AgentHistory`);
33
+
34
+ for (const [index, coreAgentBook] of coreAgentBooks.entries()) {
35
+ const createdAt = new Date().toISOString();
36
+ const { agentInsertRecord, agentHistoryInsertRecord } = createAgentPersistenceRecords(
37
+ coreAgentBook,
38
+ { folderId: coreFolderId, sortOrder: index, visibility: DEFAULT_AGENT_VISIBILITY },
39
+ createdAt,
40
+ );
41
+
42
+ await client.query(
43
+ `
44
+ INSERT INTO ${agentTableIdentifier} (
45
+ "agentName",
46
+ "createdAt",
47
+ "updatedAt",
48
+ "permanentId",
49
+ "agentHash",
50
+ "agentSource",
51
+ "agentProfile",
52
+ "promptbookEngineVersion",
53
+ "usage",
54
+ "folderId",
55
+ "sortOrder",
56
+ "visibility"
57
+ )
58
+ VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8, $9::jsonb, $10, $11, $12)
59
+ `,
60
+ [
61
+ agentInsertRecord.agentName,
62
+ agentInsertRecord.createdAt,
63
+ agentInsertRecord.updatedAt,
64
+ agentInsertRecord.permanentId,
65
+ agentInsertRecord.agentHash,
66
+ agentInsertRecord.agentSource,
67
+ JSON.stringify(agentInsertRecord.agentProfile),
68
+ agentInsertRecord.promptbookEngineVersion,
69
+ JSON.stringify(agentInsertRecord.usage),
70
+ coreFolderId,
71
+ agentInsertRecord.sortOrder ?? index,
72
+ agentInsertRecord.visibility ?? DEFAULT_AGENT_VISIBILITY,
73
+ ],
74
+ );
75
+ sqlRecorder.addStatement(
76
+ createInsertStatement(`${input.tablePrefix}Agent`, {
77
+ ...agentInsertRecord,
78
+ agentProfile: JSON.stringify(agentInsertRecord.agentProfile),
79
+ usage: JSON.stringify(agentInsertRecord.usage),
80
+ folderId: coreFolderId,
81
+ sortOrder: agentInsertRecord.sortOrder ?? index,
82
+ visibility: agentInsertRecord.visibility ?? DEFAULT_AGENT_VISIBILITY,
83
+ }),
84
+ );
85
+
86
+ await client.query(
87
+ `
88
+ INSERT INTO ${agentHistoryTableIdentifier} (
89
+ "createdAt",
90
+ "agentName",
91
+ "permanentId",
92
+ "agentHash",
93
+ "previousAgentHash",
94
+ "agentSource",
95
+ "promptbookEngineVersion",
96
+ "versionName"
97
+ )
98
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
99
+ `,
100
+ [
101
+ agentHistoryInsertRecord.createdAt,
102
+ agentHistoryInsertRecord.agentName,
103
+ agentHistoryInsertRecord.permanentId,
104
+ agentHistoryInsertRecord.agentHash,
105
+ agentHistoryInsertRecord.previousAgentHash,
106
+ agentHistoryInsertRecord.agentSource,
107
+ agentHistoryInsertRecord.promptbookEngineVersion,
108
+ agentHistoryInsertRecord.versionName,
109
+ ],
110
+ );
111
+ sqlRecorder.addStatement(createInsertStatement(`${input.tablePrefix}AgentHistory`, agentHistoryInsertRecord));
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Inserts the `.core` folder row for the newly bootstrapped server.
117
+ *
118
+ * @param client - Connected PostgreSQL client inside the bootstrap transaction.
119
+ * @param input - Normalized create-server payload.
120
+ * @param sqlRecorder - Mutable SQL dump recorder.
121
+ * @returns Identifier of the inserted `.core` folder.
122
+ *
123
+ * @private function of createManagedServer
124
+ */
125
+ async function insertCoreFolder(
126
+ client: Client,
127
+ input: NormalizedCreateServerInput,
128
+ sqlRecorder: SqlRecorder,
129
+ ): Promise<number> {
130
+ const agentFolderTableIdentifier = quoteIdentifier(`${input.tablePrefix}AgentFolder`);
131
+ const createdAt = new Date().toISOString();
132
+ const insertResult = await client.query<{ id: number }>(
133
+ `
134
+ INSERT INTO ${agentFolderTableIdentifier} (
135
+ "name",
136
+ "parentId",
137
+ "sortOrder",
138
+ "icon",
139
+ "color",
140
+ "createdAt",
141
+ "updatedAt"
142
+ )
143
+ VALUES ($1, NULL, $2, NULL, NULL, $3, NULL)
144
+ RETURNING "id"
145
+ `,
146
+ [CORE_AGENT_DIRECTORY_NAME, 0, createdAt],
147
+ );
148
+
149
+ sqlRecorder.addStatement(
150
+ createInsertStatement(`${input.tablePrefix}AgentFolder`, {
151
+ name: CORE_AGENT_DIRECTORY_NAME,
152
+ parentId: null,
153
+ sortOrder: 0,
154
+ icon: null,
155
+ color: null,
156
+ createdAt,
157
+ updatedAt: null,
158
+ }),
159
+ );
160
+
161
+ return insertResult.rows[0].id;
162
+ }
@@ -3,6 +3,7 @@ import { cookies, headers } from 'next/headers';
3
3
  import { cache } from 'react';
4
4
  import { spaceTrim } from 'spacetrim';
5
5
  import { EnvironmentMismatchError } from '../../../../src/errors/EnvironmentMismatchError';
6
+ import { isTimingSafeEqualString } from '../../../../src/utils/isTimingSafeEqualString';
6
7
  import { isStandaloneVpsRawIpBootstrapActive } from './standaloneVpsRawIpBootstrap';
7
8
 
8
9
  /**
@@ -153,7 +154,7 @@ export function parseSessionToken(token: string | null | undefined): SessionUser
153
154
  const payload = Buffer.from(payloadBase64, 'base64').toString('utf-8');
154
155
  const expectedSignature = createHmac('sha256', getSessionSigningKey()).update(payload).digest('hex');
155
156
 
156
- if (signature !== expectedSignature) {
157
+ if (!isTimingSafeEqualString(signature, expectedSignature)) {
157
158
  return null;
158
159
  }
159
160
 
@@ -207,6 +207,10 @@ export type VpsSelfUpdateOverview = {
207
207
  * Number of commits the deployed checkout is behind the latest remote commit, or `null` when unknown.
208
208
  */
209
209
  readonly commitsBehindCount: number | null;
210
+ /**
211
+ * Commits that the deployed checkout is behind the latest remote commit (newest first).
212
+ */
213
+ readonly pendingCommits: ReadonlyArray<VpsSelfUpdatePendingCommit>;
210
214
  /**
211
215
  * Whether the remote branch contains a newer commit than the deployed checkout.
212
216
  */
@@ -465,6 +469,10 @@ export async function readVpsSelfUpdateOverview(): Promise<VpsSelfUpdateOverview
465
469
  currentCommitSha && latestRemoteCommitSha
466
470
  ? await countCommitsBetween(repositoryDirectory, currentCommitSha, latestRemoteCommitSha)
467
471
  : null;
472
+ const pendingCommits =
473
+ currentCommitSha && latestRemoteCommitSha
474
+ ? await listCommitsBetween(repositoryDirectory, currentCommitSha, latestRemoteCommitSha)
475
+ : [];
468
476
  const resolvedJob = resolveVpsSelfUpdateJobForOverview(job, {
469
477
  currentEnvironment,
470
478
  currentCommitSha,
@@ -484,6 +492,7 @@ export async function readVpsSelfUpdateOverview(): Promise<VpsSelfUpdateOverview
484
492
  latestRemoteCommitShortSha: abbreviateCommitSha(latestRemoteCommitSha),
485
493
  latestRemoteCommitDate,
486
494
  commitsBehindCount,
495
+ pendingCommits,
487
496
  isUpdateAvailable: Boolean(
488
497
  currentCommitSha && latestRemoteCommitSha && currentCommitSha !== latestRemoteCommitSha,
489
498
  ),
@@ -494,6 +503,33 @@ export async function readVpsSelfUpdateOverview(): Promise<VpsSelfUpdateOverview
494
503
  };
495
504
  }
496
505
 
506
+ /**
507
+ * Browser-safe summary of one commit that the deployed checkout is behind the latest remote commit.
508
+ */
509
+ export type VpsSelfUpdatePendingCommit = {
510
+ /**
511
+ * Full commit hash.
512
+ */
513
+ readonly commitSha: string;
514
+ /**
515
+ * Short commit hash (first 7 chars).
516
+ */
517
+ readonly shortCommitSha: string;
518
+ /**
519
+ * Single-line commit subject.
520
+ */
521
+ readonly subject: string;
522
+ /**
523
+ * Author timestamp in ISO format or `null` when unknown.
524
+ */
525
+ readonly authoredAt: string | null;
526
+ };
527
+
528
+ /**
529
+ * Hard ceiling for the pending-commits listing returned in the overview to avoid huge payloads on a long-stale server.
530
+ */
531
+ const VPS_SELF_UPDATE_MAX_PENDING_COMMITS = 100;
532
+
497
533
  /**
498
534
  * Browser-safe summary of one commit that the super admin can pick from the custom-target picker.
499
535
  */
@@ -790,6 +826,7 @@ function createUnavailableOverview(context: {
790
826
  latestRemoteCommitShortSha: null,
791
827
  latestRemoteCommitDate: null,
792
828
  commitsBehindCount: null,
829
+ pendingCommits: [],
793
830
  isUpdateAvailable: false,
794
831
  originRepositoryUrl: context.originRepositoryUrl,
795
832
  isOriginRepositoryDefault: context.originRepositoryUrl === VPS_SELF_UPDATE_DEFAULT_ORIGIN_REPOSITORY_URL,
@@ -1205,6 +1242,79 @@ async function countCommitsBetween(
1205
1242
  return Number.isFinite(parsedCount) ? parsedCount : null;
1206
1243
  }
1207
1244
 
1245
+ /**
1246
+ * Lists commits that separate two commits in the local repository so the admin UI can show subject/hash/date for each one.
1247
+ *
1248
+ * Returns an empty list when either commit cannot be resolved (typical for a shallow clone that has not been deepened yet)
1249
+ * or when both commits are identical.
1250
+ *
1251
+ * @param repositoryDirectory - Repository checkout path.
1252
+ * @param fromCommitSha - Older commit hash (deployed commit).
1253
+ * @param toCommitSha - Newer commit hash (latest remote commit).
1254
+ * @returns Browser-safe pending-commit list (newest first).
1255
+ */
1256
+ async function listCommitsBetween(
1257
+ repositoryDirectory: string,
1258
+ fromCommitSha: string,
1259
+ toCommitSha: string,
1260
+ ): Promise<ReadonlyArray<VpsSelfUpdatePendingCommit>> {
1261
+ if (fromCommitSha === toCommitSha) {
1262
+ return [];
1263
+ }
1264
+
1265
+ const output = await runGitInRepository(repositoryDirectory, [
1266
+ 'log',
1267
+ `--max-count=${VPS_SELF_UPDATE_MAX_PENDING_COMMITS}`,
1268
+ `--format=%H${GIT_LOG_FIELD_SEPARATOR}%aI${GIT_LOG_FIELD_SEPARATOR}%s`,
1269
+ `${fromCommitSha}..${toCommitSha}`,
1270
+ ]);
1271
+ if (!output) {
1272
+ return [];
1273
+ }
1274
+
1275
+ const pendingCommits: Array<VpsSelfUpdatePendingCommit> = [];
1276
+ for (const line of output.split('\n')) {
1277
+ if (!line) {
1278
+ continue;
1279
+ }
1280
+
1281
+ const fields = line.split(GIT_LOG_FIELD_SEPARATOR);
1282
+ const commitSha = fields[0] ?? '';
1283
+ if (!commitSha) {
1284
+ continue;
1285
+ }
1286
+
1287
+ const authoredAt = fields[1] || null;
1288
+ const subject = fields.slice(2).join(GIT_LOG_FIELD_SEPARATOR);
1289
+
1290
+ pendingCommits.push({
1291
+ commitSha,
1292
+ shortCommitSha: commitSha.slice(0, 7),
1293
+ subject,
1294
+ authoredAt,
1295
+ });
1296
+ }
1297
+
1298
+ return pendingCommits;
1299
+ }
1300
+
1301
+ /**
1302
+ * Reads the full persisted standalone VPS self-update log so the super admin can copy/download it for debugging.
1303
+ *
1304
+ * @returns Log file content or `null` when the file does not exist yet.
1305
+ */
1306
+ export async function readVpsSelfUpdateLogFileContent(): Promise<string | null> {
1307
+ const logFilePath = resolveVpsSelfUpdateLogFilePath();
1308
+ try {
1309
+ return await readFile(logFilePath, 'utf-8');
1310
+ } catch (error) {
1311
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
1312
+ return null;
1313
+ }
1314
+ throw error;
1315
+ }
1316
+ }
1317
+
1208
1318
  /**
1209
1319
  * Checks whether a detached update process is still alive.
1210
1320
  *
package/esm/index.es.js CHANGED
@@ -59,7 +59,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
59
59
  * @generated
60
60
  * @see https://github.com/webgptorg/promptbook
61
61
  */
62
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-135';
62
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-137';
63
63
  /**
64
64
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
65
65
  * Note: [💞] Ignore a discrepancy between file name and entity name