Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ brew install integromat/tap/make-cli
npm install -g @makehq/cli
```

Or run directly without installing:

```bash
npx @makehq/cli scenarios list --team-id=123
```

### Binary releases

Pre-built binaries are available for download from the [GitHub Releases](https://github.com/integromat/make-cli/releases) page:
Expand Down
12 changes: 6 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@makehq/cli",
"version": "1.2.1",
"version": "1.3.0",
"description": "A command-line tool for Make automation platform",
"license": "MIT",
"author": "Make",
Expand All @@ -17,7 +17,8 @@
"build": "tsup",
"test": "jest --coverage --coverageReporters=\"text\" --runInBand --forceExit --verbose false --testMatch \"**/test/**/*.spec.ts\"",
"lint": "tsc && eslint --quiet .",
"format": "npx prettier . --write"
"format": "npx prettier . --write",
"build:docs": "npx tsx scripts/build-docs.ts"
},
"engines": {
"node": ">=20"
Expand All @@ -27,7 +28,7 @@
],
"dependencies": {
"@inquirer/prompts": "^8.3.2",
"@makehq/sdk": "^1.1.1",
"@makehq/sdk": "^1.2.1",
"commander": "^14.0.3",
"open": "^11.0.0"
},
Expand Down
185 changes: 185 additions & 0 deletions scripts/build-docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { writeFileSync, mkdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { MakeMCPTools } from '@makehq/sdk/mcp';
import type { MakeMCPTool, JSONSchema } from '@makehq/sdk/mcp';
import { CATEGORY_TITLES, CATEGORY_GROUPS } from '../src/categories.js';
import { camelToKebab, formatExampleCommand } from '../src/examples.js';
import { deriveActionName } from '../src/commands.js';

const DOCS_DIR = join(import.meta.dirname, '..', 'docs');
Comment thread
patriksimek marked this conversation as resolved.

function schemaTypeLabel(schema: JSONSchema): string {
const type = Array.isArray(schema.type) ? schema.type[0] : schema.type;
if (type === 'array' && schema.items) {
const inner = Array.isArray(schema.items.type) ? schema.items.type[0] : schema.items.type;
return `${inner}[]`;
}
return type ?? 'string';
}

function buildToolSection(tool: MakeMCPTool, categorySlug: string): string {
const action = deriveActionName(tool.name, tool.category);
const lines: string[] = [];

lines.push(`### \`make-cli ${categorySlug} ${action}\``);
lines.push('');
lines.push(tool.description);
lines.push('');

const properties = tool.inputSchema.properties ?? {};
const required = new Set(tool.inputSchema.required ?? []);
const propEntries = Object.entries(properties);

if (propEntries.length > 0) {
lines.push('**Options**');
lines.push('');
lines.push('| Option | Description | Required |');
lines.push('|--------|-------------|----------|');

for (const [propName, schema] of propEntries) {
const flagName = camelToKebab(propName);
const type = schemaTypeLabel(schema);
const isBooleanFlag = type === 'boolean';
const flag = isBooleanFlag
? schema.default === true
? `--no-${flagName}`
: `--${flagName}`
: `--${flagName}`;

const isRequired = required.has(propName) && !isBooleanFlag;
const propDesc = schema.description?.replace(/\|/g, '\\|').replace(/\n/g, ' ') ?? '';

lines.push(`| \`${flag}\` | ${propDesc} | ${isRequired ? 'Yes' : 'No'} |`);
}

lines.push('');
}

lines.push('**Example**');
lines.push('');
lines.push('```bash');

const cmd = `make-cli ${categorySlug} ${action}`;
const example = tool.examples?.[0];
if (example && Object.keys(example).length > 0) {
lines.push(formatExampleCommand(cmd, example));
} else {
lines.push(cmd);
}

lines.push('```');

return lines.join('\n');
}

