@dboio/cli 0.15.3 → 0.16.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 +103 -25
- package/package.json +1 -1
- package/plugins/claude/dbo/docs/dbo-cli-readme.md +103 -25
- package/src/commands/add.js +18 -18
- package/src/commands/clone.js +361 -139
- package/src/commands/init.js +42 -1
- package/src/commands/input.js +2 -32
- package/src/commands/mv.js +3 -3
- package/src/commands/push.js +12 -8
- package/src/commands/rm.js +2 -2
- package/src/lib/columns.js +1 -0
- package/src/lib/config.js +83 -1
- package/src/lib/delta.js +3 -2
- package/src/lib/dependencies.js +217 -2
- package/src/lib/diff.js +9 -11
- package/src/lib/filenames.js +2 -2
- package/src/lib/ignore.js +1 -0
- package/src/lib/logger.js +35 -0
- package/src/lib/metadata-schema.js +492 -0
- package/src/lib/save-to-disk.js +1 -1
- package/src/lib/schema.js +53 -0
- package/src/lib/structure.js +3 -3
- package/src/lib/tagging.js +1 -1
- package/src/lib/toe-stepping.js +2 -2
- package/src/migrations/007-natural-entity-companion-filenames.js +5 -2
- package/src/migrations/011-schema-driven-metadata.js +120 -0
package/src/commands/add.js
CHANGED
|
@@ -7,7 +7,7 @@ import { formatResponse, formatError } from '../lib/formatter.js';
|
|
|
7
7
|
import { log } from '../lib/logger.js';
|
|
8
8
|
import { shouldSkipColumn } from '../lib/columns.js';
|
|
9
9
|
import { loadAppConfig, loadAppJsonBaseline, saveAppJsonBaseline, loadExtensionDocumentationMDPlacement, loadDescriptorFilenamePreference, loadConfig } from '../lib/config.js';
|
|
10
|
-
import { resolveDirective, resolveTemplateCols, assembleMetadata, promptReferenceColumn, setTemplateCols,
|
|
10
|
+
import { resolveDirective, resolveTemplateCols, assembleMetadata, promptReferenceColumn, setTemplateCols, saveMetadataSchema, loadMetadataSchema } from '../lib/metadata-schema.js';
|
|
11
11
|
import { hasUidInFilename, buildMetaFilename, isMetadataFile } from '../lib/filenames.js';
|
|
12
12
|
import { setFileTimestamps } from '../lib/timestamps.js';
|
|
13
13
|
import { checkStoredTicket, clearGlobalTicket } from '../lib/ticketing.js';
|
|
@@ -137,7 +137,7 @@ async function detectManifestFile(filePath) {
|
|
|
137
137
|
|
|
138
138
|
const meta = {
|
|
139
139
|
_entity: 'content',
|
|
140
|
-
|
|
140
|
+
_companionReferenceColumns: ['Content'],
|
|
141
141
|
Content: '@/manifest.json',
|
|
142
142
|
Path: 'manifest.json',
|
|
143
143
|
Name: 'manifest.json',
|
|
@@ -202,7 +202,7 @@ export async function detectBinFile(filePath) {
|
|
|
202
202
|
|
|
203
203
|
const meta = {
|
|
204
204
|
_entity: 'content',
|
|
205
|
-
|
|
205
|
+
_companionReferenceColumns: ['Content'],
|
|
206
206
|
Name: base,
|
|
207
207
|
Content: `@${fileName}`,
|
|
208
208
|
Extension: ext.toUpperCase(),
|
|
@@ -216,7 +216,7 @@ export async function detectBinFile(filePath) {
|
|
|
216
216
|
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
217
217
|
log.success(`Auto-created content metadata for "${fileName}"`);
|
|
218
218
|
|
|
219
|
-
// Seed
|
|
219
|
+
// Seed metadata_schema.json with content fields if missing
|
|
220
220
|
await seedMetadataTemplate();
|
|
221
221
|
|
|
222
222
|
return { meta, metaPath };
|
|
@@ -250,7 +250,7 @@ export async function detectBinFile(filePath) {
|
|
|
250
250
|
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
251
251
|
log.success(`Auto-created media metadata for "${fileName}"`);
|
|
252
252
|
|
|
253
|
-
// Seed
|
|
253
|
+
// Seed metadata_schema.json with media fields if missing
|
|
254
254
|
await seedMetadataTemplate();
|
|
255
255
|
|
|
256
256
|
return { meta, metaPath };
|
|
@@ -296,11 +296,11 @@ const TEMPLATE_DEFAULTS = {
|
|
|
296
296
|
};
|
|
297
297
|
|
|
298
298
|
/**
|
|
299
|
-
* Seed .dbo/
|
|
299
|
+
* Seed .dbo/metadata_schema.json with default fields for the given entity
|
|
300
300
|
* (and any other missing core entities) if an entry doesn't already exist.
|
|
301
301
|
*/
|
|
302
302
|
async function seedMetadataTemplate() {
|
|
303
|
-
const templates = await
|
|
303
|
+
const templates = await loadMetadataSchema() ?? {};
|
|
304
304
|
|
|
305
305
|
// Seed all missing core entities in one pass
|
|
306
306
|
const seeded = [];
|
|
@@ -312,8 +312,8 @@ async function seedMetadataTemplate() {
|
|
|
312
312
|
|
|
313
313
|
if (seeded.length === 0) return;
|
|
314
314
|
|
|
315
|
-
await
|
|
316
|
-
log.dim(` Seeded
|
|
315
|
+
await saveMetadataSchema(templates);
|
|
316
|
+
log.dim(` Seeded metadata_schema.json with ${seeded.join(', ')} fields`);
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
async function addSingleFile(filePath, client, options, batchDefaults) {
|
|
@@ -369,14 +369,14 @@ async function addSingleFile(filePath, client, options, batchDefaults) {
|
|
|
369
369
|
const hasRefMarker = cols.some(c => c.includes('=@reference'));
|
|
370
370
|
if (!hasRefMarker) {
|
|
371
371
|
if (options.yes) {
|
|
372
|
-
console.warn(`Warning: No @reference column in template for ${entity}${descriptor ? '.' + descriptor : ''} — skipping content column. Update .dbo/
|
|
372
|
+
console.warn(`Warning: No @reference column in template for ${entity}${descriptor ? '.' + descriptor : ''} — skipping content column. Update .dbo/metadata_schema.json to add Key=@reference.`);
|
|
373
373
|
} else {
|
|
374
374
|
const chosen = await promptReferenceColumn(cols, entity, descriptor);
|
|
375
375
|
if (chosen) {
|
|
376
376
|
cols = cols.map(c => c === chosen ? `${chosen}=@reference` : c);
|
|
377
|
-
templates = templates ?? await
|
|
377
|
+
templates = templates ?? await loadMetadataSchema() ?? {};
|
|
378
378
|
setTemplateCols(templates, entity, descriptor, cols);
|
|
379
|
-
await
|
|
379
|
+
await saveMetadataSchema(templates);
|
|
380
380
|
}
|
|
381
381
|
}
|
|
382
382
|
}
|
|
@@ -419,7 +419,7 @@ async function addSingleFile(filePath, client, options, batchDefaults) {
|
|
|
419
419
|
const contentCol = filenameCol === 'Name' ? 'String10' : 'String10';
|
|
420
420
|
const relPath = relative(process.cwd(), filePath).replace(/\\/g, '/');
|
|
421
421
|
docMeta[contentCol] = `@/${relPath}`;
|
|
422
|
-
docMeta.
|
|
422
|
+
docMeta._companionReferenceColumns = [contentCol];
|
|
423
423
|
|
|
424
424
|
const docMetaFile = join(companionDir, `${docBase}.metadata.json`);
|
|
425
425
|
await writeFile(docMetaFile, JSON.stringify(docMeta, null, 2) + '\n');
|
|
@@ -544,7 +544,7 @@ async function addSingleFile(filePath, client, options, batchDefaults) {
|
|
|
544
544
|
if (answers.Path.trim()) meta.Path = answers.Path.trim();
|
|
545
545
|
meta[answers.contentColumn.trim()] = `@${fileName}`;
|
|
546
546
|
meta._entity = answers.entity.trim();
|
|
547
|
-
meta.
|
|
547
|
+
meta._companionReferenceColumns = [answers.contentColumn.trim()];
|
|
548
548
|
|
|
549
549
|
// Write metadata file
|
|
550
550
|
await writeFile(metaPath, JSON.stringify(meta, null, 2) + '\n');
|
|
@@ -569,7 +569,7 @@ async function addSingleFile(filePath, client, options, batchDefaults) {
|
|
|
569
569
|
*/
|
|
570
570
|
export async function submitAdd(meta, metaPath, filePath, client, options) {
|
|
571
571
|
const entity = meta._entity;
|
|
572
|
-
const contentCols = new Set(meta._contentColumns || []);
|
|
572
|
+
const contentCols = new Set(meta._companionReferenceColumns || meta._contentColumns || []);
|
|
573
573
|
const metaDir = dirname(metaPath);
|
|
574
574
|
|
|
575
575
|
if (!entity) {
|
|
@@ -691,7 +691,7 @@ export async function submitAdd(meta, metaPath, filePath, client, options) {
|
|
|
691
691
|
if (serverTz && returnedLastUpdated) {
|
|
692
692
|
try {
|
|
693
693
|
await setFileTimestamps(newMetaPath, returnedLastUpdated, returnedLastUpdated, serverTz);
|
|
694
|
-
for (const col of (meta._contentColumns || [])) {
|
|
694
|
+
for (const col of (meta._companionReferenceColumns || meta._contentColumns || [])) {
|
|
695
695
|
const ref = meta[col];
|
|
696
696
|
if (ref && String(ref).startsWith('@')) {
|
|
697
697
|
const fp = join(metaDir, String(ref).substring(1));
|
|
@@ -835,7 +835,7 @@ export async function findUnaddedFiles(dir, ig, referencedFiles) {
|
|
|
835
835
|
const meta = JSON.parse(raw);
|
|
836
836
|
// Only count records that are on the server (have UID or _CreatedOn)
|
|
837
837
|
if (!meta.UID && !meta._CreatedOn) continue;
|
|
838
|
-
for (const col of (meta._contentColumns || [])) {
|
|
838
|
+
for (const col of (meta._companionReferenceColumns || meta._contentColumns || [])) {
|
|
839
839
|
const val = meta[col];
|
|
840
840
|
if (typeof val === 'string' && val.startsWith('@') && !val.startsWith('@/')) {
|
|
841
841
|
localRefs.add(val.substring(1));
|
|
@@ -912,7 +912,7 @@ async function _scanMetadataRefs(dir, referenced) {
|
|
|
912
912
|
const meta = JSON.parse(raw);
|
|
913
913
|
if (!meta._CreatedOn && !meta.UID) continue; // only count server-confirmed records
|
|
914
914
|
|
|
915
|
-
for (const col of (meta._contentColumns || [])) {
|
|
915
|
+
for (const col of (meta._companionReferenceColumns || meta._contentColumns || [])) {
|
|
916
916
|
const val = meta[col];
|
|
917
917
|
if (typeof val === 'string' && val.startsWith('@')) {
|
|
918
918
|
const ref = val.substring(1);
|