@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
package/umd/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('fs/promises'), require('path'), require('crypto'), require('child_process'), require('moment'), require('fs'), require('dotenv'), require('readline'), require('waitasecond'), require('prompts'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('socket.io-client'), require('jszip'), require('@mozilla/readability'), require('jsdom'), require('crypto-js'), require('showdown'), require('glob-promise'), require('http'), require('express'), require('socket.io'), require('express-openapi-validator'), require('swagger-ui-express'), require('react'), require('react-dom/server'), require('@anthropic-ai/sdk'), require('bottleneck'), require('@azure/openai'), require('rxjs'), require('@openai/agents'), require('openai'), require('typescript'), require('ignore'), require('os'), require('events'), require('mime-types'), require('papaparse'), require('pg'), require('@supabase/supabase-js'), require('url')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'fs/promises', 'path', 'crypto', 'child_process', 'moment', 'fs', 'dotenv', 'readline', 'waitasecond', 'prompts', 'crypto-js/enc-hex', 'crypto-js/sha256', 'socket.io-client', 'jszip', '@mozilla/readability', 'jsdom', 'crypto-js', 'showdown', 'glob-promise', 'http', 'express', 'socket.io', 'express-openapi-validator', 'swagger-ui-express', 'react', 'react-dom/server', '@anthropic-ai/sdk', 'bottleneck', '@azure/openai', 'rxjs', '@openai/agents', 'openai', 'typescript', 'ignore', 'os', 'events', 'mime-types', 'papaparse', 'pg', '@supabase/supabase-js', 'url'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global._spaceTrim, global.promises, global.path, global.crypto, global.child_process, global.moment, global.fs, global.dotenv, global.readline, global.waitasecond, global.prompts, global.hexEncoder, global.sha256, global.socket_ioClient, global.JSZip, global.readability, global.jsdom, global.CryptoJS, global.showdown, global.glob, global.http, global.express, global.socket_io, global.OpenApiValidator, global.swaggerUi, global.react, global.server, global.Anthropic, global.Bottleneck, global.openai, global.rxjs, global.agents, global.OpenAI, global.ts, global.ignore, global.os, global.events, global.mimeTypes, global.papaparse, global.pg, null, global.url));
5
- })(this, (function (exports, colors, commander, _spaceTrim, promises, path, crypto, child_process, moment, fs, dotenv, readline, waitasecond, prompts, hexEncoder, sha256, socket_ioClient, JSZip, readability, jsdom, CryptoJS, showdown, glob, http, express, socket_io, OpenApiValidator, swaggerUi, react, server, Anthropic, Bottleneck, openai, rxjs, agents, OpenAI, ts, ignore, os, events, mimeTypes, papaparse, pg, supabaseJs, url) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('fs/promises'), require('path'), require('crypto'), require('child_process'), require('moment'), require('fs'), require('dotenv'), require('readline'), require('waitasecond'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto-js'), require('showdown'), require('glob-promise'), require('http'), require('express'), require('socket.io'), require('express-openapi-validator'), require('swagger-ui-express'), require('react'), require('react-dom/server'), require('bottleneck'), require('rxjs'), require('ignore'), require('events'), require('os'), require('mime-types'), require('papaparse'), require('@supabase/supabase-js'), require('url')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'fs/promises', 'path', 'crypto', 'child_process', 'moment', 'fs', 'dotenv', 'readline', 'waitasecond', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto-js', 'showdown', 'glob-promise', 'http', 'express', 'socket.io', 'express-openapi-validator', 'swagger-ui-express', 'react', 'react-dom/server', 'bottleneck', 'rxjs', 'ignore', 'events', 'os', 'mime-types', 'papaparse', '@supabase/supabase-js', 'url'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global._spaceTrim, global.promises, global.path, global.crypto, global.child_process, global.moment, global.fs, global.dotenv, global.readline, global.waitasecond, global.hexEncoder, global.sha256, global.CryptoJS, global.showdown, global.glob, global.http, global.express, global.socket_io, global.OpenApiValidator, global.swaggerUi, global.react, global.server, global.Bottleneck, global.rxjs, global.ignore, global.events, global.os, global.mimeTypes, global.papaparse, null, global.url));
5
+ })(this, (function (exports, colors, commander, _spaceTrim, promises, path, crypto, child_process, moment, fs, dotenv, readline, waitasecond, hexEncoder, sha256, CryptoJS, showdown, glob, http, express, socket_io, OpenApiValidator, swaggerUi, react, server, Bottleneck, rxjs, ignore, events, os, mimeTypes, papaparse, supabaseJs, url) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
@@ -31,10 +31,8 @@
31
31
  var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
32
32
  var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
33
33
  var readline__namespace = /*#__PURE__*/_interopNamespace(readline);
34
- var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts);
35
34
  var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
36
35
  var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
37
- var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip);
38
36
  var CryptoJS__default = /*#__PURE__*/_interopDefaultLegacy(CryptoJS);
39
37
  var showdown__default = /*#__PURE__*/_interopDefaultLegacy(showdown);
40
38
  var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
@@ -42,10 +40,7 @@
42
40
  var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
43
41
  var OpenApiValidator__namespace = /*#__PURE__*/_interopNamespace(OpenApiValidator);
44
42
  var swaggerUi__default = /*#__PURE__*/_interopDefaultLegacy(swaggerUi);
45
- var Anthropic__default = /*#__PURE__*/_interopDefaultLegacy(Anthropic);
46
43
  var Bottleneck__default = /*#__PURE__*/_interopDefaultLegacy(Bottleneck);
47
- var OpenAI__default = /*#__PURE__*/_interopDefaultLegacy(OpenAI);
48
- var ts__namespace = /*#__PURE__*/_interopNamespace(ts);
49
44
  var ignore__default = /*#__PURE__*/_interopDefaultLegacy(ignore);
50
45
  var papaparse__default = /*#__PURE__*/_interopDefaultLegacy(papaparse);
51
46
 
@@ -63,7 +58,7 @@
63
58
  * @generated
64
59
  * @see https://github.com/webgptorg/promptbook
65
60
  */
66
- const PROMPTBOOK_ENGINE_VERSION = '0.114.0-2';
61
+ const PROMPTBOOK_ENGINE_VERSION = '0.114.0-3';
67
62
  /**
68
63
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
69
64
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -3297,6 +3292,12 @@
3297
3292
  * @private internal constant of `buildAgentsServer`
3298
3293
  */
3299
3294
  const PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV = 'PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION';
3295
+ /**
3296
+ * Environment variable that disables throwaway webpack filesystem caches for CLI-owned production builds.
3297
+ *
3298
+ * @private internal constant of `buildAgentsServer`
3299
+ */
3300
+ const PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE_ENV = 'PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE';
3300
3301
  /**
3301
3302
  * Conservative Next.js build worker count used by CLI-owned Agents Server production builds.
3302
3303
  *
@@ -3321,6 +3322,11 @@
3321
3322
  [PTBK_AGENTS_SERVER_IGNORE_NEXT_VALIDATION_ENV]: 'true',
3322
3323
  }
3323
3324
  : {}),
3325
+ ...(options.isWebpackFilesystemCacheDisabled
3326
+ ? {
3327
+ [PTBK_AGENTS_SERVER_DISABLE_WEBPACK_FILESYSTEM_CACHE_ENV]: 'true',
3328
+ }
3329
+ : {}),
3324
3330
  };
3325
3331
  }
3326
3332
  /**
@@ -4054,6 +4060,7 @@
4054
4060
  });
4055
4061
  const buildEnvironment = createAgentsServerRuntimeEnvironment(environment, preparedRuntime.nodeModulesPath, {
4056
4062
  isNextValidationIgnored: preparedRuntime.isAppPathMaterialized,
4063
+ isWebpackFilesystemCacheDisabled: true,
4057
4064
  });
4058
4065
  if (!options.isBuildForced &&
4059
4066
  (await isAgentsServerBuildCacheCurrent({
@@ -28230,6 +28237,13 @@
28230
28237
  * Environment variable read by the shell wrapper to tee live output into the temporary runtime log file.
28231
28238
  */
28232
28239
  const PTBK_CODER_LOG_FILE_ENV_NAME = 'PTBK_CODER_LOG_FILE';
28240
+ /**
28241
+ * Log line which separates the raw script input from the raw script output of one execution section.
28242
+ *
28243
+ * Readers of a runtime log split on this marker to look only at what the harness really produced,
28244
+ * without the generated script and the prompt it embeds.
28245
+ */
28246
+ const SCRIPT_EXECUTION_LOG_RAW_OUTPUT_MARKER = '--- raw output ---';
28233
28247
  /**
28234
28248
  * Small bash wrapper that preserves stdout/stderr streams while teeing both into the runtime log file.
28235
28249
  */
@@ -28265,7 +28279,7 @@
28265
28279
  --- raw input ---
28266
28280
  ${block(normalizedInput)}
28267
28281
 