function buildCategoryDoc(categorySlug: string, tools: MakeMCPTool[]): string {
const originalCategory = tools[0]!.category;
const title = CATEGORY_TITLES[originalCategory] ?? categorySlug;
const lines: string[] = [];

lines.push(`## ${title}`);
lines.push('');
lines.push(`Manage your ${title.toLowerCase()}.`);
lines.push('');
lines.push('---');

for (let i = 0; i < tools.length; i++) {
lines.push('');
lines.push(buildToolSection(tools[i]!, categorySlug));
if (i < tools.length - 1) {
lines.push('');
lines.push('---');
}
}

lines.push('');

return lines.join('\n');
}

function buildIndex(categoryMap: Map<string, MakeMCPTool[]>): string {
const lines: string[] = [];

lines.push('# Make CLI Documentation');
lines.push('');
lines.push('Command-line tool for the [Make](https://www.make.com) automation platform.');
lines.push('');
lines.push('## Global Options');
lines.push('');
lines.push('| Flag | Description |');
lines.push('| --- | --- |');
lines.push('| `--api-key <key>` | Make API key (or set `MAKE_API_KEY` env var) |');
lines.push('| `--zone <zone>` | Make zone, e.g. `eu1.make.com` (or set `MAKE_ZONE` env var) |');
lines.push('| `--output <format>` | Output format: `json` (default), `compact`, `table` |');
lines.push('| `--version` | Show version number |');
lines.push('| `--help` | Display help |');
lines.push('');
lines.push('## Authentication');
lines.push('');
lines.push('```bash');
lines.push('# Interactive login (saves credentials locally)');
lines.push('make-cli login');
lines.push('');
lines.push('# Check who you are logged in as');
lines.push('make-cli whoami');
lines.push('');
lines.push('# Log out');
lines.push('make-cli logout');
lines.push('```');
lines.push('');
lines.push('## Command Reference');
lines.push('');

const groups = new Map<string, { slug: string; title: string }[]>();

for (const [slug, tools] of categoryMap) {
const originalCategory = tools[0]!.category;
const title = CATEGORY_TITLES[originalCategory] ?? slug;
const group = CATEGORY_GROUPS[originalCategory] ?? 'Commands:';
const groupName = group.replace(/:$/, '');

const entries = groups.get(groupName) ?? [];
entries.push({ slug, title });
groups.set(groupName, entries);
}

for (const [groupName, entries] of groups) {
lines.push(`### ${groupName}`);
lines.push('');
lines.push('| Category | Description |');
lines.push('| --- | --- |');
for (const { slug, title } of entries) {
lines.push(`| [\`${slug}\`](./${slug}.md) | ${title} |`);
}
lines.push('');
}

return lines.join('\n');
}

// --- Main ---

const categoryMap = new Map<string, MakeMCPTool[]>();

for (const tool of MakeMCPTools) {
const slug = tool.category.replace(/\./g, '-');
const group = categoryMap.get(slug) ?? [];
group.push(tool);
categoryMap.set(slug, group);
}

if (!existsSync(DOCS_DIR)) {
mkdirSync(DOCS_DIR, { recursive: true });
}

for (const [slug, tools] of categoryMap) {
const content = buildCategoryDoc(slug, tools);
writeFileSync(join(DOCS_DIR, `${slug}.md`), content);
}

const index = buildIndex(categoryMap);
writeFileSync(join(DOCS_DIR, 'README.md'), index);

