@promptbook/cli 0.112.0-111 → 0.112.0-113
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/apps/agents-server/README.md +1 -1
- package/apps/agents-server/next.config.ts +20 -1
- package/apps/agents-server/src/app/admin/servers/CreateServerDialog.tsx +16 -0
- package/apps/agents-server/src/app/admin/servers/useCreateServerWizard.ts +31 -5
- package/apps/agents-server/src/app/api/admin/code-runners/route.ts +1 -1
- package/apps/agents-server/src/app/api/admin/servers/route.ts +5 -0
- package/apps/agents-server/src/app/api/internal/user-chat-jobs/run/route.ts +1 -1
- package/apps/agents-server/src/app/api/metadata/route.ts +4 -0
- package/apps/agents-server/src/database/customJavascript.ts +62 -1
- package/apps/agents-server/src/database/customStylesheet.ts +60 -1
- package/apps/agents-server/src/database/getMetadata.ts +84 -3
- package/apps/agents-server/src/instrumentation-client.ts +28 -0
- package/apps/agents-server/src/instrumentation.ts +19 -0
- package/apps/agents-server/src/sentry.edge.config.ts +18 -0
- package/apps/agents-server/src/sentry.server.config.ts +19 -0
- package/apps/agents-server/src/utils/codeRunnerConfiguration.ts +1 -1
- package/apps/agents-server/src/utils/errorReporting/agentsServerSentryContext.ts +203 -0
- package/apps/agents-server/src/utils/errorReporting/registerServerErrorSentryLogging.ts +381 -0
- package/apps/agents-server/src/utils/errorReporting/sendApplicationErrorReportToSentry.ts +43 -152
- package/apps/agents-server/src/utils/errorReporting/sentrySdkConfig.ts +237 -0
- package/apps/agents-server/src/utils/errorReporting/sentryStore.ts +187 -0
- package/apps/agents-server/src/utils/externalChatRunner/createExternalAgentRepositoryFiles.ts +2 -2
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/bootstrapManagedServer.ts +3 -1
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/normalizeCreateServerInput.ts +6 -0
- package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerDefaultAgents.ts +7 -3
- package/apps/agents-server/src/utils/serverManagement/createManagedServer.ts +5 -0
- package/apps/agents-server/src/utils/userChat/listUserChats.ts +109 -0
- package/apps/agents-server/src/utils/userChat/triggerUserChatJobWorker.ts +54 -19
- package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -1
- package/esm/index.es.js +9256 -8795
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
- package/esm/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
- package/esm/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
- package/esm/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
- package/esm/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
- package/esm/src/_packages/node.index.d.ts +20 -0
- package/esm/src/_packages/types.index.d.ts +16 -0
- package/esm/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
- package/esm/src/book-3.0/CliAgent.d.ts +68 -0
- package/esm/src/book-3.0/CliAgent.test.d.ts +1 -0
- package/esm/src/book-3.0/LiteAgent.d.ts +68 -0
- package/esm/src/book-3.0/LiteAgent.test.d.ts +1 -0
- package/esm/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
- package/esm/src/cli/cli-commands/agent/agentCliOptions.d.ts +29 -0
- package/esm/src/cli/cli-commands/agent/chat.d.ts +10 -0
- package/esm/src/cli/cli-commands/agent/exec.d.ts +10 -0
- package/esm/src/cli/cli-commands/agent/run.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/agent.d.ts +14 -0
- package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +2 -2
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/_packages/node.index.ts +20 -0
- package/src/_packages/types.index.ts +16 -0
- package/src/book-3.0/BookNodeAgentSource.ts +135 -0
- package/src/book-3.0/CliAgent.ts +236 -0
- package/src/book-3.0/LiteAgent.ts +463 -0
- package/src/book-components/BookEditor/BookEditor.module.css +61 -0
- package/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.tsx +74 -0
- package/src/book-components/BookEditor/BookEditorActionbar.tsx +3 -3
- package/src/cli/cli-commands/agent/agentCliOptions.ts +63 -0
- package/src/cli/cli-commands/agent/chat.ts +54 -0
- package/src/cli/cli-commands/agent/exec.ts +60 -0
- package/src/cli/cli-commands/agent.ts +45 -0
- package/src/cli/cli-commands/agents-server/startAgentsServer.ts +2 -2
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
- package/src/cli/cli-commands/common/promptRunnerCliOptions.ts +27 -23
- package/src/cli/promptbookCli.ts +2 -0
- package/src/other/templates/getTemplatesPipelineCollection.ts +809 -901
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/index.umd.js +9255 -8794
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
- package/umd/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
- package/umd/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
- package/umd/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
- package/umd/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
- package/umd/src/_packages/node.index.d.ts +20 -0
- package/umd/src/_packages/types.index.d.ts +16 -0
- package/umd/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
- package/umd/src/book-3.0/CliAgent.d.ts +68 -0
- package/umd/src/book-3.0/CliAgent.test.d.ts +1 -0
- package/umd/src/book-3.0/LiteAgent.d.ts +68 -0
- package/umd/src/book-3.0/LiteAgent.test.d.ts +1 -0
- package/umd/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
- package/umd/src/cli/cli-commands/agent/agentCliOptions.d.ts +29 -0
- package/umd/src/cli/cli-commands/agent/chat.d.ts +10 -0
- package/umd/src/cli/cli-commands/agent/exec.d.ts +10 -0
- package/umd/src/cli/cli-commands/agent/run.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/agent.d.ts +14 -0
- package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +2 -2
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
- package/umd/src/version.d.ts +1 -1
package/README.md
CHANGED
|
@@ -561,11 +561,11 @@ npx ts-node ./src/cli/test/ptbk.ts coder generate-boilerplates --template prompt
|
|
|
561
561
|
|
|
562
562
|
npx ts-node ./src/cli/test/ptbk.ts coder generate-boilerplates --template prompts/templates/agents-server.md
|
|
563
563
|
|
|
564
|
-
npx ts-node ./src/cli/test/ptbk.ts coder run --
|
|
564
|
+
npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md
|
|
565
565
|
|
|
566
|
-
npx ts-node ./src/cli/test/ptbk.ts coder run --
|
|
566
|
+
npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --auto-push
|
|
567
567
|
|
|
568
|
-
npx ts-node ./src/cli/test/ptbk.ts coder run --
|
|
568
|
+
npx ts-node ./src/cli/test/ptbk.ts coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --ignore-git-changes --no-wait
|
|
569
569
|
|
|
570
570
|
npx ts-node ./src/cli/test/ptbk.ts coder find-refactor-candidates
|
|
571
571
|
|
|
@@ -587,11 +587,11 @@ ptbk coder generate-boilerplates
|
|
|
587
587
|
|
|
588
588
|
ptbk coder generate-boilerplates --template prompts/templates/common.md
|
|
589
589
|
|
|
590
|
-
ptbk coder run --
|
|
590
|
+
ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --test npm run test
|
|
591
591
|
|
|
592
|
-
ptbk coder run --
|
|
592
|
+
ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --auto-push
|
|
593
593
|
|
|
594
|
-
ptbk coder run --
|
|
594
|
+
ptbk coder run --harness github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --test npm run test --ignore-git-changes --no-wait
|
|
595
595
|
|
|
596
596
|
ptbk coder find-refactor-candidates
|
|
597
597
|
|
|
@@ -616,7 +616,7 @@ ptbk coder verify
|
|
|
616
616
|
|
|
617
617
|
| Flag | Purpose |
|
|
618
618
|
| -------------------------- | -------------------------------------------------------------------------------------------------- |
|
|
619
|
-
| `--
|
|
619
|
+
| `--harness <name>` | Selects the coding harness. |
|
|
620
620
|
| `--model <model>` | Chooses the runner model; required for `openai-codex` and `gemini`, optional for `github-copilot`. |
|
|
621
621
|
| `--context <text-or-file>` | Appends extra instructions inline or from a file like `AGENTS.md`. |
|
|
622
622
|
| `--test <command>` | Runs a verification command after each prompt attempt and feeds failing output back for retries. |
|
|
@@ -9,7 +9,7 @@ The installed CLI can initialize a local Agents Server project before it starts
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install ptbk
|
|
11
11
|
ptbk agents-server init
|
|
12
|
-
ptbk agents-server start --
|
|
12
|
+
ptbk agents-server start --harness github-copilot --model gpt-5.4 --thinking-level xhigh
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
`ptbk agents-server init` adds missing placeholders to `.env` and local runtime exclusions to `.gitignore` without deleting existing configuration. Use `PTBK_AGENTS_SERVER_DATABASE=supabase` for a Supabase-backed server or `PTBK_AGENTS_SERVER_DATABASE=sqlite` for a standalone local database in `.promptbook`. When using Supabase, fill the initialized values from your project before starting the server. The Supabase project URL and API keys are available in the [Supabase project API settings](https://supabase.com/docs/guides/api/api-keys), and the PostgreSQL connection string is available from the [Supabase database connection guide](https://supabase.com/docs/guides/database/connecting-to-postgres).
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { withSentryConfig } from '@sentry/nextjs';
|
|
1
2
|
import type { NextConfig } from 'next';
|
|
2
3
|
import { readdirSync } from 'fs';
|
|
3
4
|
import path from 'path';
|
|
5
|
+
import { SENTRY_ORGANIZATION, SENTRY_PROJECT } from './src/utils/errorReporting/sentrySdkConfig';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Next.js build output directory.
|
|
@@ -20,6 +22,11 @@ const agentsServerNodeModulesPath = process.env.PTBK_AGENTS_SERVER_NODE_MODULES_
|
|
|
20
22
|
*/
|
|
21
23
|
const isNextValidationIgnored = process.env.PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION === 'true';
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Whether Sentry source maps can be uploaded during production builds.
|
|
27
|
+
*/
|
|
28
|
+
const IS_SENTRY_SOURCE_MAP_UPLOAD_ENABLED = Boolean(process.env.SENTRY_AUTH_TOKEN);
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
* Exact aliases for local generated Promptbook package entrypoints.
|
|
25
32
|
*/
|
|
@@ -122,7 +129,19 @@ const nextConfig: NextConfig = {
|
|
|
122
129
|
},
|
|
123
130
|
};
|
|
124
131
|
|
|
125
|
-
export default nextConfig
|
|
132
|
+
export default withSentryConfig(nextConfig, {
|
|
133
|
+
org: SENTRY_ORGANIZATION,
|
|
134
|
+
project: SENTRY_PROJECT,
|
|
135
|
+
silent: true,
|
|
136
|
+
sourcemaps: {
|
|
137
|
+
disable: !IS_SENTRY_SOURCE_MAP_UPLOAD_ENABLED,
|
|
138
|
+
},
|
|
139
|
+
webpack: {
|
|
140
|
+
treeshake: {
|
|
141
|
+
removeDebugLogging: true,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
});
|
|
126
145
|
|
|
127
146
|
/**
|
|
128
147
|
* Creates webpack/Turbopack aliases from imports like `@promptbook-local/core` to generated local sources.
|
|
@@ -203,6 +203,22 @@ function CreateServerForm(props: {
|
|
|
203
203
|
) : null}
|
|
204
204
|
</div>
|
|
205
205
|
|
|
206
|
+
<div className="rounded-lg border border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
|
207
|
+
<label htmlFor="create-server-default-agents" className="flex items-start gap-3">
|
|
208
|
+
<input
|
|
209
|
+
id="create-server-default-agents"
|
|
210
|
+
type="checkbox"
|
|
211
|
+
checked={wizardState.isDefaultAgentsInstalled}
|
|
212
|
+
onChange={(event) => updateWizardField('isDefaultAgentsInstalled', event.target.checked)}
|
|
213
|
+
className="mt-0.5 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
214
|
+
/>
|
|
215
|
+
<span>
|
|
216
|
+
<span className="block font-semibold text-gray-900">Install default agents</span>
|
|
217
|
+
<span className="mt-1 block">Create bundled starter agents from agents/default.</span>
|
|
218
|
+
</span>
|
|
219
|
+
</label>
|
|
220
|
+
</div>
|
|
221
|
+
|
|
206
222
|
<div className="rounded-lg border border-gray-200 bg-gray-50 p-4 text-sm text-gray-600">
|
|
207
223
|
<p className="font-semibold text-gray-900">Admin user exists</p>
|
|
208
224
|
<p className="mt-1">
|
|
@@ -121,6 +121,11 @@ export type CreateServerWizardState = {
|
|
|
121
121
|
*/
|
|
122
122
|
additionalUsers: WizardUser[];
|
|
123
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Whether bundled default agents should be installed during server creation.
|
|
126
|
+
*/
|
|
127
|
+
isDefaultAgentsInstalled: boolean;
|
|
128
|
+
|
|
124
129
|
/**
|
|
125
130
|
* Initial metadata values.
|
|
126
131
|
*/
|
|
@@ -155,7 +160,10 @@ export type CreateServerWizardError = {
|
|
|
155
160
|
* @private function of <ServersClient/>
|
|
156
161
|
*/
|
|
157
162
|
export type UpdateCreateServerWizardField = <
|
|
158
|
-
TFieldName extends keyof Pick<
|
|
163
|
+
TFieldName extends keyof Pick<
|
|
164
|
+
CreateServerWizardState,
|
|
165
|
+
'name' | 'domain' | 'iconUrl' | 'isDefaultAgentsInstalled'
|
|
166
|
+
>,
|
|
159
167
|
>(
|
|
160
168
|
fieldName: TFieldName,
|
|
161
169
|
value: CreateServerWizardState[TFieldName],
|
|
@@ -262,6 +270,7 @@ function createInitialWizardState(): CreateServerWizardState {
|
|
|
262
270
|
password: '',
|
|
263
271
|
},
|
|
264
272
|
additionalUsers: [],
|
|
273
|
+
isDefaultAgentsInstalled: true,
|
|
265
274
|
initialSettings: {
|
|
266
275
|
language: 'en',
|
|
267
276
|
homepageMessage: '',
|
|
@@ -345,7 +354,8 @@ function hasCreateServerWizardChanges(wizardState: CreateServerWizardState): boo
|
|
|
345
354
|
wizardState.name !== initialWizardState.name ||
|
|
346
355
|
wizardState.identifier !== initialWizardState.identifier ||
|
|
347
356
|
wizardState.domain !== initialWizardState.domain ||
|
|
348
|
-
wizardState.iconUrl !== initialWizardState.iconUrl
|
|
357
|
+
wizardState.iconUrl !== initialWizardState.iconUrl ||
|
|
358
|
+
wizardState.isDefaultAgentsInstalled !== initialWizardState.isDefaultAgentsInstalled
|
|
349
359
|
);
|
|
350
360
|
}
|
|
351
361
|
|
|
@@ -402,16 +412,32 @@ export function useCreateServerWizard(options: UseCreateServerWizardOptions): Us
|
|
|
402
412
|
const updateWizardField = useCallback<UpdateCreateServerWizardField>((fieldName, value) => {
|
|
403
413
|
setWizardState((previous) => {
|
|
404
414
|
if (fieldName === 'name') {
|
|
415
|
+
const name = value as CreateServerWizardState['name'];
|
|
416
|
+
|
|
417
|
+
return {
|
|
418
|
+
...previous,
|
|
419
|
+
name,
|
|
420
|
+
identifier: createServerIdentifierFromName(name),
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
if (fieldName === 'domain') {
|
|
425
|
+
return {
|
|
426
|
+
...previous,
|
|
427
|
+
domain: value as CreateServerWizardState['domain'],
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (fieldName === 'iconUrl') {
|
|
405
432
|
return {
|
|
406
433
|
...previous,
|
|
407
|
-
|
|
408
|
-
identifier: createServerIdentifierFromName(value),
|
|
434
|
+
iconUrl: value as CreateServerWizardState['iconUrl'],
|
|
409
435
|
};
|
|
410
436
|
}
|
|
411
437
|
|
|
412
438
|
return {
|
|
413
439
|
...previous,
|
|
414
|
-
|
|
440
|
+
isDefaultAgentsInstalled: value as CreateServerWizardState['isDefaultAgentsInstalled'],
|
|
415
441
|
};
|
|
416
442
|
});
|
|
417
443
|
}, []);
|
|
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server';
|
|
|
2
2
|
import { spaceTrim } from 'spacetrim';
|
|
3
3
|
import { DatabaseError } from '../../../../../../../src/errors/DatabaseError';
|
|
4
4
|
import { isAgentsServerSqliteMode } from '../../../../database/agentsServerDatabaseMode';
|
|
5
|
+
import { seedDefaultAgents } from '../../../../database/seedDefaultAgents';
|
|
5
6
|
import { resolveCurrentServerRegistryContext } from '../../../../utils/currentServerRegistryContext';
|
|
6
7
|
import { isUserAdmin } from '../../../../utils/isUserAdmin';
|
|
7
8
|
import { isUserGlobalAdmin } from '../../../../utils/isUserGlobalAdmin';
|
|
@@ -97,6 +98,7 @@ export async function POST(request: Request) {
|
|
|
97
98
|
|
|
98
99
|
const body = withEnvironmentAdminUser((await request.json()) as CreateServerInput);
|
|
99
100
|
if (isAgentsServerSqliteMode()) {
|
|
101
|
+
const isDefaultAgentsInstalled = body.isDefaultAgentsInstalled !== false;
|
|
100
102
|
const normalizedDomain = normalizeServerDomain(body.domain);
|
|
101
103
|
if (!normalizedDomain) {
|
|
102
104
|
return NextResponse.json({ error: 'A valid domain is required.' }, { status: 400 });
|
|
@@ -114,6 +116,9 @@ export async function POST(request: Request) {
|
|
|
114
116
|
iconUrl: body.iconUrl,
|
|
115
117
|
});
|
|
116
118
|
}
|
|
119
|
+
if (isDefaultAgentsInstalled) {
|
|
120
|
+
await seedDefaultAgents({ tablePrefix });
|
|
121
|
+
}
|
|
117
122
|
|
|
118
123
|
return NextResponse.json(
|
|
119
124
|
{
|
|
@@ -57,7 +57,7 @@ async function handleUserChatJobWorkerRequest(request: Request) {
|
|
|
57
57
|
|
|
58
58
|
after(() =>
|
|
59
59
|
triggerUserChatJobWorker({ origin }).catch((error) =>
|
|
60
|
-
console.
|
|
60
|
+
console.warn('[user-chat-job] requeue failed', error),
|
|
61
61
|
),
|
|
62
62
|
);
|
|
63
63
|
|
|
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from 'next/server';
|
|
|
2
2
|
import { keepUnused } from '../../../../../../src/utils/organization/keepUnused';
|
|
3
3
|
import { $getTableName } from '../../../database/$getTableName';
|
|
4
4
|
import { $provideSupabase } from '../../../database/$provideSupabase';
|
|
5
|
+
import { invalidateMetadataCache } from '../../../database/getMetadata';
|
|
5
6
|
import { validateMetadataValue } from '../../../database/metadataDefaults';
|
|
6
7
|
import { isUserAdmin } from '../../../utils/isUserAdmin';
|
|
7
8
|
|
|
@@ -121,6 +122,7 @@ export async function POST(request: NextRequest) {
|
|
|
121
122
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
122
123
|
}
|
|
123
124
|
|
|
125
|
+
invalidateMetadataCache();
|
|
124
126
|
return NextResponse.json(data);
|
|
125
127
|
}
|
|
126
128
|
|
|
@@ -152,6 +154,7 @@ export async function PUT(request: NextRequest) {
|
|
|
152
154
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
153
155
|
}
|
|
154
156
|
|
|
157
|
+
invalidateMetadataCache();
|
|
155
158
|
return NextResponse.json(data);
|
|
156
159
|
}
|
|
157
160
|
|
|
@@ -179,5 +182,6 @@ export async function DELETE(request: NextRequest) {
|
|
|
179
182
|
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
180
183
|
}
|
|
181
184
|
|
|
185
|
+
invalidateMetadataCache();
|
|
182
186
|
return NextResponse.json({ success: true });
|
|
183
187
|
}
|
|
@@ -14,6 +14,13 @@ export const MAX_CUSTOM_JAVASCRIPT_LENGTH = 100_000;
|
|
|
14
14
|
*/
|
|
15
15
|
const CUSTOM_JAVASCRIPT_TABLE_BASENAME = 'CustomJavascript';
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Process-level cache lifetime for custom JavaScript rows.
|
|
19
|
+
*
|
|
20
|
+
* @private
|
|
21
|
+
*/
|
|
22
|
+
const CUSTOM_JAVASCRIPT_CACHE_TTL_MS = 30_000;
|
|
23
|
+
|
|
17
24
|
/**
|
|
18
25
|
* Stored `CustomJavascript` row shape.
|
|
19
26
|
*
|
|
@@ -90,6 +97,28 @@ type DynamicSupabaseClient = {
|
|
|
90
97
|
from: (tableName: string) => DynamicCustomJavascriptTableQuery;
|
|
91
98
|
};
|
|
92
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Cached custom JavaScript rows keyed by the resolved table name.
|
|
102
|
+
*
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
const cachedCustomJavascriptByTableName = new Map<
|
|
106
|
+
string,
|
|
107
|
+
{
|
|
108
|
+
readonly loadedAt: number;
|
|
109
|
+
readonly rowsPromise: Promise<CustomJavascriptRow[]>;
|
|
110
|
+
}
|
|
111
|
+
>();
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Clears process-level custom JavaScript cache after admin writes.
|
|
115
|
+
*
|
|
116
|
+
* @private
|
|
117
|
+
*/
|
|
118
|
+
export function invalidateCustomJavascriptCache(): void {
|
|
119
|
+
cachedCustomJavascriptByTableName.clear();
|
|
120
|
+
}
|
|
121
|
+
|
|
93
122
|
/**
|
|
94
123
|
* Resolves the prefixed table name for `CustomJavascript`.
|
|
95
124
|
*
|
|
@@ -137,8 +166,37 @@ function getCustomJavascriptClient() {
|
|
|
137
166
|
*/
|
|
138
167
|
export async function getCustomJavascriptFiles(): Promise<CustomJavascriptRow[]> {
|
|
139
168
|
const table = await getCustomJavascriptTableName();
|
|
140
|
-
const
|
|
169
|
+
const cachedJavascript = cachedCustomJavascriptByTableName.get(table);
|
|
170
|
+
if (cachedJavascript && Date.now() - cachedJavascript.loadedAt < CUSTOM_JAVASCRIPT_CACHE_TTL_MS) {
|
|
171
|
+
return cachedJavascript.rowsPromise;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const rowsPromise = loadCustomJavascriptFilesFromDatabase(table);
|
|
175
|
+
cachedCustomJavascriptByTableName.set(table, {
|
|
176
|
+
loadedAt: Date.now(),
|
|
177
|
+
rowsPromise,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
try {
|
|
181
|
+
return await rowsPromise;
|
|
182
|
+
} catch (error) {
|
|
183
|
+
if (cachedCustomJavascriptByTableName.get(table)?.rowsPromise === rowsPromise) {
|
|
184
|
+
cachedCustomJavascriptByTableName.delete(table);
|
|
185
|
+
}
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
141
189
|
|
|
190
|
+
/**
|
|
191
|
+
* Reads custom JavaScript rows from the database.
|
|
192
|
+
*
|
|
193
|
+
* @param table - Resolved CustomJavascript table name.
|
|
194
|
+
* @returns Stored JavaScript rows.
|
|
195
|
+
*
|
|
196
|
+
* @private
|
|
197
|
+
*/
|
|
198
|
+
async function loadCustomJavascriptFilesFromDatabase(table: string): Promise<CustomJavascriptRow[]> {
|
|
199
|
+
const supabase = getCustomJavascriptClient();
|
|
142
200
|
const { data, error } = await supabase.from(table).select('*').order('scope', { ascending: true });
|
|
143
201
|
|
|
144
202
|
if (error) {
|
|
@@ -234,6 +292,7 @@ export async function saveCustomJavascriptFile({
|
|
|
234
292
|
throw new Error(`Failed to save custom JavaScript: ${error.message || String(error)}`);
|
|
235
293
|
}
|
|
236
294
|
|
|
295
|
+
invalidateCustomJavascriptCache();
|
|
237
296
|
return data as CustomJavascriptRow;
|
|
238
297
|
}
|
|
239
298
|
|
|
@@ -255,4 +314,6 @@ export async function deleteCustomJavascriptFile(id: number): Promise<void> {
|
|
|
255
314
|
|
|
256
315
|
throw new Error(`Failed to delete custom JavaScript: ${error.message || String(error)}`);
|
|
257
316
|
}
|
|
317
|
+
|
|
318
|
+
invalidateCustomJavascriptCache();
|
|
258
319
|
}
|
|
@@ -7,6 +7,11 @@ import { $provideSupabase } from './$provideSupabase';
|
|
|
7
7
|
*/
|
|
8
8
|
const CUSTOM_STYLESHEET_TABLE_BASENAME = 'CustomStylesheet';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Process-level cache lifetime for custom stylesheet rows.
|
|
12
|
+
*/
|
|
13
|
+
const CUSTOM_STYLESHEET_CACHE_TTL_MS = 30_000;
|
|
14
|
+
|
|
10
15
|
/**
|
|
11
16
|
* Stored CustomStylesheet row shape.
|
|
12
17
|
*
|
|
@@ -82,6 +87,28 @@ type DynamicSupabaseClient = {
|
|
|
82
87
|
from: (tableName: string) => DynamicCustomStylesheetTableQuery;
|
|
83
88
|
};
|
|
84
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Cached custom stylesheet rows keyed by the resolved table name.
|
|
92
|
+
*
|
|
93
|
+
* @private
|
|
94
|
+
*/
|
|
95
|
+
const cachedCustomStylesheetsByTableName = new Map<
|
|
96
|
+
string,
|
|
97
|
+
{
|
|
98
|
+
readonly loadedAt: number;
|
|
99
|
+
readonly rowsPromise: Promise<CustomStylesheetRow[]>;
|
|
100
|
+
}
|
|
101
|
+
>();
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Clears process-level stylesheet cache after admin writes.
|
|
105
|
+
*
|
|
106
|
+
* @public
|
|
107
|
+
*/
|
|
108
|
+
export function invalidateCustomStylesheetCache(): void {
|
|
109
|
+
cachedCustomStylesheetsByTableName.clear();
|
|
110
|
+
}
|
|
111
|
+
|
|
85
112
|
/**
|
|
86
113
|
* Resolves the prefixed table name for CustomStylesheet.
|
|
87
114
|
*
|
|
@@ -127,8 +154,37 @@ function getCustomStylesheetClient(): DynamicSupabaseClient {
|
|
|
127
154
|
*/
|
|
128
155
|
export async function listCustomStylesheets(): Promise<CustomStylesheetRow[]> {
|
|
129
156
|
const table = await getCustomStylesheetTableName();
|
|
130
|
-
const
|
|
157
|
+
const cachedStylesheets = cachedCustomStylesheetsByTableName.get(table);
|
|
158
|
+
if (cachedStylesheets && Date.now() - cachedStylesheets.loadedAt < CUSTOM_STYLESHEET_CACHE_TTL_MS) {
|
|
159
|
+
return cachedStylesheets.rowsPromise;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const rowsPromise = loadCustomStylesheetsFromDatabase(table);
|
|
163
|
+
cachedCustomStylesheetsByTableName.set(table, {
|
|
164
|
+
loadedAt: Date.now(),
|
|
165
|
+
rowsPromise,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
try {
|
|
169
|
+
return await rowsPromise;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
if (cachedCustomStylesheetsByTableName.get(table)?.rowsPromise === rowsPromise) {
|
|
172
|
+
cachedCustomStylesheetsByTableName.delete(table);
|
|
173
|
+
}
|
|
174
|
+
throw error;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
131
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Reads custom stylesheet rows from the database.
|
|
180
|
+
*
|
|
181
|
+
* @param table - Resolved CustomStylesheet table name.
|
|
182
|
+
* @returns Stored stylesheet rows.
|
|
183
|
+
*
|
|
184
|
+
* @private
|
|
185
|
+
*/
|
|
186
|
+
async function loadCustomStylesheetsFromDatabase(table: string): Promise<CustomStylesheetRow[]> {
|
|
187
|
+
const supabase = getCustomStylesheetClient();
|
|
132
188
|
const { data, error } = await supabase.from(table).select('*').order('createdAt', { ascending: true });
|
|
133
189
|
|
|
134
190
|
if (error) {
|
|
@@ -206,6 +262,7 @@ export async function saveCustomStylesheetFile({
|
|
|
206
262
|
throw new Error(`Failed to save custom stylesheet: ${error.message || String(error)}`);
|
|
207
263
|
}
|
|
208
264
|
|
|
265
|
+
invalidateCustomStylesheetCache();
|
|
209
266
|
return data as CustomStylesheetRow;
|
|
210
267
|
}
|
|
211
268
|
|
|
@@ -229,4 +286,6 @@ export async function deleteCustomStylesheetFile(id: number): Promise<void> {
|
|
|
229
286
|
|
|
230
287
|
throw new Error(`Failed to delete custom stylesheet: ${error.message || String(error)}`);
|
|
231
288
|
}
|
|
289
|
+
|
|
290
|
+
invalidateCustomStylesheetCache();
|
|
232
291
|
}
|
|
@@ -10,6 +10,45 @@ import { cache } from 'react';
|
|
|
10
10
|
*/
|
|
11
11
|
const metadataDefaultsMap = new Map<string, string>(metadataDefaults.map((metadata) => [metadata.key, metadata.value]));
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Process-level cache lifetime for metadata reads.
|
|
15
|
+
*
|
|
16
|
+
* @private Internal helper for metadata lookups in `apps/agents-server`.
|
|
17
|
+
*/
|
|
18
|
+
const METADATA_CACHE_TTL_MS = 30_000;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Cached metadata table payload keyed by the resolved table name.
|
|
22
|
+
*
|
|
23
|
+
* @private Internal helper for metadata lookups in `apps/agents-server`.
|
|
24
|
+
*/
|
|
25
|
+
const cachedMetadataValuesByTableName = new Map<
|
|
26
|
+
string,
|
|
27
|
+
{
|
|
28
|
+
readonly loadedAt: number;
|
|
29
|
+
readonly valuesPromise: Promise<Map<string, string | null>>;
|
|
30
|
+
}
|
|
31
|
+
>();
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Metadata row shape loaded by the lightweight metadata select.
|
|
35
|
+
*
|
|
36
|
+
* @private Internal helper for metadata lookups in `apps/agents-server`.
|
|
37
|
+
*/
|
|
38
|
+
type MetadataValueRow = {
|
|
39
|
+
readonly key: string;
|
|
40
|
+
readonly value: string | null;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Clears process-level metadata cache after admin metadata writes.
|
|
45
|
+
*
|
|
46
|
+
* @public exported from `apps/agents-server`
|
|
47
|
+
*/
|
|
48
|
+
export function invalidateMetadataCache(): void {
|
|
49
|
+
cachedMetadataValuesByTableName.clear();
|
|
50
|
+
}
|
|
51
|
+
|
|
13
52
|
/**
|
|
14
53
|
* Loads the full metadata table once per request so callers can cheaply project subsets.
|
|
15
54
|
*
|
|
@@ -18,17 +57,59 @@ const metadataDefaultsMap = new Map<string, string>(metadataDefaults.map((metada
|
|
|
18
57
|
* @private Internal helper for batched metadata lookups in `apps/agents-server`.
|
|
19
58
|
*/
|
|
20
59
|
const loadAllMetadataValues = cache(async (): Promise<Map<string, string | null>> => {
|
|
21
|
-
const supabase = $provideSupabase();
|
|
22
60
|
const table = await $getTableName('Metadata');
|
|
61
|
+
return loadCachedMetadataValues(table);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Loads metadata values using a short process-level cache shared by consecutive requests.
|
|
66
|
+
*
|
|
67
|
+
* @param table - Resolved metadata table name.
|
|
68
|
+
* @returns Metadata values keyed by metadata key.
|
|
69
|
+
*
|
|
70
|
+
* @private Internal helper for metadata lookups in `apps/agents-server`.
|
|
71
|
+
*/
|
|
72
|
+
async function loadCachedMetadataValues(table: string): Promise<Map<string, string | null>> {
|
|
73
|
+
const cachedMetadataValues = cachedMetadataValuesByTableName.get(table);
|
|
74
|
+
if (cachedMetadataValues && Date.now() - cachedMetadataValues.loadedAt < METADATA_CACHE_TTL_MS) {
|
|
75
|
+
return cachedMetadataValues.valuesPromise;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const valuesPromise = loadMetadataValuesFromDatabase(table);
|
|
79
|
+
cachedMetadataValuesByTableName.set(table, {
|
|
80
|
+
loadedAt: Date.now(),
|
|
81
|
+
valuesPromise,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
return await valuesPromise;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
if (cachedMetadataValuesByTableName.get(table)?.valuesPromise === valuesPromise) {
|
|
88
|
+
cachedMetadataValuesByTableName.delete(table);
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Reads all persisted metadata values from the database.
|
|
96
|
+
*
|
|
97
|
+
* @param table - Resolved metadata table name.
|
|
98
|
+
* @returns Metadata values keyed by metadata key.
|
|
99
|
+
*
|
|
100
|
+
* @private Internal helper for metadata lookups in `apps/agents-server`.
|
|
101
|
+
*/
|
|
102
|
+
async function loadMetadataValuesFromDatabase(table: string): Promise<Map<string, string | null>> {
|
|
103
|
+
const supabase = $provideSupabase();
|
|
23
104
|
const { data } = await supabase.from(table).select('key, value');
|
|
24
105
|
|
|
25
106
|
const loadedMap = new Map<string, string | null>();
|
|
26
|
-
for (const row of data ?? []) {
|
|
107
|
+
for (const row of (data ?? []) as Array<MetadataValueRow>) {
|
|
27
108
|
loadedMap.set(row.key, row.value);
|
|
28
109
|
}
|
|
29
110
|
|
|
30
111
|
return loadedMap;
|
|
31
|
-
}
|
|
112
|
+
}
|
|
32
113
|
|
|
33
114
|
/**
|
|
34
115
|
* Get metadata value by key
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/nextjs';
|
|
2
|
+
import {
|
|
3
|
+
createSentrySdkTags,
|
|
4
|
+
resolveBrowserSentryDsn,
|
|
5
|
+
resolveSentrySdkEnvironment,
|
|
6
|
+
resolveSentrySdkRelease,
|
|
7
|
+
SENTRY_TRACE_PROPAGATION_TARGETS,
|
|
8
|
+
SENTRY_TRACES_SAMPLE_RATE,
|
|
9
|
+
} from './utils/errorReporting/sentrySdkConfig';
|
|
10
|
+
|
|
11
|
+
Sentry.init({
|
|
12
|
+
dsn: resolveBrowserSentryDsn(),
|
|
13
|
+
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
|
|
14
|
+
environment: resolveSentrySdkEnvironment(),
|
|
15
|
+
release: resolveSentrySdkRelease(),
|
|
16
|
+
integrations: [Sentry.browserTracingIntegration()],
|
|
17
|
+
tracePropagationTargets: SENTRY_TRACE_PROPAGATION_TARGETS,
|
|
18
|
+
initialScope: {
|
|
19
|
+
tags: createSentrySdkTags(),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Reports app-router navigation spans to Sentry.
|
|
25
|
+
*
|
|
26
|
+
* @private Sentry hook for Next.js client navigation instrumentation
|
|
27
|
+
*/
|
|
28
|
+
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/nextjs';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Registers startup hooks for the Agents Server runtime.
|
|
3
5
|
*
|
|
@@ -5,11 +7,21 @@
|
|
|
5
7
|
* @private internal startup hook for Agents Server runtime
|
|
6
8
|
*/
|
|
7
9
|
export async function register(): Promise<void> {
|
|
10
|
+
if (process.env.NEXT_RUNTIME === 'edge') {
|
|
11
|
+
await import('./sentry.edge.config');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
8
15
|
if (process.env.NEXT_RUNTIME !== 'nodejs') {
|
|
9
16
|
return;
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
try {
|
|
20
|
+
await import('./sentry.server.config');
|
|
21
|
+
|
|
22
|
+
const { registerServerErrorSentryLogging } = await import('./utils/errorReporting/registerServerErrorSentryLogging');
|
|
23
|
+
registerServerErrorSentryLogging();
|
|
24
|
+
|
|
13
25
|
const { registerNodeRuntimeInstrumentation } = await import('./instrumentation-node');
|
|
14
26
|
await registerNodeRuntimeInstrumentation();
|
|
15
27
|
} catch (error) {
|
|
@@ -22,3 +34,10 @@ export async function register(): Promise<void> {
|
|
|
22
34
|
});
|
|
23
35
|
}
|
|
24
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Reports request errors from the Next.js app router to Sentry.
|
|
40
|
+
*
|
|
41
|
+
* @private Sentry hook for Next.js request instrumentation
|
|
42
|
+
*/
|
|
43
|
+
export const onRequestError = Sentry.captureRequestError;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/nextjs';
|
|
2
|
+
import {
|
|
3
|
+
createSentrySdkTags,
|
|
4
|
+
resolveBrowserSentryDsn,
|
|
5
|
+
resolveSentrySdkEnvironment,
|
|
6
|
+
resolveSentrySdkRelease,
|
|
7
|
+
SENTRY_TRACES_SAMPLE_RATE,
|
|
8
|
+
} from './utils/errorReporting/sentrySdkConfig';
|
|
9
|
+
|
|
10
|
+
Sentry.init({
|
|
11
|
+
dsn: resolveBrowserSentryDsn(),
|
|
12
|
+
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
|
|
13
|
+
environment: resolveSentrySdkEnvironment(),
|
|
14
|
+
release: resolveSentrySdkRelease(),
|
|
15
|
+
initialScope: {
|
|
16
|
+
tags: createSentrySdkTags(),
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as Sentry from '@sentry/nextjs';
|
|
2
|
+
import { createAgentsServerSentryContext } from './utils/errorReporting/agentsServerSentryContext';
|
|
3
|
+
import { resolveServerSentryDsn, SENTRY_TRACES_SAMPLE_RATE } from './utils/errorReporting/sentrySdkConfig';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Shared diagnostic context applied to server-side SDK events at initialization time.
|
|
7
|
+
*/
|
|
8
|
+
const agentsServerSentryContext = createAgentsServerSentryContext();
|
|
9
|
+
|
|
10
|
+
Sentry.init({
|
|
11
|
+
dsn: resolveServerSentryDsn(),
|
|
12
|
+
tracesSampleRate: SENTRY_TRACES_SAMPLE_RATE,
|
|
13
|
+
environment: agentsServerSentryContext.environment,
|
|
14
|
+
release: agentsServerSentryContext.release,
|
|
15
|
+
initialScope: {
|
|
16
|
+
tags: agentsServerSentryContext.tags,
|
|
17
|
+
extra: agentsServerSentryContext.extra,
|
|
18
|
+
},
|
|
19
|
+
});
|