@notegen/plugin-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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NoteGen contributors
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,349 @@
1
+ # `@notegen/plugin-cli`
2
+
3
+ ## Offline usage guides
4
+
5
+ Place `USAGE.md` in the plugin project root, beside `plugin.json`. Add localized
6
+ guides such as `USAGE.zh-CN.md` as needed. `notegen-plugin build` automatically
7
+ includes these files in `.notegen/package` and its integrity manifest; source
8
+ validation also checks them. No new manifest field is required.
9
+
10
+ Each guide must be UTF-8 Markdown, at most 128 KiB. Up to 50 guide files are
11
+ accepted. Locale suffixes use a language tag, for example `en` or `zh-CN`.
12
+ The host tries the exact language tag, its base language, then `USAGE.md`.
13
+ Write the default guide in English when supporting a mixed-language audience.
14
+
15
+ Explain the visible entry point, first-use steps, defaults, permissions, and
16
+ common problems. Keep developer setup instructions in `README.md` instead.
17
+ The current viewer renders Markdown text without raw HTML, image loading, or
18
+ link navigation. Guides are available offline without activating plugin code.
19
+ An explicit action button invokes a declared entry command only after the user
20
+ clicks it and the plugin is enabled. Never put executable onboarding in a guide.
21
+
22
+ Rebuild the CLI before using these changes from a source checkout, then rebuild
23
+ and reimport the plugin to include its guides. Older packages without guides
24
+ remain usable and display a missing-guide message.
25
+
26
+ ## Watch mode
27
+
28
+ Use `notegen-plugin dev [directory]` for watch mode. It polls source changes,
29
+ serially builds, and replaces `.notegen/package` only after a successful build
30
+ and package validation. In NoteGen Developer Mode, import and enable that
31
+ directory and opt into Auto-reload for the plugin. Permission expansions still
32
+ require review. This rebuilds the runtime, not state-preserving hot replacement.
33
+ Watch mode does not run type checks or tests. Project-external dependencies and
34
+ ignored output/node_modules directories require restarting the watcher.
35
+
36
+ `@notegen/plugin-cli` is the official command-line tool for creating,
37
+ validating, building, packaging, signing, and verifying NoteGen plugins.
38
+
39
+ > The package source is implemented in the NoteGen Plugin SDK repository, but
40
+ > its first npm release has not been published. The installation commands below
41
+ > become available after that release. Until then, build the SDK workspace and
42
+ > run `node packages/plugin-cli/dist/bin.js` from its checkout.
43
+
44
+ ## Requirements
45
+
46
+ - Node.js 20 or newer
47
+ - A plugin with a version 1 `plugin.json`
48
+ - One TypeScript or JavaScript source entry for `build`
49
+
50
+ After the npm release, install the CLI in a plugin project:
51
+
52
+ ```bash
53
+ pnpm add -D @notegen/plugin-cli
54
+ pnpm exec notegen-plugin --help
55
+ ```
56
+
57
+ From an SDK source checkout:
58
+
59
+ ```bash
60
+ pnpm install
61
+ pnpm build
62
+ node packages/plugin-cli/dist/bin.js --help
63
+ ```
64
+
65
+ The examples below use `notegen-plugin`. Substitute
66
+ `node /absolute/path/to/note-gen-plugin-sdk/packages/plugin-cli/dist/bin.js`
67
+ when running from source.
68
+
69
+ ## Standard workflow
70
+
71
+ From the plugin project root:
72
+
73
+ ```bash
74
+ notegen-plugin validate
75
+ notegen-plugin build
76
+ notegen-plugin validate .notegen/package
77
+ ```
78
+
79
+ `build` bundles the configured source into one self-contained JavaScript ESM
80
+ entry, copies the manifest and declared locale files, generates
81
+ `integrity.json`, validates the complete payload, and replaces
82
+ `.notegen/package` atomically. Import the absolute path to this directory from
83
+ NoteGen's Developer page.
84
+
85
+ Projects created by this SDK run `tsc -p tsconfig.json --noEmit` before this
86
+ command. If you maintain a project by hand, keep the same type-check step in
87
+ your package script; the bundler itself is not a TypeScript type checker.
88
+
89
+ To prepare a release artifact:
90
+
91
+ ```bash
92
+ notegen-plugin pack
93
+ notegen-plugin sign \
94
+ .notegen/releases/com.example.my-plugin-0.1.0.unsigned.notegen-plugin \
95
+ --private-key /secure/path/publisher-private.pem
96
+ notegen-plugin verify \
97
+ .notegen/releases/com.example.my-plugin-0.1.0.notegen-plugin \
98
+ --public-key ./publisher-public.json \
99
+ --require-signature
100
+ ```
101
+
102
+ The default artifacts are:
103
+
104
+ ```text
105
+ .notegen/package/
106
+ .notegen/releases/<id>-<version>.unsigned.notegen-plugin
107
+ .notegen/releases/<id>-<version>.notegen-plugin
108
+ ```
109
+
110
+ `pack` does not accept or read private keys. `sign` reads an already-built
111
+ unsigned archive, validates it, adds `signature.sig`, and writes the final
112
+ `.notegen-plugin`; it never reads or builds a source project. Keep those stages
113
+ separate when signing on an isolated machine.
114
+
115
+ ## Commands
116
+
117
+ ### `create`
118
+
119
+ ```text
120
+ notegen-plugin create <directory> [options]
121
+ ```
122
+
123
+ Creates a new project and refuses to overwrite a non-empty directory.
124
+
125
+ | Option | Meaning |
126
+ | --- | --- |
127
+ | `--id <id>` | Reverse-domain plugin ID; prompted in an interactive terminal and required with `--yes` |
128
+ | `--name <name>` | Display name; an interactive prompt offers the directory name as its default |
129
+ | `--description <text>` | Initial manifest description |
130
+ | `--template <name>` | `command` or `editor-statistics` |
131
+ | `--min-app-version <version>` | Oldest supported NoteGen version |
132
+ | `--api-version <range>` | Required plugin API range |
133
+ | `--package-manager <name>` | `pnpm` or `npm` |
134
+ | `--install` | Run the selected package manager after creation |
135
+ | `--yes` | Disable prompts; `--id` is required and a missing name defaults from the directory |
136
+ | `--json` | Emit machine-readable success output and diagnostic errors |
137
+
138
+ Use a lowercase reverse-domain ID that you control, such as
139
+ `com.example.my-plugin`. The `app.notegen` namespace is reserved for NoteGen
140
+ host internals and remains unavailable to official marketplace plugins.
141
+ Dependency installation is opt-in so that project creation does not silently execute
142
+ package-manager lifecycle behavior.
143
+
144
+ `--json` also disables interactive prompts: provide `--id`, while an omitted
145
+ name is derived from the directory. If `--install` is combined with `--json`,
146
+ package-manager logs go to stderr and the CLI keeps stdout as one JSON document.
147
+
148
+ For the shorter scaffold entry point, see
149
+ [`create-notegen-plugin`](../create-notegen-plugin/README.md).
150
+
151
+ ### `validate`
152
+
153
+ ```text
154
+ notegen-plugin validate [path] [options]
155
+ ```
156
+
157
+ Runs the validation applicable to a source project, built development directory,
158
+ or package archive. It accepts unsigned development input by default.
159
+ For a source project, preflight parses every declared locale resource and checks
160
+ that the default locale contains every contribution key. It validates the source
161
+ entry separately and does not require the configured built `.js` entry to exist
162
+ before `build` creates it.
163
+
164
+ | Option | Meaning |
165
+ | --- | --- |
166
+ | `--api-version <version>` | Check against a specific host API version |
167
+ | `--app-version <version>` | Check against a specific NoteGen version |
168
+ | `--public-key <file>` | Verify an embedded signature with a publisher public-key JSON file |
169
+ | `--require-signature` | Reject input without `signature.sig` |
170
+ | `--json` | Emit machine-readable diagnostics |
171
+
172
+ Use `validate` for project preflight and development output. Use `verify` when
173
+ you specifically want to inspect a complete directory or archive without
174
+ executing it.
175
+
176
+ If `--app-version` is omitted, the manifest is still validated but its
177
+ `minAppVersion` is not compared with a concrete NoteGen release. Text output
178
+ states that explicitly, and JSON output sets `appCompatibilityChecked` to
179
+ `false`. Release automation should always pass the target app version.
180
+
181
+ ### `build`
182
+
183
+ ```text
184
+ notegen-plugin build [directory] [options]
185
+ ```
186
+
187
+ Builds a source project and always writes `.notegen/package` below that project.
188
+ The source path defaults to `src/main.ts` and may be set as
189
+ `package.json#notegen.source`.
190
+
191
+ | Option | Meaning |
192
+ | --- | --- |
193
+ | `--api-version <version>` | Check the built plugin against a host API version |
194
+ | `--app-version <version>` | Check the built plugin against a NoteGen version |
195
+ | `--json` | Emit machine-readable output |
196
+
197
+ The bundle must export a named `activate` function. Residual relative, package,
198
+ remote, or dynamic imports are rejected because the NoteGen runtime does not
199
+ resolve modules for a plugin.
200
+
201
+ ### `pack`
202
+
203
+ ```text
204
+ notegen-plugin pack [directory] [options]
205
+ ```
206
+
207
+ Builds and validates a plugin project, then writes a deterministic unsigned ZIP
208
+ archive. Its default output is
209
+ `.notegen/releases/<id>-<version>.unsigned.notegen-plugin`.
210
+
211
+ | Option | Meaning |
212
+ | --- | --- |
213
+ | `--output <file>` | Select the unsigned archive path |
214
+ | `--force` | Replace the exact output file if it already exists |
215
+ | `--api-version <version>` | Check against a host API version |
216
+ | `--app-version <version>` | Check against a NoteGen version |
217
+ | `--json` | Emit machine-readable output |
218
+
219
+ `pack` never reads a private key and never produces a signed marketplace
220
+ artifact.
221
+
222
+ ### `keygen`
223
+
224
+ ```text
225
+ notegen-plugin keygen [options]
226
+ ```
227
+
228
+ Generates an Ed25519 publisher key pair. The private key is PKCS#8 PEM; the
229
+ public JSON contains the raw 32-byte public key encoded as Base64. Choose
230
+ explicit destinations when integrating with a release process:
231
+
232
+ ```bash
233
+ notegen-plugin keygen \
234
+ --private-key /secure/path/publisher-private.pem \
235
+ --public-key ./publisher-public.json
236
+ ```
237
+
238
+ | Option | Meaning |
239
+ | --- | --- |
240
+ | `--output <directory>` | Base directory for default key filenames |
241
+ | `--private-key <file>` | Private PEM destination |
242
+ | `--public-key <file>` | Public JSON destination |
243
+ | `--passphrase-env <name>` | Encrypt or read the private key with a passphrase from this environment variable |
244
+ | `--force` | Replace the exact selected key files |
245
+ | `--json` | Emit machine-readable output; private key material is never printed |
246
+
247
+ Store the private key outside source control, synced note folders, and public CI
248
+ artifacts. Back it up offline. The public JSON is safe to publish and is the file
249
+ passed to `verify`; marketplace key registration will be documented only when
250
+ submissions open.
251
+
252
+ The two key files are staged and published as a recoverable pair. When replacing
253
+ an existing pair with `--force`, the CLI keeps both previous files until both new
254
+ files are active and rolls back the pair if publication fails.
255
+
256
+ This command creates publisher keys only. It cannot create the NoteGen
257
+ marketplace root key, sign a marketplace index, or register a publisher.
258
+
259
+ ### `sign`
260
+
261
+ ```text
262
+ notegen-plugin sign <unsigned-archive> --private-key <pem> [options]
263
+ ```
264
+
265
+ Validates and signs an unsigned archive, embeds `signature.sig`, and writes a
266
+ final `.notegen-plugin`. The signed documents use RFC 8785 JCS before NoteGen's
267
+ length-framed Ed25519 signature message is created.
268
+
269
+ | Option | Meaning |
270
+ | --- | --- |
271
+ | `--output <file>` | Select the final archive path |
272
+ | `--passphrase-env <name>` | Read the private-key passphrase from this environment variable |
273
+ | `--force` | Replace the exact output file if it already exists |
274
+ | `--api-version <version>` | Check against a host API version |
275
+ | `--app-version <version>` | Check against a NoteGen version |
276
+ | `--json` | Emit machine-readable output |
277
+
278
+ `sign` accepts only an already-built archive. It does not scan, install, or
279
+ build source code. Do not put the private key or its passphrase in a command-line
280
+ argument, repository, package, log, or unsigned archive.
281
+
282
+ ### `verify`
283
+
284
+ ```text
285
+ notegen-plugin verify <archive-or-directory> [options]
286
+ ```
287
+
288
+ Validates a complete package without loading or executing its JavaScript.
289
+
290
+ | Option | Meaning |
291
+ | --- | --- |
292
+ | `--public-key <publisher-public.json>` | Verify `signature.sig` against the publisher public key |
293
+ | `--api-version <version>` | Check against a host API version |
294
+ | `--app-version <version>` | Check against a NoteGen version |
295
+ | `--require-signature` | Reject unsigned input |
296
+ | `--json` | Emit machine-readable diagnostics |
297
+
298
+ An archive whose name ends in the final `.notegen-plugin` suffix always requires
299
+ `signature.sig`; the programmatic API cannot turn that rule off.
300
+ `--require-signature` additionally applies the same policy to development
301
+ directories and `.unsigned.notegen-plugin` input. For a release candidate, use
302
+ both `--public-key` and `--require-signature`. Without a public key, the command
303
+ can validate signature encoding and package integrity but cannot prove who
304
+ signed the package.
305
+
306
+ Successful local verification does not validate a marketplace listing, root
307
+ index signature, publisher reputation, source reproducibility, license, or
308
+ review status. It never means “official” or “approved by NoteGen.”
309
+
310
+ ## Validation and package rules
311
+
312
+ The CLI mirrors the version 1 desktop-host boundary, including:
313
+
314
+ - strict JSON parsing with duplicate and unknown field rejection;
315
+ - manifest IDs, namespaces, SemVer requirements, permissions, contributions,
316
+ activation events, and locale validation;
317
+ - path normalization, collision (including implicit parent directories), forbidden-name, file-type, archive-size, and
318
+ compression-ratio checks;
319
+ - exact SHA-256 payload coverage through `integrity.json`;
320
+ - Ed25519 package signatures using RFC 8785 JSON Canonicalization Scheme (JCS).
321
+
322
+ An archive is ZIP-formatted but should always use the `.notegen-plugin`
323
+ extension. NoteGen does not install dependencies or run package scripts on a
324
+ user's device.
325
+
326
+ ## Exit codes
327
+
328
+ | Code | Meaning |
329
+ | --- | --- |
330
+ | `0` | Success |
331
+ | `1` | Plugin project or package failed validation/build/signing |
332
+ | `2` | Invalid command usage |
333
+ | `3` | Unsafe or destructive operation refused |
334
+ | `70` | Unexpected internal failure |
335
+ | `130` | Interrupted |
336
+
337
+ Every command supports `--json`. In that mode, both successful results and
338
+ diagnostic errors are emitted as exactly one JSON document on stdout; incidental
339
+ installation output is sent to stderr. JSON mode never prompts. For unattended
340
+ creation, provide an explicit `--id`; `--yes` is optional when `--json` is
341
+ already present. Always treat a non-zero exit code as failure.
342
+
343
+ ## Marketplace status
344
+
345
+ Community submissions are not open. The CLI can produce and locally verify a
346
+ publisher-signed package, but it cannot upload a release, edit the marketplace
347
+ catalog, create a root-signed index, or grant trust. Follow the instructions in
348
+ [`codexu/note-gen-plugins`](https://github.com/codexu/note-gen-plugins) only
349
+ after that repository explicitly opens submissions.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/bin.js ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from './cli.js';
3
+ process.exitCode = await runCli();
package/dist/cli.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ import { Command } from 'commander';
2
+ export declare const PLUGIN_CLI_VERSION: "0.1.0";
3
+ export interface CliIo {
4
+ readonly stdout: Pick<NodeJS.WriteStream, 'write'>;
5
+ readonly stderr: Pick<NodeJS.WriteStream, 'write'>;
6
+ }
7
+ export interface CreateCliProgramOptions {
8
+ /** Suppress Commander's prose errors so runCli can emit one JSON document. */
9
+ readonly jsonMode?: boolean;
10
+ /** Captures help/version prose so runCli can wrap it in JSON. */
11
+ readonly commanderOutput?: string[];
12
+ }
13
+ export declare function createCliProgram(io?: CliIo, options?: CreateCliProgramOptions): Command;
14
+ export declare function runCli(argv?: readonly string[], io?: CliIo): Promise<number>;
15
+ export declare function runCreateCli(argv?: readonly string[], io?: CliIo): Promise<number>;