@seliseblocks/cli-os 0.2.8 → 0.2.9
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/AI_USAGE_GUIDE.md +560 -560
- package/LICENSE +21 -21
- package/README.md +173 -173
- package/bin/run.js +2 -2
- package/dist/commands/data/rules/deploy.js +84 -9
- package/dist/commands/data/rules/pull.js +13 -7
- package/dist/commands/data/schema/get.js +31 -0
- package/dist/commands/data/schema/list.js +8 -1
- package/dist/commands/data/schema/pull.js +22 -9
- package/dist/commands/data/schema/push.js +31 -9
- package/dist/index.js +702 -692
- package/dist/lib/data-files.d.ts +14 -0
- package/dist/lib/data-files.js +91 -0
- package/dist/lib/data-response.d.ts +13 -0
- package/dist/lib/data-response.js +26 -0
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +204 -204
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +223 -223
- package/dist/skills/blocks-data-storage/SKILL.md +253 -253
- package/dist/skills/blocks-data-storage/flows/object-management.md +124 -124
- package/dist/skills/blocks-frontend-local-https/SKILL.md +100 -100
- package/dist/skills/blocks-iam-account/SKILL.md +169 -169
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +80 -80
- package/dist/skills/blocks-iam-users/SKILL.md +131 -131
- package/dist/skills/blocks-localization-configuration/SKILL.md +149 -149
- package/dist/skills/blocks-localization-implementation/SKILL.md +63 -63
- package/dist/skills/blocks-onboarding/SKILL.md +72 -72
- package/dist/skills/blocks-storage-configuration/SKILL.md +93 -93
- package/package.json +47 -47
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-localization-implementation
|
|
3
|
-
description: "Consume SELISE Blocks localization at runtime in a scaffolded frontend, entirely through the `@seliseblocks/client` SDK's `localization` namespace — never raw fetch/curl. Use for making a Blocks web app multilingual on the client: language/module discovery, loading dictionaries, the built-in `t()` lookup, and a language switcher that reloads and re-renders. Frontend consumption only — authoring/pushing translation content is the sibling skill blocks-localization-configuration."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Localization — Implementation (frontend)
|
|
7
|
-
|
|
8
|
-
Make a scaffolded Blocks web app render its UI in the user's language, using only the `localization` namespace on the SDK client — `createBlocksClient(...).localization`. No fetch, no manual query strings, no hand-rolled caching: the SDK client already does all of that.
|
|
9
|
-
|
|
10
|
-
The translations themselves (keys, modules, per-language values) are authored and pushed with the blocks-localization-configuration skill (uses `blocks localization *`). This skill only covers loading and rendering them in the app.
|
|
11
|
-
|
|
12
|
-
## The client and its cache
|
|
13
|
-
|
|
14
|
-
`localization` is a `BlocksLocalizationClient` instance created once inside `createBlocksClient()`. It holds its dictionary cache as instance state — a `Map` keyed by `` `${language}:${moduleName}` `` plus an `activeLanguage`. That cache is **only as shared as the client instance is**: the canonical scaffold creates one `blocksClient` singleton (`src/lib/blocks/client.ts`, from `createBlocksClient()`) and imports it everywhere, so every `t()` call sees every dictionary loaded anywhere in the app. If you instantiate a second `createBlocksClient()` somewhere, it gets its own empty cache — don't do that; import the one singleton.
|
|
15
|
-
|
|
16
|
-
## Public vs. authenticated methods
|
|
17
|
-
|
|
18
|
-
Every method has a matching pair — one public, one tenant/session-scoped:
|
|
19
|
-
|
|
20
|
-
| Public (no token sent) | Authenticated (sends token when configured) |
|
|
21
|
-
|---|---|
|
|
22
|
-
| `languages()` | `languagesForCurrentTenant()` |
|
|
23
|
-
| `modules()` | `modulesForCurrentTenant()` |
|
|
24
|
-
| `translations(moduleName, language)` | `cloudTranslations(moduleName, language)` |
|
|
25
|
-
| `load(language, modules[])` | `loadCloud(language, modules[])` |
|
|
26
|
-
|
|
27
|
-
- `languages()`/`modules()`/`translations()`/`load()` are explicitly public — all tenant-supported cultures and translation bundles, usable pre-login for a language picker or startup locale selection.
|
|
28
|
-
- `languagesForCurrentTenant()`/`modulesForCurrentTenant()`/`cloudTranslations()`/`loadCloud()` are scoped to whichever tenant the active `x-blocks-key` resolves to (and send the caller's access token if the client is configured with one) — use these for protected, tenant-specific dictionaries behind a signed-in session.
|
|
29
|
-
|
|
30
|
-
`keysByNames({ keyNames, moduleId? })` fetches specific key records (metadata/translations) without downloading a whole module dictionary; useful for a one-off label or an admin screen that inspects individual keys.
|
|
31
|
-
|
|
32
|
-
**Argument order matters**: `translations(moduleName, language)` and `cloudTranslations(moduleName, language)` take module first, language second — easy to transpose.
|
|
33
|
-
|
|
34
|
-
## Startup sequence
|
|
35
|
-
|
|
36
|
-
1. **List languages** on app boot (or in a query hook) — `blocksClient.localization.languagesForCurrentTenant()` (or `languages()` if you want it available pre-login). Use `isDefault`/`languageCode` from the result to build the picker and preselect a default, falling back to a persisted user choice (e.g. `localStorage`).
|
|
37
|
-
2. **Load dictionaries** for the active language — `blocksClient.localization.load(language, modules)` where `modules` is the list of bundles the app needs (e.g. `["common", "dashboard", "assets"]`). `load()` fetches each module's dictionary in parallel via `translations()` and merges them into one object, with later modules in the array overwriting earlier ones on key collision. Use `loadCloud()` instead for protected dictionaries once the user is signed in.
|
|
38
|
-
3. **Render labels** with `blocksClient.localization.t(key, fallback, { language, moduleName })`. It reads from dictionaries already loaded by `translations()`/`load()` (or their cloud equivalents) — it does not fetch anything itself. Missing key → `fallback` → the raw key, in that order.
|
|
39
|
-
4. **Switch language**: on switcher change, call `load()` (or `loadCloud()`) again with the new language and the same module list, then re-render. There's no separate "invalidate" step — loading a language populates its own cache entries; you don't need to clear the old language's entries (they just stop being read once `activeLanguage`/your app state moves on).
|
|
40
|
-
|
|
41
|
-
The canonical scaffold (`blocks new web`) wires exactly this pattern in `src/lib/i18n/LocalizationProvider.tsx`: a React context holds `language` state (seeded from `localStorage`), a `useEffect` on `language` calls `blocksClient.localization.load(language, MODULES)` and stores the merged dictionary in state, and `t(key, fallback)` reads `cloudDictionary[key] ?? defaultDictionary[key] ?? fallback ?? key` — layering the network dictionary over a build-time `defaultDictionary` (from `src/lib/i18n/dictionary.ts`, generated from the same keys as the seed JSON in `blocks/localization/*.json`) as an offline/first-paint safety net, itself falling back to the caller-supplied fallback and finally the key. Mirror this shape rather than inventing your own provider — it's already generated into new projects. Note the scaffold's own `t()` is a plain function on context, not the SDK's `localization.t()` — either is fine; the SDK's built-in `t()` needs no separate context/provider if you're happy reading `blocksClient.localization.t(...)` directly in components.
|
|
42
|
-
|
|
43
|
-
## `t()` lookup details worth knowing
|
|
44
|
-
|
|
45
|
-
- If you pass `moduleName`, `t()` does an exact `` `${language}:${moduleName}` `` cache lookup — deterministic.
|
|
46
|
-
- If you omit `moduleName`, `t()` scans all cached dictionaries and returns the first match whose cache key starts with `` `${language}:` `` (or any language if you didn't pass one). Scan order follows Map insertion order, which is the order the underlying HTTP requests *resolved* in (not necessarily the order you listed modules in `load()`) — fine when keys are unique across modules, ambiguous if two modules define the same key. Pass `moduleName` explicitly whenever you know it and key collisions across modules are possible.
|
|
47
|
-
- `t()` never throws and never fetches — call `load()`/`translations()` (or the cloud variants) first, or every lookup falls straight to `fallback`/the key.
|
|
48
|
-
|
|
49
|
-
## Gotchas
|
|
50
|
-
|
|
51
|
-
- **No raw fetch/curl, ever** — every read here goes through `blocksClient.localization.*`. The SDK already sends `x-blocks-key` and, for the authenticated variants, the caller's access token when configured.
|
|
52
|
-
- **One client, one cache** — don't call `createBlocksClient()` more than once in the app; import the scaffold's `blocksClient` singleton everywhere `t()`/`load()` is needed, or dictionaries loaded in one part of the app won't be visible in another.
|
|
53
|
-
- **`translations`/`cloudTranslations` take `(moduleName, language)`** — module first.
|
|
54
|
-
- **Dictionaries only contain string values** — the SDK strips any non-string fields from the raw response (and unwraps a `data` envelope if present) before caching, so don't expect nested objects in a loaded dictionary.
|
|
55
|
-
- **This skill doesn't author content.** Adding a new key/module or changing a translated value goes through `blocks-localization-configuration`'s `blocks localization *` commands, not this skill.
|
|
56
|
-
|
|
57
|
-
## Example trigger prompts
|
|
58
|
-
|
|
59
|
-
- "Add a language switcher and translate the UI."
|
|
60
|
-
- "Load the `common` and `dashboard` translation modules on app startup and use them to render labels."
|
|
61
|
-
- "The Assets page still has hard-coded English strings — replace them with `t()` lookups."
|
|
62
|
-
- "Show only the languages this tenant actually has configured, with the default one preselected."
|
|
63
|
-
- "I need one specific translated key without pulling down the whole module."
|
|
1
|
+
---
|
|
2
|
+
name: blocks-localization-implementation
|
|
3
|
+
description: "Consume SELISE Blocks localization at runtime in a scaffolded frontend, entirely through the `@seliseblocks/client` SDK's `localization` namespace — never raw fetch/curl. Use for making a Blocks web app multilingual on the client: language/module discovery, loading dictionaries, the built-in `t()` lookup, and a language switcher that reloads and re-renders. Frontend consumption only — authoring/pushing translation content is the sibling skill blocks-localization-configuration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks Localization — Implementation (frontend)
|
|
7
|
+
|
|
8
|
+
Make a scaffolded Blocks web app render its UI in the user's language, using only the `localization` namespace on the SDK client — `createBlocksClient(...).localization`. No fetch, no manual query strings, no hand-rolled caching: the SDK client already does all of that.
|
|
9
|
+
|
|
10
|
+
The translations themselves (keys, modules, per-language values) are authored and pushed with the blocks-localization-configuration skill (uses `blocks localization *`). This skill only covers loading and rendering them in the app.
|
|
11
|
+
|
|
12
|
+
## The client and its cache
|
|
13
|
+
|
|
14
|
+
`localization` is a `BlocksLocalizationClient` instance created once inside `createBlocksClient()`. It holds its dictionary cache as instance state — a `Map` keyed by `` `${language}:${moduleName}` `` plus an `activeLanguage`. That cache is **only as shared as the client instance is**: the canonical scaffold creates one `blocksClient` singleton (`src/lib/blocks/client.ts`, from `createBlocksClient()`) and imports it everywhere, so every `t()` call sees every dictionary loaded anywhere in the app. If you instantiate a second `createBlocksClient()` somewhere, it gets its own empty cache — don't do that; import the one singleton.
|
|
15
|
+
|
|
16
|
+
## Public vs. authenticated methods
|
|
17
|
+
|
|
18
|
+
Every method has a matching pair — one public, one tenant/session-scoped:
|
|
19
|
+
|
|
20
|
+
| Public (no token sent) | Authenticated (sends token when configured) |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `languages()` | `languagesForCurrentTenant()` |
|
|
23
|
+
| `modules()` | `modulesForCurrentTenant()` |
|
|
24
|
+
| `translations(moduleName, language)` | `cloudTranslations(moduleName, language)` |
|
|
25
|
+
| `load(language, modules[])` | `loadCloud(language, modules[])` |
|
|
26
|
+
|
|
27
|
+
- `languages()`/`modules()`/`translations()`/`load()` are explicitly public — all tenant-supported cultures and translation bundles, usable pre-login for a language picker or startup locale selection.
|
|
28
|
+
- `languagesForCurrentTenant()`/`modulesForCurrentTenant()`/`cloudTranslations()`/`loadCloud()` are scoped to whichever tenant the active `x-blocks-key` resolves to (and send the caller's access token if the client is configured with one) — use these for protected, tenant-specific dictionaries behind a signed-in session.
|
|
29
|
+
|
|
30
|
+
`keysByNames({ keyNames, moduleId? })` fetches specific key records (metadata/translations) without downloading a whole module dictionary; useful for a one-off label or an admin screen that inspects individual keys.
|
|
31
|
+
|
|
32
|
+
**Argument order matters**: `translations(moduleName, language)` and `cloudTranslations(moduleName, language)` take module first, language second — easy to transpose.
|
|
33
|
+
|
|
34
|
+
## Startup sequence
|
|
35
|
+
|
|
36
|
+
1. **List languages** on app boot (or in a query hook) — `blocksClient.localization.languagesForCurrentTenant()` (or `languages()` if you want it available pre-login). Use `isDefault`/`languageCode` from the result to build the picker and preselect a default, falling back to a persisted user choice (e.g. `localStorage`).
|
|
37
|
+
2. **Load dictionaries** for the active language — `blocksClient.localization.load(language, modules)` where `modules` is the list of bundles the app needs (e.g. `["common", "dashboard", "assets"]`). `load()` fetches each module's dictionary in parallel via `translations()` and merges them into one object, with later modules in the array overwriting earlier ones on key collision. Use `loadCloud()` instead for protected dictionaries once the user is signed in.
|
|
38
|
+
3. **Render labels** with `blocksClient.localization.t(key, fallback, { language, moduleName })`. It reads from dictionaries already loaded by `translations()`/`load()` (or their cloud equivalents) — it does not fetch anything itself. Missing key → `fallback` → the raw key, in that order.
|
|
39
|
+
4. **Switch language**: on switcher change, call `load()` (or `loadCloud()`) again with the new language and the same module list, then re-render. There's no separate "invalidate" step — loading a language populates its own cache entries; you don't need to clear the old language's entries (they just stop being read once `activeLanguage`/your app state moves on).
|
|
40
|
+
|
|
41
|
+
The canonical scaffold (`blocks new web`) wires exactly this pattern in `src/lib/i18n/LocalizationProvider.tsx`: a React context holds `language` state (seeded from `localStorage`), a `useEffect` on `language` calls `blocksClient.localization.load(language, MODULES)` and stores the merged dictionary in state, and `t(key, fallback)` reads `cloudDictionary[key] ?? defaultDictionary[key] ?? fallback ?? key` — layering the network dictionary over a build-time `defaultDictionary` (from `src/lib/i18n/dictionary.ts`, generated from the same keys as the seed JSON in `blocks/localization/*.json`) as an offline/first-paint safety net, itself falling back to the caller-supplied fallback and finally the key. Mirror this shape rather than inventing your own provider — it's already generated into new projects. Note the scaffold's own `t()` is a plain function on context, not the SDK's `localization.t()` — either is fine; the SDK's built-in `t()` needs no separate context/provider if you're happy reading `blocksClient.localization.t(...)` directly in components.
|
|
42
|
+
|
|
43
|
+
## `t()` lookup details worth knowing
|
|
44
|
+
|
|
45
|
+
- If you pass `moduleName`, `t()` does an exact `` `${language}:${moduleName}` `` cache lookup — deterministic.
|
|
46
|
+
- If you omit `moduleName`, `t()` scans all cached dictionaries and returns the first match whose cache key starts with `` `${language}:` `` (or any language if you didn't pass one). Scan order follows Map insertion order, which is the order the underlying HTTP requests *resolved* in (not necessarily the order you listed modules in `load()`) — fine when keys are unique across modules, ambiguous if two modules define the same key. Pass `moduleName` explicitly whenever you know it and key collisions across modules are possible.
|
|
47
|
+
- `t()` never throws and never fetches — call `load()`/`translations()` (or the cloud variants) first, or every lookup falls straight to `fallback`/the key.
|
|
48
|
+
|
|
49
|
+
## Gotchas
|
|
50
|
+
|
|
51
|
+
- **No raw fetch/curl, ever** — every read here goes through `blocksClient.localization.*`. The SDK already sends `x-blocks-key` and, for the authenticated variants, the caller's access token when configured.
|
|
52
|
+
- **One client, one cache** — don't call `createBlocksClient()` more than once in the app; import the scaffold's `blocksClient` singleton everywhere `t()`/`load()` is needed, or dictionaries loaded in one part of the app won't be visible in another.
|
|
53
|
+
- **`translations`/`cloudTranslations` take `(moduleName, language)`** — module first.
|
|
54
|
+
- **Dictionaries only contain string values** — the SDK strips any non-string fields from the raw response (and unwraps a `data` envelope if present) before caching, so don't expect nested objects in a loaded dictionary.
|
|
55
|
+
- **This skill doesn't author content.** Adding a new key/module or changing a translated value goes through `blocks-localization-configuration`'s `blocks localization *` commands, not this skill.
|
|
56
|
+
|
|
57
|
+
## Example trigger prompts
|
|
58
|
+
|
|
59
|
+
- "Add a language switcher and translate the UI."
|
|
60
|
+
- "Load the `common` and `dashboard` translation modules on app startup and use them to render labels."
|
|
61
|
+
- "The Assets page still has hard-coded English strings — replace them with `t()` lookups."
|
|
62
|
+
- "Show only the languages this tenant actually has configured, with the default one preselected."
|
|
63
|
+
- "I need one specific translated key without pulling down the whole module."
|
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-onboarding
|
|
1
|
+
---
|
|
2
|
+
name: blocks-onboarding
|
|
3
3
|
description: "Onboard a user into SELISE Blocks before any other Blocks skill can run, using the `blocks` CLI — never raw API calls. Detects CLI/login/project state via `blocks auth status --json`/`doctor --json`, closes install/login/project gaps, resolves the app OIDC client, scaffolds with `blocks new web`, then runs `blocks init` only inside the generated/existing app directory when local Blocks files are needed. Use for new users or `not_logged_in`/`project_not_selected`."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks — Onboarding
|
|
7
|
-
|
|
8
|
-
Every other Blocks skill assumes: the `blocks` CLI is installed, the user is logged in (`login`), and a project is selected (`use`). This skill detects which of those is missing and closes the gap. **Everything here goes through `blocks` — never a raw `fetch`/`curl` against `api.seliseblocks.com`.**
|
|
9
|
-
|
|
10
|
-
The CLI's own usage guide (bundled with the `blocks-cli` package) is the command-level ground truth (exact flags, defaults, failure codes); this skill is the conversational flow around it — what to ask, what's portal-only, and in what order.
|
|
11
|
-
|
|
12
|
-
## Probe first, ask second
|
|
13
|
-
|
|
14
|
-
Run `blocks auth status --json` and branch on the result — don't interrogate the user about state that's discoverable:
|
|
15
|
-
|
|
16
|
-
| Signal | State | Do this |
|
|
17
|
-
|---|---|---|
|
|
18
|
-
| command not found | CLI not installed | `npm install -g @seliseblocks/cli-os`, then re-probe |
|
|
19
|
-
| `accountAccessToken`/`accountRefreshToken` both `"missing"` | Never logged in | Step 1 — `login` |
|
|
20
|
-
| logged in, no project selected (check `blocks doctor --json`'s "Project selected" check) | No project selected | Step 2 — list/`use` |
|
|
21
|
-
| logged in, project selected | Ready | Confirm the project with the user — always show the full accessible-project list and which one is currently selected, never silently continue on a prior session's selection — then hand off to the skill/task that brought you here |
|
|
22
|
-
|
|
23
|
-
If anything looks broken rather than simply "not yet done" (unreadable/stale local token storage after a machine migration, Windows profile change, Keychain reset), run `blocks doctor --json` for the fuller diagnostic — it checks Node version, config/token/secret file locations, and token freshness in one pass. If storage itself is unreadable or corrupted, `blocks auth remove <account>` clears cached tokens and stored local credentials (restoring the packaged default account), then re-run `login`.
|
|
24
|
-
|
|
25
|
-
## Step 1 — Log in
|
|
26
|
-
|
|
27
|
-
The CLI authenticates itself with no setup. There is no OIDC client to register in the portal for this, no client id/secret to collect from the user, and nothing about how the CLI does it to look up, print, or report — just log in:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
blocks login
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Device-code flow: it prints a verification URL and user code, opens the browser to the verification page when possible so the user only needs to click approve, then polls until the device is authorized; stores account access and refresh tokens and auto-refreshes later. Run it yourself rather than only telling the user to run it, so you can read the printed code/URL and confirm the result right after.
|
|
34
|
-
|
|
35
|
-
Verify with `blocks auth status --json` — re-run after login rather than assuming it worked.
|
|
36
|
-
|
|
37
|
-
## Step 2 — Project
|
|
38
|
-
|
|
39
|
-
Ask **what the user wants to build** and whether they already have a project, rather than assuming:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
blocks projects list --json
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
Always show the full list of accessible projects, and if one already appears selected, say which one — never silently continue on a prior session's selection. If projects exist, confirm which one (and which environment) the user wants; never guess.
|
|
46
|
-
|
|
47
|
-
**`projects create` is currently disabled in this CLI build** (commented out pending a product decision — there is no CLI path to create a new project). If none of the listed projects fit, tell the user a new project must be created from the Blocks portal first; once they confirm it exists, re-run `blocks projects list --json` and continue from here.
|
|
48
|
-
|
|
49
|
-
Then select it:
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
blocks use <x-blocks-key>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Project (impersonation) tokens are created lazily from the account session the first time a project-scoped command needs one — never ask the user for a project token directly. If an impersonated project token later gets stuck, rejected, or expired and `blocks auth refresh --project --json` doesn't fix it, recover with:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
blocks deselect # drops the selection and its cached impersonation token
|
|
59
|
-
blocks use <x-blocks-key> # reselect the same x-blocks-key to force a fresh impersonation
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Step 3 — Local workspace + hand off
|
|
63
|
-
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks — Onboarding
|
|
7
|
+
|
|
8
|
+
Every other Blocks skill assumes: the `blocks` CLI is installed, the user is logged in (`login`), and a project is selected (`use`). This skill detects which of those is missing and closes the gap. **Everything here goes through `blocks` — never a raw `fetch`/`curl` against `api.seliseblocks.com`.**
|
|
9
|
+
|
|
10
|
+
The CLI's own usage guide (bundled with the `blocks-cli` package) is the command-level ground truth (exact flags, defaults, failure codes); this skill is the conversational flow around it — what to ask, what's portal-only, and in what order.
|
|
11
|
+
|
|
12
|
+
## Probe first, ask second
|
|
13
|
+
|
|
14
|
+
Run `blocks auth status --json` and branch on the result — don't interrogate the user about state that's discoverable:
|
|
15
|
+
|
|
16
|
+
| Signal | State | Do this |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| command not found | CLI not installed | `npm install -g @seliseblocks/cli-os`, then re-probe |
|
|
19
|
+
| `accountAccessToken`/`accountRefreshToken` both `"missing"` | Never logged in | Step 1 — `login` |
|
|
20
|
+
| logged in, no project selected (check `blocks doctor --json`'s "Project selected" check) | No project selected | Step 2 — list/`use` |
|
|
21
|
+
| logged in, project selected | Ready | Confirm the project with the user — always show the full accessible-project list and which one is currently selected, never silently continue on a prior session's selection — then hand off to the skill/task that brought you here |
|
|
22
|
+
|
|
23
|
+
If anything looks broken rather than simply "not yet done" (unreadable/stale local token storage after a machine migration, Windows profile change, Keychain reset), run `blocks doctor --json` for the fuller diagnostic — it checks Node version, config/token/secret file locations, and token freshness in one pass. If storage itself is unreadable or corrupted, `blocks auth remove <account>` clears cached tokens and stored local credentials (restoring the packaged default account), then re-run `login`.
|
|
24
|
+
|
|
25
|
+
## Step 1 — Log in
|
|
26
|
+
|
|
27
|
+
The CLI authenticates itself with no setup. There is no OIDC client to register in the portal for this, no client id/secret to collect from the user, and nothing about how the CLI does it to look up, print, or report — just log in:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
blocks login
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Device-code flow: it prints a verification URL and user code, opens the browser to the verification page when possible so the user only needs to click approve, then polls until the device is authorized; stores account access and refresh tokens and auto-refreshes later. Run it yourself rather than only telling the user to run it, so you can read the printed code/URL and confirm the result right after.
|
|
34
|
+
|
|
35
|
+
Verify with `blocks auth status --json` — re-run after login rather than assuming it worked.
|
|
36
|
+
|
|
37
|
+
## Step 2 — Project
|
|
38
|
+
|
|
39
|
+
Ask **what the user wants to build** and whether they already have a project, rather than assuming:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
blocks projects list --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Always show the full list of accessible projects, and if one already appears selected, say which one — never silently continue on a prior session's selection. If projects exist, confirm which one (and which environment) the user wants; never guess.
|
|
46
|
+
|
|
47
|
+
**`projects create` is currently disabled in this CLI build** (commented out pending a product decision — there is no CLI path to create a new project). If none of the listed projects fit, tell the user a new project must be created from the Blocks portal first; once they confirm it exists, re-run `blocks projects list --json` and continue from here.
|
|
48
|
+
|
|
49
|
+
Then select it:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
blocks use <x-blocks-key>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Project (impersonation) tokens are created lazily from the account session the first time a project-scoped command needs one — never ask the user for a project token directly. If an impersonated project token later gets stuck, rejected, or expired and `blocks auth refresh --project --json` doesn't fix it, recover with:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
blocks deselect # drops the selection and its cached impersonation token
|
|
59
|
+
blocks use <x-blocks-key> # reselect the same x-blocks-key to force a fresh impersonation
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Step 3 — Local workspace + hand off
|
|
63
|
+
|
|
64
64
|
Route to what the user actually wants. Do **not** run `blocks init` from a parent workspace before scaffolding a new app; it creates `blocks.json` and `blocks/` in the current directory. For a new frontend, scaffold first, `cd <appName>`, then run `blocks init` there only when the work needs project-local Blocks files such as data schemas or rules. For an existing app, run `blocks init` from that app's root. Safe to re-run: it never overwrites files that already exist. (`init` does not create a localization folder or any release-related file — `blocks/localization/` only appears later, lazily, the first time `blocks localization pull` writes to it, and there is no `blocks/release/*` file at all.)
|
|
65
65
|
|
|
66
66
|
- Building a frontend from scratch → resolve the app's public OIDC client first, then scaffold:
|
|
67
|
-
- `blocks auth oidc-clients list --json` — check whether a client already registered for this project fits. If none fits, create one directly (no portal visit needed): `blocks auth oidc-clients save --client-display-name <appName> --client-type public --redirect-uris https://<domain>:5173/login/callback --scope "openid profile" --require-pkce --register-as-identity-provider --auto-redirect --dry-run --json`, then re-run with `--yes` after showing the dry-run output and getting approval. `--client-type public` is required — IAM derives `tokenEndpointAuthMethod` from it, so omitting it stores a browser client as confidential. `--register-as-identity-provider` creates the linked identity provider in the same call; nothing further to run. `--auto-redirect` matters too — the scaffolded login page already navigates straight to the provider itself, so without it IAM's hosted login page shows a redundant manual "continue" click. When updating an *existing* client instead of creating one, always pass `--item-id` — the save endpoint replaces the whole client document, and the CLI fetches the current one first to merge your change into it rather than resetting the rest. See the blocks-iam-sso-oidc-configuration skill for the full decision tree and field-level gotchas.
|
|
67
|
+
- `blocks auth oidc-clients list --json` — check whether a client already registered for this project fits. If none fits, create one directly (no portal visit needed): `blocks auth oidc-clients save --client-display-name <appName> --client-type public --redirect-uris https://<domain>:5173/login/callback --scope "openid profile" --require-pkce --register-as-identity-provider --auto-redirect --dry-run --json`, then re-run with `--yes` after showing the dry-run output and getting approval. `--client-type public` is required — IAM derives `tokenEndpointAuthMethod` from it, so omitting it stores a browser client as confidential. `--register-as-identity-provider` creates the linked identity provider in the same call; nothing further to run. `--auto-redirect` matters too — the scaffolded login page already navigates straight to the provider itself, so without it IAM's hosted login page shows a redundant manual "continue" click. When updating an *existing* client instead of creating one, always pass `--item-id` — the save endpoint replaces the whole client document, and the CLI fetches the current one first to merge your change into it rather than resetting the rest. See the blocks-iam-sso-oidc-configuration skill for the full decision tree and field-level gotchas.
|
|
68
68
|
- `blocks new web <name> --x-blocks-key <tenantId> --app-domain <domain> --client-id <the-resolved-client-id>`. **Always pass `--client-id` and `--app-domain` explicitly** — omitting either drops `new web` into an interactive pick-list prompt with no non-interactive escape (not even to "skip"), which hangs a scripted/agent run with no stdin to answer it. Omit `--blocks-api-url` unless the project uses a non-default gateway; the scaffold derives it from the app domain, e.g. `https://dqrsf.slsblx.com` -> `https://blocksapi.slsblx.com`. After scaffolding, `cd <name>` before installing packages, running `blocks init`, or adding local skill files so `blocks.json` and `blocks/` stay inside the app. Once it resolves the client id, `new web` also checks the tenant's AuthController config and turns on `isOidcEnabled` if it's off — nothing further to do for login to actually work; if you're wiring an existing app instead (`blocks sdk client`, no `new web` call), check that yourself first: `blocks auth config get --json`, and if `isOidcEnabled` is `false`, `blocks auth config save --oidc-enabled --dry-run --json` then `--yes`.
|
|
69
|
-
- Defining data / CRUD / localization / release on an existing project → hand off to the matching skill; the project is already selected via `blocks use`, so its commands can proceed directly.
|
|
70
|
-
|
|
71
|
-
## Gotchas
|
|
72
|
-
|
|
73
|
-
- **Only one OIDC client matters here, and it's not the CLI's.** The CLI authenticates itself with no setup — nothing to register, nothing portal-only about `blocks login` itself, and nothing about how it does so to look up or mention. The only OIDC client involved is the scaffolded app's *public* browser client for its own end-user login (Step 3) — and that no longer requires the portal either: `blocks auth oidc-clients list`/`save` resolve or create it entirely through the CLI on the project's impersonated token. The portal remains available if the user prefers it, but it's an alternative, not a requirement. Don't tell a user they need to register anything before `blocks login` will work, and don't send them to the portal for the app's OIDC client by default.
|
|
74
|
-
- **`blocks new web` hangs a non-interactive run if `--client-id` or `--app-domain` is omitted** — it drops into an interactive pick-list (even to offer "skip") with no stdin to answer it in an agent-driven session. Always resolve both explicitly first (Step 3) rather than omitting either and hoping for a graceful default.
|
|
75
|
-
- **Never open, read, print, or expose the CLI's local storage files** (its config/token/secret files on disk) or anything inside them — client ids, root tenant id, account names, tokens. Only ever interact with them through `blocks` commands, never by inspecting the files directly. `auth status`/`doctor` only ever report token state (`missing`/`valid`/`expired`), never the value.
|
|
76
|
-
- **Known CLI error codes and fixes** (from the CLI's own error handling): `not_logged_in` → `blocks login`; `refresh_token_rejected` → `blocks login`; unreadable/stale local auth storage → `blocks auth remove <account>` then `blocks login`; `project_not_selected` → `blocks use <x-blocks-key>` (or pass `--project <tenantId>` for a single one-off command); `api_auth_failed` → `blocks auth status --json` then log in again; `impersonation_invalid_client` → not a stale-token problem, the account's OIDC client isn't registered for impersonation — check `blocks auth config get` and have an admin register it, `login`/`deselect`+`use` won't fix this one.
|
|
77
|
-
- **`--dry-run` before `--yes`** on every mutating command (`auth oidc-clients save`, `data schema push`/`data rules deploy`, `localization push`, `release deploy`) — this recurs in every skill that mutates project state.
|
|
69
|
+
- Defining data / CRUD / localization / release on an existing project → hand off to the matching skill; the project is already selected via `blocks use`, so its commands can proceed directly.
|
|
70
|
+
|
|
71
|
+
## Gotchas
|
|
72
|
+
|
|
73
|
+
- **Only one OIDC client matters here, and it's not the CLI's.** The CLI authenticates itself with no setup — nothing to register, nothing portal-only about `blocks login` itself, and nothing about how it does so to look up or mention. The only OIDC client involved is the scaffolded app's *public* browser client for its own end-user login (Step 3) — and that no longer requires the portal either: `blocks auth oidc-clients list`/`save` resolve or create it entirely through the CLI on the project's impersonated token. The portal remains available if the user prefers it, but it's an alternative, not a requirement. Don't tell a user they need to register anything before `blocks login` will work, and don't send them to the portal for the app's OIDC client by default.
|
|
74
|
+
- **`blocks new web` hangs a non-interactive run if `--client-id` or `--app-domain` is omitted** — it drops into an interactive pick-list (even to offer "skip") with no stdin to answer it in an agent-driven session. Always resolve both explicitly first (Step 3) rather than omitting either and hoping for a graceful default.
|
|
75
|
+
- **Never open, read, print, or expose the CLI's local storage files** (its config/token/secret files on disk) or anything inside them — client ids, root tenant id, account names, tokens. Only ever interact with them through `blocks` commands, never by inspecting the files directly. `auth status`/`doctor` only ever report token state (`missing`/`valid`/`expired`), never the value.
|
|
76
|
+
- **Known CLI error codes and fixes** (from the CLI's own error handling): `not_logged_in` → `blocks login`; `refresh_token_rejected` → `blocks login`; unreadable/stale local auth storage → `blocks auth remove <account>` then `blocks login`; `project_not_selected` → `blocks use <x-blocks-key>` (or pass `--project <tenantId>` for a single one-off command); `api_auth_failed` → `blocks auth status --json` then log in again; `impersonation_invalid_client` → not a stale-token problem, the account's OIDC client isn't registered for impersonation — check `blocks auth config get` and have an admin register it, `login`/`deselect`+`use` won't fix this one.
|
|
77
|
+
- **`--dry-run` before `--yes`** on every mutating command (`auth oidc-clients save`, `data schema push`/`data rules deploy`, `localization push`, `release deploy`) — this recurs in every skill that mutates project state.
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-storage-configuration
|
|
3
|
-
description: "Configure which storage provider (Azure Blob, S3-compatible object storage, or local/SFTP storage) backs a SELISE Blocks project's file object tree: named configurations with host, port, credentials, region/endpoint or connection string, and strategy, via the blocks CLI ('storage config get/list/save/delete'). CLI-only, project-scoped admin surface. Use to create, inspect, rotate, switch, or delete provider configurations; file/directory/object operations belong to blocks-data-storage."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Storage — Configuration
|
|
7
|
-
|
|
8
|
-
This skill manages the **storage configuration record itself** — which cloud provider (or local/SFTP storage) a named configuration points at, and the connection details needed to reach it. It does not upload, download, browse, share, version, move, or trash objects; those runtime concerns belong to blocks-data-storage.
|
|
9
|
-
|
|
10
|
-
**CLI-only, no SDK path.** There is no `@seliseblocks/client` method for reading or writing a storage configuration's own fields. Runtime storage calls select an existing record by `configurationName`. If the user wants to manipulate a file/directory or its access policies, hand off to blocks-data-storage.
|
|
11
|
-
|
|
12
|
-
**Prerequisite:** a project is selected (`blocks use <tenantId>`). If login/project state is unknown, run the blocks-onboarding skill first.
|
|
13
|
-
|
|
14
|
-
## Command family
|
|
15
|
-
|
|
16
|
-
All four commands require an **impersonated project token** — there is no account-token path for this surface, consistent with other project-scoped admin commands (`secrets *`, `data config *`, etc.).
|
|
17
|
-
|
|
18
|
-
| Command | Notes |
|
|
19
|
-
|---|---|
|
|
20
|
-
| `blocks storage config list` | No parameters beyond the selected project. Read-only. |
|
|
21
|
-
| `blocks storage config get <name>` | `<name>` (positional) or `--name` (required if no positional arg). Read-only. |
|
|
22
|
-
| `blocks storage config save` | Upsert — create or update a configuration. Mutating. |
|
|
23
|
-
| `blocks storage config delete <name>` | `<name>` (positional) or `--name` (required if no positional arg). Mutating. |
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
blocks storage config list --json
|
|
27
|
-
blocks storage config get Default --json
|
|
28
|
-
blocks storage config get --name Default --json
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## `storage config save` — fields
|
|
32
|
-
|
|
33
|
-
`save` builds its request body from `--body`/`--file` (a raw JSON object, spread first) merged with these convenience flags (later, so they win if both are given):
|
|
34
|
-
|
|
35
|
-
| Flag | Body field |
|
|
36
|
-
|---|---|
|
|
37
|
-
| `--name` | `name` |
|
|
38
|
-
| `--item-id` | `itemId` |
|
|
39
|
-
| `--strategy` | `storageStrategy` |
|
|
40
|
-
| `--host` | `host` |
|
|
41
|
-
| `--port` | `port` |
|
|
42
|
-
| `--region-endpoint` | `cloudStorageRegionEndPoint` |
|
|
43
|
-
| `--connection-string` | `connectionString` |
|
|
44
|
-
| `--access-key` | `accessKey` |
|
|
45
|
-
| `--secret-key` | `secretKey` |
|
|
46
|
-
| `--username` | `userName` |
|
|
47
|
-
| `--password` | `password` |
|
|
48
|
-
| `--remote-base-path` | `remoteBasePath` |
|
|
49
|
-
| `--update` (boolean) | `updateRequest` |
|
|
50
|
-
|
|
51
|
-
Unset flags are dropped (`compact`), so they never overwrite fields already present in a `--body`/`--file` payload. `save` is a create-or-update in one command, not two separate verbs — pass `--item-id` (and typically `--update`) when modifying an existing configuration, omit it to create a new one.
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
blocks storage config save --name Default --strategy AzureBlob \
|
|
55
|
-
--host mystorageaccount.blob.core.windows.net --region-endpoint eu-west-1 \
|
|
56
|
-
--access-key <key> --secret-key <secret> --dry-run --json
|
|
57
|
-
blocks storage config save --name Default --strategy AzureBlob \
|
|
58
|
-
--host mystorageaccount.blob.core.windows.net --region-endpoint eu-west-1 \
|
|
59
|
-
--access-key <key> --secret-key <secret> --yes --json
|
|
60
|
-
|
|
61
|
-
# Update an existing configuration
|
|
62
|
-
blocks storage config save --item-id <id> --update --connection-string "<new connection string>" --dry-run --json
|
|
63
|
-
blocks storage config save --item-id <id> --update --connection-string "<new connection string>" --yes --json
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## `--dry-run` before `--yes` — always
|
|
67
|
-
|
|
68
|
-
Both mutating commands (`save`, `delete`) follow the standard `blocks` mutation discipline: `--dry-run` prints what would be sent and returns without calling the API; `--yes` skips the interactive confirmation prompt and sends the request for real. Omitting both drops into an interactive "Type 'yes' to continue" prompt — not viable in a scripted/agent context, so always pass one or the other explicitly.
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
blocks storage config delete Default --dry-run --json
|
|
72
|
-
blocks storage config delete Default --yes --json
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`save`'s dry-run output redacts secret-shaped fields before printing (`accessKey`, `connectionString`, `password`, `secretKey` become `"***"`) — this redaction is **dry-run-preview only**, it does not change what's actually sent when you run with `--yes`, and it doesn't apply to `get`/`list` responses (see Gotchas).
|
|
76
|
-
|
|
77
|
-
## Gotchas
|
|
78
|
-
|
|
79
|
-
- **`get`/`list` are not redacted.** Only `save --dry-run`'s own preview output redacts `accessKey`/`connectionString`/`password`/`secretKey`. If a `get`/`list` response ever echoes credential fields back, treat that output as sensitive — don't paste it into logs, tickets, or chat verbatim.
|
|
80
|
-
- **`save` is upsert, not separate create/update commands.** Whether a call creates or updates is determined by whether `--item-id` is present, not by a different command name.
|
|
81
|
-
- **This is provider configuration, not object management.** `blocks storage config *` never touches file bytes, directory hierarchy, versions, trash, sharing, or ACLs. Those belong to **blocks-data-storage**, using a `configurationName` that a storage config already defines.
|
|
82
|
-
- **No positional-or-flag ambiguity trap:** `get`/`delete` accept the configuration name as either the first positional argument or `--name`; only one is required, not both.
|
|
83
|
-
- **Impersonated project token only.** Like `secrets *` and `data config *`, none of these four commands run against the account token — a project must be selected first (`blocks use <tenantId>`).
|
|
84
|
-
|
|
85
|
-
## Example trigger prompts
|
|
86
|
-
|
|
87
|
-
- "Set up Azure Blob storage for this project." → `storage config save --strategy AzureBlob ...`.
|
|
88
|
-
- "What storage configurations exist on this project?" → `storage config list`.
|
|
89
|
-
- "Show me the `Default` storage configuration." → `storage config get Default`.
|
|
90
|
-
- "Rotate the access key on our storage config." → `storage config save --item-id <id> --update --access-key <new key> ...`.
|
|
91
|
-
- "Switch this project to local storage." → `storage config save --strategy <local strategy value> --host ... --port ...` (confirm the exact strategy value expected by the project rather than guessing).
|
|
92
|
-
- "Delete this storage configuration, we don't use it anymore." → `storage config delete <name>`.
|
|
93
|
-
- "How do I actually upload a file once storage is configured?" → hand off to **blocks-data-storage**, not this skill.
|
|
1
|
+
---
|
|
2
|
+
name: blocks-storage-configuration
|
|
3
|
+
description: "Configure which storage provider (Azure Blob, S3-compatible object storage, or local/SFTP storage) backs a SELISE Blocks project's file object tree: named configurations with host, port, credentials, region/endpoint or connection string, and strategy, via the blocks CLI ('storage config get/list/save/delete'). CLI-only, project-scoped admin surface. Use to create, inspect, rotate, switch, or delete provider configurations; file/directory/object operations belong to blocks-data-storage."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks Storage — Configuration
|
|
7
|
+
|
|
8
|
+
This skill manages the **storage configuration record itself** — which cloud provider (or local/SFTP storage) a named configuration points at, and the connection details needed to reach it. It does not upload, download, browse, share, version, move, or trash objects; those runtime concerns belong to blocks-data-storage.
|
|
9
|
+
|
|
10
|
+
**CLI-only, no SDK path.** There is no `@seliseblocks/client` method for reading or writing a storage configuration's own fields. Runtime storage calls select an existing record by `configurationName`. If the user wants to manipulate a file/directory or its access policies, hand off to blocks-data-storage.
|
|
11
|
+
|
|
12
|
+
**Prerequisite:** a project is selected (`blocks use <tenantId>`). If login/project state is unknown, run the blocks-onboarding skill first.
|
|
13
|
+
|
|
14
|
+
## Command family
|
|
15
|
+
|
|
16
|
+
All four commands require an **impersonated project token** — there is no account-token path for this surface, consistent with other project-scoped admin commands (`secrets *`, `data config *`, etc.).
|
|
17
|
+
|
|
18
|
+
| Command | Notes |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `blocks storage config list` | No parameters beyond the selected project. Read-only. |
|
|
21
|
+
| `blocks storage config get <name>` | `<name>` (positional) or `--name` (required if no positional arg). Read-only. |
|
|
22
|
+
| `blocks storage config save` | Upsert — create or update a configuration. Mutating. |
|
|
23
|
+
| `blocks storage config delete <name>` | `<name>` (positional) or `--name` (required if no positional arg). Mutating. |
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
blocks storage config list --json
|
|
27
|
+
blocks storage config get Default --json
|
|
28
|
+
blocks storage config get --name Default --json
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## `storage config save` — fields
|
|
32
|
+
|
|
33
|
+
`save` builds its request body from `--body`/`--file` (a raw JSON object, spread first) merged with these convenience flags (later, so they win if both are given):
|
|
34
|
+
|
|
35
|
+
| Flag | Body field |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `--name` | `name` |
|
|
38
|
+
| `--item-id` | `itemId` |
|
|
39
|
+
| `--strategy` | `storageStrategy` |
|
|
40
|
+
| `--host` | `host` |
|
|
41
|
+
| `--port` | `port` |
|
|
42
|
+
| `--region-endpoint` | `cloudStorageRegionEndPoint` |
|
|
43
|
+
| `--connection-string` | `connectionString` |
|
|
44
|
+
| `--access-key` | `accessKey` |
|
|
45
|
+
| `--secret-key` | `secretKey` |
|
|
46
|
+
| `--username` | `userName` |
|
|
47
|
+
| `--password` | `password` |
|
|
48
|
+
| `--remote-base-path` | `remoteBasePath` |
|
|
49
|
+
| `--update` (boolean) | `updateRequest` |
|
|
50
|
+
|
|
51
|
+
Unset flags are dropped (`compact`), so they never overwrite fields already present in a `--body`/`--file` payload. `save` is a create-or-update in one command, not two separate verbs — pass `--item-id` (and typically `--update`) when modifying an existing configuration, omit it to create a new one.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
blocks storage config save --name Default --strategy AzureBlob \
|
|
55
|
+
--host mystorageaccount.blob.core.windows.net --region-endpoint eu-west-1 \
|
|
56
|
+
--access-key <key> --secret-key <secret> --dry-run --json
|
|
57
|
+
blocks storage config save --name Default --strategy AzureBlob \
|
|
58
|
+
--host mystorageaccount.blob.core.windows.net --region-endpoint eu-west-1 \
|
|
59
|
+
--access-key <key> --secret-key <secret> --yes --json
|
|
60
|
+
|
|
61
|
+
# Update an existing configuration
|
|
62
|
+
blocks storage config save --item-id <id> --update --connection-string "<new connection string>" --dry-run --json
|
|
63
|
+
blocks storage config save --item-id <id> --update --connection-string "<new connection string>" --yes --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## `--dry-run` before `--yes` — always
|
|
67
|
+
|
|
68
|
+
Both mutating commands (`save`, `delete`) follow the standard `blocks` mutation discipline: `--dry-run` prints what would be sent and returns without calling the API; `--yes` skips the interactive confirmation prompt and sends the request for real. Omitting both drops into an interactive "Type 'yes' to continue" prompt — not viable in a scripted/agent context, so always pass one or the other explicitly.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
blocks storage config delete Default --dry-run --json
|
|
72
|
+
blocks storage config delete Default --yes --json
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`save`'s dry-run output redacts secret-shaped fields before printing (`accessKey`, `connectionString`, `password`, `secretKey` become `"***"`) — this redaction is **dry-run-preview only**, it does not change what's actually sent when you run with `--yes`, and it doesn't apply to `get`/`list` responses (see Gotchas).
|
|
76
|
+
|
|
77
|
+
## Gotchas
|
|
78
|
+
|
|
79
|
+
- **`get`/`list` are not redacted.** Only `save --dry-run`'s own preview output redacts `accessKey`/`connectionString`/`password`/`secretKey`. If a `get`/`list` response ever echoes credential fields back, treat that output as sensitive — don't paste it into logs, tickets, or chat verbatim.
|
|
80
|
+
- **`save` is upsert, not separate create/update commands.** Whether a call creates or updates is determined by whether `--item-id` is present, not by a different command name.
|
|
81
|
+
- **This is provider configuration, not object management.** `blocks storage config *` never touches file bytes, directory hierarchy, versions, trash, sharing, or ACLs. Those belong to **blocks-data-storage**, using a `configurationName` that a storage config already defines.
|
|
82
|
+
- **No positional-or-flag ambiguity trap:** `get`/`delete` accept the configuration name as either the first positional argument or `--name`; only one is required, not both.
|
|
83
|
+
- **Impersonated project token only.** Like `secrets *` and `data config *`, none of these four commands run against the account token — a project must be selected first (`blocks use <tenantId>`).
|
|
84
|
+
|
|
85
|
+
## Example trigger prompts
|
|
86
|
+
|
|
87
|
+
- "Set up Azure Blob storage for this project." → `storage config save --strategy AzureBlob ...`.
|
|
88
|
+
- "What storage configurations exist on this project?" → `storage config list`.
|
|
89
|
+
- "Show me the `Default` storage configuration." → `storage config get Default`.
|
|
90
|
+
- "Rotate the access key on our storage config." → `storage config save --item-id <id> --update --access-key <new key> ...`.
|
|
91
|
+
- "Switch this project to local storage." → `storage config save --strategy <local strategy value> --host ... --port ...` (confirm the exact strategy value expected by the project rather than guessing).
|
|
92
|
+
- "Delete this storage configuration, we don't use it anymore." → `storage config delete <name>`.
|
|
93
|
+
- "How do I actually upload a file once storage is configured?" → hand off to **blocks-data-storage**, not this skill.
|
package/package.json
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@seliseblocks/cli-os",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "CLI for SELISE Blocks project setup and configuration.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"blocks": "bin/run.js"
|
|
9
|
-
},
|
|
10
|
-
"main": "./dist/index.js",
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"exports": {
|
|
13
|
-
".": {
|
|
14
|
-
"types": "./dist/index.d.ts",
|
|
15
|
-
"import": "./dist/index.js"
|
|
16
|
-
},
|
|
17
|
-
"./package.json": "./package.json"
|
|
18
|
-
},
|
|
19
|
-
"publishConfig": {
|
|
20
|
-
"access": "public"
|
|
21
|
-
},
|
|
22
|
-
"sideEffects": false,
|
|
23
|
-
"files": [
|
|
24
|
-
"bin",
|
|
25
|
-
"dist",
|
|
26
|
-
"README.md",
|
|
27
|
-
"AI_USAGE_GUIDE.md",
|
|
28
|
-
"LICENSE"
|
|
29
|
-
],
|
|
30
|
-
"scripts": {
|
|
31
|
-
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
32
|
-
"build": "npm run clean && tsc -p tsconfig.json && node scripts/copy-skills.mjs",
|
|
33
|
-
"dev": "tsx src/index.ts",
|
|
34
|
-
"lint": "tsc -p tsconfig.json --noEmit",
|
|
35
|
-
"test": "npm run build && node --test test/*.test.mjs",
|
|
36
|
-
"prepack": "npm run build",
|
|
37
|
-
"prepublishOnly": "npm test"
|
|
38
|
-
},
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@types/node": "^22.0.0",
|
|
41
|
-
"tsx": "^4.16.0",
|
|
42
|
-
"typescript": "^5.5.0"
|
|
43
|
-
},
|
|
44
|
-
"engines": {
|
|
45
|
-
"node": ">=20"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@seliseblocks/cli-os",
|
|
3
|
+
"version": "0.2.9",
|
|
4
|
+
"description": "CLI for SELISE Blocks project setup and configuration.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"blocks": "bin/run.js"
|
|
9
|
+
},
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"files": [
|
|
24
|
+
"bin",
|
|
25
|
+
"dist",
|
|
26
|
+
"README.md",
|
|
27
|
+
"AI_USAGE_GUIDE.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
32
|
+
"build": "npm run clean && tsc -p tsconfig.json && node scripts/copy-skills.mjs",
|
|
33
|
+
"dev": "tsx src/index.ts",
|
|
34
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
35
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
36
|
+
"prepack": "npm run build",
|
|
37
|
+
"prepublishOnly": "npm test"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^22.0.0",
|
|
41
|
+
"tsx": "^4.16.0",
|
|
42
|
+
"typescript": "^5.5.0"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=20"
|
|
46
|
+
}
|
|
47
|
+
}
|