@vsceasy/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +474 -0
- package/dist/bin/cli.d.ts +1 -0
- package/dist/bin/cli.js +9044 -0
- package/dist/cli.d.ts +3 -0
- package/dist/commands/command/add.d.ts +3 -0
- package/dist/commands/components/add.d.ts +3 -0
- package/dist/commands/create.d.ts +3 -0
- package/dist/commands/crud/add.d.ts +3 -0
- package/dist/commands/db/init.d.ts +3 -0
- package/dist/commands/doctor.d.ts +3 -0
- package/dist/commands/groups.d.ts +16 -0
- package/dist/commands/helper/add.d.ts +3 -0
- package/dist/commands/job/add.d.ts +3 -0
- package/dist/commands/menu/add.d.ts +3 -0
- package/dist/commands/menu/edit.d.ts +3 -0
- package/dist/commands/model/add.d.ts +3 -0
- package/dist/commands/panel/add.d.ts +3 -0
- package/dist/commands/publish/init.d.ts +3 -0
- package/dist/commands/rpc/add.d.ts +3 -0
- package/dist/commands/statusBar/add.d.ts +3 -0
- package/dist/commands/subpanel/add.d.ts +3 -0
- package/dist/commands/test/setup.d.ts +3 -0
- package/dist/commands/treeView/add.d.ts +3 -0
- package/dist/commands/upgrade.d.ts +3 -0
- package/dist/commands/wizard.d.ts +3 -0
- package/dist/data/codicons.d.ts +9 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3169 -0
- package/dist/lib/command/add.d.ts +31 -0
- package/dist/lib/components/add.d.ts +20 -0
- package/dist/lib/config.d.ts +10 -0
- package/dist/lib/crud/add.d.ts +19 -0
- package/dist/lib/crud/crudConfig.d.ts +37 -0
- package/dist/lib/crud/parseModel.d.ts +33 -0
- package/dist/lib/db/init.d.ts +16 -0
- package/dist/lib/db/wire.d.ts +10 -0
- package/dist/lib/doctor.d.ts +30 -0
- package/dist/lib/findProject.d.ts +10 -0
- package/dist/lib/helper/add.d.ts +14 -0
- package/dist/lib/iconPicker.d.ts +7 -0
- package/dist/lib/index.d.ts +46 -0
- package/dist/lib/interactive.d.ts +30 -0
- package/dist/lib/job/add.d.ts +24 -0
- package/dist/lib/menu/add.d.ts +13 -0
- package/dist/lib/menu/edit.d.ts +39 -0
- package/dist/lib/menuTree.d.ts +33 -0
- package/dist/lib/model/add.d.ts +27 -0
- package/dist/lib/model/parseFields.d.ts +14 -0
- package/dist/lib/panel/add.d.ts +29 -0
- package/dist/lib/publish/init.d.ts +12 -0
- package/dist/lib/rpc/add.d.ts +22 -0
- package/dist/lib/scaffold.d.ts +13 -0
- package/dist/lib/statusBar/add.d.ts +33 -0
- package/dist/lib/subpanel/add.d.ts +20 -0
- package/dist/lib/testSetup/index.d.ts +10 -0
- package/dist/lib/treeView/add.d.ts +13 -0
- package/dist/lib/upgrade.d.ts +22 -0
- package/dist/lib/validate.d.ts +14 -0
- package/dist/lib/wizard/run.d.ts +13 -0
- package/package.json +67 -0
- package/templates/_generators/command/command.ts.tpl +8 -0
- package/templates/_generators/components/Button.tsx.tpl +12 -0
- package/templates/_generators/components/Card.tsx.tpl +22 -0
- package/templates/_generators/components/Field.tsx.tpl +20 -0
- package/templates/_generators/components/Input.tsx.tpl +10 -0
- package/templates/_generators/components/List.tsx.tpl +29 -0
- package/templates/_generators/components/components.css.tpl +66 -0
- package/templates/_generators/components/index.ts.tpl +10 -0
- package/templates/_generators/crud/formApp.tsx.tpl +83 -0
- package/templates/_generators/crud/formNav.ts.tpl +19 -0
- package/templates/_generators/crud/formPanel.ts.tpl +32 -0
- package/templates/_generators/crud/listApp.tsx.tpl +84 -0
- package/templates/_generators/crud/listPanel.ts.tpl +30 -0
- package/templates/_generators/crud/main.tsx.tpl +6 -0
- package/templates/_generators/crud/service.ts.tpl +27 -0
- package/templates/_generators/helper/cache.ts.tpl +117 -0
- package/templates/_generators/helper/config.ts.tpl +36 -0
- package/templates/_generators/helper/db.ts.tpl +322 -0
- package/templates/_generators/helper/notifications.ts.tpl +45 -0
- package/templates/_generators/helper/secrets.ts.tpl +36 -0
- package/templates/_generators/helper/state.ts.tpl +44 -0
- package/templates/_generators/job/job.ts.tpl +10 -0
- package/templates/_generators/menu/menu.ts.tpl +21 -0
- package/templates/_generators/model/model.ts.tpl +17 -0
- package/templates/_generators/panel/App.tsx.tpl +10 -0
- package/templates/_generators/panel/main.tsx.tpl +6 -0
- package/templates/_generators/panel/panel.ts.tpl +5 -0
- package/templates/_generators/panel/templates/dashboard/App.tsx.tpl +41 -0
- package/templates/_generators/panel/templates/form/App.tsx.tpl +44 -0
- package/templates/_generators/panel/templates/list/App.tsx.tpl +40 -0
- package/templates/_generators/publish/CHANGELOG.md.tpl +8 -0
- package/templates/_generators/publish/README.md.tpl +23 -0
- package/templates/_generators/statusBar/statusBar.ts.tpl +7 -0
- package/templates/_generators/subpanel/App.tsx.tpl +10 -0
- package/templates/_generators/subpanel/main.tsx.tpl +6 -0
- package/templates/_generators/subpanel/subpanel.ts.tpl +6 -0
- package/templates/_generators/test/_helpers.ts.tpl +120 -0
- package/templates/_generators/test/sample.test.ts.tpl +38 -0
- package/templates/_generators/test/vitest.config.ts.tpl +23 -0
- package/templates/_generators/test/vscode.stub.ts.tpl +109 -0
- package/templates/_generators/treeView/treeView.ts.tpl +16 -0
- package/templates/react/.vscode/launch.json +34 -0
- package/templates/react/.vscode/tasks.json +32 -0
- package/templates/react/.vscodeignore +8 -0
- package/templates/react/README.md +50 -0
- package/templates/react/package.json +54 -0
- package/templates/react/scripts/gen.ts +395 -0
- package/templates/react/src/commands/hello.ts +6 -0
- package/templates/react/src/extension/extension.ts +5 -0
- package/templates/react/src/panels/dashboard.ts +21 -0
- package/templates/react/src/shared/api.ts +7 -0
- package/templates/react/src/shared/vsceasy/bootstrap.ts +657 -0
- package/templates/react/src/shared/vsceasy/client.ts +8 -0
- package/templates/react/src/shared/vsceasy/codiconNames.ts +196 -0
- package/templates/react/src/shared/vsceasy/define.ts +269 -0
- package/templates/react/src/shared/vsceasy/index.ts +13 -0
- package/templates/react/src/shared/vsceasy/rpc.ts +214 -0
- package/templates/react/src/webview/panels/dashboard/App.tsx +31 -0
- package/templates/react/src/webview/panels/dashboard/main.tsx +6 -0
- package/templates/react/src/webview/styles.css +33 -0
- package/templates/react/tsconfig.json +17 -0
- package/templates/react/vite.config.ts +42 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes follow [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **`vsceasy job add`** — scaffold recurring / event-triggered jobs into `src/jobs/`. Schedules: `--every "60s"`, `--dailyAt "09:00"`, `--on startup|saveDocument|openDocument|changeActiveEditor|changeConfig`, `--onFile "**/*.md"`. Optional `--minIntervalMs` throttles re-runs via globalState. Runtime (`bootstrap`) auto-registers timers/listeners + cleanup on deactivate, catches errors so they don't crash the host.
|
|
9
|
+
- **`command add --when <expr>`** — declare VS Code `when` clauses on commands. Auto-written to `contributes.commands[].enablement` and `contributes.menus.commandPalette` by `bun run gen`. Enables context-aware visibility (e.g. `editorTextFocus`, `resourceLangId == typescript`).
|
|
10
|
+
- **`vsceasy helper add <kind>`** — generate typed runtime wrappers in `src/helpers/`:
|
|
11
|
+
- `secrets` — `context.secrets.{get,set,delete}` typed and lazily initialized.
|
|
12
|
+
- `config` — `getConfiguration('<prefix>')` with `get<T>` / `set` / `onChange`.
|
|
13
|
+
- `state` — workspace + global memento with typed `get`/`set`/`delete`.
|
|
14
|
+
- `notifications` — `notify.{info,warn,error,confirm}` + `withProgress`.
|
|
15
|
+
- `cache` — in-memory TTL + LRU cache (`createCache({ ttlMs, max })`) with `wrap(key, fn)` memoization, in-flight de-dupe, and `refresh(key, fn)`. Pairs with the ORM for cheap reads.
|
|
16
|
+
- **`vsceasy db init`** — scaffold the project database at `src/helpers/db.ts` (idempotent). Exposes `initDb(ctx)` + `db()` singleton + `defineEntity<T>()`. Filesystem JSON provider out of the box (`--provider storage|global`). Provider interface designed to host SQLite/etc. next.
|
|
17
|
+
- **`vsceasy crud add --model X`** — Rails-style scaffold: reads `src/models/X.ts`, generates `src/services/XService.ts`, `src/panels/{xsList,xForm}.ts`, React webview bundles, and appends `XsListApi` + `XFormApi` to `src/shared/api.ts`. Auto-renders inputs by TS type (number, boolean, Date, literal union → select, string → text). Optional menu wiring (none / existing / new). Optional `src/models/X.crud.ts` overrides labels, hidden fields, field order, and input kinds per field.
|
|
18
|
+
- **`vsceasy model add --name X`** — typed entity + repo under `src/models/X.ts`. Interactive field loop (`name:type` per line, empty to finish) or compact flag spec `--fields "id:string!,email?:string@,score:number"`. Flags: `!` = primaryKey, `@` = indexed, `?` after name = optional. Generates `interface X`, `export const Xs = defineEntity<X>(...)`, and `export const XsRepo = () => db()(Xs)`. Requires `db init` first.
|
|
19
|
+
|
|
20
|
+
### Removed
|
|
21
|
+
- `vsceasy helper add --kind orm` — replaced by `vsceasy db init` for clearer UX.
|
|
22
|
+
- **Webview RPC call timeout** (`createRpcClient(transport, { callTimeoutMs })`, default 15s) — rejects pending calls when the extension host reloads mid-flight, preventing infinite hangs during `bun run dev`.
|
|
23
|
+
- **`webviewState<T>(defaults)`** helper exported from `vsceasy-runtime` — typed wrapper over `vscode.getState/setState`. Persists scroll position, form data, selection across panel hide/show and host reloads.
|
|
24
|
+
- **Doctor checks (3 new):**
|
|
25
|
+
- `activationEvents` — flags redundant `onCommand:` entries (VS Code ≥1.74 auto-activates).
|
|
26
|
+
- `icon` — validates `package.json#icon` exists on disk, is PNG, ≥128×128, square.
|
|
27
|
+
- `gen-script` — detects outdated `scripts/gen.ts` (missing `TREE_VIEWS_DIR`, `commandPalette`) and suggests `vsceasy upgrade --apply=true`.
|
|
28
|
+
- **Test helpers** — `vsceasy test setup` now drops `src/__tests__/_helpers.ts` exporting `mockVscode()`, `mockContext()`, `mockRpcPair<H>()` for unit-testing handlers end-to-end.
|
|
29
|
+
- `vsceasy.config.ts` — persistent project defaults (publisher, commandPrefix, defaultCategory, defaultIcon). Auto-written by `create`; consumed by `command add` (category) and `menu add` (icon).
|
|
30
|
+
- **New package: `vsceasy-runtime`** — the framework runtime (`bootstrap`, `define*`, RPC bridge) extracted as a standalone npm package. Single source of truth at `packages/vsceasy-runtime/src/`; the bundled template is now kept in sync via `bun run sync:runtime`. Allows external consumers to import the runtime without scaffolding a full project.
|
|
31
|
+
- `treeview add` — scaffold native VS Code tree views with `getChildren`/`getTreeItem` handlers and auto-registered `views` contribution.
|
|
32
|
+
- `create --preset minimal|full` — `minimal` ships only extension entry + one command; `full` includes panel + tree view + subpanel + RPC sample.
|
|
33
|
+
- `test:setup` — adds Vitest config and a sample panel test inside a generated project.
|
|
34
|
+
- `.vscode/launch.json` autogenerated by `vsceasy create` (Extension Development Host launch).
|
|
35
|
+
- `publish --init` — generates marketplace metadata (icon placeholder, README sections, CHANGELOG), runs `vsce ls` for a publish dry-run.
|
|
36
|
+
- Input validation across generators: duplicate name detection, identifier format checks, helpful error messages quoting target paths.
|
|
37
|
+
- ESLint + Prettier configs and `lint` / `format` scripts.
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
- Bumped to **0.1.0** — first signed/tagged release.
|
|
41
|
+
- Dropped Svelte/Vue/Vanilla mentions from docs and CLI options. Only React UI is supported in this release.
|
|
42
|
+
|
|
43
|
+
## [0.0.1] — 2026-05-21
|
|
44
|
+
|
|
45
|
+
- Initial MVP. React template, typed RPC bridge, file-based registry, CLI generators (`panel`, `command`, `menu`, `rpc`, `statusBar`, `subpanel`), `doctor`, `upgrade`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jairo Fernandez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,474 @@
|
|
|
1
|
+
# vsceasy
|
|
2
|
+
|
|
3
|
+
Build VS Code extensions fast. React UI + typed RPC bridge between extension and webview + zero-config build.
|
|
4
|
+
|
|
5
|
+
> Status: v0.1 — React UI. Typed RPC bridge + file-based registry + scaffolding for panels, commands, menus, tree views, subpanels, status bars.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bunx vsceasy create my-extension
|
|
11
|
+
cd my-extension
|
|
12
|
+
bun install
|
|
13
|
+
bun run dev
|
|
14
|
+
# press F5 in VS Code to launch the Extension Development Host
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Or with flags:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
bunx vsceasy create \
|
|
21
|
+
--name my-extension \
|
|
22
|
+
--displayName "My Extension" \
|
|
23
|
+
--description "Does cool things" \
|
|
24
|
+
--publisher my-publisher \
|
|
25
|
+
--ui react
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## What you get
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
my-extension/
|
|
32
|
+
├── src/
|
|
33
|
+
│ ├── extension/
|
|
34
|
+
│ │ ├── extension.ts # entry, command registration
|
|
35
|
+
│ │ └── panels/DashboardPanel.ts # webview panel + RPC handlers
|
|
36
|
+
│ ├── webview/
|
|
37
|
+
│ │ ├── App.tsx # React UI (typed RPC client)
|
|
38
|
+
│ │ ├── main.tsx
|
|
39
|
+
│ │ └── styles.css # VS Code theme tokens
|
|
40
|
+
│ └── shared/
|
|
41
|
+
│ ├── api.ts # RPC contract (types both sides)
|
|
42
|
+
│ └── rpc.ts # bridge implementation
|
|
43
|
+
├── vite.config.ts # webview build
|
|
44
|
+
└── package.json # esbuild for extension, vite for UI
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Command map
|
|
48
|
+
|
|
49
|
+
```mermaid
|
|
50
|
+
flowchart TD
|
|
51
|
+
V["vsceasy"] --> CR["create<br/>scaffold project"]
|
|
52
|
+
V --> UI_["ui features"]
|
|
53
|
+
V --> DATA["data"]
|
|
54
|
+
V --> OPS["ops"]
|
|
55
|
+
UI_ --> P["panel add"]
|
|
56
|
+
UI_ --> SP["subpanel add"]
|
|
57
|
+
UI_ --> MN["menu add / edit"]
|
|
58
|
+
UI_ --> TV["treeview add"]
|
|
59
|
+
UI_ --> CMD["command add"]
|
|
60
|
+
UI_ --> SB["statusBar add"]
|
|
61
|
+
UI_ --> RPC["rpc add"]
|
|
62
|
+
DATA --> DB["db init"]
|
|
63
|
+
DATA --> MD["model add"]
|
|
64
|
+
DATA --> CRUD["crud add"]
|
|
65
|
+
OPS --> JOB["job add"]
|
|
66
|
+
OPS --> HLP["helper add"]
|
|
67
|
+
OPS --> TST["test setup"]
|
|
68
|
+
OPS --> PUB["publish init"]
|
|
69
|
+
OPS --> DOC["doctor"]
|
|
70
|
+
OPS --> UPG["upgrade"]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Run `vsceasy <group> <subcommand> --help` for details on any command.
|
|
74
|
+
|
|
75
|
+
## Typed RPC
|
|
76
|
+
|
|
77
|
+
Define the contract once:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
// src/shared/api.ts
|
|
81
|
+
export interface DashboardApi {
|
|
82
|
+
listFiles(pattern: string): Promise<string[]>;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Extension side — implement:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const handlers: DashboardApi = {
|
|
90
|
+
async listFiles(pattern) {
|
|
91
|
+
const uris = await vscode.workspace.findFiles(pattern);
|
|
92
|
+
return uris.map(u => vscode.workspace.asRelativePath(u));
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
createRpcServer(webviewTransport(panel.webview), handlers);
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Webview side — call with full type inference:
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
const api = createRpcClient<DashboardApi>(vscodeApiTransport(vscode));
|
|
102
|
+
const files = await api.listFiles('**/*.ts'); // typed string[]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
No manual `postMessage`. No string-typed message channels.
|
|
106
|
+
|
|
107
|
+
## CLI commands
|
|
108
|
+
|
|
109
|
+
Structure: `vsceasy <resource> <verb> [flags]`. Every command runs interactively when flags are omitted (banner + per-param prompts) or fully scripted via flags.
|
|
110
|
+
|
|
111
|
+
New to the project? Run the guided wizard:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
vsceasy wizard
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
It detects whether you're inside a vsceasy project — outside it walks you through `create`, inside it menus the common generators (panel, command, database, model, helper) and points you at the rest.
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
vsceasy
|
|
121
|
+
├── wizard interactive guided flow (create or add features)
|
|
122
|
+
├── create scaffold a new extension project
|
|
123
|
+
├── panel
|
|
124
|
+
│ └── add new webview panel + optional typed RPC (opens in editor area)
|
|
125
|
+
├── menu
|
|
126
|
+
│ ├── add new sidebar tree view (activity bar)
|
|
127
|
+
│ └── edit add an item (panel / command / url / group)
|
|
128
|
+
├── command
|
|
129
|
+
│ └── add new palette command (with optional menu entry + keybinding)
|
|
130
|
+
├── rpc
|
|
131
|
+
│ └── add add a typed RPC method to a panel
|
|
132
|
+
├── statusBar
|
|
133
|
+
│ └── add status bar item → command / panel / menu popup
|
|
134
|
+
├── subpanel
|
|
135
|
+
│ └── add inline sidebar section (lives under a menu container)
|
|
136
|
+
├── treeview
|
|
137
|
+
│ └── add data-driven tree view (getChildren/getTreeItem) under a menu
|
|
138
|
+
├── test
|
|
139
|
+
│ └── setup Vitest config + sample test + vscode/RPC mock helpers
|
|
140
|
+
├── publish
|
|
141
|
+
│ └── init marketplace preflight (README, CHANGELOG, icon, vsce ls)
|
|
142
|
+
├── helper
|
|
143
|
+
│ └── add generate runtime helper (secrets | config | state | notifications)
|
|
144
|
+
├── job
|
|
145
|
+
│ └── add recurring / event-triggered job (interval | dailyAt | on event | onFile)
|
|
146
|
+
├── db
|
|
147
|
+
│ └── init scaffold project database (mini-ORM) at src/helpers/db.ts
|
|
148
|
+
├── model
|
|
149
|
+
│ └── add typed entity + repo under src/models/
|
|
150
|
+
├── crud
|
|
151
|
+
│ └── add full CRUD scaffold (service + list panel + form panel + menu wire)
|
|
152
|
+
├── components
|
|
153
|
+
│ └── add themed React UI library (Button/Input/Field/Card/List) for webviews
|
|
154
|
+
├── doctor diagnose project + safe --fix
|
|
155
|
+
└── upgrade sync framework-owned files from the bundled templates
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Run `vsceasy <resource> --help` for verbs and `vsceasy <resource> <verb> --help` for params.
|
|
159
|
+
|
|
160
|
+
### `panel add`
|
|
161
|
+
```bash
|
|
162
|
+
vsceasy panel add --name settings --title "Settings" --withApi yes
|
|
163
|
+
|
|
164
|
+
# start from a working UI instead of a blank component:
|
|
165
|
+
vsceasy panel add --name signup --template form # inputs + save() RPC
|
|
166
|
+
vsceasy panel add --name items --template list # list + load() RPC
|
|
167
|
+
vsceasy panel add --name stats --template dashboard # stat cards + stats() RPC
|
|
168
|
+
```
|
|
169
|
+
Generates `src/panels/<name>.ts` + `src/webview/panels/<name>/{App.tsx,main.tsx}` + appends `<Name>Api` to `src/shared/api.ts` when `withApi=yes`.
|
|
170
|
+
|
|
171
|
+
`--template` (`blank` | `form` | `list` | `dashboard`, default `blank`) starts the panel from a working UI built with the shared component library (auto-generated on first use via `components add`) and wires the matching RPC method. Non-blank templates force `--withApi` on.
|
|
172
|
+
|
|
173
|
+
### `components add`
|
|
174
|
+
```bash
|
|
175
|
+
vsceasy components add # idempotent; --force to overwrite
|
|
176
|
+
```
|
|
177
|
+
Writes a theme-aware React component library (`Button`, `Input`, `Field`, `Card`, `List` + `components.css`) to `src/webview/components/`, styled with VS Code theme tokens (`var(--vscode-*)`). Import it from any webview: `import { Button, Card, List } from '../../components'`.
|
|
178
|
+
|
|
179
|
+
### `command add`
|
|
180
|
+
```bash
|
|
181
|
+
vsceasy command add \
|
|
182
|
+
--name doStuff \
|
|
183
|
+
--title "Do Stuff" \
|
|
184
|
+
--menuEntry main \
|
|
185
|
+
--group "Actions" \
|
|
186
|
+
--icon play \
|
|
187
|
+
--keybinding "ctrl+shift+h" \
|
|
188
|
+
--when "editorTextFocus && resourceLangId == typescript"
|
|
189
|
+
```
|
|
190
|
+
`--when` writes a VS Code `when` clause that controls palette enablement + auto-injects `contributes.menus.commandPalette` so the command is hidden when the context doesn't match. See [when-clause contexts](https://code.visualstudio.com/api/references/when-clause-contexts).
|
|
191
|
+
For richer keybindings (mac override / `when` clause) edit the generated file:
|
|
192
|
+
```ts
|
|
193
|
+
keybinding: { key: 'ctrl+shift+h', mac: 'cmd+shift+h', when: 'editorTextFocus' }
|
|
194
|
+
// or an array
|
|
195
|
+
keybinding: ['ctrl+a', { key: 'ctrl+b', mac: 'cmd+b' }]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### `menu add`
|
|
199
|
+
Sidebar tree view. Icon picker is searchable across 186+ codicons.
|
|
200
|
+
```bash
|
|
201
|
+
vsceasy menu add --name main --title "My Tools" --icon rocket
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### `menu edit`
|
|
205
|
+
Add an item to an existing menu — opens a panel, runs a command, opens a URL, or creates a collapsible group. Conditional prompts adapt to the chosen item kind.
|
|
206
|
+
```bash
|
|
207
|
+
vsceasy menu edit --name main --kind panel --panel dashboard --label "Dashboard" --icon window
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### `rpc add`
|
|
211
|
+
Extends `src/shared/api.ts` (creates the interface if missing) + inserts a handler stub into the panel (creates the `rpc:` block if missing). Auto-adds `import type` + `definePanel<…Api>` generic when needed.
|
|
212
|
+
```bash
|
|
213
|
+
vsceasy rpc add --panel dashboard --method getCount --params "limit: number" --returns "number"
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### `statusBar add`
|
|
217
|
+
Bind to a command, panel, or popup menu (QuickPick). Markdown tooltip available (Copilot/GitLens-style hover).
|
|
218
|
+
```bash
|
|
219
|
+
# existing command
|
|
220
|
+
vsceasy statusBar add --name buildBtn --text Build --bindTo command --command hello --icon tools
|
|
221
|
+
|
|
222
|
+
# panel (auto-wires <prefix>.open<Panel>)
|
|
223
|
+
vsceasy statusBar add --name openDash --text Dashboard --bindTo panel --panel dashboard
|
|
224
|
+
|
|
225
|
+
# bootstrap new command + status bar together
|
|
226
|
+
vsceasy statusBar add --name sync --text Sync --bindTo "create new command" --newCommandTitle "Run Sync"
|
|
227
|
+
|
|
228
|
+
# popup menu — interactive loop builds each item
|
|
229
|
+
vsceasy statusBar add --name tools --text Tools --bindTo menu
|
|
230
|
+
```
|
|
231
|
+
Rich markdown tooltip:
|
|
232
|
+
```bash
|
|
233
|
+
vsceasy statusBar add \
|
|
234
|
+
--name copilotPro --text "Copilot Pro" --icon copilot \
|
|
235
|
+
--bindTo panel --panel dashboard \
|
|
236
|
+
--tooltipMarkdown "### Copilot Pro\n\n**18% used**\n\n[Upgrade](command:myext.openDashboard)"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### `subpanel add`
|
|
240
|
+
Inline sidebar section (the GitLens / Copilot pattern — collapsible webview that lives inside a menu container). Each subpanel becomes a new section under the chosen activity-bar menu, stacked alongside the tree view and any other sibling subpanels.
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
vsceasy subpanel add --name welcome --menu main --title "Welcome" --withApi yes
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Files:
|
|
247
|
+
- `src/subpanels/<name>.ts` (defineSubpanel with `menu: '<container>'`)
|
|
248
|
+
- `src/webview/subpanels/<name>/{App.tsx,main.tsx}` (React bundle)
|
|
249
|
+
- `<Name>ViewApi` appended to `src/shared/api.ts` when `withApi=yes`
|
|
250
|
+
|
|
251
|
+
Multiple subpanels can reference the same `menu` — they render as stacked collapsible sections in that container.
|
|
252
|
+
|
|
253
|
+
### `doctor`
|
|
254
|
+
Diagnose engine, scripts, panels, RPC contract sync, menu refs, codicons, status bar refs, package.json `contributes` drift, `.gitignore`.
|
|
255
|
+
```bash
|
|
256
|
+
vsceasy doctor # report
|
|
257
|
+
vsceasy doctor --fix=true # auto-fix: missing RPC handler stubs, orphan menu items, .gitignore entries
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### `upgrade`
|
|
261
|
+
Sync framework-owned files (`src/shared/vsceasy/*`, `scripts/gen.ts`) from the bundled templates. Use after upgrading `vsceasy`.
|
|
262
|
+
```bash
|
|
263
|
+
vsceasy upgrade # dry-run
|
|
264
|
+
vsceasy upgrade --apply=true # write + auto-run `bun run gen`
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### `treeview add`
|
|
268
|
+
Data-driven tree view inside an existing menu container. Lazy children via `getChildren`. Built-in dispatch for `run` / `panel` / `command` on click.
|
|
269
|
+
```bash
|
|
270
|
+
vsceasy treeview add --name explorer --menu main --title "Explorer"
|
|
271
|
+
```
|
|
272
|
+
Generates `src/treeViews/<name>.ts`. Refresh from anywhere: `vscode.commands.executeCommand('<prefix>._tree.<name>.refresh')`.
|
|
273
|
+
|
|
274
|
+
### `test setup`
|
|
275
|
+
Drops a `vitest.config.ts`, a sample `src/__tests__/sample.test.ts`, and `src/__tests__/_helpers.ts` with `mockVscode()`, `mockContext()`, and `mockRpcPair<H>()` for end-to-end handler tests. Also adds `test` / `test:watch` scripts + `vitest` devDep.
|
|
276
|
+
```bash
|
|
277
|
+
vsceasy test setup
|
|
278
|
+
bun install && bun run test
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Example:
|
|
282
|
+
```ts
|
|
283
|
+
import { mockRpcPair } from './_helpers';
|
|
284
|
+
import type { DashboardApi } from '../shared/api';
|
|
285
|
+
|
|
286
|
+
const handlers: DashboardApi = { async listFiles() { return ['a.ts']; } };
|
|
287
|
+
const api = mockRpcPair<DashboardApi>(handlers);
|
|
288
|
+
expect(await api.listFiles('**/*.ts')).toEqual(['a.ts']);
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### `job add`
|
|
292
|
+
Recurring or event-triggered background work. Runtime handles registration, cleanup on deactivate, and error isolation. Optional `--minIntervalMs` throttles re-runs across triggers (persisted in `context.globalState`).
|
|
293
|
+
```bash
|
|
294
|
+
# every 60s, runs on startup
|
|
295
|
+
vsceasy job add --name sync --every 60s
|
|
296
|
+
|
|
297
|
+
# at 02:30 local time daily
|
|
298
|
+
vsceasy job add --name nightlyIndex --dailyAt 02:30
|
|
299
|
+
|
|
300
|
+
# on document save (with at-most-once-per-hour throttle)
|
|
301
|
+
vsceasy job add --name lint --on saveDocument --minIntervalMs 3600000
|
|
302
|
+
|
|
303
|
+
# on filesystem changes (create | change | delete)
|
|
304
|
+
vsceasy job add --name reindexMd --onFile "**/*.md"
|
|
305
|
+
|
|
306
|
+
# event triggers: startup | saveDocument | openDocument | changeActiveEditor | changeConfig
|
|
307
|
+
```
|
|
308
|
+
`--every` accepts `30s`, `5m`, `2h`, `1d`, or a raw ms number. Jobs run only while the extension host is active — for cross-session schedules use OS cron or GitHub Actions.
|
|
309
|
+
|
|
310
|
+
### `helper add`
|
|
311
|
+
Generates typed wrappers into `src/helpers/`. Cuts boilerplate for the most-touched VS Code APIs + storage.
|
|
312
|
+
```bash
|
|
313
|
+
vsceasy helper add --kind secrets # context.secrets — OS keychain
|
|
314
|
+
vsceasy helper add --kind config # workspace.getConfiguration — typed
|
|
315
|
+
vsceasy helper add --kind state # workspace + global mementos
|
|
316
|
+
vsceasy helper add --kind notifications # toast + confirm + withProgress
|
|
317
|
+
vsceasy helper add --kind cache # in-memory TTL + LRU + wrap()
|
|
318
|
+
# For ORM use the dedicated commands: `vsceasy db init` + `vsceasy model add`
|
|
319
|
+
```
|
|
320
|
+
For `secrets` and `state`, wire on activate:
|
|
321
|
+
```ts
|
|
322
|
+
import { initSecrets } from './helpers/secrets';
|
|
323
|
+
initSecrets(context);
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### `db init` + `model add` (mini-ORM)
|
|
327
|
+
Typed entities, CRUD, transactions. Workflow:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# 1. one-time per project — creates src/helpers/db.ts
|
|
331
|
+
vsceasy db init # filesystem JSON under context.storageUri/db/
|
|
332
|
+
vsceasy db init --provider global # or globalStorageUri (user-wide)
|
|
333
|
+
|
|
334
|
+
# 2. add models interactively — type `name:type` per line, empty to finish
|
|
335
|
+
vsceasy model add --name User
|
|
336
|
+
# field 1: id:string! (! = primary key)
|
|
337
|
+
# field 2: name:string
|
|
338
|
+
# field 3: email?:string@ (? = optional, @ = indexed)
|
|
339
|
+
# field 4: createdAt:number
|
|
340
|
+
# field 5: (enter to finish)
|
|
341
|
+
|
|
342
|
+
# 3. or in one shot
|
|
343
|
+
vsceasy model add --name Post --fields "id:string!,userId:string@,title:string,body:string"
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
Wire on activate (`src/extension/extension.ts`):
|
|
347
|
+
```ts
|
|
348
|
+
import { initDb } from '../helpers/db';
|
|
349
|
+
initDb(context);
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Use:
|
|
353
|
+
```ts
|
|
354
|
+
import { UsersRepo } from '../models/User';
|
|
355
|
+
|
|
356
|
+
await UsersRepo().insert({ id: 'u1', name: 'Jairo', email: 'j@x.io', createdAt: Date.now() });
|
|
357
|
+
await UsersRepo().update('u1', { name: 'Jairo F' });
|
|
358
|
+
const u = await UsersRepo().findById('u1');
|
|
359
|
+
const recent = await UsersRepo().findMany({ orderBy: 'createdAt:desc', limit: 10 });
|
|
360
|
+
const matches = await UsersRepo().findMany({ where: { email: { in: ['a@x.io', 'b@x.io'] } } });
|
|
361
|
+
await UsersRepo().deleteMany({ email: 'spam@x.io' });
|
|
362
|
+
|
|
363
|
+
// Atomic — rolls back on throw
|
|
364
|
+
import { db } from '../helpers/db';
|
|
365
|
+
import { Users } from '../models/User';
|
|
366
|
+
await db().transaction(async (tx) => {
|
|
367
|
+
await tx(Users).insert({ id: 'u2', name: 'A', email: 'a@x.io', createdAt: Date.now() });
|
|
368
|
+
await tx(Users).update('u1', { name: 'B' });
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Operators: `value` (eq), `{ in: [...] }`, `{ neq: value }`. `orderBy`: `'field:asc'` | `'field:desc'` | `'field'`.
|
|
373
|
+
|
|
374
|
+
Field-spec grammar (interactive loop + `--fields`):
|
|
375
|
+
- `name:type` — required field
|
|
376
|
+
- `name?:type` — optional
|
|
377
|
+
- `name:type!` — primary key (defaults to `id` or first field)
|
|
378
|
+
- `name:type@` — indexed
|
|
379
|
+
- combine: `score:number!@`
|
|
380
|
+
|
|
381
|
+
### `crud add` (Rails-style scaffold)
|
|
382
|
+
End-to-end CRUD UI for a model. Reads `src/models/X.ts`, generates:
|
|
383
|
+
|
|
384
|
+
```
|
|
385
|
+
src/services/UserService.ts ← business logic between RPC and repo
|
|
386
|
+
src/panels/usersList.ts ← list panel (RPC: list, delete, openForm)
|
|
387
|
+
src/panels/userForm.ts ← form panel (RPC: get, save, cancel)
|
|
388
|
+
src/webview/panels/usersList/ ← React table w/ Edit + Delete buttons
|
|
389
|
+
src/webview/panels/userForm/ ← React form, inputs inferred from TS types
|
|
390
|
+
src/shared/api.ts ← appends UsersListApi + UserFormApi
|
|
391
|
+
src/menus/users.ts (optional) ← if --menu new:users
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Inputs auto-inferred:
|
|
395
|
+
- `string` → `<input type="text">`
|
|
396
|
+
- `number` → `<input type="number">`
|
|
397
|
+
- `boolean` → `<input type="checkbox">`
|
|
398
|
+
- `Date` → `<input type="date">`
|
|
399
|
+
- `'a' | 'b' | 'c'` → `<select>` with options
|
|
400
|
+
- `null | undefined` unions stripped before inference
|
|
401
|
+
|
|
402
|
+
```bash
|
|
403
|
+
# Interactive — picks menu policy (none | existing | new)
|
|
404
|
+
vsceasy crud add --model User
|
|
405
|
+
|
|
406
|
+
# Scripted
|
|
407
|
+
vsceasy crud add --model User --menu new:users
|
|
408
|
+
vsceasy crud add --model Post --menu existing:settings
|
|
409
|
+
vsceasy crud add --model Note --menu "(no menu)"
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
#### Custom overrides — `src/models/X.crud.ts`
|
|
413
|
+
Optional file next to your model:
|
|
414
|
+
```ts
|
|
415
|
+
export default {
|
|
416
|
+
title: 'People', // display label
|
|
417
|
+
icon: 'person', // codicon for menu
|
|
418
|
+
hidden: ['createdAt'], // strip from list + form
|
|
419
|
+
order: ['name', 'email', 'role'], // explicit field order
|
|
420
|
+
fields: {
|
|
421
|
+
name: { label: 'Full name' },
|
|
422
|
+
bio: { input: 'textarea', placeholder: 'Short bio…' },
|
|
423
|
+
role: { input: 'select', options: ['admin', 'editor', 'viewer'] },
|
|
424
|
+
email: { hideInList: true }, // visible in form, hidden in table
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
#### Cache
|
|
430
|
+
```ts
|
|
431
|
+
import { createCache } from './helpers/cache';
|
|
432
|
+
|
|
433
|
+
const cache = createCache<User>({ ttlMs: 60_000, max: 200 });
|
|
434
|
+
const u = await cache.wrap(`user:${id}`, () => orm(User).findById(id));
|
|
435
|
+
await cache.refresh(`user:${id}`, () => orm(User).findById(id)); // force reload
|
|
436
|
+
```
|
|
437
|
+
Concurrent `wrap()` calls for the same key share one in-flight loader.
|
|
438
|
+
|
|
439
|
+
### `publish init`
|
|
440
|
+
Marketplace preflight: writes `README.md`, `CHANGELOG.md`, an `assets/icon.png` placeholder, fills `repository` / `categories` / `icon` in package.json, and runs `npx @vscode/vsce ls` as a dry-pack.
|
|
441
|
+
```bash
|
|
442
|
+
vsceasy publish init
|
|
443
|
+
# fix any warnings, then:
|
|
444
|
+
npx @vscode/vsce package
|
|
445
|
+
npx @vscode/vsce publish
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Project config (`vsceasy.config.ts`)
|
|
449
|
+
Auto-generated by `vsceasy create`. Persists per-project defaults so generators don't re-prompt them.
|
|
450
|
+
```ts
|
|
451
|
+
import type { VsceasyConfig } from 'vsceasy';
|
|
452
|
+
|
|
453
|
+
const config: VsceasyConfig = {
|
|
454
|
+
publisher: 'my-publisher',
|
|
455
|
+
commandPrefix: 'myExt',
|
|
456
|
+
ui: 'react',
|
|
457
|
+
defaultCategory: 'My Extension', // used by `command add` when --category is omitted
|
|
458
|
+
defaultIcon: 'rocket', // used by `menu add` when --icon is omitted
|
|
459
|
+
};
|
|
460
|
+
|
|
461
|
+
export default config;
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
## Convention
|
|
465
|
+
|
|
466
|
+
Files in `src/{panels,commands,menus,statusBars,subpanels}/*.ts` are auto-discovered by `bun run gen`, which produces `src/extension/_registry.ts` and keeps `package.json#contributes` in sync. The framework's runtime (`bootstrap(registry)`) wires everything into VS Code on activation.
|
|
467
|
+
|
|
468
|
+
## Architecture
|
|
469
|
+
|
|
470
|
+
See [ARCHITECTURE.md](./ARCHITECTURE.md).
|
|
471
|
+
|
|
472
|
+
## License
|
|
473
|
+
|
|
474
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|