Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 7
feat(example): add interactive CLI demo with @clack/prompts#203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,160 @@ | ||||||||||||||||
| /** | ||||||||||||||||
| * Interactive CLI Demo | ||||||||||||||||
| * | ||||||||||||||||
| * This example demonstrates how to build an interactive CLI tool using | ||||||||||||||||
| * @clack/prompts to dynamically discover and execute StackOne tools. | ||||||||||||||||
| * | ||||||||||||||||
| * Features: | ||||||||||||||||
| * - Interactive credential input with environment variable fallback | ||||||||||||||||
| * - Dynamic tool discovery and selection | ||||||||||||||||
| * - Spinner feedback during async operations | ||||||||||||||||
| * | ||||||||||||||||
| * Run with: | ||||||||||||||||
| * ```bash | ||||||||||||||||
| * npx tsx examples/interactive-cli.ts | ||||||||||||||||
| * ``` | ||||||||||||||||
| */ | ||||||||||||||||
| import process from 'node:process'; | ||||||||||||||||
| import * as clack from '@clack/prompts'; | ||||||||||||||||
| import { StackOneToolSet } from '@stackone/ai'; | ||||||||||||||||
| // Enable verbose fetch logging when running with Bun | ||||||||||||||||
| process.env.BUN_CONFIG_VERBOSE_FETCH = 'curl'; | ||||||||||||||||
| ||||||||||||||||
| clack.intro('Welcome to StackOne AI Tool Tester'); | ||||||||||||||||
| // Check if environment variables are available | ||||||||||||||||
| const hasEnvVars = process.env.STACKONE_API_KEY && process.env.STACKONE_ACCOUNT_ID; | ||||||||||||||||
| let apiKey: string; | ||||||||||||||||
| let baseUrl: string; | ||||||||||||||||
| let accountId: string; | ||||||||||||||||
| if (hasEnvVars) { | ||||||||||||||||
| const useEnv = await clack.confirm({ | ||||||||||||||||
| message: 'Use environment variables from .env file?', | ||||||||||||||||
| }); | ||||||||||||||||
| if (clack.isCancel(useEnv)) { | ||||||||||||||||
| clack.cancel('Operation cancelled'); | ||||||||||||||||
| process.exit(0); | ||||||||||||||||
| } | ||||||||||||||||
| if (useEnv) { | ||||||||||||||||
| apiKey = process.env.STACKONE_API_KEY!; | ||||||||||||||||
| baseUrl = process.env.STACKONE_BASE_URL || 'https://api.stackone.com'; | ||||||||||||||||
| accountId = process.env.STACKONE_ACCOUNT_ID!; | ||||||||||||||||
| } else { | ||||||||||||||||
| const credentials = await promptCredentials(); | ||||||||||||||||
| apiKey = credentials.apiKey; | ||||||||||||||||
| baseUrl = credentials.baseUrl; | ||||||||||||||||
| accountId = credentials.accountId; | ||||||||||||||||
| } | ||||||||||||||||
| } else { | ||||||||||||||||
| const credentials = await promptCredentials(); | ||||||||||||||||
| apiKey = credentials.apiKey; | ||||||||||||||||
| baseUrl = credentials.baseUrl; | ||||||||||||||||
| accountId = credentials.accountId; | ||||||||||||||||
| } | ||||||||||||||||
| async function promptCredentials(): Promise<{ | ||||||||||||||||
| apiKey: string; | ||||||||||||||||
| baseUrl: string; | ||||||||||||||||
| accountId: string; | ||||||||||||||||
| }> { | ||||||||||||||||
| const apiKeyInput = await clack.text({ | ||||||||||||||||
| message: 'Enter your StackOne API key:', | ||||||||||||||||
| placeholder: 'v1.us1.xxx...', | ||||||||||||||||
| validate: (value) => { | ||||||||||||||||
| if (!value) return 'API key is required'; | ||||||||||||||||
| }, | ||||||||||||||||
| }); | ||||||||||||||||
| if (clack.isCancel(apiKeyInput)) { | ||||||||||||||||
| clack.cancel('Operation cancelled'); | ||||||||||||||||
| process.exit(0); | ||||||||||||||||
| } | ||||||||||||||||
| const baseUrlInput = await clack.text({ | ||||||||||||||||
| message: 'Enter StackOne Base URL (optional):', | ||||||||||||||||
| placeholder: 'https://api.stackone.com', | ||||||||||||||||
| defaultValue: 'https://api.stackone.com', | ||||||||||||||||
| }); | ||||||||||||||||
| if (clack.isCancel(baseUrlInput)) { | ||||||||||||||||
| clack.cancel('Operation cancelled'); | ||||||||||||||||
| process.exit(0); | ||||||||||||||||
| } | ||||||||||||||||
| const accountIdInput = await clack.text({ | ||||||||||||||||
| message: 'Enter your StackOne Account ID:', | ||||||||||||||||
| placeholder: 'acc_xxx...', | ||||||||||||||||
| validate: (value) => { | ||||||||||||||||
| if (!value) return 'Account ID is required'; | ||||||||||||||||
| }, | ||||||||||||||||
| }); | ||||||||||||||||
| if (clack.isCancel(accountIdInput)) { | ||||||||||||||||
| clack.cancel('Operation cancelled'); | ||||||||||||||||
| process.exit(0); | ||||||||||||||||
| } | ||||||||||||||||
| return { | ||||||||||||||||
| apiKey: apiKeyInput as string, | ||||||||||||||||
| baseUrl: baseUrlInput as string, | ||||||||||||||||
| accountId: accountIdInput as string, | ||||||||||||||||
| }; | ||||||||||||||||
| } | ||||||||||||||||
| const spinner = clack.spinner(); | ||||||||||||||||
| spinner.start('Initialising StackOne client...'); | ||||||||||||||||
| const toolset = new StackOneToolSet({ | ||||||||||||||||
| apiKey, | ||||||||||||||||
| baseUrl, | ||||||||||||||||
| accountId, | ||||||||||||||||
| }); | ||||||||||||||||
| spinner.message('Fetching available tools...'); | ||||||||||||||||
| const tools = await toolset.fetchTools(); | ||||||||||||||||
| const allTools = tools.toArray(); | ||||||||||||||||
CopilotAI | ||||||||||||||||
| constallTools=tools.toArray(); | |
| constallTools=tools.toArray(); | |
| if(allTools.length===0){ | |
| spinner.stop('No tools found'); | |
| clack.log.error('No tools available. Please check your API key and account ID.'); | |
| process.exit(1); | |
| } |
CopilotAIDec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hardcoding { query: { limit: 5 } } as execution parameters may not work for all tools. Different tools have different parameter requirements. Some tools may not accept a query parameter or limit field, which could cause execution failures. Consider either:
- Prompting the user for parameters based on the selected tool's schema
- Using empty parameters
{}for a more generic approach - Adding error handling that explains parameter mismatches
| constresult=awaitselectedTool.execute({ | |
| query: {limit: 5}, | |
| }); | |
| constresult=awaitselectedTool.execute({}); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
CopilotAIDec 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The file header documentation lists features but omits "Verbose fetch logging when running with Bun" which is mentioned in the PR description and implemented on line 23. For completeness, consider adding this feature to the documentation comment, or clarify that it's an internal implementation detail not intended as a user-facing feature.