@dboio/cli 0.10.1 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,7 +20,7 @@ This installs the `dbo` command globally on your system.
20
20
  ### From the repository (local development)
21
21
 
22
22
  ```bash
23
- cd tools/dbo-cli
23
+ cd tools/cli
24
24
  npm install
25
25
  npm link
26
26
  ```
@@ -108,7 +108,7 @@ dbo login
108
108
  dbo status
109
109
 
110
110
  # 4. Query some data
111
- dbo output -e user --format json --maxrows 5
111
+ dbo output -e user --template json_indented --maxrows 5
112
112
 
113
113
  # 5. Deploy a CSS file
114
114
  dbo content deploy albain3dwkofbhnd1qtd1q assets/css/colors.css
@@ -124,28 +124,38 @@ When you run `dbo init --scaffold` or `dbo clone`, the following standard direct
124
124
  my-project/
125
125
  ├── .dbo/ # Config, synchronization and session info for dbo cli commands
126
126
  ├── .claude/ # Claude Code plugin config (commands, specs, plans, skills)
127
- ├── node_modules/ # Automatically created; contains all external libraries
127
+ ├── lib/ # All DBO server-managed assets
128
+ │ ├── bins/ # Assets (contents, outputs, images, HTML, CSS)
129
+ │ │ └── app/ # Default application bin
130
+ │ ├── automation/ # Automation entity records
131
+ │ ├── app_version/ # App version entity records
132
+ │ ├── entity/ # Entity definitions
133
+ │ ├── entity_column/ # Column definitions
134
+ │ ├── entity_column_value/ # Column value definitions
135
+ │ ├── extension/ # Extension entity records (organized by descriptor type)
136
+ │ │ ├── widget/
137
+ │ │ ├── documentation/
138
+ │ │ └── _unsupported/
139
+ │ ├── integration/ # Integration entity records
140
+ │ ├── security/ # Security policy records
141
+ │ ├── security_column/ # Column-level security records
142
+ │ ├── data_source/ # (created when data sources exist)
143
+ │ ├── group/ # (created when groups exist)
144
+ │ ├── site/ # (created when sites exist)
145
+ │ └── redirect/ # (created when redirects exist)
128
146
  ├── src/ # Your actual source code (sass, typescript, etc.)
129
- ├── tests/ # Project-level tests
130
- ├── bins/ # Assets (contents, outputs, images, HTML, CSS)
147
+ ├── test/ # Project-level tests
131
148
  ├── trash/ # Staged soft-deleted files from dbo rm
132
- ├── automation/ # Automation entity records
133
- ├── app_version/ # App version entity records
134
- ├── data_source/ # Data source entity records
135
149
  ├── docs/ # Project documentation and docs entities
136
- ├── extension/ # Extension entity records
137
- ├── <DescriptorType>/ # Sub-directory per descriptor type (e.g., component/, form/)
138
- │ └── _unsupported/ # Extensions with unrecognized descriptor types
139
- ├── group/ # Group entity records
140
- ├── integration/ # Integration entity records
141
- ├── site/ # Site entity records
150
+ ├── app.json # Clone of original app JSON with @references
151
+ ├── manifest.json # PWA web app manifest (auto-generated from app metadata)
142
152
  ├── .gitignore # Tells Git to ignore files in the repo sync
143
153
  ├── .dboignore # Tells dbo cli to ignore files in commands
144
154
  ├── package.json # Metadata, scripts, and dependency list
145
155
  └── package-lock.json # Records exact versions of dependencies installed
