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: 3 additions & 3 deletions package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,12 +5,12 @@
"description": "ObjectStack Protocol & Specification - Monorepo for TypeScript Interfaces, JSON Schemas, and Convention Configurations",
"scripts": {
"build": "turbo run build --filter=!@objectstack/docs",
"dev": "pnpm --filter @objectstack/cli build && node packages/cli/bin/objectstack.js serve --dev",
"dev": "pnpm --filter @objectstack/cli build && node packages/cli/bin/run.js serve --dev",
"dev:studio": "pnpm --filter @objectstack/studio dev",
"studio": "pnpm --filter @objectstack/cli build && node packages/cli/bin/objectstack.js studio",
"studio": "pnpm --filter @objectstack/cli build && node packages/cli/bin/run.js studio",
"test": "turbo run test --filter=@objectstack/spec",
"clean": "turbo run clean && rm -rf dist",
"doctor": "pnpm --filter @objectstack/cli build && node packages/cli/bin/objectstack.js doctor",
"doctor": "pnpm --filter @objectstack/cli build && node packages/cli/bin/run.js doctor",
"setup": "pnpm install && pnpm --filter @objectstack/spec build",
"version": "changeset version",
"release": "pnpm run build && changeset publish",
Expand Down
152 changes: 98 additions & 54 deletions packages/cli/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,8 @@

Command Line Interface for building metadata-driven applications with the ObjectStack Protocol.

Built on [oclif](https://oclif.io/) — commands are auto-discovered, and plugins can extend the CLI without modifying the main package.

## Installation

```bash
Expand DownExpand Up@@ -40,6 +42,7 @@ os compile
| `os init [name]` | Initialize a new ObjectStack project in the current directory |
| `os dev [package]` | Start development mode with hot reload |
| `os serve [config]` | Start the ObjectStack server with plugin auto-detection |
| `os studio [config]` | Launch Studio UI with development server |

### Build & Validate

Expand DownExpand Up@@ -73,6 +76,20 @@ Available generate types: `object`, `view`, `action`, `flow`, `agent`, `dashboar
|---------|-------------|
| `os test [files]` | Run Quality Protocol test scenarios against a running server |
| `os doctor` | Check development environment health |
| `os lint [config]` | Check configuration for style and convention issues |
| `os diff [before] [after]` | Compare two configurations and detect breaking changes |

### Reference

| Command | Description |
|---------|-------------|
| `os explain [schema]` | Display human-readable explanation of an ObjectStack schema |

### Code Transforms

| Command | Description |
|---------|-------------|
| `os codemod v2-to-v3` | Migrate ObjectStack v2 config to v3 format |

## Configuration

Expand DownExpand Up@@ -120,12 +137,12 @@ export default defineStack({

- `-p, --port <port>` — Server port (default: `3000`)
- `--dev` — Run in development mode (load devPlugins, pretty logging)
- `--ui` — Enable Studio UI
- `--no-server` — Skip starting HTTP server plugin

### `os generate`

- `-d, --dir <directory>` — Override target directory
- `--dry-run` — Preview without writing files

### `os plugin list`

Expand All@@ -140,75 +157,78 @@ export default defineStack({

- `-c, --config <path>` — Configuration file path

## Plugin CLI Extensions
### `os info`

- `--json` — Output as JSON

Plugins can extend the CLI with custom commands via the `contributes.commands` manifest field. The CLI automatically discovers and loads these commands at startup.
### `os doctor`

### How to Create a CLI Plugin
- `-v, --verbose` — Show fix suggestions for warnings
- `--scan-deprecations` — Scan for deprecated patterns

**1. Declare commands in the plugin manifest:**
## oclif Plugin System

```typescript
export default defineStack({
manifest: {
id: 'com.acme.marketplace',
version: '1.0.0',
type: 'plugin',
name: 'Marketplace Plugin',
contributes: {
commands: [
{
name: 'marketplace',
description: 'Manage marketplace applications',
module: './dist/cli.js',
},
],
},
},
});
The CLI uses oclif's built-in plugin system for extensibility. Third-party plugins (e.g., cloud commands, marketplace tools) can extend the CLI without modifying the main package.

### How Plugin Extension Works

1. **Create an oclif plugin package** with its own `oclif` config in `package.json`
2. **Export oclif Command classes** from the plugin's `src/commands/` directory
3. **Install the plugin** via `os plugins install <package>` or declare it in the main CLI's `oclif.plugins`

### Creating a CLI Plugin

**1. Configure the plugin's `package.json`:**

```json
{
"name": "@acme/plugin-marketplace",
"oclif": {
"commands": {
"strategy": "pattern",
"target": "./dist/commands",
"glob": "**/*.js"
}
}
}
```

**2. Export Commander.js commands from the module:**
**2. Create oclif Command classes:**

```typescript
// src/cli.ts
import { Command } from 'commander';

const marketplaceCommand = new Command('marketplace')
.description('Manage marketplace applications')
.addCommand(
new Command('search')
.argument('<query>')
.action(async (query) => { /* ... */ })
)
.addCommand(
new Command('install')
.argument('<app>')
.action(async (app) => { /* ... */ })
);

// Named export (recommended)
export const commands = [marketplaceCommand];
// Also supports: export default Command | Command[]
// src/commands/marketplace/search.ts
import { Args, Command, Flags } from '@oclif/core';

export default class MarketplaceSearch extends Command {
static override description = 'Search marketplace applications';

static override args = {
query: Args.string({ description: 'Search query', required: true }),
};

async run() {
const { args } = await this.parse(MarketplaceSearch);
// Implementation...
}
}
```

**3. Register the plugin in the host project and use:**
**3. Install and use:**

```bash
os plugin add @acme/plugin-marketplace
os plugins install @acme/plugin-marketplace
os marketplace search "crm"
os marketplace install com.acme.crm
```

For a complete guide, see the [Plugin CLI Extensions](/docs/guides/plugins#cli-command-extensions) section in the Plugins guide.
### Key Differences from Previous Plugin Model

### `os info`

- `--json` — Output as JSON

### `os doctor`

- `-v, --verbose` — Show fix suggestions for warnings
| Before (Commander.js) | After (oclif) |
|---|---|
| Plugins declared in `objectstack.config.ts` | Plugins installed via `os plugins install` or `oclif.plugins` |
| Custom `loadPluginCommands` mechanism | oclif's built-in plugin discovery |
| `contributes.commands` in manifest | `oclif.commands` in `package.json` |
| Commander.js `new Command(...)` exports | oclif `class extends Command` exports |
| Project config determines CLI commands | CLI commands available without project init |

## Typical Workflow

Expand All@@ -223,6 +243,30 @@ os dev # 7. Start dev server
os compile # 8. Build for production
```

## Architecture

```
@objectstack/cli (oclif)
├── bin/run.js # Entry point (os / objectstack)
├── src/commands/ # Auto-discovered command classes
│ ├── init.ts # os init
│ ├── dev.ts # os dev
│ ├── serve.ts # os serve
│ ├── compile.ts # os compile
│ ├── validate.ts # os validate
│ ├── generate.ts # os generate (alias: g)
│ ├── plugin/ # os plugin <subcommand>
│ │ ├── list.ts
│ │ ├── info.ts
│ │ ├── add.ts
│ │ └── remove.ts
│ ├── codemod/ # os codemod <subcommand>
│ │ └── v2-to-v3.ts
│ └── ...
├── src/utils/ # Shared utilities
└── package.json # oclif config under "oclif" key
```

## License

Apache-2.0
2 changes: 0 additions & 2 deletions packages/cli/bin/objectstack.js

This file was deleted.

5 changes: 5 additions & 0 deletions packages/cli/bin/run-dev.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env tsx

import { execute } from '@oclif/core';

await execute({ type: 'esm', development: true, dir: import.meta.url });
5 changes: 5 additions & 0 deletions packages/cli/bin/run.js
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env node

import { execute } from '@oclif/core';

await execute({ type: 'esm', dir: import.meta.url });
28 changes: 23 additions & 5 deletions packages/cli/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -3,25 +3,41 @@
"version": "3.0.6",
"description": "Command Line Interface for ObjectStack Protocol",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
"objectstack": "./bin/objectstack.js",
"os": "./bin/objectstack.js"
"objectstack": "./bin/run.js",
"os": "./bin/run.js"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"build": "tsc -p tsconfig.build.json",
"dev": "tsc -p tsconfig.build.json --watch",
"test": "vitest run",
"lint": "eslint src"
},
"keywords": [
"objectstack",
"cli",
"oclif",
"compiler",
"scaffold"
],
"type": "module",
"author": "Steedos",
"license": "Apache-2.0",
"oclif": {
"bin": "os",
"dirname": "objectstack",
"commands": {
"strategy": "pattern",
"target": "./dist/commands",
"glob": "**/*.js"
},
"plugins": [
"@oclif/plugin-help",
"@oclif/plugin-plugins"
],
"topicSeparator": " "
},
"dependencies": {
"@objectstack/core": "workspace:*",
"@objectstack/driver-memory": "workspace:^",
Expand All@@ -30,16 +46,18 @@
"@objectstack/rest": "workspace:*",
"@objectstack/runtime": "workspace:^",
"@objectstack/spec": "workspace:*",
"@oclif/core": "^4.8.0",
"bundle-require": "^5.1.0",
"chalk": "^5.3.0",
"commander": "^14.0.3",
"tsx": "^4.7.1",
"zod": "^4.3.6"
},
"peerDependencies": {
"@objectstack/core": "workspace:*"
},
"devDependencies": {
"@oclif/plugin-help": "^6.2.37",
"@oclif/plugin-plugins": "^5.4.56",
"@types/node": "^25.2.2",
"tsup": "^8.0.2",

CopilotAIFeb 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsup is still listed in devDependencies, but the package scripts now build/watch via tsc -p tsconfig.build.json and there are no remaining script references to tsup. If it’s no longer needed, consider removing it (and any related config) to reduce dependency surface.

Suggested change
"tsup": "^8.0.2",

Copilot uses AI. Check for mistakes.
"typescript": "^5.3.3",
Expand Down
Loading