@crossdelta/platform-sdk 0.22.1 → 0.22.2
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/CHANGELOG.md +16 -0
- package/bin/cli.mjs +110 -109
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to `@crossdelta/platform-sdk` will be documented in this fil
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.22.2] - 2026-08-24
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **`pf dev` reported a missing `@crossdelta/infrastructure` as an unreadable module error and
|
|
12
|
+
carried on.** The package is a peer dependency, so neither `bun add -g` nor `npm i -g` installs it
|
|
13
|
+
with the CLI, and bun says nothing when it is absent. The failed `/streams` import was then
|
|
14
|
+
classified as recoverable, leaving the services to create the streams: they keep whatever shape
|
|
15
|
+
they already had, so a corrected contract subject never takes effect and its events are dropped
|
|
16
|
+
without an error. The failure now stops `pf dev` and names the package, the reason and the
|
|
17
|
+
install command.
|
|
18
|
+
|
|
19
|
+
The classification was reached through `instanceof Error`, which bun never satisfies for a failed
|
|
20
|
+
import: it rejects with a `ResolveMessage` carrying `message` and `code` but not extending
|
|
21
|
+
`Error`. Every bun-side resolution failure therefore took the "unknown, so recoverable" path.
|
|
22
|
+
Error inspection now reads a `message` off any thrown object.
|
|
23
|
+
|
|
8
24
|
## [0.22.1] - 2026-08-24
|
|
9
25
|
|
|
10
26
|
### Fixed
|
package/bin/cli.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
Hint: ${this.hint}`),t.join("")}},z=class extends U{path;constructor(t,r,n={}){super(t,w.IO_ERROR,{...n,category:"io"}),this.name="IoError",this.path=r}},qe=class extends U{constructor(t="Operation cancelled",r={}){super(t,w.CANCELLED,{...r,category:"user"}),this.name="CancelledError"}}});import Z from"chalk";var X,
|
|
4
|
-
Hint: ${e.hint}`)),n&&process.exit(
|
|
5
|
-
`)}function
|
|
2
|
+
var sa=Object.defineProperty;var Jt=(e=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(e,{get:(t,r)=>(typeof require<"u"?require:t)[r]}):e)(function(e){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+e+'" is not supported')});var S=(e,t)=>()=>(e&&(t=e(e=0)),t);var ia=(e,t)=>{for(var r in t)sa(e,r,{get:t[r],enumerable:!0})};var w,Ke=S(()=>{"use strict";w={SUCCESS:0,GENERAL_ERROR:1,USAGE_ERROR:2,WORKSPACE_ERROR:64,VALIDATION_ERROR:65,CONFIG_ERROR:66,IO_ERROR:74,PERMISSION_ERROR:77,CANCELLED:130}});var U,z,qe,Kt=S(()=>{"use strict";Ke();U=class extends Error{exitCode;category;hint;cause;constructor(t,r=w.GENERAL_ERROR,n={}){super(t),this.name="CliError",this.exitCode=r,this.category=n.category??"process",this.hint=n.hint,this.cause=n.cause}toUserMessage(){let t=[this.message];return this.hint&&t.push(`
|
|
3
|
+
Hint: ${this.hint}`),t.join("")}},z=class extends U{path;constructor(t,r,n={}){super(t,w.IO_ERROR,{...n,category:"io"}),this.name="IoError",this.path=r}},qe=class extends U{constructor(t="Operation cancelled",r={}){super(t,w.CANCELLED,{...r,category:"user"}),this.name="CancelledError"}}});import Z from"chalk";var X,kn,xn,wn,aa,ca,Ye,la,pa,$,Pn=S(()=>{"use strict";Kt();Ke();X=e=>e instanceof Error,kn=e=>X(e)?e.message:typeof e=="string"?e:String(e),xn=["ExitPromptError"],wn=["Cancelled prompt","User force closed"],aa=["ERR_USE_AFTER_CLOSE"],ca=e=>xn.some(t=>e.name?.includes(t))||wn.some(t=>e.message?.includes(t)),Ye=e=>{if(e instanceof qe)return!0;if(!(e instanceof Error))return!1;if(xn.some(r=>e.name?.includes(r))||wn.some(r=>e.message?.includes(r)))return!0;let t=e.code;return t&&aa.includes(t)?ca(e):!1},la=e=>{if(e instanceof U){let r=e.toUserMessage();return Z.red(`\u2716 ${r||"Unexpected error (re-run with DEBUG=true for details)"}`)}if(e instanceof Error){let r=e.message?.trim();return r?Z.red(`\u2716 ${r}`):Z.red("\u2716 Unexpected error (re-run with DEBUG=true for details)")}let t=String(e);return!t||t==="undefined"||t==="null"?Z.red("\u2716 Unexpected error (re-run with DEBUG=true for details)"):Z.red(`\u2716 ${t}`)},pa=e=>e instanceof U?e.exitCode:Ye(e)?w.CANCELLED:w.GENERAL_ERROR,$=(e,t={})=>{let{debug:r=process.env.DEBUG==="true",exit:n=!0,logger:o=console.error}=t;if(Ye(e)){n&&process.exit(w.CANCELLED);return}o(la(e)),r&&e instanceof Error&&e.stack&&o(Z.dim(e.stack)),e instanceof U&&e.hint&&o(Z.dim(`
|
|
4
|
+
Hint: ${e.hint}`)),n&&process.exit(pa(e))}});var V=S(()=>{"use strict";Kt();Pn();Ke()});var Yu,Sn,qt,Ze=S(()=>{"use strict";Yu=process.env.npm_package_version||"0.0.0",Sn=["bun.lock","bun.lockb","package-lock.json","yarn.lock","pnpm-lock.yaml"],qt="start:dev"});import Xe from"chalk";function Yt(e,t){if(e.length===0)return"No entries to display.";let r=t?.title||"Benchmark Results",n=t?.footer||"",o=t?.maxBarWidth||50,s=t?.unit||"",i=Math.max(...e.map(c=>c.value)),a=[];a.push(""),a.push(r),a.push("");for(let c of e){let l=ma(c.barColor??t?.barColor),p=da(c,i,o,l,s,t?.labelColor);a.push(p)}return n&&(a.push(""),a.push(n)),a.join(`
|
|
5
|
+
`)}function ma(e){return e?Xe[e]("\u2587"):"\u2587"}function da(e,t,r,n,o,s){let i=Math.round(e.value/t*r),a=e.barColor?Xe[e.barColor](n.repeat(i)):n.repeat(i),c=e.color??s;return`${Xe.bold(c?Xe[c](e.label.padEnd(12)):e.label.padEnd(12))} ${a} ${e.value.toLocaleString()}${o?` ${o}`:""}`}var bn=S(()=>{"use strict"});import{existsSync as Qt,unlinkSync as ga,writeFileSync as ua}from"fs";import{join as Xt}from"path";import Zt from"chokidar";var er,Qe,fa,En,tr,ha,Tn,rr=S(()=>{"use strict";v();f();er=".pf-generating",Qe=e=>Xt(e,er),fa=e=>Qt(Qe(e)),En=e=>{ua(Qe(e),"","utf-8")},tr=e=>{let t=Qe(e);Qt(t)&&ga(t)},ha=e=>{let r=F(e)?.pf?.paths;return r?Object.values(r).filter(n=>typeof n=="object"&&n!==null&&n.watch===!0&&typeof n.path=="string"):[{path:"services"},{path:"apps"}]},Tn=(e,t)=>{tr(e);let r=ha(e),n=Qe(e),s=ae(async()=>{fa(e)||await t()},300),i=[];i.push(Zt.watch(n,{ignoreInitial:!0}).on("unlink",()=>t()));for(let a of r){let c=Xt(e,a.path);if(!Qt(c))continue;let l=a.ignorePatterns?.map(p=>Xt(c,p));i.push(Zt.watch(c,{ignoreInitial:!0,depth:0,ignored:l,usePolling:!0,interval:1e3}).on("addDir",p=>p!==c&&s()).on("unlinkDir",p=>p!==c&&s())),i.push(Zt.watch(`${c}/*/package.json`,{ignoreInitial:!0,ignored:l}).on("add",s).on("change",s))}return async()=>{await Promise.all(i.map(a=>a.close()))}}});import $n from"chalk";import{Command as ya}from"commander";import{Listr as An}from"listr2";var J,va,In,Rn=S(()=>{"use strict";V();rr();f();J=e=>{let t=new ya(e.name).description(e.description).showHelpAfterError();e.arguments?.forEach(([o,s])=>{t.argument(o,s)}),e.options?.forEach(([o,s])=>{t.option(o,s)}),e.exampleUsage&&t.addHelpText("after",()=>`${$n.cyan.bold(`
|
|
6
6
|
Example:`)}
|
|
7
|
-
${
|
|
8
|
-
`),e.additionalInfo&&t.addHelpText("after",()=>(typeof e.additionalInfo=="function"?e.additionalInfo():e.additionalInfo)??"");let r=async o=>{e.prompts?.length&&await new
|
|
9
|
-
`,"utf-8"),
|
|
7
|
+
${$n.bold(e.exampleUsage)}
|
|
8
|
+
`),e.additionalInfo&&t.addHelpText("after",()=>(typeof e.additionalInfo=="function"?e.additionalInfo():e.additionalInfo)??"");let r=async o=>{e.prompts?.length&&await new An(In(e.prompts,o),{rendererOptions:{lazy:!0,showErrorMessage:!1}}).run(o),await new An(In(e.actions,o),{rendererOptions:{lazy:!1,showErrorMessage:!1}}).run(o),await e.onComplete?.(o)},n=()=>{try{let o=g();return En(o),o}catch{return null}};return t.action(async(...o)=>{let s=null;try{let i=o.at(-1),a=i.args,c=i.opts(),l=va(e.arguments??[],a);if(e.shouldSkipWorkflow?.(l,c)){await e.onSkipWorkflow?.(l,c);return}let p=await e.buildContext(l,c);s=n(),await r(p)}catch(i){$(i,{exit:!1})}finally{s&&tr(s)}}),t},va=(e,t)=>{let r=e.map(([n],o)=>[n.replace(/[<>[\]]/g,""),t[o]]);return Object.fromEntries(r)},In=(e,t)=>e.map(r=>typeof r=="function"?r(t):r)});var ae,Nn=S(()=>{"use strict";ae=(e,t)=>{let r=null;return(...n)=>(r&&clearTimeout(r),new Promise(o=>{r=setTimeout(async()=>{r=null,await e(...n),o()},t)}))}});var Fn=S(()=>{"use strict"});import{execaSync as Ca}from"execa";function Ee(e){try{return Ca(e,["--version"]),!0}catch{return!1}}var nr=S(()=>{"use strict"});var On=S(()=>{"use strict";nr()});import{readdirSync as ka}from"fs";import{dirname as Mn,isAbsolute as xa,join as wa,normalize as Pa,resolve as Dn,sep as Sa}from"path";import{fileURLToPath as ba}from"url";import{packageUpSync as Ea}from"package-up";import{rimraf as Ta}from"rimraf";function jn(){let e=Ea({cwd:Mn($a())});if(!e)throw new Error("Could not find package.json");return Mn(e)}var $a,O,_n,et,Ln,or=S(()=>{"use strict";V();f();$a=()=>typeof import.meta?.url=="string"?ba(import.meta.url):process.cwd(),O=e=>{let t=sr()?g():process.cwd();return wa(t,e)},_n=(e,t)=>{if(!e?.trim())throw new z("Path cannot be empty",e,{hint:"Provide a valid relative path"});if(xa(e))throw new z(`Absolute paths are not allowed: ${e}`,e,{hint:"Use a relative path within the target directory"});if(/^[a-zA-Z]:/.test(e))throw new z(`Windows drive paths are not allowed: ${e}`,e,{hint:"Use a relative path within the target directory"});if(e.replace(/\\/g,"/").split("/").some(a=>a===".."))throw new z(`Path traversal not allowed: ${e}`,e,{hint:"The path must stay within the target directory"});let o=Pa(e),s=Dn(t),i=Dn(t,o);if(!i.startsWith(s+Sa)&&i!==s)throw new z(`Path escapes target directory: ${e}`,e,{hint:"The path must stay within the target directory"});return i},et=e=>{try{return ka(e).length===0}catch{return!0}};Ln=e=>Ta(e)});import Te from"chalk";var Wn,Aa,Ia,tt,d,Hn=S(()=>{"use strict";Wn={debug:0,info:1,warn:2,error:3,silent:4},Aa=e=>e==="debug"||e==="info"||e==="warn"||e==="error"||e==="silent",Ia=()=>{let e=process.env.LOG_LEVEL;return Aa(e)?e:process.env.DEBUG==="true"||process.env.VERBOSE==="true"?"debug":"info"},tt=e=>{let t=Ia();return Wn[e]>=Wn[t]},d={logs:[],breakLine:()=>(console.log(),d),success:(e,...t)=>(console.log(Te.green(`\u2714 ${e}`),...t),d),info:(e,...t)=>(tt("info")&&console.log(Te.cyan(`\u{1F6C8} ${e}`),...t),d),warn:(e,...t)=>(tt("warn")&&console.warn(Te.yellow(`\u26A0\uFE0E ${e}`),...t),d),error:(e,...t)=>(tt("error")&&console.error(Te.red(`\u2716 ${e}`),...t),d),debug:(e,...t)=>(tt("debug")&&console.log(Te.dim(`[debug] ${e}`),...t),d),log:(e,...t)=>(console.log(e,...t),d.logs.push({message:e,context:t.join()}),d),getStoredLogs:e=>e?d.logs.filter(t=>t.context?.includes(e)):d.logs,storeLog:(e,t)=>d.logs.push({message:e,context:t})}});var Gn=S(()=>{"use strict"});import Ra from"chalk";async function M(e,t){let r=Date.now(),n=e.title,o=()=>Math.floor((Date.now()-r)/1e3),s=setInterval(()=>{o()>1&&(e.title=`${n} (${o()}s)`)},1e3);try{return await t(o)}finally{clearInterval(s)}}async function rt(e,t,r){for(let n=0;n<t.length;n++){let o=t[n];e.output=Ra.dim(`[${n+1}/${t.length}] ${o.title}`),await o.fn(r??{},e)}}var Bn=S(()=>{"use strict"});var v=S(()=>{"use strict";bn();Rn();Nn();Fn();On();or();Hn();Gn();nr();Bn()});var Jn={};ia(Jn,{discoverAvailableServices:()=>at,findWorkspaceRoot:()=>g,getContractsConfig:()=>x,getGeneratorConfig:()=>ce,getPackageJsonField:()=>za,getPfConfig:()=>Ie,getPkgJson:()=>cr,getRootPackageScope:()=>st,getWorkspacePackageJson:()=>F,getWorkspacePathsConfig:()=>E,isInWorkspace:()=>sr,pkgJson:()=>R,readPackageConfig:()=>Re,updatePackageJsonField:()=>it});import{existsSync as Ae,readdirSync as Na,readFileSync as Un,writeFileSync as Fa}from"fs";import{join as I,resolve as Oa}from"path";var ar,Ma,Da,_a,$e,ja,ot,nt,La,Wa,zn,Ha,Ga,Vn,sr,g,F,E,Ie,x,st,Ba,Ua,za,it,Re,ir,cr,R,ce,at,f=S(()=>{"use strict";Ze();v();ar=e=>JSON.parse(Un(e,"utf-8")),Ma=ar,Da=(e,t,r)=>Fa(e,`${JSON.stringify(t,null,2)}
|
|
9
|
+
`,"utf-8"),_a=["@crossdelta/cloudevents"],$e={services:"services",apps:"apps",packages:"packages",contracts:"packages/contracts"},ja={docs:{base:["service.md"],frameworks:{}},serviceTypes:{hono:{commandType:"hono-micro",entryPoint:"src/index.ts",skipFiles:[]},nest:{commandType:"nest-micro",entryPoint:"src/main.ts",skipFiles:[]}}},ot=e=>{if(!Ae(e))return null;try{return JSON.parse(Un(e,"utf-8"))}catch{return null}},nt=(e,t)=>typeof e=="string"?e:typeof e=="object"&&e!==null&&"path"in e?e.path:t,La=e=>e.split("/").pop()||"workspace",Wa=e=>{let t=e.slice(0,e.lastIndexOf("/"));return t===e?null:t},zn=e=>e.split("."),Ha=(e,t)=>{if(!e.workspaces)return!1;if(e.pf||Ae(I(t,"turbo.json")))return!0;let r=Sn.some(o=>Ae(I(t,o))),n=Ae(I(t,"infra"));return r&&n},Ga=e=>{let t=ot(I(e,"package.json"));return t?Ha(t,e):!1},Vn=e=>{let t=e;for(;t;){if(Ga(t))return t;t=Wa(t)}return null},sr=()=>Vn(process.cwd())!==null,g=()=>{let e=Vn(process.cwd());if(!e)throw new Error(`
|
|
10
10
|
\x1B[31m\u2716\x1B[0m Not in a workspace directory
|
|
11
11
|
|
|
12
12
|
Current directory: ${process.cwd()}
|
|
@@ -16,35 +16,35 @@ This command must be run from within a workspace created with \x1B[36mpf new wor
|
|
|
16
16
|
To create a new workspace, run:
|
|
17
17
|
|
|
18
18
|
\x1B[36mpf new workspace my-platform\x1B[0m
|
|
19
|
-
`);return e},F=e=>{let t=e??g();return ot(I(t,"package.json"))},E=e=>{let t=F(e);if(!t?.pf?.paths)return $e;let{paths:r}=t.pf;return{services:nt(r.services,$e.services),apps:nt(r.apps,$e.apps),packages:nt(r.packages,$e.packages),contracts:nt(r.contracts,$e.contracts)}},Ie=e=>{let t=F(e);return{plugins:t?.pf?.plugins??
|
|
20
|
-
`,encoding:"utf-8"})},Re=e=>{let t=
|
|
21
|
-
`).filter(Boolean);for(let s of o)try{process.kill(Number.parseInt(s,10),"SIGKILL")}catch{}}catch{}}f();var ct=e=>Ee(e);function dr(e=process.cwd()){let t=r=>
|
|
19
|
+
`);return e},F=e=>{let t=e??g();return ot(I(t,"package.json"))},E=e=>{let t=F(e);if(!t?.pf?.paths)return $e;let{paths:r}=t.pf;return{services:nt(r.services,$e.services),apps:nt(r.apps,$e.apps),packages:nt(r.packages,$e.packages),contracts:nt(r.contracts,$e.contracts)}},Ie=e=>{let t=F(e);return{plugins:t?.pf?.plugins??_a,dev:{filter:t?.pf?.dev?.filter??[]}}},x=e=>{let t=e??g(),r=E(t),n=I(t,r.contracts),s=ot(I(n,"package.json"))?.name??`${st()}/contracts`;return{packagePath:n,eventsPath:I(n,"src","events"),indexPath:I(n,"src","index.ts"),relativePath:r.contracts,packageName:s}},st=()=>{let e=g(),t=ot(I(e,"package.json")),r=`@${La(e)}`;return t?.name?t.name.startsWith("@")?t.name.split("/")[0]:`@${t.name}`:r},Ba=(e,t)=>{let r=zn(t),n=e;for(let o of r){if(n===null||typeof n!="object"||!(o in n))return;n=n[o]}return n},Ua=(e,t,r)=>{let n=zn(t),o=n[n.length-1],s=e;for(let i of n.slice(0,-1))(!(i in s)||typeof s[i]!="object"||s[i]===null)&&(s[i]={}),s=s[i];s[o]=r},za=(e,t=process.cwd())=>{let r=ar(I(t,"package.json"));return Ba(r,e)},it=(e,t,r=process.cwd())=>{let n=I(r,"package.json"),o=ar(n);Ua(o,e,t),Da(n,o,{spaces:2,EOL:`
|
|
20
|
+
`,encoding:"utf-8"})},Re=e=>{let t=jn();return Ma(Oa(t,e))},ir=null,cr=()=>(ir||(ir=Re("package.json")),ir),R=new Proxy({},{get:(e,t)=>cr()[t]}),ce=()=>cr().generatorConfig??ja,at=e=>{let t=e??g(),r=E(t),n=I(t,r.services);if(!Ae(n))return[];try{return Na(n,{withFileTypes:!0}).filter(s=>s.isDirectory()&&!s.name.startsWith(".")).map(s=>`${r.services}/${s.name}`).sort()}catch{return[]}}});import{argv as $u}from"process";import Je from"chalk";import{Command as Au}from"commander";import Iu from"terminal-link";V();f();import cc from"chalk";import{Command as lc}from"commander";v();import{existsSync as rc}from"fs";import{join as nc}from"path";import{cwd as Qn}from"process";import{execaSync as oc}from"execa";v();import{spawn as mr}from"child_process";import{resolve as qa}from"path";import{execa as Ya}from"execa";import{existsSync as Va}from"fs";import{resolve as Ja}from"path";import{config as Ka}from"dotenv";var lr=(e,t)=>{let r=Ja(t,e);return Va(r)?Ka({path:r,processEnv:{}}).parsed||{}:{}},Kn=(e,t)=>{let r=lr(e,t),n=[];for(let[o,s]of Object.entries(r))if(o.endsWith("_PORT")&&s){let i=Number.parseInt(s,10);!Number.isNaN(i)&&i>0&&n.push(i)}return n};var pr={...process.env,NODE_NO_WARNINGS:"1"},Za=(e,t,r)=>e?"pipe":t||r?["ignore","pipe","pipe"]:"inherit",Xa=(e,t,r)=>e?{...pr,...e}:t||r?{...pr,CI:"true"}:{...pr},Qa=e=>e.includes("EEXIST")||e.includes("failed to link package");async function K(e,t,{cwd:r=process.cwd(),task:n,shell:o,context:s=e,quiet:i=!1,nonInteractive:a=!1,env:c}={}){try{t.length===0&&(t=e.split(" ").slice(1));let l=Ya(e,t,{cwd:r,stdio:Za(i,n,a),all:n||a?!0:void 0,shell:o??!0,env:Xa(c,n,a)});l.all&&l.all.on("data",p=>{let m=p.toString().trim();n?(n.output=m,m.length&&d.storeLog(m,s)):a&&m.length&&console.log(m)}),await l}catch(l){let p=l instanceof Error?l.message:String(l);if(Qa(p))return;throw new Error(ec(p))}}var ec=e=>{let t=e.match(/error: (.+)/);return t?t[1].trim():e};function qn(e,t,r={}){let{cwd:n=process.cwd(),envFile:o,detached:s=!0,pipeStdout:i=!1,onStdout:a,onStderr:c,onExit:l}=r,p=o?lr(o,n):{},m=qa(n,"node_modules",".bin"),y=process.env.PATH||"",j=`${m}:${y}`,be={...process.env,...p,PATH:j,FORCE_COLOR:"1"},N=mr(e,t,{cwd:n,env:be,stdio:["inherit",i?"pipe":"inherit","pipe"],detached:s});return a&&i&&N.stdout?.on("data",a),c&&N.stderr?.on("data",c),l&&N.on("exit",l),N}function Yn(e,t,r={}){let{cwd:n=process.cwd()}=r;mr(e,t,{cwd:n,stdio:"inherit"}).on("exit",s=>process.exit(s||0))}function Zn(e,t,r={}){let{cwd:n=process.cwd()}=r,o=t.length>0?`${e} ${t.join(" ")}`:e;mr(o,[],{cwd:n,env:process.env,stdio:"inherit",shell:!0}).on("exit",i=>process.exit(i||0))}async function Xn(e){let{execSync:t}=await import("child_process");for(let r of e)try{let o=t(`lsof -ti:${r}`,{encoding:"utf8",stdio:"pipe"}).trim().split(`
|
|
21
|
+
`).filter(Boolean);for(let s of o)try{process.kill(Number.parseInt(s,10),"SIGKILL")}catch{}}catch{}}f();var ct=e=>Ee(e);function dr(e=process.cwd()){let t=r=>rc(nc(e,r));if(t("bun.lock")||t("bun.lockb"))return"bun";if(t("pnpm-lock.yaml"))return"pnpm";if(t("yarn.lock"))return"yarn";if(t("package-lock.json"))return"npm"}function b(e){return dr(e)??sc()}function sc(){return ct("bun")?"bun":ct("pnpm")?"pnpm":ct("yarn")?"yarn":"npm"}function eo(){return["bun","pnpm","yarn","npm"].filter(ct)}async function L(e,t){let r=ic(e,t),{mergedOptions:n,packages:o}=r,{cwd:s=process.cwd(),flags:i=[],task:a,quiet:c}=n,l=n.packageManager??b(),p=[],m=Array.isArray(o)?o:[o];l==="bun"&&(m=m.map(j=>j.replace("git+ssh://",""))),l==="pnpm"&&(p.push("--config.engine-strict=false"),p.push("--no-frozen-lockfile")),["yarn","npm"].includes(l)&&p.push("--ignore-engines");let y=m.length?l==="npm"?["install",...i,...p,...m]:["add",...i,...p,...m]:["install",...i,...p];await K(l,y,{cwd:s,task:a,quiet:c})}async function to(e){let t=["-g"],r=[...e.flags??[],...t];await L({...e,flags:r,packageManager:e.packageManager??b()})}function ro(e,t,r){let{args:n,mergedOptions:o}=oo(t??[],r),s=o.manager??b(),{command:i,args:a}=no(s);console.log(`
|
|
22
22
|
Running command: ${i} ${[...a,e,...n].join(" ")}
|
|
23
|
-
`),
|
|
23
|
+
`),oc(i,[...a,e,...n],{cwd:o.cwd??Qn(),stdio:"inherit",preferLocal:!0})}async function Ne(e,t,r){let{args:n,mergedOptions:o}=oo(t??[],r),s=o.manager??b(),{command:i,args:a}=no(s);await K(i,[...a,e,...n],o)}async function Fe(e,t){let{script:r,mergedOptions:n}=ac(e,t),o=n.packageManager??b();await K(o,["run",r,...n.args??[]],{cwd:n.cwd??Qn(),task:n.task})}function no(e){let r={bun:"bunx",pnpm:"npx",yarn:"npx",npm:"npx"}[e];if(!r)throw new Error(`No executor found for the detected package manager: ${e}`);let[n,...o]=r.split(" ");return{command:n,args:o}}function ic(e,t){return Array.isArray(e)?{packages:e,mergedOptions:{...t,packages:e}}:{packages:e.packages??[],mergedOptions:e}}function oo(e,t){return Array.isArray(e)?{args:e,mergedOptions:t??{}}:{args:[],mergedOptions:e}}function ac(e,t){return typeof e=="string"?{script:e,mergedOptions:t??{}}:{script:e.script,mergedOptions:e}}var pc=e=>e==="yarn"?["npm","audit"]:["audit"],so=new lc("audit").description("Run security audit on dependencies").allowUnknownOption(!0).action((e,t)=>{try{let r=g(),n=b(),o=pc(n),s=t.args||[];console.log(cc.dim(`Running ${n} ${[...o,...s].join(" ")}`)),Yn(n,[...o,...s],{cwd:r})}catch(r){$(r)}});import q from"chalk";import{existsSync as Sc,readFileSync as bc,writeFileSync as Ec}from"fs";import{homedir as Tc}from"os";import{join as $c}from"path";import{createCipheriv as mc,createDecipheriv as dc,createHash as gc,randomBytes as uc}from"crypto";import{existsSync as fc,readFileSync as hc,writeFileSync as yc}from"fs";import{homedir as io,hostname as vc,userInfo as Cc}from"os";import{join as kc}from"path";var gr=kc(io(),".platform-sdk-keys"),ao="aes-256-gcm",co=()=>{let e=`${vc()}:${Cc().username}:${io()}`;return gc("sha256").update(e).digest()},lo=()=>{if(!fc(gr))return{};try{return JSON.parse(hc(gr,"utf-8"))}catch{return{}}},xc=e=>{yc(gr,JSON.stringify(e,null,2),{mode:384})},wc=e=>{let t=co(),r=uc(16),n=mc(ao,t,r),o=n.update(e,"utf8","hex");return o+=n.final("hex"),{iv:r.toString("hex"),tag:n.getAuthTag().toString("hex"),data:o}},Pc=e=>{let t=co(),r=Buffer.from(e.iv,"hex"),n=Buffer.from(e.tag,"hex"),o=dc(ao,t,r);o.setAuthTag(n);let s=o.update(e.data,"hex","utf8");return s+=o.final("utf8"),s};async function po(e,t){let r=lo();r[e]=wc(t),xc(r)}async function lt(e){let r=lo()[e];if(!r)return null;try{return Pc(r)}catch{return null}}var Oe={openai:{id:"openai",name:"OpenAI",defaultApiKeyEnvVar:"OPENAI_API_KEY",defaultModel:"gpt-4o-mini",modelsApiUrl:"https://api.openai.com/v1/models",apiKeyUrl:"https://platform.openai.com/api-keys",buildHeaders:e=>({Authorization:`Bearer ${e}`}),parseModelsResponse:e=>e.data??[],modelFilters:[/^gpt-4/,/^gpt-3\.5/,/^o1/,/^o3/]},anthropic:{id:"anthropic",name:"Anthropic (Claude)",defaultApiKeyEnvVar:"ANTHROPIC_API_KEY",defaultModel:"claude-sonnet-4-20250514",modelsApiUrl:"https://api.anthropic.com/v1/models",apiKeyUrl:"https://console.anthropic.com/settings/keys",buildHeaders:e=>({"x-api-key":e,"anthropic-version":"2023-06-01"}),parseModelsResponse:e=>(e.data??[]).map(r=>({id:r.id,created:new Date(r.created_at).getTime()})),modelFilters:[/^claude-/]}};function mo(){return Object.entries(Oe).map(([e,t])=>({name:t.name,value:e}))}function Me(e){let t=Oe[e];if(!t)throw new Error(`Unknown AI provider: ${e}`);return t}var Q=$c(Tc(),".platform-sdk-ai.json"),Ac=()=>{let e="anthropic",t=Oe[e];return{provider:e,model:t.defaultModel}},ur=Ac();function De(){return Sc(Q)}function pt(){if(!De())throw new Error("AI configuration not found. Please run 'pf ai:setup' to configure your AI provider.");try{let e=bc(Q,"utf-8"),t=JSON.parse(e);return{...ur,...t}}catch{throw new Error(`Failed to load AI configuration from ${Q}. Please run 'pf setup --ai' again.`)}}function go(e){let t=JSON.stringify(e,null,2);Ec(Q,t,"utf-8")}async function uo(e,t){await po(e,t)}async function fo(e){let t=await lt(e.provider);if(t)return t;let r=Oe[e.provider],n=process.env[r.defaultApiKeyEnvVar];if(n)return n;throw new Error("API key not found. Please run 'pf setup --ai' to configure your API key.")}var Ic=async(e,t,r,n)=>{let{createOpenAI:o}=await import("@ai-sdk/openai"),s=o({apiKey:r});if(n.onToken){let{streamText:c}=await import("ai"),l=c({model:s(t),prompt:e,system:n.system,maxOutputTokens:n.maxTokens,temperature:n.temperature}),p="";for await(let m of(await l).textStream)p+=m,n.onToken(m);return p}let{generateText:i}=await import("ai"),{text:a}=await i({model:s(t),prompt:e,system:n.system,maxOutputTokens:n.maxTokens,temperature:n.temperature});return a},Rc=async(e,t,r,n)=>{let{createAnthropic:o}=await import("@ai-sdk/anthropic"),s=o({apiKey:r});if(n.onToken){let{streamText:c}=await import("ai"),l=c({model:s(t),prompt:e,system:n.system,maxOutputTokens:n.maxTokens,temperature:n.temperature}),p="";for await(let m of(await l).textStream)p+=m,n.onToken(m);return p}let{generateText:i}=await import("ai"),{text:a}=await i({model:s(t),prompt:e,system:n.system,maxOutputTokens:n.maxTokens,temperature:n.temperature});return a};async function ho(e,t,r={}){let{system:n,maxTokens:o=4096,temperature:s=.7,onToken:i}=r,a=await fo(e);switch(e.provider){case"openai":return Ic(t,e.model,a,{system:n,maxTokens:o,temperature:s,onToken:i});case"anthropic":return Rc(t,e.model,a,{system:n,maxTokens:o,temperature:s,onToken:i});default:throw new Error(`Unsupported AI provider: ${e.provider}`)}}V();import{existsSync as Qo,readFileSync as op,unlinkSync as sp,writeFileSync as ip}from"fs";import{join as es,resolve as Zo}from"path";import{input as ap}from"@inquirer/prompts";import h from"chalk";import cp from"ora";import{existsSync as fr,readdirSync as Oc}from"fs";import{dirname as Mc,join as yo}from"path";import{dirname as Nc}from"path";import{fileURLToPath as Fc}from"url";var W=e=>Nc(Fc(e));rr();var Dc=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),ee=e=>{let t=e??Dc(),r=o=>fr(yo(o,"package.json")),n=Mc(t);if(r(t))return t;if(t==="/")throw new Error("Could not find package.json (package root)");return ee(n)},vo=(e,t)=>{let r=e.find(fr);if(!r)throw new Error(t??`Directory not found. Searched in: ${e.join(", ")}`);return r},Co=async e=>{let{getWorkspacePathsConfig:t}=await Promise.resolve().then(()=>(f(),Jn)),r=t(e);return[r.services,r.apps].flatMap(o=>{let s=yo(e,o);if(!fr(s))return[];try{return Oc(s,{withFileTypes:!0}).filter(i=>i.isDirectory()&&i.name!==".gitkeep").map(i=>`${o}/${i.name}`)}catch{return[]}})};import{existsSync as il,readFileSync as al}from"fs";import{join as cl}from"path";import{Project as ll}from"ts-morph";import{deriveEventNames as _y,getContractPaths as jy,getStreamName as Ly}from"@crossdelta/cloudevents";import{existsSync as mt,readFileSync as ko,writeFileSync as _c}from"fs";import{join as hr}from"path";import{getStreamName as jc}from"@crossdelta/cloudevents";var xo=(e,t)=>{let r=hr(e,"src","index.ts");if(!mt(r))return!1;let n=ko(r,"utf-8"),o=t.toLowerCase();return new RegExp(`streams:\\s*\\[[^\\]]*['"]${t}['"]`).test(n)||n.includes(`stream: '${t}'`)?!0:new RegExp(`subjects:\\s*\\[.*['"]${o}\\.[*>]`).test(n)},Lc=e=>{if(e.includes("@crossdelta/cloudevents"))return e;let t=`import { consumeJetStreams } from '@crossdelta/cloudevents'
|
|
24
24
|
`,r=e.match(/import\s+['"]@crossdelta\/telemetry['"]\s*\n/);if(r){let o=(r.index??0)+r[0].length;return`${e.slice(0,o)}
|
|
25
|
-
${t}${e.slice(o)}`}let n=e.match(/import\s+.*\n/);if(n){let o=(n.index??0)+n[0].length;return e.slice(0,o)+t+e.slice(o)}return e},
|
|
25
|
+
${t}${e.slice(o)}`}let n=e.match(/import\s+.*\n/);if(n){let o=(n.index??0)+n[0].length;return e.slice(0,o)+t+e.slice(o)}return e},Wc=(e,t)=>`
|
|
26
26
|
|
|
27
27
|
// Consume from ${e} stream
|
|
28
28
|
consumeJetStreams({
|
|
29
29
|
streams: ['${e}'],
|
|
30
30
|
consumer: '${t}-service',
|
|
31
31
|
discover: './src/events/**/*.handler.ts',
|
|
32
|
-
})`,yr=(e,t)=>{let r=
|
|
33
|
-
`;return
|
|
32
|
+
})`,yr=(e,t)=>{let r=jc(t),n=hr(e,"src","index.ts"),o=hr(e,"src","main.ts");if(!mt(n)&&mt(o))return{added:!1,streamName:r};if(!mt(n))return{added:!1,streamName:r,warning:"Entry point not found (index.ts or main.ts)"};if(xo(e,r))return{added:!1,streamName:r};let s=ko(n,"utf-8"),i=e.split("/").pop()||"unknown";s.includes("consumeJetStreams")||(s=Lc(s));let a=Wc(r,i),c=`${s.trimEnd()+a}
|
|
33
|
+
`;return _c(n,c,"utf-8"),{added:!0,streamName:r}};f();import{existsSync as Xh,readFileSync as Qh}from"fs";import{join as ty}from"path";import{contractCreated as ny,deriveEventNames as oy,generateContract as sy,getContractFilePath as iy}from"@crossdelta/cloudevents";import{readdirSync as Hc,readFileSync as Gc}from"fs";import{join as wo}from"path";import{getStreamName as Bc,singularize as Uc}from"@crossdelta/cloudevents";var Po=e=>{try{return Hc(e,{withFileTypes:!0}).flatMap(r=>{let n=wo(e,r.name);return r.isDirectory()?Po(n):r.name.endsWith(".handler.ts")?[n]:[]})}catch{return[]}},vr=e=>{let t=wo(e,"src","events");return Po(t).flatMap(n=>{let o=Gc(n,"utf-8");return zc(n,o)})},zc=(e,t)=>{let r=Jc(t);if(!r)return[];let n=Vc(r);return n?[{filePath:e,eventType:n,contractName:r}]:[]},Vc=e=>{let r=e.replace(/Contract$/,"").match(/[A-Z][a-z]*/g);if(!r||r.length<2)return null;let n=r[0].toLowerCase(),o=Uc(n),i=r.slice(1).map(a=>a.toLowerCase()).join("-");return`${o}.${i}`},Jc=e=>{let r=/import\s+{([^}]+)}\s+from\s+['"]@[\w-]+\/contracts['"]/.exec(e);return r?r[1].split(",").map(s=>s.trim()).filter(s=>s.endsWith("Contract")).map(s=>s.replace(/\s+as\s+.+$/,"").trim()).at(0)??null:null},Cr=e=>{let t=e.reduce((r,n)=>{let o=n.eventType.split(".")[0],s=r.get(o)??[];return r.set(o,[...s,n]),r},new Map);return Array.from(t.entries()).map(([r,n])=>Kc(r,n)).sort((r,n)=>r.stream.localeCompare(n.stream))},Kc=(e,t)=>{let r=Bc(t[0]?.eventType??`${e}.event`),n=`${e}.>`;return{stream:r,subjects:[n],handlers:t}},kr=(e,t)=>e.length===0?"":` // Development: pf dev auto-creates ephemeral streams from contracts
|
|
34
34
|
// Production: Pulumi materializes persistent streams
|
|
35
35
|
|
|
36
36
|
consumeJetStreams({
|
|
37
37
|
streams: [${e.map(r=>`'${r.stream}'`).join(", ")}],
|
|
38
38
|
consumer: '${t}',
|
|
39
39
|
discover: './src/events/**/*.handler.ts',
|
|
40
|
-
})`;f();import{existsSync as te,mkdirSync as
|
|
41
|
-
* ${
|
|
40
|
+
})`;f();import{existsSync as te,mkdirSync as qc,readFileSync as dt,writeFileSync as pe}from"fs";import{dirname as So,join as le}from"path";import{deriveEventNames as Yc}from"@crossdelta/cloudevents";var Zc=(e,t)=>{let r=`export * from './${t}'`;if(!te(e)){let s=So(e);te(s)||qc(s,{recursive:!0});let i=`/**
|
|
41
|
+
* ${So(e).split("/").pop()} Domain Events
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
44
|
`;return pe(e,`${i+r}
|
|
45
45
|
`,"utf-8"),!0}let n=dt(e,"utf-8");if(n.includes(`'./${t}'`))return!1;let o=`${n.trimEnd()}
|
|
46
46
|
${r}
|
|
47
|
-
`;return pe(e,o,"utf-8"),!0},
|
|
47
|
+
`;return pe(e,o,"utf-8"),!0},Xc=(e,t)=>{let r=`export * from './${t}'`;if(!te(e))return pe(e,`/**
|
|
48
48
|
* Event Contracts Index
|
|
49
49
|
*
|
|
50
50
|
* Re-exports all event contracts for convenient importing.
|
|
@@ -53,17 +53,17 @@ ${r}
|
|
|
53
53
|
${r}
|
|
54
54
|
`,"utf-8"),!0;let o=dt(e,"utf-8").split(`
|
|
55
55
|
`);if(o.some(i=>i.trim()===r))return!1;let s=o.findLastIndex(i=>i.startsWith("export"));return s>=0?o.splice(s+1,0,r):o.push(r),pe(e,o.join(`
|
|
56
|
-
`),"utf-8"),!0},
|
|
56
|
+
`),"utf-8"),!0},Qc=e=>{if(!te(e))return!1;let t=dt(e,"utf-8"),r="export * from './events'";if(t.split(`
|
|
57
57
|
`).some(s=>s.trim()===r||s.trim().startsWith(r)))return!1;let o=t;return o=o.replace(/\/\/\s*export \* from '\.\/events'/,r),o=o.replace(/\/\/\s*export \* from '\.\/stream-policies'/,"export * from './stream-policies'"),/export \* from '\.\/events\/\w+\/\w+'/.test(o)&&(o=o.replace(/export \* from '\.\/events\/\w+\/\w+'\n?/g,"")),o.includes(r)||(o=`${o.trimEnd()}
|
|
58
58
|
${r}
|
|
59
|
-
`),o!==t?(pe(e,o,"utf-8"),!0):!1},xr=(e,t)=>{let{packagePath:r}=x(t),{domain:n,action:o}=
|
|
59
|
+
`),o!==t?(pe(e,o,"utf-8"),!0):!1},xr=(e,t)=>{let{packagePath:r}=x(t),{domain:n,action:o}=Yc(e),s=le(r,"src","events");if(!te(s))return!1;let i=le(s,n),a=le(i,"index.ts"),c=le(s,"index.ts"),l=le(r,"src","index.ts"),p=e.split(".")[0],m=le(s,p);p!==n&&te(m)&&(console.warn(`\u26A0\uFE0F Warning: Legacy folder '${p}/' found. Please migrate to '${n}/' to avoid conflicts.`),console.warn(` Run: mv ${m} ${i}`));let y=!1;return Zc(a,o)&&(y=!0),Xc(c,n)&&(y=!0),Qc(l)&&(y=!0),y},wr=(e,t)=>{if(!te(e))return!1;let r=`export * from './events/${t}'`,n=dt(e,"utf-8");if(n.includes(`'./events/${t}'`))return!1;let o=n.split(`
|
|
60
60
|
`),s=o.findLastIndex(i=>i.startsWith("export"));return s>=0?o.splice(s+1,0,r):o.push("",r),pe(e,o.join(`
|
|
61
|
-
`),"utf-8"),!0};f();import{existsSync as
|
|
61
|
+
`),"utf-8"),!0};f();import{existsSync as bo,readdirSync as tl,readFileSync as rl}from"fs";import{join as Eo}from"path";import{generateJsonMockFromContract as nl,getJsonMockPath as ol,initFaker as sl}from"@crossdelta/cloudevents";var To=e=>{let t=e.match(/handleEvent\s*\(\s*(\w+Contract)/m);if(t){let n=e.match(/type:\s*['"]([^'"]+)['"]/m);if(n)return n[1]}let r=e.match(/handleEvent\s*\(\s*\{[^}]*type:\s*['"]([^'"]+)['"]/m);if(r)return r[1];if(t){let s=t[1].replace(/Contract$/,"").split(/(?=[A-Z])/).filter(Boolean);if(s.length>=2){let i=s[0].toLowerCase(),a=s.slice(1).join("").toLowerCase();return`${i}.${a}`}}return null};var Pr=async(e,t={})=>{let r=Eo(e,"src","events");if(!bo(r))return{mockPaths:[],skippedHandlers:[]};await sl();let n=tl(r).filter(i=>i.endsWith(".handler.ts")||i.endsWith(".event.ts")),o=[],s=[];for(let i of n){let a=Eo(r,i),c=rl(a,"utf-8"),l=To(c);if(!l){s.push(`${i} (Could not extract event type)`);continue}let p=t.outputDir??x().packagePath,m=ol(l,p);if(bo(m)&&!t.overwrite){s.push(`${i} (Mock already exists)`);continue}let y=nl(l,p,{useFaker:!0});y&&y.status!=="skipped"&&"ref"in y?o.push(y.ref):s.push(`${i} (Contract not found or generation failed)`)}return{mockPaths:o,skippedHandlers:s}};var $o=e=>{let t=e.split("/").pop()||"service",r=cl(e,"src","events","events.service.ts");if(!il(r))return!1;let n=vr(e);if(n.length===0||al(r,"utf-8").replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"").includes("consumeJetStreams"))return!1;let a=Cr(n),c=kr(a,t);if(!c)return!1;let l=new ll({skipAddingFilesFromTsConfig:!0,skipFileDependencyResolution:!0}),p=l.addSourceFileAtPath(r),m=!1;for(let y of p.getClasses()){let j=y.getMethod("startConsumers");if(!j)continue;let N=[...c.split(`
|
|
62
62
|
`),""," this.logger.log('Event consumers started successfully')"].join(`
|
|
63
|
-
`);j.setBodyText(N),m=!0;break}return m&&l.saveSync(),m};f();var
|
|
64
|
-
`));for(let r of e)console.log(G.dim(` ${t}/contracts \u2192 ${r}`));console.log()}},
|
|
63
|
+
`);j.setBodyText(N),m=!0;break}return m&&l.saveSync(),m};f();var pl=e=>{let t=e.split(/\s+/),r=t[0],n=t.slice(1);return r==="pf"&&(r=process.argv[1]),{executable:r,args:n}},ml=async(e,t)=>{try{let{executable:r,args:n}=pl(e.command);return await K(r,n,{cwd:t,shell:!1}),{command:e.command,success:!0}}catch(r){return{command:e.command,success:!1,error:r instanceof Error?r.message:String(r)}}},Sr=async(e,t)=>{let r=[];for(let n of e){let o=await ml(n,t);if(r.push(o),!o.success)break}return r},br=e=>{let t=[/^pf\s+/,/^bun\s+pf\s+/,/^npx\s+pf\s+/,/^bunx\s+pf\s+/];return e.filter(r=>t.some(n=>n.test(r.command)))},Ao=e=>{for(let t of e){let r=t.command.match(/(?:bun\s+)?pf\s+new\s+\S+\s+(\S+)/);if(r)return r[1]}return null};import{existsSync as No,readFileSync as hl}from"fs";import{join as Er}from"path";import G from"chalk";f();or();import{existsSync as Io,mkdirSync as dl,writeFileSync as gl}from"fs";import{dirname as ul}from"path";var fl=(e,t)=>{let n=e.path.startsWith("packages/")&&t.workspaceRoot?t.workspaceRoot:t.baseDir,o;try{o=_n(e.path,n)}catch(s){return{status:"failed",path:e.path,error:s.message}}try{if(Io(o)&&!t.overwrite)return{status:"skipped",path:e.path};if(t.dryRun)return{status:"written",path:e.path};let s=ul(o);return Io(s)||dl(s,{recursive:!0}),gl(o,e.content,"utf-8"),{status:"written",path:e.path}}catch(s){return{status:"failed",path:e.path,error:s.message}}},Ro=(e,t)=>{let r=e.map(n=>fl(n,t));return{written:r.filter(n=>n.status==="written").map(n=>n.path),skipped:r.filter(n=>n.status==="skipped").map(n=>n.path),failed:r.filter(n=>n.status==="failed").map(n=>({path:n.path,error:n.error}))}};var yl=(e,t)=>{let r=E(t.workspaceRoot),n=Er(t.workspaceRoot,r.contracts);if(!No(n))return[];let o=/import\s+(?:type\s+)?{([^}]+)}\s+from\s+['"]@\w+\/contracts['"]/g,s=new Set;for(let i of e){let a=i.content.matchAll(o);for(let c of a){let p=c[1].split(",").map(m=>m.trim()).map(m=>m.replace(/^type\s+/,"").replace(/\s+as\s+.+$/,"").trim()).filter(m=>m.endsWith("Contract"));for(let m of p)s.add(m)}}return Array.from(s).sort()},vl=e=>{let t=Er(e,"packages/contracts/src/index.ts");if(!No(t))return new Set;try{let r=hl(t,"utf-8"),n=new Set,o=/export\s+(?:\*|{[^}]*Contract[^}]*})\s+from\s+['"]\.\/events\/([^'"]+)['"]/g,s=r.matchAll(o);for(let i of s){let a=i[0],c=/(\w+Contract)/g,l=a.matchAll(c);for(let p of l)n.add(p[1])}return n}catch{return new Set}},Cl=e=>{let t=e.replace(/Contract$/,""),r=t.split(/(?=[A-Z])/).filter(Boolean);if(r.length<2)return t.toLowerCase();let n=r[0].toLowerCase(),o=r.slice(1).join("").toLowerCase();return`${n}.${o}`},kl=(e,t,r)=>{let n=vl(t),o=[],s=[],i=[];for(let a of e)if(n.has(a))o.push(a);else{s.push(a);let c=Cl(a),l=r.replace(`${t}/`,"");i.push(`pf cloudevents add ${c} --service ${l}`)}return{existing:o,missing:s,suggestedCommands:i}},xl=(e,t)=>{if(e.length!==0){console.log(G.cyan(`\u{1F4E6} Using existing contracts:
|
|
64
|
+
`));for(let r of e)console.log(G.dim(` ${t}/contracts \u2192 ${r}`));console.log()}},wl=(e,t)=>{let r=/^packages\/contracts\/src\/events\/([^/]+)\.ts$/,n=Er(t,"packages/contracts/src/index.ts");for(let o of e){let s=o.match(r);s&&s[1]!=="index"&&wr(n,s[1])}},Fo=async(e,t)=>{t.start("Applying code formatting...");try{await Ne("biome",["check","--fix","--unsafe","."],{cwd:e,quiet:!0}),t.succeed("Code formatted!")}catch{t.warn("Code formatting completed with warnings")}},Pl=async(e,t)=>{t.start("Scanning for event handlers...");let{mockPaths:r,skippedHandlers:n}=await Pr(e);if(r.length+n.length===0){t.info("No event handlers found");return}if(r.length>0){t.succeed(`Generated ${r.length} event ${r.length===1?"mock":"mocks"}`),console.log();for(let s of r){let i=s.replace(`${e}/`,"");console.log(G.dim(` ${i}`))}console.log()}else t.succeed("Event handlers found");if(n.length>0){for(let s of n)console.log(G.dim(` \u2139 Skipped: ${s}`));console.log()}},Oo=async(e,t,r,n)=>{n.start("Writing generated files...");let o=Ro(e,{baseDir:t,workspaceRoot:r.workspaceRoot,overwrite:!0});if(o.written.length>0){n.succeed(`Created ${o.written.length} files`),console.log();for(let l of o.written)console.log(G.dim(` ${l}`));console.log()}else n.succeed("No files to write");let s=yl(e,r),{existing:i,missing:a,suggestedCommands:c}=kl(s,r.workspaceRoot,t);if(i.length>0&&xl(i,r.scope),a.length>0){console.log(G.yellow(`\u26A0\uFE0F Missing contracts (not exported from @${r.scope}/contracts):
|
|
65
65
|
`));for(let l of a)console.log(G.yellow(` ${l}`));console.log(),console.log(G.cyan(`\u{1F4A1} Run these commands to create the missing contracts:
|
|
66
|
-
`));for(let l of c)console.log(G.dim(` ${l}`));console.log()}return
|
|
66
|
+
`));for(let l of c)console.log(G.dim(` ${l}`));console.log()}return wl(o.written,r.workspaceRoot),o.written.length>0&&await Pl(t,n),{missingContractCommands:c}};f();import{existsSync as Rl,readFileSync as Nl}from"fs";import{join as _e}from"path";f();f();import{existsSync as Sl,readdirSync as bl,readFileSync as El}from"fs";import{join as Tl}from"path";var Mo=e=>{let{eventsPath:t}=x(e);if(!Sl(t))return[];let r=[];try{let n=bl(t).filter(o=>o.endsWith(".ts")&&!o.endsWith(".mock.json")&&o!=="index.ts");for(let o of n){let s=Tl(t,o),i=El(s,"utf-8"),a=$l(i,s);a&&r.push(a)}}catch(n){return console.warn("Warning: Could not scan contracts package:",n),[]}return r},$l=(e,t)=>{try{let r=e.match(/export const (\w+Contract) = createContract/);if(!r)return null;let n=r[1],o=e.match(/export type (\w+(?:Data|Event)) = z\.infer/);if(!o)return null;let s=o[1],i=e.match(/type:\s*['"]([^'"]+)['"]/);if(!i)return null;let a=i[1],c=Il(e);return{name:n,typeName:s,eventType:a,fields:c,filePath:t}}catch{return null}},Al={string:"string",number:"number",boolean:"boolean",array:"array",object:"object",date:"date"},Il=e=>{let t=e.match(/z\.object\({([^}]+)\}/);if(!t)return[];let r=t[1],n=/(\w+):\s*z\.(\w+)\([^)]*\)/g,o=[...r.matchAll(n)].map(([,a,c])=>{let l=Al[c]||c;return`${a}: ${l}`});if(!e.includes("z.array("))return o;let s=/(\w+):\s*z\.array\(/g,i=[...e.matchAll(s)].map(([,a])=>a).filter(a=>!o.some(c=>c.startsWith(a))).map(a=>`${a}: array`);return[...o,...i]},Do=(e,t)=>{if(e.length===0)return`
|
|
67
67
|
**Available Contracts:**
|
|
68
68
|
|
|
69
69
|
No contracts are currently defined. Use Basic Mode with inline schemas for all events.
|
|
@@ -84,15 +84,15 @@ The following event contracts are available in \`${t}/contracts\`:
|
|
|
84
84
|
${r}
|
|
85
85
|
|
|
86
86
|
If the event type your service consumes matches one of these, **you MUST use Advanced Mode**.
|
|
87
|
-
`.trim()};var
|
|
87
|
+
`.trim()};var Fl=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),Ol=(e,t)=>{let r=_e(Fl(),"docs","generators"),n=ce(),o=[];for(let s of n.docs.base)o.push(_e(r,s));if(e&&n.docs.frameworks[e]){let s=n.docs.frameworks[e];if(typeof s=="string")o.push(_e(r,s));else{let i=t==="bun"?"bun":"node";s[i]&&o.push(_e(r,s[i]))}}return o},Ml=["CLAUDE.md","AGENTS.md",".github/copilot-instructions.md","docs/ai-guidelines.md"],_o=1500,jo=50,Lo=e=>{try{return Rl(e)?Nl(e,"utf-8"):null}catch{return null}},Dl=e=>e.replace(/<!--[\s\S]*?-->/g,"").replace(/^\[.+\]:\s*.+$/gm,"").replace(/\n{3,}/g,`
|
|
88
88
|
|
|
89
|
-
`).replace(/[ \t]+$/gm,"").trim(),
|
|
89
|
+
`).replace(/[ \t]+$/gm,"").trim(),_l=e=>e.replace(/<!--[\s\S]*?-->/g,"").replace(/^\[.+\]:\s*.+$/gm,"").replace(/```[\s\S]*?```/g,"").replace(/`[^`]{50,}`/g,"`...`").replace(/\n{3,}/g,`
|
|
90
90
|
|
|
91
|
-
`).replace(/[ \t]+$/gm,"").trim(),
|
|
91
|
+
`).replace(/[ \t]+$/gm,"").trim(),jl=e=>Math.ceil(e.length/4),Ll=(e,t)=>{let r=e.split(/(?=^## )/m),n="",o=0;for(let s of r){let i=jl(s);if(o+i<=t)n+=s,o+=i;else if(o===0){n=s.slice(0,t*4);break}else break}return n.trim()},Wl=(e,t)=>{let{workspaceRoot:r,scope:n}=t,o=Mo(r),s=Do(o,n);return e.replace(/\{\{scope\}\}/g,n).replace(/\{\{AVAILABLE_CONTRACTS\}\}/g,s)},Wo=e=>{let{workspaceRoot:t,scope:r}=e,n=[],o=Ol(e.serviceType,e.packageManager);for(let a of o){let c=Lo(a);if(c){let l=Wl(c,e),p=Dl(l);n.push(p)}}let s=[...new Set(Ml.map(a=>Lo(_e(t,a))).filter(a=>a!==null).map(_l).filter(a=>a.length>jo))],i=s.length?Math.floor(_o/s.length):_o;for(let a of s){let c=Ll(a,i);c.length>jo&&n.push(c)}return n.length===0?(console.warn("\u26A0\uFE0F No instruction files found."),`Use ${r}/contracts for shared types.`):n.join(`
|
|
92
92
|
|
|
93
93
|
---
|
|
94
94
|
|
|
95
|
-
`)};var
|
|
95
|
+
`)};var Hl=`You are an expert code generator. Generate clean, production-ready code.
|
|
96
96
|
|
|
97
97
|
## Output Format
|
|
98
98
|
|
|
@@ -106,13 +106,13 @@ Format your code blocks with the file path on the line before the code block:
|
|
|
106
106
|
**IMPORTANT:** Always generate:
|
|
107
107
|
- Source code files (src/**)
|
|
108
108
|
- Test files (src/**/*.test.ts) for all business logic
|
|
109
|
-
- README.md with service documentation`,
|
|
109
|
+
- README.md with service documentation`,Gl=e=>e.replace(/-/g,"_").toUpperCase(),Bl=e=>e.split("/").pop()||"my-service",Ho=(e,t,r)=>{let n=Wo({...e,serviceType:t,packageManager:r});return`${Hl}
|
|
110
110
|
|
|
111
111
|
## Project Guidelines & Patterns
|
|
112
112
|
|
|
113
113
|
Follow these project-specific conventions and patterns when generating code:
|
|
114
114
|
|
|
115
|
-
${n}`},
|
|
115
|
+
${n}`},Go=(e,t,r,n)=>{let o=Bl(e),s=`${Gl(o)}_PORT`,i=st();return`Generate source code for a microservice at path "${e}".
|
|
116
116
|
|
|
117
117
|
Use the patterns and conventions from the Project Guidelines above.
|
|
118
118
|
|
|
@@ -127,11 +127,11 @@ Service purpose: ${t}
|
|
|
127
127
|
- BUT you MUST keep the existing port configuration line unchanged!
|
|
128
128
|
|
|
129
129
|
Do NOT include the service path in file headers (use \`src/...\`, NOT \`${e}/src/...\`).
|
|
130
|
-
`};var
|
|
131
|
-
`).map(o=>o.trim()).filter(o=>o.length>0&&!o.startsWith("#"))),
|
|
132
|
-
`),r=[],n=0;for(let o of t){let s=gt.fileHeader.exec(o);s&&r.push({path:s[1],index:n}),n+=o.length+1}return r},
|
|
130
|
+
`};var Ul=()=>!!process.env.DEBUG,Bo=(e,t)=>{Ul()&&console.log(`[AI Parser] ${e}`,t??"")},gt={commandsBlock:/```commands\n([\s\S]*?)```/gi,postCommandsBlock:/```post-commands\n([\s\S]*?)```/gi,dependenciesBlock:/```dependencies\n([\s\S]*?)```/gi,fileHeader:/^#{1,4}\s+`([^`]+)`\s*$/},$r=(e,t)=>[...e.matchAll(t)].flatMap(n=>n[1].split(`
|
|
131
|
+
`).map(o=>o.trim()).filter(o=>o.length>0&&!o.startsWith("#"))),Uo=e=>({command:e,isPfCommand:e.startsWith("pf ")||e.includes(" pf ")}),zl=e=>$r(e,gt.commandsBlock).map(Uo),Vl=e=>$r(e,gt.postCommandsBlock).map(Uo),Jl=e=>$r(e,gt.dependenciesBlock).filter(t=>!t.startsWith("@crossdelta/")&&t!=="zod"),Kl=e=>{let t={ts:"typescript",js:"javascript",md:"markdown",yml:"yaml"},r=(e||"typescript").toLowerCase();return t[r]||r},ql=e=>{let t=e.split(".").pop()?.toLowerCase();return{ts:"typescript",tsx:"typescript",js:"javascript",jsx:"javascript",json:"json",yaml:"yaml",yml:"yaml",md:"markdown"}[t||""]||"plaintext"},Yl=e=>e.replace(/^\s*\/\/ \.{3,}.*$/gm,"").replace(/^\s*\/\/ Lines? \d+.*omitted.*$/gim,"").replace(/^\s*\/\* Lines? \d+.*omitted.*\*\/$/gim,"").trim(),Zl=e=>{let t=e.split(`
|
|
132
|
+
`),r=[],n=0;for(let o of t){let s=gt.fileHeader.exec(o);s&&r.push({path:s[1],index:n}),n+=o.length+1}return r},Xl=(e,t)=>{let n=e.slice(t).match(/```(\w+)?\n([\s\S]*?)```/);return n?{language:n[1]?Kl(n[1]):void 0,content:Yl(n[2])}:null},Ql=e=>Zl(e).map(r=>{let n=Xl(e,r.index);return!n||n.content.length===0?null:{path:r.path,language:n.language||ql(r.path),content:n.content,startIndex:r.index}}).filter(r=>r!==null),Tr=e=>e.includes("packages/contracts")||e.includes("contracts/src"),ep=e=>{let t=e.filter(n=>Tr(n.path)),r=e.filter(n=>!Tr(n.path));return[...t,...r]},tp=e=>{let t=e.replace(/^\/+/,"").replace(/\/{2,}/g,"/");if(Tr(t))return t;let r=t.match(/^services\/[^/]+\/(.+)$/);return r?r[1]:t},zo=(e,t)=>{Bo("Parsing AI response",{length:e.length});let r=zl(e),n=Vl(e),o=Jl(e),s=Ql(e),i=ep(s.map(a=>({path:tp(a.path),content:a.content,language:a.language})));return Bo("Parsed response",{commands:r.length,postCommands:n.length,dependencies:o.length,files:i.length}),{commands:r,files:i,dependencies:o,postCommands:n}},Vo=e=>{let t=e.filter(s=>!s.content||s.content.trim().length===0),r=e.length===0?["No files could be extracted from the AI response"]:t.map(s=>`File ${s.path} is empty`),n=e.some(s=>["src/index.ts","src/main.ts","index.ts"].includes(s.path)),o=e.length>0&&!n?["No entry point file (src/index.ts or src/main.ts) found - assuming it exists from scaffolding"]:[];return{valid:r.length===0,errors:r,warnings:o}};import{mkdirSync as rp}from"fs";import H from"chalk";var Jo=async(e,t,r)=>{if(e.length===0){rp(t,{recursive:!0}),console.log(H.yellow(`\u26A0 No scaffolding command found - creating empty directory
|
|
133
133
|
`));return}let o=(await Sr(e,r)).find(s=>!s.success);if(o)throw console.log(H.red(`
|
|
134
|
-
\u2717 Scaffolding failed: ${o.command}`)),o.error&&console.log(H.red(` Error: ${o.error}`)),new Error(`Command failed: ${o.command}${o.error?` - ${o.error}`:""}`)},
|
|
134
|
+
\u2717 Scaffolding failed: ${o.command}`)),o.error&&console.log(H.red(` Error: ${o.error}`)),new Error(`Command failed: ${o.command}${o.error?` - ${o.error}`:""}`)},Ko=async(e,t,r)=>{if(e.length===0)return;r.stop();let n=e.length===1?"package":"packages";console.log(H.cyan(`
|
|
135
135
|
\u25B6 Installing ${e.length} additional ${n}...
|
|
136
136
|
`));try{await L({packages:e,cwd:t,flags:["--silent"]}),console.log(H.green(`\u2713 Installed ${e.length} ${n}
|
|
137
137
|
`))}catch(o){throw console.log(H.red(`\u2717 Package installation failed
|
|
@@ -139,48 +139,48 @@ Do NOT include the service path in file headers (use \`src/...\`, NOT \`${e}/src
|
|
|
139
139
|
\u25B6 Running post-generation commands...
|
|
140
140
|
`));let n=(await Sr(e,t)).find(o=>!o.success);if(n){console.log(H.yellow(`
|
|
141
141
|
\u26A0 Post-command failed: ${n.command}`)),n.error&&console.log(H.yellow(` Error: ${n.error}`));return}console.log(H.green(`\u2713 Post-generation commands complete
|
|
142
|
-
`))};import ut from"chalk";var
|
|
143
|
-
`,
|
|
144
|
-
`),
|
|
142
|
+
`))};import ut from"chalk";var np=e=>`${ut.dim(" \u2022 ")+ut.cyan(e)}
|
|
143
|
+
`,qo=e=>ut.dim(` \u2728 Generated ${ut.white.bold(e)} tokens
|
|
144
|
+
`),Yo=()=>{let e="",t=0,r=Date.now(),n=[],o=()=>{let i=e.match(/####\s+`([^`]+)`/);if(!i)return!1;n.push(i[1]),process.stdout.write(np(i[1]));let a=e.indexOf(i[0])+i[0].length;return e=e.slice(a),!0},s=i=>{e+=i,t++,o(),e.length>500&&(e=e.slice(-200))};return s.getStats=()=>{let i=((Date.now()-r)/1e3).toFixed(2),a=(t/Number.parseFloat(i)).toFixed(0);return{tokenCount:t,duration:i,tokensPerSec:a}},s.getFiles=()=>n,s};var lp=()=>{let e=g(),t=es(e,"package.json"),r=(()=>{if(!Qo(t))throw new Error("No package.json found in workspace root. Run from a valid workspace.");try{let o=JSON.parse(op(t,"utf-8")).name;if(!o)throw new Error('package.json has no "name" field. Please add a name to your root package.json.');return o.startsWith("@")?o:`@${o}`}catch(n){throw n instanceof SyntaxError?new Error("Invalid JSON in package.json"):n}})();return{workspaceRoot:e,scope:r,cwd:process.cwd()}},pp=async(e,t,r,n,o,s)=>{let i=Go(r,n,o,t.workspaceRoot),a=Ho(t,o,s),c=Yo(),l=await ho(e,i,{system:a,maxTokens:16384,temperature:.7,onToken:c}),p=c.getStats();return console.log(qo(p.tokenCount)),console.log(),l},mp=(e,t)=>{let{serviceTypes:r}=ce(),n=r[t]?.commandType;if(!n)return e;let o=Object.values(r).map(s=>s.commandType);return e.map(s=>{for(let i of o)if(i!==n&&s.command.includes(`pf new ${i}`))return{...s,command:s.command.replace(`pf new ${i}`,`pf new ${n}`)};return s})},dp=e=>e.length===0?"":`${[h.cyan(`
|
|
145
145
|
\u{1F4C1} Files to create:`),...e.map(t=>` ${h.green("\u2022")} ${h.white(t.path)} ${h.dim(`(${t.language})`)}`)].join(`
|
|
146
146
|
`)}
|
|
147
|
-
`,
|
|
147
|
+
`,Xo=(e,t,r)=>e.length===0?"":`${[h.cyan(`
|
|
148
148
|
${r} ${t}:`),...e.map(n=>` ${h.yellow("$")} ${h.white(n.command)}`)].join(`
|
|
149
149
|
`)}
|
|
150
|
-
`,
|
|
150
|
+
`,gp=e=>e.length===0?"":`${[h.cyan(`
|
|
151
151
|
\u{1F4E6} Dependencies to install:`),...e.map(t=>` ${h.magenta("+")} ${h.white(t)}`)].join(`
|
|
152
152
|
`)}
|
|
153
|
-
`,
|
|
153
|
+
`,up=(e,t)=>`${[h.yellow(`
|
|
154
154
|
Validation errors:`),...e.map(r=>h.yellow(` \u26A0 ${r}`)),h.dim(`
|
|
155
155
|
Response preview:`),h.dim(t)].join(`
|
|
156
156
|
`)}
|
|
157
|
-
`,me=e=>{e&&process.stdout.write(e)},
|
|
158
|
-
`)},
|
|
157
|
+
`,me=e=>{e&&process.stdout.write(e)},fp=(e,t)=>{let r=zo(e,t),n=br(r.commands),o=br(r.postCommands),s=Vo(r.files);return s.valid?{files:r.files,commands:n,dependencies:r.dependencies,postCommands:o}:(console.log(`${h.yellow("\u26A0")} Could not extract structured files from AI response`),me(up(s.errors,e.slice(0,500))),null)},hp=e=>{console.log(`${h.green("\u2714")} Extracted ${e.files.length} files`),me(dp(e.files)),me(Xo(e.commands,"Commands to run","\u{1F527}")),me(Xo(e.postCommands,"Post-generation commands","\u{1F4DD}")),me(gp(e.dependencies)),me(`
|
|
158
|
+
`)},yp=(e,t,r)=>{let n=Ao(e);return n&&!n.includes("/")&&!n.startsWith(".")&&(n=`${E().services}/${n}`),n?Zo(r,n):Zo(r,t)},vp=(e,t)=>{let{serviceTypes:r}=ce(),n=r[t]?.skipFiles||["package.json","tsconfig.json","Dockerfile"];return e.filter(o=>!n.includes(o.path))},de=()=>{if(!De())return{valid:!1,error:h.red.bold(`\u274C AI configuration not found.
|
|
159
159
|
`)+h.yellow("Please run ")+h.cyan.bold("pf setup --ai")+h.yellow(` first to configure your AI provider.
|
|
160
160
|
`)};try{return{valid:!0,config:pt()}}catch(e){return{valid:!1,error:h.red.bold(`\u274C ${e.message}
|
|
161
|
-
`)}}},ft=async e=>e||
|
|
161
|
+
`)}}},ft=async e=>e||ap({message:"\u{1F4DD} Describe what this service should do:",validate:t=>t.trim().length>0||"Please provide a description for the AI to generate code"}),ht=(e,t,r)=>{console.log(h.cyan.bold(`
|
|
162
162
|
\u{1F916} AI-Powered Generation
|
|
163
163
|
`)),console.log(h.dim(`Service: ${e.split("/").pop()}`)),console.log(h.dim(`Path: ${e}`)),console.log(h.dim(`Model: ${t.model}`)),console.log(h.dim(`Description: ${r}
|
|
164
|
-
`))},yt=async(e,t)=>{let{servicePath:r,description:n="",serviceType:o,packageManager:s}=e,i=r.split("/").pop()||r,a=
|
|
164
|
+
`))},yt=async(e,t)=>{let{servicePath:r,description:n="",serviceType:o,packageManager:s}=e,i=r.split("/").pop()||r,a=lp(),c=es(a.workspaceRoot,er);ip(c,`generating:${r}`);let l=()=>{Qo(c)&&sp(c)},p=()=>{l(),process.exit(w.CANCELLED)};process.on("SIGINT",p),process.on("SIGTERM",p);try{console.log(h.cyan.bold(`
|
|
165
165
|
\u{1F916} AI Generation
|
|
166
|
-
`));let m=await
|
|
167
|
-
`));let
|
|
166
|
+
`));let m=await pp(t,a,r,n,o,s),y=fp(m,i);if(!y)return!1;hp(y);let j=cp({text:"Processing files...",color:"cyan"}).start(),be=mp(y.commands,o),N=yp(be,r,a.cwd),ra=vp(y.files,o);await Jo(be,N,a.workspaceRoot);let{missingContractCommands:Cn}=await Oo(ra,N,a,j);if(y.postCommands.length>0)await Ar(y.postCommands,a.workspaceRoot);else if(Cn.length>0){console.log(h.cyan(`\u{1F527} Auto-creating missing contracts...
|
|
167
|
+
`));let na=Cn.map(oa=>({command:oa,isPfCommand:!0}));await Ar(na,a.workspaceRoot)}return $o(N),await Ko(y.dependencies,N,j),await Fo(N,j),!0}finally{process.off("SIGINT",p),process.off("SIGTERM",p),l()}};import{existsSync as tC}from"fs";import{Project as Cp,SyntaxKind as nC}from"ts-morph";var oC=new Cp({skipAddingFilesFromTsConfig:!0,skipFileDependencyResolution:!0});v();import{promises as Ir}from"fs";import vt from"path";import ts from"chalk";var rs=async e=>{await K("bash",["-c",`
|
|
168
168
|
curl -fsSL https://bun.sh/install | bash && if [ -f "$HOME/.bun/bin/bun" ]; then export PATH="$HOME/.bun/bin:$PATH"; fi
|
|
169
|
-
`],{task:e,shell:!0}),await
|
|
169
|
+
`],{task:e,shell:!0}),await Sp()},Rr=()=>Ee("bun"),ns=()=>Yt([{label:"Bun",value:59026,color:"magenta",barColor:"magenta"},{label:"Deno",value:25335},{label:"Node.js",value:19039}],{title:'Express.js "hello world" HTTP requests per second (Linux x64)',barColor:"blackBright"}),os=()=>Yt([{label:"Bun",value:.36,color:"magenta",barColor:"magenta"},{label:"pnpm",value:6.44},{label:"npm",value:10.58},{label:"yarn",value:12.08}],{title:"Bun is an npm-compatible package manager.",unit:"s",footer:ts.blackBright("* Installing dependencies from cache for a Remix app."),barColor:"blackBright"}),Sp=async()=>{let e='export PATH="$HOME/.bun/bin:$PATH"',t=process.env.HOME;if(!t){d.error("Could not detect $HOME environment variable. Cannot update shell config.");return}let r=[vt.join(t,".zshrc"),vt.join(t,".bashrc"),vt.join(t,".bash_profile")];for(let n of r)try{if(await Ir.stat(n).then(()=>!0).catch(()=>!1)){(await Ir.readFile(n,"utf8")).includes(e)||(await Ir.appendFile(n,`
|
|
170
170
|
# Added by platform installer
|
|
171
171
|
${e}
|
|
172
|
-
`),d.log(`Added Bun path to ${vt.basename(n)}`));return}}catch(o){d.error(`Failed to update ${n}: ${o.message}`)}d.warn("No shell config file (.zshrc, .bashrc, .bash_profile) found. Please add the following manually:"),d.log(
|
|
172
|
+
`),d.log(`Added Bun path to ${vt.basename(n)}`));return}}catch(o){d.error(`Failed to update ${n}: ${o.message}`)}d.warn("No shell config file (.zshrc, .bashrc, .bash_profile) found. Please add the following manually:"),d.log(ts.cyan(e))};f();import{existsSync as xt,mkdirSync as Lp,readFileSync as Wp,renameSync as Hp,statSync as ps,unlinkSync as Gp,writeFileSync as Bp}from"fs";import{join as We}from"path";import{existsSync as bp}from"fs";import{join as Ep}from"path";import Ct from"chalk";f();import Nr from"chalk";var ge=e=>{let t=Math.max(...e.commands.map(o=>o.name.length)),r=e.commands.map(o=>{let s=" ".repeat(t-o.name.length+3);return` ${Nr.cyan(o.name)}${s}${o.description}`}),n=e.footer||'Run "<command> --help" for more information';return[Nr.cyan.bold(`
|
|
173
173
|
${e.title}
|
|
174
174
|
`),`Available commands:
|
|
175
175
|
`,...r,"",Nr.dim(`${n}
|
|
176
176
|
`)].join(`
|
|
177
|
-
`)};var
|
|
177
|
+
`)};var Tp=(e,t)=>t.some(r=>r.name()===e),$p=(e,t)=>t.pf?.commands?.[e]??null,Ap=(e,t)=>!!t.scripts?.[e],Ip=(e,t)=>t.cwd?Ep(e,t.cwd):e,Rp=(e,t)=>t.command||e,Np=(e,t,r,n)=>{let o=Ip(n,r),s=Rp(e,r);if(r.cwd&&!bp(o))return console.error(Ct.red(`
|
|
178
178
|
\u2716 Directory not found: ${o}
|
|
179
|
-
`)),!0;let i=r.cwd?Ct.dim(` in ${r.cwd}/`):"";return console.log(Ct.dim(`Running ${s}${i}`)),
|
|
179
|
+
`)),!0;let i=r.cwd?Ct.dim(` in ${r.cwd}/`):"";return console.log(Ct.dim(`Running ${s}${i}`)),Zn(s,t,{cwd:o}),!0},Fp=(e,t,r)=>(console.log(Ct.dim(`Running workspace script: ${e}`)),Fe(e,{args:t,cwd:r}),!0);async function Op(e,t,r){if(Tp(e,r))return!1;let n;try{n=g()}catch{return!1}let o=F(n);if(!o)return!1;let s=$p(e,o);return s?Np(e,t,s,n):Ap(e,o)?Fp(e,t,n):!1}function ss(){let e;try{e=F()}catch{return{configured:[],scripts:[]}}if(!e)return{configured:[],scripts:[]};let t=Object.keys(e.pf?.commands??{}),n=Object.keys(e.scripts??{}).filter(o=>!t.includes(o));return{configured:t,scripts:n}}function Fr(){let{configured:e,scripts:t}=ss();return[...e,...t]}function is(){let{configured:e,scripts:t}=ss(),r=[...e,...t];if(r.length===0)return"";let o=F()?.pf?.commands||{},s=r.map(i=>({name:i,description:o[i]?.description||kt[i]||""}));return ge({title:"Workspace Commands",commands:s,footer:""})}function as(e,t,r){let n=t.slice(2);if(n.length>0&&!n[0].startsWith("-")){let o=n[0],s=n.slice(1);if(o==="__workspace-commands"&&s.includes("--names-only")){let i=Fr();for(let a of i)console.log(a);return}Op(o,s,r).then(i=>{i||e.parse(t)})}else e.parse(t)}f();var cs={setup:"Configure platform settings",new:"Create a new project",dev:"Start development mode",event:"Event management commands",token:"Token management commands",audit:"Run security audit"},kt={build:"Build all packages",test:"Run tests",lint:"Lint codebase",format:"Format code",preview:"Preview application",prepare:"Prepare workspace",pulumi:"Run Pulumi commands","pub-sdk":"Publish platform SDK","pub-cloudevents":"Publish cloudevents package","check-versions":"Check internal version consistency","sync-versions":"Sync internal package versions","sync-templates":"Sync service templates","generate-env":"Generate environment files",dev:"Start development environment"},ls=(e,t)=>t?`${e}:${t}`:e,Mp=()=>Object.entries(cs).map(([e,t])=>ls(e,t)),Dp=()=>{try{let e=Fr(),r=F()?.pf?.commands||{},n=Object.keys(cs);return e.filter(o=>!n.includes(o)).map(o=>{let s=r[o]?.description||kt[o]||"";return ls(o,s)})}catch{return[]}},_p=()=>{try{let e=g(),t=x(e),r=`${e}/${t.relativePath}/src`,{discoverEventTypes:n}=Jt("@crossdelta/cloudevents");return n(r)}catch{return[]}},jp=async()=>{try{let e=g();return await Co(e)}catch{return[]}},Or=async()=>({commands:[...Mp(),...Dp()],events:_p(),services:await jp()});var je="node_modules/.cache/pf",Le="completion-cache";var Up=e=>{let t=R.version||"0.0.0",r=e.commands.join("|"),n=e.events.join("|"),o=e.services.join("|");return`${t} ${r} ${n} ${o}`},zp=e=>{let t=e.split(" ");if(t.length===4){let[o,s,i,a]=t;return{version:o,commands:s?s.split("|"):[],events:i?i.split("|"):[],services:a?a.split("|"):[]}}if(t.length===3){let[o,s,i]=t;return{version:o,commands:s?s.split("|"):[],events:i?i.split("|"):[],services:[]}}let[r,n]=t;return{commands:r?r.split("|"):[],events:n?n.split("|"):[],services:[]}},Vp=e=>{let t=We(e,je);return We(t,Le)},Jp=(e,t=!1)=>{if(t)return!0;let r=Vp(e);if(!xt(r))return!0;let n=Wp(r,"utf-8").trim(),o=zp(n),s=R.version||"0.0.0";if(o.version!==s)return!0;let i=We(e,"package.json");if(!xt(i))return!1;let a=ps(r).mtimeMs;return ps(i).mtimeMs>a};var Kp=(e,t)=>{let r=We(e,je),n=We(r,Le),o=`${n}.tmp.${process.pid}`;xt(r)||Lp(r,{recursive:!0});let s=Up(t);try{Bp(o,s,"utf-8"),Hp(o,n)}catch(i){try{xt(o)&&Gp(o)}catch{}throw i}},wt=async(e={})=>{let t;try{t=g()}catch{return!1}if(!t)return!1;if(!Jp(t,e.force))return e.verbose&&console.log("[completion] Cache is up to date"),!1;let r=await Or();return Kp(t,r),e.verbose&&console.log(`[completion] Cache regenerated: ${r.commands.length} commands, ${r.events.length} events`),!0},He=async(e={})=>{await wt({...e,force:!0})};import{existsSync as Dr,readFileSync as fs,writeFileSync as hs}from"fs";import{homedir as ys}from"os";import{join as Mr}from"path";import ue from"chalk";var ms=`${je}/${Le}`,ds=e=>`# ${e} completion (workspace-local cache)
|
|
180
180
|
# Generated: ${new Date().toISOString()}
|
|
181
181
|
|
|
182
182
|
# Cache file path (relative to workspace root)
|
|
183
|
-
_${e}_cache_path="${
|
|
183
|
+
_${e}_cache_path="${ms}"
|
|
184
184
|
|
|
185
185
|
# Find workspace root (walk up to find monorepo package.json)
|
|
186
186
|
_${e}_find_workspace() {
|
|
@@ -307,11 +307,11 @@ _${e}_completions() {
|
|
|
307
307
|
esac
|
|
308
308
|
}
|
|
309
309
|
|
|
310
|
-
compdef _${e}_completions ${e}`,
|
|
310
|
+
compdef _${e}_completions ${e}`,gs=e=>`# ${e} completion (workspace-local cache)
|
|
311
311
|
# Generated: ${new Date().toISOString()}
|
|
312
312
|
|
|
313
313
|
# Cache file path (relative to workspace root)
|
|
314
|
-
_${e}_cache_path="${
|
|
314
|
+
_${e}_cache_path="${ms}"
|
|
315
315
|
|
|
316
316
|
# Find workspace root
|
|
317
317
|
_${e}_find_workspace() {
|
|
@@ -405,13 +405,13 @@ _${e}_completions() {
|
|
|
405
405
|
return 0
|
|
406
406
|
}
|
|
407
407
|
|
|
408
|
-
complete -F _${e}_completions ${e}`;var
|
|
408
|
+
complete -F _${e}_completions ${e}`;var qp=(e,t)=>Mr(ys(),`.${t}-completion.${e}`),vs=e=>{let t=ys();return e==="zsh"?Mr(t,".zshrc"):Mr(t,".bashrc")},Yp=e=>`[[ -f "${e}" ]] && source "${e}"`,Zp=(e,t)=>Dr(e)?fs(e,"utf-8").includes(t):!1,Xp=(e,t)=>{let r=Dr(e)?fs(e,"utf-8"):"",n=r.endsWith(`
|
|
409
409
|
`)?`${r}${t}
|
|
410
410
|
`:`${r}
|
|
411
411
|
${t}
|
|
412
|
-
`;
|
|
412
|
+
`;hs(e,n,"utf-8")},Qp=(e,t)=>{let r=qp(e,t),n=e==="zsh"?ds(t):gs(t);return hs(r,n,"utf-8"),r},us=(e,t,r)=>{let n=Qp(e,t),o=vs(e),s=Yp(n);return Zp(o,s)?(r&&console.log(ue.dim(`[${e}] Already configured in ${o}`)),!1):(Xp(o,s),r&&console.log(ue.green(`[${e}] Added source line to ${o}`)),!0)},em=()=>(process.env.SHELL||"").includes("zsh")?"zsh":"bash",_r=(e,t=!1)=>{let r=em();t&&console.log(ue.cyan(`Installing ${r} completion...`)),us(r,e,t);let n=r==="zsh"?"bash":"zsh",o=vs(n);Dr(o)&&us(n,e,t),t&&(console.log(ue.green("\u2713 Shell completion installed")),console.log(ue.dim(` Run: ${ue.cyan("exec $SHELL")} to reload`)))};V();import{readdir as zx}from"fs/promises";import{dirname as Jx,join as Kx}from"path";import{fileURLToPath as Yx}from"url";import{runFlow as Xx}from"@crossdelta/flowcore";var tm={debug:()=>{},info:console.log,warn:console.warn,error:console.error},Cs=e=>e!==null&&typeof e=="object",ks=e=>typeof e=="string"&&e.length>0,xs=e=>typeof e=="string",jr=e=>typeof e=="function",rm=(e,t)=>Cs(e)?[!ks(e.name)&&`commands[${t}]: missing or invalid 'name'`,!xs(e.description)&&`commands[${t}]: missing or invalid 'description'`,!Array.isArray(e.args)&&`commands[${t}]: missing 'args' array`,!Array.isArray(e.options)&&`commands[${t}]: missing 'options' array`,!jr(e.run)&&`commands[${t}]: missing 'run' function`].filter(r=>r!==!1):[`commands[${t}]: must be an object`];var ws=e=>{if(!Cs(e))return["Plugin must be an object"];let t=[!ks(e.name)&&"Missing or invalid 'name'",!xs(e.version)&&"Missing or invalid 'version'",!Array.isArray(e.commands)&&"Missing 'commands' array",!Array.isArray(e.flows)&&"Missing 'flows' array",!jr(e.setup)&&"Missing 'setup' function"].filter(n=>n!==!1),r=Array.isArray(e.commands)?e.commands.flatMap((n,o)=>rm(n,o)):[];return[...t,...r]},Pt=(e,t=tm)=>({workspace:e,logger:t}),St=async(e,t)=>{let{logger:r}=t;r.debug(`Loading plugin from module: ${e}`);let n=await import(e),o=n.createPfPlugin||n.default?.createPfPlugin;if(!jr(o))throw new Error(`Module ${e} does not export createPfPlugin`);let s=o({contractsPath:t.workspace.contracts.path,contractsPackage:t.workspace.contracts.packageName,availableServices:t.workspace.availableServices}),i=ws(s);if(i.length>0)throw new Error(`Plugin from ${e} does not conform to PfPlugin interface:
|
|
413
413
|
- ${i.join(`
|
|
414
|
-
- `)}`);let a=s;return r.debug(`Loaded plugin: ${a.name} v${a.version}`),await a.setup(t),{plugin:a,source:e}};import{deriveEventNames as
|
|
414
|
+
- `)}`);let a=s;return r.debug(`Loaded plugin: ${a.name} v${a.version}`),await a.setup(t),{plugin:a,source:e}};import{deriveEventNames as rw}from"@crossdelta/cloudevents";import{z as C}from"zod";var bt=C.object({dependencies:C.record(C.string(),C.string()).default({}),envVars:C.array(C.object({key:C.string(),description:C.string(),required:C.boolean().default(!0)})).default([]),adapterFile:C.string().optional()}),nm=C.object({push:C.string().optional(),email:C.string().optional(),slack:C.string().optional(),sms:C.string().optional()}).optional(),om=C.object({defaults:nm,providers:C.object({push:C.record(C.string(),bt).optional(),email:C.record(C.string(),bt).optional(),slack:C.record(C.string(),bt).optional(),sms:C.record(C.string(),bt).optional()}).optional()}),nk=C.object({notifier:om.optional()});import{z as u}from"zod";var sm=u.object({type:u.literal("event"),eventType:u.string(),stream:u.string().optional()}),im=u.object({type:u.literal("http"),method:u.enum(["GET","POST","PUT","DELETE","PATCH"]).optional(),path:u.string().optional()}),Ps=u.discriminatedUnion("type",[sm,im]),am=u.object({type:u.literal("emit.event"),eventType:u.string()}),cm=u.object({type:u.literal("notify"),channel:u.enum(["push","email","slack","sms"]),provider:u.string().optional()}),lm=u.object({type:u.literal("call.http"),name:u.string().optional(),baseUrl:u.string().optional()}),pm=u.object({type:u.literal("persist"),store:u.enum(["db","kv","cache"]),entity:u.string().optional()}),Ss=u.discriminatedUnion("type",[am,cm,lm,pm]),bs=u.object({serviceName:u.string().regex(/^[a-z][a-z0-9]*(-[a-z0-9]+)*$/),framework:u.enum(["hono","nest"]).default("hono"),triggers:u.array(Ps).min(1),actions:u.array(Ss).default([])});var km=(e,t,r)=>{let{stream:n,servicePath:o}=e,s=o.startsWith("/")?o:`${t.workspace.workspaceRoot}/${o}`;if(r?.dryRun)return{success:!0,message:`Would wire stream ${n} to ${o}`,changes:[{type:"update",path:s,description:`Wire ${n} stream to service`,preview:`consumeJetStreams({ streams: ['${n.toUpperCase()}'], ... })`}]};let i=yr(s,`${n.toLowerCase()}.event`);return i.warning?(t.logger.warn(i.warning),{success:!1,message:i.warning}):i.added?(t.logger.info(`Wired stream ${i.streamName} to service`),{success:!0,message:`Wired stream ${i.streamName}`}):(t.logger.debug(`Stream ${i.streamName} already wired`),{success:!0,message:`Stream ${i.streamName} already configured`})},xm=(e,t,r)=>{let{path:n,eventType:o}=e;if(r?.dryRun){let i=`
|
|
415
415
|
import { createContract } from '@crossdelta/cloudevents'
|
|
416
416
|
import { z } from 'zod'
|
|
417
417
|
|
|
@@ -419,7 +419,7 @@ export const ${Lr(o)}Contract = createContract({
|
|
|
419
419
|
type: '${o}',
|
|
420
420
|
schema: z.object({ ... }),
|
|
421
421
|
})
|
|
422
|
-
`.trim();return{success:!0,message:`Would create contract ${o}`,changes:[{type:"create",path:n,description:`Create event contract for ${o}`,preview:i.slice(0,500)}]}}let s=xr(o,t.workspace.workspaceRoot);return s&&t.logger.debug(`Added export for ${o} to contracts index`),t.logger.debug(`Contract created: ${o} at ${n}`),{success:!0,message:s?`Contract ${o} created with exports`:`Contract ${o} created`}},Lr=e=>e.split(".").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),
|
|
422
|
+
`.trim();return{success:!0,message:`Would create contract ${o}`,changes:[{type:"create",path:n,description:`Create event contract for ${o}`,preview:i.slice(0,500)}]}}let s=xr(o,t.workspace.workspaceRoot);return s&&t.logger.debug(`Added export for ${o} to contracts index`),t.logger.debug(`Contract created: ${o} at ${n}`),{success:!0,message:s?`Contract ${o} created with exports`:`Contract ${o} created`}},Lr=e=>e.split(".").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(""),wm=(e,t,r)=>{let{path:n,eventType:o,servicePath:s}=e;if(r?.dryRun){let i=`
|
|
423
423
|
import { handleEvent } from '@crossdelta/cloudevents'
|
|
424
424
|
import { ${Lr(o)}Contract } from '@your-scope/contracts'
|
|
425
425
|
|
|
@@ -427,9 +427,9 @@ export default handleEvent(${Lr(o)}Contract, async (data) => {
|
|
|
427
427
|
console.log('Processing ${o}:', data)
|
|
428
428
|
// TODO: Implement handler logic
|
|
429
429
|
})
|
|
430
|
-
`.trim();return{success:!0,message:`Would create handler for ${o}`,changes:[{type:"create",path:n,description:`Create event handler for ${o}`,preview:i.slice(0,500)}]}}return t.logger.debug(`Handler created: ${o} at ${n} (service: ${s})`),{success:!0}},
|
|
430
|
+
`.trim();return{success:!0,message:`Would create handler for ${o}`,changes:[{type:"create",path:n,description:`Create event handler for ${o}`,preview:i.slice(0,500)}]}}return t.logger.debug(`Handler created: ${o} at ${n} (service: ${s})`),{success:!0}},Pm={"stream.wired":km,"contract.created":xm,"handler.created":wm},Wr=(e,t,r)=>e.map(n=>{let o=Pm[n.kind];return o?o(n,t,r):(t.logger.warn(`Unknown effect kind: ${n.kind}`),{success:!1,message:`Unknown effect kind: ${n.kind}`})});import{join as It}from"path";import{deriveEventNames as dd}from"@crossdelta/cloudevents";var Hr=(e,t,r={})=>({ok:!0,operation:e,summary:t,artifacts:r.artifacts??[],changes:r.changes??[],diagnostics:r.diagnostics??[],next:r.next,data:r.data});f();import{join as Br}from"path";import{readFileSync as Sm}from"fs";import{join as bm}from"path";import Em from"handlebars";var fe=(e,t)=>vo(e,t??`Templates directory not found. Searched in: ${e.join(", ")}`),Gr=(e,t={})=>{let r=Sm(e,"utf-8");return Em.compile(r)(t)},Et=e=>(t,r={})=>{let n=bm(e,t);return Gr(n,r)};var B=e=>e.toUpperCase().replace(/-/g,"_");var Ts=e=>e.split("-").map(t=>t.charAt(0).toUpperCase()+t.slice(1)).join(" ");var Tm=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),$m=()=>{let e=Tm(),t=ee();return fe([Br(e,"templates","hono-microservice"),Br(e,"..","hono-microservice","templates"),Br(t,"bin","templates","hono-microservice")],"Hono templates directory not found.")},Tt=(e,t={})=>Et($m())(e,t);function $s(){return Tt("tsconfig.json.hbs")}function As(e="1.2.23"){return Tt("Dockerfile.hbs",{bunVersion:e})}function Is(){return Tt("biome.json.hbs")}function Rs(e,t=[]){return Tt("src/config/env.ts.hbs",{envKey:B(e),envVars:t})}var Am=e=>{let t=["import './config/env'","import '@crossdelta/telemetry'",""];return e&&t.push("import { consumeJetStreams, isConsumerConnected } from '@crossdelta/cloudevents'"),t.push("import { Hono } from 'hono'"),t},Im=(e,t)=>{let r=[`const port = Number(process.env.${e}_PORT) || 8080`,"const app = new Hono()","","app.get('/health', (c) => {"," return c.json({ status: 'ok' })","})"];return t&&r.push("","app.get('/health/ready', (c) => {"," const ready = isConsumerConnected()"," return c.json({ status: ready ? 'ok' : 'not-ready' }, ready ? 200 : 503)","})"),r},Rm=(e,t)=>["","// Start NATS JetStream consumer","consumeJetStreams({",` streams: [${t.map(r=>`'${r}'`).join(", ")}],`,` consumer: '${e}',`," discover: './src/events/**/*.handler.ts',","})"],Nm=()=>["","Bun.serve({"," port,"," fetch: app.fetch,","})","","console.log(`\u{1F680} Service ready at http://localhost:${port}`)"],Fm=e=>{let t=B(e.serviceName);return`${[...Am(e.hasEvents),"",...Im(t,e.hasEvents),...e.hasEvents?Rm(e.serviceName,e.streams):[],...Nm()].join(`
|
|
431
431
|
`)}
|
|
432
|
-
`},
|
|
432
|
+
`},Om=e=>{let t={hono:"^4.6.14","@crossdelta/telemetry":"workspace:*",zod:"^4.1.0",[`${e.workspaceScope}/contracts`]:"workspace:*"};e.hasEvents&&(t["@crossdelta/cloudevents"]="workspace:*");let r={name:e.packageName,version:"0.0.1",type:"module",scripts:{"start:dev":"bun --watch src/index.ts",start:"bun src/index.ts",test:"bun test"},dependencies:t,devDependencies:{"@types/bun":"^1.2.23"}};return JSON.stringify(r,null,2)},Mm=e=>`# ${e.serviceName}
|
|
433
433
|
|
|
434
434
|
## Development
|
|
435
435
|
|
|
@@ -449,7 +449,7 @@ ${e.hasEvents?`
|
|
|
449
449
|
This service consumes from:
|
|
450
450
|
${e.streams.map(t=>`- ${t}`).join(`
|
|
451
451
|
`)}`:""}
|
|
452
|
-
`,
|
|
452
|
+
`,Dm=()=>"",Ns={name:"hono-bun",runtime:"bun",framework:"hono",files:[{path:"src/index.ts",content:Fm},{path:"src/config/env.ts",content:e=>Rs(e.serviceName,e.envVars)},{path:"package.json",content:Om},{path:"tsconfig.json",content:()=>$s()},{path:"Dockerfile",content:()=>As()},{path:"biome.json",content:()=>Is()},{path:"README.md",content:Mm},{path:"src/events/.gitkeep",content:Dm,skip:e=>!e.hasEvents}]};import{join as Ur}from"path";var _m=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),jm=()=>{let e=_m(),t=ee();return fe([Ur(e,"templates","nest-microservice"),Ur(e,"..","nest-microservice","templates"),Ur(t,"bin","templates","nest-microservice")],"NestJS templates directory not found.")},re=(e,t={})=>Et(jm())(e,t);function Fs(e,t=3e3){return re("src/main.ts.hbs",{serviceName:e,envKey:B(e),displayName:Ts(e),defaultPort:t})}function Os(){return re("src/app.context.ts.hbs",{})}function Ms(){return re("src/events/events.module.ts.hbs",{})}function Ds(e){return re("src/events/events.service.ts.hbs",{serviceName:e})}function _s(e="24",t="1.2.23"){return re("Dockerfile.hbs",{nodeVersion:e,bunVersion:t})}function js(){return re("biome.json.hbs",{})}function Ls(e,t=[]){return re("src/config/env.ts.hbs",{envKey:B(e),envVars:t})}var Lm=e=>{let t={"@nestjs/common":"^11.0.0","@nestjs/core":"^11.0.0","@nestjs/platform-express":"^11.0.0","@crossdelta/telemetry":"workspace:*","reflect-metadata":"^0.2.0",rxjs:"^7.8.0",zod:"^4.1.0",[`${e.workspaceScope}/contracts`]:"workspace:*"};e.hasEvents&&(t["@crossdelta/cloudevents"]="workspace:*");let r={name:e.packageName,version:"0.0.1",scripts:{"start:dev":"bun --watch src/main.ts",start:"node dist/main.js",build:"tsc",test:"bun test"},dependencies:t,devDependencies:{"@nestjs/cli":"^11.0.0","@types/node":"^24.0.0",typescript:"^5.7.0"}};return JSON.stringify(r,null,2)},Wm=()=>JSON.stringify({extends:"../../../../tsconfig.json",compilerOptions:{outDir:"./dist",rootDir:"./src",experimentalDecorators:!0,emitDecoratorMetadata:!0},include:["src/**/*"],exclude:["node_modules","dist","**/*.test.ts"]},null,2),Hm=e=>{let t=["Module","HttpModule"],r=["HttpModule"];return e.hasEvents&&(t.push("OnModuleInit"),r.push("EventsModule")),`import { ${t.join(", ")} } from '@nestjs/common'
|
|
453
453
|
${e.hasEvents?"import { EventsModule } from './events/events.module'":""}
|
|
454
454
|
|
|
455
455
|
@Module({
|
|
@@ -462,7 +462,7 @@ export class AppModule${e.hasEvents?" implements OnModuleInit":""} {
|
|
|
462
462
|
// Events module initializes NATS consumer
|
|
463
463
|
}`:""}
|
|
464
464
|
}
|
|
465
|
-
`},
|
|
465
|
+
`},Gm=()=>`import { Controller, Get } from '@nestjs/common'
|
|
466
466
|
|
|
467
467
|
@Controller()
|
|
468
468
|
export class AppController {
|
|
@@ -471,7 +471,7 @@ export class AppController {
|
|
|
471
471
|
return { status: 'ok' }
|
|
472
472
|
}
|
|
473
473
|
}
|
|
474
|
-
`,
|
|
474
|
+
`,Bm=e=>`# ${e.serviceName}
|
|
475
475
|
|
|
476
476
|
## Development
|
|
477
477
|
|
|
@@ -491,8 +491,8 @@ ${e.hasEvents?`
|
|
|
491
491
|
This service consumes from:
|
|
492
492
|
${e.streams.map(t=>`- ${t}`).join(`
|
|
493
493
|
`)}`:""}
|
|
494
|
-
`,
|
|
495
|
-
`);for(let{pattern:s,description:i,code:a}of t){let c=new RegExp(s,"g");for(let l=0;l<o.length;l++)c.test(o[l])&&n.push({code:a,message:i,path:r,line:l+1}),c.lastIndex=0}return n},
|
|
494
|
+
`,Um=()=>"",Ws={name:"nest",runtime:"node",framework:"nest",files:[{path:"src/config/env.ts",content:e=>Ls(e.serviceName,e.envVars)},{path:"src/main.ts",content:e=>Fs(e.serviceName,e.port)},{path:"src/app.module.ts",content:Hm},{path:"src/app.controller.ts",content:()=>Gm()},{path:"src/app.context.ts",content:()=>Os()},{path:"package.json",content:Lm},{path:"tsconfig.json",content:()=>Wm()},{path:"Dockerfile",content:()=>_s()},{path:"biome.json",content:()=>js()},{path:"README.md",content:Bm},{path:"src/events/events.module.ts",content:()=>Ms(),skip:e=>!e.hasEvents},{path:"src/events/events.service.ts",content:e=>Ds(e.serviceName),skip:e=>!e.hasEvents},{path:"src/events/handlers/.gitkeep",content:Um,skip:e=>!e.hasEvents}]};var Hs=[Ns,Ws],Gs=e=>{let t=zm(e),r=Hs.find(n=>n.name===t);if(!r)throw new Error(`Template '${e}' not found. Available: ${Hs.map(n=>n.name).join(", ")}`);return r},zm=e=>({"hono-micro":"hono-bun","nest-micro":"nest"})[e]||e;import{join as Vr}from"path";import{deriveEventNames as Jr}from"@crossdelta/cloudevents";var Bs={appliesTo:["src/domain","src/use-cases"],forbiddenPatterns:[{pattern:"console\\.(log|error|warn|info|debug)\\s*\\(",description:"console.* is forbidden in business logic (use structured logging)",code:"CONSOLE_IN_DOMAIN"},{pattern:"process\\.env\\b",description:"process.env is forbidden in business logic (use dependency injection)",code:"PROCESS_ENV_IN_DOMAIN"},{pattern:"\\bfetch\\s*\\(",description:"fetch() is forbidden in business logic (use adapters/services)",code:"FETCH_IN_DOMAIN"}]},Ge={hono:{businessLogicDir:"use-cases",eventsDir:"events",filePattern:"{name}.use-case.ts",suffix:"use-case",handlerDelegatesToBusinessLogic:!0,pathGuards:{forbidDirs:["src/services"]},codingConstraints:Bs},nestjs:{businessLogicDir:"",eventsDir:"events",filePattern:"{name}.service.ts",suffix:"service",handlerDelegatesToBusinessLogic:!1,pathGuards:{forbidDirs:[]},codingConstraints:{appliesTo:["src/domain"],forbiddenPatterns:Bs.forbiddenPatterns}}},Vm=e=>e.replace(/-([a-z])/g,(t,r)=>r.toUpperCase()),Jm=(e,t)=>`../${e}/${t}`,he=(e,t)=>{let r=Ge[e],n=r.filePattern.replace("{name}",t),o=n.replace(/\.ts$/,""),s=r.businessLogicDir?`src/${r.businessLogicDir}`:"src";return{filePath:s?`${s}/${n}`:`src/${n}`,dirPath:s,fileName:n,functionName:Vm(t),delegateFromHandler:r.handlerDelegatesToBusinessLogic,importFromEvents:r.businessLogicDir?Jm(r.businessLogicDir,o):`./${o}`}},zr=(e,t)=>{let n=`src/${Ge[e].eventsDir}`,o=`${t}.handler.ts`;return{filePath:`${n}/${o}`,dirPath:n,fileName:o}},Be=e=>`handle-${e.replace(/\./g,"-")}`,$t=e=>{let t=e.replace(/\\/g,"/");t=t.replace(/^\.\//,"").replace(/^\//,"");let r=t.split("/"),n=[];for(let o of r)o===".."?n.pop():o!=="."&&o!==""&&n.push(o);return n.join("/")},Km=(e,t)=>{let r=$t(e);for(let n of t){let o=$t(n);if(r.startsWith(`${o}/`)||r===o)return n}return null},qm=(e,t)=>{let r=$t(e);return t.some(n=>{let o=$t(n);return r.startsWith(`${o}/`)||r===o})},Ym=(e,t,r)=>{let n=[],o=e.split(`
|
|
495
|
+
`);for(let{pattern:s,description:i,code:a}of t){let c=new RegExp(s,"g");for(let l=0;l<o.length;l++)c.test(o[l])&&n.push({code:a,message:i,path:r,line:l+1}),c.lastIndex=0}return n},Zm=(e,t)=>{let r=[],n=Km(e.path,t.pathGuards.forbidDirs);if(n&&r.push({code:"FORBIDDEN_DIR",message:`Path '${e.path}' is in forbidden directory '${n}'`,path:e.path}),qm(e.path,t.codingConstraints.appliesTo)){let o=Ym(e.content,t.codingConstraints.forbiddenPatterns,e.path);r.push(...o)}return r},At=(e,t)=>{let r=Ge[e],n=[];for(let o of t)n.push(...Zm(o,r));return{valid:n.length===0,violations:n}};var ed=(e,t)=>t.map(r=>({kind:"file:write",path:Vr(e,r.path),content:r.content})),td=(e,t,r)=>({kind:"infra:add",serviceName:e,port:t,framework:r.framework,runtime:r.runtime}),rd=(e,t)=>({kind:"env:add",key:`${e}_PORT`,value:t.toString()}),nd=(e,t)=>{let{typeName:r}=Jr(e),n=Be(e),o=he("hono",n);return`import type { ${r} } from '${t}/contracts'
|
|
496
496
|
|
|
497
497
|
/**
|
|
498
498
|
* Handle ${e} event
|
|
@@ -504,7 +504,7 @@ export const ${o.functionName} = async (data: ${r}): Promise<void> => {
|
|
|
504
504
|
// TODO: Implement business logic
|
|
505
505
|
// Example: validate data, transform, call external services
|
|
506
506
|
}
|
|
507
|
-
`},
|
|
507
|
+
`},od=(e,t,r)=>{let{contractName:n,typeName:o}=Jr(e),s=Be(e),i=he(r,s);return i.delegateFromHandler?`import { handleEvent } from '@crossdelta/cloudevents'
|
|
508
508
|
import { ${n}, type ${o} } from '${t}/contracts'
|
|
509
509
|
import { ${i.functionName} } from '${i.importFromEvents}'
|
|
510
510
|
|
|
@@ -519,12 +519,13 @@ export default handleEvent(${n}, async (data: ${o}) => {
|
|
|
519
519
|
console.log('\u{1F4E6} [${e}] Event received:', data)
|
|
520
520
|
// TODO: Inject and call service
|
|
521
521
|
})
|
|
522
|
-
`},
|
|
523
|
-
`):
|
|
524
|
-
|
|
525
|
-
|
|
522
|
+
`},sd=(e,t,r)=>!t.hasEvents||t.events.length===0?[]:he(r,"stub").delegateFromHandler?t.events.map(o=>{let s=Be(o),i=he(r,s);return{kind:"file:write",path:Vr(e,i.filePath),content:nd(o,t.workspaceScope)}}):[],id=(e,t,r)=>!t.hasEvents||t.events.length===0?[]:t.events.map(n=>{let{kebab:o}=Jr(n),s=zr(r,o);return{kind:"file:write",path:Vr(e,s.filePath),content:od(n,t.workspaceScope,r)}}),ad=e=>e==="hono"?"hono":e==="nest"?"nestjs":"hono",Us=(e,t,r,n)=>{let o=ad(n.framework),s=ed(e,t),i=sd(e,r,o),a=id(e,r,o),c=td(r.serviceName,r.port,n),l=rd(r.envVarName,r.port);return[...s,...i,...a,c,l]};import{existsSync as cd,readdirSync as ld,readFileSync as pd}from"fs";import{join as zs}from"path";var Vs=4001,md=e=>{let t=e.match(/ports\(\)\.(?:http|https|grpc|primary)\((\d+)\)/);if(t)return Number.parseInt(t[1],10);let r=e.match(/containerPort:\s*(\d+)/);return r?Number.parseInt(r[1],10):null},Js=e=>{try{let t=zs(e,"infra","services");return cd(t)?ld(t).filter(n=>n.endsWith(".ts")).reduce((n,o)=>{let s=pd(zs(t,o),"utf-8"),i=md(s);return i!==null&&n.add(i),n},new Set):new Set}catch(t){return console.warn("Failed to scan ports:",t),new Set}},Kr=(e,t)=>e.has(t)?Kr(e,t+1):t;var gd=e=>{if(!e||e.trim().length===0)throw new Error("Service name cannot be empty");if(!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(e))throw new Error(`Service name '${e}' must be kebab-case (lowercase, alphanumeric, hyphens only)`)},ud=(e,t,r)=>{if(t){if(t.startsWith("/"))return t;if(t.startsWith("."))return It(r,t);if(t.includes("/"))return It(r,t)}let n=E(r);return It(r,n.services,e)},fd=e=>[...new Set(e.map(t=>dd(t).streamName))],hd=(e,t,r,n)=>{let s=x(t).packageName.split("/")[0],i=e.events??[],a=i.length>0||e.hasEvents||!1,c=i.length>0?fd(i):e.streams??[];return{serviceName:e.name,packageName:`${s}/${e.name}`,servicePath:r.replace(`${t}/`,""),port:n,envVarName:B(e.name),hasEvents:a,streams:c,events:i,workspaceScope:s,envVars:e.envVars}},yd=(e,t)=>e.files.filter(r=>!r.skip?.(t)).map(r=>({path:r.path,content:r.content(t)})),vd=(e,t,r)=>[...e.map(o=>({type:"file",path:It(r,o.path),description:`Service file: ${o.path}`})),{type:"config",path:`infra/services/${t}.ts`,description:"Infrastructure configuration"},{type:"env",path:".env.local",description:"Environment variables"}],Cd=e=>[{command:`cd ${e} && bun dev`,description:"Start this service"},{command:"pf dev",description:"Start all services"}],Ks=e=>{gd(e.name);let t=e.workspaceRoot??g(),r=ud(e.name,e.path,t),n=e.port??Kr(Js(t),Vs),o=hd(e,t,r,n),s=Gs(e.type),i=yd(s,o),a=Us(r,i,o,s),c=vd(i,e.name,r),l=Cd(r);return Hr("service.generate",`Generated ${e.name} service (port ${n})`,{artifacts:c,changes:a,next:l,data:{serviceName:e.name,servicePath:r,port:n,vars:o}})},qs=e=>{let t=Ks(e);if(!t.ok||!t.data)throw new Error(t.summary);return{serviceName:t.data.serviceName,servicePath:t.data.servicePath,port:t.data.port,effects:t.changes,vars:t.data.vars}};f();f();f();import A from"chalk";import{execa as xd}from"execa";import{createJiti as wd}from"jiti";var Yr=async e=>{let{stdout:t}=await xd("sh",["-c",e]);return t.trim()},Pd="pf-local-nats",Sd="2.10-alpine",bd=4222,Ed=8222,Td=e=>({clientPort:e.clientPort??bd,monitoringPort:e.monitoringPort??Ed,containerName:e.containerName??Pd,version:e.version??Sd}),$d=e=>["run","--rm","--detach",`--name=${e.containerName}`,`-p=${e.clientPort}:4222`,`-p=${e.monitoringPort}:8222`,`nats:${e.version}`,"--jetstream","--store_dir=/data","--http_port=8222"],Ad=e=>({containerName:e.containerName,clientUrl:`nats://localhost:${e.clientPort}`,monitoringUrl:`http://localhost:${e.monitoringPort}`}),Id=async()=>{try{return await Yr("docker info"),!0}catch{return!1}},Rd=async e=>{try{return(await Yr(`docker ps -q -f name=${e}`)).length>0}catch{return!1}};var Nd=async e=>{let t=$d(e);try{return await Yr(`docker ${t.join(" ")}`),{success:!0,value:Ad(e)}}catch{return{success:!1}}},Fd=e=>{console.log(A.green("\u2713 NATS started")),console.log(A.dim(` Client: ${e.clientUrl}`)),console.log(A.dim(` Monitoring: ${e.monitoringUrl}`)),console.log(A.dim(" Streams: ephemeral, auto-created by services")),console.log("")},Ys=async(e={})=>{let t=Td(e);if(!await Id())return console.log(A.yellow("\u26A0\uFE0F Docker not available - skipping NATS (services may fail)")),!1;if(await Rd(t.containerName))return console.log(A.dim("\u2713 NATS already running")),!0;console.log(A.cyan("\u{1F680} Starting development infrastructure...")),console.log(A.dim(" NATS with JetStream (ephemeral)"));let r=await Nd(t);return r.success?(Fd(r.value),!0):(console.error(A.red("\u2717 Failed to start NATS")),!1)},Od=e=>e.map(({stream:t,subjects:r})=>({stream:t,subjects:r,config:{storage:"memory",retention:"limits",maxAge:36e5}})),qr="@crossdelta/infrastructure",Zs=e=>e.includes(qr)&&(e.includes("is not defined by")||e.includes("Cannot find module")||e.includes("Cannot find package")),Xs=e=>{if(typeof e!="object"||e===null)return null;let{message:t}=e;return typeof t=="string"?t:null},Md=e=>{let t=Xs(e);if(t===null)return!0;if(Zs(t))return!1;let r=t.toLowerCase();return!r.includes("insufficient storage")&&!r.includes("connection refused")},Dd=e=>{let t=Xs(e);if(t===null)return"Unknown error";let r=t.toLowerCase();return r.includes("insufficient storage")?["NATS has insufficient storage to create streams."," Your disk is likely full. Free space and restart:",""," docker system prune -af"," pf dev"].join(`
|
|
523
|
+
`):r.includes("connection refused")?"Cannot connect to NATS \u2014 is the container running?":Zs(t)?[`${qr} is missing or too old to provide its /streams entry point.`,""," It is a peer dependency of this CLI, so neither `bun add -g` nor `npm i -g` installs it"," alongside pf, and bun reports nothing when it is absent. Install it explicitly:","",` bun add -g ${qr}`,""," Not continuing without it: letting the services create the streams instead leaves them in"," whatever shape they already had, so a corrected contract subject never takes effect and"," its events are dropped without an error."].join(`
|
|
524
|
+
`):t},Zr=async e=>{try{let{ensureJetStreams:t}=await import("@crossdelta/cloudevents"),{indexPath:r}=x(e),o=await wd(e,{moduleCache:!1}).import(r,{default:!0}),{collectStreamDefinitions:s}=await import("@crossdelta/infrastructure/streams"),i=s(o);if(i.length===0){console.log(A.dim(" No streams found in contracts"));return}let a=Od(i);await t({streams:a});let c=i.map(l=>l.stream);console.log(A.dim(` Created ${i.length} ephemeral stream(s): ${c.join(", ")}`))}catch(t){if(!Md(t))throw console.error(A.red(`
|
|
525
|
+
\u2717 ${Dd(t)}
|
|
526
|
+
`)),t;console.log(A.yellow(` \u26A0\uFE0F Stream creation failed: ${t instanceof Error?t.message:"Unknown error"}`)),console.log(A.dim(" Streams will be created when services connect"))}};var Qs=`// env: string literals \u2192 written to .env.local by generate-env (use for values meaningful locally)
|
|
526
527
|
// containerEnv: \u2192 only applied in the K8s container, never in .env.local
|
|
527
|
-
// (use for deployment-specific values like ORIGIN or NODE_OPTIONS)`;function
|
|
528
|
+
// (use for deployment-specific values like ORIGIN or NODE_OPTIONS)`;function ei(e,t){return`import type { K8sServiceConfig } from '@crossdelta/infrastructure'
|
|
528
529
|
import { ports } from '@crossdelta/infrastructure'
|
|
529
530
|
|
|
530
531
|
/**
|
|
@@ -533,7 +534,7 @@ import { ports } from '@crossdelta/infrastructure'
|
|
|
533
534
|
* Internal-only service - accessed via cluster DNS:
|
|
534
535
|
* http://${e}.{namespace}.svc.cluster.local:${t}
|
|
535
536
|
*/
|
|
536
|
-
${
|
|
537
|
+
${Qs}
|
|
537
538
|
const config: K8sServiceConfig = {
|
|
538
539
|
name: '${e}',
|
|
539
540
|
ports: ports().http(${t}).build(),
|
|
@@ -546,7 +547,7 @@ const config: K8sServiceConfig = {
|
|
|
546
547
|
}
|
|
547
548
|
|
|
548
549
|
export default config
|
|
549
|
-
`}function
|
|
550
|
+
`}function ti(e,t){return`import type { K8sServiceConfig } from '@crossdelta/infrastructure'
|
|
550
551
|
import { ports } from '@crossdelta/infrastructure'
|
|
551
552
|
|
|
552
553
|
/**
|
|
@@ -555,7 +556,7 @@ import { ports } from '@crossdelta/infrastructure'
|
|
|
555
556
|
* Internal-only service - accessed via cluster DNS:
|
|
556
557
|
* http://${e}.{namespace}.svc.cluster.local:${t}
|
|
557
558
|
*/
|
|
558
|
-
${
|
|
559
|
+
${Qs}
|
|
559
560
|
const config: K8sServiceConfig = {
|
|
560
561
|
name: '${e}',
|
|
561
562
|
ports: ports().http(${t}).build(),
|
|
@@ -568,62 +569,62 @@ const config: K8sServiceConfig = {
|
|
|
568
569
|
}
|
|
569
570
|
|
|
570
571
|
export default config
|
|
571
|
-
`}v();import ne from"chalk";import
|
|
572
|
-
`))}};var D=()=>{try{let e=Re("bin/integration.collection.json");return
|
|
572
|
+
`}v();import ne from"chalk";import jd from"terminal-link";var Rt="integrations-run";import{z as T}from"zod";var _d=T.object({name:T.string(),description:T.string(),link:T.url().optional(),install:T.union([T.string(),T.array(T.string())]).transform(e=>Array.isArray(e)?e:[e]),installFlags:T.array(T.string()).optional(),run:T.array(T.string()).optional(),initial:T.boolean().optional(),interactive:T.boolean().optional()}),ri=T.array(_d);var ni=e=>{try{return ri.parse(e)}catch(t){throw new Error(t.issues.map(r=>` - Path ${r.path.join(". ")} : ${r.message}`).join(`
|
|
573
|
+
`))}};var D=()=>{try{let e=Re("bin/integration.collection.json");return ni(e)}catch(e){throw new Error(`Failed to load integrations!
|
|
573
574
|
Check your integration.collection.json:
|
|
574
|
-
${e.message}`)}},ye=()=>D().reduce((t,r)=>(r.initial&&t.push(r.name),t),[]),
|
|
575
|
-
`))}))},
|
|
576
|
-
`),fn:()=>
|
|
577
|
-
`)),e.shouldInstallBun=await r.toggle({message:"Would you like to use Bun? (recommended)",initial:!0}),e.shouldInstallBun&&(e.packageManager="bun")}};import
|
|
575
|
+
${e.message}`)}},ye=()=>D().reduce((t,r)=>(r.initial&&t.push(r.name),t),[]),Ld=e=>!!e?.name&&!!e?.link&&!!e?.description,Nt=e=>{let t=D();if(!t?.length||!e?.length)return;let r=e.map(n=>t.find(o=>o.name===n)).filter(Ld);r.length&&(d.breakLine().log("\u{1F50C} Installed Integrations:"),r.forEach(({name:n,link:o,description:s})=>{let i=d.getStoredLogs(`${Rt}:${n}`);o&&d.log(`${jd(ne.cyan(n),o)} - ${s}`),i.length&&d.log(i.map(a=>` \u203A ${ne.dim(a.message)}`).join(`
|
|
576
|
+
`))}))},Wd=e=>e.toUpperCase().replace(/-/g,"_"),oi=(e,t)=>{let r=Wd(e);d.breakLine().log(ne.bold("Environment variables:")).log(ne.dim(" Local (.env.local):")).log(ne.cyan(` ${r}_PORT=${t}`)).breakLine().log(ne.dim(" Production (auto-injected by infra):")).log(ne.cyan(` PORT=${t}`))};v();import si from"chalk";var Hd=e=>{let t=e.match(/^(@?[^@]+)@(.+)$/);return t?{name:t[1],version:t[2]}:{name:e,version:"latest"}},ii=async e=>{let{selectedIntegrations:t,cwd:r,packageManager:n=b(),task:o}=e;if(!t?.length||!o)return;let s=Gd(t,r,n,o);await rt(o,s)},Gd=(e,t,r,n)=>{let s=D()?.filter(a=>e.includes(a.name))?.flatMap(a=>a.install.map(c=>{let{name:l,version:p}=Hd(c);return{title:si.cyanBright(`Adding ${c} (${a.name})`),fn:async()=>{it(`dependencies.${l}`,p,t)}}})),i={title:si.cyanBright("Installing packages..."),fn:async()=>{await L({cwd:t,packageManager:r,task:n})}};return[...s??[],i]};v();import Bd from"chalk";var ai=async e=>{let{selectedIntegrations:t,cwd:r,task:n}=e;if(!t?.length||!n)return;let o=Ud(t,r,n,e.packageManager);await rt(n,o)},Ud=(e,t,r,n)=>D().filter(s=>e.includes(s.name)&&s.run?.length).flatMap(s=>(s.run||[]).map(i=>({title:Bd.cyanBright(`Running "${i}" for ${s.name}
|
|
577
|
+
`),fn:()=>zd(s,i,t,r,n)}))),zd=async(e,t,r,n,o)=>{let s=`${Rt}:${e.name}`;try{if(e.interactive)return ro(t,[],{cwd:r,context:s,task:n,manager:o});await Ne(t,[],{cwd:r,task:n,context:s})}catch(i){d.error(`Failed to run command "${t}" for ${e.name}: ${i.message}`)}};v();import{readFileSync as Zw,writeFileSync as Xw}from"fs";import{join as eP}from"path";v();import{join as oP}from"path";import{ListrEnquirerPromptAdapter as Ue}from"@listr2/prompt-adapter-enquirer";var k=e=>({select:async t=>e.prompt(Ue).run({type:"select",message:t.message,choices:t.choices}),confirm:async t=>e.prompt(Ue).run({type:"confirm",message:t.message,initial:t.initial??!1}),toggle:async t=>e.prompt(Ue).run({type:"toggle",message:t.message,enabled:t.enabled??"Yes",disabled:t.disabled??"No",initial:t.initial??!1}),input:async t=>e.prompt(Ue).run({type:"input",message:t.message,initial:t.initial,validate:t.validate}),multiSelect:async t=>e.prompt(Ue).run({type:"MultiSelect",message:t.message,hint:t.hint,initial:t.initial,choices:t.choices})});v();import{readFileSync as vP}from"fs";import{join as kP}from"path";import IP from"chalk";import NP from"cli-table3";v();function Ft(e){return e.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}async function ci(e,t,r={},n=[],o=[]){if(!e){console.error("Subcommand is not defined.");return}let s=n.map(l=>t[l]).filter(l=>l!==void 0),i=o.map(l=>{let p=t[l];if(!(p===!1||p===void 0))return p===!0?`--${Ft(String(l))}`:`--${Ft(String(l))}=${String(p)}`}).filter(l=>l!==void 0),a=Object.entries(r).map(([l,p])=>{if(!(p===!1||p===void 0))return p===!0?`--${Ft(l)}`:`--${Ft(l)}=${String(p)}`}).filter(l=>l!==void 0),c=[...s,...i,...a].map(String);await e.parseAsync(c,{from:"user"})}import{basename as fg}from"path";import oe from"chalk";f();var ve={title:"Confirm creation",enabled:e=>!e.userConfirmed,task:async(e,t)=>{let r=k(t);if(e.userConfirmed=await r.toggle({initial:!0,message:"\u{1F680} Ready to launch your project?"}),!e.userConfirmed)throw new Error("Project creation was canceled by the user.")}};import{existsSync as Xr,readdirSync as Jd,readFileSync as Kd,writeFileSync as qd}from"fs";import{basename as Yd,join as Qr}from"path";var Zd=4001,Xd=4e3;function Qd(e){let t=[],r=e.matchAll(/ports\(\)\.(?:http|https|grpc|primary)\((\d+)\)/g);for(let c of r)t.push(Number(c[1]));let n=e.matchAll(/\.add(?:Http|Grpc)?\((\d+)/g);for(let c of n)t.push(Number(c[1]));let o=e.match(/containerPort\s*:\s*(\d+)/);o&&t.push(Number(o[1]));let s=e.match(/internalPorts\s*:\s*\[([^\]]+)\]/);if(s){let c=s[1].match(/\d+/g);c&&t.push(...c.map(Number))}let i=e.match(/httpPort\s*:\s*(\d+)/);i&&t.push(Number(i[1]));let a=e.matchAll(/const\s+\w*[pP]ort\w*\s*=\s*(\d+)/g);for(let c of a)t.push(Number(c[1]));return t}function eg(e,t){let r=t?Zd:Xd,n=new Set;if(!Xr(e))return r;let o=Jd(e).filter(i=>i.endsWith(".ts"));for(let i of o){let a=Qr(e,i);try{let c=Kd(a,"utf-8"),l=Qd(c);for(let p of l)n.add(p)}catch{}}let s=r;for(;n.has(s);)s++;return s}function tg(e){return Yd(e)}var Ot={title:"Creating infrastructure service config",task:async(e,t)=>{let r=tg(e.projectName),n=g(),o=Qr(n,"infra","services");if(!Xr(o)){t.title="Skipping infra config (no infra/services directory found)";return}let s=Qr(o,`${r}.ts`);if(Xr(s)){t.title=`Service config already exists: infra/services/${r}.ts`;return}let i=eg(o,!0);e.assignedPort=i;let a=e.serviceType==="hono"?ei(r,i):ti(r,i);qd(s,a),t.title=`Created infra/services/${r}.ts (port: ${i})`}};import{execSync as Mt}from"child_process";import{existsSync as rg}from"fs";import{join as ng}from"path";var og=()=>{try{return Mt("git --version",{stdio:"ignore"}),!0}catch{return!1}},sg=e=>rg(ng(e,".git")),li={title:"Initializing git repository",enabled:()=>og(),skip:e=>sg(e.cwd)?"Already a git repository":!1,task:async(e,t)=>{try{Mt("git init",{cwd:e.cwd,stdio:"ignore"}),Mt("git add -A",{cwd:e.cwd,stdio:"ignore"}),Mt('git commit -m "chore: initial commit"',{cwd:e.cwd,stdio:"ignore",env:{...process.env,GIT_AUTHOR_NAME:process.env.GIT_AUTHOR_NAME||"Platform SDK",GIT_AUTHOR_EMAIL:process.env.GIT_AUTHOR_EMAIL||"platform-sdk@localhost",GIT_COMMITTER_NAME:process.env.GIT_COMMITTER_NAME||"Platform SDK",GIT_COMMITTER_EMAIL:process.env.GIT_COMMITTER_EMAIL||"platform-sdk@localhost"}}),t.title="Git repository initialized with initial commit"}catch{t.title="Git initialization skipped (git error)"}}};import pi from"chalk";v();var Ce={title:"Installing Bun",enabled:e=>!!e.shouldInstallBun&&!Rr(),task:async(e,t)=>M(t,async r=>{await rs(t),e.elapsedTime+=r(),t.title=`Bun installed successfully. (${e.elapsedTime}s)`})},ke={enabled:e=>!Rr()&&!e.shouldInstallBun&&!e.packageManager,task:async(e,t)=>{let r=k(t);console.log(["",`${pi.magenta.bold("Bun")} is a fast JavaScript runtime, package manager, bundler, and test runner: ${pi.underline("https://bun.sh")}`,ns(),os()].join(`
|
|
578
|
+
`)),e.shouldInstallBun=await r.toggle({message:"Would you like to use Bun? (recommended)",initial:!0}),e.shouldInstallBun&&(e.packageManager="bun")}};import mi from"chalk";v();var Dt={title:"Install integrations",enabled:e=>e.selectedIntegrations.length>0,task:async(e,t)=>M(t,async r=>{let{selectedIntegrations:n,cwd:o,packageManager:s}=e;await ii({selectedIntegrations:n,packageManager:s,cwd:o,task:t}),e.elapsedTime+=r()}),rendererOptions:{outputBar:1e3}},_t={title:"Select integrations",enabled:e=>e.selectedIntegrations.length===0,task:async(e,t)=>{let r=k(t);e.selectedIntegrations=await r.multiSelect({hint:"\\nPress <space> to select/deselect, <enter> to confirm, <i> to invert selection",message:"Which integrations would you like to include?",initial:ye().map((n,o)=>o),choices:e.availableIntegrations.map(({name:n,description:o})=>({name:n,message:[mi.bold(n),o].join(" - "),value:n}))}),!e.selectedIntegrations||e.selectedIntegrations.length===0?t.title="No integrations selected.":t.title=["Selected integrations:",...e.selectedIntegrations.map(n=>mi.bold(`\u2022 ${n}`))].join("\\n")}};v();var di={title:"Install Nest CLI",task:async(e,t)=>M(t,async r=>{await to({packages:["@nestjs/cli"],task:t,cwd:e.cwd}),e.elapsedTime+=r()}),rendererOptions:{outputBar:1e3}};v();var jt={title:"Install dependencies",task:async(e,t)=>M(t,async r=>{await L({cwd:e.cwd,task:t,packageManager:e.packageManager}),e.elapsedTime+=r()})};import ig from"chalk";v();var xe={enabled:e=>!e.removeDir&&!et(e.cwd),task:async(e,t)=>{let r=k(t);if(e.removeDir=await r.toggle({message:ig.bold("\u26A0\uFE0F Overwrite existing directory?"),initial:!1}),!e.removeDir)throw new Error("Project creation was canceled by the user.")}},we={enabled:e=>!!e.removeDir,task:async e=>Ln(e.cwd)};v();var Lt={title:"Run integration commands",enabled:e=>e.selectedIntegrations.length>0,task:async(e,t)=>M(t,async r=>{let{selectedIntegrations:n,cwd:o}=e;await ai({selectedIntegrations:n,cwd:o,task:t,packageManager:e.packageManager}),e.elapsedTime+=r()}),rendererOptions:{outputBar:1}};v();var ag=["services/my-hono-service","services/my-nest-service","my-platform"],Pe={enabled:e=>e.skipInputPrompts||e.userConfirmed?!1:e.projectName?ag.includes(e.projectName):!0,task:async(e,t)=>{let r=k(t);e.projectName=await r.input({initial:e.projectName,message:"Enter project name",validate:n=>n?!0:"Project name is required."}),e.cwd&&(e.cwd=O(e.projectName))}};import gi from"chalk";var Se={title:"Select Package manager",task:async(e,t)=>{if(e.packageManager??=dr(),e.packageManager){t.title=`Using ${gi.bold(e.packageManager)} as package manager.`;return}let r=k(t);e.packageManager=await r.select({message:"Which package manager would you like to use?",choices:eo().map(n=>({name:n,value:n}))}),t.title=`Using ${gi.bold(e.packageManager)} as package manager.`}};import Wt from"chalk";var ui={title:"GitHub repository owner",task:async(e,t)=>{if(e.githubOwner){t.title=`GitHub owner: ${Wt.bold(e.githubOwner)}`;return}let r=k(t);e.githubOwner=await r.input({message:"Enter GitHub organization or username",initial:"my-org",validate:n=>n?.trim()?!0:"GitHub owner is required."}),t.title=`GitHub owner: ${Wt.bold(e.githubOwner)}`}},fi={title:"Include GitHub CI/CD",task:async(e,t)=>{if(e.includeGitHubCI!==void 0){t.title=e.includeGitHubCI?"Including GitHub CI/CD workflows":"Skipping GitHub CI/CD";return}let r=k(t);e.includeGitHubCI=await r.toggle({message:"Include GitHub Actions workflows and CI/CD?",initial:!0,enabled:"Yes",disabled:"No"}),t.title=e.includeGitHubCI?"Including GitHub CI/CD workflows":"Skipping GitHub CI/CD"}};var hi={title:"Pulumi stack name",task:async(e,t)=>{if(e.pulumiStackBase){t.title=`Pulumi stack: ${Wt.bold(e.pulumiStackBase)}`;return}let r=e.githubOwner||"myorg",n=e.projectName?.replace(/[^a-zA-Z0-9-]/g,"-")||"myproject",o=`${r}/${n}`,s=k(t);e.pulumiStackBase=await s.input({message:"Enter Pulumi stack base name (org/project)",initial:o,validate:i=>i?.trim()?i.includes("/")?!0:"Format should be org/project (e.g., myorg/myproject)":"Pulumi stack name is required."}),t.title=`Pulumi stack: ${Wt.bold(e.pulumiStackBase)}`}};v();import{mkdirSync as cg,writeFileSync as lg}from"fs";import{dirname as pg}from"path";v();var mg=e=>e==="hono"?"hono":"nestjs",dg=e=>{let t=pg(e.path);cg(t,{recursive:!0}),lg(e.path,e.content,"utf-8")},gg=(e,t)=>{let r=e.map(o=>{let s=o.path.match(/services\/[^/]+\/(.+)$/);return{path:s?s[1]:o.path,content:o.content}}),n=At(t,r);if(!n.valid){let o=n.violations.map(s=>` - ${s.code}: ${s.message} (${s.path})`).join(`
|
|
578
579
|
`);throw new Error(`Policy violation(s) detected:
|
|
579
|
-
${o}`)}e.forEach(
|
|
580
|
-
${oe.bold(`cd ${e} && ${o} run dev`)}`).breakLine().log("Happy shipping with Hono! \u26A1\uFE0F").breakLine()}});import se from"chalk";f();v();var
|
|
581
|
-
${se.bold(`cd ${e} && ${t} run start:dev`)}`).breakLine().log("Happy coding! \u{1F389}").breakLine()}});import _ from"chalk";v();import{spawnSync as Cg}from"child_process";import{chmodSync as kg,existsSync as tn,mkdirSync as xg,readFileSync as wg,writeFileSync as rn}from"fs";import{dirname as Pg,join as nn}from"path";import{existsSync as yg}from"fs";import{join as Gt}from"path";var vg=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),en=()=>{let e=vg(),t=ee();return fe([Gt(e,"templates","workspace"),Gt(e,"..","..","..","..","templates","workspace"),Gt(t,"bin","templates","workspace")],"Workspace templates directory not found.")},hi=()=>{let e=en(),t=Gt(e,"packages","contracts");if(!yg(t))throw new Error(`Contracts templates directory not found at: ${t}`);return t},Bt=(e,t)=>Gr(e,t);var yi=e=>{e.endsWith(".sh")&&kg(e,493)},Sg=[{template:"package.json.hbs",output:"package.json"},{template:"tsconfig.json.hbs",output:"tsconfig.json"},{template:"pnpm-workspace.yaml.hbs",output:"pnpm-workspace.yaml",forPackageManager:"pnpm"},{template:"biome.json.hbs",output:"biome.json"},{template:"turbo.json.hbs",output:"turbo.json"},{template:"bunfig.toml.hbs",output:"bunfig.toml"},{template:"gitignore.hbs",output:".gitignore"},{template:"editorconfig.hbs",output:".editorconfig"},{template:"npmrc.hbs",output:".npmrc"},{template:".vscode/settings.json",output:".vscode/settings.json",isStatic:!0},{template:".vscode/extensions.json",output:".vscode/extensions.json",isStatic:!0},{template:"infra/package.json.hbs",output:"infra/package.json"},{template:"infra/index.ts.hbs",output:"infra/index.ts"},{template:"infra/tsconfig.json.hbs",output:"infra/tsconfig.json"},{template:"infra/Pulumi.yaml.hbs",output:"infra/Pulumi.yaml"},{template:"infra/Pulumi.dev.yaml.hbs",output:"infra/Pulumi.dev.yaml"},{template:"apps/.gitkeep",output:"apps/.gitkeep",isStatic:!0},{template:"services/.gitkeep",output:"services/.gitkeep",isStatic:!0},{template:"packages/.gitkeep",output:"packages/.gitkeep",isStatic:!0},{template:"docs/.gitkeep",output:"docs/.gitkeep",isStatic:!0},{template:"infra/services/.gitkeep",output:"infra/services/.gitkeep",isStatic:!0},{template:".github/README.md",output:".github/README.md",isStatic:!0,isGitHubCI:!0},{template:".github/dependabot.yml",output:".github/dependabot.yml",isStatic:!0,isGitHubCI:!0},{template:".github/workflows/lint-and-tests.yml.hbs",output:".github/workflows/lint-and-tests.yml",isGitHubCI:!0},{template:".github/workflows/build-and-deploy.yml.hbs",output:".github/workflows/build-and-deploy.yml",isGitHubCI:!0},{template:".github/workflows/publish-packages.yml",output:".github/workflows/publish-packages.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/setup-bun-install/action.yml.hbs",output:".github/actions/setup-bun-install/action.yml",isGitHubCI:!0},{template:".github/actions/check-image-tag-exists/action.yml",output:".github/actions/check-image-tag-exists/action.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/check-image-tag-exists/index.js",output:".github/actions/check-image-tag-exists/index.js",isStatic:!0,isGitHubCI:!0},{template:".github/actions/generate-scope-matrix/action.yml",output:".github/actions/generate-scope-matrix/action.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/generate-scope-matrix/index.js",output:".github/actions/generate-scope-matrix/index.js",isStatic:!0,isGitHubCI:!0},{template:".github/actions/prepare-build-context/action.yml",output:".github/actions/prepare-build-context/action.yml",isStatic:!0,isGitHubCI:!0},{template:"CLAUDE.md",output:"CLAUDE.md",isStatic:!0},{template:".claude/rules/cloudevents.md",output:".claude/rules/cloudevents.md",isStatic:!0}],vi={title:"Creating workspace structure",task:async(e,t)=>{if(tn(e.cwd)){t.title="Workspace directory already exists, skipping...";return}let r=en(),n=e.includeGitHubCI??!0,o=e.packageManager||"bun",s=c=>{try{let m=Cg(c,["--version"],{encoding:"utf-8",timeout:5e3}).stdout?.trim();if(m&&/^\d+\.\d+/.test(m))return`${c}@${m}`}catch{}return{bun:"bun@1.2.7",npm:"npm@10.9.2",yarn:"yarn@4.6.0",pnpm:"pnpm@9.15.2"}[c]||`${c}@latest`},i={projectName:e.projectName,scope:`@${e.projectName}`,githubOwner:e.githubOwner||"",pulumiStackBase:e.pulumiStackBase||e.projectName,packageManager:o,packageManagerVersion:s(o)},a=Sg.filter(c=>!(c.isGitHubCI&&!n||c.forPackageManager&&c.forPackageManager!==o));for(let c of a){let l=nn(e.cwd,c.output),p=Pg(l);if(tn(p)||xg(p,{recursive:!0}),c.isStatic){let m=nn(r,c.template);tn(m)?rn(l,wg(m)):rn(l,""),yi(l)}else{let m=nn(r,c.template),y=Bt(m,i);rn(l,y),yi(l)}}t.title="Workspace structure created"}};f();import{existsSync as ki,mkdirSync as Ci,readFileSync as bg,writeFileSync as Eg}from"fs";import{join as Ut}from"path";import Tg from"chalk";var $g=()=>{let e=Ut(process.cwd(),"package.json");if(!ki(e))throw new Error("Root package.json not found. Please run this command from the workspace root.");let r=JSON.parse(bg(e,"utf-8")).name;if(!r)throw new Error('package.json must have a "name" field');return r.startsWith("@")?r:`@${r}`},Ag=()=>{let e=$g(),{relativePath:t,packagePath:r}=x();if(ki(r))throw new Error(`${t} already exists. Remove it first if you want to regenerate.`);let n=hi(),o={scope:e,workspaceName:e.replace("@","").replace("/","-")};Ci(r,{recursive:!0}),Ci(Ut(r,"src","events"),{recursive:!0});let s=[{template:"package.json.hbs",output:"package.json"},{template:"tsconfig.json.hbs",output:"tsconfig.json"},{template:"tsup.config.ts",output:"tsup.config.ts"},{template:"README.md.hbs",output:"README.md"},{template:"src/index.ts",output:"src/index.ts"},{template:"src/stream-policies.ts.hbs",output:"src/stream-policies.ts"},{template:"src/events/index.ts",output:"src/events/index.ts"}];for(let i of s){let a=Ut(n,i.template),c=Ut(r,i.output),l=Bt(a,o);Eg(c,l,"utf-8")}},xi={title:"Initializing contracts package",task:(e,t)=>{let r=process.cwd();try{process.chdir(e.cwd),Ag(),t.title="Contracts package initialized"}catch(n){throw t.title=Tg.red(`Contracts package failed: ${n.message}`),n}finally{process.chdir(r)}}};import Ig from"chalk";var wi={title:"Registering shell completion",task:async(e,t)=>{let r=process.cwd();try{process.chdir(e.cwd),await He(),t.title="Shell completion registered"}catch{t.title=Ig.dim("Shell completion skipped")}finally{process.chdir(r)}}};var Pi=J({name:"workspace",description:"Create a new workspace with infrastructure setup",arguments:[["[name]","Name or path of the workspace"]],options:[["-P, --package-manager <manager>","Specify the package manager (e.g., npm, yarn, pnpm, bun)"],["-y, --yes","Skip all prompts and use default values"],["-o, --github-owner <owner>","GitHub organization or username"],["-s, --pulumi-stack <name>","Pulumi stack base name (org/project)"],["--no-github","Skip GitHub CI/CD workflows"],["--remove-dir","Remove existing directory before creating (internal use)"]],exampleUsage:"pf new workspace my-platform -o my-org",buildContext:(e,t)=>{let r=(e.name??"my-platform").trim(),n=O(r),o=!!t.yes,s=t.packageManager??(o?b():void 0),i=t.packageManager==="bun",a=t.githubOwner??(o?"my-org":void 0),c=t.pulumiStack??(o?`${a}/${r}`:void 0),l=t.github===!1?!1:o?!0:void 0,p=!!e.name,m=t.removeDir||o;return{cwd:n,projectName:r,shouldInstallBun:i,packageManager:s,elapsedTime:0,userConfirmed:o,skipInputPrompts:p&&!o,removeDir:m,githubOwner:a,pulumiStackBase:c,includeGitHubCI:l}},prompts:[{enabled:e=>!e.userConfirmed,task:async(e,t)=>{try{let r=g();if(!await k(t).toggle({message:`\u26A0\uFE0F You are inside an existing workspace (${r}). Create a nested workspace anyway?`,initial:!1}))throw new Error("Workspace creation cancelled - already inside a workspace");t.title=_.yellow("Warning: Creating nested workspace")}catch(r){if(X(r)&&r.message?.includes("cancelled"))throw r;t.title="No existing workspace detected"}}},Pe,xe,mi,di,gi,ke,Se,ve],actions:[we,Ce,vi,xi,jt,ii,wi],onComplete:({projectName:e,includeGitHubCI:t})=>{d.breakLine().log(_.bold.green("Workspace created successfully!")),d.breakLine().log(_.bold("Next steps:")).log(` 1. ${_.cyan(`cd ${e}`)}`).log(` 2. ${_.cyan("exec $SHELL")} ${_.dim("(enable tab completion)")}`),t&&d.breakLine().log(_.bold("GitHub Setup:")).log(" Configure these secrets in your GitHub repository:").log(` \u2022 ${_.yellow("PULUMI_ACCESS_TOKEN")} - Pulumi Cloud access token`).log(` \u2022 ${_.yellow("DIGITALOCEAN_TOKEN")} - DigitalOcean API token`).log(` \u2022 ${_.yellow("NPM_TOKEN")} - (optional) NPM token for private packages`),d.breakLine().log(_.bold("Structure created:")).log(" apps/ # Frontend applications").log(" services/ # Backend microservices").log(" packages/").log(" \u2514\u2500\u2500 contracts/ # Shared event contracts").log(" infra/").log(" \u251C\u2500\u2500 index.ts # Pulumi entry point").log(" \u251C\u2500\u2500 services/ # Service configs").log(" \u251C\u2500\u2500 Pulumi.yaml # Pulumi project config").log(" \u2514\u2500\u2500 Pulumi.dev.yaml # Dev stack config"),t&&d.log(" .github/").log(" \u251C\u2500\u2500 workflows/ # CI/CD workflows").log(" \u2514\u2500\u2500 actions/ # Custom actions"),d.breakLine().log("Happy coding! \u{1F389}").breakLine()}});var ze=[{name:"Hono Microservice",value:"hono-micro",command:ui,supportsAi:!0},{name:"Nest Microservice",value:"nest-micro",command:fi,supportsAi:!0},{name:"Workspace (Infrastructure)",value:"workspace",command:Pi,supportsAi:!1}],Si=()=>{let e=J({name:"new",description:"Create a new project",arguments:[["[type]","Type of the project (e.g., nest-micro, hono-micro, workspace)"]],exampleUsage:"platform new hono-micro test-service",buildContext:t=>({projectType:t.type??"",useAi:!1,aiDescription:"",elapsedTime:0,cwd:process.cwd()}),prompts:[{enabled:t=>!t.projectType,task:async(t,r)=>{let o=await k(r).select({message:"Select Project type",choices:ze});t.projectType=ze.find(s=>s.name===o)?.value||"",r.title=`Using ${q.bold(o)}`}},{enabled:t=>t.projectType!=="workspace"&&t.projectType!=="",task:async(t,r)=>{try{g(),r.title="Workspace detected"}catch{let n=["Not in a workspace directory","",`Current directory: ${process.cwd()}`,"","This command must be run from within a workspace created with pf new workspace","","To create a new workspace, run:",""," pf new workspace my-platform"].join(`
|
|
582
|
-
`);throw new Error(n)}}},{enabled:t=>t.projectType==="workspace",task:async(t,r)=>{try{let n=g();if(!await k(r).toggle({message:`\u26A0\uFE0F You are inside an existing workspace (${n}). Create a nested workspace anyway?`,initial:!1}))throw new Error("Workspace creation cancelled - already inside a workspace");r.title=q.yellow("Warning: Creating nested workspace")}catch(n){if(X(n)&&n.message?.includes("cancelled"))throw n;r.title="No existing workspace detected"}}},{enabled:t=>!!t.projectType,task:async(t,r)=>{let o={"hono-micro":"services/my-hono-service","nest-micro":"services/my-nest-service",workspace:"my-platform"}[t.projectType]||"my-project",s=t.projectType==="workspace"?"\u{1F4E6} Workspace name:":"\u{1F4E6} Service path (e.g., services/my-service):",a=await k(r).input({message:s,initial:o});t.servicePath=a.trim(),r.title=`Path: ${q.dim(a)}`}},{enabled:t=>!!ze.find(n=>n.value===t.projectType)?.supportsAi&&de().valid,task:async(t,r)=>{let o=await k(r).toggle({message:"Use AI to generate service code?",initial:!1});t.useAi=o,r.title=o?q.cyan("\u{1F916} AI-powered generation"):"Standard scaffolding"}},{enabled:t=>t.useAi,task:async(t,r)=>{let o=await k(r).input({message:"Describe what this service should do:"});t.aiDescription=o,r.title=`Description: ${q.dim(o.slice(0,50))}${o.length>50?"...":""}`}},{enabled:t=>{if(!t.servicePath)return!1;let r=O(t.servicePath);return!et(r)},task:async(t,r)=>{if(!await k(r).toggle({message:q.bold("\u26A0\uFE0F Overwrite existing directory?"),initial:!1}))throw new Error("Project creation was canceled by the user.");t.shouldRemoveDir=!0,r.title=q.yellow("Will overwrite existing directory")}},{title:"Confirm creation",enabled:t=>t.projectType!=="workspace",task:async(t,r)=>{if(!await k(r).toggle({message:"\u{1F680} Ready to launch your project?",initial:!0}))throw new Error("Project creation was canceled by the user.")}}],actions:[],onComplete:async t=>{ze.find(s=>s.value===t.projectType)||e.error(q.red(`Project type ${t.projectType} is not supported.`));let r=e.commands.find(s=>s.name()===t.projectType),n={};t.projectType!=="workspace"&&(n.yes=!0);let o=[];t.servicePath&&o.push("servicePath"),t.shouldRemoveDir&&(n.removeDir=!0),t.useAi&&(n.ai=!0,n.description=t.aiDescription),await
|
|
583
|
-
\u{1F4E6} Contracts changed, updating streams...`),await
|
|
584
|
-
`),
|
|
580
|
+
${o}`)}e.forEach(dg)},ug=async(e,t,r)=>{let{projectName:n,serviceType:o,hasEvents:s,streams:i}=e,a=n.split("/").pop()||n,l=qs({type:o==="hono"?"hono-micro":"nest",name:a,path:n,hasEvents:s,streams:i}),p=l.effects.filter(y=>y.kind==="file:write"),m=mg(o);gg(p,m),e.assignedPort=l.port,e.elapsedTime+=r(),t.title=`Generated ${a} (port ${l.port}, ${e.elapsedTime}s)`},Ht={title:"Generating service",task:async(e,t)=>M(t,async r=>{await ug(e,t,r)})};var hg=e=>{let t=(e||"my-hono-service").trim();return t.includes("/")||t.startsWith(".")?t:`${E().services}/${t}`},yg=async(e,t)=>{let{valid:r,config:n,error:o}=de();if(!r||!n){$(new Error(o||"AI configuration is invalid"),{exit:!1});return}let s=hg(e.name),i=t.packageManager||b(),a=await ft(t.description);if(ht(s,n,a),await yt({servicePath:s,description:a,serviceType:"hono",packageManager:i},n))d.breakLine().success("Service generated successfully!").breakLine().log(oe.dim("Next steps:")).log(oe.dim(` ${oe.cyan("pf dev")} - Start all services`)).log(oe.dim(` ${oe.cyan(`cd ${s} && bun dev`)} - Start this service only`)).breakLine();else throw new Error("Service generation failed")},yi=J({name:"hono-micro",description:"Create a new Hono microservice with the Crossdelta setup. Use --ai for AI-powered generation.",arguments:[["[name]","Name or path of the service"]],options:[["-P, --package-manager <manager>","Specify the package manager (e.g., npm, yarn, pnpm, bun)"],["-y, --yes","Skip all prompts and use default values"],["--ai","Use AI to generate service code based on a description"],["-d, --description <description>","Service description for AI generation (requires --ai)"],["--remove-dir","Remove existing directory before creating (used internally)"]],exampleUsage:'platform new hono-micro my-service --ai -d "Payment processing service"',shouldSkipWorkflow:(e,t)=>!!t.ai,onSkipWorkflow:yg,buildContext:async(e,t)=>{let r=(e.name??"my-hono-service").trim();!r.includes("/")&&!r.startsWith(".")&&(r=`${E().services}/${r}`);let n=O(r),o=t.packageManager??(t.yes&&b()),s=D(),i=t.yes?ye():[],a=t.packageManager==="bun",c=!!t.yes||!!e.name&&e.name!=="my-hono-service";return{cwd:n,projectName:r,packageManager:o,shouldInstallBun:a,availableIntegrations:s,selectedIntegrations:i,serviceType:"hono",elapsedTime:0,userConfirmed:!!t.yes,skipInputPrompts:c,removeDir:!!t.removeDir||!!t.yes}},prompts:[Pe,xe,ke,Se,_t,ve],actions:[we,Ce,Ht,Ot,Dt,Lt],onComplete:({projectName:e,packageManager:t,selectedIntegrations:r,assignedPort:n})=>{d.breakLine().log(oe.bold.green("Hono Microservice created successfully!")),Nt(r),oi(fg(e),n??8080);let o=t??b();d.breakLine().log(`To start the project, run:
|
|
581
|
+
${oe.bold(`cd ${e} && ${o} run dev`)}`).breakLine().log("Happy shipping with Hono! \u26A1\uFE0F").breakLine()}});import se from"chalk";f();v();var vg=e=>{let t=(e||"my-nest-service").trim();return t.includes("/")||t.startsWith(".")?t:`${E().services}/${t}`},Cg=async(e,t)=>{let{valid:r,config:n,error:o}=de();if(!r||!n){$(new Error(o||"AI configuration is invalid"),{exit:!1});return}let s=vg(e.name),i=t.packageManager||b(),a=await ft(t.description);if(ht(s,n,a),await yt({servicePath:s,description:a,serviceType:"nest",packageManager:i},n))d.breakLine().success("Service generated successfully!").breakLine().log(se.dim("Next steps:")).log(se.dim(` ${se.cyan("pf dev")} - Start all services`)).log(se.dim(` ${se.cyan(`cd ${s} && bun run start:dev`)} - Start this service only`)).breakLine();else throw new Error("Service generation failed")},vi=J({name:"nest-micro",description:"Create a new NestJS microservice with the Crossdelta setup. Use --ai for AI-powered generation.",arguments:[["[name]","Name or path of the service"]],options:[["-P, --package-manager <manager>","Specify the package manager (e.g., npm, yarn, pnpm, bun)"],["-y, --yes","Skip all prompts and use default values"],["--ai","Use AI to generate service code based on a description"],["-d, --description <description>","Service description for AI generation (requires --ai)"],["--remove-dir","Remove existing directory before creating (used internally)"]],exampleUsage:'platform new nest-micro my-service --ai -d "User authentication service"',shouldSkipWorkflow:(e,t)=>!!t.ai,onSkipWorkflow:Cg,buildContext:async(e,t)=>{let r=(e.name??"my-nest-service").trim();!r.includes("/")&&!r.startsWith(".")&&(r=`${E().services}/${r}`);let n=O(r),o=t.packageManager??(t.yes&&b()),s=t.packageManager==="bun",i=D(),a=t.yes?ye():[],c=!!t.yes||!!e.name;return{cwd:n,projectName:r,shouldInstallBun:s,packageManager:o,availableIntegrations:i,selectedIntegrations:a,serviceType:"nest",elapsedTime:0,userConfirmed:!!t.yes,skipInputPrompts:c,removeDir:!!t.removeDir||!!t.yes}},prompts:[Pe,xe,ke,Se,_t,ve],actions:[we,Ce,Ht,Ot,jt,di,Dt,Lt],onComplete:({projectName:e,packageManager:t,selectedIntegrations:r})=>{d.breakLine().log(se.bold.green("NestJS Microservice created successfully!")),Nt(r),d.breakLine().log(`To start the project, run:
|
|
582
|
+
${se.bold(`cd ${e} && ${t} run start:dev`)}`).breakLine().log("Happy coding! \u{1F389}").breakLine()}});import _ from"chalk";v();import{spawnSync as wg}from"child_process";import{chmodSync as Pg,existsSync as rn,mkdirSync as Sg,readFileSync as bg,writeFileSync as nn}from"fs";import{dirname as Eg,join as on}from"path";import{existsSync as kg}from"fs";import{join as Gt}from"path";var xg=()=>typeof import.meta?.url=="string"?W(import.meta.url):typeof __dirname=="string"?__dirname:process.cwd(),tn=()=>{let e=xg(),t=ee();return fe([Gt(e,"templates","workspace"),Gt(e,"..","..","..","..","templates","workspace"),Gt(t,"bin","templates","workspace")],"Workspace templates directory not found.")},Ci=()=>{let e=tn(),t=Gt(e,"packages","contracts");if(!kg(t))throw new Error(`Contracts templates directory not found at: ${t}`);return t},Bt=(e,t)=>Gr(e,t);var ki=e=>{e.endsWith(".sh")&&Pg(e,493)},Tg=[{template:"package.json.hbs",output:"package.json"},{template:"tsconfig.json.hbs",output:"tsconfig.json"},{template:"pnpm-workspace.yaml.hbs",output:"pnpm-workspace.yaml",forPackageManager:"pnpm"},{template:"biome.json.hbs",output:"biome.json"},{template:"turbo.json.hbs",output:"turbo.json"},{template:"bunfig.toml.hbs",output:"bunfig.toml"},{template:"gitignore.hbs",output:".gitignore"},{template:"editorconfig.hbs",output:".editorconfig"},{template:"npmrc.hbs",output:".npmrc"},{template:".vscode/settings.json",output:".vscode/settings.json",isStatic:!0},{template:".vscode/extensions.json",output:".vscode/extensions.json",isStatic:!0},{template:"infra/package.json.hbs",output:"infra/package.json"},{template:"infra/index.ts.hbs",output:"infra/index.ts"},{template:"infra/tsconfig.json.hbs",output:"infra/tsconfig.json"},{template:"infra/Pulumi.yaml.hbs",output:"infra/Pulumi.yaml"},{template:"infra/Pulumi.dev.yaml.hbs",output:"infra/Pulumi.dev.yaml"},{template:"apps/.gitkeep",output:"apps/.gitkeep",isStatic:!0},{template:"services/.gitkeep",output:"services/.gitkeep",isStatic:!0},{template:"packages/.gitkeep",output:"packages/.gitkeep",isStatic:!0},{template:"docs/.gitkeep",output:"docs/.gitkeep",isStatic:!0},{template:"infra/services/.gitkeep",output:"infra/services/.gitkeep",isStatic:!0},{template:".github/README.md",output:".github/README.md",isStatic:!0,isGitHubCI:!0},{template:".github/dependabot.yml",output:".github/dependabot.yml",isStatic:!0,isGitHubCI:!0},{template:".github/workflows/lint-and-tests.yml.hbs",output:".github/workflows/lint-and-tests.yml",isGitHubCI:!0},{template:".github/workflows/build-and-deploy.yml.hbs",output:".github/workflows/build-and-deploy.yml",isGitHubCI:!0},{template:".github/workflows/publish-packages.yml",output:".github/workflows/publish-packages.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/setup-bun-install/action.yml.hbs",output:".github/actions/setup-bun-install/action.yml",isGitHubCI:!0},{template:".github/actions/check-image-tag-exists/action.yml",output:".github/actions/check-image-tag-exists/action.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/check-image-tag-exists/index.js",output:".github/actions/check-image-tag-exists/index.js",isStatic:!0,isGitHubCI:!0},{template:".github/actions/generate-scope-matrix/action.yml",output:".github/actions/generate-scope-matrix/action.yml",isStatic:!0,isGitHubCI:!0},{template:".github/actions/generate-scope-matrix/index.js",output:".github/actions/generate-scope-matrix/index.js",isStatic:!0,isGitHubCI:!0},{template:".github/actions/prepare-build-context/action.yml",output:".github/actions/prepare-build-context/action.yml",isStatic:!0,isGitHubCI:!0},{template:"CLAUDE.md",output:"CLAUDE.md",isStatic:!0},{template:".claude/rules/cloudevents.md",output:".claude/rules/cloudevents.md",isStatic:!0}],xi={title:"Creating workspace structure",task:async(e,t)=>{if(rn(e.cwd)){t.title="Workspace directory already exists, skipping...";return}let r=tn(),n=e.includeGitHubCI??!0,o=e.packageManager||"bun",s=c=>{try{let m=wg(c,["--version"],{encoding:"utf-8",timeout:5e3}).stdout?.trim();if(m&&/^\d+\.\d+/.test(m))return`${c}@${m}`}catch{}return{bun:"bun@1.2.7",npm:"npm@10.9.2",yarn:"yarn@4.6.0",pnpm:"pnpm@9.15.2"}[c]||`${c}@latest`},i={projectName:e.projectName,scope:`@${e.projectName}`,githubOwner:e.githubOwner||"",pulumiStackBase:e.pulumiStackBase||e.projectName,packageManager:o,packageManagerVersion:s(o)},a=Tg.filter(c=>!(c.isGitHubCI&&!n||c.forPackageManager&&c.forPackageManager!==o));for(let c of a){let l=on(e.cwd,c.output),p=Eg(l);if(rn(p)||Sg(p,{recursive:!0}),c.isStatic){let m=on(r,c.template);rn(m)?nn(l,bg(m)):nn(l,""),ki(l)}else{let m=on(r,c.template),y=Bt(m,i);nn(l,y),ki(l)}}t.title="Workspace structure created"}};f();import{existsSync as Pi,mkdirSync as wi,readFileSync as $g,writeFileSync as Ag}from"fs";import{join as Ut}from"path";import Ig from"chalk";var Rg=()=>{let e=Ut(process.cwd(),"package.json");if(!Pi(e))throw new Error("Root package.json not found. Please run this command from the workspace root.");let r=JSON.parse($g(e,"utf-8")).name;if(!r)throw new Error('package.json must have a "name" field');return r.startsWith("@")?r:`@${r}`},Ng=()=>{let e=Rg(),{relativePath:t,packagePath:r}=x();if(Pi(r))throw new Error(`${t} already exists. Remove it first if you want to regenerate.`);let n=Ci(),o={scope:e,workspaceName:e.replace("@","").replace("/","-")};wi(r,{recursive:!0}),wi(Ut(r,"src","events"),{recursive:!0});let s=[{template:"package.json.hbs",output:"package.json"},{template:"tsconfig.json.hbs",output:"tsconfig.json"},{template:"tsup.config.ts",output:"tsup.config.ts"},{template:"README.md.hbs",output:"README.md"},{template:"src/index.ts",output:"src/index.ts"},{template:"src/stream-policies.ts.hbs",output:"src/stream-policies.ts"},{template:"src/events/index.ts",output:"src/events/index.ts"}];for(let i of s){let a=Ut(n,i.template),c=Ut(r,i.output),l=Bt(a,o);Ag(c,l,"utf-8")}},Si={title:"Initializing contracts package",task:(e,t)=>{let r=process.cwd();try{process.chdir(e.cwd),Ng(),t.title="Contracts package initialized"}catch(n){throw t.title=Ig.red(`Contracts package failed: ${n.message}`),n}finally{process.chdir(r)}}};import Fg from"chalk";var bi={title:"Registering shell completion",task:async(e,t)=>{let r=process.cwd();try{process.chdir(e.cwd),await He(),t.title="Shell completion registered"}catch{t.title=Fg.dim("Shell completion skipped")}finally{process.chdir(r)}}};var Ei=J({name:"workspace",description:"Create a new workspace with infrastructure setup",arguments:[["[name]","Name or path of the workspace"]],options:[["-P, --package-manager <manager>","Specify the package manager (e.g., npm, yarn, pnpm, bun)"],["-y, --yes","Skip all prompts and use default values"],["-o, --github-owner <owner>","GitHub organization or username"],["-s, --pulumi-stack <name>","Pulumi stack base name (org/project)"],["--no-github","Skip GitHub CI/CD workflows"],["--remove-dir","Remove existing directory before creating (internal use)"]],exampleUsage:"pf new workspace my-platform -o my-org",buildContext:(e,t)=>{let r=(e.name??"my-platform").trim(),n=O(r),o=!!t.yes,s=t.packageManager??(o?b():void 0),i=t.packageManager==="bun",a=t.githubOwner??(o?"my-org":void 0),c=t.pulumiStack??(o?`${a}/${r}`:void 0),l=t.github===!1?!1:o?!0:void 0,p=!!e.name,m=t.removeDir||o;return{cwd:n,projectName:r,shouldInstallBun:i,packageManager:s,elapsedTime:0,userConfirmed:o,skipInputPrompts:p&&!o,removeDir:m,githubOwner:a,pulumiStackBase:c,includeGitHubCI:l}},prompts:[{enabled:e=>!e.userConfirmed,task:async(e,t)=>{try{let r=g();if(!await k(t).toggle({message:`\u26A0\uFE0F You are inside an existing workspace (${r}). Create a nested workspace anyway?`,initial:!1}))throw new Error("Workspace creation cancelled - already inside a workspace");t.title=_.yellow("Warning: Creating nested workspace")}catch(r){if(X(r)&&r.message?.includes("cancelled"))throw r;t.title="No existing workspace detected"}}},Pe,xe,ui,fi,hi,ke,Se,ve],actions:[we,Ce,xi,Si,jt,li,bi],onComplete:({projectName:e,includeGitHubCI:t})=>{d.breakLine().log(_.bold.green("Workspace created successfully!")),d.breakLine().log(_.bold("Next steps:")).log(` 1. ${_.cyan(`cd ${e}`)}`).log(` 2. ${_.cyan("exec $SHELL")} ${_.dim("(enable tab completion)")}`),t&&d.breakLine().log(_.bold("GitHub Setup:")).log(" Configure these secrets in your GitHub repository:").log(` \u2022 ${_.yellow("PULUMI_ACCESS_TOKEN")} - Pulumi Cloud access token`).log(` \u2022 ${_.yellow("DIGITALOCEAN_TOKEN")} - DigitalOcean API token`).log(` \u2022 ${_.yellow("NPM_TOKEN")} - (optional) NPM token for private packages`),d.breakLine().log(_.bold("Structure created:")).log(" apps/ # Frontend applications").log(" services/ # Backend microservices").log(" packages/").log(" \u2514\u2500\u2500 contracts/ # Shared event contracts").log(" infra/").log(" \u251C\u2500\u2500 index.ts # Pulumi entry point").log(" \u251C\u2500\u2500 services/ # Service configs").log(" \u251C\u2500\u2500 Pulumi.yaml # Pulumi project config").log(" \u2514\u2500\u2500 Pulumi.dev.yaml # Dev stack config"),t&&d.log(" .github/").log(" \u251C\u2500\u2500 workflows/ # CI/CD workflows").log(" \u2514\u2500\u2500 actions/ # Custom actions"),d.breakLine().log("Happy coding! \u{1F389}").breakLine()}});var ze=[{name:"Hono Microservice",value:"hono-micro",command:yi,supportsAi:!0},{name:"Nest Microservice",value:"nest-micro",command:vi,supportsAi:!0},{name:"Workspace (Infrastructure)",value:"workspace",command:Ei,supportsAi:!1}],Ti=()=>{let e=J({name:"new",description:"Create a new project",arguments:[["[type]","Type of the project (e.g., nest-micro, hono-micro, workspace)"]],exampleUsage:"platform new hono-micro test-service",buildContext:t=>({projectType:t.type??"",useAi:!1,aiDescription:"",elapsedTime:0,cwd:process.cwd()}),prompts:[{enabled:t=>!t.projectType,task:async(t,r)=>{let o=await k(r).select({message:"Select Project type",choices:ze});t.projectType=ze.find(s=>s.name===o)?.value||"",r.title=`Using ${q.bold(o)}`}},{enabled:t=>t.projectType!=="workspace"&&t.projectType!=="",task:async(t,r)=>{try{g(),r.title="Workspace detected"}catch{let n=["Not in a workspace directory","",`Current directory: ${process.cwd()}`,"","This command must be run from within a workspace created with pf new workspace","","To create a new workspace, run:",""," pf new workspace my-platform"].join(`
|
|
583
|
+
`);throw new Error(n)}}},{enabled:t=>t.projectType==="workspace",task:async(t,r)=>{try{let n=g();if(!await k(r).toggle({message:`\u26A0\uFE0F You are inside an existing workspace (${n}). Create a nested workspace anyway?`,initial:!1}))throw new Error("Workspace creation cancelled - already inside a workspace");r.title=q.yellow("Warning: Creating nested workspace")}catch(n){if(X(n)&&n.message?.includes("cancelled"))throw n;r.title="No existing workspace detected"}}},{enabled:t=>!!t.projectType,task:async(t,r)=>{let o={"hono-micro":"services/my-hono-service","nest-micro":"services/my-nest-service",workspace:"my-platform"}[t.projectType]||"my-project",s=t.projectType==="workspace"?"\u{1F4E6} Workspace name:":"\u{1F4E6} Service path (e.g., services/my-service):",a=await k(r).input({message:s,initial:o});t.servicePath=a.trim(),r.title=`Path: ${q.dim(a)}`}},{enabled:t=>!!ze.find(n=>n.value===t.projectType)?.supportsAi&&de().valid,task:async(t,r)=>{let o=await k(r).toggle({message:"Use AI to generate service code?",initial:!1});t.useAi=o,r.title=o?q.cyan("\u{1F916} AI-powered generation"):"Standard scaffolding"}},{enabled:t=>t.useAi,task:async(t,r)=>{let o=await k(r).input({message:"Describe what this service should do:"});t.aiDescription=o,r.title=`Description: ${q.dim(o.slice(0,50))}${o.length>50?"...":""}`}},{enabled:t=>{if(!t.servicePath)return!1;let r=O(t.servicePath);return!et(r)},task:async(t,r)=>{if(!await k(r).toggle({message:q.bold("\u26A0\uFE0F Overwrite existing directory?"),initial:!1}))throw new Error("Project creation was canceled by the user.");t.shouldRemoveDir=!0,r.title=q.yellow("Will overwrite existing directory")}},{title:"Confirm creation",enabled:t=>t.projectType!=="workspace",task:async(t,r)=>{if(!await k(r).toggle({message:"\u{1F680} Ready to launch your project?",initial:!0}))throw new Error("Project creation was canceled by the user.")}}],actions:[],onComplete:async t=>{ze.find(s=>s.value===t.projectType)||e.error(q.red(`Project type ${t.projectType} is not supported.`));let r=e.commands.find(s=>s.name()===t.projectType),n={};t.projectType!=="workspace"&&(n.yes=!0);let o=[];t.servicePath&&o.push("servicePath"),t.shouldRemoveDir&&(n.removeDir=!0),t.useAi&&(n.ai=!0,n.description=t.aiDescription),await ci(r,t,n,o)}});for(let t of ze)e.addCommand(t.command);return e};import{Command as Gg}from"commander";v();import{createHash as Og}from"crypto";import{existsSync as ie,readdirSync as $i,readFileSync as Ai,unlinkSync as Mg,writeFileSync as Dg}from"fs";import{join as Y}from"path";import _g from"chokidar";f();v();var jg=e=>{let t=Y(e,"infra","services");if(!ie(t))return[];let r=$i(t).filter(a=>a.endsWith(".ts")&&a!=="index.ts").map(a=>a.replace(".ts","")),n=E(e),o=a=>{let c=Y(e,a);return ie(c)?$i(c).filter(l=>ie(Y(c,l,"package.json"))):[]},s=[...o(n.services),...o(n.apps)],i=r.filter(a=>!s.includes(a));for(let a of i)Mg(Y(t,`${a}.ts`));return i},Ii=".install-hash",Ri=e=>{let t=Ai(e);return Og("sha256").update(t).digest("hex")},Lg=e=>{let t=Y(e,"node_modules",Ii),r=Y(e,"bun.lock");return!ie(r)||!ie(t)?!0:Ai(t,"utf-8")!==Ri(r)},Wg=e=>{let t=Y(e,"bun.lock"),r=Y(e,"node_modules",Ii);ie(t)&&Dg(r,Ri(t),"utf-8")},sn=async e=>{let t=jg(e);t.length>0&&console.log(`\u{1F9F9} Cleaned ${t.length} orphaned infra config(s): ${t.join(", ")}`),Lg(e)&&(await L({cwd:e,quiet:!0}),Wg(e)),await Fe("generate-env",{cwd:e})},an=async e=>{await Ys()&&await Zr(e)},Ni=e=>{let{eventsPath:t}=x(e);if(!ie(t))return async()=>{};let r=ae(async()=>{console.log(`
|
|
584
|
+
\u{1F4E6} Contracts changed, updating streams...`),await Zr(e)},500),n=_g.watch(`${t}/**/*.ts`,{ignoreInitial:!0,ignored:["**/index.ts","**/*.test.ts","**/*.spec.ts"]});return n.on("add",r).on("change",r),async()=>{await n.close()}};Ze();import Fi from"chalk";f();var cn=e=>new Promise(t=>setTimeout(t,e)),Oi=e=>process.stdout.write(`${e}
|
|
585
|
+
`),Hg=()=>{process.stdout.write("\x1B[2J\x1B[3J\x1B[H"),process.stdout.isTTY&&process.stdout.write("\x1Bc")},Mi=()=>({turboProcess:null,isRestarting:!1,isShuttingDown:!1}),ln=async(e,t)=>{let r=Kn(".env.local",t);r.length>0&&(await Xn(r),await cn(50));let{dev:n}=Ie(t),o=n.filter.flatMap(s=>["--filter",s]);Oi(Fi.cyan("\u{1F525} Starting services...")),Oi(Fi.dim(` Command: turbo run ${qt} --continue${o.length?` ${o.join(" ")}`:""}`)),e.isShuttingDown=!1,e.isRestarting=!1,e.turboProcess=qn("turbo",["run",qt,"--continue","--no-daemon",...o],{cwd:t,envFile:".env.local",onExit:s=>{e.isRestarting||e.isShuttingDown||s===1&&process.exit(w.SUCCESS)}})},zt=async e=>{let t=e.turboProcess?.pid;if(t){e.isShuttingDown=!0;try{try{process.kill(-t,"SIGTERM")}catch{e.turboProcess?.kill("SIGTERM")}await cn(200);try{process.kill(-t,"SIGKILL")}catch{}await cn(30)}catch{}e.turboProcess=null,Hg()}};var Di=new Gg("dev").description("Start development mode with auto-reload").action(async()=>{let e;try{e=g()}catch(a){$(a);return}let t=Mi(),r=async()=>{await sn(e),await an(e),await ln(t,e)},o=ae(async()=>{if(!(t.isRestarting||t.isShuttingDown)){t.isRestarting=!0,console.log(`
|
|
585
586
|
\u{1F504} Change detected, restarting...
|
|
586
|
-
`);try{await zt(t),await
|
|
587
|
-
\u{1F6D1} Shutting down...`),await zt(t),process.exit(w.SUCCESS))};process.removeAllListeners("SIGINT"),process.removeAllListeners("SIGTERM"),process.on("SIGINT",s),process.on("SIGTERM",s);let i;try{await r(),
|
|
587
|
+
`);try{await zt(t),await sn(e),await an(e),await ln(t,e)}catch(a){$(a)}finally{t.isRestarting=!1}}},300),s=async()=>{t.isShuttingDown||(console.log(`
|
|
588
|
+
\u{1F6D1} Shutting down...`),await zt(t),process.exit(w.SUCCESS))};process.removeAllListeners("SIGINT"),process.removeAllListeners("SIGTERM"),process.on("SIGINT",s),process.on("SIGTERM",s);let i;try{await r(),Tn(e,o),i=Ni(e),console.log(`
|
|
588
589
|
\u{1F440} Watching for changes...`),console.log(` Press Ctrl+C twice to exit (first stops Turbo, second triggers cleanup)
|
|
589
|
-
`)}catch(a){await i?.(),await zt(t),$(a)}});import
|
|
590
|
+
`)}catch(a){await i?.(),await zt(t),$(a)}});import Wi from"chalk";import{Command as tu}from"commander";import{existsSync as Bg,readFileSync as Ug,writeFileSync as zg}from"fs";import Vg from"os";import _i from"path";import pn from"chalk";import{Command as Jg}from"commander";v();var{name:Kg,publishConfig:qg}=R,Yg=qg?.registry,Zg=Kg?.split("/")[0],DE=new Jg("token:set").description(pn.bold("Set a registry auth token in a .npmrc file")).argument("<token>","Authentication token (e.g. GitHub or npm token)").option("--scope <scope>","Package scope (e.g. @my-workspace)",Zg).option("--registry <registry>","Registry URL",Yg).option("--local","Write token to a local .npmrc in the current directory",!1).option("--force","Force overwrite existing token if already present",!1).action((e,t)=>ji(e,t.scope||"",t.registry||"",t.local,t.force)).addHelpText("after",()=>`${pn.cyan(`
|
|
590
591
|
Example:`)}
|
|
591
|
-
${
|
|
592
|
-
`),
|
|
593
|
-
//${n}/:_authToken=${e}`:`//${n}/:_authToken=${e}`},
|
|
594
|
-
`),d.success(`Created new .npmrc and set token for ${a}`);return}if(l.test(c)){if(!o){d.warn(`Token for ${a} already exists in ${s}. Use --force to overwrite.`);return}c=c.replace(l,i),
|
|
592
|
+
${pn.bold("pf token set <token> --scope @my-workspace --registry https://npm.pkg.github.com")}
|
|
593
|
+
`),Xg=e=>e?_i.join(process.cwd(),".npmrc"):_i.join(Vg.homedir(),".npmrc"),Qg=(e,t,r)=>{let n=new URL(r).host;return t?`${t}:registry=https://${n}
|
|
594
|
+
//${n}/:_authToken=${e}`:`//${n}/:_authToken=${e}`},eu=e=>Bg(e)?Ug(e,"utf8"):"",mn=(e,t)=>zg(e,t),ji=(e,t,r,n=!1,o=!1)=>{let s=Xg(n),i=Qg(e,t,r),a=new URL(r).host,c=eu(s),l=new RegExp(`//${a}/:_authToken=\\S+`);if(!c){mn(s,`${i}
|
|
595
|
+
`),d.success(`Created new .npmrc and set token for ${a}`);return}if(l.test(c)){if(!o){d.warn(`Token for ${a} already exists in ${s}. Use --force to overwrite.`);return}c=c.replace(l,i),mn(s,c),d.success(`Overwrote existing token for ${a} in ${s}`);return}c+=`
|
|
595
596
|
${i}
|
|
596
|
-
`,
|
|
597
|
+
`,mn(s,c),d.success(`Appended token for ${a} to ${s}`)},Li=(e,t)=>ji(e,t.scope||"",t.registry||"",t.local,t.force);var{name:ru,publishConfig:nu}=R,ou=nu?.registry,su=ru?.split("/")[0],dn=new tu("token").description("Token management commands");dn.command("set").description("Set a registry auth token in a .npmrc file").argument("<token>","Authentication token (e.g. GitHub or npm token)").option("--scope <scope>","Package scope (e.g. @my-workspace)",su).option("--registry <registry>","Registry URL",ou).option("--local","Write token to a local .npmrc in the current directory",!1).option("--force","Force overwrite existing token if already present",!1).action(Li).addHelpText("after",()=>`${Wi.cyan(`
|
|
597
598
|
Example:`)}
|
|
598
|
-
${
|
|
599
|
-
`);
|
|
599
|
+
${Wi.bold("pf token set <token> --scope @my-workspace --registry https://npm.pkg.github.com")}
|
|
600
|
+
`);dn.action(()=>{let e=ge({title:"\u{1F511} Token Management",commands:[{name:"set",description:"Set a registry auth token in a .npmrc file"}],footer:'Run "pf token <command> --help" for more information'});console.log(e)});var Hi=dn;import un from"chalk";import{Command as vu}from"commander";f();Ze();var zE={AI_GENERATION:!0,DEBUG:process.env.PF_DEBUG==="true"};import{confirm as Bi,input as pu,password as mu,select as Ui}from"@inquirer/prompts";import P from"chalk";var iu=[/embed/i,/whisper/i,/tts/i,/dall-e/i,/davinci/i,/babbage/i,/curie/i,/ada(?!-)/i,/moderation/i,/realtime/i,/audio/i,/transcription/i,/search/i],au=async(e,t,r=1e4)=>{let n=new AbortController,o=setTimeout(()=>n.abort(),r);try{return await fetch(e,{...t,signal:n.signal})}finally{clearTimeout(o)}},cu=e=>e.replace(/-(\d{8})$/," ($1)").replace(/^claude-/,"Claude ").replace(/^gpt-/,"GPT-").replace(/-/g," ").replace(/(\d)\.(\d)/g,"$1.$2").replace(/\s+/g," ").split(" ").map(t=>/^\d/.test(t)||/^\(\d+\)$/.test(t)?t:t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join(" ").trim(),lu=async(e,t)=>{let r=Me(e),n=await au(r.modelsApiUrl,{headers:r.buildHeaders(t)});if(!n.ok)throw new Error(`${r.name} API error: ${n.status}`);let o=await n.json(),s=r.parseModelsResponse(o);if(!Array.isArray(s)||s.length===0)throw new Error(`No models returned from ${r.name} API`);let i=s.filter(a=>{let c=r.modelFilters.some(p=>p.test(a.id)),l=iu.some(p=>p.test(a.id));return c&&!l}).sort((a,c)=>{let l=typeof a.created=="number"?a.created:new Date(a.created).getTime();return(typeof c.created=="number"?c.created:new Date(c.created).getTime())-l}).map(a=>({name:cu(a.id),value:a.id}));if(i.length===0)throw new Error(`No chat models found from ${r.name} API`);return i};async function Gi(e,t){if(!t)throw new Error("API key is required to fetch available models");return{models:await lu(e,t),fromApi:!0}}V();function du(){if(!De())return null;try{let e=pt();return console.log(P.dim(`Found existing configuration at ${Q}
|
|
600
601
|
`)),e}catch{return console.log(P.yellow(`Found corrupted configuration, starting fresh.
|
|
601
|
-
`)),null}}async function
|
|
602
|
+
`)),null}}async function gu(e,t){return console.log(P.dim(`
|
|
602
603
|
\u{1F4CB} Get your ${e} API key here:`)),console.log(P.cyan(` ${t}
|
|
603
|
-
`)),
|
|
604
|
+
`)),mu({message:`Enter your ${e} API key:`,mask:"*",validate:r=>r.trim()?r.length<10?"API key seems too short":!0:"API key cannot be empty"})}async function uu(e,t,r){let n=await Ui({message:"Select model:",choices:e,default:t?.provider===r?t.model:void 0});return await Bi({message:"Enter a custom model ID instead?",default:!1})?pu({message:"Enter custom model ID:",default:n,validate:s=>s.trim()?!0:"Model ID cannot be empty"}):n}function zi(e){return e.length<=12?"****":`${e.slice(0,4)}...${e.slice(-4)}`}function fu(e,t){console.log(P.green.bold(`
|
|
604
605
|
\u2705 AI configuration saved successfully!
|
|
605
|
-
`)),console.log(P.dim(`Configuration file: ${Q}`)),console.log(P.dim("API Key: Stored securely in system keychain")),console.log(P.dim(`Provider: ${e.provider}`)),console.log(P.dim(`Model: ${e.model}`)),console.log(P.dim(`API Key: ${
|
|
606
|
+
`)),console.log(P.dim(`Configuration file: ${Q}`)),console.log(P.dim("API Key: Stored securely in system keychain")),console.log(P.dim(`Provider: ${e.provider}`)),console.log(P.dim(`Model: ${e.model}`)),console.log(P.dim(`API Key: ${zi(t)}
|
|
606
607
|
`)),console.log(P.cyan("You can now use AI-powered service generation:")),console.log(P.dim(` pf new hono-micro services/my-service --ai
|
|
607
|
-
`))}async function
|
|
608
|
+
`))}async function hu(e){let t=await lt(e);if(t)return t;let r=Me(e);return process.env[r.defaultApiKeyEnvVar]??null}async function Vi(){console.log(P.cyan.bold(`
|
|
608
609
|
\u{1F916} AI Configuration Setup
|
|
609
|
-
`));let e=
|
|
610
|
-
\u2713 Found existing API key: ${
|
|
611
|
-
Fetching available models...`));let s;try{s=(await
|
|
610
|
+
`));let e=du();try{let t=await Ui({message:"Select AI provider:",choices:mo(),default:e?.provider??ur.provider}),r=Me(t),n,o=await hu(t);o&&(console.log(P.green(`
|
|
611
|
+
\u2713 Found existing API key: ${zi(o)}`)),await Bi({message:"Use this existing API key?",default:!0})&&(n=o)),n||(n=await gu(r.name,r.apiKeyUrl)),console.log(P.dim(`
|
|
612
|
+
Fetching available models...`));let s;try{s=(await Gi(t,n)).models,console.log(P.green(`\u2713 Loaded ${s.length} models from ${r.name} API
|
|
612
613
|
`))}catch(c){console.error(P.red(`
|
|
613
|
-
\u274C Failed to fetch models: ${
|
|
614
|
+
\u274C Failed to fetch models: ${kn(c)}`)),console.log(P.yellow(`
|
|
614
615
|
Please check your API key and try again.
|
|
615
|
-
`)),process.exit(w.CONFIG_ERROR)}let i=await
|
|
616
|
+
`)),process.exit(w.CONFIG_ERROR)}let i=await uu(s,e,t),a={provider:t,model:i.trim()};go(a),await uo(t,n),fu(a,n)}catch(t){throw X(t)&&t.name==="ExitPromptError"&&(console.log(P.yellow(`
|
|
616
617
|
Setup cancelled.
|
|
617
|
-
`)),process.exit(w.CANCELLED)),t}}import{existsSync as
|
|
618
|
+
`)),process.exit(w.CANCELLED)),t}}import{existsSync as sT,readFileSync as iT}from"fs";import{homedir as cT}from"os";import{join as pT}from"path";var gn=async(e,t=!1)=>{try{return _r(e,t),await He({verbose:t}),!0}catch{return!1}};var Vt=e=>{let t=new vu("setup").description("Configure platform settings");return t.command("completion").description("Install shell autocompletion").option("--verbose","Enable verbose logging").addHelpText("after",`
|
|
618
619
|
Examples:
|
|
619
620
|
$ pf setup completion
|
|
620
621
|
$ pf setup completion --verbose
|
|
621
|
-
`).action(async r=>{await
|
|
622
|
-
\u2714 Shell autocompletion installed!`)),console.log(
|
|
623
|
-
`)),console.log(
|
|
622
|
+
`).action(async r=>{await gn(e,r.verbose),r.verbose||(console.log(un.green(`
|
|
623
|
+
\u2714 Shell autocompletion installed!`)),console.log(un.dim(` Restart your shell:
|
|
624
|
+
`)),console.log(un.cyan(` exec $SHELL
|
|
624
625
|
`)))}),t.command("ai").description("Configure AI provider and API key for code generation").addHelpText("after",`
|
|
625
626
|
Example:
|
|
626
627
|
$ pf setup ai
|
|
627
|
-
`).action(async()=>{await
|
|
628
|
+
`).action(async()=>{await Vi()}),t.action(()=>{let r=ge({title:"\u2699\uFE0F Platform Setup",commands:[{name:"completion",description:"Install shell autocompletion"},{name:"ai",description:"Configure AI provider"}],footer:'Run "pf setup <command> --help" for more information'});console.log(r)}),t},Cu=Vt("pf");V();f();import xu from"chalk";import{Command as Ki}from"commander";import Ji from"chalk";var ku=e=>({debug:()=>{},info:e?()=>{}:t=>console.log(` ${t}`),warn:e?()=>{}:t=>console.log(Ji.yellow(` ${t}`)),error:e?()=>{}:t=>console.error(Ji.red(` ${t}`))}),fn=async e=>{let{command:t,args:r,options:n,context:o,silent:s=!1}=e,i=await t.run(r,n),a=i?.effects??[];if(a.length>0){let c={workspace:o.workspace,logger:ku(s)};Wr(a,c)}if(!s&&i?.output){let c=Array.isArray(i.output)?i.output:[i.output];for(let l of c)console.log(l)}return{effects:a,output:i?.output}};var wu=e=>e.required?`<${e.name}>`:`[${e.name}]`,Pu=(e,t)=>{e.argument(wu(t),t.description)},Su=(e,t)=>{t.default!==void 0?e.option(t.flags,t.description,t.default):e.option(t.flags,t.description)},bu=(e,t)=>Object.fromEntries(e.args.map((r,n)=>[r.name,t[n]])),Eu=e=>e[e.length-2],Tu=(e,t)=>async(...r)=>{try{await fn({command:e,args:bu(e,r),options:Eu(r),context:t})}catch(n){console.error(xu.red(`Error executing ${e.name}:`),n instanceof Error?n.message:n),process.exit(1)}},qi=(e,t)=>{let r=new Ki(e.name).description(e.description);return e.args.forEach(n=>{Pu(r,n)}),e.options.forEach(n=>{Su(r,n)}),r.action(Tu(e,t)),r},hn=(e,t,r,n)=>{let o=new Ki(e).description(t);return r.forEach(s=>{o.addCommand(qi(s,n))}),o};wt();process.on("SIGINT",()=>{process.exit(w.CANCELLED)});process.on("unhandledRejection",e=>{throw Ye(e)&&process.exit(w.CANCELLED),e});process.on("uncaughtException",e=>{$(e)});var Ve=new Au,Yi=Object.keys(R.bin||{}),[vn="pf",yn]=Yi.length>0?Yi:["pf"],{description:Zi,version:Ru,repository:Xi,homepage:Nu}=R,Qi=Zi?.split(/ —|,|\./)[0]||Zi||"Platform CLI",ta=Xi?.url?`https://${Xi.url.replace(/^(git\+|git@)/,"").replace(/\.git$/,"").replace(":","/")}`:null,ea=ta||Nu,Fu=ta?"GitHub":"README",Ou=ea?[Je.bold(Qi),`
|
|
628
629
|
|
|
629
|
-
`,Je.cyan("See more at: "),Je.bold(
|
|
630
|
+
`,Je.cyan("See more at: "),Je.bold(Iu(Fu,String(ea)))].join(""):Je.bold(Qi),Mu=[Vt(vn),Ti(),Di,Hi,so],Du=async()=>{try{let e=g(),t=Ie(e);if(!t.plugins?.length)return[];let r=x(e),n=Pt({workspaceRoot:e,availableServices:at(e),contracts:{path:`${r.relativePath}/src`,packageName:r.packageName}}),o=[];for(let s of t.plugins)try{let{plugin:i}=await St(s,n),a=hn(i.name,i.description??`Commands from ${i.name}`,i.commands,n);o.push(a)}catch(i){console.warn(`\u26A0\uFE0F Failed to load plugin '${s}':`,i.message)}return o}catch{return[]}},_u=async()=>{let e=await Du(),t=[...Mu,...e];Ve.name(vn).description(Ou).version(Ru||"0.0.1").helpCommand(!1).configureHelp({subcommandTerm:r=>Je.cyan(r.name())}).addHelpText("after",is),yn&&yn!==vn&&Ve.alias(yn);for(let r of t)Ve.addCommand(r);Ve.command("__workspace-hash",{hidden:!0}).action(()=>{let r=process.cwd(),n=Math.abs(r.split("").reduce((o,s)=>(o<<5)-o+s.charCodeAt(0)|0,0));console.log(n)}),as(Ve,$u,t)};_u();
|