kenobi-pages 0.1.14 → 0.1.16

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/bin/cli.mjs CHANGED
@@ -1,80 +1,91 @@
1
+ #!/usr/bin/env tsx
1
2
  #!/usr/bin/env node
2
- var R=Object.defineProperty;var t=(e,o)=>R(e,"name",{value:o,configurable:!0});import{existsSync as S,readFileSync as E,writeFileSync as $,appendFileSync as _}from"node:fs";import{readFile as U}from"node:fs/promises";import{resolve as k}from"node:path";import{createInterface as j}from"node:readline";var T="https://kenobi.ai",w="KENOBI_PAGES_KEY",I=[".env.local",".env",".env.development",".env.development.local"],F=t(()=>{let e={},o=process.cwd();for(let n of I){let s=k(o,n);if(!S(s))continue;let r=E(s,"utf-8");for(let i of r.split(`
3
- `)){let c=i.trim();if(!c||c.startsWith("#"))continue;let a=c.match(/^([A-Z_][A-Z0-9_]*)=["']?([^"']*)["']?$/);a&&(e[a[1]]??=a[2])}}return e},"loadEnvFromCwd"),v=null,O=t(e=>process.env[e]?process.env[e]:(v??=F(),v[e]),"getEnvVar"),J=t(()=>{let e=O(w);return e||(console.error("Error: No API key found."),console.error(""),console.error("Run 'npx kenobi-pages init' to set up your API key,"),console.error("or add KENOBI_PAGES_KEY to your project's env file (e.g. .env or .env.local)."),process.exit(1)),e},"getApiKey"),K=t(()=>(O("KENOBI_BASE_URL")??T).replace(/\/+$/,""),"getBaseUrl"),p=t(async(e,o={})=>{let n=`${K()}${e}`,s=await fetch(n,{method:o.method??"GET",headers:{"x-kenobi-key":J(),"Content-Type":"application/json"},body:o.body?JSON.stringify(o.body):void 0});if(!s.ok){let r=await s.text().catch(()=>"Unknown error"),i=s.status===401||s.status===403?4:s.status===404?3:1;console.error(`Error ${s.status}: ${r}`),i===4&&console.error("If you're using a custom base URL, make sure KENOBI_BASE_URL is set in your project's env file."),process.exit(i)}return s.json()},"fetchKenobi"),y=t(e=>new Promise(o=>{let n=j({input:process.stdin,output:process.stderr});n.question(e,s=>{n.close(),o(s.trim())})}),"prompt"),A=t(()=>new Promise((e,o)=>{let n="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",s=>{n+=s}),process.stdin.on("end",()=>e(n)),process.stdin.on("error",o),process.stdin.isTTY&&e("")}),"readStdin"),P=t(async e=>{let o=e.indexOf("--file");return o!==-1&&e[o+1]?U(e[o+1],"utf-8"):null},"parseFileArg"),L=t(()=>{let e=process.cwd();return I.filter(o=>S(k(e,o)))},"discoverEnvFiles"),B=t((e,o,n)=>{let s=E(e,"utf-8");if(s.includes(o)){console.error(` \u2713 ${o} already present in ${e.split("/").pop()}`);return}let r=s.endsWith(`
3
+ var ve=Object.defineProperty;var o=(e,t)=>ve(e,"name",{value:t,configurable:!0});var k=class extends Error{static{o(this,"CliError")}exitCode;payload;constructor(t,n=1){super(t.message),this.name="CliError",this.exitCode=n,this.payload={ok:!1,...t}}},p=o((e,t)=>new k({status:null,code:"invalid_usage",message:e,details:t},2),"usageError"),P=o((e,t)=>new k({status:404,code:"not_found",message:e,details:t},3),"notFoundError"),d=o((e,t,n)=>{if(!e)throw p(t,n);return e},"assertArg"),l=o(e=>{console.log(JSON.stringify(e,null,2))},"printJson"),B=o(e=>{console.error(JSON.stringify(e,null,2))},"writeError"),H=o(e=>{e instanceof k&&(B(e.payload),process.exit(e.exitCode));let t=e instanceof Error?e.message:"Unknown error";B({ok:!1,status:null,code:"runtime_error",message:t}),process.exit(1)},"handleCliError");var g=o((e,t)=>{let n=e.indexOf(t);return n!==-1?e[n+1]:void 0},"parseFlag"),S=o((e,t)=>e.includes(t),"hasFlag"),f=o((e,t,n)=>{let s=g(e,t);if(!s||s.startsWith("--"))throw p(n);return s},"parseRequiredFlag"),j=o((e,t)=>{let n=g(e,t);if(n===void 0)return;let s=Number(n);if(!Number.isInteger(s)||s<=0)throw p(`${t} must be a positive integer`);return s},"parseOptionalPositiveIntFlag"),K=o((e,t)=>{let n=g(e,t);if(n===void 0)return;let s=Number(n);if(!Number.isInteger(s)||s<0)throw p(`${t} must be a non-negative integer`);return s},"parseOptionalNonNegativeIntFlag");import{appendFileSync as $e,existsSync as D,readFileSync as N,writeFileSync as G}from"node:fs";import{resolve as V}from"node:path";var xe="https://kenobi.ai",w="KENOBI_PAGES_KEY",q=[".env.local",".env",".env.development",".env.development.local"],Ie=o(()=>{let e={},t=process.cwd();for(let n of q){let s=V(t,n);if(!D(s))continue;let r=N(s,"utf-8");for(let i of r.split(`
4
+ `)){let c=i.trim();if(!c||c.startsWith("#"))continue;let a=c.match(/^([A-Z_][A-Z0-9_]*)=["']?([^"']*)["']?$/);a&&(e[a[1]]??=a[2])}}return e},"loadEnvFromCwd"),_=null,E=o(e=>process.env[e]?process.env[e]:(_??=Ie(),_[e]),"getEnvVar"),Ee=o(()=>{_=null},"resetEnvCache"),b=o(()=>(E("KENOBI_BASE_URL")??xe).replace(/\/+$/,""),"getBaseUrl"),Y=o(()=>{let e=E(w);if(e)return e;throw new k({status:null,code:"missing_api_key",message:`No API key found. Run 'npx kenobi-pages init' or set ${w}.`},4)},"getApiKey"),z=o(()=>E(w),"getApiKeyOptional"),R=o(()=>{let e=process.cwd();return q.filter(t=>D(V(e,t)))},"discoverEnvFiles"),Q=o((e,t,n)=>{let s=N(e,"utf-8");if(s.includes(t)){console.error(` ${t} already present in ${e.split("/").pop()}`);return}let r=s.endsWith(`
4
5
  `)?"":`
5
- `;_(e,`${r}${o}="${n}"
6
- `),console.error(` \u2713 Added ${o} to ${e.split("/").pop()}`)},"appendEnvVar"),W=t((e,o)=>{B(e,w,o)},"appendKeyToEnvFile"),D=t(async()=>{console.error(""),console.error(" Kenobi Pages \u2014 Setup"),console.error(""),console.error(" Find your API key at: https://kenobi.ai/setup"),console.error("");let e=await y(" Paste your API key (pk_live_... or pk_test_...): ");e||(console.error(" No key provided. Aborting."),process.exit(1)),!e.startsWith("pk_live_")&&!e.startsWith("pk_test_")&&(console.error(` Warning: "${e}" doesn't look like a Kenobi key (expected pk_live_... or pk_test_...).`),(await y(" Continue anyway? (y/N): ")).toLowerCase()!=="y"&&(console.error(" Aborting."),process.exit(1))),console.error("");let o=L();if(o.length>0){console.error(""),console.error(" Found env files in this project:"),o.forEach((r,i)=>console.error(` ${i+1}. ${r}`)),console.error(` ${o.length+1}. Create a new file`),console.error(` ${o.length+2}. Skip`),console.error("");let n=await y(` Which file should ${w} be added to? [1]: `),s=n===""?0:parseInt(n,10)-1;if(s===o.length){let r=await y(" Filename (e.g. .env.local): ");if(r){let i=k(process.cwd(),r);$(i,`${w}="${e}"
7
- `),console.error(` \u2713 Created ${r} with ${w}`)}}else s>=0&&s<o.length&&W(k(process.cwd(),o[s]),e)}else{console.error("");let n=await y(" No env files found. Create one? (filename or 'n' to skip) [.env.local]: "),s=`${w}="${e}"
8
- `;if(n.toLowerCase()!=="n"&&n!==""){let r=k(process.cwd(),n);$(r,s),console.error(` \u2713 Created ${n} with ${w}`)}else if(n===""){let r=k(process.cwd(),".env.local");$(r,s),console.error(` \u2713 Created .env.local with ${w}`)}}console.error(""),console.error(" Done! Your agent can now use kenobi-pages commands."),console.error(" Run 'npx kenobi-pages --help' to see what's available."),console.error("")},"initCommand"),G=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages schema get <workflowId>"),process.exit(2));let n=await p(`/api/v1/pages/${o}/schema`);console.log(JSON.stringify(n,null,2))},"schemaGet"),x=t((e,o)=>{let n=" ".repeat(o);switch(e.type){case"string":case"url":return"string";case"number":return"number";case"boolean":return"boolean";case"array":return e.items?.type==="object"&&e.items.fields?`Array<{
9
- ${Object.entries(e.items.fields).map(([i,c])=>`${n} ${i}: ${x(c,o+2)}`).join(`
6
+ `;$e(e,`${r}${t}="${n}"
7
+ `),console.error(` Added ${t} to ${e.split("/").pop()}`)},"appendEnvVar"),T=o((e,t,n)=>{G(e,`${t}="${n}"
8
+ `)},"writeEnvFile"),J=o((e,t,n)=>{let s=D(e)?N(e,"utf-8"):"",r=`${t}="${n}"`,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),c=new RegExp(`^${i}=.*$`,"m"),a=c.test(s)?s.replace(c,r):`${s}${s.length>0&&!s.endsWith(`
9
+ `)?`
10
+ `:""}${r}
11
+ `;G(e,a),Ee()},"upsertEnvVar");var Re=o(async e=>{let t=await e.text().catch(()=>"");if(!t)return null;try{return JSON.parse(t)}catch{return t}},"parseErrorBody"),Ue=o(e=>{if(typeof e=="string")return e;if(typeof e=="object"&&e!==null&&"error"in e){let t=e.error;return typeof t=="string"?t:JSON.stringify(t)}return"Kenobi API request failed"},"errorMessageFromBody"),Oe=o(e=>e===401||e===403?4:e===404?3:1,"exitCodeForStatus"),u=o(async(e,t={})=>{let n=await fetch(`${b()}${e}`,{method:t.method??"GET",headers:{"x-kenobi-key":Y(),"Content-Type":"application/json"},body:t.body?JSON.stringify(t.body):void 0});if(n.ok)return await n.json();let s=await Re(n);throw new k({status:n.status,code:n.status===401||n.status===403?"unauthorized":"api_error",message:Ue(s),details:s},Oe(n.status))},"fetchKenobi"),v=o(e=>{let t=new URLSearchParams;for(let[n,s]of Object.entries(e))s!==void 0&&t.set(n,s);return t.toString()},"buildQuery");var $=o(e=>Object.keys(e??{}),"keys"),Z=o(e=>{let t=e.packJson??null,n=t?.tokens??{},s=t?.surfaces??{},r=t?.typography??{},i=t?.accents??{};return{designPack:{id:e.id,status:e.status,hostDomain:t?.hostDomain??e.hostDomain??null,raw:t},templateGuidance:{brandSummary:t?.compositionDescription??"Use the raw design pack tokens and recipes as the source of truth.",tokens:{color:n.color??{},font:n.font??{},radius:n.radius??{},container:n.container??{},section:n.section??{}},surfaces:s,typography:r,accents:i,use:["Use color, font, radius, spacing, surface, and typography recipes from this design pack before inventing new styles.","Preserve the source site's visual rhythm, density, button treatment, and section composition.","Keep the template source self-contained and accept all dynamic values through the Template content prop."],avoid:["Do not use generic SaaS gradients, decorative orbs, or unrelated stock-style visuals.","Do not introduce a new palette when the design pack already contains brand colors.","Do not hard-code personalized copy that should come from the content schema."],availableRecipes:{colors:$(n.color),fonts:$(n.font),radii:$(n.radius),surfaces:$(s),typography:$(r),accents:$(i)}}}},"exportDesignPackForAgent");var Fe=new Set(["COMPLETED","FAILED","CANCELED","SYSTEM_FAILURE","CRASHED"]),Pe=o(e=>new Promise(t=>setTimeout(t,e)),"sleep"),Te=o(async(e,t)=>{let n=2e3,s=15e3;for(;;){await Pe(n);let r=await u(`/api/v1/pages/evidence-bundles/${e}/design-packs/runs/${t}`),i=typeof r.status=="string"?r.status:"UNKNOWN";if(console.error(`Status: ${i}`),Fe.has(i)){l(r),i!=="COMPLETED"&&process.exit(1);return}n=Math.min(n*1.5,s)}},"pollDesignPack"),X=o(async e=>{let[t,...n]=e,s=n[0];if(t==="list"){d(s,"Usage: kenobi-pages design-pack list <bundleId>"),l(await u(`/api/v1/pages/evidence-bundles/${s}/design-packs`));return}if(t==="generate"){d(s,"Usage: kenobi-pages design-pack generate <bundleId> [--wait]");let r=await u(`/api/v1/pages/evidence-bundles/${s}/design-packs`,{method:"POST"});if(!S(n.slice(1),"--wait")){l(r);return}let i=typeof r.taskId=="string"?r.taskId:void 0;if(!i){l(r);return}console.error(`Design pack generation queued: ${i}`),await Te(s,i);return}if(t==="status"){let r=d(n[1],"Usage: kenobi-pages design-pack status <bundleId> <taskId>");d(s,"Usage: kenobi-pages design-pack status <bundleId> <taskId>"),l(await u(`/api/v1/pages/evidence-bundles/${s}/design-packs/runs/${r}`));return}if(t==="get"){let r=d(n[1],"Usage: kenobi-pages design-pack get <bundleId> <designPackId>");d(s,"Usage: kenobi-pages design-pack get <bundleId> <designPackId>"),l(await u(`/api/v1/pages/evidence-bundles/${s}/design-packs/${r}`));return}if(t==="export"){let r=d(n[1],"Usage: kenobi-pages design-pack export <bundleId> <designPackId>");d(s,"Usage: kenobi-pages design-pack export <bundleId> <designPackId>");let i=await u(`/api/v1/pages/evidence-bundles/${s}/design-packs/${r}`);l(Z(i.designPack??{}));return}throw p(`Unknown design-pack command: ${e.join(" ")}`)},"handleDesignPack");import{existsSync as Ce,readFileSync as Ae}from"node:fs";import{dirname as ee,join as je}from"node:path";import{fileURLToPath as Ke}from"node:url";var _e=o(()=>{let e=ee(Ke(import.meta.url));for(let t=0;t<6;t+=1){let n=je(e,"package.json");if(Ce(n))try{let s=JSON.parse(Ae(n,"utf-8"));if(s.name==="kenobi-pages"&&s.version)return s.version}catch{return"unknown"}e=ee(e)}return"unknown"},"findPackageVersion"),te=_e();var De=o(async e=>{try{let t=await fetch(`${b()}/api/v1/cortex/sources`,{headers:{"x-kenobi-key":e,"Content-Type":"application/json"}});if(!t.ok)return{auth:{ok:!1,status:t.status},sources:{count:null}};let n=await t.json();return{auth:{ok:!0,status:t.status},sources:{count:Array.isArray(n.sources)?n.sources.length:0}}}catch(t){return{auth:{ok:!1,status:null,error:t instanceof Error?t.message:"Unknown error"},sources:{count:null}}}},"authCheck"),ne=o(async()=>{let e=z(),t=R(),n=e?await De(e):{auth:{ok:!1,status:null,skipped:!0},sources:{count:null}},s=[];e?n.auth.ok||s.push("Check that the Kenobi API key is valid for this org."):s.push(`Run 'kenobi-pages init' or set ${w}.`),e&&n.auth.ok&&n.sources.count===0&&s.push("Connect at least one source in Kenobi before building data-backed workflows."),l({ok:!!(e&&n.auth.ok),cli:{version:te},env:{hasApiKey:!!e,apiKeyEnvVar:w,baseUrl:b(),envFiles:t},auth:n.auth,sources:n.sources,nextSteps:s})},"handleDoctor");import{readFile as oe}from"node:fs/promises";var se=o(()=>new Promise((e,t)=>{if(process.stdin.isTTY){e("");return}let n="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",s=>{n+=s}),process.stdin.on("end",()=>e(n)),process.stdin.on("error",t)}),"readStdin"),y=o((e,t)=>{try{return JSON.parse(e)}catch{throw p(`Invalid JSON for ${t}`)}},"parseJson"),U=o(async(e,t)=>y(await oe(e,"utf-8"),t),"readJsonFile"),W=o(async(e,t)=>{if(!e){let n=await se();if(!n.trim())throw p(`Missing ${t}`);return y(n,t)}if(e==="-"){let n=await se();if(!n.trim())throw p(`Missing ${t} on stdin`);return y(n,t)}return e.trim().startsWith("{")||e.trim().startsWith("[")?y(e,t):U(e,t)},"readJsonSource"),x=o(async(e,t="JSON")=>{let n=g(e,"--file");if(n)return U(n,t);let s=e.find(r=>r.trim().startsWith("{")||r.trim().startsWith("["));return W(s,t)},"readJsonInput"),re=o(async(e,t,n)=>{let s=g(e,t);if(s!==void 0)return W(s,n)},"readJsonFlag"),C=o(async(e,t,n)=>W(g(e,t),n),"readRequiredJsonFlag"),ie=o(async(e,t,n)=>{let s=g(e,t);if(!s||s.startsWith("--"))throw p(`Missing ${n}`);return oe(s,"utf-8")},"readTextFileFlag");var Ne=o((e,t)=>{let n={url:e},s=g(t,"--viewport"),r=g(t,"--headers"),i=g(t,"--wait-for-selector"),c=K(t,"--wait-timeout"),a=g(t,"--wait-until"),m=K(t,"--extra-wait-ms");return s&&(n.viewport=y(s,"--viewport")),r&&(n.headers=y(r,"--headers")),i&&(n.waitForSelector=i),c!==void 0&&(n.waitTimeout=c),a&&(n.waitUntil=a.trim().startsWith("[")?y(a,"--wait-until"):a),m!==void 0&&(n.extraWaitMs=m),S(t,"--block-annoyances")&&(n.blockAnnoyances=!0),n},"createEvidenceBody"),ae=o(async e=>{let[t,...n]=e;if(t==="list"){l(await u("/api/v1/pages/evidence-bundles"));return}if(t==="create"){let s=d(n[0],"Usage: kenobi-pages evidence create <url> [flags]");l(await u("/api/v1/pages/evidence-bundles",{method:"POST",body:Ne(s,n.slice(1))}));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages evidence get <bundleId>");l(await u(`/api/v1/pages/evidence-bundles/${s}`));return}throw p(`Unknown evidence command: ${e.join(" ")}`)},"handleEvidence");var Je="kenobi.page",We=o(e=>(e??Je).replace(/^https?:\/\//,"").replace(/\/+$/,"").toLowerCase(),"normalizeHostedDomain"),Me=o(()=>We(E("KENOBI_PAGES_HOSTED_DOMAIN")),"getHostedPagesDomain"),I=o(({siteSlug:e,templateSlug:t,itemSlug:n})=>`https://${e}.${Me()}/${t}/${n}`,"buildHostedPublicUrl"),ce=o((e,t)=>{if(typeof e!="object"||e===null)return e;let n=e,s=typeof n.siteSlug=="string"?n.siteSlug:t?.siteSlug,r=typeof n.templateSlug=="string"?n.templateSlug:t?.templateSlug,i=typeof n.itemSlug=="string"?n.itemSlug:t?.itemSlug;return!s||!r||!i?e:{...e,publicUrl:I({siteSlug:s,templateSlug:r,itemSlug:i})}},"maybeDecorateHostedContent"),M=o((e,t)=>({...e,publicUrl:I(t)}),"decorateHostedContentResponse");var le=o(async e=>{let t=f(e,"--template-slug","Usage: kenobi-pages hosted draft save --template-slug <slug> --template-name <name> --source <tsx-file> --schema <json-file> --content <json-file>"),n=f(e,"--template-name","Usage: kenobi-pages hosted draft save --template-slug <slug> --template-name <name> --source <tsx-file> --schema <json-file> --content <json-file>"),s=await ie(e,"--source","--source <tsx-file>"),r=f(e,"--schema","Missing --schema <json-file>"),i=f(e,"--content","Missing --content <json-file>"),c=j(e,"--design-pack-id"),a=g(e,"--site-slug"),m=g(e,"--site-name"),h={templateSlug:t,templateName:n,sourceTsx:s,contentSchema:{title:n,schemaJson:await U(r,"--schema")},defaultContentJson:await U(i,"--content"),setCurrentDraft:!S(e,"--no-current-draft")};return c!==void 0&&(h.designPackId=c),a&&(h.site={slug:a,...m?{name:m}:{}}),h},"parseHostedDraftBody"),ue=o(e=>{let t=typeof e.previewPath=="string"?e.previewPath:null;return{...e,...t?{previewUrl:`${b()}${t}`}:{}}},"withPreviewUrl"),Le=o(async e=>{let[t,...n]=e;if(t==="list"){l(await u("/api/v1/pages/hosted/sites"));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages hosted site get <siteSlug>");l(await u(`/api/v1/pages/hosted/sites?${v({slug:s})}`));return}throw p(`Unknown hosted site command: ${e.join(" ")}`)},"handleHostedSite"),Be=o(async e=>{let[t,...n]=e;if(t==="list"){let s=v({full:S(n,"--full")?"true":void 0});l(await u(`/api/v1/pages/hosted/templates${s?`?${s}`:""}`));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages hosted template get <templateIdOrSlug> [--full]"),r=v({full:S(n.slice(1),"--full")?"true":void 0});l(await u(`/api/v1/pages/hosted/templates/${s}${r?`?${r}`:""}`));return}throw p(`Unknown hosted template command: ${e.join(" ")}`)},"handleHostedTemplate"),He=o(async e=>{let[t,...n]=e;if(t==="list"){let s=d(n[0],"Usage: kenobi-pages hosted publication list <templateIdOrSlug>");l(await u(`/api/v1/pages/hosted/templates/${s}/publications`));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages hosted publication get <templateIdOrSlug> <publicationId>"),r=d(n[1],"Usage: kenobi-pages hosted publication get <templateIdOrSlug> <publicationId>");l(await u(`/api/v1/pages/hosted/templates/${s}/publications/${r}`));return}throw p(`Unknown hosted publication command: ${e.join(" ")}`)},"handleHostedPublication"),Ge=o(async e=>{let[t,...n]=e;if(t==="list"){let s=f(n,"--site","Usage: kenobi-pages hosted content list --site <siteSlug> [--template <templateSlug>]"),r=g(n,"--template"),i=await u(`/api/v1/pages/hosted/instances?${v({siteSlug:s,templateSlug:r})}`);l({...i,instances:(i.instances??[]).map(c=>ce(c,{siteSlug:s,templateSlug:r}))});return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages hosted content get <siteSlug> <templateSlug> <itemSlug>"),r=d(n[1],"Usage: kenobi-pages hosted content get <siteSlug> <templateSlug> <itemSlug>"),i=d(n[2],"Usage: kenobi-pages hosted content get <siteSlug> <templateSlug> <itemSlug>"),c=await u(`/api/v1/pages/hosted/instances/${s}/${r}/${i}`);l(M(c,{siteSlug:s,templateSlug:r,itemSlug:i}));return}if(t==="upsert"){let s=f(n,"--site","Usage: kenobi-pages hosted content upsert --site <siteSlug> --template <templateSlug> --item <itemSlug> --content <json|file|->"),r=f(n,"--template","Missing --template <templateSlug>"),i=f(n,"--item","Missing --item <itemSlug>"),c=j(n,"--publication-id"),a=await C(n,"--content","--content"),m=await u("/api/v1/pages/hosted/instances",{method:"POST",body:{siteSlug:s,templateSlug:r,itemSlug:i,contentJson:a,...c!==void 0?{publicationId:c}:{}}});l(M(m,{siteSlug:s,templateSlug:r,itemSlug:i}));return}if(t==="verify"){let s=d(n[0],"Usage: kenobi-pages hosted content verify <siteSlug> <templateSlug> <itemSlug>"),r=d(n[1],"Usage: kenobi-pages hosted content verify <siteSlug> <templateSlug> <itemSlug>"),i=d(n[2],"Usage: kenobi-pages hosted content verify <siteSlug> <templateSlug> <itemSlug>"),c=I({siteSlug:s,templateSlug:r,itemSlug:i});try{let a=await u(`/api/v1/pages/hosted/instances/${s}/${r}/${i}`);l({ok:!0,publicUrl:c,resolved:!0,contentValid:!0,publication:a.templatePublication??null})}catch(a){if(!(a instanceof k))throw a;let h=(typeof a.payload.details=="object"&&a.payload.details!==null&&"stage"in a.payload.details?a.payload.details.stage:null)==="invalid-content"?!1:null;l({ok:!1,publicUrl:c,resolved:a.payload.status!==404,contentValid:h,publication:null,error:a.payload}),process.exit(a.exitCode)}return}throw p(`Unknown hosted content command: ${e.join(" ")}`)},"handleHostedContent"),Ve=o(async e=>{let[t,...n]=e;if(t==="create"){let s=["--site-slug",f(n,"--site-slug","Missing --site-slug <siteSlug>"),...g(n,"--site-name")?["--site-name",g(n,"--site-name")]:[],"--template-slug",f(n,"--template-slug","Missing --template-slug <templateSlug>"),"--template-name",f(n,"--template-name","Missing --template-name <templateName>"),"--source",f(n,"--source","Missing --source <tsx-file>"),"--schema",f(n,"--schema","Missing --schema <json-file>"),"--content",f(n,"--content","Missing --content <json-file>"),...g(n,"--design-pack-id")?["--design-pack-id",g(n,"--design-pack-id")]:[],...S(n,"--no-current-draft")?["--no-current-draft"]:[]];l(ue(await u("/api/v1/pages/hosted/templates/drafts",{method:"POST",body:await le(s)})));return}throw p(`Unknown hosted page command: ${e.join(" ")}`)},"handleHostedPage"),de=o(async e=>{let[t,n,...s]=e;if(t==="site")return Le([n,...s].filter(Boolean));if(t==="template")return Be([n,...s].filter(Boolean));if(t==="publication")return He([n,...s].filter(Boolean));if(t==="content")return Ge([n,...s].filter(Boolean));if(t==="page")return Ve([n,...s].filter(Boolean));if(t==="draft"&&n==="save"){l(ue(await u("/api/v1/pages/hosted/templates/drafts",{method:"POST",body:await le(s)})));return}if(t==="publish"){let r=d(n,"Usage: kenobi-pages hosted publish <templateIdOrSlug>");l(await u(`/api/v1/pages/hosted/templates/${r}/publish`,{method:"POST"}));return}throw p(`Unknown hosted command: ${e.join(" ")}`)},"handleHosted");var qe=new Set(["COMPLETED","FAILED","CANCELED","SYSTEM_FAILURE","CRASHED"]),Ye=o(e=>new Promise(t=>setTimeout(t,e)),"sleep"),ze=o(e=>{if(typeof e=="string")return e;if(typeof e=="object"&&e!==null&&"message"in e){let t=e.message;if(typeof t=="string")return t}return"Unknown error"},"runStatusErrorMessage"),pe=o(async e=>{let t=d(e[0],"Usage: kenobi-pages run <workflowIdOrSlug> [--params '<json>'] [--context <text>]"),n=e.slice(1),s=g(n,"--params"),r=g(n,"--context"),i={params:s?y(s,"--params"):{}};r&&(i.context=r);let c=await u(`/api/v1/cortex/workflows/${t}/run`,{method:"POST",body:i});console.error(`Run triggered: ${c.runId}`),console.error("Polling for completion...");let a=2e3,m=15e3;for(;;){await Ye(a);let h=await u(`/api/v1/cortex/workflows/${t}/runs/${c.runId}`);if(console.error(`Status: ${h.status}`),qe.has(h.status)){h.status!=="COMPLETED"&&(console.error(`Run failed (${h.status}): ${ze(h.error)}`),l(h),process.exit(1)),l(h);return}a=Math.min(a*1.5,m)}},"handleRun");var A=o((e,t)=>{let n=" ".repeat(t);switch(e.type){case"string":case"url":return"string";case"number":return"number";case"boolean":return"boolean";case"array":return e.items?.type==="object"&&e.items.fields?`Array<{
12
+ ${Object.entries(e.items.fields).map(([i,c])=>`${n} ${i}: ${A(c,t+2)}`).join(`
10
13
  `)}
11
- ${n} }>`:`${e.items?x(e.items,o):"unknown"}[]`;case"object":return e.fields?`{
12
- ${Object.entries(e.fields).map(([r,i])=>`${n} ${r}: ${x(i,o+1)}`).join(`
14
+ ${n} }>`:`${e.items?A(e.items,t):"unknown"}[]`;case"object":return e.fields?`{
15
+ ${Object.entries(e.fields).map(([r,i])=>`${n} ${r}: ${A(i,t+1)}`).join(`
13
16
  `)}
14
- ${n}}`:"Record<string, unknown>";default:return"unknown"}},"schemaTypeToTs"),M=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages schema codegen <workflowId>"),console.error(" npx kenobi-pages schema codegen 42 > lib/kenobi-types.ts"),process.exit(2));let n=await p(`/api/v1/pages/${o}/schema`),r=(n.title??"KenobiPage").replace(/[^a-zA-Z0-9\s]/g,"").split(/\s+/).map(c=>c.charAt(0).toUpperCase()+c.slice(1).toLowerCase()).join("")+"Content",i=Object.entries(n.schema).map(([c,a])=>`${a.description?` /** ${a.description} */
15
- `:""} ${c}: ${x(a,1)}`).join(`
16
- `);console.log(`export interface ${r} {
17
+ ${n}}`:"Record<string, unknown>";default:return"unknown"}},"schemaTypeToTs"),Qe=o(e=>`${e.replace(/[^a-zA-Z0-9\s]/g,"").split(/\s+/).filter(Boolean).map(t=>t.charAt(0).toUpperCase()+t.slice(1).toLowerCase()).join("")}Content`,"interfaceNameFromTitle"),Ze=o(async e=>(await u(`/api/v1/cortex/workflows/${e}`)).id,"resolveWorkflowId"),Xe=o(async e=>{let[t,...n]=e;if(t==="list"){l(await u("/api/v1/pages/self-hosted/schemas"));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages self-hosted schema get <workflowIdOrSlug>");l(await u(`/api/v1/pages/self-hosted/${s}/schema`));return}if(t==="codegen"){let s=d(n[0],"Usage: kenobi-pages self-hosted schema codegen <workflowIdOrSlug>"),r=await u(`/api/v1/pages/self-hosted/${s}/schema`),i=Object.entries(r.schema).map(([c,a])=>`${a.description?` /** ${a.description} */
18
+ `:""} ${c}: ${A(a,1)}`).join(`
19
+ `);console.log(`export interface ${Qe(r.title??"KenobiPage")} {
17
20
  ${i}
18
- }`),console.error(`Generated interface ${r} from workflow ${o}`)},"schemaCodegen"),Y=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages schema push <name> '<json>'"),console.error(" kenobi-pages schema push <name> --file schema.json"),console.error(" echo '<json>' | kenobi-pages schema push <name>"),process.exit(2));let n=e.slice(1),s=await P(n),r=s?null:n.find(h=>h.startsWith("{")),i=!s&&!r?await A():null,c=s??r??i;(!c||c.trim().length===0)&&(console.error("Error: No schema provided."),console.error("Pass inline JSON, --file <path>, or pipe to stdin."),process.exit(2));let a;try{a=JSON.parse(c)}catch{console.error("Error: Invalid JSON."),process.exit(2)}let f=await p("/api/v1/pages/schema",{method:"POST",body:{name:o,schema:a}});console.log(JSON.stringify(f,null,2)),console.error(`Schema "${f.name}" pushed successfully.`),console.error(`Source key: ${f.sourceKey}`),console.error("You can now select this schema as an output target in the Kenobi workflow builder.")},"schemaPush"),V=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages pages <workflowId>"),process.exit(2));let n=await p(`/api/v1/pages/${o}`);console.log(JSON.stringify(n,null,2))},"listPages"),Z=t(async e=>{let[o,n]=e;(!o||!n)&&(console.error("Usage: kenobi-pages page get <workflowId> <slug>"),process.exit(2));let s=await p(`/api/v1/pages/${o}/${n}`);console.log(JSON.stringify(s,null,2))},"pageGet"),q=new Set(["COMPLETED","FAILED","CANCELED","SYSTEM_FAILURE","CRASHED"]),z=t(e=>{if(typeof e=="string")return e;if(typeof e=="object"&&e!==null&&"message"in e){let o=e.message;if(typeof o=="string")return o}return"Unknown error"},"runStatusErrorMessage"),H=t(e=>new Promise(o=>setTimeout(o,e)),"sleep"),m=t((e,o)=>{let n=e.indexOf(o);return n!==-1&&e[n+1]?e[n+1]:void 0},"parseFlag"),X=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages run <workflowId> [--params '<json>'] [--context '<text>']"),process.exit(2));let n=e.slice(1),s={},r=m(n,"--params");if(r)try{s=JSON.parse(r)}catch{console.error("Error: Invalid JSON in --params"),process.exit(2)}let i=m(n,"--context"),c={params:s};i&&(c.context=i);let a=await p(`/api/v1/workflows/${o}/run`,{method:"POST",body:c});console.error(`Run triggered: ${a.runId}`),console.error("Polling for completion...");let f=2e3,h=15e3;for(;;){await H(f);let u=await p(`/api/v1/workflows/${o}/runs/${a.runId}`);if(console.error(` Status: ${u.status}`),q.has(u.status)){if(u.status!=="COMPLETED"){let C=z(u.error);console.error(`
19
- Run failed (${u.status}): ${C}`),console.log(JSON.stringify(u,null,2)),process.exit(1)}console.log(JSON.stringify(u,null,2));return}f=Math.min(f*1.5,h)}},"runWorkflow"),Q=t(async()=>{let e=await p("/api/v1/workflows");console.log(JSON.stringify(e,null,2))},"listWorkflows"),ee=t(async()=>{let e=await p("/api/v1/sources");console.log(JSON.stringify(e,null,2))},"listSources"),oe=t(async e=>{let o=await p(`/api/v1/sources/${encodeURIComponent(e)}/sample`);console.log(JSON.stringify(o,null,2))},"sampleSource"),N=t(async e=>{let o=await P(e),n=o?null:e.find(i=>i.startsWith("{")),s=!o&&!n?await A():null,r=o??n??s;(!r||r.trim().length===0)&&(console.error("Error: No JSON provided."),console.error("Pass inline JSON, --file <path>, or pipe to stdin."),process.exit(2));try{return JSON.parse(r)}catch{console.error("Error: Invalid JSON."),process.exit(2)}},"readJsonInput"),ne=t(async e=>{let o=m(e,"--name"),n=m(e,"--slug");(!o||!n)&&(console.error("Usage: kenobi-pages workflow create --name '<name>' --slug '<slug>' --config '<json>'"),console.error(" kenobi-pages workflow create --name '<name>' --slug '<slug>' --file config.json"),process.exit(2));let s=m(e,"--description"),r=e.indexOf("--config"),i=r!==-1&&e[r+1]?[e[r+1]]:e,c=await N(i),a={name:o,slug:n,config:c};s&&(a.description=s);let f=await p("/api/v1/workflows",{method:"POST",body:a});console.log(JSON.stringify(f,null,2)),console.error(`Workflow "${o}" created.`)},"workflowCreate"),se=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages workflow get <workflowId>"),process.exit(2));let n=await p(`/api/v1/workflows/${o}?full=true`);console.log(JSON.stringify(n,null,2))},"workflowGet"),re=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages workflow update <workflowId> --config '<json>'"),console.error(" kenobi-pages workflow update <workflowId> --file config.json"),process.exit(2));let n=e.slice(1),s=m(n,"--name"),r=m(n,"--description"),i=n.indexOf("--config"),c=i!==-1&&n[i+1]?[n[i+1]]:n,a={};s&&(a.name=s),r!==void 0&&(a.description=r),(n.includes("--config")||n.includes("--file"))&&(a.config=await N(c)),Object.keys(a).length===0&&(console.error("Error: Nothing to update. Pass --name, --description, --config, or --file."),process.exit(2));let h=await p(`/api/v1/workflows/${o}`,{method:"PUT",body:a});console.log(JSON.stringify(h,null,2)),console.error("Workflow updated.")},"workflowUpdate"),te=t(async e=>{let o=e[0];o||(console.error("Usage: kenobi-pages workflow delete <workflowId>"),process.exit(2)),await p(`/api/v1/workflows/${o}`,{method:"DELETE"}),console.error("Workflow deleted.")},"workflowDelete"),ie=`kenobi-pages \u2014 Kenobi Pages CLI
21
+ }`);return}if(t==="push"){let s=d(n[0],"Usage: kenobi-pages self-hosted schema push <name> '<json>'"),r=await x(n.slice(1),"schema");l(await u("/api/v1/pages/self-hosted/schemas",{method:"POST",body:{title:s,schemaJson:r}}));return}throw p(`Unknown self-hosted schema command: ${e.join(" ")}`)},"handleSchema"),et=o(async e=>{let[t,...n]=e;if(t==="list"){let s=d(n[0],"Usage: kenobi-pages self-hosted content list <workflowIdOrSlug>");l(await u(`/api/v1/pages/self-hosted/content-entries?${v({workflowId:s})}`));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages self-hosted content get <workflowIdOrSlug> <slug>"),r=d(n[1],"Usage: kenobi-pages self-hosted content get <workflowIdOrSlug> <slug>");l(await u(`/api/v1/pages/self-hosted/${s}/${r}`));return}if(t==="upsert"){let s=f(n,"--workflow","Missing --workflow <idOrSlug>"),r=f(n,"--source-key","Missing --source-key <sourceKey>"),i=f(n,"--slug","Missing --slug <slug>"),c=await C(n,"--content","--content"),a=await re(n,"--metadata","--metadata");l(await u("/api/v1/pages/self-hosted/content-entries",{method:"POST",body:{workflowId:await Ze(s),slug:i,sourceKey:r,contentJson:c,...a!==void 0?{metadataJson:a}:{}}}));return}throw p(`Unknown self-hosted content command: ${e.join(" ")}`)},"handleContent"),ge=o(async e=>{let[t,n,...s]=e;if(t==="schema")return Xe([n,...s].filter(Boolean));if(t==="content")return et([n,...s].filter(Boolean));throw p(`Unknown self-hosted command: ${e.join(" ")}`)},"handleSelfHosted");var fe=o(async e=>{let[t,...n]=e;if(t===void 0||t==="list"){l(await u("/api/v1/cortex/sources"));return}if(t==="sample"){let s=d(n[0],"Usage: kenobi-pages sources sample <sourceKey>");l(await u(`/api/v1/cortex/sources/${encodeURIComponent(s)}/sample`));return}if(t==="schema"){let s=d(n[0],"Usage: kenobi-pages sources schema <sourceKey>"),i=(await u("/api/v1/cortex/sources")).sources.find(c=>c.sourceKey===s);if(!i)throw P(`Source not found: ${s}`);l({sourceKey:s,schema:i.schema??null});return}throw p(`Unknown sources command: ${e.join(" ")}`)},"handleSources");var tt=o(e=>{let t=e.resolution;return t?t.kind==="single"?"Use one record from this source.":t.kind==="lookup"?`Look up one record where ${t.field??"(missing field)"} equals runtime param ${t.param??"(missing param)"}.`:t.kind==="collection"?"Use this source as a collection.":`Unknown source resolution: ${t.kind??"(missing kind)"}.`:"Resolution is not configured."},"formatSourceResolution"),me=o((e,t)=>{let n=new Set;for(let s of Object.values(e.output?.fields??{}))s.binding?.strategy==="passthrough"&&s.binding.sourceId===t&&s.binding.sourceField&&n.add(s.binding.sourceField);for(let s of e.generationGroups??[])for(let r of s.contextSources??[])r.sourceId===t&&(r.fields?r.fields.forEach(i=>n.add(i)):Object.keys((e.sources??[]).find(i=>i.id===t)?.schema??{}).forEach(i=>n.add(i)));return[...n].sort((s,r)=>s.localeCompare(r))},"fieldsForSource"),he=o((e,t)=>Object.entries(e.output?.fields??{}).filter(([,n])=>n.binding?.groupId===t).map(([n])=>n).sort((n,s)=>n.localeCompare(s)),"producedByGroup"),nt=o(e=>{let t=e.adapterConfig??{},n=typeof t.slugField=="string"?t.slugField:null;if(e.adapter==="hosted-pages"){let s=typeof t.siteSlug=="string"?t.siteSlug:null,r=typeof t.templateSlug=="string"?t.templateSlug:null;return{id:e.id,type:e.adapter,writes:s&&r&&n?I({siteSlug:s,templateSlug:r,itemSlug:`{${n}}`}):"Hosted page URL pattern is incomplete.",slugField:n}}return e.adapter==="self-hosted-pages"?{id:e.id,type:e.adapter,writes:n?`Self-hosted page content keyed by workflowId + {${n}}.`:"Self-hosted page slug field is not configured.",slugField:n}:{id:e.id,type:e.adapter??"unknown",writes:"Destination is not a Kenobi Pages destination.",slugField:n}},"destinationSummary"),st=o(e=>{let t=[],n=new Set((e.params??[]).map(i=>i.name)),s=e.output?.fields??{},r=new Set;for(let[i,c]of Object.entries(s)){let a=c.binding;(!a||a.strategy==="unconfigured")&&t.push(`Output field "${i}" is unconfigured.`),a?.strategy==="param"&&a.paramName&&!n.has(a.paramName)&&t.push(`Output field "${i}" references missing param "${a.paramName}".`),(a?.strategy==="generate"||a?.strategy==="generate-image")&&r.add(i)}for(let i of e.sources??[])i.resolution?.kind==="lookup"&&i.resolution.param&&(n.has(i.resolution.param)||t.push(`Source "${i.id}" lookup references missing param "${i.resolution.param}".`));for(let i of e.generationGroups??[])he(e,i.id).length===0&&t.push(`Generation group "${i.id}" does not produce any output fields.`);for(let i of e.destinations??[]){let c=i.adapterConfig??{},a=typeof c.slugField=="string"?c.slugField:null;if(!a){t.push(`Destination "${i.id}" is missing adapterConfig.slugField.`);continue}s[a]?s[a].type!=="string"&&t.push(`Destination "${i.id}" slugField "${a}" is not a string field.`):t.push(`Destination "${i.id}" slugField "${a}" is not in output.fields.`)}return t},"collectWarnings"),we=o(e=>({summary:e.description??e.output?.title??e.id??"Kenobi workflow",inputs:(e.params??[]).map(t=>({name:t.name,description:t.description??null})),sources:(e.sources??[]).map(t=>({id:t.id,title:t.title??t.id,provider:t.provider??null,sourceKey:t.dataSourceKey??null,resolution:tt(t),fieldsUsed:me(e,t.id)})),generation:(e.generationGroups??[]).map(t=>({group:t.id,strategy:t.strategy??null,uses:(t.contextSources??[]).map(n=>({sourceId:n.sourceId,fields:n.fields??me(e,n.sourceId)})),produces:he(e,t.id)})),output:{dataSourceKey:e.output?.dataSourceKey??null,title:e.output?.title??null,fields:Object.keys(e.output?.fields??{})},destinations:(e.destinations??[]).map(nt),warnings:st(e)}),"explainWorkflow");var ke=o((e,t)=>Object.fromEntries(Object.entries(e).map(([n,s])=>[n,{...s,binding:n===t?{strategy:"param",paramName:t}:{strategy:"unconfigured"}}])),"asUnconfiguredOutputFields"),ye=o((e,t)=>({...e,[t]:{type:"string",description:"URL slug for the generated page.",...e[t]}}),"ensureSlugField"),ot=o(e=>e.split(":").pop()?.replace(/[^a-z0-9]+/gi,"-").replace(/^-+|-+$/g,"").toLowerCase()||"pages-workflow","slugFromSourceKey"),rt=o(async e=>{let t=f(e,"--template-publication","Usage: kenobi-pages workflow scaffold hosted --template-publication <templateId:publicationId> --site <siteSlug> --template <templateSlug> --slug-field <field>"),[n,s]=t.split(":");if(!n||!s)throw p("--template-publication must be <templateId:publicationId>");let r=f(e,"--site","Missing --site <siteSlug>"),i=f(e,"--template","Missing --template <templateSlug>"),c=f(e,"--slug-field","Missing --slug-field <field>"),m=(await u(`/api/v1/pages/hosted/templates/${n}/publications/${s}`)).cortexOutputFieldSpecs??{},h=ke(ye(m,c),c);l({id:`${r}-${i}`,params:[{name:c,description:"Public hosted page item slug."}],sources:[],output:{dataSourceKey:`hosted-pages:${i}`,title:`${i} hosted page`,fields:h},generationGroups:[],destinations:[{id:"hosted-pages",adapter:"hosted-pages",adapterConfig:{siteSlug:r,templateSlug:i,slugField:c,publicationId:Number(s)}}]})},"scaffoldHosted"),it=o(async e=>{let t=f(e,"--source-key","Usage: kenobi-pages workflow scaffold self-hosted --source-key <sourceKey> --slug-field <field>"),n=f(e,"--slug-field","Missing --slug-field <field>"),r=(await u("/api/v1/cortex/sources")).sources.find(a=>a.sourceKey===t);if(!r)throw P(`Source not found: ${t}`);let i=ke(ye(r.schema??{},n),n),c=ot(t);l({id:c,params:[{name:n,description:"URL slug for the generated page."}],sources:[],output:{dataSourceKey:t,title:r.sourceTitle??c,fields:i},generationGroups:[],destinations:[{id:"self-hosted-pages",adapter:"self-hosted-pages",adapterConfig:{slugField:n}}]})},"scaffoldSelfHosted"),at=o(async e=>{let[t,...n]=e;if(t==="hosted")return rt(n);if(t==="self-hosted")return it(n);throw p(`Unknown workflow scaffold command: ${e.join(" ")}`)},"handleScaffold"),L=o(async e=>{let[t,...n]=e;if(t===void 0||t==="list"){l(await u("/api/v1/cortex/workflows"));return}if(t==="create"){let s=f(n,"--name","Missing --name <name>"),r=f(n,"--slug","Missing --slug <slug>"),i=g(n,"--description"),c=n.indexOf("--config"),a=c!==-1&&n[c+1]?[n[c+1]]:n,m={name:s,slug:r,config:await x(a,"workflow config")};i&&(m.description=i),l(await u("/api/v1/cortex/workflows",{method:"POST",body:m}));return}if(t==="get"){let s=d(n[0],"Usage: kenobi-pages workflow get <workflowIdOrSlug>");l(await u(`/api/v1/cortex/workflows/${s}?full=true`));return}if(t==="update"){let s=d(n[0],"Usage: kenobi-pages workflow update <workflowIdOrSlug> [flags]"),r=n.slice(1),i={},c=g(r,"--name"),a=g(r,"--description"),m=r.indexOf("--config"),h=m!==-1&&r[m+1]?[r[m+1]]:r;if(c&&(i.name=c),a!==void 0&&(i.description=a),(r.includes("--config")||r.includes("--file"))&&(i.config=await x(h,"workflow config")),Object.keys(i).length===0)throw p("Nothing to update");l(await u(`/api/v1/cortex/workflows/${s}`,{method:"PUT",body:i}));return}if(t==="delete"){let s=d(n[0],"Usage: kenobi-pages workflow delete <workflowIdOrSlug>");l(await u(`/api/v1/cortex/workflows/${s}`,{method:"DELETE"}));return}if(t==="explain"){let s=await x(n,"workflow config");l(we(s));return}if(t==="scaffold")return at(n);throw p(`Unknown workflow command: ${e.join(" ")}`)},"handleWorkflows");var ct=`kenobi-pages - Kenobi Pages CLI
20
22
 
