@promptbook/cli 0.114.0-2 → 0.114.0-3

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 (105) hide show
  1. package/apps/agents-server/next.config.ts +11 -0
  2. package/apps/agents-server/src/app/layout.tsx +6 -0
  3. package/esm/index.es.js +677 -199
  4. package/esm/index.es.js.map +1 -1
  5. package/esm/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +7 -0
  6. package/esm/scripts/run-codex-prompts/git/coderGitSync.d.ts +43 -0
  7. package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -0
  8. package/esm/scripts/run-codex-prompts/main/resolvePromptRunner.d.ts +8 -1
  9. package/esm/scripts/run-codex-prompts/ping/buildCoderPingPrompt.d.ts +20 -0
  10. package/esm/scripts/run-codex-prompts/ping/extractCoderPingAnswer.d.ts +9 -0
  11. package/esm/scripts/run-codex-prompts/ping/pingCoderHarness.d.ts +23 -0
  12. package/esm/scripts/run-codex-prompts/ping/printCoderPingResult.d.ts +5 -0
  13. package/esm/scripts/verify-prompts/verify-prompts.d.ts +5 -0
  14. package/esm/src/book-components/Chat/utils/$provideServerDomWindow.d.ts +11 -0
  15. package/esm/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerRuntimeEnvironment.d.ts +7 -0
  16. package/esm/src/cli/cli-commands/coder/ping.d.ts +2 -5
  17. package/esm/src/cli/cli-commands/coder.d.ts +1 -1
  18. package/esm/src/cli/cli-commands/common/coderGitSyncCliOptions.d.ts +34 -0
  19. package/esm/src/cli/cli-commands/common/coderGitSyncCliOptions.test.d.ts +1 -0
  20. package/esm/src/cli/common/loadPromptsModule.d.ts +16 -0
  21. package/esm/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +1 -1
  22. package/esm/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +1 -1
  23. package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +1 -1
  24. package/esm/src/llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder.d.ts +1 -1
  25. package/esm/src/llm-providers/openai/OpenAiAssistantExecutionToolsStreamRunner.d.ts +1 -1
  26. package/esm/src/llm-providers/openai/OpenAiAssistantExecutionToolsToolRunner.d.ts +1 -1
  27. package/esm/src/llm-providers/openai/OpenAiCompatibleNonChatPromptCaller.d.ts +1 -1
  28. package/esm/src/llm-providers/openai/OpenAiCompatibleRequestManager.d.ts +1 -1
  29. package/esm/src/llm-providers/openai/utils/callOpenAiCompatibleChatModel.d.ts +1 -1
  30. package/esm/src/llm-providers/openai/utils/loadOpenAiAgentsModule.d.ts +203 -0
  31. package/esm/src/llm-providers/openai/utils/uploadFilesToOpenAi.d.ts +1 -1
  32. package/esm/src/utils/misc/createLazyModuleLoader.d.ts +14 -0
  33. package/esm/src/version.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/src/book-3.0/LiteAgent.ts +11 -9
  36. package/src/book-components/Chat/utils/$provideServerDomWindow.ts +77 -0
  37. package/src/book-components/Chat/utils/renderMarkdown.ts +2 -23
  38. package/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerRuntimeEnvironment.ts +14 -0
  39. package/src/cli/cli-commands/agents-server/buildAgentsServer/ensureAgentsServerBuild.ts +1 -0
  40. package/src/cli/cli-commands/coder/add.ts +40 -12
  41. package/src/cli/cli-commands/coder/generate-boilerplates.ts +31 -5
  42. package/src/cli/cli-commands/coder/init.ts +27 -1
  43. package/src/cli/cli-commands/coder/ping.ts +23 -45
  44. package/src/cli/cli-commands/coder/verify.ts +27 -12
  45. package/src/cli/cli-commands/coder.ts +3 -3
  46. package/src/cli/cli-commands/common/coderGitSyncCliOptions.ts +78 -0
  47. package/src/cli/cli-commands/run/prepareRunCommandResources.ts +2 -1
  48. package/src/cli/cli-commands/run/resolveRunInputParameters.ts +2 -1
  49. package/src/cli/cli-commands/runInteractiveChatbot.ts +2 -1
  50. package/src/cli/common/$provideLlmToolsForCli.ts +2 -1
  51. package/src/cli/common/loadPromptsModule.ts +13 -0
  52. package/src/conversion/archive/loadArchive.ts +2 -1
  53. package/src/conversion/archive/loadJsZipModule.ts +10 -0
  54. package/src/conversion/archive/saveArchive.ts +2 -1
  55. package/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.ts +13 -1
  56. package/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.ts +13 -1
  57. package/src/llm-providers/openai/OpenAiAgentKitExecutionTools.ts +6 -2
  58. package/src/llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder.ts +7 -5
  59. package/src/llm-providers/openai/OpenAiAssistantExecutionTools.ts +1 -1
  60. package/src/llm-providers/openai/OpenAiAssistantExecutionToolsStreamRunner.ts +1 -1
  61. package/src/llm-providers/openai/OpenAiAssistantExecutionToolsToolRunner.ts +1 -1
  62. package/src/llm-providers/openai/OpenAiCompatibleNonChatPromptCaller.ts +1 -1
  63. package/src/llm-providers/openai/OpenAiCompatibleRequestManager.ts +12 -1
  64. package/src/llm-providers/openai/utils/callOpenAiCompatibleChatModel.ts +1 -1
  65. package/src/llm-providers/openai/utils/loadOpenAiAgentsModule.ts +11 -0
  66. package/src/llm-providers/openai/utils/uploadFilesToOpenAi.ts +1 -1
  67. package/src/other/templates/getTemplatesPipelineCollection.ts +678 -967
  68. package/src/remote-server/createRemoteClient.ts +12 -1
  69. package/src/scrapers/website/WebsiteScraper.ts +22 -2
  70. package/src/utils/misc/createLazyModuleLoader.ts +27 -0
  71. package/src/version.ts +2 -2
  72. package/src/versions.txt +1 -0
  73. package/umd/index.umd.js +750 -266
  74. package/umd/index.umd.js.map +1 -1
  75. package/umd/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +7 -0
  76. package/umd/scripts/run-codex-prompts/git/coderGitSync.d.ts +43 -0
  77. package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -0
  78. package/umd/scripts/run-codex-prompts/main/resolvePromptRunner.d.ts +8 -1
  79. package/umd/scripts/run-codex-prompts/ping/buildCoderPingPrompt.d.ts +20 -0
  80. package/umd/scripts/run-codex-prompts/ping/extractCoderPingAnswer.d.ts +9 -0
  81. package/umd/scripts/run-codex-prompts/ping/pingCoderHarness.d.ts +23 -0
  82. package/umd/scripts/run-codex-prompts/ping/printCoderPingResult.d.ts +5 -0
  83. package/umd/scripts/verify-prompts/verify-prompts.d.ts +5 -0
  84. package/umd/src/book-components/Chat/utils/$provideServerDomWindow.d.ts +11 -0
  85. package/umd/src/cli/cli-commands/agents-server/buildAgentsServer/createAgentsServerRuntimeEnvironment.d.ts +7 -0
  86. package/umd/src/cli/cli-commands/coder/ping.d.ts +2 -5
  87. package/umd/src/cli/cli-commands/coder.d.ts +1 -1
  88. package/umd/src/cli/cli-commands/common/coderGitSyncCliOptions.d.ts +34 -0
  89. package/umd/src/cli/cli-commands/common/coderGitSyncCliOptions.test.d.ts +1 -0
  90. package/umd/src/cli/common/loadPromptsModule.d.ts +16 -0
  91. package/umd/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +1 -1
  92. package/umd/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +1 -1
  93. package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionTools.d.ts +1 -1
  94. package/umd/src/llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder.d.ts +1 -1
  95. package/umd/src/llm-providers/openai/OpenAiAssistantExecutionToolsStreamRunner.d.ts +1 -1
  96. package/umd/src/llm-providers/openai/OpenAiAssistantExecutionToolsToolRunner.d.ts +1 -1
  97. package/umd/src/llm-providers/openai/OpenAiCompatibleNonChatPromptCaller.d.ts +1 -1
  98. package/umd/src/llm-providers/openai/OpenAiCompatibleRequestManager.d.ts +1 -1
  99. package/umd/src/llm-providers/openai/utils/callOpenAiCompatibleChatModel.d.ts +1 -1
  100. package/umd/src/llm-providers/openai/utils/loadOpenAiAgentsModule.d.ts +203 -0
  101. package/umd/src/llm-providers/openai/utils/uploadFilesToOpenAi.d.ts +1 -1
  102. package/umd/src/utils/misc/createLazyModuleLoader.d.ts +14 -0
  103. package/umd/src/version.d.ts +1 -1
  104. package/esm/scripts/run-agent-chat/runCoderPing.d.ts +0 -48
  105. package/umd/scripts/run-agent-chat/runCoderPing.d.ts +0 -48
