@promptbook/cli 0.112.0-126 → 0.112.0-128

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 (190) hide show
  1. package/README.md +5 -5
  2. package/apps/agents-server/README.md +3 -0
  3. package/apps/agents-server/playwright.config.ts +1 -0
  4. package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
  5. package/apps/agents-server/public/promptbook-logo-white.png +0 -0
  6. package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
  7. package/apps/agents-server/src/app/actions.ts +2 -2
  8. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
  9. package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
  11. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
  12. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
  13. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
  14. package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
  15. package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
  16. package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
  17. package/apps/agents-server/src/app/globals.css +78 -0
  18. package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
  19. package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
  20. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
  21. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
  22. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
  23. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
  24. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
  25. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
  26. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
  27. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
  28. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
  29. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
  30. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
  31. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
  32. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
  33. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
  34. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
  35. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
  36. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
  37. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
  38. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
  39. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
  40. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
  41. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
  42. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
  43. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
  44. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
  45. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
  46. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
  47. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
  48. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
  49. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
  50. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
  51. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
  52. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
  53. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
  54. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
  55. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
  56. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
  57. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
  58. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
  59. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
  60. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
  61. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
  62. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
  63. package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
  64. package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
  65. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
  66. package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
  67. package/apps/agents-server/src/database/getMetadata.ts +37 -1
  68. package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
  69. package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
  70. package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
  71. package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
  72. package/apps/agents-server/src/languages/translations/english.yaml +1 -1
  73. package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
  74. package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
  75. package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
  76. package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
  77. package/apps/agents-server/src/utils/session.ts +62 -5
  78. package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
  79. package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
  80. package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
  81. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
  82. package/esm/index.es.js +1052 -455
  83. package/esm/index.es.js.map +1 -1
  84. package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  85. package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  86. package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  87. package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  88. package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  89. package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  90. package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  91. package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  92. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  93. package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  94. package/esm/src/_packages/components.index.d.ts +2 -0
  95. package/esm/src/_packages/types.index.d.ts +2 -0
  96. package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  97. package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  98. package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  99. package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  100. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  101. package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  102. package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  103. package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  104. package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  105. package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  106. package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  107. package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  108. package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  109. package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  110. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  111. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  112. package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  113. package/esm/src/version.d.ts +1 -1
  114. package/package.json +1 -1
  115. package/src/_packages/components.index.ts +2 -0
  116. package/src/_packages/types.index.ts +2 -0
  117. package/src/avatars/avatarAnimationScheduler.ts +61 -20
  118. package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
  119. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
  120. package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
  121. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
  122. package/src/book-components/Chat/Chat/Chat.tsx +4 -0
  123. package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
  124. package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
  125. package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
  126. package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
  127. package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
  128. package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
  129. package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
  130. package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
  131. package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
  132. package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
  133. package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
  134. package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
  135. package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
  136. package/src/book-components/Chat/types/ChatMessage.ts +5 -0
  137. package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
  138. package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
  139. package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
  140. package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
  141. package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
  142. package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
  143. package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
  144. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  145. package/src/cli/cli-commands/coder/run.ts +17 -20
  146. package/src/cli/cli-commands/coder/server.ts +13 -16
  147. package/src/cli/common/$deprecateCliCommand.ts +10 -1
  148. package/src/commitments/GOAL/GOAL.ts +7 -2
  149. package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
  150. package/src/commitments/TEAM/TEAM.ts +12 -1
  151. package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
  152. package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
  153. package/src/import-plugins/TextFileImportPlugin.ts +8 -1
  154. package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
  155. package/src/other/templates/getTemplatesPipelineCollection.ts +713 -785
  156. package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
  157. package/src/version.ts +2 -2
  158. package/src/versions.txt +1 -0
  159. package/umd/index.umd.js +1055 -458
  160. package/umd/index.umd.js.map +1 -1
  161. package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  162. package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  163. package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  164. package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  165. package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  166. package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  167. package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  168. package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  169. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  170. package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  171. package/umd/src/_packages/components.index.d.ts +2 -0
  172. package/umd/src/_packages/types.index.d.ts +2 -0
  173. package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  174. package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  175. package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  176. package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  177. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  178. package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  179. package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  180. package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  181. package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  182. package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  183. package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  184. package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  185. package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  186. package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  187. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  188. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  189. package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  190. package/umd/src/version.d.ts +1 -1
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Commits staged changes with the provided message using the dedicated coding-agent identity when configured,
3
3
  * otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush`,
4
- * `options.includePaths` can restrict staging, and `options.excludePaths` can keep temporary artifacts out of the created commit.
4
+ * `options.includePaths` can restrict staging, `options.onlyPaths` can restrict the commit pathspec,
5
+ * and `options.excludePaths` can keep temporary artifacts out of the created commit.
5
6
  */
6
7
  export declare function commitChanges(message: string, options?: {
7
8
  autoPush?: boolean;
8
9
  includePaths?: ReadonlyArray<string>;
10
+ onlyPaths?: ReadonlyArray<string>;
9
11
  excludePaths?: ReadonlyArray<string>;
10
12
  projectPath?: string;
11
13
  }): Promise<void>;
@@ -1,6 +1,6 @@
1
- import type { WaitForCoderRunPauseCheckpoint } from '../common/CoderRunPauseCheckpoint';
2
- import type { CliProgressDisplay } from '../common/cliProgressDisplay';
3
1
  import type { RunOptions } from '../cli/RunOptions';
2
+ import type { CliProgressDisplay } from '../common/cliProgressDisplay';
3
+ import type { WaitForCoderRunPauseCheckpoint } from '../common/CoderRunPauseCheckpoint';
4
4
  import type { PromptSelection } from '../prompts/types/PromptSelection';
5
5
  import type { PromptRunner } from '../runners/types/PromptRunner';
6
6
  import type { CoderRunUiHandle } from '../ui/renderCoderRunUi';
@@ -0,0 +1,50 @@
1
+ import type { PromptFile } from '../prompts/types/PromptFile';
2
+ import type { PromptStatus } from '../prompts/types/PromptStatus';
3
+ import type { CoderRunUiState } from '../ui/CoderRunUiState';
4
+ /**
5
+ * Browser board columns used by `ptbk coder server`.
6
+ */
7
+ export type CoderServerBoardColumn = 'backlog' | 'low-priority' | 'todo' | 'in-progress' | 'done' | 'errors' | 'finished';
8
+ /**
9
+ * UI tag attached to one prompt card.
10
+ */
11
+ export type CoderServerPromptTag = {
12
+ readonly id: 'not-ready' | 'unwritten' | 'implementing' | 'verifying';
13
+ readonly label: string;
14
+ };
15
+ /**
16
+ * One prompt section as returned from `GET /api/prompts`.
17
+ */
18
+ export type CoderServerPromptSectionResponse = {
19
+ readonly index: number;
20
+ readonly status: PromptStatus;
21
+ readonly column: CoderServerBoardColumn;
22
+ readonly priority: number;
23
+ readonly summary: string;
24
+ readonly content: string;
25
+ readonly label: string;
26
+ readonly tags: readonly CoderServerPromptTag[];
27
+ };
28
+ /**
29
+ * One prompt file as returned from `GET /api/prompts`.
30
+ */
31
+ export type CoderServerPromptFileResponse = {
32
+ readonly filePath: string;
33
+ readonly fileName: string;
34
+ readonly relativeFilePath: string;
35
+ readonly isFinished: boolean;
36
+ readonly sections: readonly CoderServerPromptSectionResponse[];
37
+ };
38
+ /**
39
+ * Input for converting parsed prompt files into the browser API shape.
40
+ */
41
+ export type BuildCoderServerPromptFileResponsesOptions = {
42
+ readonly promptFiles: readonly PromptFile[];
43
+ readonly finishedPromptFiles: readonly PromptFile[];
44
+ readonly minimumPriority: number;
45
+ readonly uiState?: CoderRunUiState;
46
+ };
47
+ /**
48
+ * Converts parsed prompt files into a web-board response with derived columns and tags.
49
+ */
50
+ export declare function buildCoderServerPromptFileResponses(options: BuildCoderServerPromptFileResponsesOptions): CoderServerPromptFileResponse[];
@@ -0,0 +1,23 @@
1
+ import type { CoderRunConfig, CoderRunPhase, CoderRunProgressSnapshot, CoderRunUiState } from '../ui/CoderRunUiState';
2
+ import type { AgentRunStatusTableRow } from '../ui/buildCoderRunUiFrame';
3
+ /**
4
+ * Snapshot of the active coder runner exposed to the browser UI.
5
+ */
6
+ export type CoderServerRunState = {
7
+ readonly config: CoderRunConfig;
8
+ readonly phase: CoderRunPhase;
9
+ readonly currentPromptLabel: string;
10
+ readonly currentAttempt: number;
11
+ readonly maxAttempts: number;
12
+ readonly statusMessage: string;
13
+ readonly detailLines: readonly string[];
14
+ readonly agentStatusLines: readonly string[];
15
+ readonly agentStatusTableRows: readonly AgentRunStatusTableRow[];
16
+ readonly agentOutputLines: readonly string[];
17
+ readonly errors: readonly string[];
18
+ readonly progress: CoderRunProgressSnapshot;
19
+ };
20
+ /**
21
+ * Builds a plain JSON-safe snapshot from the shared terminal UI state.
22
+ */
23
+ export declare function buildCoderServerRunState(uiState: CoderRunUiState): CoderServerRunState;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  * @private internal constant of `ptbk coder server`
8
8
  */
9
- export declare const CODER_SERVER_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Ptbk Coder Server</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: #f4f5f7;\n color: #172b4d;\n min-height: 100vh;\n }\n\n header {\n background: #0052cc;\n color: white;\n padding: 12px 20px;\n display: flex;\n align-items: center;\n gap: 12px;\n position: sticky;\n top: 0;\n z-index: 10;\n box-shadow: 0 2px 8px rgba(0,0,0,0.2);\n }\n header h1 { font-size: 17px; font-weight: 700; flex-shrink: 0; }\n\n .status-badge {\n padding: 3px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.5px;\n text-transform: uppercase;\n flex-shrink: 0;\n }\n .status-RUNNING { background: #00875a; color: white; }\n .status-PAUSING { background: #ff8b00; color: white; }\n .status-PAUSED { background: #bf2600; color: white; }\n\n #pause-label {\n font-size: 12px;\n color: rgba(255,255,255,0.75);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .btn {\n padding: 6px 14px;\n border: none;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 600;\n transition: opacity 0.15s;\n flex-shrink: 0;\n }\n .btn:hover { opacity: 0.85; }\n .btn-pause { background: #ffc400; color: #172b4d; }\n .btn-resume { background: #00875a; color: white; }\n\n .board {\n display: flex;\n gap: 14px;\n padding: 16px;\n overflow-x: auto;\n min-height: calc(100vh - 52px);\n align-items: flex-start;\n }\n\n .column {\n background: #ebecf0;\n border-radius: 8px;\n padding: 10px;\n min-width: 250px;\n width: 270px;\n flex-shrink: 0;\n }\n\n .column-header {\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.6px;\n color: #5e6c84;\n margin-bottom: 10px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .column-count {\n background: #dfe1e6;\n border-radius: 10px;\n padding: 1px 7px;\n font-size: 11px;\n color: #5e6c84;\n }\n\n .column-cards { min-height: 40px; }\n\n .card {\n background: white;\n border-radius: 6px;\n padding: 10px 12px;\n margin-bottom: 8px;\n box-shadow: 0 1px 3px rgba(0,0,0,0.08);\n cursor: pointer;\n transition: box-shadow 0.15s, transform 0.1s;\n border-left: 3px solid transparent;\n }\n .card:hover {\n box-shadow: 0 4px 10px rgba(0,0,0,0.14);\n transform: translateY(-1px);\n }\n .card-todo { border-left-color: #0052cc; }\n .card-not-ready { border-left-color: #8993a4; }\n .card-done { border-left-color: #00875a; }\n .card-failed { border-left-color: #bf2600; }\n\n .card-file {\n font-size: 10px;\n color: #8993a4;\n margin-bottom: 5px;\n font-weight: 500;\n }\n\n .card-summary {\n font-size: 13px;\n line-height: 1.5;\n color: #172b4d;\n word-break: break-word;\n white-space: pre-wrap;\n max-height: 78px;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n }\n\n .card-priority {\n margin-top: 6px;\n color: #ff8b00;\n font-size: 11px;\n font-weight: 700;\n }\n\n .card-edit-hint {\n font-size: 10px;\n color: #c1c7d0;\n margin-top: 6px;\n display: none;\n }\n .card:hover .card-edit-hint { display: block; }\n\n .empty-column {\n color: #b3bac5;\n font-size: 12px;\n padding: 10px 4px;\n text-align: center;\n }\n\n .modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(9,30,66,0.54);\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 60px 16px 16px;\n z-index: 100;\n animation: fadeIn 0.1s ease;\n }\n .modal-overlay.hidden { display: none; }\n\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n\n .modal {\n background: white;\n border-radius: 8px;\n width: 100%;\n max-width: 620px;\n padding: 20px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.25);\n animation: slideIn 0.15s ease;\n }\n @keyframes slideIn { from { transform: translateY(-8px); opacity: 0; } to { transform: none; opacity: 1; } }\n\n .modal-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 14px;\n gap: 12px;\n }\n\n .modal-meta { flex: 1; min-width: 0; }\n .modal-file { font-size: 11px; color: #8993a4; margin-bottom: 4px; }\n .modal-section-label { font-size: 13px; font-weight: 600; color: #172b4d; }\n\n .modal-status {\n font-size: 11px;\n font-weight: 700;\n padding: 2px 8px;\n border-radius: 10px;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n flex-shrink: 0;\n }\n .status-todo { background: #deebff; color: #0052cc; }\n .status-not-ready { background: #f4f5f7; color: #5e6c84; }\n .status-done { background: #e3fcef; color: #006644; }\n .status-failed { background: #ffebe6; color: #bf2600; }\n\n .modal-close {\n background: none;\n border: none;\n color: #8993a4;\n cursor: pointer;\n font-size: 18px;\n padding: 0 4px;\n line-height: 1;\n flex-shrink: 0;\n }\n .modal-close:hover { color: #172b4d; }\n\n textarea {\n width: 100%;\n min-height: 220px;\n font-family: 'SFMono-Regular', 'Consolas', 'Courier New', monospace;\n font-size: 13px;\n border: 2px solid #dfe1e6;\n border-radius: 4px;\n padding: 10px 12px;\n resize: vertical;\n line-height: 1.65;\n color: #172b4d;\n transition: border-color 0.15s;\n }\n textarea:focus {\n outline: none;\n border-color: #0052cc;\n box-shadow: 0 0 0 3px rgba(0,82,204,0.12);\n }\n\n .modal-hint {\n font-size: 11px;\n color: #8993a4;\n margin-top: 6px;\n }\n\n .modal-actions {\n display: flex;\n gap: 8px;\n margin-top: 14px;\n justify-content: flex-end;\n }\n\n .btn-save { background: #0052cc; color: white; }\n .btn-cancel { background: #f4f5f7; color: #172b4d; }\n .btn-cancel:hover { background: #ebecf0; opacity: 1; }\n\n .error-banner {\n background: #ffebe6;\n border-bottom: 2px solid #bf2600;\n color: #bf2600;\n padding: 8px 20px;\n font-size: 13px;\n font-weight: 500;\n }\n .error-banner.hidden { display: none; }\n </style>\n</head>\n<body>\n\n <div id=\"error-banner\" class=\"error-banner hidden\"></div>\n\n <header>\n <h1>&#128295; Ptbk Coder Server</h1>\n <span id=\"status-badge\" class=\"status-badge status-RUNNING\">RUNNING</span>\n <span id=\"pause-label\"></span>\n <button id=\"toggle-btn\" class=\"btn btn-pause\">&#9646;&#9646; Pause</button>\n </header>\n\n <div class=\"board\">\n <div class=\"column\">\n <div class=\"column-header\">\n To Do\n <span class=\"column-count\" id=\"count-todo\">0</span>\n </div>\n <div class=\"column-cards\" id=\"cards-todo\">\n <div class=\"empty-column\">Loading&hellip;</div>\n </div>\n </div>\n\n <div class=\"column\">\n <div class=\"column-header\">\n Not Ready\n <span class=\"column-count\" id=\"count-not-ready\">0</span>\n </div>\n <div class=\"column-cards\" id=\"cards-not-ready\"></div>\n </div>\n\n <div class=\"column\">\n <div class=\"column-header\">\n Done\n <span class=\"column-count\" id=\"count-done\">0</span>\n </div>\n <div class=\"column-cards\" id=\"cards-done\"></div>\n </div>\n\n <div class=\"column\">\n <div class=\"column-header\">\n Failed\n <span class=\"column-count\" id=\"count-failed\">0</span>\n </div>\n <div class=\"column-cards\" id=\"cards-failed\"></div>\n </div>\n </div>\n\n <div class=\"modal-overlay hidden\" id=\"modal-overlay\">\n <div class=\"modal\">\n <div class=\"modal-header\">\n <div class=\"modal-meta\">\n <div class=\"modal-file\" id=\"modal-file\"></div>\n <div class=\"modal-section-label\" id=\"modal-section-label\"></div>\n </div>\n <span class=\"modal-status\" id=\"modal-status-badge\"></span>\n <button class=\"modal-close\" onclick=\"closeModal()\" title=\"Close (Esc)\">&#x2715;</button>\n </div>\n\n <textarea id=\"modal-content\" placeholder=\"Prompt content&hellip;\"></textarea>\n <div class=\"modal-hint\">Tip: press Ctrl+Enter to save, Esc to cancel.</div>\n\n <div class=\"modal-actions\">\n <button class=\"btn btn-cancel\" onclick=\"closeModal()\">Cancel</button>\n <button class=\"btn btn-save\" onclick=\"saveModal()\">Save</button>\n </div>\n </div>\n </div>\n\n <script>\n 'use strict';\n\n let modalState = null;\n let lastPauseState = 'RUNNING';\n\n function showError(msg) {\n const banner = document.getElementById('error-banner');\n banner.textContent = '\\u26a0 ' + msg;\n banner.classList.remove('hidden');\n clearTimeout(banner._timer);\n banner._timer = setTimeout(() => banner.classList.add('hidden'), 6000);\n }\n\n function escapeHtml(str) {\n const d = document.createElement('div');\n d.textContent = String(str);\n return d.innerHTML;\n }\n\n async function fetchStatus() {\n try {\n const res = await fetch('/api/status');\n if (!res.ok) { showError('Status API error: ' + res.status); return; }\n const data = await res.json();\n\n lastPauseState = data.pauseState;\n\n const badge = document.getElementById('status-badge');\n badge.textContent = data.pauseState;\n badge.className = 'status-badge status-' + data.pauseState;\n\n const btn = document.getElementById('toggle-btn');\n const label = document.getElementById('pause-label');\n\n if (data.pauseState === 'RUNNING') {\n btn.textContent = '\\u23f8 Pause';\n btn.className = 'btn btn-pause';\n label.textContent = '';\n } else if (data.pauseState === 'PAUSING') {\n btn.textContent = '\\u23f5 Resume';\n btn.className = 'btn btn-resume';\n label.textContent = 'Pausing before: ' + (data.pauseTargetLabel || '\\u2026');\n } else {\n btn.textContent = '\\u23f5 Resume';\n btn.className = 'btn btn-resume';\n label.textContent = 'Paused before: ' + (data.pauseTargetLabel || '\\u2026');\n }\n } catch (e) {\n showError('Could not reach coder server: ' + e.message);\n }\n }\n\n async function fetchPrompts() {\n try {\n const res = await fetch('/api/prompts');\n if (!res.ok) { showError('Prompts API error: ' + res.status); return; }\n renderBoard(await res.json());\n } catch (e) {\n showError('Could not load prompts: ' + e.message);\n }\n }\n\n function renderBoard(promptFiles) {\n const columns = { 'todo': [], 'not-ready': [], 'done': [], 'failed': [] };\n\n for (const file of promptFiles) {\n for (const section of file.sections) {\n const col = columns[section.status];\n if (col) col.push({ file, section });\n }\n }\n\n for (const [status, cards] of Object.entries(columns)) {\n const container = document.getElementById('cards-' + status);\n const countEl = document.getElementById('count-' + status);\n if (!container) continue;\n\n countEl.textContent = cards.length;\n container.innerHTML = '';\n\n if (cards.length === 0) {\n container.innerHTML = '<div class=\"empty-column\">Empty</div>';\n continue;\n }\n\n for (const { file, section } of cards) {\n const card = document.createElement('div');\n card.className = 'card card-' + section.status;\n card.innerHTML =\n '<div class=\"card-file\">' + escapeHtml(file.fileName) + ' &bull; #' + (section.index + 1) + '</div>' +\n '<div class=\"card-summary\">' + escapeHtml(section.summary) + '</div>' +\n (section.priority > 0\n ? '<div class=\"card-priority\">' + '!'.repeat(section.priority) + ' priority ' + section.priority + '</div>'\n : '') +\n '<div class=\"card-edit-hint\">Click to edit</div>';\n card.onclick = () => openModal(file, section);\n container.appendChild(card);\n }\n }\n }\n\n function openModal(file, section) {\n modalState = { filePath: file.filePath, sectionIndex: section.index };\n\n document.getElementById('modal-file').textContent = file.fileName;\n document.getElementById('modal-section-label').textContent = 'Section ' + (section.index + 1);\n\n const badge = document.getElementById('modal-status-badge');\n badge.textContent = section.status.replace('-', '\\u2011');\n badge.className = 'modal-status status-' + section.status;\n\n document.getElementById('modal-content').value = section.content;\n document.getElementById('modal-overlay').classList.remove('hidden');\n setTimeout(() => document.getElementById('modal-content').focus(), 50);\n }\n\n function closeModal() {\n document.getElementById('modal-overlay').classList.add('hidden');\n modalState = null;\n }\n\n async function saveModal() {\n if (!modalState) return;\n\n const content = document.getElementById('modal-content').value;\n const saveBtn = document.querySelector('.btn-save');\n saveBtn.disabled = true;\n saveBtn.textContent = 'Saving\\u2026';\n\n try {\n const res = await fetch('/api/prompts/update', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n filePath: modalState.filePath,\n sectionIndex: modalState.sectionIndex,\n content,\n }),\n });\n if (!res.ok) throw new Error('HTTP ' + res.status);\n closeModal();\n fetchPrompts();\n } catch (e) {\n showError('Save failed: ' + e.message);\n } finally {\n saveBtn.disabled = false;\n saveBtn.textContent = 'Save';\n }\n }\n\n document.getElementById('toggle-btn').onclick = async () => {\n try {\n const endpoint = lastPauseState === 'RUNNING' ? '/api/pause' : '/api/resume';\n await fetch(endpoint, { method: 'POST' });\n await fetchStatus();\n } catch (e) {\n showError('Toggle failed: ' + e.message);\n }\n };\n\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') { closeModal(); return; }\n if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') { saveModal(); return; }\n });\n\n document.getElementById('modal-overlay').addEventListener('click', (e) => {\n if (e.target === document.getElementById('modal-overlay')) closeModal();\n });\n\n fetchStatus();\n fetchPrompts();\n setInterval(fetchStatus, 2000);\n setInterval(fetchPrompts, 5000);\n </script>\n</body>\n</html>";
9
+ export declare const CODER_SERVER_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Ptbk Coder Server</title>\n <style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n background: #f6f7f9;\n color: #1f2933;\n min-height: 100vh;\n }\n\n header {\n background: #22313f;\n color: white;\n padding: 12px 18px;\n display: flex;\n align-items: center;\n gap: 12px;\n position: sticky;\n top: 0;\n z-index: 10;\n box-shadow: 0 2px 10px rgba(15,23,42,0.22);\n }\n header h1 { font-size: 17px; font-weight: 700; flex-shrink: 0; letter-spacing: 0; }\n\n .status-badge {\n padding: 3px 10px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n flex-shrink: 0;\n }\n .status-RUNNING { background: #0b875b; color: white; }\n .status-PAUSING { background: #d97904; color: white; }\n .status-PAUSED { background: #b42318; color: white; }\n\n #pause-label {\n font-size: 12px;\n color: rgba(255,255,255,0.75);\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .btn {\n padding: 6px 12px;\n border: 0;\n border-radius: 4px;\n cursor: pointer;\n font-size: 13px;\n font-weight: 700;\n transition: background 0.15s, opacity 0.15s;\n flex-shrink: 0;\n }\n .btn:disabled { opacity: 0.55; cursor: default; }\n .btn-pause { background: #ffd166; color: #1f2933; }\n .btn-resume { background: #0b875b; color: white; }\n .btn-save { background: #2563eb; color: white; }\n .btn-cancel { background: #edf0f4; color: #1f2933; }\n\n .run-strip {\n background: white;\n border-bottom: 1px solid #d8dee8;\n padding: 12px 18px;\n display: grid;\n grid-template-columns: minmax(220px, 1.2fr) minmax(240px, 1fr) minmax(260px, 1.4fr);\n gap: 14px;\n align-items: center;\n }\n .run-title {\n font-size: 14px;\n font-weight: 700;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .run-subtitle,\n .run-current,\n .run-output {\n color: #64748b;\n font-size: 12px;\n line-height: 1.45;\n overflow: hidden;\n }\n .run-current,\n .run-output {\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n }\n .progress-shell {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 8px;\n align-items: center;\n }\n .progress-track {\n height: 10px;\n background: #e4e9f0;\n border-radius: 999px;\n overflow: hidden;\n }\n .progress-fill {\n display: block;\n height: 100%;\n width: 0;\n background: linear-gradient(90deg, #0b875b, #2563eb);\n transition: width 0.2s;\n }\n .progress-label {\n color: #475569;\n font-size: 12px;\n font-weight: 700;\n min-width: 72px;\n text-align: right;\n }\n\n .board {\n display: flex;\n gap: 14px;\n padding: 16px;\n overflow-x: auto;\n min-height: calc(100vh - 119px);\n align-items: flex-start;\n }\n\n .column {\n background: #e9edf3;\n border-top: 4px solid #94a3b8;\n border-radius: 6px;\n padding: 10px;\n min-width: 250px;\n width: 270px;\n flex-shrink: 0;\n }\n .column-backlog { border-top-color: #64748b; }\n .column-low-priority { border-top-color: #d97904; }\n .column-todo { border-top-color: #2563eb; }\n .column-in-progress { border-top-color: #7c3aed; }\n .column-done { border-top-color: #0b875b; }\n .column-errors { border-top-color: #b42318; }\n .column-finished { border-top-color: #0891b2; }\n\n .column-header {\n font-size: 12px;\n font-weight: 800;\n text-transform: uppercase;\n color: #475569;\n margin-bottom: 10px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n }\n .column-count {\n background: rgba(255,255,255,0.72);\n border-radius: 999px;\n padding: 2px 8px;\n font-size: 11px;\n color: #475569;\n }\n .column-cards { min-height: 40px; }\n\n .card {\n background: white;\n border-radius: 6px;\n padding: 10px 12px;\n margin-bottom: 8px;\n box-shadow: 0 1px 3px rgba(15,23,42,0.12);\n cursor: pointer;\n border-left: 3px solid #94a3b8;\n }\n .card:hover { box-shadow: 0 4px 12px rgba(15,23,42,0.16); }\n .card-backlog { border-left-color: #64748b; }\n .card-low-priority { border-left-color: #d97904; }\n .card-todo { border-left-color: #2563eb; }\n .card-in-progress { border-left-color: #7c3aed; }\n .card-done { border-left-color: #0b875b; }\n .card-errors { border-left-color: #b42318; }\n .card-finished { border-left-color: #0891b2; }\n\n .card-file {\n font-size: 10px;\n color: #7b8794;\n margin-bottom: 6px;\n font-weight: 600;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .card-summary {\n font-size: 13px;\n line-height: 1.45;\n color: #1f2933;\n word-break: break-word;\n white-space: pre-wrap;\n max-height: 76px;\n overflow: hidden;\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n }\n .card-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 5px;\n margin-top: 8px;\n }\n .card-tag {\n border-radius: 999px;\n padding: 2px 7px;\n font-size: 10px;\n font-weight: 800;\n line-height: 1.35;\n }\n .tag-not-ready { background: #e2e8f0; color: #475569; }\n .tag-unwritten { background: #fff4cc; color: #8a5a00; }\n .tag-implementing { background: #ede9fe; color: #5b21b6; }\n .tag-verifying { background: #fae8ff; color: #86198f; }\n .tag-priority { background: #ffedd5; color: #9a3412; }\n\n .empty-column {\n color: #94a3b8;\n font-size: 12px;\n padding: 10px 4px;\n text-align: center;\n }\n\n .modal-overlay {\n position: fixed;\n inset: 0;\n background: rgba(15,23,42,0.58);\n display: flex;\n align-items: flex-start;\n justify-content: center;\n padding: 56px 16px 16px;\n z-index: 100;\n }\n .modal-overlay.hidden { display: none; }\n\n .modal {\n background: white;\n border-radius: 8px;\n width: 100%;\n max-width: 720px;\n padding: 18px;\n box-shadow: 0 14px 40px rgba(15,23,42,0.28);\n }\n .modal-header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: 14px;\n gap: 12px;\n }\n .modal-meta { flex: 1; min-width: 0; }\n .modal-file {\n font-size: 11px;\n color: #7b8794;\n margin-bottom: 4px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n .modal-section-label { font-size: 14px; font-weight: 700; color: #1f2933; }\n .modal-status {\n font-size: 11px;\n font-weight: 800;\n padding: 3px 8px;\n border-radius: 999px;\n text-transform: uppercase;\n flex-shrink: 0;\n }\n .status-backlog { background: #e2e8f0; color: #475569; }\n .status-low-priority { background: #ffedd5; color: #9a3412; }\n .status-todo { background: #dbeafe; color: #1d4ed8; }\n .status-in-progress { background: #ede9fe; color: #5b21b6; }\n .status-done { background: #dcfce7; color: #166534; }\n .status-errors { background: #fee2e2; color: #991b1b; }\n .status-finished { background: #cffafe; color: #155e75; }\n .modal-close {\n background: transparent;\n border: 0;\n color: #64748b;\n cursor: pointer;\n font-size: 20px;\n padding: 0 4px;\n line-height: 1;\n }\n .modal-close:hover { color: #1f2933; }\n\n textarea {\n width: 100%;\n min-height: 300px;\n font-family: \"SFMono-Regular\", Consolas, \"Courier New\", monospace;\n font-size: 13px;\n border: 2px solid #d8dee8;\n border-radius: 4px;\n padding: 10px 12px;\n resize: vertical;\n line-height: 1.6;\n color: #1f2933;\n }\n textarea:focus {\n outline: none;\n border-color: #2563eb;\n box-shadow: 0 0 0 3px rgba(37,99,235,0.12);\n }\n .modal-actions {\n display: flex;\n gap: 8px;\n margin-top: 14px;\n justify-content: flex-end;\n }\n\n .error-banner {\n background: #fee2e2;\n border-bottom: 2px solid #b42318;\n color: #991b1b;\n padding: 8px 18px;\n font-size: 13px;\n font-weight: 700;\n }\n .error-banner.hidden { display: none; }\n\n @media (max-width: 860px) {\n header { flex-wrap: wrap; }\n #pause-label { order: 4; flex-basis: 100%; }\n .run-strip { grid-template-columns: 1fr; }\n .board { min-height: calc(100vh - 212px); }\n }\n </style>\n</head>\n<body>\n <div id=\"error-banner\" class=\"error-banner hidden\"></div>\n\n <header>\n <h1>Ptbk Coder Server</h1>\n <span id=\"status-badge\" class=\"status-badge status-RUNNING\">RUNNING</span>\n <span id=\"pause-label\"></span>\n <button id=\"toggle-btn\" class=\"btn btn-pause\">Pause</button>\n </header>\n\n <section class=\"run-strip\">\n <div>\n <div class=\"run-title\" id=\"run-title\">Initializing...</div>\n <div class=\"run-subtitle\" id=\"run-subtitle\">Loading runner state</div>\n </div>\n <div class=\"progress-shell\">\n <div class=\"progress-track\"><span class=\"progress-fill\" id=\"progress-fill\"></span></div>\n <div class=\"progress-label\" id=\"progress-label\">0%</div>\n </div>\n <div>\n <div class=\"run-current\" id=\"run-current\">No active prompt</div>\n <div class=\"run-output\" id=\"run-output\"></div>\n </div>\n </section>\n\n <div class=\"board\" id=\"board\"></div>\n\n <div class=\"modal-overlay hidden\" id=\"modal-overlay\">\n <div class=\"modal\">\n <div class=\"modal-header\">\n <div class=\"modal-meta\">\n <div class=\"modal-file\" id=\"modal-file\"></div>\n <div class=\"modal-section-label\" id=\"modal-section-label\"></div>\n </div>\n <span class=\"modal-status\" id=\"modal-status-badge\"></span>\n <button class=\"modal-close\" id=\"modal-close\" title=\"Close\">&times;</button>\n </div>\n\n <textarea id=\"modal-content\" placeholder=\"Prompt content\"></textarea>\n\n <div class=\"modal-actions\">\n <button class=\"btn btn-cancel\" id=\"cancel-button\">Cancel</button>\n <button class=\"btn btn-save\" id=\"save-button\">Save</button>\n </div>\n </div>\n </div>\n\n <script>\n \"use strict\";\n\n const BOARD_COLUMNS = [\n { id: \"backlog\", title: \"Backlog\" },\n { id: \"low-priority\", title: \"Low priority\" },\n { id: \"todo\", title: \"To do\" },\n { id: \"in-progress\", title: \"In progress\" },\n { id: \"done\", title: \"Done\" },\n { id: \"errors\", title: \"Errors\" },\n { id: \"finished\", title: \"Finished\" },\n ];\n\n let modalState = null;\n let lastPauseState = \"RUNNING\";\n\n function getColumnTitle(columnId) {\n const column = BOARD_COLUMNS.find((columnCandidate) => columnCandidate.id === columnId);\n return column ? column.title : columnId;\n }\n\n function showError(message) {\n const banner = document.getElementById(\"error-banner\");\n banner.textContent = message;\n banner.classList.remove(\"hidden\");\n clearTimeout(banner.timer);\n banner.timer = setTimeout(() => banner.classList.add(\"hidden\"), 6000);\n }\n\n function escapeHtml(value) {\n const element = document.createElement(\"div\");\n element.textContent = String(value);\n return element.innerHTML;\n }\n\n function renderBoardSkeleton() {\n const board = document.getElementById(\"board\");\n board.innerHTML = \"\";\n\n for (const column of BOARD_COLUMNS) {\n const columnElement = document.createElement(\"section\");\n columnElement.className = \"column column-\" + column.id;\n columnElement.innerHTML =\n '<div class=\"column-header\">' +\n '<span>' + escapeHtml(column.title) + '</span>' +\n '<span class=\"column-count\" id=\"count-' + column.id + '\">0</span>' +\n '</div>' +\n '<div class=\"column-cards\" id=\"cards-' + column.id + '\">' +\n '<div class=\"empty-column\">Loading</div>' +\n '</div>';\n board.appendChild(columnElement);\n }\n }\n\n async function fetchStatus() {\n try {\n const response = await fetch(\"/api/status\");\n if (!response.ok) {\n showError(\"Status API error: \" + response.status);\n return;\n }\n\n const status = await response.json();\n renderPauseState(status);\n renderRunState(status.runState);\n } catch (error) {\n showError(\"Could not reach coder server: \" + error.message);\n }\n }\n\n function renderPauseState(status) {\n lastPauseState = status.pauseState;\n\n const badge = document.getElementById(\"status-badge\");\n badge.textContent = status.pauseState;\n badge.className = \"status-badge status-\" + status.pauseState;\n\n const toggleButton = document.getElementById(\"toggle-btn\");\n const pauseLabel = document.getElementById(\"pause-label\");\n\n if (status.pauseState === \"RUNNING\") {\n toggleButton.textContent = \"Pause\";\n toggleButton.className = \"btn btn-pause\";\n pauseLabel.textContent = \"\";\n return;\n }\n\n toggleButton.textContent = \"Resume\";\n toggleButton.className = \"btn btn-resume\";\n pauseLabel.textContent =\n (status.pauseState === \"PAUSING\" ? \"Pausing before: \" : \"Paused before: \") +\n (status.pauseTargetLabel || \"next checkpoint\");\n }\n\n function renderRunState(runState) {\n if (!runState) {\n document.getElementById(\"run-title\").textContent = \"Waiting for runner state\";\n document.getElementById(\"run-subtitle\").textContent = \"\";\n return;\n }\n\n const progress = runState.progress || {};\n const percentage = Number(progress.percentage || 0);\n const runnerParts = [runState.config.agentName, runState.config.modelName, runState.config.thinkingLevel]\n .filter(Boolean);\n\n document.getElementById(\"run-title\").textContent = runState.statusMessage || runState.phase;\n document.getElementById(\"run-subtitle\").textContent = runnerParts.join(\" / \");\n document.getElementById(\"progress-fill\").style.width = Math.max(0, Math.min(100, percentage)) + \"%\";\n document.getElementById(\"progress-label\").textContent =\n percentage + \"% \" + (progress.sessionDone || 0) + \"/\" + (progress.sessionTotal || 0);\n document.getElementById(\"run-current\").textContent = runState.currentPromptLabel\n ? runState.currentPromptLabel + \" - attempt \" + runState.currentAttempt + \"/\" + runState.maxAttempts\n : \"No active prompt\";\n\n renderRunOutput(runState);\n }\n\n function renderRunOutput(runState) {\n const statusLines = (runState.agentStatusTableRows || []).map((row) =>\n row.status + \" - \" + row.agentName + (row.url ? \" - \" + row.url : \"\")\n );\n const outputLines = [\n ...(runState.agentStatusLines || []),\n ...statusLines,\n ...(runState.agentOutputLines || []),\n ...(runState.errors || []).map((errorLine) => \"Error: \" + errorLine),\n ].slice(-3);\n\n document.getElementById(\"run-output\").textContent = outputLines.join(\"\\n\");\n }\n\n async function fetchPrompts() {\n try {\n const response = await fetch(\"/api/prompts\");\n if (!response.ok) {\n showError(\"Prompts API error: \" + response.status);\n return;\n }\n\n renderBoard(await response.json());\n } catch (error) {\n showError(\"Could not load prompts: \" + error.message);\n }\n }\n\n function renderBoard(promptFiles) {\n const columns = Object.fromEntries(BOARD_COLUMNS.map((column) => [column.id, []]));\n\n for (const file of promptFiles) {\n for (const section of file.sections) {\n if (columns[section.column]) {\n columns[section.column].push({ file, section });\n }\n }\n }\n\n for (const column of BOARD_COLUMNS) {\n renderColumn(column.id, columns[column.id]);\n }\n }\n\n function renderColumn(columnId, cards) {\n const container = document.getElementById(\"cards-\" + columnId);\n const countElement = document.getElementById(\"count-\" + columnId);\n\n countElement.textContent = cards.length;\n container.innerHTML = \"\";\n\n if (cards.length === 0) {\n container.innerHTML = '<div class=\"empty-column\">Empty</div>';\n return;\n }\n\n for (const cardData of cards) {\n container.appendChild(createPromptCard(cardData.file, cardData.section));\n }\n }\n\n function createPromptCard(file, section) {\n const card = document.createElement(\"article\");\n card.className = \"card card-\" + section.column;\n card.innerHTML =\n '<div class=\"card-file\">' + escapeHtml(file.relativeFilePath || file.fileName) + \" #\" + (section.index + 1) + '</div>' +\n '<div class=\"card-summary\">' + escapeHtml(section.summary) + '</div>' +\n renderTags(section);\n card.onclick = () => openModal(file, section);\n return card;\n }\n\n function renderTags(section) {\n const tags = [...(section.tags || [])];\n if (section.priority > 0) {\n tags.push({ id: \"priority\", label: \"P\" + section.priority });\n }\n\n if (tags.length === 0) {\n return \"\";\n }\n\n return '<div class=\"card-tags\">' + tags.map((tag) =>\n '<span class=\"card-tag tag-' + escapeHtml(tag.id) + '\">' + escapeHtml(tag.label) + '</span>'\n ).join(\"\") + '</div>';\n }\n\n function openModal(file, section) {\n modalState = { filePath: file.filePath, sectionIndex: section.index };\n\n document.getElementById(\"modal-file\").textContent = file.relativeFilePath || file.fileName;\n document.getElementById(\"modal-section-label\").textContent = \"Section \" + (section.index + 1);\n\n const statusBadge = document.getElementById(\"modal-status-badge\");\n statusBadge.textContent = getColumnTitle(section.column);\n statusBadge.className = \"modal-status status-\" + section.column;\n\n document.getElementById(\"modal-content\").value = section.content;\n document.getElementById(\"modal-overlay\").classList.remove(\"hidden\");\n setTimeout(() => document.getElementById(\"modal-content\").focus(), 50);\n }\n\n function closeModal() {\n document.getElementById(\"modal-overlay\").classList.add(\"hidden\");\n modalState = null;\n }\n\n async function saveModal() {\n if (!modalState) {\n return;\n }\n\n const content = document.getElementById(\"modal-content\").value;\n const saveButton = document.getElementById(\"save-button\");\n saveButton.disabled = true;\n saveButton.textContent = \"Saving...\";\n\n try {\n const response = await fetch(\"/api/prompts/update\", {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n filePath: modalState.filePath,\n sectionIndex: modalState.sectionIndex,\n content,\n }),\n });\n\n if (!response.ok) {\n throw new Error(\"HTTP \" + response.status);\n }\n\n closeModal();\n await fetchPrompts();\n } catch (error) {\n showError(\"Save failed: \" + error.message);\n } finally {\n saveButton.disabled = false;\n saveButton.textContent = \"Save\";\n }\n }\n\n document.getElementById(\"toggle-btn\").onclick = async () => {\n try {\n const endpoint = lastPauseState === \"RUNNING\" ? \"/api/pause\" : \"/api/resume\";\n await fetch(endpoint, { method: \"POST\" });\n await fetchStatus();\n } catch (error) {\n showError(\"Toggle failed: \" + error.message);\n }\n };\n\n document.getElementById(\"modal-close\").onclick = closeModal;\n document.getElementById(\"cancel-button\").onclick = closeModal;\n document.getElementById(\"save-button\").onclick = saveModal;\n\n document.addEventListener(\"keydown\", (event) => {\n if (event.key === \"Escape\") {\n closeModal();\n return;\n }\n if ((event.ctrlKey || event.metaKey) && event.key === \"Enter\") {\n saveModal();\n }\n });\n\n document.getElementById(\"modal-overlay\").addEventListener(\"click\", (event) => {\n if (event.target === document.getElementById(\"modal-overlay\")) {\n closeModal();\n }\n });\n\n renderBoardSkeleton();\n fetchStatus();\n fetchPrompts();\n setInterval(fetchStatus, 2000);\n setInterval(fetchPrompts, 5000);\n </script>\n</body>\n</html>\n";
@@ -1,4 +1,5 @@
1
1
  import type { number_port } from '../../../src/types/number_positive';
2
+ import type { CoderRunUiState } from '../ui/CoderRunUiState';
2
3
  /**
3
4
  * Handle returned by the running coder HTTP server.
4
5
  *
@@ -7,6 +8,17 @@ import type { number_port } from '../../../src/types/number_positive';
7
8
  export type CoderHttpServerHandle = {
8
9
  close: () => void;
9
10
  };
11
+ /**
12
+ * Options for the coder HTTP server.
13
+ *
14
+ * @private internal type of `ptbk coder server`
15
+ */
16
+ export type StartCoderHttpServerOptions = {
17
+ readonly port: number_port;
18
+ readonly minimumPriority: number;
19
+ readonly serverUrl: string;
20
+ readonly uiState?: CoderRunUiState;
21
+ };
10
22
  /**
11
23
  * Starts the lightweight HTTP server that serves the coder kanban UI and REST API.
12
24
  *
@@ -20,4 +32,4 @@ export type CoderHttpServerHandle = {
20
32
  *
21
33
  * @private internal utility of `ptbk coder server`
22
34
  */
23
- export declare function startCoderHttpServer(port: number_port): CoderHttpServerHandle;
35
+ export declare function startCoderHttpServer(options: StartCoderHttpServerOptions): CoderHttpServerHandle;
@@ -6,4 +6,4 @@
6
6
  *
7
7
  * @private internal utility of `ptbk coder server`
8
8
  */
9
- export declare function updatePromptSection(filePath: string, sectionIndex: number, newContent: string): Promise<void>;
9
+ export declare function updatePromptSection(filePath: string, sectionIndex: number, newContent: string): Promise<boolean>;
@@ -21,6 +21,7 @@ export type CoderRunConfig = {
21
21
  readonly modelName?: string;
22
22
  readonly thinkingLevel?: string;
23
23
  readonly context?: string;
24
+ readonly serverUrl?: string;
24
25
  readonly priority: number;
25
26
  readonly testCommand?: string;
26
27
  };
@@ -39,6 +39,10 @@ export declare function buildLabeledSessionLine(label: string, value: string, bo
39
39
  * Builds session rows with clickable links to active temporary runner shell scripts.
40
40
  */
41
41
  export declare function buildScriptPathSessionRows(scriptPaths: readonly string[], bodyWidth: number): readonly SessionRow[];
42
+ /**
43
+ * Builds one OSC 8 terminal hyperlink to an HTTP URL.
44
+ */
45
+ export declare function buildTerminalUrlLink(url: string, availableWidth: number): string;
42
46
  /**
43
47
  * Builds the colored phase badge shown in the session box.
44
48
  */
@@ -33,4 +33,5 @@ export type CoderRunUiHandle = {
33
33
  */
34
34
  export declare function renderCoderRunUi(startTime: moment.Moment, options?: {
35
35
  readonly buildFrameLines?: (options: BuildCoderRunUiFrameOptions) => string[];
36
+ readonly state?: CoderRunUiState;
36
37
  }): CoderRunUiHandle;
@@ -66,6 +66,7 @@ import type { ChatProgressCard } from '../book-components/Chat/types/ChatMessage
66
66
  import type { ChatMessageReplyingTo } from '../book-components/Chat/types/ChatMessage';
67
67
  import type { ChatMessage } from '../book-components/Chat/types/ChatMessage';
68
68
  import type { ChatParticipant } from '../book-components/Chat/types/ChatParticipant';
69
+ import type { CitationLabelResolver } from '../book-components/Chat/types/CitationLabelResolver';
69
70
  import type { MessageButton } from '../book-components/Chat/utils/parseMessageButtons';
70
71
  import { parseMessageButtons } from '../book-components/Chat/utils/parseMessageButtons';
71
72
  import { ArrowIcon } from '../book-components/icons/ArrowIcon';
@@ -150,6 +151,7 @@ export type { ChatProgressCard };
150
151
  export type { ChatMessageReplyingTo };
151
152
  export type { ChatMessage };
152
153
  export type { ChatParticipant };
154
+ export type { CitationLabelResolver };
153
155
  export type { MessageButton };
154
156
  export { parseMessageButtons };
155
157
  export { ArrowIcon };
@@ -55,6 +55,7 @@ import type { ChatProgressCard } from '../book-components/Chat/types/ChatMessage
55
55
  import type { ChatMessageReplyingTo } from '../book-components/Chat/types/ChatMessage';
56
56
  import type { ChatMessage } from '../book-components/Chat/types/ChatMessage';
57
57
  import type { ChatParticipant } from '../book-components/Chat/types/ChatParticipant';
58
+ import type { CitationLabelResolver } from '../book-components/Chat/types/CitationLabelResolver';
58
59
  import type { ParsedCitation } from '../book-components/Chat/utils/parseCitationsFromContent';
59
60
  import type { MessageButton } from '../book-components/Chat/utils/parseMessageButtons';
60
61
  import type { TeamToolResult } from '../book-components/Chat/utils/toolCallParsing/TeamToolResult';
@@ -496,6 +497,7 @@ export type { ChatProgressCard };
496
497
  export type { ChatMessageReplyingTo };
497
498
  export type { ChatMessage };
498
499
  export type { ChatParticipant };
500
+ export type { CitationLabelResolver };
499
501
  export type { ParsedCitation };
500
502
  export type { MessageButton };
501
503
  export type { TeamToolResult };
@@ -7,6 +7,10 @@ type AvatarAnimationListener = (now: number) => void;
7
7
  /**
8
8
  * Registers one avatar animation callback in the shared animation loop.
9
9
  *
10
+ * Each listener is staggered at registration time so it does not fire on the same animation
11
+ * frame as the existing listeners, and the shared loop further caps how many listeners run
12
+ * per frame, keeping the main thread responsive when many avatars are mounted.
13
+ *
10
14
  * @param avatarAnimationListener Frame callback invoked on every animation frame.
11
15
  * @returns Cleanup function that unregisters the callback.
12
16
  *
@@ -1,4 +1,5 @@
1
1
  import type { ChatParticipant } from '../types/ChatParticipant';
2
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
2
3
  import type { ParsedCitation } from '../utils/parseCitationsFromContent';
3
4
  import type { ChatSoundSystem } from './ChatProps';
4
5
  /**
@@ -10,6 +11,7 @@ export type ChatCitationModalProps = {
10
11
  isOpen: boolean;
11
12
  citation: ParsedCitation | null;
12
13
  participants: ReadonlyArray<ChatParticipant>;
14
+ resolveCitationLabel?: CitationLabelResolver;
13
15
  soundSystem?: ChatSoundSystem;
14
16
  onClose: () => void;
15
17
  };
@@ -38,6 +38,10 @@ type ChatMessageItemProps = Pick<ChatProps, 'onMessage' | 'onActionButton' | 'on
38
38
  * Optional localized labels used by timestamp metadata.
39
39
  */
40
40
  timingTranslations?: ChatProps['timingTranslations'];
41
+ /**
42
+ * Optional resolver for turning technical citation sources into page/document titles.
43
+ */
44
+ resolveCitationLabel?: ChatProps['resolveCitationLabel'];
41
45
  /**
42
46
  * Optional moment locale used to format message timestamps.
43
47
  */
@@ -32,6 +32,10 @@ export type ChatMessageListProps = {
32
32
  * Optional localized labels used by timestamp metadata.
33
33
  */
34
34
  timingTranslations?: ChatProps['timingTranslations'];
35
+ /**
36
+ * Optional resolver for turning technical citation sources into page/document titles.
37
+ */
38
+ resolveCitationLabel?: ChatProps['resolveCitationLabel'];
35
39
  /**
36
40
  * Optional moment locale used to format message timestamps.
37
41
  */
@@ -8,6 +8,7 @@ import type { AgentChipData } from '../AgentChip/AgentChip';
8
8
  import type { string_chat_format_name } from '../save/_common/string_chat_format_name';
9
9
  import type { ChatMessage } from '../types/ChatMessage';
10
10
  import type { ChatParticipant } from '../types/ChatParticipant';
11
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
11
12
  import type { ChatSaveFormatHandlerMap } from '../save/_common/ChatSaveFormatHandler';
12
13
  /**
13
14
  * Response data returned by the optional `onFeedback` handler.
@@ -715,6 +716,10 @@ export type ChatProps = {
715
716
  * Optional localized labels used by timestamp metadata shown under messages.
716
717
  */
717
718
  readonly timingTranslations?: ChatTimingTranslations;
719
+ /**
720
+ * Optional resolver for turning technical citation sources into page/document titles.
721
+ */
722
+ readonly resolveCitationLabel?: CitationLabelResolver;
718
723
  /**
719
724
  * Optional localized labels for general Chat UI elements such as button labels,
720
725
  * lifecycle state badges, tool call modal strings, and the default input placeholder.
@@ -3,6 +3,7 @@ import type { WithTake } from '../../../utils/take/interfaces/ITakeChain';
3
3
  import type { AgentChipData } from '../AgentChip/AgentChip';
4
4
  import type { ChatMessage } from '../types/ChatMessage';
5
5
  import type { ChatParticipant } from '../types/ChatParticipant';
6
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
6
7
  /**
7
8
  * Props for the tool call details modal.
8
9
  *
@@ -20,6 +21,7 @@ export type ChatToolCallModalProps = {
20
21
  toolCallIdentity?: string | null;
21
22
  onClose: () => void;
22
23
  toolTitles?: Record<string, string>;
24
+ resolveCitationLabel?: CitationLabelResolver;
23
25
  agentParticipant?: ChatParticipant;
24
26
  buttonColor: WithTake<Color>;
25
27
  /**
@@ -3,6 +3,7 @@ import { Color } from '../../../utils/color/Color';
3
3
  import type { WithTake } from '../../../utils/take/interfaces/ITakeChain';
4
4
  import type { ChatMessage } from '../types/ChatMessage';
5
5
  import type { ChatParticipant } from '../types/ChatParticipant';
6
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
6
7
  import type { TeamToolCallSummary, TransitiveToolCall } from '../utils/collectTeamToolCallSummary';
7
8
  import type { AgentProfileData } from '../utils/loadAgentProfile';
8
9
  import type { TeamToolResult } from '../utils/toolCallParsing/TeamToolResult';
@@ -27,6 +28,7 @@ type ChatToolCallModalContentProps = {
27
28
  readonly isAdvancedView: boolean;
28
29
  readonly locale?: string;
29
30
  readonly mode: 'LIGHT' | 'DARK';
31
+ readonly resolveCitationLabel?: CitationLabelResolver;
30
32
  readonly onClearSelectedTeamToolCall: () => void;
31
33
  readonly onRequestAdvancedView: () => void;
32
34
  readonly onSelectTeamToolCall: (toolCall: TransitiveToolCall) => void;
@@ -43,5 +45,5 @@ type ChatToolCallModalContentProps = {
43
45
  *
44
46
  * @private component of `ChatToolCallModal`
45
47
  */
46
- export declare function ChatToolCallModalContent({ agentParticipant, availableTools, buttonColor, chatUiTranslations, focusedToolCall, isAdvancedView, locale, mode, onClearSelectedTeamToolCall, onRequestAdvancedView, onSelectTeamToolCall, selectedTeamToolCall, teamProfiles, teamResult, teamToolCallSummary, toolCall, toolCallDate, toolTitles, }: ChatToolCallModalContentProps): ReactElement;
48
+ export declare function ChatToolCallModalContent({ agentParticipant, availableTools, buttonColor, chatUiTranslations, focusedToolCall, isAdvancedView, locale, mode, resolveCitationLabel, onClearSelectedTeamToolCall, onRequestAdvancedView, onSelectTeamToolCall, selectedTeamToolCall, teamProfiles, teamResult, teamToolCallSummary, toolCall, toolCallDate, toolTitles, }: ChatToolCallModalContentProps): ReactElement;
47
49
  export {};
@@ -2,6 +2,7 @@ import { type ReactElement } from 'react';
2
2
  import { Color } from '../../../utils/color/Color';
3
3
  import type { WithTake } from '../../../utils/take/interfaces/ITakeChain';
4
4
  import type { ChatParticipant } from '../types/ChatParticipant';
5
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
5
6
  import type { TeamToolCallSummary, TransitiveToolCall } from '../utils/collectTeamToolCallSummary';
6
7
  import type { AgentProfileData } from '../utils/loadAgentProfile';
7
8
  import type { TeamToolResult } from '../utils/toolCallParsing/TeamToolResult';
@@ -19,6 +20,7 @@ type TeamToolCallModalContentOptions = {
19
20
  onClearSelectedTeamToolCall: () => void;
20
21
  teamProfiles: Record<string, AgentProfileData>;
21
22
  toolTitles?: Record<string, string>;
23
+ resolveCitationLabel?: CitationLabelResolver;
22
24
  agentParticipant?: ChatParticipant;
23
25
  buttonColor: WithTake<Color>;
24
26
  };
@@ -1,3 +1,4 @@
1
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
1
2
  import type { ParsedCitation } from '../utils/parseCitationsFromContent';
2
3
  /**
3
4
  * Props for SourceChip component
@@ -19,6 +20,10 @@ export type SourceChipProps = {
19
20
  * Optional suffix text to display after the citation label.
20
21
  */
21
22
  suffix?: string;
23
+ /**
24
+ * Optional resolver for richer citation labels.
25
+ */
26
+ resolveCitationLabel?: CitationLabelResolver;
22
27
  /**
23
28
  * Controls whether the technical citation id is shown inside the chip label.
24
29
  */
@@ -41,4 +46,4 @@ export type SourceChipProps = {
41
46
  *
42
47
  * @private utility of `ChatMessageItem` component
43
48
  */
44
- export declare function SourceChip({ citation, onClick, className, suffix, isCitationIdVisible }: SourceChipProps): import("react/jsx-runtime").JSX.Element;
49
+ export declare function SourceChip({ citation, onClick, className, suffix, resolveCitationLabel, isCitationIdVisible, }: SourceChipProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,12 @@
1
+ import type { CitationLabelResolver } from '../types/CitationLabelResolver';
2
+ import type { ParsedCitation } from '../utils/parseCitationsFromContent';
3
+ /**
4
+ * Resolves the best available label for one citation.
5
+ *
6
+ * @param citation - Citation metadata.
7
+ * @param resolveCitationLabel - Optional async host resolver.
8
+ * @returns Current label, starting with a synchronous fallback and updating when the resolver finishes.
9
+ *
10
+ * @private hook of `<Chat/>`
11
+ */
12
+ export declare function useResolvedCitationLabel(citation: ParsedCitation, resolveCitationLabel?: CitationLabelResolver): string;
@@ -254,6 +254,10 @@ export type ChatMessage = Omit<Message<id>, 'direction' | 'recipients' | 'thread
254
254
  * Optional URL to the source document
255
255
  */
256
256
  url?: string;
257
+ /**
258
+ * Optional human-readable source title.
259
+ */
260
+ title?: string;
257
261
  /**
258
262
  * Optional preview/excerpt from the source
259
263
  */
@@ -47,7 +47,7 @@ export type ChatParticipant = {
47
47
  * Knowledge sources (documents, URLs) used by the agent
48
48
  * Used for resolving document citations when the agent references sources
49
49
  */
50
- knowledgeSources?: Array<{
50
+ knowledgeSources?: ReadonlyArray<{
51
51
  url: string;
52
52
  filename: string;
53
53
  }>;
@@ -0,0 +1,8 @@
1
+ import type { Promisable } from 'type-fest';
2
+ import type { ParsedCitation } from '../utils/parseCitationsFromContent';
3
+ /**
4
+ * Optional host-provided resolver for citation display labels.
5
+ *
6
+ * @public exported from `@promptbook/components`
7
+ */
8
+ export type CitationLabelResolver = (citation: ParsedCitation) => Promisable<string | null | undefined>;
@@ -37,3 +37,12 @@ export declare function getCitationLabel(citation: ParsedCitation): string;
37
37
  * @private utility of `<Chat/>` citation rendering
38
38
  */
39
39
  export declare function resolveCitationPreviewUrl(citation: ParsedCitation, participants: ReadonlyArray<ChatParticipant>): string | null;
40
+ /**
41
+ * Creates a readable fallback label from a citation source when no title metadata is available.
42
+ *
43
+ * @param source - Raw citation source value.
44
+ * @returns Human-friendly source label.
45
+ *
46
+ * @private utility of `<Chat/>` citation rendering
47
+ */
48
+ export declare function createReadableCitationSourceLabel(source: string): string;
@@ -0,0 +1,14 @@
1
+ import type { string_markdown } from '../../../types/string_markdown';
2
+ /**
3
+ * Decodes JSON-style Unicode escape sequences in markdown prose while preserving code.
4
+ *
5
+ * Model/tool output can occasionally arrive as already JSON-escaped text, which makes
6
+ * natural-language replies render `\u00fd` instead of the decoded character. This
7
+ * keeps code examples intact by skipping fenced code blocks and inline code spans.
8
+ *
9
+ * @param markdown - Markdown chat content to normalize for display.
10
+ * @returns Markdown chat content with non-ASCII JSON Unicode escapes decoded.
11
+ *
12
+ * @private internal utility of `<Chat/>`
13
+ */
14
+ export declare function decodeJsonUnicodeEscapesInMarkdownText(markdown: string_markdown): string_markdown;
@@ -15,6 +15,10 @@ export type ParsedCitation = {
15
15
  * Optional URL to the source document
16
16
  */
17
17
  url?: string;
18
+ /**
19
+ * Optional human-readable source title.
20
+ */
21
+ title?: string;
18
22
  /**
19
23
  * Optional preview/excerpt from the source
20
24
  */
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
15
15
  export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
16
16
  /**
17
17
  * Represents the version string of the Promptbook engine.
18
- * It follows semantic versioning (e.g., `0.112.0-123`).
18
+ * It follows semantic versioning (e.g., `0.112.0-126`).
19
19
  *
20
20
  * @generated
21
21
  */