@promptbook/cli 0.112.0-95 → 0.112.0-97

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 (70) hide show
  1. package/apps/agents-server/README.md +3 -3
  2. package/apps/agents-server/next.config.ts +8 -1
  3. package/apps/agents-server/playwright.config.ts +4 -1
  4. package/apps/agents-server/src/app/admin/code-runners/CodeRunnersClient.tsx +358 -19
  5. package/apps/agents-server/src/app/admin/database/DatabaseAdminClient.tsx +38 -0
  6. package/apps/agents-server/src/app/admin/database/DatabaseAdminStudioSurface.tsx +42 -0
  7. package/apps/agents-server/src/app/admin/database/page.tsx +34 -0
  8. package/apps/agents-server/src/app/admin/servers/CreateServerDialog.tsx +46 -505
  9. package/apps/agents-server/src/app/admin/servers/ServersClient.tsx +23 -11
  10. package/apps/agents-server/src/app/admin/servers/ServersRegistryApi.ts +5 -0
  11. package/apps/agents-server/src/app/admin/servers/ServersRegistryDnsTypes.ts +87 -0
  12. package/apps/agents-server/src/app/admin/servers/ServersRegistryTable.tsx +258 -128
  13. package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +46 -334
  14. package/apps/agents-server/src/app/admin/servers/useServersRegistryState.ts +26 -2
  15. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +435 -0
  16. package/apps/agents-server/src/app/admin/update/page.tsx +14 -0
  17. package/apps/agents-server/src/app/api/admin/code-runners/authentication/route.ts +197 -0
  18. package/apps/agents-server/src/app/api/admin/code-runners/route.ts +4 -35
  19. package/apps/agents-server/src/app/api/admin/database/studio/route.ts +113 -0
  20. package/apps/agents-server/src/app/api/admin/servers/[serverId]/route.ts +10 -5
  21. package/apps/agents-server/src/app/api/admin/servers/route.ts +97 -6
  22. package/apps/agents-server/src/app/api/admin/update/route.ts +52 -0
  23. package/apps/agents-server/src/app/api/auth/login/route.ts +8 -0
  24. package/apps/agents-server/src/app/api/auth/logout/route.ts +10 -2
  25. package/apps/agents-server/src/app/layout.tsx +1 -0
  26. package/apps/agents-server/src/app/page.tsx +10 -0
  27. package/apps/agents-server/src/components/Header/buildHeaderSystemMenuItems.ts +10 -0
  28. package/apps/agents-server/src/database/$provideClientSql.ts +4 -21
  29. package/apps/agents-server/src/database/$provideDatabaseAdminExecutor.ts +252 -0
  30. package/apps/agents-server/src/database/$providePostgresPool.ts +27 -0
  31. package/apps/agents-server/src/database/$provideSupabaseForServer.ts +11 -1
  32. package/apps/agents-server/src/database/agentsServerDatabaseMode.ts +20 -1
  33. package/apps/agents-server/src/database/postgres/$provideLocalPostgresSupabase.ts +1261 -0
  34. package/apps/agents-server/src/database/resolvePostgresConnectionString.ts +26 -0
  35. package/apps/agents-server/src/database/sqlite/$provideAgentsServerSqliteDatabase.ts +83 -0
  36. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +20 -71
  37. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +2 -0
  38. package/apps/agents-server/src/languages/translations/czech.yaml +2 -0
  39. package/apps/agents-server/src/languages/translations/english.yaml +2 -0
  40. package/apps/agents-server/src/middleware.ts +32 -0
  41. package/apps/agents-server/src/tools/$provideServer.ts +2 -2
  42. package/apps/agents-server/src/utils/codeRunnerAuthentication.ts +394 -0
  43. package/apps/agents-server/src/utils/codeRunnerConfiguration.ts +67 -0
  44. package/apps/agents-server/src/utils/serverManagement/standaloneVpsServerMetadata.ts +145 -0
  45. package/apps/agents-server/src/utils/serverRegistry.ts +7 -6
  46. package/apps/agents-server/src/utils/session.ts +37 -9
  47. package/apps/agents-server/src/utils/shibboleth/createShibbolethAuthenticationLogPayload.ts +173 -0
  48. package/apps/agents-server/src/utils/shibboleth/writeShibbolethAuthenticationLog.ts +27 -0
  49. package/apps/agents-server/src/utils/standaloneVpsDnsDiagnostics.ts +258 -0
  50. package/apps/agents-server/src/utils/standaloneVpsRawIpBootstrap.ts +87 -0
  51. package/apps/agents-server/src/utils/vpsConfiguration.ts +87 -15
  52. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +664 -0
  53. package/esm/apps/agents-server/src/database/agentsServerDatabaseMode.d.ts +9 -1
  54. package/esm/apps/agents-server/src/utils/serverRegistry.d.ts +1 -1
  55. package/esm/index.es.js +8 -6
  56. package/esm/index.es.js.map +1 -1
  57. package/esm/src/version.d.ts +1 -1
  58. package/package.json +2 -1
  59. package/src/book-components/Chat/utils/renderMarkdown.ts +1 -3
  60. package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +1 -1
  61. package/src/other/templates/getTemplatesPipelineCollection.ts +767 -745
  62. package/src/scrapers/document/DocumentScraper.ts +1 -1
  63. package/src/scrapers/document-legacy/LegacyDocumentScraper.ts +1 -1
  64. package/src/version.ts +2 -2
  65. package/src/versions.txt +2 -1
  66. package/umd/apps/agents-server/src/database/agentsServerDatabaseMode.d.ts +9 -1
  67. package/umd/apps/agents-server/src/utils/serverRegistry.d.ts +1 -1
  68. package/umd/index.umd.js +8 -6
  69. package/umd/index.umd.js.map +1 -1
  70. package/umd/src/version.d.ts +1 -1