28268
- --- raw output ---
28282
+ ${SCRIPT_EXECUTION_LOG_RAW_OUTPUT_MARKER}
28269
28283
  `);
28270
28284
  await promises.appendFile(logPath, `${logSection}\n`, 'utf-8');
28271
28285
  }
@@ -32942,8 +32956,12 @@
32942
32956
  * `options.includePaths` can restrict staging, `options.onlyPaths` can restrict the commit pathspec,
32943
32957
  * `options.excludePaths` can keep temporary artifacts out of the created commit and
32944
32958
  * `options.isEmptyCommitAllowed` keeps a round without any file change from failing.
32959
+ *
32960
+ * Note: The temporary commit message file is written inside the project, so it is always excluded from the commit
32961
+ * itself for projects which do not keep the Promptbook temporary directory out of version control.
32945
32962
  */
32946
32963
  async function commitChanges(message, options) {
32964
+ var _a;
32947
32965
  const projectPath = (options === null || options === void 0 ? void 0 : options.projectPath) || process.cwd();
32948
32966
  const commitMessagePath = resolvePromptbookTemporaryPath(projectPath, 'ptbk-coder', 'commit-messages', `COMMIT_MESSAGE_${Date.now()}.txt`);
32949
32967
  await promises.mkdir(path.dirname(commitMessagePath), { recursive: true });
@@ -32951,7 +32969,10 @@
32951
32969
  try {
32952
32970
  const agentEnv = buildAgentGitEnv();
32953
32971
  const signingFlag = buildAgentGitSigningFlag();
32954
- await stageCommitChanges(projectPath, agentEnv, options === null || options === void 0 ? void 0 : options.includePaths, options === null || options === void 0 ? void 0 : options.excludePaths);
32972
+ await stageCommitChanges(projectPath, agentEnv, options === null || options === void 0 ? void 0 : options.includePaths, [
32973
+ commitMessagePath,
32974
+ ...((_a = options === null || options === void 0 ? void 0 : options.excludePaths) !== null && _a !== void 0 ? _a : []),
32975
+ ]);
32955
32976
  await runGitCommand({
32956
32977
  command: buildGitCommitCommand({
32957
32978
  commitMessagePath,
@@ -42291,6 +42312,91 @@
42291
42312
  // Note: [🟡] Code for CLI command [agents-server](src/cli/cli-commands/agents-server.ts) should never be published outside of `@promptbook/cli`
42292
42313
  // Note: [💞] Ignore a discrepancy between file name and entity name
42293
42314
 
42315
+ /**
42316
+ * Creates a loader which imports one module on the first call and reuses the very same module afterwards
42317
+ *
42318
+ * Note: [🐌] Heavy third-party dependencies are imported lazily to keep the startup of the Promptbook CLI fast.
42319
+ * A statically imported dependency is loaded every single time the bundle is loaded, even when the running
42320
+ * command never touches it. A lazily imported dependency is loaded only when the feature is really used.
42321
+ *
42322
+ * @example
42323
+ * const loadJsdomModule = createLazyModuleLoader(() => import('jsdom'));
42324
+ * const { JSDOM } = await loadJsdomModule();
42325
+ *
42326
+ * @private internal utility of Promptbook
42327
+ */
42328
+ function createLazyModuleLoader(importModule) {
42329
+ let importedModulePromise = null;
42330
+ return function loadModule() {
42331
+ if (importedModulePromise === null) {
42332
+ importedModulePromise = importModule();
42333
+ }
42334
+ return importedModulePromise;
42335
+ };
42336
+ }
42337
+ // Note: [🐌] Do not convert the lazy `import(...)` calls back to static `import` statements, it would bring back the
42338
+ // slow startup of the `ptbk` CLI utility
42339
+
42340
+ /**
42341
+ * Loads the interactive terminal prompt library (`prompts`) on demand
42342
+ *
42343
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast - most commands never ask the user
42344
+ * anything interactively
42345
+ *
42346
+ * @private internal utility of Promptbook CLI
42347
+ */
42348
+ const loadPromptsModule = createLazyModuleLoader(() => import('prompts'));
42349
+ // Note: [🟡] Code for CLI prompt loading [loadPromptsModule](src/cli/common/loadPromptsModule.ts) should never be published outside of `@promptbook/cli`
42350
+
42351
+ /**
42352
+ * Description block shared by the `ptbk coder` commands which can synchronize their changes with git.
42353
+ *
42354
+ * @private internal utility of `promptbookCli`
42355
+ */
42356
+ const CODER_GIT_SYNC_DESCRIPTION = _spaceTrim.spaceTrim(`
42357
+ Git synchronization:
42358
+ - --auto-pull pulls the latest changes before this command changes anything
42359
+ - --commit commits the changes made by this command
42360
+ - --auto-push pushes the created commit to the remote repository
42361
+ `);
42362
+ /**
42363
+ * Registers the shared `--commit`, `--auto-push` and `--auto-pull` flags on a `ptbk coder` command.
42364
+ *
42365
+ * Note: Unlike `ptbk coder run`, which commits by default and opts out through `--no-commit`,
42366
+ * these commands never touch git unless the flags are used explicitly.
42367
+ *
42368
+ * @private internal utility of `promptbookCli`
42369
+ */
42370
+ function addCoderGitSyncOptions(command) {
42371
+ command.option('--commit', 'Commit the changes made by this command with the coding-agent git identity', false);
42372
+ command.option('--auto-push', 'Automatically git push the created commit, requires --commit', false);
42373
+ command.option('--auto-pull', 'Automatically git pull the latest changes before this command changes anything', false);
42374
+ }
42375
+ /**
42376
+ * Converts the Commander git synchronization flags into normalized git synchronization options.
42377
+ *
42378
+ * @private internal utility of `promptbookCli`
42379
+ */
42380
+ function normalizeCoderGitSyncCliOptions(cliOptions) {
42381
+ if (cliOptions.autoPush && !cliOptions.commit) {
42382
+ throw new NotAllowed(_spaceTrim.spaceTrim(`
42383
+ Flag \`--auto-push\` can be used only together with \`--commit\`.
42384
+
42385
+ **There is nothing to push when the changes are not committed.**
42386
+
42387
+ Actionable hint:
42388
+ - Add \`--commit\`, for example \`ptbk coder init --commit --auto-push\`.
42389
+ `));
42390
+ }
42391
+ return {
42392
+ isCommitEnabled: cliOptions.commit,
42393
+ isAutoPushEnabled: cliOptions.autoPush,
42394
+ isAutoPullEnabled: cliOptions.autoPull,
42395
+ };
42396
+ }
42397
+ // Note: [🟡] Code for CLI git synchronization options [coderGitSyncCliOptions](src/cli/cli-commands/common/coderGitSyncCliOptions.ts) should never be published outside of `@promptbook/cli`
42398
+ // Note: [💞] Ignore a discrepancy between file name and exported helper names
42399
+
42294
42400
  /**
42295
42401
  * Relative path to the root prompts directory used by Promptbook coder utilities.
42296
42402
  *
@@ -42544,15 +42650,17 @@
42544
42650
  */
42545
42651
  function $initializeCoderAddCommand(program) {
42546
42652
  const command = program.command('add');
42547
- command.description(_spaceTrim.spaceTrim(`
42548
- Add one ready-to-run prompt file to the queue
42653
+ command.description(_spaceTrim.spaceTrim((block) => `
42654
+ Add one ready-to-run prompt file to the queue
42549
42655
 
42550
- Provide the description as an argument, pipe it through stdin, or run without arguments to type it interactively:
42551
- - \`ptbk coder add "some new feature"\`
42552
- - \`ptbk coder add --priority 1 "some new feature"\`
42553
- - \`ptbk coder add <<EOF ... EOF\`
42554
- - \`ptbk coder add\`
42555
- `));
42656
+ Provide the description as an argument, pipe it through stdin, or run without arguments to type it interactively:
42657
+ - \`ptbk coder add "some new feature"\`
42658
+ - \`ptbk coder add --priority 1 "some new feature"\`
42659
+ - \`ptbk coder add <<EOF ... EOF\`
42660
+ - \`ptbk coder add\`
42661
+
42662
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
42663
+ `));
42556
42664
  command.argument('[description]', 'Plain-language description of the feature or task to implement');
42557
42665
  command.option('--priority <priority>', 'Priority of the new prompt — higher priorities run first (rendered as trailing `!` markers)', parsePriorityOption, 0);
42558
42666
  command.option('--template <template>', _spaceTrim.spaceTrim(`
@@ -42562,15 +42670,26 @@
42562
42670
  .map(({ id }) => id)
42563
42671
  .join(', ')}) or a markdown file path relative to the current project root.
42564
42672
  `));
42673
+ addCoderGitSyncOptions(command);
42565
42674
  command.action(handleActionErrors(async (descriptionArgument, cliOptions) => {
42566
42675
  const { priority, template: templateOption } = cliOptions;
42676
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
42677
+ const projectPath = process.cwd();
42567
42678
  const description = await resolveCoderPromptDescription(descriptionArgument);
42568
- await addCoderPrompt({
42569
- projectPath: process.cwd(),
42679
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
42680
+ const { $commitCoderChanges, $pullCoderChanges } = await Promise.resolve().then(function () { return coderGitSync; });
42681
+ await $pullCoderChanges({ gitSync, projectPath });
42682
+ const { /* filePath,*/ emojiTag } = await addCoderPrompt({
42683
+ projectPath,
42570
42684
  description,
42571
42685
  priority,
42572
42686
  templateOption,
42573
42687
  });
42688
+ await $commitCoderChanges({
42689
+ gitSync,
42690
+ projectPath,
42691
+ commitMessage: `${emojiTag} Add prompt`,
42692
+ });
42574
42693
  }));
42575
42694
  }
42576
42695
  /**
@@ -42644,7 +42763,8 @@
42644
42763
  }
42645
42764
  return standardInputDescription;
42646
42765
  }
42647
- const response = await prompts__default["default"]({
42766
+ const { default: prompts } = await loadPromptsModule();
42767
+ const response = await prompts({
42648
42768
  type: 'text',
42649
42769
  name: 'description',
42650
42770
  message: 'Describe the feature or task to add',
@@ -43064,9 +43184,11 @@
43064
43184
  */
43065
43185
  function $initializeCoderGenerateBoilerplatesCommand(program) {
43066
43186
  const command = program.command('generate-boilerplates');
43067
- command.description(_spaceTrim.spaceTrim(`
43068
- Generate prompt boilerplate files with unique emoji tags
43069
- `));
43187
+ command.description(_spaceTrim.spaceTrim((block) => `
43188
+ Generate prompt boilerplate files with unique emoji tags
43189
+
43190
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
43191
+ `));
43070
43192
  command.option('--count <count>', `Number of prompt boilerplate files to generate`, '5');
43071
43193
  command.option('--template <template>', _spaceTrim.spaceTrim(`
43072
43194
  Prompt template to use.
@@ -43075,14 +43197,25 @@
43075
43197
  .map(({ id }) => id)
43076
43198
  .join(', ')}) or a markdown file path relative to the current project root.
43077
43199
  `));
43200
+ addCoderGitSyncOptions(command);
43078
43201
  command.action(handleActionErrors(async (cliOptions) => {
43079
43202
  const { count: countOption, template: templateOption } = cliOptions;
43080
43203
  const filesCount = parseFilesCount(countOption);
43204
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
43205
+ const projectPath = process.cwd();
43206
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
43207
+ const { $commitCoderChanges, $pullCoderChanges } = await Promise.resolve().then(function () { return coderGitSync; });
43208
+ await $pullCoderChanges({ gitSync, projectPath });
43081
43209
  await generatePromptBoilerplate({
43082
- projectPath: process.cwd(),
43210
+ projectPath,
43083
43211
  filesCount,
43084
43212
  templateOption,
43085
43213
  });
43214
+ await $commitCoderChanges({
43215
+ gitSync,
43216
+ projectPath,
43217
+ commitMessage: `Prompts ${filesCount}x`,
43218
+ });
43086
43219
  return process.exit(0);
43087
43220
  }));
43088
43221
  }
@@ -44058,12 +44191,24 @@
44058
44191
 
44059
44192
  Checks that the coding harnesses are installed globally and up to date:
44060
44193
  ${block(listCheckedHarnessLabels())}
44194
+
44195
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
44061
44196
  `));
44062
- command.action(handleActionErrors(async () => {
44197
+ addCoderGitSyncOptions(command);
44198
+ command.action(handleActionErrors(async (cliOptions) => {
44199
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
44063
44200
  const projectPath = process.cwd();
44201
+ // Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
44202
+ const { $commitCoderChanges, $pullCoderChanges } = await Promise.resolve().then(function () { return coderGitSync; });
44203
+ await $pullCoderChanges({ gitSync, projectPath });
44064
44204
  const summary = await initializeCoderProjectConfiguration(projectPath);
44065
44205
  printInitializationSummary(summary);
44066
44206
  await generatePromptBoilerplate({ projectPath, filesCount: 5 });
44207
+ await $commitCoderChanges({
44208
+ gitSync,
44209
+ projectPath,
44210
+ commitMessage: 'Initialize Promptbook Coder',
44211
+ });
44067
44212
  await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES);
44068
44213
  }));
44069
44214
  }
@@ -44085,62 +44230,44 @@
44085
44230
  // Note: [💞] Ignore a discrepancy between file name and entity name
44086
44231
 
44087
44232
  /**
44088
- * Initializes `coder ping` command for Promptbook CLI utilities.
44089
- *
44090
- * The command makes one small, isolated harness/model call, prints its result
44091
- * and reports how long the harness/model turn took.
44233
+ * Initializes `coder ping` command for Promptbook CLI utilities
44092
44234
  *
44093
- * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI.
44235
+ * Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
44094
44236
  *
44095
44237
  * @private internal function of `promptbookCli`
44096
44238
  */
44097
44239
  function $initializeCoderPingCommand(program) {
44098
44240
  const command = program.command('ping');
44099
44241
  command.description(_spaceTrim.spaceTrim(`
44100
- Test one harness and model connection with a small disposable task
44242
+ Send one tiny dummy prompt to a harness and model to measure and warm them up
44101
44243
 
44102
44244
  ${PROMPT_RUNNER_DESCRIPTION}
44103
44245
 
44104
44246
  Features:
44105
- - Runs the dummy task in a temporary directory outside the current project
44106
- - Prints the result returned by the selected harness and model
44107
- - Reports the elapsed harness/model response time in milliseconds
44108
- - Can be used to start consuming an applicable harness/model quota before a longer run
44247
+ - Verifies that the selected harness, model, thinking level and authentication really work
44248
+ - Reports the answer of the harness, the response time and the reported usage
44249
+ - Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
44250
+ - Leaves the project exactly as it was nothing is read, written, changed or committed
44251
+ - Use --no-ui to stream the raw harness output instead of only the compact result
44109
44252
  `));
44110
44253
  addPromptRunnerSelectionOptions(command);
44111
44254
  addPromptRunnerRuntimeOptions(command);
44112
44255
  command.action(handleActionErrors(async (cliOptions) => {
44113
- const normalizedOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
44114
- const agentName = normalizedOptions.agentName;
44115
- if (!agentName) {
44116
- throw new NotAllowed(_spaceTrim.spaceTrim(`
44117
- A harness is required for \`ptbk coder ping\`.
44118
-
44119
- Pass one with \`--harness <harness-name>\`.
44120
- `));
44121
- }
44122
- await $ensureHarnessInstallations([agentName]);
44123
- // Note: Import the runner-backed implementation dynamically to avoid loading heavy dependencies until needed.
44124
- const { runCoderPing } = await Promise.resolve().then(function () { return runCoderPing$1; });
44125
- const pingResult = await runCoderPing({
44126
- agentName,
44127
- model: normalizedOptions.model,
44128
- thinkingLevel: normalizedOptions.thinkingLevel,
44129
- isUiDisabled: normalizedOptions.noUi,
44130
- isCreditsAllowed: normalizedOptions.allowCredits,
44256
+ const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
44257
+ await $ensureHarnessInstallations([runnerOptions.agentName]);
44258
+ // Note: Import the ping dynamically to avoid loading heavy dependencies until needed
44259
+ const { pingCoderHarness } = await Promise.resolve().then(function () { return pingCoderHarness$1; });
44260
+ const { printCoderPingResult } = await Promise.resolve().then(function () { return printCoderPingResult$1; });
44261
+ const result = await pingCoderHarness({
44262
+ agentName: runnerOptions.agentName,
44263
+ model: runnerOptions.model,
44264
+ thinkingLevel: runnerOptions.thinkingLevel,
44265
+ allowCredits: runnerOptions.allowCredits,
44266
+ shouldPrintLiveOutput: runnerOptions.noUi,
44131
44267
  });
44132
- printCoderPingResult(pingResult);
44268
+ printCoderPingResult(result);
44133
44269
  }));
