@nocobase/cli 2.1.0-beta.43 → 2.1.0-beta.44.test.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/LICENSE +201 -0
- package/README.md +63 -380
- package/assets/env-proxy/nginx/app.conf.tpl +23 -0
- package/assets/env-proxy/nginx/nocobase.conf.tpl +5 -0
- package/assets/env-proxy/nginx/snippets/dist-location.conf +5 -0
- package/assets/env-proxy/nginx/snippets/gzip.conf +17 -0
- package/assets/env-proxy/nginx/snippets/log-format-http.conf +13 -0
- package/assets/env-proxy/nginx/snippets/maps-http.conf +14 -0
- package/assets/env-proxy/nginx/snippets/mime-types.conf +98 -0
- package/assets/env-proxy/nginx/snippets/proxy-location.conf +17 -0
- package/assets/env-proxy/nginx/snippets/spa-location.conf +6 -0
- package/assets/env-proxy/nginx/snippets/uploads-location.conf +21 -0
- package/dist/commands/app/autostart/disable.js +55 -0
- package/dist/commands/app/autostart/enable.js +55 -0
- package/dist/commands/app/autostart/list.js +37 -0
- package/dist/commands/app/autostart/run.js +84 -0
- package/dist/commands/app/autostart/shared.js +49 -0
- package/dist/commands/app/destroy.js +8 -6
- package/dist/commands/app/down.js +2 -2
- package/dist/commands/app/logs.js +2 -1
- package/dist/commands/app/restart.js +79 -23
- package/dist/commands/app/shared.js +1 -1
- package/dist/commands/app/start.js +134 -38
- package/dist/commands/app/stop.js +31 -2
- package/dist/commands/app/upgrade.js +3 -1
- package/dist/commands/config/delete.js +4 -1
- package/dist/commands/config/get.js +4 -1
- package/dist/commands/config/set.js +5 -2
- package/dist/commands/env/add.js +19 -39
- package/dist/commands/env/info.js +3 -2
- package/dist/commands/env/proxy/caddy.js +28 -0
- package/dist/commands/env/proxy/index.js +353 -0
- package/dist/commands/env/proxy/nginx.js +28 -0
- package/dist/commands/env/remove.js +112 -22
- package/dist/commands/env/shared.js +17 -9
- package/dist/commands/env/update.js +385 -21
- package/dist/commands/init.js +233 -91
- package/dist/commands/install.js +174 -68
- package/dist/commands/license/activate.js +63 -244
- package/dist/commands/license/plugins/shared.js +64 -13
- package/dist/commands/plugin/import.js +108 -0
- package/dist/commands/revision/create.js +89 -0
- package/dist/locale/en-US.json +105 -19
- package/dist/locale/zh-CN.json +102 -16
- package/package.json +5 -8
- package/scripts/build.mjs +34 -0
- package/scripts/clean.mjs +9 -0
- package/tsconfig.json +19 -0
- package/LICENSE.txt +0 -107
- package/README.zh-CN.md +0 -355
- package/dist/lib/api-client.js +0 -335
- package/dist/lib/api-command-compat.js +0 -641
- package/dist/lib/app-health.js +0 -139
- package/dist/lib/app-managed-resources.js +0 -316
- package/dist/lib/app-runtime.js +0 -180
- package/dist/lib/auth-store.js +0 -405
- package/dist/lib/backup.js +0 -171
- package/dist/lib/bootstrap.js +0 -409
- package/dist/lib/build-config.js +0 -18
- package/dist/lib/builtin-db.js +0 -86
- package/dist/lib/cli-config.js +0 -309
- package/dist/lib/cli-entry-error.js +0 -44
- package/dist/lib/cli-home.js +0 -47
- package/dist/lib/cli-locale.js +0 -141
- package/dist/lib/command-discovery.js +0 -39
- package/dist/lib/db-connection-check.js +0 -219
- package/dist/lib/docker-env-file.js +0 -52
- package/dist/lib/docker-image.js +0 -37
- package/dist/lib/docker-log-stream.js +0 -45
- package/dist/lib/env-auth.js +0 -960
- package/dist/lib/env-config.js +0 -95
- package/dist/lib/env-guard.js +0 -62
- package/dist/lib/generated-command.js +0 -203
- package/dist/lib/http-request.js +0 -49
- package/dist/lib/inquirer-theme.js +0 -17
- package/dist/lib/inquirer.js +0 -244
- package/dist/lib/naming.js +0 -70
- package/dist/lib/object-utils.js +0 -76
- package/dist/lib/openapi.js +0 -62
- package/dist/lib/plugin-storage.js +0 -64
- package/dist/lib/post-processors.js +0 -23
- package/dist/lib/prompt-catalog-core.js +0 -185
- package/dist/lib/prompt-catalog-terminal.js +0 -375
- package/dist/lib/prompt-catalog.js +0 -10
- package/dist/lib/prompt-validators.js +0 -258
- package/dist/lib/prompt-web-ui.js +0 -2227
- package/dist/lib/resource-command.js +0 -357
- package/dist/lib/resource-request.js +0 -104
- package/dist/lib/run-npm.js +0 -385
- package/dist/lib/runtime-env-vars.js +0 -32
- package/dist/lib/runtime-generator.js +0 -498
- package/dist/lib/runtime-store.js +0 -56
- package/dist/lib/self-manager.js +0 -301
- package/dist/lib/session-id.js +0 -17
- package/dist/lib/session-integration.js +0 -703
- package/dist/lib/session-store.js +0 -118
- package/dist/lib/skills-manager.js +0 -436
- package/dist/lib/source-publish.js +0 -309
- package/dist/lib/source-registry.js +0 -188
- package/dist/lib/startup-update.js +0 -309
- package/dist/lib/ui.js +0 -158
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
import { Args, Command, Flags } from '@oclif/core';
|
|
10
|
+
import { executeRawApiRequest } from '../../lib/api-client.js';
|
|
11
|
+
import { ensureCrossEnvConfirmed } from '../../lib/env-guard.js';
|
|
12
|
+
export default class RevisionCreate extends Command {
|
|
13
|
+
static summary = 'Save the current NocoBase build as a restorable revision';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> "description here"',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> --env app1 "description here"',
|
|
17
|
+
];
|
|
18
|
+
static args = {
|
|
19
|
+
description: Args.string({
|
|
20
|
+
required: true,
|
|
21
|
+
description: 'Revision description, up to 2000 characters.',
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
static flags = {
|
|
25
|
+
'api-base-url': Flags.string({
|
|
26
|
+
description: 'NocoBase API base URL, for example http://localhost:13000/api',
|
|
27
|
+
}),
|
|
28
|
+
env: Flags.string({
|
|
29
|
+
char: 'e',
|
|
30
|
+
description: 'Environment name',
|
|
31
|
+
}),
|
|
32
|
+
role: Flags.string({
|
|
33
|
+
description: 'Role override, sent as X-Role',
|
|
34
|
+
}),
|
|
35
|
+
token: Flags.string({
|
|
36
|
+
char: 't',
|
|
37
|
+
description: 'API key override',
|
|
38
|
+
}),
|
|
39
|
+
yes: Flags.boolean({
|
|
40
|
+
char: 'y',
|
|
41
|
+
description: 'Confirm using --env when it targets a different env than the current env',
|
|
42
|
+
default: false,
|
|
43
|
+
}),
|
|
44
|
+
'json-output': Flags.boolean({
|
|
45
|
+
char: 'j',
|
|
46
|
+
description: 'Print raw JSON response',
|
|
47
|
+
default: true,
|
|
48
|
+
allowNo: true,
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
async run() {
|
|
52
|
+
const { args, flags } = await this.parse(RevisionCreate);
|
|
53
|
+
const description = args.description;
|
|
54
|
+
if (description.length > 2000) {
|
|
55
|
+
this.error('Description length should not be over 2000');
|
|
56
|
+
}
|
|
57
|
+
const confirmed = await ensureCrossEnvConfirmed({
|
|
58
|
+
command: this,
|
|
59
|
+
requestedEnv: flags.env,
|
|
60
|
+
yes: flags.yes,
|
|
61
|
+
});
|
|
62
|
+
if (!confirmed) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const response = await executeRawApiRequest({
|
|
66
|
+
envName: flags.env,
|
|
67
|
+
baseUrl: flags['api-base-url'],
|
|
68
|
+
role: flags.role,
|
|
69
|
+
token: flags.token,
|
|
70
|
+
method: 'POST',
|
|
71
|
+
path: '/app:publishEvent',
|
|
72
|
+
body: {
|
|
73
|
+
plugin: 'plugin-version-control',
|
|
74
|
+
command: 'revision:create',
|
|
75
|
+
payload: {
|
|
76
|
+
description,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
if (!response.ok) {
|
|
81
|
+
this.error(`Request failed with status ${response.status}\n${JSON.stringify(response.data, null, 2)}`);
|
|
82
|
+
}
|
|
83
|
+
if (flags['json-output']) {
|
|
84
|
+
this.log(JSON.stringify(response.data, null, 2));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.log(`HTTP ${response.status}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
package/dist/locale/en-US.json
CHANGED
|
@@ -116,8 +116,90 @@
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
|
+
"envProxy": {
|
|
120
|
+
"messages": {
|
|
121
|
+
"generating": "Generating proxy config for env \"{{envName}}\"...",
|
|
122
|
+
"printed": "Printed proxy config for env \"{{envName}}\".",
|
|
123
|
+
"saved": "Saved generated proxy config for env \"{{envName}}\" at {{outputPath}}.",
|
|
124
|
+
"savedWithAppEntryCreated": "Saved generated proxy config for env \"{{envName}}\" at {{outputPath}}, and created editable app entry config at {{appConfigPath}}.",
|
|
125
|
+
"savedWithAppEntryMigrated": "Saved generated proxy config for env \"{{envName}}\" at {{outputPath}}, and migrated the app entry config at {{appConfigPath}}.",
|
|
126
|
+
"savedNginxBundleCreated": "Saved nginx proxy files for env \"{{envName}}\" under {{entryDir}}, and created editable app entry config at {{appConfigPath}}.",
|
|
127
|
+
"savedNginxBundleUpdated": "Saved nginx proxy files for env \"{{envName}}\" under {{entryDir}}, and refreshed editable app entry config at {{appConfigPath}}.",
|
|
128
|
+
"savedCaddyBundleCreated": "Saved caddy proxy files for env \"{{envName}}\" under {{entryDir}}, and created editable app entry config at {{appConfigPath}}.",
|
|
129
|
+
"savedCaddyBundleMigrated": "Saved caddy proxy files for env \"{{envName}}\" under {{entryDir}}, and migrated the app entry config at {{appConfigPath}}.",
|
|
130
|
+
"savedCaddyBundleUpdated": "Saved caddy proxy files for env \"{{envName}}\" under {{entryDir}}, and refreshed editable app entry config at {{appConfigPath}}.",
|
|
131
|
+
"failed": "Failed to generate proxy config for env \"{{envName}}\".",
|
|
132
|
+
"installingProvider": "Installing the shared proxy config into {{provider}}...",
|
|
133
|
+
"providerInstalled": "Installed the shared proxy config into the {{provider}} main config at {{configPath}}.",
|
|
134
|
+
"providerAlreadyInstalled": "The shared proxy config is already installed in the {{provider}} main config at {{configPath}}.",
|
|
135
|
+
"installProviderFailed": "Failed to install the shared proxy config into {{provider}}.",
|
|
136
|
+
"reloadingProvider": "Validating and reloading {{provider}}...",
|
|
137
|
+
"providerReloaded": "Validated and reloaded {{provider}}.",
|
|
138
|
+
"reloadProviderFailed": "Failed to validate and reload {{provider}}."
|
|
139
|
+
},
|
|
140
|
+
"errors": {
|
|
141
|
+
"httpEnvUnsupported": "Can't generate a proxy config for \"{{envName}}\" from this machine because the env only has an API connection.",
|
|
142
|
+
"sshEnvUnsupported": "Can't generate a proxy config for \"{{envName}}\" yet because SSH envs are not implemented.",
|
|
143
|
+
"invalidProxyPort": "Invalid proxy entry port \"{{port}}\". Use an integer between 1 and 65535.",
|
|
144
|
+
"missingAppPort": "Missing appPort for env \"{{envName}}\". Save or update the app port before generating proxy config.",
|
|
145
|
+
"missingVersion": "Couldn't determine the app version for env \"{{envName}}\". Run `nb env update {{envName}}` and try again.",
|
|
146
|
+
"appEntryMissingInclude": "The editable app entry config at {{appConfigPath}} does not reference {{generatedConfigPath}}. Add the managed generated-config reference back into the editable app entry and rerun the command.",
|
|
147
|
+
"nginxOutputUnsupported": "The nginx provider does not support `--output`. It writes `app.conf`, `public/index-v1.html`, `public/index-v2.html`, and `nocobase.conf` into `~/.nocobase/proxy/nginx/<env>/`.",
|
|
148
|
+
"caddyOutputUnsupported": "The caddy provider does not support `--output`. It writes `app.caddy`, `generated.caddy`, `public/index-v1.html`, `public/index-v2.html`, and `nocobase.caddy` into `~/.nocobase/proxy/caddy/<env>/`.",
|
|
149
|
+
"nginxAppEntryMissingManagedBlock": "The editable nginx app entry config at {{appConfigPath}} does not contain the NocoBase managed block. Restore the managed block or delete the file and rerun `nb env proxy`."
|
|
150
|
+
}
|
|
151
|
+
},
|
|
119
152
|
"shared": {
|
|
120
|
-
"missingCommand": "Couldn't run `{{action}}` because the {{displayName}} executable could not be found. Install {{displayName}} or update `nb config set {{configKey}} <path>` and try again."
|
|
153
|
+
"missingCommand": "Couldn't run `{{action}}` because the {{displayName}} executable could not be found. Install {{displayName}} or update `nb config set {{configKey}} <path>` and try again.",
|
|
154
|
+
"targetEnv": "Using env \"{{envName}}\".",
|
|
155
|
+
"crossEnv": {
|
|
156
|
+
"prompt": "Current env is \"{{currentEnv}}\", but this command targets \"{{requestedEnv}}\" via --env. Continue without switching the current env?",
|
|
157
|
+
"refusal": "Refusing to run against env \"{{requestedEnv}}\" because the current env is \"{{currentEnv}}\" and interactive confirmation is unavailable in the current agent session.\n\nFor safety, the agent will not switch envs automatically and will not add --yes on your behalf.\n\nTo continue:\n- run `nb env use {{requestedEnv}}` yourself and then re-run the command, or\n- re-run the same command with `--env {{requestedEnv}} --yes` to confirm this one-off cross-env operation."
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"license": {
|
|
161
|
+
"activate": {
|
|
162
|
+
"interactive": {
|
|
163
|
+
"notice": {
|
|
164
|
+
"hostnameLabel": "❯ Hostname",
|
|
165
|
+
"instanceIdLabel": "❯ Instance ID",
|
|
166
|
+
"copyHintWithHostname": "Copy this hostname and instance ID when checking or activating the license key.",
|
|
167
|
+
"copyHintWithoutHostname": "Copy this instance ID when checking or activating the license key."
|
|
168
|
+
},
|
|
169
|
+
"prompts": {
|
|
170
|
+
"provideMethod": {
|
|
171
|
+
"message": "How do you want to provide the license key?",
|
|
172
|
+
"keyOption": "Paste the license key",
|
|
173
|
+
"fileOption": "Read the key from a file"
|
|
174
|
+
},
|
|
175
|
+
"key": {
|
|
176
|
+
"message": "License key",
|
|
177
|
+
"transformer": "Entered {{count}} chars",
|
|
178
|
+
"required": "License key is required."
|
|
179
|
+
},
|
|
180
|
+
"keyFile": {
|
|
181
|
+
"message": "Path to the license key file",
|
|
182
|
+
"required": "License key file path is required."
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"errors": {
|
|
187
|
+
"provideKeyOrKeyFile": "Provide --key or --key-file to continue.",
|
|
188
|
+
"emptyInput": "License key input was empty.",
|
|
189
|
+
"activationFailed": "Failed to activate the license for env \"{{envName}}\": {{reason}}.",
|
|
190
|
+
"reasons": {
|
|
191
|
+
"keyStatus": "license key is {{status}}",
|
|
192
|
+
"envMismatch": "license key does not match the current instance environment",
|
|
193
|
+
"domainMismatch": "license key does not match the current app domain",
|
|
194
|
+
"licenseStatus": "license status is {{status}}",
|
|
195
|
+
"validationFailed": "license validation failed"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"messages": {
|
|
199
|
+
"activated": "Activated the license for env \"{{envName}}\".",
|
|
200
|
+
"savedLicenseKey": "Saved license key at {{licenseKeyPath}}"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
121
203
|
},
|
|
122
204
|
"download": {
|
|
123
205
|
"failures": {
|
|
@@ -236,9 +318,9 @@
|
|
|
236
318
|
"lang": {
|
|
237
319
|
"message": "Which language would you like to use?"
|
|
238
320
|
},
|
|
239
|
-
"
|
|
240
|
-
"message": "Where should this app be stored?",
|
|
241
|
-
"placeholder": "./<env>/
|
|
321
|
+
"appPath": {
|
|
322
|
+
"message": "Where should this app be stored? (relative to {{root}})",
|
|
323
|
+
"placeholder": "./<env>/"
|
|
242
324
|
},
|
|
243
325
|
"appPort": {
|
|
244
326
|
"message": "Which port should this app use?",
|
|
@@ -308,7 +390,7 @@
|
|
|
308
390
|
"envExists": "Env \"{{envName}}\" already exists. Choose another env name."
|
|
309
391
|
},
|
|
310
392
|
"messages": {
|
|
311
|
-
"title": "Set
|
|
393
|
+
"title": "Set up NocoBase for coding agents",
|
|
312
394
|
"appNameRequiredWhenSkipped": "Env name is required when prompts are skipped.",
|
|
313
395
|
"appNameEnvHelp": "Use `nb init --yes --env <envName>` to continue.",
|
|
314
396
|
"resumeEnvRequired": "Env name is required when resuming setup.",
|
|
@@ -325,10 +407,14 @@
|
|
|
325
407
|
"message": "What should this environment use for `--env`?",
|
|
326
408
|
"placeholder": "local"
|
|
327
409
|
},
|
|
328
|
-
"
|
|
329
|
-
"message": "
|
|
330
|
-
"
|
|
331
|
-
"
|
|
410
|
+
"setupMode": {
|
|
411
|
+
"message": "How would you like to set up this environment?",
|
|
412
|
+
"installNewLabel": "Install a new app",
|
|
413
|
+
"installNewHint": "Install a brand-new app from scratch. Best for first-time setup, evaluation, or a fresh local environment.",
|
|
414
|
+
"manageLocalLabel": "Manage an app already on this machine",
|
|
415
|
+
"manageLocalHint": "Bring an app on this machine under nb management so install, upgrade, and startup can be handled in one place. During takeover, nb will re-download the app source or image and upgrade the app; storage will be created automatically when needed.",
|
|
416
|
+
"connectRemoteLabel": "Connect a remote app",
|
|
417
|
+
"connectRemoteHint": "Save only the remote app connection. Nothing will be installed or taken over on this machine."
|
|
332
418
|
},
|
|
333
419
|
"installSkills": {
|
|
334
420
|
"message": "Install NocoBase AI coding skills (nocobase/skills)?"
|
|
@@ -342,24 +428,24 @@
|
|
|
342
428
|
}
|
|
343
429
|
},
|
|
344
430
|
"webUi": {
|
|
345
|
-
"pageTitle": "Set
|
|
346
|
-
"documentHeading": "Set
|
|
347
|
-
"documentHint": "
|
|
431
|
+
"pageTitle": "Set up NocoBase for coding agents",
|
|
432
|
+
"documentHeading": "Set up NocoBase for coding agents",
|
|
433
|
+
"documentHint": "Install a new app, manage one that already exists on this machine, or connect a remote app so coding agents can access and work with NocoBase.",
|
|
348
434
|
"gettingStarted": {
|
|
349
435
|
"title": "Getting started",
|
|
350
|
-
"description": "Choose whether to
|
|
436
|
+
"description": "Choose whether to install a new app, manage a local app, or connect a remote app."
|
|
351
437
|
},
|
|
352
438
|
"connectExistingApp": {
|
|
353
|
-
"title": "
|
|
354
|
-
"description": "Save your app connection."
|
|
439
|
+
"title": "Remote connection",
|
|
440
|
+
"description": "Save your remote app connection."
|
|
355
441
|
},
|
|
356
442
|
"createNewApp": {
|
|
357
|
-
"title": "
|
|
358
|
-
"description": "Set app basics and
|
|
443
|
+
"title": "App environment",
|
|
444
|
+
"description": "Set the app basics, storage location, and runtime port."
|
|
359
445
|
},
|
|
360
446
|
"downloadAppFiles": {
|
|
361
|
-
"title": "
|
|
362
|
-
"description": "Choose how to get the app
|
|
447
|
+
"title": "App source and version",
|
|
448
|
+
"description": "Choose how to get the app and which source and version to use."
|
|
363
449
|
},
|
|
364
450
|
"configureDatabase": {
|
|
365
451
|
"title": "Configure the database",
|
package/dist/locale/zh-CN.json
CHANGED
|
@@ -116,8 +116,90 @@
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
},
|
|
119
|
+
"envProxy": {
|
|
120
|
+
"messages": {
|
|
121
|
+
"generating": "正在为 env \"{{envName}}\" 生成代理配置...",
|
|
122
|
+
"printed": "已输出 env \"{{envName}}\" 的代理配置。",
|
|
123
|
+
"saved": "已将 env \"{{envName}}\" 的生成代理配置保存到 {{outputPath}}。",
|
|
124
|
+
"savedWithAppEntryCreated": "已将 env \"{{envName}}\" 的生成代理配置保存到 {{outputPath}},并创建可编辑的入口配置 {{appConfigPath}}。",
|
|
125
|
+
"savedWithAppEntryMigrated": "已将 env \"{{envName}}\" 的生成代理配置保存到 {{outputPath}},并将入口配置迁移为 {{appConfigPath}}。",
|
|
126
|
+
"savedNginxBundleCreated": "已将 env \"{{envName}}\" 的 nginx 代理文件保存到 {{entryDir}},并创建可编辑的入口配置 {{appConfigPath}}。",
|
|
127
|
+
"savedNginxBundleUpdated": "已将 env \"{{envName}}\" 的 nginx 代理文件保存到 {{entryDir}},并刷新可编辑的入口配置 {{appConfigPath}}。",
|
|
128
|
+
"savedCaddyBundleCreated": "已将 env \"{{envName}}\" 的 caddy 代理文件保存到 {{entryDir}},并创建可编辑的入口配置 {{appConfigPath}}。",
|
|
129
|
+
"savedCaddyBundleMigrated": "已将 env \"{{envName}}\" 的 caddy 代理文件保存到 {{entryDir}},并将入口配置迁移为 {{appConfigPath}}。",
|
|
130
|
+
"savedCaddyBundleUpdated": "已将 env \"{{envName}}\" 的 caddy 代理文件保存到 {{entryDir}},并刷新可编辑的入口配置 {{appConfigPath}}。",
|
|
131
|
+
"failed": "为 env \"{{envName}}\" 生成代理配置失败。",
|
|
132
|
+
"installingProvider": "正在将共享代理配置安装到 {{provider}}...",
|
|
133
|
+
"providerInstalled": "已将共享代理配置安装到 {{provider}} 主配置 {{configPath}}。",
|
|
134
|
+
"providerAlreadyInstalled": "共享代理配置已存在于 {{provider}} 主配置 {{configPath}} 中。",
|
|
135
|
+
"installProviderFailed": "将共享代理配置安装到 {{provider}} 失败。",
|
|
136
|
+
"reloadingProvider": "正在校验并重载 {{provider}}...",
|
|
137
|
+
"providerReloaded": "已校验并重载 {{provider}}。",
|
|
138
|
+
"reloadProviderFailed": "校验并重载 {{provider}} 失败。"
|
|
139
|
+
},
|
|
140
|
+
"errors": {
|
|
141
|
+
"httpEnvUnsupported": "无法在当前机器上为 \"{{envName}}\" 生成代理配置,因为这个 env 只有 API 连接。",
|
|
142
|
+
"sshEnvUnsupported": "暂时无法为 \"{{envName}}\" 生成代理配置,因为 SSH env 还没有实现。",
|
|
143
|
+
"invalidProxyPort": "代理入口端口 \"{{port}}\" 无效。请使用 1 到 65535 之间的整数。",
|
|
144
|
+
"missingAppPort": "env \"{{envName}}\" 缺少 appPort。请先保存或更新应用端口后再生成代理配置。",
|
|
145
|
+
"missingVersion": "无法确定 env \"{{envName}}\" 的应用版本。请先运行 `nb env update {{envName}}`,然后再试一次。",
|
|
146
|
+
"appEntryMissingInclude": "可编辑入口配置 {{appConfigPath}} 没有引用 {{generatedConfigPath}}。请把托管的 generated 配置引用补回入口配置中,然后重新执行该命令。",
|
|
147
|
+
"nginxOutputUnsupported": "nginx provider 不支持 `--output`。它会把 `app.conf`、`public/index-v1.html`、`public/index-v2.html` 和 `nocobase.conf` 写入 `~/.nocobase/proxy/nginx/<env>/`。",
|
|
148
|
+
"caddyOutputUnsupported": "caddy provider 不支持 `--output`。它会把 `app.caddy`、`generated.caddy`、`public/index-v1.html`、`public/index-v2.html` 和 `nocobase.caddy` 写入 `~/.nocobase/proxy/caddy/<env>/`。",
|
|
149
|
+
"nginxAppEntryMissingManagedBlock": "可编辑的 nginx 入口配置 {{appConfigPath}} 不包含 NocoBase 的托管区块。请恢复这个托管区块,或删除该文件后重新执行 `nb env proxy`。"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
119
152
|
"shared": {
|
|
120
|
-
"missingCommand": "无法执行 `{{action}}`,因为找不到 {{displayName}} 可执行文件。请先安装 {{displayName}},或更新 `nb config set {{configKey}} <path>` 后重试。"
|
|
153
|
+
"missingCommand": "无法执行 `{{action}}`,因为找不到 {{displayName}} 可执行文件。请先安装 {{displayName}},或更新 `nb config set {{configKey}} <path>` 后重试。",
|
|
154
|
+
"targetEnv": "正在使用 env \"{{envName}}\"。",
|
|
155
|
+
"crossEnv": {
|
|
156
|
+
"prompt": "当前 env 是 \"{{currentEnv}}\",但该命令通过 --env 指向了 \"{{requestedEnv}}\"。要在不切换当前 env 的情况下继续吗?",
|
|
157
|
+
"refusal": "拒绝对 env \"{{requestedEnv}}\" 执行该命令,因为当前 env 是 \"{{currentEnv}}\",且当前 agent 会话无法进行交互确认。\n\n出于安全考虑,agent 不会自动切换 env,也不会替你自动补上 --yes。\n\n如果要继续:\n- 请先自行执行 `nb env use {{requestedEnv}}`,然后重新运行该命令,或\n- 使用相同命令并追加 `--env {{requestedEnv}} --yes`,以确认这是一次性的跨 env 操作。"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"license": {
|
|
161
|
+
"activate": {
|
|
162
|
+
"interactive": {
|
|
163
|
+
"notice": {
|
|
164
|
+
"hostnameLabel": "❯ 主机名",
|
|
165
|
+
"instanceIdLabel": "❯ 实例 ID",
|
|
166
|
+
"copyHintWithHostname": "校验或激活 license key 时,请复制这个主机名和实例 ID。",
|
|
167
|
+
"copyHintWithoutHostname": "校验或激活 license key 时,请复制这个实例 ID。"
|
|
168
|
+
},
|
|
169
|
+
"prompts": {
|
|
170
|
+
"provideMethod": {
|
|
171
|
+
"message": "你想通过哪种方式提供 license key?",
|
|
172
|
+
"keyOption": "直接粘贴 license key",
|
|
173
|
+
"fileOption": "从文件读取 key"
|
|
174
|
+
},
|
|
175
|
+
"key": {
|
|
176
|
+
"message": "License Key",
|
|
177
|
+
"transformer": "已输入 {{count}} 个字符",
|
|
178
|
+
"required": "必须提供 license key。"
|
|
179
|
+
},
|
|
180
|
+
"keyFile": {
|
|
181
|
+
"message": "license key 文件路径",
|
|
182
|
+
"required": "必须提供 license key 文件路径。"
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
"errors": {
|
|
187
|
+
"provideKeyOrKeyFile": "请通过 --key 或 --key-file 继续。",
|
|
188
|
+
"emptyInput": "license key 输入为空。",
|
|
189
|
+
"activationFailed": "为 env \"{{envName}}\" 激活 license 失败:{{reason}}。",
|
|
190
|
+
"reasons": {
|
|
191
|
+
"keyStatus": "license key 状态为 {{status}}",
|
|
192
|
+
"envMismatch": "license key 与当前实例环境不匹配",
|
|
193
|
+
"domainMismatch": "license key 与当前应用域名不匹配",
|
|
194
|
+
"licenseStatus": "license 状态为 {{status}}",
|
|
195
|
+
"validationFailed": "license 校验失败"
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
"messages": {
|
|
199
|
+
"activated": "已为 env \"{{envName}}\" 激活 license。",
|
|
200
|
+
"savedLicenseKey": "license key 已保存到 {{licenseKeyPath}}"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
121
203
|
},
|
|
122
204
|
"download": {
|
|
123
205
|
"failures": {
|
|
@@ -236,9 +318,9 @@
|
|
|
236
318
|
"lang": {
|
|
237
319
|
"message": "你想使用哪种语言?"
|
|
238
320
|
},
|
|
239
|
-
"
|
|
240
|
-
"message": "
|
|
241
|
-
"placeholder": "./<env>/
|
|
321
|
+
"appPath": {
|
|
322
|
+
"message": "应用要放到哪里?(相对路径基于 {{root}})",
|
|
323
|
+
"placeholder": "./<env>/"
|
|
242
324
|
},
|
|
243
325
|
"appPort": {
|
|
244
326
|
"message": "应用要使用哪个端口?",
|
|
@@ -325,10 +407,14 @@
|
|
|
325
407
|
"message": "这个环境要使用什么 `--env` 标识?",
|
|
326
408
|
"placeholder": "local"
|
|
327
409
|
},
|
|
328
|
-
"
|
|
329
|
-
"message": "
|
|
330
|
-
"
|
|
331
|
-
"
|
|
410
|
+
"setupMode": {
|
|
411
|
+
"message": "你想用哪种方式配置这个环境?",
|
|
412
|
+
"installNewLabel": "新安装",
|
|
413
|
+
"installNewHint": "从零安装一个新的应用,适合首次部署、试用或新建本地开发环境。",
|
|
414
|
+
"manageLocalLabel": "本机接管",
|
|
415
|
+
"manageLocalHint": "将本机已有应用纳入 nb 管理,后续可统一执行安装、升级和启动等操作。接管过程中会重新下载应用代码或镜像并升级应用,storage 会在需要时自动创建。",
|
|
416
|
+
"connectRemoteLabel": "远程连接",
|
|
417
|
+
"connectRemoteHint": "只保存远程应用的连接信息,不在本机安装或接管应用。"
|
|
332
418
|
},
|
|
333
419
|
"installSkills": {
|
|
334
420
|
"message": "是否安装 NocoBase AI coding skills(nocobase/skills)?"
|
|
@@ -344,22 +430,22 @@
|
|
|
344
430
|
"webUi": {
|
|
345
431
|
"pageTitle": "配置供 Coding Agents 使用的 NocoBase",
|
|
346
432
|
"documentHeading": "配置供 Coding Agents 使用的 NocoBase",
|
|
347
|
-
"documentHint": "
|
|
433
|
+
"documentHint": "安装一个新的应用、接管本机已有应用,或连接远程应用,让 Coding Agents 可以在当前工作区中访问和操作 NocoBase。",
|
|
348
434
|
"gettingStarted": {
|
|
349
435
|
"title": "开始设置",
|
|
350
|
-
"description": "
|
|
436
|
+
"description": "选择新安装、本机接管,或远程连接。"
|
|
351
437
|
},
|
|
352
438
|
"connectExistingApp": {
|
|
353
|
-
"title": "
|
|
354
|
-
"description": "
|
|
439
|
+
"title": "远程连接",
|
|
440
|
+
"description": "保存远程应用连接。"
|
|
355
441
|
},
|
|
356
442
|
"createNewApp": {
|
|
357
|
-
"title": "
|
|
358
|
-
"description": "
|
|
443
|
+
"title": "应用环境信息",
|
|
444
|
+
"description": "设置应用的基础信息、存储位置和运行端口。"
|
|
359
445
|
},
|
|
360
446
|
"downloadAppFiles": {
|
|
361
|
-
"title": "
|
|
362
|
-
"description": "
|
|
447
|
+
"title": "应用来源和版本",
|
|
448
|
+
"description": "选择应用的获取方式,以及要使用的来源和版本。"
|
|
363
449
|
},
|
|
364
450
|
"configureDatabase": {
|
|
365
451
|
"title": "配置数据库",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nocobase/cli",
|
|
3
|
-
"version": "2.1.0-beta.
|
|
3
|
+
"version": "2.1.0-beta.44.test.1",
|
|
4
4
|
"description": "NocoBase Command Line Tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/generated/command-registry.js",
|
|
@@ -12,11 +12,6 @@
|
|
|
12
12
|
"keywords": [],
|
|
13
13
|
"author": "",
|
|
14
14
|
"license": "Apache-2.0",
|
|
15
|
-
"files": [
|
|
16
|
-
"bin",
|
|
17
|
-
"dist",
|
|
18
|
-
"nocobase-ctl.config.json"
|
|
19
|
-
],
|
|
20
15
|
"bin": {
|
|
21
16
|
"nb": "./bin/run.js"
|
|
22
17
|
},
|
|
@@ -73,6 +68,9 @@
|
|
|
73
68
|
"skills": {
|
|
74
69
|
"description": "Inspect or synchronize NocoBase AI coding skills for the current workspace."
|
|
75
70
|
},
|
|
71
|
+
"revision": {
|
|
72
|
+
"description": "Manage restorable revisions during NocoBase app building."
|
|
73
|
+
},
|
|
76
74
|
"examples": {
|
|
77
75
|
"description": "Internal example commands for prompt and UI experiments.",
|
|
78
76
|
"hidden": true
|
|
@@ -139,6 +137,5 @@
|
|
|
139
137
|
"repository": {
|
|
140
138
|
"type": "git",
|
|
141
139
|
"url": "git+https://github.com/nocobase/nocobase.git"
|
|
142
|
-
}
|
|
143
|
-
"gitHead": "6d7750e2373bf2451d246de88cc1f62491685e18"
|
|
140
|
+
}
|
|
144
141
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { copyFileSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const scriptsDir = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const packageRoot = path.resolve(scriptsDir, '..');
|
|
10
|
+
const distDir = path.join(packageRoot, 'dist');
|
|
11
|
+
const srcLocaleDir = path.join(packageRoot, 'src', 'locale');
|
|
12
|
+
const distLocaleDir = path.join(distDir, 'locale');
|
|
13
|
+
const tscBin = require.resolve('typescript/bin/tsc');
|
|
14
|
+
|
|
15
|
+
rmSync(distDir, { recursive: true, force: true });
|
|
16
|
+
|
|
17
|
+
const compile = spawnSync(process.execPath, [tscBin, '-p', path.join(packageRoot, 'tsconfig.json')], {
|
|
18
|
+
cwd: packageRoot,
|
|
19
|
+
stdio: 'inherit',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
if (compile.status !== 0) {
|
|
23
|
+
process.exit(compile.status ?? 1);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
mkdirSync(distLocaleDir, { recursive: true });
|
|
27
|
+
|
|
28
|
+
for (const entry of readdirSync(srcLocaleDir, { withFileTypes: true })) {
|
|
29
|
+
if (!entry.isFile() || !entry.name.endsWith('.json')) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
copyFileSync(path.join(srcLocaleDir, entry.name), path.join(distLocaleDir, entry.name));
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { rmSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const scriptsDir = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const packageRoot = path.resolve(scriptsDir, '..');
|
|
7
|
+
const distDir = path.join(packageRoot, 'dist');
|
|
8
|
+
|
|
9
|
+
rmSync(distDir, { recursive: true, force: true });
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"rewriteRelativeImportExtensions": true,
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"outDir": "dist",
|
|
9
|
+
"declaration": false,
|
|
10
|
+
"resolveJsonModule": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"types": ["node"],
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"strict": false
|
|
16
|
+
},
|
|
17
|
+
"include": ["src/**/*.ts"],
|
|
18
|
+
"exclude": ["src/**/__tests__/**"]
|
|
19
|
+
}
|
package/LICENSE.txt
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
Updated Date: February 24, 2026
|
|
2
|
-
|
|
3
|
-
NocoBase License Agreement
|
|
4
|
-
|
|
5
|
-
NOCOBASE PTE. LTD.,a Singaporean Exempt Private Company Limited by Shares with its principal place of business located at 112 ROBINSON ROAD, #03-01, SINGAPORE ("The Company") https://www.nocobase.com/ issues this License Agreement ("Agreement") to you. You, as an individual or a company ("The User"), will be deemed to voluntarily accept all terms of this Agreement by using NocoBase (including but not limited to obtaining NocoBase source code or installation package in any form, installing and using NocoBase, purchasing NocoBase commercial license and services, purchasing NocoBase commercial plugins). If the User does not agree to any term of this Agreement, or cannot accurately understand our interpretation of the relevant terms, please stop using it immediately.
|
|
6
|
-
|
|
7
|
-
This Agreement applies to any use, quotation, contract, invoice, and all software delivered by the Company. The User and the Company or NocoBase's agents can no longer sign a separate license agreement for the sale and delivery of the software.
|
|
8
|
-
|
|
9
|
-
The Company reserves the right to formulate and modify this Agreement from time to time as needed. If there are changes, the Company will announce them in the form of website announcements, without further individual notification. The changed Agreement will automatically take effect once it is announced, becoming part of this Agreement.
|
|
10
|
-
|
|
11
|
-
==============
|
|
12
|
-
1. Definitions
|
|
13
|
-
==============
|
|
14
|
-
|
|
15
|
-
1.1 "Software" refers to the NocoBase kernel and plugins placed in the same code repository as the kernel, including their source code, installation packages, images, and all their modifications, updates, and upgrades.
|
|
16
|
-
|
|
17
|
-
1.2 "Community Edition" refers to the free version of the Software provided to the User through public channels.
|
|
18
|
-
|
|
19
|
-
1.3 "Commercial Edition" refers to the paid version of the Software purchased by the User from the Company or its agents, downloaded through exclusive channels, and includes additional benefits. It consists of three versions: Standard Edition, Professional Edition, and Enterprise Edition.
|
|
20
|
-
|
|
21
|
-
1.4 "Upper Layer Application" refers to a specific business use case application serving internal or external customers of the User, developed based on Software and Commercial Plugins, such as ERP/CRM.
|
|
22
|
-
|
|
23
|
-
1.5 "Customer" refers to the clients who purchase the User's Upper Layer Application.
|
|
24
|
-
|
|
25
|
-
1.6 "Third-Party Open Source Software" refers to open source software provided with Software and Commercial Plugins. They are licensed through various published open source software licenses or copyright notices accompanying such software.
|
|
26
|
-
|
|
27
|
-
===================================
|
|
28
|
-
2. Intellectual Property Protection
|
|
29
|
-
===================================
|
|
30
|
-
|
|
31
|
-
Except for Third-Party Open Source Software, the Company owns all copyrights, trademark rights, patent rights, trade secrets, and other intellectual property rights of the Software, and has registered and protected them in relevant countries and regions according to the "Paris Convention" or "TRIPS Agreement", ensuring that the intellectual property rights of the Software and Commercial Plugins are internationally recognized and protected.
|
|
32
|
-
|
|
33
|
-
=============
|
|
34
|
-
3. Disclaimer
|
|
35
|
-
=============
|
|
36
|
-
|
|
37
|
-
3.1 The User shall not use the Software and Commercial Plugins to engage in activities that contravene applicable laws and regulations or offend against public order or religious prohibitions. All legal liabilities and consequences arising from the User’s use shall be borne by the User.
|
|
38
|
-
|
|
39
|
-
3.2 The Company shall not be liable for any direct, indirect, special, incidental, or consequential damages (including but not limited to loss of profits, business interruption, data loss, or business information disclosure) caused by the User's use of the Software and Commercial Plugins, even if it has been previously informed of the possibility of such damages.
|
|
40
|
-
|
|
41
|
-
===============
|
|
42
|
-
4. License Type
|
|
43
|
-
===============
|
|
44
|
-
|
|
45
|
-
4.1 This Agreement serves as the unified license agreement for NocoBase Software, applying to both the Community Edition and the Commercial Editions.
|
|
46
|
-
|
|
47
|
-
4.2 This Agreement incorporates and references the full text of the Apache License, Version 2.0 ("Apache-2.0", available at: https://www.apache.org/licenses/LICENSE-2.0 ). Users must comply with the Apache-2.0 License as well as the supplementary terms set forth in this Agreement. In case of any inconsistency between Apache-2.0 and this Agreement, the supplementary terms of this Agreement shall prevail.
|
|
48
|
-
|
|
49
|
-
================================================
|
|
50
|
-
5. Rights and Obligations of Open Source License
|
|
51
|
-
================================================
|
|
52
|
-
|
|
53
|
-
5.1 The Software can be used for commercial purposes.
|
|
54
|
-
|
|
55
|
-
5.2 It is not allowed to remove or change the brand, name, link, version number, license, and other information about NocoBase on the Software interface, except for the main LOGO in the upper left corner of the page.
|
|
56
|
-
|
|
57
|
-
5.3 It is not allowed to remove or change all intellectual property statements about NocoBase in the code.
|
|
58
|
-
|
|
59
|
-
5.4 It is not allowed to provide to the public any form of no-code, zero-code, low-code, AI platform SaaS/PaaS products using the original or modified Software.
|
|
60
|
-
|
|
61
|
-
===============================
|
|
62
|
-
6. Rights of Commercial License
|
|
63
|
-
===============================
|
|
64
|
-
|
|
65
|
-
6.1 Obtain a permanent commercial license of the Software.
|
|
66
|
-
|
|
67
|
-
6.2 Get software upgrades and exclusive technical support during the upgrade validity period.
|
|
68
|
-
|
|
69
|
-
6.3 The licensed Software can be used for commercial purposes with no restrictions on the number of applications and users.
|
|
70
|
-
|
|
71
|
-
6.4 Can remove or change the brand, name, link, version number, license, and other information about NocoBase on the Software interface.
|
|
72
|
-
|
|
73
|
-
6.5 The User holding a Professional or Enterprise Edition License can sell Upper Layer Application to its Customers.
|
|
74
|
-
|
|
75
|
-
6.6 If there are other agreements in the contract for the above rights, the contract agreement shall prevail.
|
|
76
|
-
|
|
77
|
-
====================================
|
|
78
|
-
7. Obligations of Commercial License
|
|
79
|
-
====================================
|
|
80
|
-
|
|
81
|
-
7.1 It is not allowed to remove or change all intellectual property statements about NocoBase in the code.
|
|
82
|
-
|
|
83
|
-
7.2 It is not allowed to sell, transfer, lease, share, gift, or distribute the Commercial License.
|
|
84
|
-
|
|
85
|
-
7.3 It is not allowed to sell, transfer, lease, share, or distribute any form of no-code, zero-code, low-code, AI platform, or developer tools developed based on Software.
|
|
86
|
-
|
|
87
|
-
7.4 It is not allowed to provide any form of no-code, zero-code, low-code, AI platform SaaS/PaaS products to the public using the original or modified Software.
|
|
88
|
-
|
|
89
|
-
7.5 It is not allowed for the User holding a Standard Edition license to sell Upper Layer Application to Customers without a Commercial license.
|
|
90
|
-
|
|
91
|
-
7.6 It is not allowed for the User holding a Professional or Enterprise Edition license to sell Upper Layer Application to Customers without a Commercial license with access to further development and configuration.
|
|
92
|
-
|
|
93
|
-
7.7 If there is a violation of the above obligations or the terms of this Agreement, the rights owned by the User will be immediately terminated, the paid fees will not be refunded, and the Company reserves the right to pursue the User's legal responsibility.
|
|
94
|
-
|
|
95
|
-
7.8 If there are other agreements in the contract for the above obligations, the contract agreement shall prevail.
|
|
96
|
-
|
|
97
|
-
=============================================================
|
|
98
|
-
8. Legal Jurisdiction, Interpretation, and Dispute Resolution
|
|
99
|
-
=============================================================
|
|
100
|
-
|
|
101
|
-
8.1 Except for Mainland China, the interpretation, application, and all matters related to this agreement are subject to the jurisdiction of Singapore law.
|
|
102
|
-
|
|
103
|
-
8.2 Any dispute related to this Agreement should first be resolved through friendly negotiation. If the negotiation fails to resolve the dispute, the dispute should be submitted to the International Chamber of Commerce (ICC) for arbitration. The arbitration venue should be Singapore, conducted in English.
|
|
104
|
-
|
|
105
|
-
8.3 All terms and conditions of this Agreement shall be deemed enforceable to the maximum extent permitted by applicable law. If any term of this Agreement is deemed invalid by any applicable law, the invalidity of that term does not affect the validity of any other term of this Agreement, and it should be deemed that the invalid term has been modified as much as possible to make it valid and enforceable, or if the term cannot be modified, it should be deemed to have been deleted from this Agreement.
|
|
106
|
-
|
|
107
|
-
8.4 The arbitration award is final, binding on both parties, and can be enforced in any court with jurisdiction.
|