@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.
Files changed (124) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/LICENSE +21 -0
  3. package/README.md +474 -0
  4. package/dist/bin/cli.d.ts +1 -0
  5. package/dist/bin/cli.js +9044 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/commands/command/add.d.ts +3 -0
  8. package/dist/commands/components/add.d.ts +3 -0
  9. package/dist/commands/create.d.ts +3 -0
  10. package/dist/commands/crud/add.d.ts +3 -0
  11. package/dist/commands/db/init.d.ts +3 -0
  12. package/dist/commands/doctor.d.ts +3 -0
  13. package/dist/commands/groups.d.ts +16 -0
  14. package/dist/commands/helper/add.d.ts +3 -0
  15. package/dist/commands/job/add.d.ts +3 -0
  16. package/dist/commands/menu/add.d.ts +3 -0
  17. package/dist/commands/menu/edit.d.ts +3 -0
  18. package/dist/commands/model/add.d.ts +3 -0
  19. package/dist/commands/panel/add.d.ts +3 -0
  20. package/dist/commands/publish/init.d.ts +3 -0
  21. package/dist/commands/rpc/add.d.ts +3 -0
  22. package/dist/commands/statusBar/add.d.ts +3 -0
  23. package/dist/commands/subpanel/add.d.ts +3 -0
  24. package/dist/commands/test/setup.d.ts +3 -0
  25. package/dist/commands/treeView/add.d.ts +3 -0
  26. package/dist/commands/upgrade.d.ts +3 -0
  27. package/dist/commands/wizard.d.ts +3 -0
  28. package/dist/data/codicons.d.ts +9 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +3169 -0
  31. package/dist/lib/command/add.d.ts +31 -0
  32. package/dist/lib/components/add.d.ts +20 -0
  33. package/dist/lib/config.d.ts +10 -0
  34. package/dist/lib/crud/add.d.ts +19 -0
  35. package/dist/lib/crud/crudConfig.d.ts +37 -0
  36. package/dist/lib/crud/parseModel.d.ts +33 -0
  37. package/dist/lib/db/init.d.ts +16 -0
  38. package/dist/lib/db/wire.d.ts +10 -0
  39. package/dist/lib/doctor.d.ts +30 -0
  40. package/dist/lib/findProject.d.ts +10 -0
  41. package/dist/lib/helper/add.d.ts +14 -0
  42. package/dist/lib/iconPicker.d.ts +7 -0
  43. package/dist/lib/index.d.ts +46 -0
  44. package/dist/lib/interactive.d.ts +30 -0
  45. package/dist/lib/job/add.d.ts +24 -0
  46. package/dist/lib/menu/add.d.ts +13 -0
  47. package/dist/lib/menu/edit.d.ts +39 -0
  48. package/dist/lib/menuTree.d.ts +33 -0
  49. package/dist/lib/model/add.d.ts +27 -0
  50. package/dist/lib/model/parseFields.d.ts +14 -0
  51. package/dist/lib/panel/add.d.ts +29 -0
  52. package/dist/lib/publish/init.d.ts +12 -0
  53. package/dist/lib/rpc/add.d.ts +22 -0
  54. package/dist/lib/scaffold.d.ts +13 -0
  55. package/dist/lib/statusBar/add.d.ts +33 -0
  56. package/dist/lib/subpanel/add.d.ts +20 -0
  57. package/dist/lib/testSetup/index.d.ts +10 -0
  58. package/dist/lib/treeView/add.d.ts +13 -0
  59. package/dist/lib/upgrade.d.ts +22 -0
  60. package/dist/lib/validate.d.ts +14 -0
  61. package/dist/lib/wizard/run.d.ts +13 -0
  62. package/package.json +67 -0
  63. package/templates/_generators/command/command.ts.tpl +8 -0
  64. package/templates/_generators/components/Button.tsx.tpl +12 -0
  65. package/templates/_generators/components/Card.tsx.tpl +22 -0
  66. package/templates/_generators/components/Field.tsx.tpl +20 -0
  67. package/templates/_generators/components/Input.tsx.tpl +10 -0
  68. package/templates/_generators/components/List.tsx.tpl +29 -0
  69. package/templates/_generators/components/components.css.tpl +66 -0
  70. package/templates/_generators/components/index.ts.tpl +10 -0
  71. package/templates/_generators/crud/formApp.tsx.tpl +83 -0
  72. package/templates/_generators/crud/formNav.ts.tpl +19 -0
  73. package/templates/_generators/crud/formPanel.ts.tpl +32 -0
  74. package/templates/_generators/crud/listApp.tsx.tpl +84 -0
  75. package/templates/_generators/crud/listPanel.ts.tpl +30 -0
  76. package/templates/_generators/crud/main.tsx.tpl +6 -0
  77. package/templates/_generators/crud/service.ts.tpl +27 -0
  78. package/templates/_generators/helper/cache.ts.tpl +117 -0
  79. package/templates/_generators/helper/config.ts.tpl +36 -0
  80. package/templates/_generators/helper/db.ts.tpl +322 -0
  81. package/templates/_generators/helper/notifications.ts.tpl +45 -0
  82. package/templates/_generators/helper/secrets.ts.tpl +36 -0
  83. package/templates/_generators/helper/state.ts.tpl +44 -0
  84. package/templates/_generators/job/job.ts.tpl +10 -0
  85. package/templates/_generators/menu/menu.ts.tpl +21 -0
  86. package/templates/_generators/model/model.ts.tpl +17 -0
  87. package/templates/_generators/panel/App.tsx.tpl +10 -0
  88. package/templates/_generators/panel/main.tsx.tpl +6 -0
  89. package/templates/_generators/panel/panel.ts.tpl +5 -0
  90. package/templates/_generators/panel/templates/dashboard/App.tsx.tpl +41 -0
  91. package/templates/_generators/panel/templates/form/App.tsx.tpl +44 -0
  92. package/templates/_generators/panel/templates/list/App.tsx.tpl +40 -0
  93. package/templates/_generators/publish/CHANGELOG.md.tpl +8 -0
  94. package/templates/_generators/publish/README.md.tpl +23 -0
  95. package/templates/_generators/statusBar/statusBar.ts.tpl +7 -0
  96. package/templates/_generators/subpanel/App.tsx.tpl +10 -0
  97. package/templates/_generators/subpanel/main.tsx.tpl +6 -0
  98. package/templates/_generators/subpanel/subpanel.ts.tpl +6 -0
  99. package/templates/_generators/test/_helpers.ts.tpl +120 -0
  100. package/templates/_generators/test/sample.test.ts.tpl +38 -0
  101. package/templates/_generators/test/vitest.config.ts.tpl +23 -0
  102. package/templates/_generators/test/vscode.stub.ts.tpl +109 -0
  103. package/templates/_generators/treeView/treeView.ts.tpl +16 -0
  104. package/templates/react/.vscode/launch.json +34 -0
  105. package/templates/react/.vscode/tasks.json +32 -0
  106. package/templates/react/.vscodeignore +8 -0
  107. package/templates/react/README.md +50 -0
  108. package/templates/react/package.json +54 -0
  109. package/templates/react/scripts/gen.ts +395 -0
  110. package/templates/react/src/commands/hello.ts +6 -0
  111. package/templates/react/src/extension/extension.ts +5 -0
  112. package/templates/react/src/panels/dashboard.ts +21 -0
  113. package/templates/react/src/shared/api.ts +7 -0
  114. package/templates/react/src/shared/vsceasy/bootstrap.ts +657 -0
  115. package/templates/react/src/shared/vsceasy/client.ts +8 -0
  116. package/templates/react/src/shared/vsceasy/codiconNames.ts +196 -0
  117. package/templates/react/src/shared/vsceasy/define.ts +269 -0
  118. package/templates/react/src/shared/vsceasy/index.ts +13 -0
  119. package/templates/react/src/shared/vsceasy/rpc.ts +214 -0
  120. package/templates/react/src/webview/panels/dashboard/App.tsx +31 -0
  121. package/templates/react/src/webview/panels/dashboard/main.tsx +6 -0
  122. package/templates/react/src/webview/styles.css +33 -0
  123. package/templates/react/tsconfig.json +17 -0
  124. 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