Skip to content

feat: add Executor SDK plugin for cli-to-js#1

Open
aidenybai wants to merge 3 commits intomainfrom
cursor/executor-integration-7544
Open

feat: add Executor SDK plugin for cli-to-js#1
aidenybai wants to merge 3 commits intomainfrom
cursor/executor-integration-7544

Conversation

@aidenybai
Copy link
Copy Markdown
Member

@aidenybai aidenybai commented Apr 11, 2026

Summary

Adds a new package @cli-to-js/plugin-executor that integrates cli-to-js with the Executor SDK (@executor-js/sdk). This lets any CLI tool wrapped by cli-to-js be exposed as invocable tools inside an Executor, alongside MCP, OpenAPI, GraphQL, and other plugin-based tool sources.

Usage

import { createExecutor } from "@executor-js/sdk";
import { cliPlugin } from "@cli-to-js/plugin-executor";

const executor = await createExecutor({
  scope: { name: "my-app" },
  plugins: [cliPlugin()] as const,
});

// Auto-discover a CLI tool by running its --help
await executor.cli.addBinary({ binary: "git", options: { subcommands: true } });

// Or register from pre-parsed help text
await executor.cli.addHelpText({
  binary: "curl",
  helpText: "Usage: curl [options] <url> ...",
  namespace: "curl",
});

// All CLI tools are now in the unified tool catalog
const tools = await executor.tools.list();

// Invoke any CLI subcommand as a tool
const result = await executor.tools.invoke(
  "git.status",
  { short: true },
  { onElicitation: "accept-all" },
);

// Clean up
await executor.close();

What the plugin does

  • Registers as an Executor plugin under the "cli" key
  • addBinary(config) — runs a binary's --help, parses the output via cli-to-js, and registers every flag/subcommand as an executor tool with JSON Schema inputSchema
  • addHelpText(config) — same as above but from a string (no subprocess needed)
  • removeBinary(namespace) — unregisters all tools for a namespace
  • list() — returns all registered namespace keys
  • Tool invocation routes through cli-to-js's CliApi proxy, returning { stdout, stderr, exitCode }
  • Cleanup on executor.close() unregisters all tools via Promise.all

Package structure

packages/plugin-cli-to-js/
├── src/
│   ├── index.ts                      # Public re-exports
│   ├── plugin.ts                     # Core plugin (definePlugin + invoker)
│   ├── constants.ts                  # PLUGIN_KEY, SOURCE_PREFIX, ROOT_TOOL_SUFFIX
│   └── utils/
│       └── build-input-schema.ts     # Flags/positionals → JSON Schema
├── tests/
│   ├── build-input-schema.test.ts    # 11 unit tests
│   └── plugin.test.ts               # 12 integration tests via createExecutor
├── package.json
├── tsconfig.json
└── vite.config.ts

Tests

23 tests across 2 test files, all passing:

Test file Tests Coverage
build-input-schema.test.ts 11 Schema generation from flags + positionals (including kebab→camel conversion, flag types, descriptions, defaults, positional signatures, required markers)
plugin.test.ts 12 Full integration via createExecutor — plugin registration, addHelpText, addBinary, tool listing, schema inspection, tool invocation with real binaries, ToolNotFoundError, removeBinary, multi-binary isolation
Open in Web Open in Cursor 

Adds a new package  that integrates cli-to-js
with the Executor SDK (@executor-js/sdk). The plugin:

- Registers as an executor plugin under the 'cli' key
- Exposes addBinary() to auto-discover CLI tools via --help parsing
- Exposes addHelpText() for offline schema-based registration
- Converts CLI flags/subcommands into executor ToolRegistrations with
  JSON Schema inputSchema
- Routes tool invocations through cli-to-js's CliApi proxy
- Supports removeBinary() for cleanup and list() for inspection
- Properly cleans up on executor.close()

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
@aidenybai aidenybai marked this pull request as ready for review April 11, 2026 04:28
cursoragent and others added 2 commits April 11, 2026 04:34
- kebab-to-camel: 6 unit tests for case conversion
- flag-to-json-schema: 7 unit tests for flag-to-schema conversion
- build-input-schema: 8 unit tests for full schema generation
- plugin integration: 13 tests using createExecutor from @executor-js/sdk
  - Plugin registration and extension API
  - addHelpText with root tools, subcommands, schema generation
  - addBinary with real echo binary
  - Tool invocation returning stdout/stderr/exitCode
  - ToolNotFoundError for unregistered tools
  - removeBinary cleanup
  - Multiple binary registration
  - Executor close cleanup

34 tests total, all passing.

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Source changes:
- Inline kebab-to-camel and flag-to-json-schema into build-input-schema
  (eliminating two single-use utility files)
- Remove formatCommandResult — CommandResult already has the right shape
- Extract parseToolId, describeCommand, subcommandToRegistration as
  pure helpers outside the closure
- Extract shared registerApi for addBinary/addHelpText
- Replace push loop with .map() in registerToolsFromSchema
- Use Promise.all in close handler instead of sequential loop
- Remove redundant String() coercion on already-typed parameter

Test changes:
- Delete kebab-to-camel.test.ts and flag-to-json-schema.test.ts (for
  removed files); fold their coverage into build-input-schema.test.ts
- Extract shared startExecutor helper and afterEach cleanup
- Extract toolNamesForSource helper to reduce assertion boilerplate
- 34 tests → 23 tests with same coverage, less duplication

Co-authored-by: Aiden Bai <aidenybai@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants