@coreframe/scripts 0.1.31 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/coreframe.d.ts +54 -0
- package/dist/coreframe.js +2 -2
- package/dist/dev-device.js +1 -1
- package/dist/recipes/apply.d.ts +26 -0
- package/dist/recipes/apply.js +2 -0
- package/dist/recipes/list.d.ts +14 -0
- package/dist/recipes/list.js +1 -0
- package/dist/recipes/manifest.d.ts +14 -0
- package/dist/recipes/manifest.js +1 -0
- package/dist/recipes/source.d.ts +22 -0
- package/dist/recipes/source.js +1 -0
- package/dist/upgrade/ensure-template-remote.d.ts +2 -0
- package/dist/upgrade/ensure-template-remote.js +1 -1
- package/dist/user-preferences.d.ts +8 -0
- package/dist/user-preferences.js +1 -0
- package/package.json +3 -2
package/dist/coreframe.d.ts
CHANGED
|
@@ -125,6 +125,24 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
125
125
|
apply: boolean;
|
|
126
126
|
};
|
|
127
127
|
};
|
|
128
|
+
} | {
|
|
129
|
+
command: "recipes";
|
|
130
|
+
args: {
|
|
131
|
+
command: "apply";
|
|
132
|
+
args: {
|
|
133
|
+
recipe: string;
|
|
134
|
+
target: string | undefined;
|
|
135
|
+
remote: string;
|
|
136
|
+
noFetch: boolean;
|
|
137
|
+
};
|
|
138
|
+
} | {
|
|
139
|
+
command: "list";
|
|
140
|
+
args: {
|
|
141
|
+
target: string | undefined;
|
|
142
|
+
remote: string;
|
|
143
|
+
noFetch: boolean;
|
|
144
|
+
};
|
|
145
|
+
};
|
|
128
146
|
} | {
|
|
129
147
|
command: "db";
|
|
130
148
|
args: {
|
|
@@ -297,6 +315,24 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
297
315
|
apply: boolean;
|
|
298
316
|
};
|
|
299
317
|
};
|
|
318
|
+
} | {
|
|
319
|
+
command: "recipes";
|
|
320
|
+
args: {
|
|
321
|
+
command: "apply";
|
|
322
|
+
args: {
|
|
323
|
+
recipe: string;
|
|
324
|
+
target: string | undefined;
|
|
325
|
+
remote: string;
|
|
326
|
+
noFetch: boolean;
|
|
327
|
+
};
|
|
328
|
+
} | {
|
|
329
|
+
command: "list";
|
|
330
|
+
args: {
|
|
331
|
+
target: string | undefined;
|
|
332
|
+
remote: string;
|
|
333
|
+
noFetch: boolean;
|
|
334
|
+
};
|
|
335
|
+
};
|
|
300
336
|
} | {
|
|
301
337
|
command: "db";
|
|
302
338
|
args: {
|
|
@@ -406,6 +442,15 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
406
442
|
command: "sync-coreframe-packages";
|
|
407
443
|
value: void;
|
|
408
444
|
};
|
|
445
|
+
} | {
|
|
446
|
+
command: "recipes";
|
|
447
|
+
value: {
|
|
448
|
+
command: "apply";
|
|
449
|
+
value: void;
|
|
450
|
+
} | {
|
|
451
|
+
command: "list";
|
|
452
|
+
value: void;
|
|
453
|
+
};
|
|
409
454
|
} | {
|
|
410
455
|
command: "db";
|
|
411
456
|
value: {
|
|
@@ -506,6 +551,15 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
506
551
|
command: "sync-coreframe-packages";
|
|
507
552
|
value: void;
|
|
508
553
|
};
|
|
554
|
+
} | {
|
|
555
|
+
command: "recipes";
|
|
556
|
+
value: {
|
|
557
|
+
command: "apply";
|
|
558
|
+
value: void;
|
|
559
|
+
} | {
|
|
560
|
+
command: "list";
|
|
561
|
+
value: void;
|
|
562
|
+
};
|
|
509
563
|
} | {
|
|
510
564
|
command: "db";
|
|
511
565
|
value: {
|
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{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.`}),device:B({type:z(H),displayName:`device`,description:`Device name or ID for iOS or Android development.`}),port:R({long:`port`,type:z(I),description:`Port for the web development server.`})},handler:({device:e,host:t,https:n,managed:r,noManaged:i,platform:a,port:o})=>C({device:e,host:t,https:n,managed:r,noManaged:i,platform:a??`web`,webPort:o})}),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
|
|
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{validateRecipeName as w}from"./recipes/manifest.js";import{ensureTemplateRemote as T}from"./upgrade/ensure-template-remote.js";import{applyRecipe as E,printAppliedRecipe as D}from"./recipes/apply.js";import{listRecipes as O,printRecipeCatalog as k}from"./recipes/list.js";import{run as A}from"./runner.js";import{typecheckProject as j}from"./typecheck.js";import{checkUpgradeSkillCurrent as M}from"./upgrade/check-skill-current.js";import{fastForwardTemplateFiles as N}from"./upgrade/fast-forward-template-files.js";import{syncCoreframePackages as P}from"./upgrade/sync-coreframe-packages.js";import*as F from"@clack/prompts";import{array as I,command as L,extendType as R,flag as z,multioption as B,number as V,oneOf as H,option as U,optional as W,positional as G,rest as K,string as q,subcommands as J}from"cmd-ts";const Y=[`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.`],X=R(q,{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}}),Z=R(q,{displayName:`recipe`,description:`Coreframe recipe name, such as yam-db.`,async from(e){return w(e)}}),Q=J({name:`coreframe`,cmds:{assets:J({name:`assets`,cmds:{add:L({name:`add`,args:{file:G({type:q,displayName:`file`,description:`Source image to add to the asset library.`}),id:U({long:`id`,type:q,description:`Logical asset ID, such as blog/my-post/hero.`}),alt:U({long:`alt`,type:q,description:`Required alt text for the asset.`}),variantWidths:U({long:`widths`,type:W(X),description:`Generate exactly these comma-separated widths instead of the default ladder.`}),json:z({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:L({name:`build`,args:{id:U({long:`id`,type:W(q),description:`Build only one logical asset ID.`}),noPull:z({long:`no-pull`,description:`Do not perform targeted Git LFS pulls for missing source objects.`,defaultValue:()=>!1}),json:z({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:L({name:`check`,args:{fix:z({long:`fix`,description:`Build missing generated variants when possible.`,defaultValue:()=>!1}),json:z({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:L({name:`publish`,args:{outputDir:U({long:`output-dir`,type:W(q),description:`Root directory for additive local publish output. Defaults to COREFRAME_ASSETS_PUBLISH_DIR or release-upload.`}),json:z({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:L({name:`status`,args:{json:z({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:L({name:`deploy`,args:{environment:G({type:H(p),displayName:`environment`,description:`Deploy to the staging or production environment.`}),runMigrations:z({long:`run-migrations`,description:`Run pending deploy-safe database migrations before deploying.`,defaultValue:()=>!1}),skipMigrations:z({long:`skip-migrations`,description:`Deploy without running pending deploy-safe database migrations.`,defaultValue:()=>!1}),skipPostDeployChecks:z({long:`skip-post-deploy-checks`,description:`Skip post-deploy checks after Cloudflare deployment.`,defaultValue:()=>!1}),tauriLocalPlatforms:B({long:`tauri-local-platform`,type:I(H(m)),description:`Build one Tauri release platform locally. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowName:U({long:`tauri-workflow-name`,type:W(q),description:`GitHub Actions workflow file or name for remote Tauri release builds.`}),tauriWorkflowPlatforms:B({long:`tauri-workflow-platform`,type:I(H(m)),description:`Build one Tauri release platform with GitHub Actions. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowRef:U({long:`tauri-workflow-ref`,type:W(q),description:`Git ref used when dispatching remote Tauri release builds.`}),yes:z({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:J({name:`staging`,cmds:{reassign:L({name:`reassign`,args:{json:z({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:Y}));return}console.log(t.url),console.error(`Staging hostname reassigned. ${Y.join(` `)}`)}}),url:L({name:`url`,args:{json:z({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:J({name:`secrets`,cmds:{status:L({name:`status`,args:{environment:G({type:W(H(p)),displayName:`environment`,description:`Inspect staging, production, or both when omitted.`}),json:z({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):$(n))}}),set:L({name:`set`,args:{environment:G({type:H(p),displayName:`environment`,description:`Worker environment to update on its next deploy.`}),name:G({type:q,displayName:`name`,description:`Declared Worker secret name.`})},handler:async({environment:e,name:t})=>{await y({environment:e,name:t,value:await ee(t)}),console.log(`Queued ${t} for ${e}. Run coreframe deploy ${e} to apply.`)}}),discard:L({name:`discard`,args:{environment:G({type:H(p),displayName:`environment`,description:`Worker environment with a queued secret update.`}),name:G({type:q,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:L({name:`typecheck`,args:{},handler:j}),dev:L({name:`dev`,args:{https:z({long:`https`,description:`Serve the web app over locally trusted HTTPS.`,defaultValue:()=>!1}),host:U({long:`host`,type:W(q),description:`Host address for the web development server.`}),managed:z({long:`managed`,description:`Run managed checkout synchronization even without an interactive terminal.`,defaultValue:()=>!1}),noManaged:z({long:`no-managed`,description:`Run without managed checkout synchronization for this invocation.`,defaultValue:()=>!1}),platform:G({type:W(H(S)),displayName:`platform`,description:`Development target platform. Defaults to web.`}),device:G({type:W(q),displayName:`device`,description:`Device name or ID for iOS or Android development.`}),port:U({long:`port`,type:W(V),description:`Port for the web development server.`})},handler:({device:e,host:t,https:n,managed:r,noManaged:i,platform:a,port:o})=>C({device:e,host:t,https:n,managed:r,noManaged:i,platform:a??`web`,webPort:o})}),upgrade:J({name:`upgrade`,cmds:{"ensure-template-remote":L({name:`ensure-template-remote`,args:{remote:U({long:`remote`,type:q,defaultValue:()=>`template`,description:`Remote name to ensure.`}),noFetch:z({long:`no-fetch`,description:`Do not fetch the remote after ensuring it exists.`,defaultValue:()=>!1})},handler:({noFetch:e,remote:t})=>T({fetch:!e,remote:t})}),"check-skill-current":L({name:`check-skill-current`,args:{target:U({long:`target`,type:q,description:`Target Coreframe template git ref.`}),apply:z({long:`apply`,description:`Replace the local upgrade skill with the target version when it differs.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>{process.exitCode=M({apply:e,target:t})}}),"fast-forward-template-files":L({name:`fast-forward-template-files`,args:{target:U({long:`target`,type:q,description:`Target Coreframe template git ref.`}),base:U({long:`base`,type:W(q),description:`Previous Coreframe template git ref. Defaults to package.json engines.coreframe.`}),apply:z({long:`apply`,description:`Write clean fast-forwards to the worktree.`,defaultValue:()=>!1})},handler:({apply:e,base:t,target:n})=>N({apply:e,base:t,target:n})}),"sync-coreframe-packages":L({name:`sync-coreframe-packages`,args:{target:U({long:`target`,type:q,description:`Target Coreframe template git ref.`}),apply:z({long:`apply`,description:`Update existing published Coreframe dependency specifications.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>P({apply:e,target:t})})}}),recipes:J({name:`recipes`,cmds:{apply:L({name:`apply`,args:{recipe:G({type:Z,displayName:`recipe`,description:`Recipe to prepare and apply.`}),target:U({long:`target`,type:W(q),description:`Coreframe Git ref. Defaults to package.json engines.coreframe.`}),remote:U({long:`remote`,type:q,defaultValue:()=>`template`,description:`Coreframe Git remote name.`}),noFetch:z({long:`no-fetch`,description:`Use already-fetched recipe refs without fetching the remote.`,defaultValue:()=>!1})},handler:({noFetch:e,recipe:t,remote:n,target:r})=>D(E({fetch:!e,name:t,remote:n,target:r}))}),list:L({name:`list`,args:{target:U({long:`target`,type:W(q),description:`Coreframe Git ref. Defaults to package.json engines.coreframe.`}),remote:U({long:`remote`,type:q,defaultValue:()=>`template`,description:`Coreframe Git remote name.`}),noFetch:z({long:`no-fetch`,description:`Use already-fetched recipe refs without fetching the remote.`,defaultValue:()=>!1})},handler:({noFetch:e,remote:t,target:n})=>k(O({fetch:!e,remote:t,target:n}))})}}),db:J({name:`db`,cmds:{ensure:L({name:`ensure`,args:{},handler:u}),generate:L({name:`generate`,args:{args:K({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit generate.`})},handler:({args:e})=>a(`generate`,e)}),migrate:L({name:`migrate`,args:{args:K({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit migrate.`})},handler:({args:e})=>a(`migrate`,e)}),"migrate-held":L({name:`migrate-held`,args:{confirm:U({long:`confirm`,type:W(H([`run-held-migrations`])),description:`Required confirmation value for held migrations.`})},handler:({confirm:e})=>d({argv:e?[`--confirm=${e}`]:[]})}),"migrate-local":L({name:`migrate-local`,args:{},handler:s}),"migrations-check":L({name:`migrations-check`,args:{},handler:x}),reset:L({name:`reset`,args:{},handler:c}),seed:L({name:`seed`,args:{},handler:()=>o()}),"schema-check":L({name:`schema-check`,args:{seed:z({long:`seed`,description:`Run the configured project seed against the throwaway database.`,defaultValue:()=>!1})},handler:({seed:e})=>f({seed:e})}),setup:L({name:`setup`,args:{},handler:()=>l()}),studio:L({name:`studio`,args:{args:K({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit studio.`})},handler:({args:e})=>a(`studio`,e)})}})}});import.meta.main&&A(Q);function $(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 ee(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 F.password({message:`Enter the new value for ${e}`});if(F.isCancel(t))throw F.cancel(`Secret update cancelled.`),Error(`Secret update cancelled.`);return t}export{Q as coreframeCli};
|
package/dist/dev-device.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{fs as e,os as t}from"./environment.js";import n from"node:path";import
|
|
1
|
+
import{fs as e,os as t}from"./environment.js";import{readUserPreferences as n,updateUserPreferences as r}from"./user-preferences.js";import i from"node:path";import a from"nano-spawn";import*as o from"@clack/prompts";import s from"node:process";async function c({env:e=s.env,interactive:t=s.stdin.isTTY===!0,platform:n,target:r}){let i=await p(n,e).catch(()=>[]),a=r?D(i,r):void 0;if(a)return a;if(!r&&i.length>0)return f(i,n,t);let o=await m(n,e),c=r?D(o,r):void 0;if(c)return c;if(!r&&o.length>0)return f(o,n,t);let l=n===`ios`?`iOS`:`Android`;throw Error(r?`Could not find a ${l} device matching "${r}".`:`No connected ${l} devices or available ${l} ${n===`ios`?`simulators`:`emulators`} were detected.`)}async function l({device:e,host:t,interactive:n=s.stdin.isTTY===!0,platform:r}){if(!(e.physical||r===`android`&&s.platform===`win32`)&&t===void 0)return;if(typeof t==`string`&&t!==`0.0.0.0`&&t!==`::`)return t;let i=k();if(i.length===0)throw Error(`No external IP address was detected. Pass one explicitly with --host.`);let a=await u();if(a&&i.includes(a))return a;if(i.length===1)return await d(i[0]),i[0];if(!n)throw Error(`Multiple external IP addresses were detected (${i.join(`, `)}). Pass one explicitly with --host.`);let c=await o.select({message:`Which IP address should the mobile device use to reach the development server?`,options:i.map(e=>({label:e,value:e}))});if(o.isCancel(c))throw Error(`Mobile development IP selection was cancelled.`);return await d(c),c}async function u(){return(await n()).mobileDevHost}async function d(e){try{await r({mobileDevHost:e})}catch(e){o.log.warn(`Could not remember the mobile development IP address: ${e instanceof Error?e.message:String(e)}`)}}async function f(e,t,n){if(e.length===1)return e[0];if(!n)throw Error(`Multiple ${t===`ios`?`iOS`:`Android`} devices were detected. Pass a device name explicitly.`);let r=await o.select({message:`Which ${t===`ios`?`iOS`:`Android`} device should Coreframe use?`,options:e.map(e=>({label:e.label,value:e}))});if(o.isCancel(r))throw Error(`Mobile development device selection was cancelled.`);return r}async function p(e,t){return e===`android`?h(t):_(t)}async function m(e,t){return e===`android`?g(t):v(t)}async function h(e){let t=await b(e,`platform-tools`,s.platform===`win32`?`adb.exe`:`adb`),{stdout:n}=await a(t,[`devices`],{env:e}),r=n.split(/\r?\n/).map(e=>e.match(/^(\S+)\s+device(?:\s|$)/)?.[1]).filter(e=>e!==void 0);return(await Promise.all(r.map(async n=>{let r=await S(t,e,n,`ro.product.model`),i=n.startsWith(`emulator-`),a=i?await w(t,e,n,r):await T(t,e,n,r);return{id:n,label:a===r?a:`${a} (${r})`,name:a,physical:!i}}))).sort(A)}async function g(e){let{stdout:t}=await a(await b(e,`emulator`,s.platform===`win32`?`emulator.exe`:`emulator`),[`-list-avds`],{env:e});return t.split(/\r?\n/).map(e=>e.trim()).filter(e=>e.length>0&&!/^(INFO|WARNING|ERROR)\s+\|/.test(e)).map(e=>({id:e,label:e,name:e,physical:!1}))}async function _(n){let r=await e.mkdtemp(i.join(t.tmpdir(),`coreframe-ios-devices-`)),o=i.join(r,`devices.json`);try{return await e.writeFile(o,``),await a(`xcrun`,[`devicectl`,`list`,`devices`,`--json-output`,o],{env:n}),(JSON.parse(await e.readFile(o,`utf8`)).result?.devices??[]).filter(y).map(e=>({id:e.hardwareProperties.udid,label:`${e.deviceProperties.name} (${e.hardwareProperties.productType})`,name:e.deviceProperties.name,physical:!0})).sort(A)}finally{await e.rm(r,{force:!0,recursive:!0})}}async function v(e){let{stdout:t}=await a(`xcrun`,[`simctl`,`list`,`--json`,`devices`,`available`],{env:e}),n=JSON.parse(t);return Object.entries(n.devices??{}).filter(([e])=>e.includes(`iOS-`)).flatMap(([,e])=>e).flatMap(e=>e.name?[{id:e.udid,label:e.name,name:e.name,physical:!1}]:[]).sort(A)}function y(e){return e.connectionProperties?.tunnelState!==`unavailable`&&typeof e.hardwareProperties?.platform==`string`&&(e.hardwareProperties.platform.includes(`iOS`)||e.hardwareProperties.platform.includes(`xrOS`))&&typeof e.deviceProperties?.name==`string`&&typeof e.hardwareProperties.productType==`string`&&typeof e.hardwareProperties.udid==`string`}async function b(t,n,r){let a=t.ANDROID_HOME??t.ANDROID_SDK_ROOT,o=a?[a]:x(t);for(let t of o){let a=i.join(t,n,r);try{return await e.access(a),a}catch{}}return r}function x(e){return s.platform===`darwin`?[i.join(t.homedir(),`Library`,`Android`,`sdk`)]:s.platform===`win32`&&e.LOCALAPPDATA?[i.join(e.LOCALAPPDATA,`Android`,`Sdk`)]:[i.join(t.homedir(),`Android`,`Sdk`)]}async function S(e,t,n,r){return(await C(e,t,[`-s`,n,`shell`,`getprop`,r])).trim()}async function C(e,t,n){return(await a(e,n,{env:t,timeout:3e3})).stdout}async function w(e,t,n,r){return C(e,t,[`-s`,n,`emu`,`avd`,`name`]).then(e=>e.split(/\r?\n/)[0]?.trim()||r).catch(()=>r)}async function T(e,t,n,r){return C(e,t,[`-s`,n,`shell`,`dumpsys`,`bluetooth_manager`]).then(e=>E(e)||r).catch(()=>r)}function E(e){return e.match(/\bname: (.+)/)?.[1]?.trim()}function D(e,t){let n=e.map(e=>({device:e,score:Math.max(O(t,e.name),O(t,e.id??``))})).sort((e,t)=>t.score-e.score)[0];return n&&n.score>0?n.device:void 0}function O(e,t){let n=e.toLowerCase(),r=t.toLowerCase();if(r===n)return 1e4;let i=r.indexOf(n);if(i>=0)return 5e3-i;let a=0,o=0;for(let e of n){let t=r.indexOf(e,o);if(t<0)return 0;a+=t===o?2:1,o=t+1}return a}function k(){return[...new Set(Object.values(t.networkInterfaces()).flatMap(e=>e??[]).filter(e=>!e.internal&&e.family===`IPv4`).map(e=>e.address))].sort()}function A(e,t){return e.label.localeCompare(t.label)}export{l as resolveMobileDevHost,c as selectMobileDevDevice};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region recipes/apply.d.ts
|
|
2
|
+
type ApplyRecipeOptions = {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
fetch?: boolean;
|
|
5
|
+
name: string;
|
|
6
|
+
remote?: string;
|
|
7
|
+
target?: string;
|
|
8
|
+
};
|
|
9
|
+
type AppliedRecipe = {
|
|
10
|
+
created: string[];
|
|
11
|
+
instructions: string;
|
|
12
|
+
name: string;
|
|
13
|
+
ref: string;
|
|
14
|
+
unchanged: string[];
|
|
15
|
+
updated: string[];
|
|
16
|
+
};
|
|
17
|
+
declare function applyRecipe({
|
|
18
|
+
cwd,
|
|
19
|
+
fetch,
|
|
20
|
+
name,
|
|
21
|
+
remote,
|
|
22
|
+
target
|
|
23
|
+
}: ApplyRecipeOptions): AppliedRecipe;
|
|
24
|
+
declare function printAppliedRecipe(result: AppliedRecipe): void;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { AppliedRecipe, ApplyRecipeOptions, applyRecipe, printAppliedRecipe };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{parseRecipeManifest as e,validateRecipeName as t}from"./manifest.js";import{listGitFiles as n,readGitBuffer as r,readGitText as i,resolveRecipeSource as a}from"./source.js";import{dirname as o,isAbsolute as s,join as c,posix as l}from"node:path";import{existsSync as u,lstatSync as d,mkdirSync as f,readFileSync as p,writeFileSync as m}from"node:fs";import{parse as h,stringify as g}from"yaml";function _({cwd:s=process.cwd(),fetch:c=!0,name:l,remote:d=`template`,target:p}){t(l);let{projectRoot:h,ref:_,repositoryRoot:v}=a({cwd:s,fetch:c,remote:d,target:p}),b=`recipes/${l}`,C=`${b}/recipe.yaml`,E=e(i(v,_,C),C),D=i(v,_,`${b}/RECIPE.md`),O=n(v,_,`${b}/.agents`),k=new Map,A=[],j=[],M=[];for(let e of O){let t=e.slice(`${b}/`.length);x(t,`Recipe asset ${e}`),k.set(t,r(v,_,e))}let N=new Map;for(let[e,t]of k){let n=w(S(h,e));if(n===void 0)N.set(e,t),A.push(e);else if(n.equals(t))j.push(e);else throw Error(`Recipe ${l} cannot replace modified ${e}. Reconcile that agent asset manually.`)}let P=new Map;for(let e of E.routes){if(x(e.router,`Recipe route router`),x(e.path,`Recipe route path`),k.has(e.router))throw Error(`Recipe cannot replace its destination router ${e.router}.`);if(!k.has(e.path)&&!u(S(h,e.path)))throw Error(`Recipe route target ${e.path} does not exist.`);let t=P.get(e.router)??y(T(S(h,e.router),e.router),e.router);P.set(e.router,t);let n=t.routes.find(t=>t.path===e.path);if(n){if(n.when!==e.when)throw Error(`Recipe ${l} route ${e.path} conflicts with the existing trigger in ${e.router}.`);continue}t.routes.push({path:e.path,when:e.when})}for(let[e,t]of P){t.routes.sort((e,t)=>e.path<t.path?-1:+(e.path>t.path));let n=T(S(h,e),e),r=g(t,{lineWidth:0});r===n?j.push(e):(N.set(e,r),M.push(e))}for(let[e,t]of N){let n=S(h,e);f(o(n),{recursive:!0}),m(n,t)}return{created:A.sort(),instructions:D,name:l,ref:_,unchanged:[...new Set(j)].sort(),updated:M.sort()}}function v(e){console.log(`Prepared Coreframe recipe ${e.name} from ${e.ref}.`);for(let t of e.created)console.log(`created: ${t}`);for(let t of e.updated)console.log(`updated: ${t}`);for(let t of e.unchanged)console.log(`unchanged: ${t}`);console.log(`\nContinue by following ${e.ref}:recipes/${e.name}/RECIPE.md:\n`),console.log(e.instructions.trimEnd())}function y(e,t){let n=b(e,t);if(!E(n)||!D(n,[`routes`,`rules`])||!Array.isArray(n.rules)||!n.rules.every(O)||!Array.isArray(n.routes))throw Error(`${t} must contain only string rules and a routes array.`);let r=n.routes.map((e,n)=>{if(!E(e)||!D(e,[`path`,`when`])||!O(e.path)||!O(e.when))throw Error(`${t} route ${n+1} must contain path and when strings.`);return{path:e.path,when:e.when}}),i=r.map(e=>e.path);if(new Set(i).size!==i.length)throw Error(`${t} contains duplicate route paths.`);return{rules:n.rules,routes:r}}function b(e,t){try{return h(e)}catch(e){throw Error(`Could not parse ${t}.`,{cause:e})}}function x(e,t){if(!e.startsWith(`.agents/`)||s(e)||e.includes(`\\`)||l.normalize(e)!==e)throw Error(`${t} must be a normalized project-relative path beneath .agents/.`)}function S(e,t){x(t,`Recipe destination`);let n=c(e,t),r=e;for(let e of t.split(`/`))if(r=c(r,e),u(r)&&d(r).isSymbolicLink())throw Error(`Recipe destination ${t} crosses symbolic link ${r}.`);return n}function C(e){return w(e)?.toString(`utf8`)}function w(e){try{return p(e)}catch(e){if(k(e)&&e.code===`ENOENT`)return;throw e}}function T(e,t){let n=C(e);if(n===void 0)throw Error(`Required file ${t} does not exist.`);return n}function E(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function D(e,t){let n=Object.keys(e).sort();return n.length===t.length&&n.every((e,n)=>e===t[n])}function O(e){return typeof e==`string`&&e.length>0}function k(e){return e instanceof Error&&`code`in e}export{_ as applyRecipe,v as printAppliedRecipe};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RecipeSourceOptions } from "./source.js";
|
|
2
|
+
|
|
3
|
+
//#region recipes/list.d.ts
|
|
4
|
+
type RecipeCatalog = {
|
|
5
|
+
recipes: Array<{
|
|
6
|
+
description: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}>;
|
|
9
|
+
ref: string;
|
|
10
|
+
};
|
|
11
|
+
declare function listRecipes(options?: RecipeSourceOptions): RecipeCatalog;
|
|
12
|
+
declare function printRecipeCatalog(catalog: RecipeCatalog): void;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RecipeCatalog, listRecipes, printRecipeCatalog };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parseRecipeManifest as e,validateRecipeName as t}from"./manifest.js";import{listGitFiles as n,readGitText as r,resolveRecipeSource as i}from"./source.js";function a(a={}){let{ref:o,repositoryRoot:s}=i(a),c=n(s,o,`recipes`).filter(e=>/^recipes\/[^/]+\/recipe\.yaml$/u.test(e)).map(n=>{let i=n.split(`/`)[1];return t(i),{description:e(r(s,o,n),n).description,name:i}});return c.sort((e,t)=>e.name.localeCompare(t.name)),{recipes:c,ref:o}}function o(e){console.log(`Coreframe recipes at ${e.ref}:`);for(let t of e.recipes)console.log(`${t.name} — ${t.description}`)}export{a as listRecipes,o as printRecipeCatalog};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region recipes/manifest.d.ts
|
|
2
|
+
type RecipeRoute = {
|
|
3
|
+
path: string;
|
|
4
|
+
router: string;
|
|
5
|
+
when: string;
|
|
6
|
+
};
|
|
7
|
+
type RecipeManifest = {
|
|
8
|
+
description: string;
|
|
9
|
+
routes: RecipeRoute[];
|
|
10
|
+
};
|
|
11
|
+
declare function parseRecipeManifest(contents: string, path: string): RecipeManifest;
|
|
12
|
+
declare function validateRecipeName(name: string): string;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { RecipeManifest, RecipeRoute, parseRecipeManifest, validateRecipeName };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parse as e}from"yaml";const t=/^[a-z0-9]+(?:-[a-z0-9]+)*$/u;function n(e,t){let n=i(e,t);if(!a(n)||!o(n,[`description`,`routes`])||!s(n.description)||!Array.isArray(n.routes))throw Error(`${t} must contain only a description string and routes array.`);let r=n.routes.map((e,n)=>{if(!a(e)||!o(e,[`path`,`router`,`when`])||!s(e.path)||!s(e.router)||!s(e.when))throw Error(`${t} route ${n+1} must contain router, path, and when strings.`);return{path:e.path,router:e.router,when:e.when}}),c=r.map(e=>`${e.router}\0${e.path}`);if(new Set(c).size!==c.length)throw Error(`${t} contains a duplicate router and path pair.`);return{description:n.description,routes:r}}function r(e){if(!t.test(e))throw Error(`Recipe names use lowercase letters, numbers, and single hyphens.`);return e}function i(t,n){try{return e(t)}catch(e){throw Error(`Could not parse ${n}.`,{cause:e})}}function a(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function o(e,t){let n=Object.keys(e).sort();return n.length===t.length&&n.every((e,n)=>e===t[n])}function s(e){return typeof e==`string`&&e.length>0}export{n as parseRecipeManifest,r as validateRecipeName};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region recipes/source.d.ts
|
|
2
|
+
type RecipeSourceOptions = {
|
|
3
|
+
cwd?: string;
|
|
4
|
+
fetch?: boolean;
|
|
5
|
+
remote?: string;
|
|
6
|
+
target?: string;
|
|
7
|
+
};
|
|
8
|
+
declare function resolveRecipeSource({
|
|
9
|
+
cwd,
|
|
10
|
+
fetch,
|
|
11
|
+
remote,
|
|
12
|
+
target
|
|
13
|
+
}?: RecipeSourceOptions): {
|
|
14
|
+
projectRoot: string;
|
|
15
|
+
ref: string;
|
|
16
|
+
repositoryRoot: string;
|
|
17
|
+
};
|
|
18
|
+
declare function readGitText(repositoryRoot: string, ref: string, path: string): string;
|
|
19
|
+
declare function readGitBuffer(repositoryRoot: string, ref: string, path: string): NonSharedBuffer;
|
|
20
|
+
declare function listGitFiles(repositoryRoot: string, ref: string, path: string): string[];
|
|
21
|
+
//#endregion
|
|
22
|
+
export { RecipeSourceOptions, listGitFiles, readGitBuffer, readGitText, resolveRecipeSource };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ensureTemplateRemote as e}from"../upgrade/ensure-template-remote.js";import{coreframeGitRef as t}from"../upgrade/template-ref.js";import{dirname as n,join as r,resolve as i}from"node:path";import{readFileSync as a}from"node:fs";import{spawnSync as o}from"node:child_process";function s({cwd:n=process.cwd(),fetch:r=!0,remote:i=`template`,target:a}={}){let o=d(n),s=h(o,[`rev-parse`,`--show-toplevel`]),c=t(a??f(o));return e({cwd:s,fetch:r,remote:i}),{projectRoot:o,ref:c,repositoryRoot:s}}function c(e,t,n){return l(e,t,n).toString(`utf8`)}function l(e,t,n){let r=`${t}:${n}`,i=o(`git`,[`show`,r],{cwd:e,encoding:`buffer`});if(i.status!==0)throw Error(`Could not read ${r}. ${g([`show`,r],i)}`);return i.stdout}function u(e,t,n){let r=o(`git`,[`ls-tree`,`-r`,`--name-only`,`-z`,t,`--`,n],{cwd:e,encoding:`buffer`});if(r.status!==0)throw Error(g([`ls-tree`,t,n],r));return r.stdout.toString(`utf8`).split(`\0`).filter(Boolean)}function d(e){let t=i(e);for(;;){let e=r(t,`package.json`),i=m(e);if(i!==void 0&&p(i,e).engines?.coreframe)return t;let a=n(t);if(a===t)throw Error(`Could not find a package.json with engines.coreframe.`);t=a}}function f(e){let t=r(e,`package.json`),n=m(t);if(n===void 0)throw Error(`Required file package.json does not exist.`);let i=p(n,t).engines?.coreframe;if(!i)throw Error(`package.json must declare an exact engines.coreframe recipe baseline.`);return i}function p(e,t){try{return JSON.parse(e)}catch(e){throw Error(`Could not parse ${t}.`,{cause:e})}}function m(e){try{return a(e,`utf8`)}catch(e){if(_(e)&&e.code===`ENOENT`)return;throw e}}function h(e,t){let n=o(`git`,t,{cwd:e,encoding:`utf8`});if(n.status!==0)throw Error(g(t,n));return n.stdout.trim()}function g(e,t){let n=t.stderr.toString(`utf8`).trim()||t.stdout.toString(`utf8`).trim();return`Git command failed: git ${e.join(` `)}${n?`\n${n}`:``}`}function _(e){return e instanceof Error&&`code`in e}export{u as listGitFiles,l as readGitBuffer,c as readGitText,s as resolveRecipeSource};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
//#region upgrade/ensure-template-remote.d.ts
|
|
2
2
|
type EnsureTemplateRemoteOptions = {
|
|
3
|
+
cwd: string;
|
|
3
4
|
fetch: boolean;
|
|
4
5
|
remote: string;
|
|
5
6
|
};
|
|
6
7
|
declare function ensureTemplateRemote({
|
|
8
|
+
cwd,
|
|
7
9
|
fetch,
|
|
8
10
|
remote
|
|
9
11
|
}?: Partial<EnsureTemplateRemoteOptions>): void;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawnSync as e}from"node:child_process";const t=`https://github.com/airlock-labs/coreframe.git`;function n(t){return e(`git`,t,{encoding:`utf8`})}function r(e){let
|
|
2
|
+
import{spawnSync as e}from"node:child_process";const t=`https://github.com/airlock-labs/coreframe.git`;function n(t,n){return e(`git`,t,{cwd:n,encoding:`utf8`})}function r(e,t){let r=n(e,t);if(r.status!==0){let t=r.stderr.trim()||r.stdout.trim();throw Error(`Git command failed: git ${e.join(` `)}${t?`\n${t}`:``}`)}return r.stdout}function i(e,t){let r=n([`remote`,`get-url`,e],t);if(r.status===2)return null;if(r.status!==0){let t=r.stderr.trim()||r.stdout.trim();throw Error(`Could not inspect remote ${e}.${t?`\n${t}`:``}`)}return r.stdout.trim()}function a({cwd:e=process.cwd(),fetch:n=!0,remote:a=`template`}={}){if(a.length===0)throw Error(`Remote name must not be empty.`);r([`rev-parse`,`--show-toplevel`],e);let o=i(a,e);if(o===null)r([`remote`,`add`,a,t],e),console.log(`Added ${a} remote: ${t}`);else if(o===t)console.log(`${a} remote already points at ${t}`);else throw Error(`${a} remote points at ${o}, not ${t}.\nChoose the intended template source before continuing, then update or rename the remote manually.`);n&&(r([`fetch`,a,`--tags`,`--prune`],e),console.log(`Fetched ${a}.`))}export{a as ensureTemplateRemote};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region user-preferences.d.ts
|
|
2
|
+
type UserPreferences = {
|
|
3
|
+
mobileDevHost?: string;
|
|
4
|
+
};
|
|
5
|
+
declare function readUserPreferences(): Promise<UserPreferences>;
|
|
6
|
+
declare function updateUserPreferences(updates: Partial<UserPreferences>): Promise<void>;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { UserPreferences, readUserPreferences, updateUserPreferences };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{fs as e,os as t}from"./environment.js";import n from"node:path";async function r(){let e=await a();return typeof e.mobileDevHost==`string`?{mobileDevHost:e.mobileDevHost}:{}}async function i(t){let r=await a(),i=o();await e.mkdir(n.dirname(i),{recursive:!0}),await e.writeFile(i,`${JSON.stringify({...r,...t},void 0,2)}\n`)}async function a(){try{let t=await e.readFile(o(),`utf8`),n=JSON.parse(t);return s(n)?n:{}}catch{return{}}}function o(){return n.join(t.homedir(),`.coreframe`,`preferences.json`)}function s(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}export{r as readUserPreferences,i as updateUserPreferences};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreframe/scripts",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.33",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/airlock-labs/coreframe.git",
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"local-postgres": "0.3.0",
|
|
29
29
|
"nano-spawn": "^2.1.0",
|
|
30
30
|
"procband": "^0.3.7",
|
|
31
|
-
"tinyglobby": "^0.2.17"
|
|
31
|
+
"tinyglobby": "^0.2.17",
|
|
32
|
+
"yaml": "^2.9.0"
|
|
32
33
|
},
|
|
33
34
|
"devDependencies": {
|
|
34
35
|
"@types/node": "^26.1.0",
|