@doist/cli-core 0.5.0 → 0.7.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 +12 -0
- package/README.md +115 -4
- package/dist/commands/changelog.d.ts +56 -0
- package/dist/commands/changelog.d.ts.map +1 -0
- package/dist/commands/changelog.js +159 -0
- package/dist/commands/changelog.js.map +1 -0
- package/dist/commands/errors.d.ts +7 -0
- package/dist/commands/errors.d.ts.map +1 -0
- package/dist/commands/errors.js +2 -0
- package/dist/commands/errors.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +3 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/update.d.ts +88 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +294 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +49 -0
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts +2 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +53 -0
- package/dist/markdown.d.ts.map +1 -0
- package/dist/markdown.js +71 -0
- package/dist/markdown.js.map +1 -0
- package/package.json +24 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [0.7.0](https://github.com/Doist/cli-core/compare/v0.6.0...v0.7.0) (2026-05-09)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* add registerUpdateCommand to ./commands subpath ([#9](https://github.com/Doist/cli-core/issues/9)) ([17c6dc7](https://github.com/Doist/cli-core/commit/17c6dc74cd180ddcdb3e30bf2395ad3db05fe5c9))
|
|
6
|
+
|
|
7
|
+
## [0.6.0](https://github.com/Doist/cli-core/compare/v0.5.0...v0.6.0) (2026-05-09)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* add ./markdown and ./commands subpaths (optional peer-dep extractions) ([#8](https://github.com/Doist/cli-core/issues/8)) ([6b2ad9d](https://github.com/Doist/cli-core/commit/6b2ad9d5a23b5d1d9ae83a2272e959e927a82d40))
|
|
12
|
+
|
|
1
13
|
## [0.5.0](https://github.com/Doist/cli-core/compare/v0.4.0...v0.5.0) (2026-05-08)
|
|
2
14
|
|
|
3
15
|
### Features
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Shared core utilities for Doist CLI projects ([todoist-cli](https://github.com/Doist/todoist-cli), [twist-cli](https://github.com/Doist/twist-cli), [outline-cli](https://github.com/Doist/outline-cli)).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
TypeScript, ESM-only, Node ≥ 20.18.1.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -10,17 +10,128 @@ Shared core utilities for Doist CLI projects ([todoist-cli](https://github.com/D
|
|
|
10
10
|
npm install @doist/cli-core
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
## What's in it
|
|
14
|
+
|
|
15
|
+
| Module | Key exports | Purpose |
|
|
16
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| `commands` (subpath) | `registerChangelogCommand`, `registerUpdateCommand` (+ semver helpers) | Commander wiring for cli-core's standard commands (e.g. `<cli> changelog`, `<cli> update`, `<cli> update switch`). **Requires** `commander` as an optional peer-dep. |
|
|
18
|
+
| `config` | `getConfigPath`, `readConfig`, `readConfigStrict`, `writeConfig`, `updateConfig`, `CoreConfig`, `UpdateChannel` | Read / write a per-CLI JSON config file with typed error codes; `CoreConfig` is the shape of fields cli-core itself owns (extend it for per-CLI fields). |
|
|
19
|
+
| `empty` | `printEmpty` | Print an empty-state message gated on `--json` / `--ndjson` so machine consumers never see human strings on stdout. |
|
|
20
|
+
| `errors` | `CliError` | Typed CLI error class with `code` and exit-code mapping. |
|
|
21
|
+
| `global-args` | `parseGlobalArgs`, `createGlobalArgsStore`, `createAccessibleGate`, `createSpinnerGate`, `getProgressJsonlPath`, `isProgressJsonlEnabled` | Parse well-known global flags (`--json`, `--ndjson`, `--quiet`, `--verbose`, `--accessible`, `--no-spinner`, `--progress-jsonl`) and derive predicates from them. |
|
|
22
|
+
| `json` | `formatJson`, `formatNdjson` | Stable JSON / newline-delimited JSON formatting for stdout. |
|
|
23
|
+
| `markdown` (subpath) | `preloadMarkdown`, `renderMarkdown`, `TerminalRendererOptions` | Lazy-init terminal markdown renderer. **Requires** `marked` and `marked-terminal-renderer` as peer-deps — install only if your CLI uses this subpath. |
|
|
24
|
+
| `options` | `ViewOptions` | Type contract for `{ json?, ndjson? }` per-command options that machine-output gates derive from. |
|
|
25
|
+
| `spinner` | `createSpinner` | Loading spinner factory wrapping `yocto-spinner` with disable gates. |
|
|
26
|
+
| `terminal` | `isCI`, `isStderrTTY`, `isStdinTTY`, `isStdoutTTY` | TTY / CI detection helpers. |
|
|
27
|
+
| `testing` (subpath) | `describeEmptyMachineOutput` | Vitest helpers reusable by consuming CLIs (e.g. parametrised empty-state suite covering `--json` / `--ndjson` / human modes). |
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Global args + spinner gate
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { createGlobalArgsStore, createSpinnerGate, createSpinner } from '@doist/cli-core'
|
|
35
|
+
|
|
36
|
+
const store = createGlobalArgsStore()
|
|
37
|
+
export const isJsonMode = () => store.get().json
|
|
38
|
+
|
|
39
|
+
const shouldDisableSpinner = createSpinnerGate({
|
|
40
|
+
envVar: 'TD_SPINNER',
|
|
41
|
+
getArgs: store.get,
|
|
42
|
+
})
|
|
43
|
+
const { withSpinner } = createSpinner({ isDisabled: shouldDisableSpinner })
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Empty-state print
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { printEmpty } from '@doist/cli-core'
|
|
50
|
+
|
|
51
|
+
if (tasks.length === 0) {
|
|
52
|
+
printEmpty({ options, message: 'No tasks found.' })
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Markdown rendering (optional subpath)
|
|
58
|
+
|
|
59
|
+
Install the peer-deps in the consuming CLI:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install marked marked-terminal-renderer
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Then:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { preloadMarkdown, renderMarkdown } from '@doist/cli-core/markdown'
|
|
69
|
+
|
|
70
|
+
if (!options.json && !options.raw) {
|
|
71
|
+
await preloadMarkdown()
|
|
72
|
+
}
|
|
73
|
+
console.log(await renderMarkdown(comment.body))
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If the peer-deps are missing, `preloadMarkdown` throws a clear error pointing to the install command. TypeScript will also fail to resolve the subpath's types until the peers are installed.
|
|
77
|
+
|
|
78
|
+
### Standard commands (optional subpath)
|
|
79
|
+
|
|
80
|
+
Install the peer-dep in the consuming CLI:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install commander
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Then wire `<cli> changelog` in one call:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { dirname, join } from 'node:path'
|
|
90
|
+
import { fileURLToPath } from 'node:url'
|
|
91
|
+
import { registerChangelogCommand } from '@doist/cli-core/commands'
|
|
92
|
+
import packageJson from '../package.json' with { type: 'json' }
|
|
93
|
+
|
|
94
|
+
registerChangelogCommand(program, {
|
|
95
|
+
path: join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'CHANGELOG.md'),
|
|
96
|
+
repoUrl: 'https://github.com/Doist/todoist-cli',
|
|
97
|
+
version: packageJson.version,
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The helper throws `CliError` (`INVALID_TYPE` for a bad `--count`, `FILE_READ_ERROR` if the file can't be read) so the CLI's top-level error handler formats and exits.
|
|
102
|
+
|
|
103
|
+
Wire `<cli> update` and `<cli> update switch` similarly:
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { createSpinner, getConfigPath } from '@doist/cli-core'
|
|
107
|
+
import { registerUpdateCommand } from '@doist/cli-core/commands'
|
|
108
|
+
import packageJson from '../package.json' with { type: 'json' }
|
|
109
|
+
|
|
110
|
+
const { withSpinner } = createSpinner()
|
|
111
|
+
registerUpdateCommand(program, {
|
|
112
|
+
packageName: '@doist/todoist-cli',
|
|
113
|
+
currentVersion: packageJson.version,
|
|
114
|
+
configPath: getConfigPath('todoist-cli'),
|
|
115
|
+
changelogCommandName: 'td changelog',
|
|
116
|
+
withSpinner,
|
|
117
|
+
})
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`update` checks the configured channel's npm dist-tag (`stable` → `latest`, `pre-release` → `next`), compares against `currentVersion`, and shells out to `npm i -g` (or `pnpm add -g` if `npm_execpath` indicates pnpm). `update switch --stable | --pre-release` flips the persisted `update_channel` field via `updateConfig`, preserving any sibling keys. Both subcommands accept `--json` / `--ndjson`. Errors are `CliError` (`INVALID_FLAGS`, `UPDATE_CHECK_FAILED`, `UPDATE_INSTALL_FAILED`, or the canonical `CONFIG_*` codes if the config file is broken).
|
|
121
|
+
|
|
122
|
+
The semver helpers (`parseVersion`, `compareVersions`, `isNewer`, `getInstallTag`, `fetchLatestVersion`, `getConfiguredUpdateChannel`) are also exported for ad-hoc use outside the registered command.
|
|
123
|
+
|
|
13
124
|
## Development
|
|
14
125
|
|
|
15
126
|
```bash
|
|
16
127
|
npm install
|
|
17
128
|
npm run build
|
|
18
129
|
npm test
|
|
19
|
-
npm run check #
|
|
20
|
-
npm run fix #
|
|
130
|
+
npm run check # oxlint + oxfmt --check (PR gate)
|
|
131
|
+
npm run fix # oxlint --fix + oxfmt
|
|
21
132
|
```
|
|
22
133
|
|
|
23
|
-
|
|
134
|
+
See [AGENTS.md](AGENTS.md) for project conventions, including the rule that this README is kept in sync with public API changes.
|
|
24
135
|
|
|
25
136
|
## License
|
|
26
137
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
export type ChangelogHeadingLevel = 1 | 2 | 'flexible';
|
|
3
|
+
export type ChangelogBulletMarker = '*' | '-';
|
|
4
|
+
export type ChangelogCommandOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Absolute path to the consuming CLI's `CHANGELOG.md`. Resolve from the
|
|
7
|
+
* caller's `import.meta.url` so it works in both `src/` and built `dist/`.
|
|
8
|
+
*/
|
|
9
|
+
path: string;
|
|
10
|
+
/** Repo URL with no trailing slash; the `/blob/v<version>/CHANGELOG.md` suffix is appended. */
|
|
11
|
+
repoUrl: string;
|
|
12
|
+
/** Package version embedded in the "View full changelog" link. */
|
|
13
|
+
version: string;
|
|
14
|
+
/** Default value for the `-n/--count` flag. Default: `5`. */
|
|
15
|
+
defaultCount?: number;
|
|
16
|
+
/** Heading level used for version rows. Default: `2` (i.e. `## 1.2.3`). */
|
|
17
|
+
headingLevel?: ChangelogHeadingLevel;
|
|
18
|
+
/** Bullet markers parsed and rendered. Default: `['*']`. */
|
|
19
|
+
bulletMarkers?: ReadonlyArray<ChangelogBulletMarker>;
|
|
20
|
+
/** Indent continuation lines after a bullet (twist-style wrapped bullets). Default: `false`. */
|
|
21
|
+
continuationIndent?: boolean;
|
|
22
|
+
/** Drop versions empty after cleaning (e.g. deps-only releases). Default: `false`. */
|
|
23
|
+
filterEmptyVersions?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare function formatInline(text: string): string;
|
|
26
|
+
export declare function formatForTerminal(text: string, options: ChangelogCommandOptions): string;
|
|
27
|
+
export declare function cleanChangelog(text: string, options: ChangelogCommandOptions): string;
|
|
28
|
+
export declare function parseChangelog(content: string, count: number, options: ChangelogCommandOptions): {
|
|
29
|
+
text: string;
|
|
30
|
+
hasMore: boolean;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Register the standard `<cli> changelog` command on a Commander program. The
|
|
34
|
+
* command reads `options.path`, prints the latest `--count` versions with
|
|
35
|
+
* conventional-commit boilerplate stripped, and appends a "View full
|
|
36
|
+
* changelog" link to the matching tag on GitHub.
|
|
37
|
+
*
|
|
38
|
+
* Errors as `CliError`: `INVALID_TYPE` for a non-positive `--count`,
|
|
39
|
+
* `FILE_READ_ERROR` if the file cannot be read. The consumer's top-level
|
|
40
|
+
* error handler is expected to format and exit.
|
|
41
|
+
*
|
|
42
|
+
* ```ts
|
|
43
|
+
* import { dirname, join } from 'node:path'
|
|
44
|
+
* import { fileURLToPath } from 'node:url'
|
|
45
|
+
* import { registerChangelogCommand } from '@doist/cli-core/commands'
|
|
46
|
+
* import packageJson from '../package.json' with { type: 'json' }
|
|
47
|
+
*
|
|
48
|
+
* registerChangelogCommand(program, {
|
|
49
|
+
* path: join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'CHANGELOG.md'),
|
|
50
|
+
* repoUrl: 'https://github.com/Doist/todoist-cli',
|
|
51
|
+
* version: packageJson.version,
|
|
52
|
+
* })
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function registerChangelogCommand(program: Command, options: ChangelogCommandOptions): void;
|
|
56
|
+
//# sourceMappingURL=changelog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.d.ts","sourceRoot":"","sources":["../../src/commands/changelog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAGxC,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,CAAC,GAAG,UAAU,CAAA;AACtD,MAAM,MAAM,qBAAqB,GAAG,GAAG,GAAG,GAAG,CAAA;AAE7C,MAAM,MAAM,uBAAuB,GAAG;IAClC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,+FAA+F;IAC/F,OAAO,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAA;IACf,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,2EAA2E;IAC3E,YAAY,CAAC,EAAE,qBAAqB,CAAA;IACpC,4DAA4D;IAC5D,aAAa,CAAC,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAA;IACpD,gGAAgG;IAChG,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAC5B,sFAAsF;IACtF,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAChC,CAAA;AA6BD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAIjD;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CA8BxF;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAwBrF;AASD,wBAAgB,cAAc,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,uBAAuB,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAoBpC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,uBAAuB,GAAG,IAAI,CA2BjG"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { CliError } from '../errors.js';
|
|
4
|
+
function resolve(options) {
|
|
5
|
+
return {
|
|
6
|
+
path: options.path,
|
|
7
|
+
repoUrl: options.repoUrl,
|
|
8
|
+
version: options.version,
|
|
9
|
+
defaultCount: options.defaultCount ?? 5,
|
|
10
|
+
headingLevel: options.headingLevel ?? 2,
|
|
11
|
+
bulletMarkers: options.bulletMarkers ?? ['*'],
|
|
12
|
+
continuationIndent: options.continuationIndent ?? false,
|
|
13
|
+
filterEmptyVersions: options.filterEmptyVersions ?? false,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function headingPrefixSrc(level) {
|
|
17
|
+
if (level === 1)
|
|
18
|
+
return '#';
|
|
19
|
+
if (level === 2)
|
|
20
|
+
return '##';
|
|
21
|
+
return '#{1,2}';
|
|
22
|
+
}
|
|
23
|
+
function bulletCharClass(markers) {
|
|
24
|
+
if (markers.length === 1)
|
|
25
|
+
return markers[0] === '*' ? '\\*' : '-';
|
|
26
|
+
return '[*-]';
|
|
27
|
+
}
|
|
28
|
+
export function formatInline(text) {
|
|
29
|
+
return text
|
|
30
|
+
.replace(/\*\*([^*]+)\*\*/g, (_, content) => chalk.bold(content))
|
|
31
|
+
.replace(/`([^`]+)`/g, (_, code) => chalk.cyan(code));
|
|
32
|
+
}
|
|
33
|
+
export function formatForTerminal(text, options) {
|
|
34
|
+
const { headingLevel, bulletMarkers, continuationIndent } = resolve(options);
|
|
35
|
+
const headerRe = new RegExp(`^${headingPrefixSrc(headingLevel)} `);
|
|
36
|
+
const isBulletLine = (line) => bulletMarkers.some((m) => line.startsWith(`${m} `));
|
|
37
|
+
let inBullet = false;
|
|
38
|
+
return text
|
|
39
|
+
.split('\n')
|
|
40
|
+
.map((line) => {
|
|
41
|
+
if (headerRe.test(line)) {
|
|
42
|
+
inBullet = false;
|
|
43
|
+
return chalk.green.bold(line.replace(headerRe, ''));
|
|
44
|
+
}
|
|
45
|
+
if (line.startsWith('### ')) {
|
|
46
|
+
inBullet = false;
|
|
47
|
+
return chalk.bold(line.slice(4));
|
|
48
|
+
}
|
|
49
|
+
if (isBulletLine(line)) {
|
|
50
|
+
inBullet = true;
|
|
51
|
+
return ` ${chalk.dim('•')} ${formatInline(line.slice(2))}`;
|
|
52
|
+
}
|
|
53
|
+
if (continuationIndent && inBullet && line.length > 0) {
|
|
54
|
+
return ` ${formatInline(line)}`;
|
|
55
|
+
}
|
|
56
|
+
if (line.length === 0) {
|
|
57
|
+
inBullet = false;
|
|
58
|
+
}
|
|
59
|
+
return formatInline(line);
|
|
60
|
+
})
|
|
61
|
+
.join('\n');
|
|
62
|
+
}
|
|
63
|
+
export function cleanChangelog(text, options) {
|
|
64
|
+
const { headingLevel, bulletMarkers } = resolve(options);
|
|
65
|
+
const bullets = bulletCharClass(bulletMarkers);
|
|
66
|
+
const headerSrc = headingPrefixSrc(headingLevel);
|
|
67
|
+
return (text
|
|
68
|
+
// Version headers: `## [1.2.3](url)` → `## 1.2.3` (heading level honoured).
|
|
69
|
+
.replace(new RegExp(`(${headerSrc}) \\[([^\\]]+)\\]\\([^)]*\\)`, 'g'), '$1 $2')
|
|
70
|
+
// Plain commit-hash parens: ` (abc1234)` and ` ([abc1234](url))`.
|
|
71
|
+
.replace(/ \([a-f0-9]{7}\)/g, '')
|
|
72
|
+
.replace(/ \(\[[a-f0-9]{7}\]\([^)]*\)\)/g, '')
|
|
73
|
+
// Issue / PR links: `[#nnn](url)` → `#nnn`.
|
|
74
|
+
.replace(/\[#(\d+)\]\([^)]*\)/g, '#$1')
|
|
75
|
+
// Drop `**deps:**` lines wholesale; not useful to end users.
|
|
76
|
+
.replace(new RegExp(`^${bullets} \\*\\*deps:\\*\\*.*$`, 'gm'), '')
|
|
77
|
+
// Drop `**scope:**` prefixes, keep the content: `**task:** foo` → `foo`.
|
|
78
|
+
.replace(/\*\*[\w-]+:\*\* /g, '')
|
|
79
|
+
// Collapse blank-line runs left by removed deps lines.
|
|
80
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
81
|
+
// Drop now-empty section headers (e.g. `### Bug Fixes` with no items).
|
|
82
|
+
// The lookahead includes `### ` so consecutive empty sections all peel
|
|
83
|
+
// away, not just the last one before a version row.
|
|
84
|
+
.replace(new RegExp(`### [\\w ]+\\n\\n(?=${headerSrc} |### |$)`, 'gm'), ''));
|
|
85
|
+
}
|
|
86
|
+
function isEmptyAfterClean(section, options) {
|
|
87
|
+
const { headingLevel } = resolve(options);
|
|
88
|
+
const cleaned = cleanChangelog(section, options);
|
|
89
|
+
const headerRe = new RegExp(`^${headingPrefixSrc(headingLevel)} .+$`, 'm');
|
|
90
|
+
return cleaned.replace(headerRe, '').trim().length === 0;
|
|
91
|
+
}
|
|
92
|
+
export function parseChangelog(content, count, options) {
|
|
93
|
+
const { headingLevel, filterEmptyVersions } = resolve(options);
|
|
94
|
+
const versionHeaderSrc = `${headingPrefixSrc(headingLevel)} (?:\\d|\\[)`;
|
|
95
|
+
const splitRe = new RegExp(`\\n(?=${versionHeaderSrc})`);
|
|
96
|
+
const matchRe = new RegExp(`^${versionHeaderSrc}`);
|
|
97
|
+
const allVersions = content.split(splitRe).filter((s) => matchRe.test(s));
|
|
98
|
+
const versionSections = filterEmptyVersions
|
|
99
|
+
? allVersions.filter((s) => !isEmptyAfterClean(s, options))
|
|
100
|
+
: allVersions;
|
|
101
|
+
const selected = versionSections.slice(0, count);
|
|
102
|
+
if (selected.length === 0) {
|
|
103
|
+
return { text: 'No changelog entries found.', hasMore: false };
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
text: cleanChangelog(selected.join('\n').trimEnd(), options),
|
|
107
|
+
hasMore: versionSections.length > count,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Register the standard `<cli> changelog` command on a Commander program. The
|
|
112
|
+
* command reads `options.path`, prints the latest `--count` versions with
|
|
113
|
+
* conventional-commit boilerplate stripped, and appends a "View full
|
|
114
|
+
* changelog" link to the matching tag on GitHub.
|
|
115
|
+
*
|
|
116
|
+
* Errors as `CliError`: `INVALID_TYPE` for a non-positive `--count`,
|
|
117
|
+
* `FILE_READ_ERROR` if the file cannot be read. The consumer's top-level
|
|
118
|
+
* error handler is expected to format and exit.
|
|
119
|
+
*
|
|
120
|
+
* ```ts
|
|
121
|
+
* import { dirname, join } from 'node:path'
|
|
122
|
+
* import { fileURLToPath } from 'node:url'
|
|
123
|
+
* import { registerChangelogCommand } from '@doist/cli-core/commands'
|
|
124
|
+
* import packageJson from '../package.json' with { type: 'json' }
|
|
125
|
+
*
|
|
126
|
+
* registerChangelogCommand(program, {
|
|
127
|
+
* path: join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'CHANGELOG.md'),
|
|
128
|
+
* repoUrl: 'https://github.com/Doist/todoist-cli',
|
|
129
|
+
* version: packageJson.version,
|
|
130
|
+
* })
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export function registerChangelogCommand(program, options) {
|
|
134
|
+
const resolved = resolve(options);
|
|
135
|
+
program
|
|
136
|
+
.command('changelog')
|
|
137
|
+
.description('Show recent changelog entries')
|
|
138
|
+
.option('-n, --count <number>', 'Number of versions to show', String(resolved.defaultCount))
|
|
139
|
+
.action(async (commandOptions) => {
|
|
140
|
+
const count = Number(commandOptions.count);
|
|
141
|
+
if (!Number.isInteger(count) || count < 1) {
|
|
142
|
+
throw new CliError('INVALID_TYPE', 'Count must be a positive integer');
|
|
143
|
+
}
|
|
144
|
+
let content;
|
|
145
|
+
try {
|
|
146
|
+
content = await readFile(options.path, 'utf-8');
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
throw new CliError('FILE_READ_ERROR', 'Could not read changelog file');
|
|
150
|
+
}
|
|
151
|
+
const { text, hasMore } = parseChangelog(content, count, options);
|
|
152
|
+
console.log(formatForTerminal(text, options));
|
|
153
|
+
if (hasMore) {
|
|
154
|
+
const url = `${options.repoUrl}/blob/v${options.version}/CHANGELOG.md`;
|
|
155
|
+
console.log(chalk.dim(`\nView full changelog: ${url}`));
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=changelog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changelog.js","sourceRoot":"","sources":["../../src/commands/changelog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error codes thrown by `@doist/cli-core/commands` registration helpers. Folded
|
|
3
|
+
* into the `CliErrorCode` aggregator in `../errors.ts` so consumers don't have
|
|
4
|
+
* to redeclare them in their own `TCode` union when catching.
|
|
5
|
+
*/
|
|
6
|
+
export type CommandErrorCode = 'INVALID_TYPE' | 'FILE_READ_ERROR' | 'INVALID_FLAGS' | 'INVALID_UPDATE_CHANNEL' | 'UPDATE_CHECK_FAILED' | 'UPDATE_INSTALL_FAILED';
|
|
7
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/commands/errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GACtB,cAAc,GACd,iBAAiB,GACjB,eAAe,GACf,wBAAwB,GACxB,qBAAqB,GACrB,uBAAuB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/commands/errors.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { registerChangelogCommand } from './changelog.js';
|
|
2
|
+
export type { ChangelogBulletMarker, ChangelogCommandOptions, ChangelogHeadingLevel, } from './changelog.js';
|
|
3
|
+
export type { CommandErrorCode } from './errors.js';
|
|
4
|
+
export { compareVersions, fetchLatestVersion, getConfiguredUpdateChannel, getInstallTag, isNewer, parseVersion, registerUpdateCommand, } from './update.js';
|
|
5
|
+
export type { UpdateCommandOptions } from './update.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AACzD,YAAY,EACR,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,GACxB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EACH,eAAe,EACf,kBAAkB,EAClB,0BAA0B,EAC1B,aAAa,EACb,OAAO,EACP,YAAY,EACZ,qBAAqB,GACxB,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AAOzD,OAAO,EACH,eAAe,EACf,kBAAkB,EAClB,0BAA0B,EAC1B,aAAa,EACb,OAAO,EACP,YAAY,EACZ,qBAAqB,GACxB,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { type UpdateChannel } from '../config.js';
|
|
3
|
+
import type { SpinnerOptions } from '../spinner.js';
|
|
4
|
+
type WithSpinner = <T>(options: SpinnerOptions, op: () => Promise<T>) => Promise<T>;
|
|
5
|
+
export type UpdateCommandOptions = {
|
|
6
|
+
/** npm package name to query the registry for, e.g. `'@doist/todoist-cli'`. */
|
|
7
|
+
packageName: string;
|
|
8
|
+
/** Caller's current version (read from their package.json at startup). */
|
|
9
|
+
currentVersion: string;
|
|
10
|
+
/** Absolute path to the CLI's config file (use `getConfigPath(appName)`). */
|
|
11
|
+
configPath: string;
|
|
12
|
+
/** Override the npm registry base URL. Default `'https://registry.npmjs.org'`. */
|
|
13
|
+
registryUrl?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Hint shown after a successful stable-channel install, e.g. `'td changelog'`.
|
|
16
|
+
* Omit to skip the post-update tip.
|
|
17
|
+
*/
|
|
18
|
+
changelogCommandName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Optional spinner runner — typically `withSpinner` from a `createSpinner()`
|
|
21
|
+
* kit. When omitted, the operation runs without a spinner.
|
|
22
|
+
*/
|
|
23
|
+
withSpinner?: WithSpinner;
|
|
24
|
+
};
|
|
25
|
+
type ParsedVersion = {
|
|
26
|
+
major: number;
|
|
27
|
+
minor: number;
|
|
28
|
+
patch: number;
|
|
29
|
+
prerelease: string | undefined;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Parse a semver-ish string into core triplet + optional prerelease tag. Build
|
|
33
|
+
* metadata (`+build…`) is stripped per semver §10 since it doesn't affect
|
|
34
|
+
* ordering. Throws on input that doesn't have a numeric `major.minor.patch`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseVersion(version: string): ParsedVersion;
|
|
37
|
+
/** Numeric-aware semver compare. Returns -1, 0, or 1. Pre-releases sort below the same core. */
|
|
38
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
39
|
+
/** Returns true when `candidate` is strictly newer than `current` per semver. */
|
|
40
|
+
export declare function isNewer(current: string, candidate: string): boolean;
|
|
41
|
+
/** Map an `UpdateChannel` to its npm dist-tag. */
|
|
42
|
+
export declare function getInstallTag(channel: UpdateChannel): string;
|
|
43
|
+
export declare function fetchLatestVersion(args: {
|
|
44
|
+
packageName: string;
|
|
45
|
+
channel: UpdateChannel;
|
|
46
|
+
registryUrl?: string;
|
|
47
|
+
}): Promise<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Read the persisted channel. Missing config returns `'stable'`; broken config
|
|
50
|
+
* surfaces as a canonical `CONFIG_*` `CliError`; an unrecognised
|
|
51
|
+
* `update_channel` value surfaces as `INVALID_UPDATE_CHANNEL`.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getConfiguredUpdateChannel(configPath: string): Promise<UpdateChannel>;
|
|
54
|
+
/**
|
|
55
|
+
* Register the standard `<cli> update` and `<cli> update switch` commands on a
|
|
56
|
+
* Commander program. The `update` action checks the npm registry for the
|
|
57
|
+
* configured channel's dist-tag, compares against `currentVersion`, and shells
|
|
58
|
+
* out to `npm i -g` (or `pnpm add -g` if pnpm is detected on the running
|
|
59
|
+
* script's path). `update switch` flips the persisted `update_channel` field
|
|
60
|
+
* between `'stable'` and `'pre-release'`.
|
|
61
|
+
*
|
|
62
|
+
* Errors as `CliError` (`INVALID_FLAGS`, `INVALID_UPDATE_CHANNEL`,
|
|
63
|
+
* `UPDATE_CHECK_FAILED`, `UPDATE_INSTALL_FAILED`, or the canonical `CONFIG_*`
|
|
64
|
+
* codes when the config file is broken). The consumer's top-level error
|
|
65
|
+
* handler is expected to format and exit.
|
|
66
|
+
*
|
|
67
|
+
* Both subcommands accept `--json` / `--ndjson`; success branches emit a single
|
|
68
|
+
* record (`{ currentVersion, latestVersion, channel, updateAvailable | installed }`
|
|
69
|
+
* for `update`, `{ channel }` for `update switch`).
|
|
70
|
+
*
|
|
71
|
+
* ```ts
|
|
72
|
+
* import { getConfigPath, createSpinner } from '@doist/cli-core'
|
|
73
|
+
* import { registerUpdateCommand } from '@doist/cli-core/commands'
|
|
74
|
+
* import packageJson from '../package.json' with { type: 'json' }
|
|
75
|
+
*
|
|
76
|
+
* const { withSpinner } = createSpinner()
|
|
77
|
+
* registerUpdateCommand(program, {
|
|
78
|
+
* packageName: '@doist/todoist-cli',
|
|
79
|
+
* currentVersion: packageJson.version,
|
|
80
|
+
* configPath: getConfigPath('todoist-cli'),
|
|
81
|
+
* changelogCommandName: 'td changelog',
|
|
82
|
+
* withSpinner,
|
|
83
|
+
* })
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export declare function registerUpdateCommand(program: Command, options: UpdateCommandOptions): void;
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACxC,OAAO,EAGH,KAAK,aAAa,EAErB,MAAM,cAAc,CAAA;AAIrB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAInD,KAAK,WAAW,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;AAEnF,MAAM,MAAM,oBAAoB,GAAG;IAC/B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAA;IACnB,0EAA0E;IAC1E,cAAc,EAAE,MAAM,CAAA;IACtB,6EAA6E;IAC7E,UAAU,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;OAGG;IACH,WAAW,CAAC,EAAE,WAAW,CAAA;CAC5B,CAAA;AAED,KAAK,aAAa,GAAG;IACjB,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,GAAG,SAAS,CAAA;CACjC,CAAA;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAS3D;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAY5D;AAED,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,kDAAkD;AAClD,wBAAgB,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAE5D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC3C,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,aAAa,CAAA;IACtB,WAAW,CAAC,EAAE,MAAM,CAAA;CACvB,GAAG,OAAO,CAAC,MAAM,CAAC,CAalB;AAMD;;;;GAIG;AACH,wBAAsB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAW3F;AAmOD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAyB3F"}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { readConfigOrThrow, updateConfigOrThrow, } from '../config.js';
|
|
4
|
+
import { CliError } from '../errors.js';
|
|
5
|
+
import { formatJson, formatNdjson } from '../json.js';
|
|
6
|
+
const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org';
|
|
7
|
+
/**
|
|
8
|
+
* Parse a semver-ish string into core triplet + optional prerelease tag. Build
|
|
9
|
+
* metadata (`+build…`) is stripped per semver §10 since it doesn't affect
|
|
10
|
+
* ordering. Throws on input that doesn't have a numeric `major.minor.patch`.
|
|
11
|
+
*/
|
|
12
|
+
export function parseVersion(version) {
|
|
13
|
+
// Strip leading `v` and any `+build` metadata before splitting prerelease.
|
|
14
|
+
const stripped = version.replace(/^v/, '').split('+', 1)[0];
|
|
15
|
+
const [core, ...rest] = stripped.split('-');
|
|
16
|
+
const [major, minor, patch] = core.split('.').map(Number);
|
|
17
|
+
if (!Number.isInteger(major) || !Number.isInteger(minor) || !Number.isInteger(patch)) {
|
|
18
|
+
throw new Error(`Invalid version string: '${version}'`);
|
|
19
|
+
}
|
|
20
|
+
return { major, minor, patch, prerelease: rest.length > 0 ? rest.join('-') : undefined };
|
|
21
|
+
}
|
|
22
|
+
/** Numeric-aware semver compare. Returns -1, 0, or 1. Pre-releases sort below the same core. */
|
|
23
|
+
export function compareVersions(a, b) {
|
|
24
|
+
const left = parseVersion(a);
|
|
25
|
+
const right = parseVersion(b);
|
|
26
|
+
for (const key of ['major', 'minor', 'patch']) {
|
|
27
|
+
if (left[key] !== right[key])
|
|
28
|
+
return left[key] > right[key] ? 1 : -1;
|
|
29
|
+
}
|
|
30
|
+
if (!left.prerelease && right.prerelease)
|
|
31
|
+
return 1;
|
|
32
|
+
if (left.prerelease && !right.prerelease)
|
|
33
|
+
return -1;
|
|
34
|
+
if (left.prerelease && right.prerelease) {
|
|
35
|
+
return left.prerelease.localeCompare(right.prerelease, undefined, { numeric: true });
|
|
36
|
+
}
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
/** Returns true when `candidate` is strictly newer than `current` per semver. */
|
|
40
|
+
export function isNewer(current, candidate) {
|
|
41
|
+
return compareVersions(candidate, current) > 0;
|
|
42
|
+
}
|
|
43
|
+
/** Map an `UpdateChannel` to its npm dist-tag. */
|
|
44
|
+
export function getInstallTag(channel) {
|
|
45
|
+
return channel === 'pre-release' ? 'next' : 'latest';
|
|
46
|
+
}
|
|
47
|
+
export async function fetchLatestVersion(args) {
|
|
48
|
+
const base = args.registryUrl ?? DEFAULT_REGISTRY_URL;
|
|
49
|
+
const url = `${base}/${args.packageName}/${getInstallTag(args.channel)}`;
|
|
50
|
+
// The abbreviated metadata format skips `readme`, dependency trees, etc.
|
|
51
|
+
// (~50× smaller than the default response on a typical package).
|
|
52
|
+
const response = await fetch(url, {
|
|
53
|
+
headers: { Accept: 'application/vnd.npm.install-v1+json' },
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
throw new Error(`Registry request failed (HTTP ${response.status})`);
|
|
57
|
+
}
|
|
58
|
+
const data = (await response.json());
|
|
59
|
+
return data.version;
|
|
60
|
+
}
|
|
61
|
+
function isValidChannel(value) {
|
|
62
|
+
return value === 'stable' || value === 'pre-release';
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Read the persisted channel. Missing config returns `'stable'`; broken config
|
|
66
|
+
* surfaces as a canonical `CONFIG_*` `CliError`; an unrecognised
|
|
67
|
+
* `update_channel` value surfaces as `INVALID_UPDATE_CHANNEL`.
|
|
68
|
+
*/
|
|
69
|
+
export async function getConfiguredUpdateChannel(configPath) {
|
|
70
|
+
const config = await readConfigOrThrow(configPath);
|
|
71
|
+
const channel = config.update_channel;
|
|
72
|
+
if (channel === undefined)
|
|
73
|
+
return 'stable';
|
|
74
|
+
if (!isValidChannel(channel)) {
|
|
75
|
+
throw new CliError('INVALID_UPDATE_CHANNEL', `Invalid update_channel '${String(channel)}' in config; expected 'stable' or 'pre-release'`);
|
|
76
|
+
}
|
|
77
|
+
return channel;
|
|
78
|
+
}
|
|
79
|
+
function detectPackageManager() {
|
|
80
|
+
// `npm_execpath` is only set when the CLI is invoked via a package manager
|
|
81
|
+
// (e.g. `npm run`). Globally-installed CLIs run directly from the shell, so
|
|
82
|
+
// also widen the search to the running script path and node binary path —
|
|
83
|
+
// both typically include `pnpm` when installed via pnpm's global store.
|
|
84
|
+
const haystack = [process.env.npm_execpath, process.argv[1], process.execPath]
|
|
85
|
+
.filter(Boolean)
|
|
86
|
+
.join(' ');
|
|
87
|
+
return haystack.includes('pnpm') ? 'pnpm' : 'npm';
|
|
88
|
+
}
|
|
89
|
+
function runInstall(pm, packageName, tag) {
|
|
90
|
+
const command = pm === 'pnpm' ? 'add' : 'install';
|
|
91
|
+
return new Promise((resolve, reject) => {
|
|
92
|
+
const child = spawn(pm, [command, '-g', `${packageName}@${tag}`], {
|
|
93
|
+
// Ignore stdout so a chatty install can't deadlock by filling an
|
|
94
|
+
// unread pipe buffer; keep stderr piped so we can surface the tail
|
|
95
|
+
// in the CliError hint on a non-zero exit.
|
|
96
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
97
|
+
// npm/pnpm on Windows are `.cmd` shims that spawn() can't resolve
|
|
98
|
+
// without the shell. Safe to enable here because every argv element
|
|
99
|
+
// is library-controlled (literal command, fixed flags, validated
|
|
100
|
+
// package name + tag).
|
|
101
|
+
shell: process.platform === 'win32',
|
|
102
|
+
});
|
|
103
|
+
let stderr = '';
|
|
104
|
+
child.stderr?.on('data', (data) => {
|
|
105
|
+
stderr += data.toString();
|
|
106
|
+
});
|
|
107
|
+
child.on('error', reject);
|
|
108
|
+
child.on('close', (code) => resolve({ exitCode: code ?? 1, stderr }));
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function emit(view, payload, humanLines) {
|
|
112
|
+
if (view.json) {
|
|
113
|
+
console.log(formatJson(payload));
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (view.ndjson) {
|
|
117
|
+
console.log(formatNdjson([payload]));
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
for (const line of humanLines())
|
|
121
|
+
console.log(line);
|
|
122
|
+
}
|
|
123
|
+
function formatChannel(channel) {
|
|
124
|
+
return channel === 'pre-release' ? chalk.magenta('pre-release') : chalk.green('stable');
|
|
125
|
+
}
|
|
126
|
+
function channelLabel(channel) {
|
|
127
|
+
return channel === 'pre-release' ? ` ${chalk.magenta('(pre-release)')}` : '';
|
|
128
|
+
}
|
|
129
|
+
async function runWithSpinner(withSpinner, text, op) {
|
|
130
|
+
return withSpinner ? withSpinner({ text, color: 'blue' }, op) : op();
|
|
131
|
+
}
|
|
132
|
+
async function runUpdate(options, cmd) {
|
|
133
|
+
if (cmd.check && cmd.channel) {
|
|
134
|
+
throw new CliError('INVALID_FLAGS', 'Specify either --check or --channel, not both.');
|
|
135
|
+
}
|
|
136
|
+
const view = { json: cmd.json, ndjson: cmd.ndjson };
|
|
137
|
+
const channel = await getConfiguredUpdateChannel(options.configPath);
|
|
138
|
+
if (cmd.channel) {
|
|
139
|
+
emit(view, { channel }, () => [`Update channel: ${formatChannel(channel)}`]);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const tag = getInstallTag(channel);
|
|
143
|
+
const label = channelLabel(channel);
|
|
144
|
+
let latestVersion;
|
|
145
|
+
try {
|
|
146
|
+
latestVersion = await runWithSpinner(options.withSpinner, `Checking for updates${label}...`, () => fetchLatestVersion({
|
|
147
|
+
packageName: options.packageName,
|
|
148
|
+
channel,
|
|
149
|
+
registryUrl: options.registryUrl,
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
154
|
+
throw new CliError('UPDATE_CHECK_FAILED', `Failed to check for updates: ${message}`);
|
|
155
|
+
}
|
|
156
|
+
const { currentVersion } = options;
|
|
157
|
+
const upToDate = currentVersion === latestVersion;
|
|
158
|
+
const updateAvailable = !upToDate && isNewer(currentVersion, latestVersion);
|
|
159
|
+
if (cmd.check) {
|
|
160
|
+
emit(view, { currentVersion, latestVersion, channel, updateAvailable }, () => {
|
|
161
|
+
const channelLine = ` Channel: ${formatChannel(channel)}`;
|
|
162
|
+
const headline = upToDate
|
|
163
|
+
? `${chalk.green('✓')} Already up to date (v${currentVersion})`
|
|
164
|
+
: updateAvailable
|
|
165
|
+
? `Update available: ${chalk.dim(`v${currentVersion}`)} → ${chalk.green(`v${latestVersion}`)}`
|
|
166
|
+
: `Downgrade available: ${chalk.dim(`v${currentVersion}`)} → ${chalk.yellow(`v${latestVersion}`)}`;
|
|
167
|
+
return [headline, channelLine];
|
|
168
|
+
});
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (upToDate) {
|
|
172
|
+
emit(view, { currentVersion, latestVersion, channel, installed: false }, () => [
|
|
173
|
+
`${chalk.green('✓')} Already up to date${label} (v${currentVersion})`,
|
|
174
|
+
]);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (!view.json && !view.ndjson) {
|
|
178
|
+
const headline = updateAvailable
|
|
179
|
+
? `Update available${label}: ${chalk.dim(`v${currentVersion}`)} → ${chalk.green(`v${latestVersion}`)}`
|
|
180
|
+
: `Downgrade available${label}: ${chalk.dim(`v${currentVersion}`)} → ${chalk.yellow(`v${latestVersion}`)}`;
|
|
181
|
+
console.log(headline);
|
|
182
|
+
}
|
|
183
|
+
const pm = detectPackageManager();
|
|
184
|
+
let result;
|
|
185
|
+
try {
|
|
186
|
+
result = await runWithSpinner(options.withSpinner, `Updating to v${latestVersion}${label}...`, () => runInstall(pm, options.packageName, tag));
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (error instanceof Error &&
|
|
190
|
+
'code' in error &&
|
|
191
|
+
error.code === 'EACCES') {
|
|
192
|
+
throw new CliError('UPDATE_INSTALL_FAILED', 'Permission denied.', {
|
|
193
|
+
hints: [
|
|
194
|
+
`Run with sudo: sudo ${pm} ${pm === 'pnpm' ? 'add' : 'install'} -g ${options.packageName}@${tag}`,
|
|
195
|
+
],
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
199
|
+
throw new CliError('UPDATE_INSTALL_FAILED', `Install failed: ${message}`);
|
|
200
|
+
}
|
|
201
|
+
if (result.exitCode !== 0) {
|
|
202
|
+
throw new CliError('UPDATE_INSTALL_FAILED', `${pm} exited with code ${result.exitCode}`, result.stderr ? { hints: [result.stderr.trim()] } : {});
|
|
203
|
+
}
|
|
204
|
+
emit(view, { currentVersion, latestVersion, channel, installed: true }, () => {
|
|
205
|
+
const lines = [`${chalk.green('✓')} Updated to v${latestVersion}${label}`];
|
|
206
|
+
if (channel === 'stable' && options.changelogCommandName) {
|
|
207
|
+
lines.push(`${chalk.dim(' Run')} ${chalk.cyan(options.changelogCommandName)} ${chalk.dim('to see what changed')}`);
|
|
208
|
+
}
|
|
209
|
+
return lines;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
async function runSwitch(options, cmd, program) {
|
|
213
|
+
if (cmd.stable && cmd.preRelease) {
|
|
214
|
+
throw new CliError('INVALID_FLAGS', 'Specify either --stable or --pre-release, not both.');
|
|
215
|
+
}
|
|
216
|
+
if (!cmd.stable && !cmd.preRelease) {
|
|
217
|
+
throw new CliError('INVALID_FLAGS', 'Specify --stable or --pre-release.');
|
|
218
|
+
}
|
|
219
|
+
const channel = cmd.preRelease ? 'pre-release' : 'stable';
|
|
220
|
+
const view = { json: cmd.json, ndjson: cmd.ndjson };
|
|
221
|
+
await updateConfigOrThrow(options.configPath, { update_channel: channel });
|
|
222
|
+
emit(view, { channel }, () => {
|
|
223
|
+
if (channel === 'pre-release') {
|
|
224
|
+
return [
|
|
225
|
+
`${chalk.green('✓')} Update channel set to ${formatChannel(channel)}`,
|
|
226
|
+
'',
|
|
227
|
+
`${chalk.yellow('Note:')} Pre-release updates follow the ${chalk.cyan('next')} branch.`,
|
|
228
|
+
'When pre-release changes are merged into a stable release, no further',
|
|
229
|
+
'pre-release updates will be published until a new pre-release cycle begins.',
|
|
230
|
+
'Remember to switch back to stable when done:',
|
|
231
|
+
chalk.dim(` ${program.name()} update switch --stable`),
|
|
232
|
+
];
|
|
233
|
+
}
|
|
234
|
+
return [`${chalk.green('✓')} Update channel set to ${formatChannel(channel)}`];
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Register the standard `<cli> update` and `<cli> update switch` commands on a
|
|
239
|
+
* Commander program. The `update` action checks the npm registry for the
|
|
240
|
+
* configured channel's dist-tag, compares against `currentVersion`, and shells
|
|
241
|
+
* out to `npm i -g` (or `pnpm add -g` if pnpm is detected on the running
|
|
242
|
+
* script's path). `update switch` flips the persisted `update_channel` field
|
|
243
|
+
* between `'stable'` and `'pre-release'`.
|
|
244
|
+
*
|
|
245
|
+
* Errors as `CliError` (`INVALID_FLAGS`, `INVALID_UPDATE_CHANNEL`,
|
|
246
|
+
* `UPDATE_CHECK_FAILED`, `UPDATE_INSTALL_FAILED`, or the canonical `CONFIG_*`
|
|
247
|
+
* codes when the config file is broken). The consumer's top-level error
|
|
248
|
+
* handler is expected to format and exit.
|
|
249
|
+
*
|
|
250
|
+
* Both subcommands accept `--json` / `--ndjson`; success branches emit a single
|
|
251
|
+
* record (`{ currentVersion, latestVersion, channel, updateAvailable | installed }`
|
|
252
|
+
* for `update`, `{ channel }` for `update switch`).
|
|
253
|
+
*
|
|
254
|
+
* ```ts
|
|
255
|
+
* import { getConfigPath, createSpinner } from '@doist/cli-core'
|
|
256
|
+
* import { registerUpdateCommand } from '@doist/cli-core/commands'
|
|
257
|
+
* import packageJson from '../package.json' with { type: 'json' }
|
|
258
|
+
*
|
|
259
|
+
* const { withSpinner } = createSpinner()
|
|
260
|
+
* registerUpdateCommand(program, {
|
|
261
|
+
* packageName: '@doist/todoist-cli',
|
|
262
|
+
* currentVersion: packageJson.version,
|
|
263
|
+
* configPath: getConfigPath('todoist-cli'),
|
|
264
|
+
* changelogCommandName: 'td changelog',
|
|
265
|
+
* withSpinner,
|
|
266
|
+
* })
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
export function registerUpdateCommand(program, options) {
|
|
270
|
+
const update = program
|
|
271
|
+
.command('update')
|
|
272
|
+
.description('Update the CLI to the latest version for the configured channel')
|
|
273
|
+
.option('--check', 'Check for updates without installing')
|
|
274
|
+
.option('--channel', 'Show the current update channel')
|
|
275
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
276
|
+
.option('--ndjson', 'Emit machine-readable NDJSON output')
|
|
277
|
+
.action(async (cmdOptions) => {
|
|
278
|
+
await runUpdate(options, cmdOptions);
|
|
279
|
+
});
|
|
280
|
+
update
|
|
281
|
+
.command('switch')
|
|
282
|
+
.description('Switch update channel between stable and pre-release')
|
|
283
|
+
.option('--stable', 'Use the stable release channel')
|
|
284
|
+
.option('--pre-release', 'Use the pre-release (next) channel')
|
|
285
|
+
.option('--json', 'Emit machine-readable JSON output')
|
|
286
|
+
.option('--ndjson', 'Emit machine-readable NDJSON output')
|
|
287
|
+
.action(async function () {
|
|
288
|
+
// optsWithGlobals merges parent (`update`) options into the
|
|
289
|
+
// subcommand's view; without this, `--json` / `--ndjson` would land
|
|
290
|
+
// on the parent because they're declared on both.
|
|
291
|
+
await runSwitch(options, this.optsWithGlobals(), program);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
//# sourceMappingURL=update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export type UpdateChannel = 'stable' | 'pre-release';
|
|
2
|
+
/**
|
|
3
|
+
* Shape of the fields cli-core itself reads or writes in a CLI's config file.
|
|
4
|
+
* Consumers compose their own config type with `type MyConfig = CoreConfig & { … }`
|
|
5
|
+
* so a single CLI config can be typed once and extended as future cli-core
|
|
6
|
+
* modules (auth, token storage, …) claim more fields.
|
|
7
|
+
*/
|
|
8
|
+
export type CoreConfig = {
|
|
9
|
+
update_channel?: UpdateChannel;
|
|
10
|
+
};
|
|
1
11
|
/**
|
|
2
12
|
* Resolve the canonical config path for a CLI, honouring `XDG_CONFIG_HOME`
|
|
3
13
|
* when set: `${XDG_CONFIG_HOME ?? ~/.config}/<appName>/config.json`.
|
|
@@ -85,4 +95,20 @@ export declare function writeConfig<T extends object>(path: string, config: T, o
|
|
|
85
95
|
* fixing their config file.
|
|
86
96
|
*/
|
|
87
97
|
export declare function updateConfig<T extends object>(path: string, updates: Partial<T>, options?: WriteConfigOptions): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* `readConfig` variant that surfaces broken-config states as `CliError` keyed
|
|
100
|
+
* off `BROKEN_CONFIG_STATE_TO_CODE`. Use this when a command needs to fail
|
|
101
|
+
* loudly on a damaged file (rather than silently treating it as empty), so the
|
|
102
|
+
* consumer's top-level handler can format and exit consistently.
|
|
103
|
+
*
|
|
104
|
+
* Missing files still return an empty object — that's the same "no config"
|
|
105
|
+
* affordance `readConfig` already offers.
|
|
106
|
+
*/
|
|
107
|
+
export declare function readConfigOrThrow<T extends object>(path: string): Promise<Partial<T>>;
|
|
108
|
+
/**
|
|
109
|
+
* `updateConfig` variant that translates broken-config states to `CliError`
|
|
110
|
+
* keyed off `BROKEN_CONFIG_STATE_TO_CODE` in the same single read pass — no
|
|
111
|
+
* pre-check needed at the call site.
|
|
112
|
+
*/
|
|
113
|
+
export declare function updateConfigOrThrow<T extends object>(path: string, updates: Partial<T>, options?: WriteConfigOptions): Promise<void>;
|
|
88
114
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,aAAa,CAAA;AAEpD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,cAAc,CAAC,EAAE,aAAa,CAAA;CACjC,CAAA;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,UAAU,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAGpF;AAED,MAAM,MAAM,sBAAsB,GAC5B;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,GACpB;IAAE,KAAK,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACtC;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GACvC;IAAE,KAAK,EAAE,eAAe,CAAC;IAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;CAAE,GACtF;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAA;AAU3D;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B;;;;CAIc,CAAA;AAEtD;;;;;;;;;;GAUG;AACH,MAAM,MAAM,eAAe,GACvB,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,OAAO,2BAA2B,CAAC,CAAA;AAElF;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAqBpF;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC9C,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,EACT,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EAC/C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAoBf;AAgBD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAe3F;AAED;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EACtD,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,OAAO,GAAE,kBAAuB,GACjC,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { chmod, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
|
+
import { CliError } from './errors.js';
|
|
4
5
|
import { formatJson } from './json.js';
|
|
5
6
|
/**
|
|
6
7
|
* Resolve the canonical config path for a CLI, honouring `XDG_CONFIG_HOME`
|
|
@@ -117,6 +118,54 @@ export async function updateConfig(path, updates, options = {}) {
|
|
|
117
118
|
throw new Error(`Cannot update config at ${path}: file contents are ${result.actual}, not a JSON object. Fix or remove the file before retrying.`);
|
|
118
119
|
}
|
|
119
120
|
}
|
|
121
|
+
function describeBrokenConfig(verb, path, result) {
|
|
122
|
+
if (result.state === 'invalid-shape') {
|
|
123
|
+
return `Cannot ${verb} config at ${path}: contents are ${result.actual}, not a JSON object`;
|
|
124
|
+
}
|
|
125
|
+
return `Cannot ${verb} config at ${path}: ${result.error.message}`;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* `readConfig` variant that surfaces broken-config states as `CliError` keyed
|
|
129
|
+
* off `BROKEN_CONFIG_STATE_TO_CODE`. Use this when a command needs to fail
|
|
130
|
+
* loudly on a damaged file (rather than silently treating it as empty), so the
|
|
131
|
+
* consumer's top-level handler can format and exit consistently.
|
|
132
|
+
*
|
|
133
|
+
* Missing files still return an empty object — that's the same "no config"
|
|
134
|
+
* affordance `readConfig` already offers.
|
|
135
|
+
*/
|
|
136
|
+
export async function readConfigOrThrow(path) {
|
|
137
|
+
const result = await readConfigStrict(path);
|
|
138
|
+
switch (result.state) {
|
|
139
|
+
case 'missing':
|
|
140
|
+
return {};
|
|
141
|
+
case 'present':
|
|
142
|
+
return result.config;
|
|
143
|
+
case 'read-failed':
|
|
144
|
+
case 'invalid-json':
|
|
145
|
+
case 'invalid-shape':
|
|
146
|
+
throw new CliError(BROKEN_CONFIG_STATE_TO_CODE[result.state], describeBrokenConfig('read', path, result));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* `updateConfig` variant that translates broken-config states to `CliError`
|
|
151
|
+
* keyed off `BROKEN_CONFIG_STATE_TO_CODE` in the same single read pass — no
|
|
152
|
+
* pre-check needed at the call site.
|
|
153
|
+
*/
|
|
154
|
+
export async function updateConfigOrThrow(path, updates, options = {}) {
|
|
155
|
+
const result = await readConfigStrict(path);
|
|
156
|
+
switch (result.state) {
|
|
157
|
+
case 'missing':
|
|
158
|
+
await writeConfig(path, updates, options);
|
|
159
|
+
return;
|
|
160
|
+
case 'present':
|
|
161
|
+
await writeConfig(path, { ...result.config, ...updates }, options);
|
|
162
|
+
return;
|
|
163
|
+
case 'read-failed':
|
|
164
|
+
case 'invalid-json':
|
|
165
|
+
case 'invalid-shape':
|
|
166
|
+
throw new CliError(BROKEN_CONFIG_STATE_TO_CODE[result.state], describeBrokenConfig('update', path, result));
|
|
167
|
+
}
|
|
168
|
+
}
|
|
120
169
|
function isPlainObject(value) {
|
|
121
170
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
122
171
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAC5E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CommandErrorCode } from './commands/errors.js';
|
|
1
2
|
import type { ConfigErrorCode } from './config.js';
|
|
2
3
|
export type ErrorType = 'error' | 'info';
|
|
3
4
|
export type CliErrorOptions = {
|
|
@@ -15,7 +16,7 @@ export type CliErrorOptions = {
|
|
|
15
16
|
* export type CliErrorCode = ConfigErrorCode | SpinnerErrorCode | …
|
|
16
17
|
* ```
|
|
17
18
|
*/
|
|
18
|
-
export type CliErrorCode = ConfigErrorCode;
|
|
19
|
+
export type CliErrorCode = CommandErrorCode | ConfigErrorCode;
|
|
19
20
|
/**
|
|
20
21
|
* Generic CLI error carrying a structured code, optional hints, and a severity
|
|
21
22
|
* type.
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAExC,MAAM,MAAM,eAAe,GAAG;IAC1B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;CACnB,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAA;AAExC,MAAM,MAAM,eAAe,GAAG;IAC1B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,IAAI,CAAC,EAAE,SAAS,CAAA;CACnB,CAAA;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,eAAe,CAAA;AAE7D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,QAAQ,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,KAAK;IAC9D,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,YAAY,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;gBAEZ,IAAI,EAAE,KAAK,GAAG,YAAY,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;CAOzF"}
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAuBA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,QAAwC,SAAQ,KAAK;IACrD,IAAI,CAAsB;IAC1B,KAAK,CAAW;IAChB,IAAI,CAAW;IAExB,YAAY,IAA0B,EAAE,OAAe,EAAE,UAA2B,EAAE;QAClF,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAA;QAC1B,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAA;IACvC,CAAC;CACJ"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export { BROKEN_CONFIG_STATE_TO_CODE, getConfigPath, readConfig, readConfigStrict, updateConfig, writeConfig, } from './config.js';
|
|
2
|
-
export type { ConfigErrorCode, ReadConfigStrictResult, WriteConfigOptions } from './config.js';
|
|
1
|
+
export { BROKEN_CONFIG_STATE_TO_CODE, getConfigPath, readConfig, readConfigOrThrow, readConfigStrict, updateConfig, updateConfigOrThrow, writeConfig, } from './config.js';
|
|
2
|
+
export type { ConfigErrorCode, CoreConfig, ReadConfigStrictResult, UpdateChannel, WriteConfigOptions, } from './config.js';
|
|
3
3
|
export { printEmpty } from './empty.js';
|
|
4
4
|
export { CliError } from './errors.js';
|
|
5
5
|
export type { CliErrorCode, CliErrorOptions, ErrorType } from './errors.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACd,MAAM,aAAa,CAAA;AACpB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,WAAW,GACd,MAAM,aAAa,CAAA;AACpB,YAAY,EACR,eAAe,EACf,UAAU,EACV,sBAAsB,EACtB,aAAa,EACb,kBAAkB,GACrB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC3E,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,GAClB,MAAM,kBAAkB,CAAA;AACzB,YAAY,EACR,qBAAqB,EACrB,UAAU,EACV,eAAe,EACf,kBAAkB,GACrB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACpD,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5C,YAAY,EACR,cAAc,EACd,YAAY,EACZ,aAAa,EACb,UAAU,EACV,cAAc,GACjB,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { BROKEN_CONFIG_STATE_TO_CODE, getConfigPath, readConfig, readConfigStrict, updateConfig, writeConfig, } from './config.js';
|
|
1
|
+
export { BROKEN_CONFIG_STATE_TO_CODE, getConfigPath, readConfig, readConfigOrThrow, readConfigStrict, updateConfig, updateConfigOrThrow, writeConfig, } from './config.js';
|
|
2
2
|
export { printEmpty } from './empty.js';
|
|
3
3
|
export { CliError } from './errors.js';
|
|
4
4
|
export { createAccessibleGate, createGlobalArgsStore, createSpinnerGate, getProgressJsonlPath, isProgressJsonlEnabled, parseGlobalArgs, } from './global-args.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,WAAW,GACd,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,2BAA2B,EAC3B,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,mBAAmB,EACnB,WAAW,GACd,MAAM,aAAa,CAAA;AAQpB,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EACH,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,eAAe,GAClB,MAAM,kBAAkB,CAAA;AAOzB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAQ5C,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { TerminalRendererOptions } from 'marked-terminal-renderer';
|
|
2
|
+
export type { TerminalRendererOptions } from 'marked-terminal-renderer';
|
|
3
|
+
export type PreloadMarkdownOptions = {
|
|
4
|
+
/** Theme to drive the renderer; defaults to `darkTheme()`. */
|
|
5
|
+
theme?: TerminalRendererOptions;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Lazy-init a shared `marked` renderer for terminal output. Idempotent — safe
|
|
9
|
+
* to call multiple times; later calls are no-ops once initialised, so the
|
|
10
|
+
* `theme` from the first call wins.
|
|
11
|
+
*
|
|
12
|
+
* Defer the dynamic import to the call site so CLIs that never render
|
|
13
|
+
* markdown (e.g. `--json` / `--ndjson` runs) don't pay the load cost. The
|
|
14
|
+
* peer-dep packages (`marked`, `marked-terminal-renderer`) are loaded only
|
|
15
|
+
* inside this function — a missing peer surfaces here as a friendly error,
|
|
16
|
+
* never as a module-link crash on `import`.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { preloadMarkdown, renderMarkdown } from '@doist/cli-core/markdown'
|
|
20
|
+
*
|
|
21
|
+
* if (!options.json && !options.raw) {
|
|
22
|
+
* await preloadMarkdown()
|
|
23
|
+
* }
|
|
24
|
+
* console.log(await renderMarkdown(comment.body))
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* Custom theme — import directly from the renderer package, which the
|
|
28
|
+
* consumer already has installed as a peer-dep:
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { preloadMarkdown } from '@doist/cli-core/markdown'
|
|
32
|
+
* import { lightTheme } from 'marked-terminal-renderer'
|
|
33
|
+
* await preloadMarkdown({ theme: lightTheme() })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function preloadMarkdown(options?: PreloadMarkdownOptions): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Render a markdown string to ANSI-styled terminal output.
|
|
39
|
+
*
|
|
40
|
+
* Returns the input unchanged if `preloadMarkdown` has not yet run — keeps
|
|
41
|
+
* call sites simple in code paths that may execute before init (e.g. early
|
|
42
|
+
* errors). Trailing whitespace from the renderer is trimmed so callers can
|
|
43
|
+
* `console.log` the result without a stray blank line.
|
|
44
|
+
*
|
|
45
|
+
* ```ts
|
|
46
|
+
* import { preloadMarkdown, renderMarkdown } from '@doist/cli-core/markdown'
|
|
47
|
+
*
|
|
48
|
+
* await preloadMarkdown()
|
|
49
|
+
* console.log(await renderMarkdown('# Title\n\n- one\n- two'))
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function renderMarkdown(text: string): Promise<string>;
|
|
53
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAEvE,YAAY,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAEvE,MAAM,MAAM,sBAAsB,GAAG;IACjC,8DAA8D;IAC9D,KAAK,CAAC,EAAE,uBAAuB,CAAA;CAClC,CAAA;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBrF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIlE"}
|
package/dist/markdown.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
let markedInstance = null;
|
|
2
|
+
/**
|
|
3
|
+
* Lazy-init a shared `marked` renderer for terminal output. Idempotent — safe
|
|
4
|
+
* to call multiple times; later calls are no-ops once initialised, so the
|
|
5
|
+
* `theme` from the first call wins.
|
|
6
|
+
*
|
|
7
|
+
* Defer the dynamic import to the call site so CLIs that never render
|
|
8
|
+
* markdown (e.g. `--json` / `--ndjson` runs) don't pay the load cost. The
|
|
9
|
+
* peer-dep packages (`marked`, `marked-terminal-renderer`) are loaded only
|
|
10
|
+
* inside this function — a missing peer surfaces here as a friendly error,
|
|
11
|
+
* never as a module-link crash on `import`.
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { preloadMarkdown, renderMarkdown } from '@doist/cli-core/markdown'
|
|
15
|
+
*
|
|
16
|
+
* if (!options.json && !options.raw) {
|
|
17
|
+
* await preloadMarkdown()
|
|
18
|
+
* }
|
|
19
|
+
* console.log(await renderMarkdown(comment.body))
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* Custom theme — import directly from the renderer package, which the
|
|
23
|
+
* consumer already has installed as a peer-dep:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { preloadMarkdown } from '@doist/cli-core/markdown'
|
|
27
|
+
* import { lightTheme } from 'marked-terminal-renderer'
|
|
28
|
+
* await preloadMarkdown({ theme: lightTheme() })
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export async function preloadMarkdown(options) {
|
|
32
|
+
if (markedInstance)
|
|
33
|
+
return;
|
|
34
|
+
let modules;
|
|
35
|
+
try {
|
|
36
|
+
modules = await Promise.all([import('marked'), import('marked-terminal-renderer')]);
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (err instanceof Error && 'code' in err && err.code === 'ERR_MODULE_NOT_FOUND') {
|
|
40
|
+
throw new Error("@doist/cli-core/markdown requires 'marked' and 'marked-terminal-renderer' as peer dependencies. " +
|
|
41
|
+
'Install them with: npm install marked marked-terminal-renderer', { cause: err });
|
|
42
|
+
}
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
const [{ Marked }, { createTerminalRenderer, darkTheme }] = modules;
|
|
46
|
+
const instance = new Marked();
|
|
47
|
+
instance.use(createTerminalRenderer(options?.theme ?? darkTheme()));
|
|
48
|
+
markedInstance = instance;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Render a markdown string to ANSI-styled terminal output.
|
|
52
|
+
*
|
|
53
|
+
* Returns the input unchanged if `preloadMarkdown` has not yet run — keeps
|
|
54
|
+
* call sites simple in code paths that may execute before init (e.g. early
|
|
55
|
+
* errors). Trailing whitespace from the renderer is trimmed so callers can
|
|
56
|
+
* `console.log` the result without a stray blank line.
|
|
57
|
+
*
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { preloadMarkdown, renderMarkdown } from '@doist/cli-core/markdown'
|
|
60
|
+
*
|
|
61
|
+
* await preloadMarkdown()
|
|
62
|
+
* console.log(await renderMarkdown('# Title\n\n- one\n- two'))
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export async function renderMarkdown(text) {
|
|
66
|
+
if (!markedInstance)
|
|
67
|
+
return text;
|
|
68
|
+
const rendered = await markedInstance.parse(text);
|
|
69
|
+
return typeof rendered === 'string' ? rendered.trimEnd() : text;
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../src/markdown.ts"],"names":[],"mappings":"AAUA,IAAI,cAAc,GAAkB,IAAI,CAAA;AAExC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAgC;IAClE,IAAI,cAAc;QAAE,OAAM;IAC1B,IAAI,OAA6E,CAAA;IACjF,IAAI,CAAC;QACD,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAA;IACvF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,IAAI,GAAG,YAAY,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,sBAAsB,EAAE,CAAC;YAC/E,MAAM,IAAI,KAAK,CACX,kGAAkG;gBAC9F,gEAAgE,EACpE,EAAE,KAAK,EAAE,GAAG,EAAE,CACjB,CAAA;QACL,CAAC;QACD,MAAM,GAAG,CAAA;IACb,CAAC;IACD,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC,GAAG,OAAO,CAAA;IACnE,MAAM,QAAQ,GAAG,IAAI,MAAM,EAAE,CAAA;IAC7B,QAAQ,CAAC,GAAG,CAAC,sBAAsB,CAAC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,CAAC,CAAC,CAAA;IACnE,cAAc,GAAG,QAAQ,CAAA;AAC7B,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC7C,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAA;IAChC,MAAM,QAAQ,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACjD,OAAO,OAAO,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACnE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@doist/cli-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Shared core utilities for Doist CLI projects",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,6 +10,14 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
},
|
|
13
|
+
"./commands": {
|
|
14
|
+
"types": "./dist/commands/index.d.ts",
|
|
15
|
+
"import": "./dist/commands/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./markdown": {
|
|
18
|
+
"types": "./dist/markdown.d.ts",
|
|
19
|
+
"import": "./dist/markdown.js"
|
|
20
|
+
},
|
|
13
21
|
"./testing": {
|
|
14
22
|
"types": "./dist/testing.d.ts",
|
|
15
23
|
"import": "./dist/testing.js"
|
|
@@ -55,8 +63,11 @@
|
|
|
55
63
|
"@semantic-release/exec": "7.1.0",
|
|
56
64
|
"@semantic-release/git": "10.0.1",
|
|
57
65
|
"@types/node": "25.6.0",
|
|
66
|
+
"commander": "14.0.3",
|
|
58
67
|
"conventional-changelog-conventionalcommits": "9.3.1",
|
|
59
68
|
"lefthook": "2.1.6",
|
|
69
|
+
"marked": "18.0.3",
|
|
70
|
+
"marked-terminal-renderer": "2.2.0",
|
|
60
71
|
"oxfmt": "0.46.0",
|
|
61
72
|
"oxlint": "1.61.0",
|
|
62
73
|
"semantic-release": "25.0.3",
|
|
@@ -68,9 +79,21 @@
|
|
|
68
79
|
"yocto-spinner": "1.1.0"
|
|
69
80
|
},
|
|
70
81
|
"peerDependencies": {
|
|
82
|
+
"commander": ">=14",
|
|
83
|
+
"marked": ">=18",
|
|
84
|
+
"marked-terminal-renderer": ">=2",
|
|
71
85
|
"vitest": ">=4.1"
|
|
72
86
|
},
|
|
73
87
|
"peerDependenciesMeta": {
|
|
88
|
+
"commander": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"marked": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"marked-terminal-renderer": {
|
|
95
|
+
"optional": true
|
|
96
|
+
},
|
|
74
97
|
"vitest": {
|
|
75
98
|
"optional": true
|
|
76
99
|
}
|