@promptbook/cli 0.112.0-31 → 0.112.0-32

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 (63) hide show
  1. package/esm/index.es.js +183 -50
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/scripts/run-codex-prompts/runners/github-copilot/GitHubCopilotRunner.d.ts +19 -0
  4. package/esm/scripts/run-codex-prompts/runners/github-copilot/buildGitHubCopilotScript.d.ts +5 -0
  5. package/esm/src/_packages/components.index.d.ts +6 -0
  6. package/esm/src/_packages/types.index.d.ts +6 -0
  7. package/esm/src/book-2.0/agent-source/AgentReferenceResolver.d.ts +11 -0
  8. package/esm/src/book-2.0/agent-source/CreateAgentModelRequirementsOptions.d.ts +8 -0
  9. package/esm/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +33 -0
  10. package/esm/src/book-2.0/agent-source/createTeamToolName.d.ts +7 -7
  11. package/esm/src/book-components/Chat/Chat/ChatActionsBar.d.ts +5 -0
  12. package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +17 -1
  13. package/esm/src/book-components/Chat/Chat/ChatMessageItem.test.d.ts +1 -1
  14. package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +14 -0
  15. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +290 -0
  16. package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +16 -0
  17. package/esm/src/book-components/Chat/Chat/renderAdvancedToolCallDetails.d.ts +4 -0
  18. package/esm/src/book-components/Chat/Chat/renderToolCallDetails.d.ts +9 -0
  19. package/esm/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +2 -1
  20. package/esm/src/book-components/Chat/MarkdownContent/MarkdownContent.test.d.ts +2 -0
  21. package/esm/src/book-components/Chat/hooks/useChatCompleteNotification.d.ts +18 -0
  22. package/esm/src/book-components/Chat/hooks/useChatCompleteNotification.test.d.ts +2 -0
  23. package/esm/src/book-components/Chat/types/ChatMessage.d.ts +77 -1
  24. package/esm/src/book-components/Chat/utils/formatToolCallDateTime.d.ts +37 -0
  25. package/esm/src/book-components/Chat/utils/formatToolCallLocalTime.d.ts +11 -0
  26. package/esm/src/book-components/Chat/utils/formatToolCallTranslationTemplate.d.ts +10 -0
  27. package/esm/src/book-components/Chat/utils/getChatMessageTimingDisplay.d.ts +5 -1
  28. package/esm/src/book-components/Chat/utils/getToolCallChipletInfo.d.ts +26 -1
  29. package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +26 -3
  30. package/esm/src/utils/toolCalls/mergeToolCalls.d.ts +1 -1
  31. package/esm/src/version.d.ts +1 -1
  32. package/package.json +1 -1
  33. package/umd/index.umd.js +183 -50
  34. package/umd/index.umd.js.map +1 -1
  35. package/umd/scripts/run-codex-prompts/runners/github-copilot/GitHubCopilotRunner.d.ts +19 -0
  36. package/umd/scripts/run-codex-prompts/runners/github-copilot/buildGitHubCopilotScript.d.ts +5 -0
  37. package/umd/src/_packages/components.index.d.ts +6 -0
  38. package/umd/src/_packages/types.index.d.ts +6 -0
  39. package/umd/src/book-2.0/agent-source/AgentReferenceResolver.d.ts +11 -0
  40. package/umd/src/book-2.0/agent-source/CreateAgentModelRequirementsOptions.d.ts +8 -0
  41. package/umd/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +33 -0
  42. package/umd/src/book-2.0/agent-source/createTeamToolName.d.ts +7 -7
  43. package/umd/src/book-components/Chat/Chat/ChatActionsBar.d.ts +5 -0
  44. package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +17 -1
  45. package/umd/src/book-components/Chat/Chat/ChatMessageItem.test.d.ts +1 -1
  46. package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +14 -0
  47. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +290 -0
  48. package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +16 -0
  49. package/umd/src/book-components/Chat/Chat/renderAdvancedToolCallDetails.d.ts +4 -0
  50. package/umd/src/book-components/Chat/Chat/renderToolCallDetails.d.ts +9 -0
  51. package/umd/src/book-components/Chat/MarkdownContent/MarkdownContent.d.ts +2 -1
  52. package/umd/src/book-components/Chat/MarkdownContent/MarkdownContent.test.d.ts +2 -0
  53. package/umd/src/book-components/Chat/hooks/useChatCompleteNotification.d.ts +18 -0
  54. package/umd/src/book-components/Chat/hooks/useChatCompleteNotification.test.d.ts +2 -0
  55. package/umd/src/book-components/Chat/types/ChatMessage.d.ts +77 -1
  56. package/umd/src/book-components/Chat/utils/formatToolCallDateTime.d.ts +37 -0
  57. package/umd/src/book-components/Chat/utils/formatToolCallLocalTime.d.ts +11 -0
  58. package/umd/src/book-components/Chat/utils/formatToolCallTranslationTemplate.d.ts +10 -0
  59. package/umd/src/book-components/Chat/utils/getChatMessageTimingDisplay.d.ts +5 -1
  60. package/umd/src/book-components/Chat/utils/getToolCallChipletInfo.d.ts +26 -1
  61. package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +26 -3
  62. package/umd/src/utils/toolCalls/mergeToolCalls.d.ts +1 -1
  63. package/umd/src/version.d.ts +1 -1
