@seliseblocks/cli-os 0.2.11 → 0.2.12

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.
Files changed (47) hide show
  1. package/AI_USAGE_GUIDE.md +551 -560
  2. package/README.md +171 -173
  3. package/dist/commands/auth/refresh.js +21 -2
  4. package/dist/commands/mfa/generate.js +7 -4
  5. package/dist/commands/mfa/method-set.js +13 -4
  6. package/dist/commands/mfa/totp-enable.d.ts +3 -3
  7. package/dist/commands/mfa/totp-enable.js +4 -4
  8. package/dist/commands/mfa/verify.js +4 -2
  9. package/dist/commands/projects/create.js +110 -16
  10. package/dist/index.js +696 -703
  11. package/package.json +2 -2
  12. package/dist/commands/sdk/client.d.ts +0 -1
  13. package/dist/commands/sdk/client.js +0 -99
  14. package/dist/commands/skill/add.d.ts +0 -1
  15. package/dist/commands/skill/add.js +0 -19
  16. package/dist/commands/skill/list.d.ts +0 -1
  17. package/dist/commands/skill/list.js +0 -15
  18. package/dist/commands/skill/show.d.ts +0 -1
  19. package/dist/commands/skill/show.js +0 -15
  20. package/dist/lib/skills.d.ts +0 -17
  21. package/dist/lib/skills.js +0 -69
  22. package/dist/skills/blocks-data-gateway-configuration/SKILL.md +0 -204
  23. package/dist/skills/blocks-data-gateway-crud/SKILL.md +0 -223
  24. package/dist/skills/blocks-data-storage/SKILL.md +0 -253
  25. package/dist/skills/blocks-data-storage/flows/object-management.md +0 -124
  26. package/dist/skills/blocks-frontend-local-https/SKILL.md +0 -100
  27. package/dist/skills/blocks-iam-access-control/SKILL.md +0 -49
  28. package/dist/skills/blocks-iam-access-control/flows/feature-gating.md +0 -38
  29. package/dist/skills/blocks-iam-access-control/flows/manage-roles-permissions.md +0 -110
  30. package/dist/skills/blocks-iam-account/SKILL.md +0 -169
  31. package/dist/skills/blocks-iam-mfa/SKILL.md +0 -124
  32. package/dist/skills/blocks-iam-organizations/SKILL.md +0 -43
  33. package/dist/skills/blocks-iam-organizations/flows/admin-mutations.md +0 -89
  34. package/dist/skills/blocks-iam-organizations/flows/read-and-switch.md +0 -57
  35. package/dist/skills/blocks-iam-sso-oidc-configuration/SKILL.md +0 -105
  36. package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +0 -80
  37. package/dist/skills/blocks-iam-users/SKILL.md +0 -131
  38. package/dist/skills/blocks-localization-configuration/SKILL.md +0 -149
  39. package/dist/skills/blocks-localization-implementation/SKILL.md +0 -63
  40. package/dist/skills/blocks-mail/SKILL.md +0 -95
  41. package/dist/skills/blocks-notification/SKILL.md +0 -69
  42. package/dist/skills/blocks-notifier/SKILL.md +0 -107
  43. package/dist/skills/blocks-onboarding/SKILL.md +0 -77
  44. package/dist/skills/blocks-release-deployment/SKILL.md +0 -81
  45. package/dist/skills/blocks-secrets/SKILL.md +0 -81
  46. package/dist/skills/blocks-storage-configuration/SKILL.md +0 -93
  47. package/dist/skills/lint.mjs +0 -168
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seliseblocks/cli-os",
3
- "version": "0.2.11",
3
+ "version": "0.2.12",
4
4
  "description": "CLI for SELISE Blocks project setup and configuration.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -29,7 +29,7 @@
29
29
  ],
