@nocobase/cli 2.2.0-beta.1 → 2.2.0-beta.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/bin/early-locale.js +89 -0
- package/bin/node-version.js +35 -0
- package/bin/run.js +9 -0
- package/bin/windows-admin.js +60 -0
- package/dist/commands/app/destroy.js +4 -3
- package/dist/commands/app/shared.js +49 -3
- package/dist/commands/examples/prompts-stages.js +2 -2
- package/dist/commands/examples/prompts-test.js +2 -2
- package/dist/commands/init.js +5 -9
- package/dist/commands/license/activate.js +4 -1
- package/dist/commands/license/shared.js +24 -15
- package/dist/commands/self/check.js +1 -1
- package/dist/commands/self/update.js +2 -2
- package/dist/commands/skills/check.js +4 -5
- package/dist/commands/skills/install.js +18 -1
- package/dist/commands/skills/update.js +19 -4
- package/dist/commands/source/download.js +1 -2
- package/dist/lib/api-command-compat.js +51 -8
- package/dist/lib/prompt-web-ui.js +7 -11
- package/dist/lib/self-manager.js +3 -0
- package/dist/lib/skills-manager.js +116 -23
- package/dist/locale/en-US.json +10 -4
- package/dist/locale/zh-CN.json +10 -4
- package/package.json +7 -2
- package/assets/env-proxy/nginx/app.conf.tpl +0 -23
- package/assets/env-proxy/nginx/nocobase.conf.tpl +0 -5
- package/assets/env-proxy/nginx/snippets/dist-location.conf +0 -5
- package/assets/env-proxy/nginx/snippets/gzip.conf +0 -17
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +0 -13
- package/assets/env-proxy/nginx/snippets/maps-http.conf +0 -14
- package/assets/env-proxy/nginx/snippets/mime-types.conf +0 -98
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +0 -17
- package/assets/env-proxy/nginx/snippets/spa-location.conf +0 -6
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +0 -21
- package/scripts/build.mjs +0 -34
- package/scripts/clean.mjs +0 -9
- package/tsconfig.json +0 -19
|
@@ -16,7 +16,7 @@ import { DEFAULT_DOCKER_REGISTRY, DEFAULT_DOCKER_REGISTRY_ZH_CN, resolveDockerIm
|
|
|
16
16
|
import { run } from "../../lib/run-npm.js";
|
|
17
17
|
import { printVerbose, setVerboseMode, startTask, stopTask, updateTask } from '../../lib/ui.js';
|
|
18
18
|
const DEFAULT_DOCKER_PLATFORM = 'auto';
|
|
19
|
-
const DEFAULT_DOWNLOAD_VERSION = '
|
|
19
|
+
const DEFAULT_DOWNLOAD_VERSION = 'latest';
|
|
20
20
|
const downloadText = (key, values) => localeText(`commands.download.${key}`, values);
|
|
21
21
|
const downloadTranslatedText = (key, values, fallback) => translateCli(`commands.download.${key}`, values, { fallback });
|
|
22
22
|
function defaultOutputDirForVersion(versionTag) {
|
|
@@ -276,7 +276,6 @@ export default class SourceDownload extends Command {
|
|
|
276
276
|
value: 'latest',
|
|
277
277
|
label: downloadText('prompts.version.latestLabel'),
|
|
278
278
|
hint: downloadText('prompts.version.latestHint'),
|
|
279
|
-
disabled: true,
|
|
280
279
|
},
|
|
281
280
|
{
|
|
282
281
|
value: 'beta',
|
|
@@ -114,12 +114,22 @@ function compareWithOperator(version, operator, expected) {
|
|
|
114
114
|
}
|
|
115
115
|
function normalizeAppByChannelComparableVersion(version) {
|
|
116
116
|
const normalized = String(version ?? '').trim();
|
|
117
|
-
const match = normalized.match(/^(\d+\.\d+\.\d+)
|
|
117
|
+
const match = normalized.match(/^(\d+\.\d+\.\d+)(?:-([0-9A-Za-z-.]+))?$/);
|
|
118
118
|
if (!match) {
|
|
119
119
|
return normalized;
|
|
120
120
|
}
|
|
121
|
-
const [, base,
|
|
122
|
-
|
|
121
|
+
const [, base, prerelease] = match;
|
|
122
|
+
if (!prerelease) {
|
|
123
|
+
return base;
|
|
124
|
+
}
|
|
125
|
+
const [channel, sequence] = prerelease.split('.');
|
|
126
|
+
if ((channel === 'alpha' || channel === 'beta') && sequence && /^\d+$/.test(sequence)) {
|
|
127
|
+
return `${base}-${channel}.${sequence}`;
|
|
128
|
+
}
|
|
129
|
+
if (channel === 'alpha' || channel === 'beta') {
|
|
130
|
+
return `${base}-${channel}`;
|
|
131
|
+
}
|
|
132
|
+
return base;
|
|
123
133
|
}
|
|
124
134
|
function normalizeAppByChannelCondition(condition) {
|
|
125
135
|
if (!condition) {
|
|
@@ -134,6 +144,42 @@ function normalizeAppByChannelCondition(condition) {
|
|
|
134
144
|
}
|
|
135
145
|
return normalized;
|
|
136
146
|
}
|
|
147
|
+
function compareAppByChannelVersions(version, expected) {
|
|
148
|
+
const comparableVersion = normalizeAppByChannelComparableVersion(version);
|
|
149
|
+
const comparableExpected = normalizeAppByChannelComparableVersion(expected);
|
|
150
|
+
if (comparableVersion === comparableExpected ||
|
|
151
|
+
comparableVersion.startsWith(`${comparableExpected}.`) ||
|
|
152
|
+
comparableVersion.startsWith(`${comparableExpected}-`)) {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
return compareVersions(comparableVersion, comparableExpected);
|
|
156
|
+
}
|
|
157
|
+
function compareAppByChannelWithOperator(version, operator, expected) {
|
|
158
|
+
const compared = compareAppByChannelVersions(version, expected);
|
|
159
|
+
switch (operator) {
|
|
160
|
+
case 'eq':
|
|
161
|
+
return compared === 0;
|
|
162
|
+
case 'gt':
|
|
163
|
+
return compared > 0;
|
|
164
|
+
case 'gte':
|
|
165
|
+
return compared >= 0;
|
|
166
|
+
case 'lt':
|
|
167
|
+
return compared < 0;
|
|
168
|
+
case 'lte':
|
|
169
|
+
return compared <= 0;
|
|
170
|
+
default:
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function matchesAppByChannelVersionCondition(version, condition) {
|
|
175
|
+
if (!condition) {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
return ['eq', 'gt', 'gte', 'lt', 'lte'].every((operator) => {
|
|
179
|
+
const expected = condition[operator];
|
|
180
|
+
return expected ? compareAppByChannelWithOperator(version, operator, expected) : true;
|
|
181
|
+
});
|
|
182
|
+
}
|
|
137
183
|
function matchesVersionCondition(version, condition) {
|
|
138
184
|
if (!condition) {
|
|
139
185
|
return true;
|
|
@@ -168,10 +214,7 @@ function resolveAppChannel(version) {
|
|
|
168
214
|
if (channel === 'beta') {
|
|
169
215
|
return 'beta';
|
|
170
216
|
}
|
|
171
|
-
|
|
172
|
-
return 'rc';
|
|
173
|
-
}
|
|
174
|
-
return 'unknownPrerelease';
|
|
217
|
+
return 'stable';
|
|
175
218
|
}
|
|
176
219
|
function evaluateAppByChannelCondition(version, condition) {
|
|
177
220
|
if (!condition) {
|
|
@@ -208,7 +251,7 @@ function evaluateAppByChannelCondition(version, condition) {
|
|
|
208
251
|
const comparableVersion = normalizeAppByChannelComparableVersion(version);
|
|
209
252
|
const comparableCondition = normalizeAppByChannelCondition(channelCondition);
|
|
210
253
|
return {
|
|
211
|
-
result:
|
|
254
|
+
result: matchesAppByChannelVersionCondition(comparableVersion, comparableCondition) ? 'match' : 'mismatch',
|
|
212
255
|
channel,
|
|
213
256
|
condition: channelCondition,
|
|
214
257
|
};
|
|
@@ -19,7 +19,8 @@ export const PWC_FORM_META_STEP = '_pwcStep';
|
|
|
19
19
|
/** Form POST JSON meta field: current field key when validating a single field. */
|
|
20
20
|
export const PWC_FORM_META_FIELD = '_pwcField';
|
|
21
21
|
const DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
|
|
22
|
-
const
|
|
22
|
+
const DEFAULT_PUBLIC_HOST = '127.0.0.1';
|
|
23
|
+
const LISTEN_HOST = '0.0.0.0';
|
|
23
24
|
function resolveUiText(text, locale, fallback = '') {
|
|
24
25
|
return resolveLocalizedText(text, { locale, fallback });
|
|
25
26
|
}
|
|
@@ -705,7 +706,7 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
705
706
|
const initialShow = reflowWebFormState(merged, Object.fromEntries(Object.entries(formDefaults).map(([k, v]) => [k, v])), userSeed).show;
|
|
706
707
|
const submitPath = options.submitPath ?? DEFAULT_SUBMIT;
|
|
707
708
|
const reflowPath = options.reflowPath ?? DEFAULT_REFLOW;
|
|
708
|
-
const
|
|
709
|
+
const publicHost = options.host ?? DEFAULT_PUBLIC_HOST;
|
|
709
710
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
710
711
|
const pageTitle = resolveUiText(options.pageTitle, locale, t('promptCatalog.web.pageTitle'));
|
|
711
712
|
const h1 = resolveUiText(options.documentHeading, locale, t('promptCatalog.web.documentHeading'));
|
|
@@ -753,7 +754,7 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
753
754
|
}
|
|
754
755
|
};
|
|
755
756
|
const servePage = (port) => {
|
|
756
|
-
const base = `http://${
|
|
757
|
+
const base = `http://${publicHost}:${port}`;
|
|
757
758
|
const formInner = buildPwcFormHtml(catalog, formDefaults, initialShow, pwcStepDefs, 0, pwcNSteps, locale, uiText);
|
|
758
759
|
const wizardClientJson = JSON.stringify({ n: pwcNSteps, stepDefs: pwcStepDefs });
|
|
759
760
|
const pwcValStepUrl = pwcNSteps > 1 ? JSON.stringify(base + resolveValidateStepPath) : 'null';
|
|
@@ -2071,11 +2072,6 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
2071
2072
|
return page;
|
|
2072
2073
|
};
|
|
2073
2074
|
server = createServer((req, res) => {
|
|
2074
|
-
if (!req.socket.remoteAddress ||
|
|
2075
|
-
!['127.0.0.1', '::1', '::ffff:127.0.0.1'].includes(req.socket.remoteAddress)) {
|
|
2076
|
-
res.writeHead(403).end();
|
|
2077
|
-
return;
|
|
2078
|
-
}
|
|
2079
2075
|
if (req.method === 'GET' && (req.url === '/' || req.url === '')) {
|
|
2080
2076
|
const addr = server?.address();
|
|
2081
2077
|
const port = typeof addr === 'object' && addr ? Number(addr.port) : 0;
|
|
@@ -2212,15 +2208,15 @@ function runPromptCatalogWebUIImpl(options) {
|
|
|
2212
2208
|
}
|
|
2213
2209
|
res.writeHead(404).end();
|
|
2214
2210
|
});
|
|
2215
|
-
server.listen(options.port ?? 0,
|
|
2211
|
+
server.listen(options.port ?? 0, LISTEN_HOST, () => {
|
|
2216
2212
|
const addr = server?.address();
|
|
2217
2213
|
if (typeof addr !== 'object' || !addr) {
|
|
2218
2214
|
rejectAndClose(new Error('Failed to bind HTTP server'));
|
|
2219
2215
|
return;
|
|
2220
2216
|
}
|
|
2221
2217
|
const port = addr.port;
|
|
2222
|
-
const startUrl = `http://${
|
|
2223
|
-
options.onServerStart?.({ host, port, url: startUrl });
|
|
2218
|
+
const startUrl = `http://${publicHost}:${port}/`;
|
|
2219
|
+
options.onServerStart?.({ host: publicHost, listenHost: LISTEN_HOST, port, url: startUrl });
|
|
2224
2220
|
const onOpenBrowserError = options.onOpenBrowserError ?? ((u, err) => console.warn(String(err), u));
|
|
2225
2221
|
try {
|
|
2226
2222
|
openUrlInDefaultBrowser(startUrl, onOpenBrowserError);
|
package/dist/lib/self-manager.js
CHANGED
|
@@ -97,6 +97,9 @@ function detectChannel(currentVersion) {
|
|
|
97
97
|
if (/-beta(?:[.-]|$)/i.test(currentVersion)) {
|
|
98
98
|
return 'beta';
|
|
99
99
|
}
|
|
100
|
+
if (/-test(?:[.-]|$)/i.test(currentVersion)) {
|
|
101
|
+
return 'test';
|
|
102
|
+
}
|
|
100
103
|
return 'latest';
|
|
101
104
|
}
|
|
102
105
|
function readCurrentVersion(packageRoot) {
|
|
@@ -21,8 +21,8 @@ const NOCOBASE_SKILLS_NAME_PREFIX = 'nocobase-';
|
|
|
21
21
|
// resolves and boots the package, even when the local skills installation is healthy.
|
|
22
22
|
const SKILLS_LIST_TIMEOUT_MS = 15000;
|
|
23
23
|
const SKILLS_NPM_VIEW_TIMEOUT_MS = 3000;
|
|
24
|
-
const SKILLS_PACK_TIMEOUT_MS =
|
|
25
|
-
const SKILLS_ADD_TIMEOUT_MS =
|
|
24
|
+
const SKILLS_PACK_TIMEOUT_MS = 120000;
|
|
25
|
+
const SKILLS_ADD_TIMEOUT_MS = 120000;
|
|
26
26
|
const NPM_REGISTRY_UNAVAILABLE_PATTERNS = [
|
|
27
27
|
'enotfound',
|
|
28
28
|
'eai_again',
|
|
@@ -154,10 +154,13 @@ export async function listGlobalSkills(options = {}) {
|
|
|
154
154
|
export async function listProjectSkills(options = {}) {
|
|
155
155
|
return await listGlobalSkills(options);
|
|
156
156
|
}
|
|
157
|
-
function pickInstalledNocoBaseSkillNames(installedSkills, state) {
|
|
157
|
+
function pickInstalledNocoBaseSkillNames(installedSkills, state, sourceSkillNames = []) {
|
|
158
158
|
const installedNames = new Set(installedSkills.map((skill) => String(skill.name ?? '').trim()).filter(Boolean));
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
const managedNames = new Set([...sourceSkillNames, ...(state?.skillNames ?? [])]);
|
|
160
|
+
if (managedNames.size > 0) {
|
|
161
|
+
return Array.from(managedNames)
|
|
162
|
+
.filter((name) => installedNames.has(name))
|
|
163
|
+
.sort();
|
|
161
164
|
}
|
|
162
165
|
return Array.from(installedNames)
|
|
163
166
|
.filter((name) => name.startsWith(NOCOBASE_SKILLS_NAME_PREFIX))
|
|
@@ -194,6 +197,31 @@ async function readCachedSkillsVersion(cacheRoot) {
|
|
|
194
197
|
return undefined;
|
|
195
198
|
}
|
|
196
199
|
}
|
|
200
|
+
async function readCachedPackageSkillNames(globalRoot) {
|
|
201
|
+
const skillsDir = path.join(getCachedSkillsPackageDir(getSkillsCacheRoot(globalRoot)), 'skills');
|
|
202
|
+
try {
|
|
203
|
+
const entries = await fsp.readdir(skillsDir, { withFileTypes: true });
|
|
204
|
+
const skillNames = await Promise.all(entries
|
|
205
|
+
.filter((entry) => entry.isDirectory())
|
|
206
|
+
.map(async (entry) => {
|
|
207
|
+
const skillName = entry.name.trim();
|
|
208
|
+
if (!skillName) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
await fsp.access(path.join(skillsDir, skillName, 'SKILL.md'));
|
|
213
|
+
return skillName;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
}));
|
|
219
|
+
return skillNames.filter((name) => Boolean(name)).sort();
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
return [];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
197
225
|
async function resolvePackedSkillsTarball(packRoot) {
|
|
198
226
|
const entries = await fsp.readdir(packRoot, { withFileTypes: true });
|
|
199
227
|
const tarballs = entries
|
|
@@ -251,6 +279,7 @@ async function prepareLocalSkillsPackage(globalRoot, options = {}, targetVersion
|
|
|
251
279
|
const cachedVersion = await readCachedSkillsVersion(cacheRoot);
|
|
252
280
|
await fsp.mkdir(cacheRoot, { recursive: true });
|
|
253
281
|
if (targetVersion && cachedVersion && compareVersions(cachedVersion, targetVersion) === 0) {
|
|
282
|
+
options.onProgress?.(`Using cached ${NOCOBASE_SKILLS_PACKAGE_NAME}@${targetVersion}...`);
|
|
254
283
|
return {
|
|
255
284
|
packageDir,
|
|
256
285
|
cleanup: async () => undefined,
|
|
@@ -259,12 +288,14 @@ async function prepareLocalSkillsPackage(globalRoot, options = {}, targetVersion
|
|
|
259
288
|
await fsp.rm(packRoot, { recursive: true, force: true });
|
|
260
289
|
await fsp.mkdir(packRoot, { recursive: true });
|
|
261
290
|
try {
|
|
262
|
-
|
|
291
|
+
options.onProgress?.(`Downloading ${packageSpec}...`);
|
|
292
|
+
await (options.runFn ?? run)('npm', ['pack', ...(options.verbose ? [] : ['--silent']), packageSpec], {
|
|
263
293
|
cwd: packRoot,
|
|
264
294
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
265
295
|
errorName: 'npm pack',
|
|
266
296
|
timeoutMs: SKILLS_PACK_TIMEOUT_MS,
|
|
267
297
|
});
|
|
298
|
+
options.onProgress?.(`Extracting ${NOCOBASE_SKILLS_PACKAGE_NAME}...`);
|
|
268
299
|
const tarballPath = await resolvePackedSkillsTarball(packRoot);
|
|
269
300
|
await extractPackedSkillsTarball(tarballPath, cacheRoot, targetVersion);
|
|
270
301
|
}
|
|
@@ -279,14 +310,16 @@ async function prepareLocalSkillsPackage(globalRoot, options = {}, targetVersion
|
|
|
279
310
|
export async function inspectSkillsStatus(options = {}) {
|
|
280
311
|
const globalRoot = resolveSkillsRoot(options);
|
|
281
312
|
const stateFile = getManagedSkillsStateFile(globalRoot);
|
|
282
|
-
const [installedSkills, managedState] = await Promise.all([
|
|
313
|
+
const [installedSkills, managedState, cachedSkillNames] = await Promise.all([
|
|
283
314
|
listGlobalSkills({
|
|
284
315
|
globalRoot,
|
|
285
316
|
commandOutputFn: options.commandOutputFn,
|
|
286
317
|
}),
|
|
287
318
|
readManagedSkillsState(globalRoot),
|
|
319
|
+
readCachedPackageSkillNames(globalRoot),
|
|
288
320
|
]);
|
|
289
|
-
const installedSkillNames = pickInstalledNocoBaseSkillNames(installedSkills, managedState);
|
|
321
|
+
const installedSkillNames = pickInstalledNocoBaseSkillNames(installedSkills, managedState, cachedSkillNames);
|
|
322
|
+
const packageSkillNames = cachedSkillNames;
|
|
290
323
|
const managedByNb = managedState?.packageName === NOCOBASE_SKILLS_PACKAGE_NAME;
|
|
291
324
|
let latestVersion;
|
|
292
325
|
let registryError;
|
|
@@ -312,6 +345,7 @@ export async function inspectSkillsStatus(options = {}) {
|
|
|
312
345
|
managedByNb,
|
|
313
346
|
sourcePackage: managedState?.sourcePackage ?? NOCOBASE_SKILLS_SOURCE,
|
|
314
347
|
npmPackageName: managedState?.packageName ?? NOCOBASE_SKILLS_PACKAGE_NAME,
|
|
348
|
+
packageSkillNames,
|
|
315
349
|
installedSkillNames,
|
|
316
350
|
latestVersion,
|
|
317
351
|
installedVersion,
|
|
@@ -321,13 +355,18 @@ export async function inspectSkillsStatus(options = {}) {
|
|
|
321
355
|
registryError,
|
|
322
356
|
};
|
|
323
357
|
}
|
|
324
|
-
async function persistManagedSkillsState(globalRoot, options = {}) {
|
|
325
|
-
const installedSkills = await
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
358
|
+
async function persistManagedSkillsState(globalRoot, options = {}, installedVersion) {
|
|
359
|
+
const [installedSkills, managedState, cachedSkillNames] = await Promise.all([
|
|
360
|
+
listGlobalSkills({
|
|
361
|
+
globalRoot,
|
|
362
|
+
commandOutputFn: options.commandOutputFn,
|
|
363
|
+
}),
|
|
364
|
+
readManagedSkillsState(globalRoot),
|
|
365
|
+
readCachedPackageSkillNames(globalRoot),
|
|
366
|
+
]);
|
|
367
|
+
const installedSkillNames = pickInstalledNocoBaseSkillNames(installedSkills, managedState, cachedSkillNames);
|
|
368
|
+
const packageSkillNames = cachedSkillNames.length ? cachedSkillNames : installedSkillNames;
|
|
369
|
+
const cachedVersion = await readCachedSkillsVersion(getSkillsCacheRoot(globalRoot));
|
|
331
370
|
const published = await readPublishedSkillsVersion({
|
|
332
371
|
globalRoot,
|
|
333
372
|
commandOutputFn: options.commandOutputFn,
|
|
@@ -338,8 +377,8 @@ async function persistManagedSkillsState(globalRoot, options = {}) {
|
|
|
338
377
|
sourcePackage: NOCOBASE_SKILLS_SOURCE,
|
|
339
378
|
installedAt: managedState?.installedAt ?? now,
|
|
340
379
|
updatedAt: now,
|
|
341
|
-
installedVersion: published.version,
|
|
342
|
-
skillNames:
|
|
380
|
+
installedVersion: installedVersion ?? cachedVersion ?? published.version,
|
|
381
|
+
skillNames: packageSkillNames,
|
|
343
382
|
});
|
|
344
383
|
return await inspectSkillsStatus({
|
|
345
384
|
globalRoot,
|
|
@@ -349,7 +388,8 @@ async function persistManagedSkillsState(globalRoot, options = {}) {
|
|
|
349
388
|
async function reinstallManagedSkills(globalRoot, options = {}, targetVersion) {
|
|
350
389
|
const prepared = await prepareLocalSkillsPackage(globalRoot, options, targetVersion);
|
|
351
390
|
try {
|
|
352
|
-
|
|
391
|
+
options.onProgress?.('Installing NocoBase AI coding skills globally...');
|
|
392
|
+
await (options.runFn ?? run)('npx', ['-y', 'skills', 'add', prepared.packageDir, '-g', '-y', '--skill', '*'], {
|
|
353
393
|
cwd: globalRoot,
|
|
354
394
|
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
355
395
|
errorName: 'skills add',
|
|
@@ -360,31 +400,66 @@ async function reinstallManagedSkills(globalRoot, options = {}, targetVersion) {
|
|
|
360
400
|
await prepared.cleanup();
|
|
361
401
|
}
|
|
362
402
|
}
|
|
403
|
+
function pickObsoleteManagedSkillNames(installedSkillNames, packageSkillNames) {
|
|
404
|
+
if (!packageSkillNames.length) {
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
407
|
+
const packageSkillNameSet = new Set(packageSkillNames);
|
|
408
|
+
return installedSkillNames.filter((skillName) => !packageSkillNameSet.has(skillName)).sort();
|
|
409
|
+
}
|
|
410
|
+
async function removeObsoleteManagedSkills(globalRoot, installedSkillNames, options = {}) {
|
|
411
|
+
const packageSkillNames = await readCachedPackageSkillNames(globalRoot);
|
|
412
|
+
const obsoleteSkillNames = pickObsoleteManagedSkillNames(installedSkillNames, packageSkillNames);
|
|
413
|
+
for (const skillName of obsoleteSkillNames) {
|
|
414
|
+
options.onProgress?.(`Removing obsolete skill ${skillName}...`);
|
|
415
|
+
await (options.runFn ?? run)('npx', ['-y', 'skills', 'remove', skillName, '-g', '-y'], {
|
|
416
|
+
cwd: globalRoot,
|
|
417
|
+
stdio: options.verbose ? 'inherit' : 'ignore',
|
|
418
|
+
errorName: 'skills remove',
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
363
422
|
export async function installNocoBaseSkills(options = {}) {
|
|
364
423
|
const globalRoot = resolveSkillsRoot(options);
|
|
424
|
+
options.onProgress?.('Checking installed NocoBase AI coding skills...');
|
|
365
425
|
const status = await inspectSkillsStatus({
|
|
366
426
|
globalRoot,
|
|
367
427
|
commandOutputFn: options.commandOutputFn,
|
|
368
428
|
});
|
|
369
|
-
|
|
429
|
+
const cachedSkillNames = await readCachedPackageSkillNames(globalRoot);
|
|
430
|
+
const missingCachedSkillNames = cachedSkillNames.filter((name) => !status.installedSkillNames.includes(name));
|
|
431
|
+
const obsoleteSkillNames = pickObsoleteManagedSkillNames(status.installedSkillNames, cachedSkillNames);
|
|
432
|
+
const targetVersion = String(options.targetVersion ?? '').trim() || undefined;
|
|
433
|
+
const targetVersionMatches = !targetVersion || status.installedVersion === targetVersion;
|
|
434
|
+
if (status.installed && targetVersionMatches && missingCachedSkillNames.length === 0 && obsoleteSkillNames.length === 0) {
|
|
370
435
|
return {
|
|
371
436
|
action: 'noop',
|
|
372
437
|
status,
|
|
373
438
|
};
|
|
374
439
|
}
|
|
375
440
|
await ensureSkillsWorkspaceRoot(globalRoot);
|
|
376
|
-
|
|
441
|
+
if (!status.installed || !targetVersionMatches || missingCachedSkillNames.length > 0) {
|
|
442
|
+
const installVersion = targetVersion ?? status.latestVersion;
|
|
443
|
+
await reinstallManagedSkills(globalRoot, options, installVersion);
|
|
444
|
+
}
|
|
445
|
+
await removeObsoleteManagedSkills(globalRoot, status.installedSkillNames, options);
|
|
446
|
+
options.onProgress?.('Verifying installed NocoBase AI coding skills...');
|
|
377
447
|
return {
|
|
378
448
|
action: 'installed',
|
|
379
|
-
status: await persistManagedSkillsState(globalRoot, options),
|
|
449
|
+
status: await persistManagedSkillsState(globalRoot, options, targetVersion),
|
|
380
450
|
};
|
|
381
451
|
}
|
|
382
452
|
export async function updateNocoBaseSkills(options = {}) {
|
|
383
453
|
const globalRoot = resolveSkillsRoot(options);
|
|
454
|
+
options.onProgress?.('Checking installed NocoBase AI coding skills...');
|
|
384
455
|
const status = await inspectSkillsStatus({
|
|
385
456
|
globalRoot,
|
|
386
457
|
commandOutputFn: options.commandOutputFn,
|
|
387
458
|
});
|
|
459
|
+
const cachedSkillNames = await readCachedPackageSkillNames(globalRoot);
|
|
460
|
+
const missingCachedSkillNames = cachedSkillNames.filter((name) => !status.installedSkillNames.includes(name));
|
|
461
|
+
const obsoleteSkillNames = pickObsoleteManagedSkillNames(status.installedSkillNames, cachedSkillNames);
|
|
462
|
+
const targetVersion = String(options.targetVersion ?? '').trim() || undefined;
|
|
388
463
|
if (!status.installed) {
|
|
389
464
|
return {
|
|
390
465
|
action: 'noop',
|
|
@@ -393,8 +468,11 @@ export async function updateNocoBaseSkills(options = {}) {
|
|
|
393
468
|
};
|
|
394
469
|
}
|
|
395
470
|
if (status.managedByNb &&
|
|
471
|
+
!targetVersion &&
|
|
396
472
|
status.latestVersion &&
|
|
397
473
|
status.installedVersion &&
|
|
474
|
+
missingCachedSkillNames.length === 0 &&
|
|
475
|
+
obsoleteSkillNames.length === 0 &&
|
|
398
476
|
compareVersions(status.latestVersion, status.installedVersion) <= 0) {
|
|
399
477
|
return {
|
|
400
478
|
action: 'noop',
|
|
@@ -402,10 +480,25 @@ export async function updateNocoBaseSkills(options = {}) {
|
|
|
402
480
|
status,
|
|
403
481
|
};
|
|
404
482
|
}
|
|
405
|
-
|
|
483
|
+
if (targetVersion &&
|
|
484
|
+
status.installedVersion === targetVersion &&
|
|
485
|
+
missingCachedSkillNames.length === 0 &&
|
|
486
|
+
obsoleteSkillNames.length === 0) {
|
|
487
|
+
return {
|
|
488
|
+
action: 'noop',
|
|
489
|
+
reason: 'up-to-date',
|
|
490
|
+
status,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
if (!targetVersion || status.installedVersion !== targetVersion || missingCachedSkillNames.length > 0) {
|
|
494
|
+
const installVersion = targetVersion ?? status.latestVersion;
|
|
495
|
+
await reinstallManagedSkills(globalRoot, options, installVersion);
|
|
496
|
+
}
|
|
497
|
+
await removeObsoleteManagedSkills(globalRoot, status.installedSkillNames, options);
|
|
498
|
+
options.onProgress?.('Verifying installed NocoBase AI coding skills...');
|
|
406
499
|
return {
|
|
407
500
|
action: 'updated',
|
|
408
|
-
status: await persistManagedSkillsState(globalRoot, options),
|
|
501
|
+
status: await persistManagedSkillsState(globalRoot, options, targetVersion),
|
|
409
502
|
};
|
|
410
503
|
}
|
|
411
504
|
export async function removeNocoBaseSkills(options = {}) {
|
package/dist/locale/en-US.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
+
"entry": {
|
|
3
|
+
"windowsAdministratorRequired": {
|
|
4
|
+
"message": "NocoBase CLI must be run as Administrator on Windows.",
|
|
5
|
+
"hint": "Open your terminal as Administrator, then run the command again."
|
|
6
|
+
}
|
|
7
|
+
},
|
|
2
8
|
"promptCatalog": {
|
|
3
9
|
"common": {
|
|
4
10
|
"cancelled": "Cancelled.",
|
|
@@ -399,7 +405,7 @@
|
|
|
399
405
|
"envExists": "Env \"{{envName}}\" already exists. Choose another env name."
|
|
400
406
|
},
|
|
401
407
|
"messages": {
|
|
402
|
-
"title": "Set up NocoBase
|
|
408
|
+
"title": "Set up NocoBase",
|
|
403
409
|
"appNameRequiredWhenSkipped": "Env name is required when prompts are skipped.",
|
|
404
410
|
"appNameEnvHelp": "Use `nb init --yes --env <envName>` to continue.",
|
|
405
411
|
"resumeEnvRequired": "Env name is required when resuming setup.",
|
|
@@ -437,9 +443,9 @@
|
|
|
437
443
|
}
|
|
438
444
|
},
|
|
439
445
|
"webUi": {
|
|
440
|
-
"pageTitle": "Set up NocoBase
|
|
441
|
-
"documentHeading": "Set up NocoBase
|
|
442
|
-
"documentHint": "Install a new app, manage
|
|
446
|
+
"pageTitle": "Set up NocoBase",
|
|
447
|
+
"documentHeading": "Set up NocoBase",
|
|
448
|
+
"documentHint": "Install a new app, manage an existing one, or connect a remote app. You can use it directly or let a coding agent access it later.",
|
|
443
449
|
"gettingStarted": {
|
|
444
450
|
"title": "Getting started",
|
|
445
451
|
"description": "Choose whether to install a new app, manage a local app, or connect a remote app."
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
+
"entry": {
|
|
3
|
+
"windowsAdministratorRequired": {
|
|
4
|
+
"message": "Windows 上运行 NocoBase CLI 必须使用管理员模式。",
|
|
5
|
+
"hint": "请以管理员身份打开终端,然后重新执行命令。"
|
|
6
|
+
}
|
|
7
|
+
},
|
|
2
8
|
"promptCatalog": {
|
|
3
9
|
"common": {
|
|
4
10
|
"cancelled": "已取消。",
|
|
@@ -399,7 +405,7 @@
|
|
|
399
405
|
"envExists": "Env \"{{envName}}\" 已存在,请换一个 env name。"
|
|
400
406
|
},
|
|
401
407
|
"messages": {
|
|
402
|
-
"title": "
|
|
408
|
+
"title": "配置 NocoBase",
|
|
403
409
|
"appNameRequiredWhenSkipped": "跳过 prompts 时必须提供 Env name。",
|
|
404
410
|
"appNameEnvHelp": "请使用 `nb init --yes --env <envName>` 继续。",
|
|
405
411
|
"resumeEnvRequired": "恢复安装时必须提供 Env name。",
|
|
@@ -437,9 +443,9 @@
|
|
|
437
443
|
}
|
|
438
444
|
},
|
|
439
445
|
"webUi": {
|
|
440
|
-
"pageTitle": "
|
|
441
|
-
"documentHeading": "
|
|
442
|
-
"documentHint": "
|
|
446
|
+
"pageTitle": "配置 NocoBase",
|
|
447
|
+
"documentHeading": "配置 NocoBase",
|
|
448
|
+
"documentHint": "安装一个新的应用、管理已有应用,或连接远程应用。你可以直接使用它,也可以稍后让 coding agent 访问它。",
|
|
443
449
|
"gettingStarted": {
|
|
444
450
|
"title": "开始设置",
|
|
445
451
|
"description": "选择新安装、本机接管,或远程连接。"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.2.0-beta.
|
|
3
|
+
"version": "2.2.0-beta.3",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -12,6 +12,11 @@
|
|
|
12
12
|
"keywords": [],
|
|
13
13
|
"author": "",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"dist",
|
|
18
|
+
"nocobase-ctl.config.json"
|
|
19
|
+
],
|
|
15
20
|
"bin": {
|
|
16
21
|
"nb": "./bin/run.js"
|
|
17
22
|
},
|
|
@@ -138,5 +143,5 @@
|
|
|
138
143
|
"type": "git",
|
|
139
144
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
140
145
|
},
|
|
141
|
-
"gitHead": "
|
|
146
|
+
"gitHead": "7b16bb2cfd427c110c6671252138cd85155723c5"
|
|
142
147
|
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Rendered by `nb env proxy`.
|
|
2
|
-
# Context:
|
|
3
|
-
# publicBasePath={{publicBasePath}}
|
|
4
|
-
# apiBasePath={{apiBasePath}}
|
|
5
|
-
# wsPath={{wsPath}}
|
|
6
|
-
# v2PublicPath={{v2PublicPath}}
|
|
7
|
-
# backendUrl={{backendUrl}}
|
|
8
|
-
# snippetsDir={{snippetsDir}}
|
|
9
|
-
# uploadsDir={{uploadsDir}}
|
|
10
|
-
# distRootDir={{distRootDir}}
|
|
11
|
-
# entryDir={{entryDir}}
|
|
12
|
-
# publicDir={{publicDir}}
|
|
13
|
-
|
|
14
|
-
server {
|
|
15
|
-
listen 80;
|
|
16
|
-
server_name _;
|
|
17
|
-
|
|
18
|
-
# Add custom directives or locations above the managed block as needed.
|
|
19
|
-
|
|
20
|
-
{{managedConfigBlock}}
|
|
21
|
-
|
|
22
|
-
# Add custom directives or locations below the managed block as needed.
|
|
23
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
gzip on;
|
|
2
|
-
gzip_types
|
|
3
|
-
text/plain
|
|
4
|
-
text/css
|
|
5
|
-
text/xml
|
|
6
|
-
text/markdown
|
|
7
|
-
text/javascript
|
|
8
|
-
application/javascript
|
|
9
|
-
application/json
|
|
10
|
-
application/manifest+json
|
|
11
|
-
application/atom+xml
|
|
12
|
-
application/rss+xml
|
|
13
|
-
application/xml
|
|
14
|
-
application/xml+rss
|
|
15
|
-
application/xhtml+xml
|
|
16
|
-
application/wasm
|
|
17
|
-
image/svg+xml;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
log_format apm '"$time_local" client=$remote_addr '
|
|
2
|
-
'method=$request_method request="$request" '
|
|
3
|
-
'request_length=$request_length '
|
|
4
|
-
'status=$status bytes_sent=$bytes_sent '
|
|
5
|
-
'body_bytes_sent=$body_bytes_sent '
|
|
6
|
-
'referer=$http_referer '
|
|
7
|
-
'user_agent="$http_user_agent" '
|
|
8
|
-
'upstream_addr=$upstream_addr '
|
|
9
|
-
'upstream_status=$upstream_status '
|
|
10
|
-
'request_time=$request_time '
|
|
11
|
-
'upstream_response_time=$upstream_response_time '
|
|
12
|
-
'upstream_connect_time=$upstream_connect_time '
|
|
13
|
-
'upstream_header_time=$upstream_header_time';
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
map $http_upgrade $connection_upgrade {
|
|
2
|
-
default upgrade;
|
|
3
|
-
"" close;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
map $http_x_forwarded_proto $upstream_x_forwarded_proto {
|
|
7
|
-
default $http_x_forwarded_proto;
|
|
8
|
-
"" $scheme;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
map $http_host $final_host {
|
|
12
|
-
default $http_host;
|
|
13
|
-
"" $host;
|
|
14
|
-
}
|