package/esm/index.es.js CHANGED
@@ -57,7 +57,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
57
57
  * @generated
58
58
  * @see https://github.com/webgptorg/promptbook
59
59
  */
60
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-31';
60
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-32';
61
61
  /**
62
62
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
63
63
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -2040,6 +2040,7 @@ function $initializeCoderRunCommand(program) {
2040
2040
 
2041
2041
  Runners:
2042
2042
  - openai-codex: OpenAI Codex integration (requires --model)
2043
+ - github-copilot: GitHub Copilot CLI integration
2043
2044
  - cline: Cline CLI integration
2044
2045
  - claude-code: Claude Code integration
2045
2046
  - opencode: Opencode integration
@@ -2052,7 +2053,7 @@ function $initializeCoderRunCommand(program) {
2052
2053
  - Dry-run mode to preview prompts
2053
2054
  `));
2054
2055
  command.option('--dry-run', 'Print unwritten prompts without executing', false);
2055
- command.option('--agent <agent-name>', 'Select runner: openai-codex, cline, claude-code, opencode, gemini (required for non-dry-run)');
2056
+ command.option('--agent <agent-name>', 'Select runner: openai-codex, github-copilot, cline, claude-code, opencode, gemini (required for non-dry-run)');
2056
2057
  command.option('--model <model>', spaceTrim$1(`
2057
2058
  Model to use (required for openai-codex and gemini)
2058
2059
 
@@ -2072,6 +2073,7 @@ function $initializeCoderRunCommand(program) {
2072
2073
  let agentName = undefined;
2073
2074
  if (agent) {
2074
2075
  if (agent === 'openai-codex' ||
2076
+ agent === 'github-copilot' ||
2075
2077
  agent === 'cline' ||
2076
2078
  agent === 'claude-code' ||
2077
2079
  agent === 'opencode' ||
@@ -2079,12 +2081,12 @@ function $initializeCoderRunCommand(program) {
2079
2081
  agentName = agent;
2080
2082
  }
2081
2083
  else {
2082
- console.error(colors.red(`Invalid agent "${agent}". Must be one of: openai-codex, cline, claude-code, opencode, gemini`));
2084
+ console.error(colors.red(`Invalid agent "${agent}". Must be one of: openai-codex, github-copilot, cline, claude-code, opencode, gemini`));
2083
2085
  return process.exit(1);
2084
2086
  }
2085
2087
  }
2086
2088
  if (!agentName && !dryRun) {
2087
- console.error(colors.red('You must choose an agent using --agent <openai-codex|cline|claude-code|opencode|gemini>'));
2089
+ console.error(colors.red('You must choose an agent using --agent <openai-codex|github-copilot|cline|claude-code|opencode|gemini>'));
2088
2090
  return process.exit(1);
2089
2091
  }
2090
2092
  // Convert commander options to RunOptions format
@@ -21113,10 +21115,6 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
21113
21115
  * Prefix used for TEAM tool names.
21114
21116
  */
