@leeoohoo/ui-apps-devkit 0.1.1 → 0.1.3
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 +84 -76
- package/bin/chatos-uiapp.js +3 -4
- package/package.json +28 -25
- package/src/cli.js +53 -53
- package/src/commands/dev.js +14 -14
- package/src/commands/init.js +143 -142
- package/src/commands/install.js +56 -55
- package/src/commands/pack.js +72 -72
- package/src/commands/validate.js +113 -113
- package/src/lib/args.js +49 -49
- package/src/lib/config.js +29 -29
- package/src/lib/fs.js +78 -78
- package/src/lib/path-boundary.js +16 -16
- package/src/lib/plugin.js +45 -45
- package/src/lib/state-constants.js +2 -0
- package/src/lib/template.js +172 -172
- package/src/sandbox/server.js +2302 -1200
- package/templates/basic/README.md +80 -77
- package/templates/basic/chatos.config.json +5 -5
- package/templates/basic/docs/CHATOS_UI_APPS_AI_CONTRIBUTIONS.md +178 -178
- package/templates/basic/docs/CHATOS_UI_APPS_BACKEND_PROTOCOL.md +75 -74
- package/templates/basic/docs/CHATOS_UI_APPS_HOST_API.md +136 -136
- package/templates/basic/docs/CHATOS_UI_APPS_OVERVIEW.md +115 -113
- package/templates/basic/docs/CHATOS_UI_APPS_PLUGIN_MANIFEST.md +225 -224
- package/templates/basic/docs/CHATOS_UI_APPS_STYLE_GUIDE.md +95 -95
- package/templates/basic/docs/CHATOS_UI_APPS_TROUBLESHOOTING.md +45 -45
- package/templates/basic/docs/CHATOS_UI_PROMPTS_PROTOCOL.md +392 -392
- package/templates/basic/plugin/apps/app/compact.mjs +41 -41
- package/templates/basic/plugin/apps/app/index.mjs +287 -287
- package/templates/basic/plugin/apps/app/mcp-prompt.en.md +7 -7
- package/templates/basic/plugin/apps/app/mcp-prompt.zh.md +7 -7
- package/templates/basic/plugin/apps/app/mcp-server.mjs +15 -15
- package/templates/basic/plugin/backend/index.mjs +37 -37
- package/templates/basic/template.json +7 -7
- package/templates/notepad/README.md +61 -58
- package/templates/notepad/chatos.config.json +4 -4
- package/templates/notepad/docs/CHATOS_UI_APPS_AI_CONTRIBUTIONS.md +178 -178
- package/templates/notepad/docs/CHATOS_UI_APPS_BACKEND_PROTOCOL.md +75 -74
- package/templates/notepad/docs/CHATOS_UI_APPS_HOST_API.md +136 -136
- package/templates/notepad/docs/CHATOS_UI_APPS_OVERVIEW.md +115 -113
- package/templates/notepad/docs/CHATOS_UI_APPS_PLUGIN_MANIFEST.md +225 -224
- package/templates/notepad/docs/CHATOS_UI_APPS_STYLE_GUIDE.md +95 -95
- package/templates/notepad/docs/CHATOS_UI_APPS_TROUBLESHOOTING.md +45 -45
- package/templates/notepad/docs/CHATOS_UI_PROMPTS_PROTOCOL.md +392 -392
- package/templates/notepad/plugin/apps/app/api.mjs +30 -30
- package/templates/notepad/plugin/apps/app/compact.mjs +41 -41
- package/templates/notepad/plugin/apps/app/dom.mjs +14 -14
- package/templates/notepad/plugin/apps/app/ds-tree.mjs +35 -35
- package/templates/notepad/plugin/apps/app/index.mjs +1056 -1056
- package/templates/notepad/plugin/apps/app/layers.mjs +338 -338
- package/templates/notepad/plugin/apps/app/markdown.mjs +120 -120
- package/templates/notepad/plugin/apps/app/mcp-prompt.en.md +22 -22
- package/templates/notepad/plugin/apps/app/mcp-prompt.zh.md +22 -22
- package/templates/notepad/plugin/apps/app/mcp-server.mjs +207 -200
- package/templates/notepad/plugin/apps/app/styles.mjs +355 -355
- package/templates/notepad/plugin/apps/app/tags.mjs +21 -21
- package/templates/notepad/plugin/apps/app/ui.mjs +280 -280
- package/templates/notepad/plugin/backend/index.mjs +99 -99
- package/templates/notepad/plugin/plugin.json +23 -23
- package/templates/notepad/plugin/shared/notepad-paths.mjs +80 -62
- package/templates/notepad/plugin/shared/notepad-store.mjs +765 -765
- package/templates/notepad/template.json +8 -8
package/src/commands/init.js
CHANGED
|
@@ -1,142 +1,143 @@
|
|
|
1
|
-
import path from 'path';
|
|
2
|
-
import readline from 'readline';
|
|
3
|
-
|
|
4
|
-
import { ensureDir, isDirectory, isFile, rmForce, writeText } from '../lib/fs.js';
|
|
5
|
-
import {
|
|
6
|
-
copyTemplate,
|
|
7
|
-
listTemplates,
|
|
8
|
-
readTemplateMeta,
|
|
9
|
-
maybeReplaceTokensInFile,
|
|
10
|
-
writeScaffoldConfig,
|
|
11
|
-
writeScaffoldManifest,
|
|
12
|
-
writeScaffoldPackageJson,
|
|
13
|
-
} from '../lib/template.js';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const appId
|
|
80
|
-
|
|
81
|
-
(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
maybeReplaceTokensInFile(path.join(destDir, '
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
maybeReplaceTokensInFile(path.join(
|
|
123
|
-
maybeReplaceTokensInFile(path.join(dstAppDir, '
|
|
124
|
-
maybeReplaceTokensInFile(path.join(dstAppDir, '
|
|
125
|
-
maybeReplaceTokensInFile(path.join(dstAppDir, 'mcp-
|
|
126
|
-
maybeReplaceTokensInFile(path.join(dstAppDir, 'mcp-prompt.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
console
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
npm
|
|
141
|
-
|
|
142
|
-
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import readline from 'readline';
|
|
3
|
+
|
|
4
|
+
import { ensureDir, isDirectory, isFile, rmForce, writeText } from '../lib/fs.js';
|
|
5
|
+
import {
|
|
6
|
+
copyTemplate,
|
|
7
|
+
listTemplates,
|
|
8
|
+
readTemplateMeta,
|
|
9
|
+
maybeReplaceTokensInFile,
|
|
10
|
+
writeScaffoldConfig,
|
|
11
|
+
writeScaffoldManifest,
|
|
12
|
+
writeScaffoldPackageJson,
|
|
13
|
+
} from '../lib/template.js';
|
|
14
|
+
import { COMPAT_STATE_ROOT_DIRNAME, STATE_ROOT_DIRNAME } from '../lib/state-constants.js';
|
|
15
|
+
|
|
16
|
+
function canPrompt() {
|
|
17
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function promptLine(question, { defaultValue = '' } = {}) {
|
|
21
|
+
if (!canPrompt()) throw new Error(`Missing required value: ${question}`);
|
|
22
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
23
|
+
try {
|
|
24
|
+
const answer = await new Promise((resolve) => rl.question(question, resolve));
|
|
25
|
+
const v = String(answer || '').trim();
|
|
26
|
+
return v || defaultValue;
|
|
27
|
+
} finally {
|
|
28
|
+
rl.close();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function cmdInit({ positionals, flags }) {
|
|
33
|
+
const list = Boolean(flags['list-templates'] || flags.listTemplates);
|
|
34
|
+
if (list) {
|
|
35
|
+
const templates = listTemplates();
|
|
36
|
+
if (templates.length === 0) {
|
|
37
|
+
// eslint-disable-next-line no-console
|
|
38
|
+
console.log('No templates found.');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const lines = templates.map((t) => `- ${t.name}${t.description ? `: ${t.description}` : ''}`).join('\n');
|
|
42
|
+
// eslint-disable-next-line no-console
|
|
43
|
+
console.log(`Templates:\n${lines}\n\nUse:\n chatos-uiapp init my-app --template <name>\n`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const dirArg = String(positionals[0] || '').trim();
|
|
48
|
+
if (!dirArg) throw new Error('init requires <dir>');
|
|
49
|
+
|
|
50
|
+
const templateName = String(flags.template || flags.t || '').trim() || 'basic';
|
|
51
|
+
const templateMeta = readTemplateMeta(templateName);
|
|
52
|
+
|
|
53
|
+
const destDir = path.resolve(process.cwd(), dirArg);
|
|
54
|
+
const force = Boolean(flags.force);
|
|
55
|
+
|
|
56
|
+
if (isDirectory(destDir)) {
|
|
57
|
+
const entries = await (async () => {
|
|
58
|
+
try {
|
|
59
|
+
return (await import('fs')).default.readdirSync(destDir);
|
|
60
|
+
} catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
})();
|
|
64
|
+
if (entries.length > 0 && !force) {
|
|
65
|
+
throw new Error(`Target directory is not empty: ${destDir} (use --force to overwrite)`);
|
|
66
|
+
}
|
|
67
|
+
if (force) rmForce(destDir);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
ensureDir(destDir);
|
|
71
|
+
copyTemplate({ templateName, destDir });
|
|
72
|
+
|
|
73
|
+
const pluginId =
|
|
74
|
+
String(flags['plugin-id'] || flags.pluginId || '').trim() || (await promptLine('pluginId (e.g. com.example.myapp): '));
|
|
75
|
+
const pluginName =
|
|
76
|
+
String(flags.name || '').trim() ||
|
|
77
|
+
(await promptLine('plugin name (display): ', { defaultValue: String(templateMeta?.defaults?.pluginName || '').trim() || pluginId }));
|
|
78
|
+
|
|
79
|
+
const defaultAppId = String(templateMeta?.defaults?.appId || '').trim() || 'app';
|
|
80
|
+
const appId =
|
|
81
|
+
String(flags['app-id'] || flags.appId || '').trim() ||
|
|
82
|
+
(await promptLine('appId (e.g. manager): ', { defaultValue: defaultAppId }));
|
|
83
|
+
|
|
84
|
+
const version = String(flags.version || '').trim() || String(templateMeta?.defaults?.version || '').trim() || '0.1.0';
|
|
85
|
+
|
|
86
|
+
const pluginDir = path.join(destDir, 'plugin');
|
|
87
|
+
ensureDir(pluginDir);
|
|
88
|
+
|
|
89
|
+
if (!isFile(path.join(pluginDir, 'plugin.json'))) {
|
|
90
|
+
const withBackend = templateMeta?.defaults?.withBackend !== false;
|
|
91
|
+
writeScaffoldManifest({ destPluginDir: pluginDir, pluginId, pluginName, version, appId, withBackend });
|
|
92
|
+
}
|
|
93
|
+
writeScaffoldPackageJson({ destDir, projectName: path.basename(destDir) });
|
|
94
|
+
writeScaffoldConfig({ destDir, pluginDir: 'plugin', appId });
|
|
95
|
+
|
|
96
|
+
// rename template app folder "app" -> actual appId
|
|
97
|
+
const srcAppDir = path.join(pluginDir, 'apps', 'app');
|
|
98
|
+
const dstAppDir = path.join(pluginDir, 'apps', appId);
|
|
99
|
+
try {
|
|
100
|
+
const fs = (await import('fs')).default;
|
|
101
|
+
if (fs.existsSync(srcAppDir) && fs.statSync(srcAppDir).isDirectory()) {
|
|
102
|
+
ensureDir(path.dirname(dstAppDir));
|
|
103
|
+
fs.renameSync(srcAppDir, dstAppDir);
|
|
104
|
+
}
|
|
105
|
+
} catch {
|
|
106
|
+
// ignore
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Token replacements inside README/template code.
|
|
110
|
+
const replacements = {
|
|
111
|
+
__PLUGIN_ID__: pluginId,
|
|
112
|
+
__PLUGIN_NAME__: pluginName,
|
|
113
|
+
__APP_ID__: appId,
|
|
114
|
+
__VERSION__: version,
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
maybeReplaceTokensInFile(path.join(destDir, 'README.md'), replacements);
|
|
118
|
+
maybeReplaceTokensInFile(path.join(destDir, 'chatos.config.json'), replacements);
|
|
119
|
+
if (isFile(path.join(pluginDir, 'plugin.json'))) {
|
|
120
|
+
maybeReplaceTokensInFile(path.join(pluginDir, 'plugin.json'), replacements);
|
|
121
|
+
}
|
|
122
|
+
maybeReplaceTokensInFile(path.join(pluginDir, 'backend', 'index.mjs'), replacements);
|
|
123
|
+
maybeReplaceTokensInFile(path.join(dstAppDir, 'index.mjs'), replacements);
|
|
124
|
+
maybeReplaceTokensInFile(path.join(dstAppDir, 'compact.mjs'), replacements);
|
|
125
|
+
maybeReplaceTokensInFile(path.join(dstAppDir, 'mcp-server.mjs'), replacements);
|
|
126
|
+
maybeReplaceTokensInFile(path.join(dstAppDir, 'mcp-prompt.zh.md'), replacements);
|
|
127
|
+
maybeReplaceTokensInFile(path.join(dstAppDir, 'mcp-prompt.en.md'), replacements);
|
|
128
|
+
|
|
129
|
+
// Ensure a helpful note exists even if template is edited later.
|
|
130
|
+
writeText(
|
|
131
|
+
path.join(destDir, '.gitignore'),
|
|
132
|
+
`node_modules/\n.DS_Store\n${STATE_ROOT_DIRNAME}/\n${COMPAT_STATE_ROOT_DIRNAME}/\n*.log\n\n# build outputs (if you add bundling later)\ndist/\n`
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// eslint-disable-next-line no-console
|
|
136
|
+
console.log(`Created: ${destDir}
|
|
137
|
+
|
|
138
|
+
Next:
|
|
139
|
+
cd ${dirArg}
|
|
140
|
+
npm install
|
|
141
|
+
npm run dev
|
|
142
|
+
`);
|
|
143
|
+
}
|
package/src/commands/install.js
CHANGED
|
@@ -1,55 +1,56 @@
|
|
|
1
|
-
import os from 'os';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
|
|
4
|
-
import { copyDir, ensureDir, isDirectory, rmForce, sanitizeDirComponent } from '../lib/fs.js';
|
|
5
|
-
import { loadDevkitConfig } from '../lib/config.js';
|
|
6
|
-
import { findPluginDir, loadPluginManifest } from '../lib/plugin.js';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
if (base === '
|
|
21
|
-
if (base === '.
|
|
22
|
-
if (base
|
|
23
|
-
return
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
console
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
`
|
|
52
|
-
`
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import { copyDir, ensureDir, isDirectory, rmForce, sanitizeDirComponent } from '../lib/fs.js';
|
|
5
|
+
import { loadDevkitConfig } from '../lib/config.js';
|
|
6
|
+
import { findPluginDir, loadPluginManifest } from '../lib/plugin.js';
|
|
7
|
+
import { STATE_ROOT_DIRNAME } from '../lib/state-constants.js';
|
|
8
|
+
|
|
9
|
+
function defaultStateDir(hostApp) {
|
|
10
|
+
const app = typeof hostApp === 'string' && hostApp.trim() ? hostApp.trim() : 'chatos';
|
|
11
|
+
return path.join(os.homedir(), STATE_ROOT_DIRNAME, app);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function copyPluginDir(srcDir, destDir) {
|
|
15
|
+
ensureDir(path.dirname(destDir));
|
|
16
|
+
rmForce(destDir);
|
|
17
|
+
copyDir(srcDir, destDir, {
|
|
18
|
+
filter: (src) => {
|
|
19
|
+
const base = path.basename(src);
|
|
20
|
+
if (base === 'node_modules') return false;
|
|
21
|
+
if (base === '.git') return false;
|
|
22
|
+
if (base === '.DS_Store') return false;
|
|
23
|
+
if (base.endsWith('.map')) return false;
|
|
24
|
+
return true;
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function cmdInstall({ flags }) {
|
|
30
|
+
const { config } = loadDevkitConfig(process.cwd());
|
|
31
|
+
const pluginDir = findPluginDir(process.cwd(), flags['plugin-dir'] || flags.pluginDir || config?.pluginDir);
|
|
32
|
+
const { pluginId, name, version } = loadPluginManifest(pluginDir);
|
|
33
|
+
|
|
34
|
+
const hostApp = String(flags['host-app'] || flags.hostApp || 'chatos').trim() || 'chatos';
|
|
35
|
+
const stateDir = String(flags['state-dir'] || flags.stateDir || defaultStateDir(hostApp)).trim();
|
|
36
|
+
if (!stateDir) throw new Error('stateDir is required');
|
|
37
|
+
|
|
38
|
+
const pluginsRoot = path.join(stateDir, 'ui_apps', 'plugins');
|
|
39
|
+
ensureDir(pluginsRoot);
|
|
40
|
+
|
|
41
|
+
const dirName = sanitizeDirComponent(pluginId);
|
|
42
|
+
if (!dirName) throw new Error(`Invalid plugin id: ${pluginId}`);
|
|
43
|
+
|
|
44
|
+
const destDir = path.join(pluginsRoot, dirName);
|
|
45
|
+
const replaced = isDirectory(destDir);
|
|
46
|
+
copyPluginDir(pluginDir, destDir);
|
|
47
|
+
|
|
48
|
+
// eslint-disable-next-line no-console
|
|
49
|
+
console.log(
|
|
50
|
+
`Installed: ${pluginId} (${name}@${version})\n` +
|
|
51
|
+
` -> ${destDir}\n` +
|
|
52
|
+
` replaced: ${replaced}\n\n` +
|
|
53
|
+
`Open ChatOS -> 应用 -> 刷新(同 id 覆盖生效)。`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
package/src/commands/pack.js
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
import os from 'os';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { spawnSync } from 'child_process';
|
|
4
|
-
|
|
5
|
-
import { copyDir, ensureDir, rmForce } from '../lib/fs.js';
|
|
6
|
-
import { loadDevkitConfig } from '../lib/config.js';
|
|
7
|
-
import { findPluginDir, loadPluginManifest } from '../lib/plugin.js';
|
|
8
|
-
|
|
9
|
-
function hasCmd(cmd) {
|
|
10
|
-
const res = spawnSync('sh', ['-lc', `command -v ${cmd} >/dev/null 2>&1`], { stdio: 'ignore' });
|
|
11
|
-
return res.status === 0;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function packWithZip({ cwd, srcDir, outFile }) {
|
|
15
|
-
// zip -r out.zip . (from within srcDir)
|
|
16
|
-
const res = spawnSync('zip', ['-r', outFile, '.'], { cwd: srcDir, stdio: 'inherit' });
|
|
17
|
-
if (res.status !== 0) throw new Error('zip failed');
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function packWithPowershell({ srcDir, outFile }) {
|
|
21
|
-
const script = `Compress-Archive -Path "${srcDir}\\*" -DestinationPath "${outFile}" -Force`;
|
|
22
|
-
const res = spawnSync('powershell', ['-NoProfile', '-Command', script], { stdio: 'inherit' });
|
|
23
|
-
if (res.status !== 0) throw new Error('powershell Compress-Archive failed');
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export async function cmdPack({ flags }) {
|
|
27
|
-
const { config } = loadDevkitConfig(process.cwd());
|
|
28
|
-
const pluginDir = findPluginDir(process.cwd(), flags['plugin-dir'] || flags.pluginDir || config?.pluginDir);
|
|
29
|
-
const { pluginId, version } = loadPluginManifest(pluginDir);
|
|
30
|
-
|
|
31
|
-
const outArg = String(flags.out || '').trim();
|
|
32
|
-
const outDir = outArg ? path.dirname(path.resolve(process.cwd(), outArg)) : path.join(process.cwd(), 'dist');
|
|
33
|
-
ensureDir(outDir);
|
|
34
|
-
|
|
35
|
-
const outFile = outArg
|
|
36
|
-
? path.resolve(process.cwd(), outArg)
|
|
37
|
-
: path.join(outDir, `${pluginId.replace(/[^a-zA-Z0-9._-]+/g, '-')}-${version || '0.0.0'}.zip`);
|
|
38
|
-
|
|
39
|
-
rmForce(outFile);
|
|
40
|
-
|
|
41
|
-
const stagingBase = path.join(os.tmpdir(), `chatos-uiapp-pack-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
42
|
-
ensureDir(stagingBase);
|
|
43
|
-
try {
|
|
44
|
-
// mimic ChatOS importer: exclude node_modules/.git/*.map/.DS_Store
|
|
45
|
-
copyDir(pluginDir, stagingBase, {
|
|
46
|
-
filter: (src) => {
|
|
47
|
-
const base = path.basename(src);
|
|
48
|
-
if (base === 'node_modules') return false;
|
|
49
|
-
if (base === '.git') return false;
|
|
50
|
-
if (base === '.DS_Store') return false;
|
|
51
|
-
if (base.endsWith('.map')) return false;
|
|
52
|
-
return true;
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const platform = process.platform;
|
|
57
|
-
if (hasCmd('zip')) {
|
|
58
|
-
packWithZip({ cwd: process.cwd(), srcDir: stagingBase, outFile });
|
|
59
|
-
} else if (platform === 'win32') {
|
|
60
|
-
packWithPowershell({ srcDir: stagingBase, outFile });
|
|
61
|
-
} else {
|
|
62
|
-
throw new Error('zip command not found (install "zip" or run on Windows with powershell)');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// eslint-disable-next-line no-console
|
|
66
|
-
console.log(`Packed: ${outFile}
|
|
67
|
-
|
|
68
|
-
ChatOS -> 应用 -> 导入应用包 -> 选择该 zip`);
|
|
69
|
-
} finally {
|
|
70
|
-
rmForce(stagingBase);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { spawnSync } from 'child_process';
|
|
4
|
+
|
|
5
|
+
import { copyDir, ensureDir, rmForce } from '../lib/fs.js';
|
|
6
|
+
import { loadDevkitConfig } from '../lib/config.js';
|
|
7
|
+
import { findPluginDir, loadPluginManifest } from '../lib/plugin.js';
|
|
8
|
+
|
|
9
|
+
function hasCmd(cmd) {
|
|
10
|
+
const res = spawnSync('sh', ['-lc', `command -v ${cmd} >/dev/null 2>&1`], { stdio: 'ignore' });
|
|
11
|
+
return res.status === 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function packWithZip({ cwd, srcDir, outFile }) {
|
|
15
|
+
// zip -r out.zip . (from within srcDir)
|
|
16
|
+
const res = spawnSync('zip', ['-r', outFile, '.'], { cwd: srcDir, stdio: 'inherit' });
|
|
17
|
+
if (res.status !== 0) throw new Error('zip failed');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function packWithPowershell({ srcDir, outFile }) {
|
|
21
|
+
const script = `Compress-Archive -Path "${srcDir}\\*" -DestinationPath "${outFile}" -Force`;
|
|
22
|
+
const res = spawnSync('powershell', ['-NoProfile', '-Command', script], { stdio: 'inherit' });
|
|
23
|
+
if (res.status !== 0) throw new Error('powershell Compress-Archive failed');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function cmdPack({ flags }) {
|
|
27
|
+
const { config } = loadDevkitConfig(process.cwd());
|
|
28
|
+
const pluginDir = findPluginDir(process.cwd(), flags['plugin-dir'] || flags.pluginDir || config?.pluginDir);
|
|
29
|
+
const { pluginId, version } = loadPluginManifest(pluginDir);
|
|
30
|
+
|
|
31
|
+
const outArg = String(flags.out || '').trim();
|
|
32
|
+
const outDir = outArg ? path.dirname(path.resolve(process.cwd(), outArg)) : path.join(process.cwd(), 'dist');
|
|
33
|
+
ensureDir(outDir);
|
|
34
|
+
|
|
35
|
+
const outFile = outArg
|
|
36
|
+
? path.resolve(process.cwd(), outArg)
|
|
37
|
+
: path.join(outDir, `${pluginId.replace(/[^a-zA-Z0-9._-]+/g, '-')}-${version || '0.0.0'}.zip`);
|
|
38
|
+
|
|
39
|
+
rmForce(outFile);
|
|
40
|
+
|
|
41
|
+
const stagingBase = path.join(os.tmpdir(), `chatos-uiapp-pack-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
42
|
+
ensureDir(stagingBase);
|
|
43
|
+
try {
|
|
44
|
+
// mimic ChatOS importer: exclude node_modules/.git/*.map/.DS_Store
|
|
45
|
+
copyDir(pluginDir, stagingBase, {
|
|
46
|
+
filter: (src) => {
|
|
47
|
+
const base = path.basename(src);
|
|
48
|
+
if (base === 'node_modules') return false;
|
|
49
|
+
if (base === '.git') return false;
|
|
50
|
+
if (base === '.DS_Store') return false;
|
|
51
|
+
if (base.endsWith('.map')) return false;
|
|
52
|
+
return true;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const platform = process.platform;
|
|
57
|
+
if (hasCmd('zip')) {
|
|
58
|
+
packWithZip({ cwd: process.cwd(), srcDir: stagingBase, outFile });
|
|
59
|
+
} else if (platform === 'win32') {
|
|
60
|
+
packWithPowershell({ srcDir: stagingBase, outFile });
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error('zip command not found (install "zip" or run on Windows with powershell)');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// eslint-disable-next-line no-console
|
|
66
|
+
console.log(`Packed: ${outFile}
|
|
67
|
+
|
|
68
|
+
ChatOS -> 应用 -> 导入应用包 -> 选择该 zip`);
|
|
69
|
+
} finally {
|
|
70
|
+
rmForce(stagingBase);
|
|
71
|
+
}
|
|
72
|
+
}
|