diff --git a/packages/db/src/migration-runtime.ts b/packages/db/src/migration-runtime.ts index 23a15b1c..3696b54b 100644 --- a/packages/db/src/migration-runtime.ts +++ b/packages/db/src/migration-runtime.ts @@ -66,13 +66,17 @@ async function ensureEmbeddedPostgresConnection( ): Promise { const EmbeddedPostgres = await loadEmbeddedPostgresCtor(); const postmasterPidFile = path.resolve(dataDir, "postmaster.pid"); + const pgVersionFile = path.resolve(dataDir, "PG_VERSION"); const runningPid = readRunningPostmasterPid(postmasterPidFile); const runningPort = readPidFilePort(postmasterPidFile); const preferredAdminConnectionString = `postgres://paperclip:paperclip@127.0.0.1:${preferredPort}/postgres`; - if (!runningPid) { + if (!runningPid && existsSync(pgVersionFile)) { try { await ensurePostgresDatabase(preferredAdminConnectionString, "paperclip"); + process.emitWarning( + `Adopting an existing PostgreSQL instance on port ${preferredPort} for embedded data dir ${dataDir} because postmaster.pid is missing.`, + ); return { connectionString: `postgres://paperclip:paperclip@127.0.0.1:${preferredPort}/paperclip`, source: `embedded-postgres@${preferredPort}`, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 122105c8..f6820f52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -226,9 +226,6 @@ importers: drizzle-orm: specifier: ^0.38.4 version: 0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4) - embedded-postgres: - specifier: ^18.1.0-beta.16 - version: 18.1.0-beta.16 postgres: specifier: ^3.4.5 version: 3.4.8 @@ -249,180 +246,6 @@ importers: specifier: ^3.0.5 version: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) - packages/plugins/create-paperclip-plugin: - dependencies: - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../sdk - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - typescript: - specifier: ^5.7.3 - version: 5.9.3 - - packages/plugins/examples/plugin-authoring-smoke-example: - dependencies: - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../../sdk - react: - specifier: '>=18' - version: 19.2.4 - devDependencies: - '@rollup/plugin-node-resolve': - specifier: ^16.0.1 - version: 16.0.3(rollup@4.57.1) - '@rollup/plugin-typescript': - specifier: ^12.1.2 - version: 12.3.0(rollup@4.57.1)(tslib@2.8.1)(typescript@5.9.3) - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - '@types/react': - specifier: ^19.0.8 - version: 19.2.14 - esbuild: - specifier: ^0.27.3 - version: 0.27.3 - rollup: - specifier: ^4.38.0 - version: 4.57.1 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - typescript: - specifier: ^5.7.3 - version: 5.9.3 - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) - - packages/plugins/examples/plugin-file-browser-example: - dependencies: - '@codemirror/lang-javascript': - specifier: ^6.2.2 - version: 6.2.4 - '@codemirror/language': - specifier: ^6.11.0 - version: 6.12.1 - '@codemirror/state': - specifier: ^6.4.0 - version: 6.5.4 - '@codemirror/view': - specifier: ^6.28.0 - version: 6.39.15 - '@lezer/highlight': - specifier: ^1.2.1 - version: 1.2.3 - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../../sdk - codemirror: - specifier: ^6.0.1 - version: 6.0.2 - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - '@types/react': - specifier: ^19.0.8 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.3 - version: 19.2.3(@types/react@19.2.14) - esbuild: - specifier: ^0.27.3 - version: 0.27.3 - react: - specifier: ^19.0.0 - version: 19.2.4 - react-dom: - specifier: ^19.0.0 - version: 19.2.4(react@19.2.4) - typescript: - specifier: ^5.7.3 - version: 5.9.3 - - packages/plugins/examples/plugin-hello-world-example: - dependencies: - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../../sdk - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - '@types/react': - specifier: ^19.0.8 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.3 - version: 19.2.3(@types/react@19.2.14) - react: - specifier: ^19.0.0 - version: 19.2.4 - react-dom: - specifier: ^19.0.0 - version: 19.2.4(react@19.2.4) - typescript: - specifier: ^5.7.3 - version: 5.9.3 - - packages/plugins/examples/plugin-kitchen-sink-example: - dependencies: - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../../sdk - '@paperclipai/shared': - specifier: workspace:* - version: link:../../../shared - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - '@types/react': - specifier: ^19.0.8 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.3 - version: 19.2.3(@types/react@19.2.14) - esbuild: - specifier: ^0.27.3 - version: 0.27.3 - react: - specifier: ^19.0.0 - version: 19.2.4 - react-dom: - specifier: ^19.0.0 - version: 19.2.4(react@19.2.4) - typescript: - specifier: ^5.7.3 - version: 5.9.3 - - packages/plugins/sdk: - dependencies: - '@paperclipai/shared': - specifier: workspace:* - version: link:../../shared - react: - specifier: '>=18' - version: 19.2.4 - zod: - specifier: ^3.24.2 - version: 3.25.76 - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - '@types/react': - specifier: ^19.0.8 - version: 19.2.14 - typescript: - specifier: ^5.7.3 - version: 5.9.3 - packages/shared: dependencies: zod: @@ -465,24 +288,12 @@ importers: '@paperclipai/db': specifier: workspace:* version: link:../packages/db - '@paperclipai/plugin-sdk': - specifier: workspace:* - version: link:../packages/plugins/sdk '@paperclipai/shared': specifier: workspace:* version: link:../packages/shared - ajv: - specifier: ^8.18.0 - version: 8.18.0 - ajv-formats: - specifier: ^3.0.1 - version: 3.0.1(ajv@8.18.0) better-auth: specifier: 1.4.18 version: 1.4.18(drizzle-kit@0.31.9)(drizzle-orm@0.38.4(@electric-sql/pglite@0.3.15)(@types/react@19.2.14)(kysely@0.28.11)(pg@8.18.0)(postgres@3.4.8)(react@19.2.4))(pg@8.18.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) - chokidar: - specifier: ^4.0.3 - version: 4.0.3 detect-port: specifier: ^2.1.0 version: 2.1.0 @@ -2625,37 +2436,6 @@ packages: '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - '@rollup/plugin-node-resolve@16.0.3': - resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/plugin-typescript@12.3.0': - resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - '@rollup/rollup-android-arm-eabi@4.57.1': resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} cpu: [arm] @@ -3288,9 +3068,6 @@ packages: '@types/react@19.2.14': resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - '@types/resolve@1.20.2': - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} @@ -3371,17 +3148,6 @@ packages: resolution: {integrity: sha512-XNAb/a6TCqou+TufU8/u11HCu9x1gYvOoxLwtlXgIqmkrYQADVv6ljyW2zwiPhHz9R1gItAWpuDrdJMmrOBFEA==} engines: {node: '>= 16.0.0'} - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - anser@2.3.5: resolution: {integrity: sha512-vcZjxvvVoxTeR5XBNJB38oTu/7eDCZlwdz32N1eNgpyPF7j/Z7Idf+CUwQOkKKpJ7RJyjxgLHCM7vdIK0iCNMQ==} @@ -3595,10 +3361,6 @@ packages: chevrotain@11.1.2: resolution: {integrity: sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -3898,10 +3660,6 @@ packages: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - default-browser-id@5.0.1: resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} engines: {node: '>=18'} @@ -4183,9 +3941,6 @@ packages: estree-util-visit@2.0.0: resolution: {integrity: sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==} - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -4216,9 +3971,6 @@ packages: fast-copy@4.0.2: resolution: {integrity: sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw==} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} @@ -4226,9 +3978,6 @@ packages: fast-safe-stringify@2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@5.3.6: resolution: {integrity: sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==} hasBin: true @@ -4416,10 +4165,6 @@ packages: is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -4448,9 +4193,6 @@ packages: engines: {node: '>=14.16'} hasBin: true - is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -4510,9 +4252,6 @@ packages: engines: {node: '>=6'} hasBin: true - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -5003,9 +4742,6 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -5294,10 +5030,6 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - real-require@0.2.0: resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} engines: {node: '>= 12.13.0'} @@ -5314,10 +5046,6 @@ packages: remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} @@ -5325,11 +5053,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -5534,10 +5257,6 @@ packages: resolution: {integrity: sha512-oK8WG9diS3DlhdUkcFn4tkNIiIbBx9lI2ClF8K+b2/m8Eyv47LSawxUzZQSNKUrVb2KsqeTDCcjAAVPYaSLVTA==} engines: {node: '>=14.18.0'} - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - tabbable@6.4.0: resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} @@ -8493,33 +8212,6 @@ snapshots: '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/plugin-node-resolve@16.0.3(rollup@4.57.1)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.57.1) - '@types/resolve': 1.20.2 - deepmerge: 4.3.1 - is-module: 1.0.0 - resolve: 1.22.11 - optionalDependencies: - rollup: 4.57.1 - - '@rollup/plugin-typescript@12.3.0(rollup@4.57.1)(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.57.1) - resolve: 1.22.11 - typescript: 5.9.3 - optionalDependencies: - rollup: 4.57.1 - tslib: 2.8.1 - - '@rollup/pluginutils@5.3.0(rollup@4.57.1)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.57.1 - '@rollup/rollup-android-arm-eabi@4.57.1': optional: true @@ -9242,8 +8934,6 @@ snapshots: dependencies: csstype: 3.2.3 - '@types/resolve@1.20.2': {} - '@types/send@1.2.1': dependencies: '@types/node': 25.2.3 @@ -9353,17 +9043,6 @@ snapshots: address@2.0.3: {} - ajv-formats@3.0.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - anser@2.3.5: {} ansi-colors@4.1.3: {} @@ -9530,10 +9209,6 @@ snapshots: '@chevrotain/utils': 11.1.2 lodash-es: 4.17.23 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 @@ -9842,8 +9517,6 @@ snapshots: deep-eql@5.0.2: {} - deepmerge@4.3.1: {} - default-browser-id@5.0.1: {} default-browser@5.5.0: @@ -10116,8 +9789,6 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/unist': 3.0.3 - estree-walker@2.0.2: {} - estree-walker@3.0.3: dependencies: '@types/estree': 1.0.8 @@ -10174,8 +9845,6 @@ snapshots: fast-copy@4.0.2: {} - fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10186,8 +9855,6 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-uri@3.1.0: {} - fast-xml-parser@5.3.6: dependencies: strnum: 2.1.2 @@ -10390,10 +10057,6 @@ snapshots: is-alphabetical: 2.0.1 is-decimal: 2.0.1 - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - is-decimal@2.0.1: {} is-docker@3.0.0: {} @@ -10412,8 +10075,6 @@ snapshots: dependencies: is-docker: 3.0.0 - is-module@1.0.0: {} - is-number@7.0.0: {} is-plain-obj@4.1.0: {} @@ -10455,8 +10116,6 @@ snapshots: jsesc@3.1.0: {} - json-schema-traverse@1.0.0: {} - json5@2.2.3: {} jsonfile@4.0.0: @@ -11214,8 +10873,6 @@ snapshots: path-key@3.1.1: {} - path-parse@1.0.7: {} - path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -11564,8 +11221,6 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@4.1.2: {} - real-require@0.2.0: {} remark-gfm@4.0.1: @@ -11602,18 +11257,10 @@ snapshots: mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - require-from-string@2.0.2: {} - resolve-from@5.0.0: {} resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - reusify@1.1.0: {} robust-predicates@3.0.2: {} @@ -11863,8 +11510,6 @@ snapshots: transitivePeerDependencies: - supports-color - supports-preserve-symlinks-flag@1.0.0: {} - tabbable@6.4.0: {} tailwind-merge@3.4.1: {} diff --git a/server/src/__tests__/workspace-runtime.test.ts b/server/src/__tests__/workspace-runtime.test.ts index 20dcf838..cddba34e 100644 --- a/server/src/__tests__/workspace-runtime.test.ts +++ b/server/src/__tests__/workspace-runtime.test.ts @@ -457,6 +457,8 @@ describe("ensureRuntimeServicesForRun", () => { expect(captured.customEnv).toBe("from-adapter"); expect(captured.port).toMatch(/^\d+$/); expect(services[0]?.executionWorkspaceId).toBe("execution-workspace-1"); + expect(services[0]?.scopeType).toBe("execution_workspace"); + expect(services[0]?.scopeId).toBe("execution-workspace-1"); }); it("stops execution workspace runtime services by executionWorkspaceId", async () => { @@ -584,4 +586,33 @@ describe("normalizeAdapterManagedRuntimeServices", () => { }); expect(first[0]?.id).toBe(second[0]?.id); }); + + it("prefers execution workspace ids over cwd for execution-scoped adapter services", () => { + const workspace = buildWorkspace("/tmp/project"); + + const refs = normalizeAdapterManagedRuntimeServices({ + adapterType: "openclaw_gateway", + runId: "run-1", + agent: { + id: "agent-1", + name: "Gateway Agent", + companyId: "company-1", + }, + issue: null, + workspace, + executionWorkspaceId: "execution-workspace-1", + reports: [ + { + serviceName: "preview", + scopeType: "execution_workspace", + }, + ], + }); + + expect(refs[0]).toMatchObject({ + scopeType: "execution_workspace", + scopeId: "execution-workspace-1", + executionWorkspaceId: "execution-workspace-1", + }); + }); }); diff --git a/server/src/routes/execution-workspaces.ts b/server/src/routes/execution-workspaces.ts index 1661ddc2..9c43bcd5 100644 --- a/server/src/routes/execution-workspaces.ts +++ b/server/src/routes/execution-workspaces.ts @@ -54,6 +54,7 @@ export function executionWorkspaceRoutes(db: Db) { ...req.body, ...(req.body.cleanupEligibleAt ? { cleanupEligibleAt: new Date(req.body.cleanupEligibleAt) } : {}), }; + let workspace = existing; let cleanupWarnings: string[] = []; if (req.body.status === "archived" && existing.status !== "archived") { @@ -73,52 +74,85 @@ export function executionWorkspaceRoutes(db: Db) { return; } - await stopRuntimeServicesForExecutionWorkspace({ - db, - executionWorkspaceId: existing.id, - workspaceCwd: existing.cwd, + const closedAt = new Date(); + const archivedWorkspace = await svc.update(id, { + ...patch, + status: "archived", + closedAt, + cleanupReason: null, }); - const projectWorkspace = existing.projectWorkspaceId - ? await db - .select({ - cwd: projectWorkspaces.cwd, - cleanupCommand: projectWorkspaces.cleanupCommand, - }) - .from(projectWorkspaces) - .where( - and( - eq(projectWorkspaces.id, existing.projectWorkspaceId), - eq(projectWorkspaces.companyId, existing.companyId), - ), - ) - .then((rows) => rows[0] ?? null) - : null; - const projectPolicy = existing.projectId - ? await db - .select({ - executionWorkspacePolicy: projects.executionWorkspacePolicy, - }) - .from(projects) - .where(and(eq(projects.id, existing.projectId), eq(projects.companyId, existing.companyId))) - .then((rows) => parseProjectExecutionWorkspacePolicy(rows[0]?.executionWorkspacePolicy)) - : null; - const cleanupResult = await cleanupExecutionWorkspaceArtifacts({ - workspace: existing, - projectWorkspace, - teardownCommand: projectPolicy?.workspaceStrategy?.teardownCommand ?? null, - }); - cleanupWarnings = cleanupResult.warnings; - patch.closedAt = new Date(); - patch.cleanupReason = cleanupWarnings.length > 0 ? cleanupWarnings.join(" | ") : null; - if (!cleanupResult.cleaned) { - patch.status = "cleanup_failed"; + if (!archivedWorkspace) { + res.status(404).json({ error: "Execution workspace not found" }); + return; } - } + workspace = archivedWorkspace; - const workspace = await svc.update(id, patch); - if (!workspace) { - res.status(404).json({ error: "Execution workspace not found" }); - return; + try { + await stopRuntimeServicesForExecutionWorkspace({ + db, + executionWorkspaceId: existing.id, + workspaceCwd: existing.cwd, + }); + const projectWorkspace = existing.projectWorkspaceId + ? await db + .select({ + cwd: projectWorkspaces.cwd, + cleanupCommand: projectWorkspaces.cleanupCommand, + }) + .from(projectWorkspaces) + .where( + and( + eq(projectWorkspaces.id, existing.projectWorkspaceId), + eq(projectWorkspaces.companyId, existing.companyId), + ), + ) + .then((rows) => rows[0] ?? null) + : null; + const projectPolicy = existing.projectId + ? await db + .select({ + executionWorkspacePolicy: projects.executionWorkspacePolicy, + }) + .from(projects) + .where(and(eq(projects.id, existing.projectId), eq(projects.companyId, existing.companyId))) + .then((rows) => parseProjectExecutionWorkspacePolicy(rows[0]?.executionWorkspacePolicy)) + : null; + const cleanupResult = await cleanupExecutionWorkspaceArtifacts({ + workspace: existing, + projectWorkspace, + teardownCommand: projectPolicy?.workspaceStrategy?.teardownCommand ?? null, + }); + cleanupWarnings = cleanupResult.warnings; + const cleanupPatch: Record = { + closedAt, + cleanupReason: cleanupWarnings.length > 0 ? cleanupWarnings.join(" | ") : null, + }; + if (!cleanupResult.cleaned) { + cleanupPatch.status = "cleanup_failed"; + } + if (cleanupResult.warnings.length > 0 || !cleanupResult.cleaned) { + workspace = (await svc.update(id, cleanupPatch)) ?? workspace; + } + } catch (error) { + const failureReason = error instanceof Error ? error.message : String(error); + workspace = + (await svc.update(id, { + status: "cleanup_failed", + closedAt, + cleanupReason: failureReason, + })) ?? workspace; + res.status(500).json({ + error: `Failed to archive execution workspace: ${failureReason}`, + }); + return; + } + } else { + const updatedWorkspace = await svc.update(id, patch); + if (!updatedWorkspace) { + res.status(404).json({ error: "Execution workspace not found" }); + return; + } + workspace = updatedWorkspace; } const actor = getActorInfo(req); await logActivity(db, { diff --git a/server/src/services/execution-workspace-policy.ts b/server/src/services/execution-workspace-policy.ts index 584f44e9..6f61e6d3 100644 --- a/server/src/services/execution-workspace-policy.ts +++ b/server/src/services/execution-workspace-policy.ts @@ -34,6 +34,7 @@ export function parseProjectExecutionWorkspacePolicy(raw: unknown): ProjectExecu const parsed = parseObject(raw); if (Object.keys(parsed).length === 0) return null; const enabled = typeof parsed.enabled === "boolean" ? parsed.enabled : false; + const workspaceStrategy = parseExecutionWorkspaceStrategy(parsed.workspaceStrategy); const defaultMode = asString(parsed.defaultMode, ""); const defaultProjectWorkspaceId = typeof parsed.defaultProjectWorkspaceId === "string" ? parsed.defaultProjectWorkspaceId : undefined; @@ -57,9 +58,7 @@ export function parseProjectExecutionWorkspacePolicy(raw: unknown): ProjectExecu ...(normalizedDefaultMode ? { defaultMode: normalizedDefaultMode } : {}), ...(allowIssueOverride !== undefined ? { allowIssueOverride } : {}), ...(defaultProjectWorkspaceId ? { defaultProjectWorkspaceId } : {}), - ...(parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) - ? { workspaceStrategy: parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) } - : {}), + ...(workspaceStrategy ? { workspaceStrategy } : {}), ...(parsed.workspaceRuntime && typeof parsed.workspaceRuntime === "object" && !Array.isArray(parsed.workspaceRuntime) ? { workspaceRuntime: { ...(parsed.workspaceRuntime as Record) } } : {}), @@ -81,6 +80,7 @@ export function parseProjectExecutionWorkspacePolicy(raw: unknown): ProjectExecu export function parseIssueExecutionWorkspaceSettings(raw: unknown): IssueExecutionWorkspaceSettings | null { const parsed = parseObject(raw); if (Object.keys(parsed).length === 0) return null; + const workspaceStrategy = parseExecutionWorkspaceStrategy(parsed.workspaceStrategy); const mode = asString(parsed.mode, ""); const normalizedMode = (() => { if ( @@ -101,9 +101,7 @@ export function parseIssueExecutionWorkspaceSettings(raw: unknown): IssueExecuti ...(normalizedMode ? { mode: normalizedMode as IssueExecutionWorkspaceSettings["mode"] } : {}), - ...(parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) - ? { workspaceStrategy: parseExecutionWorkspaceStrategy(parsed.workspaceStrategy) } - : {}), + ...(workspaceStrategy ? { workspaceStrategy } : {}), ...(parsed.workspaceRuntime && typeof parsed.workspaceRuntime === "object" && !Array.isArray(parsed.workspaceRuntime) ? { workspaceRuntime: { ...(parsed.workspaceRuntime as Record) } } : {}), diff --git a/server/src/services/workspace-runtime.ts b/server/src/services/workspace-runtime.ts index 87de0f08..9329a1f0 100644 --- a/server/src/services/workspace-runtime.ts +++ b/server/src/services/workspace-runtime.ts @@ -644,6 +644,7 @@ function buildTemplateData(input: { function resolveServiceScopeId(input: { service: Record; workspace: RealizedExecutionWorkspace; + executionWorkspaceId?: string | null; issue: ExecutionWorkspaceIssueRef | null; runId: string; agent: ExecutionWorkspaceAgentRef; @@ -659,7 +660,9 @@ function resolveServiceScopeId(input: { ? scopeTypeRaw : "run"; if (scopeType === "project_workspace") return { scopeType, scopeId: input.workspace.workspaceId ?? input.workspace.projectId }; - if (scopeType === "execution_workspace") return { scopeType, scopeId: input.workspace.cwd }; + if (scopeType === "execution_workspace") { + return { scopeType, scopeId: input.executionWorkspaceId ?? input.workspace.cwd }; + } if (scopeType === "agent") return { scopeType, scopeId: input.agent.id }; return { scopeType: "run" as const, scopeId: input.runId }; } @@ -780,7 +783,7 @@ export function normalizeAdapterManagedRuntimeServices(input: { (scopeType === "project_workspace" ? input.workspace.workspaceId : scopeType === "execution_workspace" - ? input.workspace.cwd + ? input.executionWorkspaceId ?? input.workspace.cwd : scopeType === "agent" ? input.agent.id : input.runId) ?? @@ -1043,6 +1046,7 @@ export async function ensureRuntimeServicesForRun(input: { const { scopeType, scopeId } = resolveServiceScopeId({ service, workspace: input.workspace, + executionWorkspaceId: input.executionWorkspaceId, issue: input.issue, runId: input.runId, agent: input.agent,