@coreframe/scripts 0.1.5 → 0.1.6
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/assets.d.ts +118 -0
- package/dist/assets.js +4 -0
- package/dist/coreframe.d.ts +106 -0
- package/dist/coreframe.js +1 -1
- package/dist/db/drizzle-kit.js +1 -1
- package/dist/db/migrate-held.js +1 -1
- package/dist/deploy/tauri-release.js +1 -1
- package/dist/upgrade/check-skill-current.js +1 -1
- package/dist/upgrade/fast-forward-template-files.js +1 -1
- package/dist/upgrade/template-ref.d.ts +6 -0
- package/dist/upgrade/template-ref.js +1 -0
- package/package.json +1 -1
package/dist/assets.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Plugin } from "vite";
|
|
2
|
+
|
|
3
|
+
//#region assets.d.ts
|
|
4
|
+
type AssetManifest = Record<string, AssetManifestEntry>;
|
|
5
|
+
type AssetManifestEntry = {
|
|
6
|
+
source: string;
|
|
7
|
+
alt: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
variants: AssetVariant[];
|
|
11
|
+
};
|
|
12
|
+
type AssetVariant = {
|
|
13
|
+
format: "webp";
|
|
14
|
+
width: number;
|
|
15
|
+
height: number;
|
|
16
|
+
path: string;
|
|
17
|
+
size: number;
|
|
18
|
+
hash: string;
|
|
19
|
+
};
|
|
20
|
+
type AssetProblem = {
|
|
21
|
+
code: "GENERATED_VARIANT_MISSING" | "INVALID_ALT" | "INVALID_ASSET_ID" | "INVALID_MANIFEST" | "INVALID_REFERENCE" | "INVALID_SOURCE_PATH" | "LFS_NOT_TRACKED" | "MANIFEST_MISSING" | "REFERENCE_MISSING" | "SOURCE_MISSING" | "SOURCE_POINTER_MISSING_OBJECT";
|
|
22
|
+
message: string;
|
|
23
|
+
assetId?: string;
|
|
24
|
+
file?: string;
|
|
25
|
+
fix?: string;
|
|
26
|
+
};
|
|
27
|
+
type AssetStatus = {
|
|
28
|
+
ok: boolean;
|
|
29
|
+
assets: AssetStatusEntry[];
|
|
30
|
+
problems: AssetProblem[];
|
|
31
|
+
};
|
|
32
|
+
type AssetStatusEntry = {
|
|
33
|
+
assetId: string;
|
|
34
|
+
source: string;
|
|
35
|
+
sourceExists: boolean;
|
|
36
|
+
lfsTracked: boolean;
|
|
37
|
+
variants: AssetVariantStatus[];
|
|
38
|
+
};
|
|
39
|
+
type AssetVariantStatus = AssetVariant & {
|
|
40
|
+
exists: boolean;
|
|
41
|
+
};
|
|
42
|
+
type AssetBuildResult = {
|
|
43
|
+
ok: boolean;
|
|
44
|
+
assets: AssetBuildEntry[];
|
|
45
|
+
fetched: string[];
|
|
46
|
+
problems: AssetProblem[];
|
|
47
|
+
};
|
|
48
|
+
type AssetBuildEntry = {
|
|
49
|
+
assetId: string;
|
|
50
|
+
variants: AssetVariant[];
|
|
51
|
+
};
|
|
52
|
+
type AssetPublishResult = {
|
|
53
|
+
ok: boolean;
|
|
54
|
+
uploaded: PublishedAsset[];
|
|
55
|
+
skipped: PublishedAsset[];
|
|
56
|
+
reportPath: string;
|
|
57
|
+
problems: AssetProblem[];
|
|
58
|
+
};
|
|
59
|
+
type PublishedAsset = {
|
|
60
|
+
assetId: string;
|
|
61
|
+
source: string;
|
|
62
|
+
target: string;
|
|
63
|
+
size: number;
|
|
64
|
+
};
|
|
65
|
+
type AssetWorkflowOptions = {
|
|
66
|
+
cwd?: string;
|
|
67
|
+
json?: boolean;
|
|
68
|
+
env?: NodeJS.ProcessEnv;
|
|
69
|
+
};
|
|
70
|
+
type AddAssetOptions = AssetWorkflowOptions & {
|
|
71
|
+
file: string;
|
|
72
|
+
id: string;
|
|
73
|
+
alt: string;
|
|
74
|
+
};
|
|
75
|
+
type BuildAssetsOptions = AssetWorkflowOptions & {
|
|
76
|
+
id?: string;
|
|
77
|
+
pull?: boolean;
|
|
78
|
+
updateManifest?: boolean;
|
|
79
|
+
};
|
|
80
|
+
type CheckAssetsOptions = AssetWorkflowOptions & {
|
|
81
|
+
fix?: boolean;
|
|
82
|
+
};
|
|
83
|
+
type PublishAssetsOptions = AssetWorkflowOptions & {
|
|
84
|
+
outputDir?: string;
|
|
85
|
+
};
|
|
86
|
+
type CoreframeAssetsPluginOptions = {
|
|
87
|
+
devMaterialize?: boolean;
|
|
88
|
+
cwd?: string;
|
|
89
|
+
};
|
|
90
|
+
declare function addAsset({
|
|
91
|
+
alt,
|
|
92
|
+
cwd,
|
|
93
|
+
file,
|
|
94
|
+
id
|
|
95
|
+
}: AddAssetOptions): Promise<AssetBuildResult>;
|
|
96
|
+
declare function buildAssets({
|
|
97
|
+
cwd,
|
|
98
|
+
id,
|
|
99
|
+
pull,
|
|
100
|
+
updateManifest
|
|
101
|
+
}?: BuildAssetsOptions): Promise<AssetBuildResult>;
|
|
102
|
+
declare function checkAssets({
|
|
103
|
+
cwd,
|
|
104
|
+
fix
|
|
105
|
+
}?: CheckAssetsOptions): Promise<AssetStatus>;
|
|
106
|
+
declare function publishAssets({
|
|
107
|
+
cwd,
|
|
108
|
+
env,
|
|
109
|
+
outputDir
|
|
110
|
+
}?: PublishAssetsOptions): Promise<AssetPublishResult>;
|
|
111
|
+
declare function materializeAsset(assetId: string, options?: BuildAssetsOptions): Promise<AssetBuildResult>;
|
|
112
|
+
declare function coreframeAssetsPlugin({
|
|
113
|
+
cwd,
|
|
114
|
+
devMaterialize
|
|
115
|
+
}?: CoreframeAssetsPluginOptions): Plugin;
|
|
116
|
+
declare function printAssetResult(result: unknown, json?: boolean): void;
|
|
117
|
+
//#endregion
|
|
118
|
+
export { AddAssetOptions, AssetBuildEntry, AssetBuildResult, AssetManifest, AssetManifestEntry, AssetProblem, AssetPublishResult, AssetStatus, AssetStatusEntry, AssetVariant, AssetVariantStatus, AssetWorkflowOptions, BuildAssetsOptions, CheckAssetsOptions, CoreframeAssetsPluginOptions, PublishAssetsOptions, PublishedAsset, addAsset, buildAssets, checkAssets, coreframeAssetsPlugin, materializeAsset, printAssetResult, publishAssets };
|
package/dist/assets.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{createHash as e}from"node:crypto";import{copyFile as t,mkdir as n,readFile as r,stat as i,writeFile as a}from"node:fs/promises";import{dirname as o,extname as s,join as c,relative as l,resolve as u,sep as d}from"node:path";import f from"nano-spawn";const p=`assets-src`,m=c(`assets`,`manifest.json`),h=/^[a-z0-9]+(?:[/-][a-z0-9]+)*$/,g=/@asset\s+([a-z0-9][a-z0-9/-]*)/g,_=/^version https:\/\/git-lfs.github.com\/spec\/v1\n/m;async function v({alt:e,cwd:r=process.cwd(),file:i,id:a}){T(a);let s=k(a,i),c=u(r,s),l=u(r,i);await n(o(c),{recursive:!0}),await t(l,c),await N(r,s);let d=await E(r),f=await j(c);return d.manifest[a]={source:s,alt:e,width:f.width,height:f.height,variants:[]},await D(r,d.manifest),y({cwd:r,id:a,pull:!1})}async function y({cwd:e=process.cwd(),id:t,pull:n=!0,updateManifest:r=!0}={}){let{manifest:i,problems:a}=await E(e),o=[],s=[];for(let[r,c]of Object.entries(i)){if(t&&r!==t)continue;let l=u(e,c.source);if(!await z(l)){a.push(B(r,c.source));continue}if(await I(l)&&(n&&(await P(e,c.source),o.push(c.source)),await I(l))){a.push({code:`SOURCE_POINTER_MISSING_OBJECT`,message:`Source asset "${c.source}" is still a Git LFS pointer after a targeted pull.`,assetId:r,file:c.source,fix:`Run: git lfs pull --include="${c.source}"`});continue}let d=await A(e,r,c);i[r]={...c,variants:[d]},s.push({assetId:r,variants:[d]})}return t&&!i[t]&&a.push({code:`REFERENCE_MISSING`,message:`Asset "${t}" is not present in ${m}.`,assetId:t,fix:`Run: coreframe assets add <file> --id ${t} --alt "..."`}),r&&a.length===0&&s.length>0&&await D(e,i),{ok:a.length===0,assets:s,fetched:o,problems:a}}async function b({cwd:e=process.cwd(),fix:t=!1}={}){if(t){let t=await y({cwd:e}),n=await b({cwd:e,fix:!1});return{...n,ok:n.ok&&t.ok,problems:[...n.problems,...t.problems]}}let n=await E(e),r=[...n.problems],i=[],a=await L(e);for(let[a,o]of Object.entries(n.manifest)){h.test(a)||r.push({code:`INVALID_ASSET_ID`,message:`Asset ID "${a}" must use lowercase path segments.`,assetId:a}),o.alt.trim()||r.push({code:`INVALID_ALT`,message:`Asset "${a}" is missing alt text.`,assetId:a,file:o.source,fix:`Run: coreframe assets add ${o.source} --id ${a} --alt "..."`}),o.source.startsWith(`${p}/`)||r.push({code:`INVALID_SOURCE_PATH`,message:`Asset "${a}" source must be under ${p}/.`,assetId:a,file:o.source});let n=await z(u(e,o.source)),s=n?await F(e,o.source):!1;n?s||r.push({code:`LFS_NOT_TRACKED`,message:`Source asset "${o.source}" is not tracked by Git LFS.`,assetId:a,file:o.source,fix:`Run: git lfs track "${o.source}" && git add .gitattributes ${o.source}`}):r.push(B(a,o.source));let c=await Promise.all(o.variants.map(async t=>({...t,exists:await z(u(e,t.path))})));(o.variants.length===0||c.some(e=>!e.exists))&&r.push({code:`GENERATED_VARIANT_MISSING`,message:`Asset "${a}" is missing generated variants.`,assetId:a,file:o.source,fix:t?void 0:`Run: coreframe assets build --id ${a}`}),i.push({assetId:a,source:o.source,sourceExists:n,lfsTracked:s,variants:c})}for(let e of a)n.manifest[e.assetId]||r.push({code:`INVALID_REFERENCE`,message:`Asset reference "${e.assetId}" is not present in ${m}.`,assetId:e.assetId,file:e.file,fix:`Run: coreframe assets add <file> --id ${e.assetId} --alt "..."`});return{ok:r.length===0,assets:i,problems:r}}async function x({cwd:e=process.cwd(),env:r=process.env,outputDir:i}={}){let s=[...(await b({cwd:e})).problems],l=[],d=[],f=u(e,i??r.COREFRAME_ASSETS_PUBLISH_DIR??`release-upload/assets`),p=c(f,`asset-publish-report.json`);if(s.length===0){let{manifest:r}=await E(e);for(let[i,a]of Object.entries(r))for(let r of a.variants){let a=u(e,r.path),s=c(f,r.path),p={assetId:i,source:r.path,target:s,size:r.size};if(await z(s)){d.push(p);continue}await n(o(s),{recursive:!0}),await t(a,s),l.push(p)}}let m={ok:s.length===0,uploaded:l,skipped:d,reportPath:p,problems:s};return await n(o(p),{recursive:!0}),await a(p,`${JSON.stringify(m,null,2)}\n`),m}async function S(e,t={}){return y({...t,id:e})}function C({cwd:e=process.cwd(),devMaterialize:t=!0}={}){let n=`virtual:assets`,r=`\0${n}`;return{name:`coreframe:assets`,async buildStart(){if(this.meta.watchMode)return;let t=await b({cwd:e});if(!t.ok)throw Error(V(t.problems))},async resolveId(e){if(e===n)return r},async load(t){if(t!==r)return;let{manifest:n,problems:i}=await E(e);if(i.length>0)throw Error(V(i));return[`const manifest = ${JSON.stringify(n)};`,`export { manifest };`,`export function asset(id) {`,` const entry = manifest[id];`," if (!entry) throw new Error(`Unknown Coreframe asset: ${id}`);",` return entry;`,`}`].join(`
|
|
2
|
+
`)},async transform(n,r){let i=[...n.matchAll(g)].map(e=>e[1]);if(i.length===0)return;let a=await E(e),o=[...a.problems],s=n;for(let n of i){let i=a.manifest[n];if(!i){o.push({code:`INVALID_REFERENCE`,message:`Asset reference "${n}" in "${r}" is not present in ${m}.`,assetId:n,file:r});continue}if(this.meta.watchMode&&t&&i.variants.length===0){this.warn(`Materializing Coreframe asset "${n}" for dev.`);let t=await S(n,{cwd:e,updateManifest:!1});o.push(...t.problems);let r=t.assets.find(e=>e.assetId===n);r&&(a.manifest[n]={...i,variants:r.variants})}let c=a.manifest[n]?.variants[0];if(!c){o.push({code:`GENERATED_VARIANT_MISSING`,message:`Asset "${n}" has no generated variant.`,assetId:n,file:r,fix:`Run: coreframe assets build --id ${n}`});continue}s=s.replaceAll(`@asset ${n}`,`/${c.path}`)}if(o.length>0)throw Error(V(o));return s}}}function w(e,t=!1){if(t){console.log(JSON.stringify(e,null,2));return}let n=e;n.problems&&n.problems.length>0&&console.error(V(n.problems)),console.log(n.ok===!1?`Asset workflow has problems.`:`Asset workflow complete.`)}function T(e){if(!h.test(e))throw Error(`Asset ID "${e}" must use lowercase path segments.`)}async function E(e){let t=u(e,m);if(!await z(t))return{manifest:{},problems:[{code:`MANIFEST_MISSING`,message:`${m} does not exist.`,file:m,fix:`Run: coreframe assets add <file> --id <asset-id> --alt "..."`}]};try{return{manifest:JSON.parse(await r(t,`utf8`)),problems:[]}}catch(e){return{manifest:{},problems:[{code:`INVALID_MANIFEST`,message:`${m} is not valid JSON: ${e.message}`,file:m}]}}}async function D(e,t){let r=u(e,m);await n(o(r),{recursive:!0}),await a(r,`${JSON.stringify(O(t),null,2)}\n`)}function O(e){return Object.fromEntries(Object.entries(e).sort(([e],[t])=>e.localeCompare(t)))}function k(e,t){return c(p,`${e}${s(t).toLowerCase()}`).split(d).join(`/`)}async function A(t,r,i){let s=await M(),l=u(t,i.source),d=Math.min(i.width,1200),f=c(`.coreframe/assets`,r),p=await s(l).resize({width:d,withoutEnlargement:!0}).webp().toBuffer(),m=e(`sha256`).update(p).digest(`hex`).slice(0,12),h=`${f}.${m}.${d}.webp`,g=u(t,h);await n(o(g),{recursive:!0}),await a(g,p);let _=await s(p).metadata();return{format:`webp`,width:_.width??d,height:_.height??Math.round(i.height/i.width*d),path:h,size:p.byteLength,hash:m}}async function j(e){let t=await(await M())(e).metadata();if(!t.width||!t.height)throw Error(`Could not read dimensions for ${e}.`);return{width:t.width,height:t.height}}async function M(){try{return(await import(`sharp`)).default}catch{throw Error(`The assets workflow requires the optional sharp dependency.`)}}async function N(e,t){await f(`git`,[`lfs`,`track`,t],{cwd:e})}async function P(e,t){await f(`git`,[`lfs`,`pull`,`--include=${t}`],{cwd:e})}async function F(e,t){try{return(await f(`git`,[`check-attr`,`filter`,`--`,t],{cwd:e})).stdout.includes(`filter: lfs`)}catch{return!1}}async function I(e){try{let t=await r(e,`utf8`);return _.test(t)}catch{return!1}}async function L(e){let t=await R(e),n=[];for(let i of t){let t=await r(u(e,i),`utf8`);for(let e of t.matchAll(g))n.push({assetId:e[1],file:i})}return n}async function R(e){return(await f(`git`,[`ls-files`,`*.md`,`*.mdx`,`*.ts`,`*.tsx`],{cwd:e})).stdout.split(/\r?\n/).map(e=>e.trim()).filter(Boolean).filter(e=>!e.startsWith(`dist/`))}async function z(e){try{return await i(e),!0}catch{return!1}}function B(e,t){return{code:`SOURCE_MISSING`,message:`Source asset "${t}" does not exist.`,assetId:e,file:t,fix:`Run: coreframe assets add <file> --id ${e} --alt "..."`}}function V(e){return e.map(e=>[`${e.code}: ${e.message}`,e.file?` file: ${l(process.cwd(),u(e.file))}`:void 0,e.fix?` fix: ${e.fix}`:void 0].filter(Boolean).join(`
|
|
3
|
+
`)).join(`
|
|
4
|
+
`)}export{v as addAsset,y as buildAssets,b as checkAssets,C as coreframeAssetsPlugin,S as materializeAsset,w as printAssetResult,x as publishAssets};
|
package/dist/coreframe.d.ts
CHANGED
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
//#region coreframe.d.ts
|
|
2
2
|
declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register> & {
|
|
3
3
|
parse(context: import("cmd-ts/dist/cjs/argparser").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser").ParsingResult<{
|
|
4
|
+
command: "assets";
|
|
5
|
+
args: {
|
|
6
|
+
command: "add";
|
|
7
|
+
args: {
|
|
8
|
+
file: string;
|
|
9
|
+
id: string;
|
|
10
|
+
alt: string;
|
|
11
|
+
json: boolean;
|
|
12
|
+
};
|
|
13
|
+
} | {
|
|
14
|
+
command: "build";
|
|
15
|
+
args: {
|
|
16
|
+
id: string | undefined;
|
|
17
|
+
noPull: boolean;
|
|
18
|
+
json: boolean;
|
|
19
|
+
};
|
|
20
|
+
} | {
|
|
21
|
+
command: "check";
|
|
22
|
+
args: {
|
|
23
|
+
fix: boolean;
|
|
24
|
+
json: boolean;
|
|
25
|
+
};
|
|
26
|
+
} | {
|
|
27
|
+
command: "publish";
|
|
28
|
+
args: {
|
|
29
|
+
outputDir: string | undefined;
|
|
30
|
+
json: boolean;
|
|
31
|
+
};
|
|
32
|
+
} | {
|
|
33
|
+
command: "status";
|
|
34
|
+
args: {
|
|
35
|
+
json: boolean;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
} | {
|
|
4
39
|
command: "deploy";
|
|
5
40
|
args: {
|
|
6
41
|
runMigrations: boolean;
|
|
@@ -90,6 +125,41 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
90
125
|
};
|
|
91
126
|
}>>;
|
|
92
127
|
} & import("cmd-ts/dist/cjs/helpdoc").Named & Partial<import("cmd-ts/dist/cjs/helpdoc").Descriptive & import("cmd-ts/dist/cjs/helpdoc").Versioned> & import("cmd-ts/dist/cjs/helpdoc").PrintHelp & Partial<import("cmd-ts/dist/cjs/helpdoc").Versioned> & import("cmd-ts/dist/cjs/argparser").Register & import("cmd-ts/dist/cjs/runner").Handling<{
|
|
128
|
+
command: "assets";
|
|
129
|
+
args: {
|
|
130
|
+
command: "add";
|
|
131
|
+
args: {
|
|
132
|
+
file: string;
|
|
133
|
+
id: string;
|
|
134
|
+
alt: string;
|
|
135
|
+
json: boolean;
|
|
136
|
+
};
|
|
137
|
+
} | {
|
|
138
|
+
command: "build";
|
|
139
|
+
args: {
|
|
140
|
+
id: string | undefined;
|
|
141
|
+
noPull: boolean;
|
|
142
|
+
json: boolean;
|
|
143
|
+
};
|
|
144
|
+
} | {
|
|
145
|
+
command: "check";
|
|
146
|
+
args: {
|
|
147
|
+
fix: boolean;
|
|
148
|
+
json: boolean;
|
|
149
|
+
};
|
|
150
|
+
} | {
|
|
151
|
+
command: "publish";
|
|
152
|
+
args: {
|
|
153
|
+
outputDir: string | undefined;
|
|
154
|
+
json: boolean;
|
|
155
|
+
};
|
|
156
|
+
} | {
|
|
157
|
+
command: "status";
|
|
158
|
+
args: {
|
|
159
|
+
json: boolean;
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
} | {
|
|
93
163
|
command: "deploy";
|
|
94
164
|
args: {
|
|
95
165
|
runMigrations: boolean;
|
|
@@ -178,6 +248,24 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
178
248
|
args: {};
|
|
179
249
|
};
|
|
180
250
|
}, {
|
|
251
|
+
command: "assets";
|
|
252
|
+
value: {
|
|
253
|
+
command: "add";
|
|
254
|
+
value: Promise<void>;
|
|
255
|
+
} | {
|
|
256
|
+
command: "build";
|
|
257
|
+
value: Promise<void>;
|
|
258
|
+
} | {
|
|
259
|
+
command: "check";
|
|
260
|
+
value: Promise<void>;
|
|
261
|
+
} | {
|
|
262
|
+
command: "publish";
|
|
263
|
+
value: Promise<void>;
|
|
264
|
+
} | {
|
|
265
|
+
command: "status";
|
|
266
|
+
value: Promise<void>;
|
|
267
|
+
};
|
|
268
|
+
} | {
|
|
181
269
|
command: "deploy";
|
|
182
270
|
value: Promise<void>;
|
|
183
271
|
} | {
|
|
@@ -236,6 +324,24 @@ declare const coreframeCli: Partial<import("cmd-ts/dist/cjs/argparser").Register
|
|
|
236
324
|
};
|
|
237
325
|
}> & {
|
|
238
326
|
run(context: import("cmd-ts/dist/cjs/argparser").ParseContext): Promise<import("cmd-ts/dist/cjs/argparser").ParsingResult<{
|
|
327
|
+
command: "assets";
|
|
328
|
+
value: {
|
|
329
|
+
command: "add";
|
|
330
|
+
value: Promise<void>;
|
|
331
|
+
} | {
|
|
332
|
+
command: "build";
|
|
333
|
+
value: Promise<void>;
|
|
334
|
+
} | {
|
|
335
|
+
command: "check";
|
|
336
|
+
value: Promise<void>;
|
|
337
|
+
} | {
|
|
338
|
+
command: "publish";
|
|
339
|
+
value: Promise<void>;
|
|
340
|
+
} | {
|
|
341
|
+
command: "status";
|
|
342
|
+
value: Promise<void>;
|
|
343
|
+
};
|
|
344
|
+
} | {
|
|
239
345
|
command: "deploy";
|
|
240
346
|
value: Promise<void>;
|
|
241
347
|
} | {
|
package/dist/coreframe.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
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{tauriReleasePlatforms as p}from"./deploy/config.js";import{deployProject as m}from"./deploy.js";import{checkDeployMigrations as h}from"./deploy/check-migrations.js";import{runDevServer as g}from"./dev.js";import{typecheckProject as _}from"./typecheck.js";import{checkUpgradeSkillCurrent as v}from"./upgrade/check-skill-current.js";import{ensureTemplateRemote as y}from"./upgrade/ensure-template-remote.js";import{fastForwardTemplateFiles as b}from"./upgrade/fast-forward-template-files.js";import{array as x,binary as S,command as C,flag as w,multioption as T,oneOf as E,option as D,optional as O,positional as k,rest as A,run as j,string as M,subcommands as N}from"cmd-ts";const P=N({name:`coreframe`,cmds:{assets:N({name:`assets`,cmds:{add:C({name:`add`,args:{file:k({type:M,displayName:`file`,description:`Source image to add to the asset library.`}),id:D({long:`id`,type:M,description:`Logical asset ID, such as blog/my-post/hero.`}),alt:D({long:`alt`,type:M,description:`Required alt text for the asset.`}),json:w({long:`json`,description:`Print machine-readable JSON.`,defaultValue:()=>!1})},handler:async({alt:t,file:n,id:i,json:a})=>r(await e({alt:t,file:n,id:i,json:a}),a)}),build:C({name:`build`,args:{id:D({long:`id`,type:O(M),description:`Build only one logical asset ID.`}),noPull:w({long:`no-pull`,description:`Do not perform targeted Git LFS pulls for missing source objects.`,defaultValue:()=>!1}),json:w({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:C({name:`check`,args:{fix:w({long:`fix`,description:`Build missing generated variants when possible.`,defaultValue:()=>!1}),json:w({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:C({name:`publish`,args:{outputDir:D({long:`output-dir`,type:O(M),description:`Directory for additive local publish output. Defaults to COREFRAME_ASSETS_PUBLISH_DIR or release-upload/assets.`}),json:w({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:C({name:`status`,args:{json:w({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:C({name:`deploy`,args:{runMigrations:w({long:`run-migrations`,description:`Run pending deploy-safe database migrations before deploying.`,defaultValue:()=>!1}),skipMigrations:w({long:`skip-migrations`,description:`Deploy without running pending deploy-safe database migrations.`,defaultValue:()=>!1}),skipPostDeployChecks:w({long:`skip-post-deploy-checks`,description:`Skip post-deploy checks after Cloudflare deployment.`,defaultValue:()=>!1}),tauriLocalPlatforms:T({long:`tauri-local-platform`,type:x(E(p)),description:`Build one Tauri release platform locally. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowName:D({long:`tauri-workflow-name`,type:O(M),description:`GitHub Actions workflow file or name for remote Tauri release builds.`}),tauriWorkflowPlatforms:T({long:`tauri-workflow-platform`,type:x(E(p)),description:`Build one Tauri release platform with GitHub Actions. Repeat for multiple platforms.`,defaultValue:()=>[]}),tauriWorkflowRef:D({long:`tauri-workflow-ref`,type:O(M),description:`Git ref used when dispatching remote Tauri release builds.`}),yes:w({long:`yes`,short:`y`,description:`Approve noninteractive deploy prompts.`,defaultValue:()=>!1})},handler:({runMigrations:e,skipMigrations:t,skipPostDeployChecks:n,tauriLocalPlatforms:r,tauriWorkflowName:i,tauriWorkflowPlatforms:a,tauriWorkflowRef:o,yes:s})=>m([...e?[`--run-migrations`]:[],...t?[`--skip-migrations`]:[],...n?[`--skip-post-deploy-checks`]:[],...r.flatMap(e=>[`--tauri-local-platform`,e]),...i?[`--tauri-workflow-name`,i]:[],...a.flatMap(e=>[`--tauri-workflow-platform`,e]),...o?[`--tauri-workflow-ref`,o]:[],...s?[`--yes`]:[]])}),typecheck:C({name:`typecheck`,args:{},handler:_}),dev:C({name:`dev`,args:{platform:k({type:O(E([`web`,`desktop`,`ios`,`android`])),displayName:`platform`,description:`Development target platform. Defaults to web.`})},handler:({platform:e})=>g({platform:e??`web`})}),upgrade:N({name:`upgrade`,cmds:{"ensure-template-remote":C({name:`ensure-template-remote`,args:{remote:D({long:`remote`,type:M,defaultValue:()=>`template`,description:`Remote name to ensure.`}),noFetch:w({long:`no-fetch`,description:`Do not fetch the remote after ensuring it exists.`,defaultValue:()=>!1})},handler:({noFetch:e,remote:t})=>y({fetch:!e,remote:t})}),"check-skill-current":C({name:`check-skill-current`,args:{target:D({long:`target`,type:M,description:`Target Coreframe template git ref.`}),apply:w({long:`apply`,description:`Replace the local upgrade skill with the target version when it differs.`,defaultValue:()=>!1})},handler:({apply:e,target:t})=>{process.exitCode=v({apply:e,target:t})}}),"fast-forward-template-files":C({name:`fast-forward-template-files`,args:{target:D({long:`target`,type:M,description:`Target Coreframe template git ref.`}),base:D({long:`base`,type:O(M),description:`Previous Coreframe template git ref. Defaults to package.json engines.coreframe.`}),apply:w({long:`apply`,description:`Write clean fast-forwards to the worktree.`,defaultValue:()=>!1})},handler:({apply:e,base:t,target:n})=>b({apply:e,base:t,target:n})})}}),db:N({name:`db`,cmds:{ensure:C({name:`ensure`,args:{},handler:u}),generate:C({name:`generate`,args:{args:A({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit generate.`})},handler:({args:e})=>a(`generate`,e)}),migrate:C({name:`migrate`,args:{args:A({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit migrate.`})},handler:({args:e})=>a(`migrate`,e)}),"migrate-held":C({name:`migrate-held`,args:{confirm:D({long:`confirm`,type:O(E([`run-held-migrations`])),description:`Required confirmation value for held migrations.`})},handler:({confirm:e})=>d({argv:e?[`--confirm=${e}`]:[]})}),"migrate-local":C({name:`migrate-local`,args:{},handler:s}),"migrations-check":C({name:`migrations-check`,args:{},handler:h}),reset:C({name:`reset`,args:{},handler:c}),seed:C({name:`seed`,args:{},handler:()=>o()}),"schema-check":C({name:`schema-check`,args:{seed:w({long:`seed`,description:`Run the configured project seed against the throwaway database.`,defaultValue:()=>!1})},handler:({seed:e})=>f({seed:e})}),setup:C({name:`setup`,args:{},handler:()=>l()}),studio:C({name:`studio`,args:{args:A({displayName:`drizzle-kit args`,description:`Additional arguments passed to drizzle-kit studio.`})},handler:({args:e})=>a(`studio`,e)})}})}});import.meta.main&&j(S(P),process.argv);export{P as coreframeCli};
|
package/dist/db/drizzle-kit.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{startProjectPostgres as e}from"./local-postgres.js";import t from"../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import n from"node:path";import r from"
|
|
2
|
+
import{startProjectPostgres as e}from"./local-postgres.js";import t from"../_virtual/_@oxc-project_runtime@0.138.0/helpers/esm/usingCtx.js";import n from"node:path";import r from"nano-spawn";import i from"node:process";const a=n.resolve(`node_modules`,`.bin`),o=i.platform===`win32`?`drizzle-kit.cmd`:`drizzle-kit`,s={startProjectPostgres:e};async function c(e,c=[],{env:l=i.env,spawn:u=r,startProjectPostgres:d=s.startProjectPostgres}={}){try{var f=t();let r=f.a(await d({env:l})),i=l.PATH??l.Path??``;await u(o,[e,...c],{env:{...r.env,PATH:a+n.delimiter+i},stdio:`inherit`})}catch(e){f.e=e}finally{await f.d()}}import.meta.main&&c(i.argv[2],i.argv.slice(3)).catch(e=>{console.error(e),i.exit(1)});export{c as runDrizzleKitCommand};
|
package/dist/db/migrate-held.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createProjectDeployDatabase as e}from"./project.js";import{collectHeldMigrationFiles as t,formatMigrationList as n}from"../deploy/migrations.js";import{
|
|
2
|
+
import{createProjectDeployDatabase as e}from"./project.js";import{collectHeldMigrationFiles as t,formatMigrationList as n}from"../deploy/migrations.js";import{createHash as r}from"node:crypto";import{readFile as i}from"node:fs/promises";const a=`--confirm=run-held-migrations`,o=[`-- Held migration:`,`-- Safe after:`,`-- Verification:`];async function s({argv:r=process.argv.slice(2),database:o,env:s=process.env}={}){let d=await t();if(console.log(`Held migration files:`),console.log(n(d)),!r.includes(a))throw Error(`Held migrations require explicit confirmation. Re-run with ${a}.`);if(d.length===0){console.log(`No held migrations to run.`);return}let m=o??await e({env:s});try{await u(m);for(let e of d){let t=await i(e.path,`utf8`);c(t,e.relativePath);let n=l(t),r=await m.execute(f(m.dialect,e.id));if(r.rows.length===1){if(r.rows[0]?.sha256!==n)throw Error(`Held migration ${e.relativePath} changed after it was applied.`);console.log(`Skipping already-applied held migration ${e.relativePath}`);continue}console.log(`Applying held migration ${e.relativePath}`),await h(m,async r=>{await r.execute(t),await r.execute(p(m.dialect,e.id,n))})}}finally{o||await m.close?.()}}function c(e,t){let n=o.filter(t=>!e.includes(t));if(n.length>0)throw Error(`${t} is missing held migration header fields: ${n.join(`, `)}`)}function l(e){return r(`sha256`).update(e).digest(`hex`)}async function u(e){for(let t of d(e.dialect))await e.execute(t)}function d(e){switch(e){case`postgres`:return[`create schema if not exists drizzle`,`create table if not exists drizzle.__held_migrations (
|
|
3
3
|
id text primary key,
|
|
4
4
|
sha256 text not null,
|
|
5
5
|
applied_at timestamptz not null default now()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{tauriReleasePlatforms as e}from"./config.js";import{access as t,cp as n,mkdir as r,readFile as i,rm as a,stat as o,writeFile as s}from"node:fs/promises";import{basename as c,dirname as l,join as u,relative as d,resolve as f,sep as p}from"node:path";import m from"nano-spawn";import{randomUUID as h}from"node:crypto";import{constants as g}from"node:fs";import{setTimeout as _}from"node:timers/promises";import{glob as v}from"tinyglobby";const y={android:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/android/**/*.sig`],buildArgs:[`tauri`,`android`,`build`,`--target`,`aarch64-linux-android`],targetTriple:`aarch64-linux-android`,updatePlatform:`android-aarch64`},ios:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/apple/**/*.sig`],buildArgs:[`tauri`,`ios`,`build`,`--target`,`aarch64-apple-ios`],targetTriple:`aarch64-apple-ios`,updatePlatform:`ios-aarch64`},linux:{artifactGlobs:[`tauri/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-unknown-linux-gnu`,`--`,`--locked`],targetTriple:`x86_64-unknown-linux-gnu`,updatePlatform:`linux-x86_64`},macos:{artifactGlobs:[`tauri/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`aarch64-apple-darwin`,`--`,`--locked`],targetTriple:`aarch64-apple-darwin`,updatePlatform:`darwin-aarch64`},windows:{artifactGlobs:[`tauri/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-pc-windows-msvc`,`--`,`--locked`],targetTriple:`x86_64-pc-windows-msvc`,updatePlatform:`windows-x86_64`}};function b(e){return e?e.split(/[,\s]+/u).filter(Boolean).map(e=>x(e)):[]}function x(t){if(Y(t))return t;throw Error(`Invalid Tauri release platform "${t}". Expected one of: ${e.join(`, `)}.`)}function S({args:e,config:t={},env:n}){let r=J([...t.localPlatforms??[],...b(n.TAURI_RELEASE_LOCAL_PLATFORMS),...e.tauriLocalPlatforms]),i=J([...t.workflowPlatforms??[],...b(n.TAURI_RELEASE_WORKFLOW_PLATFORMS),...e.tauriWorkflowPlatforms]),a=r.filter(e=>i.includes(e));if(a.length>0)throw Error(`Build each Tauri release platform either locally or through the workflow, not both: ${a.join(`, `)}.`);return{artifactDownloadDir:n.TAURI_RELEASE_ARTIFACT_DOWNLOAD_DIR??t.artifactDownloadDir??`.coreframe/tauri-artifacts`,b2ApplicationKey:n.B2_APPLICATION_KEY??n.B2_SECRET_ACCESS_KEY,b2ApplicationKeyId:n.B2_APPLICATION_KEY_ID??n.B2_KEY_ID??n.B2_ACCESS_KEY_ID,b2Bucket:t.b2Bucket??n.B2_BUCKET,enabled:r.length>0||i.length>0,latestManifestPath:n.TAURI_RELEASE_LATEST_MANIFEST_PATH??t.latestManifestPath??`latest.json`,localPlatforms:r,platform:I(t.platform,n),publicBaseUrl:t.publicBaseUrl??n.TAURI_RELEASE_PUBLIC_BASE_URL??n.UPDATE_PUBLIC_BASE_URL,publicPathPrefix:n.TAURI_RELEASE_PUBLIC_PATH_PREFIX??t.publicPathPrefix??n.UPDATE_PUBLIC_PATH_PREFIX??``,releaseNotesPath:n.TAURI_RELEASE_NOTES_FILE??t.releaseNotesPath,releasePath:n.TAURI_RELEASE_PATH??t.releasePath??"releases/${version}",releaseUploadDir:n.TAURI_RELEASE_UPLOAD_DIR??t.releaseUploadDir??`release-upload`,signingPrivateKey:n.TAURI_SIGNING_PRIVATE_KEY,workflowName:e.tauriWorkflowName??n.TAURI_RELEASE_WORKFLOW_NAME??t.workflowName??`tauri-release-artifacts.yml`,workflowPlatforms:i,workflowPollIntervalMs:q(n.TAURI_RELEASE_WORKFLOW_POLL_SECONDS,`TAURI_RELEASE_WORKFLOW_POLL_SECONDS`)*1e3||t.workflowPollIntervalMs||15e3,workflowRef:e.tauriWorkflowRef??n.TAURI_RELEASE_WORKFLOW_REF??t.workflowRef,workflowTimeoutMs:q(n.TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES,`TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES`)*6e4||t.workflowTimeoutMs||36e5}}async function C(e,t=process.cwd()){if(!e.enabled)return;let n=[[`TAURI_RELEASE_PUBLIC_BASE_URL`,e.publicBaseUrl],[`B2_APPLICATION_KEY_ID`,e.b2ApplicationKeyId],[`B2_APPLICATION_KEY`,e.b2ApplicationKey],[`B2_BUCKET`,e.b2Bucket]].flatMap(([e,t])=>t?[]:[e]);if(n.length>0)throw Error(`Missing required Tauri release configuration: ${n.join(`, `)}`);try{new URL(e.publicBaseUrl)}catch{throw Error(`Invalid TAURI_RELEASE_PUBLIC_BASE_URL: ${e.publicBaseUrl}`)}if(!await X(u(t,`tauri/src-tauri/tauri.conf.json`)))throw Error(`Tauri release platforms were requested, but tauri/src-tauri/tauri.conf.json does not exist.`);if(e.localPlatforms.length>0&&!e.signingPrivateKey)throw Error(`TAURI_SIGNING_PRIVATE_KEY is required for local Tauri release builds.`);e.workflowPlatforms.length>0&&await m(`gh`,[`workflow`,`view`,e.workflowName,`--ref`,e.workflowRef??await V()],{stdin:`ignore`}),await m(`b2`,[`version`],{stdin:`ignore`})}async function w(e,t,n=process.cwd()){if(!e.enabled)return{files:[]};let r=u(n,`tauri/src-tauri/tauri.conf.json`),a=u(n,`tauri/src-tauri/Cargo.toml`),o=u(n,`tauri/src-tauri/Cargo.lock`),c=await i(r,`utf8`),l=await i(a,`utf8`),d=R(l,a),f=[{path:r,source:c},{path:a,source:l}],p=[],m=JSON.parse(c);if(m.version=t,m.bundle={...m.bundle??{},createUpdaterArtifacts:!0},p.push({path:r,source:`${JSON.stringify(m,null,2)}\n`}),p.push({path:a,source:z(l,d,t,a)}),await X(o)){let e=await i(o,`utf8`);f.push({path:o,source:e}),p.push({path:o,source:B(e,d,t,o)})}for(let e of p)await s(e.path,e.source);return{files:f}}async function T(e){for(let t of e.files)await s(t.path,t.source)}async function E({env:e,plan:t,releaseName:n,version:r}){if(!t.enabled)return;await H(t.artifactDownloadDir),await H(t.releaseUploadDir);let i=t.workflowPlatforms.length>0?await A({plan:t,releaseName:n,version:r}):void 0;for(let n of t.localPlatforms)await N(n,t,e);if(i){let e=await j(t,i.runNameMarker);await m(`gh`,[`run`,`download`,String(e),`--dir`,t.artifactDownloadDir],{stdio:`inherit`})}return k({plan:t,version:r})}async function D(e,t){await m(`b2`,[`account`,`authorize`,e.b2ApplicationKeyId,e.b2ApplicationKey],{stdin:`ignore`});let n=(await v(`**/*`,{cwd:t.uploadDir,onlyFiles:!0})).sort((e,n)=>e===t.manifestPath?1:n===t.manifestPath?-1:e.localeCompare(n));for(let r of n)await m(`b2`,[`file`,`upload`,e.b2Bucket,u(t.uploadDir,r),r],{stdin:`ignore`}),console.log(`Uploaded ${r}`)}function O({artifacts:e,notes:t,pubDate:n=new Date,version:r}){return{...t?{notes:t}:{},platforms:Object.fromEntries(e.map(e=>[e.updatePlatform,{signature:e.signature,url:e.url}])),pub_date:n.toISOString(),version:r}}async function k({plan:e,version:t}){let a=K(e.publicPathPrefix,W(e.releasePath,t)),o=K(e.publicPathPrefix,e.latestManifestPath),d=[...e.localPlatforms,...e.workflowPlatforms],f=[];for(let o of d){let s=e.platform[o],d=e.localPlatforms.includes(o)?`.`:u(e.artifactDownloadDir,`tauri-${o}-${t}`),p=await P({globs:e.localPlatforms.includes(o)?s.artifactGlobs:[`**/*.sig`],sourceRoot:d,version:t}),m=K(a,s.updatePlatform),h=K(m,c(p.artifactPath)),g=K(m,c(p.signaturePath)),_=u(e.releaseUploadDir,...h.split(`/`)),v=u(e.releaseUploadDir,...g.split(`/`)),y=(await i(p.signaturePath,`utf8`)).trim();await r(l(_),{recursive:!0}),await n(p.artifactPath,_),await n(p.signaturePath,v),f.push({signature:y,updatePlatform:s.updatePlatform,url:G(e.publicBaseUrl,h)})}let p=O({artifacts:f,notes:e.releaseNotesPath?await i(e.releaseNotesPath,`utf8`):void 0,version:t}),m=u(e.releaseUploadDir,...o.split(`/`));return await r(l(m),{recursive:!0}),await s(m,`${JSON.stringify(p,null,2)}\n`),{manifestPath:o,uploadDir:e.releaseUploadDir}}async function A({plan:t,releaseName:n,version:r}){let i=t.workflowRef??await V(),a=`coreframe-${Date.now()}-${h().slice(0,8)}`;return await m(`gh`,[`workflow`,`run`,t.workflowName,`--ref`,i,`-f`,`release_name=${n}`,`-f`,`run_id=${a}`,`-f`,`version=${r}`,...e.flatMap(e=>[`-f`,`${e}=${t.workflowPlatforms.includes(e)?`true`:`false`}`])],{stdin:`ignore`}),{runNameMarker:a}}async function j(e,t){let n=Date.now()+e.workflowTimeoutMs;for(;Date.now()<n;){let n=await M(e,t);if(n?.status===`completed`){if(n.conclusion===`success`)return n.databaseId;throw Error(`Tauri release workflow ${n.databaseId} finished with ${n.conclusion}.`)}await _(e.workflowPollIntervalMs)}throw Error(`Timed out waiting for Tauri release workflow after ${Math.round(e.workflowTimeoutMs/6e4)} minutes.`)}async function M(e,t){let{stdout:n}=await m(`gh`,[`run`,`list`,`--workflow`,e.workflowName,`--event`,`workflow_dispatch`,`--json`,`conclusion,databaseId,displayTitle,status`,`--limit`,`50`],{stdin:`ignore`});return JSON.parse(n).find(e=>e.displayTitle.includes(t))}async function N(e,t,n){await m(`pnpm`,t.platform[e].buildArgs,{env:n,stdio:`inherit`})}async function P({globs:e,sourceRoot:t,version:n}){let r=await v(e,{cwd:t,absolute:!0,onlyFiles:!0}),i=[];for(let e of r){let t=e.replace(/\.sig$/u,``);await Z(t)&&i.push({artifactPath:t,signaturePath:e})}if(i.length===0)throw Error(`Could not find a Tauri updater artifact and .sig pair under ${t}.`);return i.sort((e,t)=>{let r=F(e.artifactPath,n);return F(t.artifactPath,n)-r||e.artifactPath.localeCompare(t.artifactPath)})[0]}function F(e,t){let n=0;return e.includes(t)&&(n+=100),/\.(app\.tar\.gz|AppImage\.tar\.gz|zip)$/u.test(e)&&(n+=10),/\.(exe|msi|dmg|AppImage|deb|rpm|apk|aab|ipa)$/u.test(e)&&(n+=5),n}function I(t={},n){return Object.fromEntries(e.map(e=>{let r=t[e]??{},i={...y[e],...r},a=n[`TAURI_RELEASE_${e.toUpperCase()}_TARGET_TRIPLE`],o=n[`TAURI_RELEASE_${e.toUpperCase()}_UPDATE_PLATFORM`],s=a??i.targetTriple,c=r.buildArgs?r.buildArgs:L(e,s);return[e,{...i,artifactGlobs:i.artifactGlobs??y[e].artifactGlobs,buildArgs:c,targetTriple:s,updatePlatform:o??i.updatePlatform}]}))}function L(e,t){return e===`android`?[`tauri`,`android`,`build`,`--target`,t]:e===`ios`?[`tauri`,`ios`,`build`,`--target`,t]:[`tauri`,`build`,`--target`,t,`--`,`--locked`]}function R(e,t){let n=/^\[package\][\s\S]*?^name = "(?<name>[^"]+)"/mu.exec(e);if(!n?.groups?.name)throw Error(`${t} is missing a [package] name.`);return n.groups.name}function z(e,t,n,r){let i=RegExp(`(^\\[package\\][\\s\\S]*?^name = "${Q(t)}"[\\s\\S]*?^version = ")[^"]+(")`,`mu`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package version for ${t}.`);return a}function B(e,t,n,r){let i=RegExp(`(\\[\\[package\\]\\]\\nname = "${Q(t)}"\\nversion = ")[^"]+(")`,`u`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package lock entry for ${t}.`);return a}async function V(){let{stdout:e}=await m(`git`,[`rev-parse`,`--abbrev-ref`,`HEAD`],{stdin:`ignore`}),t=e.trim();if(t!==`HEAD`)return t;let{stdout:n}=await m(`git`,[`rev-parse`,`HEAD`],{stdin:`ignore`});return n.trim()}async function H(e){U(e),await a(e,{force:!0,recursive:!0}),await r(e,{recursive:!0})}function U(e){let t=f(e),n=d(process.cwd(),t).split(p).join(`/`);if(n===``||n===`.`||n.startsWith(`../`)||n===`tauri`||n.startsWith(`tauri/`))throw Error(`Refusing to reset unsafe Tauri release directory: ${e}`)}function W(e,t){return e.replaceAll("${version}",t)}function G(e,t){let n=new URL(e),r=K(n.pathname.replace(/\/+$/u,``),t);return n.pathname=r.startsWith(`/`)?r:`/${r}`,n.toString()}function K(...e){return e.flatMap(e=>e.split(`/`)).map(e=>e.trim()).filter(Boolean).join(`/`)}function q(e,t){if(!e)return 0;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`${t} must be a positive integer.`);return n}function J(e){return[...new Set(e)]}function Y(t){return e.includes(t)}async function X(e){try{return await t(e,g.F_OK),!0}catch{return!1}}async function Z(e){try{return(await o(e)).isFile()}catch{return!1}}function Q(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{k as createTauriReleaseUpload,O as createTauriUpdateManifest,x as parseTauriReleasePlatform,b as parseTauriReleasePlatformList,E as prepareTauriRelease,S as resolveTauriReleasePlan,T as restoreTauriReleaseMetadata,D as uploadTauriReleaseToB2,C as validateTauriReleasePlan,w as writeTauriReleaseMetadata};
|
|
1
|
+
import{tauriReleasePlatforms as e}from"./config.js";import{randomUUID as t}from"node:crypto";import{access as n,cp as r,mkdir as i,readFile as a,rm as o,stat as s,writeFile as c}from"node:fs/promises";import{basename as l,dirname as u,join as d,relative as f,resolve as p,sep as m}from"node:path";import h from"nano-spawn";import{constants as g}from"node:fs";import{setTimeout as _}from"node:timers/promises";import{glob as v}from"tinyglobby";const y={android:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/android/**/*.sig`],buildArgs:[`tauri`,`android`,`build`,`--target`,`aarch64-linux-android`],targetTriple:`aarch64-linux-android`,updatePlatform:`android-aarch64`},ios:{artifactGlobs:[`tauri/src-tauri/target/**/*.sig`,`tauri/gen/apple/**/*.sig`],buildArgs:[`tauri`,`ios`,`build`,`--target`,`aarch64-apple-ios`],targetTriple:`aarch64-apple-ios`,updatePlatform:`ios-aarch64`},linux:{artifactGlobs:[`tauri/src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-unknown-linux-gnu`,`--`,`--locked`],targetTriple:`x86_64-unknown-linux-gnu`,updatePlatform:`linux-x86_64`},macos:{artifactGlobs:[`tauri/src-tauri/target/aarch64-apple-darwin/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`aarch64-apple-darwin`,`--`,`--locked`],targetTriple:`aarch64-apple-darwin`,updatePlatform:`darwin-aarch64`},windows:{artifactGlobs:[`tauri/src-tauri/target/x86_64-pc-windows-msvc/release/bundle/**/*.sig`,`tauri/src-tauri/target/release/bundle/**/*.sig`,`tauri/src-tauri/target/**/release/bundle/**/*.sig`],buildArgs:[`tauri`,`build`,`--target`,`x86_64-pc-windows-msvc`,`--`,`--locked`],targetTriple:`x86_64-pc-windows-msvc`,updatePlatform:`windows-x86_64`}};function b(e){return e?e.split(/[,\s]+/u).filter(Boolean).map(e=>x(e)):[]}function x(t){if(Y(t))return t;throw Error(`Invalid Tauri release platform "${t}". Expected one of: ${e.join(`, `)}.`)}function S({args:e,config:t={},env:n}){let r=J([...t.localPlatforms??[],...b(n.TAURI_RELEASE_LOCAL_PLATFORMS),...e.tauriLocalPlatforms]),i=J([...t.workflowPlatforms??[],...b(n.TAURI_RELEASE_WORKFLOW_PLATFORMS),...e.tauriWorkflowPlatforms]),a=r.filter(e=>i.includes(e));if(a.length>0)throw Error(`Build each Tauri release platform either locally or through the workflow, not both: ${a.join(`, `)}.`);return{artifactDownloadDir:n.TAURI_RELEASE_ARTIFACT_DOWNLOAD_DIR??t.artifactDownloadDir??`.coreframe/tauri-artifacts`,b2ApplicationKey:n.B2_APPLICATION_KEY??n.B2_SECRET_ACCESS_KEY,b2ApplicationKeyId:n.B2_APPLICATION_KEY_ID??n.B2_KEY_ID??n.B2_ACCESS_KEY_ID,b2Bucket:t.b2Bucket??n.B2_BUCKET,enabled:r.length>0||i.length>0,latestManifestPath:n.TAURI_RELEASE_LATEST_MANIFEST_PATH??t.latestManifestPath??`latest.json`,localPlatforms:r,platform:I(t.platform,n),publicBaseUrl:t.publicBaseUrl??n.TAURI_RELEASE_PUBLIC_BASE_URL??n.UPDATE_PUBLIC_BASE_URL,publicPathPrefix:n.TAURI_RELEASE_PUBLIC_PATH_PREFIX??t.publicPathPrefix??n.UPDATE_PUBLIC_PATH_PREFIX??``,releaseNotesPath:n.TAURI_RELEASE_NOTES_FILE??t.releaseNotesPath,releasePath:n.TAURI_RELEASE_PATH??t.releasePath??"releases/${version}",releaseUploadDir:n.TAURI_RELEASE_UPLOAD_DIR??t.releaseUploadDir??`release-upload`,signingPrivateKey:n.TAURI_SIGNING_PRIVATE_KEY,workflowName:e.tauriWorkflowName??n.TAURI_RELEASE_WORKFLOW_NAME??t.workflowName??`tauri-release-artifacts.yml`,workflowPlatforms:i,workflowPollIntervalMs:q(n.TAURI_RELEASE_WORKFLOW_POLL_SECONDS,`TAURI_RELEASE_WORKFLOW_POLL_SECONDS`)*1e3||t.workflowPollIntervalMs||15e3,workflowRef:e.tauriWorkflowRef??n.TAURI_RELEASE_WORKFLOW_REF??t.workflowRef,workflowTimeoutMs:q(n.TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES,`TAURI_RELEASE_WORKFLOW_TIMEOUT_MINUTES`)*6e4||t.workflowTimeoutMs||36e5}}async function C(e,t=process.cwd()){if(!e.enabled)return;let n=[[`TAURI_RELEASE_PUBLIC_BASE_URL`,e.publicBaseUrl],[`B2_APPLICATION_KEY_ID`,e.b2ApplicationKeyId],[`B2_APPLICATION_KEY`,e.b2ApplicationKey],[`B2_BUCKET`,e.b2Bucket]].flatMap(([e,t])=>t?[]:[e]);if(n.length>0)throw Error(`Missing required Tauri release configuration: ${n.join(`, `)}`);try{new URL(e.publicBaseUrl)}catch{throw Error(`Invalid TAURI_RELEASE_PUBLIC_BASE_URL: ${e.publicBaseUrl}`)}if(!await X(d(t,`tauri/src-tauri/tauri.conf.json`)))throw Error(`Tauri release platforms were requested, but tauri/src-tauri/tauri.conf.json does not exist.`);if(e.localPlatforms.length>0&&!e.signingPrivateKey)throw Error(`TAURI_SIGNING_PRIVATE_KEY is required for local Tauri release builds.`);e.workflowPlatforms.length>0&&await h(`gh`,[`workflow`,`view`,e.workflowName,`--ref`,e.workflowRef??await V()],{stdin:`ignore`}),await h(`b2`,[`version`],{stdin:`ignore`})}async function w(e,t,n=process.cwd()){if(!e.enabled)return{files:[]};let r=d(n,`tauri/src-tauri/tauri.conf.json`),i=d(n,`tauri/src-tauri/Cargo.toml`),o=d(n,`tauri/src-tauri/Cargo.lock`),s=await a(r,`utf8`),l=await a(i,`utf8`),u=R(l,i),f=[{path:r,source:s},{path:i,source:l}],p=[],m=JSON.parse(s);if(m.version=t,m.bundle={...m.bundle??{},createUpdaterArtifacts:!0},p.push({path:r,source:`${JSON.stringify(m,null,2)}\n`}),p.push({path:i,source:z(l,u,t,i)}),await X(o)){let e=await a(o,`utf8`);f.push({path:o,source:e}),p.push({path:o,source:B(e,u,t,o)})}for(let e of p)await c(e.path,e.source);return{files:f}}async function T(e){for(let t of e.files)await c(t.path,t.source)}async function E({env:e,plan:t,releaseName:n,version:r}){if(!t.enabled)return;await H(t.artifactDownloadDir),await H(t.releaseUploadDir);let i=t.workflowPlatforms.length>0?await A({plan:t,releaseName:n,version:r}):void 0;for(let n of t.localPlatforms)await N(n,t,e);if(i){let e=await j(t,i.runNameMarker);await h(`gh`,[`run`,`download`,String(e),`--dir`,t.artifactDownloadDir],{stdio:`inherit`})}return k({plan:t,version:r})}async function D(e,t){await h(`b2`,[`account`,`authorize`,e.b2ApplicationKeyId,e.b2ApplicationKey],{stdin:`ignore`});let n=(await v(`**/*`,{cwd:t.uploadDir,onlyFiles:!0})).sort((e,n)=>e===t.manifestPath?1:n===t.manifestPath?-1:e.localeCompare(n));for(let r of n)await h(`b2`,[`file`,`upload`,e.b2Bucket,d(t.uploadDir,r),r],{stdin:`ignore`}),console.log(`Uploaded ${r}`)}function O({artifacts:e,notes:t,pubDate:n=new Date,version:r}){return{...t?{notes:t}:{},platforms:Object.fromEntries(e.map(e=>[e.updatePlatform,{signature:e.signature,url:e.url}])),pub_date:n.toISOString(),version:r}}async function k({plan:e,version:t}){let n=K(e.publicPathPrefix,W(e.releasePath,t)),o=K(e.publicPathPrefix,e.latestManifestPath),s=[...e.localPlatforms,...e.workflowPlatforms],f=[];for(let o of s){let s=e.platform[o],c=e.localPlatforms.includes(o)?`.`:d(e.artifactDownloadDir,`tauri-${o}-${t}`),p=await P({globs:e.localPlatforms.includes(o)?s.artifactGlobs:[`**/*.sig`],sourceRoot:c,version:t}),m=K(n,s.updatePlatform),h=K(m,l(p.artifactPath)),g=K(m,l(p.signaturePath)),_=d(e.releaseUploadDir,...h.split(`/`)),v=d(e.releaseUploadDir,...g.split(`/`)),y=(await a(p.signaturePath,`utf8`)).trim();await i(u(_),{recursive:!0}),await r(p.artifactPath,_),await r(p.signaturePath,v),f.push({signature:y,updatePlatform:s.updatePlatform,url:G(e.publicBaseUrl,h)})}let p=O({artifacts:f,notes:e.releaseNotesPath?await a(e.releaseNotesPath,`utf8`):void 0,version:t}),m=d(e.releaseUploadDir,...o.split(`/`));return await i(u(m),{recursive:!0}),await c(m,`${JSON.stringify(p,null,2)}\n`),{manifestPath:o,uploadDir:e.releaseUploadDir}}async function A({plan:n,releaseName:r,version:i}){let a=n.workflowRef??await V(),o=`coreframe-${Date.now()}-${t().slice(0,8)}`;return await h(`gh`,[`workflow`,`run`,n.workflowName,`--ref`,a,`-f`,`release_name=${r}`,`-f`,`run_id=${o}`,`-f`,`version=${i}`,...e.flatMap(e=>[`-f`,`${e}=${n.workflowPlatforms.includes(e)?`true`:`false`}`])],{stdin:`ignore`}),{runNameMarker:o}}async function j(e,t){let n=Date.now()+e.workflowTimeoutMs;for(;Date.now()<n;){let n=await M(e,t);if(n?.status===`completed`){if(n.conclusion===`success`)return n.databaseId;throw Error(`Tauri release workflow ${n.databaseId} finished with ${n.conclusion}.`)}await _(e.workflowPollIntervalMs)}throw Error(`Timed out waiting for Tauri release workflow after ${Math.round(e.workflowTimeoutMs/6e4)} minutes.`)}async function M(e,t){let{stdout:n}=await h(`gh`,[`run`,`list`,`--workflow`,e.workflowName,`--event`,`workflow_dispatch`,`--json`,`conclusion,databaseId,displayTitle,status`,`--limit`,`50`],{stdin:`ignore`});return JSON.parse(n).find(e=>e.displayTitle.includes(t))}async function N(e,t,n){await h(`pnpm`,t.platform[e].buildArgs,{env:n,stdio:`inherit`})}async function P({globs:e,sourceRoot:t,version:n}){let r=await v(e,{cwd:t,absolute:!0,onlyFiles:!0}),i=[];for(let e of r){let t=e.replace(/\.sig$/u,``);await Z(t)&&i.push({artifactPath:t,signaturePath:e})}if(i.length===0)throw Error(`Could not find a Tauri updater artifact and .sig pair under ${t}.`);return i.sort((e,t)=>{let r=F(e.artifactPath,n);return F(t.artifactPath,n)-r||e.artifactPath.localeCompare(t.artifactPath)})[0]}function F(e,t){let n=0;return e.includes(t)&&(n+=100),/\.(app\.tar\.gz|AppImage\.tar\.gz|zip)$/u.test(e)&&(n+=10),/\.(exe|msi|dmg|AppImage|deb|rpm|apk|aab|ipa)$/u.test(e)&&(n+=5),n}function I(t={},n){return Object.fromEntries(e.map(e=>{let r=t[e]??{},i={...y[e],...r},a=n[`TAURI_RELEASE_${e.toUpperCase()}_TARGET_TRIPLE`],o=n[`TAURI_RELEASE_${e.toUpperCase()}_UPDATE_PLATFORM`],s=a??i.targetTriple,c=r.buildArgs?r.buildArgs:L(e,s);return[e,{...i,artifactGlobs:i.artifactGlobs??y[e].artifactGlobs,buildArgs:c,targetTriple:s,updatePlatform:o??i.updatePlatform}]}))}function L(e,t){return e===`android`?[`tauri`,`android`,`build`,`--target`,t]:e===`ios`?[`tauri`,`ios`,`build`,`--target`,t]:[`tauri`,`build`,`--target`,t,`--`,`--locked`]}function R(e,t){let n=/^\[package\][\s\S]*?^name = "(?<name>[^"]+)"/mu.exec(e);if(!n?.groups?.name)throw Error(`${t} is missing a [package] name.`);return n.groups.name}function z(e,t,n,r){let i=RegExp(`(^\\[package\\][\\s\\S]*?^name = "${Q(t)}"[\\s\\S]*?^version = ")[^"]+(")`,`mu`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package version for ${t}.`);return a}function B(e,t,n,r){let i=RegExp(`(\\[\\[package\\]\\]\\nname = "${Q(t)}"\\nversion = ")[^"]+(")`,`u`),a=e.replace(i,`$1${n}$2`);if(a===e)throw Error(`${r} is missing a package lock entry for ${t}.`);return a}async function V(){let{stdout:e}=await h(`git`,[`rev-parse`,`--abbrev-ref`,`HEAD`],{stdin:`ignore`}),t=e.trim();if(t!==`HEAD`)return t;let{stdout:n}=await h(`git`,[`rev-parse`,`HEAD`],{stdin:`ignore`});return n.trim()}async function H(e){U(e),await o(e,{force:!0,recursive:!0}),await i(e,{recursive:!0})}function U(e){let t=p(e),n=f(process.cwd(),t).split(m).join(`/`);if(n===``||n===`.`||n.startsWith(`../`)||n===`tauri`||n.startsWith(`tauri/`))throw Error(`Refusing to reset unsafe Tauri release directory: ${e}`)}function W(e,t){return e.replaceAll("${version}",t)}function G(e,t){let n=new URL(e),r=K(n.pathname.replace(/\/+$/u,``),t);return n.pathname=r.startsWith(`/`)?r:`/${r}`,n.toString()}function K(...e){return e.flatMap(e=>e.split(`/`)).map(e=>e.trim()).filter(Boolean).join(`/`)}function q(e,t){if(!e)return 0;let n=Number(e);if(!Number.isInteger(n)||n<=0)throw Error(`${t} must be a positive integer.`);return n}function J(e){return[...new Set(e)]}function Y(t){return e.includes(t)}async function X(e){try{return await n(e,g.F_OK),!0}catch{return!1}}async function Z(e){try{return(await s(e)).isFile()}catch{return!1}}function Q(e){return e.replace(/[.*+?^${}()|[\]\\]/gu,`\\$&`)}export{k as createTauriReleaseUpload,O as createTauriUpdateManifest,x as parseTauriReleasePlatform,b as parseTauriReleasePlatformList,E as prepareTauriRelease,S as resolveTauriReleasePlan,T as restoreTauriReleaseMetadata,D as uploadTauriReleaseToB2,C as validateTauriReleasePlan,w as writeTauriReleaseMetadata};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{coreframeGitRef as e,coreframeTemplateFile as t}from"./template-ref.js";import{join as n}from"node:path";import{tmpdir as r}from"node:os";import{existsSync as i,mkdtempSync as a,readFileSync as o,rmSync as s,writeFileSync as c}from"node:fs";import{spawnSync as l}from"node:child_process";const u=`.agents/skills/coreframe-upgrade/SKILL.md`;function d(e,t={}){return l(`git`,e,t)}function f(e){return e.stderr.toString(`utf8`).trim()||e.stdout.toString(`utf8`).trim()}function p(e,n){let r=t(e,n),i=d([`show`,r],{encoding:`utf8`});if(i.status!==0){let e=f(i);throw Error(`Could not read ${r}.${e?` ${e}`:``}`)}return i.stdout.toString()}function m(){let e=d([`rev-parse`,`--show-toplevel`],{encoding:`utf8`});if(e.status!==0){let t=f(e);throw Error(`Could not find git repository root.${t?` ${t}`:``}`)}return e.stdout.toString().trim()}function h(e,t){let i=a(n(r(),`coreframe-upgrade-skill-`)),o=n(i,`SKILL.md`);try{c(o,t);let n=f(d([`--no-pager`,`diff`,`--no-index`,`--color=never`,`--`,e,o]));n&&console.log(n)}finally{s(i,{force:!0,recursive:!0})}}function g({apply:t,target:r}){let a=n(m(),u),s=e(r);if(!i(a))throw Error(`Local ${u} does not exist.`);let l=o(a,`utf8`),d=p(r,u);return l===d?(console.log(`Coreframe upgrade skill matches ${s}:template/${u}.`),0):t?(c(a,d),console.error(`Updated ${u} from ${s}:template. Reread it before continuing the upgrade.`),20):(console.error(`Coreframe upgrade skill differs from ${s}:template/${u}.`),console.error(`Run again with --apply to update it, then reread ${u} before continuing.`),h(a,d),20)}if(import.meta.main){let e=process.argv.indexOf(`--target`),t=e===-1?null:process.argv[e+1];t||(console.error(`Usage: coreframe upgrade check-skill-current --target <git-ref> [--apply]`),process.exit(64));try{process.exit(g({apply:process.argv.includes(`--apply`),target:t}))}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(65)}}export{g as checkUpgradeSkillCurrent};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
2
|
+
import{coreframeGitRef as e,coreframeTemplateTree as t}from"./template-ref.js";import{dirname as n,join as r,resolve as i,sep as a}from"node:path";import{chmodSync as o,existsSync as s,lstatSync as c,mkdirSync as l,readFileSync as u,readlinkSync as d,rmSync as f,symlinkSync as p,writeFileSync as m}from"node:fs";import{spawnSync as h}from"node:child_process";const g=[`drizzle/`,`drizzle-hold/`],_=new Set([`100644`,`100755`,`120000`]);function v(e,t={}){return h(`git`,e,t)}function y(e){let t=v(e,{encoding:`utf8`});if(t.status!==0){let n=t.stderr.toString().trim()||t.stdout.toString().trim();throw Error(`Git command failed: git ${e.join(` `)}${n?`\n${n}`:``}`)}return t.stdout.toString()}function b(e){let t=v(e);if(t.status!==0){let n=t.stderr.toString(`utf8`).trim()||t.stdout.toString(`utf8`).trim();throw Error(`Git command failed: git ${e.join(` `)}${n?`\n${n}`:``}`)}return t.stdout}function x(){return y([`rev-parse`,`--show-toplevel`]).trim()}function S(e){let t=r(e,`package.json`);if(!s(t))throw Error(`Missing --base <git-ref>, and package.json does not exist.`);let n=JSON.parse(u(t,`utf8`)).engines?.coreframe;if(typeof n!=`string`||n.length===0)throw Error(`Missing --base <git-ref>, and package.json engines.coreframe is not set.`);return n}function C(e){let t=[],n=0;for(let r=0;r<e.length;r+=1)e[r]===0&&(t.push(e.subarray(n,r).toString(`utf8`)),n=r+1);return t.filter(e=>e.length>0)}function w(e,n){let r=C(b([`diff`,`--name-status`,`-z`,`--no-renames`,t(e),t(n),`--`])),i=[];for(let e=0;e<r.length;e+=2){let t=r[e],n=r[e+1];if(!t||!n)throw Error(`Could not parse git diff --name-status output.`);i.push({path:n,status:t})}return i}function T(e,n){let r=b([`ls-tree`,`-z`,t(e),`--`,n]);if(r.length===0)return null;let i=C(r)[0],a=i.indexOf(` `);if(a===-1)throw Error(`Could not parse git ls-tree output for ${e}:${n}.`);let[o,s,c]=i.slice(0,a).split(` `);if(!o||!s||!c)throw Error(`Could not parse git ls-tree metadata for ${e}:${n}.`);return{mode:o,object:c,path:n,type:s}}function E(e){return b([`cat-file`,`blob`,e.object])}function D(e,t){let n=i(e,t),r=e.endsWith(a)?e:`${e}${a}`;if(n!==e&&!n.startsWith(r))throw Error(`Refusing to access path outside repository: ${t}`);return n}function O(e){try{return c(e),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw e}}function k(e){return(e.mode&73)!=0}function A(e){return e===null||e.type===`blob`&&_.has(e.mode)}function j(e){return g.some(t=>e===t.slice(0,-1)||e.startsWith(t))}function M(e,t,n){let r=D(e,t);if(n===null)return{matches:!O(r)};if(!A(n))return{matches:!1,reason:`unsupported template entry mode ${n.mode} ${n.type}`};let i;try{i=c(r)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{matches:!1,reason:`path is missing from worktree`};throw e}let a=E(n);return n.mode===`120000`?i.isSymbolicLink()?{matches:Buffer.from(d(r),`utf8`).equals(a)}:{matches:!1,reason:`worktree path is not a symlink`}:i.isFile()?(n.mode===`100755`?k(i):!k(i))?{matches:u(r).equals(a)}:{matches:!1,reason:`worktree executable bit differs from template`}:{matches:!1,reason:`worktree path is not a regular file`}}function N(e){O(e)&&f(e,{force:!0,recursive:!1})}function P(e,t,r){let i=D(e,t);if(r===null){N(i);return}if(l(n(i),{recursive:!0}),r.mode===`120000`){N(i),p(E(r).toString(`utf8`),i);return}let a=O(i)?c(i):null;a&&!a.isFile()&&N(i),m(i,E(r)),o(i,r.mode===`100755`?493:420)}function F(e,t){return e===null&&t!==null?`add`:e!==null&&t===null?`delete`:`update`}function I(e,t){if(t.length!==0){console.log(`${e}:`);for(let e of t){let t=e.reason?` (${e.reason})`:``;console.log(` ${e.action}: ${e.path}${t}`)}console.log(``)}}function L(t){let n=x(),r=e(t.base??S(n)),i=e(t.target),a=w(r,i),o=[],s=[],c=[],l=[];for(let e of a){if(j(e.path)){s.push({action:`ignored`,path:e.path,reason:`project-owned migration history`});continue}let t=T(r,e.path),a=T(i,e.path),u=F(t,a);if(!A(t)||!A(a)){c.push({action:u,path:e.path,reason:`unsupported template entry type`});continue}if(M(n,e.path,a).matches){l.push({action:`unchanged`,path:e.path});continue}let d=M(n,e.path,t);if(!d.matches){c.push({action:u,path:e.path,reason:d.reason??`downstream differs from base template`});continue}o.push({action:u,path:e.path,targetEntry:a})}if(t.apply)for(let e of o)P(n,e.path,e.targetEntry??null);console.log(`Coreframe template fast-forward: ${r} -> ${i}`),console.log(``),I(t.apply?`Applied clean template updates`:`Would apply clean template updates`,o),I(`Ignored project-owned paths`,s),I(`Skipped for agent review`,c),l.length>0&&console.log(`${l.length} changed template path(s) already matched the target state.`),a.length===0&&console.log(`No template file changes found in the requested range.`),!t.apply&&o.length>0&&(console.log(``),console.log(`Run with --apply to write the ${o.length} clean update(s).`))}if(import.meta.main){let e=process.argv.indexOf(`--target`),t=e===-1?null:process.argv[e+1];t||(console.error(`Usage: coreframe upgrade fast-forward-template-files --target <git-ref> [--base <git-ref>] [--apply]`),process.exit(64));try{let e=process.argv.indexOf(`--base`);L({apply:process.argv.includes(`--apply`),base:e===-1?void 0:process.argv[e+1],target:t})}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(65)}}export{L as fastForwardTemplateFiles};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
//#region upgrade/template-ref.d.ts
|
|
2
|
+
declare function coreframeGitRef(ref: string): string;
|
|
3
|
+
declare function coreframeTemplateTree(ref: string): string;
|
|
4
|
+
declare function coreframeTemplateFile(ref: string, path: string): string;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { coreframeGitRef, coreframeTemplateFile, coreframeTemplateTree };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=/^\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;function t(t){return e.test(t)?`v${t}`:t}function n(e){return`${t(e)}:template`}function r(e,t){return`${n(e)}/${t}`}export{t as coreframeGitRef,r as coreframeTemplateFile,n as coreframeTemplateTree};
|