@@ -1,10 +1,4 @@
1
- import {
2
- Agent as AgentFromKit,
3
- fileSearchTool,
4
- run,
5
- setDefaultOpenAIClient,
6
- setDefaultOpenAIKey,
7
- } from '@openai/agents';
1
+ import type { Agent as AgentFromKit } from '@openai/agents';
8
2
  import { readFile } from 'fs/promises';
9
3
  import { basename, resolve } from 'path';
10
4
  import { fileURLToPath } from 'url';
@@ -17,6 +11,7 @@ import { computeOpenAiUsage } from '../llm-providers/openai/computeOpenAiUsage';
17
11
  import { OPENAI_MODELS } from '../llm-providers/openai/openai-models';
18
12
  import { OpenAiAgentKitExecutionToolsToolBuilder } from '../llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder';
19
13
  import { OpenAiVectorStoreHandler } from '../llm-providers/openai/OpenAiVectorStoreHandler';
14
+ import { loadOpenAiAgentsModule } from '../llm-providers/openai/utils/loadOpenAiAgentsModule';
20
15
  import { $provideScriptingForNode } from '../scrapers/_common/register/$provideScriptingForNode';
21
16
  import type { string_knowledge_source_link } from '../types/string_knowledge_source_content';
22
17
  import type { string_markdown, string_markdown_text } from '../types/string_markdown';
