@stackone/cli 1.31.1 → 1.33.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/README.md +16 -0
- package/dist/cli.cjs +1 -1
- package/dist/cli.mjs +1 -1
- package/dist/{cliCore-5wAl_HuC.cjs → cliCore-DZnmJlqN.cjs} +20 -18
- package/dist/{cliCore-fYXUb78K.mjs → cliCore-_BZmg0kj.mjs} +20 -18
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -672,6 +672,19 @@ stackone agent setup --global
|
|
|
672
672
|
|
|
673
673
|
By default the command opens a browser-based device-code flow — sign in to StackOne in the browser and the CLI picks up the resulting token automatically. Pass `--legacy` to fall back to an interactive email/password prompt.
|
|
674
674
|
|
|
675
|
+
For programmatic / CI use, the legacy flow can run non-interactively. Pass `--legacy` to opt in (env vars and credential flags are only honored when `--legacy` is set). Email comes from `--email` or `STACKONE_EMAIL`; password comes from `--password-stdin` (preferred), `--password`, or `STACKONE_PASSWORD`:
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
# env vars
|
|
679
|
+
STACKONE_EMAIL=me@stackone.com STACKONE_PASSWORD=$SECRET stackone agent setup --legacy
|
|
680
|
+
|
|
681
|
+
# pipe password from a secret manager
|
|
682
|
+
vault read -field=pw secret/stackone | \
|
|
683
|
+
stackone agent setup --legacy --email me@stackone.com --password-stdin
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
`--password` puts the password in argv (visible to other processes via `ps` and shell history) — prefer `--password-stdin` or env vars wherever possible.
|
|
687
|
+
|
|
675
688
|
Configuration is saved to `~/.stackone/agent-config.json` with secure permissions. API keys expire after 24 hours.
|
|
676
689
|
|
|
677
690
|
**Local setup** - Setup the StackOne agent for a specific project:
|
|
@@ -687,6 +700,9 @@ Options:
|
|
|
687
700
|
- `-g, --global` - Setup global configuration (default)
|
|
688
701
|
- `-l, --local` - Setup local project configuration
|
|
689
702
|
- `--legacy` - Use email/password login instead of browser-based auth
|
|
703
|
+
- `--email <email>` - Email for legacy login (or set `STACKONE_EMAIL`); requires `--legacy`
|
|
704
|
+
- `--password <password>` - Password for legacy login (or set `STACKONE_PASSWORD`); requires `--legacy`. Prefer `--password-stdin`
|
|
705
|
+
- `--password-stdin` - Read password for legacy login from stdin; requires `--legacy`
|
|
690
706
|
|
|
691
707
|
### `agent cleanup`
|
|
692
708
|
|
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-
|
|
2
|
+
const e=require(`./agentConfig-KBkYYmMr.cjs`),t=require(`./cliCore-DZnmJlqN.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-
|
|
2
|
+
import{t as e}from"./cliCore-_BZmg0kj.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{};
|
|
@@ -122,32 +122,34 @@ If you continue to see this error, try running:`)),e.w.log(i.default.cyan(` sta
|
|
|
122
122
|
`)),process.exit(1)}}},J=class{async execute(){e.w.log(i.default.blue.bold(`🧹 StackOne Agent Cleanup
|
|
123
123
|
`));try{let t=(0,_.default)(`Removing stored configuration...`).start();await e.n(),t.succeed(`Removed ~/.stackone/agent-config.json`);let n=(0,_.default)(`Removing MCP servers from Claude...`).start(),r=0;e.p(e.a(),e.s())&&r++,e.p(e.o(process.cwd()),e.c())&&r++,r>0?n.succeed(`Removed ${r} MCP server(s) from Claude`):n.warn(`No MCP servers found in Claude (already removed or not configured)`),e.w.success(`Cleanup complete!`),e.w.log(i.default.white(`
|
|
124
124
|
What was removed:`)),e.w.log(i.default.cyan(` • ~/.stackone/agent-config.json`)),r>0&&e.w.log(i.default.cyan(` • MCP server entries from Claude configuration`)),e.w.log(i.default.dim(`
|
|
125
|
-
To authenticate again:`)),e.w.log(i.default.cyan(` stackone agent setup`),i.default.dim(`(for global setup)`)),e.w.log(i.default.cyan(` stackone agent setup --local`),i.default.dim(`(for local project setup)`)),e.w.log(``),process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}};const ke=`stackone-cli`,
|
|
126
|
-
`)),process.exit(1)),
|
|
127
|
-
`));try{let r=process.cwd(),a=await(0,v.access)(`${r}/CLAUDE.md`).then(()=>!0).catch(()=>!1),o=await(0,v.access)(`${r}/.mcp.json`).then(()=>!0).catch(()=>!1);if(a||o)
|
|
128
|
-
|
|
125
|
+
To authenticate again:`)),e.w.log(i.default.cyan(` stackone agent setup`),i.default.dim(`(for global setup)`)),e.w.log(i.default.cyan(` stackone agent setup --local`),i.default.dim(`(for local project setup)`)),e.w.log(``),process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}};const ke=(e,t)=>e?!!(t?.email||t?.password||t?.passwordFromStdin||process.env.STACKONE_EMAIL?.trim()||process.env.STACKONE_PASSWORD?.trim()):!1,Y=`stackone-cli`,Ae=`urn:ietf:params:oauth:grant-type:device_code`,X=async e=>{let t=`HTTP ${e.status}: ${e.statusText}`;try{let n=await e.text(),r=JSON.parse(n);return r.error_description||r.error||t}catch{return t}};var je=class{constructor(e){this.baseUrl=e||process.env.AUTH_SERVER_URL||`https://idp-api.stackone.com`}async login(e,t){try{let n=await fetch(`${this.baseUrl}/auth/sign-in/mcp`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({email:e,password:t})});if(!n.ok)return{success:!1,error:await X(n)};let r=await n.json();return r.apiKey?{success:!0,apiKey:r.apiKey}:{success:!1,error:`Invalid response format`}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Network error occurred`}}}async validateKey(e){try{let t=await fetch(`${this.baseUrl}/api-key/verify`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e})});return t.ok?await t.json():{valid:!1,error:await X(t)}}catch(e){return{valid:!1,error:e instanceof Error?e.message:`Network error occurred`}}}async requestDeviceCode(){let e=await fetch(`${this.baseUrl}/api/auth/device/code`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({client_id:Y})});if(!e.ok)throw Error(await X(e));return await e.json()}async pollDeviceToken(e){try{let t=await fetch(`${this.baseUrl}/api/auth/device/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({grant_type:`urn:ietf:params:oauth:grant-type:device_code`,device_code:e,client_id:Y})});if(t.ok)return{token:await t.json()};try{let e=await t.json();if(e.error)return{error:e}}catch{}return{error:{error:`server_error`,error_description:`HTTP ${t.status}: ${t.statusText}`}}}catch(e){return{error:{error:`network_error`,error_description:e instanceof Error?e.message:`Network error`}}}}async createApiKey(e){let t=10080*60,n=await fetch(`${this.baseUrl}/api/auth/api-key/create`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e}`},body:JSON.stringify({prefix:`falcon_key_`,expiresIn:t,name:`CLI Auth Key`})});if(!n.ok)throw Error(await X(n));let r=await n.json(),i=new Date(Date.now()+t*1e3).toISOString();return{key:r.key,expiresAt:i}}};const Z=e=>new Promise(t=>{let n=(0,c.platform)(),r,i;n===`darwin`?(r=`open`,i=[e]):n===`win32`?(r=`rundll32`,i=[`url.dll,FileProtocolHandler`,e]):(r=`xdg-open`,i=[e]),(0,f.execFile)(r,i,e=>{t(!e)})}),Me=5,Ne=async(e,t)=>{let n=await e.requestDeviceCode(),r=await Z(n.verification_uri_complete),i=`Confirmation code: ${n.user_code}`;t(r?`Browser opened. ${i}\nWaiting for authentication...`:`Could not open browser. Please visit:\n ${n.verification_uri_complete}\n\n${i}`);let a=n.interval*1e3,o=0,s=Date.now()+n.expires_in*1e3;for(;Date.now()<s;){await new Promise(e=>setTimeout(e,a));let r=await e.pollDeviceToken(n.device_code);if(`token`in r){t(`Authenticated. Creating API key...`);let n=await e.createApiKey(r.token.access_token),i=await e.validateKey(n.key);return{success:!0,apiKey:n.key,email:i.email,userId:i.userId,expiresAt:n.expiresAt}}let i=r.error.error;if(i===`authorization_pending`){o=0;continue}if(i===`slow_down`){o=0,await new Promise(e=>setTimeout(e,a));continue}if(i===`expired_token`)return{success:!1,error:`Authentication session expired`};if(i===`access_denied`)return{success:!1,error:`Access denied by user`};if(o++,o>=5)return{success:!1,error:`Polling failed: ${r.error.error_description??`unknown error`}`}}return{success:!1,error:`Authentication timed out`}},Pe=new je,Fe=async()=>{let t=(0,x.createInterface)({input:b.stdin,output:b.stdout}),n=await new Promise(e=>{t.question(i.default.white(`Email: `),t=>{e(t.trim())})});return t.close(),n||(e.w.error(`Email is required`),process.exit(1)),n},Q=async()=>{process.stdin.isTTY&&(e.w.error(`--password-stdin was set but no input was piped to stdin`),process.exit(1));let t=[];for await(let e of process.stdin)t.push(e);return Buffer.concat(t).toString(`utf8`).replace(/[\r\n]+$/,``)},Ie=async e=>{let t=e.email?.trim()||process.env.STACKONE_EMAIL?.trim()||void 0,n;return e.passwordFromStdin?n=await Q():e.password?n=e.password:process.env.STACKONE_PASSWORD&&(n=process.env.STACKONE_PASSWORD),{email:t,password:n||void 0}},Le=async t=>{let n=await Ie(t),r=n.email;if(!r){let t=await e.u();if(t?.email){e.w.log(i.default.dim(`Last used email: ${t.email}\n`));let{useExisting:n}=await y.default.prompt([{type:`confirm`,name:`useExisting`,message:`Sign in with this email?`,default:!0}]);r=n?t.email:await Fe()}else r=await Fe()}let a=n.password;a||=(t.passwordFromStdin&&(e.w.error(`Password is required`),process.exit(1)),(await y.default.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}])).password),a||(e.w.error(`Password is required`),process.exit(1)),e.w.log(``);let o=(0,_.default)(`Authenticating...`).start(),s=await Pe.login(r,a);(!s.success||!s.apiKey)&&(o.fail(`Authentication failed`),e.w.error(`${s.error||`Invalid credentials`}`),e.w.log(i.default.dim(`Please check your email and password and try again.
|
|
126
|
+
`)),process.exit(1)),o.succeed(`Login successful!`);let c=new Date(Date.now()+10080*60*1e3).toISOString();return{apiKey:s.apiKey,email:r,expiresAt:c}},Re=async()=>{let t=(0,_.default)(`Starting browser authentication...`).start(),n;try{n=await Ne(Pe,e=>{t.text=e})}catch(n){t.fail(`Authentication failed`),e.w.error(n instanceof Error?n.message:`Unknown error`),process.exit(1)}(!n.success||!n.apiKey)&&(t.fail(`Authentication failed`),e.w.error(n.error||`Unknown error`),process.exit(1)),t.succeed(`Login successful!`);let r=n.expiresAt||new Date(Date.now()+10080*60*1e3).toISOString();return{apiKey:n.apiKey,email:n.email??``,userId:n.userId,expiresAt:r}},ze=async(t,n={})=>{let{apiKey:r,email:i,userId:a,expiresAt:o}=t?await Le(n):await Re(),s={apiKey:r,userId:a??i,email:i,expiresAt:o,serverUrl:e.r()};return await e.m(s),s},Be=e=>{let t=new Date(e),n=new Date,r=t.getTime()-n.getTime(),i=Math.floor(r/(1440*60*1e3)),a=Math.floor(r%(1440*60*1e3)/(3600*1e3)),o=t.toLocaleTimeString(`en-US`,{hour:`numeric`,minute:`2-digit`,hour12:!0});return`${t.toLocaleDateString(`en-US`,{weekday:`short`,month:`short`,day:`numeric`})} at ${o} (${i>0?`${i} days, ${a} hours`:`${a} hours`} from now)`};var Ve=class{async execute(t){e.w.log(i.default.blue.bold(`🤖 StackOne Agent Setup - Global Configuration
|
|
127
|
+
`));try{let r=process.cwd(),a=await(0,v.access)(`${r}/CLAUDE.md`).then(()=>!0).catch(()=>!1),o=await(0,v.access)(`${r}/.mcp.json`).then(()=>!0).catch(()=>!1);if(a||o)if(e.w.warn(`Existing local setup detected:`),a&&e.w.log(i.default.dim(` • CLAUDE.md found in current directory`)),o&&e.w.log(i.default.dim(` • .mcp.json found in current directory`)),e.w.log(``),ke(!!t?.legacy,t?.credentials))e.w.log(i.default.dim(`Non-interactive credentials detected; proceeding without confirmation.
|
|
128
|
+
`));else{let{proceed:t}=await y.default.prompt([{type:`confirm`,name:`proceed`,message:`Re-authenticate globally despite existing local setup?`,default:!0}]);t||(e.w.log(i.default.dim(`
|
|
129
|
+
Setup cancelled.`)),process.exit(0)),e.w.log(``)}let s=await ze(!!t?.legacy,t?.credentials);e.w.success(`API key saved to ~/.stackone/agent-config.json`),e.w.log(i.default.white(`✓ Key expires at`),i.default.cyan(Be(s.expiresAt))),n.t(await n.r(process.cwd(),s.apiKey));let c=(0,_.default)(`Setting up global MCP configuration...`).start();try{e.h(e.a(),e.s(),s.apiKey),c.succeed(`Installed to Claude (global)`),e.w.success(`Global setup complete!`),e.w.log(i.default.white(`Config location:`),i.default.cyan(`~/.claude.json`)),e.w.log(i.default.dim(`Token stored securely in Claude MCP server config.`)),e.w.log(i.default.blue(`
|
|
129
130
|
Verify:`),i.default.cyan(`claude mcp list`)),e.w.log(i.default.dim(`
|
|
130
131
|
💡 Tip: Run Claude without permission prompts:`),i.default.cyan(`claude --dangerously-skip-permissions`)),e.w.log(i.default.dim(`
|
|
131
|
-
To setup for a specific project, run:`),i.default.cyan(`stackone agent setup --local`)),e.w.log(``)}catch(t){c.fail(`Installation to Claude failed`),t instanceof Error&&e.w.error(t.message)}process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}};const
|
|
132
|
+
To setup for a specific project, run:`),i.default.cyan(`stackone agent setup --local`)),e.w.log(``)}catch(t){c.fail(`Installation to Claude failed`),t instanceof Error&&e.w.error(t.message)}process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}};const He={research:`Researching API...`,"discover-actions":`Discovering available actions...`,"build-and-validate":`Building and validating connector...`};var Ue=class{async execute(t){let{prompt:n,mode:a=`build`,maxTurns:s=25,verbose:c=!1}=t;n.trim()||(e.w.error(`A prompt is required.`),process.exit(1));let l;try{l=r.r()}catch(t){t instanceof Error&&t.name===`CredentialMissingError`?(e.w.error(`
|
|
132
133
|
❌ Authentication Required
|
|
133
|
-
`),e.w.log(i.default.white("Run `stackone agent setup` to authenticate, then try again.\n"))):e.w.error(t instanceof Error?t.message:String(t)),process.exit(1)}let u=xe(),d=(0,o.extractBuildIntent)(n.trim());if(a===`build`&&d.isConnectorBuild&&d.provider)return this.executeOrchestratedBuild({provider:d.provider,category:d.category,apiKey:l,mcpServers:u,verbose:c});c&&(e.w.log(i.default.dim(`Mode: ${a}\n`)),u.length>0&&e.w.log(i.default.dim(`MCP Servers: ${u.map(e=>e.name).join(`, `)}\n`)));let f=null;try{for await(let e of(0,o.executeAgent)({prompt:n.trim(),mode:a,apiKey:l,maxTurns:s,verbose:c,mcpServers:u,origin:`cli`}))
|
|
134
|
+
`),e.w.log(i.default.white("Run `stackone agent setup` to authenticate, then try again.\n"))):e.w.error(t instanceof Error?t.message:String(t)),process.exit(1)}let u=xe(),d=(0,o.extractBuildIntent)(n.trim());if(a===`build`&&d.isConnectorBuild&&d.provider)return this.executeOrchestratedBuild({provider:d.provider,category:d.category,apiKey:l,mcpServers:u,verbose:c});c&&(e.w.log(i.default.dim(`Mode: ${a}\n`)),u.length>0&&e.w.log(i.default.dim(`MCP Servers: ${u.map(e=>e.name).join(`, `)}\n`)));let f=null;try{for await(let e of(0,o.executeAgent)({prompt:n.trim(),mode:a,apiKey:l,maxTurns:s,verbose:c,mcpServers:u,origin:`cli`}))Ge(e,e=>{f&&f.stop(),f=e})}catch(t){f?.fail(),e.w.error(i.default.red(`
|
|
134
135
|
Error: `+(t instanceof Error?t.message:String(t)))),process.exit(1)}f?.stop(),e.w.log(i.default.green(`
|
|
135
136
|
✓ Done
|
|
136
|
-
`))}async executeOrchestratedBuild(t){let{provider:n,category:r,verbose:a}=t,o=r?` (${r})`:``;e.w.log(i.default.bold(`\nOrchestrated build: ${n}${o}\n`));let s=null,c=new Map;try{for await(let e of U(t))switch(e.type){case`phase_start`:{let t=
|
|
137
|
+
`))}async executeOrchestratedBuild(t){let{provider:n,category:r,verbose:a}=t,o=r?` (${r})`:``;e.w.log(i.default.bold(`\nOrchestrated build: ${n}${o}\n`));let s=null,c=new Map;try{for await(let e of U(t))switch(e.type){case`phase_start`:{let t=He[e.phase]||`${e.phase}...`,n=e.model?i.default.dim(` (${N(e.model)})`):``;s?.stop(),s=(0,_.default)(i.default.cyan(`[${e.phase}]${n} ${t}`)).start(),c.set(e.phase,Date.now());break}case`phase_complete`:{let t=c.get(e.phase),n=t===void 0?0:Math.round((Date.now()-t)/1e3);s?.succeed(i.default.green(`[${e.phase}] Done (${n}s)`)),s=null;break}case`phase_error`:s?.fail(i.default.red(`[${e.phase}] ${e.error}`)),s=null;break;case`agent_message`:We(e,s,a);break}}catch(t){s?.fail(),e.w.error(i.default.red(`
|
|
137
138
|
Error: `+(t instanceof Error?t.message:String(t)))),process.exit(1)}s?.stop(),e.w.log(i.default.green(`
|
|
138
139
|
✓ Build complete
|
|
139
|
-
`))}};const
|
|
140
|
-
`));try{let r=process.cwd(),a=await(0,v.access)(`${r}/CLAUDE.md`).then(()=>!0).catch(()=>!1),o=await(0,v.access)(`${r}/.mcp.json`).then(()=>!0).catch(()=>!1);if(a||o)
|
|
140
|
+
`))}};const We=(t,n,r)=>{let a=t.message;switch(a.type){case`text`:r&&process.stdout.write(a.content??``);break;case`tool_call`:{let e=a.toolName??`unknown tool`;n&&(n.text=i.default.cyan(`[${t.phase}] Tool: ${e}`));break}case`tool_error`:e.w.error(i.default.red(`\n[${t.phase}] Tool error (${a.toolName}): ${a.error??`Unknown error`}`));break;case`error`:e.w.error(i.default.red(`\n[${t.phase}] ${a.error??`Unknown error`}`));break;default:break}};function Ge(t,n){switch(t.type){case`text`:n(null),process.stdout.write(t.content??``);break;case`tool_call`:{let e=t.toolName??`unknown tool`;n((0,_.default)(i.default.cyan(`Tool: ${e}`)).start());break}case`tool_result`:n(null);break;case`tool_progress`:{let e=t.progress?.operation||t.toolName||`Working...`;n((0,_.default)(i.default.cyan(`Tool: ${e}`)).start());break}case`tool_error`:n(null),e.w.error(i.default.red(`\nTool error (${t.toolName}): ${t.error??`Unknown error`}`));break;case`error`:n(null),e.w.error(i.default.red(`\n${t.error??`Unknown error`}`));break;case`done`:n(null);break;default:process.env.VERBOSE&&console.warn(`[AgentRun] Unknown message type:`,t.type);break}}var Ke=class{async execute(t){e.w.log(i.default.blue.bold(`🤖 StackOne Agent Setup - Local Project
|
|
141
|
+
`));try{let r=process.cwd(),a=await(0,v.access)(`${r}/CLAUDE.md`).then(()=>!0).catch(()=>!1),o=await(0,v.access)(`${r}/.mcp.json`).then(()=>!0).catch(()=>!1);if(a||o)if(e.w.warn(`Existing local setup detected:`),a&&e.w.log(i.default.dim(` • CLAUDE.md found`)),o&&e.w.log(i.default.dim(` • .mcp.json found`)),e.w.log(``),ke(!!t?.legacy,t?.credentials))e.w.log(i.default.dim(`Non-interactive credentials detected; proceeding without confirmation.
|
|
142
|
+
`));else{let{proceed:t}=await y.default.prompt([{type:`confirm`,name:`proceed`,message:`Overwrite existing local configuration?`,default:!1}]);t||(e.w.log(i.default.dim(`
|
|
141
143
|
Setup cancelled.`)),process.exit(0)),e.w.log(``)}let s=await e.u();(!s||!e.l(s))&&(e.w.warn(`Not authenticated globally.`),e.w.log(i.default.white(`Let's authenticate now...
|
|
142
|
-
`)),s=await
|
|
144
|
+
`)),s=await ze(!!t?.legacy,t?.credentials),e.w.log(``)),n.t(await n.r(r,s.apiKey));let c=(0,_.default)(`Creating .mcp.json...`).start();try{e.h(e.o(r),e.c(),s.apiKey),c.succeed(`Created .mcp.json`),e.w.success(`Local setup complete!`),e.w.log(i.default.white(`Files created:`)),e.w.log(i.default.cyan(` • .mcp.json`)),e.w.log(i.default.dim(`Token stored securely in Claude MCP server config.`)),e.w.log(i.default.dim(`
|
|
143
145
|
💡 The stackone-agent-local MCP server is now available in this project`)),e.w.log(i.default.dim(`
|
|
144
146
|
💡 Tip: Run Claude without permission prompts:`),i.default.cyan(`claude --dangerously-skip-permissions`)),e.w.log(i.default.blue(`
|
|
145
|
-
Verify:`),i.default.cyan(`claude mcp list`)),e.w.log(``)}catch(t){c.fail(`Failed to create .mcp.json`),t instanceof Error&&e.w.error(t.message)}process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}},
|
|
147
|
+
Verify:`),i.default.cyan(`claude mcp list`)),e.w.log(``)}catch(t){c.fail(`Failed to create .mcp.json`),t instanceof Error&&e.w.error(t.message)}process.exit(0)}catch(t){t instanceof Error?e.w.error(t.message):e.w.error(`Unknown error occurred`),process.exit(1)}}},qe=class{async execute(t){let n=(0,o.getAvailableSkillNames)(),r=t?.mode;if(e.w.log(i.default.bold(`
|
|
146
148
|
Available skills
|
|
147
149
|
`)),n.length===0){e.w.log(i.default.dim(` No bundled skills found.
|
|
148
|
-
`));return}for(let t of n)e.w.log(` • ${t}`);if(r){let t=(0,o.getSkillsForMode)(r);if(t.length>0){e.w.log(i.default.bold(`\nRecommended for mode "${r}":\n`));for(let r of t){let t=n.includes(r);e.w.log(` • ${r}${t?``:i.default.dim(` (not found)`)}`)}}}e.w.log(``)}};const
|
|
150
|
+
`));return}for(let t of n)e.w.log(` • ${t}`);if(r){let t=(0,o.getSkillsForMode)(r);if(t.length>0){e.w.log(i.default.bold(`\nRecommended for mode "${r}":\n`));for(let r of t){let t=n.includes(r);e.w.log(` • ${r}${t?``:i.default.dim(` (not found)`)}`)}}}e.w.log(``)}};const Je={profiles:{}},Ye=()=>{let n=e._.readConfigFile(t.n);if(!n)return Je;try{return JSON.parse(n)}catch{return Je}},Xe=e=>Ye().profiles[e],Ze=e=>!!Ye().profiles[e],Qe=(n,r)=>{let i=Ye();i.profiles[n]=r,e._.writeConfigFile(t.n,JSON.stringify(i,null,2))},$e=()=>{let e=Ye();return Object.keys(e.profiles)},et=`https://api.stackone.com`;var tt=class{async execute({profile:t,connector:n,apiUrl:r,apiKey:a}={}){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&&!Ze(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=$e();n.length>0&&(e.w.info(`Available configuration profiles:`),n.forEach(t=>{e.w.log(` - ${i.default.blue(t)}`)})),process.exit(1)}let o=t?Xe(t):{apiUrl:r??et,apiKey:a};o?.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(`Connector identifier is required in the format provider_key@version.`),process.exit(1));let s=n.split(`@`);(s.length!==2||!s[0]||!s[1])&&(e.w.error(`Invalid connector format ${e.S(n)}. Expected format: ${e.C(`provider_key@version`)}`),process.exit(1));let c=o.apiUrl??et,l=await this.dropConnector(n,c,o.apiKey);process.exit(l?0:1)}async dropConnector(t,n,r){let i=(0,_.default)(`🗑️ Dropping connector ${e.C(t)}...`).start();try{let a=Buffer.from(r).toString(`base64`),o=await fetch(`${n}/registry/connectors/${t}`,{method:`DELETE`,headers:{Authorization:`Basic ${a}`}});return i.stop(),o.status===204?(e.w.success(`Successfully dropped connector ${e.C(t)} from the registry`),!0):o.status===404?(e.w.error(`Connector ${e.C(t)} not found in the registry`),!1):o.status===401||o.status===403?(e.w.error(`You do not have permission to drop this connector`),!1):o.status===409?(e.w.error(`Connector ${e.C(t)} has associated configs and cannot be dropped`),e.w.log(`Please delete all associated integration configurations before dropping the connector.`),!1):(o.ok||await e.x(o,`Failed to drop connector ${e.C(t)} from the registry`),!1)}catch(r){return i.stop(),e.w.error(`Failed to drop 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`),!1}}};const nt=`stackone`;async function rt(t,n){n.length===0&&(e.w.error(`Multiple versions of connector ${e.C(t)} were found but no owner information was returned`),process.exit(1));let r=n.map(e=>({value:e,label:e===nt?`StackOne`:`Custom`,hint:e===nt?`Official StackOne connector`:`Custom connector version created by your organization`}));e.w.warn(`Multiple versions of connector ${e.C(t)} were found. Please select which version to use.`);let i=await(0,C.select)({message:`Which version would you like to use?`,options:r});return(0,C.isCancel)(i)&&(e.w.error(`Operation cancelled.`),process.exit(1)),i}const it=`https://api.stackone.com`;var at=class{async execute({profile:t,connector:n,accountId:r,format:a,outputFile:o,apiUrl:s,apiKey:c,owner:l}={}){if(!t&&!c&&(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&&c&&(e.w.error(`Please provide either a profile or an API key, not both`),process.exit(1)),t&&s&&e.w.warn(`Specifying ${e.C(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),t&&!Ze(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=$e();n.length>0&&(e.w.info(`Available configuration profiles:`),n.forEach(t=>{e.w.log(` - ${i.default.blue(t)}`)})),process.exit(1)}let u=t?Xe(t):{apiUrl:s??it,apiKey:c};u?.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)),(0,S.isMissing)(n)&&(0,S.isMissing)(r)&&(e.w.error(`Either ${e.C(`--connector`)} or ${e.C(`--account-id`)} must be provided`),process.exit(1)),(0,S.notMissing)(n)&&(0,S.notMissing)(r)&&(e.w.error(`Please provide either ${e.C(`--connector`)} or ${e.C(`--account-id`)}, not both.`),process.exit(1)),(0,S.notMissing)(a)&&a!==`yaml`&&a!==`json`&&(e.w.error(`Format must be either ${e.C(`yaml`)} or ${e.C(`json`)}.`),process.exit(1));let d=u.apiUrl??it,f;if((0,S.notMissing)(n)){this.#t(n)||(e.w.error(`Invalid connector format ${e.S(n)}. Expected format: ${e.C(`provider_key@version`)} or ${e.C(`provider_key`)}`),process.exit(1));let t=this.#n(n);f=await this.#r(t,d,u.apiKey,a,l)}else (0,S.notMissing)(r)?f=await this.#i(r,d,u.apiKey,a):(e.w.error(`Either ${e.C(`--connector`)} or ${e.C(`--account-id`)} must be provided`),process.exit(1));if((0,S.notMissing)(o))try{m.default.writeFileSync(o,f,`utf-8`),e.w.success(`Connector written to file: ${e.C(o)}`)}catch(t){e.w.error(`Failed to write connector to file ${e.C(o)}: ${t.message}`),process.exit(1)}else if(e.w.log(`\n${i.default.blue.inverse(` CONNECTOR CONTENT `)}\n`),!a||a===`yaml`)e.w.log(this.#e(f));else if(a===`json`)try{e.b(JSON.parse(f))}catch{e.w.log(f)}else e.w.log(f);process.exit(0)}#e(e){return e.split(`
|
|
149
151
|
`).map(e=>{if(e.trim().startsWith(`#`))return i.default.gray(e);if(e.includes(`:`)){let t=e.indexOf(`:`),n=e.substring(0,t+1),r=e.substring(t+1),a=r,o=r.trim();return o===`true`||o===`false`?a=r.replace(o,i.default.cyan(o)):o===`null`||o===`~`?a=r.replace(o,i.default.gray(o)):/^-?\d+(\.\d+)?$/.test(o)?a=r.replace(o,i.default.green(o)):(o.startsWith(`"`)&&o.endsWith(`"`)||o.startsWith(`'`)&&o.endsWith(`'`)||o&&!o.startsWith(`-`))&&(a=r.replace(o,i.default.yellow(o))),i.default.red(n)+a}return e.trim().startsWith(`-`)?e.replace(`-`,i.default.gray(`-`)):e}).join(`
|
|
150
|
-
`)}#t=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#n=e=>e.includes(`@`)?e:`${e}@latest`;async#r(t,n,r,i,a){let o=(0,_.default)(`Getting connector ${e.C(t)} from registry...`).start();try{let s=Buffer.from(r).toString(`base64`),c=i?`?format=${i}`:``,l=a?`${c?`&`:`?`}owner=${encodeURIComponent(a)}`:``,u=await fetch(`${n}/registry/connectors/${t}${c}${l}`,{method:`GET`,headers:{Authorization:`Basic ${s}`}});if(o.stop(),u.status===409){a&&(await e.x(u,`Failed to get connector ${e.C(t)} from the registry`),process.exit(1));let r=await
|
|
152
|
+
`)}#t=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#n=e=>e.includes(`@`)?e:`${e}@latest`;async#r(t,n,r,i,a){let o=(0,_.default)(`Getting connector ${e.C(t)} from registry...`).start();try{let s=Buffer.from(r).toString(`base64`),c=i?`?format=${i}`:``,l=a?`${c?`&`:`?`}owner=${encodeURIComponent(a)}`:``,u=await fetch(`${n}/registry/connectors/${t}${c}${l}`,{method:`GET`,headers:{Authorization:`Basic ${s}`}});if(o.stop(),u.status===409){a&&(await e.x(u,`Failed to get connector ${e.C(t)} from the registry`),process.exit(1));let r=await rt(t,(await u.json()).availableOwners??[]),i=`${n}/registry/connectors/${t}${c}${c?`&`:`?`}owner=${encodeURIComponent(r)}`;o.text=`Getting connector ${e.C(t)} from registry...`,o.start();let l=await fetch(i,{method:`GET`,headers:{Authorization:`Basic ${s}`}});return o.stop(),l.ok||(await e.x(l,`Failed to get connector ${e.C(t)} from the registry`),process.exit(1)),await l.text()}return u.ok||(await e.x(u,`Failed to get connector ${e.C(t)} from the registry`),process.exit(1)),await u.text()}catch(r){o.stop(),e.w.error(`Failed to get connector ${e.C(t)} 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#i(t,n,r,i){let a=(0,_.default)(`Getting connector from account ${e.C(t)}...`).start();try{let o=Buffer.from(r).toString(`base64`),s=i?`?format=${i}`:``,c=await fetch(`${n}/accounts/${t}/connector${s}`,{method:`GET`,headers:{Authorization:`Basic ${o}`}});return a.stop(),c.ok||(await e.x(c,`Failed to get connector from account ${e.C(t)}`),process.exit(1)),await c.text()}catch(r){a.stop(),e.w.error(`Failed to get connector from account ${e.C(t)}: ${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)}}};const ot=`https://api.stackone.com`,st=`https://api.stackone-dev.com`,ct=`http://localhost:4000`;var lt=class{async execute({environment:t}={}){let n=t?.toLowerCase()??`production`;try{(0,C.intro)(`${i.default.inverse(` Initialize profile `)}`);let t=await(0,C.text)({message:`Profile label`,validate:e=>{if(!e||e.trim().length===0)return`The profile label is required`;if(e.includes(` `))return`The profile label cannot contain spaces`}});if((0,C.isCancel)(t))return(0,C.cancel)(`Configuration profile initialization cancelled`),process.exit(0);if(Ze(t)){let n=await(0,C.confirm)({message:`Configuration profile with name ${e.C(t)} already exists. Do you want to overwrite it?`});if((0,C.isCancel)(n)||!n)return(0,C.cancel)(`Configuration profile initialization cancelled`),process.exit(0)}let r;if(n===`production`)r=`https://api.stackone.com`;else if(n===`staging`)r=`https://api.stackone-dev.com`;else{let e=await(0,C.text)({message:`API URL`,placeholder:ct,initialValue:ct,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{new URL(e)}catch{return`Please enter a valid URL`}}});if((0,C.isCancel)(e))return(0,C.cancel)(`Configuration profile initialization cancelled`),process.exit(0);r=e}let a=await(0,C.password)({message:`API Key`,validate:e=>{if(!e||e.trim().length===0)return`API Key is required`}});if((0,C.isCancel)(a))return(0,C.cancel)(`Configuration profile initialization cancelled`),process.exit(0);Qe(t,{label:t,environment:n,apiUrl:r,apiKey:a}),(0,C.outro)(`${i.default.green(`✔`)} Configuration profile ${e.C(t)} initialized successfully!`),process.exit(0)}catch(t){t?.isTtyError?e.w.error(`Prompt couldn't be rendered in the current environment`):e.w.error(`Failed to initialize configuration profile: ${t}`),process.exit(1)}}};const ut=20,$={pending:`○`,acceptRemote:`●`,acceptLocal:`◐`,acceptBoth:`◑`,current:`◉`,arrow:`→`,check:`✓`,cross:`✗`,warning:`⚠`};var dt=class{constructor(e,t,n,r){this.conflicts=[],this.currentIndex=0,this.totalConflicts=0,this.currentCleanup=null,this.connectorId=t,this.localVersion=n,this.remoteVersion=r,this.conflicts=e.map(e=>({conflict:e,choice:e.type===`unchanged`?`remote`:`pending`})),this.totalConflicts=e.filter(e=>e.type===`conflict`).length}resetForReResolution(){this.currentIndex=0}async resolve(){return this.totalConflicts===0?{cancelled:!1,states:this.conflicts}:(this.moveToNextConflict(),new Promise(e=>{let t=(0,E.createInterface)({input:process.stdin,output:process.stdout});process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume(),this.render();let n=n=>{let r=n.toString();if(r===``){this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});return}if(r===`\x1B`&&n.length===1){this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});return}if(r.startsWith(`\x1B[`)){switch(r.slice(2)){case`D`:this.moveToPrevConflict(),this.render();break;case`C`:this.moveToNextConflict(),this.render();break}return}switch(r){case`r`:case`R`:this.setCurrentChoice(`remote`),this.advanceAfterChoice(t);break;case`l`:case`L`:this.setCurrentChoice(`local`),this.advanceAfterChoice(t);break;case`b`:case`B`:this.setCurrentChoice(`both`),this.advanceAfterChoice(t);break;case`\r`:case`
|
|
151
153
|
`:this.allResolved()?(this.cleanup(t),e({cancelled:!1,states:this.conflicts})):(this.moveToNextUnresolved(),this.render());break;case`q`:case`Q`:this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});break;case`a`:case`A`:this.acceptAllRemaining(`remote`),this.render();break;case`u`:case`U`:this.setCurrentChoice(`pending`),this.render();break}};process.stdin.on(`data`,n),this.currentCleanup=()=>{process.stdin.removeListener(`data`,n),process.stdin.isTTY&&process.stdin.setRawMode(!1),t.close()}}))}cleanup(e){this.currentCleanup?(this.currentCleanup(),this.currentCleanup=null):(process.stdin.isTTY&&process.stdin.setRawMode(!1),e.close())}advanceAfterChoice(e){this.allResolved()||this.moveToNextUnresolved(),this.render()}render(){e.v();let t=process.stdout.columns||80;this.renderHeader(t),this.renderProgressBar(t),this.renderCurrentConflict(t),this.renderControls(t)}renderHeader(t){let n=this.connectorId,r=`${this.localVersion} ${$.arrow} ${this.remoteVersion}`,a=Math.max(0,t-17),o=Math.floor(a/2),s=a-o,c=` `.repeat(o)+`CONFLICT RESOLVER`+` `.repeat(s);e.w.log(``),e.w.log(i.default.bgBlue.white.bold(c)),e.w.log(i.default.gray(this.centerText(n,t))),e.w.log(i.default.gray(this.centerText(r,t))),e.w.log(``)}renderProgressBar(t){let n=this.conflicts.filter(e=>e.conflict.type===`conflict`),r=this.getCurrentConflictIndex(),a=n.map((e,t)=>{let n=t===r,a,o;switch(e.choice){case`remote`:a=n?$.current:$.acceptRemote,o=i.default.green;break;case`local`:a=n?$.current:$.acceptLocal,o=i.default.yellow;break;case`both`:a=n?$.current:$.acceptBoth,o=i.default.cyan;break;default:a=n?$.current:$.pending,o=n?i.default.white:i.default.gray}return o(a)}),o=n.filter(e=>e.choice!==`pending`).length,s=` Conflict ${r+1} of ${this.totalConflicts} • ${o}/${this.totalConflicts} resolved `;e.w.log(i.default.gray(this.centerText(s,t))),e.w.log(this.centerText(a.join(` `),t)),e.w.log(``)}renderCurrentConflict(t){let n=this.conflicts[this.currentIndex];if(!n||n.conflict.type!==`conflict`)return;let r=n.conflict;if(e.w.log(i.default.gray(`_`.repeat(t))),e.w.log(`
|
|
152
154
|
|
|
153
155
|
`),r.local){let t=n.choice===`local`||n.choice===`both`?i.default.yellow.bold(`${$.check} LOCAL (keeping)`):i.default.red.bold(`${$.cross} LOCAL (removing)`),a=r.local.split(`
|
|
@@ -161,9 +163,9 @@ Available skills
|
|
|
161
163
|
`),l=a.length>20?`\n${i.default.gray(`... and ${a.length-20} more lines`)}`:``;e.w.log(`${t}\n\n${c}${l}`)}e.w.log(`
|
|
162
164
|
|
|
163
165
|
`),e.w.log(i.default.gray(`_`.repeat(t))),e.w.log(``)}renderControls(t){let n=[i.default.green(`[R] Accept Remote`),i.default.yellow(`[L] Keep Local`),i.default.cyan(`[B] Keep Both`),i.default.gray(`[U] Undo`)],r=[i.default.gray(`[←/→] Navigate`),i.default.gray(`[A] Accept all remaining`)],a=this.allResolved()?[i.default.green.bold(`[Enter] Apply Changes`),i.default.gray(`[Esc] Cancel`)]:[i.default.gray(`[Enter] Next Unresolved`),i.default.gray(`[Esc] Cancel`)];e.w.log(this.centerText(n.join(` `),t)),e.w.log(``),e.w.log(this.centerText(r.join(` `),t)),e.w.log(``),e.w.log(this.centerText(a.join(` `),t)),this.allResolved()&&(e.w.log(``),e.w.log(i.default.green.bold(this.centerText(`✓ All conflicts resolved!`,t))))}renderFinalSummary(){e.v();let t=this.conflicts.filter(e=>e.conflict.type===`conflict`),n=0,r=0,a=0;for(let e of t)switch(e.choice){case`remote`:n++;break;case`local`:r++;break;case`both`:a++;break}let o=[i.default.green.bold(`Conflict resolution complete`),``,`${i.default.bold(this.totalConflicts)} conflicts resolved:`,``,`${i.default.green($.acceptRemote)} Accepted remote: ${n}`,`${i.default.yellow($.acceptLocal)} Kept local: ${r}`,`${i.default.cyan($.acceptBoth)} Kept both: ${a}`];e.w.box(o.join(`
|
|
164
|
-
`))}renderCancelled(){e.v(),e.w.log(i.default.yellow(`Conflict resolution cancelled`)),e.w.log(``),e.w.log(`No changes were made to your local connector file.`)}getCurrentConflictIndex(){let e=-1;for(let t=0;t<=this.currentIndex&&t<this.conflicts.length;t++)this.conflicts[t].conflict.type===`conflict`&&e++;return e}moveToNextConflict(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToPrevConflict(){for(let e=this.currentIndex-1;e>=0;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=this.conflicts.length-1;e>this.currentIndex;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToNextUnresolved(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}}setCurrentChoice(e){this.conflicts[this.currentIndex]?.conflict.type===`conflict`&&(this.conflicts[this.currentIndex].choice=e)}allResolved(){return this.conflicts.filter(e=>e.conflict.type===`conflict`).every(e=>e.choice!==`pending`)}acceptAllRemaining(e){for(let t of this.conflicts)t.conflict.type===`conflict`&&t.choice===`pending`&&(t.choice=e)}centerText(e,t){let n=this.stripAnsi(e),r=Math.max(0,Math.floor((t-n.length)/2));return` `.repeat(r)+e}stripAnsi(e){return e.replace(/\x1b\[[0-9;]*m/g,``)}getResolvedContent(){let e=[];for(let t of this.conflicts)if(t.conflict.type===`unchanged`)e.push(t.conflict.content||``);else if(t.conflict.type===`conflict`)switch(t.choice){case`remote`:t.conflict.remote&&e.push(t.conflict.remote);break;case`local`:t.conflict.local&&e.push(t.conflict.local);break;case`both`:t.conflict.local&&e.push(t.conflict.local),t.conflict.remote&&e.push(t.conflict.remote);break;case`pending`:t.conflict.remote&&e.push(t.conflict.remote);break}return e.join(``)}};const
|
|
165
|
-
`).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,T.diffLines)(e,t).some(e=>e.added||e.removed)}async#s(t,n,r,i,a){e.w.log(``);let o=await(0,C.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,C.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,T.diffLines)(t,n),s=this.#u(o);if(s.length===0)return e.w.info(`No conflicts to resolve.`),n;let c=new
|
|
166
|
-
`);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,_.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 et(`${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 ft=`https://api.stackone.com`;var pt=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&&!Je(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=Xe();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?qe(t):{apiUrl:r??ft,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??ft;if(c.isDirectory()){let t=_t(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,_.default)(`📤 Pushing connector in ${(0,h.basename)(t)}...`).start();try{let o=gt(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=mt(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,C.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,C.isCancel)(v)||v===`cancel`?((0,C.cancel)(`Push cancelled`),!1):((0,m.writeFileSync)(n,ht(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 mt=e=>e.match(/^\s*version: (\S+)/m)?.[1],ht=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),gt=t=>{let n=(0,w.loadConnector)(t),r=(0,w.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.`)},_t=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(..._t(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},vt=S.z.object({provider_key:S.z.string().optional(),provider_version:S.z.string().optional(),auth_config_key:S.z.string(),environment:S.z.string().default(`production`),organization_id:S.z.string().default(`cli-organization-id`),account_id:S.z.string().default(`cli-account-secure-id`),project_id:S.z.string().default(`cli-project-secure-id`),credentials:S.z.record(S.z.string(),S.z.any()).default({})}),yt=S.z.record(S.z.string(),S.z.any()),bt=S.z.object({path:S.z.record(S.z.string(),S.z.any()).default({}),queryParams:S.z.record(S.z.string(),S.z.any()).default({}),header:S.z.record(S.z.string(),S.z.any()).default({}),body:S.z.record(S.z.string(),S.z.any()).default({})}),xt=`https://api.stackone.com`;var St=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&&!Je(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=Xe();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?qe(l):{apiUrl:f??xt,apiKey:p};(0,S.isMissing)(a)&&(0,S.isMissing)(o)&&(e.w.error(`A valid account or account ID is required to run an action`),process.exit(1));let _;if((0,S.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??xt,g?.apiKey,h)}else _=this.#e(t);else (0,S.notMissing)(o)&&(_=await this.#c(o,g?.apiUrl??xt,g?.apiKey));let v=(0,S.notMissing)(n)?this.#r(n,t):_;(0,S.isMissing)(v)&&(e.w.error(`A valid connector is required to run an action.`),process.exit(1));let y=(0,S.notMissing)(v?.actions)?Object.keys(v?.actions).length:0,b=(0,S.notMissing)(v?.actions)?Object.keys(v.actions)[y-1]:void 0,x=(0,S.notMissing)(b)?v?.actions?.[b]?.id:void 0,C=((0,S.notMissing)(r)&&!r?.startsWith(`${v.key}_`)?`${v.key}_${r}`:r)??x;(0,S.isMissing)(C)&&(e.w.error(`A valid action ID is required to run an action`),process.exit(1));let w=(0,S.notMissing)(o)?await this.#l(o,g?.apiUrl??xt,g?.apiKey):{},T=(0,S.notMissing)(a)?this.#i(a,v.key??`unknown`,v.version??`unknown`):void 0,E=(0,S.notMissing)(c)?this.#u(c):{},D={...w,...T,credentials:{...w.credentials??{},...E}};(0,S.isMissing)(D)&&(e.w.error(`A valid account data is required to run an action.`),process.exit(1));let ee=v.actions?.[C];(0,S.isMissing)(ee)&&(e.w.error(`Action ID ${e.C(C)} not found in the connector ${e.C(v.key)}@${e.C(v.version)}.`),process.exit(1));let O=(0,S.notMissing)(s)?this.#d(s,C):{path:{},queryParams:{},header:{},body:{}},k=Date.now(),A=await this.#f({connector:v,actionId:C,account:D,queryParams:{...O.queryParams,...d?{debug:`true`}:{}},pathParams:O.path,body:O.body,headers:O.header}),j=Date.now()-k;if((0,S.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(C)} 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,w.loadConnector)(e)}catch{}return t?this.#n(t):void 0};#t=t=>{try{return(0,w.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,w.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,S.isMissing)(n)&&(e.w.error(`A valid connector is required to load an action.`),process.exit(1));let i=`${this.#t(n)} - ${r.split(`
|
|
166
|
+
`))}renderCancelled(){e.v(),e.w.log(i.default.yellow(`Conflict resolution cancelled`)),e.w.log(``),e.w.log(`No changes were made to your local connector file.`)}getCurrentConflictIndex(){let e=-1;for(let t=0;t<=this.currentIndex&&t<this.conflicts.length;t++)this.conflicts[t].conflict.type===`conflict`&&e++;return e}moveToNextConflict(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToPrevConflict(){for(let e=this.currentIndex-1;e>=0;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=this.conflicts.length-1;e>this.currentIndex;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToNextUnresolved(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}}setCurrentChoice(e){this.conflicts[this.currentIndex]?.conflict.type===`conflict`&&(this.conflicts[this.currentIndex].choice=e)}allResolved(){return this.conflicts.filter(e=>e.conflict.type===`conflict`).every(e=>e.choice!==`pending`)}acceptAllRemaining(e){for(let t of this.conflicts)t.conflict.type===`conflict`&&t.choice===`pending`&&(t.choice=e)}centerText(e,t){let n=this.stripAnsi(e),r=Math.max(0,Math.floor((t-n.length)/2));return` `.repeat(r)+e}stripAnsi(e){return e.replace(/\x1b\[[0-9;]*m/g,``)}getResolvedContent(){let e=[];for(let t of this.conflicts)if(t.conflict.type===`unchanged`)e.push(t.conflict.content||``);else if(t.conflict.type===`conflict`)switch(t.choice){case`remote`:t.conflict.remote&&e.push(t.conflict.remote);break;case`local`:t.conflict.local&&e.push(t.conflict.local);break;case`both`:t.conflict.local&&e.push(t.conflict.local),t.conflict.remote&&e.push(t.conflict.remote);break;case`pending`:t.conflict.remote&&e.push(t.conflict.remote);break}return e.join(``)}};const ft=`https://api.stackone.com`,pt=3;var mt=class{async execute({profile:t,connector:n,outputPath:r,apiUrl:a,apiKey:o,owner:s}={}){if((0,S.isMissing)(n)&&(e.w.error(`Connector identifier is required`),e.w.log(`Please provide a connector identifier using the ${e.C(`--connector`)} option in the format: ${e.C(`provider_key@version`)} or ${e.C(`provider_key`)}`),e.w.log(`If no version is specified, the latest version will be pulled.`),process.exit(1)),!t&&!o&&(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&&o&&(e.w.error(`Please provide either a profile or an API key, not both`),process.exit(1)),t&&a&&e.w.warn(`Specifying ${e.C(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),t&&!Ze(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=$e();n.length>0&&(e.w.info(`Available configuration profiles:`),n.forEach(t=>{e.w.log(` - ${i.default.blue(t)}`)})),process.exit(1)}let c=t?Xe(t):{apiUrl:a??ft,apiKey:o};c?.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));let l=c.apiUrl??ft,[u,d]=n.split(`@`),f=await this.#f(u,l,c.apiKey,d??`latest`,s),p=this.#e(f),m=p.version??`unknown`,h=this.#t(r,p.key,m),g=this.#r(h),_=g===null,v=f;if(!_){let t=this.#i(g,h);t&&(e.w.warn(t.message),t.errors.length>0&&e.y(t.errors,!1),e.w.log(``));let r=t?void 0:this.#e(g);if(this.#o(g,f)){this.#a(g,f,h);let t=r?.version??`unknown`,i=await this.#s(g,f,n,t,m);i.action===`cancel`&&((0,C.cancel)(`Pull cancelled`),process.exit(0)),i.action===`keep-local`&&(e.w.log(``),e.w.info(`Keeping local version. No changes made.`),process.exit(0)),i.action===`interactive-cancel`&&process.exit(0),i.action===`interactive`&&(v=i.resolvedContent)}else e.w.info(`No changes detected in connector configuration.`),process.exit(0)}let y=(0,w.validateYamlConnector)(v).connector,b=y?.key??p.key,x=y?.version??m,T=this.#t(r,b,x),E=T;if(T!==h){let t=await this.#n(T);e.w.log(``),t!==void 0&&(E=t)}await this.#d(E,v),_?e.w.success(`Connector ${e.C(b)}@${e.C(x)} pulled successfully (new connector)`):e.w.success(`Connector ${e.C(b)}@${e.C(x)} updated successfully`);let D=b===p.key?e.C(b):`${e.C(p.key)} ${i.default.whiteBright(`→`)} ${e.C(b)}`,ee=x===m?e.C(x):`${e.C(m)} ${i.default.whiteBright(`→`)} ${e.C(x)}`,O=E===h?e.C(E):`${e.C(h)}\n ${i.default.whiteBright(`→`)} ${e.C(E)}`;e.w.log(`\n${i.default.blue.inverse(` CONNECTOR DETAILS `)}\n`),e.w.log(` Provider: ${D}`),e.w.log(` Version: ${ee}`),e.w.log(` Output file: ${O}`),process.exit(0)}#e(t){let n=(0,w.validateYamlConnector)(t),r=n?.errors??[];if(n.success)return n.connector;e.w.error(`Connector pulled from the registry is not valid`),e.w.log(`Please make sure you are using the latest version of the StackOne CLI by running ${e.C(`stackone update`)}`),r.length>0&&e.y(r,!0),process.exit(1)}#t(t,n,r){let i=`${n}_v${r.replaceAll(`.`,`-`)}.s1.yaml`;return t?(m.default.existsSync(t)&&(m.default.statSync(t).isDirectory()||(e.w.error(`Output path ${e.C(t)} is not a directory`),e.w.log(`Please provide a valid directory path to store connectors or use the default path.`),process.exit(1))),h.default.resolve(t,n,i)):h.default.resolve(process.cwd(),`connectors`,n,i)}async#n(t){if(!m.default.existsSync(t))return;let n=h.default.basename(t),r=h.default.dirname(t);e.w.warn(`File ${e.C(n)} already exists at ${e.C(r)}`);let i=await(0,C.select)({message:`How would you like to proceed?`,options:[{value:`override`,label:`Override existing file`,hint:`Replace the existing file with the new content`},{value:`rename`,label:`Save with a different name`,hint:`Provide a new filename for the connector`},{value:`cancel`,label:`Cancel`,hint:`Abort the pull operation`}]});if(((0,C.isCancel)(i)||i===`cancel`)&&((0,C.cancel)(`Operation cancelled. No local changes were made.`),process.exit(0)),i===`override`)return;let a=await(0,C.text)({message:`Enter the new filename:`,placeholder:n,validate:e=>{if(!e||e.trim()===``)return`Filename cannot be empty`;if(!e.endsWith(`.s1.yaml`))return`Filename must end with .s1.yaml`;let t=h.default.join(r,e.trim());if(m.default.existsSync(t))return`File ${e} already exists`}});return(0,C.isCancel)(a)&&((0,C.cancel)(`Operation cancelled. No local changes were made.`),process.exit(0)),h.default.join(r,a.trim())}#r(e){if(!m.default.existsSync(e))return null;try{return m.default.readFileSync(e,`utf-8`)}catch{return null}}#i(t,n){try{let r=(0,w.validateYamlConnector)(t);if(!r.success){let t=r.errors??[];return{message:`Local connector ${e.C(h.default.basename(n))} has validation errors:`,errors:t}}}catch(t){return{message:`Local connector ${e.C(h.default.basename(n))} could not be validated: ${t.message}`,errors:[]}}return null}#a(t,n,r){let a=(0,T.diffLines)(t,n);if(!a.some(e=>e.added||e.removed)){e.w.info(`No changes detected in connector configuration.`);return}e.w.log(`${i.default.blue.inverse(` CHANGES `)}\n`),e.w.log(i.default.gray(`--- local: ${r}`)),e.w.log(i.default.gray(`+++ remote: StackOne Registry`)),e.w.log(``);let o=0,s=0;for(let t of a){let n=t.value.split(`
|
|
167
|
+
`).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,T.diffLines)(e,t).some(e=>e.added||e.removed)}async#s(t,n,r,i,a){e.w.log(``);let o=await(0,C.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,C.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,T.diffLines)(t,n),s=this.#u(o);if(s.length===0)return e.w.info(`No conflicts to resolve.`),n;let c=new dt(s,r,i,a);for(;;){if((await c.resolve()).cancelled)return null;let t=c.getResolvedContent(),n=(0,w.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(`
|
|
168
|
+
`);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,_.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 rt(`${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 ht=`https://api.stackone.com`;var gt=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&&!Ze(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=$e();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?Xe(t):{apiUrl:r??ht,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??ht;if(c.isDirectory()){let t=bt(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,_.default)(`📤 Pushing connector in ${(0,h.basename)(t)}...`).start();try{let o=yt(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=_t(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,C.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,C.isCancel)(v)||v===`cancel`?((0,C.cancel)(`Push cancelled`),!1):((0,m.writeFileSync)(n,vt(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 _t=e=>e.match(/^\s*version: (\S+)/m)?.[1],vt=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),yt=t=>{let n=(0,w.loadConnector)(t),r=(0,w.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.`)},bt=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(...bt(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},xt=S.z.object({provider_key:S.z.string().optional(),provider_version:S.z.string().optional(),auth_config_key:S.z.string(),environment:S.z.string().default(`production`),organization_id:S.z.string().default(`cli-organization-id`),account_id:S.z.string().default(`cli-account-secure-id`),project_id:S.z.string().default(`cli-project-secure-id`),credentials:S.z.record(S.z.string(),S.z.any()).default({})}),St=S.z.record(S.z.string(),S.z.any()),Ct=S.z.object({path:S.z.record(S.z.string(),S.z.any()).default({}),queryParams:S.z.record(S.z.string(),S.z.any()).default({}),header:S.z.record(S.z.string(),S.z.any()).default({}),body:S.z.record(S.z.string(),S.z.any()).default({})}),wt=`https://api.stackone.com`;var Tt=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&&!Ze(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=$e();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?Xe(l):{apiUrl:f??wt,apiKey:p};(0,S.isMissing)(a)&&(0,S.isMissing)(o)&&(e.w.error(`A valid account or account ID is required to run an action`),process.exit(1));let _;if((0,S.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??wt,g?.apiKey,h)}else _=this.#e(t);else (0,S.notMissing)(o)&&(_=await this.#c(o,g?.apiUrl??wt,g?.apiKey));let v=(0,S.notMissing)(n)?this.#r(n,t):_;(0,S.isMissing)(v)&&(e.w.error(`A valid connector is required to run an action.`),process.exit(1));let y=(0,S.notMissing)(v?.actions)?Object.keys(v?.actions).length:0,b=(0,S.notMissing)(v?.actions)?Object.keys(v.actions)[y-1]:void 0,x=(0,S.notMissing)(b)?v?.actions?.[b]?.id:void 0,C=((0,S.notMissing)(r)&&!r?.startsWith(`${v.key}_`)?`${v.key}_${r}`:r)??x;(0,S.isMissing)(C)&&(e.w.error(`A valid action ID is required to run an action`),process.exit(1));let w=(0,S.notMissing)(o)?await this.#l(o,g?.apiUrl??wt,g?.apiKey):{},T=(0,S.notMissing)(a)?this.#i(a,v.key??`unknown`,v.version??`unknown`):void 0,E=(0,S.notMissing)(c)?this.#u(c):{},D={...w,...T,credentials:{...w.credentials??{},...E}};(0,S.isMissing)(D)&&(e.w.error(`A valid account data is required to run an action.`),process.exit(1));let ee=v.actions?.[C];(0,S.isMissing)(ee)&&(e.w.error(`Action ID ${e.C(C)} not found in the connector ${e.C(v.key)}@${e.C(v.version)}.`),process.exit(1));let O=(0,S.notMissing)(s)?this.#d(s,C):{path:{},queryParams:{},header:{},body:{}},k=Date.now(),A=await this.#f({connector:v,actionId:C,account:D,queryParams:{...O.queryParams,...d?{debug:`true`}:{}},pathParams:O.path,body:O.body,headers:O.header}),j=Date.now()-k;if((0,S.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(C)} 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,w.loadConnector)(e)}catch{}return t?this.#n(t):void 0};#t=t=>{try{return(0,w.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,w.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,S.isMissing)(n)&&(e.w.error(`A valid connector is required to load an action.`),process.exit(1));let i=`${this.#t(n)} - ${r.split(`
|
|
167
169
|
`).map((e,t)=>t===0?e:` ${e}`).join(`
|
|
168
|
-
`)}`;return this.#n(i)};#i=(t,n,r)=>{let i=t;try{i=m.default.readFileSync(t,`utf-8`)}catch{}try{let e=
|
|
169
|
-
Exiting watch mode...`)),process.exit(0)};Et(),e.w.start(`Validating connectors...`);let c=await jt(o);t=Ot(t,c||{}),kt(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 Nt(n):[n];if(!(!r||r.length===0)){e.v(),a.stop(),Et(),e.w.log(i.default.gray(`File change detected: ${n}`)),e.w.start(`Validating connectors...`);for(let e of r){let n=await jt(e);t=Ot(t,n||{})}kt(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 jt(o,e.w),process.exit(0)}};const Ot=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},kt=(t,n)=>{e.v(),Et();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`)},At=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 At(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},jt=async(t,n)=>{let r=await(0,A.stat)(t),a={};if(r.isDirectory()){let r=await At(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 Mt(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 Mt(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 Nt(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},Mt=async(t,n)=>{let r=(0,w.validateYamlConnector)((0,w.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`),[]},Nt=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{}};function Pt(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(e)try{(0,o.initUnifiedApiTelemetry)({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 Ft=`@stackone/cli`,It=2880*60*1e3,Lt=(0,l.join)((0,c.homedir)(),`.stackone`),Rt=(0,l.join)(Lt,`version-check.json`),zt=(e=!1)=>{let t=Ut(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=Bt();e&&Vt(e)&&Ht(e),Wt({lastCheckTime:n})}},Bt=()=>{try{return(0,f.execSync)(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},Vt=e=>{try{let t=Ct();return D.default.gt(e,t)}catch{return!1}},Ht=t=>{let n=Ct(),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)},Ut=()=>{try{if(!(0,s.existsSync)(Rt))return null;let e=(0,s.readFileSync)(Rt,`utf-8`);return JSON.parse(e)}catch{return null}},Wt=e=>{try{(0,s.existsSync)(Lt)||(0,s.mkdirSync)(Lt,{recursive:!0}),(0,s.writeFileSync)(Rt,JSON.stringify(e,null,2),`utf-8`)}catch{}};var Gt=class{constructor(e=new a.Command,t=Ct()){this.program=e,this.version=t,Pt(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let t=new ot,n=new pt,r=new dt,o=new Qe,s=new nt,c=new Dt,l=new Re,u=new Ue,d=new J,f=new Oe,p=new Be,m=new We,h=new St,g=new Tt;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)),h.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 _=this.program.command(`agent`).description(`StackOne agent commands`);_.command(`setup`).option(`-g, --global`,`Setup global configuration (default)`).option(`-l, --local`,`Setup local project configuration`).option(`--legacy`,`Use email/password login instead of browser-based auth`).description(`Setup StackOne agent (global or local)`).action(t=>{t.global&&t.local&&(e.w.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1)),t.local?u.execute({legacy:!!t.legacy}):l.execute({legacy:!!t.legacy})}),_.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{d.execute()}),_.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})}),_.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})}),_.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=>{g.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)}`),zt(!0),process.exit(0)})}run(){process.argv.includes(`version`)||zt(),this.program.parse(process.argv)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return Gt}});
|
|
170
|
+
`)}`;return this.#n(i)};#i=(t,n,r)=>{let i=t;try{i=m.default.readFileSync(t,`utf-8`)}catch{}try{let e=xt.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,S.isMissing)(t)||(0,S.isMissing)(n)||(0,S.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,_.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 rt(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,S.isMissing)(t)||(0,S.isMissing)(n)||(0,S.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch connector`),process.exit(1));let i=(0,_.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,S.isMissing)(t)||(0,S.isMissing)(n)||(0,S.isMissing)(r))&&(e.w.error(`Account ID, API URL, and API key are required to fetch account information.`),process.exit(1));let i=(0,_.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 St.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 Ct.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,w.runAction)({mode:`action_id`,actionId:n,account:r,connector:t,pathParams:a,queryParams:o,body:s,headers:c,getHttpClient:async()=>new ee.HttpClient});if(l.response?.successful){let e={...this.#p(o,l.steps),...(0,S.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,S.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 Et=()=>{try{let e=(0,h.join)((0,h.dirname)((0,k.fileURLToPath)(require(`url`).pathToFileURL(__filename).href)),`..`,`package.json`);return JSON.parse((0,m.readFileSync)(e,`utf8`)).version}catch{return`unknown`}},Dt=(0,O.promisify)(f.exec);var Ot=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=(0,_.default)(),this.currentVersion=Et()}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 Dt(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return D.default.gt(e,t)}isUsingVolta(){if(typeof process.env.VOLTA_HOME!=`string`||process.env.VOLTA_HOME.length===0)return!1;let e=(0,l.join)(process.env.VOLTA_HOME,`bin`),t=(0,l.join)(e,`stackone`),n=(0,l.join)(e,`stackone.exe`);return(0,s.existsSync)(t)||(0,s.existsSync)(n)}async performUpdate(t){let n=this.isUsingVolta();this.spinner.text=`Updating to latest version (${e.C(t)})...`,this.spinner.start();try{await Dt(n?`volta install ${this.packageName}@latest`:`npm install -g ${this.packageName}@latest`,{encoding:`utf-8`}),this.spinner.stop(),e.w.success(`StackOne CLI updated successfully to latest version (${e.C(t)})`)}catch{this.spinner.stop();let e=n?`volta install ${this.packageName}@latest`:`npm install -g ${this.packageName}@latest`;throw Error(`Failed to install update. Please try manually: ${e}`)}}};const kt=()=>{e.w.log(`${i.default.gray.inverse(` CONNECTORS VALIDATION `)} ${i.default.yellow.inverse(` WATCH MODE `)}\n`)};var At=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,a=(0,_.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(`
|
|
171
|
+
Exiting watch mode...`)),process.exit(0)};kt(),e.w.start(`Validating connectors...`);let c=await Pt(o);t=jt(t,c||{}),Mt(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 It(n):[n];if(!(!r||r.length===0)){e.v(),a.stop(),kt(),e.w.log(i.default.gray(`File change detected: ${n}`)),e.w.start(`Validating connectors...`);for(let e of r){let n=await Pt(e);t=jt(t,n||{})}Mt(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 Pt(o,e.w),process.exit(0)}};const jt=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Mt=(t,n)=>{e.v(),kt();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`)},Nt=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 Nt(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Pt=async(t,n)=>{let r=await(0,A.stat)(t),a={};if(r.isDirectory()){let r=await Nt(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 Ft(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 Ft(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 It(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},Ft=async(t,n)=>{let r=(0,w.validateYamlConnector)((0,w.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`),[]},It=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{}};function Lt(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(e)try{(0,o.initUnifiedApiTelemetry)({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 Rt=`@stackone/cli`,zt=2880*60*1e3,Bt=(0,l.join)((0,c.homedir)(),`.stackone`),Vt=(0,l.join)(Bt,`version-check.json`),Ht=(e=!1)=>{let t=Kt(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=Ut();e&&Wt(e)&&Gt(e),qt({lastCheckTime:n})}},Ut=()=>{try{return(0,f.execSync)(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},Wt=e=>{try{let t=Et();return D.default.gt(e,t)}catch{return!1}},Gt=t=>{let n=Et(),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)},Kt=()=>{try{if(!(0,s.existsSync)(Vt))return null;let e=(0,s.readFileSync)(Vt,`utf-8`);return JSON.parse(e)}catch{return null}},qt=e=>{try{(0,s.existsSync)(Bt)||(0,s.mkdirSync)(Bt,{recursive:!0}),(0,s.writeFileSync)(Vt,JSON.stringify(e,null,2),`utf-8`)}catch{}};var Jt=class{constructor(e=new a.Command,t=Et()){this.program=e,this.version=t,Lt(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let t=new lt,n=new gt,r=new mt,o=new tt,s=new at,c=new At,l=new Ve,u=new Ke,d=new J,f=new Oe,p=new Ue,m=new qe,h=new Tt,g=new Ot;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)),h.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 _=this.program.command(`agent`).description(`StackOne agent commands`);_.command(`setup`).option(`-g, --global`,`Setup global configuration (default)`).option(`-l, --local`,`Setup local project configuration`).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(`Setup StackOne agent (global or local)`).action(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,i=t.passwordStdin===!0;r&&i&&(e.w.error(`--password and --password-stdin are mutually exclusive. Please provide only one.`),process.exit(1)),(n||r||i)&&!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)),i&&(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 a={email:t.email,password:t.password,passwordFromStdin:i};t.local?u.execute({legacy:!!t.legacy,credentials:a}):l.execute({legacy:!!t.legacy,credentials:a})}),_.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{d.execute()}),_.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})}),_.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})}),_.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=>{g.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)}`),Ht(!0),process.exit(0)})}run(){process.argv.includes(`version`)||Ht(),this.program.parse(process.argv)}};Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return Jt}});
|
|
@@ -122,32 +122,34 @@ If you continue to see this error, try running:`)),y.log(w.cyan(` stackone agen
|
|
|
122
122
|
`)),process.exit(1)}}},Wt=class{async execute(){y.log(w.blue.bold(`🧹 StackOne Agent Cleanup
|
|
123
123
|
`));try{let e=J(`Removing stored configuration...`).start();await p(),e.succeed(`Removed ~/.stackone/agent-config.json`);let t=J(`Removing MCP servers from Claude...`).start(),n=0;h(a(),_())&&n++,h(m(process.cwd()),s())&&n++,n>0?t.succeed(`Removed ${n} MCP server(s) from Claude`):t.warn(`No MCP servers found in Claude (already removed or not configured)`),y.success(`Cleanup complete!`),y.log(w.white(`
|
|
124
124
|
What was removed:`)),y.log(w.cyan(` • ~/.stackone/agent-config.json`)),n>0&&y.log(w.cyan(` • MCP server entries from Claude configuration`)),y.log(w.dim(`
|
|
125
|
-
To authenticate again:`)),y.log(w.cyan(` stackone agent setup`),w.dim(`(for global setup)`)),y.log(w.cyan(` stackone agent setup --local`),w.dim(`(for local project setup)`)),y.log(``),process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}};const Gt=`stackone-cli`,
|
|
126
|
-
`)),process.exit(1)),
|
|
127
|
-
`));try{let t=process.cwd(),n=await Ae(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await Ae(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r)
|
|
128
|
-
|
|
125
|
+
To authenticate again:`)),y.log(w.cyan(` stackone agent setup`),w.dim(`(for global setup)`)),y.log(w.cyan(` stackone agent setup --local`),w.dim(`(for local project setup)`)),y.log(``),process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}};const Gt=(e,t)=>e?!!(t?.email||t?.password||t?.passwordFromStdin||process.env.STACKONE_EMAIL?.trim()||process.env.STACKONE_PASSWORD?.trim()):!1,Kt=`stackone-cli`,qt=async e=>{let t=`HTTP ${e.status}: ${e.statusText}`;try{let n=await e.text(),r=JSON.parse(n);return r.error_description||r.error||t}catch{return t}};var Jt=class{constructor(e){this.baseUrl=e||process.env.AUTH_SERVER_URL||`https://idp-api.stackone.com`}async login(e,t){try{let n=await fetch(`${this.baseUrl}/auth/sign-in/mcp`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({email:e,password:t})});if(!n.ok)return{success:!1,error:await qt(n)};let r=await n.json();return r.apiKey?{success:!0,apiKey:r.apiKey}:{success:!1,error:`Invalid response format`}}catch(e){return{success:!1,error:e instanceof Error?e.message:`Network error occurred`}}}async validateKey(e){try{let t=await fetch(`${this.baseUrl}/api-key/verify`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e})});return t.ok?await t.json():{valid:!1,error:await qt(t)}}catch(e){return{valid:!1,error:e instanceof Error?e.message:`Network error occurred`}}}async requestDeviceCode(){let e=await fetch(`${this.baseUrl}/api/auth/device/code`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({client_id:Kt})});if(!e.ok)throw Error(await qt(e));return await e.json()}async pollDeviceToken(e){try{let t=await fetch(`${this.baseUrl}/api/auth/device/token`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({grant_type:`urn:ietf:params:oauth:grant-type:device_code`,device_code:e,client_id:Kt})});if(t.ok)return{token:await t.json()};try{let e=await t.json();if(e.error)return{error:e}}catch{}return{error:{error:`server_error`,error_description:`HTTP ${t.status}: ${t.statusText}`}}}catch(e){return{error:{error:`network_error`,error_description:e instanceof Error?e.message:`Network error`}}}}async createApiKey(e){let t=10080*60,n=await fetch(`${this.baseUrl}/api/auth/api-key/create`,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${e}`},body:JSON.stringify({prefix:`falcon_key_`,expiresIn:t,name:`CLI Auth Key`})});if(!n.ok)throw Error(await qt(n));let r=await n.json(),i=new Date(Date.now()+t*1e3).toISOString();return{key:r.key,expiresAt:i}}};const Yt=e=>new Promise(t=>{let n=he(),r,i;n===`darwin`?(r=`open`,i=[e]):n===`win32`?(r=`rundll32`,i=[`url.dll,FileProtocolHandler`,e]):(r=`xdg-open`,i=[e]),Se(r,i,e=>{t(!e)})}),Xt=async(e,t)=>{let n=await e.requestDeviceCode(),r=await Yt(n.verification_uri_complete),i=`Confirmation code: ${n.user_code}`;t(r?`Browser opened. ${i}\nWaiting for authentication...`:`Could not open browser. Please visit:\n ${n.verification_uri_complete}\n\n${i}`);let a=n.interval*1e3,o=0,s=Date.now()+n.expires_in*1e3;for(;Date.now()<s;){await new Promise(e=>setTimeout(e,a));let r=await e.pollDeviceToken(n.device_code);if(`token`in r){t(`Authenticated. Creating API key...`);let n=await e.createApiKey(r.token.access_token),i=await e.validateKey(n.key);return{success:!0,apiKey:n.key,email:i.email,userId:i.userId,expiresAt:n.expiresAt}}let i=r.error.error;if(i===`authorization_pending`){o=0;continue}if(i===`slow_down`){o=0,await new Promise(e=>setTimeout(e,a));continue}if(i===`expired_token`)return{success:!1,error:`Authentication session expired`};if(i===`access_denied`)return{success:!1,error:`Access denied by user`};if(o++,o>=5)return{success:!1,error:`Polling failed: ${r.error.error_description??`unknown error`}`}}return{success:!1,error:`Authentication timed out`}},Zt=new Jt,Qt=async()=>{let e=Pe({input:Me,output:Ne}),t=await new Promise(t=>{e.question(w.white(`Email: `),e=>{t(e.trim())})});return e.close(),t||(y.error(`Email is required`),process.exit(1)),t},$t=async()=>{process.stdin.isTTY&&(y.error(`--password-stdin was set but no input was piped to stdin`),process.exit(1));let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString(`utf8`).replace(/[\r\n]+$/,``)},en=async e=>{let t=e.email?.trim()||process.env.STACKONE_EMAIL?.trim()||void 0,n;return e.passwordFromStdin?n=await $t():e.password?n=e.password:process.env.STACKONE_PASSWORD&&(n=process.env.STACKONE_PASSWORD),{email:t,password:n||void 0}},tn=async e=>{let t=await en(e),n=t.email;if(!n){let e=await ee();if(e?.email){y.log(w.dim(`Last used email: ${e.email}\n`));let{useExisting:t}=await je.prompt([{type:`confirm`,name:`useExisting`,message:`Sign in with this email?`,default:!0}]);n=t?e.email:await Qt()}else n=await Qt()}let r=t.password;r||=(e.passwordFromStdin&&(y.error(`Password is required`),process.exit(1)),(await je.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}])).password),r||(y.error(`Password is required`),process.exit(1)),y.log(``);let i=J(`Authenticating...`).start(),a=await Zt.login(n,r);(!a.success||!a.apiKey)&&(i.fail(`Authentication failed`),y.error(`${a.error||`Invalid credentials`}`),y.log(w.dim(`Please check your email and password and try again.
|
|
126
|
+
`)),process.exit(1)),i.succeed(`Login successful!`);let o=new Date(Date.now()+10080*60*1e3).toISOString();return{apiKey:a.apiKey,email:n,expiresAt:o}},nn=async()=>{let e=J(`Starting browser authentication...`).start(),t;try{t=await Xt(Zt,t=>{e.text=t})}catch(t){e.fail(`Authentication failed`),y.error(t instanceof Error?t.message:`Unknown error`),process.exit(1)}(!t.success||!t.apiKey)&&(e.fail(`Authentication failed`),y.error(t.error||`Unknown error`),process.exit(1)),e.succeed(`Login successful!`);let n=t.expiresAt||new Date(Date.now()+10080*60*1e3).toISOString();return{apiKey:t.apiKey,email:t.email??``,userId:t.userId,expiresAt:n}},rn=async(e,t={})=>{let{apiKey:n,email:r,userId:i,expiresAt:a}=e?await tn(t):await nn(),o={apiKey:n,userId:i??r,email:r,expiresAt:a,serverUrl:g()};return await f(o),o},an=e=>{let t=new Date(e),n=new Date,r=t.getTime()-n.getTime(),i=Math.floor(r/(1440*60*1e3)),a=Math.floor(r%(1440*60*1e3)/(3600*1e3)),o=t.toLocaleTimeString(`en-US`,{hour:`numeric`,minute:`2-digit`,hour12:!0});return`${t.toLocaleDateString(`en-US`,{weekday:`short`,month:`short`,day:`numeric`})} at ${o} (${i>0?`${i} days, ${a} hours`:`${a} hours`} from now)`};var on=class{async execute(e){y.log(w.blue.bold(`🤖 StackOne Agent Setup - Global Configuration
|
|
127
|
+
`));try{let t=process.cwd(),n=await Ae(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await Ae(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r)if(y.warn(`Existing local setup detected:`),n&&y.log(w.dim(` • CLAUDE.md found in current directory`)),r&&y.log(w.dim(` • .mcp.json found in current directory`)),y.log(``),Gt(!!e?.legacy,e?.credentials))y.log(w.dim(`Non-interactive credentials detected; proceeding without confirmation.
|
|
128
|
+
`));else{let{proceed:e}=await je.prompt([{type:`confirm`,name:`proceed`,message:`Re-authenticate globally despite existing local setup?`,default:!0}]);e||(y.log(w.dim(`
|
|
129
|
+
Setup cancelled.`)),process.exit(0)),y.log(``)}let i=await rn(!!e?.legacy,e?.credentials);y.success(`API key saved to ~/.stackone/agent-config.json`),y.log(w.white(`✓ Key expires at`),w.cyan(an(i.expiresAt))),te(await S(process.cwd(),i.apiKey));let o=J(`Setting up global MCP configuration...`).start();try{l(a(),_(),i.apiKey),o.succeed(`Installed to Claude (global)`),y.success(`Global setup complete!`),y.log(w.white(`Config location:`),w.cyan(`~/.claude.json`)),y.log(w.dim(`Token stored securely in Claude MCP server config.`)),y.log(w.blue(`
|
|
129
130
|
Verify:`),w.cyan(`claude mcp list`)),y.log(w.dim(`
|
|
130
131
|
💡 Tip: Run Claude without permission prompts:`),w.cyan(`claude --dangerously-skip-permissions`)),y.log(w.dim(`
|
|
131
|
-
To setup for a specific project, run:`),w.cyan(`stackone agent setup --local`)),y.log(``)}catch(e){o.fail(`Installation to Claude failed`),e instanceof Error&&y.error(e.message)}process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}};const
|
|
132
|
+
To setup for a specific project, run:`),w.cyan(`stackone agent setup --local`)),y.log(``)}catch(e){o.fail(`Installation to Claude failed`),e instanceof Error&&y.error(e.message)}process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}};const sn={research:`Researching API...`,"discover-actions":`Discovering available actions...`,"build-and-validate":`Building and validating connector...`};var cn=class{async execute(e){let{prompt:t,mode:n=`build`,maxTurns:r=25,verbose:i=!1}=e;t.trim()||(y.error(`A prompt is required.`),process.exit(1));let a;try{a=ne()}catch(e){e instanceof Error&&e.name===`CredentialMissingError`?(y.error(`
|
|
132
133
|
❌ Authentication Required
|
|
133
|
-
`),y.log(w.white("Run `stackone agent setup` to authenticate, then try again.\n"))):y.error(e instanceof Error?e.message:String(e)),process.exit(1)}let o=Mt(),s=le(t.trim());if(n===`build`&&s.isConnectorBuild&&s.provider)return this.executeOrchestratedBuild({provider:s.provider,category:s.category,apiKey:a,mcpServers:o,verbose:i});i&&(y.log(w.dim(`Mode: ${n}\n`)),o.length>0&&y.log(w.dim(`MCP Servers: ${o.map(e=>e.name).join(`, `)}\n`)));let c=null;try{for await(let e of ce({prompt:t.trim(),mode:n,apiKey:a,maxTurns:r,verbose:i,mcpServers:o,origin:`cli`}))
|
|
134
|
+
`),y.log(w.white("Run `stackone agent setup` to authenticate, then try again.\n"))):y.error(e instanceof Error?e.message:String(e)),process.exit(1)}let o=Mt(),s=le(t.trim());if(n===`build`&&s.isConnectorBuild&&s.provider)return this.executeOrchestratedBuild({provider:s.provider,category:s.category,apiKey:a,mcpServers:o,verbose:i});i&&(y.log(w.dim(`Mode: ${n}\n`)),o.length>0&&y.log(w.dim(`MCP Servers: ${o.map(e=>e.name).join(`, `)}\n`)));let c=null;try{for await(let e of ce({prompt:t.trim(),mode:n,apiKey:a,maxTurns:r,verbose:i,mcpServers:o,origin:`cli`}))un(e,e=>{c&&c.stop(),c=e})}catch(e){c?.fail(),y.error(w.red(`
|
|
134
135
|
Error: `+(e instanceof Error?e.message:String(e)))),process.exit(1)}c?.stop(),y.log(w.green(`
|
|
135
136
|
✓ Done
|
|
136
|
-
`))}async executeOrchestratedBuild(e){let{provider:t,category:n,verbose:r}=e,i=n?` (${n})`:``;y.log(w.bold(`\nOrchestrated build: ${t}${i}\n`));let a=null,o=new Map;try{for await(let t of jt(e))switch(t.type){case`phase_start`:{let e=
|
|
137
|
+
`))}async executeOrchestratedBuild(e){let{provider:t,category:n,verbose:r}=e,i=n?` (${n})`:``;y.log(w.bold(`\nOrchestrated build: ${t}${i}\n`));let a=null,o=new Map;try{for await(let t of jt(e))switch(t.type){case`phase_start`:{let e=sn[t.phase]||`${t.phase}...`,n=t.model?w.dim(` (${rt(t.model)})`):``;a?.stop(),a=J(w.cyan(`[${t.phase}]${n} ${e}`)).start(),o.set(t.phase,Date.now());break}case`phase_complete`:{let e=o.get(t.phase),n=e===void 0?0:Math.round((Date.now()-e)/1e3);a?.succeed(w.green(`[${t.phase}] Done (${n}s)`)),a=null;break}case`phase_error`:a?.fail(w.red(`[${t.phase}] ${t.error}`)),a=null;break;case`agent_message`:ln(t,a,r);break}}catch(e){a?.fail(),y.error(w.red(`
|
|
137
138
|
Error: `+(e instanceof Error?e.message:String(e)))),process.exit(1)}a?.stop(),y.log(w.green(`
|
|
138
139
|
✓ Build complete
|
|
139
|
-
`))}};const
|
|
140
|
-
`));try{let t=process.cwd(),n=await Ae(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await Ae(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r)
|
|
140
|
+
`))}};const ln=(e,t,n)=>{let r=e.message;switch(r.type){case`text`:n&&process.stdout.write(r.content??``);break;case`tool_call`:{let n=r.toolName??`unknown tool`;t&&(t.text=w.cyan(`[${e.phase}] Tool: ${n}`));break}case`tool_error`:y.error(w.red(`\n[${e.phase}] Tool error (${r.toolName}): ${r.error??`Unknown error`}`));break;case`error`:y.error(w.red(`\n[${e.phase}] ${r.error??`Unknown error`}`));break;default:break}};function un(e,t){switch(e.type){case`text`:t(null),process.stdout.write(e.content??``);break;case`tool_call`:{let n=e.toolName??`unknown tool`;t(J(w.cyan(`Tool: ${n}`)).start());break}case`tool_result`:t(null);break;case`tool_progress`:{let n=e.progress?.operation||e.toolName||`Working...`;t(J(w.cyan(`Tool: ${n}`)).start());break}case`tool_error`:t(null),y.error(w.red(`\nTool error (${e.toolName}): ${e.error??`Unknown error`}`));break;case`error`:t(null),y.error(w.red(`\n${e.error??`Unknown error`}`));break;case`done`:t(null);break;default:process.env.VERBOSE&&console.warn(`[AgentRun] Unknown message type:`,e.type);break}}var dn=class{async execute(e){y.log(w.blue.bold(`🤖 StackOne Agent Setup - Local Project
|
|
141
|
+
`));try{let t=process.cwd(),n=await Ae(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await Ae(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r)if(y.warn(`Existing local setup detected:`),n&&y.log(w.dim(` • CLAUDE.md found`)),r&&y.log(w.dim(` • .mcp.json found`)),y.log(``),Gt(!!e?.legacy,e?.credentials))y.log(w.dim(`Non-interactive credentials detected; proceeding without confirmation.
|
|
142
|
+
`));else{let{proceed:e}=await je.prompt([{type:`confirm`,name:`proceed`,message:`Overwrite existing local configuration?`,default:!1}]);e||(y.log(w.dim(`
|
|
141
143
|
Setup cancelled.`)),process.exit(0)),y.log(``)}let i=await ee();(!i||!d(i))&&(y.warn(`Not authenticated globally.`),y.log(w.white(`Let's authenticate now...
|
|
142
|
-
`)),i=await
|
|
144
|
+
`)),i=await rn(!!e?.legacy,e?.credentials),y.log(``)),te(await S(t,i.apiKey));let a=J(`Creating .mcp.json...`).start();try{l(m(t),s(),i.apiKey),a.succeed(`Created .mcp.json`),y.success(`Local setup complete!`),y.log(w.white(`Files created:`)),y.log(w.cyan(` • .mcp.json`)),y.log(w.dim(`Token stored securely in Claude MCP server config.`)),y.log(w.dim(`
|
|
143
145
|
💡 The stackone-agent-local MCP server is now available in this project`)),y.log(w.dim(`
|
|
144
146
|
💡 Tip: Run Claude without permission prompts:`),w.cyan(`claude --dangerously-skip-permissions`)),y.log(w.blue(`
|
|
145
|
-
Verify:`),w.cyan(`claude mcp list`)),y.log(``)}catch(e){a.fail(`Failed to create .mcp.json`),e instanceof Error&&y.error(e.message)}process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}},
|
|
147
|
+
Verify:`),w.cyan(`claude mcp list`)),y.log(``)}catch(e){a.fail(`Failed to create .mcp.json`),e instanceof Error&&y.error(e.message)}process.exit(0)}catch(e){e instanceof Error?y.error(e.message):y.error(`Unknown error occurred`),process.exit(1)}}},fn=class{async execute(e){let t=D(),n=e?.mode;if(y.log(w.bold(`
|
|
146
148
|
Available skills
|
|
147
149
|
`)),t.length===0){y.log(w.dim(` No bundled skills found.
|
|
148
|
-
`));return}for(let e of t)y.log(` • ${e}`);if(n){let e=k(n);if(e.length>0){y.log(w.bold(`\nRecommended for mode "${n}":\n`));for(let n of e){let e=t.includes(n);y.log(` • ${n}${e?``:w.dim(` (not found)`)}`)}}}y.log(``)}};const
|
|
150
|
+
`));return}for(let e of t)y.log(` • ${e}`);if(n){let e=k(n);if(e.length>0){y.log(w.bold(`\nRecommended for mode "${n}":\n`));for(let n of e){let e=t.includes(n);y.log(` • ${n}${e?``:w.dim(` (not found)`)}`)}}}y.log(``)}};const pn={profiles:{}},mn=()=>{let t=i.readConfigFile(e);if(!t)return pn;try{return JSON.parse(t)}catch{return pn}},hn=e=>mn().profiles[e],gn=e=>!!mn().profiles[e],_n=(t,n)=>{let r=mn();r.profiles[t]=n,i.writeConfigFile(e,JSON.stringify(r,null,2))},vn=()=>{let e=mn();return Object.keys(e.profiles)},yn=`https://api.stackone.com`;var bn=class{async execute({profile:e,connector:r,apiUrl:i,apiKey:a}={}){if(!e&&!a&&(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&&a&&(y.error(`Please provide either a profile or an API key, not both`),process.exit(1)),e&&i&&y.warn(`Specifying ${t(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),e&&!gn(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=vn();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let o=e?hn(e):{apiUrl:i??yn,apiKey:a};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)),r||(y.error(`Connector identifier is required in the format provider_key@version.`),process.exit(1));let s=r.split(`@`);(s.length!==2||!s[0]||!s[1])&&(y.error(`Invalid connector format ${n(r)}. Expected format: ${t(`provider_key@version`)}`),process.exit(1));let c=o.apiUrl??yn,l=await this.dropConnector(r,c,o.apiKey);process.exit(l?0:1)}async dropConnector(e,n,i){let a=J(`🗑️ Dropping connector ${t(e)}...`).start();try{let r=Buffer.from(i).toString(`base64`),o=await fetch(`${n}/registry/connectors/${e}`,{method:`DELETE`,headers:{Authorization:`Basic ${r}`}});return a.stop(),o.status===204?(y.success(`Successfully dropped connector ${t(e)} from the registry`),!0):o.status===404?(y.error(`Connector ${t(e)} not found in the registry`),!1):o.status===401||o.status===403?(y.error(`You do not have permission to drop this connector`),!1):o.status===409?(y.error(`Connector ${t(e)} has associated configs and cannot be dropped`),y.log(`Please delete all associated integration configurations before dropping the connector.`),!1):(o.ok||await b(o,`Failed to drop connector ${t(e)} from the registry`),!1)}catch(i){return a.stop(),y.error(`Failed to drop 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`),!1}}};const xn=`stackone`;async function Sn(e,n){n.length===0&&(y.error(`Multiple versions of connector ${t(e)} were found but no owner information was returned`),process.exit(1));let r=n.map(e=>({value:e,label:e===xn?`StackOne`:`Custom`,hint:e===xn?`Official StackOne connector`:`Custom connector version created by your organization`}));y.warn(`Multiple versions of connector ${t(e)} were found. Please select which version to use.`);let i=await He({message:`Which version would you like to use?`,options:r});return ze(i)&&(y.error(`Operation cancelled.`),process.exit(1)),i}const Cn=`https://api.stackone.com`;var wn=class{async execute({profile:e,connector:r,accountId:i,format:a,outputFile:s,apiUrl:c,apiKey:l,owner:u}={}){if(!e&&!l&&(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&&l&&(y.error(`Please provide either a profile or an API key, not both`),process.exit(1)),e&&c&&y.warn(`Specifying ${t(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),e&&!gn(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=vn();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let d=e?hn(e):{apiUrl:c??Cn,apiKey:l};d?.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)),Y(r)&&Y(i)&&(y.error(`Either ${t(`--connector`)} or ${t(`--account-id`)} must be provided`),process.exit(1)),X(r)&&X(i)&&(y.error(`Please provide either ${t(`--connector`)} or ${t(`--account-id`)}, not both.`),process.exit(1)),X(a)&&a!==`yaml`&&a!==`json`&&(y.error(`Format must be either ${t(`yaml`)} or ${t(`json`)}.`),process.exit(1));let f=d.apiUrl??Cn,p;if(X(r)){this.#t(r)||(y.error(`Invalid connector format ${n(r)}. Expected format: ${t(`provider_key@version`)} or ${t(`provider_key`)}`),process.exit(1));let e=this.#n(r);p=await this.#r(e,f,d.apiKey,a,u)}else X(i)?p=await this.#i(i,f,d.apiKey,a):(y.error(`Either ${t(`--connector`)} or ${t(`--account-id`)} must be provided`),process.exit(1));if(X(s))try{U.writeFileSync(s,p,`utf-8`),y.success(`Connector written to file: ${t(s)}`)}catch(e){y.error(`Failed to write connector to file ${t(s)}: ${e.message}`),process.exit(1)}else if(y.log(`\n${w.blue.inverse(` CONNECTOR CONTENT `)}\n`),!a||a===`yaml`)y.log(this.#e(p));else if(a===`json`)try{o(JSON.parse(p))}catch{y.log(p)}else y.log(p);process.exit(0)}#e(e){return e.split(`
|
|
149
151
|
`).map(e=>{if(e.trim().startsWith(`#`))return w.gray(e);if(e.includes(`:`)){let t=e.indexOf(`:`),n=e.substring(0,t+1),r=e.substring(t+1),i=r,a=r.trim();return a===`true`||a===`false`?i=r.replace(a,w.cyan(a)):a===`null`||a===`~`?i=r.replace(a,w.gray(a)):/^-?\d+(\.\d+)?$/.test(a)?i=r.replace(a,w.green(a)):(a.startsWith(`"`)&&a.endsWith(`"`)||a.startsWith(`'`)&&a.endsWith(`'`)||a&&!a.startsWith(`-`))&&(i=r.replace(a,w.yellow(a))),w.red(n)+i}return e.trim().startsWith(`-`)?e.replace(`-`,w.gray(`-`)):e}).join(`
|
|
150
|
-
`)}#t=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#n=e=>e.includes(`@`)?e:`${e}@latest`;async#r(e,n,i,a,o){let s=J(`Getting connector ${t(e)} from registry...`).start();try{let r=Buffer.from(i).toString(`base64`),c=a?`?format=${a}`:``,l=o?`${c?`&`:`?`}owner=${encodeURIComponent(o)}`:``,u=await fetch(`${n}/registry/connectors/${e}${c}${l}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});if(s.stop(),u.status===409){o&&(await b(u,`Failed to get connector ${t(e)} from the registry`),process.exit(1));let i=await
|
|
152
|
+
`)}#t=e=>!e.includes(`/`)&&!e.includes(`\\`)&&!e.endsWith(`.yaml`)&&!e.endsWith(`.yml`)?e.includes(`@`)?e.split(`@`).length===2:!0:!1;#n=e=>e.includes(`@`)?e:`${e}@latest`;async#r(e,n,i,a,o){let s=J(`Getting connector ${t(e)} from registry...`).start();try{let r=Buffer.from(i).toString(`base64`),c=a?`?format=${a}`:``,l=o?`${c?`&`:`?`}owner=${encodeURIComponent(o)}`:``,u=await fetch(`${n}/registry/connectors/${e}${c}${l}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});if(s.stop(),u.status===409){o&&(await b(u,`Failed to get connector ${t(e)} from the registry`),process.exit(1));let i=await Sn(e,(await u.json()).availableOwners??[]),a=`${n}/registry/connectors/${e}${c}${c?`&`:`?`}owner=${encodeURIComponent(i)}`;s.text=`Getting connector ${t(e)} from registry...`,s.start();let l=await fetch(a,{method:`GET`,headers:{Authorization:`Basic ${r}`}});return s.stop(),l.ok||(await b(l,`Failed to get connector ${t(e)} from the registry`),process.exit(1)),await l.text()}return u.ok||(await b(u,`Failed to get connector ${t(e)} from the registry`),process.exit(1)),await u.text()}catch(i){s.stop(),y.error(`Failed to get connector ${t(e)} 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#i(e,n,i,a){let o=J(`Getting connector from account ${t(e)}...`).start();try{let r=Buffer.from(i).toString(`base64`),s=a?`?format=${a}`:``,c=await fetch(`${n}/accounts/${e}/connector${s}`,{method:`GET`,headers:{Authorization:`Basic ${r}`}});return o.stop(),c.ok||(await b(c,`Failed to get connector from account ${t(e)}`),process.exit(1)),await c.text()}catch(i){o.stop(),y.error(`Failed to get connector from account ${t(e)}: ${i.message}`),y.log(`Please ensure that the API at ${r(n)} is reachable and the API key is valid`),process.exit(1)}}};const Tn=`http://localhost:4000`;var En=class{async execute({environment:e}={}){let n=e?.toLowerCase()??`production`;try{Re(`${w.inverse(` Initialize profile `)}`);let e=await Ue({message:`Profile label`,validate:e=>{if(!e||e.trim().length===0)return`The profile label is required`;if(e.includes(` `))return`The profile label cannot contain spaces`}});if(ze(e))return Ie(`Configuration profile initialization cancelled`),process.exit(0);if(gn(e)){let n=await Le({message:`Configuration profile with name ${t(e)} already exists. Do you want to overwrite it?`});if(ze(n)||!n)return Ie(`Configuration profile initialization cancelled`),process.exit(0)}let r;if(n===`production`)r=`https://api.stackone.com`;else if(n===`staging`)r=`https://api.stackone-dev.com`;else{let e=await Ue({message:`API URL`,placeholder:Tn,initialValue:Tn,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{new URL(e)}catch{return`Please enter a valid URL`}}});if(ze(e))return Ie(`Configuration profile initialization cancelled`),process.exit(0);r=e}let i=await Ve({message:`API Key`,validate:e=>{if(!e||e.trim().length===0)return`API Key is required`}});if(ze(i))return Ie(`Configuration profile initialization cancelled`),process.exit(0);_n(e,{label:e,environment:n,apiUrl:r,apiKey:i}),Be(`${w.green(`✔`)} Configuration profile ${t(e)} initialized successfully!`),process.exit(0)}catch(e){e?.isTtyError?y.error(`Prompt couldn't be rendered in the current environment`):y.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}};const $={pending:`○`,acceptRemote:`●`,acceptLocal:`◐`,acceptBoth:`◑`,current:`◉`,arrow:`→`,check:`✓`,cross:`✗`,warning:`⚠`};var Dn=class{constructor(e,t,n,r){this.conflicts=[],this.currentIndex=0,this.totalConflicts=0,this.currentCleanup=null,this.connectorId=t,this.localVersion=n,this.remoteVersion=r,this.conflicts=e.map(e=>({conflict:e,choice:e.type===`unchanged`?`remote`:`pending`})),this.totalConflicts=e.filter(e=>e.type===`conflict`).length}resetForReResolution(){this.currentIndex=0}async resolve(){return this.totalConflicts===0?{cancelled:!1,states:this.conflicts}:(this.moveToNextConflict(),new Promise(e=>{let t=Je({input:process.stdin,output:process.stdout});process.stdin.isTTY&&process.stdin.setRawMode(!0),process.stdin.resume(),this.render();let n=n=>{let r=n.toString();if(r===``){this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});return}if(r===`\x1B`&&n.length===1){this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});return}if(r.startsWith(`\x1B[`)){switch(r.slice(2)){case`D`:this.moveToPrevConflict(),this.render();break;case`C`:this.moveToNextConflict(),this.render();break}return}switch(r){case`r`:case`R`:this.setCurrentChoice(`remote`),this.advanceAfterChoice(t);break;case`l`:case`L`:this.setCurrentChoice(`local`),this.advanceAfterChoice(t);break;case`b`:case`B`:this.setCurrentChoice(`both`),this.advanceAfterChoice(t);break;case`\r`:case`
|
|
151
153
|
`:this.allResolved()?(this.cleanup(t),e({cancelled:!1,states:this.conflicts})):(this.moveToNextUnresolved(),this.render());break;case`q`:case`Q`:this.cleanup(t),this.renderCancelled(),e({cancelled:!0,states:this.conflicts});break;case`a`:case`A`:this.acceptAllRemaining(`remote`),this.render();break;case`u`:case`U`:this.setCurrentChoice(`pending`),this.render();break}};process.stdin.on(`data`,n),this.currentCleanup=()=>{process.stdin.removeListener(`data`,n),process.stdin.isTTY&&process.stdin.setRawMode(!1),t.close()}}))}cleanup(e){this.currentCleanup?(this.currentCleanup(),this.currentCleanup=null):(process.stdin.isTTY&&process.stdin.setRawMode(!1),e.close())}advanceAfterChoice(e){this.allResolved()||this.moveToNextUnresolved(),this.render()}render(){v();let e=process.stdout.columns||80;this.renderHeader(e),this.renderProgressBar(e),this.renderCurrentConflict(e),this.renderControls(e)}renderHeader(e){let t=this.connectorId,n=`${this.localVersion} ${$.arrow} ${this.remoteVersion}`,r=Math.max(0,e-17),i=Math.floor(r/2),a=r-i,o=` `.repeat(i)+`CONFLICT RESOLVER`+` `.repeat(a);y.log(``),y.log(w.bgBlue.white.bold(o)),y.log(w.gray(this.centerText(t,e))),y.log(w.gray(this.centerText(n,e))),y.log(``)}renderProgressBar(e){let t=this.conflicts.filter(e=>e.conflict.type===`conflict`),n=this.getCurrentConflictIndex(),r=t.map((e,t)=>{let r=t===n,i,a;switch(e.choice){case`remote`:i=r?$.current:$.acceptRemote,a=w.green;break;case`local`:i=r?$.current:$.acceptLocal,a=w.yellow;break;case`both`:i=r?$.current:$.acceptBoth,a=w.cyan;break;default:i=r?$.current:$.pending,a=r?w.white:w.gray}return a(i)}),i=t.filter(e=>e.choice!==`pending`).length,a=` Conflict ${n+1} of ${this.totalConflicts} • ${i}/${this.totalConflicts} resolved `;y.log(w.gray(this.centerText(a,e))),y.log(this.centerText(r.join(` `),e)),y.log(``)}renderCurrentConflict(e){let t=this.conflicts[this.currentIndex];if(!t||t.conflict.type!==`conflict`)return;let n=t.conflict;if(y.log(w.gray(`_`.repeat(e))),y.log(`
|
|
152
154
|
|
|
153
155
|
`),n.local){let e=t.choice===`local`||t.choice===`both`?w.yellow.bold(`${$.check} LOCAL (keeping)`):w.red.bold(`${$.cross} LOCAL (removing)`),r=n.local.split(`
|
|
@@ -161,9 +163,9 @@ Available skills
|
|
|
161
163
|
`),s=r.length>20?`\n${w.gray(`... and ${r.length-20} more lines`)}`:``;y.log(`${e}\n\n${o}${s}`)}y.log(`
|
|
162
164
|
|
|
163
165
|
`),y.log(w.gray(`_`.repeat(e))),y.log(``)}renderControls(e){let t=[w.green(`[R] Accept Remote`),w.yellow(`[L] Keep Local`),w.cyan(`[B] Keep Both`),w.gray(`[U] Undo`)],n=[w.gray(`[←/→] Navigate`),w.gray(`[A] Accept all remaining`)],r=this.allResolved()?[w.green.bold(`[Enter] Apply Changes`),w.gray(`[Esc] Cancel`)]:[w.gray(`[Enter] Next Unresolved`),w.gray(`[Esc] Cancel`)];y.log(this.centerText(t.join(` `),e)),y.log(``),y.log(this.centerText(n.join(` `),e)),y.log(``),y.log(this.centerText(r.join(` `),e)),this.allResolved()&&(y.log(``),y.log(w.green.bold(this.centerText(`✓ All conflicts resolved!`,e))))}renderFinalSummary(){v();let e=this.conflicts.filter(e=>e.conflict.type===`conflict`),t=0,n=0,r=0;for(let i of e)switch(i.choice){case`remote`:t++;break;case`local`:n++;break;case`both`:r++;break}let i=[w.green.bold(`Conflict resolution complete`),``,`${w.bold(this.totalConflicts)} conflicts resolved:`,``,`${w.green($.acceptRemote)} Accepted remote: ${t}`,`${w.yellow($.acceptLocal)} Kept local: ${n}`,`${w.cyan($.acceptBoth)} Kept both: ${r}`];y.box(i.join(`
|
|
164
|
-
`))}renderCancelled(){v(),y.log(w.yellow(`Conflict resolution cancelled`)),y.log(``),y.log(`No changes were made to your local connector file.`)}getCurrentConflictIndex(){let e=-1;for(let t=0;t<=this.currentIndex&&t<this.conflicts.length;t++)this.conflicts[t].conflict.type===`conflict`&&e++;return e}moveToNextConflict(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToPrevConflict(){for(let e=this.currentIndex-1;e>=0;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=this.conflicts.length-1;e>this.currentIndex;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToNextUnresolved(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}}setCurrentChoice(e){this.conflicts[this.currentIndex]?.conflict.type===`conflict`&&(this.conflicts[this.currentIndex].choice=e)}allResolved(){return this.conflicts.filter(e=>e.conflict.type===`conflict`).every(e=>e.choice!==`pending`)}acceptAllRemaining(e){for(let t of this.conflicts)t.conflict.type===`conflict`&&t.choice===`pending`&&(t.choice=e)}centerText(e,t){let n=this.stripAnsi(e),r=Math.max(0,Math.floor((t-n.length)/2));return` `.repeat(r)+e}stripAnsi(e){return e.replace(/\x1b\[[0-9;]*m/g,``)}getResolvedContent(){let e=[];for(let t of this.conflicts)if(t.conflict.type===`unchanged`)e.push(t.conflict.content||``);else if(t.conflict.type===`conflict`)switch(t.choice){case`remote`:t.conflict.remote&&e.push(t.conflict.remote);break;case`local`:t.conflict.local&&e.push(t.conflict.local);break;case`both`:t.conflict.local&&e.push(t.conflict.local),t.conflict.remote&&e.push(t.conflict.remote);break;case`pending`:t.conflict.remote&&e.push(t.conflict.remote);break}return e.join(``)}};const
|
|
165
|
-
`).filter(e=>e!==``);if(e.added){i+=t.length;for(let e of t)y.log(w.green(`+ ${e}`))}else if(e.removed){a+=t.length;for(let e of t)y.log(w.red(`- ${e}`))}else if(t.length<=6)for(let e of t)y.log(w.gray(` ${e}`));else{for(let e=0;e<3;e++)y.log(w.gray(` ${t[e]}`));y.log(w.gray(` ... (${t.length-6} unchanged lines)`));for(let e=t.length-3;e<t.length;e++)y.log(w.gray(` ${t[e]}`))}}y.log(``),y.log(w.gray(`Summary: ${w.green(`+${i}`)} additions, ${w.red(`-${a}`)} deletions`))}#o(e,t){return qe(e,t).some(e=>e.added||e.removed)}async#s(e,t,n,r,i){y.log(``);let a=await He({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(ze(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=qe(e,t),o=this.#u(a);if(o.length===0)return y.info(`No conflicts to resolve.`),t;let s=new
|
|
166
|
-
`);y.box({title:`⚠️ Validation Failed`,message:`The resolved connector configuration is invalid:\n\n${r}`,style:{borderColor:`yellow`,padding:1}}),y.log(``),y.log(w.bold(` Choose an action:`)),y.log(``),y.log(w.cyan(` [B]`)+` ← Go back to conflict resolution`),y.log(w.dim(` Modify your choices to fix the validation errors`)),y.log(``),y.log(w.yellow(` [S]`)+` 💾 Save anyway`),y.log(w.dim(` Save the invalid configuration (not recommended)`)),y.log(``),y.log(w.red(` [C]`)+` ✖ Cancel`),y.log(w.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=W.dirname(e);U.existsSync(r)||U.mkdirSync(r,{recursive:!0});try{U.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 yn(`${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 Dn=`https://api.stackone.com`;var On=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&&!pn(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=hn();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let o=e?fn(e):{apiUrl:r??Dn,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{De(n)}catch{y.error(`File or directory not found: ${w.red(n)}`),process.exit(1)}let s=De(n),c=o.apiUrl??Dn;if(s.isDirectory()){let e=Mn(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: ${w.green(t)} of ${w.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 ${G(e)}...`).start();try{let r=jn(e);if(!r)return!1;let s=G(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=Ye.valid(s?.latestVersion);if(!c)return await b(new Response(o,{status:e.status,statusText:e.statusText}),`Failed to push connector in ${t(G(n))} to the registry`),!1;let l=Te(n,`utf-8`),u=kn(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=Ye.inc(c,`patch`)??c,m=Ye.inc(c,`minor`)??c,h=Ye.inc(c,`major`)??c,g=await He({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 ze(g)||g===`cancel`?(Ie(`Push cancelled`),!1):(Oe(n,An(l,g),`utf-8`),y.info(`Updated version to ${t(g)} in ${G(n)}`),this.uploadFile(n,r,i,a))}};const kn=e=>e.match(/^\s*version: (\S+)/m)?.[1],An=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),jn=e=>{let t=We(e),r=Ke(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.`)},Mn=e=>{let t=[],n=Ee(e,{withFileTypes:!0});for(let r of n){let n=K(e,r.name);r.isDirectory()?t.push(...Mn(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},Nn=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({})}),Pn=Z.record(Z.string(),Z.any()),Fn=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({})}),In=`https://api.stackone.com`;var Ln=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&&!pn(l)){y.error(`Configuration profile ${t(l)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let e=hn();e.length>0&&(y.info(`Available configuration profiles:`),e.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let h=l?fn(l):{apiUrl:f??In,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??In,h?.apiKey,m)}else g=this.#e(e);else X(a)&&(g=await this.#c(a,h?.apiUrl??In,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??In,h?.apiKey):{},te=X(i)?this.#i(i,_.key??`unknown`,_.version??`unknown`):void 0,ne=X(c)?this.#u(c):{},C={...S,...te,credentials:{...S.credentials??{},...ne}};Y(C)&&(y.error(`A valid account data is required to run an action.`),process.exit(1));let T=_.actions?.[x];Y(T)&&(y.error(`Action ID ${t(x)} not found in the connector ${t(_.key)}@${t(_.version)}.`),process.exit(1));let re=X(s)?this.#d(s,x):{path:{},queryParams:{},header:{},body:{}},E=Date.now(),ie=await this.#f({connector:_,actionId:x,account:C,queryParams:{...re.queryParams,...d?{debug:`true`}:{}},pathParams:re.path,body:re.body,headers:re.header}),ae=Date.now()-E;if(X(u))try{U.writeFileSync(u,JSON.stringify(ie.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${w.blue.inverse(` ACTION OUTPUT `)}`),o(ie.output);y.log(``),y.info(`Action ${t(x)} from connector ${t(_?.key)}@${t(_?.version)} finished in ${w.yellowBright((ae/1e3).toFixed(2))} seconds.`),process.exit(0)}#e=e=>{let t=e;try{t=We(e)}catch{}return t?this.#n(t):void 0};#t=e=>{try{return We(e)}catch(n){y.error(`Failed to load connector file from ${t(e)}: ${n.message}`),process.exit(1)}};#n=e=>{let t=Ke(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=U.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(`
|
|
166
|
+
`))}renderCancelled(){v(),y.log(w.yellow(`Conflict resolution cancelled`)),y.log(``),y.log(`No changes were made to your local connector file.`)}getCurrentConflictIndex(){let e=-1;for(let t=0;t<=this.currentIndex&&t<this.conflicts.length;t++)this.conflicts[t].conflict.type===`conflict`&&e++;return e}moveToNextConflict(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToPrevConflict(){for(let e=this.currentIndex-1;e>=0;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}for(let e=this.conflicts.length-1;e>this.currentIndex;e--)if(this.conflicts[e].conflict.type===`conflict`){this.currentIndex=e;return}}moveToNextUnresolved(){for(let e=this.currentIndex+1;e<this.conflicts.length;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}for(let e=0;e<this.currentIndex;e++)if(this.conflicts[e].conflict.type===`conflict`&&this.conflicts[e].choice===`pending`){this.currentIndex=e;return}}setCurrentChoice(e){this.conflicts[this.currentIndex]?.conflict.type===`conflict`&&(this.conflicts[this.currentIndex].choice=e)}allResolved(){return this.conflicts.filter(e=>e.conflict.type===`conflict`).every(e=>e.choice!==`pending`)}acceptAllRemaining(e){for(let t of this.conflicts)t.conflict.type===`conflict`&&t.choice===`pending`&&(t.choice=e)}centerText(e,t){let n=this.stripAnsi(e),r=Math.max(0,Math.floor((t-n.length)/2));return` `.repeat(r)+e}stripAnsi(e){return e.replace(/\x1b\[[0-9;]*m/g,``)}getResolvedContent(){let e=[];for(let t of this.conflicts)if(t.conflict.type===`unchanged`)e.push(t.conflict.content||``);else if(t.conflict.type===`conflict`)switch(t.choice){case`remote`:t.conflict.remote&&e.push(t.conflict.remote);break;case`local`:t.conflict.local&&e.push(t.conflict.local);break;case`both`:t.conflict.local&&e.push(t.conflict.local),t.conflict.remote&&e.push(t.conflict.remote);break;case`pending`:t.conflict.remote&&e.push(t.conflict.remote);break}return e.join(``)}};const On=`https://api.stackone.com`;var kn=class{async execute({profile:e,connector:n,outputPath:r,apiUrl:i,apiKey:a,owner:o}={}){if(Y(n)&&(y.error(`Connector identifier is required`),y.log(`Please provide a connector identifier using the ${t(`--connector`)} option in the format: ${t(`provider_key@version`)} or ${t(`provider_key`)}`),y.log(`If no version is specified, the latest version will be pulled.`),process.exit(1)),!e&&!a&&(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&&a&&(y.error(`Please provide either a profile or an API key, not both`),process.exit(1)),e&&i&&y.warn(`Specifying ${t(`--api-url`)} with a profile won't have any effect. Using API url from profile.`),e&&!gn(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=vn();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let s=e?hn(e):{apiUrl:i??On,apiKey:a};s?.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));let c=s.apiUrl??On,[l,u]=n.split(`@`),d=await this.#f(l,c,s.apiKey,u??`latest`,o),f=this.#e(d),p=f.version??`unknown`,m=this.#t(r,f.key,p),h=this.#r(m),g=h===null,_=d;if(!g){let e=this.#i(h,m);e&&(y.warn(e.message),e.errors.length>0&&x(e.errors,!1),y.log(``));let t=e?void 0:this.#e(h);if(this.#o(h,d)){this.#a(h,d,m);let e=t?.version??`unknown`,r=await this.#s(h,d,n,e,p);r.action===`cancel`&&(Ie(`Pull cancelled`),process.exit(0)),r.action===`keep-local`&&(y.log(``),y.info(`Keeping local version. No changes made.`),process.exit(0)),r.action===`interactive-cancel`&&process.exit(0),r.action===`interactive`&&(_=r.resolvedContent)}else y.info(`No changes detected in connector configuration.`),process.exit(0)}let ee=Ke(_).connector,v=ee?.key??f.key,b=ee?.version??p,S=this.#t(r,v,b),te=S;if(S!==m){let e=await this.#n(S);y.log(``),e!==void 0&&(te=e)}await this.#d(te,_),g?y.success(`Connector ${t(v)}@${t(b)} pulled successfully (new connector)`):y.success(`Connector ${t(v)}@${t(b)} updated successfully`);let ne=v===f.key?t(v):`${t(f.key)} ${w.whiteBright(`→`)} ${t(v)}`,C=b===p?t(b):`${t(p)} ${w.whiteBright(`→`)} ${t(b)}`,T=te===m?t(te):`${t(m)}\n ${w.whiteBright(`→`)} ${t(te)}`;y.log(`\n${w.blue.inverse(` CONNECTOR DETAILS `)}\n`),y.log(` Provider: ${ne}`),y.log(` Version: ${C}`),y.log(` Output file: ${T}`),process.exit(0)}#e(e){let n=Ke(e),r=n?.errors??[];if(n.success)return n.connector;y.error(`Connector pulled from the registry is not valid`),y.log(`Please make sure you are using the latest version of the StackOne CLI by running ${t(`stackone update`)}`),r.length>0&&x(r,!0),process.exit(1)}#t(e,n,r){let i=`${n}_v${r.replaceAll(`.`,`-`)}.s1.yaml`;return e?(U.existsSync(e)&&(U.statSync(e).isDirectory()||(y.error(`Output path ${t(e)} is not a directory`),y.log(`Please provide a valid directory path to store connectors or use the default path.`),process.exit(1))),W.resolve(e,n,i)):W.resolve(process.cwd(),`connectors`,n,i)}async#n(e){if(!U.existsSync(e))return;let n=W.basename(e),r=W.dirname(e);y.warn(`File ${t(n)} already exists at ${t(r)}`);let i=await He({message:`How would you like to proceed?`,options:[{value:`override`,label:`Override existing file`,hint:`Replace the existing file with the new content`},{value:`rename`,label:`Save with a different name`,hint:`Provide a new filename for the connector`},{value:`cancel`,label:`Cancel`,hint:`Abort the pull operation`}]});if((ze(i)||i===`cancel`)&&(Ie(`Operation cancelled. No local changes were made.`),process.exit(0)),i===`override`)return;let a=await Ue({message:`Enter the new filename:`,placeholder:n,validate:e=>{if(!e||e.trim()===``)return`Filename cannot be empty`;if(!e.endsWith(`.s1.yaml`))return`Filename must end with .s1.yaml`;let t=W.join(r,e.trim());if(U.existsSync(t))return`File ${e} already exists`}});return ze(a)&&(Ie(`Operation cancelled. No local changes were made.`),process.exit(0)),W.join(r,a.trim())}#r(e){if(!U.existsSync(e))return null;try{return U.readFileSync(e,`utf-8`)}catch{return null}}#i(e,n){try{let r=Ke(e);if(!r.success){let e=r.errors??[];return{message:`Local connector ${t(W.basename(n))} has validation errors:`,errors:e}}}catch(e){return{message:`Local connector ${t(W.basename(n))} could not be validated: ${e.message}`,errors:[]}}return null}#a(e,t,n){let r=qe(e,t);if(!r.some(e=>e.added||e.removed)){y.info(`No changes detected in connector configuration.`);return}y.log(`${w.blue.inverse(` CHANGES `)}\n`),y.log(w.gray(`--- local: ${n}`)),y.log(w.gray(`+++ remote: StackOne Registry`)),y.log(``);let i=0,a=0;for(let e of r){let t=e.value.split(`
|
|
167
|
+
`).filter(e=>e!==``);if(e.added){i+=t.length;for(let e of t)y.log(w.green(`+ ${e}`))}else if(e.removed){a+=t.length;for(let e of t)y.log(w.red(`- ${e}`))}else if(t.length<=6)for(let e of t)y.log(w.gray(` ${e}`));else{for(let e=0;e<3;e++)y.log(w.gray(` ${t[e]}`));y.log(w.gray(` ... (${t.length-6} unchanged lines)`));for(let e=t.length-3;e<t.length;e++)y.log(w.gray(` ${t[e]}`))}}y.log(``),y.log(w.gray(`Summary: ${w.green(`+${i}`)} additions, ${w.red(`-${a}`)} deletions`))}#o(e,t){return qe(e,t).some(e=>e.added||e.removed)}async#s(e,t,n,r,i){y.log(``);let a=await He({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(ze(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=qe(e,t),o=this.#u(a);if(o.length===0)return y.info(`No conflicts to resolve.`),t;let s=new Dn(o,n,r,i);for(;;){if((await s.resolve()).cancelled)return null;let e=s.getResolvedContent(),t=Ke(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(`
|
|
168
|
+
`);y.box({title:`⚠️ Validation Failed`,message:`The resolved connector configuration is invalid:\n\n${r}`,style:{borderColor:`yellow`,padding:1}}),y.log(``),y.log(w.bold(` Choose an action:`)),y.log(``),y.log(w.cyan(` [B]`)+` ← Go back to conflict resolution`),y.log(w.dim(` Modify your choices to fix the validation errors`)),y.log(``),y.log(w.yellow(` [S]`)+` 💾 Save anyway`),y.log(w.dim(` Save the invalid configuration (not recommended)`)),y.log(``),y.log(w.red(` [C]`)+` ✖ Cancel`),y.log(w.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=W.dirname(e);U.existsSync(r)||U.mkdirSync(r,{recursive:!0});try{U.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 Sn(`${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 An=`https://api.stackone.com`;var jn=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&&!gn(e)){y.error(`Configuration profile ${t(e)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let n=vn();n.length>0&&(y.info(`Available configuration profiles:`),n.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let o=e?hn(e):{apiUrl:r??An,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{De(n)}catch{y.error(`File or directory not found: ${w.red(n)}`),process.exit(1)}let s=De(n),c=o.apiUrl??An;if(s.isDirectory()){let e=Fn(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: ${w.green(t)} of ${w.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 ${G(e)}...`).start();try{let r=Pn(e);if(!r)return!1;let s=G(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=Ye.valid(s?.latestVersion);if(!c)return await b(new Response(o,{status:e.status,statusText:e.statusText}),`Failed to push connector in ${t(G(n))} to the registry`),!1;let l=Te(n,`utf-8`),u=Mn(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=Ye.inc(c,`patch`)??c,m=Ye.inc(c,`minor`)??c,h=Ye.inc(c,`major`)??c,g=await He({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 ze(g)||g===`cancel`?(Ie(`Push cancelled`),!1):(Oe(n,Nn(l,g),`utf-8`),y.info(`Updated version to ${t(g)} in ${G(n)}`),this.uploadFile(n,r,i,a))}};const Mn=e=>e.match(/^\s*version: (\S+)/m)?.[1],Nn=(e,t)=>e.replace(/^(\s*version: )\S+/m,`$1${t}`),Pn=e=>{let t=We(e),r=Ke(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.`)},Fn=e=>{let t=[],n=Ee(e,{withFileTypes:!0});for(let r of n){let n=K(e,r.name);r.isDirectory()?t.push(...Fn(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t},In=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({})}),Ln=Z.record(Z.string(),Z.any()),Rn=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({})}),zn=`https://api.stackone.com`;var Bn=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&&!gn(l)){y.error(`Configuration profile ${t(l)} not found`),y.log(`Run ${t(`stackone init`)} to create a new configuration profile.\n`);let e=vn();e.length>0&&(y.info(`Available configuration profiles:`),e.forEach(e=>{y.log(` - ${w.blue(e)}`)})),process.exit(1)}let h=l?hn(l):{apiUrl:f??zn,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??zn,h?.apiKey,m)}else g=this.#e(e);else X(a)&&(g=await this.#c(a,h?.apiUrl??zn,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??zn,h?.apiKey):{},te=X(i)?this.#i(i,_.key??`unknown`,_.version??`unknown`):void 0,ne=X(c)?this.#u(c):{},C={...S,...te,credentials:{...S.credentials??{},...ne}};Y(C)&&(y.error(`A valid account data is required to run an action.`),process.exit(1));let T=_.actions?.[x];Y(T)&&(y.error(`Action ID ${t(x)} not found in the connector ${t(_.key)}@${t(_.version)}.`),process.exit(1));let re=X(s)?this.#d(s,x):{path:{},queryParams:{},header:{},body:{}},E=Date.now(),ie=await this.#f({connector:_,actionId:x,account:C,queryParams:{...re.queryParams,...d?{debug:`true`}:{}},pathParams:re.path,body:re.body,headers:re.header}),ae=Date.now()-E;if(X(u))try{U.writeFileSync(u,JSON.stringify(ie.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${w.blue.inverse(` ACTION OUTPUT `)}`),o(ie.output);y.log(``),y.info(`Action ${t(x)} from connector ${t(_?.key)}@${t(_?.version)} finished in ${w.yellowBright((ae/1e3).toFixed(2))} seconds.`),process.exit(0)}#e=e=>{let t=e;try{t=We(e)}catch{}return t?this.#n(t):void 0};#t=e=>{try{return We(e)}catch(n){y.error(`Failed to load connector file from ${t(e)}: ${n.message}`),process.exit(1)}};#n=e=>{let t=Ke(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=U.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(`
|
|
167
169
|
`).map((e,t)=>t===0?e:` ${e}`).join(`
|
|
168
|
-
`)}`;return this.#n(r)};#i=(e,t,n)=>{let r=e;try{r=U.readFileSync(e,`utf-8`)}catch{}try{let e=
|
|
169
|
-
Exiting watch mode...`)),process.exit(0)};Vn(),y.start(`Validating connectors...`);let o=await Kn(i);e=Un(e,o||{}),Wn(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 Jn(t):[t];if(!(!n||n.length===0)){v(),r.stop(),Vn(),y.log(w.gray(`File change detected: ${t}`)),y.start(`Validating connectors...`);for(let t of n){let n=await Kn(t);e=Un(e,n||{})}Wn(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 Kn(i,y),process.exit(0)}};const Un=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},Wn=(e,n)=>{v(),Vn();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(w.blue.inverse(` Validation Summary `)),y.log(`Connectors path: ${t(n)}`),y.log(`${r===0?w.red(`0`):w.green(r)} valid, ${i===0?w.green(`0`):w.red(i)} invalid connectors\n`)},Gn=async e=>{let t=[],n=await $e(e);for(let r of n){let n=K(e,r),i=await et(n);i.isDirectory()?t.push(...await Gn(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Kn=async(e,r)=>{let i=await et(e),a={};if(i.isDirectory()){let i=await Gn(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 qn(e,r);t===null?o++:(r?.log(``),s++),a[e]=t}return r?.log(``),r?.log(w.blue.inverse(` Validation Summary `)),r?.log(`${o===0?w.red(`0`):w.green(o)} valid, ${s===0?w.green(`0`):w.red(s)} invalid connectors`),a}else if(i.isFile()&&e.endsWith(`s1.yaml`))return a[e]=await qn(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 Jn(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},qn=async(e,n)=>{let r=Ke(We(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`),[]},Jn=async e=>{let t=ke(e);try{return(await $e(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>K(t,e))}catch{}};function Yn(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(e)try{ue({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 Xn=I(me(),`.stackone`),Zn=I(Xn,`version-check.json`),Qn=(e=!1)=>{let t=nr(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=$n();e&&er(e)&&tr(e),rr({lastCheckTime:n})}},$n=()=>{try{return Ce(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},er=e=>{try{let t=Rn();return Ye.gt(e,t)}catch{return!1}},tr=e=>{let t=Rn(),n=`Update available: ${w.dim(t)} → ${w.green(e)}`,r=`\n\nRun ${w.cyan(`stackone update`)} to update`;y.box(n,r)},nr=()=>{try{if(!j(Zn))return null;let e=fe(Zn,`utf-8`);return JSON.parse(e)}catch{return null}},rr=e=>{try{j(Xn)||de(Xn,{recursive:!0}),M(Zn,JSON.stringify(e,null,2),`utf-8`)}catch{}};var ir=class{constructor(e=new re,t=Rn()){this.program=e,this.version=t,Yn(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new Cn,t=new On,n=new En,r=new _n,i=new xn,a=new Hn,o=new nn,s=new cn,c=new Wt,l=new Ut,u=new an,d=new ln,f=new Ln,p=new Bn;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(w.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 T(`<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 T(`<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 T(`<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)),f.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 m=this.program.command(`agent`).description(`StackOne agent commands`);m.command(`setup`).option(`-g, --global`,`Setup global configuration (default)`).option(`-l, --local`,`Setup local project configuration`).option(`--legacy`,`Use email/password login instead of browser-based auth`).description(`Setup StackOne agent (global or local)`).action(e=>{e.global&&e.local&&(y.error(`--global and --local are mutually exclusive. Please provide only one.`),process.exit(1)),e.local?s.execute({legacy:!!e.legacy}):o.execute({legacy:!!e.legacy})}),m.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{c.execute()}),m.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(`${w.red(`Invalid mode:`)} ${w.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})}),m.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})}),m.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=>{p.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{y.log(`${w.inverse.greenBright(`StackOne`)} ${w.grey(`CLI`)} ${w.whiteBright(this.version)}`),Qn(!0),process.exit(0)})}run(){process.argv.includes(`version`)||Qn(),this.program.parse(process.argv)}};export{ir as t};
|
|
170
|
+
`)}`;return this.#n(r)};#i=(e,t,n)=>{let r=e;try{r=U.readFileSync(e,`utf-8`)}catch{}try{let e=In.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 Sn(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=U.readFileSync(e,`utf-8`)}catch{}try{return Ln.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=U.readFileSync(e,`utf-8`)}catch{}try{return Rn.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 Ge({mode:`action_id`,actionId:n,account:r,connector:e,pathParams:i,queryParams:a,body:s,headers:c,getHttpClient:async()=>new Xe});if(l.response?.successful){let e={...this.#p(a,l.steps),...Fe(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(`${w.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 Vn=()=>{try{let e=K(ke(Qe(import.meta.url)),`..`,`package.json`);return JSON.parse(Te(e,`utf8`)).version}catch{return`unknown`}},Hn=Ze(xe);var Un=class{constructor(){this.packageName=`@stackone/cli`,this.spinner=J(),this.currentVersion=Vn()}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: ${w.yellow(this.currentVersion)} → ${w.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 Hn(`npm view ${this.packageName} version`,{encoding:`utf-8`});return e.trim()}catch{return null}}isNewerVersion(e,t){return Ye.gt(e,t)}isUsingVolta(){if(typeof process.env.VOLTA_HOME!=`string`||process.env.VOLTA_HOME.length===0)return!1;let e=I(process.env.VOLTA_HOME,`bin`),t=I(e,`stackone`),n=I(e,`stackone.exe`);return j(t)||j(n)}async performUpdate(e){let n=this.isUsingVolta();this.spinner.text=`Updating to latest version (${t(e)})...`,this.spinner.start();try{await Hn(n?`volta install ${this.packageName}@latest`:`npm install -g ${this.packageName}@latest`,{encoding:`utf-8`}),this.spinner.stop(),y.success(`StackOne CLI updated successfully to latest version (${t(e)})`)}catch{this.spinner.stop();let e=n?`volta install ${this.packageName}@latest`:`npm install -g ${this.packageName}@latest`;throw Error(`Failed to install update. Please try manually: ${e}`)}}};const Wn=()=>{y.log(`${w.gray.inverse(` CONNECTORS VALIDATION `)} ${w.yellow.inverse(` WATCH MODE `)}\n`)};var Gn=class{async execute(e){let{watchMode:t,fileOrDir:n}=e,r=J(`Watching for file changes... ${w.gray(`(press "q" to quit)`)}`);if(!n)return;let i=q(n);try{await et(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(w.grey(`
|
|
171
|
+
Exiting watch mode...`)),process.exit(0)};Wn(),y.start(`Validating connectors...`);let o=await Yn(i);e=Kn(e,o||{}),qn(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 Zn(t):[t];if(!(!n||n.length===0)){v(),r.stop(),Wn(),y.log(w.gray(`File change detected: ${t}`)),y.start(`Validating connectors...`);for(let t of n){let n=await Yn(t);e=Kn(e,n||{})}qn(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 Yn(i,y),process.exit(0)}};const Kn=(e,t)=>{for(let[n,r]of Object.entries(t))e[n]=r;return e},qn=(e,n)=>{v(),Wn();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(w.blue.inverse(` Validation Summary `)),y.log(`Connectors path: ${t(n)}`),y.log(`${r===0?w.red(`0`):w.green(r)} valid, ${i===0?w.green(`0`):w.red(i)} invalid connectors\n`)},Jn=async e=>{let t=[],n=await $e(e);for(let r of n){let n=K(e,r),i=await et(n);i.isDirectory()?t.push(...await Jn(n)):i.isFile()&&r.endsWith(`.s1.yaml`)&&t.push(n)}return t},Yn=async(e,r)=>{let i=await et(e),a={};if(i.isDirectory()){let i=await Jn(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 Xn(e,r);t===null?o++:(r?.log(``),s++),a[e]=t}return r?.log(``),r?.log(w.blue.inverse(` Validation Summary `)),r?.log(`${o===0?w.red(`0`):w.green(o)} valid, ${s===0?w.green(`0`):w.red(s)} invalid connectors`),a}else if(i.isFile()&&e.endsWith(`s1.yaml`))return a[e]=await Xn(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 Zn(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},Xn=async(e,n)=>{let r=Ke(We(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`),[]},Zn=async e=>{let t=ke(e);try{return(await $e(t)).filter(e=>e.endsWith(`.s1.yaml`))?.map(e=>K(t,e))}catch{}};function Qn(){let e=process.env.STACKONE_AGENT_TOKEN,t=process.env.LANGSMITH_PROJECT||`stackone-agent-cli`;if(e)try{ue({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 $n=I(me(),`.stackone`),er=I($n,`version-check.json`),tr=(e=!1)=>{let t=ar(),n=Date.now();if(e||!t||n-t.lastCheckTime>1728e5){let e=nr();e&&rr(e)&&ir(e),or({lastCheckTime:n})}},nr=()=>{try{return Ce(`npm view @stackone/cli version`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:15e3}).trim()}catch{return null}},rr=e=>{try{let t=Vn();return Ye.gt(e,t)}catch{return!1}},ir=e=>{let t=Vn(),n=`Update available: ${w.dim(t)} → ${w.green(e)}`,r=`\n\nRun ${w.cyan(`stackone update`)} to update`;y.box(n,r)},ar=()=>{try{if(!j(er))return null;let e=fe(er,`utf-8`);return JSON.parse(e)}catch{return null}},or=e=>{try{j($n)||de($n,{recursive:!0}),M(er,JSON.stringify(e,null,2),`utf-8`)}catch{}};var sr=class{constructor(e=new re,t=Vn()){this.program=e,this.version=t,Qn(),this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new En,t=new jn,n=new kn,r=new bn,i=new wn,a=new Gn,o=new on,s=new dn,c=new Wt,l=new Ut,u=new cn,d=new fn,f=new Bn,p=new Un;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,t)=>{t(w.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 T(`<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 T(`<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 T(`<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)),f.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 m=this.program.command(`agent`).description(`StackOne agent commands`);m.command(`setup`).option(`-g, --global`,`Setup global configuration (default)`).option(`-l, --local`,`Setup local project configuration`).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(`Setup StackOne agent (global or local)`).action(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)),(t||n||r)&&!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 i={email:e.email,password:e.password,passwordFromStdin:r};e.local?s.execute({legacy:!!e.legacy,credentials:i}):o.execute({legacy:!!e.legacy,credentials:i})}),m.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{c.execute()}),m.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(`${w.red(`Invalid mode:`)} ${w.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})}),m.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})}),m.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=>{p.execute({force:e.force})}),this.program.command(`version`).description(`Show version information`).action(async()=>{y.log(`${w.inverse.greenBright(`StackOne`)} ${w.grey(`CLI`)} ${w.whiteBright(this.version)}`),tr(!0),process.exit(0)})}run(){process.argv.includes(`version`)||tr(),this.program.parse(process.argv)}};export{sr as t};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./agentConfig-KBkYYmMr.cjs`);const e=require(`./cliCore-
|
|
1
|
+
require(`./agentConfig-KBkYYmMr.cjs`);const e=require(`./cliCore-DZnmJlqN.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-
|
|
1
|
+
import{t as e}from"./cliCore-_BZmg0kj.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.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"description": "StackOne Connect CLI tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"@clack/prompts": "0.11.0",
|
|
51
51
|
"@stackone/agent-config": "1.4.0",
|
|
52
52
|
"@stackone/agent-harness": "0.10.0",
|
|
53
|
-
"@stackone/connect-sdk": "2.
|
|
54
|
-
"@stackone/core": "2.
|
|
53
|
+
"@stackone/connect-sdk": "2.69.0",
|
|
54
|
+
"@stackone/core": "2.55.0",
|
|
55
55
|
"@stackone/defender": "0.6.3",
|
|
56
|
-
"@stackone/transport": "2.
|
|
56
|
+
"@stackone/transport": "2.23.0",
|
|
57
57
|
"@stackone/utils": "0.22.0",
|
|
58
58
|
"chalk": "5.6.2",
|
|
59
59
|
"chokidar": "5.0.0",
|