146
156
  ```
147
157
 
148
- > **Breaking change from pre-0.9.1**: Directory names have changed from mixed-case (`Extensions/`, `App Versions/`, `bins/`) to lowercase snake_case (`extension/`, `app_version/`, `bins/`). If you have an existing project, rename your directories manually before running `dbo clone` again.
158
+ > **Breaking change in 0.11.1**: All server-managed directories (`bins/`, `extension/`, `automation/`, etc.) have moved into a `lib/` subdirectory. Existing projects are migrated **automatically** on the first `dbo` command after upgrade. Also, `tests/` has been renamed to `test/`.
149
159
 
150
160
  ---
151
161
 
@@ -163,18 +173,34 @@ All configuration is **directory-scoped**. Each project folder maintains its own
163
173
  | File | Purpose | Git |
164
174
  |------|---------|-----|
165
175
  | `config.json` | Domain, app metadata, placement preferences | Committable (shared) |
166
- | `config.local.json` | Per-user settings: plugin scopes, future user prefs | Gitignored (per-user) |
176
+ | `config.local.json` | Per-user settings: plugin scopes, `_completedMigrations` (system-managed) | Gitignored (per-user) |
167
177
  | `ticketing.local.json` | Stored ticket IDs for submission error recovery | Gitignored (per-user) |
168
178
  | `credentials.json` | Username, user ID, UID, name, email (no password) | Gitignored (per-user) |
169
179
  | `cookies.txt` | Session cookie (Netscape format) | Gitignored (per-user) |
170
180
  | `structure.json` | Bin directory mapping (created by `dbo clone`) | Committable (shared) |
171
181
  | `metadata_templates.json` | Column templates per entity/descriptor (auto-generated by `dbo clone`) | Committable (shared) |
172
- | `.app_baseline.json` | App JSON baseline for delta detection (auto-generated by `dbo clone`) | Gitignored (per-machine) |
182
+ | `synchronize.json` | Pending deletions and sync state (updated by `dbo rm` and `dbo push`) | Committable (shared) |
183
+ | `.app_baseline.json` | Server-state snapshot for delta detection — stores column values at last clone/push so `dbo push` can detect which columns changed locally. Read-only (chmod 444); auto-migrated from legacy root `.app.json`. | Committable (shared) |
173
184
 
174
185
  `dbo init` automatically adds `.dbo/credentials.json`, `.dbo/cookies.txt`, `.dbo/config.local.json`, and `.dbo/ticketing.local.json` to `.gitignore` (creates the file if it doesn't exist).
175
186
 
176
187
  > **Upgrading from pre-0.9.9**: The baseline file `.app.json` in the project root has moved to `.dbo/.app_baseline.json`. Running any `dbo` command will auto-migrate the file. You can also manually remove the `.app.json` entry from your `.gitignore`.
177
188
 
189
+ > **Upgrading from pre-0.11.0**: `TransactionKeyPreset` now applies only to records that carry a `UID` column (core assets). Data records without a UID are always submitted with `RowID` regardless of the preset. Migration 001 runs automatically on first command after upgrade and logs a one-time notice.
190
+
191
+ #### Automatic migrations
192
+
193
+ When the CLI version is upgraded, one-time migration scripts in `tools/cli/src/migrations/` run automatically on the first command invocation in a project directory. Completed migration IDs are recorded in `.dbo/config.local.json` under `_completedMigrations` (per-user, gitignored) so each developer runs them independently and they never re-fire.
194
+
195
+ To skip migrations for a single command run:
196
+
197
+ ```bash
198
+ dbo push bins/ --no-migrate
199
+ dbo clone --app myapp --no-migrate
200
+ ```
201
+
202
+ Use `dbo status` to see how many pending migrations exist.
203
+
178
204
  #### config.json reference
179
205
 
180
206
  ```json
@@ -185,8 +211,7 @@ All configuration is **directory-scoped**. Each project folder maintains its own
185
211
  "AppName": "My App",
186
212
  "AppShortName": "myapp",
187
213
  "cloneSource": "default",
188
- "ContentPlacement": "bin",
189
- "MediaPlacement": "fullpath"
214
+ "ContentPlacement": "bin"
190
215
  }