21115
21117
  const TEAM_TOOL_PREFIX = 'team_chat_';
21116
- /**
21117
- * Length of URL hash suffix appended to TEAM tool names.
21118
- */
21119
- const TEAM_TOOL_HASH_LENGTH = 10;
21120
21118
  /**
21121
21119
  * Fallback normalized name when teammate label is empty.
21122
21120
  */
@@ -21133,20 +21131,19 @@ function normalizeTeammateToolNamePart(teammateLabel) {
21133
21131
  return normalized || TEAM_TOOL_FALLBACK_NAME;
21134
21132
  }
21135
21133
  /**
21136
- * Builds a deterministic TEAM tool name from teammate identity.
21134
+ * Builds a deterministic TEAM tool name from the teammate label.
21137
21135
  *
21138
- * The readable part is based on teammate label while the hash suffix
21139
- * keeps uniqueness and stable mapping for the underlying teammate URL.
21136
+ * The tool name is derived solely from the human-readable label so that it
21137
+ * remains stable and predictable regardless of internal technical identifiers.
21140
21138
  *
21141
- * @param teammateUrl - Canonical teammate URL used at runtime.
21142
- * @param teammateLabel - Human-readable teammate label.
21143
- * @returns Deterministic TEAM tool name.
21139
+ * @param _teammateUrl - Canonical teammate URL (kept for API compatibility, not used).
21140
+ * @param teammateLabel - Human-readable teammate label used as the basis for the name.
21141
+ * @returns TEAM tool name derived from the label.
21144
21142
  * @private internal utility of TEAM commitments and chat UI mapping
21145
21143
  */
