@promptbook/cli 0.112.0-88 → 0.112.0-90

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 (27) hide show
  1. package/apps/agents-server/next.config.ts +58 -3
  2. package/apps/agents-server/src/database/ensureAutomaticDatabaseMigrations.ts +8 -1
  3. package/apps/agents-server/src/database/runDatabaseMigrations.ts +31 -1
  4. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +2 -2
  5. package/apps/agents-server/src/middleware/createMiddlewareRequestContext.ts +1 -1
  6. package/apps/agents-server/src/tools/$provideServer.ts +27 -0
  7. package/apps/agents-server/src/utils/serverRegistry.ts +117 -3
  8. package/esm/apps/agents-server/src/utils/serverRegistry.d.ts +6 -0
  9. package/esm/index.es.js +348 -17
  10. package/esm/index.es.js.map +1 -1
  11. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +31 -0
  12. package/esm/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +6 -0
  13. package/esm/src/version.d.ts +1 -1
  14. package/package.json +5 -3
  15. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +330 -8
  16. package/src/cli/cli-commands/agents-server/run.ts +2 -1
  17. package/src/cli/cli-commands/agents-server/startAgentsServer.ts +40 -16
  18. package/src/other/templates/getTemplatesPipelineCollection.ts +691 -794
  19. package/src/version.ts +2 -2
  20. package/src/versions.txt +2 -0
  21. package/umd/apps/agents-server/src/utils/serverRegistry.d.ts +6 -0
  22. package/umd/index.umd.js +346 -15
  23. package/umd/index.umd.js.map +1 -1
  24. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer.d.ts +31 -0
  25. package/umd/src/cli/cli-commands/agents-server/startAgentsServer.d.ts +6 -0
  26. package/umd/src/version.d.ts +1 -1
  27. package/src/wizard/test/sub/subsub/subsubsub/.promptbook/executions-cache/8/c/report-whoami-6e340b9cffb37a98.json +0 -104
@@ -1,4 +1,17 @@
1
1
  /// <reference types="node" />
2
+ /**
3
+ * Environment variable passed to the bundled Next app so webpack can resolve dependencies
4
+ * installed beside `ptbk` even when the app sources are materialized into a project cache.
5
+ *
6
+ * @private internal constant of `ptbk agents-server`
7
+ */
8
+ export declare const PTBK_AGENTS_SERVER_NODE_MODULES_PATH_ENV = "PTBK_AGENTS_SERVER_NODE_MODULES_PATH";
9
+ /**
10
+ * Environment variable used only by the CLI-owned production build.
11
+ *
12
+ * @private internal constant of `ptbk agents-server`
13
+ */
14
+ export declare const PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV = "PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION";
2
15
  /**
3
16
  * Inputs controlling one cached Agents Server production build.
4
17
  *
@@ -18,6 +31,7 @@ type EnsureAgentsServerBuildOptions = {
18
31
  */
19
32
  export type AgentsServerBuildArtifacts = {
20
33
  readonly appPath: string;
34
+ readonly nodeModulesPath: string;
21
35
  readonly nextCliPath: string;
22
36
  };
23
37
  /**
@@ -53,4 +67,21 @@ export declare function writeAgentsServerBuildCache(options: AgentsServerBuildCa
53
67
  * @private internal utility of `ptbk agents-server`
54
68
  */
55
69
  export declare function resolveAgentsServerAppPath(): Promise<string>;
70
+ /**
71
+ * Adds dependency-resolution environment required by the materialized Agents Server runtime.
72
+ *
73
+ * @private internal utility of `ptbk agents-server`
74
+ */
75
+ export declare function createAgentsServerRuntimeEnvironment(environment: NodeJS.ProcessEnv, nodeModulesPath: string, options?: {
76
+ readonly isNextValidationIgnored?: boolean;
77
+ }): NodeJS.ProcessEnv;
78
+ /**
79
+ * Uses the source checkout app directly, but copies npm-packaged app sources out of `node_modules`.
80
+ *
81
+ * @private internal utility of `ptbk agents-server`
82
+ */
83
+ export declare function resolveAgentsServerBuildAppPath(options: {
84
+ readonly nodeModulesPath: string;
85
+ readonly sourceAppPath: string;
86
+ }): Promise<string>;
56
87
  export {};