21
23
  Commands:
22
- init Set up your API key (interactive)
24
+ doctor
25
+ init
26
+ init --key <key> [--env-file <path>] [--base-url <url>]
23
27
 
24
- schema get <workflowId> Fetch a workflow's output schema
25
- schema codegen <workflowId> Generate a TypeScript interface from a schema
26
- schema push <name> '<json>' Push a schema to Kenobi (inline JSON)
27
- schema push <name> --file f Push a schema to Kenobi (from file)
28
+ evidence list
29
+ evidence create <url> [flags]
30
+ evidence get <bundleId>
28
31
 
29
- pages <workflowId> List all generated pages for a workflow
30
- page get <workflowId> <slug> Fetch page content for a specific lead
32
+ design-pack list <bundleId>
33
+ design-pack generate <bundleId> [--wait]
34
+ design-pack status <bundleId> <taskId>
35
+ design-pack get <bundleId> <designPackId>
36
+ design-pack export <bundleId> <designPackId>
31
37
 
32
- sources List connected data sources
33
- sources sample <sourceKey> Preview sample rows from a source
34
- workflows List workflows for your org
38
+ hosted site list
39
+ hosted site get <siteSlug>
40
+ hosted page create --site-slug <slug> --template-slug <slug> --template-name <name> --source <tsx-file> --schema <json-file> --content <json-file> [flags]
41
+ hosted template list [--full]
42
+ hosted template get <templateIdOrSlug> [--full]
43
+ hosted draft save --template-slug <slug> --template-name <name> --source <tsx-file> --schema <json-file> --content <json-file> [flags]
44
+ hosted publish <templateIdOrSlug>
45
+ hosted publication list <templateIdOrSlug>
46
+ hosted publication get <templateIdOrSlug> <publicationId>
47
+ hosted content list --site <siteSlug> [--template <templateSlug>]
48
+ hosted content get <siteSlug> <templateSlug> <itemSlug>
49
+ hosted content upsert --site <siteSlug> --template <templateSlug> --item <itemSlug> --content <json|file|->
50
+ hosted content verify <siteSlug> <templateSlug> <itemSlug>
35
51
 
