@dboio/cli 0.19.4 → 0.20.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/README.md +69 -16
- package/bin/dbo.js +5 -0
- package/package.json +1 -1
- package/plugins/claude/dbo/.claude-plugin/plugin.json +6 -1
- package/plugins/claude/dbo/commands/dbo.md +39 -12
- package/plugins/claude/dbo/docs/dbo-cli-readme.md +69 -16
- package/plugins/claude/dbo/skills/cookbook/SKILL.md +162 -0
- package/plugins/claude/dbo/skills/white-paper/SKILL.md +49 -8
- package/plugins/claude/dbo/skills/white-paper/references/api-reference.md +1 -1
- package/plugins/claude/track/.claude-plugin/plugin.json +1 -1
- package/src/commands/adopt.js +69 -14
- package/src/commands/clone.js +451 -87
- package/src/commands/init.js +2 -2
- package/src/commands/input.js +2 -2
- package/src/commands/login.js +3 -3
- package/src/commands/push.js +203 -54
- package/src/commands/status.js +15 -7
- package/src/lib/config.js +137 -10
- package/src/lib/filenames.js +54 -66
- package/src/lib/ignore.js +3 -0
- package/src/lib/insert.js +29 -45
- package/src/lib/structure.js +23 -8
- package/src/lib/ticketing.js +9 -8
- package/src/migrations/008-metadata-uid-in-suffix.js +4 -2
- package/src/migrations/009-fix-media-collision-metadata-names.js +9 -3
- package/src/migrations/013-remove-uid-from-meta-filenames.js +117 -0
- package/src/migrations/014-entity-dir-to-data-source.js +68 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cookbook
|
|
3
|
+
description: >-
|
|
4
|
+
DBO project cookbook — operational DOs and DON'Ts for working correctly in any
|
|
5
|
+
DBO project. Load this skill when editing files, adding new features, debugging,
|
|
6
|
+
or when the white-paper provides architecture context but you need behavioral
|
|
7
|
+
rules. Covers file operations, build recipes, metadata handling, and common
|
|
8
|
+
gotchas.
|
|
9
|
+
user-invocable: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# DBO Project Cookbook
|
|
13
|
+
|
|
14
|
+
Operational rules for working correctly in a DBO project. This is a living document — rules are added as new patterns and pitfalls are discovered.
|
|
15
|
+
|
|
16
|
+
For architecture context, load the **white-paper** skill. For CLI command reference, use `/dbo`. This cookbook focuses on *how to behave* when making changes.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## DOs
|
|
21
|
+
|
|
22
|
+
- **DO use UIDs, not numeric IDs, in templates.** Numeric IDs change across environments (dev → staging → prod). UIDs are stable and portable.
|
|
23
|
+
- **DO always pass `-e <entity>` when running `dbo adopt`.** Every file in `lib/` needs a metadata companion. `dbo adopt path/to/file -e {entity}` creates one. Without it, `dbo push` won't know what server record to target. **Never omit `-e`** — auto-inference fails for most `lib/bins/` files because the directory maps to multiple entity types. Use `-e content` for HTML/CSS/JS/SQL, `-e media` for images and binaries.
|
|
24
|
+
- **DO build from `src/` before pushing compiled assets.** Check `.app/scripts.json` for the build command. Run `npm run build` or the specific build script, then push the compiled output from `lib/`.
|
|
25
|
+
- **DO check `.app/scripts.json` for build/postpush chains before manual deploys.** A file may have postpush hooks that auto-deploy dependent assets. Pushing manually with `dbo deploy` bypasses these chains.
|
|
26
|
+
- **DO read the metadata file before modifying a server-tracked file.** The `.metadata.json` companion tells you what entity, column, and record the file maps to (check the `UID` field inside the JSON). This context prevents wrong-target pushes.
|
|
27
|
+
- **DO use `dbo diff` to verify local vs server state before bulk pushes.** Catches unexpected server-side changes that would be overwritten.
|
|
28
|
+
- **DO check `app_dependencies/` for parent app patterns when building extensions.** Descriptor definitions, CSS design tokens, and JS APIs from the parent app define what's available.
|
|
29
|
+
- **DO know that `dbo clone` skips dependencies that are already up to date.** Before re-cloning a dependency, the CLI hits `/api/app/object/<name>?UpdatedAfter=<stored-date>` and compares `_LastUpdated`. If the server hasn't changed, the dep is skipped silently. Use `--force` or `--schema` to bypass this check and force a re-clone.
|
|
30
|
+
- **DO use the REST API with `.app/cookies.txt` for data operations, CLI for file operations.** The CLI handles metadata sync; the API handles data reads/writes. Don't cross these boundaries.
|
|
31
|
+
- **DO check `.app/deploy_config.json` for existing shorthands before creating deploy commands.** Shorthands are auto-generated by `dbo clone` and `dbo adopt`.
|
|
32
|
+
- **DO use `dbo push --confirm false` to validate before committing a push.** Dry-run catches issues without touching the server.
|
|
33
|
+
|
|
34
|
+
## DON'Ts
|
|
35
|
+
|
|
36
|
+
- **DON'T push `src/`, `test/`, `node_modules/`, `app_dependencies/`, or `trash/` to the server.** These are strictly local. Only `lib/` and `docs/` contents map to server records.
|
|
37
|
+
- **DON'T use numeric IDs in templates.** They break across environments. Always use UIDs.
|
|
38
|
+
- **DON'T create files in `lib/` without a metadata companion.** Use `dbo adopt` to assign one. Files without metadata are invisible to the CLI and won't sync.
|
|
39
|
+
- **DON'T bypass `dbo push` by deploying raw files.** Push handles build scripts, metadata sync, and postpush hooks. Deploying directly skips all of that.
|
|
40
|
+
- **DON'T assume a deploy shorthand exists — check `.app/deploy_config.json` first.** Not all files have shorthands. Use `dbo push` for files without one.
|
|
41
|
+
- **DON'T modify vendor files in `node_modules/` or `app_dependencies/`.** These are read-only references. Vendor changes belong upstream; dependency changes belong in the source project.
|
|
42
|
+
- **DON'T edit files in `app_dependencies/` directly.** They are cloned read-only mirrors. Edit in the source project and re-clone.
|
|
43
|
+
- **DON'T push minified files without also pushing their unminified source.** The server tracks both. Pushing only `.min.css` leaves the content record out of sync.
|
|
44
|
+
- **DON'T delete metadata files manually.** Use `dbo rm` to remove a file and its metadata together. Orphaned metadata causes ghost records.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## File Operation Recipes
|
|
49
|
+
|
|
50
|
+
### Add a new file to the server
|
|
51
|
+
```bash
|
|
52
|
+
# 1. Create the file in the correct lib/ subdirectory
|
|
53
|
+
# 2. Create metadata companion (entity is usually "content" for text, "media" for binary)
|
|
54
|
+
dbo adopt lib/bins/app/assets/css/new-file.css -e content
|
|
55
|
+
|
|
56
|
+
# 3. Push — inserts a new server record
|
|
57
|
+
dbo push lib/bins/app/assets/css/new-file.css
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Modify an existing server-tracked file
|
|
61
|
+
```bash
|
|
62
|
+
# 1. Edit the file locally
|
|
63
|
+
# 2. Push the change (metadata already exists from clone)
|
|
64
|
+
dbo push lib/bins/app/assets/css/colors.css
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Delete a file from the server
|
|
68
|
+
```bash
|
|
69
|
+
# Removes the local file, its metadata, and the server record
|
|
70
|
+
dbo rm lib/bins/app/assets/css/old-file.css
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Rename or move a file
|
|
74
|
+
There is no rename command. Instead:
|
|
75
|
+
```bash
|
|
76
|
+
# 1. Create the new file with the desired name/location
|
|
77
|
+
# 2. Adopt it as a new record
|
|
78
|
+
dbo adopt lib/bins/app/assets/css/renamed.css -e content
|
|
79
|
+
# 3. Push the new file
|
|
80
|
+
dbo push lib/bins/app/assets/css/renamed.css
|
|
81
|
+
# 4. Remove the old file
|
|
82
|
+
dbo rm lib/bins/app/assets/css/old-name.css
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Move a file between bins
|
|
86
|
+
Same as rename — the bin is determined by the directory path. Moving to a new directory means a new BinID, which requires a new record.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Build Recipes
|
|
91
|
+
|
|
92
|
+
### CSS: SASS source → compiled → minified
|
|
93
|
+
```bash
|
|
94
|
+
# Build compiles src/sass/ → lib/bins/.../css/ and minifies
|
|
95
|
+
npm run build
|
|
96
|
+
# Or run the specific target from .app/scripts.json:
|
|
97
|
+
sass src/sass/colors:lib/bins/app/assets/css
|
|
98
|
+
csso lib/bins/app/assets/css/colors.css --output lib/bins/app/assets/css/colors.min.css
|
|
99
|
+
```
|
|
100
|
+
Then push both the unminified and minified versions.
|
|
101
|
+
|
|
102
|
+
### JS: Rollup bundle
|
|
103
|
+
```bash
|
|
104
|
+
# Bundles ES6 modules from src/ into lib/bins/.../js/app.min.js
|
|
105
|
+
rollup --config src/rollup.config.mjs
|
|
106
|
+
# Then push
|
|
107
|
+
dbo push lib/bins/app/assets/js/app.min.js
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### When does push auto-compile?
|
|
111
|
+
It doesn't. `dbo push` triggers **postpush** scripts (defined in `.app/scripts.json` under `targets.{file}.postpush`), but these are for deploying *dependent* assets, not for compiling. Always build first, then push.
|
|
112
|
+
|
|
113
|
+
### Check what builds exist
|
|
114
|
+
```bash
|
|
115
|
+
# Read the scripts config
|
|
116
|
+
cat .app/scripts.json
|
|
117
|
+
```
|
|
118
|
+
Look at `targets.{file}.build` for compile commands and `targets.{file}.postpush` for post-push deploy chains.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Gotchas
|
|
123
|
+
|
|
124
|
+
### Metadata mismatch after manual file creation
|
|
125
|
+
**Symptom:** `dbo push` says "no changes detected" for a file you just created.
|
|
126
|
+
**Cause:** No metadata companion exists. The CLI doesn't track unregistered files.
|
|
127
|
+
**Fix:** Run `dbo adopt path/to/file -e {entity}` first.
|
|
128
|
+
|
|
129
|
+
### Postpush chain didn't fire
|
|
130
|
+
**Symptom:** You pushed a JS file but the documentation deploy didn't happen.
|
|
131
|
+
**Cause:** You used `dbo deploy` instead of `dbo push`. Deploy bypasses postpush hooks.
|
|
132
|
+
**Fix:** Use `dbo push` for files with postpush chains, or manually run the postpush commands.
|
|
133
|
+
|
|
134
|
+
### Content and media records out of sync
|
|
135
|
+
**Symptom:** CSS looks wrong on the server even though you pushed the file.
|
|
136
|
+
**Cause:** You pushed only the content record but not the media companion (or vice versa).
|
|
137
|
+
**Fix:** Push both — check `deploy_config.json` for paired `{name}` and `{name}_media` entries.
|
|
138
|
+
|
|
139
|
+
### `dbo adopt` fails — entity cannot be inferred
|
|
140
|
+
**Symptom:** `dbo adopt path/to/file` errors with "entity cannot be inferred" or similar.
|
|
141
|
+
**Cause:** `-e <entity>` was omitted. Auto-inference only works for exact directive template matches. Files in `lib/bins/` (HTML, CSS, JS, SQL) almost never infer correctly because `lib/bins/` maps to multiple entity types.
|
|
142
|
+
**Fix:** Always pass `-e content` for text/code files, `-e media` for images and binaries:
|
|
143
|
+
```bash
|
|
144
|
+
dbo adopt lib/bins/app/user_first_names.html -e content
|
|
145
|
+
dbo adopt lib/bins/app/assets/img/logo.png -e media
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Wrong entity type on adopt
|
|
149
|
+
**Symptom:** Pushed file lands in unexpected server location.
|
|
150
|
+
**Cause:** Used wrong `-e` flag on `dbo adopt` (e.g., `-e media` for a text file).
|
|
151
|
+
**Fix:** Remove with `dbo rm`, re-adopt with correct entity type, re-push.
|
|
152
|
+
|
|
153
|
+
### Extension files not picked up
|
|
154
|
+
**Symptom:** New extension file doesn't appear in the app.
|
|
155
|
+
**Cause:** Extension files follow strict naming: `{Name}.{ContentColumnName}.{ext}` with metadata companion.
|
|
156
|
+
**Fix:** Verify the file name matches the pattern and the descriptor type exists in `app_dependencies/`.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Project-Specific Overlays
|
|
161
|
+
|
|
162
|
+
Individual DBO projects may provide an additional conventions file at `docs/Operator_Claude.md` (or equivalent). When present, load it alongside this cookbook for project-specific DOs, DON'Ts, and patterns. When the project is a dependency of another app, the overlay appears at `app_dependencies/{app}/docs/{App}_Claude.md`.
|
|
@@ -49,10 +49,9 @@ project-root/
|
|
|
49
49
|
├── lib/ # Server-mapped files (mirrors DBO table data)
|
|
50
50
|
│ ├── bins/ # Bin entities and their children (see Bin Mapping below)
|
|
51
51
|
│ ├── extension/ # Extension records, sub-foldered by Descriptor
|
|
52
|
-
│ ├──
|
|
52
|
+
│ ├── data_source/ # Data source configs + entity (table) definitions
|
|
53
53
|
│ ├── site/ # Site definitions
|
|
54
54
|
│ ├── security/ # Security rule records
|
|
55
|
-
│ ├── data_source/ # Data source configurations
|
|
56
55
|
│ └── app_version/ # App version metadata
|
|
57
56
|
│
|
|
58
57
|
├── docs/ # Project documentation (scripts, embeds, pages, components)
|
|
@@ -83,11 +82,11 @@ Files belonging to a `bin` entity are placed in directories matching their BinID
|
|
|
83
82
|
}
|
|
84
83
|
```
|
|
85
84
|
|
|
86
|
-
So `lib/bins/app/assets/css/colors.css` lives inside the bin whose `fullPath` is `app/assets/css`. Every file has a companion `.metadata.json` (
|
|
85
|
+
So `lib/bins/app/assets/css/colors.css` lives inside the bin whose `fullPath` is `app/assets/css`. Every file has a companion `.metadata.json` (e.g. `colors.metadata.json`) containing the server record fields, including the `UID` field.
|
|
87
86
|
|
|
88
87
|
### Non-bin entities (no BinID column)
|
|
89
88
|
|
|
90
|
-
Entities without a BinID column get their own directory under `lib/`, named after the entity: `lib/extension/`, `lib/
|
|
89
|
+
Entities without a BinID column get their own directory under `lib/`, named after the entity: `lib/extension/`, `lib/site/`, `lib/security/`, `lib/data_source/`, `lib/app_version/`. Exception: `entity` (table definitions) shares `lib/data_source/` rather than getting its own directory — both `_entity: "data_source"` and `_entity: "entity"` records live there.
|
|
91
90
|
|
|
92
91
|
### Extension special case
|
|
93
92
|
|
|
@@ -96,7 +95,7 @@ The `extension` entity has sub-folders based on the **Descriptor** column value:
|
|
|
96
95
|
- `lib/extension/Widget/` — Widget extensions
|
|
97
96
|
- `lib/extension/Descriptor Definition/` — Descriptor definitions themselves
|
|
98
97
|
|
|
99
|
-
Each extension file follows: `{Name}.{ContentColumnName}.{ext}` with a companion `{Name}.metadata
|
|
98
|
+
Each extension file follows: `{Name}.{ContentColumnName}.{ext}` with a companion `{Name}.metadata.json` (UID stored inside the JSON).
|
|
100
99
|
|
|
101
100
|
## .app/ Configuration
|
|
102
101
|
|
|
@@ -152,10 +151,10 @@ When `app_dependencies/{app_name}/` exists (e.g., `app_dependencies/operator/`),
|
|
|
152
151
|
## CLI vs REST API
|
|
153
152
|
|
|
154
153
|
### Use the DBO CLI for:
|
|
155
|
-
- **File operations**: `pull`, `push`, `
|
|
154
|
+
- **File operations**: `pull`, `push`, `adopt`, `clone`, `rm`, `diff` — for `adopt`, always pass `-e <entity>` (e.g., `-e content` for HTML/CSS/JS, `-e media` for images/binaries); entity cannot be inferred for standalone files in `lib/bins/`
|
|
156
155
|
- **Deployment**: `deploy` (shorthand or UID), content deploy
|
|
157
156
|
- **Project setup**: `init`, `login`, `status`
|
|
158
|
-
- **Batch operations**: pushing directories, scanning for
|
|
157
|
+
- **Batch operations**: pushing directories, scanning for unadopted files
|
|
159
158
|
|
|
160
159
|
The CLI handles metadata management, change detection, and file-to-record synchronization automatically.
|
|
161
160
|
|
|
@@ -182,6 +181,48 @@ RowID:del{id};entity:entityName=true # Delete
|
|
|
182
181
|
```
|
|
183
182
|
Always include `_confirm=true`. Special values: `_{now}` (datetime), `_{null}` (null).
|
|
184
183
|
|
|
184
|
+
## Creating New Assets
|
|
185
|
+
|
|
186
|
+
Two approaches — choose based on whether the file exists locally first or on the server first.
|
|
187
|
+
|
|
188
|
+
### File-first (CLI)
|
|
189
|
+
|
|
190
|
+
Use when you're creating a new file locally and want the server to create the record.
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# 1. Write the file in the correct lib/ subdirectory
|
|
194
|
+
# 2. Create the metadata companion (required before push)
|
|
195
|
+
dbo adopt -e content lib/bins/app/my-file.html # HTML/CSS/JS/SQL → content
|
|
196
|
+
dbo adopt -e media lib/bins/app/assets/img/x.png # images/binaries → media
|
|
197
|
+
|
|
198
|
+
# 3. Push — inserts a new record on the server, assigns a UID, updates local metadata
|
|
199
|
+
dbo push lib/bins/app/my-file.html
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Always pass `-e <entity>` to `adopt`. Entity cannot be inferred for standalone files in `lib/bins/` because the directory maps to multiple entity types.
|
|
203
|
+
|
|
204
|
+
### Server-first (REST API)
|
|
205
|
+
|
|
206
|
+
Use when you want to create the server record first, then pull the file locally. Required fields for the insert come from three local config files:
|
|
207
|
+
|
|
208
|
+
- **`.app/<app_short_name>.metadata_schema.json`** — entity schema: which columns are required, their types and allowed values
|
|
209
|
+
- **`.app/directories.json`** — BinID for the target directory (needed for bin-based entities like `content` and `media`)
|
|
210
|
+
- **`.app/config.json`** — `AppID`, `AppUID`, and other app-level fields required on most records
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
# 1. Insert the record via REST API (RowID:add1 — must use RowID:, not RowUID:)
|
|
214
|
+
curl -b .app/cookies.txt \
|
|
215
|
+
"https://{{domain}}/api/input/submit?_confirm=true" \
|
|
216
|
+
--data-urlencode 'RowID:add1;column:content.BinID=11042' \
|
|
217
|
+
--data-urlencode 'RowID:add1;column:content.AppID={{appID}}' \
|
|
218
|
+
--data-urlencode 'RowID:add1;column:content.Name=My File'
|
|
219
|
+
|
|
220
|
+
# 2. Pull to create the local file and metadata companion
|
|
221
|
+
dbo pull -e content --filter 'Name=My File'
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
After pull, the file appears in `lib/bins/` at the path matching its BinID in `directories.json`, with a `.metadata.json` companion.
|
|
225
|
+
|
|
185
226
|
## docs/ Directory
|
|
186
227
|
|
|
187
228
|
Contains Markdown documentation for this project's components — scripts, embeds, pages, UI features. These are project-specific references generated or maintained alongside development. Read these to understand documented behaviors of the current app.
|
|
@@ -213,7 +254,7 @@ The `test/` directory is for developer and Claude Code test scripts. Tests targe
|
|
|
213
254
|
| Write/update data | REST API | `POST /api/input/submit` |
|
|
214
255
|
| Pull files from server | CLI | `dbo pull -e content` |
|
|
215
256
|
| Push local changes | CLI | `dbo push path/to/file` |
|
|
216
|
-
| Add new file to server | CLI | `dbo
|
|
257
|
+
| Add new file to server | CLI | `dbo adopt path/to/file -e <entity>` |
|
|
217
258
|
| Deploy by shorthand | CLI | `dbo deploy css:colors` |
|
|
218
259
|
| Deploy by UID | CLI | `dbo deploy {uid}` |
|
|
219
260
|
| Compare with server | CLI | `dbo diff` |
|
|
@@ -87,7 +87,7 @@ RowID:{ref};column:{entity}.{Column}={value}
|
|
|
87
87
|
| `{id}` or `{uid}` | Update existing record |
|
|
88
88
|
| `del{id}` | Delete record |
|
|
89
89
|
|
|
90
|
-
`RowID:` and `RowUID:` are interchangeable. Use `RowUID:` for cross-environment stability.
|
|
90
|
+
`RowID:` and `RowUID:` are interchangeable for updates and deletes. Use `RowUID:` for cross-environment stability. **Inserts (`add1`, `add2`, …) must use `RowID:` — `RowUID:` does not work for inserts.**
|
|
91
91
|
|
|
92
92
|
### Cross-referencing within a batch
|
|
93
93
|
```
|
package/src/commands/adopt.js
CHANGED
|
@@ -3,7 +3,7 @@ import { readFile, writeFile, stat, mkdir } from 'fs/promises';
|
|
|
3
3
|
import { join, dirname, basename, extname, relative } from 'path';
|
|
4
4
|
import { log } from '../lib/logger.js';
|
|
5
5
|
import { loadIgnore } from '../lib/ignore.js';
|
|
6
|
-
import { loadAppConfig, loadAppJsonBaseline, loadExtensionDocumentationMDPlacement, loadDescriptorFilenamePreference } from '../lib/config.js';
|
|
6
|
+
import { loadAppConfig, loadAppJsonBaseline, loadExtensionDocumentationMDPlacement, loadDescriptorFilenamePreference, loadRootContentFiles } from '../lib/config.js';
|
|
7
7
|
import {
|
|
8
8
|
resolveDirective, resolveTemplateCols, assembleMetadata,
|
|
9
9
|
promptReferenceColumn, getTemplateCols, setTemplateCols,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '../lib/metadata-schema.js';
|
|
12
12
|
import { loadStructureFile, findBinByPath, BINS_DIR } from '../lib/structure.js';
|
|
13
13
|
import { isMetadataFile } from '../lib/filenames.js';
|
|
14
|
-
import { findUnaddedFiles, MIME_TYPES, seedMetadataTemplate, detectDocumentationFile
|
|
14
|
+
import { findUnaddedFiles, MIME_TYPES, seedMetadataTemplate, detectDocumentationFile } from '../lib/insert.js';
|
|
15
15
|
import { runPendingMigrations } from '../lib/migrations.js';
|
|
16
16
|
|
|
17
17
|
export const adoptCommand = new Command('adopt')
|
|
@@ -79,6 +79,15 @@ function parseEntitySpec(spec, metadataSchema) {
|
|
|
79
79
|
return { entity, descriptor: null, column: sub };
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Metadata templates for known root content files (mirrors push.js ROOT_FILE_TEMPLATES).
|
|
84
|
+
*/
|
|
85
|
+
const ROOT_FILE_TEMPLATES = {
|
|
86
|
+
'manifest.json': { Extension: 'JSON', Public: 1, Active: 1, Title: 'PWA Manifest' },
|
|
87
|
+
'CLAUDE.md': { Extension: 'MD', Public: 0, Active: 1, Title: 'Claude Code Instructions' },
|
|
88
|
+
'README.md': { Extension: 'MD', Public: 1, Active: 1, Title: 'README' },
|
|
89
|
+
};
|
|
90
|
+
|
|
82
91
|
/**
|
|
83
92
|
* Build entity-specific metadata for a file in or outside lib/bins/.
|
|
84
93
|
*/
|
|
@@ -144,6 +153,62 @@ async function buildBinMetadata(filePath, entity, appConfig, structure) {
|
|
|
144
153
|
async function adoptSingleFile(filePath, entityArg, options) {
|
|
145
154
|
const ig = await loadIgnore();
|
|
146
155
|
const relPath = relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
156
|
+
const fileName = basename(filePath);
|
|
157
|
+
|
|
158
|
+
// --- Root content file check (before ignore): CLAUDE.md, README.md, manifest.json, etc. ---
|
|
159
|
+
// These files live at the project root but their metadata goes in lib/bins/app/.
|
|
160
|
+
// They bypass the dboignore check and entity inference.
|
|
161
|
+
const rootFiles = await loadRootContentFiles();
|
|
162
|
+
if (rootFiles.some(f => f.toLowerCase() === fileName.toLowerCase()) && relPath === fileName) {
|
|
163
|
+
const appConfig = await loadAppConfig();
|
|
164
|
+
const structure = await loadStructureFile();
|
|
165
|
+
const appBin = findBinByPath('app', structure);
|
|
166
|
+
const binsAppDir = join(process.cwd(), BINS_DIR, 'app');
|
|
167
|
+
const ext = extname(fileName).replace('.', '').toUpperCase() || 'TXT';
|
|
168
|
+
const stem = basename(fileName, extname(fileName));
|
|
169
|
+
|
|
170
|
+
const metaFilename = `${stem}.metadata.json`;
|
|
171
|
+
const metaPath = join(binsAppDir, metaFilename);
|
|
172
|
+
|
|
173
|
+
// Check for existing metadata
|
|
174
|
+
let existingMeta = null;
|
|
175
|
+
try { existingMeta = JSON.parse(await readFile(metaPath, 'utf8')); } catch {}
|
|
176
|
+
if (existingMeta) {
|
|
177
|
+
if (existingMeta.UID || existingMeta._CreatedOn) {
|
|
178
|
+
log.warn(`"${fileName}" is already on the server (has UID/_CreatedOn) — skipping.`);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (!options.yes) {
|
|
182
|
+
const inquirer = (await import('inquirer')).default;
|
|
183
|
+
const { overwrite } = await inquirer.prompt([{
|
|
184
|
+
type: 'confirm', name: 'overwrite',
|
|
185
|
+
message: `Metadata already exists for "${fileName}" (no UID). Overwrite?`,
|
|
186
|
+
default: false,
|
|
187
|
+
}]);
|
|
188
|
+
if (!overwrite) return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const tmplKey = Object.keys(ROOT_FILE_TEMPLATES).find(k => k.toLowerCase() === fileName.toLowerCase());
|
|
193
|
+
const tmpl = (tmplKey ? ROOT_FILE_TEMPLATES[tmplKey] : null) || { Extension: ext, Public: 0, Active: 1, Title: fileName };
|
|
194
|
+
const meta = {
|
|
195
|
+
_entity: 'content',
|
|
196
|
+
_companionReferenceColumns: ['Content'],
|
|
197
|
+
...tmpl,
|
|
198
|
+
Content: `@/${fileName}`,
|
|
199
|
+
Path: fileName,
|
|
200
|
+
Name: fileName,
|
|
201
|
+
};
|
|
202
|
+
if (appBin) meta.BinID = appBin.binId;
|
|
203
|
+
if (appConfig.AppID) meta.AppID = appConfig.AppID;
|
|
204
|
+
|
|
205
|
+
await mkdir(binsAppDir, { recursive: true });
|
|
206
|
+
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
207
|
+
log.success(`Created ${metaFilename} for ${fileName}`);
|
|
208
|
+
log.dim(` Run "dbo push" to insert this record on the server.`);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
147
212
|
if (ig.ignores(relPath)) {
|
|
148
213
|
log.dim(`Skipped (dboignored): ${relPath}`);
|
|
149
214
|
return;
|
|
@@ -152,7 +217,6 @@ async function adoptSingleFile(filePath, entityArg, options) {
|
|
|
152
217
|
const dir = dirname(filePath);
|
|
153
218
|
const ext = extname(filePath);
|
|
154
219
|
const base = basename(filePath, ext);
|
|
155
|
-
const fileName = basename(filePath);
|
|
156
220
|
|
|
157
221
|
// Check for existing metadata
|
|
158
222
|
const metaPath = join(dir, `${base}.metadata.json`);
|
|
@@ -204,16 +268,6 @@ async function adoptSingleFile(filePath, entityArg, options) {
|
|
|
204
268
|
|
|
205
269
|
const appConfig = await loadAppConfig();
|
|
206
270
|
|
|
207
|
-
// --- Special case: manifest.json ---
|
|
208
|
-
const rel = relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
209
|
-
if (rel.toLowerCase() === 'manifest.json') {
|
|
210
|
-
const manifestResult = await detectManifestFile(filePath);
|
|
211
|
-
if (manifestResult) {
|
|
212
|
-
log.success(`Created manifest metadata at ${manifestResult.metaPath}`);
|
|
213
|
-
return;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
271
|
// --- content or media entities: build entity-specific metadata ---
|
|
218
272
|
if ((entity === 'content' || entity === 'media') && !column) {
|
|
219
273
|
const structure = await loadStructureFile();
|
|
@@ -238,7 +292,8 @@ async function adoptSingleFile(filePath, entityArg, options) {
|
|
|
238
292
|
Descriptor: 'documentation',
|
|
239
293
|
Name: docBase,
|
|
240
294
|
};
|
|
241
|
-
|
|
295
|
+
if (appConfig.AppID) docMeta.AppID = appConfig.AppID;
|
|
296
|
+
const contentCol = 'Text';
|
|
242
297
|
docMeta[contentCol] = `@/${relPath}`;
|
|
243
298
|
docMeta._companionReferenceColumns = [contentCol];
|
|
244
299
|
|