@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.
Files changed (45) hide show
  1. package/README.md +175 -138
  2. package/bin/dbo.js +2 -2
  3. package/package.json +1 -1
  4. package/plugins/claude/dbo/docs/dbo-cli-readme.md +175 -138
  5. package/src/commands/adopt.js +534 -0
  6. package/src/commands/build.js +3 -3
  7. package/src/commands/clone.js +209 -75
  8. package/src/commands/deploy.js +3 -3
  9. package/src/commands/init.js +11 -11
  10. package/src/commands/install.js +3 -3
  11. package/src/commands/login.js +2 -2
  12. package/src/commands/mv.js +15 -15
  13. package/src/commands/pull.js +1 -1
  14. package/src/commands/push.js +194 -15
  15. package/src/commands/rm.js +2 -2
  16. package/src/commands/run.js +4 -4
  17. package/src/commands/status.js +1 -1
  18. package/src/commands/sync.js +2 -2
  19. package/src/lib/config.js +186 -135
  20. package/src/lib/delta.js +119 -17
  21. package/src/lib/dependencies.js +51 -24
  22. package/src/lib/deploy-config.js +4 -4
  23. package/src/lib/domain-guard.js +8 -9
  24. package/src/lib/filenames.js +13 -2
  25. package/src/lib/ignore.js +2 -3
  26. package/src/{commands/add.js → lib/insert.js} +127 -472
  27. package/src/lib/metadata-schema.js +14 -20
  28. package/src/lib/metadata-templates.js +4 -4
  29. package/src/lib/migrations.js +1 -1
  30. package/src/lib/modify-key.js +1 -1
  31. package/src/lib/scaffold.js +5 -12
  32. package/src/lib/schema.js +67 -37
  33. package/src/lib/structure.js +6 -6
  34. package/src/lib/tagging.js +2 -2
  35. package/src/lib/ticketing.js +3 -7
  36. package/src/lib/toe-stepping.js +5 -5
  37. package/src/lib/transaction-key.js +1 -1
  38. package/src/migrations/004-rename-output-files.js +2 -2
  39. package/src/migrations/005-rename-output-metadata.js +2 -2
  40. package/src/migrations/006-remove-uid-companion-filenames.js +1 -1
  41. package/src/migrations/007-natural-entity-companion-filenames.js +1 -1
  42. package/src/migrations/008-metadata-uid-in-suffix.js +1 -1
  43. package/src/migrations/009-fix-media-collision-metadata-names.js +1 -1
  44. package/src/migrations/010-delete-paren-media-orphans.js +1 -1
  45. 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
+ }