36
- workflow create --name '\u2026' --slug '\u2026' --config '<json>' Create a workflow
37
- workflow create --name '\u2026' --slug '\u2026' --file config.json Create from file
38
- workflow get <id> Get full workflow config
39
- workflow update <id> --config '<json>' Update workflow config
40
- workflow update <id> --file config.json Update from file
41
- workflow delete <id> Delete a workflow
52
+ self-hosted schema list
53
+ self-hosted schema get <workflowIdOrSlug>
54
+ self-hosted schema codegen <workflowIdOrSlug>
55
+ self-hosted schema push <name> '<json>'
56
+ self-hosted content list <workflowIdOrSlug>
57
+ self-hosted content get <workflowIdOrSlug> <slug>
58
+ self-hosted content upsert --workflow <idOrSlug> --source-key <sourceKey> --slug <slug> --content <json|file|-> [--metadata <json|file|->]
42
59
 
43
- run <workflowId> [flags] Trigger a workflow run and poll to completion
60
+ sources [list]
61
+ sources sample <sourceKey>
62
+ sources schema <sourceKey>
63
+ workflows
64
+ workflow create --name <name> --slug <slug> --config '<json>'
65
+ workflow create --name <name> --slug <slug> --file config.json
66
+ workflow get <idOrSlug>
67
+ workflow update <idOrSlug> [--name <name>] [--description <description>] [--config '<json>'|--file config.json]
68
+ workflow delete <idOrSlug>
69
+ workflow explain --file workflow.json
70
+ workflow explain --config '<json>'
71
+ workflow scaffold hosted --template-publication <templateId:publicationId> --site <siteSlug> --template <templateSlug> --slug-field <field>
72
+ workflow scaffold self-hosted --source-key <sourceKey> --slug-field <field>
73
+ run <workflowIdOrSlug> [--params '<json>'] [--context <text>]
44
74
 
