@promptbook/cli 0.112.0-112 → 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.
Files changed (84) hide show
  1. package/README.md +7 -7
  2. package/apps/agents-server/README.md +1 -1
  3. package/apps/agents-server/next.config.ts +20 -1
  4. package/apps/agents-server/src/app/api/admin/code-runners/route.ts +1 -1
  5. package/apps/agents-server/src/app/api/internal/user-chat-jobs/run/route.ts +1 -1
  6. package/apps/agents-server/src/instrumentation-client.ts +28 -0
  7. package/apps/agents-server/src/instrumentation.ts +16 -0
  8. package/apps/agents-server/src/sentry.edge.config.ts +18 -0
  9. package/apps/agents-server/src/sentry.server.config.ts +19 -0
  10. package/apps/agents-server/src/utils/codeRunnerConfiguration.ts +1 -1
  11. package/apps/agents-server/src/utils/errorReporting/agentsServerSentryContext.ts +203 -0
  12. package/apps/agents-server/src/utils/errorReporting/registerServerErrorSentryLogging.ts +59 -9
  13. package/apps/agents-server/src/utils/errorReporting/sendApplicationErrorReportToSentry.ts +39 -3
  14. package/apps/agents-server/src/utils/errorReporting/sentrySdkConfig.ts +237 -0
  15. package/apps/agents-server/src/utils/errorReporting/sentryStore.ts +10 -0
  16. package/apps/agents-server/src/utils/externalChatRunner/createExternalAgentRepositoryFiles.ts +2 -2
  17. package/apps/agents-server/src/utils/userChat/triggerUserChatJobWorker.ts +54 -19
  18. package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -1
  19. package/esm/index.es.js +9325 -8883
  20. package/esm/index.es.js.map +1 -1
  21. package/esm/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
  22. package/esm/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
  23. package/esm/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
  24. package/esm/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
  25. package/esm/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
  26. package/esm/src/_packages/node.index.d.ts +20 -0
  27. package/esm/src/_packages/types.index.d.ts +16 -0
  28. package/esm/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
  29. package/esm/src/book-3.0/CliAgent.d.ts +68 -0
  30. package/esm/src/book-3.0/LiteAgent.d.ts +68 -0
  31. package/esm/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
  32. package/esm/src/cli/cli-commands/agent/agentCliOptions.d.ts +29 -0
  33. package/esm/src/cli/cli-commands/agent/chat.d.ts +10 -0
  34. package/esm/src/cli/cli-commands/agent/exec.d.ts +10 -0
  35. package/esm/src/cli/cli-commands/agent/run.test.d.ts +1 -0
  36. package/esm/src/cli/cli-commands/agent.d.ts +14 -0
  37. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -4
  38. package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
  39. package/esm/src/version.d.ts +1 -1
  40. package/package.json +2 -1
  41. package/src/_packages/node.index.ts +20 -0
  42. package/src/_packages/types.index.ts +16 -0
  43. package/src/book-3.0/BookNodeAgentSource.ts +135 -0
  44. package/src/book-3.0/CliAgent.ts +236 -0
  45. package/src/book-3.0/LiteAgent.ts +463 -0
  46. package/src/book-components/BookEditor/BookEditor.module.css +61 -0
  47. package/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.tsx +74 -0
  48. package/src/book-components/BookEditor/BookEditorActionbar.tsx +3 -3
  49. package/src/cli/cli-commands/agent/agentCliOptions.ts +63 -0
  50. package/src/cli/cli-commands/agent/chat.ts +54 -0
  51. package/src/cli/cli-commands/agent/exec.ts +60 -0
  52. package/src/cli/cli-commands/agent.ts +45 -0
  53. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +3 -19
  54. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  55. package/src/cli/cli-commands/common/promptRunnerCliOptions.ts +27 -23
  56. package/src/cli/promptbookCli.ts +2 -0
  57. package/src/other/templates/getTemplatesPipelineCollection.ts +836 -774
  58. package/src/version.ts +2 -2
  59. package/src/versions.txt +1 -0
  60. package/umd/index.umd.js +9325 -8883
  61. package/umd/index.umd.js.map +1 -1
  62. package/umd/scripts/run-agent-chat/executeAgentChatTurn.d.ts +28 -0
  63. package/umd/scripts/run-agent-chat/runAgentChat.d.ts +5 -0
  64. package/umd/scripts/run-agent-chat/runAgentExec.d.ts +11 -0
  65. package/umd/scripts/run-agent-messages/messages/createAgentRunnerSystemMessage.d.ts +10 -0
  66. package/umd/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +14 -0
  67. package/umd/src/_packages/node.index.d.ts +20 -0
  68. package/umd/src/_packages/types.index.d.ts +16 -0
  69. package/umd/src/book-3.0/BookNodeAgentSource.d.ts +38 -0
  70. package/umd/src/book-3.0/CliAgent.d.ts +68 -0
  71. package/umd/src/book-3.0/CliAgent.test.d.ts +1 -0
  72. package/umd/src/book-3.0/LiteAgent.d.ts +68 -0
  73. package/umd/src/book-3.0/LiteAgent.test.d.ts +1 -0
  74. package/umd/src/book-components/BookEditor/BookEditorAboutPromptbookInformation.d.ts +12 -0
  75. package/umd/src/cli/cli-commands/agent/agentCliOptions.d.ts +29 -0
  76. package/umd/src/cli/cli-commands/agent/chat.d.ts +10 -0
  77. package/umd/src/cli/cli-commands/agent/exec.d.ts +10 -0
  78. package/umd/src/cli/cli-commands/agent/run.test.d.ts +1 -0
  79. package/umd/src/cli/cli-commands/agent.d.ts +14 -0
  80. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +3 -4
  81. package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +9 -9
  82. package/umd/src/version.d.ts +1 -1
  83. /package/esm/src/{cli/cli-commands/agents-server/startAgentsServer.test.d.ts → book-3.0/CliAgent.test.d.ts} +0 -0
  84. /package/{umd/src/cli/cli-commands/agents-server/startAgentsServer.test.d.ts → esm/src/book-3.0/LiteAgent.test.d.ts} +0 -0
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --auto-push
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --ignore-git-changes --no-wait
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --test npm run test
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --auto-push
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh --context AGENTS.md --test npm run test --ignore-git-changes --no-wait
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
- | `--agent <name>` | Selects the coding backend. |
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 --agent github-copilot --model gpt-5.4 --thinking-level xhigh
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.
@@ -52,7 +52,7 @@ export async function PATCH(request: Request) {
52
52
  }
