@stackone/cli 1.39.0 → 1.40.0

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/cli.cjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const e=require(`./agentConfig-KBkYYmMr.cjs`),t=require(`./cliCore-BnaGcYG7.cjs`);require(`./setupMigration-rqPZ8MV6.cjs`),require(`./agentApiKey-BDp7EFMI.cjs`);let n=require(`dotenv`);process.env.DOTENV_CONFIG_QUIET=`true`,(0,n.config)(),new t.t().run();
2
+ const e=require(`./agentConfig-KBkYYmMr.cjs`),t=require(`./cliCore-CtAXBkSt.cjs`);require(`./setupMigration-rqPZ8MV6.cjs`),require(`./agentApiKey-BDp7EFMI.cjs`);let n=require(`dotenv`);process.env.DOTENV_CONFIG_QUIET=`true`,(0,n.config)(),new t.t().run();
package/dist/cli.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{t as e}from"./cliCore-BEt2cFAT.mjs";import"./agentConfig-BWQWMYKQ.mjs";import"./setupMigration-C1ShGzOu.mjs";import"./agentApiKey-CWXxJgCO.mjs";import{config as t}from"dotenv";process.env.DOTENV_CONFIG_QUIET=`true`,t(),new e().run();export{};
2
+ import{t as e}from"./cliCore-DrKweOPX.mjs";import"./agentConfig-BWQWMYKQ.mjs";import"./setupMigration-C1ShGzOu.mjs";import"./agentApiKey-CWXxJgCO.mjs";import{config as t}from"dotenv";process.env.DOTENV_CONFIG_QUIET=`true`,t(),new e().run();export{};
@@ -171,5 +171,5 @@ Available skills
171
171
  `).filter(e=>e!==``);if(t.added){o+=n.length;for(let t of n)e.w.log(i.default.green(`+ ${t}`))}else if(t.removed){s+=n.length;for(let t of n)e.w.log(i.default.red(`- ${t}`))}else if(n.length<=6)for(let t of n)e.w.log(i.default.gray(` ${t}`));else{for(let t=0;t<3;t++)e.w.log(i.default.gray(` ${n[t]}`));e.w.log(i.default.gray(` ... (${n.length-6} unchanged lines)`));for(let t=n.length-3;t<n.length;t++)e.w.log(i.default.gray(` ${n[t]}`))}}e.w.log(``),e.w.log(i.default.gray(`Summary: ${i.default.green(`+${o}`)} additions, ${i.default.red(`-${s}`)} deletions`))}#o(e,t){return(0,E.diffLines)(e,t).some(e=>e.added||e.removed)}async#s(t,n,r,i,a){e.w.log(``);let o=await(0,w.select)({message:`How would you like to resolve the differences?`,options:[{value:`override`,label:`Override local with remote`,hint:`Replace your local file with the StackOne version`},{value:`keep-local`,label:`Keep local version`,hint:`Cancel the pull and keep your current file`},{value:`interactive`,label:`Resolve conflicts interactively`,hint:`Choose which changes to accept one by one`},{value:`cancel`,label:`Cancel`,hint:`Abort the pull operation`}]});if((0,w.isCancel)(o))return{action:`cancel`};if(o===`override`)return{action:`override`};if(o===`keep-local`)return{action:`keep-local`};if(o===`interactive`){let e=await this.#c(t,n,r,i,a);return e===null?{action:`interactive-cancel`}:{action:`interactive`,resolvedContent:e}}return{action:`cancel`}}async#c(t,n,r,i,a){let o=(0,E.diffLines)(t,n),s=this.#u(o);if(s.length===0)return e.w.info(`No conflicts to resolve.`),n;let c=new fn(s,r,i,a);for(;;){if((await c.resolve()).cancelled)return null;let t=c.getResolvedContent(),n=(0,T.validateYamlConnector)(t);if(n.success)return c.renderFinalSummary(),t;let r=await this.#l(n.errors);if(r===`cancel`)return e.v(),e.w.info(`Operation cancelled. No changes were made to the local connector.`),null;if(r===`save`)return e.v(),e.w.warn(`The connector was saved but it is invalid`),t;c.resetForReResolution()}}async#l(t){let{createInterface:n}=await import(`readline`);return new Promise(r=>{e.v();let a=(t||[{message:`Unknown validation error`}]).map(e=>` • ${e.message}`).join(`