45
- Examples:
46
- npx kenobi-pages init
47
- npx kenobi-pages sources
48
- npx kenobi-pages sources sample "notion:abc123"
49
- npx kenobi-pages schema get 42
50
- npx kenobi-pages schema codegen 42 > lib/kenobi-types.ts
51
- npx kenobi-pages schema push "My Page" '{"fields":{"headline":{"type":"string"}}}'
52
- npx kenobi-pages pages 42
53
- npx kenobi-pages page get 42 acme-corp
54
- npx kenobi-pages workflows
55
- npx kenobi-pages workflow create --name "Lead page" --slug "lead-page" --config '{...}'
56
- npx kenobi-pages workflow get 42
57
- npx kenobi-pages workflow update 42 --config '{...}'
58
- npx kenobi-pages workflow delete 42
59
- npx kenobi-pages run 42 --params '{"slug":"acme-corp"}'
60
- npx kenobi-pages run 42 --params '{"slug":"acme-corp"}' --context "Call transcript: ..."
75
+ Agent-first examples:
76
+ kenobi-pages doctor
77
+ kenobi-pages init --key pk_test_... --env-file .env.local
78
+ kenobi-pages evidence create https://example.com --block-annoyances
79
+ kenobi-pages design-pack generate 123 --wait
80
+ kenobi-pages design-pack export 123 456
81
+ kenobi-pages hosted page create --site-slug acme --template-slug follow-up --template-name "Follow-up" --source template.tsx --schema schema.json --content preview.json --design-pack-id 456
82
+ kenobi-pages workflow explain --file workflow.json
83
+ kenobi-pages hosted content verify acme follow-up globex
61
84
 