44134
44270
  }
44135
- /**
44136
- * Prints the result and duration of one completed coder ping.
44137
- */
44138
- function printCoderPingResult(pingResult) {
44139
- console.info(_spaceTrim.spaceTrim(`
44140
- Result: ${pingResult.result}
44141
- Time: ${pingResult.elapsedTimeMs.toFixed(0)} ms
44142
- `));
44143
- }
44144
44271
  // Note: [🟡] Code for CLI command [ping](src/cli/cli-commands/coder/ping.ts) should never be published outside of `@promptbook/cli`
44145
44272
  // Note: [💞] Ignore a discrepancy between file name and entity name
44146
44273
 
@@ -44511,25 +44638,31 @@
44511
44638
  */
44512
44639
  function $initializeCoderVerifyCommand(program) {
44513
44640
  const command = program.command('verify');
44514
- command.description(_spaceTrim.spaceTrim(`
44515
- Interactive verification helper for completed prompts
44641
+ command.description(_spaceTrim.spaceTrim((block) => `
44642
+ Interactive verification helper for completed prompts
44516
44643
 
44517
- Features:
44518
- - Displays list of prompt files with status counts
44519
- - Guides through verification of completed prompts marked [x]
44520
- - Archives verified prompt files to prompts/done/ directory
44521
- - Auto-appends repair prompts for incomplete work
44522
- - Processes files with all-done prompts first
44523
- - Supports ignoring matching prompt candidates for one verification run
44524
- `));
44644
+ Features:
44645
+ - Displays list of prompt files with status counts
44646
+ - Guides through verification of completed prompts marked [x]
44647
+ - Archives verified prompt files to prompts/done/ directory
44648
+ - Auto-appends repair prompts for incomplete work
44649
+ - Processes files with all-done prompts first
44650
+ - Supports ignoring matching prompt candidates for one verification run
44651
+
44652
+ ${block(CODER_GIT_SYNC_DESCRIPTION)}
44653
+
44654
+ Note: The git synchronization is applied around each single verification, not once per run.
44655
+ `));
44525
44656
  command.option('--reverse', 'Process prompt files in reverse order', false);
44526
44657
  command.option('--ignore <candidate-text>', 'Ignore prompt files whose filename or first prompt line contains the given text (repeatable)', collectStringOption, []);
44658
+ addCoderGitSyncOptions(command);
44527
44659
  command.action(handleActionErrors(async (cliOptions) => {
44528
44660
  const { reverse, ignore } = cliOptions;
44661
+ const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
44529
44662
  // Note: Import the main function dynamically to avoid loading heavy dependencies until needed
44530
44663
  const { verifyPrompts } = await Promise.resolve().then(function () { return verifyPrompts$1; });
44531
44664
  try {
44532
- await verifyPrompts({ reverse, ignore });
44665
+ await verifyPrompts({ reverse, ignore, gitSync });
44533
44666
  }
44534
44667
  catch (error) {
44535
44668
  console.error(colors__default["default"].bgRed('Prompt verification failed:'), error);
@@ -44557,8 +44690,8 @@
44557
44690
  * - add: Add one ready-to-run prompt file to the queue
44558
44691
  * - generate-boilerplates: Generate prompt boilerplate files
44559
44692
  * - find-refactor-candidates: Find files that need refactoring
44560
- * - ping: Test one harness and model connection with a disposable task
44561
44693
  * - run: Run coding prompts with AI agents
44694
+ * - ping: Test one harness and model with a tiny dummy prompt
44562
44695
  * - verify: Verify completed prompts
44563
44696
  * - find-fresh-emoji-tags: Find unused emoji tags
44564
44697
  *
@@ -44577,8 +44710,8 @@
44577
44710
  - generate-boilerplates: Generate prompt boilerplate files
44578
44711
  - find-refactor-candidates: Find files that need refactoring
44579
44712
  - find-unwritten: List prompt sections that still need to be authored
44580
- - ping: Test one harness and model connection with a disposable task
44581
44713
  - run: Run coding prompts with AI agents
44714
+ - ping: Test the connection, response time and quota of one harness and model
44582
44715
  - server: Start a long-running coder server with a kanban web UI
44583
44716
  - verify: Verify completed prompts
44584
44717
  - find-fresh-emoji-tags: Find unused emoji tags
@@ -44589,8 +44722,8 @@
44589
44722
  $initializeCoderGenerateBoilerplatesCommand(coderCommand);
44590
44723
  $initializeCoderFindRefactorCandidatesCommand(coderCommand);
44591
44724
  $initializeCoderFindUnwrittenCommand(coderCommand);
44592
- $initializeCoderPingCommand(coderCommand);
44593
44725
  $initializeCoderRunCommand(coderCommand);
44726
+ $initializeCoderPingCommand(coderCommand);
44594
44727
  $initializeCoderServerCommand(coderCommand);
44595
44728
  $initializeCoderVerifyCommand(coderCommand);
44596
44729
  $initializeCoderFindFreshEmojiTagCommand(coderCommand);
@@ -45424,6 +45557,14 @@
45424
45557
  // Note: [🟢] Code for Node file-cache storage [FileCacheStorage](src/storage/file-cache-storage/FileCacheStorage.ts) should never be published into packages that could be imported into browser environment
45425
45558
  // TODO: [🌗] Maybe some checkers, not all valid JSONs are desired and valid values
45426
45559
 
45560
+ /**
45561
+ * Loads the Socket.io client (`socket.io-client`) on demand
45562
+ *
45563
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
45564
+ *
45565
+ * @private internal utility of `createRemoteClient`
45566
+ */
45567
+ const loadSocketIoClientModule = createLazyModuleLoader(() => import('socket.io-client'));
45427
45568
  /**
45428
45569
  * Creates a connection to the remote proxy server.
45429
45570
  *
@@ -45452,8 +45593,9 @@
45452
45593
 
45453
45594
  `));
45454
45595
  }
45596
+ const { io } = await loadSocketIoClientModule();
45455
45597
  return new Promise((resolve, reject) => {
45456
- const socket = socket_ioClient.io(remoteServerUrl, {
45598
+ const socket = io(remoteServerUrl, {
45457
45599
  retries: CONNECTION_RETRIES_LIMIT,
45458
45600
  timeout: CONNECTION_TIMEOUT_MS,
45459
45601
  path: '/socket.io',
@@ -46119,7 +46261,8 @@
46119
46261
  You will be logged in to ${remoteServerUrl}
46120
46262
  If you don't have an account, it will be created automatically.
46121
46263
  `)));
46122
- const { username, password } = await prompts__default["default"]([
46264
+ const { default: prompts } = await loadPromptsModule();
46265
+ const { username, password } = await prompts([
46123
46266
  {
46124
46267
  type: 'text',
46125
46268
  name: 'username',
@@ -46494,6 +46637,15 @@
46494
46637
  // TODO: Implement non-interactive login
46495
46638
  // Note: [💞] Ignore a discrepancy between file name and entity name
46496
46639
 
46640
+ /**
46641
+ * Loads the ZIP archive library (`jszip`) on demand
46642
+ *
46643
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
46644
+ *
46645
+ * @private internal utility of `loadArchive` and `saveArchive`
46646
+ */
46647
+ const loadJsZipModule = createLazyModuleLoader(() => import('jszip'));
46648
+
46497
46649
  /**
46498
46650
  * Loads the books from the archive file with `.bookc` extension
46499
46651
  *
@@ -46508,7 +46660,8 @@
46508
46660
  throw new UnexpectedError(`Archive file must have '.bookc' extension`);
46509
46661
  }
46510
46662
  const data = await fs.readFile(filePath);
46511
- const archive = await JSZip__default["default"].loadAsync(data);
46663
+ const { default: JSZip } = await loadJsZipModule();
46664
+ const archive = await JSZip.loadAsync(data);
46512
46665
  const indexFile = archive.file('index.book.json');
46513
46666
  if (!indexFile) {
46514
46667
  throw new UnexpectedError(`Archive does not contain 'index.book.json' file`);
@@ -50571,7 +50724,23 @@
50571
50724
  });
50572
50725
  }
50573
50726
 
50574
- // TODO: [🏳‍🌈] Finally take pick of .json vs .ts
50727
+ /**
50728
+ * Loads `jsdom` on demand
50729
+ *
50730
+ * Note: [🐌] `jsdom` is by far the heaviest dependency of Promptbook, loading it eagerly would slow down every single
50731
+ * run of the `ptbk` CLI utility even when no website is scraped
50732
+ *
50733
+ * @private internal utility of `WebsiteScraper`
50734
+ */
50735
+ const loadJsdomModule = createLazyModuleLoader(() => import('jsdom'));
50736
+ /**
50737
+ * Loads `@mozilla/readability` on demand
50738
+ *
50739
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
50740
+ *
50741
+ * @private internal utility of `WebsiteScraper`
50742
+ */
50743
+ const loadReadabilityModule = createLazyModuleLoader(() => import('@mozilla/readability'));
50575
50744
  /**
50576
50745
  * Scraper for websites
50577
50746
  *
@@ -50607,14 +50776,15 @@
50607
50776
  if (this.tools.fs === undefined) {
50608
50777
  throw new EnvironmentMismatchError('Can not scrape websites without filesystem tools');
50609
50778
  }
50610
- const jsdom$1 = new jsdom.JSDOM(await source.asText(), {
50779
+ const [{ JSDOM }, { Readability }] = await Promise.all([loadJsdomModule(), loadReadabilityModule()]);
50780
+ const jsdom = new JSDOM(await source.asText(), {
50611
50781
  url: source.url,
50612
50782
  });
50613
- const reader = new readability.Readability(jsdom$1.window.document);
50783
+ const reader = new Readability(jsdom.window.document);
50614
50784
  const article = reader.parse();
50615
50785
  // console.log(article);
50616
50786
  // await forTime(10000);
50617
- let html = (article === null || article === void 0 ? void 0 : article.content) || (article === null || article === void 0 ? void 0 : article.textContent) || jsdom$1.window.document.body.innerHTML;
50787
+ let html = (article === null || article === void 0 ? void 0 : article.content) || (article === null || article === void 0 ? void 0 : article.textContent) || jsdom.window.document.body.innerHTML;
50618
50788
  // Note: Unwrap html such as it is convertable by `markdownConverter`
50619
50789
  for (let i = 0; i < 2; i++) {
50620
50790
  html = html.replace(/<div\s*(?:id="readability-page-\d+"\s+class="page")?>(.*)<\/div>/is, '$1');
@@ -50647,7 +50817,7 @@
50647
50817
  throw error;
50648
50818
  }
50649
50819
  }
50650
- const markdown = this.showdownConverter.makeMarkdown(html, jsdom$1.window.document);
50820
+ const markdown = this.showdownConverter.makeMarkdown(html, jsdom.window.document);
50651
50821
  return { ...cacheFilehandler, markdown };
50652
50822
  }
50653
50823
  /**
@@ -54210,7 +54380,8 @@
54210
54380
  for (const pipelineJson of collectionJson) {
54211
54381
  validatePipeline(pipelineJson);
54212
54382
  }
54213
- const archive = new JSZip__default["default"]();
54383
+ const { default: JSZip } = await loadJsZipModule();
54384
+ const archive = new JSZip();
54214
54385
  const collectionJsonString = stringifyPipelineJson(collectionJson);
54215
54386
  archive.file('index.book.json', collectionJsonString);
54216
54387
  const data = await archive.generateAsync({ type: 'nodebuffer', streamFiles: true });
@@ -54838,7 +55009,8 @@
54838
55009
  else {
54839
55010
  console.info(colors__default["default"].gray(`---`));
54840
55011
  }
54841
- const response = await prompts__default["default"]({
55012
+ const { default: prompts } = await loadPromptsModule();
55013
+ const response = await prompts({
54842
55014
  type: 'text',
54843
55015
  name: 'userMessage',
54844
55016
  message: 'User message',
@@ -55145,7 +55317,8 @@
55145
55317
  if (pipelineSource) {
55146
55318
  return pipelineSource;
55147
55319
  }
55148
- const response = await prompts__default["default"]({
55320
+ const { default: prompts } = await loadPromptsModule();
55321
+ const response = await prompts({
55149
55322
  type: 'text',
55150
55323
  name: 'pipelineSource',
55151
55324
  message: '',
@@ -55232,7 +55405,8 @@
55232
55405
  console.error(colors__default["default"].red(createRunMissingInputParametersMessage(pipeline, inputParameters, questions)));
55233
55406
  return process.exit(1);
55234
55407
  }
55235
- const response = await prompts__default["default"](questions);
55408
+ const { default: prompts } = await loadPromptsModule();
55409
+ const response = await prompts(questions);
55236
55410
  // <- TODO: [🧠][🍼] Change behavior according to the formfactor
55237
55411
  return { ...inputParameters, ...response };
55238
55412
  // <- TODO: Maybe do some validation of the response (and --json argument which is passed)
@@ -58137,6 +58311,14 @@
58137
58311
  fullname: 'Anthropic Claude',
58138
58312
  color: '#d97706',
58139
58313
  };
58314
+ /**
58315
+ * Loads the Anthropic Claude SDK (`@anthropic-ai/sdk`) on demand
58316
+ *
58317
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
58318
+ *
58319
+ * @private internal utility of `AnthropicClaudeExecutionTools`
58320
+ */
58321
+ const loadAnthropicClaudeModule = createLazyModuleLoader(() => import('@anthropic-ai/sdk'));
58140
58322
  /**
58141
58323
  * Execution Tools for calling Anthropic Claude API.
58142
58324
  *
@@ -58174,7 +58356,8 @@
58174
58356
  const anthropicOptions = { ...this.options };
58175
58357
  delete anthropicOptions.isVerbose;
58176
58358
  delete anthropicOptions.isProxied;
58177
- this.client = new Anthropic__default["default"](anthropicOptions);
58359
+ const { Anthropic } = await loadAnthropicClaudeModule();
58360
+ this.client = new Anthropic(anthropicOptions);
58178
58361
  }
58179
58362
  return this.client;
58180
58363
  }
@@ -58437,6 +58620,14 @@
58437
58620
  fullname: 'Azure OpenAI',
58438
58621
  color: '#0078d4',
58439
58622
  };
58623
+ /**
58624
+ * Loads the Azure OpenAI SDK (`@azure/openai`) on demand
58625
+ *
58626
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
58627
+ *
58628
+ * @private internal utility of `AzureOpenAiExecutionTools`
58629
+ */
58630
+ const loadAzureOpenAiModule = createLazyModuleLoader(() => import('@azure/openai'));
58440
58631
  /**
58441
58632
  * Execution Tools for calling Azure OpenAI API.
58442
58633
  *
@@ -58470,7 +58661,8 @@
58470
58661
  }
58471
58662
  async getClient() {
58472
58663
  if (this.client === null) {
58473
- this.client = new openai.OpenAIClient(`https://${this.options.resourceName}.openai.azure.com/`, new openai.AzureKeyCredential(this.options.apiKey));
58664
+ const { AzureKeyCredential, OpenAIClient } = await loadAzureOpenAiModule();
58665
+ this.client = new OpenAIClient(`https://${this.options.resourceName}.openai.azure.com/`, new AzureKeyCredential(this.options.apiKey));
58474
58666
  }
58475
58667
  return this.client;
58476
58668
  }
@@ -60279,6 +60471,14 @@
60279
60471
  }
60280
60472
  }
60281
60473
 
60474
+ /**
60475
+ * Loads the OpenAI SDK (`openai`) on demand
60476
+ *
60477
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
60478
+ *
60479
+ * @private internal utility of `OpenAiCompatibleRequestManager`
60480
+ */
60481
+ const loadOpenAiModule = createLazyModuleLoader(() => import('openai'));
60282
60482
  /**
60283
60483
  * Manages OpenAI-compatible client creation plus shared retry and rate-limit behavior.
60284
60484
  *
@@ -60305,7 +60505,8 @@
60305
60505
  timeout: API_REQUEST_TIMEOUT,
60306
60506
  maxRetries: CONNECTION_RETRIES_LIMIT,
60307
60507
  };
60308
- this.client = new OpenAI__default["default"](enhancedOptions);
60508
+ const { default: OpenAI } = await loadOpenAiModule();
60509
+ this.client = new OpenAI(enhancedOptions);
60309
60510
  }
60310
60511
  return this.client;
60311
60512
  }
@@ -68018,8 +68219,9 @@
68018
68219
  if (options.isVerbose) {
68019
68220
  console.info(colors__default["default"].gray('Type "exit" or "quit" to end the chat.'));
68020
68221
  }
68222
+ const { default: prompts } = await loadPromptsModule();
68021
68223
  while (true) {
68022
- const response = await prompts__default["default"]({
68224
+ const response = await prompts({
68023
68225
  type: 'text',
68024
68226
  name: 'userMessage',
68025
68227
  message: 'User message',
@@ -69231,6 +69433,16 @@
69231
69433
  }
69232
69434
  }
69233
69435
 
69436
+ /**
69437
+ * Loads the OpenAI AgentKit SDK (`@openai/agents`) on demand
69438
+ *
69439
+ * Note: [🐌] The AgentKit SDK is one of the heaviest dependencies of Promptbook, loading it eagerly would slow down
69440
+ * every single run of the `ptbk` CLI utility even when no AgentKit agent is used
69441
+ *
69442
+ * @private internal utility of `@promptbook/openai`
69443
+ */
69444
+ const loadOpenAiAgentsModule = createLazyModuleLoader(() => import('@openai/agents'));
69445
+
69234
69446
  /**
69235
69447
  * Constant for default model used for nested DeepSearch tool invocations.
69236
69448
  */
@@ -69284,11 +69496,12 @@
69284
69496
  /**
69285
69497
  * Builds the tool list for AgentKit, including hosted file search when applicable.
69286
69498
  */
69287
- buildAgentKitTools(options) {
69499
+ async buildAgentKitTools(options) {
69288
69500
  const { tools, vectorStoreId } = options;
69501
+ const { fileSearchTool, tool: agentKitTool } = await loadOpenAiAgentsModule();
69289
69502
  const agentKitTools = [];
69290
69503
  if (vectorStoreId) {
69291
- agentKitTools.push(agents.fileSearchTool(vectorStoreId));
69504
+ agentKitTools.push(fileSearchTool(vectorStoreId));
69292
69505
  }
69293
69506
  if (!tools || tools.length === 0) {
69294
69507
  return agentKitTools;
@@ -69296,11 +69509,11 @@
69296
69509
  let scriptTools = null;
69297
69510
  for (const toolDefinition of tools) {
69298
69511
  if (this.isDeepSearchToolDefinition(toolDefinition)) {
69299
- agentKitTools.push(this.createDeepSearchAgentKitTool(toolDefinition));
69512
+ agentKitTools.push(await this.createDeepSearchAgentKitTool(toolDefinition));
69300
69513
  continue;
69301
69514
  }
69302
69515
  scriptTools !== null && scriptTools !== void 0 ? scriptTools : (scriptTools = this.resolveScriptTools());
69303
- agentKitTools.push(agents.tool({
69516
+ agentKitTools.push(agentKitTool({
69304
69517
  name: toolDefinition.name,
69305
69518
  description: toolDefinition.description,
69306
69519
  parameters: this.normalizeAgentKitToolParameters(toolDefinition.parameters),
@@ -69507,12 +69720,13 @@
69507
69720
  /**
69508
69721
  * Creates the native Agent SDK tool used for `USE DEEPSEARCH`.
69509
69722
  */
69510
- createDeepSearchAgentKitTool(toolDefinition) {
69511
- const deepSearchAgent = new agents.Agent({
69723
+ async createDeepSearchAgentKitTool(toolDefinition) {
69724
+ const { Agent: AgentFromKit, webSearchTool } = await loadOpenAiAgentsModule();
69725
+ const deepSearchAgent = new AgentFromKit({
69512
69726
  name: 'DeepSearch',
69513
69727
  model: DEFAULT_DEEP_SEARCH_MODEL_NAME,
69514
69728
  instructions: this.createDeepSearchAgentInstructions(toolDefinition.description),
69515
- tools: [agents.webSearchTool({ searchContextSize: 'high' })],
69729
+ tools: [webSearchTool({ searchContextSize: 'high' })],
69516
69730
  });
69517
69731
  return deepSearchAgent.asTool({
69518
69732
  toolName: toolDefinition.name,
@@ -69721,8 +69935,9 @@
69721
69935
  vectorStoreId,
69722
69936
  });
69723
69937
  }
69724
- const agentKitTools = this.buildAgentKitTools({ tools, vectorStoreId });
69725
- const openAiAgentKitAgent = new agents.Agent({
69938
+ const { Agent: AgentFromKit } = await loadOpenAiAgentsModule();
69939
+ const agentKitTools = await this.buildAgentKitTools({ tools, vectorStoreId });
69940
+ const openAiAgentKitAgent = new AgentFromKit({
69726
69941
  name,
69727
69942
  model: this.agentKitModelName,
69728
69943
  instructions: instructions || 'You are a helpful assistant.',
@@ -69767,7 +69982,8 @@
69767
69982
  agentName: agentForRun.name,
69768
69983
  input: inputItems,
69769
69984
  };
69770
- const streamResult = await agents.run(agentForRun, inputItems, {
69985
+ const { run } = await loadOpenAiAgentsModule();
69986
+ const streamResult = await run(agentForRun, inputItems, {
69771
69987
  stream: true,
69772
69988
  maxTurns: 200,
69773
69989
  context: {
@@ -69909,11 +70125,12 @@
69909
70125
  * Ensures the AgentKit SDK is wired to the OpenAI client and API key.
69910
70126
  */
69911
70127
  async ensureAgentKitDefaults() {
70128
+ const { setDefaultOpenAIClient, setDefaultOpenAIKey } = await loadOpenAiAgentsModule();
69912
70129
  const client = await this.getClient();
69913
- agents.setDefaultOpenAIClient(client);
70130
+ setDefaultOpenAIClient(client);
69914
70131
  const apiKey = this.agentKitOptions.apiKey;
69915
70132
  if (apiKey && typeof apiKey === 'string') {
69916
- agents.setDefaultOpenAIKey(apiKey);
70133
+ setDefaultOpenAIKey(apiKey);
69917
70134
  }
69918
70135
  }
69919
70136
  /**
@@ -72241,6 +72458,66 @@
72241
72458
  RemoteAgent: RemoteAgent
72242
72459
  });
72243
72460
 
72461
+ /**
72462
+ * Git synchronization which leaves the repository completely untouched.
72463
+ *
72464
+ * Note: This is the default for every command and helper which supports the git synchronization.
72465
+ */
72466
+ const DISABLED_CODER_GIT_SYNC_OPTIONS = Object.freeze({
72467
+ isCommitEnabled: false,
72468
+ isAutoPushEnabled: false,
72469
+ isAutoPullEnabled: false,
72470
+ });
72471
+ /**
72472
+ * Pulls the latest repository changes before a `ptbk coder` command changes the project.
72473
+ */
72474
+ async function $pullCoderChanges(options) {
72475
+ const { gitSync, projectPath = process.cwd() } = options;
72476
+ if (!gitSync.isAutoPullEnabled) {
72477
+ return;
72478
+ }
72479
+ console.info(colors__default["default"].gray('Pulling the latest changes from the remote repository...'));
72480
+ await pullLatestChanges(projectPath);
72481
+ }
72482
+ /**
72483
+ * Commits - and when requested also pushes - the changes one `ptbk coder` command has just made.
72484
+ *
72485
+ * Note: A repository without any change is left alone instead of creating an empty commit.
72486
+ */
72487
+ async function $commitCoderChanges(options) {
72488
+ const { gitSync, commitMessage, projectPath = process.cwd() } = options;
72489
+ if (!gitSync.isCommitEnabled) {
72490
+ return;
72491
+ }
72492
+ if (!(await hasChangesToCommit(projectPath))) {
72493
+ console.info(colors__default["default"].gray('Nothing to commit, the working tree is clean'));
72494
+ return;
72495
+ }
72496
+ await commitChanges(commitMessage, {
72497
+ projectPath,
72498
+ autoPush: gitSync.isAutoPushEnabled,
72499
+ });
72500
+ console.info(colors__default["default"].green(`✓ ${gitSync.isAutoPushEnabled ? 'Committed and pushed' : 'Committed'}: ${commitMessage}`));
72501
+ }
72502
+ /**
72503
+ * Checks whether the repository holds any change which can be committed.
72504
+ */
72505
+ async function hasChangesToCommit(projectPath) {
72506
+ const gitStatus = await runGitCommand({
72507
+ command: 'git status --porcelain',
72508
+ cwd: projectPath,
72509
+ isVerbose: false,
72510
+ });
72511
+ return gitStatus.trim() !== '';
72512
+ }
72513
+
72514
+ var coderGitSync = /*#__PURE__*/Object.freeze({
72515
+ __proto__: null,
72516
+ DISABLED_CODER_GIT_SYNC_OPTIONS: DISABLED_CODER_GIT_SYNC_OPTIONS,
72517
+ $pullCoderChanges: $pullCoderChanges,
72518
+ $commitCoderChanges: $commitCoderChanges
72519
+ });
72520
+
72244
72521
  /**
72245
72522
  * Calculates the next available prompt numbering sequence for a month.
72246
72523
  */
@@ -72715,6 +72992,31 @@
72715
72992
  }
72716
72993
  // Note: [🟡] Code for repository script [normalizeRefactorCandidatePath](scripts/find-refactor-candidates/normalizeRefactorCandidatePath.ts) should never be published outside of `@promptbook/cli`
72717
72994
 
72995
+ /**
72996
+ * The TypeScript compiler API once it was loaded by `analyzeSourceFileForRefactorCandidate`
72997
+ *
72998
+ * Note: [🐌] `typescript` is a heavy package, it is loaded on demand so that it does not slow down every single run
72999
+ * of the `ptbk` CLI utility
73000
+ *
73001
+ * @private variable of analyzeSourceFileForRefactorCandidate
73002
+ */
73003
+ let loadedTypescriptModule = null;
73004
+ /**
73005
+ * Returns the TypeScript compiler API which was already loaded for the structural analysis.
73006
+ *
73007
+ * @private function of analyzeSourceFileForRefactorCandidate
73008
+ */
73009
+ function getLoadedTypescriptModule() {
73010
+ if (loadedTypescriptModule === null) {
73011
+ throw new UnexpectedError(spaceTrim(`
73012
+ The \`typescript\` module was not loaded yet.
73013
+
73014
+ Structural analysis helpers must be called only from \`analyzeSourceFileForRefactorCandidate\` which
73015
+ loads \`typescript\` lazily.
73016
+ `));
73017
+ }
73018
+ return loadedTypescriptModule;
73019
+ }
72718
73020
  /**
72719
73021
  * Resolves whether a source file should produce a refactor candidate entry.
72720
73022
  *
@@ -72740,6 +73042,7 @@
72740
73042
  }
72741
73043
  }
72742
73044
  if (STRUCTURAL_ANALYSIS_EXTENSIONS.includes(extension)) {
73045
+ loadedTypescriptModule !== null && loadedTypescriptModule !== void 0 ? loadedTypescriptModule : (loadedTypescriptModule = await getTypescriptModule());
72743
73046
  const structureSummary = summarizeSourceFileStructure(content, extension, filePath);
72744
73047
  if (structureSummary.entityCount > heuristics.maxEntityCountPerFile) {
72745
73048
  reasons.push(`entities ${structureSummary.entityCount}/${heuristics.maxEntityCountPerFile}`);
@@ -72799,8 +73102,9 @@
72799
73102
  * @private function of analyzeSourceFileForRefactorCandidate
72800
73103
  */
72801
73104
  function summarizeSourceFileStructure(content, extension, filePath) {
73105
+ const ts = getLoadedTypescriptModule();
72802
73106
  const scriptKind = getScriptKindForExtension(extension);
72803
- const sourceFile = ts__namespace.createSourceFile(filePath, content, ts__namespace.ScriptTarget.Latest, true, scriptKind);
73107
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, scriptKind);
72804
73108
  return {
72805
73109
  entityCount: countEntitiesInSourceFile(sourceFile),
72806
73110
  ...summarizeFunctionsInSourceFile(sourceFile),
@@ -72812,25 +73116,26 @@
72812
73116
  * @private function of analyzeSourceFileForRefactorCandidate
72813
73117
  */
72814
73118
  function countEntitiesInSourceFile(sourceFile) {
73119
+ const ts = getLoadedTypescriptModule();
72815
73120
  let count = 0;
72816
73121
  // Only count top-level declarations to avoid inflating with members or nested scopes.
72817
73122
  for (const statement of sourceFile.statements) {
72818
- if (ts__namespace.isFunctionDeclaration(statement) ||
72819
- ts__namespace.isClassDeclaration(statement) ||
72820
- ts__namespace.isInterfaceDeclaration(statement) ||
72821
- ts__namespace.isTypeAliasDeclaration(statement) ||
72822
- ts__namespace.isEnumDeclaration(statement) ||
72823
- ts__namespace.isModuleDeclaration(statement)) {
73123
+ if (ts.isFunctionDeclaration(statement) ||
73124
+ ts.isClassDeclaration(statement) ||
73125
+ ts.isInterfaceDeclaration(statement) ||
73126
+ ts.isTypeAliasDeclaration(statement) ||
73127
+ ts.isEnumDeclaration(statement) ||
73128
+ ts.isModuleDeclaration(statement)) {
72824
73129
  count += 1;
72825
73130
  continue;
72826
73131
  }
72827
- if (ts__namespace.isVariableStatement(statement)) {
73132
+ if (ts.isVariableStatement(statement)) {
72828
73133
  for (const declaration of statement.declarationList.declarations) {
72829
73134
  const initializer = declaration.initializer;
72830
73135
  if (initializer &&
72831
- (ts__namespace.isArrowFunction(initializer) ||
72832
- ts__namespace.isFunctionExpression(initializer) ||
72833
- ts__namespace.isClassExpression(initializer))) {
73136
+ (ts.isArrowFunction(initializer) ||
73137
+ ts.isFunctionExpression(initializer) ||
73138
+ ts.isClassExpression(initializer))) {
72834
73139
  count += 1;
72835
73140
  }
72836
73141
  }
@@ -72844,6 +73149,7 @@
72844
73149
  * @private function of analyzeSourceFileForRefactorCandidate
72845
73150
  */
72846
73151
  function summarizeFunctionsInSourceFile(sourceFile) {
73152
+ const ts = getLoadedTypescriptModule();
72847
73153
  let functionCount = 0;
72848
73154
  let maxFunctionComplexity = 0;
72849
73155
  let mostComplexFunctionName = null;
@@ -72856,7 +73162,7 @@
72856
73162
  mostComplexFunctionName = getFunctionDisplayName(node);
72857
73163
  }
72858
73164
  }
72859
- ts__namespace.forEachChild(node, visitNode);
73165
+ ts.forEachChild(node, visitNode);
72860
73166
  };
72861
73167
  visitNode(sourceFile);
72862
73168
  return {
@@ -72871,14 +73177,15 @@
72871
73177
  * @private function of analyzeSourceFileForRefactorCandidate
72872
73178
  */
72873
73179
  function isCountedFunctionLikeDeclaration(node) {
72874
- if (ts__namespace.isFunctionDeclaration(node) ||
72875
- ts__namespace.isMethodDeclaration(node) ||
72876
- ts__namespace.isConstructorDeclaration(node) ||
72877
- ts__namespace.isGetAccessorDeclaration(node) ||
72878
- ts__namespace.isSetAccessorDeclaration(node)) {
73180
+ const ts = getLoadedTypescriptModule();
73181
+ if (ts.isFunctionDeclaration(node) ||
73182
+ ts.isMethodDeclaration(node) ||
73183
+ ts.isConstructorDeclaration(node) ||
73184
+ ts.isGetAccessorDeclaration(node) ||
73185
+ ts.isSetAccessorDeclaration(node)) {
72879
73186
  return true;
72880
73187
  }
72881
- if (ts__namespace.isArrowFunction(node) || ts__namespace.isFunctionExpression(node)) {
73188
+ if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) {
72882
73189
  return isNamedFunctionExpression(node);
72883
73190
  }
72884
73191
  return false;
@@ -72889,8 +73196,9 @@
72889
73196
  * @private function of analyzeSourceFileForRefactorCandidate
72890
73197
  */
72891
73198
  function isNamedFunctionExpression(node) {
73199
+ const ts = getLoadedTypescriptModule();
72892
73200
  const parent = node.parent;
72893
- return (ts__namespace.isVariableDeclaration(parent) || ts__namespace.isPropertyDeclaration(parent) || ts__namespace.isPropertyAssignment(parent));
73201
+ return (ts.isVariableDeclaration(parent) || ts.isPropertyDeclaration(parent) || ts.isPropertyAssignment(parent));
72894
73202
  }
72895
73203
  /**
72896
73204
  * Calculates a lightweight cyclomatic-complexity score for one function.
@@ -72901,6 +73209,7 @@
72901
73209
  if (!functionNode.body) {
72902
73210
  return 1;
72903
73211
  }
73212
+ const ts = getLoadedTypescriptModule();
72904
73213
  let complexity = 1;
72905
73214
  const visitNode = (node) => {
72906
73215
  if (node !== functionNode.body && isCountedFunctionLikeDeclaration(node)) {
@@ -72909,7 +73218,7 @@
72909
73218
  if (isComplexityDecisionNode(node)) {
72910
73219
  complexity += 1;
72911
73220
  }
72912
- ts__namespace.forEachChild(node, visitNode);
73221
+ ts.forEachChild(node, visitNode);
72913
73222
  };
72914
73223
  visitNode(functionNode.body);
72915
73224
  return complexity;
@@ -72920,22 +73229,23 @@
72920
73229
  * @private function of analyzeSourceFileForRefactorCandidate
72921
73230
  */
72922
73231
  function isComplexityDecisionNode(node) {
72923
- if (ts__namespace.isIfStatement(node) ||
72924
- ts__namespace.isConditionalExpression(node) ||
72925
- ts__namespace.isCatchClause(node) ||
72926
- ts__namespace.isForStatement(node) ||
72927
- ts__namespace.isForInStatement(node) ||
72928
- ts__namespace.isForOfStatement(node) ||
72929
- ts__namespace.isWhileStatement(node) ||
72930
- ts__namespace.isDoStatement(node) ||
72931
- ts__namespace.isCaseClause(node)) {
73232
+ const ts = getLoadedTypescriptModule();
73233
+ if (ts.isIfStatement(node) ||
73234
+ ts.isConditionalExpression(node) ||
73235
+ ts.isCatchClause(node) ||
73236
+ ts.isForStatement(node) ||
73237
+ ts.isForInStatement(node) ||
73238
+ ts.isForOfStatement(node) ||
73239
+ ts.isWhileStatement(node) ||
73240
+ ts.isDoStatement(node) ||
73241
+ ts.isCaseClause(node)) {
72932
73242
  return true;
72933
73243
  }
72934
- if (ts__namespace.isBinaryExpression(node)) {
73244
+ if (ts.isBinaryExpression(node)) {
72935
73245
  const operatorKind = node.operatorToken.kind;
72936
- return (operatorKind === ts__namespace.SyntaxKind.AmpersandAmpersandToken ||
72937
- operatorKind === ts__namespace.SyntaxKind.BarBarToken ||
72938
- operatorKind === ts__namespace.SyntaxKind.QuestionQuestionToken);
73246
+ return (operatorKind === ts.SyntaxKind.AmpersandAmpersandToken ||
73247
+ operatorKind === ts.SyntaxKind.BarBarToken ||
73248
+ operatorKind === ts.SyntaxKind.QuestionQuestionToken);
72939
73249
  }
72940
73250
  return false;
72941
73251
  }
@@ -72945,27 +73255,28 @@
72945
73255
  * @private function of analyzeSourceFileForRefactorCandidate
72946
73256
  */
72947
73257
  function getFunctionDisplayName(functionNode) {
72948
- if (ts__namespace.isConstructorDeclaration(functionNode)) {
73258
+ const ts = getLoadedTypescriptModule();
73259
+ if (ts.isConstructorDeclaration(functionNode)) {
72949
73260
  return 'constructor';
72950
73261
  }
72951
- if (ts__namespace.isFunctionDeclaration(functionNode) ||
72952
- ts__namespace.isMethodDeclaration(functionNode) ||
72953
- ts__namespace.isGetAccessorDeclaration(functionNode) ||
72954
- ts__namespace.isSetAccessorDeclaration(functionNode)) {
73262
+ if (ts.isFunctionDeclaration(functionNode) ||
73263
+ ts.isMethodDeclaration(functionNode) ||
73264
+ ts.isGetAccessorDeclaration(functionNode) ||
73265
+ ts.isSetAccessorDeclaration(functionNode)) {
72955
73266
  if (!functionNode.name) {
72956
73267
  return null;
72957
73268
  }
72958
73269
  return getPropertyNameText(functionNode.name);
72959
73270
  }
72960
- if (ts__namespace.isArrowFunction(functionNode) || ts__namespace.isFunctionExpression(functionNode)) {
73271
+ if (ts.isArrowFunction(functionNode) || ts.isFunctionExpression(functionNode)) {
72961
73272
  if (functionNode.name) {
72962
73273
  return functionNode.name.text;
72963
73274
  }
72964
73275
  const parent = functionNode.parent;
72965
- if (ts__namespace.isVariableDeclaration(parent)) {
73276
+ if (ts.isVariableDeclaration(parent)) {
72966
73277
  return getBindingNameText(parent.name);
72967
73278
  }
72968
- if (ts__namespace.isPropertyDeclaration(parent) || ts__namespace.isPropertyAssignment(parent)) {
73279
+ if (ts.isPropertyDeclaration(parent) || ts.isPropertyAssignment(parent)) {
72969
73280
  return getPropertyNameText(parent.name);
72970
73281
  }
72971
73282
  }
@@ -72977,7 +73288,8 @@
72977
73288
  * @private function of analyzeSourceFileForRefactorCandidate
72978
73289
  */
72979
73290
  function getBindingNameText(name) {
72980
- return ts__namespace.isIdentifier(name) ? name.text : null;
73291
+ const ts = getLoadedTypescriptModule();
73292
+ return ts.isIdentifier(name) ? name.text : null;
72981
73293
  }
72982
73294
  /**
72983
73295
  * Resolves text for a property name while preserving computed names when necessary.
@@ -72985,7 +73297,8 @@
72985
73297
  * @private function of analyzeSourceFileForRefactorCandidate
72986
73298
  */
72987
73299
  function getPropertyNameText(name) {
72988
- if (ts__namespace.isIdentifier(name) || ts__namespace.isPrivateIdentifier(name) || ts__namespace.isStringLiteral(name) || ts__namespace.isNumericLiteral(name)) {
73300
+ const ts = getLoadedTypescriptModule();
73301
+ if (ts.isIdentifier(name) || ts.isPrivateIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)) {
72989
73302
  return name.text;
72990
73303
  }
72991
73304
  return name.getText();
@@ -73007,16 +73320,17 @@
73007
73320
  * @private function of analyzeSourceFileForRefactorCandidate
73008
73321
  */
73009
73322
  function getScriptKindForExtension(extension) {
73323
+ const ts = getLoadedTypescriptModule();
73010
73324
  if (extension === '.tsx') {
73011
- return ts__namespace.ScriptKind.TSX;
73325
+ return ts.ScriptKind.TSX;
73012
73326
  }
73013
73327
  if (extension === '.jsx') {
73014
- return ts__namespace.ScriptKind.JSX;
73328
+ return ts.ScriptKind.JSX;
73015
73329
  }
73016
73330
  if (extension === '.js') {
73017
- return ts__namespace.ScriptKind.JS;
73331
+ return ts.ScriptKind.JS;
73018
73332
  }
73019
- return ts__namespace.ScriptKind.TS;
73333
+ return ts.ScriptKind.TS;
73020
73334
  }
73021
73335
  /**
73022
73336
  * Normalizes an absolute path for consistent comparisons.
@@ -73866,63 +74180,240 @@
73866
74180
  });
73867
74181
 
73868
74182
  /**
73869
- * Agent source used by `ptbk coder ping` for its disposable connectivity turn.
74183
+ * Builds a normalized temporary shell script path for prompt runners.
73870
74184
  */
73871
- const PING_AGENT_SOURCE = _spaceTrim.spaceTrim(`
73872
- Promptbook Coder Ping Agent
74185
+ function buildTemporaryPromptScriptPath(options) {
74186
+ const sourceFileName = path.basename(options.sourceFileName);
74187
+ const scriptFileName = `${sourceFileName.replace(/\.[^.]+$/u, '')}${options.suffix || ''}.sh`;
74188
+ return resolvePromptbookTemporaryPath(options.projectPath, options.scriptDirectoryName, scriptFileName);
74189
+ }
73873
74190
 
73874
- PERSONA You are a connectivity test agent. Perform only the tiny task requested by the user and answer concisely.
73875
- `);
73876
74191
  /**
73877
- * User message used by `ptbk coder ping` to produce a deterministic response.
74192
+ * Marker the pinged harness is asked to prefix its answer with, so the reply can be recognized
74193
+ * in the raw runner output of every supported harness.
74194
+ *
74195
+ * Note: The marker must stay free of regular-expression metacharacters, because
74196
+ * `extractCoderPingAnswer` builds its pattern from it.
74197
+ */
74198
+ const CODER_PING_ANSWER_MARKER = 'PTBK-CODER-PING-ANSWER';
74199
+ /**
74200
+ * First factor of the dummy multiplication the pinged harness is asked to compute.
74201
+ */
74202
+ const CODER_PING_FIRST_FACTOR = 6;
74203
+ /**
74204
+ * Second factor of the dummy multiplication the pinged harness is asked to compute.
74205
+ */
74206
+ const CODER_PING_SECOND_FACTOR = 7;
74207
+ /**
74208
+ * Answer a working harness and model returns for the dummy work of `ptbk coder ping`.
73878
74209
  */
73879
- const PING_MESSAGE = 'Reply with exactly the single word PONG and nothing else.';
74210
+ const CODER_PING_EXPECTED_ANSWER = String(CODER_PING_FIRST_FACTOR * CODER_PING_SECOND_FACTOR);
73880
74211
  /**
73881
- * Runs one small harness/model turn in a disposable temporary project.
74212
+ * Builds the dummy prompt sent by `ptbk coder ping`.
73882
74213
  *
73883
- * The temporary project is outside the caller's repository, so even a harness
73884
- * that writes files cannot change the project from which `ptbk coder ping` was
73885
- * started.
74214
+ * The work is intentionally the smallest possible one that still reaches the model: it spends a
74215
+ * negligible amount of the harness quota, it needs no tool and it explicitly forbids touching the
74216
+ * project, so a ping leaves the project exactly as it was.
73886
74217
  */
73887
- async function runCoderPing(options) {
73888
- const temporaryProjectPath = await promises.mkdtemp(path.join(os.tmpdir(), 'promptbook-coder-ping-'));
73889
- const originalWorkingDirectory = process.cwd();
73890
- try {
73891
- const agentPath = path.join(temporaryProjectPath, 'ping.book');
73892
- await promises.writeFile(agentPath, `${PING_AGENT_SOURCE}\n`, 'utf-8');
73893
- // Note: Some supported CLI wrappers inherit the Node process working directory instead of using projectPath.
73894
- process.chdir(temporaryProjectPath);
73895
- const startedAt = performance.now();
73896
- const result = await executeAgentChatTurn({
73897
- agentPath,
73898
- currentWorkingDirectory: temporaryProjectPath,
73899
- agentName: options.agentName,
73900
- model: options.model,
73901
- isVerbose: false,
73902
- noUi: options.isUiDisabled,
73903
- thinkingLevel: options.thinkingLevel,
73904
- allowCredits: options.isCreditsAllowed,
73905
- messages: [
73906
- {
73907
- sender: 'USER',
73908
- content: PING_MESSAGE,
73909
- },
73910
- ],
74218
+ function buildCoderPingPrompt() {
74219
+ return spaceTrim(`
74220
+ # Promptbook connection check
74221
+
74222
+ This is an automated \`ptbk coder ping\` connection check, not a coding task.
74223
+
74224
+ Do exactly this and nothing else:
74225
+
74226
+ 1. Multiply \`${CODER_PING_FIRST_FACTOR}\` by \`${CODER_PING_SECOND_FACTOR}\`.
74227
+ 2. Answer with one single line \`${CODER_PING_ANSWER_MARKER}: <result>\` where \`<result>\` is the number you computed.
74228
+
74229
+ Rules:
74230
+
74231
+ - Do not read, create, change, move or delete any file.
74232
+ - Do not run any command and do not use any tool.
74233
+ - Do not write anything except the single answer line.
74234
+ `);
74235
+ }
74236
+
74237
+ /**
74238
+ * Pattern matching one answer line produced by the pinged harness.
74239
+ *
74240
+ * The captured answer deliberately stops at a quote, a backslash or a line break, so an answer
74241
+ * embedded in a JSON event stream — as produced by Claude Code, Opencode or Codex `--json` — is
74242
+ * captured without the surrounding JSON.
74243
+ */
74244
+ const CODER_PING_ANSWER_PATTERN = new RegExp(`${CODER_PING_ANSWER_MARKER}\\s*:[ \\t]*([^\\r\\n"\\\\]*)`, 'gu');
74245
+ /**
74246
+ * Extracts the answer of a pinged harness from the runtime log of its runner shell.
74247
+ *
74248
+ * Only the raw output of the last execution is searched, so the answer marker contained in the
74249
+ * prompt of the raw input is never mistaken for the answer of the harness.
74250
+ *
74251
+ * @returns The answer of the harness, or `null` when the harness produced no recognizable answer
74252
+ */
74253
+ function extractCoderPingAnswer(runtimeLog) {
74254
+ var _a;
74255
+ const rawOutput = runtimeLog.split(SCRIPT_EXECUTION_LOG_RAW_OUTPUT_MARKER).pop();
74256
+ if (rawOutput === undefined) {
74257
+ return null;
74258
+ }
74259
+ // Note: The last answer wins because harnesses which stream partial messages repeat the growing answer line
74260
+ const answers = Array.from(rawOutput.matchAll(CODER_PING_ANSWER_PATTERN))
74261
+ .map((match) => (match[1] || '').trim())
74262
+ .filter((answer) => answer !== '');
74263
+ return (_a = answers[answers.length - 1]) !== null && _a !== void 0 ? _a : null;
74264
+ }
74265
+
74266
+ /**
74267
+ * Temporary subdirectory used for the `ptbk coder ping` runner shell script and its runtime log.
74268
+ */
74269
+ const CODER_PING_SCRIPT_DIRECTORY_NAME = 'coder-ping';
74270
+ /**
74271
+ * Base name of the temporary `ptbk coder ping` runner shell script.
74272
+ */
74273
+ const CODER_PING_SCRIPT_SOURCE_NAME = 'ping';
74274
+ /**
74275
+ * Sends one tiny dummy prompt through the selected harness and model and measures the round trip.
74276
+ *
74277
+ * The ping reuses the very same runner the coding queue uses, so it really exercises the configured
74278
+ * harness, model, thinking level and authentication — including the retry behavior on rate limits.
74279
+ * Both temporary artifacts it creates are removed again, so the project is left as it was.
74280
+ */
74281
+ async function pingCoderHarness(options) {
74282
+ const projectPath = options.projectPath || process.cwd();
74283
+ const { runner, runnerMetadata } = resolvePromptRunner(options);
74284
+ const scriptPath = buildTemporaryPromptScriptPath({
74285
+ projectPath,
74286
+ scriptDirectoryName: CODER_PING_SCRIPT_DIRECTORY_NAME,
74287
+ sourceFileName: CODER_PING_SCRIPT_SOURCE_NAME,
74288
+ });
74289
+ const startedTimeMs = Date.now();
74290
+ const { answer, usage, loginMethod } = await withPromptRuntimeLog(scriptPath, async (logPath) => {
74291
+ var _a;
74292
+ const result = await runner.runPrompt({
74293
+ prompt: buildCoderPingPrompt(),
74294
+ scriptPath,
74295
+ projectPath,
74296
+ logPath,
74297
+ shouldPrintLiveOutput: (_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : false,
74298
+ preserveArtifactsOnSuccess: false,
73911
74299
  });
73912
- return {
73913
- result: result.answer,
73914
- elapsedTimeMs: performance.now() - startedAt,
73915
- };
74300
+ return { ...result, answer: extractCoderPingAnswer(await readRuntimeLog(logPath)) };
74301
+ }, { preserveArtifactsOnSuccess: false });
74302
+ return {
74303
+ runnerName: runnerMetadata.runnerName,
74304
+ modelName: runnerMetadata.modelName,
74305
+ thinkingLevel: options.thinkingLevel,
74306
+ answer,
74307
+ isAnswerCorrect: answer === CODER_PING_EXPECTED_ANSWER,
74308
+ durationMs: Date.now() - startedTimeMs,
74309
+ usage,
74310
+ loginMethod,
74311
+ };
74312
+ }
74313
+ /**
74314
+ * Reads the runtime log of the finished ping, treating an unreadable log as no output at all.
74315
+ */
74316
+ async function readRuntimeLog(logPath) {
74317
+ return await promises.readFile(logPath, 'utf-8').catch(() => '');
74318
+ }
74319
+
74320
+ var pingCoderHarness$1 = /*#__PURE__*/Object.freeze({
74321
+ __proto__: null,
74322
+ pingCoderHarness: pingCoderHarness
74323
+ });
74324
+
74325
+ /**
74326
+ * Formats usage price for display in prompt status lines and task details.
74327
+ * Examples:
74328
+ * - "$0.12" (certain)
74329
+ * - "~$3.05" (uncertain)
74330
+ * - "$0.00" (zero cost)
74331
+ * - "<$0.01" (tiny non-zero cost)
74332
+ *
74333
+ * @private internal utility of the prompt runners and the Agents Server task details
74334
+ */
74335
+ function formatUsagePrice(usage) {
74336
+ const price = usage.price.value;
74337
+ const isUncertain = usage.price.isUncertain === true;
74338
+ const prefix = isUncertain ? '~' : '';
74339
+ if (price === 0) {
74340
+ return `${prefix}$0.00`;
73916
74341
  }
73917
- finally {
73918
- process.chdir(originalWorkingDirectory);
73919
- await promises.rm(temporaryProjectPath, { recursive: true, force: true });
74342
+ if (price < 0.01) {
74343
+ return `${prefix}<$0.01`;
74344
+ }
74345
+ if (price < 1) {
74346
+ return `${prefix}$${price.toFixed(4)}`;
74347
+ }
74348
+ return `${prefix}$${price.toFixed(2)}`;
74349
+ }
74350
+
74351
+ /**
74352
+ * Formats runner details for prompt status lines.
74353
+ */
74354
+ function formatRunnerSignature(runnerName, modelName, thinkingLevel) {
74355
+ const normalizedRunner = runnerName === null || runnerName === void 0 ? void 0 : runnerName.trim();
74356
+ const normalizedModel = modelName === null || modelName === void 0 ? void 0 : modelName.trim();
74357
+ const thinkingLevelSuffix = thinkingLevel ? ` thinking \`${thinkingLevel}\`` : '';
74358
+ if (!normalizedRunner && !normalizedModel) {
74359
+ return 'unknown';
74360
+ }
74361
+ const runnerLabel = normalizedRunner || 'unknown';
74362
+ if (!normalizedModel) {
74363
+ return `${runnerLabel}${thinkingLevelSuffix}`;
73920
74364
  }
74365
+ return `${runnerLabel} \`${normalizedModel}\`${thinkingLevelSuffix}`;
73921
74366
  }
73922
74367
 
73923
- var runCoderPing$1 = /*#__PURE__*/Object.freeze({
74368
+ /**
74369
+ * Prints the compact summary of one finished `ptbk coder ping`.
74370
+ */
74371
+ function printCoderPingResult(result) {
74372
+ const runnerSignature = formatRunnerSignature(result.runnerName, result.modelName, result.thinkingLevel);
74373
+ const loginMethodLabel = formatCodexLoginMethod(result.loginMethod);
74374
+ const loginMethodSuffix = loginMethodLabel === undefined ? '' : ` (${loginMethodLabel})`;
74375
+ console.info(colors__default["default"].green(`🏓 ${runnerSignature}${loginMethodSuffix} answered in ${formatCoderPingResponseTime(result.durationMs)}`));
74376
+ console.info(colors__default["default"].gray(` Answer: ${formatCoderPingAnswer(result)}`));
74377
+ console.info(colors__default["default"].gray(` Usage: ${formatCoderPingUsage(result.usage)}`));
74378
+ }
74379
+ /**
74380
+ * Formats the measured round-trip time, keeping the sub-second precision a response time needs.
74381
+ */
74382
+ function formatCoderPingResponseTime(durationMs) {
74383
+ return `${(durationMs / 1000).toFixed(2)}s`;
74384
+ }
74385
+ /**
74386
+ * Formats the answer of the pinged harness together with what was expected from it.
74387
+ */
74388
+ function formatCoderPingAnswer(result) {
74389
+ if (result.answer === null) {
74390
+ return `Reached, but the answer line was missing from the output (expected \`${CODER_PING_EXPECTED_ANSWER}\`)`;
74391
+ }
74392
+ if (result.isAnswerCorrect) {
74393
+ return result.answer;
74394
+ }
74395
+ return `${result.answer} (expected \`${CODER_PING_EXPECTED_ANSWER}\`)`;
74396
+ }
74397
+ /**
74398
+ * Formats the resources the pinged harness reported for the dummy work.
74399
+ */
74400
+ function formatCoderPingUsage(usage) {
74401
+ return [
74402
+ formatUsagePrice(usage),
74403
+ `${formatUncertainCount(usage.input.tokensCount)} input tokens`,
74404
+ `${formatUncertainCount(usage.output.tokensCount)} output tokens`,
74405
+ ].join(', ');
74406
+ }
74407
+ /**
74408
+ * Formats one counted usage value, marking an estimated count with a leading `~`.
74409
+ */
74410
+ function formatUncertainCount(count) {
74411
+ return `${count.isUncertain === true ? '~' : ''}${Math.round(count.value)}`;
74412
+ }
74413
+
74414
+ var printCoderPingResult$1 = /*#__PURE__*/Object.freeze({
73924
74415
  __proto__: null,
73925
- runCoderPing: runCoderPing
74416
+ printCoderPingResult: printCoderPingResult
73926
74417
  });
73927
74418
 
73928
74419
  /**
@@ -75837,6 +76328,14 @@
75837
76328
  .filter((statement) => statement !== '');
75838
76329
  }
75839
76330
 
76331
+ /**
76332
+ * Loads the PostgreSQL client (`pg`) on demand
76333
+ *
76334
+ * Note: [🐌] Loaded lazily to keep the startup of the `ptbk` CLI utility fast
76335
+ *
76336
+ * @private function of runAutoMigrateTestingServers
76337
+ */
76338
+ const loadPostgresModule = createLazyModuleLoader(() => import('pg'));
75840
76339
  /**
75841
76340
  * Migration targets for testing servers that should be migrated by coding-script auto-migration.
75842
76341
  */
@@ -75914,7 +76413,8 @@
75914
76413
  * @returns Pending migration files grouped by prefix.
75915
76414
  */
75916
76415
  async function listPendingMigrationsByPrefix(options) {
75917
- const client = new pg.Client({
76416
+ const { Client } = await loadPostgresModule();
76417
+ const client = new Client({
75918
76418
  connectionString: options.connectionString,
75919
76419
  ssl: { rejectUnauthorized: false },
75920
76420
  });
@@ -76071,15 +76571,6 @@
76071
76571
  return lines.join(file.eol);
76072
76572
  }
76073
76573
 
76074
- /**
76075
- * Builds a normalized temporary shell script path for prompt runners.
76076
- */
76077
- function buildTemporaryPromptScriptPath(options) {
76078
- const sourceFileName = path.basename(options.sourceFileName);
76079
- const scriptFileName = `${sourceFileName.replace(/\.[^.]+$/u, '')}${options.suffix || ''}.sh`;
76080
- return resolvePromptbookTemporaryPath(options.projectPath, options.scriptDirectoryName, scriptFileName);
76081
- }
76082
-
76083
76574
  /**
76084
76575
  * Builds the suffix which disambiguates one prompt section inside its prompt file.
76085
76576
  *
@@ -76106,32 +76597,6 @@
76106
76597
  });
76107
76598
  }
76108
76599
 
76109
- /**
76110
- * Formats usage price for display in prompt status lines and task details.
76111
- * Examples:
76112
- * - "$0.12" (certain)
76113
- * - "~$3.05" (uncertain)
76114
- * - "$0.00" (zero cost)
76115
- * - "<$0.01" (tiny non-zero cost)
76116
- *
76117
- * @private internal utility of the prompt runners and the Agents Server task details
76118
- */
76119
- function formatUsagePrice(usage) {
76120
- const price = usage.price.value;
76121
- const isUncertain = usage.price.isUncertain === true;
76122
- const prefix = isUncertain ? '~' : '';
76123
- if (price === 0) {
76124
- return `${prefix}$0.00`;
76125
- }
76126
- if (price < 0.01) {
76127
- return `${prefix}<$0.01`;
76128
- }
76129
- if (price < 1) {
76130
- return `${prefix}$${price.toFixed(4)}`;
76131
- }
76132
- return `${prefix}$${price.toFixed(2)}`;
76133
- }
76134
-
76135
76600
  /**
76136
76601
  * Human-readable labels for each coder run step kind shown in prompt status lines.
76137
76602
  */
@@ -76176,23 +76641,6 @@
76176
76641
  return `(failed after ${attemptCount} attempts) `;
76177
76642
  }
76178
76643
 
76179
- /**
76180
- * Formats runner details for prompt status lines.
76181
- */
76182
- function formatRunnerSignature(runnerName, modelName, thinkingLevel) {
76183
- const normalizedRunner = runnerName === null || runnerName === void 0 ? void 0 : runnerName.trim();
76184
- const normalizedModel = modelName === null || modelName === void 0 ? void 0 : modelName.trim();
76185
- const thinkingLevelSuffix = thinkingLevel ? ` thinking \`${thinkingLevel}\`` : '';
76186
- if (!normalizedRunner && !normalizedModel) {
76187
- return 'unknown';
76188
- }
76189
- const runnerLabel = normalizedRunner || 'unknown';
76190
- if (!normalizedModel) {
76191
- return `${runnerLabel}${thinkingLevelSuffix}`;
76192
- }
76193
- return `${runnerLabel} \`${normalizedModel}\`${thinkingLevelSuffix}`;
76194
- }
76195
-
76196
76644
  /**
76197
76645
  * Replaces the complete todo status line while preserving its indentation.
76198
76646
  *
@@ -79346,14 +79794,21 @@
79346
79794
  let promptFiles = initialFiles;
79347
79795
  const skippedFiles = new Set();
79348
79796
  while (true) {
79797
+ // Note: The git synchronization is applied around each single verification, not once per whole run
79798
+ await $pullCoderChanges({ gitSync: normalizedOptions.gitSync });
79799
+ if (normalizedOptions.gitSync.isAutoPullEnabled) {
79800
+ // Note: The pull can bring in prompt file changes, so the queue is reloaded before it is used
79801
+ promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
79802
+ }
79349
79803
  displayPromptOverview(promptFiles);
79350
79804
  // First priority: verify files where all prompts are marked as done
79351
79805
  const fileWithAllDone = findFileWithAllDonePrompts(promptFiles, skippedFiles);
79352
79806
  if (fileWithAllDone) {
79353
- const wasSkipped = await verifyDonePromptsInFile(fileWithAllDone);
79354
- if (wasSkipped) {
79807
+ const outcome = await verifyDonePromptsInFile(fileWithAllDone);
79808
+ if (outcome.wasSkipped) {
79355
79809
  skippedFiles.add(fileWithAllDone.path);
79356
79810
  }
79811
+ await $commitVerificationOutcome(normalizedOptions.gitSync, outcome);
79357
79812
  promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
79358
79813
  continue;
79359
79814
  }
@@ -79363,10 +79818,20 @@
79363
79818
  console.info(colors__default["default"].green('\n✅ All prompts have been verified.'));
79364
79819
  break;
79365
79820
  }
79366
- await resolvePrompt(nextPrompt);
79821
+ const outcome = await resolvePrompt(nextPrompt);
79822
+ await $commitVerificationOutcome(normalizedOptions.gitSync, outcome);
79367
79823
  promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
79368
79824
  }
79369
79825
  }
79826
+ /**
79827
+ * Commits and pushes one applied verification when the git synchronization is enabled.
79828
+ */
79829
+ async function $commitVerificationOutcome(gitSync, outcome) {
79830
+ if (outcome.commitMessage === null) {
79831
+ return;
79832
+ }
79833
+ await $commitCoderChanges({ gitSync, commitMessage: outcome.commitMessage });
79834
+ }
79370
79835
  /**
79371
79836
  * Parses supported command-line arguments for the standalone verification script.
79372
79837
  */
@@ -79374,6 +79839,11 @@
79374
79839
  return {
79375
79840
  reverse: args.includes('--reverse'),
79376
79841
  ignore: readRepeatableStringOption(args, '--ignore'),
79842
+ gitSync: {
79843
+ isCommitEnabled: args.includes('--commit'),
79844
+ isAutoPushEnabled: args.includes('--auto-push'),
79845
+ isAutoPullEnabled: args.includes('--auto-pull'),
79846
+ },
79377
79847
  };
79378
79848
  }
79379
79849
  /**
@@ -79425,10 +79895,11 @@
79425
79895
  * Normalizes verification options so the rest of the flow can assume stable defaults.
79426
79896
  */
79427
79897
  function normalizeVerifyPromptsOptions(options) {
79428
- var _a, _b;
79898
+ var _a, _b, _c;
79429
79899
  return {
79430
79900
  reverse: (_a = options.reverse) !== null && _a !== void 0 ? _a : false,
79431
79901
  ignore: normalizeIgnoreValues((_b = options.ignore) !== null && _b !== void 0 ? _b : []),
79902
+ gitSync: (_c = options.gitSync) !== null && _c !== void 0 ? _c : DISABLED_CODER_GIT_SYNC_OPTIONS,
79432
79903
  };
79433
79904
  }
79434
79905
  /**
@@ -79559,7 +80030,6 @@
79559
80030
  /**
79560
80031
  * Verifies the last done [x] prompt in a file and decides whether to archive it or add a repair prompt.
79561
80032
  * Ignores not-ready prompts like [-], [.], [?], etc.
79562
- * Returns true if the file was skipped, false otherwise.
79563
80033
  */
79564
80034
  async function verifyDonePromptsInFile(file) {
79565
80035
  const doneCount = file.sections.filter((s) => s.status === 'done').length;
@@ -79579,32 +80049,45 @@
79579
80049
  }
79580
80050
  if (!lastDoneSection) {
79581
80051
  console.info(colors__default["default"].gray('No done [x] prompts found in this file.'));
79582
- return false;
80052
+ return { wasSkipped: false, commitMessage: null };
79583
80053
  }
79584
80054
  console.info(colors__default["default"].gray('Verifying the last [x] prompt in the file...\n'));
79585
80055
  displayPromptSnippet({ file, section: lastDoneSection });
79586
80056
  const decision = await promptForDoneVerification(file, lastDoneSection);
79587
80057
  if (decision === 'done') {
79588
80058
  await archivePromptFile(file);
79589
- return false;
80059
+ return { wasSkipped: false, commitMessage: buildArchiveCommitMessage(file) };
79590
80060
  }
79591
80061
  else if (decision === 'needs-work') {
79592
80062
  console.info(colors__default["default"].yellow('\n⚠️ This prompt needs repair.'));
79593
80063
  await appendRepairPrompt(file, lastDoneSection);
79594
- return false;
80064
+ return { wasSkipped: false, commitMessage: buildRepairCommitMessage(file) };
79595
80065
  }
79596
80066
  else {
79597
80067
  console.info(colors__default["default"].gray('\n⏩ Skipped, no changes made.'));
79598
- return true;
80068
+ return { wasSkipped: true, commitMessage: null };
79599
80069
  }
79600
80070
  }
80071
+ /**
80072
+ * Builds the commit message describing one archived prompt file.
80073
+ */
80074
+ function buildArchiveCommitMessage(file) {
80075
+ return `✅ Prompt done and archived \`${file.name}\``; // <- $commitCoderChanges({
80076
+ }
80077
+ /**
80078
+ * Builds the commit message describing one appended repair prompt.
80079
+ */
80080
+ function buildRepairCommitMessage(file) {
80081
+ return `❌ Repair prompt added into \`${file.name}\``; // <- $commitCoderChanges({
80082
+ }
79601
80083
  /**
79602
80084
  * Asks the user to verify if a done prompt is actually completed.
79603
80085
  * Returns 'done' if verified, 'needs-work' if not done, or 'skip' to skip this file.
79604
80086
  */
79605
80087
  async function promptForDoneVerification(file, section) {
79606
80088
  const promptLabel = buildPromptLabelForDisplay(file, section);
79607
- const response = await prompts__default["default"]({
80089
+ const { default: prompts } = await loadPromptsModule();
80090
+ const response = await prompts({
79608
80091
  type: 'select',
79609
80092
  name: 'verified',
79610
80093
  message: `Is ${colors__default["default"].bold(promptLabel)} actually done?`,
@@ -79672,17 +80155,18 @@
79672
80155
  const decision = await promptForDecision(selection);
79673
80156
  if (decision === 'done') {
79674
80157
  await archivePromptFile(selection.file);
80158
+ return { wasSkipped: false, commitMessage: buildArchiveCommitMessage(selection.file) };
79675
80159
  }
79676
- else {
79677
- await appendRepairPrompt(selection.file, selection.section);
79678
- }
80160
+ await appendRepairPrompt(selection.file, selection.section);
80161
+ return { wasSkipped: false, commitMessage: buildRepairCommitMessage(selection.file) };
79679
80162
  }
79680
80163
  /**
79681
80164
  * Presents the interactive decision menu for the current prompt section.
79682
80165
  */
79683
80166
  async function promptForDecision(selection) {
79684
80167
  const promptLabel = buildPromptLabelForDisplay(selection.file, selection.section);
79685
- const response = await prompts__default["default"]({
80168
+ const { default: prompts } = await loadPromptsModule();
80169
+ const response = await prompts({
79686
80170
  type: 'select',
79687
80171
  name: 'decision',
79688
80172
  message: `Is ${colors__default["default"].bold(promptLabel)} resolved?`,