53
53
 
54
54
  await updateVpsEnvironmentVariables({
55
- PTBK_AGENT: body.agent || '',
55
+ PTBK_HARNESS: body.agent || '',
56
56
  PTBK_MODEL: body.model || '',
57
57
  PTBK_THINKING_LEVEL: body.thinkingLevel || '',
58
58
  });
@@ -57,7 +57,7 @@ async function handleUserChatJobWorkerRequest(request: Request) {
57
57
 
58
58
  after(() =>
59
59
  triggerUserChatJobWorker({ origin }).catch((error) =>
60
- console.error('[user-chat-job] requeue failed', error),
60
+ console.warn('[user-chat-job] requeue failed', error),
61
61
  ),
62
62
  );
63
63
 
@@ -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,18 @@
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
+
13
22
  const { registerServerErrorSentryLogging } = await import('./utils/errorReporting/registerServerErrorSentryLogging');
14
23
  registerServerErrorSentryLogging();
15
24
 
@@ -25,3 +34,10 @@ export async function register(): Promise<void> {
25
34
  });
26
35
  }
27
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
+ });
@@ -37,7 +37,7 @@ export async function readConfiguredCodeRunner(): Promise<ConfiguredCodeRunner>
37
37
  >;
38
38
 
39
39
  return {
40
- agent: environmentByKey.PTBK_AGENT || process.env.PTBK_AGENT || 'github-copilot',
40
+ agent: environmentByKey.PTBK_HARNESS || process.env.PTBK_HARNESS || process.env.PTBK_AGENT || 'github-copilot',
41
41
  model: environmentByKey.PTBK_MODEL || process.env.PTBK_MODEL || 'gpt-5.4',
42
42
  thinkingLevel: environmentByKey.PTBK_THINKING_LEVEL || process.env.PTBK_THINKING_LEVEL || 'xhigh',
43
43
  };
