@stackone/cli 1.9.0 → 1.9.1
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 +1 -5
- package/dist/cli.cjs +1 -1
- package/dist/cli.js +1 -1
- package/dist/{cliCore-DObMBAP8.js → cliCore-57MzGvkG.js} +23 -23
- package/dist/{cliCore-BJMMc7zt.cjs → cliCore-BRPqDxQ9.cjs} +24 -24
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -160,11 +160,7 @@ This command requires prior authentication with `agent setup --global`. It creat
|
|
|
160
160
|
- `CLAUDE.md` - Agent workflow instructions and guidelines
|
|
161
161
|
- `.mcp.json` - Local MCP server configuration
|
|
162
162
|
|
|
163
|
-
The MCP configuration uses the `STACKONE_AGENT_MCP_TOKEN` environment variable
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
export STACKONE_AGENT_MCP_TOKEN=<your-api-key>
|
|
167
|
-
```
|
|
163
|
+
The MCP configuration uses the `STACKONE_AGENT_MCP_TOKEN` environment variable, which is automatically managed by the `agent setup` command.
|
|
168
164
|
|
|
169
165
|
Options:
|
|
170
166
|
|
package/dist/cli.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const e=require(`./cliCore-
|
|
2
|
+
const e=require(`./cliCore-BRPqDxQ9.cjs`),t=new e.CLI;t.run();
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{CLI as e}from"./cliCore-
|
|
2
|
+
import{CLI as e}from"./cliCore-57MzGvkG.js";const t=new e;t.run();
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
import e from"chalk";import{Argument as t,Command as n}from"commander";import{exec as r}from"node:child_process";import{access as i,chmod as a,mkdir as o,readFile as s,rm as c,writeFile as l}from"node:fs/promises";import{dirname as u,join as d}from"node:path";import{promisify as f}from"node:util";import p from"ora";import{
|
|
2
|
-
`));let t={configsCleaned:0};try{let n=p(`Removing stored configuration...`).start();await
|
|
1
|
+
import e from"chalk";import{Argument as t,Command as n}from"commander";import{exec as r}from"node:child_process";import{access as i,chmod as a,mkdir as o,readFile as s,rm as c,writeFile as l}from"node:fs/promises";import{dirname as u,join as d}from"node:path";import{promisify as f}from"node:util";import p from"ora";import{existsSync as ee}from"node:fs";import{homedir as m}from"node:os";import{stdin as h,stdout as g}from"node:process";import{createInterface as _}from"node:readline";import v from"inquirer";import{fileURLToPath as y}from"node:url";import{existsSync as b,mkdirSync as te,readFileSync as x,readdirSync as S,statSync as C,writeFileSync as ne}from"fs";import{homedir as w}from"os";import{basename as T,dirname as re,join as E}from"path";import{loadConnector as D,validateYamlConnector as O}from"@stackone/connect-sdk";import{fileURLToPath as ie}from"url";const k=d(m(),`.stackone`),A=d(k,`agent-config.json`),ae=`stackone-agent-global`,oe=`stackone-agent-local`,se=process.env.STACKONE_AGENT_SERVER_URL||`https://mcp-internal-falcon.stackonehq.workers.dev/mcp`;async function j(){let e=ee(k);e||await o(k,{recursive:!0,mode:448})}async function M(e){await j(),await l(A,JSON.stringify(e,null,2)),await a(A,384)}async function N(){try{let e=await s(A,`utf-8`);return JSON.parse(e)}catch{return null}}async function ce(){try{await c(A,{force:!0})}catch{}}function P(){return se}function F(){return ae}function I(){return oe}function le(e){return new Date(e)<=new Date}function ue(e){return!!e?.apiKey&&!le(e.expiresAt)}const L=f(r);async function R(e){try{let t=await s(e,`utf-8`),n=JSON.parse(t),r=!1;if(n.mcpServers&&typeof n.mcpServers==`object`){for(let[e,t]of Object.entries(n.mcpServers))if(t&&typeof t==`object`&&`transport`in t){let e=t.transport;if(e&&typeof e==`object`&&`headers`in e){let t=e.headers;if(t&&typeof t==`object`&&`Authorization`in t){let e=t.Authorization;typeof e==`string`&&e.startsWith(`Bearer `)&&!e.includes("${")&&(t.Authorization="Bearer ${STACKONE_AGENT_MCP_TOKEN}",r=!0)}}}}return r&&await l(e,JSON.stringify(n,null,2)),r}catch{return!1}}var z=class{async execute(){console.log(e.blue.bold(`🧹 StackOne Agent Cleanup
|
|
2
|
+
`));let t={configsCleaned:0};try{let n=p(`Removing stored configuration...`).start();await ce(),n.succeed(`Removed ~/.stackone/agent-config.json`);let r=p(`Removing MCP servers from Claude...`).start(),i=0;try{let e=F();await L(`claude mcp remove ${e} 2>/dev/null`),i++}catch{}try{let e=I();await L(`claude mcp remove ${e} 2>/dev/null`),i++}catch{}i>0?r.succeed(`Removed ${i} MCP server(s) from Claude`):r.warn(`No MCP servers found in Claude (already removed or not configured)`);let a=p(`Checking for .mcp.json file...`).start(),o=process.cwd(),s=d(o,`.mcp.json`);try{let e=await R(s);e?(t.configsCleaned=1,a.succeed(`Cleaned .mcp.json (replaced tokens with environment variables)`)):a.info(`.mcp.json already uses environment variables or not found`)}catch{a.info(`.mcp.json not found (already cleaned or not created)`)}console.log(e.green(`
|
|
3
3
|
✓ Cleanup complete!`)),console.log(e.white(`
|
|
4
4
|
What was removed:`)),console.log(e.cyan(` • ~/.stackone/agent-config.json`)),console.log(e.cyan(` • MCP server from Claude configuration`)),t.configsCleaned>0&&console.log(e.cyan(` • Hardcoded credentials from .mcp.json`)),console.log(e.dim(`
|
|
5
5
|
To authenticate again:`)),console.log(e.cyan(` stackone agent setup --global`),e.dim(`(for global setup)`)),console.log(e.cyan(` stackone agent setup --local`),e.dim(`(for local project setup)`)),console.log(``),process.exit(0)}catch(t){t instanceof Error?console.error(e.red(`\n✗ ${t.message}\n`)):console.error(e.red(`
|
|
6
6
|
✗ Unknown error occurred
|
|
7
|
-
`)),process.exit(1)}}},
|
|
8
|
-
`));try{let t=process.cwd(),n=await i(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await i(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(e.yellow(`⚠ Existing local setup detected:`)),n&&console.log(e.dim(` • CLAUDE.md found in current directory`)),r&&console.log(e.dim(` • .mcp.json found in current directory`)),console.log();let{proceed:t}=await
|
|
9
|
-
Setup cancelled.`)),process.exit(0)),console.log()}let a=await N(),o;if(a?.email){console.log(e.dim(`Last used email: ${a.email}\n`));let{useExisting:t}=await
|
|
7
|
+
`)),process.exit(1)}}},B=class{baseUrl;constructor(e){this.baseUrl=e||process.env.AUTH_SERVER_URL||`https://idp-api.stackone.com`}async login(e,t){try{let n=`${this.baseUrl}/auth/sign-in/mcp`,r=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({email:e,password:t})});if(!r.ok){let e=await r.text(),t={};try{t=JSON.parse(e)}catch{}return{success:!1,error:t.error||`HTTP ${r.status}: ${r.statusText}`}}let i=await r.text(),a=JSON.parse(i);return a.apiKey?{success:!0,apiKey:a.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=`${this.baseUrl}/api-key/verify`,n=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e})});if(!n.ok){let e=await n.text(),t={};try{t=JSON.parse(e)}catch{}return{valid:!1,error:t.error||`HTTP ${n.status}: ${n.statusText}`}}let r=await n.text();return JSON.parse(r)}catch(e){return{valid:!1,error:e instanceof Error?e.message:`Network error occurred`}}}};const V=new B,H=f(r);function U(e){let t=new Date(e),n=new Date,r=t.getTime()-n.getTime(),i=Math.floor(r/(3600*1e3)),a=t.toLocaleTimeString(`en-US`,{hour:`numeric`,minute:`2-digit`,hour12:!0}),o=t.toDateString()===n.toDateString()?`Today`:t.toDateString()===new Date(n.getTime()+864e5).toDateString()?`Tomorrow`:t.toLocaleDateString(`en-US`,{month:`short`,day:`numeric`});return`${o} at ${a} (${i} hours from now)`}var de=class{async execute(){console.log(e.blue.bold(`🤖 StackOne Agent Setup - Global Configuration
|
|
8
|
+
`));try{let t=process.cwd(),n=await i(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await i(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(e.yellow(`⚠ Existing local setup detected:`)),n&&console.log(e.dim(` • CLAUDE.md found in current directory`)),r&&console.log(e.dim(` • .mcp.json found in current directory`)),console.log();let{proceed:t}=await v.prompt([{type:`confirm`,name:`proceed`,message:`Re-authenticate globally despite existing local setup?`,default:!0}]);t||(console.log(e.dim(`
|
|
9
|
+
Setup cancelled.`)),process.exit(0)),console.log()}let a=await N(),o;if(a?.email){console.log(e.dim(`Last used email: ${a.email}\n`));let{useExisting:t}=await v.prompt([{type:`confirm`,name:`useExisting`,message:`Sign in with this email?`,default:!0}]);if(t)o=a.email;else{let t=_({input:h,output:g});o=await new Promise(n=>{t.question(e.white(`Email: `),e=>{n(e.trim())})}),t.close(),o||(console.error(e.red(`
|
|
10
10
|
✗ Email is required
|
|
11
|
-
`)),process.exit(1))}}else{let t=
|
|
11
|
+
`)),process.exit(1))}}else{let t=_({input:h,output:g});o=await new Promise(n=>{t.question(e.white(`Email: `),e=>{n(e.trim())})}),t.close(),o||(console.error(e.red(`
|
|
12
12
|
✗ Email is required
|
|
13
|
-
`)),process.exit(1))}let s=await
|
|
13
|
+
`)),process.exit(1))}let s=await v.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}]);s.password||(console.error(e.red(`
|
|
14
14
|
✗ Password is required
|
|
15
|
-
`)),process.exit(1)),console.log();let c=p(`Authenticating...`).start(),l=await
|
|
15
|
+
`)),process.exit(1)),console.log();let c=p(`Authenticating...`).start(),l=await V.login(o,s.password);(!l.success||!l.apiKey)&&(c.fail(`Authentication failed`),console.error(e.red(`\n✗ ${l.error||`Invalid credentials`}\n`)),console.log(e.dim(`Please check your email and password and try again.
|
|
16
16
|
`)),process.exit(1)),c.succeed(`Login successful!`);let u=new Date(Date.now()+1440*60*1e3).toISOString();await M({apiKey:l.apiKey,userId:o,email:o,expiresAt:u,serverUrl:P()}),console.log(e.green.bold(`
|
|
17
|
-
✓ API key saved to ~/.stackone/agent-config.json`)),console.log(e.white(`✓ Key expires at`),e.cyan(
|
|
17
|
+
✓ API key saved to ~/.stackone/agent-config.json`)),console.log(e.white(`✓ Key expires at`),e.cyan(U(u)));let d=p(`Setting up global MCP configuration...`).start();try{let t=F(),n=P();try{await H(`claude mcp remove ${t} 2>/dev/null`)}catch{}let r=`claude mcp add ${t} ${n} --scope user --transport http --header "Authorization: Bearer ${l.apiKey}"`;await H(r),d.succeed(`Installed to Claude (global)`),console.log(e.green(`
|
|
18
18
|
✓ Global setup complete!`)),console.log(e.white(`Config location:`),e.cyan(`~/.claude.json`)),console.log(e.blue(`
|
|
19
19
|
Verify:`),e.cyan(`claude mcp list`)),console.log(e.dim(`
|
|
20
20
|
💡 Tip: Run Claude without permission prompts:`),e.cyan(`claude --dangerously-skip-permissions`)),console.log(e.dim(`
|
|
21
21
|
To setup for a specific project, run:`),e.cyan(`stackone agent setup --local`)),console.log(``)}catch(t){d.fail(`Installation to Claude failed`),t instanceof Error&&(console.error(e.red(`\n✗ ${t.message}\n`)),console.error(e.dim(`You can manually add the server later with:`)),console.error(e.cyan(` claude mcp add ${F()} ${P()} --scope user --transport http --header "Authorization: Bearer ${l.apiKey}"`)))}process.exit(0)}catch(t){t instanceof Error?console.error(e.red(`\n✗ ${t.message}\n`)):console.error(e.red(`
|
|
22
22
|
✗ Unknown error occurred
|
|
23
|
-
`)),process.exit(1)}}};const W=f(r),
|
|
23
|
+
`)),process.exit(1)}}};const W=f(r),fe=y(import.meta.url),pe=u(fe);async function me(){let e=d(pe,`..`,`..`,`..`,`CLAUDE_TEMPLATE.md`);try{return await s(e,`utf-8`)}catch{return`# 🚀 STACKONE API CONFIG BUILDER
|
|
24
24
|
|
|
25
25
|
This document provides the complete methodology for building StackOne API configurations with Claude. Follow this strict workflow to ensure comprehensive, tested, and customer-valuable integrations.
|
|
26
26
|
|
|
@@ -104,7 +104,7 @@ stackone agent cleanup
|
|
|
104
104
|
|
|
105
105
|
*Authenticated with StackOne • Agent MCP Server*
|
|
106
106
|
*For full workflow details, see the complete CLAUDE.md in repository*
|
|
107
|
-
`}}const
|
|
107
|
+
`}}const he=()=>`{
|
|
108
108
|
"mcpServers": {
|
|
109
109
|
"${I()}": {
|
|
110
110
|
"url": "${P()}",
|
|
@@ -116,24 +116,24 @@ stackone agent cleanup
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
}`;var
|
|
120
|
-
`));try{let t=process.cwd(),n=await i(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await i(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(e.yellow(`⚠ Existing local setup detected:`)),n&&console.log(e.dim(` • CLAUDE.md found`)),r&&console.log(e.dim(` • .mcp.json found`)),console.log();let{proceed:t}=await
|
|
121
|
-
Setup cancelled.`)),process.exit(0)),console.log()}let a=await N();if(!a||!
|
|
122
|
-
`));let t=
|
|
119
|
+
}`;var ge=class{async execute(){console.log(e.blue.bold(`🤖 StackOne Agent Setup - Local Project
|
|
120
|
+
`));try{let t=process.cwd(),n=await i(`${t}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await i(`${t}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(e.yellow(`⚠ Existing local setup detected:`)),n&&console.log(e.dim(` • CLAUDE.md found`)),r&&console.log(e.dim(` • .mcp.json found`)),console.log();let{proceed:t}=await v.prompt([{type:`confirm`,name:`proceed`,message:`Overwrite existing local configuration?`,default:!1}]);t||(console.log(e.dim(`
|
|
121
|
+
Setup cancelled.`)),process.exit(0)),console.log()}let a=await N();if(!a||!ue(a)){console.log(e.yellow(`⚠ Not authenticated globally.`)),console.log(e.white(`Let's authenticate now...
|
|
122
|
+
`));let t=_({input:h,output:g}),n=await new Promise(n=>{t.question(e.white(`Email: `),e=>{n(e.trim())})});t.close(),n||(console.error(e.red(`
|
|
123
123
|
✗ Email is required
|
|
124
|
-
`)),process.exit(1));let r=await
|
|
124
|
+
`)),process.exit(1));let r=await v.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}]);r.password||(console.error(e.red(`
|
|
125
125
|
✗ Password is required
|
|
126
|
-
`)),process.exit(1)),console.log();let i=p(`Authenticating...`).start(),o=await
|
|
127
|
-
`)),process.exit(1)),i.succeed(`Login successful!`);let s=new Date(Date.now()+1440*60*1e3).toISOString();await M({apiKey:o.apiKey,userId:n,email:n,expiresAt:s,serverUrl:P()}),a={apiKey:o.apiKey,userId:n,email:n,expiresAt:s,serverUrl:P()},console.log()}let o=p(`Setting up local project configuration...`).start();o.text=`Creating CLAUDE.md...`;let s=await
|
|
126
|
+
`)),process.exit(1)),console.log();let i=p(`Authenticating...`).start(),o=await V.login(n,r.password);(!o.success||!o.apiKey)&&(i.fail(`Authentication failed`),console.error(e.red(`\n✗ ${o.error||`Invalid credentials`}\n`)),console.log(e.dim(`Please check your email and password and try again.
|
|
127
|
+
`)),process.exit(1)),i.succeed(`Login successful!`);let s=new Date(Date.now()+1440*60*1e3).toISOString();await M({apiKey:o.apiKey,userId:n,email:n,expiresAt:s,serverUrl:P()}),a={apiKey:o.apiKey,userId:n,email:n,expiresAt:s,serverUrl:P()},console.log()}let o=p(`Setting up local project configuration...`).start();o.text=`Creating CLAUDE.md...`;let s=await me();await l(`CLAUDE.md`,s),o.succeed(`Created CLAUDE.md`);let c=p(`Creating .mcp.json...`).start();await l(`.mcp.json`,he()),c.succeed(`Created .mcp.json (using STACKONE_AGENT_MCP_TOKEN env var)`);let u=p(`Installing to Claude (local)...`).start();try{let t=I();try{await W(`claude mcp remove ${t} 2>/dev/null`)}catch{}let n=`claude mcp add ${t} ${P()} --scope local --transport http --header "Authorization: Bearer ${a.apiKey}"`;await W(n),u.succeed(`Installed to Claude (local)`),console.log(e.green(`
|
|
128
128
|
✓ Local setup complete!`)),console.log(e.white(`Files created:`)),console.log(e.cyan(` - CLAUDE.md`)),console.log(e.cyan(` - .mcp.json`)),console.log(e.dim(`
|
|
129
129
|
💡 The stackone-agent-local MCP server is now available in this project`)),console.log(e.dim(`
|
|
130
130
|
💡 Tip: Run Claude without permission prompts:`),e.cyan(`claude --dangerously-skip-permissions`)),console.log(e.blue(`
|
|
131
131
|
Verify:`),e.cyan(`claude mcp list`)),console.log(``)}catch(t){u.fail(`Installation to Claude failed`),t instanceof Error&&(console.error(e.red(`\n✗ ${t.message}\n`)),console.error(e.dim(`Configuration files created, but Claude setup failed.`)),console.error(e.dim(`You can manually add the server later with:`)),console.error(e.cyan(` claude mcp add ${I()} ${P()} --scope local --transport http --header "Authorization: Bearer ${a.apiKey}"`))),console.log(``)}process.exit(0)}catch(t){t instanceof Error?console.error(e.red(`\n✗ ${t.message}\n`)):console.error(e.red(`
|
|
132
132
|
✗ Unknown error occurred
|
|
133
|
-
`)),process.exit(1)}}};const G=
|
|
133
|
+
`)),process.exit(1)}}};const G=E(w(),`.stackone`),K={profiles:{}},q=()=>{if(!b(G))return K;try{let e=x(G,`utf-8`);return JSON.parse(e)}catch{return K}},_e=e=>{let t=q();return t.profiles[e]},J=e=>{let t=q();return!!t.profiles[e]},ve=(e,t)=>{let n=q();n.profiles[e]=t;let r=E(w());b(r)||te(r,{recursive:!0}),ne(G,JSON.stringify(n,null,2),`utf-8`)},ye=()=>{let e=q();return Object.keys(e.profiles)};var Y=class{static info(t){console.info(e.blue(`ℹ`),t)}static warn(t){console.info(e.yellow(`⚠`),t)}static error(t){console.info(e.red(`✗`),t)}static success(t){console.info(e.green(`✓`),t)}};const be=`https://api.stackone.com`,xe=`https://api.stackone-dev.com`,Se=`http://localhost:4000`;var Ce=class{async execute({environment:t}={}){let n=t?.toLowerCase()??`production`;try{let{label:t}=await v.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(J(t)){let{overwrite:e}=await v.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${t}" already exists. Do you want to overwrite it?`,default:!1}]);e||(Y.info(`Configuration profile initialization cancelled`),process.exit(0))}let r;if(n===`production`)r=be;else if(n===`staging`)r=xe;else{let{customUrl:e}=await v.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:Se,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);r=e}let{apiKey:i}=await v.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),a={label:t,environment:n,apiUrl:r,apiKey:i};ve(t,a),console.info(e.green(`\n✓ Configuration profile "${t}" saved 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 X=`https://api.stackone.com`;var we=class{async execute({profile:e,fileOrDir:t,apiUrl:n,apiKey:r}={}){if(!e&&!r&&(Y.error(`Please provide a profile or API key to use for pushing the connector.`),Y.info(`You can provide these using the --profile and --api-key options.`),Y.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),e&&r&&(Y.error(`Please provide either a profile or an API key, not both.`),process.exit(1)),e&&n&&Y.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),e&&!J(e)){Y.error(`Configuration profile "${e}" not found.`),Y.info(`Run "stackone init" to create a new configuration profile.`);let t=ye();Y.info(`Available profiles: ${t.join(`, `)||`none`}`),process.exit(1)}let i=e?_e(e):{apiUrl:n??X,apiKey:r};i||(Y.error(`Failed to load configuration profile "${e}".`),process.exit(1)),i.apiKey||(Y.error(`API key is missing. Please provide a valid API key in the profile or via the --api-key option.`),process.exit(1)),t||(Y.error(`File or directory path is required.`),process.exit(1));try{C(t)}catch{Y.error(`File or directory not found: ${t}`),process.exit(1)}let a=C(t),o=i.apiUrl??X;if(a.isDirectory()){let e=Z(t),n=0;e.length===0?(Y.error(`No .s1.yaml connector files found in the directory: ${t}.`),process.exit(1)):Y.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let t of e){console.info(`
|
|
134
134
|
`);let e=await this.uploadFile(t,o,i.apiKey);e&&n++}console.info(`
|
|
135
|
-
`),Y.info(`Upload completed: ${n} of ${e.length} file(s) uploaded successfully.`),process.exit(n>0?0:1)}else t.endsWith(`.s1.yaml`)||(Y.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let s=await this.uploadFile(t,o,i.apiKey);process.exit(s?0:1)}async uploadFile(t,n,r){try{console.info(e.blue(`📤 Uploading ${
|
|
136
|
-
`))};if(r){try{
|
|
135
|
+
`),Y.info(`Upload completed: ${n} of ${e.length} file(s) uploaded successfully.`),process.exit(n>0?0:1)}else t.endsWith(`.s1.yaml`)||(Y.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let s=await this.uploadFile(t,o,i.apiKey);process.exit(s?0:1)}async uploadFile(t,n,r){try{console.info(e.blue(`📤 Uploading ${T(t)}...`));let i=Te(t);if(!i)return!1;let a=T(t),o=new FormData,s=new Blob([i],{type:`application/x-yaml`});o.append(`file`,s,a);let c=Buffer.from(r).toString(`base64`),l=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${c}`},body:o});if(!l.ok){let t=await l.text();return Y.error(`Upload failed: ${l.status} - ${l.statusText}`),t&&console.error(e.red(t)),!1}let u=await l.json();return console.info(e.green(`✓ Successfully uploaded ${a} with connector "${u.provider}@${u.version}"`)),!0}catch(e){return Y.error(`Failed to upload file: ${e}`),!1}}};const Te=t=>{let n=D(t),r=O(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return Y.success(`Connector ${e} is valid!`),n}else i.length>0?(Y.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))})):Y.error(`Connector ${t} is not valid. Please check the file for errors.`)},Z=e=>{let t=[],n=S(e,{withFileTypes:!0});for(let r of n){let n=E(e,r.name);r.isDirectory()?t.push(...Z(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var Ee=class{async execute(t){let{watchMode:n,fileOrDir:r}=t,i=p(`Watching for changes...`),a=()=>{console.clear(),console.info(e.yellow(`Watch mode enabled. Press "q" to quit.
|
|
136
|
+
`))};if(r){try{C(r)}catch{Y.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:t}=await import(`./esm-Wey0v-fi.js`),n=await import(`readline`),o=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(e.grey(`
|
|
137
137
|
|
|
138
|
-
Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(e.blue(`Running connector(s) validations...`)),await Q(r),i.start();let c=t(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async t=>{a(),i.stop(),console.info(e.blue(`File change detected. Running connector(s) validations...`)),await Q(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await Q(r),process.exit(0)}}};const Q=async e=>{let t=
|
|
139
|
-
`),!1;else return Y.error(`Connector ${t} is not valid. Please check the file for errors.`),!1},
|
|
138
|
+
Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(e.blue(`Running connector(s) validations...`)),await Q(r),i.start();let c=t(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async t=>{a(),i.stop(),console.info(e.blue(`File change detected. Running connector(s) validations...`)),await Q(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await Q(r),process.exit(0)}}};const Q=async e=>{let t=C(e);if(t.isDirectory()){let t=S(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){Y.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,i=0;for(let t of n){let n=`${e}/${t}`,a=C(n);if(a.isFile()){let e=await $(n);e?r++:i++}}Y.info(`Validation completed: ${r} valid, ${i} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await $(e):Y.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},$=async t=>{let n=D(t),r=O(n),i=r?.errors??[];if(r.success){let e=t.split(`/`).pop()||t;return Y.success(`Connector ${e} is valid!\n`),!0}else if(i.length>0)return Y.error(`Connector ${t} is not valid. Please fix the following errors:\n`),i.forEach(t=>{console.info(e.red(`- L${t.line}: ${t.message}`))}),console.info(`
|
|
139
|
+
`),!1;else return Y.error(`Connector ${t} is not valid. Please check the file for errors.`),!1},De=()=>{try{let e=ie(import.meta.url),t=re(e),n=E(t,`..`,`package.json`),r=JSON.parse(x(n,`utf8`));return r.version}catch{return`unknown`}};var Oe=class{constructor(e=new n,t=De()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let n=new Ce,r=new we,i=new Ee,a=new de,o=new ge,s=new z;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(t,n)=>{n(e.red(t))}}),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=>{n.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`).addArgument(new t(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),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)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${e.greenBright(`StackOne`)} ${e.grey(`CLI`)} ${e.whiteBright(this.version)}`),process.exit(0)});let c=this.program.command(`agent`).description(`StackOne agent commands`);c.command(`setup`).option(`-g, --global`,`Setup global configuration`).option(`-l, --local`,`Setup local project configuration`).description(`Setup StackOne agent (global or local)`).action(e=>{e.global?a.execute():o.execute()}),c.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{s.execute()})}run(){this.program.parse(process.argv)}};export{Oe as CLI};
|
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
const e=require(`./chunk-CUT6urMc.cjs`),t=e.__toESM(require(`chalk`)),n=e.__toESM(require(`commander`)),r=e.__toESM(require(`node:child_process`)),i=e.__toESM(require(`node:fs/promises`)),a=e.__toESM(require(`node:path`)),o=e.__toESM(require(`node:util`)),s=e.__toESM(require(`ora`)),c=e.__toESM(require(`node:
|
|
2
|
-
`));let e={configsCleaned:0};try{let n=(0,s.default)(`Removing stored configuration...`).start();await
|
|
1
|
+
const e=require(`./chunk-CUT6urMc.cjs`),t=e.__toESM(require(`chalk`)),n=e.__toESM(require(`commander`)),r=e.__toESM(require(`node:child_process`)),i=e.__toESM(require(`node:fs/promises`)),a=e.__toESM(require(`node:path`)),o=e.__toESM(require(`node:util`)),s=e.__toESM(require(`ora`)),c=e.__toESM(require(`node:fs`)),l=e.__toESM(require(`node:os`)),u=e.__toESM(require(`node:process`)),d=e.__toESM(require(`node:readline`)),f=e.__toESM(require(`inquirer`)),p=e.__toESM(require(`node:url`)),m=e.__toESM(require(`fs`)),h=e.__toESM(require(`os`)),g=e.__toESM(require(`path`)),_=e.__toESM(require(`@stackone/connect-sdk`)),ee=e.__toESM(require(`url`)),v=(0,a.join)((0,l.homedir)(),`.stackone`),y=(0,a.join)(v,`agent-config.json`),te=`stackone-agent-global`,b=`stackone-agent-local`,x=process.env.STACKONE_AGENT_SERVER_URL||`https://mcp-internal-falcon.stackonehq.workers.dev/mcp`;async function S(){let e=(0,c.existsSync)(v);e||await(0,i.mkdir)(v,{recursive:!0,mode:448})}async function C(e){await S(),await(0,i.writeFile)(y,JSON.stringify(e,null,2)),await(0,i.chmod)(y,384)}async function w(){try{let e=await(0,i.readFile)(y,`utf-8`);return JSON.parse(e)}catch{return null}}async function ne(){try{await(0,i.rm)(y,{force:!0})}catch{}}function T(){return x}function E(){return te}function D(){return b}function O(e){return new Date(e)<=new Date}function k(e){return!!e?.apiKey&&!O(e.expiresAt)}const A=(0,o.promisify)(r.exec);async function re(e){try{let t=await(0,i.readFile)(e,`utf-8`),n=JSON.parse(t),r=!1;if(n.mcpServers&&typeof n.mcpServers==`object`){for(let[e,t]of Object.entries(n.mcpServers))if(t&&typeof t==`object`&&`transport`in t){let e=t.transport;if(e&&typeof e==`object`&&`headers`in e){let t=e.headers;if(t&&typeof t==`object`&&`Authorization`in t){let e=t.Authorization;typeof e==`string`&&e.startsWith(`Bearer `)&&!e.includes("${")&&(t.Authorization="Bearer ${STACKONE_AGENT_MCP_TOKEN}",r=!0)}}}}return r&&await(0,i.writeFile)(e,JSON.stringify(n,null,2)),r}catch{return!1}}var ie=class{async execute(){console.log(t.default.blue.bold(`🧹 StackOne Agent Cleanup
|
|
2
|
+
`));let e={configsCleaned:0};try{let n=(0,s.default)(`Removing stored configuration...`).start();await ne(),n.succeed(`Removed ~/.stackone/agent-config.json`);let r=(0,s.default)(`Removing MCP servers from Claude...`).start(),i=0;try{let e=E();await A(`claude mcp remove ${e} 2>/dev/null`),i++}catch{}try{let e=D();await A(`claude mcp remove ${e} 2>/dev/null`),i++}catch{}i>0?r.succeed(`Removed ${i} MCP server(s) from Claude`):r.warn(`No MCP servers found in Claude (already removed or not configured)`);let o=(0,s.default)(`Checking for .mcp.json file...`).start(),c=process.cwd(),l=(0,a.join)(c,`.mcp.json`);try{let t=await re(l);t?(e.configsCleaned=1,o.succeed(`Cleaned .mcp.json (replaced tokens with environment variables)`)):o.info(`.mcp.json already uses environment variables or not found`)}catch{o.info(`.mcp.json not found (already cleaned or not created)`)}console.log(t.default.green(`
|
|
3
3
|
✓ Cleanup complete!`)),console.log(t.default.white(`
|
|
4
4
|
What was removed:`)),console.log(t.default.cyan(` • ~/.stackone/agent-config.json`)),console.log(t.default.cyan(` • MCP server from Claude configuration`)),e.configsCleaned>0&&console.log(t.default.cyan(` • Hardcoded credentials from .mcp.json`)),console.log(t.default.dim(`
|
|
5
5
|
To authenticate again:`)),console.log(t.default.cyan(` stackone agent setup --global`),t.default.dim(`(for global setup)`)),console.log(t.default.cyan(` stackone agent setup --local`),t.default.dim(`(for local project setup)`)),console.log(``),process.exit(0)}catch(e){e instanceof Error?console.error(t.default.red(`\n✗ ${e.message}\n`)):console.error(t.default.red(`
|
|
6
6
|
✗ Unknown error occurred
|
|
7
|
-
`)),process.exit(1)}}},
|
|
8
|
-
`));try{let e=process.cwd(),n=await(0,i.access)(`${e}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await(0,i.access)(`${e}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(t.default.yellow(`⚠ Existing local setup detected:`)),n&&console.log(t.default.dim(` • CLAUDE.md found in current directory`)),r&&console.log(t.default.dim(` • .mcp.json found in current directory`)),console.log();let{proceed:e}=await
|
|
9
|
-
Setup cancelled.`)),process.exit(0)),console.log()}let a=await
|
|
7
|
+
`)),process.exit(1)}}},ae=class{baseUrl;constructor(e){this.baseUrl=e||process.env.AUTH_SERVER_URL||`https://idp-api.stackone.com`}async login(e,t){try{let n=`${this.baseUrl}/auth/sign-in/mcp`,r=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({email:e,password:t})});if(!r.ok){let e=await r.text(),t={};try{t=JSON.parse(e)}catch{}return{success:!1,error:t.error||`HTTP ${r.status}: ${r.statusText}`}}let i=await r.text(),a=JSON.parse(i);return a.apiKey?{success:!0,apiKey:a.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=`${this.baseUrl}/api-key/verify`,n=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:e})});if(!n.ok){let e=await n.text(),t={};try{t=JSON.parse(e)}catch{}return{valid:!1,error:t.error||`HTTP ${n.status}: ${n.statusText}`}}let r=await n.text();return JSON.parse(r)}catch(e){return{valid:!1,error:e instanceof Error?e.message:`Network error occurred`}}}};const j=new ae,M=(0,o.promisify)(r.exec);function N(e){let t=new Date(e),n=new Date,r=t.getTime()-n.getTime(),i=Math.floor(r/(3600*1e3)),a=t.toLocaleTimeString(`en-US`,{hour:`numeric`,minute:`2-digit`,hour12:!0}),o=t.toDateString()===n.toDateString()?`Today`:t.toDateString()===new Date(n.getTime()+864e5).toDateString()?`Tomorrow`:t.toLocaleDateString(`en-US`,{month:`short`,day:`numeric`});return`${o} at ${a} (${i} hours from now)`}var P=class{async execute(){console.log(t.default.blue.bold(`🤖 StackOne Agent Setup - Global Configuration
|
|
8
|
+
`));try{let e=process.cwd(),n=await(0,i.access)(`${e}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await(0,i.access)(`${e}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(t.default.yellow(`⚠ Existing local setup detected:`)),n&&console.log(t.default.dim(` • CLAUDE.md found in current directory`)),r&&console.log(t.default.dim(` • .mcp.json found in current directory`)),console.log();let{proceed:e}=await f.default.prompt([{type:`confirm`,name:`proceed`,message:`Re-authenticate globally despite existing local setup?`,default:!0}]);e||(console.log(t.default.dim(`
|
|
9
|
+
Setup cancelled.`)),process.exit(0)),console.log()}let a=await w(),o;if(a?.email){console.log(t.default.dim(`Last used email: ${a.email}\n`));let{useExisting:e}=await f.default.prompt([{type:`confirm`,name:`useExisting`,message:`Sign in with this email?`,default:!0}]);if(e)o=a.email;else{let e=(0,d.createInterface)({input:u.stdin,output:u.stdout});o=await new Promise(n=>{e.question(t.default.white(`Email: `),e=>{n(e.trim())})}),e.close(),o||(console.error(t.default.red(`
|
|
10
10
|
✗ Email is required
|
|
11
|
-
`)),process.exit(1))}}else{let e=(0,
|
|
11
|
+
`)),process.exit(1))}}else{let e=(0,d.createInterface)({input:u.stdin,output:u.stdout});o=await new Promise(n=>{e.question(t.default.white(`Email: `),e=>{n(e.trim())})}),e.close(),o||(console.error(t.default.red(`
|
|
12
12
|
✗ Email is required
|
|
13
|
-
`)),process.exit(1))}let c=await
|
|
13
|
+
`)),process.exit(1))}let c=await f.default.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}]);c.password||(console.error(t.default.red(`
|
|
14
14
|
✗ Password is required
|
|
15
|
-
`)),process.exit(1)),console.log();let
|
|
16
|
-
`)),process.exit(1)),
|
|
17
|
-
✓ API key saved to ~/.stackone/agent-config.json`)),console.log(t.default.white(`✓ Key expires at`),t.default.cyan(
|
|
15
|
+
`)),process.exit(1)),console.log();let l=(0,s.default)(`Authenticating...`).start(),p=await j.login(o,c.password);(!p.success||!p.apiKey)&&(l.fail(`Authentication failed`),console.error(t.default.red(`\n✗ ${p.error||`Invalid credentials`}\n`)),console.log(t.default.dim(`Please check your email and password and try again.
|
|
16
|
+
`)),process.exit(1)),l.succeed(`Login successful!`);let m=new Date(Date.now()+1440*60*1e3).toISOString();await C({apiKey:p.apiKey,userId:o,email:o,expiresAt:m,serverUrl:T()}),console.log(t.default.green.bold(`
|
|
17
|
+
✓ API key saved to ~/.stackone/agent-config.json`)),console.log(t.default.white(`✓ Key expires at`),t.default.cyan(N(m)));let h=(0,s.default)(`Setting up global MCP configuration...`).start();try{let e=E(),n=T();try{await M(`claude mcp remove ${e} 2>/dev/null`)}catch{}let r=`claude mcp add ${e} ${n} --scope user --transport http --header "Authorization: Bearer ${p.apiKey}"`;await M(r),h.succeed(`Installed to Claude (global)`),console.log(t.default.green(`
|
|
18
18
|
✓ Global setup complete!`)),console.log(t.default.white(`Config location:`),t.default.cyan(`~/.claude.json`)),console.log(t.default.blue(`
|
|
19
19
|
Verify:`),t.default.cyan(`claude mcp list`)),console.log(t.default.dim(`
|
|
20
20
|
💡 Tip: Run Claude without permission prompts:`),t.default.cyan(`claude --dangerously-skip-permissions`)),console.log(t.default.dim(`
|
|
21
21
|
To setup for a specific project, run:`),t.default.cyan(`stackone agent setup --local`)),console.log(``)}catch(e){h.fail(`Installation to Claude failed`),e instanceof Error&&(console.error(t.default.red(`\n✗ ${e.message}\n`)),console.error(t.default.dim(`You can manually add the server later with:`)),console.error(t.default.cyan(` claude mcp add ${E()} ${T()} --scope user --transport http --header "Authorization: Bearer ${p.apiKey}"`)))}process.exit(0)}catch(e){e instanceof Error?console.error(t.default.red(`\n✗ ${e.message}\n`)):console.error(t.default.red(`
|
|
22
22
|
✗ Unknown error occurred
|
|
23
|
-
`)),process.exit(1)}}};const
|
|
23
|
+
`)),process.exit(1)}}};const F=(0,o.promisify)(r.exec),I=(0,p.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),L=(0,a.dirname)(I);async function R(){let e=(0,a.join)(L,`..`,`..`,`..`,`CLAUDE_TEMPLATE.md`);try{return await(0,i.readFile)(e,`utf-8`)}catch{return`# 🚀 STACKONE API CONFIG BUILDER
|
|
24
24
|
|
|
25
25
|
This document provides the complete methodology for building StackOne API configurations with Claude. Follow this strict workflow to ensure comprehensive, tested, and customer-valuable integrations.
|
|
26
26
|
|
|
@@ -104,7 +104,7 @@ stackone agent cleanup
|
|
|
104
104
|
|
|
105
105
|
*Authenticated with StackOne • Agent MCP Server*
|
|
106
106
|
*For full workflow details, see the complete CLAUDE.md in repository*
|
|
107
|
-
`}}const
|
|
107
|
+
`}}const z=()=>`{
|
|
108
108
|
"mcpServers": {
|
|
109
109
|
"${D()}": {
|
|
110
110
|
"url": "${T()}",
|
|
@@ -116,24 +116,24 @@ stackone agent cleanup
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
}
|
|
119
|
-
}`;var
|
|
120
|
-
`));try{let e=process.cwd(),n=await(0,i.access)(`${e}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await(0,i.access)(`${e}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(t.default.yellow(`⚠ Existing local setup detected:`)),n&&console.log(t.default.dim(` • CLAUDE.md found`)),r&&console.log(t.default.dim(` • .mcp.json found`)),console.log();let{proceed:e}=await
|
|
121
|
-
Setup cancelled.`)),process.exit(0)),console.log()}let a=await
|
|
122
|
-
`));let e=(0,
|
|
119
|
+
}`;var B=class{async execute(){console.log(t.default.blue.bold(`🤖 StackOne Agent Setup - Local Project
|
|
120
|
+
`));try{let e=process.cwd(),n=await(0,i.access)(`${e}/CLAUDE.md`).then(()=>!0).catch(()=>!1),r=await(0,i.access)(`${e}/.mcp.json`).then(()=>!0).catch(()=>!1);if(n||r){console.log(t.default.yellow(`⚠ Existing local setup detected:`)),n&&console.log(t.default.dim(` • CLAUDE.md found`)),r&&console.log(t.default.dim(` • .mcp.json found`)),console.log();let{proceed:e}=await f.default.prompt([{type:`confirm`,name:`proceed`,message:`Overwrite existing local configuration?`,default:!1}]);e||(console.log(t.default.dim(`
|
|
121
|
+
Setup cancelled.`)),process.exit(0)),console.log()}let a=await w();if(!a||!k(a)){console.log(t.default.yellow(`⚠ Not authenticated globally.`)),console.log(t.default.white(`Let's authenticate now...
|
|
122
|
+
`));let e=(0,d.createInterface)({input:u.stdin,output:u.stdout}),n=await new Promise(n=>{e.question(t.default.white(`Email: `),e=>{n(e.trim())})});e.close(),n||(console.error(t.default.red(`
|
|
123
123
|
✗ Email is required
|
|
124
|
-
`)),process.exit(1));let r=await
|
|
124
|
+
`)),process.exit(1));let r=await f.default.prompt([{type:`password`,name:`password`,message:`Password:`,mask:`*`}]);r.password||(console.error(t.default.red(`
|
|
125
125
|
✗ Password is required
|
|
126
|
-
`)),process.exit(1)),console.log();let i=(0,s.default)(`Authenticating...`).start(),o=await
|
|
127
|
-
`)),process.exit(1)),i.succeed(`Login successful!`);let c=new Date(Date.now()+1440*60*1e3).toISOString();await
|
|
126
|
+
`)),process.exit(1)),console.log();let i=(0,s.default)(`Authenticating...`).start(),o=await j.login(n,r.password);(!o.success||!o.apiKey)&&(i.fail(`Authentication failed`),console.error(t.default.red(`\n✗ ${o.error||`Invalid credentials`}\n`)),console.log(t.default.dim(`Please check your email and password and try again.
|
|
127
|
+
`)),process.exit(1)),i.succeed(`Login successful!`);let c=new Date(Date.now()+1440*60*1e3).toISOString();await C({apiKey:o.apiKey,userId:n,email:n,expiresAt:c,serverUrl:T()}),a={apiKey:o.apiKey,userId:n,email:n,expiresAt:c,serverUrl:T()},console.log()}let o=(0,s.default)(`Setting up local project configuration...`).start();o.text=`Creating CLAUDE.md...`;let c=await R();await(0,i.writeFile)(`CLAUDE.md`,c),o.succeed(`Created CLAUDE.md`);let l=(0,s.default)(`Creating .mcp.json...`).start();await(0,i.writeFile)(`.mcp.json`,z()),l.succeed(`Created .mcp.json (using STACKONE_AGENT_MCP_TOKEN env var)`);let p=(0,s.default)(`Installing to Claude (local)...`).start();try{let e=D();try{await F(`claude mcp remove ${e} 2>/dev/null`)}catch{}let n=`claude mcp add ${e} ${T()} --scope local --transport http --header "Authorization: Bearer ${a.apiKey}"`;await F(n),p.succeed(`Installed to Claude (local)`),console.log(t.default.green(`
|
|
128
128
|
✓ Local setup complete!`)),console.log(t.default.white(`Files created:`)),console.log(t.default.cyan(` - CLAUDE.md`)),console.log(t.default.cyan(` - .mcp.json`)),console.log(t.default.dim(`
|
|
129
129
|
💡 The stackone-agent-local MCP server is now available in this project`)),console.log(t.default.dim(`
|
|
130
130
|
💡 Tip: Run Claude without permission prompts:`),t.default.cyan(`claude --dangerously-skip-permissions`)),console.log(t.default.blue(`
|
|
131
131
|
Verify:`),t.default.cyan(`claude mcp list`)),console.log(``)}catch(e){p.fail(`Installation to Claude failed`),e instanceof Error&&(console.error(t.default.red(`\n✗ ${e.message}\n`)),console.error(t.default.dim(`Configuration files created, but Claude setup failed.`)),console.error(t.default.dim(`You can manually add the server later with:`)),console.error(t.default.cyan(` claude mcp add ${D()} ${T()} --scope local --transport http --header "Authorization: Bearer ${a.apiKey}"`))),console.log(``)}process.exit(0)}catch(e){e instanceof Error?console.error(t.default.red(`\n✗ ${e.message}\n`)):console.error(t.default.red(`
|
|
132
132
|
✗ Unknown error occurred
|
|
133
|
-
`)),process.exit(1)}}};const
|
|
133
|
+
`)),process.exit(1)}}};const V=(0,g.join)((0,h.homedir)(),`.stackone`),H={profiles:{}},U=()=>{if(!(0,m.existsSync)(V))return H;try{let e=(0,m.readFileSync)(V,`utf-8`);return JSON.parse(e)}catch{return H}},W=e=>{let t=U();return t.profiles[e]},G=e=>{let t=U();return!!t.profiles[e]},K=(e,t)=>{let n=U();n.profiles[e]=t;let r=(0,g.join)((0,h.homedir)());(0,m.existsSync)(r)||(0,m.mkdirSync)(r,{recursive:!0}),(0,m.writeFileSync)(V,JSON.stringify(n,null,2),`utf-8`)},q=()=>{let e=U();return Object.keys(e.profiles)};var J=class{static info(e){console.info(t.default.blue(`ℹ`),e)}static warn(e){console.info(t.default.yellow(`⚠`),e)}static error(e){console.info(t.default.red(`✗`),e)}static success(e){console.info(t.default.green(`✓`),e)}};const oe=`https://api.stackone.com`,se=`https://api.stackone-dev.com`,ce=`http://localhost:4000`;var le=class{async execute({environment:e}={}){let n=e?.toLowerCase()??`production`;try{let{label:e}=await f.default.prompt([{type:`input`,name:`label`,message:`Profile label:`,validate:e=>!e||e.trim().length===0?`The profile label is required`:e.includes(` `)?`The profile label cannot contain spaces`:!0}]);if(G(e)){let{overwrite:t}=await f.default.prompt([{type:`confirm`,name:`overwrite`,message:`Configuration profile with name "${e}" already exists. Do you want to overwrite it?`,default:!1}]);t||(J.info(`Configuration profile initialization cancelled`),process.exit(0))}let r;if(n===`production`)r=oe;else if(n===`staging`)r=se;else{let{customUrl:e}=await f.default.prompt([{type:`input`,name:`customUrl`,message:`API URL:`,default:ce,validate:e=>{if(!e||e.trim().length===0)return`API URL is required`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}]);r=e}let{apiKey:i}=await f.default.prompt([{type:`password`,name:`apiKey`,message:`API Key:`,validate:e=>!e||e.trim().length===0?`API Key is required`:!0}]),a={label:e,environment:n,apiUrl:r,apiKey:i};K(e,a),console.info(t.default.green(`\n✓ Configuration profile "${e}" saved successfully`)),process.exit(0)}catch(e){e.isTtyError?J.error(`Prompt couldn't be rendered in the current environment`):J.error(`Failed to initialize configuration profile: ${e}`),process.exit(1)}}};const Y=`https://api.stackone.com`;var X=class{async execute({profile:e,fileOrDir:t,apiUrl:n,apiKey:r}={}){if(!e&&!r&&(J.error(`Please provide a profile or API key to use for pushing the connector.`),J.info(`You can provide these using the --profile and --api-key options.`),J.info(`Run "stackone init" to create a new configuration profile.`),process.exit(1)),e&&r&&(J.error(`Please provide either a profile or an API key, not both.`),process.exit(1)),e&&n&&J.warn(`Specifying --api-url with a profile won't have any effect. Using API url from profile.`),e&&!G(e)){J.error(`Configuration profile "${e}" not found.`),J.info(`Run "stackone init" to create a new configuration profile.`);let t=q();J.info(`Available profiles: ${t.join(`, `)||`none`}`),process.exit(1)}let i=e?W(e):{apiUrl:n??Y,apiKey:r};i||(J.error(`Failed to load configuration profile "${e}".`),process.exit(1)),i.apiKey||(J.error(`API key is missing. Please provide a valid API key in the profile or via the --api-key option.`),process.exit(1)),t||(J.error(`File or directory path is required.`),process.exit(1));try{(0,m.statSync)(t)}catch{J.error(`File or directory not found: ${t}`),process.exit(1)}let a=(0,m.statSync)(t),o=i.apiUrl??Y;if(a.isDirectory()){let e=Z(t),n=0;e.length===0?(J.error(`No .s1.yaml connector files found in the directory: ${t}.`),process.exit(1)):J.info(`Found ${e.length} connector(s) file(s). Processing...`);for(let t of e){console.info(`
|
|
134
134
|
`);let e=await this.uploadFile(t,o,i.apiKey);e&&n++}console.info(`
|
|
135
|
-
`),
|
|
136
|
-
`))};if(r){try{(0,
|
|
135
|
+
`),J.info(`Upload completed: ${n} of ${e.length} file(s) uploaded successfully.`),process.exit(n>0?0:1)}else t.endsWith(`.s1.yaml`)||(J.error(`Only .s1.yaml files are supported for upload.`),process.exit(1));let s=await this.uploadFile(t,o,i.apiKey);process.exit(s?0:1)}async uploadFile(e,n,r){try{console.info(t.default.blue(`📤 Uploading ${(0,g.basename)(e)}...`));let i=ue(e);if(!i)return!1;let a=(0,g.basename)(e),o=new FormData,s=new Blob([i],{type:`application/x-yaml`});o.append(`file`,s,a);let c=Buffer.from(r).toString(`base64`),l=await fetch(`${n}/registry/connectors`,{method:`POST`,headers:{Authorization:`Basic ${c}`},body:o});if(!l.ok){let e=await l.text();return J.error(`Upload failed: ${l.status} - ${l.statusText}`),e&&console.error(t.default.red(e)),!1}let u=await l.json();return console.info(t.default.green(`✓ Successfully uploaded ${a} with connector "${u.provider}@${u.version}"`)),!0}catch(e){return J.error(`Failed to upload file: ${e}`),!1}}};const ue=e=>{let n=(0,_.loadConnector)(e),r=(0,_.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return J.success(`Connector ${t} is valid!`),n}else i.length>0?(J.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))})):J.error(`Connector ${e} is not valid. Please check the file for errors.`)},Z=e=>{let t=[],n=(0,m.readdirSync)(e,{withFileTypes:!0});for(let r of n){let n=(0,g.join)(e,r.name);r.isDirectory()?t.push(...Z(n)):r.name.endsWith(`.s1.yaml`)&&t.push(n)}return t};var de=class{async execute(e){let{watchMode:n,fileOrDir:r}=e,i=(0,s.default)(`Watching for changes...`),a=()=>{console.clear(),console.info(t.default.yellow(`Watch mode enabled. Press "q" to quit.
|
|
136
|
+
`))};if(r){try{(0,m.statSync)(r)}catch{J.error(`File or directory not found: ${r}`),process.exit(1)}if(n){let{watch:e}=await Promise.resolve().then(()=>require(`./esm-BSZWAx0q.cjs`)),n=await import(`readline`),o=n.createInterface({input:process.stdin,output:process.stdout});process.stdin.setRawMode(!0),process.stdin.resume(),process.stdin.setEncoding(`utf8`);let s=()=>{console.info(t.default.grey(`
|
|
137
137
|
|
|
138
|
-
Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(t.default.blue(`Running connector(s) validations...`)),await Q(r),i.start();let c=e(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async e=>{a(),i.stop(),console.info(t.default.blue(`File change detected. Running connector(s) validations...`)),await Q(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await Q(r),process.exit(0)}}};const Q=async e=>{let t=(0,
|
|
139
|
-
`),!1;else return
|
|
138
|
+
Exiting watch mode...`)),c.close(),i.stop(),o.close(),process.exit(0)};a(),console.info(t.default.blue(`Running connector(s) validations...`)),await Q(r),i.start();let c=e(r||`.`,{ignored:/(^|[/\\])\../,persistent:!0});c.on(`change`,async e=>{a(),i.stop(),console.info(t.default.blue(`File change detected. Running connector(s) validations...`)),await Q(r),i.start()}),process.stdin.on(`data`,e=>{e.toString()===`q`&&s()}),process.on(`SIGINT`,()=>{s()})}else await Q(r),process.exit(0)}}};const Q=async e=>{let t=(0,m.statSync)(e);if(t.isDirectory()){let t=(0,m.readdirSync)(e),n=t.filter(e=>e.endsWith(`.s1.yaml`));if(n.length===0){J.error(`No StackOne connectors found in directory: ${e}. Connector files need to have the extension .s1.yaml.\n`);return}let r=0,i=0;for(let t of n){let n=`${e}/${t}`,a=(0,m.statSync)(n);if(a.isFile()){let e=await $(n);e?r++:i++}}J.info(`Validation completed: ${r} valid, ${i} invalid connectors.\n`)}else t.isFile()&&e.endsWith(`s1.yaml`)?await $(e):J.error(`No StackOne connector found: ${e}. Connector files need to have the extension .s1.yaml.\n`)},$=async e=>{let n=(0,_.loadConnector)(e),r=(0,_.validateYamlConnector)(n),i=r?.errors??[];if(r.success){let t=e.split(`/`).pop()||e;return J.success(`Connector ${t} is valid!\n`),!0}else if(i.length>0)return J.error(`Connector ${e} is not valid. Please fix the following errors:\n`),i.forEach(e=>{console.info(t.default.red(`- L${e.line}: ${e.message}`))}),console.info(`
|
|
139
|
+
`),!1;else return J.error(`Connector ${e} is not valid. Please check the file for errors.`),!1},fe=()=>{try{let e=(0,ee.fileURLToPath)(require(`url`).pathToFileURL(__filename).href),t=(0,g.dirname)(e),n=(0,g.join)(t,`..`,`package.json`),r=JSON.parse((0,m.readFileSync)(n,`utf8`));return r.version}catch{return`unknown`}};var pe=class{constructor(e=new n.Command,t=fe()){this.program=e,this.version=t,this.setupProgram(),this.registerCommands()}setupProgram(){this.program.name(`stackone`).description(`StackOne CLI`).version(this.version,`-v, --version`)}registerCommands(){let e=new le,r=new X,i=new de,a=new P,o=new B,s=new ie;this.program.configureOutput({writeOut:e=>process.stdout.write(e),writeErr:e=>process.stderr.write(e),outputError:(e,n)=>{n(t.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(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`).addArgument(new n.Argument(`<path>`,`Connector file or directory to push`)).description(`Push a connector to the StackOne registry`).action((e,t)=>{r.execute({profile:t.profile,fileOrDir:e,apiUrl:t.apiUrl,apiKey:t.apiKey})}),this.program.command(`validate`).option(`-w, --watch`,`Run in watch mode`).addArgument(new n.Argument(`<path>`,`Connector file or directory with connectors to validate`)).description(`Validate a StackOne connector`).action((e,t)=>{i.execute({watchMode:t.watch,fileOrDir:e})}),this.program.command(`version`).description(`Show version information`).action(()=>{console.info(`${t.default.greenBright(`StackOne`)} ${t.default.grey(`CLI`)} ${t.default.whiteBright(this.version)}`),process.exit(0)});let c=this.program.command(`agent`).description(`StackOne agent commands`);c.command(`setup`).option(`-g, --global`,`Setup global configuration`).option(`-l, --local`,`Setup local project configuration`).description(`Setup StackOne agent (global or local)`).action(e=>{e.global?a.execute():o.execute()}),c.command(`cleanup`).description(`Remove all API keys and credentials from configurations`).action(()=>{s.execute()})}run(){this.program.parse(process.argv)}};Object.defineProperty(exports,`CLI`,{enumerable:!0,get:function(){return pe}});
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./cliCore-
|
|
1
|
+
const e=require(`./cliCore-BRPqDxQ9.cjs`);exports.CLI=e.CLI;
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CLI as e}from"./cliCore-
|
|
1
|
+
import{CLI as e}from"./cliCore-57MzGvkG.js";export{e as CLI};
|