21146
- function createTeamToolName(teammateUrl, teammateLabel) {
21144
+ function createTeamToolName(_teammateUrl, teammateLabel) {
21147
21145
  const normalizedLabel = normalizeTeammateToolNamePart(teammateLabel);
21148
- const hash = computeHash(teammateUrl).substring(0, TEAM_TOOL_HASH_LENGTH);
21149
- return `${TEAM_TOOL_PREFIX}${normalizedLabel}_${hash}`;
21146
+ return `${TEAM_TOOL_PREFIX}${normalizedLabel}`;
21150
21147
  }
21151
21148
 
21152
21149
  const urlRegex = /https?:\/\/[^\s]+/gi;
@@ -21351,7 +21348,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
21351
21348
  `);
21352
21349
  }
21353
21350
  applyToAgentModelRequirements(requirements, content) {
21354
- var _a, _b;
21351
+ var _a, _b, _c;
21355
21352
  const trimmedContent = content.trim();
21356
21353
  if (!trimmedContent) {
21357
21354
  return requirements;
@@ -21363,14 +21360,18 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
21363
21360
  }
21364
21361
  const agentName = ((_a = requirements._metadata) === null || _a === void 0 ? void 0 : _a.agentName) || 'Agent';
21365
21362
  const existingTeammates = ((_b = requirements._metadata) === null || _b === void 0 ? void 0 : _b.teammates) || [];
21363
+ const preResolvedProfiles = (((_c = requirements._metadata) === null || _c === void 0 ? void 0 : _c.preResolvedTeammateProfiles) || {});
21366
21364
  const resolvedTeammates = resolveTeamTeammateLabels(trimmedContent, teammates);
21367
21365
  const teamEntries = resolvedTeammates.map((teammate) => {
21366
+ const profile = preResolvedProfiles[teammate.url];
21367
+ const resolvedLabel = (profile === null || profile === void 0 ? void 0 : profile.agentName) || teammate.label;
21368
21368
  const existingTeammate = existingTeammates.find((entry) => entry.url === teammate.url);
21369
21369
  return {
21370
21370
  toolName: ((existingTeammate === null || existingTeammate === void 0 ? void 0 : existingTeammate.toolName) ||
21371
- createTeamToolName(teammate.url, teammate.label)),
21372
- teammate,
21371
+ createTeamToolName(teammate.url, resolvedLabel)),
21372
+ teammate: { ...teammate, label: resolvedLabel },
21373
21373
  agentName,
21374
+ description: (profile === null || profile === void 0 ? void 0 : profile.personaDescription) || null,
21374
21375
  };
21375
21376
  });
21376
21377
  for (const entry of teamEntries) {
@@ -21382,9 +21383,12 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
21382
21383
  if (updatedTools.some((tool) => tool.name === entry.toolName)) {
21383
21384
  continue;
21384
21385
  }
21386
+ const toolDescription = entry.description
21387
+ ? `Consult teammate ${entry.teammate.label}\n${entry.description}`
21388
+ : `Consult teammate ${entry.teammate.label}`;
21385
21389
  updatedTools.push({
21386
21390
  name: entry.toolName,
21387
- description: `Consult teammate ${entry.teammate.label}`,
21391
+ description: toolDescription,
21388
21392
  parameters: {
21389
21393
  type: 'object',
21390
21394
  properties: {
@@ -21413,8 +21417,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
21413
21417
  toolName: entry.toolName,
21414
21418
  });
21415
21419
  }
21416
- const teamOverviewText = createTeamOverviewText(trimmedContent, teamEntries);
21417
- const teamSystemMessage = this.createSystemMessageSection('Teammates:', buildTeamSystemMessageBody(teamOverviewText, teamEntries));
21420
+ const teamSystemMessage = this.createSystemMessageSection('Teammates:', buildTeamSystemMessageBody(teamEntries));
21418
21421
  return this.appendToSystemMessage({
21419
21422
  ...requirements,
21420
21423
  tools: updatedTools,
@@ -21451,25 +21454,24 @@ function resolveTeamTeammateLabels(teamContent, teammates) {
21451
21454
  };
21452
21455
  });
21453
21456
  }
21454
- /**
21455
- * Rewrites TEAM commitment content into a URL-free teammate overview text.
21456
- */
21457
- function createTeamOverviewText(teamContent, teamEntries) {
21458
- let overviewText = teamContent;
21459
- for (const entry of teamEntries) {
21460
- overviewText = overviewText.split(entry.teammate.url).join(entry.teammate.label);
21461
- }
21462
- return overviewText.trim();
21463
- }
21464
21457
  /**
21465
21458
  * Builds the textual TEAM section body for the final system message.
21459
+ *
21460
+ * Each teammate is listed with its tool name and, when available, a one-line description.
21461
+ * Uses `spaceTrim` to ensure consistent whitespace and indentation.
21466
21462
  */
21467
- function buildTeamSystemMessageBody(teamOverviewText, teamEntries) {
21468
- const teammateLines = teamEntries.map((entry, index) => `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``);
21469
- if (!teamOverviewText) {
21470
- return teammateLines.join('\n');
21471
- }
21472
- return `${teamOverviewText}\n\n${teammateLines.join('\n')}`;
21463
+ function buildTeamSystemMessageBody(teamEntries) {
21464
+ const lines = teamEntries.map((entry, index) => {
21465
+ const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
21466
+ if (!entry.description) {
21467
+ return toolLine;
21468
+ }
21469
+ return spaceTrim$1(`
21470
+ ${toolLine}
21471
+ ${entry.description}
21472
+ `);
21473
+ });
21474
+ return lines.join('\n');
21473
21475
  }
21474
21476
  /**
21475
21477
  * Registers tool function and title for a teammate tool.
@@ -39117,7 +39119,7 @@ function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
39117
39119
  * @private @@@
39118
39120
  */
39119
39121
  async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
39120
- var _a;
39122
+ var _a, _b, _c;
39121
39123
  const agentReferenceResolver = options === null || options === void 0 ? void 0 : options.agentReferenceResolver;
39122
39124
  // Parse the agent source to extract commitments
39123
39125
  const parseResult = parseAgentSourceWithCommitments(agentSource);
@@ -39185,6 +39187,36 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
39185
39187
  if (commitment.type === 'CLOSED' && i !== filteredCommitments.length - 1) {
39186
39188
  continue;
39187
39189
  }
