@codeyam/codeyam-cli 0.1.0-staging.ae0de75 → 0.1.0-staging.b49802d
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/analyzer-template/.build-info.json +8 -8
- package/analyzer-template/log.txt +3 -3
- package/analyzer-template/package.json +9 -9
- package/analyzer-template/packages/ai/package.json +1 -1
- package/analyzer-template/packages/ai/src/lib/astScopes/methodSemantics.ts +135 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/nodeToSource.ts +19 -0
- package/analyzer-template/packages/ai/src/lib/astScopes/paths.ts +11 -4
- package/analyzer-template/packages/ai/src/lib/dataStructure/ScopeDataStructure.ts +36 -9
- package/analyzer-template/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.ts +10 -3
- package/analyzer-template/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.ts +16 -6
- package/analyzer-template/packages/ai/src/lib/generateExecutionFlows.ts +0 -33
- package/analyzer-template/packages/analyze/index.ts +4 -1
- package/analyzer-template/packages/analyze/src/lib/ProjectAnalyzer.ts +13 -7
- package/analyzer-template/packages/analyze/src/lib/asts/index.ts +7 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.ts +28 -2
- package/analyzer-template/packages/analyze/src/lib/files/analyze/analyzeEntities.ts +5 -36
- package/analyzer-template/packages/analyze/src/lib/files/analyze/findOrCreateEntity.ts +10 -6
- package/analyzer-template/packages/analyze/src/lib/files/analyze/gatherEntityMap.ts +9 -12
- package/analyzer-template/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.ts +21 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.ts +82 -10
- package/analyzer-template/packages/analyze/src/lib/files/analyzeChange.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyzeInitial.ts +4 -0
- package/analyzer-template/packages/analyze/src/lib/files/analyzeNextRoute.ts +8 -3
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateDataStructure.ts +239 -58
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.ts +0 -98
- package/analyzer-template/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.ts +1684 -1462
- package/analyzer-template/packages/aws/package.json +7 -7
- package/analyzer-template/packages/database/package.json +3 -3
- package/analyzer-template/packages/database/src/lib/kysely/tables/editorScenariosTable.ts +102 -0
- package/analyzer-template/packages/database/src/lib/loadAnalysis.ts +25 -15
- package/analyzer-template/packages/database/src/lib/loadEntities.ts +0 -6
- package/analyzer-template/packages/database/src/lib/loadEntity.ts +19 -8
- package/analyzer-template/packages/database/src/lib/updateCommitMetadata.ts +0 -65
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts +9 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js +104 -0
- package/analyzer-template/packages/github/dist/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js +7 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadAnalysis.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js +0 -6
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntities.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts +4 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js +5 -5
- package/analyzer-template/packages/github/dist/database/src/lib/loadEntity.js.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js +0 -25
- package/analyzer-template/packages/github/dist/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts +2 -0
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js +2 -0
- package/analyzer-template/packages/github/dist/types/src/enums/ProjectFramework.js.map +1 -1
- package/analyzer-template/packages/types/src/enums/ProjectFramework.ts +2 -0
- package/analyzer-template/packages/ui-components/package.json +1 -1
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts +2 -0
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js +2 -0
- package/analyzer-template/packages/utils/dist/types/src/enums/ProjectFramework.js.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts +3 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.d.ts.map +1 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/analyzer-template/packages/utils/dist/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/analyzer-template/packages/utils/src/lib/fs/rsyncCopy.ts +27 -0
- package/analyzer-template/project/analyzeFileEntities.ts +26 -0
- package/analyzer-template/project/runMultiScenarioServer.ts +26 -3
- package/background/src/lib/virtualized/project/analyzeFileEntities.js +22 -0
- package/background/src/lib/virtualized/project/analyzeFileEntities.js.map +1 -1
- package/background/src/lib/virtualized/project/runMultiScenarioServer.js +23 -3
- package/background/src/lib/virtualized/project/runMultiScenarioServer.js.map +1 -1
- package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js +196 -0
- package/codeyam-cli/src/__tests__/memory-scripts/filter-session.test.js.map +1 -0
- package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js +114 -0
- package/codeyam-cli/src/__tests__/memory-scripts/read-json-field.test.js.map +1 -0
- package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js +149 -0
- package/codeyam-cli/src/__tests__/memory-scripts/ripgrep-fallback.test.js.map +1 -0
- package/codeyam-cli/src/cli.js +24 -0
- package/codeyam-cli/src/cli.js.map +1 -1
- package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js +47 -0
- package/codeyam-cli/src/commands/__tests__/editor.analyzeImportsArgs.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js +71 -0
- package/codeyam-cli/src/commands/__tests__/editor.auditNoAutoAnalysis.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js +30 -0
- package/codeyam-cli/src/commands/__tests__/editor.designSystem.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js +51 -0
- package/codeyam-cli/src/commands/__tests__/editor.isolateArgs.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js +55 -0
- package/codeyam-cli/src/commands/__tests__/editor.statePersistence.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js +56 -0
- package/codeyam-cli/src/commands/__tests__/editor.stepDispatch.test.js.map +1 -0
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js +137 -47
- package/codeyam-cli/src/commands/__tests__/init.gitignore.test.js.map +1 -1
- package/codeyam-cli/src/commands/default.js +3 -46
- package/codeyam-cli/src/commands/default.js.map +1 -1
- package/codeyam-cli/src/commands/editor.js +5268 -794
- package/codeyam-cli/src/commands/editor.js.map +1 -1
- package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js +23 -0
- package/codeyam-cli/src/commands/editorAnalyzeImportsArgs.js.map +1 -0
- package/codeyam-cli/src/commands/editorIsolateArgs.js +25 -0
- package/codeyam-cli/src/commands/editorIsolateArgs.js.map +1 -0
- package/codeyam-cli/src/commands/init.js +89 -34
- package/codeyam-cli/src/commands/init.js.map +1 -1
- package/codeyam-cli/src/commands/telemetry.js +37 -0
- package/codeyam-cli/src/commands/telemetry.js.map +1 -0
- package/codeyam-cli/src/data/designSystems.js +27 -0
- package/codeyam-cli/src/data/designSystems.js.map +1 -0
- package/codeyam-cli/src/data/techStacks.js +77 -0
- package/codeyam-cli/src/data/techStacks.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js +173 -0
- package/codeyam-cli/src/utils/__tests__/analyzerFinalization.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js +46 -0
- package/codeyam-cli/src/utils/__tests__/backgroundServer.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/devServerState.test.js +226 -0
- package/codeyam-cli/src/utils/__tests__/devServerState.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorApi.test.js +181 -0
- package/codeyam-cli/src/utils/__tests__/editorApi.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js +3915 -1
- package/codeyam-cli/src/utils/__tests__/editorAudit.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js +76 -0
- package/codeyam-cli/src/utils/__tests__/editorBroadcastViewport.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorCapture.test.js +93 -0
- package/codeyam-cli/src/utils/__tests__/editorCapture.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js +137 -0
- package/codeyam-cli/src/utils/__tests__/editorCaptureScenarioSeeding.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js +100 -0
- package/codeyam-cli/src/utils/__tests__/editorDeleteScenario.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js +181 -3
- package/codeyam-cli/src/utils/__tests__/editorDevServer.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js +194 -0
- package/codeyam-cli/src/utils/__tests__/editorEntityChangeStatus.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js +381 -0
- package/codeyam-cli/src/utils/__tests__/editorEntityHelpers.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js +67 -0
- package/codeyam-cli/src/utils/__tests__/editorGuardMiddleware.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js +294 -0
- package/codeyam-cli/src/utils/__tests__/editorImageVerifier.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorJournal.test.js +249 -2
- package/codeyam-cli/src/utils/__tests__/editorJournal.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js +594 -0
- package/codeyam-cli/src/utils/__tests__/editorLoaderHelpers.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorMigration.test.js +435 -0
- package/codeyam-cli/src/utils/__tests__/editorMigration.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js +118 -1
- package/codeyam-cli/src/utils/__tests__/editorPreloadHelpers.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js +217 -3
- package/codeyam-cli/src/utils/__tests__/editorPreview.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js +250 -0
- package/codeyam-cli/src/utils/__tests__/editorProxySession.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js +1108 -0
- package/codeyam-cli/src/utils/__tests__/editorRoadmap.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js +139 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioLookup.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js +411 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarioSwitch.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js +1694 -2
- package/codeyam-cli/src/utils/__tests__/editorScenarios.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js +413 -0
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapter.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js +143 -0
- package/codeyam-cli/src/utils/__tests__/editorSeedAdapterPrismaValidation.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js +66 -0
- package/codeyam-cli/src/utils/__tests__/editorSessionFilter.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js +53 -0
- package/codeyam-cli/src/utils/__tests__/editorShouldRevalidate.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js +2121 -0
- package/codeyam-cli/src/utils/__tests__/entityChangeStatus.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/envFile.test.js +125 -0
- package/codeyam-cli/src/utils/__tests__/envFile.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js +177 -0
- package/codeyam-cli/src/utils/__tests__/glossaryAdd.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/handoffContext.test.js +500 -0
- package/codeyam-cli/src/utils/__tests__/handoffContext.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js +122 -0
- package/codeyam-cli/src/utils/__tests__/journalCaptureStabilization.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js +302 -0
- package/codeyam-cli/src/utils/__tests__/manualEntityAnalysis.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js +129 -0
- package/codeyam-cli/src/utils/__tests__/parseRegisterArg.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js +127 -0
- package/codeyam-cli/src/utils/__tests__/registerScenarioResult.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js +118 -0
- package/codeyam-cli/src/utils/__tests__/routePatternMatching.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js +284 -0
- package/codeyam-cli/src/utils/__tests__/scenarioCoverage.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js +672 -0
- package/codeyam-cli/src/utils/__tests__/scenariosManifest.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/screenshotHash.test.js +84 -0
- package/codeyam-cli/src/utils/__tests__/screenshotHash.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js +26 -5
- package/codeyam-cli/src/utils/__tests__/setupClaudeCodeSettings.test.js.map +1 -1
- package/codeyam-cli/src/utils/__tests__/telemetry.test.js +159 -0
- package/codeyam-cli/src/utils/__tests__/telemetry.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js +51 -0
- package/codeyam-cli/src/utils/__tests__/templateConsistency.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/testRunner.test.js +216 -0
- package/codeyam-cli/src/utils/__tests__/testRunner.test.js.map +1 -0
- package/codeyam-cli/src/utils/__tests__/webappDetection.test.js +148 -0
- package/codeyam-cli/src/utils/__tests__/webappDetection.test.js.map +1 -0
- package/codeyam-cli/src/utils/analysisRunner.js +39 -8
- package/codeyam-cli/src/utils/analysisRunner.js.map +1 -1
- package/codeyam-cli/src/utils/analyzer.js +19 -0
- package/codeyam-cli/src/utils/analyzer.js.map +1 -1
- package/codeyam-cli/src/utils/analyzerFinalization.js +100 -0
- package/codeyam-cli/src/utils/analyzerFinalization.js.map +1 -0
- package/codeyam-cli/src/utils/backgroundServer.js +95 -19
- package/codeyam-cli/src/utils/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/utils/database.js +37 -2
- package/codeyam-cli/src/utils/database.js.map +1 -1
- package/codeyam-cli/src/utils/designSystemShowcase.js +810 -0
- package/codeyam-cli/src/utils/designSystemShowcase.js.map +1 -0
- package/codeyam-cli/src/utils/devServerState.js +103 -0
- package/codeyam-cli/src/utils/devServerState.js.map +1 -0
- package/codeyam-cli/src/utils/editorApi.js +95 -0
- package/codeyam-cli/src/utils/editorApi.js.map +1 -0
- package/codeyam-cli/src/utils/editorAudit.js +780 -13
- package/codeyam-cli/src/utils/editorAudit.js.map +1 -1
- package/codeyam-cli/src/utils/editorBroadcastViewport.js +26 -0
- package/codeyam-cli/src/utils/editorBroadcastViewport.js.map +1 -0
- package/codeyam-cli/src/utils/editorCapture.js +102 -0
- package/codeyam-cli/src/utils/editorCapture.js.map +1 -0
- package/codeyam-cli/src/utils/editorDeleteScenario.js +67 -0
- package/codeyam-cli/src/utils/editorDeleteScenario.js.map +1 -0
- package/codeyam-cli/src/utils/editorDevServer.js +100 -1
- package/codeyam-cli/src/utils/editorDevServer.js.map +1 -1
- package/codeyam-cli/src/utils/editorEntityChangeStatus.js +50 -0
- package/codeyam-cli/src/utils/editorEntityChangeStatus.js.map +1 -0
- package/codeyam-cli/src/utils/editorEntityHelpers.js +144 -0
- package/codeyam-cli/src/utils/editorEntityHelpers.js.map +1 -0
- package/codeyam-cli/src/utils/editorGuard.js +36 -0
- package/codeyam-cli/src/utils/editorGuard.js.map +1 -0
- package/codeyam-cli/src/utils/editorImageVerifier.js +155 -0
- package/codeyam-cli/src/utils/editorImageVerifier.js.map +1 -0
- package/codeyam-cli/src/utils/editorJournal.js +92 -4
- package/codeyam-cli/src/utils/editorJournal.js.map +1 -1
- package/codeyam-cli/src/utils/editorLoaderHelpers.js +152 -0
- package/codeyam-cli/src/utils/editorLoaderHelpers.js.map +1 -0
- package/codeyam-cli/src/utils/editorMigration.js +224 -0
- package/codeyam-cli/src/utils/editorMigration.js.map +1 -0
- package/codeyam-cli/src/utils/editorMockState.js +1 -1
- package/codeyam-cli/src/utils/editorPreloadHelpers.js +72 -1
- package/codeyam-cli/src/utils/editorPreloadHelpers.js.map +1 -1
- package/codeyam-cli/src/utils/editorPreview.js +74 -1
- package/codeyam-cli/src/utils/editorPreview.js.map +1 -1
- package/codeyam-cli/src/utils/editorRecapture.js +109 -0
- package/codeyam-cli/src/utils/editorRecapture.js.map +1 -0
- package/codeyam-cli/src/utils/editorRoadmap.js +574 -0
- package/codeyam-cli/src/utils/editorRoadmap.js.map +1 -0
- package/codeyam-cli/src/utils/editorScenarioSwitch.js +149 -0
- package/codeyam-cli/src/utils/editorScenarioSwitch.js.map +1 -0
- package/codeyam-cli/src/utils/editorScenarios.js +631 -0
- package/codeyam-cli/src/utils/editorScenarios.js.map +1 -1
- package/codeyam-cli/src/utils/editorSeedAdapter.js +475 -0
- package/codeyam-cli/src/utils/editorSeedAdapter.js.map +1 -0
- package/codeyam-cli/src/utils/editorShouldRevalidate.js +21 -0
- package/codeyam-cli/src/utils/editorShouldRevalidate.js.map +1 -0
- package/codeyam-cli/src/utils/entityChangeStatus.js +394 -0
- package/codeyam-cli/src/utils/entityChangeStatus.js.map +1 -0
- package/codeyam-cli/src/utils/entityChangeStatus.server.js +227 -0
- package/codeyam-cli/src/utils/entityChangeStatus.server.js.map +1 -0
- package/codeyam-cli/src/utils/envFile.js +90 -0
- package/codeyam-cli/src/utils/envFile.js.map +1 -0
- package/codeyam-cli/src/utils/fileWatcher.js +38 -0
- package/codeyam-cli/src/utils/fileWatcher.js.map +1 -1
- package/codeyam-cli/src/utils/glossaryAdd.js +74 -0
- package/codeyam-cli/src/utils/glossaryAdd.js.map +1 -0
- package/codeyam-cli/src/utils/handoffContext.js +257 -0
- package/codeyam-cli/src/utils/handoffContext.js.map +1 -0
- package/codeyam-cli/src/utils/install-skills.js +51 -7
- package/codeyam-cli/src/utils/install-skills.js.map +1 -1
- package/codeyam-cli/src/utils/manualEntityAnalysis.js +196 -0
- package/codeyam-cli/src/utils/manualEntityAnalysis.js.map +1 -0
- package/codeyam-cli/src/utils/parseRegisterArg.js +31 -0
- package/codeyam-cli/src/utils/parseRegisterArg.js.map +1 -0
- package/codeyam-cli/src/utils/progress.js +2 -2
- package/codeyam-cli/src/utils/progress.js.map +1 -1
- package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js +159 -0
- package/codeyam-cli/src/utils/queue/__tests__/job.interactiveStart.test.js.map +1 -0
- package/codeyam-cli/src/utils/queue/job.js +35 -6
- package/codeyam-cli/src/utils/queue/job.js.map +1 -1
- package/codeyam-cli/src/utils/registerScenarioResult.js +52 -0
- package/codeyam-cli/src/utils/registerScenarioResult.js.map +1 -0
- package/codeyam-cli/src/utils/routePatternMatching.js +129 -0
- package/codeyam-cli/src/utils/routePatternMatching.js.map +1 -0
- package/codeyam-cli/src/utils/scenarioCoverage.js +77 -0
- package/codeyam-cli/src/utils/scenarioCoverage.js.map +1 -0
- package/codeyam-cli/src/utils/scenariosManifest.js +313 -0
- package/codeyam-cli/src/utils/scenariosManifest.js.map +1 -0
- package/codeyam-cli/src/utils/screenshotHash.js +26 -0
- package/codeyam-cli/src/utils/screenshotHash.js.map +1 -0
- package/codeyam-cli/src/utils/serverState.js +30 -0
- package/codeyam-cli/src/utils/serverState.js.map +1 -1
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js +47 -16
- package/codeyam-cli/src/utils/setupClaudeCodeSettings.js.map +1 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js +17 -1
- package/codeyam-cli/src/utils/simulationGateMiddleware.js.map +1 -1
- package/codeyam-cli/src/utils/slugUtils.js +25 -0
- package/codeyam-cli/src/utils/slugUtils.js.map +1 -0
- package/codeyam-cli/src/utils/syncMocksMiddleware.js +2 -2
- package/codeyam-cli/src/utils/syncMocksMiddleware.js.map +1 -1
- package/codeyam-cli/src/utils/techStackConfig.js +38 -0
- package/codeyam-cli/src/utils/techStackConfig.js.map +1 -0
- package/codeyam-cli/src/utils/techStackConfig.test.js +85 -0
- package/codeyam-cli/src/utils/techStackConfig.test.js.map +1 -0
- package/codeyam-cli/src/utils/telemetry.js +106 -0
- package/codeyam-cli/src/utils/telemetry.js.map +1 -0
- package/codeyam-cli/src/utils/telemetryMiddleware.js +22 -0
- package/codeyam-cli/src/utils/telemetryMiddleware.js.map +1 -0
- package/codeyam-cli/src/utils/testResultCache.js +53 -0
- package/codeyam-cli/src/utils/testResultCache.js.map +1 -0
- package/codeyam-cli/src/utils/testResultCache.server.js +81 -0
- package/codeyam-cli/src/utils/testResultCache.server.js.map +1 -0
- package/codeyam-cli/src/utils/testResultCache.server.test.js +187 -0
- package/codeyam-cli/src/utils/testResultCache.server.test.js.map +1 -0
- package/codeyam-cli/src/utils/testResultCache.test.js +230 -0
- package/codeyam-cli/src/utils/testResultCache.test.js.map +1 -0
- package/codeyam-cli/src/utils/testRunner.js +193 -1
- package/codeyam-cli/src/utils/testRunner.js.map +1 -1
- package/codeyam-cli/src/utils/webappDetection.js +25 -2
- package/codeyam-cli/src/utils/webappDetection.js.map +1 -1
- package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js +99 -0
- package/codeyam-cli/src/webserver/__tests__/api.interactive-switch-scenario.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js +153 -0
- package/codeyam-cli/src/webserver/__tests__/buildPtyEnv.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js +107 -0
- package/codeyam-cli/src/webserver/__tests__/clientErrors.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js +1000 -0
- package/codeyam-cli/src/webserver/__tests__/editorProxy.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js +315 -0
- package/codeyam-cli/src/webserver/__tests__/idleDetector.test.js.map +1 -0
- package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js +135 -0
- package/codeyam-cli/src/webserver/__tests__/stripClaudeCommand.test.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js +86 -0
- package/codeyam-cli/src/webserver/app/lib/clientErrors.js.map +1 -0
- package/codeyam-cli/src/webserver/app/lib/database.js.map +1 -1
- package/codeyam-cli/src/webserver/app/lib/git.js +397 -0
- package/codeyam-cli/src/webserver/app/lib/git.js.map +1 -0
- package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js +34 -0
- package/codeyam-cli/src/webserver/app/routes/api.interactive-switch-scenario.js.map +1 -0
- package/codeyam-cli/src/webserver/app/types/editor.js +8 -0
- package/codeyam-cli/src/webserver/app/types/editor.js.map +1 -0
- package/codeyam-cli/src/webserver/backgroundServer.js +60 -61
- package/codeyam-cli/src/webserver/backgroundServer.js.map +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DTBZZfSk.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityItem-C76mRRiF.js → EntityItem-BxclONWq.js} +5 -5
- package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-CQgyEGV-.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{EntityTypeIcon-CobE682z.js → EntityTypeIcon-BsnEOJZ_.js} +9 -9
- package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-ByaELMbv.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-6WjVfhxX.js +25 -0
- package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-ChX-Hp7W.js +3 -0
- package/codeyam-cli/src/webserver/build/client/assets/{LoadingDots-BU_OAEMP.js → LoadingDots-By5zI316.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/{LogViewer-ceAyBX-H.js → LogViewer-C-9zQdXg.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/MiniClaudeChat-Bs2_Oua4.js +36 -0
- package/codeyam-cli/src/webserver/build/client/assets/{ReportIssueModal-djPLI-WV.js → ReportIssueModal-DQsceHVv.js} +4 -4
- package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-DThcm_9M.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{ScenarioViewer-B76aig_2.js → ScenarioViewer-Cl4oOA3A.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/Spinner-CIil5-gb.js +34 -0
- package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-CK7-NaPZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/ViewportInspectBar-BqkA9zyZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{_index-C96V0n15.js → _index-DnOgyseQ.js} +4 -4
- package/codeyam-cli/src/webserver/build/client/assets/{activity.(_tab)-BpKzcsJz.js → activity.(_tab)-DqM9hbNE.js} +8 -8
- package/codeyam-cli/src/webserver/build/client/assets/addon-canvas-DpzMmAy5.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/addon-fit-YJmn1quW.js +12 -0
- package/codeyam-cli/src/webserver/build/client/assets/{addon-web-links-Duc5hnl7.js → addon-web-links-C58dYPwR.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/addon-webgl-DI8QOUvO.js +58 -0
- package/codeyam-cli/src/webserver/build/client/assets/{agent-transcripts-D9hemwl6.js → agent-transcripts-B8NCeOrm.js} +7 -7
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-database-verify-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-diff-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-file-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-github-verify-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-handoff-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-hosting-verify-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-project-info-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-recapture-stale-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-rename-scenario-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-roadmap-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-scenario-data-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-save-seed-state-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-coverage-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-scenario-prompt-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-schema-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-session-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.editor-verify-routes-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/api.interactive-switch-scenario-l0sNRNKZ.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{book-open-D_nMCFmP.js → book-open-BFSIqZgO.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{chevron-down-BH2h1Ea2.js → chevron-down-B9fDzFVh.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/chunk-UVKPFVEO-Bmq2apuh.js +43 -0
- package/codeyam-cli/src/webserver/build/client/assets/{circle-check-DyIKORY6.js → circle-check-DLPObLUx.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{copy-NDbZjXao.js → copy-DXEmO0TD.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-BwyFiRot.js +41 -0
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-Coe5NhbS.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{cy-logo-cli-CCKUIm0S.svg → cy-logo-cli-DoA97ML3.svg} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-iRhRIFlp.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/editor._tab-BZPBzV73.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/editor.entity.(_sha)-DhtVC4aI.js +161 -0
- package/codeyam-cli/src/webserver/build/client/assets/editorPreview-C6fEYHrh.js +41 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha._-CrjR3zZW.js → entity._sha._-pc-vc6wO.js} +14 -13
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-C8AyYgYT.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-DziaVQX1.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-BTcpgIpC.js +6 -0
- package/codeyam-cli/src/webserver/build/client/assets/{entity._sha_.edit._scenarioId-BMvVHNXU.js → entity._sha_.edit._scenarioId-D_O_ajfZ.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/{entry.client-DTvKq3TY.js → entry.client-j1Vi0bco.js} +6 -6
- package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-Daa96Fr1.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/files-kuny2Q_s.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/git-DgCZPMie.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/globals-L-aUIeux.css +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-BcvgDzbZ.js → index-BliGSSpl.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/index-SqjQKTdH.js +15 -0
- package/codeyam-cli/src/webserver/build/client/assets/{index-10oVnAAH.js → index-vyrZD2g4.js} +1 -1
- package/codeyam-cli/src/webserver/build/client/assets/jsx-runtime-D_zvdyIk.js +9 -0
- package/codeyam-cli/src/webserver/build/client/assets/labs-c3yLxSEp.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{loader-circle-BAXYRVEO.js → loader-circle-D-q28GLF.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/manifest-79d0d81a.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/memory-CEWIUC4t.js +101 -0
- package/codeyam-cli/src/webserver/build/client/assets/{pause-DTAcYxBt.js → pause-BP6fitdh.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/root-L2V0jea7.js +80 -0
- package/codeyam-cli/src/webserver/build/client/assets/{search-fKo7v0Zo.js → search-BooqacKS.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/settings-BM0nbryO.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/simulations-ovy6FjRY.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/{terminal-BG4heKCG.js → terminal-DHemCJIs.js} +3 -3
- package/codeyam-cli/src/webserver/build/client/assets/{triangle-alert-DtSmdtM4.js → triangle-alert-D87ekDl8.js} +2 -2
- package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-Dk0Tciqg.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-C8QvIe05.js +2 -0
- package/codeyam-cli/src/webserver/build/client/assets/useReportContext-jkCytuYz.js +1 -0
- package/codeyam-cli/src/webserver/build/client/assets/useToast-BgqkixU9.js +1 -0
- package/codeyam-cli/src/webserver/build/client/sound-test.html +98 -0
- package/codeyam-cli/src/webserver/build/server/assets/analysisRunner-QgInFGdU.js +16 -0
- package/codeyam-cli/src/webserver/build/server/assets/index-zblh9auj.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/init-DaE0CBjk.js +14 -0
- package/codeyam-cli/src/webserver/build/server/assets/progress-CHTtrxFG.js +1 -0
- package/codeyam-cli/src/webserver/build/server/assets/server-build-CNvgz1cC.js +853 -0
- package/codeyam-cli/src/webserver/build/server/index.js +1 -1
- package/codeyam-cli/src/webserver/build-info.json +5 -5
- package/codeyam-cli/src/webserver/editorProxy.js +877 -54
- package/codeyam-cli/src/webserver/editorProxy.js.map +1 -1
- package/codeyam-cli/src/webserver/idleDetector.js +130 -0
- package/codeyam-cli/src/webserver/idleDetector.js.map +1 -0
- package/codeyam-cli/src/webserver/mockStateEvents.js +28 -0
- package/codeyam-cli/src/webserver/mockStateEvents.js.map +1 -0
- package/codeyam-cli/src/webserver/public/sound-test.html +98 -0
- package/codeyam-cli/src/webserver/scripts/codeyam-preload.mjs +242 -3
- package/codeyam-cli/src/webserver/scripts/journalCapture.ts +147 -4
- package/codeyam-cli/src/webserver/server.js +236 -16
- package/codeyam-cli/src/webserver/server.js.map +1 -1
- package/codeyam-cli/src/webserver/terminalServer.js +422 -58
- package/codeyam-cli/src/webserver/terminalServer.js.map +1 -1
- package/codeyam-cli/templates/__tests__/editor-step-hook.prompt-capture.test.ts +118 -0
- package/codeyam-cli/templates/chrome-extension-react/EXTENSION_SETUP.md +75 -0
- package/codeyam-cli/templates/chrome-extension-react/README.md +46 -0
- package/codeyam-cli/templates/chrome-extension-react/gitignore +15 -0
- package/codeyam-cli/templates/chrome-extension-react/index.html +12 -0
- package/codeyam-cli/templates/chrome-extension-react/package.json +27 -0
- package/codeyam-cli/templates/chrome-extension-react/popup.html +12 -0
- package/codeyam-cli/templates/chrome-extension-react/public/manifest.json +15 -0
- package/codeyam-cli/templates/chrome-extension-react/src/background/service-worker.ts +7 -0
- package/codeyam-cli/templates/chrome-extension-react/src/globals.css +6 -0
- package/codeyam-cli/templates/chrome-extension-react/src/lib/storage.ts +37 -0
- package/codeyam-cli/templates/chrome-extension-react/src/popup/App.tsx +12 -0
- package/codeyam-cli/templates/chrome-extension-react/src/popup/main.tsx +10 -0
- package/codeyam-cli/templates/chrome-extension-react/tsconfig.json +24 -0
- package/codeyam-cli/templates/chrome-extension-react/vite.config.ts +41 -0
- package/codeyam-cli/templates/codeyam-editor-claude.md +86 -5
- package/codeyam-cli/templates/codeyam-editor-codex.md +61 -0
- package/codeyam-cli/templates/codeyam-editor-gemini.md +59 -0
- package/codeyam-cli/templates/codeyam-editor-reference.md +216 -0
- package/codeyam-cli/templates/design-systems/clean-dashboard-design-system.md +255 -0
- package/codeyam-cli/templates/design-systems/editorial-design-system.md +267 -0
- package/codeyam-cli/templates/design-systems/mono-brutalist-design-system.md +256 -0
- package/codeyam-cli/templates/design-systems/neo-brutalist-design-system.md +294 -0
- package/codeyam-cli/templates/editor-step-hook.py +262 -41
- package/codeyam-cli/templates/expo-react-native/MOBILE_SETUP.md +288 -0
- package/codeyam-cli/templates/expo-react-native/README.md +41 -0
- package/codeyam-cli/templates/expo-react-native/__tests__/.gitkeep +0 -0
- package/codeyam-cli/templates/expo-react-native/app/_layout.tsx +15 -0
- package/codeyam-cli/templates/expo-react-native/app/index.tsx +36 -0
- package/codeyam-cli/templates/expo-react-native/app.json +29 -0
- package/codeyam-cli/templates/expo-react-native/babel.config.js +10 -0
- package/codeyam-cli/templates/expo-react-native/gitignore +14 -0
- package/codeyam-cli/templates/expo-react-native/global.css +10 -0
- package/codeyam-cli/templates/expo-react-native/lib/storage.ts +32 -0
- package/codeyam-cli/templates/expo-react-native/lib/theme.ts +73 -0
- package/codeyam-cli/templates/expo-react-native/metro.config.js +6 -0
- package/codeyam-cli/templates/expo-react-native/nativewind-env.d.ts +1 -0
- package/codeyam-cli/templates/expo-react-native/package.json +54 -0
- package/codeyam-cli/templates/expo-react-native/patches/expo-modules-autolinking+3.0.24.patch +29 -0
- package/codeyam-cli/templates/expo-react-native/tailwind.config.js +10 -0
- package/codeyam-cli/templates/expo-react-native/tsconfig.json +10 -0
- package/codeyam-cli/templates/isolation-route/expo-router.tsx.template +54 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_PATTERNS.md +308 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/AUTH_UPGRADE.md +304 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/DATABASE.md +126 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/FEATURE_PATTERNS.md +37 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/README.md +53 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/app/codeyam-isolate/layout.tsx +12 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/app/lib/prisma.ts +9 -4
- package/codeyam-cli/templates/nextjs-prisma-sqlite/env +4 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/gitignore +22 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/package.json +6 -2
- package/codeyam-cli/templates/nextjs-prisma-sqlite/prisma/seed.ts +4 -1
- package/codeyam-cli/templates/nextjs-prisma-sqlite/seed-adapter.ts +140 -0
- package/codeyam-cli/templates/nextjs-prisma-sqlite/vitest.config.ts +13 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/README.md +52 -0
- package/codeyam-cli/templates/{nextjs-prisma-sqlite/PRISMA_SETUP.md → nextjs-prisma-supabase/SUPABASE_SETUP.md} +37 -17
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/api/todos/route.ts +17 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/globals.css +26 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/layout.tsx +34 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/prisma.ts +20 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/lib/supabase.ts +12 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/app/page.tsx +10 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/env +9 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/eslint.config.mjs +11 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/gitignore +40 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/next.config.ts +11 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/package.json +37 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/postcss.config.mjs +7 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/schema.prisma +27 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma/seed.ts +39 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/prisma.config.ts +12 -0
- package/codeyam-cli/templates/nextjs-prisma-supabase/tsconfig.json +34 -0
- package/codeyam-cli/templates/seed-adapters/supabase.ts +475 -0
- package/codeyam-cli/templates/skills/codeyam-dev-mode/SKILL.md +2 -2
- package/codeyam-cli/templates/skills/codeyam-editor/SKILL.md +192 -17
- package/codeyam-cli/templates/skills/codeyam-memory/SKILL.md +10 -10
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.mjs +139 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.mjs +52 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/read-json-field.mjs +61 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/lib/ripgrep-fallback.mjs +155 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.mjs +13 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter-session.mjs +95 -0
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.mjs +160 -0
- package/package.json +16 -10
- package/packages/ai/src/lib/astScopes/methodSemantics.js +99 -0
- package/packages/ai/src/lib/astScopes/methodSemantics.js.map +1 -1
- package/packages/ai/src/lib/astScopes/nodeToSource.js +16 -0
- package/packages/ai/src/lib/astScopes/nodeToSource.js.map +1 -1
- package/packages/ai/src/lib/astScopes/paths.js +12 -3
- package/packages/ai/src/lib/astScopes/paths.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js +27 -10
- package/packages/ai/src/lib/dataStructure/ScopeDataStructure.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js +9 -2
- package/packages/ai/src/lib/dataStructure/equivalencyManagers/ParentScopeManager.js.map +1 -1
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js +14 -4
- package/packages/ai/src/lib/dataStructure/helpers/cleanKnownObjectFunctions.js.map +1 -1
- package/packages/ai/src/lib/generateExecutionFlows.js +0 -11
- package/packages/ai/src/lib/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/index.js +1 -1
- package/packages/analyze/index.js.map +1 -1
- package/packages/analyze/src/lib/ProjectAnalyzer.js +10 -4
- package/packages/analyze/src/lib/ProjectAnalyzer.js.map +1 -1
- package/packages/analyze/src/lib/asts/index.js +4 -2
- package/packages/analyze/src/lib/asts/index.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js +16 -2
- package/packages/analyze/src/lib/files/analyze/analyzeEntities/prepareDataStructures.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js +6 -26
- package/packages/analyze/src/lib/files/analyze/analyzeEntities.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js +3 -2
- package/packages/analyze/src/lib/files/analyze/findOrCreateEntity.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js +9 -7
- package/packages/analyze/src/lib/files/analyze/gatherEntityMap.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js +14 -0
- package/packages/analyze/src/lib/files/analyze/trackEntityCircularDependencies.js.map +1 -1
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js +44 -11
- package/packages/analyze/src/lib/files/analyze/validateDependencyAnalyses.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeChange.js +1 -0
- package/packages/analyze/src/lib/files/analyzeChange.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeInitial.js +1 -0
- package/packages/analyze/src/lib/files/analyzeInitial.js.map +1 -1
- package/packages/analyze/src/lib/files/analyzeNextRoute.js +5 -1
- package/packages/analyze/src/lib/files/analyzeNextRoute.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js +120 -28
- package/packages/analyze/src/lib/files/scenarios/generateDataStructure.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js +0 -40
- package/packages/analyze/src/lib/files/scenarios/generateExecutionFlows.js.map +1 -1
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js +1368 -1193
- package/packages/analyze/src/lib/files/scenarios/mergeInDependentDataStructure.js.map +1 -1
- package/packages/database/src/lib/kysely/tables/editorScenariosTable.js +104 -0
- package/packages/database/src/lib/kysely/tables/editorScenariosTable.js.map +1 -1
- package/packages/database/src/lib/loadAnalysis.js +7 -1
- package/packages/database/src/lib/loadAnalysis.js.map +1 -1
- package/packages/database/src/lib/loadEntities.js +0 -6
- package/packages/database/src/lib/loadEntities.js.map +1 -1
- package/packages/database/src/lib/loadEntity.js +5 -5
- package/packages/database/src/lib/loadEntity.js.map +1 -1
- package/packages/database/src/lib/updateCommitMetadata.js +0 -25
- package/packages/database/src/lib/updateCommitMetadata.js.map +1 -1
- package/packages/types/src/enums/ProjectFramework.js +2 -0
- package/packages/types/src/enums/ProjectFramework.js.map +1 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js +22 -1
- package/packages/utils/src/lib/fs/rsyncCopy.js.map +1 -1
- package/scripts/npm-post-install.cjs +22 -0
- package/codeyam-cli/src/webserver/build/client/assets/CopyButton-DmJveP3T.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/EntityTypeBadge-g3saevPb.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/InlineSpinner-Bu6c6aDe.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/InteractivePreview-DYFW3lDD.js +0 -25
- package/codeyam-cli/src/webserver/build/client/assets/LibraryFunctionPreview-DLeucoVX.js +0 -3
- package/codeyam-cli/src/webserver/build/client/assets/SafeScreenshot-BED4B6sP.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/Spinner-Bb5uFQ5V.js +0 -34
- package/codeyam-cli/src/webserver/build/client/assets/Terminal-wkqC0AQk.js +0 -41
- package/codeyam-cli/src/webserver/build/client/assets/TruncatedFilePath-C8OKAR5x.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/addon-fit-CUXOrorO.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/chunk-JZWAC4HX-C4pqxYJB.js +0 -51
- package/codeyam-cli/src/webserver/build/client/assets/createLucideIcon-CMT1jU2q.js +0 -21
- package/codeyam-cli/src/webserver/build/client/assets/cy-logo-cli-DcX-ZS3p.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/dev.empty-BiM6z3Do.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/editor-CdjF_fX6.js +0 -8
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.dev-D8ILZMR0.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha.scenarios._scenarioId.fullscreen-C28BiQzt.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/entity._sha_.create-scenario-p9hhkjJM.js +0 -6
- package/codeyam-cli/src/webserver/build/client/assets/fileTableUtils-cPo8LiG3.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/files-DO4CZ16O.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/git-CFCTYk9I.js +0 -15
- package/codeyam-cli/src/webserver/build/client/assets/globals-B17TBSS6.css +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/labs-Zk7ryIM1.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/manifest-b8fd6b07.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/memory-FweZHj5U.js +0 -93
- package/codeyam-cli/src/webserver/build/client/assets/root-DUKqhFlb.js +0 -67
- package/codeyam-cli/src/webserver/build/client/assets/settings-DfuTtcJP.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/simulations-B3aOzpCZ.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/useCustomSizes-ByhSyh0W.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/useLastLogLine-C14nCb1q.js +0 -2
- package/codeyam-cli/src/webserver/build/client/assets/useReportContext-O-jkvSPx.js +0 -1
- package/codeyam-cli/src/webserver/build/client/assets/useToast-9FIWuYfK.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/index-BLhjL9Xi.js +0 -1
- package/codeyam-cli/src/webserver/build/server/assets/server-build-DyMuI5mU.js +0 -363
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/detect-deprecated-patterns.sh +0 -108
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/holistic-analysis/find-exports.sh +0 -69
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/cleanup.sh +0 -12
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/filter.jq +0 -45
- package/codeyam-cli/templates/skills/codeyam-memory/scripts/session-mining/preprocess.sh +0 -139
|
@@ -4,10 +4,185 @@ import fs from 'fs';
|
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { getProjectRoot } from "../state.js";
|
|
6
6
|
import { createMockStateManager, } from "../utils/editorMockState.js";
|
|
7
|
+
import { computeEditorPorts } from "../utils/editorDevServer.js";
|
|
8
|
+
import { mockStateEventEmitter } from "./mockStateEvents.js";
|
|
9
|
+
/**
|
|
10
|
+
* Normalize a target URL by stripping trailing slashes for consistency.
|
|
11
|
+
*
|
|
12
|
+
* Previously this also replaced `localhost` with `127.0.0.1`, but that broke
|
|
13
|
+
* forwarding to dev servers that bind to IPv6 only (e.g. Vite 6 on macOS
|
|
14
|
+
* binds to `[::1]`). The hostname is now left as-is — `resolveLoopbackAddress`
|
|
15
|
+
* probes the actual target at startup to pick the right address.
|
|
16
|
+
*/
|
|
17
|
+
export function normalizeTargetUrl(url) {
|
|
18
|
+
try {
|
|
19
|
+
const parsed = new URL(url);
|
|
20
|
+
return parsed.toString().replace(/\/$/, '');
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return url;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Probe a localhost port to determine the correct loopback address.
|
|
28
|
+
* Dev servers may bind to IPv4 (127.0.0.1), IPv6 (::1), or both.
|
|
29
|
+
* Returns the first address that accepts a TCP connection.
|
|
30
|
+
*/
|
|
31
|
+
export async function resolveLoopbackAddress(port) {
|
|
32
|
+
const candidates = ['127.0.0.1', '::1'];
|
|
33
|
+
for (const host of candidates) {
|
|
34
|
+
try {
|
|
35
|
+
const connected = await new Promise((resolve) => {
|
|
36
|
+
const socket = new net.Socket();
|
|
37
|
+
socket.setTimeout(1000);
|
|
38
|
+
socket.once('connect', () => {
|
|
39
|
+
socket.destroy();
|
|
40
|
+
resolve(true);
|
|
41
|
+
});
|
|
42
|
+
socket.once('error', () => {
|
|
43
|
+
socket.destroy();
|
|
44
|
+
resolve(false);
|
|
45
|
+
});
|
|
46
|
+
socket.once('timeout', () => {
|
|
47
|
+
socket.destroy();
|
|
48
|
+
resolve(false);
|
|
49
|
+
});
|
|
50
|
+
socket.connect(port, host);
|
|
51
|
+
});
|
|
52
|
+
if (connected) {
|
|
53
|
+
return host;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Try next candidate
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
7
62
|
// Global key so the proxy survives HMR
|
|
8
63
|
const GLOBAL_KEY = '__codeyam_editor_proxy__';
|
|
64
|
+
// ─── Live Preview Health ─────────────────────────────────────────────
|
|
65
|
+
const PREVIEW_HEALTH_KEY = '__codeyam_preview_health__';
|
|
66
|
+
function getPreviewHealth() {
|
|
67
|
+
return globalThis[PREVIEW_HEALTH_KEY] ?? null;
|
|
68
|
+
}
|
|
69
|
+
function setPreviewHealth(report) {
|
|
70
|
+
globalThis[PREVIEW_HEALTH_KEY] = report;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get the current live preview health report (read by API endpoint).
|
|
74
|
+
*/
|
|
75
|
+
export function getPreviewHealthReport() {
|
|
76
|
+
return getPreviewHealth();
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Reset preview health state (called when a new HTML page is served).
|
|
80
|
+
*/
|
|
81
|
+
export function resetPreviewHealth() {
|
|
82
|
+
setPreviewHealth(null);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Error-catching script injected into HTML responses.
|
|
86
|
+
* Uses vanilla JS for maximum compatibility.
|
|
87
|
+
*/
|
|
88
|
+
export const PREVIEW_HEALTH_SCRIPT = `<script data-codeyam-health>
|
|
89
|
+
(function() {
|
|
90
|
+
var errors = [];
|
|
91
|
+
var reported = false;
|
|
92
|
+
function report(type, msg, stack) {
|
|
93
|
+
errors.push({ type: type, message: msg, stack: stack, timestamp: Date.now() });
|
|
94
|
+
if (!reported) {
|
|
95
|
+
reported = true;
|
|
96
|
+
setTimeout(function() { flush(); }, 500);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function flush() {
|
|
100
|
+
fetch('/__codeyam__/preview-health', {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: { 'Content-Type': 'application/json' },
|
|
103
|
+
body: JSON.stringify({ errors: errors, url: location.href })
|
|
104
|
+
}).catch(function(){});
|
|
105
|
+
reported = false;
|
|
106
|
+
errors = [];
|
|
107
|
+
}
|
|
108
|
+
window.addEventListener('error', function(e) {
|
|
109
|
+
report('error', e.message, e.error && e.error.stack);
|
|
110
|
+
});
|
|
111
|
+
window.addEventListener('unhandledrejection', function(e) {
|
|
112
|
+
report('unhandledrejection', String(e.reason), e.reason && e.reason.stack);
|
|
113
|
+
});
|
|
114
|
+
var origError = console.error;
|
|
115
|
+
console.error = function() {
|
|
116
|
+
report('console.error', Array.prototype.join.call(arguments, ' '));
|
|
117
|
+
origError.apply(console, arguments);
|
|
118
|
+
};
|
|
119
|
+
window.addEventListener('load', function() {
|
|
120
|
+
setTimeout(function() {
|
|
121
|
+
var hasContent = document.body && document.body.innerText.trim().length > 0;
|
|
122
|
+
fetch('/__codeyam__/preview-health', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: { 'Content-Type': 'application/json' },
|
|
125
|
+
body: JSON.stringify({
|
|
126
|
+
loaded: true,
|
|
127
|
+
hasContent: hasContent,
|
|
128
|
+
url: location.href,
|
|
129
|
+
errorCount: errors.length
|
|
130
|
+
})
|
|
131
|
+
}).catch(function(){});
|
|
132
|
+
}, 1000);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// Network-idle detection: notify the parent editor when all initial
|
|
136
|
+
// fetch requests have completed, so it can show the preview after
|
|
137
|
+
// client-side data (API calls) has arrived — not just when the DOM loads.
|
|
138
|
+
var inflight = 0;
|
|
139
|
+
var settled = false;
|
|
140
|
+
var settleTimer = null;
|
|
141
|
+
var origFetch = window.fetch;
|
|
142
|
+
window.fetch = function() {
|
|
143
|
+
if (!settled) inflight++;
|
|
144
|
+
return origFetch.apply(this, arguments).then(function(resp) {
|
|
145
|
+
if (!settled) { inflight--; checkSettle(); }
|
|
146
|
+
return resp;
|
|
147
|
+
}, function(err) {
|
|
148
|
+
if (!settled) { inflight--; checkSettle(); }
|
|
149
|
+
throw err;
|
|
150
|
+
});
|
|
151
|
+
};
|
|
152
|
+
function checkSettle() {
|
|
153
|
+
if (inflight <= 0 && !settled) {
|
|
154
|
+
clearTimeout(settleTimer);
|
|
155
|
+
// Small delay to allow React to re-render with the fetched data
|
|
156
|
+
settleTimer = setTimeout(function() {
|
|
157
|
+
if (inflight <= 0) {
|
|
158
|
+
settled = true;
|
|
159
|
+
try {
|
|
160
|
+
window.parent.postMessage({ type: 'codeyam-preview-ready' }, '*');
|
|
161
|
+
} catch(e) {}
|
|
162
|
+
}
|
|
163
|
+
}, 100);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Fallback: if no fetches happen (static page), settle after load
|
|
167
|
+
window.addEventListener('load', function() {
|
|
168
|
+
setTimeout(function() { checkSettle(); }, 200);
|
|
169
|
+
});
|
|
170
|
+
})();
|
|
171
|
+
</script>`;
|
|
9
172
|
const CACHE_TTL_MS = 500;
|
|
10
173
|
let scenarioCache = { data: null, timestamp: 0 };
|
|
174
|
+
// Session config extracted from the active scenario — drives cookie injection
|
|
175
|
+
let sessionConfig = undefined;
|
|
176
|
+
/** Session cookies from the seed adapter (e.g. Supabase auth tokens). */
|
|
177
|
+
let seedSessionCookies = undefined;
|
|
178
|
+
// localStorage config extracted from the active scenario — drives HTML injection
|
|
179
|
+
let localStorageConfig = null;
|
|
180
|
+
// Active scenario ID — used to gate localStorage seeding (only re-seed on switch)
|
|
181
|
+
let activeScenarioId = null;
|
|
182
|
+
// Prototype ID — used to gate a one-time localStorage.clear() when a new project is scaffolded
|
|
183
|
+
let currentPrototypeId = null;
|
|
184
|
+
// Current scenario type — 'application'/'user' for seed-based, 'component' for mock-based
|
|
185
|
+
let currentScenarioType = null;
|
|
11
186
|
// Max body size to buffer for mock matching (10MB)
|
|
12
187
|
const MAX_BODY_SIZE = 10 * 1024 * 1024;
|
|
13
188
|
function getProxyState() {
|
|
@@ -38,6 +213,12 @@ export function getProxyUrl() {
|
|
|
38
213
|
/**
|
|
39
214
|
* Read the active scenario's mock data from disk, with brief caching.
|
|
40
215
|
* Feeds the data into the MockStateManager.
|
|
216
|
+
*
|
|
217
|
+
* For application/user scenarios (type-aware): only loads `externalApis`
|
|
218
|
+
* into the mock state manager. All DB-backed routes flow through to the
|
|
219
|
+
* real app (database is seeded with real data).
|
|
220
|
+
*
|
|
221
|
+
* For component scenarios (or legacy): loads all routes as before.
|
|
41
222
|
*/
|
|
42
223
|
function readScenarioData() {
|
|
43
224
|
const now = Date.now();
|
|
@@ -55,6 +236,8 @@ function readScenarioData() {
|
|
|
55
236
|
const active = JSON.parse(fs.readFileSync(activeScenarioPath, 'utf-8'));
|
|
56
237
|
const scenarioId = active.scenarioId;
|
|
57
238
|
if (!scenarioId) {
|
|
239
|
+
// No active scenario — but may have a prototypeId for localStorage clearing
|
|
240
|
+
currentPrototypeId = active.prototypeId || null;
|
|
58
241
|
scenarioCache = { data: null, timestamp: now };
|
|
59
242
|
return null;
|
|
60
243
|
}
|
|
@@ -64,11 +247,37 @@ function readScenarioData() {
|
|
|
64
247
|
scenarioCache = { data: null, timestamp: now };
|
|
65
248
|
return null;
|
|
66
249
|
}
|
|
67
|
-
const
|
|
68
|
-
|
|
250
|
+
const rawData = JSON.parse(fs.readFileSync(dataFilePath, 'utf-8'));
|
|
251
|
+
// Extract session config for cookie injection
|
|
252
|
+
sessionConfig = rawData.session || null;
|
|
253
|
+
// Extract seed adapter session cookies (e.g. Supabase auth)
|
|
254
|
+
seedSessionCookies = rawData.sessionCookies || undefined;
|
|
255
|
+
// Extract localStorage config for HTML injection
|
|
256
|
+
localStorageConfig = rawData.localStorage || null;
|
|
257
|
+
activeScenarioId = scenarioId;
|
|
258
|
+
// Type-aware: for seed-based scenarios, only serve externalApis via proxy
|
|
259
|
+
const scenarioType = active.type || rawData.type || null;
|
|
260
|
+
currentScenarioType = scenarioType;
|
|
261
|
+
let mockData;
|
|
262
|
+
if ((scenarioType === 'application' || scenarioType === 'user') &&
|
|
263
|
+
rawData.seed) {
|
|
264
|
+
// Seed-based scenario: only load externalApis as routes for the proxy
|
|
265
|
+
if (rawData.externalApis && typeof rawData.externalApis === 'object') {
|
|
266
|
+
mockData = { routes: rawData.externalApis };
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
// No external APIs — proxy passes everything through
|
|
270
|
+
mockData = {};
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
// Component/legacy scenario: load all data
|
|
275
|
+
mockData = rawData;
|
|
276
|
+
}
|
|
277
|
+
scenarioCache = { data: mockData, timestamp: now };
|
|
69
278
|
// Feed into mock state manager (smart reload handles dedup)
|
|
70
|
-
getMockStateManager().loadScenario(
|
|
71
|
-
return
|
|
279
|
+
getMockStateManager().loadScenario(mockData);
|
|
280
|
+
return mockData;
|
|
72
281
|
}
|
|
73
282
|
catch (err) {
|
|
74
283
|
console.warn('[editorProxy] Error reading scenario data:', err);
|
|
@@ -76,39 +285,6 @@ function readScenarioData() {
|
|
|
76
285
|
return null;
|
|
77
286
|
}
|
|
78
287
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Find a matching route in the scenario data.
|
|
81
|
-
*
|
|
82
|
-
* Supports two formats:
|
|
83
|
-
* - New route-keyed: { "routes": { "/api/drinks": { "body": [...] } } }
|
|
84
|
-
* - Legacy key-based: { "drinks": [...] } → matches /api/drinks
|
|
85
|
-
*
|
|
86
|
-
* @deprecated Use MockStateManager.matchRequest() instead for method-aware matching.
|
|
87
|
-
*/
|
|
88
|
-
export function findMatchingRoute(pathname, scenarioData) {
|
|
89
|
-
// New format: check routes map
|
|
90
|
-
const routes = scenarioData.routes;
|
|
91
|
-
if (routes && typeof routes === 'object') {
|
|
92
|
-
const routeEntry = routes[pathname];
|
|
93
|
-
if (routeEntry && typeof routeEntry === 'object') {
|
|
94
|
-
const entry = routeEntry;
|
|
95
|
-
return {
|
|
96
|
-
body: entry.body ?? routeEntry,
|
|
97
|
-
status: typeof entry.status === 'number' ? entry.status : 200,
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
// Legacy format: key "drinks" matches "/api/drinks"
|
|
102
|
-
// Extract the last segment of the path after /api/
|
|
103
|
-
const apiMatch = pathname.match(/^\/api\/(.+)$/);
|
|
104
|
-
if (apiMatch) {
|
|
105
|
-
const key = apiMatch[1];
|
|
106
|
-
if (key in scenarioData && key !== 'routes') {
|
|
107
|
-
return { body: scenarioData[key], status: 200 };
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
288
|
/**
|
|
113
289
|
* Buffer the request body, up to MAX_BODY_SIZE.
|
|
114
290
|
* Returns null if the body exceeds the limit.
|
|
@@ -137,33 +313,108 @@ function bufferRequestBody(req) {
|
|
|
137
313
|
});
|
|
138
314
|
});
|
|
139
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Strip IPv6 bracket notation for use with http.request hostname.
|
|
318
|
+
* URL.hostname returns `[::1]` for IPv6 but http.request needs `::1`.
|
|
319
|
+
*/
|
|
320
|
+
function stripIPv6Brackets(hostname) {
|
|
321
|
+
if (hostname.startsWith('[') && hostname.endsWith(']')) {
|
|
322
|
+
return hostname.slice(1, -1);
|
|
323
|
+
}
|
|
324
|
+
return hostname;
|
|
325
|
+
}
|
|
140
326
|
/**
|
|
141
327
|
* Forward a buffered request to the target dev server.
|
|
142
328
|
* Unlike the streaming forwardRequest, this replays a buffered body.
|
|
143
329
|
*/
|
|
144
330
|
function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
|
|
145
331
|
const target = new URL(targetUrl);
|
|
332
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
146
333
|
const headers = { ...req.headers, host: `${target.hostname}:${target.port}` };
|
|
334
|
+
// Remove accept-encoding so the dev server returns uncompressed responses.
|
|
335
|
+
// The proxy injects a health script into HTML — this fails on compressed bodies.
|
|
336
|
+
delete headers['accept-encoding'];
|
|
337
|
+
// Inject session cookies into the request so the dev server sees auth
|
|
338
|
+
// on the first request after a scenario switch (before the browser has
|
|
339
|
+
// stored them from Set-Cookie responses).
|
|
340
|
+
injectRequestCookies(headers);
|
|
147
341
|
// Update content-length if we have the body buffer
|
|
148
342
|
if (bodyBuffer) {
|
|
149
343
|
headers['content-length'] = String(bodyBuffer.length);
|
|
150
344
|
}
|
|
151
345
|
const options = {
|
|
152
|
-
hostname
|
|
346
|
+
hostname,
|
|
153
347
|
port: target.port,
|
|
154
348
|
path: req.url,
|
|
155
349
|
method: req.method,
|
|
156
350
|
headers,
|
|
157
351
|
};
|
|
158
352
|
const proxyReq = http.request(options, (proxyRes) => {
|
|
159
|
-
|
|
353
|
+
const status = proxyRes.statusCode || 200;
|
|
354
|
+
if (status >= 300 && status < 400) {
|
|
355
|
+
console.log(`[editorProxy] Target redirect ${status} for ${req.method} ${req.url} → ${proxyRes.headers.location}`);
|
|
356
|
+
}
|
|
357
|
+
if (status >= 400) {
|
|
358
|
+
console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
|
|
359
|
+
}
|
|
360
|
+
const headers = { ...proxyRes.headers };
|
|
361
|
+
injectSessionCookie(headers);
|
|
362
|
+
// Check if response is HTML — if so, buffer and inject health script
|
|
363
|
+
const contentType = proxyRes.headers['content-type'] || '';
|
|
364
|
+
if (contentType.includes('text/html')) {
|
|
365
|
+
resetPreviewHealth();
|
|
366
|
+
const chunks = [];
|
|
367
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
368
|
+
proxyRes.on('end', () => {
|
|
369
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
370
|
+
delete headers['content-length'];
|
|
371
|
+
delete headers['content-encoding'];
|
|
372
|
+
headers['cache-control'] = 'no-store, must-revalidate';
|
|
373
|
+
// Serve a friendly error page for 5xx responses instead of
|
|
374
|
+
// forwarding the raw error HTML (e.g. Next.js "Internal Server Error")
|
|
375
|
+
if (status >= 500) {
|
|
376
|
+
const errorPage = buildErrorPage(status, 'Internal Server Error', body);
|
|
377
|
+
res.writeHead(status, headers);
|
|
378
|
+
res.end(errorPage);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
|
|
382
|
+
const injected = injectHealthScript(body, lsScript);
|
|
383
|
+
res.writeHead(status, headers);
|
|
384
|
+
res.end(injected);
|
|
385
|
+
});
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
// For 5xx responses without a content type or with text/plain,
|
|
389
|
+
// serve a friendly error page. These are typically broken dev servers
|
|
390
|
+
// (e.g. Next.js returning bare "Internal Server Error" with no headers).
|
|
391
|
+
// JSON API errors are left alone — they're legitimate responses.
|
|
392
|
+
if (status >= 500 && !contentType.includes('application/json')) {
|
|
393
|
+
const chunks = [];
|
|
394
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
395
|
+
proxyRes.on('end', () => {
|
|
396
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
397
|
+
const errorPage = buildErrorPage(status, 'Internal Server Error', body);
|
|
398
|
+
res.writeHead(status, {
|
|
399
|
+
'Content-Type': 'text/html',
|
|
400
|
+
'Cache-Control': 'no-store',
|
|
401
|
+
});
|
|
402
|
+
res.end(errorPage);
|
|
403
|
+
});
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
res.writeHead(status, headers);
|
|
160
407
|
proxyRes.pipe(res, { end: true });
|
|
161
408
|
});
|
|
162
409
|
proxyReq.on('error', (err) => {
|
|
163
410
|
console.warn(`[editorProxy] Forward error for ${req.method} ${req.url}: ${err.message}`);
|
|
164
411
|
if (!res.headersSent) {
|
|
165
|
-
|
|
166
|
-
res.
|
|
412
|
+
const errorPage = buildErrorPage(502, 'Dev Server Unreachable', `The proxy could not connect to the dev server. It may be starting up, restarting, or crashed.\n\n${err.message}`);
|
|
413
|
+
res.writeHead(502, {
|
|
414
|
+
'Content-Type': 'text/html',
|
|
415
|
+
'Cache-Control': 'no-store',
|
|
416
|
+
});
|
|
417
|
+
res.end(errorPage);
|
|
167
418
|
}
|
|
168
419
|
});
|
|
169
420
|
if (bodyBuffer && bodyBuffer.length > 0) {
|
|
@@ -174,38 +425,531 @@ function forwardBufferedRequest(req, res, targetUrl, bodyBuffer) {
|
|
|
174
425
|
}
|
|
175
426
|
}
|
|
176
427
|
/**
|
|
177
|
-
* Forward an HTTP request to the target dev server
|
|
428
|
+
* Forward an HTTP request to the target dev server.
|
|
429
|
+
* For HTML responses: buffers body to inject health-check script.
|
|
430
|
+
* For non-HTML responses: pipes directly (no buffering).
|
|
178
431
|
*/
|
|
179
432
|
function forwardRequest(req, res, targetUrl) {
|
|
180
433
|
const target = new URL(targetUrl);
|
|
434
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
435
|
+
// Build headers, stripping accept-encoding so the dev server returns uncompressed
|
|
436
|
+
// responses. The proxy injects a health script into HTML — this fails on compressed bodies.
|
|
437
|
+
const { 'accept-encoding': _ae, ...forwardHeaders } = req.headers;
|
|
438
|
+
const reqHeaders = {
|
|
439
|
+
...forwardHeaders,
|
|
440
|
+
host: `${target.hostname}:${target.port}`,
|
|
441
|
+
};
|
|
442
|
+
// Inject session cookies into the request so the dev server sees auth
|
|
443
|
+
// on the first request after a scenario switch.
|
|
444
|
+
injectRequestCookies(reqHeaders);
|
|
181
445
|
const options = {
|
|
182
|
-
hostname
|
|
446
|
+
hostname,
|
|
183
447
|
port: target.port,
|
|
184
448
|
path: req.url,
|
|
185
449
|
method: req.method,
|
|
186
|
-
headers:
|
|
450
|
+
headers: reqHeaders,
|
|
187
451
|
};
|
|
188
452
|
const proxyReq = http.request(options, (proxyRes) => {
|
|
189
|
-
|
|
453
|
+
const status = proxyRes.statusCode || 200;
|
|
454
|
+
if (status >= 300 && status < 400) {
|
|
455
|
+
console.log(`[editorProxy] Target redirect ${status} for ${req.method} ${req.url} → ${proxyRes.headers.location}`);
|
|
456
|
+
}
|
|
457
|
+
if (status >= 400) {
|
|
458
|
+
console.warn(`[editorProxy] Target returned ${status} for ${req.method} ${req.url}`);
|
|
459
|
+
}
|
|
460
|
+
const headers = { ...proxyRes.headers };
|
|
461
|
+
injectSessionCookie(headers);
|
|
462
|
+
// Check if response is HTML — if so, buffer and inject health script
|
|
463
|
+
const contentType = proxyRes.headers['content-type'] || '';
|
|
464
|
+
if (contentType.includes('text/html')) {
|
|
465
|
+
// Reset health state for new page loads
|
|
466
|
+
resetPreviewHealth();
|
|
467
|
+
const chunks = [];
|
|
468
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
469
|
+
proxyRes.on('end', () => {
|
|
470
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
471
|
+
delete headers['content-length'];
|
|
472
|
+
delete headers['content-encoding'];
|
|
473
|
+
headers['cache-control'] = 'no-store, must-revalidate';
|
|
474
|
+
// Serve a friendly error page for 5xx responses instead of
|
|
475
|
+
// forwarding the raw error HTML (e.g. Next.js "Internal Server Error")
|
|
476
|
+
if (status >= 500) {
|
|
477
|
+
const errorPage = buildErrorPage(status, 'Internal Server Error', body);
|
|
478
|
+
res.writeHead(status, headers);
|
|
479
|
+
res.end(errorPage);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const lsScript = buildLocalStorageScript(localStorageConfig, activeScenarioId || '', currentPrototypeId);
|
|
483
|
+
const injected = injectHealthScript(body, lsScript);
|
|
484
|
+
res.writeHead(status, headers);
|
|
485
|
+
res.end(injected);
|
|
486
|
+
});
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
// For 5xx responses without a content type or with text/plain,
|
|
490
|
+
// serve a friendly error page. These are typically broken dev servers
|
|
491
|
+
// (e.g. Next.js returning bare "Internal Server Error" with no headers).
|
|
492
|
+
// JSON API errors are left alone — they're legitimate responses.
|
|
493
|
+
if (status >= 500 && !contentType.includes('application/json')) {
|
|
494
|
+
const chunks = [];
|
|
495
|
+
proxyRes.on('data', (chunk) => chunks.push(chunk));
|
|
496
|
+
proxyRes.on('end', () => {
|
|
497
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
498
|
+
const errorPage = buildErrorPage(status, 'Internal Server Error', body);
|
|
499
|
+
res.writeHead(status, {
|
|
500
|
+
'Content-Type': 'text/html',
|
|
501
|
+
'Cache-Control': 'no-store',
|
|
502
|
+
});
|
|
503
|
+
res.end(errorPage);
|
|
504
|
+
});
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
res.writeHead(status, headers);
|
|
190
508
|
proxyRes.pipe(res, { end: true });
|
|
191
509
|
});
|
|
192
510
|
proxyReq.on('error', (err) => {
|
|
193
511
|
console.warn(`[editorProxy] Forward error for ${req.method} ${req.url}: ${err.message}`);
|
|
194
512
|
if (!res.headersSent) {
|
|
195
|
-
|
|
196
|
-
res.
|
|
513
|
+
const errorPage = buildErrorPage(502, 'Dev Server Unreachable', `The proxy could not connect to the dev server. It may be starting up, restarting, or crashed.\n\n${err.message}`);
|
|
514
|
+
res.writeHead(502, {
|
|
515
|
+
'Content-Type': 'text/html',
|
|
516
|
+
'Cache-Control': 'no-store',
|
|
517
|
+
});
|
|
518
|
+
res.end(errorPage);
|
|
197
519
|
}
|
|
198
520
|
});
|
|
199
521
|
req.pipe(proxyReq, { end: true });
|
|
200
522
|
}
|
|
523
|
+
/**
|
|
524
|
+
* Inject or clear the session-token cookie on proxied responses.
|
|
525
|
+
* When a scenario has session.cookieValue, sets the cookie to auto-log the user in.
|
|
526
|
+
* When a scenario has no session field (null), clears any existing session cookie.
|
|
527
|
+
* When sessionConfig is undefined (no scenario loaded yet), does nothing.
|
|
528
|
+
*/
|
|
529
|
+
function injectSessionCookie(headers) {
|
|
530
|
+
const cookies = [];
|
|
531
|
+
// Dev auth cookie (built-in session-token)
|
|
532
|
+
if (sessionConfig !== undefined) {
|
|
533
|
+
if (sessionConfig?.cookieValue) {
|
|
534
|
+
cookies.push(`session-token=${sessionConfig.cookieValue}; Path=/; SameSite=Lax`);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
cookies.push(`session-token=; Path=/; Max-Age=0`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
// Seed adapter session cookies (e.g. Supabase auth tokens)
|
|
541
|
+
if (seedSessionCookies && seedSessionCookies.length > 0) {
|
|
542
|
+
for (const sc of seedSessionCookies) {
|
|
543
|
+
const cookiePath = sc.path || '/';
|
|
544
|
+
const sameSite = sc.sameSite || 'Lax';
|
|
545
|
+
cookies.push(`${sc.name}=${sc.value}; Path=${cookiePath}; SameSite=${sameSite}`);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (cookies.length === 0)
|
|
549
|
+
return;
|
|
550
|
+
const existing = headers['set-cookie'];
|
|
551
|
+
if (existing) {
|
|
552
|
+
headers['set-cookie'] = [
|
|
553
|
+
...(Array.isArray(existing) ? existing : [existing]),
|
|
554
|
+
...cookies,
|
|
555
|
+
];
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
headers['set-cookie'] = cookies;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Get session cookies that should be injected into requests forwarded to the
|
|
563
|
+
* dev server. Returns an array of {name, value} pairs, or null if no session
|
|
564
|
+
* cookies are configured.
|
|
565
|
+
*
|
|
566
|
+
* This is the counterpart to `injectSessionCookie()` (which adds Set-Cookie
|
|
567
|
+
* to responses). Without request-side injection, the first request after a
|
|
568
|
+
* scenario switch has no cookies — the dev server's auth middleware sees no
|
|
569
|
+
* session and redirects to the login page before the browser ever receives
|
|
570
|
+
* the Set-Cookie response.
|
|
571
|
+
*/
|
|
572
|
+
export function getRequestCookieInjection() {
|
|
573
|
+
const cookies = [];
|
|
574
|
+
if (sessionConfig?.cookieValue) {
|
|
575
|
+
cookies.push({ name: 'session-token', value: sessionConfig.cookieValue });
|
|
576
|
+
}
|
|
577
|
+
if (seedSessionCookies && seedSessionCookies.length > 0) {
|
|
578
|
+
for (const sc of seedSessionCookies) {
|
|
579
|
+
cookies.push({ name: sc.name, value: sc.value });
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return cookies.length > 0 ? cookies : null;
|
|
583
|
+
}
|
|
584
|
+
/**
|
|
585
|
+
* Inject session cookies into the request's Cookie header before forwarding
|
|
586
|
+
* to the dev server. This ensures the dev server sees auth cookies on the
|
|
587
|
+
* very first request after a scenario switch (before the browser has stored
|
|
588
|
+
* them from Set-Cookie responses).
|
|
589
|
+
*/
|
|
590
|
+
function injectRequestCookies(headers) {
|
|
591
|
+
const injection = getRequestCookieInjection();
|
|
592
|
+
if (!injection)
|
|
593
|
+
return;
|
|
594
|
+
// Parse existing cookies from the request
|
|
595
|
+
const existing = typeof headers.cookie === 'string' ? headers.cookie : '';
|
|
596
|
+
const existingPairs = existing
|
|
597
|
+
? existing.split(';').map((s) => s.trim())
|
|
598
|
+
: [];
|
|
599
|
+
// Build a map of existing cookies for deduplication
|
|
600
|
+
const cookieMap = new Map();
|
|
601
|
+
for (const pair of existingPairs) {
|
|
602
|
+
const eqIdx = pair.indexOf('=');
|
|
603
|
+
if (eqIdx !== -1) {
|
|
604
|
+
cookieMap.set(pair.slice(0, eqIdx), pair.slice(eqIdx + 1));
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
// Override with injected cookies
|
|
608
|
+
for (const { name, value } of injection) {
|
|
609
|
+
cookieMap.set(name, value);
|
|
610
|
+
}
|
|
611
|
+
// Reassemble
|
|
612
|
+
const parts = [];
|
|
613
|
+
for (const [k, v] of cookieMap) {
|
|
614
|
+
parts.push(`${k}=${v}`);
|
|
615
|
+
}
|
|
616
|
+
if (parts.length > 0) {
|
|
617
|
+
headers.cookie = parts.join('; ');
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Get the current session config (for testing).
|
|
622
|
+
*/
|
|
623
|
+
export function getSessionConfig() {
|
|
624
|
+
return sessionConfig;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Get the current localStorage config (for testing and script generation).
|
|
628
|
+
*/
|
|
629
|
+
export function getLocalStorageConfig() {
|
|
630
|
+
return localStorageConfig;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* Get the active scenario ID (for testing and script generation).
|
|
634
|
+
*/
|
|
635
|
+
export function getActiveScenarioId() {
|
|
636
|
+
return activeScenarioId;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Get the current prototype ID (for testing).
|
|
640
|
+
*/
|
|
641
|
+
export function getCurrentPrototypeId() {
|
|
642
|
+
return currentPrototypeId;
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* Simple djb2 hash — fast, deterministic, good enough for cache busting.
|
|
646
|
+
* Not cryptographic — just detects when localStorage config content changes.
|
|
647
|
+
*/
|
|
648
|
+
function simpleHash(str) {
|
|
649
|
+
let hash = 5381;
|
|
650
|
+
for (let i = 0; i < str.length; i++) {
|
|
651
|
+
hash = ((hash << 5) + hash + str.charCodeAt(i)) | 0;
|
|
652
|
+
}
|
|
653
|
+
return (hash >>> 0).toString(36);
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Build a script tag that seeds localStorage with scenario data on first load.
|
|
657
|
+
* Gated by scenario ID — only seeds when the scenario changes, preserving
|
|
658
|
+
* interactive modifications across page reloads / HMR.
|
|
659
|
+
*
|
|
660
|
+
* Returns empty string if no localStorage config is provided.
|
|
661
|
+
*/
|
|
662
|
+
export function buildLocalStorageScript(localStorageConfig, scenarioId, prototypeId) {
|
|
663
|
+
// null/undefined means no localStorage config at all — clean up keys
|
|
664
|
+
// that were set by a previous scenario so stale filter/sort state
|
|
665
|
+
// doesn't bleed through and hide data in the new scenario.
|
|
666
|
+
if (!localStorageConfig || typeof localStorageConfig !== 'object') {
|
|
667
|
+
// Always clean up previous scenario's keys, gated by scenarioId
|
|
668
|
+
// so it only runs once per switch (not on every HMR reload).
|
|
669
|
+
const guardValue = scenarioId ? `clear:${scenarioId}` : '';
|
|
670
|
+
if (prototypeId) {
|
|
671
|
+
return `<script data-codeyam-ls>
|
|
672
|
+
(function() {
|
|
673
|
+
if (localStorage.getItem('__codeyam_proto__') === ${JSON.stringify(prototypeId)}) return;
|
|
674
|
+
localStorage.clear();
|
|
675
|
+
localStorage.setItem('__codeyam_proto__', ${JSON.stringify(prototypeId)});
|
|
676
|
+
})();
|
|
677
|
+
</script>`;
|
|
678
|
+
}
|
|
679
|
+
if (scenarioId) {
|
|
680
|
+
// No prototypeId but we do have a scenarioId — clean up keys
|
|
681
|
+
// from the previous scenario without doing a full clear.
|
|
682
|
+
return `<script data-codeyam-ls>
|
|
683
|
+
(function() {
|
|
684
|
+
if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(guardValue)}) return;
|
|
685
|
+
var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
|
|
686
|
+
for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
|
|
687
|
+
localStorage.removeItem('__codeyam_ls_keys__');
|
|
688
|
+
localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(guardValue)});
|
|
689
|
+
})();
|
|
690
|
+
</script>`;
|
|
691
|
+
}
|
|
692
|
+
return '';
|
|
693
|
+
}
|
|
694
|
+
// Even an empty object needs a cleanup script — switching from a scenario
|
|
695
|
+
// with localStorage data to one without must clear the previous keys.
|
|
696
|
+
const entries = Object.entries(localStorageConfig);
|
|
697
|
+
const keys = entries.map(([k]) => k);
|
|
698
|
+
// Build setItem calls — stringify non-string values
|
|
699
|
+
const setStatements = entries
|
|
700
|
+
.map(([key, value]) => {
|
|
701
|
+
const serialized = typeof value === 'string' ? value : JSON.stringify(value);
|
|
702
|
+
return `localStorage.setItem(${JSON.stringify(key)}, ${JSON.stringify(serialized)});`;
|
|
703
|
+
})
|
|
704
|
+
.join('\n');
|
|
705
|
+
// Guard value includes a content hash so re-registering a scenario with
|
|
706
|
+
// updated data (same ID, different content) busts the cache. Without this,
|
|
707
|
+
// the browser skips re-seeding because the scenario ID hasn't changed,
|
|
708
|
+
// causing stale data in the live preview while screenshots show fresh data.
|
|
709
|
+
const contentHash = simpleHash(JSON.stringify(localStorageConfig));
|
|
710
|
+
const guardValue = `${scenarioId}:${contentHash}`;
|
|
711
|
+
return (`<script data-codeyam-ls>
|
|
712
|
+
(function() {
|
|
713
|
+
if (localStorage.getItem('__codeyam_ls_sid__') === ${JSON.stringify(guardValue)}) return;
|
|
714
|
+
var prev = JSON.parse(localStorage.getItem('__codeyam_ls_keys__') || '[]');
|
|
715
|
+
for (var i = 0; i < prev.length; i++) localStorage.removeItem(prev[i]);
|
|
716
|
+
${setStatements}
|
|
717
|
+
localStorage.setItem('__codeyam_ls_keys__', ${JSON.stringify(JSON.stringify(keys))});
|
|
718
|
+
localStorage.setItem('__codeyam_ls_sid__', ${JSON.stringify(guardValue)});
|
|
719
|
+
})();
|
|
720
|
+
</script>` + buildLocalStorageWatcherScript());
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Build a script that watches for localStorage mutations and notifies the parent
|
|
724
|
+
* frame via postMessage. Also responds to `codeyam-get-localstorage` requests so
|
|
725
|
+
* the editor can read the current localStorage state when saving.
|
|
726
|
+
*/
|
|
727
|
+
function buildLocalStorageWatcherScript() {
|
|
728
|
+
return `<script data-codeyam-ls-watcher>
|
|
729
|
+
(function() {
|
|
730
|
+
if (window.__codeyam_ls_watcher_installed__) return;
|
|
731
|
+
window.__codeyam_ls_watcher_installed__ = true;
|
|
732
|
+
|
|
733
|
+
var origSet = localStorage.setItem.bind(localStorage);
|
|
734
|
+
var origRemove = localStorage.removeItem.bind(localStorage);
|
|
735
|
+
var origClear = localStorage.clear.bind(localStorage);
|
|
736
|
+
window.__codeyam_orig_setItem__ = origSet;
|
|
737
|
+
window.__codeyam_orig_removeItem__ = origRemove;
|
|
738
|
+
window.__codeyam_orig_clear__ = origClear;
|
|
739
|
+
|
|
740
|
+
function isInternal(key) {
|
|
741
|
+
return typeof key === 'string' && key.indexOf('__codeyam_') === 0;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
localStorage.setItem = function(key, value) {
|
|
745
|
+
origSet(key, value);
|
|
746
|
+
if (!isInternal(key) && window.parent !== window) {
|
|
747
|
+
window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'set', key: key }, '*');
|
|
748
|
+
}
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
localStorage.removeItem = function(key) {
|
|
752
|
+
origRemove(key);
|
|
753
|
+
if (!isInternal(key) && window.parent !== window) {
|
|
754
|
+
window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'remove', key: key }, '*');
|
|
755
|
+
}
|
|
756
|
+
};
|
|
757
|
+
|
|
758
|
+
localStorage.clear = function() {
|
|
759
|
+
origClear();
|
|
760
|
+
if (window.parent !== window) {
|
|
761
|
+
window.parent.postMessage({ type: 'codeyam-localstorage-changed', action: 'clear' }, '*');
|
|
762
|
+
}
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
window.addEventListener('message', function(event) {
|
|
766
|
+
if (event.data && event.data.type === 'codeyam-get-localstorage') {
|
|
767
|
+
var data = {};
|
|
768
|
+
for (var i = 0; i < localStorage.length; i++) {
|
|
769
|
+
var k = localStorage.key(i);
|
|
770
|
+
if (k && !isInternal(k)) {
|
|
771
|
+
data[k] = localStorage.getItem(k);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
event.source.postMessage({ type: 'codeyam-localstorage-state', data: data }, '*');
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
})();
|
|
778
|
+
</script>`;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Inject the health-check script (and optional localStorage script) into an HTML response body.
|
|
782
|
+
* Inserts before </head> if present, otherwise before </body>, otherwise appends.
|
|
783
|
+
* When a localStorageScript is provided, it's injected BEFORE the health script
|
|
784
|
+
* so localStorage is populated before the app loads.
|
|
785
|
+
*/
|
|
786
|
+
export function injectHealthScript(html, localStorageScript) {
|
|
787
|
+
const scripts = (localStorageScript || '') + PREVIEW_HEALTH_SCRIPT;
|
|
788
|
+
if (html.includes('</head>')) {
|
|
789
|
+
return html.replace('</head>', scripts + '</head>');
|
|
790
|
+
}
|
|
791
|
+
if (html.includes('</body>')) {
|
|
792
|
+
return html.replace('</body>', scripts + '</body>');
|
|
793
|
+
}
|
|
794
|
+
return html + scripts;
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Escape HTML special characters to prevent XSS when embedding
|
|
798
|
+
* dev server error output into the error page.
|
|
799
|
+
*/
|
|
800
|
+
export function escapeHtml(str) {
|
|
801
|
+
return str
|
|
802
|
+
.replace(/&/g, '&')
|
|
803
|
+
.replace(/</g, '<')
|
|
804
|
+
.replace(/>/g, '>')
|
|
805
|
+
.replace(/"/g, '"')
|
|
806
|
+
.replace(/'/g, ''');
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Build a self-contained HTML error page for display in the preview iframe.
|
|
810
|
+
*
|
|
811
|
+
* - Sends `codeyam-server-error` postMessage to the parent editor on load
|
|
812
|
+
* so the editor can auto-restart the dev server.
|
|
813
|
+
* - Includes a "Retry" button that sends `codeyam-server-error-retry`.
|
|
814
|
+
* - Does NOT send `codeyam-preview-ready` (so the editor doesn't
|
|
815
|
+
* mistake the error page for a successful load).
|
|
816
|
+
*/
|
|
817
|
+
export function buildErrorPage(statusCode, title, detail) {
|
|
818
|
+
const escapedDetail = escapeHtml(detail);
|
|
819
|
+
const escapedTitle = escapeHtml(title);
|
|
820
|
+
return `<!DOCTYPE html>
|
|
821
|
+
<html lang="en">
|
|
822
|
+
<head>
|
|
823
|
+
<meta charset="utf-8" />
|
|
824
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
825
|
+
<title>${escapedTitle}</title>
|
|
826
|
+
<style>
|
|
827
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
828
|
+
body {
|
|
829
|
+
background: #1e1e1e;
|
|
830
|
+
color: #e0e0e0;
|
|
831
|
+
font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
832
|
+
display: flex;
|
|
833
|
+
align-items: center;
|
|
834
|
+
justify-content: center;
|
|
835
|
+
min-height: 100vh;
|
|
836
|
+
padding: 24px;
|
|
837
|
+
}
|
|
838
|
+
.container {
|
|
839
|
+
max-width: 560px;
|
|
840
|
+
width: 100%;
|
|
841
|
+
text-align: center;
|
|
842
|
+
}
|
|
843
|
+
.status-code {
|
|
844
|
+
font-size: 48px;
|
|
845
|
+
font-weight: 600;
|
|
846
|
+
color: #f87171;
|
|
847
|
+
line-height: 1;
|
|
848
|
+
margin-bottom: 8px;
|
|
849
|
+
}
|
|
850
|
+
.title {
|
|
851
|
+
font-size: 18px;
|
|
852
|
+
font-weight: 500;
|
|
853
|
+
color: #f87171;
|
|
854
|
+
margin-bottom: 16px;
|
|
855
|
+
}
|
|
856
|
+
.detail {
|
|
857
|
+
background: #2a2a2a;
|
|
858
|
+
border: 1px solid #3a3a3a;
|
|
859
|
+
border-radius: 6px;
|
|
860
|
+
padding: 16px;
|
|
861
|
+
margin-bottom: 20px;
|
|
862
|
+
max-height: 240px;
|
|
863
|
+
overflow: auto;
|
|
864
|
+
text-align: left;
|
|
865
|
+
}
|
|
866
|
+
.detail pre {
|
|
867
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
868
|
+
font-size: 12px;
|
|
869
|
+
color: #b0b0b0;
|
|
870
|
+
white-space: pre-wrap;
|
|
871
|
+
word-break: break-word;
|
|
872
|
+
}
|
|
873
|
+
.message {
|
|
874
|
+
font-size: 13px;
|
|
875
|
+
color: #888;
|
|
876
|
+
margin-bottom: 16px;
|
|
877
|
+
}
|
|
878
|
+
button {
|
|
879
|
+
background: #005c75;
|
|
880
|
+
color: white;
|
|
881
|
+
border: none;
|
|
882
|
+
border-radius: 4px;
|
|
883
|
+
padding: 8px 20px;
|
|
884
|
+
font-size: 14px;
|
|
885
|
+
font-weight: 500;
|
|
886
|
+
cursor: pointer;
|
|
887
|
+
transition: background 0.15s;
|
|
888
|
+
}
|
|
889
|
+
button:hover { background: #004d63; }
|
|
890
|
+
</style>
|
|
891
|
+
</head>
|
|
892
|
+
<body>
|
|
893
|
+
<div class="container">
|
|
894
|
+
<div class="status-code">${statusCode}</div>
|
|
895
|
+
<div class="title">${escapedTitle}</div>
|
|
896
|
+
<div class="detail"><pre>${escapedDetail}</pre></div>
|
|
897
|
+
<p class="message">Attempting to restart the dev server...</p>
|
|
898
|
+
<button onclick="window.parent.postMessage({type:'codeyam-server-error-retry'},'*')">Retry</button>
|
|
899
|
+
</div>
|
|
900
|
+
<script>
|
|
901
|
+
try { window.parent.postMessage({type:'codeyam-server-error',statusCode:${statusCode}},'*'); } catch(e) {}
|
|
902
|
+
</script>
|
|
903
|
+
</body>
|
|
904
|
+
</html>`;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* Handle POST /__codeyam__/preview-health — store health data in globalThis.
|
|
908
|
+
*/
|
|
909
|
+
function handlePreviewHealthPost(req, res) {
|
|
910
|
+
const chunks = [];
|
|
911
|
+
req.on('data', (chunk) => chunks.push(chunk));
|
|
912
|
+
req.on('end', () => {
|
|
913
|
+
try {
|
|
914
|
+
const body = JSON.parse(Buffer.concat(chunks).toString('utf-8'));
|
|
915
|
+
const current = getPreviewHealth() || {
|
|
916
|
+
errors: [],
|
|
917
|
+
loaded: false,
|
|
918
|
+
hasContent: false,
|
|
919
|
+
url: '',
|
|
920
|
+
lastUpdated: 0,
|
|
921
|
+
};
|
|
922
|
+
if (body.errors && Array.isArray(body.errors)) {
|
|
923
|
+
current.errors = current.errors.concat(body.errors);
|
|
924
|
+
}
|
|
925
|
+
if (body.loaded !== undefined) {
|
|
926
|
+
current.loaded = body.loaded;
|
|
927
|
+
}
|
|
928
|
+
if (body.hasContent !== undefined) {
|
|
929
|
+
current.hasContent = body.hasContent;
|
|
930
|
+
}
|
|
931
|
+
if (body.url) {
|
|
932
|
+
current.url = body.url;
|
|
933
|
+
}
|
|
934
|
+
current.lastUpdated = Date.now();
|
|
935
|
+
setPreviewHealth(current);
|
|
936
|
+
}
|
|
937
|
+
catch {
|
|
938
|
+
// Ignore malformed JSON
|
|
939
|
+
}
|
|
940
|
+
res.writeHead(204);
|
|
941
|
+
res.end();
|
|
942
|
+
});
|
|
943
|
+
}
|
|
201
944
|
/**
|
|
202
945
|
* Handle WebSocket upgrade by piping to the target dev server.
|
|
203
946
|
*/
|
|
204
947
|
function handleUpgrade(req, socket, head, targetUrl) {
|
|
205
948
|
const target = new URL(targetUrl);
|
|
949
|
+
const hostname = stripIPv6Brackets(target.hostname);
|
|
206
950
|
const port = parseInt(target.port, 10) || 80;
|
|
207
|
-
console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${
|
|
208
|
-
const proxySocket = net.connect(port,
|
|
951
|
+
console.log(`[editorProxy] WebSocket upgrade: ${req.url} → ${hostname}:${port}`);
|
|
952
|
+
const proxySocket = net.connect(port, hostname, () => {
|
|
209
953
|
// Reconstruct the HTTP upgrade request
|
|
210
954
|
const requestLine = `${req.method} ${req.url} HTTP/${req.httpVersion}\r\n`;
|
|
211
955
|
const headers = Object.entries(req.headers)
|
|
@@ -267,10 +1011,34 @@ function removeProxyConfig() {
|
|
|
267
1011
|
* Supports all HTTP methods (GET, POST, PUT, DELETE, PATCH) with body buffering.
|
|
268
1012
|
*/
|
|
269
1013
|
export async function startEditorProxy(options) {
|
|
270
|
-
//
|
|
1014
|
+
// If proxy is already running, reuse it (prevents second tab from killing first tab's proxy)
|
|
1015
|
+
const existing = getProxyState();
|
|
1016
|
+
if (existing) {
|
|
1017
|
+
console.log(`[editorProxy] Proxy already running on port ${existing.port} → ${existing.targetUrl}`);
|
|
1018
|
+
return { port: existing.port };
|
|
1019
|
+
}
|
|
1020
|
+
// Stop any leftover state (shouldn't happen, but defensive)
|
|
271
1021
|
await stopEditorProxy();
|
|
272
|
-
|
|
1022
|
+
let targetUrl = normalizeTargetUrl(options.targetUrl);
|
|
273
1023
|
let port = options.port;
|
|
1024
|
+
// When the target is localhost, probe to find the correct loopback address.
|
|
1025
|
+
// Dev servers may bind to IPv4 (127.0.0.1) or IPv6 (::1) — Vite 6 on macOS
|
|
1026
|
+
// binds to ::1 by default. We need to match the actual binding.
|
|
1027
|
+
try {
|
|
1028
|
+
const parsed = new URL(targetUrl);
|
|
1029
|
+
if (parsed.hostname === 'localhost') {
|
|
1030
|
+
const targetPort = parseInt(parsed.port || '80', 10);
|
|
1031
|
+
const resolvedHost = await resolveLoopbackAddress(targetPort);
|
|
1032
|
+
if (resolvedHost) {
|
|
1033
|
+
parsed.hostname = resolvedHost;
|
|
1034
|
+
targetUrl = parsed.toString().replace(/\/$/, '');
|
|
1035
|
+
console.log(`[editorProxy] Resolved localhost to ${resolvedHost} for port ${targetPort}`);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
catch {
|
|
1040
|
+
// Keep original targetUrl
|
|
1041
|
+
}
|
|
274
1042
|
console.log(`[editorProxy] Starting proxy (requested port ${port}, target ${targetUrl})`);
|
|
275
1043
|
const mockState = getMockStateManager();
|
|
276
1044
|
const server = http.createServer((req, res) => {
|
|
@@ -289,6 +1057,11 @@ export async function startEditorProxy(options) {
|
|
|
289
1057
|
res.end();
|
|
290
1058
|
return;
|
|
291
1059
|
}
|
|
1060
|
+
// Intercept preview health reports from the injected script
|
|
1061
|
+
if (method === 'POST' && pathname === '/__codeyam__/preview-health') {
|
|
1062
|
+
handlePreviewHealthPost(req, res);
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
292
1065
|
// Load scenario data (also feeds MockStateManager)
|
|
293
1066
|
readScenarioData();
|
|
294
1067
|
// For methods that may carry a body, buffer it first
|
|
@@ -320,11 +1093,17 @@ export async function startEditorProxy(options) {
|
|
|
320
1093
|
'Content-Type': 'application/json',
|
|
321
1094
|
'Access-Control-Allow-Origin': '*',
|
|
322
1095
|
'X-CodeYam-Proxy': 'scenario-data',
|
|
1096
|
+
'Cache-Control': 'no-store',
|
|
323
1097
|
});
|
|
324
1098
|
res.end(match.body != null ? JSON.stringify(match.body) : '');
|
|
325
1099
|
return;
|
|
326
1100
|
}
|
|
327
1101
|
// No mock match — forward with buffered body
|
|
1102
|
+
if ((currentScenarioType === 'application' ||
|
|
1103
|
+
currentScenarioType === 'user') &&
|
|
1104
|
+
pathname.startsWith('/api/')) {
|
|
1105
|
+
mockStateEventEmitter.emitDataMutationForwarded(method, pathname);
|
|
1106
|
+
}
|
|
328
1107
|
forwardBufferedRequest(req, res, targetUrl, bodyBuffer);
|
|
329
1108
|
return;
|
|
330
1109
|
}
|
|
@@ -336,6 +1115,7 @@ export async function startEditorProxy(options) {
|
|
|
336
1115
|
'Content-Type': 'application/json',
|
|
337
1116
|
'Access-Control-Allow-Origin': '*',
|
|
338
1117
|
'X-CodeYam-Proxy': 'scenario-data',
|
|
1118
|
+
'Cache-Control': 'no-store',
|
|
339
1119
|
});
|
|
340
1120
|
res.end(match.body != null ? JSON.stringify(match.body) : '');
|
|
341
1121
|
return;
|
|
@@ -360,7 +1140,10 @@ export async function startEditorProxy(options) {
|
|
|
360
1140
|
resolve();
|
|
361
1141
|
});
|
|
362
1142
|
});
|
|
363
|
-
port
|
|
1143
|
+
// When port 0 is requested, the OS assigns an ephemeral port
|
|
1144
|
+
const addr = server.address();
|
|
1145
|
+
port =
|
|
1146
|
+
typeof addr === 'object' && addr !== null ? addr.port : currentPort;
|
|
364
1147
|
const state = { server, port, targetUrl };
|
|
365
1148
|
setProxyState(state);
|
|
366
1149
|
// Write proxy-config.json for the preload module
|
|
@@ -403,6 +1186,41 @@ export async function stopEditorProxy() {
|
|
|
403
1186
|
*/
|
|
404
1187
|
export function invalidateScenarioCache() {
|
|
405
1188
|
scenarioCache = { data: null, timestamp: 0 };
|
|
1189
|
+
sessionConfig = undefined;
|
|
1190
|
+
seedSessionCookies = undefined;
|
|
1191
|
+
localStorageConfig = null;
|
|
1192
|
+
activeScenarioId = null;
|
|
1193
|
+
currentPrototypeId = null;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Verify that the proxy can successfully forward a request to the target dev server.
|
|
1197
|
+
* Makes a HEAD request through the proxy and checks that it gets a response (any status).
|
|
1198
|
+
* Returns false if the proxy isn't running or if the request fails entirely.
|
|
1199
|
+
*/
|
|
1200
|
+
export async function verifyProxyForwarding() {
|
|
1201
|
+
const state = getProxyState();
|
|
1202
|
+
if (!state) {
|
|
1203
|
+
console.warn('[editorProxy] Cannot verify — proxy is not running');
|
|
1204
|
+
return false;
|
|
1205
|
+
}
|
|
1206
|
+
try {
|
|
1207
|
+
const response = await fetch(`http://127.0.0.1:${state.port}/`, {
|
|
1208
|
+
method: 'HEAD',
|
|
1209
|
+
signal: AbortSignal.timeout(5000),
|
|
1210
|
+
});
|
|
1211
|
+
// Any response from the target (even 404) means forwarding works.
|
|
1212
|
+
// Only 502 (our own Bad Gateway) means the target is unreachable.
|
|
1213
|
+
if (response.status === 502) {
|
|
1214
|
+
console.warn(`[editorProxy] Verification failed — proxy returned 502 (target unreachable)`);
|
|
1215
|
+
return false;
|
|
1216
|
+
}
|
|
1217
|
+
console.log(`[editorProxy] Verification passed — proxy forwarding to ${state.targetUrl} (status ${response.status})`);
|
|
1218
|
+
return true;
|
|
1219
|
+
}
|
|
1220
|
+
catch (err) {
|
|
1221
|
+
console.warn(`[editorProxy] Verification failed — could not reach proxy on port ${state.port}`);
|
|
1222
|
+
return false;
|
|
1223
|
+
}
|
|
406
1224
|
}
|
|
407
1225
|
/**
|
|
408
1226
|
* Ensure the proxy is running. If it's not, start it using the current dev server URL.
|
|
@@ -424,9 +1242,10 @@ export async function ensureProxyRunning() {
|
|
|
424
1242
|
return null;
|
|
425
1243
|
}
|
|
426
1244
|
const codeyamPort = parseInt(process.env.CODEYAM_PORT || '3111', 10);
|
|
427
|
-
|
|
1245
|
+
const { proxyPort } = computeEditorPorts(codeyamPort);
|
|
1246
|
+
console.log(`[editorProxy] Proxy not running, starting on-demand (port ${proxyPort}, target ${devServer.url})`);
|
|
428
1247
|
const result = await startEditorProxy({
|
|
429
|
-
port:
|
|
1248
|
+
port: proxyPort,
|
|
430
1249
|
targetUrl: devServer.url,
|
|
431
1250
|
});
|
|
432
1251
|
if (result) {
|
|
@@ -437,4 +1256,8 @@ export async function ensureProxyRunning() {
|
|
|
437
1256
|
console.error('[editorProxy] Failed to start on-demand proxy');
|
|
438
1257
|
return null;
|
|
439
1258
|
}
|
|
1259
|
+
/**
|
|
1260
|
+
* Test-only export: trigger readScenarioData so tests can verify session config extraction.
|
|
1261
|
+
*/
|
|
1262
|
+
export const _readScenarioDataForTest = readScenarioData;
|
|
440
1263
|
//# sourceMappingURL=editorProxy.js.map
|