@coreframe/scripts 0.1.19 → 0.1.21

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.
@@ -117,6 +117,12 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
117
117
  base: string | undefined;
118
118
  apply: boolean;
119
119
  };
120
+ } | {
121
+ command: "sync-coreframe-packages";
122
+ args: {
123
+ target: string;
124
+ apply: boolean;
125
+ };
120
126
  };
121
127
  } | {
122
128
  command: "db";
@@ -282,6 +288,12 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
282
288
  base: string | undefined;
283
289
  apply: boolean;
284
290
  };
291
+ } | {
292
+ command: "sync-coreframe-packages";
293
+ args: {
294
+ target: string;
295
+ apply: boolean;
296
+ };
285
297
  };
286
298
  } | {
287
299
  command: "db";
@@ -388,6 +400,9 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
388
400
  } | {
389
401
  command: "fast-forward-template-files";
390
402
  value: void;
403
+ } | {
404
+ command: "sync-coreframe-packages";
405
+ value: void;
391
406
  };
392
407
  } | {
393
408
  command: "db";
@@ -485,6 +500,9 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
485
500
  } | {
486
501
  command: "fast-forward-template-files";
487
502
  value: void;
503
+ } | {
504
+ command: "sync-coreframe-packages";
505
+ value: void;
488
506
  };