39190
+ // For TEAM commitments, pre-resolve teammate profiles if a resolver is provided
39191
+ // and store them in metadata before the commitment is applied.
39192
+ const profileResolver = (_a = options === null || options === void 0 ? void 0 : options.teammateProfileResolver) !== null && _a !== void 0 ? _a : options === null || options === void 0 ? void 0 : options.agentReferenceResolver;
39193
+ if (commitment.type === 'TEAM' && (profileResolver === null || profileResolver === void 0 ? void 0 : profileResolver.resolveTeammateProfile)) {
39194
+ try {
39195
+ const parsedTeammates = parseTeamCommitmentContent(commitmentContent, { strict: false });
39196
+ const preResolved = {
39197
+ ...(_b = requirements._metadata) === null || _b === void 0 ? void 0 : _b.preResolvedTeammateProfiles,
39198
+ };
39199
+ for (const teammate of parsedTeammates) {
39200
+ if (preResolved[teammate.url]) {
39201
+ continue;
39202
+ }
39203
+ const profile = await profileResolver.resolveTeammateProfile(teammate.url);
39204
+ if (profile) {
39205
+ preResolved[teammate.url] = profile;
39206
+ }
39207
+ }
39208
+ requirements = {
39209
+ ...requirements,
39210
+ _metadata: {
39211
+ ...requirements._metadata,
39212
+ preResolvedTeammateProfiles: preResolved,
39213
+ },
39214
+ };
39215
+ }
39216
+ catch (error) {
39217
+ console.warn('Failed to pre-resolve teammate profiles for TEAM commitment:', error);
39218
+ }
39219
+ }
39188
39220
  const definition = getCommitmentDefinition(commitment.type);
