Skip to content

Commit 47e7cca

Browse files
--profile option with profile name added
1 parent c120b4e commit 47e7cca

12 files changed

Lines changed: 573 additions & 184 deletions

File tree

.claude/rules/architecture.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ HttpClient (axios) -> performs the real HTTP request to API_BASE_URL
5454
4. **Pure transform layer**: `bm25.ts`, `openapi-to-commands.ts`, and `command-search.ts` perform no I/O; they take inputs and return outputs. This keeps them trivially unit-testable.
5555
5. **Side effects at the edges**: filesystem in `config.ts`/`profile-store.ts`/`openapi-loader.ts`, network in `cli.ts` via `HttpClient`. Inject these via constructors (`fs`, `httpClient`) so tests can swap them.
5656
6. **TypeScript strict**: `strict: true` in `tsconfig.json`. Explicit types for exported functions and public interfaces.
57-
7. **No surprise breaking changes**: every CLI-visible change must be reflected in `README.md` and `CHANGELOG.md`.
57+
7. **No surprise breaking changes**: every CLI-visible change must be reflected in `README.md`.
5858

5959
## Layers and allowed dependencies
6060

.claude/rules/workflow.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ When the user asks for a new feature (words like "feature", "add", "implement",
1616
6. **Full suite**: `npm test`. All tests must be green. Fix regressions before moving on.
1717
7. **Build check**: `npm run build` to confirm `tsc` is clean (no type errors).
1818
8. **Docs**: update `README.md` whenever any of the following change: CLI flags, command names, profile fields, `.ocli/` layout, BM25 search behavior, supported OpenAPI/Swagger features, or the benchmark numbers. If you changed observable CLI output (`--help`, error messages, exit codes), update the relevant section of the README. The `examples/skill-ocli-api.md` and `skills/ocli-api/SKILL.md` must stay aligned with the documented agent workflow.
19-
9. **Changelog**: add an entry to `CHANGELOG.md` for any user-visible change.
20-
10. **Report**: brief summary of files touched, tests added, suite result.
19+
9. **Report**: brief summary of files touched, tests added, suite result.
2120

2221
## Bug fixes (TDD)
2322

@@ -30,14 +29,14 @@ When the user reports a bug (words like "bug", "fix", "ошибка", "баг",
3029
5. **Confirm green**: re-run the regression test.
3130
6. **Full suite**: `npm test`. All tests green.
3231
7. **Build check**: `npm run build`.
33-
8. **Docs**: update `README.md` if the bug affected documented behavior; add a `CHANGELOG.md` entry.
32+
8. **Docs**: update `README.md` if the bug affected documented behavior.
3433
9. **Report**: what was broken, what changed, suite result.
3534

3635
## Before the final answer
3736

3837
- `npm test` is green - **always**.
3938
- `npm run build` is clean.
40-
- `README.md` and `CHANGELOG.md` reflect any user-visible change.
39+
- `README.md` reflects any user-visible change.
4140
- Report what changed, which tests were added, and the suite result.
4241

4342
## Rules sync (Cursor <-> Claude)

.cursor/rules/architecture.mdc

Lines changed: 70 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,88 @@
11
---
22
description: Architecture of openapi-to-cli (ocli)
3+
globs: "src/**/*.ts"
34
alwaysApply: true
45
---
56

6-
## Architectural Rules
7+
# Architecture of openapi-to-cli (ocli)
78

8-
### General Architecture
9+
`ocli` is a TypeScript/Node CLI that converts OpenAPI/Swagger specs into runtime CLI commands. No code generation: at every invocation it loads a cached spec and builds command definitions on the fly.
910

10-
The `openapi-to-cli` project is a Node.js/TypeScript CLI application that:
11+
## Data flow
1112

12-
- reads an OpenAPI/Swagger spec from a URL or file;
13-
- caches the spec in `.ocli/specs`;
14-
- uses profiles to describe connected APIs;
15-
- maps OpenAPI operations to `ocli` subcommands.
16-
17-
### Data Flow
18-
19-
```text
20-
ocli onboard --options --> write profile (profiles.ini) --> download OpenAPI --> save to .ocli/specs
13+
```
14+
ocli profiles add <name> --api-base-url ... --openapi-spec ...
15+
|
16+
v
17+
ConfigLocator -> .ocli/ dir (global or local)
18+
|
19+
v
20+
ProfileStore -> profiles.ini (read/write/select)
21+
|
22+
v
23+
OpenapiLoader -> fetches spec, caches under .ocli/specs/<profile>.json
24+
|
25+
v
26+
OpenapiToCommands -> parses spec, applies include/exclude filters,
27+
builds CliCommand[] (name, method, path, options, body schema)
2128
|
2229
v
23-
ocli [--profile] <tool> [options] --> load profile + cached spec --> build commands from OpenAPI --> perform HTTP request to API_BASE_URL
30+
CommandSearch (BM25) -> ranks commands by NL query or regex
31+
|
32+
v
33+
cli.ts (yargs) -> resolves profile + spec, dispatches: profiles | use | commands | <toolName>
34+
|
35+
v
36+
HttpClient (axios) -> performs the real HTTP request to API_BASE_URL
2437
```
2538

26-
### Components
39+
## Components (mapping to `src/`)
40+
41+
- `config.ts` - `ConfigLocator`. Finds `.ocli/` (global `~/.ocli/`, local in CWD), resolves `profiles.ini` paths.
42+
- `profile-store.ts` - `ProfileStore`, `Profile`. Reads/writes `profiles.ini`, tracks current profile, validates fields.
43+
- `openapi-loader.ts` - `OpenapiLoader`. Loads spec from URL or local file, caches it to `.ocli/specs/<profile>.json`, refreshes on demand. Resolves external `$ref` across multi-file specs.
44+
- `openapi-to-commands.ts` - `OpenapiToCommands`, `CliCommand`, `CliCommandOption`. Walks the spec, applies include/exclude filters, expands path-level params, resolves local `$ref`, builds command names with optional prefix, expands `enum`/`default`/`nullable`/`oneOf` schema hints for `--help`.
45+
- `command-search.ts` - `CommandSearch`. BM25 over `(name, method, path, description, options[].name)`, plus regex fallback. Same engine used by both `ocli commands` and any future agent skill.
46+
- `bm25.ts` - tokenizer + BM25 scorer, no I/O.
47+
- `cli.ts` - `ocli` entry point. yargs command tree: `profiles add|remove|list`, `use`, `commands`, and dynamic per-spec commands. Builds the `axios` request from a `CliCommand` + parsed args; injects auth, custom headers, server URL overrides.
48+
- `version.ts` - generated by `scripts/generate-version.js` during `prebuild`. Do not edit by hand.
49+
50+
## Design principles
51+
52+
1. **OpenAPI-driven**: commands and their options come from the spec. No hand-maintained registry.
53+
2. **Profiles**: every API connection is named; `profiles.ini` is the source of truth. Global vs local `.ocli/` priority is decided by `ConfigLocator`.
54+
3. **Spec cache**: never re-download a spec on every invocation. Refresh is explicit (`onboard`/profile add or refresh flag).
55+
4. **Pure transform layer**: `bm25.ts`, `openapi-to-commands.ts`, and `command-search.ts` perform no I/O; they take inputs and return outputs. This keeps them trivially unit-testable.
56+
5. **Side effects at the edges**: filesystem in `config.ts`/`profile-store.ts`/`openapi-loader.ts`, network in `cli.ts` via `HttpClient`. Inject these via constructors (`fs`, `httpClient`) so tests can swap them.
57+
6. **TypeScript strict**: `strict: true` in `tsconfig.json`. Explicit types for exported functions and public interfaces.
58+
7. **No surprise breaking changes**: every CLI-visible change must be reflected in `README.md`.
59+
60+
## Layers and allowed dependencies
61+
62+
```
63+
Layer 0 (pure) bm25.ts, version.ts, types in openapi-to-commands.ts
64+
Layer 1 (I/O wrappers) config.ts, profile-store.ts, openapi-loader.ts
65+
Layer 2 (transform) openapi-to-commands.ts (uses Profile), command-search.ts (uses CliCommand + bm25)
66+
Layer 3 (entry) cli.ts (uses everything above; only this layer talks to yargs/axios/process)
67+
```
2768

28-
- **config** - locate and select `.ocli` directory, resolve `profiles.ini` paths with global and local priority.
29-
- **profile-store** - read and write profile INI files (`profiles.ini`), select current profile.
30-
- **openapi-loader** - load spec from URL or file and cache it into `.ocli/specs/<profile>.json`.
31-
- **openapi-to-commands** - parse OpenAPI, apply include/exclude filters, build command names and option schemas.
32-
- **cli** - entry point, argument parser, command registration, help rendering.
69+
Lower layers must not import from higher layers. New behavior should live in the lowest layer where it makes sense - prefer adding to Layer 2 over expanding `cli.ts`.
3370

34-
### Design Principles
71+
## Repository layout
3572

36-
1. **OpenAPI-driven** - the list of commands and their parameters is defined by the spec.
37-
2. **Profiles** - all API settings are configured via profiles (global or local).
38-
3. **Spec cache** - the spec is cached under `.ocli/specs` to avoid fetching it on every run.
39-
4. **TypeScript strict** - `strict: true`; explicit types for public APIs and profile interfaces.
40-
5. **TDD for core logic** - unit tests for profile parsing, spec loading and command mapping.
41-
6. **Language** - all documentation and code comments for this project must be written in English.
73+
- `src/` - production code (see components above).
74+
- `tests/` - Jest test files (`*.test.ts`), fixtures under `tests/fixtures/`, recorded results under `tests/results/`.
75+
- `examples/skill-ocli-api.md` - example Claude Code skill describing the agent workflow.
76+
- `skills/ocli-api/SKILL.md` - portable OpenClaw skill.
77+
- `benchmarks/benchmark.ts` - token-overhead comparison (MCP variants vs CLI).
78+
- `scripts/generate-version.js` - writes `src/version.ts` before build.
79+
- `.ocli/` - working dir at runtime (not part of source). Never committed.
80+
- `dist/` - `tsc` build output.
4281

43-
### Repository Layout (for the openapi-to-cli directory)
82+
## When extending the spec parser
4483

45-
- `README.md` - concept and description of the CLI and profiles.
46-
- `package.json` - npm package with the `ocli` binary.
47-
- `tsconfig.json` - TypeScript config with strict mode.
48-
- `jest.config.js` - Jest configuration.
49-
- `src/`:
50-
- `cli.ts` - `ocli` binary entry point.
51-
- future modules: `config`, `profile-store`, `openapi-loader`, `openapi-to-commands`, etc.
52-
- `tests/` - tests for the modules above.
84+
Real-world OpenAPI/Swagger documents drift from any single example. Before changing `openapi-to-commands.ts` or `openapi-loader.ts`:
5385

86+
- Add a minimal fixture under `tests/fixtures/` that reproduces the case (don't hand-edit `box-api-yaml.test.ts` or `github-api.test.ts` fixtures - those are real specs).
87+
- Cover both OAS 3 (`requestBody`, `components/schemas`) and Swagger 2 (`body`/`formData`, `definitions`) when the change affects request building.
88+
- Mention the new spec feature in the README "Broader spec support" or "Better request generation" section.

.cursor/rules/code-style.mdc

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,52 @@ globs: "**/*.ts"
44
alwaysApply: true
55
---
66

7-
## Code Style Rules
7+
# Code style (TypeScript)
88

9-
### General rules
9+
Applies to every `.ts` file in `src/` and `tests/`.
1010

11-
1. All code comments for this project must be written in English.
12-
2. All documentation files for this project must be written in English.
13-
3. New files must end with a single empty line.
14-
4. Use straight double quotes `"`. Use the regular dash `-` for punctuation, do not use long dashes.
11+
## General
1512

16-
### TypeScript
13+
1. All code comments and identifiers in English. Documentation files in English.
14+
2. New files end with a single trailing newline.
15+
3. Straight double quotes `"` for string literals. Regular hyphen `-`, not em-dashes, in any English prose inside code or docs.
16+
4. Default to no comments. Add a comment only when the **why** is non-obvious (workaround, hidden constraint, subtle invariant). Identifiers should carry intent.
1717

18-
- `strict: true` is enabled in `tsconfig.json`.
19-
- For exported functions and public APIs, prefer explicit parameter and return types.
20-
- For reusable object shapes, use `interface`.
18+
## TypeScript
2119

22-
### File structure
20+
- `strict: true` in `tsconfig.json`. Do not weaken it locally.
21+
- Exported functions and public APIs declare explicit parameter and return types. Local variables may use inference.
22+
- Use `interface` for reusable object shapes, `type` for unions, intersections, and mapped types.
23+
- Avoid `any`. When unavoidable, scope it as narrowly as possible and annotate `// eslint-disable-next-line @typescript-eslint/no-explicit-any` with a one-line reason (see `cli.ts:HttpClient` for the canonical example).
24+
- Prefer `unknown` over `any` at module boundaries; narrow with type guards.
2325

24-
1. Imports first (Node/third-party, then local).
25-
2. Then constants and types.
26-
3. Then main logic (functions, classes, exports).
26+
## File structure
2727

28-
### Naming
28+
1. Imports first - Node built-ins (`path`, `fs`), then third-party (`axios`, `yargs`, `js-yaml`, `zod`, `ini`), then local relative imports.
29+
2. Types and interfaces.
30+
3. Module-level constants.
31+
4. Functions and classes.
32+
5. `export` last when it improves readability; `export class` / `export function` inline is also fine.
2933

30-
- Classes - PascalCase.
31-
- Functions and methods - camelCase.
32-
- Configuration constants - UPPER_SNAKE_CASE or meaningful camelCase names.
33-
- Files - kebab-case or camelCase, consistent with existing files.
34+
## Naming
3435

36+
- Classes - `PascalCase` (`ProfileStore`, `OpenapiLoader`, `CommandSearch`).
37+
- Functions and methods - `camelCase` (`loadSpec`, `buildCommands`, `selectProfile`).
38+
- Interfaces and type aliases - `PascalCase` (`Profile`, `CliCommand`, `HttpClient`).
39+
- Constants - `UPPER_SNAKE_CASE` for environment-style globals, otherwise meaningful `camelCase`.
40+
- Files - `kebab-case.ts` matching the dominant exported type (`profile-store.ts` exports `ProfileStore`).
3541

42+
## Error handling
43+
44+
- Throw `Error` subclasses with informative messages; never throw strings.
45+
- At the CLI boundary (`cli.ts`), catch and translate to a user-friendly message + non-zero exit code. Inner layers should let exceptions propagate.
46+
- For external input (HTTP responses, parsed YAML/JSON), validate with `zod` schemas before consuming.
47+
48+
## Async
49+
50+
- Prefer `async/await`. Avoid `.then()` chains in new code.
51+
- Don't fire-and-forget Promises; always `await` or explicitly handle.
52+
53+
## Testing-facing affordances
54+
55+
When a module performs I/O, accept the dependency via a constructor option (`fs`, `httpClient`, `stdout`). This is how `OpenapiLoader`, `ProfileStore`, and the `run()` entry in `cli.ts` are structured; follow the same pattern in new modules.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
description: Implementation order for openapi-to-cli (one unit at a time)
3+
globs: "src/**/*.ts"
4+
alwaysApply: false
5+
---
6+
7+
# Implementation order (one unit at a time)
8+
9+
Applies when adding or extending modules under `src/`.
10+
11+
## Layer order (lower first)
12+
13+
The architecture in @architecture.mdc defines four layers. New behavior should be added at the lowest layer it can live in, then composed upward:
14+
15+
1. **Layer 0 - pure** (`bm25.ts`, type-only files): no I/O, no Node built-ins beyond `Buffer`/`URL`/etc.
16+
2. **Layer 1 - I/O wrappers** (`config.ts`, `profile-store.ts`, `openapi-loader.ts`): touch `fs`, network, or env.
17+
3. **Layer 2 - transform** (`openapi-to-commands.ts`, `command-search.ts`): combine Layer 0 + Layer 1 outputs into the CLI command model.
18+
4. **Layer 3 - entry** (`cli.ts`): wire everything together for yargs and axios.
19+
20+
Forbidden: Layer N importing from Layer M when M > N. If a Layer 1 module suddenly needs a Layer 2 type, that is a sign the type belongs lower.
21+
22+
## Steps for a new module or class
23+
24+
1. Decide the layer using @architecture.mdc.
25+
2. Write a failing test in `tests/<module>.test.ts` that describes the smallest useful behavior (see @testing.mdc and @workflow.mdc).
26+
3. Add the minimum implementation in `src/<module>.ts`. Follow @code-style.mdc for types, naming, and constructor-injected I/O.
27+
4. Make the test pass.
28+
5. Run `npm test` to confirm no regressions, then `npm run build` to confirm `tsc` is clean.
29+
6. Only **then** integrate the new module into the layer above (typically `cli.ts`), guarded by its own test.
30+
31+
## Forbidden
32+
33+
- Implementing two unrelated modules in one step before either has tests.
34+
- Wiring a new module into `cli.ts` before its own tests pass.
35+
- Adding optional fields to `Profile`, `CliCommand`, or `CliCommandOption` without a test that exercises the new field.
36+
- Editing real-spec fixtures (`github-api.*`, `box-api-yaml.*`) to "make tests pass" - those represent contracts.
37+
38+
## Allowed
39+
40+
- Stub or fake dependencies (mock `HttpClient`, in-memory `fs`) while a lower layer is incomplete, provided the stub matches the documented contract.
41+
- Refactor a passing module to a cleaner shape after the test suite stays green.
42+
- Extending an existing Layer 2 module with a new transformation, as long as it is covered by a new test and does not import upward.

.cursor/rules/testing.mdc

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,52 @@
11
---
2-
description: Test rules for openapi-to-cli
3-
globs: "**/tests/**/*.ts, **/*.test.ts"
2+
description: Test conventions for openapi-to-cli (Jest)
3+
globs: "tests/**/*.ts"
44
alwaysApply: true
55
---
66

7-
## Test Writing Rules
7+
# Test conventions (Jest)
88

9-
### General principles
9+
Applies when editing or adding files under `tests/`.
1010

11-
1. Tests live in the `tests/` directory inside `openapi-to-cli`.
12-
2. Each test must be independent; use mocks for HTTP (axios) and the filesystem when needed.
13-
3. `describe` and `it` names should clearly describe the behavior under test.
11+
## Layout
1412

15-
### Test structure
13+
- All tests live in `tests/` alongside the matching `src/` module.
14+
- Test files: `tests/<module>.test.ts` (one per `src/<module>.ts`).
15+
- Shared inputs in `tests/fixtures/` (OpenAPI/Swagger documents, sample profiles). Recorded outputs in `tests/results/`.
16+
- `github-api.test.ts` and `box-api-yaml.test.ts` are large real-spec regression tests - do not hand-edit their fixtures.
1617

17-
- Test files: `*.test.ts`.
18-
- Grouping by modules, for example: `describe("profile-store", ...)`, `describe("openapi-loader", ...)` etc.
18+
## Structure
1919

20-
### Running tests
20+
- Group with `describe(<moduleName>, ...)`; one nested `describe` per public method or scenario.
21+
- Test names: `it("does X when Y", ...)` - describe behavior, not implementation.
22+
- Arrange / Act / Assert order inside each `it`. Blank lines between the three sections are encouraged.
2123

22-
From the `openapi-to-cli` directory:
24+
## Isolation
25+
26+
- Each `it` is independent. Use `beforeEach`/`afterEach` for setup and teardown, not module-level mutable state.
27+
- Mock `fs` and `axios` (`HttpClient`) through the constructor options the modules expose. Do **not** monkey-patch the real `fs`/`axios` modules in tests.
28+
- For `.ocli/` fixtures, use `fs.mkdtempSync(os.tmpdir() + "/...")` and clean up in `afterEach`.
29+
30+
## Running
2331

2432
```bash
25-
npm test
33+
npm test # full Jest suite
34+
npx jest tests/<file>.test.ts # one file
35+
npx jest tests/<file>.test.ts -t "X" # one test by name
2636
```
2737

38+
## What to assert
39+
40+
- Public behavior visible at the module boundary - return values, written files, requests issued via the mocked `HttpClient`, captured `stdout`.
41+
- For BM25 / `command-search` - assert ranking order and matched commands, not internal scores.
42+
- For `openapi-to-commands` - assert the resulting `CliCommand[]` structure (names, options, body schema), not intermediate spec normalization.
43+
44+
## What not to assert
45+
46+
- Internal helper signatures, private state, exact log strings - those are implementation details.
47+
- Floating-point BM25 scores beyond ranking order.
48+
49+
## Fixtures
50+
51+
- Add new spec fixtures only when an existing one cannot reproduce the case. Keep them minimal: one path, one operation, only the fields needed for the test.
52+
- For tests covering spec features (OAS 3 `requestBody`, Swagger 2 `formData`, multi-file `$ref`, header/cookie params), name the fixture after the feature, e.g. `tests/fixtures/swagger2-formdata.yaml`.

0 commit comments

Comments
 (0)