@@ -0,0 +1,26 @@
1
+ import spaceTrim from 'spacetrim';
2
+ import { DatabaseError } from '../../../../src/errors/DatabaseError';
3
+
4
+ /**
5
+ * Resolves the PostgreSQL connection string used by Supabase-backed Agents Server database access.
6
+ *
7
+ * @returns PostgreSQL connection string.
8
+ * @throws DatabaseError when neither supported environment variable is configured.
9
+ *
10
+ * @private exported from Agents Server database utilities
11
+ */
12
+ export function resolvePostgresConnectionString(): string {
13
+ const connectionString = process.env.POSTGRES_URL || process.env.DATABASE_URL;
14
+
15
+ if (!connectionString) {
16
+ throw new DatabaseError(
17
+ spaceTrim(`
18
+ Environment variable \`POSTGRES_URL\` or \`DATABASE_URL\` must be defined.
19
+
20
+ Configure one of these variables to use the Supabase/PostgreSQL database backend.
21
+ `),
22
+ );
23
+ }
24
+
25
+ return connectionString;
26
+ }
@@ -0,0 +1,83 @@
1
+ import { existsSync, mkdirSync } from 'fs';
2
+ import { dirname } from 'path';
3
+ import { resolveAgentsServerSqliteDatabasePath } from './resolveAgentsServerSqliteDatabasePath';
4
+
5
+ /**
6
+ * Shape of the `better-sqlite3` module constructor loaded at runtime.
7
+ *
8
+ * @private internal SQLite utility of Agents Server
9
+ */
10
+ export type BetterSqliteConstructor = new (path: string) => AgentsServerSqliteDatabase;
11
+
12
+ /**
13
+ * Minimal `better-sqlite3` database surface shared by Agents Server SQLite utilities.
14
+ *
15
+ * @private internal SQLite utility of Agents Server
16
+ */
17
+ export type AgentsServerSqliteDatabase = {
18
+ readonly pragma: (source: string) => unknown;
19
+ readonly exec: (source: string) => void;
20
+ readonly prepare: (source: string) => AgentsServerSqliteStatement;
21
+ readonly transaction: <TArguments extends ReadonlyArray<unknown>, TResult>(
22
+ fn: (...args: TArguments) => TResult,
23
+ ) => (...args: TArguments) => TResult;
24
+ readonly close?: () => void;
25
+ };
26
+
27
+ /**
28
+ * Minimal `better-sqlite3` prepared statement surface shared by Agents Server SQLite utilities.
29
+ *
30
+ * @private internal SQLite utility of Agents Server
31
+ */
32
+ export type AgentsServerSqliteStatement = {
33
+ readonly reader?: boolean;
34
+ readonly all: (...values: ReadonlyArray<unknown>) => Array<Record<string, unknown>>;
35
+ readonly get: (...values: ReadonlyArray<unknown>) => Record<string, unknown> | undefined;
36
+ readonly run: (...values: ReadonlyArray<unknown>) => {
37
+ readonly changes: number;
38
+ readonly lastInsertRowid: number | bigint;
39
+ };
40
+ };
41
+
42
+ /**
43
+ * Cached SQLite database connection.
44
+ */
45
+ let agentsServerSqliteDatabase: AgentsServerSqliteDatabase | null = null;
46
+
47
+ /**
48
+ * Opens and initializes the shared local SQLite database.
49
+ *
50
+ * @returns Shared SQLite database connection.
51
+ *
52
+ * @private exported from Agents Server SQLite utilities
53
+ */
54
+ export function $provideAgentsServerSqliteDatabase(): AgentsServerSqliteDatabase {
55
+ if (agentsServerSqliteDatabase) {
56
+ return agentsServerSqliteDatabase;
57
+ }
58
+
59
+ const databasePath = resolveAgentsServerSqliteDatabasePath();
60
+ const databaseDirectory = dirname(databasePath);
61
+
62
+ if (!existsSync(databaseDirectory)) {
63
+ mkdirSync(databaseDirectory, { recursive: true });
64
+ }
65
+
66
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
67
+ const BetterSqlite = require('better-sqlite3') as BetterSqliteConstructor;
68
+ agentsServerSqliteDatabase = new BetterSqlite(databasePath);
69
+ agentsServerSqliteDatabase.pragma('journal_mode = WAL');
70
+ agentsServerSqliteDatabase.pragma('foreign_keys = ON');
71
+
72
+ return agentsServerSqliteDatabase;
73
+ }
74
+
75
+ /**
76
+ * Closes the cached SQLite connection and resets adapter state for isolated tests.
77
+ *
78
+ * @private exported from Agents Server SQLite utilities
79
+ */
80
+ export function $resetAgentsServerSqliteDatabaseForTests(): void {
81
+ agentsServerSqliteDatabase?.close?.();
82
+ agentsServerSqliteDatabase = null;
83
+ }
@@ -1,8 +1,10 @@
1
- import { existsSync, mkdirSync } from 'fs';
2
- import { dirname } from 'path';
3
1
  import type { SupabaseClient } from '@supabase/supabase-js';