39189
39221
  if (definition) {
39190
39222
  try {
@@ -39280,7 +39312,7 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
39280
39312
  // Add example interactions to the system message
39281
39313
  const examples = [];
39282
39314
  // 1. Initial message as an example agent response
39283
- const initialMessage = (_a = parseResult.commitments.find((c) => c.type === 'INITIAL MESSAGE')) === null || _a === void 0 ? void 0 : _a.content;
39315
+ const initialMessage = (_c = parseResult.commitments.find((c) => c.type === 'INITIAL MESSAGE')) === null || _c === void 0 ? void 0 : _c.content;
39284
39316
  if (initialMessage) {
39285
39317
  examples.push(`Agent: ${initialMessage}`);
39286
39318
  }
@@ -40733,6 +40765,7 @@ async function findRefactorCandidates() {
40733
40765
  const { selectedEmojis } = await getFreshPromptEmojiTags({
40734
40766
  count: candidatesToWrite.length,
40735
40767
  rootDir,
40768
+ tagPrefix: '🧹',
40736
40769
  });
40737
40770
  await mkdir(promptsDir, { recursive: true });
40738
40771
  const createdPrompts = [];
@@ -40745,7 +40778,7 @@ async function findRefactorCandidates() {
40745
40778
  if (!selectedEmoji) {
40746
40779
  throw new Error(`Missing emoji for prompt candidate #${index + 1}`);
40747
40780
  }
40748
- const emojiTag = formatPromptEmojiTag(selectedEmoji);
40781
+ const emojiTag = formatPromptEmojiTag(selectedEmoji, '🧹');
40749
40782
  const promptContent = buildPromptContent(candidate, emojiTag);
40750
40783
  await writeFile(promptPath, promptContent, 'utf-8');
40751
40784
  createdPrompts.push(filename);
@@ -40791,7 +40824,7 @@ function buildPromptGuidance(candidate) {
40791
40824
  if (counts.entityCount !== null && counts.maxEntities !== null) {
40792
40825
  guidance.push(`- The file defines too many responsibilities (${counts.entityCount} in single file)`, ` - Keep in mind the Single Responsibility Principle (SRP)`, ` - Consider breaking it down into smaller, focused modules or components.`);
40793
40826
  }
40794
- guidance.push('- Purpose of this refactoring is to improve code maintainability and readability.', '- Look at the internal structure, the usage and also surrounding code to understand how to best refactor this file.', '- Consider breaking down large functions into smaller, more manageable ones, removing any redundant code, and ensuring that the file adheres to the project coding standards.', '- After the refactoring, ensure that (1) `npm run test-name-discrepancies` and (2) `npm run test-package-generation` are passing successfully.', ' 1. All the things you have moved to new files should correspond the thing in the file with the file name, for example `MyComponent.tsx` should export `MyComponent`.', ' 2. All the things you have moved to new files but are private things to the outside world should have `@private function of TheMainThing` JSDoc comment.', '- Keep in mind DRY *(Do not repeat yourself)* and SOLID principles while refactoring.', '- **Do not change the external behavior** of the code. Focus solely on improving the internal structure and organization of the code.');
40827
+ guidance.push('- Purpose of this refactoring is to improve code maintainability and readability.', '- Look at the internal structure, the usage and also surrounding code to understand how to best refactor this file.', '- Consider breaking down large functions into smaller, more manageable ones, removing any redundant code, and ensuring that the file adheres to the project coding standards.', '- After the refactoring, ensure that (1) `npm run test-name-discrepancies` and (2) `npm run test-package-generation` are passing successfully.', ' 1. All the things you have moved to new files should correspond the thing in the file with the file name, for example `MyComponent.tsx` should export `MyComponent`.', ' 2. All the things you have moved to new files but are private things to the outside world should have `@private function of TheMainThing` JSDoc comment.', '- Keep in mind DRY *(Do not repeat yourself)* and SOLID principles while refactoring.', '- **Do not change the external behavior** of the code. Focus solely on improving the internal structure and organization of the code.', '- Before you start refactoring, make sure to read the code carefully and understand its current structure and functionality. Do a analysis of the current functionality before you start.');
40795
40828
  // <- TODO: Leverage `spaceTrim` here
40796
40829
  return guidance;
40797
40830
  }
@@ -41043,6 +41076,7 @@ function parseRunOptions(args) {
41043
41076
  if (agentValue) {
41044
41077
  const value = agentValue;
41045
41078
  if (value === 'openai-codex' ||
41079
+ value === 'github-copilot' ||
41046
41080
  value === 'cline' ||
41047
41081
  value === 'claude-code' ||
41048
41082
  value === 'opencode' ||
@@ -41059,7 +41093,7 @@ function parseRunOptions(args) {
41059
41093
  const autoMigrate = args.includes('--auto-migrate');
41060
41094
  const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
41061
41095
  if (!agentName && !dryRun) {
41062
- exitWithUsageError('You must choose an agent using --agent <openai-codex|cline|claude-code|opencode|gemini>');
41096
+ exitWithUsageError('You must choose an agent using --agent <openai-codex|github-copilot|cline|claude-code|opencode|gemini>');
41063
41097
  }
41064
41098
  return {
41065
41099
  dryRun,
@@ -43488,6 +43522,7 @@ function createCodingContext() {
43488
43522
  - Keep small responsibilities of functions and classes, avoid creating big functions or classes that do many things.
43489
43523
  - When throwing errors, throw [branded errors](src/errors) and use \`spaceTrim\` utility to write clear and well-formatted multilie detailed error messages.
43490
43524
  - Format errors as markdown, for example \`variabiles\` should be in backticks, important notes can be in bold, etc.
43525
+ - Constants should be always \`UPPER_SNAKE_CASE\`
43491
43526
  - When writing multiline strings, use \`spaceTrim\` utility
43492
43527
  - DO only the change described here above DO not add any additional features or make any additional changes that are not described in the prompt.
43493
43528
  - If you find some critical issue that is not described in the prompt, report it to the file \`./AGENT_REPORT.md\` on the root of the project
@@ -43851,6 +43886,60 @@ class GeminiRunner {
43851
43886
  }
43852
43887
  }
43853
43888
 
43889
+ /**
43890
+ * Builds the shell script that runs GitHub Copilot CLI with the prompt and coding context.
43891
+ */
43892
+ function buildGitHubCopilotScript(options) {
43893
+ const delimiter = 'GITHUB_COPILOT_PROMPT';
43894
+ const projectPath = toPosixPath(options.projectPath);
43895
+ const modelArgument = options.model ? ` --model ${options.model}` : '';
43896
+ return spaceTrim((block) => `
43897
+ cd "${projectPath}"
43898
+
43899
+ copilot -p "$(cat <<'${delimiter}'
43900
+
43901
+ ${block(options.prompt)}
43902
+
43903
+ ${block(createCodingContext())}
43904
+
43905
+ ${delimiter}
43906
+ )" \
43907
+ --yolo \
43908
+ --no-ask-user \
43909
+ --no-color \
43910
+ --output-format json \
43911
+ --stream off${modelArgument}
43912
+ `);
43913
+ }
43914
+
43915
+ /**
43916
+ * Runs prompts via the GitHub Copilot CLI.
43917
+ */
43918
+ class GitHubCopilotRunner {
43919
+ /**
43920
+ * Creates a new GitHub Copilot runner.
43921
+ */
43922
+ constructor(options) {
43923
+ this.options = options;
43924
+ this.name = 'github-copilot';
43925
+ }
43926
+ /**
43927
+ * Runs the prompt using GitHub Copilot CLI.
43928
+ */
43929
+ async runPrompt(options) {
43930
+ const scriptContent = buildGitHubCopilotScript({
43931
+ prompt: options.prompt,
43932
+ projectPath: options.projectPath,
43933
+ model: this.options.model,
43934
+ });
43935
+ await $runGoScript({
43936
+ scriptPath: options.scriptPath,
43937
+ scriptContent,
43938
+ });
43939
+ return { usage: UNCERTAIN_USAGE };
43940
+ }
43941
+ }
43942
+
43854
43943
  /**
43855
43944
  * Maximum number of output characters included in thrown error messages.
43856
43945
  */
@@ -44588,6 +44677,7 @@ const DEFAULT_CODEX_MODEL = 'gpt-5.2-codex';
44588
44677
  const CLINE_MODEL = 'gemini:gemini-3-flash-preview';
44589
44678
  const RUNNER_LABELS = {
44590
44679
  'openai-codex': 'OpenAI Codex',
44680
+ 'github-copilot': 'GitHub Copilot',
44591
44681
  cline: 'Cline',
44592
44682
  'claude-code': 'Claude Code',
44593
44683
  opencode: 'Opencode',
@@ -44603,6 +44693,9 @@ function getRunnerMetadata(options, actualModel) {
44603
44693
  if (options.agentName === 'openai-codex') {
44604
44694
  modelName = actualModel;
44605
44695
  }
44696
+ else if (options.agentName === 'github-copilot') {
44697
+ modelName = actualModel;
44698
+ }
44606
44699
  else if (options.agentName === 'gemini') {
44607
44700
  modelName = actualModel;
44608
44701
  }
@@ -44640,8 +44733,7 @@ async function runCodexPrompts(providedOptions) {
44640
44733
  return;
44641
44734
  }
44642
44735
  let runner;
44643
- let actualCodexModel;
44644
- let actualGeminiModel;
44736
+ let actualRunnerModel;
44645
44737
  const agentName = options.agentName;
44646
44738
  if (!agentName) {
44647
44739
  throw new Error('Missing --agent in non-dry run mode');
@@ -44668,7 +44760,7 @@ async function runCodexPrompts(providedOptions) {
44668
44760
  else {
44669
44761
  modelToUse = options.model;
44670
44762
  }
44671
- actualCodexModel = modelToUse;
44763
+ actualRunnerModel = modelToUse;
44672
44764
  runner = new OpenAiCodexRunner({
44673
44765
  codexCommand: 'codex',
44674
44766
  model: modelToUse,
@@ -44685,6 +44777,13 @@ async function runCodexPrompts(providedOptions) {
44685
44777
  model: CLINE_MODEL,
44686
44778
  });
44687
44779
  }
44780
+ else if (agentName === 'github-copilot') {
44781
+ const modelToUse = options.model === 'default' ? undefined : options.model;
44782
+ actualRunnerModel = modelToUse;
44783
+ runner = new GitHubCopilotRunner({
44784
+ model: modelToUse,
44785
+ });
44786
+ }
44688
44787
  else if (agentName === 'claude-code') {
44689
44788
  runner = new ClaudeCodeRunner();
44690
44789
  }
@@ -44709,7 +44808,7 @@ async function runCodexPrompts(providedOptions) {
44709
44808
  else {
44710
44809
  modelToUse = options.model;
44711
44810
  }
44712
- actualGeminiModel = modelToUse;
44811
+ actualRunnerModel = modelToUse;
44713
44812
  runner = new GeminiRunner({
44714
44813
  model: modelToUse,
44715
44814
  });
@@ -44718,7 +44817,7 @@ async function runCodexPrompts(providedOptions) {
44718
44817
  throw new Error(`Unknown agent: ${agentName}`);
44719
44818
  }
44720
44819
  console.info(colors.green(`Running prompts with ${runner.name}`));
44721
- const runnerMetadata = getRunnerMetadata(options, actualCodexModel !== null && actualCodexModel !== void 0 ? actualCodexModel : actualGeminiModel);
44820
+ const runnerMetadata = getRunnerMetadata(options, actualRunnerModel);
44722
44821
  let hasShownUpcomingTasks = false;
44723
44822
  let hasWaitedForStart = false;
44724
44823
  while (just(true)) {
@@ -45465,13 +45564,23 @@ function getToolCallIdentity(toolCall) {
45465
45564
  */
45466
45565
  function mergeToolCalls(existingToolCalls, incomingToolCalls) {
45467
45566
  if (!existingToolCalls || existingToolCalls.length === 0) {
45468
- return incomingToolCalls ? [...incomingToolCalls] : [];
45567
+ return incomingToolCalls ? deduplicatePreparationToolCalls([...incomingToolCalls]) : [];
45469
45568
  }
45470
45569
  if (!incomingToolCalls || incomingToolCalls.length === 0) {
45471
45570
  return [...existingToolCalls];
45472
45571
  }
45473
45572
  const mergedToolCalls = [...existingToolCalls];
45474
45573
  for (const incomingToolCall of incomingToolCalls) {
45574
+ if (isAssistantPreparationToolCall(incomingToolCall)) {
45575
+ // A new preparation phase always replaces any previous assistant_preparation tool
45576
+ // call, regardless of phase argument, so only one chip is ever shown at a time.
45577
+ const existingPreparationIndex = mergedToolCalls.findIndex(isAssistantPreparationToolCall);
45578
+ if (existingPreparationIndex !== -1) {
45579
+ mergedToolCalls.splice(existingPreparationIndex, 1);
45580
+ }
45581
+ mergedToolCalls.push(incomingToolCall);
45582
+ continue;
45583
+ }
45475
45584
  const incomingIdentity = getToolCallIdentity(incomingToolCall);
45476
45585
  const existingIndex = mergedToolCalls.findIndex((existingToolCall) => getToolCallIdentity(existingToolCall) === incomingIdentity);
45477
45586
  if (existingIndex === -1) {
@@ -45583,6 +45692,30 @@ function serializeValueForMerge(value) {
45583
45692
  return String(value);
45584
45693
  }
45585
45694
  }
45695
+ /**
45696
+ * Ensures at most one `assistant_preparation` tool call survives in the list,
45697
+ * keeping the last occurrence so the most recent preparation phase is shown.
45698
+ *
45699
+ * @param toolCalls - Mutable list to deduplicate in-place.
45700
+ * @returns The same array after removing redundant preparation entries.
45701
+ * @private helper of `mergeToolCalls`
45702
+ */
45703
+ function deduplicatePreparationToolCalls(toolCalls) {
45704
+ let lastPreparationIndex = -1;
45705
+ for (let index = toolCalls.length - 1; index >= 0; index--) {
45706
+ if (!isAssistantPreparationToolCall(toolCalls[index])) {
45707
+ continue;
45708
+ }
45709
+ if (lastPreparationIndex === -1) {
45710
+ lastPreparationIndex = index;
45711
+ }
45712
+ else {
45713
+ // Remove earlier duplicate — keep only the last (most recent) one.
45714
+ toolCalls.splice(index, 1);
45715
+ }
45716
+ }
45717
+ return toolCalls;
45718
+ }
45586
45719
 
45587
45720
  /**
45588
45721
  * Gets all tool titles provided by all commitments