@@ -0,0 +1,203 @@
1
+ import { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION } from '../../../../../src/version';
2
+ import {
3
+ createSentrySdkTags,
4
+ resolveSentrySdkCommitHash,
5
+ resolveSentrySdkEnvironment,
6
+ resolveSentrySdkRelease,
7
+ resolveSentrySdkRepositoryBranch,
8
+ } from './sentrySdkConfig';
9
+ import type { SentryStorePayload } from './sentryStore';
10
+
11
+ /**
12
+ * Shared deployment and runtime context added to every Agents Server Sentry event.
13
+ */
14
+ type AgentsServerSentryContext = {
15
+ /**
16
+ * Sentry release identifier.
17
+ */
18
+ readonly release: string;
19
+
20
+ /**
21
+ * Sentry environment identifier.
22
+ */
23
+ readonly environment: string;
24
+
25
+ /**
26
+ * Filterable Sentry tags.
27
+ */
28
+ readonly tags: Record<string, string>;
29
+
30
+ /**
31
+ * Full non-secret diagnostic context.
32
+ */
33
+ readonly extra: Record<string, unknown>;
34
+ };
35
+
36
+ /**
37
+ * Adds shared Agents Server release, environment, version, deployment, git, and runtime details.
38
+ *
39
+ * @param payload - Event-specific Sentry payload.
40
+ * @returns Payload enriched with common Agents Server diagnostics.
41
+ *
42
+ * @private internal helper for Agents Server Sentry reporting
43
+ */
44
+ export function enrichSentryStorePayloadWithAgentsServerContext(payload: SentryStorePayload): SentryStorePayload {
45
+ const context = createAgentsServerSentryContext();
46
+
47
+ return {
48
+ ...payload,
49
+ release: context.release,
50
+ environment: context.environment,
51
+ tags: {
52
+ ...context.tags,
53
+ ...payload.tags,
54
+ },
55
+ extra: {
56
+ ...context.extra,
57
+ ...payload.extra,
58
+ },
59
+ };
60
+ }
61
+
62
+ /**
63
+ * Creates a current Agents Server diagnostic context matching the admin About page metadata.
64
+ *
65
+ * @returns Common Sentry context for one event.
66
+ *
67
+ * @private internal helper for Agents Server Sentry reporting
68
+ */
69
+ export function createAgentsServerSentryContext(): AgentsServerSentryContext {
70
+ const deploymentEnvironment = resolveSentrySdkEnvironment();
71
+ const appPackageVersion = normalizeOptionalString(process.env.npm_package_version) ?? PROMPTBOOK_ENGINE_VERSION;
72
+ const commitHash = resolveSentrySdkCommitHash();
73
+ const repositoryBranch = resolveSentrySdkRepositoryBranch();
74
+ const memoryUsage = process.memoryUsage();
75
+
76
+ return {
77
+ release: resolveSentrySdkRelease(),
78
+ environment: deploymentEnvironment,
79
+ tags: createSentrySdkTags(),
80
+ extra: {
81
+ agentsServer: {
82
+ versions: {
83
+ promptbookEngineVersion: PROMPTBOOK_ENGINE_VERSION,
84
+ bookLanguageVersion: BOOK_LANGUAGE_VERSION,
85
+ appPackageVersion,
86
+ appPackageName: normalizeOptionalString(process.env.npm_package_name),
87
+ nextBuildId: normalizeOptionalString(process.env.NEXT_BUILD_ID),
88
+ nextDistDirectory: normalizeOptionalString(process.env.NEXT_DIST_DIR),
89
+ npmLifecycleEvent: normalizeOptionalString(process.env.npm_lifecycle_event),
90
+ npmUserAgent: normalizeOptionalString(process.env.npm_config_user_agent),
91
+ },
92
+ deployment: {
93
+ environment: deploymentEnvironment,
94
+ vercelEnvironment: getFirstNonEmptyString(process.env.NEXT_PUBLIC_VERCEL_ENV, process.env.VERCEL_ENV),
95
+ targetEnvironment: getFirstNonEmptyString(
96
+ process.env.NEXT_PUBLIC_VERCEL_TARGET_ENV,
97
+ process.env.VERCEL_TARGET_ENV,
98
+ ),
99
+ siteUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_SITE_URL),
100
+ vercelUrl: getFirstNonEmptyString(process.env.NEXT_PUBLIC_VERCEL_URL, process.env.VERCEL_URL),
101
+ vercelBranchUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL),
102
+ vercelProductionUrl: normalizeOptionalString(process.env.NEXT_PUBLIC_VERCEL_PROJECT_PRODUCTION_URL),
103
+ vercelRegion: normalizeOptionalString(process.env.VERCEL_REGION),
104
+ repositoryRef: normalizeOptionalString(process.env.PROMPTBOOK_REPOSITORY_REF),
105
+ supabaseTablePrefix: normalizeOptionalString(process.env.SUPABASE_TABLE_PREFIX),
106
+ currentWorkingDirectory: process.cwd(),
107
+ },
108
+ git: {
109
+ provider: getFirstNonEmptyString(
110
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER,
111
+ process.env.VERCEL_GIT_PROVIDER,
112
+ ),
113
+ repositoryOwner: getFirstNonEmptyString(
114
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER,
115
+ process.env.VERCEL_GIT_REPO_OWNER,
116
+ ),
117
+ repositorySlug: getFirstNonEmptyString(
118
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG,
119
+ process.env.VERCEL_GIT_REPO_SLUG,
120
+ ),
121
+ repositoryId: getFirstNonEmptyString(
122
+ process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_ID,
123
+ process.env.VERCEL_GIT_REPO_ID,
124
+ ),
125
+ commitHash,
126
+ previousCommitHash: getFirstNonEmptyString(
127
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PREVIOUS_SHA,
128
+ process.env.VERCEL_GIT_PREVIOUS_SHA,
129
+ ),
130
+ branch: repositoryBranch,
131
+ commitMessage: getFirstNonEmptyString(
132
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE,
133
+ process.env.VERCEL_GIT_COMMIT_MESSAGE,
134
+ ),
135
+ authorName: getFirstNonEmptyString(
136
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME,
137
+ process.env.VERCEL_GIT_COMMIT_AUTHOR_NAME,
138
+ ),
139
+ authorLogin: getFirstNonEmptyString(
140
+ process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
141
+ process.env.VERCEL_GIT_COMMIT_AUTHOR_LOGIN,
142
+ ),
143
+ pullRequestId: getFirstNonEmptyString(
144
+ process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID,
145
+ process.env.VERCEL_GIT_PULL_REQUEST_ID,
146
+ ),
147
+ },
148
+ runtime: {
149
+ nodeVersion: process.version,
150
+ nodeEnvironment: normalizeOptionalString(process.env.NODE_ENV),
151
+ nextRuntime: normalizeOptionalString(process.env.NEXT_RUNTIME),
152
+ processId: process.pid,
153
+ processUptimeSeconds: process.uptime(),
154
+ hostname: getFirstNonEmptyString(process.env.HOSTNAME, process.env.COMPUTERNAME),
155
+ platform: process.platform,
156
+ architecture: process.arch,
157
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC',
158
+ },
159
+ memory: {
160
+ rssBytes: memoryUsage.rss,
161
+ heapUsedBytes: memoryUsage.heapUsed,
162
+ heapTotalBytes: memoryUsage.heapTotal,
163
+ externalBytes: memoryUsage.external,
164
+ arrayBuffersBytes: memoryUsage.arrayBuffers ?? 0,
165
+ },
166
+ },
167
+ },
168
+ };
169
+ }
170
+
171
+ /**
172
+ * Returns the first non-empty string from a list.
173
+ *
174
+ * @param values - Candidate values in priority order.
175
+ * @returns First trimmed string or null.
176
+ */
177
+ function getFirstNonEmptyString(...values: Array<string | null | undefined>): string | null {
178
+ for (const value of values) {
179
+ const normalizedValue = normalizeOptionalString(value);
180
+
181
+ if (normalizedValue) {
182
+ return normalizedValue;
183
+ }
184
+ }
185
+
186
+ return null;
187
+ }
188
+
189
+ /**
190
+ * Trims one optional environment value.
191
+ *
192
+ * @param value - Raw optional value.
193
+ * @returns Trimmed string or null.
194
+ */
195
+ function normalizeOptionalString(value: string | null | undefined): string | null {
196
+ if (typeof value !== 'string') {
197
+ return null;
198
+ }
199
+
200
+ const normalizedValue = value.trim();
201
+
202
+ return normalizedValue || null;
203
+ }
@@ -1,5 +1,8 @@
1
1
  import { inspect } from 'node:util';