@@ -112,6 +107,7 @@ export class LiteAgent {
112
107
  const preparedAgent = await this.prepareAgent();
113
108
  preparedAgent.toolBuilder?.clearRunState();
114
109
 
110
+ const { run } = await loadOpenAiAgentsModule();
115
111
  const result = await run(
116
112
  preparedAgent.agent,
117
113
  createLiteAgentPromptText(normalizedMessage, options.context, preparedAgent.modelRequirements.promptSuffix),
@@ -165,6 +161,12 @@ export class LiteAgent {
165
161
  userId: this.options.userId,
166
162
  });
167
163
  const client = await runtime.getClient();
164
+ const {
165
+ Agent: AgentFromKit,
166
+ fileSearchTool,
167
+ setDefaultOpenAIClient,
168
+ setDefaultOpenAIKey,
169
+ } = await loadOpenAiAgentsModule();
168
170
 
169
171
  setDefaultOpenAIClient(client as TODO_any);
170
172
 
@@ -190,9 +192,9 @@ export class LiteAgent {
190
192
  })
191
193
  : null;
192
194
  const agentTools =
193
- toolBuilder?.buildAgentKitTools({
195
+ (await toolBuilder?.buildAgentKitTools({
194
196
  tools: modelRequirements.tools ? [...modelRequirements.tools] : undefined,
195
- }) || [];
197
+ })) || [];
196
198
  const normalizedKnowledgeSources = await normalizeLiteAgentKnowledgeSources(
197
199
  modelRequirements.knowledgeSources || [],
198
200
  resolvedSource.sourceDirectoryPath,
@@ -0,0 +1,77 @@
1
+ import type { WindowLike as DomWindowLike } from 'dompurify';
2
+ import { spaceTrim } from 'spacetrim';
3
+ import { assertsError } from '../../../errors/assertsError';
4
+ import { EnvironmentMismatchError } from '../../../errors/EnvironmentMismatchError';
5
+
6
+ /**
7
+ * Shared DOM window reused by every render which happens outside of a browser
8
+ *
9
+ * @private utility of `$provideServerDomWindow`
10
+ */
11
+ let serverDomWindow: DomWindowLike | null = null;
12
+
13
+ /**
14
+ * Provides a DOM `window` for runtimes which do not have one, for example Node.js during server-side rendering
15
+ *
16
+ * Note: `$` is used to indicate that this function is not a pure function - it creates and caches one shared DOM window
17
+ *
18
+ * @returns DOM window which can back a DOM-dependent library like `DOMPurify`
19
+ * @throws {EnvironmentMismatchError} When the current runtime can not create a DOM window
20
+ * @private utility of `renderMarkdown`
21
+ */
22
+ export function $provideServerDomWindow(): DomWindowLike {
23
+ if (serverDomWindow === null) {
24
+ const { JSDOM } = requireServerDomLibrary();
25
+ serverDomWindow = new JSDOM('').window as unknown as DomWindowLike;
26
+ }
27
+
28
+ return serverDomWindow;
29
+ }
30
+
31
+ /**
32
+ * Loads `jsdom` which backs the DOM window outside of a browser
33
+ *
34
+ * Note: [😷] `jsdom` reaches for Node.js built-ins like `fs`, `child_process` and `net`, so browser bundlers must
35
+ * never follow the `require` below - even though it is unreachable in a browser, bundlers resolve it statically.
36
+ * They are told to replace `jsdom` with an empty module by the `browser` field of the generated package
37
+ * manifests, which is written by `applyBrowserUnsupportedDependencyStubs` during the package generation.
38
+ *
39
+ * @returns The `jsdom` library
40
+ * @throws {EnvironmentMismatchError} When `jsdom` can not be loaded in the current runtime
41
+ * @private utility of `$provideServerDomWindow`
42
+ */
43
+ function requireServerDomLibrary(): typeof import('jsdom') {
44
+ let serverDomLibrary: Partial<typeof import('jsdom')> | null = null;
45
+ let serverDomLibraryError: Error | null = null;
46
+
47
+ try {
48
+ // Note: [😷] Keep `'jsdom'` written as a literal, bundlers do not replace a computed module name
49
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
50
+ serverDomLibrary = require('jsdom') as typeof import('jsdom');
51
+ } catch (error) {
52
+ assertsError(error);
53
+ serverDomLibraryError = error;
54
+ }
55
+
56
+ if (typeof serverDomLibrary?.JSDOM !== 'function') {
57
+ throw new EnvironmentMismatchError(
58
+ spaceTrim(
59
+ (block) => `
60
+ Markdown can not be rendered because there is no DOM in the current runtime.
61
+
62
+ Rendered markdown is sanitized through \`DOMPurify\`, which needs a DOM - the DOM of the browser
63
+ when the code runs in a browser and \`jsdom\` in every other runtime, for example during
64
+ server-side rendering in **Node.js**.
65
+
66
+ ${block(
67
+ serverDomLibraryError === null
68
+ ? 'The `jsdom` module was resolved but it does not export `JSDOM`, which happens when a bundler replaces `jsdom` with an empty module in a build which is neither a browser build nor a Node.js build.'
69
+ : `${serverDomLibraryError.name}: ${serverDomLibraryError.message}`,
70
+ )}
71
+ `,
72
+ ),
73
+ );
74
+ }
75
+
76
+ return serverDomLibrary as typeof import('jsdom');
77
+ }
@@ -9,6 +9,7 @@ import type { Converter as ShowdownConverter } from 'showdown';
9
9
  import showdown from 'showdown';
10
10
  import type { string_html, string_markdown } from '../../../types/string_markdown';
11
11
  import { TODO_USE } from '../../../utils/organization/TODO_USE';
12
+ import { $provideServerDomWindow } from './$provideServerDomWindow';
12
13
  import { createCitationMarkerRegex, parseCitationMarker } from './parseCitationMarker';
13
14
 
14
15
  /**
@@ -218,13 +219,6 @@ let browserMarkdownSanitizer: DomPurifyInstance | null = null;
218
219
  */
219
220
  let serverMarkdownSanitizer: DomPurifyInstance | null = null;
220
221
 
221
- /**
222
- * Shared JSDOM window backing the server-side DOMPurify instance.
223
- *
224
- * @private utility of `renderMarkdown`
225
- */
226
- let serverMarkdownSanitizerWindow: DomPurifyWindowLike | null = null;
227
-
228
222
  /**
229
223
  * Pattern matching CODE FENCE.
230
224
  */
@@ -546,21 +540,6 @@ function createMarkdownSanitizer(sanitizerWindow: DomPurifyWindowLike): DomPurif
546
540
  return markdownSanitizer;
547
541
  }