4
2
  import type { TODO_any } from '@promptbook-local/types';
5
- import { resolveAgentsServerSqliteDatabasePath } from './resolveAgentsServerSqliteDatabasePath';
3
+ import {
4
+ $provideAgentsServerSqliteDatabase,
5
+ $resetAgentsServerSqliteDatabaseForTests,
6
+ type AgentsServerSqliteDatabase,
7
+ } from './$provideAgentsServerSqliteDatabase';
6
8
 
7
9
  /**
8
10
  * Minimal query result shape consumed by Agents Server Supabase call sites.
@@ -63,33 +65,6 @@ type LocalSqliteUpsertOptions = {
63
65
  readonly onConflict?: string;
64
66
  };
65
67
 
66
- /**
67
- * Shape of the `better-sqlite3` module constructor loaded at runtime.
68
- */
69
- type BetterSqliteConstructor = new (path: string) => BetterSqliteDatabase;
70
-
71
- /**
72
- * Minimal `better-sqlite3` database surface used by this adapter.
73
- */
74
- type BetterSqliteDatabase = {
75
- readonly pragma: (source: string) => unknown;
76
- readonly exec: (source: string) => void;
77
- readonly prepare: (source: string) => BetterSqliteStatement;
78
- readonly close?: () => void;
79
- };
80
-
81
- /**
82
- * Minimal `better-sqlite3` prepared statement surface used by this adapter.
83
- */
84
- type BetterSqliteStatement = {
85
- readonly all: (...values: ReadonlyArray<unknown>) => Array<Record<string, unknown>>;
86
- readonly get: (...values: ReadonlyArray<unknown>) => Record<string, unknown> | undefined;
87
- readonly run: (...values: ReadonlyArray<unknown>) => {
88
- readonly changes: number;
89
- readonly lastInsertRowid: number | bigint;
90
- };
91
- };
92
-
93
68
  /**
94
69
  * Columns whose values are persisted as JSON text in local SQLite.
95
70
  */
