@dboio/cli 0.9.8 → 0.10.1
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 +38 -1
- package/bin/dbo.js +2 -0
- package/package.json +1 -1
- package/src/commands/add.js +46 -0
- package/src/commands/clone.js +557 -239
- package/src/commands/init.js +30 -32
- package/src/commands/pull.js +264 -87
- package/src/commands/push.js +502 -57
- package/src/commands/rm.js +1 -1
- package/src/commands/sync.js +68 -0
- package/src/lib/config.js +49 -8
- package/src/lib/delta.js +86 -25
- package/src/lib/diff.js +9 -3
- package/src/lib/folder-icon.js +120 -0
- package/src/lib/ignore.js +1 -1
- package/src/lib/input-parser.js +37 -10
- package/src/lib/scaffold.js +82 -2
- package/src/lib/structure.js +2 -0
package/src/lib/scaffold.js
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { mkdir, stat, writeFile, access } from 'fs/promises';
|
|
1
|
+
import { mkdir, stat, readFile, writeFile, access } from 'fs/promises';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { DEFAULT_PROJECT_DIRS } from './structure.js';
|
|
4
4
|
import { log } from './logger.js';
|
|
5
|
+
import { applyTrashIcon } from './folder-icon.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Scaffold the standard DBO project directory structure in cwd.
|
|
8
9
|
* Creates missing directories, skips existing ones, warns on name conflicts.
|
|
9
10
|
* Also creates app.json with {} if absent.
|
|
10
11
|
*
|
|
12
|
+
* When appShortName is provided, also creates media sub-directories:
|
|
13
|
+
* media/<appShortName>/app/
|
|
14
|
+
* media/<appShortName>/user/
|
|
15
|
+
*
|
|
11
16
|
* @param {string} [cwd=process.cwd()]
|
|
17
|
+
* @param {{ appShortName?: string }} [options]
|
|
12
18
|
* @returns {Promise<{ created: string[], skipped: string[], warned: string[] }>}
|
|
13
19
|
*/
|
|
14
|
-
export async function scaffoldProjectDirs(cwd = process.cwd()) {
|
|
20
|
+
export async function scaffoldProjectDirs(cwd = process.cwd(), options = {}) {
|
|
15
21
|
const created = [];
|
|
16
22
|
const skipped = [];
|
|
17
23
|
const warned = [];
|
|
@@ -33,6 +39,29 @@ export async function scaffoldProjectDirs(cwd = process.cwd()) {
|
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
// Create media sub-directories when app short name is known:
|
|
43
|
+
// media/<appShortName>/app/ — app-level media assets
|
|
44
|
+
// media/<appShortName>/user/ — user-uploaded media
|
|
45
|
+
if (options.appShortName) {
|
|
46
|
+
const mediaSubs = [
|
|
47
|
+
`media/${options.appShortName}/app`,
|
|
48
|
+
`media/${options.appShortName}/user`,
|
|
49
|
+
];
|
|
50
|
+
for (const sub of mediaSubs) {
|
|
51
|
+
const target = join(cwd, sub);
|
|
52
|
+
try {
|
|
53
|
+
await stat(target);
|
|
54
|
+
skipped.push(sub);
|
|
55
|
+
} catch {
|
|
56
|
+
await mkdir(target, { recursive: true });
|
|
57
|
+
created.push(sub);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Best-effort: apply trash icon to the trash directory
|
|
63
|
+
await applyTrashIcon(join(cwd, 'trash'));
|
|
64
|
+
|
|
36
65
|
// Create app.json if absent
|
|
37
66
|
const appJsonPath = join(cwd, 'app.json');
|
|
38
67
|
try {
|
|
@@ -42,6 +71,57 @@ export async function scaffoldProjectDirs(cwd = process.cwd()) {
|
|
|
42
71
|
created.push('app.json');
|
|
43
72
|
}
|
|
44
73
|
|
|
74
|
+
// Create manifest.json if absent
|
|
75
|
+
const manifestPath = join(cwd, 'manifest.json');
|
|
76
|
+
try {
|
|
77
|
+
await access(manifestPath);
|
|
78
|
+
} catch {
|
|
79
|
+
// Try to resolve values from local app.json; fall back to empty strings
|
|
80
|
+
let appName = '';
|
|
81
|
+
let shortName = '';
|
|
82
|
+
let description = '';
|
|
83
|
+
let bgColor = '#ffffff';
|
|
84
|
+
let domain = '';
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const appData = JSON.parse(await readFile(appJsonPath, 'utf8'));
|
|
88
|
+
appName = appData.Name || '';
|
|
89
|
+
shortName = appData.ShortName || '';
|
|
90
|
+
description = appData.Description || '';
|
|
91
|
+
domain = appData._domain || '';
|
|
92
|
+
|
|
93
|
+
// Find background_color from extension children (widget matching ShortName)
|
|
94
|
+
if (shortName && Array.isArray(appData.children?.extension)) {
|
|
95
|
+
for (const ext of appData.children.extension) {
|
|
96
|
+
if (ext.Descriptor === 'widget' && ext.String1 === shortName && ext.String4) {
|
|
97
|
+
bgColor = ext.String4;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
} catch { /* app.json missing or unparseable — use empty defaults */ }
|
|
103
|
+
|
|
104
|
+
const manifest = {
|
|
105
|
+
name: `${appName} | ${domain}`,
|
|
106
|
+
short_name: shortName,
|
|
107
|
+
description,
|
|
108
|
+
orientation: 'portrait',
|
|
109
|
+
start_url: shortName ? `/app/${shortName}/ui/` : '',
|
|
110
|
+
lang: 'en',
|
|
111
|
+
scope: shortName ? `/app/${shortName}/ui/` : '',
|
|
112
|
+
display_override: ['window-control-overlay', 'minimal-ui'],
|
|
113
|
+
display: 'standalone',
|
|
114
|
+
background_color: bgColor,
|
|
115
|
+
theme_color: '#000000',
|
|
116
|
+
id: shortName,
|
|
117
|
+
screenshots: [],
|
|
118
|
+
ios: {},
|
|
119
|
+
icons: [],
|
|
120
|
+
};
|
|
121
|
+
await writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
122
|
+
created.push('manifest.json');
|
|
123
|
+
}
|
|
124
|
+
|
|
45
125
|
return { created, skipped, warned };
|
|
46
126
|
}
|
|
47
127
|
|
package/src/lib/structure.js
CHANGED
|
@@ -13,6 +13,7 @@ export const DEFAULT_PROJECT_DIRS = [
|
|
|
13
13
|
'app_version',
|
|
14
14
|
'docs',
|
|
15
15
|
'site',
|
|
16
|
+
'media',
|
|
16
17
|
'extension',
|
|
17
18
|
'data_source',
|
|
18
19
|
'group',
|
|
@@ -43,6 +44,7 @@ export const ENTITY_DIR_NAMES = new Set([
|
|
|
43
44
|
'extension',
|
|
44
45
|
'app_version',
|
|
45
46
|
'data_source',
|
|
47
|
+
'media',
|
|
46
48
|
'site',
|
|
47
49
|
'group',
|
|
48
50
|
'integration',
|