@@ -21,3 +21,9 @@ export type StartAgentsServerOptions = {
21
21
  * @private internal utility of `ptbk agents-server`
22
22
  */
23
23
  export declare function startAgentsServer(options: StartAgentsServerOptions): Promise<void>;
24
+ /**
25
+ * Loads launch-directory `.env` values without overriding explicit process environment.
26
+ *
27
+ * @private internal utility of `ptbk agents-server`
28
+ */
29
+ export declare function loadAgentsServerProjectEnvironment(launchWorkingDirectory: string): void;
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
15
15
  export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
16
16
  /**
17
17
  * Represents the version string of the Promptbook engine.
18
- * It follows semantic versioning (e.g., `0.112.0-82`).
18
+ * It follows semantic versioning (e.g., `0.112.0-89`).
19
19
  *
20
20
  * @generated
21
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptbook/cli",
3
- "version": "0.112.0-88",
3
+ "version": "0.112.0-90",
4
4
  "description": "Promptbook: Create persistent AI agents that turn your company's scattered knowledge into action",
5
5
  "private": false,
6
6
  "sideEffects": false,
@@ -121,8 +121,8 @@
121
121
  "papaparse": "5.4.1",
122
122
  "pg": "8.16.3",
123
123
  "prompts": "2.4.2",
124
- "react": "18.2.0",
125
- "react-dom": "18.2.0",
124
+ "react": "19.1.2",
125
+ "react-dom": "19.1.2",
126
126
  "rxjs": "7.8.2",
127
127
  "showdown": "2.1.0",
128
128
  "socket.io": "4.8.3",
@@ -136,8 +136,10 @@
136
136
  "typescript": "5.2.2",
137
137
  "ts-node": "10.9.2",
138
138
  "next": "15.4.11",
139
+ "lucide-react": "0.536.0",
139
140
  "raw-loader": "^4.0.2",
140
141
  "tailwindcss": "3.4.19",
142
+ "@tailwindcss/typography": "0.5.19",
141
143
  "postcss": "8.5.12",
142
144
  "autoprefixer": "10.4.27",
143
145
  "@ai-sdk/openai": "1.0.20",
@@ -1,9 +1,10 @@
1
1
  import { spawn } from 'child_process';
2
2
  import { createHash, type Hash } from 'crypto';
3
- import { mkdir, readFile, readdir, stat, writeFile } from 'fs/promises';
4
- import { basename, join, relative, resolve } from 'path';
3
+ import { cp, lstat, mkdir, readFile, readdir, rm, stat, symlink, writeFile } from 'fs/promises';
4
+ import { basename, delimiter, dirname, join, relative, resolve } from 'path';
5
5
  import { spaceTrim } from 'spacetrim';
6
6
  import { NotAllowed } from '../../../errors/NotAllowed';
7
+ import { resolvePromptbookTemporaryPath } from '../../../utils/filesystem/promptbookTemporaryPath';
7
8
 
8
9
  /**
9
10
  * Version of the CLI-owned Agents Server build cache metadata.
@@ -33,6 +34,35 @@ const AGENTS_SERVER_NEXT_BUILD_ID_FILENAME = 'BUILD_ID';
33
34
  */
34
35
  const DEFAULT_AGENTS_SERVER_NEXT_DIST_DIRECTORY_NAME = '.next';
35
36
 
37
+ /**
38
+ * Environment variable passed to the bundled Next app so webpack can resolve dependencies
39
+ * installed beside `ptbk` even when the app sources are materialized into a project cache.
40
+ *
41
+ * @private internal constant of `ptbk agents-server`
42
+ */
43
+ export const PTBK_AGENTS_SERVER_NODE_MODULES_PATH_ENV = 'PTBK_AGENTS_SERVER_NODE_MODULES_PATH';
44
+
45
+ /**
46
+ * Environment variable used only by the CLI-owned production build.
47
+ *
48
+ * @private internal constant of `ptbk agents-server`
49
+ */
50
+ export const PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV = 'PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION';
51
+
52
+ /**
53
+ * Runtime copy metadata filename stored in the project-local materialized app root.
54
+ *
55
+ * @private internal constant of `ptbk agents-server`
56
+ */
57
+ const AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME = '.ptbk-agents-server-runtime-cache.json';
58
+
59
+ /**
60
+ * Directory segment used for Node package installs.
61
+ *
62
+ * @private internal constant of `ptbk agents-server`
63
+ */
64
+ const NODE_MODULES_DIRECTORY_NAME = 'node_modules';
65
+
36
66
  /**
37
67
  * Runtime paths copied into the CLI package and used by the Agents Server production build.
38
68
  *
@@ -83,6 +113,16 @@ type AgentsServerBuildCache = {
83
113
  readonly sourceFingerprint: string;
84
114
  };
85
115
 
116
+ /**
117
+ * Metadata persisted after copying the npm-packaged Agents Server runtime into the launch project.
118
+ *
119
+ * @private internal type of `ptbk agents-server`
120
+ */
121
+ type AgentsServerMaterializedRuntimeCache = {
122
+ readonly version: typeof AGENTS_SERVER_BUILD_CACHE_VERSION;
123
+ readonly sourceFingerprint: string;
124
+ };
125
+
86
126
  /**
87
127
  * Inputs controlling one cached Agents Server production build.
88
128
  *
@@ -103,6 +143,7 @@ type EnsureAgentsServerBuildOptions = {
103
143
  */
104
144
  export type AgentsServerBuildArtifacts = {
105
145
  readonly appPath: string;
146
+ readonly nodeModulesPath: string;
106
147
  readonly nextCliPath: string;
107
148
  };
108
149
 
@@ -124,31 +165,38 @@ type AgentsServerBuildCacheOptions = {
124
165
  export async function ensureAgentsServerBuild(
125
166
  options: EnsureAgentsServerBuildOptions = {},
126
167
  ): Promise<AgentsServerBuildArtifacts> {
127
- const appPath = options.appPath ?? (await resolveAgentsServerAppPath());
128
168
  const environment = options.environment ?? process.env;
129
169
  const nextCliPath = resolveNextCliPath();
170
+ const nodeModulesPath = resolveNodeModulesPath(nextCliPath);
171
+ const appPath = await resolveAgentsServerBuildAppPath({
172
+ sourceAppPath: options.appPath ?? (await resolveAgentsServerAppPath()),
173
+ nodeModulesPath,
174
+ });
175
+ const buildEnvironment = createAgentsServerRuntimeEnvironment(environment, nodeModulesPath, {
176
+ isNextValidationIgnored: isAgentsServerAppPathMaterialized(appPath),
177
+ });
130
178
 
131
179
  if (
132
180
  !options.isBuildForced &&
133
181
  (await isAgentsServerBuildCacheCurrent({
134
182
  appPath,
135
- environment,
183
+ environment: buildEnvironment,
136
184
  }))
137
185
  ) {
138
186
  options.onBuildEvent?.('Using the cached Agents Server Next app build.');
139
- return { appPath, nextCliPath };
187
+ return { appPath, nextCliPath, nodeModulesPath };
140
188
  }
141
189
 
142
190
  options.onBuildEvent?.('Building the Agents Server Next app.');
143
191
  await runNextBuild({
144
192
  appPath,
145
- environment,
193
+ environment: buildEnvironment,
146
194
  nextCliPath,
147
195
  onBuildOutput: options.onBuildOutput,
148
196
  });
149
- await writeAgentsServerBuildCache({ appPath, environment });
197
+ await writeAgentsServerBuildCache({ appPath, environment: buildEnvironment });
150
198
 
151
- return { appPath, nextCliPath };
199
+ return { appPath, nextCliPath, nodeModulesPath };
152
200
  }
153
201
 
154
202
  /**
@@ -220,6 +268,233 @@ export async function resolveAgentsServerAppPath(): Promise<string> {
220
268
  );
221
269
  }
222
270
 
271
+ /**
272
+ * Adds dependency-resolution environment required by the materialized Agents Server runtime.
273
+ *
274
+ * @private internal utility of `ptbk agents-server`
275
+ */
276
+ export function createAgentsServerRuntimeEnvironment(
277
+ environment: NodeJS.ProcessEnv,
278
+ nodeModulesPath: string,
279
+ options: {
280
+ readonly isNextValidationIgnored?: boolean;
281
+ } = {},
282
+ ): NodeJS.ProcessEnv {
283
+ return {
284
+ ...environment,
285
+ NODE_PATH: mergeNodePath(nodeModulesPath, environment.NODE_PATH),
286
+ [PTBK_AGENTS_SERVER_NODE_MODULES_PATH_ENV]: nodeModulesPath,
287
+ ...(options.isNextValidationIgnored
288
+ ? {
289
+ [PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV]: 'true',
290
+ }
291
+ : {}),
292
+ };
293
+ }
294
+
295
+ /**
296
+ * Uses the source checkout app directly, but copies npm-packaged app sources out of `node_modules`.
297
+ *
298
+ * @private internal utility of `ptbk agents-server`
299
+ */
300
+ export async function resolveAgentsServerBuildAppPath(options: {
301
+ readonly nodeModulesPath: string;
302
+ readonly sourceAppPath: string;
303
+ }): Promise<string> {
304
+ if (!isPathInsideNodeModules(options.sourceAppPath)) {
305
+ return options.sourceAppPath;
306
+ }
307
+
308
+ const sourceRuntimeRootPath = resolve(options.sourceAppPath, '..', '..');
309
+ const materializedRuntimeRootPath = resolvePromptbookTemporaryPath(process.cwd(), 'agents-server', 'runtime');
310
+
311
+ await synchronizeMaterializedAgentsServerRuntime({
312
+ materializedRuntimeRootPath,
313
+ nodeModulesPath: options.nodeModulesPath,
314
+ sourceAppPath: options.sourceAppPath,
315
+ sourceRuntimeRootPath,
316
+ });
317
+
318
+ return join(materializedRuntimeRootPath, 'apps', 'agents-server');
319
+ }
320
+
321
+ /**
322
+ * Copies the bundled runtime into the launch project when the original app lives under `node_modules`.
323
+ */
324
+ async function synchronizeMaterializedAgentsServerRuntime(options: {
325
+ readonly materializedRuntimeRootPath: string;
326
+ readonly nodeModulesPath: string;
327
+ readonly sourceAppPath: string;
328
+ readonly sourceRuntimeRootPath: string;
329
+ }): Promise<void> {
330
+ const sourceFingerprint = await createAgentsServerBuildSourceFingerprint(options.sourceAppPath);
331
+ const runtimeCache = await readAgentsServerMaterializedRuntimeCache(options.materializedRuntimeRootPath);
332
+ const isRuntimeCurrent =
333
+ runtimeCache?.version === AGENTS_SERVER_BUILD_CACHE_VERSION &&
334
+ runtimeCache.sourceFingerprint === sourceFingerprint &&
335
+ (await isAgentsServerAppPath(join(options.materializedRuntimeRootPath, 'apps', 'agents-server')));
336
+
337
+ if (!isRuntimeCurrent) {
338
+ await rm(options.materializedRuntimeRootPath, { recursive: true, force: true });
339
+ await mkdir(options.materializedRuntimeRootPath, { recursive: true });
340
+
341
+ for (const relativeInputPath of AGENTS_SERVER_BUILD_INPUT_RELATIVE_PATHS) {
342
+ await copyAgentsServerRuntimePath({
343
+ destinationPath: join(options.materializedRuntimeRootPath, relativeInputPath),
344
+ sourcePath: join(options.sourceRuntimeRootPath, relativeInputPath),
345
+ });
346
+ }
347
+
348
+ await assertMaterializedAgentsServerAppExists(options.materializedRuntimeRootPath);
349
+ await writeAgentsServerMaterializedRuntimeCache(options.materializedRuntimeRootPath, sourceFingerprint);
350
+ }
351
+
352
+ await ensureMaterializedRuntimeNodeModulesLink({
353
+ materializedRuntimeRootPath: options.materializedRuntimeRootPath,
354
+ nodeModulesPath: options.nodeModulesPath,
355
+ });
356
+ }
357
+
358
+ /**
359
+ * Verifies that the materialized runtime contains a usable Next app before caching it.
360
+ */
361
+ async function assertMaterializedAgentsServerAppExists(materializedRuntimeRootPath: string): Promise<void> {
362
+ const materializedAppPath = join(materializedRuntimeRootPath, 'apps', 'agents-server');
363
+
364
+ if (await isAgentsServerAppPath(materializedAppPath)) {
365
+ return;
366
+ }
367
+
368
+ throw new NotAllowed(
369
+ spaceTrim(`
370
+ Cannot prepare the bundled Agents Server runtime.
371
+
372
+ The materialized app path is missing required files:
373
+ \`${materializedAppPath}\`
374
+ `),
375
+ );
376
+ }
377
+
378
+ /**
379
+ * Copies one source path into the materialized runtime, skipping generated or private files.
380
+ */
381
+ async function copyAgentsServerRuntimePath(options: {
382
+ readonly destinationPath: string;
383
+ readonly sourcePath: string;
384
+ }): Promise<void> {
385
+ let sourceStats;
386
+
387
+ try {
388
+ sourceStats = await stat(options.sourcePath);
389
+ } catch {
390
+ return;
391
+ }
392
+
393
+ await mkdir(dirname(options.destinationPath), { recursive: true });
394
+
395
+ if (sourceStats.isDirectory()) {
396
+ await cp(options.sourcePath, options.destinationPath, {
397
+ recursive: true,
398
+ filter: (sourcePath) => shouldCopyAgentsServerRuntimePath(sourcePath, options.sourcePath),
399
+ });
400
+ return;
401
+ }
402
+
403
+ if (sourceStats.isFile() && shouldCopyAgentsServerRuntimePath(options.sourcePath, dirname(options.sourcePath))) {
404
+ await cp(options.sourcePath, options.destinationPath);
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Excludes build artifacts, dependency folders, private env files, and test sources.
410
+ */
411
+ function shouldCopyAgentsServerRuntimePath(sourcePath: string, sourceRootPath: string): boolean {
412
+ const sourceRelativePath = relative(sourceRootPath, sourcePath).replace(/\\/gu, '/');
413
+ const sourcePathSegments = sourceRelativePath.split('/').filter(Boolean);
414
+ const sourceBasename = basename(sourcePath);
415
+
416
+ if (
417
+ sourcePathSegments.some((sourcePathSegment) =>
418
+ AGENTS_SERVER_BUILD_INPUT_EXCLUDED_DIRECTORY_NAMES.has(sourcePathSegment),
419
+ )
420
+ ) {
421
+ return false;
422
+ }
423
+
424
+ if (sourceBasename.startsWith('.env')) {
425
+ return false;
426
+ }
427
+
428
+ return !AGENTS_SERVER_BUILD_INPUT_TEST_FILE_PATTERN.test(sourceBasename);
429
+ }
430
+
431
+ /**
432
+ * Links the materialized runtime back to the package dependency tree used by the installed CLI.
433
+ */
434
+ async function ensureMaterializedRuntimeNodeModulesLink(options: {
435
+ readonly materializedRuntimeRootPath: string;
436
+ readonly nodeModulesPath: string;
437
+ }): Promise<void> {
438
+ const nodeModulesLinkPath = join(options.materializedRuntimeRootPath, NODE_MODULES_DIRECTORY_NAME);
439
+
440
+ try {
441
+ const existingLinkStats = await lstat(nodeModulesLinkPath);
442
+ await rm(nodeModulesLinkPath, {
443
+ force: true,
444
+ recursive: existingLinkStats.isDirectory() && !existingLinkStats.isSymbolicLink(),
445
+ });
446
+ } catch {
447
+ // The link does not exist yet.
448
+ }
449
+
450
+ await symlink(options.nodeModulesPath, nodeModulesLinkPath, process.platform === 'win32' ? 'junction' : 'dir');
451
+ }
452
+
453
+ /**
454
+ * Reads and validates materialized runtime metadata.
455
+ */
456
+ async function readAgentsServerMaterializedRuntimeCache(
457
+ materializedRuntimeRootPath: string,
458
+ ): Promise<AgentsServerMaterializedRuntimeCache | undefined> {
459
+ try {
460
+ const serializedRuntimeCache = await readFile(
461
+ join(materializedRuntimeRootPath, AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME),
462
+ 'utf-8',
463
+ );
464
+ const runtimeCache = JSON.parse(serializedRuntimeCache) as Partial<AgentsServerMaterializedRuntimeCache>;
465
+
466
+ if (
467
+ runtimeCache.version !== AGENTS_SERVER_BUILD_CACHE_VERSION ||
468
+ typeof runtimeCache.sourceFingerprint !== 'string'
469
+ ) {
470
+ return undefined;
471
+ }
472
+
473
+ return runtimeCache as AgentsServerMaterializedRuntimeCache;
474
+ } catch {
475
+ return undefined;
476
+ }
477
+ }
478
+
479
+ /**
480
+ * Persists the source fingerprint used for the materialized runtime copy.
481
+ */
482
+ async function writeAgentsServerMaterializedRuntimeCache(
483
+ materializedRuntimeRootPath: string,
484
+ sourceFingerprint: string,
485
+ ): Promise<void> {
486
+ const runtimeCache: AgentsServerMaterializedRuntimeCache = {
487
+ version: AGENTS_SERVER_BUILD_CACHE_VERSION,
488
+ sourceFingerprint,
489
+ };
490
+
491
+ await writeFile(
492
+ join(materializedRuntimeRootPath, AGENTS_SERVER_MATERIALIZED_RUNTIME_CACHE_FILENAME),
493
+ `${JSON.stringify(runtimeCache, null, 4)}\n`,
494
+ 'utf-8',
495
+ );
496
+ }
497
+
223
498
  /**
224
499
  * Runs the finite Next production build used by local Agents Server commands.
225
500
  */
@@ -384,6 +659,53 @@ function resolveAgentsServerBuildOutputPath(options: AgentsServerBuildCacheOptio
384
659
  );
385
660
  }
386
661
 
662
+ /**
663
+ * Returns true when the app path points at the project-local materialized runtime.
664
+ */
665
+ function isAgentsServerAppPathMaterialized(appPath: string): boolean {
666
+ const normalizedAppPath = appPath.replace(/\\/gu, '/');
667
+ const normalizedMaterializedRuntimePath = resolvePromptbookTemporaryPath(
668
+ process.cwd(),
669
+ 'agents-server',
670
+ 'runtime',
671
+ ).replace(/\\/gu, '/');
672
+
673
+ return normalizedAppPath.includes(normalizedMaterializedRuntimePath);
674
+ }
675
+
676
+ /**
677
+ * Returns true when one path is nested below a `node_modules` segment.
678
+ */
679
+ function isPathInsideNodeModules(path: string): boolean {
680
+ return path.split(/[\\/]+/u).includes(NODE_MODULES_DIRECTORY_NAME);
681
+ }
682
+
683
+ /**
684
+ * Resolves the dependency root that contains the installed Next CLI.
685
+ */
686
+ function resolveNodeModulesPath(nextCliPath: string): string {
687
+ const normalizedNextCliPath = nextCliPath.replace(/\\/gu, '/');
688
+ const marker = `/${NODE_MODULES_DIRECTORY_NAME}/next/`;
689
+ const markerIndex = normalizedNextCliPath.lastIndexOf(marker);
690
+
691
+ if (markerIndex === -1) {
692
+ return resolve(nextCliPath, '..', '..', '..');
693
+ }
694
+
695
+ return normalizedNextCliPath.slice(0, markerIndex + marker.length - '/next/'.length);
696
+ }
697
+
698
+ /**
699
+ * Prepends one dependency root to `NODE_PATH` while preserving any existing value.
700
+ */
701
+ function mergeNodePath(nodeModulesPath: string, nodePath: string | undefined): string {
702
+ if (!nodePath) {
703
+ return nodeModulesPath;
704
+ }
705
+
706
+ return `${nodeModulesPath}${delimiter}${nodePath}`;
707
+ }
708
+
387
709
  /**
388
710
  * Returns true when one path exists as a regular file.
389
711
  */
@@ -17,7 +17,7 @@ import {
17
17
  PROMPT_RUNNER_DESCRIPTION,
18
18
  } from '../common/promptRunnerCliOptions';
19
19
  import { ensureAgentsServerBuild } from './buildAgentsServer';
20
- import { startAgentsServer } from './startAgentsServer';
20
+ import { loadAgentsServerProjectEnvironment, startAgentsServer } from './startAgentsServer';
21
21
 
22
22
  /**
23
23
  * Default port used by `ptbk agents-server start`.
@@ -102,6 +102,7 @@ export function $initializeAgentsServerBuildCommand(program: Program): $side_eff
102
102
  command.action(
103
103
  handleActionErrors(async () => {
104
104
  console.info(colors.gray('Building Promptbook Agents Server.'));
105
+ loadAgentsServerProjectEnvironment(process.cwd());
105
106
  await ensureAgentsServerBuild({ isBuildForced: true });
106
107
  }),
107
108
  );
@@ -14,7 +14,11 @@ import type { AgentRunOptions } from '../../../../scripts/run-agent-messages/Age
14
14
  import { runMultipleAgentMessages } from '../../../../scripts/run-agent-messages/main/runMultipleAgentMessages';
15
15
  import { withCurrentWorkingDirectory } from '../../../../scripts/run-agent-messages/main/withCurrentWorkingDirectory';
16
16
  import type { CoderRunUiHandle } from '../../../../scripts/run-codex-prompts/ui/renderCoderRunUi';
17
- import { ensureAgentsServerBuild, resolveAgentsServerAppPath } from './buildAgentsServer';
17
+ import {
18
+ createAgentsServerRuntimeEnvironment,
19
+ ensureAgentsServerBuild,
20
+ resolveAgentsServerAppPath,
21
+ } from './buildAgentsServer';
18
22
 
19
23
  /**
20
24
  * Local worker-pump delay while the Agents Server foreground process stays active.
@@ -79,6 +83,13 @@ const PTBK_AGENTS_SERVER_DATABASE_ENV = 'PTBK_AGENTS_SERVER_DATABASE';
79
83
  */
80
84
  const PTBK_AGENTS_SERVER_SQLITE_PATH_ENV = 'PTBK_AGENTS_SERVER_SQLITE_PATH';
81
85
 
86
+ /**
87
+ * Optional hostname used by the internal Next server.
88
+ *
89
+ * @private internal constant of `ptbk agents-server`
90
+ */
91
+ const PTBK_HOSTNAME_ENV = 'PTBK_HOSTNAME';
92
+
82
93
  /**
83
94
  * Entropy size for the local-only token shared by the CLI pump and the Next app.
84
95
  *
@@ -181,7 +192,7 @@ export async function startAgentsServer(options: StartAgentsServerOptions): Prom
181
192
  process.once('exit', processExitHandler);
182
193
 
183
194
  try {
184
- const { nextCliPath } = await ensureAgentsServerBuild({
195
+ const buildArtifacts = await ensureAgentsServerBuild({
185
196
  appPath: runtimePaths.appPath,
186
197
  environment: childEnvironment,
187
198
  isBuildForced: options.isBuildForced,
@@ -201,18 +212,26 @@ export async function startAgentsServer(options: StartAgentsServerOptions): Prom
201
212
  });
202
213
  },
203
214
  });
215
+ const runtimeChildEnvironment = createAgentsServerRuntimeEnvironment(
216
+ childEnvironment,
217
+ buildArtifacts.nodeModulesPath,
218
+ ) as AgentsServerChildEnvironment;
219
+ const builtRuntimePaths: AgentsServerRuntimePaths = {
220
+ ...runtimePaths,
221
+ appPath: buildArtifacts.appPath,
222
+ };
204
223
 
205
224
  nextServerProcess = startNextServer({
206
- nextCliPath,
225
+ nextCliPath: buildArtifacts.nextCliPath,
207
226
  options,
208
- runtimePaths,
209
- childEnvironment,
227
+ runtimePaths: builtRuntimePaths,
228
+ childEnvironment: runtimeChildEnvironment,
210
229
  logStreams,
211
230
  state,
212
231
  });
213
232
  stopUserChatJobWorkerPump = startUserChatJobWorkerPump({
214
233
  port: options.port,
215
- environment: childEnvironment,
234
+ environment: runtimeChildEnvironment,
216
235
  logStreams,
217
236
  state,
218
237
  });
@@ -243,8 +262,10 @@ export async function startAgentsServer(options: StartAgentsServerOptions): Prom
243
262
 
244
263
  /**
245
264
  * Loads launch-directory `.env` values without overriding explicit process environment.
265
+ *
266
+ * @private internal utility of `ptbk agents-server`
246
267
  */
247
- function loadAgentsServerProjectEnvironment(launchWorkingDirectory: string): void {
268
+ export function loadAgentsServerProjectEnvironment(launchWorkingDirectory: string): void {
248
269
  dotenv.config({ path: join(launchWorkingDirectory, AGENTS_SERVER_PROJECT_ENV_FILE_NAME) });
249
270
  }
250
271
 
@@ -278,16 +299,19 @@ function startNextServer(options: {
278
299
  readonly state: AgentsServerSupervisorState;
279
300
  }): ChildProcess {
280
301
  logRunnerEvent(options.logStreams.runner, 'Starting the Agents Server Next process.');
302
+ const nextArguments = [options.nextCliPath, 'start', '--port', String(options.options.port)];
303
+ const hostname = options.childEnvironment[PTBK_HOSTNAME_ENV]?.trim();
281
304
 
282
- const commandProcess = spawn(
283
- process.execPath,
284
- [options.nextCliPath, 'start', '--port', String(options.options.port)],
285
- {
286
- cwd: options.runtimePaths.appPath,
287
- env: options.childEnvironment,
288
- stdio: ['ignore', 'pipe', 'pipe'],
289
- },
290
- );
305
+ if (hostname) {
306
+ nextArguments.push('--hostname', hostname);
307
+ logRunnerEvent(options.logStreams.runner, `Binding Agents Server Next process to ${hostname}.`);
308
+ }
309
+
310
+ const commandProcess = spawn(process.execPath, nextArguments, {
311
+ cwd: options.runtimePaths.appPath,
312
+ env: options.childEnvironment,
313
+ stdio: ['ignore', 'pipe', 'pipe'],
314
+ });
291
315
 
292
316
  bindChildOutput(commandProcess, {
293
317
  label: 'next',