@localess/cli 3.0.0-dev.20260313114825 → 3.0.0-dev.20260323211059
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/README.md +13 -0
- package/SKILL.md +363 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -249,6 +249,19 @@ const content = await client.getContentBySlug<Page>('home', { locale: 'en' });
|
|
|
249
249
|
|
|
250
250
|
---
|
|
251
251
|
|
|
252
|
+
## AI Coding Agents
|
|
253
|
+
|
|
254
|
+
This package ships a [`SKILL.md`](./SKILL.md) file that provides AI coding agents (GitHub Copilot, Claude Code, Cursor, and others) with accurate, up-to-date APIs, patterns, and best practices. Most agents automatically read `SKILL.md` when starting a session.
|
|
255
|
+
|
|
256
|
+
When you change the public API of this package, update `SKILL.md` alongside your code:
|
|
257
|
+
|
|
258
|
+
- **New option or parameter** → add it to the relevant options table and usage example
|
|
259
|
+
- **Changed behaviour** → update the description and any affected code snippets
|
|
260
|
+
- **Deprecated API** → mark it clearly and point to the replacement
|
|
261
|
+
- **New command or subcommand** → add a full entry with all flags and examples
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
252
265
|
## License
|
|
253
266
|
|
|
254
267
|
[MIT](../../LICENSE)
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
# SKILL: @localess/cli
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@localess/cli` is the **command-line interface** for the Localess headless CMS platform. It enables:
|
|
6
|
+
|
|
7
|
+
- Authenticating with a Localess instance
|
|
8
|
+
- Pushing and pulling translations (flat JSON; nested format supported for pull only)
|
|
9
|
+
- Generating TypeScript type definitions from the OpenAPI schema
|
|
10
|
+
|
|
11
|
+
**Status:** Early development (v3.0.0). Requires Node.js >= 20.0.0.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @localess/cli
|
|
19
|
+
# or use npx
|
|
20
|
+
npx @localess/cli [command]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Authentication
|
|
26
|
+
|
|
27
|
+
### Login
|
|
28
|
+
|
|
29
|
+
Authenticate and persist credentials locally. Interactive prompts fill in any missing options.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
localess login \
|
|
33
|
+
--origin https://my-localess.web.app \
|
|
34
|
+
--space YOUR_SPACE_ID \
|
|
35
|
+
--token YOUR_API_TOKEN
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Options:**
|
|
39
|
+
|
|
40
|
+
| Flag | Description |
|
|
41
|
+
|------------------------|---------------------------------|
|
|
42
|
+
| `-o, --origin <url>` | Localess instance URL |
|
|
43
|
+
| `-s, --space <id>` | Space ID (from Space settings) |
|
|
44
|
+
| `-t, --token <token>` | API token (masked input prompt) |
|
|
45
|
+
|
|
46
|
+
**Behavior:**
|
|
47
|
+
1. Checks for existing credentials (env vars or file)
|
|
48
|
+
2. Prompts interactively for any missing options
|
|
49
|
+
3. Validates credentials by calling the API
|
|
50
|
+
4. Saves credentials to `.localess/credentials.json` (mode `0o600`)
|
|
51
|
+
|
|
52
|
+
### Logout
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
localess logout
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Clears `.localess/credentials.json` (writes `{}`)
|
|
59
|
+
- If authenticated via environment variables, instructs you to unset them manually
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Credential Storage
|
|
64
|
+
|
|
65
|
+
Credentials are resolved in this priority order:
|
|
66
|
+
|
|
67
|
+
1. **Environment variables** (highest priority)
|
|
68
|
+
2. **`.localess/credentials.json`** (file-based)
|
|
69
|
+
|
|
70
|
+
### Environment Variables
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
export LOCALESS_ORIGIN=https://my-localess.web.app
|
|
74
|
+
export LOCALESS_SPACE=YOUR_SPACE_ID
|
|
75
|
+
export LOCALESS_TOKEN=YOUR_API_TOKEN
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Recommended for **CI/CD pipelines** — no `localess login` step needed.
|
|
79
|
+
|
|
80
|
+
### File-based Credentials
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
// .localess/credentials.json
|
|
84
|
+
{
|
|
85
|
+
"origin": "https://my-localess.web.app",
|
|
86
|
+
"space": "YOUR_SPACE_ID",
|
|
87
|
+
"token": "YOUR_API_TOKEN"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> **Add `.localess/credentials.json` to your `.gitignore`** to avoid committing secrets.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Translations
|
|
96
|
+
|
|
97
|
+
### Push Translations
|
|
98
|
+
|
|
99
|
+
Upload a local JSON translation file to Localess.
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
localess translations push <locale> --path <file> [options]
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**Arguments:**
|
|
106
|
+
|
|
107
|
+
| Argument | Description |
|
|
108
|
+
|------------|-------------------------------------|
|
|
109
|
+
| `<locale>` | ISO 639-1 locale code: `en`, `de`… |
|
|
110
|
+
|
|
111
|
+
**Options:**
|
|
112
|
+
|
|
113
|
+
| Flag | Default | Description |
|
|
114
|
+
|-------------------------|-----------------|-------------------------------------------------------|
|
|
115
|
+
| `-p, --path <path>` | required | Path to the translations JSON file |
|
|
116
|
+
| `-f, --format <format>` | `flat` | File format: `flat` only (**nested not yet implemented**) |
|
|
117
|
+
| `-t, --type <type>` | `add-missing` | Update strategy: `add-missing` or `update-existing` |
|
|
118
|
+
| `--dry-run` | `false` | Preview changes without applying them |
|
|
119
|
+
|
|
120
|
+
**Update Strategies:**
|
|
121
|
+
|
|
122
|
+
| Strategy | Behaviour |
|
|
123
|
+
|--------------------|------------------------------------------------------------|
|
|
124
|
+
| `add-missing` | Only adds keys that don't yet exist in Localess |
|
|
125
|
+
| `update-existing` | Only updates keys that already exist in Localess |
|
|
126
|
+
|
|
127
|
+
**File Formats:**
|
|
128
|
+
|
|
129
|
+
*Flat (default — only supported format for push):*
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"common.submit": "Submit",
|
|
133
|
+
"nav.home": "Home",
|
|
134
|
+
"errors.required": "This field is required"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **⚠️ Nested format is not yet implemented for push.** Passing `--format nested` logs an error and exits without uploading. Use `flat` format only.
|
|
139
|
+
|
|
140
|
+
**Examples:**
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Basic push — add missing translations only
|
|
144
|
+
localess translations push en --path ./locales/en.json
|
|
145
|
+
|
|
146
|
+
# Update existing translations (don't add new)
|
|
147
|
+
localess translations push de --path ./locales/de.json --type update-existing
|
|
148
|
+
|
|
149
|
+
# Preview changes without applying
|
|
150
|
+
localess translations push fr --path ./locales/fr.json --dry-run
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### Pull Translations
|
|
156
|
+
|
|
157
|
+
Download translations from Localess to a local JSON file.
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
localess translations pull <locale> --path <file> [options]
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Arguments:**
|
|
164
|
+
|
|
165
|
+
| Argument | Description |
|
|
166
|
+
|------------|-------------------------------------|
|
|
167
|
+
| `<locale>` | ISO 639-1 locale code: `en`, `de`… |
|
|
168
|
+
|
|
169
|
+
**Options:**
|
|
170
|
+
|
|
171
|
+
| Flag | Default | Description |
|
|
172
|
+
|-------------------------|-----------|--------------------------------------|
|
|
173
|
+
| `-p, --path <path>` | required | Output file path |
|
|
174
|
+
| `-f, --format <format>` | `flat` | File format: `flat` or `nested` |
|
|
175
|
+
|
|
176
|
+
**Examples:**
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Pull as flat JSON
|
|
180
|
+
localess translations pull en --path ./locales/en.json
|
|
181
|
+
|
|
182
|
+
# Pull as nested JSON
|
|
183
|
+
localess translations pull de --path ./locales/de.json --format nested
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Type Generation
|
|
189
|
+
|
|
190
|
+
Generate TypeScript type definitions from your Localess space's OpenAPI schema.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
localess types generate [--path <output>]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Options:**
|
|
197
|
+
|
|
198
|
+
| Flag | Default | Description |
|
|
199
|
+
|---------------------|-------------------------------|-------------------------------|
|
|
200
|
+
| `-p, --path <path>` | `.localess/localess.d.ts` | Output file path |
|
|
201
|
+
|
|
202
|
+
> **Prerequisite:** The API token must have the **Development Tools** permission in Localess Space settings.
|
|
203
|
+
|
|
204
|
+
**What it does:**
|
|
205
|
+
1. Fetches the OpenAPI 3.0 spec from your space
|
|
206
|
+
2. Extracts schema components
|
|
207
|
+
3. Generates TypeScript `.d.ts` definitions with `openapi-typescript`
|
|
208
|
+
|
|
209
|
+
**Examples:**
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Default output to .localess/localess.d.ts
|
|
213
|
+
localess types generate
|
|
214
|
+
|
|
215
|
+
# Custom output path
|
|
216
|
+
localess types generate --path src/types/localess.d.ts
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Generated output:**
|
|
220
|
+
|
|
221
|
+
```typescript
|
|
222
|
+
// .localess/localess.d.ts (auto-generated — do not edit)
|
|
223
|
+
export type Page = {
|
|
224
|
+
_id: string;
|
|
225
|
+
_schema: string;
|
|
226
|
+
title: string;
|
|
227
|
+
body: (HeroSection | CardGrid | RichTextBlock)[];
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export type HeroSection = {
|
|
231
|
+
_id: string;
|
|
232
|
+
_schema: string;
|
|
233
|
+
headline: string;
|
|
234
|
+
subheadline?: string;
|
|
235
|
+
image?: ContentAsset;
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// ... all schemas from your Localess space
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
**Using generated types:**
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
import type { Page, HeroSection } from './.localess/localess';
|
|
245
|
+
import { getLocalessClient } from "@localess/react";
|
|
246
|
+
|
|
247
|
+
const client = getLocalessClient();
|
|
248
|
+
const content = await client.getContentBySlug<Page>('home');
|
|
249
|
+
// content.data is fully typed as Page
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## CI/CD Integration
|
|
255
|
+
|
|
256
|
+
### GitHub Actions Example
|
|
257
|
+
|
|
258
|
+
```yaml
|
|
259
|
+
# .github/workflows/sync-translations.yml
|
|
260
|
+
name: Sync translations
|
|
261
|
+
|
|
262
|
+
on:
|
|
263
|
+
push:
|
|
264
|
+
paths:
|
|
265
|
+
- 'locales/**'
|
|
266
|
+
|
|
267
|
+
jobs:
|
|
268
|
+
push-translations:
|
|
269
|
+
runs-on: ubuntu-latest
|
|
270
|
+
steps:
|
|
271
|
+
- uses: actions/checkout@v4
|
|
272
|
+
- uses: actions/setup-node@v4
|
|
273
|
+
with:
|
|
274
|
+
node-version: '20'
|
|
275
|
+
- run: npm install -g @localess/cli
|
|
276
|
+
- run: localess translations push en --path ./locales/en.json
|
|
277
|
+
env:
|
|
278
|
+
LOCALESS_ORIGIN: ${{ secrets.LOCALESS_ORIGIN }}
|
|
279
|
+
LOCALESS_SPACE: ${{ secrets.LOCALESS_SPACE_ID }}
|
|
280
|
+
LOCALESS_TOKEN: ${{ secrets.LOCALESS_TOKEN }}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Pull Translations in CI
|
|
284
|
+
|
|
285
|
+
```yaml
|
|
286
|
+
- run: localess translations pull en --path ./locales/en.json
|
|
287
|
+
env:
|
|
288
|
+
LOCALESS_ORIGIN: ${{ secrets.LOCALESS_ORIGIN }}
|
|
289
|
+
LOCALESS_SPACE: ${{ secrets.LOCALESS_SPACE_ID }}
|
|
290
|
+
LOCALESS_TOKEN: ${{ secrets.LOCALESS_TOKEN }}
|
|
291
|
+
- run: git diff --exit-code locales/ || (git commit -am "chore: sync translations" && git push)
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### Generate Types in CI
|
|
295
|
+
|
|
296
|
+
```yaml
|
|
297
|
+
- run: localess types generate --path src/types/localess.d.ts
|
|
298
|
+
env:
|
|
299
|
+
LOCALESS_ORIGIN: ${{ secrets.LOCALESS_ORIGIN }}
|
|
300
|
+
LOCALESS_SPACE: ${{ secrets.LOCALESS_SPACE_ID }}
|
|
301
|
+
LOCALESS_TOKEN: ${{ secrets.LOCALESS_TOKEN }}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Local Development Workflow
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# 1. Authenticate once
|
|
310
|
+
localess login
|
|
311
|
+
|
|
312
|
+
# 2. Pull latest translations
|
|
313
|
+
localess translations pull en --path ./locales/en.json
|
|
314
|
+
|
|
315
|
+
# 3. Edit translations locally...
|
|
316
|
+
|
|
317
|
+
# 4. Push back (dry-run first)
|
|
318
|
+
localess translations push en --path ./locales/en.json --dry-run
|
|
319
|
+
localess translations push en --path ./locales/en.json
|
|
320
|
+
|
|
321
|
+
# 5. Generate types after schema changes in Localess
|
|
322
|
+
localess types generate
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
---
|
|
326
|
+
|
|
327
|
+
## .gitignore Recommendations
|
|
328
|
+
|
|
329
|
+
```gitignore
|
|
330
|
+
# Localess credentials (contains API token)
|
|
331
|
+
.localess/credentials.json
|
|
332
|
+
|
|
333
|
+
# Generated types are typically committed to the repo
|
|
334
|
+
# but can be excluded if auto-generated in CI:
|
|
335
|
+
# .localess/localess.d.ts
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Files Written by the CLI
|
|
341
|
+
|
|
342
|
+
| File | Created by | Permissions | Purpose |
|
|
343
|
+
|-------------------------------|-----------------------------|----------------|--------------------------------|
|
|
344
|
+
| `.localess/credentials.json` | `localess login` | `0o600` (owner only) | Persisted auth credentials |
|
|
345
|
+
| `.localess/localess.d.ts` | `localess types generate` | Standard | Generated TypeScript types |
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Best Practices
|
|
350
|
+
|
|
351
|
+
1. **Use environment variables in CI/CD** — set `LOCALESS_ORIGIN`, `LOCALESS_SPACE`, `LOCALESS_TOKEN` as secrets. No `login` command needed.
|
|
352
|
+
|
|
353
|
+
2. **Always dry-run before pushing translations** in automated scripts: add `--dry-run` first, inspect the output, then run without it.
|
|
354
|
+
|
|
355
|
+
3. **Commit generated types** (`.localess/localess.d.ts`) to your repo so the whole team benefits from type safety without running the CLI.
|
|
356
|
+
|
|
357
|
+
4. **Re-run `types generate` after any schema change** in the Localess CMS to keep types in sync.
|
|
358
|
+
|
|
359
|
+
5. **Use `add-missing` strategy (default)** for initial import of translations; switch to `update-existing` when syncing copy changes.
|
|
360
|
+
|
|
361
|
+
6. **Never commit `.localess/credentials.json`** — add it to `.gitignore` immediately after `localess login`.
|
|
362
|
+
|
|
363
|
+
7. **Give the token minimum required permissions** — the `types generate` command needs "Development Tools" permission; other commands only need standard API access.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localess/cli",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.20260323211059",
|
|
4
4
|
"description": "Localess Command Line.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"localess",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"homepage": "https://github.com/Lessify/localess-js",
|
|
14
14
|
"sideEffects": false,
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"SKILL.md"
|
|
17
18
|
],
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|