@@ -170,11 +145,6 @@ const DEFAULT_UPSERT_CONFLICT_COLUMNS_BY_TABLE = new Map<string, ReadonlyArray<s
170
145
  ['ServerLimit', ['key']],
171
146
  ]);
172
147
 
173
- /**
174
- * Cached SQLite database connection.
175
- */
176
- let sqliteDatabase: BetterSqliteDatabase | null = null;
177
-
178
148
  /**
179
149
  * Cached Supabase-shaped local client.
180
150
  */
@@ -188,7 +158,7 @@ export function $provideLocalSqliteSupabase(): SupabaseClient {
188
158
  return localSqliteSupabase;
189
159
  }
190
160
 
191
- localSqliteSupabase = new LocalSqliteSupabaseClient(getSqliteDatabase()) as unknown as SupabaseClient;
161
+ localSqliteSupabase = new LocalSqliteSupabaseClient($provideAgentsServerSqliteDatabase()) as unknown as SupabaseClient;
192
162
  return localSqliteSupabase;
193
163
  }
194
164
 
@@ -196,40 +166,15 @@ export function $provideLocalSqliteSupabase(): SupabaseClient {
196
166
  * Closes the cached SQLite connection and resets adapter state for isolated tests.
197
167
  */
198
168
  export function $resetLocalSqliteSupabaseForTests(): void {
199
- sqliteDatabase?.close?.();
200
- sqliteDatabase = null;
169
+ $resetAgentsServerSqliteDatabaseForTests();
201
170
  localSqliteSupabase = null;
202
171
  }
203
172
 
204
- /**
205
- * Opens and initializes the shared local SQLite database.
206
- */
207
- function getSqliteDatabase(): BetterSqliteDatabase {
208
- if (sqliteDatabase) {
209
- return sqliteDatabase;
210
- }
211
-
212
- const databasePath = resolveAgentsServerSqliteDatabasePath();
213
- const databaseDirectory = dirname(databasePath);
214
-
215
- if (!existsSync(databaseDirectory)) {
216
- mkdirSync(databaseDirectory, { recursive: true });
217
- }
218
-
219
- // eslint-disable-next-line @typescript-eslint/no-var-requires
220
- const BetterSqlite = require('better-sqlite3') as BetterSqliteConstructor;
221
- sqliteDatabase = new BetterSqlite(databasePath);
222
- sqliteDatabase.pragma('journal_mode = WAL');
223
- sqliteDatabase.pragma('foreign_keys = ON');
224
-
225
- return sqliteDatabase;
226
- }
227
-
228
173
  /**
229
174
  * Supabase-shaped client with only the table query surface used by Agents Server.
230
175
  */
231
176
  class LocalSqliteSupabaseClient {
232
- public constructor(private readonly database: BetterSqliteDatabase) {}
177
+ public constructor(private readonly database: AgentsServerSqliteDatabase) {}
233
178
 
234
179
  /**
235
180
  * Starts a query for one SQLite table.
@@ -244,7 +189,7 @@ class LocalSqliteSupabaseClient {
244
189
  */
245
190
  class LocalSqliteTable {
246
191
  public constructor(
247
- private readonly database: BetterSqliteDatabase,
192
+ private readonly database: AgentsServerSqliteDatabase,
248
193
  private readonly tableName: string,
249
194
  ) {}
250
195
 
@@ -304,7 +249,7 @@ class LocalSqliteQueryBuilder implements PromiseLike<LocalSqliteQueryResult> {
304
249
  private isReturningSelection = false;
305
250
 
306
251
  public constructor(
307
- private readonly database: BetterSqliteDatabase,
252
+ private readonly database: AgentsServerSqliteDatabase,
308
253
  private readonly tableName: string,
309
254
  ) {}
310
255
 
@@ -851,7 +796,11 @@ type ParsedPostgrestFilter = {
851
796
  /**
852
797
  * Ensures a table and all required columns exist.
853
798
  */
854
- function ensureTable(database: BetterSqliteDatabase, tableName: string, requiredColumns: ReadonlyArray<string>): void {
799
+ function ensureTable(
800
+ database: AgentsServerSqliteDatabase,
801
+ tableName: string,
802
+ requiredColumns: ReadonlyArray<string>,
803
+ ): void {
855
804
  const tableBaseName = resolveTableBaseName(tableName);
856
805
  const primaryKey = TEXT_PRIMARY_KEY_TABLES.has(tableBaseName)
857
806
  ? '"id" TEXT PRIMARY KEY'
@@ -886,7 +835,7 @@ function ensureTable(database: BetterSqliteDatabase, tableName: string, required
886
835
  /**
887
836
  * Creates known unique indexes after required columns exist.
888
837
  */
889
- function ensureUniqueIndexes(database: BetterSqliteDatabase, tableName: string, tableBaseName: string): void {
838
+ function ensureUniqueIndexes(database: AgentsServerSqliteDatabase, tableName: string, tableBaseName: string): void {
890
839
  const uniqueIndexes = UNIQUE_INDEX_COLUMNS_BY_TABLE.get(tableBaseName) || [];
891
840
 
892
841
  for (const columns of uniqueIndexes) {
@@ -900,7 +849,7 @@ function ensureUniqueIndexes(database: BetterSqliteDatabase, tableName: string,
900
849
  * Inserts one row into the table.
901
850
  */
902
851
  function insertRow(
903
- database: BetterSqliteDatabase,
852
+ database: AgentsServerSqliteDatabase,
904
853
  tableName: string,
905
854
  row: Record<string, unknown>,
906
855
  ): { readonly lastInsertRowid: number | bigint } {
@@ -921,7 +870,7 @@ function insertRow(
921
870
  * Updates one row by SQLite rowid.
922
871
  */
923
872
  function updateRowid(
924
- database: BetterSqliteDatabase,
873
+ database: AgentsServerSqliteDatabase,
925
874
  tableName: string,
926
875
  rowid: number | bigint,
927
876
  row: Record<string, unknown>,
@@ -940,7 +889,7 @@ function updateRowid(
940
889
  * Finds the rowid matching an upsert conflict target.
941
890
  */
942
891
  function findConflictRowid(
943
- database: BetterSqliteDatabase,
892
+ database: AgentsServerSqliteDatabase,
944
893
  tableName: string,
945
894
  row: Record<string, unknown>,
946
895
  conflictColumns: ReadonlyArray<string>,
@@ -960,7 +909,7 @@ function findConflictRowid(
960
909
  * Selects rows by rowids for a mutation returning clause.
961
910
  */
962
911
  function selectRowsByRowids(
963
- database: BetterSqliteDatabase,
912
+ database: AgentsServerSqliteDatabase,
964
913
  tableName: string,
965
914
  rowids: ReadonlyArray<number | bigint>,
966
915
  selectedColumns: ReadonlyArray<string>,
@@ -142,6 +142,8 @@ export const SERVER_TRANSLATION_KEYS = [
142
142
  'header.createNewUser',
143
143
  'header.servers',
144
144
  'header.environmentVariables',
145
+ 'header.update',
146
+ 'header.database',
145
147
  'header.logs',
146
148
  'header.codeRunners',
147
149
  'header.models',
@@ -136,6 +136,8 @@ header.viewAllUsers: Zobrazit všechny uživatele
136
136
  header.createNewUser: Vytvořit nového uživatele
137
137
  header.servers: Servery
138
138
  header.environmentVariables: Proměnné prostředí
139
+ header.update: Aktualizace
140
+ header.database: Databáze
139
141
  header.logs: Logy
140
142
  header.codeRunners: Code runnery
141
143
  header.models: Modely
@@ -138,6 +138,8 @@ header.viewAllUsers: View all users
138
138
  header.createNewUser: Create new user
139
139
  header.servers: Servers
140
140
  header.environmentVariables: Environment variables
141
+ header.update: Update
142
+ header.database: Database
141
143
  header.logs: Logs
142
144
  header.codeRunners: Code runners
143
145
  header.models: Models
@@ -3,6 +3,7 @@ import { applyVisibilityHeaders } from './middleware/applyVisibilityHeaders';
3
3
  import { createMiddlewareRequestContext } from './middleware/createMiddlewareRequestContext';
4
4
  import { resolveAccessControlResponse } from './middleware/resolveAccessControlResponse';
5
5
  import { resolveMiddlewareResponse } from './middleware/resolveMiddlewareResponse';
6
+ import { writeShibbolethAuthenticationLog } from './utils/shibboleth/writeShibbolethAuthenticationLog';
6
7
 
7
8
  /**
8
9
  * Main Next.js middleware coordinating request context loading, access control,
@@ -12,6 +13,15 @@ import { resolveMiddlewareResponse } from './middleware/resolveMiddlewareRespons
12
13
  * @returns Middleware response.
13
14
  */
14
15
  export async function middleware(request: NextRequest): Promise<NextResponse> {
16
+ if (shouldLogShibbolethRequestFromMiddleware(request)) {
17
+ writeShibbolethAuthenticationLog(request.headers, {
18
+ event: 'middleware-request',
19
+ pathname: request.nextUrl.pathname,
20
+ method: request.method,
21
+ hasSessionCookie: request.cookies.has('sessionToken'),
22
+ });
23
+ }
24
+
15
25
  const middlewareRequestContext = await createMiddlewareRequestContext(request);
16
26
  const applyResponseHeaders = async (response: NextResponse): Promise<void> => {
17
27
  await applyVisibilityHeaders({
@@ -58,3 +68,25 @@ export const config = {
58
68
  '/((?!_next/static|_next/image|favicon.ico|logo-|fonts/|robots.txt|api/internal).*)',
59
69
  ],
60
70
  };
71
+
72
+ /**
73
+ * Decides whether the current middleware request should emit Shibboleth diagnostics.
74
+ *
75
+ * We log the first anonymous request plus explicit auth/SAML routes so standalone VPS
76
+ * pm2 logs show the incoming Shibboleth attributes without flooding every authenticated
77
+ * page load once the browser already carries a session cookie.
78
+ *
79
+ * @param request - Incoming middleware request.
80
+ * @returns `true` when the request is useful for Shibboleth diagnostics.
81
+ */
82
+ function shouldLogShibbolethRequestFromMiddleware(request: NextRequest): boolean {
83
+ const pathname = request.nextUrl.pathname.toLowerCase();
84
+ const isAuthenticationPath = pathname.startsWith('/api/auth');
85
+ const isShibbolethPath = pathname.includes('shibboleth') || pathname.includes('saml');
86
+
87
+ if (isAuthenticationPath || isShibbolethPath) {
88
+ return true;
89
+ }
90
+
91
+ return !request.cookies.has('sessionToken');
92
+ }
@@ -1,7 +1,7 @@
1
1
  import { NEXT_PUBLIC_SITE_URL, SUPABASE_TABLE_PREFIX } from '@/config';
2
2
  import { headers } from 'next/headers';
3
3
  import { cache } from 'react';
4
- import { isAgentsServerSqliteMode } from '../database/agentsServerDatabaseMode';
4
+ import { isAgentsServerStandaloneMode } from '../database/agentsServerDatabaseMode';
5
5
  import { resolveInternalServerOrigin } from '../utils/resolveInternalServerOrigin';
6
6
  import { createServerPublicUrl, listRegisteredServersUsingServiceRole } from '../utils/serverRegistry';
7
7
  import { resolveServerSelection } from '../utils/serverSelection';
@@ -37,7 +37,7 @@ const getCachedProvidedServer = cache(async (): Promise<ProvidedServer> => {
37
37
  const requestHost = headersList.get('host');
38
38
  const xPromptbookServer = headersList.get('x-promptbook-server');
39
39
 
40
- if (isAgentsServerSqliteMode()) {
40
+ if (isAgentsServerStandaloneMode()) {
41
41
  if (isLocalDevelopmentHost(requestHost)) {
42
42
  return {
43
43
  id: null,