62
85
  Output:
63
- All data is written as JSON to stdout. Status messages go to stderr.
64
- Pipe stdout to jq, a file, or another command safely.
65
-
66
- Exit codes:
67
- 0 Success
68
- 1 API or network error
69
- 2 Invalid usage (bad arguments)
70
- 3 Resource not found (404)
71
- 4 Unauthorized (invalid API key)
86
+ Data is JSON on stdout. Progress goes to stderr. Errors are JSON on stderr.
72
87
 
73
88
  Environment:
74
- KENOBI_PAGES_KEY Org public key. Set via 'init' or in your env file.
75
- KENOBI_BASE_URL Optional. Override the Kenobi API base URL.
76
-
77
- Key resolution order:
78
- 1. Shell environment variables
79
- 2. Env files in working directory (.env.local, .env, .env.development, etc.)
80
- `,[,,...b]=process.argv;(b.length===0||b[0]==="--help"||b[0]==="-h")&&(console.log(ie),process.exit(0));var[g,l,...d]=b;if(g==="init")await D();else if(g==="schema"&&l==="get")await G(d);else if(g==="schema"&&l==="codegen")await M(d);else if(g==="schema"&&l==="push")await Y(d);else if(g==="pages")await V([l,...d].filter(Boolean));else if(g==="page"&&l==="get")await Z(d);else if(g==="sources")if(l==="sample"){let e=d[0];e||(console.error("Usage: kenobi-pages sources sample <sourceKey>"),process.exit(2)),await oe(e)}else l===void 0||l==="list"?await ee():(console.error(`Unknown sources subcommand: ${l}`),console.error("Run 'kenobi-pages --help' for usage."),process.exit(2));else g==="workflows"?await Q():g==="workflow"&&l==="create"?await ne(d):g==="workflow"&&l==="get"?await se(d):g==="workflow"&&l==="update"?await re(d):g==="workflow"&&l==="delete"?await te(d):g==="run"?await X([l,...d].filter(Boolean)):(console.error(`Unknown command: ${b.join(" ")}`),console.error("Run 'kenobi-pages --help' for usage."),process.exit(1));
89
+ KENOBI_PAGES_KEY Org public key. Set via init or in your env file.
90
+ KENOBI_BASE_URL Optional API base URL override.
91
+ `,Se=o(()=>{console.log(ct)},"printHelp");import{resolve as O}from"node:path";import{createInterface as lt}from"node:readline";var F=o(e=>new Promise(t=>{let n=lt({input:process.stdin,output:process.stderr});n.question(e,s=>{n.close(),t(s.trim())})}),"prompt"),ut=o(async e=>e.startsWith("pk_live_")||e.startsWith("pk_test_")?!0:(console.error(` Warning: "${e}" does not look like a Kenobi key (expected pk_live_... or pk_test_...).`),(await F(" Continue anyway? (y/N): ")).toLowerCase()==="y"),"validateKey"),dt=o(()=>R()[0]??".env.local","defaultEnvFile"),pt=o(e=>{let t=g(e,"--key");if(!t||t.startsWith("--"))throw p("Usage: kenobi-pages init --key <key> [--env-file <path>] [--base-url <url>]");let n=g(e,"--env-file")??dt(),s=g(e,"--base-url"),r=O(process.cwd(),n);J(r,w,t),s&&!s.startsWith("--")&&J(r,"KENOBI_BASE_URL",s),l({ok:!0,envFile:n,wrote:{[w]:!0,KENOBI_BASE_URL:!!(s&&!s.startsWith("--"))}})},"nonInteractiveInit"),be=o(async(e=[])=>{if(g(e,"--key")!==void 0){pt(e);return}console.error(""),console.error(" Kenobi Pages - Setup"),console.error(""),console.error(" Find your API key at: https://kenobi.ai/setup"),console.error("");let t=await F(" Paste your API key (pk_live_... or pk_test_...): ");t||(console.error(" No key provided. Aborting."),process.exit(1)),await ut(t)||(console.error(" Aborting."),process.exit(1));let n=R();if(n.length>0){console.error(""),console.error(" Found env files in this project:"),n.forEach((i,c)=>console.error(` ${c+1}. ${i}`)),console.error(` ${n.length+1}. Create a new file`),console.error(` ${n.length+2}. Skip`),console.error("");let s=await F(` Which file should ${w} be added to? [1]: `),r=s===""?0:parseInt(s,10)-1;if(r===n.length){let i=await F(" Filename (e.g. .env.local): ");i&&(T(O(process.cwd(),i),w,t),console.error(` Created ${i} with ${w}`))}else r>=0&&r<n.length&&Q(O(process.cwd(),n[r]),w,t)}else{console.error("");let s=await F(" No env files found. Create one? (filename or 'n' to skip) [.env.local]: ");s.toLowerCase()!=="n"&&s!==""?(T(O(process.cwd(),s),w,t),console.error(` Created ${s} with ${w}`)):s===""&&(T(O(process.cwd(),".env.local"),w,t),console.error(` Created .env.local with ${w}`))}console.error(""),console.error(" Done. Your agent can now use kenobi-pages commands."),console.error(" Run 'npx kenobi-pages --help' to see what is available."),console.error("")},"initCommand");var gt=o(async e=>{if(e.length===0||e[0]==="--help"||e[0]==="-h"){Se();return}let[t,...n]=e;if(t==="init")return be(n);if(t==="doctor")return ne();if(t==="evidence")return ae(n);if(t==="design-pack")return X(n);if(t==="hosted")return de(n);if(t==="self-hosted")return ge(n);if(t==="sources")return fe(n);if(t==="workflows")return L(["list",...n]);if(t==="workflow")return L(n);if(t==="run")return pe(n);throw p(`Unknown command: ${e.join(" ")}`)},"main");gt(process.argv.slice(2)).catch(H);
package/dist/client.js CHANGED
@@ -1 +1 @@
1
- var b=Object.defineProperty;var o=(i,s)=>b(i,"name",{value:s,configurable:!0});import{KenobiPagesError as c,KenobiNotFoundError as a,KenobiUnauthorizedError as f}from"./errors";const K="https://kenobi.ai",l=o(async(i,s,e)=>{const r=(i.baseUrl??K).replace(/\/+$/,""),n={headers:{"x-kenobi-key":i.apiKey}};(e?.revalidate!==void 0||e?.tags)&&(n.next={},e.revalidate!==void 0&&(n.next.revalidate=e.revalidate),e.tags&&(n.next.tags=[...e.tags]));const t=await fetch(`${r}${s}`,n);if(t.ok)return t;if(t.status===401)throw new f;if(t.status===404)throw new a;const g=await t.text().catch(()=>"Unknown error");throw new c(`Kenobi API error (${t.status}): ${g}`,t.status,"API_ERROR")},"fetchPage"),h=o(i=>({getPage:o(async(s,e,r)=>{try{return await(await l(i,`/api/v1/pages/${s}/${e}`,r)).json()}catch(n){if(n instanceof a)return null;throw n}},"getPage")}),"createKenobiPagesClient");export{h as createKenobiPagesClient};
1
+ var l=Object.defineProperty;var o=(s,e)=>l(s,"name",{value:e,configurable:!0});import{KenobiPagesError as d,KenobiNotFoundError as c,KenobiUnauthorizedError as u}from"./errors";const b="https://kenobi.ai",p=o(async(s,e,n,t)=>{const r=(s.baseUrl??b).replace(/\/+$/,""),a={...n,headers:{"x-kenobi-key":s.apiKey,...n?.headers}};(t?.revalidate!==void 0||t?.tags)&&(a.next={},t.revalidate!==void 0&&(a.next.revalidate=t.revalidate),t.tags&&(a.next.tags=[...t.tags]));const i=await fetch(`${r}${e}`,a);if(i.ok)return i;if(i.status===401)throw new u;if(i.status===404)throw new c;const g=await i.text().catch(()=>"Unknown error");throw new d(`Kenobi API error (${i.status}): ${g}`,i.status,"API_ERROR")},"fetchPage"),f=o(s=>({selfHosted:{getPage:o(async(e,n,t)=>{try{return await(await p(s,`/api/v1/pages/self-hosted/${e}/${n}`,void 0,t)).json()}catch(r){if(r instanceof c)return null;throw r}},"getPage")},hosted:{getPageInstance:o(async(e,n,t,r)=>{try{return await(await p(s,`/api/v1/pages/hosted/instances/${e}/${n}/${t}`,void 0,r)).json()}catch(a){if(a instanceof c)return null;throw a}},"getPageInstance"),upsertPageInstance:o(async e=>await(await p(s,"/api/v1/pages/hosted/instances",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})).json(),"upsertPageInstance"),saveTemplateDraft:o(async e=>await(await p(s,"/api/v1/pages/hosted/templates/drafts",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})).json(),"saveTemplateDraft"),publishTemplate:o(async e=>await(await p(s,`/api/v1/pages/hosted/templates/${e}/publish`,{method:"POST"})).json(),"publishTemplate")}}),"createKenobiPagesClient");export{f as createKenobiPagesClient};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { createKenobiPagesClient } from "./client";
2
2
  export { KenobiPagesError, KenobiUnauthorizedError, KenobiNotFoundError } from "./errors";