191
216
  ```
192
217
 
@@ -198,24 +223,39 @@ All configuration is **directory-scoped**. Each project folder maintains its own
198
223
  | `AppName` | string | App display name |
199
224
  | `AppShortName` | string | App short name (used for `dbo clone --app`) |
200
225
  | `AppModifyKey` | string | ModifyKey for locked/production apps (set by `dbo clone`, used for submission guards) |
201
- | `TransactionKeyPreset` | `RowUID` \| `RowID` | Row key type for auto-assembled expressions (set during `dbo init`/`dbo clone`, default `RowUID`) |
202
- | `TicketSuggestionOutput` | string | Output UID for fetching ticket suggestions during error recovery (set during `dbo init`, default `ojaie9t3o0kfvliahnuuda`) |
226
+ | `TransactionKeyPreset` | `RowUID` \| `RowID` | Row key type (auto-set to `RowUID` during init/clone) |
227
+ | `TicketSuggestionOutput` | string | Output UID for ticket suggestions (auto-set during init, default `ojaie9t3o0kfvliahnuuda`) |
203
228
  | `cloneSource` | `"default"` \| file path \| URL | Where the last `dbo clone` fetched app JSON from. `"default"` = server fetch via `AppShortName`; any other value = the explicit local file path or URL used. Set automatically after each successful clone. |
204
- | `ContentPlacement` | `bin` \| `path` \| `ask` | Where to place content files during clone |
205
- | `MediaPlacement` | `bin` \| `fullpath` \| `ask` | Where to place media files during clone |
229
+ | `ContentPlacement` | `bin` \| `path` | Where to place content files during clone (default: `bin`) |
206
230
  | `<Entity>FilenameCol` | column name | Filename column for entity-dir records (e.g., `ExtensionFilenameCol`) |
207
231
 
208
- **Placement values:**
209
- - `bin` — Place files in the BinID-mapped directory (from `structure.json`)
210
- - `path` / `fullpath` — Place files in the Path/FullPath directory from the record
211
- - `ask` — Prompt for each file that has both a BinID and a Path/FullPath
232
+ **File placement:** All content, media, and output files are placed by BinID into the `lib/bins/` directory structure. Records without a BinID go into `lib/bins/` root. Media always uses BinID — no FullPath option. Bins with `Name=null` (legacy) map directly to `lib/bins/` root.
233
+
234
+ ### Root-level project files
212
235
 
213
- These are set interactively on first clone and saved for future use. Pre-set them in `config.json` to skip the prompt entirely.
236
+ #### `app.json`
237
+
238
+ Clone of the original app JSON from the server with entity entries replaced by `@path/to/*.metadata.json` references. Created by `dbo init` (empty `{}`) and populated by `dbo clone`. Committed to git.
214
239
 
215
240
  #### `app.json._domain`
216
241
 
217
242
  The `_domain` field in `app.json` stores the project's reference domain (set during `dbo clone`). This is committed to git and used for domain-change detection when running `dbo init --force` or `dbo clone --domain`. It provides a stable cross-user baseline — all collaborators share the same reference domain.
218
243
 
244
+ #### `manifest.json`
245
+
246
+ A [PWA web app manifest](https://developer.mozilla.org/en-US/docs/Web/Manifest) auto-generated during scaffolding (`dbo init` or `dbo clone`). Values are derived from `app.json` when available:
247
+
248
+ | Field | Source |
249
+ |-------|--------|
250
+ | `name` | `<AppName> \| <domain>` |
251
+ | `short_name` | `AppShortName` |
252
+ | `description` | `App.Description` |
253
+ | `start_url` / `scope` | `/app/<ShortName>/ui/` |
254
+ | `background_color` | Extracted from the `widget` extension matching the app's `ShortName` (field `String4`), defaults to `#ffffff` |
255
+ | `theme_color` | `#000000` |
256
+
257
+ The file is only created if absent — it is never overwritten by subsequent clones, so local edits (icons, screenshots, display overrides) are preserved. A companion `manifest.metadata.json` is auto-created by `dbo push` if missing, allowing the manifest to be pushed to the server as a content record.
258
+
219
259
  ### `.dboignore`
220
260
 
221
261
  A gitignore-style file in the project root that controls which files and directories are excluded from CLI operations. Created automatically by `dbo init` with sensible defaults.
@@ -251,7 +291,6 @@ bins/
251
291
  .dbo/ # DBO internal
252
292
  *.dboio.json # Export files
253
293
  app.json # Clone output
254
- dbo.deploy.json # Deployment manifest
255
294
  .git/ # Version control
256
295
  .gitignore
257
296
  node_modules/ # Node
@@ -259,7 +298,10 @@ package.json
259
298
  package-lock.json
260
299
  .claude/ # AI / tooling
261
300
  .mcp.json
262
- .idea/ # Editor / IDE
301
+ .DS_Store # Editor / IDE / OS
302
+ Thumbs.db
303
+ Icon\r
304
+ .idea/
263
305
  .vscode/
264
306
  *.codekit3
265
307
  README.md # Repo scaffolding
@@ -310,7 +352,6 @@ dbo init --scaffold --yes # scaffold dirs non-intera
310
352
  | `--local` | Install Claude commands to project (`.claude/commands/`) |
311
353
  | `--scaffold` | Pre-create standard project directories (`app_version`, `automation`, `bins`, `data_source`, `docs`, `extension`, `group`, `integration`, `site`, `src`, `tests`, `trash`) |
312
354
  | `--dboignore` | Create `.dboignore` with default patterns (use with `--force` to overwrite existing) |
313
- | `--media-placement <placement>` | Set media placement when cloning: `fullpath` or `binpath` (default: `bin`) |
314
355
  | `-y, --yes` | Skip all interactive prompts (legacy migration, Claude Code setup) |
315
356
  | `--non-interactive` | Alias for `--yes` |
316
357
 
@@ -347,7 +388,6 @@ dbo clone -e extension --descriptor-types false # Clone extensions flat (no de
347
388
  | `-e, --entity <type>` | Only clone a specific entity type (e.g. `output`, `content`, `media`, `extension`) |
348
389
  | `--documentation-only` | When used with `-e extension`, clone only documentation extensions |
349
390
  | `--descriptor-types <bool>` | Sort extensions into descriptor sub-directories (default: `true`). Set to `false` to use flat `extension/` layout |
350
- | `--media-placement <placement>` | Set media placement: `fullpath` or `binpath` (default: `bin`). Skips interactive media placement prompt |
351
391
  | `--domain <host>` | Override domain. Triggers a domain-change confirmation prompt when it differs from the project reference domain |
352
392
  | `--force` | Skip source mismatch confirmation and change detection; re-processes all files |
353
393
  | `-y, --yes` | Auto-accept all prompts (also skips source mismatch confirmation) |
@@ -367,7 +407,7 @@ The project's reference domain is stored in `app.json._domain` (committed to git
367
407
  4. **Creates directories** — processes `children.bin` to build the directory hierarchy based on `ParentBinID` relationships
368
408
  5. **Saves `.dbo/structure.json`** — maps BinIDs to directory paths for file placement
369
409
  6. **Writes content files** — decodes base64 content, creates `*.metadata.json` + content files in the correct bin directory. When a record's `Extension` field is empty, prompts you to choose from `css`, `js`, `html`, `xml`, `txt`, `md`, `cs`, `json`, `sql` (or skip to keep no extension). The chosen extension is saved back into the `metadata.json` `Extension` field
370
- 7. **Downloads media files** — fetches binary files (images, CSS, fonts) from the server via `/api/media/{uid}` and saves with metadata
410
+ 7. **Downloads media files** — fetches binary files (images, CSS, fonts) from the server using a fallback chain: `FullPath` directly (`/media/{app}/{path}`) → `/dir/` route → `/api/media/{uid}`, and saves with metadata. Errors are logged to `.dbo/errors.log`
371
411
  8. **Processes entity-dir records** — entities matching project directories (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) are saved as `.metadata.json` files in their corresponding directory (e.g., `extension/`, `data_source/`)
372
412
  9. **Processes other entities** — remaining entities with a `BinID` are placed in the corresponding bin directory
373
413
  10. **Saves `app.json`** — clone of the original JSON with processed entries replaced by `@path/to/*.metadata.json` references
@@ -526,54 +566,72 @@ project/
526
566
  MySQL-Primary.metadata.json
527
567
  site/
528
568
  MainSite.metadata.json
529
- media/operator/app/... # FullPath placement (when MediaPlacement=fullpath)
569
+ # Media files placed by BinID into bins/ (alongside content)
530
570
  ```
531
571
 
532
- #### Understanding the `bins/` directory structure
572
+ #### Understanding the `lib/bins/` directory structure
533
573
 
534
- The `bins/` directory is the default location for all bin-placed content files during clone. It organizes files according to your app's bin hierarchy from DBO.io.
574
+ The `lib/bins/` directory is the default location for all bin-placed content files during clone. It organizes files according to your app's bin hierarchy from DBO.io.
535
575
 
536
576
  **Directory Organization:**
537
577
 
538
- - **`bins/`** — Root directory for all bin-placed files (local organizational directory only)
539
- - **`bins/app/`** — Special subdirectory for the main app bin (typically the default bin)
540
- - **`bins/custom_name/`** — Custom bin directories (e.g., `tpl/`, `ticket_test/`, etc.)
578
+ - **`lib/bins/`** — Root directory for all bin-placed files (local organizational directory only)
579
+ - **`lib/bins/app/`** — Special subdirectory for the main app bin (typically the default bin)
580
+ - **`lib/bins/custom_name/`** — Custom bin directories (e.g., `tpl/`, `ticket_test/`, etc.)
541
581
 
542
- **Important: The `bins/app/` special case**
582
+ **Important: The `lib/bins/app/` special case**
543
583
 
544
- The `app/` subdirectory under `bins/` is treated specially:
584
+ The `app/` subdirectory under `lib/bins/` is treated specially:
545
585
 
546
- 1. **It's organizational only** — The `bins/app/` prefix exists only for local file organization and is **not part of the server-side path**.
586
+ 1. **It's organizational only** — The `lib/bins/app/` prefix exists only for local file organization and is **not part of the server-side path**.
547
587
 
548
- 2. **Path normalization** — When comparing paths (during `dbo push`), the CLI automatically strips both `bins/` and `app/` from paths:
588
+ 2. **Path normalization** — When comparing paths (during `dbo push`), the CLI automatically strips both `lib/bins/` and `app/` from paths:
549
589
  ```
550
- Local file: bins/app/assets/css/operator.css
590
+ Local file: lib/bins/app/assets/css/operator.css
551
591
  Server Path: assets/css/operator.css
552
592
  → These are considered the same path ✓
553
593
  ```
554
594
 
555
- 3. **Custom bins are preserved** — Other subdirectories like `bins/tpl/` or `bins/ticket_test/` represent actual bin hierarchies and their names are meaningful:
595
+ 3. **Custom bins are preserved** — Other subdirectories like `lib/bins/tpl/` or `lib/bins/ticket_test/` represent actual bin hierarchies and their names are meaningful:
556
596
  ```
557
- Local file: bins/tpl/header.html
597
+ Local file: lib/bins/tpl/header.html
558
598
  Server Path: tpl/header.html
559
599
  → The 'tpl/' directory is preserved ✓
560
600
  ```
561
601
 
562
602
  **Why this matters:**
563
603
 
564
- - When you `dbo push` files from `bins/app/`, the CLI knows these paths should match the root-level paths in your metadata
565
- - If your metadata `Path` column contains `assets/css/colors.css`, it will correctly match files in `bins/app/assets/css/colors.css`
566
- - Custom bin directories like `bins/tpl/` serve from the `tpl/` directive and maintain their path structure
604
+ - When you `dbo push` files from `lib/bins/app/`, the CLI knows these paths should match the root-level paths in your metadata
605
+ - If your metadata `Path` column contains `assets/css/colors.css`, it will correctly match files in `lib/bins/app/assets/css/colors.css`
606
+ - Custom bin directories like `lib/bins/tpl/` serve from the `tpl/` directive and maintain their path structure
567
607
 
568
608
  **Leading slash handling:**
569
609
 
570
610
  The CLI handles leading `/` in metadata paths flexibly:
571
- - `Path: assets/css/file.css` matches `bins/app/assets/css/file.css` ✓
572
- - `Path: /assets/css/file.css` also matches `bins/app/assets/css/file.css` ✓
573
- - `Path: /assets/css/file.css` matches `bins/assets/css/file.css` ✓
611
+ - `Path: assets/css/file.css` matches `lib/bins/app/assets/css/file.css` ✓
612
+ - `Path: /assets/css/file.css` also matches `lib/bins/app/assets/css/file.css` ✓
613
+ - `Path: /assets/css/file.css` matches `lib/bins/assets/css/file.css` ✓
574
614
 
575
615
  This ensures compatibility with various path formats from the server while maintaining correct local file organization.
576
616
 
617
+ #### Media file serving (API)
618
+
619
+ The DBO.io server provides three routes for serving media files:
620
+
621
+ | Route | Example | Description |
622
+ |-------|---------|-------------|
623
+ | `/media/{app}/{path}` | `/media/todoes/App/assets/fonts/file.ttf` | Legacy FullPath — the value stored in the media record's `FullPath` column |
624
+ | `/dir/{app}/{bins}/{file}` | `/dir/todoes/App/assets/fonts/file.ttf` | Modern BinID-based route — parses `appShortName/binHierarchy/filename` |
625
+ | `/api/media/{uid}` | `/api/media/ujrOQPCdUEamNJdAjUQdYA` | UID-based endpoint — looks up media by unique identifier |
626
+
627
+ During `dbo clone`, the CLI downloads media using a **fallback chain**:
628
+
629
+ 1. **FullPath** (`/media/...`) — uses the record's `FullPath` column directly
630
+ 2. **`/dir/` route** — strips the `/media/` prefix from FullPath and uses the `/dir/` route
631
+ 3. **`/api/media/{uid}`** — UID-based endpoint as last resort (when no FullPath exists)
632
+
633
+ If all attempts fail, the error is logged to `.dbo/errors.log` (JSONL format) with the record's UID, filename, FullPath, and error details.
634
+
577
635
  #### Output hierarchy format
578
636
 
579
637
  Each root output record produces a **single compound JSON file** containing all child entities (columns, joins, filters) embedded inline:
@@ -767,16 +825,16 @@ Query data from DBO.io outputs or entities.
767
825
  dbo output qfkyyp2vxeaggdeo7dwbig
768
826
 
769
827
  # Entity query
770
- dbo output -e user --format json
828
+ dbo output -e user --template json_indented
771
829
 
772
830
  # Single record
773
831
  dbo output -e user --row 10296
774
832
 
775
833
  # With filtering and sorting
776
- dbo output -e user --filter 'FirstName=John' --sort 'LastName:asc' --format json
834
+ dbo output -e user --filter 'FirstName=John' --sort 'LastName:asc' --template json_indented
777
835
 
778
836
  # Contains filter
779
- dbo output -e content --filter 'Name:contains=color' --format json
837
+ dbo output -e content --filter 'Name:contains=color' --template json_indented
780
838
 
781
839
  # Pagination
782
840
  dbo output -e user --page 2 --rows-per-page 25
@@ -800,18 +858,17 @@ dbo output myOutputUID --debug-sql
800
858
  | `-e, --entity <uid>` | Query by entity UID |
801
859
  | `--row <id>` | Specific row ID |
802
860
  | `--filter <expr>` | Filter expression (repeatable) |
803
- | `--format <type>` | Output format: `json`, `html`, `csv`, `xml`, `txt`, `pdf` |
861
+ | `--template <value>` | Output template: `json_raw` (default), `json_indented`, `json`, `html`, `csv`, `xml`, `txt`, `pdf`, or a content UID for custom templates |
804
862
  | `--sort <expr>` | Sort expression (repeatable), e.g., `LastName:asc` |
805
863
  | `--search <expr>` | Full-text search |
806
864
  | `--page <n>` | Page number |
807
865
  | `--rows-per-page <n>` | Rows per page |
808
866
  | `--maxrows <n>` | Maximum rows |
809
867
  | `--rows <range>` | Row range, e.g., `1-10` |
810
- | `--template <value>` | Custom template |
811
868
  | `--limit <n>` | Maximum rows to return (preferred over `--maxrows`) |
812
869
  | `--rowcount <bool>` | Include row count: `true` (default) or `false` for performance |
813
870
  | `--display <expr>` | Show/hide template tags (repeatable), e.g., `sidebar=hide` |
814
- | `--format-values` | Enable value formatting in `json_raw` output |
871
+ | `--format-values` | Enable value formatting with `--template json_raw` |
815
872
  | `--empty-response-code <code>` | HTTP status code when output returns no results |
816
873
  | `--fallback-content <expr>` | Fallback content UID for error codes, e.g., `404=contentUID` |
817
874
  | `--escape-html <bool>` | Control HTML escaping: `true` or `false` |
@@ -877,14 +934,14 @@ dbo content ykqucv0eb0ggjqgcncj6dq
877
934
  dbo content ykqucv0eb0ggjqgcncj6dq -o local/file.html
878
935
 
879
936
  # Get as plain text (disable minification)
880
- dbo content ykqucv0eb0ggjqgcncj6dq --format txt --no-minify
937
+ dbo content ykqucv0eb0ggjqgcncj6dq --template txt --no-minify
881
938
  ```
882
939
 
883
940
  | Flag | Description |
884
941
  |------|-------------|
885
942
  | `<uid>` | Content UID |
886
943
  | `-o, --output <path>` | Save to local file |
887
- | `--format <type>` | Output format |
944
+ | `--template <value>` | Output template (e.g., `json_raw`, `html`, `txt`, or a content UID) |
888
945
  | `--no-minify` | Disable minification |
889
946
  | `--json` | Output raw JSON |
890
947
 
@@ -1231,9 +1288,16 @@ The `@colors.css` reference tells push to read the content from that file. All o
1231
1288
  | `--meta-only` | Only push metadata, skip file content |
1232
1289
  | `--content-only` | Only push file content, skip metadata |
1233
1290
  | `-y, --yes` | Auto-accept all prompts |
1291
+ | `--toe-stepping <true\|false>` | Check server for conflicts before pushing (default: `true`). Set to `false` to skip the check and push unconditionally |
1234
1292
  | `--json` | Output raw JSON |
1235
1293
  | `--jq <expr>` | Filter JSON response |
1236
1294
 
1295
+ #### Server conflict detection (toe-stepping)
1296
+
1297
+ By default, `dbo push` checks the live server state before submitting changes. For each record being pushed, it fetches the current server version and compares `_LastUpdated` against the local baseline. If another user has modified a record since your last `dbo clone` or `dbo push`, you'll see a conflict warning with the name of the user who made the server-side change and a per-column diff of what changed.
1298
+
1299
+ You can then choose to overwrite the server changes or cancel and pull first. Use `--toe-stepping false` to disable the check entirely, or `--yes` to auto-accept conflicts (useful for CI/scripts).
1300
+
1237
1301
  ---
1238
1302
 
1239
1303
  ### `dbo rm`
@@ -1563,7 +1627,7 @@ If no stored user info is available, it prompts for direct input. The CLI automa
1563
1627
 
1564
1628
  ### `dbo install` (alias: `dbo i`)
1565
1629
 
1566
- Install or upgrade dbo-cli components including the CLI itself, plugins, and Claude Code integration.
1630
+ Install or upgrade dbo cli components including the CLI itself, plugins, and Claude Code integration.
1567
1631
 
1568
1632
  ```bash
1569
1633
  # Interactive — choose what to install
@@ -1621,7 +1685,7 @@ Smart behavior:
1621
1685
 
1622
1686
  ### `dbo deploy`
1623
1687
 
1624
- Deploy files to DBO.io using a `dbo.deploy.json` manifest or direct arguments.
1688
+ Deploy files to DBO.io using a `.dbo/deploy_config.json` manifest or direct arguments.
1625
1689
 
1626
1690
  ```bash
1627
1691
  # Deploy a named entry from the manifest
@@ -1642,7 +1706,7 @@ dbo deploy img:logo
1642
1706
 
1643
1707
  | Flag | Description |
1644
1708
  |------|-------------|
1645
- | `<name>` | Deployment name from `dbo.deploy.json` |
1709
+ | `<name>` | Deployment name from `.dbo/deploy_config.json` |
1646
1710
  | `--all` | Deploy all entries in the manifest |
1647
1711
  | `-C, --confirm <true\|false>` | Commit (default: `true`) |
1648
1712
  | `--ticket <id>` | Override ticket ID |
@@ -1654,9 +1718,9 @@ dbo deploy img:logo
1654
1718
 
1655
1719
  The `deploy` command includes the same automatic error recovery as `push`, `input`, and `add` — including ticket error handling, repository mismatch recovery, user identity prompts, and ModifyKey protection. When a stored ticket exists, you'll be prompted before the first submission (see [Pre-submission ticket prompt](#pre-submission-ticket-prompt)).
1656
1720
 
1657
- #### `dbo.deploy.json` manifest
1721
+ #### `.dbo/deploy_config.json` manifest
1658
1722
 
1659
- Create a `dbo.deploy.json` file in your project root to define named deployments:
1723
+ Create a `.dbo/deploy_config.json` file to define named deployments:
1660
1724
 
1661
1725
  ```json
1662
1726
  {
@@ -1786,7 +1850,7 @@ dbo message myUID --jq '.Successful'
1786
1850
  | `.[] \| .field` | Pipe: iterate then access |
1787
1851
  | `.["key.name"]` | Bracket notation for keys with dots |
1788
1852
 
1789
- When `--jq` is used, the API request is automatically made with `_format=json`.
1853
+ When `--jq` is used, the API request is automatically made with `_template=json_raw`.
1790
1854
 
1791
1855
  ### JSON syntax highlighting
1792
1856
 
@@ -1871,14 +1935,15 @@ _search@ColumnName=keyword # search specific column
1871
1935
  #### Template & Format
1872
1936
 
1873
1937
  ```
1874
- _template=json_raw # format name: json_raw, html, json, json_indented, csv, xml, txt, pdf
1938
+ _template=json_raw # system template name: json_raw, json_indented, json, html, csv, xml, txt, pdf
1875
1939
  _template=3iX9fHFTL064Shgol8Bktw # content UID (custom template)
1876
1940
  _format_values=true # enable value formatting in json_raw
1877
- _format=json # legacy format specifier
1878
1941
  _mime=application/json # override MIME/content type
1879
1942
  _escape_html=false # disable HTML escaping of data values
1880
1943
  ```
1881
1944
 
1945
+ > **`_format` is deprecated.** Do not use `_format` — use `_template` instead. The `_format` key is demoted and retained only for backwards compatibility in the API. Do not use `_format` in combination with `_template` — combining both in a single request causes broken responses.
1946
+
1882
1947
  #### Display Control
1883
1948
 
1884
1949
  ```
@@ -2010,12 +2075,12 @@ dbo upload image.jpg --bin 12345 --app 67890 --ownership app --path assets/image
2010
2075
 
2011
2076
  **Before:**
2012
2077
  ```bash
2013
- curl -b .cookies "https://my-domain.com/api/output/entity/user?_format=json&_filter@FirstName=John"
2078
+ curl -b .cookies "https://my-domain.com/api/output/entity/user?_template=json_indented&_filter@FirstName=John"
2014
2079
  ```
2015
2080
 
2016
2081
  **After:**
2017
2082
  ```bash
2018
- dbo output -e user --filter 'FirstName=John' --format json
2083
+ dbo output -e user --filter 'FirstName=John' --template json_indented
2019
2084
  ```
2020
2085
 
2021
2086
  ### Cookie compatibility
@@ -3,6 +3,9 @@
3
3
  // Post-install hook for `npm i @dboio/cli`
4
4
  // Interactive plugin picker when TTY is available, static message otherwise.
5
5
 
6
+ import { dirname, join } from 'path';
7
+ import { fileURLToPath } from 'url';
8
+
6
9
  const RESET = '\x1b[0m';
7
10
  const BOLD = '\x1b[1m';
8
11
  const DIM = '\x1b[2m';
@@ -14,12 +17,17 @@ function write(message) {
14
17
  console.log(message);
15
18
  }
16
19
 
20
+ // Resolve path to dbo.js entrypoint — used instead of bare `dbo` command
21
+ // because during npm postinstall the bin symlink may not be on PATH yet.
22
+ const __dirname = dirname(fileURLToPath(import.meta.url));
23
+ const DBO_BIN = join(__dirname, 'dbo.js');
24
+
17
25
  // Available plugins — add new entries here as plugins are created
18
26
  const PLUGINS = [
19
27
  {
20
28
  name: 'dbo',
21
29
  label: 'Claude Code — /dbo:cli slash command',
22
- command: 'dbo install --claudecommand dbo'
30
+ command: `node "${DBO_BIN}" install --claudecommand dbo`
23
31
  }
24
32
  ];
25
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dboio/cli",
3
- "version": "0.10.1",
3
+ "version": "0.11.2",
4
4
  "description": "CLI for the DBO.io framework",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,9 +39,9 @@
39
39
  "repository": {
40
40
  "type": "git",
41
41
  "url": "https://github.com/dboio/api.git",
42
- "directory": "tools/dbo-cli"
42
+ "directory": "tools/cli"
43
43
  },
44
- "homepage": "https://github.com/dboio/api/tree/master/tools/dbo-cli#readme",
44
+ "homepage": "https://github.com/dboio/api/tree/master/tools/cli#readme",
45
45
  "bugs": {
46
46
  "url": "https://github.com/dboio/api/issues"
47
47
  }
@@ -74,7 +74,7 @@ Available subcommands:
74
74
  - `rm <directory>` — Remove a directory, all files, and sub-directories recursively
75
75
  - `rm -f <path>` — Remove without confirmation prompts
76
76
  - `rm --keep-local <path>` — Stage server deletions without deleting local files/directories
77
- - `deploy [name]` — Deploy via dbo.deploy.json manifest
77
+ - `deploy [name]` — Deploy via .dbo/deploy_config.json manifest
78
78
  - `install` (alias: `i`) — Install or upgrade CLI, plugins, or Claude commands
79
79
  - `i dbo` or `i dbo@latest` — Install/upgrade the CLI from npm
80
80
  - `i dbo@0.4.1` — Install a specific CLI version
@@ -235,8 +235,8 @@ Flags: `--app <name>`, `--domain <host>`, `-y/--yes`, `-v/--verbose`
235
235
  3. Updates `package.json` with `name`, `productName`, `description`, `homepage`, and `deploy` script
236
236
  4. Creates directory structure from `children.bin` hierarchy → saves `.dbo/structure.json`
237
237
  5. Writes content files (decodes base64) with `*.metadata.json` into bin directories
238
- 6. Downloads media files from server via `/api/media/{uid}` with `*.metadata.json`
239
- 7. Processes entity-dir records (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) into project directories (`Extensions/`, `Data Sources/`, etc.) as `.metadata.json` files with optional companion content files
238
+ 6. Downloads media files from server using fallback chain: FullPath (`/media/{app}/{path}`) → `/dir/` route → `/api/media/{uid}`, with `*.metadata.json`. Errors logged to `.dbo/errors.log`
239
+ 7. Processes entity-dir records (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) into `lib/` project directories as `.metadata.json` files with optional companion content files
240
240
  8. Processes remaining entities with BinID into corresponding bin directories
241
241
  9. Saves `app.json` to project root with `@path/to/*.metadata.json` references
242
242
 
@@ -80,7 +80,7 @@ Available subcommands:
80
80
  - `rm <directory>` — Remove a directory, all files, and sub-directories recursively
81
81
  - `rm -f <path>` — Remove without confirmation prompts
82
82
  - `rm --keep-local <path>` — Stage server deletions without deleting local files/directories
83
- - `deploy [name]` — Deploy via dbo.deploy.json manifest
83
+ - `deploy [name]` — Deploy via .dbo/deploy_config.json manifest
84
84
  - `install` (alias: `i`) — Install or upgrade CLI, plugins, or Claude commands
85
85
  - `i dbo` or `i dbo@latest` — Install/upgrade the CLI from npm
86
86
  - `i dbo@0.4.1` — Install a specific CLI version
@@ -241,8 +241,8 @@ Flags: `--app <name>`, `--domain <host>`, `-y/--yes`, `-v/--verbose`
241
241
  3. Updates `package.json` with `name`, `productName`, `description`, `homepage`, and `deploy` script
242
242
  4. Creates directory structure from `children.bin` hierarchy → saves `.dbo/structure.json`
243
243
  5. Writes content files (decodes base64) with `*.metadata.json` into bin directories
244
- 6. Downloads media files from server via `/api/media/{uid}` with `*.metadata.json`
245
- 7. Processes entity-dir records (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) into project directories (`Extensions/`, `Data Sources/`, etc.) as `.metadata.json` files with optional companion content files
244
+ 6. Downloads media files from server using fallback chain: FullPath (`/media/{app}/{path}`) → `/dir/` route → `/api/media/{uid}`, with `*.metadata.json`. Errors logged to `.dbo/errors.log`
245
+ 7. Processes entity-dir records (`extension`, `app_version`, `data_source`, `site`, `group`, `integration`, `automation`) into `lib/` project directories as `.metadata.json` files with optional companion content files
246
246
  8. Processes remaining entities with BinID into corresponding bin directories
247
247
  9. Saves `app.json` to project root with `@path/to/*.metadata.json` references
248
248
 
@@ -14,6 +14,7 @@ import { checkStoredTicket, clearGlobalTicket } from '../lib/ticketing.js';
14
14
  import { checkModifyKey, isModifyKeyError, handleModifyKeyError } from '../lib/modify-key.js';
15
15
  import { loadIgnore } from '../lib/ignore.js';
16
16
  import { loadStructureFile, findBinByPath } from '../lib/structure.js';
17
+ import { runPendingMigrations } from '../lib/migrations.js';
17
18
 
18
19
  export const addCommand = new Command('add')
19
20
  .description('Add a new file to DBO.io (creates record on server)')
@@ -27,8 +28,10 @@ export const addCommand = new Command('add')
27
28
  .option('--jq <expr>', 'Filter JSON response')
28
29
  .option('-v, --verbose', 'Show HTTP request details')
29
30
  .option('--domain <host>', 'Override domain')
31
+ .option('--no-migrate', 'Skip pending migrations for this invocation')
30
32
  .action(async (targetPath, options) => {
31
33
  try {
34
+ await runPendingMigrations(options);
32
35
  const client = new DboClient({ domain: options.domain, verbose: options.verbose });
33
36
 
34
37
  // ModifyKey guard
@@ -432,6 +435,7 @@ async function submitAdd(meta, metaPath, filePath, client, options) {
432
435
  result = await client.postUrlEncoded('/api/input/submit', body);
433
436
  }
434
437
 
438
+ if (result.successful) await client.voidCache();
435
439
  formatResponse(result, { json: options.json, jq: options.jq, verbose: options.verbose });
436
440
 
437
441
  if (!result.successful) {