548
542
 
549
- /**
550
- * Lazily creates the JSDOM window used by server-side markdown sanitization.
551
- *
552
- * @private utility of `renderMarkdown`
553
- */
554
- function getServerMarkdownSanitizerWindow(): DomPurifyWindowLike {
555
- if (!serverMarkdownSanitizerWindow) {
556
- // eslint-disable-next-line @typescript-eslint/no-var-requires
557
- const { JSDOM } = require('jsdom') as typeof import('jsdom');
558
- serverMarkdownSanitizerWindow = new JSDOM('').window as unknown as DomPurifyWindowLike;
559
- }
560
-
561
- return serverMarkdownSanitizerWindow;
562
- }
563
-
564
543
  /**
565
544
  * Returns the shared DOMPurify instance appropriate for the current runtime.
566
545
  *
@@ -573,7 +552,7 @@ function getMarkdownSanitizer(): DomPurifyInstance {
573
552
  return browserMarkdownSanitizer;
574
553
  }
575
554
 
576
- serverMarkdownSanitizer ??= createMarkdownSanitizer(getServerMarkdownSanitizerWindow());
555
+ serverMarkdownSanitizer ??= createMarkdownSanitizer($provideServerDomWindow());
577
556
 
578
557
  return serverMarkdownSanitizer;
579
558
  }
@@ -22,6 +22,14 @@ export const PTBK_AGENTS_SERVER_BUILD_WORKER_COUNT_ENV = 'PTBK_AGENTS_SERVER_BUI
22
22
  */
23
23
  export const PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV = 'PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION';
24
24
 
25
+ /**
26
+ * Environment variable that disables throwaway webpack filesystem caches for CLI-owned production builds.
27
+ *
28
+ * @private internal constant of `buildAgentsServer`
29
+ */
30
+ export const PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE_ENV =
31
+ 'PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE';
32
+
25
33
  /**
26
34
  * Conservative Next.js build worker count used by CLI-owned Agents Server production builds.
27
35
  *
@@ -41,6 +49,7 @@ export function createAgentsServerRuntimeEnvironment(
41
49
  nodeModulesPath: string,
42
50
  options: {
43
51
  readonly isNextValidationIgnored?: boolean;
52
+ readonly isWebpackFilesystemCacheDisabled?: boolean;
44
53
  } = {},
45
54
  ): NodeJS.ProcessEnv {
46
55
  return {
@@ -54,6 +63,11 @@ export function createAgentsServerRuntimeEnvironment(
54
63
  [PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV]: 'true',
55
64
  }
56
65
  : {}),
66
+ ...(options.isWebpackFilesystemCacheDisabled
67
+ ? {
68
+ [PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE_ENV]: 'true',
69
+ }
70
+ : {}),
57
71
  };
58
72
  }
59
73
 
@@ -30,6 +30,7 @@ export async function ensureAgentsServerBuild(
30
30
  });
31
31
  const buildEnvironment = createAgentsServerRuntimeEnvironment(environment, preparedRuntime.nodeModulesPath, {
32
32
  isNextValidationIgnored: preparedRuntime.isAppPathMaterialized,
33
+ isWebpackFilesystemCacheDisabled: true,
33
34
  });
34
35
 
35
36
  if (
@@ -4,12 +4,18 @@ import type {
4
4
  } from 'commander';
5
5
  import { mkdirSync, writeFileSync } from 'fs';
6
6
  import { join } from 'path';
7
- import prompts from 'prompts';
8
7
  import { spaceTrim } from 'spacetrim';
9
8
  import { NotAllowed } from '../../../errors/NotAllowed';
10
9
  import { ParseError } from '../../../errors/ParseError';
11
10
  import { normalizeToKebabCase } from '../../../utils/normalization/normalize-to-kebab-case';
12
11
  import type { $side_effect } from '../../../utils/organization/$side_effect';
12
+ import { loadPromptsModule } from '../../common/loadPromptsModule';
13
+ import type { CoderGitSyncCliOptions } from '../common/coderGitSyncCliOptions';
14
+ import {
15
+ addCoderGitSyncOptions,
16
+ CODER_GIT_SYNC_DESCRIPTION,
17
+ normalizeCoderGitSyncCliOptions,
18
+ } from '../common/coderGitSyncCliOptions';
13
19
  import { handleActionErrors } from '../common/handleActionErrors';
14
20
  import {
15
21
  buildCoderPromptSection,
@@ -49,15 +55,19 @@ const FALLBACK_PROMPT_SLUG = 'prompt';
49
55
  export function $initializeCoderAddCommand(program: Program): $side_effect {
50
56
  const command = program.command('add');
51
57
  command.description(
52
- spaceTrim(`
53
- Add one ready-to-run prompt file to the queue
58
+ spaceTrim(
59
+ (block) => `
60
+ Add one ready-to-run prompt file to the queue
54
61
 
55
- Provide the description as an argument, pipe it through stdin, or run without arguments to type it interactively:
56
- - \`ptbk coder add "some new feature"\`
57
- - \`ptbk coder add --priority 1 "some new feature"\`
58
- - \`ptbk coder add <<EOF ... EOF\`
59
- - \`ptbk coder add\`
60
- `),
62
+ Provide the description as an argument, pipe it through stdin, or run without arguments to type it interactively:
63
+ - \`ptbk coder add "some new feature"\`
64
+ - \`ptbk coder add --priority 1 "some new feature"\`
65
+ - \`ptbk coder add <<EOF ... EOF\`
66
+ - \`ptbk coder add\`
67
+
68
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
69
+ `,
70
+ ),
61
71
  );
62
72
 
63
73
  command.argument('[description]', 'Plain-language description of the feature or task to implement');
@@ -77,22 +87,39 @@ export function $initializeCoderAddCommand(program: Program): $side_effect {
77
87
  .join(', ')}) or a markdown file path relative to the current project root.
78
88
  `),
79
89
  );
90
+ addCoderGitSyncOptions(command);
80
91
 
81
92
  command.action(
82
93
  handleActionErrors(async (descriptionArgument: string | undefined, cliOptions) => {
83
94
  const { priority, template: templateOption } = cliOptions as {
84
95
  readonly priority: number;
85
96
  readonly template?: string;
86
- };
97
+ } & CoderGitSyncCliOptions;
98
+
99
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions as CoderGitSyncCliOptions);
100
+ const projectPath = process.cwd();
87
101
 
88
102
  const description = await resolveCoderPromptDescription(descriptionArgument);
89
103
 
90
- await addCoderPrompt({
91
- projectPath: process.cwd(),
104
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
105
+ const { $commitCoderChanges, $pullCoderChanges } = await import(
106
+ '../../../../scripts/run-codex-prompts/git/coderGitSync'
107
+ );
108
+
109
+ await $pullCoderChanges({ gitSync, projectPath });
110
+
111
+ const { /* filePath,*/ emojiTag } = await addCoderPrompt({
112
+ projectPath,
92
113
  description,
93
114
  priority,
94
115
  templateOption,
95
116
  });
117
+
118
+ await $commitCoderChanges({
119
+ gitSync,
120
+ projectPath,
121
+ commitMessage: `${emojiTag} Add prompt`,
122
+ });
96
123
  }),
97
124
  );
98
125
  }
@@ -216,6 +243,7 @@ async function resolveCoderPromptDescription(descriptionArgument: string | undef
216
243
  return standardInputDescription;
217
244
  }
218
245
 