489
507
  } | {
490
508
  command: "db";
package/dist/coreframe.js CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import{addAsset as e,buildAssets as t,checkAssets as n,printAssetResult as r,publishAssets as i}from"./assets.js";import{runDrizzleKitCommand as a}from"./db/drizzle-kit.js";import{seedLocalDb as o}from"./db/seed.js";import{migrateLocalDb as s}from"./db/migrate.js";import{resetLocalDb as c}from"./db/reset.js";import{setupLocalDb as l}from"./db/setup.js";import{ensureLocalDb as u}from"./db/ensure.js";import{migrateHeldMigrations as d}from"./db/migrate-held.js";import{checkSchemaPush as f}from"./db/schema-check.js";import{deployEnvironments as p,tauriReleasePlatforms as m}from"./deploy/config.js";import{discoverStagingUrl as h,reassignStagingHostname as g}from"./staging.js";import{discardPendingWorkerSecret as _,inspectWorkerEnvironment as v,queueWorkerSecret as y}from"./worker-environment.js";import{deployProject as b}from"./deploy.js";import{checkDeployMigrations as x}from"./deploy/check-migrations.js";import{devPlatforms as S,runDevServer as C}from"./dev.js";import{run as w}from"./runner.js";import{typecheckProject as T}from"./typecheck.js";import{checkUpgradeSkillCurrent as E}from"./upgrade/check-skill-current.js";import{ensureTemplateRemote as D}from"./upgrade/ensure-template-remote.js";import{fastForwardTemplateFiles as O}from"./upgrade/fast-forward-template-files.js";import*as k from"@clack/prompts";import{array as A,command as j,extendType as M,flag as N,multioption as P,number as F,oneOf as I,option as L,optional as R,positional as z,rest as B,string as V,subcommands as H}from"cmd-ts";const U=[`Cookies and sessions are origin-scoped.`,`Exact-host passkeys may require re-registration unless a stable eligible parent RP ID was configured in advance.`,`External OAuth callbacks such as Google may need updating.`,`Database data and private backend resources are unchanged.`],W=M(V,{displayName:`widths`,description:`Comma-separated responsive variant widths.`,async from(e){let t=e.split(`,`).map(e=>Number(e));if(t.length===0||t.some(e=>!Number.isInteger(e)||e<=0)||t.some((e,n)=>n>0&&e<=t[n-1]))throw Error(`Widths must be positive, unique, strictly ascending integers.`);return t}}),G=H({name:`coreframe`,cmds:{assets:H({name:`assets`,cmds:{add:j({name:`add`,args:{file:z({type:V,displayName:`file`,description:`Source image to add to the asset library.`}),id:L({long:`id`,type:V,description:`Logical asset ID, such as blog/my-post/hero.`}),alt:L({long:`alt`,type:V,description:`Required alt text for the asset.`}),variantWidths:L({long:`widths`,type:R(W),description:`Generate exactly these comma-separated widths instead of the default ladder.`}),json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({alt:t,file:n,id:i,json:a,variantWidths:o})=>r(await e({alt:t,file:n,id:i,json:a,variantWidths:o}),a)}),build:j({name:`build`,args:{id:L({long:`id`,type:R(V),description:`Build only one logical asset ID.`}),noPull:N({long:`no-pull`,description:`Do not perform targeted Git LFS pulls for missing source objects.`,defaultValue:()=>!1}),json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({id:e,json:n,noPull:i})=>r(await t({id:e,json:n,pull:!i}),n)}),check:j({name:`check`,args:{fix:N({long:`fix`,description:`Build missing generated variants when possible.`,defaultValue:()=>!1}),json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({fix:e,json:t})=>{let i=await n({fix:e,json:t});r(i,t),i.ok||(process.exitCode=1)}}),publish:j({name:`publish`,args:{outputDir:L({long:`output-dir`,type:R(V),description:`Root directory for additive local publish output. Defaults to COREFRAME_ASSETS_PUBLISH_DIR or release-upload.`}),json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e,outputDir:t})=>{let n=await i({json:e,outputDir:t});r(n,e),n.ok||(process.exitCode=1)}}),status:j({name:`status`,args:{json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await n({json:e});r(t,e),t.ok||(process.exitCode=1)}})}}),deploy:j({name:`deploy`,args:{environment:z({type:I(p),displayName:`environment`,description:`Deploy to the staging or production environment.`}),runMigrations:N({long:`run-migrations`,description:`Run pending deploy-safe database migrations before deploying.`,defaultValue:()=>!1}),skipMigrations:N({long:`skip-migrations`,description:`Deploy without running pending deploy-safe database migrations.`,defaultValue:()=>!1}),skipPostDeployChecks:N({long:`skip-post-deploy-checks`,description:`Skip post-deploy checks after Cloudflare deployment.`,defaultValue:()=>!1}),tauriLocalPlatforms:P({long:`tauri-local-platform`,type:A(I(m)),description:`Build one Tauri release platform locally. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowName:L({long:`tauri-workflow-name`,type:R(V),description:`GitHub Actions workflow file or name for remote Tauri release builds.`}),tauriWorkflowPlatforms:P({long:`tauri-workflow-platform`,type:A(I(m)),description:`Build one Tauri release platform with GitHub Actions. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowRef:L({long:`tauri-workflow-ref`,type:R(V),description:`Git ref used when dispatching remote Tauri release builds.`}),yes:N({long:`yes`,short:`y`,description:`Approve the production deployment confirmation.`,defaultValue:()=>!1})},handler:({environment:e,runMigrations:t,skipMigrations:n,skipPostDeployChecks:r,tauriLocalPlatforms:i,tauriWorkflowName:a,tauriWorkflowPlatforms:o,tauriWorkflowRef:s,yes:c})=>b([e,...t?[`--run-migrations`]:[],...n?[`--skip-migrations`]:[],...r?[`--skip-post-deploy-checks`]:[],...i.flatMap(e=>[`--tauri-local-platform`,e]),...a?[`--tauri-workflow-name`,a]:[],...o.flatMap(e=>[`--tauri-workflow-platform`,e]),...s?[`--tauri-workflow-ref`,s]:[],...c?[`--yes`]:[]])}),staging:H({name:`staging`,cmds:{reassign:j({name:`reassign`,args:{json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await g();if(e){console.log(JSON.stringify({...t,notices:U}));return}console.log(t.url),console.error(`Staging hostname reassigned. ${U.join(` `)}`)}}),url:j({name:`url`,args:{json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await h();console.log(e?JSON.stringify({url:t}):t)}})}}),secrets:H({name:`secrets`,cmds:{status:j({name:`status`,args:{environment:z({type:R(I(p)),displayName:`environment`,description:`Inspect staging, production, or both when omitted.`}),json:N({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({environment:e,json:t})=>{let n=await v({environment:e});console.log(t?JSON.stringify(n):K(n))}}),set:j({name:`set`,args:{environment:z({type:I(p),displayName:`environment`,description:`Worker environment to update on its next deploy.`}),name:z({type:V,displayName:`name`,description:`Declared Worker secret name.`})},handler:async({environment:e,name:t})=>{await y({environment:e,name:t,value:await q(t)}),console.log(`Queued ${t} for ${e}. Run coreframe deploy ${e} to apply.`)}}),discard:j({name:`discard`,args:{environment:z({type:I(p),displayName:`environment`,description:`Worker environment with a queued secret update.`}),name:z({type:V,displayName:`name`,description:`Declared Worker secret name.`})},handler:async({environment:e,name:t})=>{let n=await _({environment:e,name:t});console.log(n?`Discarded the queued ${t} update for ${e}.`:`No ${t} update is queued for ${e}.`)}})}}),typecheck:j({name:`typecheck`,args:{},handler:T}),dev:j({name:`dev`,args:{https:N({long:`https`,description:`Serve the web app over locally trusted HTTPS.`,defaultValue:()=>!1}),host:L({long:`host`,type:R(V),description:`Host address for the web development server.`}),managed:N({long:`managed`,description:`Run managed checkout synchronization even without an interactive terminal.`,defaultValue:()=>!1}),noManaged:N({long:`no-managed`,description:`Run without managed checkout synchronization for this invocation.`,defaultValue:()=>!1}),platform:z({type:R(I(S)),displayName:`platform`,description:`Development target platform. Defaults to web.`}),port:L({long:`port`,type:R(F),description:`Port for the web development server.`})},handler:({host:e,https:t,managed:n,noManaged:r,platform:i,port:a})=>C({host:e,https:t,managed:n,noManaged:r,platform:i??`web`,webPort:a})}),upgrade:H({name:`upgrade`,cmds:{"ensure-template-remote":j({name:`ensure-template-remote`,args:{remote:L({long:`remote`,type:V,defaultValue:()=>`template`,description:`Remote name to ensure.`}),noFetch:N({long:`no-fetch`,description:`Do not fetch the remote after ensuring it exists.`,defaultValue:()=>!1})},handler:({noFetch:e,remote:t})=>D({fetch:!e,remote:t})}),"check-skill-current":j({name:`check-skill-current`,args:{target:L({long:`target`,type:V,description:`Target Coreframe template git ref.`}),apply:N({long:`apply`,description:`Replace the local upgrade skill with the target version when it differs.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>{process.exitCode=E({apply:e,target:t})}}),"fast-forward-template-files":j({name:`fast-forward-template-files`,args:{target:L({long:`target`,type:V,description:`Target Coreframe template git ref.`}),base:L({long:`base`,type:R(V),description:`Previous Coreframe template git ref. Defaults to package.json engines.coreframe.`}),apply:N({long:`apply`,description:`Write clean fast-forwards to the worktree.`,defaultValue:()=>!1})},handler:({apply:e,base:t,target:n})=>O({apply:e,base:t,target:n})})}}),db:H({name:`db`,cmds:{ensure:j({name:`ensure`,args:{},handler:u}),generate:j({name:`generate`,args:{args:B({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit generate.`})},handler:({args:e})=>a(`generate`,e)}),migrate:j({name:`migrate`,args:{args:B({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit migrate.`})},handler:({args:e})=>a(`migrate`,e)}),"migrate-held":j({name:`migrate-held`,args:{confirm:L({long:`confirm`,type:R(I([`run-held-migrations`])),description:`Required confirmation value for held migrations.`})},handler:({confirm:e})=>d({argv:e?[`--confirm=${e}`]:[]})}),"migrate-local":j({name:`migrate-local`,args:{},handler:s}),"migrations-check":j({name:`migrations-check`,args:{},handler:x}),reset:j({name:`reset`,args:{},handler:c}),seed:j({name:`seed`,args:{},handler:()=>o()}),"schema-check":j({name:`schema-check`,args:{seed:N({long:`seed`,description:`Run the configured project seed against the throwaway database.`,defaultValue:()=>!1})},handler:({seed:e})=>f({seed:e})}),setup:j({name:`setup`,args:{},handler:()=>l()}),studio:j({name:`studio`,args:{args:B({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit studio.`})},handler:({args:e})=>a(`studio`,e)})}})}});import.meta.main&&w(G);function K(e){if(e.entries.length===0)return`No Worker environment values are declared in coreframe.config.ts.`;let t=e.entries.map(e=>[e.name,e.kind,e.local===`override`?`override`:`built-in default`,e.deployed.staging.replaceAll(`_`,` `),e.deployed.production.replaceAll(`_`,` `)]),n=[`Name`,`Kind`,`Local`,`Staging`,`Production`],r=n.map((e,n)=>Math.max(e.length,...t.map(e=>e[n].length))),i=e=>e.map((e,t)=>e.padEnd(r[t])).join(` `).trimEnd();return[i(n),i(r.map(e=>`-`.repeat(e))),...t].join(`
3
- `)}async function q(e){if(!process.stdin.isTTY){let e=``;for await(let t of process.stdin)e+=t.toString();return e.replace(/\r?\n$/,``)}let t=await k.password({message:`Enter the new value for ${e}`});if(k.isCancel(t))throw k.cancel(`Secret update cancelled.`),Error(`Secret update cancelled.`);return t}export{G as coreframeCli};
2
+ import{addAsset as e,buildAssets as t,checkAssets as n,printAssetResult as r,publishAssets as i}from"./assets.js";import{runDrizzleKitCommand as a}from"./db/drizzle-kit.js";import{seedLocalDb as o}from"./db/seed.js";import{migrateLocalDb as s}from"./db/migrate.js";import{resetLocalDb as c}from"./db/reset.js";import{setupLocalDb as l}from"./db/setup.js";import{ensureLocalDb as u}from"./db/ensure.js";import{migrateHeldMigrations as d}from"./db/migrate-held.js";import{checkSchemaPush as f}from"./db/schema-check.js";import{deployEnvironments as p,tauriReleasePlatforms as m}from"./deploy/config.js";import{discoverStagingUrl as h,reassignStagingHostname as g}from"./staging.js";import{discardPendingWorkerSecret as _,inspectWorkerEnvironment as v,queueWorkerSecret as y}from"./worker-environment.js";import{deployProject as b}from"./deploy.js";import{checkDeployMigrations as x}from"./deploy/check-migrations.js";import{devPlatforms as S,runDevServer as C}from"./dev.js";import{run as w}from"./runner.js";import{typecheckProject as T}from"./typecheck.js";import{checkUpgradeSkillCurrent as E}from"./upgrade/check-skill-current.js";import{ensureTemplateRemote as D}from"./upgrade/ensure-template-remote.js";import{fastForwardTemplateFiles as O}from"./upgrade/fast-forward-template-files.js";import{syncCoreframePackages as k}from"./upgrade/sync-coreframe-packages.js";import*as A from"@clack/prompts";import{array as j,command as M,extendType as N,flag as P,multioption as F,number as I,oneOf as L,option as R,optional as z,positional as B,rest as V,string as H,subcommands as U}from"cmd-ts";const W=[`Cookies and sessions are origin-scoped.`,`Exact-host passkeys may require re-registration unless a stable eligible parent RP ID was configured in advance.`,`External OAuth callbacks such as Google may need updating.`,`Database data and private backend resources are unchanged.`],G=N(H,{displayName:`widths`,description:`Comma-separated responsive variant widths.`,async from(e){let t=e.split(`,`).map(e=>Number(e));if(t.length===0||t.some(e=>!Number.isInteger(e)||e<=0)||t.some((e,n)=>n>0&&e<=t[n-1]))throw Error(`Widths must be positive, unique, strictly ascending integers.`);return t}}),K=U({name:`coreframe`,cmds:{assets:U({name:`assets`,cmds:{add:M({name:`add`,args:{file:B({type:H,displayName:`file`,description:`Source image to add to the asset library.`}),id:R({long:`id`,type:H,description:`Logical asset ID, such as blog/my-post/hero.`}),alt:R({long:`alt`,type:H,description:`Required alt text for the asset.`}),variantWidths:R({long:`widths`,type:z(G),description:`Generate exactly these comma-separated widths instead of the default ladder.`}),json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({alt:t,file:n,id:i,json:a,variantWidths:o})=>r(await e({alt:t,file:n,id:i,json:a,variantWidths:o}),a)}),build:M({name:`build`,args:{id:R({long:`id`,type:z(H),description:`Build only one logical asset ID.`}),noPull:P({long:`no-pull`,description:`Do not perform targeted Git LFS pulls for missing source objects.`,defaultValue:()=>!1}),json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({id:e,json:n,noPull:i})=>r(await t({id:e,json:n,pull:!i}),n)}),check:M({name:`check`,args:{fix:P({long:`fix`,description:`Build missing generated variants when possible.`,defaultValue:()=>!1}),json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({fix:e,json:t})=>{let i=await n({fix:e,json:t});r(i,t),i.ok||(process.exitCode=1)}}),publish:M({name:`publish`,args:{outputDir:R({long:`output-dir`,type:z(H),description:`Root directory for additive local publish output. Defaults to COREFRAME_ASSETS_PUBLISH_DIR or release-upload.`}),json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e,outputDir:t})=>{let n=await i({json:e,outputDir:t});r(n,e),n.ok||(process.exitCode=1)}}),status:M({name:`status`,args:{json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await n({json:e});r(t,e),t.ok||(process.exitCode=1)}})}}),deploy:M({name:`deploy`,args:{environment:B({type:L(p),displayName:`environment`,description:`Deploy to the staging or production environment.`}),runMigrations:P({long:`run-migrations`,description:`Run pending deploy-safe database migrations before deploying.`,defaultValue:()=>!1}),skipMigrations:P({long:`skip-migrations`,description:`Deploy without running pending deploy-safe database migrations.`,defaultValue:()=>!1}),skipPostDeployChecks:P({long:`skip-post-deploy-checks`,description:`Skip post-deploy checks after Cloudflare deployment.`,defaultValue:()=>!1}),tauriLocalPlatforms:F({long:`tauri-local-platform`,type:j(L(m)),description:`Build one Tauri release platform locally. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowName:R({long:`tauri-workflow-name`,type:z(H),description:`GitHub Actions workflow file or name for remote Tauri release builds.`}),tauriWorkflowPlatforms:F({long:`tauri-workflow-platform`,type:j(L(m)),description:`Build one Tauri release platform with GitHub Actions. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowRef:R({long:`tauri-workflow-ref`,type:z(H),description:`Git ref used when dispatching remote Tauri release builds.`}),yes:P({long:`yes`,short:`y`,description:`Approve the production deployment confirmation.`,defaultValue:()=>!1})},handler:({environment:e,runMigrations:t,skipMigrations:n,skipPostDeployChecks:r,tauriLocalPlatforms:i,tauriWorkflowName:a,tauriWorkflowPlatforms:o,tauriWorkflowRef:s,yes:c})=>b([e,...t?[`--run-migrations`]:[],...n?[`--skip-migrations`]:[],...r?[`--skip-post-deploy-checks`]:[],...i.flatMap(e=>[`--tauri-local-platform`,e]),...a?[`--tauri-workflow-name`,a]:[],...o.flatMap(e=>[`--tauri-workflow-platform`,e]),...s?[`--tauri-workflow-ref`,s]:[],...c?[`--yes`]:[]])}),staging:U({name:`staging`,cmds:{reassign:M({name:`reassign`,args:{json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await g();if(e){console.log(JSON.stringify({...t,notices:W}));return}console.log(t.url),console.error(`Staging hostname reassigned. ${W.join(` `)}`)}}),url:M({name:`url`,args:{json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({json:e})=>{let t=await h();console.log(e?JSON.stringify({url:t}):t)}})}}),secrets:U({name:`secrets`,cmds:{status:M({name:`status`,args:{environment:B({type:z(L(p)),displayName:`environment`,description:`Inspect staging, production, or both when omitted.`}),json:P({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({environment:e,json:t})=>{let n=await v({environment:e});console.log(t?JSON.stringify(n):q(n))}}),set:M({name:`set`,args:{environment:B({type:L(p),displayName:`environment`,description:`Worker environment to update on its next deploy.`}),name:B({type:H,displayName:`name`,description:`Declared Worker secret name.`})},handler:async({environment:e,name:t})=>{await y({environment:e,name:t,value:await J(t)}),console.log(`Queued ${t} for ${e}. Run coreframe deploy ${e} to apply.`)}}),discard:M({name:`discard`,args:{environment:B({type:L(p),displayName:`environment`,description:`Worker environment with a queued secret update.`}),name:B({type:H,displayName:`name`,description:`Declared Worker secret name.`})},handler:async({environment:e,name:t})=>{let n=await _({environment:e,name:t});console.log(n?`Discarded the queued ${t} update for ${e}.`:`No ${t} update is queued for ${e}.`)}})}}),typecheck:M({name:`typecheck`,args:{},handler:T}),dev:M({name:`dev`,args:{https:P({long:`https`,description:`Serve the web app over locally trusted HTTPS.`,defaultValue:()=>!1}),host:R({long:`host`,type:z(H),description:`Host address for the web development server.`}),managed:P({long:`managed`,description:`Run managed checkout synchronization even without an interactive terminal.`,defaultValue:()=>!1}),noManaged:P({long:`no-managed`,description:`Run without managed checkout synchronization for this invocation.`,defaultValue:()=>!1}),platform:B({type:z(L(S)),displayName:`platform`,description:`Development target platform. Defaults to web.`}),port:R({long:`port`,type:z(I),description:`Port for the web development server.`})},handler:({host:e,https:t,managed:n,noManaged:r,platform:i,port:a})=>C({host:e,https:t,managed:n,noManaged:r,platform:i??`web`,webPort:a})}),upgrade:U({name:`upgrade`,cmds:{"ensure-template-remote":M({name:`ensure-template-remote`,args:{remote:R({long:`remote`,type:H,defaultValue:()=>`template`,description:`Remote name to ensure.`}),noFetch:P({long:`no-fetch`,description:`Do not fetch the remote after ensuring it exists.`,defaultValue:()=>!1})},handler:({noFetch:e,remote:t})=>D({fetch:!e,remote:t})}),"check-skill-current":M({name:`check-skill-current`,args:{target:R({long:`target`,type:H,description:`Target Coreframe template git ref.`}),apply:P({long:`apply`,description:`Replace the local upgrade skill with the target version when it differs.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>{process.exitCode=E({apply:e,target:t})}}),"fast-forward-template-files":M({name:`fast-forward-template-files`,args:{target:R({long:`target`,type:H,description:`Target Coreframe template git ref.`}),base:R({long:`base`,type:z(H),description:`Previous Coreframe template git ref. Defaults to package.json engines.coreframe.`}),apply:P({long:`apply`,description:`Write clean fast-forwards to the worktree.`,defaultValue:()=>!1})},handler:({apply:e,base:t,target:n})=>O({apply:e,base:t,target:n})}),"sync-coreframe-packages":M({name:`sync-coreframe-packages`,args:{target:R({long:`target`,type:H,description:`Target Coreframe template git ref.`}),apply:P({long:`apply`,description:`Update existing published Coreframe dependency specifications.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>k({apply:e,target:t})})}}),db:U({name:`db`,cmds:{ensure:M({name:`ensure`,args:{},handler:u}),generate:M({name:`generate`,args:{args:V({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit generate.`})},handler:({args:e})=>a(`generate`,e)}),migrate:M({name:`migrate`,args:{args:V({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit migrate.`})},handler:({args:e})=>a(`migrate`,e)}),"migrate-held":M({name:`migrate-held`,args:{confirm:R({long:`confirm`,type:z(L([`run-held-migrations`])),description:`Required confirmation value for held migrations.`})},handler:({confirm:e})=>d({argv:e?[`--confirm=${e}`]:[]})}),"migrate-local":M({name:`migrate-local`,args:{},handler:s}),"migrations-check":M({name:`migrations-check`,args:{},handler:x}),reset:M({name:`reset`,args:{},handler:c}),seed:M({name:`seed`,args:{},handler:()=>o()}),"schema-check":M({name:`schema-check`,args:{seed:P({long:`seed`,description:`Run the configured project seed against the throwaway database.`,defaultValue:()=>!1})},handler:({seed:e})=>f({seed:e})}),setup:M({name:`setup`,args:{},handler:()=>l()}),studio:M({name:`studio`,args:{args:V({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit studio.`})},handler:({args:e})=>a(`studio`,e)})}})}});import.meta.main&&w(K);function q(e){if(e.entries.length===0)return`No Worker environment values are declared in coreframe.config.ts.`;let t=e.entries.map(e=>[e.name,e.kind,e.local===`override`?`override`:`built-in default`,e.deployed.staging.replaceAll(`_`,` `),e.deployed.production.replaceAll(`_`,` `)]),n=[`Name`,`Kind`,`Local`,`Staging`,`Production`],r=n.map((e,n)=>Math.max(e.length,...t.map(e=>e[n].length))),i=e=>e.map((e,t)=>e.padEnd(r[t])).join(` `).trimEnd();return[i(n),i(r.map(e=>`-`.repeat(e))),...t].join(`
3
+ `)}async function J(e){if(!process.stdin.isTTY){let e=``;for await(let t of process.stdin)e+=t.toString();return e.replace(/\r?\n$/,``)}let t=await A.password({message:`Enter the new value for ${e}`});if(A.isCancel(t))throw A.cancel(`Secret update cancelled.`),Error(`Secret update cancelled.`);return t}export{K as coreframeCli};
@@ -32,12 +32,21 @@ type StartProjectPostgresOptions = {
32
32
  postgresOutput?: PostgresOutputTarget;
33
33
  };
34
34
  type StartTemporaryProjectPostgresOptions = StartProjectPostgresOptions;
35
+ declare class ProjectPostgresAlreadyRunningError extends Error {
36
+ readonly dataDir: string;
37
+ readonly pid: number;
38
+ constructor(dataDir: string, pid: number, options?: ErrorOptions);
39
+ }
35
40
  declare function startProjectPostgres({
36
41
  config,
37
42
  cwd,
38
43
  env,
39
44
  postgresOutput
40
45
  }?: StartProjectPostgresOptions): Promise<ProjectPostgresSidecar>;
46
+ declare function stopProjectPostgres({
47
+ dataDir,
48
+ pid
49
+ }: ProjectPostgresAlreadyRunningError): Promise<void>;
41
50
  declare function startTemporaryProjectPostgres({
42
51
  config,
43
52
  cwd,
@@ -49,4 +58,4 @@ declare function createLocalPostgresDb({
49
58
  }?: LocalPostgresOptions): Promise<LocalPostgresDb>;
50
59
  declare function getLocalPostgresConnectionString(env?: NodeJS.ProcessEnv): string;
51
60
  //#endregion
52
- export { LOCAL_POSTGRES_ENV_FLAG, LocalPostgresDb, ProjectPostgresSidecar, StartProjectPostgresOptions, StartTemporaryProjectPostgresOptions, createLocalPostgresDb, createLocalPostgresEnv, getLocalPostgresConnectionString, startProjectPostgres, startTemporaryProjectPostgres };
61
+ export { LOCAL_POSTGRES_ENV_FLAG, LocalPostgresDb, ProjectPostgresAlreadyRunningError, ProjectPostgresSidecar, StartProjectPostgresOptions, StartTemporaryProjectPostgresOptions, createLocalPostgresDb, createLocalPostgresEnv, getLocalPostgresConnectionString, startProjectPostgres, startTemporaryProjectPostgres, stopProjectPostgres };
@@ -1,2 +1,2 @@
1
- import{readProjectConfig as e}from"../config.js";import{fs as t,os as n}from"../environment.js";import{createProjectPostgresDrizzleDatabase as r}from"./project.js";import i from"node:path";import{startPostgres as a}from"local-postgres";const o=`COREFRAME_LOCAL_POSTGRES`,s=`coreframe`,c={name:`coreframe`,password:`coreframe`};async function l({config:n,cwd:r=process.cwd(),env:o=process.env,postgresOutput:l}={}){if(o.COREFRAME_LOCAL_POSTGRES===`1`||((n??await e({cwd:r})).database?.dialect??`postgres`)!==`postgres`)return m(o);let u=i.resolve(r,`.coreframe/postgres`),d=await h(u);if(d!==void 0)throw Error(`PostgreSQL is already running for this project (PID ${d}). Stop the other top-level \`coreframe dev\` process before starting another.`);let f=i.join(u,`postgres.log`);await t.rm(f,{force:!0});let _;try{_=await a({dataDir:u,database:s,postgresOutput:l??{filePath:f},postgres:{strategy:`prefer-local`},superuser:c})}catch(e){throw await g(e,l?void 0:f)}return p(o,_)}async function u({config:r,cwd:o=process.cwd(),env:l=process.env}={}){let u=(r??await e({cwd:o})).database?.dialect??`postgres`;if(u!==`postgres`)throw Error(`Temporary schema push checks require PostgreSQL, but this project uses ${u}.`);let d=await t.mkdtemp(i.join(n.tmpdir(),`coreframe-schema-check-`));try{let e=p(l,await a({dataDir:d,database:s,postgresOutput:`ignore`,postgres:{strategy:`prefer-local`},superuser:c}));return{env:e.env,async[Symbol.asyncDispose](){try{await e[Symbol.asyncDispose]()}finally{await t.rm(d,{force:!0,recursive:!0})}}}}catch(e){throw await t.rm(d,{force:!0,recursive:!0}),e}}function d(e,t){return{...e,...t,[o]:`1`}}async function f({env:e=process.env}={}){let t=v(e);return r({env:{...e,DATABASE_URL:t}})}function p(e,t){return{env:d(e,t.env),async[Symbol.asyncDispose](){await t[Symbol.asyncDispose]()}}}function m(e){return{env:e,async[Symbol.asyncDispose](){}}}async function h(e){let r;try{r=await t.readFile(i.join(e,`postmaster.pid`),`utf8`)}catch{return}let a=Number(r.split(`
2
- `,1)[0]);if(!(!Number.isSafeInteger(a)||a<=0))try{return n.kill(a,0),a}catch(e){return _(e)&&e.code===`EPERM`?a:void 0}}async function g(e,n){let r=e instanceof Error?e.message:String(e),i;if(n)try{i=(await t.readFile(n,`utf8`)).trim()||void 0}catch{}let a=i?`\n\nPostgreSQL output:\n${i}`:``,o=n?`\n\nPostgreSQL log: ${n}`:``;return Error(`Local PostgreSQL failed to start: ${r}${a}${o}`,{cause:e})}function _(e){return e instanceof Error}function v(e=process.env){let t=e.DATABASE_URL||y(e);if(!t)throw Error(`DATABASE_URL or PGDATABASE, PGHOST, PGPORT, and PGUSER are required.`);return t}function y(e){let{PGDATABASE:t,PGHOST:n,PGPASSWORD:r,PGPORT:i,PGUSER:a}=e;if(!t||!n||!i||!a)return;let o=new URL(`postgresql://${n}:${i}/${t}`);return o.username=a,r&&(o.password=r),o.href}export{o as LOCAL_POSTGRES_ENV_FLAG,f as createLocalPostgresDb,d as createLocalPostgresEnv,v as getLocalPostgresConnectionString,l as startProjectPostgres,u as startTemporaryProjectPostgres};
1
+ import{readProjectConfig as e}from"../config.js";import{fs as t,os as n}from"../environment.js";import{createProjectPostgresDrizzleDatabase as r}from"./project.js";import i from"node:path";import{startPostgres as a}from"local-postgres";import{PostgresDataDirInUseError as o,stopPostgresDataDir as s}from"local-postgres/core";const c=`COREFRAME_LOCAL_POSTGRES`,l=`coreframe`,u={name:`coreframe`,password:`coreframe`};var d=class extends Error{dataDir;pid;constructor(e,t,n){super(`PostgreSQL is already running for this project (PID ${t}). Stop the other top-level \`coreframe dev\` process before starting another.`,n),this.name=`ProjectPostgresAlreadyRunningError`,this.dataDir=e,this.pid=t}};async function f({config:n,cwd:r=process.cwd(),env:o=process.env,postgresOutput:s}={}){if(o.COREFRAME_LOCAL_POSTGRES===`1`||((n??await e({cwd:r})).database?.dialect??`postgres`)!==`postgres`)return v(o);let c=i.resolve(r,`.coreframe/postgres`),f=await y(c);if(f!==void 0)throw new d(c,f);let p=i.join(c,`postgres.log`);await t.rm(p,{force:!0});let m;try{m=await a({dataDir:c,database:l,postgresOutput:s??{filePath:p},postgres:{strategy:`prefer-local`},superuser:u})}catch(e){throw await b(e,s?void 0:p)}return _(o,m)}async function p({dataDir:e,pid:t}){await s({dataDir:e,expectedPid:t})}async function m({config:r,cwd:o=process.cwd(),env:s=process.env}={}){let c=(r??await e({cwd:o})).database?.dialect??`postgres`;if(c!==`postgres`)throw Error(`Temporary schema push checks require PostgreSQL, but this project uses ${c}.`);let d=await t.mkdtemp(i.join(n.tmpdir(),`coreframe-schema-check-`));try{let e=_(s,await a({dataDir:d,database:l,postgresOutput:`ignore`,postgres:{strategy:`prefer-local`},superuser:u}));return{env:e.env,async[Symbol.asyncDispose](){try{await e[Symbol.asyncDispose]()}finally{await t.rm(d,{force:!0,recursive:!0})}}}}catch(e){throw await t.rm(d,{force:!0,recursive:!0}),e}}function h(e,t){return{...e,...t,[c]:`1`}}async function g({env:e=process.env}={}){let t=S(e);return r({env:{...e,DATABASE_URL:t}})}function _(e,t){return{env:h(e,t.env),async[Symbol.asyncDispose](){await t[Symbol.asyncDispose]()}}}function v(e){return{env:e,async[Symbol.asyncDispose](){}}}async function y(e){let r;try{r=await t.readFile(i.join(e,`postmaster.pid`),`utf8`)}catch{return}let a=Number(r.split(`
2
+ `,1)[0]);if(!(!Number.isSafeInteger(a)||a<=0))try{return n.kill(a,0),a}catch(e){return x(e)&&e.code===`EPERM`?a:void 0}}async function b(e,n){if(e instanceof o)return new d(e.dataDir,e.pid,{cause:e});let r=e instanceof Error?e.message:String(e),i;if(n)try{i=(await t.readFile(n,`utf8`)).trim()||void 0}catch{}let a=i?`\n\nPostgreSQL output:\n${i}`:``,s=n?`\n\nPostgreSQL log: ${n}`:``;return Error(`Local PostgreSQL failed to start: ${r}${a}${s}`,{cause:e})}function x(e){return e instanceof Error}function S(e=process.env){let t=e.DATABASE_URL||C(e);if(!t)throw Error(`DATABASE_URL or PGDATABASE, PGHOST, PGPORT, and PGUSER are required.`);return t}function C(e){let{PGDATABASE:t,PGHOST:n,PGPASSWORD:r,PGPORT:i,PGUSER:a}=e;if(!t||!n||!i||!a)return;let o=new URL(`postgresql://${n}:${i}/${t}`);return o.username=a,r&&(o.password=r),o.href}export{c as LOCAL_POSTGRES_ENV_FLAG,d as ProjectPostgresAlreadyRunningError,g as createLocalPostgresDb,h as createLocalPostgresEnv,S as getLocalPostgresConnectionString,f as startProjectPostgres,m as startTemporaryProjectPostgres,p as stopProjectPostgres};
@@ -13,6 +13,7 @@ type AcquireDevLockOptions = {
13
13
  };
14
14
  type DevLock = {
15
15
  release(): Promise<void>;
16
+ takeoverApproved: boolean;
16
17
  };
17
18
  declare function acquireDevLock({
18
19
  confirmStop,
package/dist/dev-lock.js CHANGED
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";import{link as t,mkdir as n,readFile as r,unlink as i,writeFile as a}from"node:fs/promises";import o from"node:path";import*as s from"@clack/prompts";import c from"node:process";const l={isRunning:m,stop(e){try{c.kill(e,`SIGTERM`)}catch(e){if(!_(e))throw e}},waitForExit:h};async function u({confirmStop:r=d,cwd:s=c.cwd(),interactive:u=c.stdin.isTTY===!0,pid:m=c.pid,processes:h=l}={}){let _=o.resolve(s,`.coreframe/dev.lock`),v={pid:m,token:e()},y=`${JSON.stringify(v)}\n`,b=`${_}.${v.token}.tmp`;await n(o.dirname(_),{recursive:!0}),await a(b,y,{flag:`wx`,mode:384});try{for(;;){try{return await t(b,_),{async release(){await p(_,y)}}}catch(e){if(!g(e))throw e}let e=await f(_);if(!e||!h.isRunning(e.owner.pid)){await p(_,e?.source);continue}if(!u)throw Error(`Coreframe dev is already running for this project (PID ${e.owner.pid}). Stop it before starting another.`);if(!await r(e.owner.pid))return;h.stop(e.owner.pid),await h.waitForExit(e.owner.pid),await p(_,e.source)}}finally{await i(b).catch(()=>void 0)}}async function d(e){let t=await s.confirm({initialValue:!1,message:`Coreframe dev is already running for this project (PID ${e}). Stop it and start here?`});return s.isCancel(t)||!t?(s.cancel(`Keeping the existing Coreframe dev process.`),!1):!0}async function f(e){try{let t=await r(e,`utf8`),n=JSON.parse(t);return!Number.isSafeInteger(n.pid)||Number(n.pid)<=0||!n.token?void 0:{owner:n,source:t}}catch{return}}async function p(e,t){let n=await r(e,`utf8`).catch(()=>void 0);(t===void 0||n===t)&&await i(e).catch(()=>void 0)}function m(e){try{return c.kill(e,0),!0}catch(e){return!_(e)}}async function h(e){let t=Date.now()+1e4;for(;m(e);){if(Date.now()>=t)throw Error(`Coreframe dev process ${e} did not stop within 10 seconds.`);await new Promise(e=>setTimeout(e,50))}}function g(e){return v(e)&&e.code===`EEXIST`}function _(e){return v(e)&&e.code===`ESRCH`}function v(e){return e instanceof Error}export{u as acquireDevLock};
1
+ import{randomUUID as e}from"node:crypto";import{link as t,mkdir as n,readFile as r,unlink as i,writeFile as a}from"node:fs/promises";import o from"node:path";import*as s from"@clack/prompts";import c from"node:process";const l={isRunning:m,stop(e){try{c.kill(e,`SIGTERM`)}catch(e){if(!_(e))throw e}},waitForExit:h};async function u({confirmStop:r=d,cwd:s=c.cwd(),interactive:u=c.stdin.isTTY===!0,pid:m=c.pid,processes:h=l}={}){let _=o.resolve(s,`.coreframe/dev.lock`),v={pid:m,token:e()},y=`${JSON.stringify(v)}\n`,b=`${_}.${v.token}.tmp`,x=!1;await n(o.dirname(_),{recursive:!0}),await a(b,y,{flag:`wx`,mode:384});try{for(;;){try{return await t(b,_),{async release(){await p(_,y)},takeoverApproved:x}}catch(e){if(!g(e))throw e}let e=await f(_);if(!e||!h.isRunning(e.owner.pid)){await p(_,e?.source);continue}if(!u)throw Error(`Coreframe dev is already running for this project (PID ${e.owner.pid}). Stop it before starting another.`);if(!await r(e.owner.pid))return;x=!0,h.stop(e.owner.pid),await h.waitForExit(e.owner.pid),await p(_,e.source)}}finally{await i(b).catch(()=>void 0)}}async function d(e){let t=await s.confirm({initialValue:!1,message:`Coreframe dev is already running for this project (PID ${e}). Stop it and start here?`});return s.isCancel(t)||!t?(s.cancel(`Keeping the existing Coreframe dev process.`),!1):!0}async function f(e){try{let t=await r(e,`utf8`),n=JSON.parse(t);return!Number.isSafeInteger(n.pid)||Number(n.pid)<=0||!n.token?void 0:{owner:n,source:t}}catch{return}}async function p(e,t){let n=await r(e,`utf8`).catch(()=>void 0);(t===void 0||n===t)&&await i(e).catch(()=>void 0)}function m(e){try{return c.kill(e,0),!0}catch(e){return!_(e)}}async function h(e){let t=Date.now()+1e4;for(;m(e);){if(Date.now()>=t)throw Error(`Coreframe dev process ${e} did not stop within 10 seconds.`);await new Promise(e=>setTimeout(e,50))}}function g(e){return v(e)&&e.code===`EEXIST`}function _(e){return v(e)&&e.code===`ESRCH`}function v(e){return e instanceof Error}export{u as acquireDevLock};
package/dist/dev.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{readProjectConfig as e}from"./config.js";import{fs as t,net as n}from"./environment.js";import{startProjectPostgres as r}from"./db/local-postgres.js";import i from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{devHttpsCertEnv as a,devHttpsKeyEnv as o,prepareDevHttps as s}from"./dev-https.js";import{acquireDevLock as c}from"./dev-lock.js";import{isPrimaryGitCheckout as l,startManagedDevSession as u}from"./managed-dev.js";import d from"node:path";import f from"node:process";import{createPrefixStream as p,supervise as m}from"procband";const h=[`web`,`desktop`,`ios`,`android`];function g(e){let t=e.dev?.platforms??[`web`];for(let e of t)if(!h.includes(e))throw Error(`Invalid development platform "${String(e)}". Expected one of: ${h.join(`, `)}.`);return[...new Set(t)]}const _=d.resolve(`node_modules`,`.bin`),v=f.platform===`win32`?`pnpm.cmd`:`pnpm`,y=f.platform===`win32`?`react-router.cmd`:`react-router`,b=f.platform===`win32`?`turso.cmd`:`turso`;async function x({cwd:h=f.cwd(),env:g=f.env,host:x,https:E=!1,interactive:D=f.stdin.isTTY===!0,managed:O=!1,noManaged:k=!1,platform:A=`web`,webPort:j}={}){let M=g.PATH??g.Path??``,N=A===`web`?T(j??g.COREFRAME_WEB_PORT):void 0,P,F,I,L=!1,R=g;if(O&&k)throw Error(`Cannot use --managed and --no-managed together.`);if(E&&A!==`web`)throw Error(`Local HTTPS is only supported for the web development platform.`);let z=await c({cwd:h,interactive:D});if(!z)return;try{if(A===`web`){let c=await e({cwd:h}),_=E?await s({cwd:h}):void 0;if(R=_?{...g,[a]:_.cert,[o]:_.key}:g,(O||D&&!k)&&await l(h)&&(F=await u({config:c,cwd:h,env:R,onRestart(){I&&(L=!0,I.kill(`SIGTERM`))}}),R=F.env),c.database?.dialect===`sqlite`){let e=await n.getAvailablePort(),r=d.resolve(h,`.coreframe`),i=d.join(r,`turso.db`);await t.mkdir(r,{recursive:!0}),R={...R,TURSO_DATABASE_URL:`http://127.0.0.1:${e}`},F?.setRuntimeEnv(R),P=m({name:`turso`,command:b,args:[`dev`,`--port`,String(e),`--db-file`,i],cwd:h,env:g}),await P.waitFor(`listening`),await m({name:`db`,command:v,args:[`db`,`ensure`],cwd:h,env:R,prefix:!1}).expectSuccess()}if(S(c)){let e=p({label:`postgres`});e.pipe(f.stdout,{end:!1});try{try{var B=i();let t=B.a(await r({config:c,cwd:h,env:R,postgresOutput:e})).env;F?.setRuntimeEnv(t),R=t,await m({name:`db`,command:v,args:[`db`,`ensure`],cwd:h,env:t,prefix:!1}).expectSuccess(),await V()}catch(e){B.e=e}finally{await B.d()}}finally{e.end()}return}F?.setRuntimeEnv(R),await V();return}let c=C(A);await m({name:A,command:v,args:c,cwd:h,env:g}).expectSuccess()}finally{I?.kill(`SIGTERM`),await F?.close(),P&&P.kill(`SIGTERM`),await z.release()}async function V(){let e=async()=>{do L=!1,I=m({name:`web`,command:y,args:w({host:x,port:N}),cwd:h,env:{...R,CLOUDFLARE_ENV:`development`,PATH:_+d.delimiter+M}}),await I.wait(),L||await I.expectSuccess(),I=void 0;while(L)};if(!F){await e();return}await Promise.race([e(),F.failure.catch(e=>{throw L=!1,I?.kill(`SIGTERM`),e})])}}function S(e){return(e.database?.dialect??`postgres`)===`postgres`}function C(e){return[`--dir=tauri`,`tauri`,...e===`desktop`?[]:[e],`dev`]}function w({host:e,port:t}){return[`dev`,...e===void 0?[]:[`--host`,e],...t===void 0?[]:[`--port`,String(t)]]}function T(e){if(e===void 0)return;let t=Number(e);if(!Number.isInteger(t)||t<=0||t>65535)throw Error(`COREFRAME_WEB_PORT must be a valid TCP port.`);return t}export{h as devPlatforms,g as resolveDevPlatforms,x as runDevServer};
2
+ import{readProjectConfig as e}from"./config.js";import{fs as t,net as n}from"./environment.js";import{ProjectPostgresAlreadyRunningError as r,startProjectPostgres as i,stopProjectPostgres as a}from"./db/local-postgres.js";import o from"./_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import{devHttpsCertEnv as s,devHttpsKeyEnv as c,prepareDevHttps as l}from"./dev-https.js";import{acquireDevLock as u}from"./dev-lock.js";import{managedDevEnv as d}from"./managed-dev-protocol.js";import{isManagedDevCheckout as f}from"./managed-dev.js";import p from"node:path";import*as m from"@clack/prompts";import h from"node:process";import{createPrefixStream as g,supervise as _}from"procband";const v=[`web`,`desktop`,`ios`,`android`];function y(e){let t=e.dev?.platforms??[`web`];for(let e of t)if(!v.includes(e))throw Error(`Invalid development platform "${String(e)}". Expected one of: ${v.join(`, `)}.`);return[...new Set(t)]}const b=p.resolve(`node_modules`,`.bin`),x=h.platform===`win32`?`pnpm.cmd`:`pnpm`,S=h.platform===`win32`?`react-router.cmd`:`react-router`,C=h.platform===`win32`?`turso.cmd`:`turso`;async function w({cwd:r=h.cwd(),env:i=h.env,host:a,https:m=!1,interactive:v=h.stdin.isTTY===!0,managed:y=!1,noManaged:w=!1,platform:A=`web`,webPort:j}={}){let M=i.PATH??i.Path??``,N=A===`web`?k(j??i.COREFRAME_WEB_PORT):void 0,P,F,I=i;if(y&&w)throw Error(`Cannot use --managed and --no-managed together.`);if(m&&A!==`web`)throw Error(`Local HTTPS is only supported for the web development platform.`);let L=await u({cwd:r,interactive:v});if(!L)return;try{if(A===`web`){let a=await e({cwd:r}),u=m?await l({cwd:r}):void 0;if(I=u?{...i,[s]:u.cert,[c]:u.key}:i,(y||v&&!w)&&await f(r)&&(I={...I,[d]:`1`}),a.database?.dialect===`sqlite`){let e=await n.getAvailablePort(),a=p.resolve(r,`.coreframe`),o=p.join(a,`turso.db`);await t.mkdir(a,{recursive:!0}),I={...I,TURSO_DATABASE_URL:`http://127.0.0.1:${e}`,TURSO_AUTH_TOKEN:`dev`},P=_({name:`turso`,command:C,args:[`dev`,`--port`,String(e),`--db-file`,o],cwd:r,env:i}),await P.waitFor(`listening`),await _({name:`db`,command:x,args:[`db`,`ensure`],cwd:r,env:I,prefix:!1}).expectSuccess()}if(E(a)){let e=g({label:`postgres`});e.pipe(h.stdout,{end:!1});try{try{var R=o();let t=await T({config:a,cwd:r,env:I,interactive:v,postgresOutput:e,takeoverApproved:L.takeoverApproved});if(!t)return;R.a(t);let n=t.env;I=n,await _({name:`db`,command:x,args:[`db`,`ensure`],cwd:r,env:n,prefix:!1}).expectSuccess(),await z()}catch(e){R.e=e}finally{await R.d()}}finally{e.end()}return}await z();return}let a=D(A);await _({name:A,command:x,args:a,cwd:r,env:i}).expectSuccess()}finally{F?.kill(`SIGTERM`),P&&P.kill(`SIGTERM`),await L.release()}async function z(){F=_({name:`web`,command:S,args:O({host:a,port:N}),cwd:r,env:{...I,CLOUDFLARE_ENV:`development`,PATH:b+p.delimiter+M}}),await F.wait(),await F.expectSuccess(),F=void 0}}async function T({interactive:e,takeoverApproved:t,...n}){try{return await i(n)}catch(o){if(!(o instanceof r)||!e)throw o;if(!t){let e=await m.confirm({initialValue:!1,message:`PostgreSQL is already running for this project (PID ${o.pid}). Stop it and start here?`});if(m.isCancel(e)||!e){m.cancel(`Keeping the existing PostgreSQL process.`);return}}return await a(o),i(n)}}function E(e){return(e.database?.dialect??`postgres`)===`postgres`}function D(e){return[`--dir=tauri`,`tauri`,...e===`desktop`?[]:[e],`dev`]}function O({host:e,port:t}){return[`dev`,...e===void 0?[]:[`--host`,e],...t===void 0?[]:[`--port`,String(t)]]}function k(e){if(e===void 0)return;let t=Number(e);if(!Number.isInteger(t)||t<=0||t>65535)throw Error(`COREFRAME_WEB_PORT must be a valid TCP port.`);return t}export{v as devPlatforms,y as resolveDevPlatforms,w as runDevServer};
@@ -1,10 +1,9 @@
1
1
  //#region managed-dev-protocol.d.ts
2
- declare const managedDevUrlEnv = "COREFRAME_MANAGED_DEV_URL";
3
- declare const managedDevTokenEnv = "COREFRAME_MANAGED_DEV_TOKEN";
2
+ declare const managedDevEnv = "COREFRAME_MANAGED_DEV";
4
3
  type ManagedDevTarget = {
5
4
  commit: string;
6
5
  shortCommit: string;
7
- source: "local" | "upstream";
6
+ source: "dev" | "upstream";
8
7
  subject: string;
9
8
  };
10
9
  type ManagedDevDraft = {
@@ -42,4 +41,4 @@ type ManagedDevActionResult = {
42
41
  status: ManagedDevStatus;
43
42
  };
44
43
  //#endregion
45
- export { ManagedDevAction, ManagedDevActionResult, ManagedDevDraft, ManagedDevStatus, ManagedDevTarget, managedDevTokenEnv, managedDevUrlEnv };
44
+ export { ManagedDevAction, ManagedDevActionResult, ManagedDevDraft, ManagedDevStatus, ManagedDevTarget, managedDevEnv };
@@ -1 +1 @@
1
- const e=`COREFRAME_MANAGED_DEV_URL`,t=`COREFRAME_MANAGED_DEV_TOKEN`;export{t as managedDevTokenEnv,e as managedDevUrlEnv};
1
+ const e=`COREFRAME_MANAGED_DEV`;export{e as managedDevEnv};
@@ -1,4 +1,5 @@
1
1
  import { CoreframeConfig } from "./config.js";
2
+ import { ManagedDevAction, ManagedDevActionResult, ManagedDevStatus } from "./managed-dev-protocol.js";
2
3
 
3
4
  //#region managed-dev.d.ts
4
5
  type ManagedDevSessionOptions = {
@@ -9,12 +10,12 @@ type ManagedDevSessionOptions = {
9
10
  remoteCheckInterval?: number;
10
11
  };
11
12
  type ManagedDevSession = {
12
- env: NodeJS.ProcessEnv;
13
- failure: Promise<never>;
14
- setRuntimeEnv(env: NodeJS.ProcessEnv): void;
13
+ action(action: ManagedDevAction): Promise<ManagedDevActionResult>;
14
+ activate(): Promise<void>;
15
+ getStatus(): ManagedDevStatus;
15
16
  close(): Promise<void>;
16
17
  };
17
- declare function isPrimaryGitCheckout(cwd?: string): Promise<boolean>;
18
+ declare function isManagedDevCheckout(cwd?: string): Promise<boolean>;
18
19
  declare function startManagedDevSession({
19
20
  config,
20
21
  cwd,
@@ -23,4 +24,4 @@ declare function startManagedDevSession({
23
24
  remoteCheckInterval
24
25
  }: ManagedDevSessionOptions): Promise<ManagedDevSession>;
25
26
  //#endregion
26
- export { ManagedDevSession, isPrimaryGitCheckout, startManagedDevSession };
27
+ export { ManagedDevSession, isManagedDevCheckout, startManagedDevSession };
@@ -1,2 +1,2 @@
1
- import{managedDevTokenEnv as e,managedDevUrlEnv as t}from"./managed-dev-protocol.js";import{createRequire as n}from"node:module";import{createHash as r,randomBytes as i}from"node:crypto";import{copyFile as a,mkdir as o,mkdtemp as s,open as c,readFile as l,realpath as u,rm as d,unlink as f}from"node:fs/promises";import p from"node:path";import m,{SubprocessError as h}from"nano-spawn";import{pathToFileURL as g}from"node:url";import _ from"node:process";import{watch as v}from"node:fs";import{createServer as ee}from"node:http";const y=`refs/heads/main`,te=/^[a-z][a-z0-9-]*(?:\([^)]+\))?!?:\s+\S/i;async function b(e=_.cwd()){return(await x(e)).primary}async function x(e){let t=await u(await H(e,[`rev-parse`,`--show-toplevel`])),n=await u(e),r=p.resolve(t,await H(e,[`rev-parse`,`--git-dir`])),i=p.resolve(t,await H(e,[`rev-parse`,`--git-common-dir`]));return{commonDir:i,gitDir:r,primary:t===n&&r===i}}async function S({config:n,cwd:r=_.cwd(),env:a=_.env,onRestart:o=()=>void 0,remoteCheckInterval:s=6e4}){let c=i(32).toString(`base64url`),l=a,u={mode:`waiting`,warnings:[]},d,f=!1,h=!1,g=!1,v=!1,b=!1,x,S,C,T,E,D=[],O,k,A=new Promise((e,t)=>{k=t}),j=e=>{let t=e instanceof Error?e:Error(String(e));u={...u,busy:void 0,message:t.message,mode:`error`},k(t)},M=async({fetch:e=!1}={})=>{if(!(!h||f||!S)){if(v){b=!0;return}try{if(await H(r,[`rev-parse`,`HEAD`])!==x){await P(`HEAD changed outside Coreframe; managed synchronization is disabled until restart.`);return}if(e){let e=await U(r,[`for-each-ref`,`--format=%(upstream:short)`,y]);if(e){let t=e.indexOf(`/`);if(t>0){let n=e.slice(0,t),i=e.slice(t+1);await V(r,[`fetch`,n,`+refs/heads/${i}:refs/remotes/${n}/${i}`])}}}let t=await H(r,[`rev-parse`,y]),n=await U(r,[`for-each-ref`,`--format=%(upstream:short)`,y]),i=n?await U(r,[`rev-parse`,`refs/remotes/${n}`]):void 0,a=i&&!await W(r,i,t)?i:t;u={...u,currentCommit:x,draft:u.target?.commit===a?u.draft:void 0,message:void 0,mode:`managed`,proposal:u.target?.commit===a?u.proposal:void 0,target:a===x?void 0:await ue(r,a,a===i?`upstream`:`local`)}}catch(e){u={...u,message:J(e),warnings:[J(e)]}}}},N=()=>{clearTimeout(E),E=setTimeout(()=>void M(),50),E.unref()},P=async e=>{h=!1,g=!0,clearInterval(T),clearTimeout(E);for(let e of D)e.close();D=[],await B(C),C=void 0,u={message:e,mode:`unmanaged`,warnings:[]}},F=async()=>{if(h||f||g)return;let e=await re(r);if(!e.primary){u={message:`Managed development only runs from the primary checkout.`,mode:`unmanaged`,warnings:[]};return}if(e.branch&&(e.branch!==`main`||e.status.length>0)){let t=e.branch===`main`?`Managed development requires a clean primary checkout on main. Dirty paths:\n${e.status}`:`Managed development requires the primary checkout on main; current branch is ${e.branch}.`;console.warn(`Coreframe managed development disabled: ${t}`),u={message:t,mode:`unmanaged`,warnings:[]};return}if(!e.branch&&!await W(r,e.head,e.main))throw Error(`Detached HEAD ${e.head.slice(0,12)} is not part of local main's history.`);C=p.join(e.commonDir,`coreframe-managed-dev.lock`),await R(C),e.branch===`main`&&await V(r,[`switch`,`--detach`,e.head]),S={...e,branch:void 0},x=e.head,h=!0,u={currentCommit:e.head,mode:`managed`,warnings:[]},D=await ie(e,N),T=setInterval(()=>void M({fetch:!0}),s),T.unref(),await M(),M({fetch:!0})},I=async e=>{if(!h||u.mode!==`managed`)throw Error(`Managed development is not active.`);if(v)throw Error(`Another managed development action is already running.`);v=!0,u={...u,busy:fe(e),message:void 0};try{if(e.type===`reject`)u={...u,draft:void 0,proposal:void 0};else if(e.type===`prepare`){z(e.target);let t=await w(r);t.tracked||t.untracked.length>0?u={...u,draft:t,proposal:Y(t.fingerprint)}:await Q({target:e.target})}else if(e.type===`message`){let t=await Z(e.fingerprint,e.untracked),n=Y(t.fingerprint);if(n===void 0){try{n=await ae(r,l,t.context)}catch(e){n=``,u={...u,warnings:[...u.warnings,`Codex could not generate a commit message: ${J(e)}`]}}O={fingerprint:t.fingerprint,message:n}}u={...u,draft:t,proposal:n}}else{z(e.target);let t=await w(r);if(t.tracked||t.untracked.length>0){if(!e.fingerprint||!e.untracked)throw Error(`Refresh requires the current working-tree confirmation.`);if(await Z(e.fingerprint,e.untracked),!e.message||!te.test(de(e.message)))throw Error(`Enter a commit message with a valid Conventional Commits header.`)}await Q({fingerprint:e.fingerprint,message:e.message,target:e.target,untracked:e.untracked})}}finally{v=!1,u={...u,busy:void 0},b&&(b=!1,N())}return{status:u}},z=e=>{if(!u.target||u.target.commit!==e)throw Error(`The offered update changed. Review the latest target before refreshing.`)},Y=e=>O?.fingerprint===e?O.message:void 0,Z=async(e,t)=>{let n=await w(r);if(n.fingerprint!==e)throw O=void 0,Error(`Working-tree changes changed; generate a new commit message.`);if(!G(n.untracked,t))throw Error(`Include every untracked file or remove it before refreshing.`);return n},Q=async({fingerprint:e,message:t,target:i,untracked:a=[]})=>{z(i);let s=await H(r,[`rev-parse`,`HEAD`]),c=await H(r,[`rev-parse`,y]),d,f,p=await w(r);if(p.tracked||p.untracked.length>0){if(!e||p.fingerprint!==e||!G(p.untracked,a))throw Error(`Working-tree changes changed; review them before refreshing.`);await V(r,[`add`,`--update`]),a.length>0&&await V(r,[`add`,`--`,...a]),await V(r,[`commit`,`--message`,t],{env:{GIT_EDITOR:`true`}}),d=await H(r,[`rev-parse`,`HEAD`]),x=d,f=`refs/coreframe/recovery/${Date.now()}-${d.slice(0,12)}`,await V(r,[`update-ref`,f,d])}let h=d??s,g;try{if(g=await oe({cwd:r,developerCommit:d,env:l,localMain:c,target:i}),await H(r,[`rev-parse`,`HEAD`])!==h)throw Error(`HEAD changed while the accepted update was being prepared.`);if(await H(r,[`rev-parse`,y])!==c)throw Error(`Local main changed while the accepted update was being prepared.`);await V(r,[`switch`,`--detach`,g.commit]);try{await V(r,[`update-ref`,y,g.commit,c])}catch(e){throw await V(r,[`switch`,`--detach`,h]),e}x=g.commit;let e=K(await H(r,[`diff`,`--name-only`,`-z`,s,g.commit]));L(e)&&await m(q(),[`install`,`--frozen-lockfile`],{cwd:r,env:l,stdio:`inherit`}),g.hadConflicts&&(u={...u,warnings:[...u.warnings,...await se(r,l)]});try{await ce({config:n,cwd:r,env:l})}catch(e){throw await V(r,[`switch`,`--detach`,h]),x=h,u={...u,currentCommit:h},Error(`Database migration failed; the database and preview were restored. ${J(e)}`)}le(e)&&o(),O=void 0,f&&await V(r,[`update-ref`,`-d`,f]),u={...u,currentCommit:g.commit,draft:void 0,proposal:void 0,target:void 0}}catch(e){g?.commit&&x===g.commit&&(await V(r,[`switch`,`--detach`,h]).catch(()=>void 0),x=h);let t=f?` Recovery commit: ${f}.`:``;throw u={...u,currentCommit:x,message:`${J(e)}${t}`},e}};d=ee((e,t)=>{ne(e,t,{action:I,activate:F,getStatus:()=>u,token:c}).catch(n=>{t.headersSent||X(t,400,{error:J(n),status:u}),e.url===`/handshake`&&j(n)})}),await pe(d);let $=d.address();if(!$||typeof $==`string`)throw Error(`Managed dev server failed to listen.`);return{env:{...a,[t]:`http://127.0.0.1:${$.port}`,[e]:c},failure:A,setRuntimeEnv(e){l=e},async close(){f=!0,clearInterval(T),clearTimeout(E);for(let e of D)e.close();try{h&&await H(r,[`rev-parse`,`HEAD`])===await H(r,[`rev-parse`,y])&&await V(r,[`switch`,`main`])}finally{await B(C),await me(d)}}}}async function ne(e,t,n){if(e.headers.authorization!==`Bearer ${n.token}`){X(t,401,{error:`Invalid managed development capability.`});return}if(e.method===`POST`&&e.url===`/handshake`){await n.activate(),X(t,200,{status:n.getStatus()});return}if(e.method===`GET`&&e.url===`/status`){X(t,200,{status:n.getStatus()});return}if(e.method===`POST`&&e.url===`/action`){let r=await Y(e);X(t,200,await n.action(r));return}X(t,404,{error:`Unknown managed development endpoint.`})}async function re(e){let t=await x(e);return{branch:C(await H(e,[`rev-parse`,`--abbrev-ref`,`HEAD`])),commonDir:t.commonDir,gitDir:t.gitDir,head:await H(e,[`rev-parse`,`HEAD`]),main:await H(e,[`rev-parse`,y]),primary:t.primary,status:await H(e,[`status`,`--porcelain`])}}function C(e){return e===`HEAD`?void 0:e}async function ie(e,t){let n=[e.gitDir,p.join(e.commonDir,`refs`,`heads`)],r=[];for(let e of n)try{r.push(v(e,{persistent:!1},t))}catch{}return r}async function w(e){let[t,n,i]=await Promise.all([H(e,[`status`,`--porcelain`,`--untracked-files=no`]),H(e,[`diff`,`HEAD`,`--binary`]),H(e,[`ls-files`,`--others`,`--exclude-standard`,`-z`])]),a=K(i).sort(),o=r(`sha256`).update(n),s=[`Tracked changes:`,n];for(let t of a){let n=await l(p.join(e,t));o.update(t).update(n),s.push(`\nUntracked file: ${t}\n`,n.toString(`utf8`))}return{context:s.join(`
2
- `),fingerprint:o.digest(`hex`),tracked:t.length>0,untracked:a}}async function ae(e,t,n){let{stdout:r}=await m(`codex`,[`exec`,`--ephemeral`,`--ignore-user-config`,`--sandbox`,`read-only`,`--cd`,e,`Return only a concise Conventional Commits message for the supplied working-tree changes. Use a body only when it adds material context.`],{cwd:e,env:t,stdin:{string:n}});return r.trim().replace(/^```(?:text)?\s*|\s*```$/g,``)}async function oe({cwd:e,developerCommit:t,env:n,localMain:r,target:a}){let s=p.resolve(e,await H(e,[`rev-parse`,`--git-common-dir`])),c=p.join(s,`coreframe-managed-dev`);await o(c,{recursive:!0});let l=p.join(c,`integration-${i(8).toString(`hex`)}`),u=!1;try{if(await V(e,[`worktree`,`add`,`--detach`,l,r]),r!==a){let e=await U(l,[`merge-base`,r,a]);u=await T(l,n,e?[`rebase`,`--onto`,a,e]:[`rebase`,`--root`,`--onto`,a],`rebase`)||u}return t&&(u=await T(l,n,[`cherry-pick`,t],`cherry-pick`)||u),{commit:await H(l,[`rev-parse`,`HEAD`]),hadConflicts:u}}finally{await V(e,[`worktree`,`remove`,`--force`,l]).catch(()=>void 0),await d(l,{force:!0,recursive:!0})}}async function T(e,t,n,r){try{return await V(e,n,{env:{GIT_EDITOR:`true`}}),!1}catch(n){let i=await D(e);if(i.length===0)throw n;console.warn(`Git ${r} conflicts occurred; Codex is resolving them.`);try{for(;i.length>0;){await E(e,t,r,i),await V(e,[`diff`,`--check`]),await V(e,[`add`,`--all`]);let n=await D(e);if(n.length>0)throw Error(`Codex left unresolved paths: ${n.join(`, `)}`);try{await V(e,[r,`--continue`],{env:{GIT_EDITOR:`true`}})}catch(t){if(i=await D(e),i.length===0)throw t;continue}i=await D(e)}return!0}catch(t){throw await V(e,[r,`--abort`]).catch(()=>void 0),Error(`Codex could not resolve ${r} conflicts: ${J(t)}`)}}}async function E(e,t,n,r){await m(`codex`,[`exec`,`--ephemeral`,`--ignore-user-config`,`--sandbox`,`workspace-write`,`--cd`,e,`Resolve the current Git ${n} conflicts cleanly. Edit only files needed for the resolution, preserve intended behavior from both sides, remove all conflict markers, and do not stage files or run Git continuation commands. Conflicted paths: ${r.join(`, `)}`],{cwd:e,env:t,stdio:`inherit`})}async function D(e){return K(await H(e,[`diff`,`--name-only`,`--diff-filter=U`,`-z`]))}async function se(e,t){let n=[];for(let r of[`test`,`typecheck`,`lint`])try{await m(q(),[r],{cwd:e,env:t,stdio:`inherit`})}catch(e){n.push(`${r} failed after Codex conflict resolution: ${J(e)}`)}return n}async function ce({config:e,cwd:t,env:n}){if(!e.database)return;let r=await O({config:e,cwd:t,env:n});try{await m(q(),[`db`,`migrate`],{cwd:t,env:n,stdio:`inherit`})}catch(e){throw await r.restore(),e}await r.discard().catch(e=>{console.warn(`Could not remove the managed-development database snapshot: ${J(e)}`)}),await d(r.directory,{force:!0,recursive:!0})}async function O({config:e,cwd:t,env:n}){let r=p.join(t,`.coreframe`,`managed-dev-backups`);await o(r,{recursive:!0});let i=await s(p.join(r,`refresh-`));if(e.database?.dialect===`sqlite`){let e=[`turso.db`,`turso.db-wal`,`turso.db-shm`],n=new Set;for(let r of e)await k(p.join(t,`.coreframe`,r),p.join(i,r))&&n.add(r);return{directory:i,async discard(){},async restore(){for(let r of e){let e=p.join(t,`.coreframe`,r);n.has(r)?await a(p.join(i,r),e):await d(e,{force:!0})}}}}if(!n.DATABASE_URL)throw Error(`DATABASE_URL is required to snapshot local PostgreSQL.`);let c=await A(t);if(c)return j({directory:i,connectionString:n.DATABASE_URL,postgres:c});let l=p.join(i,`database.dump`),u=I(n,n.DATABASE_URL);return await m(`pg_dump`,[`--format=custom`,`--file`,l],{cwd:t,env:u,stdin:`ignore`}),{directory:i,async discard(){},async restore(){await m(`pg_restore`,[`--clean`,`--if-exists`,`--no-owner`,`--dbname`,u.PGDATABASE,l],{cwd:t,env:u,stdin:`ignore`})}}}async function k(e,t){try{return await a(e,t),!0}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e;return!1}}async function A(e){let t=JSON.parse(await l(p.join(e,`package.json`),`utf8`));if(!(!t.dependencies?.pg&&!t.devDependencies?.pg&&!t.optionalDependencies?.pg))try{return await import(g(n(p.join(e,`package.json`)).resolve(`pg`)).href)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`MODULE_NOT_FOUND`)return;throw e}}async function j({directory:e,connectionString:t,postgres:n}){let r=new URL(t),a=decodeURIComponent(r.pathname.slice(1));if(!a)throw Error(`DATABASE_URL must name a PostgreSQL database to snapshot.`);let o=`coreframe_backup_${i(6).toString(`hex`)}`,s=`${o}_failed`,c=new URL(r);c.pathname=a===`postgres`?`/template1`:`/postgres`;let l=new n.Client({connectionString:c.href});await l.connect();try{await N(l,a,!1),await P(l,a),await l.query(`CREATE DATABASE ${F(o)} WITH TEMPLATE ${F(a)}`),await N(l,o,!0)}finally{await N(l,a,!0).catch(()=>void 0),await l.end()}return{directory:e,async discard(){await M(n,c.href,async e=>{await P(e,o),await e.query(`DROP DATABASE ${F(o)}`)})},async restore(){await M(n,c.href,async e=>{await N(e,a,!1),await P(e,a),await e.query(`ALTER DATABASE ${F(a)} RENAME TO ${F(s)}`);try{await e.query(`ALTER DATABASE ${F(o)} RENAME TO ${F(a)}`)}catch(t){throw await e.query(`ALTER DATABASE ${F(s)} RENAME TO ${F(a)}`).catch(()=>void 0),await N(e,a,!0).catch(()=>void 0),t}await P(e,s),await e.query(`DROP DATABASE ${F(s)}`)})}}}async function M(e,t,n){let r=new e.Client({connectionString:t});await r.connect();try{return await n(r)}finally{await r.end()}}async function N(e,t,n){await e.query(`ALTER DATABASE ${F(t)} ALLOW_CONNECTIONS ${n?`true`:`false`}`)}async function P(e,t){await e.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`,[t])}function F(e){return`"${e.replaceAll(`"`,`""`)}"`}function I(e,t){let n=new URL(t);return{...e,PGDATABASE:decodeURIComponent(n.pathname.slice(1)),PGHOST:n.hostname,PGPASSWORD:decodeURIComponent(n.password),PGPORT:n.port||`5432`,PGUSER:decodeURIComponent(n.username)}}function L(e){return e.some(e=>p.basename(e)===`package.json`||p.basename(e).endsWith(`lock.yaml`)||p.basename(e)===`pnpm-workspace.yaml`)}function le(e){return e.some(e=>L([e])||/(^|\/)(vite|coreframe|tsconfig|drizzle)\.[^/]+$/.test(e)||/(^|\/)(drizzle|scripts|src\/api|tauri)(\/|$)/.test(e))}async function ue(e,t,n){return{commit:t,shortCommit:t.slice(0,12),source:n,subject:await H(e,[`show`,`-s`,`--format=%s`,t])}}async function R(e){try{let t=await c(e,`wx`);await t.writeFile(`${_.pid}\n`),await t.close()}catch(t){if(!(t instanceof Error&&`code`in t&&t.code===`EEXIST`))throw t;let n=(await l(e,`utf8`).catch(()=>`unknown`)).trim(),r=Number(n);if(Number.isInteger(r)&&!z(r)){await f(e).catch(()=>void 0),await R(e);return}throw Error(`Managed development is already owned by PID ${n}.`)}}function z(e){try{return _.kill(e,0),!0}catch(e){return!(e instanceof Error&&`code`in e&&e.code===`ESRCH`)}}async function B(e){e&&(await l(e,`utf8`).catch(()=>void 0))?.trim()===String(_.pid)&&await f(e).catch(()=>void 0)}async function V(e,t,{env:n}={}){return m(`git`,t,{cwd:e,env:n,stdin:`ignore`})}async function H(e,t){return(await V(e,t)).stdout.trim()}async function U(e,t){try{return await H(e,t)||void 0}catch(e){if(e instanceof h&&e.exitCode&&e.exitCode>0)return;throw e}}async function W(e,t,n){try{return await V(e,[`merge-base`,`--is-ancestor`,t,n]),!0}catch(e){if(e instanceof h&&e.exitCode===1)return!1;throw e}}function G(e,t){return e.length===t.length&&[...e].sort().every((e,n)=>e===[...t].sort()[n])}function K(e){return e.split(`\0`).filter(Boolean)}function de(e){return e.split(/\r?\n/,1)[0]??``}function fe(e){return e.type===`message`?`Generating commit message`:e.type===`apply`?`Integrating accepted update`:e.type===`prepare`?`Reviewing working tree`:`Aborting refresh`}function q(){return _.platform===`win32`?`pnpm.cmd`:`pnpm`}function J(e){return e instanceof Error?e.message:String(e)}async function Y(e){let t=``;for await(let n of e)if(t+=String(n),t.length>1e6)throw Error(`Managed development request is too large.`);return t?JSON.parse(t):{}}function X(e,t,n){let r=JSON.stringify(n);e.statusCode=t,e.setHeader(`Content-Type`,`application/json`),e.setHeader(`Content-Length`,Buffer.byteLength(r)),e.end(r)}async function pe(e){await new Promise((t,n)=>{e.once(`error`,n),e.listen(0,`127.0.0.1`,t)})}async function me(e){e.listening&&await new Promise((t,n)=>{e.close(e=>e?n(e):t())})}export{b as isPrimaryGitCheckout,S as startManagedDevSession};
1
+ import{createRequire as e}from"node:module";import{createHash as t,randomBytes as n}from"node:crypto";import{copyFile as r,mkdir as i,mkdtemp as a,open as o,readFile as s,realpath as c,rm as l,unlink as u}from"node:fs/promises";import d from"node:path";import f,{SubprocessError as p}from"nano-spawn";import{pathToFileURL as m}from"node:url";import h from"node:process";import{watch as g}from"node:fs";const _=`refs/heads/main`,v=`refs/remotes/origin/main`,y=/^[a-z][a-z0-9-]*(?:\([^)]+\))?!?:\s+\S/i;async function b(e=h.cwd()){let t=await C(e);return t.primary&&t.branch===`main`&&t.head===t.main}async function x(e){let t=await c(await J(e,[`rev-parse`,`--show-toplevel`])),n=await c(e),r=d.resolve(t,await J(e,[`rev-parse`,`--git-dir`])),i=d.resolve(t,await J(e,[`rev-parse`,`--git-common-dir`]));return{commonDir:i,gitDir:r,primary:t===n&&r===i}}async function S({config:e,cwd:t=h.cwd(),env:n=h.env,onRestart:r=()=>void 0,remoteCheckInterval:i=6e4}){let a=n,o={mode:`waiting`,warnings:[]},s=!1,c=!1,l=!1,u=!1,p=!1,m,g,b,x,S,w=[],D,O=async({fetch:e=!1}={})=>{if(!(!c||s||!g)){if(u){p=!0;return}try{let[n,r]=await Promise.all([J(t,[`rev-parse`,`--abbrev-ref`,`HEAD`]),J(t,[`rev-parse`,`HEAD`])]);if(n!==`main`||r!==m){await M(`The local main checkout changed outside Coreframe; managed synchronization is disabled until restart.`);return}e&&await Y(t,[`remote`,`get-url`,`origin`])&&await q(t,[`fetch`,`origin`,`+refs/heads/main:${v}`]);let i=await Y(t,[`rev-parse`,`refs/heads/dev`]),a=await Y(t,[`rev-parse`,v]),s=[...a?[{commit:a,source:`upstream`}]:[],...i?[{commit:i,source:`dev`}]:[]],c;for(let e of s)if(!await ne(t,e.commit,m)){c=e;break}let l=c?.commit;o={...o,currentCommit:m,draft:o.target?.commit===l?o.draft:void 0,message:void 0,mode:`managed`,proposal:o.target?.commit===l?o.proposal:void 0,target:c===void 0?void 0:await U(t,c.commit,c.source)}}catch(e){o={...o,message:$(e),warnings:[$(e)]}}}},k=()=>{clearTimeout(S),S=setTimeout(()=>void O(),50),S.unref()},M=async e=>{c=!1,l=!0,clearInterval(x),clearTimeout(S);for(let e of w)e.close();w=[],await K(b),b=void 0,o={message:e,mode:`unmanaged`,warnings:[]}},N=async()=>{if(c||s||l)return;let e=await C(t);if(!e.primary){o={message:`Managed development only runs from the primary checkout.`,mode:`unmanaged`,warnings:[]};return}if(e.branch!==`main`||e.head!==e.main||e.status.length>0){let t=e.branch===`main`&&e.head===e.main?`Managed development requires a clean primary checkout on main. Dirty paths:\n${e.status}`:`Managed development requires the primary checkout on local main; current branch is ${e.branch??`detached HEAD`}.`;console.warn(`Coreframe managed development disabled: ${t}`),o={message:t,mode:`unmanaged`,warnings:[]};return}b=d.join(e.commonDir,`coreframe-managed-dev.lock`),await W(b),g=e,m=e.head,c=!0,o={currentCommit:e.head,mode:`managed`,warnings:[]},w=await T(e,k),x=setInterval(()=>void O({fetch:!0}),i),x.unref(),await O(),O({fetch:!0})},P=async e=>{if(!c||o.mode!==`managed`)throw Error(`Managed development is not active.`);if(u)throw Error(`Another managed development action is already running.`);u=!0,o={...o,busy:ie(e),message:void 0};try{if(e.type===`reject`)o={...o,draft:void 0,proposal:void 0};else if(e.type===`prepare`){F(e.target);let n=await E(t);n.tracked||n.untracked.length>0?o={...o,draft:n,proposal:I(n.fingerprint)}:await R({target:e.target})}else if(e.type===`message`){let n=await L(e.fingerprint,e.untracked),r=I(n.fingerprint);if(r===void 0){try{r=await ee(t,a,n.context)}catch(e){r=``,o={...o,warnings:[...o.warnings,`Codex could not generate a commit message: ${$(e)}`]}}D={fingerprint:n.fingerprint,message:r}}o={...o,draft:n,proposal:r}}else{F(e.target);let n=await E(t);if(n.tracked||n.untracked.length>0){if(!e.fingerprint||!e.untracked)throw Error(`Refresh requires the current working-tree confirmation.`);if(await L(e.fingerprint,e.untracked),!e.message||!y.test(re(e.message)))throw Error(`Enter a commit message with a valid Conventional Commits header.`)}await R({fingerprint:e.fingerprint,message:e.message,target:e.target,untracked:e.untracked})}}finally{u=!1,o={...o,busy:void 0},p&&(p=!1,k())}return{status:o}},F=e=>{if(!o.target||o.target.commit!==e)throw Error(`The offered update changed. Review the latest target before refreshing.`)},I=e=>D?.fingerprint===e?D.message:void 0,L=async(e,n)=>{let r=await E(t);if(r.fingerprint!==e)throw D=void 0,Error(`Working-tree changes changed; generate a new commit message.`);if(!X(r.untracked,n))throw Error(`Include every untracked file or remove it before refreshing.`);return r},R=async({fingerprint:n,message:i,target:s,untracked:c=[]})=>{F(s);let l=await J(t,[`rev-parse`,`HEAD`]),u=await J(t,[`rev-parse`,_]),d,p,h=await E(t);if(h.tracked||h.untracked.length>0){if(!n||h.fingerprint!==n||!X(h.untracked,c))throw Error(`Working-tree changes changed; review them before refreshing.`);await q(t,[`add`,`--update`]),c.length>0&&await q(t,[`add`,`--`,...c]),await q(t,[`commit`,`--message`,i],{env:{GIT_EDITOR:`true`}}),d=await J(t,[`rev-parse`,`HEAD`]),m=d,p=`refs/coreframe/recovery/${Date.now()}-${d.slice(0,12)}`,await q(t,[`update-ref`,p,d])}let g=d??l,v;try{if(v=await te({cwd:t,developerCommit:d,env:a,localMain:u,target:s}),await J(t,[`rev-parse`,`HEAD`])!==g)throw Error(`HEAD changed while the accepted update was being prepared.`);if(await J(t,[`rev-parse`,_])!==g)throw Error(`Local main changed while the accepted update was being prepared.`);try{await q(t,[`update-ref`,_,v.commit,g]),await q(t,[`reset`,`--hard`,v.commit])}catch(e){throw await q(t,[`update-ref`,_,g,v.commit]).catch(()=>void 0),await q(t,[`reset`,`--hard`,g]).catch(()=>void 0),e}m=v.commit;let n=Z(await J(t,[`diff`,`--name-only`,`-z`,l,v.commit]));V(n)&&await f(Q(),[`install`,`--frozen-lockfile`],{cwd:t,env:a,stdio:`inherit`}),v.hadConflicts&&(o={...o,warnings:[...o.warnings,...await A(t,a)]});try{await j({config:e,cwd:t,env:a})}catch(e){throw await q(t,[`reset`,`--hard`,g]),m=g,o={...o,currentCommit:g},Error(`Database migration failed; the database and preview were restored. ${$(e)}`)}H(n)&&r(),D=void 0,p&&await q(t,[`update-ref`,`-d`,p]),o={...o,currentCommit:v.commit,draft:void 0,proposal:void 0,target:void 0}}catch(e){v?.commit&&m===v.commit&&(await q(t,[`reset`,`--hard`,g]).catch(()=>void 0),m=g);let n=p?` Recovery commit: ${p}.`:``;throw o={...o,currentCommit:m,message:`${$(e)}${n}`},e}};return{action:P,activate:N,getStatus:()=>o,async close(){if(!s){s=!0,clearInterval(x),clearTimeout(S);for(let e of w)e.close();await K(b)}}}}async function C(e){let t=await x(e);return{branch:w(await J(e,[`rev-parse`,`--abbrev-ref`,`HEAD`])),commonDir:t.commonDir,gitDir:t.gitDir,head:await J(e,[`rev-parse`,`HEAD`]),main:await J(e,[`rev-parse`,_]),primary:t.primary,status:await J(e,[`status`,`--porcelain`])}}function w(e){return e===`HEAD`?void 0:e}async function T(e,t){let n=[e.gitDir,d.join(e.commonDir,`refs`,`heads`)],r=[];for(let e of n)try{r.push(g(e,{persistent:!1},t))}catch{}return r}async function E(e){let[n,r,i]=await Promise.all([J(e,[`status`,`--porcelain`,`--untracked-files=no`]),J(e,[`diff`,`HEAD`,`--binary`]),J(e,[`ls-files`,`--others`,`--exclude-standard`,`-z`])]),a=Z(i).sort(),o=t(`sha256`).update(r),c=[`Tracked changes:`,r];for(let t of a){let n=await s(d.join(e,t));o.update(t).update(n),c.push(`\nUntracked file: ${t}\n`,n.toString(`utf8`))}return{context:c.join(`
2
+ `),fingerprint:o.digest(`hex`),tracked:n.length>0,untracked:a}}async function ee(e,t,n){let{stdout:r}=await f(`codex`,[`exec`,`--ephemeral`,`--ignore-user-config`,`--sandbox`,`read-only`,`--cd`,e,`Return only a concise Conventional Commits message for the supplied working-tree changes. Use a body only when it adds material context.`],{cwd:e,env:t,stdin:{string:n}});return r.trim().replace(/^```(?:text)?\s*|\s*```$/g,``)}async function te({cwd:e,developerCommit:t,env:r,localMain:a,target:o}){let s=d.resolve(e,await J(e,[`rev-parse`,`--git-common-dir`])),c=d.join(s,`coreframe-managed-dev`);await i(c,{recursive:!0});let u=n(8).toString(`hex`),f=d.join(c,`integration-${u}`),p=!1;try{if(await q(e,[`worktree`,`add`,`--detach`,f,a]),a!==o){let e=await Y(f,[`merge-base`,a,o]);p=await D(f,r,e?[`rebase`,`--onto`,o,e]:[`rebase`,`--root`,`--onto`,o],`rebase`)||p}return t&&(p=await D(f,r,[`cherry-pick`,t],`cherry-pick`)||p),{commit:await J(f,[`rev-parse`,`HEAD`]),hadConflicts:p}}finally{await q(e,[`worktree`,`remove`,`--force`,f]).catch(()=>void 0),await l(f,{force:!0,recursive:!0})}}async function D(e,t,n,r){try{return await q(e,n,{env:{GIT_EDITOR:`true`}}),!1}catch(n){let i=await k(e);if(i.length===0)throw n;console.warn(`Git ${r} conflicts occurred; Codex is resolving them.`);try{for(;i.length>0;){await O(e,t,r,i),await q(e,[`diff`,`--check`]),await q(e,[`add`,`--all`]);let n=await k(e);if(n.length>0)throw Error(`Codex left unresolved paths: ${n.join(`, `)}`);try{await q(e,[r,`--continue`],{env:{GIT_EDITOR:`true`}})}catch(t){if(i=await k(e),i.length===0)throw t;continue}i=await k(e)}return!0}catch(t){throw await q(e,[r,`--abort`]).catch(()=>void 0),Error(`Codex could not resolve ${r} conflicts: ${$(t)}`)}}}async function O(e,t,n,r){await f(`codex`,[`exec`,`--ephemeral`,`--ignore-user-config`,`--sandbox`,`workspace-write`,`--cd`,e,`Resolve the current Git ${n} conflicts cleanly. Edit only files needed for the resolution, preserve intended behavior from both sides, remove all conflict markers, and do not stage files or run Git continuation commands. Conflicted paths: ${r.join(`, `)}`],{cwd:e,env:t,stdio:`inherit`})}async function k(e){return Z(await J(e,[`diff`,`--name-only`,`--diff-filter=U`,`-z`]))}async function A(e,t){let n=[];for(let r of[`test`,`typecheck`,`lint`])try{await f(Q(),[r],{cwd:e,env:t,stdio:`inherit`})}catch(e){n.push(`${r} failed after Codex conflict resolution: ${$(e)}`)}return n}async function j({config:e,cwd:t,env:n}){if(!e.database)return;let r=await M({config:e,cwd:t,env:n});try{await f(Q(),[`db`,`migrate`],{cwd:t,env:n,stdio:`inherit`})}catch(e){throw await r.restore(),e}await r.discard().catch(e=>{console.warn(`Could not remove the managed-development database snapshot: ${$(e)}`)}),await l(r.directory,{force:!0,recursive:!0})}async function M({config:e,cwd:t,env:n}){let o=d.join(t,`.coreframe`,`managed-dev-backups`);await i(o,{recursive:!0});let s=await a(d.join(o,`refresh-`));if(e.database?.dialect===`sqlite`){let e=[`turso.db`,`turso.db-wal`,`turso.db-shm`],n=new Set;for(let r of e)await N(d.join(t,`.coreframe`,r),d.join(s,r))&&n.add(r);return{directory:s,async discard(){},async restore(){for(let i of e){let e=d.join(t,`.coreframe`,i);n.has(i)?await r(d.join(s,i),e):await l(e,{force:!0})}}}}if(!n.DATABASE_URL)throw Error(`DATABASE_URL is required to snapshot local PostgreSQL.`);let c=await P(t);if(c)return F({directory:s,connectionString:n.DATABASE_URL,postgres:c});let u=d.join(s,`database.dump`),p=B(n,n.DATABASE_URL);return await f(`pg_dump`,[`--format=custom`,`--file`,u],{cwd:t,env:p,stdin:`ignore`}),{directory:s,async discard(){},async restore(){await f(`pg_restore`,[`--clean`,`--if-exists`,`--no-owner`,`--dbname`,p.PGDATABASE,u],{cwd:t,env:p,stdin:`ignore`})}}}async function N(e,t){try{return await r(e,t),!0}catch(e){if(!(e instanceof Error&&`code`in e&&e.code===`ENOENT`))throw e;return!1}}async function P(t){let n=JSON.parse(await s(d.join(t,`package.json`),`utf8`));if(!(!n.dependencies?.pg&&!n.devDependencies?.pg&&!n.optionalDependencies?.pg))try{return await import(m(e(d.join(t,`package.json`)).resolve(`pg`)).href)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`MODULE_NOT_FOUND`)return;throw e}}async function F({directory:e,connectionString:t,postgres:r}){let i=new URL(t),a=decodeURIComponent(i.pathname.slice(1));if(!a)throw Error(`DATABASE_URL must name a PostgreSQL database to snapshot.`);let o=`coreframe_backup_${n(6).toString(`hex`)}`,s=`${o}_failed`,c=new URL(i);c.pathname=a===`postgres`?`/template1`:`/postgres`;let l=new r.Client({connectionString:c.href});await l.connect();try{await L(l,a,!1),await R(l,a),await l.query(`CREATE DATABASE ${z(o)} WITH TEMPLATE ${z(a)}`),await L(l,o,!0)}finally{await L(l,a,!0).catch(()=>void 0),await l.end()}return{directory:e,async discard(){await I(r,c.href,async e=>{await R(e,o),await e.query(`DROP DATABASE ${z(o)}`)})},async restore(){await I(r,c.href,async e=>{await L(e,a,!1),await R(e,a),await e.query(`ALTER DATABASE ${z(a)} RENAME TO ${z(s)}`);try{await e.query(`ALTER DATABASE ${z(o)} RENAME TO ${z(a)}`)}catch(t){throw await e.query(`ALTER DATABASE ${z(s)} RENAME TO ${z(a)}`).catch(()=>void 0),await L(e,a,!0).catch(()=>void 0),t}await R(e,s),await e.query(`DROP DATABASE ${z(s)}`)})}}}async function I(e,t,n){let r=new e.Client({connectionString:t});await r.connect();try{return await n(r)}finally{await r.end()}}async function L(e,t,n){await e.query(`ALTER DATABASE ${z(t)} ALLOW_CONNECTIONS ${n?`true`:`false`}`)}async function R(e,t){await e.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`,[t])}function z(e){return`"${e.replaceAll(`"`,`""`)}"`}function B(e,t){let n=new URL(t);return{...e,PGDATABASE:decodeURIComponent(n.pathname.slice(1)),PGHOST:n.hostname,PGPASSWORD:decodeURIComponent(n.password),PGPORT:n.port||`5432`,PGUSER:decodeURIComponent(n.username)}}function V(e){return e.some(e=>d.basename(e)===`package.json`||d.basename(e).endsWith(`lock.yaml`)||d.basename(e)===`pnpm-workspace.yaml`)}function H(e){return e.some(e=>V([e])||/(^|\/)(vite|coreframe|tsconfig|drizzle)\.[^/]+$/.test(e)||/(^|\/)(drizzle|scripts|src\/api|tauri)(\/|$)/.test(e))}async function U(e,t,n){return{commit:t,shortCommit:t.slice(0,12),source:n,subject:await J(e,[`show`,`-s`,`--format=%s`,t])}}async function W(e){try{let t=await o(e,`wx`);await t.writeFile(`${h.pid}\n`),await t.close()}catch(t){if(!(t instanceof Error&&`code`in t&&t.code===`EEXIST`))throw t;let n=(await s(e,`utf8`).catch(()=>`unknown`)).trim(),r=Number(n);if(Number.isInteger(r)&&!G(r)){await u(e).catch(()=>void 0),await W(e);return}throw Error(`Managed development is already owned by PID ${n}.`)}}function G(e){try{return h.kill(e,0),!0}catch(e){return!(e instanceof Error&&`code`in e&&e.code===`ESRCH`)}}async function K(e){e&&(await s(e,`utf8`).catch(()=>void 0))?.trim()===String(h.pid)&&await u(e).catch(()=>void 0)}async function q(e,t,{env:n}={}){return f(`git`,t,{cwd:e,env:n,stdin:`ignore`})}async function J(e,t){return(await q(e,t)).stdout.trim()}async function Y(e,t){try{return await J(e,t)||void 0}catch(e){if(e instanceof p&&e.exitCode&&e.exitCode>0)return;throw e}}async function ne(e,t,n){try{return await q(e,[`merge-base`,`--is-ancestor`,t,n]),!0}catch(e){if(e instanceof p&&e.exitCode===1)return!1;throw e}}function X(e,t){return e.length===t.length&&[...e].sort().every((e,n)=>e===[...t].sort()[n])}function Z(e){return e.split(`\0`).filter(Boolean)}function re(e){return e.split(/\r?\n/,1)[0]??``}function ie(e){return e.type===`message`?`Generating commit message`:e.type===`apply`?`Integrating accepted update`:e.type===`prepare`?`Reviewing working tree`:`Aborting refresh`}function Q(){return h.platform===`win32`?`pnpm.cmd`:`pnpm`}function $(e){return e instanceof Error?e.message:String(e)}export{b as isManagedDevCheckout,S as startManagedDevSession};
@@ -0,0 +1,8 @@
1
+ //#region upgrade/sync-coreframe-packages.d.ts
2
+ type SyncCoreframePackagesOptions = {
3
+ apply: boolean;
4
+ target: string;
5
+ };
6
+ declare function syncCoreframePackages(args: SyncCoreframePackagesOptions): void;
7
+ //#endregion
8
+ export { SyncCoreframePackagesOptions, syncCoreframePackages };
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import{coreframeGitRef as e}from"./template-ref.js";import{posix as t,resolve as n}from"node:path";import{readFileSync as r,writeFileSync as i}from"node:fs";import{spawnSync as a}from"node:child_process";const o=[`dependencies`,`devDependencies`];function s(e){let t=a(`git`,e,{encoding:`utf8`});if(t.status!==0){let n=t.stderr.trim()||t.stdout.trim();throw Error(`Git command failed: git ${e.join(` `)}${n?`\n${n}`:``}`)}return t.stdout}function c(e,t){try{return JSON.parse(e)}catch(e){throw Error(`Could not parse ${t}: ${e instanceof Error?e.message:e}`)}}function l(t,n){let r=`${e(t)}:${n}`;return c(s([`show`,r]),r)}function u(e){return e.startsWith(`@coreframe/`)}function d(e){return e.startsWith(`file:`)||e.startsWith(`link:`)||e.startsWith(`workspace:`)}function f(e){return e.startsWith(`file:`)||e.startsWith(`link:`)}function p(e,n){let r=e.indexOf(`:`),i=e.slice(r+1),a=t.normalize(t.join(`template`,i,`package.json`));if(i.length===0||t.isAbsolute(i)||a===`..`||a.startsWith(`../`))throw Error(`Invalid local template dependency for ${n}: ${e}`);return a}function m(t){let n=l(t,`template/package.json`),r=[],i=new Set;for(let a of o)for(let[o,s]of Object.entries(n[a]??{})){if(!u(o)||!f(s))continue;if(i.has(o))throw Error(`Target template declares ${o} more than once.`);let n=p(s,o),c=l(t,n);if(c.name!==o||typeof c.version!=`string`)throw Error(`${e(t)}:${n} must declare ${o} with a version.`);r.push({group:a,name:o,spec:`^${c.version}`}),i.add(o)}return r}function h(e,t){for(let n of o){let r=e[n]?.[t];if(r)return{group:n,spec:r}}}function g(e,t,n){let r=t.match(/\n([\t ]+)"/u)?.[1]??` `,a=t.endsWith(`
3
+ `)?`
4
+ `:``;i(e,`${JSON.stringify(n,null,r)}${a}`)}function _(e,t){if(t.length!==0){console.log(`${e}:`);for(let e of t)console.log(` ${e}`);console.log(``)}}function v(t){let i=n(s([`rev-parse`,`--show-toplevel`]).trim(),`package.json`),a=r(i,`utf8`),l=c(a,i),f=e(t.target),p=m(f),v=new Set(p.map(({name:e})=>e)),y=[],b=[],x=[],S=0;for(let e of p){let t=h(l,e.name);if(!t){b.push(`missing: ${e.name} ${e.spec} (${e.group})`);continue}if(d(t.spec)){x.push(`linked: ${e.name} ${t.spec}`);continue}if(t.spec===e.spec){S+=1;continue}y.push({...e,currentGroup:t.group,currentSpec:t.spec})}let C=o.flatMap(e=>Object.entries(l[e]??{}).filter(([e])=>u(e)&&!v.has(e)).map(([t,n])=>`review: ${t} ${n} (${e})`));if(t.apply&&y.length>0){for(let e of y)l[e.currentGroup][e.name]=e.spec;g(i,a,l)}console.log(`Coreframe package sync: ${f}`),console.log(``),_(t.apply?`Updated Coreframe packages`:`Would update Coreframe packages`,y.map(({currentSpec:e,name:t,spec:n})=>`update: ${t} ${e} -> ${n}`)),_(`Missing target Coreframe packages`,b),_(`Locally linked Coreframe packages`,x),_(`Downstream-only Coreframe packages`,C),S>0&&console.log(`${S} Coreframe package(s) already match the target versions.`),y.length===0?console.log(`No Coreframe package version updates found.`):t.apply||(console.log(``),console.log(`Run with --apply to write the ${y.length} package update(s).`))}export{v as syncCoreframePackages};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreframe/scripts",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/airlock-labs/coreframe.git",