30
30
  "scripts": {
31
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",
32
+ "build": "npm run clean && tsc -p tsconfig.json",
33
33
  "dev": "tsx src/index.ts",
34
34
  "lint": "tsc -p tsconfig.json --noEmit",
35
35
  "test": "npm run build && node --test test/*.test.mjs",
@@ -1 +0,0 @@
1
- export declare function sdkClient(argv: string[]): Promise<void>;
@@ -1,99 +0,0 @@
1
- import { blocksRequest } from "../../lib/api.js";
2
- import { stringFlag } from "../../lib/args.js";
3
- import { defaults } from "../../lib/config.js";
4
- import { findProjectByTenantId } from "../../lib/project-info.js";
5
- import { writeOutput } from "../../lib/output.js";
6
- import { requestContext } from "../../lib/request-context.js";
7
- import { parseCommand, selectedProject } from "../../lib/workspace.js";
8
- // Read-only: "I want to use the Blocks SDK in my app -- show me the client."
9
- // Resolves this project's createBlocksClient() config and prints it, same
10
- // values 'new web' scaffolds with. Never writes a file and never mutates
11
- // anything -- if you want the SDK wired into a new app, use 'new web'.
12
- export async function sdkClient(argv) {
13
- const { flags } = parseCommand(argv);
14
- const tenantId = stringFlag(flags, "x-blocks-key") || (await selectedProject(flags));
15
- const apiUrl = stringFlag(flags, "blocks-api-url", { defaultValue: defaults().apiUrl });
16
- const oidcUrl = stringFlag(flags, "oidc-url", { defaultValue: defaults().oidcUrl });
17
- let appDomain = stringFlag(flags, "app-domain");
18
- let oidcClientId = stringFlag(flags, "client-id");
19
- const notes = [];
20
- if (!appDomain || !oidcClientId) {
21
- const { project } = await findProjectByTenantId(tenantId, flags);
22
- if (!appDomain) {
23
- const domains = (project.applications ?? [])
24
- .map((application) => application.domain)
25
- .filter((domain) => Boolean(domain));
26
- if (domains.length === 1) {
27
- appDomain = domains[0];
28
- }
29
- else if (domains.length > 1) {
30
- notes.push(`Multiple domains registered for this project (${domains.join(", ")}) -- pass --app-domain to pick one.`);
31
- }
32
- else {
33
- notes.push("This project has no domains registered in Blocks -- pass --app-domain explicitly.");
34
- }
35
- }
36
- if (!oidcClientId) {
37
- const clients = await listOidcClients(tenantId, flags);
38
- if (clients.length === 1) {
39
- oidcClientId = clients[0].id;
40
- }
41
- else if (clients.length > 1) {
42
- notes.push(`Multiple OIDC clients found (${clients.map((client) => `${client.label} [${client.id}]`).join(", ")}) -- pass --client-id to pick one.`);
43
- }
44
- else {
45
- notes.push("No OIDC client registered for this project -- create one ('auth:oidc-clients:save') and pass --client-id.");
46
- }
47
- }
48
- }
49
- if (flags.json) {
50
- writeOutput({ apiUrl, appDomain: appDomain || undefined, notes, oidcClientId: oidcClientId || undefined, oidcUrl, xBlocksKey: tenantId }, flags);
51
- return;
52
- }
53
- console.log("import { createBlocksClient } from \"@seliseblocks/client\";");
54
- console.log("");
55
- console.log("export const blocksClient = createBlocksClient({");
56
- console.log(` apiUrl: "${apiUrl}",`);
57
- if (appDomain)
58
- console.log(` appDomain: "${appDomain}",`);
59
- console.log(" oidc: {");
60
- console.log(` clientId: "${oidcClientId || "<register a public OIDC client, see auth:oidc-clients:save>"}",`);
61
- console.log(" scope: \"openid profile\",");
62
- console.log(` url: "${oidcUrl}"`);
63
- console.log(" },");
64
- console.log(` xBlocksKey: "${tenantId}"`);
65
- console.log("});");
66
- for (const note of notes)
67
- console.log(`\n${note}`);
68
- }
69
- async function listOidcClients(tenantId, flags) {
70
- const raw = await blocksRequest("/iam/v4/oidc-clients", {
71
- impersonatedProjectAuth: true,
72
- projectTenantId: tenantId,
73
- ...requestContext(flags)
74
- });
75
- const clients = [];
76
- for (const item of normalizeList(raw)) {
77
- if (typeof item !== "object" || item === null)
78
- continue;
79
- const record = item;
80
- const id = record.itemId ?? record.clientId ?? record.id;
81
- if (typeof id !== "string" || !id)
82
- continue;
83
- const label = typeof record.clientDisplayName === "string" && record.clientDisplayName ? record.clientDisplayName : id;
84
- clients.push({ id, label });
85
- }
86
- return clients;
87
- }
88
- function normalizeList(raw) {
89
- if (Array.isArray(raw))
90
- return raw;
91
- if (raw && typeof raw === "object") {
92
- for (const key of ["data", "items", "results"]) {
93
- const value = raw[key];
94
- if (Array.isArray(value))
95
- return value;
96
- }
97
- }
98
- return [];
99
- }
@@ -1 +0,0 @@
1
- export declare function skillAdd(argv: string[]): Promise<void>;
@@ -1,19 +0,0 @@
1
- import { cp } from "node:fs/promises";
2
- import { dirname, join } from "node:path";
3
- import { stringFlag } from "../../lib/args.js";
4
- import { readSkill } from "../../lib/skills.js";
5
- import { parseCommand } from "../../lib/workspace.js";
6
- export async function skillAdd(argv) {
7
- const { args, flags } = parseCommand(argv);
8
- const name = args[0];
9
- if (!name)
10
- throw new Error("Missing skill name. Run 'blocks skill list' to see available skills.");
11
- const skill = await readSkill(name);
12
- const sourceDir = dirname(skill.path);
13
- const targetDir = stringFlag(flags, "dir", { defaultValue: "blocks-skills" });
14
- const targetPath = join(process.cwd(), targetDir, name);
15
- // Copy the whole skill directory, not just SKILL.md -- some skills also ship
16
- // supporting files (e.g. flows/*.md) that SKILL.md links to.
17
- await cp(sourceDir, targetPath, { recursive: true });
18
- console.log(`Added ${targetPath}`);
19
- }
@@ -1 +0,0 @@
1
- export declare function skillList(argv: string[]): Promise<void>;
@@ -1,15 +0,0 @@
1
- import { listSkills, SKILLS_REPO_URL } from "../../lib/skills.js";
2
- import { writeOutput } from "../../lib/output.js";
3
- import { parseCommand } from "../../lib/workspace.js";
4
- export async function skillList(argv) {
5
- const { flags } = parseCommand(argv);
6
- const skills = await listSkills();
7
- if (flags.json) {
8
- writeOutput(skills, flags);
9
- return;
10
- }
11
- for (const skill of skills) {
12
- console.log(`${skill.name} ${skill.description}`);
13
- }
14
- console.log(`\nFull catalog (may be ahead of this bundled list): ${SKILLS_REPO_URL}`);
15
- }
@@ -1 +0,0 @@
1
- export declare function skillShow(argv: string[]): Promise<void>;
@@ -1,15 +0,0 @@
1
- import { readSkill } from "../../lib/skills.js";
2
- import { writeOutput } from "../../lib/output.js";
3
- import { parseCommand } from "../../lib/workspace.js";
4
- export async function skillShow(argv) {
5
- const { args, flags } = parseCommand(argv);
6
- const name = args[0];
7
- if (!name)
8
- throw new Error("Missing skill name. Run 'blocks skill list' to see available skills.");
9
- const skill = await readSkill(name);
10
- if (flags.json) {
11
- writeOutput(skill, flags);
12
- return;
13
- }
14
- console.log(skill.content);
15
- }
@@ -1,17 +0,0 @@
1
- export type SkillSummary = {
2
- description: string;
3
- name: string;
4
- path: string;
5
- };
6
- export type SkillDetail = SkillSummary & {
7
- content: string;
8
- };
9
- export declare const SKILLS_REPO_URL = "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-skills";
10
- export declare function resolveSkillsDir(): string;
11
- export declare function parseFrontmatter(raw: string): {
12
- body: string;
13
- description?: string;
14
- name?: string;
15
- };
16
- export declare function listSkills(): Promise<SkillSummary[]>;
17
- export declare function readSkill(name: string): Promise<SkillDetail>;
@@ -1,69 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { readdir, readFile } from "node:fs/promises";
3
- import { dirname, join } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- // Canonical public catalog -- the source of truth when the locally bundled
6
- // skills are missing a name, or out of date relative to what's published.
7
- export const SKILLS_REPO_URL = "https://github.com/SELISEdigitalplatforms/blocks-cli/tree/main/blocks-skills";
8
- // Resolves where blocks-skills/*/SKILL.md content lives, in priority order:
9
- // 1. Bundled into this package at build time (see scripts/copy-skills.mjs) --
10
- // what a published npm install actually ships.
11
- // 2. The monorepo root's blocks-skills/ folder -- covers 'npm run dev' (tsx,
12
- // no build step) and running straight from a source checkout.
13
- export function resolveSkillsDir() {
14
- const moduleDir = dirname(fileURLToPath(import.meta.url));
15
- const candidates = [join(moduleDir, "..", "skills"), join(moduleDir, "..", "..", "..", "blocks-skills")];
16
- for (const candidate of candidates) {
17
- if (existsSync(candidate))
18
- return candidate;
19
- }
20
- throw new Error("No blocks-skills content found. Expected a bundled 'skills' folder next to this package, or a 'blocks-skills' folder at the monorepo root.");
21
- }
22
- // Hand-rolled parser for this repo's flat, single-line SKILL.md frontmatter
23
- // (`name: ...` / `description: "..."`) -- no YAML dependency exists in this
24
- // package and none of these fields span multiple lines.
25
- export function parseFrontmatter(raw) {
26
- const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
27
- if (!match)
28
- return { body: raw };
29
- const [, frontmatter, body] = match;
30
- const fields = {};
31
- for (const line of frontmatter.split(/\r?\n/)) {
32
- const separator = line.indexOf(":");
33
- if (separator === -1)
34
- continue;
35
- const key = line.slice(0, separator).trim();
36
- let value = line.slice(separator + 1).trim();
37
- if (value.length >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
38
- value = value.slice(1, -1);
39
- }
40
- fields[key] = value;
41
- }
42
- return { body, description: fields.description, name: fields.name };
43
- }
44
- export async function listSkills() {
45
- const dir = resolveSkillsDir();
46
- const entries = await readdir(dir, { withFileTypes: true });
47
- const summaries = [];
48
- for (const entry of entries) {
49
- if (!entry.isDirectory())
50
- continue;
51
- const skillPath = join(dir, entry.name, "SKILL.md");
52
- if (!existsSync(skillPath))
53
- continue;
54
- const raw = await readFile(skillPath, "utf8");
55
- const { description, name } = parseFrontmatter(raw);
56
- summaries.push({ description: description ?? "", name: name ?? entry.name, path: skillPath });
57
- }
58
- return summaries.sort((a, b) => a.name.localeCompare(b.name));
59
- }
60
- export async function readSkill(name) {
61
- const skills = await listSkills();
62
- const match = skills.find((skill) => skill.name === name);
63
- if (!match) {
64
- const available = skills.map((skill) => skill.name).join(", ") || "(none found)";
65
- throw new Error(`Unknown skill '${name}'. Available skills: ${available}. If the skill you're looking for isn't listed (the bundled set may be out of date), check the full catalog at ${SKILLS_REPO_URL}.`);
66
- }
67
- const content = await readFile(match.path, "utf8");
68
- return { ...match, content };
69
- }
@@ -1,204 +0,0 @@
1
- ---
2
- name: blocks-data-gateway-configuration
3
- description: "Configure a SELISE Blocks project's data model via the blocks CLI — never raw fetch/curl against api.seliseblocks.com. Covers data-source config (data config get/create/update), schema authoring and push (data schema list/pull/push, plus granular get/fields/info commands), data-access policies (data rules pull/deploy/policy), field-level validation rules (data validation *), and reloading so changes go live (data reload, or the composed data sync). Use for defining, editing, securing, validating, or reloading a project's DATA MODEL — schema fields, access policies, and validation rules."
4
- ---
5
-
6
- # Blocks Data — Gateway Configuration
7
-
8
- The Data schema/rules model of a Blocks project is configured entirely through the `blocks` CLI now — there is no supported reason to hand-roll `fetch`/`curl` calls against `api.seliseblocks.com/data/v4` anymore. The CLI reads and writes local files under `blocks/data/` and talks to the Data service for you.
9
-
10
- **Prerequisite:** `blocks init` has been run (creates `blocks/data/schemas/` and `blocks/data/rules.json`) and a project is selected (`blocks use <tenantId>`). If either is missing, or auth state is unknown, run the blocks-onboarding skill first — it covers `auth status` probing, login, and project selection in detail; this skill assumes that's already done.
11
-
12
- ## Check the data-source configuration first
13
-
14
- Before touching schemas, confirm what database actually backs this project's Data Gateway:
15
-
16
- ```bash
17
- blocks data config get --json
18
- ```
19
-
20
- By default every Blocks project runs on **Blocks-managed storage** — most of the time this is the only data-source command you'll ever need, just to confirm it. Only reach for the mutating commands below if the user explicitly wants to point the gateway at their own external database — this is a rare, deliberate action, not a routine step:
21
-
22
- ```bash
23
- blocks data config create --connection-string "<connection string>" --database-name "<name>" --dry-run --json
24
- blocks data config create --connection-string "<connection string>" --database-name "<name>" --yes --json
25
-
26
- blocks data config update --item-id <id> --connection-string "<new connection string>" --dry-run --json
27
- blocks data config update --item-id <id> --connection-string "<new connection string>" --yes --json
28
- ```
29
-
30
- `data config update` also takes `--database-name`, `--collection-name-pattern`, and `--collection-name-editable` (boolean) — use these to rename the target database or adjust how collection names are derived/whether they're editable, on an existing configuration (`--item-id` required either way).
31
-
32
- Treat `--connection-string` as a secret: never print it back unredacted, and don't log it outside the command's own `--dry-run` preview (which redacts it).
33
-
34
- ## Probe first, ask second
35
-
36
- Don't assume the local workspace matches the cloud project. Before editing anything, find out what's actually there:
37
-
38
- ```bash
39
- blocks data schema list --json # what schemas exist in the selected project (read-only)
40
- blocks data schema pull --json # sync them into blocks/data/schemas/*.json locally
41
- blocks data rules pull --json # sync data-access policies into blocks/data/rules.json
42
- ```
43
-
44
- Pulling before editing avoids clobbering schema changes someone else made in the portal or another session.
45
-
46
- ## Workflow: define or edit a schema
47
-
48
- 1. **Pull current state** (above), so local files reflect the project.
49
- 2. **Edit** the relevant JSON file(s) under `blocks/data/schemas/` — add/rename fields, change types, add a new schema file. This is plain file editing; there's no *file-oriented* CLI subcommand for individual field edits (`data schema push` always sends the whole schema), you edit the JSON directly. (`data schema fields` exists as a raw API alternative that adds/updates fields on an existing schema without touching the local file — see "More granular Schema commands" below — but for the local-file workflow described here, just edit the JSON.)
50
- 3. **Validate locally, no API call:**
51
- ```bash
52
- blocks data validate --json
53
- ```
54
- Fix anything it flags before going further — this catches malformed schema/rules JSON before it reaches the network.
55
- 4. **Dry-run the push** to see exactly what would change (create vs. update, which schemas):
56
- ```bash
57
- blocks data schema push --dry-run --json
58
- ```
59
- 5. **Get user approval**, then push for real:
60
- ```bash
61
- blocks data schema push --yes --json
62
- ```
63
- This is mutating — it creates new schemas and updates existing ones in a single call. Never skip straight to `--yes`.
64
- 6. **Reload so it goes live.** Schema/rule edits are staged until reload succeeds — the runtime gateway doesn't see them before this:
65
- ```bash
66
- blocks data reload --dry-run --json
67
- blocks data reload --yes --json
68
- ```
69
-
70
- **Shortcut — recommended default:** steps 3–6 above (validate → schema push → rules deploy → reload) are exactly what `blocks data sync` automates behind a single confirmation:
71
-
72
- ```bash
73
- blocks data sync --dry-run --json
74
- blocks data sync --yes --json
75
- ```
76
-
77
- Reach for `data sync` first unless the user specifically wants to inspect or run one step at a time — it's also the only way to *guarantee* the reload actually happens: nothing else in this CLI calls `data reload` automatically, so a bare `schema push` (or `rules deploy`) without a following `data reload` can leave changes staged but not live. Keep the manual step-by-step above for cases where you want to push schema without touching rules, or need to stop and inspect a dry-run at an individual step.
78
-
79
- ## Workflow: data-access policies / schema security
80
-
81
- Same shape as schemas, in `blocks/data/rules.json`:
82
-
83
- ```bash
84
- blocks data rules pull --json # get current policies locally
85
- # edit blocks/data/rules.json
86
- blocks data validate --json # local-only check
87
- blocks data rules deploy --dry-run --json # preview
88
- blocks data rules deploy --yes --json # apply, after approval
89
- blocks data reload --dry-run --json # then reload so it's live
90
- blocks data reload --yes --json
91
- ```
92
-
93
- **Shortcut:** `blocks data sync --dry-run --json` then `--yes --json` runs validate → schema push → rules deploy → reload together in one confirmed step (see the schema workflow above for the full explanation) — use it instead of the manual deploy+reload above unless you need to run/inspect these steps individually.
94
-
95
- `data rules deploy` applies schema security and data-access policies together — there's no finer-grained CLI split between "field access level" and "policy rule"; both live in `rules.json`.
96
-
97
- For a single policy without touching the rest of `rules.json`, use the granular commands instead of a full pull/edit/deploy round-trip:
98
-
99
- ```bash
100
- blocks data rules policy get <schemaName> --json # read-only, all policies for one schema
101
- blocks data rules policy delete <itemId> --dry-run --json
102
- blocks data rules policy delete <itemId> --yes --json
103
- ```
104
-
105
- There's no single-policy `create`/`update` command — those go through `data rules deploy` (it POSTs new policies and PUTs existing ones from `rules.json`).
106
-
107
- ## Workflow: field-level validation rules
108
-
109
- Data validations are a separate resource from schema field types — a schema field's `type` says *what kind* of value it holds, a validation rule says *what values are acceptable*. There's no file-oriented pull/push for these yet (no `blocks/data/validations.json`); work with them directly:
110
-
111
- ```bash
112
- blocks data validation by-schema <schemaId> --json # everything for one schema
113
- blocks data validation by-schema-field <schemaId> <fieldName> --json # one field's rule
114
- blocks data validation list --schema-id <schemaId> --json # paginated browse
115
- ```
116
-
117
- Create or update a rule (upsert: omit `--item-id` to create, pass it to update). The `validations` array itself has no scalar-flag equivalent — pass it via `--body`/`--file`:
118
-
119
- ```bash
120
- blocks data validation save --schema-id <schemaId> --field-name email \
121
- --body '{"validations":[{"type":1,"value":"^[^@]+@[^@]+\\.[^@]+$","errorMessage":"Enter a valid email","isActive":true}]}' \
122
- --dry-run --json
123
- blocks data validation save --schema-id <schemaId> --field-name email \
124
- --body '{"validations":[{"type":1,"value":"^[^@]+@[^@]+\\.[^@]+$","errorMessage":"Enter a valid email","isActive":true}]}' \
125
- --yes --json
126
-
127
- blocks data validation delete <validationId> --dry-run --json
128
- blocks data validation delete <validationId> --yes --json
129
- ```
130
-
131
- The API doesn't publish named constants for the `type` enum in its schema — if the user needs a specific validation type and you're not sure of its numeric value, run `data validation by-schema-field` on a field with a known-working rule (e.g. one set up in the portal) to see the value in context, rather than guessing.
132
-
133
- ## More granular Schema commands
134
-
135
- `data schema list/pull/push` cover the everyday file-based workflow above. For one-off lookups or advanced schema metadata, these go straight to the API without touching local files:
136
-
137
- ```bash
138
- blocks data schema get <id> --json # single schema by id
139
- blocks data schema get-by-name <schemaName> --json # full field detail by collection name
140
- blocks data schema aggregation --json # schemas + access-level summary (Public/User/Custom x Read/Write/Edit/Delete)
141
- blocks data schema change-logs --json # unadapted change logs; data reload clears these
142
- blocks data schema delete <id> --dry-run --json # irreversible
143
- blocks data schema delete <id> --yes --json
144
- ```
145
-
146
- `data schema info list/save/update` and `data schema fields` are the two-step alternative to `data schema push` (metadata first, fields second) — prefer the file-based `push` workflow above for normal schema authoring; reach for these only if the user specifically wants to add fields to an existing schema without touching its full JSON file, or needs the raw `/schemas/info` metadata-only shape.
147
-
148
- ## `--dry-run` before `--yes` — always
149
-
150
- Every mutating command here (`data config create/update`, `data schema push`, `data schema delete`, `data schema fields`, `data schema info save/update`, `data rules deploy`, `data rules policy delete`, `data validation save/delete`, `data reload`) supports `--dry-run`. Run it, show the user what it says it will do, and only add `--yes` after they approve. This is not optional caution — it's the standard pattern across every `blocks` mutation, not unique to this skill.
151
-
152
- ## What this skill does NOT cover (and why)
153
-
154
- Two things the old, pre-CLI version of this skill used to handle no longer have any supported path — do not paper over the gap by inventing a command or improvising a raw API call:
155
-
156
- - **Mock/sample data cleanup.** There is no `blocks data mock*` command, and the SDK's `data.utilities.mockData()` (in `@seliseblocks/client`) is **read-only** — it inventories mock data, it does not delete it. If a user asks to "wipe the demo data" or "clean up sample records," tell them plainly: this isn't exposed in the current CLI or SDK. Check whether the OS portal (`https://os.seliseblocks.com`) has a Data-section control for it; if not, there's no way to do this today short of deleting real records through generated GraphQL mutations one at a time, which is not the same thing and should not be presented as equivalent.
157
- - **Schema export/import between projects** (e.g. cloning a dev project's data model into staging). No CLI command and no SDK method exist for this. If a user wants to copy a data model between projects, the honest answer is: not supported by current tooling. Check the OS portal for a manual option; otherwise the only fallback is manually recreating schemas in the target project's `blocks/data/schemas/` and pushing them — which is a manual reconstruction, not a real export/import, and should be described as such.
158
-
159
- Don't guess at a raw API call to work around either gap — there is no supported path today, full stop.
160
-
161
- ## The one thing that goes through the SDK, not the CLI
162
-
163
- **AI-generated regex for field validation** is real, but it lives only in `@seliseblocks/client`, not in `blocks`. There's no CLI command for it because it's a single request/response utility call better suited to being scripted inline in app code than wrapped as a terminal command:
164
-
165
- ```ts
166
- import { createBlocksClient } from "@seliseblocks/client";
167
-
168
- const blocks = createBlocksClient({
169
- apiUrl: "https://api.seliseblocks.com",
170
- xBlocksKey: "<project-tenant-id>",
171
- accessToken: () => currentAccessToken
172
- });
173
-
174
- const suggestion = await blocks.data.utilities.generateRegex({
175
- description: "a valid US phone number, digits only, 10 characters"
176
- });
177
- ```
178
-
179
- If a user wants a regex suggestion for a field, write a small one-off script using the SDK like the above rather than trying to shoehorn it into a `blocks` invocation — the CLI genuinely has no equivalent, this isn't an oversight to work around. Once you have the pattern, put it into the relevant field's validation in `blocks/data/schemas/<Schema>.json` and continue with the normal push/reload workflow above.
180
-
181
- ## Gotchas
182
-
183
- - **Reload or it didn't happen.** `data schema push` and `data rules deploy` stage changes; `data reload` is what makes them visible to the runtime gateway (and to any app querying it via `@seliseblocks/client`).
184
- - **Pull before you edit** if you're not sure local files are current — someone may have changed the schema in the portal since your last pull.
185
- - **`data validate` is local-only** — it does not confirm the push will succeed against the server, only that the JSON is well-formed. Still run `--dry-run` on the actual push/deploy/reload commands.
186
- - **Don't invent mock-data-delete or schema-export commands.** They don't exist in the CLI or the SDK today — say so, check the portal, don't fake it with unrelated calls.
187
- - **Never define platform-managed system fields** (`ItemId`, `CreatedDate`, `CreatedBy`, `LastUpdatedDate`, `LastUpdatedBy`, `Language`, `OrganizationId`, `Tags`) in your schema JSON — Blocks adds these to every entity schema automatically.
188
- - **Check `data config get` before assuming Blocks-managed storage.** Most projects use it, but don't state it as fact without checking — and never create/update a data source configuration without explicit user intent, it repoints the project at a different database.
189
- - **`data validation save` requires a `validations` array via `--body`/`--file`.** There's no flag for it — the command errors out with a clear message if it's missing, don't try to work around that by guessing a flag name.
190
-
191
- ## Example trigger prompts
192
-
193
- - "Add an `email` field to my `Customer` schema and push it."
194
- - "Pull the current schemas so I can see what's already defined."
195
- - "Validate my local schema files before I push."
196
- - "Set up a data-access policy so only admins can delete `Order` records."
197
- - "Reload the data schema, I just pushed some field changes."
198
- - "Suggest a regex for validating a postal code field."
199
- - "What database is this project actually using?" → `data config get`.
200
- - "Add a validation rule so the `phone` field only accepts digits." → `data validation save`.
201
- - "What validation rules exist on the `Order` schema?" → `data validation by-schema`.
202
- - "Delete this one data-access policy without touching the rest of my rules file." → `data rules policy delete`.
203
- - "Can you wipe the demo/sample data from my project?" → explain this isn't supported by the CLI or SDK today; point to the portal.
204
- - "Copy my dev project's schemas over to staging." → explain export/import isn't supported by current tooling; point to the portal or manual recreation.