@lowdefy/server-dev 6.1.0 → 7.0.0
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/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +67 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +679 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/findCollectionCollisions.js +52 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +44 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +119 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +343 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +68 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +220 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +33 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +203 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +8 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +54 -6
- package/lib/docs/getBuildStatus.test.mjs +133 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +83 -0
- package/lib/server/applyDataSetRedirect.test.mjs +340 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +204 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +131 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +328 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +112 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +24 -2
- package/manager/processes/initialBuild.mjs +14 -0
- package/manager/processes/initialBuild.test.mjs +101 -0
- package/manager/processes/lowdefyBuild.mjs +30 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +62 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -15,51 +15,63 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
18
|
-
import {
|
|
18
|
+
import { createTraceId, type } from '@lowdefy/helpers';
|
|
19
|
+
import { validateJourneyUser } from '@lowdefy/node-utils';
|
|
19
20
|
|
|
20
21
|
import checkpointToMocks from './checkpointToMocks.js';
|
|
21
22
|
import createConfigCheckpoint from './createConfigCheckpoint.js';
|
|
23
|
+
import { subscribe as subscribeToDevEvents } from './devEventBus.js';
|
|
22
24
|
import evalOperator from './evalOperator.js';
|
|
23
25
|
import findConfig from './findConfig.js';
|
|
24
26
|
import getAppMap from './getAppMap.js';
|
|
25
27
|
import getBuildStatus from './getBuildStatus.js';
|
|
26
|
-
import
|
|
28
|
+
import getBuildStatusAfterEdits from './getBuildStatusAfterEdits.js';
|
|
29
|
+
import readJourneySession from './readJourneySession.js';
|
|
30
|
+
import readProxyBuildWait from './readProxyBuildWait.js';
|
|
31
|
+
import getDoc from './getDoc.js';
|
|
27
32
|
import getExamples from './getExamples.js';
|
|
28
33
|
import getOverview from './getOverview.js';
|
|
29
34
|
import getPageConfig from './getPageConfig.js';
|
|
30
35
|
import getPluginDoc from './getPluginDoc.js';
|
|
31
36
|
import getSchema from './getSchema.js';
|
|
37
|
+
import getStaleStatus from './getStaleStatus.js';
|
|
32
38
|
import inspectState from './inspectState.js';
|
|
33
39
|
import listConfigCheckpoints from './listConfigCheckpoints.js';
|
|
34
40
|
import listPlugins from './listPlugins.js';
|
|
35
41
|
import listTypes from './listTypes.js';
|
|
36
42
|
import loadState from './loadState.js';
|
|
37
43
|
import revertConfigCheckpoint from './revertConfigCheckpoint.js';
|
|
44
|
+
import requestRestart from './requestRestart.js';
|
|
45
|
+
import runCheck from './runCheck.js';
|
|
46
|
+
import runEndpoint from './runEndpoint.js';
|
|
47
|
+
import runJourney from './runJourney.js';
|
|
48
|
+
import runJourneyAsUsers from './runJourneyAsUsers.js';
|
|
49
|
+
import selectExercised from './selectExercised.js';
|
|
38
50
|
import runRequest from './runRequest.js';
|
|
39
51
|
import snapshotState from './snapshotState.js';
|
|
40
52
|
import { listStateCheckpoints } from './checkpointStore.js';
|
|
41
53
|
import createLogger from '../server/log/createLogger.js';
|
|
54
|
+
import lowdefyConfig from '../build/config.js';
|
|
55
|
+
import devToolDefinitions, { INSTRUCTIONS } from './devToolDefinitions.js';
|
|
42
56
|
import scaffoldPage from './scaffoldPage.js';
|
|
43
57
|
import screenshotPage from './screenshotPage.js';
|
|
44
58
|
import searchDocs from './searchDocs.js';
|
|
59
|
+
import searchIcons from './searchIcons.js';
|
|
45
60
|
|
|
46
61
|
const logger = createLogger({ server: 'lowdefy-dev-mcp' });
|
|
47
62
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Visual feedback: developers can press Cmd/Ctrl+/ in the running app to point at elements, draw, and copy annotated feedback to their clipboard, then paste it to you. Pasted annotation blocks start with "Feedback:" and carry the blockId, the resolved config file:line, drawn shapes, and usually an "Annotated screenshot:" file path — READ that image to see exactly what the developer drew. Treat them as precise UI feedback and use lowdefy_inspect_state for the page's live state.
|
|
61
|
-
|
|
62
|
-
State checkpoints (testing): lowdefy_snapshot_state captures a page's live state AND its request/api responses into .lowdefy/state-checkpoints/<name>/ (one file per part; gitignored — checkpoints contain user/session data). lowdefy_load_state puts the app back into that state: headless for your own verification, or registry-only which returns a ?_checkpoint URL the developer can open to manually test the app in that exact state (recorded request data is served automatically). lowdefy_checkpoint_to_mocks converts a checkpoint into e2e mocks.yaml fixtures — use it when asked to write e2e tests.`;
|
|
63
|
+
// get_doc returns markdown rather than JSON, so hazards resolved for the
|
|
64
|
+
// requested type are appended as a section instead of a sibling key.
|
|
65
|
+
function appendHazards(doc) {
|
|
66
|
+
if (type.isNone(doc.hazards) || doc.hazards.length === 0) {
|
|
67
|
+
return doc.markdown;
|
|
68
|
+
}
|
|
69
|
+
const lines = doc.hazards.map((hazard) => {
|
|
70
|
+
const see = type.isNone(hazard.see) ? '' : ` (see \`${hazard.see}\`)`;
|
|
71
|
+
return `- **${hazard.id}**: ${hazard.message}${see}`;
|
|
72
|
+
});
|
|
73
|
+
return `${doc.markdown}\n\n## Hazards\n\n${lines.join('\n')}\n`;
|
|
74
|
+
}
|
|
63
75
|
|
|
64
76
|
function textResult(value) {
|
|
65
77
|
const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
|
|
@@ -70,76 +82,74 @@ function notFoundResult(message) {
|
|
|
70
82
|
return { content: [{ type: 'text', text: message }], isError: true };
|
|
71
83
|
}
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
// admin and the next as a plain member — each headless call gets its own browser
|
|
75
|
-
// context, so they never share an identity.
|
|
76
|
-
const userSchema = z
|
|
77
|
-
.object({})
|
|
78
|
-
.passthrough()
|
|
79
|
-
.optional()
|
|
80
|
-
.describe(
|
|
81
|
-
'Act as this caller instead of the default roleless headless user, e.g. {"roles":["user-admin"]} to render a role-gated page. Merged over the default, so include email/profile/attributes fields too if the page reads them — no auth engine runs for an injected caller, so nothing derives them. Headless only: it is never applied to a page the developer opens in their own browser, so combining it with source "tab" or load_state mode "registry-only" is an error rather than a silently dropped role.'
|
|
82
|
-
);
|
|
83
|
-
|
|
84
|
-
function createDocsMcpServer({ origin, honoContext } = {}) {
|
|
85
|
+
function createDocsMcpServer({ origin, honoContext, version } = {}) {
|
|
85
86
|
const server = new McpServer(
|
|
86
|
-
{ name: 'lowdefy
|
|
87
|
-
{ instructions: INSTRUCTIONS }
|
|
87
|
+
{ name: 'lowdefy', version },
|
|
88
|
+
{ capabilities: { logging: {} }, instructions: INSTRUCTIONS }
|
|
88
89
|
);
|
|
89
90
|
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
//
|
|
93
|
-
|
|
94
|
-
server
|
|
95
|
-
|
|
91
|
+
// Every tool's contract comes from devToolDefinitions, which the stdio shim
|
|
92
|
+
// also lists, so a tool registered here without a definition - or a
|
|
93
|
+
// definition left without a handler - would make the two disagree.
|
|
94
|
+
// registerDevTool looks the definition up, and the check after the last
|
|
95
|
+
// registration fails the server if any definition was missed.
|
|
96
|
+
//
|
|
97
|
+
// It also debug-logs every tool call (name + args, never the response) so
|
|
98
|
+
// agent activity is visible in the dev terminal with --log-level=debug.
|
|
99
|
+
const registered = new Set();
|
|
100
|
+
function registerDevTool(name, handler) {
|
|
101
|
+
const definition = devToolDefinitions[name];
|
|
102
|
+
if (definition === undefined) {
|
|
103
|
+
throw new Error(`Dev tool "${name}" has no entry in devToolDefinitions.`);
|
|
104
|
+
}
|
|
105
|
+
registered.add(name);
|
|
106
|
+
server.registerTool(name, definition, async (args, extra) => {
|
|
96
107
|
try {
|
|
97
108
|
logger.debug({ event: 'mcp_tool_call', tool: name, args }, `MCP tool call: ${name}`);
|
|
98
109
|
} catch {
|
|
99
110
|
// Logging must never break a tool call.
|
|
100
111
|
}
|
|
101
|
-
|
|
112
|
+
const result = await handler(args, extra);
|
|
113
|
+
try {
|
|
114
|
+
const stale = getStaleStatus();
|
|
115
|
+
// Prepended rather than merged so it covers textResult, notFoundResult
|
|
116
|
+
// and any future result shape without parsing the tool's own payload.
|
|
117
|
+
if (stale && Array.isArray(result?.content)) {
|
|
118
|
+
result.content.unshift({
|
|
119
|
+
type: 'text',
|
|
120
|
+
text: `STALE: ${stale.staleReason} ${JSON.stringify({
|
|
121
|
+
stale: true,
|
|
122
|
+
staleSince: stale.staleSince,
|
|
123
|
+
})}`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
} catch {
|
|
127
|
+
// A missing or half-written artifact must never break a tool call.
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
102
130
|
});
|
|
131
|
+
}
|
|
103
132
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
"Read the LIVE state of a running page: state, request results, event log (recent actions fired), global, user, input, and urlQuery. If the developer has the page open in a browser it reads their actual tab (ask them to interact first, then inspect); otherwise it runs the page headless. Use this to see what the app's data model really looks like.",
|
|
109
|
-
inputSchema: {
|
|
110
|
-
pageId: z.string().describe('The page id to inspect.'),
|
|
111
|
-
source: z
|
|
112
|
-
.enum(['tab', 'headless'])
|
|
113
|
-
.optional()
|
|
114
|
-
.describe('Force a source. Default: live tab if connected, else headless.'),
|
|
115
|
-
user: userSchema,
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
async ({ pageId, source, user }) => {
|
|
119
|
-
const result = await inspectState({ origin, pageId, source, user });
|
|
120
|
-
if (result.error) {
|
|
121
|
-
return notFoundResult(result.error);
|
|
122
|
-
}
|
|
123
|
-
return textResult(result);
|
|
133
|
+
registerDevTool('lowdefy_inspect_state', async ({ pageId, pathParams, source, user, data }) => {
|
|
134
|
+
const result = await inspectState({ origin, pageId, pathParams, source, user, data });
|
|
135
|
+
if (result.error) {
|
|
136
|
+
return notFoundResult(result.error);
|
|
124
137
|
}
|
|
125
|
-
|
|
138
|
+
return textResult(result);
|
|
139
|
+
});
|
|
126
140
|
|
|
127
|
-
|
|
141
|
+
registerDevTool(
|
|
128
142
|
'lowdefy_eval_operator',
|
|
129
|
-
{
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
expression
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
},
|
|
140
|
-
},
|
|
141
|
-
async ({ pageId, expression, source, user }) => {
|
|
142
|
-
const result = await evalOperator({ origin, pageId, expression, source, user });
|
|
143
|
+
async ({ pageId, pathParams, expression, source, user, data }) => {
|
|
144
|
+
const result = await evalOperator({
|
|
145
|
+
origin,
|
|
146
|
+
pageId,
|
|
147
|
+
pathParams,
|
|
148
|
+
expression,
|
|
149
|
+
source,
|
|
150
|
+
user,
|
|
151
|
+
data,
|
|
152
|
+
});
|
|
143
153
|
if (result.error) {
|
|
144
154
|
return notFoundResult(result.error);
|
|
145
155
|
}
|
|
@@ -147,46 +157,43 @@ function createDocsMcpServer({ origin, honoContext } = {}) {
|
|
|
147
157
|
}
|
|
148
158
|
);
|
|
149
159
|
|
|
150
|
-
|
|
160
|
+
registerDevTool(
|
|
151
161
|
'lowdefy_run_request',
|
|
152
|
-
{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
async ({ pageId, requestId, payload, user, data, saveResponse }) =>
|
|
163
|
+
textResult(
|
|
164
|
+
await runRequest({ pageId, requestId, payload, user, data, saveResponse, honoContext })
|
|
165
|
+
)
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
registerDevTool(
|
|
169
|
+
'lowdefy_run_endpoint',
|
|
170
|
+
async ({ endpointId, payload, user, data, system, saveResponse }) =>
|
|
171
|
+
textResult(
|
|
172
|
+
await runEndpoint({ endpointId, payload, user, data, system, saveResponse, honoContext })
|
|
173
|
+
)
|
|
163
174
|
);
|
|
164
175
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
inputSchema: {},
|
|
171
|
-
},
|
|
172
|
-
() => textResult(getAppMap())
|
|
176
|
+
registerDevTool('lowdefy_restart', ({ reason }) =>
|
|
177
|
+
textResult({
|
|
178
|
+
...requestRestart({ reason }),
|
|
179
|
+
note: 'The dev server is restarting. Call GET /lowdefy-docs/build-status?wait=true (lowdefy_build_status with wait: true) before your next call; it answers once the server is back.',
|
|
180
|
+
})
|
|
173
181
|
);
|
|
174
182
|
|
|
175
|
-
|
|
183
|
+
registerDevTool('lowdefy_app_map', () => textResult(getAppMap()));
|
|
184
|
+
|
|
185
|
+
registerDevTool(
|
|
176
186
|
'lowdefy_snapshot_state',
|
|
177
|
-
{
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
name
|
|
183
|
-
notes
|
|
184
|
-
source
|
|
185
|
-
overwrite
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
async ({ pageId, name, notes, source, overwrite }) => {
|
|
189
|
-
const result = await snapshotState({ origin, pageId, name, notes, source, overwrite });
|
|
187
|
+
async ({ pageId, pathParams, name, notes, source, overwrite }) => {
|
|
188
|
+
const result = await snapshotState({
|
|
189
|
+
origin,
|
|
190
|
+
pageId,
|
|
191
|
+
pathParams,
|
|
192
|
+
name,
|
|
193
|
+
notes,
|
|
194
|
+
source,
|
|
195
|
+
overwrite,
|
|
196
|
+
});
|
|
190
197
|
if (result.error) {
|
|
191
198
|
return notFoundResult(result.error);
|
|
192
199
|
}
|
|
@@ -194,338 +201,288 @@ function createDocsMcpServer({ origin, honoContext } = {}) {
|
|
|
194
201
|
}
|
|
195
202
|
);
|
|
196
203
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
{
|
|
200
|
-
|
|
201
|
-
"Put the app back into a saved state checkpoint. mode 'headless' (default) verifies the restored state itself; mode 'registry-only' loads the recorded request data into the dev server and returns a ?_checkpoint URL the developer can open to manually test the app in that exact state.",
|
|
202
|
-
inputSchema: {
|
|
203
|
-
name: z.string().describe('The checkpoint name.'),
|
|
204
|
-
mode: z.enum(['headless', 'registry-only']).optional(),
|
|
205
|
-
user: userSchema,
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
|
-
async ({ name, mode, user }) => {
|
|
209
|
-
const result = await loadState({ origin, name, mode, user });
|
|
210
|
-
if (result.error) {
|
|
211
|
-
return notFoundResult(result.error);
|
|
212
|
-
}
|
|
213
|
-
return textResult(result);
|
|
204
|
+
registerDevTool('lowdefy_load_state', async ({ name, mode, user, data }) => {
|
|
205
|
+
const result = await loadState({ origin, name, mode, user, data });
|
|
206
|
+
if (result.error) {
|
|
207
|
+
return notFoundResult(result.error);
|
|
214
208
|
}
|
|
215
|
-
|
|
209
|
+
return textResult(result);
|
|
210
|
+
});
|
|
216
211
|
|
|
217
|
-
|
|
218
|
-
'lowdefy_list_state_checkpoints',
|
|
219
|
-
{
|
|
220
|
-
description: 'List saved state checkpoints (name, page, captured time, notes).',
|
|
221
|
-
inputSchema: {},
|
|
222
|
-
},
|
|
223
|
-
() => textResult(listStateCheckpoints())
|
|
224
|
-
);
|
|
212
|
+
registerDevTool('lowdefy_list_state_checkpoints', () => textResult(listStateCheckpoints()));
|
|
225
213
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
|
|
230
|
-
'Convert a state checkpoint into @lowdefy/e2e-utils mocks.yaml fixtures (requests/api entries plus rendered yaml). Use when writing e2e tests from a captured scenario.',
|
|
231
|
-
inputSchema: {
|
|
232
|
-
name: z.string().describe('The checkpoint name.'),
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
({ name }) => {
|
|
236
|
-
const result = checkpointToMocks({ name });
|
|
237
|
-
if (result.error) {
|
|
238
|
-
return notFoundResult(result.error);
|
|
239
|
-
}
|
|
240
|
-
return textResult(result);
|
|
214
|
+
registerDevTool('lowdefy_checkpoint_to_mocks', ({ name }) => {
|
|
215
|
+
const result = checkpointToMocks({ name });
|
|
216
|
+
if (result.error) {
|
|
217
|
+
return notFoundResult(result.error);
|
|
241
218
|
}
|
|
242
|
-
|
|
219
|
+
return textResult(result);
|
|
220
|
+
});
|
|
243
221
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
{
|
|
247
|
-
description:
|
|
248
|
-
'Snapshot all config files before risky changes. Returns a checkpoint id for lowdefy_revert_checkpoint. Use before multi-file edits so you can restore instantly.',
|
|
249
|
-
inputSchema: {
|
|
250
|
-
label: z.string().describe('Short label for the checkpoint, e.g. "before-refactor".'),
|
|
251
|
-
},
|
|
252
|
-
},
|
|
253
|
-
({ label }) => textResult(createConfigCheckpoint({ label }))
|
|
222
|
+
registerDevTool('lowdefy_checkpoint', ({ label }) =>
|
|
223
|
+
textResult(createConfigCheckpoint({ label }))
|
|
254
224
|
);
|
|
255
225
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
description:
|
|
260
|
-
'Restore config files from a checkpoint made with lowdefy_checkpoint (restores changed files and removes files added since). Omit id to list available checkpoints.',
|
|
261
|
-
inputSchema: {
|
|
262
|
-
id: z.string().optional().describe('Checkpoint id. Omit to list checkpoints.'),
|
|
263
|
-
},
|
|
264
|
-
},
|
|
265
|
-
({ id }) => {
|
|
266
|
-
if (!id) {
|
|
267
|
-
return textResult(listConfigCheckpoints());
|
|
268
|
-
}
|
|
269
|
-
return textResult(revertConfigCheckpoint({ id }));
|
|
226
|
+
registerDevTool('lowdefy_revert_checkpoint', ({ id }) => {
|
|
227
|
+
if (!id) {
|
|
228
|
+
return textResult(listConfigCheckpoints());
|
|
270
229
|
}
|
|
271
|
-
|
|
230
|
+
return textResult(revertConfigCheckpoint({ id }));
|
|
231
|
+
});
|
|
272
232
|
|
|
273
|
-
|
|
274
|
-
'lowdefy_build_status',
|
|
275
|
-
{
|
|
276
|
-
description:
|
|
277
|
-
'Call after every config edit. Returns the current build status: errors and warnings from the last build (with source file locations), plus recent browser runtime errors. The dev server rebuilds automatically on file change — edit, then call this to see what broke.',
|
|
278
|
-
inputSchema: {},
|
|
279
|
-
},
|
|
280
|
-
() => textResult(getBuildStatus())
|
|
281
|
-
);
|
|
233
|
+
registerDevTool('lowdefy_check', async () => textResult(await runCheck()));
|
|
282
234
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
pageId: z.string().describe('The page id.'),
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
async ({ pageId }) => {
|
|
293
|
-
const result = await getPageConfig({ pageId });
|
|
294
|
-
if (result === null) {
|
|
295
|
-
return notFoundResult(
|
|
296
|
-
`Page "${pageId}" not found. Use lowdefy_overview or check pageRegistry for valid page ids.`
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
return textResult(result);
|
|
235
|
+
registerDevTool('lowdefy_build_status', async ({ wait }) => {
|
|
236
|
+
if (wait === true) {
|
|
237
|
+
const proxyWait = readProxyBuildWait({
|
|
238
|
+
getHeader: (name) => honoContext?.req.header(name),
|
|
239
|
+
});
|
|
240
|
+
return textResult(await getBuildStatusAfterEdits({ proxyWait }));
|
|
300
241
|
}
|
|
301
|
-
|
|
242
|
+
return textResult(await getBuildStatus());
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
registerDevTool('lowdefy_get_page_config', async ({ pageId }) => {
|
|
246
|
+
const result = await getPageConfig({ pageId });
|
|
247
|
+
if (result === null) {
|
|
248
|
+
return notFoundResult(
|
|
249
|
+
`Page "${pageId}" not found. Use lowdefy_overview or check pageRegistry for valid page ids.`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
return textResult(result);
|
|
253
|
+
});
|
|
302
254
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
{
|
|
306
|
-
description:
|
|
307
|
-
'Find where a config entity is defined: pass a page, block, or request id and get the source yaml file (and line where available). For block/request ids also pass the owning pageId so the page is built first.',
|
|
308
|
-
inputSchema: {
|
|
309
|
-
id: z.string().describe('The id to find, e.g. a pageId, blockId, or requestId.'),
|
|
310
|
-
pageId: z
|
|
311
|
-
.string()
|
|
312
|
-
.optional()
|
|
313
|
-
.describe(
|
|
314
|
-
'The page the id belongs to — required for block/request ids on pages not yet built.'
|
|
315
|
-
),
|
|
316
|
-
},
|
|
317
|
-
},
|
|
318
|
-
async ({ id, pageId }) => textResult(await findConfig({ id, pageId }))
|
|
255
|
+
registerDevTool('lowdefy_find_config', async ({ id, pageId }) =>
|
|
256
|
+
textResult(await findConfig({ id, pageId }))
|
|
319
257
|
);
|
|
320
258
|
|
|
321
|
-
|
|
259
|
+
registerDevTool(
|
|
322
260
|
'lowdefy_screenshot_page',
|
|
323
|
-
{
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
"Crop to a viewport-relative region — pass an annotation's geometry from feedback."
|
|
339
|
-
),
|
|
340
|
-
scrollX: z.number().optional().describe('Scroll offset the clip was recorded at.'),
|
|
341
|
-
scrollY: z.number().optional().describe('Scroll offset the clip was recorded at.'),
|
|
342
|
-
user: userSchema,
|
|
343
|
-
},
|
|
344
|
-
},
|
|
345
|
-
async ({ pageId, fullPage, clip, scrollX, scrollY, user }) => {
|
|
261
|
+
async ({
|
|
262
|
+
pageId,
|
|
263
|
+
pathParams,
|
|
264
|
+
urlQuery,
|
|
265
|
+
steps,
|
|
266
|
+
fullPage,
|
|
267
|
+
clip,
|
|
268
|
+
scrollX,
|
|
269
|
+
scrollY,
|
|
270
|
+
user,
|
|
271
|
+
data,
|
|
272
|
+
width,
|
|
273
|
+
height,
|
|
274
|
+
colorScheme,
|
|
275
|
+
}) => {
|
|
346
276
|
if (!origin) {
|
|
347
277
|
return notFoundResult('Screenshot unavailable: server origin unknown for this transport.');
|
|
348
278
|
}
|
|
349
279
|
const result = await screenshotPage({
|
|
350
280
|
origin,
|
|
351
281
|
pageId,
|
|
282
|
+
pathParams,
|
|
283
|
+
urlQuery,
|
|
284
|
+
steps,
|
|
352
285
|
fullPage,
|
|
353
286
|
clip,
|
|
354
287
|
scrollX,
|
|
355
288
|
scrollY,
|
|
356
289
|
user,
|
|
290
|
+
data,
|
|
291
|
+
width,
|
|
292
|
+
height,
|
|
293
|
+
colorScheme,
|
|
357
294
|
});
|
|
358
295
|
if (result.error) {
|
|
359
296
|
return notFoundResult(result.error);
|
|
360
297
|
}
|
|
361
|
-
|
|
298
|
+
const image = { type: 'image', data: result.data, mimeType: result.mimeType };
|
|
299
|
+
if (!result.failure && result.screenshots.length === 0) {
|
|
300
|
+
return { content: [image] };
|
|
301
|
+
}
|
|
302
|
+
// The final capture shows the page where the steps (or the failing step)
|
|
303
|
+
// left it; the images of `screenshot` steps follow it in step order, named
|
|
304
|
+
// in the JSON.
|
|
305
|
+
const summary = { passed: !result.failure, failure: result.failure };
|
|
306
|
+
if (result.screenshots.length > 0) {
|
|
307
|
+
summary.screenshots = result.screenshots.map(({ name }) => ({ name }));
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
content: [
|
|
311
|
+
{ type: 'text', text: JSON.stringify(summary, null, 2) },
|
|
312
|
+
image,
|
|
313
|
+
...result.screenshots.map(({ data, mimeType }) => ({ type: 'image', data, mimeType })),
|
|
314
|
+
],
|
|
315
|
+
};
|
|
362
316
|
}
|
|
363
317
|
);
|
|
364
318
|
|
|
365
|
-
|
|
366
|
-
'
|
|
367
|
-
{
|
|
368
|
-
|
|
369
|
-
'
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
319
|
+
registerDevTool(
|
|
320
|
+
'lowdefy_run_journey',
|
|
321
|
+
async ({ pageId, pathParams, steps, user, urlQuery, state, timeout, data, exercised }) => {
|
|
322
|
+
if (!origin) {
|
|
323
|
+
return notFoundResult('Journey unavailable: server origin unknown for this transport.');
|
|
324
|
+
}
|
|
325
|
+
const { error: userError } = validateJourneyUser({ user, data });
|
|
326
|
+
if (userError) {
|
|
327
|
+
return notFoundResult(userError);
|
|
328
|
+
}
|
|
329
|
+
// One params object for both branches, so neither can drop a parameter
|
|
330
|
+
// the other passes. basePath is read as the HTTP route reads it, so
|
|
331
|
+
// expect.calls counts and app errors match under a basePath.
|
|
332
|
+
const params = {
|
|
333
|
+
origin,
|
|
334
|
+
pageId,
|
|
335
|
+
pathParams,
|
|
336
|
+
steps,
|
|
337
|
+
urlQuery,
|
|
338
|
+
state,
|
|
339
|
+
stepTimeout: timeout,
|
|
340
|
+
data,
|
|
341
|
+
basePath: lowdefyConfig.basePath ?? '',
|
|
342
|
+
};
|
|
343
|
+
if (type.isArray(user)) {
|
|
344
|
+
const { passed, runs } = await runJourneyAsUsers({ ...params, users: user });
|
|
345
|
+
// Every run's screenshots follow the JSON as images, run by run in
|
|
346
|
+
// the order of the runs, each named in its run.
|
|
347
|
+
const summary = {
|
|
348
|
+
passed,
|
|
349
|
+
runs: runs.map(({ screenshots = [], exercised: runExercised, ...run }) => ({
|
|
350
|
+
...run,
|
|
351
|
+
...selectExercised({ exercised: runExercised, selection: exercised }),
|
|
352
|
+
screenshots: screenshots.map(({ name }) => ({ name })),
|
|
353
|
+
})),
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
content: [
|
|
357
|
+
{ type: 'text', text: JSON.stringify(summary, null, 2) },
|
|
358
|
+
...runs.flatMap(({ screenshots = [] }) =>
|
|
359
|
+
screenshots.map(({ data: image, mimeType }) => ({
|
|
360
|
+
type: 'image',
|
|
361
|
+
data: image,
|
|
362
|
+
mimeType,
|
|
363
|
+
}))
|
|
364
|
+
),
|
|
365
|
+
],
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
const result = await runJourney({
|
|
369
|
+
...params,
|
|
370
|
+
user,
|
|
371
|
+
// Each call is its own journey run, recorded apart from the suite's.
|
|
372
|
+
recording: { source: 'journey', run: { id: createTraceId(), by: 'agent', journey: null } },
|
|
373
|
+
});
|
|
377
374
|
if (result.error) {
|
|
378
375
|
return notFoundResult(result.error);
|
|
379
376
|
}
|
|
380
|
-
|
|
377
|
+
// The PNGs travel as image content blocks (the shape lowdefy_screenshot_page
|
|
378
|
+
// returns) so an MCP client renders them; the JSON keeps only their names.
|
|
379
|
+
const { screenshots, exercised: resultExercised, ...rest } = result;
|
|
380
|
+
const summary = {
|
|
381
|
+
...rest,
|
|
382
|
+
...selectExercised({ exercised: resultExercised, selection: exercised }),
|
|
383
|
+
screenshots: screenshots.map(({ name }) => ({ name })),
|
|
384
|
+
};
|
|
385
|
+
return {
|
|
386
|
+
content: [
|
|
387
|
+
{ type: 'text', text: JSON.stringify(summary, null, 2) },
|
|
388
|
+
...screenshots.map(({ data, mimeType }) => ({ type: 'image', data, mimeType })),
|
|
389
|
+
],
|
|
390
|
+
};
|
|
381
391
|
}
|
|
382
392
|
);
|
|
383
393
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
{
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
() => textResult(getOverview())
|
|
392
|
-
);
|
|
394
|
+
registerDevTool('lowdefy_scaffold_page', ({ pageId, title }) => {
|
|
395
|
+
const result = scaffoldPage({ pageId, title });
|
|
396
|
+
if (result.error) {
|
|
397
|
+
return notFoundResult(result.error);
|
|
398
|
+
}
|
|
399
|
+
return textResult(result);
|
|
400
|
+
});
|
|
393
401
|
|
|
394
|
-
|
|
395
|
-
'lowdefy_list_types',
|
|
396
|
-
{
|
|
397
|
-
description:
|
|
398
|
-
'List ALL available types of a kind — every block, operator, action, connection, or request type installed in this project (core and local plugins), whether used yet or not. Call this before writing any config to get exact type names.',
|
|
399
|
-
inputSchema: {
|
|
400
|
-
kind: z
|
|
401
|
-
.enum([
|
|
402
|
-
'blocks',
|
|
403
|
-
'operators',
|
|
404
|
-
'actions',
|
|
405
|
-
'connections',
|
|
406
|
-
'requests',
|
|
407
|
-
'agents',
|
|
408
|
-
'notifications',
|
|
409
|
-
'websockets',
|
|
410
|
-
])
|
|
411
|
-
.describe('The kind of types to list.'),
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
({ kind }) => textResult(listTypes({ kind }))
|
|
415
|
-
);
|
|
402
|
+
registerDevTool('lowdefy_overview', () => textResult(getOverview()));
|
|
416
403
|
|
|
417
|
-
|
|
418
|
-
'lowdefy_list_plugins',
|
|
419
|
-
{
|
|
420
|
-
description:
|
|
421
|
-
"List installed plugin packages (including this project's local custom plugins) and the type names each provides.",
|
|
422
|
-
inputSchema: {},
|
|
423
|
-
},
|
|
424
|
-
() => textResult(listPlugins())
|
|
425
|
-
);
|
|
404
|
+
registerDevTool('lowdefy_list_types', ({ kind }) => textResult(listTypes({ kind })));
|
|
426
405
|
|
|
427
|
-
|
|
428
|
-
'lowdefy_get_schema',
|
|
429
|
-
{
|
|
430
|
-
description:
|
|
431
|
-
'Get the JSON Schema for a specific type: all properties, events, and their descriptions. Use the exact type name from lowdefy_list_types.',
|
|
432
|
-
inputSchema: {
|
|
433
|
-
kind: z
|
|
434
|
-
.enum(['blocks', 'operators', 'actions', 'connections', 'requests'])
|
|
435
|
-
.describe('The kind of the type.'),
|
|
436
|
-
type: z.string().describe('The exact type name, e.g. "Button", "_get", "MongoDBFind".'),
|
|
437
|
-
},
|
|
438
|
-
},
|
|
439
|
-
({ kind, type }) => {
|
|
440
|
-
const schema = getSchema({ kind, type });
|
|
441
|
-
if (schema === null) {
|
|
442
|
-
return notFoundResult(
|
|
443
|
-
`No schema found for ${kind} type "${type}". Use lowdefy_list_types to see available types.`
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
return textResult(schema);
|
|
447
|
-
}
|
|
448
|
-
);
|
|
406
|
+
registerDevTool('lowdefy_list_plugins', () => textResult(listPlugins()));
|
|
449
407
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
{
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
type: z.string().describe('The exact block type name, e.g. "Button".'),
|
|
457
|
-
},
|
|
458
|
-
},
|
|
459
|
-
({ type }) => {
|
|
460
|
-
const examples = getExamples({ type });
|
|
461
|
-
if (examples === null) {
|
|
462
|
-
return notFoundResult(
|
|
463
|
-
`No examples shipped for block type "${type}". Use lowdefy_get_schema for its contract, or lowdefy_get_doc for its documentation page.`
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
return textResult(examples);
|
|
408
|
+
registerDevTool('lowdefy_get_schema', ({ kind, type }) => {
|
|
409
|
+
const schema = getSchema({ kind, type });
|
|
410
|
+
if (schema === null) {
|
|
411
|
+
return notFoundResult(
|
|
412
|
+
`No schema found for ${kind} type "${type}". Use lowdefy_list_types to see available types.`
|
|
413
|
+
);
|
|
467
414
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
{
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
kind: z
|
|
478
|
-
.enum(['block', 'operator', 'action', 'connection'])
|
|
479
|
-
.optional()
|
|
480
|
-
.describe('Kind of the type to find the doc for.'),
|
|
481
|
-
type: z.string().optional().describe('Type name to find the doc for, e.g. "_get".'),
|
|
482
|
-
},
|
|
483
|
-
},
|
|
484
|
-
({ slug, kind, type }) => {
|
|
485
|
-
const doc = getCoreDoc({ slug, kind, type });
|
|
486
|
-
if (doc === null) {
|
|
487
|
-
return notFoundResult(
|
|
488
|
-
`No doc found${slug ? ` for slug "${slug}"` : ''}${
|
|
489
|
-
type ? ` for type "${type}"` : ''
|
|
490
|
-
}. Use lowdefy_search_docs to find the right slug.`
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
return textResult(doc.markdown);
|
|
415
|
+
return textResult(schema);
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
registerDevTool('lowdefy_get_examples', ({ type }) => {
|
|
419
|
+
const examples = getExamples({ type });
|
|
420
|
+
if (examples === null) {
|
|
421
|
+
return notFoundResult(
|
|
422
|
+
`No examples shipped for block type "${type}". Use lowdefy_get_schema for its contract, or lowdefy_get_doc for its documentation page.`
|
|
423
|
+
);
|
|
494
424
|
}
|
|
425
|
+
return textResult(examples);
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
registerDevTool('lowdefy_get_doc', ({ slug, kind, type }) => {
|
|
429
|
+
const doc = getDoc({ slug, kind, type });
|
|
430
|
+
if (doc === null) {
|
|
431
|
+
return notFoundResult(
|
|
432
|
+
`No doc found${slug ? ` for slug "${slug}"` : ''}${
|
|
433
|
+
type ? ` for type "${type}"` : ''
|
|
434
|
+
}. Use lowdefy_search_docs to find the right slug.`
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
return textResult(appendHazards(doc));
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
registerDevTool('lowdefy_search_docs', ({ query, source }) =>
|
|
441
|
+
textResult(searchDocs({ query, source }))
|
|
495
442
|
);
|
|
496
443
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
{
|
|
500
|
-
description: 'Search the core Lowdefy docs by keyword. Returns matching slugs with snippets.',
|
|
501
|
-
inputSchema: {
|
|
502
|
-
query: z.string().describe('Search keywords.'),
|
|
503
|
-
},
|
|
504
|
-
},
|
|
505
|
-
({ query }) => textResult(searchDocs({ query }))
|
|
444
|
+
registerDevTool('lowdefy_search_icons', async ({ query, limit }) =>
|
|
445
|
+
textResult(await searchIcons({ query, limit }))
|
|
506
446
|
);
|
|
507
447
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
{
|
|
511
|
-
|
|
512
|
-
"
|
|
513
|
-
|
|
514
|
-
package: z.string().describe('The package name, e.g. "@lowdefy/blocks-antd".'),
|
|
515
|
-
},
|
|
516
|
-
},
|
|
517
|
-
({ package: packageName }) => {
|
|
518
|
-
const doc = getPluginDoc({ packageName });
|
|
519
|
-
if (doc === null) {
|
|
520
|
-
return notFoundResult(
|
|
521
|
-
`Package "${packageName}" ships no markdown docs. Use lowdefy_list_types and lowdefy_get_schema for its types.`
|
|
522
|
-
);
|
|
523
|
-
}
|
|
524
|
-
return textResult(doc.markdown);
|
|
448
|
+
registerDevTool('lowdefy_get_plugin_doc', ({ package: packageName }) => {
|
|
449
|
+
const doc = getPluginDoc({ packageName });
|
|
450
|
+
if (doc === null) {
|
|
451
|
+
return notFoundResult(
|
|
452
|
+
`Package "${packageName}" ships no markdown docs. Use lowdefy_list_types and lowdefy_get_schema for its types.`
|
|
453
|
+
);
|
|
525
454
|
}
|
|
526
|
-
|
|
455
|
+
return textResult(doc.markdown);
|
|
456
|
+
});
|
|
527
457
|
|
|
458
|
+
registerDevTool('lowdefy_journey_session', ({ id, since }) => {
|
|
459
|
+
const result = readJourneySession({ id, since });
|
|
460
|
+
if (!type.isUndefined(result.error)) {
|
|
461
|
+
return notFoundResult(result.error);
|
|
462
|
+
}
|
|
463
|
+
return textResult(result.text);
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
const unregistered = Object.keys(devToolDefinitions).filter((name) => !registered.has(name));
|
|
467
|
+
if (unregistered.length > 0) {
|
|
468
|
+
throw new Error(`Dev tools defined without a handler: ${unregistered.join(', ')}.`);
|
|
469
|
+
}
|
|
528
470
|
return server;
|
|
529
471
|
}
|
|
530
472
|
|
|
473
|
+
// Forwards dev events to one connected MCP client as notifications/message
|
|
474
|
+
// (the only server→client notification MCP clients surface generically; it
|
|
475
|
+
// needs the logging capability declared above). Build failures go out at
|
|
476
|
+
// error level so clients that filter by level still see them.
|
|
477
|
+
function subscribeMcpServerToDevEvents(server) {
|
|
478
|
+
return subscribeToDevEvents((event) =>
|
|
479
|
+
server.server.sendLoggingMessage({
|
|
480
|
+
level: event.type === 'build' && event.status === 'error' ? 'error' : 'info',
|
|
481
|
+
logger: 'lowdefy',
|
|
482
|
+
data: event,
|
|
483
|
+
})
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
export { subscribeMcpServerToDevEvents };
|
|
531
488
|
export default createDocsMcpServer;
|