@botlr/cli 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @botlr/cli
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Prop types from the dashboard's schema, and a warning when the code and the dashboard disagree about the props.
8
+
9
+ - `pull` writes `<name>.props.ts` next to the manifest: `export interface <ExportName>Props { ... }` generated from the section definition's props schema as the dashboard stores it (`definition.schema` in the pull response), in both the field DSL and the older FormBuilder format. `required: true` makes a property non-optional; a `select` with plain or `{ value }` options becomes a union of literals; asset and reference types become `string | Record<string, unknown>`; types the CLI does not know become `unknown`. The file carries a "generated, do not edit" header and is left alone when its text is unchanged. `--no-types` on a pull, or `"types": false` in `botlr.config.json`, turns it off.
10
+ - `push` and `sections status` warn when the manifest has a `schema` object (the props the code expects, field DSL only) and its keys differ from the definition's schema on the server: props the code expects that the dashboard does not define, and props the dashboard defines that the code does not list. The warning only reports; the dashboard owns the schema. The manifest's `schema` is otherwise a seed for `push --create`.
11
+ - `sections init` fills `schema` from the zod object a component's `XDefinition.schema` points at when it can read it (field names, a best-effort type, `required` unless optional or defaulted); otherwise it leaves `schema` out.
12
+ - `@botlr/sdk`: `SectionManifest.schema`, the `SectionSchemaField`, `SectionFieldSchema`, `SectionFormBuilderNode`, `SectionFormBuilderSchema` and `SectionSchema` types, and the `isFieldSchema` / `isFormBuilderSchema` guards. `SectionDefinition.schema` is typed as `SectionSchema | Record<string, unknown>`.
13
+
14
+ - Pull writes manifests in a fixed key order and keeps the section registry up to date.
15
+
16
+ - `<name>.botlr.json` is always written as 2-space JSON with `section`, `framework`, `entry`, `exportName`, `files`, `title`, `description`, `category`, `icon`, `dependencies`, then unknown keys alphabetically (`dependencies` lists `npm` before `internal`, nested objects sorted). The server stores manifests as jsonb, which forgets key order, so a pull right after a push no longer shows up as a change in git. A pull also leaves the manifest file alone when it already holds the same data.
17
+ - After a pull, when `publisher-section-registry.ts` (or the file named by the new `registryFile` config key, relative to `sectionsDir`) exists, the CLI adds `import { <exportName> } from "./<entry>";` after the last import and `"<name>": <exportName>,` as the last registry entry, keeping existing entries and formatting. Already-registered sections leave the file untouched; `--no-registry` skips the step; a missing registry prints a one-line notice.
18
+ - `sections init` reads the registry from `registryFile` too.
19
+ - The lock stays one entry per section name per app (documented; `--dir` shares it). `pulledAt` is now kept when the same scope, version and hash land again, so re-pulling does not rewrite the lock.
20
+
21
+ ### Patch Changes
22
+
23
+ - Updated dependencies
24
+ - @botlr/sdk@0.4.0
25
+
3
26
  ## 0.1.2
4
27
 
5
28
  ### Patch Changes
package/README.md CHANGED
@@ -17,10 +17,17 @@ pnpm add -D @botlr/cli
17
17
  "baseUrl": "https://api.botlr.io",
18
18
  "appId": "00000000-0000-0000-0000-000000000000",
19
19
  "framework": "react-next",
20
- "sectionsDir": "components/sections"
20
+ "sectionsDir": "components/sections",
21
+ "registryFile": "publisher-section-registry.ts",
22
+ "types": true
21
23
  }
22
24
  ```
23
25
 
26
+ `registryFile` is optional and relative to `sectionsDir`; it names the
27
+ component registry `pull` keeps up to date and `sections init` reads.
28
+ `types` (default true) makes `pull` write `<name>.props.ts` from the
29
+ definition's props schema; `false` turns it off for the app.
30
+
24
31
  Environment: `BOTLR_API_KEY` (site token, for pull/list/status) and
25
32
  `BOTLR_PAT` (personal access token with `write:sections`, for push).
26
33
  `BOTLR_BASE_URL`, `BOTLR_APP_ID`, `BOTLR_FRAMEWORK` and `BOTLR_SECTIONS_DIR`
@@ -29,7 +36,7 @@ override the file; `--framework` and `--dir` override both.
29
36
  ## Commands
30
37
 
31
38
  ```
32
- botlr pull <name...> | --all [--framework react-next] [--dir components/sections] [--version N] [--shared] [--force]
39
+ botlr pull <name...> | --all [--framework react-next] [--dir components/sections] [--version N] [--shared] [--force] [--no-registry] [--no-types]
33
40
  botlr push <name> [-m msg] [--shared] [--create] [--force]
34
41
  botlr sections list
35
42
  botlr sections status [name...] [--offline]
@@ -39,16 +46,112 @@ botlr sections init [--force] [--dry-run]
39
46
  - `pull` writes every file of the section under `sectionsDir`, plus
40
47
  `<name>.botlr.json` (the manifest, never holding version or hash) and the
41
48
  lock entry in `.botlr/sections.lock.json`. A section whose local files
42
- changed since the last pull is skipped unless `--force`.
49
+ changed since the last pull is skipped unless `--force`. When the registry
50
+ file exists, `pull` also adds `import { <exportName> } from "./<entry>";`
51
+ and `"<name>": <exportName>,` to it, keeping what is there; a section that
52
+ is already registered leaves the file untouched, and `--no-registry` skips
53
+ this step. Without a registry file the pull prints a one-line notice.
54
+ A pull also writes `<name>.props.ts` from the definition's props schema
55
+ (see "Prop types" below) unless `--no-types` or `"types": false`.
43
56
  - `push` reads the manifest and its files, hashes them, and pushes with
