@dboio/cli 0.16.2 → 0.19.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 +175 -138
- package/bin/dbo.js +2 -2
- package/package.json +1 -1
- package/plugins/claude/dbo/docs/dbo-cli-readme.md +175 -138
- package/src/commands/adopt.js +534 -0
- package/src/commands/build.js +3 -3
- package/src/commands/clone.js +209 -75
- package/src/commands/deploy.js +3 -3
- package/src/commands/init.js +11 -11
- package/src/commands/install.js +3 -3
- package/src/commands/login.js +2 -2
- package/src/commands/mv.js +15 -15
- package/src/commands/pull.js +1 -1
- package/src/commands/push.js +194 -15
- package/src/commands/rm.js +2 -2
- package/src/commands/run.js +4 -4
- package/src/commands/status.js +1 -1
- package/src/commands/sync.js +2 -2
- package/src/lib/config.js +186 -135
- package/src/lib/delta.js +119 -17
- package/src/lib/dependencies.js +51 -24
- package/src/lib/deploy-config.js +4 -4
- package/src/lib/domain-guard.js +8 -9
- package/src/lib/filenames.js +13 -2
- package/src/lib/ignore.js +2 -3
- package/src/{commands/add.js → lib/insert.js} +127 -472
- package/src/lib/metadata-schema.js +14 -20
- package/src/lib/metadata-templates.js +4 -4
- package/src/lib/migrations.js +1 -1
- package/src/lib/modify-key.js +1 -1
- package/src/lib/scaffold.js +5 -12
- package/src/lib/schema.js +67 -37
- package/src/lib/structure.js +6 -6
- package/src/lib/tagging.js +2 -2
- package/src/lib/ticketing.js +3 -7
- package/src/lib/toe-stepping.js +5 -5
- package/src/lib/transaction-key.js +1 -1
- package/src/migrations/004-rename-output-files.js +2 -2
- package/src/migrations/005-rename-output-metadata.js +2 -2
- package/src/migrations/006-remove-uid-companion-filenames.js +1 -1
- package/src/migrations/007-natural-entity-companion-filenames.js +1 -1
- package/src/migrations/008-metadata-uid-in-suffix.js +1 -1
- package/src/migrations/009-fix-media-collision-metadata-names.js +1 -1
- package/src/migrations/010-delete-paren-media-orphans.js +1 -1
- package/src/migrations/012-project-dir-restructure.js +211 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { readFile, writeFile, rename, mkdir, rm, readdir, access } from 'fs/promises';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
|
|
5
|
+
export const description = 'Rename .dbo/ → .app/; rename baseline/structure/metadata files; move dependencies → app_dependencies/; move config.local.json → ~/.dbo/settings.json; remove schema.json';
|
|
6
|
+
|
|
7
|
+
async function fileExists(p) {
|
|
8
|
+
try { await access(p); return true; } catch { return false; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default async function run() {
|
|
12
|
+
const cwd = process.cwd();
|
|
13
|
+
const log = (...args) => console.log(...args);
|
|
14
|
+
|
|
15
|
+
const dboDirPath = join(cwd, '.dbo');
|
|
16
|
+
const appDirPath = join(cwd, '.app');
|
|
17
|
+
|
|
18
|
+
// Guard: skip if already on new layout
|
|
19
|
+
if (!(await fileExists(dboDirPath)) || (await fileExists(appDirPath))) {
|
|
20
|
+
log(' .dbo/ not found or .app/ already exists — skipping');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Step 1: Read AppShortName from .dbo/config.json BEFORE rename
|
|
25
|
+
let appShortName = null;
|
|
26
|
+
try {
|
|
27
|
+
const cfg = JSON.parse(await readFile(join(dboDirPath, 'config.json'), 'utf8'));
|
|
28
|
+
appShortName = cfg.AppShortName || null;
|
|
29
|
+
} catch { /* no config — proceed without AppShortName */ }
|
|
30
|
+
|
|
31
|
+
const safeName = appShortName
|
|
32
|
+
? String(appShortName).replace(/[/\\:*?"<>|]/g, '-')
|
|
33
|
+
: null;
|
|
34
|
+
|
|
35
|
+
// Step 2: Rename .dbo/ → .app/
|
|
36
|
+
try {
|
|
37
|
+
await rename(dboDirPath, appDirPath);
|
|
38
|
+
log(` Renamed .dbo/ → .app/`);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
log(` (skip) Could not rename .dbo/ → .app/: ${err.message}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Step 3: Rename .app/.app_baseline.json → .app/<shortName>.json
|
|
45
|
+
if (safeName) {
|
|
46
|
+
const oldBaseline = join(appDirPath, '.app_baseline.json');
|
|
47
|
+
const newBaseline = join(appDirPath, `${safeName}.json`);
|
|
48
|
+
if ((await fileExists(oldBaseline)) && !(await fileExists(newBaseline))) {
|
|
49
|
+
try {
|
|
50
|
+
await rename(oldBaseline, newBaseline);
|
|
51
|
+
log(` Renamed .app/.app_baseline.json → .app/${safeName}.json`);
|
|
52
|
+
} catch (e) { log(` (skip) baseline rename: ${e.message}`); }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Step 4: Rename .app/structure.json → .app/directories.json
|
|
57
|
+
const oldStructure = join(appDirPath, 'structure.json');
|
|
58
|
+
const newStructure = join(appDirPath, 'directories.json');
|
|
59
|
+
if ((await fileExists(oldStructure)) && !(await fileExists(newStructure))) {
|
|
60
|
+
try {
|
|
61
|
+
await rename(oldStructure, newStructure);
|
|
62
|
+
log(` Renamed .app/structure.json → .app/directories.json`);
|
|
63
|
+
} catch (e) { log(` (skip) structure rename: ${e.message}`); }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Step 4b: Rename .app/metadata_schema.json → .app/<shortName>.metadata_schema.json
|
|
67
|
+
if (safeName) {
|
|
68
|
+
const oldSchema = join(appDirPath, 'metadata_schema.json');
|
|
69
|
+
const newSchema = join(appDirPath, `${safeName}.metadata_schema.json`);
|
|
70
|
+
if ((await fileExists(oldSchema)) && !(await fileExists(newSchema))) {
|
|
71
|
+
try {
|
|
72
|
+
await rename(oldSchema, newSchema);
|
|
73
|
+
log(` Renamed .app/metadata_schema.json → .app/${safeName}.metadata_schema.json`);
|
|
74
|
+
} catch (e) { log(` (skip) metadata_schema rename: ${e.message}`); }
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Step 5: Move .app/dependencies/ → app_dependencies/
|
|
79
|
+
const oldDepsDir = join(appDirPath, 'dependencies');
|
|
80
|
+
const newDepsRoot = join(cwd, 'app_dependencies');
|
|
81
|
+
if (await fileExists(oldDepsDir)) {
|
|
82
|
+
try {
|
|
83
|
+
await mkdir(newDepsRoot, { recursive: true });
|
|
84
|
+
const depNames = await readdir(oldDepsDir);
|
|
85
|
+
for (const name of depNames) {
|
|
86
|
+
const src = join(oldDepsDir, name);
|
|
87
|
+
const dest = join(newDepsRoot, name);
|
|
88
|
+
if (!(await fileExists(dest))) {
|
|
89
|
+
await rename(src, dest);
|
|
90
|
+
log(` Moved app_dependencies/${name}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
try { await rm(oldDepsDir, { recursive: true }); } catch { /* non-empty */ }
|
|
94
|
+
} catch (e) { log(` (skip) dependencies move: ${e.message}`); }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Step 6: Move root app.json → .app/<shortName>.metadata.json
|
|
98
|
+
if (safeName) {
|
|
99
|
+
const rootAppJson = join(cwd, 'app.json');
|
|
100
|
+
const newMetaPath = join(appDirPath, `${safeName}.metadata.json`);
|
|
101
|
+
if ((await fileExists(rootAppJson)) && !(await fileExists(newMetaPath))) {
|
|
102
|
+
try {
|
|
103
|
+
await rename(rootAppJson, newMetaPath);
|
|
104
|
+
log(` Moved app.json → .app/${safeName}.metadata.json`);
|
|
105
|
+
} catch (e) { log(` (skip) app.json move: ${e.message}`); }
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Step 7: Remove root schema.json
|
|
110
|
+
const rootSchema = join(cwd, 'schema.json');
|
|
111
|
+
if (await fileExists(rootSchema)) {
|
|
112
|
+
try {
|
|
113
|
+
await rm(rootSchema);
|
|
114
|
+
log(` Removed schema.json (schema now sourced from app_dependencies/_system/.app/_system.json)`);
|
|
115
|
+
} catch (e) { log(` (skip) schema.json removal: ${e.message}`); }
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Step 8: Move .app/config.local.json → ~/.dbo/settings.json
|
|
119
|
+
const oldLocal = join(appDirPath, 'config.local.json');
|
|
120
|
+
const globalSettingsDir = join(homedir(), '.dbo');
|
|
121
|
+
const globalSettings = join(globalSettingsDir, 'settings.json');
|
|
122
|
+
if (await fileExists(oldLocal)) {
|
|
123
|
+
try {
|
|
124
|
+
await mkdir(globalSettingsDir, { recursive: true });
|
|
125
|
+
let oldData = {};
|
|
126
|
+
try { oldData = JSON.parse(await readFile(oldLocal, 'utf8')); } catch { /* ignore */ }
|
|
127
|
+
|
|
128
|
+
let newData = {};
|
|
129
|
+
try { newData = JSON.parse(await readFile(globalSettings, 'utf8')); } catch { /* new file */ }
|
|
130
|
+
|
|
131
|
+
if (oldData.plugins) {
|
|
132
|
+
if (!newData.plugins) newData.plugins = {};
|
|
133
|
+
Object.assign(newData.plugins, oldData.plugins);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (Array.isArray(oldData._completedMigrations) && oldData._completedMigrations.length > 0) {
|
|
137
|
+
if (!newData._completedMigrations) newData._completedMigrations = {};
|
|
138
|
+
const existing = new Set(Array.isArray(newData._completedMigrations[cwd]) ? newData._completedMigrations[cwd] : []);
|
|
139
|
+
for (const id of oldData._completedMigrations) existing.add(id);
|
|
140
|
+
newData._completedMigrations[cwd] = [...existing].sort();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
await writeFile(globalSettings, JSON.stringify(newData, null, 2) + '\n');
|
|
144
|
+
try { await rm(oldLocal); } catch { /* leave it */ }
|
|
145
|
+
log(` Merged .app/config.local.json → ~/.dbo/settings.json`);
|
|
146
|
+
} catch (e) { log(` (skip) config.local.json merge: ${e.message}`); }
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Step 9: Update .gitignore
|
|
150
|
+
const gitignorePath = join(cwd, '.gitignore');
|
|
151
|
+
try {
|
|
152
|
+
let content = '';
|
|
153
|
+
try { content = await readFile(gitignorePath, 'utf8'); } catch { /* no .gitignore */ }
|
|
154
|
+
|
|
155
|
+
const replacements = [
|
|
156
|
+
['.dbo/credentials.json', '.app/credentials.json'],
|
|
157
|
+
['.dbo/cookies.txt', '.app/cookies.txt'],
|
|
158
|
+
['.dbo/config.local.json', null],
|
|
159
|
+
['.dbo/.app_baseline.json', null],
|
|
160
|
+
['.dbo/ticketing.local.json', '.app/ticketing.local.json'],
|
|
161
|
+
['.dbo/scripts.local.json', '.app/scripts.local.json'],
|
|
162
|
+
['.dbo/errors.log', '.app/errors.log'],
|
|
163
|
+
['.dbo/dependencies/', null],
|
|
164
|
+
['schema.json', null],
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
let changed = false;
|
|
168
|
+
let lines = content.split('\n');
|
|
169
|
+
|
|
170
|
+
for (const [oldPat, newPat] of replacements) {
|
|
171
|
+
const idx = lines.findIndex(l => l.trim() === oldPat);
|
|
172
|
+
if (idx >= 0) {
|
|
173
|
+
if (newPat) { lines[idx] = newPat; }
|
|
174
|
+
else lines.splice(idx, 1);
|
|
175
|
+
changed = true;
|
|
176
|
+
} else if (newPat && !content.includes(newPat)) {
|
|
177
|
+
lines.push(newPat);
|
|
178
|
+
changed = true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (!content.includes('app_dependencies/')) {
|
|
183
|
+
lines.push('app_dependencies/');
|
|
184
|
+
changed = true;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (changed) {
|
|
188
|
+
await writeFile(gitignorePath, lines.join('\n'));
|
|
189
|
+
log(` Updated .gitignore with new .app/ paths`);
|
|
190
|
+
}
|
|
191
|
+
} catch (e) { log(` (skip) .gitignore update: ${e.message}`); }
|
|
192
|
+
|
|
193
|
+
// Step 10: Update .dboignore
|
|
194
|
+
const dboignorePath = join(cwd, '.dboignore');
|
|
195
|
+
try {
|
|
196
|
+
let content = await readFile(dboignorePath, 'utf8');
|
|
197
|
+
const updated = content
|
|
198
|
+
.replace(/^\.dbo\/$/m, '.app/')
|
|
199
|
+
.replace(/^\.dbo\/dependencies\/$/m, '')
|
|
200
|
+
.replace(/^app\.json$/m, '');
|
|
201
|
+
if (!updated.includes('app_dependencies/')) {
|
|
202
|
+
const finalContent = updated.replace(/^\.app\/$/m, '.app/\napp_dependencies/');
|
|
203
|
+
await writeFile(dboignorePath, finalContent);
|
|
204
|
+
} else {
|
|
205
|
+
await writeFile(dboignorePath, updated);
|
|
206
|
+
}
|
|
207
|
+
log(` Updated .dboignore`);
|
|
208
|
+
} catch { /* no .dboignore */ }
|
|
209
|
+
|
|
210
|
+
log(` Migration 012 complete: .dbo/ → .app/`);
|
|
211
|
+
}
|