@dboio/cli 0.15.3 → 0.17.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 +165 -76
- package/bin/dbo.js +2 -2
- package/package.json +1 -1
- package/plugins/claude/dbo/docs/dbo-cli-readme.md +165 -76
- package/src/commands/adopt.js +534 -0
- package/src/commands/clone.js +365 -143
- 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 +13 -9
- 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 +3 -3
- package/src/lib/ignore.js +1 -0
- package/src/{commands/add.js → lib/insert.js} +133 -478
- 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
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { readFile, writeFile, rename, readdir, rm, utimes } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { stat } from 'fs/promises';
|
|
4
|
+
|
|
5
|
+
export const description = 'Rename metadata_templates.json → metadata_schema.json; migrate _contentColumns → _companionReferenceColumns; remove _unsupported dir; retire Extension_* config keys';
|
|
6
|
+
|
|
7
|
+
export default async function run(_options) {
|
|
8
|
+
const log = (...args) => console.log(...args);
|
|
9
|
+
|
|
10
|
+
// ── Step 1: Rename .dbo/metadata_templates.json → .dbo/metadata_schema.json ──
|
|
11
|
+
try {
|
|
12
|
+
const oldPath = '.dbo/metadata_templates.json';
|
|
13
|
+
const newPath = '.dbo/metadata_schema.json';
|
|
14
|
+
if (await fileExists(oldPath) && !(await fileExists(newPath))) {
|
|
15
|
+
await rename(oldPath, newPath);
|
|
16
|
+
log(` Renamed .dbo/metadata_templates.json → .dbo/metadata_schema.json`);
|
|
17
|
+
} else if (await fileExists(newPath)) {
|
|
18
|
+
log(` .dbo/metadata_schema.json already exists — skipping rename`);
|
|
19
|
+
}
|
|
20
|
+
} catch (e) {
|
|
21
|
+
log(` (skip) metadata_templates rename: ${e.message}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ── Step 2: Rename _contentColumns → _companionReferenceColumns in all metadata files ──
|
|
25
|
+
try {
|
|
26
|
+
const metaFiles = await findMetadataFiles('.');
|
|
27
|
+
let updated = 0;
|
|
28
|
+
for (const file of metaFiles) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = await readFile(file, 'utf8');
|
|
31
|
+
const obj = JSON.parse(raw);
|
|
32
|
+
if ('_contentColumns' in obj && !('_companionReferenceColumns' in obj)) {
|
|
33
|
+
// Preserve file timestamps so the write doesn't cause false
|
|
34
|
+
// "local changes" detections during the subsequent clone/pull.
|
|
35
|
+
const before = await stat(file);
|
|
36
|
+
obj._companionReferenceColumns = obj._contentColumns;
|
|
37
|
+
delete obj._contentColumns;
|
|
38
|
+
await writeFile(file, JSON.stringify(obj, null, 2) + '\n');
|
|
39
|
+
await utimes(file, before.atime, before.mtime);
|
|
40
|
+
updated++;
|
|
41
|
+
}
|
|
42
|
+
} catch { /* skip malformed files */ }
|
|
43
|
+
}
|
|
44
|
+
if (updated > 0) log(` Migrated _contentColumns in ${updated} metadata file(s)`);
|
|
45
|
+
} catch (e) {
|
|
46
|
+
log(` (skip) _contentColumns rename: ${e.message}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ── Step 3: Move lib/extension/_unsupported/* → lib/extension/ ──
|
|
50
|
+
try {
|
|
51
|
+
const unsupportedDir = 'lib/extension/_unsupported';
|
|
52
|
+
if (await fileExists(unsupportedDir)) {
|
|
53
|
+
const files = await readdir(unsupportedDir);
|
|
54
|
+
let moved = 0;
|
|
55
|
+
for (const file of files) {
|
|
56
|
+
const src = join(unsupportedDir, file);
|
|
57
|
+
const dst = join('lib/extension', file);
|
|
58
|
+
try {
|
|
59
|
+
await rename(src, dst);
|
|
60
|
+
moved++;
|
|
61
|
+
} catch (e) {
|
|
62
|
+
log(` (warn) Could not move ${file}: ${e.message}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
await rm(unsupportedDir, { recursive: true, force: true });
|
|
67
|
+
} catch { /* ignore */ }
|
|
68
|
+
if (moved > 0) log(` Moved ${moved} file(s) from lib/extension/_unsupported/ to lib/extension/`);
|
|
69
|
+
}
|
|
70
|
+
} catch (e) {
|
|
71
|
+
log(` (skip) _unsupported relocation: ${e.message}`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Step 4: Remove retired config.json keys ──
|
|
75
|
+
try {
|
|
76
|
+
const configPath = '.dbo/config.json';
|
|
77
|
+
const raw = await readFile(configPath, 'utf8');
|
|
78
|
+
const config = JSON.parse(raw);
|
|
79
|
+
const retiredPattern = /^Extension_.+_(FilenameCol|ContentExtractions)$|^ExtensionFilenameCol$/;
|
|
80
|
+
const keysToRemove = Object.keys(config).filter(k => retiredPattern.test(k));
|
|
81
|
+
if (keysToRemove.length > 0) {
|
|
82
|
+
for (const k of keysToRemove) delete config[k];
|
|
83
|
+
await writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
|
|
84
|
+
log(` Removed ${keysToRemove.length} retired config key(s): ${keysToRemove.join(', ')}`);
|
|
85
|
+
}
|
|
86
|
+
} catch (e) {
|
|
87
|
+
log(` (skip) config key retirement: ${e.message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function fileExists(p) {
|
|
92
|
+
try {
|
|
93
|
+
await stat(p);
|
|
94
|
+
return true;
|
|
95
|
+
} catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function findMetadataFiles(dir) {
|
|
101
|
+
const results = [];
|
|
102
|
+
async function walk(d) {
|
|
103
|
+
let entries;
|
|
104
|
+
try {
|
|
105
|
+
entries = await readdir(d, { withFileTypes: true });
|
|
106
|
+
} catch {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
for (const entry of entries) {
|
|
110
|
+
const full = join(d, entry.name);
|
|
111
|
+
if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules' && entry.name !== 'trash') {
|
|
112
|
+
await walk(full);
|
|
113
|
+
} else if (entry.isFile() && /\.metadata~[^.]+\.json$/.test(entry.name)) {
|
|
114
|
+
results.push(full);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
await walk(dir);
|
|
119
|
+
return results;
|
|
120
|
+
}
|