44
57
  `baseVersion` from the lock so a stale checkout gets a conflict instead of
45
58
  overwriting someone's version. `--force` omits `baseVersion`. `--create`
46
- adds the section definition when the dashboard does not know it yet.
59
+ adds the section definition when the dashboard does not know it yet,
60
+ seeded with the manifest's `schema` when it has one. After the push the
61
+ CLI warns when the manifest's `schema` and the definition's schema list
62
+ different props (see "Schema drift" below).
47
63
  - `sections status` compares the local content hash with the lock and the
48
64
  server's latest: `clean`, `modified`, `behind`, `diverged`, or
49
- `untracked` for a manifest with no lock entry.
65
+ `untracked` for a manifest with no lock entry. For manifests that carry a
66
+ `schema`, it also fetches the definition and prints the drift warning
67
+ (not with `--offline`).
50
68
  - `sections init` derives first manifests from a satellite app's
51
69
  `publisher-section-registry.ts` and the `XDefinition` exports next to each
52
- component. Review them, then `botlr push <name> --create` per section.
70
+ component. When the definition's `schema` points at a `z.object({...})`
71
+ in the same file, the manifest gets a `schema` with the field names and a
72
+ best-effort type (`z.string()` → `text`, `z.number()` → `number`,
73
+ `z.boolean()` → `boolean`, `z.enum([...])` → `select` with options,
74
+ `z.array(...)` → `array`, `z.object`/`z.record` → `json`,
75
+ `z.union([z.string(), z.any()])` → `asset`; `required` unless
76
+ `.optional()`, `.nullable()` or `.default(...)`). Fields it cannot read are
77
+ left out, and so is `schema` when nothing could be read. Review them, then
78
+ `botlr push <name> --create` per section.
79
+
80
+ ## Prop types
81
+
82
+ The dashboard owns a section definition's props schema. `pull` turns it
83
+ into TypeScript so a component does not have to repeat it in zod:
84
+
85
+ ```ts
86
+ // components/sections/hero.props.ts (generated, do not edit)
87
+ export interface HeroProps {
88
+ /** Heading */
89
+ heading: string;
90
+ subheading?: string;
91
+ alignment?: "left" | "center" | "right";
92
+ image?: string | Record<string, unknown>;
93
+ }
94
+ ```
95
+
96
+ The interface is named after the manifest's `exportName` (else a
97
+ PascalCase of the slug) plus `Props`. Field types map as follows: text,
98
+ textarea, markdown, richtext, string, email, tel, url, icon, color, date,
99
+ datetime → `string`; number, integer, currency → `number`; boolean →
100
+ `boolean`; select → a union of the option values (`options` as plain values
101
+ or `{ value }` objects), else `string`, and an array of that with
102
+ `multiple`; multiselect, tags → `string[]`; array, list, repeater →
103
+ `unknown[]`; json, jsonb, object → `Record<string, unknown>`; asset,
104
+ asset-picker-*, media, document, page, reference, relation,
105
+ entity_reference, app_instance, forum_thread → `string | Record<string,
106
+ unknown>`; anything else → `unknown`. `required: true` makes the property
107
+ non-optional. The older FormBuilder format (`{ nodes: [...] }`) is walked
108
+ the same way, with groups flattened and repeater items typed from their
109
+ `fields`. A definition without fields yields `Record<string, unknown>`. The
110
+ file is rewritten only when its text changes. Import the type in the
111
+ component:
112
+
113
+ ```ts
114
+ import type { HeroProps } from "./hero.props";
115
+ export function Hero(props: HeroProps) { ... }
116
+ ```
117
+
118
+ ## Schema drift
119
+
120
+ A manifest may carry a `schema` object in the field DSL (the same shape the
121
+ dashboard stores): the props the code expects. The CLI never writes it to
122
+ the server's definition except as the seed for `push --create`. On `push`
123
+ and `sections status` it compares that object's keys with the definition's
124
+ schema and warns:
125
+
126
+ ```
127
+ warning: props schema of 'hero' differs between the code and the dashboard
128
+ the code expects props the dashboard does not define: ctaLink
129
+ the dashboard defines props the code does not list: image
130
+ the dashboard owns the schema: edit it there, or update 'schema' in hero.botlr.json
131
+ ```
132
+
133
+ The warning changes nothing; fix the schema in the dashboard, pull to
134
+ refresh `<name>.props.ts`, and update the manifest's `schema` (or drop it)
135
+ when the code catches up.
136
+
137
+ ## Manifest format
138
+
139
+ The CLI always writes `<name>.botlr.json` the same way: 2-space JSON with
140
+ the keys `section`, `framework`, `entry`, `exportName`, `files`, `title`,
141
+ `description`, `category`, `icon`, `dependencies`, `schema` in that order,
142
+ then any other keys alphabetically; inside `dependencies`, `npm` before `internal`,
143
+ with package names sorted. The server stores manifests as jsonb and does not
144
+ keep key order, so this normalization is what makes a pull right after a
145
+ push produce no diff. A pull leaves a manifest file alone when the local
146
+ file already says the same thing, whatever its formatting.
147
+
148
+ ## The lock file
149
+
150
+ `.botlr/sections.lock.json` has one entry per section name for the whole
151
+ app, next to `botlr.config.json`. It is not keyed by directory: `--dir`
152
+ points a command at another sections directory but records into the same
153
+ lock, so a section name means one thing per app. `pulledAt` is when the
154
+ recorded version first landed locally; pulling the same version again keeps
155
+ it, so a no-op pull does not touch the lock file either.
53
156
 
54
157
  Commit the manifests and the lock file; keep `BOTLR_PAT` out of the repo.