From c58938e2b36193f9f036955465c6df0a37a69490 Mon Sep 17 00:00:00 2001 From: korone Date: Tue, 4 Aug 2026 16:19:15 +0900 Subject: [PATCH 1/4] fix: restore gateway after dev refresh --- .changeset/quiet-wolves-connect.md | 5 +++ docs/development.md | 5 ++- packages/cli/src/dev.test.ts | 49 +++++++++++++++++++++++ packages/cli/src/dev.ts | 29 ++++++++++++-- scripts/dev-container-refresh.mjs | 22 +++++----- templates/fullstack-nest-svelte/README.md | 3 ++ templates/todo/README.md | 3 ++ 7 files changed, 103 insertions(+), 13 deletions(-) create mode 100644 .changeset/quiet-wolves-connect.md diff --git a/.changeset/quiet-wolves-connect.md b/.changeset/quiet-wolves-connect.md new file mode 100644 index 00000000..7e715352 --- /dev/null +++ b/.changeset/quiet-wolves-connect.md @@ -0,0 +1,5 @@ +--- +"@podosoft/podokit": patch +--- + +Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, and remove stale routes when a project's local hostname changes. diff --git a/docs/development.md b/docs/development.md index 59b72ee0..c538b5be 100644 --- a/docs/development.md +++ b/docs/development.md @@ -109,6 +109,8 @@ replace it with `npx @podosoft/podokit`, for example ```bash cd /tmp/myapp podo dev watch # core stack +# For a detached stack without source watching: +podo dev up -d # installed modules automatically enable cache/storage/queue as needed # first run only — create the tables (in the api container): podo dev exec api \ @@ -140,7 +142,8 @@ What you get: - **Live edits.** `podo dev watch` delegates to Compose Watch. The web has instant Vite HMR; an **API** source change restarts the api service (~5s) — the stable approach for NestJS in a container (its in-process watcher doesn't reliably respawn). -- **Lifecycle helpers.** Use `podo dev ps`, `podo dev logs`, `podo dev exec`, and +- **Lifecycle helpers.** Use `podo dev up -d` for a detached stack and `podo dev ps`, + `podo dev logs`, `podo dev exec`, and `podo dev down`. `down` automatically activates every Compose profile so it also removes optional services that were started by an earlier `watch` command. The last project removed also removes the shared gateway and network. diff --git a/packages/cli/src/dev.test.ts b/packages/cli/src/dev.test.ts index cf132d25..d3e68bbc 100644 --- a/packages/cli/src/dev.test.ts +++ b/packages/cli/src/dev.test.ts @@ -177,6 +177,55 @@ describe("PodoKit development gateway", () => { expect(calls.some(({ args }) => args[0] === "rm" && args.includes("podokit-dev-gateway"))).toBe(true); }); + it("starts a detached stack through the shared gateway", () => { + const root = project(); + const devHome = temporaryDirectory("podokit-dev-home-"); + process.env.PODOKIT_DEV_HOME = devHome; + const calls: string[][] = []; + let networkExists = false; + let gatewayExists = false; + const runner: CommandRunner = (_command, args) => { + calls.push(args); + if (args[0] === "info") return { status: 0, stdout: "27.0.0\n", stderr: "" }; + if (args[0] === "network" && args[1] === "inspect") { + return { status: networkExists ? 0 : 1, stdout: "", stderr: "" }; + } + if (args[0] === "network" && args[1] === "create") { + networkExists = true; + return { status: 0, stdout: "created\n", stderr: "" }; + } + if (args[0] === "inspect") { + return { + status: gatewayExists ? 0 : 1, + stdout: gatewayExists ? "1 true\n" : "", + stderr: "", + }; + } + if (args[0] === "run") gatewayExists = true; + return { status: 0, stdout: "", stderr: "" }; + }; + + runDevCommand(root, "up", ["-d", "--build"], runner); + + const upCall = calls.find((args) => args.includes("up")); + expect(upCall?.slice(-3)).toEqual(["up", "-d", "--build"]); + const originalRuntime = resolveDevRuntime(root); + expect(readFileSync(originalRuntime.runtimeComposePath, "utf8")).toContain( + "podokit-dev-gateway", + ); + expect(calls.filter((args) => args[0] === "run")).toHaveLength(1); + + writeFileSync( + join(root, ".podokit", "dev.json"), + JSON.stringify({ schemaVersion: 1, hostname: "renamed.localhost" }), + ); + runDevCommand(root, "up", ["-d"], runner); + const renamedRuntime = resolveDevRuntime(root); + expect(existsSync(join(devHome, "projects", `${originalRuntime.routeId}.json`))).toBe(false); + expect(existsSync(join(devHome, "routes", `${originalRuntime.routeId}.yml`))).toBe(false); + expect(existsSync(join(devHome, "projects", `${renamedRuntime.routeId}.json`))).toBe(true); + }); + it("activates every compose profile when stopping a project", () => { const root = project(); const devHome = temporaryDirectory("podokit-dev-home-"); diff --git a/packages/cli/src/dev.ts b/packages/cli/src/dev.ts index 46d302c2..359e7861 100644 --- a/packages/cli/src/dev.ts +++ b/packages/cli/src/dev.ts @@ -211,7 +211,8 @@ function writeRuntimeFiles(runtime: DevRuntime): void { } function registerRoute(runtime: DevRuntime): void { - const collision = activeEntries().find( + const entries = activeEntries(); + const collision = entries.find( (entry) => entry.hostname === runtime.config.hostname && entry.projectRoot !== runtime.projectRoot, ); if (collision) { @@ -219,6 +220,12 @@ function registerRoute(runtime: DevRuntime): void { `Development hostname ${runtime.config.hostname} is already registered by ${collision.projectRoot}. Change .podokit/dev.json or run podo dev down there.`, ); } + for (const stale of entries.filter( + (entry) => entry.projectRoot === runtime.projectRoot && entry.routeId !== runtime.routeId, + )) { + rmSync(join(registryDirectory(), `${stale.routeId}.json`), { force: true }); + rmSync(join(routesDirectory(), `${stale.routeId}.yml`), { force: true }); + } mkdirSync(registryDirectory(), { recursive: true }); mkdirSync(routesDirectory(), { recursive: true }); writeFileSync(routePath(runtime), renderRoute(runtime)); @@ -320,7 +327,7 @@ function runCompose(runtime: DevRuntime, args: string[], runner: CommandRunner): } function composeCommand( - action: "down" | "exec" | "logs" | "ps" | "watch", + action: "down" | "exec" | "logs" | "ps" | "up" | "watch", args: string[], installedProfiles: string[], ): string[] { @@ -391,6 +398,22 @@ export function runDevCommand( return; } + if (action === "up") { + ensureNetwork(runner); + registerRoute(runtime); + try { + ensureGateway(runner); + process.stdout.write(`Development URL: http://${runtime.config.hostname}\n`); + if (runtime.config.publicUrl) process.stdout.write(`Public OAuth URL: ${runtime.config.publicUrl}\n`); + runCompose(runtime, composeCommand("up", args, profiles), runner); + } catch (error) { + unregisterRoute(runtime); + stopGatewayWhenUnused(runner); + throw error; + } + return; + } + if (action === "down") { runCompose(runtime, composeCommand("down", args, profiles), runner); unregisterRoute(runtime); @@ -403,5 +426,5 @@ export function runDevCommand( return; } - throw new Error("Usage: podo dev [docker compose options]"); + throw new Error("Usage: podo dev [docker compose options]"); } diff --git a/scripts/dev-container-refresh.mjs b/scripts/dev-container-refresh.mjs index f9cde7ed..628f2475 100644 --- a/scripts/dev-container-refresh.mjs +++ b/scripts/dev-container-refresh.mjs @@ -3,12 +3,14 @@ // end to end — the repetitive, error-prone dance done in one command: // 1. read the app's installed modules from .podokit/manifest.json // 2. back up .env.docker and .podokit/dev.json (instance config) -// 3. docker compose down +// 3. podo dev down (all profiles, route, and gateway lifecycle) // 4. regenerate with dev-app.mjs --published (container-friendly, avoids the // host file:-link dangling-symlink issue — docs/pitfalls.md P-008) // 5. restore .env.docker -// 6. docker compose up -d --build, then force-recreate api (env-cache fix so -// trustedOrigins pick up the restored CORS_ORIGIN — P-005 "Invalid origin") +// 6. podo dev up -d --build, then force-recreate api (env-cache fix so +// trustedOrigins pick up the restored CORS_ORIGIN — P-005 "Invalid origin"). +// Going through podo reconnects the regenerated web container to the shared +// gateway network and re-registers its hostname route. // 7. run Better Auth and TypeORM migrations (new auth/module tables) // 8. health-check: wait until the site answers 200 via Traefik // @@ -22,6 +24,7 @@ import { fileURLToPath } from "node:url"; import { externalPackageSpec, planRefreshModules, refreshHost } from "./dev-container-refresh-lib.mjs"; const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +const cliEntry = join(repoRoot, "packages/cli/dist/index.js"); const args = process.argv.slice(2); const appDir = args.find((a) => !a.startsWith("--")) && resolve(args.find((a) => !a.startsWith("--"))); const addFlag = (() => { @@ -69,8 +72,8 @@ const corsLine = hasEnv ? (readFileSync(envDocker, "utf8").match(/^CORS_ORIGIN=( const host = refreshHost(corsLine); console.log(`Instance host: ${host}`); -// 3) compose down -try { sh("docker", ["compose", "-f", compose, "down"], { cwd: appDir }); } catch { /* ok */ } +// 3) stop every module profile and unregister the old route +try { sh("node", [cliEntry, "dev", "down"], { cwd: appDir }); } catch { /* ok */ } // 4) regenerate (container-friendly). External modules must be installed before // podo can resolve and add them, so replay them after the bundled module pass. @@ -103,10 +106,11 @@ try { } } -// 6) up + rebuild, then force-recreate api so it re-reads the restored env -sh("docker", ["compose", "-f", compose, "up", "-d", "--build"], { cwd: appDir }); -sh("docker", ["compose", "-f", compose, "up", "-d", "--force-recreate", "--no-build", "api"], { cwd: appDir }); -sh("docker", ["compose", "-f", compose, "up", "-d"], { cwd: appDir }); // ensure traefik/web are up +// 6) up + rebuild through podo so the shared gateway route/network are restored, +// then force-recreate api so it re-reads the restored env. +sh("node", [cliEntry, "dev", "up", "-d", "--build"], { cwd: appDir }); +sh("node", [cliEntry, "dev", "up", "-d", "--force-recreate", "--no-build", "api"], { cwd: appDir }); +sh("node", [cliEntry, "dev", "up", "-d"], { cwd: appDir }); // 7) wait for api, then run migrations const waitApi = async () => { diff --git a/templates/fullstack-nest-svelte/README.md b/templates/fullstack-nest-svelte/README.md index f7644c6b..3ec91334 100644 --- a/templates/fullstack-nest-svelte/README.md +++ b/templates/fullstack-nest-svelte/README.md @@ -27,6 +27,7 @@ Run lifecycle and container commands from a second terminal: ```bash npx @podosoft/podokit dev url +npx @podosoft/podokit dev up -d # detached stack without source watching npx @podosoft/podokit dev ps npx @podosoft/podokit dev logs npx @podosoft/podokit dev exec api npm run migration:run -w {{projectName}}-api @@ -35,6 +36,8 @@ npx @podosoft/podokit dev down `dev watch` reads `.podokit/manifest.json` and automatically activates `cache`, `storage`, and `queue` when installed modules require Redis, MinIO, or a worker. +`dev up` uses the same shared gateway and module profiles without keeping Compose +Watch attached. You can still activate an additional Compose profile explicitly: ```bash diff --git a/templates/todo/README.md b/templates/todo/README.md index e4631bcd..7ff748cf 100644 --- a/templates/todo/README.md +++ b/templates/todo/README.md @@ -28,6 +28,7 @@ In a second terminal, apply the included Todo migration and use the lifecycle he ```bash npx @podosoft/podokit dev exec api npm run migration:run -w {{projectName}}-api npx @podosoft/podokit dev url +npx @podosoft/podokit dev up -d # detached stack without source watching npx @podosoft/podokit dev ps npx @podosoft/podokit dev logs npx @podosoft/podokit dev down @@ -35,6 +36,8 @@ npx @podosoft/podokit dev down `dev watch` reads `.podokit/manifest.json` and automatically activates `cache`, `storage`, and `queue` when installed modules require Redis, MinIO, or a worker. +`dev up` uses the same shared gateway and module profiles without keeping Compose +Watch attached. You can still activate an additional Compose profile explicitly: ```bash From 6f34458f690a0806e9bce77a8a99216631a16629 Mon Sep 17 00:00:00 2001 From: korone Date: Tue, 4 Aug 2026 16:25:04 +0900 Subject: [PATCH 2/4] fix: seed new owned files during update --- .changeset/quiet-wolves-connect.md | 2 +- packages/cli/src/update.test.ts | 47 ++++++++++++++++++++++++++++++ packages/cli/src/update.ts | 22 ++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/.changeset/quiet-wolves-connect.md b/.changeset/quiet-wolves-connect.md index 7e715352..fd927d6a 100644 --- a/.changeset/quiet-wolves-connect.md +++ b/.changeset/quiet-wolves-connect.md @@ -2,4 +2,4 @@ "@podosoft/podokit": patch --- -Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, and remove stale routes when a project's local hostname changes. +Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, remove stale routes when a project's local hostname changes, and seed newly introduced owned files without overwriting existing application paths. diff --git a/packages/cli/src/update.test.ts b/packages/cli/src/update.test.ts index a4754082..1fd51162 100644 --- a/packages/cli/src/update.test.ts +++ b/packages/cli/src/update.test.ts @@ -309,6 +309,53 @@ describe("applyUpdate", () => { return templates; } + it("adds newly introduced owned template and module seeds once", () => { + const oldTemplates = oldTemplatesCopy(); + const extension = "apps/api/src/app.extensions.ts"; + const settingsComponent = + "apps/web/src/routes/(admin)/admin/settings/general-settings.svelte"; + rmSync(join(oldTemplates, "fullstack-nest-svelte", extension)); + rmSync(join(oldTemplates, "modules/admin-dashboard/files", settingsComponent)); + + const project = join(tmp(), "app"); + create({ + name: "app", + template: "fullstack-nest-svelte", + templatesDir: oldTemplates, + targetDir: project, + }); + addModule({ + projectRoot: project, + module: "admin-dashboard", + modulesDir: join(oldTemplates, "modules"), + }); + + expect(existsSync(join(project, extension))).toBe(false); + expect(existsSync(join(project, settingsComponent))).toBe(false); + const plan = planUpdate(project, REPO_TEMPLATES); + expect(plan.changes.find((change) => change.path === extension)).toMatchObject({ + action: "add", + tier: "owned", + }); + expect(plan.changes.find((change) => change.path === settingsComponent)).toMatchObject({ + action: "add", + tier: "owned", + }); + + const result = applyUpdate(project, REPO_TEMPLATES); + expect(result.written).toEqual(expect.arrayContaining([extension, settingsComponent])); + expect(readFilesLock(project)?.files[extension]?.tier).toBe("owned"); + expect(readFilesLock(project)?.files[settingsComponent]?.tier).toBe("owned"); + + writeFileSync(join(project, extension), "// application extension\n"); + rmSync(join(project, settingsComponent)); + const repeat = planUpdate(project, REPO_TEMPLATES); + expect(repeat.changes.find((change) => change.path === extension)?.action).toBe("skip"); + expect(repeat.changes.find((change) => change.path === settingsComponent)?.action).toBe( + "skip", + ); + }); + function legacyAdminProject(): string { const templates = legacyAdminTemplatesCopy(); const project = join(tmp(), "legacy-admin-app"); diff --git a/packages/cli/src/update.ts b/packages/cli/src/update.ts index 1ff01347..c3e7cd5a 100644 --- a/packages/cli/src/update.ts +++ b/packages/cli/src/update.ts @@ -242,6 +242,14 @@ export function planUpdate(projectRoot: string, templatesDir: string): UpdatePla const tier: Tier = controlledByTarget ? classified : locked?.tier ?? classified; if (tier === "owned") { + // A file introduced by a newer template or module has no previous lock + // entry. Seed it once when the application has not already claimed that + // path; subsequent edits or deletions stay protected by the recorded + // owned entry. + if (!locked && disk === null && newText !== null) { + changes.push({ path, tier, action: "add", note: "new owned seed in this version" }); + continue; + } const explicitlyOwned = ownedGlobs.some( (glob) => !glob.includes("*") && matchGlob(path, glob), ); @@ -440,6 +448,20 @@ function updatedFilesLock( } } + // Keep a tombstone for an owned seed that the application deleted or moved. + // Without the previous entry, the next update would mistake the missing path + // for a newly introduced seed and recreate it. + for (const [path, entry] of Object.entries(previous.files)) { + if (entry.tier !== "owned" || next.files[path]) continue; + const newText = treeText(newTree, path); + if ( + newText !== null && + classifyTier(path, newText, ownedGlobs, managedOverrides) === "owned" + ) { + next.files[path] = entry; + } + } + return next; } From 26223cbd97d6e5f3c295ea0bcece88cf3dc19525 Mon Sep 17 00:00:00 2001 From: korone Date: Tue, 4 Aug 2026 16:27:29 +0900 Subject: [PATCH 3/4] fix: update pristine owned seeds --- .changeset/quiet-wolves-connect.md | 2 +- packages/cli/src/update.test.ts | 44 ++++++++++++++++++++++++++++++ packages/cli/src/update.ts | 15 ++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/.changeset/quiet-wolves-connect.md b/.changeset/quiet-wolves-connect.md index fd927d6a..b009dc84 100644 --- a/.changeset/quiet-wolves-connect.md +++ b/.changeset/quiet-wolves-connect.md @@ -2,4 +2,4 @@ "@podosoft/podokit": patch --- -Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, remove stale routes when a project's local hostname changes, and seed newly introduced owned files without overwriting existing application paths. +Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, remove stale routes when a project's local hostname changes, and safely deliver new or pristine owned seeds without overwriting application edits, deletions, or moves. diff --git a/packages/cli/src/update.test.ts b/packages/cli/src/update.test.ts index 1fd51162..cce31552 100644 --- a/packages/cli/src/update.test.ts +++ b/packages/cli/src/update.test.ts @@ -356,6 +356,50 @@ describe("applyUpdate", () => { ); }); + it("updates pristine owned seeds while preserving application edits", () => { + const oldTemplates = oldTemplatesCopy(); + const layout = "apps/web/src/routes/+layout.svelte"; + const oldLayoutPath = join(oldTemplates, "fullstack-nest-svelte", layout); + writeFileSync(oldLayoutPath, "
old generated layout
\n"); + + const pristineProject = join(tmp(), "pristine-app"); + create({ + name: "pristine-app", + template: "fullstack-nest-svelte", + templatesDir: oldTemplates, + targetDir: pristineProject, + }); + expect( + planUpdate(pristineProject, REPO_TEMPLATES).changes.find( + (change) => change.path === layout, + ), + ).toMatchObject({ action: "update", tier: "owned" }); + const result = applyUpdate(pristineProject, REPO_TEMPLATES); + expect(result.written).toContain(layout); + expect(readFileSync(join(pristineProject, layout), "utf8")).toBe( + readFileSync(join(REPO_TEMPLATES, "fullstack-nest-svelte", layout), "utf8"), + ); + + const editedProject = join(tmp(), "edited-app"); + create({ + name: "edited-app", + template: "fullstack-nest-svelte", + templatesDir: oldTemplates, + targetDir: editedProject, + }); + writeFileSync(join(editedProject, layout), "
application layout
\n"); + expect( + planUpdate(editedProject, REPO_TEMPLATES).changes.find( + (change) => change.path === layout, + )?.action, + ).toBe("skip"); + const editedResult = applyUpdate(editedProject, REPO_TEMPLATES); + expect(editedResult.written).not.toContain(layout); + expect(readFileSync(join(editedProject, layout), "utf8")).toBe( + "
application layout
\n", + ); + }); + function legacyAdminProject(): string { const templates = legacyAdminTemplatesCopy(); const project = join(tmp(), "legacy-admin-app"); diff --git a/packages/cli/src/update.ts b/packages/cli/src/update.ts index c3e7cd5a..6d395e21 100644 --- a/packages/cli/src/update.ts +++ b/packages/cli/src/update.ts @@ -250,6 +250,21 @@ export function planUpdate(projectRoot: string, templatesDir: string): UpdatePla changes.push({ path, tier, action: "add", note: "new owned seed in this version" }); continue; } + if ( + locked?.tier === "owned" && + disk !== null && + newText !== null && + hashContent(disk) === locked.outHash && + hashContent(newText) !== locked.outHash + ) { + changes.push({ + path, + tier, + action: "update", + note: "pristine owned seed update", + }); + continue; + } const explicitlyOwned = ownedGlobs.some( (glob) => !glob.includes("*") && matchGlob(path, glob), ); From ed732b979c8e0de8dd175b0d4ffced26781cfd3c Mon Sep 17 00:00:00 2001 From: korone Date: Tue, 4 Aug 2026 16:30:05 +0900 Subject: [PATCH 4/4] fix: preserve existing owned files --- .changeset/quiet-wolves-connect.md | 2 +- packages/cli/src/update.test.ts | 44 ------------------------------ packages/cli/src/update.ts | 15 ---------- 3 files changed, 1 insertion(+), 60 deletions(-) diff --git a/.changeset/quiet-wolves-connect.md b/.changeset/quiet-wolves-connect.md index b009dc84..fd927d6a 100644 --- a/.changeset/quiet-wolves-connect.md +++ b/.changeset/quiet-wolves-connect.md @@ -2,4 +2,4 @@ "@podosoft/podokit": patch --- -Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, remove stale routes when a project's local hostname changes, and safely deliver new or pristine owned seeds without overwriting application edits, deletions, or moves. +Add a detached `podo dev up` lifecycle command, restore shared gateway routing when refreshing generated development apps, remove stale routes when a project's local hostname changes, and seed newly introduced owned files without overwriting existing application paths. diff --git a/packages/cli/src/update.test.ts b/packages/cli/src/update.test.ts index cce31552..1fd51162 100644 --- a/packages/cli/src/update.test.ts +++ b/packages/cli/src/update.test.ts @@ -356,50 +356,6 @@ describe("applyUpdate", () => { ); }); - it("updates pristine owned seeds while preserving application edits", () => { - const oldTemplates = oldTemplatesCopy(); - const layout = "apps/web/src/routes/+layout.svelte"; - const oldLayoutPath = join(oldTemplates, "fullstack-nest-svelte", layout); - writeFileSync(oldLayoutPath, "
old generated layout
\n"); - - const pristineProject = join(tmp(), "pristine-app"); - create({ - name: "pristine-app", - template: "fullstack-nest-svelte", - templatesDir: oldTemplates, - targetDir: pristineProject, - }); - expect( - planUpdate(pristineProject, REPO_TEMPLATES).changes.find( - (change) => change.path === layout, - ), - ).toMatchObject({ action: "update", tier: "owned" }); - const result = applyUpdate(pristineProject, REPO_TEMPLATES); - expect(result.written).toContain(layout); - expect(readFileSync(join(pristineProject, layout), "utf8")).toBe( - readFileSync(join(REPO_TEMPLATES, "fullstack-nest-svelte", layout), "utf8"), - ); - - const editedProject = join(tmp(), "edited-app"); - create({ - name: "edited-app", - template: "fullstack-nest-svelte", - templatesDir: oldTemplates, - targetDir: editedProject, - }); - writeFileSync(join(editedProject, layout), "
application layout
\n"); - expect( - planUpdate(editedProject, REPO_TEMPLATES).changes.find( - (change) => change.path === layout, - )?.action, - ).toBe("skip"); - const editedResult = applyUpdate(editedProject, REPO_TEMPLATES); - expect(editedResult.written).not.toContain(layout); - expect(readFileSync(join(editedProject, layout), "utf8")).toBe( - "
application layout
\n", - ); - }); - function legacyAdminProject(): string { const templates = legacyAdminTemplatesCopy(); const project = join(tmp(), "legacy-admin-app"); diff --git a/packages/cli/src/update.ts b/packages/cli/src/update.ts index 6d395e21..c3e7cd5a 100644 --- a/packages/cli/src/update.ts +++ b/packages/cli/src/update.ts @@ -250,21 +250,6 @@ export function planUpdate(projectRoot: string, templatesDir: string): UpdatePla changes.push({ path, tier, action: "add", note: "new owned seed in this version" }); continue; } - if ( - locked?.tier === "owned" && - disk !== null && - newText !== null && - hashContent(disk) === locked.outHash && - hashContent(newText) !== locked.outHash - ) { - changes.push({ - path, - tier, - action: "update", - note: "pristine owned seed update", - }); - continue; - } const explicitlyOwned = ownedGlobs.some( (glob) => !glob.includes("*") && matchGlob(path, glob), );