3
- export type { KenobiPagesClient, KenobiPagesConfig, KenobiFetchOptions, KenobiPageResponse, } from "./types";
3
+ export type { KenobiFetchOptions, KenobiHostedPagesClient, KenobiPageInstanceResponse, KenobiPageResponse, KenobiPagesClient, KenobiPagesConfig, KenobiSelfHostedPagesClient, PublishTemplateResponse, UpsertPageInstanceInput, } from "./types";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{createKenobiPagesClient as r}from"./client";import{KenobiPagesError as i,KenobiUnauthorizedError as t,KenobiNotFoundError as b}from"./errors";export{b as KenobiNotFoundError,i as KenobiPagesError,t as KenobiUnauthorizedError,r as createKenobiPagesClient};
1
+ import{createKenobiPagesClient as n}from"./client";import{KenobiPagesError as s,KenobiUnauthorizedError as i,KenobiNotFoundError as r}from"./errors";export{r as KenobiNotFoundError,s as KenobiPagesError,i as KenobiUnauthorizedError,n as createKenobiPagesClient};
package/dist/types.d.ts CHANGED
@@ -13,8 +13,62 @@ export interface KenobiFetchOptions {
13
13
  export interface KenobiPageResponse {
14
14
  readonly content: Record<string, unknown>;
15
15
  readonly metadata: Record<string, unknown> | null;
16
+ readonly outputSchemaSnapshot?: Record<string, unknown> | null;
16
17
  readonly updatedAt: string;
17
18
  }
18
- export interface KenobiPagesClient {
19
+ export interface KenobiPageInstanceResponse {
20
+ readonly pageInstance: Record<string, unknown>;
21
+ readonly templatePublication?: Record<string, unknown>;
22
+ readonly content?: Record<string, unknown>;
23
+ }
24
+ export interface UpsertPageInstanceInput {
25
+ readonly siteSlug: string;
26
+ readonly templateSlug: string;
27
+ readonly itemSlug: string;
28
+ readonly publicationId?: number;
29
+ readonly contentJson: Record<string, unknown>;
30
+ readonly metadataJson?: Record<string, unknown> | null;
31
+ readonly sourceWorkflowId?: number | null;
32
+ readonly sourceRunId?: string | null;
33
+ }
34
+ export interface PublishTemplateResponse {
35
+ readonly publication: Record<string, unknown>;
36
+ readonly currentPublishedPublicationId: number | null;
37
+ }
38
+ export interface SaveHostedTemplateDraftInput {
39
+ readonly templateSlug: string;
40
+ readonly templateName: string;
41
+ readonly sourceTsx: string;
42
+ readonly contentSchema: {
43
+ readonly sourceKey?: string;
44
+ readonly title?: string;
45
+ readonly schemaJson: Record<string, unknown>;
46
+ };
47
+ readonly defaultContentJson: Record<string, unknown>;
48
+ readonly designPackId?: number | null;
49
+ readonly site?: {
50
+ readonly slug: string;
51
+ readonly name?: string | null;
52
+ };
53
+ readonly setCurrentDraft?: boolean;
54
+ }
55
+ export interface SaveHostedTemplateDraftResponse {
56
+ readonly template: Record<string, unknown>;
57
+ readonly revision: Record<string, unknown>;
58
+ readonly contentSchema: Record<string, unknown>;
59
+ readonly site: Record<string, unknown> | null;
60
+ readonly previewPath: string;
61
+ }
62
+ export interface KenobiSelfHostedPagesClient {
19
63
  readonly getPage: (workflowId: number | string, slug: string, opts?: KenobiFetchOptions) => Promise<KenobiPageResponse | null>;
20
64
  }
65
+ export interface KenobiHostedPagesClient {
66
+ readonly getPageInstance: (siteSlug: string, templateSlug: string, itemSlug: string, opts?: KenobiFetchOptions) => Promise<KenobiPageInstanceResponse | null>;
67
+ readonly upsertPageInstance: (input: UpsertPageInstanceInput) => Promise<KenobiPageInstanceResponse>;
68
+ readonly saveTemplateDraft: (input: SaveHostedTemplateDraftInput) => Promise<SaveHostedTemplateDraftResponse>;
69
+ readonly publishTemplate: (templateId: number | string) => Promise<PublishTemplateResponse>;
70
+ }
71
+ export interface KenobiPagesClient {
72
+ readonly selfHosted: KenobiSelfHostedPagesClient;
73
+ readonly hosted: KenobiHostedPagesClient;
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kenobi-pages",
3
- "version": "0.1.14",
3
+ "version": "0.1.16",
4
4
  "description": "Kenobi Pages SDK — fetch personalized page content from Kenobi workflows",
5
5
  "type": "module",
6
6
  "exports": {