246
+ const { default: prompts } = await loadPromptsModule();
219
247
  const response = await prompts({
220
248
  type: 'text',
221
249
  name: 'description',
@@ -6,6 +6,12 @@ import { mkdirSync, writeFileSync } from 'fs';
6
6
  import { join } from 'path';
7
7
  import { spaceTrim } from 'spacetrim';
8
8
  import type { $side_effect } from '../../../utils/organization/$side_effect';
9
+ import type { CoderGitSyncCliOptions } from '../common/coderGitSyncCliOptions';
10
+ import {
11
+ addCoderGitSyncOptions,
12
+ CODER_GIT_SYNC_DESCRIPTION,
13
+ normalizeCoderGitSyncCliOptions,
14
+ } from '../common/coderGitSyncCliOptions';
9
15
  import { handleActionErrors } from '../common/handleActionErrors';
10
16
  import {
11
17
  buildCoderPromptSection,
@@ -24,9 +30,13 @@ import {
24
30
  export function $initializeCoderGenerateBoilerplatesCommand(program: Program): $side_effect {
25
31
  const command = program.command('generate-boilerplates');
26
32
  command.description(
27
- spaceTrim(`
28
- Generate prompt boilerplate files with unique emoji tags
29
- `),
33
+ spaceTrim(
34
+ (block) => `
35
+ Generate prompt boilerplate files with unique emoji tags
36
+
37
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
38
+ `,
39
+ ),
30
40
  );
31
41
 
32
42
  command.option('--count <count>', `Number of prompt boilerplate files to generate`, '5');
@@ -40,22 +50,38 @@ export function $initializeCoderGenerateBoilerplatesCommand(program: Program): $
40
50
  .join(', ')}) or a markdown file path relative to the current project root.
41
51
  `),
42
52
  );
53
+ addCoderGitSyncOptions(command);
43
54
 
44
55
  command.action(
45
56
  handleActionErrors(async (cliOptions) => {
46
57
  const { count: countOption, template: templateOption } = cliOptions as {
47
58
  readonly count: string;
48
59
  readonly template?: string;
49
- };
60
+ } & CoderGitSyncCliOptions;
50
61
 
51
62
  const filesCount = parseFilesCount(countOption);
63
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions as CoderGitSyncCliOptions);
64
+ const projectPath = process.cwd();
65
+
66
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
67
+ const { $commitCoderChanges, $pullCoderChanges } = await import(
68
+ '../../../../scripts/run-codex-prompts/git/coderGitSync'
69
+ );
70
+
71
+ await $pullCoderChanges({ gitSync, projectPath });
52
72
 
53
73
  await generatePromptBoilerplate({
54
- projectPath: process.cwd(),
74
+ projectPath,
55
75
  filesCount,
56
76
  templateOption,
57
77
  });
58
78
 
79
+ await $commitCoderChanges({
80
+ gitSync,
81
+ projectPath,
82
+ commitMessage: `Prompts ${filesCount}x`,
83
+ });
84
+
59
85
  return process.exit(0);
60
86
  }),
61
87
  );
@@ -3,6 +3,12 @@ import type {
3
3
  } from 'commander';
4
4
  import { spaceTrim } from 'spacetrim';
5
5
  import type { $side_effect } from '../../../utils/organization/$side_effect';
6
+ import type { CoderGitSyncCliOptions } from '../common/coderGitSyncCliOptions';
7
+ import {
8
+ addCoderGitSyncOptions,
9
+ CODER_GIT_SYNC_DESCRIPTION,
10
+ normalizeCoderGitSyncCliOptions,
11
+ } from '../common/coderGitSyncCliOptions';
6
12
  import { handleActionErrors } from '../common/handleActionErrors';
7
13
  import { $ensureHarnessInstallations } from '../common/harness/$ensureHarnessInstallations';
8
14
  import { getHarnessDefinition } from '../common/harness/HarnessDefinition';
@@ -61,16 +67,36 @@ export function $initializeCoderInitCommand(program: Program): $side_effect {
61
67
 
62
68
  Checks that the coding harnesses are installed globally and up to date:
63
69
  ${block(listCheckedHarnessLabels())}
70
+
71
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
64
72
  `,
65
73
  ),
66
74
  );
67
75
 
76
+ addCoderGitSyncOptions(command);
77
+
68
78
  command.action(
69
- handleActionErrors(async () => {
79
+ handleActionErrors(async (cliOptions) => {
80
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions as CoderGitSyncCliOptions);
70
81
  const projectPath = process.cwd();
82
+
83
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
84
+ const { $commitCoderChanges, $pullCoderChanges } = await import(
85
+ '../../../../scripts/run-codex-prompts/git/coderGitSync'
86
+ );
87
+
88
+ await $pullCoderChanges({ gitSync, projectPath });
89
+
71
90
  const summary = await initializeCoderProjectConfiguration(projectPath);
72
91
  printInitializationSummary(summary);
73
92
  await generatePromptBoilerplate({ projectPath, filesCount: 5 });
93
+
94
+ await $commitCoderChanges({
95
+ gitSync,
96
+ projectPath,
97
+ commitMessage: 'Initialize Promptbook Coder',
98
+ });
99
+
74
100
  await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES);
75
101
  }),
76
102
  );
@@ -2,10 +2,9 @@ import type {
2
2
  Command as Program /* <- Note: [🔸] Using Program because Command is misleading name */,
3
3
  } from 'commander';
4
4
  import { spaceTrim } from 'spacetrim';
5
- import { NotAllowed } from '../../../errors/NotAllowed';
6
5
  import type { $side_effect } from '../../../utils/organization/$side_effect';
7
- import { $ensureHarnessInstallations } from '../common/harness/$ensureHarnessInstallations';
8
6
  import { handleActionErrors } from '../common/handleActionErrors';
7
+ import { $ensureHarnessInstallations } from '../common/harness/$ensureHarnessInstallations';
9
8
  import type { PromptRunnerSelectionCliOptions } from '../common/promptRunnerCliOptions';
10
9
  import {
11
10
  addPromptRunnerRuntimeOptions,
@@ -15,12 +14,9 @@ import {
15
14
  } from '../common/promptRunnerCliOptions';
16
15
 
17
16
  /**
18
- * Initializes `coder ping` command for Promptbook CLI utilities.
19
- *
20
- * The command makes one small, isolated harness/model call, prints its result
21
- * and reports how long the harness/model turn took.
17
+ * Initializes `coder ping` command for Promptbook CLI utilities
22
18
  *
23
- * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI.
19
+ * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
24
20
  *
25
21
  * @private internal function of `promptbookCli`
26
22
  */
@@ -28,15 +24,16 @@ export function $initializeCoderPingCommand(program: Program): $side_effect {
28
24
  const command = program.command('ping');
29
25
  command.description(
30
26
  spaceTrim(`
31
- Test one harness and model connection with a small disposable task
27
+ Send one tiny dummy prompt to a harness and model to measure and warm them up
32
28
 
33
29
  ${PROMPT_RUNNER_DESCRIPTION}
34
30
 
35
31
  Features:
36
- - Runs the dummy task in a temporary directory outside the current project
37
- - Prints the result returned by the selected harness and model
38
- - Reports the elapsed harness/model response time in milliseconds
39
- - Can be used to start consuming an applicable harness/model quota before a longer run
32
+ - Verifies that the selected harness, model, thinking level and authentication really work
33
+ - Reports the answer of the harness, the response time and the reported usage
34
+ - Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
35
+ - Leaves the project exactly as it was nothing is read, written, changed or committed
36
+ - Use --no-ui to stream the raw harness output instead of only the compact result
40
37
  `),
41
38
  );
42
39
 
@@ -45,50 +42,31 @@ export function $initializeCoderPingCommand(program: Program): $side_effect {
45
42
 
46
43
  command.action(
47
44
  handleActionErrors(async (cliOptions) => {
48
- const normalizedOptions = normalizePromptRunnerSelectionCliOptions(
45
+ const runnerOptions = normalizePromptRunnerSelectionCliOptions(
49
46
  cliOptions as PromptRunnerSelectionCliOptions,
50
47
  { isAgentRequired: true },
51
48
  );
52
49
 
53
- const agentName = normalizedOptions.agentName;
54
- if (!agentName) {
55
- throw new NotAllowed(
56
- spaceTrim(`
57
- A harness is required for \`ptbk coder ping\`.
50
+ await $ensureHarnessInstallations([runnerOptions.agentName]);
58
51
 
59
- Pass one with \`--harness <harness-name>\`.
60
- `),
61
- );
62
- }
63
-
64
- await $ensureHarnessInstallations([agentName]);
52
+ // Note: Import the ping dynamically to avoid loading heavy dependencies until needed
53
+ const { pingCoderHarness } = await import('../../../../scripts/run-codex-prompts/ping/pingCoderHarness');
54
+ const { printCoderPingResult } = await import(
55
+ '../../../../scripts/run-codex-prompts/ping/printCoderPingResult'
56
+ );
65
57
 
66
- // Note: Import the runner-backed implementation dynamically to avoid loading heavy dependencies until needed.
67
- const { runCoderPing } = await import('../../../../scripts/run-agent-chat/runCoderPing');
68
- const pingResult = await runCoderPing({
69
- agentName,
70
- model: normalizedOptions.model,
71
- thinkingLevel: normalizedOptions.thinkingLevel,
72
- isUiDisabled: normalizedOptions.noUi,
73
- isCreditsAllowed: normalizedOptions.allowCredits,
58
+ const result = await pingCoderHarness({
59
+ agentName: runnerOptions.agentName,
60
+ model: runnerOptions.model,
61
+ thinkingLevel: runnerOptions.thinkingLevel,
62
+ allowCredits: runnerOptions.allowCredits,
63
+ shouldPrintLiveOutput: runnerOptions.noUi,
74
64
  });
75
65
 
76
- printCoderPingResult(pingResult);
66
+ printCoderPingResult(result);
77
67
  }),
78
68
  );
79
69
  }
80
70
 
81
- /**
82
- * Prints the result and duration of one completed coder ping.
83
- */
84
- function printCoderPingResult(pingResult: { readonly result: string; readonly elapsedTimeMs: number }): void {
85
- console.info(
86
- spaceTrim(`
87
- Result: ${pingResult.result}
88
- Time: ${pingResult.elapsedTimeMs.toFixed(0)} ms
89
- `),
90
- );
91
- }
92
-
93
71
  // Note: [🟡] Code for CLI command [ping](src/cli/cli-commands/coder/ping.ts) should never be published outside of `@promptbook/cli`
94
72
  // Note: [💞] Ignore a discrepancy between file name and entity name
@@ -4,6 +4,12 @@ import type {
4
4
  } from 'commander';
5
5
  import { spaceTrim } from 'spacetrim';
6
6
  import type { $side_effect } from '../../../utils/organization/$side_effect';
7
+ import type { CoderGitSyncCliOptions } from '../common/coderGitSyncCliOptions';
8
+ import {
9
+ addCoderGitSyncOptions,
10
+ CODER_GIT_SYNC_DESCRIPTION,
11
+ normalizeCoderGitSyncCliOptions,
12
+ } from '../common/coderGitSyncCliOptions';
7
13
  import { handleActionErrors } from '../common/handleActionErrors';
8
14
 
9
15
  /**
@@ -16,17 +22,23 @@ import { handleActionErrors } from '../common/handleActionErrors';
16
22
  export function $initializeCoderVerifyCommand(program: Program): $side_effect {
17
23
  const command = program.command('verify');
18
24
  command.description(
19
- spaceTrim(`
20
- Interactive verification helper for completed prompts
25
+ spaceTrim(
26
+ (block) => `
27
+ Interactive verification helper for completed prompts
21
28
 
22
- Features:
23
- - Displays list of prompt files with status counts
24
- - Guides through verification of completed prompts marked [x]
25
- - Archives verified prompt files to prompts/done/ directory
26
- - Auto-appends repair prompts for incomplete work
27
- - Processes files with all-done prompts first
28
- - Supports ignoring matching prompt candidates for one verification run
29
- `),
29
+ Features:
30
+ - Displays list of prompt files with status counts
31
+ - Guides through verification of completed prompts marked [x]
32
+ - Archives verified prompt files to prompts/done/ directory
33
+ - Auto-appends repair prompts for incomplete work
34
+ - Processes files with all-done prompts first
35
+ - Supports ignoring matching prompt candidates for one verification run
36
+
37
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
38
+
39
+ Note: The git synchronization is applied around each single verification, not once per run.
40
+ `,
41
+ ),
30
42
  );
31
43
 
32
44
  command.option('--reverse', 'Process prompt files in reverse order', false);
@@ -36,19 +48,22 @@ export function $initializeCoderVerifyCommand(program: Program): $side_effect {
36
48
  collectStringOption,
37
49
  [],
38
50
  );
51
+ addCoderGitSyncOptions(command);
39
52
 
40
53
  command.action(
41
54
  handleActionErrors(async (cliOptions) => {
42
55
  const { reverse, ignore } = cliOptions as {
43
56
  readonly reverse: boolean;
44
57
  readonly ignore: ReadonlyArray<string>;
45
- };
58
+ } & CoderGitSyncCliOptions;
59
+
60
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions as CoderGitSyncCliOptions);
46
61
 
47
62
  // Note: Import the main function dynamically to avoid loading heavy dependencies until needed
48
63
  const { verifyPrompts } = await import('../../../../scripts/verify-prompts/verify-prompts');
49
64
 
50
65
  try {
51
- await verifyPrompts({ reverse, ignore });
66
+ await verifyPrompts({ reverse, ignore, gitSync });
52
67
  } catch (error) {
53
68
  console.error(colors.bgRed('Prompt verification failed:'), error);
54
69
  return process.exit(1);
@@ -23,8 +23,8 @@ import { $initializeCoderVerifyCommand } from './coder/verify';
23
23
  * - add: Add one ready-to-run prompt file to the queue
24
24
  * - generate-boilerplates: Generate prompt boilerplate files
25
25
  * - find-refactor-candidates: Find files that need refactoring
26
- * - ping: Test one harness and model connection with a disposable task
27
26
  * - run: Run coding prompts with AI agents
27
+ * - ping: Test one harness and model with a tiny dummy prompt
28
28
  * - verify: Verify completed prompts
29
29
  * - find-fresh-emoji-tags: Find unused emoji tags
30
30
  *
@@ -44,8 +44,8 @@ export function $initializeCoderCommand(program: Program): $side_effect {
44
44
  - generate-boilerplates: Generate prompt boilerplate files
45
45
  - find-refactor-candidates: Find files that need refactoring
46
46
  - find-unwritten: List prompt sections that still need to be authored
47
- - ping: Test one harness and model connection with a disposable task
48
47
  - run: Run coding prompts with AI agents
48
+ - ping: Test the connection, response time and quota of one harness and model
49
49
  - server: Start a long-running coder server with a kanban web UI
50
50
  - verify: Verify completed prompts
51
51
  - find-fresh-emoji-tags: Find unused emoji tags
@@ -58,8 +58,8 @@ export function $initializeCoderCommand(program: Program): $side_effect {
58
58
  $initializeCoderGenerateBoilerplatesCommand(coderCommand);
59
59
  $initializeCoderFindRefactorCandidatesCommand(coderCommand);
60
60
  $initializeCoderFindUnwrittenCommand(coderCommand);
61
- $initializeCoderPingCommand(coderCommand);
62
61
  $initializeCoderRunCommand(coderCommand);
62
+ $initializeCoderPingCommand(coderCommand);
63
63
  $initializeCoderServerCommand(coderCommand);
64
64
  $initializeCoderVerifyCommand(coderCommand);
65
65
  $initializeCoderFindFreshEmojiTagCommand(coderCommand);