172
172
  `);e.w.box({title:`⚠️ Validation Failed`,message:`The resolved connector configuration is invalid:\n\n${a}`,style:{borderColor:`yellow`,padding:1}}),e.w.log(``),e.w.log(i.default.bold(` Choose an action:`)),e.w.log(``),e.w.log(i.default.cyan(` [B]`)+` ← Go back to conflict resolution`),e.w.log(i.default.dim(` Modify your choices to fix the validation errors`)),e.w.log(``),e.w.log(i.default.yellow(` [S]`)+` 💾 Save anyway`),e.w.log(i.default.dim(` Save the invalid configuration (not recommended)`)),e.w.log(``),e.w.log(i.default.red(` [C]`)+` ✖ Cancel`),e.w.log(i.default.dim(` Discard all changes`)),e.w.log(``);let o=n({input:process.stdin,output:process.stdout});process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume();let s=e=>{let t=e.toString().toLowerCase(),n=()=>{process.stdin.removeListener(`data`,s),process.stdin.isTTY&&process.stdin.setRawMode(!1),o.close()};if(t===``||t===`\x1B`){n(),r(`cancel`);return}switch(t){case`b`:n(),r(`back`);break;case`s`:n(),r(`save`);break;case`c`:case`q`:n(),r(`cancel`);break}};process.stdin.on(`data`,s)})}#u(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(!r.added&&!r.removed)t.push({type:`unchanged`,content:r.value}),n++;else if(r.removed){let i=e[n+1];i?.added?(t.push({type:`conflict`,local:r.value,remote:i.value}),n+=2):(t.push({type:`conflict`,local:r.value,remote:void 0}),n++)}else r.added&&t.push({type:`conflict`,local:void 0,remote:r.value}),n++}return t}async#d(t,n){let r=h.default.dirname(t);m.default.existsSync(r)||m.default.mkdirSync(r,{recursive:!0});try{m.default.writeFileSync(t,n,`utf-8`)}catch(n){e.w.error(`Failed to write connector to file ${e.C(t)}: ${n.message}`),process.exit(1)}}async#f(t,n,r,i,a){let o=(0,v.default)(`Pulling connector ${e.C(t)}@${e.C(i)} from registry...`).start();try{let s=Buffer.from(r).toString(`base64`),c=`${n}/registry/connectors/${t}@${i}${a?`?owner=${encodeURIComponent(a)}`:``}`,l=await fetch(c,{method:`GET`,headers:{Authorization:`Basic ${s}`}});if(o.stop(),l.status===409){a&&(await this.#p(l,t,i),process.exit(1));let r=(await l.json()).availableOwners??[],c=await rn(`${t}@${i}`,r);o.text=`Pulling connector ${e.C(t)}@${e.C(i)} from registry...`,o.start();let u=`${n}/registry/connectors/${t}@${i}`,d=await fetch(`${u}?owner=${encodeURIComponent(c)}`,{method:`GET`,headers:{Authorization:`Basic ${s}`}});return o.stop(),d.ok||(await this.#p(d,t,i),process.exit(1)),await d.text()}return l.ok||(await this.#p(l,t,i),process.exit(1)),await l.text()}catch(r){o.stop(),e.w.error(`Failed to pull connector ${e.C(t)}@${e.C(i)} from the registry: ${r.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid.`),process.exit(1)}}async#p(t,n,r){switch(t.status){case 401:case 403:e.w.error(`Access denied`),e.w.log(`Please ensure that your API key is valid and has the ${e.C(`connectors:read`)} scope required to pull connectors.`);break;case 404:e.w.error(`Connector ${e.C(n)}@${e.C(r)} was not found in the registry`),await this.#m(n);break;case 429:e.w.error(`Rate limit exceeded`),e.w.log(`Too many requests. Please wait a moment before trying again.`);break;default:await e.x(t,`Failed to pull connector ${e.C(n)}`)}}async#m(t){e.w.info(`To see available versions, check the connector documentation or contact support.`)}};const gn=`https://api.stackone.com`;var _n=class{async execute({profile:t,fileOrDir:n,apiUrl:r,apiKey:a,force:o}={}){if(!t&&!a&&(e.w.error(`Profile or API key is required`),e.w.log(`Please provide a profile using the ${e.C(`--profile`)} option or an API key using the ${e.C(`--api-key`)} option.`),e.w.log(`To create a profile, run ${e.C(`stackone init`)}.`),process.exit(1)),t&&a&&(e.w.error(`Please provide either a profile or an API key, not both`),process.exit(1)),t&&r&&e.w.warn(`Specifying ${e.C(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),t&&!Zt(t)){e.w.error(`Configuration profile ${e.C(t)} not found`),e.w.log(`Run ${e.C(`stackone init`)} to create a new configuration profile.\n`);let n=$t();n.length>0&&(e.w.info(`Available configuration profiles:`),n.forEach(t=>{e.w.log(` - ${i.default.blue(t)}`)})),process.exit(1)}let s=t?Xt(t):{apiUrl:r??gn,apiKey:a};s?.apiKey||(e.w.error(`API key is missing`),e.w.log(`Please provide a valid API key in the profile or via the ${e.C(`--api-key`)} option.`),process.exit(1)),n||(e.w.error(`File or directory is required.`),process.exit(1));try{(0,m.statSync)(n)}catch{e.w.error(`File or directory not found: ${i.default.red(n)}`),process.exit(1)}let c=(0,m.statSync)(n),l=s.apiUrl??gn;if(c.isDirectory()){let t=xn(n),r=0;t.length===0?(e.w.error(`No .s1.yaml connector files found in the directory: ${n}.`),process.exit(1)):(e.w.start(`Found ${t.length} connector(s) file(s). Pushing to registry...`),e.w.log(``));for(let e of t)await this.uploadFile(e,l,s.apiKey,o)&&r++;r===0?e.w.error(`Error while pushing connectors: no files were uploaded`):(e.w.log(``),e.w.info(`Upload completed: ${i.default.green(r)} of ${i.default.blue(t.length)} file(s) uploaded successfully.`)),process.exit(r>0?0:1)}else n.endsWith(`.s1.yaml`)||(e.w.error(`Only ${e.C(`.s1.yaml`)} files are supported for upload`),process.exit(1));let u=await this.uploadFile(n,l,s.apiKey,o);process.exit(u?0:1)}async uploadFile(t,n,r,i){let a=(0,v.default)(`📤 Pushing connector in ${(0,h.basename)(t)}...`).start();try{let o=bn(t);if(!o)return!1;let s=(0,h.basename)(t),c=new FormData,l=new Blob([o],{type:`application/x-yaml`});c.append(`file`,l,s),i&&c.append(`force`,`true`);let u=Buffer.from(r).toString(`base64`),d=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${u}`},body:c});if(a.stop(),!d.ok)return d.status===409||d.status===422?await this.handleVersionConflict(d,t,n,r,i):(await e.x(d,`Failed to push connector in ${e.C(s)} to the registry`),!1);let f=await d.json();return e.w.success(`Successfully uploaded ${e.C(s)} with connector ${e.C(f.provider)}@${e.C(f.version)}`),!0}catch(r){return a.stop(),e.w.error(`Failed to upload file ${e.C(t)}: ${r}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),!1}}async handleVersionConflict(t,n,r,i,a){let o=await t.text(),s;try{s=JSON.parse(o)}catch{}let c=D.default.valid(s?.latestVersion);if(!c)return await e.x(new Response(o,{status:t.status,statusText:t.statusText}),`Failed to push connector in ${e.C((0,h.basename)(n))} to the registry`),!1;let l=(0,m.readFileSync)(n,`utf-8`),u=vn(l),d=u?`${e.C(u)}`:``,f=t.status===409?`Version ${d} already exists in the registry. Latest version: ${e.C(c)}`:`Version ${d} is lower than the latest version in the registry. Latest version: ${e.C(c)}`;e.w.error(f);let p=D.default.inc(c,`patch`)??c,g=D.default.inc(c,`minor`)??c,_=D.default.inc(c,`major`)??c,v=await(0,w.select)({message:`How would you like to proceed?`,options:[{value:p,label:`Bump patch version (${p})`},{value:g,label:`Bump minor version (${g})`},{value:_,label:`Bump major version (${_})`},{value:`cancel`,label:`Cancel push`}]});return(0,w.isCancel)(v)||v===`cancel`?((0,w.cancel)(`Push cancelled`),!1):((0,m.writeFileSync)(n,yn(l,v),`utf-8`),e.w.info(`Updated version to ${e.C(v)} in ${(0,h.basename)(n)}`),this.uploadFile(n,r,i,a))}};const vn=e=>e.match(/^\s*version: (\S+)/m)?.[1],yn=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),bn=t=>{let n=(0,T.loadConnector)(t),r=(0,T.validateYamlConnector)(n),i=r?.errors??[];if(r.success)return n;i.length>0?(e.w.error(`Connector in ${e.S(t)} is not valid`),e.y(i,!0)):e.w.error(`Connector in ${e.S(t)} is not valid. Please check the file for errors.`)},xn=e=>{let t=[],n=(0,m.readdirSync)(e,{withFileTypes:!0});for(let r of n){let n=(0,h.join)(e,r.name);r.isDirectory()?t.push(...xn(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},Sn=C.z.object({provider_key:C.z.string().optional(),provider_version:C.z.string().optional(),auth_config_key:C.z.string(),environment:C.z.string().default(`production`),organization_id:C.z.string().default(`cli-organization-id`),account_id:C.z.string().default(`cli-account-secure-id`),project_id:C.z.string().default(`cli-project-secure-id`),credentials:C.z.record(C.z.string(),C.z.any()).default({})}),Cn=C.z.record(C.z.string(),C.z.any()),wn=C.z.object({path:C.z.record(C.z.string(),C.z.any()).default({}),queryParams:C.z.record(C.z.string(),C.z.any()).default({}),header:C.z.record(C.z.string(),C.z.any()).default({}),body:C.z.record(C.z.string(),C.z.any()).default({})}),Tn=`https://api.stackone.com`;var En=class{async execute({connector:t,action:n,actionId:r,account:a,accountId:o,params:s,credentials:c,profile:l,outputFile:u,debug:d,apiUrl:f,apiKey:p,owner:h}={}){if(!l&&!p&&o&&(e.w.error(`Profile or API key is required when providing an account ID`),e.w.log(`Please provide a profile using the ${e.C(`--profile`)} option or an API key using the ${e.C(`--api-key`)} option.`),e.w.log(`To create a profile, run ${e.C(`stackone init`)}.`),process.exit(1)),l&&p&&(e.w.error(`Please provide either a profile or an API key, not both`),process.exit(1)),l&&f&&e.w.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),l&&!Zt(l)){e.w.error(`Configuration profile ${e.C(l)} not found`),e.w.log(`Run ${e.C(`stackone init`)} to create a new configuration profile.\n`);let t=$t();t.length>0&&(e.w.info(`Available configuration profiles:`),t.forEach(t=>{e.w.log(` - ${i.default.blue(t)}`)})),process.exit(1)}let g=l?Xt(l):{apiUrl:f??Tn,apiKey:p};(0,C.isMissing)(a)&&(0,C.isMissing)(o)&&(e.w.error(`A valid account or account ID is required to run an action`),process.exit(1));let _;if((0,C.notMissing)(t))if(this.#a(t)){!l&&!p&&(e.w.error(`Profile or API key is required when using a connector identifier`),e.w.log(`Please provide a profile using the ${e.C(`--profile`)} option or an API key using the ${e.C(`--api-key`)} option.`),e.w.log(`Run ${e.C(`stackone init`)} to create a new configuration profile.`),process.exit(1));let n=this.#o(t);_=await this.#s(n,g?.apiUrl??Tn,g?.apiKey,h)}else _=this.#e(t);else (0,C.notMissing)(o)&&(_=await this.#c(o,g?.apiUrl??Tn,g?.apiKey));let v=(0,C.notMissing)(n)?this.#r(n,t):_;(0,C.isMissing)(v)&&(e.w.error(`A valid connector is required to run an action.`),process.exit(1));let y=(0,C.notMissing)(v?.actions)?Object.keys(v?.actions).length:0,b=(0,C.notMissing)(v?.actions)?Object.keys(v.actions)[y-1]:void 0,x=(0,C.notMissing)(b)?v?.actions?.[b]?.id:void 0,S=((0,C.notMissing)(r)&&!r?.startsWith(`${v.key}_`)?`${v.key}_${r}`:r)??x;(0,C.isMissing)(S)&&(e.w.error(`A valid action ID is required to run an action`),process.exit(1));let w=(0,C.notMissing)(o)?await this.#l(o,g?.apiUrl??Tn,g?.apiKey):{},T=(0,C.notMissing)(a)?this.#i(a,v.key??`unknown`,v.version??`unknown`):void 0,E=(0,C.notMissing)(c)?this.#u(c):{},ee={...w,...T,credentials:{...w.credentials??{},...E}};(0,C.isMissing)(ee)&&(e.w.error(`A valid account data is required to run an action.`),process.exit(1));let D=v.actions?.[S];(0,C.isMissing)(D)&&(e.w.error(`Action ID ${e.C(S)} not found in the connector ${e.C(v.key)}@${e.C(v.version)}.`),process.exit(1));let O=(0,C.notMissing)(s)?this.#d(s,S):{path:{},queryParams:{},header:{},body:{}},k=Date.now(),A=await this.#f({connector:v,actionId:S,account:ee,queryParams:{...O.queryParams,...d?{debug:`true`}:{}},pathParams:O.path,body:O.body,headers:O.header}),j=Date.now()-k;if((0,C.notMissing)(u))try{m.default.writeFileSync(u,JSON.stringify(A.output,null,2),`utf-8`),e.w.info(`Output written to file: ${u}`)}catch(t){e.w.error(`Failed to write output to file ${u}: ${t.message}`),process.exit(1)}else e.w.log(`\n${i.default.blue.inverse(` ACTION OUTPUT `)}`),e.b(A.output);e.w.log(``),e.w.info(`Action ${e.C(S)} from connector ${e.C(v?.key)}@${e.C(v?.version)} finished in ${i.default.yellowBright((j/1e3).toFixed(2))} seconds.`),process.exit(0)}#e=e=>{let t=e;try{t=(0,T.loadConnector)(e)}catch{}return t?this.#n(t):void 0};#t=t=>{try{return(0,T.loadConnector)(t)}catch(n){e.w.error(`Failed to load connector file from ${e.C(t)}: ${n.message}`),process.exit(1)}};#n=t=>{let n=(0,T.validateYamlConnector)(t),r=n?.errors??[];if(n.success)return n.connector||(e.w.error(`Failed to load connector.`),process.exit(1)),n.connector;r.length>0?(e.w.error(`Connector is not valid`),e.y(r,!0),process.exit(1)):(e.w.error(`Connector is not valid. Please check the file for errors.`),process.exit(1))};#r=(t,n)=>{let r=t;try{r=m.default.readFileSync(t,`utf-8`)}catch{}(0,C.isMissing)(n)&&(e.w.error(`A valid connector is required to load an action.`),process.exit(1));let i=`${this.#t(n)} - ${r.split(`
173
173
  `).map((e,t)=>t===0?e:` ${e}`).join(`
174
- `)}`;return this.#n(i)};#i=(t,n,r)=>{let i=t;try{i=m.default.readFileSync(t,`utf-8`)}catch{}try{let e=Sn.parse(JSON.parse(i));return{providerKey:n,providerVersion:r,authConfigKey:e.auth_config_key,environment:e.environment,organizationId:e.organization_id,secureId:e.account_id,projectSecureId:e.project_id}}catch(t){let n=[];try{n=JSON.parse(t.message)}catch{}e.w.error(`Failed to parse account information`),e.y(n,!1),n.length===0&&e.w.log(t.message),process.exit(1)}};#a=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#o=e=>e.includes(`@`)?e:`${e}@latest`;#s=async(t,n,r,i)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Connector identifier, API URL, and API key are required to fetch connector from registry.`),process.exit(1));let a=(0,v.default)();try{a.text=`Fetching connector ${e.C(t)} from registry...`,a.start();let o=Buffer.from(r).toString(`base64`),s=i?`?owner=${encodeURIComponent(i)}`:``,c=await fetch(`${n}/registry/connectors/${t}${s}`,{method:`GET`,headers:{Authorization:`Basic ${o}`}});if(a.stop(),c.status===409){i&&(await e.x(c,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let r=await rn(t,(await c.json()).availableOwners??[]);a.text=`Fetching connector ${e.C(t)} from registry...`,a.start();let s=await fetch(`${n}/registry/connectors/${t}?owner=${encodeURIComponent(r)}`,{method:`GET`,headers:{Authorization:`Basic ${o}`}});a.stop(),s.ok||(await e.x(s,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let l=await s.text(),u=this.#n(l);return e.w.success(`Fetched connector ${e.C(u.key)}@${e.C(u.version)} from registry`),u}c.ok||(await e.x(c,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let l=await c.text(),u=this.#n(l);return e.w.success(`Fetched connector ${e.C(u.key)}@${e.C(u.version)} from registry`),u}catch(r){a.stop(),e.w.error(`Failed to fetch connector ${e.C(t)} from registry: ${r.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#c=async(t,n,r)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch connector`),process.exit(1));let i=(0,v.default)();try{i.text=`Fetching connector for account ${e.C(t)} from API...`,i.start();let a=Buffer.from(r).toString(`base64`),o=await fetch(`${n}/accounts/${t}/connector`,{method:`GET`,headers:{Authorization:`Basic ${a}`}});i.stop(),o.ok||(await e.x(o,`Failed to fetch connector`),process.exit(1));let s=await o.text(),c=this.#n(s);return e.w.success(`Fetched connector ${e.C(c.key)}@${e.C(c.version)} for account ${e.C(t)}`),c}catch(t){i.stop(),e.w.error(`Failed to fetch connector: ${t.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#l=async(t,n,r)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch account information.`),process.exit(1));let i=(0,v.default)();try{i.text=`Fetching account ${e.C(t)} information from API...`,i.start();let a=Buffer.from(r).toString(`base64`),o=await fetch(`${n}/accounts/${t}/credentials`,{method:`GET`,headers:{Authorization:`Basic ${a}`}});i.stop(),o.ok||(await e.x(o,`Failed to fetch account ${e.C(t)} information`),process.exit(1));let s=await o.json();return e.w.success(`Fetched account ${e.C(t)} information from project ${e.C(s.project_id)}`),{providerKey:s.provider_key,providerVersion:s.provider_version,authConfigKey:s.auth_config_key,environment:s.environment,organizationId:s.organization_id,secureId:s.account_id,projectSecureId:s.project_id,credentials:s.credentials}}catch(r){i.stop(),e.w.error(`Failed to fetch account ${e.C(t)} information: ${r.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#u=t=>{let n=t;try{n=m.default.readFileSync(t,`utf-8`)}catch{}try{return Cn.parse(JSON.parse(n))}catch(t){let n=[];try{n=JSON.parse(t.message)}catch{}e.w.error(`Failed to parse credentials`),e.y(n,!1),n.length===0&&e.w.log(t.message),process.exit(1)}};#d=(t,n)=>{let r=t;try{r=m.default.readFileSync(t,`utf-8`)}catch{}try{return wn.parse(JSON.parse(r))}catch(t){let r=[];try{r=JSON.parse(t.message)}catch{}e.w.error(`Invalid parameters for action ${e.C(n)}.`),e.y(r,!1),r.length===0&&e.w.log(t.message),process.exit(1)}};async#f({connector:t,actionId:n,account:r,pathParams:a={},queryParams:o={},body:s={},headers:c={}}){try{let l=await(0,T.runAction)({mode:`action_id`,actionId:n,account:r,connector:t,pathParams:a,queryParams:o,body:s,headers:c,getHttpClient:async()=>new O.HttpClient});if(l.response?.successful){let e={...this.#p(o,l.steps),...(0,C.isObject)(l.outputs)?l.outputs:{data:l.outputs}};return{statusCode:l.response?.statusCode,output:e}}else{let r=l.response?.message??`An error occurred while processing the request`;e.w.error(`Action ID ${e.C(n)} from connector ${e.C(t.key)}@${e.C(t.version)} failed with status ${l.response?.statusCode}: ${r}`);let a={...this.#p(o,l.steps)};Object.keys(a).length>0&&(e.w.log(`${i.default.yellow.inverse(` EXECUTION DETAILS `)}`),e.b(a)),process.exit(1)}}catch(e){this.#m(e)}}#p(e,t){return e?.debug===`true`?{debug:{steps:t}}:{}}#m(t){let n=t;switch((0,C.isMissing)(n.errorType)&&(e.w.error(`An unknown error occurred`),e.w.log(`${t instanceof Error?t.message:String(t)}`),process.exit(1)),n.errorType){case`MISSING_ACTION_ERROR`:e.w.error(`The specified action was not found: ${n.message}`);break;case`INVALID_ACTION_INPUTS_ERROR`:let t=n;e.w.error(`Invalid action inputs`),e.y(t.validationErrors,!1);break;case`INVALID_CURSOR_ERROR`:e.w.error(`Invalid cursor: ${n.message}`);break;default:e.w.error(`An error occurred: ${n.message}`)}process.exit(1)}};const Dn=(0,k.promisify)(f.exec);var On=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=(0,v.default)(),this.currentVersion=q()}async execute(t={}){this.spinner.text=`Checking for updates...`,this.spinner.start();try{let n=await this.getLatestVersion();this.spinner.stop(),n||(e.w.error(`Failed to check for updates`),process.exit(1)),this.isNewerVersion(n,this.currentVersion)?(e.w.box(`New version available: ${i.default.yellow(this.currentVersion)} → ${i.default.green(n)}`),await this.performUpdate(n)):t.force?(e.w.warn(`No updates available, but forcing reinstall...`),await this.performUpdate(n)):e.w.success(`You are already on the latest version (${this.currentVersion})`),process.exit(0)}catch(t){this.spinner.stop(),e.w.error(`Error while trying to update StackOne CLI: ${t?.message??`Unknown error`}`),process.exit(1)}}async getLatestVersion(){try{let{stdout:e}=await Dn(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return D.default.gt(e,t)}async performUpdate(t){this.spinner.text=`Updating to latest version (${e.C(t)})...`,this.spinner.start();let n=`npm install -g ${this.packageName}@latest`;try{await Dn(n,{encoding:`utf-8`}),this.spinner.stop(),e.w.success(`StackOne CLI updated successfully to latest version (${e.C(t)})`)}catch{throw this.spinner.stop(),Error(`Failed to install update. Please try manually: ${n}`)}}};const kn=()=>{e.w.log(`${i.default.gray.inverse(` CONNECTORS VALIDATION `)} ${i.default.yellow.inverse(` WATCH MODE `)}\n`)};var An=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,a=(0,v.default)(`Watching for file changes... ${i.default.gray(`(press "q" to quit)`)}`);if(!r)return;let o=(0,h.resolve)(r);try{await(0,A.stat)(o)}catch{e.w.error(`The specified path does not exist: ${o}\n`),process.exit(1)}if(n){e.v();let t={},{watch:n}=await import(`chokidar`),r=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{l.close(),a.stop(),r.close(),e.w.log(i.default.grey(`
175
- Exiting watch mode...`)),process.exit(0)};kn(),e.w.start(`Validating connectors...`);let c=await Pn(o);t=jn(t,c||{}),Mn(t,o),a.start();let l=n(o,{persistent:!0,ignoreInitial:!0}),u=async n=>{if(!n.endsWith(`.s1.yaml`)&&!n.endsWith(`s1.partial.yaml`))return;let r=n.endsWith(`s1.partial.yaml`)?await In(n):[n];if(!(!r||r.length===0)){e.v(),a.stop(),kn(),e.w.log(i.default.gray(`File change detected: ${n}`)),e.w.start(`Validating connectors...`);for(let e of r){let n=await Pn(e);t=jn(t,n||{})}Mn(t,o),a.start()}};l.on(`change`,async e=>await u(e)),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await Pn(o,e.w),process.exit(0)}};const jn=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Mn=(t,n)=>{e.v(),kn();let r=0,a=0;for(let[n,i]of Object.entries(t))i===null?r++:(e.w?.error(`Connector ${e.C(n)} is not valid`),e.y(i,!0),a++);e.w.log(``),e.w.log(i.default.blue.inverse(` Validation Summary `)),e.w.log(`Connectors path: ${e.C(n)}`),e.w.log(`${r===0?i.default.red(`0`):i.default.green(r)} valid, ${a===0?i.default.green(`0`):i.default.red(a)} invalid connectors\n`)},Nn=async e=>{let t=[],n=await(0,A.readdir)(e);for(let r of n){let n=(0,h.join)(e,r),i=await(0,A.stat)(n);i.isDirectory()?t.push(...await Nn(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Pn=async(t,n)=>{let r=await(0,A.stat)(t),a={};if(r.isDirectory()){let r=await Nn(t);if(r.length===0)return n?.error(`No StackOne connector found in ${e.S(t)}`),n?.log(`Connector files need to have the extension ${e.C(`*.s1.yaml`)}`),null;let o=0,s=0;for(let e of r){let t=await Fn(e,n);t===null?o++:(n?.log(``),s++),a[e]=t}return n?.log(``),n?.log(i.default.blue.inverse(` Validation Summary `)),n?.log(`${o===0?i.default.red(`0`):i.default.green(o)} valid, ${s===0?i.default.green(`0`):i.default.red(s)} invalid connectors`),a}else if(r.isFile()&&t.endsWith(`s1.yaml`))return a[t]=await Fn(t,n),a;else if(r.isFile()&&t.endsWith(`partial.yaml`)){n?.error(`Partial connector files cannot be validated directly`),n?.log(`The file ${e.S(t)} is a partial connector file.`);let r=await In(t);return r&&r?.length>0&&n?.log(`Did you mean ${e.C(r[0])}?`),null}else return n?.error(`No StackOne connector found in ${e.S(t)}`),n?.log(`Connector files need to have the extension ${e.C(`*.s1.yaml`)}`),null},Fn=async(t,n)=>{let r=(0,T.validateYamlConnector)((0,T.loadConnector)(t)),i=r?.errors??[];if(r.success){let r=t.split(`/`).pop()||t;return n?.success(`Connector ${e.C(r)} is valid!`),null}else if(i.length>0)return n?.error(`Connector ${e.C(t)} is not valid`),n&&e.y(i,!0),i;else return n?.error(`Connector ${e.C(t)} is not valid. Please check the file for errors`),[]},In=async e=>{let t=(0,h.dirname)(e);try{return(await(0,A.readdir)(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>(0,h.join)(t,e))}catch{}},Ln=`https://ai-telemetry.stackone.com`,Rn=`https://ai-telemetry.stackone-dev.com`;function zn(e){if(!e)return!1;try{let{hostname:t}=new URL(e);return t===`stackone-dev.com`||t.endsWith(`.stackone-dev.com`)}catch{return!1}}function Bn(){return process.env.AI_TELEMETRY_URL?process.env.AI_TELEMETRY_URL:[process.env.AUTH_SERVER_URL,process.env.STACKONE_API_URL].some(zn)?`https://ai-telemetry.stackone-dev.com`:`https://ai-telemetry.stackone.com`}function Vn(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(process.env.AI_TELEMETRY_URL=Bn(),e)try{(0,o.initAgentTelemetry)({apiKey:e,projectName:t}),process.env.VERBOSE&&console.log(`[Telemetry] Initialized for project:`,t)}catch(e){process.env.VERBOSE&&console.error(`[Telemetry] Failed to initialize:`,e)}}const Hn=`@stackone/cli`,Un=2880*60*1e3,Wn=(0,l.join)((0,c.homedir)(),`.stackone`),Gn=(0,l.join)(Wn,`version-check.json`),Kn=(e=!1)=>{let t=Xn(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=qn();e&&Jn(e)&&Yn(e),Zn({lastCheckTime:n})}},qn=()=>{try{return(0,f.execSync)(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},Jn=e=>{try{let t=q();return D.default.gt(e,t)}catch{return!1}},Yn=t=>{let n=q(),r=`Update available: ${i.default.dim(n)} → ${i.default.green(t)}`,a=`\n\nRun ${i.default.cyan(`stackone update`)} to update`;e.w.box(r,a)},Xn=()=>{try{if(!(0,s.existsSync)(Gn))return null;let e=(0,s.readFileSync)(Gn,`utf-8`);return JSON.parse(e)}catch{return null}},Zn=e=>{try{(0,s.existsSync)(Wn)||(0,s.mkdirSync)(Wn,{recursive:!0}),(0,s.writeFileSync)(Gn,JSON.stringify(e,null,2),`utf-8`)}catch{}};var Qn=class{constructor(e=new a.Command,t=q()){this.program=e,this.version=t,Vn(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let t=new un,n=new _n,r=new hn,o=new tn,s=new on,c=new An,l=new Je,u=new Ut,d=new Me,f=new je,p=new Xe,m=new Wt,h=new qt,g=new En,_=new On;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(i.default.red(e))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(e=>{t.execute({environment:e.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`--force`,`Force push the connector, bypassing version conflict checks`).addArgument(new a.Argument(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{n.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey,force:t.force})}),this.program.command(`drop`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new a.Argument(`<connector>`,`Connector identifier in format provider_key@version`)).description(`Drop a connector from the StackOne registry`).action((e,t)=>{o.execute({profile:t.profile,connector:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`get`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key (defaults to latest)`).option(`--account-id <account-id>`,`Account ID to fetch connector from`).option(`-f, --format <format>`,`Output format: yaml or json (default: yaml)`,`yaml`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Get a connector from the StackOne registry`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),s.execute({profile:t.profile,connector:t.connector,accountId:t.accountId,format:t.format,outputFile:t.outputFile,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})}),this.program.command(`pull`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output <path>`,`Output directory for the connectors files (default: ./connectors)`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Pull a connector configuration from StackOne registry to local filesystem`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),r.execute({profile:t.profile,connector:t.connector,outputPath:t.output,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new a.Argument(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{c.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`run`).option(`--connector <connector>`,`Connector file, inline YAML, or identifier (provider_key@version or provider_key for latest)`).option(`--action <action>`,`Action to execute on the connector (path to file or inline string action code)`).option(`--action-id <action-id>`,`Action ID to execute on the connector`).option(`--account <account>`,`Account details to use for running the connector (path to file or inline string account data)`).option(`--account-id <account-id>`,`Account ID to use for running the connector against (fetches connector from API if --connector not provided)`).option(`--params <params>`,`Action parameters (path to file or inline string with JSON parameters)`).option(`--credentials <credentials>`,`Credentials to use (path to file or inline string with JSON credentials)`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`-d, --debug`,`Enables debug mode to include more details in the action execution output`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Run a connector action`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),g.execute({connector:t.connector,action:t.action,actionId:t.actionId,account:t.account,accountId:t.accountId,params:t.params,credentials:t.credentials,profile:t.profile,outputFile:t.outputFile,debug:t.debug,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})});let v=this.program.command(`agent`).description(`StackOne agent commands`);v.command(`setup`).option(`-g, --global`,`Global only: auth + MCP server (no connector skills/guide)`).option(`-l, --local`,`Local: auth + .mcp.json + connector skills (.claude/) and guide (CLAUDE.md)`).option(`--path <dir>`,`Target project path for local setup (defaults to the current directory)`).option(`--legacy`,`Use email/password login instead of browser-based auth`).option(`--email <email>`,`Email for legacy login (or set STACKONE_EMAIL); requires --legacy`).option(`--password <password>`,`Password for legacy login (or set STACKONE_PASSWORD); requires --legacy. Prefer --password-stdin`).option(`--password-stdin`,`Read password for legacy login from stdin; requires --legacy`).description(`Set up the StackOne agent — prompts for global vs local when neither flag is given`).action(async t=>{t.global&&t.local&&(e.w.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1));let n=t.email!==void 0,r=t.password!==void 0,a=t.passwordStdin===!0;r&&a&&(e.w.error(`--password and --password-stdin are mutually exclusive. Please provide only one.`),process.exit(1));let o=n||r||a;o&&!t.legacy&&(e.w.error(`--email, --password, and --password-stdin require --legacy.`),process.exit(1)),n&&t.email.trim()===``&&(e.w.error(`--email cannot be empty.`),process.exit(1)),r&&t.password===``&&(e.w.error(`--password cannot be empty.`),process.exit(1)),a&&(n||process.env.STACKONE_EMAIL?.trim()||(e.w.error(`--password-stdin requires --email or STACKONE_EMAIL (stdin is consumed for the password, so email cannot be prompted).`),process.exit(1)));let s={email:t.email,password:t.password,passwordFromStdin:a},c=!!process.stdin.isTTY;if(c&&!t.legacy&&!o){let e=await Ht({initialMode:t.global?`global`:t.local?`local`:null,pathFlag:t.path});process.exit(e.status===`error`?1:0)}let d=c&&!o;!t.global&&!t.local&&!d&&e.w.log(i.default.dim(`No interactive terminal detected — defaulting to global setup. Run in a terminal for the prompt, or pass --local (with --path) / --global.`));let f=et(t.global,t.local,d);if(f===null&&(f=await zt()),f===`local`){let e=tt(t.path,d);e===null&&(e=await Vt(process.cwd())),await u.execute({legacy:!!t.legacy,credentials:s,targetPath:e})}else await l.execute({legacy:!!t.legacy,credentials:s})}),v.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{d.execute()}),v.command(`run`).description(`Run the agent once with a prompt (non-interactive)`).argument(`<prompt>`,`What to do`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`--max-turns <n>`,`Max agent turns`,`25`).option(`-v, --verbose`,`Verbose output`).action(async(t,n)=>{let r=[`build`,`test`,`research`],a=n.mode??`build`;r.includes(a)||(e.w.error(`${i.default.red(`Invalid mode:`)} ${i.default.white(a)}. Valid modes are: ${r.join(`, `)}.`),process.exit(1));let o=n.maxTurns?parseInt(String(n.maxTurns),10):void 0;await p.execute({prompt:String(t),mode:a,maxTurns:o!==void 0&&!isNaN(o)?o:void 0,verbose:n.verbose})}),v.command(`skills`).description(`List available agent skills and optional recommendations by mode`).option(`-m, --mode <mode>`,`Show skills recommended for this mode`).action(async e=>{await m.execute({mode:e.mode})}),v.command(`sync`).description(`Sync the connector-building skills + guide into this project (.claude/ + CLAUDE.md)`).option(`--check`,`Report drift and exit non-zero instead of writing (CI guard)`).option(`--plugin-dir <path>`,`Override the agent-harness plugin dir (e.g. point at a checkout in CI/benchmarks)`).action(async e=>{await h.execute({check:!!e.check,pluginDir:e.pluginDir})}),v.command(`chat`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`-c, --connector <name>`,`Connector name`).option(`-a, --action <name>`,`Action name`).option(`-g, --goal <goal>`,`Initial goal/message`).option(`-t, --temperature <number>`,`Temperature (0-1, default: 0.5)`,parseFloat).option(`-v, --verbose`,`Enable verbose logging`).description(`Start an interactive chat session with the agent (use /commands in chat)`).action(async t=>{let n=[`build`,`test`,`research`];t.mode&&!n.includes(t.mode)&&(e.w.error(`❌ Error: Invalid mode "${t.mode}". Must be one of: ${n.join(`, `)}`),process.exit(1)),t.temperature!==void 0&&(isNaN(t.temperature)&&(e.w.error(`❌ Error: Temperature must be a valid number`),process.exit(1)),(t.temperature<0||t.temperature>1)&&(e.w.error(`❌ Error: Temperature must be between 0 and 1`),process.exit(1))),f.execute({mode:t.mode,connector:t.connector,action:t.action,goal:t.goal,temperature:t.temperature,verbose:t.verbose})}),this.program.command(`update`).option(`-f, --force`,`Force reinstall even if already on latest version`).description(`Update the CLI to the latest version`).action(e=>{_.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{e.w.log(`${i.default.inverse.greenBright(`StackOne`)} ${i.default.grey(`CLI`)} ${i.default.whiteBright(this.version)}`),Kn(!0),process.exit(0)})}run(){process.argv.includes(`version`)||Kn(),this.program.parse(process.argv)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return Qn}});
174
+ `)}`;return this.#n(i)};#i=(t,n,r)=>{let i=t;try{i=m.default.readFileSync(t,`utf-8`)}catch{}try{let e=Sn.parse(JSON.parse(i));return{providerKey:n,providerVersion:r,authConfigKey:e.auth_config_key,environment:e.environment,organizationId:e.organization_id,secureId:e.account_id,projectSecureId:e.project_id}}catch(t){let n=[];try{n=JSON.parse(t.message)}catch{}e.w.error(`Failed to parse account information`),e.y(n,!1),n.length===0&&e.w.log(t.message),process.exit(1)}};#a=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#o=e=>e.includes(`@`)?e:`${e}@latest`;#s=async(t,n,r,i)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Connector identifier, API URL, and API key are required to fetch connector from registry.`),process.exit(1));let a=(0,v.default)();try{a.text=`Fetching connector ${e.C(t)} from registry...`,a.start();let o=Buffer.from(r).toString(`base64`),s=i?`?owner=${encodeURIComponent(i)}`:``,c=await fetch(`${n}/registry/connectors/${t}${s}`,{method:`GET`,headers:{Authorization:`Basic ${o}`}});if(a.stop(),c.status===409){i&&(await e.x(c,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let r=await rn(t,(await c.json()).availableOwners??[]);a.text=`Fetching connector ${e.C(t)} from registry...`,a.start();let s=await fetch(`${n}/registry/connectors/${t}?owner=${encodeURIComponent(r)}`,{method:`GET`,headers:{Authorization:`Basic ${o}`}});a.stop(),s.ok||(await e.x(s,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let l=await s.text(),u=this.#n(l);return e.w.success(`Fetched connector ${e.C(u.key)}@${e.C(u.version)} from registry`),u}c.ok||(await e.x(c,`Failed to fetch connector ${e.C(t)} from registry`),process.exit(1));let l=await c.text(),u=this.#n(l);return e.w.success(`Fetched connector ${e.C(u.key)}@${e.C(u.version)} from registry`),u}catch(r){a.stop(),e.w.error(`Failed to fetch connector ${e.C(t)} from registry: ${r.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#c=async(t,n,r)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch connector`),process.exit(1));let i=(0,v.default)();try{i.text=`Fetching connector for account ${e.C(t)} from API...`,i.start();let a=Buffer.from(r).toString(`base64`),o=await fetch(`${n}/accounts/${t}/connector`,{method:`GET`,headers:{Authorization:`Basic ${a}`}});i.stop(),o.ok||(await e.x(o,`Failed to fetch connector`),process.exit(1));let s=await o.text(),c=this.#n(s);return e.w.success(`Fetched connector ${e.C(c.key)}@${e.C(c.version)} for account ${e.C(t)}`),c}catch(t){i.stop(),e.w.error(`Failed to fetch connector: ${t.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#l=async(t,n,r)=>{((0,C.isMissing)(t)||(0,C.isMissing)(n)||(0,C.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch account information.`),process.exit(1));let i=(0,v.default)();try{i.text=`Fetching account ${e.C(t)} information from API...`,i.start();let a=Buffer.from(r).toString(`base64`),o=await fetch(`${n}/accounts/${t}/credentials`,{method:`GET`,headers:{Authorization:`Basic ${a}`}});i.stop(),o.ok||(await e.x(o,`Failed to fetch account ${e.C(t)} information`),process.exit(1));let s=await o.json();return e.w.success(`Fetched account ${e.C(t)} information from project ${e.C(s.project_id)}`),{providerKey:s.provider_key,providerVersion:s.provider_version,authConfigKey:s.auth_config_key,environment:s.environment,organizationId:s.organization_id,secureId:s.account_id,projectSecureId:s.project_id,credentials:s.credentials}}catch(r){i.stop(),e.w.error(`Failed to fetch account ${e.C(t)} information: ${r.message}`),e.w.log(`Please ensure that the API at ${e.T(n)} is reachable and the API key is valid`),process.exit(1)}};#u=t=>{let n=t;try{n=m.default.readFileSync(t,`utf-8`)}catch{}try{return Cn.parse(JSON.parse(n))}catch(t){let n=[];try{n=JSON.parse(t.message)}catch{}e.w.error(`Failed to parse credentials`),e.y(n,!1),n.length===0&&e.w.log(t.message),process.exit(1)}};#d=(t,n)=>{let r=t;try{r=m.default.readFileSync(t,`utf-8`)}catch{}try{return wn.parse(JSON.parse(r))}catch(t){let r=[];try{r=JSON.parse(t.message)}catch{}e.w.error(`Invalid parameters for action ${e.C(n)}.`),e.y(r,!1),r.length===0&&e.w.log(t.message),process.exit(1)}};async#f({connector:t,actionId:n,account:r,pathParams:a={},queryParams:o={},body:s={},headers:c={}}){try{let l=await(0,T.runAction)({mode:`action_id`,actionId:n,account:r,connector:t,pathParams:a,queryParams:o,body:s,headers:c,getHttpClient:async()=>new O.HttpClient});if(l.response?.successful){let e={...this.#p(o,l.steps),...(0,C.isObject)(l.outputs)?l.outputs:{data:l.outputs}};return{statusCode:l.response?.statusCode,output:e}}else{let r=l.response?.message??`An error occurred while processing the request`;e.w.error(`Action ID ${e.C(n)} from connector ${e.C(t.key)}@${e.C(t.version)} failed with status ${l.response?.statusCode}: ${r}`);let a={...this.#p(o,l.steps)};Object.keys(a).length>0&&(e.w.log(`${i.default.yellow.inverse(` EXECUTION DETAILS `)}`),e.b(a)),process.exit(1)}}catch(e){this.#m(e)}}#p(e,t){return e?.debug===`true`?{debug:{steps:t}}:{}}#m(t){let n=t;switch((0,C.isMissing)(n.errorType)&&(e.w.error(`An unknown error occurred`),e.w.log(`${t instanceof Error?t.message:String(t)}`),process.exit(1)),n.errorType){case`MISSING_ACTION_ERROR`:e.w.error(`The specified action was not found: ${n.message}`);break;case`INVALID_ACTION_INPUTS_ERROR`:let t=n;e.w.error(`Invalid action inputs`),e.y(t.validationErrors,!1);break;case`INVALID_CURSOR_ERROR`:e.w.error(`Invalid cursor: ${n.message}`);break;default:e.w.error(`An error occurred: ${n.message}`)}process.exit(1)}};const Dn=(0,k.promisify)(f.exec);var On=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=(0,v.default)(),this.currentVersion=q()}async execute(t={}){this.spinner.text=`Checking for updates...`,this.spinner.start();try{let n=await this.getLatestVersion();this.spinner.stop(),n||(e.w.error(`Failed to check for updates`),process.exit(1)),this.isNewerVersion(n,this.currentVersion)?(e.w.box(`New version available: ${i.default.yellow(this.currentVersion)} → ${i.default.green(n)}`),await this.performUpdate(n)):t.force?(e.w.warn(`No updates available, but forcing reinstall...`),await this.performUpdate(n)):e.w.success(`You are already on the latest version (${this.currentVersion})`),process.exit(0)}catch(t){this.spinner.stop(),e.w.error(`Error while trying to update StackOne CLI: ${t?.message??`Unknown error`}`),process.exit(1)}}async getLatestVersion(){try{let{stdout:e}=await Dn(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return D.default.gt(e,t)}async performUpdate(t){this.spinner.text=`Updating to latest version (${e.C(t)})...`,this.spinner.start();let n=`npm install -g ${this.packageName}@latest`;try{await Dn(n,{encoding:`utf-8`}),this.spinner.stop(),e.w.success(`StackOne CLI updated successfully to latest version (${e.C(t)})`)}catch{throw this.spinner.stop(),Error(`Failed to install update. Please try manually: ${n}`)}}};const kn=e=>e===null?!0:Object.values(e).some(e=>e!==null),An=()=>{e.w.log(`${i.default.gray.inverse(` CONNECTORS VALIDATION `)} ${i.default.yellow.inverse(` WATCH MODE `)}\n`)};var jn=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,a=(0,v.default)(`Watching for file changes... ${i.default.gray(`(press "q" to quit)`)}`);if(!r)return;let o=(0,h.resolve)(r);try{await(0,A.stat)(o)}catch{e.w.error(`The specified path does not exist: ${o}\n`),process.exit(1)}if(n){e.v();let t={},{watch:n}=await import(`chokidar`),r=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{l.close(),a.stop(),r.close(),e.w.log(i.default.grey(`
175
+ Exiting watch mode...`)),process.exit(0)};An(),e.w.start(`Validating connectors...`);let c=await Fn(o);t=Mn(t,c||{}),Nn(t,o),a.start();let l=n(o,{persistent:!0,ignoreInitial:!0}),u=async n=>{if(!n.endsWith(`.s1.yaml`)&&!n.endsWith(`s1.partial.yaml`))return;let r=n.endsWith(`s1.partial.yaml`)?await Ln(n):[n];if(!(!r||r.length===0)){e.v(),a.stop(),An(),e.w.log(i.default.gray(`File change detected: ${n}`)),e.w.start(`Validating connectors...`);for(let e of r){let n=await Fn(e);t=Mn(t,n||{})}Nn(t,o),a.start()}};l.on(`change`,async e=>await u(e)),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else{let t=await Fn(o,e.w);process.exit(kn(t)?1:0)}}};const Mn=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Nn=(t,n)=>{e.v(),An();let r=0,a=0;for(let[n,i]of Object.entries(t))i===null?r++:(e.w?.error(`Connector ${e.C(n)} is not valid`),e.y(i,!0),a++);e.w.log(``),e.w.log(i.default.blue.inverse(` Validation Summary `)),e.w.log(`Connectors path: ${e.C(n)}`),e.w.log(`${r===0?i.default.red(`0`):i.default.green(r)} valid, ${a===0?i.default.green(`0`):i.default.red(a)} invalid connectors\n`)},Pn=async e=>{let t=[],n=await(0,A.readdir)(e);for(let r of n){let n=(0,h.join)(e,r),i=await(0,A.stat)(n);i.isDirectory()?t.push(...await Pn(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Fn=async(t,n)=>{let r=await(0,A.stat)(t),a={};if(r.isDirectory()){let r=await Pn(t);if(r.length===0)return n?.error(`No StackOne connector found in ${e.S(t)}`),n?.log(`Connector files need to have the extension ${e.C(`*.s1.yaml`)}`),null;let o=0,s=0;for(let e of r){let t=await In(e,n);t===null?o++:(n?.log(``),s++),a[e]=t}return n?.log(``),n?.log(i.default.blue.inverse(` Validation Summary `)),n?.log(`${o===0?i.default.red(`0`):i.default.green(o)} valid, ${s===0?i.default.green(`0`):i.default.red(s)} invalid connectors`),a}else if(r.isFile()&&t.endsWith(`s1.yaml`))return a[t]=await In(t,n),a;else if(r.isFile()&&t.endsWith(`partial.yaml`)){n?.error(`Partial connector files cannot be validated directly`),n?.log(`The file ${e.S(t)} is a partial connector file.`);let r=await Ln(t);return r&&r?.length>0&&n?.log(`Did you mean ${e.C(r[0])}?`),null}else return n?.error(`No StackOne connector found in ${e.S(t)}`),n?.log(`Connector files need to have the extension ${e.C(`*.s1.yaml`)}`),null},In=async(t,n)=>{let r=(0,T.validateYamlConnector)((0,T.loadConnector)(t)),i=r?.errors??[];if(r.success){let r=t.split(`/`).pop()||t;return n?.success(`Connector ${e.C(r)} is valid!`),null}else if(i.length>0)return n?.error(`Connector ${e.C(t)} is not valid`),n&&e.y(i,!0),i;else return n?.error(`Connector ${e.C(t)} is not valid. Please check the file for errors`),[]},Ln=async e=>{let t=(0,h.dirname)(e);try{return(await(0,A.readdir)(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>(0,h.join)(t,e))}catch{}},Rn=`https://ai-telemetry.stackone.com`,zn=`https://ai-telemetry.stackone-dev.com`;function Bn(e){if(!e)return!1;try{let{hostname:t}=new URL(e);return t===`stackone-dev.com`||t.endsWith(`.stackone-dev.com`)}catch{return!1}}function Vn(){return process.env.AI_TELEMETRY_URL?process.env.AI_TELEMETRY_URL:[process.env.AUTH_SERVER_URL,process.env.STACKONE_API_URL].some(Bn)?`https://ai-telemetry.stackone-dev.com`:`https://ai-telemetry.stackone.com`}function Hn(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(process.env.AI_TELEMETRY_URL=Vn(),e)try{(0,o.initAgentTelemetry)({apiKey:e,projectName:t}),process.env.VERBOSE&&console.log(`[Telemetry] Initialized for project:`,t)}catch(e){process.env.VERBOSE&&console.error(`[Telemetry] Failed to initialize:`,e)}}const Un=`@stackone/cli`,Wn=2880*60*1e3,Gn=(0,l.join)((0,c.homedir)(),`.stackone`),Kn=(0,l.join)(Gn,`version-check.json`),qn=(e=!1)=>{let t=Zn(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=Jn();e&&Yn(e)&&Xn(e),Qn({lastCheckTime:n})}},Jn=()=>{try{return(0,f.execSync)(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},Yn=e=>{try{let t=q();return D.default.gt(e,t)}catch{return!1}},Xn=t=>{let n=q(),r=`Update available: ${i.default.dim(n)} → ${i.default.green(t)}`,a=`\n\nRun ${i.default.cyan(`stackone update`)} to update`;e.w.box(r,a)},Zn=()=>{try{if(!(0,s.existsSync)(Kn))return null;let e=(0,s.readFileSync)(Kn,`utf-8`);return JSON.parse(e)}catch{return null}},Qn=e=>{try{(0,s.existsSync)(Gn)||(0,s.mkdirSync)(Gn,{recursive:!0}),(0,s.writeFileSync)(Kn,JSON.stringify(e,null,2),`utf-8`)}catch{}};var $n=class{constructor(e=new a.Command,t=q()){this.program=e,this.version=t,Hn(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let t=new un,n=new _n,r=new hn,o=new tn,s=new on,c=new jn,l=new Je,u=new Ut,d=new Me,f=new je,p=new Xe,m=new Wt,h=new qt,g=new En,_=new On;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(i.default.red(e))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(e=>{t.execute({environment:e.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`--force`,`Force push the connector, bypassing version conflict checks`).addArgument(new a.Argument(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{n.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey,force:t.force})}),this.program.command(`drop`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new a.Argument(`<connector>`,`Connector identifier in format provider_key@version`)).description(`Drop a connector from the StackOne registry`).action((e,t)=>{o.execute({profile:t.profile,connector:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`get`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key (defaults to latest)`).option(`--account-id <account-id>`,`Account ID to fetch connector from`).option(`-f, --format <format>`,`Output format: yaml or json (default: yaml)`,`yaml`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Get a connector from the StackOne registry`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),s.execute({profile:t.profile,connector:t.connector,accountId:t.accountId,format:t.format,outputFile:t.outputFile,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})}),this.program.command(`pull`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output <path>`,`Output directory for the connectors files (default: ./connectors)`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Pull a connector configuration from StackOne registry to local filesystem`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),r.execute({profile:t.profile,connector:t.connector,outputPath:t.output,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new a.Argument(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{c.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`run`).option(`--connector <connector>`,`Connector file, inline YAML, or identifier (provider_key@version or provider_key for latest)`).option(`--action <action>`,`Action to execute on the connector (path to file or inline string action code)`).option(`--action-id <action-id>`,`Action ID to execute on the connector`).option(`--account <account>`,`Account details to use for running the connector (path to file or inline string account data)`).option(`--account-id <account-id>`,`Account ID to use for running the connector against (fetches connector from API if --connector not provided)`).option(`--params <params>`,`Action parameters (path to file or inline string with JSON parameters)`).option(`--credentials <credentials>`,`Credentials to use (path to file or inline string with JSON credentials)`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`-d, --debug`,`Enables debug mode to include more details in the action execution output`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Run a connector action`).action(t=>{[t.builtin,t.custom,t.owner].filter(Boolean).length>1&&(e.w.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),g.execute({connector:t.connector,action:t.action,actionId:t.actionId,account:t.account,accountId:t.accountId,params:t.params,credentials:t.credentials,profile:t.profile,outputFile:t.outputFile,debug:t.debug,apiUrl:t.apiUrl,apiKey:t.apiKey,owner:t.builtin?`builtin`:t.custom?`custom`:t.owner})});let v=this.program.command(`agent`).description(`StackOne agent commands`);v.command(`setup`).option(`-g, --global`,`Global only: auth + MCP server (no connector skills/guide)`).option(`-l, --local`,`Local: auth + .mcp.json + connector skills (.claude/) and guide (CLAUDE.md)`).option(`--path <dir>`,`Target project path for local setup (defaults to the current directory)`).option(`--legacy`,`Use email/password login instead of browser-based auth`).option(`--email <email>`,`Email for legacy login (or set STACKONE_EMAIL); requires --legacy`).option(`--password <password>`,`Password for legacy login (or set STACKONE_PASSWORD); requires --legacy. Prefer --password-stdin`).option(`--password-stdin`,`Read password for legacy login from stdin; requires --legacy`).description(`Set up the StackOne agent — prompts for global vs local when neither flag is given`).action(async t=>{t.global&&t.local&&(e.w.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1));let n=t.email!==void 0,r=t.password!==void 0,a=t.passwordStdin===!0;r&&a&&(e.w.error(`--password and --password-stdin are mutually exclusive. Please provide only one.`),process.exit(1));let o=n||r||a;o&&!t.legacy&&(e.w.error(`--email, --password, and --password-stdin require --legacy.`),process.exit(1)),n&&t.email.trim()===``&&(e.w.error(`--email cannot be empty.`),process.exit(1)),r&&t.password===``&&(e.w.error(`--password cannot be empty.`),process.exit(1)),a&&(n||process.env.STACKONE_EMAIL?.trim()||(e.w.error(`--password-stdin requires --email or STACKONE_EMAIL (stdin is consumed for the password, so email cannot be prompted).`),process.exit(1)));let s={email:t.email,password:t.password,passwordFromStdin:a},c=!!process.stdin.isTTY;if(c&&!t.legacy&&!o){let e=await Ht({initialMode:t.global?`global`:t.local?`local`:null,pathFlag:t.path});process.exit(e.status===`error`?1:0)}let d=c&&!o;!t.global&&!t.local&&!d&&e.w.log(i.default.dim(`No interactive terminal detected — defaulting to global setup. Run in a terminal for the prompt, or pass --local (with --path) / --global.`));let f=et(t.global,t.local,d);if(f===null&&(f=await zt()),f===`local`){let e=tt(t.path,d);e===null&&(e=await Vt(process.cwd())),await u.execute({legacy:!!t.legacy,credentials:s,targetPath:e})}else await l.execute({legacy:!!t.legacy,credentials:s})}),v.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{d.execute()}),v.command(`run`).description(`Run the agent once with a prompt (non-interactive)`).argument(`<prompt>`,`What to do`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`--max-turns <n>`,`Max agent turns`,`25`).option(`-v, --verbose`,`Verbose output`).action(async(t,n)=>{let r=[`build`,`test`,`research`],a=n.mode??`build`;r.includes(a)||(e.w.error(`${i.default.red(`Invalid mode:`)} ${i.default.white(a)}. Valid modes are: ${r.join(`, `)}.`),process.exit(1));let o=n.maxTurns?parseInt(String(n.maxTurns),10):void 0;await p.execute({prompt:String(t),mode:a,maxTurns:o!==void 0&&!isNaN(o)?o:void 0,verbose:n.verbose})}),v.command(`skills`).description(`List available agent skills and optional recommendations by mode`).option(`-m, --mode <mode>`,`Show skills recommended for this mode`).action(async e=>{await m.execute({mode:e.mode})}),v.command(`sync`).description(`Sync the connector-building skills + guide into this project (.claude/ + CLAUDE.md)`).option(`--check`,`Report drift and exit non-zero instead of writing (CI guard)`).option(`--plugin-dir <path>`,`Override the agent-harness plugin dir (e.g. point at a checkout in CI/benchmarks)`).action(async e=>{await h.execute({check:!!e.check,pluginDir:e.pluginDir})}),v.command(`chat`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`-c, --connector <name>`,`Connector name`).option(`-a, --action <name>`,`Action name`).option(`-g, --goal <goal>`,`Initial goal/message`).option(`-t, --temperature <number>`,`Temperature (0-1, default: 0.5)`,parseFloat).option(`-v, --verbose`,`Enable verbose logging`).description(`Start an interactive chat session with the agent (use /commands in chat)`).action(async t=>{let n=[`build`,`test`,`research`];t.mode&&!n.includes(t.mode)&&(e.w.error(`❌ Error: Invalid mode "${t.mode}". Must be one of: ${n.join(`, `)}`),process.exit(1)),t.temperature!==void 0&&(isNaN(t.temperature)&&(e.w.error(`❌ Error: Temperature must be a valid number`),process.exit(1)),(t.temperature<0||t.temperature>1)&&(e.w.error(`❌ Error: Temperature must be between 0 and 1`),process.exit(1))),f.execute({mode:t.mode,connector:t.connector,action:t.action,goal:t.goal,temperature:t.temperature,verbose:t.verbose})}),this.program.command(`update`).option(`-f, --force`,`Force reinstall even if already on latest version`).description(`Update the CLI to the latest version`).action(e=>{_.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{e.w.log(`${i.default.inverse.greenBright(`StackOne`)} ${i.default.grey(`CLI`)} ${i.default.whiteBright(this.version)}`),qn(!0),process.exit(0)})}run(){process.argv.includes(`version`)||qn(),this.program.parse(process.argv)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return $n}});
@@ -171,5 +171,5 @@ Available skills
171
171
  `).filter(e=>e!==``);if(e.added){i+=t.length;for(let e of t)y.log(T.green(`+ ${e}`))}else if(e.removed){a+=t.length;for(let e of t)y.log(T.red(`- ${e}`))}else if(t.length<=6)for(let e of t)y.log(T.gray(` ${e}`));else{for(let e=0;e<3;e++)y.log(T.gray(` ${t[e]}`));y.log(T.gray(` ... (${t.length-6} unchanged lines)`));for(let e=t.length-3;e<t.length;e++)y.log(T.gray(` ${t[e]}`))}}y.log(``),y.log(T.gray(`Summary: ${T.green(`+${i}`)} additions, ${T.red(`-${a}`)} deletions`))}#o(e,t){return et(e,t).some(e=>e.added||e.removed)}async#s(e,t,n,r,i){y.log(``);let a=await Ye({message:`How would you like to resolve the differences?`,options:[{value:`override`,label:`Override local with remote`,hint:`Replace your local file with the StackOne version`},{value:`keep-local`,label:`Keep local version`,hint:`Cancel the pull and keep your current file`},{value:`interactive`,label:`Resolve conflicts interactively`,hint:`Choose which changes to accept one by one`},{value:`cancel`,label:`Cancel`,hint:`Abort the pull operation`}]});if(Ke(a))return{action:`cancel`};if(a===`override`)return{action:`override`};if(a===`keep-local`)return{action:`keep-local`};if(a===`interactive`){let a=await this.#c(e,t,n,r,i);return a===null?{action:`interactive-cancel`}:{action:`interactive`,resolvedContent:a}}return{action:`cancel`}}async#c(e,t,n,r,i){let a=et(e,t),o=this.#u(a);if(o.length===0)return y.info(`No conflicts to resolve.`),t;let s=new jr(o,n,r,i);for(;;){if((await s.resolve()).cancelled)return null;let e=s.getResolvedContent(),t=$e(e);if(t.success)return s.renderFinalSummary(),e;let n=await this.#l(t.errors);if(n===`cancel`)return v(),y.info(`Operation cancelled. No changes were made to the local connector.`),null;if(n===`save`)return v(),y.warn(`The connector was saved but it is invalid`),e;s.resetForReResolution()}}async#l(e){let{createInterface:t}=await import(`readline`);return new Promise(n=>{v();let r=(e||[{message:`Unknown validation error`}]).map(e=>` • ${e.message}`).join(`
172
172
  `);y.box({title:`⚠️ Validation Failed`,message:`The resolved connector configuration is invalid:\n\n${r}`,style:{borderColor:`yellow`,padding:1}}),y.log(``),y.log(T.bold(` Choose an action:`)),y.log(``),y.log(T.cyan(` [B]`)+` ← Go back to conflict resolution`),y.log(T.dim(` Modify your choices to fix the validation errors`)),y.log(``),y.log(T.yellow(` [S]`)+` 💾 Save anyway`),y.log(T.dim(` Save the invalid configuration (not recommended)`)),y.log(``),y.log(T.red(` [C]`)+` ✖ Cancel`),y.log(T.dim(` Discard all changes`)),y.log(``);let i=t({input:process.stdin,output:process.stdout});process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume();let a=e=>{let t=e.toString().toLowerCase(),r=()=>{process.stdin.removeListener(`data`,a),process.stdin.isTTY&&process.stdin.setRawMode(!1),i.close()};if(t===``||t===`\x1B`){r(),n(`cancel`);return}switch(t){case`b`:r(),n(`back`);break;case`s`:r(),n(`save`);break;case`c`:case`q`:r(),n(`cancel`);break}};process.stdin.on(`data`,a)})}#u(e){let t=[],n=0;for(;n<e.length;){let r=e[n];if(!r.added&&!r.removed)t.push({type:`unchanged`,content:r.value}),n++;else if(r.removed){let i=e[n+1];i?.added?(t.push({type:`conflict`,local:r.value,remote:i.value}),n+=2):(t.push({type:`conflict`,local:r.value,remote:void 0}),n++)}else r.added&&t.push({type:`conflict`,local:void 0,remote:r.value}),n++}return t}async#d(e,n){let r=je.dirname(e);K.existsSync(r)||K.mkdirSync(r,{recursive:!0});try{K.writeFileSync(e,n,`utf-8`)}catch(n){y.error(`Failed to write connector to file ${t(e)}: ${n.message}`),process.exit(1)}}async#f(e,n,i,a,o){let s=J(`Pulling connector ${t(e)}@${t(a)} from registry...`).start();try{let r=Buffer.from(i).toString(`base64`),c=`${n}/registry/connectors/${e}@${a}${o?`?owner=${encodeURIComponent(o)}`:``}`,l=await fetch(c,{method:`GET`,headers:{Authorization:`Basic ${r}`}});if(s.stop(),l.status===409){o&&(await this.#p(l,e,a),process.exit(1));let i=(await l.json()).availableOwners??[],c=await Er(`${e}@${a}`,i);s.text=`Pulling connector ${t(e)}@${t(a)} from registry...`,s.start();let u=`${n}/registry/connectors/${e}@${a}`,d=await fetch(`${u}?owner=${encodeURIComponent(c)}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});return s.stop(),d.ok||(await this.#p(d,e,a),process.exit(1)),await d.text()}return l.ok||(await this.#p(l,e,a),process.exit(1)),await l.text()}catch(i){s.stop(),y.error(`Failed to pull connector ${t(e)}@${t(a)} from the registry: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid.`),process.exit(1)}}async#p(e,n,r){switch(e.status){case 401:case 403:y.error(`Access denied`),y.log(`Please ensure that your API key is valid and has the ${t(`connectors:read`)} scope required to pull connectors.`);break;case 404:y.error(`Connector ${t(n)}@${t(r)} was not found in the registry`),await this.#m(n);break;case 429:y.error(`Rate limit exceeded`),y.log(`Too many requests. Please wait a moment before trying again.`);break;default:await b(e,`Failed to pull connector ${t(n)}`)}}async#m(e){y.info(`To see available versions, check the connector documentation or contact support.`)}};const Pr=`https://api.stackone.com`;var Fr=class{async execute({profile:e,fileOrDir:n,apiUrl:r,apiKey:i,force:a}={}){if(!e&&!i&&(y.error(`Profile or API key is required`),y.log(`Please provide a profile using the ${t(`--profile`)} option or an API key using the ${t(`--api-key`)} option.`),y.log(`To create a profile, run ${t(`stackone init`)}.`),process.exit(1)),e&&i&&(y.error(`Please provide either a profile or an API key, not both`),process.exit(1)),e&&r&&y.warn(`Specifying ${t(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),e&&!br(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=Sr();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${T.blue(e)}`)})),process.exit(1)}let o=e?yr(e):{apiUrl:r??Pr,apiKey:i};o?.apiKey||(y.error(`API key is missing`),y.log(`Please provide a valid API key in the profile or via the ${t(`--api-key`)} option.`),process.exit(1)),n||(y.error(`File or directory is required.`),process.exit(1));try{q(n)}catch{y.error(`File or directory not found: ${T.red(n)}`),process.exit(1)}let s=q(n),c=o.apiUrl??Pr;if(s.isDirectory()){let e=zr(n),t=0;e.length===0?(y.error(`No .s1.yaml connector files found in the directory: ${n}.`),process.exit(1)):(y.start(`Found ${e.length} connector(s) file(s). Pushing to registry...`),y.log(``));for(let n of e)await this.uploadFile(n,c,o.apiKey,a)&&t++;t===0?y.error(`Error while pushing connectors: no files were uploaded`):(y.log(``),y.info(`Upload completed: ${T.green(t)} of ${T.blue(e.length)} file(s) uploaded successfully.`)),process.exit(t>0?0:1)}else n.endsWith(`.s1.yaml`)||(y.error(`Only ${t(`.s1.yaml`)} files are supported for upload`),process.exit(1));let l=await this.uploadFile(n,c,o.apiKey,a);process.exit(l?0:1)}async uploadFile(e,n,i,a){let o=J(`📤 Pushing connector in ${Me(e)}...`).start();try{let r=Rr(e);if(!r)return!1;let s=Me(e),c=new FormData,l=new Blob([r],{type:`application/x-yaml`});c.append(`file`,l,s),a&&c.append(`force`,`true`);let u=Buffer.from(i).toString(`base64`),d=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${u}`},body:c});if(o.stop(),!d.ok)return d.status===409||d.status===422?await this.handleVersionConflict(d,e,n,i,a):(await b(d,`Failed to push connector in ${t(s)} to the registry`),!1);let f=await d.json();return y.success(`Successfully uploaded ${t(s)} with connector ${t(f.provider)}@${t(f.version)}`),!0}catch(i){return o.stop(),y.error(`Failed to upload file ${t(e)}: ${i}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),!1}}async handleVersionConflict(e,n,r,i,a){let o=await e.text(),s;try{s=JSON.parse(o)}catch{}let c=nt.valid(s?.latestVersion);if(!c)return await b(new Response(o,{status:e.status,statusText:e.statusText}),`Failed to push connector in ${t(Me(n))} to the registry`),!1;let l=Oe(n,`utf-8`),u=Ir(l),d=u?`${t(u)}`:``,f=e.status===409?`Version ${d} already exists in the registry. Latest version: ${t(c)}`:`Version ${d} is lower than the latest version in the registry. Latest version: ${t(c)}`;y.error(f);let p=nt.inc(c,`patch`)??c,m=nt.inc(c,`minor`)??c,h=nt.inc(c,`major`)??c,g=await Ye({message:`How would you like to proceed?`,options:[{value:p,label:`Bump patch version (${p})`},{value:m,label:`Bump minor version (${m})`},{value:h,label:`Bump major version (${h})`},{value:`cancel`,label:`Cancel push`}]});return Ke(g)||g===`cancel`?(Ue(`Push cancelled`),!1):(Ae(n,Lr(l,g),`utf-8`),y.info(`Updated version to ${t(g)} in ${Me(n)}`),this.uploadFile(n,r,i,a))}};const Ir=e=>e.match(/^\s*version: (\S+)/m)?.[1],Lr=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),Rr=e=>{let t=Ze(e),r=$e(t),i=r?.errors??[];if(r.success)return t;i.length>0?(y.error(`Connector in ${n(e)} is not valid`),x(i,!0)):y.error(`Connector in ${n(e)} is not valid. Please check the file for errors.`)},zr=e=>{let t=[],n=ke(e,{withFileTypes:!0});for(let r of n){let n=Pe(e,r.name);r.isDirectory()?t.push(...zr(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},Br=Z.object({provider_key:Z.string().optional(),provider_version:Z.string().optional(),auth_config_key:Z.string(),environment:Z.string().default(`production`),organization_id:Z.string().default(`cli-organization-id`),account_id:Z.string().default(`cli-account-secure-id`),project_id:Z.string().default(`cli-project-secure-id`),credentials:Z.record(Z.string(),Z.any()).default({})}),Vr=Z.record(Z.string(),Z.any()),Hr=Z.object({path:Z.record(Z.string(),Z.any()).default({}),queryParams:Z.record(Z.string(),Z.any()).default({}),header:Z.record(Z.string(),Z.any()).default({}),body:Z.record(Z.string(),Z.any()).default({})}),Ur=`https://api.stackone.com`;var Wr=class{async execute({connector:e,action:n,actionId:r,account:i,accountId:a,params:s,credentials:c,profile:l,outputFile:u,debug:d,apiUrl:f,apiKey:p,owner:m}={}){if(!l&&!p&&a&&(y.error(`Profile or API key is required when providing an account ID`),y.log(`Please provide a profile using the ${t(`--profile`)} option or an API key using the ${t(`--api-key`)} option.`),y.log(`To create a profile, run ${t(`stackone init`)}.`),process.exit(1)),l&&p&&(y.error(`Please provide either a profile or an API key, not both`),process.exit(1)),l&&f&&y.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),l&&!br(l)){y.error(`Configuration profile ${t(l)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let e=Sr();e.length>0&&(y.info(`Available configuration profiles:`),e.forEach(e=>{y.log(` - ${T.blue(e)}`)})),process.exit(1)}let h=l?yr(l):{apiUrl:f??Ur,apiKey:p};Y(i)&&Y(a)&&(y.error(`A valid account or account ID is required to run an action`),process.exit(1));let g;if(X(e))if(this.#a(e)){!l&&!p&&(y.error(`Profile or API key is required when using a connector identifier`),y.log(`Please provide a profile using the ${t(`--profile`)} option or an API key using the ${t(`--api-key`)} option.`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.`),process.exit(1));let n=this.#o(e);g=await this.#s(n,h?.apiUrl??Ur,h?.apiKey,m)}else g=this.#e(e);else X(a)&&(g=await this.#c(a,h?.apiUrl??Ur,h?.apiKey));let _=X(n)?this.#r(n,e):g;Y(_)&&(y.error(`A valid connector is required to run an action.`),process.exit(1));let ee=X(_?.actions)?Object.keys(_?.actions).length:0,v=X(_?.actions)?Object.keys(_.actions)[ee-1]:void 0,b=X(v)?_?.actions?.[v]?.id:void 0,x=(X(r)&&!r?.startsWith(`${_.key}_`)?`${_.key}_${r}`:r)??b;Y(x)&&(y.error(`A valid action ID is required to run an action`),process.exit(1));let S=X(a)?await this.#l(a,h?.apiUrl??Ur,h?.apiKey):{},C=X(i)?this.#i(i,_.key??`unknown`,_.version??`unknown`):void 0,te=X(c)?this.#u(c):{},w={...S,...C,credentials:{...S.credentials??{},...te}};Y(w)&&(y.error(`A valid account data is required to run an action.`),process.exit(1));let E=_.actions?.[x];Y(E)&&(y.error(`Action ID ${t(x)} not found in the connector ${t(_.key)}@${t(_.version)}.`),process.exit(1));let ne=X(s)?this.#d(s,x):{path:{},queryParams:{},header:{},body:{}},D=Date.now(),re=await this.#f({connector:_,actionId:x,account:w,queryParams:{...ne.queryParams,...d?{debug:`true`}:{}},pathParams:ne.path,body:ne.body,headers:ne.header}),ie=Date.now()-D;if(X(u))try{K.writeFileSync(u,JSON.stringify(re.output,null,2),`utf-8`),y.info(`Output written to file: ${u}`)}catch(e){y.error(`Failed to write output to file ${u}: ${e.message}`),process.exit(1)}else y.log(`\n${T.blue.inverse(` ACTION OUTPUT `)}`),o(re.output);y.log(``),y.info(`Action ${t(x)} from connector ${t(_?.key)}@${t(_?.version)} finished in ${T.yellowBright((ie/1e3).toFixed(2))} seconds.`),process.exit(0)}#e=e=>{let t=e;try{t=Ze(e)}catch{}return t?this.#n(t):void 0};#t=e=>{try{return Ze(e)}catch(n){y.error(`Failed to load connector file from ${t(e)}: ${n.message}`),process.exit(1)}};#n=e=>{let t=$e(e),n=t?.errors??[];if(t.success)return t.connector||(y.error(`Failed to load connector.`),process.exit(1)),t.connector;n.length>0?(y.error(`Connector is not valid`),x(n,!0),process.exit(1)):(y.error(`Connector is not valid. Please check the file for errors.`),process.exit(1))};#r=(e,t)=>{let n=e;try{n=K.readFileSync(e,`utf-8`)}catch{}Y(t)&&(y.error(`A valid connector is required to load an action.`),process.exit(1));let r=`${this.#t(t)} - ${n.split(`
173
173
  `).map((e,t)=>t===0?e:` ${e}`).join(`
174
- `)}`;return this.#n(r)};#i=(e,t,n)=>{let r=e;try{r=K.readFileSync(e,`utf-8`)}catch{}try{let e=Br.parse(JSON.parse(r));return{providerKey:t,providerVersion:n,authConfigKey:e.auth_config_key,environment:e.environment,organizationId:e.organization_id,secureId:e.account_id,projectSecureId:e.project_id}}catch(e){let t=[];try{t=JSON.parse(e.message)}catch{}y.error(`Failed to parse account information`),x(t,!1),t.length===0&&y.log(e.message),process.exit(1)}};#a=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#o=e=>e.includes(`@`)?e:`${e}@latest`;#s=async(e,n,i,a)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Connector identifier, API URL, and API key are required to fetch connector from registry.`),process.exit(1));let o=J();try{o.text=`Fetching connector ${t(e)} from registry...`,o.start();let r=Buffer.from(i).toString(`base64`),s=a?`?owner=${encodeURIComponent(a)}`:``,c=await fetch(`${n}/registry/connectors/${e}${s}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});if(o.stop(),c.status===409){a&&(await b(c,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let i=await Er(e,(await c.json()).availableOwners??[]);o.text=`Fetching connector ${t(e)} from registry...`,o.start();let s=await fetch(`${n}/registry/connectors/${e}?owner=${encodeURIComponent(i)}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});o.stop(),s.ok||(await b(s,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let l=await s.text(),u=this.#n(l);return y.success(`Fetched connector ${t(u.key)}@${t(u.version)} from registry`),u}c.ok||(await b(c,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let l=await c.text(),u=this.#n(l);return y.success(`Fetched connector ${t(u.key)}@${t(u.version)} from registry`),u}catch(i){o.stop(),y.error(`Failed to fetch connector ${t(e)} from registry: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#c=async(e,n,i)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Account ID, API URL, and API key are required to fetch connector`),process.exit(1));let a=J();try{a.text=`Fetching connector for account ${t(e)} from API...`,a.start();let r=Buffer.from(i).toString(`base64`),o=await fetch(`${n}/accounts/${e}/connector`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});a.stop(),o.ok||(await b(o,`Failed to fetch connector`),process.exit(1));let s=await o.text(),c=this.#n(s);return y.success(`Fetched connector ${t(c.key)}@${t(c.version)} for account ${t(e)}`),c}catch(e){a.stop(),y.error(`Failed to fetch connector: ${e.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#l=async(e,n,i)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Account ID, API URL, and API key are required to fetch account information.`),process.exit(1));let a=J();try{a.text=`Fetching account ${t(e)} information from API...`,a.start();let r=Buffer.from(i).toString(`base64`),o=await fetch(`${n}/accounts/${e}/credentials`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});a.stop(),o.ok||(await b(o,`Failed to fetch account ${t(e)} information`),process.exit(1));let s=await o.json();return y.success(`Fetched account ${t(e)} information from project ${t(s.project_id)}`),{providerKey:s.provider_key,providerVersion:s.provider_version,authConfigKey:s.auth_config_key,environment:s.environment,organizationId:s.organization_id,secureId:s.account_id,projectSecureId:s.project_id,credentials:s.credentials}}catch(i){a.stop(),y.error(`Failed to fetch account ${t(e)} information: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#u=e=>{let t=e;try{t=K.readFileSync(e,`utf-8`)}catch{}try{return Vr.parse(JSON.parse(t))}catch(e){let t=[];try{t=JSON.parse(e.message)}catch{}y.error(`Failed to parse credentials`),x(t,!1),t.length===0&&y.log(e.message),process.exit(1)}};#d=(e,n)=>{let r=e;try{r=K.readFileSync(e,`utf-8`)}catch{}try{return Hr.parse(JSON.parse(r))}catch(e){let r=[];try{r=JSON.parse(e.message)}catch{}y.error(`Invalid parameters for action ${t(n)}.`),x(r,!1),r.length===0&&y.log(e.message),process.exit(1)}};async#f({connector:e,actionId:n,account:r,pathParams:i={},queryParams:a={},body:s={},headers:c={}}){try{let l=await Qe({mode:`action_id`,actionId:n,account:r,connector:e,pathParams:i,queryParams:a,body:s,headers:c,getHttpClient:async()=>new rt});if(l.response?.successful){let e={...this.#p(a,l.steps),...He(l.outputs)?l.outputs:{data:l.outputs}};return{statusCode:l.response?.statusCode,output:e}}else{let r=l.response?.message??`An error occurred while processing the request`;y.error(`Action ID ${t(n)} from connector ${t(e.key)}@${t(e.version)} failed with status ${l.response?.statusCode}: ${r}`);let i={...this.#p(a,l.steps)};Object.keys(i).length>0&&(y.log(`${T.yellow.inverse(` EXECUTION DETAILS `)}`),o(i)),process.exit(1)}}catch(e){this.#m(e)}}#p(e,t){return e?.debug===`true`?{debug:{steps:t}}:{}}#m(e){let t=e;switch(Y(t.errorType)&&(y.error(`An unknown error occurred`),y.log(`${e instanceof Error?e.message:String(e)}`),process.exit(1)),t.errorType){case`MISSING_ACTION_ERROR`:y.error(`The specified action was not found: ${t.message}`);break;case`INVALID_ACTION_INPUTS_ERROR`:let e=t;y.error(`Invalid action inputs`),x(e.validationErrors,!1);break;case`INVALID_CURSOR_ERROR`:y.error(`Invalid cursor: ${t.message}`);break;default:y.error(`An error occurred: ${t.message}`)}process.exit(1)}};const Gr=it(Ce);var Kr=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=J(),this.currentVersion=Wt()}async execute(e={}){this.spinner.text=`Checking for updates...`,this.spinner.start();try{let t=await this.getLatestVersion();this.spinner.stop(),t||(y.error(`Failed to check for updates`),process.exit(1)),this.isNewerVersion(t,this.currentVersion)?(y.box(`New version available: ${T.yellow(this.currentVersion)} → ${T.green(t)}`),await this.performUpdate(t)):e.force?(y.warn(`No updates available, but forcing reinstall...`),await this.performUpdate(t)):y.success(`You are already on the latest version (${this.currentVersion})`),process.exit(0)}catch(e){this.spinner.stop(),y.error(`Error while trying to update StackOne CLI: ${e?.message??`Unknown error`}`),process.exit(1)}}async getLatestVersion(){try{let{stdout:e}=await Gr(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return nt.gt(e,t)}async performUpdate(e){this.spinner.text=`Updating to latest version (${t(e)})...`,this.spinner.start();let n=`npm install -g ${this.packageName}@latest`;try{await Gr(n,{encoding:`utf-8`}),this.spinner.stop(),y.success(`StackOne CLI updated successfully to latest version (${t(e)})`)}catch{throw this.spinner.stop(),Error(`Failed to install update. Please try manually: ${n}`)}}};const qr=()=>{y.log(`${T.gray.inverse(` CONNECTORS VALIDATION `)} ${T.yellow.inverse(` WATCH MODE `)}\n`)};var Jr=class{async execute(e){let{watchMode:t,fileOrDir:n}=e,r=J(`Watching for file changes... ${T.gray(`(press "q" to quit)`)}`);if(!n)return;let i=Fe(n);try{await ot(i)}catch{y.error(`The specified path does not exist: ${i}\n`),process.exit(1)}if(t){v();let e={},{watch:t}=await import(`chokidar`),n=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let a=()=>{s.close(),r.stop(),n.close(),y.log(T.grey(`
175
- Exiting watch mode...`)),process.exit(0)};qr(),y.start(`Validating connectors...`);let o=await Qr(i);e=Yr(e,o||{}),Xr(e,i),r.start();let s=t(i,{persistent:!0,ignoreInitial:!0}),c=async t=>{if(!t.endsWith(`.s1.yaml`)&&!t.endsWith(`s1.partial.yaml`))return;let n=t.endsWith(`s1.partial.yaml`)?await ei(t):[t];if(!(!n||n.length===0)){v(),r.stop(),qr(),y.log(T.gray(`File change detected: ${t}`)),y.start(`Validating connectors...`);for(let t of n){let n=await Qr(t);e=Yr(e,n||{})}Xr(e,i),r.start()}};s.on(`change`,async e=>await c(e)),process.stdin.on(`data`,e=>{e.toString()===`q`&&a()}),process.on(`SIGINT`,()=>{a()})}else await Qr(i,y),process.exit(0)}};const Yr=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Xr=(e,n)=>{v(),qr();let r=0,i=0;for(let[n,a]of Object.entries(e))a===null?r++:(y?.error(`Connector ${t(n)} is not valid`),x(a,!0),i++);y.log(``),y.log(T.blue.inverse(` Validation Summary `)),y.log(`Connectors path: ${t(n)}`),y.log(`${r===0?T.red(`0`):T.green(r)} valid, ${i===0?T.green(`0`):T.red(i)} invalid connectors\n`)},Zr=async e=>{let t=[],n=await at(e);for(let r of n){let n=Pe(e,r),i=await ot(n);i.isDirectory()?t.push(...await Zr(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Qr=async(e,r)=>{let i=await ot(e),a={};if(i.isDirectory()){let i=await Zr(e);if(i.length===0)return r?.error(`No StackOne connector found in ${n(e)}`),r?.log(`Connector files need to have the extension ${t(`*.s1.yaml`)}`),null;let o=0,s=0;for(let e of i){let t=await $r(e,r);t===null?o++:(r?.log(``),s++),a[e]=t}return r?.log(``),r?.log(T.blue.inverse(` Validation Summary `)),r?.log(`${o===0?T.red(`0`):T.green(o)} valid, ${s===0?T.green(`0`):T.red(s)} invalid connectors`),a}else if(i.isFile()&&e.endsWith(`s1.yaml`))return a[e]=await $r(e,r),a;else if(i.isFile()&&e.endsWith(`partial.yaml`)){r?.error(`Partial connector files cannot be validated directly`),r?.log(`The file ${n(e)} is a partial connector file.`);let i=await ei(e);return i&&i?.length>0&&r?.log(`Did you mean ${t(i[0])}?`),null}else return r?.error(`No StackOne connector found in ${n(e)}`),r?.log(`Connector files need to have the extension ${t(`*.s1.yaml`)}`),null},$r=async(e,n)=>{let r=$e(Ze(e)),i=r?.errors??[];if(r.success){let r=e.split(`/`).pop()||e;return n?.success(`Connector ${t(r)} is valid!`),null}else if(i.length>0)return n?.error(`Connector ${t(e)} is not valid`),n&&x(i,!0),i;else return n?.error(`Connector ${t(e)} is not valid. Please check the file for errors`),[]},ei=async e=>{let t=Ne(e);try{return(await at(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>Pe(t,e))}catch{}};function ti(e){if(!e)return!1;try{let{hostname:t}=new URL(e);return t===`stackone-dev.com`||t.endsWith(`.stackone-dev.com`)}catch{return!1}}function ni(){return process.env.AI_TELEMETRY_URL?process.env.AI_TELEMETRY_URL:[process.env.AUTH_SERVER_URL,process.env.STACKONE_API_URL].some(ti)?`https://ai-telemetry.stackone-dev.com`:`https://ai-telemetry.stackone.com`}function ri(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(process.env.AI_TELEMETRY_URL=ni(),e)try{ce({apiKey:e,projectName:t}),process.env.VERBOSE&&console.log(`[Telemetry] Initialized for project:`,t)}catch(e){process.env.VERBOSE&&console.error(`[Telemetry] Failed to initialize:`,e)}}const ii=R(I(),`.stackone`),ai=R(ii,`version-check.json`),oi=(e=!1)=>{let t=ui(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=si();e&&ci(e)&&li(e),di({lastCheckTime:n})}},si=()=>{try{return Ee(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},ci=e=>{try{let t=Wt();return nt.gt(e,t)}catch{return!1}},li=e=>{let t=Wt(),n=`Update available: ${T.dim(t)} → ${T.green(e)}`,r=`\n\nRun ${T.cyan(`stackone update`)} to update`;y.box(n,r)},ui=()=>{try{if(!N(ai))return null;let e=de(ai,`utf-8`);return JSON.parse(e)}catch{return null}},di=e=>{try{N(ii)||ue(ii,{recursive:!0}),me(ai,JSON.stringify(e,null,2),`utf-8`)}catch{}};var fi=class{constructor(e=new ne,t=Wt()){this.program=e,this.version=t,ri(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new Ar,t=new Fr,n=new Nr,r=new wr,i=new Or,a=new Jr,o=new yn,s=new fr,c=new nn,l=new tn,u=new xn,d=new pr,f=new gr,p=new Wr,m=new Kr;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(T.red(e))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(t=>{e.execute({environment:t.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`--force`,`Force push the connector, bypassing version conflict checks`).addArgument(new E(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,n)=>{t.execute({profile:n.profile,fileOrDir:e,apiUrl:n.apiUrl,apiKey:n.apiKey,force:n.force})}),this.program.command(`drop`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new E(`<connector>`,`Connector identifier in format provider_key@version`)).description(`Drop a connector from the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,connector:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`get`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key (defaults to latest)`).option(`--account-id <account-id>`,`Account ID to fetch connector from`).option(`-f, --format <format>`,`Output format: yaml or json (default: yaml)`,`yaml`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Get a connector from the StackOne registry`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),i.execute({profile:e.profile,connector:e.connector,accountId:e.accountId,format:e.format,outputFile:e.outputFile,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})}),this.program.command(`pull`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output <path>`,`Output directory for the connectors files (default: ./connectors)`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Pull a connector configuration from StackOne registry to local filesystem`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),n.execute({profile:e.profile,connector:e.connector,outputPath:e.output,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new E(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{a.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`run`).option(`--connector <connector>`,`Connector file, inline YAML, or identifier (provider_key@version or provider_key for latest)`).option(`--action <action>`,`Action to execute on the connector (path to file or inline string action code)`).option(`--action-id <action-id>`,`Action ID to execute on the connector`).option(`--account <account>`,`Account details to use for running the connector (path to file or inline string account data)`).option(`--account-id <account-id>`,`Account ID to use for running the connector against (fetches connector from API if --connector not provided)`).option(`--params <params>`,`Action parameters (path to file or inline string with JSON parameters)`).option(`--credentials <credentials>`,`Credentials to use (path to file or inline string with JSON credentials)`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`-d, --debug`,`Enables debug mode to include more details in the action execution output`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Run a connector action`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),p.execute({connector:e.connector,action:e.action,actionId:e.actionId,account:e.account,accountId:e.accountId,params:e.params,credentials:e.credentials,profile:e.profile,outputFile:e.outputFile,debug:e.debug,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})});let h=this.program.command(`agent`).description(`StackOne agent commands`);h.command(`setup`).option(`-g, --global`,`Global only: auth + MCP server (no connector skills/guide)`).option(`-l, --local`,`Local: auth + .mcp.json + connector skills (.claude/) and guide (CLAUDE.md)`).option(`--path <dir>`,`Target project path for local setup (defaults to the current directory)`).option(`--legacy`,`Use email/password login instead of browser-based auth`).option(`--email <email>`,`Email for legacy login (or set STACKONE_EMAIL); requires --legacy`).option(`--password <password>`,`Password for legacy login (or set STACKONE_PASSWORD); requires --legacy. Prefer --password-stdin`).option(`--password-stdin`,`Read password for legacy login from stdin; requires --legacy`).description(`Set up the StackOne agent — prompts for global vs local when neither flag is given`).action(async e=>{e.global&&e.local&&(y.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1));let t=e.email!==void 0,n=e.password!==void 0,r=e.passwordStdin===!0;n&&r&&(y.error(`--password and --password-stdin are mutually exclusive. Please provide only one.`),process.exit(1));let i=t||n||r;i&&!e.legacy&&(y.error(`--email, --password, and --password-stdin require --legacy.`),process.exit(1)),t&&e.email.trim()===``&&(y.error(`--email cannot be empty.`),process.exit(1)),n&&e.password===``&&(y.error(`--password cannot be empty.`),process.exit(1)),r&&(t||process.env.STACKONE_EMAIL?.trim()||(y.error(`--password-stdin requires --email or STACKONE_EMAIL (stdin is consumed for the password, so email cannot be prompted).`),process.exit(1)));let a={email:e.email,password:e.password,passwordFromStdin:r},c=!!process.stdin.isTTY;if(c&&!e.legacy&&!i){let t=await dr({initialMode:e.global?`global`:e.local?`local`:null,pathFlag:e.path});process.exit(t.status===`error`?1:0)}let l=c&&!i;!e.global&&!e.local&&!l&&y.log(T.dim(`No interactive terminal detected — defaulting to global setup. Run in a terminal for the prompt, or pass --local (with --path) / --global.`));let u=Tn(e.global,e.local,l);if(u===null&&(u=await cr()),u===`local`){let t=En(e.path,l);t===null&&(t=await ur(process.cwd())),await s.execute({legacy:!!e.legacy,credentials:a,targetPath:t})}else await o.execute({legacy:!!e.legacy,credentials:a})}),h.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{c.execute()}),h.command(`run`).description(`Run the agent once with a prompt (non-interactive)`).argument(`<prompt>`,`What to do`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`--max-turns <n>`,`Max agent turns`,`25`).option(`-v, --verbose`,`Verbose output`).action(async(e,t)=>{let n=[`build`,`test`,`research`],r=t.mode??`build`;n.includes(r)||(y.error(`${T.red(`Invalid mode:`)} ${T.white(r)}. Valid modes are: ${n.join(`, `)}.`),process.exit(1));let i=t.maxTurns?parseInt(String(t.maxTurns),10):void 0;await u.execute({prompt:String(e),mode:r,maxTurns:i!==void 0&&!isNaN(i)?i:void 0,verbose:t.verbose})}),h.command(`skills`).description(`List available agent skills and optional recommendations by mode`).option(`-m, --mode <mode>`,`Show skills recommended for this mode`).action(async e=>{await d.execute({mode:e.mode})}),h.command(`sync`).description(`Sync the connector-building skills + guide into this project (.claude/ + CLAUDE.md)`).option(`--check`,`Report drift and exit non-zero instead of writing (CI guard)`).option(`--plugin-dir <path>`,`Override the agent-harness plugin dir (e.g. point at a checkout in CI/benchmarks)`).action(async e=>{await f.execute({check:!!e.check,pluginDir:e.pluginDir})}),h.command(`chat`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`-c, --connector <name>`,`Connector name`).option(`-a, --action <name>`,`Action name`).option(`-g, --goal <goal>`,`Initial goal/message`).option(`-t, --temperature <number>`,`Temperature (0-1, default: 0.5)`,parseFloat).option(`-v, --verbose`,`Enable verbose logging`).description(`Start an interactive chat session with the agent (use /commands in chat)`).action(async e=>{let t=[`build`,`test`,`research`];e.mode&&!t.includes(e.mode)&&(y.error(`❌ Error: Invalid mode "${e.mode}". Must be one of: ${t.join(`, `)}`),process.exit(1)),e.temperature!==void 0&&(isNaN(e.temperature)&&(y.error(`❌ Error: Temperature must be a valid number`),process.exit(1)),(e.temperature<0||e.temperature>1)&&(y.error(`❌ Error: Temperature must be between 0 and 1`),process.exit(1))),l.execute({mode:e.mode,connector:e.connector,action:e.action,goal:e.goal,temperature:e.temperature,verbose:e.verbose})}),this.program.command(`update`).option(`-f, --force`,`Force reinstall even if already on latest version`).description(`Update the CLI to the latest version`).action(e=>{m.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{y.log(`${T.inverse.greenBright(`StackOne`)} ${T.grey(`CLI`)} ${T.whiteBright(this.version)}`),oi(!0),process.exit(0)})}run(){process.argv.includes(`version`)||oi(),this.program.parse(process.argv)}};export{fi as t};
174
+ `)}`;return this.#n(r)};#i=(e,t,n)=>{let r=e;try{r=K.readFileSync(e,`utf-8`)}catch{}try{let e=Br.parse(JSON.parse(r));return{providerKey:t,providerVersion:n,authConfigKey:e.auth_config_key,environment:e.environment,organizationId:e.organization_id,secureId:e.account_id,projectSecureId:e.project_id}}catch(e){let t=[];try{t=JSON.parse(e.message)}catch{}y.error(`Failed to parse account information`),x(t,!1),t.length===0&&y.log(e.message),process.exit(1)}};#a=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#o=e=>e.includes(`@`)?e:`${e}@latest`;#s=async(e,n,i,a)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Connector identifier, API URL, and API key are required to fetch connector from registry.`),process.exit(1));let o=J();try{o.text=`Fetching connector ${t(e)} from registry...`,o.start();let r=Buffer.from(i).toString(`base64`),s=a?`?owner=${encodeURIComponent(a)}`:``,c=await fetch(`${n}/registry/connectors/${e}${s}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});if(o.stop(),c.status===409){a&&(await b(c,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let i=await Er(e,(await c.json()).availableOwners??[]);o.text=`Fetching connector ${t(e)} from registry...`,o.start();let s=await fetch(`${n}/registry/connectors/${e}?owner=${encodeURIComponent(i)}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});o.stop(),s.ok||(await b(s,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let l=await s.text(),u=this.#n(l);return y.success(`Fetched connector ${t(u.key)}@${t(u.version)} from registry`),u}c.ok||(await b(c,`Failed to fetch connector ${t(e)} from registry`),process.exit(1));let l=await c.text(),u=this.#n(l);return y.success(`Fetched connector ${t(u.key)}@${t(u.version)} from registry`),u}catch(i){o.stop(),y.error(`Failed to fetch connector ${t(e)} from registry: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#c=async(e,n,i)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Account ID, API URL, and API key are required to fetch connector`),process.exit(1));let a=J();try{a.text=`Fetching connector for account ${t(e)} from API...`,a.start();let r=Buffer.from(i).toString(`base64`),o=await fetch(`${n}/accounts/${e}/connector`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});a.stop(),o.ok||(await b(o,`Failed to fetch connector`),process.exit(1));let s=await o.text(),c=this.#n(s);return y.success(`Fetched connector ${t(c.key)}@${t(c.version)} for account ${t(e)}`),c}catch(e){a.stop(),y.error(`Failed to fetch connector: ${e.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#l=async(e,n,i)=>{(Y(e)||Y(n)||Y(i))&&(y.error(`Account ID, API URL, and API key are required to fetch account information.`),process.exit(1));let a=J();try{a.text=`Fetching account ${t(e)} information from API...`,a.start();let r=Buffer.from(i).toString(`base64`),o=await fetch(`${n}/accounts/${e}/credentials`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});a.stop(),o.ok||(await b(o,`Failed to fetch account ${t(e)} information`),process.exit(1));let s=await o.json();return y.success(`Fetched account ${t(e)} information from project ${t(s.project_id)}`),{providerKey:s.provider_key,providerVersion:s.provider_version,authConfigKey:s.auth_config_key,environment:s.environment,organizationId:s.organization_id,secureId:s.account_id,projectSecureId:s.project_id,credentials:s.credentials}}catch(i){a.stop(),y.error(`Failed to fetch account ${t(e)} information: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}};#u=e=>{let t=e;try{t=K.readFileSync(e,`utf-8`)}catch{}try{return Vr.parse(JSON.parse(t))}catch(e){let t=[];try{t=JSON.parse(e.message)}catch{}y.error(`Failed to parse credentials`),x(t,!1),t.length===0&&y.log(e.message),process.exit(1)}};#d=(e,n)=>{let r=e;try{r=K.readFileSync(e,`utf-8`)}catch{}try{return Hr.parse(JSON.parse(r))}catch(e){let r=[];try{r=JSON.parse(e.message)}catch{}y.error(`Invalid parameters for action ${t(n)}.`),x(r,!1),r.length===0&&y.log(e.message),process.exit(1)}};async#f({connector:e,actionId:n,account:r,pathParams:i={},queryParams:a={},body:s={},headers:c={}}){try{let l=await Qe({mode:`action_id`,actionId:n,account:r,connector:e,pathParams:i,queryParams:a,body:s,headers:c,getHttpClient:async()=>new rt});if(l.response?.successful){let e={...this.#p(a,l.steps),...He(l.outputs)?l.outputs:{data:l.outputs}};return{statusCode:l.response?.statusCode,output:e}}else{let r=l.response?.message??`An error occurred while processing the request`;y.error(`Action ID ${t(n)} from connector ${t(e.key)}@${t(e.version)} failed with status ${l.response?.statusCode}: ${r}`);let i={...this.#p(a,l.steps)};Object.keys(i).length>0&&(y.log(`${T.yellow.inverse(` EXECUTION DETAILS `)}`),o(i)),process.exit(1)}}catch(e){this.#m(e)}}#p(e,t){return e?.debug===`true`?{debug:{steps:t}}:{}}#m(e){let t=e;switch(Y(t.errorType)&&(y.error(`An unknown error occurred`),y.log(`${e instanceof Error?e.message:String(e)}`),process.exit(1)),t.errorType){case`MISSING_ACTION_ERROR`:y.error(`The specified action was not found: ${t.message}`);break;case`INVALID_ACTION_INPUTS_ERROR`:let e=t;y.error(`Invalid action inputs`),x(e.validationErrors,!1);break;case`INVALID_CURSOR_ERROR`:y.error(`Invalid cursor: ${t.message}`);break;default:y.error(`An error occurred: ${t.message}`)}process.exit(1)}};const Gr=it(Ce);var Kr=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=J(),this.currentVersion=Wt()}async execute(e={}){this.spinner.text=`Checking for updates...`,this.spinner.start();try{let t=await this.getLatestVersion();this.spinner.stop(),t||(y.error(`Failed to check for updates`),process.exit(1)),this.isNewerVersion(t,this.currentVersion)?(y.box(`New version available: ${T.yellow(this.currentVersion)} → ${T.green(t)}`),await this.performUpdate(t)):e.force?(y.warn(`No updates available, but forcing reinstall...`),await this.performUpdate(t)):y.success(`You are already on the latest version (${this.currentVersion})`),process.exit(0)}catch(e){this.spinner.stop(),y.error(`Error while trying to update StackOne CLI: ${e?.message??`Unknown error`}`),process.exit(1)}}async getLatestVersion(){try{let{stdout:e}=await Gr(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return nt.gt(e,t)}async performUpdate(e){this.spinner.text=`Updating to latest version (${t(e)})...`,this.spinner.start();let n=`npm install -g ${this.packageName}@latest`;try{await Gr(n,{encoding:`utf-8`}),this.spinner.stop(),y.success(`StackOne CLI updated successfully to latest version (${t(e)})`)}catch{throw this.spinner.stop(),Error(`Failed to install update. Please try manually: ${n}`)}}};const qr=e=>e===null?!0:Object.values(e).some(e=>e!==null),Jr=()=>{y.log(`${T.gray.inverse(` CONNECTORS VALIDATION `)} ${T.yellow.inverse(` WATCH MODE `)}\n`)};var Yr=class{async execute(e){let{watchMode:t,fileOrDir:n}=e,r=J(`Watching for file changes... ${T.gray(`(press "q" to quit)`)}`);if(!n)return;let i=Fe(n);try{await ot(i)}catch{y.error(`The specified path does not exist: ${i}\n`),process.exit(1)}if(t){v();let e={},{watch:t}=await import(`chokidar`),n=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let a=()=>{s.close(),r.stop(),n.close(),y.log(T.grey(`
175
+ Exiting watch mode...`)),process.exit(0)};Jr(),y.start(`Validating connectors...`);let o=await $r(i);e=Xr(e,o||{}),Zr(e,i),r.start();let s=t(i,{persistent:!0,ignoreInitial:!0}),c=async t=>{if(!t.endsWith(`.s1.yaml`)&&!t.endsWith(`s1.partial.yaml`))return;let n=t.endsWith(`s1.partial.yaml`)?await ti(t):[t];if(!(!n||n.length===0)){v(),r.stop(),Jr(),y.log(T.gray(`File change detected: ${t}`)),y.start(`Validating connectors...`);for(let t of n){let n=await $r(t);e=Xr(e,n||{})}Zr(e,i),r.start()}};s.on(`change`,async e=>await c(e)),process.stdin.on(`data`,e=>{e.toString()===`q`&&a()}),process.on(`SIGINT`,()=>{a()})}else{let e=await $r(i,y);process.exit(qr(e)?1:0)}}};const Xr=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Zr=(e,n)=>{v(),Jr();let r=0,i=0;for(let[n,a]of Object.entries(e))a===null?r++:(y?.error(`Connector ${t(n)} is not valid`),x(a,!0),i++);y.log(``),y.log(T.blue.inverse(` Validation Summary `)),y.log(`Connectors path: ${t(n)}`),y.log(`${r===0?T.red(`0`):T.green(r)} valid, ${i===0?T.green(`0`):T.red(i)} invalid connectors\n`)},Qr=async e=>{let t=[],n=await at(e);for(let r of n){let n=Pe(e,r),i=await ot(n);i.isDirectory()?t.push(...await Qr(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},$r=async(e,r)=>{let i=await ot(e),a={};if(i.isDirectory()){let i=await Qr(e);if(i.length===0)return r?.error(`No StackOne connector found in ${n(e)}`),r?.log(`Connector files need to have the extension ${t(`*.s1.yaml`)}`),null;let o=0,s=0;for(let e of i){let t=await ei(e,r);t===null?o++:(r?.log(``),s++),a[e]=t}return r?.log(``),r?.log(T.blue.inverse(` Validation Summary `)),r?.log(`${o===0?T.red(`0`):T.green(o)} valid, ${s===0?T.green(`0`):T.red(s)} invalid connectors`),a}else if(i.isFile()&&e.endsWith(`s1.yaml`))return a[e]=await ei(e,r),a;else if(i.isFile()&&e.endsWith(`partial.yaml`)){r?.error(`Partial connector files cannot be validated directly`),r?.log(`The file ${n(e)} is a partial connector file.`);let i=await ti(e);return i&&i?.length>0&&r?.log(`Did you mean ${t(i[0])}?`),null}else return r?.error(`No StackOne connector found in ${n(e)}`),r?.log(`Connector files need to have the extension ${t(`*.s1.yaml`)}`),null},ei=async(e,n)=>{let r=$e(Ze(e)),i=r?.errors??[];if(r.success){let r=e.split(`/`).pop()||e;return n?.success(`Connector ${t(r)} is valid!`),null}else if(i.length>0)return n?.error(`Connector ${t(e)} is not valid`),n&&x(i,!0),i;else return n?.error(`Connector ${t(e)} is not valid. Please check the file for errors`),[]},ti=async e=>{let t=Ne(e);try{return(await at(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>Pe(t,e))}catch{}};function ni(e){if(!e)return!1;try{let{hostname:t}=new URL(e);return t===`stackone-dev.com`||t.endsWith(`.stackone-dev.com`)}catch{return!1}}function ri(){return process.env.AI_TELEMETRY_URL?process.env.AI_TELEMETRY_URL:[process.env.AUTH_SERVER_URL,process.env.STACKONE_API_URL].some(ni)?`https://ai-telemetry.stackone-dev.com`:`https://ai-telemetry.stackone.com`}function ii(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(process.env.AI_TELEMETRY_URL=ri(),e)try{ce({apiKey:e,projectName:t}),process.env.VERBOSE&&console.log(`[Telemetry] Initialized for project:`,t)}catch(e){process.env.VERBOSE&&console.error(`[Telemetry] Failed to initialize:`,e)}}const ai=R(I(),`.stackone`),oi=R(ai,`version-check.json`),si=(e=!1)=>{let t=di(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=ci();e&&li(e)&&ui(e),fi({lastCheckTime:n})}},ci=()=>{try{return Ee(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},li=e=>{try{let t=Wt();return nt.gt(e,t)}catch{return!1}},ui=e=>{let t=Wt(),n=`Update available: ${T.dim(t)} → ${T.green(e)}`,r=`\n\nRun ${T.cyan(`stackone update`)} to update`;y.box(n,r)},di=()=>{try{if(!N(oi))return null;let e=de(oi,`utf-8`);return JSON.parse(e)}catch{return null}},fi=e=>{try{N(ai)||ue(ai,{recursive:!0}),me(oi,JSON.stringify(e,null,2),`utf-8`)}catch{}};var pi=class{constructor(e=new ne,t=Wt()){this.program=e,this.version=t,ii(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new Ar,t=new Fr,n=new Nr,r=new wr,i=new Or,a=new Yr,o=new yn,s=new fr,c=new nn,l=new tn,u=new xn,d=new pr,f=new gr,p=new Wr,m=new Kr;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(T.red(e))}}),this.program.command(`init`).option(`-e, --env <environment>`,`Specify the environment for the configuration profile`).description(`Initialize & create a StackOne CLI configuration profile`).action(t=>{e.execute({environment:t.env})}),this.program.command(`push`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`--force`,`Force push the connector, bypassing version conflict checks`).addArgument(new E(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,n)=>{t.execute({profile:n.profile,fileOrDir:e,apiUrl:n.apiUrl,apiKey:n.apiKey,force:n.force})}),this.program.command(`drop`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).addArgument(new E(`<connector>`,`Connector identifier in format provider_key@version`)).description(`Drop a connector from the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,connector:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`get`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key (defaults to latest)`).option(`--account-id <account-id>`,`Account ID to fetch connector from`).option(`-f, --format <format>`,`Output format: yaml or json (default: yaml)`,`yaml`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Get a connector from the StackOne registry`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),i.execute({profile:e.profile,connector:e.connector,accountId:e.accountId,format:e.format,outputFile:e.outputFile,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})}),this.program.command(`pull`).option(`-c, --connector <connector>`,`Connector identifier in format provider_key@version or provider_key`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output <path>`,`Output directory for the connectors files (default: ./connectors)`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Pull a connector configuration from StackOne registry to local filesystem`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),n.execute({profile:e.profile,connector:e.connector,outputPath:e.output,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new E(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{a.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`run`).option(`--connector <connector>`,`Connector file, inline YAML, or identifier (provider_key@version or provider_key for latest)`).option(`--action <action>`,`Action to execute on the connector (path to file or inline string action code)`).option(`--action-id <action-id>`,`Action ID to execute on the connector`).option(`--account <account>`,`Account details to use for running the connector (path to file or inline string account data)`).option(`--account-id <account-id>`,`Account ID to use for running the connector against (fetches connector from API if --connector not provided)`).option(`--params <params>`,`Action parameters (path to file or inline string with JSON parameters)`).option(`--credentials <credentials>`,`Credentials to use (path to file or inline string with JSON credentials)`).option(`-p, --profile <label>`,`Configuration profile to use`).option(`--api-url <api url>`,`API URL`).option(`--api-key <api key>`,`API Key`).option(`-o, --output-file <output-file>`,`File to write the output to`).option(`-d, --debug`,`Enables debug mode to include more details in the action execution output`).option(`--builtin`,`Use the builtin (StackOne) version of the connector`).option(`--custom`,`Use the custom (organization) version of the connector`).option(`--owner <owner>`,`Owner to use for disambiguating connector versions`).description(`Run a connector action`).action(e=>{[e.builtin,e.custom,e.owner].filter(Boolean).length>1&&(y.error(`--builtin, --custom, and --owner are mutually exclusive. Please provide only one.`),process.exit(1)),p.execute({connector:e.connector,action:e.action,actionId:e.actionId,account:e.account,accountId:e.accountId,params:e.params,credentials:e.credentials,profile:e.profile,outputFile:e.outputFile,debug:e.debug,apiUrl:e.apiUrl,apiKey:e.apiKey,owner:e.builtin?`builtin`:e.custom?`custom`:e.owner})});let h=this.program.command(`agent`).description(`StackOne agent commands`);h.command(`setup`).option(`-g, --global`,`Global only: auth + MCP server (no connector skills/guide)`).option(`-l, --local`,`Local: auth + .mcp.json + connector skills (.claude/) and guide (CLAUDE.md)`).option(`--path <dir>`,`Target project path for local setup (defaults to the current directory)`).option(`--legacy`,`Use email/password login instead of browser-based auth`).option(`--email <email>`,`Email for legacy login (or set STACKONE_EMAIL); requires --legacy`).option(`--password <password>`,`Password for legacy login (or set STACKONE_PASSWORD); requires --legacy. Prefer --password-stdin`).option(`--password-stdin`,`Read password for legacy login from stdin; requires --legacy`).description(`Set up the StackOne agent — prompts for global vs local when neither flag is given`).action(async e=>{e.global&&e.local&&(y.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1));let t=e.email!==void 0,n=e.password!==void 0,r=e.passwordStdin===!0;n&&r&&(y.error(`--password and --password-stdin are mutually exclusive. Please provide only one.`),process.exit(1));let i=t||n||r;i&&!e.legacy&&(y.error(`--email, --password, and --password-stdin require --legacy.`),process.exit(1)),t&&e.email.trim()===``&&(y.error(`--email cannot be empty.`),process.exit(1)),n&&e.password===``&&(y.error(`--password cannot be empty.`),process.exit(1)),r&&(t||process.env.STACKONE_EMAIL?.trim()||(y.error(`--password-stdin requires --email or STACKONE_EMAIL (stdin is consumed for the password, so email cannot be prompted).`),process.exit(1)));let a={email:e.email,password:e.password,passwordFromStdin:r},c=!!process.stdin.isTTY;if(c&&!e.legacy&&!i){let t=await dr({initialMode:e.global?`global`:e.local?`local`:null,pathFlag:e.path});process.exit(t.status===`error`?1:0)}let l=c&&!i;!e.global&&!e.local&&!l&&y.log(T.dim(`No interactive terminal detected — defaulting to global setup. Run in a terminal for the prompt, or pass --local (with --path) / --global.`));let u=Tn(e.global,e.local,l);if(u===null&&(u=await cr()),u===`local`){let t=En(e.path,l);t===null&&(t=await ur(process.cwd())),await s.execute({legacy:!!e.legacy,credentials:a,targetPath:t})}else await o.execute({legacy:!!e.legacy,credentials:a})}),h.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{c.execute()}),h.command(`run`).description(`Run the agent once with a prompt (non-interactive)`).argument(`<prompt>`,`What to do`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`--max-turns <n>`,`Max agent turns`,`25`).option(`-v, --verbose`,`Verbose output`).action(async(e,t)=>{let n=[`build`,`test`,`research`],r=t.mode??`build`;n.includes(r)||(y.error(`${T.red(`Invalid mode:`)} ${T.white(r)}. Valid modes are: ${n.join(`, `)}.`),process.exit(1));let i=t.maxTurns?parseInt(String(t.maxTurns),10):void 0;await u.execute({prompt:String(e),mode:r,maxTurns:i!==void 0&&!isNaN(i)?i:void 0,verbose:t.verbose})}),h.command(`skills`).description(`List available agent skills and optional recommendations by mode`).option(`-m, --mode <mode>`,`Show skills recommended for this mode`).action(async e=>{await d.execute({mode:e.mode})}),h.command(`sync`).description(`Sync the connector-building skills + guide into this project (.claude/ + CLAUDE.md)`).option(`--check`,`Report drift and exit non-zero instead of writing (CI guard)`).option(`--plugin-dir <path>`,`Override the agent-harness plugin dir (e.g. point at a checkout in CI/benchmarks)`).action(async e=>{await f.execute({check:!!e.check,pluginDir:e.pluginDir})}),h.command(`chat`).option(`-m, --mode <mode>`,`Mode: build, test, or research`,`build`).option(`-c, --connector <name>`,`Connector name`).option(`-a, --action <name>`,`Action name`).option(`-g, --goal <goal>`,`Initial goal/message`).option(`-t, --temperature <number>`,`Temperature (0-1, default: 0.5)`,parseFloat).option(`-v, --verbose`,`Enable verbose logging`).description(`Start an interactive chat session with the agent (use /commands in chat)`).action(async e=>{let t=[`build`,`test`,`research`];e.mode&&!t.includes(e.mode)&&(y.error(`❌ Error: Invalid mode "${e.mode}". Must be one of: ${t.join(`, `)}`),process.exit(1)),e.temperature!==void 0&&(isNaN(e.temperature)&&(y.error(`❌ Error: Temperature must be a valid number`),process.exit(1)),(e.temperature<0||e.temperature>1)&&(y.error(`❌ Error: Temperature must be between 0 and 1`),process.exit(1))),l.execute({mode:e.mode,connector:e.connector,action:e.action,goal:e.goal,temperature:e.temperature,verbose:e.verbose})}),this.program.command(`update`).option(`-f, --force`,`Force reinstall even if already on latest version`).description(`Update the CLI to the latest version`).action(e=>{m.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{y.log(`${T.inverse.greenBright(`StackOne`)} ${T.grey(`CLI`)} ${T.whiteBright(this.version)}`),si(!0),process.exit(0)})}run(){process.argv.includes(`version`)||si(),this.program.parse(process.argv)}};export{pi as t};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- require(`./agentConfig-KBkYYmMr.cjs`);const e=require(`./cliCore-BnaGcYG7.cjs`);require(`./setupMigration-rqPZ8MV6.cjs`),require(`./agentApiKey-BDp7EFMI.cjs`),exports.CLI=e.t;
1
+ require(`./agentConfig-KBkYYmMr.cjs`);const e=require(`./cliCore-CtAXBkSt.cjs`);require(`./setupMigration-rqPZ8MV6.cjs`),require(`./agentApiKey-BDp7EFMI.cjs`),exports.CLI=e.t;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./cliCore-BEt2cFAT.mjs";import"./agentConfig-BWQWMYKQ.mjs";import"./setupMigration-C1ShGzOu.mjs";import"./agentApiKey-CWXxJgCO.mjs";export{e as CLI};
1
+ import{t as e}from"./cliCore-DrKweOPX.mjs";import"./agentConfig-BWQWMYKQ.mjs";import"./setupMigration-C1ShGzOu.mjs";import"./agentApiKey-CWXxJgCO.mjs";export{e as CLI};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/cli",
3
- "version": "1.39.0",
3
+ "version": "1.40.0",
4
4
  "description": "StackOne Connect CLI tool",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -36,11 +36,11 @@
36
36
  "@clack/prompts": "0.11.0",
37
37
  "@stackone/agent-config": "1.4.0",
38
38
  "@stackone/agent-harness": "0.14.1",
39
- "@stackone/connect-sdk": "2.93.0",
40
- "@stackone/core": "3.6.0",
39
+ "@stackone/connect-sdk": "2.94.0",
40
+ "@stackone/core": "3.8.0",
41
41
  "@stackone/defender": "0.7.1",
42
42
  "@stackone/expressions": "0.35.0",
43
- "@stackone/transport": "2.27.2",
43
+ "@stackone/transport": "2.28.0",
44
44
  "@stackone/utils": "1.0.0",
45
45
  "chalk": "5.6.2",
46
46
  "chokidar": "5.0.0",