@flexkit/cli 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -548,10 +548,10 @@ ${mB.default.bold("Skills")}
|
|
|
548
548
|
`)),0}async function FbA(A,e,t,i,n){let{client:r}=A,o=hX(e,n,i,{cwd:r.cwd}),s=o.file,g=Ee(s),B=ZA__default.default.existsSync(s)?ZA__default.default.readFileSync(s,"utf8"):null,I=hU(B,o.key,t,o.entry);if(I.status==="unchanged")return r.output.log(`${g} already has the ${t} server with this URL.`),0;if(I.status==="conflict"){if(r.output.log(`${g} already has a "${t}" server: ${JSON.stringify(I.previous)}`),A.flags["--dry-run"]&&!A.yes&&r.output.log("Installing will ask before replacing it (or pass --yes); --name adds the server under another name."),!A.flags["--dry-run"]&&!await $A(A,`Replace the "${t}" server in ${g}?`))return 1;I=hU(B,o.key,t,o.entry,{replace:true});}if(I.status==="conflict"||I.status==="unchanged")return 1;if(A.flags["--dry-run"])return r.output.log(`Would ${B===null?"create":"update"} ${g}:`),r.stdout.write(I.text),0;ZA__default.default.mkdirSync(ut__default.default.dirname(s),{recursive:true}),ZA__default.default.writeFileSync(s,I.text);let E=I.status==="replaced"?"Replaced":"Added",u={cursor:"Cursor",vscode:"VS Code",windsurf:"Windsurf"};return r.output.success(`${E} the ${t} server in ${g}. Reload ${u[e]} and sign in to Flexkit when it asks.`),0}var SbA={command:lU,aliases:["add"],flags:{...fX,"--client":String,"--scope":String,"--name":String,"--dry-run":Boolean},async run(A){let{client:e}=A,t=await mbA(A);if(!t)return 1;let i=lX[t],n=A.flags["--scope"]??i[0];if(!i.includes(n))return e.output.error(`--scope for ${t} must be one of: ${i.join(", ")}.`),1;let r=A.flags["--name"]?.trim()||"flexkit";if(!/^[A-Za-z0-9_-]{1,64}$/.test(r))return e.output.error("--name may only use letters, digits, - and _."),1;let o=await pX(A);if(!o)return 1;switch(t){case "claude-code":return wbA(A,r,o.url,n);case "claude-desktop":return ybA(e,r,o.url);default:return FbA(A,t,r,o.url,n)}}};async function pU(A){return KA(A,{command:uX,subcommands:[DbA,SbA],defaultSubcommand:"url"})}var da=nA(RA());function RQ(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var ID=RQ("json",Boolean,"Print the API response as JSON on stdout"),CD=RQ("project",String,"Project to use (default: linked project)","ID","p"),kbA=RQ("yes",Boolean,"Skip the confirmation prompt",void 0,"y"),DU={name:"ls",description:"List the project API tokens: name, role, spaces, the last characters of the token, who created it and when. The secrets are never shown again.",arguments:[],options:[ID,CD],examples:[{name:"List tokens",value:"flexkit tokens ls"},{name:"Names and roles as JSON",value:`flexkit tokens ls --json | jq -r '.tokens[] | "\\(.name) \\(.role)"'`},{name:"Tokens of another project",value:"flexkit tokens ls --project abcdefghij"}]},mU={name:"create",description:"Create a project API token and print it once. The token goes to stdout and the notes to stderr, so `$(flexkit tokens create \u2026)` captures only the token. You cannot give a token a higher role than yours, nor spaces you are not in.",arguments:[{name:"name",required:true}],options:[RQ("role",String,"Token role: viewer, editor, contributor or developer (default: viewer)","ROLE","r"),RQ("space",[String],"Space code or id the token may read, repeatable or comma separated (default: unrestricted data only)","SPACE","s"),ID,CD],examples:[{name:"Create a read-only token",value:'flexkit tokens create "Storefront"'},{name:"A developer token for CI",value:'flexkit tokens create "GitHub Actions" --role developer'},{name:"An editor token that also reads two spaces",value:'flexkit tokens create "Sales sync" --role editor --space sales --space marketing'},{name:"Store the token as a GitHub secret",value:'flexkit tokens create "GitHub Actions" --role developer | gh secret set FLEXKIT_TOKEN'},{name:"Read the token from JSON in a script",value:"flexkit tokens create nightly-export --json | jq -r '.token.value'"}]},wU={name:"rm",description:"Revoke a project API token by its id or exact name. Apps and scripts that use it stop working at once.",arguments:[{name:"idOrName",required:true}],options:[kbA,ID,CD],examples:[{name:"Revoke a token by name",value:'flexkit tokens rm "Storefront"'},{name:"Revoke by id without a prompt",value:"flexkit tokens rm 42 --yes"}]},DX={name:"tokens",description:"Manage the project's API tokens, which authenticate apps, scripts and CI (FLEXKIT_TOKEN). Needs a signed-in Owner or Developer: API tokens cannot manage tokens.",arguments:[],subcommands:[DU,mU,wU],options:[ID,CD],examples:[{name:"List tokens",value:"flexkit tokens ls"},{name:"Create a developer token for CI",value:'flexkit tokens create "GitHub Actions" --role developer'},{name:"Revoke a token",value:'flexkit tokens rm "GitHub Actions"'}]};var mX=["viewer","editor","contributor","developer"];function RbA(A){if(A===void 0)return "viewer";let e=A.trim().toLowerCase();if(e==="owner")throw new Error("Owner tokens cannot be created. Use --role developer for a token that manages the project.");if(!mX.includes(e))throw new Error(`Unknown role "${A}". Use one of: ${mX.join(", ")}.`);return e}function bbA(A){let e=(A??[]).flatMap(t=>t.split(",")).map(t=>t.trim());return [...new Set(e.filter(Boolean))]}function wX(A){let e=A.name?.trim()??"";if(!e)throw new Error('Give the token a name, for example `flexkit tokens create "GitHub Actions"`.');return {name:e,role:RbA(A.role),spaces:bbA(A.spaces)}}function yU(A){return A.length>0?A.map(e=>e.code).join(", "):"unrestricted only"}function yX(A,e=Date.now()){return A.map(t=>[String(t.id),t.name,t.role.toLowerCase(),yU(t.spaces),t.last_digits?`****${t.last_digits}`:"",t.created_by_name??"",QA(t.created_at,e)])}function FX(A,e){let t=e.trim();if(/^\d+$/.test(t)){let r=A.find(o=>String(o.id)===t);if(r)return r}let i=t.toLowerCase(),n=A.filter(r=>r.name.toLowerCase()===i);if(n.length===0)throw new Error(`No token named "${e}". Run \`flexkit tokens ls\` to see the project's tokens.`);if(n.length>1)throw new Error(`Several tokens are named "${e}": ${n.map(r=>String(r.id)).join(", ")}. Pass the id instead.`);return n[0]}async function SX(A){let{tokens:e}=await A.client.fetch("/tokens",{projectId:A.projectId});return e}var NbA={command:DU,aliases:["list"],needsProject:true,async run(A){let e=await SX(A);return A.json?(q(A.client,{tokens:e}),0):(fA(A.client,["ID","NAME","ROLE","SPACES","TOKEN","CREATED BY","CREATED"],yX(e),"No API tokens yet. Create one with `flexkit tokens create <name>`."),0)}},MbA={command:mU,aliases:["add"],needsProject:true,flags:{"--role":String,"-r":"--role","--space":[String],"-s":"--space"},async run(A){let e=wX({name:A.args[0],role:A.flags["--role"],spaces:A.flags["--space"]}),t=await A.client.fetch("/tokens",{method:"POST",body:{...e},projectId:A.projectId});if(!t.success||!t.token?.value)throw new Error(t.errorMessage||"The token could not be created.");let{token:i}=t;if(A.json)return q(A.client,{token:i}),0;let{output:n}=A.client;return n.success(`Created token ${da.default.bold(i.name)} ${da.default.dim(`(id ${String(i.id)}, ${i.role.toLowerCase()}, spaces: ${yU(i.spaces)})`)}`),n.warn("Copy the token now: it won't be shown again."),A.client.stdout.write(`${i.value}
|
|
549
549
|
`),n.log(`Use it in CI with ${da.default.cyan("FLEXKIT_TOKEN=<token>")}, or as ${da.default.cyan("Authorization: Bearer <token>")}.`),0}},UbA={command:wU,aliases:["remove","revoke"],needsProject:true,async run(A){let e=FX(await SX(A),A.args[0]),t=e.last_digits?` ****${e.last_digits}`:"";return await $A(A,`Revoke the token "${e.name}" (id ${String(e.id)}${t})? Apps and scripts that use it stop working.`)?(await A.client.fetch(`/tokens/${String(e.id)}`,{method:"DELETE",projectId:A.projectId}),A.json?(q(A.client,{deleted:true,id:e.id}),0):(A.client.output.success(`Revoked token ${da.default.bold(e.name)} ${da.default.dim(`(id ${String(e.id)})`)}`),0)):1}};async function FU(A){return KA(A,{command:DX,subcommands:[NbA,MbA,UbA],defaultSubcommand:"ls"})}var NQ=nA(RA());function bQ(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var wB=bQ("json",Boolean,"Print the API response as JSON on stdout"),yB=bQ("project",String,"Project to use (default: linked project)","ID","p"),kX=bQ("yes",Boolean,"Skip the confirmation prompt",void 0,"y"),SU={name:"ls",description:"List the members of the project with their roles. Needs an owner or developer.",arguments:[],options:[bQ("role",String,"Only these roles, comma separated (owner,developer,contributor,editor,viewer)","LIST"),wB,yB],examples:[{name:"List members",value:"flexkit members ls"},{name:"Only owners and developers",value:"flexkit members ls --role owner,developer"},{name:"Emails of every member",value:"flexkit members ls --json | jq -r '.members[].email'"}]},kU={name:"invite",description:"Invite people by email with a role. People without a Flexkit account get an invitation email; people already in the project get the new role. Only owners can invite owners.",arguments:[{name:"email...",required:true}],options:[bQ("role",String,"Role to give: owner, developer, contributor, editor or viewer (default: viewer)","ROLE","r"),wB,yB],examples:[{name:"Invite a viewer",value:"flexkit members invite ana@acme.com"},{name:"Invite two developers",value:"flexkit members invite ana@acme.com ben@acme.com --role developer"},{name:"Invite everyone in a file, one email per line",value:"flexkit members invite $(cat team.txt) --role editor"}]},RU={name:"role",description:"Change a member's role. The member is a user id or an email. Only owners can make someone an owner or change an owner's role, and the last owner keeps the role.",arguments:[{name:"member",required:true},{name:"role",required:true}],options:[wB,yB],examples:[{name:"Make a member a developer",value:"flexkit members role ana@acme.com developer"},{name:"Hand over ownership",value:"flexkit members role ben@acme.com owner"},{name:"Downgrade by user id",value:"flexkit members role 3f9c2a1e-8d4b-4c7a-9e2f-5b6a7c8d9e0f viewer"}]},bU={name:"rm",description:"Remove a member from the project (user id or email). Anyone can remove themselves; removing someone else takes an owner or developer, and removing an owner takes an owner. The last owner cannot be removed.",arguments:[{name:"member",required:true}],options:[kX,wB,yB],examples:[{name:"Remove a member",value:"flexkit members rm ana@acme.com"},{name:"Remove without asking (scripts)",value:"flexkit members rm ana@acme.com --yes"}]},NU={name:"invitations",description:"List pending invitations (people invited who haven't accepted yet), or cancel one with `invitations cancel <id|email>`. Cancelling takes an owner or developer.",arguments:[{name:"cancel",required:false},{name:"id|email",required:false}],options:[kX,wB,yB],examples:[{name:"List pending invitations",value:"flexkit members invitations"},{name:"Cancel an invitation by email",value:"flexkit members invitations cancel ana@acme.com"},{name:"Cancel by id without asking",value:"flexkit members invitations cancel 3f9c2a1e-8d4b-4c7a-9e2f-5b6a7c8d9e0f --yes"}]},RX={name:"members",description:"Manage the people in a project: list members, invite by email, change roles, remove members and cancel invitations. Needs a signed-in user (`flexkit login`); API tokens cannot manage members.",arguments:[],subcommands:[SU,kU,RU,bU,NU],options:[wB,yB],examples:[{name:"List members",value:"flexkit members ls"},{name:"Invite a developer",value:"flexkit members invite ana@acme.com --role developer"},{name:"Change a role",value:"flexkit members role ana@acme.com viewer"},{name:"See pending invitations",value:"flexkit members invitations"}]};var FB=["owner","developer","contributor","editor","viewer"],LbA=/^\S+@\S+\.\S+$/;function BD(A,e="role"){let t=A?.trim().toLowerCase()??"";if(!FB.includes(t))throw new Error(A?`Unknown ${e} "${A}". Use one of: ${FB.join(", ")}.`:`Pass a ${e}: ${FB.join(", ")}.`);return t}function NX(A){let e=new Set,t=[];for(let i of A.flatMap(n=>n.split(/[\s,]+/)).filter(Boolean)){if(!LbA.test(i))throw new Error(`Invalid email address: ${i}`);e.has(i.toLowerCase())||(e.add(i.toLowerCase()),t.push(i));}if(t.length===0)throw new Error("Pass at least one email address.");return t}function MX(A){return A?A.split(",").map(e=>e.trim()).filter(Boolean).map(e=>BD(e,"--role")):null}var bX=Object.fromEntries(FB.map((A,e)=>[A,e]));function UX(A){return [...A].sort((e,t)=>(bX[e.role]??FB.length)-(bX[t.role]??FB.length)||e.displayName.localeCompare(t.displayName))}function LX(A){return [A.id,A.displayName===A.email?"":A.displayName,A.email,A.role]}function GX(A,e){return [A.id,A.email,A.role,e,A.invitedBy?.displayName??""]}function xX(A){let e=Array.isArray(A.errorMessage)?A.errorMessage.join(" "):A.errorMessage;return A.errorCode&&e?e:null}var GbA={command:SU,aliases:["list"],needsProject:true,flags:{"--role":String},async run(A){let e=MX(A.flags["--role"]),{members:t}=await A.client.fetch("/members",{projectId:A.projectId}),i=UX(e?t.filter(n=>e.includes(n.role)):t);return A.json?(q(A.client,{members:i}),0):(fA(A.client,["ID","NAME","EMAIL","ROLE"],i.map(n=>{let[r="",...o]=LX(n);return [NQ.default.dim(r),...o]}),e?"No members with these roles.":"No members."),0)}},xbA={command:kU,aliases:["add"],needsProject:true,flags:{"--role":String,"-r":"--role"},async run(A){let e=NX(A.args),t=A.flags["--role"],i=t===void 0?"viewer":BD(t,"--role"),n=await A.client.fetch("/members",{method:"POST",body:{emails:e,role:i},projectId:A.projectId});if(A.json)return q(A.client,n),0;for(let o of n.members)A.client.output.success(`${o.email} is now ${NQ.default.bold(o.role)} in the project`);let r=xX(n);return r&&A.client.output.warn(r),0}},vbA={command:RU,needsProject:true,async run(A){let[e="",t]=A.args,i=BD(t),n=await A.client.fetch(`/members/${encodeURIComponent(e)}`,{method:"PATCH",body:{role:i},projectId:A.projectId});return A.json?(q(A.client,n),0):(A.client.output.success(`${e} is now ${NQ.default.bold(i)}`),0)}},JbA={command:bU,aliases:["remove"],needsProject:true,async run(A){let e=A.args[0];if(!await $A(A,`Remove ${e} from project ${A.projectId}?`))return 1;let t=await A.client.fetch(`/members/${encodeURIComponent(e)}`,{method:"DELETE",projectId:A.projectId});return A.json?(q(A.client,t),0):(A.client.output.success(`Removed ${e} from the project`),0)}},HbA={command:NU,aliases:["invites"],needsProject:true,async run(A){let[e,t]=A.args;if(e===void 0||e==="ls"||e==="list"){let n=await A.client.fetch("/members/invitations",{projectId:A.projectId});return A.json?(q(A.client,n),0):(fA(A.client,["ID","EMAIL","ROLE","INVITED","BY"],n.invitations.map(r=>{let[o="",...s]=GX(r,QA(r.invitedAt));return [NQ.default.dim(o),...s]}),"No pending invitations."),0)}if(e!=="cancel"&&e!=="rm")throw new Error(`Unknown action "${e}". Use \`flexkit members invitations\` to list or \`flexkit members invitations cancel <id|email>\`.`);if(!t)throw new Error("Pass the invitation id or the invited email: `flexkit members invitations cancel <id|email>`.");if(!await $A(A,`Cancel the invitation of ${t}?`))return 1;let i=await A.client.fetch(`/members/invitations/${encodeURIComponent(t)}`,{method:"DELETE",projectId:A.projectId});return A.json?(q(A.client,i),0):(A.client.output.success(`Canceled the invitation of ${i.email}`),0)}};async function MU(A){return KA(A,{command:RX,subcommands:[GbA,xbA,vbA,JbA,HbA],defaultSubcommand:"ls"})}var Br=nA(RA());function mi(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var Ws=mi("json",Boolean,"Print the API response as JSON on stdout"),Zs=mi("project",String,"Project to use (default: linked project)","ID","p"),SB=mi("show-secrets",Boolean,"Show header values and the secret, also in --json output (owners and developers only)"),YbA=mi("yes",Boolean,"Skip the confirmation prompt",void 0,"y"),vX=A=>[mi("url",String,A?"The http(s) address that receives the events (required)":"New receiver address","URL"),mi("name",String,A?"Webhook name (default: the URL host)":"New name","NAME"),mi("description",String,"What the webhook is for","TEXT"),mi("entity",[String],A?"Only changes to this entity, repeatable or comma separated (default: every entity)":"Only changes to these entities; replaces the current list (repeatable)","NAME"),mi("on",[String],A?"Events that trigger it: create, update, delete or all, repeatable (default: all)":"Events that trigger it; replaces the current events (repeatable)","EVENT"),mi("header",[String],A?"Header sent with every delivery, as Key=Value (repeatable)":"Add or replace a header, as Key=Value; Key= removes it (repeatable)","KEY=VALUE"),mi("method",String,"HTTP method: POST (default), PUT, PATCH, GET or DELETE","METHOD"),mi("secret",String,'A shared secret stored with the webhook ("" clears it)',"SECRET")],UU={name:"ls",description:"List the outgoing webhooks of the project, with their status, events, entities and deliveries.",arguments:[],options:[SB,Ws,Zs],examples:[{name:"List webhooks",value:"flexkit webhooks ls"},{name:"Names of the disabled webhooks",value:"flexkit webhooks ls --json | jq -r '.webhooks[] | select(.enabled | not) | .name'"}]},LU={name:"inspect",description:"Show a webhook: receiver, events, entities, headers and delivery counts. Accepts the webhook id or its exact name. Header values and the secret are hidden, also in --json output, unless you pass --show-secrets (owners and developers only).",arguments:[{name:"idOrName",required:true}],options:[SB,Ws,Zs],examples:[{name:"Show a webhook by name",value:'flexkit webhooks inspect "Orders to ERP"'},{name:"Include header values",value:"flexkit webhooks inspect 3f9c2a1e-8d4b-4c7a-9e2f-5b6a7c8d9e0f --show-secrets"},{name:"Read one field",value:"flexkit webhooks inspect erp.example.com --json | jq '.webhook.deliveries'"}]},GU={name:"create",description:"Create an outgoing webhook that calls a URL when records change. By default it fires on every event of every entity and is enabled.",arguments:[],options:[...vX(true),mi("disabled",Boolean,"Create it disabled; turn it on later with `flexkit webhooks enable`"),SB,Ws,Zs],examples:[{name:"Notify a receiver about new and changed orders",value:'flexkit webhooks create --name "Orders to ERP" --url https://erp.example.com/hooks/flexkit --entity Order --on create --on update'},{name:"Authenticate to the receiver with a header",value:'flexkit webhooks create --url https://hooks.example.com/flexkit --header "Authorization=Bearer $RECEIVER_TOKEN"'},{name:"Create it disabled and print its id",value:"flexkit webhooks create --url https://staging.example.com/hook --disabled --json | jq -r '.webhook.id'"}]},xU={name:"update",description:"Change a webhook. Fields you do not pass keep their value. --entity and --on replace the current lists; --header adds or replaces single headers.",arguments:[{name:"idOrName",required:true}],options:[...vX(false),mi("remove-header",[String],"Stop sending this header (repeatable)","KEY"),mi("all-entities",Boolean,"Fire for every entity again (clears the --entity filter)"),SB,Ws,Zs],examples:[{name:"Point a webhook at a new URL",value:'flexkit webhooks update "Orders to ERP" --url https://erp.example.com/v2/hooks/flexkit'},{name:"Rotate the receiver token",value:'flexkit webhooks update "Orders to ERP" --header "Authorization=Bearer $NEW_RECEIVER_TOKEN"'},{name:"Fire on deletes of every entity only",value:"flexkit webhooks update 3f9c2a1e-8d4b-4c7a-9e2f-5b6a7c8d9e0f --on delete --all-entities"}]},vU={name:"enable",description:"Turn one or more webhooks on.",arguments:[{name:"idOrName...",required:true}],options:[SB,Ws,Zs],examples:[{name:"Enable a webhook",value:'flexkit webhooks enable "Orders to ERP"'}]},JU={name:"disable",description:"Turn one or more webhooks off without deleting them. Changes made while off are not delivered later.",arguments:[{name:"idOrName...",required:true}],options:[SB,Ws,Zs],examples:[{name:"Pause a webhook during receiver maintenance",value:'flexkit webhooks disable "Orders to ERP"'}]},HU={name:"rm",description:"Delete one or more webhooks. Asks first; pass --yes in scripts.",arguments:[{name:"idOrName...",required:true}],options:[YbA,Ws,Zs],examples:[{name:"Delete a webhook",value:'flexkit webhooks rm "Orders to ERP"'},{name:"Delete without a prompt",value:"flexkit webhooks rm 3f9c2a1e-8d4b-4c7a-9e2f-5b6a7c8d9e0f --yes"}]},JX={name:"webhooks",description:"Manage outgoing webhooks: HTTP calls Flexkit makes to your URL when records are created, updated or deleted.",arguments:[],subcommands:[UU,LU,GU,xU,vU,JU,HU],options:[Ws,Zs],examples:[{name:"List webhooks",value:"flexkit webhooks ls"},{name:"Create a webhook for order changes",value:"flexkit webhooks create --url https://erp.example.com/hooks/flexkit --entity Order"},{name:"Pause a webhook",value:'flexkit webhooks disable "Orders to ERP"'}]};var MQ=["create","update","delete"],HX=["GET","POST","PUT","PATCH","DELETE"],KbA=/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;function YU(A){return KbA.test(A)}function KU(A){return A.flatMap(e=>e.split(",")).map(e=>e.trim()).filter(Boolean)}function KX(A){let e=new Set;for(let t of KU(A)){let i=t.toLowerCase();if(i==="all"){MQ.forEach(n=>e.add(n));continue}if(!MQ.includes(i))throw new Error(`Unknown event "${t}" for --on. Use create, update, delete or all.`);e.add(i);}return MQ.filter(t=>e.has(t))}function TX(A){let e=A.trim().toUpperCase();if(!HX.includes(e))throw new Error(`Unknown method "${A}" for --method. Use ${HX.join(", ")}.`);return e}function PX(A){let e=/^\s*([^=:\s]+)\s*[=:]\s?(.*)$/.exec(A);if(!e?.[1])throw new Error(`Invalid --header "${A}". Use Key=Value, for example --header "Authorization=Bearer abc".`);return {name:e[1],value:e[2]??""}}function TbA(A,e,t){let i=A.find(o=>o.value===null);if(i)throw new Error(`The value of header "${i.name}" is hidden from your role, so the headers can't be changed. Ask an owner or developer.`);let n=new Set([...t,...e.filter(o=>!o.value).map(o=>o.name)]),r=A.map(o=>({name:o.name,value:o.value}));for(let o of e.filter(s=>s.value)){let s=r.findIndex(g=>g.name.toLowerCase()===o.name.toLowerCase());s===-1?r.push(o):r[s]=o;}return r.filter(o=>![...n].some(s=>s.toLowerCase()===o.name.toLowerCase()))}function PbA(A){try{return new URL(A).host}catch{return A}}function OX(A){let e=A.url?.trim();if(!e)throw new Error("Pass --url with the address that receives the events.");let t=(A.headers??[]).map(PX).filter(r=>r.value),i=A.on&&A.on.length>0?KX(A.on):[...MQ],n={name:A.name?.trim()||PbA(e),url:e,enabled:!A.disabled,events:i,entities:KU(A.entities??[]),headers:t};return A.method&&(n.method=TX(A.method)),A.description!==void 0&&(n.description=A.description),A.secret!==void 0&&(n.secret=A.secret),n}function qX(A,e){let t={};if(A.name!==void 0&&(t.name=A.name),A.description!==void 0&&(t.description=A.description),A.url!==void 0&&(t.url=A.url.trim()),A.method!==void 0&&(t.method=TX(A.method)),A.secret!==void 0&&(t.secret=A.secret),A.allEntities&&A.entities&&A.entities.length>0)throw new Error("Pass either --entity or --all-entities, not both.");return A.allEntities?t.entities=[]:A.entities&&A.entities.length>0&&(t.entities=KU(A.entities)),A.on&&A.on.length>0&&(t.events=KX(A.on)),((A.headers?.length??0)>0||(A.removeHeaders?.length??0)>0)&&(t.headers=TbA(e.headers,(A.headers??[]).map(PX),A.removeHeaders??[])),t}function TU(A){return A.length===MQ.length?"all":A.join(",")}function uD(A){return A.length===0?"all":A.join(", ")}function jX(A){return A.total===0?"0":A.failed>0?`${String(A.total)} (${String(A.failed)} failed)`:String(A.total)}function _X(A,e){if(YU(e))return A.filter(i=>i.id.toLowerCase()===e.toLowerCase());let t=e.trim().toLowerCase();return A.filter(i=>i.name.toLowerCase()===t)}var YX="[redacted]";function kB(A,e){return e?A:{...A,headers:A.headers.map(t=>({...t,value:t.value===null?null:YX})),secret:A.secret===null?null:YX}}var VX={"--show-secrets":Boolean,"--url":String,"--name":String,"--description":String,"--entity":[String],"--on":[String],"--header":[String],"--method":String,"--secret":String};function WX(A){return {url:A["--url"],name:A["--name"],description:A["--description"],entities:A["--entity"],on:A["--on"],headers:A["--header"],removeHeaders:A["--remove-header"],allEntities:!!A["--all-entities"],method:A["--method"],secret:A["--secret"],disabled:!!A["--disabled"]}}function PU(A){return A.client.fetch("/webhooks",{projectId:A.projectId})}async function OU(A,e,t){if(YU(e)){let n=t?.find(o=>o.id===e);if(n)return n;let{webhook:r}=await A.client.fetch(`/webhooks/${encodeURIComponent(e)}`,{projectId:A.projectId});return r}let i=_X(t??(await PU(A)).webhooks,e);if(i.length===0)throw new Error(`No webhook named "${e}". Run \`flexkit webhooks ls\` to see the webhooks.`);if(i.length>1)throw new Error(`Several webhooks are named "${e}": ${i.map(n=>n.id).join(", ")}. Pass the id instead.`);return i[0]}async function ZX(A){let e=(await PU(A)).webhooks,t=[];for(let i of A.args){let n=await OU(A,i,e);t.some(r=>r.id===n.id)||t.push(n);}return t}function qU(A){if(!A.success||!A.webhook){let e=Array.isArray(A.errorMessage)?A.errorMessage.join(`
|
|
550
550
|
`):A.errorMessage;throw new Error(e||"The webhook could not be saved.")}return A.webhook}function XX(A,e,t){return A.client.fetch(`/webhooks/${encodeURIComponent(e)}`,{method:"PATCH",body:{...t},projectId:A.projectId})}function ED(A,e,t){A.client.output.success(`${e} webhook ${Br.default.bold(t.name)} ${Br.default.dim(`(${t.id})`)}`);}function UQ(A){return !!A.flags["--show-secrets"]}function zX(A){return Ce(A.enabled?"enabled":"disabled")}var ObA={command:UU,aliases:["list"],needsProject:true,flags:{"--show-secrets":Boolean},async run(A){let e=await PU(A);return A.json?(q(A.client,{...e,webhooks:e.webhooks.map(t=>kB(t,UQ(A)))}),0):(fA(A.client,["ID","NAME","STATUS","REQUEST","EVENTS","ENTITIES","DELIVERIES","LAST CALL"],e.webhooks.map(t=>[Br.default.dim(t.id),t.name,zX(t),`${t.method} ${TA(t.url,45)}`,TU(t.events),TA(uD(t.entities),30),jX(t.deliveries),QA(t.lastTriggeredAt)||Br.default.dim("never")]),"No webhooks yet. Create one with `flexkit webhooks create --url <url>`."),e.limit!==null&&e.webhooks.length>0&&A.client.output.log(Br.default.dim(`${String(e.webhooks.length)} of ${String(e.limit)} webhooks allowed on your plan.`)),0)}},qbA={command:LU,aliases:["get"],needsProject:true,flags:{"--show-secrets":Boolean},async run(A){let e=await OU(A,A.args[0]);if(A.json)return q(A.client,{webhook:kB(e,UQ(A))}),0;let t=!!A.flags["--show-secrets"],i=e.headers.some(o=>o.value===null)||e.hasSecret&&!e.secret,n=o=>o===null?Br.default.dim("(hidden for your role)"):t?o:Br.default.dim("\u2022\u2022\u2022\u2022\u2022\u2022"),r;return e.hasSecret&&(r=n(e.secret)),ie(A.client,[["ID",e.id],["Name",e.name],["Description",e.description],["Status",zX(e)],["Request",`${e.method} ${e.url}`],["Events",e.events.join(", ")],["Entities",uD(e.entities)],...e.headers.map(o=>[`Header ${o.name}`,n(o.value)]),["Secret",r],["Deliveries",`${String(e.deliveries.total)} total, ${String(e.deliveries.successful)} succeeded, ${String(e.deliveries.failed)} failed`],["Last call",e.lastTriggeredAt?`${QA(e.lastTriggeredAt)} (${e.lastTriggeredAt})`:Br.default.dim("never")],["Created",e.createdAt?`${QA(e.createdAt)} (${e.createdAt})`:void 0],["Created by",e.createdByName],["Updated",e.updatedAt?`${QA(e.updatedAt)} (${e.updatedAt})`:void 0]]),!t&&!i&&(e.headers.length>0||e.hasSecret)&&A.client.output.log(Br.default.dim("Pass --show-secrets to print header values and the secret.")),0}},jbA={command:GU,aliases:["add"],needsProject:true,flags:{...VX,"--disabled":Boolean},async run(A){let e=OX(WX(A.flags)),t=qU(await A.client.fetch("/webhooks",{method:"POST",body:{...e},projectId:A.projectId}));return A.json?(q(A.client,{webhook:kB(t,UQ(A))}),0):(ED(A,"Created",t),A.client.output.log(Br.default.dim(`${t.method} ${t.url} on ${TU(t.events)} events of ${uD(t.entities)} entities${t.enabled?"":" (disabled)"}.`)),0)}},_bA={command:xU,aliases:["edit"],needsProject:true,flags:{...VX,"--remove-header":[String],"--all-entities":Boolean},async run(A){let e=await OU(A,A.args[0]),t=qX(WX(A.flags),e);if(Object.keys(t).length===0)throw new Error("Nothing to change. Pass at least one option, such as --url or --on. See --help.");let i=qU(await XX(A,e.id,t));return A.json?(q(A.client,{webhook:kB(i,UQ(A))}),0):(ED(A,"Updated",i),0)}};function $X(A){return async e=>{let t=await ZX(e),i=[];for(let n of t){if(n.enabled===A){i.push(n),e.json||e.client.output.log(`${n.name} is already ${A?"enabled":"disabled"}.`);continue}let r=qU(await XX(e,n.id,{enabled:A}));i.push(r),e.json||ED(e,A?"Enabled":"Disabled",r);}return e.json&&q(e.client,{webhooks:i.map(n=>kB(n,UQ(e)))}),0}}var VbA={command:vU,needsProject:true,flags:{"--show-secrets":Boolean},run:$X(true)},WbA={command:JU,needsProject:true,flags:{"--show-secrets":Boolean},run:$X(false)},ZbA={command:HU,aliases:["remove","delete"],needsProject:true,async run(A){let e=await ZX(A),t=e.length===1?`the webhook "${e[0].name}"`:`${String(e.length)} webhooks (${e.map(i=>i.name).join(", ")})`;if(!await $A(A,`Delete ${t}?`))return 1;for(let i of e)await A.client.fetch(`/webhooks/${encodeURIComponent(i.id)}`,{method:"DELETE",projectId:A.projectId}),A.json||ED(A,"Deleted",i);return A.json&&q(A.client,{deleted:e.map(i=>i.id)}),0}};async function jU(A){return KA(A,{command:JX,subcommands:[ObA,qbA,jbA,_bA,VbA,WbA,ZbA],defaultSubcommand:"ls"})}var fa=nA(RA());function QD(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var cD=QD("json",Boolean,"Print the API response as JSON on stdout"),lD=QD("project",String,"Project to use (default: linked project)","ID","p"),XbA=QD("yes",Boolean,"Skip the confirmation prompt",void 0,"y"),_U={name:"ls",description:"List the browser origins allowed to call the project API.",arguments:[],options:[cD,lD],examples:[{name:"List origins",value:"flexkit cors ls"},{name:"Origins only, one per line",value:"flexkit cors ls --json | jq -r '.origins[].origin'"}]},VU={name:"add",description:"Allow one or more browser origins (scheme, host and port, e.g. https://app.example.com). `*` may stand for one hostname label or the port. Origins already in the list are skipped, so the command is safe to rerun.",arguments:[{name:"origin...",required:true}],options:[QD("credentials",Boolean,"Mark the origins as sending credentials (cookies). Any such origin makes the API allow credentials for every listed origin. Needs a signed-in user: API tokens can add origins only without it"),cD,lD],examples:[{name:"Allow local development",value:"flexkit cors add http://localhost:3000"},{name:"Allow production and every preview subdomain",value:"flexkit cors add https://studio.example.com 'https://*.preview.example.com'"}]},WU={name:"rm",description:"Remove origins by origin or by id. Browsers may keep using a cached preflight for up to two hours.",arguments:[{name:"origin|id...",required:true}],options:[XbA,cD,lD],examples:[{name:"Remove an origin",value:"flexkit cors rm http://localhost:3000"},{name:"Remove by id without a prompt",value:"flexkit cors rm 42 43 --yes"}]},Az={name:"cors",description:"Manage the CORS allowlist: the browser origins that may call the project API (for example a hosted Studio).",arguments:[],subcommands:[_U,VU,WU],options:[cD,lD],examples:[{name:"List origins",value:"flexkit cors ls"},{name:"Allow an origin",value:"flexkit cors add https://studio.example.com"},{name:"Remove an origin",value:"flexkit cors rm https://old.example.com --yes"}]};function hD(A){return A.trim().replace(/\/+$/,"")}function ZU(A){return /^(\*|https?):\/\/[a-z0-9*.-]+(:(\d{1,5}|\*))?(\/.*)?$/i.test(A)?null:`"${A}" is not an origin. Include the scheme, for example https://app.example.com or http://localhost:3000.`}function ez(A,e){let t=[],i=[],n=[];for(let r of e){let o=hD(r);if(ZU(o)){n.push(r);continue}let s=A.find(g=>g.origin.toLowerCase()===o.toLowerCase());s?i.includes(s)||i.push(s):t.some(g=>g.toLowerCase()===o.toLowerCase())||t.push(o);}return {add:t,skipped:i,invalid:n}}function tz(A,e){let t=[],i=[];for(let n of e){let r=hD(n).toLowerCase(),o=/^\d+$/.test(n.trim())?A.find(s=>s.id===Number(n.trim())):A.find(s=>s.origin.toLowerCase()===r);o?t.includes(o)||t.push(o):i.push(n);}return {targets:t,unknown:i}}async function XU(A){let{origins:e}=await A.client.fetch("/cors",{projectId:A.projectId});return e}var zbA={command:_U,aliases:["list"],needsProject:true,async run(A){let e=await XU(A);return A.json?(q(A.client,{origins:e}),0):(fA(A.client,["ID","ORIGIN","CREDENTIALS","ADDED"],e.map(t=>[fa.default.dim(String(t.id)),t.origin,t.allowCredentials?"allowed":fa.default.dim("no"),QA(t.createdAt)]),"No origins yet: browsers cannot call the project API. Allow one with `flexkit cors add <origin>`."),0)}},$bA={command:VU,aliases:["allow"],needsProject:true,flags:{"--credentials":Boolean},async run(A){let e=ez(await XU(A),A.args);if(e.invalid.length>0)throw new Error(e.invalid.map(i=>ZU(hD(i))).join(`
|
|
551
|
-
`));let t=[];for(let i of e.add){let n=await A.client.fetch("/cors",{method:"POST",body:{origin:i,allowCredentials:!!A.flags["--credentials"]},projectId:A.projectId});t.push(n.origin),A.json||A.client.output.success(`Allowed ${fa.default.bold(n.origin.origin)} ${fa.default.dim(`(${String(n.origin.id)})`)}`);}if(A.json)return q(A.client,{added:t,skipped:e.skipped}),0;for(let i of e.skipped)A.client.output.log(`${i.origin} is already allowed.`);return A.flags["--credentials"]&&e.skipped.some(i=>!i.allowCredentials)&&A.client.output.log(fa.default.dim("Already listed origins keep their credentials setting; remove and add them again to change it.")),0}},ANA={command:WU,aliases:["remove"],needsProject:true,async run(A){let{targets:e,unknown:t}=tz(await XU(A),A.args);if(t.length>0)throw new Error(`Not in the allowlist: ${t.join(", ")}. Run \`flexkit cors ls\` to see the origins and their ids.`);let i=e.map(n=>n.origin).join(", ");if(!await $A(A,`Remove ${i} from the CORS allowlist?`))return 1;for(let n of e)await A.client.fetch(`/cors/${String(n.id)}`,{method:"DELETE",projectId:A.projectId}),A.json||A.client.output.success(`Removed ${fa.default.bold(n.origin)}`);return A.json&&q(A.client,{removed:e}),0}};async function zU(A){return KA(A,{command:Az,subcommands:[zbA,$bA,ANA],defaultSubcommand:"ls"})}var RB=nA(RA());function on(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var dD=[on("since",String,"Start of the time range: a duration back from now (30m, 1h, 2d, 1w) or an ISO date-time (default: 1h)","TIME","s"),on("until",String,"End of the time range, same formats as --since (default: now)","TIME"),on("before",String,"Only entries older than this time, for paging (the hint after a full page prints it)","TIME"),on("limit",Number,"Entries to fetch, 1\u2013500 (default: 50)","N","n"),on("follow",Boolean,"Keep running and print new entries as they arrive (Ctrl+C to stop)",void 0,"f"),on("interval",Number,"How often --follow polls, in seconds (default: 5, minimum: 2)","SECONDS"),on("utc",Boolean,"Print times in UTC instead of local time"),on("json",Boolean,"Print the entries as a JSON array, newest first (with --follow: one entry per line, oldest first)"),on("project",String,"Project to use (default: linked project)","ID","p")],$U={name:"api",description:"Show GraphQL API requests made to the project: operation, status code, duration, size and location. Newest entries are printed last.",arguments:[],options:[on("operation",String,"Only requests with this exact GraphQL operation name","NAME"),on("status",String,"Only requests that returned this HTTP status code, such as 500","CODE"),...dD],examples:[{name:"API requests from the last hour",value:"flexkit logs"},{name:"Server errors over the last two days",value:"flexkit logs api --since 2d --status 500"},{name:"Watch one operation live",value:"flexkit logs api --operation GetProducts --follow"},{name:"Slowest requests of a day, with jq",value:"flexkit logs api --since 2026-11-02 --until 2026-11-03 --limit 500 --json | jq 'sort_by(-.duration_ms) | .[:10]'"}]},AL={name:"webhooks",description:"Show webhook deliveries: the event, the HTTP status your endpoint answered, duration, URL and the error of failed deliveries.",arguments:[],options:[on("event",String,"Only deliveries for this event: create, update or delete","EVENT"),on("status",String,"Only succeeded or failed deliveries","succeeded|failed"),...dD],examples:[{name:"Failed deliveries today",value:"flexkit logs webhooks --since 1d --status failed"},{name:"Watch deliveries while you test an endpoint",value:"flexkit logs webhooks -f"},{name:"Count failures by URL",value:"flexkit logs webhooks --since 1w --status failed --limit 500 --json | jq 'group_by(.url) | map({url: .[0].url, failures: length})'"}]},eL={name:"llm",description:"Show AI model calls made by the chat agent and automations: model, input and output tokens, cost, duration and the automation that made the call.",arguments:[],options:dD,examples:[{name:"Model calls from the last hour",value:"flexkit logs llm"},{name:"Total cost of the last 7 days (up to 500 calls)",value:"flexkit logs llm --since 7d --limit 500 --json | jq '[.[].actual_cost_micros] | add / 1000000'"},{name:"Watch an automation run spend tokens",value:"flexkit logs llm --follow --interval 2"}]},iz={name:"logs",description:"Read project logs: GraphQL API requests (api, the default), webhook deliveries (webhooks) and AI model calls (llm). Any project member or project API token can read them.",arguments:[],subcommands:[$U,AL,eL],options:dD,examples:[{name:"API requests from the last hour",value:"flexkit logs"},{name:"Failed webhook deliveries over 2 days",value:"flexkit logs webhooks --since 2d --status failed"},{name:"Follow AI model calls live",value:"flexkit logs llm --follow"},{name:"Stream API requests as JSON lines",value:"flexkit logs api -f --json | jq -c .operation_name"}]};var eNA={s:1e3,m:6e4,h:36e5,d:864e5,w:6048e5},tNA=/^(\d+(?:\.\d+)?)\s*(s|m|h|d|w)$/i;function LQ(A,e,t=Date.now(),i=false){let n=A.trim();if(n.toLowerCase()==="now")return new Date(t);let r=tNA.exec(n);if(r){let o=Number(r[1]),s=eNA[r[2].toLowerCase()];return new Date(t-o*s)}if(/^\d{4}-\d{2}-\d{2}/.test(n)){let s=n.includes("T")||n.includes(" ")?n.replace(" ","T"):`${n}T00:00:00`,g=/[zZ]$|[+-]\d{2}:?\d{2}$/.test(s),B=new Date(!g&&i?`${s}Z`:s);if(!Number.isNaN(B.getTime()))return B}throw new Error(`${e} must be a duration such as 30m, 1h or 2d, or an ISO date-time such as 2026-11-03T10:00:00Z (got "${A}").`)}function tL(A){let e=new URLSearchParams({type:A.type});if(A.since&&e.set("since",A.since.toISOString()),A.until&&e.set("until",A.until.toISOString()),A.before&&e.set("before",A.before.toISOString()),A.limit!==void 0){if(!Number.isInteger(A.limit)||A.limit<1||A.limit>500)throw new Error(`--limit must be a whole number from 1 to ${String(500)}.`);e.set("limit",String(A.limit));}if(A.operation){if(A.type!=="api")throw new Error("--operation only applies to API request logs.");e.set("operation",A.operation);}if(A.event){let t=A.event.toLowerCase();if(A.type!=="webhooks")throw new Error("--event only applies to webhook logs.");if(!["create","update","delete"].includes(t))throw new Error("--event must be create, update or delete.");e.set("event",t);}if(A.status){let t=A.status.toLowerCase();if(A.type==="llm")throw new Error("--status does not apply to LLM logs.");if(A.type==="api"&&!/^[1-5]\d\d$/.test(t))throw new Error("--status must be an HTTP status code, such as 500, for API request logs.");if(A.type==="webhooks"){let i=t==="success"||t==="ok"?"succeeded":t==="failure"?"failed":t;if(i!=="succeeded"&&i!=="failed")throw new Error("--status must be succeeded or failed for webhook logs.");return e.set("status",i),e.toString()}e.set("status",t);}return e.toString()}function iNA(A){return JSON.stringify(Object.entries(A).sort(([e],[t])=>e.localeCompare(t)))}function iL(A,e){let t=[];for(let i of A){let n=iNA(i);e.has(n)||(e.set(n,Date.parse(i.timestamp)),t.push(i));}return t.sort((i,n)=>Date.parse(i.timestamp)-Date.parse(n.timestamp))}function nz(A,e){for(let[t,i]of A)i<e&&A.delete(t);}function nNA(A,e=false){let t=new Date(A);if(Number.isNaN(t.getTime()))return A;let i=E=>String(E).padStart(2,"0"),n=e?[t.getUTCFullYear(),t.getUTCMonth()+1,t.getUTCDate(),t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds()]:[t.getFullYear(),t.getMonth()+1,t.getDate(),t.getHours(),t.getMinutes(),t.getSeconds()],[r,o,s,g,B,I]=n;return `${String(r)}-${i(o)}-${i(s)} ${i(g)}:${i(B)}:${i(I)}`}function rNA(A){return A<1024?`${String(A)} B`:A<1024*1024?`${(A/1024).toFixed(1)} KB`:`${(A/(1024*1024)).toFixed(1)} MB`}function oNA(A){let e=A/1e6;return e===0?"$0":e<.01?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}var rz={api:["TIME","OPERATION","STATUS","DURATION","SIZE","LOCATION"],webhooks:["TIME","EVENT","STATUS","METHOD","DURATION","URL","ERROR"],llm:["TIME","MODEL","TOKENS IN/OUT","COST","DURATION","AUTOMATION"]};function sNA(A){if(!A.includes("%")&&!A.includes("+"))return A;try{return decodeURIComponent(A.replaceAll("+"," "))}catch{return A}}function nL(A,e=false){let t=nNA(A.timestamp,e);if(A.type==="webhook-executions"){let n=A.was_successful?"":[A.error_type,A.error_message].filter(Boolean).join(": ")||"failed";return [t,`${A.event_type} ${A.entity_name}`,String(A.status_code),A.http_method,`${String(A.duration_ms)}ms`,A.url,n]}if(A.type==="llm-requests")return [t,A.gateway_model_id,`${A.input_tokens.toLocaleString("en-US")} / ${A.output_tokens.toLocaleString("en-US")}`,oNA(A.actual_cost_micros),`${String(A.duration_ms)}ms`,A.automation_id];let i=[sNA(A.city),A.country].filter(n=>n&&n!=="Unknown").join(", ");return [t,A.operation_name,String(A.status_code),`${String(A.duration_ms)}ms`,rNA(A.request_size_bytes+A.response_size_bytes),i]}function oz(A){return A.type==="webhook-executions"?!A.was_successful:A.type==="api-requests"?A.status_code>=400||A.status_code===0:false}var gNA=50,aNA="1h",sz=3e4,INA={"--since":String,"-s":"--since","--until":String,"--before":String,"--limit":Number,"-n":"--limit","--follow":Boolean,"-f":"--follow","--interval":Number,"--utc":Boolean};function gz(A,e){let t=A.type==="llm-requests"?-1:2;return e.map((i,n)=>n===0?RB.default.dim(i):n===t?oz(A)?RB.default.red(i):RB.default.green(i):A.type==="webhook-executions"&&n===6&&i?RB.default.red(i):i)}function CNA(A,e){let{flags:t}=A,i=Date.now(),n=!!t["--follow"],r=t["--until"],o=t["--before"];if(n&&(r||o))throw new Error("--follow cannot be combined with --until or --before.");let s=!!t["--utc"],g=r?LQ(r,"--until",i,s):void 0,B=o?LQ(o,"--before",i,s):void 0,I=t["--since"],E=Math.min(g?.getTime()??i,B?.getTime()??i),u=I?LQ(I,"--since",i,s):LQ(aNA,"--since",E),a={type:e,since:u,until:g,before:B,limit:t["--limit"]??gNA,operation:t["--operation"],status:t["--status"],event:t["--event"]};return tL(a),{options:a,following:n}}async function az(A,e,t){return A.client.fetch(`/logs?${tL(e)}`,{projectId:A.projectId,signal:t})}function BNA(A,e){return new Promise(t=>{let i=()=>{clearTimeout(n),e.removeEventListener("abort",i),t();},n=setTimeout(i,A);e.addEventListener("abort",i);})}function Iz(A,e,t){if(A.json){for(let i of e)A.client.stdout.write(`${JSON.stringify(i)}
|
|
551
|
+
`));let t=[];for(let i of e.add){let n=await A.client.fetch("/cors",{method:"POST",body:{origin:i,allowCredentials:!!A.flags["--credentials"]},projectId:A.projectId});t.push(n.origin),A.json||A.client.output.success(`Allowed ${fa.default.bold(n.origin.origin)} ${fa.default.dim(`(${String(n.origin.id)})`)}`);}if(A.json)return q(A.client,{added:t,skipped:e.skipped}),0;for(let i of e.skipped)A.client.output.log(`${i.origin} is already allowed.`);return A.flags["--credentials"]&&e.skipped.some(i=>!i.allowCredentials)&&A.client.output.log(fa.default.dim("Already listed origins keep their credentials setting; remove and add them again to change it.")),0}},ANA={command:WU,aliases:["remove"],needsProject:true,async run(A){let{targets:e,unknown:t}=tz(await XU(A),A.args);if(t.length>0)throw new Error(`Not in the allowlist: ${t.join(", ")}. Run \`flexkit cors ls\` to see the origins and their ids.`);let i=e.map(n=>n.origin).join(", ");if(!await $A(A,`Remove ${i} from the CORS allowlist?`))return 1;for(let n of e)await A.client.fetch(`/cors/${String(n.id)}`,{method:"DELETE",projectId:A.projectId}),A.json||A.client.output.success(`Removed ${fa.default.bold(n.origin)}`);return A.json&&q(A.client,{removed:e}),0}};async function zU(A){return KA(A,{command:Az,subcommands:[zbA,$bA,ANA],defaultSubcommand:"ls"})}var RB=nA(RA());function on(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var dD=[on("since",String,"Start of the time range: a duration back from now (30m, 1h, 2d, 1w) or an ISO date-time (default: 1h)","TIME","s"),on("until",String,"End of the time range, same formats as --since (default: now)","TIME"),on("before",String,"Only entries older than this time, for paging (the hint after a full page prints it)","TIME"),on("limit",Number,"Entries to fetch, 1\u2013500 (default: 50)","N","n"),on("follow",Boolean,"Keep running and print new entries as they arrive (Ctrl+C to stop)",void 0,"f"),on("interval",Number,"How often --follow polls, in seconds (default: 5, minimum: 2)","SECONDS"),on("utc",Boolean,"Print times in UTC instead of local time"),on("json",Boolean,"Print JSON: the page with its entries (newest first) and nextBefore, the --before value for the next page; with --follow, one entry per line, oldest first"),on("project",String,"Project to use (default: linked project)","ID","p")],$U={name:"api",description:"Show GraphQL API requests made to the project: operation, status code, duration, size and location. Newest entries are printed last.",arguments:[],options:[on("operation",String,"Only requests with this exact GraphQL operation name","NAME"),on("status",String,"Only requests that returned this HTTP status code, such as 500","CODE"),...dD],examples:[{name:"API requests from the last hour",value:"flexkit logs"},{name:"Server errors over the last two days",value:"flexkit logs api --since 2d --status 500"},{name:"Watch one operation live",value:"flexkit logs api --operation GetProducts --follow"},{name:"Slowest requests of a day, with jq",value:"flexkit logs api --since 2026-11-02 --until 2026-11-03 --limit 500 --json | jq '.data | sort_by(-.duration_ms) | .[:10]'"},{name:"The --before value for the next page, in a script",value:"flexkit logs api --since 1d --limit 500 --json | jq -r '.nextBefore // empty'"}]},AL={name:"webhooks",description:"Show webhook deliveries: the event, the HTTP status your endpoint answered, duration, URL and the error of failed deliveries.",arguments:[],options:[on("event",String,"Only deliveries for this event: create, update or delete","EVENT"),on("status",String,"Only succeeded or failed deliveries","succeeded|failed"),...dD],examples:[{name:"Failed deliveries today",value:"flexkit logs webhooks --since 1d --status failed"},{name:"Watch deliveries while you test an endpoint",value:"flexkit logs webhooks -f"},{name:"Count failures by URL",value:"flexkit logs webhooks --since 1w --status failed --limit 500 --json | jq '.data | group_by(.url) | map({url: .[0].url, failures: length})'"}]},eL={name:"llm",description:"Show AI model calls made by the chat agent and automations: model, input and output tokens, cost, duration and the automation that made the call.",arguments:[],options:dD,examples:[{name:"Model calls from the last hour",value:"flexkit logs llm"},{name:"Total cost of the last 7 days (up to 500 calls)",value:"flexkit logs llm --since 7d --limit 500 --json | jq '[.data[].actual_cost_micros] | add / 1000000'"},{name:"Watch an automation run spend tokens",value:"flexkit logs llm --follow --interval 2"}]},iz={name:"logs",description:"Read project logs: GraphQL API requests (api, the default), webhook deliveries (webhooks) and AI model calls (llm). Any project member or project API token can read them.",arguments:[],subcommands:[$U,AL,eL],options:dD,examples:[{name:"API requests from the last hour",value:"flexkit logs"},{name:"Failed webhook deliveries over 2 days",value:"flexkit logs webhooks --since 2d --status failed"},{name:"Follow AI model calls live",value:"flexkit logs llm --follow"},{name:"Stream API requests as JSON lines",value:"flexkit logs api -f --json | jq -c .operation_name"}]};var eNA={s:1e3,m:6e4,h:36e5,d:864e5,w:6048e5},tNA=/^(\d+(?:\.\d+)?)\s*(s|m|h|d|w)$/i;function LQ(A,e,t=Date.now(),i=false){let n=A.trim();if(n.toLowerCase()==="now")return new Date(t);let r=tNA.exec(n);if(r){let o=Number(r[1]),s=eNA[r[2].toLowerCase()];return new Date(t-o*s)}if(/^\d{4}-\d{2}-\d{2}/.test(n)){let s=n.includes("T")||n.includes(" ")?n.replace(" ","T"):`${n}T00:00:00`,g=/[zZ]$|[+-]\d{2}:?\d{2}$/.test(s),B=new Date(!g&&i?`${s}Z`:s);if(!Number.isNaN(B.getTime()))return B}throw new Error(`${e} must be a duration such as 30m, 1h or 2d, or an ISO date-time such as 2026-11-03T10:00:00Z (got "${A}").`)}function tL(A){let e=new URLSearchParams({type:A.type});if(A.since&&e.set("since",A.since.toISOString()),A.until&&e.set("until",A.until.toISOString()),A.before&&e.set("before",A.before.toISOString()),A.limit!==void 0){if(!Number.isInteger(A.limit)||A.limit<1||A.limit>500)throw new Error(`--limit must be a whole number from 1 to ${String(500)}.`);e.set("limit",String(A.limit));}if(A.operation){if(A.type!=="api")throw new Error("--operation only applies to API request logs.");e.set("operation",A.operation);}if(A.event){let t=A.event.toLowerCase();if(A.type!=="webhooks")throw new Error("--event only applies to webhook logs.");if(!["create","update","delete"].includes(t))throw new Error("--event must be create, update or delete.");e.set("event",t);}if(A.status){let t=A.status.toLowerCase();if(A.type==="llm")throw new Error("--status does not apply to LLM logs.");if(A.type==="api"&&!/^[1-5]\d\d$/.test(t))throw new Error("--status must be an HTTP status code, such as 500, for API request logs.");if(A.type==="webhooks"){let i=t==="success"||t==="ok"?"succeeded":t==="failure"?"failed":t;if(i!=="succeeded"&&i!=="failed")throw new Error("--status must be succeeded or failed for webhook logs.");return e.set("status",i),e.toString()}e.set("status",t);}return e.toString()}function iNA(A){return JSON.stringify(Object.entries(A).sort(([e],[t])=>e.localeCompare(t)))}function iL(A,e){let t=[];for(let i of A){let n=iNA(i);e.has(n)||(e.set(n,Date.parse(i.timestamp)),t.push(i));}return t.sort((i,n)=>Date.parse(i.timestamp)-Date.parse(n.timestamp))}function nz(A,e){for(let[t,i]of A)i<e&&A.delete(t);}function nNA(A,e=false){let t=new Date(A);if(Number.isNaN(t.getTime()))return A;let i=E=>String(E).padStart(2,"0"),n=e?[t.getUTCFullYear(),t.getUTCMonth()+1,t.getUTCDate(),t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds()]:[t.getFullYear(),t.getMonth()+1,t.getDate(),t.getHours(),t.getMinutes(),t.getSeconds()],[r,o,s,g,B,I]=n;return `${String(r)}-${i(o)}-${i(s)} ${i(g)}:${i(B)}:${i(I)}`}function rNA(A){return A<1024?`${String(A)} B`:A<1024*1024?`${(A/1024).toFixed(1)} KB`:`${(A/(1024*1024)).toFixed(1)} MB`}function oNA(A){let e=A/1e6;return e===0?"$0":e<.01?`$${e.toFixed(4)}`:`$${e.toFixed(2)}`}var rz={api:["TIME","OPERATION","STATUS","DURATION","SIZE","LOCATION"],webhooks:["TIME","EVENT","STATUS","METHOD","DURATION","URL","ERROR"],llm:["TIME","MODEL","TOKENS IN/OUT","COST","DURATION","AUTOMATION"]};function sNA(A){if(!A.includes("%")&&!A.includes("+"))return A;try{return decodeURIComponent(A.replaceAll("+"," "))}catch{return A}}function nL(A,e=false){let t=nNA(A.timestamp,e);if(A.type==="webhook-executions"){let n=A.was_successful?"":[A.error_type,A.error_message].filter(Boolean).join(": ")||"failed";return [t,`${A.event_type} ${A.entity_name}`,String(A.status_code),A.http_method,`${String(A.duration_ms)}ms`,A.url,n]}if(A.type==="llm-requests")return [t,A.gateway_model_id,`${A.input_tokens.toLocaleString("en-US")} / ${A.output_tokens.toLocaleString("en-US")}`,oNA(A.actual_cost_micros),`${String(A.duration_ms)}ms`,A.automation_id];let i=[sNA(A.city),A.country].filter(n=>n&&n!=="Unknown").join(", ");return [t,A.operation_name,String(A.status_code),`${String(A.duration_ms)}ms`,rNA(A.request_size_bytes+A.response_size_bytes),i]}function oz(A){return A.type==="webhook-executions"?!A.was_successful:A.type==="api-requests"?A.status_code>=400||A.status_code===0:false}var gNA=50,aNA="1h",sz=3e4,INA={"--since":String,"-s":"--since","--until":String,"--before":String,"--limit":Number,"-n":"--limit","--follow":Boolean,"-f":"--follow","--interval":Number,"--utc":Boolean};function gz(A,e){let t=A.type==="llm-requests"?-1:2;return e.map((i,n)=>n===0?RB.default.dim(i):n===t?oz(A)?RB.default.red(i):RB.default.green(i):A.type==="webhook-executions"&&n===6&&i?RB.default.red(i):i)}function CNA(A,e){let{flags:t}=A,i=Date.now(),n=!!t["--follow"],r=t["--until"],o=t["--before"];if(n&&(r||o))throw new Error("--follow cannot be combined with --until or --before.");let s=!!t["--utc"],g=r?LQ(r,"--until",i,s):void 0,B=o?LQ(o,"--before",i,s):void 0,I=t["--since"],E=Math.min(g?.getTime()??i,B?.getTime()??i),u=I?LQ(I,"--since",i,s):LQ(aNA,"--since",E),a={type:e,since:u,until:g,before:B,limit:t["--limit"]??gNA,operation:t["--operation"],status:t["--status"],event:t["--event"]};return tL(a),{options:a,following:n}}async function az(A,e,t){return A.client.fetch(`/logs?${tL(e)}`,{projectId:A.projectId,signal:t})}function BNA(A,e){return new Promise(t=>{let i=()=>{clearTimeout(n),e.removeEventListener("abort",i),t();},n=setTimeout(i,A);e.addEventListener("abort",i);})}function Iz(A,e,t){if(A.json){for(let i of e)A.client.stdout.write(`${JSON.stringify(i)}
|
|
552
552
|
`);return}for(let i of e)A.client.output.print(`${gz(i,nL(i,t)).join(" ")}
|
|
553
553
|
`);}async function uNA(A,e,t,i,n){let{client:r}=A,o=A.flags["--interval"]??5;if(!Number.isFinite(o))return r.output.error("--interval must be a number of seconds."),1;let s=Math.max(2,o),g=Date.parse(n),B=new AbortController,I=()=>{B.abort();};process.on("SIGINT",I),A.json||r.output.print(`${RB.default.dim(`Watching for new entries every ${s}s. Press Ctrl+C to stop.`)}
|
|
554
|
-
`);try{for(;!B.signal.aborted&&(await BNA(s*1e3,B.signal),!B.signal.aborted);){let E;try{E=await az(A,{...e,since:new Date(g-sz),until:void 0,before:void 0,limit:500},B.signal);}catch(u){if(B.signal.aborted)break;if(zA(u)&&u.status>=400&&u.status<500)throw u;r.output.debug(u);continue}g=Math.max(g,Date.parse(E.until)),Iz(A,iL(E.data,t),i),nz(t,g-sz-1e3);}}finally{process.off("SIGINT",I);}return 0}var ENA={api:"No API requests in this time range.",webhooks:"No webhook deliveries in this time range.",llm:"No AI model calls in this time range."};function rL(A,e,t,i={}){return {command:e,aliases:t,needsProject:true,flags:{...INA,...i},run:async n=>{let{client:r}=n,o;try{o=CNA(n,A);}catch(u){return r.output.error(u instanceof Error?u.message:String(u)),1}let{options:s,following:g}=o,B=!!n.flags["--utc"];r.output.spinner("Loading logs\u2026");let I=await az(n,s);r.output.stopSpinner();let E=[...I.data].reverse();if(n.json&&!g?q(r,I
|
|
554
|
+
`);try{for(;!B.signal.aborted&&(await BNA(s*1e3,B.signal),!B.signal.aborted);){let E;try{E=await az(A,{...e,since:new Date(g-sz),until:void 0,before:void 0,limit:500},B.signal);}catch(u){if(B.signal.aborted)break;if(zA(u)&&u.status>=400&&u.status<500)throw u;r.output.debug(u);continue}g=Math.max(g,Date.parse(E.until)),Iz(A,iL(E.data,t),i),nz(t,g-sz-1e3);}}finally{process.off("SIGINT",I);}return 0}var ENA={api:"No API requests in this time range.",webhooks:"No webhook deliveries in this time range.",llm:"No AI model calls in this time range."};function rL(A,e,t,i={}){return {command:e,aliases:t,needsProject:true,flags:{...INA,...i},run:async n=>{let{client:r}=n,o;try{o=CNA(n,A);}catch(u){return r.output.error(u instanceof Error?u.message:String(u)),1}let{options:s,following:g}=o,B=!!n.flags["--utc"];r.output.spinner("Loading logs\u2026");let I=await az(n,s);r.output.stopSpinner();let E=[...I.data].reverse();if(n.json&&!g?q(r,I):n.json?Iz(n,E,B):(fA(r,rz[A],E.map(u=>gz(u,nL(u,B))),ENA[A]),I.nextBefore&&!g&&r.output.log(`Showing the newest ${I.data.length} ${I.data.length===1?"entry":"entries"}. For older ones run ${eA(`logs ${A} --before ${I.nextBefore}`)} (with the same --since and filters).`)),g){let u=new Map;return iL(I.data,u),uNA(n,s,u,B,I.until)}return 0}}}var QNA=rL("api",$U,["requests"],{"--operation":String,"--status":String}),cNA=rL("webhooks",AL,["webhook"],{"--event":String,"--status":String}),lNA=rL("llm",eL,[]);async function oL(A){return KA(A,{command:iz,subcommands:[QNA,cNA,lNA],defaultSubcommand:"api"})}var vQ=nA(RA());function GQ(A,e,t,i,n=null){return {name:A,shorthand:n,type:e,argument:i,description:t,deprecated:false}}var fD=GQ("json",Boolean,"Print the API response as JSON on stdout"),xQ=GQ("project",String,"Project to use (default: linked project)","ID","p"),hNA=GQ("yes",Boolean,"Skip the confirmation prompt",void 0,"y"),Cz=GQ("name",String,"How the agent should address you (kept unchanged when omitted)","NAME"),sL={name:"show",description:"Show what the agent remembers about you in this project: your preferred name, your memory document (Markdown) and the read-only company memories every member shares.",arguments:[],options:[GQ("content",Boolean,"Print only your memory document on stdout (for redirecting to a file)"),fD,xQ],examples:[{name:"Show your memory",value:"flexkit memory show"},{name:"Save it to a file to edit it",value:"flexkit memory show --content > memory.md"},{name:"Print the company memories with jq",value:"flexkit memory show --json | jq -r '.companyMemories[]'"}]},gL={name:"set",description:"Replace your memory document with a Markdown file (or - for stdin). The Chat Agent and the MCP server read it in every session and may rewrite it as they learn.",arguments:[{name:"file|-",required:true}],options:[Cz,fD,xQ],examples:[{name:"Replace the memory with a file",value:"flexkit memory set memory.md"},{name:"Also set your preferred name",value:"flexkit memory set memory.md --name Dani"},{name:"Append a note from a script",value:'{ flexkit memory show --content; echo "- Prices are in EUR"; } | flexkit memory set -'}]},aL={name:"edit",description:"Open your memory document in $VISUAL or $EDITOR (vi by default) and save it when the editor closes. Needs a terminal.",arguments:[],options:[Cz,xQ],examples:[{name:"Edit the memory",value:"flexkit memory edit"},{name:"Edit it in VS Code",value:'EDITOR="code --wait" flexkit memory edit'}]},IL={name:"clear",description:"Empty your memory document. Your preferred name and the company memories stay. The agent starts learning again from your next sessions.",arguments:[],options:[hNA,fD,xQ],examples:[{name:"Clear the memory",value:"flexkit memory clear"},{name:"Clear it without the prompt",value:"flexkit memory clear --yes"}]},Bz={name:"memory",description:"Read and edit what the agent remembers about you in a project. The memory is personal: it needs your own session from `flexkit login`, and API tokens can't read or change it.",arguments:[],subcommands:[sL,gL,aL,IL],options:[fD,xQ],examples:[{name:"Show your memory",value:"flexkit memory show"},{name:"Edit it in your editor",value:"flexkit memory edit"},{name:"Replace it with a file",value:"flexkit memory set memory.md"},{name:"Start over",value:"flexkit memory clear"}]};function uz(A,e,t=2e4){if(A.length>t)return {error:`The memory is limited to ${t.toLocaleString("en-US")} characters; this one has ${A.length.toLocaleString("en-US")}.`};if(e===void 0)return {body:{content:A}};let i=e.trim();return i?i.length>100?{error:`--name is limited to ${String(100)} characters.`}:{body:{content:A,preferredName:i}}:{error:"--name needs a value. Omit it to keep the stored name."}}function CL(A,e=2e4){return `${A.length.toLocaleString("en-US")} / ${e.toLocaleString("en-US")} characters`}function Ez(A,e=process.platform){let t=A.VISUAL?.trim()||A.EDITOR?.trim();return t||(e==="win32"?"notepad":"vi")}function Qz(A,e=process.platform){return e==="win32"?`"${A.replace(/"/g,'""')}"`:`'${A.replace(/'/g,"'\\''")}'`}function cz(A,e){return A.replace(/\s+$/,"")!==e.replace(/\s+$/,"")}var uL="/agent/memory";function lz(A){return A.client.fetch(uL,{projectId:A.projectId})}async function hz(A,e,t=2e4){let i=uz(e,A.flags["--name"],t);if("error"in i)return A.client.output.error(i.error),1;A.client.output.spinner("Saving the memory");let n=await A.client.fetch(uL,{projectId:A.projectId,method:"PUT",body:i.body});return A.client.output.stopSpinner(),A.json?(q(A.client,n),0):(A.client.output.success(`Saved your memory (${CL(n.memory.content,n.maxLength??t)}).`),0)}async function DNA(A,e){if(e==="-")return bo(A);let t=ut__default.default.resolve(A.cwd,e.startsWith("@")?e.slice(1):e);if(!ZA__default.default.existsSync(t)||!ZA__default.default.statSync(t).isFile())throw new Error(`File not found: ${e}. Pass a Markdown file, or - to read stdin.`);return ZA__default.default.readFileSync(t,"utf8")}var mNA={command:sL,flags:{"--content":Boolean},needsProject:true,async run(A){let e=await lz(A);if(A.json)return q(A.client,e),0;if(A.flags["--content"])return A.client.stdout.write(e.memory.content.endsWith(`
|
|
555
555
|
`)?e.memory.content:`${e.memory.content}
|
|
556
556
|
`),0;let{memory:t}=e;if(ie(A.client,[["Preferred name",t.preferredName??vQ.default.dim("not set")],["Updated",t.updatedAt?QA(t.updatedAt):vQ.default.dim("never")],["Size",CL(t.content,e.maxLength)]]),t.content.trim()?A.client.output.print(`
|
|
557
557
|
${t.content.trimEnd()}
|