2
+ import * as Sentry from '@sentry/nextjs';
2
3
  import { DEFAULT_APPLICATION_ERROR_SERVER_NAME } from './applicationErrorHandling';
4
+ import { createAgentsServerSentryContext } from './agentsServerSentryContext';
5
+ import { enrichSentryStorePayloadWithAgentsServerContext } from './agentsServerSentryContext';
3
6
  import {
4
7
  createSentryTimestamp,
5
8
  resolveOptionalSentryDsn,
@@ -81,13 +84,17 @@ export function registerServerErrorSentryLogging(): void {
81
84
  console.error = (...consoleArguments: unknown[]): void => {
82
85
  loggingState.originalConsoleError?.(...consoleArguments);
83
86
 
87
+ const sentryPayload = createServerErrorSentryStorePayload(consoleArguments);
88
+
89
+ if (captureServerErrorWithSentrySdk(sentryPayload)) {
90
+ return;
91
+ }
92
+
84
93
  const sentryDsn = resolveOptionalSentryDsn();
85
94
  if (!sentryDsn) {
86
95
  return;
87
96
  }
88
97
 
89
- const sentryPayload = createServerErrorSentryStorePayload(consoleArguments);
90
-
91
98
  // Never log reporting failures through `console.error`, otherwise a broken Sentry configuration would recurse.
92
99
  void sendSentryStorePayload(sentryPayload, sentryDsn).catch(() => undefined);
93
100
  };
@@ -144,7 +151,7 @@ function getServerErrorSentryLoggingState(): ServerErrorSentryLoggingState {
144
151
  function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[]): SentryStorePayload {
145
152
  const loggedError = findLoggedErrorInfo(consoleArguments);
146
153
 
147
- return {
154
+ return enrichSentryStorePayloadWithAgentsServerContext({
148
155
  platform: 'javascript',
149
156
  level: 'error',
150
157
  logger: SENTRY_SERVER_ERROR_LOGGER,
@@ -153,8 +160,6 @@ function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[
153
160
  server_name: process.env.NEXT_PUBLIC_SERVER_NAME ?? DEFAULT_APPLICATION_ERROR_SERVER_NAME,
154
161
  tags: {
155
162
  source: 'agents-server.console-error',
156
- nextRuntime: process.env.NEXT_RUNTIME ?? 'nodejs',
157
- nodeEnv: process.env.NODE_ENV ?? 'unknown',
158
163
  },
159
164
  exception: loggedError
160
165
  ? {
@@ -169,11 +174,56 @@ function createServerErrorSentryStorePayload(consoleArguments: readonly unknown[
169
174
  extra: {
170
175
  consoleArguments: consoleArguments.map(serializeConsoleArgument),
171
176
  errorStack: loggedError?.stack ?? null,
172
- vercelEnv: process.env.VERCEL_ENV ?? null,
173
- vercelRegion: process.env.VERCEL_REGION ?? null,
174
- vercelUrl: process.env.VERCEL_URL ?? null,
175
177
  },
176
- };
178
+ });
179
+ }
180
+
181
+ /**
182
+ * Captures a server-side console error through the official Sentry SDK when it is initialized.
183
+ *
184
+ * @param sentryPayload - Structured event payload created from the original `console.error` call.
185
+ * @returns True when the SDK accepted the event.
186
+ */
187
+ function captureServerErrorWithSentrySdk(sentryPayload: SentryStorePayload): boolean {
188
+ if (!Sentry.getClient()) {
189
+ return false;
190
+ }
191
+
192
+ const agentsServerContext = createAgentsServerSentryContext();
193
+
194
+ Sentry.captureException(createServerErrorSdkException(sentryPayload), {
195
+ level: sentryPayload.level,
196
+ tags: {
197
+ ...agentsServerContext.tags,
198
+ ...sentryPayload.tags,
199
+ },
200
+ extra: {
201
+ ...agentsServerContext.extra,
202
+ ...sentryPayload.extra,
203
+ },
204
+ });
205
+
206
+ return true;
207
+ }
208
+
209
+ /**
210
+ * Rebuilds an `Error` object from the structured Sentry payload so the SDK can parse stack frames.
211
+ *
212
+ * @param sentryPayload - Structured event payload created from the original `console.error` call.
213
+ * @returns Error object with the original stack when one was logged.
214
+ */
215
+ function createServerErrorSdkException(sentryPayload: SentryStorePayload): Error {
216
+ const error = new Error(sentryPayload.message);
217
+ const exceptionValue = sentryPayload.exception?.values.at(0);
218
+ const errorStack = sentryPayload.extra?.errorStack;
219
+
220
+ error.name = exceptionValue?.type ?? 'Error';
221
+
222
+ if (typeof errorStack === 'string' && errorStack.trim()) {
223
+ error.stack = errorStack;
224
+ }
225
+
226
+ return error;
177
227
  }
178
228
 
179
229
  /**
@@ -1,4 +1,6 @@
1
+ import * as Sentry from '@sentry/nextjs';
1
2
  import type { ApplicationErrorReportPayload } from './applicationErrorHandling';
3
+ import { enrichSentryStorePayloadWithAgentsServerContext } from './agentsServerSentryContext';
2
4
  import {
3
5
  createSentryTimestamp,
4
6
  resolveRequiredSentryDsn,
@@ -18,7 +20,7 @@ const SENTRY_APPLICATION_ERROR_LOGGER = 'agents-server.application-error';
18
20
  * @returns Sentry store payload.
19
21
  */
20
22
  function createSentryStorePayload(report: ApplicationErrorReportPayload): SentryStorePayload {
21
- return {
23
+ return enrichSentryStorePayloadWithAgentsServerContext({
22
24
  platform: 'javascript',
23
25
  level: 'error',
24
26
  logger: SENTRY_APPLICATION_ERROR_LOGGER,
@@ -44,7 +46,7 @@ function createSentryStorePayload(report: ApplicationErrorReportPayload): Sentry
44
46
  pageUrl: report.pageUrl ?? null,
45
47
  reportedAt: report.reportedAt,
46
48
  },
47
- };
49
+ });
48
50
  }
49
51
 
50
52
  /**
@@ -53,5 +55,39 @@ function createSentryStorePayload(report: ApplicationErrorReportPayload): Sentry
53
55
  * @param report - Structured browser report payload.
54
56
  */
55
57
  export async function sendApplicationErrorReportToSentry(report: ApplicationErrorReportPayload): Promise<void> {
56
- await sendSentryStorePayload(createSentryStorePayload(report), resolveRequiredSentryDsn());
58
+ const sentryPayload = createSentryStorePayload(report);
59
+
60
+ if (Sentry.getClient()) {
61
+ Sentry.captureException(createApplicationErrorSdkException(report, sentryPayload), {
62
+ level: sentryPayload.level,
63
+ tags: sentryPayload.tags,
64
+ extra: sentryPayload.extra,
65
+ });
66
+ await Sentry.flush(2000);
67
+ return;
68
+ }
69
+
70
+ await sendSentryStorePayload(sentryPayload, resolveRequiredSentryDsn());
71
+ }
72
+
73
+ /**
74
+ * Rebuilds an `Error` object from a browser application report so the SDK can parse stack frames.
75
+ *
76
+ * @param report - Browser-generated application error report.
77
+ * @param sentryPayload - Structured Sentry payload created from the report.
78
+ * @returns Error object with the original browser stack when available.
79
+ */
80
+ function createApplicationErrorSdkException(
81
+ report: ApplicationErrorReportPayload,
82
+ sentryPayload: SentryStorePayload,
83
+ ): Error {
84
+ const error = new Error(sentryPayload.message);
85
+
86
+ error.name = report.errorName || 'Error';
87
+
88
+ if (report.errorStack?.trim()) {
89
+ error.stack = report.errorStack;
90
+ }
91
+
92
+ return error;
57
93
  }