@promptbook/cli 0.112.0-126 → 0.112.0-127
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.
- package/README.md +5 -5
- package/apps/agents-server/README.md +3 -0
- package/apps/agents-server/playwright.config.ts +1 -0
- package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
- package/apps/agents-server/public/promptbook-logo-white.png +0 -0
- package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
- package/apps/agents-server/src/app/actions.ts +2 -2
- package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
- package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
- package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
- package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
- package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
- package/apps/agents-server/src/app/globals.css +78 -0
- package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
- package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
- package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
- package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
- package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
- package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
- package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
- package/apps/agents-server/src/database/getMetadata.ts +37 -1
- package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
- package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
- package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
- package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
- package/apps/agents-server/src/languages/translations/english.yaml +1 -1
- package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
- package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
- package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
- package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
- package/apps/agents-server/src/utils/session.ts +62 -5
- package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
- package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
- package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
- package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
- package/esm/index.es.js +1052 -455
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/esm/src/_packages/components.index.d.ts +2 -0
- package/esm/src/_packages/types.index.d.ts +2 -0
- package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/components.index.ts +2 -0
- package/src/_packages/types.index.ts +2 -0
- package/src/avatars/avatarAnimationScheduler.ts +61 -20
- package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
- package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
- package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
- package/src/book-components/Chat/Chat/Chat.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
- package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
- package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
- package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
- package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
- package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
- package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
- package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
- package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
- package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
- package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
- package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
- package/src/book-components/Chat/types/ChatMessage.ts +5 -0
- package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
- package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
- package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
- package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
- package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
- package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
- package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
- package/src/cli/cli-commands/coder/run.ts +17 -20
- package/src/cli/cli-commands/coder/server.ts +13 -16
- package/src/cli/common/$deprecateCliCommand.ts +10 -1
- package/src/commitments/GOAL/GOAL.ts +7 -2
- package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
- package/src/commitments/TEAM/TEAM.ts +12 -1
- package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
- package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
- package/src/import-plugins/TextFileImportPlugin.ts +8 -1
- package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +681 -837
- package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +1055 -458
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
- package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
- package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
- package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
- package/umd/src/_packages/components.index.d.ts +2 -0
- package/umd/src/_packages/types.index.d.ts +2 -0
- package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
- package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
- package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
- package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
- package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
- package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
- package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
- package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
- package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
- package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -37,10 +37,10 @@ import * as ts from 'typescript';
|
|
|
37
37
|
import ignore from 'ignore';
|
|
38
38
|
import * as readline from 'readline';
|
|
39
39
|
import { emitKeypressEvents, clearLine, cursorTo, createInterface } from 'readline';
|
|
40
|
+
import { EventEmitter } from 'events';
|
|
40
41
|
import { lookup, extension } from 'mime-types';
|
|
41
42
|
import papaparse from 'papaparse';
|
|
42
43
|
import { pathToFileURL } from 'url';
|
|
43
|
-
import { EventEmitter } from 'events';
|
|
44
44
|
import { Client } from 'pg';
|
|
45
45
|
import '@supabase/supabase-js';
|
|
46
46
|
|
|
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
58
58
|
* @generated
|
|
59
59
|
* @see https://github.com/webgptorg/promptbook
|
|
60
60
|
*/
|
|
61
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-127';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2692,8 +2692,16 @@ function createAgentsServerEnvVariable(name, value) {
|
|
|
2692
2692
|
* Builds a `.env` block containing missing Agents Server variables and documentation links.
|
|
2693
2693
|
*/
|
|
2694
2694
|
function buildMissingEnvVariablesBlock$1(variables) {
|
|
2695
|
-
const variableBlocks = variables.map(({ documentationUrl, name, value }) =>
|
|
2696
|
-
|
|
2695
|
+
const variableBlocks = variables.map(({ documentationUrl, name, value }) => spaceTrim$1(`
|
|
2696
|
+
${AGENTS_SERVER_ENV_CREATED_COMMENT}
|
|
2697
|
+
# Documentation: ${documentationUrl}
|
|
2698
|
+
${name}=${value}
|
|
2699
|
+
`));
|
|
2700
|
+
return spaceTrim$1((block) => `
|
|
2701
|
+
# Promptbook Agents Server
|
|
2702
|
+
|
|
2703
|
+
${block(variableBlocks.join('\n\n'))}
|
|
2704
|
+
`);
|
|
2697
2705
|
}
|
|
2698
2706
|
// Note: [🟡] Code for Agents Server environment bootstrapping [ensureAgentsServerEnvFile](src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts) should never be published outside of `@promptbook/cli`
|
|
2699
2707
|
|
|
@@ -4265,6 +4273,13 @@ function buildScriptPathSessionRows(scriptPaths, bodyWidth) {
|
|
|
4265
4273
|
},
|
|
4266
4274
|
];
|
|
4267
4275
|
}
|
|
4276
|
+
/**
|
|
4277
|
+
* Builds one OSC 8 terminal hyperlink to an HTTP URL.
|
|
4278
|
+
*/
|
|
4279
|
+
function buildTerminalUrlLink(url, availableWidth) {
|
|
4280
|
+
const displayUrl = fitPlainText(url, availableWidth);
|
|
4281
|
+
return `\u001B]8;;${url}\u0007${displayUrl}\u001B]8;;\u0007`;
|
|
4282
|
+
}
|
|
4268
4283
|
/**
|
|
4269
4284
|
* Builds the colored phase badge shown in the session box.
|
|
4270
4285
|
*/
|
|
@@ -4455,6 +4470,9 @@ function buildSessionRows(options, bodyWidth, pausePresentation) {
|
|
|
4455
4470
|
}
|
|
4456
4471
|
const configurationRows = [
|
|
4457
4472
|
...buildOptionalSessionRow('Context', options.config.context),
|
|
4473
|
+
...buildOptionalSessionRow('Server', options.config.serverUrl
|
|
4474
|
+
? buildTerminalUrlLink(options.config.serverUrl, bodyWidth - SESSION_LABEL_WIDTH - 1)
|
|
4475
|
+
: undefined),
|
|
4458
4476
|
...buildOptionalSessionRow('Test', options.config.testCommand),
|
|
4459
4477
|
];
|
|
4460
4478
|
return [
|
|
@@ -4897,7 +4915,8 @@ function getTerminalWidth() {
|
|
|
4897
4915
|
* @private internal entry point of coder run UI
|
|
4898
4916
|
*/
|
|
4899
4917
|
function renderCoderRunUi(startTime, options = {}) {
|
|
4900
|
-
|
|
4918
|
+
var _a;
|
|
4919
|
+
const state = (_a = options.state) !== null && _a !== void 0 ? _a : new CoderRunUiState(startTime);
|
|
4901
4920
|
const buildFrameLinesFromState = options.buildFrameLines || buildCoderRunUiFrame;
|
|
4902
4921
|
if (!process.stdout.isTTY) {
|
|
4903
4922
|
return {
|
|
@@ -7876,8 +7895,11 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
7876
7895
|
if (!trimmedContent) {
|
|
7877
7896
|
return requirements;
|
|
7878
7897
|
}
|
|
7879
|
-
|
|
7880
|
-
|
|
7898
|
+
const goalSection = spaceTrim$1((block) => `
|
|
7899
|
+
## Goal
|
|
7900
|
+
|
|
7901
|
+
${block(trimmedContent)}
|
|
7902
|
+
`);
|
|
7881
7903
|
const requirementsWithGoal = this.appendToSystemMessage(requirements, goalSection, '\n\n');
|
|
7882
7904
|
return this.appendToPromptSuffix(requirementsWithGoal, trimmedContent);
|
|
7883
7905
|
}
|
|
@@ -8399,8 +8421,11 @@ class LanguageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
8399
8421
|
if (!trimmedContent) {
|
|
8400
8422
|
return requirements;
|
|
8401
8423
|
}
|
|
8402
|
-
|
|
8403
|
-
|
|
8424
|
+
const languageSection = spaceTrim$1((block) => `
|
|
8425
|
+
## Language
|
|
8426
|
+
|
|
8427
|
+
- Your language is ${block(trimmedContent)}
|
|
8428
|
+
`);
|
|
8404
8429
|
return this.appendToSystemMessage(requirements, languageSection, '\n\n');
|
|
8405
8430
|
}
|
|
8406
8431
|
}
|
|
@@ -13365,41 +13390,91 @@ function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, mo
|
|
|
13365
13390
|
context.fill();
|
|
13366
13391
|
context.restore();
|
|
13367
13392
|
}
|
|
13393
|
+
/**
|
|
13394
|
+
* Number of latitude segments used by the single blobby octopus mesh.
|
|
13395
|
+
*
|
|
13396
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
13397
|
+
*/
|
|
13398
|
+
const LATITUDE_PATCH_COUNT$1 = 12;
|
|
13399
|
+
/**
|
|
13400
|
+
* Number of longitude segments used by the single blobby octopus mesh.
|
|
13401
|
+
*
|
|
13402
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
13403
|
+
*/
|
|
13404
|
+
const LONGITUDE_PATCH_COUNT$1 = 24;
|
|
13368
13405
|
/**
|
|
13369
13406
|
* Resolves all visible projected patches for the single blobby octopus mesh.
|
|
13370
13407
|
*
|
|
13408
|
+
* Within a single frame, mesh corner samples and longitude-only lobe-wave values are
|
|
13409
|
+
* quantized to the patch grid and computed once each rather than re-evaluated for every
|
|
13410
|
+
* patch corner — the patch loop alone would call `sampleBlobbyOctopusSurfacePoint`
|
|
13411
|
+
* `latitudePatchCount * longitudePatchCount * 4` times without caching, even though most
|
|
13412
|
+
* corners are shared between neighboring patches.
|
|
13413
|
+
*
|
|
13371
13414
|
* @private helper of `octopus3d2AvatarVisual`
|
|
13372
13415
|
*/
|
|
13373
13416
|
function resolveVisibleBlobbyOctopusPatches(options) {
|
|
13374
13417
|
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, morphologyProfile, animationPhase, timeMs, } = options;
|
|
13375
|
-
const latitudePatchCount =
|
|
13376
|
-
const longitudePatchCount =
|
|
13418
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT$1;
|
|
13419
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT$1;
|
|
13377
13420
|
const surfacePatches = [];
|
|
13421
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
13422
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
13423
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
13424
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
13425
|
+
}
|
|
13426
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
13427
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
13428
|
+
}
|
|
13429
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
13430
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
13431
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveLowerLobeWave(longitudeBoundaries[boundaryIndex], morphologyProfile, animationPhase, timeMs);
|
|
13432
|
+
}
|
|
13433
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
13434
|
+
const transformedCornerSamples = new Array(cornerCount);
|
|
13435
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
13436
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex];
|
|
13437
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
13438
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex];
|
|
13439
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
13440
|
+
const cornerSample = sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, cornerLatitude, cornerLongitude, cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]);
|
|
13441
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
13442
|
+
}
|
|
13443
|
+
}
|
|
13378
13444
|
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
13379
|
-
const startLatitude =
|
|
13380
|
-
const endLatitude =
|
|
13445
|
+
const startLatitude = latitudeBoundaries[latitudeIndex];
|
|
13446
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1];
|
|
13381
13447
|
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
13382
13448
|
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
13449
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
13450
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
13383
13451
|
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
13384
|
-
const startLongitude =
|
|
13385
|
-
const endLongitude =
|
|
13452
|
+
const startLongitude = longitudeBoundaries[longitudeIndex];
|
|
13453
|
+
const endLongitude = longitudeBoundaries[longitudeIndex + 1];
|
|
13386
13454
|
const centerLongitude = (startLongitude + endLongitude) / 2;
|
|
13387
|
-
const
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13455
|
+
const transformedCorners = [
|
|
13456
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex],
|
|
13457
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1],
|
|
13458
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1],
|
|
13459
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex],
|
|
13392
13460
|
];
|
|
13393
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
13394
13461
|
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
13395
13462
|
if (surfaceNormal.z <= 0.01) {
|
|
13396
13463
|
continue;
|
|
13397
13464
|
}
|
|
13398
|
-
const projectedCorners =
|
|
13465
|
+
const projectedCorners = [
|
|
13466
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
13467
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
13468
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
13469
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
13470
|
+
];
|
|
13399
13471
|
surfacePatches.push({
|
|
13400
13472
|
corners: projectedCorners,
|
|
13401
|
-
averageDepth: transformedCorners.
|
|
13402
|
-
transformedCorners.
|
|
13473
|
+
averageDepth: (transformedCorners[0].z +
|
|
13474
|
+
transformedCorners[1].z +
|
|
13475
|
+
transformedCorners[2].z +
|
|
13476
|
+
transformedCorners[3].z) /
|
|
13477
|
+
4,
|
|
13403
13478
|
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION$1), -1, 1),
|
|
13404
13479
|
fillStyle: resolveBlobbySurfacePatchFillStyle(palette, verticalProgress, Math.max(0, Math.cos(centerLongitude)), resolveLowerLobeWave(centerLongitude, morphologyProfile, animationPhase, timeMs)),
|
|
13405
13480
|
outlineColor: verticalProgress < 0.58 ? `${palette.highlight}73` : `${palette.shadow}8a`,
|
|
@@ -13417,12 +13492,21 @@ function resolveVisibleBlobbyOctopusPatches(options) {
|
|
|
13417
13492
|
* @private helper of `octopus3d2AvatarVisual`
|
|
13418
13493
|
*/
|
|
13419
13494
|
function sampleBlobbyOctopusSurfacePoint(options, latitude, longitude) {
|
|
13495
|
+
const { morphologyProfile, animationPhase, timeMs } = options;
|
|
13496
|
+
return sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs));
|
|
13497
|
+
}
|
|
13498
|
+
/**
|
|
13499
|
+
* Samples one point on the continuous Octopus 3D 2 surface using a precomputed lower-lobe wave
|
|
13500
|
+
* to skip the per-call trig evaluation for `latitudePatchCount + 1` longitude-shared corners.
|
|
13501
|
+
*
|
|
13502
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
13503
|
+
*/
|
|
13504
|
+
function sampleBlobbyOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, lowerLobeWave) {
|
|
13420
13505
|
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
13421
13506
|
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
13422
13507
|
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
13423
13508
|
const upperBlend = Math.pow(1 - verticalProgress, 1.2);
|
|
13424
13509
|
const lowerBlend = Math.pow(verticalProgress, 1.42);
|
|
13425
|
-
const lowerLobeWave = resolveLowerLobeWave(longitude, morphologyProfile, animationPhase, timeMs);
|
|
13426
13510
|
const skirtEnvelope = Math.pow(cosineLatitude, 0.5) * lowerBlend;
|
|
13427
13511
|
const horizontalScale = 1.02 +
|
|
13428
13512
|
skirtEnvelope * (0.34 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.22 + lowerLobeWave * 0.22) -
|
|
@@ -13719,45 +13803,102 @@ function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs
|
|
|
13719
13803
|
context.fill();
|
|
13720
13804
|
context.restore();
|
|
13721
13805
|
}
|
|
13806
|
+
/**
|
|
13807
|
+
* Number of latitude segments used by the continuous Octopus 3D 3 mesh.
|
|
13808
|
+
*
|
|
13809
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13810
|
+
*/
|
|
13811
|
+
const LATITUDE_PATCH_COUNT = 16;
|
|
13812
|
+
/**
|
|
13813
|
+
* Number of longitude segments used by the continuous Octopus 3D 3 mesh.
|
|
13814
|
+
*
|
|
13815
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13816
|
+
*/
|
|
13817
|
+
const LONGITUDE_PATCH_COUNT = 40;
|
|
13722
13818
|
/**
|
|
13723
13819
|
* Resolves visible projected patches for the continuous octopus mesh.
|
|
13724
13820
|
*
|
|
13821
|
+
* Within a single frame, mesh corner samples and longitude-only computations (tentacle
|
|
13822
|
+
* influence and lobe wave) are quantized to the patch grid and computed once each rather
|
|
13823
|
+
* than re-evaluated for every patch corner — the patch loop alone calls `sampleContinuousOctopusSurfacePoint`
|
|
13824
|
+
* for `latitudePatchCount * longitudePatchCount * 4` corners without caching, and each call
|
|
13825
|
+
* triggers an inner 8-iteration `Math.exp` loop, which dominates the per-frame cost.
|
|
13826
|
+
*
|
|
13725
13827
|
* @private helper of `octopus3d3AvatarVisual`
|
|
13726
13828
|
*/
|
|
13727
13829
|
function resolveVisibleContinuousOctopusPatches(options) {
|
|
13728
13830
|
const { center, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette } = options;
|
|
13729
|
-
const latitudePatchCount =
|
|
13730
|
-
const longitudePatchCount =
|
|
13831
|
+
const latitudePatchCount = LATITUDE_PATCH_COUNT;
|
|
13832
|
+
const longitudePatchCount = LONGITUDE_PATCH_COUNT;
|
|
13731
13833
|
const surfacePatches = [];
|
|
13834
|
+
const latitudeBoundaries = new Float64Array(latitudePatchCount + 1);
|
|
13835
|
+
const longitudeBoundaries = new Float64Array(longitudePatchCount + 1);
|
|
13836
|
+
for (let boundaryIndex = 0; boundaryIndex <= latitudePatchCount; boundaryIndex++) {
|
|
13837
|
+
latitudeBoundaries[boundaryIndex] = -Math.PI / 2 + (boundaryIndex / latitudePatchCount) * Math.PI;
|
|
13838
|
+
}
|
|
13839
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
13840
|
+
longitudeBoundaries[boundaryIndex] = -Math.PI + (boundaryIndex / longitudePatchCount) * Math.PI * 2;
|
|
13841
|
+
}
|
|
13842
|
+
const cachedTentacleInfluencesByCornerLongitude = new Array(longitudePatchCount + 1);
|
|
13843
|
+
const cachedLobeWavesByCornerLongitude = new Float64Array(longitudePatchCount + 1);
|
|
13844
|
+
const cachedTentacleInfluencesByPatchCenterLongitude = new Array(longitudePatchCount);
|
|
13845
|
+
const cachedLobeWavesByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
13846
|
+
const cachedCosByPatchCenterLongitude = new Float64Array(longitudePatchCount);
|
|
13847
|
+
for (let boundaryIndex = 0; boundaryIndex <= longitudePatchCount; boundaryIndex++) {
|
|
13848
|
+
const cornerLongitude = longitudeBoundaries[boundaryIndex];
|
|
13849
|
+
cachedTentacleInfluencesByCornerLongitude[boundaryIndex] = resolveContinuousTentacleInfluence(options, cornerLongitude);
|
|
13850
|
+
cachedLobeWavesByCornerLongitude[boundaryIndex] = resolveContinuousLobeWave(options, cornerLongitude);
|
|
13851
|
+
}
|
|
13852
|
+
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
13853
|
+
const patchCenterLongitude = (longitudeBoundaries[longitudeIndex] + longitudeBoundaries[longitudeIndex + 1]) / 2;
|
|
13854
|
+
cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex] = resolveContinuousTentacleInfluence(options, patchCenterLongitude);
|
|
13855
|
+
cachedLobeWavesByPatchCenterLongitude[longitudeIndex] = resolveContinuousLobeWave(options, patchCenterLongitude);
|
|
13856
|
+
cachedCosByPatchCenterLongitude[longitudeIndex] = Math.max(0, Math.cos(patchCenterLongitude));
|
|
13857
|
+
}
|
|
13858
|
+
const cornerCount = (latitudePatchCount + 1) * (longitudePatchCount + 1);
|
|
13859
|
+
const transformedCornerSamples = new Array(cornerCount);
|
|
13860
|
+
for (let latitudeBoundaryIndex = 0; latitudeBoundaryIndex <= latitudePatchCount; latitudeBoundaryIndex++) {
|
|
13861
|
+
const cornerLatitude = latitudeBoundaries[latitudeBoundaryIndex];
|
|
13862
|
+
for (let longitudeBoundaryIndex = 0; longitudeBoundaryIndex <= longitudePatchCount; longitudeBoundaryIndex++) {
|
|
13863
|
+
const cornerLongitude = longitudeBoundaries[longitudeBoundaryIndex];
|
|
13864
|
+
const cornerIndex = latitudeBoundaryIndex * (longitudePatchCount + 1) + longitudeBoundaryIndex;
|
|
13865
|
+
const cornerSample = sampleContinuousOctopusSurfacePointWithLongitudeCache(options, cornerLatitude, cornerLongitude, cachedTentacleInfluencesByCornerLongitude[longitudeBoundaryIndex], cachedLobeWavesByCornerLongitude[longitudeBoundaryIndex]);
|
|
13866
|
+
transformedCornerSamples[cornerIndex] = transformScenePoint(cornerSample, center, rotationX, rotationY);
|
|
13867
|
+
}
|
|
13868
|
+
}
|
|
13732
13869
|
for (let latitudeIndex = 0; latitudeIndex < latitudePatchCount; latitudeIndex++) {
|
|
13733
|
-
const startLatitude =
|
|
13734
|
-
const endLatitude =
|
|
13870
|
+
const startLatitude = latitudeBoundaries[latitudeIndex];
|
|
13871
|
+
const endLatitude = latitudeBoundaries[latitudeIndex + 1];
|
|
13735
13872
|
const centerLatitude = (startLatitude + endLatitude) / 2;
|
|
13736
13873
|
const verticalProgress = (Math.sin(centerLatitude) + 1) / 2;
|
|
13874
|
+
const startCornerRowOffset = latitudeIndex * (longitudePatchCount + 1);
|
|
13875
|
+
const endCornerRowOffset = (latitudeIndex + 1) * (longitudePatchCount + 1);
|
|
13737
13876
|
for (let longitudeIndex = 0; longitudeIndex < longitudePatchCount; longitudeIndex++) {
|
|
13738
|
-
const
|
|
13739
|
-
|
|
13740
|
-
|
|
13741
|
-
|
|
13742
|
-
|
|
13743
|
-
sampleContinuousOctopusSurfacePoint(options, startLatitude, endLongitude),
|
|
13744
|
-
sampleContinuousOctopusSurfacePoint(options, endLatitude, endLongitude),
|
|
13745
|
-
sampleContinuousOctopusSurfacePoint(options, endLatitude, startLongitude),
|
|
13877
|
+
const transformedCorners = [
|
|
13878
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex],
|
|
13879
|
+
transformedCornerSamples[startCornerRowOffset + longitudeIndex + 1],
|
|
13880
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex + 1],
|
|
13881
|
+
transformedCornerSamples[endCornerRowOffset + longitudeIndex],
|
|
13746
13882
|
];
|
|
13747
|
-
const transformedCorners = localCorners.map((localCorner) => transformScenePoint(localCorner, center, rotationX, rotationY));
|
|
13748
13883
|
const surfaceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
13749
13884
|
if (surfaceNormal.z <= 0.008) {
|
|
13750
13885
|
continue;
|
|
13751
13886
|
}
|
|
13752
|
-
const projectedCorners =
|
|
13753
|
-
|
|
13754
|
-
|
|
13887
|
+
const projectedCorners = [
|
|
13888
|
+
projectScenePoint(transformedCorners[0], size, sceneCenterX, sceneCenterY),
|
|
13889
|
+
projectScenePoint(transformedCorners[1], size, sceneCenterX, sceneCenterY),
|
|
13890
|
+
projectScenePoint(transformedCorners[2], size, sceneCenterX, sceneCenterY),
|
|
13891
|
+
projectScenePoint(transformedCorners[3], size, sceneCenterX, sceneCenterY),
|
|
13892
|
+
];
|
|
13755
13893
|
surfacePatches.push({
|
|
13756
13894
|
corners: projectedCorners,
|
|
13757
|
-
averageDepth: transformedCorners.
|
|
13758
|
-
transformedCorners.
|
|
13895
|
+
averageDepth: (transformedCorners[0].z +
|
|
13896
|
+
transformedCorners[1].z +
|
|
13897
|
+
transformedCorners[2].z +
|
|
13898
|
+
transformedCorners[3].z) /
|
|
13899
|
+
4,
|
|
13759
13900
|
lightIntensity: clampNumber$1(dotProduct3D(surfaceNormal, LIGHT_DIRECTION), -1, 1),
|
|
13760
|
-
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress,
|
|
13901
|
+
fillStyle: resolveContinuousSurfacePatchFillStyle(palette, verticalProgress, cachedCosByPatchCenterLongitude[longitudeIndex], cachedTentacleInfluencesByPatchCenterLongitude[longitudeIndex].core, cachedLobeWavesByPatchCenterLongitude[longitudeIndex]),
|
|
13761
13902
|
outlineColor: verticalProgress < 0.54 ? `${palette.highlight}69` : `${palette.shadow}78`,
|
|
13762
13903
|
});
|
|
13763
13904
|
}
|
|
@@ -13773,16 +13914,27 @@ function resolveVisibleContinuousOctopusPatches(options) {
|
|
|
13773
13914
|
* @private helper of `octopus3d3AvatarVisual`
|
|
13774
13915
|
*/
|
|
13775
13916
|
function sampleContinuousOctopusSurfacePoint(options, latitude, longitude) {
|
|
13917
|
+
return sampleContinuousOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, resolveContinuousTentacleInfluence(options, longitude), resolveContinuousLobeWave(options, longitude));
|
|
13918
|
+
}
|
|
13919
|
+
/**
|
|
13920
|
+
* Samples one point on the continuous Octopus 3D 3 surface using precomputed longitude-only
|
|
13921
|
+
* values to skip the per-call `Math.exp` tentacle-influence loop and the lobe-wave trig call.
|
|
13922
|
+
*
|
|
13923
|
+
* The patch loop quantizes the mesh into a fixed `(latitudePatchCount + 1) * (longitudePatchCount + 1)`
|
|
13924
|
+
* corner grid, so the same longitude is reused across every latitude row and each
|
|
13925
|
+
* tentacle/lobe value can be computed once per frame instead of `latitudePatchCount * 4` times.
|
|
13926
|
+
*
|
|
13927
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13928
|
+
*/
|
|
13929
|
+
function sampleContinuousOctopusSurfacePointWithLongitudeCache(options, latitude, longitude, tentacleInfluence, lowerLobeWave) {
|
|
13776
13930
|
const { radiusX, radiusY, radiusZ, morphologyProfile, timeMs, animationPhase } = options;
|
|
13777
13931
|
const cosineLatitude = Math.max(0, Math.cos(latitude));
|
|
13778
13932
|
const verticalProgress = (Math.sin(latitude) + 1) / 2;
|
|
13779
13933
|
const upperBlend = Math.pow(1 - verticalProgress, 1.28);
|
|
13780
13934
|
const lowerBlend = smoothStep(0.38, 1, verticalProgress);
|
|
13781
13935
|
const tipBlend = smoothStep(0.68, 1, verticalProgress);
|
|
13782
|
-
const tentacleInfluence = resolveContinuousTentacleInfluence(options, longitude);
|
|
13783
13936
|
const centerPull = resolveSignedAngularDistance(longitude, tentacleInfluence.centerLongitude);
|
|
13784
13937
|
const effectiveLongitude = longitude + centerPull * lowerBlend * tentacleInfluence.core * (0.24 + tipBlend * 0.2);
|
|
13785
|
-
const lowerLobeWave = resolveContinuousLobeWave(options, longitude);
|
|
13786
13938
|
const mantleRipple = Math.sin(longitude * morphologyProfile.body.lobeCount +
|
|
13787
13939
|
animationPhase * 0.6 +
|
|
13788
13940
|
timeMs / (1750 + morphologyProfile.body.lobeCount * 30)) *
|
|
@@ -17187,7 +17339,15 @@ function buildTeammateMetadata(entry) {
|
|
|
17187
17339
|
* Builds the teammate request text, optionally including context.
|
|
17188
17340
|
*/
|
|
17189
17341
|
function buildTeammateRequest(message, context) {
|
|
17190
|
-
|
|
17342
|
+
if (!context) {
|
|
17343
|
+
return message;
|
|
17344
|
+
}
|
|
17345
|
+
return spaceTrim$1((block) => `
|
|
17346
|
+
${block(message)}
|
|
17347
|
+
|
|
17348
|
+
Context:
|
|
17349
|
+
${block(context)}
|
|
17350
|
+
`);
|
|
17191
17351
|
}
|
|
17192
17352
|
/**
|
|
17193
17353
|
* Builds a minimal chat prompt for teammate calls.
|
|
@@ -21210,7 +21370,11 @@ function createUseProjectToolFunctions() {
|
|
|
21210
21370
|
const lineRangedContent = applyOptionalLineRange(decodedContent, args.startLine, args.endLine);
|
|
21211
21371
|
const wasCharacterTruncated = lineRangedContent.length > MAX_PROJECT_FILE_CONTENT_CHARACTERS;
|
|
21212
21372
|
const contentToReturn = wasCharacterTruncated
|
|
21213
|
-
?
|
|
21373
|
+
? spaceTrim$1((block) => `
|
|
21374
|
+
${block(lineRangedContent.slice(0, MAX_PROJECT_FILE_CONTENT_CHARACTERS))}
|
|
21375
|
+
|
|
21376
|
+
[...truncated...]
|
|
21377
|
+
`)
|
|
21214
21378
|
: lineRangedContent;
|
|
21215
21379
|
const wasTruncated = decoded.isTruncated || wasCharacterTruncated;
|
|
21216
21380
|
if (wasCharacterTruncated) {
|
|
@@ -26085,7 +26249,8 @@ function readOptionalSigningKeyValue() {
|
|
|
26085
26249
|
/**
|
|
26086
26250
|
* Commits staged changes with the provided message using the dedicated coding-agent identity when configured,
|
|
26087
26251
|
* otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush`,
|
|
26088
|
-
* `options.includePaths` can restrict staging,
|
|
26252
|
+
* `options.includePaths` can restrict staging, `options.onlyPaths` can restrict the commit pathspec,
|
|
26253
|
+
* and `options.excludePaths` can keep temporary artifacts out of the created commit.
|
|
26089
26254
|
*/
|
|
26090
26255
|
async function commitChanges(message, options) {
|
|
26091
26256
|
const projectPath = (options === null || options === void 0 ? void 0 : options.projectPath) || process.cwd();
|
|
@@ -26097,7 +26262,7 @@ async function commitChanges(message, options) {
|
|
|
26097
26262
|
const signingFlag = buildAgentGitSigningFlag();
|
|
26098
26263
|
await stageCommitChanges(projectPath, agentEnv, options === null || options === void 0 ? void 0 : options.includePaths, options === null || options === void 0 ? void 0 : options.excludePaths);
|
|
26099
26264
|
await runGitCommand({
|
|
26100
|
-
command: buildGitCommitCommand(commitMessagePath, signingFlag),
|
|
26265
|
+
command: buildGitCommitCommand(commitMessagePath, signingFlag, options === null || options === void 0 ? void 0 : options.onlyPaths),
|
|
26101
26266
|
cwd: projectPath,
|
|
26102
26267
|
env: agentEnv,
|
|
26103
26268
|
});
|
|
@@ -26277,12 +26442,15 @@ async function executeGitPushCommand(command, projectPath, agentEnv) {
|
|
|
26277
26442
|
/**
|
|
26278
26443
|
* Builds the `git commit` command with an optional signing flag.
|
|
26279
26444
|
*/
|
|
26280
|
-
function buildGitCommitCommand(commitMessagePath, signingFlag) {
|
|
26445
|
+
function buildGitCommitCommand(commitMessagePath, signingFlag, onlyPaths) {
|
|
26281
26446
|
const commandParts = ['git commit'];
|
|
26282
26447
|
if (signingFlag) {
|
|
26283
26448
|
commandParts.push(signingFlag);
|
|
26284
26449
|
}
|
|
26285
26450
|
commandParts.push(`--file "${commitMessagePath}"`);
|
|
26451
|
+
if (onlyPaths && onlyPaths.length > 0) {
|
|
26452
|
+
commandParts.push('--', ...onlyPaths.map(quoteShellPath$1));
|
|
26453
|
+
}
|
|
26286
26454
|
return commandParts.join(' ');
|
|
26287
26455
|
}
|
|
26288
26456
|
/**
|
|
@@ -27780,7 +27948,11 @@ function createOutputSnippet(output) {
|
|
|
27780
27948
|
if (normalized.length <= OUTPUT_SNIPPET_MAX_CHARS) {
|
|
27781
27949
|
return normalized;
|
|
27782
27950
|
}
|
|
27783
|
-
return
|
|
27951
|
+
return spaceTrim$1((block) => `
|
|
27952
|
+
${block(normalized.slice(0, OUTPUT_SNIPPET_MAX_CHARS))}
|
|
27953
|
+
|
|
27954
|
+
...[truncated]
|
|
27955
|
+
`);
|
|
27784
27956
|
}
|
|
27785
27957
|
/**
|
|
27786
27958
|
* Builds one command failure message that keeps a useful snippet of CLI output.
|
|
@@ -27790,7 +27962,11 @@ function buildCommandFailureMessage(scriptPathPosix, code, fullOutput) {
|
|
|
27790
27962
|
if (!outputSnippet) {
|
|
27791
27963
|
return `Command "bash ${scriptPathPosix}" exited with code ${code !== null && code !== void 0 ? code : 'unknown'}`;
|
|
27792
27964
|
}
|
|
27793
|
-
return
|
|
27965
|
+
return spaceTrim$1((block) => `
|
|
27966
|
+
Command "bash ${scriptPathPosix}" exited with code ${code !== null && code !== void 0 ? code : 'unknown'}
|
|
27967
|
+
|
|
27968
|
+
${block(outputSnippet)}
|
|
27969
|
+
`);
|
|
27794
27970
|
}
|
|
27795
27971
|
/**
|
|
27796
27972
|
* Runs a script until a completion marker is observed and output is idle for a set timeout.
|
|
@@ -27907,7 +28083,9 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
27907
28083
|
* Handles process exit and resolves or rejects accordingly.
|
|
27908
28084
|
*/
|
|
27909
28085
|
const handleExit = (code) => {
|
|
27910
|
-
const failure = code === 0 || markerSeen
|
|
28086
|
+
const failure = code === 0 || markerSeen
|
|
28087
|
+
? undefined
|
|
28088
|
+
: new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput));
|
|
27911
28089
|
const status = failure ? `failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}` : 'succeeded';
|
|
27912
28090
|
settleWithLog(status, () => {
|
|
27913
28091
|
if (!failure) {
|
|
@@ -27925,8 +28103,14 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
27925
28103
|
});
|
|
27926
28104
|
commandProcess.on('error', (error) => {
|
|
27927
28105
|
const outputSnippet = createOutputSnippet(fullOutput);
|
|
27928
|
-
const
|
|
27929
|
-
|
|
28106
|
+
const failureMessage = outputSnippet
|
|
28107
|
+
? spaceTrim$1((block) => `
|
|
28108
|
+
Command "bash ${scriptPathPosix}" failed: ${error.message}
|
|
28109
|
+
|
|
28110
|
+
${block(outputSnippet)}
|
|
28111
|
+
`)
|
|
28112
|
+
: `Command "bash ${scriptPathPosix}" failed: ${error.message}`;
|
|
28113
|
+
const failure = new Error(failureMessage);
|
|
27930
28114
|
settleWithLog('failed before completion', () => reject(failure), failure);
|
|
27931
28115
|
});
|
|
27932
28116
|
});
|
|
@@ -28265,7 +28449,11 @@ function limitErrorDetails(details, maxChars = 4000) {
|
|
|
28265
28449
|
if (normalized.length <= maxChars) {
|
|
28266
28450
|
return normalized;
|
|
28267
28451
|
}
|
|
28268
|
-
return
|
|
28452
|
+
return spaceTrim((block) => `
|
|
28453
|
+
${block(normalized.slice(0, maxChars))}
|
|
28454
|
+
|
|
28455
|
+
...[truncated]
|
|
28456
|
+
`);
|
|
28269
28457
|
}
|
|
28270
28458
|
/**
|
|
28271
28459
|
* Returns true if at least one regex matches the provided text.
|
|
@@ -34914,11 +35102,19 @@ const JsonFileImportPlugin = {
|
|
|
34914
35102
|
try {
|
|
34915
35103
|
const json = JSON.parse(content);
|
|
34916
35104
|
const formattedJson = JSON.stringify(json, null, 4);
|
|
34917
|
-
return
|
|
35105
|
+
return spaceTrim$1((block) => `
|
|
35106
|
+
\`\`\`json
|
|
35107
|
+
${block(formattedJson)}
|
|
35108
|
+
\`\`\`
|
|
35109
|
+
`);
|
|
34918
35110
|
}
|
|
34919
35111
|
catch (error) {
|
|
34920
35112
|
// If JSON is invalid, still import it but maybe not as pretty JSON
|
|
34921
|
-
return
|
|
35113
|
+
return spaceTrim$1((block) => `
|
|
35114
|
+
\`\`\`json
|
|
35115
|
+
${block(content)}
|
|
35116
|
+
\`\`\`
|
|
35117
|
+
`);
|
|
34922
35118
|
}
|
|
34923
35119
|
},
|
|
34924
35120
|
};
|
|
@@ -34942,7 +35138,11 @@ const TextFileImportPlugin = {
|
|
|
34942
35138
|
import(content, mimeType) {
|
|
34943
35139
|
const extension = mimeTypeToExtension(mimeType);
|
|
34944
35140
|
const codeBlockType = extension || 'txt';
|
|
34945
|
-
return
|
|
35141
|
+
return spaceTrim$1((block) => `
|
|
35142
|
+
\`\`\`${codeBlockType}
|
|
35143
|
+
${block(content)}
|
|
35144
|
+
\`\`\`
|
|
35145
|
+
`);
|
|
34946
35146
|
},
|
|
34947
35147
|
};
|
|
34948
35148
|
|
|
@@ -35189,11 +35389,19 @@ function collectExampleInteractionLines(parseResult, samples) {
|
|
|
35189
35389
|
const examples = [];
|
|
35190
35390
|
const initialMessage = (_a = parseResult.commitments.find((commitment) => commitment.type === 'INITIAL MESSAGE')) === null || _a === void 0 ? void 0 : _a.content;
|
|
35191
35391
|
if (initialMessage) {
|
|
35192
|
-
examples.push(
|
|
35392
|
+
examples.push(spaceTrim$1((block) => `
|
|
35393
|
+
**Agent:**
|
|
35394
|
+
${block(initialMessage)}
|
|
35395
|
+
`));
|
|
35193
35396
|
}
|
|
35194
35397
|
if (samples && samples.length > 0) {
|
|
35195
35398
|
for (const sample of samples) {
|
|
35196
|
-
examples.push(
|
|
35399
|
+
examples.push(spaceTrim$1((block) => `
|
|
35400
|
+
**User:** ${block(String(sample.question))}
|
|
35401
|
+
|
|
35402
|
+
**Agent:**
|
|
35403
|
+
${block(sample.answer)}
|
|
35404
|
+
`));
|
|
35197
35405
|
}
|
|
35198
35406
|
}
|
|
35199
35407
|
return examples;
|
|
@@ -35628,10 +35836,14 @@ async function createAgentRunnerSystemMessage(agentSource) {
|
|
|
35628
35836
|
* Formats prepared model requirements for a text-only CLI harness prompt.
|
|
35629
35837
|
*/
|
|
35630
35838
|
function formatAgentModelRequirementsForRunner(modelRequirements) {
|
|
35839
|
+
const promptSuffix = modelRequirements.promptSuffix.trim();
|
|
35631
35840
|
return [
|
|
35632
35841
|
modelRequirements.systemMessage.trim(),
|
|
35633
|
-
|
|
35634
|
-
?
|
|
35842
|
+
promptSuffix
|
|
35843
|
+
? spaceTrim$1((block) => `
|
|
35844
|
+
## Prompt suffix
|
|
35845
|
+
${block(promptSuffix)}
|
|
35846
|
+
`)
|
|
35635
35847
|
: '',
|
|
35636
35848
|
]
|
|
35637
35849
|
.filter(Boolean)
|
|
@@ -39284,7 +39496,7 @@ async function ensureCoderGitignoreFile(projectPath) {
|
|
|
39284
39496
|
*/
|
|
39285
39497
|
const DEFAULT_CODER_PACKAGE_JSON_SCRIPTS = {
|
|
39286
39498
|
'coder:generate-boilerplates': 'ptbk coder generate-boilerplates --template ./prompts/templates/common.md',
|
|
39287
|
-
'coder:run': 'ptbk coder run --harness openai-codex --model gpt-5.4 --thinking-level xhigh --agent agents/developer.book --context AGENTS.md
|
|
39499
|
+
'coder:run': 'ptbk coder run --harness openai-codex --model gpt-5.4 --thinking-level xhigh --agent agents/developer.book --context AGENTS.md',
|
|
39288
39500
|
// 'coder:find-refactor-candidates': 'ptbk coder find-refactor-candidates',
|
|
39289
39501
|
'coder:verify': 'ptbk coder verify',
|
|
39290
39502
|
};
|
|
@@ -39743,33 +39955,26 @@ function $initializeCoderRunCommand(program) {
|
|
|
39743
39955
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
39744
39956
|
addPromptRunnerExecutionOptions(command);
|
|
39745
39957
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption$1, 0);
|
|
39746
|
-
command.option('--wait
|
|
39747
|
-
Wait between prompt rounds.
|
|
39748
|
-
|
|
39749
|
-
|
|
39750
|
-
|
|
39751
|
-
|
|
39752
|
-
command.option('--no-wait', 'Skip all waiting between prompts and run non-interactively');
|
|
39958
|
+
command.option('--wait <duration>', spaceTrim$1(`
|
|
39959
|
+
Wait this long between prompt rounds to avoid hitting rate limits of the harness.
|
|
39960
|
+
Accepts durations like 1h, 30m, 5s.
|
|
39961
|
+
`));
|
|
39962
|
+
// Note: --no-auto disables the default auto behaviour and waits for user confirmation before each prompt
|
|
39963
|
+
command.option('--no-auto', 'Wait for user confirmation before each prompt instead of running automatically through the queue');
|
|
39753
39964
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
39754
39965
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
39755
39966
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
39756
|
-
const { dryRun, agent, context, test, preserveLogs, priority, wait, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
39967
|
+
const { dryRun, agent, context, test, preserveLogs, priority, wait, auto, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
39757
39968
|
const testCommand = normalizeCommandOptionValue$1(test);
|
|
39758
39969
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
39759
39970
|
isAgentRequired: !dryRun,
|
|
39760
39971
|
});
|
|
39761
|
-
// [1] Parse the --wait
|
|
39762
|
-
//
|
|
39763
|
-
//
|
|
39764
|
-
//
|
|
39765
|
-
|
|
39766
|
-
|
|
39767
|
-
if (wait === true) {
|
|
39768
|
-
waitForUser = true;
|
|
39769
|
-
}
|
|
39770
|
-
else if (typeof wait === 'string' && wait !== '') {
|
|
39771
|
-
waitBetweenPrompts = parseDuration(wait);
|
|
39772
|
-
}
|
|
39972
|
+
// [1] Parse the --wait and --no-auto options:
|
|
39973
|
+
// default: run automatically through the queue (no waiting)
|
|
39974
|
+
// --no-auto: wait for user confirmation before each prompt (interactive mode)
|
|
39975
|
+
// --wait <duration>: wait that long between prompt rounds to avoid rate limits
|
|
39976
|
+
const waitForUser = !auto;
|
|
39977
|
+
const waitBetweenPrompts = typeof wait === 'string' && wait !== '' ? parseDuration(wait) : 0;
|
|
39773
39978
|
// Convert commander options to RunOptions format
|
|
39774
39979
|
const runOptions = {
|
|
39775
39980
|
dryRun,
|
|
@@ -39882,30 +40087,23 @@ function $initializeCoderServerCommand(program) {
|
|
|
39882
40087
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
39883
40088
|
addPromptRunnerExecutionOptions(command);
|
|
39884
40089
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
39885
|
-
command.option('--wait
|
|
39886
|
-
Wait between prompt rounds.
|
|
39887
|
-
|
|
39888
|
-
|
|
39889
|
-
|
|
39890
|
-
command.option('--no-wait', 'Skip all waiting between prompts and run non-interactively');
|
|
40090
|
+
command.option('--wait <duration>', spaceTrim$1(`
|
|
40091
|
+
Wait this long between prompt rounds to avoid hitting rate limits of the harness.
|
|
40092
|
+
Accepts durations like 1h, 30m, 5s.
|
|
40093
|
+
`));
|
|
40094
|
+
command.option('--no-auto', 'Wait for user confirmation before each prompt instead of running automatically through the queue');
|
|
39891
40095
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
39892
40096
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
39893
40097
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
39894
|
-
const { port: rawPort, dryRun, agent, context, test, preserveLogs, priority, wait, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
40098
|
+
const { port: rawPort, dryRun, agent, context, test, preserveLogs, priority, wait, auto, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
39895
40099
|
const port = parseCoderServerPort(rawPort);
|
|
39896
40100
|
const testCommand = normalizeCommandOptionValue(test);
|
|
39897
40101
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
39898
40102
|
isAgentRequired: !dryRun,
|
|
39899
40103
|
});
|
|
39900
|
-
// [1] Parse the --wait
|
|
39901
|
-
|
|
39902
|
-
|
|
39903
|
-
if (wait === true) {
|
|
39904
|
-
waitForUser = true;
|
|
39905
|
-
}
|
|
39906
|
-
else if (typeof wait === 'string' && wait !== '') {
|
|
39907
|
-
waitBetweenPrompts = parseDuration(wait);
|
|
39908
|
-
}
|
|
40104
|
+
// [1] Parse the --wait and --no-auto options (same logic as `coder run`)
|
|
40105
|
+
const waitForUser = !auto;
|
|
40106
|
+
const waitBetweenPrompts = typeof wait === 'string' && wait !== '' ? parseDuration(wait) : 0;
|
|
39909
40107
|
const runOptions = {
|
|
39910
40108
|
port,
|
|
39911
40109
|
dryRun,
|
|
@@ -40511,7 +40709,12 @@ function colorizeAvailableProviderMessage(providerMessage, { isInstalled, isFull
|
|
|
40511
40709
|
* @private internal function of `$registeredLlmToolsMessage`
|
|
40512
40710
|
*/
|
|
40513
40711
|
function createUsedEnvMessage() {
|
|
40514
|
-
return $usedEnvFilename === null
|
|
40712
|
+
return $usedEnvFilename === null
|
|
40713
|
+
? `Unknown \`.env\` file`
|
|
40714
|
+
: spaceTrim$1(`
|
|
40715
|
+
Used \`.env\` file:
|
|
40716
|
+
${$usedEnvFilename}
|
|
40717
|
+
`);
|
|
40515
40718
|
}
|
|
40516
40719
|
// TODO: [®] DRY Register logic
|
|
40517
40720
|
// TODO: [🧠][⚛] Maybe pass env as argument
|
|
@@ -53101,7 +53304,11 @@ function $addGlobalOptionsToCommand(command) {
|
|
|
53101
53304
|
* @private utility of CLI
|
|
53102
53305
|
*/
|
|
53103
53306
|
function $deprecateCliCommand(command, deprecationMessage) {
|
|
53104
|
-
command.description(
|
|
53307
|
+
command.description(spaceTrim$1((block) => `
|
|
53308
|
+
${block(command.description())}
|
|
53309
|
+
|
|
53310
|
+
Deprecated: ${block(deprecationMessage)}
|
|
53311
|
+
`));
|
|
53105
53312
|
command.hook('preAction', () => {
|
|
53106
53313
|
console.warn(colors.yellow(createDeprecatedCliCommandWarning(command, deprecationMessage)));
|
|
53107
53314
|
});
|
|
@@ -65910,7 +66117,11 @@ function truncateAttachmentInlineText(content, maxCharacters) {
|
|
|
65910
66117
|
};
|
|
65911
66118
|
}
|
|
65912
66119
|
return {
|
|
65913
|
-
content:
|
|
66120
|
+
content: spaceTrim$1((block) => `
|
|
66121
|
+
${block(content.slice(0, Math.max(0, maxCharacters)))}
|
|
66122
|
+
|
|
66123
|
+
[...truncated...]
|
|
66124
|
+
`),
|
|
65914
66125
|
isTruncated: true,
|
|
65915
66126
|
};
|
|
65916
66127
|
}
|
|
@@ -69210,7 +69421,7 @@ var findUnwrittenPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
69210
69421
|
/**
|
|
69211
69422
|
* CLI usage text for this script.
|
|
69212
69423
|
*/
|
|
69213
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--preserve-logs] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--wait
|
|
69424
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--preserve-logs] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--wait <duration>] [--no-auto] [--no-commit] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push] [--auto-pull]';
|
|
69214
69425
|
/**
|
|
69215
69426
|
* Top-level flags supported by this command.
|
|
69216
69427
|
*/
|
|
@@ -69228,7 +69439,7 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
69228
69439
|
'--auto-migrate',
|
|
69229
69440
|
'--allow-destructive-auto-migrate',
|
|
69230
69441
|
'--wait',
|
|
69231
|
-
'--no-
|
|
69442
|
+
'--no-auto',
|
|
69232
69443
|
'--no-commit',
|
|
69233
69444
|
'--ignore-git-changes',
|
|
69234
69445
|
'--no-normalize-line-endings',
|
|
@@ -69266,22 +69477,20 @@ function parseRunOptions(args) {
|
|
|
69266
69477
|
const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
|
|
69267
69478
|
const autoPush = args.includes('--auto-push');
|
|
69268
69479
|
const autoPull = args.includes('--auto-pull');
|
|
69269
|
-
// [1] Parse --wait
|
|
69270
|
-
//
|
|
69271
|
-
// --
|
|
69480
|
+
// [1] Parse --wait <duration> and --no-auto:
|
|
69481
|
+
// default: run automatically through the queue (no waiting)
|
|
69482
|
+
// --no-auto: wait for user confirmation before each prompt (interactive mode)
|
|
69272
69483
|
// --wait 1h: wait 1h between prompt rounds to avoid rate limits
|
|
69273
|
-
const
|
|
69274
|
-
let waitForUser = false;
|
|
69484
|
+
const waitForUser = args.includes('--no-auto');
|
|
69275
69485
|
let waitBetweenPrompts = 0;
|
|
69276
|
-
|
|
69277
|
-
|
|
69278
|
-
|
|
69279
|
-
|
|
69280
|
-
|
|
69281
|
-
|
|
69282
|
-
waitBetweenPrompts = parseDuration(
|
|
69486
|
+
const hasWaitFlag = args.includes('--wait');
|
|
69487
|
+
const waitValue = readOptionValue(args, '--wait');
|
|
69488
|
+
if (hasWaitFlag) {
|
|
69489
|
+
if (waitValue === undefined || waitValue.startsWith('-')) {
|
|
69490
|
+
exitWithUsageError('Missing value for --wait. Use a duration like 1h, 30m, 5s.');
|
|
69491
|
+
}
|
|
69492
|
+
waitBetweenPrompts = parseDuration(waitValue);
|
|
69283
69493
|
}
|
|
69284
|
-
// --no-wait (or no flag): both waitForUser and waitBetweenPrompts remain false/0
|
|
69285
69494
|
let thinkingLevel;
|
|
69286
69495
|
if (hasTestCommandFlag && testCommand === undefined) {
|
|
69287
69496
|
exitWithUsageError('Missing value for --test. Use a shell command such as `npm run test` and quote it when it contains top-level CLI flags.');
|
|
@@ -69320,23 +69529,6 @@ function parseRunOptions(args) {
|
|
|
69320
69529
|
priority,
|
|
69321
69530
|
};
|
|
69322
69531
|
}
|
|
69323
|
-
/**
|
|
69324
|
-
* Reads an optional value for a flag that may appear with or without a following value.
|
|
69325
|
-
*
|
|
69326
|
-
* Returns `undefined` when the flag is absent, `null` when the flag is present but has no value
|
|
69327
|
-
* (the next token is another flag or the end of args), and the value string otherwise.
|
|
69328
|
-
*/
|
|
69329
|
-
function readOptionalOptionValue(args, flag) {
|
|
69330
|
-
if (!args.includes(flag)) {
|
|
69331
|
-
return undefined;
|
|
69332
|
-
}
|
|
69333
|
-
const index = args.indexOf(flag);
|
|
69334
|
-
const nextArg = args[index + 1];
|
|
69335
|
-
if (nextArg === undefined || nextArg.startsWith('-')) {
|
|
69336
|
-
return null;
|
|
69337
|
-
}
|
|
69338
|
-
return nextArg;
|
|
69339
|
-
}
|
|
69340
69532
|
/**
|
|
69341
69533
|
* Reads a value of a CLI option that follows a given flag.
|
|
69342
69534
|
*/
|
|
@@ -71313,7 +71505,13 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
71313
71505
|
const taskPrompt = buildCodexPrompt(nextPrompt.file, nextPrompt.section);
|
|
71314
71506
|
// Prepend agent system message before the task so the harness sees agent instructions first
|
|
71315
71507
|
const promptWithAgent = resolvedAgentSystemMessage
|
|
71316
|
-
?
|
|
71508
|
+
? spaceTrim$1((block) => `
|
|
71509
|
+
${block(resolvedAgentSystemMessage.trim())}
|
|
71510
|
+
|
|
71511
|
+
## Your Task
|
|
71512
|
+
|
|
71513
|
+
${block(taskPrompt)}
|
|
71514
|
+
`)
|
|
71317
71515
|
: taskPrompt;
|
|
71318
71516
|
const codexPrompt = appendCoderContext(promptWithAgent, resolvedCoderContext);
|
|
71319
71517
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
@@ -71382,11 +71580,11 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
71382
71580
|
*/
|
|
71383
71581
|
function setPromptRoundRunningState(options) {
|
|
71384
71582
|
const { isRichUiEnabled, promptLabel, scriptPath, uiHandle } = options;
|
|
71583
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
71584
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(scriptPath);
|
|
71585
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
71586
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
71385
71587
|
if (isRichUiEnabled) {
|
|
71386
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
71387
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(scriptPath);
|
|
71388
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
71389
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
71390
71588
|
return;
|
|
71391
71589
|
}
|
|
71392
71590
|
console.info(colors.blue(`Processing ${promptLabel}`));
|
|
@@ -71656,7 +71854,7 @@ function validateRunCodexPromptOptions(options) {
|
|
|
71656
71854
|
}
|
|
71657
71855
|
if (options.noCommit && !options.waitForUser && !options.ignoreGitChanges) {
|
|
71658
71856
|
throw new NotAllowed(spaceTrim$1(`
|
|
71659
|
-
Flag \`--no-commit\` requires \`--ignore-git-changes\` when
|
|
71857
|
+
Flag \`--no-commit\` requires \`--ignore-git-changes\` when running in auto mode (the default; pass \`--no-auto\` for interactive confirmation).
|
|
71660
71858
|
|
|
71661
71859
|
Without commits, the next prompt round would fail the clean working tree check.
|
|
71662
71860
|
`));
|
|
@@ -71688,7 +71886,11 @@ async function pullLatestChangesIfEnabled(options) {
|
|
|
71688
71886
|
function createRunDisplays(options, runStartDate) {
|
|
71689
71887
|
const isRichUiEnabled = !options.dryRun && !options.noUi && Boolean(process.stdout.isTTY);
|
|
71690
71888
|
const progressDisplay = options.dryRun || options.noUi || isRichUiEnabled ? undefined : new CliProgressDisplay(runStartDate, options.priority);
|
|
71691
|
-
const uiHandle = isRichUiEnabled
|
|
71889
|
+
const uiHandle = isRichUiEnabled || options.uiState
|
|
71890
|
+
? renderCoderRunUi(runStartDate, {
|
|
71891
|
+
state: options.uiState,
|
|
71892
|
+
})
|
|
71893
|
+
: undefined;
|
|
71692
71894
|
return {
|
|
71693
71895
|
isRichUiEnabled,
|
|
71694
71896
|
progressDisplay,
|
|
@@ -71753,6 +71955,7 @@ function initializeRunUi(uiHandle, runnerName, actualRunnerModel, options) {
|
|
|
71753
71955
|
modelName: actualRunnerModel,
|
|
71754
71956
|
thinkingLevel: options.thinkingLevel,
|
|
71755
71957
|
context: options.context,
|
|
71958
|
+
serverUrl: options.serverUrl,
|
|
71756
71959
|
priority: options.priority,
|
|
71757
71960
|
testCommand: options.testCommand,
|
|
71758
71961
|
});
|
|
@@ -71911,6 +72114,166 @@ var runCodexPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
71911
72114
|
runCodexPrompts: runCodexPrompts
|
|
71912
72115
|
});
|
|
71913
72116
|
|
|
72117
|
+
/**
|
|
72118
|
+
* Converts parsed prompt files into a web-board response with derived columns and tags.
|
|
72119
|
+
*/
|
|
72120
|
+
function buildCoderServerPromptFileResponses(options) {
|
|
72121
|
+
const activePrompt = getActivePrompt(options.uiState);
|
|
72122
|
+
return [
|
|
72123
|
+
...options.promptFiles.map((promptFile) => buildCoderServerPromptFileResponse({
|
|
72124
|
+
promptFile,
|
|
72125
|
+
isFinished: false,
|
|
72126
|
+
minimumPriority: options.minimumPriority,
|
|
72127
|
+
activePrompt,
|
|
72128
|
+
})),
|
|
72129
|
+
...options.finishedPromptFiles.map((promptFile) => buildCoderServerPromptFileResponse({
|
|
72130
|
+
promptFile,
|
|
72131
|
+
isFinished: true,
|
|
72132
|
+
minimumPriority: options.minimumPriority,
|
|
72133
|
+
activePrompt,
|
|
72134
|
+
})),
|
|
72135
|
+
];
|
|
72136
|
+
}
|
|
72137
|
+
/**
|
|
72138
|
+
* Builds one prompt-file response.
|
|
72139
|
+
*/
|
|
72140
|
+
function buildCoderServerPromptFileResponse(options) {
|
|
72141
|
+
const { promptFile, isFinished, minimumPriority, activePrompt } = options;
|
|
72142
|
+
return {
|
|
72143
|
+
filePath: promptFile.path,
|
|
72144
|
+
fileName: promptFile.name,
|
|
72145
|
+
relativeFilePath: relative(process.cwd(), promptFile.path).replace(/\\/gu, '/'),
|
|
72146
|
+
isFinished,
|
|
72147
|
+
sections: promptFile.sections.map((section) => buildCoderServerPromptSectionResponse({
|
|
72148
|
+
promptFile,
|
|
72149
|
+
section,
|
|
72150
|
+
isFinished,
|
|
72151
|
+
minimumPriority,
|
|
72152
|
+
activePrompt,
|
|
72153
|
+
})),
|
|
72154
|
+
};
|
|
72155
|
+
}
|
|
72156
|
+
/**
|
|
72157
|
+
* Builds one prompt-section response with derived board metadata.
|
|
72158
|
+
*/
|
|
72159
|
+
function buildCoderServerPromptSectionResponse(options) {
|
|
72160
|
+
const { promptFile, section, isFinished, minimumPriority, activePrompt } = options;
|
|
72161
|
+
const isUnwritten = isPromptToBeWritten(promptFile, section);
|
|
72162
|
+
const isActive = isPromptActive(promptFile, section, activePrompt);
|
|
72163
|
+
const column = getPromptColumn({
|
|
72164
|
+
section,
|
|
72165
|
+
isFinished,
|
|
72166
|
+
isUnwritten,
|
|
72167
|
+
isActive,
|
|
72168
|
+
minimumPriority,
|
|
72169
|
+
});
|
|
72170
|
+
return {
|
|
72171
|
+
index: section.index,
|
|
72172
|
+
status: section.status,
|
|
72173
|
+
column,
|
|
72174
|
+
priority: section.priority,
|
|
72175
|
+
summary: buildPromptSummary(promptFile, section),
|
|
72176
|
+
content: buildCodexPrompt(promptFile, section),
|
|
72177
|
+
label: buildPromptLabelForDisplay(promptFile, section),
|
|
72178
|
+
tags: buildPromptTags({
|
|
72179
|
+
section,
|
|
72180
|
+
isUnwritten,
|
|
72181
|
+
isActive,
|
|
72182
|
+
activePrompt,
|
|
72183
|
+
}),
|
|
72184
|
+
};
|
|
72185
|
+
}
|
|
72186
|
+
/**
|
|
72187
|
+
* Chooses the web-board column for one prompt section without changing persisted prompt status.
|
|
72188
|
+
*/
|
|
72189
|
+
function getPromptColumn(options) {
|
|
72190
|
+
const { section, isFinished, isUnwritten, isActive, minimumPriority } = options;
|
|
72191
|
+
if (isFinished) {
|
|
72192
|
+
return 'finished';
|
|
72193
|
+
}
|
|
72194
|
+
if (section.status === 'failed') {
|
|
72195
|
+
return 'errors';
|
|
72196
|
+
}
|
|
72197
|
+
if (section.status === 'done') {
|
|
72198
|
+
return 'done';
|
|
72199
|
+
}
|
|
72200
|
+
if (section.status === 'not-ready' || isUnwritten) {
|
|
72201
|
+
return 'backlog';
|
|
72202
|
+
}
|
|
72203
|
+
if (isActive) {
|
|
72204
|
+
return 'in-progress';
|
|
72205
|
+
}
|
|
72206
|
+
if (!hasSufficientPriority(section, minimumPriority)) {
|
|
72207
|
+
return 'low-priority';
|
|
72208
|
+
}
|
|
72209
|
+
return 'todo';
|
|
72210
|
+
}
|
|
72211
|
+
/**
|
|
72212
|
+
* Builds all tags shown on a prompt card.
|
|
72213
|
+
*/
|
|
72214
|
+
function buildPromptTags(options) {
|
|
72215
|
+
var _a;
|
|
72216
|
+
const tags = [];
|
|
72217
|
+
if (options.section.status === 'not-ready') {
|
|
72218
|
+
tags.push({ id: 'not-ready', label: '[-]' });
|
|
72219
|
+
}
|
|
72220
|
+
if (options.isUnwritten) {
|
|
72221
|
+
tags.push({ id: 'unwritten', label: '@@@' });
|
|
72222
|
+
}
|
|
72223
|
+
if (options.isActive) {
|
|
72224
|
+
tags.push(((_a = options.activePrompt) === null || _a === void 0 ? void 0 : _a.phase) === 'verifying'
|
|
72225
|
+
? { id: 'verifying', label: 'Verifying' }
|
|
72226
|
+
: { id: 'implementing', label: 'Implementing' });
|
|
72227
|
+
}
|
|
72228
|
+
return tags;
|
|
72229
|
+
}
|
|
72230
|
+
/**
|
|
72231
|
+
* Extracts an active prompt only while an agent is implementing or verifying it.
|
|
72232
|
+
*/
|
|
72233
|
+
function getActivePrompt(uiState) {
|
|
72234
|
+
if (!(uiState === null || uiState === void 0 ? void 0 : uiState.currentPromptLabel)) {
|
|
72235
|
+
return undefined;
|
|
72236
|
+
}
|
|
72237
|
+
if (uiState.phase !== 'running' && uiState.phase !== 'verifying') {
|
|
72238
|
+
return undefined;
|
|
72239
|
+
}
|
|
72240
|
+
return {
|
|
72241
|
+
label: uiState.currentPromptLabel,
|
|
72242
|
+
phase: uiState.phase,
|
|
72243
|
+
};
|
|
72244
|
+
}
|
|
72245
|
+
/**
|
|
72246
|
+
* Checks whether a parsed section is the prompt currently handled by the active agent.
|
|
72247
|
+
*/
|
|
72248
|
+
function isPromptActive(promptFile, section, activePrompt) {
|
|
72249
|
+
if (!activePrompt || section.status !== 'todo') {
|
|
72250
|
+
return false;
|
|
72251
|
+
}
|
|
72252
|
+
return buildPromptLabelForDisplay(promptFile, section) === activePrompt.label;
|
|
72253
|
+
}
|
|
72254
|
+
// Note: [🟡] Code for CLI command [coder server](scripts/run-codex-prompts/server/buildCoderServerPromptResponse.ts) should never be published outside of `@promptbook/cli`
|
|
72255
|
+
|
|
72256
|
+
/**
|
|
72257
|
+
* Builds a plain JSON-safe snapshot from the shared terminal UI state.
|
|
72258
|
+
*/
|
|
72259
|
+
function buildCoderServerRunState(uiState) {
|
|
72260
|
+
return {
|
|
72261
|
+
config: uiState.config,
|
|
72262
|
+
phase: uiState.phase,
|
|
72263
|
+
currentPromptLabel: uiState.currentPromptLabel,
|
|
72264
|
+
currentAttempt: uiState.currentAttempt,
|
|
72265
|
+
maxAttempts: uiState.maxAttempts,
|
|
72266
|
+
statusMessage: uiState.statusMessage,
|
|
72267
|
+
detailLines: [...uiState.detailLines],
|
|
72268
|
+
agentStatusLines: [...uiState.agentStatusLines],
|
|
72269
|
+
agentStatusTableRows: [...uiState.agentStatusTableRows],
|
|
72270
|
+
agentOutputLines: [...uiState.agentOutputLines],
|
|
72271
|
+
errors: [...uiState.errors],
|
|
72272
|
+
progress: uiState.getProgress(),
|
|
72273
|
+
};
|
|
72274
|
+
}
|
|
72275
|
+
// Note: [🟡] Code for CLI command [coder server](scripts/run-codex-prompts/server/buildCoderServerRunState.ts) should never be published outside of `@promptbook/cli`
|
|
72276
|
+
|
|
71914
72277
|
/**
|
|
71915
72278
|
* Overwrites the body of one prompt section with new content, preserving the status line.
|
|
71916
72279
|
*
|
|
@@ -71923,9 +72286,14 @@ async function updatePromptSection(filePath, sectionIndex, newContent) {
|
|
|
71923
72286
|
var _a;
|
|
71924
72287
|
const rawContent = await readFile(filePath, 'utf-8');
|
|
71925
72288
|
const promptFile = parsePromptFile(filePath, rawContent);
|
|
71926
|
-
const section = promptFile.sections.find((
|
|
72289
|
+
const section = promptFile.sections.find((sectionCandidate) => sectionCandidate.index === sectionIndex);
|
|
71927
72290
|
if (!section) {
|
|
71928
|
-
throw new
|
|
72291
|
+
throw new NotFoundError(spaceTrim$1(`
|
|
72292
|
+
Prompt section \`${sectionIndex}\` was not found.
|
|
72293
|
+
|
|
72294
|
+
File:
|
|
72295
|
+
\`${filePath}\`
|
|
72296
|
+
`));
|
|
71929
72297
|
}
|
|
71930
72298
|
// Lines before the status line (usually empty lines at section start)
|
|
71931
72299
|
const linesBeforeStatus = section.statusLineIndex !== undefined
|
|
@@ -71952,7 +72320,11 @@ async function updatePromptSection(filePath, sectionIndex, newContent) {
|
|
|
71952
72320
|
...promptFile.lines.slice(section.endLine + 1),
|
|
71953
72321
|
];
|
|
71954
72322
|
const updatedContent = updatedLines.join(promptFile.eol) + (promptFile.hasFinalEol ? promptFile.eol : '');
|
|
72323
|
+
if (updatedContent === rawContent) {
|
|
72324
|
+
return false;
|
|
72325
|
+
}
|
|
71955
72326
|
await writeFile(filePath, updatedContent, 'utf-8');
|
|
72327
|
+
return true;
|
|
71956
72328
|
}
|
|
71957
72329
|
// Note: [🟡] Code for CLI command [coder server](scripts/run-codex-prompts/server/updatePromptSection.ts) should never be published outside of `@promptbook/cli`
|
|
71958
72330
|
|
|
@@ -71973,38 +72345,37 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
71973
72345
|
<style>
|
|
71974
72346
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
71975
72347
|
body {
|
|
71976
|
-
font-family: -apple-system, BlinkMacSystemFont,
|
|
71977
|
-
background: #
|
|
71978
|
-
color: #
|
|
72348
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
72349
|
+
background: #f6f7f9;
|
|
72350
|
+
color: #1f2933;
|
|
71979
72351
|
min-height: 100vh;
|
|
71980
72352
|
}
|
|
71981
72353
|
|
|
71982
72354
|
header {
|
|
71983
|
-
background: #
|
|
72355
|
+
background: #22313f;
|
|
71984
72356
|
color: white;
|
|
71985
|
-
padding: 12px
|
|
72357
|
+
padding: 12px 18px;
|
|
71986
72358
|
display: flex;
|
|
71987
72359
|
align-items: center;
|
|
71988
72360
|
gap: 12px;
|
|
71989
72361
|
position: sticky;
|
|
71990
72362
|
top: 0;
|
|
71991
72363
|
z-index: 10;
|
|
71992
|
-
box-shadow: 0 2px
|
|
72364
|
+
box-shadow: 0 2px 10px rgba(15,23,42,0.22);
|
|
71993
72365
|
}
|
|
71994
|
-
header h1 { font-size: 17px; font-weight: 700; flex-shrink: 0; }
|
|
72366
|
+
header h1 { font-size: 17px; font-weight: 700; flex-shrink: 0; letter-spacing: 0; }
|
|
71995
72367
|
|
|
71996
72368
|
.status-badge {
|
|
71997
72369
|
padding: 3px 10px;
|
|
71998
|
-
border-radius:
|
|
72370
|
+
border-radius: 999px;
|
|
71999
72371
|
font-size: 11px;
|
|
72000
72372
|
font-weight: 700;
|
|
72001
|
-
letter-spacing: 0.5px;
|
|
72002
72373
|
text-transform: uppercase;
|
|
72003
72374
|
flex-shrink: 0;
|
|
72004
72375
|
}
|
|
72005
|
-
.status-RUNNING
|
|
72006
|
-
.status-PAUSING
|
|
72007
|
-
.status-PAUSED
|
|
72376
|
+
.status-RUNNING { background: #0b875b; color: white; }
|
|
72377
|
+
.status-PAUSING { background: #d97904; color: white; }
|
|
72378
|
+
.status-PAUSED { background: #b42318; color: white; }
|
|
72008
72379
|
|
|
72009
72380
|
#pause-label {
|
|
72010
72381
|
font-size: 12px;
|
|
@@ -72017,57 +72388,122 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72017
72388
|
}
|
|
72018
72389
|
|
|
72019
72390
|
.btn {
|
|
72020
|
-
padding: 6px
|
|
72021
|
-
border:
|
|
72391
|
+
padding: 6px 12px;
|
|
72392
|
+
border: 0;
|
|
72022
72393
|
border-radius: 4px;
|
|
72023
72394
|
cursor: pointer;
|
|
72024
72395
|
font-size: 13px;
|
|
72025
|
-
font-weight:
|
|
72026
|
-
transition: opacity 0.15s;
|
|
72396
|
+
font-weight: 700;
|
|
72397
|
+
transition: background 0.15s, opacity 0.15s;
|
|
72027
72398
|
flex-shrink: 0;
|
|
72028
72399
|
}
|
|
72029
|
-
.btn:
|
|
72030
|
-
.btn-pause
|
|
72031
|
-
.btn-resume { background: #
|
|
72400
|
+
.btn:disabled { opacity: 0.55; cursor: default; }
|
|
72401
|
+
.btn-pause { background: #ffd166; color: #1f2933; }
|
|
72402
|
+
.btn-resume { background: #0b875b; color: white; }
|
|
72403
|
+
.btn-save { background: #2563eb; color: white; }
|
|
72404
|
+
.btn-cancel { background: #edf0f4; color: #1f2933; }
|
|
72405
|
+
|
|
72406
|
+
.run-strip {
|
|
72407
|
+
background: white;
|
|
72408
|
+
border-bottom: 1px solid #d8dee8;
|
|
72409
|
+
padding: 12px 18px;
|
|
72410
|
+
display: grid;
|
|
72411
|
+
grid-template-columns: minmax(220px, 1.2fr) minmax(240px, 1fr) minmax(260px, 1.4fr);
|
|
72412
|
+
gap: 14px;
|
|
72413
|
+
align-items: center;
|
|
72414
|
+
}
|
|
72415
|
+
.run-title {
|
|
72416
|
+
font-size: 14px;
|
|
72417
|
+
font-weight: 700;
|
|
72418
|
+
overflow: hidden;
|
|
72419
|
+
text-overflow: ellipsis;
|
|
72420
|
+
white-space: nowrap;
|
|
72421
|
+
}
|
|
72422
|
+
.run-subtitle,
|
|
72423
|
+
.run-current,
|
|
72424
|
+
.run-output {
|
|
72425
|
+
color: #64748b;
|
|
72426
|
+
font-size: 12px;
|
|
72427
|
+
line-height: 1.45;
|
|
72428
|
+
overflow: hidden;
|
|
72429
|
+
}
|
|
72430
|
+
.run-current,
|
|
72431
|
+
.run-output {
|
|
72432
|
+
display: -webkit-box;
|
|
72433
|
+
-webkit-box-orient: vertical;
|
|
72434
|
+
-webkit-line-clamp: 2;
|
|
72435
|
+
}
|
|
72436
|
+
.progress-shell {
|
|
72437
|
+
display: grid;
|
|
72438
|
+
grid-template-columns: 1fr auto;
|
|
72439
|
+
gap: 8px;
|
|
72440
|
+
align-items: center;
|
|
72441
|
+
}
|
|
72442
|
+
.progress-track {
|
|
72443
|
+
height: 10px;
|
|
72444
|
+
background: #e4e9f0;
|
|
72445
|
+
border-radius: 999px;
|
|
72446
|
+
overflow: hidden;
|
|
72447
|
+
}
|
|
72448
|
+
.progress-fill {
|
|
72449
|
+
display: block;
|
|
72450
|
+
height: 100%;
|
|
72451
|
+
width: 0;
|
|
72452
|
+
background: linear-gradient(90deg, #0b875b, #2563eb);
|
|
72453
|
+
transition: width 0.2s;
|
|
72454
|
+
}
|
|
72455
|
+
.progress-label {
|
|
72456
|
+
color: #475569;
|
|
72457
|
+
font-size: 12px;
|
|
72458
|
+
font-weight: 700;
|
|
72459
|
+
min-width: 72px;
|
|
72460
|
+
text-align: right;
|
|
72461
|
+
}
|
|
72032
72462
|
|
|
72033
72463
|
.board {
|
|
72034
72464
|
display: flex;
|
|
72035
72465
|
gap: 14px;
|
|
72036
72466
|
padding: 16px;
|
|
72037
72467
|
overflow-x: auto;
|
|
72038
|
-
min-height: calc(100vh -
|
|
72468
|
+
min-height: calc(100vh - 119px);
|
|
72039
72469
|
align-items: flex-start;
|
|
72040
72470
|
}
|
|
72041
72471
|
|
|
72042
72472
|
.column {
|
|
72043
|
-
background: #
|
|
72044
|
-
border-
|
|
72473
|
+
background: #e9edf3;
|
|
72474
|
+
border-top: 4px solid #94a3b8;
|
|
72475
|
+
border-radius: 6px;
|
|
72045
72476
|
padding: 10px;
|
|
72046
72477
|
min-width: 250px;
|
|
72047
72478
|
width: 270px;
|
|
72048
72479
|
flex-shrink: 0;
|
|
72049
72480
|
}
|
|
72481
|
+
.column-backlog { border-top-color: #64748b; }
|
|
72482
|
+
.column-low-priority { border-top-color: #d97904; }
|
|
72483
|
+
.column-todo { border-top-color: #2563eb; }
|
|
72484
|
+
.column-in-progress { border-top-color: #7c3aed; }
|
|
72485
|
+
.column-done { border-top-color: #0b875b; }
|
|
72486
|
+
.column-errors { border-top-color: #b42318; }
|
|
72487
|
+
.column-finished { border-top-color: #0891b2; }
|
|
72050
72488
|
|
|
72051
72489
|
.column-header {
|
|
72052
72490
|
font-size: 12px;
|
|
72053
|
-
font-weight:
|
|
72491
|
+
font-weight: 800;
|
|
72054
72492
|
text-transform: uppercase;
|
|
72055
|
-
|
|
72056
|
-
color: #5e6c84;
|
|
72493
|
+
color: #475569;
|
|
72057
72494
|
margin-bottom: 10px;
|
|
72058
72495
|
display: flex;
|
|
72059
72496
|
align-items: center;
|
|
72060
72497
|
justify-content: space-between;
|
|
72498
|
+
gap: 8px;
|
|
72061
72499
|
}
|
|
72062
|
-
|
|
72063
72500
|
.column-count {
|
|
72064
|
-
background:
|
|
72065
|
-
border-radius:
|
|
72066
|
-
padding:
|
|
72501
|
+
background: rgba(255,255,255,0.72);
|
|
72502
|
+
border-radius: 999px;
|
|
72503
|
+
padding: 2px 8px;
|
|
72067
72504
|
font-size: 11px;
|
|
72068
|
-
color: #
|
|
72505
|
+
color: #475569;
|
|
72069
72506
|
}
|
|
72070
|
-
|
|
72071
72507
|
.column-cards { min-height: 40px; }
|
|
72072
72508
|
|
|
72073
72509
|
.card {
|
|
@@ -72075,57 +72511,61 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72075
72511
|
border-radius: 6px;
|
|
72076
72512
|
padding: 10px 12px;
|
|
72077
72513
|
margin-bottom: 8px;
|
|
72078
|
-
box-shadow: 0 1px 3px rgba(
|
|
72514
|
+
box-shadow: 0 1px 3px rgba(15,23,42,0.12);
|
|
72079
72515
|
cursor: pointer;
|
|
72080
|
-
|
|
72081
|
-
border-left: 3px solid transparent;
|
|
72516
|
+
border-left: 3px solid #94a3b8;
|
|
72082
72517
|
}
|
|
72083
|
-
.card:hover {
|
|
72084
|
-
|
|
72085
|
-
|
|
72086
|
-
}
|
|
72087
|
-
.card-
|
|
72088
|
-
.card-
|
|
72089
|
-
.card-
|
|
72090
|
-
.card-
|
|
72518
|
+
.card:hover { box-shadow: 0 4px 12px rgba(15,23,42,0.16); }
|
|
72519
|
+
.card-backlog { border-left-color: #64748b; }
|
|
72520
|
+
.card-low-priority { border-left-color: #d97904; }
|
|
72521
|
+
.card-todo { border-left-color: #2563eb; }
|
|
72522
|
+
.card-in-progress { border-left-color: #7c3aed; }
|
|
72523
|
+
.card-done { border-left-color: #0b875b; }
|
|
72524
|
+
.card-errors { border-left-color: #b42318; }
|
|
72525
|
+
.card-finished { border-left-color: #0891b2; }
|
|
72091
72526
|
|
|
72092
72527
|
.card-file {
|
|
72093
72528
|
font-size: 10px;
|
|
72094
|
-
color: #
|
|
72095
|
-
margin-bottom:
|
|
72096
|
-
font-weight:
|
|
72529
|
+
color: #7b8794;
|
|
72530
|
+
margin-bottom: 6px;
|
|
72531
|
+
font-weight: 600;
|
|
72532
|
+
overflow: hidden;
|
|
72533
|
+
text-overflow: ellipsis;
|
|
72534
|
+
white-space: nowrap;
|
|
72097
72535
|
}
|
|
72098
|
-
|
|
72099
72536
|
.card-summary {
|
|
72100
72537
|
font-size: 13px;
|
|
72101
|
-
line-height: 1.
|
|
72102
|
-
color: #
|
|
72538
|
+
line-height: 1.45;
|
|
72539
|
+
color: #1f2933;
|
|
72103
72540
|
word-break: break-word;
|
|
72104
72541
|
white-space: pre-wrap;
|
|
72105
|
-
max-height:
|
|
72542
|
+
max-height: 76px;
|
|
72106
72543
|
overflow: hidden;
|
|
72107
72544
|
display: -webkit-box;
|
|
72108
72545
|
-webkit-line-clamp: 4;
|
|
72109
72546
|
-webkit-box-orient: vertical;
|
|
72110
72547
|
}
|
|
72111
|
-
|
|
72112
|
-
|
|
72113
|
-
|
|
72114
|
-
|
|
72115
|
-
|
|
72116
|
-
font-weight: 700;
|
|
72548
|
+
.card-tags {
|
|
72549
|
+
display: flex;
|
|
72550
|
+
flex-wrap: wrap;
|
|
72551
|
+
gap: 5px;
|
|
72552
|
+
margin-top: 8px;
|
|
72117
72553
|
}
|
|
72118
|
-
|
|
72119
|
-
|
|
72554
|
+
.card-tag {
|
|
72555
|
+
border-radius: 999px;
|
|
72556
|
+
padding: 2px 7px;
|
|
72120
72557
|
font-size: 10px;
|
|
72121
|
-
|
|
72122
|
-
|
|
72123
|
-
display: none;
|
|
72558
|
+
font-weight: 800;
|
|
72559
|
+
line-height: 1.35;
|
|
72124
72560
|
}
|
|
72125
|
-
.
|
|
72561
|
+
.tag-not-ready { background: #e2e8f0; color: #475569; }
|
|
72562
|
+
.tag-unwritten { background: #fff4cc; color: #8a5a00; }
|
|
72563
|
+
.tag-implementing { background: #ede9fe; color: #5b21b6; }
|
|
72564
|
+
.tag-verifying { background: #fae8ff; color: #86198f; }
|
|
72565
|
+
.tag-priority { background: #ffedd5; color: #9a3412; }
|
|
72126
72566
|
|
|
72127
72567
|
.empty-column {
|
|
72128
|
-
color: #
|
|
72568
|
+
color: #94a3b8;
|
|
72129
72569
|
font-size: 12px;
|
|
72130
72570
|
padding: 10px 4px;
|
|
72131
72571
|
text-align: center;
|
|
@@ -72134,29 +72574,23 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72134
72574
|
.modal-overlay {
|
|
72135
72575
|
position: fixed;
|
|
72136
72576
|
inset: 0;
|
|
72137
|
-
background: rgba(
|
|
72577
|
+
background: rgba(15,23,42,0.58);
|
|
72138
72578
|
display: flex;
|
|
72139
72579
|
align-items: flex-start;
|
|
72140
72580
|
justify-content: center;
|
|
72141
|
-
padding:
|
|
72581
|
+
padding: 56px 16px 16px;
|
|
72142
72582
|
z-index: 100;
|
|
72143
|
-
animation: fadeIn 0.1s ease;
|
|
72144
72583
|
}
|
|
72145
72584
|
.modal-overlay.hidden { display: none; }
|
|
72146
72585
|
|
|
72147
|
-
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
|
72148
|
-
|
|
72149
72586
|
.modal {
|
|
72150
72587
|
background: white;
|
|
72151
72588
|
border-radius: 8px;
|
|
72152
72589
|
width: 100%;
|
|
72153
|
-
max-width:
|
|
72154
|
-
padding:
|
|
72155
|
-
box-shadow: 0
|
|
72156
|
-
animation: slideIn 0.15s ease;
|
|
72590
|
+
max-width: 720px;
|
|
72591
|
+
padding: 18px;
|
|
72592
|
+
box-shadow: 0 14px 40px rgba(15,23,42,0.28);
|
|
72157
72593
|
}
|
|
72158
|
-
@keyframes slideIn { from { transform: translateY(-8px); opacity: 0; } to { transform: none; opacity: 1; } }
|
|
72159
|
-
|
|
72160
72594
|
.modal-header {
|
|
72161
72595
|
display: flex;
|
|
72162
72596
|
align-items: flex-start;
|
|
@@ -72164,62 +72598,59 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72164
72598
|
margin-bottom: 14px;
|
|
72165
72599
|
gap: 12px;
|
|
72166
72600
|
}
|
|
72167
|
-
|
|
72168
72601
|
.modal-meta { flex: 1; min-width: 0; }
|
|
72169
|
-
.modal-file {
|
|
72170
|
-
|
|
72171
|
-
|
|
72602
|
+
.modal-file {
|
|
72603
|
+
font-size: 11px;
|
|
72604
|
+
color: #7b8794;
|
|
72605
|
+
margin-bottom: 4px;
|
|
72606
|
+
overflow: hidden;
|
|
72607
|
+
text-overflow: ellipsis;
|
|
72608
|
+
white-space: nowrap;
|
|
72609
|
+
}
|
|
72610
|
+
.modal-section-label { font-size: 14px; font-weight: 700; color: #1f2933; }
|
|
72172
72611
|
.modal-status {
|
|
72173
72612
|
font-size: 11px;
|
|
72174
|
-
font-weight:
|
|
72175
|
-
padding:
|
|
72176
|
-
border-radius:
|
|
72613
|
+
font-weight: 800;
|
|
72614
|
+
padding: 3px 8px;
|
|
72615
|
+
border-radius: 999px;
|
|
72177
72616
|
text-transform: uppercase;
|
|
72178
|
-
letter-spacing: 0.4px;
|
|
72179
72617
|
flex-shrink: 0;
|
|
72180
72618
|
}
|
|
72181
|
-
.status-
|
|
72182
|
-
.status-
|
|
72183
|
-
.status-
|
|
72184
|
-
.status-
|
|
72185
|
-
|
|
72619
|
+
.status-backlog { background: #e2e8f0; color: #475569; }
|
|
72620
|
+
.status-low-priority { background: #ffedd5; color: #9a3412; }
|
|
72621
|
+
.status-todo { background: #dbeafe; color: #1d4ed8; }
|
|
72622
|
+
.status-in-progress { background: #ede9fe; color: #5b21b6; }
|
|
72623
|
+
.status-done { background: #dcfce7; color: #166534; }
|
|
72624
|
+
.status-errors { background: #fee2e2; color: #991b1b; }
|
|
72625
|
+
.status-finished { background: #cffafe; color: #155e75; }
|
|
72186
72626
|
.modal-close {
|
|
72187
|
-
background:
|
|
72188
|
-
border:
|
|
72189
|
-
color: #
|
|
72627
|
+
background: transparent;
|
|
72628
|
+
border: 0;
|
|
72629
|
+
color: #64748b;
|
|
72190
72630
|
cursor: pointer;
|
|
72191
|
-
font-size:
|
|
72631
|
+
font-size: 20px;
|
|
72192
72632
|
padding: 0 4px;
|
|
72193
72633
|
line-height: 1;
|
|
72194
|
-
flex-shrink: 0;
|
|
72195
72634
|
}
|
|
72196
|
-
.modal-close:hover { color: #
|
|
72635
|
+
.modal-close:hover { color: #1f2933; }
|
|
72197
72636
|
|
|
72198
72637
|
textarea {
|
|
72199
72638
|
width: 100%;
|
|
72200
|
-
min-height:
|
|
72201
|
-
font-family:
|
|
72639
|
+
min-height: 300px;
|
|
72640
|
+
font-family: "SFMono-Regular", Consolas, "Courier New", monospace;
|
|
72202
72641
|
font-size: 13px;
|
|
72203
|
-
border: 2px solid #
|
|
72642
|
+
border: 2px solid #d8dee8;
|
|
72204
72643
|
border-radius: 4px;
|
|
72205
72644
|
padding: 10px 12px;
|
|
72206
72645
|
resize: vertical;
|
|
72207
|
-
line-height: 1.
|
|
72208
|
-
color: #
|
|
72209
|
-
transition: border-color 0.15s;
|
|
72646
|
+
line-height: 1.6;
|
|
72647
|
+
color: #1f2933;
|
|
72210
72648
|
}
|
|
72211
72649
|
textarea:focus {
|
|
72212
72650
|
outline: none;
|
|
72213
|
-
border-color: #
|
|
72214
|
-
box-shadow: 0 0 0 3px rgba(
|
|
72215
|
-
}
|
|
72216
|
-
|
|
72217
|
-
.modal-hint {
|
|
72218
|
-
font-size: 11px;
|
|
72219
|
-
color: #8993a4;
|
|
72220
|
-
margin-top: 6px;
|
|
72651
|
+
border-color: #2563eb;
|
|
72652
|
+
box-shadow: 0 0 0 3px rgba(37,99,235,0.12);
|
|
72221
72653
|
}
|
|
72222
|
-
|
|
72223
72654
|
.modal-actions {
|
|
72224
72655
|
display: flex;
|
|
72225
72656
|
gap: 8px;
|
|
@@ -72227,67 +72658,50 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72227
72658
|
justify-content: flex-end;
|
|
72228
72659
|
}
|
|
72229
72660
|
|
|
72230
|
-
.btn-save { background: #0052cc; color: white; }
|
|
72231
|
-
.btn-cancel { background: #f4f5f7; color: #172b4d; }
|
|
72232
|
-
.btn-cancel:hover { background: #ebecf0; opacity: 1; }
|
|
72233
|
-
|
|
72234
72661
|
.error-banner {
|
|
72235
|
-
background: #
|
|
72236
|
-
border-bottom: 2px solid #
|
|
72237
|
-
color: #
|
|
72238
|
-
padding: 8px
|
|
72662
|
+
background: #fee2e2;
|
|
72663
|
+
border-bottom: 2px solid #b42318;
|
|
72664
|
+
color: #991b1b;
|
|
72665
|
+
padding: 8px 18px;
|
|
72239
72666
|
font-size: 13px;
|
|
72240
|
-
font-weight:
|
|
72667
|
+
font-weight: 700;
|
|
72241
72668
|
}
|
|
72242
72669
|
.error-banner.hidden { display: none; }
|
|
72670
|
+
|
|
72671
|
+
@media (max-width: 860px) {
|
|
72672
|
+
header { flex-wrap: wrap; }
|
|
72673
|
+
#pause-label { order: 4; flex-basis: 100%; }
|
|
72674
|
+
.run-strip { grid-template-columns: 1fr; }
|
|
72675
|
+
.board { min-height: calc(100vh - 212px); }
|
|
72676
|
+
}
|
|
72243
72677
|
</style>
|
|
72244
72678
|
</head>
|
|
72245
72679
|
<body>
|
|
72246
|
-
|
|
72247
72680
|
<div id="error-banner" class="error-banner hidden"></div>
|
|
72248
72681
|
|
|
72249
72682
|
<header>
|
|
72250
|
-
<h1
|
|
72683
|
+
<h1>Ptbk Coder Server</h1>
|
|
72251
72684
|
<span id="status-badge" class="status-badge status-RUNNING">RUNNING</span>
|
|
72252
72685
|
<span id="pause-label"></span>
|
|
72253
|
-
<button id="toggle-btn" class="btn btn-pause"
|
|
72686
|
+
<button id="toggle-btn" class="btn btn-pause">Pause</button>
|
|
72254
72687
|
</header>
|
|
72255
72688
|
|
|
72256
|
-
<
|
|
72257
|
-
<div
|
|
72258
|
-
<div class="
|
|
72259
|
-
|
|
72260
|
-
<span class="column-count" id="count-todo">0</span>
|
|
72261
|
-
</div>
|
|
72262
|
-
<div class="column-cards" id="cards-todo">
|
|
72263
|
-
<div class="empty-column">Loading…</div>
|
|
72264
|
-
</div>
|
|
72689
|
+
<section class="run-strip">
|
|
72690
|
+
<div>
|
|
72691
|
+
<div class="run-title" id="run-title">Initializing...</div>
|
|
72692
|
+
<div class="run-subtitle" id="run-subtitle">Loading runner state</div>
|
|
72265
72693
|
</div>
|
|
72266
|
-
|
|
72267
|
-
|
|
72268
|
-
<div class="
|
|
72269
|
-
Not Ready
|
|
72270
|
-
<span class="column-count" id="count-not-ready">0</span>
|
|
72271
|
-
</div>
|
|
72272
|
-
<div class="column-cards" id="cards-not-ready"></div>
|
|
72694
|
+
<div class="progress-shell">
|
|
72695
|
+
<div class="progress-track"><span class="progress-fill" id="progress-fill"></span></div>
|
|
72696
|
+
<div class="progress-label" id="progress-label">0%</div>
|
|
72273
72697
|
</div>
|
|
72274
|
-
|
|
72275
|
-
|
|
72276
|
-
<div class="
|
|
72277
|
-
Done
|
|
72278
|
-
<span class="column-count" id="count-done">0</span>
|
|
72279
|
-
</div>
|
|
72280
|
-
<div class="column-cards" id="cards-done"></div>
|
|
72698
|
+
<div>
|
|
72699
|
+
<div class="run-current" id="run-current">No active prompt</div>
|
|
72700
|
+
<div class="run-output" id="run-output"></div>
|
|
72281
72701
|
</div>
|
|
72702
|
+
</section>
|
|
72282
72703
|
|
|
72283
|
-
|
|
72284
|
-
<div class="column-header">
|
|
72285
|
-
Failed
|
|
72286
|
-
<span class="column-count" id="count-failed">0</span>
|
|
72287
|
-
</div>
|
|
72288
|
-
<div class="column-cards" id="cards-failed"></div>
|
|
72289
|
-
</div>
|
|
72290
|
-
</div>
|
|
72704
|
+
<div class="board" id="board"></div>
|
|
72291
72705
|
|
|
72292
72706
|
<div class="modal-overlay hidden" id="modal-overlay">
|
|
72293
72707
|
<div class="modal">
|
|
@@ -72297,196 +72711,317 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72297
72711
|
<div class="modal-section-label" id="modal-section-label"></div>
|
|
72298
72712
|
</div>
|
|
72299
72713
|
<span class="modal-status" id="modal-status-badge"></span>
|
|
72300
|
-
<button class="modal-close"
|
|
72714
|
+
<button class="modal-close" id="modal-close" title="Close">×</button>
|
|
72301
72715
|
</div>
|
|
72302
72716
|
|
|
72303
|
-
<textarea id="modal-content" placeholder="Prompt content
|
|
72304
|
-
<div class="modal-hint">Tip: press Ctrl+Enter to save, Esc to cancel.</div>
|
|
72717
|
+
<textarea id="modal-content" placeholder="Prompt content"></textarea>
|
|
72305
72718
|
|
|
72306
72719
|
<div class="modal-actions">
|
|
72307
|
-
<button class="btn btn-cancel"
|
|
72308
|
-
<button class="btn btn-save"
|
|
72720
|
+
<button class="btn btn-cancel" id="cancel-button">Cancel</button>
|
|
72721
|
+
<button class="btn btn-save" id="save-button">Save</button>
|
|
72309
72722
|
</div>
|
|
72310
72723
|
</div>
|
|
72311
72724
|
</div>
|
|
72312
72725
|
|
|
72313
72726
|
<script>
|
|
72314
|
-
|
|
72727
|
+
"use strict";
|
|
72728
|
+
|
|
72729
|
+
const BOARD_COLUMNS = [
|
|
72730
|
+
{ id: "backlog", title: "Backlog" },
|
|
72731
|
+
{ id: "low-priority", title: "Low priority" },
|
|
72732
|
+
{ id: "todo", title: "To do" },
|
|
72733
|
+
{ id: "in-progress", title: "In progress" },
|
|
72734
|
+
{ id: "done", title: "Done" },
|
|
72735
|
+
{ id: "errors", title: "Errors" },
|
|
72736
|
+
{ id: "finished", title: "Finished" },
|
|
72737
|
+
];
|
|
72315
72738
|
|
|
72316
72739
|
let modalState = null;
|
|
72317
|
-
let lastPauseState =
|
|
72318
|
-
|
|
72319
|
-
function
|
|
72320
|
-
const
|
|
72321
|
-
|
|
72322
|
-
|
|
72323
|
-
|
|
72324
|
-
|
|
72325
|
-
|
|
72326
|
-
|
|
72327
|
-
|
|
72328
|
-
|
|
72329
|
-
|
|
72330
|
-
|
|
72740
|
+
let lastPauseState = "RUNNING";
|
|
72741
|
+
|
|
72742
|
+
function getColumnTitle(columnId) {
|
|
72743
|
+
const column = BOARD_COLUMNS.find((columnCandidate) => columnCandidate.id === columnId);
|
|
72744
|
+
return column ? column.title : columnId;
|
|
72745
|
+
}
|
|
72746
|
+
|
|
72747
|
+
function showError(message) {
|
|
72748
|
+
const banner = document.getElementById("error-banner");
|
|
72749
|
+
banner.textContent = message;
|
|
72750
|
+
banner.classList.remove("hidden");
|
|
72751
|
+
clearTimeout(banner.timer);
|
|
72752
|
+
banner.timer = setTimeout(() => banner.classList.add("hidden"), 6000);
|
|
72753
|
+
}
|
|
72754
|
+
|
|
72755
|
+
function escapeHtml(value) {
|
|
72756
|
+
const element = document.createElement("div");
|
|
72757
|
+
element.textContent = String(value);
|
|
72758
|
+
return element.innerHTML;
|
|
72759
|
+
}
|
|
72760
|
+
|
|
72761
|
+
function renderBoardSkeleton() {
|
|
72762
|
+
const board = document.getElementById("board");
|
|
72763
|
+
board.innerHTML = "";
|
|
72764
|
+
|
|
72765
|
+
for (const column of BOARD_COLUMNS) {
|
|
72766
|
+
const columnElement = document.createElement("section");
|
|
72767
|
+
columnElement.className = "column column-" + column.id;
|
|
72768
|
+
columnElement.innerHTML =
|
|
72769
|
+
'<div class="column-header">' +
|
|
72770
|
+
'<span>' + escapeHtml(column.title) + '</span>' +
|
|
72771
|
+
'<span class="column-count" id="count-' + column.id + '">0</span>' +
|
|
72772
|
+
'</div>' +
|
|
72773
|
+
'<div class="column-cards" id="cards-' + column.id + '">' +
|
|
72774
|
+
'<div class="empty-column">Loading</div>' +
|
|
72775
|
+
'</div>';
|
|
72776
|
+
board.appendChild(columnElement);
|
|
72777
|
+
}
|
|
72331
72778
|
}
|
|
72332
72779
|
|
|
72333
72780
|
async function fetchStatus() {
|
|
72334
72781
|
try {
|
|
72335
|
-
const
|
|
72336
|
-
if (!
|
|
72337
|
-
|
|
72338
|
-
|
|
72339
|
-
lastPauseState = data.pauseState;
|
|
72340
|
-
|
|
72341
|
-
const badge = document.getElementById('status-badge');
|
|
72342
|
-
badge.textContent = data.pauseState;
|
|
72343
|
-
badge.className = 'status-badge status-' + data.pauseState;
|
|
72344
|
-
|
|
72345
|
-
const btn = document.getElementById('toggle-btn');
|
|
72346
|
-
const label = document.getElementById('pause-label');
|
|
72347
|
-
|
|
72348
|
-
if (data.pauseState === 'RUNNING') {
|
|
72349
|
-
btn.textContent = '\\u23f8 Pause';
|
|
72350
|
-
btn.className = 'btn btn-pause';
|
|
72351
|
-
label.textContent = '';
|
|
72352
|
-
} else if (data.pauseState === 'PAUSING') {
|
|
72353
|
-
btn.textContent = '\\u23f5 Resume';
|
|
72354
|
-
btn.className = 'btn btn-resume';
|
|
72355
|
-
label.textContent = 'Pausing before: ' + (data.pauseTargetLabel || '\\u2026');
|
|
72356
|
-
} else {
|
|
72357
|
-
btn.textContent = '\\u23f5 Resume';
|
|
72358
|
-
btn.className = 'btn btn-resume';
|
|
72359
|
-
label.textContent = 'Paused before: ' + (data.pauseTargetLabel || '\\u2026');
|
|
72782
|
+
const response = await fetch("/api/status");
|
|
72783
|
+
if (!response.ok) {
|
|
72784
|
+
showError("Status API error: " + response.status);
|
|
72785
|
+
return;
|
|
72360
72786
|
}
|
|
72361
|
-
|
|
72362
|
-
|
|
72787
|
+
|
|
72788
|
+
const status = await response.json();
|
|
72789
|
+
renderPauseState(status);
|
|
72790
|
+
renderRunState(status.runState);
|
|
72791
|
+
} catch (error) {
|
|
72792
|
+
showError("Could not reach coder server: " + error.message);
|
|
72793
|
+
}
|
|
72794
|
+
}
|
|
72795
|
+
|
|
72796
|
+
function renderPauseState(status) {
|
|
72797
|
+
lastPauseState = status.pauseState;
|
|
72798
|
+
|
|
72799
|
+
const badge = document.getElementById("status-badge");
|
|
72800
|
+
badge.textContent = status.pauseState;
|
|
72801
|
+
badge.className = "status-badge status-" + status.pauseState;
|
|
72802
|
+
|
|
72803
|
+
const toggleButton = document.getElementById("toggle-btn");
|
|
72804
|
+
const pauseLabel = document.getElementById("pause-label");
|
|
72805
|
+
|
|
72806
|
+
if (status.pauseState === "RUNNING") {
|
|
72807
|
+
toggleButton.textContent = "Pause";
|
|
72808
|
+
toggleButton.className = "btn btn-pause";
|
|
72809
|
+
pauseLabel.textContent = "";
|
|
72810
|
+
return;
|
|
72811
|
+
}
|
|
72812
|
+
|
|
72813
|
+
toggleButton.textContent = "Resume";
|
|
72814
|
+
toggleButton.className = "btn btn-resume";
|
|
72815
|
+
pauseLabel.textContent =
|
|
72816
|
+
(status.pauseState === "PAUSING" ? "Pausing before: " : "Paused before: ") +
|
|
72817
|
+
(status.pauseTargetLabel || "next checkpoint");
|
|
72818
|
+
}
|
|
72819
|
+
|
|
72820
|
+
function renderRunState(runState) {
|
|
72821
|
+
if (!runState) {
|
|
72822
|
+
document.getElementById("run-title").textContent = "Waiting for runner state";
|
|
72823
|
+
document.getElementById("run-subtitle").textContent = "";
|
|
72824
|
+
return;
|
|
72363
72825
|
}
|
|
72826
|
+
|
|
72827
|
+
const progress = runState.progress || {};
|
|
72828
|
+
const percentage = Number(progress.percentage || 0);
|
|
72829
|
+
const runnerParts = [runState.config.agentName, runState.config.modelName, runState.config.thinkingLevel]
|
|
72830
|
+
.filter(Boolean);
|
|
72831
|
+
|
|
72832
|
+
document.getElementById("run-title").textContent = runState.statusMessage || runState.phase;
|
|
72833
|
+
document.getElementById("run-subtitle").textContent = runnerParts.join(" / ");
|
|
72834
|
+
document.getElementById("progress-fill").style.width = Math.max(0, Math.min(100, percentage)) + "%";
|
|
72835
|
+
document.getElementById("progress-label").textContent =
|
|
72836
|
+
percentage + "% " + (progress.sessionDone || 0) + "/" + (progress.sessionTotal || 0);
|
|
72837
|
+
document.getElementById("run-current").textContent = runState.currentPromptLabel
|
|
72838
|
+
? runState.currentPromptLabel + " - attempt " + runState.currentAttempt + "/" + runState.maxAttempts
|
|
72839
|
+
: "No active prompt";
|
|
72840
|
+
|
|
72841
|
+
renderRunOutput(runState);
|
|
72842
|
+
}
|
|
72843
|
+
|
|
72844
|
+
function renderRunOutput(runState) {
|
|
72845
|
+
const statusLines = (runState.agentStatusTableRows || []).map((row) =>
|
|
72846
|
+
row.status + " - " + row.agentName + (row.url ? " - " + row.url : "")
|
|
72847
|
+
);
|
|
72848
|
+
const outputLines = [
|
|
72849
|
+
...(runState.agentStatusLines || []),
|
|
72850
|
+
...statusLines,
|
|
72851
|
+
...(runState.agentOutputLines || []),
|
|
72852
|
+
...(runState.errors || []).map((errorLine) => "Error: " + errorLine),
|
|
72853
|
+
].slice(-3);
|
|
72854
|
+
|
|
72855
|
+
document.getElementById("run-output").textContent = outputLines.join("\\n");
|
|
72364
72856
|
}
|
|
72365
72857
|
|
|
72366
72858
|
async function fetchPrompts() {
|
|
72367
72859
|
try {
|
|
72368
|
-
const
|
|
72369
|
-
if (!
|
|
72370
|
-
|
|
72371
|
-
|
|
72372
|
-
|
|
72860
|
+
const response = await fetch("/api/prompts");
|
|
72861
|
+
if (!response.ok) {
|
|
72862
|
+
showError("Prompts API error: " + response.status);
|
|
72863
|
+
return;
|
|
72864
|
+
}
|
|
72865
|
+
|
|
72866
|
+
renderBoard(await response.json());
|
|
72867
|
+
} catch (error) {
|
|
72868
|
+
showError("Could not load prompts: " + error.message);
|
|
72373
72869
|
}
|
|
72374
72870
|
}
|
|
72375
72871
|
|
|
72376
72872
|
function renderBoard(promptFiles) {
|
|
72377
|
-
const columns =
|
|
72873
|
+
const columns = Object.fromEntries(BOARD_COLUMNS.map((column) => [column.id, []]));
|
|
72378
72874
|
|
|
72379
72875
|
for (const file of promptFiles) {
|
|
72380
72876
|
for (const section of file.sections) {
|
|
72381
|
-
|
|
72382
|
-
|
|
72877
|
+
if (columns[section.column]) {
|
|
72878
|
+
columns[section.column].push({ file, section });
|
|
72879
|
+
}
|
|
72383
72880
|
}
|
|
72384
72881
|
}
|
|
72385
72882
|
|
|
72386
|
-
for (const
|
|
72387
|
-
|
|
72388
|
-
|
|
72389
|
-
|
|
72883
|
+
for (const column of BOARD_COLUMNS) {
|
|
72884
|
+
renderColumn(column.id, columns[column.id]);
|
|
72885
|
+
}
|
|
72886
|
+
}
|
|
72390
72887
|
|
|
72391
|
-
|
|
72392
|
-
|
|
72888
|
+
function renderColumn(columnId, cards) {
|
|
72889
|
+
const container = document.getElementById("cards-" + columnId);
|
|
72890
|
+
const countElement = document.getElementById("count-" + columnId);
|
|
72393
72891
|
|
|
72394
|
-
|
|
72395
|
-
|
|
72396
|
-
continue;
|
|
72397
|
-
}
|
|
72892
|
+
countElement.textContent = cards.length;
|
|
72893
|
+
container.innerHTML = "";
|
|
72398
72894
|
|
|
72399
|
-
|
|
72400
|
-
|
|
72401
|
-
|
|
72402
|
-
|
|
72403
|
-
|
|
72404
|
-
|
|
72405
|
-
|
|
72406
|
-
? '<div class="card-priority">' + '!'.repeat(section.priority) + ' priority ' + section.priority + '</div>'
|
|
72407
|
-
: '') +
|
|
72408
|
-
'<div class="card-edit-hint">Click to edit</div>';
|
|
72409
|
-
card.onclick = () => openModal(file, section);
|
|
72410
|
-
container.appendChild(card);
|
|
72411
|
-
}
|
|
72895
|
+
if (cards.length === 0) {
|
|
72896
|
+
container.innerHTML = '<div class="empty-column">Empty</div>';
|
|
72897
|
+
return;
|
|
72898
|
+
}
|
|
72899
|
+
|
|
72900
|
+
for (const cardData of cards) {
|
|
72901
|
+
container.appendChild(createPromptCard(cardData.file, cardData.section));
|
|
72412
72902
|
}
|
|
72413
72903
|
}
|
|
72414
72904
|
|
|
72905
|
+
function createPromptCard(file, section) {
|
|
72906
|
+
const card = document.createElement("article");
|
|
72907
|
+
card.className = "card card-" + section.column;
|
|
72908
|
+
card.innerHTML =
|
|
72909
|
+
'<div class="card-file">' + escapeHtml(file.relativeFilePath || file.fileName) + " #" + (section.index + 1) + '</div>' +
|
|
72910
|
+
'<div class="card-summary">' + escapeHtml(section.summary) + '</div>' +
|
|
72911
|
+
renderTags(section);
|
|
72912
|
+
card.onclick = () => openModal(file, section);
|
|
72913
|
+
return card;
|
|
72914
|
+
}
|
|
72915
|
+
|
|
72916
|
+
function renderTags(section) {
|
|
72917
|
+
const tags = [...(section.tags || [])];
|
|
72918
|
+
if (section.priority > 0) {
|
|
72919
|
+
tags.push({ id: "priority", label: "P" + section.priority });
|
|
72920
|
+
}
|
|
72921
|
+
|
|
72922
|
+
if (tags.length === 0) {
|
|
72923
|
+
return "";
|
|
72924
|
+
}
|
|
72925
|
+
|
|
72926
|
+
return '<div class="card-tags">' + tags.map((tag) =>
|
|
72927
|
+
'<span class="card-tag tag-' + escapeHtml(tag.id) + '">' + escapeHtml(tag.label) + '</span>'
|
|
72928
|
+
).join("") + '</div>';
|
|
72929
|
+
}
|
|
72930
|
+
|
|
72415
72931
|
function openModal(file, section) {
|
|
72416
72932
|
modalState = { filePath: file.filePath, sectionIndex: section.index };
|
|
72417
72933
|
|
|
72418
|
-
document.getElementById(
|
|
72419
|
-
document.getElementById(
|
|
72934
|
+
document.getElementById("modal-file").textContent = file.relativeFilePath || file.fileName;
|
|
72935
|
+
document.getElementById("modal-section-label").textContent = "Section " + (section.index + 1);
|
|
72420
72936
|
|
|
72421
|
-
const
|
|
72422
|
-
|
|
72423
|
-
|
|
72937
|
+
const statusBadge = document.getElementById("modal-status-badge");
|
|
72938
|
+
statusBadge.textContent = getColumnTitle(section.column);
|
|
72939
|
+
statusBadge.className = "modal-status status-" + section.column;
|
|
72424
72940
|
|
|
72425
|
-
document.getElementById(
|
|
72426
|
-
document.getElementById(
|
|
72427
|
-
setTimeout(() => document.getElementById(
|
|
72941
|
+
document.getElementById("modal-content").value = section.content;
|
|
72942
|
+
document.getElementById("modal-overlay").classList.remove("hidden");
|
|
72943
|
+
setTimeout(() => document.getElementById("modal-content").focus(), 50);
|
|
72428
72944
|
}
|
|
72429
72945
|
|
|
72430
72946
|
function closeModal() {
|
|
72431
|
-
document.getElementById(
|
|
72947
|
+
document.getElementById("modal-overlay").classList.add("hidden");
|
|
72432
72948
|
modalState = null;
|
|
72433
72949
|
}
|
|
72434
72950
|
|
|
72435
72951
|
async function saveModal() {
|
|
72436
|
-
if (!modalState)
|
|
72952
|
+
if (!modalState) {
|
|
72953
|
+
return;
|
|
72954
|
+
}
|
|
72437
72955
|
|
|
72438
|
-
const content = document.getElementById(
|
|
72439
|
-
const
|
|
72440
|
-
|
|
72441
|
-
|
|
72956
|
+
const content = document.getElementById("modal-content").value;
|
|
72957
|
+
const saveButton = document.getElementById("save-button");
|
|
72958
|
+
saveButton.disabled = true;
|
|
72959
|
+
saveButton.textContent = "Saving...";
|
|
72442
72960
|
|
|
72443
72961
|
try {
|
|
72444
|
-
const
|
|
72445
|
-
method:
|
|
72446
|
-
headers: {
|
|
72962
|
+
const response = await fetch("/api/prompts/update", {
|
|
72963
|
+
method: "PUT",
|
|
72964
|
+
headers: { "Content-Type": "application/json" },
|
|
72447
72965
|
body: JSON.stringify({
|
|
72448
|
-
filePath:
|
|
72966
|
+
filePath: modalState.filePath,
|
|
72449
72967
|
sectionIndex: modalState.sectionIndex,
|
|
72450
72968
|
content,
|
|
72451
72969
|
}),
|
|
72452
72970
|
});
|
|
72453
|
-
|
|
72971
|
+
|
|
72972
|
+
if (!response.ok) {
|
|
72973
|
+
throw new Error("HTTP " + response.status);
|
|
72974
|
+
}
|
|
72975
|
+
|
|
72454
72976
|
closeModal();
|
|
72455
|
-
fetchPrompts();
|
|
72456
|
-
} catch (
|
|
72457
|
-
showError(
|
|
72977
|
+
await fetchPrompts();
|
|
72978
|
+
} catch (error) {
|
|
72979
|
+
showError("Save failed: " + error.message);
|
|
72458
72980
|
} finally {
|
|
72459
|
-
|
|
72460
|
-
|
|
72981
|
+
saveButton.disabled = false;
|
|
72982
|
+
saveButton.textContent = "Save";
|
|
72461
72983
|
}
|
|
72462
72984
|
}
|
|
72463
72985
|
|
|
72464
|
-
document.getElementById(
|
|
72986
|
+
document.getElementById("toggle-btn").onclick = async () => {
|
|
72465
72987
|
try {
|
|
72466
|
-
const endpoint = lastPauseState ===
|
|
72467
|
-
await fetch(endpoint, { method:
|
|
72988
|
+
const endpoint = lastPauseState === "RUNNING" ? "/api/pause" : "/api/resume";
|
|
72989
|
+
await fetch(endpoint, { method: "POST" });
|
|
72468
72990
|
await fetchStatus();
|
|
72469
|
-
} catch (
|
|
72470
|
-
showError(
|
|
72991
|
+
} catch (error) {
|
|
72992
|
+
showError("Toggle failed: " + error.message);
|
|
72471
72993
|
}
|
|
72472
72994
|
};
|
|
72473
72995
|
|
|
72474
|
-
document.
|
|
72475
|
-
|
|
72476
|
-
|
|
72996
|
+
document.getElementById("modal-close").onclick = closeModal;
|
|
72997
|
+
document.getElementById("cancel-button").onclick = closeModal;
|
|
72998
|
+
document.getElementById("save-button").onclick = saveModal;
|
|
72999
|
+
|
|
73000
|
+
document.addEventListener("keydown", (event) => {
|
|
73001
|
+
if (event.key === "Escape") {
|
|
73002
|
+
closeModal();
|
|
73003
|
+
return;
|
|
73004
|
+
}
|
|
73005
|
+
if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
|
|
73006
|
+
saveModal();
|
|
73007
|
+
}
|
|
72477
73008
|
});
|
|
72478
73009
|
|
|
72479
|
-
document.getElementById(
|
|
72480
|
-
if (
|
|
73010
|
+
document.getElementById("modal-overlay").addEventListener("click", (event) => {
|
|
73011
|
+
if (event.target === document.getElementById("modal-overlay")) {
|
|
73012
|
+
closeModal();
|
|
73013
|
+
}
|
|
72481
73014
|
});
|
|
72482
73015
|
|
|
73016
|
+
renderBoardSkeleton();
|
|
72483
73017
|
fetchStatus();
|
|
72484
73018
|
fetchPrompts();
|
|
72485
|
-
setInterval(fetchStatus,
|
|
73019
|
+
setInterval(fetchStatus, 2000);
|
|
72486
73020
|
setInterval(fetchPrompts, 5000);
|
|
72487
73021
|
</script>
|
|
72488
73022
|
</body>
|
|
72489
|
-
</html
|
|
73023
|
+
</html>
|
|
73024
|
+
`;
|
|
72490
73025
|
// Note: [🟡] Code for CLI command [coder server](scripts/run-codex-prompts/server/coderServerHtml.ts) should never be published outside of `@promptbook/cli`
|
|
72491
73026
|
// Note: Keep in sync with apps/coder-server/index.html
|
|
72492
73027
|
|
|
@@ -72496,6 +73031,12 @@ const CODER_SERVER_HTML = `<!DOCTYPE html>
|
|
|
72496
73031
|
* @private internal constant of `ptbk coder server`
|
|
72497
73032
|
*/
|
|
72498
73033
|
const PROMPTS_DIRECTORY_NAME = 'prompts';
|
|
73034
|
+
/**
|
|
73035
|
+
* Directory containing human-verified prompt files, relative to `prompts/`.
|
|
73036
|
+
*
|
|
73037
|
+
* @private internal constant of `ptbk coder server`
|
|
73038
|
+
*/
|
|
73039
|
+
const FINISHED_PROMPTS_DIRECTORY_NAME = 'done';
|
|
72499
73040
|
/**
|
|
72500
73041
|
* Starts the lightweight HTTP server that serves the coder kanban UI and REST API.
|
|
72501
73042
|
*
|
|
@@ -72509,24 +73050,29 @@ const PROMPTS_DIRECTORY_NAME = 'prompts';
|
|
|
72509
73050
|
*
|
|
72510
73051
|
* @private internal utility of `ptbk coder server`
|
|
72511
73052
|
*/
|
|
72512
|
-
function startCoderHttpServer(
|
|
73053
|
+
function startCoderHttpServer(options) {
|
|
73054
|
+
const { port, minimumPriority, serverUrl, uiState } = options;
|
|
72513
73055
|
const promptsDir = join(process.cwd(), PROMPTS_DIRECTORY_NAME);
|
|
72514
|
-
const server = createServer(async (
|
|
73056
|
+
const server = createServer(async (request, response) => {
|
|
72515
73057
|
try {
|
|
72516
|
-
await handleRequest(
|
|
73058
|
+
await handleRequest(request, response, {
|
|
73059
|
+
promptsDir,
|
|
73060
|
+
minimumPriority,
|
|
73061
|
+
uiState,
|
|
73062
|
+
});
|
|
72517
73063
|
}
|
|
72518
73064
|
catch (error) {
|
|
72519
73065
|
const message = error instanceof Error ? error.message : String(error);
|
|
72520
73066
|
console.error(colors.red(`Coder server request error: ${message}`));
|
|
72521
|
-
if (!
|
|
72522
|
-
|
|
73067
|
+
if (!response.headersSent) {
|
|
73068
|
+
response.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
72523
73069
|
}
|
|
72524
|
-
|
|
73070
|
+
response.end('Internal server error');
|
|
72525
73071
|
}
|
|
72526
73072
|
});
|
|
72527
73073
|
server.listen(port, () => {
|
|
72528
73074
|
console.info(spaceTrim$1(`
|
|
72529
|
-
Coder server running at ${colors.cyan(
|
|
73075
|
+
Coder server running at ${colors.cyan(serverUrl)}
|
|
72530
73076
|
Open the URL above in your browser to see the kanban board.
|
|
72531
73077
|
Press ${colors.bold('p')} to pause / resume the agent runner.
|
|
72532
73078
|
`));
|
|
@@ -72540,51 +73086,57 @@ function startCoderHttpServer(port) {
|
|
|
72540
73086
|
/**
|
|
72541
73087
|
* Routes one HTTP request to the appropriate handler.
|
|
72542
73088
|
*/
|
|
72543
|
-
async function handleRequest(
|
|
72544
|
-
const
|
|
72545
|
-
const
|
|
73089
|
+
async function handleRequest(request, response, options) {
|
|
73090
|
+
const { promptsDir, minimumPriority, uiState } = options;
|
|
73091
|
+
const urlPath = new URL(request.url || '/', `http://localhost`).pathname;
|
|
73092
|
+
const method = (request.method || 'GET').toUpperCase();
|
|
72546
73093
|
// Serve the kanban UI
|
|
72547
73094
|
if (urlPath === '/' && method === 'GET') {
|
|
72548
|
-
|
|
73095
|
+
response.writeHead(200, {
|
|
72549
73096
|
'Content-Type': 'text/html; charset=utf-8',
|
|
72550
73097
|
'Cache-Control': 'no-cache',
|
|
72551
73098
|
});
|
|
72552
|
-
|
|
73099
|
+
response.end(CODER_SERVER_HTML);
|
|
72553
73100
|
return;
|
|
72554
73101
|
}
|
|
72555
73102
|
// GET /api/status
|
|
72556
73103
|
if (urlPath === '/api/status' && method === 'GET') {
|
|
72557
|
-
|
|
72558
|
-
|
|
73104
|
+
response.writeHead(200, jsonHeaders());
|
|
73105
|
+
response.end(JSON.stringify({
|
|
72559
73106
|
pauseState: getPauseState(),
|
|
72560
73107
|
pauseTargetLabel: getPauseTargetLabel(),
|
|
73108
|
+
runState: uiState ? buildCoderServerRunState(uiState) : undefined,
|
|
72561
73109
|
}));
|
|
72562
73110
|
return;
|
|
72563
73111
|
}
|
|
72564
73112
|
// GET /api/prompts
|
|
72565
73113
|
if (urlPath === '/api/prompts' && method === 'GET') {
|
|
72566
|
-
const promptData = await loadPromptsForApi(
|
|
72567
|
-
|
|
72568
|
-
|
|
73114
|
+
const promptData = await loadPromptsForApi({
|
|
73115
|
+
promptsDir,
|
|
73116
|
+
minimumPriority,
|
|
73117
|
+
uiState,
|
|
73118
|
+
});
|
|
73119
|
+
response.writeHead(200, jsonHeaders());
|
|
73120
|
+
response.end(JSON.stringify(promptData));
|
|
72569
73121
|
return;
|
|
72570
73122
|
}
|
|
72571
73123
|
// POST /api/pause
|
|
72572
73124
|
if (urlPath === '/api/pause' && method === 'POST') {
|
|
72573
73125
|
requestPause();
|
|
72574
|
-
|
|
72575
|
-
|
|
73126
|
+
response.writeHead(200, jsonHeaders());
|
|
73127
|
+
response.end(JSON.stringify({ pauseState: getPauseState() }));
|
|
72576
73128
|
return;
|
|
72577
73129
|
}
|
|
72578
73130
|
// POST /api/resume
|
|
72579
73131
|
if (urlPath === '/api/resume' && method === 'POST') {
|
|
72580
73132
|
requestResume();
|
|
72581
|
-
|
|
72582
|
-
|
|
73133
|
+
response.writeHead(200, jsonHeaders());
|
|
73134
|
+
response.end(JSON.stringify({ pauseState: getPauseState() }));
|
|
72583
73135
|
return;
|
|
72584
73136
|
}
|
|
72585
73137
|
// PUT /api/prompts/update
|
|
72586
73138
|
if (urlPath === '/api/prompts/update' && method === 'PUT') {
|
|
72587
|
-
const body = await readRequestBody(
|
|
73139
|
+
const body = await readRequestBody(request);
|
|
72588
73140
|
const parsed = JSON.parse(body);
|
|
72589
73141
|
if (typeof parsed.filePath !== 'string' ||
|
|
72590
73142
|
typeof parsed.sectionIndex !== 'number' ||
|
|
@@ -72595,49 +73147,85 @@ async function handleRequest(req, res, promptsDir) {
|
|
|
72595
73147
|
Expected: \`{ filePath: string, sectionIndex: number, content: string }\`
|
|
72596
73148
|
`));
|
|
72597
73149
|
}
|
|
72598
|
-
|
|
72599
|
-
|
|
72600
|
-
|
|
73150
|
+
const promptFilePath = resolveEditablePromptFilePath(parsed.filePath, promptsDir);
|
|
73151
|
+
const isUpdated = await updatePromptSection(promptFilePath, parsed.sectionIndex, parsed.content);
|
|
73152
|
+
if (isUpdated) {
|
|
73153
|
+
await commitPromptEdit(promptFilePath, parsed.sectionIndex);
|
|
73154
|
+
}
|
|
73155
|
+
response.writeHead(200, jsonHeaders());
|
|
73156
|
+
response.end(JSON.stringify({ success: true, committed: isUpdated }));
|
|
72601
73157
|
return;
|
|
72602
73158
|
}
|
|
72603
|
-
|
|
72604
|
-
|
|
73159
|
+
response.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
73160
|
+
response.end('Not found');
|
|
72605
73161
|
}
|
|
72606
73162
|
/**
|
|
72607
73163
|
* Loads all prompt files and converts them to the API response shape.
|
|
72608
73164
|
*/
|
|
72609
|
-
async function loadPromptsForApi(
|
|
73165
|
+
async function loadPromptsForApi(options) {
|
|
73166
|
+
const { promptsDir, minimumPriority, uiState } = options;
|
|
73167
|
+
const promptFiles = await loadPromptFilesSafely(promptsDir);
|
|
73168
|
+
const finishedPromptFiles = await loadPromptFilesSafely(join(promptsDir, FINISHED_PROMPTS_DIRECTORY_NAME));
|
|
73169
|
+
return buildCoderServerPromptFileResponses({
|
|
73170
|
+
promptFiles,
|
|
73171
|
+
finishedPromptFiles,
|
|
73172
|
+
minimumPriority,
|
|
73173
|
+
uiState,
|
|
73174
|
+
});
|
|
73175
|
+
}
|
|
73176
|
+
/**
|
|
73177
|
+
* Loads prompt files from a directory that may not exist yet.
|
|
73178
|
+
*/
|
|
73179
|
+
async function loadPromptFilesSafely(promptsDir) {
|
|
72610
73180
|
try {
|
|
72611
|
-
|
|
72612
|
-
return promptFiles.map((file) => ({
|
|
72613
|
-
filePath: file.path,
|
|
72614
|
-
fileName: file.name,
|
|
72615
|
-
sections: file.sections.map((section) => ({
|
|
72616
|
-
index: section.index,
|
|
72617
|
-
status: section.status,
|
|
72618
|
-
priority: section.priority,
|
|
72619
|
-
summary: buildPromptSummary(file, section),
|
|
72620
|
-
content: buildCodexPrompt(file, section),
|
|
72621
|
-
})),
|
|
72622
|
-
}));
|
|
73181
|
+
return await loadPromptFiles(promptsDir);
|
|
72623
73182
|
}
|
|
72624
73183
|
catch (error) {
|
|
72625
|
-
// Prompts directory may not exist yet; return empty list
|
|
72626
73184
|
if (error.code === 'ENOENT') {
|
|
72627
73185
|
return [];
|
|
72628
73186
|
}
|
|
72629
73187
|
throw error;
|
|
72630
73188
|
}
|
|
72631
73189
|
}
|
|
73190
|
+
/**
|
|
73191
|
+
* Resolves and validates one editable prompt file path received from the browser.
|
|
73192
|
+
*/
|
|
73193
|
+
function resolveEditablePromptFilePath(filePath, promptsDir) {
|
|
73194
|
+
const promptFilePath = resolve(filePath);
|
|
73195
|
+
const promptsDirectoryPath = resolve(promptsDir);
|
|
73196
|
+
const relativePromptFilePath = relative(promptsDirectoryPath, promptFilePath);
|
|
73197
|
+
const isOutsidePromptsDirectory = relativePromptFilePath === '' ||
|
|
73198
|
+
relativePromptFilePath.startsWith('..') ||
|
|
73199
|
+
isAbsolute(relativePromptFilePath);
|
|
73200
|
+
if (isOutsidePromptsDirectory || !promptFilePath.toLowerCase().endsWith('.md')) {
|
|
73201
|
+
throw new NotAllowed(spaceTrim$1(`
|
|
73202
|
+
Prompt file edits are limited to Markdown files inside \`${promptsDirectoryPath}\`.
|
|
73203
|
+
|
|
73204
|
+
Requested file:
|
|
73205
|
+
\`${filePath}\`
|
|
73206
|
+
`));
|
|
73207
|
+
}
|
|
73208
|
+
return promptFilePath;
|
|
73209
|
+
}
|
|
73210
|
+
/**
|
|
73211
|
+
* Commits a browser prompt edit to Git without sweeping unrelated staged files into the commit.
|
|
73212
|
+
*/
|
|
73213
|
+
async function commitPromptEdit(promptFilePath, sectionIndex) {
|
|
73214
|
+
const relativePromptFilePath = relative(process.cwd(), promptFilePath).replace(/\\/gu, '/');
|
|
73215
|
+
await commitChanges(`Edit coder prompt ${relativePromptFilePath}#${sectionIndex + 1}`, {
|
|
73216
|
+
includePaths: [relativePromptFilePath],
|
|
73217
|
+
onlyPaths: [relativePromptFilePath],
|
|
73218
|
+
});
|
|
73219
|
+
}
|
|
72632
73220
|
/**
|
|
72633
73221
|
* Reads the full request body as a UTF-8 string.
|
|
72634
73222
|
*/
|
|
72635
|
-
function readRequestBody(
|
|
73223
|
+
function readRequestBody(request) {
|
|
72636
73224
|
return new Promise((resolve, reject) => {
|
|
72637
73225
|
const chunks = [];
|
|
72638
|
-
|
|
72639
|
-
|
|
72640
|
-
|
|
73226
|
+
request.on('data', (chunk) => chunks.push(chunk));
|
|
73227
|
+
request.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
|
|
73228
|
+
request.on('error', reject);
|
|
72641
73229
|
});
|
|
72642
73230
|
}
|
|
72643
73231
|
/**
|
|
@@ -72666,12 +73254,21 @@ function jsonHeaders() {
|
|
|
72666
73254
|
*/
|
|
72667
73255
|
async function runCodexPromptsServer(options) {
|
|
72668
73256
|
const { port, ...runOptions } = options;
|
|
72669
|
-
const
|
|
73257
|
+
const serverUrl = `http://localhost:${port}`;
|
|
73258
|
+
const uiState = new CoderRunUiState(moment());
|
|
73259
|
+
const serverHandle = startCoderHttpServer({
|
|
73260
|
+
port,
|
|
73261
|
+
minimumPriority: runOptions.priority,
|
|
73262
|
+
serverUrl,
|
|
73263
|
+
uiState,
|
|
73264
|
+
});
|
|
72670
73265
|
console.info(colors.gray('Starting prompt runner in server (keep-alive) mode…'));
|
|
72671
73266
|
try {
|
|
72672
73267
|
await runCodexPrompts({
|
|
72673
73268
|
...runOptions,
|
|
72674
73269
|
keepAlive: true,
|
|
73270
|
+
serverUrl,
|
|
73271
|
+
uiState,
|
|
72675
73272
|
});
|
|
72676
73273
|
}
|
|
72677
73274
|
finally {
|