const totalTools = MakeMCPTools.length;
const totalCategories = categoryMap.size;
console.log(`Generated docs for ${totalTools} commands across ${totalCategories} categories in docs/`);
52 changes: 26 additions & 26 deletions src/categories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,45 +14,45 @@ export const CATEGORY_GROUPS: Record<string, string> = {
hooks: 'Scenarios:',
devices: 'Scenarios:',
'data-structures': 'Scenarios:',
'data-stores': 'Data Stores:',
'data-store-records': 'Data Stores:',
teams: 'Account Management:',
organizations: 'Account Management:',
users: 'Account Management:',
'data-stores': 'Data stores:',
'data-store-records': 'Data stores:',
teams: 'Account management:',
organizations: 'Account management:',
users: 'Account management:',
enums: 'Others:',
// SDK categories
'sdk-apps': 'Custom App Development:',
'sdk-connections': 'Custom App Development:',
'sdk-functions': 'Custom App Development:',
'sdk-modules': 'Custom App Development:',
'sdk-rpcs': 'Custom App Development:',
'sdk-webhooks': 'Custom App Development:',
'sdk-apps': 'Custom app development:',
'sdk-connections': 'Custom app development:',
'sdk-functions': 'Custom app development:',
'sdk-modules': 'Custom app development:',
'sdk-rpcs': 'Custom app development:',
'sdk-webhooks': 'Custom app development:',
};

export const CATEGORY_TITLES: Record<string, string> = {
// Top-level categories
connections: 'Connections',
'credential-requests': 'Credential Requests',
'data-store-records': 'Data Store Records',
'data-stores': 'Data Stores',
'data-structures': 'Data Structures',
enums: 'Shared Enumerations',
executions: 'Scenario Executions',
folders: 'Scenario Folders',
functions: 'Custom Functions',
'credential-requests': 'Credential requests',
'data-store-records': 'Data store records',
'data-stores': 'Data stores',
'data-structures': 'Data structures',
enums: 'Shared enumerations',
executions: 'Scenario executions',
folders: 'Scenario folders',
functions: 'Custom functions',
hooks: 'Webhooks',
devices: 'Devices',
'incomplete-executions': 'Incomplete Executions',
'incomplete-executions': 'Incomplete executions',
keys: 'Keys',
organizations: 'Organizations',
scenarios: 'Scenarios',
teams: 'Teams',
users: 'Users',
// SDK categories
'sdk-apps': 'App Definitions',
'sdk-connections': 'App Connections',
'sdk-functions': 'App Functions',
'sdk-modules': 'App Modules',
'sdk-rpcs': 'App Remote Procedures',
'sdk-webhooks': 'App Webhooks',
'sdk-apps': 'App definitions',
'sdk-connections': 'App connections',
'sdk-functions': 'App functions',
'sdk-modules': 'App modules',
'sdk-rpcs': 'App remote procedures',
'sdk-webhooks': 'App webhooks',
};
19 changes: 12 additions & 7 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { MakeError } from '@makehq/sdk';
import { resolveAuth } from './auth.js';
import { formatOutput, type OutputFormat } from './output.js';
import { CATEGORY_TITLES, CATEGORY_GROUPS } from './categories.js';
import { camelToKebab, formatExampleCommand } from './examples.js';

/**
* Derives the CLI action name from an MCP tool name and its category.
Expand All @@ -25,13 +26,6 @@ export function deriveActionName(toolName: string, category: string): string {
return toolName.slice(prefix.length).replace(/_/g, '-');
}

/**
* Converts a camelCase string to kebab-case.
*/
export function camelToKebab(str: string): string {
return str.replace(/[A-Z]/g, letter => `-${letter.toLowerCase()}`);
}

/**
* Converts a kebab-case string to camelCase.
*/
Expand Down Expand Up @@ -128,6 +122,17 @@ function registerToolAsCommand(parent: Command, tool: MakeMCPTool, category: str
cmd.addOption(option);
}

const example = tool.examples?.[0];
if (example && Object.keys(example).length > 0) {
const slug = category.replace(/\./g, '-');
const exampleCmd = formatExampleCommand(`make-cli ${slug} ${actionName}`, example);
const indented = exampleCmd
.split('\n')
.map(l => ' ' + l)
.join('\n');
cmd.addHelpText('after', `\nExample:\n\n${indented}\n`);
}

cmd.action(async (localOptions: Record<string, string>) => {
const globalOptions = cmd.optsWithGlobals();
const { token, zone } = await resolveAuth({
Expand Down
Loading