sitevision-cli 1.0.0-beta.32 → 1.0.0-beta.33
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/CHANGELOG.md +50 -0
- package/LICENSE +21 -0
- package/dist/cli.js +56 -35
- package/dist/commands/TaskScreen.js +32 -0
- package/dist/commands/build.js +6 -185
- package/dist/commands/deploy.js +85 -238
- package/dist/commands/dev.js +34 -37
- package/dist/commands/info.js +1 -1
- package/dist/commands/setup-signing.js +43 -28
- package/dist/commands/sign.js +9 -86
- package/dist/commands/use-finish.js +17 -0
- package/dist/commands/watch.js +0 -8
- package/dist/components/AuthLoginScreen.js +27 -12
- package/dist/shell/ConfigForm.js +90 -29
- package/dist/shell/Frame.js +4 -1
- package/dist/shell/Help.js +2 -1
- package/dist/shell/Settings.js +59 -6
- package/dist/shell/Shell.js +124 -41
- package/dist/shell/Tabs.js +8 -2
- package/dist/shell/actions.js +0 -0
- package/dist/utils/config.js +46 -3
- package/dist/utils/create-app.js +9 -2
- package/dist/utils/i18n.js +36 -13
- package/dist/utils/jsonc.js +2 -1
- package/dist/utils/keychain.js +44 -4
- package/dist/utils/oauth2-auth.js +35 -7
- package/dist/utils/password-prompt.js +23 -3
- package/dist/utils/process-runner.js +4 -2
- package/dist/utils/project-detection.js +84 -33
- package/dist/utils/session-cookie-auth.js +5 -4
- package/dist/utils/sitevision-api.js +21 -14
- package/dist/utils/sitevision-scripts-runner.js +32 -15
- package/dist/utils/tasks.js +130 -64
- package/dist/utils/version-check.js +3 -3
- package/dist/utils/webpack-runner.js +6 -5
- package/dist/utils/workspace.js +41 -3
- package/dist/utils/zip.js +18 -19
- package/package.json +24 -3
- package/readme.md +11 -4
- package/dist/app.d.ts +0 -6
- package/dist/app.js +0 -321
- package/dist/cli.d.ts +0 -2
- package/dist/commands/build.d.ts +0 -12
- package/dist/commands/deploy.d.ts +0 -17
- package/dist/commands/dev.d.ts +0 -14
- package/dist/commands/index.d.ts +0 -4
- package/dist/commands/info.d.ts +0 -2
- package/dist/commands/setup-signing.d.ts +0 -2
- package/dist/commands/sign.d.ts +0 -14
- package/dist/commands/types.d.ts +0 -18
- package/dist/commands/watch.d.ts +0 -2
- package/dist/components/AnimatedLogo.d.ts +0 -10
- package/dist/components/AuthLoginScreen.d.ts +0 -21
- package/dist/components/DevPropertiesForm.d.ts +0 -11
- package/dist/components/DevPropertiesForm.js +0 -246
- package/dist/components/InfoScreen.d.ts +0 -7
- package/dist/components/InfoScreen.js +0 -14
- package/dist/components/KeychainPasswordChoice.d.ts +0 -8
- package/dist/components/KeychainPasswordChoice.js +0 -30
- package/dist/components/MainMenu.d.ts +0 -7
- package/dist/components/MainMenu.js +0 -88
- package/dist/components/PasswordInput.d.ts +0 -10
- package/dist/components/ProcessOutput.d.ts +0 -6
- package/dist/components/ProcessOutput.js +0 -30
- package/dist/components/SetupFlow.d.ts +0 -8
- package/dist/components/SetupFlow.js +0 -233
- package/dist/components/SigningPropertiesForm.d.ts +0 -7
- package/dist/components/SigningPropertiesForm.js +0 -38
- package/dist/components/StatusIndicator.d.ts +0 -8
- package/dist/components/TextInput.d.ts +0 -10
- package/dist/components/TextInput.js +0 -29
- package/dist/components/WelcomeScreen.d.ts +0 -14
- package/dist/scaffold/inquirer-stub.d.ts +0 -6
- package/dist/scaffold/register.d.ts +0 -1
- package/dist/shell/AddonPicker.d.ts +0 -14
- package/dist/shell/Changelog.d.ts +0 -10
- package/dist/shell/CommandPalette.d.ts +0 -12
- package/dist/shell/ConfigForm.d.ts +0 -42
- package/dist/shell/Frame.d.ts +0 -59
- package/dist/shell/Help.d.ts +0 -9
- package/dist/shell/Popover.d.ts +0 -12
- package/dist/shell/Settings.d.ts +0 -6
- package/dist/shell/Shell.d.ts +0 -11
- package/dist/shell/Tabs.d.ts +0 -36
- package/dist/shell/actions.d.ts +0 -49
- package/dist/types/index.d.ts +0 -295
- package/dist/utils/branding.d.ts +0 -28
- package/dist/utils/config.d.ts +0 -27
- package/dist/utils/create-app.d.ts +0 -53
- package/dist/utils/environments.d.ts +0 -20
- package/dist/utils/i18n.d.ts +0 -12
- package/dist/utils/jsonc.d.ts +0 -19
- package/dist/utils/keychain.d.ts +0 -15
- package/dist/utils/oauth2-auth.d.ts +0 -64
- package/dist/utils/password-prompt.d.ts +0 -14
- package/dist/utils/process-runner.d.ts +0 -32
- package/dist/utils/project-detection.d.ts +0 -210
- package/dist/utils/session-cookie-auth.d.ts +0 -35
- package/dist/utils/signing-password.d.ts +0 -12
- package/dist/utils/signing-step.d.ts +0 -15
- package/dist/utils/signing-step.js +0 -16
- package/dist/utils/sitevision-api.d.ts +0 -155
- package/dist/utils/sitevision-scripts-runner.d.ts +0 -84
- package/dist/utils/tasks.d.ts +0 -61
- package/dist/utils/version-check.d.ts +0 -9
- package/dist/utils/webpack-runner.d.ts +0 -76
- package/dist/utils/workspace.d.ts +0 -17
- package/dist/utils/zip.d.ts +0 -71
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.33
|
|
4
|
+
|
|
5
|
+
- **Breaking:** `--token` and `--cookie` are removed, since credentials on the
|
|
6
|
+
command line end up in shell history. Use `SITEVISION_ACCESS_TOKEN` or
|
|
7
|
+
`SITEVISION_SESSION_COOKIE` instead.
|
|
8
|
+
- **Breaking:** an unknown flag is now an error (exit code 2), so a misspelt
|
|
9
|
+
`--production` never turns into a dev deploy.
|
|
10
|
+
- `svc build`, `svc sign` and `svc deploy` work without a terminal. They print
|
|
11
|
+
their log line by line and exit on their own with a proper exit code: 0 on
|
|
12
|
+
success, 1 on failure, 130 when a prompt is cancelled. `svc dev` and
|
|
13
|
+
`svc watch` no longer crash when stdin is a pipe.
|
|
14
|
+
- New flags: `--no-zip` for `build`, and the short forms `-s`, `-f`, `-p` and
|
|
15
|
+
`-a`.
|
|
16
|
+
- Global settings in `~/.config/sitevision-cli/config.json`: a default signing
|
|
17
|
+
user and certificate for every project that does not set its own, and
|
|
18
|
+
switches for the update check and the addon name warning. Edit them with `,`
|
|
19
|
+
in the shell, which now shows a description of each setting and opens from
|
|
20
|
+
anywhere, or run `svc setup-signing --global`. A file that does not parse is
|
|
21
|
+
reported and left alone.
|
|
22
|
+
- The Config tab marks the addon name with `≠ manifest` when it matches none
|
|
23
|
+
of the manifest's names. Nothing is changed for you; the two are different
|
|
24
|
+
things and `svc` only points the difference out.
|
|
25
|
+
- The manifest's name and description always have a Swedish row in the Config
|
|
26
|
+
tab. Filling it in on a plain name keeps the old text as the English one.
|
|
27
|
+
- In a workspace, an environment's addon name is stored per app. Setting it
|
|
28
|
+
for one app no longer leaks into the others.
|
|
29
|
+
- `svc` names the missing setting when the deploy config is incomplete,
|
|
30
|
+
instead of posting to "undefined".
|
|
31
|
+
- A production deploy with `--activate` fails if the activation did not
|
|
32
|
+
happen, and the confirmation names the addon it deploys to.
|
|
33
|
+
- OAuth2 requires https and a token endpoint on the site's own domain. A
|
|
34
|
+
refresh token is only thrown away when the site rejects it, not on a network
|
|
35
|
+
error. An expired session cookie is removed so the next deploy asks for a
|
|
36
|
+
new login.
|
|
37
|
+
- A plaintext password in `.dev_properties.json` is moved to the keychain when
|
|
38
|
+
the file is saved, and `svc` says so when the keychain cannot store a secret.
|
|
39
|
+
`SVC_NO_KEYCHAIN=1` turns the keychain off for CI.
|
|
40
|
+
- `svc dev` with a project's own webpack config no longer deploys a half-built
|
|
41
|
+
zip when several files change at once.
|
|
42
|
+
- Builds work when dependencies are hoisted to the workspace root, a
|
|
43
|
+
`manifest.json` in the project root is picked up, file names with å, ä and ö
|
|
44
|
+
survive in the zip, and `SITEVISION_APP_ID_PREFIX`/`_SUFFIX` apply to build,
|
|
45
|
+
sign and deploy alike.
|
|
46
|
+
- A broken app in a workspace is skipped with a message instead of stopping
|
|
47
|
+
the shell. The shell asks before quitting during app creation, the PROD
|
|
48
|
+
badge survives a narrow terminal, Esc cancels a confirm, and Ctrl-modified
|
|
49
|
+
keys never fire a shortcut.
|
|
50
|
+
- The update check is skipped without a terminal and when `CI` is set.
|
|
51
|
+
- Updated user guides in English and Swedish.
|
|
52
|
+
|
|
3
53
|
## 1.0.0-beta.32
|
|
4
54
|
|
|
5
55
|
- Sitevision CLI can now create new apps. **New app** in the command palette
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rasmus Söderström
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { requireProject, detectProject, migrateLegacyPassword, } from './utils/p
|
|
|
13
13
|
import { discoverApps } from './utils/workspace.js';
|
|
14
14
|
import { promptYesNo } from './utils/password-prompt.js';
|
|
15
15
|
import { checkForUpdate } from './utils/version-check.js';
|
|
16
|
-
import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, getSettings, } from './utils/config.js';
|
|
16
|
+
import { isFirstRun, markFirstRunComplete, getLastSeenVersion, setLastSeenVersion, getSettings, configProblem, settingsFile, } from './utils/config.js';
|
|
17
17
|
import { setLanguage } from './utils/i18n.js';
|
|
18
18
|
import { WelcomeScreen } from './components/WelcomeScreen.js';
|
|
19
19
|
import { AnimatedLogo } from './components/AnimatedLogo.js';
|
|
@@ -31,11 +31,21 @@ const cli = meow(`
|
|
|
31
31
|
sign Sign the app for production deployment
|
|
32
32
|
deploy Deploy the application
|
|
33
33
|
info Show project information
|
|
34
|
+
setup-signing Store the signing username and certificate
|
|
34
35
|
|
|
35
36
|
Options
|
|
36
|
-
--
|
|
37
|
-
--
|
|
38
|
-
--
|
|
37
|
+
--signed, -s dev/watch: sign after each build
|
|
38
|
+
--force, -f deploy: overwrite the existing addon version
|
|
39
|
+
--production, -p deploy: upload the signed zip to production
|
|
40
|
+
--activate, -a deploy: activate after a production deploy
|
|
41
|
+
--no-zip build: skip the zip archive
|
|
42
|
+
--global setup-signing: save for every project on this machine
|
|
43
|
+
--minimal Shell: compact layout for small terminals
|
|
44
|
+
--help Show this help message
|
|
45
|
+
--version Show version number
|
|
46
|
+
|
|
47
|
+
Credentials for CI come from the environment: SITEVISION_DEPLOY_PASSWORD,
|
|
48
|
+
SITEVISION_ACCESS_TOKEN or SITEVISION_SESSION_COOKIE.
|
|
39
49
|
|
|
40
50
|
Examples
|
|
41
51
|
$ svc # Shell: run inside an app, or at the repo root
|
|
@@ -50,9 +60,20 @@ const cli = meow(`
|
|
|
50
60
|
$ svc info
|
|
51
61
|
`, {
|
|
52
62
|
importMeta: import.meta,
|
|
63
|
+
allowUnknownFlags: false,
|
|
53
64
|
flags: {
|
|
54
65
|
signed: {
|
|
55
66
|
type: 'boolean',
|
|
67
|
+
shortFlag: 's',
|
|
68
|
+
default: false,
|
|
69
|
+
},
|
|
70
|
+
zip: {
|
|
71
|
+
type: 'boolean',
|
|
72
|
+
default: true,
|
|
73
|
+
},
|
|
74
|
+
activate: {
|
|
75
|
+
type: 'boolean',
|
|
76
|
+
shortFlag: 'a',
|
|
56
77
|
default: false,
|
|
57
78
|
},
|
|
58
79
|
force: {
|
|
@@ -65,16 +86,14 @@ const cli = meow(`
|
|
|
65
86
|
shortFlag: 'p',
|
|
66
87
|
default: false,
|
|
67
88
|
},
|
|
68
|
-
token: {
|
|
69
|
-
type: 'string',
|
|
70
|
-
},
|
|
71
|
-
cookie: {
|
|
72
|
-
type: 'string',
|
|
73
|
-
},
|
|
74
89
|
minimal: {
|
|
75
90
|
type: 'boolean',
|
|
76
91
|
default: false,
|
|
77
92
|
},
|
|
93
|
+
global: {
|
|
94
|
+
type: 'boolean',
|
|
95
|
+
default: false,
|
|
96
|
+
},
|
|
78
97
|
},
|
|
79
98
|
});
|
|
80
99
|
const [commandName, ...args] = cli.input;
|
|
@@ -145,10 +164,19 @@ async function playIntro(art) {
|
|
|
145
164
|
// Run the full-screen shell on the alternate screen buffer so the scrollback
|
|
146
165
|
// is untouched, and restore it on exit. The animated wordmark plays first,
|
|
147
166
|
// inside the same buffer, when the terminal is wide enough for it.
|
|
148
|
-
async function runShell(apps, workspaceRoot, updatedFrom) {
|
|
167
|
+
async function runShell(apps, workspaceRoot, updatedFrom, skipped = []) {
|
|
149
168
|
process.stdout.write('\x1b[?1049h\x1b[H');
|
|
150
169
|
// Also leave the alternate screen when a signal exits past the finally.
|
|
151
170
|
process.once('exit', () => process.stdout.write('\x1b[?1049l'));
|
|
171
|
+
// A crash outside React would print into the alternate screen and vanish
|
|
172
|
+
// with it: leave it first, then report.
|
|
173
|
+
const crash = (error) => {
|
|
174
|
+
process.stdout.write('\x1b[?1049l');
|
|
175
|
+
console.error('svc crashed:', error);
|
|
176
|
+
shutdown(1);
|
|
177
|
+
};
|
|
178
|
+
process.once('uncaughtException', crash);
|
|
179
|
+
process.once('unhandledRejection', crash);
|
|
152
180
|
try {
|
|
153
181
|
const art = process.stdin.isTTY && settings.introAnimation && !cli.flags.minimal
|
|
154
182
|
? pickIntroArt(process.stdout.columns ?? 0)
|
|
@@ -161,7 +189,7 @@ async function runShell(apps, workspaceRoot, updatedFrom) {
|
|
|
161
189
|
// the terminal to itself, and starts the shell again.
|
|
162
190
|
for (;;) {
|
|
163
191
|
let job;
|
|
164
|
-
const app = render(_jsx(Shell, { apps: apps, workspaceRoot: workspaceRoot, version: pkg.version, minimal: cli.flags.minimal, updatedFrom: updatedFrom, handover: next => {
|
|
192
|
+
const app = render(_jsx(Shell, { apps: apps, workspaceRoot: workspaceRoot, version: pkg.version, minimal: cli.flags.minimal, updatedFrom: updatedFrom, skipped: skipped, handover: next => {
|
|
165
193
|
job = next;
|
|
166
194
|
app.unmount();
|
|
167
195
|
} }));
|
|
@@ -172,8 +200,10 @@ async function runShell(apps, workspaceRoot, updatedFrom) {
|
|
|
172
200
|
process.stdout.write('\x1b[?1049l');
|
|
173
201
|
// eslint-disable-next-line no-await-in-loop
|
|
174
202
|
await job();
|
|
175
|
-
if (workspaceRoot)
|
|
176
|
-
|
|
203
|
+
if (workspaceRoot) {
|
|
204
|
+
skipped = [];
|
|
205
|
+
apps = discoverApps(workspaceRoot, skipped);
|
|
206
|
+
}
|
|
177
207
|
updatedFrom = undefined;
|
|
178
208
|
process.stdout.write('\x1b[?1049h\x1b[2J\x1b[H');
|
|
179
209
|
}
|
|
@@ -209,8 +239,13 @@ async function main() {
|
|
|
209
239
|
}
|
|
210
240
|
// Record the current version so the banner shows once per upgrade.
|
|
211
241
|
setLastSeenVersion(pkg.version);
|
|
242
|
+
if (configProblem()) {
|
|
243
|
+
console.log(`\x1b[33m ${settingsFile()} does not parse and is ignored: ${configProblem()}\x1b[0m`);
|
|
244
|
+
}
|
|
212
245
|
// Check npm for a newer published release.
|
|
213
|
-
const latestVersion =
|
|
246
|
+
const latestVersion = settings.updateCheck && process.stdout.isTTY && !process.env['CI']
|
|
247
|
+
? await checkForUpdate(pkg.name, pkg.version)
|
|
248
|
+
: null;
|
|
214
249
|
if (latestVersion) {
|
|
215
250
|
console.log(`\x1b[33m ↑ update available: ${pkg.version} → ${latestVersion} (run: npm i -g ${pkg.name})\x1b[0m`);
|
|
216
251
|
}
|
|
@@ -226,11 +261,13 @@ async function main() {
|
|
|
226
261
|
fail(error.message, 'Fix the manifest and try again');
|
|
227
262
|
}
|
|
228
263
|
if (!project) {
|
|
229
|
-
const
|
|
264
|
+
const skipped = [];
|
|
265
|
+
const apps = discoverApps(process.cwd(), skipped);
|
|
230
266
|
if (apps.length === 0) {
|
|
231
|
-
fail('No Sitevision apps found here.',
|
|
267
|
+
fail('No Sitevision apps found here.', skipped[0] ??
|
|
268
|
+
'Run svc inside an app directory (manifest.json) or at the root of a repo that contains apps.');
|
|
232
269
|
}
|
|
233
|
-
await runShell(apps, process.cwd(), isUpdate ? lastSeen : undefined);
|
|
270
|
+
await runShell(apps, process.cwd(), isUpdate ? lastSeen : undefined, skipped);
|
|
234
271
|
shutdown();
|
|
235
272
|
return;
|
|
236
273
|
}
|
|
@@ -257,22 +294,6 @@ async function main() {
|
|
|
257
294
|
return fail(error.message, "Make sure you're in a Sitevision project directory");
|
|
258
295
|
}
|
|
259
296
|
})();
|
|
260
|
-
// --token / --cookie override the resolved bearer token / session cookie for
|
|
261
|
-
// this run (manual / CI path, alongside SITEVISION_ACCESS_TOKEN and
|
|
262
|
-
// SITEVISION_SESSION_COOKIE).
|
|
263
|
-
if (cli.flags.token || cli.flags.cookie) {
|
|
264
|
-
if (project.devProperties) {
|
|
265
|
-
if (cli.flags.token) {
|
|
266
|
-
project.devProperties.accessToken = cli.flags.token;
|
|
267
|
-
}
|
|
268
|
-
if (cli.flags.cookie) {
|
|
269
|
-
project.devProperties.sessionCookie = cli.flags.cookie;
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
console.log('\x1b[33m--token/--cookie needs a .dev_properties.json (domain, site, addon) to deploy against.\x1b[0m');
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
297
|
// Get the command
|
|
277
298
|
const command = getCommand(commandName);
|
|
278
299
|
if (!command) {
|
|
@@ -290,7 +311,7 @@ async function main() {
|
|
|
290
311
|
console.log('\x1b[32m✓ Password moved to keychain.\x1b[0m\n');
|
|
291
312
|
}
|
|
292
313
|
else {
|
|
293
|
-
console.log('\x1b[31mCould not
|
|
314
|
+
console.log('\x1b[31mCould not move the password; the file still holds it.\x1b[0m\n');
|
|
294
315
|
}
|
|
295
316
|
}
|
|
296
317
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { styleText } from 'node:util';
|
|
4
|
+
import { Box, useStdout } from 'ink';
|
|
5
|
+
import { StatusIndicator } from '../components/StatusIndicator.js';
|
|
6
|
+
import { useTasks } from '../utils/tasks.js';
|
|
7
|
+
import { useFinish } from './use-finish.js';
|
|
8
|
+
const LEVEL_STYLE = { info: 'reset', ok: 'green', warn: 'yellow', error: 'red' };
|
|
9
|
+
/**
|
|
10
|
+
* A one-shot command: the task's log printed above the status as it comes (a
|
|
11
|
+
* terminal keeps it in scrollback, CI keeps all of it), then exit with its result.
|
|
12
|
+
*/
|
|
13
|
+
export function TaskScreen({ task, stay = false, children }) {
|
|
14
|
+
const { write } = useStdout();
|
|
15
|
+
const live = useTasks().find(t => t.id === task.id) ?? task;
|
|
16
|
+
const result = live.status === 'running'
|
|
17
|
+
? undefined
|
|
18
|
+
: live.status === 'success'
|
|
19
|
+
? 'success'
|
|
20
|
+
: 'error';
|
|
21
|
+
// ponytail: counts lines, so past the task's 2000-line cap (where old lines
|
|
22
|
+
// are dropped) some would be skipped. No one-shot command logs that much.
|
|
23
|
+
const printed = useRef(0);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
for (const line of live.lines.slice(printed.current)) {
|
|
26
|
+
write(`${styleText('dim', line.tag.padEnd(3))} ${styleText(LEVEL_STYLE[line.level], line.text)}\n`);
|
|
27
|
+
}
|
|
28
|
+
printed.current = live.lines.length;
|
|
29
|
+
});
|
|
30
|
+
useFinish(result, stay && result === 'error');
|
|
31
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [_jsx(StatusIndicator, { status: result ?? 'running', label: live.phase, message: `${live.label} ${live.appName}` }), children] }));
|
|
32
|
+
}
|
package/dist/commands/build.js
CHANGED
|
@@ -1,192 +1,13 @@
|
|
|
1
|
-
import { jsx as _jsx
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { WebpackRunner, hasLocalWebpackConfig } from '../utils/webpack-runner.js';
|
|
6
|
-
import { hasSitevisionScripts, runSitevisionScriptsBuild, getDelegatedZipPath, checkSitevisionScriptsCompatibility, } from '../utils/sitevision-scripts-runner.js';
|
|
7
|
-
import { copyStaticToBuild, copySrcToBuild, cleanBuild, formatFileSize, createBuildZip, getZipSize, zipExists, } from '../utils/zip.js';
|
|
8
|
-
import { isBundledApp, getAppType, getFullAppId, } from '../utils/project-detection.js';
|
|
9
|
-
export function BuildScreen({ projectRoot, manifest, createZip = true, onBack, }) {
|
|
10
|
-
const [state, setState] = React.useState({
|
|
11
|
-
status: 'cleaning',
|
|
12
|
-
message: 'Cleaning build directory...',
|
|
13
|
-
});
|
|
14
|
-
useInput((input, key) => {
|
|
15
|
-
if (onBack &&
|
|
16
|
-
(key.escape || input === 'q') &&
|
|
17
|
-
(state.status === 'success' || state.status === 'error')) {
|
|
18
|
-
onBack();
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
const isBundled = isBundledApp(manifest);
|
|
22
|
-
React.useEffect(() => {
|
|
23
|
-
async function runBuild() {
|
|
24
|
-
try {
|
|
25
|
-
// Step 1: Clean build directory
|
|
26
|
-
setState({ status: 'cleaning', message: 'Cleaning build directory...' });
|
|
27
|
-
cleanBuild(projectRoot);
|
|
28
|
-
// Step 2: Build or copy files
|
|
29
|
-
if (isBundled && !hasLocalWebpackConfig(projectRoot)) {
|
|
30
|
-
// No project-local webpack config: delegate the whole build to
|
|
31
|
-
// @sitevision/sitevision-scripts, which compiles + zips to
|
|
32
|
-
// dist/<appId>.zip (the path the CLI's sign/deploy already use).
|
|
33
|
-
if (!hasSitevisionScripts(projectRoot)) {
|
|
34
|
-
setState({
|
|
35
|
-
status: 'error',
|
|
36
|
-
error: 'No webpack.config.js found and @sitevision/sitevision-scripts is not installed. Run npm install.',
|
|
37
|
-
});
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
// Warn if the installed sitevision-scripts is outside the range
|
|
41
|
-
// the delegated build was validated against.
|
|
42
|
-
const warning = checkSitevisionScriptsCompatibility(projectRoot).warning;
|
|
43
|
-
setState({
|
|
44
|
-
status: 'building',
|
|
45
|
-
message: 'Building via sitevision-scripts...',
|
|
46
|
-
warning,
|
|
47
|
-
});
|
|
48
|
-
const sitevisionResult = await runSitevisionScriptsBuild(projectRoot);
|
|
49
|
-
if (!sitevisionResult.success) {
|
|
50
|
-
setState({
|
|
51
|
-
status: 'error',
|
|
52
|
-
error: `${sitevisionResult.error}\n${sitevisionResult.output.slice(-1000)}`,
|
|
53
|
-
warning,
|
|
54
|
-
});
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
// sitevision-scripts already produced the zip; report it directly.
|
|
58
|
-
const zipPath = getDelegatedZipPath(projectRoot, manifest.id);
|
|
59
|
-
if (!zipExists(zipPath)) {
|
|
60
|
-
setState({
|
|
61
|
-
status: 'error',
|
|
62
|
-
error: `Build reported success but no zip was found at ${zipPath}.`,
|
|
63
|
-
warning,
|
|
64
|
-
});
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
setState({
|
|
68
|
-
status: 'success',
|
|
69
|
-
message: 'Build complete',
|
|
70
|
-
zipPath,
|
|
71
|
-
zipSize: getZipSize(zipPath),
|
|
72
|
-
warning,
|
|
73
|
-
});
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
if (isBundled) {
|
|
77
|
-
// Project ships its own webpack config: build it in-process.
|
|
78
|
-
if (!WebpackRunner.isWebpackAvailable(projectRoot)) {
|
|
79
|
-
setState({
|
|
80
|
-
status: 'error',
|
|
81
|
-
error: 'webpack not found. Run npm install to install dependencies.',
|
|
82
|
-
});
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
setState({ status: 'building', message: 'Compiling with webpack...' });
|
|
86
|
-
const appType = getAppType(manifest);
|
|
87
|
-
const runner = new WebpackRunner(projectRoot, {
|
|
88
|
-
mode: 'production',
|
|
89
|
-
cssPrefix: manifest.id,
|
|
90
|
-
restApp: appType !== 'web' && appType !== 'widget',
|
|
91
|
-
});
|
|
92
|
-
const result = await runner.run();
|
|
93
|
-
await runner.close();
|
|
94
|
-
if (!result.success) {
|
|
95
|
-
setState({
|
|
96
|
-
status: 'error',
|
|
97
|
-
error: result.errors?.join('\n') || 'Build failed',
|
|
98
|
-
result,
|
|
99
|
-
});
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
// Copy static files after webpack build
|
|
103
|
-
setState({ status: 'copying', message: 'Copying static files...' });
|
|
104
|
-
copyStaticToBuild(projectRoot);
|
|
105
|
-
setState(prev => ({ ...prev, result }));
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
// Non-bundled app: just copy files
|
|
109
|
-
setState({ status: 'copying', message: 'Copying source files...' });
|
|
110
|
-
copySrcToBuild(projectRoot);
|
|
111
|
-
copyStaticToBuild(projectRoot);
|
|
112
|
-
}
|
|
113
|
-
// Step 3: Create zip if requested
|
|
114
|
-
if (createZip) {
|
|
115
|
-
setState({ status: 'zipping', message: 'Creating zip archive...' });
|
|
116
|
-
const appId = getFullAppId(manifest.id);
|
|
117
|
-
const zipPath = await createBuildZip(projectRoot, appId);
|
|
118
|
-
const zipSize = getZipSize(zipPath);
|
|
119
|
-
setState(prev => ({
|
|
120
|
-
...prev,
|
|
121
|
-
status: 'success',
|
|
122
|
-
message: 'Build complete',
|
|
123
|
-
zipPath,
|
|
124
|
-
zipSize,
|
|
125
|
-
}));
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
setState(prev => ({
|
|
129
|
-
...prev,
|
|
130
|
-
status: 'success',
|
|
131
|
-
message: 'Build complete',
|
|
132
|
-
}));
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
catch (error) {
|
|
136
|
-
setState({
|
|
137
|
-
status: 'error',
|
|
138
|
-
error: error instanceof Error ? error.message : String(error),
|
|
139
|
-
});
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
runBuild();
|
|
143
|
-
}, [projectRoot, manifest, isBundled, createZip]);
|
|
144
|
-
const getStatusIndicator = () => {
|
|
145
|
-
switch (state.status) {
|
|
146
|
-
case 'cleaning':
|
|
147
|
-
case 'building':
|
|
148
|
-
case 'copying':
|
|
149
|
-
case 'zipping':
|
|
150
|
-
return 'running';
|
|
151
|
-
case 'success':
|
|
152
|
-
return 'success';
|
|
153
|
-
case 'error':
|
|
154
|
-
return 'error';
|
|
155
|
-
}
|
|
156
|
-
};
|
|
157
|
-
const getStatusLabel = () => {
|
|
158
|
-
switch (state.status) {
|
|
159
|
-
case 'cleaning':
|
|
160
|
-
return 'Cleaning';
|
|
161
|
-
case 'building':
|
|
162
|
-
return 'Building';
|
|
163
|
-
case 'copying':
|
|
164
|
-
return 'Copying files';
|
|
165
|
-
case 'zipping':
|
|
166
|
-
return 'Creating zip';
|
|
167
|
-
case 'success':
|
|
168
|
-
return 'Build complete';
|
|
169
|
-
case 'error':
|
|
170
|
-
return 'Build failed';
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(StatusIndicator, { status: getStatusIndicator(), label: getStatusLabel(), message: state.message }) }), state.warning && (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "yellow", children: ["\u26A0 ", state.warning] }) })), state.status === 'success' && state.result?.stats && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Text, { dimColor: true, children: ["Compiled in ", state.result.stats.time, "ms"] }), state.result.stats.assets &&
|
|
174
|
-
state.result.stats.assets.length > 0 && (_jsxs(Text, { dimColor: true, children: ["Assets: ", state.result.stats.assets.join(', ')] }))] })), state.status === 'success' && state.zipPath && (_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, children: [_jsxs(Text, { color: "green", children: ["\u2713 Created: ", state.zipPath] }), state.zipSize !== undefined && (_jsxs(Text, { dimColor: true, children: [" Size: ", formatFileSize(state.zipSize)] }))] })), state.result?.warnings && state.result.warnings.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: "yellow", children: "Warnings:" }), state.result.warnings.slice(0, 5).map((warning, i) => (_jsx(Text, { color: "yellow", dimColor: true, children: warning.substring(0, 200) }, i))), state.result.warnings.length > 5 && (_jsxs(Text, { color: "yellow", dimColor: true, children: ["...and ", state.result.warnings.length - 5, " more"] }))] })), state.status === 'error' && state.error && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(Text, { color: "red", children: state.error }) })), onBack && (state.status === 'success' || state.status === 'error') && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Press q or Esc to return to menu" }) }))] }));
|
|
175
|
-
}
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { render } from 'ink';
|
|
3
|
+
import { TaskScreen } from './TaskScreen.js';
|
|
4
|
+
import { startBuild } from '../utils/tasks.js';
|
|
176
5
|
export const buildCommand = {
|
|
177
6
|
name: 'build',
|
|
178
7
|
description: 'Build the application for production',
|
|
179
8
|
requiresProject: true,
|
|
180
|
-
flags: {
|
|
181
|
-
'no-zip': {
|
|
182
|
-
type: 'boolean',
|
|
183
|
-
description: 'Skip creating the zip archive',
|
|
184
|
-
default: false,
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
9
|
async execute({ project, flags }) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
await waitUntilExit();
|
|
10
|
+
const task = startBuild(project, { zip: flags['zip'] !== false });
|
|
11
|
+
await render(_jsx(TaskScreen, { task: task })).waitUntilExit();
|
|
191
12
|
},
|
|
192
13
|
};
|