@mx-space/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 +33 -0
- package/README.md +375 -0
- package/ROADMAP.md +42 -0
- package/bin/mxs.cjs +40 -0
- package/dist/Lexical.dev-DpU35QTu.mjs +10992 -0
- package/dist/Lexical.dev-DpU35QTu.mjs.map +1 -0
- package/dist/Lexical.node-gYNDt_p9.mjs +247 -0
- package/dist/Lexical.node-gYNDt_p9.mjs.map +1 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs +5579 -0
- package/dist/Lexical.prod-t4c3bHV3.mjs.map +1 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs +496 -0
- package/dist/LexicalClipboard.dev-CdeeWCIq.mjs.map +1 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs +26 -0
- package/dist/LexicalClipboard.node-0e9GBL1g.mjs.map +1 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs +293 -0
- package/dist/LexicalClipboard.prod-CsCWYmV7.mjs.map +1 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs +539 -0
- package/dist/LexicalCodeCore.dev-haI2cqH8.mjs.map +1 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs +383 -0
- package/dist/LexicalCodeCore.prod-D_k7zuE5.mjs.map +1 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs +90 -0
- package/dist/LexicalDragon.dev-CAggdFh_.mjs.map +1 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs +15 -0
- package/dist/LexicalDragon.node-QMR_wqJg.mjs.map +1 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs +61 -0
- package/dist/LexicalDragon.prod-OssQhwS-.mjs.map +1 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs +1665 -0
- package/dist/LexicalExtension.dev-CtDZiMCU.mjs.map +1 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs +51 -0
- package/dist/LexicalExtension.node-BM0gh8zu.mjs.map +1 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs +971 -0
- package/dist/LexicalExtension.prod-Ug6emhEO.mjs.map +1 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs +45 -0
- package/dist/LexicalHeadless.dev-D4yQpl_s.mjs.map +1 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs +31 -0
- package/dist/LexicalHeadless.prod-jeN65B3k.mjs.map +1 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs +686 -0
- package/dist/LexicalHtml.dev-BdU1_ITQ.mjs.map +1 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs +26 -0
- package/dist/LexicalHtml.node-DLtAh00E.mjs.map +1 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs +432 -0
- package/dist/LexicalHtml.prod-DdLE1HHT.mjs.map +1 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs +1084 -0
- package/dist/LexicalLink.dev-DK87Biuy.mjs.map +1 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs +717 -0
- package/dist/LexicalLink.prod-fssuv6Sf.mjs.map +1 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs +1352 -0
- package/dist/LexicalList.dev-BJ4dr_rk.mjs.map +1 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs +841 -0
- package/dist/LexicalList.prod-jWBbaWfi.mjs.map +1 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs +1207 -0
- package/dist/LexicalMarkdown.dev-C8e-eh6y.mjs.map +1 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs +756 -0
- package/dist/LexicalMarkdown.prod-k73tZVb2.mjs.map +1 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs +645 -0
- package/dist/LexicalRichText.dev-CrSqq3K-.mjs.map +1 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs +106 -0
- package/dist/LexicalRichText.node-B7k7wlQz.mjs.map +1 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs +429 -0
- package/dist/LexicalRichText.prod-CqvyxQ9m.mjs.map +1 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs +725 -0
- package/dist/LexicalSelection.dev-sNOHKHe_.mjs.map +1 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs +38 -0
- package/dist/LexicalSelection.node-Di7GwBCZ.mjs.map +1 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs +388 -0
- package/dist/LexicalSelection.prod-SWllPJop.mjs.map +1 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs +3262 -0
- package/dist/LexicalTable.dev-CQkLHXJx.mjs.map +1 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs +2218 -0
- package/dist/LexicalTable.prod-BtqCwKSi.mjs.map +1 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs +850 -0
- package/dist/LexicalUtils.dev-DiUpsXE8.mjs.map +1 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs +66 -0
- package/dist/LexicalUtils.node-CmK462d1.mjs.map +1 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs +377 -0
- package/dist/LexicalUtils.prod-bWwV4GAF.mjs.map +1 -0
- package/dist/auth-DIFZzoMm.mjs +211 -0
- package/dist/auth-DIFZzoMm.mjs.map +1 -0
- package/dist/bin/mxs.d.mts +927 -0
- package/dist/bin/mxs.mjs +3249 -0
- package/dist/bin/mxs.mjs.map +1 -0
- package/dist/chunk-hT5z_Zn9.mjs +35 -0
- package/dist/config-store-DIu7x0ao.mjs +121 -0
- package/dist/config-store-DIu7x0ao.mjs.map +1 -0
- package/dist/create-B2AOQL1e.mjs +24 -0
- package/dist/create-B2AOQL1e.mjs.map +1 -0
- package/dist/create-CwjGcv2n.mjs +23 -0
- package/dist/create-CwjGcv2n.mjs.map +1 -0
- package/dist/create-DT1l2hue.mjs +23 -0
- package/dist/create-DT1l2hue.mjs.map +1 -0
- package/dist/create-DjlRHPXy.mjs +23 -0
- package/dist/create-DjlRHPXy.mjs.map +1 -0
- package/dist/create-Dz6rJJSS.mjs +19 -0
- package/dist/create-Dz6rJJSS.mjs.map +1 -0
- package/dist/delete-B4dGrrus.mjs +22 -0
- package/dist/delete-B4dGrrus.mjs.map +1 -0
- package/dist/delete-BH6ZngTz.mjs +22 -0
- package/dist/delete-BH6ZngTz.mjs.map +1 -0
- package/dist/delete-BrY5zJ6S.mjs +22 -0
- package/dist/delete-BrY5zJ6S.mjs.map +1 -0
- package/dist/delete-CaG2d_xt.mjs +31 -0
- package/dist/delete-CaG2d_xt.mjs.map +1 -0
- package/dist/delete-YzRliRn8.mjs +31 -0
- package/dist/delete-YzRliRn8.mjs.map +1 -0
- package/dist/document-output-BVB8emLt.mjs +145 -0
- package/dist/document-output-BVB8emLt.mjs.map +1 -0
- package/dist/edit-Bb0Ze4w6.mjs +79 -0
- package/dist/edit-Bb0Ze4w6.mjs.map +1 -0
- package/dist/edit-BeFmC3XD.mjs +80 -0
- package/dist/edit-BeFmC3XD.mjs.map +1 -0
- package/dist/edit-DLDw_ZWX.mjs +86 -0
- package/dist/edit-DLDw_ZWX.mjs.map +1 -0
- package/dist/edit-z55ofr1S.mjs +40 -0
- package/dist/edit-z55ofr1S.mjs.map +1 -0
- package/dist/editor-xrF-j3UE.mjs +42 -0
- package/dist/editor-xrF-j3UE.mjs.map +1 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs +26 -0
- package/dist/envelope-overlays-DPAlMNW1.mjs.map +1 -0
- package/dist/get-2qjq0wgG.mjs +28 -0
- package/dist/get-2qjq0wgG.mjs.map +1 -0
- package/dist/get-BGAk1Zmv.mjs +14 -0
- package/dist/get-BGAk1Zmv.mjs.map +1 -0
- package/dist/get-CRR13lgj.mjs +10 -0
- package/dist/get-CRR13lgj.mjs.map +1 -0
- package/dist/get-ClkpDBTL.mjs +13 -0
- package/dist/get-ClkpDBTL.mjs.map +1 -0
- package/dist/get-DJfUJ3sP.mjs +10 -0
- package/dist/get-DJfUJ3sP.mjs.map +1 -0
- package/dist/get-DiqaQvoS.mjs +14 -0
- package/dist/get-DiqaQvoS.mjs.map +1 -0
- package/dist/index.d.mts +338 -0
- package/dist/index.mjs +10 -0
- package/dist/list-BYzhflDg.mjs +14 -0
- package/dist/list-BYzhflDg.mjs.map +1 -0
- package/dist/list-DY-tPNG-.mjs +10 -0
- package/dist/list-DY-tPNG-.mjs.map +1 -0
- package/dist/list-DlQSkbqx.mjs +10 -0
- package/dist/list-DlQSkbqx.mjs.map +1 -0
- package/dist/list-DsrA5wIz.mjs +15 -0
- package/dist/list-DsrA5wIz.mjs.map +1 -0
- package/dist/list-Fp4nKfQb.mjs +10 -0
- package/dist/list-Fp4nKfQb.mjs.map +1 -0
- package/dist/list-s_tloiEX.mjs +10 -0
- package/dist/list-s_tloiEX.mjs.map +1 -0
- package/dist/litexml-codec-CDoRloiR.mjs +13451 -0
- package/dist/litexml-codec-CDoRloiR.mjs.map +1 -0
- package/dist/login-CLOJ-fTJ.mjs +579 -0
- package/dist/login-CLOJ-fTJ.mjs.map +1 -0
- package/dist/logout-v8ihxsim.mjs +11 -0
- package/dist/logout-v8ihxsim.mjs.map +1 -0
- package/dist/onboarding-640IldLz.mjs +888 -0
- package/dist/onboarding-640IldLz.mjs.map +1 -0
- package/dist/output-BM7aBFwt.mjs +120 -0
- package/dist/output-BM7aBFwt.mjs.map +1 -0
- package/dist/output-CTnO1lYt.d.mts +16 -0
- package/dist/payload-CN11pUto.mjs +547 -0
- package/dist/payload-CN11pUto.mjs.map +1 -0
- package/dist/publish-DkTYB-eK.mjs +23 -0
- package/dist/publish-DkTYB-eK.mjs.map +1 -0
- package/dist/publish-pRBfTJfe.mjs +23 -0
- package/dist/publish-pRBfTJfe.mjs.map +1 -0
- package/dist/resolve-BogJOR7R.mjs +119 -0
- package/dist/resolve-BogJOR7R.mjs.map +1 -0
- package/dist/resolve-Bp1AfBmM.mjs +26 -0
- package/dist/resolve-Bp1AfBmM.mjs.map +1 -0
- package/dist/resolve-Bw5Po9yK.mjs +16 -0
- package/dist/resolve-Bw5Po9yK.mjs.map +1 -0
- package/dist/resolve-CyjMlaoJ.mjs +23 -0
- package/dist/resolve-CyjMlaoJ.mjs.map +1 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs +30 -0
- package/dist/resolve-helpers-CahPoJ0Y.mjs.map +1 -0
- package/dist/set-BEGQz2si.mjs +43 -0
- package/dist/set-BEGQz2si.mjs.map +1 -0
- package/dist/shared-D0HVBDHI.mjs +39 -0
- package/dist/shared-D0HVBDHI.mjs.map +1 -0
- package/dist/status-LXrN9fI-.mjs +22 -0
- package/dist/status-LXrN9fI-.mjs.map +1 -0
- package/dist/update-B9ynFCdZ.mjs +30 -0
- package/dist/update-B9ynFCdZ.mjs.map +1 -0
- package/dist/update-BMZQPOvR.mjs +28 -0
- package/dist/update-BMZQPOvR.mjs.map +1 -0
- package/dist/update-BXz0l7Lz.mjs +36 -0
- package/dist/update-BXz0l7Lz.mjs.map +1 -0
- package/dist/update-Dx6AF8tf.mjs +30 -0
- package/dist/update-Dx6AF8tf.mjs.map +1 -0
- package/dist/update-q66TLS38.mjs +37 -0
- package/dist/update-q66TLS38.mjs.map +1 -0
- package/dist/whoami-CTkctOEd.mjs +22 -0
- package/dist/whoami-CTkctOEd.mjs.map +1 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
** Mix Space Open Source License**
|
|
2
|
+
|
|
3
|
+
This project is dual-licensed under different terms for different parts of the project. It is important for users and contributors to understand the licensing terms applicable to each part of the project.
|
|
4
|
+
|
|
5
|
+
### For the `apps/` Directory
|
|
6
|
+
|
|
7
|
+
**License:** GNU Affero General Public License v3.0 (AGPLv3) with Additional Terms (ADDITIONAL_TERMS).
|
|
8
|
+
|
|
9
|
+
**Scope:** This license applies exclusively to all files within the `apps/` directory of this project.
|
|
10
|
+
|
|
11
|
+
**Summary:**
|
|
12
|
+
- The AGPLv3 is a free, copyleft license suitable for software that will be distributed over a network. It allows users to use, modify, and distribute the software and any modifications under the same terms.
|
|
13
|
+
- The "Additional Terms" (ADDITIONAL_TERMS) are specific conditions that are added to the AGPLv3 license. These terms must be reviewed in the accompanying LICENSE file or documentation to understand any additional restrictions or permissions that apply to the software.
|
|
14
|
+
|
|
15
|
+
### For Other Parts of the Project
|
|
16
|
+
|
|
17
|
+
**License:** MIT License.
|
|
18
|
+
|
|
19
|
+
**Scope:** This license applies to all parts of the project that are not included within the `apps/` directory.
|
|
20
|
+
|
|
21
|
+
**Summary:**
|
|
22
|
+
- The MIT License is a permissive open-source license that allows users considerable freedom. It permits use, copying, modification, merging, publishing, distribution, sublicensing, and/or selling copies of the software.
|
|
23
|
+
- It also protects the authors by including a limitation of liability and a disclaimer of warranty.
|
|
24
|
+
|
|
25
|
+
**General Conditions:**
|
|
26
|
+
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the above license notices and this permission notice appear in all copies of the software.
|
|
27
|
+
- The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and noninfringement.
|
|
28
|
+
|
|
29
|
+
**Contribution:**
|
|
30
|
+
- Contributions to this project are accepted under the terms of the same license as the part of the project to which the contribution is made.
|
|
31
|
+
|
|
32
|
+
**Notice:**
|
|
33
|
+
- This summary is not the license itself and is not a substitute for reading the licenses in their entirety. All users and contributors are encouraged to read the full text of the licenses for a comprehensive understanding.
|
package/README.md
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# @mx-space/cli (`mxs`)
|
|
2
|
+
|
|
3
|
+
Command-line interface for managing a deployed mx-core instance. The CLI is designed for single-owner blog operations, script automation, and AI agents that need stable read/write contracts.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
| Method | Command |
|
|
8
|
+
| ------ | ------------------------------ |
|
|
9
|
+
| pnpm | `pnpm add -g @mx-space/cli` |
|
|
10
|
+
| npm | `npm install -g @mx-space/cli` |
|
|
11
|
+
|
|
12
|
+
Node.js 22 or newer is required.
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
mxs auth login
|
|
18
|
+
mxs post create --file ./post.xml
|
|
19
|
+
mxs post update my-slug --title "New title" --state publish
|
|
20
|
+
mxs post get my-slug --output llm
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
When the CLI cannot resolve an API URL, it starts an interactive onboarding prompt in TTY contexts. Use `MXS_API_URL` or `--api-url` for non-interactive environments.
|
|
24
|
+
|
|
25
|
+
## Global Flags
|
|
26
|
+
|
|
27
|
+
| Flag | Effect |
|
|
28
|
+
| ----------------- | ----------------------------------------------------------------------------- |
|
|
29
|
+
| `--json` | Emit `{ ok: true, data }` on stdout. Takes precedence over `--output`. |
|
|
30
|
+
| `--output <mode>` | Output mode. Supported: `pretty-json`, `json`, `readable`, `llm`, `envelope`. |
|
|
31
|
+
| `--api-url <url>` | Override the configured mx-core API origin. |
|
|
32
|
+
| `--token <token>` | Override the stored access token. |
|
|
33
|
+
| `--api-key <key>` | Authenticate with an API key through the `x-api-key` header. |
|
|
34
|
+
| `--quiet`, `-q` | Suppress non-error stderr messages. |
|
|
35
|
+
| `--verbose` | Print HTTP method, URL, status, and duration to stderr. |
|
|
36
|
+
| `--dry-run` | Resolve payloads without mutating the server where supported. |
|
|
37
|
+
|
|
38
|
+
`readable`, `llm`, and `envelope` are currently document output modes for `post get`, `note get`, and `page get`. Other commands keep their existing JSON-oriented output.
|
|
39
|
+
|
|
40
|
+
## Output Modes
|
|
41
|
+
|
|
42
|
+
| Mode | Shape | Primary Use |
|
|
43
|
+
| ------------- | ------------------------------------------------ | --------------------------------------------- |
|
|
44
|
+
| `pretty-json` | Raw response payload formatted with indentation. | Human inspection and existing behavior. |
|
|
45
|
+
| `json` | `{ ok: true, data }` JSON envelope. | Scripts and structured automation. |
|
|
46
|
+
| `readable` | Compact key-value metadata plus readable body. | Human terminal reading. |
|
|
47
|
+
| `llm` | Same stable readable structure as `readable`. | AI-agent context with lower structural noise. |
|
|
48
|
+
| `envelope` | `<mxpost>` or `<mxnote>` LiteXML envelope. | Editable document round trips. |
|
|
49
|
+
|
|
50
|
+
For Lexical documents, `readable`, `llm`, and `envelope` render the body as LiteXML through `@haklex/rich-litexml` instead of exposing Lexical JSON.
|
|
51
|
+
|
|
52
|
+
Example:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
mxs post get my-slug --output llm
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
post
|
|
60
|
+
id: 123
|
|
61
|
+
title: Example
|
|
62
|
+
slug: example
|
|
63
|
+
state: published
|
|
64
|
+
category: Tech
|
|
65
|
+
tags: cli, ai
|
|
66
|
+
|
|
67
|
+
summary:
|
|
68
|
+
Short summary.
|
|
69
|
+
|
|
70
|
+
content_format: litexml
|
|
71
|
+
|
|
72
|
+
content:
|
|
73
|
+
<p>Hello world.</p>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Authentication
|
|
77
|
+
|
|
78
|
+
| Command | Description |
|
|
79
|
+
| ----------------- | ----------------------------------------------------------------------- |
|
|
80
|
+
| `mxs auth login` | Start the OIDC device authorization flow and store credentials. |
|
|
81
|
+
| `mxs auth logout` | Delete stored credentials. |
|
|
82
|
+
| `mxs auth whoami` | Show the server-validated authenticated user and resolved API URL. |
|
|
83
|
+
| `mxs auth status` | Show token presence, expiry, refresh-token availability, and user data. |
|
|
84
|
+
|
|
85
|
+
`auth login` prints the verification URL and user code. In non-JSON interactive mode, it attempts to open the complete verification URL in the browser.
|
|
86
|
+
|
|
87
|
+
The CLI refreshes credentials in two ways. If a stored OAuth `refresh_token`
|
|
88
|
+
exists, it uses the refresh-token grant. Device authorization normally stores a
|
|
89
|
+
Better Auth session token instead; for that path the CLI calls Better Auth
|
|
90
|
+
`/get-session`, accepts the refreshed `set-auth-token` header, and updates the
|
|
91
|
+
local expiry from the refreshed session.
|
|
92
|
+
|
|
93
|
+
## Posts
|
|
94
|
+
|
|
95
|
+
| Command | Description |
|
|
96
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| `mxs post list` | List posts. |
|
|
98
|
+
| `mxs post get <slugOrId>` | Read a post by Snowflake id or slug. |
|
|
99
|
+
| `mxs post create` | Create a post. |
|
|
100
|
+
| `mxs post edit <slugOrId>` | Edit a post through `$EDITOR` when no content flags are supplied; otherwise replace through flags/file. |
|
|
101
|
+
| `mxs post update <slugOrId>` | Patch selected post fields. Content is left unchanged unless `--content` or `--file` is supplied. |
|
|
102
|
+
| `mxs post delete <slugOrId>` | Delete a post. Requires `--force` in non-TTY contexts. |
|
|
103
|
+
| `mxs post publish <slugOrId>` | Set `isPublished=true`. |
|
|
104
|
+
| `mxs post unpublish <slugOrId>` | Set `isPublished=false`. |
|
|
105
|
+
|
|
106
|
+
### Post List Flags
|
|
107
|
+
|
|
108
|
+
| Flag | Effect |
|
|
109
|
+
| ----------------- | --------------------------------------------------------------- |
|
|
110
|
+
| `--page <n>` | Page number. |
|
|
111
|
+
| `--size <n>` | Page size. |
|
|
112
|
+
| `--state <state>` | Publication filter, such as `draft` or `publish`. |
|
|
113
|
+
| `--sort <field>` | Sort field passed as `sortBy`, such as `created` or `modified`. |
|
|
114
|
+
|
|
115
|
+
### Post Write Flags
|
|
116
|
+
|
|
117
|
+
| Flag | Field |
|
|
118
|
+
| ------------------------- | ---------------------------------------------------------------------- |
|
|
119
|
+
| `--title <text>` | `title` |
|
|
120
|
+
| `--slug <slug>` | `slug` |
|
|
121
|
+
| `--category <id-or-name>` | Resolved to `categoryId` by id, slug, or name. |
|
|
122
|
+
| `--content <spec>` | Body source. See content spec grammar below. |
|
|
123
|
+
| `--format <format>` | `contentFormat`; supported: `lexical`, `markdown`. Default: `lexical`. |
|
|
124
|
+
| `--summary <text>` | `summary` |
|
|
125
|
+
| `--state <state>` | `publish` or `draft`; maps to `isPublished`. |
|
|
126
|
+
| `--tags <csv>` | Comma-separated tags. |
|
|
127
|
+
| `--copyright <bool>` | `copyright`; accepts `true` or `false`. |
|
|
128
|
+
| `--pin <iso>` | Pin timestamp/date. |
|
|
129
|
+
| `--pin-order <n>` | Numeric pin order. |
|
|
130
|
+
| `--related <csv>` | Comma-separated related document ids. |
|
|
131
|
+
| `--meta <spec>` | JSON literal or `file=<path>`. |
|
|
132
|
+
| `--file <path>` | LiteXML envelope. |
|
|
133
|
+
|
|
134
|
+
## Notes
|
|
135
|
+
|
|
136
|
+
| Command | Description |
|
|
137
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
138
|
+
| `mxs note list` | List notes. |
|
|
139
|
+
| `mxs note get <slugOrId>` | Read a note by Snowflake id, numeric nid, or direct identifier. |
|
|
140
|
+
| `mxs note create` | Create a note. |
|
|
141
|
+
| `mxs note edit <slugOrId>` | Edit a note through `$EDITOR` when no content flags are supplied; otherwise replace through flags/file. |
|
|
142
|
+
| `mxs note update <slugOrId>` | Patch selected note fields. Content is left unchanged unless `--content` or `--file` is supplied. |
|
|
143
|
+
| `mxs note delete <slugOrId>` | Delete a note. Requires `--force` in non-TTY contexts. |
|
|
144
|
+
| `mxs note publish <slugOrId>` | Set `isPublished=true`. |
|
|
145
|
+
| `mxs note unpublish <slugOrId>` | Set `isPublished=false`. |
|
|
146
|
+
|
|
147
|
+
### Note List Flags
|
|
148
|
+
|
|
149
|
+
| Flag | Effect |
|
|
150
|
+
| ----------------- | ------------------------------ |
|
|
151
|
+
| `--page <n>` | Page number. |
|
|
152
|
+
| `--size <n>` | Page size. |
|
|
153
|
+
| `--state <state>` | Publication filter. |
|
|
154
|
+
| `--sort <field>` | Sort field passed as `sortBy`. |
|
|
155
|
+
|
|
156
|
+
### Note Write Flags
|
|
157
|
+
|
|
158
|
+
| Flag | Field |
|
|
159
|
+
| ---------------------- | ---------------------------------------------------------------------- |
|
|
160
|
+
| `--title <text>` | `title`; defaults to `无题` for create payloads. |
|
|
161
|
+
| `--slug <slug>` | `slug` |
|
|
162
|
+
| `--topic <id-or-name>` | Resolved to `topicId` by id, slug, or name. |
|
|
163
|
+
| `--content <spec>` | Body source. |
|
|
164
|
+
| `--format <format>` | `contentFormat`; supported: `lexical`, `markdown`. Default: `lexical`. |
|
|
165
|
+
| `--state <state>` | `publish` or `draft`; maps to `isPublished`. |
|
|
166
|
+
| `--mood <text>` | `mood` |
|
|
167
|
+
| `--weather <text>` | `weather` |
|
|
168
|
+
| `--public-at <iso>` | `publicAt` |
|
|
169
|
+
| `--password <text>` | `password` |
|
|
170
|
+
| `--bookmark <bool>` | `bookmark`; accepts `true` or `false`. |
|
|
171
|
+
| `--coords <lat,lng>` | `coordinates` |
|
|
172
|
+
| `--location <text>` | `location` |
|
|
173
|
+
| `--images <spec>` | JSON literal or `file=<path>`. |
|
|
174
|
+
| `--meta <spec>` | JSON literal or `file=<path>`. |
|
|
175
|
+
| `--file <path>` | LiteXML envelope. |
|
|
176
|
+
|
|
177
|
+
## Pages
|
|
178
|
+
|
|
179
|
+
| Command | Description |
|
|
180
|
+
| ---------------------------- | ------------------------------------------------------------------------------------------------------- |
|
|
181
|
+
| `mxs page list` | List pages. |
|
|
182
|
+
| `mxs page get <slugOrId>` | Read a page by Snowflake id or slug. |
|
|
183
|
+
| `mxs page create` | Create a page. |
|
|
184
|
+
| `mxs page edit <slugOrId>` | Edit a page through `$EDITOR` when no content flags are supplied; otherwise replace through flags/file. |
|
|
185
|
+
| `mxs page update <slugOrId>` | Patch selected page fields. Content is left unchanged unless `--content` or `--file` is supplied. |
|
|
186
|
+
| `mxs page delete <slugOrId>` | Delete a page. Requires `--force` in non-TTY contexts. |
|
|
187
|
+
|
|
188
|
+
### Page Write Flags
|
|
189
|
+
|
|
190
|
+
| Flag | Field |
|
|
191
|
+
| ------------------- | ---------------------------------------------------------------------- |
|
|
192
|
+
| `--title <text>` | `title` |
|
|
193
|
+
| `--slug <slug>` | `slug` |
|
|
194
|
+
| `--subtitle <text>` | `subtitle` |
|
|
195
|
+
| `--order <n>` | Numeric page order. |
|
|
196
|
+
| `--content <spec>` | Body source. |
|
|
197
|
+
| `--format <format>` | `contentFormat`; supported: `lexical`, `markdown`. Default: `lexical`. |
|
|
198
|
+
| `--meta <spec>` | JSON literal or `file=<path>`. |
|
|
199
|
+
| `--file <path>` | LiteXML envelope. |
|
|
200
|
+
|
|
201
|
+
Page edit and page file payloads currently reuse the `<mxpost>` envelope shape.
|
|
202
|
+
|
|
203
|
+
## Categories
|
|
204
|
+
|
|
205
|
+
| Command | Description |
|
|
206
|
+
| ------------------------------------------------- | ----------------------------------------------------------------- |
|
|
207
|
+
| `mxs category list` | List categories and tags. |
|
|
208
|
+
| `mxs category get <slugOrId>` | Read a category or tag. |
|
|
209
|
+
| `mxs category create --name <name> --slug <slug>` | Create a category or tag. |
|
|
210
|
+
| `mxs category update <slugOrId>` | Patch category or tag fields. |
|
|
211
|
+
| `mxs category delete <slugOrId>` | Delete a category or tag. Requires `--force` in non-TTY contexts. |
|
|
212
|
+
|
|
213
|
+
### Category Write Flags
|
|
214
|
+
|
|
215
|
+
| Flag | Field |
|
|
216
|
+
| --------------- | ---------------------------------------------------- |
|
|
217
|
+
| `--name <text>` | `name` |
|
|
218
|
+
| `--slug <slug>` | `slug` |
|
|
219
|
+
| `--type <type>` | `category` or `tag`; maps to server type `0` or `1`. |
|
|
220
|
+
| `--icon <text>` | `icon` |
|
|
221
|
+
|
|
222
|
+
## Topics
|
|
223
|
+
|
|
224
|
+
| Command | Description |
|
|
225
|
+
| ---------------------------------------------- | ------------------------------------------------------- |
|
|
226
|
+
| `mxs topic list` | List all topics. |
|
|
227
|
+
| `mxs topic get <slugOrId>` | Read a topic by Snowflake id or slug. |
|
|
228
|
+
| `mxs topic create --name <name> --slug <slug>` | Create a topic. |
|
|
229
|
+
| `mxs topic update <slugOrId>` | Patch topic fields. |
|
|
230
|
+
| `mxs topic delete <slugOrId>` | Delete a topic. Requires `--force` in non-TTY contexts. |
|
|
231
|
+
|
|
232
|
+
### Topic Write Flags
|
|
233
|
+
|
|
234
|
+
| Flag | Field |
|
|
235
|
+
| ---------------------- | ------------- |
|
|
236
|
+
| `--name <text>` | `name` |
|
|
237
|
+
| `--slug <slug>` | `slug` |
|
|
238
|
+
| `--description <text>` | `description` |
|
|
239
|
+
| `--icon <text>` | `icon` |
|
|
240
|
+
|
|
241
|
+
## Configuration
|
|
242
|
+
|
|
243
|
+
| Command | Description |
|
|
244
|
+
| ------------------------------ | -------------------------------------------------------------- |
|
|
245
|
+
| `mxs config list` | Read all server options from `/options`. |
|
|
246
|
+
| `mxs config get <key>` | Read one server option. |
|
|
247
|
+
| `mxs config set <key> <value>` | Patch one server option. |
|
|
248
|
+
| `mxs config edit` | Open all options in `$EDITOR`, then patch changed JSON values. |
|
|
249
|
+
|
|
250
|
+
### Config Set Flags
|
|
251
|
+
|
|
252
|
+
| Flag | Effect |
|
|
253
|
+
| --------------- | ---------------------------------------------------------------------- |
|
|
254
|
+
| `--type json` | Parse value as JSON and fail on invalid JSON. |
|
|
255
|
+
| `--type string` | Store the value as a string. |
|
|
256
|
+
| `--type number` | Parse the value as a number. |
|
|
257
|
+
| `--type bool` | Store `true` only when the value is exactly `true`; otherwise `false`. |
|
|
258
|
+
|
|
259
|
+
Without `--type`, `config set` attempts JSON parsing first and falls back to string.
|
|
260
|
+
|
|
261
|
+
## Content Sources
|
|
262
|
+
|
|
263
|
+
`--content` accepts the following grammar:
|
|
264
|
+
|
|
265
|
+
| Spec | Meaning |
|
|
266
|
+
| ---------------------------- | -------------------------------- |
|
|
267
|
+
| `--content="inline literal"` | Use the argument value directly. |
|
|
268
|
+
| `--content=file=<path>` | Read body content from a file. |
|
|
269
|
+
| `--content=-` | Read body content from stdin. |
|
|
270
|
+
| `--content=stdin` | Read body content from stdin. |
|
|
271
|
+
|
|
272
|
+
`--meta`, `--images`, and other JSON spec fields accept either an inline JSON literal or `file=<path>`.
|
|
273
|
+
|
|
274
|
+
## LiteXML Envelopes
|
|
275
|
+
|
|
276
|
+
LiteXML envelopes can carry metadata and body content in one file. Flag values override envelope metadata.
|
|
277
|
+
Use `--file -` to read an envelope from stdin.
|
|
278
|
+
|
|
279
|
+
### Post Envelope
|
|
280
|
+
|
|
281
|
+
```xml
|
|
282
|
+
<mxpost>
|
|
283
|
+
<meta>
|
|
284
|
+
<title>Title</title>
|
|
285
|
+
<slug>my-post</slug>
|
|
286
|
+
<category>tech</category>
|
|
287
|
+
<tags><tag>cli</tag><tag>ai</tag></tags>
|
|
288
|
+
<state>publish</state>
|
|
289
|
+
<summary>Summary</summary>
|
|
290
|
+
<format>lexical</format>
|
|
291
|
+
</meta>
|
|
292
|
+
<content>
|
|
293
|
+
<p>Body.</p>
|
|
294
|
+
</content>
|
|
295
|
+
</mxpost>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Note Envelope
|
|
299
|
+
|
|
300
|
+
```xml
|
|
301
|
+
<mxnote>
|
|
302
|
+
<meta>
|
|
303
|
+
<title>Daily Note</title>
|
|
304
|
+
<slug>daily-note</slug>
|
|
305
|
+
<topic>life</topic>
|
|
306
|
+
<state>draft</state>
|
|
307
|
+
<mood>calm</mood>
|
|
308
|
+
<weather>clear</weather>
|
|
309
|
+
<format>lexical</format>
|
|
310
|
+
</meta>
|
|
311
|
+
<content>
|
|
312
|
+
<p>Body.</p>
|
|
313
|
+
</content>
|
|
314
|
+
</mxnote>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
`lexical` envelope content is parsed through `@haklex/rich-litexml` and converted to Lexical JSON before writing to the server. `markdown` content is sent as-is.
|
|
318
|
+
|
|
319
|
+
## Configuration Files
|
|
320
|
+
|
|
321
|
+
| File | Mode | Purpose |
|
|
322
|
+
| -------------------------------- | ------ | --------------------------------------------------------------- |
|
|
323
|
+
| `~/.config/mxs/config.json` | `0644` | API URL, API base, auth base, API version, and client id. |
|
|
324
|
+
| `~/.config/mxs/credentials.json` | `0600` | Access token, refresh token, expiry, and optional user profile. |
|
|
325
|
+
|
|
326
|
+
`XDG_CONFIG_HOME` changes the base directory. Credentials with wider permissions are automatically changed to `0600`.
|
|
327
|
+
|
|
328
|
+
Example config:
|
|
329
|
+
|
|
330
|
+
```json
|
|
331
|
+
{
|
|
332
|
+
"api_url": "https://blog.example.com",
|
|
333
|
+
"api_base": "https://blog.example.com/api/v2",
|
|
334
|
+
"auth_base": "https://blog.example.com/api/v2/auth",
|
|
335
|
+
"api_version": 2,
|
|
336
|
+
"client_id": "mxs-cli"
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
## Environment Variables
|
|
341
|
+
|
|
342
|
+
| Variable | Meaning |
|
|
343
|
+
| ----------------- | ------------------------------------------------------------------------ |
|
|
344
|
+
| `MXS_API_URL` | API origin override. |
|
|
345
|
+
| `MXS_TOKEN` | Better Auth access token override; sent as `Authorization: Bearer`. |
|
|
346
|
+
| `MXS_API_KEY` | API key override; sent as `x-api-key`. |
|
|
347
|
+
| `MXS_DEBUG=1` | Enables verbose HTTP diagnostics in auth helpers. |
|
|
348
|
+
| `EDITOR` | Editor used by `post edit`, `note edit`, `page edit`, and `config edit`. |
|
|
349
|
+
| `XDG_CONFIG_HOME` | Base directory for `mxs` config files. |
|
|
350
|
+
|
|
351
|
+
## Exit Codes
|
|
352
|
+
|
|
353
|
+
| Code | Meaning |
|
|
354
|
+
| ---- | --------------------------------------- |
|
|
355
|
+
| `0` | Success |
|
|
356
|
+
| `1` | Generic failure |
|
|
357
|
+
| `2` | Argument parsing failure |
|
|
358
|
+
| `3` | Authentication or authorization failure |
|
|
359
|
+
| `4` | Network failure |
|
|
360
|
+
| `5` | Validation or configuration failure |
|
|
361
|
+
| `6` | Server 5xx failure |
|
|
362
|
+
| `7` | Resource not found |
|
|
363
|
+
|
|
364
|
+
## Troubleshooting
|
|
365
|
+
|
|
366
|
+
| Symptom | Resolution |
|
|
367
|
+
| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
|
|
368
|
+
| `cannot detect auth endpoint` | Verify that the URL points to a live mx-core server with device authorization enabled. Use `--verbose` to inspect probes. |
|
|
369
|
+
| `API URL is not configured` | Set `MXS_API_URL`, pass `--api-url`, or run `mxs auth login` in an interactive terminal. |
|
|
370
|
+
| `EDITOR is not set` | Set `EDITOR`, for example `EDITOR=vim`. |
|
|
371
|
+
| API key no longer works in `Authorization: Bearer` | Use `--api-key` or `MXS_API_KEY` for API keys. Bearer auth is reserved for Better Auth session/OIDC access tokens. |
|
|
372
|
+
|
|
373
|
+
## License
|
|
374
|
+
|
|
375
|
+
AGPL-3.0.
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# `@mx-space/cli` Roadmap
|
|
2
|
+
|
|
3
|
+
## v2
|
|
4
|
+
|
|
5
|
+
- AI module commands
|
|
6
|
+
- `mxs ai summary regen <id>`
|
|
7
|
+
- `mxs ai translate <id> --to <locale>`
|
|
8
|
+
- `mxs ai insights refresh`
|
|
9
|
+
- `mxs ai tokens`
|
|
10
|
+
- Comment moderation
|
|
11
|
+
- `mxs comment list`
|
|
12
|
+
- `mxs comment approve <id>`
|
|
13
|
+
- `mxs comment reject <id>`
|
|
14
|
+
- `mxs comment delete <id>`
|
|
15
|
+
- Markdown → Lexical bridge (contingent on a haklex reader)
|
|
16
|
+
|
|
17
|
+
## v3
|
|
18
|
+
|
|
19
|
+
- Maintenance
|
|
20
|
+
- `mxs cache clear [--scope=all|view|post|note|page|aggregate]`
|
|
21
|
+
- `mxs cache stats`
|
|
22
|
+
- `mxs search reindex`
|
|
23
|
+
- `mxs search status`
|
|
24
|
+
- `mxs job list`
|
|
25
|
+
- `mxs job run <name>`
|
|
26
|
+
- `mxs health`
|
|
27
|
+
- Backup
|
|
28
|
+
- `mxs backup create [--output <path>]`
|
|
29
|
+
- `mxs backup list`
|
|
30
|
+
- `mxs backup download <id> [--output <path>]`
|
|
31
|
+
- `mxs backup restore <id-or-file> [--force]`
|
|
32
|
+
- Export / import (content as files)
|
|
33
|
+
- `mxs export <dir> [--type=post,note,page] [--format=markdown|litexml]`
|
|
34
|
+
- `mxs import <dir> [--type=post] [--update-existing]`
|
|
35
|
+
- Multi-profile
|
|
36
|
+
- `mxs use <name>`
|
|
37
|
+
- `~/.config/mxs/profiles.json`
|
|
38
|
+
- Observability
|
|
39
|
+
- `mxs logs tail`
|
|
40
|
+
- `mxs metrics`
|
|
41
|
+
- OS keychain storage (keytar / libsecret) once monorepo Node version stabilizes
|
|
42
|
+
- `mxs init` — bootstrap a fresh mx-core deployment via compose
|
package/bin/mxs.cjs
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { existsSync } = require('node:fs')
|
|
3
|
+
const { join } = require('node:path')
|
|
4
|
+
const { spawnSync } = require('node:child_process')
|
|
5
|
+
|
|
6
|
+
const packageRoot = join(__dirname, '..')
|
|
7
|
+
const productionEntry = join(packageRoot, 'dist', 'bin', 'mxs.mjs')
|
|
8
|
+
const developmentEntry = join(packageRoot, 'src', 'bin', 'mxs.ts')
|
|
9
|
+
|
|
10
|
+
const args = process.argv.slice(2)
|
|
11
|
+
|
|
12
|
+
let result
|
|
13
|
+
if (existsSync(productionEntry)) {
|
|
14
|
+
result = spawnSync(process.execPath, [productionEntry, ...args], {
|
|
15
|
+
stdio: 'inherit',
|
|
16
|
+
})
|
|
17
|
+
} else if (existsSync(developmentEntry)) {
|
|
18
|
+
result = spawnSync(
|
|
19
|
+
process.execPath,
|
|
20
|
+
['--import', 'tsx', developmentEntry, ...args],
|
|
21
|
+
{
|
|
22
|
+
cwd: packageRoot,
|
|
23
|
+
stdio: 'inherit',
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
} else {
|
|
27
|
+
console.error('mxs entry not found; run `pnpm -C packages/cli run build`.')
|
|
28
|
+
process.exit(1)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (result.error) {
|
|
32
|
+
console.error(result.error.message)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (result.signal) {
|
|
37
|
+
process.exit(1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
process.exit(result.status ?? 0)
|